From 16f504a9dca3fe3b70568f67b7d41241ae485288 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:49:04 +0200 Subject: Adding upstream version 7.0.6-dfsg. Signed-off-by: Daniel Baumann --- src/libs/xpcom18a4/Config.kmk | 474 ++ src/libs/xpcom18a4/Makefile.kmk | 1485 +++++ src/libs/xpcom18a4/VBoxXPCOM-mangled.def | 1688 ++++++ src/libs/xpcom18a4/VBoxXPCOM.def | 1687 ++++++ src/libs/xpcom18a4/dependentLibs.h | 2 + src/libs/xpcom18a4/ipc/Makefile.kup | 0 src/libs/xpcom18a4/ipc/ipcd/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/Makefile.in | 64 + src/libs/xpcom18a4/ipc/ipcd/Makefile.kup | 0 src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup | 0 .../xpcom18a4/ipc/ipcd/client/public/.cvsignore | 1 + .../xpcom18a4/ipc/ipcd/client/public/Makefile.in | 59 + src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h | 53 + .../ipc/ipcd/client/public/ipcIClientObserver.idl | 51 + .../ipc/ipcd/client/public/ipcIMessageObserver.idl | 64 + .../ipc/ipcd/client/public/ipcIService.idl | 228 + .../xpcom18a4/ipc/ipcd/client/public/ipcdclient.h | 326 ++ src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in | 101 + .../xpcom18a4/ipc/ipcd/client/src/Makefile.kup | 0 .../xpcom18a4/ipc/ipcd/client/src/ipcConnection.h | 147 + .../ipc/ipcd/client/src/ipcConnectionStub.cpp | 70 + .../ipc/ipcd/client/src/ipcConnectionUnix.cpp | 615 ++ .../ipc/ipcd/client/src/ipcConnectionWin.cpp | 332 ++ .../ipc/ipcd/client/src/ipcModuleFactory.cpp | 196 + .../xpcom18a4/ipc/ipcd/client/src/ipcService.cpp | 120 + .../xpcom18a4/ipc/ipcd/client/src/ipcService.h | 51 + .../xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp | 1505 +++++ .../xpcom18a4/ipc/ipcd/daemon/public/.cvsignore | 1 + .../xpcom18a4/ipc/ipcd/daemon/public/Makefile.in | 52 + .../xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h | 240 + .../ipc/ipcd/daemon/public/ipcModuleUtil.h | 151 + src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore | 2 + src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in | 88 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp | 235 + src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h | 144 + .../ipc/ipcd/daemon/src/ipcCommandModule.cpp | 316 + .../ipc/ipcd/daemon/src/ipcCommandModule.h | 48 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp | 245 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h | 70 + src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp | 235 + src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h | 82 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h | 65 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp | 77 + .../xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp | 600 ++ src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp | 408 ++ src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in | 49 + .../xpcom18a4/ipc/ipcd/extensions/Makefile.kup | 0 .../ipc/ipcd/extensions/dconnect/Makefile.in | 52 + .../ipc/ipcd/extensions/dconnect/Makefile.kup | 0 .../ipcd/extensions/dconnect/public/Makefile.in | 53 + .../dconnect/public/ipcIDConnectService.idl | 79 + .../ipc/ipcd/extensions/dconnect/src/Makefile.in | 66 + .../ipc/ipcd/extensions/dconnect/src/Makefile.kup | 0 .../extensions/dconnect/src/ipcDConnectService.cpp | 4210 ++++++++++++++ .../extensions/dconnect/src/ipcDConnectService.h | 365 ++ .../ipc/ipcd/extensions/dconnect/test/Makefile.in | 33 + .../ipcd/extensions/dconnect/test/TestClient.js | 106 + .../ipcd/extensions/dconnect/test/TestDConnect.cpp | 268 + .../ipcd/extensions/dconnect/test/TestServer.js | 66 + .../xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore | 1 + .../xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in | 52 + .../ipc/ipcd/extensions/lock/public/.cvsignore | 1 + .../ipc/ipcd/extensions/lock/public/Makefile.in | 58 + .../extensions/lock/public/ipcILockService.idl | 65 + .../ipc/ipcd/extensions/lock/public/ipcLockCID.h | 53 + .../ipc/ipcd/extensions/lock/src/.cvsignore | 1 + .../ipc/ipcd/extensions/lock/src/Makefile.in | 69 + .../ipcd/extensions/lock/src/ipcLockProtocol.cpp | 87 + .../ipc/ipcd/extensions/lock/src/ipcLockProtocol.h | 98 + .../ipcd/extensions/lock/src/ipcLockService.cpp | 168 + .../ipc/ipcd/extensions/lock/src/ipcLockService.h | 63 + .../ipc/ipcd/extensions/lock/src/module/.cvsignore | 1 + .../ipcd/extensions/lock/src/module/Makefile.in | 92 + .../extensions/lock/src/module/ipcLockModule.cpp | 337 ++ .../ipc/ipcd/extensions/lock/test/Makefile.in | 67 + .../ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp | 244 + .../ipc/ipcd/extensions/transmngr/.cvsignore | 1 + .../ipc/ipcd/extensions/transmngr/Makefile.in | 52 + .../ipc/ipcd/extensions/transmngr/build/.cvsignore | 9 + .../ipcd/extensions/transmngr/build/Makefile.in | 75 + .../ipc/ipcd/extensions/transmngr/build/tmCID.h | 53 + .../ipcd/extensions/transmngr/build/tmModule.cpp | 71 + .../ipcd/extensions/transmngr/common/.cvsignore | 5 + .../ipcd/extensions/transmngr/common/Makefile.in | 61 + .../extensions/transmngr/common/tmTransaction.cpp | 107 + .../extensions/transmngr/common/tmTransaction.h | 234 + .../ipc/ipcd/extensions/transmngr/common/tmUtils.h | 93 + .../ipcd/extensions/transmngr/common/tmVector.cpp | 179 + .../ipcd/extensions/transmngr/common/tmVector.h | 160 + .../ipcd/extensions/transmngr/module/.cvsignore | 11 + .../ipcd/extensions/transmngr/module/Makefile.in | 100 + .../extensions/transmngr/module/tmIPCModule.cpp | 137 + .../ipcd/extensions/transmngr/module/tmIPCModule.h | 109 + .../ipcd/extensions/transmngr/module/tmQueue.cpp | 223 + .../ipc/ipcd/extensions/transmngr/module/tmQueue.h | 186 + .../transmngr/module/tmTransactionManager.cpp | 162 + .../transmngr/module/tmTransactionManager.h | 147 + .../ipcd/extensions/transmngr/public/.cvsignore | 1 + .../ipcd/extensions/transmngr/public/Makefile.in | 53 + .../transmngr/public/ipcITransactionObserver.idl | 100 + .../transmngr/public/ipcITransactionService.idl | 239 + .../ipc/ipcd/extensions/transmngr/src/.cvsignore | 4 + .../ipc/ipcd/extensions/transmngr/src/Makefile.in | 64 + .../transmngr/src/tmTransactionService.cpp | 504 ++ .../transmngr/src/tmTransactionService.h | 196 + .../ipc/ipcd/extensions/transmngr/test/.cvsignore | 6 + .../ipc/ipcd/extensions/transmngr/test/Makefile.in | 68 + .../extensions/transmngr/test/tmModuleTest.cpp | 323 ++ src/libs/xpcom18a4/ipc/ipcd/ipc.pkg | 21 + src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in | 65 + .../xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp | 104 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h | 98 + .../xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp | 62 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h | 108 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h | 211 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp | 181 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h | 111 + .../xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp | 280 + .../xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h | 214 + .../ipc/ipcd/shared/src/ipcMessagePrimitives.cpp | 81 + .../ipc/ipcd/shared/src/ipcMessagePrimitives.h | 206 + .../xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h | 46 + .../ipc/ipcd/shared/src/ipcMessageUtils.h | 66 + .../ipc/ipcd/shared/src/ipcStringList.cpp | 80 + .../xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h | 114 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp | 303 + src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h | 502 ++ src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore | 2 + src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in | 69 + src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp | 338 ++ src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore | 1 + .../xpcom18a4/ipc/ipcd/test/module/Makefile.in | 81 + .../xpcom18a4/ipc/ipcd/test/module/TestModule.cpp | 62 + src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in | 49 + src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore | 1 + .../xpcom18a4/ipc/ipcd/util/public/Makefile.in | 53 + .../ipc/ipcd/util/public/ipcMessageReader.h | 89 + .../ipc/ipcd/util/public/ipcMessageWriter.h | 99 + src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore | 1 + src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in | 56 + .../ipc/ipcd/util/src/ipcMessageReader.cpp | 100 + .../ipc/ipcd/util/src/ipcMessageWriter.cpp | 130 + src/libs/xpcom18a4/java/Makefile.kmk | 233 + src/libs/xpcom18a4/java/README.vbox | 5 + src/libs/xpcom18a4/java/src/MacJawt.mm | 47 + src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp | 81 + .../java/src/nsAppFileLocProviderProxy.cpp | 253 + .../xpcom18a4/java/src/nsAppFileLocProviderProxy.h | 65 + src/libs/xpcom18a4/java/src/nsFileStreams.cpp | 475 ++ src/libs/xpcom18a4/java/src/nsFileStreams.h | 153 + src/libs/xpcom18a4/java/src/nsIFileStreams.h | 209 + src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp | 557 ++ src/libs/xpcom18a4/java/src/nsJavaInterfaces.h | 121 + src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp | 2020 +++++++ src/libs/xpcom18a4/java/src/nsJavaWrapper.h | 75 + .../xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp | 1084 ++++ .../xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h | 392 ++ src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp | 535 ++ src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp | 1711 ++++++ src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h | 153 + .../xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp | 98 + .../xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h | 63 + src/libs/xpcom18a4/java/src/nsThreadUtils.h | 399 ++ src/libs/xpcom18a4/java/src/nsXPTCUtils.h | 128 + .../src/org/mozilla/xpcom/GREVersionRange.java | 80 + .../src/org/mozilla/xpcom/IAppFileLocProvider.java | 92 + .../xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java | 127 + .../src/org/mozilla/xpcom/IJavaXPCOMUtils.java | 59 + .../java/src/org/mozilla/xpcom/IMozilla.java | 63 + .../java/src/org/mozilla/xpcom/INIParser.java | 243 + .../java/src/org/mozilla/xpcom/IXPCOM.java | 137 + .../java/src/org/mozilla/xpcom/Mozilla.java | 1079 ++++ .../java/src/org/mozilla/xpcom/ProfileLock.java | 63 + .../src/org/mozilla/xpcom/VersionComparator.java | 272 + .../java/src/org/mozilla/xpcom/XPCOMException.java | 95 + .../xpcom/XPCOMInitializationException.java | 56 + .../src/org/mozilla/xpcom/internal/GREImpl.java | 63 + .../mozilla/xpcom/internal/JavaXPCOMMethods.java | 104 + .../org/mozilla/xpcom/internal/MozillaImpl.java | 56 + .../src/org/mozilla/xpcom/internal/XPCOMImpl.java | 73 + .../org/mozilla/xpcom/internal/XPCOMJavaProxy.java | 257 + .../mozilla/xpcom/internal/XPCOMJavaProxyBase.java | 53 + .../java/src/org/virtualbox/VBoxObjectBase.java | 31 + src/libs/xpcom18a4/java/tools/gen-nsError.pl | 161 + .../tools/genifaces/GenerateJavaInterfaces.cpp | 952 +++ src/libs/xpcom18a4/java/tools/genjifaces.xsl | 600 ++ src/libs/xpcom18a4/nsBuildID.h | 23 + src/libs/xpcom18a4/nsprpub/Makefile.in | 151 + src/libs/xpcom18a4/nsprpub/admin/explode.pl | 75 + src/libs/xpcom18a4/nsprpub/admin/makeTargetDirs.sh | 79 + src/libs/xpcom18a4/nsprpub/admin/repackage.sh | 218 + src/libs/xpcom18a4/nsprpub/admin/symlinks.sh | 75 + src/libs/xpcom18a4/nsprpub/config/.cvsignore | 11 + src/libs/xpcom18a4/nsprpub/config/Makefile.in | 149 + src/libs/xpcom18a4/nsprpub/config/autoconf.mk.in | 113 + src/libs/xpcom18a4/nsprpub/config/config.mk | 164 + src/libs/xpcom18a4/nsprpub/config/libc_r.h | 158 + src/libs/xpcom18a4/nsprpub/config/nfspwd.pl | 50 + src/libs/xpcom18a4/nsprpub/config/now.c | 142 + src/libs/xpcom18a4/nsprpub/config/nsinstall.c | 602 ++ src/libs/xpcom18a4/nsprpub/config/nspr-config.in | 116 + src/libs/xpcom18a4/nsprpub/config/nspr.m4 | 67 + src/libs/xpcom18a4/nsprpub/config/nsprincl.mk.in | 5 + src/libs/xpcom18a4/nsprpub/config/nsprincl.sh.in | 5 + src/libs/xpcom18a4/nsprpub/config/pathsub.h | 78 + src/libs/xpcom18a4/nsprpub/config/prdepend.h | 44 + src/libs/xpcom18a4/nsprpub/config/prmkdir.bat | 38 + src/libs/xpcom18a4/nsprpub/config/rules.mk | 514 ++ src/libs/xpcom18a4/nsprpub/configure | 6034 ++++++++++++++++++++ src/libs/xpcom18a4/nsprpub/configure.in | 2556 +++++++++ src/libs/xpcom18a4/nsprpub/gmakefile.win | 96 + src/libs/xpcom18a4/nsprpub/lib/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/lib/Makefile.in | 56 + src/libs/xpcom18a4/nsprpub/lib/ds/.cvsignore | 2 + src/libs/xpcom18a4/nsprpub/lib/ds/MANIFEST | 7 + src/libs/xpcom18a4/nsprpub/lib/ds/Makefile.in | 202 + src/libs/xpcom18a4/nsprpub/lib/ds/plarena.c | 442 ++ src/libs/xpcom18a4/nsprpub/lib/ds/plarena.h | 219 + src/libs/xpcom18a4/nsprpub/lib/ds/plarenas.h | 126 + src/libs/xpcom18a4/nsprpub/lib/ds/plds.def | 78 + src/libs/xpcom18a4/nsprpub/lib/ds/plds.rc | 102 + src/libs/xpcom18a4/nsprpub/lib/ds/plds_symvec.opt | 37 + src/libs/xpcom18a4/nsprpub/lib/ds/plhash.c | 541 ++ src/libs/xpcom18a4/nsprpub/lib/ds/plhash.h | 183 + src/libs/xpcom18a4/nsprpub/lib/ds/plvrsion.c | 125 + src/libs/xpcom18a4/nsprpub/lib/libc/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/lib/libc/Makefile.in | 56 + src/libs/xpcom18a4/nsprpub/lib/libc/README | 20 + .../xpcom18a4/nsprpub/lib/libc/include/.cvsignore | 1 + .../xpcom18a4/nsprpub/lib/libc/include/MANIFEST | 9 + .../xpcom18a4/nsprpub/lib/libc/include/Makefile.in | 61 + src/libs/xpcom18a4/nsprpub/lib/libc/include/README | 7 + .../xpcom18a4/nsprpub/lib/libc/include/plbase64.h | 103 + .../xpcom18a4/nsprpub/lib/libc/include/plerror.h | 71 + .../xpcom18a4/nsprpub/lib/libc/include/plgetopt.h | 87 + .../xpcom18a4/nsprpub/lib/libc/include/plresolv.h | 108 + .../xpcom18a4/nsprpub/lib/libc/include/plstr.h | 505 ++ src/libs/xpcom18a4/nsprpub/lib/libc/src/.cvsignore | 2 + .../xpcom18a4/nsprpub/lib/libc/src/Makefile.in | 202 + src/libs/xpcom18a4/nsprpub/lib/libc/src/README | 20 + src/libs/xpcom18a4/nsprpub/lib/libc/src/base64.c | 428 ++ src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.def | 94 + src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.rc | 103 + .../xpcom18a4/nsprpub/lib/libc/src/plc_symvec.opt | 53 + src/libs/xpcom18a4/nsprpub/lib/libc/src/plerror.c | 168 + src/libs/xpcom18a4/nsprpub/lib/libc/src/plgetopt.c | 184 + src/libs/xpcom18a4/nsprpub/lib/libc/src/plvrsion.c | 125 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strcat.c | 81 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strccmp.c | 115 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strchr.c | 88 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strcmp.c | 57 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strcpy.c | 84 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strcstr.c | 123 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strdup.c | 100 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strlen.c | 71 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strpbrk.c | 100 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strstr.c | 117 + src/libs/xpcom18a4/nsprpub/lib/libc/src/strtok.c | 89 + src/libs/xpcom18a4/nsprpub/lib/msgc/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/lib/msgc/Makefile.in | 52 + .../xpcom18a4/nsprpub/lib/msgc/include/.cvsignore | 1 + .../xpcom18a4/nsprpub/lib/msgc/include/MANIFEST | 5 + .../xpcom18a4/nsprpub/lib/msgc/include/Makefile.in | 61 + .../xpcom18a4/nsprpub/lib/msgc/include/gcint.h | 129 + src/libs/xpcom18a4/nsprpub/lib/msgc/include/prgc.h | 419 ++ src/libs/xpcom18a4/nsprpub/lib/msgc/src/.cvsignore | 1 + .../xpcom18a4/nsprpub/lib/msgc/src/Makefile.in | 103 + src/libs/xpcom18a4/nsprpub/lib/msgc/src/macgc.c | 75 + src/libs/xpcom18a4/nsprpub/lib/msgc/src/os2gc.c | 83 + src/libs/xpcom18a4/nsprpub/lib/msgc/src/prgcapi.c | 351 ++ src/libs/xpcom18a4/nsprpub/lib/msgc/src/prmsgc.c | 3514 ++++++++++++ src/libs/xpcom18a4/nsprpub/lib/msgc/src/unixgc.c | 155 + src/libs/xpcom18a4/nsprpub/lib/msgc/src/win16gc.c | 77 + src/libs/xpcom18a4/nsprpub/lib/msgc/src/win32gc.c | 129 + .../xpcom18a4/nsprpub/lib/msgc/tests/.cvsignore | 1 + .../xpcom18a4/nsprpub/lib/msgc/tests/Makefile.in | 315 + src/libs/xpcom18a4/nsprpub/lib/msgc/tests/gc1.c | 257 + .../xpcom18a4/nsprpub/lib/msgc/tests/thrashgc.c | 274 + .../xpcom18a4/nsprpub/lib/prstreams/.cvsignore | 1 + .../xpcom18a4/nsprpub/lib/prstreams/Makefile.in | 207 + .../xpcom18a4/nsprpub/lib/prstreams/plvrsion.c | 125 + .../xpcom18a4/nsprpub/lib/prstreams/prstrms.cpp | 550 ++ src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.h | 153 + .../xpcom18a4/nsprpub/lib/prstreams/prstrms.rc | 102 + .../lib/prstreams/tests/testprstrm/.cvsignore | 1 + .../lib/prstreams/tests/testprstrm/Makefile.in | 254 + .../lib/prstreams/tests/testprstrm/testprstrm.cpp | 204 + src/libs/xpcom18a4/nsprpub/lib/tests/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/lib/tests/Makefile.in | 259 + src/libs/xpcom18a4/nsprpub/lib/tests/arena.c | 401 ++ src/libs/xpcom18a4/nsprpub/lib/tests/base64t.c | 3047 ++++++++++ src/libs/xpcom18a4/nsprpub/lib/tests/string.c | 3116 ++++++++++ .../xpcom18a4/nsprpub/lib/tests/windows/makefile | 82 + .../xpcom18a4/nsprpub/lib/tests/windows/readme.1st | 37 + .../xpcom18a4/nsprpub/lib/tests/windows/winevent.c | 348 ++ src/libs/xpcom18a4/nsprpub/makefile.win | 127 + src/libs/xpcom18a4/nsprpub/pkg/Makefile.in | 58 + src/libs/xpcom18a4/nsprpub/pkg/linux/Makefile.in | 44 + src/libs/xpcom18a4/nsprpub/pkg/linux/sun-nspr.spec | 122 + .../xpcom18a4/nsprpub/pkg/solaris/Makefile.com | 32 + src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.in | 60 + .../xpcom18a4/nsprpub/pkg/solaris/Makefile.targ | 40 + .../nsprpub/pkg/solaris/SUNWpr/Makefile.in | 22 + .../xpcom18a4/nsprpub/pkg/solaris/SUNWpr/depend | 27 + .../nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl | 34 + .../nsprpub/pkg/solaris/SUNWpr/prototype_com | 31 + .../nsprpub/pkg/solaris/SUNWpr/prototype_i386 | 30 + .../nsprpub/pkg/solaris/SUNWpr/prototype_sparc | 33 + .../nsprpub/pkg/solaris/SUNWprx/Makefile.in | 22 + .../xpcom18a4/nsprpub/pkg/solaris/SUNWprx/depend | 30 + .../nsprpub/pkg/solaris/SUNWprx/pkginfo.tmpl | 35 + .../nsprpub/pkg/solaris/SUNWprx/prototype_com | 28 + .../nsprpub/pkg/solaris/SUNWprx/prototype_sparc | 35 + .../nsprpub/pkg/solaris/bld_awk_pkginfo.ksh | 105 + .../nsprpub/pkg/solaris/common_files/copyright | 28 + src/libs/xpcom18a4/nsprpub/pr/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/Makefile.in | 49 + src/libs/xpcom18a4/nsprpub/pr/include/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/include/MANIFEST | 52 + src/libs/xpcom18a4/nsprpub/pr/include/Makefile.in | 59 + src/libs/xpcom18a4/nsprpub/pr/include/gencfg.c | 309 + .../xpcom18a4/nsprpub/pr/include/md/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/include/md/Makefile.in | 80 + src/libs/xpcom18a4/nsprpub/pr/include/md/_aix.h | 254 + .../xpcom18a4/nsprpub/pr/include/md/_aix32.cfg | 145 + .../xpcom18a4/nsprpub/pr/include/md/_aix64.cfg | 146 + src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.cfg | 147 + src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.h | 612 ++ src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.cfg | 198 + src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.h | 214 + .../xpcom18a4/nsprpub/pr/include/md/_darwin.cfg | 172 + src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.h | 306 + src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.cfg | 138 + src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.h | 221 + .../xpcom18a4/nsprpub/pr/include/md/_freebsd.cfg | 337 ++ .../xpcom18a4/nsprpub/pr/include/md/_freebsd.h | 290 + src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux.h | 257 + .../xpcom18a4/nsprpub/pr/include/md/_hpux32.cfg | 142 + .../xpcom18a4/nsprpub/pr/include/md/_hpux64.cfg | 143 + .../xpcom18a4/nsprpub/pr/include/md/_iprt_atomic.h | 64 + src/libs/xpcom18a4/nsprpub/pr/include/md/_irix.h | 470 ++ .../xpcom18a4/nsprpub/pr/include/md/_irix32.cfg | 149 + .../xpcom18a4/nsprpub/pr/include/md/_irix64.cfg | 148 + .../xpcom18a4/nsprpub/pr/include/md/_linux.cfg | 661 +++ src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.h | 501 ++ src/libs/xpcom18a4/nsprpub/pr/include/md/_macos.h | 725 +++ src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.cfg | 140 + src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.h | 230 + src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.cfg | 140 + src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.h | 196 + .../xpcom18a4/nsprpub/pr/include/md/_netbsd.cfg | 289 + src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.h | 322 ++ .../xpcom18a4/nsprpub/pr/include/md/_nextstep.cfg | 255 + .../xpcom18a4/nsprpub/pr/include/md/_nextstep.h | 299 + .../nsprpub/pr/include/md/_nspr_pthread.h | 283 + src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.cfg | 150 + src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.h | 221 + .../xpcom18a4/nsprpub/pr/include/md/_openbsd.cfg | 387 ++ .../xpcom18a4/nsprpub/pr/include/md/_openbsd.h | 238 + .../xpcom18a4/nsprpub/pr/include/md/_openvms.cfg | 146 + .../xpcom18a4/nsprpub/pr/include/md/_openvms.h | 332 ++ src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.cfg | 151 + src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.h | 601 ++ .../xpcom18a4/nsprpub/pr/include/md/_os2_errors.h | 162 + src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.cfg | 146 + src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.h | 255 + src/libs/xpcom18a4/nsprpub/pr/include/md/_pcos.h | 89 + src/libs/xpcom18a4/nsprpub/pr/include/md/_pth.h | 298 + src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.cfg | 96 + src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.h | 215 + .../nsprpub/pr/include/md/_reliantunix.cfg | 145 + .../xpcom18a4/nsprpub/pr/include/md/_reliantunix.h | 270 + .../xpcom18a4/nsprpub/pr/include/md/_rhapsody.cfg | 148 + .../xpcom18a4/nsprpub/pr/include/md/_rhapsody.h | 225 + .../xpcom18a4/nsprpub/pr/include/md/_scoos.cfg | 140 + src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.h | 204 + .../xpcom18a4/nsprpub/pr/include/md/_solaris.h | 832 +++ .../xpcom18a4/nsprpub/pr/include/md/_solaris32.cfg | 150 + .../xpcom18a4/nsprpub/pr/include/md/_solaris64.cfg | 151 + src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.cfg | 140 + src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.h | 204 + .../xpcom18a4/nsprpub/pr/include/md/_sunos4.cfg | 138 + src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.h | 236 + .../xpcom18a4/nsprpub/pr/include/md/_unix_errors.h | 171 + src/libs/xpcom18a4/nsprpub/pr/include/md/_unixos.h | 641 +++ .../xpcom18a4/nsprpub/pr/include/md/_unixware.cfg | 140 + .../xpcom18a4/nsprpub/pr/include/md/_unixware.h | 219 + .../xpcom18a4/nsprpub/pr/include/md/_unixware7.cfg | 142 + src/libs/xpcom18a4/nsprpub/pr/include/md/_vbox.cfg | 66 + .../xpcom18a4/nsprpub/pr/include/md/_win16.cfg | 177 + src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.h | 568 ++ .../nsprpub/pr/include/md/_win32_errors.h | 154 + .../xpcom18a4/nsprpub/pr/include/md/_win95.cfg | 200 + src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.h | 533 ++ .../xpcom18a4/nsprpub/pr/include/md/_winnt.cfg | 200 + src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.h | 594 ++ src/libs/xpcom18a4/nsprpub/pr/include/md/prosdep.h | 166 + src/libs/xpcom18a4/nsprpub/pr/include/md/sunos4.h | 164 + src/libs/xpcom18a4/nsprpub/pr/include/nspr.h | 75 + .../nsprpub/pr/include/obsolete/.cvsignore | 1 + .../nsprpub/pr/include/obsolete/Makefile.in | 60 + .../nsprpub/pr/include/obsolete/pralarm.h | 200 + .../nsprpub/pr/include/obsolete/probslet.h | 188 + .../nsprpub/pr/include/obsolete/protypes.h | 260 + .../xpcom18a4/nsprpub/pr/include/obsolete/prsem.h | 104 + src/libs/xpcom18a4/nsprpub/pr/include/pratom.h | 172 + src/libs/xpcom18a4/nsprpub/pr/include/prbit.h | 117 + src/libs/xpcom18a4/nsprpub/pr/include/prclist.h | 140 + src/libs/xpcom18a4/nsprpub/pr/include/prcmon.h | 107 + src/libs/xpcom18a4/nsprpub/pr/include/prcountr.h | 572 ++ src/libs/xpcom18a4/nsprpub/pr/include/prcvar.h | 134 + src/libs/xpcom18a4/nsprpub/pr/include/prdtoa.h | 96 + src/libs/xpcom18a4/nsprpub/pr/include/prenv.h | 162 + src/libs/xpcom18a4/nsprpub/pr/include/prerr.h | 278 + src/libs/xpcom18a4/nsprpub/pr/include/prerror.h | 339 ++ src/libs/xpcom18a4/nsprpub/pr/include/prinet.h | 126 + src/libs/xpcom18a4/nsprpub/pr/include/prinit.h | 260 + src/libs/xpcom18a4/nsprpub/pr/include/prinrval.h | 186 + src/libs/xpcom18a4/nsprpub/pr/include/prio.h | 2107 +++++++ src/libs/xpcom18a4/nsprpub/pr/include/pripcsem.h | 141 + .../nsprpub/pr/include/private/.cvsignore | 1 + .../nsprpub/pr/include/private/Makefile.in | 61 + .../xpcom18a4/nsprpub/pr/include/private/pprio.h | 294 + .../nsprpub/pr/include/private/pprmwait.h | 136 + .../nsprpub/pr/include/private/pprthred.h | 414 ++ .../xpcom18a4/nsprpub/pr/include/private/primpl.h | 2141 +++++++ .../xpcom18a4/nsprpub/pr/include/private/prpriv.h | 53 + src/libs/xpcom18a4/nsprpub/pr/include/prlink.h | 271 + src/libs/xpcom18a4/nsprpub/pr/include/prlock.h | 128 + src/libs/xpcom18a4/nsprpub/pr/include/prlog.h | 265 + src/libs/xpcom18a4/nsprpub/pr/include/prlong.h | 440 ++ src/libs/xpcom18a4/nsprpub/pr/include/prmem.h | 166 + src/libs/xpcom18a4/nsprpub/pr/include/prmon.h | 123 + src/libs/xpcom18a4/nsprpub/pr/include/prmwait.h | 424 ++ src/libs/xpcom18a4/nsprpub/pr/include/prnetdb.h | 524 ++ src/libs/xpcom18a4/nsprpub/pr/include/prolock.h | 217 + src/libs/xpcom18a4/nsprpub/pr/include/prpdce.h | 127 + src/libs/xpcom18a4/nsprpub/pr/include/prprf.h | 169 + src/libs/xpcom18a4/nsprpub/pr/include/prproces.h | 133 + src/libs/xpcom18a4/nsprpub/pr/include/prrng.h | 111 + src/libs/xpcom18a4/nsprpub/pr/include/prrwlock.h | 128 + src/libs/xpcom18a4/nsprpub/pr/include/prshm.h | 297 + src/libs/xpcom18a4/nsprpub/pr/include/prshma.h | 279 + src/libs/xpcom18a4/nsprpub/pr/include/prsystem.h | 131 + src/libs/xpcom18a4/nsprpub/pr/include/prthread.h | 305 + src/libs/xpcom18a4/nsprpub/pr/include/prtime.h | 311 + src/libs/xpcom18a4/nsprpub/pr/include/prtpool.h | 130 + src/libs/xpcom18a4/nsprpub/pr/include/prtrace.h | 692 +++ src/libs/xpcom18a4/nsprpub/pr/include/prtypes.h | 570 ++ src/libs/xpcom18a4/nsprpub/pr/include/prvrsion.h | 137 + src/libs/xpcom18a4/nsprpub/pr/include/prwin16.h | 196 + src/libs/xpcom18a4/nsprpub/pr/src/.cvsignore | 2 + src/libs/xpcom18a4/nsprpub/pr/src/Makefile.in | 422 ++ .../xpcom18a4/nsprpub/pr/src/bthreads/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/bthreads/Makefile.in | 63 + .../xpcom18a4/nsprpub/pr/src/bthreads/bsrcs.mk | 49 + .../xpcom18a4/nsprpub/pr/src/bthreads/btcvar.c | 276 + .../xpcom18a4/nsprpub/pr/src/bthreads/btlocks.c | 116 + .../xpcom18a4/nsprpub/pr/src/bthreads/btmisc.c | 104 + src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmon.c | 219 + src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btsem.c | 130 + .../xpcom18a4/nsprpub/pr/src/bthreads/btthread.c | 694 +++ src/libs/xpcom18a4/nsprpub/pr/src/bthreads/objs.mk | 43 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/cplus/Makefile.in | 75 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcascii.h | 175 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.cpp | 55 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.h | 83 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.cpp | 97 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.h | 96 + .../xpcom18a4/nsprpub/pr/src/cplus/rcfileio.cpp | 199 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.h | 161 + .../xpcom18a4/nsprpub/pr/src/cplus/rcinrval.cpp | 69 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.h | 169 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.cpp | 46 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.h | 148 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.cpp | 72 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.h | 98 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcmon.h | 79 + .../xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.cpp | 232 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.h | 129 + .../xpcom18a4/nsprpub/pr/src/cplus/rcnetio.cpp | 195 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.h | 126 + .../xpcom18a4/nsprpub/pr/src/cplus/rcthread.cpp | 220 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.h | 227 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.cpp | 66 + src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.h | 138 + .../nsprpub/pr/src/cplus/tests/.cvsignore | 1 + .../nsprpub/pr/src/cplus/tests/Makefile.in | 288 + .../nsprpub/pr/src/cplus/tests/fileio.cpp | 65 + .../nsprpub/pr/src/cplus/tests/interval.cpp | 133 + .../nsprpub/pr/src/cplus/tests/ranfile.cpp | 432 ++ .../nsprpub/pr/src/cplus/tests/switch.cpp | 266 + .../nsprpub/pr/src/cplus/tests/thread.cpp | 140 + .../xpcom18a4/nsprpub/pr/src/cplus/tests/time.cpp | 61 + .../xpcom18a4/nsprpub/pr/src/cplus/tests/tpd.cpp | 368 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/src/io/Makefile.in | 97 + src/libs/xpcom18a4/nsprpub/pr/src/io/prdir.c | 164 + src/libs/xpcom18a4/nsprpub/pr/src/io/prfdcach.c | 311 + src/libs/xpcom18a4/nsprpub/pr/src/io/prfile.c | 861 +++ src/libs/xpcom18a4/nsprpub/pr/src/io/prio.c | 202 + src/libs/xpcom18a4/nsprpub/pr/src/io/priometh.c | 628 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c | 382 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c | 769 +++ src/libs/xpcom18a4/nsprpub/pr/src/io/prlog.c | 617 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/prmapopt.c | 517 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/prmmap.c | 93 + src/libs/xpcom18a4/nsprpub/pr/src/io/prmwait.c | 1491 +++++ src/libs/xpcom18a4/nsprpub/pr/src/io/prpolevt.c | 530 ++ src/libs/xpcom18a4/nsprpub/pr/src/io/prprf.c | 1229 ++++ src/libs/xpcom18a4/nsprpub/pr/src/io/prscanf.c | 669 +++ src/libs/xpcom18a4/nsprpub/pr/src/io/prsocket.c | 1842 ++++++ src/libs/xpcom18a4/nsprpub/pr/src/io/prstdio.c | 103 + .../xpcom18a4/nsprpub/pr/src/linking/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/linking/Makefile.in | 80 + src/libs/xpcom18a4/nsprpub/pr/src/linking/prlink.c | 2147 +++++++ .../xpcom18a4/nsprpub/pr/src/malloc/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/malloc/Makefile.in | 67 + .../xpcom18a4/nsprpub/pr/src/malloc/prmalloc.c | 1174 ++++ src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmem.c | 762 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/src/md/Makefile.in | 64 + .../xpcom18a4/nsprpub/pr/src/md/beos/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/md/beos/Makefile.in | 60 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bcpu.c | 55 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos.c | 264 + .../xpcom18a4/nsprpub/pr/src/md/beos/beos_errors.c | 1525 +++++ src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bfile.c | 892 +++ .../xpcom18a4/nsprpub/pr/src/md/beos/bmemory.c | 42 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmisc.c | 123 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmmap.c | 73 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bnet.c | 929 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bproc.c | 237 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/brng.c | 69 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bseg.c | 54 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bsrcs.mk | 54 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/btime.c | 75 + src/libs/xpcom18a4/nsprpub/pr/src/md/beos/objs.mk | 43 + src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST | 7 + .../nsprpub/pr/src/md/mac/MacErrorHandling.h | 668 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c | 587 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h | 57 + src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c | 1949 +++++++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h | 51 + src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c | 52 + .../xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h | 238 + .../xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c | 2321 ++++++++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c | 721 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c | 253 + src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h | 51 + .../nsprpub/pr/src/md/mac/mdcriticalregion.c | 173 + .../nsprpub/pr/src/md/mac/mdcriticalregion.h | 59 + src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c | 776 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h | 51 + .../xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h | 136 + .../xpcom18a4/nsprpub/pr/src/md/os2/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/md/os2/Makefile.in | 85 + src/libs/xpcom18a4/nsprpub/pr/src/md/os2/objs.mk | 65 + .../xpcom18a4/nsprpub/pr/src/md/os2/os2_errors.c | 1129 ++++ src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2cv.c | 432 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2emx.s | 111 + src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2gc.c | 90 + .../xpcom18a4/nsprpub/pr/src/md/os2/os2inrval.c | 103 + src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2io.c | 907 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c | 666 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2poll.c | 382 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2rng.c | 111 + src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sem.c | 93 + src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sock.c | 733 +++ .../xpcom18a4/nsprpub/pr/src/md/os2/os2thred.c | 407 ++ .../xpcom18a4/nsprpub/pr/src/md/os2/os2vaclegacy.s | 73 + .../xpcom18a4/nsprpub/pr/src/md/os2/os2vacpp.asm | 293 + src/libs/xpcom18a4/nsprpub/pr/src/md/prosdep.c | 114 + .../xpcom18a4/nsprpub/pr/src/md/unix/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/md/unix/Makefile.in | 135 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aix.c | 333 ++ .../xpcom18a4/nsprpub/pr/src/md/unix/aixwrap.c | 65 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/bsdi.c | 119 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/darwin.c | 110 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/dgux.c | 109 + .../xpcom18a4/nsprpub/pr/src/md/unix/freebsd.c | 119 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/hpux.c | 261 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/irix.c | 1680 ++++++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/linux.c | 123 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/ncr.c | 395 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nec.c | 100 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/netbsd.c | 121 + .../xpcom18a4/nsprpub/pr/src/md/unix/nextstep.c | 284 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nto.c | 66 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/objs.mk | 63 + .../xpcom18a4/nsprpub/pr/src/md/unix/openbsd.c | 121 + .../xpcom18a4/nsprpub/pr/src/md/unix/openvms.c | 286 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_AIX.s | 119 + .../nsprpub/pr/src/md/unix/os_BSD_386_2.s | 71 + .../nsprpub/pr/src/md/unix/os_Darwin_ppc.s | 92 + .../nsprpub/pr/src/md/unix/os_Darwin_x86.s | 109 + .../xpcom18a4/nsprpub/pr/src/md/unix/os_HPUX.s | 54 + .../xpcom18a4/nsprpub/pr/src/md/unix/os_Irix.s | 163 + .../nsprpub/pr/src/md/unix/os_Linux_ia64.s | 80 + .../nsprpub/pr/src/md/unix/os_Linux_x86.s | 114 + .../nsprpub/pr/src/md/unix/os_Linux_x86_64.s | 95 + .../nsprpub/pr/src/md/unix/os_ReliantUNIX.s | 125 + .../xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS.s | 68 + .../xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_32.s | 117 + .../nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s | 201 + .../nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s | 201 + .../nsprpub/pr/src/md/unix/os_SunOS_x86.s | 249 + .../nsprpub/pr/src/md/unix/os_SunOS_x86_64.s | 95 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/osf1.c | 107 + .../nsprpub/pr/src/md/unix/pthreads_user.c | 480 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/qnx.c | 102 + .../xpcom18a4/nsprpub/pr/src/md/unix/reliantunix.c | 133 + .../xpcom18a4/nsprpub/pr/src/md/unix/rhapsody.c | 137 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/scoos.c | 181 + .../xpcom18a4/nsprpub/pr/src/md/unix/solaris.c | 889 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sony.c | 109 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sunos4.c | 96 + src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix.c | 3738 ++++++++++++ .../xpcom18a4/nsprpub/pr/src/md/unix/unix_errors.c | 862 +++ .../xpcom18a4/nsprpub/pr/src/md/unix/unixware.c | 583 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxpoll.c | 708 +++ .../xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c | 1118 ++++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxrng.c | 340 ++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxshm.c | 658 +++ src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxwrap.c | 548 ++ .../xpcom18a4/nsprpub/pr/src/md/windows/.cvsignore | 1 + .../nsprpub/pr/src/md/windows/Makefile.in | 121 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntdllmn.c | 88 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntgc.c | 126 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntinrval.c | 124 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntio.c | 4684 +++++++++++++++ .../xpcom18a4/nsprpub/pr/src/md/windows/ntmisc.c | 929 +++ .../xpcom18a4/nsprpub/pr/src/md/windows/ntsec.c | 279 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntsem.c | 84 + .../xpcom18a4/nsprpub/pr/src/md/windows/ntthread.c | 563 ++ .../xpcom18a4/nsprpub/pr/src/md/windows/objs.mk | 94 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16callb.c | 262 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16error.c | 252 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16fmem.c | 85 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16gc.c | 86 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16io.c | 855 +++ .../xpcom18a4/nsprpub/pr/src/md/windows/w16mem.c | 84 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16null.c | 116 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16proc.c | 77 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16sock.c | 1170 ++++ .../xpcom18a4/nsprpub/pr/src/md/windows/w16stdio.c | 169 + .../xpcom18a4/nsprpub/pr/src/md/windows/w16thred.c | 426 ++ .../nsprpub/pr/src/md/windows/w32ipcsem.c | 227 + .../xpcom18a4/nsprpub/pr/src/md/windows/w32poll.c | 351 ++ .../xpcom18a4/nsprpub/pr/src/md/windows/w32rng.c | 107 + .../xpcom18a4/nsprpub/pr/src/md/windows/w32shm.c | 356 ++ .../xpcom18a4/nsprpub/pr/src/md/windows/w95cv.c | 347 ++ .../nsprpub/pr/src/md/windows/w95dllmain.c | 71 + .../xpcom18a4/nsprpub/pr/src/md/windows/w95io.c | 1511 +++++ .../xpcom18a4/nsprpub/pr/src/md/windows/w95sock.c | 658 +++ .../xpcom18a4/nsprpub/pr/src/md/windows/w95thred.c | 295 + .../nsprpub/pr/src/md/windows/win32_errors.c | 562 ++ .../xpcom18a4/nsprpub/pr/src/memory/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/memory/Makefile.in | 69 + .../xpcom18a4/nsprpub/pr/src/memory/prgcleak.c | 122 + src/libs/xpcom18a4/nsprpub/pr/src/memory/prseg.c | 93 + src/libs/xpcom18a4/nsprpub/pr/src/memory/prshm.c | 156 + src/libs/xpcom18a4/nsprpub/pr/src/memory/prshma.c | 142 + src/libs/xpcom18a4/nsprpub/pr/src/misc/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/src/misc/Makefile.in | 107 + .../xpcom18a4/nsprpub/pr/src/misc/compile-et.pl | 140 + src/libs/xpcom18a4/nsprpub/pr/src/misc/pralarm.c | 282 + src/libs/xpcom18a4/nsprpub/pr/src/misc/pratom.c | 409 ++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prcountr.c | 506 ++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prdtoa.c | 3519 ++++++++++++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prenv.c | 109 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.c | 128 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.et | 135 + .../xpcom18a4/nsprpub/pr/src/misc/prerr.properties | 116 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prerror.c | 107 + .../xpcom18a4/nsprpub/pr/src/misc/prerrortable.c | 240 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prinit.c | 880 +++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prinrval.c | 157 + src/libs/xpcom18a4/nsprpub/pr/src/misc/pripc.c | 132 + src/libs/xpcom18a4/nsprpub/pr/src/misc/pripcsem.c | 130 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prlog2.c | 81 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prlong.c | 282 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prnetdb.c | 2189 +++++++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prolock.c | 100 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prrng.c | 76 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prsystem.c | 233 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prthinfo.c | 247 + src/libs/xpcom18a4/nsprpub/pr/src/misc/prtime.c | 1973 +++++++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prtpool.c | 1217 ++++ src/libs/xpcom18a4/nsprpub/pr/src/misc/prtrace.c | 922 +++ src/libs/xpcom18a4/nsprpub/pr/src/nspr.def | 457 ++ src/libs/xpcom18a4/nsprpub/pr/src/nspr.rc | 102 + src/libs/xpcom18a4/nsprpub/pr/src/nspr_symvec.opt | 500 ++ src/libs/xpcom18a4/nsprpub/pr/src/os2extra.def | 16 + src/libs/xpcom18a4/nsprpub/pr/src/prvrsion.c | 127 + .../xpcom18a4/nsprpub/pr/src/pthreads/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/pthreads/Makefile.in | 79 + src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptio.c | 4920 ++++++++++++++++ .../xpcom18a4/nsprpub/pr/src/pthreads/ptmisc.c | 71 + .../xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c | 1126 ++++ .../xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c | 1610 ++++++ .../xpcom18a4/nsprpub/pr/src/threads/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/src/threads/Makefile.in | 94 + .../nsprpub/pr/src/threads/combined/.cvsignore | 1 + .../nsprpub/pr/src/threads/combined/Makefile.in | 79 + .../nsprpub/pr/src/threads/combined/README | 62 + .../nsprpub/pr/src/threads/combined/prucpu.c | 440 ++ .../nsprpub/pr/src/threads/combined/prucv.c | 681 +++ .../nsprpub/pr/src/threads/combined/prulock.c | 463 ++ .../nsprpub/pr/src/threads/combined/prustack.c | 206 + .../nsprpub/pr/src/threads/combined/pruthr.c | 1918 +++++++ src/libs/xpcom18a4/nsprpub/pr/src/threads/prcmon.c | 413 ++ src/libs/xpcom18a4/nsprpub/pr/src/threads/prcthr.c | 446 ++ src/libs/xpcom18a4/nsprpub/pr/src/threads/prdump.c | 153 + src/libs/xpcom18a4/nsprpub/pr/src/threads/prmon.c | 222 + .../xpcom18a4/nsprpub/pr/src/threads/prrwlock.c | 512 ++ src/libs/xpcom18a4/nsprpub/pr/src/threads/prsem.c | 174 + src/libs/xpcom18a4/nsprpub/pr/src/threads/prtpd.c | 280 + src/libs/xpcom18a4/nsprpub/pr/tests/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/pr/tests/Makefile.in | 571 ++ src/libs/xpcom18a4/nsprpub/pr/tests/README.TXT | 434 ++ src/libs/xpcom18a4/nsprpub/pr/tests/accept.c | 524 ++ src/libs/xpcom18a4/nsprpub/pr/tests/acceptread.c | 272 + .../xpcom18a4/nsprpub/pr/tests/acceptreademu.c | 302 + src/libs/xpcom18a4/nsprpub/pr/tests/addrstr.c | 114 + src/libs/xpcom18a4/nsprpub/pr/tests/affinity.c | 124 + src/libs/xpcom18a4/nsprpub/pr/tests/alarm.c | 569 ++ src/libs/xpcom18a4/nsprpub/pr/tests/anonfm.c | 343 ++ src/libs/xpcom18a4/nsprpub/pr/tests/append.c | 158 + src/libs/xpcom18a4/nsprpub/pr/tests/atomic.c | 126 + src/libs/xpcom18a4/nsprpub/pr/tests/attach.c | 392 ++ src/libs/xpcom18a4/nsprpub/pr/tests/bigfile.c | 318 ++ src/libs/xpcom18a4/nsprpub/pr/tests/bigfile2.c | 127 + src/libs/xpcom18a4/nsprpub/pr/tests/bigfile3.c | 125 + src/libs/xpcom18a4/nsprpub/pr/tests/bug1test.c | 257 + src/libs/xpcom18a4/nsprpub/pr/tests/cleanup.c | 131 + src/libs/xpcom18a4/nsprpub/pr/tests/cltsrv.c | 1226 ++++ src/libs/xpcom18a4/nsprpub/pr/tests/concur.c | 193 + src/libs/xpcom18a4/nsprpub/pr/tests/cvar.c | 334 ++ src/libs/xpcom18a4/nsprpub/pr/tests/cvar2.c | 1008 ++++ src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc.c | 347 ++ src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc1.c | 141 + src/libs/xpcom18a4/nsprpub/pr/tests/dceemu.c | 132 + src/libs/xpcom18a4/nsprpub/pr/tests/depend.c | 153 + src/libs/xpcom18a4/nsprpub/pr/tests/dll/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/tests/dll/Makefile.in | 121 + src/libs/xpcom18a4/nsprpub/pr/tests/dll/my.def | 53 + src/libs/xpcom18a4/nsprpub/pr/tests/dll/mygetval.c | 58 + src/libs/xpcom18a4/nsprpub/pr/tests/dll/mysetval.c | 45 + src/libs/xpcom18a4/nsprpub/pr/tests/dlltest.c | 221 + src/libs/xpcom18a4/nsprpub/pr/tests/dtoa.c | 217 + src/libs/xpcom18a4/nsprpub/pr/tests/env.c | 221 + src/libs/xpcom18a4/nsprpub/pr/tests/errcodes.c | 167 + src/libs/xpcom18a4/nsprpub/pr/tests/errset.c | 186 + src/libs/xpcom18a4/nsprpub/pr/tests/exit.c | 137 + src/libs/xpcom18a4/nsprpub/pr/tests/fdcach.c | 259 + src/libs/xpcom18a4/nsprpub/pr/tests/fileio.c | 250 + src/libs/xpcom18a4/nsprpub/pr/tests/foreign.c | 416 ++ src/libs/xpcom18a4/nsprpub/pr/tests/forktest.c | 346 ++ src/libs/xpcom18a4/nsprpub/pr/tests/formattm.c | 59 + src/libs/xpcom18a4/nsprpub/pr/tests/freeif.c | 75 + src/libs/xpcom18a4/nsprpub/pr/tests/fsync.c | 155 + src/libs/xpcom18a4/nsprpub/pr/tests/getai.c | 64 + src/libs/xpcom18a4/nsprpub/pr/tests/gethost.c | 291 + src/libs/xpcom18a4/nsprpub/pr/tests/getproto.c | 114 + src/libs/xpcom18a4/nsprpub/pr/tests/i2l.c | 133 + src/libs/xpcom18a4/nsprpub/pr/tests/initclk.c | 108 + src/libs/xpcom18a4/nsprpub/pr/tests/inrval.c | 242 + src/libs/xpcom18a4/nsprpub/pr/tests/instrumt.c | 507 ++ src/libs/xpcom18a4/nsprpub/pr/tests/intrio.c | 169 + src/libs/xpcom18a4/nsprpub/pr/tests/intrupt.c | 373 ++ src/libs/xpcom18a4/nsprpub/pr/tests/io_timeout.c | 299 + src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutk.c | 233 + src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutu.c | 234 + src/libs/xpcom18a4/nsprpub/pr/tests/ioconthr.c | 146 + src/libs/xpcom18a4/nsprpub/pr/tests/ipv6.c | 248 + src/libs/xpcom18a4/nsprpub/pr/tests/join.c | 264 + src/libs/xpcom18a4/nsprpub/pr/tests/joinkk.c | 193 + src/libs/xpcom18a4/nsprpub/pr/tests/joinku.c | 199 + src/libs/xpcom18a4/nsprpub/pr/tests/joinuk.c | 195 + src/libs/xpcom18a4/nsprpub/pr/tests/joinuu.c | 197 + src/libs/xpcom18a4/nsprpub/pr/tests/layer.c | 465 ++ src/libs/xpcom18a4/nsprpub/pr/tests/lazyinit.c | 139 + src/libs/xpcom18a4/nsprpub/pr/tests/libfilename.c | 129 + src/libs/xpcom18a4/nsprpub/pr/tests/lltest.c | 859 +++ src/libs/xpcom18a4/nsprpub/pr/tests/lock.c | 547 ++ src/libs/xpcom18a4/nsprpub/pr/tests/lockfile.c | 276 + src/libs/xpcom18a4/nsprpub/pr/tests/logger.c | 167 + src/libs/xpcom18a4/nsprpub/pr/tests/makedir.c | 99 + src/libs/xpcom18a4/nsprpub/pr/tests/many_cv.c | 150 + src/libs/xpcom18a4/nsprpub/pr/tests/mbcs.c | 187 + src/libs/xpcom18a4/nsprpub/pr/tests/multiacc.c | 252 + src/libs/xpcom18a4/nsprpub/pr/tests/multiwait.c | 725 +++ src/libs/xpcom18a4/nsprpub/pr/tests/nameshm1.c | 599 ++ src/libs/xpcom18a4/nsprpub/pr/tests/nbconn.c | 591 ++ src/libs/xpcom18a4/nsprpub/pr/tests/nblayer.c | 707 +++ src/libs/xpcom18a4/nsprpub/pr/tests/nonblock.c | 273 + src/libs/xpcom18a4/nsprpub/pr/tests/ntioto.c | 317 + src/libs/xpcom18a4/nsprpub/pr/tests/ntoh.c | 125 + src/libs/xpcom18a4/nsprpub/pr/tests/obsints.c | 83 + src/libs/xpcom18a4/nsprpub/pr/tests/op_2long.c | 117 + src/libs/xpcom18a4/nsprpub/pr/tests/op_excl.c | 156 + src/libs/xpcom18a4/nsprpub/pr/tests/op_filnf.c | 91 + src/libs/xpcom18a4/nsprpub/pr/tests/op_filok.c | 110 + src/libs/xpcom18a4/nsprpub/pr/tests/op_noacc.c | 94 + src/libs/xpcom18a4/nsprpub/pr/tests/op_nofil.c | 99 + src/libs/xpcom18a4/nsprpub/pr/tests/openfile.c | 145 + src/libs/xpcom18a4/nsprpub/pr/tests/parent.c | 157 + src/libs/xpcom18a4/nsprpub/pr/tests/peek.c | 392 ++ src/libs/xpcom18a4/nsprpub/pr/tests/perf.c | 485 ++ src/libs/xpcom18a4/nsprpub/pr/tests/pipeping.c | 190 + src/libs/xpcom18a4/nsprpub/pr/tests/pipeping2.c | 192 + src/libs/xpcom18a4/nsprpub/pr/tests/pipepong.c | 92 + src/libs/xpcom18a4/nsprpub/pr/tests/pipepong2.c | 130 + src/libs/xpcom18a4/nsprpub/pr/tests/pipeself.c | 260 + src/libs/xpcom18a4/nsprpub/pr/tests/poll_er.c | 244 + src/libs/xpcom18a4/nsprpub/pr/tests/poll_nm.c | 399 ++ src/libs/xpcom18a4/nsprpub/pr/tests/poll_to.c | 216 + src/libs/xpcom18a4/nsprpub/pr/tests/pollable.c | 293 + src/libs/xpcom18a4/nsprpub/pr/tests/prftest.c | 97 + src/libs/xpcom18a4/nsprpub/pr/tests/prftest1.c | 152 + src/libs/xpcom18a4/nsprpub/pr/tests/prftest2.c | 129 + src/libs/xpcom18a4/nsprpub/pr/tests/primblok.c | 148 + src/libs/xpcom18a4/nsprpub/pr/tests/priotest.c | 233 + src/libs/xpcom18a4/nsprpub/pr/tests/provider.c | 1447 +++++ src/libs/xpcom18a4/nsprpub/pr/tests/prpoll.c | 373 ++ src/libs/xpcom18a4/nsprpub/pr/tests/prpollml.c | 162 + src/libs/xpcom18a4/nsprpub/pr/tests/prselect.c | 372 ++ src/libs/xpcom18a4/nsprpub/pr/tests/prttools.h | 43 + src/libs/xpcom18a4/nsprpub/pr/tests/randseed.c | 162 + src/libs/xpcom18a4/nsprpub/pr/tests/ranfile.c | 433 ++ src/libs/xpcom18a4/nsprpub/pr/tests/rmdir.c | 127 + src/libs/xpcom18a4/nsprpub/pr/tests/runtests.ksh | 292 + src/libs/xpcom18a4/nsprpub/pr/tests/runtests.sh | 292 + .../xpcom18a4/nsprpub/pr/tests/runy2ktests.ksh | 269 + src/libs/xpcom18a4/nsprpub/pr/tests/rwlocktest.c | 241 + src/libs/xpcom18a4/nsprpub/pr/tests/sel_spd.c | 567 ++ src/libs/xpcom18a4/nsprpub/pr/tests/selct_er.c | 234 + src/libs/xpcom18a4/nsprpub/pr/tests/selct_nm.c | 320 ++ src/libs/xpcom18a4/nsprpub/pr/tests/selct_to.c | 208 + src/libs/xpcom18a4/nsprpub/pr/tests/select2.c | 354 ++ src/libs/xpcom18a4/nsprpub/pr/tests/selintr.c | 81 + src/libs/xpcom18a4/nsprpub/pr/tests/sem.c | 253 + src/libs/xpcom18a4/nsprpub/pr/tests/sema.c | 180 + src/libs/xpcom18a4/nsprpub/pr/tests/semaerr.c | 142 + src/libs/xpcom18a4/nsprpub/pr/tests/semaerr1.c | 137 + src/libs/xpcom18a4/nsprpub/pr/tests/semaping.c | 203 + src/libs/xpcom18a4/nsprpub/pr/tests/semapong.c | 147 + src/libs/xpcom18a4/nsprpub/pr/tests/sendzlf.c | 246 + src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c | 634 ++ src/libs/xpcom18a4/nsprpub/pr/tests/servr_kk.c | 613 ++ src/libs/xpcom18a4/nsprpub/pr/tests/servr_ku.c | 593 ++ src/libs/xpcom18a4/nsprpub/pr/tests/servr_uk.c | 595 ++ src/libs/xpcom18a4/nsprpub/pr/tests/servr_uu.c | 593 ++ src/libs/xpcom18a4/nsprpub/pr/tests/short_thread.c | 90 + src/libs/xpcom18a4/nsprpub/pr/tests/sigpipe.c | 131 + src/libs/xpcom18a4/nsprpub/pr/tests/sleep.c | 134 + src/libs/xpcom18a4/nsprpub/pr/tests/socket.c | 2354 ++++++++ src/libs/xpcom18a4/nsprpub/pr/tests/sockopt.c | 213 + src/libs/xpcom18a4/nsprpub/pr/tests/sockping.c | 164 + src/libs/xpcom18a4/nsprpub/pr/tests/sockpong.c | 115 + src/libs/xpcom18a4/nsprpub/pr/tests/sprintf.c | 454 ++ src/libs/xpcom18a4/nsprpub/pr/tests/sproc_ch.c | 119 + src/libs/xpcom18a4/nsprpub/pr/tests/sproc_p.c | 101 + src/libs/xpcom18a4/nsprpub/pr/tests/stack.c | 310 + src/libs/xpcom18a4/nsprpub/pr/tests/stat.c | 119 + src/libs/xpcom18a4/nsprpub/pr/tests/stdio.c | 83 + src/libs/xpcom18a4/nsprpub/pr/tests/str2addr.c | 82 + src/libs/xpcom18a4/nsprpub/pr/tests/strod.c | 106 + src/libs/xpcom18a4/nsprpub/pr/tests/suspend.c | 231 + src/libs/xpcom18a4/nsprpub/pr/tests/switch.c | 274 + src/libs/xpcom18a4/nsprpub/pr/tests/system.c | 82 + src/libs/xpcom18a4/nsprpub/pr/tests/testbit.c | 129 + src/libs/xpcom18a4/nsprpub/pr/tests/testfile.c | 1008 ++++ src/libs/xpcom18a4/nsprpub/pr/tests/threads.c | 249 + .../xpcom18a4/nsprpub/pr/tests/thrpool_client.c | 392 ++ .../xpcom18a4/nsprpub/pr/tests/thrpool_server.c | 607 ++ src/libs/xpcom18a4/nsprpub/pr/tests/thruput.c | 412 ++ src/libs/xpcom18a4/nsprpub/pr/tests/time.c | 201 + src/libs/xpcom18a4/nsprpub/pr/tests/timemac.c | 153 + src/libs/xpcom18a4/nsprpub/pr/tests/timetest.c | 782 +++ src/libs/xpcom18a4/nsprpub/pr/tests/tmoacc.c | 333 ++ src/libs/xpcom18a4/nsprpub/pr/tests/tmocon.c | 401 ++ src/libs/xpcom18a4/nsprpub/pr/tests/tpd.c | 334 ++ src/libs/xpcom18a4/nsprpub/pr/tests/udpsrv.c | 566 ++ src/libs/xpcom18a4/nsprpub/pr/tests/ut_ttools.h | 43 + src/libs/xpcom18a4/nsprpub/pr/tests/vercheck.c | 108 + src/libs/xpcom18a4/nsprpub/pr/tests/version.c | 123 + .../xpcom18a4/nsprpub/pr/tests/w16gui/.cvsignore | 1 + .../xpcom18a4/nsprpub/pr/tests/w16gui/Makefile.in | 99 + .../xpcom18a4/nsprpub/pr/tests/w16gui/popfile.c | 167 + .../xpcom18a4/nsprpub/pr/tests/w16gui/popfind.c | 149 + .../xpcom18a4/nsprpub/pr/tests/w16gui/popfont.c | 94 + .../xpcom18a4/nsprpub/pr/tests/w16gui/poppad.c | 672 +++ .../xpcom18a4/nsprpub/pr/tests/w16gui/poppad.h | 66 + .../xpcom18a4/nsprpub/pr/tests/w16gui/poppad.ico | Bin 0 -> 326 bytes .../xpcom18a4/nsprpub/pr/tests/w16gui/poppad.rc | 121 + .../xpcom18a4/nsprpub/pr/tests/w16gui/popprnt0.c | 49 + .../xpcom18a4/nsprpub/pr/tests/w16gui/readme.1st | 37 + src/libs/xpcom18a4/nsprpub/pr/tests/writev.c | 234 + src/libs/xpcom18a4/nsprpub/pr/tests/xnotify.c | 389 ++ src/libs/xpcom18a4/nsprpub/pr/tests/y2k.c | 840 +++ src/libs/xpcom18a4/nsprpub/pr/tests/y2ktmo.c | 546 ++ src/libs/xpcom18a4/nsprpub/pr/tests/yield.c | 88 + src/libs/xpcom18a4/nsprpub/pr/tests/zerolen.c | 282 + src/libs/xpcom18a4/nsprpub/tools/.cvsignore | 1 + src/libs/xpcom18a4/nsprpub/tools/Makefile.in | 249 + src/libs/xpcom18a4/nsprpub/tools/httpget.c | 466 ++ src/libs/xpcom18a4/nsprpub/tools/tail.c | 166 + src/libs/xpcom18a4/python/.cvsignore | 4 + src/libs/xpcom18a4/python/Makefile.kmk | 789 +++ src/libs/xpcom18a4/python/README.vbox | 5 + src/libs/xpcom18a4/python/__init__.py | 173 + src/libs/xpcom18a4/python/client/.cvsignore | 2 + src/libs/xpcom18a4/python/client/__init__.py | 539 ++ src/libs/xpcom18a4/python/components.py | 248 + src/libs/xpcom18a4/python/doc/advanced.html | 176 + src/libs/xpcom18a4/python/doc/architecture.html | 116 + src/libs/xpcom18a4/python/doc/configure.html | 196 + src/libs/xpcom18a4/python/doc/credits.html | 86 + src/libs/xpcom18a4/python/doc/tutorial.html | 286 + src/libs/xpcom18a4/python/file.py | 318 ++ src/libs/xpcom18a4/python/gen_python_deps.py | 147 + src/libs/xpcom18a4/python/nsError.py | 166 + src/libs/xpcom18a4/python/primitives.py | 39 + src/libs/xpcom18a4/python/readme.html | 121 + src/libs/xpcom18a4/python/server/.cvsignore | 2 + src/libs/xpcom18a4/python/server/__init__.py | 88 + src/libs/xpcom18a4/python/server/enumerator.py | 58 + src/libs/xpcom18a4/python/server/factory.py | 68 + src/libs/xpcom18a4/python/server/loader.py | 227 + src/libs/xpcom18a4/python/server/module.py | 108 + src/libs/xpcom18a4/python/server/policy.py | 398 ++ src/libs/xpcom18a4/python/src/ErrorUtils.cpp | 483 ++ src/libs/xpcom18a4/python/src/PyGBase.cpp | 852 +++ src/libs/xpcom18a4/python/src/PyGInputStream.cpp | 173 + src/libs/xpcom18a4/python/src/PyGModule.cpp | 297 + src/libs/xpcom18a4/python/src/PyGStub.cpp | 180 + src/libs/xpcom18a4/python/src/PyGWeakReference.cpp | 112 + src/libs/xpcom18a4/python/src/PyIClassInfo.cpp | 181 + .../xpcom18a4/python/src/PyIComponentManager.cpp | 138 + .../python/src/PyIComponentManagerObsolete.cpp | 203 + src/libs/xpcom18a4/python/src/PyIEnumerator.cpp | 235 + src/libs/xpcom18a4/python/src/PyIID.cpp | 410 ++ src/libs/xpcom18a4/python/src/PyIInputStream.cpp | 190 + src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp | 431 ++ .../python/src/PyIInterfaceInfoManager.cpp | 206 + .../xpcom18a4/python/src/PyISimpleEnumerator.cpp | 202 + src/libs/xpcom18a4/python/src/PyISupports.cpp | 621 ++ src/libs/xpcom18a4/python/src/PyIVariant.cpp | 231 + src/libs/xpcom18a4/python/src/PyXPCOM.h | 1036 ++++ src/libs/xpcom18a4/python/src/PyXPCOM_std.h | 56 + src/libs/xpcom18a4/python/src/Pyxpt_info.cpp | 197 + src/libs/xpcom18a4/python/src/TypeObject.cpp | 457 ++ src/libs/xpcom18a4/python/src/VariantUtils.cpp | 3112 ++++++++++ src/libs/xpcom18a4/python/src/dllmain.cpp | 352 ++ src/libs/xpcom18a4/python/src/loader/pyloader.cpp | 435 ++ src/libs/xpcom18a4/python/src/module/_xpcom.cpp | 950 +++ src/libs/xpcom18a4/python/src/readme.html | 99 + src/libs/xpcom18a4/python/test/.cvsignore | 2 + .../python/test/output/test_com_exceptions | 8 + src/libs/xpcom18a4/python/test/output/test_comfile | 7 + .../xpcom18a4/python/test/output/test_components | 4 + .../python/test/output/test_isupports_primitives | 2 + src/libs/xpcom18a4/python/test/output/test_streams | 1 + .../python/test/output/test_test_component | 4 + .../python/test/output/test_weakreferences | 2 + .../xpcom18a4/python/test/pyxpcom_test_tools.py | 126 + src/libs/xpcom18a4/python/test/regrtest.py | 91 + .../xpcom18a4/python/test/test_com_exceptions.py | 124 + src/libs/xpcom18a4/python/test/test_comfile.py | 49 + .../python/test/test_component/_xpidlgen/.done | 0 .../test_component/_xpidlgen/py_test_component.h | 1411 +++++ .../test/test_component/py_test_component.html | 182 + .../test/test_component/py_test_component.idl | 231 + .../test/test_component/py_test_component.py | 421 ++ src/libs/xpcom18a4/python/test/test_components.py | 109 + .../python/test/test_isupports_primitives.py | 207 + src/libs/xpcom18a4/python/test/test_misc.py | 236 + src/libs/xpcom18a4/python/test/test_streams.py | 96 + .../xpcom18a4/python/test/test_test_component.js | 138 + .../xpcom18a4/python/test/test_test_component.py | 575 ++ .../xpcom18a4/python/test/test_weakreferences.py | 114 + src/libs/xpcom18a4/python/tools/regxpcom.py | 68 + src/libs/xpcom18a4/python/tools/tracer_demo.py | 113 + src/libs/xpcom18a4/python/vboxxpcom.py | 83 + src/libs/xpcom18a4/python/xpcom_consts.py | 272 + src/libs/xpcom18a4/python/xpt.py | 471 ++ src/libs/xpcom18a4/vboxdeps.cpp | 75 + src/libs/xpcom18a4/xpcom-config.h | 69 + src/libs/xpcom18a4/xpcom-namespace-cleanup.map | 34 + src/libs/xpcom18a4/xpcom-private.h | 32 + src/libs/xpcom18a4/xpcom/.cvsignore | 3 + src/libs/xpcom18a4/xpcom/Makefile.in | 84 + src/libs/xpcom18a4/xpcom/Makefile.kup | 0 src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in | 70 + src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c | 2765 +++++++++ src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h | 1800 ++++++ src/libs/xpcom18a4/xpcom/base/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/base/Makefile.in | 133 + src/libs/xpcom18a4/xpcom/base/nsAgg.h | 155 + src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp | 41 + src/libs/xpcom18a4/xpcom/base/nsAllocator.h | 50 + src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h | 1353 +++++ src/libs/xpcom18a4/xpcom/base/nsCom.h | 43 + src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp | 69 + src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h | 58 + src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp | 321 ++ src/libs/xpcom18a4/xpcom/base/nsConsoleService.h | 89 + src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp | 477 ++ src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h | 61 + src/libs/xpcom18a4/xpcom/base/nsError.h | 317 + src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp | 153 + src/libs/xpcom18a4/xpcom/base/nsErrorService.h | 76 + .../xpcom18a4/xpcom/base/nsExceptionService.cpp | 383 ++ src/libs/xpcom18a4/xpcom/base/nsExceptionService.h | 94 + src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c | 127 + src/libs/xpcom18a4/xpcom/base/nsIAllocator.h | 56 + .../xpcom18a4/xpcom/base/nsIConsoleListener.idl | 49 + .../xpcom18a4/xpcom/base/nsIConsoleMessage.idl | 56 + .../xpcom18a4/xpcom/base/nsIConsoleService.idl | 85 + src/libs/xpcom18a4/xpcom/base/nsID.cpp | 152 + src/libs/xpcom18a4/xpcom/base/nsID.h | 166 + src/libs/xpcom18a4/xpcom/base/nsIDebug.idl | 67 + src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl | 100 + src/libs/xpcom18a4/xpcom/base/nsIException.idl | 101 + .../xpcom18a4/xpcom/base/nsIExceptionService.idl | 97 + src/libs/xpcom18a4/xpcom/base/nsIID.h | 41 + .../xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl | 72 + src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl | 54 + src/libs/xpcom18a4/xpcom/base/nsIMemory.idl | 126 + .../xpcom/base/nsIProgrammingLanguage.idl | 70 + src/libs/xpcom18a4/xpcom/base/nsISupports.idl | 80 + src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h | 119 + .../xpcom18a4/xpcom/base/nsISupportsObsolete.h | 243 + src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl | 62 + src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl | 72 + src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl | 102 + src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp | 248 + src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h | 60 + src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp | 548 ++ src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h | 91 + src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp | 375 ++ src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h | 46 + src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp | 351 ++ src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h | 126 + .../xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp | 1444 +++++ src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h | 109 + src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h | 48 + src/libs/xpcom18a4/xpcom/base/nscore.h | 468 ++ src/libs/xpcom18a4/xpcom/base/nsrootidl.idl | 128 + src/libs/xpcom18a4/xpcom/base/pure.h | 135 + src/libs/xpcom18a4/xpcom/base/pure_api.c | 126 + src/libs/xpcom18a4/xpcom/build/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/build/Makefile.in | 165 + src/libs/xpcom18a4/xpcom/build/dlldeps.cpp | 202 + src/libs/xpcom18a4/xpcom/build/malloc.c | 5126 +++++++++++++++++ src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp | 753 +++ src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp | 261 + src/libs/xpcom18a4/xpcom/build/nsXPCOM.h | 217 + src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h | 174 + src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h | 228 + src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp | 1079 ++++ src/libs/xpcom18a4/xpcom/build/win32.order | 1514 +++++ src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg | 47 + src/libs/xpcom18a4/xpcom/build/xpcom.pkg | 106 + src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def | 252 + src/libs/xpcom18a4/xpcom/components/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/components/Makefile.in | 107 + .../xpcom/components/nsCategoryManager.cpp | 799 +++ .../xpcom18a4/xpcom/components/nsCategoryManager.h | 159 + .../xpcom/components/nsCategoryManagerUtils.h | 88 + .../xpcom/components/nsComponentManager.cpp | 3794 ++++++++++++ .../xpcom/components/nsComponentManager.h | 339 ++ .../components/nsComponentManagerObsolete.cpp | 271 + .../xpcom/components/nsComponentManagerObsolete.h | 185 + .../xpcom/components/nsComponentManagerUtils.h | 196 + .../xpcom/components/nsICategoryManager.idl | 101 + .../xpcom18a4/xpcom/components/nsIClassInfo.idl | 132 + .../xpcom/components/nsIComponentLoader.idl | 109 + .../xpcom/components/nsIComponentLoaderManager.idl | 72 + .../xpcom/components/nsIComponentManager.idl | 111 + .../components/nsIComponentManagerObsolete.idl | 351 ++ .../xpcom/components/nsIComponentManagerUtils.h | 43 + .../xpcom/components/nsIComponentRegistrar.idl | 243 + src/libs/xpcom18a4/xpcom/components/nsIFactory.idl | 79 + src/libs/xpcom18a4/xpcom/components/nsIModule.idl | 115 + .../xpcom/components/nsINativeComponentLoader.idl | 70 + .../xpcom/components/nsIServiceManager.idl | 119 + .../xpcom/components/nsIServiceManagerObsolete.h | 250 + .../xpcom/components/nsIServiceManagerUtils.h | 185 + src/libs/xpcom18a4/xpcom/components/nsModule.h | 58 + .../xpcom/components/nsNativeComponentLoader.cpp | 1150 ++++ .../xpcom/components/nsNativeComponentLoader.h | 84 + .../xpcom/components/nsObsoleteModuleLoading.h | 27 + .../xpcom/components/nsServiceManagerObsolete.cpp | 155 + .../xpcom18a4/xpcom/components/nsStaticComponent.h | 52 + .../xpcom/components/nsStaticComponentLoader.cpp | 317 + src/libs/xpcom18a4/xpcom/components/xcDll.cpp | 457 ++ src/libs/xpcom18a4/xpcom/components/xcDll.h | 121 + src/libs/xpcom18a4/xpcom/doc/README | 8 + src/libs/xpcom18a4/xpcom/ds/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/ds/Makefile.in | 171 + src/libs/xpcom18a4/xpcom/ds/nsArray.cpp | 226 + src/libs/xpcom18a4/xpcom/ds/nsArray.h | 118 + src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp | 210 + src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h | 87 + src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp | 67 + src/libs/xpcom18a4/xpcom/ds/nsAtomService.h | 56 + src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp | 616 ++ src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h | 101 + src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h | 127 + src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h | 458 ++ src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp | 170 + src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h | 67 + src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp | 162 + src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h | 267 + src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp | 534 ++ src/libs/xpcom18a4/xpcom/ds/nsCRT.h | 301 + src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp | 180 + src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h | 194 + src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h | 149 + src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h | 127 + src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h | 62 + src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp | 627 ++ src/libs/xpcom18a4/xpcom/ds/nsDeque.h | 405 ++ src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h | 505 ++ src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp | 108 + src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h | 64 + src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp | 253 + src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h | 129 + .../xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp | 153 + src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h | 201 + src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h | 315 + src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp | 46 + src/libs/xpcom18a4/xpcom/ds/nsHashSets.h | 107 + src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp | 896 +++ src/libs/xpcom18a4/xpcom/ds/nsHashtable.h | 454 ++ src/libs/xpcom18a4/xpcom/ds/nsIArray.idl | 202 + src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl | 161 + src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl | 73 + src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h | 95 + src/libs/xpcom18a4/xpcom/ds/nsICollection.idl | 92 + src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl | 89 + src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl | 58 + src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl | 72 + src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl | 111 + .../xpcom18a4/xpcom/ds/nsIPersistentProperties.h | 8 + .../xpcom/ds/nsIPersistentProperties2.idl | 107 + src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl | 79 + src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl | 77 + .../xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl | 68 + src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl | 65 + .../xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl | 81 + .../xpcom18a4/xpcom/ds/nsIStringEnumerator.idl | 58 + src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl | 139 + .../xpcom18a4/xpcom/ds/nsISupportsIterators.idl | 325 ++ .../xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl | 304 + src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl | 242 + src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h | 73 + src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl | 188 + src/libs/xpcom18a4/xpcom/ds/nsInt64.h | 399 ++ src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h | 196 + src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h | 121 + src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp | 211 + src/libs/xpcom18a4/xpcom/ds/nsObserverList.h | 79 + src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp | 227 + src/libs/xpcom18a4/xpcom/ds/nsObserverService.h | 75 + .../xpcom18a4/xpcom/ds/nsPersistentProperties.cpp | 492 ++ .../xpcom18a4/xpcom/ds/nsPersistentProperties.h | 106 + src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp | 150 + src/libs/xpcom18a4/xpcom/ds/nsProperties.h | 72 + src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp | 182 + src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h | 72 + .../xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp | 443 ++ src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h | 208 + src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h | 197 + src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h | 65 + src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp | 217 + src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h | 81 + src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp | 261 + src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h | 122 + src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp | 684 +++ src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h | 172 + .../xpcom/ds/nsSupportsArrayEnumerator.cpp | 148 + .../xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h | 67 + .../xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp | 880 +++ src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h | 358 ++ src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp | 62 + src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h | 429 ++ src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp | 1557 +++++ src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h | 115 + src/libs/xpcom18a4/xpcom/ds/nsTime.h | 143 + src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp | 613 ++ src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h | 64 + src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp | 141 + src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h | 65 + src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h | 207 + src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp | 304 + src/libs/xpcom18a4/xpcom/ds/nsValueArray.h | 125 + src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp | 2092 +++++++ src/libs/xpcom18a4/xpcom/ds/nsVariant.h | 203 + src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp | 1560 +++++ src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h | 410 ++ src/libs/xpcom18a4/xpcom/ds/pldhash.c | 826 +++ src/libs/xpcom18a4/xpcom/ds/pldhash.h | 603 ++ src/libs/xpcom18a4/xpcom/glue/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/glue/Makefile.in | 86 + src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp | 124 + src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h | 1405 +++++ .../xpcom/glue/nsComponentManagerUtils.cpp | 133 + src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp | 119 + src/libs/xpcom18a4/xpcom/glue/nsDebug.h | 276 + src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp | 547 ++ src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h | 129 + src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h | 480 ++ .../xpcom/glue/nsIInterfaceRequestorUtils.cpp | 64 + .../xpcom/glue/nsIInterfaceRequestorUtils.h | 83 + src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h | 1246 ++++ src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h | 230 + .../xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h | 162 + src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp | 151 + src/libs/xpcom18a4/xpcom/glue/nsMemory.h | 154 + .../xpcom18a4/xpcom/glue/nsServiceManagerUtils.h | 183 + src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp | 125 + src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h | 135 + src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp | 169 + src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h | 150 + src/libs/xpcom18a4/xpcom/glue/objs.mk | 60 + .../xpcom18a4/xpcom/glue/standalone/.cvsignore | 8 + .../xpcom18a4/xpcom/glue/standalone/Makefile.in | 88 + .../glue/standalone/nsGREDirServiceProvider.cpp | 596 ++ .../glue/standalone/nsGREDirServiceProvider.h | 68 + .../xpcom/glue/standalone/nsXPCOMGlue.cpp | 524 ++ .../xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h | 109 + src/libs/xpcom18a4/xpcom/io/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/io/Makefile.in | 175 + .../xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp | 770 +++ .../xpcom18a4/xpcom/io/SpecialSystemDirectory.h | 136 + src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c | 784 +++ src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h | 158 + .../xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h | 120 + .../xpcom/io/nsAppFileLocationProvider.cpp | 608 ++ .../xpcom18a4/xpcom/io/nsAppFileLocationProvider.h | 67 + src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp | 663 +++ src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h | 125 + .../xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp | 164 + .../xpcom18a4/xpcom/io/nsByteArrayInputStream.h | 59 + src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp | 1241 ++++ src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h | 177 + .../xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h | 197 + .../xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h | 61 + src/libs/xpcom18a4/xpcom/io/nsEscape.cpp | 491 ++ src/libs/xpcom18a4/xpcom/io/nsEscape.h | 196 + src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp | 2581 +++++++++ src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h | 566 ++ src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h | 112 + src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp | 571 ++ src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h | 71 + .../xpcom18a4/xpcom/io/nsIAsyncInputStream.idl | 136 + .../xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl | 136 + src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl | 45 + .../xpcom18a4/xpcom/io/nsIBinaryInputStream.idl | 121 + .../xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl | 119 + .../xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl | 48 + .../xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl | 68 + .../xpcom18a4/xpcom/io/nsIDirectoryService.idl | 138 + .../xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl | 123 + src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl | 155 + src/libs/xpcom18a4/xpcom/io/nsIFile.idl | 343 ++ src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl | 139 + src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl | 61 + src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl | 54 + src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl | 180 + src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl | 262 + src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl | 90 + .../xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl | 88 + .../xpcom18a4/xpcom/io/nsIObjectInputStream.idl | 87 + .../xpcom18a4/xpcom/io/nsIObjectOutputStream.idl | 131 + .../xpcom/io/nsIObservableInputStream.idl | 67 + .../xpcom/io/nsIObservableOutputStream.idl | 67 + src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl | 167 + src/libs/xpcom18a4/xpcom/io/nsIPipe.idl | 211 + .../xpcom/io/nsIScriptableInputStream.idl | 73 + src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl | 102 + src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl | 107 + .../xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl | 191 + src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl | 138 + .../xpcom18a4/xpcom/io/nsIUnicharInputStream.h | 94 + src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp | 224 + .../xpcom18a4/xpcom/io/nsLinebreakConverter.cpp | 495 ++ src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h | 156 + src/libs/xpcom18a4/xpcom/io/nsLocalFile.h | 118 + src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp | 278 + src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp | 3554 ++++++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h | 137 + src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp | 1742 ++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h | 113 + src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp | 2542 +++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h | 119 + src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h | 47 + src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp | 1724 ++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h | 132 + src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp | 2440 ++++++++ src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h | 113 + .../xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp | 389 ++ .../xpcom18a4/xpcom/io/nsMultiplexInputStream.h | 63 + .../xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp | 1280 +++++ src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h | 66 + src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp | 1276 +++++ .../xpcom18a4/xpcom/io/nsScriptableInputStream.cpp | 102 + .../xpcom18a4/xpcom/io/nsScriptableInputStream.h | 71 + src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp | 207 + src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h | 125 + src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp | 563 ++ src/libs/xpcom18a4/xpcom/io/nsStorageStream.h | 98 + src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp | 583 ++ src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h | 111 + src/libs/xpcom18a4/xpcom/io/nsStringIO.h | 86 + src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp | 457 ++ src/libs/xpcom18a4/xpcom/io/nsStringStream.h | 84 + .../xpcom18a4/xpcom/io/nsUnicharInputStream.cpp | 415 ++ .../xpcom18a4/xpcom/libxpt/xptcall/porting.html | 13 + .../xpcom18a4/xpcom/libxpt/xptcall/status.html | 13 + src/libs/xpcom18a4/xpcom/obsolete/Makefile.in | 130 + .../xpcom18a4/xpcom/obsolete/component/Makefile.in | 81 + .../xpcom/obsolete/component/nsFileSpecImpl.cpp | 857 +++ .../xpcom/obsolete/component/nsFileSpecImpl.h | 116 + .../xpcom/obsolete/component/nsIRegistry.idl | 186 + .../xpcom/obsolete/component/nsIRegistryUtils.h | 63 + .../xpcom/obsolete/component/nsRegistry.cpp | 2019 +++++++ .../xpcom/obsolete/component/nsRegistry.h | 77 + .../xpcom/obsolete/component/nsXPCOMObsolete.cpp | 57 + .../xpcom/obsolete/component/regExport.cpp | 357 ++ .../xpcom/obsolete/component/xpcomobsoletec.pkg | 6 + src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp | 50 + src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp | 1367 +++++ src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h | 782 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp | 547 ++ .../xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp | 879 +++ src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h | 116 + .../xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp | 1471 +++++ .../xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp | 840 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp | 703 +++ .../xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp | 766 +++ src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp | 392 ++ src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h | 772 +++ src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl | 204 + .../xpcom18a4/xpcom/obsolete/nsIFileStream.cpp | 727 +++ src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h | 157 + src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl | 186 + .../xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h | 63 + .../xpcom/obsolete/nsSpecialSystemDirectory.cpp | 1189 ++++ .../xpcom/obsolete/nsSpecialSystemDirectory.h | 167 + .../xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp | 54 + src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h | 50 + .../xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg | 7 + src/libs/xpcom18a4/xpcom/proxy/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in | 63 + .../xpcom/proxy/public/nsIProxyCreateInstance.idl | 53 + .../xpcom/proxy/public/nsIProxyObjectManager.idl | 87 + .../xpcom/proxy/public/nsProxiedService.h | 164 + .../xpcom18a4/xpcom/proxy/public/nsProxyEvent.h | 183 + .../xpcom18a4/xpcom/proxy/public/nsProxyRelease.h | 112 + src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in | 67 + .../xpcom/proxy/src/nsIProxyCreateInstance.h | 39 + .../xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp | 613 ++ .../xpcom/proxy/src/nsProxyEventClass.cpp | 367 ++ .../xpcom/proxy/src/nsProxyEventObject.cpp | 555 ++ .../xpcom/proxy/src/nsProxyEventPrivate.h | 201 + .../xpcom/proxy/src/nsProxyObjectManager.cpp | 322 ++ .../xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp | 55 + src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in | 60 + .../xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl | 9 + .../xpcom18a4/xpcom/proxy/tests/proxytests.cpp | 553 ++ src/libs/xpcom18a4/xpcom/reflect/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/reflect/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/reflect/Makefile.kup | 0 .../xpcom18a4/xpcom/reflect/xptcall/.cvsignore | 4 + .../xpcom18a4/xpcom/reflect/xptcall/Makefile.in | 49 + .../xpcom18a4/xpcom/reflect/xptcall/Makefile.kup | 0 src/libs/xpcom18a4/xpcom/reflect/xptcall/README | 6 + .../xpcom18a4/xpcom/reflect/xptcall/porting.html | 212 + .../xpcom/reflect/xptcall/public/.cvsignore | 1 + .../xpcom/reflect/xptcall/public/Makefile.in | 54 + .../xpcom/reflect/xptcall/public/genstubs.pl | 78 + .../xpcom/reflect/xptcall/public/xptcall.h | 271 + .../xpcom/reflect/xptcall/public/xptcstubsdecl.inc | 761 +++ .../xpcom/reflect/xptcall/public/xptcstubsdef.inc | 256 + .../xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/Makefile.in | 62 + .../xpcom/reflect/xptcall/src/Makefile.kup | 0 .../xpcom/reflect/xptcall/src/md/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/Makefile.in | 56 + .../xpcom/reflect/xptcall/src/md/Makefile.kup | 0 .../reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp | 148 + .../reflect/xptcall/src/md/mac/xptcinvoke_mac.s | 128 + .../reflect/xptcall/src/md/mac/xptcstubs_mac.cpp | 265 + .../reflect/xptcall/src/md/mac/xptcstubs_mac.s | 78 + .../xpcom/reflect/xptcall/src/md/os2/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/os2/Makefile.in | 72 + .../reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp | 185 + .../xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp | 159 + .../xptcall/src/md/os2/xptcinvoke_vacpp.asm | 268 + .../reflect/xptcall/src/md/os2/xptcstubs_emx.cpp | 153 + .../xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp | 180 + .../reflect/xptcall/src/md/os2/xptcstubs_os2.cpp | 195 + .../reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm | 1563 +++++ .../xpcom/reflect/xptcall/src/md/test/.cvsignore | 2 + .../xpcom/reflect/xptcall/src/md/test/Makefile.in | 50 + .../xpcom/reflect/xptcall/src/md/test/README | 6 + .../xpcom/reflect/xptcall/src/md/test/clean.bat | 5 + .../reflect/xptcall/src/md/test/invoke_test.cpp | 239 + .../reflect/xptcall/src/md/test/mk_invoke.bat | 9 + .../xpcom/reflect/xptcall/src/md/test/mk_stub.bat | 9 + .../reflect/xptcall/src/md/test/stub_test.cpp | 210 + .../xpcom/reflect/xptcall/src/md/unix/.cvsignore | 2 + .../xpcom/reflect/xptcall/src/md/unix/Makefile.in | 416 ++ .../xpcom/reflect/xptcall/src/md/unix/Makefile.kup | 0 .../xptcall/src/md/unix/vtable_layout_x86.cpp | 62 + .../xptcall/src/md/unix/xptc_gcc_x86_unix.h | 92 + .../src/md/unix/xptc_platforms_unixish_x86.h | 161 + .../src/md/unix/xptcinvoke_amd64_darwin.cpp | 218 + .../xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm | 403 ++ .../reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp | 220 + .../xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp | 296 + .../xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp | 213 + .../xptcall/src/md/unix/xptcinvoke_asm_ipf32.s | 145 + .../xptcall/src/md/unix/xptcinvoke_asm_ipf64.s | 145 + .../xptcall/src/md/unix/xptcinvoke_asm_irix.s | 149 + .../xptcall/src/md/unix/xptcinvoke_asm_mips.s | 166 + .../src/md/unix/xptcinvoke_asm_openvms_alpha.s | 99 + .../src/md/unix/xptcinvoke_asm_osf1_alpha.s | 83 + .../xptcall/src/md/unix/xptcinvoke_asm_pa32.s | 131 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s | 146 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s | 161 + .../src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s | 140 + .../xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s | 113 + .../src/md/unix/xptcinvoke_asm_ppc_netbsd.s | 114 + .../src/md/unix/xptcinvoke_asm_ppc_rhapsody.s | 162 + .../src/md/unix/xptcinvoke_asm_sparc_bsdos.s | 121 + .../src/md/unix/xptcinvoke_asm_sparc_linux.s | 67 + .../src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s | 84 + .../src/md/unix/xptcinvoke_asm_sparc_netbsd.s | 71 + .../src/md/unix/xptcinvoke_asm_sparc_solaris.s | 71 + .../src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s | 71 + .../md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s | 70 + .../md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s | 72 + .../md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s | 103 + .../src/md/unix/xptcinvoke_gcc_x86_unix.cpp | 215 + .../xptcall/src/md/unix/xptcinvoke_ipf32.cpp | 164 + .../xptcall/src/md/unix/xptcinvoke_ipf64.cpp | 133 + .../xptcall/src/md/unix/xptcinvoke_irix.cpp | 173 + .../xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp | 181 + .../xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp | 170 + .../xptcall/src/md/unix/xptcinvoke_linux_s390.cpp | 254 + .../xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp | 250 + .../xptcall/src/md/unix/xptcinvoke_mips.cpp | 122 + .../xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp | 175 + .../src/md/unix/xptcinvoke_openvms_alpha.cpp | 107 + .../xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp | 93 + .../xptcall/src/md/unix/xptcinvoke_pa32.cpp | 181 + .../xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp | 106 + .../xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp | 95 + .../xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp | 141 + .../xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp | 147 + .../src/md/unix/xptcinvoke_ppc_rhapsody.cpp | 145 + .../src/md/unix/xptcinvoke_sparc_netbsd.cpp | 156 + .../src/md/unix/xptcinvoke_sparc_solaris.cpp | 156 + .../src/md/unix/xptcinvoke_sparcv9_solaris.cpp | 107 + .../xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp | 187 + .../xptcall/src/md/unix/xptcinvoke_unsupported.cpp | 48 + .../src/md/unix/xptcinvoke_x86_64_linux.cpp | 227 + .../xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp | 285 + .../xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp | 243 + .../reflect/xptcall/src/md/unix/xptcstubs_arm.cpp | 244 + .../xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp | 272 + .../xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp | 145 + .../xptcall/src/md/unix/xptcstubs_asm_ipf32.s | 124 + .../xptcall/src/md/unix/xptcstubs_asm_ipf64.s | 124 + .../xptcall/src/md/unix/xptcstubs_asm_irix.s | 97 + .../xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 | 109 + .../src/md/unix/xptcstubs_asm_openvms_alpha.s | 115 + .../xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s | 75 + .../xptcall/src/md/unix/xptcstubs_asm_pa32.s | 68 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s | 117 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s | 137 + .../src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 | 126 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s | 89 + .../xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s | 89 + .../src/md/unix/xptcstubs_asm_sparc_netbsd.s | 65 + .../src/md/unix/xptcstubs_asm_sparc_solaris.s | 65 + .../src/md/unix/xptcstubs_asm_sparcv9_solaris.s | 67 + .../xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp | 202 + .../xptcall/src/md/unix/xptcstubs_ipf32.cpp | 185 + .../xptcall/src/md/unix/xptcstubs_ipf64.cpp | 186 + .../reflect/xptcall/src/md/unix/xptcstubs_irix.cpp | 226 + .../xptcall/src/md/unix/xptcstubs_linux_alpha.cpp | 236 + .../xptcall/src/md/unix/xptcstubs_linux_m68k.cpp | 146 + .../xptcall/src/md/unix/xptcstubs_linux_s390.cpp | 220 + .../xptcall/src/md/unix/xptcstubs_linux_s390x.cpp | 224 + .../reflect/xptcall/src/md/unix/xptcstubs_mips.cpp | 131 + .../xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp | 147 + .../src/md/unix/xptcstubs_openvms_alpha.cpp | 147 + .../xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp | 149 + .../reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp | 176 + .../xptcall/src/md/unix/xptcstubs_ppc_aix.cpp | 228 + .../xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp | 215 + .../xptcall/src/md/unix/xptcstubs_ppc_linux.cpp | 253 + .../xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp | 217 + .../xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp | 254 + .../xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp | 146 + .../src/md/unix/xptcstubs_sparc_solaris.cpp | 146 + .../src/md/unix/xptcstubs_sparcv9_solaris.cpp | 139 + .../xptcall/src/md/unix/xptcstubs_unixish_x86.cpp | 188 + .../xptcall/src/md/unix/xptcstubs_unsupported.cpp | 56 + .../xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp | 242 + .../src/md/unix/xptcstubs_x86_64_solaris.cpp | 271 + .../xptcall/src/md/unix/xptcstubs_x86_solaris.cpp | 165 + .../xpcom/reflect/xptcall/src/md/win32/.cvsignore | 1 + .../xpcom/reflect/xptcall/src/md/win32/Makefile.in | 82 + .../reflect/xptcall/src/md/win32/xptcinvoke.cpp | 107 + .../xptcall/src/md/win32/xptcinvoke_alpha.cpp | 171 + .../xptcall/src/md/win32/xptcinvoke_asm_alpha.s | 128 + .../reflect/xptcall/src/md/win32/xptcstubs.cpp | 202 + .../xptcall/src/md/win32/xptcstubs_alpha.cpp | 228 + .../xptcall/src/md/win32/xptcstubs_asm_alpha.s | 120 + .../xpcom/reflect/xptcall/src/xptcall.cpp | 62 + .../xpcom/reflect/xptcall/src/xptcprivate.h | 45 + .../xpcom18a4/xpcom/reflect/xptcall/status.html | 404 ++ .../xpcom/reflect/xptcall/tests/.cvsignore | 2 + .../xpcom/reflect/xptcall/tests/Makefile.in | 64 + .../xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp | 1464 +++++ .../xpcom18a4/xpcom/reflect/xptinfo/.cvsignore | 1 + .../xpcom18a4/xpcom/reflect/xptinfo/Makefile.in | 49 + .../xpcom/reflect/xptinfo/public/.cvsignore | 1 + .../xpcom/reflect/xptinfo/public/Makefile.in | 66 + .../reflect/xptinfo/public/nsIInterfaceInfo.idl | 137 + .../xptinfo/public/nsIInterfaceInfoManager.idl | 85 + .../xpcom/reflect/xptinfo/public/nsIXPTLoader.idl | 100 + .../xpcom/reflect/xptinfo/public/xptinfo.h | 281 + .../xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore | 1 + .../xpcom/reflect/xptinfo/src/Makefile.in | 75 + src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO | 20 + .../xpcom/reflect/xptinfo/src/xptiFile.cpp | 113 + .../reflect/xptinfo/src/xptiInterfaceInfo.cpp | 819 +++ .../xptinfo/src/xptiInterfaceInfoManager.cpp | 2126 +++++++ .../xpcom/reflect/xptinfo/src/xptiManifest.cpp | 710 +++ .../xpcom/reflect/xptinfo/src/xptiMisc.cpp | 164 + .../xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp | 63 + .../xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp | 432 ++ .../xpcom/reflect/xptinfo/src/xptiZipItem.cpp | 102 + .../xpcom/reflect/xptinfo/src/xptiZipLoader.cpp | 113 + .../xpcom/reflect/xptinfo/src/xptiprivate.h | 981 ++++ .../xpcom/reflect/xptinfo/tests/.cvsignore | 2 + .../xpcom/reflect/xptinfo/tests/Makefile.in | 58 + .../reflect/xptinfo/tests/TestInterfaceInfo.cpp | 146 + src/libs/xpcom18a4/xpcom/sample/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/sample/Makefile.in | 113 + src/libs/xpcom18a4/xpcom/sample/nsISample.idl | 66 + src/libs/xpcom18a4/xpcom/sample/nsSample.cpp | 181 + src/libs/xpcom18a4/xpcom/sample/nsSample.h | 129 + src/libs/xpcom18a4/xpcom/sample/nsSample.js | 130 + src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp | 131 + src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp | 158 + src/libs/xpcom18a4/xpcom/sample/win32.order | 1 + .../xpcom18a4/xpcom/sample/xpconnect-sample.html | 220 + src/libs/xpcom18a4/xpcom/string/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/Makefile.in | 54 + src/libs/xpcom18a4/xpcom/string/README.html | 44 + src/libs/xpcom18a4/xpcom/string/doc/README.html | 44 + .../xpcom18a4/xpcom/string/doc/string-guide.html | 2508 ++++++++ src/libs/xpcom18a4/xpcom/string/public/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/public/Makefile.in | 86 + src/libs/xpcom18a4/xpcom/string/public/nsAString.h | 96 + .../xpcom18a4/xpcom/string/public/nsAlgorithm.h | 131 + .../xpcom18a4/xpcom/string/public/nsCharTraits.h | 784 +++ .../xpcom/string/public/nsDependentString.h | 60 + .../xpcom/string/public/nsDependentSubstring.h | 56 + .../xpcom18a4/xpcom/string/public/nsEmbedString.h | 158 + .../xpcom/string/public/nsLiteralString.h | 116 + .../xpcom/string/public/nsObsoleteAString.h | 102 + .../xpcom/string/public/nsPrintfCString.h | 87 + .../xpcom/string/public/nsPromiseFlatString.h | 56 + .../xpcom/string/public/nsReadableUtils.h | 370 ++ src/libs/xpcom18a4/xpcom/string/public/nsString.h | 237 + .../xpcom18a4/xpcom/string/public/nsStringAPI.h | 853 +++ .../xpcom18a4/xpcom/string/public/nsStringFwd.h | 96 + .../xpcom/string/public/nsStringIterator.h | 373 ++ .../xpcom18a4/xpcom/string/public/nsSubstring.h | 74 + .../xpcom/string/public/nsSubstringTuple.h | 56 + .../xpcom18a4/xpcom/string/public/nsTAString.h | 618 ++ .../xpcom/string/public/nsTDependentString.h | 137 + .../xpcom/string/public/nsTDependentSubstring.h | 143 + .../xpcom/string/public/nsTObsoleteAString.h | 165 + .../xpcom/string/public/nsTPromiseFlatString.h | 158 + src/libs/xpcom18a4/xpcom/string/public/nsTString.h | 721 +++ .../xpcom18a4/xpcom/string/public/nsTSubstring.h | 575 ++ .../xpcom/string/public/nsTSubstringTuple.h | 113 + .../xpcom18a4/xpcom/string/public/nsUTF8Utils.h | 462 ++ .../xpcom18a4/xpcom/string/public/nsXPIDLString.h | 46 + .../xpcom/string/public/string-template-def-char.h | 58 + .../string/public/string-template-def-unichar.h | 58 + .../xpcom/string/public/string-template-undef.h | 59 + src/libs/xpcom18a4/xpcom/string/src/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/string/src/Makefile.in | 77 + src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp | 51 + .../xpcom/string/src/nsDependentSubstring.cpp | 50 + .../xpcom/string/src/nsObsoleteAStringThunk.cpp | 52 + .../xpcom18a4/xpcom/string/src/nsPrintfCString.cpp | 83 + .../xpcom/string/src/nsPromiseFlatString.cpp | 49 + .../xpcom18a4/xpcom/string/src/nsReadableUtils.cpp | 1122 ++++ src/libs/xpcom18a4/xpcom/string/src/nsString.cpp | 49 + .../xpcom/string/src/nsStringComparator.cpp | 75 + .../xpcom/string/src/nsStringObsolete.cpp | 1327 +++++ .../xpcom18a4/xpcom/string/src/nsSubstring.cpp | 250 + .../xpcom/string/src/nsSubstringTuple.cpp | 64 + src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp | 509 ++ .../xpcom/string/src/nsTDependentSubstring.cpp | 65 + .../xpcom/string/src/nsTObsoleteAStringThunk.cpp | 235 + .../xpcom/string/src/nsTPromiseFlatString.cpp | 66 + src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp | 63 + .../xpcom/string/src/nsTStringComparator.cpp | 79 + .../xpcom/string/src/nsTStringObsolete.cpp | 518 ++ .../xpcom18a4/xpcom/string/src/nsTSubstring.cpp | 656 +++ .../xpcom/string/src/nsTSubstringTuple.cpp | 127 + src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp | 261 + src/libs/xpcom18a4/xpcom/tests/.cvsignore | 31 + src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp | 126 + src/libs/xpcom18a4/xpcom/tests/Makefile.in | 116 + src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp | 162 + src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp | 107 + src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp | 93 + src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp | 101 + src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp | 72 + src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp | 78 + src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp | 231 + .../xpcom/tests/StringFactoringTests/Makefile.in | 76 + .../tests/StringFactoringTests/StringTest.Prefix | 4 + .../tests/StringFactoringTests/StringTest.mcp | Bin 0 -> 245184 bytes .../StringFactoringTests/StringTestDebug.Prefix | 4 + .../StringTestNo_wchar_t.Prefix | 5 + .../StringTestProfileNew.Prefix | 3 + .../StringTestProfileOld.Prefix | 6 + .../StringTestProfileStd.Prefix | 7 + .../xpcom/tests/StringFactoringTests/ToDo.doc | 41 + .../StringFactoringTests/nsStdStringWrapper.h | 234 + .../tests/StringFactoringTests/profile_main.cpp | 497 ++ .../xpcom/tests/StringFactoringTests/test_main.cpp | 651 +++ src/libs/xpcom18a4/xpcom/tests/TestArray.cpp | 230 + src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp | 132 + src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp | 91 + src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp | 566 ++ src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp | 651 +++ src/libs/xpcom18a4/xpcom/tests/TestCOMPtrEq.cpp | 200 + src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp | 112 + .../xpcom18a4/xpcom/tests/TestCallTemplates.cpp | 129 + src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp | 155 + src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp | 160 + src/libs/xpcom18a4/xpcom/tests/TestFactory.h | 69 + src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp | 939 +++ src/libs/xpcom18a4/xpcom/tests/TestID.cpp | 77 + .../xpcom18a4/xpcom/tests/TestMinStringAPI.cpp | 333 ++ .../xpcom18a4/xpcom/tests/TestObserverService.cpp | 250 + .../xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp | 88 + src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp | 655 +++ src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp | 173 + src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp | 78 + src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp | 11 + src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp | 643 +++ src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp | 280 + src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp | 302 + src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp | 18 + src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in | 61 + .../xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp | 76 + src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order | 1 + .../xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp | 95 + src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp | 475 ++ src/libs/xpcom18a4/xpcom/tests/resources.h | 52 + src/libs/xpcom18a4/xpcom/tests/services/.cvsignore | 1 + .../xpcom18a4/xpcom/tests/services/Makefile.in | 58 + .../xpcom18a4/xpcom/tests/services/MyService.cpp | 93 + .../xpcom18a4/xpcom/tests/services/MyService.h | 69 + .../xpcom18a4/xpcom/tests/services/win32.order | 1 + src/libs/xpcom18a4/xpcom/tests/test.properties | 46 + src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp | 61 + src/libs/xpcom18a4/xpcom/tests/utils/cp.js | 111 + src/libs/xpcom18a4/xpcom/tests/utils/dirs.js | 155 + src/libs/xpcom18a4/xpcom/tests/utils/ls.js | 64 + src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in | 60 + src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp | 181 + .../xpcom/tests/windows/TestHelloXPLoop.cpp | 177 + .../xpcom18a4/xpcom/tests/windows/nsStringTest.cpp | 33 + .../xpcom18a4/xpcom/tests/windows/nsStringTest.h | 2277 ++++++++ .../xpcom18a4/xpcom/tests/windows/nsStringTest2.h | 444 ++ src/libs/xpcom18a4/xpcom/threads/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/threads/Makefile.in | 105 + src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp | 462 ++ src/libs/xpcom18a4/xpcom/threads/TimerThread.h | 122 + src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp | 435 ++ src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h | 383 ++ src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp | 202 + src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h | 67 + src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp | 632 ++ src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h | 89 + .../xpcom/threads/nsEventQueueService.cpp | 450 ++ .../xpcom18a4/xpcom/threads/nsEventQueueService.h | 77 + .../xpcom18a4/xpcom/threads/nsEventQueueUtils.h | 78 + .../xpcom18a4/xpcom/threads/nsIEnvironment.idl | 89 + src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl | 107 + .../xpcom/threads/nsIEventQueueService.idl | 151 + .../xpcom18a4/xpcom/threads/nsIEventTarget.idl | 67 + src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl | 32 + src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl | 44 + src/libs/xpcom18a4/xpcom/threads/nsIThread.idl | 144 + src/libs/xpcom18a4/xpcom/threads/nsITimer.idl | 191 + .../xpcom18a4/xpcom/threads/nsITimerInternal.idl | 48 + .../xpcom18a4/xpcom/threads/nsITimerManager.idl | 61 + .../xpcom18a4/xpcom/threads/nsPIEventQueueChain.h | 93 + src/libs/xpcom18a4/xpcom/threads/nsProcess.h | 71 + .../xpcom18a4/xpcom/threads/nsProcessCommon.cpp | 363 ++ src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp | 188 + src/libs/xpcom18a4/xpcom/threads/nsThread.cpp | 457 ++ src/libs/xpcom18a4/xpcom/threads/nsThread.h | 92 + src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp | 642 +++ src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h | 195 + src/libs/xpcom18a4/xpcom/threads/plevent.c | 1774 ++++++ src/libs/xpcom18a4/xpcom/threads/plevent.h | 690 +++ src/libs/xpcom18a4/xpcom/tools/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tools/Makefile.in | 53 + .../xpcom18a4/xpcom/tools/analyze-xpcom-log.pl | 177 + src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore | 3 + .../xpcom18a4/xpcom/tools/registry/Makefile.in | 77 + .../xpcom18a4/xpcom/tools/registry/regxpcom.cpp | 404 ++ src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in | 52 + .../xpcom18a4/xpcom/tools/windows/rebasedlls.cpp | 104 + src/libs/xpcom18a4/xpcom/typelib/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/typelib/Makefile.in | 49 + src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore | 2 + src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in | 88 + src/libs/xpcom18a4/xpcom/typelib/xpidl/README | 16 + .../xpcom/typelib/xpidl/macplugin/compiler.rsrc | Bin 0 -> 915 bytes .../xpcom/typelib/xpidl/macplugin/linker.rsrc | Bin 0 -> 984 bytes .../xpcom/typelib/xpidl/macplugin/mac_console.c | 139 + .../xpcom/typelib/xpidl/macplugin/mac_console.h | 49 + .../xpcom/typelib/xpidl/macplugin/mac_memory.cpp | 146 + .../xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp | 58 + .../xpcom/typelib/xpidl/macplugin/mac_strings.cpp | 38 + .../xpcom/typelib/xpidl/macplugin/mac_strings.h | 47 + .../xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp | 417 ++ .../xpcom/typelib/xpidl/macplugin/mac_xpidl.h | 25 + .../typelib/xpidl/macplugin/mac_xpidl_panel.cpp | 695 +++ .../typelib/xpidl/macplugin/mac_xpidl_panel.h | 106 + .../typelib/xpidl/macplugin/mac_xpt_linker.cpp | 546 ++ .../xpcom/typelib/xpidl/macplugin/panel.rsrc | Bin 0 -> 16238 bytes .../xpcom/typelib/xpidl/macplugin/version.rsrc | Bin 0 -> 755 bytes src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c | 275 + src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h | 278 + src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c | 312 + .../xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c | 1196 ++++ src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c | 836 +++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c | 1053 ++++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c | 1237 ++++ .../xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c | 851 +++ src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in | 50 + .../xpcom18a4/xpcom/typelib/xpt/public/.cvsignore | 1 + .../xpcom18a4/xpcom/typelib/xpt/public/Makefile.in | 51 + .../xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h | 145 + .../xpcom/typelib/xpt/public/xpt_struct.h | 562 ++ .../xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h | 240 + .../xpcom18a4/xpcom/typelib/xpt/src/.cvsignore | 1 + .../xpcom18a4/xpcom/typelib/xpt/src/Makefile.in | 76 + .../xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c | 358 ++ .../xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c | 956 ++++ src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c | 665 +++ .../xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore | 3 + .../xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in | 59 + .../xpcom/typelib/xpt/tests/PrimitiveTest.c | 157 + .../xpcom/typelib/xpt/tests/SimpleTypeLib.c | 192 + .../xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore | 3 + .../xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in | 90 + .../xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c | 941 +++ .../xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c | 883 +++ src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in | 50 + src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp | 60 + src/libs/xpcom18a4/xpcom/xpcom-config.h.in | 65 + src/libs/xpcom18a4/xpcom/xpcom-private.h.in | 31 + 1802 files changed, 493877 insertions(+) create mode 100644 src/libs/xpcom18a4/Config.kmk create mode 100644 src/libs/xpcom18a4/Makefile.kmk create mode 100644 src/libs/xpcom18a4/VBoxXPCOM-mangled.def create mode 100644 src/libs/xpcom18a4/VBoxXPCOM.def create mode 100644 src/libs/xpcom18a4/dependentLibs.h create mode 100644 src/libs/xpcom18a4/ipc/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/ipc.pkg create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp create mode 100644 src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp create mode 100644 src/libs/xpcom18a4/java/Makefile.kmk create mode 100644 src/libs/xpcom18a4/java/README.vbox create mode 100644 src/libs/xpcom18a4/java/src/MacJawt.mm create mode 100644 src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h create mode 100644 src/libs/xpcom18a4/java/src/nsFileStreams.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsFileStreams.h create mode 100644 src/libs/xpcom18a4/java/src/nsIFileStreams.h create mode 100644 src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaInterfaces.h create mode 100644 src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaWrapper.h create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp create mode 100644 src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h create mode 100644 src/libs/xpcom18a4/java/src/nsThreadUtils.h create mode 100644 src/libs/xpcom18a4/java/src/nsXPTCUtils.h create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java create mode 100644 src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java create mode 100644 src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java create mode 100755 src/libs/xpcom18a4/java/tools/gen-nsError.pl create mode 100644 src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp create mode 100644 src/libs/xpcom18a4/java/tools/genjifaces.xsl create mode 100644 src/libs/xpcom18a4/nsBuildID.h create mode 100644 src/libs/xpcom18a4/nsprpub/Makefile.in create mode 100755 src/libs/xpcom18a4/nsprpub/admin/explode.pl create mode 100755 src/libs/xpcom18a4/nsprpub/admin/makeTargetDirs.sh create mode 100755 src/libs/xpcom18a4/nsprpub/admin/repackage.sh create mode 100755 src/libs/xpcom18a4/nsprpub/admin/symlinks.sh create mode 100644 src/libs/xpcom18a4/nsprpub/config/.cvsignore create mode 100755 src/libs/xpcom18a4/nsprpub/config/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/config/autoconf.mk.in create mode 100644 src/libs/xpcom18a4/nsprpub/config/config.mk create mode 100644 src/libs/xpcom18a4/nsprpub/config/libc_r.h create mode 100755 src/libs/xpcom18a4/nsprpub/config/nfspwd.pl create mode 100644 src/libs/xpcom18a4/nsprpub/config/now.c create mode 100644 src/libs/xpcom18a4/nsprpub/config/nsinstall.c create mode 100755 src/libs/xpcom18a4/nsprpub/config/nspr-config.in create mode 100644 src/libs/xpcom18a4/nsprpub/config/nspr.m4 create mode 100644 src/libs/xpcom18a4/nsprpub/config/nsprincl.mk.in create mode 100644 src/libs/xpcom18a4/nsprpub/config/nsprincl.sh.in create mode 100644 src/libs/xpcom18a4/nsprpub/config/pathsub.h create mode 100644 src/libs/xpcom18a4/nsprpub/config/prdepend.h create mode 100644 src/libs/xpcom18a4/nsprpub/config/prmkdir.bat create mode 100644 src/libs/xpcom18a4/nsprpub/config/rules.mk create mode 100755 src/libs/xpcom18a4/nsprpub/configure create mode 100644 src/libs/xpcom18a4/nsprpub/configure.in create mode 100644 src/libs/xpcom18a4/nsprpub/gmakefile.win create mode 100644 src/libs/xpcom18a4/nsprpub/lib/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/MANIFEST create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plarena.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plarena.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plarenas.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plds.def create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plds.rc create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plds_symvec.opt create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plhash.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plhash.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/ds/plvrsion.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/README create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/MANIFEST create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/README create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/plbase64.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/plerror.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/plgetopt.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/plresolv.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/include/plstr.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/README create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/base64.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.def create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.rc create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plc_symvec.opt create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plerror.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plgetopt.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/plvrsion.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strcat.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strccmp.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strchr.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strcmp.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strcpy.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strcstr.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strdup.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strlen.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strpbrk.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strstr.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/libc/src/strtok.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/include/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/include/MANIFEST create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/include/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/include/gcint.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/include/prgc.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/macgc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/os2gc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/prgcapi.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/prmsgc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/unixgc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/win16gc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/src/win32gc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/tests/gc1.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/msgc/tests/thrashgc.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/plvrsion.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.h create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.rc create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/arena.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/base64t.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/string.c create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/windows/makefile create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/windows/readme.1st create mode 100644 src/libs/xpcom18a4/nsprpub/lib/tests/windows/winevent.c create mode 100644 src/libs/xpcom18a4/nsprpub/makefile.win create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/linux/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/linux/sun-nspr.spec create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.com create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.targ create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/depend create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_com create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_i386 create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_sparc create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/depend create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/pkginfo.tmpl create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_com create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_sparc create mode 100755 src/libs/xpcom18a4/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh create mode 100644 src/libs/xpcom18a4/nsprpub/pkg/solaris/common_files/copyright create mode 100644 src/libs/xpcom18a4/nsprpub/pr/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/MANIFEST create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/gencfg.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_aix.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_aix32.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_aix64.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux32.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux64.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_iprt_atomic.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_irix.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_irix32.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_irix64.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_macos.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nspr_pthread.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_os2_errors.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_pcos.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_pth.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris32.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris64.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_unix_errors.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_unixos.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware7.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_vbox.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_win32_errors.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.cfg create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/prosdep.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/md/sunos4.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/nspr.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/pralarm.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/probslet.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/protypes.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/obsolete/prsem.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/pratom.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prbit.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prclist.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prcmon.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prcountr.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prcvar.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prdtoa.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prenv.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prerr.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prerror.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prinet.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prinit.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prinrval.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/pripcsem.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/pprio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/pprmwait.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/pprthred.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/primpl.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/private/prpriv.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prlink.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prlock.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prlog.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prlong.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prmem.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prmon.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prmwait.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prnetdb.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prolock.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prpdce.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prprf.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prproces.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prrng.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prrwlock.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prshm.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prshma.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prsystem.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prthread.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prtime.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prtpool.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prtrace.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prtypes.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prvrsion.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/include/prwin16.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/bsrcs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btcvar.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btlocks.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmisc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmon.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btsem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btthread.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/bthreads/objs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcascii.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcmon.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/fileio.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/interval.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/ranfile.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/switch.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/thread.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/time.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/tpd.cpp create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prdir.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prfdcach.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/priometh.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prlog.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prmapopt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prmmap.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prmwait.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prpolevt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prprf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prscanf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prsocket.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/io/prstdio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/linking/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/linking/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/linking/prlink.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/malloc/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/malloc/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmalloc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bcpu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos_errors.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmemory.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmisc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmmap.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bnet.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bproc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/brng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bseg.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bsrcs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/btime.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/beos/objs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MANIFEST create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/MacErrorHandling.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macrng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsocket.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macsockotpt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macthr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mactime.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdcriticalregion.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/mdmac.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/mac/prcpucfg.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/objs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2_errors.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2cv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2emx.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2gc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2inrval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2io.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2poll.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2rng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2thred.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vaclegacy.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vacpp.asm create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/prosdep.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aix.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aixwrap.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/bsdi.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/darwin.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/dgux.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/freebsd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/hpux.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/irix.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/linux.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/ncr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nec.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/netbsd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nextstep.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nto.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/objs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openbsd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openvms.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_AIX.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_BSD_386_2.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_ppc.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_x86.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_HPUX.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Irix.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_ia64.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86_64.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_ReliantUNIX.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_32.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/osf1.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/pthreads_user.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/qnx.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/reliantunix.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/rhapsody.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/scoos.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/solaris.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sony.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sunos4.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix_errors.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unixware.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxpoll.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxrng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxshm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxwrap.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntdllmn.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntgc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntinrval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntmisc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsec.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntthread.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/objs.mk create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16callb.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16error.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16fmem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16gc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16io.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16mem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16null.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16proc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16sock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16stdio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16thred.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32ipcsem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32poll.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32rng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32shm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95cv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95dllmain.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95io.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95sock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95thred.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/md/windows/win32_errors.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/prgcleak.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/prseg.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/prshm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/memory/prshma.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/Makefile.in create mode 100755 src/libs/xpcom18a4/nsprpub/pr/src/misc/compile-et.pl create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/pralarm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/pratom.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prcountr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prdtoa.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prenv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.et create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.properties create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prerror.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prerrortable.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prinit.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prinrval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/pripc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/pripcsem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prlog2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prlong.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prnetdb.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prolock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prrng.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prsystem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prthinfo.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prtime.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prtpool.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/misc/prtrace.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/nspr.def create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/nspr.rc create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/nspr_symvec.opt create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/os2extra.def create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/prvrsion.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptmisc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/README create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucpu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prulock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prustack.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/pruthr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prcmon.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prcthr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prdump.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prmon.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prrwlock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prsem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/src/threads/prtpd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/README.TXT create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/accept.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/acceptread.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/acceptreademu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/addrstr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/affinity.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/alarm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/anonfm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/append.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/atomic.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/attach.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/bigfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/bigfile2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/bigfile3.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/bug1test.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/cleanup.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/cltsrv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/concur.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/cvar.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/cvar2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc1.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dceemu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/depend.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dll/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dll/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dll/my.def create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dll/mygetval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dll/mysetval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dlltest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/dtoa.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/env.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/errcodes.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/errset.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/exit.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/fdcach.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/fileio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/foreign.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/forktest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/formattm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/freeif.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/fsync.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/getai.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/gethost.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/getproto.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/i2l.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/initclk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/inrval.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/instrumt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/intrio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/intrupt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/io_timeout.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ioconthr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ipv6.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/join.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/joinkk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/joinku.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/joinuk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/joinuu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/layer.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/lazyinit.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/libfilename.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/lltest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/lock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/lockfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/logger.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/makedir.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/many_cv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/mbcs.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/multiacc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/multiwait.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/nameshm1.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/nbconn.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/nblayer.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/nonblock.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ntioto.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ntoh.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/obsints.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_2long.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_excl.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_filnf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_filok.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_noacc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/op_nofil.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/openfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/parent.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/peek.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/perf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pipeping.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pipeping2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pipepong.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pipepong2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pipeself.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/poll_er.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/poll_nm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/poll_to.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/pollable.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prftest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prftest1.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prftest2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/primblok.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/priotest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/provider.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prpoll.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prpollml.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prselect.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/prttools.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/randseed.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ranfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/rmdir.c create mode 100755 src/libs/xpcom18a4/nsprpub/pr/tests/runtests.ksh create mode 100755 src/libs/xpcom18a4/nsprpub/pr/tests/runtests.sh create mode 100755 src/libs/xpcom18a4/nsprpub/pr/tests/runy2ktests.ksh create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/rwlocktest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sel_spd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/selct_er.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/selct_nm.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/selct_to.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/select2.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/selintr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sem.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sema.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/semaerr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/semaerr1.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/semaping.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/semapong.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sendzlf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/servr_kk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/servr_ku.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/servr_uk.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/servr_uu.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/short_thread.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sigpipe.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sleep.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/socket.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sockopt.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sockping.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sockpong.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sprintf.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sproc_ch.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/sproc_p.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/stack.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/stat.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/stdio.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/str2addr.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/strod.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/suspend.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/switch.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/system.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/testbit.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/testfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/threads.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/thrpool_client.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/thrpool_server.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/thruput.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/time.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/timemac.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/timetest.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/tmoacc.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/tmocon.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/tpd.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/udpsrv.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/ut_ttools.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/vercheck.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/version.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfile.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfind.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfont.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.h create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.ico create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.rc create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popprnt0.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/readme.1st create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/writev.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/xnotify.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/y2k.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/y2ktmo.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/yield.c create mode 100644 src/libs/xpcom18a4/nsprpub/pr/tests/zerolen.c create mode 100644 src/libs/xpcom18a4/nsprpub/tools/.cvsignore create mode 100644 src/libs/xpcom18a4/nsprpub/tools/Makefile.in create mode 100644 src/libs/xpcom18a4/nsprpub/tools/httpget.c create mode 100644 src/libs/xpcom18a4/nsprpub/tools/tail.c create mode 100644 src/libs/xpcom18a4/python/.cvsignore create mode 100644 src/libs/xpcom18a4/python/Makefile.kmk create mode 100644 src/libs/xpcom18a4/python/README.vbox create mode 100755 src/libs/xpcom18a4/python/__init__.py create mode 100644 src/libs/xpcom18a4/python/client/.cvsignore create mode 100755 src/libs/xpcom18a4/python/client/__init__.py create mode 100755 src/libs/xpcom18a4/python/components.py create mode 100644 src/libs/xpcom18a4/python/doc/advanced.html create mode 100644 src/libs/xpcom18a4/python/doc/architecture.html create mode 100644 src/libs/xpcom18a4/python/doc/configure.html create mode 100644 src/libs/xpcom18a4/python/doc/credits.html create mode 100644 src/libs/xpcom18a4/python/doc/tutorial.html create mode 100755 src/libs/xpcom18a4/python/file.py create mode 100755 src/libs/xpcom18a4/python/gen_python_deps.py create mode 100755 src/libs/xpcom18a4/python/nsError.py create mode 100755 src/libs/xpcom18a4/python/primitives.py create mode 100644 src/libs/xpcom18a4/python/readme.html create mode 100644 src/libs/xpcom18a4/python/server/.cvsignore create mode 100755 src/libs/xpcom18a4/python/server/__init__.py create mode 100755 src/libs/xpcom18a4/python/server/enumerator.py create mode 100755 src/libs/xpcom18a4/python/server/factory.py create mode 100755 src/libs/xpcom18a4/python/server/loader.py create mode 100755 src/libs/xpcom18a4/python/server/module.py create mode 100755 src/libs/xpcom18a4/python/server/policy.py create mode 100644 src/libs/xpcom18a4/python/src/ErrorUtils.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGBase.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGInputStream.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGModule.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGStub.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyGWeakReference.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIClassInfo.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIComponentManager.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIEnumerator.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIID.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInputStream.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyISupports.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyIVariant.cpp create mode 100644 src/libs/xpcom18a4/python/src/PyXPCOM.h create mode 100644 src/libs/xpcom18a4/python/src/PyXPCOM_std.h create mode 100644 src/libs/xpcom18a4/python/src/Pyxpt_info.cpp create mode 100644 src/libs/xpcom18a4/python/src/TypeObject.cpp create mode 100644 src/libs/xpcom18a4/python/src/VariantUtils.cpp create mode 100644 src/libs/xpcom18a4/python/src/dllmain.cpp create mode 100644 src/libs/xpcom18a4/python/src/loader/pyloader.cpp create mode 100644 src/libs/xpcom18a4/python/src/module/_xpcom.cpp create mode 100644 src/libs/xpcom18a4/python/src/readme.html create mode 100644 src/libs/xpcom18a4/python/test/.cvsignore create mode 100644 src/libs/xpcom18a4/python/test/output/test_com_exceptions create mode 100644 src/libs/xpcom18a4/python/test/output/test_comfile create mode 100644 src/libs/xpcom18a4/python/test/output/test_components create mode 100644 src/libs/xpcom18a4/python/test/output/test_isupports_primitives create mode 100644 src/libs/xpcom18a4/python/test/output/test_streams create mode 100644 src/libs/xpcom18a4/python/test/output/test_test_component create mode 100644 src/libs/xpcom18a4/python/test/output/test_weakreferences create mode 100755 src/libs/xpcom18a4/python/test/pyxpcom_test_tools.py create mode 100644 src/libs/xpcom18a4/python/test/regrtest.py create mode 100755 src/libs/xpcom18a4/python/test/test_com_exceptions.py create mode 100755 src/libs/xpcom18a4/python/test/test_comfile.py create mode 100644 src/libs/xpcom18a4/python/test/test_component/_xpidlgen/.done create mode 100644 src/libs/xpcom18a4/python/test/test_component/_xpidlgen/py_test_component.h create mode 100644 src/libs/xpcom18a4/python/test/test_component/py_test_component.html create mode 100644 src/libs/xpcom18a4/python/test/test_component/py_test_component.idl create mode 100755 src/libs/xpcom18a4/python/test/test_component/py_test_component.py create mode 100755 src/libs/xpcom18a4/python/test/test_components.py create mode 100755 src/libs/xpcom18a4/python/test/test_isupports_primitives.py create mode 100755 src/libs/xpcom18a4/python/test/test_misc.py create mode 100755 src/libs/xpcom18a4/python/test/test_streams.py create mode 100644 src/libs/xpcom18a4/python/test/test_test_component.js create mode 100755 src/libs/xpcom18a4/python/test/test_test_component.py create mode 100755 src/libs/xpcom18a4/python/test/test_weakreferences.py create mode 100755 src/libs/xpcom18a4/python/tools/regxpcom.py create mode 100755 src/libs/xpcom18a4/python/tools/tracer_demo.py create mode 100755 src/libs/xpcom18a4/python/vboxxpcom.py create mode 100644 src/libs/xpcom18a4/python/xpcom_consts.py create mode 100755 src/libs/xpcom18a4/python/xpt.py create mode 100644 src/libs/xpcom18a4/vboxdeps.cpp create mode 100644 src/libs/xpcom18a4/xpcom-config.h create mode 100644 src/libs/xpcom18a4/xpcom-namespace-cleanup.map create mode 100644 src/libs/xpcom18a4/xpcom-private.h create mode 100644 src/libs/xpcom18a4/xpcom/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c create mode 100644 src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h create mode 100644 src/libs/xpcom18a4/xpcom/base/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/base/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAgg.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsCom.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsConsoleService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsError.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsErrorService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsExceptionService.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsID.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsID.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIDebug.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIException.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIID.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIMemory.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupports.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nscore.h create mode 100644 src/libs/xpcom18a4/xpcom/base/nsrootidl.idl create mode 100644 src/libs/xpcom18a4/xpcom/base/pure.h create mode 100644 src/libs/xpcom18a4/xpcom/base/pure_api.c create mode 100644 src/libs/xpcom18a4/xpcom/build/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/build/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/build/dlldeps.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/malloc.c create mode 100644 src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOM.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h create mode 100644 src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp create mode 100644 src/libs/xpcom18a4/xpcom/build/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom.pkg create mode 100644 src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def create mode 100644 src/libs/xpcom18a4/xpcom/components/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/components/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIFactory.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIModule.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsModule.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.h create mode 100644 src/libs/xpcom18a4/xpcom/doc/README create mode 100644 src/libs/xpcom18a4/xpcom/ds/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/ds/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCRT.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDeque.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashSets.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIArray.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsICollection.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsInt64.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverList.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsObserverService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsProperties.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTime.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsValueArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVariant.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h create mode 100644 src/libs/xpcom18a4/xpcom/ds/pldhash.c create mode 100644 src/libs/xpcom18a4/xpcom/ds/pldhash.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/glue/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsDebug.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsMemory.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/objs.mk create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp create mode 100644 src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h create mode 100644 src/libs/xpcom18a4/xpcom/io/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/io/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h create mode 100644 src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c create mode 100644 src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsEscape.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsEscape.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIFile.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIPipe.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl create mode 100644 src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFile.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStorageStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringIO.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/io/nsStringStream.h create mode 100644 src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html create mode 100644 src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg create mode 100644 src/libs/xpcom18a4/xpcom/proxy/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl create mode 100644 src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/README create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in create mode 100755 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/sample/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsISample.idl create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.h create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSample.js create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp create mode 100644 src/libs/xpcom18a4/xpcom/sample/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html create mode 100644 src/libs/xpcom18a4/xpcom/string/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/README.html create mode 100644 src/libs/xpcom18a4/xpcom/string/doc/README.html create mode 100644 src/libs/xpcom18a4/xpcom/string/doc/string-guide.html create mode 100644 src/libs/xpcom18a4/xpcom/string/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h create mode 100644 src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h create mode 100644 src/libs/xpcom18a4/xpcom/string/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/string/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp create mode 100644 src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp create mode 100644 src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/test_main.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestArray.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCOMPtrEq.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestFactory.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestID.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/resources.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/MyService.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/services/win32.order create mode 100644 src/libs/xpcom18a4/xpcom/tests/test.properties create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/cp.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/dirs.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/utils/ls.js create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h create mode 100644 src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/threads/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/TimerThread.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsIThread.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimer.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcess.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsThread.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsThread.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h create mode 100644 src/libs/xpcom18a4/xpcom/threads/plevent.c create mode 100644 src/libs/xpcom18a4/xpcom/threads/plevent.h create mode 100644 src/libs/xpcom18a4/xpcom/tools/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/Makefile.in create mode 100755 src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/README create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c create mode 100644 src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp create mode 100644 src/libs/xpcom18a4/xpcom/xpcom-config.h.in create mode 100644 src/libs/xpcom18a4/xpcom/xpcom-private.h.in (limited to 'src/libs/xpcom18a4') diff --git a/src/libs/xpcom18a4/Config.kmk b/src/libs/xpcom18a4/Config.kmk new file mode 100644 index 00000000..abff6790 --- /dev/null +++ b/src/libs/xpcom18a4/Config.kmk @@ -0,0 +1,474 @@ +# $Id: Config.kmk $ +## @file +# XPCOM kBuild Configuration file. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +# Include the top-level configure file. +ifndef VBOX_ROOT_CONFIG_KMK_INCLUDED + include $(PATH_ROOT)/Config.kmk +endif + +# +# Globals. +# +VBOX_PATH_XPCOM_SRC := $(PATH_ROOT)/src/libs/xpcom18a4 + + +# +# Template for building the XPCOM libraries (shared). +# +TEMPLATE_XPCOM = XPCOM libraries (shared) +TEMPLATE_XPCOM_EXTENDS = VBOXR3NP +## @todo correct inheritance here to make it use all the VBOXR3NP settings instead of overriding all of them. +TEMPLATE_XPCOM_ASTOOL = $(TEMPLATE_VBOXR3NP_TOOL) +TEMPLATE_XPCOM_ASFLAGS = $(NO_SUCH_VARIABLE) +TEMPLATE_XPCOM_ASFLAGS.x86 = -m32 +TEMPLATE_XPCOM_ASFLAGS.amd64 = -m64 +TEMPLATE_XPCOM_ASDEFS = $(NO_SUCH_VARIABLE) +TEMPLATE_XPCOM_CXXFLAGS = -g -pipe -ansi -Wall -Wno-unused -Wno-non-virtual-dtor \ + $(VBOX_GCC_Wno-invalid-offsetof) -Wno-sign-compare -Wno-unused -Wno-ctor-dtor-privacy \ + $(VBOX_GCC_fvisibility-inlines-hidden) $(VBOX_GCC_fvisibility-hidden) \ + $(VBOX_GCC_Wno-delete-non-virtual-dtor) $(VBOX_GCC_Wno-multistatement-macros) $(VBOX_GCC_fdiagnostics-show-option) \ + $(VBOX_GCC_SANITIZER_FLAGS) $(VBOX_GCC_OPT) $(VBOX_GCC_FP) +#if !defined(VBOX_GCC_Wno-delete-non-virtual-dtor) && defined(VBOX_GCC_Wno-non-virtual-dtor) +ifndef VBOX_GCC_Wno-delete-non-virtual-dtor + ifdef VBOX_GCC_Wno-non-virtual-dtor + TEMPLATE_XPCOM_CXXFLAGS += $(VBOX_GCC_Wno-non-virtual-dtor) + endif +endif +TEMPLATE_XPCOM_CXXFLAGS.x86 = -m32 +TEMPLATE_XPCOM_CXXFLAGS.amd64 = -m64 +TEMPLATE_XPCOM_CXXFLAGS.arm64 = -m64 +TEMPLATE_XPCOM_CXXFLAGS.darwin = -fpascal-strings -fshort-wchar -fno-common -fno-rtti $(VBOX_DARWIN_DEF_SDK_CXXFLAGS) +TEMPLATE_XPCOM_CXXFLAGS.freebsd = -pthread +TEMPLATE_XPCOM_CXXFLAGS.linux = -pthread +TEMPLATE_XPCOM_CXXFLAGS.solaris = -fno-omit-frame-pointer # for now anyway. +TEMPLATE_XPCOM_CFLAGS = -g -pipe -Wall -Wno-unused -Wno-parentheses -Wno-uninitialized $(VBOX_GCC_fvisibility-hidden) \ + $(VBOX_GCC_Wno-multistatement-macros) $(VBOX_GCC_fdiagnostics-show-option) $(VBOX_GCC_SANITIZER_FLAGS) $(VBOX_GCC_OPT) $(VBOX_GCC_FP) +TEMPLATE_XPCOM_CFLAGS.x86 = -m32 +TEMPLATE_XPCOM_CFLAGS.amd64 = -m64 +TEMPLATE_XPCOM_CFLAGS.arm64 = -m64 +TEMPLATE_XPCOM_CFLAGS.freebsd = -pthread +TEMPLATE_XPCOM_CFLAGS.linux = -pthread -ansi +TEMPLATE_XPCOM_CFLAGS.solaris = -fno-omit-frame-pointer # for now anyway. +TEMPLATE_XPCOM_DEFS = \ + MOZILLA_CLIENT=1 \ + NDEBUG=1 \ + _IMPL_NS_COM \ + IN_RING3 \ + VBOX_USE_IPRT_IN_XPCOM +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS += \ + XPCOM_DLL_BASE="$(basename $(notdir $(LIB_XPCOM)))" \ + MOZ_DLL_SUFFIX="$(suffix $(LIB_XPCOM))" +else + TEMPLATE_XPCOM_DEFS += \ + XPCOM_DLL_BASE=\"$(basename $(notdir $(LIB_XPCOM)))\" \ + MOZ_DLL_SUFFIX=\"$(suffix $(LIB_XPCOM))\" +endif + +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + TEMPLATE_XPCOM_DEFS += VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +endif +TEMPLATE_XPCOM_DEFS.x86 = i386=1 +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.amd64 = HAVE_VA_LIST_AS_ARRAY HAVE_VA_COPY VA_COPY(a,b)=__builtin_va_copy(a,b) +else + TEMPLATE_XPCOM_DEFS.amd64 = HAVE_VA_LIST_AS_ARRAY HAVE_VA_COPY VA_COPY\(a\,b\)=__builtin_va_copy\(a\,b\) +endif +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.arm64 = HAVE_VA_LIST_AS_ARRAY HAVE_VA_COPY VA_COPY(a,b)=__builtin_va_copy(a,b) +else + TEMPLATE_XPCOM_DEFS.arm64 = HAVE_VA_LIST_AS_ARRAY HAVE_VA_COPY VA_COPY\(a\,b\)=__builtin_va_copy\(a\,b\) +endif +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.darwin = OSTYPE="Darwin8.8.1" OSARCH="Darwin" XP_UNIX=1 XP_MACOSX=1 TARGET_CARBON=1 HAVE_VISIBILITY_ATTRIBUTE=1 DARWIN=1 $(TEMPLATE_VBOXR3NP_DEFS.darwin) +else + TEMPLATE_XPCOM_DEFS.darwin = OSTYPE=\"Darwin8.8.1\" OSARCH=\"Darwin\" XP_UNIX=1 XP_MACOSX=1 TARGET_CARBON=1 HAVE_VISIBILITY_ATTRIBUTE=1 DARWIN=1 $(TEMPLATE_VBOXR3NP_DEFS.darwin) +endif +TEMPLATE_XPCOM_DEFS.darwin.amd64 = VBOX_MACOSX_FOLLOWS_UNIX_IO +TEMPLATE_XPCOM_DEFS.darwin.arm64 = VBOX_MACOSX_FOLLOWS_UNIX_IO +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.freebsd = OSTYPE="FreeBSD5+" OSARCH="FreeBSD" XP_UNIX=1 FREEBSD=1 HAVE_VISIBILITY_ATTRIBUTE=1 +else + TEMPLATE_XPCOM_DEFS.freebsd = OSTYPE=\"FreeBSD5+\" OSARCH=\"FreeBSD\" XP_UNIX=1 FREEBSD=1 HAVE_VISIBILITY_ATTRIBUTE=1 +endif +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.linux = OSTYPE="Linux2.6" OSARCH="Linux" XP_UNIX=1 _GNU_SOURCE HAVE_VISIBILITY_ATTRIBUTE=1 ## @todo LINUX=1 +else + TEMPLATE_XPCOM_DEFS.linux = OSTYPE=\"Linux2.6\" OSARCH=\"Linux\" XP_UNIX=1 _GNU_SOURCE HAVE_VISIBILITY_ATTRIBUTE=1 ## @todo LINUX=1 +endif +# Don't define BSD_SELECT because bsdselect() from kLIBC <= 0.6.3 has problems on SMP +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.os2 = OSTYPE="OS/2_4.5" OSARCH="OS/2" XP_OS2 XP_PC OS2=4 +else + TEMPLATE_XPCOM_DEFS.os2 = OSTYPE=\"OS/2_4.5\" OSARCH=\"OS/2\" XP_OS2 XP_PC OS2=4 +endif +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOM_DEFS.solaris = OSTYPE="Solaris10" OSARCH="Solaris" XP_UNIX=1 XP_SOLARIS=1 HAVE_LIBDL=1 HAVE_SENDFILEV=1 SOLARIS=1 _REENTRANT +else + TEMPLATE_XPCOM_DEFS.solaris = OSTYPE=\"Solaris10\" OSARCH=\"Solaris\" XP_UNIX=1 XP_SOLARIS=1 HAVE_LIBDL=1 HAVE_SENDFILEV=1 SOLARIS=1 _REENTRANT +endif +TEMPLATE_XPCOM_LDFLAGS = $(TEMPLATE_VBOXR3NP_LDFLAGS) +ifdef VBOX_WITH_RUNPATH +TEMPLATE_XPCOM_LDFLAGS += '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RUNPATH)' +else ifdef VBOX_WITH_RELATIVE_RUNPATH +TEMPLATE_XPCOM_LDFLAGS += '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)' +endif +TEMPLATE_XPCOM_LDFLAGS.x86 = -m32 +TEMPLATE_XPCOM_LDFLAGS.amd64 = -m64 +TEMPLATE_XPCOM_LDFLAGS.arm64 = -m64 +TEMPLATE_XPCOM_LDFLAGS.darwin = $(TEMPLATE_VBOXR3NP_LDFLAGS.darwin) \ + -fshort-wchar -fno-rtti -fno-exceptions -fpascal-strings \ + -current_version $(VBOX_VERSION_MAJOR).$(VBOX_VERSION_MINOR).$(VBOX_VERSION_BUILD) \ + -compatibility_version $(VBOX_VERSION_MAJOR).$(VBOX_VERSION_MINOR).$(VBOX_VERSION_BUILD) \ + -framework CoreServices \ + -framework CoreFoundation \ + -framework Foundation \ + -framework AppKit \ + -framework Carbon +## @todo why is -fno-exceptions here. +ifn1of ($(KBUILD_TARGET), os2 win) + TEMPLATE_XPCOM_CXXFLAGS += -fPIC + TEMPLATE_XPCOM_CFLAGS += -fPIC + TEMPLATE_XPCOM_LDFLAGS += -fPIC + TEMPLATE_XPCOM_DEFS += MOZ_PRESERVE_PIC +endif +TEMPLATE_XPCOM_INCS = $(VBOX_PATH_XPCOM_SRC)/xpcom/build \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/ds \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/io \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/base \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/components \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/threads \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/proxy/src \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/reflect/xptcall/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/client/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/shared/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/extensions/lock/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/extensions/transmngr/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/extensions/dconnect/src \ + $(VBOX_PATH_XPCOM_SRC)/ipc/ipcd/extensions/transmngr/common \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/string \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/ipcd \ + . +ifn1of ($(VBOX_DEF_MACOSX_VERSION_MIN),10.4 10.5 10.6 10.7) # FlatCarbon is gone starting 10.8 (or Xcode 5.0). + TEMPLATE_XPCOM_DEFS.darwin += VBOX_WITH_NEWER_OSX_SDK + TEMPLATE_XPCOM_INCS.darwin = \ + $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/ \ + $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/Headers/ \ + $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Headers/ +else + TEMPLATE_XPCOM_INCS.darwin = $(VBOX_PATH_MACOSX_SDK)/Developer/Headers/FlatCarbon +endif +TEMPLATE_XPCOM_LIBS.solaris = sendfile +TEMPLATE_XPCOM_ORDERDEPS = $(foreach hdrinst, $(filter %-HEADERS, $(INSTALLS)), $($(hdrinst)_1_TARGET)) \ + $(PATH_TARGET)/VBox-xpcom-idl-timestamp +ifeq ($(KBUILD_TARGET),os2) + ifndef USE_OS2_TOOLKIT_HEADERS + TEMPLATE_XPCOM_DEFS.os2 += OS2EMX_PLAIN_CHAR + endif + TEMPLATE_XPCOM_DEFS.os2 += XP_OS2_EMX OS2=4 + # this is at least for strnicmp() + TEMPLATE_XPCOM_DEFS.os2 += _EMX_SOURCE + # @@todo shouldn't this be somehow default for ASTOOL? + TEMPLATE_XPCOM_ASFLAGS.os2 += -Zomf +endif + +# When using IPRT in NSRP or/and using IPRT for logging, link with IPRT. +TEMPLATE_XPCOM_LIBS += $(LIB_RUNTIME) + + +# +# Same as XPCOM except using YASM/NASM instead of the gnu/unix assembler. +# +TEMPLATE_XPCOMYASM = XPCOM w/ yasm +TEMPLATE_XPCOMYASM_EXTENDS = XPCOM +TEMPLATE_XPCOMYASM_ASTOOL = $(TEMPLATE_VBOXR3NP_ASTOOL) +TEMPLATE_XPCOMYASM_ASFLAGS = $(TEMPLATE_VBOXR3NP_ASFLAGS) +TEMPLATE_XPCOMYASM_ASFLAGS.x86 = $(TEMPLATE_VBOXR3NP_ASFLAGS.x86) +TEMPLATE_XPCOMYASM_ASFLAGS.amd64 = $(TEMPLATE_VBOXR3NP_ASFLAGS.amd64) +TEMPLATE_XPCOMYASM_ASDEFS = $(TEMPLATE_VBOXR3NP_DEFS) + + +# +# Template for building the XPCOM executables. +# Used as a base template by XPCOMTSTEXE and XPCOMIPCEXE. +# +TEMPLATE_XPCOMEXE = XPCOM executable files +TEMPLATE_XPCOMEXE_EXTENDS = XPCOM +## @todo undo -fPIC. +TEMPLATE_XPCOMEXE_INCS = ipc/ipcd/shared/src \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/string \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/ipcd \ + . +TEMPLATE_XPCOMEXE_LIBS = \ + $(VBox-xpcom-ipcshared_1_TARGET) \ + $(VBoxXPCOM_1_TARGET) \ + $(TEMPLATE_XPCOM_LIBS) +TEMPLATE_XPCOMEXE_LIBS.freebsd = $(LIB_PTHREAD) +TEMPLATE_XPCOMEXE_LIBS.linux = dl $(LIB_PTHREAD) +TEMPLATE_XPCOMEXE_LDFLAGS.darwin = -bind_at_load $(filter-out -current_version -compatibility_version $(VBOX_VERSION_MAJOR).$(VBOX_VERSION_MINOR).$(VBOX_VERSION_BUILD),$(TEMPLATE_XPCOM_LDFLAGS.darwin)) + + +# +# Template for building the XPCOM testcase executables +# +TEMPLATE_XPCOMTSTEXE = XPCOM executable files (testcases) +TEMPLATE_XPCOMTSTEXE_EXTENDS = XPCOMEXE +TEMPLATE_XPCOMTSTEXE_CXXFLAGS = $(TEMPLATE_XPCOMEXE_CXXFLAGS) -Wno-format +TEMPLATE_XPCOMTSTEXE_CFLAGS = $(TEMPLATE_XPCOMEXE_CFLAGS) -Wno-format +TEMPLATE_XPCOMTSTEXE_INST = $(INST_TESTCASE) +ifdef VBOX_WITH_RUNPATH + TEMPLATE_XPCOMTSTEXE_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RUNPATH)' $(TEMPLATE_XPCOMEXE_LDFLAGS) +else ifdef VBOX_WITH_RELATIVE_RUNPATH + TEMPLATE_XPCOMTSTEXE_LDFLAGS = '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)/..' $(TEMPLATE_XPCOMEXE_LDFLAGS) +endif +if "$(KBUILD_TARGET)" == "win" && defined(VBOX_SIGNING_MODE) + TEMPLATE_XPCOMTSTEXE_POST_CMDS = +endif + + +# +# Template for building XPCOM executables for running at build time. +# +# It extends the BLDPROG template in config.kmk but overrides CFLAGS +# and CXXFLAGS completely at the moment. +# +TEMPLATE_XPCOMBLDPROG = XPCOM Build programs executables +TEMPLATE_XPCOMBLDPROG_EXTENDS = VBoxBldProg +## @todo Verify that this doesn't blow up because of template inheriance ordering. (we're assuming XPCOMEXE is expanded when this is being used.) +TEMPLATE_XPCOMBLDPROG_DEFS = \ + $(TEMPLATE_VBoxBldProg_DEFS) \ + $(filter-out VBOX_USE_IPRT_IN_XPCOM, $(TEMPLATE_XPCOMEXE_DEFS)) +TEMPLATE_XPCOMBLDPROG_DEFS.$(KBUILD_HOST) = $(TEMPLATE_VBoxBldProg_DEFS.$(KBUILD_HOST)) $(TEMPLATE_XPCOMEXE_DEFS.$(KBUILD_HOST)) +TEMPLATE_XPCOMBLDPROG_DEFS.x86 = $(TEMPLATE_VBoxBldProg_DEFS.x86) $(TEMPLATE_XPCOMEXE_DEFS.x86) +TEMPLATE_XPCOMBLDPROG_DEFS.amd64 = $(TEMPLATE_VBoxBldProg_DEFS.amd64) $(TEMPLATE_XPCOMEXE_DEFS.amd64) +TEMPLATE_XPCOMBLDPROG_INCS = \ + $(VBOX_PATH_SDK)/bindings/xpcom/include \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/nsprpub \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/string \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/xpcom \ + $(VBOX_PATH_SDK)/bindings/xpcom/include/ipcd +TEMPLATE_XPCOMBLDPROG_CFLAGS = $(filter-out -pedantic -Wshadow, $(TEMPLATE_VBOX_BLDPROG_CFLAGS)) $(VBOX_GCC_Wno-int-to-pointer-cast) $(VBOX_GCC_Wno-pointer-to-int-cast) -Wno-format +TEMPLATE_XPCOMBLDPROG_CXXFLAGS.darwin = $(TEMPLATE_VBoxBldProg_CXXFLAGS.darwin) -fpascal-strings -fshort-wchar -fno-common -fno-rtti +TEMPLATE_XPCOMBLDPROG_CXXFLAGS.solaris = $(TEMPLATE_VBoxBldProg_CXXFLAGS.solaris) -fno-omit-frame-pointer # for now anyway. +TEMPLATE_XPCOMBLDPROG_LDFLAGS.darwin = $(TEMPLATE_VBoxBldProg_LDFLAGS.darwin) -fpascal-strings -fshort-wchar -fno-rtti -fno-exceptions +TEMPLATE_XPCOMBLDPROG_ORDERDEPS = $(foreach hdrinst, $(filter %-HEADERS, $(INSTALLS)), $($(hdrinst)_1_TARGET)) + + +ifeq ($(VBOX_DEF_MACOSX_VERSION_MIN),10.4) + # + # Template for building VBoxPython against the Mac OS X 10.4 SDK. + # ASSUMES that the SDK bits are in the .darwin properties we're overriding below. + # + TEMPLATE_XPCOMOSX104 = XPCOM libraries (shared) built against the Mac OS X 10.4 SDK + TEMPLATE_XPCOMOSX104_EXTENDS = XPCOM + TEMPLATE_XPCOMOSX104_CXXFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CXXFLAGS),$(TEMPLATE_XPCOM_CXXFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_4_CXXFLAGS) + TEMPLATE_XPCOMOSX104_CFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CFLAGS),$(TEMPLATE_XPCOM_CFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_4_CFLAGS) + TEMPLATE_XPCOMOSX104_LDFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_LDFLAGS),$(TEMPLATE_XPCOM_LDFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_4_LDFLAGS) + TEMPLATE_XPCOMOSX104_DEFS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_DEFS),$(TEMPLATE_XPCOM_DEFS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_4_DEFS) + TEMPLATE_XPCOMOSX104_INCS.darwin = $(VBOX_PATH_MACOSX_SDK_10_4)/Developer/Headers/FlatCarbon +endif + +# +# Template for building VBoxPython against the Mac OS X 10.5 SDK. +# ASSUMES that the SDK bits are in the .darwin properties we're overriding below. +# +TEMPLATE_XPCOMOSX105 = XPCOM libraries (shared) built against the Mac OS X 10.5 SDK +TEMPLATE_XPCOMOSX105_EXTENDS = XPCOM +TEMPLATE_XPCOMOSX105_CXXFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CXXFLAGS),$(TEMPLATE_XPCOM_CXXFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_5_CXXFLAGS) +TEMPLATE_XPCOMOSX105_CFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CFLAGS),$(TEMPLATE_XPCOM_CFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_5_CFLAGS) +TEMPLATE_XPCOMOSX105_LDFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_LDFLAGS),$(TEMPLATE_XPCOM_LDFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_5_LDFLAGS) +TEMPLATE_XPCOMOSX105_DEFS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_DEFS),$(TEMPLATE_XPCOM_DEFS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_5_DEFS) +TEMPLATE_XPCOMOSX105_INCS.darwin = $(VBOX_PATH_MACOSX_SDK_10_5)/Developer/Headers/FlatCarbon + +# +# Template for building VBoxPython against the Mac OS X 10.6 SDK. +# ASSUMES that the SDK bits are in the .darwin properties we're overriding below. +# +TEMPLATE_XPCOMOSX106 = XPCOM libraries (shared) built against the Mac OS X 10.6 SDK +TEMPLATE_XPCOMOSX106_EXTENDS = XPCOM +TEMPLATE_XPCOMOSX106_CXXFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CXXFLAGS),$(TEMPLATE_XPCOM_CXXFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_6_CXXFLAGS) +TEMPLATE_XPCOMOSX106_CFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CFLAGS),$(TEMPLATE_XPCOM_CFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_6_CFLAGS) +TEMPLATE_XPCOMOSX106_LDFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_LDFLAGS),$(TEMPLATE_XPCOM_LDFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_6_LDFLAGS) +TEMPLATE_XPCOMOSX106_DEFS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_DEFS),$(TEMPLATE_XPCOM_DEFS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_6_DEFS) +TEMPLATE_XPCOMOSX106_INCS.darwin = $(VBOX_PATH_MACOSX_SDK_10_6)/Developer/Headers/FlatCarbon + +# +# Template for building VBoxPython against the Mac OS X 10.7 SDK. +# ASSUMES that the SDK bits are in the .darwin properties we're overriding below. +# +TEMPLATE_XPCOMOSX107 = XPCOM libraries (shared) built against the Mac OS X 10.7 SDK +TEMPLATE_XPCOMOSX107_EXTENDS = XPCOM +TEMPLATE_XPCOMOSX107_TOOL = LLVMGXX42MACHO +TEMPLATE_XPCOMOSX107_CXXFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CXXFLAGS),$(TEMPLATE_XPCOM_CXXFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_7_CXXFLAGS) +TEMPLATE_XPCOMOSX107_CFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_CFLAGS),$(TEMPLATE_XPCOM_CFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_7_CFLAGS) +TEMPLATE_XPCOMOSX107_LDFLAGS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_LDFLAGS),$(TEMPLATE_XPCOM_LDFLAGS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_7_LDFLAGS) +TEMPLATE_XPCOMOSX107_DEFS.darwin = $(filter-out $(VBOX_DARWIN_DEF_SDK_DEFS),$(TEMPLATE_XPCOM_DEFS.darwin)) $(VBOX_DARWIN_DEF_SDK_10_7_DEFS) +TEMPLATE_XPCOMOSX107_INCS.darwin = $(VBOX_PATH_MACOSX_SDK_10_7)/Developer/Headers/FlatCarbon + + +# +# Creates a x86 target for an XPCOM target if so desired. +# The target is specified as the first argument: $(evalcall VBOX_XPCOM_X86,target). +# +ifdef VBOX_WITH_32_ON_64_MAIN_API + define VBOX_XPCOM_X86 + $(1)-x86_TEMPLATE := $(strip $($(1)_TEMPLATE))-x86 + $(1)-x86_EXTENDS := $(1) + endef +else + define VBOX_XPCOM_X86 + endef +endif + +# Corresponding 32-bit template(s). +TEMPLATE_XPCOM-x86 = 32-bit XPCOM libraries (shared) +TEMPLATE_XPCOM-x86_EXTENDS = XPCOM +TEMPLATE_XPCOM-x86_BLD_TRG_ARCH = x86 +TEMPLATE_XPCOM-x86_DEFS = $(TEMPLATE_XPCOM_DEFS) VBOX_IN_32_ON_64_MAIN_API +TEMPLATE_XPCOM-x86_LIBS = $(subst $(LIB_RUNTIME),$(VBOX_LIB_RUNTIME_X86),$(TEMPLATE_XPCOM_LIBS)) + +TEMPLATE_XPCOMYASM-x86 = 32-bit XPCOM libraries (shared) with YASM as assembler. +TEMPLATE_XPCOMYASM-x86_EXTENDS = XPCOMYASM +TEMPLATE_XPCOMYASM-x86_BLD_TRG_ARCH = x86 +TEMPLATE_XPCOMYASM-x86_DEFS = $(TEMPLATE_XPCOMYASM_DEFS) VBOX_IN_32_ON_64_MAIN_API +TEMPLATE_XPCOMYASM-x86_LIBS = $(subst $(LIB_RUNTIME),$(VBOX_LIB_RUNTIME_X86),$(TEMPLATE_XPCOMYASM_LIBS)) + + +# +# The list of XPCOM's IDL files. +# This is used by the java bindings as well as the XPCOM build. +# +XPCOM_IDLFILES = \ + xpcom/base/nsIDebug.idl \ + xpcom/base/nsIInterfaceRequestor.idl \ + xpcom/base/nsIMemory.idl \ + xpcom/base/nsIProgrammingLanguage.idl \ + xpcom/base/nsISupports.idl \ + xpcom/base/nsITraceRefcnt.idl \ + xpcom/base/nsIWeakReference.idl \ + xpcom/base/nsIConsoleMessage.idl \ + xpcom/base/nsIConsoleService.idl \ + xpcom/base/nsIConsoleListener.idl \ + xpcom/base/nsIErrorService.idl \ + xpcom/base/nsIException.idl \ + xpcom/base/nsIExceptionService.idl \ + xpcom/base/nsrootidl.idl \ + xpcom/components/nsIClassInfo.idl \ + xpcom/components/nsIComponentRegistrar.idl \ + xpcom/components/nsIFactory.idl \ + xpcom/components/nsIModule.idl \ + xpcom/components/nsIServiceManager.idl \ + xpcom/components/nsIComponentManager.idl \ + xpcom/components/nsICategoryManager.idl \ + xpcom/components/nsIComponentLoader.idl \ + xpcom/components/nsINativeComponentLoader.idl \ + xpcom/components/nsIComponentManagerObsolete.idl \ + xpcom/components/nsIComponentLoaderManager.idl \ + xpcom/ds/nsISupportsArray.idl \ + xpcom/ds/nsICollection.idl \ + xpcom/ds/nsISerializable.idl \ + xpcom/ds/nsIEnumerator.idl \ + xpcom/ds/nsISimpleEnumerator.idl \ + xpcom/ds/nsIObserverService.idl \ + xpcom/ds/nsIObserver.idl \ + xpcom/ds/nsIAtom.idl \ + xpcom/ds/nsIAtomService.idl \ + xpcom/ds/nsIProperties.idl \ + xpcom/ds/nsIPersistentProperties2.idl \ + xpcom/ds/nsIRecyclingAllocator.idl \ + xpcom/ds/nsIStringEnumerator.idl \ + xpcom/ds/nsISupportsPrimitives.idl \ + xpcom/ds/nsISupportsIterators.idl \ + xpcom/ds/nsIVariant.idl \ + xpcom/ds/nsITimelineService.idl \ + xpcom/ds/nsIArray.idl \ + xpcom/ds/nsIPropertyBag.idl \ + xpcom/ds/nsIHashable.idl \ + xpcom/io/nsIDirectoryService.idl \ + xpcom/io/nsIDirectoryEnumerator.idl \ + xpcom/io/nsIFile.idl \ + xpcom/io/nsILocalFile.idl \ + xpcom/io/nsILocalFileMac.idl \ + xpcom/io/nsIInputStream.idl \ + xpcom/io/nsIObjectInputStream.idl \ + xpcom/io/nsIBinaryInputStream.idl \ + xpcom/io/nsIObjectOutputStream.idl \ + xpcom/io/nsIBinaryOutputStream.idl \ + xpcom/io/nsIOutputStream.idl \ + xpcom/io/nsIStreamBufferAccess.idl \ + xpcom/io/nsIByteArrayInputStream.idl \ + xpcom/io/nsISeekableStream.idl \ + xpcom/io/nsIFastLoadFileControl.idl \ + xpcom/io/nsIFastLoadService.idl \ + xpcom/io/nsIInputStreamTee.idl \ + xpcom/io/nsIMultiplexInputStream.idl \ + xpcom/io/nsIPipe.idl \ + xpcom/io/nsIAsyncInputStream.idl \ + xpcom/io/nsIAsyncOutputStream.idl \ + xpcom/io/nsIScriptableInputStream.idl \ + xpcom/io/nsIStorageStream.idl \ + xpcom/io/nsIStringStream.idl \ + xpcom/io/nsILineInputStream.idl \ + xpcom/proxy/public/nsIProxyObjectManager.idl \ + xpcom/threads/nsIEventQueueService.idl \ + xpcom/threads/nsIEventQueue.idl \ + xpcom/threads/nsIEventTarget.idl \ + xpcom/threads/nsIRunnable.idl \ + xpcom/threads/nsIThread.idl \ + xpcom/threads/nsITimer.idl \ + xpcom/threads/nsIEnvironment.idl \ + xpcom/threads/nsITimerInternal.idl \ + xpcom/threads/nsITimerManager.idl \ + xpcom/threads/nsIProcess.idl \ + xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl \ + xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl \ + xpcom/reflect/xptinfo/public/nsIXPTLoader.idl \ + ipc/ipcd/client/public/ipcIService.idl \ + ipc/ipcd/client/public/ipcIMessageObserver.idl \ + ipc/ipcd/client/public/ipcIClientObserver.idl \ + ipc/ipcd/extensions/lock/public/ipcILockService.idl \ + ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl \ + ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl \ + ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl + +# +# The include path for the XPCOM IDL files above. +# +XPIDL_INCS = \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/base/ \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/ds/ \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/components/ \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/io/ \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/threads/ \ + -I $(VBOX_PATH_XPCOM_SRC)/xpcom/reflect/xptinfo/public/ + diff --git a/src/libs/xpcom18a4/Makefile.kmk b/src/libs/xpcom18a4/Makefile.kmk new file mode 100644 index 00000000..41f20d21 --- /dev/null +++ b/src/libs/xpcom18a4/Makefile.kmk @@ -0,0 +1,1485 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for XPCOM. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../.. +include $(KBUILD_PATH)/subheader.kmk + +# Make sure our Config.kmk is included. +ifndef VBOX_PATH_XPCOM_SRC + include $(PATH_SUB_CURRENT)/Config.kmk +endif + +# +# Globals +# + +# File for filtering out C symbols from the XPCOM library. Used to avoid +# symbol namespace pollution, causing trouble with system libraries. +XPCOM_C_NAMESPACE_MAP = $(VBOX_PATH_XPCOM_SRC)/xpcom-namespace-cleanup.map +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + # At the moment, only Solaris uses the generated map file. GNU ld is smart + # enough to handle symbol wildcards itself. + if1of ($(KBUILD_TARGET), solaris) + XPCOM_C_NAMESPACE_MAP = $(PATH_TARGET)/xpcom-namespace-cleanup.map + OTHER_CLEAN += $(XPCOM_C_NAMESPACE_MAP) + endif +endif + +# @todo check whether VBoxXPCOMIPCC.so or VBoxXPCOMIPCD contain undefined +# symbols starting with NS_, PL_, PR_ or XPT. Would move the test time failure +# when missing a symbol renaming to a build time failure. Likewise, there +# should be a check whether VBoxXPCOM.so contains global C symbols (at least +# where the whitelisting of symbols via the map file is not used). + +# +# Header installs. +# +INSTALLS += \ + NSPRPUB-HEADERS \ + NSPRPUB-MD-HEADERS \ + NSPRPUB-OBS-HEADERS \ + NSPRPUB-PRIV-HEADERS \ + STRING-HEADERS \ + XPCOM-HEADERS \ + IPCD-HEADERS + +# +# The IDL compiler, typelib linker and xpt files. +# +BLDPROGS += \ + xpidl \ + xpt_link + +BLDDIRS += \ + $(PATH_TARGET)/VBox-xpcom-xpt-files/ + +# +# Always build the VBoxXPCOM import library. +# +IMPORT_LIBS += VBoxXPCOMImp + +# +# We build several libraries so that any linker command line +# length restrictions limit will be avoided. (Solaris, Mac?) +# +if !defined(VBOX_ONLY_SDK) && (!defined(VBOX_ONLY_EXTPACKS) || !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS)) + +VBOX_XPCOM_LIBRARIES := \ + VBox-xpcom-nspr \ + VBox-xpcom-typelib \ + VBox-xpcom-string \ + VBox-xpcom-base \ + VBox-xpcom-ds \ + VBox-xpcom-io \ + VBox-xpcom-components \ + VBox-xpcom-threads \ + VBox-xpcom-xptinfo \ + VBox-xpcom-xptcall \ + VBox-xpcom-proxy \ + VBox-xpcom-ipcshared \ + VBoxXPCOMGlue_s \ + $(if $(VBOX_WITH_XPCOM_GLUE_WHICH_IS_UNUSED),VBoxXPCOMGlue,) +LIBRARIES += $(VBOX_XPCOM_LIBRARIES) + +VBOX_XPCOM_DLLS := \ + VBoxXPCOM \ + VBoxXPCOMIPCC +DLLS += $(VBOX_XPCOM_DLLS) + + ifdef VBOX_WITH_32_ON_64_MAIN_API +LIBRARIES += $(addsuffix -x86,$(VBOX_XPCOM_LIBRARIES)) +DLLS += $(addsuffix -x86,$(VBOX_XPCOM_DLLS)) + endif + + + ifdef VBOX_WITH_TESTCASES +PROGRAMS += \ + tstnsIFileTest \ + tstTestArray \ + tstTestAutoLock \ + tstTestCOMPtr \ + tstTestCOMPtrEq \ + tstTestCRT \ + tstTestFactory \ + tstTestHashtables \ + tstTestID \ + tstTestObserverService \ + tstTestPipes \ + tstTestThreads \ + tstTestXPIDLString \ + tstTestXPTCInvoke \ + tstTestDeque \ + tstTestAutoPtr \ + tstTestMinStringAPI \ + tstTestStrings \ + tstPrimitiveTest \ +# tstnsIFileEnumerator +# tstTestAtoms +# tstTestServMgr +# tstTestCallTemplates +# tstTestPermanentAtoms +# tstSimpleTypeLib +# tstXptDump +# tstXptLink + endif # VBOX_WITH_TESTCASES +PROGRAMS += VBoxXPCOMIPCD + +endif # !VBOX_ONLY_SDK && (!defined(VBOX_ONLY_EXTPACKS) || !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS)) + + + + +# +# SDK headers - lot's of files to install... +# +# Tip: If you are going to remove files here, you might +# wish to do a `kmk uninstall' first to avoid have +# obsoleted files in the $(INST_SDK) directory. +# +NSPRPUB-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/nsprpub/ +NSPRPUB-HEADERS_IFFLAGS = -m 644 +NSPRPUB-HEADERS_SOURCES = \ + nsprpub/pr/include/nspr.h \ + nsprpub/lib/ds/plarena.h \ + nsprpub/lib/ds/plarenas.h \ + nsprpub/lib/libc/include/plbase64.h \ + nsprpub/lib/libc/include/plerror.h \ + nsprpub/lib/libc/include/plgetopt.h \ + nsprpub/lib/ds/plhash.h \ + nsprpub/lib/libc/include/plresolv.h \ + nsprpub/lib/libc/include/plstr.h \ + nsprpub/pr/include/pratom.h \ + nsprpub/pr/include/prbit.h \ + nsprpub/pr/include/prclist.h \ + nsprpub/pr/include/prcmon.h \ + nsprpub/pr/include/prcountr.h \ + nsprpub/pr/include/prcvar.h \ + nsprpub/pr/include/prdtoa.h \ + nsprpub/pr/include/prenv.h \ + nsprpub/pr/include/prerr.h \ + nsprpub/pr/include/prerror.h \ + nsprpub/pr/include/prinet.h \ + nsprpub/pr/include/prinit.h \ + nsprpub/pr/include/prinrval.h \ + nsprpub/pr/include/prio.h \ + nsprpub/pr/include/pripcsem.h \ + nsprpub/pr/include/prlink.h \ + nsprpub/pr/include/prlock.h \ + nsprpub/pr/include/prlog.h \ + nsprpub/pr/include/prlong.h \ + nsprpub/pr/include/prmem.h \ + nsprpub/pr/include/prmon.h \ + nsprpub/pr/include/prmwait.h \ + nsprpub/pr/include/prnetdb.h \ + nsprpub/pr/include/prolock.h \ + nsprpub/pr/include/prpdce.h \ + nsprpub/pr/include/prprf.h \ + nsprpub/pr/include/prproces.h \ + nsprpub/pr/include/prrng.h \ + nsprpub/pr/include/prrwlock.h \ + nsprpub/pr/include/prshm.h \ + nsprpub/pr/include/prshma.h \ + nsprpub/pr/include/prsystem.h \ + nsprpub/pr/include/prthread.h \ + nsprpub/pr/include/prtime.h \ + nsprpub/pr/include/prtpool.h \ + nsprpub/pr/include/prtrace.h \ + nsprpub/pr/include/prtypes.h \ + nsprpub/pr/include/prvrsion.h \ + nsprpub/pr/include/prwin16.h \ + nsprpub/pr/include/md/_vbox.cfg=>prcpucfg.h \ + +NSPRPUB-MD-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/nsprpub/md/ +NSPRPUB-MD-HEADERS_IFFLAGS = -m 644 +NSPRPUB-MD-HEADERS_SOURCES = \ + nsprpub/pr/include/md/_iprt_atomic.h \ + nsprpub/pr/include/md/_darwin.h \ + nsprpub/pr/include/md/_freebsd.h \ + nsprpub/pr/include/md/_linux.h \ + nsprpub/pr/include/md/_macos.h \ + nsprpub/pr/include/md/_netbsd.h \ + nsprpub/pr/include/md/_openbsd.h \ + nsprpub/pr/include/md/_os2_errors.h \ + nsprpub/pr/include/md/_os2.h \ + nsprpub/pr/include/md/_pcos.h \ + nsprpub/pr/include/md/_solaris.h \ + nsprpub/pr/include/md/_unix_errors.h \ + nsprpub/pr/include/md/_unixos.h \ + nsprpub/pr/include/md/_pth.h \ + nsprpub/pr/include/md/prosdep.h \ + \ + nsprpub/pr/include/md/_freebsd.cfg \ + nsprpub/pr/include/md/_linux.cfg \ + nsprpub/pr/include/md/_darwin.cfg \ + nsprpub/pr/include/md/_netbsd.cfg \ + nsprpub/pr/include/md/_openbsd.cfg \ + nsprpub/pr/include/md/_os2.cfg \ + nsprpub/pr/include/md/_solaris32.cfg \ + nsprpub/pr/include/md/_solaris64.cfg \ + +NSPRPUB-OBS-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/nsprpub/obsolete/ +NSPRPUB-OBS-HEADERS_IFFLAGS = -m 644 +NSPRPUB-OBS-HEADERS_SOURCES = \ + nsprpub/pr/include/obsolete/pralarm.h \ + nsprpub/pr/include/obsolete/probslet.h \ + nsprpub/pr/include/obsolete/protypes.h \ + nsprpub/pr/include/obsolete/prsem.h + +NSPRPUB-PRIV-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/nsprpub/private/ +NSPRPUB-PRIV-HEADERS_IFFLAGS = -m 644 +NSPRPUB-PRIV-HEADERS_SOURCES = \ + nsprpub/pr/include/private/pprio.h \ + nsprpub/pr/include/private/pprthred.h \ + nsprpub/pr/include/private/prpriv.h + +STRING-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/string/ +STRING-HEADERS_IFFLAGS = -m 644 +STRING-HEADERS_SOURCES = \ + xpcom/string/public/nsAString.h \ + xpcom/string/public/nsAlgorithm.h \ + xpcom/string/public/nsCharTraits.h \ + xpcom/string/public/nsDependentString.h \ + xpcom/string/public/nsDependentSubstring.h \ + xpcom/string/public/nsEmbedString.h \ + xpcom/string/public/nsLiteralString.h \ + xpcom/string/public/nsObsoleteAString.h \ + xpcom/string/public/nsPrintfCString.h \ + xpcom/string/public/nsPromiseFlatString.h \ + xpcom/string/public/nsReadableUtils.h \ + xpcom/string/public/nsString.h \ + xpcom/string/public/nsStringAPI.h \ + xpcom/string/public/nsStringFwd.h \ + xpcom/string/public/nsStringIterator.h \ + xpcom/string/public/nsSubstring.h \ + xpcom/string/public/nsSubstringTuple.h \ + xpcom/string/public/nsTAString.h \ + xpcom/string/public/nsTDependentString.h \ + xpcom/string/public/nsTDependentSubstring.h \ + xpcom/string/public/nsTObsoleteAString.h \ + xpcom/string/public/nsTPromiseFlatString.h \ + xpcom/string/public/nsTString.h \ + xpcom/string/public/nsTSubstring.h \ + xpcom/string/public/nsTSubstringTuple.h \ + xpcom/string/public/nsUTF8Utils.h \ + xpcom/string/public/nsXPIDLString.h \ + xpcom/string/public/string-template-def-char.h \ + xpcom/string/public/string-template-def-unichar.h \ + xpcom/string/public/string-template-undef.h + +XPCOM-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/xpcom/ +XPCOM-HEADERS_IFFLAGS = -m 644 +XPCOM-HEADERS_SOURCES = \ + xpcom/base/nsAgg.h \ + xpcom/io/nsAppDirectoryServiceDefs.h \ + xpcom/ds/nsArray.h \ + xpcom/ds/nsArrayEnumerator.h \ + xpcom/ds/nsAtomService.h \ + xpcom/ds/nsAutoBuffer.h \ + xpcom/threads/nsAutoLock.h \ + xpcom/base/nsAutoPtr.h \ + xpcom/ds/nsBaseHashtable.h \ + xpcom/ds/nsCOMArray.h \ + xpcom/ds/nsCRT.h \ + xpcom/components/nsCategoryManagerUtils.h \ + xpcom/ds/nsCheapSets.h \ + xpcom/ds/nsClassHashtable.h \ + xpcom/base/nsCom.h \ + xpcom/components/nsComponentManagerObsolete.h \ + xpcom/components/nsComponentManagerUtils.h \ + xpcom/ds/nsCppSharedAllocator.h \ + xpcom/ds/nsDataHashtable.h \ + xpcom/base/nsDebugImpl.h \ + xpcom/ds/nsDeque.h \ + xpcom/io/nsDirectoryService.h \ + xpcom/io/nsDirectoryServiceDefs.h \ + xpcom/io/nsDirectoryServiceUtils.h \ + xpcom/ds/nsDoubleHashtable.h \ + xpcom/ds/nsEnumeratorUtils.h \ + xpcom/base/nsError.h \ + xpcom/io/nsEscape.h \ + xpcom/threads/nsEventQueueUtils.h \ + xpcom/io/nsFastLoadPtr.h \ + xpcom/io/nsFastLoadService.h \ + xpcom/ds/nsFixedSizeAllocator.h \ + xpcom/ds/nsHashKeys.h \ + xpcom/ds/nsHashSets.h \ + xpcom/ds/nsHashtable.h \ + xpcom/base/nsIAllocator.h \ + xpcom/ds/nsIByteBuffer.h \ + xpcom/base/nsID.h \ + xpcom/base/nsIID.h \ + xpcom/components/nsIServiceManagerObsolete.h \ + xpcom/components/nsIServiceManagerUtils.h \ + xpcom/base/nsISupportsBase.h \ + xpcom/base/nsISupportsObsolete.h \ + xpcom/ds/nsIUnicharBuffer.h \ + xpcom/io/nsIUnicharInputStream.h \ + xpcom/ds/nsInt64.h \ + xpcom/ds/nsInterfaceHashtable.h \ + xpcom/io/nsLinebreakConverter.h \ + xpcom/io/nsLocalFile.h \ + xpcom/io/nsLocalFileUnix.h \ + xpcom/io/nsLocalFileOS2.h \ + xpcom/io/nsLocalFileOSX.h \ + xpcom/components/nsModule.h \ + xpcom/io/nsMultiplexInputStream.h \ + xpcom/io/nsNativeCharsetUtils.h \ + xpcom/components/nsNativeComponentLoader.h \ + xpcom/ds/nsObserverService.h \ + xpcom/components/nsObsoleteModuleLoading.h \ + xpcom/threads/nsProcess.h \ + xpcom/proxy/public/nsProxiedService.h \ + xpcom/proxy/public/nsProxyEvent.h \ + xpcom/proxy/public/nsProxyRelease.h \ + xpcom/ds/nsQuickSort.h \ + xpcom/ds/nsRecyclingAllocator.h \ + xpcom/ds/nsRefPtrHashtable.h \ + xpcom/io/nsScriptableInputStream.h \ + xpcom/ds/nsStaticAtom.h \ + xpcom/components/nsStaticComponent.h \ + xpcom/ds/nsStaticNameTable.h \ + xpcom/io/nsStorageStream.h \ + xpcom/io/nsStreamUtils.h \ + xpcom/ds/nsStringEnumerator.h \ + xpcom/io/nsStringIO.h \ + xpcom/io/nsStringStream.h \ + xpcom/ds/nsSupportsArray.h \ + xpcom/ds/nsSupportsPrimitives.h \ + xpcom/ds/nsTHashtable.h \ + xpcom/ds/nsTextFormatter.h \ + xpcom/ds/nsTime.h \ + xpcom/base/nsTraceRefcntImpl.h \ + xpcom/ds/nsUnitConversion.h \ + xpcom/ds/nsValueArray.h \ + xpcom/ds/nsVariant.h \ + xpcom/ds/nsVoidArray.h \ + xpcom/base/nsWeakPtr.h \ + xpcom/build/nsXPCOM.h \ + xpcom/build/nsXPCOMCID.h \ + xpcom/base/nscore.h \ + xpcom/ds/pldhash.h \ + xpcom/threads/plevent.h \ + xpcom/components/xcDll.h \ + xpcom/typelib/xpt/public/xpt_arena.h \ + xpcom/typelib/xpt/public/xpt_struct.h \ + xpcom/typelib/xpt/public/xpt_xdr.h \ + xpcom/reflect/xptcall/public/xptcall.h \ + xpcom/reflect/xptcall/public/xptcstubsdecl.inc \ + xpcom/reflect/xptcall/public/xptcstubsdef.inc \ + xpcom/reflect/xptinfo/public/xptinfo.h \ + \ + xpcom/glue/nsIInterfaceRequestorUtils.h \ + xpcom/glue/nsISupportsImpl.h \ + xpcom/glue/nsISupportsUtils.h \ + xpcom/glue/nsIWeakReferenceUtils.h \ + \ + xpcom/glue/nsCOMPtr.h \ + xpcom/glue/nsDebug.h \ + xpcom/glue/nsGenericFactory.h \ + xpcom/glue/nsIGenericFactory.h \ + xpcom/glue/nsMemory.h \ + xpcom/glue/nsTraceRefcnt.h \ + xpcom/glue/nsWeakReference.h \ + \ + xpcom/glue/standalone/nsXPCOMGlue.h \ + \ + xpcom-config.h + +IPCD-HEADERS_INST = $(INST_SDK)bindings/xpcom/include/ipcd/ +IPCD-HEADERS_IFFLAGS = -m 644 +IPCD-HEADERS_SOURCES = \ + ipc/ipcd/client/public/ipcCID.h \ + ipc/ipcd/extensions/lock/public/ipcLockCID.h \ + ipc/ipcd/util/public/ipcMessageReader.h \ + ipc/ipcd/util/public/ipcMessageWriter.h \ + ipc/ipcd/daemon/public/ipcModule.h \ + ipc/ipcd/daemon/public/ipcModuleUtil.h \ + ipc/ipcd/client/public/ipcdclient.h + + +# +# The IDL compiler. +# +# We build it statically because we cannot rely on additional .a files +# like in the original build +# +xpidl_TEMPLATE = XPCOMBLDPROG +xpidl_DEFS = EXPORT_XPT_API +## @todo This assumes HOST == TARGET. +xpidl_INST = $(INST_BIN) +## Obsolete hack: MacPorts is 32-bit on 10.5 and 64-bit on 10.6. Set your KBUILD_HOST_ARCH env.vars. accordingly. +#if "$(KBUILD_HOST).$(KBUILD_HOST_ARCH)" == "darwin.amd64" && defined(VBOX_MACOS_10_5_WORKAROUND) +# xpidl_BLD_TRG_ARCH = x86 +# ## @todo kBuild ticket 84 workarounds: +# xpidl_DEFS.x86 = $(TEMPLATE_XPCOMBLDPROG_DEFS.x86) +# xpidl_CFLAGS.x86 = $(TEMPLATE_XPCOMBLDPROG_CFLAGS.x86) +# xpidl_CXXFLAGS.x86 = $(TEMPLATE_XPCOMBLDPROG_CXXFLAGS.x86) +# xpidl_LDFLAGS.x86 = $(TEMPLATE_XPCOMBLDPROG_LDFLAGS.x86) +#endif +ifdef VBOX_WITH_JAVA_SUPPORT_IN_XPIDL + xpidl_DEFS += VBOX_XPIDL_EMULATE_GENJIFACES VBOX_XPIDL_EMULATE_GENJIFACES_DIFF +endif +xpidl_SOURCES = \ + xpcom/typelib/xpidl/xpidl.c \ + xpcom/typelib/xpidl/xpidl_idl.c \ + xpcom/typelib/xpidl/xpidl_util.c \ + xpcom/typelib/xpidl/xpidl_header.c \ + xpcom/typelib/xpidl/xpidl_typelib.c \ + xpcom/typelib/xpidl/xpidl_doc.c \ + xpcom/typelib/xpidl/xpidl_java.c \ + xpcom/typelib/xpt/src/xpt_arena.c \ + xpcom/typelib/xpt/src/xpt_struct.c \ + xpcom/typelib/xpt/src/xpt_xdr.c + +ifeq ($(KBUILD_TARGET),os2) + # glib and libIDL needed by XPCOM on OS/2. + ifeq ($(VBOX_PATH_GLIB),) + VBOX_PATH_GLIB := $(lastword $(sort $(wildcard $(KBUILD_DEVTOOLS_TRG)/glibidl/*/glibidl/gcc335))) + endif + VBOX_PATH_LIBIDL ?= $(VBOX_PATH_GLIB) + ifeq ($(wildcard $(VBOX_PATH_GLIB)),) + $(warning VBOX_PATH_GLIB is "$(VBOX_PATH_GLIB)" which is not a valid directory!) + endif + ifeq ($(wildcard $(VBOX_PATH_LIBIDL)),) + $(warning VBOX_PATH_LIBIDL is "$(VBOX_PATH_LIBIDL)" which is not a valid directory!) + endif + xpidl_INCS = \ + $(VBOX_PATH_LIBIDL)/include \ + $(VBOX_PATH_GLIB)/include + xpidl_LIBS = \ + $(VBOX_PATH_LIBIDL)/lib/libidl.lib \ + $(VBOX_PATH_LIBIDL)/lib/glib.lib + # install necessary DLLs to the same place where xpidl goes + INSTALLS += xpidl-DLLS + xpidl_ORDERDEPS = $(xpidl-DLLS_1_TARGET) + xpidl-DLLS_INST = $(xpidl_INST) + # static libraries of these may be provided instead, + # so copy DLLs only when they are present + xpidl-DLLS_SOURCES += $(wildcard $(VBOX_PATH_GLIB)/lib/glib.dll) + xpidl-DLLS_SOURCES += $(wildcard $(VBOX_PATH_LIBIDL)/lib/libIDL.dll) +else + # We do these ONCE. + libIDL_config_cflags := $(shell $(VBOX_LIBIDL_CONFIG) --cflags) + libIDL_config_libs := $(shell $(VBOX_LIBIDL_CONFIG) --libs) + xpidl_CFLAGS = \ + $(libIDL_config_cflags) + if1of ($(KBUILD_HOST), linux solaris) + xpidl_LDFLAGS = \ + $(filter-out -l%,$(libIDL_config_libs)) + xpidl_LIBS.$(KBUILD_HOST) += \ + $(subst -l,,$(filter -l%,$(libIDL_config_libs))) + else + xpidl_LDFLAGS = \ + $(libIDL_config_libs) + endif + xpidl_LDFLAGS.linux = \ + $(VBOX_LD_as_needed) +endif + +# +# The XPT linker. +# +xpt_link_TEMPLATE = XPCOMBLDPROG +xpt_link_SOURCES = \ + xpcom/typelib/xpt/tools/xpt_link.c \ + xpcom/typelib/xpt/src/xpt_arena.c \ + xpcom/typelib/xpt/src/xpt_struct.c \ + xpcom/typelib/xpt/src/xpt_xdr.c + + +# +# The NSPR Library. +# +VBox-xpcom-nspr_TEMPLATE = XPCOM +VBox-xpcom-nspr_INSTTYPE = none +VBox-xpcom-nspr_DEFS = \ + _NSPR_BUILD_ \ + HAVE_LCHOWN=1 \ + HAVE_STRERROR=1 \ + FORCE_PR_LOG +VBox-xpcom-nspr_DEFS += \ + VBOX_USE_IPRT_IN_NSPR +VBox-xpcom-nspr_DEFS.darwin.amd64 = \ + VBOX_USE_MORE_IPRT_IN_NSPR +VBox-xpcom-nspr_DEFS.darwin.arm64 = \ + VBOX_USE_MORE_IPRT_IN_NSPR +VBox-xpcom-nspr_DEFS.darwin = \ + HAVE_BSD_FLOCK=1 \ + HAVE_SOCKLEN_T=1 \ + _PR_PTHREADS +VBox-xpcom-nspr_DEFS.freebsd = \ + FREEBSD=1 \ + HAVE_CVAR_BUILT_ON_SEM \ + _PR_PTHREADS +## @todo filling in the missing stuff, please don't just copy it from linux. +# FIXME: LINUX should be defined by _linux.cfg +VBox-xpcom-nspr_DEFS.linux = \ + LINUX=1 \ + _POSIX_SOURCE=1 \ + _BSD_SOURCE=1 \ + _SVID_SOURCE=1 \ + _DEFAULT_SOURCE \ + _REENTRANT=1 \ + _LARGEFILE64_SOURCE=1 \ + HAVE_FCNTL_FILE_LOCKING=1 \ + HAVE_CVAR_BUILT_ON_SEM \ + _PR_PTHREADS +# _BSD_SOURCE is here to keep the Glibc header files happy and make them include the right things +VBox-xpcom-nspr_DEFS.netbsd = \ + _PR_PTHREADS +VBox-xpcom-nspr_DEFS.openbsd = \ + _PR_PTHREADS +VBox-xpcom-nspr_DEFS.os2 = +VBox-xpcom-nspr_DEFS.solaris = \ + HAVE_FCNTL_FILE_LOCKING=1 \ + HAVE_SOCKLEN_T=1 \ + _PR_PTHREADS +VBox-xpcom-nspr_INCS = \ + nsprpub/pr/include/private \ + $(VBox-xpcom-nspr_0_OUTDIR) + +VBox-xpcom-nspr_SOURCES = \ + nsprpub/pr/src/io/prfdcach.c \ + nsprpub/pr/src/io/prmwait.c \ + nsprpub/pr/src/io/priometh.c \ + nsprpub/pr/src/io/pripv6.c \ + nsprpub/pr/src/io/prmapopt.c \ + nsprpub/pr/src/io/prlayer.c \ + nsprpub/pr/src/io/prlog.c \ + nsprpub/pr/src/io/prmmap.c \ + nsprpub/pr/src/io/prpolevt.c \ + nsprpub/pr/src/io/prprf.c \ + nsprpub/pr/src/io/prscanf.c \ + nsprpub/pr/src/io/prstdio.c \ + nsprpub/pr/src/linking/prlink.c \ + nsprpub/pr/src/malloc/prmalloc.c \ + nsprpub/pr/src/malloc/prmem.c \ + nsprpub/pr/src/md/prosdep.c \ + nsprpub/pr/src/memory/prseg.c \ + nsprpub/pr/src/memory/prshm.c \ + nsprpub/pr/src/memory/prshma.c \ + nsprpub/pr/src/misc/pralarm.c \ + nsprpub/pr/src/misc/pratom.c \ + nsprpub/pr/src/misc/prcountr.c \ + nsprpub/pr/src/misc/prdtoa.c \ + nsprpub/pr/src/misc/prenv.c \ + nsprpub/pr/src/misc/prerr.c \ + nsprpub/pr/src/misc/prerror.c \ + nsprpub/pr/src/misc/prerrortable.c \ + nsprpub/pr/src/misc/prinit.c \ + nsprpub/pr/src/misc/prinrval.c \ + nsprpub/pr/src/misc/pripc.c \ + nsprpub/pr/src/misc/prlog2.c \ + nsprpub/pr/src/misc/prlong.c \ + nsprpub/pr/src/misc/prnetdb.c \ + nsprpub/pr/src/misc/prolock.c \ + nsprpub/pr/src/misc/prrng.c \ + nsprpub/pr/src/misc/prsystem.c \ + nsprpub/pr/src/misc/prtime.c \ + nsprpub/pr/src/misc/prthinfo.c \ + nsprpub/pr/src/misc/prtpool.c \ + nsprpub/pr/src/misc/prtrace.c \ + nsprpub/pr/src/threads/prcmon.c \ + nsprpub/pr/src/threads/prrwlock.c \ + nsprpub/pr/src/threads/prtpd.c \ + nsprpub/pr/src/prvrsion.c \ + nsprpub/lib/ds/plarena.c \ + nsprpub/lib/ds/plhash.c \ + nsprpub/lib/libc/src/strlen.c \ + nsprpub/lib/libc/src/strcpy.c \ + nsprpub/lib/libc/src/strdup.c \ + nsprpub/lib/libc/src/strcat.c \ + nsprpub/lib/libc/src/strcmp.c \ + nsprpub/lib/libc/src/strccmp.c \ + nsprpub/lib/libc/src/strchr.c \ + nsprpub/lib/libc/src/strpbrk.c \ + nsprpub/lib/libc/src/strstr.c \ + nsprpub/lib/libc/src/strcstr.c \ + nsprpub/lib/libc/src/strtok.c \ + nsprpub/lib/libc/src/base64.c \ + nsprpub/lib/libc/src/plerror.c \ + nsprpub/lib/libc/src/plgetopt.c + +ifeq ($(filter-out darwin freebsd linux netbsd openbsd solaris,$(KBUILD_TARGET)),) # unixish +VBox-xpcom-nspr_SOURCES += \ + nsprpub/pr/src/md/unix/unix.c \ + nsprpub/pr/src/md/unix/unix_errors.c \ + nsprpub/pr/src/md/unix/uxproces.c \ + nsprpub/pr/src/md/unix/uxrng.c \ + nsprpub/pr/src/md/unix/uxshm.c \ + nsprpub/pr/src/md/unix/uxwrap.c \ + nsprpub/pr/src/pthreads/ptio.c \ + nsprpub/pr/src/pthreads/ptsynch.c \ + nsprpub/pr/src/pthreads/ptthread.c \ + nsprpub/pr/src/pthreads/ptmisc.c +endif + +VBox-xpcom-nspr_SOURCES.darwin = nsprpub/pr/src/md/unix/darwin.c +VBox-xpcom-nspr_SOURCES.darwin.x86 = nsprpub/pr/src/md/unix/os_Darwin_x86.s + +VBox-xpcom-nspr_SOURCES.freebsd = nsprpub/pr/src/md/unix/freebsd.c + +VBox-xpcom-nspr_SOURCES.linux = nsprpub/pr/src/md/unix/linux.c +VBox-xpcom-nspr_SOURCES.linux.x86 = nsprpub/pr/src/md/unix/os_Linux_x86.s +VBox-xpcom-nspr_SOURCES.linux.amd64 = nsprpub/pr/src/md/unix/os_Linux_x86_64.s + +VBox-xpcom-nspr_SOURCES.os2 = \ + nsprpub/pr/src/io/prdir.c \ + nsprpub/pr/src/io/prfile.c \ + nsprpub/pr/src/io/prio.c \ + nsprpub/pr/src/io/prsocket.c \ + nsprpub/pr/src/md/os2/os2misc.c \ + nsprpub/pr/src/md/os2/os2sem.c \ + nsprpub/pr/src/md/os2/os2inrval.c \ + nsprpub/pr/src/md/os2/os2gc.c \ + nsprpub/pr/src/md/os2/os2thred.c \ + nsprpub/pr/src/md/os2/os2io.c \ + nsprpub/pr/src/md/os2/os2cv.c \ + nsprpub/pr/src/md/os2/os2sock.c \ + nsprpub/pr/src/md/os2/os2_errors.c \ + nsprpub/pr/src/md/os2/os2poll.c \ + nsprpub/pr/src/md/os2/os2rng.c \ + nsprpub/pr/src/threads/prdump.c \ + nsprpub/pr/src/threads/prmon.c \ + nsprpub/pr/src/threads/prsem.c \ + nsprpub/pr/src/threads/prcthr.c \ + nsprpub/pr/src/threads/combined/prucpu.c \ + nsprpub/pr/src/threads/combined/prucv.c \ + nsprpub/pr/src/threads/combined/prulock.c \ + nsprpub/pr/src/threads/combined/prustack.c \ + nsprpub/pr/src/threads/combined/pruthr.c +# gcc/emx sources +VBox-xpcom-nspr_SOURCES.os2 += \ + nsprpub/pr/src/md/os2/os2emx.s \ + nsprpub/pr/src/md/os2/os2vaclegacy.s +# IBM VAC sources (not used) +#VBox-xpcom-nspr_SOURCES.os2 += \ +# nsprpub/pr/src/md/os2/os2vacpp.asm + +VBox-xpcom-nspr_SOURCES.solaris = nsprpub/pr/src/md/unix/solaris.c +VBox-xpcom-nspr_SOURCES.solaris.x86 = nsprpub/pr/src/md/unix/os_SunOS_x86.s +VBox-xpcom-nspr_SOURCES.solaris.amd64 = nsprpub/pr/src/md/unix/os_SunOS_x86_64.s + +# generate build stamps +nsprpub/pr/src/prvrsion.c_DEPS = $(VBox-xpcom-nspr_0_OUTDIR)/_pr_bld.h +nsprpub/lib/ds/plvrsion.c_DEPS = $(VBox-xpcom-nspr_0_OUTDIR)/_pl_bld.h +VBox-xpcom-nspr_CLEAN += \ + $(VBox-xpcom-nspr_0_OUTDIR)/_pr_bld.h \ + $(VBox-xpcom-nspr_0_OUTDIR)/_pl_bld.h + +$$(VBox-xpcom-nspr_0_OUTDIR)/_pr_bld.h: | $$(VBox-xpcom-nspr_0_OUTDIR)/ + $(call MSG_GENERATE,,$@) + $(QUIET)$(APPEND) -t $@ '#define _BUILD_STRING "$(date +%Y-%m-%d %T)"' + +$$(VBox-xpcom-nspr_0_OUTDIR)/_pl_bld.h: | $$(VBox-xpcom-nspr_0_OUTDIR)/ + $(call MSG_GENERATE,,$@) + $(QUIET)$(APPEND) -t $@ '#define _BUILD_STRING "$(date +%Y-%m-%d %T)"' + +$(evalcall2 VBOX_XPCOM_X86,VBox-xpcom-nspr) + + +VBox-xpcom-typelib_TEMPLATE = XPCOM +VBox-xpcom-typelib_INSTTYPE = none +VBox-xpcom-typelib_SOURCES = \ + xpcom/typelib/xpt/src/xpt_arena.c \ + xpcom/typelib/xpt/src/xpt_struct.c \ + xpcom/typelib/xpt/src/xpt_xdr.c +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-typelib) + +VBox-xpcom-string_TEMPLATE = XPCOM +VBox-xpcom-string_INSTTYPE = none +VBox-xpcom-string_SOURCES = \ + xpcom/string/src/nsAString.cpp \ + xpcom/string/src/nsDependentSubstring.cpp \ + xpcom/string/src/nsObsoleteAStringThunk.cpp \ + xpcom/string/src/nsPrintfCString.cpp \ + xpcom/string/src/nsPromiseFlatString.cpp \ + xpcom/string/src/nsReadableUtils.cpp \ + xpcom/string/src/nsSubstring.cpp \ + xpcom/string/src/nsSubstringTuple.cpp \ + xpcom/string/src/nsString.cpp \ + xpcom/string/src/nsStringComparator.cpp \ + xpcom/string/src/nsStringObsolete.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-string) + +VBox-xpcom-base_TEMPLATE = XPCOM +VBox-xpcom-base_INSTTYPE = none +VBox-xpcom-base_DEFS = _IMPL_NS_COM +VBox-xpcom-base_SOURCES = \ + xpcom/base/nsAllocator.cpp \ + xpcom/base/nsConsoleMessage.cpp \ + xpcom/base/nsConsoleService.cpp \ + xpcom/base/nsDebugImpl.cpp \ + xpcom/base/nsErrorService.cpp \ + xpcom/base/nsExceptionService.cpp \ + xpcom/base/nsID.cpp \ + xpcom/base/nsMemoryImpl.cpp \ + xpcom/base/nsTraceRefcntImpl.cpp \ + xpcom/base/nsStackFrameUnix.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-base) + +VBox-xpcom-ds_TEMPLATE = XPCOM +VBox-xpcom-ds_INSTTYPE = none +VBox-xpcom-ds_DEFS = _IMPL_NS_COM +VBox-xpcom-ds_SOURCES = \ + xpcom/ds/pldhash.c \ + xpcom/ds/nsAtomTable.cpp \ + xpcom/ds/nsAtomService.cpp \ + xpcom/ds/nsByteBuffer.cpp \ + xpcom/ds/nsCheapSets.cpp \ + xpcom/ds/nsCRT.cpp \ + xpcom/ds/nsDeque.cpp \ + xpcom/ds/nsEmptyEnumerator.cpp \ + xpcom/ds/nsEnumeratorUtils.cpp \ + xpcom/ds/nsFixedSizeAllocator.cpp \ + xpcom/ds/nsHashSets.cpp \ + xpcom/ds/nsHashtable.cpp \ + xpcom/ds/nsObserverList.cpp \ + xpcom/ds/nsObserverService.cpp \ + xpcom/ds/nsProperties.cpp \ + xpcom/ds/nsPersistentProperties.cpp \ + xpcom/ds/nsQuickSort.cpp \ + xpcom/ds/nsRecyclingAllocator.cpp \ + xpcom/ds/nsStaticNameTable.cpp \ + xpcom/ds/nsStringEnumerator.cpp \ + xpcom/ds/nsSupportsArray.cpp \ + xpcom/ds/nsSupportsArrayEnumerator.cpp \ + xpcom/ds/nsSupportsPrimitives.cpp \ + xpcom/ds/nsTHashtable.cpp \ + xpcom/ds/nsUnicharBuffer.cpp \ + xpcom/ds/nsVariant.cpp \ + xpcom/ds/nsVoidArray.cpp \ + xpcom/ds/nsTextFormatter.cpp \ + xpcom/ds/nsTimelineService.cpp \ + xpcom/ds/nsValueArray.cpp \ + xpcom/ds/nsCOMArray.cpp \ + xpcom/ds/nsArray.cpp \ + xpcom/ds/nsArrayEnumerator.cpp +# xpcom/ds/nsHashPropertyBag.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-ds) + +# @todo what about MOZ_USER_DIR? +VBox-xpcom-io_TEMPLATE = XPCOM +VBox-xpcom-io_INSTTYPE = none +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + VBox-xpcom-io_DEFS = _IMPL_NS_COM MOZ_USER_DIR=".mozilla" +else + VBox-xpcom-io_DEFS = _IMPL_NS_COM MOZ_USER_DIR=\".mozilla\" +endif +if defined(VBOX_WITH_HARDENING) && defined(VBOX_PATH_APP_PRIVATE_ARCH) + ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + VBox-xpcom-io_DEFS += MOZ_DEFAULT_VBOX_XPCOM_HOME="$(VBOX_PATH_APP_PRIVATE_ARCH)" + else + VBox-xpcom-io_DEFS += MOZ_DEFAULT_VBOX_XPCOM_HOME=\"$(VBOX_PATH_APP_PRIVATE_ARCH)\" + endif +endif +VBox-xpcom-io_INCS.darwin = \ + xpcom/MoreFiles +VBox-xpcom-io_SOURCES = \ + xpcom/io/nsAppFileLocationProvider.cpp \ + xpcom/io/nsBinaryStream.cpp \ + xpcom/io/nsByteArrayInputStream.cpp \ + xpcom/io/nsDirectoryService.cpp \ + xpcom/io/nsEscape.cpp \ + xpcom/io/nsFastLoadFile.cpp \ + xpcom/io/nsFastLoadService.cpp \ + xpcom/io/nsInputStreamTee.cpp \ + xpcom/io/nsLinebreakConverter.cpp \ + xpcom/io/nsLocalFileCommon.cpp \ + xpcom/io/nsMultiplexInputStream.cpp \ + xpcom/io/nsPipe3.cpp \ + xpcom/io/nsStreamUtils.cpp \ + xpcom/io/nsScriptableInputStream.cpp \ + xpcom/io/nsSegmentedBuffer.cpp \ + xpcom/io/SpecialSystemDirectory.cpp \ + xpcom/io/nsStorageStream.cpp \ + xpcom/io/nsStringStream.cpp \ + xpcom/io/nsUnicharInputStream.cpp \ + xpcom/io/nsNativeCharsetUtils.cpp +VBox-xpcom-io_SOURCES.darwin.x86 = \ + xpcom/io/nsLocalFileOSX.cpp \ + xpcom/MoreFiles/FSCopyObject.c \ + xpcom/MoreFiles/MoreFilesX.c +if1of ($(KBUILD_TARGET) $(KBUILD_TARGET).$(KBUILD_TARGET_ARCH), freebsd linux netbsd openbsd solaris darwin.amd64 darwin.arm64) +VBox-xpcom-io_SOURCES += \ + xpcom/io/nsLocalFileUnix.cpp +endif +VBox-xpcom-io_SOURCES.os2 = \ + xpcom/io/nsLocalFileOS2.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-io) + +VBox-xpcom-components_TEMPLATE = XPCOM +VBox-xpcom-components_INSTTYPE = none +VBox-xpcom-components_DEFS = _IMPL_NS_COM EXPORT_XPTI_API +VBox-xpcom-components_SOURCES = \ + xpcom/components/nsCategoryManager.cpp \ + xpcom/components/nsComponentManager.cpp \ + xpcom/components/nsComponentManagerObsolete.cpp \ + xpcom/components/nsNativeComponentLoader.cpp \ + xpcom/components/nsServiceManagerObsolete.cpp \ + xpcom/components/xcDll.cpp \ + xpcom/components/nsStaticComponentLoader.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-components) + +VBox-xpcom-threads_TEMPLATE = XPCOM +VBox-xpcom-threads_INSTTYPE = none +VBox-xpcom-threads_DEFS = _IMPL_NS_COM +VBox-xpcom-threads_SOURCES = \ + xpcom/threads/plevent.c \ + xpcom/threads/nsAutoLock.cpp \ + xpcom/threads/nsEnvironment.cpp \ + xpcom/threads/nsEventQueue.cpp \ + xpcom/threads/nsEventQueueService.cpp \ + xpcom/threads/nsThread.cpp \ + xpcom/threads/nsTimerImpl.cpp \ + xpcom/threads/nsProcessCommon.cpp \ + xpcom/threads/TimerThread.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-threads) + +VBox-xpcom-xptinfo_TEMPLATE = XPCOM +VBox-xpcom-xptinfo_INSTTYPE = none +VBox-xpcom-xptinfo_DEFS = _IMPL_NS_COM _IMPL_NS_BASE EXPORT_XPTI_API EXPORT_XPT_API +VBox-xpcom-xptinfo_SOURCES = \ + xpcom/reflect/xptinfo/src/xptiFile.cpp \ + xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp \ + xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp \ + xpcom/reflect/xptinfo/src/xptiManifest.cpp \ + xpcom/reflect/xptinfo/src/xptiMisc.cpp \ + xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp \ + xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp \ + xpcom/reflect/xptinfo/src/xptiZipItem.cpp \ + xpcom/reflect/xptinfo/src/xptiZipLoader.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-xptinfo) + + +VBox-xpcom-xptcall_TEMPLATE = XPCOMYASM +VBox-xpcom-xptcall_INSTTYPE = none +VBox-xpcom-xptcall_DEFS = _IMPL_NS_COM _IMPL_NS_BASE EXPORT_XPTC_API +VBox-xpcom-xptcall_DEFS.darwin = KEEP_STACK_16_BYTE_ALIGNED +VBox-xpcom-xptcall_DEFS.os2 = MOZ_NEED_LEADING_UNDERSCORE +VBox-xpcom-xptcall_INCS.os2 = xpcom/reflect/xptcall/src/md/unix +VBox-xpcom-xptcall_SOURCES = xpcom/reflect/xptcall/src/xptcall.cpp +VBox-xpcom-xptcall_SOURCES.darwin.x86 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp \ + xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp +VBox-xpcom-xptcall_SOURCES.freebsd.x86 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp \ + xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp +VBox-xpcom-xptcall_SOURCES.linux.x86 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp \ + xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp +VBox-xpcom-xptcall_SOURCES.os2 = xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp \ + xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp +VBox-xpcom-xptcall_SOURCES.solaris.x86 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp \ + xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp +VBox-xpcom-xptcall_SOURCES.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm +VBox-xpcom-xptcall_SOURCES.arm64 = xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp \ + xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp +VBox-xpcom-xptcall_SOURCES.darwin.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp # Underscore prefix. +VBox-xpcom-xptcall_SOURCES.freebsd.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp +VBox-xpcom-xptcall_SOURCES.linux.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp +ifndef VBOX_GCC_USING_SOLARIS_AS +VBox-xpcom-xptcall_SOURCES.solaris.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp +else +VBox-xpcom-xptcall_SOURCES.solaris.amd64 = xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp +endif + +xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp_CXXFLAGS = -O0 +# -O0 works fine, while -O1 doesn't. The gcc man page can't be listing all the -f* +# stuff that -O1 enables, because when using the options without -O1, it's -fomit-frame-pointer +# that triggers is, while -O1 -fno-omit-frame-pointer does not work. Anyway, it's probably a gcc/mozila +# bug and it's not worth investigating as I'm not the maintainger of the solaris gcc port. [bird, 2007-09-17] + +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-xptcall) + + +VBox-xpcom-proxy_TEMPLATE = XPCOM +VBox-xpcom-proxy_INSTTYPE = none +VBox-xpcom-proxy_DEFS = _IMPL_NS_COM EXPORT_XPTC_API EXPORT_XPTI_API +VBox-xpcom-proxy_SOURCES = \ + xpcom/proxy/src/nsProxyEvent.cpp \ + xpcom/proxy/src/nsProxyEventClass.cpp \ + xpcom/proxy/src/nsProxyEventObject.cpp \ + xpcom/proxy/src/nsProxyObjectManager.cpp \ + xpcom/proxy/src/nsProxyRelease.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-proxy) + + +# +# The VBoxXPCOM Glue static libraries. +# +# This isn't the normal XPCOM glue (see the places in XPCOM where XPCOM_GLUE is +# checked), VirtualBox has its own glue library and this means this isn't used +# much (one reason is that we don't provide frozen APIs yet). All VBox XPCOM +# client applications are dependent on the given version of both the VBox XPCOM +# runtime (binary dependency) and VirtualBox component library (COM interface +# dependency). For this reason, VBox client applications link to the VBox XPCOM +# shared library directly (instead of linking to the standalone XPCOM glue +# library that would dynamically search for and load the installed XPCOM +# runtime). For the same reason, we link all parts of XPCOM into a single +# shared XPCOM library below (as opposed to the original XPCOM where e.g. NSPR +# lives in a separate DLL). Additionally there is VBox specific glue code to +# make both the client and server side code build with both XPCOM and COM, +# which should be made part of the SDK eventually, but this is a higher level +# of abstraction than this XPCOM specific glue code. +# +VBoxXPCOMGlue_COMMON_SOURCES = \ + xpcom/glue/nsCOMPtr.cpp \ + xpcom/glue/nsComponentManagerUtils.cpp \ + xpcom/glue/nsDebug.cpp \ + xpcom/glue/nsGenericFactory.cpp \ + xpcom/glue/nsIInterfaceRequestorUtils.cpp \ + xpcom/glue/nsMemory.cpp \ + xpcom/glue/nsTraceRefcnt.cpp \ + xpcom/glue/nsWeakReference.cpp + +# dependent glue library which goes in to the VBoxXPCOM shared library +VBoxXPCOMGlue_s_TEMPLATE = XPCOM +VBoxXPCOMGlue_s_INSTTYPE = none +VBoxXPCOMGlue_s_DEFS = _IMPL_NS_COM +VBoxXPCOMGlue_s_SOURCES = $(VBoxXPCOMGlue_COMMON_SOURCES) +$(evalcall VBOX_XPCOM_X86,VBoxXPCOMGlue_s) + +# standalone glue library which all third-party client apps (if any) will +# link with (currently completely unused and nit built, to be part of the SDK) +VBoxXPCOMGlue_TEMPLATE = XPCOM +VBoxXPCOMGlue_SOURCES = $(VBoxXPCOMGlue_COMMON_SOURCES) +#VBoxXPCOMGlue_INST = lib/ $(INST_SDK)lib/ +$(evalcall VBOX_XPCOM_X86,VBoxXPCOMGlue) + + +# +# The VBoxXPCOM Shared Object, assembling all lib files. +# +VBoxXPCOM_TEMPLATE = XPCOM +VBoxXPCOM_NAME = $(basename $(notdir $(LIB_XPCOM))) +VBoxXPCOM_DEFS = BUILD_DCONNECT=1 _IMPL_NS_COM +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + VBoxXPCOM_LDFLAGS.linux = -Wl,--version-script=$(XPCOM_C_NAMESPACE_MAP) + VBoxXPCOM_LNK_DEPS.linux += $(XPCOM_C_NAMESPACE_MAP) + VBoxXPCOM_LDFLAGS.solaris = -Wl,-M,$(XPCOM_C_NAMESPACE_MAP) + VBoxXPCOM_LNK_DEPS.solaris+= $(XPCOM_C_NAMESPACE_MAP) +endif +VBoxXPCOM_SOURCES = \ + xpcom/build/nsXPComInit.cpp \ + xpcom/build/nsStringAPI.cpp +VBoxXPCOM_SOURCES.darwin = \ + vboxdeps.cpp +VBoxXPCOM_SOURCES.os2 = \ + vboxdeps.cpp +VBoxXPCOM_SOURCES.solaris = \ + vboxdeps.cpp +VBoxXPCOM_LIBS = \ + $(VBox-xpcom-typelib_1_TARGET) \ + $(VBox-xpcom-string_1_TARGET) \ + $(VBox-xpcom-base_1_TARGET) \ + $(VBox-xpcom-ds_1_TARGET) \ + $(VBox-xpcom-io_1_TARGET) \ + $(VBox-xpcom-components_1_TARGET) \ + $(VBox-xpcom-threads_1_TARGET) \ + $(VBox-xpcom-xptinfo_1_TARGET) \ + $(VBox-xpcom-xptcall_1_TARGET) \ + $(VBox-xpcom-proxy_1_TARGET) \ + $(VBox-xpcom-nspr_1_TARGET) \ + $(VBoxXPCOMGlue_s_1_TARGET) +VBoxXPCOM_LIBS.linux = \ + pthread dl + +ifeq ($(filter-out freebsd linux netbsd openbsd,$(KBUILD_TARGET)),) # gnu ld. +VBoxXPCOM_LDFLAGS = -Wl,--whole-archive \ + $(VBox-xpcom-typelib_1_TARGET) \ + $(VBox-xpcom-string_1_TARGET) \ + $(VBox-xpcom-base_1_TARGET) \ + $(VBox-xpcom-ds_1_TARGET) \ + $(VBox-xpcom-io_1_TARGET) \ + $(VBox-xpcom-components_1_TARGET) \ + $(VBox-xpcom-threads_1_TARGET) \ + $(VBox-xpcom-xptinfo_1_TARGET) \ + $(VBox-xpcom-xptcall_1_TARGET) \ + $(VBox-xpcom-proxy_1_TARGET) \ + $(VBox-xpcom-nspr_1_TARGET) \ + $(VBoxXPCOMGlue_s_1_TARGET) \ + -Wl,--no-whole-archive +endif + +VBoxXPCOM_LDFLAGS.solaris += -Wl,-z,allextract \ + $(VBox-xpcom-typelib_1_TARGET) \ + $(VBox-xpcom-string_1_TARGET) \ + $(VBox-xpcom-base_1_TARGET) \ + $(VBox-xpcom-ds_1_TARGET) \ + $(VBox-xpcom-io_1_TARGET) \ + $(VBox-xpcom-components_1_TARGET) \ + $(VBox-xpcom-threads_1_TARGET) \ + $(VBox-xpcom-xptinfo_1_TARGET) \ + $(VBox-xpcom-xptcall_1_TARGET) \ + $(VBox-xpcom-proxy_1_TARGET) \ + $(VBox-xpcom-nspr_1_TARGET) \ + $(VBoxXPCOMGlue_s_1_TARGET) \ + -Wl,-z,defaultextract + +# EF heap +#VBoxXPCOM_LIBS += $(LIB_RUNTIME_EF) +#VBoxXPCOM_LDFLAGS = -Wl,--whole-archive $(VBoxXPCOM_LIBS) -Wl,--no-whole-archive $(LIB_RUNTIME) +VBoxXPCOM_LDFLAGS.darwin = -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxXPCOM.dylib + +# +# The 32-bit VBoxXPCOM Shared Object, assembling all lib files. +# +VBoxXPCOM-x86_TEMPLATE = XPCOM-x86 +VBoxXPCOM-x86_EXTENDS = VBoxXPCOM +VBoxXPCOM-x86_NAME = VBoxXPCOM-x86 +VBoxXPCOM-x86_LIBS = \ + $(VBox-xpcom-typelib-x86_1_TARGET) \ + $(VBox-xpcom-string-x86_1_TARGET) \ + $(VBox-xpcom-base-x86_1_TARGET) \ + $(VBox-xpcom-ds-x86_1_TARGET) \ + $(VBox-xpcom-io-x86_1_TARGET) \ + $(VBox-xpcom-components-x86_1_TARGET) \ + $(VBox-xpcom-threads-x86_1_TARGET) \ + $(VBox-xpcom-xptinfo-x86_1_TARGET) \ + $(VBox-xpcom-xptcall-x86_1_TARGET) \ + $(VBox-xpcom-proxy-x86_1_TARGET) \ + $(VBox-xpcom-nspr-x86_1_TARGET) \ + $(VBoxXPCOMGlue_s-x86_1_TARGET) + +ifeq ($(filter-out freebsd linux netbsd openbsd,$(KBUILD_TARGET)),) # gnu ld. +VBoxXPCOM-x86_LDFLAGS = -Wl,--whole-archive \ + $(VBox-xpcom-typelib-x86_1_TARGET) \ + $(VBox-xpcom-string-x86_1_TARGET) \ + $(VBox-xpcom-base-x86_1_TARGET) \ + $(VBox-xpcom-ds-x86_1_TARGET) \ + $(VBox-xpcom-io-x86_1_TARGET) \ + $(VBox-xpcom-components-x86_1_TARGET) \ + $(VBox-xpcom-threads-x86_1_TARGET) \ + $(VBox-xpcom-xptinfo-x86_1_TARGET) \ + $(VBox-xpcom-xptcall-x86_1_TARGET) \ + $(VBox-xpcom-proxy-x86_1_TARGET) \ + $(VBox-xpcom-nspr-x86_1_TARGET) \ + $(VBoxXPCOMGlue_s-x86_1_TARGET) \ + -Wl,--no-whole-archive +endif + +VBoxXPCOM-x86_LDFLAGS.solaris += -Wl,-z,allextract \ + $(VBox-xpcom-typelib-x86_1_TARGET) \ + $(VBox-xpcom-string-x86_1_TARGET) \ + $(VBox-xpcom-base-x86_1_TARGET) \ + $(VBox-xpcom-ds-x86_1_TARGET) \ + $(VBox-xpcom-io-x86_1_TARGET) \ + $(VBox-xpcom-components-x86_1_TARGET) \ + $(VBox-xpcom-threads-x86_1_TARGET) \ + $(VBox-xpcom-xptinfo-x86_1_TARGET) \ + $(VBox-xpcom-xptcall-x86_1_TARGET) \ + $(VBox-xpcom-proxy-x86_1_TARGET) \ + $(VBox-xpcom-nspr-x86_1_TARGET) \ + $(VBoxXPCOMGlue_s-x86_1_TARGET) \ + -Wl,-z,defaultextract + + +# +# VBoxXPCOMImp - Import library/hack. +# +ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +$(call VBOX_GENERATE_IMPORT_TARGET_FN,VBoxXPCOMImp,VBoxXPCOM,VBoxXPCOM-mangled.def) +else +$(call VBOX_GENERATE_IMPORT_TARGET_FN,VBoxXPCOMImp,VBoxXPCOM,VBoxXPCOM.def) +endif + + +# +# IPC templates. +# +ifdef VBOX_IPC_RELEASE_LOG +IPC_LOGGING = 1 +else ifneq ($(KBUILD_TYPE),release) +IPC_LOGGING = 1 +endif + +TEMPLATE_XPCOMIPC = XPCOM IPC libraries +TEMPLATE_XPCOMIPC_EXTENDS = XPCOM +TEMPLATE_XPCOMIPC_DEFS = $(TEMPLATE_XPCOM_DEFS) BUILD_DCONNECT=1 +ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING + TEMPLATE_XPCOMIPC_DEFS += IPC_DAEMON_APP_NAME="VBoxXPCOMIPCD$(SUFF_EXE)" +else + TEMPLATE_XPCOMIPC_DEFS += IPC_DAEMON_APP_NAME=\"VBoxXPCOMIPCD$(SUFF_EXE)\" +endif +ifdef IPC_LOGGING + TEMPLATE_XPCOMIPC_DEFS += IPC_LOGGING +endif +TEMPLATE_XPCOMIPC_LIBS = $(VBoxXPCOM_1_TARGET) $(TEMPLATE_XPCOM_LIBS) +ifneq ($(KBUILD_TARGET),win) + ifeq ($(filter-out solaris.x86 %.amd64 %.sparc32 %.sparc64,$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)),) ## TODO: cleanup! + if defined(VBOX_WITH_RELATIVE_RUNPATH) && !defined(VBOX_WITH_HARDENING) + TEMPLATE_XPCOMIPC_LDFLAGS = $(filter-out '$(VBOX_GCC_RPATH_OPT)%',$(TEMPLATE_XPCOM_LDFLAGS)) '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)/..' + endif + else ifndef VBOX_WITH_HARDENING + ifdef VBOX_WITH_RELATIVE_RUNPATH + TEMPLATE_XPCOMIPC_LDFLAGS = $(filter-out '$(VBOX_GCC_RPATH_OPT)%',$(TEMPLATE_XPCOM_LDFLAGS)) '$(VBOX_GCC_RPATH_OPT)$(VBOX_WITH_RELATIVE_RUNPATH)/..' + endif + endif +endif + +TEMPLATE_XPCOMIPC-x86 = 32-bit XPCOM IPC libraries +TEMPLATE_XPCOMIPC-x86_EXTENDS = XPCOMIPC +TEMPLATE_XPCOMIPC-x86_BLD_TRG_ARCH = x86 +TEMPLATE_XPCOMIPC-x86_LIBS = $(VBoxXPCOM-x86_1_TARGET) $(TEMPLATE_XPCOM-x86_LIBS) + +TEMPLATE_XPCOMIPCEXE = XPCOM IPC executables +TEMPLATE_XPCOMIPCEXE_EXTENDS = XPCOMEXE +TEMPLATE_XPCOMIPCEXE_DEFS = $(TEMPLATE_XPCOMEXE_DEFS) BUILD_DCONNECT=1 +ifdef IPC_LOGGING + TEMPLATE_XPCOMIPCEXE_DEFS += IPC_LOGGING +endif + +# +# Shared IPC code. Used by the IPC component as well as the executables. +# +VBox-xpcom-ipcshared_TEMPLATE = XPCOMIPC +VBox-xpcom-ipcshared_INSTTYPE = none +VBox-xpcom-ipcshared_SOURCES = \ + ipc/ipcd/shared/src/ipcLog.cpp \ + ipc/ipcd/shared/src/ipcConfig.cpp \ + ipc/ipcd/shared/src/ipcMessage.cpp \ + ipc/ipcd/shared/src/ipcMessagePrimitives.cpp \ + ipc/ipcd/shared/src/ipcStringList.cpp \ + ipc/ipcd/shared/src/ipcIDList.cpp \ + ipc/ipcd/shared/src/ipcm.cpp +$(evalcall VBOX_XPCOM_X86,VBox-xpcom-ipcshared) + + +# +# DCONNECT client shared object +# +VBoxXPCOMIPCC_TEMPLATE = XPCOMIPC +VBoxXPCOMIPCC_NAME.os2 = VBoxIPCC +VBoxXPCOMIPCC_INST = $(INST_BIN)components/ +#VBoxXPCOMIPCC_DEFS = HAVE_DEPENDENT_LIBS - dependentLibs.h is linux specific, so this cannot be required. +VBoxXPCOMIPCC_SOURCES = \ + ipc/ipcd/client/src/ipcdclient.cpp \ + ipc/ipcd/client/src/ipcService.cpp \ + ipc/ipcd/client/src/ipcModuleFactory.cpp \ + ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp\ + \ + ipc/ipcd/util/src/ipcMessageReader.cpp \ + ipc/ipcd/util/src/ipcMessageWriter.cpp \ + \ + ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp \ + ipc/ipcd/extensions/lock/src/ipcLockService.cpp \ + \ + ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp \ + \ + ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp \ + ipc/ipcd/extensions/transmngr/common/tmVector.cpp + +ifeq ($(KBUILD_TARGET),win) +VBoxXPCOMIPCC_SOURCES += \ + ipc/ipcd/client/src/ipcConnectionWin.cpp +else +VBoxXPCOMIPCC_SOURCES += \ + ipc/ipcd/client/src/ipcConnectionUnix.cpp +endif +VBoxXPCOMIPCC_LDFLAGS.darwin = -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/components/VBoxXPCOMIPCC.dylib +VBoxXPCOMIPCC_LIBS = \ + $(VBox-xpcom-ipcshared_1_TARGET) + +# 32-bit version of the component. +$(evalcall VBOX_XPCOM_X86,VBoxXPCOMIPCC) +VBoxXPCOMIPCC-x86_LIBS = \ + $(VBox-xpcom-ipcshared-x86_1_TARGET) + + +# +# DCONNECT daemon executable +# +VBoxXPCOMIPCD_TEMPLATE = XPCOMIPCEXE +VBoxXPCOMIPCD_SOURCES = \ + ipc/ipcd/daemon/src/ipcd.cpp \ + ipc/ipcd/daemon/src/ipcClient.cpp \ + ipc/ipcd/daemon/src/ipcModuleReg.cpp \ + ipc/ipcd/daemon/src/ipcCommandModule.cpp +ifeq ($(KBUILD_TARGET),win) + VBoxXPCOMIPCD_SOURCES += \ + ipc/ipcd/daemon/src/ipcdWin.cpp +else + VBoxXPCOMIPCD_SOURCES += \ + ipc/ipcd/daemon/src/ipcdUnix.cpp +endif + + +# +# Include sub-makefiles for the Python<->XPCOM and Java<->XPCOM bridges. +# +ifndef VBOX_ONLY_EXTPACKS + # Find the Python headers for the Python<->XPCOM bridge if enabled. + ifdef VBOX_WITH_PYTHON + include $(PATH_SUB_CURRENT)/python/Makefile.kmk + endif + + ifdef VBOX_WITH_JXPCOM + include $(PATH_SUB_CURRENT)/java/Makefile.kmk + endif +endif # !VBOX_ONLY_EXTPACKS + + +# +# testcases +# +tstnsIFileEnumerator_TEMPLATE = XPCOMTSTEXE +tstnsIFileEnumerator_SOURCES = xpcom/tests/nsIFileEnumerator.cpp +tstnsIFileTest_TEMPLATE = XPCOMTSTEXE +tstnsIFileTest_SOURCES = xpcom/tests/nsIFileTest.cpp +tstTestArray_TEMPLATE = XPCOMTSTEXE +tstTestArray_SOURCES = xpcom/tests/TestArray.cpp +tstTestAtoms_TEMPLATE = XPCOMTSTEXE +tstTestAtoms_SOURCES = xpcom/tests/TestAtoms.cpp +tstTestAutoLock_TEMPLATE = XPCOMTSTEXE +tstTestAutoLock_SOURCES = xpcom/tests/TestAutoLock.cpp +tstTestCallTemplates_TEMPLATE = XPCOMTSTEXE +tstTestCallTemplates_SOURCES = xpcom/tests/TestCallTemplates.cpp +tstTestCOMPtr_TEMPLATE = XPCOMTSTEXE +tstTestCOMPtr_SOURCES = xpcom/tests/TestCOMPtr.cpp +tstTestCOMPtrEq_TEMPLATE = XPCOMTSTEXE +tstTestCOMPtrEq_SOURCES = xpcom/tests/TestCOMPtrEq.cpp +tstTestCRT_TEMPLATE = XPCOMTSTEXE +tstTestCRT_SOURCES = xpcom/tests/TestCRT.cpp +tstTestFactory_TEMPLATE = XPCOMTSTEXE +tstTestFactory_SOURCES = xpcom/tests/TestFactory.cpp +tstTestHashtables_TEMPLATE = XPCOMTSTEXE +tstTestHashtables_SOURCES = xpcom/tests/TestHashtables.cpp +tstTestID_TEMPLATE = XPCOMTSTEXE +tstTestID_SOURCES = xpcom/tests/TestID.cpp +tstTestObserverService_TEMPLATE= XPCOMTSTEXE +tstTestObserverService_SOURCES = xpcom/tests/TestObserverService.cpp +tstTestPermanentAtoms_TEMPLATE = XPCOMTSTEXE +tstTestPermanentAtoms_SOURCES = xpcom/tests/TestPermanentAtoms.cpp +tstTestPipes_TEMPLATE = XPCOMTSTEXE +tstTestPipes_SOURCES = xpcom/tests/TestPipes.cpp +tstTestServMgr_TEMPLATE = XPCOMTSTEXE +tstTestServMgr_SOURCES = xpcom/tests/TestServMgr.cpp +tstTestServMgr_INCS = xpcom/tests/services +tstTestThreads_TEMPLATE = XPCOMTSTEXE +tstTestThreads_SOURCES = xpcom/tests/TestThreads.cpp +tstTestXPIDLString_TEMPLATE = XPCOMTSTEXE +tstTestXPIDLString_SOURCES = xpcom/tests/TestXPIDLString.cpp +tstTestXPTCInvoke_TEMPLATE = XPCOMTSTEXE +tstTestXPTCInvoke_SOURCES = xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp +tstTestDeque_TEMPLATE = XPCOMTSTEXE +tstTestDeque_SOURCES = xpcom/tests/TestDeque.cpp +tstTestAutoPtr_TEMPLATE = XPCOMTSTEXE +tstTestAutoPtr_SOURCES = xpcom/tests/TestAutoPtr.cpp +tstTestMinStringAPI_TEMPLATE = XPCOMTSTEXE +tstTestMinStringAPI_SOURCES = xpcom/tests/TestMinStringAPI.cpp +tstTestStrings_TEMPLATE = XPCOMTSTEXE +tstTestStrings_SOURCES = xpcom/tests/TestStrings.cpp +tstPrimitiveTest_TEMPLATE = XPCOMTSTEXE +tstPrimitiveTest_SOURCES = xpcom/typelib/xpt/tests/PrimitiveTest.c +tstSimpleTypeLib_TEMPLATE = XPCOMTSTEXE +tstSimpleTypeLib_SOURCES = xpcom/typelib/xpt/tests/SimpleTypeLib.c +tstXptDump_TEMPLATE = XPCOMTSTEXE +tstXptDump_SOURCES = xpcom/typelib/xpt/tools/xpt_dump.c +tstXptLink_TEMPLATE = XPCOMTSTEXE +tstXptLink_SOURCES = xpcom/typelib/xpt/tools/xpt_link.c + + + +OTHER_CLEAN += \ + $(PATH_TARGET)/VBox-xpcom-idl-timestamp \ + $(addprefix $(VBOX_PATH_SDK)/bindings/xpcom/include,$(notdir $(subst .idl,.h,$(XPCOM_IDLFILES)))) \ + $(addprefix $(VBOX_PATH_SDK)/bindings/xpcom/include,$(notdir $(subst .idl,.xpt,$(XPCOM_IDLFILES)))) \ + $(addprefix $(VBOX_PATH_SDK)/bindings/xpcom/idl/,$(notdir $(XPCOM_IDLFILES))) \ + $(addprefix $(PATH_TARGET)/VBox-xpcom-xpt-files/,$(notdir $(subst .idl,.xpt,$(XPCOM_IDLFILES)))) + + +# +# Create and install VBoxXPCOMBase.xpt +# +INSTALLS += VBoxXPCOMBase-xpt-inst +VBOX_XPTFILES = $(addprefix $(PATH_TARGET)/VBox-xpcom-xpt-files/, \ + nsIConsoleListener.xpt \ + nsIConsoleMessage.xpt \ + nsIConsoleService.xpt \ + nsIErrorService.xpt \ + nsIException.xpt \ + nsIExceptionService.xpt \ + nsIDebug.xpt \ + nsIInterfaceRequestor.xpt \ + nsIMemory.xpt \ + nsIProgrammingLanguage.xpt \ + nsISupports.xpt \ + nsITraceRefcnt.xpt \ + nsIWeakReference.xpt \ + nsrootidl.xpt \ + nsIAtom.xpt \ + nsIAtomService.xpt \ + nsICollection.xpt \ + nsIEnumerator.xpt \ + nsIPersistentProperties2.xpt \ + nsIPropertyBag.xpt \ + nsIRecyclingAllocator.xpt \ + nsIVariant.xpt \ + nsISerializable.xpt \ + nsIStringEnumerator.xpt \ + nsISupportsArray.xpt \ + nsISupportsIterators.xpt \ + nsITimelineService.xpt \ + nsIArray.xpt \ + nsIObserverService.xpt \ + nsIObserver.xpt \ + nsIProperties.xpt \ + nsISimpleEnumerator.xpt \ + nsISupportsPrimitives.xpt \ + nsIBinaryInputStream.xpt \ + nsIBinaryOutputStream.xpt \ + nsIByteArrayInputStream.xpt \ + nsIFastLoadFileControl.xpt \ + nsIFastLoadService.xpt \ + nsIInputStreamTee.xpt \ + nsILineInputStream.xpt \ + nsIMultiplexInputStream.xpt \ + nsIObjectInputStream.xpt \ + nsIObjectOutputStream.xpt \ + nsIPipe.xpt \ + nsISeekableStream.xpt \ + nsIStorageStream.xpt \ + nsIStringStream.xpt \ + nsIStreamBufferAccess.xpt \ + nsIAsyncInputStream.xpt \ + nsIAsyncOutputStream.xpt \ + nsIDirectoryService.xpt \ + nsIFile.xpt \ + nsILocalFile.xpt \ + nsIInputStream.xpt \ + nsIOutputStream.xpt \ + nsIScriptableInputStream.xpt \ + nsIComponentLoader.xpt \ + nsIComponentLoaderManager.xpt \ + nsIComponentManagerObsolete.xpt \ + nsINativeComponentLoader.xpt \ + nsIClassInfo.xpt \ + nsIComponentRegistrar.xpt \ + nsIFactory.xpt \ + nsIModule.xpt \ + nsIServiceManager.xpt \ + nsIComponentManager.xpt \ + nsICategoryManager.xpt \ + nsIThread.xpt \ + nsITimer.xpt \ + nsITimerInternal.xpt \ + nsITimerManager.xpt \ + nsIRunnable.xpt \ + nsIEventTarget.xpt \ + nsIEventQueue.xpt \ + nsIEventQueueService.xpt \ + nsIEnvironment.xpt \ + nsIProcess.xpt \ + nsIInterfaceInfo.xpt \ + nsIInterfaceInfoManager.xpt \ + nsIXPTLoader.xpt) + +VBoxXPCOMBase-xpt-inst_INST = $(INST_BIN)components/ +VBoxXPCOMBase-xpt-inst_MODE = 0644 +VBoxXPCOMBase-xpt-inst_SOURCES = \ + $(PATH_TARGET)/VBox-xpcom-xpt-files/VBoxXPCOMBase.xpt +VBoxXPCOMBase-xpt-inst_CLEAN = \ + $(VBOX_XPTFILES) \ + $(PATH_TARGET)/VBox-xpcom-xpt-files/VBoxXPCOMBase.xpt + +# combined typelib library +$(PATH_TARGET)/VBox-xpcom-xpt-files/VBoxXPCOMBase.xpt: $$(VBOX_XPTFILES) | $$(xpt_link_1_TARGET) $(PATH_TARGET)/VBox-xpcom-xpt-files/ + $(call MSG_LINK,XPCOM_TYPELIB,$@) + $(QUIET)$(MKDIR) -p -- $(PATH_STAGE_BIN)/components + $(QUIET)$(xpt_link_1_TARGET) $@ $^ + + + +# generate rules +include $(FILE_KBUILD_SUB_FOOTER) + + + +# +# Generate IDL rules. +# + +## +# Define for compiling one IDL into a header and a typelib +# @param idl The filename with everything. +define def_IDL +$(VBOX_PATH_SDK)/bindings/xpcom/include/$(notdir $(subst .idl,.h,$(idl))) \ ++ $(PATH_TARGET)/VBox-xpcom-xpt-files/$(notdir $(subst .idl,.xpt,$(idl))): \ + $(VBOX_PATH_XPCOM_SRC)/$(idl) \ + | $$$$(xpidl_1_TARGET) \ + $(PATH_TARGET)/VBox-xpcom-xpt-files/ + $$(call MSG_TOOL,xpidl,XPCOM,$$<,$$@) + $$(QUIET)$(MKDIR) -p $(VBOX_PATH_SDK)/bindings/xpcom/include $(VBOX_PATH_SDK)/bindings/xpcom/idl + $$(QUIET)$$(xpidl_1_TARGET) -m header $(XPIDL_INCS) -e $$@ $$< + $$(QUIET)$$(xpidl_1_TARGET) -m typelib $(XPIDL_INCS) -e $(addprefix $(PATH_TARGET)/VBox-xpcom-xpt-files/,$(notdir $(subst .idl,.xpt,$(idl)))) $$< + $$(QUIET)$(CP) $$< $$(VBOX_PATH_SDK)/bindings/xpcom/idl +endef + +$(foreach idl, $(XPCOM_IDLFILES), $(eval $(def_IDL))) + +# dummy target. +$(PATH_TARGET)/VBox-xpcom-idl-timestamp: $$(addprefix $$(VBOX_PATH_SDK)/bindings/xpcom/include/,$$(notdir $$(subst .idl,.h,$$(XPCOM_IDLFILES)))) + $(call MSG_L1,IDL processing completed.) + $(QUIET)$(MKDIR) -p $(dir $@) + $(QUIET)$(APPEND) -t $@ + +# +# HACK ALERT! Make sure main doesn't start using xpidl before we're done +# with the idl files here. The trick here is that we're using TARGET_xpidl, +# i.e. the copy residing in obj/, while VBOX_XPIDL is pointing to +# xpidl_1_STAGE_TARGET which is the one in bin/. +# +$(VBOX_XPIDL): | $(PATH_TARGET)/VBox-xpcom-idl-timestamp + + +# +# Generate linker map file filtering out unwanted global symbols. +# +$(PATH_TARGET)/xpcom-namespace-cleanup.map foo.map: $$(VBoxXPCOM_LIBS) $$(VBoxXPCOM_2_OBJS) + $(call MSG_L1, Creating linker map $@ for scrubbing the symbol namespace) + $(QUIET)$(APPEND) -t $@ '{ local: *; global: ' + $(QUIET)$(VBOX_NM) -p -g $^ \ + | $(SED) -n \ + -e '/^$$/b' \ + -e '/:$$/b' \ + -e '/ U /b' \ + -e 's/^[^ ]* [A-Z] \(.*\)$$/\1/' \ + -e 's/\<_Z[^ ]*$$/&;/p' \ + -e 's/\ $@-sedtmp +# $(QUIET)$(MV) $@-sedtmp $@ +# endif +#endif + diff --git a/src/libs/xpcom18a4/VBoxXPCOM-mangled.def b/src/libs/xpcom18a4/VBoxXPCOM-mangled.def new file mode 100644 index 00000000..d2f95449 --- /dev/null +++ b/src/libs/xpcom18a4/VBoxXPCOM-mangled.def @@ -0,0 +1,1688 @@ +; $Id: VBoxXPCOM-mangled.def $ +;; @file +; VirtualBox XPCOM - Import library definition file. + +; +; Copyright (C) 2018-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; SPDX-License-Identifier: GPL-3.0-only +; + +LIBRARY VBoxXPCOM.dll +EXPORTS + ; + ; To regenerate run the following command line: + ; nm -U ../../../out/darwin.amd64/debug/dist/VirtualBox.app/Contents/MacOS/VBoxXPCOM.dylib | kmk_sed -r -e 's/^[0-9a-fA-F]+ //' -e '/^[A-Z]/!d' | sort | kmk_sed -r -e 's/[SDBC] (.+)$/ \1 DATA/' -e 's/^[A-Z] / /' -e 's/^ _/ /' >> VBoxXPCOM-mangled.def + ; + + _ZN12nsCharTraitsIcE12sEmptyBufferE DATA + _ZN12nsCharTraitsItE12sEmptyBufferE DATA + NSGetStaticModuleInfo DATA + VBoxNsxpgFastLoadService_ DATA + _ZN17nsObsoleteAString16sCanonicalVTableE DATA + _ZN18nsObsoleteACString16sCanonicalVTableE DATA + _ZTV11nsHashtable DATA + _ZTV11nsLocalFile DATA + _ZTV11nsStringKey DATA + _ZTV11nsVoidArray DATA + _ZTV12nsCStringKey DATA + _ZTV13nsStringArray DATA + _ZTV14nsCStringArray DATA + _ZTV14nsGetInterface DATA + _ZTV14nsISupportsKey DATA + _ZTV14nsXPTCStubBase DATA + _ZTV15nsAutoVoidArray DATA + _ZTV15nsQueryReferent DATA + _ZTV15nsSupportsArray DATA + _ZTV15nsWeakReference DATA + _ZTV16nsQueryElementAt DATA + _ZTV17nsArrayEnumerator DATA + _ZTV17nsGetServiceByCID DATA + _ZTV17nsObjectHashtable DATA + _ZTV17nsUnionEnumerator DATA + _ZTV18nsGetWeakReference DATA + _ZTV19nsDirEnumeratorUnix DATA + _ZTV19nsSupportsHashtable DATA + _ZTV21nsCreateInstanceByCID DATA + _ZTV21nsQueryArrayElementAt DATA + _ZTV21nsSingletonEnumerator DATA + _ZTV23nsSupportsWeakReference DATA + _ZTV24nsGetServiceByContractID DATA + _ZTV25nsDefaultStringComparator DATA + _ZTV26nsDefaultCStringComparator DATA + _ZTV28nsCreateInstanceByContractID DATA + _ZTV28nsCreateInstanceFromCategory DATA + _ZTV34nsCaseInsensitiveCStringComparator DATA + _ZTV7nsIDKey DATA + _ZTV9nsHashKey DATA + _ZTV9nsVariant DATA + VBoxNsllLL_MaxInt + VBoxNsllLL_MaxUint + VBoxNsllLL_MinInt + VBoxNsllLL_Zero + VBoxNsplPL_ArenaAllocate + VBoxNsplPL_ArenaFinish + VBoxNsplPL_ArenaGrow + VBoxNsplPL_ArenaRelease + VBoxNsplPL_CompactArenaPool + VBoxNsplPL_CompareStrings + VBoxNsplPL_CompareValues + VBoxNsplPL_CreateEventQueue + VBoxNsplPL_CreateMonitoredEventQueue + VBoxNsplPL_CreateNativeEventQueue + VBoxNsplPL_DHashAllocTable + VBoxNsplPL_DHashClearEntryStub + VBoxNsplPL_DHashFinalizeStub + VBoxNsplPL_DHashFreeStringKey + VBoxNsplPL_DHashFreeTable + VBoxNsplPL_DHashGetKeyStub + VBoxNsplPL_DHashGetStubOps + VBoxNsplPL_DHashMatchEntryStub + VBoxNsplPL_DHashMatchStringKey + VBoxNsplPL_DHashMoveEntryStub + VBoxNsplPL_DHashStringKey + VBoxNsplPL_DHashTableDestroy + VBoxNsplPL_DHashTableEnumerate + VBoxNsplPL_DHashTableFinish + VBoxNsplPL_DHashTableInit + VBoxNsplPL_DHashTableOperate + VBoxNsplPL_DHashTableRawRemove + VBoxNsplPL_DHashTableSetAlphaBounds + VBoxNsplPL_DHashVoidPtrKeyStub + VBoxNsplPL_DequeueEvent + VBoxNsplPL_DestroyEvent + VBoxNsplPL_DestroyEventQueue + VBoxNsplPL_EventAvailable + VBoxNsplPL_EventLoop + VBoxNsplPL_FavorPerformanceHint + VBoxNsplPL_FinishArenaPool + VBoxNsplPL_FreeArenaPool + VBoxNsplPL_GetEvent + VBoxNsplPL_GetEventOwner + VBoxNsplPL_GetEventQueueMonitor + VBoxNsplPL_GetEventQueueSelectFD + VBoxNsplPL_HandleEvent + VBoxNsplPL_HashString + VBoxNsplPL_HashTableAdd + VBoxNsplPL_HashTableDestroy + VBoxNsplPL_HashTableDump + VBoxNsplPL_HashTableEnumerateEntries + VBoxNsplPL_HashTableLookup + VBoxNsplPL_HashTableLookupConst + VBoxNsplPL_HashTableRawAdd + VBoxNsplPL_HashTableRawLookup + VBoxNsplPL_HashTableRawLookupConst + VBoxNsplPL_HashTableRawRemove + VBoxNsplPL_HashTableRemove + VBoxNsplPL_InitArenaPool + VBoxNsplPL_InitEvent + VBoxNsplPL_IsQueueNative + VBoxNsplPL_IsQueueOnCurrentThread + VBoxNsplPL_MapEvents + VBoxNsplPL_NewDHashTable + VBoxNsplPL_NewHashTable + VBoxNsplPL_PostEvent + VBoxNsplPL_PostSynchronousEvent + VBoxNsplPL_ProcessPendingEvents + VBoxNsplPL_RevokeEvents + VBoxNsplPL_WaitForEvent + VBoxNsplPL_strcasecmp + VBoxNsplPL_strchr + VBoxNsplPL_strcmp + VBoxNsplPL_strcpy + VBoxNsplPL_strdup + VBoxNsplPL_strfree + VBoxNsplPL_strlen + VBoxNsplPL_strncasecmp + VBoxNsplPL_strnchr + VBoxNsplPL_strncmp + VBoxNsplPL_strncpy + VBoxNsplPL_strncpyz + VBoxNsplPL_strndup + VBoxNsplPL_strnlen + VBoxNsplPL_strnrchr + VBoxNsplPL_strnrstr + VBoxNsplPL_strnstr + VBoxNsplPL_strrchr + VBoxNsplPL_strrstr + VBoxNsplPL_strstr + VBoxNsprGetExecutionEnvironment + VBoxNsprPRP_DestroyNakedCondVar + VBoxNsprPRP_NakedBroadcast + VBoxNsprPRP_NakedNotify + VBoxNsprPRP_NakedWait + VBoxNsprPRP_NewNakedCondVar + VBoxNsprPRP_TryLock + VBoxNsprPR_Abort + VBoxNsprPR_Accept + VBoxNsprPR_AcceptRead + VBoxNsprPR_Access + VBoxNsprPR_AddWaitFileDesc + VBoxNsprPR_AllocFileDesc + VBoxNsprPR_Assert + VBoxNsprPR_AtomicAdd + VBoxNsprPR_AtomicDecrement + VBoxNsprPR_AtomicIncrement + VBoxNsprPR_AtomicSet + VBoxNsprPR_AttachThread + VBoxNsprPR_Available + VBoxNsprPR_Available64 + VBoxNsprPR_Bind + VBoxNsprPR_BlockClockInterrupts + VBoxNsprPR_BlockInterrupt + VBoxNsprPR_CEnterMonitor + VBoxNsprPR_CExitMonitor + VBoxNsprPR_CNotify + VBoxNsprPR_CNotifyAll + VBoxNsprPR_CSetOnMonitorRecycle + VBoxNsprPR_CWait + VBoxNsprPR_CallOnce + VBoxNsprPR_CallOnceWithArg + VBoxNsprPR_Calloc + VBoxNsprPR_CancelWaitFileDesc + VBoxNsprPR_CancelWaitGroup + VBoxNsprPR_CeilingLog2 + VBoxNsprPR_ChangeFileDescNativeHandle + VBoxNsprPR_Cleanup + VBoxNsprPR_ClearInterrupt + VBoxNsprPR_ClearThreadGCAble + VBoxNsprPR_Close + VBoxNsprPR_CloseDir + VBoxNsprPR_CloseFileMap + VBoxNsprPR_CloseSemaphore + VBoxNsprPR_Connect + VBoxNsprPR_ConnectContinue + VBoxNsprPR_ConvertIPv4AddrToIPv6 + VBoxNsprPR_CreateFileMap + VBoxNsprPR_CreateIOLayer + VBoxNsprPR_CreateIOLayerStub + VBoxNsprPR_CreateMWaitEnumerator + VBoxNsprPR_CreatePipe + VBoxNsprPR_CreateProcess + VBoxNsprPR_CreateProcessDetached + VBoxNsprPR_CreateSocketPollFd + VBoxNsprPR_CreateStack + VBoxNsprPR_CreateThread + VBoxNsprPR_CreateThreadGCAble + VBoxNsprPR_CreateWaitGroup + VBoxNsprPR_Delete + VBoxNsprPR_DeleteSemaphore + VBoxNsprPR_DestroyCondVar + VBoxNsprPR_DestroyLock + VBoxNsprPR_DestroyMWaitEnumerator + VBoxNsprPR_DestroyMonitor + VBoxNsprPR_DestroyPollableEvent + VBoxNsprPR_DestroyProcessAttr + VBoxNsprPR_DestroyRWLock + VBoxNsprPR_DestroySem + VBoxNsprPR_DestroySocketPollFd + VBoxNsprPR_DestroyStack + VBoxNsprPR_DestroyWaitGroup + VBoxNsprPR_DetachProcess + VBoxNsprPR_DetachThread + VBoxNsprPR_DisableClockInterrupts + VBoxNsprPR_EmulateAcceptRead + VBoxNsprPR_EmulateSendFile + VBoxNsprPR_EnableClockInterrupts + VBoxNsprPR_EnterMonitor + VBoxNsprPR_EnumerateAddrInfo + VBoxNsprPR_EnumerateHostEnt + VBoxNsprPR_EnumerateThreads + VBoxNsprPR_EnumerateWaitGroup + VBoxNsprPR_ErrorInstallCallback + VBoxNsprPR_ErrorInstallTable + VBoxNsprPR_ErrorLanguages + VBoxNsprPR_ErrorToName + VBoxNsprPR_ErrorToString + VBoxNsprPR_ExitMonitor + VBoxNsprPR_ExplodeTime + VBoxNsprPR_FD_CLR + VBoxNsprPR_FD_ISSET + VBoxNsprPR_FD_NCLR + VBoxNsprPR_FD_NISSET + VBoxNsprPR_FD_NSET + VBoxNsprPR_FD_SET + VBoxNsprPR_FD_ZERO + VBoxNsprPR_FPrintZoneStats + VBoxNsprPR_FileDesc2NativeHandle + VBoxNsprPR_FindFunctionSymbol + VBoxNsprPR_FindFunctionSymbolAndLibrary + VBoxNsprPR_FindLibrary + VBoxNsprPR_FindSymbol + VBoxNsprPR_FindSymbolAndLibrary + VBoxNsprPR_FloorLog2 + VBoxNsprPR_FormatTime + VBoxNsprPR_FormatTimeUSEnglish + VBoxNsprPR_Free + VBoxNsprPR_FreeAddrInfo + VBoxNsprPR_FreeLibraryName + VBoxNsprPR_GMTParameters + VBoxNsprPR_GetAddrInfoByName + VBoxNsprPR_GetCanonNameFromAddrInfo + VBoxNsprPR_GetConnectStatus + VBoxNsprPR_GetCurrentThread + VBoxNsprPR_GetDefaultIOMethods + VBoxNsprPR_GetDescType + VBoxNsprPR_GetEnv + VBoxNsprPR_GetError + VBoxNsprPR_GetErrorText + VBoxNsprPR_GetErrorTextLength + VBoxNsprPR_GetFileInfo + VBoxNsprPR_GetFileInfo64 + VBoxNsprPR_GetFileMethods + VBoxNsprPR_GetHostByAddr + VBoxNsprPR_GetHostByName + VBoxNsprPR_GetIPNodeByName + VBoxNsprPR_GetIdentitiesLayer + VBoxNsprPR_GetInheritedFD + VBoxNsprPR_GetLayersIdentity + VBoxNsprPR_GetLibraryFilePathname + VBoxNsprPR_GetLibraryName + VBoxNsprPR_GetLibraryPath + VBoxNsprPR_GetMemMapAlignment + VBoxNsprPR_GetMonitorEntryCount + VBoxNsprPR_GetNameForIdentity + VBoxNsprPR_GetOSError + VBoxNsprPR_GetOpenFileInfo + VBoxNsprPR_GetOpenFileInfo64 + VBoxNsprPR_GetPageShift + VBoxNsprPR_GetPageSize + VBoxNsprPR_GetPeerName + VBoxNsprPR_GetPipeMethods + VBoxNsprPR_GetProtoByName + VBoxNsprPR_GetProtoByNumber + VBoxNsprPR_GetSP + VBoxNsprPR_GetSockName + VBoxNsprPR_GetSocketOption + VBoxNsprPR_GetSpecialFD + VBoxNsprPR_GetTCPMethods + VBoxNsprPR_GetThreadAffinityMask + VBoxNsprPR_GetThreadID + VBoxNsprPR_GetThreadPriority + VBoxNsprPR_GetThreadPrivate + VBoxNsprPR_GetThreadScope + VBoxNsprPR_GetThreadState + VBoxNsprPR_GetThreadType + VBoxNsprPR_GetUDPMethods + VBoxNsprPR_GetUniqueIdentity + VBoxNsprPR_ImplodeTime + VBoxNsprPR_ImportFile + VBoxNsprPR_ImportPipe + VBoxNsprPR_ImportTCPSocket + VBoxNsprPR_ImportUDPSocket + VBoxNsprPR_Init + VBoxNsprPR_Initialize + VBoxNsprPR_InitializeNetAddr + VBoxNsprPR_Initialized + VBoxNsprPR_Interrupt + VBoxNsprPR_IntervalNow + VBoxNsprPR_IntervalToMicroseconds + VBoxNsprPR_IntervalToMilliseconds + VBoxNsprPR_IntervalToSeconds + VBoxNsprPR_IsNetAddrType + VBoxNsprPR_JoinThread + VBoxNsprPR_KillProcess + VBoxNsprPR_Listen + VBoxNsprPR_LoadLibrary + VBoxNsprPR_LoadLibraryWithFlags + VBoxNsprPR_LoadStaticLibrary + VBoxNsprPR_LocalTimeParameters + VBoxNsprPR_Lock + VBoxNsprPR_LockFile + VBoxNsprPR_LogFlush + VBoxNsprPR_LogPrint + VBoxNsprPR_MakeDir + VBoxNsprPR_Malloc + VBoxNsprPR_MemMap + VBoxNsprPR_MemUnmap + VBoxNsprPR_MicrosecondsToInterval + VBoxNsprPR_MillisecondsToInterval + VBoxNsprPR_MkDir + VBoxNsprPR_NetAddrToString + VBoxNsprPR_NewCondVar + VBoxNsprPR_NewLock + VBoxNsprPR_NewLogModule + VBoxNsprPR_NewMonitor + VBoxNsprPR_NewNamedMonitor + VBoxNsprPR_NewPollableEvent + VBoxNsprPR_NewProcessAttr + VBoxNsprPR_NewRWLock + VBoxNsprPR_NewSem + VBoxNsprPR_NewTCPSocket + VBoxNsprPR_NewTCPSocketPair + VBoxNsprPR_NewThreadPrivateIndex + VBoxNsprPR_NewUDPSocket + VBoxNsprPR_NormalizeTime + VBoxNsprPR_Notify + VBoxNsprPR_NotifyAll + VBoxNsprPR_NotifyAllCondVar + VBoxNsprPR_NotifyCondVar + VBoxNsprPR_Now + VBoxNsprPR_Open + VBoxNsprPR_OpenDir + VBoxNsprPR_OpenFile + VBoxNsprPR_OpenSemaphore + VBoxNsprPR_OpenTCPSocket + VBoxNsprPR_OpenUDPSocket + VBoxNsprPR_ParseTimeString + VBoxNsprPR_Poll + VBoxNsprPR_PopIOLayer + VBoxNsprPR_PostSem + VBoxNsprPR_PostSemaphore + VBoxNsprPR_ProcessAttrSetCurrentDirectory + VBoxNsprPR_ProcessAttrSetInheritableFD + VBoxNsprPR_ProcessAttrSetStdioRedirect + VBoxNsprPR_ProcessExit + VBoxNsprPR_PushIOLayer + VBoxNsprPR_RWLock_Rlock + VBoxNsprPR_RWLock_Unlock + VBoxNsprPR_RWLock_Wlock + VBoxNsprPR_Read + VBoxNsprPR_ReadDir + VBoxNsprPR_Realloc + VBoxNsprPR_Recv + VBoxNsprPR_RecvFrom + VBoxNsprPR_Rename + VBoxNsprPR_ResetProcessAttr + VBoxNsprPR_ResumeAll + VBoxNsprPR_RmDir + VBoxNsprPR_SecondsToInterval + VBoxNsprPR_Seek + VBoxNsprPR_Seek64 + VBoxNsprPR_Select + VBoxNsprPR_Send + VBoxNsprPR_SendFile + VBoxNsprPR_SendTo + VBoxNsprPR_SetConcurrency + VBoxNsprPR_SetEnv + VBoxNsprPR_SetError + VBoxNsprPR_SetErrorText + VBoxNsprPR_SetFDCacheSize + VBoxNsprPR_SetFDInheritable + VBoxNsprPR_SetLibraryPath + VBoxNsprPR_SetLogBuffering + VBoxNsprPR_SetLogFile + VBoxNsprPR_SetNetAddr + VBoxNsprPR_SetPollableEvent + VBoxNsprPR_SetSocketOption + VBoxNsprPR_SetStdioRedirect + VBoxNsprPR_SetThreadAffinityMask + VBoxNsprPR_SetThreadDumpProc + VBoxNsprPR_SetThreadGCAble + VBoxNsprPR_SetThreadPriority + VBoxNsprPR_SetThreadPrivate + VBoxNsprPR_SetThreadRecycleMode + VBoxNsprPR_Shutdown + VBoxNsprPR_Sleep + VBoxNsprPR_Socket + VBoxNsprPR_StackPop + VBoxNsprPR_StackPush + VBoxNsprPR_Stat + VBoxNsprPR_StringToNetAddr + VBoxNsprPR_SuspendAll + VBoxNsprPR_Sync + VBoxNsprPR_TLockFile + VBoxNsprPR_TicksPerSecond + VBoxNsprPR_TransmitFile + VBoxNsprPR_USPacificTimeParameters + VBoxNsprPR_UnblockClockInterrupts + VBoxNsprPR_UnblockInterrupt + VBoxNsprPR_UnloadLibrary + VBoxNsprPR_Unlock + VBoxNsprPR_UnlockFile + VBoxNsprPR_VersionCheck + VBoxNsprPR_Wait + VBoxNsprPR_WaitCondVar + VBoxNsprPR_WaitForPollableEvent + VBoxNsprPR_WaitProcess + VBoxNsprPR_WaitRecvReady + VBoxNsprPR_WaitSem + VBoxNsprPR_WaitSemaphore + VBoxNsprPR_Write + VBoxNsprPR_Writev + VBoxNsprPR_Yield + VBoxNsprPR_cnvtf + VBoxNsprPR_dtoa + VBoxNsprPR_fprintf + VBoxNsprPR_htonl + VBoxNsprPR_htonll + VBoxNsprPR_htons + VBoxNsprPR_ntohl + VBoxNsprPR_ntohll + VBoxNsprPR_ntohs + VBoxNsprPR_smprintf + VBoxNsprPR_smprintf_free + VBoxNsprPR_snprintf + VBoxNsprPR_sprintf_append + VBoxNsprPR_sscanf + VBoxNsprPR_strtod + VBoxNsprPR_sxprintf + VBoxNsprPR_vfprintf + VBoxNsprPR_vsmprintf + VBoxNsprPR_vsnprintf + VBoxNsprPR_vsprintf_append + VBoxNsprPR_vsxprintf + VBoxNsprPT_FPrintStats + VBoxNsprSetExecutionEnvironment + VBoxNsxpNS_CStringCloneData + VBoxNsxpNS_CStringContainerFinish + VBoxNsxpNS_CStringContainerInit + VBoxNsxpNS_CStringCopy + VBoxNsxpNS_CStringGetData + VBoxNsxpNS_CStringSetData + VBoxNsxpNS_CStringSetDataRange + VBoxNsxpNS_CStringToUTF16 + VBoxNsxpNS_GetComponentManager + VBoxNsxpNS_GetComponentRegistrar + VBoxNsxpNS_GetDebug + VBoxNsxpNS_GetFrozenFunctions + VBoxNsxpNS_GetMemoryManager + VBoxNsxpNS_GetServiceManager + VBoxNsxpNS_GetTraceRefcnt + VBoxNsxpNS_InitXPCOM2 + VBoxNsxpNS_MeanAndStdDev + VBoxNsxpNS_NewByteInputStream + VBoxNsxpNS_NewCStringInputStream + VBoxNsxpNS_NewCharInputStream + VBoxNsxpNS_NewEmptyEnumerator + VBoxNsxpNS_NewLocalFile + VBoxNsxpNS_NewNativeLocalFile + VBoxNsxpNS_NewSingletonEnumerator + VBoxNsxpNS_NewStringInputStream + VBoxNsxpNS_NewUnionEnumerator + VBoxNsxpNS_QuickSort + VBoxNsxpNS_RegisterXPCOMExitRoutine + VBoxNsxpNS_ShutdownXPCOM + VBoxNsxpNS_StringCloneData + VBoxNsxpNS_StringContainerFinish + VBoxNsxpNS_StringContainerInit + VBoxNsxpNS_StringCopy + VBoxNsxpNS_StringGetData + VBoxNsxpNS_StringSetData + VBoxNsxpNS_StringSetDataRange + VBoxNsxpNS_UTF16ToCString + VBoxNsxpNS_UnregisterXPCOMExitRoutine + VBoxNsxpXPTC_InvokeByIndex + VBoxNsxpXPTI_FreeInterfaceInfoManager + VBoxNsxpXPTI_GetInterfaceInfoManager + VBoxNsxpXPT_ArenaFree + VBoxNsxpXPT_ArenaMalloc + VBoxNsxpXPT_ArenaStrDup + VBoxNsxpXPT_AssertFailed + VBoxNsxpXPT_DataOffset + VBoxNsxpXPT_DestroyArena + VBoxNsxpXPT_DestroyInterfaceDirectoryEntry + VBoxNsxpXPT_DestroyXDRState + VBoxNsxpXPT_Do16 + VBoxNsxpXPT_Do32 + VBoxNsxpXPT_Do64 + VBoxNsxpXPT_Do8 + VBoxNsxpXPT_DoCString + VBoxNsxpXPT_DoHeader + VBoxNsxpXPT_DoHeaderPrologue + VBoxNsxpXPT_DoIID + VBoxNsxpXPT_DoString + VBoxNsxpXPT_DoStringInline + VBoxNsxpXPT_DumpStats + VBoxNsxpXPT_FillInterfaceDirectoryEntry + VBoxNsxpXPT_FillMethodDescriptor + VBoxNsxpXPT_FillParamDescriptor + VBoxNsxpXPT_FreeHeader + VBoxNsxpXPT_FreeInterfaceDescriptor + VBoxNsxpXPT_GetAddrForOffset + VBoxNsxpXPT_GetInterfaceIndexByName + VBoxNsxpXPT_GetOffsetForAddr + VBoxNsxpXPT_GetXDRData + VBoxNsxpXPT_GetXDRDataLength + VBoxNsxpXPT_InterfaceDescriptorAddConsts + VBoxNsxpXPT_InterfaceDescriptorAddMethods + VBoxNsxpXPT_InterfaceDescriptorAddTypes + VBoxNsxpXPT_MakeCursor + VBoxNsxpXPT_NewAnnotation + VBoxNsxpXPT_NewArena + VBoxNsxpXPT_NewHeader + VBoxNsxpXPT_NewInterfaceDescriptor + VBoxNsxpXPT_NewString + VBoxNsxpXPT_NewStringZ + VBoxNsxpXPT_NewXDRState + VBoxNsxpXPT_NotifyDoneLoading + VBoxNsxpXPT_ParseVersionString + VBoxNsxpXPT_SeekTo + VBoxNsxpXPT_SetAddrForOffset + VBoxNsxpXPT_SetDataOffset + VBoxNsxpXPT_SetOffsetForAddr + VBoxNsxpXPT_SizeOfHeader + VBoxNsxpXPT_SizeOfHeaderBlock + _MD_LockFile + _MD_TLockFile + _MD_UnlockFile + _MD_gethostname + _MD_getsysinfo + _MD_unix_map_accept_error + _MD_unix_map_access_error + _MD_unix_map_bind_error + _MD_unix_map_close_error + _MD_unix_map_closedir_error + _MD_unix_map_connect_error + _MD_unix_map_default_error + _MD_unix_map_flock_error + _MD_unix_map_fstat_error + _MD_unix_map_fsync_error + _MD_unix_map_gethostname_error + _MD_unix_map_getpeername_error + _MD_unix_map_getsockname_error + _MD_unix_map_getsockopt_error + _MD_unix_map_listen_error + _MD_unix_map_lockf_error + _MD_unix_map_lseek_error + _MD_unix_map_mkdir_error + _MD_unix_map_mmap_error + _MD_unix_map_open_error + _MD_unix_map_opendir_error + _MD_unix_map_poll_error + _MD_unix_map_poll_revents_error + _MD_unix_map_read_error + _MD_unix_map_recv_error + _MD_unix_map_recvfrom_error + _MD_unix_map_rename_error + _MD_unix_map_rmdir_error + _MD_unix_map_select_error + _MD_unix_map_send_error + _MD_unix_map_sendto_error + _MD_unix_map_setsockopt_error + _MD_unix_map_shutdown_error + _MD_unix_map_socket_error + _MD_unix_map_socketavailable_error + _MD_unix_map_socketpair_error + _MD_unix_map_stat_error + _MD_unix_map_unlink_error + _MD_unix_map_write_error + _MD_unix_map_writev_error + _MD_unix_readdir_error + _Z10HashStringRK10nsACString + _Z10HashStringRK9nsAString + _Z10NS_NewAtomPKc + _Z10NS_NewAtomPKt + _Z10NS_NewAtomRK10nsACString + _Z10NS_NewAtomRK9nsAString + _Z11EmptyStringv + _Z11NS_NewArrayPP15nsIMutableArray + _Z11NS_NewArrayPP15nsIMutableArrayRK15nsCOMArray_base + _Z11NS_NewPipe2PP19nsIAsyncInputStreamPP20nsIAsyncOutputStreamiijjP9nsIMemory + _Z11ToLowerCaseR10nsACString + _Z11ToLowerCaseR12nsCSubstring + _Z11ToLowerCaseRK10nsACStringRS_ + _Z11ToUpperCaseR10nsACString + _Z11ToUpperCaseR12nsCSubstring + _Z11ToUpperCaseRK10nsACStringRS_ + _Z12EmptyCStringv + _Z12NS_AsyncCopyP14nsIInputStreamP15nsIOutputStreamP14nsIEventTarget15nsAsyncCopyModejPFvPvjES6_ + _Z12NS_InitXPCOMPP17nsIServiceManagerP7nsIFile + _Z12NS_NewThreadPP9nsIThreadP11nsIRunnablej13PRThreadState16PRThreadPriority13PRThreadScope + _Z12NS_NewThreadPP9nsIThreadj13PRThreadState16PRThreadPriority13PRThreadScope + _Z12ToNewCStringRK10nsACString + _Z12ToNewCStringRK9nsAString + _Z12ToNewUnicodeRK10nsACString + _Z12ToNewUnicodeRK9nsAString + _Z13CopyUnicodeToRK17nsReadingIteratorItES2_R9nsAString + _Z13CopyUnicodeToRK9nsAStringjPtj + _Z14FindInReadableRK10nsACStringR17nsReadingIteratorIcES4_RK19nsCStringComparator + _Z14FindInReadableRK9nsAStringR17nsReadingIteratorItES4_RK18nsStringComparator + _Z14StringEndsWithRK10nsACStringS1_RK19nsCStringComparator + _Z14StringEndsWithRK9nsAStringS1_RK18nsStringComparator + _Z15AppendUnicodeToRK17nsReadingIteratorItES2_R9nsAString + _Z15CopyUTF16toUTF8PKtR10nsACString + _Z15CopyUTF16toUTF8RK9nsAStringR10nsACString + _Z15CopyUTF8toUTF16PKcR9nsAString + _Z15CopyUTF8toUTF16RK10nsACStringR9nsAString + _Z15NS_ProxyReleaseP14nsIEventTargetP11nsISupportsi + _Z15RFindInReadableRK10nsACStringR17nsReadingIteratorIcES4_RK19nsCStringComparator + _Z15RFindInReadableRK9nsAStringR17nsReadingIteratorItES4_RK18nsStringComparator + _Z15ToNewUTF8StringRK9nsAStringPj + _Z16CopyASCIItoUTF16PKcR9nsAString + _Z16CopyASCIItoUTF16RK10nsACStringR9nsAString + _Z16NS_NewByteBufferPP13nsIByteBufferP11nsISupportsj + _Z16StringBeginsWithRK10nsACStringS1_RK19nsCStringComparator + _Z16StringBeginsWithRK9nsAStringS1_RK18nsStringComparator + _Z16UTF8ToNewUnicodeRK10nsACStringPj + _Z17AppendUTF16toUTF8PKtR10nsACString + _Z17AppendUTF16toUTF8RK9nsAStringR10nsACString + _Z17AppendUTF8toUTF16PKcR9nsAString + _Z17AppendUTF8toUTF16RK10nsACStringR9nsAString + _Z18AppendASCIItoUTF16PKcR9nsAString + _Z18AppendASCIItoUTF16RK10nsACStringR9nsAString + _Z18FindCharInReadablecR17nsReadingIteratorIcERKS0_ + _Z18FindCharInReadabletR17nsReadingIteratorItERKS0_ + _Z19CountCharInReadableRK10nsACStringc + _Z19CountCharInReadableRK9nsAStringt + _Z19NS_GetNumberOfAtomsv + _Z19NS_GetWeakReferenceP11nsISupportsPj + _Z19NS_NewGenericModulePKcjP21nsModuleComponentInfoPFvP9nsIModuleEPS4_ + _Z19NS_NewPermanentAtomPKc + _Z19NS_NewPermanentAtomPKt + _Z19NS_NewPermanentAtomRK10nsACString + _Z19NS_NewPermanentAtomRK9nsAString + _Z19NS_NewStorageStreamjjPP16nsIStorageStream + _Z19NS_NewUnicharBufferPP16nsIUnicharBufferP11nsISupportsj + _Z19TestSegmentedBufferv + _Z20NS_GetProxyForObjectP13nsIEventQueueRK4nsIDP11nsISupportsiPPv + _Z20NS_NewGenericFactoryPP17nsIGenericFactoryPK21nsModuleComponentInfo + _Z20NS_NewGenericModule2P12nsModuleInfoPP9nsIModule + _Z20NS_NewISupportsArrayPP16nsISupportsArray + _Z21LossyCopyUTF16toASCIIPKtR10nsACString + _Z21LossyCopyUTF16toASCIIRK9nsAStringR10nsACString + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorP16nsISupportsArray + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorP8nsIArray + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorRK15nsCOMArray_base + _Z22NS_CopyNativeToUnicodeRK10nsACStringR9nsAString + _Z22NS_CopyUnicodeToNativeRK9nsAStringR10nsACString + _Z22NS_RegisterStaticAtomsPK12nsStaticAtomj + _Z22PL_DHashStubEnumRemoveP12PLDHashTableP15PLDHashEntryHdrjPv + _Z23LossyAppendUTF16toASCIIPKtR10nsACString + _Z23LossyAppendUTF16toASCIIRK9nsAStringR10nsACString + _Z23NS_AddFastLoadChecksumsjjj + _Z23NS_ErrorAccordingToNSPRv + _Z24NS_NewFastLoadFileReaderPP20nsIObjectInputStreamP14nsIInputStream + _Z24NS_NewFastLoadFileWriterPP21nsIObjectOutputStreamP15nsIOutputStreamP17nsIFastLoadFileIO + _Z25NS_NewFastLoadFileUpdaterPP21nsIObjectOutputStreamP15nsIOutputStreamP20nsIObjectInputStream + _Z25NS_NewUTF8ConverterStreamPP21nsIUnicharInputStreamP14nsIInputStreami + _Z27NS_NewInputStreamReadyEventPP22nsIInputStreamCallbackS0_P14nsIEventTarget + _Z28NS_GetGlobalComponentManagerPP19nsIComponentManager + _Z28NS_NewOutputStreamReadyEventPP23nsIOutputStreamCallbackS0_P14nsIEventTarget + _Z29CaseInsensitiveFindInReadableRK10nsACStringR17nsReadingIteratorIcES4_ + _Z29NS_AccumulateFastLoadChecksumPjPKhji + _Z29NS_CreateServicesFromCategoryPKcP11nsISupportsS0_ + _Z29StartupSpecialSystemDirectoryv + _Z30NS_NewISupportsArrayEnumeratorP16nsISupportsArrayPP26nsIBidirectionalEnumerator + _Z30NS_NewStringUnicharInputStreamPP21nsIUnicharInputStreamP8nsString + _Z30ShutdownSpecialSystemDirectoryv + _Z6IsUTF8RK10nsACString + _Z7CompareRK10nsACStringS1_RK19nsCStringComparator + _Z7CompareRK9nsAStringS1_RK18nsStringComparator + _Z7IsASCIIRK10nsACString + _Z7IsASCIIRK9nsAString + _ZN10nsACString11AppendASCIIEPKc + _ZN10nsACString11AppendASCIIEPKcj + _ZN10nsACString11AssignASCIIEPKc + _ZN10nsACString11AssignASCIIEPKcj + _ZN10nsACString11SetCapacityEj + _ZN10nsACString17GetWritableBufferEPPc + _ZN10nsACString3CutEjj + _ZN10nsACString6AppendEPKc + _ZN10nsACString6AppendEPKcj + _ZN10nsACString6AppendERK17nsCSubstringTuple + _ZN10nsACString6AppendERKS_ + _ZN10nsACString6AppendEc + _ZN10nsACString6AssignEPKc + _ZN10nsACString6AssignEPKcj + _ZN10nsACString6AssignERK17nsCSubstringTuple + _ZN10nsACString6AssignERKS_ + _ZN10nsACString6AssignEc + _ZN10nsACString6InsertEPKcj + _ZN10nsACString6InsertEPKcjj + _ZN10nsACString6InsertERK17nsCSubstringTuplej + _ZN10nsACString6InsertERKS_j + _ZN10nsACString6InsertEcj + _ZN10nsACString7ReplaceEjjRK17nsCSubstringTuple + _ZN10nsACString7ReplaceEjjRKS_ + _ZN10nsACString9SetIsVoidEi + _ZN10nsACString9SetLengthEj + _ZN10nsACStringD1Ev + _ZN10nsACStringD2Ev + _ZN11nsHashtable3GetEP9nsHashKey + _ZN11nsHashtable3PutEP9nsHashKeyPv + _ZN11nsHashtable5CloneEv + _ZN11nsHashtable5ResetEPFiP9nsHashKeyPvS2_ES2_ + _ZN11nsHashtable5ResetEv + _ZN11nsHashtable6ExistsEP9nsHashKey + _ZN11nsHashtable6RemoveEP9nsHashKey + _ZN11nsHashtable9EnumerateEPFiP9nsHashKeyPvS2_ES2_ + _ZN11nsHashtableC1EP20nsIObjectInputStreamPFjS1_PP9nsHashKeyPPvEPFvS1_S3_S5_EPj + _ZN11nsHashtableC1Eji + _ZN11nsHashtableC2EP20nsIObjectInputStreamPFjS1_PP9nsHashKeyPPvEPFvS1_S3_S5_EPj + _ZN11nsHashtableC2Eji + _ZN11nsHashtableD0Ev + _ZN11nsHashtableD1Ev + _ZN11nsHashtableD2Ev + _ZN11nsIDHashKey7HashKeyEPK4nsID + _ZN11nsLocalFile10GlobalInitEv + _ZN11nsLocalFile13FillStatCacheEv + _ZN11nsLocalFile14GlobalShutdownEv + _ZN11nsLocalFile15CopyDirectoryToEP7nsIFile + _ZN11nsLocalFile17CreateAndKeepOpenEjijPP10PRFileDesc + _ZN11nsLocalFile18CreateAllAncestorsEj + _ZN11nsLocalFile20LocateNativeLeafNameER17nsReadingIteratorIcES2_ + _ZN11nsLocalFile22nsLocalFileConstructorEP11nsISupportsRK4nsIDPPv + _ZN11nsLocalFile23GetNativeTargetPathNameEP7nsIFileRK10nsACStringRS2_ + _ZN11nsLocalFileC1ERKS_ + _ZN11nsLocalFileC1Ev + _ZN11nsLocalFileC2ERKS_ + _ZN11nsLocalFileC2Ev + _ZN11nsStringKeyC1EP20nsIObjectInputStreamPj + _ZN11nsStringKeyC1EPKtiNS_9OwnershipE + _ZN11nsStringKeyC1ERK8nsString + _ZN11nsStringKeyC1ERK9nsAString + _ZN11nsStringKeyC1ERKS_ + _ZN11nsStringKeyC2EP20nsIObjectInputStreamPj + _ZN11nsStringKeyC2EPKtiNS_9OwnershipE + _ZN11nsStringKeyC2ERK8nsString + _ZN11nsStringKeyC2ERK9nsAString + _ZN11nsStringKeyC2ERKS_ + _ZN11nsStringKeyD0Ev + _ZN11nsStringKeyD1Ev + _ZN11nsStringKeyD2Ev + _ZN11nsSubstring11AssignASCIIEPKc + _ZN11nsSubstring11AssignASCIIEPKcj + _ZN11nsSubstring11SetCapacityEj + _ZN11nsSubstring12ReplaceASCIIEjjPKcj + _ZN11nsSubstring13EnsureMutableEv + _ZN11nsSubstring5AdoptEPtj + _ZN11nsSubstring6AssignEPKtj + _ZN11nsSubstring6AssignERK16nsSubstringTuple + _ZN11nsSubstring6AssignERK9nsAString + _ZN11nsSubstring6AssignERKS_ + _ZN11nsSubstring7ReplaceEjjPKtj + _ZN11nsSubstring7ReplaceEjjRK16nsSubstringTuple + _ZN11nsSubstring7ReplaceEjjRK9nsAString + _ZN11nsSubstring9SetIsVoidEi + _ZN11nsSubstring9SetLengthEj + _ZN11nsVoidArray11GrowArrayByEi + _ZN11nsVoidArray11MoveElementEii + _ZN11nsVoidArray13RemoveElementEPv + _ZN11nsVoidArray15InsertElementAtEPvi + _ZN11nsVoidArray16InsertElementsAtERKS_i + _ZN11nsVoidArray16RemoveElementsAtEii + _ZN11nsVoidArray16ReplaceElementAtEPvi + _ZN11nsVoidArray17EnumerateForwardsEPFiPvS0_ES0_ + _ZN11nsVoidArray18EnumerateBackwardsEPFiPvS0_ES0_ + _ZN11nsVoidArray4SortEPFiPKvS1_PvES2_ + _ZN11nsVoidArray5ClearEv + _ZN11nsVoidArray6SizeToEi + _ZN11nsVoidArray7CompactEv + _ZN11nsVoidArrayC1Ei + _ZN11nsVoidArrayC1Ev + _ZN11nsVoidArrayC2Ei + _ZN11nsVoidArrayC2Ev + _ZN11nsVoidArrayD0Ev + _ZN11nsVoidArrayD1Ev + _ZN11nsVoidArrayD2Ev + _ZN11nsVoidArrayaSERKS_ + _ZN12nsCStringKeyC1EP20nsIObjectInputStreamPj + _ZN12nsCStringKeyC1EPKciNS_9OwnershipE + _ZN12nsCStringKeyC1ERK10nsACString + _ZN12nsCStringKeyC1ERK9nsCString + _ZN12nsCStringKeyC1ERKS_ + _ZN12nsCStringKeyC2EP20nsIObjectInputStreamPj + _ZN12nsCStringKeyC2EPKciNS_9OwnershipE + _ZN12nsCStringKeyC2ERK10nsACString + _ZN12nsCStringKeyC2ERK9nsCString + _ZN12nsCStringKeyC2ERKS_ + _ZN12nsCStringKeyD0Ev + _ZN12nsCStringKeyD1Ev + _ZN12nsCStringKeyD2Ev + _ZN12nsCSubstring11AssignASCIIEPKc + _ZN12nsCSubstring11AssignASCIIEPKcj + _ZN12nsCSubstring11SetCapacityEj + _ZN12nsCSubstring12ReplaceASCIIEjjPKcj + _ZN12nsCSubstring13EnsureMutableEv + _ZN12nsCSubstring5AdoptEPcj + _ZN12nsCSubstring6AssignEPKcj + _ZN12nsCSubstring6AssignERK10nsACString + _ZN12nsCSubstring6AssignERK17nsCSubstringTuple + _ZN12nsCSubstring6AssignERKS_ + _ZN12nsCSubstring7ReplaceEjjPKcj + _ZN12nsCSubstring7ReplaceEjjRK10nsACString + _ZN12nsCSubstring7ReplaceEjjRK17nsCSubstringTuple + _ZN12nsCSubstring9SetIsVoidEi + _ZN12nsCSubstring9SetLengthEj + _ZN13nsAutoMonitor10NewMonitorEPKc + _ZN13nsAutoMonitor14DestroyMonitorEP9PRMonitor + _ZN13nsAutoMonitor4ExitEv + _ZN13nsAutoMonitor5EnterEv + _ZN13nsCOMPtr_base14assign_from_qiE16nsQueryInterfaceRK4nsID + _ZN13nsCOMPtr_base16begin_assignmentEv + _ZN13nsCOMPtr_base18assign_from_helperERK15nsCOMPtr_helperRK4nsID + _ZN13nsCOMPtr_base18assign_with_AddRefEP11nsISupports + _ZN13nsCOMPtr_base25assign_from_qi_with_errorERK25nsQueryInterfaceWithErrorRK4nsID + _ZN13nsCOMPtr_baseD1Ev + _ZN13nsCOMPtr_baseD2Ev + _ZN13nsStringArray12RemoveStringERK9nsAString + _ZN13nsStringArray14InsertStringAtERK9nsAStringi + _ZN13nsStringArray14RemoveStringAtEi + _ZN13nsStringArray15ReplaceStringAtERK9nsAStringi + _ZN13nsStringArray17EnumerateForwardsEPFiR8nsStringPvES2_ + _ZN13nsStringArray18EnumerateBackwardsEPFiR8nsStringPvES2_ + _ZN13nsStringArray4SortEPFiPK8nsStringS2_PvES3_ + _ZN13nsStringArray4SortEv + _ZN13nsStringArray5ClearEv + _ZN13nsStringArrayC1Ei + _ZN13nsStringArrayC1Ev + _ZN13nsStringArrayC2Ei + _ZN13nsStringArrayC2Ev + _ZN13nsStringArrayD0Ev + _ZN13nsStringArrayD1Ev + _ZN13nsStringArrayD2Ev + _ZN13nsStringArrayaSERKS_ + _ZN13nsTraceRefcnt10LogReleaseEPvjPKc + _ZN13nsTraceRefcnt12LogAddCOMPtrEPvP11nsISupports + _ZN13nsTraceRefcnt16LogReleaseCOMPtrEPvP11nsISupports + _ZN13nsTraceRefcnt7LogCtorEPvPKcj + _ZN13nsTraceRefcnt7LogDtorEPvPKcj + _ZN13nsTraceRefcnt9LogAddRefEPvjPKcj + _ZN14nsAutoCMonitor4ExitEv + _ZN14nsAutoCMonitor5EnterEv + _ZN14nsAutoLockBase4HideEv + _ZN14nsAutoLockBase4ShowEv + _ZN14nsAutoLockBaseC1EPvNS_14nsAutoLockTypeE + _ZN14nsAutoLockBaseC2EPvNS_14nsAutoLockTypeE + _ZN14nsAutoLockBaseD1Ev + _ZN14nsAutoLockBaseD2Ev + _ZN14nsCStringArray11ParseStringEPKcS1_ + _ZN14nsCStringArray13RemoveCStringERK10nsACString + _ZN14nsCStringArray14SortIgnoreCaseEv + _ZN14nsCStringArray15InsertCStringAtERK10nsACStringi + _ZN14nsCStringArray15RemoveCStringAtEi + _ZN14nsCStringArray16ReplaceCStringAtERK10nsACStringi + _ZN14nsCStringArray17EnumerateForwardsEPFiR9nsCStringPvES2_ + _ZN14nsCStringArray18EnumerateBackwardsEPFiR9nsCStringPvES2_ + _ZN14nsCStringArray23RemoveCStringIgnoreCaseERK10nsACString + _ZN14nsCStringArray4SortEPFiPK9nsCStringS2_PvES3_ + _ZN14nsCStringArray4SortEv + _ZN14nsCStringArray5ClearEv + _ZN14nsCStringArrayC1Ei + _ZN14nsCStringArrayC1Ev + _ZN14nsCStringArrayC2Ei + _ZN14nsCStringArrayC2Ev + _ZN14nsCStringArrayD0Ev + _ZN14nsCStringArrayD1Ev + _ZN14nsCStringArrayD2Ev + _ZN14nsCStringArrayaSERKS_ + _ZN14nsISupportsKeyC1EP20nsIObjectInputStreamPj + _ZN14nsISupportsKeyC2EP20nsIObjectInputStreamPj + _ZN14nsXPTCStubBase14QueryInterfaceERK4nsIDPPv + _ZN14nsXPTCStubBase5Stub3Ev + _ZN14nsXPTCStubBase5Stub4Ev + _ZN14nsXPTCStubBase5Stub5Ev + _ZN14nsXPTCStubBase5Stub6Ev + _ZN14nsXPTCStubBase5Stub7Ev + _ZN14nsXPTCStubBase5Stub8Ev + _ZN14nsXPTCStubBase5Stub9Ev + _ZN14nsXPTCStubBase6Stub10Ev + _ZN14nsXPTCStubBase6Stub11Ev + _ZN14nsXPTCStubBase6Stub12Ev + _ZN14nsXPTCStubBase6Stub13Ev + _ZN14nsXPTCStubBase6Stub14Ev + _ZN14nsXPTCStubBase6Stub15Ev + _ZN14nsXPTCStubBase6Stub16Ev + _ZN14nsXPTCStubBase6Stub17Ev + _ZN14nsXPTCStubBase6Stub18Ev + _ZN14nsXPTCStubBase6Stub19Ev + _ZN14nsXPTCStubBase6Stub20Ev + _ZN14nsXPTCStubBase6Stub21Ev + _ZN14nsXPTCStubBase6Stub22Ev + _ZN14nsXPTCStubBase6Stub23Ev + _ZN14nsXPTCStubBase6Stub24Ev + _ZN14nsXPTCStubBase6Stub25Ev + _ZN14nsXPTCStubBase6Stub26Ev + _ZN14nsXPTCStubBase6Stub27Ev + _ZN14nsXPTCStubBase6Stub28Ev + _ZN14nsXPTCStubBase6Stub29Ev + _ZN14nsXPTCStubBase6Stub30Ev + _ZN14nsXPTCStubBase6Stub31Ev + _ZN14nsXPTCStubBase6Stub32Ev + _ZN14nsXPTCStubBase6Stub33Ev + _ZN14nsXPTCStubBase6Stub34Ev + _ZN14nsXPTCStubBase6Stub35Ev + _ZN14nsXPTCStubBase6Stub36Ev + _ZN14nsXPTCStubBase6Stub37Ev + _ZN14nsXPTCStubBase6Stub38Ev + _ZN14nsXPTCStubBase6Stub39Ev + _ZN14nsXPTCStubBase6Stub40Ev + _ZN14nsXPTCStubBase6Stub41Ev + _ZN14nsXPTCStubBase6Stub42Ev + _ZN14nsXPTCStubBase6Stub43Ev + _ZN14nsXPTCStubBase6Stub44Ev + _ZN14nsXPTCStubBase6Stub45Ev + _ZN14nsXPTCStubBase6Stub46Ev + _ZN14nsXPTCStubBase6Stub47Ev + _ZN14nsXPTCStubBase6Stub48Ev + _ZN14nsXPTCStubBase6Stub49Ev + _ZN14nsXPTCStubBase6Stub50Ev + _ZN14nsXPTCStubBase6Stub51Ev + _ZN14nsXPTCStubBase6Stub52Ev + _ZN14nsXPTCStubBase6Stub53Ev + _ZN14nsXPTCStubBase6Stub54Ev + _ZN14nsXPTCStubBase6Stub55Ev + _ZN14nsXPTCStubBase6Stub56Ev + _ZN14nsXPTCStubBase6Stub57Ev + _ZN14nsXPTCStubBase6Stub58Ev + _ZN14nsXPTCStubBase6Stub59Ev + _ZN14nsXPTCStubBase6Stub60Ev + _ZN14nsXPTCStubBase6Stub61Ev + _ZN14nsXPTCStubBase6Stub62Ev + _ZN14nsXPTCStubBase6Stub63Ev + _ZN14nsXPTCStubBase6Stub64Ev + _ZN14nsXPTCStubBase6Stub65Ev + _ZN14nsXPTCStubBase6Stub66Ev + _ZN14nsXPTCStubBase6Stub67Ev + _ZN14nsXPTCStubBase6Stub68Ev + _ZN14nsXPTCStubBase6Stub69Ev + _ZN14nsXPTCStubBase6Stub70Ev + _ZN14nsXPTCStubBase6Stub71Ev + _ZN14nsXPTCStubBase6Stub72Ev + _ZN14nsXPTCStubBase6Stub73Ev + _ZN14nsXPTCStubBase6Stub74Ev + _ZN14nsXPTCStubBase6Stub75Ev + _ZN14nsXPTCStubBase6Stub76Ev + _ZN14nsXPTCStubBase6Stub77Ev + _ZN14nsXPTCStubBase6Stub78Ev + _ZN14nsXPTCStubBase6Stub79Ev + _ZN14nsXPTCStubBase6Stub80Ev + _ZN14nsXPTCStubBase6Stub81Ev + _ZN14nsXPTCStubBase6Stub82Ev + _ZN14nsXPTCStubBase6Stub83Ev + _ZN14nsXPTCStubBase6Stub84Ev + _ZN14nsXPTCStubBase6Stub85Ev + _ZN14nsXPTCStubBase6Stub86Ev + _ZN14nsXPTCStubBase6Stub87Ev + _ZN14nsXPTCStubBase6Stub88Ev + _ZN14nsXPTCStubBase6Stub89Ev + _ZN14nsXPTCStubBase6Stub90Ev + _ZN14nsXPTCStubBase6Stub91Ev + _ZN14nsXPTCStubBase6Stub92Ev + _ZN14nsXPTCStubBase6Stub93Ev + _ZN14nsXPTCStubBase6Stub94Ev + _ZN14nsXPTCStubBase6Stub95Ev + _ZN14nsXPTCStubBase6Stub96Ev + _ZN14nsXPTCStubBase6Stub97Ev + _ZN14nsXPTCStubBase6Stub98Ev + _ZN14nsXPTCStubBase6Stub99Ev + _ZN14nsXPTCStubBase7Stub100Ev + _ZN14nsXPTCStubBase7Stub101Ev + _ZN14nsXPTCStubBase7Stub102Ev + _ZN14nsXPTCStubBase7Stub103Ev + _ZN14nsXPTCStubBase7Stub104Ev + _ZN14nsXPTCStubBase7Stub105Ev + _ZN14nsXPTCStubBase7Stub106Ev + _ZN14nsXPTCStubBase7Stub107Ev + _ZN14nsXPTCStubBase7Stub108Ev + _ZN14nsXPTCStubBase7Stub109Ev + _ZN14nsXPTCStubBase7Stub110Ev + _ZN14nsXPTCStubBase7Stub111Ev + _ZN14nsXPTCStubBase7Stub112Ev + _ZN14nsXPTCStubBase7Stub113Ev + _ZN14nsXPTCStubBase7Stub114Ev + _ZN14nsXPTCStubBase7Stub115Ev + _ZN14nsXPTCStubBase7Stub116Ev + _ZN14nsXPTCStubBase7Stub117Ev + _ZN14nsXPTCStubBase7Stub118Ev + _ZN14nsXPTCStubBase7Stub119Ev + _ZN14nsXPTCStubBase7Stub120Ev + _ZN14nsXPTCStubBase7Stub121Ev + _ZN14nsXPTCStubBase7Stub122Ev + _ZN14nsXPTCStubBase7Stub123Ev + _ZN14nsXPTCStubBase7Stub124Ev + _ZN14nsXPTCStubBase7Stub125Ev + _ZN14nsXPTCStubBase7Stub126Ev + _ZN14nsXPTCStubBase7Stub127Ev + _ZN14nsXPTCStubBase7Stub128Ev + _ZN14nsXPTCStubBase7Stub129Ev + _ZN14nsXPTCStubBase7Stub130Ev + _ZN14nsXPTCStubBase7Stub131Ev + _ZN14nsXPTCStubBase7Stub132Ev + _ZN14nsXPTCStubBase7Stub133Ev + _ZN14nsXPTCStubBase7Stub134Ev + _ZN14nsXPTCStubBase7Stub135Ev + _ZN14nsXPTCStubBase7Stub136Ev + _ZN14nsXPTCStubBase7Stub137Ev + _ZN14nsXPTCStubBase7Stub138Ev + _ZN14nsXPTCStubBase7Stub139Ev + _ZN14nsXPTCStubBase7Stub140Ev + _ZN14nsXPTCStubBase7Stub141Ev + _ZN14nsXPTCStubBase7Stub142Ev + _ZN14nsXPTCStubBase7Stub143Ev + _ZN14nsXPTCStubBase7Stub144Ev + _ZN14nsXPTCStubBase7Stub145Ev + _ZN14nsXPTCStubBase7Stub146Ev + _ZN14nsXPTCStubBase7Stub147Ev + _ZN14nsXPTCStubBase7Stub148Ev + _ZN14nsXPTCStubBase7Stub149Ev + _ZN14nsXPTCStubBase7Stub150Ev + _ZN14nsXPTCStubBase7Stub151Ev + _ZN14nsXPTCStubBase7Stub152Ev + _ZN14nsXPTCStubBase7Stub153Ev + _ZN14nsXPTCStubBase7Stub154Ev + _ZN14nsXPTCStubBase7Stub155Ev + _ZN14nsXPTCStubBase7Stub156Ev + _ZN14nsXPTCStubBase7Stub157Ev + _ZN14nsXPTCStubBase7Stub158Ev + _ZN14nsXPTCStubBase7Stub159Ev + _ZN14nsXPTCStubBase7Stub160Ev + _ZN14nsXPTCStubBase7Stub161Ev + _ZN14nsXPTCStubBase7Stub162Ev + _ZN14nsXPTCStubBase7Stub163Ev + _ZN14nsXPTCStubBase7Stub164Ev + _ZN14nsXPTCStubBase7Stub165Ev + _ZN14nsXPTCStubBase7Stub166Ev + _ZN14nsXPTCStubBase7Stub167Ev + _ZN14nsXPTCStubBase7Stub168Ev + _ZN14nsXPTCStubBase7Stub169Ev + _ZN14nsXPTCStubBase7Stub170Ev + _ZN14nsXPTCStubBase7Stub171Ev + _ZN14nsXPTCStubBase7Stub172Ev + _ZN14nsXPTCStubBase7Stub173Ev + _ZN14nsXPTCStubBase7Stub174Ev + _ZN14nsXPTCStubBase7Stub175Ev + _ZN14nsXPTCStubBase7Stub176Ev + _ZN14nsXPTCStubBase7Stub177Ev + _ZN14nsXPTCStubBase7Stub178Ev + _ZN14nsXPTCStubBase7Stub179Ev + _ZN14nsXPTCStubBase7Stub180Ev + _ZN14nsXPTCStubBase7Stub181Ev + _ZN14nsXPTCStubBase7Stub182Ev + _ZN14nsXPTCStubBase7Stub183Ev + _ZN14nsXPTCStubBase7Stub184Ev + _ZN14nsXPTCStubBase7Stub185Ev + _ZN14nsXPTCStubBase7Stub186Ev + _ZN14nsXPTCStubBase7Stub187Ev + _ZN14nsXPTCStubBase7Stub188Ev + _ZN14nsXPTCStubBase7Stub189Ev + _ZN14nsXPTCStubBase7Stub190Ev + _ZN14nsXPTCStubBase7Stub191Ev + _ZN14nsXPTCStubBase7Stub192Ev + _ZN14nsXPTCStubBase7Stub193Ev + _ZN14nsXPTCStubBase7Stub194Ev + _ZN14nsXPTCStubBase7Stub195Ev + _ZN14nsXPTCStubBase7Stub196Ev + _ZN14nsXPTCStubBase7Stub197Ev + _ZN14nsXPTCStubBase7Stub198Ev + _ZN14nsXPTCStubBase7Stub199Ev + _ZN14nsXPTCStubBase7Stub200Ev + _ZN14nsXPTCStubBase7Stub201Ev + _ZN14nsXPTCStubBase7Stub202Ev + _ZN14nsXPTCStubBase7Stub203Ev + _ZN14nsXPTCStubBase7Stub204Ev + _ZN14nsXPTCStubBase7Stub205Ev + _ZN14nsXPTCStubBase7Stub206Ev + _ZN14nsXPTCStubBase7Stub207Ev + _ZN14nsXPTCStubBase7Stub208Ev + _ZN14nsXPTCStubBase7Stub209Ev + _ZN14nsXPTCStubBase7Stub210Ev + _ZN14nsXPTCStubBase7Stub211Ev + _ZN14nsXPTCStubBase7Stub212Ev + _ZN14nsXPTCStubBase7Stub213Ev + _ZN14nsXPTCStubBase7Stub214Ev + _ZN14nsXPTCStubBase7Stub215Ev + _ZN14nsXPTCStubBase7Stub216Ev + _ZN14nsXPTCStubBase7Stub217Ev + _ZN14nsXPTCStubBase7Stub218Ev + _ZN14nsXPTCStubBase7Stub219Ev + _ZN14nsXPTCStubBase7Stub220Ev + _ZN14nsXPTCStubBase7Stub221Ev + _ZN14nsXPTCStubBase7Stub222Ev + _ZN14nsXPTCStubBase7Stub223Ev + _ZN14nsXPTCStubBase7Stub224Ev + _ZN14nsXPTCStubBase7Stub225Ev + _ZN14nsXPTCStubBase7Stub226Ev + _ZN14nsXPTCStubBase7Stub227Ev + _ZN14nsXPTCStubBase7Stub228Ev + _ZN14nsXPTCStubBase7Stub229Ev + _ZN14nsXPTCStubBase7Stub230Ev + _ZN14nsXPTCStubBase7Stub231Ev + _ZN14nsXPTCStubBase7Stub232Ev + _ZN14nsXPTCStubBase7Stub233Ev + _ZN14nsXPTCStubBase7Stub234Ev + _ZN14nsXPTCStubBase7Stub235Ev + _ZN14nsXPTCStubBase7Stub236Ev + _ZN14nsXPTCStubBase7Stub237Ev + _ZN14nsXPTCStubBase7Stub238Ev + _ZN14nsXPTCStubBase7Stub239Ev + _ZN14nsXPTCStubBase7Stub240Ev + _ZN14nsXPTCStubBase7Stub241Ev + _ZN14nsXPTCStubBase7Stub242Ev + _ZN14nsXPTCStubBase7Stub243Ev + _ZN14nsXPTCStubBase7Stub244Ev + _ZN14nsXPTCStubBase7Stub245Ev + _ZN14nsXPTCStubBase7Stub246Ev + _ZN14nsXPTCStubBase7Stub247Ev + _ZN14nsXPTCStubBase7Stub248Ev + _ZN14nsXPTCStubBase7Stub249Ev + _ZN14nsXPTCStubBase9Sentinel0Ev + _ZN14nsXPTCStubBase9Sentinel1Ev + _ZN14nsXPTCStubBase9Sentinel2Ev + _ZN14nsXPTCStubBase9Sentinel3Ev + _ZN14nsXPTCStubBase9Sentinel4Ev + _ZN15nsAutoVoidArray5ClearEv + _ZN15nsAutoVoidArray6SizeToEi + _ZN15nsAutoVoidArray7CompactEv + _ZN15nsAutoVoidArrayC1Ev + _ZN15nsAutoVoidArrayC2Ev + _ZN15nsCOMArray_base12RemoveObjectEP11nsISupports + _ZN15nsCOMArray_base14InsertObjectAtEP11nsISupportsi + _ZN15nsCOMArray_base14RemoveObjectAtEi + _ZN15nsCOMArray_base15InsertObjectsAtERKS_i + _ZN15nsCOMArray_base15ReplaceObjectAtEP11nsISupportsi + _ZN15nsCOMArray_base5ClearEv + _ZN15nsCOMArray_baseC1ERKS_ + _ZN15nsCOMArray_baseC2ERKS_ + _ZN15nsCOMArray_baseD1Ev + _ZN15nsCOMArray_baseD2Ev + _ZN15nsPrintfCStringC1EPKcz + _ZN15nsPrintfCStringC1EjPKcz + _ZN15nsPrintfCStringC2EPKcz + _ZN15nsPrintfCStringC2EjPKcz + _ZN15nsSupportsArray11DeleteArrayEv + _ZN15nsSupportsArray11GrowArrayByEi + _ZN15nsSupportsArray11LastIndexOfEPK11nsISupports + _ZN15nsSupportsArray11MoveElementEii + _ZN15nsSupportsArray13RemoveElementEPK11nsISupportsj + _ZN15nsSupportsArray14QueryInterfaceERK4nsIDPPv + _ZN15nsSupportsArray15InsertElementAtEP11nsISupportsj + _ZN15nsSupportsArray16InsertElementsAtEP16nsISupportsArrayj + _ZN15nsSupportsArray16RemoveElementsAtEjj + _ZN15nsSupportsArray16ReplaceElementAtEP11nsISupportsj + _ZN15nsSupportsArray17EnumerateForwardsEPFiP11nsISupportsPvES2_ + _ZN15nsSupportsArray17IndexOfStartingAtEPK11nsISupportsj + _ZN15nsSupportsArray17RemoveLastElementEPK11nsISupports + _ZN15nsSupportsArray18EnumerateBackwardsEPFiP11nsISupportsPvES2_ + _ZN15nsSupportsArray4ReadEP20nsIObjectInputStream + _ZN15nsSupportsArray5ClearEv + _ZN15nsSupportsArray5CloneEPP16nsISupportsArray + _ZN15nsSupportsArray5WriteEP21nsIObjectOutputStream + _ZN15nsSupportsArray6AddRefEv + _ZN15nsSupportsArray6CreateEP11nsISupportsRK4nsIDPPv + _ZN15nsSupportsArray6EqualsEPK16nsISupportsArray + _ZN15nsSupportsArray6SizeToEi + _ZN15nsSupportsArray7CompactEv + _ZN15nsSupportsArray7IndexOfEPK11nsISupports + _ZN15nsSupportsArray7ReleaseEv + _ZN15nsSupportsArray9ElementAtEj + _ZN15nsSupportsArray9EnumerateEPP13nsIEnumerator + _ZN15nsSupportsArrayC1Ev + _ZN15nsSupportsArrayC2Ev + _ZN15nsSupportsArrayD1Ev + _ZN15nsSupportsArrayD2Ev + _ZN16nsServiceManager10GetServiceEPKcRK4nsIDPP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager10GetServiceERK4nsIDS2_PP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager14ReleaseServiceEPKcP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager14ReleaseServiceERK4nsIDP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager15RegisterServiceEPKcP11nsISupports + _ZN16nsServiceManager15RegisterServiceERK4nsIDP11nsISupports + _ZN16nsServiceManager17UnregisterServiceEPKc + _ZN16nsServiceManager17UnregisterServiceERK4nsID + _ZN16nsServiceManager23GetGlobalServiceManagerEPP17nsIServiceManager + _ZN16nsServiceManager28ShutdownGlobalServiceManagerEPP17nsIServiceManager + _ZN16nsSmallVoidArray13AppendElementEPv + _ZN16nsSmallVoidArray13RemoveElementEPv + _ZN16nsSmallVoidArray14SetSingleChildEPv + _ZN16nsSmallVoidArray14SwitchToVectorEv + _ZN16nsSmallVoidArray15InsertElementAtEPvi + _ZN16nsSmallVoidArray15RemoveElementAtEi + _ZN16nsSmallVoidArray16InsertElementsAtERK11nsVoidArrayi + _ZN16nsSmallVoidArray16RemoveElementsAtEii + _ZN16nsSmallVoidArray16ReplaceElementAtEPvi + _ZN16nsSmallVoidArray17EnumerateForwardsEPFiPvS0_ES0_ + _ZN16nsSmallVoidArray18EnumerateBackwardsEPFiPvS0_ES0_ + _ZN16nsSmallVoidArray4SortEPFiPKvS1_PvES2_ + _ZN16nsSmallVoidArray5ClearEv + _ZN16nsSmallVoidArray6SizeToEi + _ZN16nsSmallVoidArray7CompactEv + _ZN16nsSmallVoidArrayC1Ev + _ZN16nsSmallVoidArrayC2Ev + _ZN16nsSmallVoidArrayD1Ev + _ZN16nsSmallVoidArrayD2Ev + _ZN16nsSmallVoidArrayaSERS_ + _ZN17nsArrayEnumeratorC1EP16nsISupportsArray + _ZN17nsArrayEnumeratorC2EP16nsISupportsArray + _ZN17nsArrayEnumeratorD1Ev + _ZN17nsArrayEnumeratorD2Ev + _ZN17nsObjectHashtable11CopyElementEP12PLDHashTableP15PLDHashEntryHdrjPv + _ZN17nsObjectHashtable15RemoveAndDeleteEP9nsHashKey + _ZN17nsObjectHashtable5CloneEv + _ZN17nsObjectHashtable5ResetEv + _ZN17nsObjectHashtableC1EPFPvP9nsHashKeyS0_S0_ES0_PFiS2_S0_S0_ES0_ji + _ZN17nsObjectHashtableC2EPFPvP9nsHashKeyS0_S0_ES0_PFiS2_S0_S0_ES0_ji + _ZN17nsObjectHashtableD0Ev + _ZN17nsObjectHashtableD1Ev + _ZN17nsObjectHashtableD2Ev + _ZN17nsSegmentedBuffer16AppendNewSegmentEv + _ZN17nsSegmentedBuffer4InitEjjP9nsIMemory + _ZN17nsSegmentedBuffer5EmptyEv + _ZN17nsTraceRefcntImpl12WalkTheStackEP7__sFILE + _ZN17nsTraceRefcntImpl14DemangleSymbolEPKcPci + _ZN17nsTraceRefcntImpl14DumpStatisticsENS_14StatisticsTypeEP7__sFILE + _ZN17nsTraceRefcntImpl15ResetStatisticsEv + _ZN17nsTraceRefcntImpl18LoadLibrarySymbolsEPKcPv + _ZN17nsTraceRefcntImpl18SetActivityIsLegalEi + _ZN17nsTraceRefcntImpl7StartupEv + _ZN17nsTraceRefcntImpl8ShutdownEv + _ZN17nsUnionEnumeratorC1EP19nsISimpleEnumeratorS1_ + _ZN17nsUnionEnumeratorC2EP19nsISimpleEnumeratorS1_ + _ZN17nsUnionEnumeratorD1Ev + _ZN17nsUnionEnumeratorD2Ev + _ZN18nsComponentManager10InitializeEv + _ZN18nsComponentManager11FindFactoryERK4nsIDPP10nsIFactory + _ZN18nsComponentManager12AutoRegisterEiP7nsIFile + _ZN18nsComponentManager12IsRegisteredERK4nsIDPi + _ZN18nsComponentManager13FreeLibrariesEv + _ZN18nsComponentManager14CreateInstanceEPKcP11nsISupportsRK4nsIDPPv + _ZN18nsComponentManager14CreateInstanceERK4nsIDP11nsISupportsS2_PPv + _ZN18nsComponentManager14GetClassObjectERK4nsIDS2_PPv + _ZN18nsComponentManager15EnumerateCLSIDsEPP13nsIEnumerator + _ZN18nsComponentManager15RegisterFactoryERK4nsIDPKcS4_P10nsIFactoryi + _ZN18nsComponentManager17CLSIDToContractIDEP4nsIDPPcS3_ + _ZN18nsComponentManager17RegisterComponentERK4nsIDPKcS4_S4_ii + _ZN18nsComponentManager17UnregisterFactoryERK4nsIDP10nsIFactory + _ZN18nsComponentManager19ContractIDToClassIDEPKcP4nsID + _ZN18nsComponentManager19UnregisterComponentERK4nsIDPKc + _ZN18nsComponentManager20EnumerateContractIDsEPP13nsIEnumerator + _ZN18nsComponentManager20RegisterComponentLibERK4nsIDPKcS4_S4_ii + _ZN18nsComponentManager21AutoRegisterComponentEiP7nsIFile + _ZN18nsComponentManager21RegisterComponentSpecERK4nsIDPKcS4_P7nsIFileii + _ZN18nsComponentManager23AutoUnregisterComponentEiP7nsIFile + _ZN18nsComponentManager23UnregisterComponentSpecERK4nsIDP7nsIFile + _ZN18nsVoidHashSetSuper4InitEj + _ZN18nsVoidHashSetSuper6RemoveEPKv + _ZN18nsVoidHashSetSuper8AddEntryEPKv + _ZN18nsVoidHashSetSuper8GetEntryEPKv + _ZN18nsVoidHashSetSuperC1Ev + _ZN18nsVoidHashSetSuperC2Ev + _ZN18nsVoidHashSetSuperD1Ev + _ZN18nsVoidHashSetSuperD2Ev + _ZN19nsDirEnumeratorUnixC1Ev + _ZN19nsDirEnumeratorUnixC2Ev + _ZN19nsDirEnumeratorUnixD1Ev + _ZN19nsDirEnumeratorUnixD2Ev + _ZN19nsInt32HashSetSuper4InitEj + _ZN19nsInt32HashSetSuper6RemoveEi + _ZN19nsInt32HashSetSuper8AddEntryEi + _ZN19nsInt32HashSetSuper8GetEntryEi + _ZN19nsInt32HashSetSuperC1Ev + _ZN19nsInt32HashSetSuperC2Ev + _ZN19nsInt32HashSetSuperD1Ev + _ZN19nsInt32HashSetSuperD2Ev + _ZN19nsPromiseFlatString4InitERK11nsSubstring + _ZN19nsPromiseFlatString4InitERK9nsAString + _ZN19nsSupportsHashtable13EnumerateCopyEP12PLDHashTableP15PLDHashEntryHdrjPv + _ZN19nsSupportsHashtable14ReleaseElementEP9nsHashKeyPvS2_ + _ZN19nsSupportsHashtable3GetEP9nsHashKey + _ZN19nsSupportsHashtable3PutEP9nsHashKeyP11nsISupportsPS3_ + _ZN19nsSupportsHashtable5CloneEv + _ZN19nsSupportsHashtable5ResetEv + _ZN19nsSupportsHashtable6RemoveEP9nsHashKeyPP11nsISupports + _ZN19nsSupportsHashtableD0Ev + _ZN19nsSupportsHashtableD1Ev + _ZN19nsSupportsHashtableD2Ev + _ZN20nsDependentSubstring6RebindERK11nsSubstringjj + _ZN20nsDependentSubstring6RebindERK9nsAStringjj + _ZN20nsPromiseFlatCString4InitERK10nsACString + _ZN20nsPromiseFlatCString4InitERK12nsCSubstring + _ZN20nsRecyclingAllocator13AddToFreeListEPNS_5BlockE + _ZN20nsRecyclingAllocator13FindFreeBlockEm + _ZN20nsRecyclingAllocator17FreeUnusedBucketsEv + _ZN20nsRecyclingAllocator22nsRecycleTimerCallbackEP8nsITimerPv + _ZN20nsRecyclingAllocator4FreeEPv + _ZN20nsRecyclingAllocator4InitEjjPKc + _ZN20nsRecyclingAllocator6MallocEmi + _ZN20nsRecyclingAllocatorC1EjjPKc + _ZN20nsRecyclingAllocatorC2EjjPKc + _ZN20nsRecyclingAllocatorD1Ev + _ZN20nsRecyclingAllocatorD2Ev + _ZN20nsStringHashSetSuper4InitEj + _ZN20nsStringHashSetSuper6RemoveERK9nsAString + _ZN20nsStringHashSetSuper8AddEntryERK9nsAString + _ZN20nsStringHashSetSuper8GetEntryERK9nsAString + _ZN20nsStringHashSetSuperC1Ev + _ZN20nsStringHashSetSuperC2Ev + _ZN20nsStringHashSetSuperD1Ev + _ZN20nsStringHashSetSuperD2Ev + _ZN21nsCStringHashSetSuper4InitEj + _ZN21nsCStringHashSetSuper6RemoveERK10nsACString + _ZN21nsCStringHashSetSuper8AddEntryERK10nsACString + _ZN21nsCStringHashSetSuper8GetEntryERK10nsACString + _ZN21nsCStringHashSetSuperC1Ev + _ZN21nsCStringHashSetSuperC2Ev + _ZN21nsCStringHashSetSuperD1Ev + _ZN21nsCStringHashSetSuperD2Ev + _ZN21nsDependentCSubstring6RebindERK10nsACStringjj + _ZN21nsDependentCSubstring6RebindERK12nsCSubstringjj + _ZN21nsSingletonEnumeratorC1EP11nsISupports + _ZN21nsSingletonEnumeratorC2EP11nsISupports + _ZN21nsSingletonEnumeratorD1Ev + _ZN21nsSingletonEnumeratorD2Ev + _ZN23nsSupportsWeakReference16GetWeakReferenceEPP16nsIWeakReference + _ZN4nsID5ParseEPKc + _ZN5nsCRT12IsAsciiAlphaEt + _ZN5nsCRT12IsAsciiDigitEt + _ZN5nsCRT12IsAsciiSpaceEt + _ZN5nsCRT14BufferHashCodeEPKcj + _ZN5nsCRT14BufferHashCodeEPKtj + _ZN5nsCRT14HashCodeAsUTF8EPKtPj + _ZN5nsCRT5atollEPKc + _ZN5nsCRT6strcmpEPKtS1_ + _ZN5nsCRT6strdupEPKt + _ZN5nsCRT6strlenEPKt + _ZN5nsCRT6strtokEPcPKcPS0_ + _ZN5nsCRT7IsAsciiEPKc + _ZN5nsCRT7IsAsciiEPKcj + _ZN5nsCRT7IsAsciiEPKt + _ZN5nsCRT7IsAsciiEt + _ZN5nsCRT7IsLowerEc + _ZN5nsCRT7IsUpperEc + _ZN5nsCRT7ToLowerEc + _ZN5nsCRT7ToUpperEc + _ZN5nsCRT7strncmpEPKtS1_j + _ZN5nsCRT7strndupEPKtj + _ZN5nsCRT8HashCodeEPKcPj + _ZN5nsCRT8HashCodeEPKtPj + _ZN7nsDebug5AbortEPKci + _ZN7nsDebug5BreakEPKci + _ZN7nsDebug7WarningEPKcS1_i + _ZN7nsDebug9AssertionEPKcS1_S1_i + _ZN7nsDeque12GrowCapacityEv + _ZN7nsDeque14SetDeallocatorEP14nsDequeFunctor + _ZN7nsDeque3PopEv + _ZN7nsDeque4PeekEv + _ZN7nsDeque4PushEPv + _ZN7nsDeque5EmptyEv + _ZN7nsDeque5EraseEv + _ZN7nsDeque8PopFrontEv + _ZN7nsDeque9PeekFrontEv + _ZN7nsDeque9PushFrontEPv + _ZN7nsDequeC1EP14nsDequeFunctor + _ZN7nsDequeC2EP14nsDequeFunctor + _ZN7nsDequeD1Ev + _ZN7nsDequeD2Ev + _ZN7nsIDKeyC1EP20nsIObjectInputStreamPj + _ZN7nsIDKeyC2EP20nsIObjectInputStreamPj + _ZN8nsMemory12HeapMinimizeEi + _ZN8nsMemory22GetGlobalMemoryServiceEv + _ZN8nsMemory4FreeEPv + _ZN8nsMemory5AllocEm + _ZN8nsMemory5CloneEPKvm + _ZN8nsMemory7ReallocEPvm + _ZN8nsString10StripCharsEPKc + _ZN8nsString11AppendFloatEd + _ZN8nsString11ReplaceCharEPKct + _ZN8nsString11ReplaceCharEtt + _ZN8nsString15StripWhitespaceEv + _ZN8nsString16ReplaceSubstringEPKtS1_ + _ZN8nsString16ReplaceSubstringERKS_S1_ + _ZN8nsString18CompressWhitespaceEii + _ZN8nsString20AppendWithConversionEPKci + _ZN8nsString20AppendWithConversionERK10nsACString + _ZN8nsString20AssignWithConversionEPKci + _ZN8nsString20AssignWithConversionERK10nsACString + _ZN8nsString4TrimEPKciii + _ZN8nsString9AppendIntEii + _ZN8nsString9AppendIntEli + _ZN8nsString9SetCharAtEtj + _ZN8nsString9StripCharEti + _ZN9nsAString11AppendASCIIEPKc + _ZN9nsAString11AppendASCIIEPKcj + _ZN9nsAString11AssignASCIIEPKc + _ZN9nsAString11AssignASCIIEPKcj + _ZN9nsAString11SetCapacityEj + _ZN9nsAString17GetWritableBufferEPPt + _ZN9nsAString3CutEjj + _ZN9nsAString6AppendEPKt + _ZN9nsAString6AppendEPKtj + _ZN9nsAString6AppendERK16nsSubstringTuple + _ZN9nsAString6AppendERKS_ + _ZN9nsAString6AppendEt + _ZN9nsAString6AssignEPKt + _ZN9nsAString6AssignEPKtj + _ZN9nsAString6AssignERK16nsSubstringTuple + _ZN9nsAString6AssignERKS_ + _ZN9nsAString6AssignEt + _ZN9nsAString6InsertEPKtj + _ZN9nsAString6InsertEPKtjj + _ZN9nsAString6InsertERK16nsSubstringTuplej + _ZN9nsAString6InsertERKS_j + _ZN9nsAString6InsertEtj + _ZN9nsAString7ReplaceEjjRK16nsSubstringTuple + _ZN9nsAString7ReplaceEjjRKS_ + _ZN9nsAString9SetIsVoidEi + _ZN9nsAString9SetLengthEj + _ZN9nsAStringD1Ev + _ZN9nsAStringD2Ev + _ZN9nsCString10StripCharsEPKc + _ZN9nsCString11AppendFloatEd + _ZN9nsCString11ReplaceCharEPKcc + _ZN9nsCString11ReplaceCharEcc + _ZN9nsCString15StripWhitespaceEv + _ZN9nsCString16ReplaceSubstringEPKcS1_ + _ZN9nsCString16ReplaceSubstringERKS_S1_ + _ZN9nsCString18CompressWhitespaceEii + _ZN9nsCString20AppendWithConversionEPKti + _ZN9nsCString20AppendWithConversionERK9nsAString + _ZN9nsCString20AssignWithConversionEPKti + _ZN9nsCString20AssignWithConversionERK9nsAString + _ZN9nsCString4TrimEPKciii + _ZN9nsCString9AppendIntEii + _ZN9nsCString9AppendIntEli + _ZN9nsCString9SetCharAtEtj + _ZN9nsCString9StripCharEci + _ZN9nsHashKeyD0Ev + _ZN9nsHashKeyD1Ev + _ZN9nsHashKeyD2Ev + _ZN9nsIThread10GetCurrentEPPS_ + _ZN9nsIThread10GetIThreadEP8PRThreadPPS_ + _ZN9nsIThread12IsMainThreadEv + _ZN9nsIThread13GetMainThreadEPPS_ + _ZN9nsIThread13SetMainThreadEv + _ZN9nsVariant10InitializeEP20nsDiscriminatedUnion + _ZN9nsVariant10SetToEmptyEP20nsDiscriminatedUnion + _ZN9nsVariant11ConvertToIDERK20nsDiscriminatedUnionP4nsID + _ZN9nsVariant11SetFromBoolEP20nsDiscriminatedUnioni + _ZN9nsVariant11SetFromCharEP20nsDiscriminatedUnionc + _ZN9nsVariant11SetFromInt8EP20nsDiscriminatedUnionh + _ZN9nsVariant12SetFromArrayEP20nsDiscriminatedUniontPK4nsIDjPv + _ZN9nsVariant12SetFromFloatEP20nsDiscriminatedUnionf + _ZN9nsVariant12SetFromInt16EP20nsDiscriminatedUnions + _ZN9nsVariant12SetFromInt32EP20nsDiscriminatedUnioni + _ZN9nsVariant12SetFromInt64EP20nsDiscriminatedUnionl + _ZN9nsVariant12SetFromUint8EP20nsDiscriminatedUnionh + _ZN9nsVariant12SetFromWCharEP20nsDiscriminatedUniont + _ZN9nsVariant13ConvertToBoolERK20nsDiscriminatedUnionPi + _ZN9nsVariant13ConvertToCharERK20nsDiscriminatedUnionPc + _ZN9nsVariant13ConvertToInt8ERK20nsDiscriminatedUnionPh + _ZN9nsVariant13SetFromDoubleEP20nsDiscriminatedUniond + _ZN9nsVariant13SetFromStringEP20nsDiscriminatedUnionPKc + _ZN9nsVariant13SetFromUint16EP20nsDiscriminatedUniont + _ZN9nsVariant13SetFromUint32EP20nsDiscriminatedUnionj + _ZN9nsVariant13SetFromUint64EP20nsDiscriminatedUnionm + _ZN9nsVariant14ConvertToArrayERK20nsDiscriminatedUnionPtP4nsIDPjPPv + _ZN9nsVariant14ConvertToFloatERK20nsDiscriminatedUnionPf + _ZN9nsVariant14ConvertToInt16ERK20nsDiscriminatedUnionPs + _ZN9nsVariant14ConvertToInt32ERK20nsDiscriminatedUnionPi + _ZN9nsVariant14ConvertToInt64ERK20nsDiscriminatedUnionPl + _ZN9nsVariant14ConvertToUint8ERK20nsDiscriminatedUnionPh + _ZN9nsVariant14ConvertToWCharERK20nsDiscriminatedUnionPt + _ZN9nsVariant14SetFromAStringEP20nsDiscriminatedUnionRK9nsAString + _ZN9nsVariant14SetFromVariantEP20nsDiscriminatedUnionP10nsIVariant + _ZN9nsVariant14SetFromWStringEP20nsDiscriminatedUnionPKt + _ZN9nsVariant15ConvertToDoubleERK20nsDiscriminatedUnionPd + _ZN9nsVariant15ConvertToStringERK20nsDiscriminatedUnionPPc + _ZN9nsVariant15ConvertToUint16ERK20nsDiscriminatedUnionPt + _ZN9nsVariant15ConvertToUint32ERK20nsDiscriminatedUnionPj + _ZN9nsVariant15ConvertToUint64ERK20nsDiscriminatedUnionPm + _ZN9nsVariant15SetFromACStringEP20nsDiscriminatedUnionRK10nsACString + _ZN9nsVariant15SetToEmptyArrayEP20nsDiscriminatedUnion + _ZN9nsVariant16ConvertToAStringERK20nsDiscriminatedUnionR9nsAString + _ZN9nsVariant16ConvertToWStringERK20nsDiscriminatedUnionPPt + _ZN9nsVariant16SetFromISupportsEP20nsDiscriminatedUnionP11nsISupports + _ZN9nsVariant16SetFromInterfaceEP20nsDiscriminatedUnionRK4nsIDP11nsISupports + _ZN9nsVariant17ConvertToACStringERK20nsDiscriminatedUnionR10nsACString + _ZN9nsVariant18ConvertToISupportsERK20nsDiscriminatedUnionPP11nsISupports + _ZN9nsVariant18ConvertToInterfaceERK20nsDiscriminatedUnionPP4nsIDPPv + _ZN9nsVariant18SetFromAUTF8StringEP20nsDiscriminatedUnionRK10nsACString + _ZN9nsVariant20ConvertToAUTF8StringERK20nsDiscriminatedUnionR10nsACString + _ZN9nsVariant21SetFromStringWithSizeEP20nsDiscriminatedUnionjPKc + _ZN9nsVariant22SetFromWStringWithSizeEP20nsDiscriminatedUnionjPKt + _ZN9nsVariant23ConvertToStringWithSizeERK20nsDiscriminatedUnionPjPPc + _ZN9nsVariant24ConvertToWStringWithSizeERK20nsDiscriminatedUnionPjPPt + _ZN9nsVariant7CleanupEP20nsDiscriminatedUnion + _ZN9nsVariant9SetFromIDEP20nsDiscriminatedUnionRK4nsID + _ZN9nsVariant9SetToVoidEP20nsDiscriminatedUnion + _ZN9nsVariantC1Ev + _ZN9nsVariantC2Ev + _ZN9nsVariantD1Ev + _ZN9nsVariantD2Ev + _ZNK10nsACString11EqualsASCIIEPKc + _ZNK10nsACString11EqualsASCIIEPKcj + _ZNK10nsACString12IsTerminatedEv + _ZNK10nsACString17GetReadableBufferEPPKc + _ZNK10nsACString20LowerCaseEqualsASCIIEPKc + _ZNK10nsACString20LowerCaseEqualsASCIIEPKcj + _ZNK10nsACString4LastEv + _ZNK10nsACString5FirstEv + _ZNK10nsACString6EqualsEPKc + _ZNK10nsACString6EqualsEPKcRK19nsCStringComparator + _ZNK10nsACString6EqualsERKS_ + _ZNK10nsACString6EqualsERKS_RK19nsCStringComparator + _ZNK10nsACString6IsVoidEv + _ZNK10nsACString6LengthEv + _ZNK10nsACString8FindCharEcj + _ZNK10nsACString9CountCharEc + _ZNK11nsHashtable5WriteEP21nsIObjectOutputStreamPFjS1_PvE + _ZNK11nsStringKey5CloneEv + _ZNK11nsStringKey5WriteEP21nsIObjectOutputStream + _ZNK11nsStringKey6EqualsEPK9nsHashKey + _ZNK11nsStringKey8HashCodeEv + _ZNK11nsSubstring11EqualsASCIIEPKc + _ZNK11nsSubstring11EqualsASCIIEPKcj + _ZNK11nsSubstring20LowerCaseEqualsASCIIEPKc + _ZNK11nsSubstring20LowerCaseEqualsASCIIEPKcj + _ZNK11nsSubstring6EqualsEPKt + _ZNK11nsSubstring6EqualsEPKtRK18nsStringComparator + _ZNK11nsSubstring6EqualsERK9nsAString + _ZNK11nsSubstring6EqualsERK9nsAStringRK18nsStringComparator + _ZNK11nsSubstring6EqualsERKS_ + _ZNK11nsSubstring6EqualsERKS_RK18nsStringComparator + _ZNK11nsSubstring8FindCharEtj + _ZNK11nsSubstring9CountCharEt + _ZNK11nsVoidArray7IndexOfEPv + _ZNK12nsCStringKey5CloneEv + _ZNK12nsCStringKey5WriteEP21nsIObjectOutputStream + _ZNK12nsCStringKey6EqualsEPK9nsHashKey + _ZNK12nsCStringKey8HashCodeEv + _ZNK12nsCSubstring11EqualsASCIIEPKc + _ZNK12nsCSubstring11EqualsASCIIEPKcj + _ZNK12nsCSubstring20LowerCaseEqualsASCIIEPKc + _ZNK12nsCSubstring20LowerCaseEqualsASCIIEPKcj + _ZNK12nsCSubstring6EqualsEPKc + _ZNK12nsCSubstring6EqualsEPKcRK19nsCStringComparator + _ZNK12nsCSubstring6EqualsERK10nsACString + _ZNK12nsCSubstring6EqualsERK10nsACStringRK19nsCStringComparator + _ZNK12nsCSubstring6EqualsERKS_ + _ZNK12nsCSubstring6EqualsERKS_RK19nsCStringComparator + _ZNK12nsCSubstring8FindCharEcj + _ZNK12nsCSubstring9CountCharEc + _ZNK13nsStringArray7IndexOfERK9nsAString + _ZNK13nsStringArray8StringAtEi + _ZNK13nsStringArray8StringAtEiR9nsAString + _ZNK14nsCStringArray17IndexOfIgnoreCaseERK10nsACString + _ZNK14nsCStringArray7IndexOfERK10nsACString + _ZNK14nsCStringArray9CStringAtEi + _ZNK14nsCStringArray9CStringAtEiR10nsACString + _ZNK14nsGetInterfaceclERK4nsIDPPv + _ZNK14nsISupportsKey5WriteEP21nsIObjectOutputStream + _ZNK15nsCOMArray_base13IndexOfObjectEP11nsISupports + _ZNK15nsQueryReferentclERK4nsIDPPv + _ZNK16nsQueryElementAtclERK4nsIDPPv + _ZNK16nsQueryInterfaceclERK4nsIDPPv + _ZNK16nsSmallVoidArray12GetArraySizeEv + _ZNK16nsSmallVoidArray5CountEv + _ZNK16nsSmallVoidArray7IndexOfEPv + _ZNK16nsSmallVoidArray9ElementAtEi + _ZNK16nsSubstringTuple13IsDependentOnEPKtS1_ + _ZNK16nsSubstringTuple6LengthEv + _ZNK16nsSubstringTuple7WriteToEPtj + _ZNK17nsCSubstringTuple13IsDependentOnEPKcS1_ + _ZNK17nsCSubstringTuple6LengthEv + _ZNK17nsCSubstringTuple7WriteToEPcj + _ZNK17nsGetServiceByCIDclERK4nsIDPPv + _ZNK18nsGetWeakReferenceclERK4nsIDPPv + _ZNK21nsCreateInstanceByCIDclERK4nsIDPPv + _ZNK21nsQueryArrayElementAtclERK4nsIDPPv + _ZNK24nsGetServiceByContractIDclERK4nsIDPPv + _ZNK25nsDefaultStringComparatorclEPKtS1_j + _ZNK25nsDefaultStringComparatorclEtt + _ZNK25nsQueryInterfaceWithErrorclERK4nsIDPPv + _ZNK26nsDefaultCStringComparatorclEPKcS1_j + _ZNK26nsDefaultCStringComparatorclEcc + _ZNK28nsCreateInstanceByContractIDclERK4nsIDPPv + _ZNK28nsCreateInstanceFromCategoryclERK4nsIDPPv + _ZNK34nsCaseInsensitiveCStringComparatorclEPKcS1_j + _ZNK34nsCaseInsensitiveCStringComparatorclEcc + _ZNK4nsID16ToProvidedStringERA39_c + _ZNK4nsID8ToStringEv + _ZNK7nsDeque3EndEv + _ZNK7nsDeque4LastEv + _ZNK7nsDeque5BeginEv + _ZNK7nsDeque7ForEachER14nsDequeFunctor + _ZNK7nsDeque8ObjectAtEi + _ZNK7nsDeque9FirstThatER14nsDequeFunctor + _ZNK7nsIDKey5WriteEP21nsIObjectOutputStream + _ZNK8nsString13FindCharInSetEPKci + _ZNK8nsString13FindCharInSetEPKti + _ZNK8nsString14RFindCharInSetEPKti + _ZNK8nsString16EqualsIgnoreCaseEPKci + _ZNK8nsString3MidERS_jj + _ZNK8nsString4FindEPKciii + _ZNK8nsString4FindEPKtii + _ZNK8nsString4FindERK9nsCStringiii + _ZNK8nsString4FindERKS_ii + _ZNK8nsString5RFindEPKciii + _ZNK8nsString5RFindEPKtii + _ZNK8nsString5RFindERK9nsCStringiii + _ZNK8nsString5RFindERKS_ii + _ZNK8nsString7ToFloatEPi + _ZNK8nsString9RFindCharEtii + _ZNK8nsString9ToCStringEPcjj + _ZNK8nsString9ToIntegerEPij + _ZNK9nsAString11EqualsASCIIEPKc + _ZNK9nsAString11EqualsASCIIEPKcj + _ZNK9nsAString12IsTerminatedEv + _ZNK9nsAString17GetReadableBufferEPPKt + _ZNK9nsAString20LowerCaseEqualsASCIIEPKc + _ZNK9nsAString20LowerCaseEqualsASCIIEPKcj + _ZNK9nsAString4LastEv + _ZNK9nsAString5FirstEv + _ZNK9nsAString6EqualsEPKt + _ZNK9nsAString6EqualsEPKtRK18nsStringComparator + _ZNK9nsAString6EqualsERKS_ + _ZNK9nsAString6EqualsERKS_RK18nsStringComparator + _ZNK9nsAString6IsVoidEv + _ZNK9nsAString6LengthEv + _ZNK9nsAString8FindCharEtj + _ZNK9nsAString9CountCharEt + _ZNK9nsCString13FindCharInSetEPKci + _ZNK9nsCString14RFindCharInSetEPKci + _ZNK9nsCString3MidERS_jj + _ZNK9nsCString4FindEPKciii + _ZNK9nsCString4FindERKS_iii + _ZNK9nsCString5RFindEPKciii + _ZNK9nsCString5RFindERKS_iii + _ZNK9nsCString7CompareEPKcii + _ZNK9nsCString7ToFloatEPi + _ZNK9nsCString9RFindCharEtii + _ZNK9nsCString9ToIntegerEPij + _ZNK9nsHashKey5WriteEP21nsIObjectOutputStream diff --git a/src/libs/xpcom18a4/VBoxXPCOM.def b/src/libs/xpcom18a4/VBoxXPCOM.def new file mode 100644 index 00000000..010393ba --- /dev/null +++ b/src/libs/xpcom18a4/VBoxXPCOM.def @@ -0,0 +1,1687 @@ +; $Id: VBoxXPCOM.def $ +;; @file +; VirtualBox XPCOM - Import library definition file. + +; +; Copyright (C) 2018-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; SPDX-License-Identifier: GPL-3.0-only +; + +LIBRARY VBoxXPCOM.dll +EXPORTS + ; + ; To regenerate run the following command line: + ; nm -U ../../../out/darwin.amd64/debug/dist/VirtualBox.app/Contents/MacOS/VBoxXPCOM.dylib | kmk_sed -r -e 's/^[0-9a-fA-F]+ //' -e '/^[A-Z]/!d' | sort | kmk_sed -r -e 's/[SDBC] (.+)$/ \1 DATA/' -e 's/^[A-Z] / /' -e 's/^ _/ /' >> VBoxXPCOM.def + ; + _ZN12nsCharTraitsIcE12sEmptyBufferE DATA + _ZN12nsCharTraitsItE12sEmptyBufferE DATA + NSGetStaticModuleInfo DATA + _ZN17nsObsoleteAString16sCanonicalVTableE DATA + _ZN18nsObsoleteACString16sCanonicalVTableE DATA + _ZTV11nsHashtable DATA + _ZTV11nsLocalFile DATA + _ZTV11nsStringKey DATA + _ZTV11nsVoidArray DATA + _ZTV12nsCStringKey DATA + _ZTV13nsStringArray DATA + _ZTV14nsCStringArray DATA + _ZTV14nsGetInterface DATA + _ZTV14nsISupportsKey DATA + _ZTV14nsXPTCStubBase DATA + _ZTV15nsAutoVoidArray DATA + _ZTV15nsQueryReferent DATA + _ZTV15nsSupportsArray DATA + _ZTV15nsWeakReference DATA + _ZTV16nsQueryElementAt DATA + _ZTV17nsArrayEnumerator DATA + _ZTV17nsGetServiceByCID DATA + _ZTV17nsObjectHashtable DATA + _ZTV17nsUnionEnumerator DATA + _ZTV18nsGetWeakReference DATA + _ZTV19nsDirEnumeratorUnix DATA + _ZTV19nsSupportsHashtable DATA + _ZTV21nsCreateInstanceByCID DATA + _ZTV21nsQueryArrayElementAt DATA + _ZTV21nsSingletonEnumerator DATA + _ZTV23nsSupportsWeakReference DATA + _ZTV24nsGetServiceByContractID DATA + _ZTV25nsDefaultStringComparator DATA + _ZTV26nsDefaultCStringComparator DATA + _ZTV28nsCreateInstanceByContractID DATA + _ZTV28nsCreateInstanceFromCategory DATA + _ZTV34nsCaseInsensitiveCStringComparator DATA + _ZTV7nsIDKey DATA + _ZTV9nsHashKey DATA + _ZTV9nsVariant DATA + gFastLoadService_ DATA + GetExecutionEnvironment + LL_MaxInt + LL_MaxUint + LL_MinInt + LL_Zero + NS_CStringCloneData + NS_CStringContainerFinish + NS_CStringContainerInit + NS_CStringCopy + NS_CStringGetData + NS_CStringSetData + NS_CStringSetDataRange + NS_CStringToUTF16 + NS_GetComponentManager + NS_GetComponentRegistrar + NS_GetDebug + NS_GetFrozenFunctions + NS_GetMemoryManager + NS_GetServiceManager + NS_GetTraceRefcnt + NS_InitXPCOM2 + NS_MeanAndStdDev + NS_NewByteInputStream + NS_NewCStringInputStream + NS_NewCharInputStream + NS_NewEmptyEnumerator + NS_NewLocalFile + NS_NewNativeLocalFile + NS_NewSingletonEnumerator + NS_NewStringInputStream + NS_NewUnionEnumerator + NS_QuickSort + NS_RegisterXPCOMExitRoutine + NS_ShutdownXPCOM + NS_StringCloneData + NS_StringContainerFinish + NS_StringContainerInit + NS_StringCopy + NS_StringGetData + NS_StringSetData + NS_StringSetDataRange + NS_UTF16ToCString + NS_UnregisterXPCOMExitRoutine + PL_ArenaAllocate + PL_ArenaFinish + PL_ArenaGrow + PL_ArenaRelease + PL_CompactArenaPool + PL_CompareStrings + PL_CompareValues + PL_CreateEventQueue + PL_CreateMonitoredEventQueue + PL_CreateNativeEventQueue + PL_DHashAllocTable + PL_DHashClearEntryStub + PL_DHashFinalizeStub + PL_DHashFreeStringKey + PL_DHashFreeTable + PL_DHashGetKeyStub + PL_DHashGetStubOps + PL_DHashMatchEntryStub + PL_DHashMatchStringKey + PL_DHashMoveEntryStub + PL_DHashStringKey + PL_DHashTableDestroy + PL_DHashTableEnumerate + PL_DHashTableFinish + PL_DHashTableInit + PL_DHashTableOperate + PL_DHashTableRawRemove + PL_DHashTableSetAlphaBounds + PL_DHashVoidPtrKeyStub + PL_DequeueEvent + PL_DestroyEvent + PL_DestroyEventQueue + PL_EventAvailable + PL_EventLoop + PL_FavorPerformanceHint + PL_FinishArenaPool + PL_FreeArenaPool + PL_GetEvent + PL_GetEventOwner + PL_GetEventQueueMonitor + PL_GetEventQueueSelectFD + PL_HandleEvent + PL_HashString + PL_HashTableAdd + PL_HashTableDestroy + PL_HashTableDump + PL_HashTableEnumerateEntries + PL_HashTableLookup + PL_HashTableLookupConst + PL_HashTableRawAdd + PL_HashTableRawLookup + PL_HashTableRawLookupConst + PL_HashTableRawRemove + PL_HashTableRemove + PL_InitArenaPool + PL_InitEvent + PL_IsQueueNative + PL_IsQueueOnCurrentThread + PL_MapEvents + PL_NewDHashTable + PL_NewHashTable + PL_PostEvent + PL_PostSynchronousEvent + PL_ProcessPendingEvents + PL_RevokeEvents + PL_WaitForEvent + PL_strcasecmp + PL_strchr + PL_strcmp + PL_strcpy + PL_strdup + PL_strfree + PL_strlen + PL_strncasecmp + PL_strnchr + PL_strncmp + PL_strncpy + PL_strncpyz + PL_strndup + PL_strnlen + PL_strnrchr + PL_strnrstr + PL_strnstr + PL_strrchr + PL_strrstr + PL_strstr + PRP_DestroyNakedCondVar + PRP_NakedBroadcast + PRP_NakedNotify + PRP_NakedWait + PRP_NewNakedCondVar + PRP_TryLock + PR_Abort + PR_Accept + PR_AcceptRead + PR_Access + PR_AddWaitFileDesc + PR_AllocFileDesc + PR_Assert + PR_AtomicAdd + PR_AtomicDecrement + PR_AtomicIncrement + PR_AtomicSet + PR_AttachThread + PR_Available + PR_Available64 + PR_Bind + PR_BlockClockInterrupts + PR_BlockInterrupt + PR_CEnterMonitor + PR_CExitMonitor + PR_CNotify + PR_CNotifyAll + PR_CSetOnMonitorRecycle + PR_CWait + PR_CallOnce + PR_CallOnceWithArg + PR_Calloc + PR_CancelWaitFileDesc + PR_CancelWaitGroup + PR_CeilingLog2 + PR_ChangeFileDescNativeHandle + PR_Cleanup + PR_ClearInterrupt + PR_ClearThreadGCAble + PR_Close + PR_CloseDir + PR_CloseFileMap + PR_CloseSemaphore + PR_Connect + PR_ConnectContinue + PR_ConvertIPv4AddrToIPv6 + PR_CreateFileMap + PR_CreateIOLayer + PR_CreateIOLayerStub + PR_CreateMWaitEnumerator + PR_CreatePipe + PR_CreateProcess + PR_CreateProcessDetached + PR_CreateSocketPollFd + PR_CreateStack + PR_CreateThread + PR_CreateThreadGCAble + PR_CreateWaitGroup + PR_Delete + PR_DeleteSemaphore + PR_DestroyCondVar + PR_DestroyLock + PR_DestroyMWaitEnumerator + PR_DestroyMonitor + PR_DestroyPollableEvent + PR_DestroyProcessAttr + PR_DestroyRWLock + PR_DestroySem + PR_DestroySocketPollFd + PR_DestroyStack + PR_DestroyWaitGroup + PR_DetachProcess + PR_DetachThread + PR_DisableClockInterrupts + PR_EmulateAcceptRead + PR_EmulateSendFile + PR_EnableClockInterrupts + PR_EnterMonitor + PR_EnumerateAddrInfo + PR_EnumerateHostEnt + PR_EnumerateThreads + PR_EnumerateWaitGroup + PR_ErrorInstallCallback + PR_ErrorInstallTable + PR_ErrorLanguages + PR_ErrorToName + PR_ErrorToString + PR_ExitMonitor + PR_ExplodeTime + PR_FD_CLR + PR_FD_ISSET + PR_FD_NCLR + PR_FD_NISSET + PR_FD_NSET + PR_FD_SET + PR_FD_ZERO + PR_FPrintZoneStats + PR_FileDesc2NativeHandle + PR_FindFunctionSymbol + PR_FindFunctionSymbolAndLibrary + PR_FindLibrary + PR_FindSymbol + PR_FindSymbolAndLibrary + PR_FloorLog2 + PR_FormatTime + PR_FormatTimeUSEnglish + PR_Free + PR_FreeAddrInfo + PR_FreeLibraryName + PR_GMTParameters + PR_GetAddrInfoByName + PR_GetCanonNameFromAddrInfo + PR_GetConnectStatus + PR_GetCurrentThread + PR_GetDefaultIOMethods + PR_GetDescType + PR_GetEnv + PR_GetError + PR_GetErrorText + PR_GetErrorTextLength + PR_GetFileInfo + PR_GetFileInfo64 + PR_GetFileMethods + PR_GetHostByAddr + PR_GetHostByName + PR_GetIPNodeByName + PR_GetIdentitiesLayer + PR_GetInheritedFD + PR_GetLayersIdentity + PR_GetLibraryFilePathname + PR_GetLibraryName + PR_GetLibraryPath + PR_GetMemMapAlignment + PR_GetMonitorEntryCount + PR_GetNameForIdentity + PR_GetOSError + PR_GetOpenFileInfo + PR_GetOpenFileInfo64 + PR_GetPageShift + PR_GetPageSize + PR_GetPeerName + PR_GetPipeMethods + PR_GetProtoByName + PR_GetProtoByNumber + PR_GetSP + PR_GetSockName + PR_GetSocketOption + PR_GetSpecialFD + PR_GetTCPMethods + PR_GetThreadAffinityMask + PR_GetThreadID + PR_GetThreadPriority + PR_GetThreadPrivate + PR_GetThreadScope + PR_GetThreadState + PR_GetThreadType + PR_GetUDPMethods + PR_GetUniqueIdentity + PR_ImplodeTime + PR_ImportFile + PR_ImportPipe + PR_ImportTCPSocket + PR_ImportUDPSocket + PR_Init + PR_Initialize + PR_InitializeNetAddr + PR_Initialized + PR_Interrupt + PR_IntervalNow + PR_IntervalToMicroseconds + PR_IntervalToMilliseconds + PR_IntervalToSeconds + PR_IsNetAddrType + PR_JoinThread + PR_KillProcess + PR_Listen + PR_LoadLibrary + PR_LoadLibraryWithFlags + PR_LoadStaticLibrary + PR_LocalTimeParameters + PR_Lock + PR_LockFile + PR_LogFlush + PR_LogPrint + PR_MakeDir + PR_Malloc + PR_MemMap + PR_MemUnmap + PR_MicrosecondsToInterval + PR_MillisecondsToInterval + PR_MkDir + PR_NetAddrToString + PR_NewCondVar + PR_NewLock + PR_NewLogModule + PR_NewMonitor + PR_NewNamedMonitor + PR_NewPollableEvent + PR_NewProcessAttr + PR_NewRWLock + PR_NewSem + PR_NewTCPSocket + PR_NewTCPSocketPair + PR_NewThreadPrivateIndex + PR_NewUDPSocket + PR_NormalizeTime + PR_Notify + PR_NotifyAll + PR_NotifyAllCondVar + PR_NotifyCondVar + PR_Now + PR_Open + PR_OpenDir + PR_OpenFile + PR_OpenSemaphore + PR_OpenTCPSocket + PR_OpenUDPSocket + PR_ParseTimeString + PR_Poll + PR_PopIOLayer + PR_PostSem + PR_PostSemaphore + PR_ProcessAttrSetCurrentDirectory + PR_ProcessAttrSetInheritableFD + PR_ProcessAttrSetStdioRedirect + PR_ProcessExit + PR_PushIOLayer + PR_RWLock_Rlock + PR_RWLock_Unlock + PR_RWLock_Wlock + PR_Read + PR_ReadDir + PR_Realloc + PR_Recv + PR_RecvFrom + PR_Rename + PR_ResetProcessAttr + PR_ResumeAll + PR_RmDir + PR_SecondsToInterval + PR_Seek + PR_Seek64 + PR_Select + PR_Send + PR_SendFile + PR_SendTo + PR_SetConcurrency + PR_SetEnv + PR_SetError + PR_SetErrorText + PR_SetFDCacheSize + PR_SetFDInheritable + PR_SetLibraryPath + PR_SetLogBuffering + PR_SetLogFile + PR_SetNetAddr + PR_SetPollableEvent + PR_SetSocketOption + PR_SetStdioRedirect + PR_SetThreadAffinityMask + PR_SetThreadDumpProc + PR_SetThreadGCAble + PR_SetThreadPriority + PR_SetThreadPrivate + PR_SetThreadRecycleMode + PR_Shutdown + PR_Sleep + PR_Socket + PR_StackPop + PR_StackPush + PR_Stat + PR_StringToNetAddr + PR_SuspendAll + PR_Sync + PR_TLockFile + PR_TicksPerSecond + PR_TransmitFile + PR_USPacificTimeParameters + PR_UnblockClockInterrupts + PR_UnblockInterrupt + PR_UnloadLibrary + PR_Unlock + PR_UnlockFile + PR_VersionCheck + PR_Wait + PR_WaitCondVar + PR_WaitForPollableEvent + PR_WaitProcess + PR_WaitRecvReady + PR_WaitSem + PR_WaitSemaphore + PR_Write + PR_Writev + PR_Yield + PR_cnvtf + PR_dtoa + PR_fprintf + PR_htonl + PR_htonll + PR_htons + PR_ntohl + PR_ntohll + PR_ntohs + PR_smprintf + PR_smprintf_free + PR_snprintf + PR_sprintf_append + PR_sscanf + PR_strtod + PR_sxprintf + PR_vfprintf + PR_vsmprintf + PR_vsnprintf + PR_vsprintf_append + PR_vsxprintf + PT_FPrintStats + SetExecutionEnvironment + XPTC_InvokeByIndex + XPTI_FreeInterfaceInfoManager + XPTI_GetInterfaceInfoManager + XPT_ArenaFree + XPT_ArenaMalloc + XPT_ArenaStrDup + XPT_AssertFailed + XPT_DataOffset + XPT_DestroyArena + XPT_DestroyInterfaceDirectoryEntry + XPT_DestroyXDRState + XPT_Do16 + XPT_Do32 + XPT_Do64 + XPT_Do8 + XPT_DoCString + XPT_DoHeader + XPT_DoHeaderPrologue + XPT_DoIID + XPT_DoString + XPT_DoStringInline + XPT_DumpStats + XPT_FillInterfaceDirectoryEntry + XPT_FillMethodDescriptor + XPT_FillParamDescriptor + XPT_FreeHeader + XPT_FreeInterfaceDescriptor + XPT_GetAddrForOffset + XPT_GetInterfaceIndexByName + XPT_GetOffsetForAddr + XPT_GetXDRData + XPT_GetXDRDataLength + XPT_InterfaceDescriptorAddConsts + XPT_InterfaceDescriptorAddMethods + XPT_InterfaceDescriptorAddTypes + XPT_MakeCursor + XPT_NewAnnotation + XPT_NewArena + XPT_NewHeader + XPT_NewInterfaceDescriptor + XPT_NewString + XPT_NewStringZ + XPT_NewXDRState + XPT_NotifyDoneLoading + XPT_ParseVersionString + XPT_SeekTo + XPT_SetAddrForOffset + XPT_SetDataOffset + XPT_SetOffsetForAddr + XPT_SizeOfHeader + XPT_SizeOfHeaderBlock + _MD_LockFile + _MD_TLockFile + _MD_UnlockFile + _MD_gethostname + _MD_getsysinfo + _MD_unix_map_accept_error + _MD_unix_map_access_error + _MD_unix_map_bind_error + _MD_unix_map_close_error + _MD_unix_map_closedir_error + _MD_unix_map_connect_error + _MD_unix_map_default_error + _MD_unix_map_flock_error + _MD_unix_map_fstat_error + _MD_unix_map_fsync_error + _MD_unix_map_gethostname_error + _MD_unix_map_getpeername_error + _MD_unix_map_getsockname_error + _MD_unix_map_getsockopt_error + _MD_unix_map_listen_error + _MD_unix_map_lockf_error + _MD_unix_map_lseek_error + _MD_unix_map_mkdir_error + _MD_unix_map_mmap_error + _MD_unix_map_open_error + _MD_unix_map_opendir_error + _MD_unix_map_poll_error + _MD_unix_map_poll_revents_error + _MD_unix_map_read_error + _MD_unix_map_recv_error + _MD_unix_map_recvfrom_error + _MD_unix_map_rename_error + _MD_unix_map_rmdir_error + _MD_unix_map_select_error + _MD_unix_map_send_error + _MD_unix_map_sendto_error + _MD_unix_map_setsockopt_error + _MD_unix_map_shutdown_error + _MD_unix_map_socket_error + _MD_unix_map_socketavailable_error + _MD_unix_map_socketpair_error + _MD_unix_map_stat_error + _MD_unix_map_unlink_error + _MD_unix_map_write_error + _MD_unix_map_writev_error + _MD_unix_readdir_error + _Z10HashStringRK10nsACString + _Z10HashStringRK9nsAString + _Z10NS_NewAtomPKc + _Z10NS_NewAtomPKt + _Z10NS_NewAtomRK10nsACString + _Z10NS_NewAtomRK9nsAString + _Z11EmptyStringv + _Z11NS_NewArrayPP15nsIMutableArray + _Z11NS_NewArrayPP15nsIMutableArrayRK15nsCOMArray_base + _Z11NS_NewPipe2PP19nsIAsyncInputStreamPP20nsIAsyncOutputStreamiijjP9nsIMemory + _Z11ToLowerCaseR10nsACString + _Z11ToLowerCaseR12nsCSubstring + _Z11ToLowerCaseRK10nsACStringRS_ + _Z11ToUpperCaseR10nsACString + _Z11ToUpperCaseR12nsCSubstring + _Z11ToUpperCaseRK10nsACStringRS_ + _Z12EmptyCStringv + _Z12NS_AsyncCopyP14nsIInputStreamP15nsIOutputStreamP14nsIEventTarget15nsAsyncCopyModejPFvPvjES6_ + _Z12NS_InitXPCOMPP17nsIServiceManagerP7nsIFile + _Z12NS_NewThreadPP9nsIThreadP11nsIRunnablej13PRThreadState16PRThreadPriority13PRThreadScope + _Z12NS_NewThreadPP9nsIThreadj13PRThreadState16PRThreadPriority13PRThreadScope + _Z12ToNewCStringRK10nsACString + _Z12ToNewCStringRK9nsAString + _Z12ToNewUnicodeRK10nsACString + _Z12ToNewUnicodeRK9nsAString + _Z13CopyUnicodeToRK17nsReadingIteratorItES2_R9nsAString + _Z13CopyUnicodeToRK9nsAStringjPtj + _Z14FindInReadableRK10nsACStringR17nsReadingIteratorIcES4_RK19nsCStringComparator + _Z14FindInReadableRK9nsAStringR17nsReadingIteratorItES4_RK18nsStringComparator + _Z14StringEndsWithRK10nsACStringS1_RK19nsCStringComparator + _Z14StringEndsWithRK9nsAStringS1_RK18nsStringComparator + _Z15AppendUnicodeToRK17nsReadingIteratorItES2_R9nsAString + _Z15CopyUTF16toUTF8PKtR10nsACString + _Z15CopyUTF16toUTF8RK9nsAStringR10nsACString + _Z15CopyUTF8toUTF16PKcR9nsAString + _Z15CopyUTF8toUTF16RK10nsACStringR9nsAString + _Z15NS_ProxyReleaseP14nsIEventTargetP11nsISupportsi + _Z15RFindInReadableRK10nsACStringR17nsReadingIteratorIcES4_RK19nsCStringComparator + _Z15RFindInReadableRK9nsAStringR17nsReadingIteratorItES4_RK18nsStringComparator + _Z15ToNewUTF8StringRK9nsAStringPj + _Z16CopyASCIItoUTF16PKcR9nsAString + _Z16CopyASCIItoUTF16RK10nsACStringR9nsAString + _Z16NS_NewByteBufferPP13nsIByteBufferP11nsISupportsj + _Z16StringBeginsWithRK10nsACStringS1_RK19nsCStringComparator + _Z16StringBeginsWithRK9nsAStringS1_RK18nsStringComparator + _Z16UTF8ToNewUnicodeRK10nsACStringPj + _Z17AppendUTF16toUTF8PKtR10nsACString + _Z17AppendUTF16toUTF8RK9nsAStringR10nsACString + _Z17AppendUTF8toUTF16PKcR9nsAString + _Z17AppendUTF8toUTF16RK10nsACStringR9nsAString + _Z18AppendASCIItoUTF16PKcR9nsAString + _Z18AppendASCIItoUTF16RK10nsACStringR9nsAString + _Z18FindCharInReadablecR17nsReadingIteratorIcERKS0_ + _Z18FindCharInReadabletR17nsReadingIteratorItERKS0_ + _Z19CountCharInReadableRK10nsACStringc + _Z19CountCharInReadableRK9nsAStringt + _Z19NS_GetNumberOfAtomsv + _Z19NS_GetWeakReferenceP11nsISupportsPj + _Z19NS_NewGenericModulePKcjP21nsModuleComponentInfoPFvP9nsIModuleEPS4_ + _Z19NS_NewPermanentAtomPKc + _Z19NS_NewPermanentAtomPKt + _Z19NS_NewPermanentAtomRK10nsACString + _Z19NS_NewPermanentAtomRK9nsAString + _Z19NS_NewStorageStreamjjPP16nsIStorageStream + _Z19NS_NewUnicharBufferPP16nsIUnicharBufferP11nsISupportsj + _Z19TestSegmentedBufferv + _Z20NS_GetProxyForObjectP13nsIEventQueueRK4nsIDP11nsISupportsiPPv + _Z20NS_NewGenericFactoryPP17nsIGenericFactoryPK21nsModuleComponentInfo + _Z20NS_NewGenericModule2P12nsModuleInfoPP9nsIModule + _Z20NS_NewISupportsArrayPP16nsISupportsArray + _Z21LossyCopyUTF16toASCIIPKtR10nsACString + _Z21LossyCopyUTF16toASCIIRK9nsAStringR10nsACString + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorP16nsISupportsArray + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorP8nsIArray + _Z21NS_NewArrayEnumeratorPP19nsISimpleEnumeratorRK15nsCOMArray_base + _Z22NS_CopyNativeToUnicodeRK10nsACStringR9nsAString + _Z22NS_CopyUnicodeToNativeRK9nsAStringR10nsACString + _Z22NS_RegisterStaticAtomsPK12nsStaticAtomj + _Z22PL_DHashStubEnumRemoveP12PLDHashTableP15PLDHashEntryHdrjPv + _Z23LossyAppendUTF16toASCIIPKtR10nsACString + _Z23LossyAppendUTF16toASCIIRK9nsAStringR10nsACString + _Z23NS_AddFastLoadChecksumsjjj + _Z23NS_ErrorAccordingToNSPRv + _Z24NS_NewFastLoadFileReaderPP20nsIObjectInputStreamP14nsIInputStream + _Z24NS_NewFastLoadFileWriterPP21nsIObjectOutputStreamP15nsIOutputStreamP17nsIFastLoadFileIO + _Z25NS_NewFastLoadFileUpdaterPP21nsIObjectOutputStreamP15nsIOutputStreamP20nsIObjectInputStream + _Z25NS_NewUTF8ConverterStreamPP21nsIUnicharInputStreamP14nsIInputStreami + _Z27NS_NewInputStreamReadyEventPP22nsIInputStreamCallbackS0_P14nsIEventTarget + _Z28NS_GetGlobalComponentManagerPP19nsIComponentManager + _Z28NS_NewOutputStreamReadyEventPP23nsIOutputStreamCallbackS0_P14nsIEventTarget + _Z29CaseInsensitiveFindInReadableRK10nsACStringR17nsReadingIteratorIcES4_ + _Z29NS_AccumulateFastLoadChecksumPjPKhji + _Z29NS_CreateServicesFromCategoryPKcP11nsISupportsS0_ + _Z29StartupSpecialSystemDirectoryv + _Z30NS_NewISupportsArrayEnumeratorP16nsISupportsArrayPP26nsIBidirectionalEnumerator + _Z30NS_NewStringUnicharInputStreamPP21nsIUnicharInputStreamP8nsString + _Z30ShutdownSpecialSystemDirectoryv + _Z6IsUTF8RK10nsACString + _Z7CompareRK10nsACStringS1_RK19nsCStringComparator + _Z7CompareRK9nsAStringS1_RK18nsStringComparator + _Z7IsASCIIRK10nsACString + _Z7IsASCIIRK9nsAString + _ZN10nsACString11AppendASCIIEPKc + _ZN10nsACString11AppendASCIIEPKcj + _ZN10nsACString11AssignASCIIEPKc + _ZN10nsACString11AssignASCIIEPKcj + _ZN10nsACString11SetCapacityEj + _ZN10nsACString17GetWritableBufferEPPc + _ZN10nsACString3CutEjj + _ZN10nsACString6AppendEPKc + _ZN10nsACString6AppendEPKcj + _ZN10nsACString6AppendERK17nsCSubstringTuple + _ZN10nsACString6AppendERKS_ + _ZN10nsACString6AppendEc + _ZN10nsACString6AssignEPKc + _ZN10nsACString6AssignEPKcj + _ZN10nsACString6AssignERK17nsCSubstringTuple + _ZN10nsACString6AssignERKS_ + _ZN10nsACString6AssignEc + _ZN10nsACString6InsertEPKcj + _ZN10nsACString6InsertEPKcjj + _ZN10nsACString6InsertERK17nsCSubstringTuplej + _ZN10nsACString6InsertERKS_j + _ZN10nsACString6InsertEcj + _ZN10nsACString7ReplaceEjjRK17nsCSubstringTuple + _ZN10nsACString7ReplaceEjjRKS_ + _ZN10nsACString9SetIsVoidEi + _ZN10nsACString9SetLengthEj + _ZN10nsACStringD1Ev + _ZN10nsACStringD2Ev + _ZN11nsHashtable3GetEP9nsHashKey + _ZN11nsHashtable3PutEP9nsHashKeyPv + _ZN11nsHashtable5CloneEv + _ZN11nsHashtable5ResetEPFiP9nsHashKeyPvS2_ES2_ + _ZN11nsHashtable5ResetEv + _ZN11nsHashtable6ExistsEP9nsHashKey + _ZN11nsHashtable6RemoveEP9nsHashKey + _ZN11nsHashtable9EnumerateEPFiP9nsHashKeyPvS2_ES2_ + _ZN11nsHashtableC1EP20nsIObjectInputStreamPFjS1_PP9nsHashKeyPPvEPFvS1_S3_S5_EPj + _ZN11nsHashtableC1Eji + _ZN11nsHashtableC2EP20nsIObjectInputStreamPFjS1_PP9nsHashKeyPPvEPFvS1_S3_S5_EPj + _ZN11nsHashtableC2Eji + _ZN11nsHashtableD0Ev + _ZN11nsHashtableD1Ev + _ZN11nsHashtableD2Ev + _ZN11nsIDHashKey7HashKeyEPK4nsID + _ZN11nsLocalFile10GlobalInitEv + _ZN11nsLocalFile13FillStatCacheEv + _ZN11nsLocalFile14GlobalShutdownEv + _ZN11nsLocalFile15CopyDirectoryToEP7nsIFile + _ZN11nsLocalFile17CreateAndKeepOpenEjijPP10PRFileDesc + _ZN11nsLocalFile18CreateAllAncestorsEj + _ZN11nsLocalFile20LocateNativeLeafNameER17nsReadingIteratorIcES2_ + _ZN11nsLocalFile22nsLocalFileConstructorEP11nsISupportsRK4nsIDPPv + _ZN11nsLocalFile23GetNativeTargetPathNameEP7nsIFileRK10nsACStringRS2_ + _ZN11nsLocalFileC1ERKS_ + _ZN11nsLocalFileC1Ev + _ZN11nsLocalFileC2ERKS_ + _ZN11nsLocalFileC2Ev + _ZN11nsStringKeyC1EP20nsIObjectInputStreamPj + _ZN11nsStringKeyC1EPKtiNS_9OwnershipE + _ZN11nsStringKeyC1ERK8nsString + _ZN11nsStringKeyC1ERK9nsAString + _ZN11nsStringKeyC1ERKS_ + _ZN11nsStringKeyC2EP20nsIObjectInputStreamPj + _ZN11nsStringKeyC2EPKtiNS_9OwnershipE + _ZN11nsStringKeyC2ERK8nsString + _ZN11nsStringKeyC2ERK9nsAString + _ZN11nsStringKeyC2ERKS_ + _ZN11nsStringKeyD0Ev + _ZN11nsStringKeyD1Ev + _ZN11nsStringKeyD2Ev + _ZN11nsSubstring11AssignASCIIEPKc + _ZN11nsSubstring11AssignASCIIEPKcj + _ZN11nsSubstring11SetCapacityEj + _ZN11nsSubstring12ReplaceASCIIEjjPKcj + _ZN11nsSubstring13EnsureMutableEv + _ZN11nsSubstring5AdoptEPtj + _ZN11nsSubstring6AssignEPKtj + _ZN11nsSubstring6AssignERK16nsSubstringTuple + _ZN11nsSubstring6AssignERK9nsAString + _ZN11nsSubstring6AssignERKS_ + _ZN11nsSubstring7ReplaceEjjPKtj + _ZN11nsSubstring7ReplaceEjjRK16nsSubstringTuple + _ZN11nsSubstring7ReplaceEjjRK9nsAString + _ZN11nsSubstring9SetIsVoidEi + _ZN11nsSubstring9SetLengthEj + _ZN11nsVoidArray11GrowArrayByEi + _ZN11nsVoidArray11MoveElementEii + _ZN11nsVoidArray13RemoveElementEPv + _ZN11nsVoidArray15InsertElementAtEPvi + _ZN11nsVoidArray16InsertElementsAtERKS_i + _ZN11nsVoidArray16RemoveElementsAtEii + _ZN11nsVoidArray16ReplaceElementAtEPvi + _ZN11nsVoidArray17EnumerateForwardsEPFiPvS0_ES0_ + _ZN11nsVoidArray18EnumerateBackwardsEPFiPvS0_ES0_ + _ZN11nsVoidArray4SortEPFiPKvS1_PvES2_ + _ZN11nsVoidArray5ClearEv + _ZN11nsVoidArray6SizeToEi + _ZN11nsVoidArray7CompactEv + _ZN11nsVoidArrayC1Ei + _ZN11nsVoidArrayC1Ev + _ZN11nsVoidArrayC2Ei + _ZN11nsVoidArrayC2Ev + _ZN11nsVoidArrayD0Ev + _ZN11nsVoidArrayD1Ev + _ZN11nsVoidArrayD2Ev + _ZN11nsVoidArrayaSERKS_ + _ZN12nsCStringKeyC1EP20nsIObjectInputStreamPj + _ZN12nsCStringKeyC1EPKciNS_9OwnershipE + _ZN12nsCStringKeyC1ERK10nsACString + _ZN12nsCStringKeyC1ERK9nsCString + _ZN12nsCStringKeyC1ERKS_ + _ZN12nsCStringKeyC2EP20nsIObjectInputStreamPj + _ZN12nsCStringKeyC2EPKciNS_9OwnershipE + _ZN12nsCStringKeyC2ERK10nsACString + _ZN12nsCStringKeyC2ERK9nsCString + _ZN12nsCStringKeyC2ERKS_ + _ZN12nsCStringKeyD0Ev + _ZN12nsCStringKeyD1Ev + _ZN12nsCStringKeyD2Ev + _ZN12nsCSubstring11AssignASCIIEPKc + _ZN12nsCSubstring11AssignASCIIEPKcj + _ZN12nsCSubstring11SetCapacityEj + _ZN12nsCSubstring12ReplaceASCIIEjjPKcj + _ZN12nsCSubstring13EnsureMutableEv + _ZN12nsCSubstring5AdoptEPcj + _ZN12nsCSubstring6AssignEPKcj + _ZN12nsCSubstring6AssignERK10nsACString + _ZN12nsCSubstring6AssignERK17nsCSubstringTuple + _ZN12nsCSubstring6AssignERKS_ + _ZN12nsCSubstring7ReplaceEjjPKcj + _ZN12nsCSubstring7ReplaceEjjRK10nsACString + _ZN12nsCSubstring7ReplaceEjjRK17nsCSubstringTuple + _ZN12nsCSubstring9SetIsVoidEi + _ZN12nsCSubstring9SetLengthEj + _ZN13nsAutoMonitor10NewMonitorEPKc + _ZN13nsAutoMonitor14DestroyMonitorEP9PRMonitor + _ZN13nsAutoMonitor4ExitEv + _ZN13nsAutoMonitor5EnterEv + _ZN13nsCOMPtr_base14assign_from_qiE16nsQueryInterfaceRK4nsID + _ZN13nsCOMPtr_base16begin_assignmentEv + _ZN13nsCOMPtr_base18assign_from_helperERK15nsCOMPtr_helperRK4nsID + _ZN13nsCOMPtr_base18assign_with_AddRefEP11nsISupports + _ZN13nsCOMPtr_base25assign_from_qi_with_errorERK25nsQueryInterfaceWithErrorRK4nsID + _ZN13nsCOMPtr_baseD1Ev + _ZN13nsCOMPtr_baseD2Ev + _ZN13nsStringArray12RemoveStringERK9nsAString + _ZN13nsStringArray14InsertStringAtERK9nsAStringi + _ZN13nsStringArray14RemoveStringAtEi + _ZN13nsStringArray15ReplaceStringAtERK9nsAStringi + _ZN13nsStringArray17EnumerateForwardsEPFiR8nsStringPvES2_ + _ZN13nsStringArray18EnumerateBackwardsEPFiR8nsStringPvES2_ + _ZN13nsStringArray4SortEPFiPK8nsStringS2_PvES3_ + _ZN13nsStringArray4SortEv + _ZN13nsStringArray5ClearEv + _ZN13nsStringArrayC1Ei + _ZN13nsStringArrayC1Ev + _ZN13nsStringArrayC2Ei + _ZN13nsStringArrayC2Ev + _ZN13nsStringArrayD0Ev + _ZN13nsStringArrayD1Ev + _ZN13nsStringArrayD2Ev + _ZN13nsStringArrayaSERKS_ + _ZN13nsTraceRefcnt10LogReleaseEPvjPKc + _ZN13nsTraceRefcnt12LogAddCOMPtrEPvP11nsISupports + _ZN13nsTraceRefcnt16LogReleaseCOMPtrEPvP11nsISupports + _ZN13nsTraceRefcnt7LogCtorEPvPKcj + _ZN13nsTraceRefcnt7LogDtorEPvPKcj + _ZN13nsTraceRefcnt9LogAddRefEPvjPKcj + _ZN14nsAutoCMonitor4ExitEv + _ZN14nsAutoCMonitor5EnterEv + _ZN14nsAutoLockBase4HideEv + _ZN14nsAutoLockBase4ShowEv + _ZN14nsAutoLockBaseC1EPvNS_14nsAutoLockTypeE + _ZN14nsAutoLockBaseC2EPvNS_14nsAutoLockTypeE + _ZN14nsAutoLockBaseD1Ev + _ZN14nsAutoLockBaseD2Ev + _ZN14nsCStringArray11ParseStringEPKcS1_ + _ZN14nsCStringArray13RemoveCStringERK10nsACString + _ZN14nsCStringArray14SortIgnoreCaseEv + _ZN14nsCStringArray15InsertCStringAtERK10nsACStringi + _ZN14nsCStringArray15RemoveCStringAtEi + _ZN14nsCStringArray16ReplaceCStringAtERK10nsACStringi + _ZN14nsCStringArray17EnumerateForwardsEPFiR9nsCStringPvES2_ + _ZN14nsCStringArray18EnumerateBackwardsEPFiR9nsCStringPvES2_ + _ZN14nsCStringArray23RemoveCStringIgnoreCaseERK10nsACString + _ZN14nsCStringArray4SortEPFiPK9nsCStringS2_PvES3_ + _ZN14nsCStringArray4SortEv + _ZN14nsCStringArray5ClearEv + _ZN14nsCStringArrayC1Ei + _ZN14nsCStringArrayC1Ev + _ZN14nsCStringArrayC2Ei + _ZN14nsCStringArrayC2Ev + _ZN14nsCStringArrayD0Ev + _ZN14nsCStringArrayD1Ev + _ZN14nsCStringArrayD2Ev + _ZN14nsCStringArrayaSERKS_ + _ZN14nsISupportsKeyC1EP20nsIObjectInputStreamPj + _ZN14nsISupportsKeyC2EP20nsIObjectInputStreamPj + _ZN14nsXPTCStubBase14QueryInterfaceERK4nsIDPPv + _ZN14nsXPTCStubBase5Stub3Ev + _ZN14nsXPTCStubBase5Stub4Ev + _ZN14nsXPTCStubBase5Stub5Ev + _ZN14nsXPTCStubBase5Stub6Ev + _ZN14nsXPTCStubBase5Stub7Ev + _ZN14nsXPTCStubBase5Stub8Ev + _ZN14nsXPTCStubBase5Stub9Ev + _ZN14nsXPTCStubBase6Stub10Ev + _ZN14nsXPTCStubBase6Stub11Ev + _ZN14nsXPTCStubBase6Stub12Ev + _ZN14nsXPTCStubBase6Stub13Ev + _ZN14nsXPTCStubBase6Stub14Ev + _ZN14nsXPTCStubBase6Stub15Ev + _ZN14nsXPTCStubBase6Stub16Ev + _ZN14nsXPTCStubBase6Stub17Ev + _ZN14nsXPTCStubBase6Stub18Ev + _ZN14nsXPTCStubBase6Stub19Ev + _ZN14nsXPTCStubBase6Stub20Ev + _ZN14nsXPTCStubBase6Stub21Ev + _ZN14nsXPTCStubBase6Stub22Ev + _ZN14nsXPTCStubBase6Stub23Ev + _ZN14nsXPTCStubBase6Stub24Ev + _ZN14nsXPTCStubBase6Stub25Ev + _ZN14nsXPTCStubBase6Stub26Ev + _ZN14nsXPTCStubBase6Stub27Ev + _ZN14nsXPTCStubBase6Stub28Ev + _ZN14nsXPTCStubBase6Stub29Ev + _ZN14nsXPTCStubBase6Stub30Ev + _ZN14nsXPTCStubBase6Stub31Ev + _ZN14nsXPTCStubBase6Stub32Ev + _ZN14nsXPTCStubBase6Stub33Ev + _ZN14nsXPTCStubBase6Stub34Ev + _ZN14nsXPTCStubBase6Stub35Ev + _ZN14nsXPTCStubBase6Stub36Ev + _ZN14nsXPTCStubBase6Stub37Ev + _ZN14nsXPTCStubBase6Stub38Ev + _ZN14nsXPTCStubBase6Stub39Ev + _ZN14nsXPTCStubBase6Stub40Ev + _ZN14nsXPTCStubBase6Stub41Ev + _ZN14nsXPTCStubBase6Stub42Ev + _ZN14nsXPTCStubBase6Stub43Ev + _ZN14nsXPTCStubBase6Stub44Ev + _ZN14nsXPTCStubBase6Stub45Ev + _ZN14nsXPTCStubBase6Stub46Ev + _ZN14nsXPTCStubBase6Stub47Ev + _ZN14nsXPTCStubBase6Stub48Ev + _ZN14nsXPTCStubBase6Stub49Ev + _ZN14nsXPTCStubBase6Stub50Ev + _ZN14nsXPTCStubBase6Stub51Ev + _ZN14nsXPTCStubBase6Stub52Ev + _ZN14nsXPTCStubBase6Stub53Ev + _ZN14nsXPTCStubBase6Stub54Ev + _ZN14nsXPTCStubBase6Stub55Ev + _ZN14nsXPTCStubBase6Stub56Ev + _ZN14nsXPTCStubBase6Stub57Ev + _ZN14nsXPTCStubBase6Stub58Ev + _ZN14nsXPTCStubBase6Stub59Ev + _ZN14nsXPTCStubBase6Stub60Ev + _ZN14nsXPTCStubBase6Stub61Ev + _ZN14nsXPTCStubBase6Stub62Ev + _ZN14nsXPTCStubBase6Stub63Ev + _ZN14nsXPTCStubBase6Stub64Ev + _ZN14nsXPTCStubBase6Stub65Ev + _ZN14nsXPTCStubBase6Stub66Ev + _ZN14nsXPTCStubBase6Stub67Ev + _ZN14nsXPTCStubBase6Stub68Ev + _ZN14nsXPTCStubBase6Stub69Ev + _ZN14nsXPTCStubBase6Stub70Ev + _ZN14nsXPTCStubBase6Stub71Ev + _ZN14nsXPTCStubBase6Stub72Ev + _ZN14nsXPTCStubBase6Stub73Ev + _ZN14nsXPTCStubBase6Stub74Ev + _ZN14nsXPTCStubBase6Stub75Ev + _ZN14nsXPTCStubBase6Stub76Ev + _ZN14nsXPTCStubBase6Stub77Ev + _ZN14nsXPTCStubBase6Stub78Ev + _ZN14nsXPTCStubBase6Stub79Ev + _ZN14nsXPTCStubBase6Stub80Ev + _ZN14nsXPTCStubBase6Stub81Ev + _ZN14nsXPTCStubBase6Stub82Ev + _ZN14nsXPTCStubBase6Stub83Ev + _ZN14nsXPTCStubBase6Stub84Ev + _ZN14nsXPTCStubBase6Stub85Ev + _ZN14nsXPTCStubBase6Stub86Ev + _ZN14nsXPTCStubBase6Stub87Ev + _ZN14nsXPTCStubBase6Stub88Ev + _ZN14nsXPTCStubBase6Stub89Ev + _ZN14nsXPTCStubBase6Stub90Ev + _ZN14nsXPTCStubBase6Stub91Ev + _ZN14nsXPTCStubBase6Stub92Ev + _ZN14nsXPTCStubBase6Stub93Ev + _ZN14nsXPTCStubBase6Stub94Ev + _ZN14nsXPTCStubBase6Stub95Ev + _ZN14nsXPTCStubBase6Stub96Ev + _ZN14nsXPTCStubBase6Stub97Ev + _ZN14nsXPTCStubBase6Stub98Ev + _ZN14nsXPTCStubBase6Stub99Ev + _ZN14nsXPTCStubBase7Stub100Ev + _ZN14nsXPTCStubBase7Stub101Ev + _ZN14nsXPTCStubBase7Stub102Ev + _ZN14nsXPTCStubBase7Stub103Ev + _ZN14nsXPTCStubBase7Stub104Ev + _ZN14nsXPTCStubBase7Stub105Ev + _ZN14nsXPTCStubBase7Stub106Ev + _ZN14nsXPTCStubBase7Stub107Ev + _ZN14nsXPTCStubBase7Stub108Ev + _ZN14nsXPTCStubBase7Stub109Ev + _ZN14nsXPTCStubBase7Stub110Ev + _ZN14nsXPTCStubBase7Stub111Ev + _ZN14nsXPTCStubBase7Stub112Ev + _ZN14nsXPTCStubBase7Stub113Ev + _ZN14nsXPTCStubBase7Stub114Ev + _ZN14nsXPTCStubBase7Stub115Ev + _ZN14nsXPTCStubBase7Stub116Ev + _ZN14nsXPTCStubBase7Stub117Ev + _ZN14nsXPTCStubBase7Stub118Ev + _ZN14nsXPTCStubBase7Stub119Ev + _ZN14nsXPTCStubBase7Stub120Ev + _ZN14nsXPTCStubBase7Stub121Ev + _ZN14nsXPTCStubBase7Stub122Ev + _ZN14nsXPTCStubBase7Stub123Ev + _ZN14nsXPTCStubBase7Stub124Ev + _ZN14nsXPTCStubBase7Stub125Ev + _ZN14nsXPTCStubBase7Stub126Ev + _ZN14nsXPTCStubBase7Stub127Ev + _ZN14nsXPTCStubBase7Stub128Ev + _ZN14nsXPTCStubBase7Stub129Ev + _ZN14nsXPTCStubBase7Stub130Ev + _ZN14nsXPTCStubBase7Stub131Ev + _ZN14nsXPTCStubBase7Stub132Ev + _ZN14nsXPTCStubBase7Stub133Ev + _ZN14nsXPTCStubBase7Stub134Ev + _ZN14nsXPTCStubBase7Stub135Ev + _ZN14nsXPTCStubBase7Stub136Ev + _ZN14nsXPTCStubBase7Stub137Ev + _ZN14nsXPTCStubBase7Stub138Ev + _ZN14nsXPTCStubBase7Stub139Ev + _ZN14nsXPTCStubBase7Stub140Ev + _ZN14nsXPTCStubBase7Stub141Ev + _ZN14nsXPTCStubBase7Stub142Ev + _ZN14nsXPTCStubBase7Stub143Ev + _ZN14nsXPTCStubBase7Stub144Ev + _ZN14nsXPTCStubBase7Stub145Ev + _ZN14nsXPTCStubBase7Stub146Ev + _ZN14nsXPTCStubBase7Stub147Ev + _ZN14nsXPTCStubBase7Stub148Ev + _ZN14nsXPTCStubBase7Stub149Ev + _ZN14nsXPTCStubBase7Stub150Ev + _ZN14nsXPTCStubBase7Stub151Ev + _ZN14nsXPTCStubBase7Stub152Ev + _ZN14nsXPTCStubBase7Stub153Ev + _ZN14nsXPTCStubBase7Stub154Ev + _ZN14nsXPTCStubBase7Stub155Ev + _ZN14nsXPTCStubBase7Stub156Ev + _ZN14nsXPTCStubBase7Stub157Ev + _ZN14nsXPTCStubBase7Stub158Ev + _ZN14nsXPTCStubBase7Stub159Ev + _ZN14nsXPTCStubBase7Stub160Ev + _ZN14nsXPTCStubBase7Stub161Ev + _ZN14nsXPTCStubBase7Stub162Ev + _ZN14nsXPTCStubBase7Stub163Ev + _ZN14nsXPTCStubBase7Stub164Ev + _ZN14nsXPTCStubBase7Stub165Ev + _ZN14nsXPTCStubBase7Stub166Ev + _ZN14nsXPTCStubBase7Stub167Ev + _ZN14nsXPTCStubBase7Stub168Ev + _ZN14nsXPTCStubBase7Stub169Ev + _ZN14nsXPTCStubBase7Stub170Ev + _ZN14nsXPTCStubBase7Stub171Ev + _ZN14nsXPTCStubBase7Stub172Ev + _ZN14nsXPTCStubBase7Stub173Ev + _ZN14nsXPTCStubBase7Stub174Ev + _ZN14nsXPTCStubBase7Stub175Ev + _ZN14nsXPTCStubBase7Stub176Ev + _ZN14nsXPTCStubBase7Stub177Ev + _ZN14nsXPTCStubBase7Stub178Ev + _ZN14nsXPTCStubBase7Stub179Ev + _ZN14nsXPTCStubBase7Stub180Ev + _ZN14nsXPTCStubBase7Stub181Ev + _ZN14nsXPTCStubBase7Stub182Ev + _ZN14nsXPTCStubBase7Stub183Ev + _ZN14nsXPTCStubBase7Stub184Ev + _ZN14nsXPTCStubBase7Stub185Ev + _ZN14nsXPTCStubBase7Stub186Ev + _ZN14nsXPTCStubBase7Stub187Ev + _ZN14nsXPTCStubBase7Stub188Ev + _ZN14nsXPTCStubBase7Stub189Ev + _ZN14nsXPTCStubBase7Stub190Ev + _ZN14nsXPTCStubBase7Stub191Ev + _ZN14nsXPTCStubBase7Stub192Ev + _ZN14nsXPTCStubBase7Stub193Ev + _ZN14nsXPTCStubBase7Stub194Ev + _ZN14nsXPTCStubBase7Stub195Ev + _ZN14nsXPTCStubBase7Stub196Ev + _ZN14nsXPTCStubBase7Stub197Ev + _ZN14nsXPTCStubBase7Stub198Ev + _ZN14nsXPTCStubBase7Stub199Ev + _ZN14nsXPTCStubBase7Stub200Ev + _ZN14nsXPTCStubBase7Stub201Ev + _ZN14nsXPTCStubBase7Stub202Ev + _ZN14nsXPTCStubBase7Stub203Ev + _ZN14nsXPTCStubBase7Stub204Ev + _ZN14nsXPTCStubBase7Stub205Ev + _ZN14nsXPTCStubBase7Stub206Ev + _ZN14nsXPTCStubBase7Stub207Ev + _ZN14nsXPTCStubBase7Stub208Ev + _ZN14nsXPTCStubBase7Stub209Ev + _ZN14nsXPTCStubBase7Stub210Ev + _ZN14nsXPTCStubBase7Stub211Ev + _ZN14nsXPTCStubBase7Stub212Ev + _ZN14nsXPTCStubBase7Stub213Ev + _ZN14nsXPTCStubBase7Stub214Ev + _ZN14nsXPTCStubBase7Stub215Ev + _ZN14nsXPTCStubBase7Stub216Ev + _ZN14nsXPTCStubBase7Stub217Ev + _ZN14nsXPTCStubBase7Stub218Ev + _ZN14nsXPTCStubBase7Stub219Ev + _ZN14nsXPTCStubBase7Stub220Ev + _ZN14nsXPTCStubBase7Stub221Ev + _ZN14nsXPTCStubBase7Stub222Ev + _ZN14nsXPTCStubBase7Stub223Ev + _ZN14nsXPTCStubBase7Stub224Ev + _ZN14nsXPTCStubBase7Stub225Ev + _ZN14nsXPTCStubBase7Stub226Ev + _ZN14nsXPTCStubBase7Stub227Ev + _ZN14nsXPTCStubBase7Stub228Ev + _ZN14nsXPTCStubBase7Stub229Ev + _ZN14nsXPTCStubBase7Stub230Ev + _ZN14nsXPTCStubBase7Stub231Ev + _ZN14nsXPTCStubBase7Stub232Ev + _ZN14nsXPTCStubBase7Stub233Ev + _ZN14nsXPTCStubBase7Stub234Ev + _ZN14nsXPTCStubBase7Stub235Ev + _ZN14nsXPTCStubBase7Stub236Ev + _ZN14nsXPTCStubBase7Stub237Ev + _ZN14nsXPTCStubBase7Stub238Ev + _ZN14nsXPTCStubBase7Stub239Ev + _ZN14nsXPTCStubBase7Stub240Ev + _ZN14nsXPTCStubBase7Stub241Ev + _ZN14nsXPTCStubBase7Stub242Ev + _ZN14nsXPTCStubBase7Stub243Ev + _ZN14nsXPTCStubBase7Stub244Ev + _ZN14nsXPTCStubBase7Stub245Ev + _ZN14nsXPTCStubBase7Stub246Ev + _ZN14nsXPTCStubBase7Stub247Ev + _ZN14nsXPTCStubBase7Stub248Ev + _ZN14nsXPTCStubBase7Stub249Ev + _ZN14nsXPTCStubBase9Sentinel0Ev + _ZN14nsXPTCStubBase9Sentinel1Ev + _ZN14nsXPTCStubBase9Sentinel2Ev + _ZN14nsXPTCStubBase9Sentinel3Ev + _ZN14nsXPTCStubBase9Sentinel4Ev + _ZN15nsAutoVoidArray5ClearEv + _ZN15nsAutoVoidArray6SizeToEi + _ZN15nsAutoVoidArray7CompactEv + _ZN15nsAutoVoidArrayC1Ev + _ZN15nsAutoVoidArrayC2Ev + _ZN15nsCOMArray_base12RemoveObjectEP11nsISupports + _ZN15nsCOMArray_base14InsertObjectAtEP11nsISupportsi + _ZN15nsCOMArray_base14RemoveObjectAtEi + _ZN15nsCOMArray_base15InsertObjectsAtERKS_i + _ZN15nsCOMArray_base15ReplaceObjectAtEP11nsISupportsi + _ZN15nsCOMArray_base5ClearEv + _ZN15nsCOMArray_baseC1ERKS_ + _ZN15nsCOMArray_baseC2ERKS_ + _ZN15nsCOMArray_baseD1Ev + _ZN15nsCOMArray_baseD2Ev + _ZN15nsPrintfCStringC1EPKcz + _ZN15nsPrintfCStringC1EjPKcz + _ZN15nsPrintfCStringC2EPKcz + _ZN15nsPrintfCStringC2EjPKcz + _ZN15nsSupportsArray11DeleteArrayEv + _ZN15nsSupportsArray11GrowArrayByEi + _ZN15nsSupportsArray11LastIndexOfEPK11nsISupports + _ZN15nsSupportsArray11MoveElementEii + _ZN15nsSupportsArray13RemoveElementEPK11nsISupportsj + _ZN15nsSupportsArray14QueryInterfaceERK4nsIDPPv + _ZN15nsSupportsArray15InsertElementAtEP11nsISupportsj + _ZN15nsSupportsArray16InsertElementsAtEP16nsISupportsArrayj + _ZN15nsSupportsArray16RemoveElementsAtEjj + _ZN15nsSupportsArray16ReplaceElementAtEP11nsISupportsj + _ZN15nsSupportsArray17EnumerateForwardsEPFiP11nsISupportsPvES2_ + _ZN15nsSupportsArray17IndexOfStartingAtEPK11nsISupportsj + _ZN15nsSupportsArray17RemoveLastElementEPK11nsISupports + _ZN15nsSupportsArray18EnumerateBackwardsEPFiP11nsISupportsPvES2_ + _ZN15nsSupportsArray4ReadEP20nsIObjectInputStream + _ZN15nsSupportsArray5ClearEv + _ZN15nsSupportsArray5CloneEPP16nsISupportsArray + _ZN15nsSupportsArray5WriteEP21nsIObjectOutputStream + _ZN15nsSupportsArray6AddRefEv + _ZN15nsSupportsArray6CreateEP11nsISupportsRK4nsIDPPv + _ZN15nsSupportsArray6EqualsEPK16nsISupportsArray + _ZN15nsSupportsArray6SizeToEi + _ZN15nsSupportsArray7CompactEv + _ZN15nsSupportsArray7IndexOfEPK11nsISupports + _ZN15nsSupportsArray7ReleaseEv + _ZN15nsSupportsArray9ElementAtEj + _ZN15nsSupportsArray9EnumerateEPP13nsIEnumerator + _ZN15nsSupportsArrayC1Ev + _ZN15nsSupportsArrayC2Ev + _ZN15nsSupportsArrayD1Ev + _ZN15nsSupportsArrayD2Ev + _ZN16nsServiceManager10GetServiceEPKcRK4nsIDPP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager10GetServiceERK4nsIDS2_PP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager14ReleaseServiceEPKcP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager14ReleaseServiceERK4nsIDP11nsISupportsP19nsIShutdownListener + _ZN16nsServiceManager15RegisterServiceEPKcP11nsISupports + _ZN16nsServiceManager15RegisterServiceERK4nsIDP11nsISupports + _ZN16nsServiceManager17UnregisterServiceEPKc + _ZN16nsServiceManager17UnregisterServiceERK4nsID + _ZN16nsServiceManager23GetGlobalServiceManagerEPP17nsIServiceManager + _ZN16nsServiceManager28ShutdownGlobalServiceManagerEPP17nsIServiceManager + _ZN16nsSmallVoidArray13AppendElementEPv + _ZN16nsSmallVoidArray13RemoveElementEPv + _ZN16nsSmallVoidArray14SetSingleChildEPv + _ZN16nsSmallVoidArray14SwitchToVectorEv + _ZN16nsSmallVoidArray15InsertElementAtEPvi + _ZN16nsSmallVoidArray15RemoveElementAtEi + _ZN16nsSmallVoidArray16InsertElementsAtERK11nsVoidArrayi + _ZN16nsSmallVoidArray16RemoveElementsAtEii + _ZN16nsSmallVoidArray16ReplaceElementAtEPvi + _ZN16nsSmallVoidArray17EnumerateForwardsEPFiPvS0_ES0_ + _ZN16nsSmallVoidArray18EnumerateBackwardsEPFiPvS0_ES0_ + _ZN16nsSmallVoidArray4SortEPFiPKvS1_PvES2_ + _ZN16nsSmallVoidArray5ClearEv + _ZN16nsSmallVoidArray6SizeToEi + _ZN16nsSmallVoidArray7CompactEv + _ZN16nsSmallVoidArrayC1Ev + _ZN16nsSmallVoidArrayC2Ev + _ZN16nsSmallVoidArrayD1Ev + _ZN16nsSmallVoidArrayD2Ev + _ZN16nsSmallVoidArrayaSERS_ + _ZN17nsArrayEnumeratorC1EP16nsISupportsArray + _ZN17nsArrayEnumeratorC2EP16nsISupportsArray + _ZN17nsArrayEnumeratorD1Ev + _ZN17nsArrayEnumeratorD2Ev + _ZN17nsObjectHashtable11CopyElementEP12PLDHashTableP15PLDHashEntryHdrjPv + _ZN17nsObjectHashtable15RemoveAndDeleteEP9nsHashKey + _ZN17nsObjectHashtable5CloneEv + _ZN17nsObjectHashtable5ResetEv + _ZN17nsObjectHashtableC1EPFPvP9nsHashKeyS0_S0_ES0_PFiS2_S0_S0_ES0_ji + _ZN17nsObjectHashtableC2EPFPvP9nsHashKeyS0_S0_ES0_PFiS2_S0_S0_ES0_ji + _ZN17nsObjectHashtableD0Ev + _ZN17nsObjectHashtableD1Ev + _ZN17nsObjectHashtableD2Ev + _ZN17nsSegmentedBuffer16AppendNewSegmentEv + _ZN17nsSegmentedBuffer4InitEjjP9nsIMemory + _ZN17nsSegmentedBuffer5EmptyEv + _ZN17nsTraceRefcntImpl12WalkTheStackEP7__sFILE + _ZN17nsTraceRefcntImpl14DemangleSymbolEPKcPci + _ZN17nsTraceRefcntImpl14DumpStatisticsENS_14StatisticsTypeEP7__sFILE + _ZN17nsTraceRefcntImpl15ResetStatisticsEv + _ZN17nsTraceRefcntImpl18LoadLibrarySymbolsEPKcPv + _ZN17nsTraceRefcntImpl18SetActivityIsLegalEi + _ZN17nsTraceRefcntImpl7StartupEv + _ZN17nsTraceRefcntImpl8ShutdownEv + _ZN17nsUnionEnumeratorC1EP19nsISimpleEnumeratorS1_ + _ZN17nsUnionEnumeratorC2EP19nsISimpleEnumeratorS1_ + _ZN17nsUnionEnumeratorD1Ev + _ZN17nsUnionEnumeratorD2Ev + _ZN18nsComponentManager10InitializeEv + _ZN18nsComponentManager11FindFactoryERK4nsIDPP10nsIFactory + _ZN18nsComponentManager12AutoRegisterEiP7nsIFile + _ZN18nsComponentManager12IsRegisteredERK4nsIDPi + _ZN18nsComponentManager13FreeLibrariesEv + _ZN18nsComponentManager14CreateInstanceEPKcP11nsISupportsRK4nsIDPPv + _ZN18nsComponentManager14CreateInstanceERK4nsIDP11nsISupportsS2_PPv + _ZN18nsComponentManager14GetClassObjectERK4nsIDS2_PPv + _ZN18nsComponentManager15EnumerateCLSIDsEPP13nsIEnumerator + _ZN18nsComponentManager15RegisterFactoryERK4nsIDPKcS4_P10nsIFactoryi + _ZN18nsComponentManager17CLSIDToContractIDEP4nsIDPPcS3_ + _ZN18nsComponentManager17RegisterComponentERK4nsIDPKcS4_S4_ii + _ZN18nsComponentManager17UnregisterFactoryERK4nsIDP10nsIFactory + _ZN18nsComponentManager19ContractIDToClassIDEPKcP4nsID + _ZN18nsComponentManager19UnregisterComponentERK4nsIDPKc + _ZN18nsComponentManager20EnumerateContractIDsEPP13nsIEnumerator + _ZN18nsComponentManager20RegisterComponentLibERK4nsIDPKcS4_S4_ii + _ZN18nsComponentManager21AutoRegisterComponentEiP7nsIFile + _ZN18nsComponentManager21RegisterComponentSpecERK4nsIDPKcS4_P7nsIFileii + _ZN18nsComponentManager23AutoUnregisterComponentEiP7nsIFile + _ZN18nsComponentManager23UnregisterComponentSpecERK4nsIDP7nsIFile + _ZN18nsVoidHashSetSuper4InitEj + _ZN18nsVoidHashSetSuper6RemoveEPKv + _ZN18nsVoidHashSetSuper8AddEntryEPKv + _ZN18nsVoidHashSetSuper8GetEntryEPKv + _ZN18nsVoidHashSetSuperC1Ev + _ZN18nsVoidHashSetSuperC2Ev + _ZN18nsVoidHashSetSuperD1Ev + _ZN18nsVoidHashSetSuperD2Ev + _ZN19nsDirEnumeratorUnixC1Ev + _ZN19nsDirEnumeratorUnixC2Ev + _ZN19nsDirEnumeratorUnixD1Ev + _ZN19nsDirEnumeratorUnixD2Ev + _ZN19nsInt32HashSetSuper4InitEj + _ZN19nsInt32HashSetSuper6RemoveEi + _ZN19nsInt32HashSetSuper8AddEntryEi + _ZN19nsInt32HashSetSuper8GetEntryEi + _ZN19nsInt32HashSetSuperC1Ev + _ZN19nsInt32HashSetSuperC2Ev + _ZN19nsInt32HashSetSuperD1Ev + _ZN19nsInt32HashSetSuperD2Ev + _ZN19nsPromiseFlatString4InitERK11nsSubstring + _ZN19nsPromiseFlatString4InitERK9nsAString + _ZN19nsSupportsHashtable13EnumerateCopyEP12PLDHashTableP15PLDHashEntryHdrjPv + _ZN19nsSupportsHashtable14ReleaseElementEP9nsHashKeyPvS2_ + _ZN19nsSupportsHashtable3GetEP9nsHashKey + _ZN19nsSupportsHashtable3PutEP9nsHashKeyP11nsISupportsPS3_ + _ZN19nsSupportsHashtable5CloneEv + _ZN19nsSupportsHashtable5ResetEv + _ZN19nsSupportsHashtable6RemoveEP9nsHashKeyPP11nsISupports + _ZN19nsSupportsHashtableD0Ev + _ZN19nsSupportsHashtableD1Ev + _ZN19nsSupportsHashtableD2Ev + _ZN20nsDependentSubstring6RebindERK11nsSubstringjj + _ZN20nsDependentSubstring6RebindERK9nsAStringjj + _ZN20nsPromiseFlatCString4InitERK10nsACString + _ZN20nsPromiseFlatCString4InitERK12nsCSubstring + _ZN20nsRecyclingAllocator13AddToFreeListEPNS_5BlockE + _ZN20nsRecyclingAllocator13FindFreeBlockEm + _ZN20nsRecyclingAllocator17FreeUnusedBucketsEv + _ZN20nsRecyclingAllocator22nsRecycleTimerCallbackEP8nsITimerPv + _ZN20nsRecyclingAllocator4FreeEPv + _ZN20nsRecyclingAllocator4InitEjjPKc + _ZN20nsRecyclingAllocator6MallocEmi + _ZN20nsRecyclingAllocatorC1EjjPKc + _ZN20nsRecyclingAllocatorC2EjjPKc + _ZN20nsRecyclingAllocatorD1Ev + _ZN20nsRecyclingAllocatorD2Ev + _ZN20nsStringHashSetSuper4InitEj + _ZN20nsStringHashSetSuper6RemoveERK9nsAString + _ZN20nsStringHashSetSuper8AddEntryERK9nsAString + _ZN20nsStringHashSetSuper8GetEntryERK9nsAString + _ZN20nsStringHashSetSuperC1Ev + _ZN20nsStringHashSetSuperC2Ev + _ZN20nsStringHashSetSuperD1Ev + _ZN20nsStringHashSetSuperD2Ev + _ZN21nsCStringHashSetSuper4InitEj + _ZN21nsCStringHashSetSuper6RemoveERK10nsACString + _ZN21nsCStringHashSetSuper8AddEntryERK10nsACString + _ZN21nsCStringHashSetSuper8GetEntryERK10nsACString + _ZN21nsCStringHashSetSuperC1Ev + _ZN21nsCStringHashSetSuperC2Ev + _ZN21nsCStringHashSetSuperD1Ev + _ZN21nsCStringHashSetSuperD2Ev + _ZN21nsDependentCSubstring6RebindERK10nsACStringjj + _ZN21nsDependentCSubstring6RebindERK12nsCSubstringjj + _ZN21nsSingletonEnumeratorC1EP11nsISupports + _ZN21nsSingletonEnumeratorC2EP11nsISupports + _ZN21nsSingletonEnumeratorD1Ev + _ZN21nsSingletonEnumeratorD2Ev + _ZN23nsSupportsWeakReference16GetWeakReferenceEPP16nsIWeakReference + _ZN4nsID5ParseEPKc + _ZN5nsCRT12IsAsciiAlphaEt + _ZN5nsCRT12IsAsciiDigitEt + _ZN5nsCRT12IsAsciiSpaceEt + _ZN5nsCRT14BufferHashCodeEPKcj + _ZN5nsCRT14BufferHashCodeEPKtj + _ZN5nsCRT14HashCodeAsUTF8EPKtPj + _ZN5nsCRT5atollEPKc + _ZN5nsCRT6strcmpEPKtS1_ + _ZN5nsCRT6strdupEPKt + _ZN5nsCRT6strlenEPKt + _ZN5nsCRT6strtokEPcPKcPS0_ + _ZN5nsCRT7IsAsciiEPKc + _ZN5nsCRT7IsAsciiEPKcj + _ZN5nsCRT7IsAsciiEPKt + _ZN5nsCRT7IsAsciiEt + _ZN5nsCRT7IsLowerEc + _ZN5nsCRT7IsUpperEc + _ZN5nsCRT7ToLowerEc + _ZN5nsCRT7ToUpperEc + _ZN5nsCRT7strncmpEPKtS1_j + _ZN5nsCRT7strndupEPKtj + _ZN5nsCRT8HashCodeEPKcPj + _ZN5nsCRT8HashCodeEPKtPj + _ZN7nsDebug5AbortEPKci + _ZN7nsDebug5BreakEPKci + _ZN7nsDebug7WarningEPKcS1_i + _ZN7nsDebug9AssertionEPKcS1_S1_i + _ZN7nsDeque12GrowCapacityEv + _ZN7nsDeque14SetDeallocatorEP14nsDequeFunctor + _ZN7nsDeque3PopEv + _ZN7nsDeque4PeekEv + _ZN7nsDeque4PushEPv + _ZN7nsDeque5EmptyEv + _ZN7nsDeque5EraseEv + _ZN7nsDeque8PopFrontEv + _ZN7nsDeque9PeekFrontEv + _ZN7nsDeque9PushFrontEPv + _ZN7nsDequeC1EP14nsDequeFunctor + _ZN7nsDequeC2EP14nsDequeFunctor + _ZN7nsDequeD1Ev + _ZN7nsDequeD2Ev + _ZN7nsIDKeyC1EP20nsIObjectInputStreamPj + _ZN7nsIDKeyC2EP20nsIObjectInputStreamPj + _ZN8nsMemory12HeapMinimizeEi + _ZN8nsMemory22GetGlobalMemoryServiceEv + _ZN8nsMemory4FreeEPv + _ZN8nsMemory5AllocEm + _ZN8nsMemory5CloneEPKvm + _ZN8nsMemory7ReallocEPvm + _ZN8nsString10StripCharsEPKc + _ZN8nsString11AppendFloatEd + _ZN8nsString11ReplaceCharEPKct + _ZN8nsString11ReplaceCharEtt + _ZN8nsString15StripWhitespaceEv + _ZN8nsString16ReplaceSubstringEPKtS1_ + _ZN8nsString16ReplaceSubstringERKS_S1_ + _ZN8nsString18CompressWhitespaceEii + _ZN8nsString20AppendWithConversionEPKci + _ZN8nsString20AppendWithConversionERK10nsACString + _ZN8nsString20AssignWithConversionEPKci + _ZN8nsString20AssignWithConversionERK10nsACString + _ZN8nsString4TrimEPKciii + _ZN8nsString9AppendIntEii + _ZN8nsString9AppendIntEli + _ZN8nsString9SetCharAtEtj + _ZN8nsString9StripCharEti + _ZN9nsAString11AppendASCIIEPKc + _ZN9nsAString11AppendASCIIEPKcj + _ZN9nsAString11AssignASCIIEPKc + _ZN9nsAString11AssignASCIIEPKcj + _ZN9nsAString11SetCapacityEj + _ZN9nsAString17GetWritableBufferEPPt + _ZN9nsAString3CutEjj + _ZN9nsAString6AppendEPKt + _ZN9nsAString6AppendEPKtj + _ZN9nsAString6AppendERK16nsSubstringTuple + _ZN9nsAString6AppendERKS_ + _ZN9nsAString6AppendEt + _ZN9nsAString6AssignEPKt + _ZN9nsAString6AssignEPKtj + _ZN9nsAString6AssignERK16nsSubstringTuple + _ZN9nsAString6AssignERKS_ + _ZN9nsAString6AssignEt + _ZN9nsAString6InsertEPKtj + _ZN9nsAString6InsertEPKtjj + _ZN9nsAString6InsertERK16nsSubstringTuplej + _ZN9nsAString6InsertERKS_j + _ZN9nsAString6InsertEtj + _ZN9nsAString7ReplaceEjjRK16nsSubstringTuple + _ZN9nsAString7ReplaceEjjRKS_ + _ZN9nsAString9SetIsVoidEi + _ZN9nsAString9SetLengthEj + _ZN9nsAStringD1Ev + _ZN9nsAStringD2Ev + _ZN9nsCString10StripCharsEPKc + _ZN9nsCString11AppendFloatEd + _ZN9nsCString11ReplaceCharEPKcc + _ZN9nsCString11ReplaceCharEcc + _ZN9nsCString15StripWhitespaceEv + _ZN9nsCString16ReplaceSubstringEPKcS1_ + _ZN9nsCString16ReplaceSubstringERKS_S1_ + _ZN9nsCString18CompressWhitespaceEii + _ZN9nsCString20AppendWithConversionEPKti + _ZN9nsCString20AppendWithConversionERK9nsAString + _ZN9nsCString20AssignWithConversionEPKti + _ZN9nsCString20AssignWithConversionERK9nsAString + _ZN9nsCString4TrimEPKciii + _ZN9nsCString9AppendIntEii + _ZN9nsCString9AppendIntEli + _ZN9nsCString9SetCharAtEtj + _ZN9nsCString9StripCharEci + _ZN9nsHashKeyD0Ev + _ZN9nsHashKeyD1Ev + _ZN9nsHashKeyD2Ev + _ZN9nsIThread10GetCurrentEPPS_ + _ZN9nsIThread10GetIThreadEP8PRThreadPPS_ + _ZN9nsIThread12IsMainThreadEv + _ZN9nsIThread13GetMainThreadEPPS_ + _ZN9nsIThread13SetMainThreadEv + _ZN9nsVariant10InitializeEP20nsDiscriminatedUnion + _ZN9nsVariant10SetToEmptyEP20nsDiscriminatedUnion + _ZN9nsVariant11ConvertToIDERK20nsDiscriminatedUnionP4nsID + _ZN9nsVariant11SetFromBoolEP20nsDiscriminatedUnioni + _ZN9nsVariant11SetFromCharEP20nsDiscriminatedUnionc + _ZN9nsVariant11SetFromInt8EP20nsDiscriminatedUnionh + _ZN9nsVariant12SetFromArrayEP20nsDiscriminatedUniontPK4nsIDjPv + _ZN9nsVariant12SetFromFloatEP20nsDiscriminatedUnionf + _ZN9nsVariant12SetFromInt16EP20nsDiscriminatedUnions + _ZN9nsVariant12SetFromInt32EP20nsDiscriminatedUnioni + _ZN9nsVariant12SetFromInt64EP20nsDiscriminatedUnionl + _ZN9nsVariant12SetFromUint8EP20nsDiscriminatedUnionh + _ZN9nsVariant12SetFromWCharEP20nsDiscriminatedUniont + _ZN9nsVariant13ConvertToBoolERK20nsDiscriminatedUnionPi + _ZN9nsVariant13ConvertToCharERK20nsDiscriminatedUnionPc + _ZN9nsVariant13ConvertToInt8ERK20nsDiscriminatedUnionPh + _ZN9nsVariant13SetFromDoubleEP20nsDiscriminatedUniond + _ZN9nsVariant13SetFromStringEP20nsDiscriminatedUnionPKc + _ZN9nsVariant13SetFromUint16EP20nsDiscriminatedUniont + _ZN9nsVariant13SetFromUint32EP20nsDiscriminatedUnionj + _ZN9nsVariant13SetFromUint64EP20nsDiscriminatedUnionm + _ZN9nsVariant14ConvertToArrayERK20nsDiscriminatedUnionPtP4nsIDPjPPv + _ZN9nsVariant14ConvertToFloatERK20nsDiscriminatedUnionPf + _ZN9nsVariant14ConvertToInt16ERK20nsDiscriminatedUnionPs + _ZN9nsVariant14ConvertToInt32ERK20nsDiscriminatedUnionPi + _ZN9nsVariant14ConvertToInt64ERK20nsDiscriminatedUnionPl + _ZN9nsVariant14ConvertToUint8ERK20nsDiscriminatedUnionPh + _ZN9nsVariant14ConvertToWCharERK20nsDiscriminatedUnionPt + _ZN9nsVariant14SetFromAStringEP20nsDiscriminatedUnionRK9nsAString + _ZN9nsVariant14SetFromVariantEP20nsDiscriminatedUnionP10nsIVariant + _ZN9nsVariant14SetFromWStringEP20nsDiscriminatedUnionPKt + _ZN9nsVariant15ConvertToDoubleERK20nsDiscriminatedUnionPd + _ZN9nsVariant15ConvertToStringERK20nsDiscriminatedUnionPPc + _ZN9nsVariant15ConvertToUint16ERK20nsDiscriminatedUnionPt + _ZN9nsVariant15ConvertToUint32ERK20nsDiscriminatedUnionPj + _ZN9nsVariant15ConvertToUint64ERK20nsDiscriminatedUnionPm + _ZN9nsVariant15SetFromACStringEP20nsDiscriminatedUnionRK10nsACString + _ZN9nsVariant15SetToEmptyArrayEP20nsDiscriminatedUnion + _ZN9nsVariant16ConvertToAStringERK20nsDiscriminatedUnionR9nsAString + _ZN9nsVariant16ConvertToWStringERK20nsDiscriminatedUnionPPt + _ZN9nsVariant16SetFromISupportsEP20nsDiscriminatedUnionP11nsISupports + _ZN9nsVariant16SetFromInterfaceEP20nsDiscriminatedUnionRK4nsIDP11nsISupports + _ZN9nsVariant17ConvertToACStringERK20nsDiscriminatedUnionR10nsACString + _ZN9nsVariant18ConvertToISupportsERK20nsDiscriminatedUnionPP11nsISupports + _ZN9nsVariant18ConvertToInterfaceERK20nsDiscriminatedUnionPP4nsIDPPv + _ZN9nsVariant18SetFromAUTF8StringEP20nsDiscriminatedUnionRK10nsACString + _ZN9nsVariant20ConvertToAUTF8StringERK20nsDiscriminatedUnionR10nsACString + _ZN9nsVariant21SetFromStringWithSizeEP20nsDiscriminatedUnionjPKc + _ZN9nsVariant22SetFromWStringWithSizeEP20nsDiscriminatedUnionjPKt + _ZN9nsVariant23ConvertToStringWithSizeERK20nsDiscriminatedUnionPjPPc + _ZN9nsVariant24ConvertToWStringWithSizeERK20nsDiscriminatedUnionPjPPt + _ZN9nsVariant7CleanupEP20nsDiscriminatedUnion + _ZN9nsVariant9SetFromIDEP20nsDiscriminatedUnionRK4nsID + _ZN9nsVariant9SetToVoidEP20nsDiscriminatedUnion + _ZN9nsVariantC1Ev + _ZN9nsVariantC2Ev + _ZN9nsVariantD1Ev + _ZN9nsVariantD2Ev + _ZNK10nsACString11EqualsASCIIEPKc + _ZNK10nsACString11EqualsASCIIEPKcj + _ZNK10nsACString12IsTerminatedEv + _ZNK10nsACString17GetReadableBufferEPPKc + _ZNK10nsACString20LowerCaseEqualsASCIIEPKc + _ZNK10nsACString20LowerCaseEqualsASCIIEPKcj + _ZNK10nsACString4LastEv + _ZNK10nsACString5FirstEv + _ZNK10nsACString6EqualsEPKc + _ZNK10nsACString6EqualsEPKcRK19nsCStringComparator + _ZNK10nsACString6EqualsERKS_ + _ZNK10nsACString6EqualsERKS_RK19nsCStringComparator + _ZNK10nsACString6IsVoidEv + _ZNK10nsACString6LengthEv + _ZNK10nsACString8FindCharEcj + _ZNK10nsACString9CountCharEc + _ZNK11nsHashtable5WriteEP21nsIObjectOutputStreamPFjS1_PvE + _ZNK11nsStringKey5CloneEv + _ZNK11nsStringKey5WriteEP21nsIObjectOutputStream + _ZNK11nsStringKey6EqualsEPK9nsHashKey + _ZNK11nsStringKey8HashCodeEv + _ZNK11nsSubstring11EqualsASCIIEPKc + _ZNK11nsSubstring11EqualsASCIIEPKcj + _ZNK11nsSubstring20LowerCaseEqualsASCIIEPKc + _ZNK11nsSubstring20LowerCaseEqualsASCIIEPKcj + _ZNK11nsSubstring6EqualsEPKt + _ZNK11nsSubstring6EqualsEPKtRK18nsStringComparator + _ZNK11nsSubstring6EqualsERK9nsAString + _ZNK11nsSubstring6EqualsERK9nsAStringRK18nsStringComparator + _ZNK11nsSubstring6EqualsERKS_ + _ZNK11nsSubstring6EqualsERKS_RK18nsStringComparator + _ZNK11nsSubstring8FindCharEtj + _ZNK11nsSubstring9CountCharEt + _ZNK11nsVoidArray7IndexOfEPv + _ZNK12nsCStringKey5CloneEv + _ZNK12nsCStringKey5WriteEP21nsIObjectOutputStream + _ZNK12nsCStringKey6EqualsEPK9nsHashKey + _ZNK12nsCStringKey8HashCodeEv + _ZNK12nsCSubstring11EqualsASCIIEPKc + _ZNK12nsCSubstring11EqualsASCIIEPKcj + _ZNK12nsCSubstring20LowerCaseEqualsASCIIEPKc + _ZNK12nsCSubstring20LowerCaseEqualsASCIIEPKcj + _ZNK12nsCSubstring6EqualsEPKc + _ZNK12nsCSubstring6EqualsEPKcRK19nsCStringComparator + _ZNK12nsCSubstring6EqualsERK10nsACString + _ZNK12nsCSubstring6EqualsERK10nsACStringRK19nsCStringComparator + _ZNK12nsCSubstring6EqualsERKS_ + _ZNK12nsCSubstring6EqualsERKS_RK19nsCStringComparator + _ZNK12nsCSubstring8FindCharEcj + _ZNK12nsCSubstring9CountCharEc + _ZNK13nsStringArray7IndexOfERK9nsAString + _ZNK13nsStringArray8StringAtEi + _ZNK13nsStringArray8StringAtEiR9nsAString + _ZNK14nsCStringArray17IndexOfIgnoreCaseERK10nsACString + _ZNK14nsCStringArray7IndexOfERK10nsACString + _ZNK14nsCStringArray9CStringAtEi + _ZNK14nsCStringArray9CStringAtEiR10nsACString + _ZNK14nsGetInterfaceclERK4nsIDPPv + _ZNK14nsISupportsKey5WriteEP21nsIObjectOutputStream + _ZNK15nsCOMArray_base13IndexOfObjectEP11nsISupports + _ZNK15nsQueryReferentclERK4nsIDPPv + _ZNK16nsQueryElementAtclERK4nsIDPPv + _ZNK16nsQueryInterfaceclERK4nsIDPPv + _ZNK16nsSmallVoidArray12GetArraySizeEv + _ZNK16nsSmallVoidArray5CountEv + _ZNK16nsSmallVoidArray7IndexOfEPv + _ZNK16nsSmallVoidArray9ElementAtEi + _ZNK16nsSubstringTuple13IsDependentOnEPKtS1_ + _ZNK16nsSubstringTuple6LengthEv + _ZNK16nsSubstringTuple7WriteToEPtj + _ZNK17nsCSubstringTuple13IsDependentOnEPKcS1_ + _ZNK17nsCSubstringTuple6LengthEv + _ZNK17nsCSubstringTuple7WriteToEPcj + _ZNK17nsGetServiceByCIDclERK4nsIDPPv + _ZNK18nsGetWeakReferenceclERK4nsIDPPv + _ZNK21nsCreateInstanceByCIDclERK4nsIDPPv + _ZNK21nsQueryArrayElementAtclERK4nsIDPPv + _ZNK24nsGetServiceByContractIDclERK4nsIDPPv + _ZNK25nsDefaultStringComparatorclEPKtS1_j + _ZNK25nsDefaultStringComparatorclEtt + _ZNK25nsQueryInterfaceWithErrorclERK4nsIDPPv + _ZNK26nsDefaultCStringComparatorclEPKcS1_j + _ZNK26nsDefaultCStringComparatorclEcc + _ZNK28nsCreateInstanceByContractIDclERK4nsIDPPv + _ZNK28nsCreateInstanceFromCategoryclERK4nsIDPPv + _ZNK34nsCaseInsensitiveCStringComparatorclEPKcS1_j + _ZNK34nsCaseInsensitiveCStringComparatorclEcc + _ZNK4nsID16ToProvidedStringERA39_c + _ZNK4nsID8ToStringEv + _ZNK7nsDeque3EndEv + _ZNK7nsDeque4LastEv + _ZNK7nsDeque5BeginEv + _ZNK7nsDeque7ForEachER14nsDequeFunctor + _ZNK7nsDeque8ObjectAtEi + _ZNK7nsDeque9FirstThatER14nsDequeFunctor + _ZNK7nsIDKey5WriteEP21nsIObjectOutputStream + _ZNK8nsString13FindCharInSetEPKci + _ZNK8nsString13FindCharInSetEPKti + _ZNK8nsString14RFindCharInSetEPKti + _ZNK8nsString16EqualsIgnoreCaseEPKci + _ZNK8nsString3MidERS_jj + _ZNK8nsString4FindEPKciii + _ZNK8nsString4FindEPKtii + _ZNK8nsString4FindERK9nsCStringiii + _ZNK8nsString4FindERKS_ii + _ZNK8nsString5RFindEPKciii + _ZNK8nsString5RFindEPKtii + _ZNK8nsString5RFindERK9nsCStringiii + _ZNK8nsString5RFindERKS_ii + _ZNK8nsString7ToFloatEPi + _ZNK8nsString9RFindCharEtii + _ZNK8nsString9ToCStringEPcjj + _ZNK8nsString9ToIntegerEPij + _ZNK9nsAString11EqualsASCIIEPKc + _ZNK9nsAString11EqualsASCIIEPKcj + _ZNK9nsAString12IsTerminatedEv + _ZNK9nsAString17GetReadableBufferEPPKt + _ZNK9nsAString20LowerCaseEqualsASCIIEPKc + _ZNK9nsAString20LowerCaseEqualsASCIIEPKcj + _ZNK9nsAString4LastEv + _ZNK9nsAString5FirstEv + _ZNK9nsAString6EqualsEPKt + _ZNK9nsAString6EqualsEPKtRK18nsStringComparator + _ZNK9nsAString6EqualsERKS_ + _ZNK9nsAString6EqualsERKS_RK18nsStringComparator + _ZNK9nsAString6IsVoidEv + _ZNK9nsAString6LengthEv + _ZNK9nsAString8FindCharEtj + _ZNK9nsAString9CountCharEt + _ZNK9nsCString13FindCharInSetEPKci + _ZNK9nsCString14RFindCharInSetEPKci + _ZNK9nsCString3MidERS_jj + _ZNK9nsCString4FindEPKciii + _ZNK9nsCString4FindERKS_iii + _ZNK9nsCString5RFindEPKciii + _ZNK9nsCString5RFindERKS_iii + _ZNK9nsCString7CompareEPKcii + _ZNK9nsCString7ToFloatEPi + _ZNK9nsCString9RFindCharEtii + _ZNK9nsCString9ToIntegerEPij + _ZNK9nsHashKey5WriteEP21nsIObjectOutputStream diff --git a/src/libs/xpcom18a4/dependentLibs.h b/src/libs/xpcom18a4/dependentLibs.h new file mode 100644 index 00000000..fa00ec80 --- /dev/null +++ b/src/libs/xpcom18a4/dependentLibs.h @@ -0,0 +1,2 @@ +#error "This is linux specific and it works elsewhere, so it cannot be required, can it? VBoxXPCOMIPCC was the only one which used this file." +#define DEPENDENT_LIBS "VBoxXPCOM.so", "libpthread.so", "libdl.so", diff --git a/src/libs/xpcom18a4/ipc/Makefile.kup b/src/libs/xpcom18a4/ipc/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/Makefile.in new file mode 100644 index 00000000..d5f24007 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/Makefile.in @@ -0,0 +1,64 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd + +PACKAGE_FILE = ipc.pkg + +DIRS = \ + util \ + shared/src \ + daemon/public \ + client/public \ + extensions \ + client/src \ + daemon/src \ + $(NULL) + +ifdef ENABLE_TESTS +DIRS += test +endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/client/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in new file mode 100644 index 00000000..896e68b8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/Makefile.in @@ -0,0 +1,59 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd + +EXPORTS = \ + ipcdclient.h \ + ipcCID.h \ + $(NULL) + +XPIDLSRCS = \ + ipcIService.idl \ + ipcIMessageObserver.idl \ + ipcIClientObserver.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h new file mode 100644 index 00000000..4863ff0d --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcCID.h @@ -0,0 +1,53 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcCID_h__ +#define ipcCID_h__ + +#define IPC_SERVICE_CLASSNAME \ + "ipcService" +#define IPC_SERVICE_CONTRACTID \ + "@mozilla.org/ipc/service;1" +#define IPC_SERVICE_CID \ +{ /* 9f12676a-5168-4a08-beb8-edf8a593a1ca */ \ + 0x9f12676a, \ + 0x5168, \ + 0x4a08, \ + {0xbe, 0xb8, 0xed, 0xf8, 0xa5, 0x93, 0xa1, 0xca} \ +} + +#endif // !ipcCID_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl new file mode 100644 index 00000000..c72d0909 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIClientObserver.idl @@ -0,0 +1,51 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsISupports.idl" + +/** + * ipcIClientObserver + */ +[scriptable, uuid(42283079-030c-4b13-b069-a08b7ad5eab2)] +interface ipcIClientObserver : nsISupports +{ + const unsigned long CLIENT_UP = 1; + const unsigned long CLIENT_DOWN = 2; + + void onClientStateChange(in unsigned long aClientID, + in unsigned long aClientState); +}; diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl new file mode 100644 index 00000000..db24b1f2 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIMessageObserver.idl @@ -0,0 +1,64 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsISupports.idl" + +/** + * ipcIMessageObserver + */ +[scriptable, uuid(e40a4a3c-2dc1-470e-ab7f-5675fe1f1384)] +interface ipcIMessageObserver : nsISupports +{ + /** + * @param aSenderID + * the client id of the sender of this message. if sent by the + * daemon (or a deamon module), then this will have a value of 0. + * @param aTarget + * the target of the message, corresponding to the target this + * observer was registered under. this parameter is passed to allow + * an observer instance to receive messages for more than one target. + * @param aData + * the data of the message. + * @param aDataLen + * the data length of the message. + */ + void onMessageAvailable(in unsigned long aSenderID, + in nsIDRef aTarget, + [array, const, size_is(aDataLen)] + in octet aData, + in unsigned long aDataLen); +}; diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl new file mode 100644 index 00000000..671b557d --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcIService.idl @@ -0,0 +1,228 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsISupports.idl" + +interface ipcIMessageObserver; +interface ipcIClientObserver; + +/** + * ipcIService + * + * the IPC service provides the means to communicate with an external IPC + * daemon and/or other mozilla-based applications on the same physical system. + * the IPC daemon hosts modules (some builtin and others dynamically loaded) + * with which applications may interact. + * + * at application startup, the IPC service will attempt to establish a + * connection with the IPC daemon. the IPC daemon will be automatically + * started if necessary. when a connection has been established, the IPC + * service will enumerate the "ipc-startup-category" and broadcast an + * "ipc-startup" notification using the observer service. + * + * when the connection to the IPC daemon is closed, an "ipc-shutdown" + * notification will be broadcast. + * + * each client has a name. the client name need not be unique across all + * clients, but it is usually good if it is. the IPC service does not require + * unique names. instead, the IPC daemon assigns each client a unique ID that + * is good for the current "session." clients can query other clients by name + * or by ID. the IPC service supports forwarding messages from one client to + * another via the IPC daemon. + * + * for performance reasons, this system should not be used to transfer large + * amounts of data. instead, applications may choose to utilize shared memory, + * and rely on the IPC service for synchronization and small message transfer + * only. + */ +[scriptable, uuid(53d3e3a7-528f-4b09-9eab-9416272568c0)] +interface ipcIService : nsISupports +{ + /************************************************************************** + * properties of this process + */ + + /** + * returns the "client ID" assigned to this process by the IPC daemon. + * + * @throws NS_ERROR_NOT_AVAILABLE if no connection to the IPC daemon. + */ + readonly attribute unsigned long ID; + + /** + * this process can appear under several client names. use the following + * methods to add or remove names for this process. + * + * for example, the mozilla browser might have the primary name "mozilla", + * but it could also register itself under the names "browser", "mail", + * "news", "addrbook", etc. other IPC clients can then query the IPC + * daemon for the client named "mail" in order to talk with a mail program. + * + * XXX An IPC client name resembles a XPCOM contract ID. + */ + void addName(in string aName); + void removeName(in string aName); + + /** + * add a new observer of client status change notifications. + */ + void addClientObserver(in ipcIClientObserver aObserver); + + /** + * remove an observer of client status change notifications. + */ + void removeClientObserver(in ipcIClientObserver aObserver); + + /************************************************************************** + * client query methods + */ + + /** + * resolve the given client name to the id of a connected client. this + * involves a round trip to the daemon, and as a result the calling thread + * may block on this function call while waiting for the daemon to respond. + */ + unsigned long resolveClientName(in string aName); + + + /** + * tests whether a particular client is connected to the IPC daemon. + */ + boolean clientExists(in unsigned long aClientID); + + + // XXX need other functions to enumerate clients, clients implementing targets, etc. + // enumerator getClients(); + // enumerator getClientsSupportingTarget(in nsIDRef aTarget); + // enumerator getClientNames(in unsigned long aClientID); + // enumerator getClientTargets(in unsigned long aClientID); + + + /************************************************************************** + * message methods + */ + + /** + * set a message observer for a particular message target. + * + * @param aTarget + * the message target being observed. any existing observer will + * be replaced. + * @param aObserver + * the message observer to receive incoming messages for the + * specified target. pass null to remove the existing observer. + * @param aOnCurrentThread + * if true, then the message observer will be called on the same + * thread that calls defineTarget. otherwise, aObserver will be + * called on a background thread. + */ + void defineTarget(in nsIDRef aTarget, + in ipcIMessageObserver aObserver, + in boolean aOnCurrentThread); + + /** + * send message asynchronously to a client or a module in the IPC daemon. + * there is no guarantee that the message will be delivered. + * + * @param aClientID + * the client ID of the foreign application that should receive this + * message. pass 0 to send a message to a module in the IPC daemon. + * @param aTarget + * the target of the message. if aClientID is 0, then this is the + * ID of the daemon module that should receive this message. + * @param aData + * the message data. + * @param aDataLen + * the message length. + */ + void sendMessage(in unsigned long aReceiverID, + in nsIDRef aTarget, + [array, const, size_is(aDataLen)] + in octet aData, + in unsigned long aDataLen); + + /** + * block the calling thread until a matching message is received. + * + * @param aSenderID + * pass 0 to wait for a message from the daemon. pass PR_UINT32_MAX + * to wait for a message from any source. otherwise, pass a client + * id to wait for a message from that particular client. + * @param aTarget + * wait for a message to be delivered to this target. + * @param aObserver + * this observer's OnMessageAvailable method is called when a + * matching message is available. pass null to use the default + * observer associated with aTarget. + * @param aTimeout + * indicates maximum length of time in milliseconds that this + * function may block the calling thread. + * + * @throws IPC_ERROR_WOULD_BLOCK if the timeout expires. + * + * the observer's OnMessageAvailable method may throw IPC_WAIT_NEXT_MESSAGE + * to indicate that it does not wish to handle the message that it was + * given, and that it will wait to be called with the next message. this + * enables the observer to keep messages in the queue that do not match the + * desired message. messages that remain in the queue will be dispatched + * asynchronously to the default message handler after waitMessage finishes. + * + * NOTE: this function may hang the calling thread until a matching message + * is received, so use it with caution. + */ + void waitMessage(in unsigned long aSenderID, + in nsIDRef aTarget, + in ipcIMessageObserver aObserver, + in unsigned long aTimeout); + + /** + * Call this method to disable the default message observer for a target. + */ + void disableMessageObserver(in nsIDRef aTarget); + + /** + * Call this method to re-enable the default message observer for a target. + */ + void enableMessageObserver(in nsIDRef aTarget); +}; + +%{C++ +// category and observer event defines (XXX not yet implemented) +#define IPC_SERVICE_STARTUP_CATEGORY "ipc-startup-category" +#define IPC_SERVICE_STARTUP_TOPIC "ipc-startup" +#define IPC_SERVICE_SHUTDOWN_TOPIC "ipc-shutdown" +%} diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h new file mode 100644 index 00000000..5cbed879 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/public/ipcdclient.h @@ -0,0 +1,326 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcdclient_h__ +#define ipcdclient_h__ + +/***************************************************************************** + * This file provides a client-side API to the IPC daemon. + * + * This API can be used to communicate with other clients of the IPC daemon + * as well as modules running inside the IPC daemon. + * + * This API is meant to be used only on the application's main thread. It is + * assumed that callbacks can be dispatched via the main thread's event queue. + */ + +#include "nscore.h" +#include "nsID.h" +#include "nsError.h" +#include "ipcIMessageObserver.h" +#include "ipcIClientObserver.h" + +/* This API is only provided for the extensions compiled into the IPCDC + * library, hence this API is hidden in the final DSO. */ +#define IPC_METHOD NS_HIDDEN_(nsresult) + +/* This value can be used to represent the client id of any client connected + * to the IPC daemon. */ +#define IPC_SENDER_ANY PR_UINT32_MAX + +/* This error code can only be returned by OnMessageAvailable, when called by + * IPC_WaitMessage. See IPC_WaitMessage for a description of how this error + * code may be used. */ +#define IPC_WAIT_NEXT_MESSAGE \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 10) + +#ifdef VBOX +/* This error code can only be returned by the selector functions called by + * WaitTarget. The message should be dropped without processing. */ +#define IPC_DISCARD_MESSAGE \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 12) +#endif /* VBOX */ + +/* This error code is returned by IPC_WaitMessage under certain conditions. */ +#define IPC_ERROR_WOULD_BLOCK NS_BASE_STREAM_WOULD_BLOCK + +/***************************************************************************** + * Initialization and Shutdown + */ + +// XXX limit these to the main thread, and call them from our module's ctor/dtor? + +/** + * Connects this process to the IPC daemon and initializes it for use as a + * client of the IPC daemon. This function must be called once before any + * other methods defined in this file can be used. + * + * @returns NS_ERROR_ALREADY_INITIALIZED if IPC_Shutdown was not called since + * the last time IPC_Init was called. + */ +IPC_METHOD IPC_Init(); + +/** + * Disconnects this process from the IPC daemon. After this function is + * called, no other methods in this file except for IPC_Init may be called. + * + * This function calls all client observers (registered with + * IPC_AddClientObserver) before it actually disconnects from the IPC daemon, + * with aClientID parameter of the OnClientStateChange callback specially + * set to IPC_SENDER_ANY and aClientState set to CLIENT_DOWN. This gives + * the interested party an opportunity to perform a proper shutdown procedure. + * All IPC methods are still available inside OnClientStateChange call except + * the IPC_WaitMessage function, that will immediately fail with an error. + * OnClientStateChange is called on the same thread where this function is + * called. + * + * @returns NS_ERROR_NOT_INITIALIZED if IPC_Init has not been called or if + * IPC_Init did not return a success code. + */ +IPC_METHOD IPC_Shutdown(); + + +/***************************************************************************** + * The core messaging API + */ + +/** + * Call this method to define a message target. A message target is defined + * by a UUID and a message observer. This observer is notified asynchronously + * whenever a message is sent to this target in this process. + * + * This function has three main effects: + * o If the message target is already defined, then this function simply + * resets its message observer. + * o If the message target is not already defined, then the message target + * is defined and the IPC daemon is notified of the existance of this + * message target. + * o If null is passed for the message observer, then the message target is + * removed, and the daemon is notified of the removal of this message target. + * + * If aOnCurrentThread is true, then notifications to the observer will occur + * on the current thread. This means that there must be a nsIEventTarget + * associated with the calling thread. If aOnCurrentThread is false, then + * notifications to the observer will occur on a background thread. In which + * case, the observer must be threadsafe. + */ +IPC_METHOD IPC_DefineTarget( + const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRBool aOnCurrentThread = PR_TRUE +); + +/** + * Call this method to temporarily disable the message observer configured + * for a message target. + */ +IPC_METHOD IPC_DisableMessageObserver( + const nsID &aTarget +); + +/** + * Call this method to re-enable the message observer configured for a + * message target. + */ +IPC_METHOD IPC_EnableMessageObserver( + const nsID &aTarget +); + +/** + * This function sends a message to the IPC daemon asynchronously. If + * aReceiverID is non-zero, then the message is forwarded to the client + * corresponding to that identifier. + * + * If there is no client corresponding to aRecieverID, then the IPC daemon will + * simply drop the message. + */ +IPC_METHOD IPC_SendMessage( + PRUint32 aReceiverID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen +); + +/** + * This function blocks the calling thread until a message for the given target + * is received (optionally from the specified client). + * + * The aSenderID parameter is interpreted as follows: + * o If aSenderID is 0, then this function waits for a message to be sent by + * the IPC daemon. + * o If aSenderID is IPC_SENDER_ANY, then this function waits for a message + * to be sent from any source. + * o Otherwise, this function waits for a message to be sent by the client + * with ID given by aSenderID. If aSenderID does not identify a valid + * client, or if the client dies while waiting, then this function will + * return an error. + * + * The aObserver parameter is interpreted as follows: + * o If aObserver is null, then the default message observer for the target + * is invoked when the next message is received. + * o Otherwise, aObserver will be inovked when the next message is received. + * + * The aConsumer parameter is interpreted as follows: + * o If aObserver is null or aConsumer is null, this parameter is ignored. + * o Otherwise, aConsumer will be invoked right after (and only if) aObserver + * has accepted some message. It will receive exactly the same message + * that was accepted by aObserver. + * + * The aTimeout parameter is interpreted as follows: + * o If aTimeout is PR_INTERVAL_NO_TIMEOUT, then this function will block + * until a matching message is received. + * o If aTimeout is PR_INTERVAL_NO_WAIT, then this function will only inspect + * the current queue of messages. If no matching message is found, then + * IPC_ERROR_WOULD_BLOCK is returned. + * o Otherwise, aTimeout specifies the maximum amount of time to wait for a + * matching message to be received. If no matching message is found after + * the timeout expires, then IPC_ERROR_WOULD_BLOCK is returned. + * + * If aObserver's OnMessageAvailable function returns IPC_WAIT_NEXT_MESSAGE, + * then the function will continue blocking until the next matching message + * is received. Bypassed messages will be dispatched to the default message + * observer when the event queue, associated with the thread that called + * IPC_DefineTarget, is processed. + * + * There is a special case if aSenderID is IPC_SENDER_ANY and one of IPC clients + * dies while this function waits for a message. In this case, aObserver's + * OnMessageAvailable function is called with a special set of arguments: + * dead client id, empty target id and null message (both data and data length + * are zeroes). If it returns IPC_WAIT_NEXT_MESSAGE, IPC_WaitMessage continues + * blocking as usual, otherwise an error is immediately returned to the caller. + * + * aObserver is not expected to use any IPC system functons from within its + * OnMessageAvailable implementation. This is because the IPC system is not + * re-entrant during invocation of OnMessageAvailable function, and making other + * IPC calls can lead to unexpected results (like message losses or traps). On + * the contrary, aConsumer's OnMessageAvailable function is allowed to use the + * IPC system without any limitations. + * + * This function runs the risk of hanging the calling thread indefinitely if + * no matching message is ever received. + */ +IPC_METHOD IPC_WaitMessage( + PRUint32 aSenderID, + const nsID &aTarget, + ipcIMessageObserver *aObserver = nsnull, + ipcIMessageObserver *aConsumer = nsnull, + PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT +); + +/*****************************************************************************/ + +/** + * Returns the "ClientID" of the current process. + */ +IPC_METHOD IPC_GetID( + PRUint32 *aClientID +); + +/** + * Adds a new name for the current process. The IPC daemon is notified of this + * change, which allows other processes to discover this process by the given + * name. + */ +IPC_METHOD IPC_AddName( + const char *aName +); + +/** + * Removes a name associated with the current process. + */ +IPC_METHOD IPC_RemoveName( + const char *aName +); + +/** + * Adds client observer. Will be called on the main thread. + */ +IPC_METHOD IPC_AddClientObserver( + ipcIClientObserver *aObserver +); + +/** + * Removes client observer. + */ +IPC_METHOD IPC_RemoveClientObserver( + ipcIClientObserver *aObserver +); + +/** + * Resolves the given client name to a client ID of a process connected to + * the IPC daemon. + */ +IPC_METHOD IPC_ResolveClientName( + const char *aName, + PRUint32 *aClientID +); + +/** + * Tests whether the client is connected to the IPC daemon. + */ +IPC_METHOD IPC_ClientExists( + PRUint32 aClientID, + PRBool *aResult +); + +/*****************************************************************************/ + +/** + * This class can be used to temporarily disable the default message observer + * defined for a particular message target. + */ +class ipcDisableMessageObserverForScope +{ +public: + ipcDisableMessageObserverForScope(const nsID &aTarget) + : mTarget(aTarget) + { + IPC_DisableMessageObserver(mTarget); + } + + ~ipcDisableMessageObserverForScope() + { + IPC_EnableMessageObserver(mTarget); + } + +private: + const nsID &mTarget; +}; + +#define IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(_t) \ + ipcDisableMessageObserverForScope ipc_dmo_for_scope##_t(_t) + +#endif /* ipcdclient_h__ */ diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in new file mode 100644 index 00000000..b2854e35 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.in @@ -0,0 +1,101 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = ipcdc +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +MODULE_NAME = ipcdclient + +REQUIRES = \ + xpcom \ + string \ + $(NULL) + +CPPSRCS = \ + ipcdclient.cpp \ + ipcService.cpp \ + ipcModuleFactory.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += ipcConnectionWin.cpp +else +ifeq ($(OS_ARCH),BeOS) +CPPSRCS += ipcConnectionStub.cpp +else +CPPSRCS += ipcConnectionUnix.cpp +endif +endif + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../shared/src \ + -I$(srcdir)/../../extensions/lock/src \ + -I$(srcdir)/../../extensions/transmngr/src \ + -I$(srcdir)/../../extensions/transmngr/common \ + $(NULL) + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)ipcdshared_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ipcdlock_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)transmgr_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)transmgrcom_s.$(LIB_SUFFIX) \ + $(NULL) + +ifneq ($(BUILD_DCONNECT),) +DEFINES += -DBUILD_DCONNECT +LOCAL_INCLUDES += -I$(srcdir)/../../extensions/dconnect/src +SHARED_LIBRARY_LIBS += $(DIST)/lib/$(LIB_PREFIX)ipcddconnect_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ipcdutil_s.$(LIB_SUFFIX) \ + $(NULL) +endif + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(EXTRA_DSO_LIBS) \ + $(MOZ_COMPONENT_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/client/src/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h new file mode 100644 index 00000000..8773daa5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnection.h @@ -0,0 +1,147 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcConnection_h__ +#define ipcConnection_h__ + +#include "nscore.h" + +class ipcMessage; + +#define IPC_METHOD_PRIVATE_(type) NS_HIDDEN_(type) +#define IPC_METHOD_PRIVATE IPC_METHOD_PRIVATE_(nsresult) + +/* ------------------------------------------------------------------------- */ +/* Platform specific IPC connection API. + */ + +typedef void (* ipcCallbackFunc)(void *); + +/** + * IPC_Connect + * + * This function causes a connection to the IPC daemon to be established. + * If a connection already exists, then this function will be ignored. + * + * @param daemonPath + * Specifies the path to the IPC daemon executable. + * + * NOTE: This function must be called on the main thread. + */ +IPC_METHOD_PRIVATE IPC_Connect(const char *daemonPath); + +/** + * IPC_Disconnect + * + * This function causes a connection to the IPC daemon to be closed. Any + * unsent messages (IPC_SendMsg puts messages on a queue) will be sent to the + * IPC daemon before the connection is closed. + * + * NOTE: This function must be called on the main thread. + */ +IPC_METHOD_PRIVATE IPC_Disconnect(); + +/** + * IPC_SendMsg + * + * This function sends a message to the IPC daemon. Typically, the message + * is put on a queue, to be delivered asynchronously to the IPC daemon. The + * ipcMessage object will be deleted when IPC_SendMsg is done with it. The + * caller must not touch |msg| after passing it to IPC_SendMsg. + * + * IPC_SendMsg cannot be called before IPC_Connect or after IPC_Disconnect. + * + * NOTE: This function may be called on any thread. + */ +IPC_METHOD_PRIVATE IPC_SendMsg(ipcMessage *msg); + +/** + * IPC_DoCallback + * + * This function executes a callback function on the same background thread + * that calls IPC_OnConnectionEnd and IPC_OnMessageAvailable. + * + * If this function succeeds, then the caller is guaranteed that |func| will + * be called. This guarantee is important because it allows the caller to + * free any memory associated with |arg| once |func| has been called. + * + * NOTE: This function may be called on any thread. + */ +IPC_METHOD_PRIVATE IPC_DoCallback(ipcCallbackFunc func, void *arg); + +/* ------------------------------------------------------------------------- */ +/* Cross-platform IPC connection methods. + */ + +/** + * IPC_SpawnDaemon + * + * This function launches the IPC daemon process. It is called by the platform + * specific IPC_Connect implementation. It should not return until the daemon + * process is ready to receive a client connection or an error occurs. + * + * @param daemonPath + * Specifies the path to the IPC daemon executable. + */ +IPC_METHOD_PRIVATE IPC_SpawnDaemon(const char *daemonPath); + +/* ------------------------------------------------------------------------- */ +/* IPC connection callbacks (not implemented by the connection code). + * + * NOTE: These functions execute on a background thread!! + */ + +/** + * IPC_OnConnectionEnd + * + * This function is called whenever the connection to the IPC daemon has been + * terminated. If terminated due to an abnormal error, then the error will be + * described by the |error| parameter. If |error| is NS_OK, then it means the + * connection was closed in response to a call to IPC_Disconnect. + */ +IPC_METHOD_PRIVATE_(void) IPC_OnConnectionEnd(nsresult error); + +/** + * IPC_OnMessageAvailable + * + * This function is called whenever an incoming message is read from the IPC + * daemon. The ipcMessage object, |msg|, must be deleted by the implementation + * of IPC_OnMessageAvailable when the object is no longer needed. + */ +IPC_METHOD_PRIVATE_(void) IPC_OnMessageAvailable(ipcMessage *msg); + +#endif // ipcConnection_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp new file mode 100644 index 00000000..8b985785 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionStub.cpp @@ -0,0 +1,70 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcConnection.h" +#include "nsError.h" + +//----------------------------------------------------------------------------- +// use this file as a template to add client-side IPC connectivity. +// +// NOTE: if your platform supports local domain TCP sockets, then you should +// be able to make use of ipcConnectionUnix.cpp. +//----------------------------------------------------------------------------- + +nsresult +IPC_Connect(const char *daemonPath) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +IPC_Disconnect() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +IPC_SendMsg(ipcMessage *msg) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +IPC_DoCallback(ipcCallbackFunc func, void *arg) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp new file mode 100644 index 00000000..5cd7a0c8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionUnix.cpp @@ -0,0 +1,615 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "private/pprio.h" +#include "prerror.h" +#include "prthread.h" +#include "prlock.h" +#include "prlog.h" // for PR_ASSERT (we don't actually use NSPR logging) +#include "prio.h" + +#include "ipcConnection.h" +#include "ipcMessageQ.h" +#include "ipcConfig.h" +#include "ipcLog.h" + +#ifdef VBOX +# include "prenv.h" +# include +# include +#endif + + +//----------------------------------------------------------------------------- +// NOTE: this code does not need to link with anything but NSPR. that is by +// design, so it can be easily reused in other projects that want to +// talk with mozilla's IPC daemon, but don't want to depend on xpcom. +// we depend at most on some xpcom header files, but no xpcom runtime +// symbols are used. +//----------------------------------------------------------------------------- + + +// single user systems, like OS/2, don't need these security checks. +#ifndef XP_OS2 +#define IPC_SKIP_SECURITY_CHECKS +#endif + +#ifndef IPC_SKIP_SECURITY_CHECKS +#include +#include +#endif + +static PRStatus +DoSecurityCheck(PRFileDesc *fd, const char *path) +{ +#ifndef IPC_SKIP_SECURITY_CHECKS + // + // now that we have a connected socket; do some security checks on the + // file descriptor. + // + // (1) make sure owner matches + // (2) make sure permissions match expected permissions + // + // if these conditions aren't met then bail. + // + int unix_fd = PR_FileDesc2NativeHandle(fd); + + struct stat st; + if (fstat(unix_fd, &st) == -1) { + LOG(("stat failed")); + return PR_FAILURE; + } + + if (st.st_uid != getuid() && st.st_uid != geteuid()) { + // + // on OSX 10.1.5, |fstat| has a bug when passed a file descriptor to + // a socket. it incorrectly returns a UID of 0. however, |stat| + // succeeds, but using |stat| introduces a race condition. + // + // XXX come up with a better security check. + // + if (st.st_uid != 0) { + LOG(("userid check failed")); + return PR_FAILURE; + } + if (stat(path, &st) == -1) { + LOG(("stat failed")); + return PR_FAILURE; + } + if (st.st_uid != getuid() && st.st_uid != geteuid()) { + LOG(("userid check failed")); + return PR_FAILURE; + } + } +#endif + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- + +struct ipcCallback : public ipcListNode +{ + ipcCallbackFunc func; + void *arg; +}; + +typedef ipcList ipcCallbackQ; + +//----------------------------------------------------------------------------- + +struct ipcConnectionState +{ + PRLock *lock; + PRPollDesc fds[2]; + ipcCallbackQ callback_queue; + ipcMessageQ send_queue; + PRUint32 send_offset; // amount of send_queue.First() already written. + ipcMessage *in_msg; + PRBool shutdown; +}; + +#define SOCK 0 +#define POLL 1 + +static void +ConnDestroy(ipcConnectionState *s) +{ + if (s->lock) + PR_DestroyLock(s->lock); + + if (s->fds[SOCK].fd) + PR_Close(s->fds[SOCK].fd); + + if (s->fds[POLL].fd) + PR_DestroyPollableEvent(s->fds[POLL].fd); + + if (s->in_msg) + delete s->in_msg; + + s->send_queue.DeleteAll(); + delete s; +} + +static ipcConnectionState * +ConnCreate(PRFileDesc *fd) +{ + ipcConnectionState *s = new ipcConnectionState; + if (!s) + return NULL; + + s->lock = PR_NewLock(); + s->fds[SOCK].fd = NULL; + s->fds[POLL].fd = PR_NewPollableEvent(); + s->send_offset = 0; + s->in_msg = NULL; + s->shutdown = PR_FALSE; + + if (!s->lock || !s->fds[1].fd) + { + ConnDestroy(s); + return NULL; + } + + // disable inheritance of the IPC socket by children started + // using non-NSPR process API + PRStatus status = PR_SetFDInheritable(fd, PR_FALSE); + if (status != PR_SUCCESS) + { + LOG(("coudn't make IPC socket non-inheritable [err=%d]\n", PR_GetError())); + return NULL; + } + + // store this only if we are going to succeed. + s->fds[SOCK].fd = fd; + + return s; +} + +static nsresult +ConnRead(ipcConnectionState *s) +{ + char buf[1024]; + nsresult rv = NS_OK; + PRInt32 n; + + do + { + n = PR_Read(s->fds[SOCK].fd, buf, sizeof(buf)); + if (n < 0) + { + PRErrorCode err = PR_GetError(); + if (err == PR_WOULD_BLOCK_ERROR) + { + // socket is empty... we need to go back to polling. + break; + } + LOG(("PR_Read returned failure [err=%d]\n", err)); + rv = NS_ERROR_UNEXPECTED; + } + else if (n == 0) + { + LOG(("PR_Read returned EOF\n")); + rv = NS_ERROR_UNEXPECTED; + } + else + { + const char *pdata = buf; + while (n) + { + PRUint32 bytesRead; + PRBool complete; + + if (!s->in_msg) + { + s->in_msg = new ipcMessage; + if (!s->in_msg) + { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (s->in_msg->ReadFrom(pdata, n, &bytesRead, &complete) != PR_SUCCESS) + { + LOG(("error reading IPC message\n")); + rv = NS_ERROR_UNEXPECTED; + break; + } + + PR_ASSERT(PRUint32(n) >= bytesRead); + n -= bytesRead; + pdata += bytesRead; + + if (complete) + { + // protect against weird re-entrancy cases... + ipcMessage *m = s->in_msg; + s->in_msg = NULL; + + IPC_OnMessageAvailable(m); + } + } + } + } + while (NS_SUCCEEDED(rv)); + + return rv; +} + +static nsresult +ConnWrite(ipcConnectionState *s) +{ + nsresult rv = NS_OK; + + PR_Lock(s->lock); + + // write one message and then return. + if (s->send_queue.First()) + { + PRInt32 n = PR_Write(s->fds[SOCK].fd, + s->send_queue.First()->MsgBuf() + s->send_offset, + s->send_queue.First()->MsgLen() - s->send_offset); + if (n <= 0) + { + PRErrorCode err = PR_GetError(); + if (err == PR_WOULD_BLOCK_ERROR) + { + // socket is full... we need to go back to polling. + } + else + { + LOG(("error writing to socket [err=%d]\n", err)); + rv = NS_ERROR_UNEXPECTED; + } + } + else + { + s->send_offset += n; + if (s->send_offset == s->send_queue.First()->MsgLen()) + { + s->send_queue.DeleteFirst(); + s->send_offset = 0; + + // if the send queue is empty, then we need to stop trying to write. + if (s->send_queue.IsEmpty()) + s->fds[SOCK].in_flags &= ~PR_POLL_WRITE; + } + } + } + + PR_Unlock(s->lock); + return rv; +} + +PR_STATIC_CALLBACK(void) +ConnThread(void *arg) +{ + PRInt32 num; + nsresult rv = NS_OK; + + ipcConnectionState *s = (ipcConnectionState *) arg; + + // we monitor two file descriptors in this thread. the first (at index 0) is + // the socket connection with the IPC daemon. the second (at index 1) is the + // pollable event we monitor in order to know when to send messages to the + // IPC daemon. + + s->fds[SOCK].in_flags = PR_POLL_READ; + s->fds[POLL].in_flags = PR_POLL_READ; + + while (NS_SUCCEEDED(rv)) + { + s->fds[SOCK].out_flags = 0; + s->fds[POLL].out_flags = 0; + + // + // poll on the IPC socket and NSPR pollable event + // + num = PR_Poll(s->fds, 2, PR_INTERVAL_NO_TIMEOUT); + if (num > 0) + { + ipcCallbackQ cbs_to_run; + + // check if something has been added to the send queue. if so, then + // acknowledge pollable event (wait should not block), and configure + // poll flags to find out when we can write. + + if (s->fds[POLL].out_flags & PR_POLL_READ) + { + PR_WaitForPollableEvent(s->fds[POLL].fd); + PR_Lock(s->lock); + + if (!s->send_queue.IsEmpty()) + s->fds[SOCK].in_flags |= PR_POLL_WRITE; + + if (!s->callback_queue.IsEmpty()) + s->callback_queue.MoveTo(cbs_to_run); + + PR_Unlock(s->lock); + } + + // check if we can read... + if (s->fds[SOCK].out_flags & PR_POLL_READ) + rv = ConnRead(s); + + // check if we can write... + if (s->fds[SOCK].out_flags & PR_POLL_WRITE) + rv = ConnWrite(s); + + // check if we have callbacks to run + while (!cbs_to_run.IsEmpty()) + { + ipcCallback *cb = cbs_to_run.First(); + (cb->func)(cb->arg); + cbs_to_run.DeleteFirst(); + } + + // check if we should exit this thread. delay processing a shutdown + // request until after all queued up messages have been sent and until + // after all queued up callbacks have been run. + PR_Lock(s->lock); + if (s->shutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty()) + rv = NS_ERROR_ABORT; + PR_Unlock(s->lock); + } + else + { + LOG(("PR_Poll returned error %d (%s), os error %d\n", PR_GetError(), + PR_ErrorToName(PR_GetError()), PR_GetOSError())); + rv = NS_ERROR_UNEXPECTED; + } + } + + // notify termination of the IPC connection + if (rv == NS_ERROR_ABORT) + rv = NS_OK; + IPC_OnConnectionEnd(rv); + + LOG(("IPC thread exiting\n")); +} + +//----------------------------------------------------------------------------- +// IPC connection API +//----------------------------------------------------------------------------- + +static ipcConnectionState *gConnState = NULL; +static PRThread *gConnThread = NULL; + +#ifdef DEBUG +static PRThread *gMainThread = NULL; +#endif + +nsresult +TryConnect(PRFileDesc **result) +{ + PRFileDesc *fd; + PRNetAddr addr; + PRSocketOptionData opt; + // don't use NS_ERROR_FAILURE as we want to detect these kind of errors + // in the frontend + nsresult rv = NS_ERROR_SOCKET_FAIL; + + fd = PR_OpenTCPSocket(PR_AF_LOCAL); + if (!fd) + goto end; + + addr.local.family = PR_AF_LOCAL; + IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path)); + + // blocking connect... will fail if no one is listening. + if (PR_Connect(fd, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) + goto end; + +#ifdef VBOX + if (PR_GetEnv("TESTBOX_UUID")) + fprintf(stderr, "IPC socket path: %s\n", addr.local.path); + LogRel(("IPC socket path: %s\n", addr.local.path)); +#endif + + // make socket non-blocking + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + PR_SetSocketOption(fd, &opt); + + // do some security checks on connection socket... + if (DoSecurityCheck(fd, addr.local.path) != PR_SUCCESS) + goto end; + + *result = fd; + return NS_OK; + +end: + if (fd) + PR_Close(fd); + + return rv; +} + +nsresult +IPC_Connect(const char *daemonPath) +{ + // synchronous connect, spawn daemon if necessary. + + PRFileDesc *fd = NULL; + nsresult rv = NS_ERROR_FAILURE; + + if (gConnState) + return NS_ERROR_ALREADY_INITIALIZED; + + // + // here's the connection algorithm: try to connect to an existing daemon. + // if the connection fails, then spawn the daemon (wait for it to be ready), + // and then retry the connection. it is critical that the socket used to + // connect to the daemon not be inherited (this causes problems on RH9 at + // least). + // + + rv = TryConnect(&fd); + if (NS_FAILED(rv)) + { + nsresult rv1 = IPC_SpawnDaemon(daemonPath); + if (NS_SUCCEEDED(rv1) || rv != NS_ERROR_SOCKET_FAIL) + rv = rv1; + if (NS_SUCCEEDED(rv)) + rv = TryConnect(&fd); + } + + if (NS_FAILED(rv)) + goto end; + + // + // ok, we have a connection to the daemon! + // + + // build connection state object + gConnState = ConnCreate(fd); + if (!gConnState) + { + rv = NS_ERROR_OUT_OF_MEMORY; + goto end; + } + fd = NULL; // connection state now owns the socket + + gConnThread = PR_CreateThread(PR_USER_THREAD, + ConnThread, + gConnState, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + if (!gConnThread) + { + rv = NS_ERROR_OUT_OF_MEMORY; + goto end; + } + +#ifdef DEBUG + gMainThread = PR_GetCurrentThread(); +#endif + return NS_OK; + +end: + if (gConnState) + { + ConnDestroy(gConnState); + gConnState = NULL; + } + if (fd) + PR_Close(fd); + return rv; +} + +nsresult +IPC_Disconnect() +{ + // Must disconnect on same thread used to connect! + PR_ASSERT(gMainThread == PR_GetCurrentThread()); + + if (!gConnState || !gConnThread) + return NS_ERROR_NOT_INITIALIZED; + + PR_Lock(gConnState->lock); + gConnState->shutdown = PR_TRUE; + PR_SetPollableEvent(gConnState->fds[POLL].fd); + PR_Unlock(gConnState->lock); + + PR_JoinThread(gConnThread); + + ConnDestroy(gConnState); + + gConnState = NULL; + gConnThread = NULL; + return NS_OK; +} + +nsresult +IPC_SendMsg(ipcMessage *msg) +{ + if (!gConnState || !gConnThread) + return NS_ERROR_NOT_INITIALIZED; + + PR_Lock(gConnState->lock); + gConnState->send_queue.Append(msg); + PR_SetPollableEvent(gConnState->fds[POLL].fd); + PR_Unlock(gConnState->lock); + + return NS_OK; +} + +nsresult +IPC_DoCallback(ipcCallbackFunc func, void *arg) +{ + if (!gConnState || !gConnThread) + return NS_ERROR_NOT_INITIALIZED; + + ipcCallback *callback = new ipcCallback; + if (!callback) + return NS_ERROR_OUT_OF_MEMORY; + callback->func = func; + callback->arg = arg; + + PR_Lock(gConnState->lock); + gConnState->callback_queue.Append(callback); + PR_SetPollableEvent(gConnState->fds[POLL].fd); + PR_Unlock(gConnState->lock); + return NS_OK; +} + +//----------------------------------------------------------------------------- + +#ifdef TEST_STANDALONE + +void IPC_OnConnectionFault(nsresult rv) +{ + LOG(("IPC_OnConnectionFault [rv=%x]\n", rv)); +} + +void IPC_OnMessageAvailable(ipcMessage *msg) +{ + LOG(("IPC_OnMessageAvailable\n")); + delete msg; +} + +int main() +{ + IPC_InitLog(">>>"); + IPC_Connect("/builds/moz-trunk/seamonkey-debug-build/dist/bin/mozilla-ipcd"); + IPC_Disconnect(); + return 0; +} + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp new file mode 100644 index 00000000..9a99c195 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcConnectionWin.cpp @@ -0,0 +1,332 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 + +#include "prprf.h" +#include "prmon.h" +#include "prthread.h" +#include "plevent.h" + +#include "nsIServiceManager.h" +#include "nsIEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsAutoLock.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcConnection.h" +#include "ipcm.h" + + +//----------------------------------------------------------------------------- +// NOTE: this code does not need to link with anything but NSPR. that is by +// design, so it can be easily reused in other projects that want to +// talk with mozilla's IPC daemon, but don't want to depend on xpcom. +// we depend at most on some xpcom header files, but no xpcom runtime +// symbols are used. +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// windows message thread +//----------------------------------------------------------------------------- + +#define IPC_WM_SENDMSG (WM_USER + 0x1) +#define IPC_WM_CALLBACK (WM_USER + 0x2) +#define IPC_WM_SHUTDOWN (WM_USER + 0x3) + +static nsresult ipcThreadStatus = NS_OK; +static PRThread *ipcThread = NULL; +static PRMonitor *ipcMonitor = NULL; +static HWND ipcDaemonHwnd = NULL; +static HWND ipcLocalHwnd = NULL; +static PRBool ipcShutdown = PR_FALSE; // not accessed on message thread!! + +//----------------------------------------------------------------------------- +// window proc +//----------------------------------------------------------------------------- + +static LRESULT CALLBACK +ipcThreadWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam)); + + if (uMsg == WM_COPYDATA) { + COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam; + if (cd && cd->lpData) { + ipcMessage *msg = new ipcMessage(); + PRUint32 bytesRead; + PRBool complete; + PRStatus rv = msg->ReadFrom((const char *) cd->lpData, cd->cbData, + &bytesRead, &complete); + if (rv == PR_SUCCESS && complete) + IPC_OnMessageAvailable(msg); // takes ownership of msg + else { + LOG((" unable to deliver message [complete=%u]\n", complete)); + delete msg; + } + } + return TRUE; + } + + if (uMsg == IPC_WM_SENDMSG) { + ipcMessage *msg = (ipcMessage *) lParam; + if (msg) { + LOG((" sending message...\n")); + COPYDATASTRUCT cd; + cd.dwData = GetCurrentProcessId(); + cd.cbData = (DWORD) msg->MsgLen(); + cd.lpData = (PVOID) msg->MsgBuf(); + SendMessageA(ipcDaemonHwnd, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd); + LOG((" done.\n")); + delete msg; + } + return 0; + } + + if (uMsg == IPC_WM_CALLBACK) { + ipcCallbackFunc func = (ipcCallbackFunc) wParam; + void *arg = (void *) lParam; + (func)(arg); + return 0; + } + + if (uMsg == IPC_WM_SHUTDOWN) { + IPC_OnConnectionEnd(NS_OK); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +//----------------------------------------------------------------------------- +// ipc thread functions +//----------------------------------------------------------------------------- + +static void +ipcThreadFunc(void *arg) +{ + LOG(("entering message thread\n")); + + DWORD pid = GetCurrentProcessId(); + + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = ipcThreadWindowProc; + wc.lpszClassName = IPC_CLIENT_WINDOW_CLASS; + RegisterClass(&wc); + + char wName[sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20]; + PR_snprintf(wName, sizeof(wName), "%s%u", IPC_CLIENT_WINDOW_NAME_PREFIX, pid); + + ipcLocalHwnd = CreateWindow(IPC_CLIENT_WINDOW_CLASS, wName, + 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL); + + { + nsAutoMonitor mon(ipcMonitor); + if (!ipcLocalHwnd) + ipcThreadStatus = NS_ERROR_FAILURE; + mon.Notify(); + } + + if (ipcLocalHwnd) { + MSG msg; + while (GetMessage(&msg, ipcLocalHwnd, 0, 0)) + DispatchMessage(&msg); + + ipcShutdown = PR_TRUE; // assuming atomic memory write + + DestroyWindow(ipcLocalHwnd); + ipcLocalHwnd = NULL; + } + + LOG(("exiting message thread\n")); + return; +} + +static PRStatus +ipcThreadInit() +{ + if (ipcThread) + return PR_FAILURE; + + ipcShutdown = PR_FALSE; + + ipcMonitor = PR_NewMonitor(); + if (!ipcMonitor) + return PR_FAILURE; + + // spawn message thread + ipcThread = PR_CreateThread(PR_USER_THREAD, ipcThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0); + if (!ipcThread) { + NS_WARNING("thread creation failed"); + PR_DestroyMonitor(ipcMonitor); + ipcMonitor = NULL; + return PR_FAILURE; + } + + // wait for hidden window to be created + { + nsAutoMonitor mon(ipcMonitor); + while (!ipcLocalHwnd && NS_SUCCEEDED(ipcThreadStatus)) + mon.Wait(); + } + + if (NS_FAILED(ipcThreadStatus)) { + NS_WARNING("message thread failed"); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +static PRStatus +ipcThreadShutdown() +{ + if (PR_AtomicSet(&ipcShutdown, PR_TRUE) == PR_FALSE) { + LOG(("posting IPC_WM_SHUTDOWN message\n")); + PostMessage(ipcLocalHwnd, IPC_WM_SHUTDOWN, 0, 0); + } + + LOG(("joining w/ message thread...\n")); + PR_JoinThread(ipcThread); + ipcThread = NULL; + + // + // ok, now the message thread is dead + // + + PR_DestroyMonitor(ipcMonitor); + ipcMonitor = NULL; + + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// windows specific IPC connection impl +//----------------------------------------------------------------------------- + +nsresult +IPC_Disconnect() +{ + LOG(("IPC_Disconnect\n")); + + //XXX mHaveConnection = PR_FALSE; + + if (!ipcDaemonHwnd) + return NS_ERROR_NOT_INITIALIZED; + + if (ipcThread) + ipcThreadShutdown(); + + // clear our reference to the daemon's HWND. + ipcDaemonHwnd = NULL; + return NS_OK; +} + +nsresult +IPC_Connect(const char *daemonPath) +{ + LOG(("IPC_Connect\n")); + + NS_ENSURE_TRUE(ipcDaemonHwnd == NULL, NS_ERROR_ALREADY_INITIALIZED); + nsresult rv; + + ipcDaemonHwnd = FindWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME); + if (!ipcDaemonHwnd) { + LOG((" daemon does not appear to be running\n")); + // + // daemon does not exist; spawn daemon... + // + rv = IPC_SpawnDaemon(daemonPath); + if (NS_FAILED(rv)) + return rv; + + ipcDaemonHwnd = FindWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME); + if (!ipcDaemonHwnd) + return NS_ERROR_FAILURE; + } + + // + // delay creation of the message thread until we know the daemon exists. + // + if (!ipcThread && ipcThreadInit() != PR_SUCCESS) { + ipcDaemonHwnd = NULL; + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +IPC_SendMsg(ipcMessage *msg) +{ + LOG(("IPC_SendMsg\n")); + + if (ipcShutdown) { + LOG(("unable to send message b/c message thread is shutdown\n")); + goto loser; + } + if (!PostMessage(ipcLocalHwnd, IPC_WM_SENDMSG, 0, (LPARAM) msg)) { + LOG((" PostMessage failed w/ error = %u\n", GetLastError())); + goto loser; + } + return NS_OK; +loser: + delete msg; + return NS_ERROR_FAILURE; +} + +nsresult +IPC_DoCallback(ipcCallbackFunc func, void *arg) +{ + LOG(("IPC_DoCallback\n")); + + if (ipcShutdown) { + LOG(("unable to send message b/c message thread is shutdown\n")); + return NS_ERROR_FAILURE; + } + if (!PostMessage(ipcLocalHwnd, IPC_WM_CALLBACK, (WPARAM) func, (LPARAM) arg)) { + LOG((" PostMessage failed w/ error = %u\n", GetLastError())); + return NS_ERROR_FAILURE; + } + return NS_OK; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp new file mode 100644 index 00000000..7dcd6eab --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcModuleFactory.cpp @@ -0,0 +1,196 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIServiceManager.h" +#include "nsIGenericFactory.h" +#include "nsICategoryManager.h" +#include "ipcdclient.h" +#include "ipcService.h" +#include "ipcConfig.h" +#include "ipcCID.h" + +//----------------------------------------------------------------------------- +// Define the contructor function for the objects +// +// NOTE: This creates an instance of objects by using the default constructor +//----------------------------------------------------------------------------- +NS_GENERIC_FACTORY_CONSTRUCTOR(ipcService) + +// enable this code to make the IPC service auto-start. +#if 0 +NS_METHOD +ipcServiceRegisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // + // add ipcService to the XPCOM startup category + // + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) { + nsXPIDLCString prevEntry; + catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcService", + IPC_SERVICE_CONTRACTID, PR_TRUE, PR_TRUE, + getter_Copies(prevEntry)); + } + return NS_OK; +} + +NS_METHOD +ipcServiceUnregisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) + catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, + IPC_SERVICE_CONTRACTID, PR_TRUE); + return NS_OK; +} +#endif + +//----------------------------------------------------------------------------- +// extensions + +#include "ipcLockService.h" +#include "ipcLockCID.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init) + +#include "tmTransactionService.h" +NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) + +#ifdef BUILD_DCONNECT + +#include "ipcDConnectService.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init) + +// enable this code to make the IPC DCONNECT service auto-start. +NS_METHOD +ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // + // add ipcService to the XPCOM startup category + // + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) { + nsXPIDLCString prevEntry; + catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService", + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE, + getter_Copies(prevEntry)); + } + return NS_OK; +} + +NS_METHOD +ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) + catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE); + return NS_OK; +} + +#endif // BUILD_DCONNECT + +//----------------------------------------------------------------------------- +// Define a table of CIDs implemented by this module along with other +// information like the function to create an instance, contractid, and +// class name. +//----------------------------------------------------------------------------- +static const nsModuleComponentInfo components[] = { + { IPC_SERVICE_CLASSNAME, + IPC_SERVICE_CID, + IPC_SERVICE_CONTRACTID, + ipcServiceConstructor }, + /* + ipcServiceRegisterProc, + ipcServiceUnregisterProc }, + */ + // + // extensions go here: + // + { IPC_LOCKSERVICE_CLASSNAME, + IPC_LOCKSERVICE_CID, + IPC_LOCKSERVICE_CONTRACTID, + ipcLockServiceConstructor }, + { IPC_TRANSACTIONSERVICE_CLASSNAME, + IPC_TRANSACTIONSERVICE_CID, + IPC_TRANSACTIONSERVICE_CONTRACTID, + tmTransactionServiceConstructor }, + +#ifdef BUILD_DCONNECT + { IPC_DCONNECTSERVICE_CLASSNAME, + IPC_DCONNECTSERVICE_CID, + IPC_DCONNECTSERVICE_CONTRACTID, + ipcDConnectServiceConstructor, + ipcDConnectServiceRegisterProc, + ipcDConnectServiceUnregisterProc }, +#endif +}; + +//----------------------------------------------------------------------------- + +PR_STATIC_CALLBACK(nsresult) +ipcdclient_init(nsIModule *module) +{ + return IPC_Init(); +} + +PR_STATIC_CALLBACK(void) +ipcdclient_shutdown(nsIModule *module) +{ + IPC_Shutdown(); +} + +//----------------------------------------------------------------------------- +// Implement the NSGetModule() exported function for your module +// and the entire implementation of the module object. +//----------------------------------------------------------------------------- +NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(ipcdclient, components, + ipcdclient_init, + ipcdclient_shutdown) diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp new file mode 100644 index 00000000..6c2a1326 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.cpp @@ -0,0 +1,120 @@ +/* vim:set ts=4 sw=4 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcService.h" + +// The ipcService implementation is nothing more than a thin XPCOM wrapper +// around the ipcdclient.h API. + +NS_IMPL_THREADSAFE_ISUPPORTS1(ipcService, ipcIService) + +NS_IMETHODIMP +ipcService::GetID(PRUint32 *aID) +{ + return IPC_GetID(aID); +} + +NS_IMETHODIMP +ipcService::AddName(const char *aName) +{ + return IPC_AddName(aName); +} + +NS_IMETHODIMP +ipcService::RemoveName(const char *aName) +{ + return IPC_RemoveName(aName); +} + +NS_IMETHODIMP +ipcService::AddClientObserver(ipcIClientObserver *aObserver) +{ + return IPC_AddClientObserver(aObserver); +} + +NS_IMETHODIMP +ipcService::RemoveClientObserver(ipcIClientObserver *aObserver) +{ + return IPC_RemoveClientObserver(aObserver); +} + +NS_IMETHODIMP +ipcService::ResolveClientName(const char *aName, PRUint32 *aID) +{ + return IPC_ResolveClientName(aName, aID); +} + +NS_IMETHODIMP +ipcService::ClientExists(PRUint32 aClientID, PRBool *aResult) +{ + return IPC_ClientExists(aClientID, aResult); +} + +NS_IMETHODIMP +ipcService::DefineTarget(const nsID &aTarget, ipcIMessageObserver *aObserver, + PRBool aOnCurrentThread) +{ + return IPC_DefineTarget(aTarget, aObserver, aOnCurrentThread); +} + +NS_IMETHODIMP +ipcService::SendMessage(PRUint32 aReceiverID, const nsID &aTarget, + const PRUint8 *aData, PRUint32 aDataLen) +{ + return IPC_SendMessage(aReceiverID, aTarget, aData, aDataLen); +} + +NS_IMETHODIMP +ipcService::WaitMessage(PRUint32 aSenderID, const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRUint32 aTimeout) +{ + return IPC_WaitMessage(aSenderID, aTarget, aObserver, nsnull, + PR_MillisecondsToInterval(aTimeout)); +} + +NS_IMETHODIMP +ipcService::DisableMessageObserver(const nsID &aTarget) +{ + return IPC_DisableMessageObserver(aTarget); +} + +NS_IMETHODIMP +ipcService::EnableMessageObserver(const nsID &aTarget) +{ + return IPC_EnableMessageObserver(aTarget); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h new file mode 100644 index 00000000..80f953cf --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcService.h @@ -0,0 +1,51 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcService_h__ +#define ipcService_h__ + +#include "ipcIService.h" +#include "ipcdclient.h" + +class ipcService : public ipcIService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCISERVICE +}; + +#endif // !defined( ipcService_h__ ) diff --git a/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp new file mode 100644 index 00000000..ce0f86c8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/client/src/ipcdclient.cpp @@ -0,0 +1,1505 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcdclient.h" +#include "ipcConnection.h" +#include "ipcConfig.h" +#include "ipcMessageQ.h" +#include "ipcMessageUtils.h" +#include "ipcLog.h" +#include "ipcm.h" + +#include "nsIFile.h" +#include "nsEventQueueUtils.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCOMPtr.h" +#include "nsHashKeys.h" +#include "nsRefPtrHashtable.h" +#include "nsAutoLock.h" +#include "nsProxyRelease.h" +#include "nsCOMArray.h" + +#include "prio.h" +#include "prproces.h" +#include "pratom.h" + +#ifdef VBOX +# include +# define VBOX_WITH_IPCCLIENT_RW_CS +#endif + +/* ------------------------------------------------------------------------- */ + +#define IPC_REQUEST_TIMEOUT PR_SecondsToInterval(30) + +/* ------------------------------------------------------------------------- */ + +class ipcTargetData +{ +public: + static NS_HIDDEN_(ipcTargetData*) Create(); + + // threadsafe addref/release + NS_HIDDEN_(nsrefcnt) AddRef() { return PR_AtomicIncrement(&refcnt); } + NS_HIDDEN_(nsrefcnt) Release() { PRInt32 r = PR_AtomicDecrement(&refcnt); if (r == 0) delete this; return r; } + + NS_HIDDEN_(void) SetObserver(ipcIMessageObserver *aObserver, PRBool aOnCurrentThread); + + // protects access to the members of this class + PRMonitor *monitor; + + // this may be null + nsCOMPtr observer; + + // the message observer is called via this event queue + nsCOMPtr eventQ; + + // incoming messages are added to this list + ipcMessageQ pendingQ; + + // non-zero if the observer has been disabled (this means that new messages + // should not be dispatched to the observer until the observer is re-enabled + // via IPC_EnableMessageObserver). + PRInt32 observerDisabled; + +private: + + ipcTargetData() + : monitor(nsAutoMonitor::NewMonitor("ipcTargetData")) + , observerDisabled(0) + , refcnt(0) + {} + + ~ipcTargetData() + { + if (monitor) + nsAutoMonitor::DestroyMonitor(monitor); + } + + PRInt32 refcnt; +}; + +ipcTargetData * +ipcTargetData::Create() +{ + ipcTargetData *td = new ipcTargetData; + if (!td) + return NULL; + + if (!td->monitor) + { + delete td; + return NULL; + } + return td; +} + +void +ipcTargetData::SetObserver(ipcIMessageObserver *aObserver, PRBool aOnCurrentThread) +{ + observer = aObserver; + + if (aOnCurrentThread) + NS_GetCurrentEventQ(getter_AddRefs(eventQ)); + else + eventQ = nsnull; +} + +/* ------------------------------------------------------------------------- */ + +typedef nsRefPtrHashtable ipcTargetMap; + +class ipcClientState +{ +public: + static NS_HIDDEN_(ipcClientState *) Create(); + + ~ipcClientState() + { +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + if (monitor) + nsAutoMonitor::DestroyMonitor(monitor); +#else + RTCritSectRwDelete(&critSect); +#endif + } + +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + // + // the monitor protects the targetMap and the connected and shutdown flags. + // + // NOTE: we use a PRMonitor for this instead of a PRLock because we need + // the lock to be re-entrant. since we don't ever need to wait on + // this monitor, it might be worth it to implement a re-entrant + // wrapper for PRLock. + // + PRMonitor *monitor; +#else /* VBOX_WITH_IPCCLIENT_RW_CS */ + RTCRITSECTRW critSect; +#endif /* VBOX_WITH_IPCCLIENT_RW_CS */ + ipcTargetMap targetMap; + PRBool connected; + PRBool shutdown; + + // our process's client id + PRUint32 selfID; + + nsCOMArray clientObservers; + +private: + + ipcClientState() +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + : monitor(nsAutoMonitor::NewMonitor("ipcClientState")) + , connected(PR_FALSE) +#else + : connected(PR_FALSE) +#endif + , shutdown(PR_FALSE) + , selfID(0) + { +#ifdef VBOX_WITH_IPCCLIENT_RW_CS + /* Not employing the lock validator here to keep performance up in debug builds. */ + RTCritSectRwInitEx(&critSect, RTCRITSECT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL); +#endif + } +}; + +ipcClientState * +ipcClientState::Create() +{ + ipcClientState *cs = new ipcClientState; + if (!cs) + return NULL; + +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + if (!cs->monitor || !cs->targetMap.Init()) +#else + if (!RTCritSectRwIsInitialized(&cs->critSect) || !cs->targetMap.Init()) +#endif + { + delete cs; + return NULL; + } + + return cs; +} + +/* ------------------------------------------------------------------------- */ + +static ipcClientState *gClientState; + +static PRBool +GetTarget(const nsID &aTarget, ipcTargetData **td) +{ +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); + return gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td); +#else + RTCritSectRwEnterShared(&gClientState->critSect); + PRBool fRc = gClientState->targetMap.Get(nsIDHashKey(&aTarget).GetKey(), td); + RTCritSectRwLeaveShared(&gClientState->critSect); + return fRc; +#endif +} + +static PRBool +PutTarget(const nsID &aTarget, ipcTargetData *td) +{ +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); + return gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td); +#else + RTCritSectRwEnterExcl(&gClientState->critSect); + PRBool fRc = gClientState->targetMap.Put(nsIDHashKey(&aTarget).GetKey(), td); + RTCritSectRwLeaveExcl(&gClientState->critSect); + return fRc; +#endif +} + +static void +DelTarget(const nsID &aTarget) +{ +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); + gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey()); +#else + RTCritSectRwEnterExcl(&gClientState->critSect); + gClientState->targetMap.Remove(nsIDHashKey(&aTarget).GetKey()); + RTCritSectRwLeaveExcl(&gClientState->critSect); +#endif +} + +/* ------------------------------------------------------------------------- */ + +static nsresult +GetDaemonPath(nsCString &dpath) +{ + nsCOMPtr file; + + nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, + getter_AddRefs(file)); + if (NS_SUCCEEDED(rv)) + { + rv = file->AppendNative(NS_LITERAL_CSTRING(IPC_DAEMON_APP_NAME)); + if (NS_SUCCEEDED(rv)) + rv = file->GetNativePath(dpath); + } + + return rv; +} + +/* ------------------------------------------------------------------------- */ + +static void +ProcessPendingQ(const nsID &aTarget) +{ + ipcMessageQ tempQ; + + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + nsAutoMonitor mon(td->monitor); + + // if the observer for this target has been temporarily disabled, then + // we must not processing any pending messages at this time. + + if (!td->observerDisabled) + td->pendingQ.MoveTo(tempQ); + } + + // process pending queue outside monitor + while (!tempQ.IsEmpty()) + { + ipcMessage *msg = tempQ.First(); + + // it is possible that messages for other targets are in the queue + // (currently, this can be only a IPCM_MSG_PSH_CLIENT_STATE message + // initially addressed to IPCM_TARGET, see IPC_OnMessageAvailable()) + // --ignore them. + if (td->observer && msg->Target().Equals(aTarget)) + td->observer->OnMessageAvailable(msg->mMetaData, + msg->Target(), + (const PRUint8 *) msg->Data(), + msg->DataLen()); + else + { + // the IPCM target does not have an observer, and therefore any IPCM + // messages that make it here will simply be dropped. + NS_ASSERTION(aTarget.Equals(IPCM_TARGET) || msg->Target().Equals(IPCM_TARGET), + "unexpected target"); + LOG(("dropping IPCM message: type=%x\n", IPCM_GetType(msg))); + } + tempQ.DeleteFirst(); + } +} + +/* ------------------------------------------------------------------------- */ + +// WaitTarget enables support for multiple threads blocking on the same +// message target. the selector is called while inside the target's monitor. + +typedef nsresult (* ipcMessageSelector)( + void *arg, + ipcTargetData *td, + const ipcMessage *msg +); + +// selects any +static nsresult +DefaultSelector(void *arg, ipcTargetData *td, const ipcMessage *msg) +{ + return NS_OK; +} + +static nsresult +WaitTarget(const nsID &aTarget, + PRIntervalTime aTimeout, + ipcMessage **aMsg, + ipcMessageSelector aSelector = nsnull, + void *aArg = nsnull) +{ + *aMsg = nsnull; + + if (!aSelector) + aSelector = DefaultSelector; + + nsRefPtr td; + if (!GetTarget(aTarget, getter_AddRefs(td))) + return NS_ERROR_INVALID_ARG; // bad aTarget + + PRBool isIPCMTarget = aTarget.Equals(IPCM_TARGET); + + PRIntervalTime timeStart = PR_IntervalNow(); + PRIntervalTime timeEnd; + if (aTimeout == PR_INTERVAL_NO_TIMEOUT) + timeEnd = aTimeout; + else if (aTimeout == PR_INTERVAL_NO_WAIT) + timeEnd = timeStart; + else + { + timeEnd = timeStart + aTimeout; + + // if overflowed, then set to max value + if (timeEnd < timeStart) + timeEnd = PR_INTERVAL_NO_TIMEOUT; + } + + ipcMessage *lastChecked = nsnull, *beforeLastChecked = nsnull; + nsresult rv = NS_ERROR_ABORT; + + nsAutoMonitor mon(td->monitor); + + // only the ICPM target is allowed to wait for a message after shutdown + // (but before disconnection). this gives client observers called from + // IPC_Shutdown a chance to use IPC_SendMessage to send necessary + // "last minute" messages to other clients. + + while (gClientState->connected && (!gClientState->shutdown || isIPCMTarget)) + { + NS_ASSERTION(!lastChecked, "oops"); + + // + // NOTE: + // + // we must start at the top of the pending queue, possibly revisiting + // messages that our selector has already rejected. this is necessary + // because the queue may have been modified while we were waiting on + // the monitor. the impact of this on performance remains to be seen. + // + // one cheap solution is to keep a counter that is incremented each + // time a message is removed from the pending queue. that way we can + // avoid revisiting all messages sometimes. + // + + lastChecked = td->pendingQ.First(); + beforeLastChecked = nsnull; + + // loop over pending queue until we find a message that our selector likes. + while (lastChecked) + { + // + // it is possible that this call to WaitTarget() has been initiated by + // some other selector, that might be currently processing the same + // message (since the message remains in the queue until the selector + // returns TRUE). here we prevent this situation by using a special flag + // to guarantee that every message is processed only once. + // + + if (!lastChecked->TestFlag(IPC_MSG_FLAG_IN_PROCESS)) + { + lastChecked->SetFlag(IPC_MSG_FLAG_IN_PROCESS); + nsresult acceptedRV = (aSelector)(aArg, td, lastChecked); + lastChecked->ClearFlag(IPC_MSG_FLAG_IN_PROCESS); + + if (acceptedRV != IPC_WAIT_NEXT_MESSAGE) + { + if (acceptedRV == NS_OK) + { + // remove from pending queue + if (beforeLastChecked) + td->pendingQ.RemoveAfter(beforeLastChecked); + else + td->pendingQ.RemoveFirst(); + + lastChecked->mNext = nsnull; + *aMsg = lastChecked; + break; + } + else /* acceptedRV == IPC_DISCARD_MESSAGE */ + { + ipcMessage *nextToCheck = lastChecked->mNext; + + // discard from pending queue + if (beforeLastChecked) + td->pendingQ.DeleteAfter(beforeLastChecked); + else + td->pendingQ.DeleteFirst(); + + lastChecked = nextToCheck; + + continue; + } + } + } + + beforeLastChecked = lastChecked; + lastChecked = lastChecked->mNext; + } + + if (*aMsg) + { + rv = NS_OK; + break; + } +#ifdef VBOX + else + { + /* Special client liveness check if there is no message to process. + * This is necessary as there might be several threads waiting for + * a message from a single client, and only one gets the DOWN msg. */ + nsresult aliveRV = (aSelector)(aArg, td, NULL); + if (aliveRV != IPC_WAIT_NEXT_MESSAGE) + { + *aMsg = NULL; + break; + } + } +#endif /* VBOX */ + + PRIntervalTime t = PR_IntervalNow(); + if (t > timeEnd) // check if timeout has expired + { + rv = IPC_ERROR_WOULD_BLOCK; + break; + } + mon.Wait(timeEnd - t); + + LOG(("woke up from sleep [pendingQempty=%d connected=%d shutdown=%d isIPCMTarget=%d]\n", + td->pendingQ.IsEmpty(), gClientState->connected, + gClientState->shutdown, isIPCMTarget)); + } + + return rv; +} + +/* ------------------------------------------------------------------------- */ + +static void +PostEvent(nsIEventTarget *eventTarget, PLEvent *ev) +{ + if (!ev) + return; + + nsresult rv = eventTarget->PostEvent(ev); + if (NS_FAILED(rv)) + { + NS_WARNING("PostEvent failed"); + PL_DestroyEvent(ev); + } +} + +static void +PostEventToMainThread(PLEvent *ev) +{ + nsCOMPtr eventQ; + NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (!eventQ) + { + NS_WARNING("unable to get reference to main event queue"); + PL_DestroyEvent(ev); + return; + } + PostEvent(eventQ, ev); +} + +/* ------------------------------------------------------------------------- */ + +class ipcEvent_ClientState : public PLEvent +{ +public: + ipcEvent_ClientState(PRUint32 aClientID, PRUint32 aClientState) + : mClientID(aClientID) + , mClientState(aClientState) + { + PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent); + } + + PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev) + { + // maybe we've been shutdown! + if (!gClientState) + return nsnull; + + ipcEvent_ClientState *self = (ipcEvent_ClientState *) ev; + + for (PRInt32 i=0; iclientObservers.Count(); ++i) + gClientState->clientObservers[i]->OnClientStateChange(self->mClientID, + self->mClientState); + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev) + { + delete (ipcEvent_ClientState *) ev; + } + +private: + PRUint32 mClientID; + PRUint32 mClientState; +}; + +/* ------------------------------------------------------------------------- */ + +class ipcEvent_ProcessPendingQ : public PLEvent +{ +public: + ipcEvent_ProcessPendingQ(const nsID &aTarget) + : mTarget(aTarget) + { + PL_InitEvent(this, nsnull, HandleEvent, DestroyEvent); + } + + PR_STATIC_CALLBACK(void *) HandleEvent(PLEvent *ev) + { + ProcessPendingQ(((ipcEvent_ProcessPendingQ *) ev)->mTarget); + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyEvent(PLEvent *ev) + { + delete (ipcEvent_ProcessPendingQ *) ev; + } + +private: + const nsID mTarget; +}; + +static void +CallProcessPendingQ(const nsID &target, ipcTargetData *td) +{ + // we assume that we are inside td's monitor + + PLEvent *ev = new ipcEvent_ProcessPendingQ(target); + if (!ev) + return; + + nsresult rv; + + if (td->eventQ) + rv = td->eventQ->PostEvent(ev); + else + rv = IPC_DoCallback((ipcCallbackFunc) PL_HandleEvent, ev); + + if (NS_FAILED(rv)) + PL_DestroyEvent(ev); +} + +/* ------------------------------------------------------------------------- */ + +static void +DisableMessageObserver(const nsID &aTarget) +{ + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + nsAutoMonitor mon(td->monitor); + ++td->observerDisabled; + } +} + +static void +EnableMessageObserver(const nsID &aTarget) +{ + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + nsAutoMonitor mon(td->monitor); + if (td->observerDisabled > 0 && --td->observerDisabled == 0) + if (!td->pendingQ.IsEmpty()) + CallProcessPendingQ(aTarget, td); + } +} + +/* ------------------------------------------------------------------------- */ + +// converts IPCM_ERROR_* status codes to NS_ERROR_* status codes +static nsresult nsresult_from_ipcm_result(PRInt32 status) +{ + nsresult rv = NS_ERROR_FAILURE; + + switch (status) + { + case IPCM_ERROR_GENERIC: rv = NS_ERROR_FAILURE; break; + case IPCM_ERROR_INVALID_ARG: rv = NS_ERROR_INVALID_ARG; break; + case IPCM_ERROR_NO_CLIENT: rv = NS_ERROR_CALL_FAILED; break; + // TODO: select better mapping for the below codes + case IPCM_ERROR_NO_SUCH_DATA: + case IPCM_ERROR_ALREADY_EXISTS: rv = NS_ERROR_FAILURE; break; + default: NS_ASSERTION(PR_FALSE, "No conversion"); + } + + return rv; +} + +/* ------------------------------------------------------------------------- */ + +// selects the next IPCM message with matching request index +static nsresult +WaitIPCMResponseSelector(void *arg, ipcTargetData *td, const ipcMessage *msg) +{ +#ifdef VBOX + if (!msg) + return IPC_WAIT_NEXT_MESSAGE; +#endif /* VBOX */ + PRUint32 requestIndex = *(PRUint32 *) arg; + return IPCM_GetRequestIndex(msg) == requestIndex ? NS_OK : IPC_WAIT_NEXT_MESSAGE; +} + +// wait for an IPCM response message. if responseMsg is null, then it is +// assumed that the caller does not care to get a reference to the +// response itself. if the response is an IPCM_MSG_ACK_RESULT, then the +// status code is mapped to a nsresult and returned by this function. +static nsresult +WaitIPCMResponse(PRUint32 requestIndex, ipcMessage **responseMsg = nsnull) +{ + ipcMessage *msg; + + nsresult rv = WaitTarget(IPCM_TARGET, IPC_REQUEST_TIMEOUT, &msg, + WaitIPCMResponseSelector, &requestIndex); + if (NS_FAILED(rv)) + return rv; + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_RESULT) + { + ipcMessageCast result(msg); + if (result->Status() < 0) + rv = nsresult_from_ipcm_result(result->Status()); + else + rv = NS_OK; + } + + if (responseMsg) + *responseMsg = msg; + else + delete msg; + + return rv; +} + +// make an IPCM request and wait for a response. +static nsresult +MakeIPCMRequest(ipcMessage *msg, ipcMessage **responseMsg = nsnull) +{ + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 requestIndex = IPCM_GetRequestIndex(msg); + + // suppress 'ProcessPendingQ' for IPCM messages until we receive the + // response to this IPCM request. if we did not do this then there + // would be a race condition leading to the possible removal of our + // response from the pendingQ between sending the request and waiting + // for the response. + DisableMessageObserver(IPCM_TARGET); + + nsresult rv = IPC_SendMsg(msg); + if (NS_SUCCEEDED(rv)) + rv = WaitIPCMResponse(requestIndex, responseMsg); + + EnableMessageObserver(IPCM_TARGET); + return rv; +} + +/* ------------------------------------------------------------------------- */ + +static void +RemoveTarget(const nsID &aTarget, PRBool aNotifyDaemon) +{ + DelTarget(aTarget); + + if (aNotifyDaemon) + { + nsresult rv = MakeIPCMRequest(new ipcmMessageClientDelTarget(aTarget)); + if (NS_FAILED(rv)) + LOG(("failed to delete target: rv=%x\n", rv)); + } +} + +static nsresult +DefineTarget(const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRBool aOnCurrentThread, + PRBool aNotifyDaemon, + ipcTargetData **aResult) +{ + nsresult rv; + + nsRefPtr td( ipcTargetData::Create() ); + if (!td) + return NS_ERROR_OUT_OF_MEMORY; + td->SetObserver(aObserver, aOnCurrentThread); + + if (!PutTarget(aTarget, td)) + return NS_ERROR_OUT_OF_MEMORY; + + if (aNotifyDaemon) + { + rv = MakeIPCMRequest(new ipcmMessageClientAddTarget(aTarget)); + if (NS_FAILED(rv)) + { + LOG(("failed to add target: rv=%x\n", rv)); + RemoveTarget(aTarget, PR_FALSE); + return rv; + } + } + + if (aResult) + NS_ADDREF(*aResult = td); + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +static nsresult +TryConnect() +{ + nsCAutoString dpath; + nsresult rv = GetDaemonPath(dpath); + if (NS_FAILED(rv)) + return rv; + + rv = IPC_Connect(dpath.get()); + if (NS_FAILED(rv)) + return rv; + + gClientState->connected = PR_TRUE; + + rv = DefineTarget(IPCM_TARGET, nsnull, PR_FALSE, PR_FALSE, nsnull); + if (NS_FAILED(rv)) + return rv; + + ipcMessage *msg = NULL; + + // send CLIENT_HELLO and wait for CLIENT_ID response... + rv = MakeIPCMRequest(new ipcmMessageClientHello(), &msg); + if (NS_FAILED(rv)) + { +#ifdef VBOX /* MakeIPCMRequest may return a failure (e.g. NS_ERROR_CALL_FAILED) and a response msg. */ + if (msg) + delete msg; +#endif + return rv; + } + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID) + gClientState->selfID = ipcMessageCast(msg)->ClientID(); + else + { + LOG(("unexpected response from CLIENT_HELLO message: type=%x!\n", + IPCM_GetType(msg))); + rv = NS_ERROR_UNEXPECTED; + } + + delete msg; + return rv; +} + +nsresult +IPC_Init() +{ + NS_ENSURE_TRUE(!gClientState, NS_ERROR_ALREADY_INITIALIZED); + + IPC_InitLog(">>>"); + + gClientState = ipcClientState::Create(); + if (!gClientState) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = TryConnect(); + if (NS_FAILED(rv)) + IPC_Shutdown(); + + return rv; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +EnumerateTargetMapAndNotify(const nsID &aKey, + ipcTargetData *aData, + void *aClosure); + +nsresult +IPC_Shutdown() +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + LOG(("IPC_Shutdown: connected=%d\n",gClientState->connected)); + + if (gClientState->connected) + { + { + // first, set the shutdown flag and unblock any calls to WaitTarget. + // all targets but IPCM will not be able to use WaitTarget any more. + +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); +#else + RTCritSectRwEnterExcl(&gClientState->critSect); +#endif + + gClientState->shutdown = PR_TRUE; + gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull); + +#ifdef VBOX_WITH_IPCCLIENT_RW_CS + RTCritSectRwLeaveExcl(&gClientState->critSect); +#endif + } + + // inform all client observers that we're being shutdown to let interested + // parties gracefully uninitialize themselves. the IPCM target is still + // fully operational at this point, so they can use IPC_SendMessage + // (this is essential for the DConnect extension, for example, to do the + // proper uninitialization). + + ipcEvent_ClientState *ev = new ipcEvent_ClientState(IPC_SENDER_ANY, + IPCM_CLIENT_STATE_DOWN); + ipcEvent_ClientState::HandleEvent (ev); + ipcEvent_ClientState::DestroyEvent (ev); + + IPC_Disconnect(); + } + + // + // make gClientState nsnull before deletion to cause all public IPC_* + // calls (possibly made during ipcClientState destruction) to return + // NS_ERROR_NOT_INITIALIZED. + // + // NOTE: isn't just checking for gClientState->connected in every appropriate + // IPC_* method a better solution? + // + ipcClientState *aClientState = gClientState; + gClientState = nsnull; + delete aClientState; + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_DefineTarget(const nsID &aTarget, + ipcIMessageObserver *aObserver, + PRBool aOnCurrentThread) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit the re-definition of the IPCM protocol's target. + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + + nsRefPtr td; + if (GetTarget(aTarget, getter_AddRefs(td))) + { + // clear out observer before removing target since we want to ensure that + // the observer is released on the main thread. + { + nsAutoMonitor mon(td->monitor); + td->SetObserver(aObserver, aOnCurrentThread); + } + + // remove target outside of td's monitor to avoid holding the monitor + // while entering the client state's monitor. + if (!aObserver) + RemoveTarget(aTarget, PR_TRUE); + + rv = NS_OK; + } + else + { + if (aObserver) + rv = DefineTarget(aTarget, aObserver, aOnCurrentThread, PR_TRUE, nsnull); + else + rv = NS_ERROR_INVALID_ARG; // unknown target + } + + return rv; +} + +nsresult +IPC_DisableMessageObserver(const nsID &aTarget) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit modifications to the IPCM protocol's target. + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + DisableMessageObserver(aTarget); + return NS_OK; +} + +nsresult +IPC_EnableMessageObserver(const nsID &aTarget) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit modifications to the IPCM protocol's target. + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + EnableMessageObserver(aTarget); + return NS_OK; +} + +nsresult +IPC_SendMessage(PRUint32 aReceiverID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit sending IPCM messages + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + if (aReceiverID == 0) + { + ipcMessage *msg = new ipcMessage(aTarget, (const char *) aData, aDataLen); + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + + rv = IPC_SendMsg(msg); + } + else + rv = MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD, + aReceiverID, + aTarget, + (const char *) aData, + aDataLen)); + + return rv; +} + +struct WaitMessageSelectorData +{ + PRUint32 senderID; + ipcIMessageObserver *observer; + PRBool senderDead; +}; + +static nsresult WaitMessageSelector(void *arg, ipcTargetData *td, const ipcMessage *msg) +{ + WaitMessageSelectorData *data = (WaitMessageSelectorData *) arg; +#ifdef VBOX + if (!msg) + { + /* Special NULL message which asks to check whether the client is + * still alive. Called when there is nothing suitable in the queue. */ + ipcIMessageObserver *obs = data->observer; + if (!obs) + obs = td->observer; + NS_ASSERTION(obs, "must at least have a default observer"); + + nsresult rv = obs->OnMessageAvailable(IPC_SENDER_ANY, nsID(), 0, 0); + if (rv != IPC_WAIT_NEXT_MESSAGE) + data->senderDead = PR_TRUE; + + return rv; + } +#endif /* VBOX */ + + // process the specially forwarded client state message to see if the + // sender we're waiting a message from has died. + + if (msg->Target().Equals(IPCM_TARGET)) + { + switch (IPCM_GetType(msg)) + { + case IPCM_MSG_PSH_CLIENT_STATE: + { + ipcMessageCast status(msg); + if ((data->senderID == IPC_SENDER_ANY || + status->ClientID() == data->senderID) && + status->ClientState() == IPCM_CLIENT_STATE_DOWN) + { + LOG(("sender (%d) we're waiting a message from (%d) has died\n", + status->ClientID(), data->senderID)); + + if (data->senderID != IPC_SENDER_ANY) + { + // we're waiting on a particular client, so IPC_WaitMessage must + // definitely fail with the NS_ERROR_xxx result. + + data->senderDead = PR_TRUE; + return IPC_DISCARD_MESSAGE; // consume the message + } + else + { + // otherwise inform the observer about the client death using a special + // null message with an empty target id, and fail IPC_WaitMessage call + // with NS_ERROR_xxx only if the observer accepts this message. + + ipcIMessageObserver *obs = data->observer; + if (!obs) + obs = td->observer; + NS_ASSERTION(obs, "must at least have a default observer"); + + nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 0); + if (rv != IPC_WAIT_NEXT_MESSAGE) + data->senderDead = PR_TRUE; + + return IPC_DISCARD_MESSAGE; // consume the message + } + } +#ifdef VBOX + else if ((data->senderID == IPC_SENDER_ANY || + status->ClientID() == data->senderID) && + status->ClientState() == IPCM_CLIENT_STATE_UP) + { + LOG(("sender (%d) we're waiting a message from (%d) has come up\n", + status->ClientID(), data->senderID)); + if (data->senderID == IPC_SENDER_ANY) + { + // inform the observer about the client appearance using a special + // null message with an empty target id, but a length of 1. + + ipcIMessageObserver *obs = data->observer; + if (!obs) + obs = td->observer; + NS_ASSERTION(obs, "must at least have a default observer"); + + nsresult rv = obs->OnMessageAvailable(status->ClientID(), nsID(), 0, 1); + /* VBoxSVC/VBoxXPCOMIPCD auto-start can cause that a client up + * message arrives while we're already waiting for a response + * from this client. Don't declare the connection as dead in + * this case. A client ID wraparound can't falsely trigger + * this, since the waiting thread would have hit the liveness + * check in the mean time. We MUST consume the message, otherwise + * IPCM messages pile up as long as there is a pending call, which + * can lead to severe processing overhead. */ + return IPC_DISCARD_MESSAGE; // consume the message + } + } +#endif /* VBOX */ + break; + } + default: + NS_NOTREACHED("unexpected message"); + } + return IPC_WAIT_NEXT_MESSAGE; // continue iterating + } + + nsresult rv = IPC_WAIT_NEXT_MESSAGE; + + if (data->senderID == IPC_SENDER_ANY || + msg->mMetaData == data->senderID) + { + ipcIMessageObserver *obs = data->observer; + if (!obs) + obs = td->observer; + NS_ASSERTION(obs, "must at least have a default observer"); + + rv = obs->OnMessageAvailable(msg->mMetaData, + msg->Target(), + (const PRUint8 *) msg->Data(), + msg->DataLen()); + } + + // stop iterating if we got a match that the observer accepted. + return rv != IPC_WAIT_NEXT_MESSAGE ? NS_OK : IPC_WAIT_NEXT_MESSAGE; +} + +nsresult +IPC_WaitMessage(PRUint32 aSenderID, + const nsID &aTarget, + ipcIMessageObserver *aObserver, + ipcIMessageObserver *aConsumer, + PRIntervalTime aTimeout) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + // do not permit waiting for IPCM messages + if (aTarget.Equals(IPCM_TARGET)) + return NS_ERROR_INVALID_ARG; + + // use aObserver as the message selector + WaitMessageSelectorData data = { aSenderID, aObserver, PR_FALSE }; + + ipcMessage *msg; + nsresult rv = WaitTarget(aTarget, aTimeout, &msg, WaitMessageSelector, &data); + if (NS_FAILED(rv)) + return rv; + + // if the selector has accepted some message, then we pass it to aConsumer + // for safe processing. The IPC susbsystem is quite stable here (i.e. we're + // not inside any of the monitors, and the message has been already removed + // from the pending queue). + if (aObserver && aConsumer) + { + aConsumer->OnMessageAvailable(msg->mMetaData, + msg->Target(), + (const PRUint8 *) msg->Data(), + msg->DataLen()); + } + + delete msg; + + // if the requested sender has died while waiting, return an error + if (data.senderDead) + return NS_ERROR_ABORT; // XXX better error code? + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_GetID(PRUint32 *aClientID) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + *aClientID = gClientState->selfID; + return NS_OK; +} + +nsresult +IPC_AddName(const char *aName) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return MakeIPCMRequest(new ipcmMessageClientAddName(aName)); +} + +nsresult +IPC_RemoveName(const char *aName) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return MakeIPCMRequest(new ipcmMessageClientDelName(aName)); +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_AddClientObserver(ipcIClientObserver *aObserver) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + return gClientState->clientObservers.AppendObject(aObserver) + ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +IPC_RemoveClientObserver(ipcIClientObserver *aObserver) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + for (PRInt32 i = 0; i < gClientState->clientObservers.Count(); ++i) + { + if (gClientState->clientObservers[i] == aObserver) + gClientState->clientObservers.RemoveObjectAt(i); + } + + return NS_OK; +} + +/* ------------------------------------------------------------------------- */ + +// this function could be called on any thread +nsresult +IPC_ResolveClientName(const char *aName, PRUint32 *aClientID) +{ + NS_ENSURE_TRUE(gClientState, NS_ERROR_NOT_INITIALIZED); + + ipcMessage *msg = NULL; + + nsresult rv = MakeIPCMRequest(new ipcmMessageQueryClientByName(aName), &msg); + if (NS_FAILED(rv)) + { +#ifdef VBOX /* MakeIPCMRequest may return a failure (e.g. NS_ERROR_CALL_FAILED) and a response msg. */ + if (msg) + delete msg; +#endif + return rv; + } + + if (IPCM_GetType(msg) == IPCM_MSG_ACK_CLIENT_ID) + *aClientID = ipcMessageCast(msg)->ClientID(); + else + { + LOG(("unexpected IPCM response: type=%x\n", IPCM_GetType(msg))); + rv = NS_ERROR_UNEXPECTED; + } + + delete msg; + return rv; +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_ClientExists(PRUint32 aClientID, PRBool *aResult) +{ + // this is a bit of a hack. we forward a PING to the specified client. + // the assumption is that the forwarding will only succeed if the client + // exists, so we wait for the RESULT message corresponding to the FORWARD + // request. if that gives a successful status, then we know that the + // client exists. + + ipcmMessagePing ping; + + return MakeIPCMRequest(new ipcmMessageForward(IPCM_MSG_REQ_FORWARD, + aClientID, + IPCM_TARGET, + ping.Data(), + ping.DataLen())); +} + +/* ------------------------------------------------------------------------- */ + +nsresult +IPC_SpawnDaemon(const char *path) +{ + PRFileDesc *readable = nsnull, *writable = nsnull; + PRProcessAttr *attr = nsnull; + nsresult rv = NS_ERROR_FAILURE; + PRFileDesc *devNull; + char *const argv[] = { (char *const) path, nsnull }; + char c; + + // setup an anonymous pipe that we can use to determine when the daemon + // process has started up. the daemon will write a char to the pipe, and + // when we read it, we'll know to proceed with trying to connect to the + // daemon. + + if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS) + goto end; + PR_SetFDInheritable(writable, PR_TRUE); + + attr = PR_NewProcessAttr(); + if (!attr) + goto end; + + if (PR_ProcessAttrSetInheritableFD(attr, writable, IPC_STARTUP_PIPE_NAME) != PR_SUCCESS) + goto end; + + devNull = PR_Open("/dev/null", PR_RDWR, 0); + if (!devNull) + goto end; + + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull); + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull); + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull); + + if (PR_CreateProcessDetached(path, argv, nsnull, attr) != PR_SUCCESS) + goto end; + + // Close /dev/null + PR_Close(devNull); + // close the child end of the pipe in order to get notification on unexpected + // child termination instead of being infinitely blocked in PR_Read(). + PR_Close(writable); + writable = nsnull; + + if ((PR_Read(readable, &c, 1) != 1) || (c != IPC_STARTUP_PIPE_MAGIC)) + goto end; + + rv = NS_OK; +end: + if (readable) + PR_Close(readable); + if (writable) + PR_Close(writable); + if (attr) + PR_DestroyProcessAttr(attr); + return rv; +} + +/* ------------------------------------------------------------------------- */ + +PR_STATIC_CALLBACK(PLDHashOperator) +EnumerateTargetMapAndNotify(const nsID &aKey, + ipcTargetData *aData, + void *aClosure) +{ + nsAutoMonitor mon(aData->monitor); + + // wake up anyone waiting on this target. + mon.NotifyAll(); + + return PL_DHASH_NEXT; +} + +// called on a background thread +void +IPC_OnConnectionEnd(nsresult error) +{ + // now, go through the target map, and tickle each monitor. that should + // unblock any calls to WaitTarget. + +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); +#else + RTCritSectRwEnterExcl(&gClientState->critSect); +#endif + + gClientState->connected = PR_FALSE; + gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndNotify, nsnull); + +#ifdef VBOX_WITH_IPCCLIENT_RW_CS + RTCritSectRwLeaveExcl(&gClientState->critSect); +#endif +} + +/* ------------------------------------------------------------------------- */ + +static void +PlaceOnPendingQ(const nsID &target, ipcTargetData *td, ipcMessage *msg) +{ + nsAutoMonitor mon(td->monitor); + + // we only want to dispatch a 'ProcessPendingQ' event if we have not + // already done so. + PRBool dispatchEvent = td->pendingQ.IsEmpty(); + + // put this message on our pending queue + td->pendingQ.Append(msg); + +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + char *targetStr = target.ToString(); + LOG(("placed message on pending queue for target %s and notifying all...\n", targetStr)); + nsMemory::Free(targetStr); + } +#endif + + // wake up anyone waiting on this queue + mon.NotifyAll(); + + // proxy call to target's message procedure + if (dispatchEvent) + CallProcessPendingQ(target, td); +} + +PR_STATIC_CALLBACK(PLDHashOperator) +EnumerateTargetMapAndPlaceMsg(const nsID &aKey, + ipcTargetData *aData, + void *userArg) +{ + if (!aKey.Equals(IPCM_TARGET)) + { + // place a message clone to a target's event queue + ipcMessage *msg = (ipcMessage *) userArg; + PlaceOnPendingQ(aKey, aData, msg->Clone()); + } + + return PL_DHASH_NEXT; +} + +/* ------------------------------------------------------------------------- */ + +#ifdef IPC_LOGGING +#include "prprf.h" +#include +#endif + +// called on a background thread +void +IPC_OnMessageAvailable(ipcMessage *msg) +{ +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + char *targetStr = msg->Target().ToString(); + LOG(("got message for target: %s\n", targetStr)); + nsMemory::Free(targetStr); + +// IPC_LogBinary((const PRUint8 *) msg->Data(), msg->DataLen()); + } +#endif + + if (msg->Target().Equals(IPCM_TARGET)) + { + switch (IPCM_GetType(msg)) + { + // if this is a forwarded message, then post the inner message instead. + case IPCM_MSG_PSH_FORWARD: + { + ipcMessageCast fwd(msg); + ipcMessage *innerMsg = new ipcMessage(fwd->InnerTarget(), + fwd->InnerData(), + fwd->InnerDataLen()); + // store the sender's client id in the meta-data field of the message. + innerMsg->mMetaData = fwd->ClientID(); + + delete msg; + + // recurse so we can handle forwarded IPCM messages + IPC_OnMessageAvailable(innerMsg); + return; + } + case IPCM_MSG_PSH_CLIENT_STATE: + { + ipcMessageCast status(msg); + PostEventToMainThread(new ipcEvent_ClientState(status->ClientID(), + status->ClientState())); + + // go through the target map, and place this message to every target's + // pending event queue. that unblocks all WaitTarget calls (on all + // targets) giving them an opportuninty to finish wait cycle because of + // the peer client death, when appropriate. +#ifndef VBOX_WITH_IPCCLIENT_RW_CS + nsAutoMonitor mon(gClientState->monitor); +#else + RTCritSectRwEnterShared(&gClientState->critSect); +#endif + + gClientState->targetMap.EnumerateRead(EnumerateTargetMapAndPlaceMsg, msg); + +#ifdef VBOX_WITH_IPCCLIENT_RW_CS + RTCritSectRwLeaveShared(&gClientState->critSect); +#endif + delete msg; + + return; + } + } + } + + nsRefPtr td; + if (GetTarget(msg->Target(), getter_AddRefs(td))) + { + // make copy of target since |msg| may end up pointing to free'd memory + // once we notify the monitor inside PlaceOnPendingQ(). + const nsID target = msg->Target(); + + PlaceOnPendingQ(target, td, msg); + } + else + { + NS_WARNING("message target is undefined"); +#ifdef VBOX + delete msg; +#endif + } +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in new file mode 100644 index 00000000..ad1a66b7 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/Makefile.in @@ -0,0 +1,52 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +EXPORTS = \ + ipcModule.h \ + ipcModuleUtil.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h new file mode 100644 index 00000000..2f299f70 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModule.h @@ -0,0 +1,240 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcModule_h__ +#define ipcModule_h__ + +#include "nsID.h" + +// +// a client handle is used to efficiently reference a client instance object +// used by the daemon to represent a connection with a particular client app. +// +// modules should treat it as an opaque type. +// +typedef class ipcClient *ipcClientHandle; + +//----------------------------------------------------------------------------- +// interface implemented by the module: +//----------------------------------------------------------------------------- + +// +// the version of ipcModuleMethods data structure. +// +#define IPC_MODULE_METHODS_VERSION (1<<16) // 1.0 + +// +// each module defines the following structure: +// +struct ipcModuleMethods +{ + // + // this field holds the version of the data structure, which is always the + // value of IPC_MODULE_METHODS_VERSION against which the module was built. + // + PRUint32 version; + + // + // called after this module is registered. + // + void (* init) (void); + + // + // called when this module will no longer be accessed. + // + void (* shutdown) (void); + + // + // called when a new message arrives for this module. + // + // params: + // client - an opaque "handle" to an object representing the client that + // sent the message. modules should not store the value of this + // beyond the duration fo this function call. (e.g., the handle + // may be invalid after this function call returns.) modules + // wishing to hold onto a reference to a "client" should store + // the client's ID (see IPC_GetClientID). + // target - message target + // data - message data + // dataLen - message data length + // + void (* handleMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called when a new client connects to the IPC daemon. + // + void (* clientUp) (ipcClientHandle client); + + // + // called when a client disconnects from the IPC daemon. + // + void (* clientDown) (ipcClientHandle client); +}; + +//----------------------------------------------------------------------------- +// interface implemented by the daemon: +//----------------------------------------------------------------------------- + +// +// the version of ipcDaemonMethods data structure. +// +#define IPC_DAEMON_METHODS_VERSION (1<<16) // 1.0 + +// +// enumeration functions may return FALSE to stop enumeration. +// +typedef PRBool (* ipcClientEnumFunc) (void *closure, ipcClientHandle client, PRUint32 clientID); +typedef PRBool (* ipcClientNameEnumFunc) (void *closure, ipcClientHandle client, const char *name); +typedef PRBool (* ipcClientTargetEnumFunc) (void *closure, ipcClientHandle client, const nsID &target); + +// +// the daemon provides the following structure: +// +struct ipcDaemonMethods +{ + PRUint32 version; + + // + // called to send a message to another module. + // + // params: + // client - identifies the client from which this message originated. + // target - message target + // data - message data + // dataLen - message data length + // + // returns: + // PR_SUCCESS if message was dispatched. + // PR_FAILURE if message could not be dispatched (possibly because + // no module is registered for the given message target). + // + PRStatus (* dispatchMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called to send a message to a particular client or to broadcast a + // message to all clients. + // + // params: + // client - if null, then broadcast message to all clients. otherwise, + // send message to the client specified. + // target - message target + // data - message data + // dataLen - message data length + // + // returns: + // PR_SUCCESS if message was sent (or queued up to be sent later). + // PR_FAILURE if message could not be sent (possibly because the client + // does not have a registered observer for the msg's target). + // + PRStatus (* sendMsg) (ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + // + // called to lookup a client handle given its client ID. each client has + // a unique ID. + // + ipcClientHandle (* getClientByID) (PRUint32 clientID); + + // + // called to lookup a client by name or alias. names are not necessary + // unique to individual clients. this function returns the client first + // registered under the given name. + // + ipcClientHandle (* getClientByName) (const char *name); + + // + // called to enumerate all clients. + // + void (* enumClients) (ipcClientEnumFunc func, void *closure); + + // + // returns the client ID of the specified client. + // + PRUint32 (* getClientID) (ipcClientHandle client); + + // + // functions for inspecting the names and targets defined for a particular + // client instance. + // + PRBool (* clientHasName) (ipcClientHandle client, const char *name); + PRBool (* clientHasTarget) (ipcClientHandle client, const nsID &target); + void (* enumClientNames) (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure); + void (* enumClientTargets) (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure); +}; + +//----------------------------------------------------------------------------- +// interface exported by a DSO implementing one or more modules: +//----------------------------------------------------------------------------- + +struct ipcModuleEntry +{ + // + // identifies the message target of this module. + // + nsID target; + + // + // module methods + // + ipcModuleMethods *methods; +}; + +//----------------------------------------------------------------------------- + +#define IPC_EXPORT extern "C" NS_EXPORT + +// +// IPC_EXPORT int IPC_GetModules(const ipcDaemonMethods *, const ipcModuleEntry **); +// +// params: +// methods - the daemon's methods +// entries - the module entries defined by the DSO +// +// returns: +// length of the |entries| array. +// +typedef int (* ipcGetModulesFunc) (const ipcDaemonMethods *methods, const ipcModuleEntry **entries); + +#endif // !ipcModule_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h new file mode 100644 index 00000000..0d1703a8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/public/ipcModuleUtil.h @@ -0,0 +1,151 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcModuleUtil_h__ +#define ipcModuleUtil_h__ + +#include "prlog.h" +#include "ipcModule.h" + +extern const ipcDaemonMethods *gIPCDaemonMethods; + +//----------------------------------------------------------------------------- +// inline wrapper functions +// +// these functions may only be called by a module that uses the +// IPC_IMPL_GETMODULES macro. +//----------------------------------------------------------------------------- + +inline PRStatus +IPC_DispatchMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->dispatchMsg(client, target, data, dataLen); +} + +inline PRStatus +IPC_SendMsg(ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->sendMsg(client, target, data, dataLen); +} + +inline ipcClientHandle +IPC_GetClientByID(PRUint32 id) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientByID(id); +} + +inline ipcClientHandle +IPC_GetClientByName(const char *name) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientByName(name); +} + +inline void +IPC_EnumClients(ipcClientEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClients(func, closure); +} + +inline PRUint32 +IPC_GetClientID(ipcClientHandle client) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->getClientID(client); +} + +inline PRBool +IPC_ClientHasName(ipcClientHandle client, const char *name) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->clientHasName(client, name); +} + +inline PRBool +IPC_ClientHasTarget(ipcClientHandle client, const nsID &target) +{ + PR_ASSERT(gIPCDaemonMethods); + return gIPCDaemonMethods->clientHasTarget(client, target); +} + +inline void +IPC_EnumClientNames(ipcClientHandle client, ipcClientNameEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClientNames(client, func, closure); +} + +inline void +IPC_EnumClientTargets(ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure) +{ + PR_ASSERT(gIPCDaemonMethods); + gIPCDaemonMethods->enumClientTargets(client, func, closure); +} + +//----------------------------------------------------------------------------- +// inline composite functions +//----------------------------------------------------------------------------- + +inline PRStatus +IPC_SendMsg(PRUint32 clientID, const nsID &target, const void *data, PRUint32 dataLen) +{ + ipcClient *client = IPC_GetClientByID(clientID); + if (!client) + return PR_FAILURE; + return IPC_SendMsg(client, target, data, dataLen); +} + +//----------------------------------------------------------------------------- +// module factory macros +//----------------------------------------------------------------------------- + +#define IPC_IMPL_GETMODULES(_modName, _modEntries) \ + const ipcDaemonMethods *gIPCDaemonMethods; \ + IPC_EXPORT int \ + IPC_GetModules(const ipcDaemonMethods *dmeths, \ + const ipcModuleEntry **ents) { \ + /* XXX do version checking */ \ + gIPCDaemonMethods = dmeths; \ + *ents = _modEntries; \ + return sizeof(_modEntries) / sizeof(ipcModuleEntry); \ + } + +#endif // !ipcModuleUtil_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore new file mode 100644 index 00000000..8d974b7c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +mozilla-ipcd diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in new file mode 100644 index 00000000..e9ef6c38 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/Makefile.in @@ -0,0 +1,88 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd + +# required for #include "nsID.h" +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + ipcd.cpp \ + ipcClient.cpp \ + ipcModuleReg.cpp \ + ipcCommandModule.cpp + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += ipcdWin.cpp +else +ifeq ($(OS_ARCH),BeOS) +CPPSRCS += ipcdStub.cpp +else +CPPSRCS += ipcdUnix.cpp +endif +endif + +PROGRAM = mozilla-ipcd$(BIN_SUFFIX) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../shared/src \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)ipcdshared_s.$(LIB_SUFFIX) \ + $(EXTRA_DSO_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +# For fruncate +ifeq ($(OS_ARCH),Linux) +DEFINES += -D_BSD_SOURCE +endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp new file mode 100644 index 00000000..4f68d175 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.cpp @@ -0,0 +1,235 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcLog.h" +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcModuleReg.h" +#include "ipcd.h" +#include "ipcm.h" + +#if defined(XP_UNIX) || defined(XP_OS2) +#include "prio.h" +#endif + +PRUint32 ipcClient::gLastID = 0; + +// +// called to initialize this client context +// +// assumptions: +// - object's memory has already been zero'd out. +// +void +ipcClient::Init() +{ + mID = ++gLastID; + + // every client must be able to handle IPCM messages. + mTargets.Append(IPCM_TARGET); + + // although it is tempting to fire off the NotifyClientUp event at this + // time, we must wait until the client sends us a CLIENT_HELLO event. + // see ipcCommandModule::OnClientHello. +} + +// +// called when this client context is going away +// +void +ipcClient::Finalize() +{ + IPC_NotifyClientDown(this); + + mNames.DeleteAll(); + mTargets.DeleteAll(); + +#if defined(XP_UNIX) || defined(XP_OS2) + mInMsg.Reset(); + mOutMsgQ.DeleteAll(); +#endif +} + +void +ipcClient::AddName(const char *name) +{ + LOG(("adding client name: %s\n", name)); + + if (HasName(name)) + return; + + mNames.Append(name); +} + +PRBool +ipcClient::DelName(const char *name) +{ + LOG(("deleting client name: %s\n", name)); + + return mNames.FindAndDelete(name); +} + +void +ipcClient::AddTarget(const nsID &target) +{ + LOG(("adding client target\n")); + + if (HasTarget(target)) + return; + + mTargets.Append(target); +} + +PRBool +ipcClient::DelTarget(const nsID &target) +{ + LOG(("deleting client target\n")); + + // + // cannot remove the IPCM target + // + if (!target.Equals(IPCM_TARGET)) + return mTargets.FindAndDelete(target); + + return PR_FALSE; +} + +#if defined(XP_UNIX) || defined(XP_OS2) + +// +// called to process a client socket +// +// params: +// fd - the client socket +// poll_flags - the state of the client socket +// +// return: +// 0 - to end session with this client +// PR_POLL_READ - to wait for the client socket to become readable +// PR_POLL_WRITE - to wait for the client socket to become writable +// +int +ipcClient::Process(PRFileDesc *fd, int inFlags) +{ + if (inFlags & (PR_POLL_ERR | PR_POLL_HUP | + PR_POLL_EXCEPT | PR_POLL_NVAL)) { + LOG(("client socket appears to have closed\n")); + return 0; + } + + // expect to wait for more data + int outFlags = PR_POLL_READ; + + if (inFlags & PR_POLL_READ) { + LOG(("client socket is now readable\n")); + + char buf[1024]; // XXX make this larger? + PRInt32 n; + + // find out how much data is available for reading... + // n = PR_Available(fd); + + n = PR_Read(fd, buf, sizeof(buf)); + if (n <= 0) + return 0; // cancel connection + + const char *ptr = buf; + while (n) { + PRUint32 nread; + PRBool complete; + + if (mInMsg.ReadFrom(ptr, PRUint32(n), &nread, &complete) == PR_FAILURE) { + LOG(("message appears to be malformed; dropping client connection\n")); + return 0; + } + + if (complete) { + IPC_DispatchMsg(this, &mInMsg); + mInMsg.Reset(); + } + + n -= nread; + ptr += nread; + } + } + + if (inFlags & PR_POLL_WRITE) { + LOG(("client socket is now writable\n")); + + if (mOutMsgQ.First()) + WriteMsgs(fd); + } + + if (mOutMsgQ.First()) + outFlags |= PR_POLL_WRITE; + + return outFlags; +} + +// +// called to write out any messages from the outgoing queue. +// +int +ipcClient::WriteMsgs(PRFileDesc *fd) +{ + while (mOutMsgQ.First()) { + const char *buf = (const char *) mOutMsgQ.First()->MsgBuf(); + PRInt32 bufLen = (PRInt32) mOutMsgQ.First()->MsgLen(); + + if (mSendOffset) { + buf += mSendOffset; + bufLen -= mSendOffset; + } + + PRInt32 nw = PR_Write(fd, buf, bufLen); + if (nw <= 0) + break; + + LOG(("wrote %d bytes\n", nw)); + + if (nw == bufLen) { + mOutMsgQ.DeleteFirst(); + mSendOffset = 0; + } + else + mSendOffset += nw; + } + + return 0; +} + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h new file mode 100644 index 00000000..12e479cf --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcClient.h @@ -0,0 +1,144 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcClientUnix_h__ +#define ipcClientUnix_h__ + +#include "prio.h" +#include "ipcMessageQ.h" +#include "ipcStringList.h" +#include "ipcIDList.h" + +#ifdef XP_WIN +#include +#endif + +//----------------------------------------------------------------------------- +// ipcClient +// +// NOTE: this class is an implementation detail of the IPC daemon. IPC daemon +// modules (other than the built-in IPCM module) must not access methods on +// this class directly. use the API provided via ipcd.h instead. +//----------------------------------------------------------------------------- + +class ipcClient +{ +public: + void Init(); + void Finalize(); + + PRUint32 ID() const { return mID; } + + void AddName(const char *name); + PRBool DelName(const char *name); + PRBool HasName(const char *name) const { return mNames.Find(name) != NULL; } + + void AddTarget(const nsID &target); + PRBool DelTarget(const nsID &target); + PRBool HasTarget(const nsID &target) const { return mTargets.Find(target) != NULL; } + + // list iterators + const ipcStringNode *Names() const { return mNames.First(); } + const ipcIDNode *Targets() const { return mTargets.First(); } + + // returns primary client name (the one specified in the "client hello" message) + const char *PrimaryName() const { return mNames.First() ? mNames.First()->Value() : NULL; } + + void SetExpectsSyncReply(PRBool val) { mExpectsSyncReply = val; } + PRBool GetExpectsSyncReply() const { return mExpectsSyncReply; } + +#ifdef XP_WIN + PRUint32 PID() const { return mPID; } + void SetPID(PRUint32 pid) { mPID = pid; } + + HWND Hwnd() const { return mHwnd; } + void SetHwnd(HWND hwnd) { mHwnd = hwnd; } +#endif + +#if defined(XP_UNIX) || defined(XP_OS2) + // + // called to process a client file descriptor. the value of pollFlags + // indicates the state of the socket. + // + // returns: + // 0 - to cancel client connection + // PR_POLL_READ - to poll for a readable socket + // PR_POLL_WRITE - to poll for a writable socket + // (both flags) - to poll for either a readable or writable socket + // + // the socket is non-blocking. + // + int Process(PRFileDesc *sockFD, int pollFlags); + + // + // on success or failure, this function takes ownership of |msg| and will + // delete it when appropriate. + // + void EnqueueOutboundMsg(ipcMessage *msg) { mOutMsgQ.Append(msg); } +#endif + +private: + static PRUint32 gLastID; + + PRUint32 mID; + ipcStringList mNames; + ipcIDList mTargets; + PRBool mExpectsSyncReply; + +#ifdef XP_WIN + // on windows, we store the PID of the client process to help us determine + // the client from which a message originated. each message has the PID + // encoded in it. + PRUint32 mPID; + + // the hwnd of the client's message window. + HWND mHwnd; +#endif + +#if defined(XP_UNIX) || defined(XP_OS2) + ipcMessage mInMsg; // buffer for incoming message + ipcMessageQ mOutMsgQ; // outgoing message queue + + // keep track of the amount of the first message sent + PRUint32 mSendOffset; + + // utility function for writing out messages. + int WriteMsgs(PRFileDesc *fd); +#endif +}; + +#endif // !ipcClientUnix_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp new file mode 100644 index 00000000..43ac547c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.cpp @@ -0,0 +1,316 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include +#include "ipcLog.h" +#include "ipcCommandModule.h" +#include "ipcModule.h" +#include "ipcClient.h" +#include "ipcMessage.h" +#include "ipcMessageUtils.h" +#include "ipcModuleReg.h" +#include "ipcd.h" +#include "ipcm.h" + +struct ipcCommandModule +{ + typedef void (* MsgHandler)(ipcClient *, const ipcMessage *); + + // + // helpers + // + + static char ** + BuildStringArray(const ipcStringNode *nodes) + { + size_t count = 0; + + const ipcStringNode *node; + + for (node = nodes; node; node = node->mNext) + count++; + + char **strs = (char **) malloc((count + 1) * sizeof(char *)); + if (!strs) + return NULL; + + count = 0; + for (node = nodes; node; node = node->mNext, ++count) + strs[count] = (char *) node->Value(); + strs[count] = 0; + + return strs; + } + + static nsID ** + BuildIDArray(const ipcIDNode *nodes) + { + size_t count = 0; + + const ipcIDNode *node; + + for (node = nodes; node; node = node->mNext) + count++; + + nsID **ids = (nsID **) calloc(count + 1, sizeof(nsID *)); + if (!ids) + return NULL; + + count = 0; + for (node = nodes; node; node = node->mNext, ++count) + ids[count] = (nsID *) &node->Value(); + + return ids; + } + + // + // message handlers + // + + static void + OnPing(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got PING\n")); + + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); + } + + static void + OnClientHello(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_HELLO\n")); + + IPC_SendMsg(client, new ipcmMessageClientID(IPCM_GetRequestIndex(rawMsg), client->ID())); + + // + // NOTE: it would almost make sense for this notification to live + // in the transport layer code. however, clients expect to receive + // a CLIENT_ID as the first message following a CLIENT_HELLO, so we + // must not allow modules to see a client until after we have sent + // the CLIENT_ID message. + // + IPC_NotifyClientUp(client); + } + + static void + OnClientAddName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_ADD_NAME\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast msg(rawMsg); + const char *name = msg->Name(); + if (name) { + ipcClient *result = IPC_GetClientByName(msg->Name()); + if (result) { + LOG((" client with such name already exists (ID = %d)\n", result->ID())); + status = IPCM_ERROR_ALREADY_EXISTS; + } + else + client->AddName(name); + } + else + status = IPCM_ERROR_INVALID_ARG; + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientDelName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_DEL_NAME\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast msg(rawMsg); + const char *name = msg->Name(); + if (name) { + if (!client->DelName(name)) { + LOG((" client doesn't have name '%s'\n", name)); + status = IPCM_ERROR_NO_SUCH_DATA; + } + } + else + status = IPCM_ERROR_INVALID_ARG; + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientAddTarget(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_ADD_TARGET\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast msg(rawMsg); + if (client->HasTarget(msg->Target())) { + LOG((" target already defined for client\n")); + status = IPCM_ERROR_ALREADY_EXISTS; + } + else + client->AddTarget(msg->Target()); + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnClientDelTarget(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got CLIENT_DEL_TARGET\n")); + + PRInt32 status = IPCM_OK; + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast msg(rawMsg); + if (!client->DelTarget(msg->Target())) { + LOG((" client doesn't have the given target\n")); + status = IPCM_ERROR_NO_SUCH_DATA; + } + + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, status)); + } + + static void + OnQueryClientByName(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got QUERY_CLIENT_BY_NAME\n")); + + PRUint32 requestIndex = IPCM_GetRequestIndex(rawMsg); + + ipcMessageCast msg(rawMsg); + + ipcClient *result = IPC_GetClientByName(msg->Name()); + if (result) { + LOG((" client exists w/ ID = %u\n", result->ID())); + IPC_SendMsg(client, new ipcmMessageClientID(requestIndex, result->ID())); + } + else { + LOG((" client does not exist\n")); + IPC_SendMsg(client, new ipcmMessageResult(requestIndex, IPCM_ERROR_NO_CLIENT)); + } + } + +#if 0 + static void + OnQueryClientInfo(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got QUERY_CLIENT_INFO\n")); + + ipcMessageCast msg(rawMsg); + ipcClient *result = IPC_GetClientByID(msg->ClientID()); + if (result) { + char **names = BuildStringArray(result->Names()); + nsID **targets = BuildIDArray(result->Targets()); + + IPC_SendMsg(client, new ipcmMessageClientInfo(result->ID(), + msg->RequestIndex(), + (const char **) names, + (const nsID **) targets)); + + free(names); + free(targets); + } + else { + LOG((" client does not exist\n")); + IPC_SendMsg(client, new ipcmMessageError(IPCM_ERROR_NO_CLIENT, msg->RequestIndex())); + } + } +#endif + + static void + OnForward(ipcClient *client, const ipcMessage *rawMsg) + { + LOG(("got FORWARD\n")); + + ipcMessageCast msg(rawMsg); + + ipcClient *dest = IPC_GetClientByID(msg->ClientID()); + if (!dest) { + LOG((" destination client not found!\n")); + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_ERROR_NO_CLIENT)); + return; + } + // inform client that its message will be forwarded + IPC_SendMsg(client, new ipcmMessageResult(IPCM_GetRequestIndex(rawMsg), IPCM_OK)); + + ipcMessage *newMsg = new ipcmMessageForward(IPCM_MSG_PSH_FORWARD, + client->ID(), + msg->InnerTarget(), + msg->InnerData(), + msg->InnerDataLen()); + IPC_SendMsg(dest, newMsg); + } +}; + +void +IPCM_HandleMsg(ipcClient *client, const ipcMessage *rawMsg) +{ + static ipcCommandModule::MsgHandler handlers[] = + { + ipcCommandModule::OnPing, + ipcCommandModule::OnForward, + ipcCommandModule::OnClientHello, + ipcCommandModule::OnClientAddName, + ipcCommandModule::OnClientDelName, + ipcCommandModule::OnClientAddTarget, + ipcCommandModule::OnClientDelTarget, + ipcCommandModule::OnQueryClientByName + }; + + int type = IPCM_GetType(rawMsg); + LOG(("IPCM_HandleMsg [type=%x]\n", type)); + + if (!(type & IPCM_MSG_CLASS_REQ)) { + LOG(("not a request -- ignoring message\n")); + return; + } + + type &= ~IPCM_MSG_CLASS_REQ; + type--; + if (type < 0 || type >= (int) (sizeof(handlers)/sizeof(handlers[0]))) { + LOG(("unknown request -- ignoring message\n")); + return; + } + + (handlers[type])(client, rawMsg); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h new file mode 100644 index 00000000..ea146cdc --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcCommandModule.h @@ -0,0 +1,48 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcCommandModule_h__ +#define ipcCommandModule_h__ + +#include "ipcm.h" // for IPCM_TARGET + +class ipcClient; +class ipcMessage; + +void IPCM_HandleMsg(ipcClient *, const ipcMessage *); + +#endif // !ipcCommandModule_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp new file mode 100644 index 00000000..09e60ab9 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.cpp @@ -0,0 +1,245 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include + +#include "prlink.h" +#include "prio.h" +#include "prlog.h" +#include "plstr.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcCommandModule.h" +#include "ipcd.h" + +//----------------------------------------------------------------------------- + +struct ipcModuleRegEntry +{ + nsID target; + ipcModuleMethods *methods; + PRLibrary *lib; +}; + +#define IPC_MAX_MODULE_COUNT 64 + +static ipcModuleRegEntry ipcModules[IPC_MAX_MODULE_COUNT]; +static int ipcModuleCount = 0; + +//----------------------------------------------------------------------------- + +static PRStatus +AddModule(const nsID &target, ipcModuleMethods *methods, const char *libPath) +{ + if (ipcModuleCount == IPC_MAX_MODULE_COUNT) { + LOG(("too many modules!\n")); + return PR_FAILURE; + } + + if (!methods) { + PR_NOT_REACHED("null module methods"); + return PR_FAILURE; + } + + // + // each ipcModuleRegEntry holds a reference to a PRLibrary, and on + // shutdown, each PRLibrary reference will be released. this ensures + // that the library will not be unloaded until all of the modules in + // that library are shutdown. + // + ipcModules[ipcModuleCount].target = target; + ipcModules[ipcModuleCount].methods = methods; + ipcModules[ipcModuleCount].lib = PR_LoadLibrary(libPath); + + ++ipcModuleCount; + return PR_SUCCESS; +} + +static void +InitModuleFromLib(const char *modulesDir, const char *fileName) +{ + LOG(("InitModuleFromLib [%s]\n", fileName)); + + static const ipcDaemonMethods gDaemonMethods = + { + IPC_DAEMON_METHODS_VERSION, + IPC_DispatchMsg, + IPC_SendMsg, + IPC_GetClientByID, + IPC_GetClientByName, + IPC_EnumClients, + IPC_GetClientID, + IPC_ClientHasName, + IPC_ClientHasTarget, + IPC_EnumClientNames, + IPC_EnumClientTargets + }; + + int dLen = strlen(modulesDir); + int fLen = strlen(fileName); + + char *buf = (char *) malloc(dLen + 1 + fLen + 1); + memcpy(buf, modulesDir, dLen); + buf[dLen] = IPC_PATH_SEP_CHAR; + memcpy(buf + dLen + 1, fileName, fLen); + buf[dLen + 1 + fLen] = '\0'; + + PRLibrary *lib = PR_LoadLibrary(buf); + if (lib) { + ipcGetModulesFunc func = + (ipcGetModulesFunc) PR_FindFunctionSymbol(lib, "IPC_GetModules"); + + LOG((" func=%p\n", (void*) func)); + + if (func) { + const ipcModuleEntry *entries = NULL; + int count = func(&gDaemonMethods, &entries); + for (int i=0; iinit) + entries[i].methods->init(); + } + } + } + PR_UnloadLibrary(lib); + } + + free(buf); +} + +//----------------------------------------------------------------------------- +// ipcModuleReg API +//----------------------------------------------------------------------------- + +void +IPC_InitModuleReg(const char *exePath) +{ + if (!(exePath && *exePath)) + return; + + // + // register plug-in modules + // + char *p = PL_strrchr(exePath, IPC_PATH_SEP_CHAR); + if (p == NULL) { + LOG(("unexpected exe path\n")); + return; + } + + int baseLen = p - exePath; + int finalLen = baseLen + 1 + sizeof(IPC_MODULES_DIR); + + // build full path to ipc modules + char *modulesDir = (char*) malloc(finalLen); + memcpy(modulesDir, exePath, baseLen); + modulesDir[baseLen] = IPC_PATH_SEP_CHAR; + memcpy(modulesDir + baseLen + 1, IPC_MODULES_DIR, sizeof(IPC_MODULES_DIR)); + + LOG(("loading libraries in %s\n", modulesDir)); + // + // scan directory for IPC modules + // + PRDir *dir = PR_OpenDir(modulesDir); + if (dir) { + PRDirEntry *ent; + while ((ent = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { + // + // locate extension, and check if dynamic library + // + + const char *p = strrchr(ent->name, '.'); + if (p && PL_strcasecmp(p, MOZ_DLL_SUFFIX) == 0) + InitModuleFromLib(modulesDir, ent->name); + } + PR_CloseDir(dir); + } + + free(modulesDir); +} + +void +IPC_ShutdownModuleReg() +{ + // + // shutdown modules in reverse order + // + while (ipcModuleCount) { + ipcModuleRegEntry &entry = ipcModules[--ipcModuleCount]; + if (entry.methods->shutdown) + entry.methods->shutdown(); + if (entry.lib) + PR_UnloadLibrary(entry.lib); + } +} + +void +IPC_NotifyModulesClientUp(ipcClient *client) +{ + for (int i = 0; i < ipcModuleCount; ++i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.methods->clientUp) + entry.methods->clientUp(client); + } +} + +void +IPC_NotifyModulesClientDown(ipcClient *client) +{ + for (int i = 0; i < ipcModuleCount; ++i) { + ipcModuleRegEntry &entry = ipcModules[i]; + if (entry.methods->clientDown) + entry.methods->clientDown(client); + } +} + +PRStatus +IPC_DispatchMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen) +{ + // dispatch message to every module registered under the given target. + for (int i=0; ihandleMsg) + entry.methods->handleMsg(client, target, data, dataLen); + } + } + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h new file mode 100644 index 00000000..d3fecd6c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcModuleReg.h @@ -0,0 +1,70 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcModuleReg_h__ +#define ipcModuleReg_h__ + +#include "ipcModule.h" + +// +// called to init the module registry. this may only be called once at +// startup or once after calling IPC_ShutdownModuleReg. +// +// params: +// exePath - path to the daemon executable. modules are loaded from a +// directory relative to the daemon executable. +// +void IPC_InitModuleReg(const char *exePath); + +// +// called to shutdown the module registry. this may be called more than +// once and need not follow a call to IPC_InitModuleReg. +// +void IPC_ShutdownModuleReg(); + +// +// returns the ipcModuleMethods for the given target. +// +ipcModuleMethods *IPC_GetModuleByTarget(const nsID &target); + +// +// notifies all modules of client connect/disconnect +// +void IPC_NotifyModulesClientUp(ipcClient *); +void IPC_NotifyModulesClientDown(ipcClient *); + +#endif // !ipcModuleReg_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp new file mode 100644 index 00000000..60aca34a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.cpp @@ -0,0 +1,235 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "prlog.h" +#include "prio.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcModule.h" +#include "ipcCommandModule.h" +#include "ipcdPrivate.h" +#include "ipcd.h" + +//----------------------------------------------------------------------------- + +void +IPC_NotifyParent() +{ + PRFileDesc *fd = PR_GetInheritedFD(IPC_STARTUP_PIPE_NAME); + if (fd) { + char c = IPC_STARTUP_PIPE_MAGIC; + PR_Write(fd, &c, 1); + PR_Close(fd); + } +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_DispatchMsg(ipcClient *client, const ipcMessage *msg) +{ + PR_ASSERT(client); + PR_ASSERT(msg); + + // remember if client is expecting SYNC_REPLY. we'll add that flag to the + // next message sent to the client. + if (msg->TestFlag(IPC_MSG_FLAG_SYNC_QUERY)) { + PR_ASSERT(client->GetExpectsSyncReply() == PR_FALSE); + // XXX shouldn't we remember the TargetID as well, and only set the + // SYNC_REPLY flag on the next message sent to the same TargetID? + client->SetExpectsSyncReply(PR_TRUE); + } + + if (msg->Target().Equals(IPCM_TARGET)) { + IPCM_HandleMsg(client, msg); + return PR_SUCCESS; + } + + return IPC_DispatchMsg(client, msg->Target(), msg->Data(), msg->DataLen()); +} + +PRStatus +IPC_SendMsg(ipcClient *client, ipcMessage *msg) +{ + PR_ASSERT(msg); + + if (client == NULL) { + // + // broadcast + // + for (int i=0; iClone()); + delete msg; + return PR_SUCCESS; + } + + // add SYNC_REPLY flag to message if client is expecting... + if (client->GetExpectsSyncReply()) { + msg->SetFlag(IPC_MSG_FLAG_SYNC_REPLY); + client->SetExpectsSyncReply(PR_FALSE); + } + + if (client->HasTarget(msg->Target())) + return IPC_PlatformSendMsg(client, msg); + + LOG((" no registered message handler\n")); + return PR_FAILURE; +} + +void +IPC_NotifyClientUp(ipcClient *client) +{ + LOG(("IPC_NotifyClientUp: clientID=%d\n", client->ID())); + + // notify modules before other clients + IPC_NotifyModulesClientUp(client); + + for (int i=0; iID(), IPCM_CLIENT_STATE_UP)); + } +} + +void +IPC_NotifyClientDown(ipcClient *client) +{ + LOG(("IPC_NotifyClientDown: clientID=%d\n", client->ID())); + + // notify modules before other clients + IPC_NotifyModulesClientDown(client); + + for (int i=0; iID(), IPCM_CLIENT_STATE_DOWN)); + } +} + +//----------------------------------------------------------------------------- +// IPC daemon methods +//----------------------------------------------------------------------------- + +PRStatus +IPC_SendMsg(ipcClient *client, const nsID &target, const void *data, PRUint32 dataLen) +{ + return IPC_SendMsg(client, new ipcMessage(target, (const char *) data, dataLen)); +} + +ipcClient * +IPC_GetClientByID(PRUint32 clientID) +{ + // linear search OK since number of clients should be small + for (int i = 0; i < ipcClientCount; ++i) { + if (ipcClients[i].ID() == clientID) + return &ipcClients[i]; + } + return NULL; +} + +ipcClient * +IPC_GetClientByName(const char *name) +{ + // linear search OK since number of clients should be small + for (int i = 0; i < ipcClientCount; ++i) { + if (ipcClients[i].HasName(name)) + return &ipcClients[i]; + } + return NULL; +} + +void +IPC_EnumClients(ipcClientEnumFunc func, void *closure) +{ + PR_ASSERT(func); + for (int i = 0; i < ipcClientCount; ++i) { + if (func(closure, &ipcClients[i], ipcClients[i].ID()) == PR_FALSE) + break; + } +} + +PRUint32 +IPC_GetClientID(ipcClient *client) +{ + PR_ASSERT(client); + return client->ID(); +} + +PRBool +IPC_ClientHasName(ipcClient *client, const char *name) +{ + PR_ASSERT(client); + PR_ASSERT(name); + return client->HasName(name); +} + +PRBool +IPC_ClientHasTarget(ipcClient *client, const nsID &target) +{ + PR_ASSERT(client); + return client->HasTarget(target); +} + +void +IPC_EnumClientNames(ipcClient *client, ipcClientNameEnumFunc func, void *closure) +{ + PR_ASSERT(client); + PR_ASSERT(func); + const ipcStringNode *node = client->Names(); + while (node) { + if (func(closure, client, node->Value()) == PR_FALSE) + break; + node = node->mNext; + } +} + +void +IPC_EnumClientTargets(ipcClient *client, ipcClientTargetEnumFunc func, void *closure) +{ + PR_ASSERT(client); + PR_ASSERT(func); + const ipcIDNode *node = client->Targets(); + while (node) { + if (func(closure, client, node->Value()) == PR_FALSE) + break; + node = node->mNext; + } +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h new file mode 100644 index 00000000..5a0f2c2a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcd.h @@ -0,0 +1,82 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 IPCD_H__ +#define IPCD_H__ + +#include "ipcModule.h" +#include "ipcMessage.h" + +//----------------------------------------------------------------------------- +// IPC daemon methods (see struct ipcDaemonMethods) +// +// these functions may only be called directly from within the daemon. plug-in +// modules must access these through the ipcDaemonMethods structure. +//----------------------------------------------------------------------------- + +PRStatus IPC_DispatchMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen); +PRStatus IPC_SendMsg (ipcClientHandle client, const nsID &target, const void *data, PRUint32 dataLen); +ipcClientHandle IPC_GetClientByID (PRUint32 id); +ipcClientHandle IPC_GetClientByName (const char *name); +void IPC_EnumClients (ipcClientEnumFunc func, void *closure); +PRUint32 IPC_GetClientID (ipcClientHandle client); +PRBool IPC_ClientHasName (ipcClientHandle client, const char *name); +PRBool IPC_ClientHasTarget (ipcClientHandle client, const nsID &target); +void IPC_EnumClientNames (ipcClientHandle client, ipcClientNameEnumFunc func, void *closure); +void IPC_EnumClientTargets (ipcClientHandle client, ipcClientTargetEnumFunc func, void *closure); + +//----------------------------------------------------------------------------- +// other internal IPCD methods +//----------------------------------------------------------------------------- + +// +// dispatch message +// +PRStatus IPC_DispatchMsg(ipcClientHandle client, const ipcMessage *msg); + +// +// send message, takes ownership of |msg|. +// +PRStatus IPC_SendMsg(ipcClientHandle client, ipcMessage *msg); + +// +// dispatch notifications about client connects and disconnects +// +void IPC_NotifyClientUp(ipcClientHandle client); +void IPC_NotifyClientDown(ipcClientHandle client); + +#endif // !IPCD_H__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h new file mode 100644 index 00000000..023b3a03 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdPrivate.h @@ -0,0 +1,65 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcdPrivate_h__ +#define ipcdPrivate_h__ + +class ipcClient; + +// +// upper limit on the number of active connections +// XXX may want to make this more dynamic +// +#define IPC_MAX_CLIENTS 10000 + +// +// array of connected clients +// +extern ipcClient *ipcClients; +extern int ipcClientCount; + +// +// platform specific send message function, takes ownership of |msg|. +// +PRStatus IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg); + +// +// notify parent that it can connect to the daemon. +// +void IPC_NotifyParent(); + +#endif // !ipcdPrivate_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp new file mode 100644 index 00000000..10618110 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdStub.cpp @@ -0,0 +1,77 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcd.h" +#include "ipcdPrivate.h" +#include "ipcLog.h" + +#include "prerror.h" + +//----------------------------------------------------------------------------- +// use this file as a template to add server-side IPC connectivity. +// +// NOTE: if your platform supports local domain TCP sockets, then you should +// be able to make use of ipcConnectionUnix.cpp. +//----------------------------------------------------------------------------- + +// these variables are declared in ipcdPrivate.h and must be initialized by +// when the daemon starts up. +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + const char notimplemented[] = "IPC_PlatformSendMsg not implemented"; + PR_SetErrorText(sizeof(notimplemented), notimplemented); + return PR_FAILURE; +} + +int main(int argc, char **argv) +{ + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + /* + IPC_InitModuleReg(argv[0]); + IPC_ShutdownModuleReg(); + */ + + // let the parent process know that we are up-and-running + IPC_NotifyParent(); + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp new file mode 100644 index 00000000..026e9e52 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdUnix.cpp @@ -0,0 +1,600 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#if defined(VBOX) && !defined(XP_OS2) +# include +# include +#endif + +#ifdef VBOX +# include +#endif + +#include "prio.h" +#include "prerror.h" +#include "prthread.h" +#include "prinrval.h" +#include "plstr.h" +#include "prprf.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcdPrivate.h" +#include "ipcd.h" + +#if 0 +static void +IPC_Sleep(int seconds) +{ + while (seconds > 0) { + LOG(("\rsleeping for %d seconds...", seconds)); + PR_Sleep(PR_SecondsToInterval(1)); + --seconds; + } + LOG(("\ndone sleeping\n")); +} +#endif + +//----------------------------------------------------------------------------- +// ipc directory and locking... +//----------------------------------------------------------------------------- + +// +// advisory file locking is used to ensure that only one IPC daemon is active +// and bound to the local domain socket at a time. +// +// XXX this code does not work on OS/2. +// +#if !defined(XP_OS2) +#define IPC_USE_FILE_LOCK +#endif + +#ifdef IPC_USE_FILE_LOCK + +enum Status +{ + EOk = 0, + ELockFileOpen = -1, + ELockFileLock = -2, + ELockFileOwner = -3, +}; + +static int ipcLockFD = 0; + +static Status AcquireDaemonLock(const char *baseDir) +{ + const char lockName[] = "lock"; + + int dirLen = strlen(baseDir); + int len = dirLen // baseDir + + 1 // "/" + + sizeof(lockName); // "lock" + + char *lockFile = (char *) malloc(len); + memcpy(lockFile, baseDir, dirLen); + lockFile[dirLen] = '/'; + memcpy(lockFile + dirLen + 1, lockName, sizeof(lockName)); + +#ifdef VBOX + // + // Security checks for the directory + // + struct stat st; + if (stat(baseDir, &st) == -1) + { + printf("Cannot stat '%s'.\n", baseDir); + return ELockFileOwner; + } + + if (st.st_uid != getuid() && st.st_uid != geteuid()) + { + printf("Wrong owner (%d) of '%s'", st.st_uid, baseDir); + if ( !stat("/tmp", &st) + && (st.st_mode & 07777) != 01777) + printf(" -- check /tmp permissions (%o should be 1777)\n", + st.st_mode & 07777); + printf(".\n"); + return ELockFileOwner; + } + + if (st.st_mode != (S_IRUSR | S_IWUSR | S_IXUSR | S_IFDIR)) + { + printf("Wrong mode (%o) of '%s'", st.st_mode, baseDir); + if ( !stat("/tmp", &st) + && (st.st_mode & 07777) != 01777) + printf(" -- check /tmp permissions (%o should be 1777)\n", + st.st_mode & 07777); + printf(".\n"); + return ELockFileOwner; + } +#endif + + // + // open lock file. it remains open until we shutdown. + // + ipcLockFD = open(lockFile, O_WRONLY|O_CREAT, S_IWUSR|S_IRUSR); + +#ifndef VBOX + free(lockFile); +#endif + + if (ipcLockFD == -1) + return ELockFileOpen; + +#ifdef VBOX + // + // Security checks for the lock file + // + if (fstat(ipcLockFD, &st) == -1) + { + printf("Cannot stat '%s'.\n", lockFile); + free(lockFile); + return ELockFileOwner; + } + + if (st.st_uid != getuid() && st.st_uid != geteuid()) + { + printf("Wrong owner (%d) of '%s'.\n", st.st_uid, lockFile); + free(lockFile); + return ELockFileOwner; + } + + if (st.st_mode != (S_IRUSR | S_IWUSR | S_IFREG)) + { + printf("Wrong mode (%o) of '%s'.\n", st.st_mode, lockFile); + free(lockFile); + return ELockFileOwner; + } + + free(lockFile); +#endif + + // + // we use fcntl for locking. assumption: filesystem should be local. + // this API is nice because the lock will be automatically released + // when the process dies. it will also be released when the file + // descriptor is closed. + // + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_len = 0; + lock.l_whence = SEEK_SET; + if (fcntl(ipcLockFD, F_SETLK, &lock) == -1) + return ELockFileLock; + + // + // truncate lock file once we have exclusive access to it. + // + ftruncate(ipcLockFD, 0); + + // + // write our PID into the lock file (this just seems like a good idea... + // no real purpose otherwise). + // + char buf[32]; + int nb = PR_snprintf(buf, sizeof(buf), "%u\n", (unsigned long) getpid()); + write(ipcLockFD, buf, nb); + + return EOk; +} + +static Status InitDaemonDir(const char *socketPath) +{ + LOG(("InitDaemonDir [sock=%s]\n", socketPath)); + + char *baseDir = PL_strdup(socketPath); + + // + // make sure IPC directory exists (XXX this should be recursive) + // + char *p = strrchr(baseDir, '/'); + if (p) + p[0] = '\0'; + mkdir(baseDir, 0700); + + // + // if we can't acquire the daemon lock, then another daemon + // must be active, so bail. + // + Status status = AcquireDaemonLock(baseDir); + + PL_strfree(baseDir); + + if (status == EOk) { + // delete an existing socket to prevent bind from failing. + unlink(socketPath); + } + return status; +} + +static void ShutdownDaemonDir() +{ + LOG(("ShutdownDaemonDir\n")); + + // deleting directory and files underneath it allows another process + // to think it has exclusive access. better to just leave the hidden + // directory in /tmp and let the OS clean it up via the usual tmpdir + // cleanup cron job. + + // this removes the advisory lock, allowing other processes to acquire it. + if (ipcLockFD) { + close(ipcLockFD); + ipcLockFD = 0; + } +} + +#endif // IPC_USE_FILE_LOCK + +//----------------------------------------------------------------------------- +// poll list +//----------------------------------------------------------------------------- + +// +// declared in ipcdPrivate.h +// +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +// +// the first element of this array is always zero; this is done so that the +// k'th element of ipcClientArray corresponds to the k'th element of +// ipcPollList. +// +static ipcClient ipcClientArray[IPC_MAX_CLIENTS + 1]; + +// +// element 0 contains the "server socket" +// +static PRPollDesc ipcPollList[IPC_MAX_CLIENTS + 1]; + +//----------------------------------------------------------------------------- + +static int AddClient(PRFileDesc *fd) +{ + if (ipcClientCount == IPC_MAX_CLIENTS) { + LOG(("reached maximum client limit\n")); + return -1; + } + + int pollCount = ipcClientCount + 1; + + ipcClientArray[pollCount].Init(); + + ipcPollList[pollCount].fd = fd; + ipcPollList[pollCount].in_flags = PR_POLL_READ; + ipcPollList[pollCount].out_flags = 0; + + ++ipcClientCount; + return 0; +} + +static int RemoveClient(int clientIndex) +{ + PRPollDesc *pd = &ipcPollList[clientIndex]; + + PR_Close(pd->fd); + + ipcClientArray[clientIndex].Finalize(); + + // + // keep the clients and poll_fds contiguous; move the last one into + // the spot held by the one that is going away. + // + int toIndex = clientIndex; + int fromIndex = ipcClientCount; + if (fromIndex != toIndex) { + memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient)); + memcpy(&ipcPollList[toIndex], &ipcPollList[fromIndex], sizeof(PRPollDesc)); + } + + // + // zero out the old entries. + // + memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient)); + memset(&ipcPollList[fromIndex], 0, sizeof(PRPollDesc)); + + --ipcClientCount; + return 0; +} + +//----------------------------------------------------------------------------- + +static void PollLoop(PRFileDesc *listenFD) +{ + // the first element of ipcClientArray is unused. + memset(ipcClientArray, 0, sizeof(ipcClientArray)); + ipcClients = ipcClientArray + 1; + ipcClientCount = 0; + + ipcPollList[0].fd = listenFD; + ipcPollList[0].in_flags = PR_POLL_EXCEPT | PR_POLL_READ; + + while (1) { + PRInt32 rv; + PRIntn i; + + int pollCount = ipcClientCount + 1; + + ipcPollList[0].out_flags = 0; + + // + // poll + // + // timeout after 5 minutes. if no connections after timeout, then + // exit. this timeout ensures that we don't stay resident when no + // clients are interested in connecting after spawning the daemon. + // + // XXX add #define for timeout value + // + LOG(("calling PR_Poll [pollCount=%d]\n", pollCount)); + rv = PR_Poll(ipcPollList, pollCount, PR_SecondsToInterval(60 * 5)); + if (rv == -1) { + LOG(("PR_Poll failed [%d]\n", PR_GetError())); + return; + } + + if (rv > 0) { + // + // process clients that are ready + // + for (i = 1; i < pollCount; ++i) { + if (ipcPollList[i].out_flags != 0) { + ipcPollList[i].in_flags = + ipcClientArray[i].Process(ipcPollList[i].fd, + ipcPollList[i].out_flags); + ipcPollList[i].out_flags = 0; + } + } + + // + // cleanup any dead clients (indicated by a zero in_flags) + // + for (i = pollCount - 1; i >= 1; --i) { + if (ipcPollList[i].in_flags == 0) + RemoveClient(i); + } + + // + // check for new connection + // + if (ipcPollList[0].out_flags & PR_POLL_READ) { + LOG(("got new connection\n")); + + PRNetAddr clientAddr; + memset(&clientAddr, 0, sizeof(clientAddr)); + PRFileDesc *clientFD; + + // @todo : We need to handle errors from accept() especially something like + // EMFILE, which happens when we run out of file descriptors. + // and puts XPCOMIPCD in a poll/accept endless loop! + clientFD = PR_Accept(listenFD, &clientAddr, PR_INTERVAL_NO_WAIT); + if (clientFD == NULL) { + // ignore this error... perhaps the client disconnected. + LOG(("PR_Accept failed [%d]\n", PR_GetError())); + } + else { + // make socket non-blocking + PRSocketOptionData opt; + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + PR_SetSocketOption(clientFD, &opt); + + if (AddClient(clientFD) != 0) + PR_Close(clientFD); + } + } + } + + // + // shutdown if no clients + // + if (ipcClientCount == 0) { + LOG(("shutting down\n")); + break; + } + } +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + LOG(("IPC_PlatformSendMsg\n")); + + // + // must copy message onto send queue. + // + client->EnqueueOutboundMsg(msg); + + // + // since our Process method may have already been called, we must ensure + // that the PR_POLL_WRITE flag is set. + // + int clientIndex = client - ipcClientArray; + ipcPollList[clientIndex].in_flags |= PR_POLL_WRITE; + + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + PRFileDesc *listenFD = NULL; + PRNetAddr addr; + +#ifdef VBOX + /* Set up the runtime without loading the support driver. */ + RTR3InitExe(argc, &argv, 0); +#endif + + // + // ignore SIGINT so from terminal only kills the client + // which spawned this daemon. + // + signal(SIGINT, SIG_IGN); + // XXX block others? check cartman + + // ensure strict file permissions + umask(0077); + + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + //XXX uncomment these lines to test slow starting daemon + //IPC_Sleep(2); + + // set socket address + addr.local.family = PR_AF_LOCAL; + if (argc < 2) + IPC_GetDefaultSocketPath(addr.local.path, sizeof(addr.local.path)); + else + PL_strncpyz(addr.local.path, argv[1], sizeof(addr.local.path)); + +#ifdef IPC_USE_FILE_LOCK + Status status = InitDaemonDir(addr.local.path); + if (status != EOk) { + if (status == ELockFileLock) { + LOG(("Another daemon is already running, exiting.\n")); + // send a signal to the blocked parent to indicate success + IPC_NotifyParent(); + return 0; + } + else { + LOG(("InitDaemonDir failed (status=%d)\n", status)); + // don't notify the parent to cause it to fail in PR_Read() after + // we terminate +#ifdef VBOX + if (status != ELockFileOwner) + printf("Cannot create a lock file for '%s'.\n" + "Check permissions.\n", addr.local.path); +#endif + return 0; + } + } +#endif + + listenFD = PR_OpenTCPSocket(PR_AF_LOCAL); + if (!listenFD) { + LOG(("PR_OpenTCPSocket failed [%d]\n", PR_GetError())); + } + else if (PR_Bind(listenFD, &addr) != PR_SUCCESS) { + LOG(("PR_Bind failed [%d]\n", PR_GetError())); + } + else { + IPC_InitModuleReg(argv[0]); + +#ifdef VBOX + // Use large backlog, as otherwise local sockets can reject connection + // attempts. Usually harmless, but causes an unnecessary start attempt + // of IPCD (which will terminate straight away), and the next attempt + // usually succeeds. But better avoid unnecessary activities. + if (PR_Listen(listenFD, 128) != PR_SUCCESS) { +#else /* !VBOX */ + if (PR_Listen(listenFD, 5) != PR_SUCCESS) { +#endif /* !VBOX */ + LOG(("PR_Listen failed [%d]\n", PR_GetError())); + } + else { +#ifndef VBOX + // redirect all standard file descriptors to /dev/null for + // proper daemonizing + PR_Close(PR_STDIN); + PR_Open("/dev/null", O_RDONLY, 0); + PR_Close(PR_STDOUT); + PR_Open("/dev/null", O_WRONLY, 0); + PR_Close(PR_STDERR); + PR_Open("/dev/null", O_WRONLY, 0); +#endif + + IPC_NotifyParent(); + +#if defined(VBOX) && !defined(XP_OS2) + // Increase the file table size to 10240 or as high as possible. + struct rlimit lim; + if (getrlimit(RLIMIT_NOFILE, &lim) == 0) + { + if ( lim.rlim_cur < 10240 + && lim.rlim_cur < lim.rlim_max) + { + lim.rlim_cur = lim.rlim_max <= 10240 ? lim.rlim_max : 10240; + if (setrlimit(RLIMIT_NOFILE, &lim) == -1) + printf("WARNING: failed to increase file descriptor limit. (%d)\n", errno); + } + } + else + printf("WARNING: failed to obtain per-process file-descriptor limit (%d).\n", errno); +#endif + + PollLoop(listenFD); + } + + IPC_ShutdownModuleReg(); + } + + //IPC_Sleep(5); + +#ifdef IPC_USE_FILE_LOCK + // it is critical that we release the lock before closing the socket, + // otherwise, a client might launch another daemon that would be unable + // to acquire the lock and would then leave the client without a daemon. + + ShutdownDaemonDir(); +#endif + + if (listenFD) { + LOG(("closing socket\n")); + PR_Close(listenFD); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp new file mode 100644 index 00000000..f89fba06 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/daemon/src/ipcdWin.cpp @@ -0,0 +1,408 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 + +#include "prthread.h" + +#include "ipcConfig.h" +#include "ipcLog.h" +#include "ipcMessage.h" +#include "ipcClient.h" +#include "ipcModuleReg.h" +#include "ipcdPrivate.h" +#include "ipcd.h" +#include "ipcm.h" + +// +// declared in ipcdPrivate.h +// +ipcClient *ipcClients = NULL; +int ipcClientCount = 0; + +static ipcClient ipcClientArray[IPC_MAX_CLIENTS]; + +static HWND ipcHwnd = NULL; +static PRBool ipcShutdown = PR_FALSE; + +#define IPC_PURGE_TIMER_ID 1 +#define IPC_WM_SENDMSG (WM_USER + 1) +#define IPC_WM_SHUTDOWN (WM_USER + 2) + +//----------------------------------------------------------------------------- +// client array manipulation +//----------------------------------------------------------------------------- + +static void +RemoveClient(ipcClient *client) +{ + LOG(("RemoveClient\n")); + + int clientIndex = client - ipcClientArray; + + client->Finalize(); + + // + // move last ipcClient object down into the spot occupied by this client. + // + int fromIndex = ipcClientCount - 1; + int toIndex = clientIndex; + if (toIndex != fromIndex) + memcpy(&ipcClientArray[toIndex], &ipcClientArray[fromIndex], sizeof(ipcClient)); + + memset(&ipcClientArray[fromIndex], 0, sizeof(ipcClient)); + + --ipcClientCount; + LOG((" num clients = %u\n", ipcClientCount)); + + if (ipcClientCount == 0) { + LOG((" shutting down...\n")); + KillTimer(ipcHwnd, IPC_PURGE_TIMER_ID); + PostQuitMessage(0); + ipcShutdown = PR_TRUE; + } +} + +static void +PurgeStaleClients() +{ + if (ipcClientCount == 0) + return; + + LOG(("PurgeStaleClients [num-clients=%u]\n", ipcClientCount)); + // + // walk the list of supposedly active clients, and verify the existance of + // their respective message windows. + // + char wName[IPC_CLIENT_WINDOW_NAME_MAXLEN]; + for (int i=ipcClientCount-1; i>=0; --i) { + ipcClient *client = &ipcClientArray[i]; + + LOG((" checking client at index %u [client-id=%u pid=%u]\n", + i, client->ID(), client->PID())); + + IPC_GetClientWindowName(client->PID(), wName); + + // XXX dougt has ideas about how to make this better + + HWND hwnd = FindWindow(IPC_CLIENT_WINDOW_CLASS, wName); + if (!hwnd) { + LOG((" client window not found; removing client!\n")); + RemoveClient(client); + } + } +} + +static ipcClient * +AddClient(HWND hwnd, PRUint32 pid) +{ + LOG(("AddClient\n")); + + // + // before adding a new client, verify that all existing clients are + // still up and running. remove any stale clients. + // + PurgeStaleClients(); + + if (ipcClientCount == IPC_MAX_CLIENTS) { + LOG((" reached maximum client count!\n")); + return NULL; + } + + ipcClient *client = &ipcClientArray[ipcClientCount]; + client->Init(); + client->SetHwnd(hwnd); + client->SetPID(pid); // XXX one function instead of 3 + + ++ipcClientCount; + LOG((" num clients = %u\n", ipcClientCount)); + + if (ipcClientCount == 1) + SetTimer(ipcHwnd, IPC_PURGE_TIMER_ID, 1000, NULL); + + return client; +} + +static ipcClient * +GetClientByPID(PRUint32 pid) +{ + for (int i=0; iMsgLen())); + + ipcClient *client = GetClientByPID(pid); + + if (client) { + // + // if this is an IPCM "client hello" message, then reset the client + // instance object. + // + if (msg->Target().Equals(IPCM_TARGET) && + IPCM_GetType(msg) == IPCM_MSG_REQ_CLIENT_HELLO) { + RemoveClient(client); + client = NULL; + } + } + + if (client == NULL) { + client = AddClient(hwnd, pid); + if (!client) + return; + } + + IPC_DispatchMsg(client, msg); +} + +//----------------------------------------------------------------------------- + +PRStatus +IPC_PlatformSendMsg(ipcClient *client, ipcMessage *msg) +{ + LOG(("IPC_PlatformSendMsg [clientID=%u clientPID=%u]\n", + client->ID(), client->PID())); + + // use PostMessage to make this asynchronous; otherwise we might get + // some wierd SendMessage recursion between processes. + + WPARAM wParam = (WPARAM) client->Hwnd(); + LPARAM lParam = (LPARAM) msg; + if (!PostMessage(ipcHwnd, IPC_WM_SENDMSG, wParam, lParam)) { + LOG(("PostMessage failed\n")); + delete msg; + return PR_FAILURE; + } + return PR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// windows message loop +//----------------------------------------------------------------------------- + +static LRESULT CALLBACK +WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LOG(("got message [msg=%x wparam=%x lparam=%x]\n", uMsg, wParam, lParam)); + + if (uMsg == WM_COPYDATA) { + if (ipcShutdown) { + LOG(("ignoring message b/c daemon is shutting down\n")); + return TRUE; + } + COPYDATASTRUCT *cd = (COPYDATASTRUCT *) lParam; + if (cd && cd->lpData) { + ipcMessage msg; + PRUint32 bytesRead; + PRBool complete; + // XXX avoid extra malloc + PRStatus rv = msg.ReadFrom((const char *) cd->lpData, cd->cbData, + &bytesRead, &complete); + if (rv == PR_SUCCESS && complete) { + // + // grab client PID and hwnd. + // + ProcessMsg((HWND) wParam, (PRUint32) cd->dwData, &msg); + } + else + LOG(("ignoring malformed message\n")); + } + return TRUE; + } + + if (uMsg == IPC_WM_SENDMSG) { + HWND hWndDest = (HWND) wParam; + ipcMessage *msg = (ipcMessage *) lParam; + + COPYDATASTRUCT cd; + cd.dwData = GetCurrentProcessId(); + cd.cbData = (DWORD) msg->MsgLen(); + cd.lpData = (PVOID) msg->MsgBuf(); + + LOG(("calling SendMessage...\n")); + SendMessage(hWndDest, WM_COPYDATA, (WPARAM) hWnd, (LPARAM) &cd); + LOG((" done.\n")); + + delete msg; + return 0; + } + + if (uMsg == WM_TIMER) { + PurgeStaleClients(); + return 0; + } + +#if 0 + if (uMsg == IPC_WM_SHUTDOWN) { + // + // since this message is handled asynchronously, it is possible + // that other clients may have come online since this was issued. + // in which case, we need to ignore this message. + // + if (ipcClientCount == 0) { + ipcShutdown = PR_TRUE; + PostQuitMessage(0); + } + return 0; + } +#endif + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +//----------------------------------------------------------------------------- +// daemon startup synchronization +//----------------------------------------------------------------------------- + +static HANDLE ipcSyncEvent; + +static PRBool +AcquireLock() +{ + ipcSyncEvent = CreateEvent(NULL, FALSE, FALSE, + IPC_SYNC_EVENT_NAME); + if (!ipcSyncEvent) { + LOG(("CreateEvent failed [%u]\n", GetLastError())); + return PR_FALSE; + } + + // check to see if event already existed prior to this call. + if (GetLastError() == ERROR_ALREADY_EXISTS) { + LOG((" lock already set; exiting...\n")); + return PR_FALSE; + } + + LOG((" acquired lock\n")); + return PR_TRUE; +} + +static void +ReleaseLock() +{ + if (ipcSyncEvent) { + LOG(("releasing lock...\n")); + CloseHandle(ipcSyncEvent); + ipcSyncEvent = NULL; + } +} + +//----------------------------------------------------------------------------- +// main +//----------------------------------------------------------------------------- + +#ifdef DEBUG +int +main() +#else +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) +#endif +{ + IPC_InitLog("###"); + + LOG(("daemon started...\n")); + + if (!AcquireLock()) { + // unblock the parent; it should be able to find the IPC window of the + // other daemon process. + IPC_NotifyParent(); + return 0; + } + + // initialize global data + memset(ipcClientArray, 0, sizeof(ipcClientArray)); + ipcClients = ipcClientArray; + ipcClientCount = 0; + + // create message window up front... + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = WindowProc; + wc.lpszClassName = IPC_WINDOW_CLASS; + + RegisterClass(&wc); + + ipcHwnd = CreateWindow(IPC_WINDOW_CLASS, IPC_WINDOW_NAME, + 0, 0, 0, 10, 10, NULL, NULL, NULL, NULL); + + // unblock the parent process; it should now look for the IPC window. + IPC_NotifyParent(); + + if (!ipcHwnd) + return -1; + + // load modules relative to the location of the executable... + { + char path[MAX_PATH]; + GetModuleFileName(NULL, path, sizeof(path)); + IPC_InitModuleReg(path); + } + + LOG(("entering message loop...\n")); + MSG msg; + while (GetMessage(&msg, ipcHwnd, 0, 0)) + DispatchMessage(&msg); + + // unload modules + IPC_ShutdownModuleReg(); + + // + // we release the daemon lock before destroying the window because the + // absence of our window is what will cause clients to try to spawn the + // daemon. + // + ReleaseLock(); + + //LOG(("sleeping 5 seconds...\n")); + //PR_Sleep(PR_SecondsToInterval(5)); + + LOG(("destroying message window...\n")); + DestroyWindow(ipcHwnd); + ipcHwnd = NULL; + + LOG(("exiting\n")); + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in new file mode 100644 index 00000000..e258946b --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.in @@ -0,0 +1,49 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +DIRS = lock transmngr dconnect + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in new file mode 100644 index 00000000..e6a89153 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.in @@ -0,0 +1,52 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = public src + +ifdef ENABLE_TESTS +DIRS += test +endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in new file mode 100644 index 00000000..b2b3dbaa --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/Makefile.in @@ -0,0 +1,53 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +XPIDL_MODULE= ipcd_dconnect + +XPIDLSRCS = \ + ipcIDConnectService.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl new file mode 100644 index 00000000..6ca16a2d --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/public/ipcIDConnectService.idl @@ -0,0 +1,79 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsISupports.idl" + +/** + * This service provides methods similar to nsIComponentManager and + * nsIServiceManager. A ClientID parameter specifies the remote process + * in which the object should live. + * + * ipcIService can be used to determine the ClientID of a remote process. + * + * It is assumed that both processes have access to the same typelibs. + */ +[scriptable, uuid(fe07ed16-2710-4a1e-a4e2-81302b62bf0e)] +interface ipcIDConnectService : nsISupports +{ + void createInstance( + in unsigned long aClientID, + in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result + ); + + void createInstanceByContractID( + in unsigned long aClientID, + in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result + ); + + void getService( + in unsigned long aClientID, + in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result + ); + + void getServiceByContractID( + in unsigned long aClientID, + in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result + ); +}; diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in new file mode 100644 index 00000000..a9efaadf --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.in @@ -0,0 +1,66 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = ipcddconnect_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + +FORCE_USE_PIC = 1 + +REQUIRES = \ + xpcom \ + string \ + $(NULL) + +CPPSRCS = \ + ipcDConnectService.cpp \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../../shared/src \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp new file mode 100644 index 00000000..32565df2 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/src/ipcDConnectService.cpp @@ -0,0 +1,4210 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Dmitry A. Kuminov + * + * 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 "ipcDConnectService.h" +#include "ipcMessageWriter.h" +#include "ipcMessageReader.h" +#include "ipcLog.h" + +#include "nsIServiceManagerUtils.h" +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIExceptionService.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "nsCRT.h" +#include "nsDeque.h" +#include "xptcall.h" + +#ifdef VBOX +# include +# include +# include +# include +# include +# include +# include +#endif /* VBOX */ + +#if defined(DCONNECT_MULTITHREADED) + +#if !defined(DCONNECT_WITH_IPRT_REQ_POOL) +#include "nsIThread.h" +#include "nsIRunnable.h" +#endif + +#if defined(DEBUG) && !defined(DCONNECT_STATS) +#define DCONNECT_STATS +#endif + +#if defined(DCONNECT_STATS) +#include +#endif + +#endif + +// XXX TODO: +// 1. add thread affinity field to SETUP messages + +//----------------------------------------------------------------------------- + +#define DCONNECT_IPC_TARGETID \ +{ /* 43ca47ef-ebc8-47a2-9679-a4703218089f */ \ + 0x43ca47ef, \ + 0xebc8, \ + 0x47a2, \ + {0x96, 0x79, 0xa4, 0x70, 0x32, 0x18, 0x08, 0x9f} \ +} +static const nsID kDConnectTargetID = DCONNECT_IPC_TARGETID; + +//----------------------------------------------------------------------------- + +#define DCON_WAIT_TIMEOUT PR_INTERVAL_NO_TIMEOUT + +//----------------------------------------------------------------------------- + +// +// +--------------------------------------+ +// | major opcode : 1 byte | +// +--------------------------------------+ +// | minor opcode : 1 byte | +// +--------------------------------------+ +// | flags : 2 bytes | +// +--------------------------------------+ +// . . +// . variable payload . +// . . +// +--------------------------------------+ +// + +// dconnect major opcodes +#define DCON_OP_SETUP 1 +#define DCON_OP_RELEASE 2 +#define DCON_OP_INVOKE 3 + +#define DCON_OP_SETUP_REPLY 4 +#define DCON_OP_INVOKE_REPLY 5 + +// dconnect minor opcodes for DCON_OP_SETUP +#define DCON_OP_SETUP_NEW_INST_CLASSID 1 +#define DCON_OP_SETUP_NEW_INST_CONTRACTID 2 +#define DCON_OP_SETUP_GET_SERV_CLASSID 3 +#define DCON_OP_SETUP_GET_SERV_CONTRACTID 4 +#define DCON_OP_SETUP_QUERY_INTERFACE 5 + +// dconnect minor opcodes for RELEASE +// dconnect minor opcodes for INVOKE + +// DCON_OP_SETUP_REPLY and DCON_OP_INVOKE_REPLY flags +#define DCON_OP_FLAGS_REPLY_EXCEPTION 0x0001 + +// Within this time all the worker threads must be terminated. +#define VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS (5000) + +#pragma pack(1) + +struct DConnectOp +{ + PRUint8 opcode_major; + PRUint8 opcode_minor; + PRUint16 flags; + PRUint32 request_index; // initialized with NewRequestIndex +}; + +// SETUP structs + +struct DConnectSetup : DConnectOp +{ + nsID iid; +}; + +struct DConnectSetupClassID : DConnectSetup +{ + nsID classid; +}; + +struct DConnectSetupContractID : DConnectSetup +{ + char contractid[1]; // variable length +}; + +struct DConnectSetupQueryInterface : DConnectSetup +{ + DConAddr instance; +}; + +// SETUP_REPLY struct + +struct DConnectSetupReply : DConnectOp +{ + DConAddr instance; + nsresult status; + // optionally followed by a specially serialized nsIException instance (see + // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is + // present in flags +}; + +// RELEASE struct + +struct DConnectRelease : DConnectOp +{ + DConAddr instance; +}; + +// INVOKE struct + +struct DConnectInvoke : DConnectOp +{ + DConAddr instance; + PRUint16 method_index; + // followed by an array of in-param blobs +}; + +// INVOKE_REPLY struct + +struct DConnectInvokeReply : DConnectOp +{ + nsresult result; + // followed by an array of out-param blobs if NS_SUCCEEDED(result), and + // optionally by a specially serialized nsIException instance (see + // ipcDConnectService::SerializeException) if DCON_OP_FLAGS_REPLY_EXCEPTION is + // present in flags +}; + +#pragma pack() + +//----------------------------------------------------------------------------- + +struct DConAddrPlusPtr +{ + DConAddr addr; + void *p; +}; + +//----------------------------------------------------------------------------- + +ipcDConnectService *ipcDConnectService::mInstance = nsnull; + +//----------------------------------------------------------------------------- + +static nsresult +SetupPeerInstance(PRUint32 aPeerID, DConnectSetup *aMsg, PRUint32 aMsgLen, + void **aInstancePtr); + +//----------------------------------------------------------------------------- + +// A wrapper class holding an instance to an in-process XPCOM object. + +class DConnectInstance +{ +public: + DConnectInstance(PRUint32 peer, nsIInterfaceInfo *iinfo, nsISupports *instance) + : mPeer(peer) + , mIInfo(iinfo) + , mInstance(instance) + {} + + nsISupports *RealInstance() { return mInstance; } + nsIInterfaceInfo *InterfaceInfo() { return mIInfo; } + PRUint32 Peer() { return mPeer; } + + DConnectInstanceKey::Key GetKey() { + const nsID *iid; + mIInfo->GetIIDShared(&iid); + return DConnectInstanceKey::Key(mPeer, mInstance, iid); + } + + NS_IMETHODIMP_(nsrefcnt) AddRef(void) + { + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + nsrefcnt count; + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); + return count; + } + + NS_IMETHODIMP_(nsrefcnt) Release(void) + { + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + if (0 == count) { + NS_PRECONDITION(PRInt32(mRefCntIPC) == 0, "non-zero IPC refcnt"); + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + return count; + } + + // this gets called after calling AddRef() on an instance passed to the + // client over IPC in order to have a count of IPC client-related references + // separately from the overall reference count + NS_IMETHODIMP_(nsrefcnt) AddRefIPC(void) + { + NS_PRECONDITION(PRInt32(mRefCntIPC) >= 0, "illegal refcnt"); + nsrefcnt count = PR_AtomicIncrement((PRInt32*)&mRefCntIPC); + return count; + } + + // this gets called before calling Release() when DCON_OP_RELEASE is + // received from the IPC client and in other cases to balance AddRefIPC() + NS_IMETHODIMP_(nsrefcnt) ReleaseIPC(PRBool locked = PR_FALSE) + { + NS_PRECONDITION(0 != mRefCntIPC, "dup release"); + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCntIPC); + if (0 == count) { + // If the last IPC reference is released, remove this instance from the map. + // ipcDConnectService is guaranteed to still exist here + // (DConnectInstance lifetime is bound to ipcDConnectService) + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + if (dConnect) + dConnect->DeleteInstance(this, locked); + else + NS_NOTREACHED("ipcDConnectService has gone before DConnectInstance"); + } + return count; + } + +private: + nsAutoRefCnt mRefCnt; + nsAutoRefCnt mRefCntIPC; + PRUint32 mPeer; // peer process "owning" this instance + nsCOMPtr mIInfo; + nsCOMPtr mInstance; +}; + +void +ipcDConnectService::ReleaseWrappers(nsVoidArray &wrappers, PRUint32 peer) +{ + nsAutoLock lock (mLock); + + for (PRInt32 i=0; iPeer() == peer) + { + wrapper->ReleaseIPC(PR_TRUE /* locked */); + wrapper->Release(); + } + } +} + +//----------------------------------------------------------------------------- + +static nsresult +SerializeParam(ipcMessageWriter &writer, const nsXPTType &t, const nsXPTCMiniVariant &v) +{ + switch (t.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + writer.PutInt8(v.val.u8); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + writer.PutInt16(v.val.u16); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + writer.PutInt32(v.val.u32); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + writer.PutBytes(&v.val.u64, sizeof(PRUint64)); + break; + + case nsXPTType::T_FLOAT: + writer.PutBytes(&v.val.f, sizeof(float)); + break; + + case nsXPTType::T_DOUBLE: + writer.PutBytes(&v.val.d, sizeof(double)); + break; + + case nsXPTType::T_BOOL: + writer.PutBytes(&v.val.b, sizeof(PRBool)); + break; + + case nsXPTType::T_CHAR: + writer.PutBytes(&v.val.c, sizeof(char)); + break; + + case nsXPTType::T_WCHAR: + writer.PutBytes(&v.val.wc, sizeof(PRUnichar)); + break; + + case nsXPTType::T_IID: + { + AssertReturn(v.val.p, NS_ERROR_INVALID_POINTER); + writer.PutBytes(v.val.p, sizeof(nsID)); + } + break; + + case nsXPTType::T_CHAR_STR: + { + if (v.val.p) + { + int len = strlen((const char *) v.val.p); + writer.PutInt32(len); + writer.PutBytes(v.val.p, len); + } + else + { + // put -1 to indicate null string + writer.PutInt32((PRUint32) -1); + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + if (v.val.p) + { + int len = 2 * nsCRT::strlen((const PRUnichar *) v.val.p); + writer.PutInt32(len); + writer.PutBytes(v.val.p, len); + } + else + { + // put -1 to indicate null string + writer.PutInt32((PRUint32) -1); + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + NS_NOTREACHED("this should be handled elsewhere"); + return NS_ERROR_UNEXPECTED; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + const nsAString *str = (const nsAString *) v.val.p; + + PRUint32 len = 2 * str->Length(); + nsAString::const_iterator begin; + const PRUnichar *data = str->BeginReading(begin).get(); + + writer.PutInt32(len); + writer.PutBytes(data, len); + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + const nsACString *str = (const nsACString *) v.val.p; + + PRUint32 len = str->Length(); + nsACString::const_iterator begin; + const char *data = str->BeginReading(begin).get(); + + writer.PutInt32(len); + writer.PutBytes(data, len); + } + break; + + case nsXPTType::T_ARRAY: + // arrays are serialized after all other params outside this routine + break; + + case nsXPTType::T_VOID: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + LOG(("unexpected parameter type: %d\n", t.TagPart())); + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +static nsresult +DeserializeParam(ipcMessageReader &reader, const nsXPTType &t, nsXPTCVariant &v) +{ + // defaults + v.ptr = nsnull; + v.type = t; + v.flags = 0; + + switch (t.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + v.val.u8 = reader.GetInt8(); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + v.val.u16 = reader.GetInt16(); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + v.val.u32 = reader.GetInt32(); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + reader.GetBytes(&v.val.u64, sizeof(v.val.u64)); + break; + + case nsXPTType::T_FLOAT: + reader.GetBytes(&v.val.f, sizeof(v.val.f)); + break; + + case nsXPTType::T_DOUBLE: + reader.GetBytes(&v.val.d, sizeof(v.val.d)); + break; + + case nsXPTType::T_BOOL: + reader.GetBytes(&v.val.b, sizeof(v.val.b)); + break; + + case nsXPTType::T_CHAR: + reader.GetBytes(&v.val.c, sizeof(v.val.c)); + break; + + case nsXPTType::T_WCHAR: + reader.GetBytes(&v.val.wc, sizeof(v.val.wc)); + break; + + case nsXPTType::T_IID: + { + nsID *buf = (nsID *) nsMemory::Alloc(sizeof(nsID)); + reader.GetBytes(buf, sizeof(nsID)); + v.val.p = buf; + v.SetValIsAllocated(); + } + break; + + case nsXPTType::T_CHAR_STR: + { + PRUint32 len = reader.GetInt32(); + if (len == (PRUint32) -1) + { + // it's a null string + v.val.p = nsnull; + } + else + { + char *buf = (char *) nsMemory::Alloc(len + 1); + reader.GetBytes(buf, len); + buf[len] = char(0); + + v.val.p = buf; + v.SetValIsAllocated(); + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + PRUint32 len = reader.GetInt32(); + if (len == (PRUint32) -1) + { + // it's a null string + v.val.p = nsnull; + } + else + { + PRUnichar *buf = (PRUnichar *) nsMemory::Alloc(len + 2); + reader.GetBytes(buf, len); + buf[len / 2] = PRUnichar(0); + + v.val.p = buf; + v.SetValIsAllocated(); + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + reader.GetBytes(&v.val.u64, sizeof(DConAddr)); + // stub creation will be handled outside this routine. we only + // deserialize the DConAddr into v.val.u64 temporarily. + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + PRUint32 len = reader.GetInt32(); + + nsString *str = new nsString(); + str->SetLength(len / 2); + PRUnichar *buf = str->BeginWriting(); + reader.GetBytes(buf, len); + + v.val.p = str; + v.SetValIsDOMString(); + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + PRUint32 len = reader.GetInt32(); + + nsCString *str = new nsCString(); + str->SetLength(len); + char *buf = str->BeginWriting(); + reader.GetBytes(buf, len); + + v.val.p = str; + + // this distinction here is pretty pointless + if (t.TagPart() == nsXPTType::T_CSTRING) + v.SetValIsCString(); + else + v.SetValIsUTF8String(); + } + break; + + case nsXPTType::T_ARRAY: + // arrays are deserialized after all other params outside this routine + break; + + case nsXPTType::T_VOID: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + LOG(("unexpected parameter type\n")); + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +static nsresult +SetupParam(const nsXPTParamInfo &p, nsXPTCVariant &v) +{ + const nsXPTType &t = p.GetType(); + + if (p.IsIn() && p.IsDipper()) + { + v.ptr = nsnull; + v.flags = 0; + + switch (t.TagPart()) + { + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + v.val.p = new nsString(); + if (!v.val.p) + return NS_ERROR_OUT_OF_MEMORY; + v.type = t; + v.SetValIsDOMString(); + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + v.val.p = new nsCString(); + if (!v.val.p) + return NS_ERROR_OUT_OF_MEMORY; + v.type = t; + v.SetValIsCString(); + break; + + default: + LOG(("unhandled dipper: type=%d\n", t.TagPart())); + return NS_ERROR_UNEXPECTED; + } + } + else if (p.IsOut() || p.IsRetval()) + { + memset(&v.val, 0, sizeof(v.val)); + v.ptr = &v.val; + v.type = t; + v.flags = 0; + v.SetPtrIsData(); + + // the ownership of output nsID, string, wstring, interface pointers and + // arrays is transferred to the receiving party. Therefore, we need to + // instruct FinishParam() to perform a cleanup after serializing them. + switch (t.TagPart()) + { + case nsXPTType::T_IID: + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_ARRAY: + v.SetValIsAllocated(); + break; + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + v.SetValIsInterface(); + break; + default: + break; + } + } + + return NS_OK; +} + +static void +FinishParam(nsXPTCVariant &v) +{ +#ifdef VBOX + /* make valgrind happy */ + if (!v.MustFreeVal()) + return; +#endif + if (!v.val.p) + return; + + if (v.IsValAllocated()) + nsMemory::Free(v.val.p); + else if (v.IsValInterface()) + ((nsISupports *) v.val.p)->Release(); + else if (v.IsValDOMString()) + delete (nsAString *) v.val.p; + else if (v.IsValUTF8String() || v.IsValCString()) + delete (nsACString *) v.val.p; +} + +static nsresult +DeserializeResult(ipcMessageReader &reader, const nsXPTType &t, nsXPTCMiniVariant &v) +{ + if (v.val.p == nsnull) + return NS_OK; + + switch (t.TagPart()) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + *((PRUint8 *) v.val.p) = reader.GetInt8(); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + *((PRUint16 *) v.val.p) = reader.GetInt16(); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + *((PRUint32 *) v.val.p) = reader.GetInt32(); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + reader.GetBytes(v.val.p, sizeof(PRUint64)); + break; + + case nsXPTType::T_FLOAT: + reader.GetBytes(v.val.p, sizeof(float)); + break; + + case nsXPTType::T_DOUBLE: + reader.GetBytes(v.val.p, sizeof(double)); + break; + + case nsXPTType::T_BOOL: + reader.GetBytes(v.val.p, sizeof(PRBool)); + break; + + case nsXPTType::T_CHAR: + reader.GetBytes(v.val.p, sizeof(char)); + break; + + case nsXPTType::T_WCHAR: + reader.GetBytes(v.val.p, sizeof(PRUnichar)); + break; + + case nsXPTType::T_IID: + { + nsID *buf = (nsID *) nsMemory::Alloc(sizeof(nsID)); + reader.GetBytes(buf, sizeof(nsID)); + *((nsID **) v.val.p) = buf; + } + break; + + case nsXPTType::T_CHAR_STR: + { + PRUint32 len = reader.GetInt32(); + if (len == (PRUint32) -1) + { + // it's a null string +#ifdef VBOX + *((char **) v.val.p) = NULL; +#else + v.val.p = 0; +#endif + } + else + { + char *buf = (char *) nsMemory::Alloc(len + 1); + reader.GetBytes(buf, len); + buf[len] = char(0); + + *((char **) v.val.p) = buf; + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + PRUint32 len = reader.GetInt32(); + if (len == (PRUint32) -1) + { + // it's a null string +#ifdef VBOX + *((PRUnichar **) v.val.p) = 0; +#else + v.val.p = 0; +#endif + } + else + { + PRUnichar *buf = (PRUnichar *) nsMemory::Alloc(len + 2); + reader.GetBytes(buf, len); + buf[len / 2] = PRUnichar(0); + + *((PRUnichar **) v.val.p) = buf; + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + // stub creation will be handled outside this routine. we only + // deserialize the DConAddr and the original value of v.val.p + // into v.val.p temporarily. needs temporary memory alloc. + DConAddrPlusPtr *buf = (DConAddrPlusPtr *) nsMemory::Alloc(sizeof(DConAddrPlusPtr)); + reader.GetBytes(&buf->addr, sizeof(DConAddr)); + buf->p = v.val.p; + v.val.p = buf; + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + PRUint32 len = reader.GetInt32(); + + nsAString *str = (nsAString *) v.val.p; + + nsAString::iterator begin; + str->SetLength(len / 2); + str->BeginWriting(begin); + + reader.GetBytes(begin.get(), len); + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + PRUint32 len = reader.GetInt32(); + + nsACString *str = (nsACString *) v.val.p; + + nsACString::iterator begin; + str->SetLength(len); + str->BeginWriting(begin); + + reader.GetBytes(begin.get(), len); + } + break; + + case nsXPTType::T_ARRAY: + // arrays are deserialized after all other params outside this routine + break; + + case nsXPTType::T_VOID: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + LOG(("unexpected parameter type\n")); + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +//----------------------------------------------------------------------------- +// +// Returns an element from the nsXPTCMiniVariant array by properly casting it to +// nsXPTCVariant when requested +#define GET_PARAM(params, isXPTCVariantArray, idx) \ + (isXPTCVariantArray ? ((nsXPTCVariant *) params) [idx] : params [idx]) + +// isResult is PR_TRUE if the size_is and length_is params are out or retval +// so that nsXPTCMiniVariants contain pointers to their locations instead of the +// values themselves. +static nsresult +GetArrayParamInfo(nsIInterfaceInfo *iinfo, uint16 methodIndex, + const nsXPTMethodInfo &methodInfo, nsXPTCMiniVariant *params, + PRBool isXPTCVariantArray, const nsXPTParamInfo ¶mInfo, + PRBool isResult, PRUint32 &size, PRUint32 &length, + nsXPTType &elemType) +{ + // XXX multidimensional arrays are not supported so dimension is always 0 for + // getting the size_is argument number of the array itself and 1 for getting + // the type of elements stored in the array. + + nsresult rv; + + // get the array size + PRUint8 sizeArg; + rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, ¶mInfo, 0, &sizeArg); + if (NS_FAILED(rv)) + return rv; + + // get the number of valid elements + PRUint8 lenArg; + rv = iinfo->GetLengthIsArgNumberForParam(methodIndex, ¶mInfo, 0, &lenArg); + if (NS_FAILED(rv)) + return rv; + + // according to XPT specs + // (http://www.mozilla.org/scriptable/typelib_file.html), size_is and + // length_is for arrays is always uint32. Check this too. + { + nsXPTParamInfo pi = methodInfo.GetParam (sizeArg); + if (pi.GetType().TagPart() != nsXPTType::T_U32) + { + LOG(("unexpected size_is() parameter type: $d\n", + pi.GetType().TagPart())); + return NS_ERROR_UNEXPECTED; + } + + pi = methodInfo.GetParam (lenArg); + if (pi.GetType().TagPart() != nsXPTType::T_U32) + { + LOG(("unexpected length_is() parameter type: $d\n", + pi.GetType().TagPart())); + return NS_ERROR_UNEXPECTED; + } + } + + if (isResult) + { + length = *((PRUint32 *) GET_PARAM(params,isXPTCVariantArray, lenArg).val.p); + size = *((PRUint32 *) GET_PARAM(params, isXPTCVariantArray, sizeArg).val.p); + } + else + { + length = GET_PARAM(params, isXPTCVariantArray, lenArg).val.u32; + size = GET_PARAM(params, isXPTCVariantArray, sizeArg).val.u32; + } + + if (length > size) + { + NS_WARNING("length_is() value is greater than size_is() value"); + length = size; + } + + // get type of array elements + rv = iinfo->GetTypeForParam(methodIndex, ¶mInfo, 1, &elemType); + if (NS_FAILED(rv)) + return rv; + + if (elemType.IsArithmetic() && + (elemType.IsPointer() || elemType.IsUniquePointer() || + elemType.IsReference())) + { + LOG(("arrays of pointers and references to arithmetic types are " + "not yet supported\n")); + return NS_ERROR_NOT_IMPLEMENTED; + } + + if (elemType.IsArray()) + { + LOG(("multidimensional arrays are not yet supported\n")); + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; +} + +static nsresult +GetTypeSize(const nsXPTType &type, PRUint32 &size, PRBool &isSimple) +{ + // get the type size in bytes + size = 0; + isSimple = PR_TRUE; + switch (type.TagPart()) + { + case nsXPTType::T_I8: size = sizeof(PRInt8); break; + case nsXPTType::T_I16: size = sizeof(PRInt16); break; + case nsXPTType::T_I32: size = sizeof(PRInt32); break; + case nsXPTType::T_I64: size = sizeof(PRInt64); break; + case nsXPTType::T_U8: size = sizeof(PRUint8); break; + case nsXPTType::T_U16: size = sizeof(PRUint16); break; + case nsXPTType::T_U32: size = sizeof(PRUint32); break; + case nsXPTType::T_U64: size = sizeof(PRUint64); break; + case nsXPTType::T_FLOAT: size = sizeof(float); break; + case nsXPTType::T_DOUBLE: size = sizeof(double); break; + case nsXPTType::T_BOOL: size = sizeof(PRBool); break; + case nsXPTType::T_CHAR: size = sizeof(char); break; + case nsXPTType::T_WCHAR: size = sizeof(PRUnichar); break; + case nsXPTType::T_IID: /* fall through */ + case nsXPTType::T_CHAR_STR: /* fall through */ + case nsXPTType::T_WCHAR_STR: /* fall through */ + case nsXPTType::T_ASTRING: /* fall through */ + case nsXPTType::T_DOMSTRING: /* fall through */ + case nsXPTType::T_UTF8STRING: /* fall through */ + case nsXPTType::T_CSTRING: /* fall through */ + size = sizeof(void *); + isSimple = PR_FALSE; + break; + case nsXPTType::T_INTERFACE: /* fall through */ + case nsXPTType::T_INTERFACE_IS: /* fall through */ + size = sizeof(DConAddr); + isSimple = PR_FALSE; + break; + default: + LOG(("unexpected parameter type: %d\n", type.TagPart())); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +static nsresult +SerializeArrayParam(ipcDConnectService *dConnect, + ipcMessageWriter &writer, PRUint32 peerID, + nsIInterfaceInfo *iinfo, uint16 methodIndex, + const nsXPTMethodInfo &methodInfo, + nsXPTCMiniVariant *params, PRBool isXPTCVariantArray, + const nsXPTParamInfo ¶mInfo, + void *array, nsVoidArray &wrappers) +{ + if (!array) + { + // put 0 to indicate null array + writer.PutInt8(0); + return NS_OK; + } + + // put 1 to indicate non-null array + writer.PutInt8(1); + + PRUint32 size = 0; + PRUint32 length = 0; + nsXPTType elemType; + + nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params, + isXPTCVariantArray, paramInfo, PR_FALSE, + size, length, elemType); + if (NS_FAILED (rv)) + return rv; + + PRUint32 elemSize = 0; + PRBool isSimple = PR_TRUE; + rv = GetTypeSize(elemType, elemSize, isSimple); + if (NS_FAILED (rv)) + return rv; + + if (isSimple) + { + // this is a simple arithmetic type, write the whole array at once + writer.PutBytes(array, length * elemSize); + return NS_OK; + } + + // iterate over valid (length_is) elements of the array + // and serialize each of them + nsXPTCMiniVariant v; + for (PRUint32 i = 0; i < length; ++i) + { + v.val.p = ((void **) array) [i]; + + if (elemType.IsInterfacePointer()) + { + nsID iid; + rv = dConnect->GetIIDForMethodParam(iinfo, &methodInfo, paramInfo, elemType, + methodIndex, params, isXPTCVariantArray, + iid); + if (NS_SUCCEEDED(rv)) + rv = dConnect->SerializeInterfaceParam(writer, peerID, iid, + (nsISupports *) v.val.p, + wrappers); + } + else + rv = SerializeParam(writer, elemType, v); + + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +} + +// isResult is PR_TRUE if the array param is out or retval +static nsresult +DeserializeArrayParam(ipcDConnectService *dConnect, + ipcMessageReader &reader, PRUint32 peerID, + nsIInterfaceInfo *iinfo, uint16 methodIndex, + const nsXPTMethodInfo &methodInfo, + nsXPTCMiniVariant *params, PRBool isXPTCVariantArray, + const nsXPTParamInfo ¶mInfo, + PRBool isResult, void *&array) +{ + PRUint32 size = 0; + PRUint32 length = 0; + nsXPTType elemType; + + nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params, + isXPTCVariantArray, paramInfo, isResult, + size, length, elemType); + if (NS_FAILED(rv)) + return rv; + + PRUint8 prefix = reader.GetInt8(); + if (prefix == 0) + { + // it's a null array + array = nsnull; + return NS_OK; + } + // sanity + if (prefix != 1) + { + LOG(("unexpected array prefix: %u\n", prefix)); + return NS_ERROR_UNEXPECTED; + } + + PRUint32 elemSize = 0; + PRBool isSimple = PR_TRUE; + rv = GetTypeSize(elemType, elemSize, isSimple); + if (NS_FAILED (rv)) + return rv; + + // Note: for zero-sized arrays, we use the size of 1 because whether + // malloc(0) returns a null pointer or not (which is used in isNull()) + // is implementation-dependent according to the C standard + void *arr = nsMemory::Alloc((size ? size : 1) * elemSize); + if (arr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + // initialize the unused space of the array with zeroes + if (length < size) + memset(((PRUint8 *) arr) + length * elemSize, 0, + (size - length) * elemSize); + + if (isSimple) + { + // this is a simple arithmetic type, read the whole array at once + reader.GetBytes(arr, length * elemSize); + + array = arr; + return NS_OK; + } + + // iterate over valid (length_is) elements of the array + // and deserialize each of them individually + nsXPTCVariant v; + for (PRUint32 i = 0; i < length; ++i) + { + rv = DeserializeParam(reader, elemType, v); + + if (NS_SUCCEEDED(rv) && elemType.IsInterfacePointer()) + { + // grab the DConAddr value temporarily stored in the param + PtrBits bits = v.val.u64; + + // DeserializeInterfaceParamBits needs IID only if it's a remote object + nsID iid; + if (bits & PTRBITS_REMOTE_BIT) + rv = dConnect->GetIIDForMethodParam(iinfo, &methodInfo, paramInfo, + elemType, methodIndex, + params, isXPTCVariantArray, iid); + if (NS_SUCCEEDED(rv)) + { + nsISupports *obj = nsnull; + rv = dConnect->DeserializeInterfaceParamBits(bits, peerID, iid, obj); + if (NS_SUCCEEDED(rv)) + v.val.p = obj; + } + } + + if (NS_FAILED(rv)) + break; + + // note that we discard extended param informaton provided by nsXPTCVariant + // and will have to "reconstruct" it from the type tag in FinishArrayParam() + ((void **) arr) [i] = v.val.p; + } + + if (NS_FAILED(rv)) + nsMemory::Free(arr); + else + array = arr; + + return rv; +} + +static void +FinishArrayParam(nsIInterfaceInfo *iinfo, uint16 methodIndex, + const nsXPTMethodInfo &methodInfo, nsXPTCMiniVariant *params, + PRBool isXPTCVariantArray, const nsXPTParamInfo ¶mInfo, + const nsXPTCMiniVariant &arrayVal) +{ + // nothing to do for a null array + void *arr = arrayVal.val.p; + if (!arr) + return; + + PRUint32 size = 0; + PRUint32 length = 0; + nsXPTType elemType; + + // note that FinishArrayParam is called only from OnInvoke to free memory + // after the call has been served. When OnInvoke sets up out and retval + // parameters for the real method, it passes pointers to the nsXPTCMiniVariant + // elements of the params array themselves so that they will eventually + // receive the returned values. For this reason, both in 'in' param and + // 'out/retaval' param cases, size_is and length_is may be read by + // GetArrayParamInfo() by value. Therefore, isResult is always PR_FALSE. + nsresult rv = GetArrayParamInfo(iinfo, methodIndex, methodInfo, params, + isXPTCVariantArray, paramInfo, PR_FALSE, + size, length, elemType); + if (NS_FAILED (rv)) + return; + + nsXPTCVariant v; + v.ptr = nsnull; + v.flags = 0; + + // iterate over valid (length_is) elements of the array + // and free each of them + for (PRUint32 i = 0; i < length; ++i) + { + v.type = elemType.TagPart(); + + switch (elemType.TagPart()) + { + case nsXPTType::T_I8: /* fall through */ + case nsXPTType::T_I16: /* fall through */ + case nsXPTType::T_I32: /* fall through */ + case nsXPTType::T_I64: /* fall through */ + case nsXPTType::T_U8: /* fall through */ + case nsXPTType::T_U16: /* fall through */ + case nsXPTType::T_U32: /* fall through */ + case nsXPTType::T_U64: /* fall through */ + case nsXPTType::T_FLOAT: /* fall through */ + case nsXPTType::T_DOUBLE: /* fall through */ + case nsXPTType::T_BOOL: /* fall through */ + case nsXPTType::T_CHAR: /* fall through */ + case nsXPTType::T_WCHAR: /* fall through */ + // nothing to free for arithmetic types + continue; + case nsXPTType::T_IID: /* fall through */ + case nsXPTType::T_CHAR_STR: /* fall through */ + case nsXPTType::T_WCHAR_STR: /* fall through */ + v.val.p = ((void **) arr) [i]; + v.SetValIsAllocated(); + break; + case nsXPTType::T_INTERFACE: /* fall through */ + case nsXPTType::T_INTERFACE_IS: /* fall through */ + v.val.p = ((void **) arr) [i]; + v.SetValIsInterface(); + break; + case nsXPTType::T_ASTRING: /* fall through */ + case nsXPTType::T_DOMSTRING: /* fall through */ + v.val.p = ((void **) arr) [i]; + v.SetValIsDOMString(); + break; + case nsXPTType::T_UTF8STRING: /* fall through */ + v.val.p = ((void **) arr) [i]; + v.SetValIsUTF8String(); + break; + case nsXPTType::T_CSTRING: /* fall through */ + v.val.p = ((void **) arr) [i]; + v.SetValIsCString(); + break; + default: + LOG(("unexpected parameter type: %d\n", elemType.TagPart())); + return; + } + + FinishParam(v); + } +} + +//----------------------------------------------------------------------------- + +static PRUint32 +NewRequestIndex() +{ + static PRInt32 sRequestIndex; + return (PRUint32) PR_AtomicIncrement(&sRequestIndex); +} + +//----------------------------------------------------------------------------- + +#ifdef VBOX +typedef struct ClientDownInfo +{ + ClientDownInfo(PRUint32 aClient) + { + uClient = aClient; + uTimestamp = PR_IntervalNow(); + } + + PRUint32 uClient; + PRIntervalTime uTimestamp; +} ClientDownInfo; +typedef std::map ClientDownMap; +typedef std::list ClientDownList; + +#define MAX_CLIENT_DOWN_SIZE 10000 + +/* Protected by the queue monitor. */ +static ClientDownMap g_ClientDownMap; +static ClientDownList g_ClientDownList; + +#endif /* VBOX */ + +class DConnectMsgSelector : public ipcIMessageObserver +{ +public: + DConnectMsgSelector(PRUint32 peer, PRUint8 opCodeMajor, PRUint32 requestIndex) + : mPeer (peer) + , mOpCodeMajor(opCodeMajor) + , mRequestIndex(requestIndex) + {} + + // stack based only + NS_IMETHOD_(nsrefcnt) AddRef() { return 1; } + NS_IMETHOD_(nsrefcnt) Release() { return 1; } + + NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr); + + NS_IMETHOD OnMessageAvailable(PRUint32 aSenderID, const nsID &aTarget, + const PRUint8 *aData, PRUint32 aDataLen) + { + // accept special "client dead" messages for a given peer + // (empty target id, zero data and data length) +#ifndef VBOX + if (aSenderID == mPeer && aTarget.Equals(nsID()) && !aData && !aDataLen) + return NS_OK; +#else /* VBOX */ + if (aSenderID != IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen) + { + // Insert new client down information. Start by expiring outdated + // entries and free one element if there's still no space (if needed). + PRIntervalTime now = PR_IntervalNow(); + while (!g_ClientDownList.empty()) + { + ClientDownInfo *cInfo = g_ClientDownList.back(); + PRInt64 diff = (PRInt64)now - cInfo->uTimestamp; + if (diff < 0) + diff += (PRInt64)((PRIntervalTime)-1) + 1; + if (diff > PR_SecondsToInterval(15 * 60)) + { + g_ClientDownMap.erase(cInfo->uClient); + g_ClientDownList.pop_back(); + NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(), + "client down info inconsistency during expiry"); + delete cInfo; + } + else + break; + } + + ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID); + if (it == g_ClientDownMap.end()) + { + /* Getting size of a map is O(1), size of a list can be O(n). */ + while (g_ClientDownMap.size() >= MAX_CLIENT_DOWN_SIZE) + { + ClientDownInfo *cInfo = g_ClientDownList.back(); + g_ClientDownMap.erase(cInfo->uClient); + g_ClientDownList.pop_back(); + NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(), + "client down info inconsistency during emergency evicting"); + delete cInfo; + } + + ClientDownInfo *cInfo = new ClientDownInfo(aSenderID); + RTMEM_MAY_LEAK(cInfo); /* tstVBoxAPIPerf leaks one allocated during ComPtr::createInprocObject(). */ + g_ClientDownMap[aSenderID] = cInfo; + g_ClientDownList.push_front(cInfo); + NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(), + "client down info inconsistency after adding entry"); + } + return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE; + } + // accept special "client up" messages for a given peer + // (empty target id, zero data and data length=1) + if (aTarget.Equals(nsID()) && !aData && aDataLen == 1) + { + ClientDownMap::iterator it = g_ClientDownMap.find(aSenderID); + if (it != g_ClientDownMap.end()) + { + ClientDownInfo *cInfo = it->second; + g_ClientDownMap.erase(it); + g_ClientDownList.remove(cInfo); + NS_ASSERTION(g_ClientDownMap.size() == g_ClientDownList.size(), + "client down info inconsistency in client up case"); + delete cInfo; + } + return (aSenderID == mPeer) ? NS_OK : IPC_WAIT_NEXT_MESSAGE; + } + // accept special "client check" messages for an anonymous sender + // (invalid sender id, empty target id, zero data and data length + if (aSenderID == IPC_SENDER_ANY && aTarget.Equals(nsID()) && !aData && !aDataLen) + { + LOG(("DConnectMsgSelector::OnMessageAvailable: poll liveness for mPeer=%d\n", + mPeer)); + ClientDownMap::iterator it = g_ClientDownMap.find(mPeer); + return (it == g_ClientDownMap.end()) ? IPC_WAIT_NEXT_MESSAGE : NS_OK; + } +#endif /* VBOX */ + const DConnectOp *op = (const DConnectOp *) aData; + // accept only reply messages with the given peer/opcode/index + // (to prevent eating replies the other thread might be waiting for) + // as well as any non-reply messages (to serve external requests that + // might arrive while we're waiting for the given reply). + if (aDataLen >= sizeof(DConnectOp) && + ((op->opcode_major != DCON_OP_SETUP_REPLY && + op->opcode_major != DCON_OP_INVOKE_REPLY) || + (aSenderID == mPeer && + op->opcode_major == mOpCodeMajor && + op->request_index == mRequestIndex))) + return NS_OK; + else + return IPC_WAIT_NEXT_MESSAGE; + } + + const PRUint32 mPeer; + const PRUint8 mOpCodeMajor; + const PRUint32 mRequestIndex; +}; +NS_IMPL_QUERY_INTERFACE1(DConnectMsgSelector, ipcIMessageObserver) + +class DConnectCompletion : public ipcIMessageObserver +{ +public: + DConnectCompletion(PRUint32 peer, PRUint8 opCodeMajor, PRUint32 requestIndex) + : mSelector(peer, opCodeMajor, requestIndex) + {} + + // stack based only + NS_IMETHOD_(nsrefcnt) AddRef() { return 1; } + NS_IMETHOD_(nsrefcnt) Release() { return 1; } + + NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr); + + NS_IMETHOD OnMessageAvailable(PRUint32 aSenderID, const nsID &aTarget, + const PRUint8 *aData, PRUint32 aDataLen) + { + const DConnectOp *op = (const DConnectOp *) aData; + LOG(( + "DConnectCompletion::OnMessageAvailable: " + "senderID=%d, opcode_major=%d, index=%d (waiting for %d)\n", + aSenderID, op->opcode_major, op->request_index, mSelector.mRequestIndex + )); + if (aSenderID == mSelector.mPeer && + op->opcode_major == mSelector.mOpCodeMajor && + op->request_index == mSelector.mRequestIndex) + { + OnResponseAvailable(aSenderID, op, aDataLen); + } + else + { + // ensure ipcDConnectService is not deleted before we finish + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + if (dConnect) + dConnect->OnMessageAvailable(aSenderID, aTarget, aData, aDataLen); + } + return NS_OK; + } + + virtual void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen) = 0; + + DConnectMsgSelector &GetSelector() + { + return mSelector; + } + +protected: + DConnectMsgSelector mSelector; +}; +NS_IMPL_QUERY_INTERFACE1(DConnectCompletion, ipcIMessageObserver) + +//----------------------------------------------------------------------------- + +class DConnectInvokeCompletion : public DConnectCompletion +{ +public: + DConnectInvokeCompletion(PRUint32 peer, const DConnectInvoke *invoke) + : DConnectCompletion(peer, DCON_OP_INVOKE_REPLY, invoke->request_index) + , mReply(nsnull) + , mParamsLen(0) + {} + + ~DConnectInvokeCompletion() { if (mReply) free(mReply); } + + void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen) + { + mReply = (DConnectInvokeReply *) malloc(opLen); + memcpy(mReply, op, opLen); + + // the length in bytes of the parameter blob + mParamsLen = opLen - sizeof(*mReply); + } + + PRBool IsPending() const { return mReply == nsnull; } + nsresult GetResult() const { return mReply->result; } + + const PRUint8 *Params() const { return (const PRUint8 *) (mReply + 1); } + PRUint32 ParamsLen() const { return mParamsLen; } + + const DConnectInvokeReply *Reply() const { return mReply; } + +private: + DConnectInvokeReply *mReply; + PRUint32 mParamsLen; +}; + +//----------------------------------------------------------------------------- + +#define DCONNECT_STUB_ID \ +{ /* 132c1f14-5442-49cb-8fe6-e60214bbf1db */ \ + 0x132c1f14, \ + 0x5442, \ + 0x49cb, \ + {0x8f, 0xe6, 0xe6, 0x02, 0x14, 0xbb, 0xf1, 0xdb} \ +} +static NS_DEFINE_IID(kDConnectStubID, DCONNECT_STUB_ID); + +// this class represents the non-local object instance. + +class DConnectStub : public nsXPTCStubBase +{ +public: + NS_DECL_ISUPPORTS + + DConnectStub(nsIInterfaceInfo *aIInfo, + DConAddr aInstance, + PRUint32 aPeerID) + : mIInfo(aIInfo) + , mInstance(aInstance) + , mPeerID(aPeerID) + , mCachedISupports(0) + , mRefCntLevels(0) + {} + + NS_HIDDEN ~DConnectStub(); + + // return a refcounted pointer to the InterfaceInfo for this object + // NOTE: on some platforms this MUST not fail or we crash! + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo **aInfo); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const nsXPTMethodInfo *aInfo, + nsXPTCMiniVariant *aParams); + + DConAddr Instance() { return mInstance; } + PRUint32 PeerID() { return mPeerID; } + + DConnectStubKey::Key GetKey() { + return DConnectStubKey::Key(mPeerID, mInstance); + } + + NS_IMETHOD_(nsrefcnt) AddRefIPC(); + +private: + nsCOMPtr mIInfo; + + // uniquely identifies this object instance between peers. + DConAddr mInstance; + + // the "client id" of our IPC peer. this guy owns the real object. + PRUint32 mPeerID; + + // cached nsISupports stub for this object + DConnectStub *mCachedISupports; + + // stack of reference counter values (protected by + // ipcDConnectService::StubLock()) + nsDeque mRefCntLevels; +}; + +NS_IMETHODIMP_(nsrefcnt) +DConnectStub::AddRefIPC() +{ + // in this special version, we memorize the resulting reference count in the + // associated stack array. This stack is then used by Release() to determine + // when it is necessary to send a RELEASE request to the peer owning the + // object in order to balance AddRef() the peer does on DConnectInstance every + // time it passes an object over IPC. + + // NOTE: this function is to be called from DConnectInstance::CreateStub only! + + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)"); + if (!dConnect) + return 0; + + // dConnect->StubLock() must be already locked here by + // DConnectInstance::CreateStub + + nsrefcnt count = AddRef(); + mRefCntLevels.Push((void *)(uintptr_t) count); + return count; +} + +nsresult +ipcDConnectService::CreateStub(const nsID &iid, PRUint32 peer, DConAddr instance, + DConnectStub **result) +{ + nsresult rv; + + nsCOMPtr iinfo; + rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + nsAutoLock lock (mLock); + + if (mDisconnected) + return NS_ERROR_NOT_INITIALIZED; + + // we also need the stub lock which protects DConnectStub::mRefCntLevels and + // ipcDConnectService::mStubs + nsAutoLock stubLock (mStubLock); + + DConnectStub *stub = nsnull; + + // first try to find an existing stub for a given peer and instance + // (we do not care about IID because every DConAddr instance represents + // exactly one interface of the real object on the peer's side) + if (!mStubs.Get(DConnectStubKey::Key(peer, instance), &stub)) + { + stub = new DConnectStub(iinfo, instance, peer); + + if (NS_UNLIKELY(!stub)) + rv = NS_ERROR_OUT_OF_MEMORY; + else + { + rv = StoreStub(stub); + if (NS_FAILED(rv)) + delete stub; + } + } + + if (NS_SUCCEEDED(rv)) + { + stub->AddRefIPC(); + *result = stub; + } + + return rv; +} + +nsresult +ipcDConnectService::SerializeInterfaceParam(ipcMessageWriter &writer, + PRUint32 peer, const nsID &iid, + nsISupports *obj, + nsVoidArray &wrappers) +{ + nsAutoLock lock (mLock); + + if (mDisconnected) + return NS_ERROR_NOT_INITIALIZED; + + // we create an instance wrapper, and assume that the other side will send a + // RELEASE message when it no longer needs the instance wrapper. that will + // usually happen after the call returns. + // + // XXX a lazy scheme might be better, but for now simplicity wins. + + // if the interface pointer references a DConnectStub corresponding + // to an object in the address space of the peer, then no need to + // create a new wrapper. + + // if the interface pointer references an object for which we already have + // an existing wrapper, then we use it instead of creating a new one. this + // is based on the assumption that a valid COM object always returns exactly + // the same pointer value in response to every + // QueryInterface(NS_GET_IID(nsISupports), ...). + + if (!obj) + { + // write null address + DConAddr nullobj = 0; + writer.PutBytes(&nullobj, sizeof(nullobj)); + } + else + { + DConnectStub *stub = nsnull; + nsresult rv = obj->QueryInterface(kDConnectStubID, (void **) &stub); + if (NS_SUCCEEDED(rv) && (stub->PeerID() == peer)) + { + DConAddr p = stub->Instance(); + writer.PutBytes(&p, sizeof(p)); + } + else + { + // create instance wrapper + + nsCOMPtr iinfo; + rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + DConnectInstance *wrapper = nsnull; + + // first try to find an existing wrapper for the given object + if (!FindInstanceAndAddRef(peer, obj, &iid, &wrapper)) + { + wrapper = new DConnectInstance(peer, iinfo, obj); + if (!wrapper) + return NS_ERROR_OUT_OF_MEMORY; + + rv = StoreInstance(wrapper); + if (NS_FAILED(rv)) + { + delete wrapper; + return rv; + } + + // reference the newly created wrapper + wrapper->AddRef(); + } + + // increase the second, IPC-only, reference counter (mandatory before + // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove + // the wrapper from the instance map on failure) + wrapper->AddRefIPC(); + + if (!wrappers.AppendElement(wrapper)) + { + wrapper->ReleaseIPC(); + wrapper->Release(); + return NS_ERROR_OUT_OF_MEMORY; + } + + // wrapper remains referenced when passing it to the client + // (will be released upon DCON_OP_RELEASE) + + // send address of the instance wrapper, and set the low bit to indicate + // to the remote party that this is a remote instance wrapper. + PtrBits bits = ((PtrBits)(uintptr_t) wrapper); + NS_ASSERTION((bits & PTRBITS_REMOTE_BIT) == 0, "remote bit wrong)"); + bits |= PTRBITS_REMOTE_BIT; + writer.PutBytes(&bits, sizeof(bits)); + } + NS_IF_RELEASE(stub); + } + return NS_OK; +} + +// NOTE: peer and iid are ignored if bits doesn't contain PTRBITS_REMOTE_BIT +nsresult +ipcDConnectService::DeserializeInterfaceParamBits(PtrBits bits, PRUint32 peer, + const nsID &iid, + nsISupports *&obj) +{ + nsresult rv; + + obj = nsnull; + + if (bits & PTRBITS_REMOTE_BIT) + { + // pointer is to a remote object. we need to build a stub. + + bits &= ~PTRBITS_REMOTE_BIT; + + DConnectStub *stub; + rv = CreateStub(iid, peer, (DConAddr) bits, &stub); + if (NS_SUCCEEDED(rv)) + obj = stub; + } + else if (bits) + { + // pointer is to one of our instance wrappers. Replace it with the + // real instance. + + DConnectInstance *wrapper = (DConnectInstance *) bits; + // make sure we've been sent a valid wrapper + if (!CheckInstanceAndAddRef(wrapper, peer)) + { + NS_NOTREACHED("instance wrapper not found"); + return NS_ERROR_INVALID_ARG; + } + obj = wrapper->RealInstance(); + NS_ADDREF(obj); + NS_RELEASE(wrapper); + } + else + { + // obj is alredy nsnull + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +#define EXCEPTION_STUB_ID \ +{ /* 70578d68-b25e-4370-a70c-89bbe56e6699 */ \ + 0x70578d68, \ + 0xb25e, \ + 0x4370, \ + {0xa7, 0x0c, 0x89, 0xbb, 0xe5, 0x6e, 0x66, 0x99} \ +} +static NS_DEFINE_IID(kExceptionStubID, EXCEPTION_STUB_ID); + +// ExceptionStub is used to cache all primitive-typed bits of a remote nsIException +// instance (such as the error message or line number) to: +// +// a) reduce the number of IPC calls; +// b) make sure exception information is available to the calling party even if +// the called party terminates immediately after returning an exception. +// To achieve this, all cacheable information is serialized together with +// the instance wrapper itself. + +class ExceptionStub : public nsIException +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIEXCEPTION + + ExceptionStub(const nsACString &aMessage, nsresult aResult, + const nsACString &aName, const nsACString &aFilename, + PRUint32 aLineNumber, PRUint32 aColumnNumber, + DConnectStub *aXcptStub) + : mMessage(aMessage), mResult(aResult) + , mName(aName), mFilename(aFilename) + , mLineNumber (aLineNumber), mColumnNumber (aColumnNumber) + , mXcptStub (aXcptStub) { NS_ASSERTION(aXcptStub, "NULL"); } + + ~ExceptionStub() {} + + nsIException *Exception() { return (nsIException *)(nsISupports *) mXcptStub; } + DConnectStub *Stub() { return mXcptStub; } + +private: + + nsCString mMessage; + nsresult mResult; + nsCString mName; + nsCString mFilename; + PRUint32 mLineNumber; + PRUint32 mColumnNumber; + nsRefPtr mXcptStub; +}; + +NS_IMPL_THREADSAFE_ADDREF(ExceptionStub) +NS_IMPL_THREADSAFE_RELEASE(ExceptionStub) + +NS_IMETHODIMP +ExceptionStub::QueryInterface(const nsID &aIID, void **aInstancePtr) +{ + NS_ASSERTION(aInstancePtr, + "QueryInterface requires a non-NULL destination!"); + + // used to discover if this is an ExceptionStub instance. + if (aIID.Equals(kExceptionStubID)) + { + *aInstancePtr = this; + NS_ADDREF_THIS(); + return NS_OK; + } + + // regular NS_IMPL_QUERY_INTERFACE1 sequence + + nsISupports* foundInterface = 0; + + if (aIID.Equals(NS_GET_IID(nsIException))) + foundInterface = NS_STATIC_CAST(nsIException*, this); + else + if (aIID.Equals(NS_GET_IID(nsISupports))) + foundInterface = NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsIException *, this)); + else + if (mXcptStub) + { + // ask the real nsIException object + return mXcptStub->QueryInterface(aIID, aInstancePtr); + } + + nsresult status; + if (!foundInterface) + status = NS_NOINTERFACE; + else + { + NS_ADDREF(foundInterface); + status = NS_OK; + } + *aInstancePtr = foundInterface; + return status; +} + +/* readonly attribute string message; */ +NS_IMETHODIMP ExceptionStub::GetMessage(char **aMessage) +{ + AssertReturn(aMessage, NS_ERROR_INVALID_POINTER); + *aMessage = ToNewCString(mMessage); + return NS_OK; +} + +/* readonly attribute nsresult result; */ +NS_IMETHODIMP ExceptionStub::GetResult(nsresult *aResult) +{ + AssertReturn(aResult, NS_ERROR_INVALID_POINTER); + *aResult = mResult; + return NS_OK; +} + +/* readonly attribute string name; */ +NS_IMETHODIMP ExceptionStub::GetName(char **aName) +{ + AssertReturn(aName, NS_ERROR_INVALID_POINTER); + *aName = ToNewCString(mName); + return NS_OK; +} + +/* readonly attribute string filename; */ +NS_IMETHODIMP ExceptionStub::GetFilename(char **aFilename) +{ + AssertReturn(aFilename, NS_ERROR_INVALID_POINTER); + *aFilename = ToNewCString(mFilename); + return NS_OK; +} + +/* readonly attribute PRUint32 lineNumber; */ +NS_IMETHODIMP ExceptionStub::GetLineNumber(PRUint32 *aLineNumber) +{ + AssertReturn(aLineNumber, NS_ERROR_INVALID_POINTER); + *aLineNumber = mLineNumber; + return NS_OK; +} + +/* readonly attribute PRUint32 columnNumber; */ +NS_IMETHODIMP ExceptionStub::GetColumnNumber(PRUint32 *aColumnNumber) +{ + AssertReturn(aColumnNumber, NS_ERROR_INVALID_POINTER); + *aColumnNumber = mColumnNumber; + return NS_OK; +} + +/* readonly attribute nsIStackFrame location; */ +NS_IMETHODIMP ExceptionStub::GetLocation(nsIStackFrame **aLocation) +{ + if (Exception()) + return Exception()->GetLocation (aLocation); + return NS_ERROR_UNEXPECTED; +} + +/* readonly attribute nsIException inner; */ +NS_IMETHODIMP ExceptionStub::GetInner(nsIException **aInner) +{ + if (Exception()) + return Exception()->GetInner (aInner); + return NS_ERROR_UNEXPECTED; +} + +/* readonly attribute nsISupports data; */ +NS_IMETHODIMP ExceptionStub::GetData(nsISupports * *aData) +{ + if (Exception()) + return Exception()->GetData (aData); + return NS_ERROR_UNEXPECTED; +} + +/* string toString (); */ +NS_IMETHODIMP ExceptionStub::ToString(char **_retval) +{ + if (Exception()) + return Exception()->ToString (_retval); + return NS_ERROR_UNEXPECTED; +} + +nsresult +ipcDConnectService::SerializeException(ipcMessageWriter &writer, + PRUint32 peer, nsIException *xcpt, + nsVoidArray &wrappers) +{ + PRBool cache_fields = PR_FALSE; + + // first, seralize the nsIException pointer. The code is merely the same as + // in SerializeInterfaceParam() except that when the exception to serialize + // is an ExceptionStub instance and the real instance it stores as mXcpt + // is a DConnectStub corresponding to an object in the address space of the + // peer, we simply pass that object back instead of creating a new wrapper. + + { + nsAutoLock lock (mLock); + + if (mDisconnected) + return NS_ERROR_NOT_INITIALIZED; + + if (!xcpt) + { + // write null address +#ifdef VBOX + // see ipcDConnectService::DeserializeException()! + PtrBits bits = 0; + writer.PutBytes(&bits, sizeof(bits)); +#else + writer.PutBytes(&xcpt, sizeof(xcpt)); +#endif + } + else + { + ExceptionStub *stub = nsnull; + nsresult rv = xcpt->QueryInterface(kExceptionStubID, (void **) &stub); + if (NS_SUCCEEDED(rv) && (stub->Stub()->PeerID() == peer)) + { + // send the wrapper instance back to the peer + DConAddr p = stub->Stub()->Instance(); + writer.PutBytes(&p, sizeof(p)); + } + else + { + // create instance wrapper + + const nsID &iid = nsIException::GetIID(); + nsCOMPtr iinfo; + rv = GetInterfaceInfo(iid, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + DConnectInstance *wrapper = nsnull; + + // first try to find an existing wrapper for the given object + if (!FindInstanceAndAddRef(peer, xcpt, &iid, &wrapper)) + { + wrapper = new DConnectInstance(peer, iinfo, xcpt); + if (!wrapper) + return NS_ERROR_OUT_OF_MEMORY; + + rv = StoreInstance(wrapper); + if (NS_FAILED(rv)) + { + delete wrapper; + return rv; + } + + // reference the newly created wrapper + wrapper->AddRef(); + } + + // increase the second, IPC-only, reference counter (mandatory before + // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove + // the wrapper from the instance map on failure) + wrapper->AddRefIPC(); + + if (!wrappers.AppendElement(wrapper)) + { + wrapper->ReleaseIPC(); + wrapper->Release(); + return NS_ERROR_OUT_OF_MEMORY; + } + + // wrapper remains referenced when passing it to the client + // (will be released upon DCON_OP_RELEASE) + + // send address of the instance wrapper, and set the low bit to indicate + // to the remote party that this is a remote instance wrapper. + PtrBits bits = ((PtrBits)(uintptr_t) wrapper) | PTRBITS_REMOTE_BIT; + writer.PutBytes(&bits, sizeof(bits)); + + // we want to cache fields to minimize the number of IPC calls when + // accessing exception data on the peer side + cache_fields = PR_TRUE; + } + NS_IF_RELEASE(stub); + } + } + + if (!cache_fields) + return NS_OK; + + nsresult rv; + nsXPIDLCString str; + PRUint32 num; + + // message + rv = xcpt->GetMessage(getter_Copies(str)); + if (NS_SUCCEEDED (rv)) + { + PRUint32 len = str.Length(); + nsACString::const_iterator begin; + const char *data = str.BeginReading(begin).get(); + writer.PutInt32(len); + writer.PutBytes(data, len); + } + else + writer.PutInt32(0); + + // result + nsresult res = 0; + xcpt->GetResult(&res); + writer.PutInt32(res); + + // name + rv = xcpt->GetName(getter_Copies(str)); + if (NS_SUCCEEDED (rv)) + { + PRUint32 len = str.Length(); + nsACString::const_iterator begin; + const char *data = str.BeginReading(begin).get(); + writer.PutInt32(len); + writer.PutBytes(data, len); + } + else + writer.PutInt32(0); + + // filename + rv = xcpt->GetFilename(getter_Copies(str)); + if (NS_SUCCEEDED (rv)) + { + PRUint32 len = str.Length(); + nsACString::const_iterator begin; + const char *data = str.BeginReading(begin).get(); + writer.PutInt32(len); + writer.PutBytes(data, len); + } + else + writer.PutInt32(0); + + // lineNumber + num = 0; + xcpt->GetLineNumber(&num); + writer.PutInt32(num); + + // columnNumber + num = 0; + xcpt->GetColumnNumber(&num); + writer.PutInt32(num); + + return writer.HasError() ? NS_ERROR_OUT_OF_MEMORY : NS_OK; +} + +nsresult +ipcDConnectService::DeserializeException(ipcMessageReader &reader, + PRUint32 peer, + nsIException **xcpt) +{ + NS_ASSERTION (xcpt, "NULL"); + if (!xcpt) + return NS_ERROR_INVALID_POINTER; + + nsresult rv; + PRUint32 len; + + PtrBits bits = 0; + reader.GetBytes(&bits, sizeof(DConAddr)); + if (reader.HasError()) + return NS_ERROR_INVALID_ARG; + + if (bits & PTRBITS_REMOTE_BIT) + { + // pointer is a peer-side exception instance wrapper, + // read cahced exception data and create a stub for it. + + nsCAutoString message; + len = reader.GetInt32(); + if (len) + { + message.SetLength(len); + char *buf = message.BeginWriting(); + reader.GetBytes(buf, len); + } + + nsresult result = reader.GetInt32(); + + nsCAutoString name; + len = reader.GetInt32(); + if (len) + { + name.SetLength(len); + char *buf = name.BeginWriting(); + reader.GetBytes(buf, len); + } + + nsCAutoString filename; + len = reader.GetInt32(); + if (len) + { + filename.SetLength(len); + char *buf = filename.BeginWriting(); + reader.GetBytes(buf, len); + } + + PRUint32 lineNumber = reader.GetInt32(); + PRUint32 columnNumber = reader.GetInt32(); + + if (reader.HasError()) + rv = NS_ERROR_INVALID_ARG; + else + { + DConAddr addr = (DConAddr) (bits & ~PTRBITS_REMOTE_BIT); + nsRefPtr stub; + rv = CreateStub(nsIException::GetIID(), peer, addr, + getter_AddRefs(stub)); + if (NS_SUCCEEDED(rv)) + { + // create a special exception "stub" with cached error info + ExceptionStub *xcptStub = + new ExceptionStub (message, result, + name, filename, + lineNumber, columnNumber, + stub); + if (xcptStub) + { + *xcpt = xcptStub; + NS_ADDREF(xcptStub); + } + else + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } + else if (bits) + { + // pointer is to our instance wrapper for nsIException we've sent before + // (the remote method we've called had called us back and got an exception + // from us that it decided to return as its own result). Replace it with + // the real instance. + DConnectInstance *wrapper = (DConnectInstance *) bits; + if (CheckInstanceAndAddRef(wrapper, peer)) + { + *xcpt = (nsIException *) wrapper->RealInstance(); + NS_ADDREF(wrapper->RealInstance()); + wrapper->Release(); + rv = NS_OK; + } + else + { + NS_NOTREACHED("instance wrapper not found"); + rv = NS_ERROR_INVALID_ARG; + } + } + else + { + // the peer explicitly passed us a NULL exception to indicate that the + // exception on the current thread should be reset + *xcpt = NULL; + return NS_OK; + } + + + return rv; +} + +//----------------------------------------------------------------------------- + +DConnectStub::~DConnectStub() +{ +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name = NULL; + mIInfo->GetNameShared(&name); + LOG(("{%p} DConnectStub::(): peer=%d instance=0x%Lx {%s}\n", + this, mPeerID, mInstance, name)); + } +#endif + + // release the cached nsISupports instance if it's not the same object + if (mCachedISupports != 0 && mCachedISupports != this) + NS_RELEASE(mCachedISupports); +} + +NS_IMETHODIMP_(nsrefcnt) +DConnectStub::AddRef() +{ + nsrefcnt count; + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, count, "DConnectStub", sizeof(*this)); + return count; +} + +NS_IMETHODIMP_(nsrefcnt) +DConnectStub::Release() +{ + nsrefcnt count; + + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + if (dConnect) + { + // lock the stub lock on every release to make sure that once the counter + // drops to zero, we delete the stub from the set of stubs before a new + // request to create a stub on other thread tries to find the existing + // stub in the set (wchich could otherwise AddRef the object after it had + // Released to zero and pass it to the client right before its + // destruction). + nsAutoLock stubLock (dConnect->StubLock()); + + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "DConnectStub"); + + + #ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + mIInfo->GetNameShared(&name); + LOG(("{%p} DConnectStub::Release(): peer=%d instance=0x%Lx {%s}, new count=%d\n", + this, mPeerID, mInstance, name, count)); + } + #endif + + // mRefCntLevels may already be empty here (due to the "stabilize" trick below) + if (mRefCntLevels.GetSize() > 0) + { + nsrefcnt top = (nsrefcnt) (long) mRefCntLevels.Peek(); + NS_ASSERTION(top <= count + 1, "refcount is beyond the top level"); + + if (top == count + 1) + { + // refcount dropped to a value stored in ipcDConnectService::CreateStub. + // Send a RELEASE request to the peer (see also AddRefIPC). + + // remove the top refcount value + mRefCntLevels.Pop(); + + if (0 == count) + { + // this is the last reference, remove from the set before we leave + // the lock, to provide atomicity of these two operations + dConnect->DeleteStub (this); + + NS_ASSERTION(mRefCntLevels.GetSize() == 0, "refcnt levels are still left"); + } + + // leave the lock before sending a message + stubLock.unlock(); + + nsresult rv; + + DConnectRelease msg; + msg.opcode_major = DCON_OP_RELEASE; + msg.opcode_minor = 0; + msg.flags = 0; + msg.request_index = 0; // not used, set to some unused value + msg.instance = mInstance; + + // fire off asynchronously... we don't expect any response to this message. + rv = IPC_SendMessage(mPeerID, kDConnectTargetID, + (const PRUint8 *) &msg, sizeof(msg)); + if (NS_FAILED(rv)) + NS_WARNING("failed to send RELEASE event"); + } + } + } + else + { + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "DConnectStub"); + } + + if (0 == count) + { + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + + return count; +} + +NS_IMETHODIMP +DConnectStub::QueryInterface(const nsID &aIID, void **aInstancePtr) +{ + // used to discover if this is a DConnectStub instance. + if (aIID.Equals(kDConnectStubID)) + { + *aInstancePtr = this; + NS_ADDREF_THIS(); + return NS_OK; + } + + // In order to truely support the COM Identity Rule across processes, + // we need to make the following code work: + // + // IFoo *foo = ... + // nsISupports unk; + // foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk); + // unk->Release(); + // nsISupports unk2; + // foo->QueryInterface(NS_GET_IID(nsISupports), (void **) &unk2); + // Assert (unk == unk2); + // + // I.e. querying nsISupports on the same object must always return the same + // pointer, even if the nsISupports object returned for the first time is + // released before it is requested for the second time, as long as the + // original object is kept alive (referenced by the client) between these + // two queries. + // + // This is done by remembering the nsISupports stub returned by the peer + // when nsISupports is queried for the first time. The remembered stub, when + // it is not the same as this object, is strongly referenced in order to + // keep it alive (and therefore have the same pointer value) as long as this + // object is alive. + // + // Besides supporting the Identity Rule, this also reduces the number of IPC + // calls, since an IPC call requesting nsISupports will be done only once + // per every stub object. + + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + NS_ASSERTION(dConnect, "no ipcDConnectService (uninitialized?)"); + if (!dConnect) + return NS_ERROR_NOT_INITIALIZED; + + nsresult rv; + PRBool needISupports = aIID.Equals(NS_GET_IID(nsISupports)); + + if (needISupports) + { + // XXX it would be sufficient to use cmpxchg here to protect access to + // mCachedISupports, but NSPR doesn't provide cross-platform cmpxchg + // functionality, so we have to use a shared lock instead... + PR_Lock(dConnect->StubQILock()); + + // check if we have already got a nsISupports stub for this object + if (mCachedISupports != 0) + { + *aInstancePtr = mCachedISupports; + NS_ADDREF(mCachedISupports); + + PR_Unlock(dConnect->StubQILock()); + return NS_OK; + } + + // check if this object is nsISupports itself + { + nsIID *iid = 0; + rv = mIInfo->GetInterfaceIID(&iid); + NS_ASSERTION(NS_SUCCEEDED(rv) && iid, + "nsIInterfaceInfo::GetInterfaceIID failed"); + if (NS_SUCCEEDED(rv) && iid && + iid->Equals(NS_GET_IID(nsISupports))) + { + nsMemory::Free((void*)iid); + + // nsISupports is queried on nsISupports, return ourselves + *aInstancePtr = this; + NS_ADDREF_THIS(); + // cache ourselves weakly + mCachedISupports = this; + + PR_Unlock(dConnect->StubQILock()); + return NS_OK; + } + if (iid) + nsMemory::Free((void*)iid); + } + + // stub lock remains held until we've queried the peer + } + + // else, we need to query the peer object by making an IPC call + +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + mIInfo->GetNameShared(&name); + const char *nameQ; + nsCOMPtr iinfoQ; + dConnect->GetInterfaceInfo(aIID, getter_AddRefs(iinfoQ)); + if (iinfoQ) { + iinfoQ->GetNameShared(&nameQ); + LOG(("calling QueryInterface {%s} on peer object " + "(stub=%p, instance=0x%Lx {%s})\n", + nameQ, this, mInstance, name)); + } + } +#endif + + DConnectSetupQueryInterface msg; + msg.opcode_minor = DCON_OP_SETUP_QUERY_INTERFACE; + msg.iid = aIID; + msg.instance = mInstance; + + rv = SetupPeerInstance(mPeerID, &msg, sizeof(msg), aInstancePtr); + + if (needISupports) + { + if (NS_SUCCEEDED(rv)) + { + // cache the nsISupports object (SetupPeerInstance returns DConnectStub) + mCachedISupports = (DConnectStub *) *aInstancePtr; + // use a weak reference if nsISupports is the same object as us + if (this != mCachedISupports) + NS_ADDREF(mCachedISupports); + } + + PR_Unlock(dConnect->StubQILock()); + } + + return rv; +} + +NS_IMETHODIMP +DConnectStub::GetInterfaceInfo(nsIInterfaceInfo **aInfo) +{ + NS_ADDREF(*aInfo = mIInfo); + return NS_OK; +} + +NS_IMETHODIMP +DConnectStub::CallMethod(PRUint16 aMethodIndex, + const nsXPTMethodInfo *aInfo, + nsXPTCMiniVariant *aParams) +{ + LOG(("DConnectStub::CallMethod [methodIndex=%hu]\n", aMethodIndex)); + + nsresult rv; + + // reset the exception early. this is necessary because we may return a + // failure from here without setting an exception (which might be expected + // by the caller to detect the error origin: the interface we are stubbing + // may indicate in some way that it always sets the exception info on + // failure, therefore an "infoless" failure means the origin is RPC). + // besides that, resetting the excetion before every IPC call is exactly the + // same thing as Win32 RPC does, so doing this is useful for getting + // similarity in behaviors. + + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv); + if (NS_FAILED (rv)) + return rv; + nsCOMPtr em; + rv = es->GetCurrentExceptionManager (getter_AddRefs(em)); + if (NS_FAILED (rv)) + return rv; + rv = em->SetCurrentException(NULL); + if (NS_FAILED (rv)) + return rv; + + // ensure ipcDConnectService is not deleted before we finish + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + if (!dConnect) + return NS_ERROR_FAILURE; + + // dump arguments + + PRUint8 i, paramCount = aInfo->GetParamCount(); + +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + nsCOMPtr iinfo; + GetInterfaceInfo(getter_AddRefs(iinfo)); + iinfo->GetNameShared(&name); + LOG((" instance=0x%Lx {%s}\n", mInstance, name)); + LOG((" name=%s\n", aInfo->GetName())); + LOG((" param-count=%u\n", (PRUint32) paramCount)); + } +#endif + + + ipcMessageWriter writer(16 * paramCount); + + // INVOKE message header + DConnectInvoke invoke; + invoke.opcode_major = DCON_OP_INVOKE; + invoke.opcode_minor = 0; + invoke.flags = 0; + invoke.request_index = NewRequestIndex(); + invoke.instance = mInstance; + invoke.method_index = aMethodIndex; + + LOG((" request-index=%d\n", (PRUint32) invoke.request_index)); + + writer.PutBytes(&invoke, sizeof(invoke)); + + // list of wrappers that get created during parameter serialization. if we + // are unable to send the INVOKE message, then we'll clean these up. + nsVoidArray wrappers; + + for (i=0; iGetParam(i); + + if (paramInfo.IsIn() && !paramInfo.IsDipper()) + { + const nsXPTType &type = paramInfo.GetType(); + + if (type.IsInterfacePointer()) + { + nsID iid; + rv = dConnect->GetIIDForMethodParam(mIInfo, aInfo, paramInfo, type, + aMethodIndex, aParams, PR_FALSE, iid); + if (NS_SUCCEEDED(rv)) + rv = dConnect->SerializeInterfaceParam(writer, mPeerID, iid, + (nsISupports *) aParams[i].val.p, + wrappers); + } + else + rv = SerializeParam(writer, type, aParams[i]); + + AssertMsgBreak(NS_SUCCEEDED(rv), ("i=%d rv=%#x\n", i, rv)); + } + else if ((paramInfo.IsOut() || paramInfo.IsRetval()) && !aParams[i].val.p) + { + // report error early if NULL pointer is passed as an output parameter + rv = NS_ERROR_NULL_POINTER; + AssertMsgFailedBreak(("i=%d IsOut=%d IsRetval=%d NS_ERROR_NULL_POINTER\n", i, paramInfo.IsOut(), paramInfo.IsRetval())); + break; + } + } + + if (NS_FAILED(rv)) + { + // INVOKE message wasn't sent; clean up wrappers + dConnect->ReleaseWrappers(wrappers, mPeerID); + return rv; + } + + // serialize input array parameters after everything else since the + // deserialization procedure will need to get a size_is value which may be + // stored in any preceeding or following param + for (i=0; iGetParam(i); + + if (paramInfo.GetType().IsArray() && + paramInfo.IsIn() && !paramInfo.IsDipper()) + { + rv = SerializeArrayParam(dConnect, writer, mPeerID, mIInfo, aMethodIndex, + *aInfo, aParams, PR_FALSE, paramInfo, + aParams[i].val.p, wrappers); + if (NS_FAILED(rv)) + { + // INVOKE message wasn't sent; clean up wrappers + dConnect->ReleaseWrappers(wrappers, mPeerID); + return rv; + } + } + } + + // temporarily disable the DConnect target observer to block normal processing + // of pending messages through the event queue. + IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kDConnectTargetID); + + rv = IPC_SendMessage(mPeerID, kDConnectTargetID, + writer.GetBuffer(), + writer.GetSize()); + LOG(("DConnectStub::CallMethod: IPC_SendMessage()=%08X\n", rv)); + if (NS_FAILED(rv)) + { + // INVOKE message wasn't delivered; clean up wrappers + dConnect->ReleaseWrappers(wrappers, mPeerID); + return rv; + } + + // now, we wait for the method call to complete. during that time, it's + // possible that we'll receive other method call requests. we'll process + // those while waiting for out method call to complete. it's critical that + // we do so since those other method calls might need to complete before + // out method call can complete! + + DConnectInvokeCompletion completion(mPeerID, &invoke); + + do + { + rv = IPC_WaitMessage(IPC_SENDER_ANY, kDConnectTargetID, + &completion.GetSelector(), &completion, + DCON_WAIT_TIMEOUT); + LOG(("DConnectStub::CallMethod: IPC_WaitMessage()=%08X\n", rv)); + if (NS_FAILED(rv)) + { + // INVOKE message wasn't received; clean up wrappers + dConnect->ReleaseWrappers(wrappers, mPeerID); + return rv; + } + } + while (completion.IsPending()); + + ipcMessageReader reader(completion.Params(), completion.ParamsLen()); + + rv = completion.GetResult(); + if (NS_SUCCEEDED(rv)) + { + PRUint8 i; + + // handle out-params and retvals: DCON_OP_INVOKE_REPLY has the data + for (i=0; iGetParam(i); + + if (paramInfo.IsOut() || paramInfo.IsRetval()) + DeserializeResult(reader, paramInfo.GetType(), aParams[i]); + } + + // fixup any interface pointers using a second pass so we can properly + // handle INTERFACE_IS referencing an IID that is an out param! This pass is + // also used to deserialize arrays (array data goes after all other params). + for (i=0; iGetParam(i); + if ((paramInfo.IsOut() || paramInfo.IsRetval()) && aParams[i].val.p) + { + const nsXPTType &type = paramInfo.GetType(); + if (type.IsInterfacePointer()) + { + // grab the DConAddr value temporarily stored in the param, restore + // the pointer and free the temporarily allocated memory. + DConAddrPlusPtr *dptr = (DConAddrPlusPtr *)aParams[i].val.p; + PtrBits bits = dptr->addr; + aParams[i].val.p = dptr->p; + nsMemory::Free((void *)dptr); + + // DeserializeInterfaceParamBits needs IID only if it's a remote object + nsID iid; + if (bits & PTRBITS_REMOTE_BIT) + rv = dConnect->GetIIDForMethodParam(mIInfo, aInfo, paramInfo, type, + aMethodIndex, aParams, PR_FALSE, + iid); + if (NS_SUCCEEDED(rv)) + { + nsISupports *obj = nsnull; + rv = dConnect->DeserializeInterfaceParamBits(bits, mPeerID, iid, obj); + if (NS_SUCCEEDED(rv)) + *(void **)aParams[i].val.p = obj; + } + } + else if (type.IsArray()) + { + void *array = nsnull; + rv = DeserializeArrayParam(dConnect, reader, mPeerID, mIInfo, + aMethodIndex, *aInfo, aParams, PR_FALSE, + paramInfo, PR_TRUE, array); + if (NS_SUCCEEDED(rv)) + *(void **)aParams[i].val.p = array; + } + } + } + } + + if (completion.Reply()->flags & DCON_OP_FLAGS_REPLY_EXCEPTION) + { + LOG(("got nsIException instance, will create a stub\n")); + + nsIException *xcpt = nsnull; + rv = dConnect->DeserializeException (reader, mPeerID, &xcpt); + if (NS_SUCCEEDED(rv)) + { + rv = em->SetCurrentException(xcpt); + NS_IF_RELEASE(xcpt); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception"); + } + + return NS_SUCCEEDED(rv) ? completion.GetResult() : rv; +} + +//----------------------------------------------------------------------------- + +class DConnectSetupCompletion : public DConnectCompletion +{ +public: + DConnectSetupCompletion(PRUint32 peer, const DConnectSetup *setup) + : DConnectCompletion(peer, DCON_OP_SETUP_REPLY, setup->request_index) + , mSetup(setup) + , mStatus(NS_OK) + {} + + void OnResponseAvailable(PRUint32 sender, const DConnectOp *op, PRUint32 opLen) + { + if (op->opcode_major != DCON_OP_SETUP_REPLY) + { + NS_NOTREACHED("unexpected response"); + mStatus = NS_ERROR_UNEXPECTED; + return; + } + + if (opLen < sizeof(DConnectSetupReply)) + { + NS_NOTREACHED("unexpected response size"); + mStatus = NS_ERROR_UNEXPECTED; + return; + } + + const DConnectSetupReply *reply = (const DConnectSetupReply *) op; + + LOG(("got SETUP_REPLY: status=%x instance=0x%Lx\n", reply->status, reply->instance)); + + mStatus = reply->status; + + if (NS_SUCCEEDED(reply->status)) + { + // ensure ipcDConnectService is not deleted before we finish + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + nsresult rv; + if (dConnect) + rv = dConnect->CreateStub(mSetup->iid, sender, reply->instance, + getter_AddRefs(mStub)); + else + rv = NS_ERROR_FAILURE; + if (NS_FAILED(rv)) + mStatus = rv; + } + + if (reply->flags & DCON_OP_FLAGS_REPLY_EXCEPTION) + { + const PRUint8 *params = ((const PRUint8 *) op) + sizeof (DConnectSetupReply); + const PRUint32 paramsLen = opLen - sizeof (DConnectSetupReply); + + ipcMessageReader reader(params, paramsLen); + + LOG(("got nsIException instance, will create a stub\n")); + + nsresult rv; + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr em; + rv = es->GetCurrentExceptionManager (getter_AddRefs(em)); + if (NS_SUCCEEDED(rv)) + { + // ensure ipcDConnectService is not deleted before we finish + nsRefPtr dConnect (ipcDConnectService::GetInstance()); + if (dConnect) + { + nsIException *xcpt = nsnull; + rv = dConnect->DeserializeException (reader, sender, &xcpt); + if (NS_SUCCEEDED(rv)) + { + rv = em->SetCurrentException(xcpt); + NS_IF_RELEASE(xcpt); + } + } + else + rv = NS_ERROR_UNEXPECTED; + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to deserialize/set exception"); + if (NS_FAILED(rv)) + mStatus = rv; + } + } + + nsresult GetStub(void **aInstancePtr) + { + if (NS_FAILED(mStatus)) + return mStatus; + + DConnectStub *stub = mStub; + NS_IF_ADDREF(stub); + *aInstancePtr = stub; + return NS_OK; + } + +private: + const DConnectSetup *mSetup; + nsresult mStatus; + nsRefPtr mStub; +}; + +// static +nsresult +SetupPeerInstance(PRUint32 aPeerID, DConnectSetup *aMsg, PRUint32 aMsgLen, + void **aInstancePtr) +{ + *aInstancePtr = nsnull; + + aMsg->opcode_major = DCON_OP_SETUP; + aMsg->flags = 0; + aMsg->request_index = NewRequestIndex(); + + // temporarily disable the DConnect target observer to block normal processing + // of pending messages through the event queue. + IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kDConnectTargetID); + + // send SETUP message, expect SETUP_REPLY + + nsresult rv = IPC_SendMessage(aPeerID, kDConnectTargetID, + (const PRUint8 *) aMsg, aMsgLen); + if (NS_FAILED(rv)) + return rv; + + DConnectSetupCompletion completion(aPeerID, aMsg); + + // need to allow messages from other clients to be processed immediately + // to avoid distributed dead locks. the completion's OnMessageAvailable + // will call our default OnMessageAvailable if it receives any message + // other than the one for which it is waiting. + + do + { + rv = IPC_WaitMessage(IPC_SENDER_ANY, kDConnectTargetID, + &completion.GetSelector(), &completion, + DCON_WAIT_TIMEOUT); + if (NS_FAILED(rv)) + break; + + rv = completion.GetStub(aInstancePtr); + } + while (NS_SUCCEEDED(rv) && *aInstancePtr == nsnull); + + return rv; +} + +//----------------------------------------------------------------------------- + +#if defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL) + +class DConnectWorker : public nsIRunnable +{ +public: + // no reference counting + NS_IMETHOD_(nsrefcnt) AddRef() { return 1; } + NS_IMETHOD_(nsrefcnt) Release() { return 1; } + NS_IMETHOD QueryInterface(const nsIID &aIID, void **aInstancePtr); + + NS_DECL_NSIRUNNABLE + + DConnectWorker(ipcDConnectService *aDConnect) : mDConnect (aDConnect), mIsRunnable (PR_FALSE) {} + NS_HIDDEN_(nsresult) Init(); + NS_HIDDEN_(void) Join() { mThread->Join(); }; + NS_HIDDEN_(bool) IsRunning() { return mIsRunnable; }; + +private: + nsCOMPtr mThread; + ipcDConnectService *mDConnect; + + // Indicate if thread might be quickly joined on shutdown. + volatile bool mIsRunnable; +}; + +NS_IMPL_QUERY_INTERFACE1(DConnectWorker, nsIRunnable) + +nsresult +DConnectWorker::Init() +{ + return NS_NewThread(getter_AddRefs(mThread), this, 0, PR_JOINABLE_THREAD); +} + +NS_IMETHODIMP +DConnectWorker::Run() +{ + LOG(("DConnect Worker thread started.\n")); + + mIsRunnable = PR_TRUE; + + nsAutoMonitor mon(mDConnect->mPendingMon); + + while (!mDConnect->mDisconnected) + { + DConnectRequest *request = mDConnect->mPendingQ.First(); + if (!request) + { + mDConnect->mWaitingWorkers++; + { + // Note: we attempt to enter mWaitingWorkersMon from under mPendingMon + // here, but it should be safe because it's the only place where it + // happens. We could exit mPendingMon first, but we need to wait on it + // shorltly afterwards, which in turn will require us to enter it again + // just to exit immediately and start waiting. This seems to me a bit + // stupid (exit->enter->exit->wait). + nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon); + workersMon.NotifyAll(); + } + + nsresult rv = mon.Wait(); + mDConnect->mWaitingWorkers--; + + if (NS_FAILED(rv)) + break; + } + else + { + LOG(("DConnect Worker thread got request.\n")); + + // remove the request from the queue + mDConnect->mPendingQ.RemoveFirst(); + + PRBool pendingQEmpty = mDConnect->mPendingQ.IsEmpty(); + mon.Exit(); + + if (pendingQEmpty) + { + nsAutoMonitor workersMon(mDConnect->mWaitingWorkersMon); + workersMon.NotifyAll(); + } + + // request is processed outside the queue monitor + mDConnect->OnIncomingRequest(request->peer, request->op, request->opLen); + delete request; + + mon.Enter(); + } + } + + mIsRunnable = PR_FALSE; + + LOG(("DConnect Worker thread stopped.\n")); + return NS_OK; +} + +// called only on DConnect message thread +nsresult +ipcDConnectService::CreateWorker() +{ + DConnectWorker *worker = new DConnectWorker(this); + if (!worker) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = worker->Init(); + if (NS_SUCCEEDED(rv)) + { + nsAutoLock lock(mLock); + /* tracking an illegal join in Shutdown. */ + NS_ASSERTION(!mDisconnected, "CreateWorker racing Shutdown"); + if (!mWorkers.AppendElement(worker)) + rv = NS_ERROR_OUT_OF_MEMORY; + } + if (NS_FAILED(rv)) + delete worker; + return rv; +} + +#endif // defined(DCONNECT_MULTITHREADED) && !defined(DCONNECT_WITH_IPRT_REQ_POOL) + +//----------------------------------------------------------------------------- + +ipcDConnectService::ipcDConnectService() + : mLock(NULL) + , mStubLock(NULL) + , mDisconnected(PR_TRUE) + , mStubQILock(NULL) +#if defined(DCONNECT_WITH_IPRT_REQ_POOL) + , mhReqPool(NIL_RTREQPOOL) +#endif +{ +} + +PR_STATIC_CALLBACK(PLDHashOperator) +EnumerateInstanceMapAndDelete (const DConnectInstanceKey::Key &aKey, + DConnectInstance *aData, + void *userArg) +{ + // this method is to be called on ipcDConnectService shutdown only + // (after which no DConnectInstances may exist), so forcibly delete them + // disregarding the reference counter + +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + aData->InterfaceInfo()->GetNameShared(&name); + LOG(("ipcDConnectService: WARNING: deleting unreleased " + "instance=%p iface=%p {%s}\n", aData, aData->RealInstance(), name)); + } +#endif + + delete aData; + return PL_DHASH_NEXT; +} + +ipcDConnectService::~ipcDConnectService() +{ + if (!mDisconnected) + Shutdown(); + + mInstance = nsnull; + PR_DestroyLock(mStubQILock); + PR_DestroyLock(mStubLock); + PR_DestroyLock(mLock); +#if defined(DCONNECT_WITH_IPRT_REQ_POOL) + RTReqPoolRelease(mhReqPool); + mhReqPool = NIL_RTREQPOOL; +#endif +} + +//----------------------------------------------------------------------------- + +nsresult +ipcDConnectService::Init() +{ + nsresult rv; + + LOG(("ipcDConnectService::Init.\n")); + + rv = IPC_DefineTarget(kDConnectTargetID, this); + if (NS_FAILED(rv)) + return rv; + + rv = IPC_AddClientObserver(this); + if (NS_FAILED(rv)) + return rv; + + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mInstances.Init()) + return NS_ERROR_OUT_OF_MEMORY; + if (!mInstanceSet.Init()) + return NS_ERROR_OUT_OF_MEMORY; + + mStubLock = PR_NewLock(); + if (!mStubLock) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mStubs.Init()) + return NS_ERROR_OUT_OF_MEMORY; + + mIIM = do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + mStubQILock = PR_NewLock(); + if (!mStubQILock) + return NS_ERROR_OUT_OF_MEMORY; + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + int vrc = RTReqPoolCreate(1024 /*cMaxThreads*/, 10*RT_MS_1SEC /*cMsMinIdle*/, + 8 /*cThreadsPushBackThreshold */, RT_MS_1SEC /* cMsMaxPushBack */, + "DCon", &mhReqPool); + if (RT_FAILURE(vrc)) + { + mhReqPool = NIL_RTREQPOOL; + return NS_ERROR_FAILURE; + } + + mDisconnected = PR_FALSE; + +# else + + mPendingMon = nsAutoMonitor::NewMonitor("DConnect pendingQ monitor"); + if (!mPendingMon) + return NS_ERROR_OUT_OF_MEMORY; + + mWaitingWorkers = 0; + + mWaitingWorkersMon = nsAutoMonitor::NewMonitor("DConnect waiting workers monitor"); + if (!mWaitingWorkersMon) + return NS_ERROR_OUT_OF_MEMORY; + + /* The DConnectWorker::Run method checks the ipcDConnectService::mDisconnected. + * So mDisconnect must be set here to avoid an immediate exit of the worker thread. + */ + mDisconnected = PR_FALSE; + + // create a single worker thread + rv = CreateWorker(); + if (NS_FAILED(rv)) + { + mDisconnected = PR_TRUE; + return rv; + } + +# endif +#else + + mDisconnected = PR_FALSE; + +#endif + + mInstance = this; + + LOG(("ipcDConnectService::Init NS_OK.\n")); + return NS_OK; +} + +void +ipcDConnectService::Shutdown() +{ + { + // set the disconnected flag to make sensitive public methods + // unavailale from other (non worker) threads. + nsAutoLock lock(mLock); + mDisconnected = PR_TRUE; + } + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + +# if defined(DCONNECT_STATS) + fprintf(stderr, "ipcDConnectService Stats\n"); + fprintf(stderr, + " => number of worker threads: %llu (created %llu)\n" + " => requests processed: %llu\n" + " => avg requests process time: %llu ns\n" + " => avg requests waiting time: %llu ns\n", + RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_THREADS), + RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_THREADS_CREATED), + RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_REQUESTS_PROCESSED), + RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_NS_AVERAGE_REQ_PROCESSING), + RTReqPoolGetStat(mhReqPool, RTREQPOOLSTAT_NS_AVERAGE_REQ_QUEUED) + ); +# endif + + RTReqPoolRelease(mhReqPool); + mhReqPool = NIL_RTREQPOOL; + +# else + + { + // remove all pending messages and wake up all workers. + // mDisconnected is true here and they will terminate execution after + // processing the last request. + nsAutoMonitor mon(mPendingMon); + mPendingQ.DeleteAll(); + mon.NotifyAll(); + } + +#if defined(DCONNECT_STATS) + fprintf(stderr, "ipcDConnectService Stats\n"); + fprintf(stderr, " => number of worker threads: %d\n", mWorkers.Count()); + LOG(("ipcDConnectService Stats\n")); + LOG((" => number of worker threads: %d\n", mWorkers.Count())); +#endif + + + // Iterate over currently running worker threads + // during VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS, join() those who + // exited a working loop and abandon ones which have not + // managed to do that when timeout occurred. + LOG(("Worker threads: %d\n", mWorkers.Count())); + uint64_t tsStart = RTTimeMilliTS(); + while ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) > RTTimeMilliTS() && mWorkers.Count() > 0) + { + // Some array elements might be deleted while iterating. Going from the last + // to the first array element (intentionally) in order to do not conflict with + // array indexing once element is deleted. + for (int i = mWorkers.Count() - 1; i >= 0; i--) + { + DConnectWorker *worker = NS_STATIC_CAST(DConnectWorker *, mWorkers[i]); + if (worker->IsRunning() == PR_FALSE) + { + LOG(("Worker %p joined.\n", worker)); + worker->Join(); + delete worker; + mWorkers.RemoveElementAt(i); + } + } + + /* Double-ckeck if we already allowed to quit. */ + if ((tsStart + VBOX_XPCOM_SHUTDOWN_TIMEOUT_MS ) < RTTimeMilliTS() || mWorkers.Count() == 0) + break; + + // Relax a bit before the next round. + RTThreadSleep(10); + } + + LOG(("There are %d thread(s) left.\n", mWorkers.Count())); + + // If there are some running threads left, terminate the process. + if (mWorkers.Count() > 0) + exit(1); + + + nsAutoMonitor::DestroyMonitor(mWaitingWorkersMon); + nsAutoMonitor::DestroyMonitor(mPendingMon); + +# endif +#endif + + // make sure we have released all instances + mInstances.EnumerateRead(EnumerateInstanceMapAndDelete, nsnull); + + mInstanceSet.Clear(); + mInstances.Clear(); + + // clear the stub table + // (this will not release stubs -- it's the client's responsibility) + mStubs.Clear(); +} + +// this should be inlined +nsresult +ipcDConnectService::GetInterfaceInfo(const nsID &iid, nsIInterfaceInfo **result) +{ + return mIIM->GetInfoForIID(&iid, result); +} + +// this is adapted from the version in xpcwrappednative.cpp +nsresult +ipcDConnectService::GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const nsXPTMethodInfo *methodInfo, + const nsXPTParamInfo ¶mInfo, + const nsXPTType &type, + PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isXPTCVariantArray, + nsID &result) +{ + PRUint8 argnum, tag = type.TagPart(); + nsresult rv; + + if (tag == nsXPTType::T_INTERFACE) + { + rv = iinfo->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, &result); + } + else if (tag == nsXPTType::T_INTERFACE_IS) + { + rv = iinfo->GetInterfaceIsArgNumberForParam(methodIndex, ¶mInfo, &argnum); + if (NS_FAILED(rv)) + return rv; + + const nsXPTParamInfo& arg_param = methodInfo->GetParam(argnum); + const nsXPTType& arg_type = arg_param.GetType(); + + // The xpidl compiler ensures this. We reaffirm it for safety. + if (!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID) + return NS_ERROR_UNEXPECTED; + + nsID *p = (nsID *) GET_PARAM(dispatchParams, isXPTCVariantArray, argnum).val.p; + if (!p) + return NS_ERROR_UNEXPECTED; + + result = *p; + } + else + rv = NS_ERROR_UNEXPECTED; + return rv; +} + +nsresult +ipcDConnectService::StoreInstance(DConnectInstance *wrapper) +{ +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + wrapper->InterfaceInfo()->GetNameShared(&name); + LOG(("ipcDConnectService::StoreInstance(): instance=%p iface=%p {%s}\n", + wrapper, wrapper->RealInstance(), name)); + } +#endif + + nsresult rv = mInstanceSet.Put(wrapper); + if (NS_SUCCEEDED(rv)) + { + rv = mInstances.Put(wrapper->GetKey(), wrapper) + ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + if (NS_FAILED(rv)) + mInstanceSet.Remove(wrapper); + } + return rv; +} + +void +ipcDConnectService::DeleteInstance(DConnectInstance *wrapper, + PRBool locked /* = PR_FALSE */) +{ + if (!locked) + PR_Lock(mLock); + +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + wrapper->InterfaceInfo()->GetNameShared(&name); + LOG(("ipcDConnectService::DeleteInstance(): instance=%p iface=%p {%s}\n", + wrapper, wrapper->RealInstance(), name)); + } +#endif + + mInstances.Remove(wrapper->GetKey()); + mInstanceSet.Remove(wrapper); + + if (!locked) + PR_Unlock(mLock); +} + +PRBool +ipcDConnectService::FindInstanceAndAddRef(PRUint32 peer, + const nsISupports *obj, + const nsIID *iid, + DConnectInstance **wrapper) +{ + PRBool result = mInstances.Get(DConnectInstanceKey::Key(peer, obj, iid), wrapper); + if (result) + (*wrapper)->AddRef(); + return result; +} + +PRBool +ipcDConnectService::CheckInstanceAndAddRef(DConnectInstance *wrapper, PRUint32 peer) +{ + nsAutoLock lock (mLock); + + if (mInstanceSet.Contains(wrapper) && wrapper->Peer() == peer) + { + wrapper->AddRef(); + return PR_TRUE; + } + return PR_FALSE; +} + +nsresult +ipcDConnectService::StoreStub(DConnectStub *stub) +{ +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + nsCOMPtr iinfo; + stub->GetInterfaceInfo(getter_AddRefs(iinfo)); + iinfo->GetNameShared(&name); + LOG(("ipcDConnectService::StoreStub(): stub=%p instance=0x%Lx {%s}\n", + stub, stub->Instance(), name)); + } +#endif + + return mStubs.Put(stub->GetKey(), stub) + ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +void +ipcDConnectService::DeleteStub(DConnectStub *stub) +{ +#ifdef IPC_LOGGING + if (IPC_LOG_ENABLED()) + { + const char *name; + nsCOMPtr iinfo; + stub->GetInterfaceInfo(getter_AddRefs(iinfo)); + iinfo->GetNameShared(&name); + LOG(("ipcDConnectService::DeleteStub(): stub=%p instance=0x%Lx {%s}\n", + stub, stub->Instance(), name)); + } +#endif + + // this method is intended to be called only from DConnectStub::Release(). + // the stub object is not deleted when removed from the table, because + // DConnectStub pointers are not owned by mStubs. + mStubs.Remove(stub->GetKey()); +} + +// not currently used +#if 0 +PRBool +ipcDConnectService::FindStubAndAddRef(PRUint32 peer, const DConAddr instance, + DConnectStub **stub) +{ + nsAutoLock stubLock (mStubLock); + + PRBool result = mStubs.Get(DConnectStubKey::Key(peer, instance), stub); + if (result) + NS_ADDREF(*stub); + return result; +} +#endif + +NS_IMPL_THREADSAFE_ISUPPORTS3(ipcDConnectService, ipcIDConnectService, + ipcIMessageObserver, + ipcIClientObserver) + +NS_IMETHODIMP +ipcDConnectService::CreateInstance(PRUint32 aPeerID, + const nsID &aCID, + const nsID &aIID, + void **aInstancePtr) +{ + DConnectSetupClassID msg; + msg.opcode_minor = DCON_OP_SETUP_NEW_INST_CLASSID; + msg.iid = aIID; + msg.classid = aCID; + + return SetupPeerInstance(aPeerID, &msg, sizeof(msg), aInstancePtr); +} + +NS_IMETHODIMP +ipcDConnectService::CreateInstanceByContractID(PRUint32 aPeerID, + const char *aContractID, + const nsID &aIID, + void **aInstancePtr) +{ + size_t slen = strlen(aContractID); + size_t size = sizeof(DConnectSetupContractID) + slen; + + DConnectSetupContractID *msg = + (DConnectSetupContractID *) malloc(size); + + msg->opcode_minor = DCON_OP_SETUP_NEW_INST_CONTRACTID; + msg->iid = aIID; + memcpy(&msg->contractid, aContractID, slen + 1); + + nsresult rv = SetupPeerInstance(aPeerID, msg, size, aInstancePtr); + + free(msg); + return rv; +} + +NS_IMETHODIMP +ipcDConnectService::GetService(PRUint32 aPeerID, + const nsID &aCID, + const nsID &aIID, + void **aInstancePtr) +{ + DConnectSetupClassID msg; + msg.opcode_minor = DCON_OP_SETUP_GET_SERV_CLASSID; + msg.iid = aIID; + msg.classid = aCID; + + return SetupPeerInstance(aPeerID, &msg, sizeof(msg), aInstancePtr); +} + +NS_IMETHODIMP +ipcDConnectService::GetServiceByContractID(PRUint32 aPeerID, + const char *aContractID, + const nsID &aIID, + void **aInstancePtr) +{ + size_t slen = strlen(aContractID); + size_t size = sizeof(DConnectSetupContractID) + slen; + + DConnectSetupContractID *msg = + (DConnectSetupContractID *) malloc(size); + + msg->opcode_minor = DCON_OP_SETUP_GET_SERV_CONTRACTID; + msg->iid = aIID; + memcpy(&msg->contractid, aContractID, slen + 1); + + nsresult rv = SetupPeerInstance(aPeerID, msg, size, aInstancePtr); + + free(msg); + return rv; +} + +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ipcDConnectService::OnMessageAvailable(PRUint32 aSenderID, + const nsID &aTarget, + const PRUint8 *aData, + PRUint32 aDataLen) +{ + if (mDisconnected) + return NS_ERROR_NOT_INITIALIZED; + + const DConnectOp *op = (const DConnectOp *) aData; + + LOG (("ipcDConnectService::OnMessageAvailable: " + "senderID=%d, opcode_major=%d, index=%d\n", + aSenderID, op->opcode_major, op->request_index)); + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + + void *pvDataDup = RTMemDup(aData, aDataLen); + if (RT_UNLIKELY(!pvDataDup)) + return NS_ERROR_OUT_OF_MEMORY; + int rc = RTReqPoolCallVoidNoWait(mhReqPool, (PFNRT)ProcessMessageOnWorkerThread, 4, + this, aSenderID, pvDataDup, aDataLen); + if (RT_FAILURE(rc)) + return NS_ERROR_FAILURE; + +# else + + nsAutoMonitor mon(mPendingMon); + mPendingQ.Append(new DConnectRequest(aSenderID, op, aDataLen)); + // notify a worker + mon.Notify(); + mon.Exit(); + + // Yield the cpu so a worker can get a chance to start working without too much fuss. + PR_Sleep(PR_INTERVAL_NO_WAIT); + mon.Enter(); + // examine the queue + if (mPendingQ.Count() > mWaitingWorkers) + { + // wait a little while to let the workers empty the queue. + mon.Exit(); + { + PRUint32 ticks = PR_MillisecondsToInterval(PR_MIN(mWorkers.Count() / 20 + 1, 10)); + nsAutoMonitor workersMon(mWaitingWorkersMon); + workersMon.Wait(ticks); + } + mon.Enter(); + // examine the queue again + if (mPendingQ.Count() > mWaitingWorkers) + { + // we need one more worker + nsresult rv = CreateWorker(); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create one more worker thread"); + rv = rv; + } + } + +# endif +#else + + OnIncomingRequest(aSenderID, op, aDataLen); + +#endif + + return NS_OK; +} + +struct PruneInstanceMapForPeerArgs +{ + ipcDConnectService *that; + PRUint32 clientID; + nsVoidArray &wrappers; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +PruneInstanceMapForPeer (const DConnectInstanceKey::Key &aKey, + DConnectInstance *aData, + void *userArg) +{ + PruneInstanceMapForPeerArgs *args = (PruneInstanceMapForPeerArgs *)userArg; + NS_ASSERTION(args, "PruneInstanceMapForPeerArgs is NULL"); + + if (args && args->clientID == aData->Peer()) + { + nsrefcnt countIPC = aData->ReleaseIPC(PR_TRUE /* locked */); + + LOG(("ipcDConnectService::PruneInstanceMapForPeer: " + "instance=%p: %d IPC refs to release\n", + aData, countIPC + 1)); + + // release all IPC instances of the "officially dead" client (see + // #OnRelease() to understand why it must be done under the lock). Note + // that due to true multithreading, late OnRelease() requests may still + // happen on other worker threads *after* OnClientStateChange() has been + // called, but it's OK because the instance will be removed from the map + // by the below code alreay and won't be deleted for the second time. + while (countIPC) + { + countIPC = aData->ReleaseIPC(PR_TRUE /* locked */); + aData->Release(); + } + + // collect the instance for the last release + // (we'll do it later outside the lock) + if (!args->wrappers.AppendElement(aData)) + { + NS_NOTREACHED("Not enough memory"); + // bad but what to do + aData->Release(); + } + } + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +ipcDConnectService::OnClientStateChange(PRUint32 aClientID, + PRUint32 aClientState) +{ + LOG(("ipcDConnectService::OnClientStateChange: aClientID=%d, aClientState=%d\n", + aClientID, aClientState)); + + if (aClientState == ipcIClientObserver::CLIENT_DOWN) + { + if (aClientID == IPC_SENDER_ANY) + { + // a special case: our IPC system is being shutdown, try to safely + // uninitialize everything... + Shutdown(); + } + else + { + LOG(("ipcDConnectService::OnClientStateChange: " + "pruning all instances created for peer %d...\n", aClientID)); + + nsVoidArray wrappers; + + { + nsAutoLock lock (mLock); + + // make sure we have removed all instances from instance maps + PruneInstanceMapForPeerArgs args = { this, aClientID, wrappers }; + mInstances.EnumerateRead(PruneInstanceMapForPeer, (void *)&args); + } + + LOG(("ipcDConnectService::OnClientStateChange: " + "%d lost instances\n", wrappers.Count())); + + // release all pending references left after PruneInstanceMapForPeer(). + // this may call wrapper destructors so it's important to do that + // outside the lock because destructors will release the real objects + // which may need to make asynchronous use our service + for (PRInt32 i = 0; i < wrappers.Count(); ++i) + ((DConnectInstance *) wrappers[i])->Release(); + } + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- + +#if defined(DCONNECT_WITH_IPRT_REQ_POOL) +/** + * Function called by the request thread pool to process a incoming request in + * the context of a worker thread. + */ +/* static */ DECLCALLBACK(void) +ipcDConnectService::ProcessMessageOnWorkerThread(ipcDConnectService *aThis, PRUint32 aSenderID, void *aData, PRUint32 aDataLen) +{ + if (!aThis->mDisconnected) + aThis->OnIncomingRequest(aSenderID, (const DConnectOp *)aData, aDataLen); + RTMemFree(aData); +} +#endif + +void +ipcDConnectService::OnIncomingRequest(PRUint32 peer, const DConnectOp *op, PRUint32 opLen) +{ + switch (op->opcode_major) + { + case DCON_OP_SETUP: + OnSetup(peer, (const DConnectSetup *) op, opLen); + break; + case DCON_OP_RELEASE: + OnRelease(peer, (const DConnectRelease *) op); + break; + case DCON_OP_INVOKE: + OnInvoke(peer, (const DConnectInvoke *) op, opLen); + break; + default: + NS_NOTREACHED("unknown opcode major"); + } +} + +void +ipcDConnectService::OnSetup(PRUint32 peer, const DConnectSetup *setup, PRUint32 opLen) +{ + nsISupports *instance = nsnull; + nsresult rv = NS_ERROR_FAILURE; + + switch (setup->opcode_minor) + { + // CreateInstance + case DCON_OP_SETUP_NEW_INST_CLASSID: + { + const DConnectSetupClassID *setupCI = (const DConnectSetupClassID *) setup; + + nsCOMPtr compMgr; + rv = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (NS_SUCCEEDED(rv)) + rv = compMgr->CreateInstance(setupCI->classid, nsnull, setupCI->iid, (void **) &instance); + + break; + } + + // CreateInstanceByContractID + case DCON_OP_SETUP_NEW_INST_CONTRACTID: + { + const DConnectSetupContractID *setupCI = (const DConnectSetupContractID *) setup; + + nsCOMPtr compMgr; + rv = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (NS_SUCCEEDED(rv)) + rv = compMgr->CreateInstanceByContractID(setupCI->contractid, nsnull, setupCI->iid, (void **) &instance); + + break; + } + + // GetService + case DCON_OP_SETUP_GET_SERV_CLASSID: + { + const DConnectSetupClassID *setupCI = (const DConnectSetupClassID *) setup; + + nsCOMPtr svcMgr; + rv = NS_GetServiceManager(getter_AddRefs(svcMgr)); + if (NS_SUCCEEDED(rv)) + rv = svcMgr->GetService(setupCI->classid, setupCI->iid, (void **) &instance); + break; + } + + // GetServiceByContractID + case DCON_OP_SETUP_GET_SERV_CONTRACTID: + { + const DConnectSetupContractID *setupCI = (const DConnectSetupContractID *) setup; + + nsCOMPtr svcMgr; + rv = NS_GetServiceManager(getter_AddRefs(svcMgr)); + if (NS_SUCCEEDED(rv)) + rv = svcMgr->GetServiceByContractID(setupCI->contractid, setupCI->iid, (void **) &instance); + + break; + } + + // QueryInterface + case DCON_OP_SETUP_QUERY_INTERFACE: + { + const DConnectSetupQueryInterface *setupQI = (const DConnectSetupQueryInterface *) setup; + DConnectInstance *QIinstance = (DConnectInstance *)setupQI->instance; + + // make sure we've been sent a valid wrapper + if (!CheckInstanceAndAddRef(QIinstance, peer)) + { + NS_NOTREACHED("instance wrapper not found"); + rv = NS_ERROR_INVALID_ARG; + } + else + { + rv = QIinstance->RealInstance()->QueryInterface(setupQI->iid, (void **) &instance); + QIinstance->Release(); + } + break; + } + + default: + NS_NOTREACHED("unexpected minor opcode"); + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsVoidArray wrappers; + + // now, create instance wrapper, and store it in our instances set. + // this allows us to keep track of object references held on behalf of a + // particular peer. we can use this information to cleanup after a peer + // that disconnects without sending RELEASE messages for its objects. + DConnectInstance *wrapper = nsnull; + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr iinfo; + rv = GetInterfaceInfo(setup->iid, getter_AddRefs(iinfo)); + if (NS_SUCCEEDED(rv)) + { + nsAutoLock lock (mLock); + + // first try to find an existing wrapper for the given object + if (!FindInstanceAndAddRef(peer, instance, &setup->iid, &wrapper)) + { + wrapper = new DConnectInstance(peer, iinfo, instance); + if (!wrapper) + rv = NS_ERROR_OUT_OF_MEMORY; + else + { + rv = StoreInstance(wrapper); + if (NS_FAILED(rv)) + { + delete wrapper; + wrapper = nsnull; + } + else + { + // reference the newly created wrapper + wrapper->AddRef(); + } + } + } + + if (wrapper) + { + // increase the second, IPC-only, reference counter (mandatory before + // trying wrappers.AppendElement() to make sure ReleaseIPC() will remove + // the wrapper from the instance map on failure) + wrapper->AddRefIPC(); + + if (!wrappers.AppendElement(wrapper)) + { + wrapper->ReleaseIPC(); + wrapper->Release(); + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + // wrapper remains referenced when passing it to the client + // (will be released upon DCON_OP_RELEASE) + } + } + + NS_IF_RELEASE(instance); + + nsCOMPtr exception; + PRBool got_exception = PR_FALSE; + + if (rv != NS_OK) + { + // try to fetch an nsIException possibly set by one of the setup methods + nsresult rv2; + nsCOMPtr es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2); + if (NS_SUCCEEDED(rv2)) + { + nsCOMPtr em; + rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED(rv2)) + { + rv2 = em->GetCurrentException (getter_AddRefs (exception)); + if (NS_SUCCEEDED(rv2)) + { + LOG(("got nsIException instance, will serialize\n")); + got_exception = PR_TRUE; + } + } + } + NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception"); + if (NS_FAILED(rv2)) + rv = rv2; + } + + ipcMessageWriter writer(64); + + DConnectSetupReply msg; + msg.opcode_major = DCON_OP_SETUP_REPLY; + msg.opcode_minor = 0; + msg.flags = 0; + msg.request_index = setup->request_index; + msg.instance = (DConAddr)(uintptr_t)wrapper; + msg.status = rv; + + if (got_exception) + msg.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION; + + writer.PutBytes(&msg, sizeof(msg)); + + if (got_exception) + { + rv = SerializeException(writer, peer, exception, wrappers); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception"); + } + + // fire off SETUP_REPLY, don't wait for a response + if (NS_FAILED(rv)) + rv = IPC_SendMessage(peer, kDConnectTargetID, + (const PRUint8 *) &msg, sizeof(msg)); + else + rv = IPC_SendMessage(peer, kDConnectTargetID, + writer.GetBuffer(), writer.GetSize()); + + if (NS_FAILED(rv)) + { + LOG(("unable to send SETUP_REPLY: rv=%x\n", rv)); + ReleaseWrappers(wrappers, peer); + } +} + +void +ipcDConnectService::OnRelease(PRUint32 peer, const DConnectRelease *release) +{ + LOG(("ipcDConnectService::OnRelease [peer=%u instance=0x%Lx]\n", + peer, release->instance)); + + DConnectInstance *wrapper = (DConnectInstance *)release->instance; + + nsAutoLock lock (mLock); + + // make sure we've been sent a valid wrapper from the same peer we created + // this wrapper for + if (mInstanceSet.Contains(wrapper) && wrapper->Peer() == peer) + { + // release the IPC reference from under the lock to ensure atomicity of + // the "check + possible delete" sequence ("delete" is remove this wrapper + // from the instance map when the IPC reference counter drops to zero) + wrapper->ReleaseIPC(PR_TRUE /* locked */); + // leave the lock before Release() because it may call the destructor + // which will release the real object which may need to make asynchronous + // use our service + lock.unlock(); + wrapper->Release(); + } + else + { + // it is possible that the client disconnection event handler has released + // all client instances before the DCON_OP_RELEASE message sent by the + // client gets processed here (because of true multithreading). Just log + // a debug warning + LOG(("ipcDConnectService::OnRelease: WARNING: " + "instance wrapper %p for peer %d not found", wrapper, peer)); + } +} + +void +ipcDConnectService::OnInvoke(PRUint32 peer, const DConnectInvoke *invoke, PRUint32 opLen) +{ + LOG(("ipcDConnectService::OnInvoke [peer=%u instance=0x%Lx method=%u]\n", + peer, invoke->instance, invoke->method_index)); + + DConnectInstance *wrapper = (DConnectInstance *)invoke->instance; + + ipcMessageReader reader((const PRUint8 *) (invoke + 1), opLen - sizeof(*invoke)); + + const nsXPTMethodInfo *methodInfo; + nsXPTCVariant *params = nsnull; + nsCOMPtr iinfo = nsnull; + PRUint8 i, paramCount = 0, paramUsed = 0; + nsresult rv; + + nsCOMPtr exception; + PRBool got_exception = PR_FALSE; + + // make sure we've been sent a valid wrapper + if (!CheckInstanceAndAddRef(wrapper, peer)) + { + NS_NOTREACHED("instance wrapper not found"); + wrapper = nsnull; + rv = NS_ERROR_INVALID_ARG; + goto end; + } + + iinfo = wrapper->InterfaceInfo(); + + rv = iinfo->GetMethodInfo(invoke->method_index, &methodInfo); + if (NS_FAILED(rv)) + goto end; + + paramCount = methodInfo->GetParamCount(); + + LOG((" iface=%p\n", wrapper->RealInstance())); + LOG((" name=%s\n", methodInfo->GetName())); + LOG((" param-count=%u\n", (PRUint32) paramCount)); + LOG((" request-index=%d\n", (PRUint32) invoke->request_index)); + + params = new nsXPTCVariant[paramCount]; + if (!params) + { + rv = NS_ERROR_OUT_OF_MEMORY; + goto end; + } + + // setup |params| for xptcall + + for (i=0; iGetParam(i); + + // XXX are inout params an issue? + // yes, we will need to do v.ptr = &v.val for them (DeserializeParam doesn't + // currently do that) to let the callee correctly pick it up and change. + + if (paramInfo.IsIn() && !paramInfo.IsDipper()) + rv = DeserializeParam(reader, paramInfo.GetType(), params[i]); + else + rv = SetupParam(paramInfo, params[i]); + + if (NS_FAILED(rv)) + goto end; + } + + // fixup any interface pointers. we do this with a second pass so that + // we can properly handle INTERFACE_IS. This pass is also used to deserialize + // arrays (array data goes after all other params). + for (i=0; iGetParam(i); + if (paramInfo.IsIn()) + { + const nsXPTType &type = paramInfo.GetType(); + if (type.IsInterfacePointer()) + { + // grab the DConAddr value temporarily stored in the param +#ifdef VBOX + PtrBits bits = params[i].val.u64; +#else + PtrBits bits = (PtrBits)(uintptr_t) params[i].val.p; +#endif + + // DeserializeInterfaceParamBits needs IID only if it's a remote object + nsID iid; + if (bits & PTRBITS_REMOTE_BIT) + { + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type, + invoke->method_index, params, PR_TRUE, iid); + if (NS_FAILED(rv)) + goto end; + } + + nsISupports *obj = nsnull; + rv = DeserializeInterfaceParamBits(bits, peer, iid, obj); + if (NS_FAILED(rv)) + goto end; + + params[i].val.p = obj; + // mark as interface to let FinishParam() release this param + params[i].SetValIsInterface(); + } + else if (type.IsArray()) + { + void *array = nsnull; + rv = DeserializeArrayParam(this, reader, peer, iinfo, + invoke->method_index, *methodInfo, params, + PR_TRUE, paramInfo, PR_FALSE, array); + if (NS_FAILED(rv)) + goto end; + + params[i].val.p = array; + // mark to let FinishParam() free this param + params[i].SetValIsAllocated(); + } + } + } + + rv = XPTC_InvokeByIndex(wrapper->RealInstance(), + invoke->method_index, + paramCount, + params); + + if (rv != NS_OK) + { + // try to fetch an nsIException possibly set by the method + nsresult rv2; + nsCOMPtr es; + es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rv2); + if (NS_SUCCEEDED(rv2)) + { + nsCOMPtr em; + rv2 = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED(rv2)) + { + rv2 = em->GetCurrentException (getter_AddRefs (exception)); + if (NS_SUCCEEDED(rv2)) + { + LOG(("got nsIException instance, will serialize\n")); + got_exception = PR_TRUE; + } + } + } + NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get/serialize exception"); + if (NS_FAILED(rv2)) + rv = rv2; + } + +end: + LOG(("sending INVOKE_REPLY: rv=%x\n", rv)); + + // balance CheckInstanceAndAddRef() + if (wrapper) + wrapper->Release(); + + ipcMessageWriter writer(64); + + DConnectInvokeReply reply; + reply.opcode_major = DCON_OP_INVOKE_REPLY; + reply.opcode_minor = 0; + reply.flags = 0; + reply.request_index = invoke->request_index; + reply.result = rv; + + if (got_exception) + reply.flags |= DCON_OP_FLAGS_REPLY_EXCEPTION; + + writer.PutBytes(&reply, sizeof(reply)); + + nsVoidArray wrappers; + + if (NS_SUCCEEDED(rv) && params) + { + // serialize out-params and retvals + for (i=0; iGetParam(i); + + if (paramInfo.IsRetval() || paramInfo.IsOut()) + { + const nsXPTType &type = paramInfo.GetType(); + + if (type.IsInterfacePointer()) + { + nsID iid; + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type, + invoke->method_index, params, PR_TRUE, iid); + if (NS_SUCCEEDED(rv)) + rv = SerializeInterfaceParam(writer, peer, iid, + (nsISupports *) params[i].val.p, wrappers); + } + else + rv = SerializeParam(writer, type, params[i]); + + if (NS_FAILED(rv)) + { + reply.result = rv; + break; + } + } + } + + if (NS_SUCCEEDED(rv)) + { + // serialize output array parameters after everything else since the + // deserialization procedure will need to get a size_is value which may be + // stored in any preceeding or following param + for (i=0; iGetParam(i); + + if (paramInfo.GetType().IsArray() && + (paramInfo.IsRetval() || paramInfo.IsOut())) + { + rv = SerializeArrayParam(this, writer, peer, iinfo, invoke->method_index, + *methodInfo, params, PR_TRUE, paramInfo, + params[i].val.p, wrappers); + if (NS_FAILED(rv)) + { + reply.result = rv; + break; + } + } + } + } + } + + if (got_exception) + { + rv = SerializeException(writer, peer, exception, wrappers); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get/serialize exception"); + } + + if (NS_FAILED(rv)) + rv = IPC_SendMessage(peer, kDConnectTargetID, (const PRUint8 *) &reply, sizeof(reply)); + else + rv = IPC_SendMessage(peer, kDConnectTargetID, writer.GetBuffer(), writer.GetSize()); + if (NS_FAILED(rv)) + { + LOG(("unable to send INVOKE_REPLY: rv=%x\n", rv)); + ReleaseWrappers(wrappers, peer); + } + + if (params) + { + // free individual elements of arrays (note: before freeing arrays + // themselves in FinishParam()) + for (i=0; iGetParam(i); + if (paramInfo.GetType().IsArray()) + FinishArrayParam(iinfo, invoke->method_index, *methodInfo, + params, PR_TRUE, paramInfo, params[i]); + } + + for (i=0; i + * Dmitry A. Kuminov + * + * 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 ***** */ + +// DConnect service is multithreaded by default... +#if !defined(DCONNECT_SINGLETHREADED) && !defined(DCONNECT_MULTITHREADED) +#define DCONNECT_MULTITHREADED +# ifdef VBOX +//# define DCONNECT_WITH_IPRT_REQ_POOL +# endif +#endif + +#include "ipcIDConnectService.h" +#include "ipcdclient.h" + +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nsDataHashtable.h" +#include "nsHashKeys.h" +#include "nsHashSets.h" +#include "nsVoidArray.h" +#include "nsAutoLock.h" +#include "xptcall.h" +#include "xptinfo.h" + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + +# include + +# else /* !DCONNECT_WITH_IPRT_REQ_POOL*/ + +#include "ipcList.h" + +struct DConnectOp; + +struct DConnectRequest : public ipcListNode +{ + DConnectRequest (PRUint32 aPeer, const DConnectOp *aOp, PRUint32 aOpLen) + : peer(aPeer) + , opLen(aOpLen) + { + op = (const DConnectOp *) malloc(aOpLen); + memcpy ((void *) op, aOp, aOpLen); + } + ~DConnectRequest() { free((void *) op); } + + const PRUint32 peer; + const DConnectOp *op; + const PRUint32 opLen; +}; + +# endif // !DCONNECT_WITH_IPRT_REQ_POOL +#endif // DCONNECT_MULTITHREADED + +class nsIException; +class ipcMessageReader; +class ipcMessageWriter; + +// a key class used to identify DConnectInstance objects stored in a hash table +// by a composite of peer ID, XPCOM object pointer and IID this pointer represents + +class DConnectInstanceKey : public PLDHashEntryHdr +{ +public: + struct Key + { + Key(PRUint32 aPeer, const nsISupports *aObj, const nsID *aIID) + : mPeer (aPeer), mObj (aObj), mIID (aIID) {} + const PRUint32 mPeer; + const nsISupports *mObj; + const nsIID *mIID; + }; + + typedef const Key &KeyType; + typedef const Key *KeyTypePointer; + + DConnectInstanceKey(const Key *aKey) : mKey (*aKey) {} + DConnectInstanceKey(const DConnectInstanceKey &toCopy) : mKey (toCopy.mKey) {} + ~DConnectInstanceKey() {} + + KeyType GetKey() const { return mKey; } + KeyTypePointer GetKeyPointer() const { return &mKey; } + + PRBool KeyEquals(KeyTypePointer aKey) const { + return mKey.mPeer == aKey->mPeer && + mKey.mObj == aKey->mObj && + mKey.mIID->Equals(*aKey->mIID); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { + return aKey->mPeer ^ + (NS_PTR_TO_INT32(aKey->mObj) >> 2) ^ + nsIDHashKey::HashKey(aKey->mIID); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const Key mKey; +}; + +class DConnectInstance; +typedef nsDataHashtable DConnectInstanceMap; + +// extend nsVoidHashSet for compatibility with some nsTHashtable methods +class DConnectInstanceSet : public nsVoidHashSet +{ +public: + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) { + return nsVoidHashSet::Init(initSize) == NS_OK; + } + void Clear() { + PL_DHashTableEnumerate(&mHashTable, PL_DHashStubEnumRemove, nsnull); + } +}; + +typedef PRUint64 DConAddr; + +// a key class used to identify DConnectStub objects stored in a hash table +// by a composite of peer ID and DConAddr + +class DConnectStubKey : public PLDHashEntryHdr +{ +public: + struct Key + { + Key(PRUint32 aPeer, const DConAddr aInstance) + : mPeer (aPeer), mInstance (aInstance) {} + const PRUint32 mPeer; + const DConAddr mInstance; + }; + + typedef const Key &KeyType; + typedef const Key *KeyTypePointer; + + DConnectStubKey(const Key *aKey) : mKey (*aKey) {} + DConnectStubKey(const DConnectStubKey &toCopy) : mKey (toCopy.mKey) {} + ~DConnectStubKey() {} + + KeyType GetKey() const { return mKey; } + KeyTypePointer GetKeyPointer() const { return &mKey; } + + PRBool KeyEquals(KeyTypePointer aKey) const { + return mKey.mPeer == aKey->mPeer && + mKey.mInstance == aKey->mInstance; + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { + return aKey->mPeer ^ + (NS_PTR_TO_INT32(aKey->mInstance) >> 2); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const Key mKey; +}; + +// used elsewhere like nsAtomTable to safely represent the integral value +// of an address. +typedef PRUint64 PtrBits; + +// bit flag that defines if a PtrBits value represents a remote object +#define PTRBITS_REMOTE_BIT 0x1 + +class DConnectStub; +typedef nsDataHashtable DConnectStubMap; + +class ipcDConnectService : public ipcIDConnectService + , public ipcIMessageObserver + , public ipcIClientObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCIDCONNECTSERVICE + NS_DECL_IPCIMESSAGEOBSERVER + NS_DECL_IPCICLIENTOBSERVER + + ipcDConnectService(); + + NS_HIDDEN_(nsresult) Init(); + NS_HIDDEN_(void) Shutdown(); + + NS_HIDDEN_(nsresult) GetInterfaceInfo(const nsID &iid, nsIInterfaceInfo **); + NS_HIDDEN_(nsresult) GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const nsXPTMethodInfo *methodInfo, + const nsXPTParamInfo ¶mInfo, + const nsXPTType &type, + PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isXPTCVariantArray, + nsID &result); + + NS_HIDDEN_(nsresult) SerializeInterfaceParam(ipcMessageWriter &writer, + PRUint32 peer, const nsID &iid, + nsISupports *obj, + nsVoidArray &wrappers); + NS_HIDDEN_(nsresult) DeserializeInterfaceParamBits(PtrBits bits, PRUint32 peer, + const nsID &iid, + nsISupports *&obj); + + NS_HIDDEN_(nsresult) SerializeException(ipcMessageWriter &writer, + PRUint32 peer, nsIException *xcpt, + nsVoidArray &wrappers); + NS_HIDDEN_(nsresult) DeserializeException(ipcMessageReader &reader, + PRUint32 peer, nsIException **xcpt); + + NS_HIDDEN_(void) ReleaseWrappers(nsVoidArray &wrappers, PRUint32 peer); + + NS_HIDDEN_(nsresult) CreateStub(const nsID &, PRUint32, DConAddr, DConnectStub **); +#if 0 + NS_HIDDEN_(PRBool) FindStubAndAddRef(PRUint32, const DConAddr, DConnectStub **); +#endif + // public only for DConnectStub::~DConnectStub() + NS_HIDDEN_(void) DeleteStub(DConnectStub *); + + // public only for DConnectInstance::Release() + NS_HIDDEN_(void) DeleteInstance(DConnectInstance *, PRBool locked = PR_FALSE); + // public only for DConnectStub::CallMethod() + NS_HIDDEN_(PRBool) CheckInstanceAndAddRef(DConnectInstance *, PRUint32); + + PRLock *StubLock() { return mStubLock; } + PRLock *StubQILock() { return mStubQILock; } + + static nsRefPtr GetInstance() { + return nsRefPtr (mInstance); + } + +private: + + NS_HIDDEN ~ipcDConnectService(); + + NS_HIDDEN_(nsresult) StoreInstance(DConnectInstance *); + NS_HIDDEN_(PRBool) FindInstanceAndAddRef(PRUint32, + const nsISupports *, + const nsIID *, + DConnectInstance **); + + NS_HIDDEN_(nsresult) StoreStub(DConnectStub *); + + NS_HIDDEN_(void) OnIncomingRequest(PRUint32 peer, const struct DConnectOp *op, PRUint32 opLen); + + NS_HIDDEN_(void) OnSetup(PRUint32 peer, const struct DConnectSetup *, PRUint32 opLen); + NS_HIDDEN_(void) OnRelease(PRUint32 peer, const struct DConnectRelease *); + NS_HIDDEN_(void) OnInvoke(PRUint32 peer, const struct DConnectInvoke *, PRUint32 opLen); + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + static DECLCALLBACK(void) ProcessMessageOnWorkerThread(ipcDConnectService *aThis, PRUint32 aSenderID, void *aData, PRUint32 aDataLen); +# else + NS_HIDDEN_(nsresult) CreateWorker(); +# endif +#endif + +private: + nsCOMPtr mIIM; + + // lock to protect access to instance sets and the disconnected flag + PRLock *mLock; + + // table of local object instances allocated on behalf of a peer + // (keys are interface pointers of real objects these instances represent) + DConnectInstanceMap mInstances; + // hashset containing the same instances as above + // (used for quick parameter validity checks) + DConnectInstanceSet mInstanceSet; + + // lock to protect access to mStubs and DConnectStub::mRefCntLevels + // (also guards every DConnectStub::Release call to provide atomicity) + PRLock *mStubLock; + + // table of remote object stubs allocated to communicate with peer's instances + DConnectStubMap mStubs; + + // this is true after IPC_Shutdown() has been called + PRBool mDisconnected; + +// member is never initialized or used, no point in wasting memory or making +// someone believe it contains anything relevant +#ifndef VBOX + // our IPC client ID + PRUint32 mSelfID; +#endif + + // global lock to protect access to protect DConnectStub::QueryInterface() + // (we cannot use mStubLock because it isn't supposed to be held long, + // like in case of an IPC call and such) + PRLock *mStubQILock; + +#if defined(DCONNECT_MULTITHREADED) +# if defined(DCONNECT_WITH_IPRT_REQ_POOL) + + /** Request pool. */ + RTREQPOOL mhReqPool; + +# else + + friend class DConnectWorker; + + // pool of worker threads to serve incoming requests + nsVoidArray mWorkers; + // queue of pending requests + ipcList mPendingQ; + // monitor to protect mPendingQ + PRMonitor *mPendingMon; + // number of waiting workers + PRUint32 mWaitingWorkers; + // monitor used to wait on changes in mWaitingWorkers. + PRMonitor *mWaitingWorkersMon; +# endif +#endif + + // global ipcDConnectService instance for internal usage + static ipcDConnectService *mInstance; +}; + +#define IPC_DCONNECTSERVICE_CLASSNAME \ + "ipcDConnectService" +#define IPC_DCONNECTSERVICE_CONTRACTID \ + "@mozilla.org/ipc/dconnect-service;1" +#define IPC_DCONNECTSERVICE_CID \ +{ /* 63a5d9dc-4828-425a-bd50-bd10a4b26f2c */ \ + 0x63a5d9dc, \ + 0x4828, \ + 0x425a, \ + {0xbd, 0x50, 0xbd, 0x10, 0xa4, 0xb2, 0x6f, 0x2c} \ +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in new file mode 100644 index 00000000..2d511de2 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/Makefile.in @@ -0,0 +1,33 @@ +# vim:set ts=8 sw=8 noet: + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = dconnect + +REQUIRES = ipcd \ + nspr \ + string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + TestDConnect.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js new file mode 100644 index 00000000..8403fcdd --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestClient.js @@ -0,0 +1,106 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 file contains code that mirrors the code in TestDConnect.cpp:DoTest + */ + +const ipcIService = Components.interfaces.ipcIService; +const ipcIDConnectService = Components.interfaces.ipcIDConnectService; +const nsIFile = Components.interfaces.nsIFile; +const nsILocalFile = Components.interfaces.nsILocalFile; +const nsIEventQueueService = Components.interfaces.nsIEventQueueService; + +// XXX use directory service for this +const TEST_PATH = "/tmp"; + +var serverID = 0; + +function findServer() +{ + var ipc = Components.classes["@mozilla.org/ipc/service;1"].getService(ipcIService); + serverID = ipc.resolveClientName("test-server"); +} + +function doTest() +{ + var dcon = Components.classes["@mozilla.org/ipc/dconnect-service;1"] + .getService(ipcIDConnectService); + + var file = dcon.createInstanceByContractID(serverID, "@mozilla.org/file/local;1", nsIFile); + + var localFile = file.QueryInterface(nsILocalFile); + + localFile.initWithPath(TEST_PATH); + + if (file.path != TEST_PATH) + { + dump("*** path test failed [path=" + file.path + "]\n"); + return; + } + + dump("file exists: " + file.exists() + "\n"); + + var clone = file.clone(); + + const node = "hello.txt"; + clone.append(node); + dump("files are equal: " + file.equals(clone) + "\n"); + + if (!clone.exists()) + clone.create(nsIFile.NORMAL_FILE_TYPE, 0600); + + clone.moveTo(null, "helloworld.txt"); + + var localObj = Components.classes["@mozilla.org/file/local;1"].createInstance(nsILocalFile); + localObj.initWithPath(TEST_PATH); + dump("file.equals(localObj) = " + file.equals(localObj) + "\n"); + dump("localObj.equals(file) = " + localObj.equals(file) + "\n"); +} + +function setupEventQ() +{ + var eqs = Components.classes["@mozilla.org/event-queue-service;1"] + .getService(nsIEventQueueService); + eqs.createMonitoredThreadEventQueue(); +} + +setupEventQ(); +findServer(); +dump("\n---------------------------------------------------\n"); +doTest(); +dump("---------------------------------------------------\n\n"); diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp new file mode 100644 index 00000000..8eabe13c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestDConnect.cpp @@ -0,0 +1,268 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcIService.h" +#include "ipcIDConnectService.h" +#include "ipcCID.h" + +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" + +#include "nsXPCOMCID.h" +#include "nsILocalFile.h" + +#include "nsString.h" +#include "prmem.h" + +#if defined( XP_WIN ) || defined( XP_OS2 ) +#define TEST_PATH "c:" +#else +#define TEST_PATH "/tmp" +#endif + +#define RETURN_IF_FAILED(rv, step) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + printf("*** %s failed: rv=%x\n", step, rv); \ + return rv;\ + } \ + PR_END_MACRO + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static nsIEventQueue* gEventQ = nsnull; +static PRBool gKeepRunning = PR_TRUE; + +static ipcIService *gIpcServ = nsnull; + +static nsresult DoTest() +{ + nsresult rv; + + nsCOMPtr dcon = do_GetService("@mozilla.org/ipc/dconnect-service;1", &rv); + RETURN_IF_FAILED(rv, "getting dconnect service"); + + PRUint32 remoteClientID = 1; + + nsCOMPtr file; + rv = dcon->CreateInstanceByContractID(remoteClientID, + NS_LOCAL_FILE_CONTRACTID, + NS_GET_IID(nsIFile), + getter_AddRefs(file)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr sup = do_QueryInterface(file, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + printf("*** calling QueryInterface\n"); + nsCOMPtr localFile = do_QueryInterface(file, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString path; + path.AssignLiteral(TEST_PATH); + + printf("*** calling InitWithNativePath\n"); + rv = localFile->InitWithPath(path); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString buf; + rv = file->GetPath(buf); + NS_ENSURE_SUCCESS(rv, rv); + + if (!buf.Equals(path)) + { + NS_ConvertUTF16toUTF8 temp(buf); + printf("*** GetPath erroneously returned [%s]\n", temp.get()); + return NS_ERROR_FAILURE; + } + + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv)) + { + printf("*** Exists test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + printf("File exists? [%d]\n", exists); + + nsCOMPtr clone; + rv = file->Clone(getter_AddRefs(clone)); + if (NS_FAILED(rv)) + { + printf("*** Clone test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + + nsAutoString node; + node.AssignLiteral("hello.txt"); + + rv = clone->Append(node); + if (NS_FAILED(rv)) + { + printf("*** Append test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + + PRBool match; + rv = file->Equals(clone, &match); + if (NS_FAILED(rv)) + { + printf("*** Equals test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + printf("Files are equals? [%d]\n", match); + + // now test passing null for interface pointer + + rv = clone->Exists(&exists); + if (NS_FAILED(rv)) + { + printf("*** Exists test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + if (!exists) + { + rv = clone->Create(nsIFile::NORMAL_FILE_TYPE, 0600); + if (NS_FAILED(rv)) + { + printf("*** Create test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + } + + rv = clone->MoveTo(nsnull, NS_LITERAL_STRING("helloworld.txt")); + if (NS_FAILED(rv)) + { + printf("*** MoveTo test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + + // now test passing local objects to a remote object + + nsCOMPtr myLocalFile; + rv = NS_NewLocalFile(path, PR_TRUE, getter_AddRefs(myLocalFile)); + if (NS_FAILED(rv)) + { + printf("*** NS_NewLocalFile failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + + rv = file->Equals(myLocalFile, &match); + if (NS_FAILED(rv)) + { + printf("*** second Equals test failed [rv=%x]\n", rv); + return NS_ERROR_FAILURE; + } + printf("Files are equals? [%d]\n", match); + + printf("*** DoTest completed successfully :-)\n"); + return NS_OK; +} + +int main(int argc, char **argv) +{ + nsresult rv; + + PRBool serverMode = PR_FALSE; + if (argc > 1) + { + if (strcmp(argv[1], "-server") == 0) + { + serverMode = PR_TRUE; + } + else + { + printf("usage: %s [-server]\n", argv[0]); + return -1; + } + } + + { + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + // Create the Event Queue for this thread... + nsCOMPtr eqs = + do_GetService(kEventQueueServiceCID, &rv); + RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)"); + + rv = eqs->CreateMonitoredThreadEventQueue(); + RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue"); + + rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); + RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + + nsCOMPtr ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv)); + RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); + NS_ADDREF(gIpcServ = ipcServ); + + if (!serverMode) + { + rv = DoTest(); + RETURN_IF_FAILED(rv, "DoTest()"); + } + else + { + gIpcServ->AddName("DConnectServer"); + } + + PLEvent *ev; + while (gKeepRunning) + { + gEventQ->WaitForEvent(&ev); + gEventQ->HandleEvent(ev); + } + + NS_RELEASE(gIpcServ); + + printf("*** processing remaining events\n"); + + // process any remaining events + while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev) + gEventQ->HandleEvent(ev); + + printf("*** done\n"); + } // this scopes the nsCOMPtrs + + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js new file mode 100644 index 00000000..a72e133b --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/dconnect/test/TestServer.js @@ -0,0 +1,66 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 file contains code for a "server" that does nothing more + * than set a name for itself on the IPC system so that the client + * can connect and control this process. + */ + +const ipcIService = Components.interfaces.ipcIService; +const nsIEventQueueService = Components.interfaces.nsIEventQueueService; +const nsIEventQueue = Components.interfaces.nsIEventQueue; + +function registerServer() +{ + var ipc = Components.classes["@mozilla.org/ipc/service;1"].getService(ipcIService); + ipc.addName("test-server"); +} + +function runEventQ() +{ + var eqs = Components.classes["@mozilla.org/event-queue-service;1"] + .getService(nsIEventQueueService); + eqs.createMonitoredThreadEventQueue(); + var queue = eqs.getSpecialEventQueue(eqs.CURRENT_THREAD_EVENT_QUEUE); + + // this never returns + queue.eventLoop(); +} + +registerServer(); +runEventQ(); diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in new file mode 100644 index 00000000..4b94a31f --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/Makefile.in @@ -0,0 +1,52 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = public src + +ifdef ENABLE_TESTS +DIRS += test +endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in new file mode 100644 index 00000000..9a08abdb --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/Makefile.in @@ -0,0 +1,58 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +XPIDL_MODULE = ipcd_lock + +EXPORTS = \ + ipcLockCID.h \ + $(NULL) + +XPIDLSRCS = \ + ipcILockService.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl new file mode 100644 index 00000000..1cbf8651 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcILockService.idl @@ -0,0 +1,65 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsISupports.idl" + +/** + * This service provides named interprocess locking. + */ +[scriptable, uuid(9f6dbe15-d851-4b00-912a-5ac0be88a409)] +interface ipcILockService : nsISupports +{ + /** + * Call this method to acquire a named interprocess lock. + * + * @param aLockName + * specifies the name of the lock + * @param aWaitIfBusy + * wait for the lock to become available; otherwise, fail if lock + * is already held by some other process. + */ + void acquireLock(in string aLockName, + in boolean aWaitIfBusy); + + /** + * Call this method to release a named lock. + * + * @param aLockName + * specifies the name of the lock + */ + void releaseLock(in string aLockName); +}; diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h new file mode 100644 index 00000000..ba756d9b --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/public/ipcLockCID.h @@ -0,0 +1,53 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcLockCID_h__ +#define ipcLockCID_h__ + +#define IPC_LOCKSERVICE_CLASSNAME \ + "ipcLockService" +#define IPC_LOCKSERVICE_CONTRACTID \ + "@mozilla.org/ipc/lock-service;1" +#define IPC_LOCKSERVICE_CID \ +{ /* d9e56bf8-e32e-4b6d-87f1-06d73b0ce7ca */ \ + 0xd9e56bf8, \ + 0xe32e, \ + 0x4b6d, \ + {0x87, 0xf1, 0x06, 0xd7, 0x3b, 0x0c, 0xe7, 0xca} \ +} + +#endif // !ipcLockCID_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in new file mode 100644 index 00000000..26d943a8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/Makefile.in @@ -0,0 +1,69 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = module + +MODULE = ipcd +LIBRARY_NAME = ipcdlock_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + +FORCE_USE_PIC = 1 + +REQUIRES = \ + xpcom \ + string \ + $(NULL) + +CPPSRCS = \ + ipcLockProtocol.cpp \ + ipcLockService.cpp \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../../shared/src \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp new file mode 100644 index 00000000..5a7e7755 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.cpp @@ -0,0 +1,87 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include +#include "prlog.h" +#include "ipcLockProtocol.h" + +//----------------------------------------------------------------------------- + +static inline PRUint8 get_opcode(const PRUint8 *buf) +{ + return (buf[0] & 0x0f); +} + +static inline PRUint8 get_flags(const PRUint8 *buf) +{ + return (buf[0] & 0xf0) >> 4; +} + +static inline const char *get_key(const PRUint8 *buf) +{ + return ((const char *) buf) + 1; +} + +//----------------------------------------------------------------------------- + +PRUint8 * +IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen) +{ + PRUint32 len = 1 // header byte + + strlen(msg->key) // key + + 1; // null terminator + + PRUint8 *buf = (PRUint8 *) ::operator new(len); + if (!buf) + return NULL; + + buf[0] = (msg->opcode | (msg->flags << 4)); + + memcpy(&buf[1], msg->key, len - 1); + *bufLen = len; + return buf; +} + +void +IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg) +{ + PR_ASSERT(bufLen > 2); // malformed buffer otherwise + msg->opcode = get_opcode(buf); + msg->flags = get_flags(buf); + msg->key = get_key(buf); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h new file mode 100644 index 00000000..b74b5cde --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockProtocol.h @@ -0,0 +1,98 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcLockProtocol_h__ +#define ipcLockProtocol_h__ + +#include "prtypes.h" + +// +// ipc lock message format: +// +// +----------------------------------+ +// | opcode : 4 bits | +// +----------------------------------+ +// | flags : 4 bits | +// +----------------------------------+ +// | key : null terminated string | +// +----------------------------------+ +// + +// lock opcodes +#define IPC_LOCK_OP_ACQUIRE 1 +#define IPC_LOCK_OP_RELEASE 2 +#define IPC_LOCK_OP_STATUS_ACQUIRED 3 +#define IPC_LOCK_OP_STATUS_FAILED 4 +#define IPC_LOCK_OP_STATUS_BUSY 5 + +// lock flags +#define IPC_LOCK_FL_NONBLOCKING 1 + +// data structure for representing lock request message +struct ipcLockMsg +{ + PRUint8 opcode; + PRUint8 flags; + const char * key; +}; + +// +// flatten a lock message +// +// returns a malloc'd buffer containing the flattened message. on return, +// bufLen contains the length of the flattened message. +// +PRUint8 *IPC_FlattenLockMsg(const ipcLockMsg *msg, PRUint32 *bufLen); + +// +// unflatten a lock message. upon return, msg->key points into buf, so +// buf must not be deallocated until after msg is no longer needed. +// +void IPC_UnflattenLockMsg(const PRUint8 *buf, PRUint32 bufLen, ipcLockMsg *msg); + +// +// TargetID for message passing +// +#define IPC_LOCK_TARGETID \ +{ /* 703ada8a-2d38-4d5d-9d39-03d1ccceb567 */ \ + 0x703ada8a, \ + 0x2d38, \ + 0x4d5d, \ + {0x9d, 0x39, 0x03, 0xd1, 0xcc, 0xce, 0xb5, 0x67} \ +} + +#endif // !ipcLockProtocol_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp new file mode 100644 index 00000000..771aa787 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.cpp @@ -0,0 +1,168 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "nsDependentString.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" +#include "ipcLockService.h" +#include "ipcLockProtocol.h" +#include "ipcLog.h" +#include "prthread.h" + +static const nsID kLockTargetID = IPC_LOCK_TARGETID; + +//----------------------------------------------------------------------------- + +struct ipcPendingLock +{ + const char *name; + nsresult status; + PRBool complete; +}; + +//----------------------------------------------------------------------------- + +nsresult +ipcLockService::Init() +{ + if (PR_NewThreadPrivateIndex(&mTPIndex, nsnull) != PR_SUCCESS) + return NS_ERROR_OUT_OF_MEMORY; + + // Configure OnMessageAvailable to be called on the IPC thread. This is + // done to allow us to proxy OnAcquireLockComplete events to the right + // thread immediately even if the main thread is blocked waiting to acquire + // some other lock synchronously. + + return IPC_DefineTarget(kLockTargetID, this, PR_FALSE); +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(ipcLockService, ipcILockService, ipcIMessageObserver) + +NS_IMETHODIMP +ipcLockService::AcquireLock(const char *lockName, PRBool waitIfBusy) +{ + LOG(("ipcLockService::AcquireLock [lock=%s wait=%u]\n", lockName, waitIfBusy)); + + ipcLockMsg msg; + msg.opcode = IPC_LOCK_OP_ACQUIRE; + msg.flags = (waitIfBusy ? 0 : IPC_LOCK_FL_NONBLOCKING); + msg.key = lockName; + + PRUint32 bufLen; + nsAutoPtr buf( IPC_FlattenLockMsg(&msg, &bufLen) ); + if (!buf) + return NS_ERROR_OUT_OF_MEMORY; + + ipcPendingLock pendingLock; + pendingLock.name = lockName; + pendingLock.status = 0xDEADBEEF; // something bogus + pendingLock.complete = PR_FALSE; + if (PR_SetThreadPrivate(mTPIndex, &pendingLock) != PR_SUCCESS) + return NS_ERROR_UNEXPECTED; + + // prevent our OnMessageAvailable from being called until we explicitly ask + // for it to be called via IPC_WaitMessage. + IPC_DISABLE_MESSAGE_OBSERVER_FOR_SCOPE(kLockTargetID); + + nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen); + if (NS_SUCCEEDED(rv)) { + do { + // block the calling thread until we get a response from the daemon + rv = IPC_WaitMessage(0, kLockTargetID, this, nsnull, PR_INTERVAL_NO_TIMEOUT); + } + while (NS_SUCCEEDED(rv) && !pendingLock.complete); + + if (NS_SUCCEEDED(rv)) + rv = pendingLock.status; + } + + // we could clear the TPD, but that isn't really necessary. + + return rv; +} + +NS_IMETHODIMP +ipcLockService::ReleaseLock(const char *lockName) +{ + LOG(("ipcLockService::ReleaseLock [lock=%s]\n", lockName)); + + ipcLockMsg msg; + msg.opcode = IPC_LOCK_OP_RELEASE; + msg.flags = 0; + msg.key = lockName; + + PRUint32 bufLen; + PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen); + if (!buf) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = IPC_SendMessage(0, kLockTargetID, buf, bufLen); + delete buf; + + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +// called on the same thread that called IPC_WaitMessage +NS_IMETHODIMP +ipcLockService::OnMessageAvailable(PRUint32 unused, const nsID &target, + const PRUint8 *data, PRUint32 dataLen) +{ + ipcLockMsg msg; + IPC_UnflattenLockMsg(data, dataLen, &msg); + + LOG(("ipcLockService::OnMessageAvailable [lock=%s opcode=%u]\n", msg.key, msg.opcode)); + + ipcPendingLock *pendingLock = (ipcPendingLock *) PR_GetThreadPrivate(mTPIndex); + if (strcmp(pendingLock->name, msg.key) == 0) { + pendingLock->complete = PR_TRUE; + if (msg.opcode == IPC_LOCK_OP_STATUS_ACQUIRED) + pendingLock->status = NS_OK; + else + pendingLock->status = NS_ERROR_FAILURE; + return NS_OK; + } + + LOG(("message does not match; waiting for another...\n")); + + // else, we got a message that another thread is waiting to receive. + return IPC_WAIT_NEXT_MESSAGE; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h new file mode 100644 index 00000000..6014172b --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/ipcLockService.h @@ -0,0 +1,63 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcLockService_h__ +#define ipcLockService_h__ + +#include "ipcILockService.h" +#include "ipcdclient.h" + +//----------------------------------------------------------------------------- + +class ipcLockService : public ipcILockService + , public ipcIMessageObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCILOCKSERVICE + NS_DECL_IPCIMESSAGEOBSERVER + + NS_HIDDEN_(nsresult) Init(); + +private: + PRUintn mTPIndex; +}; + +//----------------------------------------------------------------------------- + +#endif // !ipcLockService_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in new file mode 100644 index 00000000..b35db1bc --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/Makefile.in @@ -0,0 +1,92 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = lockmodule +ifeq ($(OS_ARCH), OS2) +SHORT_LIBNAME = lockmod +endif +MODULE_NAME = ipcd + +FORCE_SHARED_LIB = 1 +NO_DIST_INSTALL = 1 +NO_INSTALL = 1 + +ifeq ($(OS_ARCH),Darwin) +NO_COMPONENT_LINK_MAP = 1 +MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS = +endif + +# required for #include "nsID.h" +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = ipcLockModule.cpp + +LOCAL_INCLUDES = \ + -I$(srcdir)/.. \ + $(NULL) + +EXTRA_OBJS = ../ipcLockProtocol.$(OBJ_SUFFIX) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(NSPR_LIBS) \ + $(EXTRA_DSO_LIBS) \ + $(EXTRA_OBJS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +_IPC_FILES = \ + $(DLL_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \ + $(NULL) + +libs:: $(_IPC_FILES) + $(INSTALL) $^ $(DIST)/bin/ipc/modules + +install:: $(_IPC_FILES) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp new file mode 100644 index 00000000..151c0f89 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/src/module/ipcLockModule.cpp @@ -0,0 +1,337 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include +#include "ipcModuleUtil.h" +#include "ipcLockProtocol.h" +#include "plhash.h" +#include "plstr.h" + +#ifdef DEBUG +#define LOG(args) printf args +#else +#define LOG(args) +#endif + +static const nsID kLockTargetID = IPC_LOCK_TARGETID; + +static void +ipcLockModule_Send(PRUint32 cid, const char *key, PRUint8 opcode) +{ + ipcLockMsg msg = { opcode, 0, key }; + PRUint32 bufLen; + PRUint8 *buf = IPC_FlattenLockMsg(&msg, &bufLen); + if (!buf) + return; + IPC_SendMsg(cid, kLockTargetID, buf, bufLen); + free(buf); +} + +//----------------------------------------------------------------------------- + +// +// gLockTable stores mapping from lock name to ipcLockContext +// +static PLHashTable *gLockTable = NULL; + +//----------------------------------------------------------------------------- + +struct ipcLockContext +{ + PRUint32 mOwnerID; // client ID of this lock's owner + struct ipcLockContext *mNextPending; // pointer to client next in line to + // acquire this lock. + + ipcLockContext(PRUint32 ownerID) + : mOwnerID(ownerID) + , mNextPending(NULL) {} +}; + +//----------------------------------------------------------------------------- + +PR_STATIC_CALLBACK(void *) +ipcLockModule_AllocTable(void *pool, PRSize size) +{ + return malloc(size); +} + +PR_STATIC_CALLBACK(void) +ipcLockModule_FreeTable(void *pool, void *item) +{ + free(item); +} + +PR_STATIC_CALLBACK(PLHashEntry *) +ipcLockModule_AllocEntry(void *pool, const void *key) +{ + return (PLHashEntry *) malloc(sizeof(PLHashEntry)); +} + +PR_STATIC_CALLBACK(void) +ipcLockModule_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ + PL_strfree((char *) he->key); + free(he); +} + +static const PLHashAllocOps ipcLockModule_AllocOps = { + ipcLockModule_AllocTable, + ipcLockModule_FreeTable, + ipcLockModule_AllocEntry, + ipcLockModule_FreeEntry +}; + +//----------------------------------------------------------------------------- + +static void +ipcLockModule_AcquireLock(PRUint32 cid, PRUint8 flags, const char *key) +{ + LOG(("$$$ acquiring lock [key=%s]\n", key)); + + if (!gLockTable) + return; + + ipcLockContext *ctx; + + ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key); + if (ctx) { + // + // lock is already acquired, add this client to the queue. make + // sure this client doesn't already own the lock or live on the queue. + // + while (ctx->mOwnerID != cid && ctx->mNextPending) + ctx = ctx->mNextPending; + if (ctx->mOwnerID != cid) { + // + // if nonblocking, then send busy status message. otherwise, + // proceed to add this client to the pending queue. + // + if (flags & IPC_LOCK_FL_NONBLOCKING) + ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_BUSY); + else + ctx->mNextPending = new ipcLockContext(cid); + } + } + else { + // + // ok, add this lock to the table, and notify client that it now owns + // the lock! + // + ctx = new ipcLockContext(cid); + if (!ctx) + return; + + PL_HashTableAdd(gLockTable, PL_strdup(key), ctx); + + ipcLockModule_Send(cid, key, IPC_LOCK_OP_STATUS_ACQUIRED); + } +} + +static PRBool +ipcLockModule_ReleaseLockHelper(PRUint32 cid, const char *key, ipcLockContext *ctx) +{ + LOG(("$$$ releasing lock [key=%s]\n", key)); + + PRBool removeEntry = PR_FALSE; + + // + // lock is already acquired _or_ maybe client is on the pending list. + // + if (ctx->mOwnerID == cid) { + if (ctx->mNextPending) { + // + // remove this element from the list. since this is the + // first element in the list, instead of removing it we + // shift the data from the next context into this one and + // delete the next context. + // + ipcLockContext *next = ctx->mNextPending; + ctx->mOwnerID = next->mOwnerID; + ctx->mNextPending = next->mNextPending; + delete next; + // + // notify client that it now owns the lock + // + ipcLockModule_Send(ctx->mOwnerID, key, IPC_LOCK_OP_STATUS_ACQUIRED); + } + else { + delete ctx; + removeEntry = PR_TRUE; + } + } + else { + ipcLockContext *prev; + for (;;) { + prev = ctx; + ctx = ctx->mNextPending; + if (!ctx) + break; + if (ctx->mOwnerID == cid) { + // remove ctx from list + prev->mNextPending = ctx->mNextPending; + delete ctx; + break; + } + } + } + + return removeEntry; +} + +static void +ipcLockModule_ReleaseLock(PRUint32 cid, const char *key) +{ + if (!gLockTable) + return; + + ipcLockContext *ctx; + + ctx = (ipcLockContext *) PL_HashTableLookup(gLockTable, key); + if (ctx && ipcLockModule_ReleaseLockHelper(cid, key, ctx)) + PL_HashTableRemove(gLockTable, key); +} + +PR_STATIC_CALLBACK(PRIntn) +ipcLockModule_ReleaseByCID(PLHashEntry *he, PRIntn i, void *arg) +{ + PRUint32 cid = *(PRUint32 *) arg; + + ipcLockContext *ctx = (ipcLockContext *) he->value; + if (ctx->mOwnerID != cid) + return HT_ENUMERATE_NEXT; + + LOG(("$$$ ipcLockModule_ReleaseByCID [cid=%u key=%s he=%p]\n", + cid, (char*)he->key, (void*)he)); + + if (ipcLockModule_ReleaseLockHelper(cid, (const char *) he->key, ctx)) + return HT_ENUMERATE_REMOVE; + + return HT_ENUMERATE_NEXT; +} + +//----------------------------------------------------------------------------- + +static void +ipcLockModule_Init() +{ + LOG(("$$$ ipcLockModule_Init\n")); + + gLockTable = PL_NewHashTable(32, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + &ipcLockModule_AllocOps, + NULL); +} + +static void +ipcLockModule_Shutdown() +{ + LOG(("$$$ ipcLockModule_Shutdown\n")); + + if (gLockTable) { + // XXX walk table destroying all ipcLockContext objects + + PL_HashTableDestroy(gLockTable); + gLockTable = NULL; + } +} + +static void +ipcLockModule_HandleMsg(ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen) +{ + PRUint32 cid = IPC_GetClientID(client); + + LOG(("$$$ ipcLockModule_HandleMsg [cid=%u]\n", cid)); + + ipcLockMsg msg; + IPC_UnflattenLockMsg((const PRUint8 *) data, dataLen, &msg); + + switch (msg.opcode) { + case IPC_LOCK_OP_ACQUIRE: + ipcLockModule_AcquireLock(cid, msg.flags, msg.key); + break; + case IPC_LOCK_OP_RELEASE: + ipcLockModule_ReleaseLock(cid, msg.key); + break; + default: + PR_NOT_REACHED("invalid opcode"); + } +} + +static void +ipcLockModule_ClientUp(ipcClientHandle client) +{ + LOG(("$$$ ipcLockModule_ClientUp [%u]\n", IPC_GetClientID(client))); +} + +static void +ipcLockModule_ClientDown(ipcClientHandle client) +{ + PRUint32 cid = IPC_GetClientID(client); + + LOG(("$$$ ipcLockModule_ClientDown [%u]\n", cid)); + + // + // enumerate lock table, release any locks held by this client. + // + + PL_HashTableEnumerateEntries(gLockTable, ipcLockModule_ReleaseByCID, &cid); +} + +//----------------------------------------------------------------------------- + +static ipcModuleMethods gLockMethods = +{ + IPC_MODULE_METHODS_VERSION, + ipcLockModule_Init, + ipcLockModule_Shutdown, + ipcLockModule_HandleMsg, + ipcLockModule_ClientUp, + ipcLockModule_ClientDown +}; + +static ipcModuleEntry gLockModuleEntry[] = +{ + { IPC_LOCK_TARGETID, &gLockMethods } +}; + +IPC_IMPL_GETMODULES(ipcLockModule, gLockModuleEntry) diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in new file mode 100644 index 00000000..bcf9299a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/Makefile.in @@ -0,0 +1,67 @@ +# vim:set ts=8 sw=8 noet: +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is IBM Corporation. +# Portions created by the Initial Developer are Copyright (C) 2004 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = dconnect + +REQUIRES = ipcd \ + nspr \ + string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + TestIPCLocks.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp new file mode 100644 index 00000000..f35e8434 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/lock/test/TestIPCLocks.cpp @@ -0,0 +1,244 @@ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 test program spawns N copies of itself, and each copy spawns M threads. +// Each thread acquires and releases a named, interprocess lock. +// Randomized delays are injected at various points to exercise the system, and +// help expose any race conditions that may exist. +// +// Usage: TestIPCLocks [-N] + +#include +#include +#include "ipcILockService.h" +#include "ipcLockCID.h" +#include "nsIServiceManagerUtils.h" +#include "nsIEventQueueService.h" +#include "nsCOMPtr.h" +#include "nsXPCOM.h" +#include "prproces.h" +#include "prprf.h" + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#include +static unsigned GetPID() +{ + return (unsigned) getpid(); +} +#elif defined(XP_WIN) +#include +static unsigned GetPID() +{ + return (unsigned) GetCurrentProcessId(); +} +#else +static unsigned int GetPID() +{ + return 0; // implement me! +} +#endif + +static void LOG(const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + PRUint32 nb = 0; + char buf[512]; + + nb = PR_snprintf(buf, sizeof(buf), "[%u:%p] ", GetPID(), PR_GetCurrentThread()); + + PR_vsnprintf(buf + nb, sizeof(buf) - nb, fmt, ap); + buf[sizeof(buf) - 1] = '\0'; + + fwrite(buf, strlen(buf), 1, stdout); + fflush(stdout); + + va_end(ap); +} + +static void RandomSleep(PRUint32 fromMS, PRUint32 toMS) +{ + PRUint32 ms = fromMS + (PRUint32) ((toMS - fromMS) * ((double) rand() / RAND_MAX)); + //LOG("putting thread to sleep for %u ms\n", ms); + PR_Sleep(PR_MillisecondsToInterval(ms)); +} + +static ipcILockService *gLockService; + +PR_STATIC_CALLBACK(void) TestThread(void *arg) +{ + const char *lockName = (const char *) arg; + + LOG("entering TestThread [lock=%s]\n", lockName); + + nsresult rv; + + RandomSleep(1000, 1100); + + //LOG("done sleeping\n"); + + rv = gLockService->AcquireLock(lockName, PR_TRUE); + if (NS_SUCCEEDED(rv)) + { + //LOG("acquired lock \"%s\"\n", lockName); + RandomSleep(500, 1000); + //LOG("releasing lock \"%s\"\n", lockName); + rv = gLockService->ReleaseLock(lockName); + if (NS_FAILED(rv)) + { + LOG("failed to release lock [rv=%x]\n", rv); + NS_ERROR("failed to release lock"); + } + } + else + { + LOG("failed to acquire lock [rv=%x]\n", rv); + NS_NOTREACHED("failed to acquire lock"); + } + + LOG("exiting TestThread [lock=%s rv=%x]\n", lockName, rv); +} + +static const char *kLockNames[] = { + "foopy", + "test", + "1", + "xyz", + "moz4ever", + nsnull +}; + +static nsresult DoTest() +{ + nsresult rv; + + nsCOMPtr eqs = + do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = eqs->CreateMonitoredThreadEventQueue(); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr eq; + rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eq)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr lockService = + do_GetService(IPC_LOCKSERVICE_CONTRACTID); + + gLockService = lockService; + + PRThread *threads[10] = {0}; + int i = 0; + + for (const char **lockName = kLockNames; *lockName; ++lockName, ++i) + { + threads[i] = PR_CreateThread(PR_USER_THREAD, + TestThread, + (void *) *lockName, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + } + + for (i=0; threads[i]; ++i) + { + PR_JoinThread(threads[i]); + threads[i] = nsnull; + } + + gLockService = nsnull; + + LOG("joined with all threads; exiting DoTest\n"); + return NS_OK; +} + +int main(int argc, char **argv) +{ + LOG("entering main\n"); + + int numProcs = 10; + + // if this is a child process, then just run the test + if (argc > 1) + { + if (strcmp(argv[1], "-child") == 0) + { + RandomSleep(1000, 1000); + LOG("running child test\n"); + NS_InitXPCOM2(nsnull, nsnull, nsnull); + DoTest(); + NS_ShutdownXPCOM(nsnull); + return 0; + } + else if (argv[1][0] == '-') + { + // argument is a number + numProcs = atoi(argv[1] + 1); + if (numProcs == 0) + { + printf("### usage: TestIPCLocks [-N]\n" + "where, N is the number of test processes to spawn.\n"); + return -1; + } + } + } + + LOG("sleeping for 1 second\n"); + PR_Sleep(PR_SecondsToInterval(1)); + + PRProcess **procs = (PRProcess **) malloc(sizeof(PRProcess*) * numProcs); + int i; + + // else, spawn the child processes + for (i=0; i +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = common module public src + +ifdef ENABLE_TESTS +DIRS += test +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore new file mode 100644 index 00000000..b292dd21 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/.cvsignore @@ -0,0 +1,9 @@ +Makefile +module.rc +module.res +tmModule.obj +transmngr_client.dll +transmngr_client.pdb +transmngr_client.exp +transmngr_client.lib +transmngr_client.ilk \ No newline at end of file diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in new file mode 100644 index 00000000..87277839 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/Makefile.in @@ -0,0 +1,75 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = transmngr +LIBRARY_NAME = transmngr_client +EXPORT_LIBRARY = 1 +IS_COMPONENT = 1 +MODULE_NAME = transmngr + +REQUIRES = ipcd \ + string \ + xpcom \ + $(NULL) + +CPPSRCS = tmModule.cpp +EXPORTS = tmCID.h + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)transmngr_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)transmngrcom_s.$(LIB_SUFFIX) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../src \ + -I$(srcdir)/../common \ + $(NULL) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(EXTRA_DSO_LIBS) \ + $(MOZ_COMPONENT_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h new file mode 100644 index 00000000..8ca23b84 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmCID.h @@ -0,0 +1,53 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 tmCID_h__ +#define tmCID_h__ + +#define TRANSACTION_SERVICE_CLASSNAME \ + "tmTransactionService" +#define TRANSACTION_SERVICE_CONTRACTID \ + "@mozilla.org/transaction/service;1" +#define TRANSACTION_SERVICE_CID \ +{ /* 1403adf4-94d1-4c67-a8ae-d9f86972d378 */ \ + 0x1403adf4, \ + 0x94d1, \ + 0x4c67, \ + {0xa8, 0xae, 0xd9, 0xf8, 0x69, 0x72, 0xd3, 0x78} \ +} + +#endif // !tmCID_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp new file mode 100644 index 00000000..2853ba0a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/build/tmModule.cpp @@ -0,0 +1,71 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "nsICategoryManager.h" +#include "nsIGenericFactory.h" +#include "nsIServiceManager.h" +#include "tmCID.h" +#include "tmTransactionService.h" + +//----------------------------------------------------------------------------- +// Define the contructor function for the objects +// +// NOTE: This creates an instance of objects by using the default constructor +//----------------------------------------------------------------------------- +NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) + +//----------------------------------------------------------------------------- +// Define a table of CIDs implemented by this module along with other +// information like the function to create an instance, contractid, and +// class name. +//----------------------------------------------------------------------------- +static const nsModuleComponentInfo components[] = { + { TRANSACTION_SERVICE_CLASSNAME, + TRANSACTION_SERVICE_CID, + TRANSACTION_SERVICE_CONTRACTID, + tmTransactionServiceConstructor }, + /* + tmTransactionServiceRegisterProc, + tmTransactionServiceUnregisterProc }, + */ +}; + +//----------------------------------------------------------------------------- +// Implement the NSGetModule() exported function for your module +// and the entire implementation of the module object. +//----------------------------------------------------------------------------- +NS_IMPL_NSGETMODULE(transmngr, components) diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore new file mode 100644 index 00000000..df8a43a2 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/.cvsignore @@ -0,0 +1,5 @@ +Makefile +tmTransaction.obj +tmVector.obj +transmgrcom_s.pdb +transmgrcom_s.lib diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in new file mode 100644 index 00000000..4521c39a --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/Makefile.in @@ -0,0 +1,61 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = transmgrcom_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + +FORCE_USE_PIC = 1 + +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + tmTransaction.cpp \ + tmVector.cpp \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp new file mode 100644 index 00000000..5fb7e5bf --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.cpp @@ -0,0 +1,107 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 +#include "tmTransaction.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Constructor(s) & Destructor + +tmTransaction::~tmTransaction() { + if (mHeader) +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mHeader); +#else + free(mHeader); +#endif +} + +// call only once per lifetime of object. does not reclaim the +// raw message, only sets it. +nsresult +tmTransaction::Init(PRUint32 aOwnerID, + PRInt32 aQueueID, + PRUint32 aAction, + PRInt32 aStatus, + const PRUint8 *aMessage, + PRUint32 aLength) { + nsresult rv = NS_OK; + tmHeader *header = nsnull; + + // indicates the message is the entire raw message + if (aQueueID == TM_INVALID_ID) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + header = (tmHeader*) RTMemAlloc(aLength); +#else + header = (tmHeader*) malloc(aLength); +#endif + if (header) { + mRawMessageLength = aLength; + memcpy(header, aMessage, aLength); + } + else + rv = NS_ERROR_OUT_OF_MEMORY; + } + else { // need to create the tmHeader and concat the message +#ifdef VBOX_USE_IPRT_IN_XPCOM + header = (tmHeader*) RTMemAlloc (sizeof(tmHeader) + aLength); +#else + header = (tmHeader*) malloc (sizeof(tmHeader) + aLength); +#endif + if (header) { + mRawMessageLength = sizeof(tmHeader) + aLength; + header->action = aAction; + header->queueID = aQueueID; + header->status = aStatus; + header->reserved = 0x00000000; + if (aLength > 0) // add the message if it exists + memcpy((header + 1), aMessage, aLength); + } + else + rv = NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_SUCCEEDED(rv)) { + mOwnerID = aOwnerID; + mHeader = header; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h new file mode 100644 index 00000000..b86f20f0 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmTransaction.h @@ -0,0 +1,234 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmTransaction_H_ +#define _tmTransaction_H_ + +#include "tmUtils.h" + +////////////////////////////////////////////////////////////////////////////// +// +// Message format +// +// |------------------------------------|-- +// |QueueID | | +// |------------------------------------| | +// | Action - Post/Flush/Attach etc | |- this is the tmHeader struct +// |------------------------------------| | +// |Status | | +// |------------------------------------| | +// |Padding | | +// |------------------------------------|-- +// |Message Data (payload) | +// |------------------------------------| +// +// The Attach call is a special case in that it doesn't have a QueueID yet. A +// QueueID will be 0's. The message Data will be the Queue Name String which +// will be the profile name with a domain attached, a domain being +// [prefs|cookies|etc] +// +////////////////////////////////////////////////////////////////////////////// + +/** + * tmHeader contains various flags identifying + */ +struct tmHeader { + PRInt32 queueID; // will be the index of the queue in the TM, can be < 0 + PRUint32 action; // defined by tmUtils.h will be > 0 + PRInt32 status; // return values from methods, could be < 0 + PRUint32 reserved; // not currently used, maintaining word alignment +}; + +/** + * Using tmTransaction: + * + * After creating a tmTransaction either through new or as a member + * or local variable a process must call Init() with the proper set of + * arguements to initialize the state of the transaction. tmTransaction is + * set up to accept 3 types of initialization. + * + * 1) Raw message - All data is carried in the byte pointer aMessage, + * args 2,3,4 should be set to TM_NO_ID and aLength + * must be set to the full length of aMessage, including null + * termination if the payload is a null-term string and the size of the + * tmHeader struct preceeding the message. Currently this + * format is used at the IPC boundary, where we receive a byte pointer + * from the IPC Daemon. + * + * 2) Flags only - aQueueID, aAction and aStatus are all set. aMessage + * should be set to nsnull and aLength to 0. This format is used when + * sending reply messages (except for ATTACH_REPLY) and when the TS + * Transaction Service is sending "control" messages to the Manager - + * flush, detach, etc... + * + * 3) Flags and message - All arguements are set. The aMessage is only + * the message for the client app. aLength should be set to the length + * of aMessage and not include the length of the tmHeader struct. + * + * The only data member you can set post initialization is the QueueID. + * You should only call Init() once in the lifetime of a tmTransaction + * as it doesn't clean up the exisiting data before assigning the new + * data. Therefore it would leak most heinously if Init() were to be + * called twice. + * + * mOwnerID only has relevance on the IPC daemon side of things. The + * Transaction Service has no knowledge of this ID and makes no use + * of it. + */ +class tmTransaction +{ + +public: + + //////////////////////////////////////////////////////////////////////////// + // Constructor(s) & Destructor + + tmTransaction(): mHeader(nsnull), mRawMessageLength(0), mOwnerID(0) { } + + virtual ~tmTransaction(); + + //////////////////////////////////////////////////////////////////////////// + // Public Member Functions + + // Initializer //////////// + + /** + * Sets up the internal data of the transaction. Allows for 3 basic ways + * to call this function: No flags and just one big raw message, Just + * flags and no message, and finally flags and message. If the message + * exists it is copied into the transaction. + * + * @param aOwnerID is given to us by the IPC Daemon and is specific + * to that transport layer. It is only set when transactions + * are sent from the TM to the TS. + * + * @param aQueueID is the either the destination queue, or the queue from + * where this transaction is eminating + * + * @param aAction is the action that occured to generate this transaction + * + * @param aStatus is the success state of the action. + * + * @param aMessage can be a raw message including the 3 flags above or it + * can be just the "payload" of the transaction that the destination + * process is going deal with. + * + * @param aLength is the length of the message. If there is a null + * terminated string in the message make sure the length includes + * the null termination. + * + * @returns NS_OK if everything was successful + * @returns NS_ERROR_OUT_OF_MEMORY if allocation of space for the + * copy of the message fails. + */ + nsresult Init(PRUint32 aOwnerID, + PRInt32 aQueueID, + PRUint32 aAction, + PRInt32 aStatus, + const PRUint8 *aMessage, + PRUint32 aLength); + + // Data Accessors ///////// + + /** + * @returns a const byte pointer to the message + */ + const PRUint8* GetMessage() const { return (PRUint8*)(mHeader + 1); } + + /** + * @returns the length of the message + */ + PRUint32 GetMessageLength() const { + return (mRawMessageLength > sizeof(tmHeader)) ? + (mRawMessageLength - sizeof(tmHeader)) : 0; + } + + /** + * @returns a const pointer to the memory containing the + * flag information followed immediately by the message + * data. + */ + const PRUint8* GetRawMessage() const { return (PRUint8*) mHeader; } + + /** + * @returns the length of the flags and message combined + */ + PRUint32 GetRawMessageLength() const { return mRawMessageLength; } + + /** + * @returns the id of the destination or sending queue, depending on the + * direction of the transaction. + */ + PRInt32 GetQueueID() const { return mHeader->queueID; } + + /** + * @returns the action represented by this transaction + */ + PRUint32 GetAction() const { return mHeader->action; } + + /** + * @returns the success state, if applicable of the action leading + * up to this message + */ + PRInt32 GetStatus() const { return mHeader->status; } + + /** + * @returns the client ID (in IPC daemon terms) of the client who initiated + * the exchange that generated this transaction. + */ + PRUint32 GetOwnerID() const { return mOwnerID; } + + // Data Mutator /////////// + + /** + * Sets the ID of the destination or source queue. Init should have been + * called before the call to this function. + */ + void SetQueueID(PRInt32 aID) { mHeader->queueID = aID; } + +protected: + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Variables + + tmHeader* mHeader; // points to beginning of entire message + PRUint32 mRawMessageLength; // length of entire message, incl tmHeader + PRUint32 mOwnerID; // client who sent this trans. - a IPC ClientID + +}; + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h new file mode 100644 index 00000000..f85184d3 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmUtils.h @@ -0,0 +1,93 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmUtils_H_ +#define _tmUtils_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsID.h" +#include "prlog.h" +#include + +// UUID used to identify the Transaction Module in both daemon and client +// not part of the XPCOM hooks, but rather a means of identifying +// modules withing the IPC daemon. +#define TRANSACTION_MODULE_ID \ +{ /* c3dfbcd5-f51d-420b-abf4-3bae445b96a9 */ \ + 0xc3dfbcd5, \ + 0xf51d, \ + 0x420b, \ + {0xab, 0xf4, 0x3b, 0xae, 0x44, 0x5b, 0x96, 0xa9} \ +} + +//static const nsID kTransModuleID = TRANSACTION_MODULE_ID; + +/////////////////////////////////////////////////////////////////////////////// +// match NS_ERROR_FOO error code formats +// +// only create new errors for those errors that are specific to TM + +#define NS_ERROR_MODULE_TM 27 /* XXX goes in nserror.h -- integrating with ns error codes */ + +#define TM_ERROR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 1) +#define TM_ERROR_WRONG_QUEUE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 2) +#define TM_ERROR_NOT_POSTED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 3) +#define TM_ERROR_QUEUE_EXISTS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 4) +#define TM_SUCCESS_DELETE_QUEUE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_TM, 6) + + +// XXX clean up: +#define TM_INVALID_ID 0xFFFFFFFF +#define TM_INVALID 0xFFFFFFFF +#define TM_NO_ID 0xFFFFFFFE + +// Transaction Actions +enum { + TM_ATTACH = 0, + TM_ATTACH_REPLY, + TM_POST, + TM_POST_REPLY, + TM_NOTIFY, + TM_FLUSH, + TM_FLUSH_REPLY, + TM_DETACH, + TM_DETACH_REPLY +}; + +#endif + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp new file mode 100644 index 00000000..99213f27 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.cpp @@ -0,0 +1,179 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 +#include "tmVector.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +//////////////////////////////////////////////////////////////////////////// +// Constructor(s) & Destructor + +// can not be responsible for reclaiming memory pointed to by the void*s in +// the collection - how would we reclaim, don't know how they were allocated +tmVector::~tmVector() { + if (mElements) +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree((void*)mElements); +#else + free((void*)mElements); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +// Public Member Functions + +nsresult +tmVector::Init() { + +#ifdef VBOX_USE_IPRT_IN_XPCOM + mElements = (void**) RTMemAllocZ (mCapacity * sizeof(void*)); +#else + mElements = (void**) calloc (mCapacity, sizeof(void*)); +#endif + if (!mElements) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// mutators + +PRInt32 +tmVector::Append(void *aElement){ + PR_ASSERT(aElement); + + // make sure there is room + if (mNext == mCapacity) + if (NS_FAILED(Grow())) + return -1; + + // put the element in the array + mElements[mNext] = aElement; + mCount++; + + // encapsulates the index into a success value + return mNext++; // post increment. +} + +void +tmVector::Remove(void *aElement) { + PR_ASSERT(aElement); + + for (PRUint32 index = 0; index < mNext; index++) { + if (mElements[index] == aElement) { + mElements[index] = nsnull; + mCount--; + if (index == mNext-1) { // if we removed the last element + mNext--; + // don't test for success of the shrink + Shrink(); + } + } + } +} + +void +tmVector::RemoveAt(PRUint32 aIndex) { + PR_ASSERT(aIndex < mNext); + + // remove the element if it isn't already nsnull + if (mElements[aIndex] != nsnull) { + mElements[aIndex] = nsnull; + mCount--; + if (aIndex == mNext-1) { // if we removed the last element + mNext--; + // don't test for success of the shrink + Shrink(); + } + } +} + +//void* +//tmVector::operator[](int index) { +// if (index < mNext && index >= 0) +// return mElements[index]; +// return nsnull; +//} + +// Does not delete any of the data, merely removes references to them +void +tmVector::Clear(){ + memset(mElements, 0, mCapacity); + mCount = 0; + mNext = 0; +} + +////////////////////////////////////////////////////////////////////////////// +// Protected Member Functions + +// increases the capacity by the growth increment +nsresult +tmVector::Grow() { + + PRUint32 newcap = mCapacity + GROWTH_INC; +#ifdef VBOX_USE_IPRT_IN_XPCOM + mElements = (void**) RTMemRealloc(mElements, (newcap * sizeof(void*))); +#else + mElements = (void**) realloc(mElements, (newcap * sizeof(void*))); +#endif + if (mElements) { + mCapacity = newcap; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +// reduces the capacity by the growth increment. leaves room +// for one more add before needing to Grow(). +nsresult +tmVector::Shrink() { + + PRUint32 newcap = mCapacity - GROWTH_INC; + if (mNext < newcap) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + mElements = (void**) RTMemRealloc(mElements, newcap * sizeof(void*)); +#else + mElements = (void**) realloc(mElements, newcap * sizeof(void*)); +#endif + if (!mElements) + return NS_ERROR_OUT_OF_MEMORY; + mCapacity = newcap; + } + return NS_OK; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h new file mode 100644 index 00000000..4ddb68ef --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/common/tmVector.h @@ -0,0 +1,160 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmVector_H_ +#define _tmVector_H_ + +#include "tmUtils.h" + +#define GROWTH_INC 5 + +/** + * A simple, clear, self-growing, collection of objects. typed independant + * basically a growing array. Useful in situations where you need an + * indexed collection but do not know the size in advance and need the + * ability for increase and decrease in size. Not optimized for anything + * in particular, or any size in particular. + * + * Is able to guarantee the index of an item will + * not change due to removals of a lower indexed item. The growing, + * and shrinking all happens to the end of the collection + * + * Does not backfill, adds to the end. At some point this should be + * changed to make best use of space. + */ +class tmVector +{ +public: + + //////////////////////////////////////////////////////////////////////////// + // Constructor(s) & Destructor + + /** + * Set some sane default values to set up the internal storage. Init() + * must be called after construction of the object to allcate the + * backing store. + */ + tmVector() : mNext(0), mCount(0), mCapacity(10), mElements(nsnull) {;} + + /** + * Reclaim the memory allocated in the Init() method. + */ + virtual ~tmVector(); + + //////////////////////////////////////////////////////////////////////////// + // Public Member Functions + + /** + * Allocates the storage back-end + * + * @returns NS_OK if allocation succeeded + * @returns NS_ERROR_OUT_OF_MEMORY if the allocation failed + */ + nsresult Init(); + + // mutators + + /** + * @returns the index of the element added, if successful + * @returns -1 if an error occured during allocation of space + */ + PRInt32 Append(void *aElement); + + /** + * This does not collapse the collection, it leaves holes. Note, it also + * doesn't delete the element, it merely removes it from the collection + */ + void Remove(void *aElement); + + /** + * This does not collapse the collection, it leaves holes. Note, it also + * doesn't delete the element, it merely removes it from the collection + */ + void RemoveAt(PRUint32 aIndex); + + /** + * Does not call delete on the elements since we have no idea how to + * reclaim the memory. Sets all array slots to 0. + */ + void Clear(); + + /** + * @returns the element at the index indicated, including nsnull if the + * slot is empty. + */ + void* operator[](PRUint32 index) { + PR_ASSERT(index < mNext); + return mElements[index]; + } + + /** + * @returns the number of elements stored + */ + PRUint32 Count() { return mCount; } + + /** + * Meant to be used as the conditional in a loop. |index < size| should + * reach all elements of the collection and not run out of bounds. If + * slots 0,1,4,5,6 contain elements Size() will return 7, Count() will + * return 5. + * + * @returns the number of slots in the array taken, irrespective of + * holes in the collection. + */ + PRUint32 Size() { return mNext; } + +protected: + + nsresult Grow(); // mCapacity += GROWTH_INC - realloc()s + nsresult Shrink(); // mCapacity -= GROWTH_INC - dumb, free, malloc + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Variables + + // bookkeeping variables + PRUint32 mNext; // next element insertion slot (0 based) + PRUint32 mCount; // how many elements in the Vector (1 based) + PRUint32 mCapacity; // current capacity of the Vector (1 based) + + // the actual array of objects being stored + void **mElements; + +private: + +}; + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore new file mode 100644 index 00000000..ccfb2bc3 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/.cvsignore @@ -0,0 +1,11 @@ +Makefile +module.rc +module.res +tmIPCModule.obj +tmQueue.obj +tmTransactionManager.obj +transmgr.dll +transmgr.exp +transmgr.ilk +transmgr.lib +transmgr.pdb diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in new file mode 100644 index 00000000..b8baa225 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/Makefile.in @@ -0,0 +1,100 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = transmgr +MODULE_NAME = ipcd + +FORCE_SHARED_LIB = 1 +NO_DIST_INSTALL = 1 +NO_INSTALL = 1 + +ifeq ($(OS_ARCH),Darwin) +NO_COMPONENT_LINK_MAP = 1 +MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS = +endif + +REQUIRES = nspr \ + xpcom \ + $(NULL) + +CPPSRCS = \ + tmIPCModule.cpp \ + tmQueue.cpp \ + tmTransactionManager.cpp \ + $(NULL) + +EXPORTS = \ + tmIPCModule.h \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(NSPR_LIBS) \ + $(DIST)/lib/$(LIB_PREFIX)transmgrcom_s.$(LIB_SUFFIX) \ + $(EXTRA_DSO_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +_IPC_FILES = \ + $(DLL_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \ + $(NULL) + +libs:: $(_IPC_FILES) + $(INSTALL) $^ $(DIST)/bin/ipc/modules + +install:: $(_IPC_FILES) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp new file mode 100644 index 00000000..3982c93c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.cpp @@ -0,0 +1,137 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "tmIPCModule.h" +#include "tmTransaction.h" +#include "tmTransactionManager.h" + +/////////////////////////////////////////////////////////////////////////////// +// IPC Daemon hookup stuff + +// functionpointer array giving access to this module from the IPC daemon +static ipcModuleMethods gTransMethods = +{ + IPC_MODULE_METHODS_VERSION, + tmIPCModule::Init, + tmIPCModule::Shutdown, + tmIPCModule::HandleMsg +}; + +static ipcModuleEntry gTransModuleEntry[] = +{ + { TRANSACTION_MODULE_ID, &gTransMethods } +}; + +IPC_IMPL_GETMODULES(TransactionModule, gTransModuleEntry) + +static const nsID kTransModuleID = TRANSACTION_MODULE_ID; + +/////////////////////////////////////////////////////////////////////////////// +// Define global variable + +tmTransactionManager *tmIPCModule::tm; + +/////////////////////////////////////////////////////////////////////////////// +// IPC Module API + +void +tmIPCModule::Init() { + if (!tm) + InitInternal(); +} + +void +tmIPCModule::Shutdown() { + if (tm) { + delete tm; + tm = nsnull; + } +} + +// straight pass-through, don't check args, let the TM do it. +void +tmIPCModule::HandleMsg(ipcClientHandle client, const nsID &target, + const void *data, PRUint32 dataLen) { + + // make sure the trans mngr is there + if (!tm && (InitInternal() < 0)) + return; + + // create the transaction + tmTransaction *trans = new tmTransaction(); + + // initialize it + if (trans) { + if(NS_SUCCEEDED(trans->Init(IPC_GetClientID(client), // who owns it + TM_INVALID_ID, // in data + TM_INVALID, // in data + TM_INVALID, // in data + (PRUint8 *)data, // raw message + dataLen))) { // length of message + // pass it on to the trans mngr + tm->HandleTransaction(trans); + } + else + delete trans; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// tmIPCModule API + +// straight pass-through, don't check args, let the TS & TM do it. +void +tmIPCModule::SendMsg(PRUint32 aDestClientIPCID, tmTransaction *aTransaction) { + + IPC_SendMsg(aDestClientIPCID, + kTransModuleID, + (void *)aTransaction->GetRawMessage(), + aTransaction->GetRawMessageLength()); +} + +/////////////////////////////////////////////////////////////////////////////// +// Protected Methods + +PRInt32 +tmIPCModule::InitInternal() { + + tm = new tmTransactionManager(); + if (tm) + return tm->Init(); + return -1; +} + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h new file mode 100644 index 00000000..d4623b1e --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmIPCModule.h @@ -0,0 +1,109 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmIPCModule_H_ +#define _tmIPCModule_H_ + +#include "ipcModuleUtil.h" +#include "tmUtils.h" + +// forward declarations +class tmTransaction; +class tmTransactionManager; + +/** + * Basically an interface between the tmTransactionManager and the IPC + * daemon. Does little else than format the data from one party into + * a format understandable to the other. + * + * The reason for this class is to try and abstract the transportation + * layer the transaction service uses. By using this class the Transaction + * Manager itself only needs to know that clients are identified by + * PRUint32 IDs. + */ +class tmIPCModule +{ +public: + + //////////////////////////////////////////////////////////////////////////// + // ipcModule API - called from IPC daemon + + /** + * Clean up the TM + */ + static void Shutdown(); + + /** + * Check the TM, create it if neccessary. + */ + static void Init(); + + /** + * Receives a message from the IPC daemon, creates a transaction and sends + * it to the TM to deal with. + */ + static void HandleMsg(ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen); + + //////////////////////////////////////////////////////////////////////////// + // tmIPCModule API - called from tmTransactionManager + + /** + * Sends the message to the IPC daemon to be deliverd to the client arg. + */ + static void SendMsg(PRUint32 aDestClientIPCID, tmTransaction *aTransaction); + +protected: + + /** + * tm should be null coming into this method. This does NOT delete tm + * first. + * + * @returns NS_OK if everything succeeds + * @returns -1 if initialization fails + */ + static PRInt32 InitInternal(); + + static tmTransactionManager *tm; + +}; + +#endif + + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp new file mode 100644 index 00000000..5164446f --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.cpp @@ -0,0 +1,223 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "plstr.h" +#include "tmQueue.h" +#include "tmTransaction.h" +#include "tmTransactionManager.h" +#include "tmUtils.h" + +/////////////////////////////////////////////////////////////////////////////// +// Constructors & Destructor + +tmQueue::~tmQueue() { + + // empty the vectors + PRUint32 index = 0; + PRUint32 size = mTransactions.Size(); + for ( ; index < size ; index++) { + if (mTransactions[index]) + delete (tmTransaction *)mTransactions[index]; + } + + // don't need to delete the mListeners because + // we just insert PRUint32s, no allocation + + mTM = nsnull; + mID = 0; + if (mName) + PL_strfree(mName); +} + +/////////////////////////////////////////////////////////////////////////////// +// Public Methods + +PRInt32 +tmQueue::Init(const char* aName, PRUint32 aID, tmTransactionManager *aTM) { + PR_ASSERT(mTM == nsnull); + + if (NS_SUCCEEDED(mTransactions.Init()) && + NS_SUCCEEDED(mListeners.Init()) && + ((mName = PL_strdup(aName)) != nsnull) ) { + mTM = aTM; + mID = aID; + return NS_OK; + } + return -1; +} + +PRInt32 +tmQueue::AttachClient(PRUint32 aClientID) { + + PRInt32 status = NS_OK; // success of adding client + + if (!IsAttached(aClientID)) { + // add the client to the listener list -- null safe call + status = mListeners.Append((void*) aClientID); + } + else + status = -2; + + // create & init a reply transaction + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(aClientID, // owner's ipc ID + mID, // client gets our ID + TM_ATTACH_REPLY, // action + status, // success of the add + (PRUint8*)mName, // client matches name to ID + PL_strlen(mName)+1))) { + // send the reply + mTM->SendTransaction(aClientID, &trans); + } + + // if we successfully added the client - send all current transactions + if (status >= 0) { // append returns the index of the added element + + PRUint32 size = mTransactions.Size(); + for (PRUint32 index = 0; index < size; index++) { + if (mTransactions[index]) + mTM->SendTransaction(aClientID, (tmTransaction*) mTransactions[index]); + } + } + return status; +} + +PRInt32 +tmQueue::DetachClient(PRUint32 aClientID) { + + PRUint32 size = mListeners.Size(); + PRUint32 id = 0; + PRInt32 status = -1; + + for (PRUint32 index = 0; index < size; index++) { + id = (PRUint32)NS_PTR_TO_INT32(mListeners[index]); + if(id == aClientID) { + mListeners.RemoveAt(index); + status = NS_OK; + break; + } + } + + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(aClientID, + mID, + TM_DETACH_REPLY, + status, + nsnull, + 0))) { + // send the reply + mTM->SendTransaction(aClientID, &trans); + } + + // if we've removed all the listeners, remove the queue. + if (mListeners.Size() == 0) + return TM_SUCCESS_DELETE_QUEUE; + return status; +} + +void +tmQueue::FlushQueue(PRUint32 aClientID) { + + if(!IsAttached(aClientID)) + return; + + PRUint32 size = mTransactions.Size(); + for (PRUint32 index = 0; index < size; index++) + if (mTransactions[index]) + delete (tmTransaction*)mTransactions[index]; + + mTransactions.Clear(); + + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(aClientID, + mID, + TM_FLUSH_REPLY, + NS_OK, + nsnull, + 0))) { + mTM->SendTransaction(aClientID, &trans); + } +} + +PRInt32 +tmQueue::PostTransaction(tmTransaction *aTrans) { + + PRInt32 status = -1; + PRUint32 ownerID = aTrans->GetOwnerID(); + + // if we are attached, have the right queue and have successfully + // appended the transaction to the queue, send the transaction + // to all the listeners. + + if (IsAttached(ownerID) && aTrans->GetQueueID() == mID) + status = mTransactions.Append(aTrans); + + if (status >= 0) { + // send the transaction to all members of mListeners except the owner + PRUint32 size = mListeners.Size(); + PRUint32 id = 0; + for (PRUint32 index = 0; index < size; index++) { + id = (PRUint32)NS_PTR_TO_INT32(mListeners[index]); + if (ownerID != id) + mTM->SendTransaction(id, aTrans); + } + } + + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(ownerID, + mID, + TM_POST_REPLY, + status, + nsnull, + 0))) { + // send the reply + mTM->SendTransaction(ownerID, &trans); + } + return status; +} + +PRBool +tmQueue::IsAttached(PRUint32 aClientID) { + // XXX could be an issue if the aClientID is 0 and there + // is a "hole" in the mListeners vector. - may NEED to store PRUint32*s + PRUint32 size = mListeners.Size(); + for (PRUint32 index = 0; index < size; index++) { + if (aClientID == (PRUint32)NS_PTR_TO_INT32(mListeners[index])) + return PR_TRUE; + } + return PR_FALSE; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h new file mode 100644 index 00000000..1c680084 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmQueue.h @@ -0,0 +1,186 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmQueue_H_ +#define _tmQueue_H_ + +#include "tmUtils.h" +#include "tmVector.h" + +class tmClient; +class tmTransaction; +class tmTransactionManager; + +/** + * This class isn't so much a queue as it is storage for transactions. It + * is set up to recieve and store transactions in a growing collection + * (using tmVectors). Different messages can be recieved from the + * Transaction Manager(TM) the queue belongs to which can add and remove + * listeners, empty the queue (flush), and add messages to the queue. + * + * See the documentation in tmTransactionService.h for details on the + * messages you can send to and recieve from the queues in the TM + */ +class tmQueue +{ + +public: + + //////////////////////////////////////////////////////////////////////////// + // Constructor & Destructor + + /** + * Set the internal state to default values. Init() must be called + * after construction to allocate the storage and set the name and ID. + */ + tmQueue(): mID(0), mName(nsnull), mTM(nsnull) { } + + /** + * Reclaim the memory allocated in Init(). Destroys the transactions in + * the transaction storage and the ids in the listener storage + */ + virtual ~tmQueue(); + + //////////////////////////////////////////////////////////////////////////// + // Public Member Functions + + /** + * Initialize internal storage vectors and set the name of the queue + * and the pointer to the TM container. + * + * @returns NS_OK if everything succeeds + * @returns -1 if initialization fails + */ + PRInt32 Init(const char* aName, PRUint32 aID, tmTransactionManager *aTM); + + // Queue Operations + + /** + * Adds the clientID to the list of queue listeners. A reply is created + * and sent to the client. The reply contains both the name of the + * queue and the id, so the client can match the id to the name and + * then use the id in all further communications to the queue. All + * current transactions in the queue are then sent to the client. + * + * If the client was already attached the reply is sent, but not the + * outstanding transactions, the assumption being made that all + * transactions have already been sent to the client. + * + * The reply is sent for all cases, with the return value in the status + * field. + * + * @returns >= 0 if the client was attached successfully + * @returns -1 if the client was not attached + * @returns -2 if the client was already attached + */ + PRInt32 AttachClient(PRUint32 aClientID); + + /** + * Removes the client from the list of queue listeners. A reply is created + * and sent to the client to indicate the success of the removal. + * + * The reply is sent for all cases, with the status field set to either + * -1 or NS_OK. + * + * @returns NS_OK on success + * @returns -1 if client is not attached to this queue + * @returns TM_SUCCESS_DELETE_QUEUE if there are no more listeners, + * instructing the Transaction Mangaer to delete the queue. + */ + PRInt32 DetachClient(PRUint32 aClientID); + + /** + * Removes all the transactions being held in the queue. + * A reply is created and sent to the client to indicate the + * completion of the operation. + */ + void FlushQueue(PRUint32 aClientID); + + /** + * Places the transaction passed in on the queue. Takes ownership of the + * transaction, deletes it in the destructor. A reply is created and + * sent to the client to indicate the success of the posting of the + * transaction. + * + * The reply is sent for all cases, with the status field containing the + * return value. + * + * @returns >= 0 if the message was posted properly. + * @returns -1 if the client posting is not attached to this queue, + * if the transaction has been posted to the wrong queue or + * if an error occured when trying to add the post to the + * internal storage. + */ + PRInt32 PostTransaction(tmTransaction *aTrans); + + // Accessors + + /** + * @returns the ID of the queue + */ + PRUint32 GetID() const { return mID; } + + /** + * @returns the name of the queue + */ + const char* GetName() const { return mName; } + +protected: + + /** + * Helper method to determine if the client has already attached. + * + * @returns PR_TRUE if the client is attached to the queue. + * @returns PR_FALSE if the client is not attached to the queue. + */ + PRBool IsAttached(PRUint32 aClientID); + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Variables + + // storage + tmVector mTransactions; // transactions that have been posted + tmVector mListeners; // programs listening to this queue + + // bookkeeping + PRUint32 mID; // a number linked to the name in the mTM + char *mName; // format: [namespace][domainname(ie prefs)] + tmTransactionManager *mTM; // the container that holds the queue + +}; + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp new file mode 100644 index 00000000..9d6cc98e --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.cpp @@ -0,0 +1,162 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "plstr.h" +#include +#include "tmQueue.h" +#include "tmTransactionManager.h" +#include "tmTransaction.h" +#include "tmUtils.h" + +/////////////////////////////////////////////////////////////////////////////// +// Constructors & Destructor & Initializer + +tmTransactionManager::~tmTransactionManager() { + + PRUint32 size = mQueues.Size(); + tmQueue *queue = nsnull; + for (PRUint32 index = 0; index < size; index++) { + queue = (tmQueue *)mQueues[index]; + if (queue) { + delete queue; + } + } +} + +PRInt32 +tmTransactionManager::Init() { + return mQueues.Init(); +} + +/////////////////////////////////////////////////////////////////////////////// +// public transaction module methods + +void +tmTransactionManager::HandleTransaction(tmTransaction *aTrans) { + + PRUint32 action = aTrans->GetAction(); + PRUint32 ownerID = aTrans->GetOwnerID(); + tmQueue *queue = nsnull; + + // get the right queue -- attaches do it differently + if (action == TM_ATTACH) { + const char *name = (char*) aTrans->GetMessage(); // is qName for Attaches + queue = GetQueue(name); + if (!queue) { + PRInt32 index = AddQueue(name); + if (index >= 0) + queue = GetQueue(index); // GetQueue may return nsnull + } + } + else // all other trans should have a valid queue ID already + queue = GetQueue(aTrans->GetQueueID()); + + if (queue) { + // All possible actions should have a case, default is not valid + // delete trans when done with them, let the queue own the trans + // that are posted to them. + PRInt32 result = 0; + switch (action) { + case TM_ATTACH: + queue->AttachClient(ownerID); + break; + case TM_POST: + result = queue->PostTransaction(aTrans); + if (result >= 0) // post failed, aTrans cached in a tmQueue + return; + break; + case TM_FLUSH: + queue->FlushQueue(ownerID); + break; + case TM_DETACH: + if (queue->DetachClient(ownerID) == TM_SUCCESS_DELETE_QUEUE) { + // the last client has been removed, remove the queue + RemoveQueue(aTrans->GetQueueID()); // this _could_ be out of bounds + } + break; + default: + PR_NOT_REACHED("bad action in the transaction"); + } + } + delete aTrans; +} + +/////////////////////////////////////////////////////////////////////////////// +// Protected member functions + +// +// Queue Handling +// + +tmQueue* +tmTransactionManager::GetQueue(const char *aQueueName) { + + PRUint32 size = mQueues.Size(); + tmQueue *queue = nsnull; + for (PRUint32 index = 0; index < size; index++) { + queue = (tmQueue*) mQueues[index]; + if (queue && strcmp(queue->GetName(), aQueueName) == 0) + return queue; + } + return nsnull; +} + +// if successful the nsresult contains the index of the added queue +PRInt32 +tmTransactionManager::AddQueue(const char *aQueueName) { + + tmQueue* queue = new tmQueue(); + if (!queue) + return -1; + PRInt32 index = mQueues.Append(queue); + if (index < 0) + delete queue; + else + queue->Init(aQueueName, index, this); + return index; +} + +void +tmTransactionManager::RemoveQueue(PRUint32 aQueueID) { + PR_ASSERT(aQueueID <= mQueues.Size()); + + tmQueue *queue = (tmQueue*)mQueues[aQueueID]; + if (queue) { + mQueues.RemoveAt(aQueueID); + delete queue; + } +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h new file mode 100644 index 00000000..a03ba528 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/module/tmTransactionManager.h @@ -0,0 +1,147 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmTransactionManager_H_ +#define _tmTransactionManager_H_ + +#include "plhash.h" +#include "tmUtils.h" +#include "tmVector.h" +#include "tmIPCModule.h" + +// forward declarations +class tmQueue; +class tmClient; +class tmTransaction; + +/** + * This class manages the flow of messages from the IPC daemon (coming to + * it through the tmIPCModule) that ultimately come from a Transaction + * Service (TS) in a mozilla based client somewhere. The message is + * delivered to the proper queue, where it is dealt with. + * + * New queues get created here as clients request them. + */ +class tmTransactionManager +{ + +public: + + //////////////////////////////////////////////////////////////////////////// + // Constructor(s) & Destructor & Initializer + + /** + * reclaim the memory allcoated during initialization + */ + virtual ~tmTransactionManager(); + + /** + * Set up the storage of the queues - initialize the vector + * + * @returns NS_OK if successful + * @returns -1 if initialization fails + */ + PRInt32 Init(); + + //////////////////////////////////////////////////////////////////////////// + // Public Member Functions + + /** + * Called from the tmIPCModule. Decide where to send the message and + * dispatch it. + */ + void HandleTransaction(tmTransaction *aTrans); + + /** + * Called by the queues when they need to get a message back out to a + * client. + */ + void SendTransaction(PRUint32 aDestClientIPCID, tmTransaction *aTrans) { + PR_ASSERT(aTrans); + tmIPCModule::SendMsg(aDestClientIPCID, aTrans); + } + +protected: + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Functions + + // Queue management + + /** + * @returns the queue indexed by the ID passed in, which could be nsnull + */ + tmQueue* GetQueue(PRUint32 aQueueID) { + return (tmQueue*) mQueues[aQueueID]; + } + + /** + * @returns the queue with the name passed in + * @returns nsnull if there is no queue with that name + */ + tmQueue* GetQueue(const char *aQueueName); + + /** + * If all is successful a new queue with the name provided will be created, + * and added to the collection of queues. It will be initialized and ready + * to have transactions added. + * + * This doesn't check for the existance of a queue with this name. IF + * there is already a queue with this name then you will + * get that when using GetQueue(qName) and never get the new queue + * created here. A call to GetQueue(qID) will be able to get at the new + * queue, however you had better cache the ID. + * + * @returns -1 if the queue can't be created, or is not added + * @returns >= 0 if the queue was added successfully + */ + PRInt32 AddQueue(const char *aQueueType); + + /** + */ + void RemoveQueue(PRUint32 aQueueID); + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Variables + + tmVector mQueues; + +private: + +}; + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in new file mode 100644 index 00000000..65b126e9 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/Makefile.in @@ -0,0 +1,53 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +XPIDL_MODULE = ipcd_transmngr + +XPIDLSRCS = \ + ipcITransactionService.idl \ + ipcITransactionObserver.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl new file mode 100644 index 00000000..c7df965d --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionObserver.idl @@ -0,0 +1,100 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "nsISupports.idl" + +[scriptable, uuid(656c0a6a-5cb3-45ec-8cb6-e7678897f937)] +interface ipcITransactionObserver : nsISupports +{ + /** + * This gets called when a Transaction has been sent from the + * TransactionManager. If the data passed in needs to be stored + * for longer than the life of the method the observer needs + * to make a copy. + * + * @param aQueueID + * The queue from which the transaction originated + * + * @param aData + * The data to be sent. + * + * @param aDataLen + * The length of the data argument + */ + void onTransactionAvailable(in unsigned long aQueueID, + [array, const, size_is(aDataLen)] + in octet aData, + in unsigned long aDataLen); + + /** + * Called after an application sends an Attach message to the + * Transaction Manager. + * + * @param aQueueID + * The client has been attached to the queue with this ID + * + * @param aStatus + * The status of the operation, as defined in tmUtils.h + */ + void onAttachReply(in unsigned long aQueueID, in unsigned long aStatus); + + /** + * Called after an application sends a Detach message. Indicates + * to the client that no more messages will be coming from the + * the TM to this client. Also, no messages posted from this + * client to the indicated queue will be accepted. + * + * @param aQueueID + * The client has been detached from the queue with this ID + * + * @param aStatus + * The status of the operation, as defined in tmUtils.h + */ + void onDetachReply(in unsigned long aQueueID, in unsigned long aStatus); + + /** + * The reply from the TM indicating all messages have been removed + * from the queue indicated. + * + * @param aQueueID + * The queue that has been flushed. + * + * @param aStatus + * The status of the operation, as defined in tmUtils.h + */ + void onFlushReply(in unsigned long aQueueID, in unsigned long aStatus); +}; diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl new file mode 100644 index 00000000..0bcbc453 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/public/ipcITransactionService.idl @@ -0,0 +1,239 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 ***** */ + +// from tmTransactionManager.h +// +// XXX documentation needs work +////////////////////////////////////////////////////////////////////////////// +// Overview of TransactionManager IPC Module +// +// Classes: +// tmIPCModule - From the tmTransactionManager's point of view, this +// is a proxy for the IPC daemon itself. The reverse is true +// from the daemon's point of view. This is an interface for the +// Transaction system to work with the IPC daemon as its transport +// layer. +// tmTransactionManager (TM) - Manages the different queues. Maintains +// the queues neccessary for different clients. Receives messages +// from the tmIPCModule and passes message to the IPC daemon through +// the tmIPCModule. +// tmQueue - this class manages the transactions for the different areas +// of the profiles being shared. Broken down by functional area there +// will be a queue for prefs, cookies etc, but not for profileA and +// profileB, and not for pref_delete, pref_create, pref_change etc... +// tmTransaction - the actual transaction being shared with the different +// tmClients. It contains the type of transaction, which will equate with +// a type of queue in existance, the owner of the transaction (an IPC daemon ID) +// and the actual text message to be shared. +// +////////////////////////////////////////////////////////////////////////////// + +/// XXX some docs that need to be put somewhere: +// +// from tmqueue.cpp +// Docs - note that the status of the TM_ATTACH_REPLY is only for checking +// for TM_ERROR_FAILURE. Other numbers have no importance +// success of the status means the NS_ERROR_GET_CODE(status) will +// yield the index of the listener. +// +// move to documentation page - from tmqueue.h +// +// a queue is specific to profile +// +// UUID going out from the module is a handler in the client +// (will go to the XPCOM service impling that UUID) +// -- does it make sense to have different UUIDs for cookies/prefs/etc +// + +#include "nsISupports.idl" + +interface ipcITransactionObserver; + +[scriptable, uuid(15561efb-8c58-4a47-813a-fa91cf730895)] +interface ipcITransactionService : nsISupports +{ + /** + * Connects the application to the transaction manager, defines the + * namespace and initializes internal storage + * + * @param aNamespace + * A string defining the scope of the transaction domains. It is + * used internally to seperate process listening to the same domain + * (ie. preferences) but for two different namespaces (ie. profile1 vs + * profile2). + * + * @returns NS_OK if all memory allocated properly and the IPC service was + * reached and attached to successfully. + * + * @returns an NS_ERROR_ code specific to the failure otherwise + */ + void init(in ACString aNamespace); + + /** + * Links the observer passed in with the domain specified. This will allow + * the observer to post transactions dealing with this domain as well as + * receive transactions posted by other applications observing this + * domain. + * + * Return codes for this method confer information about the success of + * this call, not of the actual attaching of the observer to the domain. + * (except the TM_ERROR code - which means the observer can not attach) + * If the attach is successful the observer will have its OnAttachReply + * method called before this method returns. + * + * Note: This call is synchronous and will not return until the call to + * OnAttachReply is made. + * + * @param aDomainName + * the name of the domain, in the current namespace, to listen for + * transactions from. i.e. cookies + * + * @param aObserver + * this will be used to notify the application when transactions + * and messages come in. + * + * @param aLockingCall + * Have the Transaction Sevice acquire a lock based on the domain + * before attaching. This should be used when persistant storage + * is being used to prevent data corruption. + * + * @returns NS_OK if the attach message was sent to the Transaction Manager. + * + * @returns an NS_ERROR_ code specific to the failure otherwise + * + * @returns TM_ERROR_QUEUE_EXISTS if the queue already exists which means + * someone has already attached to it. + */ + void attach(in ACString aDomainName, + in ipcITransactionObserver aObserver, + in PRBool aLockingCall); + + /** + * Sends a detach message to the Transaction Manager to unlink the observer + * associated with the domain passed in. + * + * As in attach, return codes do not indicate success of detachment. The + * observer will have it's OnDetach method called if it is successfully + * detached. + * + * Note: This call is an asynchronous call. + * + * @param aDomainName + * the domain, in the current namespace, from which the client + * should be removed. + * + * @returns NS_OK if the detach message is sent to the Transaction Manager + * + * @returns NS_ERROR_FAILURE is something goes wrong + * + * @returns NS_ERRROR_UNEXPECTD if the domain does not have an observer + * attached + */ + void detach(in ACString aDomainName); + + /** + * Sends a flush message to the Transaction Manager to remove all + * transactions for the domain. After this call there will be no + * transactions in the Transaction Manager for the namespace/domain + * pairing. It is up to the application to coordinate the flushing + * of the Transaction Manager with the writing of data to files, + * if needed. + * + * Note: This call is synchronous and will not return until the call to + * OnFlushReply is made. + * + * @param aDomainName + * The domain, in the current namespace, to flush. + * + * @param aLockingCall + * Have the Transaction Sevice acquire a lock based on the domain + * before flushing. This should be used when persistant storage + * is being used to prevent data corruption. + * + * @returns NS_OK if the flush message is sent to the Transaction Manager + * + * @returns NS_ERROR_FAILURE is something goes wrong + * + * @returns NS_ERRROR_UNEXPECTD if the domain does not have an observer + * attached + */ + void flush(in ACString aDomainName, in PRBool aLockingCall); + + /** + * Send the data to the Transaction Manager to be broadcast to any + * applications that have registered as observers of this particular + * namespace/domain pairing. + * + * If this domain is not being observed (attach has not been called for + * this domain) the message is queued until the attach is made and then + * the message is sent to the Transaction Manager with the proper domain + * information. + * + * XXXjg - this may not be neccessary with the synch attach call. + * + * Note: This call is an asynchronous call. + * + * @param aDomainName + * the domain, in the current namespace, to which the data will be + * sent. + * + * @param aData + * The actual data to be sent. + * + * @param aDataLen + * The length of the data argument + */ + void postTransaction(in ACString aDomainName, + [array, const, size_is(aDataLen)] + in octet aData, + in unsigned long aDataLen); +}; + +%{C++ +// singleton implementing ipcITransactionService +#define IPC_TRANSACTIONSERVICE_CLASSNAME \ + "tmTransactionService" +#define IPC_TRANSACTIONSERVICE_CONTRACTID \ + "@mozilla.org/ipc/transaction-service;1" +#define IPC_TRANSACTIONSERVICE_CID \ +{ /* 1403adf4-94d1-4c67-a8ae-d9f86972d378 */ \ + 0x1403adf4, \ + 0x94d1, \ + 0x4c67, \ + {0xa8, 0xae, 0xd9, 0xf8, 0x69, 0x72, 0xd3, 0x78} \ +} +%} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore new file mode 100644 index 00000000..7726b497 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/.cvsignore @@ -0,0 +1,4 @@ +Makefile +tmTransactionService.obj +transmgr_s.lib +transmgr_s.pdb \ No newline at end of file diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in new file mode 100644 index 00000000..6510e489 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/Makefile.in @@ -0,0 +1,64 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = transmgr_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + +REQUIRES = string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + tmTransactionService.cpp \ + $(NULL) + +include $(topsrcdir)/config/config.mk + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp new file mode 100644 index 00000000..e53d6aa7 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.cpp @@ -0,0 +1,504 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsReadableUtils.h" +#include "plstr.h" +#include "ipcITransactionObserver.h" +#include "tmTransaction.h" +#include "tmTransactionService.h" +#include "tmUtils.h" + +static const nsID kTransModuleID = TRANSACTION_MODULE_ID; + +struct tm_waiting_msg { + tmTransaction trans; // a transaction waiting to be sent to a queue + char* domainName; // the short queue name + + ~tm_waiting_msg(); +}; + +tm_waiting_msg::~tm_waiting_msg() { + if (domainName) + PL_strfree(domainName); +} + +struct tm_queue_mapping { + PRInt32 queueID; // the ID in the TM + char* domainName; // used by the consumers of this service + char* joinedQueueName; // used by the service -- namespace + domain name + + ~tm_queue_mapping(); +}; + +tm_queue_mapping::~tm_queue_mapping() { + if (domainName) + PL_strfree(domainName); + if (joinedQueueName) + PL_strfree(joinedQueueName); +} + +////////////////////////////////////////////////////////////////////////////// +// Constructor and Destructor + +tmTransactionService::~tmTransactionService() { + + // just destroy this, it contains 2 pointers it doesn't own. + if (mObservers) + PL_HashTableDestroy(mObservers); + + PRUint32 index = 0; + PRUint32 size = mWaitingMessages.Size(); + tm_waiting_msg *msg = nsnull; + for ( ; index < size; index ++) { + msg = (tm_waiting_msg*) mWaitingMessages[index]; + delete msg; + } + + size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap) + delete qmap; + } +} + +////////////////////////////////////////////////////////////////////////////// +// ISupports + +NS_IMPL_ISUPPORTS2(tmTransactionService, + ipcITransactionService, + ipcIMessageObserver) + +////////////////////////////////////////////////////////////////////////////// +// ipcITransactionService + +NS_IMETHODIMP +tmTransactionService::Init(const nsACString & aNamespace) { + + nsresult rv; + + rv = IPC_DefineTarget(kTransModuleID, this, PR_TRUE); + if (NS_FAILED(rv)) + return rv; + + // get the lock service + lockService = do_GetService("@mozilla.org/ipc/lock-service;1"); + if (!lockService) + return NS_ERROR_FAILURE; + + // create some internal storage + mObservers = PL_NewHashTable(20, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, 0, 0); + if (!mObservers) + return NS_ERROR_FAILURE; + + // init some internal storage + mQueueMaps.Init(); + mWaitingMessages.Init(); + + // store the namespace + mNamespace.Assign(aNamespace); + return NS_OK; +} + +NS_IMETHODIMP +tmTransactionService::Attach(const nsACString & aDomainName, + ipcITransactionObserver *aObserver, + PRBool aLockingCall) { + + // if the queue already exists, then someone else is attached to it. must + // return an error here. Only one module attached to a queue per app. + if (GetQueueID(aDomainName) != TM_NO_ID) + return TM_ERROR_QUEUE_EXISTS; + + // create the full queue name: namespace + queue + nsCString jQName; + jQName.Assign(mNamespace); + jQName.Append(aDomainName); + + // this char* has two homes, make sure it gets PL_free()ed properly + char* joinedQueueName = ToNewCString(jQName); + if (!joinedQueueName) + return NS_ERROR_OUT_OF_MEMORY; + + // link the observer to the joinedqueuename. home #1 for joinedQueueName + // these currently don't get removed until the destructor on this is called. + PL_HashTableAdd(mObservers, joinedQueueName, aObserver); + + // store the domainName and JoinedQueueName, create a place to store the ID + tm_queue_mapping *qm = new tm_queue_mapping(); + if (!qm) + return NS_ERROR_OUT_OF_MEMORY; + qm->queueID = TM_NO_ID; // initially no ID for the queue + qm->joinedQueueName = joinedQueueName; // home #2, owner of joinedQueueName + qm->domainName = ToNewCString(aDomainName); + if (!qm->domainName) { + PL_HashTableRemove(mObservers, joinedQueueName); + delete qm; + return NS_ERROR_OUT_OF_MEMORY; + } + mQueueMaps.Append(qm); + + nsresult rv = NS_ERROR_FAILURE; + tmTransaction trans; + + // acquire a lock if neccessary + if (aLockingCall) + lockService->AcquireLock(joinedQueueName, PR_TRUE); + // XXX need to handle lock failures + + if (NS_SUCCEEDED(trans.Init(0, // no IPC client + TM_NO_ID, // qID gets returned to us + TM_ATTACH, // action + NS_OK, // default status + (PRUint8 *)joinedQueueName, // qName gets copied + PL_strlen(joinedQueueName)+1))) { // message length + // send the attach msg + SendMessage(&trans, PR_TRUE); // synchronous + rv = NS_OK; + } + + // drop the lock if neccessary + if (aLockingCall) + lockService->ReleaseLock(joinedQueueName); + + return rv; +} + +// actual removal of the observer takes place when we get the detach reply +NS_IMETHODIMP +tmTransactionService::Detach(const nsACString & aDomainName) { + + // asynchronous detach + return SendDetachOrFlush(GetQueueID(aDomainName), TM_DETACH, PR_FALSE); + +} + +NS_IMETHODIMP +tmTransactionService::Flush(const nsACString & aDomainName, + PRBool aLockingCall) { + // acquire a lock if neccessary + if (aLockingCall) + lockService->AcquireLock(GetJoinedQueueName(aDomainName), PR_TRUE); + + // synchronous flush + nsresult rv = SendDetachOrFlush(GetQueueID(aDomainName), TM_FLUSH, PR_TRUE); + + // drop the lock if neccessary + if (aLockingCall) + lockService->ReleaseLock(GetJoinedQueueName(aDomainName)); + + return rv; + +} + +NS_IMETHODIMP +tmTransactionService::PostTransaction(const nsACString & aDomainName, + const PRUint8 *aData, + PRUint32 aDataLen) { + + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(0, // no IPC client + GetQueueID(aDomainName), // qID returned to us + TM_POST, // action + NS_OK, // default status + aData, // message data + aDataLen))) { // message length + if (trans.GetQueueID() == TM_NO_ID) { + // stack it and pack it + tm_waiting_msg *msg = new tm_waiting_msg(); + if (!msg) + return NS_ERROR_OUT_OF_MEMORY; + msg->trans = trans; + msg->domainName = ToNewCString(aDomainName); + if (!msg->domainName) { + delete msg; + return NS_ERROR_OUT_OF_MEMORY; + } + mWaitingMessages.Append(msg); + } + else { + // send it + SendMessage(&trans, PR_FALSE); + } + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +////////////////////////////////////////////////////////////////////////////// +// ipcIMessageObserver + +NS_IMETHODIMP +tmTransactionService::OnMessageAvailable(const PRUint32 aSenderID, + const nsID & aTarget, + const PRUint8 *aData, + PRUint32 aDataLength) { + + nsresult rv = NS_ERROR_OUT_OF_MEMORY; // prime the return value + + tmTransaction *trans = new tmTransaction(); + if (trans) { + rv = trans->Init(0, // no IPC client ID + TM_INVALID_ID, // in aData + TM_INVALID_ID, // in aData + TM_INVALID_ID, // in aData + aData, // message data + aDataLength); // message length + + if (NS_SUCCEEDED(rv)) { + switch(trans->GetAction()) { + case TM_ATTACH_REPLY: + OnAttachReply(trans); + break; + case TM_POST_REPLY: + // OnPostReply() would be called here + // isn't neccessary at the current time 2/19/03 + break; + case TM_DETACH_REPLY: + OnDetachReply(trans); + break; + case TM_FLUSH_REPLY: + OnFlushReply(trans); + break; + case TM_POST: + OnPost(trans); + break; + default: // error, should not happen + NS_NOTREACHED("Recieved a TM reply outside of mapped messages"); + break; + } + } + delete trans; + } + return rv; +} + +////////////////////////////////////////////////////////////////////////////// +// Protected Member Functions + +void +tmTransactionService::SendMessage(tmTransaction *aTrans, PRBool aSync) { + + NS_ASSERTION(aTrans, "tmTransactionService::SendMessage called with null transaction"); + + IPC_SendMessage(0, kTransModuleID, + aTrans->GetRawMessage(), + aTrans->GetRawMessageLength()); + if (aSync) + IPC_WaitMessage(0, kTransModuleID, nsnull, nsnull, PR_INTERVAL_NO_TIMEOUT); +} + +void +tmTransactionService::OnAttachReply(tmTransaction *aTrans) { + + // if we attached, store the queue's ID + if (aTrans->GetStatus() >= 0) { + + PRUint32 size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (PRUint32 index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap && + PL_strcmp(qmap->joinedQueueName, (char*) aTrans->GetMessage()) == 0) { + + // set the ID in the mapping + qmap->queueID = aTrans->GetQueueID(); + // send any stored messges to the queue + DispatchStoredMessages(qmap); + } + } + } + + // notify the observer we have attached (or didn't) + ipcITransactionObserver *observer = + (ipcITransactionObserver *)PL_HashTableLookup(mObservers, + (char*)aTrans->GetMessage()); + if (observer) + observer->OnAttachReply(aTrans->GetQueueID(), aTrans->GetStatus()); +} + +void +tmTransactionService::OnDetachReply(tmTransaction *aTrans) { + + tm_queue_mapping *qmap = GetQueueMap(aTrans->GetQueueID()); + + // get the observer before we release the hashtable entry + ipcITransactionObserver *observer = + (ipcITransactionObserver *)PL_HashTableLookup(mObservers, + qmap->joinedQueueName); + + // if it was removed, clean up + if (aTrans->GetStatus() >= 0) { + + // remove the link between observer and queue + PL_HashTableRemove(mObservers, qmap->joinedQueueName); + + // remove the mapping of queue names and id + mQueueMaps.Remove(qmap); + delete qmap; + } + + + // notify the observer -- could be didn't detach + if (observer) + observer->OnDetachReply(aTrans->GetQueueID(), aTrans->GetStatus()); +} + +void +tmTransactionService::OnFlushReply(tmTransaction *aTrans) { + + ipcITransactionObserver *observer = + (ipcITransactionObserver *)PL_HashTableLookup(mObservers, + GetJoinedQueueName(aTrans->GetQueueID())); + if (observer) + observer->OnFlushReply(aTrans->GetQueueID(), aTrans->GetStatus()); +} + +void +tmTransactionService::OnPost(tmTransaction *aTrans) { + + ipcITransactionObserver *observer = + (ipcITransactionObserver*) PL_HashTableLookup(mObservers, + GetJoinedQueueName(aTrans->GetQueueID())); + if (observer) + observer->OnTransactionAvailable(aTrans->GetQueueID(), + aTrans->GetMessage(), + aTrans->GetMessageLength()); +} + +void +tmTransactionService::DispatchStoredMessages(tm_queue_mapping *aQMapping) { + + PRUint32 size = mWaitingMessages.Size(); + tm_waiting_msg *msg = nsnull; + for (PRUint32 index = 0; index < size; index ++) { + msg = (tm_waiting_msg*) mWaitingMessages[index]; + // if the message is waiting on the queue passed in + if (msg && strcmp(aQMapping->domainName, msg->domainName) == 0) { + + // found a match, send it and remove + msg->trans.SetQueueID(aQMapping->queueID); + SendMessage(&(msg->trans), PR_FALSE); + + // clean up + mWaitingMessages.Remove(msg); + delete msg; + } + } +} + +// searches against the short queue name +PRInt32 +tmTransactionService::GetQueueID(const nsACString & aDomainName) { + + PRUint32 size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (PRUint32 index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap && aDomainName.Equals(qmap->domainName)) + return qmap->queueID; + } + return TM_NO_ID; +} + +char* +tmTransactionService::GetJoinedQueueName(PRUint32 aQueueID) { + + PRUint32 size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (PRUint32 index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap && qmap->queueID == aQueueID) + return qmap->joinedQueueName; + } + return nsnull; +} + +char* +tmTransactionService::GetJoinedQueueName(const nsACString & aDomainName) { + + PRUint32 size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (PRUint32 index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap && aDomainName.Equals(qmap->domainName)) + return qmap->joinedQueueName; + } + return nsnull; +} + +tm_queue_mapping* +tmTransactionService::GetQueueMap(PRUint32 aQueueID) { + + PRUint32 size = mQueueMaps.Size(); + tm_queue_mapping *qmap = nsnull; + for (PRUint32 index = 0; index < size; index++) { + qmap = (tm_queue_mapping*) mQueueMaps[index]; + if (qmap && qmap->queueID == aQueueID) + return qmap; + } + return nsnull; +} + +nsresult +tmTransactionService::SendDetachOrFlush(PRUint32 aQueueID, + PRUint32 aAction, + PRBool aSync) { + + // if the queue isn't attached to, just return + if (aQueueID == TM_NO_ID) + return NS_ERROR_UNEXPECTED; + + tmTransaction trans; + if (NS_SUCCEEDED(trans.Init(0, // no IPC client + aQueueID, // qID to detach from + aAction, // action + NS_OK, // default status + nsnull, // no message + 0))) { // no message + // send it + SendMessage(&trans, aSync); + return NS_OK; + } + return NS_ERROR_FAILURE; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h new file mode 100644 index 00000000..cd9310fe --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/src/tmTransactionService.h @@ -0,0 +1,196 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 _tmTransactionService_H_ +#define _tmTransactionService_H_ + +#include "ipcdclient.h" +#include "ipcILockService.h" +#include "ipcIMessageObserver.h" +#include "ipcITransactionService.h" +#include "nsString.h" +#include "nsVoidArray.h" +#include "plhash.h" +#include "tmTransaction.h" +#include "tmVector.h" + +struct tm_queue_mapping; + +/** + * The tmTransactionService shares packets of information + * (transactions) with other Gecko based applications interested in the same + * namespace and domain. An application registers with the Transaction Service + * for a particular namespace and domain and then can post transactions to the + * service and receive transactions from the service. + * + * For applications using the Transaction Service to share changes in state that + * get reflected in files on disk there are certain pattersn to follow to ensure + * data loss does not occur. + * + * Startup: XXX docs needed + * + * Shutdown/writing to disk: XXX docs needed + * + * + */ +class tmTransactionService : public ipcITransactionService, + public ipcIMessageObserver +{ + +public: + + //////////////////////////////////////////////////////////////////////////// + // Constructor & Destructor + tmTransactionService() : mObservers(0) {}; + + /** + * Reclaim all the memory allocated: PL_hashtable, tmVectors + */ + virtual ~tmTransactionService(); + + //////////////////////////////////////////////////////////////////////////// + // Interface Declarations + + // for API docs, see the respective *.idl files + NS_DECL_ISUPPORTS + NS_DECL_IPCITRANSACTIONSERVICE + NS_DECL_IPCIMESSAGEOBSERVER + +protected: + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Functions + + /** + * Pulls the raw message out of the transaction and sends it to the IPC + * service to be delivered to the TM. + * + * @param aTrans + * The transaction to send to the TM + * + * @param aSync + * If TRUE, calling thread will be blocked until a reply is + * received. + */ + void SendMessage(tmTransaction *aTrans, PRBool aSync); + + // handlers for reply messages from TransactionManager + + /** + * Pulls the queueID out of the ATTACH_REPLY message and stores it in the + * proper tm_queue_mapping object. Calls DispatchStoredMessages() to make + * sure we send any messages that have been waiting on the ATTACH_REPLY. + * Also calls the OnAttachReply() method for the observer of the queue. + */ + void OnAttachReply(tmTransaction *aTrans); + + /** + * Removes the tm_queue_mapping object and calls the OnDetachReply() method + * on the observer of the queue detached. + */ + void OnDetachReply(tmTransaction *aTrans); + + /** + * Calls the OnFlushReply method of the observer of the queue. + */ + void OnFlushReply(tmTransaction *aTrans); + + /** + * Calls the OnPost method of the observer of the queue. + */ + void OnPost(tmTransaction *aTrans); + + // other helper functions + + /** + * Cycle through the collection of transactions waiting to go out and + * send any that are waiting on an ATTACH_REPLY from the queue + * specified by the tm_queue_mapping passed in. + */ + void DispatchStoredMessages(tm_queue_mapping *aQMapping); + + // helper methods for accessing the void arrays + + /** + * @returns the ID corresponding to the domain name passed in + * @returns TM_NO_ID if the name is not found. + */ + PRInt32 GetQueueID(const nsACString & aDomainName); + + /** + * @returns the joined queue name - namespace + domain + * (prefs, cookies etc) corresponding to the ID passed in. + * @returns nsnull if the ID is not found. + */ + char* GetJoinedQueueName(PRUint32 aQueueID); + + /** + * @returns the joined queue name - namespace + domain + * (prefs, cookies etc) corresponding to the ID passed in. + * @returns nsnull if the ID is not found. + */ + char* GetJoinedQueueName(const nsACString & aDomainName); + + /** + * @returns the tm_queue_mapping object that contains the ID passed in. + * @returns nsnull if the ID is not found. + */ + tm_queue_mapping* GetQueueMap(PRUint32 aQueueID); + + /** + * Helper method for Detach and Flush requests. + */ + nsresult SendDetachOrFlush(PRUint32 aQueueID, + PRUint32 aAction, + PRBool aSync); + + //////////////////////////////////////////////////////////////////////////// + // Protected Member Variables + + nsCString mNamespace; // limit domains to the namespace + PLHashTable *mObservers; // maps qName -> ipcITransactionObserver + + tmVector mQueueMaps; // queue - name - domain mappings + tmVector mWaitingMessages; // messages sent before ATTACH_REPLY + + nsCOMPtr lockService; // cache the lock service + +private: + +}; + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore new file mode 100644 index 00000000..e3c610be --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/.cvsignore @@ -0,0 +1,6 @@ +Makefile +tmModuleTest.exe +tmModuleTest.ilk +tmModuleTest.pdb +tmModuleTest.obj +tmModuleTest diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in new file mode 100644 index 00000000..385751a3 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/Makefile.in @@ -0,0 +1,68 @@ +# ***** 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 Mozilla Transaction Manager. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corp. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# John Gaunt +# +# 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = tm_test + +REQUIRES = ipcd \ + nspr \ + string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + tmModuleTest.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp new file mode 100644 index 00000000..5d1dccd4 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/extensions/transmngr/test/tmModuleTest.cpp @@ -0,0 +1,323 @@ +/* ***** 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 Mozilla Transaction Manager. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Gaunt + * + * 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 ***** */ + +// transaction manager includes +#include "ipcITransactionService.h" +#include "ipcITransactionObserver.h" + +// ipc daemon includes +#include "ipcIService.h" + +// core & xpcom ns includes +#include "nsDebug.h" +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" +#include "nsString.h" + +// nspr includes +#include "prmem.h" +#include "plgetopt.h" +#include "nspr.h" +#include "prlog.h" + +////////////////////////////////////////////////////////////////////////////// +// Testing/Debug/Logging BEGIN + +const int NameSize = 1024; + +/* command line options */ +PRIntn optDebug = 0; +char optMode = 's'; +char *profileName = new char[NameSize]; +char *queueName = new char[NameSize]; + +char *data = new char[NameSize]; +PRUint32 dataLen = 10; // includes the null terminator for "test data" + +// Testing/Debug/Logging END +////////////////////////////////////////////////////////////////////////////// + +#define RETURN_IF_FAILED(rv, step) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + printf("*** %s failed: rv=%x\n", step, rv); \ + return rv;\ + } \ + PR_END_MACRO + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static nsIEventQueue* gEventQ = nsnull; +static PRBool gKeepRunning = PR_TRUE; +//static PRInt32 gMsgCount = 0; +static ipcIService *gIpcServ = nsnull; +static ipcITransactionService *gTransServ = nsnull; + +//----------------------------------------------------------------------------- + +class myTransactionObserver : public ipcITransactionObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCITRANSACTIONOBSERVER + + myTransactionObserver() { } +}; + +NS_IMPL_ISUPPORTS1(myTransactionObserver, ipcITransactionObserver) + +NS_IMETHODIMP myTransactionObserver::OnTransactionAvailable(PRUint32 aQueueID, const PRUint8 *aData, PRUint32 aDataLen) +{ + printf("tmModuleTest: myTransactionObserver::OnTransactionAvailable [%s]\n", aData); + return NS_OK; +} + +NS_IMETHODIMP myTransactionObserver::OnAttachReply(PRUint32 aQueueID, PRUint32 aStatus) +{ + printf("tmModuleTest: myTransactionObserver::OnAttachReply [%d]\n", aStatus); + return NS_OK; +} + +NS_IMETHODIMP myTransactionObserver::OnDetachReply(PRUint32 aQueueID, PRUint32 aStatus) +{ + printf("tmModuleTest: myTransactionObserver::OnDetachReply [%d]\n", aStatus); + return NS_OK; +} + +NS_IMETHODIMP myTransactionObserver::OnFlushReply(PRUint32 aQueueID, PRUint32 aStatus) +{ + printf("tmModuleTest: myTransactionObserver::OnFlushReply [%d]\n", aStatus); + return NS_OK; +} + + +//----------------------------------------------------------------------------- + +int main(PRInt32 argc, char *argv[]) +{ + nsresult rv; + + // default string values + strcpy(profileName, "defaultProfile"); + strcpy(queueName, "defaultQueue"); + strcpy(data, "test data"); + + { // scope the command line option gathering (needed for some reason) + + // Get command line options + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "bdfhlp:q:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'b': /* broadcast a bunch of messages */ + printf("tmModuleTest: broadcaster\n"); + optMode = 'b'; + break; + case 'd': /* debug mode */ + printf("tmModuleTest: debugging baby\n"); + optDebug = 1; + break; + case 'f': /* broadcast and flush */ + printf("tmModuleTest: flusher\n"); + optMode = 'f'; + break; + case 'h': /* broadcast and detach */ + printf("tmModuleTest: hit-n-run\n"); + optMode = 'h'; + break; + case 'l': /* don't broadcast, just listen */ + printf("tmModuleTest: listener\n"); + optMode = 'l'; + break; + case 'p': /* set the profile name */ + strcpy(profileName, opt->value); + printf("tmModuleTest: profilename:%s\n",profileName); + break; + case 'q': /* set the queue name */ + strcpy(queueName, opt->value); + printf("tmModuleTest: queuename:%s\n",queueName); + break; + default: + printf("tmModuleTest: default\n"); + break; + } + } + PL_DestroyOptState(opt); + } // scope the command line option gathering (needed for some reason) + + { // scope the nsCOMPtrs + + printf("tmModuleTest: Starting xpcom\n"); + + // xpcom startup stuff + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + // Create the Event Queue for this thread... + nsCOMPtr eqs = do_GetService(kEventQueueServiceCID, &rv); + RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)"); + + rv = eqs->CreateMonitoredThreadEventQueue(); + RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue"); + + rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); + RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + + // Need to make sure the ipc system has been started + printf("tmModuleTest: getting ipc service\n"); + nsCOMPtr ipcServ(do_GetService("@mozilla.org/ipc/service;1", &rv)); + RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); + NS_ADDREF(gIpcServ = ipcServ); + + // Get the transaction service + printf("tmModuleTest: getting transaction service\n"); + nsCOMPtr transServ(do_GetService("@mozilla.org/ipc/transaction-service;1", &rv)); + RETURN_IF_FAILED(rv, "do_GetService(transServ)"); + NS_ADDREF(gTransServ = transServ); + + // transaction specifc startup stuff, done for all cases + + nsCOMPtr observ = new myTransactionObserver(); + + // initialize the transaction service with a specific profile + gTransServ->Init(nsDependentCString(profileName)); + printf("tmModuleTest: using profileName [%s]\n", profileName); + + // attach to the queue in the transaction manager + gTransServ->Attach(nsDependentCString(queueName), observ, PR_TRUE); + printf("tmModuleTest: observing queue [%s]\n", queueName); + + + // run specific patterns based on the mode + int i = 0; // wasn't working inside the cases + switch (optMode) + { + case 's': + printf("tmModuleTest: start standard\n"); + // post a couple events + for (; i < 5 ; i++) { + gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen); + } + // listen for events + while (gKeepRunning) + gEventQ->ProcessPendingEvents(); + printf("tmModuleTest: end standard\n"); + break; + case 'b': + printf("tmModuleTest: start broadcast\n"); + // post a BUNCH of messages + for (; i < 50; i++) { + gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen); + } + // listen for events + while (gKeepRunning) + gEventQ->ProcessPendingEvents(); + printf("tmModuleTest: end broadcast\n"); + break; + case 'f': + printf("tmModuleTest: start flush\n"); + // post a couple events + for (; i < 5; i++) { + gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen); + } + // flush the queue + gTransServ->Flush(nsDependentCString(queueName), PR_TRUE); + // post a couple events + for (i=0; i < 8; i++) { + gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen); + } + // listen for events + while (gKeepRunning) + gEventQ->ProcessPendingEvents(); + // detach + gTransServ->Detach(nsDependentCString(queueName)); + printf("tmModuleTest: end flush\n"); + break; + case 'h': + printf("tmModuleTest: start hit-n-run\n"); + // post a couple events + for (; i < 5; i++) { + gTransServ->PostTransaction(nsDependentCString(queueName), (PRUint8 *)data, dataLen); + } + // detach + gTransServ->Detach(nsDependentCString(queueName)); + printf("tmModuleTest: end hit-n-run\n"); + break; + case 'l': + printf("tmModuleTest: start listener\n"); + // listen for events + while (gKeepRunning) + gEventQ->ProcessPendingEvents(); + printf("tmModuleTest: end listener\n"); + break; + default : + printf("tmModuleTest: start & end default\n"); + break; + } + + // shutdown process + + NS_RELEASE(gTransServ); + NS_RELEASE(gIpcServ); + + printf("tmModuleTest: processing remaining events\n"); + + // process any remaining events + PLEvent *ev; + while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev) + gEventQ->HandleEvent(ev); + + printf("tmModuleTest: done\n"); + } // this scopes the nsCOMPtrs + + // helps with shutdown on some cases + PR_Sleep(PR_SecondsToInterval(4)); + + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg b/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg new file mode 100644 index 00000000..a2171122 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/ipc.pkg @@ -0,0 +1,21 @@ +[gecko] +dist/bin/mozipcd@BINS@ +#if OS_ARCH==OS2 +dist/bin/ipc/modules/@DLLP@lockmod@DLLS@ +#else +dist/bin/ipc/modules/@DLLP@lockmodule@DLLS@ +#endif +dist/bin/ipc/modules/@DLLP@transmgr@DLLS@ +dist/bin/components/@DLLP@ipcdc@DLLS@ +!xpt dist/bin/components/ipcd.xpt + +#if ENABLE_TESTS +[gecko-tests] +dist/bin/TestIPC@BINS@ +dist/bin/tmModuleTest@BINS@ +#if USE_SHORT_LIBNAME +dist/bin/ipc/modules/@DLLP@testmod@DLLS@ +#else +dist/bin/ipc/modules/@DLLP@testmodule@DLLS@ +#endif +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in new file mode 100644 index 00000000..ffcaa10c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/Makefile.in @@ -0,0 +1,65 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = ipcdshared_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + +# required for #include "nsID.h" +REQUIRES = \ + xpcom \ + $(NULL) + +CPPSRCS = \ + ipcLog.cpp \ + ipcConfig.cpp \ + ipcMessage.cpp \ + ipcMessagePrimitives.cpp \ + ipcStringList.cpp \ + ipcIDList.cpp \ + ipcm.cpp + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp new file mode 100644 index 00000000..5f829626 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.cpp @@ -0,0 +1,104 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +#if defined(XP_WIN) +#elif defined(XP_OS2) && defined(XP_OS2_NATIVEIPC) +#else +#include +#ifdef XP_UNIX +#include +#include +#include +#endif +#include "ipcConfig.h" +#include "ipcLog.h" +#include "prenv.h" +#include "plstr.h" + +#if defined(XP_OS2) && !defined(XP_OS2_NATIVEIPC) +#ifdef VBOX +static const char kDefaultSocketPrefix[] = "\\socket\\vbox-"; +#else +static const char kDefaultSocketPrefix[] = "\\socket\\mozilla-"; +#endif +static const char kDefaultSocketSuffix[] = "-ipc\\ipcd"; +#else +#ifdef VBOX +static const char kDefaultSocketPrefix[] = "/tmp/.vbox-"; +#else +static const char kDefaultSocketPrefix[] = "/tmp/.mozilla-"; +#endif +static const char kDefaultSocketSuffix[] = "-ipc/ipcd"; +#endif + +void IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen) +{ + const char *logName; + int len; + + PL_strncpyz(buf, kDefaultSocketPrefix, bufLen); + buf += (sizeof(kDefaultSocketPrefix) - 1); + bufLen -= (sizeof(kDefaultSocketPrefix) - 1); + + logName = PR_GetEnv("VBOX_IPC_SOCKETID"); +#if defined(VBOX) && defined(XP_UNIX) + if (!logName || !logName[0]) { + struct passwd *passStruct = getpwuid(getuid()); + if (passStruct) + logName = passStruct->pw_name; + } +#endif + if (!logName || !logName[0]) { + logName = PR_GetEnv("LOGNAME"); + if (!logName || !logName[0]) { + logName = PR_GetEnv("USER"); + if (!logName || !logName[0]) { + LOG(("could not determine username from environment\n")); + goto end; + } + } + } + PL_strncpyz(buf, logName, bufLen); + len = strlen(logName); + buf += len; + bufLen -= len; + +end: + PL_strncpyz(buf, kDefaultSocketSuffix, bufLen); +} + +#endif diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h new file mode 100644 index 00000000..ab8b10e5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcConfig.h @@ -0,0 +1,98 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcProto_h__ +#define ipcProto_h__ + +#if defined(XP_WIN) +// +// use WM_COPYDATA messages +// +#include "prprf.h" + +#define IPC_WINDOW_CLASS "Mozilla:IPCWindowClass" +#define IPC_WINDOW_NAME "Mozilla:IPCWindow" +#define IPC_CLIENT_WINDOW_CLASS "Mozilla:IPCAppWindowClass" +#define IPC_CLIENT_WINDOW_NAME_PREFIX "Mozilla:IPCAppWindow:" +#define IPC_SYNC_EVENT_NAME "Local\\MozillaIPCSyncEvent" +#ifndef IPC_DAEMON_APP_NAME +#define IPC_DAEMON_APP_NAME "mozilla-ipcd.exe" +#endif +#define IPC_PATH_SEP_CHAR '\\' +#define IPC_MODULES_DIR "ipc\\modules" + +#define IPC_CLIENT_WINDOW_NAME_MAXLEN (sizeof(IPC_CLIENT_WINDOW_NAME_PREFIX) + 20) + +// writes client name into buf. buf must be at least +// IPC_CLIENT_WINDOW_NAME_MAXLEN bytes in length. +inline void IPC_GetClientWindowName(PRUint32 pid, char *buf) +{ + PR_snprintf(buf, IPC_CLIENT_WINDOW_NAME_MAXLEN, "%s%u", + IPC_CLIENT_WINDOW_NAME_PREFIX, pid); +} + +#else +#include "nscore.h" +// +// use UNIX domain socket +// +#define IPC_PORT 0 +#define IPC_SOCKET_TYPE "ipc" +#if defined(XP_OS2) +#ifndef IPC_DAEMON_APP_NAME +#define IPC_DAEMON_APP_NAME "mozilla-ipcd.exe" +#endif +#define IPC_PATH_SEP_CHAR '\\' +#define IPC_MODULES_DIR "ipc\\modules" +#else +#ifndef IPC_DAEMON_APP_NAME +#define IPC_DAEMON_APP_NAME "mozilla-ipcd" +#endif +#define IPC_PATH_SEP_CHAR '/' +#define IPC_MODULES_DIR "ipc/modules" +#endif + +NS_HIDDEN_(void) IPC_GetDefaultSocketPath(char *buf, PRUint32 bufLen); + +#endif + +// common shared configuration values + +#define IPC_STARTUP_PIPE_NAME "ipc:startup-pipe" +#define IPC_STARTUP_PIPE_MAGIC 0x1C + +#endif // !ipcProto_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp new file mode 100644 index 00000000..0f64a3a0 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.cpp @@ -0,0 +1,62 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcIDList.h" + +ipcIDNode * +ipcIDList::FindNode(ipcIDNode *node, const nsID &id) +{ + while (node) { + if (node->Equals(id)) + return node; + node = node->mNext; + } + return NULL; +} + +ipcIDNode * +ipcIDList::FindNodeBefore(ipcIDNode *node, const nsID &id) +{ + ipcIDNode *prev = NULL; + while (node) { + if (node->Equals(id)) + return prev; + prev = node; + node = node->mNext; + } + return NULL; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h new file mode 100644 index 00000000..b4fd1512 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcIDList.h @@ -0,0 +1,108 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcIDList_h__ +#define ipcIDList_h__ + +#include "nsID.h" +#include "ipcList.h" + +//----------------------------------------------------------------------------- +// nsID node +//----------------------------------------------------------------------------- + +class ipcIDNode +{ +public: + ipcIDNode(const nsID &id) + : mID(id) + { } + + const nsID &Value() const { return mID; } + + PRBool Equals(const nsID &id) const { return mID.Equals(id); } + + class ipcIDNode *mNext; +private: + nsID mID; +}; + +//----------------------------------------------------------------------------- +// singly-linked list of nsIDs +//----------------------------------------------------------------------------- + +class ipcIDList : public ipcList +{ +public: + typedef ipcList Super; + + void Prepend(const nsID &id) + { + Super::Prepend(new ipcIDNode(id)); + } + + void Append(const nsID &id) + { + Super::Append(new ipcIDNode(id)); + } + + const ipcIDNode *Find(const nsID &id) const + { + return FindNode(mHead, id); + } + + PRBool FindAndDelete(const nsID &id) + { + ipcIDNode *node = FindNodeBefore(mHead, id); + if (node) { + DeleteAfter(node); + return PR_TRUE; + } + else if (!IsEmpty()) { + DeleteFirst(); + return PR_TRUE; + } + + return PR_FALSE; + } + +private: + static NS_HIDDEN_(ipcIDNode *) FindNode (ipcIDNode *head, const nsID &id); + static NS_HIDDEN_(ipcIDNode *) FindNodeBefore(ipcIDNode *head, const nsID &id); +}; + +#endif // !ipcIDList_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h new file mode 100644 index 00000000..a9b9c959 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcList.h @@ -0,0 +1,211 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcList_h__ +#define ipcList_h__ + +#include "prtypes.h" + +//----------------------------------------------------------------------------- +// simple list of singly-linked objects. class T must have the following +// structure: +// +// class T { +// ... +// public: +// T *mNext; +// }; +// +// objects added to the list must be allocated with operator new. class T may +// optionally inherit from ipcListNode if it doesn't wish to define mNext +// explicitly. +//----------------------------------------------------------------------------- + +template +class ipcList +{ +public: + ipcList() + : mHead(NULL) + , mTail(NULL) + { } + ~ipcList() { DeleteAll(); } + + // + // prepends obj at the beginning of the list. + // + void Prepend(T *obj) + { + obj->mNext = mHead; + mHead = obj; + if (!mTail) + mTail = mHead; + } + + // + // appends obj to the end of the list. + // + void Append(T *obj) + { + obj->mNext = NULL; + if (mTail) { + mTail->mNext = obj; + mTail = obj; + } + else + mTail = mHead = obj; + } + + // + // inserts b into the list after a. + // + void InsertAfter(T *a, T *b) + { + b->mNext = a->mNext; + a->mNext = b; + if (mTail == a) + mTail = b; + } + + // + // removes first element w/o deleting it + // + void RemoveFirst() + { + if (mHead) + AdvanceHead(); + } + + // + // removes element after the given element w/o deleting it + // + void RemoveAfter(T *obj) + { + T *rej = obj->mNext; + if (rej) { + obj->mNext = rej->mNext; + if (rej == mTail) + mTail = obj; + } + } + + // + // deletes first element + // + void DeleteFirst() + { + T *first = mHead; + if (first) { + AdvanceHead(); + delete first; + } + } + + // + // deletes element after the given element + // + void DeleteAfter(T *obj) + { + T *rej = obj->mNext; + if (rej) { + RemoveAfter(obj); + delete rej; + } + } + + // + // deletes all elements + // + void DeleteAll() + { + while (mHead) + DeleteFirst(); + } + + const T *First() const { return mHead; } + T *First() { return mHead; } + const T *Last() const { return mTail; } + T *Last() { return mTail; } + + PRBool IsEmpty() const { return mHead == NULL; } + + // + // moves contents of list to another list + // + void MoveTo(ipcList &other) + { + other.mHead = mHead; + other.mTail = mTail; + mHead = NULL; + mTail = NULL; + } + + // gets count of list elements + PRUint32 Count() + { + T *obj = mHead; + PRUint32 count = 0; + while (obj) { + count++; + obj = obj->mNext; + } + + return count; + } + +protected: + void AdvanceHead() + { + mHead = mHead->mNext; + if (!mHead) + mTail = NULL; + } + + T *mHead; + T *mTail; +}; + +template +class ipcListNode +{ +public: + ipcListNode() : mNext(nsnull) {} + + T *mNext; +}; + +#endif // !ipcList_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp new file mode 100644 index 00000000..340b211c --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcLog.cpp @@ -0,0 +1,181 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcLog.h" + +#ifdef IPC_LOGGING + +#include +#include + +#include "prenv.h" +#include "prprf.h" +#include "prthread.h" +#include "plstr.h" + +#ifdef VBOX +# if defined(__OS2__) && defined(PAGE_SIZE) +# undef PAGE_SIZE +# endif +# include // for RTR3InitDll +#else // !VBOX +PRBool ipcLogEnabled = PR_FALSE; +#endif // !VBOX + +char ipcLogPrefix[10] = {0}; + +#ifndef VBOX + +//----------------------------------------------------------------------------- +// UNIX +//----------------------------------------------------------------------------- +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) + +#include +#include + +static inline PRUint32 +WritePrefix(char *buf, PRUint32 bufLen) +{ + return PR_snprintf(buf, bufLen, "[%u:%p] %s ", + (unsigned) getpid(), + PR_GetCurrentThread(), + ipcLogPrefix); +} +#endif + +//----------------------------------------------------------------------------- +// WIN32 +//----------------------------------------------------------------------------- +#ifdef XP_WIN +#include + +static inline PRUint32 +WritePrefix(char *buf, PRUint32 bufLen) +{ + return PR_snprintf(buf, bufLen, "[%u:%p] %s ", + GetCurrentProcessId(), + PR_GetCurrentThread(), + ipcLogPrefix); +} +#endif + +#endif // !VBOX + +//----------------------------------------------------------------------------- +// logging API impl +//----------------------------------------------------------------------------- + +void +IPC_InitLog(const char *prefix) +{ +#ifdef VBOX + // initialize VBox Runtime + RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + + PL_strncpyz(ipcLogPrefix, prefix, sizeof(ipcLogPrefix)); +#else + if (PR_GetEnv("IPC_LOG_ENABLE")) { + ipcLogEnabled = PR_TRUE; + PL_strncpyz(ipcLogPrefix, prefix, sizeof(ipcLogPrefix)); + } +#endif +} + +void +IPC_Log(const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + PRUint32 nb = 0; + char buf[512]; + +#ifdef VBOX + if (ipcLogPrefix[0]) { + nb = strlen(ipcLogPrefix); + if (nb > sizeof(buf) - 2) + nb = sizeof(buf) - 2; + PL_strncpy(buf, ipcLogPrefix, nb); + buf[nb++] = ' '; + } +#else + if (ipcLogPrefix[0]) + nb = WritePrefix(buf, sizeof(buf)); +#endif + + PR_vsnprintf(buf + nb, sizeof(buf) - nb, fmt, ap); + buf[sizeof(buf) - 1] = '\0'; + +#ifdef VBOX + LogFlow(("%s", buf)); +#else + fwrite(buf, strlen(buf), 1, stdout); +#endif + + va_end(ap); +} + +void +IPC_LogBinary(const PRUint8 *data, PRUint32 len) +{ + PRUint32 i, j, ln; + for (i=0; i + * + * 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 ipcLog_h__ +#define ipcLog_h__ + +#include "nscore.h" +#include "prtypes.h" + +#ifndef VBOX +#ifdef DEBUG +#define IPC_LOGGING +#endif +#endif + +#ifdef IPC_LOGGING + +#ifdef VBOX + +/* Redefine logging group to IPC */ +# ifdef LOG_GROUP +# undef LOG_GROUP +# endif +# define LOG_GROUP LOG_GROUP_IPC + +/* Ensure log macros are enabled */ +# ifndef LOG_ENABLED +# define LOG_ENABLED +# endif + +#include + +extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix); +extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...); +extern NS_HIDDEN_(void) IPC_LogBinary(const PRUint8 *data, PRUint32 len); + +# define IPC_LOG(_args) \ + PR_BEGIN_MACRO \ + if (IPC_LOG_ENABLED()) \ + IPC_Log _args; \ + PR_END_MACRO + +/* IPC_Log() internally uses LogFlow() so use LogIsFlowEnabled() below */ +# define IPC_LOG_ENABLED() (LogIsFlowEnabled()) + +# define LOG(args) IPC_LOG(args) + +#else /* !VBOX */ + +extern PRBool ipcLogEnabled; +extern NS_HIDDEN_(void) IPC_InitLog(const char *prefix); +extern NS_HIDDEN_(void) IPC_Log(const char *fmt, ...); +extern NS_HIDDEN_(void) IPC_LogBinary(const PRUint8 *data, PRUint32 len); + +#define IPC_LOG(_args) \ + PR_BEGIN_MACRO \ + if (ipcLogEnabled) \ + IPC_Log _args; \ + PR_END_MACRO + +#define IPC_LOG_ENABLED() ipcLogEnabled + +#define LOG(args) IPC_LOG(args) + +#endif /* !VBOX */ + +#else // IPC_LOGGING + +#define IPC_InitLog(prefix) PR_BEGIN_MACRO PR_END_MACRO +#define IPC_LogBinary(data, len) PR_BEGIN_MACRO PR_END_MACRO +#define IPC_LOG(_args) PR_BEGIN_MACRO PR_END_MACRO +#define IPC_LOG_ENABLED() (0) +#define LOG(args) PR_BEGIN_MACRO PR_END_MACRO + +#endif // IPC_LOGGING + +#endif // !ipcLog_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp new file mode 100644 index 00000000..bfdc7efe --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.cpp @@ -0,0 +1,280 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include +#include "prlog.h" +#include "ipcMessage.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +ipcMessage::~ipcMessage() +{ + if (mMsgHdr) +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mMsgHdr); +#else + free(mMsgHdr); +#endif +} + +void +ipcMessage::Reset() +{ + if (mMsgHdr) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mMsgHdr); +#else + free(mMsgHdr); +#endif + mMsgHdr = NULL; + } + + mMsgOffset = 0; + mMsgComplete = PR_FALSE; +} + +ipcMessage * +ipcMessage::Clone() const +{ + ipcMessage *clone = new ipcMessage(); + if (!clone) + return NULL; + + // copy buf if non-null + if (mMsgHdr) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + clone->mMsgHdr = (ipcMessageHeader *) RTMemDup(mMsgHdr, mMsgHdr->mLen); +#else + clone->mMsgHdr = (ipcMessageHeader *) malloc(mMsgHdr->mLen); + memcpy(clone->mMsgHdr, mMsgHdr, mMsgHdr->mLen); +#endif + } + else + clone->mMsgHdr = NULL; + + clone->mMsgOffset = mMsgOffset; + clone->mMsgComplete = mMsgComplete; + + return clone; +} + +PRStatus +ipcMessage::Init(const nsID &target, const char *data, PRUint32 dataLen) +{ + if (mMsgHdr) +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mMsgHdr); +#else + free(mMsgHdr); +#endif + mMsgComplete = PR_FALSE; + + // allocate message data + PRUint32 msgLen = IPC_MSG_HEADER_SIZE + dataLen; +#ifdef VBOX_USE_IPRT_IN_XPCOM + mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen); +#else + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); +#endif + if (!mMsgHdr) { + mMsgHdr = NULL; + return PR_FAILURE; + } + + // fill in message data + mMsgHdr->mLen = msgLen; + mMsgHdr->mVersion = IPC_MSG_VERSION; + mMsgHdr->mFlags = 0; + mMsgHdr->mTarget = target; + + if (data) + SetData(0, data, dataLen); + + mMsgComplete = PR_TRUE; + return PR_SUCCESS; +} + +PRStatus +ipcMessage::SetData(PRUint32 offset, const char *data, PRUint32 dataLen) +{ + PR_ASSERT(mMsgHdr != NULL); + + if (offset + dataLen > DataLen()) + return PR_FAILURE; + + memcpy((char *) Data() + offset, data, dataLen); + return PR_SUCCESS; +} + +PRBool +ipcMessage::Equals(const nsID &target, const char *data, PRUint32 dataLen) const +{ + return mMsgComplete && + mMsgHdr->mTarget.Equals(target) && + DataLen() == dataLen && + memcmp(Data(), data, dataLen) == 0; +} + +PRBool +ipcMessage::Equals(const ipcMessage *msg) const +{ + PRUint32 msgLen = MsgLen(); + return mMsgComplete && msg->mMsgComplete && + msgLen == msg->MsgLen() && + memcmp(MsgBuf(), msg->MsgBuf(), msgLen) == 0; +} + +PRStatus +ipcMessage::WriteTo(char *buf, + PRUint32 bufLen, + PRUint32 *bytesWritten, + PRBool *complete) +{ + if (!mMsgComplete) + return PR_FAILURE; + + if (mMsgOffset == MsgLen()) { + *bytesWritten = 0; + *complete = PR_TRUE; + return PR_SUCCESS; + } + + PRUint32 count = MsgLen() - mMsgOffset; + if (count > bufLen) + count = bufLen; + + memcpy(buf, MsgBuf() + mMsgOffset, count); + mMsgOffset += count; + + *bytesWritten = count; + *complete = (mMsgOffset == MsgLen()); + + return PR_SUCCESS; +} + +PRStatus +ipcMessage::ReadFrom(const char *buf, + PRUint32 bufLen, + PRUint32 *bytesRead, + PRBool *complete) +{ + *bytesRead = 0; + + if (mMsgComplete) { + *complete = PR_TRUE; + return PR_SUCCESS; + } + + if (mMsgHdr) { + // appending data to buffer + if (mMsgOffset < sizeof(PRUint32)) { + // we haven't learned the message length yet + if (mMsgOffset + bufLen < sizeof(PRUint32)) { + // we still don't know the length of the message! + memcpy((char *) mMsgHdr + mMsgOffset, buf, bufLen); + mMsgOffset += bufLen; + *bytesRead = bufLen; + *complete = PR_FALSE; + return PR_SUCCESS; + } + else { + // we now have enough data to determine the message length + PRUint32 count = sizeof(PRUint32) - mMsgOffset; + memcpy((char *) MsgBuf() + mMsgOffset, buf, count); + mMsgOffset += count; + buf += count; + bufLen -= count; + *bytesRead = count; + + if (MsgLen() > IPC_MSG_GUESSED_SIZE) { + // realloc message buffer to the correct size +#ifdef VBOX_USE_IPRT_IN_XPCOM + mMsgHdr = (ipcMessageHeader *) RTMemRealloc(mMsgHdr, MsgLen()); +#else + mMsgHdr = (ipcMessageHeader *) realloc(mMsgHdr, MsgLen()); +#endif + } + } + } + } + else { + if (bufLen < sizeof(PRUint32)) { + // not enough data available in buffer to determine allocation size + // allocate a partial buffer + PRUint32 msgLen = IPC_MSG_GUESSED_SIZE; +#ifdef VBOX_USE_IPRT_IN_XPCOM + mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen); +#else + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); +#endif + if (!mMsgHdr) + return PR_FAILURE; + memcpy(mMsgHdr, buf, bufLen); + mMsgOffset = bufLen; + *bytesRead = bufLen; + *complete = PR_FALSE; + return PR_SUCCESS; + } + else { + PRUint32 msgLen = *(PRUint32 *) buf; +#ifdef VBOX_USE_IPRT_IN_XPCOM + mMsgHdr = (ipcMessageHeader *) RTMemAlloc(msgLen); +#else + mMsgHdr = (ipcMessageHeader *) malloc(msgLen); +#endif + if (!mMsgHdr) + return PR_FAILURE; + mMsgHdr->mLen = msgLen; + mMsgOffset = 0; + } + } + + // have mMsgHdr at this point + + PRUint32 count = MsgLen() - mMsgOffset; + if (count > bufLen) + count = bufLen; + + memcpy((char *) mMsgHdr + mMsgOffset, buf, count); + mMsgOffset += count; + *bytesRead += count; + + *complete = mMsgComplete = (mMsgOffset == MsgLen()); + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h new file mode 100644 index 00000000..c9f8f184 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessage.h @@ -0,0 +1,214 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcMessage_h__ +#define ipcMessage_h__ + +#include "nsID.h" + +// +// ipc message format: +// +// +------------------------------------+ +// | DWORD : length | +// +------------------+-----------------+ +// | WORD : version | WORD : flags | +// +------------------+-----------------+ +// | nsID : target | +// +------------------------------------+ +// | data | +// +------------------------------------+ +// +// header is 24 bytes. flags are defined below. default value of flags is +// zero. protocol implementations should ignore unrecognized flags. target +// is a 16 byte UUID indicating the intended receiver of this message. +// + +struct ipcMessageHeader +{ + PRUint32 mLen; + PRUint16 mVersion; + PRUint16 mFlags; + nsID mTarget; +}; + +#define IPC_MSG_VERSION (0x1) +#define IPC_MSG_HEADER_SIZE (sizeof(ipcMessageHeader)) +#define IPC_MSG_GUESSED_SIZE (IPC_MSG_HEADER_SIZE + 64) + +// +// the IPC message protocol supports synchronous messages. these messages can +// only be sent from a client to the daemon. a daemon module cannot send a +// synchronous message. the client sets the SYNC_QUERY flag to indicate that +// it is expecting a response with the SYNC_REPLY flag set. +// +#define IPC_MSG_FLAG_SYNC_QUERY (0x1) +#define IPC_MSG_FLAG_SYNC_REPLY (0x2) + +// +// a special flag to prevent repeated processing of the same message by two +// or more selectors when walking through the queue of pending messages +// in WaitTarget(). +// +#define IPC_MSG_FLAG_IN_PROCESS (0x4) + +//----------------------------------------------------------------------------- +// ipcMessage +//----------------------------------------------------------------------------- + +class ipcMessage +{ +public: + ipcMessage() + : mNext(NULL) + , mMetaData(0) + , mMsgHdr(NULL) + , mMsgOffset(0) + , mMsgComplete(PR_FALSE) + { } + ipcMessage(const nsID &target, const char *data, PRUint32 dataLen) + : mNext(NULL) + , mMetaData(0) + , mMsgHdr(NULL) + , mMsgOffset(0) + { Init(target, data, dataLen); } + ~ipcMessage() NS_HIDDEN; + + // + // reset message to uninitialized state + // + NS_HIDDEN_(void) Reset(); + + // + // create a copy of this message + // + NS_HIDDEN_(ipcMessage *) Clone() const; + + // + // initialize message + // + // param: + // topic - message topic string + // data - message data (may be null to leave data uninitialized) + // dataLen - message data len + // + NS_HIDDEN_(PRStatus) Init(const nsID &target, const char *data, PRUint32 dataLen); + + // + // copy data into the message's data section, starting from offset. this + // function can be used to write any portion of the message's data. + // + // param: + // offset - destination offset + // data - data to write + // dataLen - number of bytes to write + // + NS_HIDDEN_(PRStatus) SetData(PRUint32 offset, const char *data, PRUint32 dataLen); + + // + // access message flags + // + void SetFlag(PRUint16 flag) { mMsgHdr->mFlags |= flag; } + void ClearFlag(PRUint16 flag) { mMsgHdr->mFlags &= ~flag; } + PRBool TestFlag(PRUint16 flag) const { return mMsgHdr->mFlags & flag; } + + // + // if true, the message is complete and the members of the message + // can be accessed. + // + PRBool IsComplete() const { return mMsgComplete; } + + // + // readonly accessors + // + const ipcMessageHeader *Header() const { return mMsgHdr; } + const nsID &Target() const { return mMsgHdr->mTarget; } + const char *Data() const { return (char *) mMsgHdr + IPC_MSG_HEADER_SIZE; } + PRUint32 DataLen() const { return mMsgHdr->mLen - IPC_MSG_HEADER_SIZE; } + const char *MsgBuf() const { return (char *) mMsgHdr; } + PRUint32 MsgLen() const { return mMsgHdr->mLen; } + + // + // message comparison functions + // + // param: + // topic - message topic (may be null) + // data - message data (must not be null) + // dataLen - message data length + // + NS_HIDDEN_(PRBool) Equals(const nsID &target, const char *data, PRUint32 dataLen) const; + NS_HIDDEN_(PRBool) Equals(const ipcMessage *msg) const; + + // + // write the message to a buffer segment; segment need not be large + // enough to hold entire message. called repeatedly. + // + NS_HIDDEN_(PRStatus) WriteTo(char *buf, + PRUint32 bufLen, + PRUint32 *bytesWritten, + PRBool *complete); + + // + // read the message from a buffer segment; segment need not contain + // the entire messgae. called repeatedly. + // + NS_HIDDEN_(PRStatus) ReadFrom(const char *buf, + PRUint32 bufLen, + PRUint32 *bytesRead, + PRBool *complete); + + // + // a message can be added to a singly-linked list. + // + class ipcMessage *mNext; + + // + // meta data associated with this message object. the owner of the + // ipcMessage object is free to use this field for any purpose. by + // default, it is initialized to 0. + // + PRUint32 mMetaData; + +private: + ipcMessageHeader *mMsgHdr; + + // XXX document me + PRUint32 mMsgOffset; + PRPackedBool mMsgComplete; +}; + +#endif // !ipcMessage_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp new file mode 100644 index 00000000..08753ddb --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.cpp @@ -0,0 +1,81 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "ipcMessagePrimitives.h" + +ipcMessage_DWORD_STR::ipcMessage_DWORD_STR(const nsID &target, + PRUint32 first, + const char *second) +{ + int sLen = strlen(second); + Init(target, NULL, 4 + sLen + 1); + SetData(0, (char *) &first, 4); + SetData(4, second, sLen + 1); +} + +ipcMessage_DWORD_DWORD_STR::ipcMessage_DWORD_DWORD_STR(const nsID &target, + PRUint32 first, + PRUint32 second, + const char *third) +{ + int sLen = strlen(third); + Init(target, NULL, 8 + sLen + 1); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, 4); + SetData(8, third, sLen + 1); +} + +ipcMessage_DWORD_ID::ipcMessage_DWORD_ID(const nsID &target, + PRUint32 first, + const nsID &second) +{ + Init(target, NULL, 4 + sizeof(nsID)); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, sizeof(nsID)); +} + +ipcMessage_DWORD_DWORD_ID::ipcMessage_DWORD_DWORD_ID(const nsID &target, + PRUint32 first, + PRUint32 second, + const nsID &third) +{ + Init(target, NULL, 8 + sizeof(nsID)); + SetData(0, (char *) &first, 4); + SetData(4, (char *) &second, 4); + SetData(8, (char *) &third, sizeof(nsID)); +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h new file mode 100644 index 00000000..abfa7d69 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessagePrimitives.h @@ -0,0 +1,206 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcMessagePrimitives_h__ +#define ipcMessagePrimitives_h__ + +#include "ipcMessage.h" + +class ipcMessage_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD(const nsID &target, PRUint32 first) + { + Init(target, (char *) &first, sizeof(first)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } +}; + +class ipcMessage_DWORD_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second) + { + PRUint32 data[2] = { first, second }; + Init(target, (char *) data, sizeof(data)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } +}; + +class ipcMessage_DWORD_DWORD_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third) + { + PRUint32 data[3] = { first, second, third }; + Init(target, (char *) data, sizeof(data)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + PRUint32 Third() const + { + return ((PRUint32 *) Data())[2]; + } +}; + +class ipcMessage_DWORD_DWORD_DWORD_DWORD : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_DWORD_DWORD(const nsID &target, PRUint32 first, PRUint32 second, PRUint32 third, PRUint32 fourth) + { + PRUint32 data[4] = { first, second, third, fourth }; + Init(target, (char *) data, sizeof(data)); + } + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + PRUint32 Third() const + { + return ((PRUint32 *) Data())[2]; + } + + PRUint32 Fourth() const + { + return ((PRUint32 *) Data())[3]; + } +}; + +class ipcMessage_DWORD_STR : public ipcMessage +{ +public: + ipcMessage_DWORD_STR(const nsID &target, PRUint32 first, const char *second) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + const char *Second() const + { + return Data() + sizeof(PRUint32); + } +}; + +class ipcMessage_DWORD_DWORD_STR : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_STR(const nsID &target, PRUint32 first, PRUint32 second, const char *third) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + const char *Third() const + { + return Data() + 2 * sizeof(PRUint32); + } +}; + +class ipcMessage_DWORD_ID : public ipcMessage +{ +public: + ipcMessage_DWORD_ID(const nsID &target, PRUint32 first, const nsID &second) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + const nsID &Second() const + { + return * (const nsID *) (Data() + sizeof(PRUint32)); + } +}; + +class ipcMessage_DWORD_DWORD_ID : public ipcMessage +{ +public: + ipcMessage_DWORD_DWORD_ID(const nsID &target, PRUint32 first, PRUint32 second, const nsID &third) NS_HIDDEN; + + PRUint32 First() const + { + return ((PRUint32 *) Data())[0]; + } + + PRUint32 Second() const + { + return ((PRUint32 *) Data())[1]; + } + + const nsID &Third() const + { + return * (const nsID *) (Data() + 2 * sizeof(PRUint32)); + } +}; + +#endif // !ipcMessagePrimitives_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h new file mode 100644 index 00000000..d372713e --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageQ.h @@ -0,0 +1,46 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcMessageQ_h__ +#define ipcMessageQ_h__ + +#include "ipcMessage.h" +#include "ipcList.h" + +typedef ipcList ipcMessageQ; + +#endif // !ipcMessageQ_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h new file mode 100644 index 00000000..99e3e6b8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcMessageUtils.h @@ -0,0 +1,66 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcMessageUtils_h__ +#define ipcMessageUtils_h__ + +class ipcMessage; + +// +// given code like this: +// +// const ipcmMessageClientID *msg = (const ipcmMessageClientID *) rawMsg; +// +// we can write: +// +// ipcMessageCast msg(rawMsg); +// +// XXX ipcMessageCast is probably not the best name for this class. +// +template +class ipcMessageCast +{ +public: + ipcMessageCast() : mPtr(NULL) {} + ipcMessageCast(const ipcMessage *ptr) : mPtr((const T *) ptr) {} + void operator=(const ipcMessage *ptr) { mPtr = (const T *) ptr; } + const T *operator->() { return mPtr; } +private: + const T *mPtr; +}; + +#endif // !ipcMessageUtils_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp new file mode 100644 index 00000000..5464f9a7 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.cpp @@ -0,0 +1,80 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcStringList.h" + +void * +ipcStringNode::operator new(size_t size, const char *str) CPP_THROW_NEW +{ + int len = strlen(str); + + size += len; + + ipcStringNode *node = (ipcStringNode *) ::operator new(size); + if (!node) + return NULL; + + node->mNext = NULL; + memcpy(node->mData, str, len); + node->mData[len] = '\0'; + + return node; +} + +ipcStringNode * +ipcStringList::FindNode(ipcStringNode *node, const char *str) +{ + while (node) { + if (node->Equals(str)) + return node; + node = node->mNext; + } + return NULL; +} + +ipcStringNode * +ipcStringList::FindNodeBefore(ipcStringNode *node, const char *str) +{ + ipcStringNode *prev = NULL; + while (node) { + if (node->Equals(str)) + return prev; + prev = node; + node = node->mNext; + } + return NULL; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h new file mode 100644 index 00000000..2a2316b6 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcStringList.h @@ -0,0 +1,114 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcStringList_h__ +#define ipcStringList_h__ + +#include +#include "plstr.h" +#include "nscore.h" +#include "ipcList.h" + +//----------------------------------------------------------------------------- +// string node +//----------------------------------------------------------------------------- + +class ipcStringNode +{ +public: + ipcStringNode() {} + + const char *Value() const { return mData; } + + PRBool Equals(const char *val) const { return strcmp(mData, val) == 0; } + PRBool EqualsIgnoreCase(const char *val) const { return PL_strcasecmp(mData, val) == 0; } + + class ipcStringNode *mNext; +private: + void *operator new(size_t size, const char *str) CPP_THROW_NEW; + + // this is actually bigger + char mData[1]; + + friend class ipcStringList; +}; + +//----------------------------------------------------------------------------- +// singly-linked list of strings +//----------------------------------------------------------------------------- + +class ipcStringList : public ipcList +{ +public: + typedef ipcList Super; + + void Prepend(const char *str) + { + Super::Prepend(new (str) ipcStringNode()); + } + + void Append(const char *str) + { + Super::Append(new (str) ipcStringNode()); + } + + const ipcStringNode *Find(const char *str) const + { + return FindNode(mHead, str); + } + + PRBool FindAndDelete(const char *str) + { + ipcStringNode *node = FindNodeBefore(mHead, str); + if (node) { + DeleteAfter(node); + return PR_TRUE; + } + else if (!IsEmpty()) { + DeleteFirst(); + return PR_TRUE; + } + + return PR_FALSE; + } + +private: + static NS_HIDDEN_(ipcStringNode *) FindNode (ipcStringNode *head, const char *str); + static NS_HIDDEN_(ipcStringNode *) FindNodeBefore(ipcStringNode *head, const char *str); +}; + +#endif // !ipcStringList_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp new file mode 100644 index 00000000..7f7ed060 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.cpp @@ -0,0 +1,303 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "ipcm.h" +#include "pratom.h" + +const nsID IPCM_TARGET = +{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */ + 0x753ca8ff, + 0xc8c2, + 0x4601, + {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50} +}; + +PRUint32 +IPCM_NewRequestIndex() +{ + static PRInt32 sRequestIndex; + return (PRUint32) PR_AtomicIncrement(&sRequestIndex); +} + +#if 0 + +// +// MSG_TYPE values +// +const PRUint32 ipcmMessagePing::MSG_TYPE = IPCM_MSG_TYPE_PING; +const PRUint32 ipcmMessageError::MSG_TYPE = IPCM_MSG_TYPE_ERROR; +const PRUint32 ipcmMessageClientHello::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_HELLO; +const PRUint32 ipcmMessageClientID::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ID; +const PRUint32 ipcmMessageClientInfo::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_INFO; +const PRUint32 ipcmMessageClientAddName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_NAME; +const PRUint32 ipcmMessageClientDelName::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_NAME; +const PRUint32 ipcmMessageClientAddTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_ADD_TARGET; +const PRUint32 ipcmMessageClientDelTarget::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_DEL_TARGET; +const PRUint32 ipcmMessageQueryClientByName::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_BY_NAME; +const PRUint32 ipcmMessageQueryClientInfo::MSG_TYPE = IPCM_MSG_TYPE_QUERY_CLIENT_INFO; +const PRUint32 ipcmMessageForward::MSG_TYPE = IPCM_MSG_TYPE_FORWARD; +const PRUint32 ipcmMessageClientStatus::MSG_TYPE = IPCM_MSG_TYPE_CLIENT_STATUS; + +// +// CLIENT_INFO message +// +// +-----------------------------------------+ +// | DWORD : MSG_TYPE | +// +--------------------+--------------------+ +// | DWORD : clientID | +// +--------------------+--------------------+ +// | DWORD : requestIndex | +// +--------------------+--------------------+ +// | WORD : nameStart | WORD : nameCount | +// +--------------------+--------------------+ +// | WORD : targetStart | WORD : targetCount | +// +--------------------+--------------------+ +// | name[0] | (null byte) | +// +--------------------+--------------------+ +// . . . +// . . . +// +--------------------+--------------------+ +// | name[count - 1] | (null byte) | +// +--------------------+--------------------+ +// | target[0] | +// +-----------------------------------------+ +// . . . +// . . . +// +-----------------------------------------+ +// | target[count - 1] | +// +-----------------------------------------+ +// + +struct ipcmClientInfoHeader +{ + PRUint32 mType; + PRUint32 mID; + PRUint32 mRequestIndex; + PRUint16 mNameStart; + PRUint16 mNameCount; + PRUint16 mTargetStart; + PRUint16 mTargetCount; +}; + +ipcmMessageClientInfo::ipcmMessageClientInfo(PRUint32 cID, PRUint32 rIdx, const char *names[], const nsID *targets[]) +{ + ipcmClientInfoHeader hdr = {0}; + + hdr.mType = MSG_TYPE; + hdr.mID = cID; + hdr.mRequestIndex = rIdx; + hdr.mNameStart = sizeof(hdr); + + PRUint32 i, namesLen = 0; + + i = 0; + while (names[i]) { + namesLen += (strlen(names[i]) + 1); + ++hdr.mNameCount; + ++i; + } + + i = 0; + while (targets[i]) { + ++hdr.mTargetCount; + ++i; + } + + // + // compute target array starting offset + // + hdr.mTargetStart = hdr.mNameStart + namesLen; + + // + // compute message length + // + PRUint32 dataLen = sizeof(hdr) + namesLen + hdr.mTargetCount * sizeof(nsID); + + Init(IPCM_TARGET, NULL, dataLen); + + // + // write message data + // + SetData(0, (const char *) &hdr, sizeof(hdr)); + + PRUint32 offset = sizeof(hdr); + + for (i = 0; names[i]; ++i) { + PRUint32 len = strlen(names[i]) + 1; + SetData(offset, names[i], len); + offset += len; + } + + for (i = 0; targets[i]; ++i) { + PRUint32 len = sizeof(nsID); + SetData(offset, (const char *) targets[i], len); + offset += len; + } +} + +PRUint32 +ipcmMessageClientInfo::ClientID() const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + return hdr->mID; +} + +PRUint32 +ipcmMessageClientInfo::RequestIndex() const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + return hdr->mRequestIndex; +} + +PRUint32 +ipcmMessageClientInfo::NameCount() const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + return hdr->mNameCount; +} + +PRUint32 +ipcmMessageClientInfo::TargetCount() const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + return hdr->mTargetCount; +} + +const char * +ipcmMessageClientInfo::NextName(const char *name) const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + + if (!name) + return (const char *) hdr + hdr->mNameStart; + + name += strlen(name) + 1; + if (name == (const char *) hdr + hdr->mTargetStart) + name = NULL; + return name; +} + +const nsID * +ipcmMessageClientInfo::NextTarget(const nsID *target) const +{ + ipcmClientInfoHeader *hdr = (ipcmClientInfoHeader *) Data(); + + if (!target) + return (const nsID *) (Data() + hdr->mTargetStart); + + if (++target == (const nsID *) (MsgBuf() + MsgLen())) + target = NULL; + return target; +} +#endif + +// +// FORWARD message +// +// +-------------------------+ +// | DWORD : MSG_TYPE | +// +-------------------------+ +// | clientID | +// +-------------------------+ +// | innerMsgHeader | +// +-------------------------+ +// | innerMsgData | +// +-------------------------+ +// + +ipcmMessageForward::ipcmMessageForward(PRUint32 type, + PRUint32 cID, + const nsID &target, + const char *data, + PRUint32 dataLen) +{ + int len = sizeof(ipcmMessageHeader) + // IPCM header + sizeof(cID) + // cID + IPC_MSG_HEADER_SIZE + // innerMsgHeader + dataLen; // innerMsgData + + Init(IPCM_TARGET, NULL, len); + + ipcmMessageHeader ipcmHdr = + { type, IPCM_NewRequestIndex() }; + + SetData(0, (char *) &ipcmHdr, sizeof(ipcmHdr)); + SetData(sizeof(ipcmHdr), (char *) &cID, sizeof(cID)); + + ipcMessageHeader hdr; + hdr.mLen = IPC_MSG_HEADER_SIZE + dataLen; + hdr.mVersion = IPC_MSG_VERSION; + hdr.mFlags = 0; + hdr.mTarget = target; + + SetData(sizeof(ipcmHdr) + sizeof(cID), (char *) &hdr, IPC_MSG_HEADER_SIZE); + if (data) + SetInnerData(0, data, dataLen); +} + +void +ipcmMessageForward::SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen) +{ + SetData(sizeof(ipcmMessageHeader) + 4 + IPC_MSG_HEADER_SIZE + offset, data, dataLen); +} + +PRUint32 +ipcmMessageForward::ClientID() const +{ + return ((PRUint32 *) Data())[2]; +} + +const nsID & +ipcmMessageForward::InnerTarget() const +{ + ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12); + return hdr->mTarget; +} + +const char * +ipcmMessageForward::InnerData() const +{ + return Data() + 12 + IPC_MSG_HEADER_SIZE; +} + +PRUint32 +ipcmMessageForward::InnerDataLen() const +{ + ipcMessageHeader *hdr = (ipcMessageHeader *) (Data() + 12); + return hdr->mLen - IPC_MSG_HEADER_SIZE; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h new file mode 100644 index 00000000..a6445654 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/shared/src/ipcm.h @@ -0,0 +1,502 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ipcm_h__ +#define ipcm_h__ + +#include "ipcMessage.h" +#include "ipcMessagePrimitives.h" + +//----------------------------------------------------------------------------- + +// +// IPCM (IPC Manager) protocol support +// + +// The IPCM message target identifier: +extern const nsID IPCM_TARGET; + +// +// Every IPCM message has the following structure: +// +// +-----------------------------------------+ +// | (ipc message header) | +// +-----------------------------------------+ +// | DWORD : type | +// +-----------------------------------------+ +// | DWORD : requestIndex | +// +-----------------------------------------+ +// . . +// . (payload) . +// . . +// +-----------------------------------------+ +// +// where |type| is an integer uniquely identifying the message. the type is +// composed of a message class identifier and a message number. there are 3 +// message classes: +// +// ACK - acknowledging a request +// REQ - making a request +// PSH - providing unrequested, "pushed" information +// +// The requestIndex field is initialized when a request is made. An +// acknowledgement's requestIndex is equal to that of its corresponding +// request message. This enables the requesting side of the message exchange +// to match acknowledgements to requests. The requestIndex field is ignored +// for PSH messages. +// + +// The IPCM message class is stored in the most significant byte. +#define IPCM_MSG_CLASS_REQ (1 << 24) +#define IPCM_MSG_CLASS_ACK (2 << 24) +#define IPCM_MSG_CLASS_PSH (4 << 24) + +// Requests +#define IPCM_MSG_REQ_PING (IPCM_MSG_CLASS_REQ | 1) +#define IPCM_MSG_REQ_FORWARD (IPCM_MSG_CLASS_REQ | 2) +#define IPCM_MSG_REQ_CLIENT_HELLO (IPCM_MSG_CLASS_REQ | 3) +#define IPCM_MSG_REQ_CLIENT_ADD_NAME (IPCM_MSG_CLASS_REQ | 4) +#define IPCM_MSG_REQ_CLIENT_DEL_NAME (IPCM_MSG_CLASS_REQ | 5) +#define IPCM_MSG_REQ_CLIENT_ADD_TARGET (IPCM_MSG_CLASS_REQ | 6) +#define IPCM_MSG_REQ_CLIENT_DEL_TARGET (IPCM_MSG_CLASS_REQ | 7) +#define IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME (IPCM_MSG_CLASS_REQ | 8) +#define IPCM_MSG_REQ_QUERY_CLIENT_NAMES (IPCM_MSG_CLASS_REQ | 9) // TODO +#define IPCM_MSG_REQ_QUERY_CLIENT_TARGETS (IPCM_MSG_CLASS_REQ | 10) // TODO + +// Acknowledgements +#define IPCM_MSG_ACK_RESULT (IPCM_MSG_CLASS_ACK | 1) +#define IPCM_MSG_ACK_CLIENT_ID (IPCM_MSG_CLASS_ACK | 2) +#define IPCM_MSG_ACK_CLIENT_NAMES (IPCM_MSG_CLASS_ACK | 3) // TODO +#define IPCM_MSG_ACK_CLIENT_TARGETS (IPCM_MSG_CLASS_ACK | 4) // TODO + +// Push messages +#define IPCM_MSG_PSH_CLIENT_STATE (IPCM_MSG_CLASS_PSH | 1) +#define IPCM_MSG_PSH_FORWARD (IPCM_MSG_CLASS_PSH | 2) + +//----------------------------------------------------------------------------- + +// +// IPCM header +// +struct ipcmMessageHeader +{ + PRUint32 mType; + PRUint32 mRequestIndex; +}; + +// +// returns IPCM message type. +// +static inline int +IPCM_GetType(const ipcMessage *msg) +{ + return ((const ipcmMessageHeader *) msg->Data())->mType; +} + +// +// return IPCM message request index. +// +static inline PRUint32 +IPCM_GetRequestIndex(const ipcMessage *msg) +{ + return ((const ipcmMessageHeader *) msg->Data())->mRequestIndex; +} + +// +// return a request index that is unique to this process. +// +NS_HIDDEN_(PRUint32) +IPCM_NewRequestIndex(); + +//----------------------------------------------------------------------------- + +// +// The IPCM protocol is detailed below: +// + +// REQUESTS + +// +// req: IPCM_MSG_REQ_PING +// ack: IPCM_MSG_ACK_RESULT +// +// A PING can be sent from either a client to the daemon, or from the daemon +// to a client. The expected acknowledgement is a RESULT message with a status +// code of 0. +// +// This request message has no payload. +// + +// +// req: IPCM_MSG_REQ_FORWARD +// ack: IPCM_MSG_ACK_RESULT +// +// A FORWARD is sent when a client wishes to send a message to another client. +// The payload of this message is another message that should be forwarded by +// the daemon's IPCM to the specified client. The expected acknowledgment is +// a RESULT message with a status code indicating success or failure. +// +// When the daemon receives a FORWARD message, it creates a PSH_FORWARD message +// and sends that on to the destination client. +// +// This request message has as its payload: +// +// +-----------------------------------------+ +// | DWORD : clientID | +// +-----------------------------------------+ +// | (innerMsgHeader) | +// +-----------------------------------------+ +// | (innerMsgData) | +// +-----------------------------------------+ +// + +// +// req: IPCM_MSG_REQ_CLIENT_HELLO +// ack: IPCM_MSG_REQ_CLIENT_ID IPCM_MSG_REQ_RESULT +// +// A CLIENT_HELLO is sent when a client connects to the IPC daemon. The +// expected acknowledgement is a CLIENT_ID message informing the new client of +// its ClientID. If for some reason the IPC daemon cannot accept the new +// client, it returns a RESULT message with a failure status code. +// +// This request message has no payload. +// + +// +// req: IPCM_MSG_REQ_CLIENT_ADD_NAME +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_ADD_NAME is sent when a client wishes to register an additional +// name for itself. The expected acknowledgement is a RESULT message with a +// status code indicating success or failure. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the name of the client. +// + +// +// req: IPCM_MSG_REQ_CLIENT_DEL_NAME +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_DEL_NAME is sent when a client wishes to unregister a name that it +// has registered. The expected acknowledgement is a RESULT message with a +// status code indicating success or failure. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the name of the client. +// + +// +// req: IPCM_MSG_REQ_CLIENT_ADD_TARGET +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_ADD_TARGET is sent when a client wishes to register an additional +// target that it supports. The expected acknowledgement is a RESULT message +// with a status code indicating success or failure. +// +// This request message has as its payload a 128-bit UUID indicating the +// target to add. +// + +// +// req: IPCM_MSG_REQ_CLIENT_DEL_TARGET +// ack: IPCM_MSG_ACK_RESULT +// +// A CLIENT_DEL_TARGET is sent when a client wishes to unregister a target +// that it has registered. The expected acknowledgement is a RESULT message +// with a status code indicating success or failure. +// +// This request message has as its payload a 128-bit UUID indicating the +// target to remove. +// + +// +// req: IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME +// ack: IPCM_MSG_ACK_CLIENT_ID IPCM_MSG_ACK_RESULT +// +// A QUERY_CLIENT_BY_NAME may be sent by a client to discover the client that +// is known by a common name. If more than one client matches the name, then +// only the ID of the more recently registered client is returned. The +// expected acknowledgement is a CLIENT_ID message carrying the ID of the +// corresponding client. If no client matches the given name or if some error +// occurs, then a RESULT message with a failure status code is returned. +// +// This request message has as its payload a null-terminated ASCII character +// string indicating the client name to query. +// + +// ACKNOWLEDGEMENTS + +// +// ack: IPCM_MSG_ACK_RESULT +// +// This acknowledgement is returned to indicate a success or failure status. +// +// The payload consists of a single DWORD value. +// +// Possible status codes are listed below (negative values indicate failure +// codes): +// +#define IPCM_OK 0 // success: generic +#define IPCM_ERROR_GENERIC -1 // failure: generic +#define IPCM_ERROR_NO_CLIENT -2 // failure: client does not exist +#define IPCM_ERROR_INVALID_ARG -3 // failure: invalid request argument +#define IPCM_ERROR_NO_SUCH_DATA -4 // failure: requested data does not exist +#define IPCM_ERROR_ALREADY_EXISTS -5 // failure: data to set already exists + +// +// ack: IPCM_MSG_ACK_CLIENT_ID +// +// This acknowledgement is returned to specify a client ID. +// +// The payload consists of a single DWORD value. +// + +// PUSH MESSAGES + +// +// psh: ICPM_MSG_PSH_CLIENT_STATE +// +// This message is sent to clients to indicate the status of other clients. +// +// The payload consists of: +// +// +-----------------------------------------+ +// | DWORD : clientID | +// +-----------------------------------------+ +// | DWORD : clientState | +// +-----------------------------------------+ +// +// where, clientState is one of the following values indicating whether the +// client has recently connected (up) or disconnected (down): +// +#define IPCM_CLIENT_STATE_UP 1 +#define IPCM_CLIENT_STATE_DOWN 2 + +// +// psh: IPCM_MSG_PSH_FORWARD +// +// This message is sent by the daemon to a client on behalf of another client. +// The recipient is expected to unpack the contained message and process it. +// +// The payload of this message matches the payload of IPCM_MSG_REQ_FORWARD, +// with the exception that the clientID field is set to the clientID of the +// sender of the IPCM_MSG_REQ_FORWARD message. +// + +//----------------------------------------------------------------------------- + +// +// NOTE: This file declares some helper classes that simplify constructing +// and parsing IPCM messages. Each class subclasses ipcMessage, but +// adds no additional member variables. |operator new| should be used +// to allocate one of the IPCM helper classes, e.g.: +// +// ipcMessage *msg = new ipcmMessageClientHello("foo"); +// +// Given an arbitrary ipcMessage, it can be parsed using logic similar +// to the following: +// +// void func(const ipcMessage *unknown) +// { +// if (unknown->Topic().Equals(IPCM_TARGET)) { +// if (IPCM_GetMsgType(unknown) == IPCM_MSG_TYPE_CLIENT_ID) { +// ipcMessageCast msg(unknown); +// printf("Client ID: %u\n", msg->ClientID()); +// } +// } +// } +// + +// REQUESTS + +class ipcmMessagePing : public ipcMessage_DWORD_DWORD +{ +public: + ipcmMessagePing() + : ipcMessage_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_REQ_PING, + IPCM_NewRequestIndex()) {} +}; + +class ipcmMessageForward : public ipcMessage +{ +public: + // @param type the type of this message: IPCM_MSG_{REQ,PSH}_FORWARD + // @param clientID the client id of the sender or receiver + // @param target the message target + // @param data the message data + // @param dataLen the message data length + ipcmMessageForward(PRUint32 type, + PRUint32 clientID, + const nsID &target, + const char *data, + PRUint32 dataLen) NS_HIDDEN; + + // set inner message data, constrained to the data length passed + // to this class's constructor. + NS_HIDDEN_(void) SetInnerData(PRUint32 offset, const char *data, PRUint32 dataLen); + + NS_HIDDEN_(PRUint32) ClientID() const; + NS_HIDDEN_(const nsID &) InnerTarget() const; + NS_HIDDEN_(const char *) InnerData() const; + NS_HIDDEN_(PRUint32) InnerDataLen() const; +}; + +class ipcmMessageClientHello : public ipcMessage_DWORD_DWORD +{ +public: + ipcmMessageClientHello() + : ipcMessage_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_HELLO, + IPCM_NewRequestIndex()) {} +}; + +class ipcmMessageClientAddName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageClientAddName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } +}; + +class ipcmMessageClientDelName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageClientDelName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_DEL_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } +}; + +class ipcmMessageClientAddTarget : public ipcMessage_DWORD_DWORD_ID +{ +public: + ipcmMessageClientAddTarget(const nsID &target) + : ipcMessage_DWORD_DWORD_ID( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_TARGET, + IPCM_NewRequestIndex(), + target) {} + + const nsID &Target() const { return Third(); } +}; + +class ipcmMessageClientDelTarget : public ipcMessage_DWORD_DWORD_ID +{ +public: + ipcmMessageClientDelTarget(const nsID &target) + : ipcMessage_DWORD_DWORD_ID( + IPCM_TARGET, + IPCM_MSG_REQ_CLIENT_ADD_TARGET, + IPCM_NewRequestIndex(), + target) {} + + const nsID &Target() const { return Third(); } +}; + +class ipcmMessageQueryClientByName : public ipcMessage_DWORD_DWORD_STR +{ +public: + ipcmMessageQueryClientByName(const char *name) + : ipcMessage_DWORD_DWORD_STR( + IPCM_TARGET, + IPCM_MSG_REQ_QUERY_CLIENT_BY_NAME, + IPCM_NewRequestIndex(), + name) {} + + const char *Name() const { return Third(); } + PRUint32 RequestIndex() const { return Second(); } +}; + +// ACKNOWLEDGEMENTS + +class ipcmMessageResult : public ipcMessage_DWORD_DWORD_DWORD +{ +public: + ipcmMessageResult(PRUint32 requestIndex, PRInt32 status) + : ipcMessage_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_ACK_RESULT, + requestIndex, + (PRUint32) status) {} + + PRInt32 Status() const { return (PRInt32) Third(); } +}; + +class ipcmMessageClientID : public ipcMessage_DWORD_DWORD_DWORD +{ +public: + ipcmMessageClientID(PRUint32 requestIndex, PRUint32 clientID) + : ipcMessage_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_ACK_CLIENT_ID, + requestIndex, + clientID) {} + + PRUint32 ClientID() const { return Third(); } +}; + +// PUSH MESSAGES + +class ipcmMessageClientState : public ipcMessage_DWORD_DWORD_DWORD_DWORD +{ +public: + ipcmMessageClientState(PRUint32 clientID, PRUint32 clientStatus) + : ipcMessage_DWORD_DWORD_DWORD_DWORD( + IPCM_TARGET, + IPCM_MSG_PSH_CLIENT_STATE, + 0, + clientID, + clientStatus) {} + + PRUint32 ClientID() const { return Third(); } + PRUint32 ClientState() const { return Fourth(); } +}; + +#endif // !ipcm_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore new file mode 100644 index 00000000..d1a44d27 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestIPC diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in new file mode 100644 index 00000000..bad636f3 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/Makefile.in @@ -0,0 +1,69 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = module + +MODULE = ipcd_test +REQUIRES = \ + xpcom \ + string \ + ipcd \ + $(NULL) + +CPPSRCS = \ + TestIPC.cpp \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS = \ + $(EXTRA_DSO_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp b/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp new file mode 100644 index 00000000..1100d674 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/TestIPC.cpp @@ -0,0 +1,338 @@ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "ipcIService.h" +#include "ipcIMessageObserver.h" +#include "ipcILockService.h" +#include "ipcCID.h" +#include "ipcLockCID.h" + +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" + +#include "nsString.h" +#include "prmem.h" + +static const nsID kIPCMTargetID = +{ /* 753ca8ff-c8c2-4601-b115-8c2944da1150 */ + 0x753ca8ff, + 0xc8c2, + 0x4601, + {0xb1, 0x15, 0x8c, 0x29, 0x44, 0xda, 0x11, 0x50} +}; + +static const nsID kTestTargetID = +{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ + 0xe628fc6e, + 0xa6a7, + 0x48c7, + {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} +}; + +#define RETURN_IF_FAILED(rv, step) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + printf("*** %s failed: rv=%x\n", step, rv); \ + return rv;\ + } \ + PR_END_MACRO + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static nsIEventQueue* gEventQ = nsnull; +static PRBool gKeepRunning = PR_TRUE; +static ipcIService *gIpcServ = nsnull; +static ipcILockService *gIpcLockServ = nsnull; + +static void +SendMsg(ipcIService *ipc, PRUint32 cID, const nsID &target, const char *data, PRUint32 dataLen, PRBool sync = PR_FALSE) +{ + printf("*** sending message: [to-client=%u dataLen=%u]\n", cID, dataLen); + + nsresult rv; + + rv = ipc->SendMessage(cID, target, (const PRUint8 *) data, dataLen); + if (NS_FAILED(rv)) { + printf("*** sending message failed: rv=%x\n", rv); + return; + } + + if (sync) { + rv = ipc->WaitMessage(cID, target, nsnull, PR_UINT32_MAX); + if (NS_FAILED(rv)) + printf("*** waiting for message failed: rv=%x\n", rv); + } +} + +//----------------------------------------------------------------------------- + +class myIpcMessageObserver : public ipcIMessageObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCIMESSAGEOBSERVER +}; +NS_IMPL_ISUPPORTS1(myIpcMessageObserver, ipcIMessageObserver) + +NS_IMETHODIMP +myIpcMessageObserver::OnMessageAvailable(PRUint32 sender, const nsID &target, const PRUint8 *data, PRUint32 dataLen) +{ + printf("*** got message: [sender=%u data=%s]\n", sender, (const char *) data); + return NS_OK; +} + +//----------------------------------------------------------------------------- + +#if 0 +class myIpcClientQueryHandler : public ipcIClientQueryHandler +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCICLIENTQUERYHANDLER +}; + +NS_IMPL_ISUPPORTS1(myIpcClientQueryHandler, ipcIClientQueryHandler) + +NS_IMETHODIMP +myIpcClientQueryHandler::OnQueryComplete(PRUint32 aQueryID, + nsresult aStatus, + PRUint32 aClientID, + const char **aNames, + PRUint32 aNameCount, + const nsID **aTargets, + PRUint32 aTargetCount) +{ + printf("*** query complete [queryID=%u status=0x%x clientID=%u]\n", + aQueryID, aStatus, aClientID); + + PRUint32 i; + printf("*** names:\n"); + for (i = 0; i < aNameCount; ++i) + printf("*** %d={%s}\n", i, aNames[i]); + printf("*** targets:\n"); + for (i = 0; i < aTargetCount; ++i) { + const char *trailer; + if (aTargets[i]->Equals(kTestTargetID)) + trailer = " (TEST_TARGET_ID)"; + else if (aTargets[i]->Equals(kIPCMTargetID)) + trailer = " (IPCM_TARGET_ID)"; + else + trailer = " (unknown)"; + char *str = aTargets[i]->ToString(); + printf("*** %d=%s%s\n", i, str, trailer); + PR_Free(str); + } + + if (aClientID != 0) { + const char hello[] = "hello friend!"; + SendMsg(gIpcServ, aClientID, kTestTargetID, hello, sizeof(hello)); + } + + return NS_OK; +} +#endif + +//----------------------------------------------------------------------------- + +#if 0 +class myIpcLockNotify : public ipcILockNotify +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_IPCILOCKNOTIFY +}; + +NS_IMPL_ISUPPORTS1(myIpcLockNotify, ipcILockNotify) + +NS_IMETHODIMP +myIpcLockNotify::OnAcquireLockComplete(const char *lockName, nsresult status) +{ + printf("*** OnAcquireLockComplete [lock=%s status=%x]\n", lockName, status); + gIpcLockServ->ReleaseLock(lockName); + return NS_OK; +} +#endif + +//----------------------------------------------------------------------------- + +int main(int argc, char **argv) +{ + nsresult rv; + + { + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + // Create the Event Queue for this thread... + nsCOMPtr eqs = + do_GetService(kEventQueueServiceCID, &rv); + RETURN_IF_FAILED(rv, "do_GetService(EventQueueService)"); + + rv = eqs->CreateMonitoredThreadEventQueue(); + RETURN_IF_FAILED(rv, "CreateMonitoredThreadEventQueue"); + + rv = eqs->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); + RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + + printf("*** getting ipc service\n"); + nsCOMPtr ipcServ(do_GetService(IPC_SERVICE_CONTRACTID, &rv)); + RETURN_IF_FAILED(rv, "do_GetService(ipcServ)"); + NS_ADDREF(gIpcServ = ipcServ); + + if (argc > 1) { + printf("*** using client name [%s]\n", argv[1]); + gIpcServ->AddName(argv[1]); + } + + ipcServ->DefineTarget(kTestTargetID, new myIpcMessageObserver(), PR_TRUE); + + const char data[] = + "01 this is a really long message.\n" + "02 this is a really long message.\n" + "03 this is a really long message.\n" + "04 this is a really long message.\n" + "05 this is a really long message.\n" + "06 this is a really long message.\n" + "07 this is a really long message.\n" + "08 this is a really long message.\n" + "09 this is a really long message.\n" + "10 this is a really long message.\n" + "11 this is a really long message.\n" + "12 this is a really long message.\n" + "13 this is a really long message.\n" + "14 this is a really long message.\n" + "15 this is a really long message.\n" + "16 this is a really long message.\n" + "17 this is a really long message.\n" + "18 this is a really long message.\n" + "19 this is a really long message.\n" + "20 this is a really long message.\n" + "21 this is a really long message.\n" + "22 this is a really long message.\n" + "23 this is a really long message.\n" + "24 this is a really long message.\n" + "25 this is a really long message.\n" + "26 this is a really long message.\n" + "27 this is a really long message.\n" + "28 this is a really long message.\n" + "29 this is a really long message.\n" + "30 this is a really long message.\n" + "31 this is a really long message.\n" + "32 this is a really long message.\n" + "33 this is a really long message.\n" + "34 this is a really long message.\n" + "35 this is a really long message.\n" + "36 this is a really long message.\n" + "37 this is a really long message.\n" + "38 this is a really long message.\n" + "39 this is a really long message.\n" + "40 this is a really long message.\n" + "41 this is a really long message.\n" + "42 this is a really long message.\n" + "43 this is a really long message.\n" + "44 this is a really long message.\n" + "45 this is a really long message.\n" + "46 this is a really long message.\n" + "47 this is a really long message.\n" + "48 this is a really long message.\n" + "49 this is a really long message.\n" + "50 this is a really long message.\n" + "51 this is a really long message.\n" + "52 this is a really long message.\n" + "53 this is a really long message.\n" + "54 this is a really long message.\n" + "55 this is a really long message.\n" + "56 this is a really long message.\n" + "57 this is a really long message.\n" + "58 this is a really long message.\n" + "59 this is a really long message.\n" + "60 this is a really long message.\n"; + SendMsg(ipcServ, 0, kTestTargetID, data, sizeof(data), PR_TRUE); + +// PRUint32 queryID; +// nsCOMPtr handler(new myIpcClientQueryHandler()); +// ipcServ->QueryClientByName("foopy", handler, PR_FALSE, &queryID); + + PRUint32 foopyID; + nsresult foopyRv = ipcServ->ResolveClientName("foopy", &foopyID); + printf("*** query for 'foopy' returned [rv=%x id=%u]\n", foopyRv, foopyID); + + if (NS_SUCCEEDED(foopyRv)) { + const char hello[] = "hello friend!"; + SendMsg(ipcServ, foopyID, kTestTargetID, hello, sizeof(hello)); + } + + // + // test lock service + // + nsCOMPtr lockService = do_GetService(IPC_LOCKSERVICE_CONTRACTID, &rv); + RETURN_IF_FAILED(rv, "do_GetService(ipcLockServ)"); + NS_ADDREF(gIpcLockServ = lockService); + + //nsCOMPtr notify(new myIpcLockNotify()); + gIpcLockServ->AcquireLock("blah", PR_TRUE); + + rv = gIpcLockServ->AcquireLock("foo", PR_TRUE); + printf("*** sync AcquireLock returned [rv=%x]\n", rv); + + PLEvent *ev; + while (gKeepRunning) { + gEventQ->WaitForEvent(&ev); + gEventQ->HandleEvent(ev); + } + + NS_RELEASE(gIpcServ); + + printf("*** processing remaining events\n"); + + // process any remaining events + while (NS_SUCCEEDED(gEventQ->GetEvent(&ev)) && ev) + gEventQ->HandleEvent(ev); + + printf("*** done\n"); + } // this scopes the nsCOMPtrs + + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + + return 0; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in new file mode 100644 index 00000000..aec7c169 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/Makefile.in @@ -0,0 +1,81 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Darin Fisher +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd_test +LIBRARY_NAME = testmodule +SHORT_LIBNAME = testmod +MODULE_NAME = ipcd_test + +FORCE_SHARED_LIB = 1 +NO_DIST_INSTALL = 1 + +REQUIRES = \ + xpcom \ + ipcd \ + $(NULL) + +CPPSRCS = TestModule.cpp + +LOCAL_INCLUDES = \ + -I$(srcdir)/../common \ + $(NULL) + +EXTRA_DSO_LDOPTS = \ + $(LIBS_DIR) \ + $(NSPR_LIBS) \ + $(EXTRA_DSO_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +_IPC_FILES = \ + $(DLL_PREFIX)$(LIBRARY_NAME)$(DLL_SUFFIX) \ + $(NULL) + +libs:: $(_IPC_FILES) + $(INSTALL) $^ $(DIST)/bin/ipc/modules + +install:: $(_IPC_FILES) + $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/ipc/modules diff --git a/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp b/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp new file mode 100644 index 00000000..fbd78867 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/test/module/TestModule.cpp @@ -0,0 +1,62 @@ +#include +#include "ipcModuleUtil.h" + +#define TEST_MODULE_ID \ +{ /* e628fc6e-a6a7-48c7-adba-f241d1128fb8 */ \ + 0xe628fc6e, \ + 0xa6a7, \ + 0x48c7, \ + {0xad, 0xba, 0xf2, 0x41, 0xd1, 0x12, 0x8f, 0xb8} \ +} +static const nsID kTestModuleID = TEST_MODULE_ID; + +struct TestModule +{ + static void Init() + { + printf("*** TestModule::Init\n"); + } + + static void Shutdown() + { + printf("*** TestModule::Shutdown\n"); + } + + static void HandleMsg(ipcClientHandle client, + const nsID &target, + const void *data, + PRUint32 dataLen) + { + printf("*** TestModule::HandleMsg [%s]\n", (const char *) data); + + static const char buf[] = "pong"; + IPC_SendMsg(client, kTestModuleID, buf, sizeof(buf)); + } + + static void ClientUp(ipcClientHandle client) + { + printf("*** TestModule::ClientUp [%u]\n", IPC_GetClientID(client)); + } + + static void ClientDown(ipcClientHandle client) + { + printf("*** TestModule::ClientDown [%u]\n", IPC_GetClientID(client)); + } +}; + +static ipcModuleMethods gTestMethods = +{ + IPC_MODULE_METHODS_VERSION, + TestModule::Init, + TestModule::Shutdown, + TestModule::HandleMsg, + TestModule::ClientUp, + TestModule::ClientDown +}; + +static ipcModuleEntry gTestModuleEntry[] = +{ + { TEST_MODULE_ID, &gTestMethods } +}; + +IPC_IMPL_GETMODULES(TestModule, gTestModuleEntry) diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in new file mode 100644 index 00000000..323f87f8 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/Makefile.in @@ -0,0 +1,49 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Conrad Carlen +# +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +DIRS = public src + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in new file mode 100644 index 00000000..84d980c4 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/Makefile.in @@ -0,0 +1,53 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Conrad Carlen +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd + +EXPORTS = \ + ipcMessageReader.h \ + ipcMessageWriter.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h new file mode 100644 index 00000000..f93bfa20 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageReader.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 ipcMessageReader_h__ +#define ipcMessageReader_h__ + +#include "prtypes.h" + +//***************************************************************************** +// ipcMessageReader +// +// Reads from a const buffer supplied to it. Does not take ownership of the +// buffer. Bytes are read in native endianess, as ipcMessageWriter writes them +// in native endianess. +//***************************************************************************** + +class ipcMessageReader +{ +public: + ipcMessageReader(const PRUint8* inBuffer, PRUint32 bufferSize) : + mBuf(inBuffer), mBufEnd(inBuffer + bufferSize), + mBufPtr(mBuf), + mError(PR_FALSE) + { } + + ~ipcMessageReader() + { } + + // Returns PR_TRUE if an error has occured at any point + // during the lifetime of this object. Any read operation + // will safely return 0 on an error condition. + PRBool HasError() + { return mError; } + + PRUint8 GetInt8(); + PRUint16 GetInt16(); + PRUint32 GetInt32(); + PRInt32 GetBytes(void* destBuffer, PRInt32 n); + + // Returns data at the current read position. + const PRUint8* GetPtr() + { return mBufPtr; } + + // Returns PR_TRUE if the new position is within the buffer. + // Returns PR_FALSE and sets error state if not. + PRBool AdvancePtr(PRInt32 n); + +private: + const PRUint8 *mBuf, *mBufEnd; + const PRUint8 *mBufPtr; + PRBool mError; +}; + +#endif // ipcMessageReader_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h new file mode 100644 index 00000000..8e0a8178 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/public/ipcMessageWriter.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 ipcMessageWriter_h__ +#define ipcMessageWriter_h__ + +#include "prtypes.h" + +//***************************************************************************** +// ipcMessageWriter +// +// Creates a block of memory and resizes it in order to hold writes. The +// block will be freed when this object is destroyed. Bytes are written in +// native endianess, as ipcMessageReader reads them in native endianess. +//***************************************************************************** + +class ipcMessageWriter +{ +public: + ipcMessageWriter(PRUint32 initialCapacity) : + mBuf(NULL), + mBufPtr(NULL), mBufEnd(NULL), + mCapacity(0), + mError(PR_FALSE) + { + EnsureCapacity(initialCapacity); + } + + ~ipcMessageWriter(); + + // Returns PR_TRUE if an error has occured at any point + // during the lifetime of this object, due to the buffer + // not being able to be grown to the required size. + PRBool HasError() + { return mError; } + + void PutInt8(PRUint8 val); + void PutInt16(PRUint16 val); + void PutInt32(PRUint32 val); + PRUint32 PutBytes(const void* src, PRUint32 n); + + // Returns the beginning of the buffer. Do not free this. + PRUint8* GetBuffer() + { return mBuf; } + + PRInt32 GetSize() + { return mBufPtr - mBuf; } + +private: + PRBool EnsureCapacity(PRInt32 sizeNeeded) + { + return (mBuf && ((mBufPtr + sizeNeeded) <= mBufEnd)) ? + PR_TRUE : GrowCapacity(sizeNeeded); + } + PRBool GrowCapacity(PRInt32 sizeNeeded); + +private: + PRUint8 *mBuf; + PRUint8 *mBufPtr, *mBufEnd; + PRInt32 mCapacity; + PRBool mError; +}; + +#endif // ipcMessageWriter_h__ diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore b/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in b/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in new file mode 100644 index 00000000..6ebca736 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/Makefile.in @@ -0,0 +1,56 @@ +# vim: noexpandtab ts=4 sw=4 +# ***** 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 Mozilla IPC. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Conrad Carlen +# +# 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = ipcd +LIBRARY_NAME = ipcdutil_s +FORCE_STATIC_LIB = 1 +MODULE_NAME = ipcd + + +CPPSRCS = \ + ipcMessageReader.cpp \ + ipcMessageWriter.cpp + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp new file mode 100644 index 00000000..87279df2 --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageReader.cpp @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 "ipcMessageReader.h" +#include + +//***************************************************************************** +// ipcMessageReader +//***************************************************************************** + +PRUint8 ipcMessageReader::GetInt8() +{ + if (mBufPtr < mBufEnd) + return *mBufPtr++; + mError = PR_TRUE; + return 0; +} + +// GetInt16 and GetInt32 go to pains to avoid unaligned memory accesses that +// are larger than a byte. On some platforms, that causes a performance penalty. +// On other platforms, Tru64 for instance, it's an error. + +PRUint16 ipcMessageReader::GetInt16() +{ + if (mBufPtr + sizeof(PRUint16) <= mBufEnd) { + PRUint8 temp[2] = { mBufPtr[0], mBufPtr[1] }; + mBufPtr += sizeof(PRUint16); + return *(PRUint16*)temp; + } + mError = PR_TRUE; + return 0; +} + +PRUint32 ipcMessageReader::GetInt32() +{ + if (mBufPtr + sizeof(PRUint32) <= mBufEnd) { + PRUint8 temp[4] = { mBufPtr[0], mBufPtr[1], mBufPtr[2], mBufPtr[3] }; + mBufPtr += sizeof(PRUint32); + return *(PRUint32*)temp; + } + mError = PR_TRUE; + return 0; +} + +PRInt32 ipcMessageReader::GetBytes(void* destBuffer, PRInt32 n) +{ + if (mBufPtr + n <= mBufEnd) { + memcpy(destBuffer, mBufPtr, n); + mBufPtr += n; + return n; + } + mError = PR_TRUE; + return 0; +} + +PRBool ipcMessageReader::AdvancePtr(PRInt32 n) +{ + const PRUint8 *newPtr = mBufPtr + n; + if (newPtr >= mBuf && newPtr <= mBufEnd) { + mBufPtr = newPtr; + return PR_TRUE; + } + mError = PR_TRUE; + return PR_FALSE; +} diff --git a/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp new file mode 100644 index 00000000..4af0dcba --- /dev/null +++ b/src/libs/xpcom18a4/ipc/ipcd/util/src/ipcMessageWriter.cpp @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla IPC. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 "ipcMessageWriter.h" +#include "prmem.h" +#include +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +//***************************************************************************** +// ipcMessageWriter +//***************************************************************************** + +ipcMessageWriter::~ipcMessageWriter() +{ + if (mBuf) +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mBuf); +#else + free(mBuf); +#endif +} + +void ipcMessageWriter::PutInt8(PRUint8 val) +{ + if (EnsureCapacity(sizeof(PRUint8))) + *mBufPtr++ = val; +} + +// PutInt16 and PutInt32 go to pains to avoid unaligned memory accesses that +// are larger than a byte. On some platforms, that causes a performance penalty. +// On other platforms, Tru64 for instance, it's an error. + +void ipcMessageWriter::PutInt16(PRUint16 val) +{ + if (EnsureCapacity(sizeof(PRUint16))) { + PRUint8 temp[2]; + *(PRUint16*)temp = val; + *mBufPtr++ = temp[0]; + *mBufPtr++ = temp[1]; + } +} + +void ipcMessageWriter::PutInt32(PRUint32 val) +{ + if (EnsureCapacity(sizeof(PRUint32))) { + PRUint8 temp[4]; + *(PRUint32*)temp = val; + *mBufPtr++ = temp[0]; + *mBufPtr++ = temp[1]; + *mBufPtr++ = temp[2]; + *mBufPtr++ = temp[3]; + } +} + +PRUint32 ipcMessageWriter::PutBytes(const void* src, PRUint32 n) +{ + if (EnsureCapacity(n)) { + memcpy(mBufPtr, src, n); + mBufPtr += n; + return n; + } + return 0; +} + +PRBool ipcMessageWriter::GrowCapacity(PRInt32 sizeNeeded) +{ + if (sizeNeeded < 0) + return PR_FALSE; + PRInt32 newCapacity = (mBufPtr - mBuf) + sizeNeeded; + if (mCapacity == 0) + mCapacity = newCapacity; + else + { + while (newCapacity > mCapacity && (mCapacity << 1) > 0) + mCapacity <<= 1; + if (newCapacity > mCapacity) // if we broke out because of rollover + return PR_FALSE; + } + + PRInt32 curPos = mBufPtr - mBuf; +#ifdef VBOX_USE_IPRT_IN_XPCOM + mBuf = (PRUint8*)RTMemRealloc(mBuf, mCapacity); +#else + mBuf = (PRUint8*)realloc(mBuf, mCapacity); +#endif + if (!mBuf) { + mError = PR_TRUE; + return PR_FALSE; + } + mBufPtr = mBuf + curPos; + mBufEnd = mBuf + mCapacity; + return PR_TRUE; +} diff --git a/src/libs/xpcom18a4/java/Makefile.kmk b/src/libs/xpcom18a4/java/Makefile.kmk new file mode 100644 index 00000000..56c34c95 --- /dev/null +++ b/src/libs/xpcom18a4/java/Makefile.kmk @@ -0,0 +1,233 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Java bindings +# + +# +# Copyright (C) 2010-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# +# Globals +# +VBOX_JXPCOM_SRC := $(PATH_SUB_CURRENT) + +VBOX_JXPCOM_TARGET := $(PATH_TARGET)/vboxjxpcom-gen +VBOX_JXPCOM_JDEST := $(VBOX_JXPCOM_TARGET)/jdest + +VBOX_GLUE_XSLT_DIR := $(PATH_ROOT)/src/VBox/Main/glue + +ifndef VBOX_ONLY_SDK +# +# VBoxJXpcom - Java<->XPCOM native library +# +DLLS += VBoxJXpcom + +VBoxJXpcom_TEMPLATE = XPCOM +VBoxJXpcom_CXXFLAGS = -Wno-write-strings +VBoxJXpcom_DEFS = \ + EXPORT_XPTI_API \ + EXPORT_XPT_API \ + VBOX_WITH_XPCOM +VBoxJXpcom_NAME = libvboxjxpcom +VBoxJXpcom_DLLSUFF.darwin = .jnilib +VBoxJXpcom_INCS = \ + src \ + $(VBOX_JAVA_INC) \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/glue \ + $(VBOX_PATH_XPCOM_SRC)/xpcom/build \ + $(VBOX_JXPCOM_JDEST) +VBoxJXpcom_SOURCES = \ + src/nsAppFileLocProviderProxy.cpp \ + src/nsJavaWrapper.cpp \ + src/nsJavaXPCOMBindingUtils.cpp \ + src/nsJavaXPTCStub.cpp \ + src/nsJavaXPTCStubWeakRef.cpp \ + src/nsJavaXPCOMGlue.cpp \ + src/nsJavaInterfaces.cpp +VBoxJXpcom_LIBS = \ + $(PATH_STAGE_LIB)/VBoxCOM$(VBOX_SUFF_LIB) \ + $(PATH_STAGE_BIN)/VBoxXPCOM$(VBOX_SUFF_DLL) + +#VBoxJXpcom_ORDERDEPS = $(VBOX_JXPCOM_GENH) +#VBoxJXpcom_CLEAN = $(VBOX_JXPCOM_GENH) +VBOX_JXPCOM_GENH = \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_XPCOMImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_GREImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_MozillaImpl.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_XPCOMJavaProxy.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_internal_JavaXPCOMMethods.h \ + $(VBOX_JXPCOM_JDEST)/org_mozilla_xpcom_ProfileLock.h + + +else # VBOX_ONLY_SDK +# Nothing yet +endif # VBOX_ONLY_SDK + +# +# Install JAR files +# +INSTALLS += VBoxJXpcom-inst-jar + +VBOX_JXPCOM_JAR = $(VBoxJXpcom-inst-jar_0_OUTDIR)/vboxjxpcom.jar +VBOX_JXPCOM_NSERROR = $(VBOX_JXPCOM_GEN)/java/XPCOMError.java +ifndef VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +VBOX_JXPCOM_GEN = $(VBOX_JXPCOM_TARGET)/jxpcomgen +else +VBOX_JXPCOM_GEN = $(VBOX_JXPCOM_TARGET)/jxpcomgen-idl +endif + +VBoxJXpcom-inst-jar_INST = $(INST_SDK)bindings/xpcom/java/ +VBoxJXpcom-inst-jar_MODE = a+r,u+w +VBoxJXpcom-inst-jar_SOURCES = \ + $(VBOX_JXPCOM_JAR) +VBoxJXpcom-inst-jar_CLEAN = \ + $(VBOX_JXPCOM_JAR) \ + $(VBOX_JXPCOM_NSERROR) \ + $(VBOX_JXPCOM_GEN)/jxpcomgen.list \ + $(VBOX_JXPCOM_GEN)/jxpcomglue.list \ + $(wildcard \ + $(VBOX_JXPCOM_GEN)/java/*.java \ + $(VBOX_JXPCOM_GEN)/java/glue/*.java \ + $(VBOX_JXPCOM_JDEST)/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*/*.class \ + $(VBOX_JXPCOM_JDEST)/*/*/*/*/*/*.class \ + ) +VBoxJXpcom-inst-jar_BLDDIRS += $(VBOX_JXPCOM_GEN)/java $(VBOX_JXPCOM_GEN)/java/glue $(VBOX_JXPCOM_GEN)/java/interfaces + +# +# For VBoxJXpcom, not currently used. +# +$(VBOX_JXPCOM_GENH): $$(VBOX_JXPCOM_JAR) + $(call MSG_L1,Generating $@ from $<) + $(QUIET)$(VBOX_JAVAH) -classpath $(VBOX_JXPCOM_JDEST) -d $(VBOX_JXPCOM_JDEST) \ + org.mozilla.xpcom.internal.XPCOMImpl \ + org.mozilla.xpcom.internal.GREImpl \ + org.mozilla.xpcom.internal.MozillaImpl \ + org.mozilla.xpcom.internal.XPCOMJavaProxy \ + org.mozilla.xpcom.ProfileLock \ + org.mozilla.xpcom.internal.JavaXPCOMMethods + +# +# Generate error constants. +# +$(VBOX_JXPCOM_NSERROR): $(VBOX_PATH_XPCOM_SRC)/xpcom/base/nsError.h $(VBOX_JXPCOM_SRC)/tools/gen-nsError.pl | $(VBOX_JXPCOM_GEN)/java/ + $(call MSG_L1,Generating $@) + $(QUIET)perl $(VBOX_JXPCOM_SRC)/tools/gen-nsError.pl < $< > $@ + +ifndef VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +# +# Generate .java interface files from .xidl +# + +$(VBOX_JXPCOM_GEN)/jxpcomgen.list: \ + $(VBOX_XIDL_FILE) \ + $(VBOX_FILESPLIT) \ + $(VBOX_JXPCOM_SRC)/tools/genjifaces.xsl \ + | $(VBOX_JXPCOM_GEN)/java/interfaces/ + $(call MSG_L1,Generating Java interface files) + $(QUIET)$(RM) -f $(wildcard $(VBOX_JXPCOM_GEN)/java/interfaces/*.java) + $(QUIET)$(VBOX_XSLTPROC) \ + -o $(VBOX_JXPCOM_GEN)/java/interfaces/merged.file $(VBOX_JXPCOM_SRC)/tools/genjifaces.xsl $< + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JXPCOM_GEN)/java/interfaces/merged.file $(VBOX_JXPCOM_GEN)/java/interfaces + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/interfaces/*.java > $@ + +else # VBOX_WITH_JAVA_SUPPORT_IN_XPIDL +# +# Generate .java interface files from the XPCOM and VirtualBox IDL files. +# +# Note! There is not a 1:1 relationship between input and output files here, unfortunately. +# Note! VBOX_JXPCOM_NSERROR shares the output directory with us. +# +$(VBOX_JXPCOM_GEN)/jxpcomgen.list: \ + $(VBOX_PATH_SDK)/bindings/xpcom/idl/VirtualBox_XPCOM.idl \ + $$(addprefix $(VBOX_PATH_XPCOM_SRC)/,$$(XPCOM_IDLFILES)) \ + $(VBOX_XPIDL) \ + | $(VBOX_JXPCOM_GEN)/java/ + $(call MSG_L1,Generating XPCOM Java interface files from IDL) + $(QUIET)$(RM) -f $(filter-out %/XPCOMError.java, $(wildcard $(VBOX_JXPCOM_GEN)/java/*.java)) + $(foreach idl, $(VBOX_PATH_SDK)/bindings/xpcom/idl/VirtualBox_XPCOM.idl $(addprefix $(VBOX_PATH_XPCOM_SRC)/,$(XPCOM_IDLFILES))\ + , $(NLTAB)$(QUIET)$(VBOX_XPIDL) -m java $(XPIDL_INCS) -e $(VBOX_JXPCOM_GEN)/java/$(basename $(notdir $(idl))).java $(idl) ) + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/*.java > $@ +endif # VBOX_WITH_JAVA_SUPPORT_IN_XPIDL + +$(VBOX_JXPCOM_GEN)/jxpcomglue.list: \ + $(VBOX_XIDL_FILE) \ + $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl \ + $(VBOX_FILESPLIT) \ + | $(VBOX_JXPCOM_GEN)/java/glue/ + $(call MSG_L1,Generating Java glue files from XIDL) + $(QUIET)$(RM) -f $(wildcard $(VBOX_JXPCOM_GEN)/java/glue/*.java) + $(QUIET)$(VBOX_XSLTPROC) \ + --stringparam filelistonly "" \ + --stringparam G_vboxApiSuffix $(VBOX_API_SUFFIX) \ + --stringparam G_vboxGlueStyle xpcom \ + --stringparam G_vboxDirPrefix "" \ + -o $(VBOX_JXPCOM_GEN)/java/glue/merged.file $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $< + $(QUIET)$(VBOX_FILESPLIT) $(VBOX_JXPCOM_GEN)/java/glue/merged.file $(VBOX_JXPCOM_GEN)/java/glue/ + $(QUIET)echo $(VBOX_JXPCOM_GEN)/java/glue/*.java > $@ + +# +# Compile the all java code into a JAR file. +# +VBOX_JXPCOM_JSRC = $(VBOX_JXPCOM_SRC)/src/org/mozilla/xpcom +VBOX_JXPCOM_JAR_SRC = \ + $(VBOX_JXPCOM_JSRC)/IXPCOM.java \ + $(VBOX_JXPCOM_JSRC)/Mozilla.java \ + $(VBOX_JXPCOM_JSRC)/VersionComparator.java \ + $(VBOX_JXPCOM_JSRC)/GREVersionRange.java \ + $(VBOX_JXPCOM_JSRC)/IAppFileLocProvider.java \ + $(VBOX_JXPCOM_JSRC)/ProfileLock.java \ + $(VBOX_JXPCOM_JSRC)/IGRE.java \ + $(VBOX_JXPCOM_JSRC)/IJavaXPCOMUtils.java \ + $(VBOX_JXPCOM_JSRC)/XPCOMException.java \ + $(VBOX_JXPCOM_JSRC)/IMozilla.java \ + $(VBOX_JXPCOM_JSRC)/XPCOMInitializationException.java \ + $(VBOX_JXPCOM_JSRC)/INIParser.java \ + $(VBOX_JXPCOM_JSRC)/internal/GREImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/JavaXPCOMMethods.java \ + $(VBOX_JXPCOM_JSRC)/internal/MozillaImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMImpl.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMJavaProxyBase.java \ + $(VBOX_JXPCOM_JSRC)/internal/XPCOMJavaProxy.java + +$$(VBOX_JXPCOM_JAR): $(VBOX_JXPCOM_JAR_SRC) $(VBOX_JXPCOM_GEN)/jxpcomgen.list $(VBOX_JXPCOM_GEN)/jxpcomglue.list $(VBOX_JXPCOM_NSERROR) $(VBOX_JXPCOM_MGR) | $$(dir $$@) + $(call MSG_TOOL,javac,$(notdir $@),jxpcomgen.list,) + $(QUIET)$(RM) -Rf $(VBOX_JXPCOM_JDEST) + $(QUIET)$(MKDIR) -p $(VBOX_JXPCOM_JDEST) + $(QUIET)$(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) @$(VBOX_JXPCOM_GEN)/jxpcomgen.list \ + -d $(VBOX_JXPCOM_JDEST) -classpath $(VBOX_JXPCOM_JDEST) + $(call MSG_TOOL,javac,$(notdir $@),...,) + $(QUIET)$(VBOX_JAVAC) $(VBOX_JAVAC_OPTS) \ + $(VBOX_JXPCOM_JAR_SRC) \ + $(VBOX_JXPCOM_NSERROR) \ + @$(VBOX_JXPCOM_GEN)/jxpcomglue.list \ + -d $(VBOX_JXPCOM_JDEST) -classpath $(VBOX_JXPCOM_JDEST) + $(call MSG_LINK,$(notdir $@),$@) + $(QUIET)$(VBOX_JAR) cf $@ -C $(VBOX_JXPCOM_JDEST) . + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/libs/xpcom18a4/java/README.vbox b/src/libs/xpcom18a4/java/README.vbox new file mode 100644 index 00000000..b22acc4d --- /dev/null +++ b/src/libs/xpcom18a4/java/README.vbox @@ -0,0 +1,5 @@ + JavaXPCOM sources (see https://developer.mozilla.org/en/JavaXPCOM) were taken from +:pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot, directory extensions/java/xpcom, +Apr 29 2010. + + Imported to VirtualBox codebase in revision . diff --git a/src/libs/xpcom18a4/java/src/MacJawt.mm b/src/libs/xpcom18a4/java/src/MacJawt.mm new file mode 100644 index 00000000..a2d0d3f8 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/MacJawt.mm @@ -0,0 +1,47 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 +#import +#include "prtypes.h" + + +PRUint64 GetPlatformHandle(JAWT_DrawingSurfaceInfo* dsi) +{ + JAWT_MacOSXDrawingSurfaceInfo* dsi_mac = + static_cast (dsi->platformInfo); + return reinterpret_cast (dsi_mac->cocoaViewRef); +} diff --git a/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp b/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp new file mode 100644 index 00000000..a78d6c1d --- /dev/null +++ b/src/libs/xpcom18a4/java/src/dlldeps-javaxpcom.cpp @@ -0,0 +1,81 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsJavaInterfaces.h" + + +void XXXNeverCalled_javaxpcom() +{ + MOZILLA_NATIVE(initialize) (nsnull, nsnull); + + GRE_NATIVE(initEmbedding) (nsnull, nsnull, nsnull, nsnull, nsnull); + + GRE_NATIVE(termEmbedding) (nsnull, nsnull); + + GRE_NATIVE(lockProfileDirectory) (nsnull, nsnull, nsnull); + + GRE_NATIVE(notifyProfile) (nsnull, nsnull); + + GRE_NATIVE(lockProfileDirectory) (nsnull, nsnull, nsnull); + + GRE_NATIVE(notifyProfile) (nsnull, nsnull); + + XPCOM_NATIVE(initXPCOM) (nsnull, nsnull, nsnull, nsnull); + + XPCOM_NATIVE(shutdownXPCOM) (nsnull, nsnull, nsnull); + + XPCOM_NATIVE(newLocalFile) (nsnull, nsnull, nsnull, nsnull); + + XPCOM_NATIVE(getComponentManager) (nsnull, nsnull); + + XPCOM_NATIVE(getComponentRegistrar) (nsnull, nsnull); + + XPCOM_NATIVE(getServiceManager) (nsnull, nsnull); + + JAVAPROXY_NATIVE(callXPCOMMethod) (nsnull, nsnull, nsnull, nsnull, nsnull); + + JAVAPROXY_NATIVE(finalizeProxy) (nsnull, nsnull, nsnull); + + JAVAPROXY_NATIVE(isSameXPCOMObject) (nsnull, nsnull, nsnull, nsnull); + + LOCKPROXY_NATIVE(release) (nsnull, nsnull, nsnull); + + MOZILLA_NATIVE(getNativeHandleFromAWT) (nsnull, nsnull, nsnull); + + JXUTILS_NATIVE(wrapJavaObject) (nsnull, nsnull, nsnull, nsnull); + + JXUTILS_NATIVE(wrapXPCOMObject) (nsnull, nsnull, nsnull, nsnull); +} diff --git a/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp new file mode 100644 index 00000000..c10bf4c1 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.cpp @@ -0,0 +1,253 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsAppFileLocProviderProxy.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsILocalFile.h" +#include "nsISimpleEnumerator.h" + + +nsAppFileLocProviderProxy::nsAppFileLocProviderProxy(jobject aJavaObject) +{ + mJavaLocProvider = GetJNIEnv()->NewGlobalRef(aJavaObject); +} + +nsAppFileLocProviderProxy::~nsAppFileLocProviderProxy() +{ + GetJNIEnv()->DeleteGlobalRef(mJavaLocProvider); +} + +NS_IMPL_ISUPPORTS2(nsAppFileLocProviderProxy, + nsIDirectoryServiceProvider, + nsIDirectoryServiceProvider2) + + +// nsIDirectoryServiceProvider + +NS_IMETHODIMP +nsAppFileLocProviderProxy::GetFile(const char* aProp, PRBool* aIsPersistant, + nsIFile** aResult) +{ + // Setup params for calling Java function + JNIEnv* env = GetJNIEnv(); + jstring prop = env->NewStringUTF(aProp); + if (!prop) + return NS_ERROR_OUT_OF_MEMORY; + jbooleanArray persistant = env->NewBooleanArray(1); + if (!persistant) + return NS_ERROR_OUT_OF_MEMORY; + + // Create method ID + jmethodID mid = nsnull; + jclass clazz = env->GetObjectClass(mJavaLocProvider); + if (clazz) { + mid = env->GetMethodID(clazz, "getFile", + "(Ljava/lang/String;[Z)Ljava/io/File;"); + } + if (!mid) + return NS_ERROR_FAILURE; + + // Call Java function + jobject javaFile = nsnull; + javaFile = env->CallObjectMethod(mJavaLocProvider, mid, prop, persistant); + if (javaFile == nsnull || env->ExceptionCheck()) + return NS_ERROR_FAILURE; + + // Set boolean output value + env->GetBooleanArrayRegion(persistant, 0, 1, (jboolean*) aIsPersistant); + + // Set nsIFile result value + nsCOMPtr localFile; + nsresult rv = File_to_nsILocalFile(env, javaFile, getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aResult); + } + + return rv; +} + + +// nsIDirectoryServiceProvider2 + +class DirectoryEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + DirectoryEnumerator(jobjectArray aJavaFileArray) + : mIndex(0) + { + JNIEnv* env = GetJNIEnv(); + mJavaFileArray = static_cast + (env->NewGlobalRef(aJavaFileArray)); + mArraySize = env->GetArrayLength(aJavaFileArray); + } + + ~DirectoryEnumerator() + { + GetJNIEnv()->DeleteGlobalRef(mJavaFileArray); + } + + NS_IMETHOD HasMoreElements(PRBool* aResult) + { + if (!mJavaFileArray) { + *aResult = PR_FALSE; + } else { + *aResult = (mIndex < mArraySize); + } + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports** aResult) + { + nsresult rv = NS_ERROR_FAILURE; + + JNIEnv* env = GetJNIEnv(); + jobject javaFile = env->GetObjectArrayElement(mJavaFileArray, mIndex++); + if (javaFile) { + nsCOMPtr localFile; + rv = File_to_nsILocalFile(env, javaFile, getter_AddRefs(localFile)); + env->DeleteLocalRef(javaFile); + + if (NS_SUCCEEDED(rv)) { + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aResult); + } + } + + env->ExceptionClear(); + return NS_ERROR_FAILURE; + } + +private: + jobjectArray mJavaFileArray; + PRUint32 mArraySize; + PRUint32 mIndex; +}; + +NS_IMPL_ISUPPORTS1(DirectoryEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsAppFileLocProviderProxy::GetFiles(const char* aProp, + nsISimpleEnumerator** aResult) +{ + nsresult rv = NS_OK; + + // Setup params for calling Java function + JNIEnv* env = GetJNIEnv(); + jstring prop = env->NewStringUTF(aProp); + if (!prop) + rv = NS_ERROR_OUT_OF_MEMORY; + + // Create method ID + jmethodID mid = nsnull; + if (NS_SUCCEEDED(rv)) { + jclass clazz = env->GetObjectClass(mJavaLocProvider); + if (clazz) { + mid = env->GetMethodID(clazz, "getFiles", + "(Ljava/lang/String;)[Ljava/io/File;"); + env->DeleteLocalRef(clazz); + } + if (!mid) + rv = NS_ERROR_FAILURE; + } + + // Call Java function + jobject javaFileArray = nsnull; + if (NS_SUCCEEDED(rv)) { + javaFileArray = env->CallObjectMethod(mJavaLocProvider, mid, prop); + + // Handle any exception thrown by Java method. + jthrowable exp = env->ExceptionOccurred(); + if (exp) { +#ifdef DEBUG + env->ExceptionDescribe(); +#endif + + // If the exception is an instance of XPCOMException, then get the + // nsresult from the exception instance. Else, default to + // NS_ERROR_FAILURE. + if (env->IsInstanceOf(exp, xpcomExceptionClass)) { + jfieldID fid; + fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J"); + if (fid) { + rv = env->GetLongField(exp, fid); + } else { + rv = NS_ERROR_FAILURE; + } + NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException"); + } else { + rv = NS_ERROR_FAILURE; + } + } else { + // No exception thrown. Check the result. + if (javaFileArray == nsnull) { + rv = NS_ERROR_FAILURE; + } + } + } + + if (NS_SUCCEEDED(rv)) { + // Parse return value + *aResult = new DirectoryEnumerator(static_cast + (javaFileArray)); + NS_ADDREF(*aResult); + return NS_OK; + } + + // Handle error conditions + *aResult = nsnull; + env->ExceptionClear(); + return rv; +} + + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +NS_NewAppFileLocProviderProxy(jobject aJavaLocProvider, + nsIDirectoryServiceProvider** aResult) +{ + nsAppFileLocProviderProxy* provider = + new nsAppFileLocProviderProxy(aJavaLocProvider); + if (provider == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(provider); + + *aResult = provider; + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h new file mode 100644 index 00000000..d3b90880 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsAppFileLocProviderProxy.h @@ -0,0 +1,65 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsAppFileLocProviderProxy_h_ +#define _nsAppFileLocProviderProxy_h_ + +#include "nsIDirectoryService.h" +#include "jni.h" + + +class nsAppFileLocProviderProxy : public nsIDirectoryServiceProvider2 +{ +public: + nsAppFileLocProviderProxy(jobject aJavaLocProvider); + ~nsAppFileLocProviderProxy(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + +private: + jobject mJavaLocProvider; +}; + +extern "C" nsresult +NS_NewAppFileLocProviderProxy(jobject aJavaLocProvider, + nsIDirectoryServiceProvider** aResult); + + +#endif //_nsAppFileLocProviderProxy_h_ + diff --git a/src/libs/xpcom18a4/java/src/nsFileStreams.cpp b/src/libs/xpcom18a4/java/src/nsFileStreams.cpp new file mode 100644 index 00000000..435df58b --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsFileStreams.cpp @@ -0,0 +1,475 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 ***** */ + +#if defined(XP_UNIX) || defined(XP_BEOS) +#include +#elif defined(XP_MAC) +#include +#elif defined(XP_WIN) +#include +#elif defined(XP_OS2) +#define INCL_DOSERRORS +#include +#else +// XXX add necessary include file for ftruncate (or equivalent) +#endif + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include "nsFileStreams.h" +#include "nsILocalFile.h" +#include "nsXPIDLString.h" +#include "prerror.h" +#include "nsCRT.h" +#include "nsInt64.h" +#include "nsIFile.h" + +#define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 + +#if defined(PR_LOGGING) +// +// Log module for nsFileTransport logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=nsFileIO:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +PRLogModuleInfo* gFileIOLog = nsnull; + +#endif /* PR_LOGGING */ + + +//////////////////////////////////////////////////////////////////////////////// +// nsFileStream + +nsFileStream::nsFileStream() + : mFD(nsnull) + , mCloseFD(PR_TRUE) +{ +} + +nsFileStream::~nsFileStream() +{ + if (mCloseFD) + Close(); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileStream, nsISeekableStream) + +nsresult +nsFileStream::InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent) +{ + NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED); + // + // this file stream is dependent on its parent to keep the + // file descriptor valid. an owning reference to the parent + // prevents the file descriptor from going away prematurely. + // + mFD = fd; + mCloseFD = PR_FALSE; + mParent = parent; + return NS_OK; +} + +nsresult +nsFileStream::Close() +{ + nsresult rv = NS_OK; + if (mFD) { + if (mCloseFD) + if (PR_Close(mFD) == PR_FAILURE) + rv = NS_BASE_STREAM_OSERROR; + mFD = nsnull; + } + return rv; +} + +NS_IMETHODIMP +nsFileStream::Seek(PRInt32 whence, PRInt64 offset) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + nsInt64 cnt = PR_Seek64(mFD, offset, (PRSeekWhence)whence); + if (cnt == nsInt64(-1)) { + return NS_ErrorAccordingToNSPR(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFileStream::Tell(PRInt64 *result) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + nsInt64 cnt = PR_Seek64(mFD, 0, PR_SEEK_CUR); + if (cnt == nsInt64(-1)) { + return NS_ErrorAccordingToNSPR(); + } + *result = cnt; + return NS_OK; +} + +NS_IMETHODIMP +nsFileStream::SetEOF() +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + +#if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_OS2) || defined(XP_BEOS) + // Some system calls require an EOF offset. + PRInt64 offset; + nsresult rv = Tell(&offset); + if (NS_FAILED(rv)) return rv; +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) + if (ftruncate(PR_FileDesc2NativeHandle(mFD), offset) != 0) { + NS_ERROR("ftruncate failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_MAC) + if (::SetEOF(PR_FileDesc2NativeHandle(mFD), offset) != 0) { + NS_ERROR("SetEOF failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_WIN) + if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) { + NS_ERROR("SetEndOfFile failed"); + return NS_ERROR_FAILURE; + } +#elif defined(XP_OS2) + if (DosSetFileSize((HFILE) PR_FileDesc2NativeHandle(mFD), offset) != NO_ERROR) { + NS_ERROR("DosSetFileSize failed"); + return NS_ERROR_FAILURE; + } +#else + // XXX not implemented +#endif + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsFileInputStream + +NS_IMPL_ISUPPORTS_INHERITED3(nsFileInputStream, + nsFileStream, + nsIInputStream, + nsIFileInputStream, + nsILineInputStream) + +NS_METHOD +nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(aOuter); + + nsFileInputStream* stream = new nsFileInputStream(); + if (stream == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(stream); + nsresult rv = stream->QueryInterface(aIID, aResult); + NS_RELEASE(stream); + return rv; +} + +nsresult +nsFileInputStream::Open(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm) +{ + nsresult rv = NS_OK; + + // If the previous file is open, close it + if (mFD) { + rv = Close(); + if (NS_FAILED(rv)) return rv; + } + + // Open the file + nsCOMPtr localFile = do_QueryInterface(aFile, &rv); + if (NS_FAILED(rv)) return rv; + if (aIOFlags == -1) + aIOFlags = PR_RDONLY; + if (aPerm == -1) + aPerm = 0; + + PRFileDesc* fd; + rv = localFile->OpenNSPRFileDesc(aIOFlags, aPerm, &fd); + if (NS_FAILED(rv)) return rv; + + mFD = fd; + + if (mBehaviorFlags & DELETE_ON_CLOSE) { + // POSIX compatible filesystems allow a file to be unlinked while a + // file descriptor is still referencing the file. since we've already + // opened the file descriptor, we'll try to remove the file. if that + // fails, then we'll just remember the nsIFile and remove it after we + // close the file descriptor. + rv = aFile->Remove(PR_FALSE); + if (NS_FAILED(rv) && !(mBehaviorFlags & REOPEN_ON_REWIND)) { + // If REOPEN_ON_REWIND is not happenin', we haven't saved the file yet + mFile = aFile; + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm, + PRInt32 aBehaviorFlags) +{ + NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED); + NS_ENSURE_TRUE(!mParent, NS_ERROR_ALREADY_INITIALIZED); + + mBehaviorFlags = aBehaviorFlags; + + // If the file will be reopened on rewind, save the info to open the file + if (mBehaviorFlags & REOPEN_ON_REWIND) { + mFile = aFile; + mIOFlags = aIOFlags; + mPerm = aPerm; + } + + return Open(aFile, aIOFlags, aPerm); +} + +NS_IMETHODIMP +nsFileInputStream::Close() +{ + nsresult rv = nsFileStream::Close(); + if (NS_FAILED(rv)) return rv; + if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) { + rv = mFile->Remove(PR_FALSE); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to delete file"); + // If we don't need to save the file for reopening, free it up + if (!(mBehaviorFlags & REOPEN_ON_REWIND)) { + mFile = nsnull; + } + } + return rv; +} + +NS_IMETHODIMP +nsFileInputStream::Available(PRUint32* aResult) +{ + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRInt32 avail = PR_Available(mFD); + if (avail == -1) { + return NS_ErrorAccordingToNSPR(); + } + *aResult = avail; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32* aResult) +{ + if (!mFD) { + return NS_BASE_STREAM_CLOSED; + } + + PRInt32 bytesRead = PR_Read(mFD, aBuf, aCount); + if (bytesRead == -1) { + return NS_ErrorAccordingToNSPR(); + } + // Check if we're at the end of file and need to close + if (mBehaviorFlags & CLOSE_ON_EOF) { + if (bytesRead == 0) { + Close(); + } + } + + *aResult = bytesRead; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::ReadLine(nsACString& aLine, PRBool* aResult) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32* aResult) +{ + // ReadSegments is not implemented because it would be inefficient when + // the writer does not consume all data. If you want to call ReadSegments, + // wrap a BufferedInputStream around the file stream. That will call + // Read(). + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsFileInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + if (!mFD) { + if (mBehaviorFlags & REOPEN_ON_REWIND) { + nsresult rv = Reopen(); + if (NS_FAILED(rv)) { + return rv; + } + } else { + return NS_BASE_STREAM_CLOSED; + } + } + + return nsFileStream::Seek(aWhence, aOffset); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsFileOutputStream + +NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream, + nsFileStream, + nsIOutputStream, + nsIFileOutputStream) + +NS_METHOD +nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_NO_AGGREGATION(aOuter); + + nsFileOutputStream* stream = new nsFileOutputStream(); + if (stream == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(stream); + nsresult rv = stream->QueryInterface(aIID, aResult); + NS_RELEASE(stream); + return rv; +} + +NS_IMETHODIMP +nsFileOutputStream::Init(nsIFile* file, PRInt32 ioFlags, PRInt32 perm, + PRInt32 behaviorFlags) +{ + NS_ENSURE_TRUE(mFD == nsnull, NS_ERROR_ALREADY_INITIALIZED); + + nsresult rv; + nsCOMPtr localFile = do_QueryInterface(file, &rv); + if (NS_FAILED(rv)) return rv; + if (ioFlags == -1) + ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; + if (perm <= 0) + perm = 0664; + + PRFileDesc* fd; + rv = localFile->OpenNSPRFileDesc(ioFlags, perm, &fd); + if (NS_FAILED(rv)) return rv; + + mFD = fd; + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::Close() +{ + return nsFileStream::Close(); +} + +NS_IMETHODIMP +nsFileOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Write(mFD, buf, count); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + *result = cnt; + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::Flush(void) +{ + if (mFD == nsnull) + return NS_BASE_STREAM_CLOSED; + + PRInt32 cnt = PR_Sync(mFD); + if (cnt == -1) { + return NS_ErrorAccordingToNSPR(); + } + return NS_OK; +} + +NS_IMETHODIMP +nsFileOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom (see source comment)"); + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +NS_IMETHODIMP +nsFileOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments (see source comment)"); + return NS_ERROR_NOT_IMPLEMENTED; + // File streams intentionally do not support this method. + // If you need something like this, then you should wrap + // the file stream using nsIBufferedOutputStream +} + +NS_IMETHODIMP +nsFileOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/java/src/nsFileStreams.h b/src/libs/xpcom18a4/java/src/nsFileStreams.h new file mode 100644 index 00000000..7d713fc5 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsFileStreams.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 nsFileStreams_h__ +#define nsFileStreams_h__ + +#include "nsIFileStreams.h" +#include "nsIFile.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsISeekableStream.h" +#include "nsILineInputStream.h" +#include "nsCOMPtr.h" +#include "prlog.h" +#include "prio.h" + +template class nsLineBuffer; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileStream : public nsISeekableStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISEEKABLESTREAM + + nsFileStream(); + virtual ~nsFileStream(); + + nsresult Close(); + nsresult InitWithFileDescriptor(PRFileDesc* fd, nsISupports* parent); + +protected: + PRFileDesc* mFD; + nsCOMPtr mParent; // strong reference to parent nsFileIO, + // which ensures mFD remains valid. + PRBool mCloseFD; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileInputStream : public nsFileStream, + public nsIFileInputStream, + public nsILineInputStream +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIFILEINPUTSTREAM + NS_DECL_NSILINEINPUTSTREAM + + // Overrided from nsFileStream + NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset); + + nsFileInputStream() : nsFileStream() + { + mBehaviorFlags = 0; + } + virtual ~nsFileInputStream() + { + Close(); + } + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +protected: + /** + * The file being opened. Only stored when DELETE_ON_CLOSE or + * REOPEN_ON_REWIND are true. + */ + nsCOMPtr mFile; + /** + * The IO flags passed to Init() for the file open. + * Only set for REOPEN_ON_REWIND. + */ + PRInt32 mIOFlags; + /** + * The permissions passed to Init() for the file open. + * Only set for REOPEN_ON_REWIND. + */ + PRInt32 mPerm; + /** + * Flags describing our behavior. See the IDL file for possible values. + */ + PRInt32 mBehaviorFlags; + +protected: + /** + * Internal, called to open a file. Parameters are the same as their + * Init() analogues. + */ + nsresult Open(nsIFile* file, PRInt32 ioFlags, PRInt32 perm); + /** + * Reopen the file (for OPEN_ON_READ only!) + */ + nsresult Reopen() { return Open(mFile, mIOFlags, mPerm); } +}; + +//////////////////////////////////////////////////////////////////////////////// + +class nsFileOutputStream : public nsFileStream, + public nsIFileOutputStream +{ +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIOUTPUTSTREAM + NS_DECL_NSIFILEOUTPUTSTREAM + + nsFileOutputStream() : nsFileStream() {} + virtual ~nsFileOutputStream() { nsFileOutputStream::Close(); } + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsFileStreams_h__ diff --git a/src/libs/xpcom18a4/java/src/nsIFileStreams.h b/src/libs/xpcom18a4/java/src/nsIFileStreams.h new file mode 100644 index 00000000..3df02b55 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsIFileStreams.h @@ -0,0 +1,209 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM nsIFileStreams.idl + */ + +#ifndef __gen_nsIFileStreams_h__ +#define __gen_nsIFileStreams_h__ + + +#ifndef __gen_nsIInputStream_h__ +#include "nsIInputStream.h" +#endif + +#ifndef __gen_nsIOutputStream_h__ +#include "nsIOutputStream.h" +#endif + +/* For IDL files that don't want to include root IDL files. */ +#ifndef NS_NO_VTABLE +#define NS_NO_VTABLE +#endif +class nsIFile; /* forward declaration */ + + +/* starting interface: nsIFileInputStream */ +#define NS_IFILEINPUTSTREAM_IID_STR "e3d56a20-c7ec-11d3-8cda-0060b0fc14a3" + +#define NS_IFILEINPUTSTREAM_IID \ + {0xe3d56a20, 0xc7ec, 0x11d3, \ + { 0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3 }} + +/** + * An input stream that allows you to read from a file. + */ +class NS_NO_VTABLE nsIFileInputStream : public nsIInputStream { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILEINPUTSTREAM_IID) + + /** + * @param file file to read from (must QI to nsILocalFile) + * @param ioFlags file open flags listed in prio.h + * @param perm file mode bits listed in prio.h + * @param behaviorFlags flags specifying various behaviors of the class + * (see enumerations in the class) + */ + /* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) = 0; + + /** + * If this is set, the file will be deleted by the time the stream is + * closed. It may be removed before the stream is closed if it is possible + * to delete it and still read from it. + * + * If OPEN_ON_READ is defined, and the file was recreated after the first + * delete, the file will be deleted again when it is closed again. + */ + enum { DELETE_ON_CLOSE = 2 }; + + /** + * If this is set, the file will close automatically when the end of the + * file is reached. + */ + enum { CLOSE_ON_EOF = 4 }; + + /** + * If this is set, the file will be reopened whenever Seek(0) occurs. If + * the file is already open and the seek occurs, it will happen naturally. + * (The file will only be reopened if it is closed for some reason.) + */ + enum { REOPEN_ON_REWIND = 8 }; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIFILEINPUTSTREAM \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags); \ + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIFILEINPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return _to Init(file, ioFlags, perm, behaviorFlags); } \ + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIFILEINPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return !_to ? NS_ERROR_NULL_POINTER : _to->Init(file, ioFlags, perm, behaviorFlags); } \ + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsFileInputStream : public nsIFileInputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEINPUTSTREAM + + nsFileInputStream(); + +private: + ~nsFileInputStream(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsFileInputStream, nsIFileInputStream) + +nsFileInputStream::nsFileInputStream() +{ + /* member initializers and constructor code */ +} + +nsFileInputStream::~nsFileInputStream() +{ + /* destructor code */ +} + +/* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ +NS_IMETHODIMP nsFileInputStream::Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +/* starting interface: nsIFileOutputStream */ +#define NS_IFILEOUTPUTSTREAM_IID_STR "e6f68040-c7ec-11d3-8cda-0060b0fc14a3" + +#define NS_IFILEOUTPUTSTREAM_IID \ + {0xe6f68040, 0xc7ec, 0x11d3, \ + { 0x8c, 0xda, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3 }} + +/** + * An output stream that lets you stream to a file. + */ +class NS_NO_VTABLE nsIFileOutputStream : public nsIOutputStream { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILEOUTPUTSTREAM_IID) + + /** + * @param file - file to write to (must QI to nsILocalFile) + * @param ioFlags - file open flags listed in prio.h + * @param perm - file mode bits listed in prio.h + * @param behaviorFlags flags specifying various behaviors of the class + * (currently none supported) + */ + /* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) = 0; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIFILEOUTPUTSTREAM \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags); + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIFILEOUTPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return _to Init(file, ioFlags, perm, behaviorFlags); } + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIFILEOUTPUTSTREAM(_to) \ + NS_IMETHOD Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) { return !_to ? NS_ERROR_NULL_POINTER : _to->Init(file, ioFlags, perm, behaviorFlags); } + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsFileOutputStream : public nsIFileOutputStream +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFILEOUTPUTSTREAM + + nsFileOutputStream(); + +private: + ~nsFileOutputStream(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsFileOutputStream, nsIFileOutputStream) + +nsFileOutputStream::nsFileOutputStream() +{ + /* member initializers and constructor code */ +} + +nsFileOutputStream::~nsFileOutputStream() +{ + /* destructor code */ +} + +/* void init (in nsIFile file, in long ioFlags, in long perm, in long behaviorFlags); */ +NS_IMETHODIMP nsFileOutputStream::Init(nsIFile *file, PRInt32 ioFlags, PRInt32 perm, PRInt32 behaviorFlags) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +#endif /* __gen_nsIFileStreams_h__ */ diff --git a/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp new file mode 100644 index 00000000..103f2f37 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.cpp @@ -0,0 +1,557 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsJavaInterfaces.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "nsIComponentRegistrar.h" +#include "nsString.h" +#include "nsISimpleEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIInputStream.h" +#include "nsEnumeratorUtils.h" +#include "nsAppFileLocProviderProxy.h" +#ifndef VBOX +#include "nsXULAppAPI.h" +#endif +#include "nsILocalFile.h" + +#ifdef XP_MACOSX +#include "jawt.h" +#endif + + +#ifdef VBOX +#if 0 +#include "org_mozilla_xpcom_internal_GREImpl.h" +#include "org_mozilla_xpcom_internal_JavaXPCOMMethods.h" +#include "org_mozilla_xpcom_internal_MozillaImpl.h" +#include "org_mozilla_xpcom_internal_XPCOMImpl.h" +#include "org_mozilla_xpcom_internal_XPCOMJavaProxy.h" +#include "org_mozilla_xpcom_ProfileLock.h" +#endif +#include +using namespace com; +#include +#include +#include +#endif + +extern "C" NS_EXPORT void JNICALL +MOZILLA_NATIVE(initialize) (JNIEnv* env, jobject) +{ + if (!InitializeJavaGlobals(env)) { + jclass clazz = + env->FindClass("org/mozilla/xpcom/XPCOMInitializationException"); + if (clazz) { + env->ThrowNew(clazz, "Failed to initialize JavaXPCOM"); + } + } +} + +nsresult +InitEmbedding_Impl(JNIEnv* env, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider) +{ + nsresult rv; + + // create an nsILocalFile from given java.io.File + nsCOMPtr libXULDir; + if (aLibXULDirectory) { + rv = File_to_nsILocalFile(env, aLibXULDirectory, getter_AddRefs(libXULDir)); + NS_ENSURE_SUCCESS(rv, rv); + } + nsCOMPtr appDir; + if (aAppDirectory) { + rv = File_to_nsILocalFile(env, aAppDirectory, getter_AddRefs(appDir)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // create nsAppFileLocProviderProxy from given Java object + nsCOMPtr provider; + if (aAppDirProvider) { + rv = NS_NewAppFileLocProviderProxy(aAppDirProvider, + getter_AddRefs(provider)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // init libXUL +#ifdef VBOX + return 0; +#else + return XRE_InitEmbedding(libXULDir, appDir, provider, nsnull, 0); +#endif +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(initEmbedding) (JNIEnv* env, jobject, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider) +{ + nsresult rv = InitEmbedding_Impl(env, aLibXULDirectory, aAppDirectory, + aAppDirProvider); + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failure in initEmbedding"); + FreeJavaGlobals(env); + } +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(termEmbedding) (JNIEnv *env, jobject) +{ + // Free globals before calling XRE_TermEmbedding(), since we need some + // XPCOM services. + FreeJavaGlobals(env); + +#ifndef VBOX + XRE_TermEmbedding(); +#endif +} +#ifdef VBOX +nsresult +InitXPCOMVBox_Impl(JNIEnv* env, jobject aVBoxBinDirectory) +{ +#if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rv = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +#else + const char *pszHome = nsnull; + const char *jhome = nsnull; + jstring path = nsnull; + + int rv; + jclass clazz; + jmethodID getPathMID; + + if (aVBoxBinDirectory && + (clazz = env->FindClass("java/io/File")) && + (getPathMID = env->GetMethodID(clazz, "getAbsolutePath", + "()Ljava/lang/String;")) + ) + { + path = (jstring)env->CallObjectMethod(aVBoxBinDirectory, getPathMID); + pszHome = jhome = env->GetStringUTFChars(path, nsnull); + } + + if (pszHome == nsnull) + pszHome = getenv("VBOX_PROGRAM_PATH"); + + if (pszHome) { + size_t cchHome = strlen(pszHome); + char *pszExePath = (char *)alloca(cchHome + 32); + memcpy(pszExePath, pszHome, cchHome); + memcpy(pszExePath + cchHome, "/javafake", sizeof("/javafake")); + rv = RTR3InitEx(RTR3INIT_VER_CUR, RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_UNOBTRUSIVE, 0, NULL, pszExePath); + } else { + rv = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + } + + if (jhome) + env->ReleaseStringUTFChars(path, jhome); +#endif + + return com::Initialize(); +} +#endif + +nsresult +InitXPCOM_Impl(JNIEnv* env, jobject aMozBinDirectory, + jobject aAppFileLocProvider, jobject* aResult) +{ + nsresult rv; + // create an nsILocalFile from given java.io.File + nsCOMPtr directory; + if (aMozBinDirectory) { + rv = File_to_nsILocalFile(env, aMozBinDirectory, getter_AddRefs(directory)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // create nsAppFileLocProviderProxy from given Java object + nsCOMPtr provider; + if (aAppFileLocProvider) { + rv = NS_NewAppFileLocProviderProxy(aAppFileLocProvider, + getter_AddRefs(provider)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // init XPCOM + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), directory, provider); + NS_ENSURE_SUCCESS(rv, rv); + + // create Java proxy for service manager returned by NS_InitXPCOM2 + return NativeInterfaceToJavaObject(env, servMan, NS_GET_IID(nsIServiceManager), + nsnull, aResult); +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jobject, jobject aMozBinDirectory, + jobject aAppFileLocProvider) +{ +#ifdef VBOX + nsresult rv = InitXPCOMVBox_Impl(env, aMozBinDirectory); + if (NS_SUCCEEDED(rv)) + return nsnull; +#else + jobject servMan; + nsresult rv = InitXPCOM_Impl(env, aMozBinDirectory, aAppFileLocProvider, + &servMan); + if (NS_SUCCEEDED(rv)) + return servMan; +#endif + + ThrowException(env, rv, "Failure in initXPCOM"); + FreeJavaGlobals(env); + return nsnull; +} + +extern "C" NS_EXPORT void JNICALL +#ifdef VBOX +XPCOM_NATIVE2(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr) +#else +XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr) +#endif +{ +#ifdef VBOX + // Free globals before calling NS_ShutdownXPCOM(), since we need some + // XPCOM services. + //FreeJavaGlobals(env); + //com::Shutdown(); +#else + nsresult rv; + nsIServiceManager* servMgr = nsnull; + if (aServMgr) { + // Get native XPCOM instance + nsISupports* instancePtr = nsnull; + rv = JavaObjectToNativeInterface(env, aServMgr, + NS_GET_IID(nsIServiceManager), (void**) &instancePtr); + NS_ASSERTION(NS_SUCCEEDED(rv) && instancePtr != nsnull, + "Failed to get XPCOM obj for ServiceMgr."); + if (NS_SUCCEEDED(rv)) { + rv = instancePtr->QueryInterface(NS_GET_IID(nsIServiceManager), + (void**) &servMgr); + NS_ASSERTION(NS_SUCCEEDED(rv), "QI for nsIServiceManager failed"); + } + + // Even if we failed to get the matching xpcom object, we don't abort this + // function. Just call NS_ShutdownXPCOM with a null service manager. + } + + // Free globals before calling NS_ShutdownXPCOM(), since we need some + // XPCOM services. + FreeJavaGlobals(env); + + rv = NS_ShutdownXPCOM(servMgr); + if (NS_FAILED(rv)) + ThrowException(env, rv, "NS_ShutdownXPCOM failed"); +#endif +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jobject, jstring aPath, + jboolean aFollowLinks) +{ + // Create a Mozilla string from the jstring + const PRUnichar* buf = nsnull; + if (aPath) { + buf = env->GetStringChars(aPath, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsAutoString path_str(buf); + env->ReleaseStringChars(aPath, buf); + + // Make call to given function + nsCOMPtr file; + nsresult rv = NS_NewLocalFile(path_str, aFollowLinks, getter_AddRefs(file)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, file, NS_GET_IID(nsILocalFile), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in newLocalFile"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +#ifdef VBOX +XPCOM_NATIVE2(getComponentManager) (JNIEnv *env, jobject) +#else +XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jobject) +#endif +{ + // Call XPCOM method + nsCOMPtr cm; + nsresult rv = NS_GetComponentManager(getter_AddRefs(cm)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, cm, NS_GET_IID(nsIComponentManager), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getComponentManager"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jobject) +{ + // Call XPCOM method + nsCOMPtr cr; + nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(cr)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, cr, NS_GET_IID(nsIComponentRegistrar), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getComponentRegistrar"); + return nsnull; +} + +#ifdef VBOX +# include +# include + +extern "C" NS_EXPORT jint JNICALL +XPCOM_NATIVE2(waitForEvents) (JNIEnv *env, jobject, jlong aTimeout) +{ + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + return -1; + + int rc = aEventQ->processEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout); + + if (RT_SUCCESS(rc)) + return 0; + + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + return 1; + + return 2; +} +#endif + +extern "C" NS_EXPORT jobject JNICALL +#ifdef VBOX +XPCOM_NATIVE2(getServiceManager) (JNIEnv *env, jobject) +#else +XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jobject) +#endif +{ + // Call XPCOM method + nsCOMPtr sm; + nsresult rv = NS_GetServiceManager(getter_AddRefs(sm)); + + if (NS_SUCCEEDED(rv)) { + jobject javaProxy; + rv = NativeInterfaceToJavaObject(env, sm, NS_GET_IID(nsIServiceManager), + nsnull, &javaProxy); + if (NS_SUCCEEDED(rv)) + return javaProxy; + } + + ThrowException(env, rv, "Failure in getServiceManager"); + return nsnull; +} + +extern "C" NS_EXPORT jobject JNICALL +GRE_NATIVE(lockProfileDirectory) (JNIEnv* env, jobject, jobject aDirectory) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (aDirectory) { + nsCOMPtr profileDir; + rv = File_to_nsILocalFile(env, aDirectory, getter_AddRefs(profileDir)); + + if (NS_SUCCEEDED(rv)) { + nsISupports* lock; +#ifdef VBOX + rv = 0; + lock = 0; +#else + rv = XRE_LockProfileDirectory(profileDir, &lock); +#endif + + if (NS_SUCCEEDED(rv)) { + jclass clazz = + env->FindClass("org/mozilla/xpcom/ProfileLock"); + if (clazz) { + jmethodID mid = env->GetMethodID(clazz, "", "(J)V"); + if (mid) { + return env->NewObject(clazz, mid, reinterpret_cast(lock)); + } + } + + // if we get here, then something failed + rv = NS_ERROR_FAILURE; + } + } + } + + ThrowException(env, rv, "Failure in lockProfileDirectory"); + return nsnull; +} + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(notifyProfile) (JNIEnv *env, jobject) +{ +#ifndef VBOX + XRE_NotifyProfile(); +#endif +} + +#ifdef XP_MACOSX +extern PRUint64 GetPlatformHandle(JAWT_DrawingSurfaceInfo* dsi); +#endif + +extern "C" NS_EXPORT jlong JNICALL +MOZILLA_NATIVE(getNativeHandleFromAWT) (JNIEnv* env, jobject clazz, + jobject widget) +{ + PRUint64 handle = 0; + +#if defined(XP_MACOSX) && !defined(VBOX) + JAWT awt; + awt.version = JAWT_VERSION_1_4; + jboolean result = JAWT_GetAWT(env, &awt); + if (result == JNI_FALSE) + return 0; + + JAWT_DrawingSurface* ds = awt.GetDrawingSurface(env, widget); + if (ds != nsnull) { + jint lock = ds->Lock(ds); + if (!(lock & JAWT_LOCK_ERROR)) { + JAWT_DrawingSurfaceInfo* dsi = ds->GetDrawingSurfaceInfo(ds); + if (dsi) { + handle = GetPlatformHandle(dsi); + ds->FreeDrawingSurfaceInfo(dsi); + } + + ds->Unlock(ds); + } + + awt.FreeDrawingSurface(ds); + } +#else + NS_WARNING("getNativeHandleFromAWT JNI method not implemented"); +#endif + + return handle; +} + +extern "C" NS_EXPORT jlong JNICALL +JXUTILS_NATIVE(wrapJavaObject) (JNIEnv* env, jobject, jobject aJavaObject, + jstring aIID) +{ + nsresult rv; + void* xpcomObject = nsnull; + + if (!aJavaObject || !aIID) { + rv = NS_ERROR_NULL_POINTER; + } else { + const char* str = env->GetStringUTFChars(aIID, nsnull); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + nsID iid; + if (iid.Parse(str)) { + rv = JavaObjectToNativeInterface(env, aJavaObject, iid, &xpcomObject); + if (NS_SUCCEEDED(rv)) { + nsISupports *xpcom_nat_obj = (nsISupports*) xpcomObject; + rv = xpcom_nat_obj->QueryInterface(iid, &xpcomObject); + NS_IF_RELEASE(xpcom_nat_obj); + } + } else { + rv = NS_ERROR_INVALID_ARG; + } + + env->ReleaseStringUTFChars(aIID, str); + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to create XPCOM proxy for Java object"); + } + return reinterpret_cast(xpcomObject); +} + +extern "C" NS_EXPORT jobject JNICALL +JXUTILS_NATIVE(wrapXPCOMObject) (JNIEnv* env, jobject, jlong aXPCOMObject, + jstring aIID) +{ + nsresult rv; + jobject javaObject = nsnull; + nsISupports* xpcomObject = reinterpret_cast(aXPCOMObject); + + if (!xpcomObject || !aIID) { + rv = NS_ERROR_NULL_POINTER; + } else { + const char* str = env->GetStringUTFChars(aIID, nsnull); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + nsID iid; + if (iid.Parse(str)) { + // XXX Should we be passing something other than NULL for aObjectLoader? + rv = NativeInterfaceToJavaObject(env, xpcomObject, iid, nsnull, + &javaObject); + } else { + rv = NS_ERROR_INVALID_ARG; + } + + env->ReleaseStringUTFChars(aIID, str); + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to create XPCOM proxy for Java object"); + } + return javaObject; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h new file mode 100644 index 00000000..69d2f680 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaInterfaces.h @@ -0,0 +1,121 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsJavaInterfaces_h_ +#define _nsJavaInterfaces_h_ + +#include "jni.h" +#include "nscore.h" + +#ifdef VBOX +#define MOZILLA_NATIVE(func) Java_org_mozilla_xpcom_internal_MozillaImpl_##func##Native +#define GRE_NATIVE(func) Java_org_mozilla_xpcom_internal_GREImpl_##func##Native +#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func##Native +#define XPCOM_NATIVE2(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func +#else +#define MOZILLA_NATIVE(func) Java_org_mozilla_xpcom_internal_MozillaImpl_##func +#define GRE_NATIVE(func) Java_org_mozilla_xpcom_internal_GREImpl_##func +#define XPCOM_NATIVE(func) Java_org_mozilla_xpcom_internal_XPCOMImpl_##func +#endif +#define JAVAPROXY_NATIVE(func) \ + Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_##func +#define LOCKPROXY_NATIVE(func) Java_org_mozilla_xpcom_ProfileLock_##func +#define JXUTILS_NATIVE(func) \ + Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_##func + + +extern "C" NS_EXPORT void JNICALL +MOZILLA_NATIVE(initialize) (JNIEnv* env, jobject); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(initEmbedding) (JNIEnv* env, jobject, jobject aLibXULDirectory, + jobject aAppDirectory, jobject aAppDirProvider); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(termEmbedding) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +GRE_NATIVE(lockProfileDirectory) (JNIEnv *, jobject, jobject aDirectory); + +extern "C" NS_EXPORT void JNICALL +GRE_NATIVE(notifyProfile) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(initXPCOM) (JNIEnv* env, jobject, jobject aMozBinDirectory, + jobject aAppFileLocProvider); + +extern "C" NS_EXPORT void JNICALL +XPCOM_NATIVE(shutdownXPCOM) (JNIEnv *env, jobject, jobject aServMgr); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(newLocalFile) (JNIEnv *env, jobject, jstring aPath, + jboolean aFollowLinks); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentManager) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getComponentRegistrar) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +XPCOM_NATIVE(getServiceManager) (JNIEnv *env, jobject); + +extern "C" NS_EXPORT jobject JNICALL +JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, + jstring aMethodName, jobjectArray aParams); + +extern "C" NS_EXPORT void JNICALL +JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy); + +extern "C" NS_EXPORT jboolean JNICALL +JAVAPROXY_NATIVE(isSameXPCOMObject) (JNIEnv *env, jclass that, jobject aProxy1, + jobject aProxy2); + +extern "C" NS_EXPORT void JNICALL +LOCKPROXY_NATIVE(release) (JNIEnv *env, jclass that, jlong aLockObject); + +extern "C" NS_EXPORT jlong JNICALL +MOZILLA_NATIVE(getNativeHandleFromAWT) (JNIEnv* env, jobject, jobject widget); + +extern "C" NS_EXPORT jlong JNICALL +JXUTILS_NATIVE(wrapJavaObject) (JNIEnv* env, jobject, jobject aJavaObject, + jstring aIID); + +extern "C" NS_EXPORT jobject JNICALL +JXUTILS_NATIVE(wrapXPCOMObject) (JNIEnv* env, jobject, jlong aXPCOMObject, + jstring aIID); + +#endif // _nsJavaInterfaces_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp b/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp new file mode 100644 index 00000000..a046c8a3 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaWrapper.cpp @@ -0,0 +1,2020 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsJavaInterfaces.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "jni.h" +#include "xptcall.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsCRT.h" +#include "prmem.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" + +static nsID nullID = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + +#ifdef VBOX +#include "nsIThread.h" +static nsresult +NS_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + +#endif + +nsresult +CreateJavaArray(JNIEnv* env, PRUint8 aType, PRUint32 aSize, const nsID& aIID, + jobject* aResult) +{ + jobject array = nsnull; + switch (aType) + { + case nsXPTType::T_I8: + array = env->NewByteArray(aSize); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + array = env->NewShortArray(aSize); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + array = env->NewIntArray(aSize); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + array = env->NewLongArray(aSize); + break; + + case nsXPTType::T_FLOAT: + array = env->NewFloatArray(aSize); + break; + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + array = env->NewDoubleArray(aSize); + break; + + case nsXPTType::T_BOOL: + array = env->NewBooleanArray(aSize); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + array = env->NewCharArray(aSize); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + array = env->NewObjectArray(aSize, stringClass, nsnull); + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ASSERTION(iim, "Failed to get InterfaceInfoManager"); + if (!iim) + return NS_ERROR_FAILURE; + + // Get interface info for given IID + nsCOMPtr info; + nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(info)); + if (NS_FAILED(rv)) + return rv; + + // Get interface name + const char* iface_name; + rv = info->GetNameShared(&iface_name); + if (NS_FAILED(rv)) + return rv; + + // Create proper Java interface name + nsCAutoString class_name("org/mozilla/interfaces/"); + class_name.AppendASCII(iface_name); + jclass ifaceClass = env->FindClass(class_name.get()); + if (!ifaceClass) + return NS_ERROR_FAILURE; + + array = env->NewObjectArray(aSize, ifaceClass, nsnull); + break; + } + + case nsXPTType::T_VOID: + array = env->NewLongArray(aSize); + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = array; + return NS_OK; +} + +nsresult +GetNativeArrayElement(PRUint8 aType, void* aArray, PRUint32 aIndex, + nsXPTCVariant* aResult) +{ + switch (aType) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + aResult->val.u8 = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + aResult->val.u16 = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + aResult->val.u32 = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + aResult->val.u64 = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_FLOAT: + aResult->val.f = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_DOUBLE: + aResult->val.d = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_BOOL: + aResult->val.b = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_CHAR: + aResult->val.c = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_WCHAR: + aResult->val.wc = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_CHAR_STR: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_WCHAR_STR: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_IID: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + case nsXPTType::T_VOID: + aResult->val.p = static_cast(aArray)[aIndex]; + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +CreateNativeArray(PRUint8 aType, PRUint32 aSize, void** aResult) +{ + void* array = nsnull; + switch (aType) + { + case nsXPTType::T_I8: + case nsXPTType::T_U8: + array = PR_Malloc(aSize * sizeof(PRUint8)); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U16: + array = PR_Malloc(aSize * sizeof(PRUint16)); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U32: + array = PR_Malloc(aSize * sizeof(PRUint32)); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U64: + array = PR_Malloc(aSize * sizeof(PRUint64)); + break; + + case nsXPTType::T_FLOAT: + array = PR_Malloc(aSize * sizeof(float)); + break; + + case nsXPTType::T_DOUBLE: + array = PR_Malloc(aSize * sizeof(double)); + break; + + case nsXPTType::T_BOOL: + array = PR_Malloc(aSize * sizeof(PRBool)); + break; + + case nsXPTType::T_CHAR: + array = PR_Malloc(aSize * sizeof(char)); + break; + + case nsXPTType::T_WCHAR: + array = PR_Malloc(aSize * sizeof(PRUnichar)); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + array = PR_Malloc(aSize * sizeof(void*)); + break; + + case nsXPTType::T_VOID: + array = PR_Malloc(aSize * sizeof(void*)); + break; + + default: + NS_WARNING("unknown type"); + return NS_ERROR_FAILURE; + } + + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = array; + return NS_OK; +} + +/** + * Handle 'in' and 'inout' params. + */ +nsresult +SetupParams(JNIEnv *env, const jobject aParam, PRUint8 aType, PRBool aIsOut, + const nsID& aIID, PRUint8 aArrayType, PRUint32 aArraySize, + PRBool aIsArrayElement, PRUint32 aIndex, nsXPTCVariant &aVariant) +{ + nsresult rv = NS_OK; + + switch (aType) + { + case nsXPTType::T_I8: + { + LOG(("byte\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.i8 = env->CallByteMethod(aParam, byteValueMID); + } else { // 'inout' & 'array' + jbyte value; + if (aParam) { + env->GetByteArrayRegion((jbyteArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.i8 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I16: + case nsXPTType::T_U8: // C++ unsigned octet <=> Java short + { + LOG(("short\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jshort value = env->CallShortMethod(aParam, shortValueMID); + if (aType == nsXPTType::T_I16) + aVariant.val.i16 = value; + else + aVariant.val.u8 = value; + } else { // 'inout' & 'array' + jshort value; + if (aParam) { + env->GetShortArrayRegion((jshortArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I16) + aVariant.val.i16 = value; + else + aVariant.val.u8 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I16) + static_cast(aVariant.val.p)[aIndex] = value; + else + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I32: + case nsXPTType::T_U16: // C++ unsigned short <=> Java int + { + LOG(("int\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jint value = env->CallIntMethod(aParam, intValueMID); + if (aType == nsXPTType::T_I32) + aVariant.val.i32 = value; + else + aVariant.val.u16 = value; + } else { // 'inout' & 'array' + jint value; + if (aParam) { + env->GetIntArrayRegion((jintArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I32) + aVariant.val.i32 = value; + else + aVariant.val.u16 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I32) + static_cast(aVariant.val.p)[aIndex] = value; + else + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_I64: + case nsXPTType::T_U32: // C++ unsigned int <=> Java long + { + LOG(("long\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jlong value = env->CallLongMethod(aParam, longValueMID); + if (aType == nsXPTType::T_I64) + aVariant.val.i64 = value; + else + aVariant.val.u32 = value; + } else { // 'inout' & 'array' + jlong value; + if (aParam) { + env->GetLongArrayRegion((jlongArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_I64) + aVariant.val.i64 = value; + else + aVariant.val.u32 = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_I64) + static_cast(aVariant.val.p)[aIndex] = value; + else + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_FLOAT: + { + LOG(("float\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.f = env->CallFloatMethod(aParam, floatValueMID); + } else { // 'inout' & 'array' + jfloat value; + if (aParam) { + env->GetFloatArrayRegion((jfloatArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.f = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + // XXX how do we handle unsigned 64-bit value? + case nsXPTType::T_U64: // C++ unsigned long <=> Java double + case nsXPTType::T_DOUBLE: + { + LOG(("double\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + jdouble value = env->CallDoubleMethod(aParam, doubleValueMID); + if (aType == nsXPTType::T_DOUBLE) + aVariant.val.d = value; + else + aVariant.val.u64 = static_cast(value); + } else { // 'inout' & 'array' + jdouble value; + if (aParam) { + env->GetDoubleArrayRegion((jdoubleArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + if (aType == nsXPTType::T_DOUBLE) + aVariant.val.d = value; + else + aVariant.val.u64 = static_cast(value); + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + if (aType == nsXPTType::T_DOUBLE) + static_cast(aVariant.val.p)[aIndex] = value; + else + static_cast(aVariant.val.p)[aIndex] = + static_cast(value); + } + } + break; + } + + case nsXPTType::T_BOOL: + { + LOG(("boolean\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.b = env->CallBooleanMethod(aParam, booleanValueMID); + } else { // 'inout' & 'array' + jboolean value; + if (aParam) { + env->GetBooleanArrayRegion((jbooleanArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.b = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_CHAR: + { + LOG(("char\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.c = env->CallCharMethod(aParam, charValueMID); + } else { // 'inout' & 'array' + jchar value; + if (aParam) { + env->GetCharArrayRegion((jcharArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.c = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_WCHAR: + { + LOG(("char\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.wc = env->CallCharMethod(aParam, charValueMID); + } else { // 'inout' & 'array' + jchar value; + if (aParam) { + env->GetCharArrayRegion((jcharArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.wc = value; + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = value; + } + } + break; + } + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + LOG(("String\n")); + jstring data = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' & 'array' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + void* buf = nsnull; + if (data) { + jsize uniLength = env->GetStringLength(data); + if (uniLength > 0) { + if (aType == nsXPTType::T_CHAR_STR) { + jsize utf8Length = env->GetStringUTFLength(data); + buf = nsMemory::Alloc((utf8Length + 1) * sizeof(char)); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + char* char_str = static_cast(buf); + env->GetStringUTFRegion(data, 0, uniLength, char_str); + char_str[utf8Length] = '\0'; + + } else { // if T_WCHAR_STR + buf = nsMemory::Alloc((uniLength + 1) * sizeof(jchar)); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + jchar* jchar_str = static_cast(buf); + env->GetStringRegion(data, 0, uniLength, jchar_str); + jchar_str[uniLength] = '\0'; + } + } else { + // create empty string + buf = nsMemory::Alloc(2); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + ((jchar*)buf)[0] = '\0'; + } + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = buf; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + if (aType == nsXPTType::T_CHAR_STR) { + char* str = static_cast(buf); + static_cast(aVariant.val.p)[aIndex] = str; + } else { + PRUnichar* str = static_cast(buf); + static_cast(aVariant.val.p)[aIndex] = str; + } + } + break; + } + + case nsXPTType::T_IID: + { + LOG(("String(IID)\n")); + jstring data = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' & 'array' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + nsID* iid = new nsID; + if (!iid) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + if (data) { + // extract IID string from Java string + const char* str = env->GetStringUTFChars(data, nsnull); + if (!str) { + delete iid; + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // parse string into IID object + iid->Parse(str); + env->ReleaseStringUTFChars(data, str); + } else { + *iid = nullID; + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = iid; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = iid; + } + break; + } + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + LOG(("nsISupports\n")); + jobject java_obj = nsnull; + if (!aIsOut && !aIsArrayElement) { // 'in' + java_obj = (jobject) aParam; + } else if (aParam) { // 'inout' & 'array' + java_obj = (jobject) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + void* xpcom_obj; + if (java_obj) { + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + nsID iid; + if (aIID.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); + } else { + isWeakRef = PR_FALSE; + iid = aIID; + } + + rv = JavaObjectToNativeInterface(env, java_obj, iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + NS_ENSURE_TRUE(xpcom_obj, NS_ERROR_FAILURE); + nsISupports *xpcom_nat_obj = (nsISupports*) xpcom_obj; + rv = xpcom_nat_obj->QueryInterface(iid, &xpcom_obj); + NS_IF_RELEASE(xpcom_nat_obj); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. + if (isWeakRef) { + nsISupports* isupports = (nsISupports*) xpcom_obj; + nsCOMPtr supportsweak = + do_QueryInterface(isupports); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + NS_RELEASE(isupports); + xpcom_obj = weakref; + NS_ADDREF((nsISupports*) xpcom_obj); + } else { + xpcom_obj = nsnull; + } + } + } else { + xpcom_obj = nsnull; + } + + if (!aIsArrayElement) { // 'in' & 'inout' + aVariant.val.p = xpcom_obj; + aVariant.SetValIsInterface(); + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = xpcom_obj; + } + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + LOG(("String\n")); + // Expecting only 'in' and 'in dipper' + NS_PRECONDITION(!aIsOut, "unexpected param descriptor"); + if (aIsOut) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = static_cast(aParam); + nsAString* str = jstring_to_nsAString(env, jstr); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + aVariant.val.p = str; + aVariant.SetValIsDOMString(); + break; + } + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + LOG(("StringUTF\n")); + // Expecting only 'in' and 'in dipper' + NS_PRECONDITION(!aIsOut, "unexpected param descriptor"); + if (aIsOut) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = static_cast(aParam); + nsACString* str = jstring_to_nsACString(env, jstr); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + aVariant.val.p = str; + if (aType == nsXPTType::T_CSTRING) { + aVariant.SetValIsCString(); + } else { + aVariant.SetValIsUTF8String(); + } + break; + } + + // handle "void *" as an "long" in Java + case nsXPTType::T_VOID: + { + LOG(("long (void*)\n")); + if (!aIsOut && !aIsArrayElement) { // 'in' + aVariant.val.p = + reinterpret_cast(env->CallLongMethod(aParam, longValueMID)); + } else { // 'inout' & 'array' + jlong value; + if (aParam) { + env->GetLongArrayRegion((jlongArray) aParam, aIndex, 1, &value); + } + + if (aIsOut) { // 'inout' + if (aParam) { + aVariant.val.p = reinterpret_cast(value); + aVariant.ptr = &aVariant.val; + } else { + aVariant.ptr = nsnull; + } + aVariant.SetPtrIsData(); + } else { // 'array' + static_cast(aVariant.val.p)[aIndex] = + reinterpret_cast(value); + } + } + break; + } + + case nsXPTType::T_ARRAY: + { + jobject sourceArray = nsnull; + if (!aIsOut) { // 'in' + sourceArray = aParam; + } else if (aParam) { // 'inout' + jobjectArray array = static_cast(aParam); + sourceArray = env->GetObjectArrayElement(array, 0); + } + + if (sourceArray) { + rv = CreateNativeArray(aArrayType, aArraySize, &aVariant.val.p); + + for (PRUint32 i = 0; i < aArraySize && NS_SUCCEEDED(rv); i++) { + rv = SetupParams(env, sourceArray, aArrayType, PR_FALSE, aIID, 0, 0, + PR_TRUE, i, aVariant); + } + } + + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val.p; + aVariant.SetPtrIsData(); + } + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + { + NS_PRECONDITION(!aIsArrayElement, "sized string array not supported"); + + LOG(("Sized string\n")); + jstring data = nsnull; + if (!aIsOut) { // 'in' + data = (jstring) aParam; + } else if (aParam) { // 'inout' + data = (jstring) env->GetObjectArrayElement((jobjectArray) aParam, + aIndex); + } + + PRUint32 length = 0; + if (data) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + length = env->GetStringUTFLength(data); + } else { + length = env->GetStringLength(data); + } + if (length > aArraySize) { + rv = NS_ERROR_ILLEGAL_VALUE; + break; + } + } + + PRUint32 size_of_char = (aType == nsXPTType::T_PSTRING_SIZE_IS) ? + sizeof(char) : sizeof(jchar); + PRUint32 allocLength = (aArraySize + 1) * size_of_char; + void* buf = nsMemory::Alloc(allocLength); + if (!buf) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (data) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + const char* str = env->GetStringUTFChars(data, nsnull); + if (!str) { + nsMemory::Free(buf); + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + memcpy(buf, str, length); + env->ReleaseStringUTFChars(data, str); + } else { + jchar* jchar_str = static_cast(buf); + env->GetStringRegion(data, 0, length, jchar_str); + } + } + + aVariant.val.p = buf; + if (aIsOut) { // 'inout' + aVariant.ptr = &aVariant.val; + aVariant.SetPtrIsData(); + } + + break; + } + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +/** + * Does any cleanup from objects created in SetupParams, as well as converting + * any out params to Java. + * + * NOTE: If aInvokeResult is an error condition, then we just do cleanup in + * this function. + */ +nsresult +FinalizeParams(JNIEnv *env, const nsXPTParamInfo &aParamInfo, PRUint8 aType, + nsXPTCVariant &aVariant, const nsID& aIID, + PRBool aIsArrayElement, PRUint8 aArrayType, PRUint32 aArraySize, + PRUint32 aIndex, nsresult aInvokeResult, jobject* aParam) +{ + nsresult rv = NS_OK; + + switch (aType) + { + case nsXPTType::T_I8: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jbyte value = aVariant.val.i8; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(byteClass, byteInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetByteArrayRegion((jbyteArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jshort value = (aType == nsXPTType::T_I16) ? aVariant.val.i16 : + aVariant.val.u8; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(shortClass, shortInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetShortArrayRegion((jshortArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jint value = (aType == nsXPTType::T_I32) ? aVariant.val.i32 : + aVariant.val.u16; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(intClass, intInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetIntArrayRegion((jintArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jlong value = (aType == nsXPTType::T_I64) ? aVariant.val.i64 : + aVariant.val.u32; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(longClass, longInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetLongArrayRegion((jlongArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_FLOAT: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jfloat value = aVariant.val.f; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(floatClass, floatInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetFloatArrayRegion((jfloatArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jdouble value = (aType == nsXPTType::T_DOUBLE) ? aVariant.val.d : + aVariant.val.u64; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(doubleClass, doubleInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetDoubleArrayRegion((jdoubleArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_BOOL: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jboolean value = aVariant.val.b; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(booleanClass, booleanInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetBooleanArrayRegion((jbooleanArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jchar value; + if (aType == nsXPTType::T_CHAR) + value = aVariant.val.c; + else + value = aVariant.val.wc; + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(charClass, charInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetCharArrayRegion((jcharArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + // create new string from data + jstring str = nsnull; + if (aVariant.val.p) { + if (aType == nsXPTType::T_CHAR_STR) { + str = env->NewStringUTF((const char*) aVariant.val.p); + } else { + PRUint32 length = nsCRT::strlen((const PRUnichar*) aVariant.val.p); + str = env->NewString((const jchar*) aVariant.val.p, length); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // cleanup + if (aVariant.val.p) + nsMemory::Free(aVariant.val.p); + break; + } + + case nsXPTType::T_IID: + { + nsID* iid = static_cast(aVariant.val.p); + + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + // Create the string from nsID + jstring str = nsnull; + if (iid) { + char iid_str[NSID_LENGTH]; + iid->ToProvidedString(iid_str); + str = env->NewStringUTF(iid_str); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // Ordinarily, we would delete 'iid' here. But we cannot do that until + // we've handled all of the params. See comment in CallXPCOMMethod. + // We can safely delete array elements, though. + if (aIsArrayElement) + delete iid; + + break; + } + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsISupports* xpcom_obj = static_cast(aVariant.val.p); + + if ((aParamInfo.IsOut() || aIsArrayElement) && + NS_SUCCEEDED(aInvokeResult)) + { + jobject java_obj = nsnull; + if (xpcom_obj) { + // Get matching Java object for given xpcom object + rv = NativeInterfaceToJavaObject(env, xpcom_obj, aIID, nsnull, + &java_obj); + if (NS_FAILED(rv)) + break; + } + + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = java_obj; + } else if (*aParam) { + // put new Java object into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, java_obj); + } + } + + // cleanup + NS_IF_RELEASE(xpcom_obj); + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsString* str = static_cast(aVariant.val.p); + if (NS_SUCCEEDED(aInvokeResult) && aParamInfo.IsDipper()) { + // Create Java string from returned nsString + jstring jstr = nsnull; + if (str && !str->IsVoid()) { + jstr = env->NewString((const jchar*) str->get(), str->Length()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + *aParam = jstr; + } + + // cleanup + if (str) { + delete str; + } + break; + } + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsCString* str = static_cast(aVariant.val.p); + if (NS_SUCCEEDED(aInvokeResult) && aParamInfo.IsDipper()) { + // Create Java string from returned nsString + jstring jstr = nsnull; + if (str && !str->IsVoid()) { + jstr = env->NewStringUTF((const char*) str->get()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + *aParam = jstr; + } + + // cleanup + if (str) { + delete str; + } + break; + } + + case nsXPTType::T_VOID: + { + if (NS_SUCCEEDED(aInvokeResult)) { + jlong value = reinterpret_cast(aVariant.val.p); + if (aParamInfo.IsRetval() && !aIsArrayElement) { + *aParam = env->NewObject(longClass, longInitMID, value); + } else if ((aParamInfo.IsOut() || aIsArrayElement) && *aParam) { + env->SetLongArrayRegion((jlongArray) *aParam, aIndex, 1, &value); + } + } + break; + } + + case nsXPTType::T_ARRAY: + { + if (aParamInfo.IsOut() && NS_SUCCEEDED(aInvokeResult)) { + // Create Java array from returned native array + jobject jarray = nsnull; + if (aVariant.val.p) { + rv = CreateJavaArray(env, aArrayType, aArraySize, aIID, &jarray); + if (NS_FAILED(rv)) + break; + + nsXPTCVariant var; + for (PRUint32 i = 0; i < aArraySize && NS_SUCCEEDED(rv); i++) { + rv = GetNativeArrayElement(aArrayType, aVariant.val.p, i, &var); + if (NS_SUCCEEDED(rv)) { + rv = FinalizeParams(env, aParamInfo, aArrayType, var, aIID, + PR_TRUE, 0, 0, i, aInvokeResult, &jarray); + } + } + } + + if (aParamInfo.IsRetval()) { + *aParam = jarray; + } else if (*aParam) { + // put new Java array into output array + env->SetObjectArrayElement((jobjectArray) *aParam, 0, jarray); + } + } + + // cleanup + // If this is not an out param or if the invokeResult is a failure case, + // then the array elements have not been cleaned up. Do so now. + if (!aParamInfo.IsOut() || (NS_FAILED(aInvokeResult) && aVariant.val.p)) { + nsXPTCVariant var; + for (PRUint32 i = 0; i < aArraySize; i++) { + rv = GetNativeArrayElement(aArrayType, aVariant.val.p, i, &var); + if (NS_SUCCEEDED(rv)) { + FinalizeParams(env, aParamInfo, aArrayType, var, aIID, PR_TRUE, + 0, 0, i, NS_ERROR_FAILURE, nsnull); + } + } + } + PR_Free(aVariant.val.p); + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + { + NS_PRECONDITION(!aIsArrayElement, "sized string array not supported"); + + if ((aParamInfo.IsOut()) && NS_SUCCEEDED(aInvokeResult)) + { + // create new string from data + jstring str = nsnull; + if (aVariant.val.p) { + if (aType == nsXPTType::T_PSTRING_SIZE_IS) { + PRUint32 len = (aArraySize + 1) * sizeof(char); + char* buf = (char*) nsMemory::Alloc(len); + if (buf) { + memcpy(buf, aVariant.val.p, len); + buf[aArraySize] = '\0'; + str = env->NewStringUTF((const char*) buf); + nsMemory::Free(buf); + } + } else { + str = env->NewString((const jchar*) aVariant.val.p, aArraySize); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (aParamInfo.IsRetval()) { + *aParam = str; + } else if (*aParam) { + // put new string into output array + env->SetObjectArrayElement((jobjectArray) *aParam, aIndex, str); + } + } + + // cleanup + if (aVariant.val.p) + nsMemory::Free(aVariant.val.p); + break; + } + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + // Check for Java exception, but don't overwrite pre-existing error code. + if (NS_SUCCEEDED(rv) && env->ExceptionCheck()) + rv = NS_ERROR_FAILURE; + + return rv; +} + +nsresult +QueryAttributeInfo(nsIInterfaceInfo* aIInfo, const char* aMethodName, + PRBool aCapitalizedAttr, PRUint16* aMethodIndex, + const nsXPTMethodInfo** aMethodInfo) + +{ + nsresult rv = NS_ERROR_FAILURE; + + // An 'attribute' will start with either "get" or "set". But first, + // we check the length, in order to skip over method names that match exactly + // "get" or "set". + if (strlen(aMethodName) > 3) { + if (strncmp("get", aMethodName, 3) == 0) { + char* getterName = strdup(aMethodName + 3); + if (!aCapitalizedAttr) { + getterName[0] = tolower(getterName[0]); + } + rv = aIInfo->GetMethodInfoForName(getterName, aMethodIndex, aMethodInfo); + free(getterName); + } else if (strncmp("set", aMethodName, 3) == 0) { + char* setterName = strdup(aMethodName + 3); + if (!aCapitalizedAttr) { + setterName[0] = tolower(setterName[0]); + } + rv = aIInfo->GetMethodInfoForName(setterName, aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) { + // If this succeeded, GetMethodInfoForName will have returned the + // method info for the 'getter'. We want the 'setter', so increase + // method index by one ('setter' immediately follows the 'getter'), + // and get its method info. + (*aMethodIndex)++; + rv = aIInfo->GetMethodInfo(*aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) { + // Double check that this methodInfo matches the given method. + if (!(*aMethodInfo)->IsSetter() || + strcmp(setterName, (*aMethodInfo)->name) != 0) { + rv = NS_ERROR_FAILURE; + } + } + } + free(setterName); + } + } + + return rv; +} + +/** + * Given an interface info struct and a method name, returns the method info + * and index, if that method exists. + * + * Most method names are lower case. Unfortunately, the method names of some + * interfaces (such as nsIAppShell) start with a capital letter. This function + * will try all of the permutations. + */ +nsresult +QueryMethodInfo(nsIInterfaceInfo* aIInfo, const char* aMethodName, + PRUint16* aMethodIndex, const nsXPTMethodInfo** aMethodInfo) +{ + // Skip over any leading underscores, since these are methods that conflicted + // with existing Java keywords + const char* methodName = aMethodName; + if (methodName[0] == '_') { + methodName++; + } + + // The common case is that the method name is lower case, so we check + // that first. + nsresult rv; + rv = aIInfo->GetMethodInfoForName(methodName, aMethodIndex, aMethodInfo); + if (NS_SUCCEEDED(rv)) + return rv; + + // If there is no method called , then maybe it is an + // 'attribute'. + rv = QueryAttributeInfo(aIInfo, methodName, PR_FALSE, aMethodIndex, + aMethodInfo); + if (NS_SUCCEEDED(rv)) + return rv; + + // If we get here, then maybe the method name is capitalized. + char* name = strdup(methodName); + name[0] = toupper(name[0]); + rv = aIInfo->GetMethodInfoForName(name, aMethodIndex, aMethodInfo); + free(name); + if (NS_SUCCEEDED(rv)) + return rv; + + // If there is no method called , then maybe it is an + // 'attribute'. + rv = QueryAttributeInfo(aIInfo, methodName, PR_TRUE, aMethodIndex, + aMethodInfo); + + return rv; +} + +#ifdef VBOX +#include +#include +#include "nspr.h" + +static void makeErrorMessage(nsresult r, char* msg, size_t msgSize) +{ + bool gotMsg = false; + + if (!gotMsg) + { + nsresult rc; + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr em; + rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr ex; + rc = em->GetCurrentException(getter_AddRefs (ex)); + if (NS_SUCCEEDED (rc) && ex) + { + nsXPIDLCString emsg; + ex->GetMessage(getter_Copies(emsg)); + PR_snprintf(msg, msgSize, "%s", + emsg.get()); + gotMsg = true; + } + } + } + } + + if (!gotMsg) + { + const RTCOMERRMSG* pMsg = RTErrCOMGet(r); + if (strncmp(pMsg->pszMsgFull, "Unknown", 7) != 0) + { + PR_snprintf(msg, msgSize, "%s (%s)", + pMsg->pszMsgFull, pMsg->pszDefine); + gotMsg = true; + } + } + + if (!gotMsg) + { + PR_snprintf(msg, msgSize, "Error 0x%x in module 0x%x", + NS_ERROR_GET_CODE(r), NS_ERROR_GET_MODULE(r)); + } +} +#endif + +/** + * org.mozilla.xpcom.XPCOMJavaProxy.internal.callXPCOMMethod + */ +extern "C" NS_EXPORT jobject JNICALL +JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, + jstring aMethodName, jobjectArray aParams) +{ + nsresult rv; + + // Get native XPCOM instance + void* xpcom_obj; + rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj); + if (NS_FAILED(rv)) { + ThrowException(env, 0, "Failed to get matching XPCOM object"); + return nsnull; + } + JavaXPCOMInstance* inst = static_cast(xpcom_obj); + + // Get method info + PRUint16 methodIndex; + const nsXPTMethodInfo* methodInfo; + nsIInterfaceInfo* iinfo = inst->InterfaceInfo(); + const char* methodName = env->GetStringUTFChars(aMethodName, nsnull); + rv = QueryMethodInfo(iinfo, methodName, &methodIndex, &methodInfo); + env->ReleaseStringUTFChars(aMethodName, methodName); + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "GetMethodInfoForName failed"); + return nsnull; + } + +#ifdef DEBUG_JAVAXPCOM + const char* ifaceName; + iinfo->GetNameShared(&ifaceName); + LOG(("===> (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); +#endif + + // Convert the Java params + PRUint8 paramCount = methodInfo->GetParamCount(); + nsXPTCVariant* params = nsnull; + if (paramCount) + { + params = new nsXPTCVariant[paramCount]; + if (!params) { + ThrowException(env, NS_ERROR_OUT_OF_MEMORY, "Can't create params array"); + return nsnull; + } + memset(params, 0, paramCount * sizeof(nsXPTCVariant)); + + PRBool foundDependentParam = PR_FALSE; + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + LOG(("\t Param %d: ", i)); + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + params[i].type = paramInfo.GetType(); + + if (params[i].type.IsDependent() && paramInfo.IsIn()) { + foundDependentParam = PR_TRUE; + continue; + } + + if (paramInfo.IsIn()) { + PRUint8 type = params[i].type.TagPart(); + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE) { + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, type, + methodIndex, params, PR_TRUE, iid); + } + + if (NS_SUCCEEDED(rv)) { + jobject param = nsnull; + if (aParams && !paramInfo.IsRetval()) { + param = env->GetObjectArrayElement(aParams, i); + } + rv = SetupParams(env, param, type, paramInfo.IsOut(), iid, 0, 0, + PR_FALSE, 0, params[i]); + } + } else { + LOG(("out/retval\n")); + params[i].ptr = &(params[i].val); + params[i].SetPtrIsData(); + } + } + + // Handle any dependent params by doing a second pass + if (foundDependentParam) { + + for (PRUint8 j = 0; j < paramCount && NS_SUCCEEDED(rv); j++) { + + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(j); + params[j].type = paramInfo.GetType(); + + if (!params[j].type.IsDependent()) + continue; + + if (paramInfo.IsIn()) { + PRUint8 type = params[j].type.TagPart(); + + // is paramater an array or sized string? + PRUint8 arrayType = 0; + PRUint32 arraySize = 0; + PRBool isArray = params[j].type.IsArray(); + PRBool isSizedString = isArray ? PR_FALSE : + type == nsXPTType::T_PSTRING_SIZE_IS || + type == nsXPTType::T_PWSTRING_SIZE_IS; + + if (isArray) { + // get array type + nsXPTType xpttype; + rv = iinfo->GetTypeForParam(methodIndex, ¶mInfo, 1, &xpttype); + if (NS_FAILED(rv)) + break; + arrayType = xpttype.TagPart(); + // IDL 'octet' arrays are not 'promoted' to short, but kept as 'byte'; + // therefore, treat as a signed 8bit value + if (arrayType == nsXPTType::T_U8) + arrayType = nsXPTType::T_I8; + } + + if (isArray || isSizedString) { + // get size of array or string + PRUint8 argnum; + rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, ¶mInfo, 0, + &argnum); + if (NS_FAILED(rv)) + break; + arraySize = params[argnum].val.u32; + } + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE_IS || + (type == nsXPTType::T_ARRAY && + (arrayType == nsXPTType::T_INTERFACE || + arrayType == nsXPTType::T_INTERFACE_IS))) + { + PRUint8 paramType = type == nsXPTType::T_ARRAY ? arrayType : type; + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, paramType, + methodIndex, params, PR_TRUE, iid); + } + + if (NS_SUCCEEDED(rv)) { + jobject param = nsnull; + if (aParams && !paramInfo.IsRetval()) { + param = env->GetObjectArrayElement(aParams, j); + } + rv = SetupParams(env, param, type, paramInfo.IsOut(), iid, arrayType, + arraySize, PR_FALSE, 0, params[j]); + } + } + } + } + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "SetupParams failed"); + return nsnull; + } + } + + // Call the XPCOM method + const nsIID* iid; + iinfo->GetIIDShared(&iid); + nsISupports* realObject; + rv = inst->GetInstance()->QueryInterface(*iid, (void**) &realObject); + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to get real XPCOM object"); + return nsnull; + } + nsresult invokeResult = NS_InvokeByIndex(realObject, methodIndex, + paramCount, params); + NS_RELEASE(realObject); + + // Clean up params + jobject result = nsnull; + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(i); + PRUint8 type = paramInfo.GetType().TagPart(); + + // is paramater an array or sized string? + PRUint8 arrayType = 0; + PRUint32 arraySize = 0; + PRBool isArray = params[i].type.IsArray(); + PRBool isSizedString = isArray ? PR_FALSE : + type == nsXPTType::T_PSTRING_SIZE_IS || + type == nsXPTType::T_PWSTRING_SIZE_IS; + + if (isArray) { + // get array type + nsXPTType array_xpttype; + rv = iinfo->GetTypeForParam(methodIndex, ¶mInfo, 1, &array_xpttype); + if (NS_FAILED(rv)) + break; + arrayType = array_xpttype.TagPart(); + // IDL 'octet' arrays are not 'promoted' to short, but kept as 'byte'; + // therefore, treat as a signed 8bit value + if (arrayType == nsXPTType::T_U8) + arrayType = nsXPTType::T_I8; + } + + if (isArray || isSizedString) { + // get size of array + PRUint8 argnum; + rv = iinfo->GetSizeIsArgNumberForParam(methodIndex, ¶mInfo, 0, + &argnum); + if (NS_FAILED(rv)) + break; + arraySize = params[argnum].val.u32; + } + + // get IID for interface params + nsID iid; + if (type == nsXPTType::T_INTERFACE || type == nsXPTType::T_INTERFACE_IS || + (type == nsXPTType::T_ARRAY && (arrayType == nsXPTType::T_INTERFACE || + arrayType == nsXPTType::T_INTERFACE_IS))) + { + PRUint8 paramType = type == nsXPTType::T_ARRAY ? arrayType : type; + rv = GetIIDForMethodParam(iinfo, methodInfo, paramInfo, paramType, + methodIndex, params, PR_TRUE, iid); + if (NS_FAILED(rv)) + break; + } + + jobject* javaElement; + jobject element = nsnull; + if (!paramInfo.IsRetval()) { + element = env->GetObjectArrayElement(aParams, i); + javaElement = &element; + } else { + javaElement = &result; + } + rv = FinalizeParams(env, paramInfo, type, params[i], iid, PR_FALSE, + arrayType, arraySize, 0, invokeResult, javaElement); + } + + // Normally, we would delete any created nsID object in the above loop. + // However, GetIIDForMethodParam may need some of the nsID params when it's + // looking for the IID of an INTERFACE_IS. Therefore, we can't delete it + // until we've gone through the 'Finalize' loop once and created the result. + for (PRUint8 j = 0; j < paramCount; j++) + { + const nsXPTParamInfo ¶mInfo = methodInfo->GetParam(j); + const nsXPTType &type = paramInfo.GetType(); + if (type.TagPart() == nsXPTType::T_IID) { + nsID* iid = (nsID*) params[j].val.p; + delete iid; + } + } + + if (params) { + delete params; + } + + // If the XPCOM method invocation failed, we don't immediately throw an + // exception and return so that we can clean up any parameters. + if (NS_FAILED(invokeResult)) { + nsCAutoString message("The function \""); + message.AppendASCII(methodInfo->GetName()); + message.AppendLiteral("\" returned an error condition"); +#ifdef VBOX + char vboxMsg[1024]; + message.AppendLiteral(": \""); + makeErrorMessage(invokeResult, vboxMsg, sizeof vboxMsg); + message.AppendASCII(vboxMsg); + message.AppendLiteral("\""); +#endif + ThrowException(env, invokeResult, message.get()); + } + if (NS_FAILED(rv)) { + ThrowException(env, rv, "FinalizeParams failed"); + return nsnull; + } + + LOG(("<=== (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); + return result; +} + +nsresult +GetNewOrUsedJavaWrapper(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + // Get the root nsISupports of the xpcom object + nsresult rv; + nsCOMPtr rootObject = do_QueryInterface(aXPCOMObject, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Get associated Java object from hash table + rv = gNativeToJavaProxyMap->Find(env, rootObject, aIID, aResult); + NS_ENSURE_SUCCESS(rv, rv); + if (*aResult) + return NS_OK; + + // No Java object is associated with the given XPCOM object, so we + // create a Java proxy. + + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ASSERTION(iim, "Failed to get InterfaceInfoManager"); + if (!iim) + return NS_ERROR_FAILURE; + + // Get interface info for class + nsCOMPtr info; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(info)); + if (NS_FAILED(rv)) + return rv; + + // Wrap XPCOM object (addrefs rootObject) + JavaXPCOMInstance* inst = new JavaXPCOMInstance(rootObject, info); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + // Get interface name + const char* iface_name; + rv = info->GetNameShared(&iface_name); + + if (NS_SUCCEEDED(rv)) { + jobject java_obj = nsnull; + + // Create proper Java interface name + nsCAutoString class_name("org.mozilla.interfaces."); + class_name.AppendASCII(iface_name); + jclass ifaceClass = FindClassInLoader(env, aObjectLoader, class_name.get()); + + if (ifaceClass) { + java_obj = env->CallStaticObjectMethod(xpcomJavaProxyClass, + createProxyMID, ifaceClass, + reinterpret_cast(inst)); + if (env->ExceptionCheck()) + java_obj = nsnull; + } + + if (java_obj) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ CreateJavaProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + java_obj), + (PRUint32) rootObject, iid_str)); + PR_Free(iid_str); +#endif + + // Associate XPCOM object with Java proxy + rv = gNativeToJavaProxyMap->Add(env, rootObject, aIID, java_obj); + if (NS_SUCCEEDED(rv)) { + *aResult = java_obj; + return NS_OK; + } + } else { + rv = NS_ERROR_FAILURE; + } + } + + // If there was an error, clean up. + delete inst; + return rv; +} + +nsresult +GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + jlong xpcom_obj = env->CallStaticLongMethod(xpcomJavaProxyClass, + getNativeXPCOMInstMID, aJavaObject); + + if (!xpcom_obj || env->ExceptionCheck()) { + return NS_ERROR_FAILURE; + } + + *aResult = reinterpret_cast(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + JavaXPCOMInstance* inst = static_cast(*aResult); + nsIID* iid; + inst->InterfaceInfo()->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< GetXPCOMInstFromProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaObject), + (PRUint32) inst->GetInstance(), iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + return NS_OK; +} + +/** + * org.mozilla.xpcom.internal.XPCOMJavaProxy.finalizeProxy + */ +extern "C" NS_EXPORT void JNICALL +JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy) +{ +#ifdef DEBUG_JAVAXPCOM + PRUint32 xpcom_addr = 0; +#endif + + // Due to Java's garbage collection, this finalize statement may get called + // after FreeJavaGlobals(). So check to make sure that everything is still + // initialized. + if (gJavaXPCOMLock) { + nsAutoLock lock(gJavaXPCOMLock); + + // If may be possible for the lock to be acquired here when FreeGlobals is + // in the middle of running. If so, then this thread will sleep until + // FreeGlobals releases its lock. At that point, we resume this thread + // here, but JavaXPCOM may no longer be initialized. So we need to check + // that everything is legit after acquiring the lock. + if (gJavaXPCOMInitialized) { + // Get native XPCOM instance + void* xpcom_obj; + nsresult rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj); + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst = static_cast(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + xpcom_addr = reinterpret_cast(inst->GetInstance()); +#endif + nsIID* iid; + rv = inst->InterfaceInfo()->GetInterfaceIID(&iid); + if (NS_SUCCEEDED(rv)) { + rv = gNativeToJavaProxyMap->Remove(env, inst->GetInstance(), *iid); + nsMemory::Free(iid); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to RemoveJavaProxy"); + // Release gJavaXPCOMLock before deleting inst (see bug 340022) + lock.unlock(); + delete inst; + } + } + } + +#ifdef DEBUG_JAVAXPCOM + LOG(("- Finalize (Java=%08x | XPCOM=%08x)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaProxy), + xpcom_addr)); +#endif +} + +/** + * org.mozilla.xpcom.XPCOMJavaProxy.isSameXPCOMObject + */ +extern "C" NS_EXPORT jboolean JNICALL +JAVAPROXY_NATIVE(isSameXPCOMObject) (JNIEnv *env, jclass that, + jobject aProxy1, jobject aProxy2) +{ + void* xpcom_obj1; + nsresult rv = GetXPCOMInstFromProxy(env, aProxy1, &xpcom_obj1); + if (NS_SUCCEEDED(rv)) { + void* xpcom_obj2; + rv = GetXPCOMInstFromProxy(env, aProxy2, &xpcom_obj2); + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst1 = static_cast(xpcom_obj1); + JavaXPCOMInstance* inst2 = static_cast(xpcom_obj2); + if (inst1->GetInstance() == inst2->GetInstance()) { + return JNI_TRUE; + } + } + } + return JNI_FALSE; +} + +/** + * org.mozilla.xpcom.ProfileLock.release + */ +extern "C" NS_EXPORT void JNICALL +LOCKPROXY_NATIVE(release) (JNIEnv *env, jclass that, jlong aLockObject) +{ + // Need to release object on the main thread. + nsresult rv = NS_ERROR_FAILURE; +#ifdef VBOX + rv = NS_ProxyRelease(do_GetMainThreadQueue().get(), reinterpret_cast(aLockObject)); +#else + nsCOMPtr thread = do_GetMainThread(); + if (thread) { + rv = NS_ProxyRelease(thread, reinterpret_cast(aLockObject)); + } +#endif + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaWrapper.h b/src/libs/xpcom18a4/java/src/nsJavaWrapper.h new file mode 100644 index 00000000..c441a41c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaWrapper.h @@ -0,0 +1,75 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsJavaWrapper_h_ +#define _nsJavaWrapper_h_ + +#include "jni.h" +#include "nsISupports.h" + + +/** + * Finds the associated Java wraper for the given XPCOM object and IID. If no + * such Java wrapper exists, then a new one is created. + * + * @param env Java environment pointer + * @param aXPCOMObject XPCOM object for which to find/create Java wrapper + * @param aIID desired interface IID for Java wrapper + * @param aObjectLoader Java wrapper whose class loader we use for finding + * classes; can be null + * @param aResult on success, holds reference to Java wrapper + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult GetNewOrUsedJavaWrapper(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult); + +/** + * Returns the XPCOM object for which the given Java proxy was created. + * + * @param env pointer to Java context + * @param aJavaObject a Java proxy created by CreateJavaProxy() + * @param aResult on exit, holds pointer to XPCOM instance + * + * @return NS_OK if the XPCOM object was successfully retrieved; + * any other value denotes an error condition. + */ +nsresult GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, + void** aResult); + +#endif // _nsJavaWrapper_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp new file mode 100644 index 00000000..f91fdd83 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.cpp @@ -0,0 +1,1084 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsJavaXPCOMBindingUtils.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaWrapper.h" +#include "jni.h" +#include "nsIInterfaceInfoManager.h" +#include "nsThreadUtils.h" +#include "nsProxyRelease.h" +#ifdef VBOX +#ifndef NS_INT32_TO_PTR +#define NS_INT32_TO_PTR(x) ((void *)((char *)0 + (x))) +#endif +#endif + + +/* Java JNI globals */ + +JavaVM* gCachedJVM = nsnull; + +jclass systemClass = nsnull; +jclass booleanClass = nsnull; +jclass charClass = nsnull; +jclass byteClass = nsnull; +jclass shortClass = nsnull; +jclass intClass = nsnull; +jclass longClass = nsnull; +jclass floatClass = nsnull; +jclass doubleClass = nsnull; +jclass stringClass = nsnull; +jclass nsISupportsClass = nsnull; +jclass xpcomExceptionClass = nsnull; +jclass xpcomJavaProxyClass = nsnull; +jclass weakReferenceClass = nsnull; +jclass javaXPCOMUtilsClass = nsnull; + +jmethodID hashCodeMID = nsnull; +jmethodID booleanValueMID = nsnull; +jmethodID booleanInitMID = nsnull; +jmethodID charValueMID = nsnull; +jmethodID charInitMID = nsnull; +jmethodID byteValueMID = nsnull; +jmethodID byteInitMID = nsnull; +jmethodID shortValueMID = nsnull; +jmethodID shortInitMID = nsnull; +jmethodID intValueMID = nsnull; +jmethodID intInitMID = nsnull; +jmethodID longValueMID = nsnull; +jmethodID longInitMID = nsnull; +jmethodID floatValueMID = nsnull; +jmethodID floatInitMID = nsnull; +jmethodID doubleValueMID = nsnull; +jmethodID doubleInitMID = nsnull; +jmethodID createProxyMID = nsnull; +jmethodID isXPCOMJavaProxyMID = nsnull; +jmethodID getNativeXPCOMInstMID = nsnull; +jmethodID weakReferenceConstructorMID = nsnull; +jmethodID getReferentMID = nsnull; +jmethodID clearReferentMID = nsnull; +jmethodID findClassInLoaderMID = nsnull; + +#ifdef DEBUG_JAVAXPCOM +jmethodID getNameMID = nsnull; +jmethodID proxyToStringMID = nsnull; +#endif + +NativeToJavaProxyMap* gNativeToJavaProxyMap = nsnull; +JavaToXPTCStubMap* gJavaToXPTCStubMap = nsnull; + +PRBool gJavaXPCOMInitialized = PR_FALSE; +PRLock* gJavaXPCOMLock = nsnull; + +static const char* kJavaKeywords[] = { + "abstract", "default" , "if" , "private" , "throw" , + "boolean" , "do" , "implements", "protected" , "throws" , + "break" , "double" , "import", "public" , "transient" , + "byte" , "else" , "instanceof", "return" , "try" , + "case" , "extends" , "int" , "short" , "void" , + "catch" , "final" , "interface" , "static" , "volatile" , + "char" , "finally" , "long" , "super" , "while" , + "class" , "float" , "native" , "switch" , + "const" , "for" , "new" , "synchronized", + "continue", "goto" , "package" , "this" , + /* added in Java 1.2 */ + "strictfp", + /* added in Java 1.4 */ + "assert" , + /* added in Java 5.0 */ + "enum" , + /* Java constants */ + "true" , "false" , "null" , + /* java.lang.Object methods * + * - don't worry about "toString", since it does the same thing * + * as Object's "toString" */ + "clone" , "equals" , "finalize" , "getClass" , "hashCode" , + "notify" , "notifyAll", /*"toString" ,*/ "wait" +}; + +nsTHashtable* gJavaKeywords = nsnull; + + +/****************************** + * InitializeJavaGlobals + ******************************/ +PRBool +InitializeJavaGlobals(JNIEnv *env) +{ + if (gJavaXPCOMInitialized) + return PR_TRUE; + + // Save pointer to JavaVM, which is valid across threads. + jint rc = env->GetJavaVM(&gCachedJVM); + if (rc != 0) { + NS_WARNING("Failed to get JavaVM"); + goto init_error; + } + + jclass clazz; + if (!(clazz = env->FindClass("java/lang/System")) || + !(systemClass = (jclass) env->NewGlobalRef(clazz)) || + !(hashCodeMID = env->GetStaticMethodID(clazz, "identityHashCode", + "(Ljava/lang/Object;)I"))) + { + NS_WARNING("Problem creating java.lang.System globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Boolean")) || + !(booleanClass = (jclass) env->NewGlobalRef(clazz)) || + !(booleanValueMID = env->GetMethodID(clazz, "booleanValue", "()Z")) || + !(booleanInitMID = env->GetMethodID(clazz, "", "(Z)V"))) + { + NS_WARNING("Problem creating java.lang.Boolean globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Character")) || + !(charClass = (jclass) env->NewGlobalRef(clazz)) || + !(charValueMID = env->GetMethodID(clazz, "charValue", "()C")) || + !(charInitMID = env->GetMethodID(clazz, "", "(C)V"))) + { + NS_WARNING("Problem creating java.lang.Character globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Byte")) || + !(byteClass = (jclass) env->NewGlobalRef(clazz)) || + !(byteValueMID = env->GetMethodID(clazz, "byteValue", "()B")) || + !(byteInitMID = env->GetMethodID(clazz, "", "(B)V"))) + { + NS_WARNING("Problem creating java.lang.Byte globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Short")) || + !(shortClass = (jclass) env->NewGlobalRef(clazz)) || + !(shortValueMID = env->GetMethodID(clazz, "shortValue", "()S")) || + !(shortInitMID = env->GetMethodID(clazz, "", "(S)V"))) + { + NS_WARNING("Problem creating java.lang.Short globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Integer")) || + !(intClass = (jclass) env->NewGlobalRef(clazz)) || + !(intValueMID = env->GetMethodID(clazz, "intValue", "()I")) || + !(intInitMID = env->GetMethodID(clazz, "", "(I)V"))) + { + NS_WARNING("Problem creating java.lang.Integer globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Long")) || + !(longClass = (jclass) env->NewGlobalRef(clazz)) || + !(longValueMID = env->GetMethodID(clazz, "longValue", "()J")) || + !(longInitMID = env->GetMethodID(clazz, "", "(J)V"))) + { + NS_WARNING("Problem creating java.lang.Long globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Float")) || + !(floatClass = (jclass) env->NewGlobalRef(clazz)) || + !(floatValueMID = env->GetMethodID(clazz, "floatValue", "()F")) || + !(floatInitMID = env->GetMethodID(clazz, "", "(F)V"))) + { + NS_WARNING("Problem creating java.lang.Float globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/Double")) || + !(doubleClass = (jclass) env->NewGlobalRef(clazz)) || + !(doubleValueMID = env->GetMethodID(clazz, "doubleValue", "()D")) || + !(doubleInitMID = env->GetMethodID(clazz, "", "(D)V"))) + { + NS_WARNING("Problem creating java.lang.Double globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/String")) || + !(stringClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating java.lang.String globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/interfaces/nsISupports")) || + !(nsISupportsClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating org.mozilla.interfaces.nsISupports globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/XPCOMException")) || + !(xpcomExceptionClass = (jclass) env->NewGlobalRef(clazz))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.XPCOMException globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMJavaProxy")) || + !(xpcomJavaProxyClass = (jclass) env->NewGlobalRef(clazz)) || + !(createProxyMID = env->GetStaticMethodID(clazz, "createProxy", + "(Ljava/lang/Class;J)Ljava/lang/Object;")) || + !(isXPCOMJavaProxyMID = env->GetStaticMethodID(clazz, "isXPCOMJavaProxy", + "(Ljava/lang/Object;)Z")) || + !(getNativeXPCOMInstMID = env->GetStaticMethodID(xpcomJavaProxyClass, + "getNativeXPCOMInstance", + "(Ljava/lang/Object;)J"))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.internal.XPCOMJavaProxy globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("java/lang/ref/WeakReference")) || + !(weakReferenceClass = (jclass) env->NewGlobalRef(clazz)) || + !(weakReferenceConstructorMID = env->GetMethodID(weakReferenceClass, + "","(Ljava/lang/Object;)V")) || + !(getReferentMID = env->GetMethodID(weakReferenceClass, + "get", "()Ljava/lang/Object;")) || + !(clearReferentMID = env->GetMethodID(weakReferenceClass, + "clear", "()V"))) + { + NS_WARNING("Problem creating java.lang.ref.WeakReference globals"); + goto init_error; + } + + if (!(clazz = env->FindClass("org/mozilla/xpcom/internal/JavaXPCOMMethods")) || + !(javaXPCOMUtilsClass = (jclass) env->NewGlobalRef(clazz)) || + !(findClassInLoaderMID = env->GetStaticMethodID(clazz, + "findClassInLoader", + "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Class;"))) + { + NS_WARNING("Problem creating org.mozilla.xpcom.internal.JavaXPCOMMethods globals"); + goto init_error; + } + +#ifdef DEBUG_JAVAXPCOM + if (!(clazz = env->FindClass("java/lang/Class")) || + !(getNameMID = env->GetMethodID(clazz, "getName","()Ljava/lang/String;"))) + { + NS_WARNING("Problem creating java.lang.Class globals"); + goto init_error; + } + + if (!(proxyToStringMID = env->GetStaticMethodID(xpcomJavaProxyClass, + "proxyToString", + "(Ljava/lang/Object;)Ljava/lang/String;"))) + { + NS_WARNING("Problem creating proxyToString global"); + goto init_error; + } +#endif + + gNativeToJavaProxyMap = new NativeToJavaProxyMap(); + if (!gNativeToJavaProxyMap || NS_FAILED(gNativeToJavaProxyMap->Init())) { + NS_WARNING("Problem creating NativeToJavaProxyMap"); + goto init_error; + } + gJavaToXPTCStubMap = new JavaToXPTCStubMap(); + if (!gJavaToXPTCStubMap || NS_FAILED(gJavaToXPTCStubMap->Init())) { + NS_WARNING("Problem creating JavaToXPTCStubMap"); + goto init_error; + } + + { + nsresult rv = NS_OK; + PRUint32 size = NS_ARRAY_LENGTH(kJavaKeywords); + gJavaKeywords = new nsTHashtable(); + if (!gJavaKeywords || NS_FAILED(gJavaKeywords->Init(size))) { + NS_WARNING("Failed to init JavaKeywords HashSet"); + goto init_error; + } + for (PRUint32 i = 0; i < size && NS_SUCCEEDED(rv); i++) { + if (!gJavaKeywords->PutEntry(kJavaKeywords[i])) { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + if (NS_FAILED(rv)) { + NS_WARNING("Failed to populate JavaKeywords hash"); + goto init_error; + } + } + + gJavaXPCOMLock = PR_NewLock(); + gJavaXPCOMInitialized = PR_TRUE; + return PR_TRUE; + +init_error: + // If we encounter an error during initialization, then free any globals that + // were allocated, and return false. + FreeJavaGlobals(env); + return PR_FALSE; +} + +/************************* + * FreeJavaGlobals + *************************/ +void +FreeJavaGlobals(JNIEnv* env) +{ + PRLock* tempLock = nsnull; + if (gJavaXPCOMLock) { + PR_Lock(gJavaXPCOMLock); + + // null out global lock so no one else can use it + tempLock = gJavaXPCOMLock; + gJavaXPCOMLock = nsnull; + } + + gJavaXPCOMInitialized = PR_FALSE; + + // Free the mappings first, since that process depends on some of the Java + // globals that are freed later. + if (gNativeToJavaProxyMap) { + gNativeToJavaProxyMap->Destroy(env); + delete gNativeToJavaProxyMap; + gNativeToJavaProxyMap = nsnull; + } + if (gJavaToXPTCStubMap) { + gJavaToXPTCStubMap->Destroy(); + delete gJavaToXPTCStubMap; + gJavaToXPTCStubMap = nsnull; + } + + // Free remaining Java globals + if (systemClass) { + env->DeleteGlobalRef(systemClass); + systemClass = nsnull; + } + if (booleanClass) { + env->DeleteGlobalRef(booleanClass); + booleanClass = nsnull; + } + if (charClass) { + env->DeleteGlobalRef(charClass); + charClass = nsnull; + } + if (byteClass) { + env->DeleteGlobalRef(byteClass); + byteClass = nsnull; + } + if (shortClass) { + env->DeleteGlobalRef(shortClass); + shortClass = nsnull; + } + if (intClass) { + env->DeleteGlobalRef(intClass); + intClass = nsnull; + } + if (longClass) { + env->DeleteGlobalRef(longClass); + longClass = nsnull; + } + if (floatClass) { + env->DeleteGlobalRef(floatClass); + floatClass = nsnull; + } + if (doubleClass) { + env->DeleteGlobalRef(doubleClass); + doubleClass = nsnull; + } + if (stringClass) { + env->DeleteGlobalRef(stringClass); + stringClass = nsnull; + } + if (nsISupportsClass) { + env->DeleteGlobalRef(nsISupportsClass); + nsISupportsClass = nsnull; + } + if (xpcomExceptionClass) { + env->DeleteGlobalRef(xpcomExceptionClass); + xpcomExceptionClass = nsnull; + } + if (xpcomJavaProxyClass) { + env->DeleteGlobalRef(xpcomJavaProxyClass); + xpcomJavaProxyClass = nsnull; + } + if (weakReferenceClass) { + env->DeleteGlobalRef(weakReferenceClass); + weakReferenceClass = nsnull; + } + + if (gJavaKeywords) { + delete gJavaKeywords; + gJavaKeywords = nsnull; + } + + if (tempLock) { + PR_Unlock(tempLock); + PR_DestroyLock(tempLock); + } +} + + +/************************************** + * Java<->XPCOM object mappings + **************************************/ + +// NativeToJavaProxyMap: The common case is that each XPCOM object will have +// one Java proxy. But there are instances where there will be multiple Java +// proxies for a given XPCOM object, each representing a different interface. +// So we optimize the common case by using a hash table. Then, if there are +// multiple Java proxies, we cycle through the linked list, comparing IIDs. + +nsresult +NativeToJavaProxyMap::Init() +{ + mHashTable = PL_NewDHashTable(PL_DHashGetStubOps(), nsnull, + sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +PLDHashOperator +DestroyJavaProxyMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData) +{ + JNIEnv* env = static_cast(aData); + NativeToJavaProxyMap::Entry* entry = + static_cast(aHeader); + + // first, delete XPCOM instances from the Java proxies + nsresult rv; + NativeToJavaProxyMap::ProxyList* item = entry->list; + while(item != nsnull) { + void* xpcom_obj; + jobject javaObject = env->CallObjectMethod(item->javaObject, getReferentMID); + rv = GetXPCOMInstFromProxy(env, javaObject, &xpcom_obj); + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get XPCOM instance from Java proxy"); + + if (NS_SUCCEEDED(rv)) { + JavaXPCOMInstance* inst = static_cast(xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + char* iid_str = item->iid.ToString(); + LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + javaObject), + (PRUint32) entry, iid_str)); + PR_Free(iid_str); +#endif + delete inst; // releases native XPCOM object + } + + NativeToJavaProxyMap::ProxyList* next = item->next; + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); + delete item; + item = next; + } + + return PL_DHASH_REMOVE; +} + +nsresult +NativeToJavaProxyMap::Destroy(JNIEnv* env) +{ + // This is only called from FreeGlobals(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + PL_DHashTableEnumerate(mHashTable, DestroyJavaProxyMappingEnum, env); + PL_DHashTableDestroy(mHashTable); + mHashTable = nsnull; + + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Add(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aProxy) +{ + nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast(PL_DHashTableOperate(mHashTable, + aXPCOMObject, + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + jobject ref = nsnull; + jobject weakRefObj = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aProxy); + if (weakRefObj) + ref = env->NewGlobalRef(weakRefObj); + if (!ref) + return NS_ERROR_OUT_OF_MEMORY; + + // Add Java proxy weak reference ref to start of list + ProxyList* item = new ProxyList(ref, aIID, e->list); + e->key = aXPCOMObject; + e->list = item; + +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, aProxy), + (PRUint32) aXPCOMObject, iid_str)); + PR_Free(iid_str); +#endif + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Find(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID, jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + nsAutoLock lock(gJavaXPCOMLock); + + *aResult = nsnull; + Entry* e = static_cast(PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + ProxyList* item = e->list; + while (item != nsnull && *aResult == nsnull) { + if (item->iid.Equals(aIID)) { + jobject referentObj = env->CallObjectMethod(item->javaObject, + getReferentMID); + if (!env->IsSameObject(referentObj, NULL)) { + *aResult = referentObj; +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("< NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + *aResult), + (PRUint32) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + } + } + item = item->next; + } + + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Remove(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID) +{ + // This is only called from finalizeProxy(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast(PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) { + NS_WARNING("XPCOM object not found in hash table"); + return NS_ERROR_FAILURE; + } + + ProxyList* item = e->list; + ProxyList* last = e->list; + while (item != nsnull) { + if (item->iid.Equals(aIID)) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) env->CallStaticIntMethod(systemClass, hashCodeMID, + item->javaObject), + (PRUint32) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + + env->CallVoidMethod(item->javaObject, clearReferentMID); + env->DeleteGlobalRef(item->javaObject); + if (item == e->list) { + e->list = item->next; + if (e->list == nsnull) + PL_DHashTableOperate(mHashTable, aNativeObject, PL_DHASH_REMOVE); + } else { + last->next = item->next; + } + + delete item; + return NS_OK; + } + + last = item; + item = item->next; + } + + NS_WARNING("Java proxy matching given IID not found"); + return NS_ERROR_FAILURE; +} + +nsresult +JavaToXPTCStubMap::Init() +{ + mHashTable = PL_NewDHashTable(PL_DHashGetStubOps(), nsnull, + sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + + +PLDHashOperator +DestroyXPTCMappingEnum(PLDHashTable* aTable, PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData) +{ + JavaToXPTCStubMap::Entry* entry = + static_cast(aHeader); + + // The XPTC stub will be released by the XPCOM side, if it hasn't been + // already. We just need to delete the Java global ref held by the XPTC stub, + // so the Java garbage collector can handle the Java object when necessary. + entry->xptcstub->DeleteStrongRef(); + + return PL_DHASH_REMOVE; +} + +nsresult +JavaToXPTCStubMap::Destroy() +{ + // This is only called from FreeGlobals(), which already holds the lock. + // nsAutoLock lock(gJavaXPCOMLock); + + PL_DHashTableEnumerate(mHashTable, DestroyXPTCMappingEnum, nsnull); + PL_DHashTableDestroy(mHashTable); + mHashTable = nsnull; + + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Add(jint aJavaObjectHashCode, nsJavaXPTCStub* aProxy) +{ + nsAutoLock lock(gJavaXPCOMLock); + + Entry* e = static_cast + (PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + NS_ASSERTION(e->key == nsnull, + "XPTCStub for given Java object already exists in hash table"); + e->key = aJavaObjectHashCode; + e->xptcstub = aProxy; + +#ifdef DEBUG_JAVAXPCOM + nsIInterfaceInfo* iface_info; + aProxy->GetInterfaceInfo(&iface_info); + nsIID* iid; + iface_info->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("+ JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) aJavaObjectHashCode, (PRUint32) aProxy, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); + NS_RELEASE(iface_info); +#endif + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Find(jint aJavaObjectHashCode, const nsIID& aIID, + nsJavaXPTCStub** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + nsAutoLock lock(gJavaXPCOMLock); + + *aResult = nsnull; + Entry* e = static_cast + (PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + nsresult rv = e->xptcstub->QueryInterface(aIID, (void**) aResult); + +#ifdef DEBUG_JAVAXPCOM + if (NS_SUCCEEDED(rv)) { + char* iid_str = aIID.ToString(); + LOG(("< JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) aJavaObjectHashCode, (PRUint32) *aResult, iid_str)); + PR_Free(iid_str); + } +#endif + + // NS_NOINTERFACE is not an error condition + if (rv == NS_NOINTERFACE) + rv = NS_OK; + return rv; +} + +nsresult +JavaToXPTCStubMap::Remove(jint aJavaObjectHashCode) +{ + PL_DHashTableOperate(mHashTable, NS_INT32_TO_PTR(aJavaObjectHashCode), + PL_DHASH_REMOVE); + +#ifdef DEBUG_JAVAXPCOM + LOG(("- JavaToXPTCStubMap (Java=%08x)\n", (PRUint32) aJavaObjectHashCode)); +#endif + + return NS_OK; +} + + +/********************************************************** + * JavaXPCOMInstance + *********************************************************/ +JavaXPCOMInstance::JavaXPCOMInstance(nsISupports* aInstance, + nsIInterfaceInfo* aIInfo) + : mInstance(aInstance) + , mIInfo(aIInfo) +{ + NS_ADDREF(mInstance); + NS_ADDREF(mIInfo); +} + +JavaXPCOMInstance::~JavaXPCOMInstance() +{ + nsresult rv = NS_OK; + +#ifdef VBOX +# if 0 + nsCOMPtr eq = do_GetMainThreadQueue(); + rv = NS_ProxyRelease(eq.get(), mInstance); + rv |= NS_ProxyRelease(eq.get(), mIInfo); +# else + // The above code crashes in nsTraceRefcntImpl::LogAddCOMPtr() (@bugref 7620) + NS_RELEASE(mInstance); + NS_RELEASE(mIInfo); + rv = NS_OK; +# endif +#else + // Need to release these objects on the main thread. + nsCOMPtr thread = do_GetMainThread(); + if (thread) { + rv = NS_ProxyRelease(thread, mInstance); + rv |= NS_ProxyRelease(thread, mIInfo); + } +#endif + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to release using NS_ProxyRelease"); +} + + +/******************************* + * Helper functions + *******************************/ + +nsresult +NativeInterfaceToJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + // If the object is an nsJavaXPTCStub, then get the Java object directly + nsJavaXPTCStub* stub = nsnull; + aXPCOMObject->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub); + if (stub) { + *aResult = stub->GetJavaObject(); + NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object"); + NS_RELEASE(stub); + return NS_OK; + } + + // ... else, get a Java wrapper for the native object + return GetNewOrUsedJavaWrapper(env, aXPCOMObject, aIID, aObjectLoader, + aResult); +} + +nsresult +JavaObjectToNativeInterface(JNIEnv* env, jobject aJavaObject, const nsIID& aIID, + void** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + *aResult = nsnull; + + // If the given Java object is one of our Java proxies, then query the + // associated XPCOM object directly from the proxy. + jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass, + isXPCOMJavaProxyMID, + aJavaObject); + if (env->ExceptionCheck()) + return NS_ERROR_FAILURE; + + if (isProxy) { + void* inst; + rv = GetXPCOMInstFromProxy(env, aJavaObject, &inst); + NS_ENSURE_SUCCESS(rv, rv); + + nsISupports* rootObject = + static_cast(inst)->GetInstance(); + rv = rootObject->QueryInterface(aIID, aResult); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + // ... else, we get an nsJavaXPTCStub + return nsJavaXPTCStub::GetNewOrUsed(env, aJavaObject, aIID, aResult); +} + +nsresult +GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const XPTMethodDescriptor *methodInfo, + const nsXPTParamInfo ¶mInfo, PRUint8 paramType, + PRUint16 methodIndex, nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, nsID &result) +{ + nsresult rv; + + switch (paramType) + { + case nsXPTType::T_INTERFACE: + rv = iinfo->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, &result); + break; + + case nsXPTType::T_INTERFACE_IS: + { + PRUint8 argnum; + rv = iinfo->GetInterfaceIsArgNumberForParam(methodIndex, ¶mInfo, + &argnum); + if (NS_FAILED(rv)) + break; + + const nsXPTParamInfo& arg_param = methodInfo->params[argnum]; + const nsXPTType& arg_type = arg_param.GetType(); + + // The xpidl compiler ensures this. We reaffirm it for safety. + if (!arg_type.IsPointer() || arg_type.TagPart() != nsXPTType::T_IID) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsID *p = nsnull; + if (isFullVariantArray) { + p = (nsID *) ((nsXPTCVariant*) dispatchParams)[argnum].val.p; + } else { + p = (nsID *) dispatchParams[argnum].val.p; + } + if (!p) + return NS_ERROR_UNEXPECTED; + + result = *p; + break; + } + + default: + rv = NS_ERROR_UNEXPECTED; + } + return rv; +} + + +/******************************* + * JNI helper functions + *******************************/ + +JNIEnv* +GetJNIEnv() +{ + JNIEnv* env = nsnull; + jint rc = gCachedJVM->GetEnv((void**) &env, JNI_VERSION_1_2); +#ifdef VBOX + if (env == nsnull) + { + rc = gCachedJVM->AttachCurrentThreadAsDaemon((void**)&env, nsnull); + printf("attaching\n"); + } +#endif + NS_ASSERTION(rc == JNI_OK && env != nsnull, + "Current thread not attached to given JVM instance"); + return env; +} + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage) +{ + // Only throw this exception if one hasn't already been thrown, so we don't + // mask a previous exception/error. + if (env->ExceptionCheck()) + return; + + // If the error code we get is for an Out Of Memory error, try to throw an + // OutOfMemoryError. The JVM may have enough memory to create this error. + if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) { + jclass clazz = env->FindClass("java/lang/OutOfMemoryError"); + if (clazz) { + env->ThrowNew(clazz, aMessage); + } + env->DeleteLocalRef(clazz); + return; + } + + // If the error was not handled above, then create an XPCOMException with the + // given error code and message. + + // Create parameters and method signature. Max of 2 params. The error code + // comes before the message string. + PRInt64 errorCode = aErrorCode ? aErrorCode : NS_ERROR_FAILURE; + nsCAutoString methodSig("(J"); + jstring message = nsnull; + if (aMessage) { + message = env->NewStringUTF(aMessage); + if (!message) { + return; + } + methodSig.AppendLiteral("Ljava/lang/String;"); + } + methodSig.AppendLiteral(")V"); + + // In some instances (such as in shutdownXPCOM() and termEmbedding()), we + // will need to throw an exception when JavaXPCOM has already been + // terminated. In such a case, 'xpcomExceptionClass' will be null. So we + // reset it temporarily in order to throw the appropriate exception. + if (xpcomExceptionClass == nsnull) { + xpcomExceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException"); + if (!xpcomExceptionClass) { + return; + } + } + + // create exception object + jthrowable throwObj = nsnull; + jmethodID mid = env->GetMethodID(xpcomExceptionClass, "", + methodSig.get()); + if (mid) { + throwObj = (jthrowable) env->NewObject(xpcomExceptionClass, mid, errorCode, + message); + } + NS_ASSERTION(throwObj, "Failed to create XPCOMException object"); + + // throw exception + if (throwObj) { + env->Throw(throwObj); + } +} + +nsAString* +jstring_to_nsAString(JNIEnv* env, jstring aString) +{ + const PRUnichar* buf = nsnull; + if (aString) { + buf = env->GetStringChars(aString, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsString* str = new nsString(buf); + + if (aString) { + env->ReleaseStringChars(aString, buf); + } else { + str->SetIsVoid(PR_TRUE); + } + + // returns string, or nsnull if 'new' failed + return str; +} + +nsACString* +jstring_to_nsACString(JNIEnv* env, jstring aString) +{ + const char* buf = nsnull; + if (aString) { + buf = env->GetStringUTFChars(aString, nsnull); + if (!buf) + return nsnull; // exception already thrown + } + + nsCString* str = new nsCString(buf); + + if (aString) { + env->ReleaseStringUTFChars(aString, buf); + } else { + str->SetIsVoid(PR_TRUE); + } + + // returns string, or nsnull if 'new' failed + return str; +} + +nsresult +File_to_nsILocalFile(JNIEnv* env, jobject aFile, nsILocalFile** aLocalFile) +{ + nsresult rv = NS_ERROR_FAILURE; + jstring pathName = nsnull; + jclass clazz = env->FindClass("java/io/File"); + if (clazz) { + jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath", + "()Ljava/lang/String;"); + if (pathMID) { + pathName = (jstring) env->CallObjectMethod(aFile, pathMID); + if (pathName != nsnull && !env->ExceptionCheck()) + rv = NS_OK; + } + } + + if (NS_SUCCEEDED(rv)) { + nsAString* path = jstring_to_nsAString(env, pathName); + if (!path) + rv = NS_ERROR_OUT_OF_MEMORY; + + if (NS_SUCCEEDED(rv)) { + rv = NS_NewLocalFile(*path, false, aLocalFile); + delete path; + } + } + + return rv; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h new file mode 100644 index 00000000..894a8cb8 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMBindingUtils.h @@ -0,0 +1,392 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsJavaXPCOMBindingUtils_h_ +#define _nsJavaXPCOMBindingUtils_h_ + +#include "jni.h" +#include "xptcall.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "pldhash.h" +#include "nsJavaXPTCStub.h" +#include "nsAutoLock.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" +#include "nsILocalFile.h" + +//#define DEBUG_JAVAXPCOM +//#define DEBUG_JAVAXPCOM_REFCNT + +#ifdef DEBUG_JAVAXPCOM +#define LOG(x) printf x +#else +#define LOG(x) /* nothing */ +#endif + + +/********************* + * Java JNI globals + *********************/ + +extern jclass systemClass; +extern jclass booleanClass; +extern jclass charClass; +extern jclass byteClass; +extern jclass shortClass; +extern jclass intClass; +extern jclass longClass; +extern jclass floatClass; +extern jclass doubleClass; +extern jclass stringClass; +extern jclass nsISupportsClass; +extern jclass xpcomExceptionClass; +extern jclass xpcomJavaProxyClass; +extern jclass weakReferenceClass; +extern jclass javaXPCOMUtilsClass; + +extern jmethodID hashCodeMID; +extern jmethodID booleanValueMID; +extern jmethodID booleanInitMID; +extern jmethodID charValueMID; +extern jmethodID charInitMID; +extern jmethodID byteValueMID; +extern jmethodID byteInitMID; +extern jmethodID shortValueMID; +extern jmethodID shortInitMID; +extern jmethodID intValueMID; +extern jmethodID intInitMID; +extern jmethodID longValueMID; +extern jmethodID longInitMID; +extern jmethodID floatValueMID; +extern jmethodID floatInitMID; +extern jmethodID doubleValueMID; +extern jmethodID doubleInitMID; +extern jmethodID createProxyMID; +extern jmethodID isXPCOMJavaProxyMID; +extern jmethodID getNativeXPCOMInstMID; +extern jmethodID weakReferenceConstructorMID; +extern jmethodID getReferentMID; +extern jmethodID clearReferentMID; +extern jmethodID findClassInLoaderMID; + +#ifdef DEBUG_JAVAXPCOM +extern jmethodID getNameMID; +extern jmethodID proxyToStringMID; +#endif + +class NativeToJavaProxyMap; +extern NativeToJavaProxyMap* gNativeToJavaProxyMap; +class JavaToXPTCStubMap; +extern JavaToXPTCStubMap* gJavaToXPTCStubMap; + +extern nsTHashtable* gJavaKeywords; + +// The Java garbage collector runs in a separate thread. Since it calls the +// finalizeProxy() function in nsJavaWrapper.cpp, we need to make sure that +// all the structures touched by finalizeProxy() are multithread aware. +extern PRLock* gJavaXPCOMLock; + +extern PRBool gJavaXPCOMInitialized; + +/** + * Initialize global structures used by JavaXPCOM. + * @param env Java environment pointer + * @return PR_TRUE if JavaXPCOM is initialized; PR_FALSE if an error occurred + */ +PRBool InitializeJavaGlobals(JNIEnv *env); + +/** + * Frees global structures that were allocated by InitializeJavaGlobals(). + * @param env Java environment pointer + */ +void FreeJavaGlobals(JNIEnv* env); + + +/************************* + * JavaXPCOMInstance + *************************/ + +class JavaXPCOMInstance +{ +public: + JavaXPCOMInstance(nsISupports* aInstance, nsIInterfaceInfo* aIInfo); + ~JavaXPCOMInstance(); + + nsISupports* GetInstance() { return mInstance; } + nsIInterfaceInfo* InterfaceInfo() { return mIInfo; } + +private: + nsISupports* mInstance; + nsIInterfaceInfo* mIInfo; +}; + + +/************************************** + * Java<->XPCOM object mappings + **************************************/ + +/** + * Maps native XPCOM objects to their associated Java proxy object. + */ +class NativeToJavaProxyMap +{ + friend PLDHashOperator DestroyJavaProxyMappingEnum(PLDHashTable* aTable, + PLDHashEntryHdr* aHeader, + PRUint32 aNumber, + void* aData); + +protected: + struct ProxyList + { + ProxyList(const jobject aRef, const nsIID& aIID, ProxyList* aList) + : javaObject(aRef) + , iid(aIID) + , next(aList) + { } + + const jobject javaObject; + const nsIID iid; + ProxyList* next; + }; + + struct Entry : public PLDHashEntryHdr + { + nsISupports* key; + ProxyList* list; + }; + +public: + NativeToJavaProxyMap() + : mHashTable(nsnull) + { } + + ~NativeToJavaProxyMap() + { + NS_ASSERTION(mHashTable == nsnull, + "MUST call Destroy() before deleting object"); + } + + nsresult Init(); + + nsresult Destroy(JNIEnv* env); + + nsresult Add(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID, + jobject aProxy); + + nsresult Find(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID, + jobject* aResult); + + nsresult Remove(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID); + +protected: + PLDHashTable* mHashTable; +}; + +/** + * Maps Java objects to their associated nsJavaXPTCStub. + */ +class JavaToXPTCStubMap +{ + friend PLDHashOperator DestroyXPTCMappingEnum(PLDHashTable* aTable, + PLDHashEntryHdr* aHeader, + PRUint32 aNumber, void* aData); + +protected: + struct Entry : public PLDHashEntryHdr + { + jint key; + nsJavaXPTCStub* xptcstub; + }; + +public: + JavaToXPTCStubMap() + : mHashTable(nsnull) + { } + + ~JavaToXPTCStubMap() + { + NS_ASSERTION(mHashTable == nsnull, + "MUST call Destroy() before deleting object"); + } + + nsresult Init(); + + nsresult Destroy(); + + nsresult Add(jint aJavaObjectHashCode, nsJavaXPTCStub* aProxy); + + nsresult Find(jint aJavaObjectHashCode, const nsIID& aIID, + nsJavaXPTCStub** aResult); + + nsresult Remove(jint aJavaObjectHashCode); + +protected: + PLDHashTable* mHashTable; +}; + + +/******************************* + * Helper functions + *******************************/ + +/** + * Convert a native nsISupports to a Java object. + * + * @param env Java environment pointer + * @param aXPCOMObject XPCOM object for which to find/create Java object + * @param aIID desired interface IID for Java object + * @param aObjectLoader Java object whose class loader we use for finding + * classes; can be null + * @param aResult on success, holds reference to Java object + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult NativeInterfaceToJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aObjectLoader, + jobject* aResult); + +/** + * Convert a Java object to a native nsISupports object. + * + * @param env Java environment pointer + * @param aJavaObject Java object for which to find/create XPCOM object + * @param aIID desired interface IID for XPCOM object + * @param aResult on success, holds AddRef'd reference to XPCOM object + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult JavaObjectToNativeInterface(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult); + +nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, + const XPTMethodDescriptor *methodInfo, + const nsXPTParamInfo ¶mInfo, + PRUint8 paramType, PRUint16 methodIndex, + nsXPTCMiniVariant *dispatchParams, + PRBool isFullVariantArray, + nsID &result); + +/** + * Returns the Class object associated with the class or interface with the + * given string name, using the class loader of the given object. + * + * @param env Java environment pointer + * @param aObjectLoader Java object whose class loader is used to load class + * @param aClassName fully qualified name of class to load + * + * @return java.lang.Class object of requested Class; NULL if the class + * wasn't found + * + * @see http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#classops + */ +inline jclass +FindClassInLoader(JNIEnv* env, jobject aObjectLoader, const char* aClassName) +{ + jclass clazz = nsnull; + jstring name = env->NewStringUTF(aClassName); + if (name) + clazz = (jclass) env->CallStaticObjectMethod(javaXPCOMUtilsClass, + findClassInLoaderMID, aObjectLoader, name); + +#ifdef DEBUG + if (!clazz) + fprintf(stderr, "WARNING: failed to find class [%s]\n", aClassName); +#endif + return clazz; +} + + +/******************************* + * JNI helper functions + *******************************/ + +/** + * Returns a pointer to the appropriate JNIEnv structure. This function is + * useful in callbacks or other functions that are not called directly from + * Java and therefore do not have the JNIEnv structure passed in. + * + * @return pointer to JNIEnv structure for current thread + */ +JNIEnv* GetJNIEnv(); + +/** + * Constructs and throws an exception. Some error codes (such as + * NS_ERROR_OUT_OF_MEMORY) are handled by the appropriate Java exception/error. + * Otherwise, an instance of XPCOMException is created with the given error + * code and message. + * + * @param env Java environment pointer + * @param aErrorCode The error code returned by an XPCOM/Gecko function. Pass + * zero for the default behaviour. + * @param aMessage A string that provides details for throwing this + * exception. Pass in nsnull for the default + * behaviour. + * + * @throws OutOfMemoryError if aErrorCode == NS_ERROR_OUT_OF_MEMORY + * XPCOMException for all other error codes + */ +void ThrowException(JNIEnv* env, const nsresult aErrorCode, + const char* aMessage); + +/** + * Helper functions for converting from java.lang.String to + * nsAString/nsACstring. Caller must delete nsAString/nsACString. + * + * @param env Java environment pointer + * @param aString Java string to convert + * + * @return nsAString/nsACString with same content as given Java string; + * a 'void' nsAString/nsACString object if aString is + * null; or nsnull if out of memory + */ +nsAString* jstring_to_nsAString(JNIEnv* env, jstring aString); +nsACString* jstring_to_nsACString(JNIEnv* env, jstring aString); + +/** + * Helper function for converting from java.io.File to nsILocalFile. + * + * @param env Java environment pointer + * @param aFile Java File to convert + * @param aLocalFile returns the converted nsILocalFile + * + * @return NS_OK for success; other values indicate error in conversion + */ +nsresult File_to_nsILocalFile(JNIEnv* env, jobject aFile, + nsILocalFile** aLocalFile); + +#endif // _nsJavaXPCOMBindingUtils_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp new file mode 100644 index 00000000..b0b6b72c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPCOMGlue.cpp @@ -0,0 +1,535 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "jni.h" +#include "nsXPCOMPrivate.h" // for XPCOM_DLL defines. +#include "nsXPCOMGlue.h" +#include + + +#ifdef VBOX +#include +#include "nsDebug.h" +#endif + +#if defined(XP_WIN) || defined(XP_OS2) +#define JX_EXPORT JNIEXPORT +#else +#define JX_EXPORT JNIEXPORT NS_EXPORT +#endif + + +/*********************** + * JNI Load & Unload + ***********************/ + +extern "C" JX_EXPORT jint JNICALL +JNI_OnLoad(JavaVM* vm, void* reserved) +{ + // Let the JVM know that we are using JDK 1.2 JNI features. + return JNI_VERSION_1_2; +} + +extern "C" JX_EXPORT void JNICALL +JNI_OnUnload(JavaVM* vm, void* reserved) +{ +} + +/******************************** + * JavaXPCOM JNI interfaces + ********************************/ + +#define JXM_NATIVE(func) Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_##func + +enum { + kFunc_Initialize, + kFunc_InitEmbedding, + kFunc_TermEmbedding, + kFunc_LockProfileDirectory, + kFunc_NotifyProfile, + kFunc_InitXPCOM, + kFunc_ShutdownXPCOM, + kFunc_GetComponentManager, + kFunc_GetComponentRegistrar, + kFunc_GetServiceManager, + kFunc_NewLocalFile, + kFunc_CallXPCOMMethod, + kFunc_FinalizeProxy, + kFunc_IsSameXPCOMObject, + kFunc_ReleaseProfileLock, + kFunc_GetNativeHandleFromAWT, + kFunc_WrapJavaObject, + kFunc_WrapXPCOMObject +}; + +#define JX_NUM_FUNCS 18 + + +// Get path string from java.io.File object. +jstring +GetJavaFilePath(JNIEnv* env, jobject aFile) +{ + jclass clazz = env->FindClass("java/io/File"); + if (clazz) { + jmethodID pathMID = env->GetMethodID(clazz, "getCanonicalPath", + "()Ljava/lang/String;"); + if (pathMID) { + return (jstring) env->CallObjectMethod(aFile, pathMID); + } + } + + return nsnull; +} +#ifdef VBOX + +#include "nsXPTCUtils.h" +#include "nsCOMPtr.h" +#include "nsIInterfaceInfoManager.h" +#include "nsJavaInterfaces.h" + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage); + +class nsXPTCJStub : public nsXPTCStubBase +{ + nsCOMPtr mII; + nsIXPTCProxy* mOuter; + public: + NS_DECL_ISUPPORTS_INHERITED + + nsXPTCJStub(REFNSIID aIID, nsIXPTCProxy* aOuter, nsIInterfaceInfo* ii) + { + mOuter = aOuter; + mII = ii; + } + + virtual ~nsXPTCJStub() + { + } + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) + { + *info = mII; + (*info)->AddRef(); + return NS_OK; + } + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) + { + return mOuter->CallMethod(methodIndex, info, params); + } +}; + +NS_IMETHODIMP_(nsrefcnt) +nsXPTCJStub::AddRef() +{ + return mOuter->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsXPTCJStub::Release() +{ + return mOuter->Release(); +} + +NS_IMETHODIMP nsXPTCJStub::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + nsIID* mIID; + mII->GetInterfaceIID(&mIID); + + if (mIID->Equals(aIID)) { + NS_ADDREF_THIS(); + *aInstancePtr = static_cast(this); + return NS_OK; + } + + return mOuter->QueryInterface(aIID, aInstancePtr); +} + +nsresult +NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, + nsISomeInterface* *aResult) +{ + NS_ENSURE_ARG(aOuter && aResult); +#if 0 + xptiInterfaceInfoManager *iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED); + + xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID); + if (!iie || !iie->EnsureResolved()) + return NS_ERROR_FAILURE; + + nsXPTCStubBase* newbase = new nsXPTCStubBase(aOuter, iie); + if (!newbase) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = newbase; +#else + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr ii; + nsresult rv; + + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(ii)); + if (NS_FAILED(rv)) + return rv; + + nsXPTCStubBase* newbase = new nsXPTCJStub(aIID, aOuter, ii); + if (!newbase) + return NS_ERROR_OUT_OF_MEMORY; + *aResult = newbase; +#endif + return NS_OK; +} + +void +NS_DestroyXPTCallStub(nsISomeInterface* aStub) +{ + nsXPTCStubBase* stub = static_cast(aStub); + delete(stub); +} + + +extern "C" void JAVAPROXY_NATIVE(finalizeProxy)(JNIEnv *env, jclass that, jobject aJavaProxy); + +nsresult +FindVBoxMethods(JNIEnv* env, jobject aXPCOMPath, void** aFunctions) +{ + nsresult rv = 0; + + // We only need to care about this function because the C function we offer + // is different from what the Java side expects + aFunctions[kFunc_FinalizeProxy] = (void*)JAVAPROXY_NATIVE(finalizeProxy); + + return rv; +} +#else +// Calls XPCOMGlueStartup using the given java.io.File object, and loads +// the JavaXPCOM methods from the XUL shared library. +nsresult +LoadXULMethods(JNIEnv* env, jobject aXPCOMPath, void** aFunctions) +{ + jstring pathString = GetJavaFilePath(env, aXPCOMPath); + if (!pathString) + return NS_ERROR_FAILURE; + const char* path = env->GetStringUTFChars(pathString, nsnull); + if (!path) + return NS_ERROR_OUT_OF_MEMORY; + + int len = strlen(path); + char* xpcomPath = (char*) malloc(len + sizeof(XPCOM_DLL) + + sizeof(XPCOM_FILE_PATH_SEPARATOR) + 1); + if (!xpcomPath) + return NS_ERROR_OUT_OF_MEMORY; + sprintf(xpcomPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, path); + + nsresult rv = XPCOMGlueStartup(xpcomPath); + free(xpcomPath); + if (NS_FAILED(rv)) + return rv; + +#ifdef XP_WIN32 + // The JNICALL calling convention defines to "__stdcall" on Win32, which + // mangles the name. + nsDynamicFunctionLoad funcs[] = { + { "_Java_org_mozilla_xpcom_internal_MozillaImpl_initialize@8", + (NSFuncPtr*) &aFunctions[kFunc_Initialize] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding@20", + (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding@8", + (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory@12", + (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] }, + { "_Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile@8", + (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM@16", + (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM@12", + (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager@8", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar@8", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager@8", + (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile@16", + (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod@20", + (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy@12", + (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] }, + { "_Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject@16", + (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] }, + { "_Java_org_mozilla_xpcom_ProfileLock_release@16", + (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] }, + { "_Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT@12", + (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] }, + { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject@16", + (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] }, + { "_Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject@20", + (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] }, + { nsnull, nsnull } + }; +#else + nsDynamicFunctionLoad funcs[] = { + { "Java_org_mozilla_xpcom_internal_MozillaImpl_initialize", + (NSFuncPtr*) &aFunctions[kFunc_Initialize] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_initEmbedding", + (NSFuncPtr*) &aFunctions[kFunc_InitEmbedding] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_termEmbedding", + (NSFuncPtr*) &aFunctions[kFunc_TermEmbedding] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_lockProfileDirectory", + (NSFuncPtr*) &aFunctions[kFunc_LockProfileDirectory] }, + { "Java_org_mozilla_xpcom_internal_GREImpl_notifyProfile", + (NSFuncPtr*) &aFunctions[kFunc_NotifyProfile] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_initXPCOM", + (NSFuncPtr*) &aFunctions[kFunc_InitXPCOM] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_shutdownXPCOM", + (NSFuncPtr*) &aFunctions[kFunc_ShutdownXPCOM] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentManager", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentManager] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getComponentRegistrar", + (NSFuncPtr*) &aFunctions[kFunc_GetComponentRegistrar] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_getServiceManager", + (NSFuncPtr*) &aFunctions[kFunc_GetServiceManager] }, + { "Java_org_mozilla_xpcom_internal_XPCOMImpl_newLocalFile", + (NSFuncPtr*) &aFunctions[kFunc_NewLocalFile] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_callXPCOMMethod", + (NSFuncPtr*) &aFunctions[kFunc_CallXPCOMMethod] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_finalizeProxy", + (NSFuncPtr*) &aFunctions[kFunc_FinalizeProxy] }, + { "Java_org_mozilla_xpcom_internal_XPCOMJavaProxy_isSameXPCOMObject", + (NSFuncPtr*) &aFunctions[kFunc_IsSameXPCOMObject] }, + { "Java_org_mozilla_xpcom_ProfileLock_release", + (NSFuncPtr*) &aFunctions[kFunc_ReleaseProfileLock] }, + { "Java_org_mozilla_xpcom_internal_MozillaImpl_getNativeHandleFromAWT", + (NSFuncPtr*) &aFunctions[kFunc_GetNativeHandleFromAWT] }, + { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapJavaObject", + (NSFuncPtr*) &aFunctions[kFunc_WrapJavaObject] }, + { "Java_org_mozilla_xpcom_internal_JavaXPCOMMethods_wrapXPCOMObject", + (NSFuncPtr*) &aFunctions[kFunc_WrapXPCOMObject] }, + { nsnull, nsnull } + }; +#endif + + rv = XPCOMGlueLoadXULFunctions(funcs); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +void +ThrowException(JNIEnv* env, const nsresult aErrorCode, const char* aMessage) +{ + // Only throw this exception if one hasn't already been thrown, so we don't + // mask a previous exception/error. + if (env->ExceptionCheck()) + return; + + // If the error code we get is for an Out Of Memory error, try to throw an + // OutOfMemoryError. The JVM may have enough memory to create this error. + if (aErrorCode == NS_ERROR_OUT_OF_MEMORY) { + jclass clazz = env->FindClass("java/lang/OutOfMemoryError"); + if (clazz) { + env->ThrowNew(clazz, aMessage); + } + env->DeleteLocalRef(clazz); + return; + } + + // If the error was not handled above, then create an XPCOMException with the + // given error code. + jthrowable throwObj = nsnull; + jclass exceptionClass = env->FindClass("org/mozilla/xpcom/XPCOMException"); + if (exceptionClass) { + jmethodID mid = env->GetMethodID(exceptionClass, "", + "(JLjava/lang/String;)V"); + if (mid) { + throwObj = (jthrowable) env->NewObject(exceptionClass, mid, + (PRInt64) aErrorCode, + env->NewStringUTF(aMessage)); + } + } + NS_ASSERTION(throwObj, "Failed to create XPCOMException object"); + + // throw exception + if (throwObj) { + env->Throw(throwObj); + } +} +#endif // VBOX + +// Register the JavaXPCOM native methods. This associates a native Java +// method with its C implementation. +nsresult +RegisterNativeMethods(JNIEnv* env, void** aFunctions) +{ + JNINativeMethod mozilla_methods[] = { + { "initializeNative", "()V", + (void*) aFunctions[kFunc_Initialize] }, + { "getNativeHandleFromAWT", "(Ljava/lang/Object;)J", + (void*) aFunctions[kFunc_GetNativeHandleFromAWT] } + }; + + JNINativeMethod gre_methods[] = { + { "initEmbeddingNative", + "(Ljava/io/File;Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)V", + (void*) aFunctions[kFunc_InitEmbedding] }, + { "termEmbedding", "()V", + (void*) aFunctions[kFunc_TermEmbedding] }, + { "lockProfileDirectory", "(Ljava/io/File;)Lorg/mozilla/xpcom/ProfileLock;", + (void*) aFunctions[kFunc_LockProfileDirectory] }, + { "notifyProfile", "()V", + (void*) aFunctions[kFunc_NotifyProfile] }, + }; + + JNINativeMethod xpcom_methods[] = { + { "initXPCOMNative", + "(Ljava/io/File;Lorg/mozilla/xpcom/IAppFileLocProvider;)Lorg/mozilla/interfaces/nsIServiceManager;", + (void*) aFunctions[kFunc_InitXPCOM] }, + { "shutdownXPCOM", "(Lorg/mozilla/interfaces/nsIServiceManager;)V", + (void*) aFunctions[kFunc_ShutdownXPCOM] }, + { "getComponentManager", "()Lorg/mozilla/interfaces/nsIComponentManager;", + (void*) aFunctions[kFunc_GetComponentManager] }, + { "getComponentRegistrar", "()Lorg/mozilla/interfaces/nsIComponentRegistrar;", + (void*) aFunctions[kFunc_GetComponentRegistrar] }, + { "getServiceManager", "()Lorg/mozilla/interfaces/nsIServiceManager;", + (void*) aFunctions[kFunc_GetServiceManager] }, + { "newLocalFile", "(Ljava/lang/String;Z)Lorg/mozilla/interfaces/nsILocalFile;", + (void*) aFunctions[kFunc_NewLocalFile] } + }; + + JNINativeMethod proxy_methods[] = { + { "callXPCOMMethod", + "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", + (void*) aFunctions[kFunc_CallXPCOMMethod] }, + { "finalizeProxyNative", "(Ljava/lang/Object;)V", + (void*) aFunctions[kFunc_FinalizeProxy] }, + { "isSameXPCOMObject", "(Ljava/lang/Object;Ljava/lang/Object;)Z", + (void*) aFunctions[kFunc_IsSameXPCOMObject] } + }; + + JNINativeMethod lockProxy_methods[] = { + { "releaseNative", "(J)V", + (void*) aFunctions[kFunc_ReleaseProfileLock] } + }; + + JNINativeMethod util_methods[] = { + { "wrapJavaObject", "(Ljava/lang/Object;Ljava/lang/String;)J", + (void*) aFunctions[kFunc_WrapJavaObject] }, + { "wrapXPCOMObject", "(JLjava/lang/String;)Ljava/lang/Object;", + (void*) aFunctions[kFunc_WrapXPCOMObject] } + }; + + jint rc = -1; + jclass clazz = env->FindClass("org/mozilla/xpcom/internal/MozillaImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, mozilla_methods, + sizeof(mozilla_methods) / sizeof(mozilla_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/GREImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, gre_methods, + sizeof(gre_methods) / sizeof(gre_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMImpl"); + if (clazz) { + rc = env->RegisterNatives(clazz, xpcom_methods, + sizeof(xpcom_methods) / sizeof(xpcom_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/XPCOMJavaProxy"); + if (clazz) { + rc = env->RegisterNatives(clazz, proxy_methods, + sizeof(proxy_methods) / sizeof(proxy_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/ProfileLock"); + if (clazz) { + rc = env->RegisterNatives(clazz, lockProxy_methods, + sizeof(lockProxy_methods) / sizeof(lockProxy_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + rc = -1; + clazz = env->FindClass("org/mozilla/xpcom/internal/JavaXPCOMMethods"); + if (clazz) { + rc = env->RegisterNatives(clazz, util_methods, + sizeof(util_methods) / sizeof(util_methods[0])); + } + NS_ENSURE_TRUE(rc == 0, NS_ERROR_FAILURE); + + return NS_OK; +} + +// Load the JavaXPCOM methods from the XUL shared library, and registers them +// as Java native methods. +extern "C" JX_EXPORT void JNICALL +JXM_NATIVE(registerJavaXPCOMMethodsNative) (JNIEnv *env, jclass that, + jobject aXPCOMPath) +{ + void* functions[JX_NUM_FUNCS]; + memset(functions, 0, JX_NUM_FUNCS * sizeof(void*)); + +#ifdef VBOX + nsresult rv = FindVBoxMethods(env, aXPCOMPath, functions); + if (NS_SUCCEEDED(rv)) { + rv = RegisterNativeMethods(env, functions); + } +#else + nsresult rv = LoadXULMethods(env, aXPCOMPath, functions); + if (NS_SUCCEEDED(rv)) { + rv = RegisterNativeMethods(env, functions); + } +#endif + + if (NS_FAILED(rv)) { + ThrowException(env, rv, "Failed to register JavaXPCOM methods"); + } +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp new file mode 100644 index 00000000..c8136ec4 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.cpp @@ -0,0 +1,1711 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsJavaXPTCStub.h" +#include "nsJavaWrapper.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "prmem.h" +#include "nsIInterfaceInfoManager.h" +#include "nsString.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsServiceManagerUtils.h" + + +nsJavaXPTCStub::nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo, + nsresult *rv) + : mJavaStrongRef(nsnull) + , mIInfo(aIInfo) + , mMaster(nsnull) + , mWeakRefCnt(0) +{ + const nsIID *iid = nsnull; + aIInfo->GetIIDShared(&iid); + NS_ASSERTION(iid, "GetIIDShared must not fail!"); + + *rv = InitStub(*iid); + if (NS_FAILED(*rv)) + return; + + JNIEnv* env = GetJNIEnv(); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mJavaWeakRef = env->NewGlobalRef(weakref); + mJavaRefHashCode = env->CallStaticIntMethod(systemClass, hashCodeMID, + aJavaObject); + +#ifdef DEBUG_JAVAXPCOM + char* iid_str = iid->ToString(); + LOG(("+ nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); +#endif +} + +nsJavaXPTCStub::~nsJavaXPTCStub() +{ +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::AddRefInternal() +{ + // If this is the first AddRef call, we create a strong global ref to the + // Java object to keep it from being garbage collected. + if (mRefCnt == 0) { + JNIEnv* env = GetJNIEnv(); + jobject referent = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + if (!env->IsSameObject(referent, NULL)) { + mJavaStrongRef = env->NewGlobalRef(referent); + } + NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref"); + } + + // if this is the master interface + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsJavaXPTCStub", sizeof(*this)); + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::AddRef() +{ +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) + 1; + LOG(("= nsJavaXPTCStub::AddRef (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->AddRefInternal(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::ReleaseInternal() +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsJavaXPTCStub"); + if (mRefCnt == 0) { + // delete strong ref; allows Java object to be garbage collected + DeleteStrongRef(); + + // If we have a weak ref, we don't delete this object. + if (mWeakRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + Destroy(); + delete this; + } + return 0; + } + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::Release() +{ +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) - 1; + LOG(("= nsJavaXPTCStub::Release (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->ReleaseInternal(); +} + +void +nsJavaXPTCStub::Destroy() +{ + JNIEnv* env = GetJNIEnv(); + +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("- nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + if (!mMaster) { + // delete each child stub + for (PRInt32 i = 0; i < mChildren.Count(); i++) { + delete (nsJavaXPTCStub*) mChildren[i]; + } + + // Since we are destroying this stub, also remove the mapping. + // It is possible for mJavaStrongRef to be NULL here. That is why we + // store the hash code value earlier. + if (gJavaXPCOMInitialized) { + gJavaToXPTCStubMap->Remove(mJavaRefHashCode); + } + } + + env->CallVoidMethod(mJavaWeakRef, clearReferentMID); + env->DeleteGlobalRef(mJavaWeakRef); +} + +void +nsJavaXPTCStub::ReleaseWeakRef() +{ + // if this is a child + if (mMaster) + mMaster->ReleaseWeakRef(); + + --mWeakRefCnt; + + // If there are no more associated weak refs, and no one else holds a strong + // ref to this object, then delete it. + if (mWeakRefCnt == 0 && mRefCnt == 0) { + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + mRefCnt = 1; /* stabilize */ + Destroy(); + delete this; + } +} + +void +nsJavaXPTCStub::DeleteStrongRef() +{ + if (mJavaStrongRef == nsnull) + return; + + GetJNIEnv()->DeleteGlobalRef(mJavaStrongRef); + mJavaStrongRef = nsnull; +} + +NS_IMETHODIMP +nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) +{ + nsresult rv; + + LOG(("JavaStub::QueryInterface()\n")); + *aInstancePtr = nsnull; + nsJavaXPTCStub *master = mMaster ? mMaster : this; + + // This helps us differentiate between the help classes. + if (aIID.Equals(NS_GET_IID(nsJavaXPTCStub))) + { + *aInstancePtr = master; + NS_ADDREF(this); + return NS_OK; + } + + // always return the master stub for nsISupports + if (aIID.Equals(NS_GET_IID(nsISupports))) + { + *aInstancePtr = master->mXPTCStub; + NS_ADDREF(master); + return NS_OK; + } + + // All Java objects support weak references + if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) + { + *aInstancePtr = static_cast(master); + NS_ADDREF(master); + return NS_OK; + } + + // does any existing stub support the requested IID? + nsJavaXPTCStub *stub = master->FindStubSupportingIID(aIID); + if (stub) + { + *aInstancePtr = stub->mXPTCStub; + NS_ADDREF(stub); + return NS_OK; + } + + JNIEnv* env = GetJNIEnv(); + + // Query Java object + LOG(("\tCalling Java object queryInterface\n")); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + + jmethodID qiMID = 0; + jclass clazz = env->GetObjectClass(javaObject); + if (clazz) { + char* sig = "(Ljava/lang/String;)Lorg/mozilla/interfaces/nsISupports;"; + qiMID = env->GetMethodID(clazz, "queryInterface", sig); + NS_ASSERTION(qiMID, "Failed to get queryInterface method ID"); + } + + if (qiMID == 0) { + env->ExceptionClear(); + return NS_NOINTERFACE; + } + + // construct IID string + jstring iid_jstr = nsnull; + char* iid_str = aIID.ToString(); + if (iid_str) { + iid_jstr = env->NewStringUTF(iid_str); + } + if (!iid_str || !iid_jstr) { + env->ExceptionClear(); + return NS_ERROR_OUT_OF_MEMORY; + } + PR_Free(iid_str); + + // call queryInterface method + jobject obj = env->CallObjectMethod(javaObject, qiMID, iid_jstr); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + return NS_ERROR_FAILURE; + } + if (!obj) + return NS_NOINTERFACE; + + // Get interface info for new java object + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr iinfo; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + stub = new nsJavaXPTCStub(obj, iinfo, &rv); + if (!stub) + return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + // add stub to the master's list of children, so we can preserve + // symmetry in future QI calls. the master will delete each child + // when it is destroyed. the refcount of each child is bound to + // the refcount of the master. this is done to deal with code + // like this: + // + // nsCOMPtr bar = ...; + // nsIFoo *foo; + // { + // nsCOMPtr temp = do_QueryInterface(bar); + // foo = temp; + // } + // foo->DoStuff(); + // + // while this code is not valid XPCOM (since it is using |foo| + // after having called Release on it), such code is unfortunately + // very common in the mozilla codebase. the assumption this code + // is making is that so long as |bar| is alive, it should be valid + // to access |foo| even if the code doesn't own a strong reference + // to |foo|! clearly wrong, but we need to support it anyways. + + stub->mMaster = master; + master->mChildren.AppendElement(stub); + + *aInstancePtr = stub->mXPTCStub; + NS_ADDREF(stub); + return NS_OK; +} + +PRBool +nsJavaXPTCStub::SupportsIID(const nsID &iid) +{ + PRBool match; + nsCOMPtr iter = mIInfo; + do + { + if (NS_SUCCEEDED(iter->IsIID(&iid, &match)) && match) + return PR_TRUE; + + nsCOMPtr parent; + iter->GetParent(getter_AddRefs(parent)); + iter = parent; + } + while (iter != nsnull); + + return PR_FALSE; +} + +nsJavaXPTCStub * +nsJavaXPTCStub::FindStubSupportingIID(const nsID &iid) +{ + NS_ASSERTION(mMaster == nsnull, "this is not a master stub"); + + if (SupportsIID(iid)) + return this; + + for (PRInt32 i = 0; i < mChildren.Count(); i++) + { + nsJavaXPTCStub *child = (nsJavaXPTCStub *) mChildren[i]; + if (child->SupportsIID(iid)) + return child; + } + return nsnull; +} + +NS_IMETHODIMP +nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aMethodInfo, + nsXPTCMiniVariant *aParams) +{ +#ifdef DEBUG_JAVAXPCOM + const char* ifaceName; + mIInfo->GetNameShared(&ifaceName); + LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); +#endif + + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + + nsCAutoString methodSig("("); + + // Create jvalue array to hold Java params + PRUint8 paramCount = aMethodInfo->num_args; + jvalue* java_params = nsnull; + const nsXPTParamInfo* retvalInfo = nsnull; + if (paramCount) { + java_params = new jvalue[paramCount]; + if (!java_params) + return NS_ERROR_OUT_OF_MEMORY; + + for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; + if (!paramInfo.IsRetval()) { + rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i], methodSig); + } else { + retvalInfo = ¶mInfo; + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed"); + } + + // Finish method signature + if (NS_SUCCEEDED(rv)) { + methodSig.Append(')'); + if (retvalInfo) { + nsCAutoString retvalSig; + rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams, + retvalSig); + methodSig.Append(retvalSig); + } else { + methodSig.Append('V'); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed"); + } + + // Get Java method to call + jmethodID mid = nsnull; + if (NS_SUCCEEDED(rv)) { + nsCAutoString methodName; + if (XPT_MD_IS_GETTER(aMethodInfo->flags) || + XPT_MD_IS_SETTER(aMethodInfo->flags)) { + if (XPT_MD_IS_GETTER(aMethodInfo->flags)) + methodName.AppendLiteral("get"); + else + methodName.AppendLiteral("set"); + methodName.AppendASCII(aMethodInfo->name); + methodName.SetCharAt(toupper(methodName[3]), 3); + } else { + methodName.AppendASCII(aMethodInfo->name); + methodName.SetCharAt(tolower(methodName[0]), 0); + } + // If it's a Java keyword, then prepend an underscore + if (gJavaKeywords->GetEntry(methodName.get())) { + methodName.Insert('_', 0); + } + + jclass clazz = env->GetObjectClass(javaObject); + if (clazz) + mid = env->GetMethodID(clazz, methodName.get(), methodSig.get()); + NS_ASSERTION(mid, "Failed to get requested method for Java object"); + if (!mid) + rv = NS_ERROR_FAILURE; + } + + // Call method + jvalue retval; + if (NS_SUCCEEDED(rv)) { + if (!retvalInfo) { + env->CallVoidMethodA(javaObject, mid, java_params); + } else { + switch (retvalInfo->GetType().TagPart()) + { + case nsXPTType::T_I8: + retval.b = env->CallByteMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + retval.s = env->CallShortMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + retval.i = env->CallIntMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + retval.j = env->CallLongMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_FLOAT: + retval.f = env->CallFloatMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + retval.d = env->CallDoubleMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_BOOL: + retval.z = env->CallBooleanMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + retval.c = env->CallCharMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + retval.l = env->CallObjectMethodA(javaObject, mid, java_params); + break; + + case nsXPTType::T_VOID: + retval.j = env->CallLongMethodA(javaObject, mid, java_params); + break; + + default: + NS_WARNING("Unhandled retval type"); + break; + } + } + + // Check for exception from called Java function + jthrowable exp = env->ExceptionOccurred(); + if (exp) { + // If the exception is an instance of XPCOMException, then get the + // nsresult from the exception instance. Else, default to + // NS_ERROR_FAILURE. + if (env->IsInstanceOf(exp, xpcomExceptionClass)) { + jfieldID fid; + fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J"); + if (fid) { + rv = env->GetLongField(exp, fid); + } else { + rv = NS_ERROR_FAILURE; + } + NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException"); + } else { + rv = NS_ERROR_FAILURE; + } + } + } + + // Handle any 'inout', 'out' and 'retval' params + if (NS_SUCCEEDED(rv)) { + for (PRUint8 i = 0; i < paramCount; i++) + { + const nsXPTParamInfo ¶mInfo = aMethodInfo->params[i]; + if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in' + continue; + + // If param is null, then caller is not expecting an output value. + if (aParams[i].val.p == nsnull) + continue; + + if (!paramInfo.IsRetval()) { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], java_params[i]); + } else { + rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams, + aParams[i], retval); + } + } + NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed"); + } + + if (java_params) + delete [] java_params; + +#ifdef DEBUG + if (env->ExceptionCheck()) + env->ExceptionDescribe(); +#endif + env->ExceptionClear(); + + LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->name)); + return rv; +} + +/** + * Handle 'in', 'inout', and 'out' params + */ +nsresult +nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue, + nsACString &aMethodSig) +{ + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + const nsXPTType &type = aParamInfo.GetType(); + + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.b = aVariant.val.i8; + aMethodSig.Append('B'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jbyteArray array = env->NewByteArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetByteArrayRegion(array, 0, 1, (jbyte*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[B"); + } + } + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.s = (tag == nsXPTType::T_I16) ? aVariant.val.i16 : + aVariant.val.u8; + aMethodSig.Append('S'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jshortArray array = env->NewShortArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetShortArrayRegion(array, 0, 1, (jshort*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[S"); + } + } + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.i = (tag == nsXPTType::T_I32) ? aVariant.val.i32 : + aVariant.val.u16; + aMethodSig.Append('I'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jintArray array = env->NewIntArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetIntArrayRegion(array, 0, 1, (jint*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[I"); + } + } + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.j = (tag == nsXPTType::T_I64) ? aVariant.val.i64 : + aVariant.val.u32; + aMethodSig.Append('J'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jlongArray array = env->NewLongArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[J"); + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.f = aVariant.val.f; + aMethodSig.Append('F'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jfloatArray array = env->NewFloatArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetFloatArrayRegion(array, 0, 1, (jfloat*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[F"); + } + } + break; + + // XXX how do we handle unsigned 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.d = (tag == nsXPTType::T_DOUBLE) ? aVariant.val.d : + aVariant.val.u64; + aMethodSig.Append('D'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jdoubleArray array = env->NewDoubleArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetDoubleArrayRegion(array, 0, 1, (jdouble*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[D"); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.z = aVariant.val.b; + aMethodSig.Append('Z'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jbooleanArray array = env->NewBooleanArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetBooleanArrayRegion(array, 0, 1, (jboolean*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Z"); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (!aParamInfo.IsOut()) { // 'in' + if (tag == nsXPTType::T_CHAR) + aJValue.c = aVariant.val.c; + else + aJValue.c = aVariant.val.wc; + aMethodSig.Append('C'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jcharArray array = env->NewCharArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetCharArrayRegion(array, 0, 1, (jchar*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[C"); + } + } + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + { + void* ptr = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + ptr = aVariant.val.p; + } else if (aVariant.val.p) { // 'inout' & 'out' + void** variant = static_cast(aVariant.val.p); + ptr = *variant; + } + + jobject str; + if (ptr) { + if (tag == nsXPTType::T_CHAR_STR) { + str = env->NewStringUTF((const char*) ptr); + } else { + const PRUnichar* buf = (const PRUnichar*) ptr; + str = env->NewString(buf, nsCRT::strlen(buf)); + } + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + str = nsnull; + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = str; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, stringClass, str); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_IID: + { + nsID* iid = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + iid = static_cast(aVariant.val.p); + } else if (aVariant.val.p) { // 'inout' & 'out' + nsID** variant = static_cast(aVariant.val.p); + iid = *variant; + } + + jobject str = nsnull; + if (iid) { + char iid_str[NSID_LENGTH]; + iid->ToProvidedString(iid_str); + str = env->NewStringUTF(iid_str); + if (!str) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = str; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, stringClass, str); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[Ljava/lang/String;"); + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + nsISupports* xpcom_obj = nsnull; + if (!aParamInfo.IsOut()) { // 'in' + xpcom_obj = static_cast(aVariant.val.p); + } else if (aVariant.val.p) { // 'inout' & 'out' + nsISupports** variant = static_cast(aVariant.val.p); + xpcom_obj = *variant; + } + + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aParamInfo.GetType().TagPart(), aMethodIndex, + aDispatchParams, PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // get name of interface + char* iface_name = nsnull; + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + break; + + rv = iim->GetNameForIID(&iid, &iface_name); + if (NS_FAILED(rv) || !iface_name) + break; + + jobject java_stub = nsnull; + if (xpcom_obj) { + // Get matching Java object for given xpcom object + jobject objLoader = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + rv = NativeInterfaceToJavaObject(env, xpcom_obj, iid, objLoader, + &java_stub); + if (NS_FAILED(rv)) + break; + } + + if (!aParamInfo.IsOut()) { // 'in' + aJValue.l = java_stub; + } else { // 'inout' & 'out' + if (aVariant.val.p) { + aJValue.l = env->NewObjectArray(1, nsISupportsClass, java_stub); + if (aJValue.l == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } else { + aJValue.l = nsnull; + } + aMethodSig.Append('['); + } + + if (tag != nsXPTType::T_INTERFACE_IS) { + aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/"); + aMethodSig.AppendASCII(iface_name); + aMethodSig.Append(';'); + } else { + aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;"); + } + + nsMemory::Free(iface_name); + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + // This only handle 'in' or 'in dipper' params. In XPIDL, the 'out' + // descriptor is mapped to 'in dipper'. + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsString* str = static_cast(aVariant.val.p); + if (!str) { + rv = NS_ERROR_FAILURE; + break; + } + + jstring jstr = nsnull; + if (!str->IsVoid()) { + jstr = env->NewString(str->get(), str->Length()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + aJValue.l = jstr; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + // This only handle 'in' or 'in dipper' params. In XPIDL, the 'out' + // descriptor is mapped to 'in dipper'. + NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor"); + if (!aParamInfo.IsIn()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + nsCString* str = static_cast(aVariant.val.p); + if (!str) { + rv = NS_ERROR_FAILURE; + break; + } + + jstring jstr = nsnull; + if (!str->IsVoid()) { + jstr = env->NewStringUTF(str->get()); + if (!jstr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + } + + aJValue.l = jstr; + aMethodSig.AppendLiteral("Ljava/lang/String;"); + } + break; + + // Pass the 'void*' address as a long + case nsXPTType::T_VOID: + { + if (!aParamInfo.IsOut()) { // 'in' + aJValue.j = reinterpret_cast(aVariant.val.p); + aMethodSig.Append('J'); + } else { // 'inout' & 'out' + if (aVariant.val.p) { + jlongArray array = env->NewLongArray(1); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p); + aJValue.l = array; + } else { + aJValue.l = nsnull; + } + aMethodSig.AppendLiteral("[J"); + } + } + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +nsresult +nsJavaXPTCStub::GetRetvalSig(const nsXPTParamInfo* aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsACString &aRetvalSig) +{ + PRUint8 type = aParamInfo->GetType().TagPart(); + switch (type) + { + case nsXPTType::T_I8: + aRetvalSig.Append('B'); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + aRetvalSig.Append('S'); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + aRetvalSig.Append('I'); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + aRetvalSig.Append('J'); + break; + + case nsXPTType::T_FLOAT: + aRetvalSig.Append('F'); + break; + + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + aRetvalSig.Append('D'); + break; + + case nsXPTType::T_BOOL: + aRetvalSig.Append('Z'); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + aRetvalSig.Append('C'); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + aRetvalSig.AppendLiteral("Ljava/lang/String;"); + break; + + case nsXPTType::T_INTERFACE: + { + nsID iid; + nsresult rv = GetIIDForMethodParam(mIInfo, aMethodInfo, *aParamInfo, type, + aMethodIndex, aDispatchParams, + PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // get name of interface + char* iface_name = nsnull; + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + break; + + rv = iim->GetNameForIID(&iid, &iface_name); + if (NS_FAILED(rv) || !iface_name) + break; + + aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/"); + aRetvalSig.AppendASCII(iface_name); + aRetvalSig.Append(';'); + nsMemory::Free(iface_name); + break; + } + + case nsXPTType::T_INTERFACE_IS: + aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;"); + break; + + case nsXPTType::T_VOID: + aRetvalSig.Append('J'); + break; + + case nsXPTType::T_ARRAY: + NS_WARNING("array types are not yet supported"); + return NS_ERROR_NOT_IMPLEMENTED; + break; + + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +/** + * Handle 'inout', 'out', and 'retval' params + */ +nsresult +nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor *aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, jvalue &aJValue) +{ + nsresult rv = NS_OK; + JNIEnv* env = GetJNIEnv(); + const nsXPTType &type = aParamInfo.GetType(); + + PRUint8 tag = type.TagPart(); + switch (tag) + { + case nsXPTType::T_I8: + { + jbyte value; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.b; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetByteArrayRegion((jbyteArray) aJValue.l, 0, 1, &value); + } + if (aVariant.val.p) + *((PRInt8 *) aVariant.val.p) = value; + } + break; + + case nsXPTType::T_U8: + case nsXPTType::T_I16: + { + jshort value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.s; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetShortArrayRegion((jshortArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U8) + *((PRUint8 *) aVariant.val.p) = value; + else + *((PRInt16 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_U16: + case nsXPTType::T_I32: + { + jint value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.i; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetIntArrayRegion((jintArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U16) + *((PRUint16 *) aVariant.val.p) = value; + else + *((PRInt32 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_U32: + case nsXPTType::T_I64: + { + jlong value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.j; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_U32) + *((PRUint32 *) aVariant.val.p) = value; + else + *((PRInt64 *) aVariant.val.p) = value; + } + } + break; + + case nsXPTType::T_FLOAT: + { + if (aParamInfo.IsRetval()) { // 'retval' + *((float *) aVariant.val.p) = aJValue.f; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetFloatArrayRegion((jfloatArray) aJValue.l, 0, 1, + (jfloat*) aVariant.val.p); + } + } + break; + + // XXX how do we handle 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + { + jdouble value = 0; + if (aParamInfo.IsRetval()) { // 'retval' + value = aJValue.d; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetDoubleArrayRegion((jdoubleArray) aJValue.l, 0, 1, &value); + } + + if (aVariant.val.p) { + if (tag == nsXPTType::T_DOUBLE) + *((double *) aVariant.val.p) = value; + else + *((PRUint64 *) aVariant.val.p) = static_cast(value); + } + } + break; + + case nsXPTType::T_BOOL: + { + if (aParamInfo.IsRetval()) { // 'retval' + *((PRBool *) aVariant.val.p) = aJValue.z; + } else if (aJValue.l) { // 'inout' & 'out' + env->GetBooleanArrayRegion((jbooleanArray) aJValue.l, 0, 1, + (jboolean*) aVariant.val.p); + } + } + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + { + if (aParamInfo.IsRetval()) { // 'retval' + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = aJValue.c; + else + *((PRUnichar *) aVariant.val.p) = aJValue.c; + } else if (aJValue.l) { // 'inout' & 'out' + jchar* array = env->GetCharArrayElements((jcharArray) aJValue.l, + nsnull); + if (!array) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (type.TagPart() == nsXPTType::T_CHAR) + *((char *) aVariant.val.p) = array[0]; + else + *((PRUnichar *) aVariant.val.p) = array[0]; + + env->ReleaseCharArrayElements((jcharArray) aJValue.l, array, JNI_ABORT); + } + } + break; + + case nsXPTType::T_CHAR_STR: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + char** variant = static_cast(aVariant.val.p); + if (str) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(str, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // If new string is different from one passed in, free old string + // and replace with new string. + if (aParamInfo.IsRetval() || + *variant == nsnull || strcmp(*variant, char_ptr) != 0) + { + if (!aParamInfo.IsRetval() && *variant) + PR_Free(*variant); + + *variant = strdup(char_ptr); + if (*variant == nsnull) { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringUTFChars(str, char_ptr); + } else { + // If we were passed in a string, delete it now, and set to null. + // (Only for 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + PR_Free(*variant); + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_WCHAR_STR: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + PRUnichar** variant = static_cast(aVariant.val.p); + if (str) { + // Get string buffer + const jchar* wchar_ptr = env->GetStringChars(str, nsnull); + if (!wchar_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + // If new string is different from one passed in, free old string + // and replace with new string. We + if (aParamInfo.IsRetval() || + *variant == nsnull || nsCRT::strcmp(*variant, wchar_ptr) != 0) + { + if (!aParamInfo.IsRetval() && *variant) + PR_Free(*variant); + + PRUint32 length = nsCRT::strlen(wchar_ptr); + *variant = (PRUnichar*) PR_Malloc((length + 1) * sizeof(PRUnichar)); + if (*variant) { + memcpy(*variant, wchar_ptr, length * sizeof(PRUnichar)); + (*variant)[length] = 0; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringChars(str, wchar_ptr); + } else { + // If we were passed in a string, delete it now, and set to null. + // (Only for 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + PR_Free(*variant); + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_IID: + { + jstring str = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + str = (jstring) aJValue.l; + } else { // 'inout' & 'out' + str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + nsID** variant = static_cast(aVariant.val.p); + if (str) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(str, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + if (!aParamInfo.IsRetval() && *variant) { + // If we were given an nsID, set it to the new string + nsID* oldIID = *variant; + oldIID->Parse(char_ptr); + } else { + // If the argument that was passed in was null, then we need to + // create a new nsID. + nsID* newIID = new nsID; + if (newIID) { + newIID->Parse(char_ptr); + *variant = newIID; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + // don't 'break'; fall through to release chars + } + } + + // Release string buffer + env->ReleaseStringUTFChars(str, char_ptr); + } else { + // If we were passed in an nsID, delete it now, and set to null. + // (Free only 'inout' & 'out' params) + if (*variant && !aParamInfo.IsRetval()) { + delete *variant; + } + *variant = nsnull; + } + } + break; + + case nsXPTType::T_INTERFACE: + case nsXPTType::T_INTERFACE_IS: + { + jobject java_obj = nsnull; + if (aParamInfo.IsRetval()) { // 'retval' + java_obj = aJValue.l; + } else if (aJValue.l) { // 'inout' & 'out' + java_obj = env->GetObjectArrayElement((jobjectArray) aJValue.l, 0); + } + + void* xpcom_obj = nsnull; + if (java_obj) { + // Get IID for this param + nsID iid; + rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, + aParamInfo.GetType().TagPart(), aMethodIndex, + aDispatchParams, PR_FALSE, iid); + if (NS_FAILED(rv)) + break; + + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + if (iid.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); + } else { + isWeakRef = PR_FALSE; + } + + rv = JavaObjectToNativeInterface(env, java_obj, iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + rv = ((nsISupports*) xpcom_obj)->QueryInterface(iid, &xpcom_obj); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. + if (isWeakRef) { + nsISupports* isupports = (nsISupports*) xpcom_obj; + nsCOMPtr supportsweak = + do_QueryInterface(isupports); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + NS_RELEASE(isupports); + xpcom_obj = weakref; + NS_ADDREF((nsISupports*) xpcom_obj); + } else { + xpcom_obj = nsnull; + } + } + } + + // For 'inout' params, if the resulting xpcom value is different than the + // one passed in, then we must release the incoming xpcom value. + nsISupports** variant = static_cast(aVariant.val.p); + if (aParamInfo.IsIn() && *variant) { + nsCOMPtr in = do_QueryInterface(*variant); + nsCOMPtr out = do_QueryInterface((nsISupports*) xpcom_obj); + if (in != out) { + NS_RELEASE(*variant); + } + } + + *(static_cast(aVariant.val.p)) = xpcom_obj; + } + break; + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + { + NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper"); + if (!aParamInfo.IsDipper()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = (jstring) aJValue.l; + nsString* variant = static_cast(aVariant.val.p); + + if (jstr) { + // Get string buffer + const jchar* wchar_ptr = env->GetStringChars(jstr, nsnull); + if (!wchar_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + variant->Assign(wchar_ptr); + + // release String buffer + env->ReleaseStringChars(jstr, wchar_ptr); + } else { + variant->SetIsVoid(PR_TRUE); + } + } + break; + + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + { + NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper"); + if (!aParamInfo.IsDipper()) { + rv = NS_ERROR_UNEXPECTED; + break; + } + + jstring jstr = (jstring) aJValue.l; + nsCString* variant = static_cast(aVariant.val.p); + + if (jstr) { + // Get string buffer + const char* char_ptr = env->GetStringUTFChars(jstr, nsnull); + if (!char_ptr) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + + variant->Assign(char_ptr); + + // release String buffer + env->ReleaseStringUTFChars(jstr, char_ptr); + } else { + variant->SetIsVoid(PR_TRUE); + } + } + break; + + case nsXPTType::T_VOID: + { + if (aParamInfo.IsRetval()) { // 'retval' + aVariant.val.p = reinterpret_cast(aJValue.j); + } else if (aJValue.l) { // 'inout' & 'out' + env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1, + (jlong*) aVariant.val.p); + } + } + break; + + default: + NS_WARNING("unexpected parameter type"); + return NS_ERROR_UNEXPECTED; + } + + return rv; +} + +NS_IMETHODIMP +nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr) +{ + if (mMaster) + return mMaster->GetWeakReference(aInstancePtr); + + LOG(("==> nsJavaXPTCStub::GetWeakReference()\n")); + + if (!aInstancePtr) + return NS_ERROR_NULL_POINTER; + + jobject javaObject = GetJNIEnv()->CallObjectMethod(mJavaWeakRef, + getReferentMID); + nsJavaXPTCStubWeakRef* weakref; + weakref = new nsJavaXPTCStubWeakRef(javaObject, this); + if (!weakref) + return NS_ERROR_OUT_OF_MEMORY; + + *aInstancePtr = weakref; + NS_ADDREF(*aInstancePtr); + ++mWeakRefCnt; + + return NS_OK; +} + +jobject +nsJavaXPTCStub::GetJavaObject() +{ + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID); + +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + return javaObject; +} + + +/*static*/ nsresult +nsJavaXPTCStub::GetNewOrUsed(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult) +{ + nsJavaXPTCStub* stub; + jint hash = env->CallStaticIntMethod(systemClass, hashCodeMID, aJavaObject); + nsresult rv = gJavaToXPTCStubMap->Find(hash, aIID, &stub); + NS_ENSURE_SUCCESS(rv, rv); + if (stub) { + // stub is already AddRef'd and QI'd + *aResult = stub; + return NS_OK; + } + + // If there is no corresponding XPCOM object, then that means that the + // parameter is a non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get interface info for class + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr iinfo; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + NS_ENSURE_SUCCESS(rv, rv); + + // Create XPCOM stub + stub = new nsJavaXPTCStub(aJavaObject, iinfo, &rv); + if (!stub) + return NS_ERROR_OUT_OF_MEMORY; + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + rv = gJavaToXPTCStubMap->Add(hash, stub); + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + NS_ADDREF(stub); + *aResult = stub; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h new file mode 100644 index 00000000..90d42c8f --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStub.h @@ -0,0 +1,153 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsJavaXPTCStub_h_ +#define _nsJavaXPTCStub_h_ + +#include "nsXPTCUtils.h" +#include "jni.h" +#include "nsVoidArray.h" +#include "nsIInterfaceInfo.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsJavaXPTCStubWeakRef.h" + + +#define NS_JAVAXPTCSTUB_IID \ +{0x88dd8130, 0xebe6, 0x4431, {0x9d, 0xa7, 0xe6, 0xb7, 0x54, 0x74, 0xfb, 0x21}} + +class nsJavaXPTCStub : protected nsAutoXPTCStub, + public nsSupportsWeakReference +{ + friend class nsJavaXPTCStubWeakRef; + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSWEAKREFERENCE + NS_DECLARE_STATIC_IID_ACCESSOR(NS_JAVAXPTCSTUB_IID) + + nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo, + nsresult *rv); + + virtual ~nsJavaXPTCStub(); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aInfo, + nsXPTCMiniVariant *aParams); + + nsISomeInterface* GetStub() { return mXPTCStub; } + + // getter for mJavaObject + jobject GetJavaObject(); + + // Deletes the strong global ref for the Java object, so it can be garbage + // collected if necessary. See DestroyXPTCMappingEnum(). + void DeleteStrongRef(); + + /** + * Finds the associated nsJavaXPTCStub for the given Java object and IID. + * If no such stub exists, then a new one is created. + * + * @param env Java environment pointer + * @param aJavaObject Java object for which to find/create nsJavaXPTCStub + * @param aIID desired interface IID for nsJavaXPTCStub + * @param aResult on success, holds AddRef'd reference to nsJavaXPTCStub + * + * @return NS_OK if succeeded; all other return values are error codes. + */ + static nsresult GetNewOrUsed(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, void** aResult); + + +private: + NS_IMETHOD_(nsrefcnt) AddRefInternal(); + NS_IMETHOD_(nsrefcnt) ReleaseInternal(); + + // Deletes this object and its members. Called by ReleaseInternal() and + // ReleaseWeakRef(). + void Destroy(); + + // When a nsJavaXPTCStubWeakRef associated with this object is released, it + // calls this function to let this object know that there is one less weak + // ref. If there are no more weakrefs referencing this object, and no one + // holds a strong ref, then this function takes care of deleting the object. + void ReleaseWeakRef(); + + // returns a weak reference to a child supporting the specified interface + nsJavaXPTCStub * FindStubSupportingIID(const nsID &aIID); + + // returns true if this stub supports the specified interface + PRBool SupportsIID(const nsID &aIID); + + nsresult SetupJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue, nsACString &aMethodSig); + nsresult GetRetvalSig(const nsXPTParamInfo* aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsACString &aRetvalSig); + nsresult FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, + const XPTMethodDescriptor* aMethodInfo, + PRUint16 aMethodIndex, + nsXPTCMiniVariant* aDispatchParams, + nsXPTCMiniVariant &aVariant, + jvalue &aJValue); + nsresult SetXPCOMRetval(); + + jobject mJavaWeakRef; + jobject mJavaStrongRef; + jint mJavaRefHashCode; + nsCOMPtr mIInfo; + + nsVoidArray mChildren; // weak references (cleared by the children) + nsJavaXPTCStub *mMaster; // strong reference + + nsAutoRefCnt mWeakRefCnt; // count for number of associated weak refs +}; + +#ifdef VBOX +NS_DEFINE_STATIC_IID_ACCESSOR2(nsJavaXPTCStub, NS_JAVAXPTCSTUB_IID) +#else +NS_DEFINE_STATIC_IID_ACCESSOR2(nsJavaXPTCStub, NS_JAVAXPTCSTUB_IID) +#endif + +#endif // _nsJavaXPTCStub_h_ diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp new file mode 100644 index 00000000..cb98fc9b --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.cpp @@ -0,0 +1,98 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "jni.h" +#include "nsJavaXPTCStubWeakRef.h" +#include "nsJavaXPTCStub.h" +#include "nsJavaXPCOMBindingUtils.h" +#include "nsIInterfaceInfoManager.h" + + +/** + * How we handle XPCOM weak references to a Java object: + * + * If XPCOM requires or asks for a weak reference of a Java object, we first + * find (or create) an nsJavaXPTCStub for that Java object. That way, there is + * always an nsJavaXPTCStub for any nsJavaXPTCStubWeakRef. However, the + * XPTCStub may not always be 'valid'; that is, its refcount may be zero if + * is not currently referenced by any XPCOM class. + * When an XPCOM method queries the referent from the weak reference, the + * weak ref checks first whether the Java object is still valid. If so, we can + * immediately return an addref'd nsJavaXPTCStub. The XPTCStub takes care of + * finding an XPTCStub for the required IID. + */ + +nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(jobject aJavaObject, + nsJavaXPTCStub* aXPTCStub) + : mXPTCStub(aXPTCStub) +{ + JNIEnv* env = GetJNIEnv(); + jobject weakref = env->NewObject(weakReferenceClass, + weakReferenceConstructorMID, aJavaObject); + mWeakRef = env->NewGlobalRef(weakref); +} + +nsJavaXPTCStubWeakRef::~nsJavaXPTCStubWeakRef() +{ + JNIEnv* env = GetJNIEnv(); + env->CallVoidMethod(mWeakRef, clearReferentMID); + env->DeleteGlobalRef(mWeakRef); + mXPTCStub->ReleaseWeakRef(); +} + +NS_IMPL_ADDREF(nsJavaXPTCStubWeakRef) +NS_IMPL_RELEASE(nsJavaXPTCStubWeakRef) + +NS_IMPL_QUERY_INTERFACE1(nsJavaXPTCStubWeakRef, nsIWeakReference) + +NS_IMETHODIMP +nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr) +{ + LOG(("nsJavaXPTCStubWeakRef::QueryReferent()\n")); + + // Is weak ref still valid? + // We create a strong local ref to make sure Java object isn't garbage + // collected during this call. + JNIEnv* env = GetJNIEnv(); + jobject javaObject = env->CallObjectMethod(mWeakRef, getReferentMID); + if (env->IsSameObject(javaObject, NULL)) + return NS_ERROR_NULL_POINTER; + + // Java object has not been garbage collected, so return QI from XPTCStub. + return mXPTCStub->QueryInterface(aIID, aInstancePtr); +} + diff --git a/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h new file mode 100644 index 00000000..b538eecb --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsJavaXPTCStubWeakRef.h @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 _nsJavaXPTCStubWeakRef_h_ +#define _nsJavaXPTCStubWeakRef_h_ + +#include "jni.h" +#include "nsIWeakReference.h" + + +class nsJavaXPTCStub; + +/** + * This class represents an XPCOM weak reference to a Java object. + */ +class nsJavaXPTCStubWeakRef : public nsIWeakReference +{ +public: + nsJavaXPTCStubWeakRef(jobject aJavaObject, nsJavaXPTCStub* aXPTCStub); + virtual ~nsJavaXPTCStubWeakRef(); + NS_DECL_ISUPPORTS + NS_DECL_NSIWEAKREFERENCE + +protected: + jobject mWeakRef; + nsJavaXPTCStub* mXPTCStub; +}; + +#endif // _nsJavaXPTCStubWeakRef_h_ diff --git a/src/libs/xpcom18a4/java/src/nsThreadUtils.h b/src/libs/xpcom18a4/java/src/nsThreadUtils.h new file mode 100644 index 00000000..53f3dbdb --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsThreadUtils.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsThreadUtils_h__ +#define nsThreadUtils_h__ + + +#ifdef VBOX +#include "nsIThread.h" + +inline already_AddRefed +do_GetMainThread() { + nsIThread *thread = nsnull; + nsIThread::GetMainThread(&thread); + return already_AddRefed(thread); +} + +#include "VBox/com/NativeEventQueue.h" + +inline already_AddRefed do_GetMainThreadQueue() +{ + com::NativeEventQueue* eq = com::NativeEventQueue::getMainEventQueue(); + NS_ASSERTION(eq != nsnull, "Must be valid"); + return eq->getIEventQueue(); +} + +#else +#include "prthread.h" +#include "prinrval.h" +#include "nsIThreadManager.h" +#include "nsIThread.h" +#include "nsIRunnable.h" +#include "nsStringGlue.h" +#include "nsCOMPtr.h" + + +// This is needed on some systems to prevent collisions between the symbols +// appearing in xpcom_core and xpcomglue. It may be unnecessary in the future +// with better toolchain support. +#ifdef MOZILLA_INTERNAL_API +# define NS_NewThread NS_NewThread_P +# define NS_GetCurrentThread NS_GetCurrentThread_P +# define NS_GetMainThread NS_GetMainThread_P +# define NS_IsMainThread NS_IsMainThread_P +# define NS_DispatchToCurrentThread NS_DispatchToCurrentThread_P +# define NS_DispatchToMainThread NS_DispatchToMainThread_P +# define NS_ProcessPendingEvents NS_ProcessPendingEvents_P +# define NS_HasPendingEvents NS_HasPendingEvents_P +# define NS_ProcessNextEvent NS_ProcessNextEvent_P +#endif + +//----------------------------------------------------------------------------- +// These methods are alternatives to the methods on nsIThreadManager, provided +// for convenience. + +/** + * Create a new thread, and optionally provide an initial event for the thread. + * + * @param result + * The resulting nsIThread object. + * @param initialEvent + * The initial event to run on this thread. This parameter may be null. + * + * @returns NS_ERROR_INVALID_ARG + * Indicates that the given name is not unique. + */ +extern NS_COM_GLUE NS_METHOD +NS_NewThread(nsIThread **result, nsIRunnable *initialEvent = nsnull); + +/** + * Get a reference to the current thread. + * + * @param result + * The resulting nsIThread object. + */ +extern NS_COM_GLUE NS_METHOD +NS_GetCurrentThread(nsIThread **result); + +/** + * Get a reference to the main thread. + * + * @param result + * The resulting nsIThread object. + */ +extern NS_COM_GLUE NS_METHOD +NS_GetMainThread(nsIThread **result); + +/** + * Test to see if the current thread is the main thread. + * + * @returns PR_TRUE if the current thread is the main thread, and PR_FALSE + * otherwise. + */ +extern NS_COM_GLUE NS_METHOD_(PRBool) +NS_IsMainThread(); + +/** + * Dispatch the given event to the current thread. + * + * @param event + * The event to dispatch. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern NS_COM_GLUE NS_METHOD +NS_DispatchToCurrentThread(nsIRunnable *event); + +/** + * Dispatch the given event to the main thread. + * + * @param event + * The event to dispatch. + * @param dispatchFlags + * The flags to pass to the main thread's dispatch method. + * + * @returns NS_ERROR_INVALID_ARG + * If event is null. + */ +extern NS_COM_GLUE NS_METHOD +NS_DispatchToMainThread(nsIRunnable *event, + PRUint32 dispatchFlags = NS_DISPATCH_NORMAL); + +#ifndef XPCOM_GLUE_AVOID_NSPR +/** + * Process all pending events for the given thread before returning. This + * method simply calls ProcessNextEvent on the thread while HasPendingEvents + * continues to return true and the time spent in NS_ProcessPendingEvents + * does not exceed the given timeout value. + * + * @param thread + * The thread object for which to process pending events. If null, then + * events will be processed for the current thread. + * @param timeout + * The maximum number of milliseconds to spend processing pending events. + * Events are not pre-empted to honor this timeout. Rather, the timeout + * value is simply used to determine whether or not to process another event. + * Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout. + */ +extern NS_COM_GLUE NS_METHOD +NS_ProcessPendingEvents(nsIThread *thread, + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT); +#endif + +/** + * Shortcut for nsIThread::HasPendingEvents. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will return PR_FALSE if called from some + * other thread. + * + * @param thread + * The current thread or null. + * + * @returns + * A boolean value that if "true" indicates that there are pending events + * in the current thread's event queue. + */ +extern NS_COM_GLUE PRBool +NS_HasPendingEvents(nsIThread *thread = nsnull); + +/** + * Shortcut for nsIThread::ProcessNextEvent. + * + * It is an error to call this function when the given thread is not the + * current thread. This function will simply return PR_FALSE if called + * from some other thread. + * + * @param thread + * The current thread or null. + * @param mayWait + * A boolean parameter that if "true" indicates that the method may block + * the calling thread to wait for a pending event. + * + * @returns + * A boolean value that if "true" indicates that an event from the current + * thread's event queue was processed. + */ +extern NS_COM_GLUE PRBool +NS_ProcessNextEvent(nsIThread *thread = nsnull, PRBool mayWait = PR_TRUE); + +//----------------------------------------------------------------------------- +// Helpers that work with nsCOMPtr: + +inline already_AddRefed +do_GetCurrentThread() { + nsIThread *thread = nsnull; + NS_GetCurrentThread(&thread); + return already_AddRefed(thread); +} + +inline already_AddRefed +do_GetMainThread() { + nsIThread *thread = nsnull; + NS_GetMainThread(&thread); + return already_AddRefed(thread); +} + +//----------------------------------------------------------------------------- + +#ifdef MOZILLA_INTERNAL_API +// Fast access to the current thread. Do not release the returned pointer! If +// you want to use this pointer from some other thread, then you will need to +// AddRef it. Otherwise, you should only consider this pointer valid from code +// running on the current thread. +extern NS_COM_GLUE nsIThread *NS_GetCurrentThread(); +#endif + +//----------------------------------------------------------------------------- + +#ifndef XPCOM_GLUE_AVOID_NSPR + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_COM_GLUE + +// This class is designed to be subclassed. +class NS_COM_GLUE nsRunnable : public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + nsRunnable() { + } + +protected: + virtual ~nsRunnable() { + } +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +// An event that can be used to call a method on a class. The class type must +// support reference counting. +template +class nsRunnableMethod : public nsRunnable +{ +public: + typedef void (T::*Method)(); + + nsRunnableMethod(T *obj, Method method) + : mObj(obj), mMethod(method) { + NS_ADDREF(mObj); + } + + NS_IMETHOD Run() { + (mObj->*mMethod)(); + return NS_OK; + } + +private: + virtual ~nsRunnableMethod() { + NS_RELEASE(mObj); + } + + T *mObj; + Method mMethod; +}; + +// Use this helper macro like so: +// +// nsCOMPtr event = +// NS_NEW_RUNNABLE_METHOD(MyClass, myObject, HandleEvent); +// NS_DispatchToCurrentThread(event); +// +// Constraints: +// - myObject must be of type MyClass +// - MyClass must defined AddRef and Release methods +// +// NOTE: Attempts to make this a template function caused VC6 to barf :-( +// +#define NS_NEW_RUNNABLE_METHOD(class_, obj_, method_) \ + new nsRunnableMethod(obj_, &class_::method_) + +#endif // XPCOM_GLUE_AVOID_NSPR + +// This class is designed to be used when you have an event class E that has a +// pointer back to resource class R. If R goes away while E is still pending, +// then it is important to "revoke" E so that it does not try use R after R has +// been destroyed. nsRevocableEventPtr makes it easy for R to manage such +// situations: +// +// class R; +// +// class E : public nsRunnable { +// public: +// void Revoke() { +// mResource = nsnull; +// } +// private: +// R *mResource; +// }; +// +// class R { +// public: +// void EventHandled() { +// mEvent.Forget(); +// } +// private: +// nsRevocableEventPtr mEvent; +// }; +// +// void R::PostEvent() { +// // Make sure any pending event is revoked. +// mEvent->Revoke(); +// +// nsCOMPtr event = new E(); +// if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) { +// // Keep pointer to event so we can revoke it. +// mEvent = event; +// } +// } +// +// NS_IMETHODIMP E::Run() { +// if (!mResource) +// return NS_OK; +// ... +// mResource->EventHandled(); +// return NS_OK; +// } +// +template +class nsRevocableEventPtr { +public: + nsRevocableEventPtr() + : mEvent(nsnull) { + } + + ~nsRevocableEventPtr() { + Revoke(); + } + + const nsRevocableEventPtr& operator=(T *event) { + Revoke(); + mEvent = event; + return *this; + } + + void Revoke() { + if (mEvent) { + mEvent->Revoke(); + mEvent = nsnull; + } + } + + void Forget() { + mEvent = nsnull; + } + + PRBool IsPending() { + return mEvent != nsnull; + } + +private: + // Not implemented + nsRevocableEventPtr(const nsRevocableEventPtr&); + nsRevocableEventPtr& operator=(const nsRevocableEventPtr&); + + T *mEvent; +}; +#endif + +#endif // nsThreadUtils_h__ diff --git a/src/libs/xpcom18a4/java/src/nsXPTCUtils.h b/src/libs/xpcom18a4/java/src/nsXPTCUtils.h new file mode 100644 index 00000000..9a1fe3cc --- /dev/null +++ b/src/libs/xpcom18a4/java/src/nsXPTCUtils.h @@ -0,0 +1,128 @@ +/* ***** 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 Mozilla XPCOM. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation . + * Portions created by the Initial Developer are Copyright (C) 2006 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Benjamin Smedberg - New code + * + * 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 nsXPTCUtils_h__ +#define nsXPTCUtils_h__ + +#include "xptcall.h" + +#ifdef VBOX + +#define NS_DECLARE_STATIC_IID_ACCESSOR(the_iid) \ + template \ + struct COMTypeInfo \ + { \ + static const nsIID kIID NS_HIDDEN; \ + }; \ + static const nsIID& GetIID() {return COMTypeInfo::kIID;} + + +#define NS_DEFINE_STATIC_IID_ACCESSOR2(the_interface, the_iid) \ + template \ + const nsIID the_interface::COMTypeInfo::kIID NS_HIDDEN = the_iid; + + +class nsIXPTCProxy : public nsISupports +{ +public: + NS_IMETHOD CallMethod(PRUint16 aMethodIndex, + const XPTMethodDescriptor *aInfo, + nsXPTCMiniVariant *aParams) = 0; +}; + +/** + * This is a typedef to avoid confusion between the canonical + * nsISupports* that provides object identity and an interface pointer + * for inheriting interfaces that aren't known at compile-time. + */ +typedef nsISupports nsISomeInterface; + +/** + * Get a proxy object to implement the specified interface. + * + * @param aIID The IID of the interface to implement. + * @param aOuter An object to receive method calls from the proxy object. + * The stub forwards QueryInterface/AddRef/Release to the + * outer object. The proxy object does not hold a reference to + * the outer object; it is the caller's responsibility to + * ensure that this pointer remains valid until the stub has + * been destroyed. + * @param aStub Out parameter for the new proxy object. The object is + * not addrefed. The object never destroys itself. It must be + * explicitly destroyed by calling + * NS_DestroyXPTCallStub when it is no longer needed. + */ +XPTC_PUBLIC_API(nsresult) +NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, + nsISomeInterface* *aStub); + +/** + * Destroys an XPTCall stub previously created with NS_GetXPTCallStub. + */ +XPTC_PUBLIC_API(void) +NS_DestroyXPTCallStub(nsISomeInterface* aStub); + + +#endif + + +/** + * A helper class that initializes an xptcall helper at construction + * and releases it at destruction. + */ +class nsAutoXPTCStub : protected nsIXPTCProxy +{ +public: + nsISomeInterface* mXPTCStub; + +protected: + nsAutoXPTCStub() : mXPTCStub(nsnull) { } + + nsresult + InitStub(const nsIID& aIID) + { + return NS_GetXPTCallStub(aIID, this, &mXPTCStub); + } + + ~nsAutoXPTCStub() + { + if (mXPTCStub) + NS_DestroyXPTCallStub(mXPTCStub); + } +}; + +#endif // nsXPTCUtils_h__ diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java new file mode 100644 index 00000000..ede1a523 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/GREVersionRange.java @@ -0,0 +1,80 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + + +public class GREVersionRange { + + private String lower; + private boolean lowerInclusive; + private String upper; + private boolean upperInclusive; + + public GREVersionRange(String aLower, boolean aLowerInclusive, + String aUpper, boolean aUpperInclusive) { + lower = aLower; + lowerInclusive = aLowerInclusive; + upper = aUpper; + upperInclusive = aUpperInclusive; + } + + public boolean check(String aVersion) { + VersionComparator comparator = new VersionComparator(); + int c = comparator.compare(aVersion, lower); + if (c < 0) { + return false; + } + + if (c == 0 && !lowerInclusive) { + return false; + } + + c = comparator.compare(aVersion, upper); + if (c > 0) { + return false; + } + + if (c == 0 && !upperInclusive) { + return false; + } + + return true; + } + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java new file mode 100644 index 00000000..633d8bbc --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IAppFileLocProvider.java @@ -0,0 +1,92 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + + +/** + * Used by XPCOM's Directory Service to get file locations. + *

+ * This interface is similar to nsIDirectoryServiceProvider and + * nsIDirectoryServiceProvider2, except that its methods use + * java.io.File instead of nsIFile. + *

+ * + * @see Mozilla#initEmbedding + * @see Mozilla#initXPCOM + * @see + * nsIDirectoryServiceProvider + * @see + * Directory Service property names + */ +public interface IAppFileLocProvider { + + /** + * Directory Service calls this when it gets the first request for + * a property or on every request if the property is not persistent. + * + * @param prop the symbolic name of the file + * @param persistent an array of length one used to supply the output value: + *
    + *
  • true - The returned file will be + * cached by Directory Service. Subsequent requests for + * this prop will bypass the provider and use the cache. + *
  • + *
  • false - The provider will be asked + * for this prop each time it is requested.
  • + *
+ * + * @return the file represented by the property + */ + File getFile(String prop, boolean[] persistent); + + /** + * Directory Service calls this when it gets a request for + * a property and the requested type is nsISimpleEnumerator. + * + * @param prop the symbolic name of the file list + * + * @return an array of file locations + */ + File[] getFiles(String prop); + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java new file mode 100644 index 00000000..ecf000fe --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IGRE.java @@ -0,0 +1,127 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + + +public interface IGRE { + + /** + * Initializes libXUL for embedding purposes. + *

+ * NOTE: This function must be called from the "main" thread. + *

+ * NOTE: At the present time, this function may only be called once in + * a given process. Use termEmbedding to clean up and free + * resources allocated by initEmbedding. + * + * @param aLibXULDirectory The directory in which the libXUL shared library + * was found. + * @param aAppDirectory The directory in which the application components + * and resources can be found. This will map to + * the "resource:app" directory service key. + * @param aAppDirProvider A directory provider for the application. This + * provider will be aggregated by a libXUL provider + * which will provide the base required GRE keys. + * + * @throws XPCOMException if a failure occurred during initialization + */ + void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) throws XPCOMException; + + /** + * Terminates libXUL embedding. + *

+ * NOTE: Release any references to XPCOM objects that you may be holding + * before calling this function. + */ + void termEmbedding(); + + /** + * Lock a profile directory using platform-specific semantics. + * + * @param aDirectory The profile directory to lock. + * + * @return A lock object. The directory will remain locked until the lock is + * released by invoking the release method, or by the + * termination of the JVM, whichever comes first. + * + * @throws XPCOMException if a failure occurred + */ + ProfileLock lockProfileDirectory(File aDirectory) throws XPCOMException; + + /** + * Fire notifications to inform the toolkit about a new profile. This + * method should be called after initEmbedding if the + * embedder wishes to run with a profile. + *

+ * Normally the embedder should call lockProfileDirectory + * to lock the directory before calling this method. + *

+ * NOTE: There are two possibilities for selecting a profile: + *

    + *
  • + * Select the profile before calling initEmbedding. + * The aAppDirProvider object passed to initEmbedding + * should provide the NS_APP_USER_PROFILE_50_DIR key, and + * may also provide the following keys: + *
      + *
    • NS_APP_USER_PROFILE_LOCAL_50_DIR + *
    • NS_APP_PROFILE_DIR_STARTUP + *
    • NS_APP_PROFILE_LOCAL_DIR_STARTUP + *
    + * In this scenario notifyProfile should be called + * immediately after initEmbedding. Component + * registration information will be stored in the profile and + * JS components may be stored in the fastload cache. + *
  • + *
  • + * Select a profile some time after calling initEmbedding. + * In this case the embedder must install a directory service + * provider which provides NS_APP_USER_PROFILE_50_DIR and optionally + * NS_APP_USER_PROFILE_LOCAL_50_DIR. Component registration information + * will be stored in the application directory and JS components will not + * fastload. + *
  • + *
+ */ + void notifyProfile(); + +} + + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java new file mode 100644 index 00000000..7b70caf9 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IJavaXPCOMUtils.java @@ -0,0 +1,59 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +public interface IJavaXPCOMUtils { + + /** + * Returns a pointer to a C++ proxy object for the given Java object. + * + * @param aJavaObject Java object to encapsulate in C++ proxy + * @param aIID interface ID for requested proxy + * @return C pointer (as long) of new proxy + */ + long wrapJavaObject(Object aJavaObject, String aIID); + + /** + * Returns a Java proxy for the given C++ XPCOM object + * + * @param aXPCOMObject C++ XPCOM object to encapsulate in Java proxy + * @param aIID interface ID for requested proxy + * @return new Proxy + */ + Object wrapXPCOMObject(long aXPCOMObject, String aIID); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java new file mode 100644 index 00000000..b148e9a2 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IMozilla.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + +public interface IMozilla { + + /** + * Initialize the Mozilla object with the given XULRunner path. All + * subsequent Mozilla method invocations be done against the given XULRunner + * version. + * + * @param aLibXULDirectory path of XULRunner build to use + * + * @throws XPCOMInitializationException if failure occurred during + * initialization + */ + void initialize(File aLibXULDirectory) throws XPCOMInitializationException; + + /** + * Return the native window handle for an AWT component. + * + * @param widget An AWT component (such as Canvas, Frame) that is backed by + * a real native window. + * @return the pointer to the native window (platform specific) + */ + long getNativeHandleFromAWT(Object widget); +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java new file mode 100644 index 00000000..ba2f11c7 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/INIParser.java @@ -0,0 +1,243 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Properties; +import java.util.StringTokenizer; + + +/** + * A simple parser for INI files. + */ +public class INIParser { + + private HashMap mSections; + + /** + * Creates a new INIParser instance from the INI file at the + * given path. aCharset specifies the character encoding of + * the file. + * + * @param aFilename path of INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if aFilename does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(String aFilename, Charset aCharset) + throws FileNotFoundException, IOException { + initFromFile(new File(aFilename), aCharset); + } + + /** + * Creates a new INIParser instance from the INI file at the + * given path, which is assumed to be in the UTF-8 charset. + * + * @param aFilename path of INI file to parse + * @throws FileNotFoundException if aFilename does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(String aFilename) throws FileNotFoundException, IOException { + initFromFile(new File(aFilename), Charset.forName("UTF-8")); + } + + /** + * Creates a new INIParser instance from the given file. + * aCharset specifies the character encoding of the file. + * + * @param aFile INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if aFile does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(File aFile, Charset aCharset) + throws FileNotFoundException, IOException { + initFromFile(aFile, aCharset); + } + + /** + * Creates a new INIParser instance from the given file, + * which is assumed to be in the UTF-8 charset. + * + * @param aFile INI file to parse + * @throws FileNotFoundException if aFile does not exist. + * @throws IOException if there is a problem reading the given file. + */ + public INIParser(File aFile) throws FileNotFoundException, IOException { + initFromFile(aFile, Charset.forName("UTF-8")); + } + + /** + * Parses given INI file. + * + * @param aFile INI file to parse + * @param aCharset character encoding of file + * @throws FileNotFoundException if aFile does not exist. + * @throws IOException if there is a problem reading the given file. + */ + private void initFromFile(File aFile, Charset aCharset) + throws FileNotFoundException, IOException { + FileInputStream fileStream = new FileInputStream(aFile); + InputStreamReader inStream = new InputStreamReader(fileStream, aCharset); + BufferedReader reader = new BufferedReader(inStream); + + mSections = new HashMap(); + String currSection = null; + + String line; + while ((line = reader.readLine()) != null) { + // skip empty lines and comment lines + String trimmedLine = line.trim(); + if (trimmedLine.length() == 0 || trimmedLine.startsWith("#") + || trimmedLine.startsWith(";")) { + continue; + } + + // Look for section headers (i.e. "[Section]"). + if (line.startsWith("[")) { + /* + * We are looking for a well-formed "[Section]". If this header is + * malformed (i.e. "[Section" or "[Section]Moretext"), just skip it + * and go on to next well-formed section header. + */ + if (!trimmedLine.endsWith("]") || + trimmedLine.indexOf("]") != (trimmedLine.length() - 1)) { + currSection = null; + continue; + } + + // remove enclosing brackets + currSection = trimmedLine.substring(1, trimmedLine.length() - 1); + continue; + } + + // If we haven't found a valid section header, continue to next line + if (currSection == null) { + continue; + } + + StringTokenizer tok = new StringTokenizer(line, "="); + if (tok.countTokens() != 2) { // looking for value pairs + continue; + } + + Properties props = mSections.get(currSection); + if (props == null) { + props = new Properties(); + mSections.put(currSection, props); + } + props.setProperty(tok.nextToken(), tok.nextToken()); + } + + reader.close(); + } + + /** + * Returns an iterator over the section names available in the INI file. + * + * @return an iterator over the section names + */ + public Iterator getSections() { + return mSections.keySet().iterator(); + } + + /** + * Returns an iterator over the keys available within a section. + * + * @param aSection section name whose keys are to be returned + * @return an iterator over section keys, or null if no + * such section exists + */ + public Iterator getKeys(String aSection) { + /* + * Simple wrapper class to convert Enumeration to Iterator + */ + class PropertiesIterator implements Iterator { + private Enumeration e; + + public PropertiesIterator(Enumeration aEnum) { + e = aEnum; + } + + public boolean hasNext() { + return e.hasMoreElements(); + } + + public Object next() { + return e.nextElement(); + } + + public void remove() { + return; + } + } + + Properties props = mSections.get(aSection); + if (props == null) { + return null; + } + + return new PropertiesIterator(props.propertyNames()); + } + + /** + * Gets the string value for a particular section and key. + * + * @param aSection a section name + * @param aKey the key whose value is to be returned. + * @return string value of particular section and key + */ + public String getString(String aSection, String aKey) { + Properties props = mSections.get(aSection); + if (props == null) { + return null; + } + + return props.getProperty(aKey); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java new file mode 100644 index 00000000..8cfbfb30 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/IXPCOM.java @@ -0,0 +1,137 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; + + +public interface IXPCOM { + + /** + * Initializes XPCOM. You must call this method before proceeding + * to use XPCOM. + * + * @param aMozBinDirectory The directory containing the component + * registry and runtime libraries; + * or use null to use the working + * directory. + * + * @param aAppFileLocProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * null for the default behaviour. + * + * @return the service manager + * + * @throws XPCOMException
    + *
  • NS_ERROR_NOT_INITIALIZED - if static globals were not initialied, + * which can happen if XPCOM is reloaded, but did not completly + * shutdown.
  • + *
  • Other error codes indicate a failure during initialisation.
  • + *
+ */ + nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) throws XPCOMException; + + /** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @param aServMgr The service manager which was returned by initXPCOM. + * This will release servMgr. + * + * @throws XPCOMException if a failure occurred during termination + */ + void shutdownXPCOM(nsIServiceManager aServMgr) throws XPCOMException; + + /** + * Public Method to access to the service manager. + * + * @return the service manager + * + * @throws XPCOMException + */ + nsIServiceManager getServiceManager() throws XPCOMException; + + /** + * Public Method to access to the component manager. + * + * @return the component manager + * + * @throws XPCOMException + */ + nsIComponentManager getComponentManager() throws XPCOMException; + + /** + * Public Method to access to the component registration manager. + * + * @return the component registration manager + * + * @throws XPCOMException + */ + nsIComponentRegistrar getComponentRegistrar() throws XPCOMException; + + /** + * Public Method to create an instance of a nsILocalFile. + * + * @param aPath A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * @param aFollowLinks This attribute will determine if the nsLocalFile will + * auto resolve symbolic links. By default, this value + * will be false on all non unix systems. On unix, this + * attribute is effectively a noop. + * + * @return an instance of an nsILocalFile that points to given path + * + * @throws XPCOMException
    + *
  • NS_ERROR_FILE_UNRECOGNIZED_PATH - raised for unrecognized paths + * or relative paths (must supply full file path)
  • + *
+ */ + nsILocalFile newLocalFile(String aPath, boolean aFollowLinks) + throws XPCOMException; + + // #ifdef VBOX + int waitForEvents(long timeout); + // #endif VBOX +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java new file mode 100644 index 00000000..05314c90 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/Mozilla.java @@ -0,0 +1,1079 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; +import org.mozilla.interfaces.nsISupports; + + +/** + * A singleton class which provides access to the Mozilla browser. Requires + * that XULRunner be installed on the user's system. + *

+ * You would use to class to find a XULRunner installation, setup a profile (if + * necessary), and initialize embedding. A typical scenario would look like + * this: + *

+ * Mozilla mozilla = Mozilla.getInstance();
+ * GREVersionRange[] range = new GREVersionRange[1];
+ * range[0] = new GREVersionRange("1.8.0.*", false, "1.8.1.*", true);
+ * try {
+ *    File grePath = Mozilla.getGREPathWithProperties(range, null);
+ *    mozilla.initialize(grePath);
+ *    profLock = mozilla.lockProfileDirectory(profileDir);
+ *    // LocationProvider is a user class that implements IAppFileLocProvider
+ *    LocationProvider locProvider = new LocationProvider(grePath, profileDir);
+ *    mozilla.initEmbedding(grePath, grePath, locProvider);
+ *    mozilla.notifyProfile();
+ * } catch (XPCOMInitializationException xie) {
+ *    // handle exception
+ * } catch (XPCOMException xe) {
+ *    // handle exception
+ * }
+ * 
+ * + * @see http://www.mozilla.org/projects/embedding/GRE.html + */ +public class Mozilla implements IMozilla, IGRE, IXPCOM, IJavaXPCOMUtils,XPCOMError { + + private static Mozilla mozillaInstance = new Mozilla(); + + private static final String JAVAXPCOM_JAR = "vboxjxpcom.jar"; + + private IMozilla mozilla = null; + private IGRE gre = null; + private IXPCOM xpcom = null; + private IJavaXPCOMUtils jxutils = null; + + /** + * @return + */ + public static Mozilla getInstance() { + return mozillaInstance; + } + + /** + * + */ + private Mozilla() { + } + + /** + * Locates the path of a GRE with the specified properties. This method + * will only return GREs that support Java embedding (looks for the + * presence of "javaxpcom.jar"). + *

+ * Currently this uses a "first-fit" algorithm, it does not select + * the newest available GRE. + * + * @param aVersions An array of version ranges: if any version range + * matches, the GRE is considered acceptable. + * @param aProperties A list of GRE property/value pairs which must + * all be satisfied. This parameter is ignored on + * Macintosh, because of the manner in which the + * XUL frameworks are installed. + * + * @return A file object of the appropriate path. If + * the "local" GRE is specified (via the USE_LOCAL_GRE + * environment variable, for example), returns + * null. + * + * @throws FileNotFoundException if an appropriate GRE could not be found + */ + public static File getGREPathWithProperties(GREVersionRange[] aVersions, + Properties aProperties) throws FileNotFoundException { + File grePath = null; + + // if GRE_HOME is in the environment, use that GRE + String env = System.getProperty("GRE_HOME"); + if (env != null) { + try { + grePath = new File(env).getCanonicalFile(); + } catch (IOException e) { + throw new FileNotFoundException("cannot access GRE_HOME"); + } + if (!grePath.exists()) { + throw new FileNotFoundException("GRE_HOME doesn't exist"); + } + return grePath; + } + + // the Gecko bits that sit next to the application or in the PATH + env = System.getProperty("USE_LOCAL_GRE"); + if (env != null) { + return null; + } + + // Search for GRE in platform specific locations. We want a GRE that + // supports Java, so we look for the "javaxpcom" property by default. + if (aProperties == null) { + aProperties = new Properties(); + } + aProperties.setProperty("javaxpcom", "1"); + + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("mac os x")) { + grePath = getGREPathMacOSX(aVersions); + } else if (osName.startsWith("windows")) { + grePath = getGREPathWindows(aVersions, aProperties); + } else { + // assume everything else is Unix/Linux + grePath = getGREPathUnix(aVersions, aProperties); + } + + if (grePath == null) { + throw new FileNotFoundException("GRE not found"); + } + + return grePath; + } + + /** + * @param aVersions + * @return + */ + private static File getGREPathMacOSX(GREVersionRange[] aVersions) { + /* + * Check the application bundle first, for + * /Contents/Frameworks/XUL.framework/libxpcom.dylib. + */ + File grePath = findGREBundleFramework(); + if (grePath != null) { + return grePath; + } + + // Check ~/Library/Frameworks/XUL.framework/Versions//libxpcom.dylib + String home = System.getProperty("user.home"); + if (home != null) { + grePath = findGREFramework(home, aVersions); + if (grePath != null) { + return grePath; + } + } + + // Check /Library/Frameworks/XUL.framework/Versions//libxpcom.dylib + return findGREFramework("", aVersions); + } + + /** + * @return + */ + private static File findGREBundleFramework() { + /* + * Use reflection to get Apple's NSBundle class, which can be used + * to get the bundle's "Frameworks" directory. + */ + try { + URL[] urls = new URL[1]; + urls[0] = new File("/System/Library/Java/").toURI().toURL(); + ClassLoader loader = new URLClassLoader(urls); + Class bundleClass = Class.forName("com.apple.cocoa.foundation.NSBundle", + true, loader); + + // Get the bundle for this app. If this is not executing from + // a bundle, this will return null. + Method mainBundleMethod = bundleClass.getMethod("mainBundle", (java.lang.Class[])null); + Object bundle = mainBundleMethod.invoke(null, (java.lang.Object[])null); + + if (bundle != null) { + // Get the path to the bundle's "Frameworks" directory + Method fwPathMethod = bundleClass.getMethod("privateFrameworksPath", + (java.lang.Class[])null); + String path = (String) fwPathMethod.invoke(bundle, (java.lang.Object[])null); + + // look for libxpcom.dylib + if (path.length() != 0) { + File xulDir = new File(path, "XUL.framework"); + if (xulDir.isDirectory()) { + File xpcomLib = new File(xulDir, "libxpcom.dylib"); + if (xpcomLib.canRead()) { + File grePath = xpcomLib.getCanonicalFile().getParentFile(); + + // Since GRE Properties aren't supported on Mac OS X, we check + // for the existence of the "javaxpcom.jar" file in the GRE. + File jar = new File(grePath, JAVAXPCOM_JAR); + if (jar.canRead()) { + // found GRE + return grePath; + } + } + } + } + } + } catch (Exception e) { } + + return null; + } + + /** + * @param aRootPath + * @param aVersions + * @return + */ + private static File findGREFramework(String aRootPath, + GREVersionRange[] aVersions) { + File frameworkDir = new File(aRootPath + + "/Library/Frameworks/XUL.framework/Versions"); + if (!frameworkDir.exists()) + return null; + + File[] files = frameworkDir.listFiles(); + for (int i = 0; i < files.length; i++) { + if (checkVersion(files[i].getName(), aVersions)) { + File xpcomLib = new File(files[i], "libxpcom.dylib"); + + // Since GRE Properties aren't supported on Mac OS X, we check + // for the existence of the "javaxpcom.jar" file in the GRE. + File jar = new File(files[i], JAVAXPCOM_JAR); + if (xpcomLib.canRead() && jar.canRead()) { + return files[i]; + } + } + } + + return null; + } + + /** + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathWindows(GREVersionRange[] aVersions, + Properties aProperties) { + /* + * Note the usage of the "Software\\mozilla.org\\GRE" subkey - this allows + * us to have multiple versions of GREs on the same machine by having + * subkeys such as 1.0, 1.1, 2.0 etc. under it. + * + * Please see http://www.mozilla.org/projects/embedding/GRE.html for + * more info. + */ + + final String greKey = "Software\\mozilla.org\\GRE"; + + // See if there is a GRE registered for the current user. + // If not, look for one on the system. + String key = "HKEY_CURRENT_USER" + "\\" + greKey; + File grePath = getGREPathFromRegKey(key, aVersions, aProperties); + if (grePath == null) { + key = "HKEY_LOCAL_MACHINE" + "\\" + greKey; + grePath = getGREPathFromRegKey(key, aVersions, aProperties); + } + + return grePath; + } + + /** + * @param aRegKey + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathFromRegKey(String aRegKey, + GREVersionRange[] aVersions, Properties aProperties) { + // create a temp file for the registry export + File tempFile; + try { + tempFile = File.createTempFile("jx_registry", null); + } catch (IOException e) { + // failed to create temp file. ABORT + return null; + } + + Process proc; + try { + proc = Runtime.getRuntime().exec("regedit /e " + "\"" + tempFile.getPath() + + "\" \"" + aRegKey + "\""); + proc.waitFor(); + } catch (Exception e) { + // Failed to run regedit.exe. Length of temp file is zero, and that's + // handled next. + } + + // If there is a key by that name in the registry, then the file length + // will not be zero. + File grePath = null; + if (tempFile.length() != 0) { + grePath = getGREPathFromRegistryFile(tempFile.getPath(), + aRegKey, aVersions, aProperties); + } + + tempFile.delete(); + return grePath; + } + + /** + * @param aFileName + * @param aCharset + * @param aKeyName + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathFromRegistryFile(String aFileName, + String aKeyName, GREVersionRange[] aVersions, + Properties aProperties) { + INIParser parser; + try { + parser = new INIParser(aFileName, Charset.forName("UTF-16")); + } catch (Exception e) { + // Problem reading from file. Bail out. + return null; + } + + Iterator sectionsIter = parser.getSections(); + while (sectionsIter.hasNext()) { + // get 'section' name, which will be a registry key name + String section = (String) sectionsIter.next(); + + // Skip over GRE key ("\Software\mozilla.org\GRE") + int gre_len = aKeyName.length(); + if (section.length() <= gre_len) { + continue; + } + + // Get the GRE subkey; that is, everything after + // "\Software\mozilla.org\GRE\" + String subkeyName = section.substring(gre_len + 1); + + // We are only interested in _immediate_ subkeys. We want + // "\Software\mozilla.org\GRE\" but not + // "\Software\mozilla.org\GRE\\". + if (subkeyName.indexOf('\\') != -1) { + continue; + } + + // See if this registry key has a "Version" value, and if so, compare + // it to our desired versions. + String version = parser.getString(section, "\"Version\""); + if (version == null) { + continue; + } + // remove quotes around string + version = version.substring(1, version.length() - 1); + if (!checkVersion(version, aVersions)) { + continue; + } + + // All properties must match, keeping in mind that the propery/value + // pairs returned by regedit.exe have quotes around them. + if (aProperties != null) { + boolean ok = true; + Enumeration e = aProperties.propertyNames(); + while (ok && e.hasMoreElements()) { + String prop = (String) e.nextElement(); + String greValue = parser.getString(section, "\"" + prop + "\""); + if (greValue == null) { + // No such property is set for this GRE. Go on to next GRE. + ok = false; + } else { + // See if the value of the property for the GRE matches + // the given value. + String value = aProperties.getProperty(prop); + if (!greValue.equals("\"" + value + "\"")) { + ok = false; + } + } + } + if (!ok) { + continue; + } + } + + String pathStr = parser.getString(section, "\"GreHome\""); + if (pathStr != null) { + // remove quotes around string + pathStr = pathStr.substring(1, pathStr.length() - 1); + File grePath = new File(pathStr); + if (grePath.exists()) { + File xpcomLib = new File(grePath, "xpcom.dll"); + if (xpcomLib.canRead()) { + // found a good GRE + return grePath; + } + } + } + } + + return null; + } + + /** + * @param aVersions + * @param aProperties + * @return + */ + private static File getGREPathUnix(GREVersionRange[] aVersions, + Properties aProperties) { + File grePath = null; + + String env = System.getProperty("MOZ_GRE_CONF"); + if (env != null) { + grePath = getPathFromConfigFile(env, aVersions, aProperties); + if (grePath != null) { + return grePath; + } + } + + final String greUserConfFile = ".gre.config"; + final String greUserConfDir = ".gre.d"; + final String greConfPath = "/etc/gre.conf"; + final String greConfDir = "/etc/gre.d"; + + env = System.getProperty("user.home"); + if (env != null) { + // Look in ~/.gre.config + grePath = getPathFromConfigFile(env + File.separator + greUserConfFile, + aVersions, aProperties); + if (grePath != null) { + return grePath; + } + + // Look in ~/.gre.d/*.conf + grePath = getPathFromConfigDir(env + File.separator + greUserConfDir, + aVersions, aProperties); + if (grePath != null) { + return grePath; + } + } + + // Look for a global /etc/gre.conf file + grePath = getPathFromConfigFile(greConfPath, aVersions, aProperties); + if (grePath != null) { + return grePath; + } + + // Look for a group of config files in /etc/gre.d/ + grePath = getPathFromConfigDir(greConfDir, aVersions, aProperties); + return grePath; + } + + /** + * @param aFileName + * @param aVersions + * @param aProperties + * @return + */ + private static File getPathFromConfigFile(String aFileName, + GREVersionRange[] aVersions, Properties aProperties) { + INIParser parser; + try { + parser = new INIParser(aFileName); + } catch (Exception e) { + // Problem reading from file. Bail out. + return null; + } + + Iterator sectionsIter = parser.getSections(); + while (sectionsIter.hasNext()) { + // get 'section' name, which will be a version string + String section = (String) sectionsIter.next(); + + // if this isn't one of the versions we are looking for, move + // on to next section + if (!checkVersion(section, aVersions)) { + continue; + } + + // all properties must match + if (aProperties != null) { + boolean ok = true; + Enumeration e = aProperties.propertyNames(); + while (ok && e.hasMoreElements()) { + String prop = (String) e.nextElement(); + String greValue = parser.getString(section, prop); + if (greValue == null) { + // No such property is set for this GRE. Go on to next GRE. + ok = false; + } else { + // See if the value of the property for the GRE matches + // the given value. + if (!greValue.equals(aProperties.getProperty(prop))) { + ok = false; + } + } + } + if (!ok) { + continue; + } + } + + String pathStr = parser.getString(section, "GRE_PATH"); + if (pathStr != null) { + File grePath = new File(pathStr); + if (grePath.exists()) { + File xpcomLib = new File(grePath, "libxpcom.so"); + if (xpcomLib.canRead()) { + // found a good GRE + return grePath; + } + } + } + } + + return null; + } + + /** + * @param aDirName + * @param aVersions + * @param aProperties + * @return + */ + private static File getPathFromConfigDir(String aDirName, + GREVersionRange[] aVersions, Properties aProperties) { + /* + * Open the directory provided and try to read any files in that + * directory that end with .conf. We look for an entry that might + * point to the GRE that we're interested in. + */ + + File dir = new File(aDirName); + if (!dir.isDirectory()) { + return null; + } + + File grePath = null; + File[] files = dir.listFiles(); + for (int i = 0; i < files.length && grePath == null; i++) { + // only look for files that end in '.conf' + if (!files[i].getName().endsWith(".conf")) { + continue; + } + + grePath = getPathFromConfigFile(files[i].getPath(), aVersions, + aProperties); + } + + return grePath; + } + + /** + * @param aVersionToCheck + * @param aVersions + * @return + */ + private static boolean checkVersion(String aVersionToCheck, + GREVersionRange[] aVersions) { + for (int i = 0; i < aVersions.length; i++) { + if (aVersions[i].check(aVersionToCheck)) { + return true; + } + } + return false; + } + + /** + * Initialize the Mozilla object with the given XULRunner path. All + * subsequent Mozilla method invocations be done against the given XULRunner + * version. + * + * @param aLibXULDirectory path of XULRunner build to use + * + * @throws XPCOMInitializationException if failure occurred during + * initialization + */ + public void initialize(File aLibXULDirectory) + throws XPCOMInitializationException { + File jar = new File(aLibXULDirectory, JAVAXPCOM_JAR); + if (!jar.exists()) { + jar = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()); + if (!jar.exists()) + throw new XPCOMInitializationException("Could not find " + JAVAXPCOM_JAR + + " in " + aLibXULDirectory); + } + + URL[] urls = new URL[1]; + try { + urls[0] = jar.toURI().toURL(); + } catch (MalformedURLException e) { + throw new XPCOMInitializationException(e); + } + ClassLoader loader = new URLClassLoader(urls, + this.getClass().getClassLoader()); + + try { + Class mozillaClass = Class.forName("org.mozilla.xpcom.internal.MozillaImpl", + true, loader); + mozilla = (IMozilla) mozillaClass.newInstance(); + + Class greClass = Class.forName("org.mozilla.xpcom.internal.GREImpl", + true, loader); + gre = (IGRE) greClass.newInstance(); + + Class xpcomClass = Class.forName("org.mozilla.xpcom.internal.XPCOMImpl", + true, loader); + xpcom = (IXPCOM) xpcomClass.newInstance(); + + Class javaXPCOMClass = + Class.forName("org.mozilla.xpcom.internal.JavaXPCOMMethods", + true, loader); + jxutils = (IJavaXPCOMUtils) javaXPCOMClass.newInstance(); + } catch (Exception e) { + throw new XPCOMInitializationException("Could not load " + + "org.mozilla.xpcom.internal.* classes", e); + } + + mozilla.initialize(aLibXULDirectory); + } + + /** + * Initializes libXUL for embedding purposes. + *

+ * NOTE: This function must be called from the "main" thread. + *

+ * NOTE: At the present time, this function may only be called once in + * a given process. Use termEmbedding to clean up and free + * resources allocated by initEmbedding. + * + * @param aLibXULDirectory The directory in which the libXUL shared library + * was found. + * @param aAppDirectory The directory in which the application components + * and resources can be found. This will map to + * the "resource:app" directory service key. + * @param aAppDirProvider A directory provider for the application. This + * provider will be aggregated by a libXUL provider + * which will provide the base required GRE keys. + * + * @throws XPCOMException if a failure occurred during initialization + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) throws XPCOMException { + try { + gre.initEmbedding(aLibXULDirectory, aAppDirectory, aAppDirProvider); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Terminates libXUL embedding. + *

+ * NOTE: Release any references to XPCOM objects that you may be holding + * before calling this function. + * + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void termEmbedding() { + try { + gre.termEmbedding(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } finally { + mozilla = null; + gre = null; + xpcom = null; + } + } + + /** + * Lock a profile directory using platform-specific semantics. + * + * @param aDirectory The profile directory to lock. + * + * @return A lock object. The directory will remain locked until the lock is + * released by invoking the release method, or by the + * termination of the JVM, whichever comes first. + * + * @throws XPCOMException if profile is already locked (with + * errorcode == NS_ERROR_FILE_ACCESS_DENIED); + * or if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public ProfileLock lockProfileDirectory(File aDirectory) + throws XPCOMException { + try { + return gre.lockProfileDirectory(aDirectory); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Fire notifications to inform the toolkit about a new profile. This + * method should be called after initEmbedding if the + * embedder wishes to run with a profile. + *

+ * Normally the embedder should call lockProfileDirectory + * to lock the directory before calling this method. + *

+ * NOTE: There are two possibilities for selecting a profile: + *

    + *
  • + * Select the profile before calling initEmbedding. + * The aAppDirProvider object passed to initEmbedding + * should provide the NS_APP_USER_PROFILE_50_DIR key, and + * may also provide the following keys: + *
      + *
    • NS_APP_USER_PROFILE_LOCAL_50_DIR + *
    • NS_APP_PROFILE_DIR_STARTUP + *
    • NS_APP_PROFILE_LOCAL_DIR_STARTUP + *
    + * In this scenario notifyProfile should be called + * immediately after initEmbedding. Component + * registration information will be stored in the profile and + * JS components may be stored in the fastload cache. + *
  • + *
  • + * Select a profile some time after calling initEmbedding. + * In this case the embedder must install a directory service + * provider which provides NS_APP_USER_PROFILE_50_DIR and optionally + * NS_APP_USER_PROFILE_LOCAL_50_DIR. Component registration information + * will be stored in the application directory and JS components will not + * fastload. + *
  • + *
+ * + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void notifyProfile() { + try { + gre.notifyProfile(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Initializes XPCOM. You must call this method before proceeding + * to use XPCOM. + * + * @param aMozBinDirectory The directory containing the component + * registry and runtime libraries; + * or use null to use the working + * directory. + * + * @param aAppFileLocProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * null for the default behaviour. + * + * @return the service manager + * + * @throws XPCOMException
    + *
  • NS_ERROR_NOT_INITIALIZED - if static globals were not initialied, + * which can happen if XPCOM is reloaded, but did not completly + * shutdown.
  • + *
  • Other error codes indicate a failure during initialisation.
  • + *
+ * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) throws XPCOMException { + try { + return xpcom.initXPCOM(aMozBinDirectory, aAppFileLocProvider); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @param aServMgr The service manager which was returned by initXPCOM. + * This will release servMgr. + * + * @throws XPCOMException if a failure occurred during termination + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public void shutdownXPCOM(nsIServiceManager aServMgr) throws XPCOMException { + try { + xpcom.shutdownXPCOM(aServMgr); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } finally { + mozilla = null; + gre = null; + xpcom = null; + } + } + + /** + * Public Method to access to the service manager. + * + * @return the service manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIServiceManager getServiceManager() throws XPCOMException { + try { + return xpcom.getServiceManager(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Public Method to access to the component manager. + * + * @return the component manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIComponentManager getComponentManager() throws XPCOMException { + try { + return xpcom.getComponentManager(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * Public Method to access to the component registration manager. + * + * @return the component registration manager + * + * @throws XPCOMException if a failure occurred + * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsIComponentRegistrar getComponentRegistrar() throws XPCOMException { + try { + return xpcom.getComponentRegistrar(); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + // #ifdef VBOX + public int waitForEvents(long tmo) throws XPCOMException { + try { + return xpcom.waitForEvents(tmo); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + // #endif // VBOX + + /** + * Public Method to create an instance of a nsILocalFile. + * + * @param aPath A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * @param aFollowLinks This attribute will determine if the nsLocalFile will + * auto resolve symbolic links. By default, this value + * will be false on all non unix systems. On unix, this + * attribute is effectively a noop. + * + * @return an instance of an nsILocalFile that points to given path + * + * @throws XPCOMException
    + *
  • NS_ERROR_FILE_UNRECOGNIZED_PATH - raised for unrecognized paths + * or relative paths (must supply full file path)
  • + *
+ * @throws XPCOMInitializationException if Mozilla was not properly + * initialized + */ + public nsILocalFile newLocalFile(String aPath, boolean aFollowLinks) + throws XPCOMException { + try { + return xpcom.newLocalFile(aPath, aFollowLinks); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + /** + * If you create a class that implements nsISupports, you will need to provide + * an implementation of the queryInterface method. This helper + * function provides a simple implementation. Therefore, if your class does + * not need to do anything special with queryInterface, your + * implementation would look like: + *
+   *      public nsISupports queryInterface(String aIID) {
+   *        return XPCOM.queryInterface(this, aIID);
+   *      }
+   * 
+ * + * @param aObject object to query + * @param aIID requested interface IID + * + * @return aObject if the given object supports that + * interface; + * null otherwise. + */ + public static nsISupports queryInterface(nsISupports aObject, String aIID) { + ArrayList classes = new ArrayList(); + classes.add(aObject.getClass()); + + while (!classes.isEmpty()) { + Class clazz = classes.remove(0); + + // Skip over any class/interface in the "java.*" and "javax.*" domains. + String className = clazz.getName(); + if (className.startsWith("java.") || className.startsWith("javax.")) { + continue; + } + + // If given IID matches that of the current interface, then we + // know that aObject implements the interface specified by the given IID. + if (clazz.isInterface() && className.startsWith("org.mozilla")) { + String iid = Mozilla.getInterfaceIID(clazz); + if (iid != null && aIID.equals(iid)) { + return aObject; + } + } + + // clazz didn't match, so add the interfaces it implements + Class[] interfaces = clazz.getInterfaces(); + for (int i = 0; i < interfaces.length; i++ ) { + classes.add(interfaces[i]); + } + + // Also add its superclass + Class superclass = clazz.getSuperclass(); + if (superclass != null) { + classes.add(superclass); + } + } + + return null; + } + + /** + * Gets the interface IID for a particular Java interface. This is similar + * to NS_GET_IID in the C++ Mozilla files. + * + * @param aInterface interface which has defined an IID + * + * @return IID for given interface + */ + public static String getInterfaceIID(Class aInterface) { + // Get short class name (i.e. "bar", not "org.blah.foo.bar") + StringBuffer iidName = new StringBuffer(); + String fullClassName = aInterface.getName(); + int index = fullClassName.lastIndexOf("."); + String className = index > 0 ? fullClassName.substring(index + 1) + : fullClassName; + + // Create iid field name + if (className.startsWith("ns")) { + iidName.append("NS_"); + iidName.append(className.substring(2).toUpperCase()); + } else { + iidName.append(className.toUpperCase()); + } + iidName.append("_IID"); + + String iid; + try { + Field iidField = aInterface.getDeclaredField(iidName.toString()); + iid = (String) iidField.get(null); + } catch (NoSuchFieldException e) { + // Class may implement non-Mozilla interfaces, which would not have an + // IID method. In that case, just null. + iid = null; + } catch (IllegalAccessException e) { + // Not allowed to access that field for some reason. Write out an + // error message, but don't fail. + System.err.println("ERROR: Could not get field " + iidName.toString()); + iid = null; + } + + return iid; + } + + public long getNativeHandleFromAWT(Object widget) { + try { + return mozilla.getNativeHandleFromAWT(widget); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + public long wrapJavaObject(Object aJavaObject, String aIID) { + try { + return jxutils.wrapJavaObject(aJavaObject, aIID); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + + public Object wrapXPCOMObject(long aXPCOMObject, String aIID) { + try { + return jxutils.wrapXPCOMObject(aXPCOMObject, aIID); + } catch (NullPointerException e) { + throw new XPCOMInitializationException("Must call " + + "Mozilla.getInstance().initialize() before using this method", e); + } + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java new file mode 100644 index 00000000..f995a389 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/ProfileLock.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +public class ProfileLock { + + private long lock = 0; + + public ProfileLock(long aLockObject) { + lock = aLockObject; + } + + public void release() { + releaseNative(lock); + lock = 0; + } + + private native void releaseNative(long aLockObject); + + public boolean isValid() { + return lock != 0; + } + + protected void finalize() throws Throwable { + release(); + super.finalize(); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java new file mode 100644 index 00000000..f9fb1058 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/VersionComparator.java @@ -0,0 +1,272 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + +import java.util.Enumeration; +import java.util.StringTokenizer; + +import org.mozilla.interfaces.nsISupports; +/* import org.mozilla.interfaces.nsIVersionComparator; */ + + +/** + * Version strings are dot-separated sequences of version-parts. + *

+ * A version-part consists of up to four parts, all of which are optional: + *
+ * <number-a><string-b><number-c> + * <string-d (everything else)> + *

+ * A version-part may also consist of a single asterisk "*" which indicates + * "infinity". + *

+ * Numbers are base-10, and are zero if left out. + * Strings are compared bytewise. + *

+ * For additional backwards compatibility, if "string-b" is "+" then + * "number-a" is incremented by 1 and "string-b" becomes "pre". + *

+ * 1.0pre1
+ * < 1.0pre2
+ *   < 1.0 == 1.0.0 == 1.0.0.0
+ *     < 1.1pre == 1.1pre0 == 1.0+
+ *       < 1.1pre1a
+ *         < 1.1pre1
+ *           < 1.1pre10a
+ *             < 1.1pre10
+ * 
+ * Although not required by this interface, it is recommended that + * numbers remain within the limits of a signed char, i.e. -127 to 128. + */ +public class VersionComparator implements nsISupports /* implements nsIVersionComparator */ { + + public nsISupports queryInterface(String aIID) { + return Mozilla.queryInterface(this, aIID); + } + + /** + * Compare two version strings + * @param A a version string + * @param B a version string + * @return a value less than 0 if A < B; + * the value 0 if A == B; + * or a value greater than 0 if A > B + */ + public int compare(String A, String B) { + int result; + String a = A, b = B; + + do { + VersionPart va = new VersionPart(); + VersionPart vb = new VersionPart(); + a = parseVersionPart(a, va); + b = parseVersionPart(b, vb); + + result = compareVersionPart(va, vb); + if (result != 0) { + break; + } + } while (a != null || b != null); + + return result; + } + + private class VersionPart { + int numA = 0; + String strB; + int numC = 0; + String extraD; + } + + private static String parseVersionPart(String aVersion, VersionPart result) { + if (aVersion == null || aVersion.length() == 0) { + return aVersion; + } + + StringTokenizer tok = new StringTokenizer(aVersion.trim(), "."); + String part = tok.nextToken(); + + if (part.equals("*")) { + result.numA = Integer.MAX_VALUE; + result.strB = ""; + } else { + VersionPartTokenizer vertok = new VersionPartTokenizer(part); + try { + result.numA = Integer.parseInt(vertok.nextToken()); + } catch (NumberFormatException e) { + // parsing error; default to zero like 'strtol' C function + result.numA = 0; + } + + if (vertok.hasMoreElements()) { + String str = vertok.nextToken(); + + // if part is of type "+" + if (str.charAt(0) == '+') { + result.numA++; + result.strB = "pre"; + } else { + // else if part is of type "..." + result.strB = str; + + if (vertok.hasMoreTokens()) { + try { + result.numC = Integer.parseInt(vertok.nextToken()); + } catch (NumberFormatException e) { + // parsing error; default to zero like 'strtol' C function + result.numC = 0; + } + if (vertok.hasMoreTokens()) { + result.extraD = vertok.getRemainder(); + } + } + } + } + } + + if (tok.hasMoreTokens()) { + // return everything after "." + return aVersion.substring(part.length() + 1); + } + return null; + } + + private int compareVersionPart(VersionPart va, VersionPart vb) { + int res = compareInt(va.numA, vb.numA); + if (res != 0) { + return res; + } + + res = compareString(va.strB, vb.strB); + if (res != 0) { + return res; + } + + res = compareInt(va.numC, vb.numC); + if (res != 0) { + return res; + } + + return compareString(va.extraD, vb.extraD); + } + + private int compareInt(int n1, int n2) { + return n1 - n2; + } + + private int compareString(String str1, String str2) { + // any string is *before* no string + if (str1 == null) { + return (str2 != null) ? 1 : 0; + } + + if (str2 == null) { + return -1; + } + + return str1.compareTo(str2); + } + +} + +/** + * Specialized tokenizer for Mozilla version strings. A token can + * consist of one of the four sections of a version string: + * <number-a><string-b><number-c> + * <string-d (everything else)>. + */ +class VersionPartTokenizer implements Enumeration { + + String part; + + public VersionPartTokenizer(String aPart) { + part = aPart; + } + + public boolean hasMoreElements() { + return part.length() != 0; + } + + public boolean hasMoreTokens() { + return part.length() != 0; + } + + public Object nextElement() { + if (part.matches("[\\+\\-]?[0-9].*")) { + // if string starts with a number... + int index = 0; + if (part.charAt(0) == '+' || part.charAt(0) == '-') { + index = 1; + } + + while (index < part.length() && Character.isDigit(part.charAt(index))) { + index++; + } + + String numPart = part.substring(0, index); + part = part.substring(index); + return numPart; + } else { + // ... or if this is the non-numeric part of version string + int index = 0; + while (index < part.length() && !Character.isDigit(part.charAt(index))) { + index++; + } + + String alphaPart = part.substring(0, index); + part = part.substring(index); + return alphaPart; + } + } + + public String nextToken() { + return (String) nextElement(); + } + + /** + * Returns what remains of the original string, without tokenization. This + * method is useful for getting the <string-d (everything else)> + * section of a version string. + * + * @return remaining version string + */ + public String getRemainder() { + return part; + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java new file mode 100644 index 00000000..9eca58f6 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMException.java @@ -0,0 +1,95 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + + +/** + * This exception is thrown whenever an internal XPCOM/Gecko error occurs. + * You can query the error ID returned by XPCOM by checking + * errorcode field. + */ +public class XPCOMException extends RuntimeException { + + /** + * The XPCOM error value. + */ + public long errorcode; + + private static final long serialVersionUID = 198521829884000593L; + + /** + * Constructs a new XPCOMException instance, with a default error + * (NS_ERROR_FAILURE) and message. + */ + public XPCOMException() { + this(0x80004005L, "Unspecified internal XPCOM error"); + } + + /** + * Constructs a new XPCOMException instance with the given message, passing + * NS_ERROR_FAILURE as the error code. + * + * @param message detailed message of exception + */ + public XPCOMException(String message) { + this(0x80004005L, message); + } + + /** + * Constructs a new XPCOMException instance with the given code, passing + * a default message. + * + * @param code internal XPCOM error ID + */ + public XPCOMException(long code) { + this(code, "Internal XPCOM error"); + } + + /** + * Constructs a new XPCOMException instance with an error code and message. + * + * @param code internal XPCOM error ID + * @param message detailed message of exception + */ + public XPCOMException(long code, String message) { + super(message + " (0x" + Long.toHexString(code) + ")"); + this.errorcode = code; + } + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java new file mode 100644 index 00000000..26ce5325 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/XPCOMInitializationException.java @@ -0,0 +1,56 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom; + + +public class XPCOMInitializationException extends RuntimeException { + + private static final long serialVersionUID = -7067350325909231055L; + + public XPCOMInitializationException(String message) { + super(message); + } + + public XPCOMInitializationException(Throwable cause) { + super(cause); + } + + public XPCOMInitializationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java new file mode 100644 index 00000000..74821c36 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/GREImpl.java @@ -0,0 +1,63 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IAppFileLocProvider; +import org.mozilla.xpcom.IGRE; +import org.mozilla.xpcom.ProfileLock; + + +public class GREImpl implements IGRE { + + public void initEmbedding(File aLibXULDirectory, File aAppDirectory, + IAppFileLocProvider aAppDirProvider) { + initEmbeddingNative(aLibXULDirectory, aAppDirectory, aAppDirProvider); + } + + public native void initEmbeddingNative(File aLibXULDirectory, + File aAppDirectory, IAppFileLocProvider aAppDirProvider); + + public native void termEmbedding(); + + public native ProfileLock lockProfileDirectory(File aDirectory); + + public native void notifyProfile(); + +} + diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java new file mode 100644 index 00000000..ab0ca251 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/JavaXPCOMMethods.java @@ -0,0 +1,104 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IJavaXPCOMUtils; + + +public class JavaXPCOMMethods implements IJavaXPCOMUtils { + + public static void registerJavaXPCOMMethods(File aLibXULDirectory) { + // load JNI library + String path = ""; + if (aLibXULDirectory != null) { + path = aLibXULDirectory + File.separator; + } + + if (false) + { + String osName = System.getProperty("os.name").toLowerCase(); + if (osName.startsWith("os/2")) { + System.load(path + System.mapLibraryName("jxpcmglu")); + } else { + System.load(path + System.mapLibraryName("javaxpcomglue")); + } + } else { + // #ifdef VBOX + try { + System.load(path + System.mapLibraryName("vboxjxpcom")); + } catch (java.lang.UnsatisfiedLinkError ule) { + System.loadLibrary("vboxjxpcom"); + } + // #endif + } + registerJavaXPCOMMethodsNative(aLibXULDirectory); + } + + public static native void + registerJavaXPCOMMethodsNative(File aLibXULDirectory); + + /** + * Returns the Class object associated with the class or interface with the + * given string name, using the class loader of the given object. + * + * @param aObject the Java object whose class loader is used to load class + * @param aClassName the fully qualified name of desired class + * @return the Class object of requested Class; null if the + * class was not found + * + * @see http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#classops + */ + public static Class findClassInLoader(Object aObject, String aClassName) { + try { + if (aObject == null) { + return Class.forName(aClassName); + } else { + return Class.forName(aClassName, true, + aObject.getClass().getClassLoader()); + } + } catch (ClassNotFoundException e) { + return null; + } + } + + public native long wrapJavaObject(Object aJavaObject, String aIID); + + public native Object wrapXPCOMObject(long aXPCOMObject, String aIID); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java new file mode 100644 index 00000000..27fd9482 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/MozillaImpl.java @@ -0,0 +1,56 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IMozilla; +import org.mozilla.xpcom.XPCOMInitializationException; + +public class MozillaImpl implements IMozilla { + + public void initialize(File aLibXULDirectory) + throws XPCOMInitializationException { + JavaXPCOMMethods.registerJavaXPCOMMethods(aLibXULDirectory); + initializeNative(); + } + + private native void initializeNative(); + + public native long getNativeHandleFromAWT(Object widget); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java new file mode 100644 index 00000000..1111a9e0 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMImpl.java @@ -0,0 +1,73 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2006 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.io.File; + +import org.mozilla.xpcom.IAppFileLocProvider; +import org.mozilla.xpcom.IXPCOM; + +import org.mozilla.interfaces.nsIComponentManager; +import org.mozilla.interfaces.nsIComponentRegistrar; +import org.mozilla.interfaces.nsILocalFile; +import org.mozilla.interfaces.nsIServiceManager; + + +public class XPCOMImpl implements IXPCOM { + + public nsIServiceManager initXPCOM(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider) { + return initXPCOMNative(aMozBinDirectory, aAppFileLocProvider); + } + + public native nsIServiceManager initXPCOMNative(File aMozBinDirectory, + IAppFileLocProvider aAppFileLocProvider); + + public native void shutdownXPCOM(nsIServiceManager aServMgr); + + public native nsIComponentManager getComponentManager(); + + public native nsIComponentRegistrar getComponentRegistrar(); + + public native nsIServiceManager getServiceManager(); + + public native nsILocalFile newLocalFile(String aPath, boolean aFollowLinks); + + // #ifdef VBOX + public native int waitForEvents(long timeout); + // #endif VBOX +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java new file mode 100644 index 00000000..c6485708 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxy.java @@ -0,0 +1,257 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.mozilla.xpcom.XPCOMException; + + +/** + * This class is used to pass XPCOM objects to Java functions. A + * java.lang.reflect.Proxy instance is created using the expected + * interface, and all calls to the proxy are forwarded to the XPCOM object. + */ +public class XPCOMJavaProxy implements InvocationHandler { + + /** + * Pointer to the XPCOM object for which we are a proxy. + */ + protected long nativeXPCOMPtr; + + /** + * Default constructor. + * + * @param aXPCOMInstance address of XPCOM object as a long + */ + public XPCOMJavaProxy(long aXPCOMInstance) { + nativeXPCOMPtr = aXPCOMInstance; + } + + /** + * Returns the XPCOM object that the given proxy references. + * + * @param aProxy Proxy created by createProxy + * + * @return address of XPCOM object as a long + */ + protected static long getNativeXPCOMInstance(Object aProxy) { + XPCOMJavaProxy proxy = (XPCOMJavaProxy) Proxy.getInvocationHandler(aProxy); + return proxy.nativeXPCOMPtr; + } + + /** + * Creates a Proxy for the given XPCOM object. + * + * @param aInterface interface from which to create Proxy + * @param aXPCOMInstance address of XPCOM object as a long + * + * @return Proxy of given XPCOM object + */ + protected static Object createProxy(Class aInterface, long aXPCOMInstance) { + // XXX We should really get the class loader from |aInterface|. However, + // that class loader doesn't know about |XPCOMJavaProxyBase|. So for + // now, we get the class loader that loaded |XPCOMJavaProxy|. When + // we get rid of the "XPCOMJavaProxyBase.java" class, we can revert + // to the old method below. +// return Proxy.newProxyInstance(aInterface.getClassLoader(), + return Proxy.newProxyInstance(XPCOMJavaProxy.class.getClassLoader(), + new Class[] { aInterface, XPCOMJavaProxyBase.class }, + new XPCOMJavaProxy(aXPCOMInstance)); + } + + /** + * All calls to the Java proxy are forwarded to this method. This method + * takes care of a few of the Object method calls; all other + * calls are forwarded to the XPCOM object. + * + * @param aProxy Proxy created by createProxy + * @param aMethod object that describes the called method + * @param aParams array of the arguments passed to the method + * + * @return return value as defined by given aMethod + */ + public Object invoke(Object aProxy, Method aMethod, Object[] aParams) + throws Throwable { + String methodName = aMethod.getName(); + + // Handle the three java.lang.Object methods that are passed to us. + if (aMethod.getDeclaringClass() == Object.class) { + if (methodName.equals("hashCode")) { + return proxyHashCode(aProxy); + } + if (methodName.equals("equals")) { + return proxyEquals(aProxy, aParams[0]); + } + if (methodName.equals("toString")) { + return proxyToString(aProxy); + } + System.err.println("WARNING: Unhandled Object method [" + + methodName + "]"); + return null; + } + + // Handle the 'finalize' method called during garbage collection + if (aMethod.getDeclaringClass() == XPCOMJavaProxyBase.class) { + if (methodName.equals("finalize")) { + finalizeProxy(aProxy); + } else { + System.err.println("WARNING: Unhandled XPCOMJavaProxyBase method [" + + methodName + "]"); + } + return null; + } + + // If not already handled, pass method calls to XPCOM object. + return callXPCOMMethod(aProxy, methodName, aParams); + } + + /** + * Handles method calls of java.lang.Object.hashCode + * + * @param aProxy Proxy created by createProxy + * + * @return Integer object representing hash code of given object + * + * @see Object#hashCode() + */ + protected static Integer proxyHashCode(Object aProxy) { + return new Integer(System.identityHashCode(aProxy)); + } + + /** + * Handles method calls of java.lang.Object.equals + * + * @param aProxy Proxy created by createProxy + * @param aOther another object + * + * @return true if the given objects are the same; + * false otherwise + * + * @see Object#equals(Object) + */ + protected static Boolean proxyEquals(Object aProxy, Object aOther) { + // See if the two are the same Java object + if (aProxy == aOther) { + return Boolean.TRUE; + } else { + // If not, then see if they represent the same XPCOM object. But first, + // we need to check if |aOther| is an XPCOMJavaProxy. + if (isXPCOMJavaProxy(aOther) && isSameXPCOMObject(aProxy, aOther)) { + return Boolean.TRUE; + } + } + return Boolean.FALSE; + } + + /** + * Indicates whether the given object is an XPCOMJavaProxy. + * + * @param aObject object to check + * + * @return true if the given object is an XPCOMJavaProxy; + * false otherwise + */ + protected static boolean isXPCOMJavaProxy(Object aObject) { + if (aObject != null && Proxy.isProxyClass(aObject.getClass())) { + InvocationHandler h = Proxy.getInvocationHandler(aObject); + if (h instanceof XPCOMJavaProxy) { + return true; + } + } + return false; + } + + /** + * Checks if the two given XPCOMJavaProxy objects are proxies for + * the same XPCOM object. + * + * @param aProxy1 XPCOMJavaProxy created by createProxy + * @param aProxy2 XPCOMJavaProxy created by createProxy + * + * @return true if both proxies represent the same XPCOM object; + * false otherwise + */ + protected static native boolean isSameXPCOMObject(Object aProxy1, + Object aProxy2); + + /** + * Handles method calls of java.lang.Object.toString + * + * @param aProxy Proxy created by createProxy + * + * @return String representation of given object + * + * @see Object#toString() + */ + protected static String proxyToString(Object aProxy) { + return aProxy.getClass().getInterfaces()[0].getName() + '@' + + Integer.toHexString(aProxy.hashCode()); + } + + /** + * Called when the proxy is garbage collected by the JVM. Allows us to clean + * up any references to the XPCOM object. + * + * @param aProxy reference to Proxy that is being garbage collected + */ + protected void finalizeProxy(Object aProxy) throws Throwable { + finalizeProxyNative(aProxy); + super.finalize(); + } + + protected static native void finalizeProxyNative(Object aProxy); + + /** + * Calls the XPCOM object referenced by the proxy with the given method. + * + * @param aProxy Proxy created by createProxy + * @param aMethodName name of method that we want to call + * @param aParams array of params passed to method + * + * @return return value as defined by given method + * + * @exception XPCOMException if XPCOM method failed. Values of XPCOMException + * are defined by the method called. + */ + protected static native Object callXPCOMMethod(Object aProxy, + String aMethodName, Object[] aParams); + +} diff --git a/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java new file mode 100644 index 00000000..595a7a2c --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/mozilla/xpcom/internal/XPCOMJavaProxyBase.java @@ -0,0 +1,53 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 ***** */ + +package org.mozilla.xpcom.internal; + + +/** + * This interface forms the foundation of any XPCOMJavaProxy that is created. + * It allows us to handle any JVM calls to finalize when the Proxy + * is garbage collected. + */ +public interface XPCOMJavaProxyBase { + + /** + * @see java.lang.Object#finalize() + */ + void finalize() throws Throwable; + +} diff --git a/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java b/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java new file mode 100644 index 00000000..0a765fa0 --- /dev/null +++ b/src/libs/xpcom18a4/java/src/org/virtualbox/VBoxObjectBase.java @@ -0,0 +1,31 @@ +/* $Id: VBoxObjectBase.java $ */ +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ +import org.mozilla.interfaces.nsISupports; + +public abstract class VBoxObjectBase implements nsISupports +{ + public nsISupports queryInterface(String iid) + { + return org.mozilla.xpcom.Mozilla.queryInterface(this, iid); + } +} diff --git a/src/libs/xpcom18a4/java/tools/gen-nsError.pl b/src/libs/xpcom18a4/java/tools/gen-nsError.pl new file mode 100755 index 00000000..da866b83 --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/gen-nsError.pl @@ -0,0 +1,161 @@ +#! /usr/bin/env perl +# ***** 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 Java XPCOM Bindings. +# +# The Initial Developer of the Original Code is +# Michal Ceresna. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Michal Ceresna (ceresna@dbai.tuwien.ac.at) +# Javier Pedemonte (jhpedemonte@gmail.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 ***** + +# Generates XPCOMError.java from xpcom/base/nsError.h +# +# usage: perl gen-nsErrors.pl < /xpcom/base/nsError.h > XPCOMError.java + + +print "/* ***** BEGIN LICENSE BLOCK *****\n"; +print " * Version: MPL 1.1/GPL 2.0/LGPL 2.1\n"; +print " *\n"; +print " * The contents of this file are subject to the Mozilla Public License Version\n"; +print " * 1.1 (the \"License\"); you may not use this file except in compliance with\n"; +print " * the License. You may obtain a copy of the License at\n"; +print " * http://www.mozilla.org/MPL/\n"; +print " *\n"; +print " * Software distributed under the License is distributed on an \"AS IS\" basis,\n"; +print " * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\n"; +print " * for the specific language governing rights and limitations under the\n"; +print " * License.\n"; +print " *\n"; +print " * The Original Code is mozilla.org code.\n"; +print " *\n"; +print " * The Initial Developer of the Original Code is\n"; +print " * Netscape Communications Corporation.\n"; +print " * Portions created by the Initial Developer are Copyright (C) 1998\n"; +print " * the Initial Developer. All Rights Reserved.\n"; +print " *\n"; +print " * Contributor(s):\n"; +print " *\n"; +print " * Alternatively, the contents of this file may be used under the terms of\n"; +print " * either of the GNU General Public License Version 2 or later (the \"GPL\"),\n"; +print " * or the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\n"; +print " * in which case the provisions of the GPL or the LGPL are applicable instead\n"; +print " * of those above. If you wish to allow use of your version of this file only\n"; +print " * under the terms of either the GPL or the LGPL, and not to allow others to\n"; +print " * use your version of this file under the terms of the MPL, indicate your\n"; +print " * decision by deleting the provisions above and replace them with the notice\n"; +print " * and other provisions required by the GPL or the LGPL. If you do not delete\n"; +print " * the provisions above, a recipient may use your version of this file under\n"; +print " * the terms of any one of the MPL, the GPL or the LGPL.\n"; +print " *\n"; +print " * ***** END LICENSE BLOCK ***** */\n"; + +print "\n"; +print "package org.mozilla.xpcom;\n"; +print "\n\n"; + +print "/**\n"; +print " * Mozilla error codes.\n"; +print " *\n"; +print " * THIS FILE GENERATED FROM mozilla/xpcom/base/nsError.h.\n"; +print " * PLEASE SEE THAT FILE FOR FULL DOCUMENTATION.\n"; +print " */\n"; +print "public interface XPCOMError {\n"; + +while () { + $line = $_; + + if ($prevline) { + $_ = $prevline.$_; + } + if (/(.*)\\$/) { + #splitted line + $prevline = $1; + next; + } + $prevline = ""; + + if (/^\s*#define\s+(NS_[A-Z_]+)\s+(0x)?([0-9a-fA-F]+)\s*$/) { + #define NS_ERROR_MODULE_XPCOM 1 + #define NS_ERROR_MODULE_BASE_OFFSET 0x45 + print " public static final long $1 = $2$3L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+\((NS_[A-Z_]+)\s+\+\s+(0x)?([0-9a-fA-F]+)\s*\)\s*/) { + #define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + #define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + print " public static final long $1 = $2 + $3$4L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+(NS_[A-Z_]+)\s\s*/) { + #define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + print " public static final long $1 = $2;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+\(\(nsresult\)\s*(0x)?([0-9a-fA-F]+)L?\)\s*$/) { + #define NS_ERROR_BASE ((nsresult) 0xC1F30000) + #define NS_ERROR_ABORT ((nsresult) 0x80004004L) + print " public static final long $1 = $2$3L;\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+NS_ERROR_GENERATE_FAILURE\s*\(\s*(NS_[A-Z_]+)\s*,\s*([0-9]+)\s*\)\s*$/) { + #define NS_BASE_STREAM_CLOSED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) + $module = $2; + $code = $3; + print " public static final long $1 = ((NS_ERROR_SEVERITY_ERROR<<31) | (($module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | $code);\n"; + } + elsif (/^\s*#define\s+(NS_[A-Z_]+)\s+NS_ERROR_GENERATE_SUCCESS\s*\(\s*(NS_[A-Z_]+)\s*,\s*([0-9]+)\s*\)\s*$/) { + #define NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 1) + $module = $2; + $code = $3; + print " public static final long $1 = ((NS_ERROR_SEVERITY_SUCCESS<<31) | (($module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | $code);\n"; + } + elsif (/^\s*\/\*(.*)\*\/\s*$/ && !/^\s*\/\*@[\{\}]\*\/\s*$/ && + !/^\s*\/\*\ -\*- Mode:/) { + #single line comment, but not + #/*@{*/, /*@}*/, + #/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + print " /*$1*/\n"; + } + elsif (/^\s*$/) { + #empty line, but write only the first + #line from a sequence of empty lines + if (!$wasEmpty) { + print "\n"; + } + $wasEmpty = 1; + next; + } + else { + next; + } + + $wasEmpty = 0; +} + +print "}\n"; + diff --git a/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp b/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp new file mode 100644 index 00000000..60648beb --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/genifaces/GenerateJavaInterfaces.cpp @@ -0,0 +1,952 @@ +/* ***** 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 Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2005 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.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 "nsXPCOM.h" +#include "nsString.h" +#include "nsILocalFile.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" +#include "nsCOMPtr.h" +#include "prmem.h" +#include "xptcall.h" +#ifdef VBOX +#include "nsFileStreams.h" +static nsresult +NS_NewLocalFileInputStream(nsIInputStream **aResult, + nsIFile *aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsFileInputStream* in = new nsFileInputStream(); + nsresult rv; + + rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_SUCCEEDED(rv)) + NS_ADDREF(*aResult = in); + + return rv; +} + +inline nsresult +NS_NewLocalFileOutputStream(nsIOutputStream **aResult, + nsIFile *aFile, + PRInt32 aIOFlags = -1, + PRInt32 aPerm = -1, + PRInt32 aBehaviorFlags = 0) +{ + nsFileOutputStream* in = new nsFileOutputStream(); + nsresult rv; + + rv = in->Init(aFile, aIOFlags, aPerm, aBehaviorFlags); + if (NS_SUCCEEDED(rv)) + NS_ADDREF(*aResult = in); + + return rv; +} + + +#else +#include "nsNetUtil.h" +#endif +#include "nsHashSets.h" +#include "nsIWeakReference.h" +#include + +#ifdef WIN32 +#define snprintf _snprintf +#endif + +#define WRITE_NOSCRIPT_METHODS + + +class TypeInfo +{ +public: + static nsresult GetParentInfo(nsIInterfaceInfo* aIInfo, + nsIInterfaceInfo** aParentInfo, + PRUint16* aParentMethodCount, + PRUint16* aParentConstCount) + { + nsCOMPtr parent; + nsresult rv = aIInfo->GetParent(getter_AddRefs(parent)); + NS_ENSURE_SUCCESS(rv, rv); + + if (!parent) { + *aParentInfo = nsnull; + *aParentMethodCount = 0; + return NS_OK; + } + + rv = parent->GetMethodCount(aParentMethodCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = parent->GetConstantCount(aParentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + + *aParentInfo = parent; + NS_ADDREF(*aParentInfo); + return rv; + } + + static nsresult GetInterfaceName(nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, + const nsXPTParamInfo* aParamInfo, + char** aResult) + { + static const char isupp_str[] = "nsISupports"; + + nsIID* iid; + nsresult rv = aIInfo->GetIIDForParam(aMethodIndex, aParamInfo, &iid); + if (NS_FAILED(rv)) { + // GetIIDForParam will sometimes fail to find an interface, particularly + // if that interface is not defined in an IDL file. In those cases, just + // return |nsISupports|. + // + // For example, the |onStreamComplete| method for the interface + // |nsIUnicharStreamLoaderObserver| takes a param of + // |nsIUnicharInputStream|, which is defined in a simple header file, not + // an IDL file. + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + + } else { + + // In Javaconnect, we handle weak references internally; no need for the + // |nsIWeakReference| interface. So just return |nsISupports|. + if (iid->Equals(NS_GET_IID(nsIWeakReference))) { + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + + } else { + + // Some methods take parameters of non-scriptable interfaces. But we + // only output scriptable interfaces. So if one of the param types is + // a non-scriptable interface, output |nsISupports| instead of the + // interface name. + nsCOMPtr info; + nsCOMPtr iim = + getter_AddRefs(XPTI_GetInterfaceInfoManager()); + NS_ASSERTION(iim, "could not get interface info manager"); + rv = iim->GetInfoForIID(iid, getter_AddRefs(info)); + NS_ENSURE_SUCCESS(rv, rv); + PRBool scriptable; + if (NS_SUCCEEDED(rv)) { + info->IsScriptable(&scriptable); + } + if (NS_FAILED(rv) || !scriptable) { + *aResult = (char*) nsMemory::Clone(isupp_str, sizeof(isupp_str)); + rv = (*aResult == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; + } else { + + // If is scriptable, get name for given IID + rv = iim->GetNameForIID(iid, aResult); + } + } + + nsMemory::Free(iid); + } + + return rv; + } +}; + + +static const char* kJavaKeywords[] = { + "abstract", "default", "if" , "private" , "this" , + "boolean" , "do" , "implements", "protected" , "throw" , + "break" , "double" , "import", "public" , "throws" , + "byte" , "else" , "instanceof", "return" , "transient", + "case" , "extends", "int" , "short" , "try" , + "catch" , "final" , "interface" , "static" , "void" , + "char" , "finally", "long" , "strictfp" , "volatile" , + "class" , "float" , "native" , "super" , "while" , + "const" , "for" , "new" , "switch" , + "continue", "goto" , "package" , "synchronized", + "assert" , /* added in Java 1.4 */ + "enum" , /* added in Java 5.0 */ + "clone" , /* clone is a member function of java.lang.Object */ + "finalize" /* finalize is a member function of java.lang.Object */ +}; + +#ifdef WRITE_NOSCRIPT_METHODS +// SWT uses [noscript] methods of the following interfaces, so we need to +// output the [noscript] methods for these interfaces. +static const char* kNoscriptMethodIfaces[] = { + "nsIBaseWindow", "nsIEmbeddingSiteWindow" +}; +#endif + + +class Generate +{ + nsILocalFile* mOutputDir; + nsCStringHashSet mIfaceTable; + nsCStringHashSet mJavaKeywords; +#ifdef WRITE_NOSCRIPT_METHODS + nsCStringHashSet mNoscriptMethodsTable; +#endif + +public: + Generate(nsILocalFile* aOutputDir) + : mOutputDir(aOutputDir) + { + mIfaceTable.Init(100); + + PRUint32 size = NS_ARRAY_LENGTH(kJavaKeywords); + mJavaKeywords.Init(size); + for (PRUint32 i = 0; i < size; i++) { + mJavaKeywords.Put(nsDependentCString(kJavaKeywords[i])); + } + +#ifdef WRITE_NOSCRIPT_METHODS + size = NS_ARRAY_LENGTH(kNoscriptMethodIfaces); + mNoscriptMethodsTable.Init(size); + for (PRUint32 j = 0; j < size; j++) { + mNoscriptMethodsTable.Put(nsDependentCString(kNoscriptMethodIfaces[j])); + } +#endif + } + + ~Generate() + { + } + + nsresult GenerateInterfaces() + { + nsresult rv; + + nsCOMPtr iim = + getter_AddRefs(XPTI_GetInterfaceInfoManager()); + NS_ASSERTION(iim, "could not get interface info manager"); + nsCOMPtr etor; + rv = iim->EnumerateInterfaces(getter_AddRefs(etor)); + NS_ENSURE_SUCCESS(rv, rv); + + // loop over interfaces + etor->First(); + do { + // get current interface + nsCOMPtr item; + rv = etor->CurrentItem(getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr iface(do_QueryInterface(item)); + if (!iface) + break; + + // we only care about scriptable interfaces, so skip over those + // that aren't + PRBool scriptable; + iface->IsScriptable(&scriptable); + if (!scriptable) { + // XXX SWT uses non-scriptable interface 'nsIAppShell' (bug 270892), so + // include that one. + const char* iface_name; + iface->GetNameShared(&iface_name); + if (strcmp("nsIAppShell", iface_name) != 0) + continue; + } + + rv = WriteOneInterface(iface); + NS_ENSURE_SUCCESS(rv, rv); + + } while (NS_SUCCEEDED(etor->Next())); + + return NS_OK; + } + + nsresult WriteOneInterface(nsIInterfaceInfo* aIInfo) + { + nsresult rv; + + // write each interface only once + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (mIfaceTable.Contains(nsDependentCString(iface_name))) + return NS_OK; + + // write any parent interface + nsCOMPtr parentInfo; + PRUint16 parentMethodCount, parentConstCount; + rv = TypeInfo::GetParentInfo(aIInfo, getter_AddRefs(parentInfo), + &parentMethodCount, &parentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + if (parentInfo) + WriteOneInterface(parentInfo); + + mIfaceTable.Put(nsDependentCString(iface_name)); + + // create file for interface + nsCOMPtr out; + rv = OpenIfaceFileStream(iface_name, getter_AddRefs(out)); + NS_ENSURE_SUCCESS(rv, rv); + + // write contents to file + rv = WriteHeader(out, iface_name); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteInterfaceStart(out, aIInfo, parentInfo); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteIID(out, aIInfo); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteConstants(out, aIInfo, parentConstCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteMethods(out, aIInfo, parentMethodCount); + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteInterfaceEnd(out); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CloseIfaceFileStream(out); + + return rv; + } + + nsresult OpenIfaceFileStream(const char* aIfaceName, + nsIOutputStream** aResult) + { + nsresult rv; + + // create interface file in output dir + nsCOMPtr iface_file; + rv = mOutputDir->Clone(getter_AddRefs(iface_file)); + NS_ENSURE_SUCCESS(rv, rv); + nsAutoString filename; + filename.AppendASCII(aIfaceName); + filename.AppendLiteral(".java"); + rv = iface_file->Append(filename); + NS_ENSURE_SUCCESS(rv, rv); + + // create interface file + PRBool exists; + iface_file->Exists(&exists); + if (exists) + iface_file->Remove(PR_FALSE); + rv = iface_file->Create(nsIFile::NORMAL_FILE_TYPE, 0644); + NS_ENSURE_SUCCESS(rv, rv); + + // create output stream for writing to file + nsCOMPtr out; + rv = NS_NewLocalFileOutputStream(getter_AddRefs(out), iface_file); + NS_ENSURE_SUCCESS(rv, rv); + + *aResult = out; + NS_ADDREF(*aResult); + return NS_OK; + } + + nsresult CloseIfaceFileStream(nsIOutputStream* out) + { + return out->Close(); + } + + nsresult WriteHeader(nsIOutputStream* out, const char* aIfaceName) + { + static const char kHeader1[] = + "/**\n" + " * NOTE: THIS IS A GENERATED FILE. PLEASE CONSULT THE ORIGINAL IDL FILE\n" + " * FOR THE FULL DOCUMENTION AND LICENSE.\n" + " *\n" + " * @see \n **/\n\n"; + static const char kPackage[] = "package org.mozilla.interfaces;\n\n"; + + PRUint32 count; + nsresult rv = out->Write(kHeader1, sizeof(kHeader1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString searchTerm; + searchTerm.AppendLiteral("interface+"); + searchTerm.AppendASCII(aIfaceName); + // LXR limits to 29 chars + rv = out->Write(searchTerm.get(), PR_MIN(29, searchTerm.Length()), &count); + NS_ENSURE_SUCCESS(rv, rv); + + rv = out->Write(kHeader2, sizeof(kHeader2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kPackage, sizeof(kPackage) - 1, &count); + return rv; + } + + nsresult WriteInterfaceStart(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + nsIInterfaceInfo* aParentInfo) + { + static const char kIfaceDecl1[] = "public interface "; + static const char kParentDecl[] = " extends "; + static const char kIfaceDecl2[] = "\n{\n"; + + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + PRUint32 count; + nsresult rv = out->Write(kIfaceDecl1, sizeof(kIfaceDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iface_name, strlen(iface_name), &count); + NS_ENSURE_SUCCESS(rv, rv); + + if (aParentInfo) { + const char* parent_name; + aParentInfo->GetNameShared(&parent_name); + rv = out->Write(kParentDecl, sizeof(kParentDecl) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(parent_name, strlen(parent_name), &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = out->Write(kIfaceDecl2, sizeof(kIfaceDecl2) - 1, &count); + return rv; + } + + nsresult WriteInterfaceEnd(nsIOutputStream* out) + { + PRUint32 count; + return out->Write("}\n", 2, &count); + } + + nsresult WriteIID(nsIOutputStream* out, nsIInterfaceInfo* aIInfo) + { + static const char kIIDDecl1[] = " public static final String "; + static const char kIIDDecl2[] = " =\n \""; + static const char kIIDDecl3[] = "\";\n\n"; + + nsIID* iid = nsnull; + aIInfo->GetInterfaceIID(&iid); + if (!iid) + return NS_ERROR_OUT_OF_MEMORY; + + // create iid field name + nsCAutoString iid_name; + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (strncmp("ns", iface_name, 2) == 0) { + iid_name.AppendLiteral("NS_"); + iid_name.Append(iface_name + 2); + } else { + iid_name.Append(iface_name); + } + iid_name.AppendLiteral("_IID"); + ToUpperCase(iid_name); + + // get iid string + char* iid_str = iid->ToString(); + if (!iid_str) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 count; + nsresult rv = out->Write(kIIDDecl1, sizeof(kIIDDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iid_name.get(), iid_name.Length(), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kIIDDecl2, sizeof(kIIDDecl2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(iid_str, strlen(iid_str), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kIIDDecl3, sizeof(kIIDDecl3) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // cleanup + PR_Free(iid_str); + nsMemory::Free(iid); + return NS_OK; + } + + nsresult WriteConstants(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aParentConstCount) + { + static const char kConstDecl1[] = " public static final "; + static const char kConstDecl2[] = " = "; + static const char kConstDecl3[] = ";\n\n"; + + PRUint16 constCount; + nsresult rv = aIInfo->GetConstantCount(&constCount); + NS_ENSURE_SUCCESS(rv, rv); + + for (PRUint16 i = aParentConstCount; i < constCount; i++) { + const nsXPTConstant* constInfo; + rv = aIInfo->GetConstant(i, &constInfo); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 count; + rv = out->Write(kConstDecl1, sizeof(kConstDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + const nsXPTType &type = constInfo->GetType(); + rv = WriteType(out, &type, aIInfo, nsnull, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(" ", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + const char* name = constInfo->GetName(); + rv = out->Write(name, strlen(name), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kConstDecl2, sizeof(kConstDecl2) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + rv = WriteConstantValue(out, &type, constInfo->GetValue()); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(kConstDecl3, sizeof(kConstDecl3) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + nsresult WriteConstantValue(nsIOutputStream* out, const nsXPTType* aType, + const nsXPTCMiniVariant* aValue) + { + char buf[32]; + switch (aType->TagPart()) { + case nsXPTType::T_I8: + snprintf(buf, sizeof(buf), "%d", aValue->val.i8); + break; + + case nsXPTType::T_U8: + snprintf(buf, sizeof(buf), "%u", aValue->val.u8); + break; + + case nsXPTType::T_I16: + snprintf(buf, sizeof(buf), "%d", aValue->val.i16); + break; + + case nsXPTType::T_U16: + snprintf(buf, sizeof(buf), "%u", aValue->val.u16); + break; + + case nsXPTType::T_I32: + snprintf(buf, sizeof(buf), "%d", aValue->val.i32); + break; + + case nsXPTType::T_U32: + snprintf(buf, sizeof(buf), "%uL", aValue->val.u32); + break; + + case nsXPTType::T_I64: + snprintf(buf, sizeof(buf), "%lldL", aValue->val.i64); + break; + + case nsXPTType::T_U64: + snprintf(buf, sizeof(buf), "%lluL", aValue->val.u64); + break; + + case nsXPTType::T_FLOAT: + snprintf(buf, sizeof(buf), "%f", aValue->val.f); + break; + + case nsXPTType::T_DOUBLE: + snprintf(buf, sizeof(buf), "%f", aValue->val.d); + break; + + case nsXPTType::T_BOOL: + if (aValue->val.b) + sprintf(buf, "true"); + else + sprintf(buf, "false"); + break; + + case nsXPTType::T_CHAR: + snprintf(buf, sizeof(buf), "%c", aValue->val.c); + break; + + case nsXPTType::T_WCHAR: + snprintf(buf, sizeof(buf), "%c", aValue->val.wc); + break; + + default: + NS_WARNING("unexpected constant type"); + return NS_ERROR_UNEXPECTED; + } + + PRUint32 count; + return out->Write(buf, strlen(buf), &count); + } + + nsresult WriteMethods(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aParentMethodCount) + { + PRUint16 methodCount; + nsresult rv = aIInfo->GetMethodCount(&methodCount); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef DEBUG_bird /* attributes first, then method. For making diffing easier. */ + for (int pass = 0; pass < 2; pass++) +#endif + for (PRUint16 i = aParentMethodCount; i < methodCount; i++) { + const nsXPTMethodInfo* methodInfo; + rv = aIInfo->GetMethodInfo(i, &methodInfo); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef WRITE_NOSCRIPT_METHODS + // XXX + // SWT makes use of [noscript] methods in some classes, so output them + // for those classes. + + // skip [notxpcom] methods + if (methodInfo->IsNotXPCOM()) + continue; + + // skip most hidden ([noscript]) methods + if (methodInfo->IsHidden()) { + const char* iface_name; + aIInfo->GetNameShared(&iface_name); + if (!mNoscriptMethodsTable.Contains(nsDependentCString(iface_name))) + continue; + } +#else + // skip hidden ([noscript]) or [notxpcom] methods + if (methodInfo->IsHidden() || methodInfo->IsNotXPCOM()) + continue; +#endif +#ifdef DEBUG_bird /* attributes first, then method. For making diffing easier. */ + if ((methodInfo->IsSetter() || methodInfo->IsGetter()) == pass) + continue; +#endif + + rv = WriteOneMethod(out, aIInfo, methodInfo, i); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + nsresult WriteOneMethod(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + const nsXPTMethodInfo* aMethodInfo, + PRUint16 aMethodIndex) + { + static const char kMethodDecl1[] = " public "; + static const char kVoidReturn[] = "void"; + static const char kParamSeparator[] = ", "; + static const char kMethodDecl2[] = ");\n\n"; + + PRUint32 count; + nsresult rv = out->Write(kMethodDecl1, sizeof(kMethodDecl1) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // write return type + PRUint8 paramCount = aMethodInfo->GetParamCount(); + const nsXPTParamInfo* resultInfo = nsnull; + for (PRUint8 i = 0; i < paramCount; i++) { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(i); + if (paramInfo.IsRetval()) { + resultInfo = ¶mInfo; + break; + } + } + if (resultInfo) { + rv = WriteParam(out, aIInfo, aMethodIndex, resultInfo, 0); + } else { + rv = out->Write(kVoidReturn, sizeof(kVoidReturn) - 1, &count); + } + NS_ENSURE_SUCCESS(rv, rv); + + // write method name string + nsCAutoString method_name; + const char* name = aMethodInfo->GetName(); + if (aMethodInfo->IsGetter() || aMethodInfo->IsSetter()) { + if (aMethodInfo->IsGetter()) + method_name.AppendLiteral("get"); + else + method_name.AppendLiteral("set"); + method_name.Append(toupper(name[0])); + method_name.AppendASCII(name + 1); + } else { + method_name.Append(tolower(name[0])); + method_name.AppendASCII(name + 1); + // don't use Java keywords as method names + if (mJavaKeywords.Contains(method_name)) + method_name.Append('_'); + } + rv = out->Write(" ", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write(method_name.get(), method_name.Length(), &count); + NS_ENSURE_SUCCESS(rv, rv); + rv = out->Write("(", 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + + // write parameters + for (PRUint8 j = 0; j < paramCount; j++) { + const nsXPTParamInfo ¶mInfo = aMethodInfo->GetParam(j); + if (paramInfo.IsRetval()) + continue; + + if (j != 0) { + rv = out->Write(kParamSeparator, sizeof(kParamSeparator) - 1, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = WriteParam(out, aIInfo, aMethodIndex, ¶mInfo, j + 1); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = out->Write(kMethodDecl2, sizeof(kMethodDecl2) - 1, &count); + return rv; + } + + nsresult WriteParam(nsIOutputStream* out, nsIInterfaceInfo* aIInfo, + PRUint16 aMethodIndex, const nsXPTParamInfo* aParamInfo, + PRUint8 aIndex) + { + const nsXPTType &type = aParamInfo->GetType(); + nsresult rv = WriteType(out, &type, aIInfo, aMethodIndex, aParamInfo); + NS_ENSURE_SUCCESS(rv, rv); + + // if parameter is 'out' or 'inout', make it a Java array + PRUint32 count; + if (aParamInfo->IsOut() && !aParamInfo->IsRetval()) { + rv = out->Write("[]", 2, &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + // write name for parameter (but not for 'retval' param) + if (aIndex) { + char buf[10]; + snprintf(buf, sizeof(buf), " arg%d", aIndex); + rv = out->Write(buf, strlen(buf), &count); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; + } + + /** + * Write out the Java type for the given XPIDL type. + * + * NOTE: Java doesn't support unsigned types. So for any unsigned XPIDL type, + * we move up to the next largest Java type. This way we ensure that we don't + * lose any info. + */ + nsresult WriteType(nsIOutputStream* out, const nsXPTType* aType, + nsIInterfaceInfo* aIInfo, PRUint16 aMethodIndex, + const nsXPTParamInfo* aParamInfo) + { + nsresult rv; + PRUint32 count; + switch (aType->TagPart()) { + case nsXPTType::T_I8: + rv = out->Write("byte", 4, &count); + break; + + case nsXPTType::T_I16: + case nsXPTType::T_U8: + rv = out->Write("short", 5, &count); + break; + + case nsXPTType::T_I32: + case nsXPTType::T_U16: + rv = out->Write("int", 3, &count); + break; + + case nsXPTType::T_I64: + case nsXPTType::T_U32: + rv = out->Write("long", 4, &count); + break; + + case nsXPTType::T_FLOAT: + rv = out->Write("float", 5, &count); + break; + + // XXX how should we handle 64-bit values? + case nsXPTType::T_U64: + case nsXPTType::T_DOUBLE: + rv = out->Write("double", 6, &count); + break; + + case nsXPTType::T_BOOL: + rv = out->Write("boolean", 7, &count); + break; + + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + rv = out->Write("char", 4, &count); + break; + + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_IID: + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_UTF8STRING: + case nsXPTType::T_CSTRING: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_PWSTRING_SIZE_IS: + rv = out->Write("String", 6, &count); + break; + + case nsXPTType::T_INTERFACE: + { + char* iface_name = nsnull; + rv = TypeInfo::GetInterfaceName(aIInfo, aMethodIndex, aParamInfo, + &iface_name); + if (NS_FAILED(rv) || !iface_name) { + rv = NS_ERROR_FAILURE; + break; + } + + rv = out->Write(iface_name, strlen(iface_name), &count); + nsMemory::Free(iface_name); + break; + } + + case nsXPTType::T_INTERFACE_IS: + rv = out->Write("nsISupports", 11, &count); + break; + + case nsXPTType::T_VOID: + rv = out->Write("int", 3, &count); + break; + + case nsXPTType::T_ARRAY: + { + // get array type + nsXPTType xpttype; + rv = aIInfo->GetTypeForParam(aMethodIndex, aParamInfo, 1, &xpttype); + if (NS_FAILED(rv)) + break; + + rv = WriteType(out, &xpttype, aIInfo, aMethodIndex, aParamInfo); + if (NS_FAILED(rv)) + break; + + rv = out->Write("[]", 2, &count); + break; + } + + default: + fprintf(stderr, "WARNING: unexpected parameter type %d\n", + aType->TagPart()); + return NS_ERROR_UNEXPECTED; + } + + return rv; + } +}; + +void PrintUsage(char** argv) +{ + static const char usage_str[] = + "Usage: %s -d path\n" + " -d output directory for Java interface files\n"; + fprintf(stderr, usage_str, argv[0]); +} +#ifdef VBOX +#include +using namespace com; + +#include +#include +#include +#include +#endif + +int main(int argc, char** argv) +{ + nsresult rv = NS_OK; + nsCOMPtr output_dir; + +#ifdef VBOX +#if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rv = RTR3InitExe(argc, &argv, 0); +#else + const char *pszHome = getenv("VBOX_PROGRAM_PATH"); + if (pszHome) { + size_t cchHome = strlen(pszHome); + char *pszExePath = (char *)alloca(cchHome + 32); + memcpy(pszExePath, pszHome, cchHome); + memcpy(pszExePath + cchHome, "/pythonfake", sizeof("/pythonfake")); + rc = RTR3InitEx(RTR3INIT_VER_CUR, 0, argc, &argv, pszExePath); + } else { + rv = RTR3InitExe(argc, &argv, 0); + } +#endif +#endif + + // handle command line arguments + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + rv = NS_ERROR_FAILURE; + break; + } + + switch (argv[i][1]) { + case 'd': { + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing output directory after -d\n"); + rv = NS_ERROR_FAILURE; + break; + } + + // see if given path exists + rv = NS_NewNativeLocalFile(nsDependentCString(argv[++i]), PR_TRUE, + getter_AddRefs(output_dir)); + PRBool val; + if (NS_FAILED(rv) || NS_FAILED(output_dir->Exists(&val)) || !val || + NS_FAILED(output_dir->IsDirectory(&val)) || !val) + { + fprintf(stderr, + "ERROR: output directory doesn't exist / isn't a directory\n"); + rv = NS_ERROR_FAILURE; + break; + } + + break; + } + + default: { + fprintf(stderr, "ERROR: unknown option %s\n", argv[i]); + rv = NS_ERROR_FAILURE; + break; + } + } + } + + if (NS_FAILED(rv)) { + PrintUsage(argv); + return 1; + } + +#ifdef VBOX + rv = com::Initialize(); +#else + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif + NS_ENSURE_SUCCESS(rv, rv); + + Generate gen(output_dir); + rv = gen.GenerateInterfaces(); + +#ifdef VBOX + // very short-living XPCOM processes trigger problem on shutdown - ignoring it not a big deal anyway + //com::Shutdown(); +#else + NS_ShutdownXPCOM(nsnull); +#endif + return rv; +} diff --git a/src/libs/xpcom18a4/java/tools/genjifaces.xsl b/src/libs/xpcom18a4/java/tools/genjifaces.xsl new file mode 100644 index 00000000..05455a4d --- /dev/null +++ b/src/libs/xpcom18a4/java/tools/genjifaces.xsl @@ -0,0 +1,600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /** @file + + + + * + * DO NOT EDIT! This is a generated file. + * Generated from: src/VBox/Main/idl/VirtualBox.xidl (VirtualBox's interface definitions in XML) + * Generator: src/VBox/src/libs/xpcom18a4/java/tools/genjifaces.xsl + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/xpcom18a4/nsBuildID.h b/src/libs/xpcom18a4/nsBuildID.h new file mode 100644 index 00000000..4f674d9d --- /dev/null +++ b/src/libs/xpcom18a4/nsBuildID.h @@ -0,0 +1,23 @@ +#ifndef _NSBUILDID_H_ +#define _NSBUILDID_H_ +/* Build ID file. +* +* If building MOZILLLA_OFFICIAL (release build) NS_BUILD_ID will be updated +* to a current build id. This will be used to determine if we need to +* re-register components. +* +*/ +#define NS_BUILD_ID 0000000000 + +/* GRE_BUILD_ID - GRE build version identifier + * + * If creating a release build (eg, MOZILLA_OFFICIAL is set), then + * GRE_BUILD_ID will be updated to contain _. + * If building a milestone build (eg, MOZ_MILESTONE_RELEASE is set), then + * GRE_BUILD_ID will just contain . + * + */ +#define GRE_BUILD_ID "1.8b2_0000000000" + +#endif /* _NSBUILDID_H_ */ + diff --git a/src/libs/xpcom18a4/nsprpub/Makefile.in b/src/libs/xpcom18a4/nsprpub/Makefile.in new file mode 100644 index 00000000..9273b16d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/Makefile.in @@ -0,0 +1,151 @@ +#! gmake + +# +# ***** 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 ***** + + +MOD_DEPTH = . +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +MAKE := $(patsubst -j%,,$(MAKE)) -j1 + +DIRS = config pr lib + +ifdef MOZILLA_CLIENT +# Make nsinstall use absolute symlinks by default for Mozilla OSX builds +# http://bugzilla.mozilla.org/show_bug.cgi?id=193164 +ifeq ($(OS_ARCH),Darwin) +ifndef NSDISTMODE +NSDISTMODE=absolute_symlink +export NSDISTMODE +endif +endif +endif + +DIST_GARBAGE = config.cache config.log config.status + +all:: config.status export + +include $(topsrcdir)/config/rules.mk + +config.status:: configure +ifeq ($(OS_ARCH),WINNT) + sh $(srcdir)/configure --no-create --no-recursion +else + ./config.status --recheck && ./config.status +endif + +# +# The -ll option of zip converts CR LF to LF. +# +ifeq ($(OS_ARCH),WINNT) +ZIP_ASCII_OPT = -ll +endif + +# Delete config/autoconf.mk last because it is included by every makefile. +distclean:: + @echo "cd pr/tests; $(MAKE) $@" + @$(MAKE) -C pr/tests $@ + rm -f config/autoconf.mk + +release:: + echo $(BUILD_NUMBER) > $(RELEASE_DIR)/$(BUILD_NUMBER)/version.df + @if test -f imports.df; then \ + echo "cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \ + cp -f imports.df $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \ + else \ + echo "echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df"; \ + echo > $(RELEASE_DIR)/$(BUILD_NUMBER)/imports.df; \ + fi + cd $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME); \ + rm -rf META-INF; mkdir META-INF; cd META-INF; \ + echo "Manifest-Version: 1.0" > MANIFEST.MF; \ + echo "" >> MANIFEST.MF; \ + cd ..; rm -f mdbinary.jar; zip -r mdbinary.jar META-INF bin lib; \ + rm -rf META-INF; \ + cd include; \ + rm -rf META-INF; mkdir META-INF; cd META-INF; \ + echo "Manifest-Version: 1.0" > MANIFEST.MF; \ + echo "" >> MANIFEST.MF; \ + cd ..; rm -f mdheader.jar; zip $(ZIP_ASCII_OPT) -r mdheader.jar *; \ + rm -rf META-INF +ifeq ($(OS_ARCH),WINNT) + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)"; \ + $(topsrcdir)/config/prmkdir.bat $(MDIST_DOS)\\$(MOD_NAME)\\$(BUILD_NUMBER); \ + fi + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)"; \ + $(topsrcdir)/config/prmkdir.bat $(MDIST_DOS)\\$(MOD_NAME)\\$(BUILD_NUMBER)\\$(RELEASE_OBJDIR_NAME); \ + fi +else + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)"; \ + $(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + fi + @if test ! -d $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); then \ + rm -rf $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + echo "making directory $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)"; \ + $(NSINSTALL) -D $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 775 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + fi +endif + cd $(RELEASE_DIR)/$(BUILD_NUMBER); \ + cp -f version.df imports.df $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/version.df; \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/imports.df; \ + cd $(OBJDIR_NAME); \ + cp -f mdbinary.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)/mdbinary.jar; \ + cd include; \ + cp -f mdheader.jar $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME); \ + chmod 664 $(MDIST)/$(MOD_NAME)/$(BUILD_NUMBER)/$(RELEASE_OBJDIR_NAME)/mdheader.jar + +package: + @echo "cd pkg; $(MAKE) publish" + $(MAKE) -C pkg publish + +depend: + @echo "NSPR20 has no dependencies. Skipped." diff --git a/src/libs/xpcom18a4/nsprpub/admin/explode.pl b/src/libs/xpcom18a4/nsprpub/admin/explode.pl new file mode 100755 index 00000000..881f21b9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/admin/explode.pl @@ -0,0 +1,75 @@ +#!/bin/perl +# +# ***** 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-2001 +# 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 ***** + +# ----------------------------------------------------------------- +# +# explode.pl -- Unpack .jar files into bin, lib, include directories +# +# syntax: perl explode.pl +# +# Description: +# explode.pl unpacks the .jar files created by the NSPR build +# procedure. +# +# Suggested use: After copying the platform directories to +# /s/b/c/nspr20/. CD to /s/b/c/nspr20/ and +# run explode.pl. This will unpack the jar files into bin, lib, +# include directories. +# +# ----------------------------------------------------------------- + +@dirs = `ls -d *.OBJ*`; + +foreach $dir (@dirs) { + chop($dir); + if (-l $dir) { + print "Skipping symbolic link $dir\n"; + next; + } + print "Unzipping $dir/mdbinary.jar\n"; + system ("unzip", "-o", "$dir/mdbinary.jar", + "-d", "$dir"); + system ("rm", "-rf", "$dir/META-INF"); + mkdir "$dir/include", 0755; + print "Unzipping $dir/mdheader.jar\n"; + system ("unzip", "-o", "-aa", + "$dir/mdheader.jar", + "-d", "$dir/include"); + system ("rm", "-rf", "$dir/include/META-INF"); +} +# --- end explode.pl ---------------------------------------------- diff --git a/src/libs/xpcom18a4/nsprpub/admin/makeTargetDirs.sh b/src/libs/xpcom18a4/nsprpub/admin/makeTargetDirs.sh new file mode 100755 index 00000000..4250ce4a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/admin/makeTargetDirs.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# +# ***** 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-2001 +# 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 ***** + +# ----------------------------------------------------------------- +# makeTargetDirs.sh -- Create target directories for building NSPR +# +# syntax: makeTargetDirs.sh +# +# Description: +# makeTargetDirs.sh creates a set of directories intended for use +# with NSPR's autoconf based build system. +# +# The enumerated directories are the same as those built for NSPR +# 4.1.1. Adjust as needed. +# +# ----------------------------------------------------------------- + +mkdir AIX4.3_64_DBG.OBJ +mkdir AIX4.3_64_OPT.OBJ +mkdir AIX4.3_DBG.OBJ +mkdir AIX4.3_OPT.OBJ +mkdir HP-UXB.11.00_64_DBG.OBJ +mkdir HP-UXB.11.00_64_OPT.OBJ +mkdir HP-UXB.11.00_DBG.OBJ +mkdir HP-UXB.11.00_OPT.OBJ +mkdir IRIX6.5_n32_PTH_DBG.OBJ +mkdir IRIX6.5_n32_PTH_OPT.OBJ +mkdir Linux2.2_x86_glibc_PTH_DBG.OBJ +mkdir Linux2.2_x86_glibc_PTH_OPT.OBJ +mkdir Linux2.4_x86_glibc_PTH_DBG.OBJ +mkdir Linux2.4_x86_glibc_PTH_OPT.OBJ +mkdir OSF1V4.0D_DBG.OBJ +mkdir OSF1V4.0D_OPT.OBJ +mkdir SunOS5.6_DBG.OBJ +mkdir SunOS5.6_OPT.OBJ +mkdir SunOS5.7_64_DBG.OBJ +mkdir SunOS5.7_64_OPT.OBJ +mkdir WIN954.0_DBG.OBJ +mkdir WIN954.0_DBG.OBJD +mkdir WIN954.0_OPT.OBJ +mkdir WINNT4.0_DBG.OBJ +mkdir WINNT4.0_DBG.OBJD +mkdir WINNT4.0_OPT.OBJ +# --- end makeTargetDirs.sh --------------------------------------- diff --git a/src/libs/xpcom18a4/nsprpub/admin/repackage.sh b/src/libs/xpcom18a4/nsprpub/admin/repackage.sh new file mode 100755 index 00000000..37ba0e16 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/admin/repackage.sh @@ -0,0 +1,218 @@ +#! /bin/sh +# ***** 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-2001 +# 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 ***** + +# ------------------------------------------------------------------ +# repackage.sh -- Repackage NSPR from /s/b/c to mozilla.org format +# +# syntax: repackage.sh +# +# Description: +# repackage.sh creates NSPR binary distributions for mozilla.org from +# the internal binary distributions in /share/builds/components/nspr20. +# There are reasons why we can't just push the internal binary distributions +# to mozilla.org. External developers prefer to use the common archive +# file format for their platforms, rather than the jar files we use internally. +# +# On Unix, we create a tar.gz file. On Windows, we create a zip file. +# For example: NSPR 4.1.1, these would be nspr-4.1.1.tar.gz and nspr-4.1.1.zip. +# +# When unpacked, nspr-4.1.1.tar.gz or nspr-4.1.1.zip should expand to a +# nspr-4.1.1 directory that contains three subdirectories: include, lib, +# and bin. The header files, with the correct line endings for the +# platform, are in nspr-4.1.1/include. The libraries are in nspr-4.1.1/lib. +# The executable programs are in nspr-4.1.1/bin. +# +# Note! Files written with Gnu tar are not readable by some non-Gnu +# versions. Sun, in particular. +# +# +# +# +# ------------------------------------------------------------------ + +FROMTOP=/share/builds/components/nspr20/v4.5 +TOTOP=./v4.5 +NSPRDIR=nspr-4.5 +SOURCETAG=NSPR_4_5_RTM + +# +# enumerate Unix object directories on /s/b/c +UNIX_OBJDIRS=" +AIX4.3_64_DBG.OBJ +AIX4.3_64_OPT.OBJ +AIX4.3_DBG.OBJ +AIX4.3_OPT.OBJ +HP-UXB.11.00_64_DBG.OBJ +HP-UXB.11.00_64_OPT.OBJ +HP-UXB.11.00_DBG.OBJ +HP-UXB.11.00_OPT.OBJ +IRIX6.5_n32_PTH_DBG.OBJ +IRIX6.5_n32_PTH_OPT.OBJ +Linux2.2_x86_glibc_PTH_DBG.OBJ +Linux2.2_x86_glibc_PTH_OPT.OBJ +Linux2.4_x86_glibc_PTH_DBG.OBJ +Linux2.4_x86_glibc_PTH_OPT.OBJ +OSF1V5.0_DBG.OBJ +OSF1V5.0_OPT.OBJ +SunOS5.6_DBG.OBJ +SunOS5.6_OPT.OBJ +SunOS5.8_64_DBG.OBJ +SunOS5.8_64_OPT.OBJ +SunOS5.8_DBG.OBJ +SunOS5.8_OPT.OBJ +" +# +# enumerate Windows object directories on /s/b/c +WIN_OBJDIRS=" +WIN954.0_DBG.OBJ +WIN954.0_DBG.OBJD +WIN954.0_OPT.OBJ +WINNT4.0_DBG.OBJ +WINNT4.0_DBG.OBJD +WINNT4.0_OPT.OBJ +" + +# +# Create the destination directory. +# +echo "removing directory $TOTOP" +rm -rf $TOTOP +echo "creating directory $TOTOP" +mkdir -p $TOTOP + +# +# Generate the tar.gz files for Unix platforms. +# +for OBJDIR in $UNIX_OBJDIRS; do + echo "removing directory $NSPRDIR" + rm -rf $NSPRDIR + echo "creating directory $NSPRDIR" + mkdir $NSPRDIR + + echo "creating directory $NSPRDIR/include" + mkdir $NSPRDIR/include + echo "copying $FROMTOP/$OBJDIR/include" + cp -r $FROMTOP/$OBJDIR/include $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/lib" + cp -r $FROMTOP/$OBJDIR/lib $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/bin" + cp -r $FROMTOP/$OBJDIR/bin $NSPRDIR + + echo "creating directory $TOTOP/$OBJDIR" + mkdir $TOTOP/$OBJDIR + echo "creating $TOTOP/$OBJDIR/$NSPRDIR.tar" + tar cvf $TOTOP/$OBJDIR/$NSPRDIR.tar $NSPRDIR + echo "gzipping $TOTOP/$OBJDIR/$NSPRDIR.tar" + gzip $TOTOP/$OBJDIR/$NSPRDIR.tar +done + +# +# Generate the zip files for Windows platforms. +# +for OBJDIR in $WIN_OBJDIRS; do + echo "removing directory $NSPRDIR" + rm -rf $NSPRDIR + echo "creating directory $NSPRDIR" + mkdir $NSPRDIR + + echo "creating directory $NSPRDIR/include" + mkdir $NSPRDIR/include + echo "creating directory $NSPRDIR/include/private" + mkdir $NSPRDIR/include/private + echo "creating directory $NSPRDIR/include/obsolete" + mkdir $NSPRDIR/include/obsolete + + # copy headers and adjust unix line-end to Windows line-end + # Note: Watch out for the "sed" command line. + # when editing the command, take care to preserve the "^M" as the literal + # cntl-M character! in vi, use "cntl-v cntl-m" to enter it! + # + headers=`ls $FROMTOP/$OBJDIR/include/*.h` + for header in $headers; do + sed -e 's/$/ +/g' $header > $NSPRDIR/include/`basename $header` + done + headers=`ls $FROMTOP/$OBJDIR/include/obsolete/*.h` + for header in $headers; do + sed -e 's/$/ +/g' $header > $NSPRDIR/include/obsolete/`basename $header` + done + headers=`ls $FROMTOP/$OBJDIR/include/private/*.h` + for header in $headers; do + sed -e 's/$/ +/g' $header > $NSPRDIR/include/private/`basename $header` + done + + echo "copying $FROMTOP/$OBJDIR/lib" + cp -r $FROMTOP/$OBJDIR/lib $NSPRDIR + + echo "copying $FROMTOP/$OBJDIR/bin" + cp -r $FROMTOP/$OBJDIR/bin $NSPRDIR + + echo "creating directory $TOTOP/$OBJDIR" + mkdir $TOTOP/$OBJDIR + echo "creating $TOTOP/$OBJDIR/$NSPRDIR.zip" + zip -r $TOTOP/$OBJDIR/$NSPRDIR.zip $NSPRDIR +done + +# +# package the source from CVS +# +echo "Packaging source" +echo "removing directory $NSPRDIR" +rm -rf $NSPRDIR +echo "creating directory $NSPRDIR" +mkdir $NSPRDIR +myWD=`pwd` +cd $NSPRDIR +echo "Pulling source from CVS with tag $SOURCETAG" +cvs co -r $SOURCETAG mozilla/nsprpub +cd $myWD +mkdir $TOTOP/src +echo "Creating source tar file: $TOTOP/src/$NSPRDIR.tar" +tar cvf $TOTOP/src/$NSPRDIR.tar $NSPRDIR +echo "gzip $TOTOP/src/$NSPRDIR.tar" +gzip $TOTOP/src/$NSPRDIR.tar + +# +# Remove the working directory. +# +echo "removing directory $NSPRDIR" +rm -rf $NSPRDIR +# --- end repackage.sh --------------------------------------------- diff --git a/src/libs/xpcom18a4/nsprpub/admin/symlinks.sh b/src/libs/xpcom18a4/nsprpub/admin/symlinks.sh new file mode 100755 index 00000000..f90582e2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/admin/symlinks.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# +# ***** 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-2001 +# 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 ***** + +# ----------------------------------------------------------------- +# symlinks.sh -- create links from NSPR builds +# +# syntax: symlinks.sh +# +# Description: +# symlinks.sh creates some symbolic links for NSPR build targets +# that are not actually build, but for which there are NSPR +# binaries suitable for running on the intended target. ... got +# that? +# +# Suggested use: After copying NSPR binaries to +# /s/b/c/nspr20/ run symlinks.sh to create the links +# for all supported platforms. +# +# The symlinks in this script correspond to the NSPR 4.1.1 +# release. Adjust as necessary. +# +# ----------------------------------------------------------------- + +ln -s SunOS5.6_DBG.OBJ SunOS5.7_DBG.OBJ +ln -s SunOS5.6_OPT.OBJ SunOS5.7_OPT.OBJ + +ln -s SunOS5.6_DBG.OBJ SunOS5.8_DBG.OBJ +ln -s SunOS5.6_OPT.OBJ SunOS5.8_OPT.OBJ + +ln -s SunOS5.7_64_DBG.OBJ SunOS5.8_64_DBG.OBJ +ln -s SunOS5.7_64_OPT.OBJ SunOS5.8_64_OPT.OBJ + +ln -s OSF1V4.0D_DBG.OBJ OSF1V5.0_DBG.OBJ +ln -s OSF1V4.0D_OPT.OBJ OSF1V5.0_OPT.OBJ + +ln -s WINNT4.0_DBG.OBJ WINNT5.0_DBG.OBJ +ln -s WINNT4.0_DBG.OBJD WINNT5.0_DBG.OBJD +ln -s WINNT4.0_OPT.OBJ WINNT5.0_OPT.OBJ +# --- end symlinks.sh --------------------------------------------- + diff --git a/src/libs/xpcom18a4/nsprpub/config/.cvsignore b/src/libs/xpcom18a4/nsprpub/config/.cvsignore new file mode 100644 index 00000000..bb3ee4bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/.cvsignore @@ -0,0 +1,11 @@ +nfspwd +revdepth +my_config.mk +my_overrides.mk +autoconf.mk +nsprincl.mk +nsprincl.sh +now +Makefile +nsinstall +nspr-config diff --git a/src/libs/xpcom18a4/nsprpub/config/Makefile.in b/src/libs/xpcom18a4/nsprpub/config/Makefile.in new file mode 100755 index 00000000..1b83ffa5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/Makefile.in @@ -0,0 +1,149 @@ +#! gmake +# +# ***** 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 ***** + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +# Indicate that this directory builds build tools. +INTERNAL_TOOLS = 1 + +# autoconf.mk must be deleted last (from the top-level directory) +# because it is included by every makefile. +DIST_GARBAGE = nsprincl.mk nsprincl.sh nspr-config + +RELEASE_BINS = nspr-config + +include $(topsrcdir)/config/config.mk + +CSRCS = now.c + +# This version hasn't been ported for us; the one in mozilla/config has +ifneq ($(OS_ARCH),OS2) +CSRCS += nsinstall.c + +PLSRCS = nfspwd.pl +endif + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +# Temporary workaround to disable the generation of +# library build time because now.c uses the 'long long' +# data type that's not available on some platforms. +ifeq (,$(filter-out NEC NEXTSTEP QNX SCOOS UNIXWARE,$(OS_ARCH))) +DEFINES += -DOMIT_LIB_BUILD_TIME +endif + +ifeq ($(OS_ARCH), IRIX) + ifeq ($(basename $(OS_RELEASE)),6) + ifndef NS_USE_GCC + ifeq ($(USE_N32),1) + XLDOPTS += -n32 -Wl,-woff,85 + else + ifeq ($(USE_64),1) + XLDOPTS += -64 + else + XLDOPTS += -32 + endif + endif + endif + endif +endif + +ifeq ($(OS_ARCH), HP-UX) + ifeq ($(USE_64),1) + XLDOPTS += +DD64 + endif +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +XCFLAGS = $(OS_CFLAGS) +ifeq ($(MOZ_OS2_EMX_OBJECTFORMAT),OMF) +XLDOPTS = -Zlinker /PM:VIO +endif +endif + +ifeq ($(MOZ_OS2_TOOLS),PGCC) +XCFLAGS = $(OS_CFLAGS) +XLDOPTS = -Zlinker /PM:VIO +endif + +include $(topsrcdir)/config/rules.mk + +PROGS = $(OBJDIR)/now$(PROG_SUFFIX) + +ifeq (,$(CROSS_COMPILE)$(filter-out OS2 WINNT,$(OS_ARCH))) +TARGETS = $(PROGS) +else +PROGS += $(OBJDIR)/nsinstall$(PROG_SUFFIX) +TARGETS = $(PROGS) $(PLSRCS:.pl=) +endif + +OUTOPTION = -o # end of the line +ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET))) +ifndef NS_USE_GCC +OUTOPTION = /Fe +endif +endif + +# Redefine MAKE_OBJDIR for just this directory +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); mkdir $(@D); else true; fi +endef + +export:: $(TARGETS) + rm -f $(dist_bindir)/nspr-config + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LD) $(EXEFLAGS) $< +else + $(CC) $(XCFLAGS) $< $(LDFLAGS) $(XLDOPTS) $(OUTOPTION)$@ +endif + +real_install:: nspr.m4 + $(NSINSTALL) -D $(DESTDIR)$(datadir)/aclocal + $(NSINSTALL) -t -m 0644 $< $(DESTDIR)$(datadir)/aclocal diff --git a/src/libs/xpcom18a4/nsprpub/config/autoconf.mk.in b/src/libs/xpcom18a4/nsprpub/config/autoconf.mk.in new file mode 100644 index 00000000..92800154 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/autoconf.mk.in @@ -0,0 +1,113 @@ +# -*- Mode: Makefile -*- + +INCLUDED_AUTOCONF_MK = 1 +USE_AUTOCONF = 1 +@SHELL_OVERRIDE@ +MOZILLA_CLIENT = @MOZILLA_CLIENT@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +datadir = @datadir@ + +dist_prefix = @dist_prefix@ +dist_bindir = @dist_bindir@ +dist_includedir = @dist_includedir@ +dist_libdir = @dist_libdir@ + +DIST = $(dist_prefix) + +RELEASE_OBJDIR_NAME = @RELEASE_OBJDIR_NAME@ +OBJDIR_NAME = @OBJDIR_NAME@ +OBJDIR = @OBJDIR@ +OBJ_SUFFIX = @OBJ_SUFFIX@ +LIB_SUFFIX = @LIB_SUFFIX@ +DLL_SUFFIX = @DLL_SUFFIX@ +ASM_SUFFIX = @ASM_SUFFIX@ +MOD_NAME = @NSPR_MODNAME@ + +MOD_MAJOR_VERSION = @MOD_MAJOR_VERSION@ +MOD_MINOR_VERSION = @MOD_MINOR_VERSION@ +MOD_PATCH_VERSION = @MOD_PATCH_VERSION@ + +LIBNSPR = @LIBNSPR@ +LIBPLC = @LIBPLC@ + +CROSS_COMPILE = @CROSS_COMPILE@ +BUILD_OPT = @MOZ_OPTIMIZE@ + +USE_CPLUS = @USE_CPLUS@ +USE_IPV6 = @USE_IPV6@ +USE_N32 = @USE_N32@ +USE_64 = @USE_64@ +GC_LEAK_DETECTOR = @GC_LEAK_DETECTOR@ +ENABLE_STRIP = @ENABLE_STRIP@ + +USE_PTHREADS = @USE_PTHREADS@ +USE_BTHREADS = @USE_BTHREADS@ +PTHREADS_USER = @USE_USER_PTHREADS@ +CLASSIC_NSPR = @USE_NSPR_THREADS@ + +AS = @AS@ +ASFLAGS = @ASFLAGS@ +CC = @CC@ +CCC = @CXX@ +NS_USE_GCC = @GNU_CC@ +GCC_USE_GNU_LD = @GCC_USE_GNU_LD@ +MSC_VER = @MSC_VER@ +AR = @AR@ +AR_FLAGS = @AR_FLAGS@ +LD = @LD@ +RANLIB = @RANLIB@ +PERL = @PERL@ +RC = @RC@ +RCFLAGS = @RCFLAGS@ +STRIP = @STRIP@ +NSINSTALL = @NSINSTALL@ +FILTER = @FILTER@ +IMPLIB = @IMPLIB@ +CYGWIN_WRAPPER = @CYGWIN_WRAPPER@ + +OS_CPPFLAGS = @CPPFLAGS@ +OS_CFLAGS = $(OS_CPPFLAGS) @CFLAGS@ $(DSO_CFLAGS) +OS_CXXFLAGS = $(OS_CPPFLAGS) @CXXFLAGS@ $(DSO_CFLAGS) +OS_LIBS = @OS_LIBS@ +OS_LDFLAGS = @LDFLAGS@ +OS_DLLFLAGS = @OS_DLLFLAGS@ +DLLFLAGS = @DLLFLAGS@ +EXEFLAGS = @EXEFLAGS@ +OPTIMIZER = @OPTIMIZER@ + +MKSHLIB = @MKSHLIB@ +DSO_CFLAGS = @DSO_CFLAGS@ +DSO_LDOPTS = @DSO_LDOPTS@ + +RESOLVE_LINK_SYMBOLS = @RESOLVE_LINK_SYMBOLS@ + +HOST_CC = @HOST_CC@ +HOST_CFLAGS = @HOST_CFLAGS@ + +DEFINES = @DEFINES@ @DEFS@ + +MDCPUCFG_H = @MDCPUCFG_H@ +PR_MD_CSRCS = @PR_MD_CSRCS@ +PR_MD_ASFILES = @PR_MD_ASFILES@ +PR_MD_ARCH_DIR = @PR_MD_ARCH_DIR@ +CPU_ARCH = @CPU_ARCH@ + +OS_TARGET = @OS_TARGET@ +OS_ARCH = @OS_ARCH@ +OS_RELEASE = @OS_RELEASE@ +OS_TEST = @OS_TEST@ + +NOSUCHFILE = @NOSUCHFILE@ +AIX_LINK_OPTS = @AIX_LINK_OPTS@ +MOZ_OBJFORMAT = @MOZ_OBJFORMAT@ +ULTRASPARC_LIBRARY = @ULTRASPARC_LIBRARY@ + +OBJECT_MODE = @OBJECT_MODE@ +ifdef OBJECT_MODE +export OBJECT_MODE +endif diff --git a/src/libs/xpcom18a4/nsprpub/config/config.mk b/src/libs/xpcom18a4/nsprpub/config/config.mk new file mode 100644 index 00000000..697a6015 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/config.mk @@ -0,0 +1,164 @@ +#! gmake +# +# ***** 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 ***** + +# Configuration information for building in the NSPR source module + +# Define an include-at-most-once-flag +NSPR_CONFIG_MK = 1 + +# +# The variable definitions in this file are inputs to NSPR's +# build system. This file, if present, is included at the +# beginning of config.mk. +# +# For example: +# +# BUILD_OPT=1 +# USE_PTHREADS=1 +# NS_USE_GCC= +# +ifndef topsrcdir +topsrcdir=$(MOD_DEPTH) +endif + +ifndef srcdir +srcdir=. +endif + +NFSPWD = $(MOD_DEPTH)/config/nfspwd + +CFLAGS = $(CC_ONLY_FLAGS) $(OPTIMIZER) $(OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +CCCFLAGS = $(CCC_ONLY_FLAGS) $(OPTIMIZER) $(OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +# For purify +NOMD_CFLAGS = $(CC_ONLY_FLAGS) $(OPTIMIZER) $(NOMD_OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) +NOMD_CCFLAGS = $(CCC_ONLY_FLAGS) $(OPTIMIZER) $(NOMD_OS_CFLAGS)\ + $(XP_DEFINE) $(DEFINES) $(INCLUDES) $(XCFLAGS) + +LDFLAGS = $(OS_LDFLAGS) + +define MAKE_OBJDIR +if test ! -d $(@D); then rm -rf $(@D); $(NSINSTALL) -D $(@D); fi +endef + +LINK_DLL = $(LD) $(OS_DLLFLAGS) $(DLLFLAGS) + +ifeq ($(OS_ARCH),Darwin) +PWD := $(shell pwd) +endif + +ifeq (,$(CROSS_COMPILE)$(filter-out WINNT OS2, $(OS_ARCH))) +INSTALL = $(NSINSTALL) +else +ifeq ($(NSDISTMODE),copy) +# copy files, but preserve source mtime +INSTALL = $(NSINSTALL) -t +else +ifeq ($(NSDISTMODE),absolute_symlink) +# install using absolute symbolic links +ifeq ($(OS_ARCH),Darwin) +INSTALL = $(NSINSTALL) -L $(PWD) +else +INSTALL = $(NSINSTALL) -L `$(NFSPWD)` +endif +else +# install using relative symbolic links +INSTALL = $(NSINSTALL) -R +endif +endif +endif # (WINNT || OS2) && !CROSS_COMPILE + +DEPENDENCIES = $(OBJDIR)/.md + +ifdef BUILD_DEBUG_GC +DEFINES += -DDEBUG_GC +endif + +GARBAGE += $(DEPENDENCIES) core $(wildcard core.[0-9]*) + +DIST_GARBAGE += Makefile + +#################################################################### +# +# The NSPR-specific configuration +# +#################################################################### + +DEFINES += -DFORCE_PR_LOG + +ifeq ($(_PR_NO_CLOCK_TIMER),1) +DEFINES += -D_PR_NO_CLOCK_TIMER +endif + +ifeq ($(USE_PTHREADS), 1) +DEFINES += -D_PR_PTHREADS -UHAVE_CVAR_BUILT_ON_SEM +endif + +ifeq ($(PTHREADS_USER), 1) +DEFINES += -DPTHREADS_USER -UHAVE_CVAR_BUILT_ON_SEM +endif + +ifeq ($(USE_IPV6),1) +DEFINES += -D_PR_INET6 +endif + +ifeq ($(MOZ_UNICODE),1) +DEFINES += -DMOZ_UNICODE +endif + +#################################################################### +# +# Configuration for the release process +# +#################################################################### + +MDIST = /m/dist +ifeq ($(OS_ARCH),WINNT) +MDIST = //helium/dist +MDIST_DOS = $(subst /,\\,$(MDIST)) +endif + +# RELEASE_DIR is ns/dist/ + +RELEASE_DIR = $(MOD_DEPTH)/dist/release/$(MOD_NAME) + +RELEASE_INCLUDE_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/include +RELEASE_BIN_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/bin +RELEASE_LIB_DIR = $(RELEASE_DIR)/$(BUILD_NUMBER)/$(OBJDIR_NAME)/lib diff --git a/src/libs/xpcom18a4/nsprpub/config/libc_r.h b/src/libs/xpcom18a4/nsprpub/config/libc_r.h new file mode 100644 index 00000000..0f66d127 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/libc_r.h @@ -0,0 +1,158 @@ +/* -*- 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 ***** */ + +/* libc_r.h -- macros, defines, etc. to make using reentrant libc calls */ +/* a bit easier. This was initially done for AIX pthreads, */ +/* but should be usable for anyone... */ + +/* Most of these use locally defined space instead of static library space. */ +/* Because of this, we use the _INIT_R to declare/allocate space (stack), */ +/* and the plain routines to actually do it..._WARNING_: avoid allocating */ +/* memory wherever possible. Memory allocation is fairly expensive, at */ +/* least on AIX...use arrays instead (which allocate from the stack.) */ +/* I know the names are a bit strange, but I wanted to be fairly certain */ +/* that we didn't have any namespace corruption...in general, the inits are */ +/* R__INIT_R(), and the actual calls are R__R(). */ + +#ifndef _LIBC_R_H +#define _LIBC_R_H + +/************/ +/* strtok */ +/************/ +#define R_STRTOK_INIT_R() \ + char *r_strtok_r=NULL + +#define R_STRTOK_R(return,source,delim) \ + return=strtok_r(source,delim,&r_strtok_r) + +#define R_STRTOK_NORET_R(source,delim) \ + strtok_r(source,delim,&r_strtok_r) + +/**************/ +/* strerror */ +/**************/ +#define R_MAX_STRERROR_LEN_R 8192 /* Straight from limits.h */ + +#define R_STRERROR_INIT_R() \ + char r_strerror_r[R_MAX_STRERROR_LEN_R] + +#define R_STRERROR_R(val) \ + strerror_r(val,r_strerror_r,R_MAX_STRERROR_LEN_R) + +/*****************/ +/* time things */ +/*****************/ +#define R_ASCTIME_INIT_R() \ + char r_asctime_r[26] + +#define R_ASCTIME_R(val) \ + asctime_r(val,r_asctime_r) + +#define R_CTIME_INIT_R() \ + char r_ctime_r[26] + +#define R_CTIME_R(val) \ + ctime_r(val,r_ctime_r) + +#define R_GMTIME_INIT_R() \ + struct tm r_gmtime_r + +#define R_GMTIME_R(time) \ + gmtime_r(time,&r_gmtime_r) + +#define R_LOCALTIME_INIT_R() \ + struct tm r_localtime_r + +#define R_LOCALTIME_R(val) \ + localtime_r(val,&r_localtime_r) + +/***********/ +/* crypt */ +/***********/ +#include +#define R_CRYPT_INIT_R() \ + CRYPTD r_cryptd_r; \ + bzero(&r_cryptd_r,sizeof(CRYPTD)) + +#define R_CRYPT_R(pass,salt) \ + crypt_r(pass,salt,&r_cryptd_r) + +/**************/ +/* pw stuff */ +/**************/ +#define R_MAX_PW_LEN_R 1024 +/* The following must be after the last declaration, but */ +/* before the first bit of code... */ +#define R_GETPWNAM_INIT_R(pw_ptr) \ + struct passwd r_getpwnam_pw_r; \ + char r_getpwnam_line_r[R_MAX_PW_LEN_R]; \ + pw_ptr = &r_getpwnam_pw_r + +#define R_GETPWNAM_R(name) \ + getpwnam_r(name,&r_getpwnam_pw_r,r_getpwnam_line_r,R_MAX_PW_LEN_R) + +/*******************/ +/* gethost stuff */ +/*******************/ +#define R_GETHOSTBYADDR_INIT_R() \ + struct hostent r_gethostbyaddr_r; \ + struct hostent_data r_gethostbyaddr_data_r + +#define R_GETHOSTBYADDR_R(addr,len,type,xptr_ent) \ + bzero(&r_gethostbyaddr_r,sizeof(struct hostent)); \ + bzero(&r_gethostbyaddr_data_r,sizeof(struct hostent_data)); \ + xptr_ent = &r_gethostbyaddr_r; \ + if (gethostbyaddr_r(addr,len,type, \ + &r_gethostbyaddr_r,&r_gethostbyaddr_data_r) == -1) { \ + xptr_ent = NULL; \ + } + +#define R_GETHOSTBYNAME_INIT_R() \ + struct hostent r_gethostbyname_r; \ + struct hostent_data r_gethostbyname_data_r + +#define R_GETHOSTBYNAME_R(name,xptr_ent) \ + bzero(&r_gethostbyname_r,sizeof(struct hostent)); \ + bzero(&r_gethostbyname_data_r,sizeof(struct hostent_data)); \ + xptr_ent = &r_gethostbyname_r; \ + if (gethostbyname_r(name, \ + &r_gethostbyname_r,&r_gethostbyname_data_r) == -1) { \ + xptr_ent = NULL; \ + } + +#endif /* _LIBC_R_H */ diff --git a/src/libs/xpcom18a4/nsprpub/config/nfspwd.pl b/src/libs/xpcom18a4/nsprpub/config/nfspwd.pl new file mode 100755 index 00000000..947b822a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nfspwd.pl @@ -0,0 +1,50 @@ +#! perl +# +# ***** 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 ***** + +require "fastcwd.pl"; + +$_ = &fastcwd; +if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) { + print("$_\n"); +} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o) + && readlink("/u/$user") eq "/usr/people/$user") { + print("/u/$user/$rest\n"); +} else { + chop($host = `hostname`); + print("/h/$host$_\n"); +} diff --git a/src/libs/xpcom18a4/nsprpub/config/now.c b/src/libs/xpcom18a4/nsprpub/config/now.c new file mode 100644 index 00000000..f797ef84 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/now.c @@ -0,0 +1,142 @@ +/* -*- 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 +#include + +#if defined(VMS) +#include +#elif defined(XP_UNIX) || defined(XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(WIN32) +#include +#elif defined(XP_OS2_VACPP) +#include +#else +#error "Architecture not supported" +#endif + + +int main(int argc, char **argv) +{ +#if defined(OMIT_LIB_BUILD_TIME) + /* + * Some platforms don't have any 64-bit integer type + * such as 'long long'. Because we can't use NSPR's + * PR_snprintf in this program, it is difficult to + * print a static initializer for PRInt64 (a struct). + * So we print nothing. The makefiles that build the + * shared libraries will detect the empty output string + * of this program and omit the library build time + * in PRVersionDescription. + */ +#elif defined(VMS) + long long now; + struct timeb b; + ftime(&b); + now = b.time; + now *= 1000000; + now += (1000 * b.millitm); + fprintf(stdout, "%Ld", now); +#elif defined(XP_UNIX) || defined(XP_OS2_EMX) || defined(XP_BEOS) + long long now; + struct timeval tv; +#ifdef HAVE_SVID_GETTOD + gettimeofday(&tv); +#else + gettimeofday(&tv, NULL); +#endif + now = ((1000000LL) * tv.tv_sec) + (long long)tv.tv_usec; +#if defined(OSF1) + fprintf(stdout, "%ld", now); +#elif defined(BEOS) && defined(__POWERPC__) + fprintf(stdout, "%Ld", now); /* Metroworks on BeOS PPC */ +#else + fprintf(stdout, "%lld", now); +#endif + +#elif defined(WIN32) + __int64 now; + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + CopyMemory(&now, &ft, sizeof(now)); + /* + * 116444736000000000 is the number of 100-nanosecond intervals + * between Jan. 1, 1601 and Jan. 1, 1970. + */ +#ifdef __GNUC__ + now = (now - 116444736000000000LL) / 10LL; + fprintf(stdout, "%lld", now); +#else + now = (now - 116444736000000000i64) / 10i64; + fprintf(stdout, "%I64d", now); +#endif + +#elif defined(XP_OS2_VACPP) +/* no long long or i64 so we use a string */ +#include + char buf[24]; + char tbuf[7]; + time_t now; + long mtime; + int i; + + struct timeb b; + ftime(&b); + now = b.time; + _ltoa(now, buf, 10); + + mtime = b.millitm * 1000; + if (mtime == 0){ + ++now; + strcat(buf, "000000"); + } else { + _ltoa(mtime, tbuf, 10); + for (i = strlen(tbuf); i < 6; ++i) + strcat(buf, "0"); + strcat(buf, tbuf); + } + fprintf(stdout, "%s", buf); + +#else +#error "Architecture not supported" +#endif + + return 0; +} /* main */ + +/* now.c */ diff --git a/src/libs/xpcom18a4/nsprpub/config/nsinstall.c b/src/libs/xpcom18a4/nsprpub/config/nsinstall.c new file mode 100644 index 00000000..319a9594 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nsinstall.c @@ -0,0 +1,602 @@ +/* -*- 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 ***** */ + +/* +** Netscape portable install command. +** +** Brendan Eich, 7/20/95 +*/ +#include /* OSF/1 requires this before grp.h, so put it first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_REENTRANT_LIBC +#include "libc_r.h" +#endif /* USE_REENTRANT_LIBC */ + +#include "pathsub.h" + +#define HAVE_FCHMOD + +#if defined(BEOS) +#undef HAVE_FCHMOD +#endif + +/* + * Does getcwd() take NULL as the first argument and malloc + * the result buffer? + */ +#if !defined(DARWIN) && !defined(NEXTSTEP) && !defined(VMS) +#define GETCWD_CAN_MALLOC +#endif + +#ifdef NEXTSTEP +#include + +/* +** balazs.pataki@sztaki.hu: The getcwd is broken in NEXTSTEP (returns 0), +** when called on a mounted fs. Did anyone notice this? Here's an ugly +** workaround ... +*/ +#define getcwd(b,s) my_getcwd(b,s) + +static char * +my_getcwd (char *buf, size_t size) +{ + FILE *pwd = popen("pwd", "r"); + char *result = fgets(buf, size, pwd); + + if (result) { + buf[strlen(buf)-1] = '\0'; + } + pclose (pwd); + return buf; +} +#endif /* NEXTSTEP */ + +#ifdef LINUX +#include +#endif + +#if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC) || defined(NEXTSTEP) +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) +#endif +#endif + +#if defined(SNI) +extern int fchmod(int fildes, mode_t mode); +#endif + +#ifdef QNX +#define d_ino d_stat.st_ino +#endif + +static void +usage(void) +{ + fprintf(stderr, + "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" + " %*s [-DdltR] file [file ...] directory\n", + program, (int)strlen(program), ""); + exit(2); +} + +static int +mkdirs(char *path, mode_t mode) +{ + char *cp; + struct stat sb; + int res; + + while (*path == '/' && path[1] == '/') + path++; + while ((cp = strrchr(path, '/')) && cp[1] == '\0') + *cp = '\0'; + if (cp && cp != path) { + *cp = '\0'; + if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(path, mode) < 0) { + return -1; + } + *cp = '/'; + } + res = mkdir(path, mode); + if ((res != 0) && (errno == EEXIST)) + return 0; + else + return res; +} + +static uid_t +touid(char *owner) +{ + struct passwd *pw; + uid_t uid; + char *cp; + + pw = getpwnam(owner); + if (pw) + return pw->pw_uid; + uid = strtol(owner, &cp, 0); + if (uid == 0 && cp == owner) + fail("cannot find uid for %s", owner); + return uid; +} + +static gid_t +togid(char *group) +{ + struct group *gr; + gid_t gid; + char *cp; + + gr = getgrnam(group); + if (gr) + return gr->gr_gid; + gid = strtol(group, &cp, 0); + if (gid == 0 && cp == group) + fail("cannot find gid for %s", group); + return gid; +} + +int +main(int argc, char **argv) +{ + int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc; + mode_t mode = 0755; + char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ]; + uid_t uid; + gid_t gid; + struct stat sb, tosb; + struct utimbuf utb; + + program = argv[0]; + cwd = linkname = linkprefix = owner = group = 0; + onlydir = dodir = dolink = dorelsymlink = dotimes = lplen = 0; + + while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { + switch (opt) { + case 'C': + cwd = optarg; + break; + case 'D': + onlydir = 1; + break; + case 'd': + dodir = 1; + break; + case 'l': + dolink = 1; + break; + case 'L': + linkprefix = optarg; + lplen = strlen(linkprefix); + dolink = 1; + break; + case 'R': + dolink = dorelsymlink = 1; + break; + case 'm': + mode = strtoul(optarg, &cp, 8); + if (mode == 0 && cp == optarg) + usage(); + break; + case 'o': + owner = optarg; + break; + case 'g': + group = optarg; + break; + case 't': + dotimes = 1; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 2 - onlydir) + usage(); + + todir = argv[argc-1]; + if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && + mkdirs(todir, 0777) < 0) { + fail("cannot make directory %s", todir); + } + if (onlydir) + return 0; + + if (!cwd) { +#ifdef GETCWD_CAN_MALLOC + cwd = getcwd(0, PATH_MAX); +#else + cwd = malloc(PATH_MAX + 1); + cwd = getcwd(cwd, PATH_MAX); +#endif + } + xchdir(todir); +#ifdef GETCWD_CAN_MALLOC + todir = getcwd(0, PATH_MAX); +#else + todir = malloc(PATH_MAX + 1); + todir = getcwd(todir, PATH_MAX); +#endif + tdlen = strlen(todir); + xchdir(cwd); + tdlen = strlen(todir); + + uid = owner ? touid(owner) : -1; + gid = group ? togid(group) : -1; + + while (--argc > 0) { + name = *argv++; + len = strlen(name); + base = xbasename(name); + bnlen = strlen(base); + toname = (char*)xmalloc(tdlen + 1 + bnlen + 1); + sprintf(toname, "%s/%s", todir, base); + exists = (lstat(toname, &tosb) == 0); + + if (dodir) { + /* -d means create a directory, always */ + if (exists && !S_ISDIR(tosb.st_mode)) { + (void) unlink(toname); + exists = 0; + } + if (!exists && mkdir(toname, mode) < 0) + fail("cannot make directory %s", toname); + if ((owner || group) && chown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); + } else if (dolink) { + if (*name == '/') { + /* source is absolute pathname, link to it directly */ + linkname = 0; + } else { + if (linkprefix) { + /* -L implies -l and prefixes names with a $cwd arg. */ + len += lplen + 1; + linkname = (char*)xmalloc(len + 1); + sprintf(linkname, "%s/%s", linkprefix, name); + } else if (dorelsymlink) { + /* Symlink the relative path from todir to source name. */ + linkname = (char*)xmalloc(PATH_MAX); + + if (*todir == '/') { + /* todir is absolute: skip over common prefix. */ + lplen = relatepaths(todir, cwd, linkname); + strcpy(linkname + lplen, name); + } else { + /* todir is named by a relative path: reverse it. */ + reversepath(todir, name, len, linkname); + xchdir(cwd); + } + + len = strlen(linkname); + } + name = linkname; + } + + /* Check for a pre-existing symlink with identical content. */ + if (exists && + (!S_ISLNK(tosb.st_mode) || + readlink(toname, buf, sizeof buf) != len || + strncmp(buf, name, len) != 0)) { + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + exists = 0; + } + if (!exists && symlink(name, toname) < 0) + fail("cannot make symbolic link %s", toname); +#ifdef HAVE_LCHOWN + if ((owner || group) && lchown(toname, uid, gid) < 0) + fail("cannot change owner of %s", toname); +#endif + + if (linkname) { + free(linkname); + linkname = 0; + } + } else { + /* Copy from name to toname, which might be the same file. */ + fromfd = open(name, O_RDONLY); + if (fromfd < 0 || fstat(fromfd, &sb) < 0) + fail("cannot access %s", name); + if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) + (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); + tofd = open(toname, O_CREAT | O_WRONLY, 0666); + if (tofd < 0) + fail("cannot create %s", toname); + + bp = buf; + while ((cc = read(fromfd, bp, sizeof buf)) > 0) { + while ((wc = write(tofd, bp, cc)) > 0) { + if ((cc -= wc) == 0) + break; + bp += wc; + } + if (wc < 0) + fail("cannot write to %s", toname); + } + if (cc < 0) + fail("cannot read from %s", name); + + if (ftruncate(tofd, sb.st_size) < 0) + fail("cannot truncate %s", toname); + /* + ** On OpenVMS we can't chmod() until the file is closed, and we + ** have to utime() last since fchown/chmod alter the timestamps. + */ +#ifndef VMS + if (dotimes) { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#ifdef HAVE_FCHMOD + if (fchmod(tofd, mode) < 0) +#else + if (chmod(toname, mode) < 0) +#endif + fail("cannot change mode of %s", toname); +#endif + if ((owner || group) && fchown(tofd, uid, gid) < 0) + fail("cannot change owner of %s", toname); + + /* Must check for delayed (NFS) write errors on close. */ + if (close(tofd) < 0) + fail("cannot write to %s", toname); + close(fromfd); +#ifdef VMS + if (chmod(toname, mode) < 0) + fail("cannot change mode of %s", toname); + if (dotimes) { + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + if (utime(toname, &utb) < 0) + fail("cannot set times of %s", toname); + } +#endif + } + + free(toname); + } + + free(cwd); + free(todir); + return 0; +} + +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ + +char *program; + +void +fail(char *format, ...) +{ + int error; + va_list ap; + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_INIT_R(); +#endif + + error = errno; + fprintf(stderr, "%s: ", program); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (error) + +#ifdef USE_REENTRANT_LIBC + R_STRERROR_R(errno); + fprintf(stderr, ": %s", r_strerror_r); +#else + fprintf(stderr, ": %s", strerror(errno)); +#endif + + putc('\n', stderr); + exit(1); +} + +char * +getcomponent(char *path, char *name) +{ + if (*path == '\0') + return 0; + if (*path == '/') { + *name++ = '/'; + } else { + do { + *name++ = *path++; + } while (*path != '/' && *path != '\0'); + } + *name = '\0'; + while (*path == '/') + path++; + return path; +} + +#ifdef UNIXWARE_READDIR_BUFFER_TOO_SMALL +/* Sigh. The static buffer in Unixware's readdir is too small. */ +struct dirent * readdir(DIR *d) +{ + static struct dirent *buf = NULL; +#define MAX_PATH_LEN 1024 + + + if(buf == NULL) + buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN) +; + return(readdir_r(d, buf)); +} +#endif + +char * +ino2name(ino_t ino, char *dir) +{ + DIR *dp; + struct dirent *ep; + char *name; + + dp = opendir(".."); + if (!dp) + fail("cannot read parent directory"); + for (;;) { + if (!(ep = readdir(dp))) + fail("cannot find current directory"); + if (ep->d_ino == ino) + break; + } + name = xstrdup(ep->d_name); + closedir(dp); + return name; +} + +void * +xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) + fail("cannot allocate %u bytes", size); + return p; +} + +char * +xstrdup(char *s) +{ + return strcpy((char*)xmalloc(strlen(s) + 1), s); +} + +char * +xbasename(char *path) +{ + char *cp; + + while ((cp = strrchr(path, '/')) && cp[1] == '\0') + *cp = '\0'; + if (!cp) return path; + return cp + 1; +} + +void +xchdir(char *dir) +{ + if (chdir(dir) < 0) + fail("cannot change directory to %s", dir); +} + +int +relatepaths(char *from, char *to, char *outpath) +{ + char *cp, *cp2; + int len; + char buf[NAME_MAX]; + + assert(*from == '/' && *to == '/'); + for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++) + if (*cp == '\0') + break; + while (cp[-1] != '/') + cp--, cp2--; + if (cp - 1 == to) { + /* closest common ancestor is /, so use full pathname */ + len = strlen(strcpy(outpath, to)); + if (outpath[len] != '/') { + outpath[len++] = '/'; + outpath[len] = '\0'; + } + } else { + len = 0; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + strcpy(outpath + len, "../"); + len += 3; + } + while ((cp = getcomponent(cp, buf)) != 0) { + sprintf(outpath + len, "%s/", buf); + len += strlen(outpath + len); + } + } + return len; +} + +void +reversepath(char *inpath, char *name, int len, char *outpath) +{ + char *cp, *cp2; + char buf[NAME_MAX]; + struct stat sb; + + cp = strcpy(outpath + PATH_MAX - (len + 1), name); + cp2 = inpath; + while ((cp2 = getcomponent(cp2, buf)) != 0) { + if (strcmp(buf, ".") == 0) + continue; + if (strcmp(buf, "..") == 0) { + if (stat(".", &sb) < 0) + fail("cannot stat current directory"); + name = ino2name(sb.st_ino, ".."); + len = strlen(name); + cp -= len + 1; + strcpy(cp, name); + cp[len] = '/'; + free(name); + xchdir(".."); + } else { + cp -= 3; + strncpy(cp, "../", 3); + xchdir(buf); + } + } + strcpy(outpath, cp); +} diff --git a/src/libs/xpcom18a4/nsprpub/config/nspr-config.in b/src/libs/xpcom18a4/nsprpub/config/nspr-config.in new file mode 100755 index 00000000..e9e18679 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nspr-config.in @@ -0,0 +1,116 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +major_version=@MOD_MAJOR_VERSION@ +minor_version=@MOD_MINOR_VERSION@ +patch_version=@MOD_PATCH_VERSION@ + +usage() +{ + cat <&2 +fi + +lib_nspr=yes +lib_plc=yes +lib_plds=yes + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --version) + echo ${major_version}.${minor_version}.${patch_version} + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + nspr) + lib_nspr=yes + ;; + plc) + lib_plc=yes + ;; + plds) + lib_plds=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + +if test "$echo_cflags" = "yes"; then + echo -I${prefix}/include/nspr +fi + +if test "$echo_libs" = "yes"; then + libdirs=-L${exec_prefix}/lib + if test -n "$lib_plds"; then + libdirs="$libdirs -lplds${major_version}" + fi + if test -n "$lib_plc"; then + libdirs="$libdirs -lplc${major_version}" + fi + if test -n "$lib_nspr"; then + libdirs="$libdirs -lnspr${major_version}" + fi + os_ldflags="@LDFLAGS@" + for i in $os_ldflags ; do + if echo $i | grep \^-L >/dev/null; then + libdirs="$libdirs $i" + fi + done + echo $libdirs @OS_LIBS@ +fi + diff --git a/src/libs/xpcom18a4/nsprpub/config/nspr.m4 b/src/libs/xpcom18a4/nsprpub/config/nspr.m4 new file mode 100644 index 00000000..8174bea9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nspr.m4 @@ -0,0 +1,67 @@ +# -*- tab-width: 4; -*- +# Configure paths for NSPR +# Public domain - Chris Seawood 2001-04-05 +# Based upon gtk.m4 (also PD) by Owen Taylor + +dnl AM_PATH_NSPR([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for NSPR, and define NSPR_CFLAGS and NSPR_LIBS +AC_DEFUN(AM_PATH_NSPR, +[dnl + +AC_ARG_WITH(nspr-prefix, + [ --with-nspr-prefix=PFX Prefix where NSPR is installed], + nspr_config_prefix="$withval", + nspr_config_prefix="") + +AC_ARG_WITH(nspr-exec-prefix, + [ --with-nspr-exec-prefix=PFX + Exec prefix where NSPR is installed], + nspr_config_exec_prefix="$withval", + nspr_config_exec_prefix="") + + if test -n "$nspr_config_exec_prefix"; then + nspr_config_args="$nspr_config_args --exec-prefix=$nspr_config_exec_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_exec_prefix/bin/nspr-config + fi + fi + if test -n "$nspr_config_prefix"; then + nspr_config_args="$nspr_config_args --prefix=$nspr_config_prefix" + if test -z "$NSPR_CONFIG"; then + NSPR_CONFIG=$nspr_config_prefix/bin/nspr-config + fi + fi + + unset ac_cv_path_NSPR_CONFIG + AC_PATH_PROG(NSPR_CONFIG, nspr-config, no) + min_nspr_version=ifelse([$1], ,4.0.0,$1) + AC_MSG_CHECKING(for NSPR - version >= $min_nspr_version (skipping)) + + no_nspr="" + if test "$NSPR_CONFIG" = "no"; then + no_nspr="yes" + else + NSPR_CFLAGS=`$NSPR_CONFIG $nspr_config_args --cflags` + NSPR_LIBS=`$NSPR_CONFIG $nspr_config_args --libs` + + dnl Skip version check for now + nspr_config_major_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + nspr_config_minor_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + nspr_config_micro_version=`$NSPR_CONFIG $nspr_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + fi + + if test -z "$no_nspr"; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + fi + + + AC_SUBST(NSPR_CFLAGS) + AC_SUBST(NSPR_LIBS) + +]) diff --git a/src/libs/xpcom18a4/nsprpub/config/nsprincl.mk.in b/src/libs/xpcom18a4/nsprpub/config/nsprincl.mk.in new file mode 100644 index 00000000..d56cc024 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nsprincl.mk.in @@ -0,0 +1,5 @@ +# Include in Makefiles to define NSPR variables + +NSPR_VERSION = @NSPR_VERSION@ +NSPR_LIB = -lnspr@NSPR_VERSION@ +NSPR_EXTRA_LIBS = @EXTRA_LIBS@ diff --git a/src/libs/xpcom18a4/nsprpub/config/nsprincl.sh.in b/src/libs/xpcom18a4/nsprpub/config/nsprincl.sh.in new file mode 100644 index 00000000..be4e1450 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/nsprincl.sh.in @@ -0,0 +1,5 @@ +# Include in shell scripts to define NSPR variables + +NSPR_VERSION=@NSPR_VERSION@ +NSPR_LIB=-lnspr$NSPR_VERSION +NSPR_EXTRA_LIBS="@EXTRA_LIBS@" diff --git a/src/libs/xpcom18a4/nsprpub/config/pathsub.h b/src/libs/xpcom18a4/nsprpub/config/pathsub.h new file mode 100644 index 00000000..bf3fca31 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/pathsub.h @@ -0,0 +1,78 @@ +/* -*- 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 pathsub_h___ +#define pathsub_h___ +/* +** Pathname subroutines. +** +** Brendan Eich, 8/29/95 +*/ +#include +#include + +#if SUNOS4 +#include "../pr/include/md/sunos4.h" +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* + * Just prevent stupidity + */ +#undef NAME_MAX +#define NAME_MAX 256 + +extern char *program; + +extern void fail(char *format, ...); +extern char *getcomponent(char *path, char *name); +extern char *ino2name(ino_t ino, char *dir); +extern void *xmalloc(size_t size); +extern char *xstrdup(char *s); +extern char *xbasename(char *path); +extern void xchdir(char *dir); + +/* Relate absolute pathnames from and to returning the result in outpath. */ +extern int relatepaths(char *from, char *to, char *outpath); + +/* XXX changes current working directory -- caveat emptor */ +extern void reversepath(char *inpath, char *name, int len, char *outpath); + +#endif /* pathsub_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/config/prdepend.h b/src/libs/xpcom18a4/nsprpub/config/prdepend.h new file mode 100644 index 00000000..df72c568 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/prdepend.h @@ -0,0 +1,44 @@ +/* -*- 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) 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 ***** */ + +/* + * A dummy header file that is a dependency for all the object files. + * Used to force a full recompilation of NSPR in Mozilla's Tinderbox + * depend builds. See comments in rules.mk. + */ + +#error "Do not include this header file." diff --git a/src/libs/xpcom18a4/nsprpub/config/prmkdir.bat b/src/libs/xpcom18a4/nsprpub/config/prmkdir.bat new file mode 100644 index 00000000..9bea8553 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/prmkdir.bat @@ -0,0 +1,38 @@ +REM +REM ***** BEGIN LICENSE BLOCK ***** +REM Version: MPL 1.1/GPL 2.0/LGPL 2.1 +REM +REM The contents of this file are subject to the Mozilla Public License Version +REM 1.1 (the "License"); you may not use this file except in compliance with +REM the License. You may obtain a copy of the License at +REM http://www.mozilla.org/MPL/ +REM +REM Software distributed under the License is distributed on an "AS IS" basis, +REM WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +REM for the specific language governing rights and limitations under the +REM License. +REM +REM The Original Code is the Netscape Portable Runtime (NSPR). +REM +REM The Initial Developer of the Original Code is +REM Netscape Communications Corporation. +REM Portions created by the Initial Developer are Copyright (C) 1998-2000 +REM the Initial Developer. All Rights Reserved. +REM +REM Contributor(s): +REM +REM Alternatively, the contents of this file may be used under the terms of +REM either the GNU General Public License Version 2 or later (the "GPL"), or +REM the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +REM in which case the provisions of the GPL or the LGPL are applicable instead +REM of those above. If you wish to allow use of your version of this file only +REM under the terms of either the GPL or the LGPL, and not to allow others to +REM use your version of this file under the terms of the MPL, indicate your +REM decision by deleting the provisions above and replace them with the notice +REM and other provisions required by the GPL or the LGPL. If you do not delete +REM the provisions above, a recipient may use your version of this file under +REM the terms of any one of the MPL, the GPL or the LGPL. +REM +REM ***** END LICENSE BLOCK ***** + +mkdir %1 diff --git a/src/libs/xpcom18a4/nsprpub/config/rules.mk b/src/libs/xpcom18a4/nsprpub/config/rules.mk new file mode 100644 index 00000000..bba50ee7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/config/rules.mk @@ -0,0 +1,514 @@ +#! gmake +# +# ***** 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 ***** + +################################################################################ +# We have a 4 pass build process: +# +# Pass 1. export - Create generated headers and stubs. Publish public headers to +# dist//include. +# +# Pass 2. libs - Create libraries. Publish libraries to dist//lib. +# +# Pass 3. all - Create programs. +# +# Pass 4. install - Publish programs to dist//bin. +# +# Parameters to this makefile (set these before including): +# +# a) +# TARGETS -- the target to create +# (defaults to $LIBRARY $PROGRAM) +# b) +# DIRS -- subdirectories for make to recurse on +# (the 'all' rule builds $TARGETS $DIRS) +# c) +# CSRCS -- .c files to compile +# (used to define $OBJS) +# d) +# PROGRAM -- the target program name to create from $OBJS +# ($OBJDIR automatically prepended to it) +# e) +# LIBRARY -- the target library name to create from $OBJS +# ($OBJDIR automatically prepended to it) +# +################################################################################ + +ifndef topsrcdir +topsrcdir=$(MOD_DEPTH) +endif + +ifndef srcdir +srcdir=. +endif + +ifndef NSPR_CONFIG_MK +include $(topsrcdir)/config/config.mk +endif + +ifdef USE_AUTOCONF +ifdef CROSS_COMPILE +ifdef INTERNAL_TOOLS +CC=$(HOST_CC) +CCC=$(HOST_CXX) +CFLAGS=$(HOST_CFLAGS) +CXXFLAGS=$(HOST_CXXFLAGS) +endif +endif +endif + +# +# This makefile contains rules for building the following kinds of +# libraries: +# - LIBRARY: a static (archival) library +# - SHARED_LIBRARY: a shared (dynamic link) library +# - IMPORT_LIBRARY: an import library, used only on Windows and OS/2 +# +# The names of these libraries can be generated by simply specifying +# LIBRARY_NAME and LIBRARY_VERSION. +# + +ifdef LIBRARY_NAME +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) + +# +# Win95, Win16, and OS/2 require library names conforming to the 8.3 rule. +# other platforms do not. +# +ifeq (,$(filter-out WIN95 OS2,$(OS_TARGET))) +LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +IMPORT_LIBRARY = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +SHARED_LIB_PDB = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb +else +LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_s.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +IMPORT_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +SHARED_LIB_PDB = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).pdb +endif + +else + +LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(LIB_SUFFIX) +ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1) +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION)_shr.a +else +ifdef MKSHLIB +SHARED_LIBRARY = $(OBJDIR)/lib$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +endif +endif + +endif +endif + +ifndef TARGETS +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(IMPORT_LIBRARY) +ifndef BUILD_OPT +ifdef MSC_VER +ifneq ($(MSC_VER),1200) +TARGETS += $(SHARED_LIB_PDB) +endif +endif +endif +else +TARGETS = $(LIBRARY) $(SHARED_LIBRARY) +endif +endif + +# +# OBJS is the list of object files. It can be constructed by +# specifying CSRCS (list of C source files) and ASFILES (list +# of assembly language source files). +# + +ifndef OBJS +OBJS = $(addprefix $(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix $(OBJDIR)/,$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))) +endif + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +EXTRA_LIBS := $(patsubst -l%,$(DIST)/lib/%.$(LIB_SUFFIX),$(EXTRA_LIBS)) +endif + +ALL_TRASH = $(TARGETS) $(OBJS) $(filter-out . .., $(OBJDIR)) LOGS TAGS $(GARBAGE) \ + $(NOSUCHFILE) \ + so_locations + +ifeq ($(OS_ARCH),OpenVMS) +ALL_TRASH += $(wildcard *.c*_defines) +ifdef SHARED_LIBRARY +VMS_SYMVEC_FILE = $(SHARED_LIBRARY:.$(DLL_SUFFIX)=_symvec.opt) +VMS_SYMVEC_FILE_MODULE = $(srcdir)/$(LIBRARY_NAME)_symvec.opt +ALL_TRASH += $(VMS_SYMVEC_FILE) +endif +endif + +ifndef RELEASE_LIBS_DEST +RELEASE_LIBS_DEST = $(RELEASE_LIB_DIR) +endif + +ifdef DIRS +LOOP_OVER_DIRS = \ + @for d in $(DIRS); do \ + if test -d $$d; then \ + set -e; \ + echo "cd $$d; $(MAKE) $@"; \ + $(MAKE) -C $$d $@; \ + set +e; \ + else \ + echo "Skipping non-directory $$d..."; \ + fi; \ + done +endif + +################################################################################ + +all:: export + +export:: + +$(LOOP_OVER_DIRS) + +libs:: export + +install:: export + +clean:: + rm -rf $(OBJS) so_locations $(NOSUCHFILE) $(GARBAGE) + +$(LOOP_OVER_DIRS) + +clobber:: + rm -rf $(OBJS) $(TARGETS) $(filter-out . ..,$(OBJDIR)) $(GARBAGE) so_locations $(NOSUCHFILE) + +$(LOOP_OVER_DIRS) + +realclean clobber_all:: + rm -rf $(wildcard *.OBJ *.OBJD) dist $(ALL_TRASH) + +$(LOOP_OVER_DIRS) + +distclean:: + rm -rf $(wildcard *.OBJ *.OBJD) dist $(ALL_TRASH) $(DIST_GARBAGE) + +$(LOOP_OVER_DIRS) + +real_install:: $(RELEASE_BINS) $(RELEASE_HEADERS) $(RELEASE_LIBS) +ifdef RELEASE_BINS + $(NSINSTALL) -t -m 0755 $(RELEASE_BINS) $(DESTDIR)$(bindir) +endif +ifdef RELEASE_HEADERS + $(NSINSTALL) -t -m 0644 $(RELEASE_HEADERS) $(DESTDIR)$(includedir)/$(include_subdir) +endif +ifdef RELEASE_LIBS + $(NSINSTALL) -t -m 0755 $(RELEASE_LIBS) $(DESTDIR)$(libdir)/$(lib_subdir) +endif + +$(LOOP_OVER_DIRS) + +release:: export +ifdef RELEASE_BINS + @echo "Copying executable programs and scripts to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_BIN_DIR); then \ + rm -rf $(RELEASE_BIN_DIR); \ + $(NSINSTALL) -D $(RELEASE_BIN_DIR);\ + else \ + true; \ + fi + cp $(RELEASE_BINS) $(RELEASE_BIN_DIR) +endif +ifdef RELEASE_LIBS + @echo "Copying libraries to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_LIBS_DEST); then \ + rm -rf $(RELEASE_LIBS_DEST); \ + $(NSINSTALL) -D $(RELEASE_LIBS_DEST);\ + else \ + true; \ + fi + cp $(RELEASE_LIBS) $(RELEASE_LIBS_DEST) +endif +ifdef RELEASE_HEADERS + @echo "Copying header files to release directory" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + else \ + true; \ + fi + @if test ! -d $(RELEASE_HEADERS_DEST); then \ + rm -rf $(RELEASE_HEADERS_DEST); \ + $(NSINSTALL) -D $(RELEASE_HEADERS_DEST);\ + else \ + true; \ + fi + cp $(RELEASE_HEADERS) $(RELEASE_HEADERS_DEST) +endif + +$(LOOP_OVER_DIRS) + +alltags: + rm -f TAGS tags + find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs etags -a + find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs ctags -a + +$(NFSPWD): + cd $(@D); $(MAKE) $(@F) + +$(PROGRAM): $(OBJS) + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) $(OBJS) -Fe$@ -link $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CC) $(OBJS) -Fe$@ $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CC) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS) +endif +endif +ifdef ENABLE_STRIP + $(STRIP) $@ +endif + +$(LIBRARY): $(OBJS) + @$(MAKE_OBJDIR) + rm -f $@ +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(AR) $(subst /,\\,$(OBJS)) $(AR_FLAGS) +else + $(AR) $(AR_FLAGS) $(OBJS) $(AR_EXTRA_ARGS) +endif + $(RANLIB) $@ + +ifeq ($(OS_TARGET), OS2) +$(IMPORT_LIBRARY): $(MAPFILE) + rm -f $@ + $(IMPLIB) $@ $(MAPFILE) +endif + +$(SHARED_LIBRARY): $(OBJS) $(RES) $(MAPFILE) + @$(MAKE_OBJDIR) + rm -f $@ +ifeq ($(OS_ARCH)$(OS_RELEASE), AIX4.1) + echo "#!" > $(OBJDIR)/lib$(LIBRARY_NAME)_syms + nm -B -C -g $(OBJS) \ + | awk '/ [T,D] / {print $$3}' \ + | sed -e 's/^\.//' \ + | sort -u >> $(OBJDIR)/lib$(LIBRARY_NAME)_syms + $(LD) $(XCFLAGS) -o $@ $(OBJS) -bE:$(OBJDIR)/lib$(LIBRARY_NAME)_syms \ + -bM:SRE -bnoentry $(OS_LIBS) $(EXTRA_LIBS) +else # AIX 4.1 +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(LINK_DLL) -MAP $(DLLBASE) $(DLL_LIBS) $(EXTRA_LIBS) $(OBJS) $(RES) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LINK_DLL) $(DLLBASE) $(OBJS) $(OS_LIBS) $(EXTRA_LIBS) $(MAPFILE) +else # !os2 vacpp +ifeq ($(OS_TARGET), OpenVMS) + @if test ! -f $(VMS_SYMVEC_FILE); then \ + if test -f $(VMS_SYMVEC_FILE_MODULE); then \ + echo Creating component options file $(VMS_SYMVEC_FILE); \ + cp $(VMS_SYMVEC_FILE_MODULE) $(VMS_SYMVEC_FILE); \ + fi; \ + fi +endif # OpenVMS + $(MKSHLIB) $(OBJS) $(RES) $(EXTRA_LIBS) +endif # OS2 vacpp +endif # WINNT +endif # AIX 4.1 +ifdef ENABLE_STRIP + $(STRIP) $@ +endif + +ifeq ($(OS_ARCH),WINNT) +$(RES): $(RESNAME) + @$(MAKE_OBJDIR) +# The resource compiler does not understand the -U option. +ifdef NS_USE_GCC + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES:-I%=--include-dir %) -o $@ $< +else + $(RC) $(RCFLAGS) $(filter-out -U%,$(DEFINES)) $(INCLUDES) -Fo$@ $< +endif # GCC + @echo $(RES) finished +endif + +$(MAPFILE): $(LIBRARY_NAME).def + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH),SunOS) + grep -v ';-' $< | \ + sed -e 's,;+,,' -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,;,' > $@ +endif +ifeq ($(OS_ARCH),OS2) + echo LIBRARY $(LIBRARY_NAME)$(LIBRARY_VERSION) INITINSTANCE TERMINSTANCE > $@ + echo PROTMODE >> $@ + echo CODE LOADONCALL MOVEABLE DISCARDABLE >> $@ + echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $@ + echo EXPORTS >> $@ +ifeq ($(MOZ_OS2_TOOLS),VACPP) + grep -v ';+' $< | grep -v ';-' | \ + sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' >> $@ +else + grep -v ';+' $< | grep -v ';-' | \ + sed -e 's; DATA ;;' -e 's,;;,,' -e 's,;.*,,' -e 's,\([\t ]*\),\1_,' | \ + awk 'BEGIN {ord=1;} { print($$0 " @" ord " RESIDENTNAME"); ord++;}' >> $@ + $(ADD_TO_DEF_FILE) +endif +endif + +# +# Translate source filenames to absolute paths. This is required for +# debuggers under Windows and OS/2 to find source files automatically. +# + +ifeq ($(OS_ARCH),OS2) +NEED_ABSOLUTE_PATH = 1 +endif + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) +NEED_ABSOLUTE_PATH = 1 +endif + +ifdef NEED_ABSOLUTE_PATH +PWD := $(shell pwd) +abspath = $(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(PWD)/$(1))) +endif + +$(OBJDIR)/%.$(OBJ_SUFFIX): %.cpp + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CCC) -Fo$@ -c $(CCCFLAGS) $(call abspath,$<) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CCC) -Fo$@ -c $(CCCFLAGS) $(call abspath,$<) +else +ifdef NEED_ABSOLUTE_PATH + $(CCC) -o $@ -c $(CCCFLAGS) $(call abspath,$<) +else + $(CCC) -o $@ -c $(CCCFLAGS) $< +endif +endif +endif + +WCCFLAGS1 = $(subst /,\\,$(CFLAGS)) +WCCFLAGS2 = $(subst -I,-i=,$(WCCFLAGS1)) +WCCFLAGS3 = $(subst -D,-d,$(WCCFLAGS2)) +$(OBJDIR)/%.$(OBJ_SUFFIX): %.c + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) $(call abspath,$<) +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(CC) -Fo$@ -c $(CFLAGS) $(call abspath,$<) +else +ifdef NEED_ABSOLUTE_PATH + $(CC) -o $@ -c $(CFLAGS) $(call abspath,$<) +else + $(CC) -o $@ -c $(CFLAGS) $< +endif +endif +endif + + +$(OBJDIR)/%.$(OBJ_SUFFIX): %.s + @$(MAKE_OBJDIR) + $(AS) -o $@ $(ASFLAGS) -c $< + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +$(OBJDIR)/%.$(OBJ_SUFFIX): %.asm + @$(MAKE_OBJDIR) + $(AS) -Fdo:./$(OBJDIR) $(ASFLAGS) $< +endif + +%.i: %.c + $(CC) -C -E $(CFLAGS) $< > $*.i + +%: %.pl + rm -f $@; cp $< $@; chmod +x $@ + +# +# HACK ALERT +# +# The only purpose of this rule is to pass Mozilla's Tinderbox depend +# builds (http://tinderbox.mozilla.org/showbuilds.cgi). Mozilla's +# Tinderbox builds NSPR continuously as part of the Mozilla client. +# Because NSPR's make depend is not implemented, whenever we change +# an NSPR header file, the depend build does not recompile the NSPR +# files that depend on the header. +# +# This rule makes all the objects depend on a dummy header file. +# Touch this dummy header file to force the depend build to recompile +# everything. +# +# This rule should be removed when make depend is implemented. +# + +DUMMY_DEPEND_H = $(topsrcdir)/config/prdepend.h + +$(filter $(OBJDIR)/%.$(OBJ_SUFFIX),$(OBJS)): $(OBJDIR)/%.$(OBJ_SUFFIX): $(DUMMY_DEPEND_H) + +# END OF HACK + +################################################################################ +# Special gmake rules. +################################################################################ + +# +# Re-define the list of default suffixes, so gmake won't have to churn through +# hundreds of built-in suffix rules for stuff we don't need. +# +.SUFFIXES: +.SUFFIXES: .a .$(OBJ_SUFFIX) .c .cpp .s .h .i .pl + +# +# Fake targets. Always run these rules, even if a file/directory with that +# name already exists. +# +.PHONY: all alltags clean export install libs realclean release + +# +# List the target pattern of an implicit rule as a dependency of the +# special target .PRECIOUS to preserve intermediate files made by +# implicit rules whose target patterns match that file's name. +# (See GNU Make documentation, Edition 0.51, May 1996, Sec. 10.4, +# p. 107.) +# +.PRECIOUS: $(OBJDIR)/%.$(OBJ_SUFFIX) diff --git a/src/libs/xpcom18a4/nsprpub/configure b/src/libs/xpcom18a4/nsprpub/configure new file mode 100755 index 00000000..2046d79f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/configure @@ -0,0 +1,6034 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-dist-prefix=DIST_PREFIX + place build files in DIST_PREFIX [dist]" +ac_help="$ac_help + --with-dist-bindir=DIR build execuatables in DIR [DIST_PREFIX/bin]" +ac_help="$ac_help + --with-dist-includedir=DIR + build include files in DIR [DIST_PREFIX/include/nspr]" +ac_help="$ac_help + --with-dist-libdir=DIR build library files in DIR [DIST_PREFIX/lib]" +ac_help="$ac_help + --with-mozilla Compile NSPR with Mozilla support" +ac_help="$ac_help + --enable-optimize(=val) Enable code optimizations (val, ie. -O2) " +ac_help="$ac_help + --disable-debug Do not compile in debugging symbols" +ac_help="$ac_help + --enable-win32-target=\$t + Specify win32 flavor. (WIN95 or WINNT)" +ac_help="$ac_help + --enable-debug-rtl Use the MSVC debug runtime library" +ac_help="$ac_help + --enable-n32 Enable n32 ABI support (IRIX only)" +ac_help="$ac_help + --enable-64bit Enable 64-bit support (on certain platforms)" +ac_help="$ac_help + --enable-mdupdate Enable use of certain compilers' mdupdate feature" +ac_help="$ac_help + --enable-macos-target=VER (default=10.1) + Set the minimum MacOS version needed at runtime" +ac_help="$ac_help + --enable-strip Enable stripping of shared libs and programs" +ac_help="$ac_help + --with-pthreads Use system pthreads library as thread subsystem" +ac_help="$ac_help + --enable-user-pthreads Build using userland pthreads" +ac_help="$ac_help + --enable-nspr-threads Build using classic nspr threads" +ac_help="$ac_help + --with-bthreads Use system bthreads library as thread subsystem (BeOS only)" +ac_help="$ac_help + --with-native-threads Use native system threads as thread subsystem (Solaris only)" +ac_help="$ac_help + --enable-cplus Enable some c++ api routines" +ac_help="$ac_help + --enable-ipv6 Compile ipv6 support" +ac_help="$ac_help + --enable-boehm Enable the Boehm Garbage Collector" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=config/libc_r.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in ${srcdir}/build/autoconf $srcdir/${srcdir}/build/autoconf" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:621: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:642: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:660: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +MOD_MAJOR_VERSION=4 +MOD_MINOR_VERSION=5 +MOD_PATCH_VERSION=0 +NSPR_MODNAME=nspr20 +_HAVE_PTHREADS= +USE_PTHREADS= +USE_USER_PTHREADS= +USE_NSPR_THREADS= +USE_N32= +USE_64= +USE_CPLUS= +USE_IPV6= +USE_MDUPDATE= +MACOS_DEPLOYMENT_TARGET= +_OPTIMIZE_FLAGS=-O +_DEBUG_FLAGS=-g +MOZ_DEBUG=1 +MOZ_OPTIMIZE= +OBJDIR=. +OBJDIR_NAME=. +OBJDIR_SUFFIX=OBJ +NSINSTALL='$(MOD_DEPTH)/config/$(OBJDIR_NAME)/nsinstall' +NOSUCHFILE=/no-such-file +LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)' +LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)' +CYGWIN_WRAPPER= + +RESOLVE_LINK_SYMBOLS= + +CFLAGS="${CFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +case "$target" in +*-cygwin*|*-mingw*) + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC= + for ac_prog in cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:727: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CC" && break +done + + if test "$CC" = "cl"; then + echo 'main() { return 0; }' > dummy.c + ${CC} -o dummy dummy.c >/dev/null 2>&1 + if test $? = 0; then + _WIN32_MSVC=1 + CXX=$CC + else + echo "configure: warning: $(CC) test failed. Using normal feature tests" 1>&2 + fi + rm -f dummy dummy.o dummy.obj dummy.exe dummy.c + fi + ;; +*-msvc*) + _WIN32_MSVC=1 + ;; +*-mks*) + _WIN32_MSVC=1 + ;; +esac + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 +fi + +dist_prefix='${MOD_DEPTH}/dist' +dist_bindir='${dist_prefix}/bin' +dist_includedir='${dist_prefix}/include/nspr' +dist_libdir='${dist_prefix}/lib' +if test "${includedir}" = '${prefix}/include'; then + includedir='${prefix}/include/nspr' +fi + +# Check whether --with-dist-prefix or --without-dist-prefix was given. +if test "${with_dist_prefix+set}" = set; then + withval="$with_dist_prefix" + dist_prefix=$withval +fi + + +# Check whether --with-dist-bindir or --without-dist-bindir was given. +if test "${with_dist_bindir+set}" = set; then + withval="$with_dist_bindir" + dist_bindir=$withval +fi + + +# Check whether --with-dist-includedir or --without-dist-includedir was given. +if test "${with_dist_includedir+set}" = set; then + withval="$with_dist_includedir" + dist_includedir=$withval +fi + + +# Check whether --with-dist-libdir or --without-dist-libdir was given. +if test "${with_dist_libdir+set}" = set; then + withval="$with_dist_libdir" + dist_libdir=$withval +fi + + + + + + + +# Check whether --with-mozilla or --without-mozilla was given. +if test "${with_mozilla+set}" = set; then + withval="$with_mozilla" + if test "$withval" = "yes"; then + cat >> confdefs.h <<\EOF +#define MOZILLA_CLIENT 1 +EOF + + MOZILLA_CLIENT=1 + else + MOZILLA_CLIENT= + fi +else + if test -n "$MOZILLA_CLIENT"; then + cat >> confdefs.h <<\EOF +#define MOZILLA_CLIENT 1 +EOF + + fi +fi + + +# Check whether --enable-optimize or --disable-optimize was given. +if test "${enable_optimize+set}" = set; then + enableval="$enable_optimize" + if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _OPTIMIZE_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_OPTIMIZE_FLAGS=$_OPTIMIZE_FLAGS + fi + else + MOZ_OPTIMIZE= + fi +fi + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if test "$enableval" = "no"; then + MOZ_DEBUG= + else + MOZ_DEBUG=1 + fi +fi + + +# Check whether --enable-win32-target or --disable-win32-target was given. +if test "${enable_win32_target+set}" = set; then + enableval="$enable_win32_target" + OS_TARGET=`echo $enableval | tr a-z A-Z` +else + OS_TARGET= +fi + + +# Check whether --enable-debug-rtl or --disable-debug-rtl was given. +if test "${enable_debug_rtl+set}" = set; then + enableval="$enable_debug_rtl" + if test "$enableval" = "yes"; then + USE_DEBUG_RTL=1 + fi +fi + + +# Check whether --enable-n32 or --disable-n32 was given. +if test "${enable_n32+set}" = set; then + enableval="$enable_n32" + if test "$enableval" = "yes"; then + USE_N32=1 + else if test "$enableval" = "no"; then + USE_N32= + fi + fi +fi + + +# Check whether --enable-64bit or --disable-64bit was given. +if test "${enable_64bit+set}" = set; then + enableval="$enable_64bit" + if test "$enableval" = "yes"; then + USE_64=1 + fi +fi + + +# Check whether --enable-mdupdate or --disable-mdupdate was given. +if test "${enable_mdupdate+set}" = set; then + enableval="$enable_mdupdate" + if test "$enableval" = "yes"; then + USE_MDUPDATE=1 + fi +fi + + +# Check whether --enable-macos-target or --disable-macos-target was given. +if test "${enable_macos_target+set}" = set; then + enableval="$enable_macos_target" + MACOS_DEPLOYMENT_TARGET_STR=$enableval +else + MACOS_DEPLOYMENT_TARGET_STR=10.1 +fi + + +case "$target" in + +*-aix*) + case "${target_os}" in + aix3.2*) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + ;; + esac + ;; + +esac + +if test -z "$CC"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CC=xlc_r + else + CC=xlc + fi + ;; + + *-hpux*) + CC=cc + ;; + + *-irix*) + CC=cc + ;; + + *-openvms*) + CC=cc + ;; + + *-osf*) + CC=cc + ;; + + *-solaris*) + CC=cc + ;; + + esac +fi + +if test -z "$CXX"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CXX=xlC_r + else + CXX=xlC + fi + ;; + + *-hpux*) + case "${target_os}" in + hpux10.30) + CXX=aCC + ;; + hpux11.*) + CXX=aCC + ;; + *) + CXX=CC + ;; + esac + ;; + + *-irix*) + CXX=CC + ;; + + *-openvms*) + CXX=cxx + ;; + + *-osf*) + CXX=cxx + ;; + + *-solaris*) + CXX=CC + ;; + + esac +fi + +if test -z "$SKIP_PATH_CHECKS"; then + # Extract the first word of "$WHOAMI whoami", so it can be a program name with args. +set dummy $WHOAMI whoami; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1025: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_WHOAMI'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$WHOAMI" in + /*) + ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_WHOAMI="$WHOAMI" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_WHOAMI="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_WHOAMI" && ac_cv_path_WHOAMI="echo not_whoami" + ;; +esac +fi +WHOAMI="$ac_cv_path_WHOAMI" +if test -n "$WHOAMI"; then + echo "$ac_t""$WHOAMI" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +fi + +if test -n "$MOZ_DEBUG"; then + cat >> confdefs.h <<\EOF +#define DEBUG 1 +EOF + + DEFINES="$DEFINES -UNDEBUG" + + case "${target_os}" in + beos*) + DEFINES="$DEFINES -DDEBUG_${USER}" + ;; + msvc*|mks*|cygwin*|mingw*|os2*) + DEFINES="$DEFINES -DDEBUG_`echo ${USERNAME} | sed -e 's| |_|g'`" + ;; + *) + DEFINES="$DEFINES -DDEBUG_`$WHOAMI`" + ;; + esac +else + cat >> confdefs.h <<\EOF +#define NDEBUG 1 +EOF + + DEFINES="$DEFINES -UDEBUG" +fi + +if test -z "$SKIP_COMPILER_CHECKS"; then +if test "$target" != "$host"; then + echo "cross compiling from $host to $target" + cross_compiling=yes + + _SAVE_CC="$CC" + _SAVE_CFLAGS="$CFLAGS" + _SAVE_LDFLAGS="$LDFLAGS" + + echo $ac_n "checking for $host compiler""... $ac_c" 1>&6 +echo "configure:1096: checking for $host compiler" >&5 + for ac_prog in $HOST_CC gcc cc /usr/ucb/cc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1102: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_HOST_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$HOST_CC"; then + ac_cv_prog_HOST_CC="$HOST_CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_HOST_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +HOST_CC="$ac_cv_prog_HOST_CC" +if test -n "$HOST_CC"; then + echo "$ac_t""$HOST_CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$HOST_CC" && break +done +test -n "$HOST_CC" || HOST_CC="""" + + if test -z "$HOST_CC"; then + { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } + fi + echo "$ac_t""$HOST_CC" 1>&6 + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + echo $ac_n "checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1148: checking whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_prog_host_cc_works=1 echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: installation or configuration problem: $host compiler $HOST_CC cannot create executables." 1>&2; exit 1; } +fi +rm -f conftest* + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + for ac_prog in $CC "${target_alias}-gcc" "${target}-gcc" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1177: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CC" && break +done +test -n "$CC" || CC="echo" + + unset ac_cv_prog_CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1211: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1241: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1292: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1324: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1335 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1340: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1366: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1371: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1399: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + for ac_prog in $CXX "${target_alias}-g++" "${target}-g++" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1435: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="echo" + + unset ac_cv_prog_CXX + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1471: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1503: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 1514 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1519: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1545: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:1550: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:1578: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + for ac_prog in $RANLIB "${target_alias}-ranlib" "${target}-ranlib" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1614: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$RANLIB" && break +done +test -n "$RANLIB" || RANLIB="echo" + + for ac_prog in $AR "${target_alias}-ar" "${target}-ar" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1649: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="echo" + + for ac_prog in $AS "${target_alias}-as" "${target}-as" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1684: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS="echo" + + for ac_prog in $LD "${target_alias}-ld" "${target}-ld" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1719: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD="echo" + + for ac_prog in $STRIP "${target_alias}-strip" "${target}-strip" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1754: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP="echo" + + for ac_prog in $WINDRES "${target_alias}-windres" "${target}-windres" +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1789: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES="echo" + + +else + for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1826: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CXX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CXX="$ac_cv_prog_CXX" +if test -n "$CXX"; then + echo "$ac_t""$CXX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$CXX" && break +done +test -n "$CXX" || CXX="gcc" + + +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1858: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext << EOF + +#line 1869 "configure" +#include "confdefs.h" + +int main(){return(0);} +EOF +if { (eval echo configure:1874: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cxx_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cxx_cross=no + else + ac_cv_prog_cxx_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cxx_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6 +if test $ac_cv_prog_cxx_works = no; then + { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1900: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6 +cross_compiling=$ac_cv_prog_cxx_cross + +echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 +echo "configure:1905: checking whether we are using GNU C++" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.C <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gxx=yes +else + ac_cv_prog_gxx=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gxx" 1>&6 + +if test $ac_cv_prog_gxx = yes; then + GXX=yes +else + GXX= +fi + +ac_test_CXXFLAGS="${CXXFLAGS+set}" +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS= +echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 +echo "configure:1933: checking whether ${CXX-g++} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.cc +if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then + ac_cv_prog_cxx_g=yes +else + ac_cv_prog_cxx_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS="$ac_save_CXXFLAGS" +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi + + if test "$CXX" = "cl" -a -z "$CC"; then + CC=$CXX + else + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1970: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2000: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2051: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:2083: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 2094 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:2099: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:2125: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:2130: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:2158: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + + fi + echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:2191: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2212: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2229: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2246: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2273: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + for ac_prog in as +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2305: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AS" in + /*) + ac_cv_path_AS="$AS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AS="$AS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AS="$ac_cv_path_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AS" && break +done +test -n "$AS" || AS="$CC" + + for ac_prog in ar +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2346: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$AR" in + /*) + ac_cv_path_AR="$AR" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_AR="$AR" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_AR="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +AR="$ac_cv_path_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AR" && break +done +test -n "$AR" || AR="echo not_ar" + + for ac_prog in ld link +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2387: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$LD" in + /*) + ac_cv_path_LD="$LD" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_LD="$LD" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_LD="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +LD="$ac_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LD" && break +done +test -n "$LD" || LD="echo not_ld" + + for ac_prog in strip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2428: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$STRIP" in + /*) + ac_cv_path_STRIP="$STRIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_STRIP="$STRIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_STRIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +STRIP="$ac_cv_path_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$STRIP" && break +done +test -n "$STRIP" || STRIP="echo not_strip" + + for ac_prog in windres +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2469: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$WINDRES" in + /*) + ac_cv_path_WINDRES="$WINDRES" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_WINDRES="$WINDRES" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_WINDRES="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +WINDRES="$ac_cv_path_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WINDRES" && break +done +test -n "$WINDRES" || WINDRES="echo not_windres" + + if test -z "$HOST_CC"; then + HOST_CC="$CC" + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi +fi + +if test "$GCC" = "yes"; then + GNU_CC=1 +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +rm -f a.out + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +echo $ac_n "checking for gcc -pipe support""... $ac_c" 1>&6 +echo "configure:2531: checking for gcc -pipe support" >&5 +if test -n "$GNU_CC" && test -n "$GNU_CXX" && test -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); return 0; }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s | ${AS} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + cat > conftest.$ac_ext < +int main() { +printf("Hello World\n"); +; return 0; } +EOF +if { (eval echo configure:2553: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + _res_gcc_pipe="yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + _res_gcc_pipe="no" +fi +rm -f conftest* + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" && test "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + echo "$ac_t""$_res" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +fi # SKIP_COMPILER_CHECKS + +if test -z "$SKIP_PATH_CHECKS"; then + for ac_prog in perl5 perl +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2586: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$PERL" in + /*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_PERL="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +PERL="$ac_cv_path_PERL" +if test -n "$PERL"; then + echo "$ac_t""$PERL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$PERL" && break +done +test -n "$PERL" || PERL="echo not_perl" + +elif test -z "$PERL"; then + PERL=perl +fi + +OBJ_SUFFIX=o +LIB_SUFFIX=a +DLL_SUFFIX=so +ASM_SUFFIX=s +MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' +PR_MD_ASFILES= +PR_MD_CSRCS= +PR_MD_ARCH_DIR=unix +AR_FLAGS='cr $@' +AS='$(CC)' +ASFLAGS='$(CFLAGS)' + +if test -n "$CROSS_COMPILE"; then + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + OS_TEST="${target_cpu}" + case "${target_os}" in + linux*) OS_ARCH=Linux ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + esac +else + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` + OS_TEST=`uname -m` +fi + +if test "$OS_ARCH" = "IRIX64"; then + OS_ARCH=IRIX +fi + +if test "$OS_ARCH" = "AIX"; then + OS_RELEASE=`uname -v`.`uname -r` +fi + +if test "$OS_ARCH" = "FreeBSD"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` +fi + +if test "$OS_ARCH" = "Linux"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` + OS_RELEASE=`echo $OS_RELEASE | awk -F\. '{ print $1 "." $2 }'` +fi + +if test "$OS_ARCH" = "OpenVMS"; then + OS_RELEASE=`uname -v` +fi + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# Note: OS_TARGET should be specified on the command line for gmake. +# When OS_TARGET=WIN95 is specified, then a Windows 95 target is built. +# The difference between the Win95 target and the WinNT target is that +# the WinNT target uses Windows NT specific features not available +# in Windows 95. The Win95 target will run on Windows NT, but (supposedly) +# at lesser performance (the Win95 target uses threads; the WinNT target +# uses fibers). +# +# When OS_TARGET=WIN16 is specified, then a Windows 3.11 (16bit) target +# is built. See: win16_3.11.mk for lots more about the Win16 target. +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# The following hack allows one to build on a WIN95 machine (as if +# s/he were cross-compiling on a WINNT host for a WIN95 target). +# It also accomodates for MKS's uname.exe. If you never intend +# to do development on a WIN95 machine, you don't need this hack. +# +if test "$OS_ARCH" = "WIN95"; then + OS_ARCH=WINNT + OS_TARGET=WIN95 +elif test "$OS_ARCH" = 'Windows_95'; then + OS_ARCH=Windows_NT + OS_TARGET=WIN95 +elif test "$OS_ARCH" = 'Windows_98'; then + OS_ARCH=Windows_NT + OS_TARGET=WIN95 +elif test "`echo $OS_ARCH | egrep -c '^(CYGWIN_9|CYGWIN_ME)' 2>/dev/null`" != 0; then + OS_ARCH='CYGWIN_NT-4.0' + OS_TARGET=WIN95 +elif test "$OS_ARCH" = "OS_2"; then + OS_ARCH=OS2 + OS_TARGET=OS2 +fi + +# +# On WIN32, we also define the variable CPU_ARCH. +# + +if test "$OS_ARCH" = "WINNT"; then + CPU_ARCH=`uname -p` + if test "$CPU_ARCH" = "I386"; then + CPU_ARCH=x86 + fi +elif test "$OS_ARCH" = "Windows_NT"; then +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + CPU_ARCH=`uname -m` + # + # MKS's uname -m returns "586" on a Pentium machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +elif echo "$OS_ARCH" | grep -c CYGWIN_NT >/dev/null; then +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# + OS_RELEASE=`echo $OS_ARCH | sed 's|^CYGWIN_NT-||'` + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # Cygwin's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +elif test "$OS_ARCH" = "CYGWIN32_NT"; then +# +# Prior to the Beta 20 release, Cygwin was called GNU-Win32. +# If uname -s returns "CYGWIN32/NT", we assume that we are using +# the uname.exe in the GNU-Win32 tools. +# + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # GNU-Win32's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +fi + +if test -n "$MOZILLA_CLIENT" && test "$OS_ARCH" = "WINNT"; then + OS_TARGET=WIN95 + if test -n "$MOZ_DEBUG"; then + USE_DEBUG_RTL=1 + fi +fi +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +if test "$OS_TARGET" = "WIN95"; then + OS_RELEASE="4.0" +fi +if test "$OS_TARGET" = "WIN16"; then + OS_RELEASE= +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + + +case "$host" in +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + NSINSTALL='$(CYGWIN_WRAPPER) nsinstall' + if test `echo "${PATH}" | grep -c \;` = 0; then + CYGWIN_WRAPPER='sh $(topsrcdir)/build/cygwin-wrapper' + fi + ;; +*-beos*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE" + ;; +*os2*) + ;; +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + ;; +esac + +case "$target" in + +*-aix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + DSO_LDOPTS='-brtl -bnortllib -bM:SRE -bnoentry -bexpall -blibpath:/usr/lib:/lib' + ac_safe=`echo "sys/atomic_op.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for sys/atomic_op.h""... $ac_c" 1>&6 +echo "configure:2831: checking for sys/atomic_op.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2841: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define AIX_HAVE_ATOMIC_OP_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + + case "${target_os}" in + aix3.2*) + cat >> confdefs.h <<\EOF +#define AIX_RENAME_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + AIX_LINK_OPTS='-bnso -berok' + PR_MD_ASFILES=os_AIX.s + ;; + aix4.1*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_1 1 +EOF + + MKSHLIB= + DSO_LDOPTS= + AIX_LINK_OPTS='-bnso -berok' + LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)_shr' + LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)_shr' + ;; + aix4.2*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + aix4.3*) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_3_PLUS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + *) + cat >> confdefs.h <<\EOF +#define AIX_TIMERS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define AIX4_3_PLUS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + esac + CFLAGS="$CFLAGS -qro -qroconst" + AIX_WRAP='$(DIST)/lib/aixwrap.o' + AIX_TMP='./_aix_tmp.o' + if test -n "$USE_64"; then + MDCPUCFG_H=_aix64.cfg + OBJECT_MODE=64 + else + MDCPUCFG_H=_aix32.cfg + fi + PR_MD_CSRCS=aix.c + RESOLVE_LINK_SYMBOLS=1 + ;; + +*-beos*) + cat >> confdefs.h <<\EOF +#define XP_BEOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define BeOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define BEOS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + DSO_LDOPTS=-nostart + MDCPUCFG_H=_beos.cfg + USE_BTHREADS=1 + PR_MD_ARCH_DIR=beos + RESOLVE_LINK_SYMBOLS=1 + case "${target_cpu}" in + i*86) + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-gdwarf-2 -O0' + MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' + echo $ac_n "checking for gethostbyaddr in -lbind""... $ac_c" 1>&6 +echo "configure:2998: checking for gethostbyaddr in -lbind" >&5 +ac_lib_var=`echo bind'_'gethostbyaddr | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lbind $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + OS_LIBS="$OS_LIBS -lbind -lsocket" +else + echo "$ac_t""no" 1>&6 +fi + + ;; + powerpc) + CC=mwcc + CCC=mwcc + LD=mwld + DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-g -O0' + ;; + esac + ;; + +*-bsdi*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define BSDI 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEED_BSDREGEX 1 +EOF + + + CFLAGS="$CFLAGS -Wall -Wno-format" + CXXFLAGS="$CXXFLAGS -Wall -Wno-format" + + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + elif echo "$OS_TEST" | grep -c sparc >/dev/null; then + CPU_ARCH=sparc + fi + + MDCPUCFG_H=_bsdi.cfg + PR_MD_CSRCS=bsdi.c + + DSO_LDOPTS=-r + + case "$target_os" in + bsdi1.1*) + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_ARRAY 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ONLY_ST_ATIME 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + MKSHLIB= + DSO_CFLAGS= + DSO_LDOPTS= + ;; + + bsdi2.1*) + cat >> confdefs.h <<\EOF +#define _PR_TIMESPEC_HAS_TS_SEC 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_ARRAY 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + PR_MD_ASFILES=os_BSD_OS_386_2.s + ;; + + bsdi4.* | bsdi5.*) + cat >> confdefs.h <<\EOF +#define _PR_SELECT_CONST_TIMEVAL 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_STRUCT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname,$(@:$(OBJDIR)/%.so=%.so)' + STRIP="$STRIP -d" + case "$target_os" in + bsdi4.2* | bsdi4.3* | bsdi5.*) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R_POINTER 1 +EOF + + ;; + esac + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_SELECT_CONST_TIMEVAL 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_BSDI_JMPBUF_IS_STRUCT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_DLL 1 +EOF + + cat >> confdefs.h <<\EOF +#define USE_DLFCN 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIMESPEC 1 +EOF + + ;; + esac + + ;; + +*-darwin*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define DARWIN 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + CFLAGS="$CFLAGS -Wmost -fno-common" + if echo $OS_TEST | grep -c 86 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + CPU_ARCH=i386 + else + cat >> confdefs.h <<\EOF +#define ppc 1 +EOF + + CPU_ARCH=ppc + fi + DSO_LDOPTS='-dynamiclib -compatibility_version 1 -current_version 1 -all_load -install_name @executable_path/$@ -headerpad_max_install_names' + # Use the standard preprocessor (cpp) + CFLAGS="$CFLAGS -no-cpp-precomp" + MKSHLIB='$(CC) -arch $(CPU_ARCH) $(DSO_LDOPTS) -o $@' + STRIP="$STRIP -x -S" + DLL_SUFFIX=dylib + USE_PTHREADS=1 + MDCPUCFG_H=_darwin.cfg + PR_MD_CSRCS=darwin.c + if test "$CPU_ARCH" = "ppc"; then + PR_MD_ASFILES=os_Darwin_ppc.s + fi + + # Add Mac OS X support for loading CFM & CFBundle plugins + if test -f /System/Library/Frameworks/Carbon.framework/Carbon; then + cat >> confdefs.h <<\EOF +#define XP_MACOSX 1 +EOF + + OS_TARGET=MacOSX + + + MACOS_VERSION_MAJOR=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 1` + MACOS_VERSION_MINOR=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 2` + MACOS_VERSION_MICRO=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 3` + if test -z "$MACOS_VERSION_MINOR"; then + MACOS_VERSION_MINOR=0 + fi + if test -z "$MACOS_VERSION_MICRO"; then + MACOS_VERSION_MICRO=0 + fi + MACOS_DEPLOYMENT_TARGET=`printf "%02d%02d%02d" "$MACOS_VERSION_MAJOR" "$MACOS_VERSION_MINOR" "$MACOS_VERSION_MICRO"` + cat >> confdefs.h <> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define DGUX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _DGUX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX4A_DRAFT6_SOURCE 1 +EOF + + DSO_LDOPTS=-G + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS= + MDCPUCFG_H=_dgux.cfg + PR_MD_CSRCS=dgux.c + ;; + +*-freebsd*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define FREEBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + CFLAGS="$CFLAGS $(DSO_CFLAGS) -ansi -Wall" + MOZ_OBJFORMAT=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + if test "$MOZ_OBJFORMAT" = "elf"; then + DLL_SUFFIX=so + else + DLL_SUFFIX=so.1.0 + fi + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + MDCPUCFG_H=_freebsd.cfg + PR_MD_CSRCS=freebsd.c + ;; + +*-hpux*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _HPUX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define hppa 1 +EOF + + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + cat >> confdefs.h <<\EOF +#define _PR_POLL_WITH_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _USE_BIG_FDS 1 +EOF + + DLL_SUFFIX=sl + DSO_LDOPTS='-b +h $(notdir $@)' + PR_MD_CSRCS=hpux.c + if test "$OS_TEST" != "ia64"; then + PR_MD_ASFILES=os_HPUX.s + fi + if test -n "$USE_64"; then + MDCPUCFG_H=_hpux64.cfg + else + MDCPUCFG_H=_hpux32.cfg + fi + if test -z "$GNU_CC"; then + CC="$CC -Ae" + CXX="$CXX -ext" + DSO_CFLAGS=+Z + else + DSO_CFLAGS=-fPIC + fi + + if test -n "$MOZILLA_CLIENT"; then + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if echo "$OS_RELEASE" | grep ^A.09 >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX9 1 +EOF + + DEFAULT_IMPL_STRATEGY=_EMU + USE_NSPR_THREADS=1 + fi + + if echo "$OS_RELEASE" | egrep '^(A.09|B.10)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_INT_LOCALTIME_R 1 +EOF + + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.30|B.11)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + + # HP-UX 11i (B.11.11) or higher + + case "$OS_RELEASE" in + [C-Z]*|B.[2-9]*|B.1[2-9]*|B.11.[2-9]*|B.11.1[1-9]*) + USE_IPV6=1 + ;; + esac + + + if test "$OS_RELEASE" = "B.10.01"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if test "$OS_RELEASE" = "B.10.10"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_10 1 +EOF + + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.20"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_20 1 +EOF + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.30"; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX10_30 1 +EOF + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if echo "$OS_RELEASE" | grep ^B.11 >/dev/null; then + cat >> confdefs.h <<\EOF +#define HPUX10 1 +EOF + + cat >> confdefs.h <<\EOF +#define HPUX11 1 +EOF + + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + if test -z "$GNU_CC"; then + if test -z "$USE_64"; then + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD32" + CXXFLAGS="$CXXFLAGS +DD32" + else + CFLAGS="$CFLAGS +DAportable +DS2.0" + CXXFLAGS="$CXXFLAGS +DAportable +DS2.0" + fi + else + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD64" + CXXFLAGS="$CXXFLAGS +DD64" + else + CFLAGS="$CFLAGS +DA2.0W +DS2.0" + CXXFLAGS="$CXXFLAGS +DA2.0W +DS2.0" + fi + fi + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$DEFAULT_IMPL_STRATEGY" = "_EMU"; then + USE_NSPR_THREADS=1 + USE_PTHREADS= + USE_USER_THREADS= + elif test "$DEFAULT_IMPL_STRATEGY" = "_PTH"; then + USE_PTHREADS=1 + if test "$USE_NSPR_THREADS"; then + USE_PTHREADS= + fi + if test "$USE_USER_PTHREADS"; then + USE_PTHREADS= + fi + fi + ;; + +*-irix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define IRIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define _SGI_MP_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + PR_MD_CSRCS=irix.c + PR_MD_ASFILES=os_Irix.s + MKSHLIB='$(LD) $(DSO_LDOPTS) -rdata_shared -shared -soname $(notdir $@) -o $@' + STRIP="$STRIP -f" + RESOLVE_LINK_SYMBOLS=1 + if test -n "$USE_64"; then + MDCPUCFG_H=_irix64.cfg + else + MDCPUCFG_H=_irix32.cfg + fi + case "${target_os}" in + irix6*) + cat >> confdefs.h <<\EOF +#define IRIX6 1 +EOF + + USE_PTHREADS=1 + USE_N32=1 + COMPILER_TAG=_n32 + IMPL_STRATEGY=_PTH + ;; + irix5*) + cat >> confdefs.h <<\EOF +#define IRIX5 1 +EOF + + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + USE_N32=1 + ;; + esac + if test "$GNU_CC"; then + AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' + CFLAGS="$CFLAGS -Wall -Wno-format" + _OPTIMIZE_FLAGS="-O6" + else + if test -n "$USE_N32"; then + AS='as -D_ASM $(INCLUDES) -n32' + else + AS='as -D_ASM $(INCLUDES)' + fi + CFLAGS="$CFLAGS -fullwarn -xansi" + if test "$USE_N32"; then + _OPTIMIZE_FLAGS="-O -OPT:Olimit=4000" + else + _OPTIMIZE_FLAGS="-O -Olimit 4000" + fi + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + case "${target}" in + *-irix6.*) + CFLAGS="$CFLAGS -multigot" + DSO_LDOPTS="-no_unresolved" + if test "$USE_N32"; then + CFLAGS="$CFLAGS -n32 -woff 1209" + DSO_LDOPTS="$DSO_LDOPTS -n32" + else + if test "$USE_64"; then + CFLAGS="$CFLAGS -64" + else + CFLAGS="$CFLAGS -32" + fi + fi + ;; + *) + CFLAGS="$CFLAGS -xgot" + ;; + esac + fi + if test "${target_os}" = "irix5.3"; then + cat >> confdefs.h <<\EOF +#define IRIX5_3 1 +EOF + + fi + case "${target_os}" in + irix6.5) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -mips3" + fi + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETPROTO_R_POINTER 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SGI_PRDA_PROCMASK 1 +EOF + + ;; + irix5*) + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SGI_PRDA_PROCMASK 1 +EOF + + ;; + esac + ;; + +*-linux*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + IMPL_STRATEGY=_PTH + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _BSD_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _SVID_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + cat >> confdefs.h <<\EOF +#define LINUX 1 +EOF + + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MDCPUCFG_H=_linux.cfg + PR_MD_CSRCS=linux.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS="-g -fno-inline" # most people on linux use gcc/gdb, and that + # combo is not yet good at debugging inlined + # functions (even when using DWARF2 as the + # debugging format) + COMPILER_TAG=_glibc + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + else + CPU_ARCH=$OS_TEST + fi + CPU_ARCH_TAG=_${CPU_ARCH} + case "${target_cpu}" in + alpha) + cat >> confdefs.h <<\EOF +#define _ALPHA_ 1 +EOF + + cat >> confdefs.h <<\EOF +#define __alpha 1 +EOF + + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + i*86) + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + PR_MD_ASFILES=os_Linux_x86.s + ;; + ia64) + PR_MD_ASFILES=os_Linux_ia64.s + ;; + x86_64) + PR_MD_ASFILES=os_Linux_x86_64.s + ;; + m68k) + CFLAGS="$CFLAGS -m68020-60" + CXXFLAGS="$CXXFLAGS -m68020-60" + ;; + esac + ;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + cat >> confdefs.h <<\EOF +#define XP_PC 1 +EOF + + cat >> confdefs.h <<\EOF +#define WIN32 1 +EOF + + PR_MD_ARCH_DIR=windows + RESOLVE_LINK_SYMBOLS=1 + + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + DLL_SUFFIX=dll + MKSHLIB='$(CC) -shared -Wl,--export-all-symbols -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) $(DLLBASE) -o $(subst $(OBJDIR)/,,$(SHARED_LIBRARY))' + RC=$WINDRES + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + else + CC=cl + CXX=cl + LD=link + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + RC=rc.exe + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_SUFFIX=dll + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | grep Version | sed -e 's|.* Version ||' -e 's| .*||'` + _CC_MAJOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $2 }'` + MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" + DLLFLAGS='-OUT:"$@"' + _DEBUG_FLAGS=-Z7 + _OPTIMIZE_FLAGS=-O2 + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -Od" + fi + + if test -n "$USE_DEBUG_RTL"; then + CFLAGS="$CFLAGS -MDd" + else + CFLAGS="$CFLAGS -MD" + fi + + if test -n "$MOZ_DEBUG"; then + cat >> confdefs.h <<\EOF +#define _DEBUG 1 +EOF + + else + DEFINES="$DEFINES -U_DEBUG" + fi + + if test -n "$MOZ_OPTIMIZE"; then + if test -n "$MOZ_PROFILE"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Z7" + fi + if test -n "$MOZ_DEBUG_SYMBOLS"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Zi" + fi + if test -n "$MOZ_PROFILE" -o -n "$MOZ_DEBUG_SYMBOLS"; then + DLLFLAGS="$DLLFLAGS -DEBUG -OPT:REF" + LDFLAGS="$LDFLAGS -DEBUG -OPT:REF" + fi + fi + + if test -n "$MOZ_DEBUG"; then + DLLFLAGS="$DLLFLAGS -DEBUG -DEBUGTYPE:CV" + LDFLAGS="$LDFLAGS -DEBUG -DEBUGTYPE:CV" + fi + + if test "$OS_TARGET" = "WINNT"; then + CFLAGS="$CFLAGS -GT" + if test "$CPU_ARCH" = "x86"; then + CFLAGS="$CFLAGS -G5" + fi + LIBNSPR='$(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + else + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + fi # GNU_CC + + if test -n "$USE_STATIC_TLS"; then + cat >> confdefs.h <<\EOF +#define _PR_USE_STATIC_TLS 1 +EOF + + fi + + if test "$OS_TARGET" = "WINNT"; then + cat >> confdefs.h <<\EOF +#define WINNT 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define WIN95 1 +EOF + + # undefine WINNT as some versions of mingw gcc define it by default + DEFINES="$DEFINES -UWINNT" + cat >> confdefs.h <<\EOF +#define _PR_GLOBAL_THREADS_ONLY 1 +EOF + + fi + + if test "$CPU_ARCH" = "x86"; then + CPU_ARCH_TAG= + else + CPU_ARCH_TAG=$CPU_ARCH + fi + + if test -n "$USE_DEBUG_RTL"; then + OBJDIR_SUFFIX=OBJD + fi + + OS_DLLFLAGS="-nologo -DLL -SUBSYSTEM:WINDOWS" + if test "$MSC_VER" = "1200" -a -z "$MOZ_DEBUG_SYMBOLS"; then + OS_DLLFLAGS="$OS_DLLFLAGS -PDB:NONE" + fi + + case "$OS_TARGET" in + WINNT) + MDCPUCFG_H=_winnt.cfg + ;; + WIN95) + MDCPUCFG_H=_win95.cfg + ;; + WIN16) + MDCPUCFG_H=_win16.cfg + ;; + *) + { echo "configure: error: Missing OS_TARGET for ${target}. Use --enable-win32-target to set." 1>&2; exit 1; } + ;; + esac + + case "$target_cpu" in + i*86) + cat >> confdefs.h <<\EOF +#define _X86_ 1 +EOF + + ;; + alpha) + cat >> confdefs.h <<\EOF +#define _ALPHA_ 1 +EOF + + ;; + mips) + cat >> confdefs.h <<\EOF +#define _MIPS_ 1 +EOF + + ;; + *) + cat >> confdefs.h <<\EOF +#define _CPU_ARCH_NOT_DEFINED 1 +EOF + + ;; + esac + + ;; + +*-ncr-sysv*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define NCR 1 +EOF + + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "2.03"; then + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIM 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define _PR_STAT_HAS_ST_ATIM_UNION 1 +EOF + + fi + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -Hnocopyr" + CXXFLAGS="$CXXFLAGS -Hnocopyr" + else + CFLAGS="$CFLAGS -fPIC -Wall" + CXXFLAGS="$CXXFLAGS -fPIC -Wall" + DSO_LDOPTS=-G + fi + MDCPUCFG_H=_ncr.cfg + PR_MD_CSRCS=ncr.c + ;; + +mips-nec-sysv*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEC 1 +EOF + + cat >> confdefs.h <<\EOF +#define nec_ews 1 +EOF + + USE_NSPR_THREADS=1 + if test -z "$GNU_CC"; then + CC='$(NSDEPTH)/build/hcc cc -Xa -KGnum=0 -KOlimit=4000' + CXX=g++ + fi + OS_LIBS="$OS_LIBS -lsocket -lnsl -ldl" + DSO_LDOPTS=-G + MDCPUCFG_H=_nec.cfg + PR_MD_CSRCS=nec.c + ;; + +*-netbsd*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NETBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + USE_NSPR_THREADS=1 + MDCPUCFG_H=_netbsd.cfg + PR_MD_CSRCS=netbsd.c + + DSO_CFLAGS='-fPIC -DPIC' + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + + if test -z "$OBJECT_FMT"; then + if echo __ELF__ | ${CC-cc} -E - | grep -q __ELF__ 2>/dev/null; then + OBJECT_FMT=a.out + DLL_SUFFIX=so.1.0 + DSO_LDOPTS='-shared' + else + OBJECT_FMT=ELF + DLL_SUFFIX=so + DSO_LDOPTS='-shared -Wl,-soname,$(notdir $@)' + fi + fi + + if test "$LIBRUNPATH"; then + DSO_LDOPTS="$DSO_LDOPTS -Wl,-R$LIBRUNPATH" + fi + ;; + +mips-sony-newsos*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SONY 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SVID_GETTOD 1 +EOF + + USE_NSPR_THREADS=1 + CFLAGS="$CFLAGS -Xa -fullwarn" + CXXFLAGS="$CXXFLAGS -Xa -fullwarn" + DSO_LDOPTS=-G + MDCPUCFG_H=_sony.cfg + PR_MD_CSRCS=sony.c + ;; + +*-nextstep*|*-openstep*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NEXTSTEP 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + CFLAGS="$CFLAGS -Wall -fno-common -traditional-cpp -posix" + CXXFLAGS="$CXXFLAGS -Wall -fno-common -traditional-cpp -posix" + USE_NSPR_THREADS=1 + DLL_SUFFIX=dylib + MDCPUCFG_H=_nextstep.cfg + PR_MD_CSRCS=nextstep.c + ;; + + +*-nto*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define NTO 1 +EOF + + cat >> confdefs.h <<\EOF +#define _QNX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + MDCPUCFG_H=_nto.cfg + PR_MD_CSRCS=nto.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -Wl,-soname -Wl,$(notdir $@) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS=-shared + OS_LIBS="$OS_LIBS -lsocket" + _OPTIMIZE_FLAGS="-O1" + _DEBUG_FLAGS="-gstabs" + ;; + +*-openbsd*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OPENBSD 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_BSD_FLOCK 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + DLL_SUFFIX=so.1.0 + DSO_CFLAGS=-fPIC + MDCPUCFG_H=_openbsd.cfg + PR_MD_CSRCS=openbsd.c + USE_NSPR_THREADS=1 + DSO_LDOPTS='-shared -fPIC' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + ;; + +*-openvms*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define VMS 1 +EOF + + cat >> confdefs.h <<\EOF +#define PR_GETIPNODE_NOT_THREADSAFE 1 +EOF + + RESOLVE_LINK_SYMBOLS=1 + AR_FLAGS='c $@' + MDCPUCFG_H=_openvms.cfg + PR_MD_CSRCS=openvms.c + DSO_LDOPTS='-shared -auto_symvec $(LDFLAGS)' + if test -n "$MOZ_DEBUG"; then + DSO_LDOPTS="$DSO_LDOPTS $_DEBUG_FLAGS" + else + DSO_LDOPTS="$DSO_LDOPTS $_OPTIMIZE_FLAGS" + fi + ;; + +*-osf*) + SHELL_OVERRIDE="SHELL = /usr/bin/ksh" + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OSF1 1 +EOF + + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + cat >> confdefs.h <<\EOF +#define _PR_POLL_WITH_SELECT 1 +EOF + + + if echo "$OS_RELEASE" | egrep -c '(V2.0|V3.2)' 2>/dev/null ; then + USE_NSPR_THREADS=1 + fi + + if test -z "$GNU_CC"; then + CC="$CC -std1 -ieee_with_inexact" + if test "$OS_RELEASE" != "V2.0"; then + CC="$CC -readonly_strings" + fi + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Olimit 4000" + ac_safe=`echo "machine/builtins.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for machine/builtins.h""... $ac_c" 1>&6 +echo "configure:4220: checking for machine/builtins.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4230: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define OSF1_HAVE_MACHINE_BUILTINS_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + + else + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + fi + + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define HAVE_INT_LOCALTIME_R 1 +EOF + + else + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if echo $OS_RELEASE | grep -c V4.0 >/dev/null; then + cat >> confdefs.h <<\EOF +#define OSF1V4_MAP_PRIVATE_BUG 1 +EOF + + fi + DSO_LDOPTS='-shared -all -expect_unresolved "*" -soname $(notdir $@)' + MDCPUCFG_H=_osf1.cfg + PR_MD_CSRCS=osf1.c + ;; + +*-qnx*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define QNX 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + USE_NSPR_THREADS=1 + MDCPUCFG_H=_qnx.cfg + PR_MD_CSRCS=qnx.c + ;; + +*-*-sco*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SCO 1 +EOF + + cat >> confdefs.h <<\EOF +#define sco 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define _SVID3 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_NEED_H_ERRNO 1 +EOF + + CC='cc -b elf -KPIC' + CXX='$(NSDEPTH)/build/hcpp CC +.cpp +w' + USE_NSPR_THREADS=1 + CPU_ARCH=x86 + DSO_LDOPTS='-b elf -G' + MDCPUCFG_H=_scoos.cfg + PR_MD_SRCS=scoos.c + ;; + +*-sinix*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SNI 1 +EOF + + cat >> confdefs.h <<\EOF +#define RELIANTUNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define sinix 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_SVID_GETTOD 1 +EOF + + if echo "$OS_TEST" | grep -c 86 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + CPU_ARCH=x86 + else + CPU_ARCH=mips + fi + + if test "$GNU_CC"; then + AS='$(CC) -x assembler-with-cpp' + if test "$CPU_ARCH" = "mips"; then + LD=gld + fi + CFLAGS="$CFLAGS -Wall -Wno-format" + else + AS='/usr/bin/cc' + _OPTIMIZE_FLAGS='-O -F Olimit,4000' + fi + + DSO_LDOPTS='-G -z defs -h $(@:$(OBJDIR)/%.so=%.so)' + + if test "$OS_RELEASE" = "5.43"; then + cat >> confdefs.h <<\EOF +#define IP_MULTICAST 1 +EOF + + fi + + OS_LIBS="$OS_LIBS -lsocket -lnsl -lresolv -ldl -lc" + USE_NSPR_THREADS=1 + MDCPUCFG_H=_reliantunix.cfg + PR_MD_CSRCS=reliantunix.c + if test "${OS_ARCH}" = "mips"; then + PR_MD_ASFILES=os_ReliantUNIX.s + fi + ;; + +*-sunos*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SUNOS4 1 +EOF + + CFLAGS="$CFLAGS -Wall -Wno-format" + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + CPU_ARCH=sparc + DLL_SUFFIX=so.1.0 + DSO_LDOPTS= + DSO_CFLAGS=-fPIC + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "4.1.3_U1"; then + _OPTIMIZE_FLAGS= + OS_LIBS="$OS_LIBS -lm" + fi + MDCPUCFG_H=_sunos4.cfg + PR_MD_CSRCS=sunos4.c + ;; + +*-solaris*) + if test -z "$USE_USER_THREADS" && test -z "$USE_NATIVE_THREADS"; then + USE_PTHREADS=1 + fi + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4 1 +EOF + + cat >> confdefs.h <<\EOF +#define __svr4__ 1 +EOF + + cat >> confdefs.h <<\EOF +#define SOLARIS 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_FCNTL_FILE_LOCKING 1 +EOF + + if test -n "$USE_64"; then + MDCPUCFG_H=_solaris64.cfg + else + MDCPUCFG_H=_solaris32.cfg + fi + PR_MD_CSRCS=solaris.c + LD=/usr/ccs/bin/ld + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RESOLVE_LINK_SYMBOLS=1 + if test -n "$GNU_CC"; then + DSO_CFLAGS=-fPIC + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi + DSO_LDOPTS='-shared -Wl,-h,$(notdir $@),-z,combreloc,-z,defs' + else + DSO_CFLAGS=-KPIC + DSO_LDOPTS='-G -h $(notdir $@) -z combreloc -z defs' + fi + if test -z "$GNU_AS"; then + ASFLAGS="$ASFLAGS -Wa,-P" + fi + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + if test -n "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + CXXFLAGS="$CXXFLAGS -MDupdate \$(DEPENDENCIES)" + fi + else + CFLAGS="$CFLAGS -xstrconst" + CXXFLAGS="$CXXFLAGS -Qoption cg -xstrconst -features=tmplife" + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -xs" + CXXFLAGS="$CXXFLAGS -xs" + fi + _OPTIMIZE_FLAGS=-xO4 + fi + if test -n "$USE_64"; then + if test -n "$GNU_CC"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + CC="$CC -xarch=v9" + CXX="$CXX -xarch=v9" + fi + fi + if test "$OS_TEST" = "i86pc"; then + cat >> confdefs.h <<\EOF +#define i386 1 +EOF + + CPU_ARCH_TAG=_$OS_TEST + # The default debug format, DWARF (-g), is not supported by gcc + # on i386-ANY-sysv4/solaris, but the stabs format is. It is + # assumed that the Solaris assembler /usr/ccs/bin/as is used. + # If your gcc uses GNU as, you do not need the -Wa,-s option. + if test -n "$MOZ_DEBUG" && test -n "$GNU_CC"; then + _DEBUG_FLAGS=-gstabs + if test -z "$GNU_AS"; then + _DEBUG_FLAGS="$_DEBUG_FLAGS -Wa,-s" + fi + fi + fi + case "${target_os}" in + solaris2.3*) + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + ;; + solaris2.4*) + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + ;; + solaris2.5*) + cat >> confdefs.h <<\EOF +#define SOLARIS2_5 1 +EOF + + ;; + *) + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + # The lfcompile64(5) man page on Solaris 2.6 says: + # For applications that do not wish to conform to the POSIX or + # X/Open specifications, the 64-bit transitional interfaces + # are available by default. No compile-time flags need to be + # set. + # But gcc 2.7.2.x fails to define _LARGEFILE64_SOURCE by default. + # The native compiler, gcc 2.8.x, and egcs don't have this problem. + if test -n "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + fi + ;; + esac + case "${target_os}" in + solaris2.3*) + ;; + solaris2.4*) + ;; + solaris2.5*) + ;; + solaris2.6*) + ;; + solaris2.7*) + ;; + *) + # Solaris 8 or higher has IPv6. + cat >> confdefs.h <<\EOF +#define _PR_INET6 1 +EOF + + ;; + esac + if test "$OS_TEST" = "sun4u"; then + # 64-bit Solaris requires SPARC V9 architecture, so the following + # is not needed. + if test -z "$USE_64"; then + ULTRASPARC_LIBRARY=nspr_flt + fi + fi + # Purify requires that binaries linked against nspr also + # be linked against -lrt (or -lposix4) so add it to OS_LIBS + _rev=`uname -r` + _librt=`echo $_rev 5.6 | awk '{ if ($1 > $2) print "-lrt"; else print "-lposix4" }'` + OS_LIBS="$OS_LIBS $_librt" + ;; + +*-sco-sysv5*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + cat >> confdefs.h <<\EOF +#define UNIXWARE 1 +EOF + + cat >> confdefs.h <<\EOF +#define SVR4 1 +EOF + + cat >> confdefs.h <<\EOF +#define SYSV 1 +EOF + + USE_NSPR_THREADS=1 + if echo $OS_RELEASE | grep -c 2.1 2>/dev/null; then + cat >> confdefs.h <<\EOF +#define _PR_NO_LARGE_FILES 1 +EOF + + CC='$(NSDEPTH)/build/hcc cc' + CXX='$(NSDEPTH)/build/hcpp CC' + MDCPUCFG_H=_unixware.cfg + else + cat >> confdefs.h <<\EOF +#define _LARGEFILE64_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_OFF64_T 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_SOCKADDR_LEN 1 +EOF + + MDCPUCFG_H=_unixware7.cfg + fi + PR_MD_CSRCS=unixware.c + DSO_LDOPTS=-G + CPU_ARCH=x86 + ;; + +*-os2*) + cat >> confdefs.h <<\EOF +#define XP_OS2 1 +EOF + + cat >> confdefs.h <<\EOF +#define XP_PC 1 +EOF + + cat >> confdefs.h <<\EOF +#define BSD_SELECT 1 +EOF + + cat >> confdefs.h <<\EOF +#define TCPV40HDRS 1 +EOF + + LIB_SUFFIX=lib + DLL_SUFFIX=dll + RC=rc.exe + PR_MD_ARCH_DIR=os2 + PROG_SUFFIX=.exe + NSINSTALL=nsinstall + MDCPUCFG_H=_os2.cfg + RESOLVE_LINK_SYMBOLS=1 + + # EMX/GCC build + if test -n "$GNU_CC"; then + cat >> confdefs.h <<\EOF +#define XP_OS2_EMX 1 +EOF + + cat >> confdefs.h <<\EOF +#define OS2 1 +EOF + + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Wall -Zomf" + CXXFLAGS="$CFLAGS -Wall -Zomf" + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS= + DSO_LDOPTS='-Zomf -Zdll -Zmap' + LDFLAGS='-Zmap' + _OPTIMIZE_FLAGS="-O2 -s" + _DEBUG_FLAGS="-g -fno-inline" + if test -n "$MOZ_OPTIMIZE"; then + DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + fi + OS_LIBS="-lsocket" + IMPLIB='emximp -o' + FILTER='emxexp -o' + + # GCC for OS/2 currently predefines these, but we don't want them + DEFINES="$DEFINES -Uunix -U__unix -U__unix__" + + # Visual Age C++ build + elif test "$VACPP" = "yes"; then + cat >> confdefs.h <<\EOF +#define XP_OS2_VACPP 1 +EOF + + cat >> confdefs.h <<\EOF +#define OS2 4 +EOF + + cat >> confdefs.h <<\EOF +#define _X86_ 1 +EOF + + OBJ_SUFFIX=obj + AS=alp + ASFLAGS='-Mb' + ASM_SUFFIX=asm + AR=-ilib + AR_FLAGS='/NOL /NOI /O:$(subst /,\\,$@)' + CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + HOST_CFLAGS="$CFLAGS" + OS_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_EXE_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + CXXFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_LIBS='so32dll.lib tcp32dll.lib' + LD='-ilink' + MKSHLIB='$(LD) $(DSO_LDOPTS)' + IMPLIB='implib -nologo -noignorecase' + FILTER='cppfilt -q -B -P' + _OPTIMIZE_FLAGS='/O+ /Gl+ /qtune=pentium /qarch=pentium' + _DEBUG_FLAGS='/Ti+ ' + LDFLAGS='/NOL /M /L' + DLLFLAGS='/O:$@ /DLL /INC:_dllentry /MAP:$(@:.dll=.map) /L /NOL' + EXEFLAGS='/OUT:$@ /PMTYPE:VIO /MAP:$(@:.exe=.map) /L /NOL' + if test -n "$MOZ_DEBUG"; then + LDFLAGS="$LDFLAGS /DE" + DLLFLAGS="$DLLFLAGS /DE" + EXEFLAGS="$EXEFLAGS /DE" + fi + if test -n "$MOZ_OPTIMIZE"; then + LDFLAGS="$LDFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + DLLFLAGS="$DLLFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + EXEFLAGS="$EXEFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + fi + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + ;; + +*) + cat >> confdefs.h <<\EOF +#define XP_UNIX 1 +EOF + + ;; + +esac + +if test -z "$SKIP_LIBRARY_CHECKS"; then + + + +case $target in +*-darwin*) + ;; +*) + echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "configure:4765: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_safe=`echo "dlfcn.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for dlfcn.h""... $ac_c" 1>&6 +echo "configure:4801: checking for dlfcn.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4811: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + OS_LIBS="-ldl $OS_LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +else + echo "$ac_t""no" 1>&6 +fi + + ;; +esac + + + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:4844: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +for ac_func in lchown strerror +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:4892: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:4920: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + + + +# Check whether --enable-strip or --disable-strip was given. +if test "${enable_strip+set}" = set; then + enableval="$enable_strip" + if test "$enableval" = "yes"; then + ENABLE_STRIP=1 + fi +fi + + +case "${target_os}" in +hpux*) +if test -z "$GNU_CC"; then + + echo $ac_n "checking for +Olit support""... $ac_c" 1>&6 +echo "configure:4961: checking for +Olit support" >&5 +if eval "test \"`echo '$''{'ac_cv_hpux_usable_olit_option'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_hpux_usable_olit_option=no + rm -f conftest* + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} ${CFLAGS} +Olit=all -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out`"; then + ac_cv_hpux_usable_olit_option=yes + fi + fi + rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_hpux_usable_olit_option" 1>&6 + + if test "$ac_cv_hpux_usable_olit_option" = "yes"; then + CFLAGS="$CFLAGS +Olit=all" + CXXFLAGS="$CXXFLAGS +Olit=all" + else + CFLAGS="$CFLAGS +ESlit" + CXXFLAGS="$CXXFLAGS +ESlit" + fi +fi +;; +esac + + + + +echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6 +echo "configure:4995: checking for pthread_create in -lpthreads" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthreads $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 +echo "configure:5017: checking for pthread_create in -lpthread" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lpthread $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6 +echo "configure:5039: checking for pthread_create in -lc_r" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc_r $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r" + else + echo "$ac_t""no" 1>&6 + +echo $ac_n "checking for pthread_create in -lc""... $ac_c" 1>&6 +echo "configure:5061: checking for pthread_create in -lc" >&5 +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -lc $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + echo "$ac_t""yes" 1>&6 + _HAVE_PTHREADS=1 + + else + echo "$ac_t""no" 1>&6 + + fi + + + fi + + + fi + + + fi + + +# Check whether --with-pthreads or --without-pthreads was given. +if test "${with_pthreads+set}" = set; then + withval="$with_pthreads" + if test "$withval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + else + { echo "configure: error: --with-pthreads specified for a system without pthread support " 1>&2; exit 1; }; + fi + else + USE_PTHREADS= + _PTHREAD_LDFLAGS= + fi +else + if test -n "$_HAVE_PTHREADS" && test -z "$USE_USER_PTHREADS" && test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + fi +fi + + +# Check whether --enable-user-pthreads or --disable-user-pthreads was given. +if test "${enable_user_pthreads+set}" = set; then + enableval="$enable_user_pthreads" + if test "$enableval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS= + USE_USER_PTHREADS=1 + USE_NSPR_THREADS= + else + { echo "configure: error: --enable-user-pthreads specified for a system without pthread support " 1>&2; exit 1; }; + fi + fi +fi + + +# Check whether --enable-nspr-threads or --disable-nspr-threads was given. +if test "${enable_nspr_threads+set}" = set; then + enableval="$enable_nspr_threads" + if test "$enableval" = "yes"; then + USE_PTHREADS= + USE_USER_PTHREADS= + USE_NSPR_THREADS=1 + fi +fi + + +case "$target" in +*-beos*) + # Check whether --with-bthreads or --without-bthreads was given. +if test "${with_bthreads+set}" = set; then + withval="$with_bthreads" + if test "$withval" = "yes"; then + USE_BTHREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi +fi + + ;; + +*-solaris*) + # Check whether --with-native-threads or --without-native-threads was given. +if test "${with_native_threads+set}" = set; then + withval="$with_native_threads" + if test "$withval" = "yes"; then + USE_NATIVE_THREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi +fi + + ;; +esac + +fi # SKIP_LIBRARY_CHECKS + +# Check whether --enable-cplus or --disable-cplus was given. +if test "${enable_cplus+set}" = set; then + enableval="$enable_cplus" + if test "$enableval" = "yes"; then + USE_CPLUS=1 + fi +fi + + +# Check whether --enable-ipv6 or --disable-ipv6 was given. +if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + if test "$enableval" = "yes"; then + USE_IPV6=1 + else + USE_IPV6= + fi +fi + + + +# Check whether --enable-boehm or --disable-boehm was given. +if test "${enable_boehm+set}" = set; then + enableval="$enable_boehm" + if test "$enableval" = "yes"; then + cat >> confdefs.h <<\EOF +#define GC_LEAK_DETECTOR 1 +EOF + + GC_LEAK_DETECTOR=1 + fi +fi + + +if test -n "$USE_PTHREADS"; then + rm -f conftest* + ac_cv_have_dash_pthread=no + echo $ac_n "checking whether ${CC-cc} accepts -pthread""... $ac_c" 1>&6 +echo "configure:5213: checking whether ${CC-cc} accepts -pthread" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthread" 1>&6 + + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + echo $ac_n "checking whether ${CC-cc} accepts -pthreads""... $ac_c" 1>&6 +echo "configure:5236: checking whether ${CC-cc} accepts -pthreads" >&5 + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + echo "$ac_t""$ac_cv_have_dash_pthreads" 1>&6 + fi + + case "$target" in + *-solaris*) + if test "$ac_cv_have_dash_pthreads" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-freebsd*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + *-netbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + *-bsdi*) + cat >> confdefs.h <<\EOF +#define _THREAD_SAFE 1 +EOF + + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-openbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS=-pthread + fi + ;; + *-linux*) + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + ;; + esac + +else + if test -n "$USE_USER_PTHREADS"; then + USE_PTHREADS= + USE_NSPR_THREADS= + else + _PTHREAD_LDFLAGS= + fi +fi + +case "$target" in +*-aix*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + case "$target_os" in + aix4.1*) + if test -z "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define AIX_RENAME_SELECT 1 +EOF + + fi + ;; + aix4.2*) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + ;; + aix4.3*) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + ;; + *) + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + ;; + esac + ;; +*-bsdi*) + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_NEED_PTHREAD_INIT 1 +EOF + + fi + ;; +*-freebsd*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-hpux*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + if test "$USE_PTHREADS"; then + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_DCETHREADS 1 +EOF + + else + cat >> confdefs.h <> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + fi + if test "$USE_USER_PTHREADS"; then + cat >> confdefs.h <> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R_POINTER 1 +EOF + + fi + fi + ;; +*-linux*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + USE_PTHREADS= + _PTHREAD_LDFLAGS= + USE_USER_PTHREADS= + ;; +*-netbsd*|*-openbsd*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + ;; +*-osf*) + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + if test -n "$USE_PTHREADS"; then + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + : + else + cat >> confdefs.h <<\EOF +#define _PR_HAVE_THREADSAFE_GETHOST 1 +EOF + + fi + fi + ;; +*-solaris*) + if test -n "$USE_NATIVE_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_GLOBAL_THREADS_ONLY 1 +EOF + + else + if test -n "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_LOCAL_THREADS_ONLY 1 +EOF + + fi + fi + if test -z "$USE_NSPR_THREADS"; then + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_POINTER_LOCALTIME_R 1 +EOF + + if test "$OS_TEST" = "i86pc"; then + PR_MD_ASFILES=os_SunOS_x86.s + else + PR_MD_ASFILES=os_SunOS.s + if test -n "$USE_64"; then + PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_sparcv9.s" + fi + fi + fi + ;; +*-nto*) + if test -n "$USE_PTHREADS"; then + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R 1 +EOF + + cat >> confdefs.h <<\EOF +#define _PR_HAVE_GETHOST_R_POINTER 1 +EOF + + fi + ;; +esac + +OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS" + +if test -n "$_SAVE_OPTIMIZE_FLAGS"; then + _OPTIMIZE_FLAGS="$_SAVE_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS $_OPTIMIZE_FLAGS" + CXXFLAGS="$CXXFLAGS $_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_DEBUG"; then + CFLAGS="$CFLAGS $_DEBUG_FLAGS" + CXXFLAGS="$CXXFLAGS $_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + OBJDIR_TAG=_OPT +else + OBJDIR_TAG=_DBG +fi + +if test -n "$USE_64"; then + COMPILER_TAG=_64 +fi + +RELEASE_OBJDIR_NAME="${OS_CONFIG}${CPU_ARCH_TAG}${COMPILER_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}.${OBJDIR_SUFFIX}" + +case "$target_os" in +mingw*|cygwin*|msvc*|mks*) + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + RC="\$(CYGWIN_WRAPPER) $RC" + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MAKEFILES=" +Makefile +config/Makefile +config/autoconf.mk +config/nsprincl.mk +config/nsprincl.sh +config/nspr-config +lib/Makefile +lib/ds/Makefile +lib/libc/Makefile +lib/libc/include/Makefile +lib/libc/src/Makefile +lib/tests/Makefile +pkg/Makefile +pkg/linux/Makefile +pkg/solaris/Makefile +pkg/solaris/SUNWpr/Makefile +pkg/solaris/SUNWprx/Makefile +pr/Makefile +pr/include/Makefile +pr/include/md/Makefile +pr/include/obsolete/Makefile +pr/include/private/Makefile +pr/src/Makefile +pr/src/io/Makefile +pr/src/linking/Makefile +pr/src/malloc/Makefile +pr/src/md/Makefile +pr/src/md/${PR_MD_ARCH_DIR}/Makefile +pr/src/memory/Makefile +pr/src/misc/Makefile +pr/src/threads/Makefile +pr/tests/Makefile +pr/tests/dll/Makefile +" + + +if test -z "$USE_PTHREADS" && test -z "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/threads/combined/Makefile" +elif test -n "$USE_PTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/pthreads/Makefile" +elif test -n "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/bthreads/Makefile" +fi + +if test -n "$USE_CPLUS"; then + MAKEFILES="$MAKEFILES pr/src/cplus/Makefile pr/src/cplus/tests/Makefile" +fi + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "$MAKEFILES" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@dist_prefix@%$dist_prefix%g +s%@dist_bindir@%$dist_bindir%g +s%@dist_includedir@%$dist_includedir%g +s%@dist_libdir@%$dist_libdir%g +s%@WHOAMI@%$WHOAMI%g +s%@HOST_CC@%$HOST_CC%g +s%@CXX@%$CXX%g +s%@RANLIB@%$RANLIB%g +s%@AR@%$AR%g +s%@AS@%$AS%g +s%@LD@%$LD%g +s%@STRIP@%$STRIP%g +s%@WINDRES@%$WINDRES%g +s%@CPP@%$CPP%g +s%@PERL@%$PERL%g +s%@SHELL_OVERRIDE@%$SHELL_OVERRIDE%g +s%@MOZILLA_CLIENT@%$MOZILLA_CLIENT%g +s%@HOST_CFLAGS@%$HOST_CFLAGS%g +s%@GNU_CC@%$GNU_CC%g +s%@GCC_USE_GNU_LD@%$GCC_USE_GNU_LD%g +s%@MSC_VER@%$MSC_VER%g +s%@CROSS_COMPILE@%$CROSS_COMPILE%g +s%@MOZ_OPTIMIZE@%$MOZ_OPTIMIZE%g +s%@USE_CPLUS@%$USE_CPLUS%g +s%@USE_IPV6@%$USE_IPV6%g +s%@USE_N32@%$USE_N32%g +s%@USE_64@%$USE_64%g +s%@OBJECT_MODE@%$OBJECT_MODE%g +s%@GC_LEAK_DETECTOR@%$GC_LEAK_DETECTOR%g +s%@ENABLE_STRIP@%$ENABLE_STRIP%g +s%@USE_PTHREADS@%$USE_PTHREADS%g +s%@USE_BTHREADS@%$USE_BTHREADS%g +s%@USE_USER_PTHREADS@%$USE_USER_PTHREADS%g +s%@USE_NATIVE_THREADS@%$USE_NATIVE_THREADS%g +s%@USE_NSPR_THREADS@%$USE_NSPR_THREADS%g +s%@LIBNSPR@%$LIBNSPR%g +s%@LIBPLC@%$LIBPLC%g +s%@MOD_MAJOR_VERSION@%$MOD_MAJOR_VERSION%g +s%@MOD_MINOR_VERSION@%$MOD_MINOR_VERSION%g +s%@MOD_PATCH_VERSION@%$MOD_PATCH_VERSION%g +s%@NSPR_MODNAME@%$NSPR_MODNAME%g +s%@MDCPUCFG_H@%$MDCPUCFG_H%g +s%@PR_MD_CSRCS@%$PR_MD_CSRCS%g +s%@PR_MD_ASFILES@%$PR_MD_ASFILES%g +s%@PR_MD_ARCH_DIR@%$PR_MD_ARCH_DIR%g +s%@CPU_ARCH@%$CPU_ARCH%g +s%@OBJ_SUFFIX@%$OBJ_SUFFIX%g +s%@LIB_SUFFIX@%$LIB_SUFFIX%g +s%@DLL_SUFFIX@%$DLL_SUFFIX%g +s%@ASM_SUFFIX@%$ASM_SUFFIX%g +s%@MKSHLIB@%$MKSHLIB%g +s%@DSO_CFLAGS@%$DSO_CFLAGS%g +s%@DSO_LDOPTS@%$DSO_LDOPTS%g +s%@OS_TARGET@%$OS_TARGET%g +s%@OS_ARCH@%$OS_ARCH%g +s%@OS_RELEASE@%$OS_RELEASE%g +s%@OS_TEST@%$OS_TEST%g +s%@MACOS_DEPLOYMENT_TARGET@%$MACOS_DEPLOYMENT_TARGET%g +s%@DEFINES@%$DEFINES%g +s%@AR_FLAGS@%$AR_FLAGS%g +s%@ASFLAGS@%$ASFLAGS%g +s%@FILTER@%$FILTER%g +s%@IMPLIB@%$IMPLIB%g +s%@OS_LIBS@%$OS_LIBS%g +s%@RESOLVE_LINK_SYMBOLS@%$RESOLVE_LINK_SYMBOLS%g +s%@AIX_LINK_OPTS@%$AIX_LINK_OPTS%g +s%@NOSUCHFILE@%$NOSUCHFILE%g +s%@MOZ_OBJFORMAT@%$MOZ_OBJFORMAT%g +s%@ULTRASPARC_LIBRARY@%$ULTRASPARC_LIBRARY%g +s%@OBJDIR@%$OBJDIR%g +s%@OBJDIR_NAME@%$OBJDIR_NAME%g +s%@RELEASE_OBJDIR_NAME@%$RELEASE_OBJDIR_NAME%g +s%@NSINSTALL@%$NSINSTALL%g +s%@OPTIMIZER@%$OPTIMIZER%g +s%@RC@%$RC%g +s%@RCFLAGS@%$RCFLAGS%g +s%@DLLFLAGS@%$DLLFLAGS%g +s%@EXEFLAGS@%$EXEFLAGS%g +s%@OS_DLLFLAGS@%$OS_DLLFLAGS%g +s%@CYGWIN_WRAPPER@%$CYGWIN_WRAPPER%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +chmod +x config/nspr-config +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/src/libs/xpcom18a4/nsprpub/configure.in b/src/libs/xpcom18a4/nsprpub/configure.in new file mode 100644 index 00000000..a9ef3c2b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/configure.in @@ -0,0 +1,2556 @@ +dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*- +dnl +dnl The contents of this file are subject to the Mozilla Public +dnl License Version 1.1 (the "License"); you may not use this file +dnl except in compliance with the License. You may obtain a copy of +dnl the License at http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS +dnl IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +dnl implied. See the License for the specific language governing +dnl rights and limitations under the License. +dnl +dnl The Original Code is the Netscape Portable Runtime (NSPR). +dnl +dnl The Initial Developer of the Original Code is Netscape +dnl Communications Corporation. Portions created by Netscape are +dnl Copyright (C) 1998o-2000 Netscape Communications Corporation. All +dnl Rights Reserved. +dnl +dnl Contributor(s): +dnl Christopher Seawood +dnl +dnl Alternatively, the contents of this file may be used under the +dnl terms of the GNU General Public License Version 2 or later (the +dnl "GPL"), in which case the provisions of the GPL are applicable +dnl instead of those above. If you wish to allow use of your +dnl version of this file only under the terms of the GPL and not to +dnl allow others to use your version of this file under the MPL, +dnl indicate your decision by deleting the provisions above and +dnl replace them with the notice and other provisions required by +dnl the GPL. If you do not delete the provisions above, a recipient +dnl may use your version of this file under either the MPL or the +dnl GPL. +dnl + +AC_PREREQ(2.12) +AC_INIT(config/libc_r.h) + +AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf) +AC_CANONICAL_SYSTEM + +dnl ======================================================== +dnl = Defaults +dnl ======================================================== +MOD_MAJOR_VERSION=4 +MOD_MINOR_VERSION=5 +MOD_PATCH_VERSION=0 +NSPR_MODNAME=nspr20 +_HAVE_PTHREADS= +USE_PTHREADS= +USE_USER_PTHREADS= +USE_NSPR_THREADS= +USE_N32= +USE_64= +USE_CPLUS= +USE_IPV6= +USE_MDUPDATE= +MACOS_DEPLOYMENT_TARGET= +_OPTIMIZE_FLAGS=-O +_DEBUG_FLAGS=-g +MOZ_DEBUG=1 +MOZ_OPTIMIZE= +OBJDIR=. +OBJDIR_NAME=. +OBJDIR_SUFFIX=OBJ +NSINSTALL='$(MOD_DEPTH)/config/$(OBJDIR_NAME)/nsinstall' +NOSUCHFILE=/no-such-file +LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)' +LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)' +CYGWIN_WRAPPER= + +dnl Link in libraries necessary to resolve all symbols for shared libs +RESOLVE_LINK_SYMBOLS= + +dnl ======================================================== +dnl = +dnl = Dont change the following lines. Doing so breaks: +dnl = +dnl = CFLAGS="-foo" ./configure +dnl = +dnl ======================================================== +CFLAGS="${CFLAGS=}" +CXXFLAGS="${CXXFLAGS=}" +LDFLAGS="${LDFLAGS=}" +HOST_CFLAGS="${HOST_CFLAGS=}" +HOST_LDFLAGS="${HOST_LDFLAGS=}" + +case "$target" in +*-cygwin*|*-mingw*) + # Check to see if we are really running in a msvc environemnt + _WIN32_MSVC= + AC_CHECK_PROGS(CC, cl) + if test "$CC" = "cl"; then + echo 'main() { return 0; }' > dummy.c + ${CC} -o dummy dummy.c >/dev/null 2>&1 + if test $? = 0; then + _WIN32_MSVC=1 + CXX=$CC + else + AC_MSG_WARN([$(CC) test failed. Using normal feature tests]) + fi + rm -f dummy dummy.o dummy.obj dummy.exe dummy.c + fi + ;; +*-msvc*) + _WIN32_MSVC=1 + ;; +*-mks*) + _WIN32_MSVC=1 + ;; +esac + +if test -n "$_WIN32_MSVC"; then + SKIP_PATH_CHECKS=1 + SKIP_COMPILER_CHECKS=1 + SKIP_LIBRARY_CHECKS=1 +fi + +dnl ======================================================== +dnl = +dnl = Check options that may affect the compiler +dnl = +dnl ======================================================== +dist_prefix='${MOD_DEPTH}/dist' +dist_bindir='${dist_prefix}/bin' +dist_includedir='${dist_prefix}/include/nspr' +dist_libdir='${dist_prefix}/lib' +if test "${includedir}" = '${prefix}/include'; then + includedir='${prefix}/include/nspr' +fi + +AC_ARG_WITH(dist-prefix, + [ --with-dist-prefix=DIST_PREFIX + place build files in DIST_PREFIX [dist]], + dist_prefix=$withval) + +AC_ARG_WITH(dist-bindir, + [ --with-dist-bindir=DIR build execuatables in DIR [DIST_PREFIX/bin]], + dist_bindir=$withval) + +AC_ARG_WITH(dist-includedir, + [ --with-dist-includedir=DIR + build include files in DIR [DIST_PREFIX/include/nspr]], + dist_includedir=$withval) + +AC_ARG_WITH(dist-libdir, + [ --with-dist-libdir=DIR build library files in DIR [DIST_PREFIX/lib]], + dist_libdir=$withval) + +AC_SUBST(dist_prefix) +AC_SUBST(dist_bindir) +AC_SUBST(dist_includedir) +AC_SUBST(dist_libdir) + +dnl Check if NSPR is being compiled for Mozilla +dnl Let --with-arg override environment setting +dnl +AC_ARG_WITH(mozilla, + [ --with-mozilla Compile NSPR with Mozilla support], + [ if test "$withval" = "yes"; then + AC_DEFINE(MOZILLA_CLIENT) + MOZILLA_CLIENT=1 + else + MOZILLA_CLIENT= + fi], + [ if test -n "$MOZILLA_CLIENT"; then + AC_DEFINE(MOZILLA_CLIENT) + fi]) + +AC_ARG_ENABLE(optimize, + [ --enable-optimize(=val) Enable code optimizations (val, ie. -O2) ], + [ if test "$enableval" != "no"; then + MOZ_OPTIMIZE=1 + if test -n "$enableval" && test "$enableval" != "yes"; then + _OPTIMIZE_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'` + _SAVE_OPTIMIZE_FLAGS=$_OPTIMIZE_FLAGS + fi + else + MOZ_OPTIMIZE= + fi ]) + +AC_ARG_ENABLE(debug, + [ --disable-debug Do not compile in debugging symbols], + [ if test "$enableval" = "no"; then + MOZ_DEBUG= + else + MOZ_DEBUG=1 + fi]) + +AC_ARG_ENABLE(win32-target, + [ --enable-win32-target=\$t + Specify win32 flavor. (WIN95 or WINNT)], + OS_TARGET=`echo $enableval | tr a-z A-Z`, + OS_TARGET=) + +AC_ARG_ENABLE(debug-rtl, + [ --enable-debug-rtl Use the MSVC debug runtime library], + [ if test "$enableval" = "yes"; then + USE_DEBUG_RTL=1 + fi ]) + +AC_ARG_ENABLE(n32, + [ --enable-n32 Enable n32 ABI support (IRIX only)], + [ if test "$enableval" = "yes"; then + USE_N32=1 + else if test "$enableval" = "no"; then + USE_N32= + fi + fi ]) + +AC_ARG_ENABLE(64bit, + [ --enable-64bit Enable 64-bit support (on certain platforms)], + [ if test "$enableval" = "yes"; then + USE_64=1 + fi ]) + +AC_ARG_ENABLE(mdupdate, + [ --enable-mdupdate Enable use of certain compilers' mdupdate feature], + [ if test "$enableval" = "yes"; then + USE_MDUPDATE=1 + fi ]) + +AC_ARG_ENABLE(macos-target, + [ --enable-macos-target=VER (default=10.1) + Set the minimum MacOS version needed at runtime], + [MACOS_DEPLOYMENT_TARGET_STR=$enableval], + [MACOS_DEPLOYMENT_TARGET_STR=10.1]) + +dnl ======================================================== +dnl = +dnl = Set the threading model +dnl = +dnl ======================================================== +case "$target" in + +*-aix*) + case "${target_os}" in + aix3.2*) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + ;; + esac + ;; + +esac + +dnl ======================================================== +dnl = +dnl = Set the default C compiler +dnl = +dnl ======================================================== +if test -z "$CC"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CC=xlc_r + else + CC=xlc + fi + ;; + + *-hpux*) + CC=cc + ;; + + *-irix*) + CC=cc + ;; + + *-openvms*) + CC=cc + ;; + + *-osf*) + CC=cc + ;; + + *-solaris*) + CC=cc + ;; + + esac +fi + +dnl ======================================================== +dnl = +dnl = Set the default C++ compiler +dnl = +dnl ======================================================== +if test -z "$CXX"; then + case "$target" in + + *-aix*) + if test -z "$USE_NSPR_THREADS"; then + CXX=xlC_r + else + CXX=xlC + fi + ;; + + *-hpux*) + case "${target_os}" in + hpux10.30) + CXX=aCC + ;; + hpux11.*) + CXX=aCC + ;; + *) + CXX=CC + ;; + esac + ;; + + *-irix*) + CXX=CC + ;; + + *-openvms*) + CXX=cxx + ;; + + *-osf*) + CXX=cxx + ;; + + *-solaris*) + CXX=CC + ;; + + esac +fi + +if test -z "$SKIP_PATH_CHECKS"; then + AC_PATH_PROG(WHOAMI, $WHOAMI whoami, echo not_whoami) +fi + +if test -n "$MOZ_DEBUG"; then + AC_DEFINE(DEBUG) + DEFINES="$DEFINES -UNDEBUG" + + case "${target_os}" in + beos*) + DEFINES="$DEFINES -DDEBUG_${USER}" + ;; + msvc*|mks*|cygwin*|mingw*|os2*) + DEFINES="$DEFINES -DDEBUG_`echo ${USERNAME} | sed -e 's| |_|g'`" + ;; + *) + DEFINES="$DEFINES -DDEBUG_`$WHOAMI`" + ;; + esac +else + AC_DEFINE(NDEBUG) + DEFINES="$DEFINES -UDEBUG" +fi + +if test -z "$SKIP_COMPILER_CHECKS"; then +dnl ======================================================== +dnl Checks for compilers. +dnl ======================================================== +if test "$target" != "$host"; then + echo "cross compiling from $host to $target" + cross_compiling=yes + + _SAVE_CC="$CC" + _SAVE_CFLAGS="$CFLAGS" + _SAVE_LDFLAGS="$LDFLAGS" + + AC_MSG_CHECKING([for $host compiler]) + AC_CHECK_PROGS(HOST_CC, $HOST_CC gcc cc /usr/ucb/cc, "") + if test -z "$HOST_CC"; then + AC_MSG_ERROR([no acceptable cc found in \$PATH]) + fi + AC_MSG_RESULT([$HOST_CC]) + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi + if test -z "$HOST_LDFLAGS"; then + HOST_LDFLAGS="$LDFLAGS" + fi + + CC="$HOST_CC" + CFLAGS="$HOST_CFLAGS" + LDFLAGS="$HOST_LDFLAGS" + + AC_MSG_CHECKING([whether the $host compiler ($HOST_CC $HOST_CFLAGS $HOST_LDFLAGS) works]) + AC_TRY_COMPILE([], [return(0);], + [ac_cv_prog_host_cc_works=1 AC_MSG_RESULT([yes])], + AC_MSG_ERROR([installation or configuration problem: $host compiler $HOST_CC cannot create executables.]) ) + + CC=$_SAVE_CC + CFLAGS=$_SAVE_CFLAGS + LDFLAGS=$_SAVE_LDFLAGS + + AC_CHECK_PROGS(CC, $CC "${target_alias}-gcc" "${target}-gcc", echo) + unset ac_cv_prog_CC + AC_PROG_CC + AC_CHECK_PROGS(CXX, $CXX "${target_alias}-g++" "${target}-g++", echo) + unset ac_cv_prog_CXX + AC_PROG_CXX + AC_CHECK_PROGS(RANLIB, $RANLIB "${target_alias}-ranlib" "${target}-ranlib", echo) + AC_CHECK_PROGS(AR, $AR "${target_alias}-ar" "${target}-ar", echo) + AC_CHECK_PROGS(AS, $AS "${target_alias}-as" "${target}-as", echo) + AC_CHECK_PROGS(LD, $LD "${target_alias}-ld" "${target}-ld", echo) + AC_CHECK_PROGS(STRIP, $STRIP "${target_alias}-strip" "${target}-strip", echo) + AC_CHECK_PROGS(WINDRES, $WINDRES "${target_alias}-windres" "${target}-windres", echo) + +else + AC_PROG_CXX + if test "$CXX" = "cl" -a -z "$CC"; then + CC=$CXX + else + AC_PROG_CC + fi + AC_PROG_CPP + AC_PROG_RANLIB + AC_PATH_PROGS(AS, as, $CC) + AC_PATH_PROGS(AR, ar, echo not_ar) + AC_PATH_PROGS(LD, ld link, echo not_ld) + AC_PATH_PROGS(STRIP, strip, echo not_strip) + AC_PATH_PROGS(WINDRES, windres, echo not_windres) + if test -z "$HOST_CC"; then + HOST_CC="$CC" + fi + if test -z "$HOST_CFLAGS"; then + HOST_CFLAGS="$CFLAGS" + fi +fi + +if test "$GCC" = "yes"; then + GNU_CC=1 +fi +if test "$GXX" = "yes"; then + GNU_CXX=1 +fi +if test "`echo | $AS -v 2>&1 | grep -c GNU`" != "0"; then + GNU_AS=1 +fi +rm -f a.out + +if test "$cross_compiling" = "yes"; then + CROSS_COMPILE=1 +else + CROSS_COMPILE= +fi + +dnl ======================================================== +dnl Check for gcc -pipe support +dnl ======================================================== +AC_MSG_CHECKING([for gcc -pipe support]) +if test -n "$GNU_CC" && test -n "$GNU_CXX" && test -n "$GNU_AS"; then + echo '#include ' > dummy-hello.c + echo 'int main() { printf("Hello World\n"); return 0; }' >> dummy-hello.c + ${CC} -S dummy-hello.c -o dummy-hello.s 2>&5 + cat dummy-hello.s | ${AS} -o dummy-hello.S - 2>&5 + if test $? = 0; then + _res_as_stdin="yes" + else + _res_as_stdin="no" + fi + if test "$_res_as_stdin" = "yes"; then + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -pipe" + AC_TRY_COMPILE( [ #include ], + [printf("Hello World\n");], + [_res_gcc_pipe="yes"], + [_res_gcc_pipe="no"] ) + CFLAGS=$_SAVE_CFLAGS + fi + if test "$_res_as_stdin" = "yes" && test "$_res_gcc_pipe" = "yes"; then + _res="yes"; + CFLAGS="$CFLAGS -pipe" + CXXFLAGS="$CXXFLAGS -pipe" + else + _res="no" + fi + rm -f dummy-hello.c dummy-hello.s dummy-hello.S dummy-hello a.out + AC_MSG_RESULT([$_res]) +else + AC_MSG_RESULT([no]) +fi + +fi # SKIP_COMPILER_CHECKS + +dnl ======================================================== +dnl Checks for programs. +dnl ======================================================== +if test -z "$SKIP_PATH_CHECKS"; then + AC_PATH_PROGS(PERL, perl5 perl, echo not_perl) +elif test -z "$PERL"; then + PERL=perl +fi + +dnl ======================================================== +dnl Default platform specific options +dnl ======================================================== +OBJ_SUFFIX=o +LIB_SUFFIX=a +DLL_SUFFIX=so +ASM_SUFFIX=s +MKSHLIB='$(LD) $(DSO_LDOPTS) -o $@' +PR_MD_ASFILES= +PR_MD_CSRCS= +PR_MD_ARCH_DIR=unix +AR_FLAGS='cr $@' +AS='$(CC)' +ASFLAGS='$(CFLAGS)' + +if test -n "$CROSS_COMPILE"; then + OS_ARCH=`echo $target_os | sed -e 's|/|_|g'` + OS_RELEASE= + OS_TEST="${target_cpu}" + case "${target_os}" in + linux*) OS_ARCH=Linux ;; + solaris*) OS_ARCH=SunOS OS_RELEASE=5 ;; + mingw*) OS_ARCH=WINNT ;; + esac +else + OS_ARCH=`uname -s | sed -e 's|/|_|g'` + OS_RELEASE=`uname -r` + OS_TEST=`uname -m` +fi + +if test "$OS_ARCH" = "IRIX64"; then + OS_ARCH=IRIX +fi + +if test "$OS_ARCH" = "AIX"; then + OS_RELEASE=`uname -v`.`uname -r` +fi + +if test "$OS_ARCH" = "FreeBSD"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` +fi + +if test "$OS_ARCH" = "Linux"; then + OS_RELEASE=`echo $OS_RELEASE | sed 's/-.*//'` + OS_RELEASE=`echo $OS_RELEASE | awk -F\. '{ print $1 "." $2 }'` +fi + +if test "$OS_ARCH" = "OpenVMS"; then + OS_RELEASE=`uname -v` +fi + +####################################################################### +# Master "Core Components" macros for getting the OS target # +####################################################################### + +# +# Note: OS_TARGET should be specified on the command line for gmake. +# When OS_TARGET=WIN95 is specified, then a Windows 95 target is built. +# The difference between the Win95 target and the WinNT target is that +# the WinNT target uses Windows NT specific features not available +# in Windows 95. The Win95 target will run on Windows NT, but (supposedly) +# at lesser performance (the Win95 target uses threads; the WinNT target +# uses fibers). +# +# When OS_TARGET=WIN16 is specified, then a Windows 3.11 (16bit) target +# is built. See: win16_3.11.mk for lots more about the Win16 target. +# +# If OS_TARGET is not specified, it defaults to $(OS_ARCH), i.e., no +# cross-compilation. +# + +# +# The following hack allows one to build on a WIN95 machine (as if +# s/he were cross-compiling on a WINNT host for a WIN95 target). +# It also accomodates for MKS's uname.exe. If you never intend +# to do development on a WIN95 machine, you don't need this hack. +# +if test "$OS_ARCH" = "WIN95"; then + OS_ARCH=WINNT + OS_TARGET=WIN95 +elif test "$OS_ARCH" = 'Windows_95'; then + OS_ARCH=Windows_NT + OS_TARGET=WIN95 +elif test "$OS_ARCH" = 'Windows_98'; then + OS_ARCH=Windows_NT + OS_TARGET=WIN95 +elif test "`echo $OS_ARCH | egrep -c '^(CYGWIN_9|CYGWIN_ME)' 2>/dev/null`" != 0; then + OS_ARCH='CYGWIN_NT-4.0' + OS_TARGET=WIN95 +elif test "$OS_ARCH" = "OS_2"; then + OS_ARCH=OS2 + OS_TARGET=OS2 +fi + +# +# On WIN32, we also define the variable CPU_ARCH. +# + +if test "$OS_ARCH" = "WINNT"; then + CPU_ARCH=`uname -p` + if test "$CPU_ARCH" = "I386"; then + CPU_ARCH=x86 + fi +elif test "$OS_ARCH" = "Windows_NT"; then +# +# If uname -s returns "Windows_NT", we assume that we are using +# the uname.exe in MKS toolkit. +# +# The -r option of MKS uname only returns the major version number. +# So we need to use its -v option to get the minor version number. +# Moreover, it doesn't have the -p option, so we need to use uname -m. +# + OS_ARCH=WINNT + OS_MINOR_RELEASE=`uname -v` + if test "$OS_MINOR_RELEASE" = "00"; then + OS_MINOR_RELEASE=0 + fi + OS_RELEASE="${OS_RELEASE}.${OS_MINOR_RELEASE}" + CPU_ARCH=`uname -m` + # + # MKS's uname -m returns "586" on a Pentium machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +elif echo "$OS_ARCH" | grep -c CYGWIN_NT >/dev/null; then +# +# If uname -s returns "CYGWIN_NT-4.0", we assume that we are using +# the uname.exe in the Cygwin tools. +# + OS_RELEASE=`echo $OS_ARCH | sed 's|^CYGWIN_NT-||'` + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # Cygwin's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +elif test "$OS_ARCH" = "CYGWIN32_NT"; then +# +# Prior to the Beta 20 release, Cygwin was called GNU-Win32. +# If uname -s returns "CYGWIN32/NT", we assume that we are using +# the uname.exe in the GNU-Win32 tools. +# + OS_ARCH=WINNT + CPU_ARCH=`uname -m` + # + # GNU-Win32's uname -m returns "i686" on a Pentium Pro machine. + # + if echo "$CPU_ARCH" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + fi +fi + +if test -n "$MOZILLA_CLIENT" && test "$OS_ARCH" = "WINNT"; then + OS_TARGET=WIN95 + if test -n "$MOZ_DEBUG"; then + USE_DEBUG_RTL=1 + fi +fi +if test -z "$OS_TARGET"; then + OS_TARGET=$OS_ARCH +fi +if test "$OS_TARGET" = "WIN95"; then + OS_RELEASE="4.0" +fi +if test "$OS_TARGET" = "WIN16"; then + OS_RELEASE= +fi +OS_CONFIG="${OS_TARGET}${OS_RELEASE}" + +dnl ======================================================== + +dnl ======================================================== +dnl Override of system specific host options +dnl ======================================================== +case "$host" in +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + NSINSTALL='$(CYGWIN_WRAPPER) nsinstall' + if test `echo "${PATH}" | grep -c \;` = 0; then + CYGWIN_WRAPPER='sh $(topsrcdir)/build/cygwin-wrapper' + fi + ;; +*-beos*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_BEOS -DBeOS -DBEOS -D_POSIX_SOURCE" + ;; +*os2*) + ;; +*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" + ;; +esac + +dnl ======================================================== +dnl Override of system specific target options +dnl ======================================================== +case "$target" in + +*-aix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(AIX) + AC_DEFINE(SYSV) + DSO_LDOPTS='-brtl -bnortllib -bM:SRE -bnoentry -bexpall -blibpath:/usr/lib:/lib' + AC_CHECK_HEADER(sys/atomic_op.h, AC_DEFINE(AIX_HAVE_ATOMIC_OP_H)) + case "${target_os}" in + aix3.2*) + AC_DEFINE(AIX_RENAME_SELECT) + AC_DEFINE(_PR_NO_LARGE_FILES) + AIX_LINK_OPTS='-bnso -berok' + PR_MD_ASFILES=os_AIX.s + ;; + aix4.1*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_NO_LARGE_FILES) + AC_DEFINE(AIX4_1) + MKSHLIB= + DSO_LDOPTS= + AIX_LINK_OPTS='-bnso -berok' + LIBNSPR='-L$(dist_libdir) -lnspr$(MOD_MAJOR_VERSION)_shr' + LIBPLC='-L$(dist_libdir) -lplc$(MOD_MAJOR_VERSION)_shr' + ;; + aix4.2*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + aix4.3*) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(AIX4_3_PLUS) + AC_DEFINE(HAVE_SOCKLEN_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + *) + AC_DEFINE(AIX_TIMERS) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(AIX4_3_PLUS) + AC_DEFINE(HAVE_SOCKLEN_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + USE_IPV6=1 + AIX_LINK_OPTS='-brtl -bnso -berok' + ;; + esac + CFLAGS="$CFLAGS -qro -qroconst" + AIX_WRAP='$(DIST)/lib/aixwrap.o' + AIX_TMP='./_aix_tmp.o' + if test -n "$USE_64"; then + MDCPUCFG_H=_aix64.cfg + OBJECT_MODE=64 + else + MDCPUCFG_H=_aix32.cfg + fi + PR_MD_CSRCS=aix.c + RESOLVE_LINK_SYMBOLS=1 + ;; + +*-beos*) + AC_DEFINE(XP_BEOS) + AC_DEFINE(BeOS) + AC_DEFINE(BEOS) + AC_DEFINE(_POSIX_SOURCE) + DSO_LDOPTS=-nostart + MDCPUCFG_H=_beos.cfg + USE_BTHREADS=1 + PR_MD_ARCH_DIR=beos + RESOLVE_LINK_SYMBOLS=1 + case "${target_cpu}" in + i*86) + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-gdwarf-2 -O0' + MKSHLIB='$(CCC) $(DSO_LDOPTS) -o $@' + AC_CHECK_LIB(bind, gethostbyaddr, [OS_LIBS="$OS_LIBS -lbind -lsocket"]) + ;; + powerpc) + CC=mwcc + CCC=mwcc + LD=mwld + DSO_LDOPTS='-xms -export pragma -init _init_routine_ -term _term_routine_ -lroot -lnet /boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o /boot/develop/lib/ppc/start_dyn.o' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS='-g -O0' + ;; + esac + ;; + +*-bsdi*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(BSDI) + AC_DEFINE(NEED_BSDREGEX) + + CFLAGS="$CFLAGS -Wall -Wno-format" + CXXFLAGS="$CXXFLAGS -Wall -Wno-format" + + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + elif echo "$OS_TEST" | grep -c sparc >/dev/null; then + CPU_ARCH=sparc + fi + + MDCPUCFG_H=_bsdi.cfg + PR_MD_CSRCS=bsdi.c + + DSO_LDOPTS=-r + + case "$target_os" in + bsdi1.1*) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_ARRAY) + AC_DEFINE(_PR_STAT_HAS_ONLY_ST_ATIME) + AC_DEFINE(_PR_NEED_H_ERRNO) + MKSHLIB= + DSO_CFLAGS= + DSO_LDOPTS= + ;; + + bsdi2.1*) + AC_DEFINE(_PR_TIMESPEC_HAS_TS_SEC) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_ARRAY) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + PR_MD_ASFILES=os_BSD_OS_386_2.s + ;; + + bsdi4.* | bsdi5.*) + AC_DEFINE(_PR_SELECT_CONST_TIMEVAL) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_STRUCT) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname,$(@:$(OBJDIR)/%.so=%.so)' + STRIP="$STRIP -d" + case "$target_os" in + bsdi4.2* | bsdi4.3* | bsdi5.*) + AC_DEFINE(_PR_HAVE_GETPROTO_R) + AC_DEFINE(_PR_HAVE_GETPROTO_R_POINTER) + ;; + esac + ;; + *) + AC_DEFINE(_PR_SELECT_CONST_TIMEVAL) + AC_DEFINE(_PR_BSDI_JMPBUF_IS_STRUCT) + AC_DEFINE(HAVE_DLL) + AC_DEFINE(USE_DLFCN) + AC_DEFINE(_PR_STAT_HAS_ST_ATIMESPEC) + ;; + esac + + ;; + +*-darwin*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(DARWIN) + AC_DEFINE(HAVE_BSD_FLOCK) + CFLAGS="$CFLAGS -Wmost -fno-common" + if echo $OS_TEST | grep -c 86 2>/dev/null; then + AC_DEFINE(i386) + CPU_ARCH=i386 + else + AC_DEFINE(ppc) + CPU_ARCH=ppc + fi + DSO_LDOPTS='-dynamiclib -compatibility_version 1 -current_version 1 -all_load -install_name @executable_path/$@ -headerpad_max_install_names' + # Use the standard preprocessor (cpp) + CFLAGS="$CFLAGS -no-cpp-precomp" + MKSHLIB='$(CC) -arch $(CPU_ARCH) $(DSO_LDOPTS) -o $@' + STRIP="$STRIP -x -S" + DLL_SUFFIX=dylib + USE_PTHREADS=1 + MDCPUCFG_H=_darwin.cfg + PR_MD_CSRCS=darwin.c + if test "$CPU_ARCH" = "ppc"; then + PR_MD_ASFILES=os_Darwin_ppc.s + fi + + # Add Mac OS X support for loading CFM & CFBundle plugins + if test -f /System/Library/Frameworks/Carbon.framework/Carbon; then + AC_DEFINE(XP_MACOSX) + OS_TARGET=MacOSX + + dnl The C preprocessor can only handle integers in comparisons, so + dnl convert the version to the form AABBCC where AA=major release, + dnl BB=minor release, and CC=point/micro release. + + MACOS_VERSION_MAJOR=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 1` + MACOS_VERSION_MINOR=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 2` + MACOS_VERSION_MICRO=`echo $MACOS_DEPLOYMENT_TARGET_STR | cut -d . -f 3` + if test -z "$MACOS_VERSION_MINOR"; then + MACOS_VERSION_MINOR=0 + fi + if test -z "$MACOS_VERSION_MICRO"; then + MACOS_VERSION_MICRO=0 + fi + MACOS_DEPLOYMENT_TARGET=`printf "%02d%02d%02d" "$MACOS_VERSION_MAJOR" "$MACOS_VERSION_MINOR" "$MACOS_VERSION_MICRO"` + AC_DEFINE_UNQUOTED(MACOS_DEPLOYMENT_TARGET, $MACOS_DEPLOYMENT_TARGET) + fi + + # do the right thing for panther SDK support + if test "$NEXT_ROOT"; then + CFLAGS="-I${NEXT_ROOT}/usr/include $CFLAGS" + CXXFLAGS="-I${NEXT_ROOT}/usr/include $CXXFLAGS" + fi + ;; + +*-dgux*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(DGUX) + AC_DEFINE(_DGUX_SOURCE) + AC_DEFINE(_POSIX4A_DRAFT6_SOURCE) + DSO_LDOPTS=-G + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS= + MDCPUCFG_H=_dgux.cfg + PR_MD_CSRCS=dgux.c + ;; + +*-freebsd*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(FREEBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(HAVE_SOCKLEN_T) + CFLAGS="$CFLAGS $(DSO_CFLAGS) -ansi -Wall" + MOZ_OBJFORMAT=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + if test "$MOZ_OBJFORMAT" = "elf"; then + DLL_SUFFIX=so + else + DLL_SUFFIX=so.1.0 + fi + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + MDCPUCFG_H=_freebsd.cfg + PR_MD_CSRCS=freebsd.c + ;; + +*-hpux*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(HPUX) + AC_DEFINE(_HPUX_SOURCE) + AC_DEFINE(hppa) + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + AC_DEFINE(_PR_POLL_WITH_SELECT) + AC_DEFINE(_USE_BIG_FDS) + DLL_SUFFIX=sl + DSO_LDOPTS='-b +h $(notdir $@)' + PR_MD_CSRCS=hpux.c + if test "$OS_TEST" != "ia64"; then + PR_MD_ASFILES=os_HPUX.s + fi + if test -n "$USE_64"; then + MDCPUCFG_H=_hpux64.cfg + else + MDCPUCFG_H=_hpux32.cfg + fi + if test -z "$GNU_CC"; then + CC="$CC -Ae" + CXX="$CXX -ext" + DSO_CFLAGS=+Z + else + DSO_CFLAGS=-fPIC + fi + + if test -n "$MOZILLA_CLIENT"; then + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if echo "$OS_RELEASE" | grep ^A.09 >/dev/null; then + AC_DEFINE(_PR_NEED_H_ERRNO) + AC_DEFINE(HPUX9) + DEFAULT_IMPL_STRATEGY=_EMU + USE_NSPR_THREADS=1 + fi + + if echo "$OS_RELEASE" | egrep '^(A.09|B.10)' >/dev/null; then + AC_DEFINE(_PR_NO_LARGE_FILES) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(_PR_NEED_H_ERRNO) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(HAVE_INT_LOCALTIME_R) + fi + + if echo "$OS_RELEASE" | egrep '^(B.10.30|B.11)' >/dev/null; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + + # HP-UX 11i (B.11.11) or higher + changequote(<<,>>) + case "$OS_RELEASE" in + [C-Z]*|B.[2-9]*|B.1[2-9]*|B.11.[2-9]*|B.11.1[1-9]*) + USE_IPV6=1 + ;; + esac + changequote([,]) + + if test "$OS_RELEASE" = "B.10.01"; then + AC_DEFINE(HPUX10) + DEFAULT_IMPL_STRATEGY=_EMU + fi + + if test "$OS_RELEASE" = "B.10.10"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_10) + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.20"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_20) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$OS_RELEASE" = "B.10.30"; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX10_30) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS +DAportable +DS1.1" + CXXFLAGS="$CXXFLAGS +DAportable +DS1.1" + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if echo "$OS_RELEASE" | grep ^B.11 >/dev/null; then + AC_DEFINE(HPUX10) + AC_DEFINE(HPUX11) + AC_DEFINE(_LARGEFILE64_SOURCE) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + if test -z "$GNU_CC"; then + if test -z "$USE_64"; then + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD32" + CXXFLAGS="$CXXFLAGS +DD32" + else + CFLAGS="$CFLAGS +DAportable +DS2.0" + CXXFLAGS="$CXXFLAGS +DAportable +DS2.0" + fi + else + if test "$OS_TEST" = "ia64"; then + CFLAGS="$CFLAGS +DD64" + CXXFLAGS="$CXXFLAGS +DD64" + else + CFLAGS="$CFLAGS +DA2.0W +DS2.0" + CXXFLAGS="$CXXFLAGS +DA2.0W +DS2.0" + fi + fi + fi + DEFAULT_IMPL_STRATEGY=_PTH + fi + + if test "$DEFAULT_IMPL_STRATEGY" = "_EMU"; then + USE_NSPR_THREADS=1 + USE_PTHREADS= + USE_USER_THREADS= + elif test "$DEFAULT_IMPL_STRATEGY" = "_PTH"; then + USE_PTHREADS=1 + if test "$USE_NSPR_THREADS"; then + USE_PTHREADS= + fi + if test "$USE_USER_PTHREADS"; then + USE_PTHREADS= + fi + fi + ;; + +*-irix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(IRIX) + AC_DEFINE(SVR4) + AC_DEFINE(_SGI_MP_SOURCE) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + PR_MD_CSRCS=irix.c + PR_MD_ASFILES=os_Irix.s + MKSHLIB='$(LD) $(DSO_LDOPTS) -rdata_shared -shared -soname $(notdir $@) -o $@' + STRIP="$STRIP -f" + RESOLVE_LINK_SYMBOLS=1 + if test -n "$USE_64"; then + MDCPUCFG_H=_irix64.cfg + else + MDCPUCFG_H=_irix32.cfg + fi + case "${target_os}" in + irix6*) + AC_DEFINE(IRIX6) + USE_PTHREADS=1 + USE_N32=1 + COMPILER_TAG=_n32 + IMPL_STRATEGY=_PTH + ;; + irix5*) + AC_DEFINE(IRIX5) + USE_NSPR_THREADS=1 + ;; + *) + USE_PTHREADS=1 + USE_N32=1 + ;; + esac + if test "$GNU_CC"; then + dnl + dnl If we are using gcc with native binutils, we need to + dnl suppress the + dnl #lineno "filename" num num + dnl lines, which confuse IRIX native as. Add -Wp,-P to the + dnl gcc command line, which passes -P to the preprocessor. + dnl + AS='$(CC) -Wp,-P -x assembler-with-cpp -D_ASM -mips2 $(INCLUDES)' + CFLAGS="$CFLAGS -Wall -Wno-format" + _OPTIMIZE_FLAGS="-O6" + else + if test -n "$USE_N32"; then + AS='as -D_ASM $(INCLUDES) -n32' + else + AS='as -D_ASM $(INCLUDES)' + fi + CFLAGS="$CFLAGS -fullwarn -xansi" + if test "$USE_N32"; then + _OPTIMIZE_FLAGS="-O -OPT:Olimit=4000" + else + _OPTIMIZE_FLAGS="-O -Olimit 4000" + fi + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + case "${target}" in + *-irix6.*) + CFLAGS="$CFLAGS -multigot" + DSO_LDOPTS="-no_unresolved" + if test "$USE_N32"; then + CFLAGS="$CFLAGS -n32 -woff 1209" + DSO_LDOPTS="$DSO_LDOPTS -n32" + else + if test "$USE_64"; then + CFLAGS="$CFLAGS -64" + else + CFLAGS="$CFLAGS -32" + fi + fi + ;; + *) + CFLAGS="$CFLAGS -xgot" + ;; + esac + fi + if test "${target_os}" = "irix5.3"; then + AC_DEFINE(IRIX5_3) + fi + case "${target_os}" in + irix6.5) + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -mips3" + fi + AC_DEFINE(_PR_HAVE_GETPROTO_R) + AC_DEFINE(_PR_HAVE_GETPROTO_R_POINTER) + AC_DEFINE(_PR_HAVE_SGI_PRDA_PROCMASK) + ;; + irix5*) + ;; + *) + AC_DEFINE(_PR_HAVE_SGI_PRDA_PROCMASK) + ;; + esac + ;; + +*-linux*) + if test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + IMPL_STRATEGY=_PTH + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(_POSIX_SOURCE) + AC_DEFINE(_BSD_SOURCE) + AC_DEFINE(_SVID_SOURCE) + AC_DEFINE(_LARGEFILE64_SOURCE) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + AC_DEFINE(LINUX) + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MDCPUCFG_H=_linux.cfg + PR_MD_CSRCS=linux.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS='-shared -Wl,-soname -Wl,$(notdir $@)' + _OPTIMIZE_FLAGS=-O2 + _DEBUG_FLAGS="-g -fno-inline" # most people on linux use gcc/gdb, and that + # combo is not yet good at debugging inlined + # functions (even when using DWARF2 as the + # debugging format) + COMPILER_TAG=_glibc + if echo "$OS_TEST" | grep -c 86 >/dev/null; then + CPU_ARCH=x86 + else + CPU_ARCH=$OS_TEST + fi + CPU_ARCH_TAG=_${CPU_ARCH} + case "${target_cpu}" in + alpha) + AC_DEFINE(_ALPHA_) + AC_DEFINE(__alpha) + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + ;; + i*86) + AC_DEFINE(i386) + PR_MD_ASFILES=os_Linux_x86.s + ;; + ia64) + PR_MD_ASFILES=os_Linux_ia64.s + ;; + x86_64) + PR_MD_ASFILES=os_Linux_x86_64.s + ;; + m68k) + CFLAGS="$CFLAGS -m68020-60" + CXXFLAGS="$CXXFLAGS -m68020-60" + ;; + esac + ;; + +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + AC_DEFINE(XP_PC) + AC_DEFINE(WIN32) + PR_MD_ARCH_DIR=windows + RESOLVE_LINK_SYMBOLS=1 + + if test -n "$GNU_CC"; then + CC="$CC -mno-cygwin" + CXX="$CXX -mno-cygwin" + DLL_SUFFIX=dll + MKSHLIB='$(CC) -shared -Wl,--export-all-symbols -Wl,--out-implib -Wl,$(IMPORT_LIBRARY) $(DLLBASE) -o $(subst $(OBJDIR)/,,$(SHARED_LIBRARY))' + RC=$WINDRES + # Use temp file for windres (bug 213281) + RCFLAGS='-O coff --use-temp-file' + else + CC=cl + CXX=cl + LD=link + AR='lib -NOLOGO -OUT:"$@"' + AR_FLAGS= + RANLIB='echo not_ranlib' + STRIP='echo not_strip' + RC=rc.exe + GARBAGE='$(OBJDIR)/vc20.pdb $(OBJDIR)/vc40.pdb' + OBJ_SUFFIX=obj + LIB_SUFFIX=lib + DLL_SUFFIX=dll + + # Determine compiler version + CC_VERSION=`"${CC}" -v 2>&1 | grep Version | sed -e 's|.* Version ||' -e 's| .*||'` + _CC_MAJOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $1 }'` + _CC_MINOR_VERSION=`echo $CC_VERSION | awk -F\. '{ print $2 }'` + MSC_VER=${_CC_MAJOR_VERSION}${_CC_MINOR_VERSION} + + CFLAGS="$CFLAGS -W3 -nologo -GF -Gy" + DLLFLAGS='-OUT:"$@"' + _DEBUG_FLAGS=-Z7 + _OPTIMIZE_FLAGS=-O2 + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -Od" + fi + + if test -n "$USE_DEBUG_RTL"; then + CFLAGS="$CFLAGS -MDd" + else + CFLAGS="$CFLAGS -MD" + fi + + if test -n "$MOZ_DEBUG"; then + AC_DEFINE(_DEBUG) + else + DEFINES="$DEFINES -U_DEBUG" + fi + + if test -n "$MOZ_OPTIMIZE"; then + if test -n "$MOZ_PROFILE"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Z7" + fi + if test -n "$MOZ_DEBUG_SYMBOLS"; then + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Zi" + fi + if test -n "$MOZ_PROFILE" -o -n "$MOZ_DEBUG_SYMBOLS"; then + DLLFLAGS="$DLLFLAGS -DEBUG -OPT:REF" + LDFLAGS="$LDFLAGS -DEBUG -OPT:REF" + fi + fi + + if test -n "$MOZ_DEBUG"; then + DLLFLAGS="$DLLFLAGS -DEBUG -DEBUGTYPE:CV" + LDFLAGS="$LDFLAGS -DEBUG -DEBUGTYPE:CV" + fi + + if test "$OS_TARGET" = "WINNT"; then + CFLAGS="$CFLAGS -GT" + if test "$CPU_ARCH" = "x86"; then + CFLAGS="$CFLAGS -G5" + fi + LIBNSPR='$(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + else + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + fi # GNU_CC + + if test -n "$USE_STATIC_TLS"; then + AC_DEFINE(_PR_USE_STATIC_TLS) + fi + + if test "$OS_TARGET" = "WINNT"; then + AC_DEFINE(WINNT) + else + AC_DEFINE(WIN95) + # undefine WINNT as some versions of mingw gcc define it by default + DEFINES="$DEFINES -UWINNT" + AC_DEFINE(_PR_GLOBAL_THREADS_ONLY) + fi + + if test "$CPU_ARCH" = "x86"; then + CPU_ARCH_TAG= + else + CPU_ARCH_TAG=$CPU_ARCH + fi + + if test -n "$USE_DEBUG_RTL"; then + OBJDIR_SUFFIX=OBJD + fi + + OS_DLLFLAGS="-nologo -DLL -SUBSYSTEM:WINDOWS" + if test "$MSC_VER" = "1200" -a -z "$MOZ_DEBUG_SYMBOLS"; then + OS_DLLFLAGS="$OS_DLLFLAGS -PDB:NONE" + fi + + case "$OS_TARGET" in + WINNT) + MDCPUCFG_H=_winnt.cfg + ;; + WIN95) + MDCPUCFG_H=_win95.cfg + ;; + WIN16) + MDCPUCFG_H=_win16.cfg + ;; + *) + AC_MSG_ERROR([Missing OS_TARGET for ${target}. Use --enable-win32-target to set.]) + ;; + esac + + case "$target_cpu" in + i*86) + AC_DEFINE(_X86_) + ;; + alpha) + AC_DEFINE(_ALPHA_) + ;; + mips) + AC_DEFINE(_MIPS_) + ;; + *) + AC_DEFINE(_CPU_ARCH_NOT_DEFINED) + ;; + esac + + ;; + +*-ncr-sysv*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(NCR) + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "2.03"; then + AC_DEFINE(_PR_STAT_HAS_ST_ATIM) + else + AC_DEFINE(_PR_STAT_HAS_ST_ATIM_UNION) + fi + + if test -z "$GNU_CC"; then + CFLAGS="$CFLAGS -Hnocopyr" + CXXFLAGS="$CXXFLAGS -Hnocopyr" + else + CFLAGS="$CFLAGS -fPIC -Wall" + CXXFLAGS="$CXXFLAGS -fPIC -Wall" + DSO_LDOPTS=-G + fi + MDCPUCFG_H=_ncr.cfg + PR_MD_CSRCS=ncr.c + ;; + +mips-nec-sysv*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(__SVR4) + AC_DEFINE(NEC) + AC_DEFINE(nec_ews) + USE_NSPR_THREADS=1 + if test -z "$GNU_CC"; then + CC='$(NSDEPTH)/build/hcc cc -Xa -KGnum=0 -KOlimit=4000' + CXX=g++ + fi + OS_LIBS="$OS_LIBS -lsocket -lnsl -ldl" + DSO_LDOPTS=-G + MDCPUCFG_H=_nec.cfg + PR_MD_CSRCS=nec.c + ;; + +*-netbsd*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NETBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + USE_NSPR_THREADS=1 + MDCPUCFG_H=_netbsd.cfg + PR_MD_CSRCS=netbsd.c + + DSO_CFLAGS='-fPIC -DPIC' + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + MKSHLIB='$(CC) -o $@ $(DSO_LDOPTS)' + + if test -z "$OBJECT_FMT"; then + if echo __ELF__ | ${CC-cc} -E - | grep -q __ELF__ 2>/dev/null; then + OBJECT_FMT=a.out + DLL_SUFFIX=so.1.0 + DSO_LDOPTS='-shared' + else + OBJECT_FMT=ELF + DLL_SUFFIX=so + DSO_LDOPTS='-shared -Wl,-soname,$(notdir $@)' + fi + fi + + if test "$LIBRUNPATH"; then + DSO_LDOPTS="$DSO_LDOPTS -Wl,-R$LIBRUNPATH" + fi + ;; + +mips-sony-newsos*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SONY) + AC_DEFINE(SYSV) + AC_DEFINE(SVR4) + AC_DEFINE(__svr4) + AC_DEFINE(__svr4__) + AC_DEFINE(HAVE_SVID_GETTOD) + USE_NSPR_THREADS=1 + CFLAGS="$CFLAGS -Xa -fullwarn" + CXXFLAGS="$CXXFLAGS -Xa -fullwarn" + DSO_LDOPTS=-G + MDCPUCFG_H=_sony.cfg + PR_MD_CSRCS=sony.c + ;; + +*-nextstep*|*-openstep*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NEXTSTEP) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(_POSIX_SOURCE) + CFLAGS="$CFLAGS -Wall -fno-common -traditional-cpp -posix" + CXXFLAGS="$CXXFLAGS -Wall -fno-common -traditional-cpp -posix" + USE_NSPR_THREADS=1 + DLL_SUFFIX=dylib + MDCPUCFG_H=_nextstep.cfg + PR_MD_CSRCS=nextstep.c + ;; + + +*-nto*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(NTO) + AC_DEFINE(_QNX_SOURCE) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + MDCPUCFG_H=_nto.cfg + PR_MD_CSRCS=nto.c + MKSHLIB='$(CC) $(DSO_LDOPTS) -Wl,-soname -Wl,$(notdir $@) -o $@' + DSO_CFLAGS=-fPIC + DSO_LDOPTS=-shared + OS_LIBS="$OS_LIBS -lsocket" + _OPTIMIZE_FLAGS="-O1" + _DEBUG_FLAGS="-gstabs" + ;; + +*-openbsd*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(OPENBSD) + AC_DEFINE(HAVE_BSD_FLOCK) + AC_DEFINE(HAVE_SOCKLEN_T) + CFLAGS="$CFLAGS -ansi -Wall" + CXXFLAGS="$CXXFLAGS -ansi -Wall" + DLL_SUFFIX=so.1.0 + DSO_CFLAGS=-fPIC + MDCPUCFG_H=_openbsd.cfg + PR_MD_CSRCS=openbsd.c + USE_NSPR_THREADS=1 + DSO_LDOPTS='-shared -fPIC' + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + ;; + +*-openvms*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(VMS) + AC_DEFINE(PR_GETIPNODE_NOT_THREADSAFE) + RESOLVE_LINK_SYMBOLS=1 + AR_FLAGS='c $@' + MDCPUCFG_H=_openvms.cfg + PR_MD_CSRCS=openvms.c + DSO_LDOPTS='-shared -auto_symvec $(LDFLAGS)' + if test -n "$MOZ_DEBUG"; then + DSO_LDOPTS="$DSO_LDOPTS $_DEBUG_FLAGS" + else + DSO_LDOPTS="$DSO_LDOPTS $_OPTIMIZE_FLAGS" + fi + ;; + +*-osf*) + SHELL_OVERRIDE="SHELL = /usr/bin/ksh" + AC_DEFINE(XP_UNIX) + AC_DEFINE(OSF1) + AC_DEFINE(_REENTRANT) + # OSF1 and HPUX report the POLLHUP event for a socket when the + # shutdown(SHUT_WR) operation is called for the remote end, even though + # the socket is still writeable. Use select(), instead of poll(), to + # workaround this problem. + AC_DEFINE(_PR_POLL_WITH_SELECT) + + if echo "$OS_RELEASE" | egrep -c '(V2.0|V3.2)' 2>/dev/null ; then + USE_NSPR_THREADS=1 + fi + + if test -z "$GNU_CC"; then + CC="$CC -std1 -ieee_with_inexact" + if test "$OS_RELEASE" != "V2.0"; then + CC="$CC -readonly_strings" + fi + _OPTIMIZE_FLAGS="$_OPTIMIZE_FLAGS -Olimit 4000" + AC_CHECK_HEADER(machine/builtins.h, AC_DEFINE(OSF1_HAVE_MACHINE_BUILTINS_H)) + else + CFLAGS="$CFLAGS -mieee" + CXXFLAGS="$CXXFLAGS -mieee" + fi + + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + AC_DEFINE(HAVE_INT_LOCALTIME_R) + else + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if echo $OS_RELEASE | grep -c V4.0 >/dev/null; then + AC_DEFINE(OSF1V4_MAP_PRIVATE_BUG) + fi + DSO_LDOPTS='-shared -all -expect_unresolved "*" -soname $(notdir $@)' + MDCPUCFG_H=_osf1.cfg + PR_MD_CSRCS=osf1.c + ;; + +*-qnx*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(QNX) + AC_DEFINE(_PR_NEED_H_ERRNO) + USE_NSPR_THREADS=1 + MDCPUCFG_H=_qnx.cfg + PR_MD_CSRCS=qnx.c + ;; + +*-*-sco*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SCO) + AC_DEFINE(sco) + AC_DEFINE(SYSV) + AC_DEFINE(_SVID3) + AC_DEFINE(_PR_NEED_H_ERRNO) + CC='cc -b elf -KPIC' + CXX='$(NSDEPTH)/build/hcpp CC +.cpp +w' + USE_NSPR_THREADS=1 + CPU_ARCH=x86 + DSO_LDOPTS='-b elf -G' + MDCPUCFG_H=_scoos.cfg + PR_MD_SRCS=scoos.c + ;; + +*-sinix*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SNI) + AC_DEFINE(RELIANTUNIX) + AC_DEFINE(sinix) + AC_DEFINE(HAVE_SVID_GETTOD) + if echo "$OS_TEST" | grep -c 86 2>/dev/null; then + AC_DEFINE(i386) + CPU_ARCH=x86 + else + CPU_ARCH=mips + fi + + if test "$GNU_CC"; then + AS='$(CC) -x assembler-with-cpp' + if test "$CPU_ARCH" = "mips"; then + LD=gld + fi + CFLAGS="$CFLAGS -Wall -Wno-format" + else + AS='/usr/bin/cc' + _OPTIMIZE_FLAGS='-O -F Olimit,4000' + fi + + DSO_LDOPTS='-G -z defs -h $(@:$(OBJDIR)/%.so=%.so)' + + if test "$OS_RELEASE" = "5.43"; then + AC_DEFINE(IP_MULTICAST) + fi + + OS_LIBS="$OS_LIBS -lsocket -lnsl -lresolv -ldl -lc" + USE_NSPR_THREADS=1 + MDCPUCFG_H=_reliantunix.cfg + PR_MD_CSRCS=reliantunix.c + if test "${OS_ARCH}" = "mips"; then + PR_MD_ASFILES=os_ReliantUNIX.s + fi + ;; + +*-sunos*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(SUNOS4) + CFLAGS="$CFLAGS -Wall -Wno-format" + if test "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + fi + CPU_ARCH=sparc + DLL_SUFFIX=so.1.0 + DSO_LDOPTS= + DSO_CFLAGS=-fPIC + USE_NSPR_THREADS=1 + if test "$OS_RELEASE" = "4.1.3_U1"; then + _OPTIMIZE_FLAGS= + OS_LIBS="$OS_LIBS -lm" + fi + MDCPUCFG_H=_sunos4.cfg + PR_MD_CSRCS=sunos4.c + ;; + +*-solaris*) + if test -z "$USE_USER_THREADS" && test -z "$USE_NATIVE_THREADS"; then + USE_PTHREADS=1 + fi + AC_DEFINE(XP_UNIX) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + AC_DEFINE(__svr4) + AC_DEFINE(__svr4__) + AC_DEFINE(SOLARIS) + AC_DEFINE(HAVE_FCNTL_FILE_LOCKING) + if test -n "$USE_64"; then + MDCPUCFG_H=_solaris64.cfg + else + MDCPUCFG_H=_solaris32.cfg + fi + PR_MD_CSRCS=solaris.c + LD=/usr/ccs/bin/ld + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + RESOLVE_LINK_SYMBOLS=1 + if test -n "$GNU_CC"; then + DSO_CFLAGS=-fPIC + if `$CC -print-prog-name=ld` -v 2>&1 | grep -c GNU >/dev/null; then + GCC_USE_GNU_LD=1 + fi + DSO_LDOPTS='-shared -Wl,-h,$(notdir $@),-z,combreloc,-z,defs' + else + DSO_CFLAGS=-KPIC + DSO_LDOPTS='-G -h $(notdir $@) -z combreloc -z defs' + fi + if test -z "$GNU_AS"; then + ASFLAGS="$ASFLAGS -Wa,-P" + fi + if test -n "$GNU_CC"; then + CFLAGS="$CFLAGS -Wall" + CXXFLAGS="$CXXFLAGS -Wall" + if test -n "$USE_MDUPDATE"; then + CFLAGS="$CFLAGS -MDupdate \$(DEPENDENCIES)" + CXXFLAGS="$CXXFLAGS -MDupdate \$(DEPENDENCIES)" + fi + else + CFLAGS="$CFLAGS -xstrconst" + CXXFLAGS="$CXXFLAGS -Qoption cg -xstrconst -features=tmplife" + if test -z "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS -xs" + CXXFLAGS="$CXXFLAGS -xs" + fi + _OPTIMIZE_FLAGS=-xO4 + fi + if test -n "$USE_64"; then + if test -n "$GNU_CC"; then + CC="$CC -m64" + CXX="$CXX -m64" + else + CC="$CC -xarch=v9" + CXX="$CXX -xarch=v9" + fi + fi + if test "$OS_TEST" = "i86pc"; then + AC_DEFINE(i386) + CPU_ARCH_TAG=_$OS_TEST + # The default debug format, DWARF (-g), is not supported by gcc + # on i386-ANY-sysv4/solaris, but the stabs format is. It is + # assumed that the Solaris assembler /usr/ccs/bin/as is used. + # If your gcc uses GNU as, you do not need the -Wa,-s option. + if test -n "$MOZ_DEBUG" && test -n "$GNU_CC"; then + _DEBUG_FLAGS=-gstabs + if test -z "$GNU_AS"; then + _DEBUG_FLAGS="$_DEBUG_FLAGS -Wa,-s" + fi + fi + fi + case "${target_os}" in + solaris2.3*) + AC_DEFINE(_PR_NO_LARGE_FILES) + ;; + solaris2.4*) + AC_DEFINE(_PR_NO_LARGE_FILES) + ;; + solaris2.5*) + AC_DEFINE(SOLARIS2_5) + ;; + *) + AC_DEFINE(_PR_HAVE_OFF64_T) + # The lfcompile64(5) man page on Solaris 2.6 says: + # For applications that do not wish to conform to the POSIX or + # X/Open specifications, the 64-bit transitional interfaces + # are available by default. No compile-time flags need to be + # set. + # But gcc 2.7.2.x fails to define _LARGEFILE64_SOURCE by default. + # The native compiler, gcc 2.8.x, and egcs don't have this problem. + if test -n "$GNU_CC"; then + AC_DEFINE(_LARGEFILE64_SOURCE) + fi + ;; + esac + case "${target_os}" in + solaris2.3*) + ;; + solaris2.4*) + ;; + solaris2.5*) + ;; + solaris2.6*) + ;; + solaris2.7*) + ;; + *) + # Solaris 8 or higher has IPv6. + AC_DEFINE(_PR_INET6) + ;; + esac + if test "$OS_TEST" = "sun4u"; then + # 64-bit Solaris requires SPARC V9 architecture, so the following + # is not needed. + if test -z "$USE_64"; then + ULTRASPARC_LIBRARY=nspr_flt + fi + fi + # Purify requires that binaries linked against nspr also + # be linked against -lrt (or -lposix4) so add it to OS_LIBS + _rev=`uname -r` + _librt=`echo $_rev 5.6 | awk '{ if ($1 > $2) print "-lrt"; else print "-lposix4" }'` + OS_LIBS="$OS_LIBS $_librt" + ;; + +*-sco-sysv5*) + AC_DEFINE(XP_UNIX) + AC_DEFINE(UNIXWARE) + AC_DEFINE(SVR4) + AC_DEFINE(SYSV) + USE_NSPR_THREADS=1 + if echo $OS_RELEASE | grep -c 2.1 2>/dev/null; then + AC_DEFINE(_PR_NO_LARGE_FILES) + CC='$(NSDEPTH)/build/hcc cc' + CXX='$(NSDEPTH)/build/hcpp CC' + MDCPUCFG_H=_unixware.cfg + else + AC_DEFINE(_LARGEFILE64_SOURCE) + AC_DEFINE(_PR_HAVE_OFF64_T) + AC_DEFINE(_PR_HAVE_SOCKADDR_LEN) + MDCPUCFG_H=_unixware7.cfg + fi + PR_MD_CSRCS=unixware.c + DSO_LDOPTS=-G + CPU_ARCH=x86 + ;; + +*-os2*) + AC_DEFINE(XP_OS2) + AC_DEFINE(XP_PC) + AC_DEFINE(BSD_SELECT) + AC_DEFINE(TCPV40HDRS) + LIB_SUFFIX=lib + DLL_SUFFIX=dll + RC=rc.exe + PR_MD_ARCH_DIR=os2 + PROG_SUFFIX=.exe + NSINSTALL=nsinstall + MDCPUCFG_H=_os2.cfg + RESOLVE_LINK_SYMBOLS=1 + + # EMX/GCC build + if test -n "$GNU_CC"; then + AC_DEFINE(XP_OS2_EMX) + AC_DEFINE(OS2) + AR=emxomfar + AR_FLAGS='r $@' + CFLAGS="$CFLAGS -Wall -Zomf" + CXXFLAGS="$CFLAGS -Wall -Zomf" + MKSHLIB='$(CC) $(DSO_LDOPTS) -o $@' + DSO_CFLAGS= + DSO_LDOPTS='-Zomf -Zdll -Zmap' + LDFLAGS='-Zmap' + _OPTIMIZE_FLAGS="-O2 -s" + _DEBUG_FLAGS="-g -fno-inline" + if test -n "$MOZ_OPTIMIZE"; then + DSO_LDOPTS="$DSO_LDOPTS -Zlinker /EXEPACK:2 -Zlinker /PACKCODE -Zlinker /PACKDATA" + fi + OS_LIBS="-lsocket" + IMPLIB='emximp -o' + FILTER='emxexp -o' + + # GCC for OS/2 currently predefines these, but we don't want them + DEFINES="$DEFINES -Uunix -U__unix -U__unix__" + + # Visual Age C++ build + elif test "$VACPP" = "yes"; then + AC_DEFINE(XP_OS2_VACPP) + AC_DEFINE(OS2,4) + AC_DEFINE(_X86_) + OBJ_SUFFIX=obj + AS=alp + ASFLAGS='-Mb' + ASM_SUFFIX=asm + AR=-ilib + AR_FLAGS='/NOL /NOI /O:$(subst /,\\,$@)' + CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + HOST_CFLAGS="$CFLAGS" + OS_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_EXE_CFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + CXXFLAGS='/Q /qlibansi /Gd+ /Gm+ /Su4 /Mp /Tl9' + OS_LIBS='so32dll.lib tcp32dll.lib' + LD='-ilink' + MKSHLIB='$(LD) $(DSO_LDOPTS)' + IMPLIB='implib -nologo -noignorecase' + FILTER='cppfilt -q -B -P' + _OPTIMIZE_FLAGS='/O+ /Gl+ /qtune=pentium /qarch=pentium' + _DEBUG_FLAGS='/Ti+ ' + LDFLAGS='/NOL /M /L' + DLLFLAGS='/O:$@ /DLL /INC:_dllentry /MAP:$(@:.dll=.map) /L /NOL' + EXEFLAGS='/OUT:$@ /PMTYPE:VIO /MAP:$(@:.exe=.map) /L /NOL' + if test -n "$MOZ_DEBUG"; then + LDFLAGS="$LDFLAGS /DE" + DLLFLAGS="$DLLFLAGS /DE" + EXEFLAGS="$EXEFLAGS /DE" + fi + if test -n "$MOZ_OPTIMIZE"; then + LDFLAGS="$LDFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + DLLFLAGS="$DLLFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + EXEFLAGS="$EXEFLAGS /OPTFUNC /EXEPACK:2 /PACKCODE /PACKDATA" + fi + LIBNSPR='$(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + LIBPLC='$(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX)' + fi + ;; + +*) + AC_DEFINE(XP_UNIX) + ;; + +esac + +if test -z "$SKIP_LIBRARY_CHECKS"; then +dnl ======================================================== +dnl Check for system libraries +dnl ======================================================== +dnl AC_CHECK_LIB(C, main) +dnl AC_CHECK_LIB(C_r, main) +dnl AC_CHECK_LIB(c, main) +dnl AC_CHECK_LIB(c_r, main) +dnl AC_CHECK_LIB(dce, main) +dnl AC_CHECK_LIB(dl, main) +dnl AC_CHECK_LIB(dld, main) +dnl AC_CHECK_LIB(gen, main) +dnl AC_CHECK_LIB(ip6, main) +dnl AC_CHECK_LIB(l, main) +dnl AC_CHECK_LIB(m, main) +dnl AC_CHECK_LIB(nsl, main) +dnl AC_CHECK_LIB(posix4, main) +dnl AC_CHECK_LIB(prstrms, main) +dnl AC_CHECK_LIB(prstrms_shr, main) +dnl AC_CHECK_LIB(pthread, main) +dnl AC_CHECK_LIB(pthreads, main) +dnl AC_CHECK_LIB(resolv, main) +dnl AC_CHECK_LIB(rt, main) +dnl AC_CHECK_LIB(socket, main) +dnl AC_CHECK_LIB(svld, main) +dnl AC_CHECK_LIB(thread, main) +dnl AC_CHECK_LIB(vms_jackets, main) + + +dnl We don't want anything to link with libdl even if it's present on OS X, +dnl since it's not used and not part of the default installation. + +case $target in +*-darwin*) + ;; +*) + AC_CHECK_LIB(dl, dlopen, + AC_CHECK_HEADER(dlfcn.h, + OS_LIBS="-ldl $OS_LIBS")) + ;; +esac + + +dnl ======================================================== +dnl Check for system header files. +dnl ======================================================== +dnl AC_HEADER_DIRENT +dnl AC_HEADER_STDC +dnl AC_HEADER_SYS_WAIT +dnl AC_CHECK_HEADERS(fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h unistd.h) + +dnl ======================================================== +dnl Check for typedefs and structs +dnl ======================================================== +dnl AC_C_CONST +dnl AC_TYPE_UID_T +dnl AC_TYPE_MODE_T +dnl AC_TYPE_OFF_T +dnl AC_TYPE_PID_T +dnl AC_TYPE_SIZE_T +dnl AC_STRUCT_ST_BLKSIZE +dnl AC_STRUCT_ST_BLOCKS +dnl AC_STRUCT_ST_RDEV +dnl AC_HEADER_TIME +dnl AC_STRUCT_TM + +dnl ======================================================== +dnl Checks for library functions. +dnl ======================================================== +AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNCS(lchown strerror) + +dnl AC_FUNC_MEMCMP +dnl AC_FUNC_MMAP +dnl AC_FUNC_SETVBUF_REVERSED +dnl AC_FUNC_STRCOLL +dnl AC_FUNC_STRFTIME +dnl AC_FUNC_UTIME_NULL +dnl AC_FUNC_VPRINTF +dnl AC_CHECK_FUNCS(ftime getcwd gethostname gettimeofday getwd mkdir mktime putenv rmdir select socket strdup strerror strstr strtol strtoul uname) + +dnl ======================================================== +dnl Check options +dnl ======================================================== + +dnl ======================================================== +dnl = +dnl = --enable-strip +dnl = +dnl = Enable stripping of libs and executables +dnl = +dnl ======================================================== +AC_ARG_ENABLE(strip, + [ --enable-strip Enable stripping of shared libs and programs], + [ if test "$enableval" = "yes"; then + ENABLE_STRIP=1 + fi ]) + +dnl Check for hpux options +case "${target_os}" in +hpux*) +if test -z "$GNU_CC"; then + + AC_CACHE_CHECK(for +Olit support, + ac_cv_hpux_usable_olit_option, + dnl since aCC doesn't throw an error on invalid options, + dnl we have to test this the hard way + [ac_cv_hpux_usable_olit_option=no + rm -f conftest* + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} ${CFLAGS} +Olit=all -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out`"; then + ac_cv_hpux_usable_olit_option=yes + fi + fi + rm -f conftest* + ]) + + if test "$ac_cv_hpux_usable_olit_option" = "yes"; then + CFLAGS="$CFLAGS +Olit=all" + CXXFLAGS="$CXXFLAGS +Olit=all" + else + CFLAGS="$CFLAGS +ESlit" + CXXFLAGS="$CXXFLAGS +ESlit" + fi +fi +;; +esac + +dnl +dnl Apparently, some systems cannot properly check for the pthread +dnl library unless is included so we need to test +dnl using it +dnl +dnl MOZ_CHECK_PTHREADS(lib, success, failure) +AC_DEFUN(MOZ_CHECK_PTHREADS, +[ +AC_MSG_CHECKING([for pthread_create in -l$1]) +echo " + #include + void *foo(void *v) { return v; } + int main() { + pthread_t t; + if (!pthread_create(&t, 0, &foo, 0)) { + pthread_join(t, 0); + } + return 0; + }" > dummy.c ; + echo "${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS" 1>&5; + ${CC-cc} -o dummy${ac_exeext} dummy.c $CFLAGS $CPPFLAGS -l[$1] $LDFLAGS $LIBS 2>&5; + _res=$? ; + rm -f dummy.c dummy${ac_exeext} ; + if test "$_res" = "0"; then + AC_MSG_RESULT([yes]) + [$2] + else + AC_MSG_RESULT([no]) + [$3] + fi +]) + +MOZ_CHECK_PTHREADS(pthreads, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthreads", + MOZ_CHECK_PTHREADS(pthread, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lpthread", + MOZ_CHECK_PTHREADS(c_r, + _HAVE_PTHREADS=1 _PTHREAD_LDFLAGS="-lc_r", + MOZ_CHECK_PTHREADS(c, + _HAVE_PTHREADS=1 + ) + ) + ) +) + +AC_ARG_WITH(pthreads, + [ --with-pthreads Use system pthreads library as thread subsystem], + [ if test "$withval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + else + AC_MSG_ERROR([ --with-pthreads specified for a system without pthread support ]); + fi + else + USE_PTHREADS= + _PTHREAD_LDFLAGS= + fi], + [ if test -n "$_HAVE_PTHREADS" && test -z "$USE_USER_PTHREADS" && test -z "$USE_NSPR_THREADS"; then + USE_PTHREADS=1 + USE_USER_PTHREADS= + USE_NSPR_THREADS= + fi]) + +AC_ARG_ENABLE(user-pthreads, + [ --enable-user-pthreads Build using userland pthreads], + [ if test "$enableval" = "yes"; then + if test -n "$_HAVE_PTHREADS"; then + USE_PTHREADS= + USE_USER_PTHREADS=1 + USE_NSPR_THREADS= + else + AC_MSG_ERROR([ --enable-user-pthreads specified for a system without pthread support ]); + fi + fi]) + +AC_ARG_ENABLE(nspr-threads, + [ --enable-nspr-threads Build using classic nspr threads], + [ if test "$enableval" = "yes"; then + USE_PTHREADS= + USE_USER_PTHREADS= + USE_NSPR_THREADS=1 + fi]) + +case "$target" in +*-beos*) + AC_ARG_WITH(bthreads, + [ --with-bthreads Use system bthreads library as thread subsystem (BeOS only)], + [ if test "$withval" = "yes"; then + USE_BTHREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi]) + ;; + +*-solaris*) + AC_ARG_WITH(native-threads, + [ --with-native-threads Use native system threads as thread subsystem (Solaris only)], + [ if test "$withval" = "yes"; then + USE_NATIVE_THREADS=1 + USE_USER_PTHREADS= + USE_PTHREADS= + fi]) + ;; +esac + +fi # SKIP_LIBRARY_CHECKS + +AC_ARG_ENABLE(cplus, + [ --enable-cplus Enable some c++ api routines], + [ if test "$enableval" = "yes"; then + USE_CPLUS=1 + fi]) + +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Compile ipv6 support], + [ if test "$enableval" = "yes"; then + USE_IPV6=1 + else + USE_IPV6= + fi]) + + +AC_ARG_ENABLE(boehm, + [ --enable-boehm Enable the Boehm Garbage Collector], + [ if test "$enableval" = "yes"; then + AC_DEFINE(GC_LEAK_DETECTOR) + GC_LEAK_DETECTOR=1 + fi]) + +if test -n "$USE_PTHREADS"; then + dnl See if -pthread is supported. + rm -f conftest* + ac_cv_have_dash_pthread=no + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthread) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthread -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthread`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthread=yes + case "$target_os" in + freebsd*) +# Freebsd doesn't use -pthread for compiles, it uses them for linking + ;; + *) + CFLAGS="$CFLAGS -pthread" + CXXFLAGS="$CXXFLAGS -pthread" + ;; + esac + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthread) + + dnl + dnl See if -pthreads is supported. + dnl + ac_cv_have_dash_pthreads=no + if test "$ac_cv_have_dash_pthread" = "no"; then + AC_MSG_CHECKING(whether ${CC-cc} accepts -pthreads) + echo 'int main() { return 0; }' | cat > conftest.c + ${CC-cc} -pthreads -o conftest conftest.c > conftest.out 2>&1 + if test $? -eq 0; then + if test -z "`egrep -i '(unrecognize|unknown)' conftest.out | grep pthreads`" && test -z "`egrep -i '(error|incorrect)' conftest.out`" ; then + ac_cv_have_dash_pthreads=yes + CFLAGS="$CFLAGS -pthreads" + CXXFLAGS="$CXXFLAGS -pthreads" + fi + fi + rm -f conftest* + AC_MSG_RESULT($ac_cv_have_dash_pthreads) + fi + + case "$target" in + *-solaris*) + if test "$ac_cv_have_dash_pthreads" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-freebsd*) + AC_DEFINE(_REENTRANT) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + else + _PTHREAD_LDFLAGS="-lc_r" + fi + ;; + *-netbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS="-pthread" + fi + ;; + *-bsdi*) + AC_DEFINE(_THREAD_SAFE) + dnl -pthread links in -lc_r, so don't specify it explicitly. + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS= + fi + ;; + *-openbsd*) + if test "$ac_cv_have_dash_pthread" = "yes"; then + _PTHREAD_LDFLAGS=-pthread + fi + ;; + *-linux*) + AC_DEFINE(_REENTRANT) + ;; + esac + +else + if test -n "$USE_USER_PTHREADS"; then + USE_PTHREADS= + USE_NSPR_THREADS= + else + _PTHREAD_LDFLAGS= + fi +fi +dnl Special thread exceptions + +case "$target" in +*-aix*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + case "$target_os" in + aix4.1*) + if test -z "$USE_PTHREADS"; then + AC_DEFINE(AIX_RENAME_SELECT) + fi + ;; + aix4.2*) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + ;; + aix4.3*) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + ;; + *) + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + fi + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + ;; + esac + ;; +*-bsdi*) + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_NEED_PTHREAD_INIT) + fi + ;; +*-freebsd*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-hpux*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + if test "$USE_PTHREADS"; then + if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(_PR_DCETHREADS) + else + AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L) + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + fi + if test "$USE_USER_PTHREADS"; then + AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L) + fi + ;; +*-irix*) + if test "${target_os}" = "irix6.5"; then + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_GETHOST_R) + AC_DEFINE(_PR_HAVE_GETHOST_R_POINTER) + fi + fi + ;; +*-linux*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-mingw*|*-cygwin*|*-msvc*|*-mks*) + dnl win32 does not use pthreads + USE_PTHREADS= + _PTHREAD_LDFLAGS= + USE_USER_PTHREADS= + ;; +*-netbsd*|*-openbsd*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + ;; +*-osf*) + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + if test -n "$USE_PTHREADS"; then + if echo $OS_RELEASE | egrep -c '(V2.0|V3.2)' 2>/dev/null; then + : + else + AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST) + fi + fi + ;; +*-solaris*) + if test -n "$USE_NATIVE_THREADS"; then + AC_DEFINE(_PR_GLOBAL_THREADS_ONLY) + else + if test -n "$USE_NSPR_THREADS"; then + AC_DEFINE(_PR_LOCAL_THREADS_ONLY) + fi + fi + if test -z "$USE_NSPR_THREADS"; then + AC_DEFINE(_REENTRANT) + AC_DEFINE(HAVE_POINTER_LOCALTIME_R) + if test "$OS_TEST" = "i86pc"; then + PR_MD_ASFILES=os_SunOS_x86.s + else + PR_MD_ASFILES=os_SunOS.s + if test -n "$USE_64"; then + PR_MD_ASFILES="$PR_MD_ASFILES os_SunOS_sparcv9.s" + fi + fi + fi + ;; +*-nto*) + if test -n "$USE_PTHREADS"; then + AC_DEFINE(_PR_HAVE_GETHOST_R) + AC_DEFINE(_PR_HAVE_GETHOST_R_POINTER) + fi + ;; +esac + +OS_LIBS="$_PTHREAD_LDFLAGS $OS_LIBS" + +dnl If the user passed in arg to --enable-optimize, +dnl make sure that we use it. +if test -n "$_SAVE_OPTIMIZE_FLAGS"; then + _OPTIMIZE_FLAGS="$_SAVE_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + CFLAGS="$CFLAGS $_OPTIMIZE_FLAGS" + CXXFLAGS="$CXXFLAGS $_OPTIMIZE_FLAGS" +fi + +if test -n "$MOZ_DEBUG"; then + CFLAGS="$CFLAGS $_DEBUG_FLAGS" + CXXFLAGS="$CXXFLAGS $_DEBUG_FLAGS" +fi + +if test -n "$MOZ_OPTIMIZE"; then + OBJDIR_TAG=_OPT +else + OBJDIR_TAG=_DBG +fi + +if test -n "$USE_64"; then + COMPILER_TAG=_64 +fi + +RELEASE_OBJDIR_NAME="${OS_CONFIG}${CPU_ARCH_TAG}${COMPILER_TAG}${IMPL_STRATEGY}${OBJDIR_TAG}.${OBJDIR_SUFFIX}" + +dnl ======================================================== +dnl Use cygwin wrapper for win32 builds +dnl ======================================================== +case "$target_os" in +mingw*|cygwin*|msvc*|mks*) + CC="\$(CYGWIN_WRAPPER) $CC" + CXX="\$(CYGWIN_WRAPPER) $CXX" + RC="\$(CYGWIN_WRAPPER) $RC" + ;; +esac + +dnl ======================================================== +dnl Substitution of found variables. +dnl ======================================================== +AC_SUBST(SHELL_OVERRIDE) + +AC_SUBST(MOZILLA_CLIENT) +AC_SUBST(CC) +AC_SUBST(CXX) +AC_SUBST(CFLAGS) +AC_SUBST(CXXFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(HOST_CC) +AC_SUBST(HOST_CFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(GNU_CC) +AC_SUBST(GCC_USE_GNU_LD) +AC_SUBST(MSC_VER) +AC_SUBST(CROSS_COMPILE) + +AC_SUBST(MOZ_OPTIMIZE) + +AC_SUBST(USE_CPLUS) +AC_SUBST(USE_IPV6) +AC_SUBST(USE_N32) +AC_SUBST(USE_64) +AC_SUBST(OBJECT_MODE) +AC_SUBST(GC_LEAK_DETECTOR) +AC_SUBST(ENABLE_STRIP) + +AC_SUBST(USE_PTHREADS) +AC_SUBST(USE_BTHREADS) +AC_SUBST(USE_USER_PTHREADS) +AC_SUBST(USE_NATIVE_THREADS) +AC_SUBST(USE_NSPR_THREADS) + +AC_SUBST(LIBNSPR) +AC_SUBST(LIBPLC) + +AC_SUBST(MOD_MAJOR_VERSION) +AC_SUBST(MOD_MINOR_VERSION) +AC_SUBST(MOD_PATCH_VERSION) +AC_SUBST(NSPR_MODNAME) +AC_SUBST(MDCPUCFG_H) +AC_SUBST(PR_MD_CSRCS) +AC_SUBST(PR_MD_ASFILES) +AC_SUBST(PR_MD_ARCH_DIR) +AC_SUBST(CPU_ARCH) + +AC_SUBST(OBJ_SUFFIX) +AC_SUBST(LIB_SUFFIX) +AC_SUBST(DLL_SUFFIX) +AC_SUBST(ASM_SUFFIX) +AC_SUBST(MKSHLIB) +AC_SUBST(DSO_CFLAGS) +AC_SUBST(DSO_LDOPTS) + +AC_SUBST(OS_TARGET) +AC_SUBST(OS_ARCH) +AC_SUBST(OS_RELEASE) +AC_SUBST(OS_TEST) +AC_SUBST(MACOS_DEPLOYMENT_TARGET) + +AC_SUBST(DEFINES) +AC_SUBST(DEFS) +AC_SUBST(AR) +AC_SUBST(AR_FLAGS) +AC_SUBST(AS) +AC_SUBST(ASFLAGS) +AC_SUBST(LD) +AC_SUBST(RANLIB) +AC_SUBST(PERL) +AC_SUBST(STRIP) +AC_SUBST(FILTER) +AC_SUBST(IMPLIB) + +AC_SUBST(OS_LIBS) +AC_SUBST(RESOLVE_LINK_SYMBOLS) +AC_SUBST(AIX_LINK_OPTS) +AC_SUBST(NOSUCHFILE) +AC_SUBST(MOZ_OBJFORMAT) +AC_SUBST(ULTRASPARC_LIBRARY) + +AC_SUBST(OBJDIR) +AC_SUBST(OBJDIR_NAME) +AC_SUBST(RELEASE_OBJDIR_NAME) +AC_SUBST(NSINSTALL) +AC_SUBST(OPTIMIZER) +AC_SUBST(RC) +AC_SUBST(RCFLAGS) +AC_SUBST(DLLFLAGS) +AC_SUBST(EXEFLAGS) +AC_SUBST(OS_DLLFLAGS) +AC_SUBST(CYGWIN_WRAPPER) + +dnl ======================================================== +dnl Generate output files. +dnl ======================================================== +MAKEFILES=" +Makefile +config/Makefile +config/autoconf.mk +config/nsprincl.mk +config/nsprincl.sh +config/nspr-config +lib/Makefile +lib/ds/Makefile +lib/libc/Makefile +lib/libc/include/Makefile +lib/libc/src/Makefile +lib/tests/Makefile +pkg/Makefile +pkg/linux/Makefile +pkg/solaris/Makefile +pkg/solaris/SUNWpr/Makefile +pkg/solaris/SUNWprx/Makefile +pr/Makefile +pr/include/Makefile +pr/include/md/Makefile +pr/include/obsolete/Makefile +pr/include/private/Makefile +pr/src/Makefile +pr/src/io/Makefile +pr/src/linking/Makefile +pr/src/malloc/Makefile +pr/src/md/Makefile +pr/src/md/${PR_MD_ARCH_DIR}/Makefile +pr/src/memory/Makefile +pr/src/misc/Makefile +pr/src/threads/Makefile +pr/tests/Makefile +pr/tests/dll/Makefile +" + +dnl lib/tests/Makefile +dnl pr/tests/w16gui/Makefile +dnl tools/Makefile + +if test -z "$USE_PTHREADS" && test -z "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/threads/combined/Makefile" +elif test -n "$USE_PTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/pthreads/Makefile" +elif test -n "$USE_BTHREADS"; then + MAKEFILES="$MAKEFILES pr/src/bthreads/Makefile" +fi + +if test -n "$USE_CPLUS"; then + MAKEFILES="$MAKEFILES pr/src/cplus/Makefile pr/src/cplus/tests/Makefile" +fi + +AC_OUTPUT([$MAKEFILES], [chmod +x config/nspr-config]) diff --git a/src/libs/xpcom18a4/nsprpub/gmakefile.win b/src/libs/xpcom18a4/nsprpub/gmakefile.win new file mode 100644 index 00000000..80e8809a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/gmakefile.win @@ -0,0 +1,96 @@ +#!gmake +# -*- Mode: Makefile -*- +# +# ***** 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) 2001 +# 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 MOZ_SRC_FLIPPED +$(error MOZ_SRC_FLIPPED is not set) +endif + +ifndef MOZ_TOP +MOZ_TOP=mozilla +endif + +MOZ_DIST_FLIPPED = $(MOZ_SRC_FLIPPED)/mozilla/dist + +ifdef MOZ_DEBUG +MOZ_OBJDIR = WIN32_D.OBJ +else +MOZ_OBJDIR = WIN32_O.OBJ +endif + +NSPR_CONFIGURE := ../configure \ + --with-mozilla \ + --with-dist-prefix=$(MOZ_DIST_FLIPPED) \ + --with-dist-bindir=$(MOZ_DIST_FLIPPED)/$(MOZ_OBJDIR)/bin \ + --with-dist-libdir=$(MOZ_DIST_FLIPPED)/$(MOZ_OBJDIR)/lib + +ifeq (,$(MOZ_DEBUG)$(MOZ_TRACE_MALLOC)) +NSPR_CONFIGURE := $(NSPR_CONFIGURE) --enable-optimize --disable-debug +endif + +define MAKE_OBJDIR +if test ! -d $(@D) ; then rm -rf $(@D) ; nsinstall -D $(@D) ; fi +endef + + +all:: build_all + +# Argh. nmake keeps the cwd from cmd to cmd and gmake does not +# Furthermore, shmsdos doesn't support '&&' so there's a chance the +# 'cd' could fail and configure would be run in the wrong dir +# +$(MOZ_OBJDIR)/config.status: configure configure.in + @$(MAKE_OBJDIR) + cd $(MOZ_OBJDIR)/ ; \ + sh $(NSPR_CONFIGURE) + +build_all: $(MOZ_OBJDIR)/config.status check_old + gmake -C $(MOZ_OBJDIR) + +clobber_all: $(MOZ_OBJDIR)/config.status check_old + gmake -C $(MOZ_OBJDIR) clobber_all + +distclean: check_old + rm -rf WIN32_D.OBJ WIN32_O.OBJ + +check_old: + @if test -f Makefile; then gmake distclean; fi + + + diff --git a/src/libs/xpcom18a4/nsprpub/lib/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/Makefile.in new file mode 100644 index 00000000..9bdc078e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +export NSPR20=1 + +include $(topsrcdir)/config/config.mk + +DIRS = ds libc + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/ds/.cvsignore new file mode 100644 index 00000000..bcab60f5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pl_bld.h diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/MANIFEST b/src/libs/xpcom18a4/nsprpub/lib/ds/MANIFEST new file mode 100644 index 00000000..ceda33b7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/MANIFEST @@ -0,0 +1,7 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +plarenas.h +plarena.h +plhash.h diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/ds/Makefile.in new file mode 100644 index 00000000..516e1a37 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/Makefile.in @@ -0,0 +1,202 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include + +CSRCS = \ + plarena.c \ + plhash.c \ + plvrsion.c \ + $(NULL) + +HEADERS = \ + plarenas.h \ + plarena.h \ + plhash.h \ + $(NULL) + +HEADERS := $(addprefix $(srcdir)/, $(HEADERS)) + +ifeq ($(OS_ARCH), WINNT) +ifdef NS_USE_GCC +DLLBASE=-Wl,--image-base -Wl,0x30000000 +else +DLLBASE=/BASE:0x30000000 +endif # GCC +RES=$(OBJDIR)/plds.res +RESNAME=plds.rc +endif # WINNT + +ifeq ($(OS_ARCH), AIX) +ifeq ($(CLASSIC_NSPR),1) +OS_LIBS = -lc +else +OS_LIBS = -lc_r +endif +endif + +ifeq ($(OS_ARCH),IRIX) +OS_LIBS = -lc +endif + +ifeq ($(OS_ARCH),SunOS) +OS_LIBS = -lc +MAPFILE = $(OBJDIR)/pldsmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# The -R '$ORIGIN' linker option instructs this library to search for its +# dependencies in the same directory where it resides. +MKSHLIB += -R '$$ORIGIN' +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the .o files. +ifeq ($(OS_ARCH),NCR) +EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) +EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +LIBRARY_NAME = plds +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(HEADERS) $(MOZ_INCL) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + + diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.c b/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.c new file mode 100644 index 00000000..e61efbe2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.c @@ -0,0 +1,442 @@ +/* -*- 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. 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 ***** + */ + +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + */ +#include +#include +#include "plarena.h" +#include "prmem.h" +#include "prbit.h" +#include "prlog.h" +#include "prlock.h" +#include "prinit.h" + +static PLArena *arena_freelist; + +#ifdef PL_ARENAMETER +static PLArenaStats *arena_stats_list; + +#define COUNT(pool,what) (pool)->stats.what++ +#else +#define COUNT(pool,what) /* nothing */ +#endif + +#define PL_ARENA_DEFAULT_ALIGN sizeof(double) + +static PRLock *arenaLock; +static PRCallOnceType once; + +/* +** InitializeArenas() -- Initialize arena operations. +** +** InitializeArenas() is called exactly once and only once from +** LockArena(). This function creates the arena protection +** lock: arenaLock. +** +** Note: If the arenaLock cannot be created, InitializeArenas() +** fails quietly, returning only PR_FAILURE. This percolates up +** to the application using the Arena API. He gets no arena +** from PL_ArenaAllocate(). It's up to him to fail gracefully +** or recover. +** +*/ +static PRStatus InitializeArenas( void ) +{ + PR_ASSERT( arenaLock == NULL ); + arenaLock = PR_NewLock(); + if ( arenaLock == NULL ) + return PR_FAILURE; + else + return PR_SUCCESS; +} /* end ArenaInitialize() */ + +static PRStatus LockArena( void ) +{ + PRStatus rc = PR_CallOnce( &once, InitializeArenas ); + + if ( PR_FAILURE != rc ) + PR_Lock( arenaLock ); + return(rc); +} /* end LockArena() */ + +static void UnlockArena( void ) +{ + PR_Unlock( arenaLock ); + return; +} /* end UnlockArena() */ + +PR_IMPLEMENT(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align) +{ +#if defined(XP_MAC) +#pragma unused (name) +#endif + + if (align == 0) + align = PL_ARENA_DEFAULT_ALIGN; + pool->mask = PR_BITMASK(PR_CeilingLog2(align)); + pool->first.next = NULL; + /* Set all three addresses in pool->first to the same dummy value. + * These addresses are only compared with each other, but never + * dereferenced. */ + pool->first.base = pool->first.avail = pool->first.limit = + (PRUword)PL_ARENA_ALIGN(pool, &pool->first + 1); + pool->current = &pool->first; + pool->arenasize = size; +#ifdef PL_ARENAMETER + memset(&pool->stats, 0, sizeof pool->stats); + pool->stats.name = strdup(name); + pool->stats.next = arena_stats_list; + arena_stats_list = &pool->stats; +#endif +} + + +/* +** PL_ArenaAllocate() -- allocate space from an arena pool +** +** Description: PL_ArenaAllocate() allocates space from an arena +** pool. +** +** First, try to satisfy the request from arenas starting at +** pool->current. +** +** If there is not enough space in the arena pool->current, try +** to claim an arena, on a first fit basis, from the global +** freelist (arena_freelist). +** +** If no arena in arena_freelist is suitable, then try to +** allocate a new arena from the heap. +** +** Returns: pointer to allocated space or NULL +** +** Notes: The original implementation had some difficult to +** solve bugs; the code was difficult to read. Sometimes it's +** just easier to rewrite it. I did that. larryh. +** +** See also: bugzilla: 45343. +** +*/ + +PR_IMPLEMENT(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb) +{ + PLArena *a; + char *rp; /* returned pointer */ + PRUint32 nbOld; + + PR_ASSERT((nb & pool->mask) == 0); + + nbOld = nb; + nb = (PRUword)PL_ARENA_ALIGN(pool, nb); /* force alignment */ + if (nb < nbOld) + return NULL; + + /* attempt to allocate from arenas at pool->current */ + { + a = pool->current; + do { + if ( a->avail +nb <= a->limit ) { + pool->current = a; + rp = (char *)a->avail; + a->avail += nb; + return rp; + } + } while( NULL != (a = a->next) ); + } + + /* attempt to allocate from arena_freelist */ + { + PLArena *p; /* previous pointer, for unlinking from freelist */ + + /* lock the arena_freelist. Make access to the freelist MT-Safe */ + if ( PR_FAILURE == LockArena()) + return(0); + + for ( a = p = arena_freelist; a != NULL ; p = a, a = a->next ) { + if ( a->base +nb <= a->limit ) { + if ( p == arena_freelist ) + arena_freelist = a->next; + else + p->next = a->next; + UnlockArena(); + a->avail = a->base; + rp = (char *)a->avail; + a->avail += nb; + /* the newly allocated arena is linked after pool->current + * and becomes pool->current */ + a->next = pool->current->next; + pool->current->next = a; + pool->current = a; + if ( NULL == pool->first.next ) + pool->first.next = a; + return(rp); + } + } + UnlockArena(); + } + + /* attempt to allocate from the heap */ + { + PRUint32 sz = PR_MAX(pool->arenasize, nb); + sz += sizeof *a + pool->mask; /* header and alignment slop */ + a = (PLArena*)PR_MALLOC(sz); + if ( NULL != a ) { + a->limit = (PRUword)a + sz; + a->base = a->avail = (PRUword)PL_ARENA_ALIGN(pool, a + 1); + rp = (char *)a->avail; + a->avail += nb; + PR_ASSERT(a->avail <= a->limit); + /* the newly allocated arena is linked after pool->current + * and becomes pool->current */ + a->next = pool->current->next; + pool->current->next = a; + pool->current = a; + if ( NULL == pool->first.next ) + pool->first.next = a; + PL_COUNT_ARENA(pool,++); + COUNT(pool, nmallocs); + return(rp); + } + } + + /* we got to here, and there's no memory to allocate */ + return(NULL); +} /* --- end PL_ArenaAllocate() --- */ + +PR_IMPLEMENT(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr) +{ + void *newp; + + if (PR_UINT32_MAX - size < incr) + return NULL; + PL_ARENA_ALLOCATE(newp, pool, size + incr); + if (newp) + memcpy(newp, p, size); + return newp; +} + +/* + * Free tail arenas linked after head, which may not be the true list head. + * Reset pool->current to point to head in case it pointed at a tail arena. + */ +static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree) +{ + PLArena **ap, *a; + + ap = &head->next; + a = *ap; + if (!a) + return; + +#ifdef DEBUG + do { + PR_ASSERT(a->base <= a->avail && a->avail <= a->limit); + a->avail = a->base; + PL_CLEAR_UNUSED(a); + } while ((a = a->next) != 0); + a = *ap; +#endif + + if (reallyFree) { + do { + *ap = a->next; + PL_CLEAR_ARENA(a); + PL_COUNT_ARENA(pool,--); + PR_DELETE(a); + } while ((a = *ap) != 0); + } else { + /* Insert the whole arena chain at the front of the freelist. */ + do { + ap = &(*ap)->next; + } while (*ap); + LockArena(); + *ap = arena_freelist; + arena_freelist = a; + head->next = 0; + UnlockArena(); + } + + pool->current = head; +} + +PR_IMPLEMENT(void) PL_ArenaRelease(PLArenaPool *pool, char *mark) +{ + PLArena *a; + + for (a = pool->first.next; a; a = a->next) { + if (PR_UPTRDIFF(mark, a->base) < PR_UPTRDIFF(a->avail, a->base)) { + a->avail = (PRUword)PL_ARENA_ALIGN(pool, mark); + FreeArenaList(pool, a, PR_FALSE); + return; + } + } +} + +PR_IMPLEMENT(void) PL_FreeArenaPool(PLArenaPool *pool) +{ + FreeArenaList(pool, &pool->first, PR_FALSE); + COUNT(pool, ndeallocs); +} + +PR_IMPLEMENT(void) PL_FinishArenaPool(PLArenaPool *pool) +{ + FreeArenaList(pool, &pool->first, PR_TRUE); +#ifdef PL_ARENAMETER + { + PLArenaStats *stats, **statsp; + + if (pool->stats.name) + PR_DELETE(pool->stats.name); + for (statsp = &arena_stats_list; (stats = *statsp) != 0; + statsp = &stats->next) { + if (stats == &pool->stats) { + *statsp = stats->next; + return; + } + } + } +#endif +} + +PR_IMPLEMENT(void) PL_CompactArenaPool(PLArenaPool *ap) +{ +#if XP_MAC +#pragma unused (ap) +#if 0 + PRArena *curr = &(ap->first); + while (curr) { + reallocSmaller(curr, curr->avail - (uprword_t)curr); + curr->limit = curr->avail; + curr = curr->next; + } +#endif +#endif +} + +PR_IMPLEMENT(void) PL_ArenaFinish(void) +{ + PLArena *a, *next; + + for (a = arena_freelist; a; a = next) { + next = a->next; + PR_DELETE(a); + } + arena_freelist = NULL; + + if (arenaLock) { + PR_DestroyLock(arenaLock); + arenaLock = NULL; + } +} + +#ifdef PL_ARENAMETER +PR_IMPLEMENT(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb) +{ + pool->stats.nallocs++; + pool->stats.nbytes += nb; + if (nb > pool->stats.maxalloc) + pool->stats.maxalloc = nb; + pool->stats.variance += nb * nb; +} + +PR_IMPLEMENT(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr) +{ + pool->stats.ninplace++; +} + +PR_IMPLEMENT(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr) +{ + pool->stats.ngrows++; + pool->stats.nbytes += incr; + pool->stats.variance -= size * size; + size += incr; + if (size > pool->stats.maxalloc) + pool->stats.maxalloc = size; + pool->stats.variance += size * size; +} + +PR_IMPLEMENT(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark) +{ + pool->stats.nreleases++; +} + +PR_IMPLEMENT(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark) +{ + pool->stats.nfastrels++; +} + +#include +#include + +PR_IMPLEMENT(void) PL_DumpArenaStats(FILE *fp) +{ + PLArenaStats *stats; + double mean, variance; + + for (stats = arena_stats_list; stats; stats = stats->next) { + if (stats->nallocs != 0) { + mean = (double)stats->nbytes / stats->nallocs; + variance = fabs(stats->variance / stats->nallocs - mean * mean); + } else { + mean = variance = 0; + } + + fprintf(fp, "\n%s allocation statistics:\n", stats->name); + fprintf(fp, " number of arenas: %u\n", stats->narenas); + fprintf(fp, " number of allocations: %u\n", stats->nallocs); + fprintf(fp, " number of free arena reclaims: %u\n", stats->nreclaims); + fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs); + fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs); + fprintf(fp, " number of allocation growths: %u\n", stats->ngrows); + fprintf(fp, " number of in-place growths: %u\n", stats->ninplace); + fprintf(fp, "number of released allocations: %u\n", stats->nreleases); + fprintf(fp, " number of fast releases: %u\n", stats->nfastrels); + fprintf(fp, " total bytes allocated: %u\n", stats->nbytes); + fprintf(fp, " mean allocation size: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sqrt(variance)); + fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc); + } +} +#endif /* PL_ARENAMETER */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.h b/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.h new file mode 100644 index 00000000..174bd975 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plarena.h @@ -0,0 +1,219 @@ +/* -*- 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. 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 plarena_h___ +#define plarena_h___ +/* + * Lifetime-based fast allocation, inspired by much prior art, including + * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" + * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). + * + * Also supports LIFO allocation (PL_ARENA_MARK/PL_ARENA_RELEASE). + */ +#include "prtypes.h" +#include "plarenas.h" + +PR_BEGIN_EXTERN_C + +typedef struct PLArena PLArena; + +struct PLArena { + PLArena *next; /* next arena for this lifetime */ + PRUword base; /* aligned base address, follows this header */ + PRUword limit; /* one beyond last byte in arena */ + PRUword avail; /* points to next available byte */ +}; + +#ifdef PL_ARENAMETER +typedef struct PLArenaStats PLArenaStats; + +struct PLArenaStats { + PLArenaStats *next; /* next in arenaStats list */ + char *name; /* name for debugging */ + PRUint32 narenas; /* number of arenas in pool */ + PRUint32 nallocs; /* number of PL_ARENA_ALLOCATE() calls */ + PRUint32 nreclaims; /* number of reclaims from freeArenas */ + PRUint32 nmallocs; /* number of malloc() calls */ + PRUint32 ndeallocs; /* number of lifetime deallocations */ + PRUint32 ngrows; /* number of PL_ARENA_GROW() calls */ + PRUint32 ninplace; /* number of in-place growths */ + PRUint32 nreleases; /* number of PL_ARENA_RELEASE() calls */ + PRUint32 nfastrels; /* number of "fast path" releases */ + PRUint32 nbytes; /* total bytes allocated */ + PRUint32 maxalloc; /* maximum allocation size in bytes */ + PRFloat64 variance; /* size variance accumulator */ +}; +#endif + +struct PLArenaPool { + PLArena first; /* first arena in pool list */ + PLArena *current; /* arena from which to allocate space */ + PRUint32 arenasize; /* net exact size of a new arena */ + PRUword mask; /* alignment mask (power-of-2 - 1) */ +#ifdef PL_ARENAMETER + PLArenaStats stats; +#endif +}; + +/* + * If the including .c file uses only one power-of-2 alignment, it may define + * PL_ARENA_CONST_ALIGN_MASK to the alignment mask and save a few instructions + * per ALLOCATE and GROW. + */ +#ifdef PL_ARENA_CONST_ALIGN_MASK +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + PL_ARENA_CONST_ALIGN_MASK) \ + & ~PL_ARENA_CONST_ALIGN_MASK) + +#define PL_INIT_ARENA_POOL(pool, name, size) \ + PL_InitArenaPool(pool, name, size, PL_ARENA_CONST_ALIGN_MASK + 1) +#else +#define PL_ARENA_ALIGN(pool, n) (((PRUword)(n) + (pool)->mask) & ~(pool)->mask) +#endif + +#define PL_ARENA_ALLOCATE(p, pool, nb) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _nb = PL_ARENA_ALIGN(pool, (PRUint32)nb); \ + PRUword _p = _a->avail; \ + if (_nb < (PRUint32)nb) { \ + _p = 0; \ + } else if (_nb > (_a->limit - _a->avail)) { \ + _p = (PRUword)PL_ArenaAllocate(pool, _nb); \ + } else { \ + _a->avail += _nb; \ + } \ + p = (void *)_p; \ + if (p) { \ + PL_ArenaCountAllocation(pool, nb); \ + } \ + PR_END_MACRO + +#define PL_ARENA_GROW(p, pool, size, incr) \ + PR_BEGIN_MACRO \ + PLArena *_a = (pool)->current; \ + PRUint32 _incr = PL_ARENA_ALIGN(pool, (PRUint32)incr); \ + if (_incr < (PRUint32)incr) { \ + p = NULL; \ + } else if (_a->avail == (PRUword)(p) + PL_ARENA_ALIGN(pool, size) && \ + _incr <= (_a->limit - _a->avail)) { \ + _a->avail = _incr; \ + PL_ArenaCountInplaceGrowth(pool, size, (RTUint32)incr); \ + } else { \ + p = PL_ArenaGrow(pool, p, size, (PRUint32)incr); \ + } \ + if (p) { \ + PL_ArenaCountGrowth(pool, size, (PRUint32)incr); \ + } \ + PR_END_MACRO + +#define PL_ARENA_MARK(pool) ((void *) (pool)->current->avail) +#define PR_UPTRDIFF(p,q) ((PRUword)(p) - (PRUword)(q)) + +#ifdef DEBUG +#define PL_FREE_PATTERN 0xDA +#define PL_CLEAR_UNUSED(a) (PR_ASSERT((a)->avail <= (a)->limit), \ + memset((void*)(a)->avail, PL_FREE_PATTERN, \ + (a)->limit - (a)->avail)) +#define PL_CLEAR_ARENA(a) memset((void*)(a), PL_FREE_PATTERN, \ + (a)->limit - (PRUword)(a)) +#else +#define PL_CLEAR_UNUSED(a) +#define PL_CLEAR_ARENA(a) +#endif + +#define PL_ARENA_RELEASE(pool, mark) \ + PR_BEGIN_MACRO \ + char *_m = (char *)(mark); \ + PLArena *_a = (pool)->current; \ + if (PR_UPTRDIFF(_m, _a->base) <= PR_UPTRDIFF(_a->avail, _a->base)) { \ + _a->avail = (PRUword)PL_ARENA_ALIGN(pool, _m); \ + PL_CLEAR_UNUSED(_a); \ + PL_ArenaCountRetract(pool, _m); \ + } else { \ + PL_ArenaRelease(pool, _m); \ + } \ + PL_ArenaCountRelease(pool, _m); \ + PR_END_MACRO + +#ifdef PL_ARENAMETER +#define PL_COUNT_ARENA(pool,op) ((pool)->stats.narenas op) +#else +#define PL_COUNT_ARENA(pool,op) +#endif + +#define PL_ARENA_DESTROY(pool, a, pnext) \ + PR_BEGIN_MACRO \ + PL_COUNT_ARENA(pool,--); \ + if ((pool)->current == (a)) (pool)->current = &(pool)->first; \ + *(pnext) = (a)->next; \ + PL_CLEAR_ARENA(a); \ + free(a); \ + (a) = 0; \ + PR_END_MACRO + +#ifdef PL_ARENAMETER + +#include + +PR_EXTERN(void) PL_ArenaCountAllocation(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void) PL_ArenaCountInplaceGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountGrowth( + PLArenaPool *pool, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaCountRelease(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_ArenaCountRetract(PLArenaPool *pool, char *mark); + +PR_EXTERN(void) PL_DumpArenaStats(FILE *fp); + +#else /* !PL_ARENAMETER */ + +#define PL_ArenaCountAllocation(ap, nb) /* nothing */ +#define PL_ArenaCountInplaceGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountGrowth(ap, size, incr) /* nothing */ +#define PL_ArenaCountRelease(ap, mark) /* nothing */ +#define PL_ArenaCountRetract(ap, mark) /* nothing */ + +#endif /* !PL_ARENAMETER */ + +PR_END_EXTERN_C + +#endif /* plarena_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plarenas.h b/src/libs/xpcom18a4/nsprpub/lib/ds/plarenas.h new file mode 100644 index 00000000..8e8a1137 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plarenas.h @@ -0,0 +1,126 @@ +/* -*- 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 ***** */ + +#if defined(PLARENAS_H) +#else /* defined(PLARENAS_H) */ +#define PLARENAS_H + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_ArenaAllocate VBoxNsplPL_ArenaAllocate +#define PL_ArenaFinish VBoxNsplPL_ArenaFinish +#define PL_ArenaGrow VBoxNsplPL_ArenaGrow +#define PL_ArenaRelease VBoxNsplPL_ArenaRelease +#define PL_CompactArenaPool VBoxNsplPL_CompactArenaPool +#define PL_FinishArenaPool VBoxNsplPL_FinishArenaPool +#define PL_FreeArenaPool VBoxNsplPL_FreeArenaPool +#define PL_InitArenaPool VBoxNsplPL_InitArenaPool +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PLArenaPool PLArenaPool; + +/* +** Allocate an arena pool as specified by the parameters. +** +** This is equivelant to allocating the space yourself and then +** calling PL_InitArenaPool(). +** +** This function may fail (and return a NULL) for a variety of +** reasons. The reason for a particular failure can be discovered +** by calling PR_GetError(). +*/ +#if 0 /* Not implemented */ +PR_EXTERN(PLArenaPool*) PL_AllocArenaPool( + const char *name, PRUint32 size, PRUint32 align); +#endif + +/* +** Destroy an arena pool previously allocated by PL_AllocArenaPool(). +** +** This function may fail if the arena is not empty and the caller +** wishes to check for empty upon descruction. +*/ +#if 0 /* Not implemented */ +PR_EXTERN(PRStatus) PL_DestroyArenaPool(PLArenaPool *pool, PRBool checkEmpty); +#endif + + +/* +** Initialize an arena pool with the given name for debugging and metering, +** with a minimum size per arena of size bytes. +**/ +PR_EXTERN(void) PL_InitArenaPool( + PLArenaPool *pool, const char *name, PRUint32 size, PRUint32 align); + +/* +** Finish using arenas, freeing all memory associated with them. +**/ +PR_EXTERN(void) PL_ArenaFinish(void); + +/* +** Free the arenas in pool. The user may continue to allocate from pool +** after calling this function. There is no need to call PL_InitArenaPool() +** again unless PL_FinishArenaPool(pool) has been called. +**/ +PR_EXTERN(void) PL_FreeArenaPool(PLArenaPool *pool); + +/* +** Free the arenas in pool and finish using it altogether. +**/ +PR_EXTERN(void) PL_FinishArenaPool(PLArenaPool *pool); + +/* +** Compact all of the arenas in a pool so that no space is wasted. +**/ +PR_EXTERN(void) PL_CompactArenaPool(PLArenaPool *pool); + +/* +** Friend functions used by the PL_ARENA_*() macros. +**/ +PR_EXTERN(void *) PL_ArenaAllocate(PLArenaPool *pool, PRUint32 nb); + +PR_EXTERN(void *) PL_ArenaGrow( + PLArenaPool *pool, void *p, PRUint32 size, PRUint32 incr); + +PR_EXTERN(void) PL_ArenaRelease(PLArenaPool *pool, char *mark); + +PR_END_EXTERN_C + +#endif /* defined(PLARENAS_H) */ + +/* plarenas */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plds.def b/src/libs/xpcom18a4/nsprpub/lib/ds/plds.def new file mode 100644 index 00000000..9e0b505a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plds.def @@ -0,0 +1,78 @@ +;+# +;+# 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 Netscape are +;+# Copyright (C) 2002-2003 Netscape Communications Corporation. All +;+# Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the +;+# terms of the GNU General Public License Version 2 or later (the +;+# "GPL"), in which case the provisions of the GPL are applicable +;+# instead of those above. If you wish to allow use of your +;+# version of this file only under the terms of the GPL and not to +;+# allow others to use your version of this file under the MPL, +;+# indicate your decision by deleting the provisions above and +;+# replace them with the notice and other provisions required by +;+# the GPL. If you do not delete the provisions above, a recipient +;+# may use your version of this file under either the MPL or the +;+# GPL. +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+NSPR_4.0 { +;+ global: +LIBRARY plds4 ;- +EXPORTS ;- +PL_ArenaAllocate; +PL_ArenaFinish; +PL_ArenaGrow; +PL_ArenaRelease; +PL_CompactArenaPool; +PL_CompareStrings; +PL_CompareValues; +PL_FinishArenaPool; +PL_FreeArenaPool; +PL_HashString; +PL_HashTableAdd; +PL_HashTableDestroy; +PL_HashTableDump; +PL_HashTableEnumerateEntries; +PL_HashTableLookup; +PL_HashTableRawAdd; +PL_HashTableRawLookup; +PL_HashTableRawRemove; +PL_HashTableRemove; +PL_InitArenaPool; +PL_NewHashTable; +libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPR_4.1 { +;+ global: +PL_HashTableLookupConst; +PL_HashTableRawLookupConst; +;+} NSPR_4.0; diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plds.rc b/src/libs/xpcom18a4/nsprpub/lib/ds/plds.rc new file mode 100644 index 00000000..fa64e192 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plds.rc @@ -0,0 +1,102 @@ +/* -*- 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 ***** */ + +#include "prinit.h" +#include + +#define MY_LIBNAME "plds" +#define MY_FILEDESCRIPTION "PLDS Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "LegalCopyright", "Copyright \251 1996-2000 Netscape Communications Corporation\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plds_symvec.opt b/src/libs/xpcom18a4/nsprpub/lib/ds/plds_symvec.opt new file mode 100644 index 00000000..71784540 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plds_symvec.opt @@ -0,0 +1,37 @@ +! Fixed section of symbol vector for LIBPLDS4 +! +GSMATCH=LEQUAL,2,2 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.3 +! Previously this was empty. Now we include everything that's specified in +! plds.def. +! -------------------------------------------------------------------------- +! +! NSPR 4.0 +SYMBOL_VECTOR=(PL_ArenaAllocate=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaFinish=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaGrow=PROCEDURE) +SYMBOL_VECTOR=(PL_ArenaRelease=PROCEDURE) +SYMBOL_VECTOR=(PL_CompactArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_CompareStrings=PROCEDURE) +SYMBOL_VECTOR=(PL_CompareValues=PROCEDURE) +SYMBOL_VECTOR=(PL_FinishArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_FreeArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_HashString=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableAdd=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableDestroy=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableDump=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableEnumerateEntries=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableLookup=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawAdd=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawLookup=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawRemove=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRemove=PROCEDURE) +SYMBOL_VECTOR=(PL_InitArenaPool=PROCEDURE) +SYMBOL_VECTOR=(PL_NewHashTable=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! NSPR 4.1 +SYMBOL_VECTOR=(PL_HashTableLookupConst=PROCEDURE) +SYMBOL_VECTOR=(PL_HashTableRawLookupConst=PROCEDURE) diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.c b/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.c new file mode 100644 index 00000000..98ce5959 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.c @@ -0,0 +1,541 @@ +/* -*- 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 ***** */ + +/* + * PL hash table package. + */ +#include "plhash.h" +#include "prbit.h" +#include "prlog.h" +#include "prmem.h" +#include "prtypes.h" +#include +#include + +/* Compute the number of buckets in ht */ +#define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift)) + +/* The smallest table has 16 buckets */ +#define MINBUCKETSLOG2 4 +#define MINBUCKETS (1 << MINBUCKETSLOG2) + +/* Compute the maximum entries given n buckets that we will tolerate, ~90% */ +#define OVERLOADED(n) ((n) - ((n) >> 3)) + +/* Compute the number of entries below which we shrink the table by half */ +#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0) + +/* +** Stubs for default hash allocator ops. +*/ +static void * PR_CALLBACK +DefaultAllocTable(void *pool, PRSize size) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + return PR_MALLOC(size); +} + +static void PR_CALLBACK +DefaultFreeTable(void *pool, void *item) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + PR_Free(item); +} + +static PLHashEntry * PR_CALLBACK +DefaultAllocEntry(void *pool, const void *key) +{ +#if defined(XP_MAC) +#pragma unused (pool,key) +#endif + + return PR_NEW(PLHashEntry); +} + +static void PR_CALLBACK +DefaultFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) + PR_Free(he); +} + +static PLHashAllocOps defaultHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, DefaultFreeEntry +}; + +PR_IMPLEMENT(PLHashTable *) +PL_NewHashTable(PRUint32 n, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv) +{ + PLHashTable *ht; + PRSize nb; + + if (n <= MINBUCKETS) { + n = MINBUCKETSLOG2; + } else { + n = PR_CeilingLog2(n); + if ((PRInt32)n < 0) + return 0; + } + + if (!allocOps) allocOps = &defaultHashAllocOps; + + ht = (PLHashTable*)((*allocOps->allocTable)(allocPriv, sizeof *ht)); + if (!ht) + return 0; + memset(ht, 0, sizeof *ht); + ht->shift = PL_HASH_BITS - n; + n = 1 << n; +#if defined(WIN16) + if (n > 16000) { + (*allocOps->freeTable)(allocPriv, ht); + return 0; + } +#endif /* WIN16 */ + nb = n * sizeof(PLHashEntry *); + ht->buckets = (PLHashEntry**)((*allocOps->allocTable)(allocPriv, nb)); + if (!ht->buckets) { + (*allocOps->freeTable)(allocPriv, ht); + return 0; + } + memset(ht->buckets, 0, nb); + + ht->keyHash = keyHash; + ht->keyCompare = keyCompare; + ht->valueCompare = valueCompare; + ht->allocOps = allocOps; + ht->allocPriv = allocPriv; + return ht; +} + +PR_IMPLEMENT(void) +PL_HashTableDestroy(PLHashTable *ht) +{ + PRUint32 i, n; + PLHashEntry *he, *next; + const PLHashAllocOps *allocOps = ht->allocOps; + void *allocPriv = ht->allocPriv; + + n = NBUCKETS(ht); + for (i = 0; i < n; i++) { + for (he = ht->buckets[i]; he; he = next) { + next = he->next; + (*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY); + } + } +#ifdef DEBUG + memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]); +#endif + (*allocOps->freeTable)(allocPriv, ht->buckets); +#ifdef DEBUG + memset(ht, 0xDB, sizeof *ht); +#endif + (*allocOps->freeTable)(allocPriv, ht); +} + +/* +** Multiplicative hash, from Knuth 6.4. +*/ +#define GOLDEN_RATIO 0x9E3779B9U /* 2/(1+sqrt(5))*(2^32) */ + +PR_IMPLEMENT(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key) +{ + PLHashEntry *he, **hep, **hep0; + PLHashNumber h; + +#ifdef HASHMETER + ht->nlookups++; +#endif + h = keyHash * GOLDEN_RATIO; + h >>= ht->shift; + hep = hep0 = &ht->buckets[h]; + while ((he = *hep) != 0) { + if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) { + /* Move to front of chain if not already there */ + if (hep != hep0) { + *hep = he->next; + he->next = *hep0; + *hep0 = he; + } + return hep0; + } + hep = &he->next; +#ifdef HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +/* +** Same as PL_HashTableRawLookup but doesn't reorder the hash entries. +*/ +PR_IMPLEMENT(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key) +{ + PLHashEntry *he, **hep; + PLHashNumber h; + +#ifdef HASHMETER + ht->nlookups++; +#endif + h = keyHash * GOLDEN_RATIO; + h >>= ht->shift; + hep = &ht->buckets[h]; + while ((he = *hep) != 0) { + if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) { + break; + } + hep = &he->next; +#ifdef HASHMETER + ht->nsteps++; +#endif + } + return hep; +} + +PR_IMPLEMENT(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, + PLHashNumber keyHash, const void *key, void *value) +{ + PRUint32 i, n; + PLHashEntry *he, *next, **oldbuckets; + PRSize nb; + + /* Grow the table if it is overloaded */ + n = NBUCKETS(ht); + if (ht->nentries >= OVERLOADED(n)) { + oldbuckets = ht->buckets; +#if defined(WIN16) + if (2 * n > 16000) + return 0; +#endif /* WIN16 */ + nb = 2 * n * sizeof(PLHashEntry *); + ht->buckets = (PLHashEntry**) + ((*ht->allocOps->allocTable)(ht->allocPriv, nb)); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return 0; + } + memset(ht->buckets, 0, nb); +#ifdef HASHMETER + ht->ngrows++; +#endif + ht->shift--; + + for (i = 0; i < n; i++) { + for (he = oldbuckets[i]; he; he = next) { + next = he->next; + hep = PL_HashTableRawLookup(ht, he->keyHash, he->key); + PR_ASSERT(*hep == 0); + he->next = 0; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]); +#endif + (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets); + hep = PL_HashTableRawLookup(ht, keyHash, key); + } + + /* Make a new key value entry */ + he = (*ht->allocOps->allocEntry)(ht->allocPriv, key); + if (!he) + return 0; + he->keyHash = keyHash; + he->key = key; + he->value = value; + he->next = *hep; + *hep = he; + ht->nentries++; + return he; +} + +PR_IMPLEMENT(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != 0) { + /* Hit; see if values match */ + if ((*ht->valueCompare)(he->value, value)) { + /* key,value pair is already present in table */ + return he; + } + if (he->value) + (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE); + he->value = value; + return he; + } + return PL_HashTableRawAdd(ht, hep, keyHash, key, value); +} + +PR_IMPLEMENT(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he) +{ + PRUint32 i, n; + PLHashEntry *next, **oldbuckets; + PRSize nb; + + *hep = he->next; + (*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY); + + /* Shrink table if it's underloaded */ + n = NBUCKETS(ht); + if (--ht->nentries < UNDERLOADED(n)) { + oldbuckets = ht->buckets; + nb = n * sizeof(PLHashEntry*) / 2; + ht->buckets = (PLHashEntry**)( + (*ht->allocOps->allocTable)(ht->allocPriv, nb)); + if (!ht->buckets) { + ht->buckets = oldbuckets; + return; + } + memset(ht->buckets, 0, nb); +#ifdef HASHMETER + ht->nshrinks++; +#endif + ht->shift++; + + for (i = 0; i < n; i++) { + for (he = oldbuckets[i]; he; he = next) { + next = he->next; + hep = PL_HashTableRawLookup(ht, he->keyHash, he->key); + PR_ASSERT(*hep == 0); + he->next = 0; + *hep = he; + } + } +#ifdef DEBUG + memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]); +#endif + (*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets); + } +} + +PR_IMPLEMENT(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) == 0) + return PR_FALSE; + + /* Hit; remove element */ + PL_HashTableRawRemove(ht, hep, he); + return PR_TRUE; +} + +PR_IMPLEMENT(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookup(ht, keyHash, key); + if ((he = *hep) != 0) { + return he->value; + } + return 0; +} + +/* +** Same as PL_HashTableLookup but doesn't reorder the hash entries. +*/ +PR_IMPLEMENT(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key) +{ + PLHashNumber keyHash; + PLHashEntry *he, **hep; + + keyHash = (*ht->keyHash)(key); + hep = PL_HashTableRawLookupConst(ht, keyHash, key); + if ((he = *hep) != 0) { + return he->value; + } + return 0; +} + +/* +** Iterate over the entries in the hash table calling func for each +** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP). +** Return a count of the number of elements scanned. +*/ +PR_IMPLEMENT(int) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg) +{ + PLHashEntry *he, **hep; + PRUint32 i, nbuckets; + int rv, n = 0; + PLHashEntry *todo = 0; + + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + hep = &ht->buckets[i]; + while ((he = *hep) != 0) { + rv = (*f)(he, n, arg); + n++; + if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) { + *hep = he->next; + if (rv & HT_ENUMERATE_REMOVE) { + he->next = todo; + todo = he; + } + } else { + hep = &he->next; + } + if (rv & HT_ENUMERATE_STOP) { + goto out; + } + } + } + +out: + hep = &todo; + while ((he = *hep) != 0) { + PL_HashTableRawRemove(ht, hep, he); + } + return n; +} + +#ifdef HASHMETER +#include +#include + +PR_IMPLEMENT(void) +PL_HashTableDumpMeter(PLHashTable *ht, PLHashEnumerator dump, FILE *fp) +{ + double mean, variance; + PRUint32 nchains, nbuckets; + PRUint32 i, n, maxChain, maxChainLen; + PLHashEntry *he; + + variance = 0; + nchains = 0; + maxChainLen = 0; + nbuckets = NBUCKETS(ht); + for (i = 0; i < nbuckets; i++) { + he = ht->buckets[i]; + if (!he) + continue; + nchains++; + for (n = 0; he; he = he->next) + n++; + variance += n * n; + if (n > maxChainLen) { + maxChainLen = n; + maxChain = i; + } + } + mean = (double)ht->nentries / nchains; + variance = fabs(variance / nchains - mean * mean); + + fprintf(fp, "\nHash table statistics:\n"); + fprintf(fp, " number of lookups: %u\n", ht->nlookups); + fprintf(fp, " number of entries: %u\n", ht->nentries); + fprintf(fp, " number of grows: %u\n", ht->ngrows); + fprintf(fp, " number of shrinks: %u\n", ht->nshrinks); + fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps + / ht->nlookups); + fprintf(fp, "mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sqrt(variance)); + fprintf(fp, " max hash chain length: %u\n", maxChainLen); + fprintf(fp, " max hash chain: [%u]\n", maxChain); + + for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++) + if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT) + break; +} +#endif /* HASHMETER */ + +PR_IMPLEMENT(int) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp) +{ + int count; + + count = PL_HashTableEnumerateEntries(ht, dump, fp); +#ifdef HASHMETER + PL_HashTableDumpMeter(ht, dump, fp); +#endif + return count; +} + +PR_IMPLEMENT(PLHashNumber) +PL_HashString(const void *key) +{ + PLHashNumber h; + const PRUint8 *s; + + h = 0; + for (s = (const PRUint8*)key; *s; s++) + h = (h >> 28) ^ (h << 4) ^ *s; + return h; +} + +PR_IMPLEMENT(int) +PL_CompareStrings(const void *v1, const void *v2) +{ + return strcmp((const char*)v1, (const char*)v2) == 0; +} + +PR_IMPLEMENT(int) +PL_CompareValues(const void *v1, const void *v2) +{ + return v1 == v2; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.h b/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.h new file mode 100644 index 00000000..e899c0dc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plhash.h @@ -0,0 +1,183 @@ +/* -*- 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 plhash_h___ +#define plhash_h___ +/* + * API to portable hash table code. + */ +#include +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_CompareStrings VBoxNsplPL_CompareStrings +#define PL_CompareValues VBoxNsplPL_CompareValues +#define PL_HashString VBoxNsplPL_HashString +#define PL_HashTableAdd VBoxNsplPL_HashTableAdd +#define PL_HashTableDestroy VBoxNsplPL_HashTableDestroy +#define PL_HashTableLookup VBoxNsplPL_HashTableLookup +#define PL_HashTableRemove VBoxNsplPL_HashTableRemove +#define PL_NewHashTable VBoxNsplPL_NewHashTable +#define PL_HashTableDump VBoxNsplPL_HashTableDump +#define PL_HashTableEnumerateEntries VBoxNsplPL_HashTableEnumerateEntries +#define PL_HashTableLookupConst VBoxNsplPL_HashTableLookupConst +#define PL_HashTableRawAdd VBoxNsplPL_HashTableRawAdd +#define PL_HashTableRawLookup VBoxNsplPL_HashTableRawLookup +#define PL_HashTableRawLookupConst VBoxNsplPL_HashTableRawLookupConst +#define PL_HashTableRawRemove VBoxNsplPL_HashTableRawRemove +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PLHashEntry PLHashEntry; +typedef struct PLHashTable PLHashTable; +typedef PRUint32 PLHashNumber; +#define PL_HASH_BITS 32 /* Number of bits in PLHashNumber */ +typedef PLHashNumber (PR_CALLBACK *PLHashFunction)(const void *key); +typedef PRIntn (PR_CALLBACK *PLHashComparator)(const void *v1, const void *v2); + +#if defined(XP_OS2_VACPP) && defined(VACPP_FLIP) /* for nsSpaceManager.cpp */ +PR_END_EXTERN_C /* and nsHTMLDocument.cpp */ +#endif +typedef PRIntn (PR_CALLBACK *PLHashEnumerator)(PLHashEntry *he, PRIntn i, void *arg); + +#if defined(XP_OS2_VACPP) && defined(VACPP_FLIP) +PR_BEGIN_EXTERN_C +#endif + +/* Flag bits in PLHashEnumerator's return value */ +#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */ +#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */ +#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */ +#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */ + +typedef struct PLHashAllocOps { + void * (PR_CALLBACK *allocTable)(void *pool, PRSize size); + void (PR_CALLBACK *freeTable)(void *pool, void *item); + PLHashEntry * (PR_CALLBACK *allocEntry)(void *pool, const void *key); + void (PR_CALLBACK *freeEntry)(void *pool, PLHashEntry *he, PRUintn flag); +} PLHashAllocOps; + +#define HT_FREE_VALUE 0 /* just free the entry's value */ +#define HT_FREE_ENTRY 1 /* free value and entire entry */ + +struct PLHashEntry { + PLHashEntry *next; /* hash chain linkage */ + PLHashNumber keyHash; /* key hash function result */ + const void *key; /* ptr to opaque key */ + void *value; /* ptr to opaque value */ +}; + +struct PLHashTable { + PLHashEntry **buckets; /* vector of hash buckets */ + PRUint32 nentries; /* number of entries in table */ + PRUint32 shift; /* multiplicative hash shift */ + PLHashFunction keyHash; /* key hash function */ + PLHashComparator keyCompare; /* key comparison function */ + PLHashComparator valueCompare; /* value comparison function */ + const PLHashAllocOps *allocOps; /* allocation operations */ + void *allocPriv; /* allocation private data */ +#ifdef HASHMETER + PRUint32 nlookups; /* total number of lookups */ + PRUint32 nsteps; /* number of hash chains traversed */ + PRUint32 ngrows; /* number of table expansions */ + PRUint32 nshrinks; /* number of table contractions */ +#endif +}; + +/* + * Create a new hash table. + * If allocOps is null, use default allocator ops built on top of malloc(). + */ +PR_EXTERN(PLHashTable *) +PL_NewHashTable(PRUint32 numBuckets, PLHashFunction keyHash, + PLHashComparator keyCompare, PLHashComparator valueCompare, + const PLHashAllocOps *allocOps, void *allocPriv); + +PR_EXTERN(void) +PL_HashTableDestroy(PLHashTable *ht); + +/* Higher level access methods */ +PR_EXTERN(PLHashEntry *) +PL_HashTableAdd(PLHashTable *ht, const void *key, void *value); + +PR_EXTERN(PRBool) +PL_HashTableRemove(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookup(PLHashTable *ht, const void *key); + +PR_EXTERN(void *) +PL_HashTableLookupConst(PLHashTable *ht, const void *key); + +PR_EXTERN(PRIntn) +PL_HashTableEnumerateEntries(PLHashTable *ht, PLHashEnumerator f, void *arg); + +/* General-purpose C string hash function. */ +PR_EXTERN(PLHashNumber) +PL_HashString(const void *key); + +/* Compare strings using strcmp(), return true if equal. */ +PR_EXTERN(PRIntn) +PL_CompareStrings(const void *v1, const void *v2); + +/* Stub function just returns v1 == v2 */ +PR_EXTERN(PRIntn) +PL_CompareValues(const void *v1, const void *v2); + +/* Low level access methods */ +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key); + +PR_EXTERN(PLHashEntry **) +PL_HashTableRawLookupConst(PLHashTable *ht, PLHashNumber keyHash, + const void *key); + +PR_EXTERN(PLHashEntry *) +PL_HashTableRawAdd(PLHashTable *ht, PLHashEntry **hep, PLHashNumber keyHash, + const void *key, void *value); + +PR_EXTERN(void) +PL_HashTableRawRemove(PLHashTable *ht, PLHashEntry **hep, PLHashEntry *he); + +/* This can be trivially implemented using PL_HashTableEnumerateEntries. */ +PR_EXTERN(PRIntn) +PL_HashTableDump(PLHashTable *ht, PLHashEnumerator dump, FILE *fp); + +PR_END_EXTERN_C + +#endif /* plhash_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/ds/plvrsion.c b/src/libs/xpcom18a4/nsprpub/lib/ds/plvrsion.c new file mode 100644 index 00000000..486a6cb1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/ds/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- 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 "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libplds, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* version */ 2, /* this is the only one supported */ + /* buildTime */ _BUILD_TIME, /* usecs since midnight 1/1/1970 GMT */ + /* buildTimeString */ _BUILD_STRING, /* ditto, but human readable */ + /* vMajor */ PR_VMAJOR, /* NSPR's version number */ + /* vMinor */ PR_VMINOR, /* and minor version */ + /* vPatch */ PR_VPATCH, /* and patch */ + /* beta */ PR_BETA, /* beta build boolean */ +#if defined(DEBUG) + /* debug */ PR_TRUE, /* a debug build */ +#else + /* debug */ PR_FALSE, /* an optomized build */ +#endif + /* special */ PR_FALSE, /* they're all special, but ... */ + /* filename */ _PRODUCTION, /* the produced library name */ + /* description */ "Portable runtime", /* what we are */ + /* security */ "N/A", /* not applicable here */ + /* copywrite */ "Copyright (c) 1998 Netscape Communications Corporation. All Rights Reserved", + /* comment */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/libc/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/libc/Makefile.in new file mode 100644 index 00000000..9755225a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +export NSPR20=1 + +include $(topsrcdir)/config/config.mk + +DIRS = include src + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/README b/src/libs/xpcom18a4/nsprpub/lib/libc/README new file mode 100644 index 00000000..74f24690 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/README @@ -0,0 +1,20 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains various libc-types of functions. All functions in +this directory are platform independent, thread friendly (both safe and +efficient). They are contributed from various sources, though the contri- +butions are monitored by the NSPR group (mailto:freier). + +All API items exported by these functions will contain the same three +character prefix, "PL_" (Portable Library). Internal function names +that are not exported (static) are of little concern, though some caution +must be used on those elements that are 'extern' but not really intended +to be part of the API. Those should all have a prefix of "_PL_" (is that +legal?). + +The responsibility for contributions in this area are distributed among +all interested parties. + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/libc/include/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/MANIFEST b/src/libs/xpcom18a4/nsprpub/lib/libc/include/MANIFEST new file mode 100644 index 00000000..63e8861d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/MANIFEST @@ -0,0 +1,9 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +plbase64.h +plerror.h +plgetopt.h +plresolv.h +plstr.h diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/libc/include/Makefile.in new file mode 100644 index 00000000..9d5e2e18 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(HEADERS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(HEADERS) $(MOZ_INCL) +endif + + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/README b/src/libs/xpcom18a4/nsprpub/lib/libc/include/README new file mode 100644 index 00000000..2b852189 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/README @@ -0,0 +1,7 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains the API for various libc-types of functions. + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/plbase64.h b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plbase64.h new file mode 100644 index 00000000..d6c7ec7b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plbase64.h @@ -0,0 +1,103 @@ +/* -*- 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 _plbase64_h +#define _plbase64_h + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_Base64Decode VBoxNsplPL_Base64Decode +#define PL_Base64Encode VBoxNsplPL_Base64Encode +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* + * PL_Base64Encode + * + * This routine encodes the data pointed to by the "src" parameter using the + * base64 algorithm, and returns a pointer to the result. If the "srclen" + * parameter is not zero, it specifies the length of the source data. If it + * is zero, the source data is assumed to be null-terminated, and PL_strlen + * is used to determine the source length. If the "dest" parameter is not + * null, it is assumed to point to a buffer of sufficient size (which may be + * calculated: ((srclen + 2)/3)*4) into which the encoded data is placed + * (without any termination). If the "dest" parameter is null, a buffer is + * allocated from the heap to hold the encoded data, and the result *will* + * be terminated with an extra null character. It is the caller's + * responsibility to free the result when it is allocated. A null is returned + * if the allocation fails. + */ + +PR_EXTERN(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +); + +/* + * PL_Base64Decode + * + * This routine decodes the data pointed to by the "src" parameter using + * the base64 algorithm, and returns a pointer to the result. The source + * may either include or exclude any trailing '=' characters. If the + * "srclen" parameter is not zero, it specifies the length of the source + * data. If it is zero, PL_strlen will be used to determine the source + * length. If the "dest" parameter is not null, it is assumed to point to + * a buffer of sufficient size (which may be calculated: (srclen * 3)/4 + * when srclen includes the '=' characters) into which the decoded data + * is placed (without any termination). If the "dest" parameter is null, + * a buffer is allocated from the heap to hold the decoded data, and the + * result *will* be terminated with an extra null character. It is the + * caller's responsibility to free the result when it is allocated. A null + * is retuned if the allocation fails, or if the source is not well-coded. + */ + +PR_EXTERN(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +); + +PR_END_EXTERN_C + +#endif /* _plbase64_h */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/plerror.h b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plerror.h new file mode 100644 index 00000000..534acf2a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plerror.h @@ -0,0 +1,71 @@ +/* -*- 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 ***** */ + +/* +** File: plerror.h +** Description: Simple routine to print translate the calling thread's +** error numbers and print them. +*/ + +#if defined(PLERROR_H) +#else +#define PLERROR_H + +#include "prio.h" +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_FPrintError VBoxNsplPL_FPrintError +#define PL_PrintError VBoxNsplPL_PrintError +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C +/* +** Print the messages to "syserr" prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_PrintError(const char *msg); + +/* +** Print the messages to specified output file prepending 'msg' if not NULL. +*/ +PR_EXTERN(void) PL_FPrintError(PRFileDesc *output, const char *msg); + +PR_END_EXTERN_C + +#endif /* defined(PLERROR_H) */ + +/* plerror.h */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/plgetopt.h b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plgetopt.h new file mode 100644 index 00000000..0f794fb0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plgetopt.h @@ -0,0 +1,87 @@ +/* -*- 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 ***** */ + +/* +** File: plgetopt.h +** Description: utilities to parse argc/argv +*/ + +#if defined(PLGETOPT_H_) +#else +#define PLGETOPT_H_ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_CreateOptState VBoxNsplPL_CreateOptState +#define PL_DestroyOptState VBoxNsplPL_DestroyOptState +#define PL_GetNextOpt VBoxNsplPL_GetNextOpt +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PLOptionInternal PLOptionInternal; + +typedef enum +{ + PL_OPT_OK, /* all's well with the option */ + PL_OPT_EOL, /* end of options list */ + PL_OPT_BAD /* invalid option (and value) */ +} PLOptStatus; + +typedef struct PLOptState +{ + char option; /* the name of the option */ + const char *value; /* the value of that option | NULL */ + + PLOptionInternal *internal; /* private processing state */ + +} PLOptState; + +PR_EXTERN(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options); + +PR_EXTERN(void) PL_DestroyOptState(PLOptState *opt); + +PR_EXTERN(PLOptStatus) PL_GetNextOpt(PLOptState *opt); + +PR_END_EXTERN_C + +#endif /* defined(PLGETOPT_H_) */ + +/* plgetopt.h */ + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/plresolv.h b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plresolv.h new file mode 100644 index 00000000..45d4e5e6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plresolv.h @@ -0,0 +1,108 @@ +/* -*- 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 ***** */ + +/* + * plresolv.h - asynchronous name resolution using DNS + */ + +#ifndef _PLRESOLV_H_ +#define _PLRESOLV_H_ + +/* +** THIS IS WORK IN PROGRESS. DO NOT ATTEMPT TO USE ANY PORTION OF THIS +** API UNTIL THIS MESSAGE NO LONGER EXISTS. IF YOU DO, THEN YOU SURRENDER +** THE RIGHT TO COMPLAIN ABOUT ANY CONTENT. +*/ + +#if defined(XP_UNIX) + +#include +#include + +NSPR_BEGIN_EXTERN_C + +#define PL_RESOLVE_MAXHOSTENTBUF 1024 +#define PL_RESOLVE_DEFAULT_TIMEOUT 0 + +/* Error return codes */ +#define PL_RESOLVE_OK 0 +#define PL_RESOLVE_EWINIT 1 /* Failed to initialize window */ +#define PL_RESOLVE_EMAKE 2 /* Failed to create request */ +#define PL_RESOLVE_ELAUNCH 3 /* Error launching Async request */ +#define PL_RESOLVE_ETIMEDOUT 4 /* Request timed-out */ +#define PL_RESOLVE_EINVAL 5 /* Invalid argument */ +#define PL_RESOLVE_EOVERFLOW 6 /* Buffer Overflow */ +#define PL_RESOLVE_EUNKNOWN 7 /* berzerk error */ + +/* ----------- Function Prototypes ----------------*/ + +PR_EXTERN(PRStatus) PL_ResolveName( + const char *name, unsigned char *buf, + PRIntn bufsize, PRIntervalTime timeout, + PRHostEnt *hostentry, PRIntervalTime *ttl); + +PR_EXTERN(PRStatus) PL_ResolveAddr( + const PRNetAddr *address, unsigned char *buf, + PRIntn bufsize, PRIntervalTime timeout, + PRHostEnt *hostentry, PRIntervalTime *ttl); + +typedef struct PLResolveStats { + int re_errors; + int re_nu_look; + int re_na_look; + int re_replies; + int re_requests; + int re_resends; + int re_sent; + int re_timeouts; +} PLResolveStats; + +typedef struct PLResoveInfo { + PRBool enabled; + PRUint32 numNameLookups; + PRUint32 numAddrLookups; + PRUint32 numLookupsInProgress; + PLResolveStats stats; +} PLResoveInfo; + +PR_EXTERN(void) PL_ResolveInfo(PLResoveInfo *info); + +NSPR_END_EXTERN_C + +#endif /* defined(XP_UNIX) */ + +#endif /* _PLRESOLV_H_ */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/include/plstr.h b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plstr.h new file mode 100644 index 00000000..443da300 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/include/plstr.h @@ -0,0 +1,505 @@ +/* -*- 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): + * Roland Mainz + * + * 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 _plstr_h +#define _plstr_h + +/* + * plstr.h + * + * This header file exports the API to the NSPR portable library or string- + * handling functions. + * + * This API was not designed as an "optimal" or "ideal" string library; it + * was based on the good ol' unix string.3 functions, and was written to + * + * 1) replace the libc functions, for cross-platform consistancy, + * 2) complete the API on platforms lacking common functions (e.g., + * strcase*), and + * 3) to implement some obvious "closure" functions that I've seen + * people hacking around in our code. + * + * Point number three largely means that most functions have an "strn" + * limited-length version, and all comparison routines have a non-case- + * sensitive version available. + */ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_strlen VBoxNsplPL_strlen +#define PL_strcmp VBoxNsplPL_strcmp +#define PL_strncmp VBoxNsplPL_strncmp +#define PL_strcasecmp VBoxNsplPL_strcasecmp +#define PL_strncasecmp VBoxNsplPL_strncasecmp +#define PL_strdup VBoxNsplPL_strdup +#define PL_strfree VBoxNsplPL_strfree +#define PL_strncpy VBoxNsplPL_strncpy +#define PL_strncpyz VBoxNsplPL_strncpyz +#define PL_strrchr VBoxNsplPL_strrchr +#define PL_strcaserstr VBoxNsplPL_strcaserstr +#define PL_strcasestr VBoxNsplPL_strcasestr +#define PL_strcat VBoxNsplPL_strcat +#define PL_strcatn VBoxNsplPL_strcatn +#define PL_strchr VBoxNsplPL_strchr +#define PL_strcpy VBoxNsplPL_strcpy +#define PL_strncaserstr VBoxNsplPL_strncaserstr +#define PL_strncasestr VBoxNsplPL_strncasestr +#define PL_strncat VBoxNsplPL_strncat +#define PL_strnchr VBoxNsplPL_strnchr +#define PL_strndup VBoxNsplPL_strndup +#define PL_strnlen VBoxNsplPL_strnlen +#define PL_strnpbrk VBoxNsplPL_strnpbrk +#define PL_strnprbrk VBoxNsplPL_strnprbrk +#define PL_strnrchr VBoxNsplPL_strnrchr +#define PL_strnrstr VBoxNsplPL_strnrstr +#define PL_strnstr VBoxNsplPL_strnstr +#define PL_strpbrk VBoxNsplPL_strpbrk +#define PL_strprbrk VBoxNsplPL_strprbrk +#define PL_strrstr VBoxNsplPL_strrstr +#define PL_strstr VBoxNsplPL_strstr +#define PL_strtok_r VBoxNsplPL_strtok_r +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C +/* + * PL_strlen + * + * Returns the length of the provided string, not including the trailing '\0'. + */ + +PR_EXTERN(PRUint32) +PL_strlen(const char *str); + +/* + * PL_strnlen + * + * Returns the length of the provided string, not including the trailing '\0', + * up to the indicated maximum. The string will not be examined beyond the + * maximum; if no terminating '\0' is found, the maximum will be returned. + */ + +PR_EXTERN(PRUint32) +PL_strnlen(const char *str, PRUint32 max); + +/* + * PL_strcpy + * + * Copies the source string, up to and including the trailing '\0', into the + * destination buffer. It does not (can not) verify that the destination + * buffer is large enough. It returns the "dest" argument. + */ + +PR_EXTERN(char *) +PL_strcpy(char *dest, const char *src); + +/* + * PL_strncpy + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up to and including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. If the source string is longer than the maximum length, + * the result will *not* be null-terminated (JLRU). + */ + +PR_EXTERN(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max); + +/* + * PL_strncpyz + * + * Copies the source string into the destination buffer, up to and including + * the trailing '\0' or up but not including the max'th character, whichever + * comes first. It does not (can not) verify that the destination buffer is + * large enough. The destination string is always terminated with a '\0', + * unlike the traditional libc implementation. It returns the "dest" argument. + * + * NOTE: If you call this with a source "abcdefg" and a max of 5, the + * destination will end up with "abcd\0" (i.e., it's strlen length will be 4)! + * + * This means you can do this: + * + * char buffer[ SOME_SIZE ]; + * PL_strncpyz(buffer, src, sizeof(buffer)); + * + * and the result will be properly terminated. + */ + +PR_EXTERN(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max); + +/* + * PL_strdup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string. The size of the allocated extent is one greater + * than the length of the argument string, because of the terminator. A + * null argument, like a zero-length argument, will result in a pointer to + * a one-byte extent containing the null value. This routine returns null + * upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strdup(const char *s); + +/* + * PL_strfree + * + * Free memory allocated by PL_strdup + */ + +PR_EXTERN(void) +PL_strfree(char *s); + +/* + * PL_strndup + * + * Returns a pointer to a malloc'd extent of memory containing a duplicate + * of the argument string, up to the maximum specified. If the argument + * string has a length greater than the value of the specified maximum, the + * return value will be a pointer to an extent of memory of length one + * greater than the maximum specified. A null string, a zero-length string, + * or a zero maximum will all result in a pointer to a one-byte extent + * containing the null value. This routine returns null upon malloc failure. + */ + +PR_EXTERN(char *) +PL_strndup(const char *s, PRUint32 max); + +/* + * PL_strcat + * + * Appends a copy of the string pointed to by the second argument to the + * end of the string pointed to by the first. The destination buffer is + * not (can not be) checked for sufficient size. A null destination + * argument returns null; otherwise, the first argument is returned. + */ + +PR_EXTERN(char *) +PL_strcat(char *dst, const char *src); + +/* + * PL_strncat + * + * Appends a copy of the string pointed to by the second argument, up to + * the maximum size specified, to the end of the string pointed to by the + * first. The destination buffer is not (can not be) checked for sufficient + * size. A null destination argument returns null; otherwise, the first + * argument is returned. If the maximum size limits the copy, then the + * result will *not* be null-terminated (JLRU). A null destination + * returns null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strncat(char *dst, const char *src, PRUint32 max); + +/* + * PL_strcatn + * + * Appends a copy of the string pointed to by the third argument, to the + * end of the string pointed to by the first. The second argument specifies + * the maximum size of the destination buffer, including the null termination. + * If the existing string in dst is longer than the max, no action is taken. + * The resulting string will be null-terminated. A null destination returns + * null; otherwise, the destination argument is returned. + */ + +PR_EXTERN(char *) +PL_strcatn(char *dst, PRUint32 max, const char *src); + +/* + * PL_strcmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated. The + * result is positive if the first string comes after the second. The + * NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcmp(const char *a, const char *b); + +/* + * PL_strncmp + * + * Returns an integer, the sign of which -- positive, zero, or negative -- + * reflects the lexical sorting order of the two strings indicated, up to + * the maximum specified. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. If the maximum + * is zero, only the existance or non-existance (pointer is null) of the + * strings is compared. + */ + +PR_EXTERN(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strcasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the two strings + * indicated. The result is positive if the first string comes after the + * second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strcasecmp(const char *a, const char *b); + +/* + * PL_strncasecmp + * + * Returns an integer, the sign of which -- positive, zero or negative -- + * reflects the case-insensitive lexical sorting order of the first n characters + * of the two strings indicated. The result is positive if the first string comes + * after the second. The NSPR implementation is not i18n. + */ + +PR_EXTERN(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max); + +/* + * PL_strchr + * + * Returns a pointer to the first instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strchr(const char *s, char c); + +/* + * PL_strrchr + * + * Returns a pointer to the last instance of the specified character in the + * provided string. It returns null if the character is not found, or if the + * provided string is null. The character may be the null character. + */ + +PR_EXTERN(char *) +PL_strrchr(const char *s, char c); + +/* + * PL_strnchr + * + * Returns a pointer to the first instance of the specified character within the + * first n characters of the provided string. It returns null if the character + * is not found, or if the provided string is null. The character may be the + * null character. + */ + +PR_EXTERN(char *) +PL_strnchr(const char *s, char c, PRUint32 n); + +/* + * PL_strnrchr + * + * Returns a pointer to the last instance of the specified character within the + * first n characters of the provided string. It returns null if the character is + * not found, or if the provided string is null. The character may be the null + * character. + */ + +PR_EXTERN(char *) +PL_strnrchr(const char *s, char c, PRUint32 n); + +/* + * NOTE: Looking for strcasechr, strcaserchr, strncasechr, or strncaserchr? + * Use strpbrk, strprbrk, strnpbrk or strnprbrk. + */ + +/* + * PL_strpbrk + * + * Returns a pointer to the first instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strpbrk(const char *s, const char *list); + +/* + * PL_strprbrk + * + * Returns a pointer to the last instance in the first string of any character + * (not including the terminating null character) of the second string. It returns + * null if either string is null. + */ + +PR_EXTERN(char *) +PL_strprbrk(const char *s, const char *list); + +/* + * PL_strnpbrk + * + * Returns a pointer to the first instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strnprbrk + * + * Returns a pointer to the last instance (within the first n characters) of any + * character (not including the terminating null character) of the second string. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 n); + +/* + * PL_strstr + * + * Returns a pointer to the first instance of the little string within the + * big one. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strstr(const char *big, const char *little); + +/* + * PL_strrstr + * + * Returns a pointer to the last instance of the little string within the big one. + * It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strrstr(const char *big, const char *little); + +/* + * PL_strnstr + * + * Returns a pointer to the first instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnstr(const char *big, const char *little, PRUint32 n); + +/* + * PL_strnrstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one. It returns null if either string is null. It + * returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strcasestr + * + * Returns a pointer to the first instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcasestr(const char *big, const char *little); + +/* + * PL_strcaserstr + * + * Returns a pointer to the last instance of the little string within the big one, + * ignoring case. It returns null if either string is null. + */ + +PR_EXTERN(char *) +PL_strcaserstr(const char *big, const char *little); + +/* + * PL_strncasestr + * + * Returns a pointer to the first instance of the listtle string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strncaserstr + * + * Returns a pointer to the last instance of the little string within the first + * n characters of the big one, ignoring case. It returns null if either string is + * null. It returns null if the length of the little string is greater than n. + */ + +PR_EXTERN(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max); + +/* + * PL_strtok_r + * + * Splits the string s1 into tokens, separated by one or more characters + * from the separator string s2. The argument lasts points to a + * user-supplied char * pointer in which PL_strtok_r stores information + * for it to continue scanning the same string. + * + * In the first call to PL_strtok_r, s1 points to a string and the value + * of *lasts is ignored. PL_strtok_r returns a pointer to the first + * token, writes '\0' into the character following the first token, and + * updates *lasts. + * + * In subsequent calls, s1 is null and lasts must stay unchanged from the + * previous call. The separator string s2 may be different from call to + * call. PL_strtok_r returns a pointer to the next token in s1. When no + * token remains in s1, PL_strtok_r returns null. + */ + +PR_EXTERN(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts); + +/* + * Things not (yet?) included: strspn/strcspn, strsep. + * memchr, memcmp, memcpy, memccpy, index, rindex, bcmp, bcopy, bzero. + * Any and all i18n/l10n stuff. + */ + +PR_END_EXTERN_C + +#endif /* _plstr_h */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/libc/src/.cvsignore new file mode 100644 index 00000000..bcab60f5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pl_bld.h diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/libc/src/Makefile.in new file mode 100644 index 00000000..162b3ed9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/Makefile.in @@ -0,0 +1,202 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) + +CSRCS =\ + plvrsion.c \ + strlen.c \ + strcpy.c \ + strdup.c \ + strcat.c \ + strcmp.c \ + strccmp.c \ + strchr.c \ + strpbrk.c \ + strstr.c \ + strcstr.c \ + strtok.c \ + base64.c \ + plerror.c \ + plgetopt.c \ + $(NULL) + +LIBRARY_NAME = plc +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +ifeq ($(OS_ARCH),WINNT) +ifdef NS_USE_GCC +DLLBASE=-Wl,--image-base -Wl,0x30000000 +else +DLLBASE=/BASE:0x30000000 +endif +RES=$(OBJDIR)/plc.res +RESNAME=plc.rc +endif # WINNT + +ifeq ($(OS_ARCH), AIX) +ifeq ($(CLASSIC_NSPR),1) +OS_LIBS = -lc +else +OS_LIBS = -lc_r +endif +endif + +ifeq ($(OS_ARCH),IRIX) +OS_LIBS = -lc +endif + +ifeq ($(OS_ARCH),SunOS) +OS_LIBS = -lc +MAPFILE = $(OBJDIR)/plcmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# The -R '$ORIGIN' linker option instructs this library to search for its +# dependencies in the same directory where it resides. +MKSHLIB += -R '$$ORIGIN' +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the .o files. +ifeq ($(OS_ARCH),NCR) +EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) +EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/README b/src/libs/xpcom18a4/nsprpub/lib/libc/src/README new file mode 100644 index 00000000..74f24690 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/README @@ -0,0 +1,20 @@ +NSPR 2.0 libc functions +----------------------- + +Last edited: AOF 04 March 1997 + +This directory contains various libc-types of functions. All functions in +this directory are platform independent, thread friendly (both safe and +efficient). They are contributed from various sources, though the contri- +butions are monitored by the NSPR group (mailto:freier). + +All API items exported by these functions will contain the same three +character prefix, "PL_" (Portable Library). Internal function names +that are not exported (static) are of little concern, though some caution +must be used on those elements that are 'extern' but not really intended +to be part of the API. Those should all have a prefix of "_PL_" (is that +legal?). + +The responsibility for contributions in this area are distributed among +all interested parties. + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/base64.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/base64.c new file mode 100644 index 00000000..234d60d8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/base64.c @@ -0,0 +1,428 @@ +/* -*- 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 "plbase64.h" +#include "prlog.h" /* For PR_NOT_REACHED */ +#include "prmem.h" /* for malloc / PR_MALLOC */ +#include "plstr.h" /* for PL_strlen */ + +static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void +encode3to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRIntn i, j = 18; + + for( i = 0; i < 3; i++ ) + { + b32 <<= 8; + b32 |= (PRUint32)src[i]; + } + + for( i = 0; i < 4; i++ ) + { + dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ]; + j -= 6; + } + + return; +} + +static void +encode2to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; + dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ]; + dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ]; + dest[3] = (unsigned char)'='; + return; +} + +static void +encode1to4 +( + const unsigned char *src, + unsigned char *dest +) +{ + dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ]; + dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ]; + dest[2] = (unsigned char)'='; + dest[3] = (unsigned char)'='; + return; +} + +static void +encode +( + const unsigned char *src, + PRUint32 srclen, + unsigned char *dest +) +{ + while( srclen >= 3 ) + { + encode3to4(src, dest); + src += 3; + dest += 4; + srclen -= 3; + } + + switch( srclen ) + { + case 2: + encode2to4(src, dest); + break; + case 1: + encode1to4(src, dest); + break; + case 0: + break; + default: + PR_NOT_REACHED("coding error"); + } + + return; +} + +/* + * PL_Base64Encode + * + * If the destination argument is NULL, a return buffer is + * allocated, and the data therein will be null-terminated. + * If the destination argument is not NULL, it is assumed to + * be of sufficient size, and the contents will not be null- + * terminated by this routine. + * + * Returns null if the allocation fails. + */ + +PR_IMPLEMENT(char *) +PL_Base64Encode +( + const char *src, + PRUint32 srclen, + char *dest +) +{ + if( 0 == srclen ) + { + srclen = PL_strlen(src); + } + + if( (char *)0 == dest ) + { + PRUint32 destlen = ((srclen + 2)/3) * 4; + dest = (char *)PR_MALLOC(destlen + 1); + if( (char *)0 == dest ) + { + return (char *)0; + } + dest[ destlen ] = (char)0; /* null terminate */ + } + + encode((const unsigned char *)src, srclen, (unsigned char *)dest); + return dest; +} + +static PRInt32 +codetovalue +( + unsigned char c +) +{ + if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') ) + { + return (PRInt32)(c - (unsigned char)'A'); + } + else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') ) + { + return ((PRInt32)(c - (unsigned char)'a') +26); + } + else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') ) + { + return ((PRInt32)(c - (unsigned char)'0') +52); + } + else if( (unsigned char)'+' == c ) + { + return (PRInt32)62; + } + else if( (unsigned char)'/' == c ) + { + return (PRInt32)63; + } + else + { + return -1; + } +} + +static PRStatus +decode4to3 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRInt32 bits; + PRIntn i; + + for( i = 0; i < 4; i++ ) + { + bits = codetovalue(src[i]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 <<= 6; + b32 |= bits; + } + + dest[0] = (unsigned char)((b32 >> 16) & 0xFF); + dest[1] = (unsigned char)((b32 >> 8) & 0xFF); + dest[2] = (unsigned char)((b32 ) & 0xFF); + + return PR_SUCCESS; +} + +static PRStatus +decode3to2 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32 = (PRUint32)0; + PRInt32 bits; + PRUint32 ubits; + + bits = codetovalue(src[0]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 = (PRUint32)bits; + b32 <<= 6; + + bits = codetovalue(src[1]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + b32 |= (PRUint32)bits; + b32 <<= 4; + + bits = codetovalue(src[2]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 |= (ubits >> 2); + + dest[0] = (unsigned char)((b32 >> 8) & 0xFF); + dest[1] = (unsigned char)((b32 ) & 0xFF); + + return PR_SUCCESS; +} + +static PRStatus +decode2to1 +( + const unsigned char *src, + unsigned char *dest +) +{ + PRUint32 b32; + PRUint32 ubits; + PRInt32 bits; + + bits = codetovalue(src[0]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 = (ubits << 2); + + bits = codetovalue(src[1]); + if( bits < 0 ) + { + return PR_FAILURE; + } + + ubits = (PRUint32)bits; + b32 |= (ubits >> 4); + + dest[0] = (unsigned char)b32; + + return PR_SUCCESS; +} + +static PRStatus +decode +( + const unsigned char *src, + PRUint32 srclen, + unsigned char *dest +) +{ + PRStatus rv; + + while( srclen >= 4 ) + { + rv = decode4to3(src, dest); + if( PR_SUCCESS != rv ) + { + return PR_FAILURE; + } + + src += 4; + dest += 3; + srclen -= 4; + } + + switch( srclen ) + { + case 3: + rv = decode3to2(src, dest); + break; + case 2: + rv = decode2to1(src, dest); + break; + case 1: + rv = PR_FAILURE; + break; + case 0: + rv = PR_SUCCESS; + break; + default: + PR_NOT_REACHED("coding error"); + } + + return rv; +} + +/* + * PL_Base64Decode + * + * If the destination argument is NULL, a return buffer is + * allocated and the data therein will be null-terminated. + * If the destination argument is not null, it is assumed + * to be of sufficient size, and the data will not be null- + * terminated by this routine. + * + * Returns null if the allocation fails, or if the source string is + * not well-formed. + */ + +PR_IMPLEMENT(char *) +PL_Base64Decode +( + const char *src, + PRUint32 srclen, + char *dest +) +{ + PRStatus status; + PRBool allocated = PR_FALSE; + + if( (char *)0 == src ) + { + return (char *)0; + } + + if( 0 == srclen ) + { + srclen = PL_strlen(src); + } + + if( srclen && (0 == (srclen & 3)) ) + { + if( (char)'=' == src[ srclen-1 ] ) + { + if( (char)'=' == src[ srclen-2 ] ) + { + srclen -= 2; + } + else + { + srclen -= 1; + } + } + } + + if( (char *)0 == dest ) + { + PRUint32 destlen = ((srclen * 3) / 4); + dest = (char *)PR_MALLOC(destlen + 1); + if( (char *)0 == dest ) + { + return (char *)0; + } + dest[ destlen ] = (char)0; /* null terminate */ + allocated = PR_TRUE; + } + + status = decode((const unsigned char *)src, srclen, (unsigned char *)dest); + if( PR_SUCCESS != status ) + { + if( PR_TRUE == allocated ) + { + PR_DELETE(dest); + } + + return (char *)0; + } + + return dest; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.def b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.def new file mode 100644 index 00000000..39eba5b7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.def @@ -0,0 +1,94 @@ +;+# +;+# 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 Netscape are +;+# Copyright (C) 2002-2003 Netscape Communications Corporation. All +;+# Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the +;+# terms of the GNU General Public License Version 2 or later (the +;+# "GPL"), in which case the provisions of the GPL are applicable +;+# instead of those above. If you wish to allow use of your +;+# version of this file only under the terms of the GPL and not to +;+# allow others to use your version of this file under the MPL, +;+# indicate your decision by deleting the provisions above and +;+# replace them with the notice and other provisions required by +;+# the GPL. If you do not delete the provisions above, a recipient +;+# may use your version of this file under either the MPL or the +;+# GPL. +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+NSPR_4.0 { +;+ global: +LIBRARY plc4 ;- +EXPORTS ;- +PL_Base64Decode; +PL_Base64Encode; +PL_CreateOptState; +PL_DestroyOptState; +PL_FPrintError; +PL_GetNextOpt; +PL_PrintError; +PL_strcasecmp; +PL_strcaserstr; +PL_strcasestr; +PL_strcat; +PL_strcatn; +PL_strchr; +PL_strcmp; +PL_strcpy; +PL_strdup; +PL_strfree; +PL_strlen; +PL_strncasecmp; +PL_strncaserstr; +PL_strncasestr; +PL_strncat; +PL_strnchr; +PL_strncmp; +PL_strncpy; +PL_strncpyz; +PL_strndup; +PL_strnlen; +PL_strnpbrk; +PL_strnprbrk; +PL_strnrchr; +PL_strnrstr; +PL_strnstr; +PL_strpbrk; +PL_strprbrk; +PL_strrchr; +PL_strrstr; +PL_strstr; +libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPR_4.2 { +;+ global: +PL_strtok_r; +;+} NSPR_4.0; diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.rc b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.rc new file mode 100644 index 00000000..15ca10f2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc.rc @@ -0,0 +1,103 @@ +/* -*- 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 ***** */ + + +#include "prinit.h" +#include + +#define MY_LIBNAME "plc" +#define MY_FILEDESCRIPTION "PLC Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "LegalCopyright", "Copyright \251 1996-2000 Netscape Communications Corporation\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc_symvec.opt b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc_symvec.opt new file mode 100644 index 00000000..8bc769e0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plc_symvec.opt @@ -0,0 +1,53 @@ +! Fixed section of symbol vector for LIBPLC4 +! +GSMATCH=LEQUAL,2,2 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.3 +! Previously this was empty. Now we include everything that's specified in +! plc.def. +! -------------------------------------------------------------------------- +! +! NSPR 4.0 +SYMBOL_VECTOR=(PL_Base64Decode=PROCEDURE) +SYMBOL_VECTOR=(PL_Base64Encode=PROCEDURE) +SYMBOL_VECTOR=(PL_CreateOptState=PROCEDURE) +SYMBOL_VECTOR=(PL_DestroyOptState=PROCEDURE) +SYMBOL_VECTOR=(PL_FPrintError=PROCEDURE) +SYMBOL_VECTOR=(PL_GetNextOpt=PROCEDURE) +SYMBOL_VECTOR=(PL_PrintError=PROCEDURE) +SYMBOL_VECTOR=(PL_strcasecmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strcaserstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcasestr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcat=PROCEDURE) +SYMBOL_VECTOR=(PL_strcatn=PROCEDURE) +SYMBOL_VECTOR=(PL_strchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strcmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strcpy=PROCEDURE) +SYMBOL_VECTOR=(PL_strdup=PROCEDURE) +SYMBOL_VECTOR=(PL_strfree=PROCEDURE) +SYMBOL_VECTOR=(PL_strlen=PROCEDURE) +SYMBOL_VECTOR=(PL_strncasecmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strncaserstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncasestr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncat=PROCEDURE) +SYMBOL_VECTOR=(PL_strnchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strncmp=PROCEDURE) +SYMBOL_VECTOR=(PL_strncpy=PROCEDURE) +SYMBOL_VECTOR=(PL_strncpyz=PROCEDURE) +SYMBOL_VECTOR=(PL_strndup=PROCEDURE) +SYMBOL_VECTOR=(PL_strnlen=PROCEDURE) +SYMBOL_VECTOR=(PL_strnpbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strnprbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strnrchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strnrstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strnstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strpbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strprbrk=PROCEDURE) +SYMBOL_VECTOR=(PL_strrchr=PROCEDURE) +SYMBOL_VECTOR=(PL_strrstr=PROCEDURE) +SYMBOL_VECTOR=(PL_strstr=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! NSPR 4.2 +SYMBOL_VECTOR=(PL_strtok_r=PROCEDURE) diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plerror.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plerror.c new file mode 100644 index 00000000..4e38ee6d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plerror.c @@ -0,0 +1,168 @@ +/* -*- 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 ***** */ + +/* +** File:plerror.c +** Description: Simple routine to print translate the calling thread's +** error numbers and print them to "syserr". +*/ + +#include "plerror.h" + +#include "prprf.h" +#include "prerror.h" + +PR_IMPLEMENT(void) PL_FPrintError(PRFileDesc *fd, const char *msg) +{ +static const char *tags[] = +{ + "PR_OUT_OF_MEMORY_ERROR", + "PR_BAD_DESCRIPTOR_ERROR", + "PR_WOULD_BLOCK_ERROR", + "PR_ACCESS_FAULT_ERROR", + "PR_INVALID_METHOD_ERROR", + "PR_ILLEGAL_ACCESS_ERROR", + "PR_UNKNOWN_ERROR", + "PR_PENDING_INTERRUPT_ERROR", + "PR_NOT_IMPLEMENTED_ERROR", + "PR_IO_ERROR", + "PR_IO_TIMEOUT_ERROR", + "PR_IO_PENDING_ERROR", + "PR_DIRECTORY_OPEN_ERROR", + "PR_INVALID_ARGUMENT_ERROR", + "PR_ADDRESS_NOT_AVAILABLE_ERROR", + "PR_ADDRESS_NOT_SUPPORTED_ERROR", + "PR_IS_CONNECTED_ERROR", + "PR_BAD_ADDRESS_ERROR", + "PR_ADDRESS_IN_USE_ERROR", + "PR_CONNECT_REFUSED_ERROR", + "PR_NETWORK_UNREACHABLE_ERROR", + "PR_CONNECT_TIMEOUT_ERROR", + "PR_NOT_CONNECTED_ERROR", + "PR_LOAD_LIBRARY_ERROR", + "PR_UNLOAD_LIBRARY_ERROR", + "PR_FIND_SYMBOL_ERROR", + "PR_INSUFFICIENT_RESOURCES_ERROR", + "PR_DIRECTORY_LOOKUP_ERROR", + "PR_TPD_RANGE_ERROR", + "PR_PROC_DESC_TABLE_FULL_ERROR", + "PR_SYS_DESC_TABLE_FULL_ERROR", + "PR_NOT_SOCKET_ERROR", + "PR_NOT_TCP_SOCKET_ERROR", + "PR_SOCKET_ADDRESS_IS_BOUND_ERROR", + "PR_NO_ACCESS_RIGHTS_ERROR", + "PR_OPERATION_NOT_SUPPORTED_ERROR", + "PR_PROTOCOL_NOT_SUPPORTED_ERROR", + "PR_REMOTE_FILE_ERROR", + "PR_BUFFER_OVERFLOW_ERROR", + "PR_CONNECT_RESET_ERROR", + "PR_RANGE_ERROR", + "PR_DEADLOCK_ERROR", + "PR_FILE_IS_LOCKED_ERROR", + "PR_FILE_TOO_BIG_ERROR", + "PR_NO_DEVICE_SPACE_ERROR", + "PR_PIPE_ERROR", + "PR_NO_SEEK_DEVICE_ERROR", + "PR_IS_DIRECTORY_ERROR", + "PR_LOOP_ERROR", + "PR_NAME_TOO_LONG_ERROR", + "PR_FILE_NOT_FOUND_ERROR", + "PR_NOT_DIRECTORY_ERROR", + "PR_READ_ONLY_FILESYSTEM_ERROR", + "PR_DIRECTORY_NOT_EMPTY_ERROR", + "PR_FILESYSTEM_MOUNTED_ERROR", + "PR_NOT_SAME_DEVICE_ERROR", + "PR_DIRECTORY_CORRUPTED_ERROR", + "PR_FILE_EXISTS_ERROR", + "PR_MAX_DIRECTORY_ENTRIES_ERROR", + "PR_INVALID_DEVICE_STATE_ERROR", + "PR_DEVICE_IS_LOCKED_ERROR", + "PR_NO_MORE_FILES_ERROR", + "PR_END_OF_FILE_ERROR", + "PR_FILE_SEEK_ERROR", + "PR_FILE_IS_BUSY_ERROR", + "", + "PR_IN_PROGRESS_ERROR", + "PR_ALREADY_INITIATED_ERROR", + "PR_GROUP_EMPTY_ERROR", + "PR_INVALID_STATE_ERROR", + "PR_NETWORK_DOWN_ERROR", + "PR_SOCKET_SHUTDOWN_ERROR", + "PR_CONNECT_ABORTED_ERROR", + "PR_HOST_UNREACHABLE_ERROR", + "PR_MAX_ERROR" +}; + +PRErrorCode error = PR_GetError(); +PRInt32 oserror = PR_GetOSError(); +PRIntn thoseIKnowAbout = sizeof(tags) / sizeof(char*); +PRIntn lastError = PR_NSPR_ERROR_BASE + thoseIKnowAbout; + + if (NULL != msg) PR_fprintf(fd, "%s: ", msg); + if ((error < PR_NSPR_ERROR_BASE) || (error >= lastError)) + PR_fprintf( + fd, " (%d)OUT OF RANGE, oserror = %d\n", error, oserror); + else + PR_fprintf( + fd, "%s(%d), oserror = %d\n", + tags[error - PR_NSPR_ERROR_BASE], error, oserror); +} /* PL_FPrintError */ + +PR_IMPLEMENT(void) PL_PrintError(const char *msg) +{ + static PRFileDesc *fd = NULL; + if (NULL == fd) fd = PR_GetSpecialFD(PR_StandardError); + PL_FPrintError(fd, msg); +} /* PL_PrintError */ + +#if defined(WIN16) +/* +** libmain() is a required function for win16 +** +*/ +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ +return TRUE; +} +#endif /* WIN16 */ + + + + + +/* plerror.c */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plgetopt.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plgetopt.c new file mode 100644 index 00000000..e2ccfa1b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plgetopt.c @@ -0,0 +1,184 @@ +/* -*- 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 ***** */ + +/* +** File: plgetopt.c +** Description: utilities to parse argc/argv +*/ + +#include "prmem.h" +#include "prlog.h" +#include "prerror.h" +#include "plstr.h" +#include "plgetopt.h" + +#include + +static char static_Nul = 0; + +struct PLOptionInternal +{ + const char *options; /* client options list specification */ + PRIntn argc; /* original number of arguments */ + char **argv; /* vector of pointers to arguments */ + PRIntn xargc; /* which one we're processing now */ + const char *xargv; /* where within *argv[xargc] */ + PRBool minus; /* do we already have the '-'? */ +}; + +/* +** Create the state in which to parse the tokens. +** +** argc the sum of the number of options and their values +** argv the options and their values +** options vector of single character options w/ | w/o ': +*/ +PR_IMPLEMENT(PLOptState*) PL_CreateOptState( + PRIntn argc, char **argv, const char *options) +{ + PLOptState *opt = NULL; + if (NULL == options) + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + else + { + opt = PR_NEWZAP(PLOptState); + if (NULL == opt) + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + PLOptionInternal *internal = PR_NEW(PLOptionInternal); + if (NULL == internal) + { + PR_DELETE(opt); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + else + { + opt->option = 0; + opt->value = NULL; + opt->internal = internal; + + internal->argc = argc; + internal->argv = argv; + internal->xargc = 0; + internal->xargv = &static_Nul; + internal->minus = PR_FALSE; + internal->options = options; + } + } + } + return opt; +} /* PL_CreateOptState */ + +/* +** Destroy object created by CreateOptState() +*/ +PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt) +{ + PR_DELETE(opt->internal); + PR_DELETE(opt); +} /* PL_DestroyOptState */ + +PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt) +{ + PLOptionInternal *internal = opt->internal; + PRIntn cop, eoo = PL_strlen(internal->options); + + /* + ** If the current xarg points to nul, advance to the next + ** element of the argv vector. If the vector index is equal + ** to argc, we're out of arguments, so return an EOL. + ** Note whether the first character of the new argument is + ** a '-' and skip by it if it is. + */ + while (0 == *internal->xargv) + { + internal->xargc += 1; + if (internal->xargc >= internal->argc) + { + opt->option = 0; + opt->value = NULL; + return PL_OPT_EOL; + } + internal->xargv = internal->argv[internal->xargc]; + internal->minus = ('-' == *internal->xargv ? PR_TRUE : PR_FALSE); /* not it */ + if (internal->minus) internal->xargv += 1; /* and consume */ + } + + /* + ** If we already have a '-' in hand, xargv points to the next + ** option. See if we can find a match in the list of possible + ** options supplied. + */ + + if (internal->minus) + { + for (cop = 0; cop < eoo; ++cop) + { + if (internal->options[cop] == *internal->xargv) + { + opt->option = *internal->xargv; + internal->xargv += 1; + /* + ** if options indicates that there's an associated + ** value, this argv is finished and the next is the + ** option's value. + */ + if (':' == internal->options[cop + 1]) + { + if (0 != *internal->xargv) return PL_OPT_BAD; + opt->value = internal->argv[++(internal->xargc)]; + internal->xargv = &static_Nul; + internal->minus = PR_FALSE; + } + else opt->value = NULL; + return PL_OPT_OK; + } + } + internal->xargv += 1; /* consume that option */ + return PL_OPT_BAD; + } + /* + ** No '-', so it must be a standalone value. The option is nul. + */ + opt->value = internal->argv[internal->xargc]; + internal->xargv = &static_Nul; + opt->option = 0; + return PL_OPT_OK; +} /* PL_GetNextOpt */ + +/* plgetopt.c */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/plvrsion.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plvrsion.c new file mode 100644 index 00000000..e9903cb7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- 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 "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libplc, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* version */ 2, /* this is the only one supported */ + /* buildTime */ _BUILD_TIME, /* usecs since midnight 1/1/1970 GMT */ + /* buildTimeString */ _BUILD_STRING, /* ditto, but human readable */ + /* vMajor */ PR_VMAJOR, /* NSPR's version number */ + /* vMinor */ PR_VMINOR, /* and minor version */ + /* vPatch */ PR_VPATCH, /* and patch */ + /* beta */ PR_BETA, /* beta build boolean */ +#if defined(DEBUG) + /* debug */ PR_TRUE, /* a debug build */ +#else + /* debug */ PR_FALSE, /* an optomized build */ +#endif + /* special */ PR_FALSE, /* they're all special, but ... */ + /* filename */ _PRODUCTION, /* the produced library name */ + /* description */ "Portable runtime", /* what we are */ + /* security */ "N/A", /* not applicable here */ + /* copywrite */ "Copyright (c) 1998 Netscape Communications Corporation. All Rights Reserved", + /* comment */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcat.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcat.c new file mode 100644 index 00000000..f71b0974 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcat.c @@ -0,0 +1,81 @@ +/* -*- 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 "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strcat(char *dest, const char *src) +{ + if( ((char *)0 == dest) || ((const char *)0 == src) ) + return dest; + + return strcat(dest, src); +} + +PR_IMPLEMENT(char *) +PL_strncat(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( ((char *)0 == dest) || ((const char *)0 == src) || (0 == max) ) + return dest; + + for( rv = dest; *dest; dest++ ) + ; + + (void)PL_strncpy(dest, src, max); + return rv; +} + +PR_IMPLEMENT(char *) +PL_strcatn(char *dest, PRUint32 max, const char *src) +{ + char *rv; + PRUint32 dl; + + if( ((char *)0 == dest) || ((const char *)0 == src) ) + return dest; + + for( rv = dest, dl = 0; *dest; dest++, dl++ ) + ; + + if( max <= dl ) return rv; + (void)PL_strncpyz(dest, src, max-dl); + + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strccmp.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strccmp.c new file mode 100644 index 00000000..ec877484 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strccmp.c @@ -0,0 +1,115 @@ +/* -*- 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 "plstr.h" + +static const unsigned char uc[] = +{ + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '{', '|', '}', '~', '\177', + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 +}; + +PR_IMPLEMENT(PRIntn) +PL_strcasecmp(const char *a, const char *b) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + } + + return (PRIntn)(uc[*ua] - uc[*ub]); +} + +PR_IMPLEMENT(PRIntn) +PL_strncasecmp(const char *a, const char *b, PRUint32 max) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( max && (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + max--; + } + + if( 0 == max ) return (PRIntn)0; + + return (PRIntn)(uc[*ua] - uc[*ub]); +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strchr.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strchr.c new file mode 100644 index 00000000..35ccedcc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strchr.c @@ -0,0 +1,88 @@ +/* -*- 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 "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strchr(const char *s, char c) +{ + if( (const char *)0 == s ) return (char *)0; + + return strchr(s, c); +} + +PR_IMPLEMENT(char *) +PL_strrchr(const char *s, char c) +{ + if( (const char *)0 == s ) return (char *)0; + + return strrchr(s, c); +} + +PR_IMPLEMENT(char *) +PL_strnchr(const char *s, char c, PRUint32 n) +{ + if( (const char *)0 == s ) return (char *)0; + + for( ; n && *s; s++, n-- ) + if( *s == c ) + return (char *)s; + + if( ((char)0 == c) && (n > 0) && ((char)0 == *s) ) return (char *)s; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnrchr(const char *s, char c, PRUint32 n) +{ + const char *p; + + if( (const char *)0 == s ) return (char *)0; + + for( p = s; n && *p; p++, n-- ) + ; + + if( ((char)0 == c) && (n > 0) && ((char)0 == *p) ) return (char *)p; + + for( p--; p >= s; p-- ) + if( *p == c ) + return (char *)p; + + return (char *)0; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcmp.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcmp.c new file mode 100644 index 00000000..095e1784 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcmp.c @@ -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 ***** */ + +#include "plstr.h" +#include + +PR_IMPLEMENT(PRIntn) +PL_strcmp(const char *a, const char *b) +{ + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + return (PRIntn)strcmp(a, b); +} + +PR_IMPLEMENT(PRIntn) +PL_strncmp(const char *a, const char *b, PRUint32 max) +{ + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + return (PRIntn)strncmp(a, b, (size_t)max); +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcpy.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcpy.c new file mode 100644 index 00000000..b576b677 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcpy.c @@ -0,0 +1,84 @@ +/* -*- 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 "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strcpy(char *dest, const char *src) +{ + if( ((char *)0 == dest) || ((const char *)0 == src) ) return (char *)0; + + return strcpy(dest, src); +} + +PR_IMPLEMENT(char *) +PL_strncpy(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( (char *)0 == dest ) return (char *)0; + if( (const char *)0 == src ) return (char *)0; + + for( rv = dest; max && ((*dest = *src) != 0); dest++, src++, max-- ) + ; + +#ifdef JLRU + /* XXX I (wtc) think the -- and ++ operators should be postfix. */ + while( --max ) + *++dest = '\0'; +#endif /* JLRU */ + + return rv; +} + +PR_IMPLEMENT(char *) +PL_strncpyz(char *dest, const char *src, PRUint32 max) +{ + char *rv; + + if( (char *)0 == dest ) return (char *)0; + if( (const char *)0 == src ) return (char *)0; + if( 0 == max ) return (char *)0; + + for( rv = dest, max--; max && ((*dest = *src) != 0); dest++, src++, max-- ) + ; + + *dest = '\0'; + + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcstr.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcstr.c new file mode 100644 index 00000000..cb587788 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strcstr.c @@ -0,0 +1,123 @@ +/* -*- 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 "plstr.h" + +PR_IMPLEMENT(char *) +PL_strcasestr(const char *big, const char *little) +{ + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + + for( ; *big; big++ ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strcaserstr(const char *big, const char *little) +{ + const char *p; + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + p = &big[ PL_strlen(big) - ll ]; + if( p < big ) return (char *)0; + + for( ; p >= big; p-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strncasestr(const char *big, const char *little, PRUint32 max) +{ + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + if( ll > max ) return (char *)0; + max -= ll; + max++; + + for( ; max && *big; big++, max-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strncaserstr(const char *big, const char *little, PRUint32 max) +{ + const char *p; + PRUint32 ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = PL_strlen(little); + + for( p = big; max && *p; p++, max-- ) + ; + + p -= ll; + if( p < big ) return (char *)0; + + for( ; p >= big; p-- ) + /* obvious improvement available here */ + if( 0 == PL_strncasecmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strdup.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strdup.c new file mode 100644 index 00000000..f5fe61ad --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strdup.c @@ -0,0 +1,100 @@ +/* -*- 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 "plstr.h" +#include "prmem.h" +#include +#ifdef VBOX_USE_IPRT_IN_NSPR +#include +#endif + +PR_IMPLEMENT(char *) +PL_strdup(const char *s) +{ + char *rv; + size_t n; + + if( (const char *)0 == s ) + s = ""; + + n = strlen(s) + 1; + +#ifdef VBOX_USE_IPRT_IN_NSPR + rv = (char *)RTMemAlloc(n); +#else + rv = (char *)malloc(n); +#endif + if( (char *)0 == rv ) return rv; + + (void)memcpy(rv, s, n); + + return rv; +} + +PR_IMPLEMENT(void) +PL_strfree(char *s) +{ +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(s); +#else + free(s); +#endif +} + +PR_IMPLEMENT(char *) +PL_strndup(const char *s, PRUint32 max) +{ + char *rv; + size_t l; + + if( (const char *)0 == s ) + s = ""; + + l = PL_strnlen(s, max); + +#ifdef VBOX_USE_IPRT_IN_NSPR + rv = (char *)RTMemAlloc(l+1); +#else + rv = (char *)malloc(l+1); +#endif + if( (char *)0 == rv ) return rv; + + (void)memcpy(rv, s, l); + rv[l] = '\0'; + + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strlen.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strlen.c new file mode 100644 index 00000000..6c476777 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strlen.c @@ -0,0 +1,71 @@ +/* -*- 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 "plstr.h" +#include "prtypes.h" +#include "prlog.h" +#include + +PR_IMPLEMENT(PRUint32) +PL_strlen(const char *str) +{ + size_t l; + + if( (const char *)0 == str ) return 0; + + l = strlen(str); + + /* error checking in case we have a 64-bit platform -- make sure + * we don't have ultra long strings that overflow an int32 + */ + if( sizeof(PRUint32) < sizeof(size_t) ) + PR_ASSERT(l < 2147483647); + + return (PRUint32)l; +} + +PR_IMPLEMENT(PRUint32) +PL_strnlen(const char *str, PRUint32 max) +{ + register const char *s; + + if( (const char *)0 == str ) return 0; + for( s = str; max && *s; s++, max-- ) + ; + + return (PRUint32)(s - str); +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strpbrk.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strpbrk.c new file mode 100644 index 00000000..afcb4f51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strpbrk.c @@ -0,0 +1,100 @@ +/* -*- 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 "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strpbrk(const char *s, const char *list) +{ + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + return strpbrk(s, list); +} + +PR_IMPLEMENT(char *) +PL_strprbrk(const char *s, const char *list) +{ + const char *p; + const char *r; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( r = s; *r; r++ ) + ; + + for( r--; r >= s; r-- ) + for( p = list; *p; p++ ) + if( *r == *p ) + return (char *)r; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnpbrk(const char *s, const char *list, PRUint32 max) +{ + const char *p; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( ; max && *s; s++, max-- ) + for( p = list; *p; p++ ) + if( *s == *p ) + return (char *)s; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnprbrk(const char *s, const char *list, PRUint32 max) +{ + const char *p; + const char *r; + + if( ((const char *)0 == s) || ((const char *)0 == list) ) return (char *)0; + + for( r = s; max && *r; r++, max-- ) + ; + + for( r--; r >= s; r-- ) + for( p = list; *p; p++ ) + if( *r == *p ) + return (char *)r; + + return (char *)0; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strstr.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strstr.c new file mode 100644 index 00000000..6bc03d37 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strstr.c @@ -0,0 +1,117 @@ +/* -*- 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 "plstr.h" +#include + +PR_IMPLEMENT(char *) +PL_strstr(const char *big, const char *little) +{ + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + return strstr(big, little); +} + +PR_IMPLEMENT(char *) +PL_strrstr(const char *big, const char *little) +{ + const char *p; + size_t ll; + size_t bl; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + bl = strlen(big); + if( bl < ll ) return (char *)0; + p = &big[ bl - ll ]; + + for( ; p >= big; p-- ) + if( *little == *p ) + if( 0 == strncmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnstr(const char *big, const char *little, PRUint32 max) +{ + size_t ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + if( ll > (size_t)max ) return (char *)0; + max -= (PRUint32)ll; + max++; + + for( ; max && *big; big++, max-- ) + if( *little == *big ) + if( 0 == strncmp(big, little, ll) ) + return (char *)big; + + return (char *)0; +} + +PR_IMPLEMENT(char *) +PL_strnrstr(const char *big, const char *little, PRUint32 max) +{ + const char *p; + size_t ll; + + if( ((const char *)0 == big) || ((const char *)0 == little) ) return (char *)0; + if( ((char)0 == *big) || ((char)0 == *little) ) return (char *)0; + + ll = strlen(little); + + for( p = big; max && *p; p++, max-- ) + ; + + p -= ll; + if( p < big ) return (char *)0; + + for( ; p >= big; p-- ) + if( *little == *p ) + if( 0 == strncmp(p, little, ll) ) + return (char *)p; + + return (char *)0; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/libc/src/strtok.c b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strtok.c new file mode 100644 index 00000000..400e9a4c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/libc/src/strtok.c @@ -0,0 +1,89 @@ +/* -*- 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) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Roland Mainz + * + * 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 "plstr.h" + +PR_IMPLEMENT(char *) +PL_strtok_r(char *s1, const char *s2, char **lasts) +{ + const char *sepp; + int c, sc; + char *tok; + + if( s1 == NULL ) + { + if( *lasts == NULL ) + return NULL; + + s1 = *lasts; + } + + for( ; (c = *s1) != 0; s1++ ) + { + for( sepp = s2 ; (sc = *sepp) != 0 ; sepp++ ) + { + if( c == sc ) + break; + } + if( sc == 0 ) + break; + } + + if( c == 0 ) + { + *lasts = NULL; + return NULL; + } + + tok = s1++; + + for( ; (c = *s1) != 0; s1++ ) + { + for( sepp = s2; (sc = *sepp) != 0; sepp++ ) + { + if( c == sc ) + { + *s1++ = '\0'; + *lasts = s1; + return tok; + } + } + } + *lasts = NULL; + return tok; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/msgc/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/msgc/Makefile.in new file mode 100644 index 00000000..d7299b2b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/Makefile.in @@ -0,0 +1,52 @@ +# +# ***** 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 ***** + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = include src tests + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/include/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/include/MANIFEST b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/MANIFEST new file mode 100644 index 00000000..a45ec20e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/MANIFEST @@ -0,0 +1,5 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +prgc.h diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/include/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/Makefile.in new file mode 100644 index 00000000..60803a02 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/config.mk + +EXPORT_HEADERS = prgc.h +HEADERS = $(EXPORT_HEADERS) gcint.h + +RELEASE_HEADERS = $(EXPORT_HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(EXPORT_HEADERS) + $(INSTALL) -m 444 $(EXPORT_HEADERS) $(dist_includedir) +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(EXPORT_HEADERS) $(MOZ_INCL) +endif + diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/include/gcint.h b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/gcint.h new file mode 100644 index 00000000..10048f06 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/gcint.h @@ -0,0 +1,129 @@ +/* -*- 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 gcint_h___ +#define gcint_h___ + +#include "prmon.h" +#include "prgc.h" + +extern PRLogModuleInfo *_pr_msgc_lm; +extern GCInfo _pr_gcData; + +#if defined(_WIN32) && !defined(DEBUG) +#undef INLINE_LOCK +#endif + +#ifdef INLINE_LOCK +#define LOCK_GC() EnterCriticalSection(&_pr_gcData.lock->mutexHandle) +#define UNLOCK_GC() LeaveCriticalSection(&_pr_gcData.lock->mutexHandle) +#else +#define LOCK_GC() PR_EnterMonitor(_pr_gcData.lock) +#define UNLOCK_GC() PR_ExitMonitor (_pr_gcData.lock) +#define GC_IS_LOCKED() (PR_GetMonitorEntryCount(_pr_gcData.lock)!=0) +#endif + +#ifdef DEBUG +#define _GCTRACE(x, y) if (_pr_gcData.flags & x) GCTrace y +#else +#define _GCTRACE(x, y) +#endif + +extern GCBeginGCHook *_pr_beginGCHook; +extern void *_pr_beginGCHookArg; +extern GCBeginGCHook *_pr_endGCHook; +extern void *_pr_endGCHookArg; + +extern GCBeginFinalizeHook *_pr_beginFinalizeHook; +extern void *_pr_beginFinalizeHookArg; +extern GCBeginFinalizeHook *_pr_endFinalizeHook; +extern void *_pr_endFinalizeHookArg; + +extern int _pr_do_a_dump; +extern FILE *_pr_dump_file; + +extern PRLogModuleInfo *_pr_gc_lm; + +/* +** Root finders. Root finders are used by the GC to find pointers into +** the GC heap that are not contained in the GC heap. +*/ +typedef struct RootFinderStr RootFinder; + +struct RootFinderStr { + RootFinder *next; + GCRootFinder *func; + char *name; + void *arg; +}; +extern RootFinder *_pr_rootFinders; + +typedef struct CollectorTypeStr { + GCType gctype; + PRUint32 flags; +} CollectorType; + +#define GC_MAX_TYPES 256 +extern CollectorType *_pr_collectorTypes; + +#define _GC_TYPE_BUSY 0x1 +#define _GC_TYPE_FINAL 0x2 +#define _GC_TYPE_WEAK 0x4 + +/* Slot in _pr_gcTypes used for free memory */ +#define FREE_MEMORY_TYPEIX 255 + +extern void _PR_InitGC(PRWord flags); +extern void _MD_InitGC(void); +extern void PR_CALLBACK _PR_ScanFinalQueue(void *notused); + +/* +** Grow the GC Heap. +*/ +extern void *_MD_GrowGCHeap(PRUint32 *sizep); + +/* +** Extend the GC Heap. +*/ +extern PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize); + +/* +** Free a GC segment. +*/ +extern void _MD_FreeGCSegment(void *base, PRInt32 len); + +#endif /* gcint_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/include/prgc.h b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/prgc.h new file mode 100644 index 00000000..add30213 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/include/prgc.h @@ -0,0 +1,419 @@ +/* -*- 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 prgc_h___ +#define prgc_h___ + +/* +** API to NSPR gc memory system. +*/ +#include "prtypes.h" +#include "prmon.h" +#include "prthread.h" +#include + +#if defined(WIN16) +#define GCPTR __far +#else +#define GCPTR +#endif + + +PR_BEGIN_EXTERN_C + +/* +** Initialize the garbage collector. +** "flags" is the trace flags (see below). +** "initialHeapSize" is the initial size of the heap and may be zero +** if the default is desired. +** "segmentSize" is the size of each segment of memory added to the +** heap when the heap is grown. +*/ +PR_EXTERN(void) PR_InitGC( + PRWord flags, PRInt32 initialHeapSize, PRInt32 segmentSize, PRThreadScope scope); + +/* +** Shuts down gc and frees up all memory associated with it. +*/ +PR_EXTERN(void) PR_ShutdownGC(PRBool finalizeOnExit); + +/* +** This walk function will be called for every gc object in the +** heap as it is walked. If it returns non-zero, the walk is terminated. +*/ +typedef PRInt32 (*PRWalkFun)(void GCPTR* obj, void* data); + +/* +** GC Type record. This defines all of the GC operations used on a +** particular object type. These structures are passed to +** PR_RegisterType. +*/ +typedef struct GCType { + /* + ** Scan an object that is in the GC heap and call GCInfo.livePointer + ** on all of the pointers in it. If this slot is null then the object + ** won't be scanned (i.e. it has no embedded pointers). + */ + void (PR_CALLBACK *scan)(void GCPTR *obj); + + /* + ** Finalize an object that has no references. This is called by the + ** GC after it has determined where the object debris is but before + ** it has moved the debris to the logical "free list". The object is + ** marked alive for this call and removed from the list of objects + ** that need finalization (finalization only happens once for an + ** object). If this slot is null then the object doesn't need + ** finalization. + */ + void (PR_CALLBACK *finalize)(void GCPTR *obj); + + /* + ** Dump out an object during a PR_DumpGCHeap(). This is used as a + ** debugging tool. + */ + void (PR_CALLBACK *dump)(FILE *out, void GCPTR *obj, PRBool detailed, PRIntn indentLevel); + + /* + ** Add object to summary table. + */ + void (PR_CALLBACK *summarize)(void GCPTR *obj, PRUint32 bytes); + + /* + ** Free hook called by GC when the object is being freed. + */ + void (PR_CALLBACK *free)(void *obj); + + /* Weak pointer support: If the object has a weak pointer (Note: + at most one), this function is used to get the weak link's + offset from the start of the body of a gc object */ + PRUint32 (PR_CALLBACK *getWeakLinkOffset)(void *obj); + + /* Descriptive character for dumping this GCType */ + char kindChar; + + /* + ** Walker routine. This routine should apply fun(obj->ptr, data) + ** for every gc pointer within the object. + */ + PRInt32 (PR_CALLBACK *walk)(void GCPTR *obj, PRWalkFun fun, void* data); +} GCType; + +/* +** This data structure must be added as the hash table passed to +** the summarize method of GCType. +*/ +typedef struct PRSummaryEntry { + void* clazz; + PRInt32 instancesCount; + PRInt32 totalSize; +} PRSummaryEntry; + +/* +** This function pointer must be registered by users of nspr +** to produce the finally summary after all object in the +** heap have been visited. +*/ +typedef void (PR_CALLBACK *PRSummaryPrinter)(FILE *out, void* closure); + +PR_EXTERN(void) PR_CALLBACK PR_RegisterSummaryPrinter(PRSummaryPrinter fun, void* closure); + +typedef void PR_CALLBACK GCRootFinder(void *arg); +typedef void PR_CALLBACK GCBeginFinalizeHook(void *arg); +typedef void PR_CALLBACK GCEndFinalizeHook(void *arg); +typedef void PR_CALLBACK GCBeginGCHook(void *arg); +typedef void PR_CALLBACK GCEndGCHook(void *arg); + +typedef enum { PR_GCBEGIN, PR_GCEND } GCLockHookArg; + +typedef void PR_CALLBACK GCLockHookFunc(GCLockHookArg arg1, void *arg2); + +typedef struct GCLockHook GCLockHook; + +struct GCLockHook { + GCLockHookFunc* func; + void* arg; + GCLockHook* next; + GCLockHook* prev; +}; + + +/* +** Hooks which are called at the beginning and end of the GC process. +** The begin hooks are called before the root finding step. The hooks are +** called with threading disabled, so it is now allowed to re-enter the +** kernel. The end hooks are called after the gc has finished but before +** the finalizer has run. +*/ +PR_EXTERN(void) PR_CALLBACK PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg); +PR_EXTERN(void) PR_CALLBACK PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg); +PR_EXTERN(void) PR_CALLBACK PR_SetEndGCHook(GCBeginGCHook *hook, void *arg); +PR_EXTERN(void) PR_CALLBACK PR_GetEndGCHook(GCEndGCHook **hook, void **arg); + +/* +** Called before SuspendAll is called by dogc, so that GC thread can hold +** all the locks before hand to avoid any deadlocks +*/ + +/* +PR_EXTERN(void) PR_SetGCLockHook(GCLockHook *hook, void *arg); +PR_EXTERN(void) PR_GetGCLockHook(GCLockHook **hook, void **arg); +*/ + +PR_EXTERN(int) PR_RegisterGCLockHook(GCLockHookFunc *hook, void *arg); + +/* +** Hooks which are called at the beginning and end of the GC finalization +** process. After the GC has identified all of the dead objects in the +** heap, it looks for objects that need finalization. Before it calls the +** first finalization proc (see the GCType structure above) it calls the +** begin hook. When it has finalized the last object it calls the end +** hook. +*/ +PR_EXTERN(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg); +PR_EXTERN(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, void **arg); +PR_EXTERN(void) PR_SetEndFinalizeHook(GCBeginFinalizeHook *hook, void *arg); +PR_EXTERN(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg); + +/* +** Register a GC type. Return's the index into the GC internal type +** table. The returned value is passed to PR_AllocMemory. After the call, +** the "type" memory belongs to the GC (the caller must not free it or +** change it). +*/ +PR_EXTERN(PRInt32) PR_RegisterType(GCType *type); + +/* +** Register a root finder with the collector. The collector will call +** these functions to identify all of the roots before collection +** proceeds. "arg" is passed to the function when it is called. +*/ +PR_EXTERN(PRStatus) PR_RegisterRootFinder(GCRootFinder func, char *name, void *arg); + +/* +** Allocate some GC'able memory. The object must be at least bytes in +** size. The type index function for the object is specified. "flags" +** specifies some control flags. If PR_ALLOC_CLEAN is set then the memory +** is zero'd before being returned. If PR_ALLOC_DOUBLE is set then the +** allocated memory is double aligned. +** +** Any memory cell that you store a pointer to something allocated by +** this call must be findable by the GC. Use the PR_RegisterRootFinder to +** register new places where the GC will look for pointers into the heap. +** The GC already knows how to scan any NSPR threads or monitors. +*/ +PR_EXTERN(PRWord GCPTR *)PR_AllocMemory( + PRWord bytes, PRInt32 typeIndex, PRWord flags); +PR_EXTERN(PRWord GCPTR *)PR_AllocSimpleMemory( + PRWord bytes, PRInt32 typeIndex); + +/* +** This function can be used to cause PR_AllocMemory to always return +** NULL. This may be useful in low memory situations when we're trying to +** shutdown applets. +*/ +PR_EXTERN(void) PR_EnableAllocation(PRBool yesOrNo); + +/* flags bits */ +#define PR_ALLOC_CLEAN 0x1 +#define PR_ALLOC_DOUBLE 0x2 +#define PR_ALLOC_ZERO_HANDLE 0x4 /* XXX yes, it's a hack */ + +/* +** Force a garbage collection right now. Return when it completes. +*/ +PR_EXTERN(void) PR_GC(void); + +/* +** Force a finalization right now. Return when finalization has +** completed. Finalization completes when there are no more objects +** pending finalization. This does not mean there are no objects in the +** gc heap that will need finalization should a collection be done after +** this call. +*/ +PR_EXTERN(void) PR_ForceFinalize(void); + +/* +** Dump the GC heap out to the given file. This will stop the system dead +** in its tracks while it is occuring. +*/ +PR_EXTERN(void) PR_DumpGCHeap(FILE *out, PRBool detailed); + +/* +** Wrapper for PR_DumpGCHeap +*/ +PR_EXTERN(void) PR_DumpMemory(PRBool detailed); + +/* +** Dump summary of objects allocated. +*/ +PR_EXTERN(void) PR_DumpMemorySummary(void); + +/* +** Dump the application heaps. +*/ +PR_EXTERN(void) PR_DumpApplicationHeaps(void); + +/* +** Helper function used by dump routines to do the indentation in a +** consistent fashion. +*/ +PR_EXTERN(void) PR_DumpIndent(FILE *out, PRIntn indent); + +/* +** The GCInfo structure contains all of the GC state... +** +** busyMemory: +** The amount of GC heap memory that is busy at this instant. Busy +** doesn't mean alive, it just means that it has been +** allocated. Immediately after a collection busy means how much is +** alive. +** +** freeMemory: +** The amount of GC heap memory that is as yet unallocated. +** +** allocMemory: +** The sum of free and busy memory in the GC heap. +** +** maxMemory: +** The maximum size that the GC heap is allowed to grow. +** +** lowSeg: +** The lowest segment currently used in the GC heap. +** +** highSeg: +** The highest segment currently used in the GC heap. +** The lowSeg and highSeg members are used for a "quick test" of whether +** a pointer falls within the GC heap. [ see GC_IN_HEAP(...) ] +** +** lock: +** Monitor used for syncronization within the GC. +** +** finalizer: +** Thread in which the GC finalizer is running. +** +** liveBlock: +** Object scanning functions call through this function pointer to +** register a potential block of pointers with the collector. (This is +** currently not at all different than processRoot.) +** +** livePointer: +** Object scanning functions call through this function pointer to +** register a single pointer with the collector. +** +** processRootBlock: +** When a root finder identifies a root it should call through this +** function pointer so that the GC can process the root. The call takes +** a base address and count which the gc will examine for valid heap +** pointers. +** +** processRootPointer: +** When a root finder identifies a root it should call through this +** function pointer so that the GC can process the root. The call takes +** a single pointer value. +*/ +typedef struct GCInfoStr { + PRWord flags; /* trace flags (see below) */ + PRWord busyMemory; /* memory in use right now */ + PRWord freeMemory; /* memory free right now */ + PRWord allocMemory; /* sum of busy & free memory */ + PRWord maxMemory; /* max memory we are allowed to allocate */ + PRWord *lowSeg; /* lowest segment in the GC heap */ + PRWord *highSeg; /* higest segment in the GC heap */ + + PRMonitor *lock; + PRThread *finalizer; + + void (PR_CALLBACK *liveBlock)(void **base, PRInt32 count); + void (PR_CALLBACK *livePointer)(void *ptr); + void (PR_CALLBACK *processRootBlock)(void **base, PRInt32 count); + void (PR_CALLBACK *processRootPointer)(void *ptr); + FILE* dumpOutput; +#ifdef GCTIMINGHOOK + void (*gcTimingHook)(int32 gcTime); +#endif +} GCInfo; + +PR_EXTERN(GCInfo *) PR_GetGCInfo(void); +PR_EXTERN(PRBool) PR_GC_In_Heap(void GCPTR *object); + +/* +** Simple bounds check to see if a pointer is anywhere near the GC heap. +** Used to avoid calls to PR_ProcessRoot and GCInfo.livePointer by object +** scanning code. +*/ +#if !defined(XP_PC) || defined(_WIN32) +#define GC_IN_HEAP(_info, _p) (((PRWord*)(_p) >= (_info)->lowSeg) && \ + ((PRWord*)(_p) < (_info)->highSeg)) +#else +/* +** The simple bounds check, above, doesn't work in Win16, because we don't +** maintain: lowSeg == MIN(all segments) and highSeg == MAX(all segments). +** So we have to do a little better. +*/ +#define GC_IN_HEAP(_info, _p) PR_GC_In_Heap(_p) +#endif + +PR_EXTERN(PRWord) PR_GetObjectHeader(void *ptr); + +PR_EXTERN(PRWord) PR_SetObjectHeader(void *ptr, PRWord newUserBits); + +/************************************************************************/ + +/* Trace flags (passed to PR_InitGC or in environment GCLOG) */ +#define GC_TRACE 0x0001 +#define GC_ROOTS 0x0002 +#define GC_LIVE 0x0004 +#define GC_ALLOC 0x0008 +#define GC_MARK 0x0010 +#define GC_SWEEP 0x0020 +#define GC_DEBUG 0x0040 +#define GC_FINAL 0x0080 + +#if defined(DEBUG_kipp) || defined(DEBUG_warren) +#define GC_CHECK 0x0100 +#endif + +#ifdef DEBUG +#define GCTRACE(x, y) if (PR_GetGCInfo()->flags & x) GCTrace y +PR_EXTERN(void) GCTrace(char *fmt, ...); +#else +#define GCTRACE(x, y) +#endif + +PR_END_EXTERN_C + +#endif /* prgc_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/Makefile.in new file mode 100644 index 00000000..e822fc29 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/Makefile.in @@ -0,0 +1,103 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +INCLUDES = -I$(dist_includedir) -I../include + +CSRCS = prgcapi.c prmsgc.c + +ifeq ($(OS_ARCH),WINNT) +CSRCS += win32gc.c +else +ifeq ($(OS_ARCH),OS2) +CSRCS += os2gc.c +else +CSRCS += unixgc.c +endif +endif + +NSPR_VERSION = $(MOD_MAJOR_VERSION) + +EXTRA_LIBS = $(LIBNSPR) + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +ifeq ($(OS_ARCH), WINNT) +ifdef NS_USE_GCC +DLLBASE=-Wl,--image-base -Wl,0x30000000 +else +DLLBASE=/BASE:0x30000000 +endif # GCC +#RES=$(OBJDIR)/ds.res +#RESNAME=$(MOD_DEPTH)/pr/src/nspr.rc +#OS_LIBS = user32.lib +endif # WINNT + +LIBRARY_NAME = msgc +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# The Client build wants the shared libraries in $(dist_bindir), +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/macgc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/macgc.c new file mode 100644 index 00000000..eafc28e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/macgc.c @@ -0,0 +1,75 @@ +/* -*- 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 "MacMemAllocator.h" + +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(size_t *sizep) +{ + void *heapPtr = NULL; + size_t heapSize = *sizep; + + // In previous versions of this code we tried to allocate GC heaps from the application + // heap. In the 4.0 application, we try to keep our app heap allications to a minimum + // and instead go through our own memory allocation routines. + heapPtr = malloc(heapSize); + + if (heapPtr == NULL) { + FreeMemoryStats stats; + + memtotal(heapSize, &stats); // How much can we allcoate? + + if (stats.maxBlockSize < heapSize) + heapSize = stats.maxBlockSize; + + heapPtr = malloc(heapSize); + + if (heapPtr == NULL) // Now we're hurting + heapSize = 0; + } + + *sizep = heapSize; + return heapPtr; +} + + +void _MD_FreeGCSegment(void *base, int32 /* len */) +{ + free(base); +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/os2gc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/os2gc.c new file mode 100644 index 00000000..f99bb678 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/os2gc.c @@ -0,0 +1,83 @@ +/* -*- 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 ***** */ + +/* + * GC related routines + * + */ +#include "prlog.h" + +#include + +/* Leave a bit of room for any malloc header bytes... */ +#define MAX_SEGMENT_SIZE (65536L - 4096L) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + + if ( *sizep > MAX_SEGMENT_SIZE ) + { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + + +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + /* Not sure about this. Todd? */ + return PR_FALSE; +} + + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + if (base) + { + free(base); + } +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prgcapi.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prgcapi.c new file mode 100644 index 00000000..23f7ea51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prgcapi.c @@ -0,0 +1,351 @@ +/* -*- 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 +#include +#include +#include "prenv.h" +#include "prmem.h" +#include "prmon.h" +#include "prlog.h" +#include "prthread.h" +#if defined(XP_MAC) +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif +#include "gcint.h" + +/* +** Generic GC implementation independent code for the NSPR GC +*/ + +RootFinder *_pr_rootFinders; + +CollectorType *_pr_collectorTypes; + +/* GC State information */ +GCInfo _pr_gcData; + +GCBeginGCHook *_pr_beginGCHook; +void *_pr_beginGCHookArg; +GCBeginGCHook *_pr_endGCHook; +void *_pr_endGCHookArg; + +GCBeginFinalizeHook *_pr_beginFinalizeHook; +void *_pr_beginFinalizeHookArg; +GCBeginFinalizeHook *_pr_endFinalizeHook; +void *_pr_endFinalizeHookArg; + +FILE *_pr_dump_file; +int _pr_do_a_dump; +GCLockHook *_pr_GCLockHook; + +extern PRLogModuleInfo *_pr_msgc_lm; + +/************************************************************************/ + +static PRStatus PR_CALLBACK +pr_ScanOneThread(PRThread* t, void** addr, PRUword count, void* closure) +{ +#if defined(XP_MAC) +#pragma unused (t, closure) +#endif + + _pr_gcData.processRootBlock(addr, count); + return PR_SUCCESS; +} + +/* +** Scan all of the threads C stack's and registers, looking for "root" +** pointers into the GC heap. These are the objects that the GC cannot +** move and are considered "live" by the GC. Caller has stopped all of +** the threads from running. +*/ +static void PR_CALLBACK ScanThreads(void *arg) +{ + PR_ScanStackPointers(pr_ScanOneThread, arg); +} + +/************************************************************************/ + +PR_IMPLEMENT(GCInfo *) PR_GetGCInfo(void) +{ + return &_pr_gcData; +} + + +PR_IMPLEMENT(PRInt32) PR_RegisterType(GCType *t) +{ + CollectorType *ct, *ect; + int rv = -1; + + LOCK_GC(); + ct = &_pr_collectorTypes[0]; + ect = &_pr_collectorTypes[FREE_MEMORY_TYPEIX]; + for (; ct < ect; ct++) { + if (ct->flags == 0) { + ct->gctype = *t; + ct->flags = _GC_TYPE_BUSY; + if (0 != ct->gctype.finalize) { + ct->flags |= _GC_TYPE_FINAL; + } + if (0 != ct->gctype.getWeakLinkOffset) { + ct->flags |= _GC_TYPE_WEAK; + } + rv = ct - &_pr_collectorTypes[0]; + break; + } + } + UNLOCK_GC(); + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_RegisterRootFinder( + GCRootFinder f, char *name, void *arg) +{ + RootFinder *rf = PR_NEWZAP(RootFinder); + if (rf) { + rf->func = f; + rf->name = name; + rf->arg = arg; + + LOCK_GC(); + rf->next = _pr_rootFinders; + _pr_rootFinders = rf; + UNLOCK_GC(); + return PR_SUCCESS; + } + return PR_FAILURE; +} + + +PR_IMPLEMENT(int) PR_RegisterGCLockHook(GCLockHookFunc* f, void *arg) +{ + + GCLockHook *rf = 0; + + rf = (GCLockHook*) calloc(1, sizeof(GCLockHook)); + if (rf) { + rf->func = f; + rf->arg = arg; + + LOCK_GC(); + /* first dummy node */ + if (! _pr_GCLockHook) { + _pr_GCLockHook = (GCLockHook*) calloc(1, sizeof(GCLockHook)); + _pr_GCLockHook->next = _pr_GCLockHook; + _pr_GCLockHook->prev = _pr_GCLockHook; + } + + rf->next = _pr_GCLockHook; + rf->prev = _pr_GCLockHook->prev; + _pr_GCLockHook->prev->next = rf; + _pr_GCLockHook->prev = rf; + UNLOCK_GC(); + return 0; + } + return -1; +} + +/* +PR_IMPLEMENT(void) PR_SetGCLockHook(GCLockHook *hook, void *arg) +{ + LOCK_GC(); + _pr_GCLockHook = hook; + _pr_GCLockHookArg2 = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetGCLockHook(GCLockHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_GCLockHook; + *arg = _pr_GCLockHookArg2; + UNLOCK_GC(); +} +*/ + + +PR_IMPLEMENT(void) PR_SetBeginGCHook(GCBeginGCHook *hook, void *arg) +{ + LOCK_GC(); + _pr_beginGCHook = hook; + _pr_beginGCHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetBeginGCHook(GCBeginGCHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_beginGCHook; + *arg = _pr_beginGCHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetEndGCHook(GCEndGCHook *hook, void *arg) +{ + LOCK_GC(); + _pr_endGCHook = hook; + _pr_endGCHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetEndGCHook(GCEndGCHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_endGCHook; + *arg = _pr_endGCHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetBeginFinalizeHook(GCBeginFinalizeHook *hook, void *arg) +{ + LOCK_GC(); + _pr_beginFinalizeHook = hook; + _pr_beginFinalizeHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetBeginFinalizeHook(GCBeginFinalizeHook **hook, + void **arg) +{ + LOCK_GC(); + *hook = _pr_beginFinalizeHook; + *arg = _pr_beginFinalizeHookArg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_SetEndFinalizeHook(GCEndFinalizeHook *hook, void *arg) +{ + LOCK_GC(); + _pr_endFinalizeHook = hook; + _pr_endFinalizeHookArg = arg; + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) PR_GetEndFinalizeHook(GCEndFinalizeHook **hook, void **arg) +{ + LOCK_GC(); + *hook = _pr_endFinalizeHook; + *arg = _pr_endFinalizeHookArg; + UNLOCK_GC(); +} + +#ifdef DEBUG +#include "prprf.h" + +#if defined(WIN16) +static FILE *tracefile = 0; +#endif + +PR_IMPLEMENT(void) GCTrace(char *fmt, ...) +{ + va_list ap; + char buf[400]; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); +#if defined(WIN16) + if ( tracefile == 0 ) + { + tracefile = fopen( "xxxGCtr", "w" ); + } + fprintf(tracefile, "%s\n", buf ); + fflush(tracefile); +#else + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("%s", buf)); +#endif +} +#endif + +void _PR_InitGC(PRWord flags) +{ + static char firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + _MD_InitGC(); + + if (flags == 0) { + char *ev = PR_GetEnv("GCLOG"); + if (ev && ev[0]) { + flags = atoi(ev); + } + } + _pr_gcData.flags = flags; + + _pr_gcData.lock = PR_NewMonitor(); + + _pr_collectorTypes = (CollectorType*) PR_CALLOC(256 * sizeof(CollectorType)); + + PR_RegisterRootFinder(ScanThreads, "scan threads", 0); + PR_RegisterRootFinder(_PR_ScanFinalQueue, "scan final queue", 0); +} + +extern void pr_FinalizeOnExit(void); + +#ifdef DEBUG +#ifdef GC_STATS +PR_PUBLIC_API(void) PR_PrintGCAllocStats(void); +#endif +#endif + +PR_IMPLEMENT(void) +PR_ShutdownGC(PRBool finalizeOnExit) +{ + /* first finalize all the objects in the heap */ + if (finalizeOnExit) { + pr_FinalizeOnExit(); + } + +#ifdef DEBUG +#ifdef GC_STATS + PR_PrintGCAllocStats(); +#endif /* GC_STATS */ +#endif /* DEBUG */ + + /* then the chance for any future allocations */ + + /* finally delete the gc heap */ + + /* write me */ +} + +/******************************************************************************/ diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prmsgc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prmsgc.c new file mode 100644 index 00000000..ad0566a4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/prmsgc.c @@ -0,0 +1,3514 @@ +/* -*- 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 +#include +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +#include "prclist.h" +#include "prbit.h" + +#include "prtypes.h" +#include "prenv.h" +#include "prgc.h" +#include "prthread.h" +#include "prlog.h" +#include "prlong.h" +#include "prinrval.h" +#include "prprf.h" +#include "gcint.h" + +#if defined(XP_MAC) +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif + +typedef void (*PRFileDumper)(FILE *out, PRBool detailed); + +PR_EXTERN(void) +PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed); + +/* +** Mark&sweep garbage collector. Supports objects that require +** finalization, objects that can have a single weak link, and special +** objects that require care during sweeping. +*/ + +PRLogModuleInfo *_pr_msgc_lm; +PRLogModuleInfo* GC; + +static PRInt32 _pr_pageShift; +static PRInt32 _pr_pageSize; + +#ifdef DEBUG +#define GCMETER +#endif +#ifdef DEBUG_jwz +# undef GCMETER +#endif /* 1 */ + +#ifdef GCMETER +#define METER(x) x +#else +#define METER(x) +#endif + +/* +** Make this constant bigger to reduce the amount of recursion during +** garbage collection. +*/ +#define MAX_SCAN_Q 100L + +#if defined(XP_PC) && !defined(WIN32) +#define MAX_SEGS 400L +#define MAX_SEGMENT_SIZE (65536L - 4096L) +#define SEGMENT_SIZE (65536L - 4096L) +#define MAX_ALLOC_SIZE (65536L - 4096L) +#else +#define MAX_SEGS 400L +#define MAX_SEGMENT_SIZE (2L * 256L * 1024L) +#define SEGMENT_SIZE (1L * 256L * 1024L) +#define MAX_ALLOC_SIZE (4L * 1024L * 1024L) +#endif + +/* + * The highest value that can fit into a signed integer. This + * is used to prevent overflow of allocation size in alloc routines. + */ + +#define MAX_INT ((1UL << (PR_BITS_PER_INT - 1)) - 1) + +/* + * On 32-bit machines, only 22 bits are used in the cibx integer to + * store size since 8 bits of the integer are used to store type, and + * of the remainder, 2 are user defined. Max allocation size = 2^22 -1 + */ + +#define MAX_ALLOC ( (1L << (PR_BYTES_PER_WORD_LOG2 + WORDS_BITS )) -1) + +/* The minimum percentage of free heap space after a collection. If + the amount of free space doesn't meet this criteria then we will + attempt to grow the heap */ +#ifdef XP_MAC +#define MIN_FREE_THRESHOLD_AFTER_GC 10L +#else +#define MIN_FREE_THRESHOLD_AFTER_GC 20L +#endif + +static PRInt32 segmentSize = SEGMENT_SIZE; + +static PRInt32 collectorCleanupNeeded; + +#ifdef GCMETER +PRUint32 _pr_gcMeter; + +#define _GC_METER_STATS 0x01L +#define _GC_METER_GROWTH 0x02L +#define _GC_METER_FREE_LIST 0x04L +#endif + +/************************************************************************/ + +#define LINEAR_BIN_EXPONENT 5 +#define NUM_LINEAR_BINS ((PRUint32)1 << LINEAR_BIN_EXPONENT) +#define FIRST_LOG_BIN (NUM_LINEAR_BINS - LINEAR_BIN_EXPONENT) + +/* Each free list bin holds a chunk of memory sized from + 2^n to (2^(n+1))-1 inclusive. */ +#define NUM_BINS (FIRST_LOG_BIN + 32) + +/* + * Find the bin number for a given size (in bytes). This does not round up as + * values from 2^n to (2^(n+1))-1 share the same bin. + */ +#define InlineBinNumber(_bin,_bytes) \ +{ \ + PRUint32 _t, _n = (PRUint32) _bytes / 4; \ + if (_n < NUM_LINEAR_BINS) { \ + _bin = _n; \ + } else { \ + _bin = FIRST_LOG_BIN; \ + if ((_t = (_n >> 16)) != 0) { _bin += 16; _n = _t; } \ + if ((_t = (_n >> 8)) != 0) { _bin += 8; _n = _t; } \ + if ((_t = (_n >> 4)) != 0) { _bin += 4; _n = _t; } \ + if ((_t = (_n >> 2)) != 0) { _bin += 2; _n = _t; } \ + if ((_n >> 1) != 0) _bin++; \ + } \ +} + +#define BIG_ALLOC 16384L + +#define MIN_FREE_CHUNK_BYTES ((PRInt32)sizeof(GCFreeChunk)) + +/* Note: fix code in PR_AllocMemory if you change the size of GCFreeChunk + so that it zeros the right number of words */ +typedef struct GCFreeChunk { + struct GCFreeChunk *next; + struct GCSeg *segment; + PRInt32 chunkSize; +} GCFreeChunk; + +typedef struct GCSegInfo { + struct GCSegInfo *next; + char *base; + char *limit; + PRWord *hbits; + int fromMalloc; +} GCSegInfo; + +typedef struct GCSeg { + char *base; + char *limit; + PRWord *hbits; + GCSegInfo *info; +} GCSeg; + +#ifdef GCMETER +typedef struct GCMeter { + PRInt32 allocBytes; + PRInt32 wastedBytes; + PRInt32 numFreeChunks; + PRInt32 skippedFreeChunks; +} GCMeter; +static GCMeter meter; +#endif + +/* +** There is one of these for each segment of GC'able memory. +*/ +static GCSeg segs[MAX_SEGS]; +static GCSegInfo *freeSegs; +static GCSeg* lastInHeap; +static int nsegs; + +static GCFreeChunk *bins[NUM_BINS]; +static PRInt32 minBin; +static PRInt32 maxBin; + +/* +** Scan Q used to avoid deep recursion when scanning live objects for +** heap pointers +*/ +typedef struct GCScanQStr { + PRWord *q[MAX_SCAN_Q]; + int queued; +} GCScanQ; + +static GCScanQ *pScanQ; + +#ifdef GCMETER +PRInt32 _pr_maxScanDepth; +PRInt32 _pr_scanDepth; +#endif + +/* +** Keeps track of the number of bytes allocated via the BigAlloc() +** allocator. When the number of bytes allocated, exceeds the +** BIG_ALLOC_GC_SIZE, then a GC will occur before the next allocation +** is done... +*/ +#define BIG_ALLOC_GC_SIZE (4*SEGMENT_SIZE) +static PRWord bigAllocBytes = 0; + +/* +** There is one GC header word in front of each GC allocated object. We +** use it to contain information about the object (what TYPEIX to use for +** scanning it, how big it is, it's mark status, and if it's a root). +*/ +#define TYPEIX_BITS 8L +#define WORDS_BITS 20L +#define MAX_CBS (1L << GC_TYPEIX_BITS) +#define MAX_WORDS (1L << GC_WORDS_BITS) +#define TYPEIX_SHIFT 24L +#define MAX_TYPEIX ((1L << TYPEIX_BITS) - 1L) +#define TYPEIX_MASK PR_BITMASK(TYPEIX_BITS) +#define WORDS_SHIFT 2L +#define WORDS_MASK PR_BITMASK(WORDS_BITS) +#define MARK_BIT 1L +#define FINAL_BIT 2L + +/* Two bits per object header are reserved for the user of the memory + system to store information into. */ +#define GC_USER_BITS_SHIFT 22L +#define GC_USER_BITS 0x00c00000L + +#define MAKE_HEADER(_cbix,_words) \ + ((PRWord) (((unsigned long)(_cbix) << TYPEIX_SHIFT) \ + | ((unsigned long)(_words) << WORDS_SHIFT))) + +#define GET_TYPEIX(_h) \ + (((PRUword)(_h) >> TYPEIX_SHIFT) & 0xff) + +#define MARK(_sp,_p) \ + (((PRWord *)(_p))[0] |= MARK_BIT) +#define IS_MARKED(_sp,_p) \ + (((PRWord *)(_p))[0] & MARK_BIT) +#define OBJ_BYTES(_h) \ + (((PRInt32) (_h) & 0x003ffffcL) << (PR_BYTES_PER_WORD_LOG2-2L)) + +#define GC_GET_USER_BITS(_h) (((_h) & GC_USER_BITS) >> GC_USER_BITS_SHIFT) + +/************************************************************************/ + +/* +** Mark the start of an object in a segment. Note that we mark the header +** word (which we always have), not the data word (which we may not have +** for empty objects). +** XXX tune: put subtract of _sp->base into _sp->hbits pointer? +*/ +#if !defined(WIN16) +#define SET_HBIT(_sp,_ph) \ + SET_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) + +#define CLEAR_HBIT(_sp,_ph) \ + CLEAR_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) + +#define IS_HBIT(_sp,_ph) \ + TEST_BIT((_sp)->hbits, (((PRWord*)(_ph)) - ((PRWord*) (_sp)->base))) +#else + +#define SET_HBIT(_sp,_ph) set_hbit(_sp,_ph) + +#define CLEAR_HBIT(_sp,_ph) clear_hbit(_sp,_ph) + +#define IS_HBIT(_sp,_ph) is_hbit(_sp,_ph) + +static void +set_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + sp->hbits[index] |= mask; +} + +static void +clear_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + sp->hbits[index] &= ~mask; +} + +static int +is_hbit(GCSeg *sp, PRWord *p) +{ + unsigned int distance; + unsigned int index; + PRWord mask; + + PR_ASSERT( SELECTOROF(p) == SELECTOROF(sp->base) ); + PR_ASSERT( OFFSETOF(p) >= OFFSETOF(sp->base) ); + + distance = (OFFSETOF(p) - OFFSETOF(sp->base)) >> 2; + index = distance >> PR_BITS_PER_WORD_LOG2; + mask = 1L << (distance&(PR_BITS_PER_WORD-1)); + + return ((sp->hbits[index] & mask) != 0); +} + + +#endif /* WIN16 */ + +/* +** Given a pointer into this segment, back it up until we are at the +** start of the object the pointer points into. Each heap segment has a +** bitmap that has one bit for each word of the objects it contains. The +** bit's are set for the firstword of an object, and clear for it's other +** words. +*/ +static PRWord *FindObject(GCSeg *sp, PRWord *p) +{ + PRWord *base; + + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p & ~(PR_BYTES_PER_WORD-1L)); + + base = (PRWord *) sp->base; +#if defined(WIN16) + PR_ASSERT( SELECTOROF(p) == SELECTOROF(base)); +#endif + do { + if (IS_HBIT(sp, p)) { + return (p); + } + p--; + } while ( p >= base ); + + /* Heap is corrupted! */ + _GCTRACE(GC_TRACE, ("ERROR: The heap is corrupted!!! aborting now!")); + abort(); + return NULL; +} + +/************************************************************************/ +#if !defined(XP_PC) || defined(XP_OS2) +#define OutputDebugString(msg) +#endif + +#if !defined(WIN16) +#define IN_SEGMENT(_sp, _p) \ + ((((char *)(_p)) >= (_sp)->base) && \ + (((char *)(_p)) < (_sp)->limit)) +#else +#define IN_SEGMENT(_sp, _p) \ + ((((PRWord)(_p)) >= ((PRWord)(_sp)->base)) && \ + (((PRWord)(_p)) < ((PRWord)(_sp)->limit))) +#endif + +static GCSeg *InHeap(void *p) +{ + GCSeg *sp, *esp; + + if (lastInHeap && IN_SEGMENT(lastInHeap, p)) { + return lastInHeap; + } + + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p)) { + lastInHeap = sp; + return sp; + } + } + return 0; +} + +/* +** Grow the heap by allocating another segment. Fudge the requestedSize +** value to try to pre-account for the HBITS. +*/ +static GCSeg* DoGrowHeap(PRInt32 requestedSize, PRBool exactly) +{ + GCSeg *sp; + GCSegInfo *segInfo; + GCFreeChunk *cp; + char *base; + PRWord *hbits; + PRInt32 nhbytes, nhbits; + PRUint32 allocSize; + + if (nsegs == MAX_SEGS) { + /* No room for more segments */ + return 0; + } + + segInfo = (GCSegInfo*) PR_MALLOC(sizeof(GCSegInfo)); +#ifdef DEBUG + { + char str[256]; + sprintf(str, "[1] Allocated %ld bytes at %p\n", + (long) sizeof(GCSegInfo), segInfo); + OutputDebugString(str); + } +#endif + if (!segInfo) { + return 0; + } + +#if defined(WIN16) + if (requestedSize > segmentSize) { + PR_DELETE(segInfo); + return 0; + } +#endif + + /* Get more memory from the OS */ + if (exactly) { + allocSize = requestedSize; + base = (char *) PR_MALLOC(requestedSize); + } else { + allocSize = requestedSize; + allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift; + allocSize <<= _pr_pageShift; + base = (char*)_MD_GrowGCHeap(&allocSize); + } + if (!base) { + PR_DELETE(segInfo); + return 0; + } + + nhbits = (PRInt32)( + (allocSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2); + nhbytes = ((nhbits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + + /* Get bitmap memory from malloc heap */ +#if defined(WIN16) + PR_ASSERT( nhbytes < MAX_ALLOC_SIZE ); +#endif + hbits = (PRWord *) PR_CALLOC((PRUint32)nhbytes); + if (!hbits) { + /* Loser! */ + PR_DELETE(segInfo); + if (exactly) { + PR_DELETE(base); + } else { + /* XXX do something about this */ + /* _MD_FreeGCSegment(base, allocSize); */ + } + return 0; + } + + /* + ** Setup new segment. + */ + sp = &segs[nsegs++]; + segInfo->base = sp->base = base; + segInfo->limit = sp->limit = base + allocSize; + segInfo->hbits = sp->hbits = hbits; + sp->info = segInfo; + segInfo->fromMalloc = exactly; + memset(base, 0, allocSize); + +#ifdef GCMETER + if (_pr_gcMeter & _GC_METER_GROWTH) { + fprintf(stderr, "[GC: new segment base=%p size=%ld]\n", + sp->base, (long) allocSize); + } +#endif + + _pr_gcData.allocMemory += allocSize; + _pr_gcData.freeMemory += allocSize; + + if (!exactly) { + PRInt32 bin; + + /* Put free memory into a freelist bin */ + cp = (GCFreeChunk *) base; + cp->segment = sp; + cp->chunkSize = allocSize; + InlineBinNumber(bin, allocSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + } else { + /* + ** When exactly allocating the entire segment is given over to a + ** single object to prevent fragmentation + */ + } + + if (!_pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + _pr_gcData.highSeg = (PRWord*) sp->limit; + } else { + if ((PRWord*)sp->base < _pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + } + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + } + + /* + ** Get rid of the GC pointer in case it shows up in some uninitialized + ** local stack variable later (while scanning the C stack looking for + ** roots). + */ + memset(&base, 0, sizeof(base)); /* optimizers beware */ + + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, ("grow heap: total gc memory now %d", + _pr_gcData.allocMemory)); + + return sp; +} + +#ifdef USE_EXTEND_HEAP +static PRBool ExtendHeap(PRInt32 requestedSize) { + GCSeg* sp; + PRUint32 allocSize; + PRInt32 oldSize, newSize; + PRInt32 newHBits, newHBytes; + PRInt32 oldHBits, oldHBytes; + PRWord* hbits; + GCFreeChunk* cp; + PRInt32 bin; + + /* Can't extend nothing */ + if (nsegs == 0) return PR_FALSE; + + /* Round up requested size to the size of a page */ + allocSize = (PRUint32) requestedSize; + allocSize = (allocSize + _pr_pageSize - 1L) >> _pr_pageShift; + allocSize <<= _pr_pageShift; + + /* Malloc some memory for the new hbits array */ + sp = segs; + oldSize = sp->limit - sp->base; + newSize = oldSize + allocSize; + newHBits = (newSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; + newHBytes = ((newHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + hbits = (PRWord*) PR_MALLOC(newHBytes); + if (0 == hbits) return PR_FALSE; + + /* Attempt to extend the last segment by the desired amount */ + if (_MD_ExtendGCHeap(sp->base, oldSize, newSize)) { + oldHBits = (oldSize + PR_BYTES_PER_WORD - 1L) >> PR_BYTES_PER_WORD_LOG2; + oldHBytes = ((oldHBits + PR_BITS_PER_WORD - 1L) >> PR_BITS_PER_WORD_LOG2) + * sizeof(PRWord); + + /* Copy hbits from old memory into new memory */ + memset(hbits, 0, newHBytes); + memcpy(hbits, sp->hbits, oldHBytes); + PR_DELETE(sp->hbits); + memset(sp->base + oldSize, 0, allocSize); + + /* Adjust segment state */ + sp->limit += allocSize; + sp->hbits = hbits; + sp->info->limit = sp->limit; + sp->info->hbits = hbits; + + /* Put free memory into a freelist bin */ + cp = (GCFreeChunk *) (sp->base + oldSize); + cp->segment = sp; + cp->chunkSize = allocSize; + InlineBinNumber(bin, allocSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + + /* Prevent a pointer that points to the free memory from showing + up on the call stack later on */ + memset(&cp, 0, sizeof(cp)); + + /* Update heap brackets and counters */ + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + _pr_gcData.allocMemory += allocSize; + _pr_gcData.freeMemory += allocSize; + + return PR_TRUE; + } + PR_DELETE(hbits); + return PR_FALSE; +} +#endif /* USE_EXTEND_HEAP */ + +static GCSeg *GrowHeapExactly(PRInt32 requestedSize) +{ + GCSeg *sp = DoGrowHeap(requestedSize, PR_TRUE); + return sp; +} + +static PRBool GrowHeap(PRInt32 requestedSize) +{ + void *p; +#ifdef USE_EXTEND_HEAP + if (ExtendHeap(requestedSize)) { + return PR_TRUE; + } +#endif + p = DoGrowHeap(requestedSize, PR_FALSE); + return (p != NULL ? PR_TRUE : PR_FALSE); +} + +/* +** Release a segment when it is entirely free. +*/ +static void ShrinkGCHeap(GCSeg *sp) +{ +#ifdef GCMETER + if (_pr_gcMeter & _GC_METER_GROWTH) { + fprintf(stderr, "[GC: free segment base=%p size=%ld]\n", + sp->base, (long) (sp->limit - sp->base)); + } +#endif + + /* + * Put segment onto free seginfo list (we can't call free right now + * because we have the GC lock and all of the other threads are + * suspended; if one of them has the malloc lock we would deadlock) + */ + sp->info->next = freeSegs; + freeSegs = sp->info; + collectorCleanupNeeded = 1; + _pr_gcData.allocMemory -= sp->limit - sp->base; + if (sp == lastInHeap) lastInHeap = 0; + + /* Squish out disappearing segment from segment table */ + --nsegs; + if ((sp - segs) != nsegs) { + *sp = segs[nsegs]; + } else { + sp->base = 0; + sp->limit = 0; + sp->hbits = 0; + sp->info = 0; + } + + /* Recalculate the lowSeg and highSeg values */ + _pr_gcData.lowSeg = (PRWord*) segs[0].base; + _pr_gcData.highSeg = (PRWord*) segs[0].limit; + for (sp = segs; sp < &segs[nsegs]; sp++) { + if ((PRWord*)sp->base < _pr_gcData.lowSeg) { + _pr_gcData.lowSeg = (PRWord*) sp->base; + } + if ((PRWord*)sp->limit > _pr_gcData.highSeg) { + _pr_gcData.highSeg = (PRWord*) sp->limit; + } + } +} + +static void FreeSegments(void) +{ + GCSegInfo *si; + + while (0 != freeSegs) { + LOCK_GC(); + si = freeSegs; + if (si) { + freeSegs = si->next; + } + UNLOCK_GC(); + + if (!si) { + break; + } + PR_DELETE(si->base); + PR_DELETE(si->hbits); + PR_DELETE(si); + } +} + +/************************************************************************/ + +void ScanScanQ(GCScanQ *iscan) +{ + PRWord *p; + PRWord **pp; + PRWord **epp; + GCScanQ nextQ, *scan, *next, *temp; + CollectorType *ct; + + if (!iscan->queued) return; + + _GCTRACE(GC_MARK, ("begin scanQ @ 0x%x (%d)", iscan, iscan->queued)); + scan = iscan; + next = &nextQ; + while (scan->queued) { + _GCTRACE(GC_MARK, ("continue scanQ @ 0x%x (%d)", scan, scan->queued)); + /* + * Set pointer to current scanQ so that _pr_gcData.livePointer + * can find it. + */ + pScanQ = next; + next->queued = 0; + + /* Now scan the scan Q */ + pp = scan->q; + epp = &scan->q[scan->queued]; + scan->queued = 0; + while (pp < epp) { + p = *pp++; + ct = &_pr_collectorTypes[GET_TYPEIX(p[0])]; + PR_ASSERT(0 != ct->gctype.scan); + /* Scan object ... */ + (*ct->gctype.scan)(p + 1); + } + + /* Exchange pointers so that we scan next */ + temp = scan; + scan = next; + next = temp; + } + + pScanQ = iscan; + PR_ASSERT(nextQ.queued == 0); + PR_ASSERT(iscan->queued == 0); +} + +/* +** Called during root finding step to identify "root" pointers into the +** GC heap. First validate if it is a real heap pointer and then mark the +** object being pointed to and add it to the scan Q for eventual +** scanning. +*/ +static void PR_CALLBACK ProcessRootBlock(void **base, PRInt32 count) +{ + GCSeg *sp; + PRWord *p0, *p, h, tix, *low, *high, *segBase; + CollectorType *ct; +#ifdef DEBUG + void **base0 = base; +#endif + + low = _pr_gcData.lowSeg; + high = _pr_gcData.highSeg; + while (--count >= 0) { + p0 = (PRWord*) *base++; + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < low) continue; /* below gc heap */ + if (p0 >= high) continue; /* above gc heap */ +#endif + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + continue; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(PR_BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + + winner: + h = p[0]; + if ((h & MARK_BIT) == 0) { +#ifdef DEBUG + _GCTRACE(GC_ROOTS, + ("root 0x%p (%d) base0=%p off=%d", + p, OBJ_BYTES(h), base0, (base-1) - base0)); +#endif + + /* Mark the root we just found */ + p[0] = h | MARK_BIT; + + /* + * See if object we just found needs scanning. It must + * have a scan function to be placed on the scanQ. + */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + if (0 == ct->gctype.scan) { + continue; + } + + /* + ** Put a pointer onto the scan Q. We use the scan Q to avoid + ** deep recursion on the C call stack. Objects are added to + ** the scan Q until the scan Q fills up. At that point we + ** make a call to ScanScanQ which proceeds to scan each of + ** the objects in the Q. This limits the recursion level by a + ** large amount though the stack frames get larger to hold + ** the GCScanQ's. + */ + pScanQ->q[pScanQ->queued++] = p; + if (pScanQ->queued == MAX_SCAN_Q) { + METER(_pr_scanDepth++); + ScanScanQ(pScanQ); + } + } + } +} + +static void PR_CALLBACK ProcessRootPointer(void *ptr) +{ + PRWord *p0, *p, h, tix, *segBase; + GCSeg* sp; + CollectorType *ct; + + p0 = (PRWord*) ptr; + + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < _pr_gcData.lowSeg) return; /* below gc heap */ + if (p0 >= _pr_gcData.highSeg) return; /* above gc heap */ +#endif + + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + return; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + + winner: + h = p[0]; + if ((h & MARK_BIT) == 0) { +#ifdef DEBUG + _GCTRACE(GC_ROOTS, ("root 0x%p (%d)", p, OBJ_BYTES(h))); +#endif + + /* Mark the root we just found */ + p[0] = h | MARK_BIT; + + /* + * See if object we just found needs scanning. It must + * have a scan function to be placed on the scanQ. + */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + if (0 == ct->gctype.scan) { + return; + } + + /* + ** Put a pointer onto the scan Q. We use the scan Q to avoid + ** deep recursion on the C call stack. Objects are added to + ** the scan Q until the scan Q fills up. At that point we + ** make a call to ScanScanQ which proceeds to scan each of + ** the objects in the Q. This limits the recursion level by a + ** large amount though the stack frames get larger to hold + ** the GCScanQ's. + */ + pScanQ->q[pScanQ->queued++] = p; + if (pScanQ->queued == MAX_SCAN_Q) { + METER(_pr_scanDepth++); + ScanScanQ(pScanQ); + } + } +} + +/************************************************************************/ + +/* +** Empty the freelist for each segment. This is done to make sure that +** the root finding step works properly (otherwise, if we had a pointer +** into a free section, we might not find its header word and abort in +** FindObject) +*/ +static void EmptyFreelists(void) +{ + GCFreeChunk *cp; + GCFreeChunk *next; + GCSeg *sp; + PRWord *p; + PRInt32 chunkSize; + PRInt32 bin; + + /* + ** Run over the freelist and make all of the free chunks look like + ** object debris. + */ + for (bin = 0; bin <= NUM_BINS-1; bin++) { + cp = bins[bin]; + while (cp) { + next = cp->next; + sp = cp->segment; + chunkSize = cp->chunkSize >> BYTES_PER_WORD_LOG2; + p = (PRWord*) cp; + PR_ASSERT(chunkSize != 0); + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize); + SET_HBIT(sp, p); + cp = next; + } + bins[bin] = 0; + } + minBin = NUM_BINS - 1; + maxBin = 0; +} + +typedef struct GCBlockEnd { + PRInt32 check; +#ifdef GC_CHECK + PRInt32 requestedBytes; +#endif +#ifdef GC_STATS + PRInt32 bin; + PRInt64 allocTime; +#endif +#ifdef GC_TRACEROOTS + PRInt32 traceGeneration; +#endif +} GCBlockEnd; + +#define PR_BLOCK_END 0xDEADBEEF + +/************************************************************************/ + +#ifdef GC_STATS + +typedef struct GCStat { + PRInt32 nallocs; + double allocTime; + double allocTimeVariance; + PRInt32 nfrees; + double lifetime; + double lifetimeVariance; +} GCStat; + +#define GCSTAT_BINS NUM_BINS + +GCStat gcstats[GCSTAT_BINS]; + +#define GCLTFREQ_BINS NUM_BINS + +PRInt32 gcltfreq[GCSTAT_BINS][GCLTFREQ_BINS]; + +#include + +static char* +pr_GetSizeString(PRUint32 size) +{ + char* sizeStr; + if (size < 1024) + sizeStr = PR_smprintf("<= %ld", size); + else if (size < 1024 * 1024) + sizeStr = PR_smprintf("<= %ldk", size / 1024); + else + sizeStr = PR_smprintf("<= %ldM", size / (1024 * 1024)); + return sizeStr; +} + +static void +pr_FreeSizeString(char *sizestr) +{ + PR_smprintf_free(sizestr); +} + + +static void +pr_PrintGCAllocStats(FILE* out) +{ + PRInt32 i, j; + _PR_DebugPrint(out, "\n--Allocation-Stats-----------------------------------------------------------"); + _PR_DebugPrint(out, "\n--Obj-Size----Count-----Avg-Alloc-Time-----------Avg-Lifetime---------%%Freed-\n"); + for (i = 0; i < GCSTAT_BINS; i++) { + GCStat stat = gcstats[i]; + double allocTimeMean = 0.0, allocTimeVariance = 0.0, lifetimeMean = 0.0, lifetimeVariance = 0.0; + PRUint32 maxSize = (1 << i); + char* sizeStr; + if (stat.nallocs != 0.0) { + allocTimeMean = stat.allocTime / stat.nallocs; + allocTimeVariance = fabs(stat.allocTimeVariance / stat.nallocs - allocTimeMean * allocTimeMean); + } + if (stat.nfrees != 0.0) { + lifetimeMean = stat.lifetime / stat.nfrees; + lifetimeVariance = fabs(stat.lifetimeVariance / stat.nfrees - lifetimeMean * lifetimeMean); + } + sizeStr = pr_GetSizeString(maxSize); + _PR_DebugPrint(out, "%10s %8lu %10.3f +- %10.3f %10.3f +- %10.3f (%2ld%%)\n", + sizeStr, stat.nallocs, + allocTimeMean, sqrt(allocTimeVariance), + lifetimeMean, sqrt(lifetimeVariance), + (stat.nallocs ? (stat.nfrees * 100 / stat.nallocs) : 0)); + pr_FreeSizeString(sizeStr); + } + _PR_DebugPrint(out, "--Lifetime-Frequency-Counts----------------------------------------------------\n"); + _PR_DebugPrint(out, "size\\cnt"); + for (j = 0; j < GCLTFREQ_BINS; j++) { + _PR_DebugPrint(out, "\t%lu", j); + } + _PR_DebugPrint(out, "\n"); + for (i = 0; i < GCSTAT_BINS; i++) { + PRInt32* freqs = gcltfreq[i]; + _PR_DebugPrint(out, "%lu", (1 << i)); + for (j = 0; j < GCLTFREQ_BINS; j++) { + _PR_DebugPrint(out, "\t%lu", freqs[j]); + } + _PR_DebugPrint(out, "\n"); + } + _PR_DebugPrint(out, "-------------------------------------------------------------------------------\n"); +} + +PR_PUBLIC_API(void) +PR_PrintGCAllocStats(void) +{ + pr_PrintGCAllocStats(stderr); +} + +#endif /* GC_STATS */ + +/************************************************************************/ + +/* +** Sweep a segment, cleaning up all of the debris. Coallese the debris +** into GCFreeChunk's which are added to the freelist bins. +*/ +static PRBool SweepSegment(GCSeg *sp) +{ + PRWord h, tix; + PRWord *p; + PRWord *np; + PRWord *limit; + GCFreeChunk *cp; + PRInt32 bytes, chunkSize, segmentSize, totalFree; + CollectorType *ct; + PRInt32 bin; + + /* + ** Now scan over the segment's memory in memory order, coallescing + ** all of the debris into a FreeChunk list. + */ + totalFree = 0; + segmentSize = sp->limit - sp->base; + p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + PR_ASSERT(segmentSize > 0); + while (p < limit) { + chunkSize = 0; + cp = (GCFreeChunk *) p; + + /* Attempt to coallesce any neighboring free objects */ + for (;;) { + PR_ASSERT(IS_HBIT(sp, p) != 0); + h = p[0]; + bytes = OBJ_BYTES(h); + PR_ASSERT(bytes != 0); + np = (PRWord *) ((char *)p + bytes); + tix = (PRWord)GET_TYPEIX(h); + if ((h & MARK_BIT) && (tix != FREE_MEMORY_TYPEIX)) { +#ifdef DEBUG + if (tix != FREE_MEMORY_TYPEIX) { + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + } +#endif + p[0] = h & ~(MARK_BIT|FINAL_BIT); + _GCTRACE(GC_SWEEP, ("busy 0x%x (%d)", p, bytes)); + break; + } + _GCTRACE(GC_SWEEP, ("free 0x%x (%d)", p, bytes)); + + /* Found a free object */ +#ifdef GC_STATS + { + PRInt32 userSize = bytes - sizeof(GCBlockEnd); + GCBlockEnd* end = (GCBlockEnd*)((char*)p + userSize); + if (userSize >= 0 && end->check == PR_BLOCK_END) { + PRInt64 now = PR_Now(); + double nowd, delta; + PRInt32 freq; + LL_L2D(nowd, now); + delta = nowd - end->allocTime; + gcstats[end->bin].nfrees++; + gcstats[end->bin].lifetime += delta; + gcstats[end->bin].lifetimeVariance += delta * delta; + + InlineBinNumber(freq, delta); + gcltfreq[end->bin][freq]++; + + end->check = 0; + } + } +#endif + CLEAR_HBIT(sp, p); + ct = &_pr_collectorTypes[tix]; + if (0 != ct->gctype.free) { + (*ct->gctype.free)(p + 1); + } + chunkSize = chunkSize + bytes; + if (np == limit) { + /* Found the end of heap */ + break; + } + PR_ASSERT(np < limit); + p = np; + } + + if (chunkSize) { + _GCTRACE(GC_SWEEP, ("free chunk 0x%p to 0x%p (%d)", + cp, (char*)cp + chunkSize - 1, chunkSize)); + if (chunkSize < MIN_FREE_CHUNK_BYTES) { + /* Lost a tiny fragment until (maybe) next time */ + METER(meter.wastedBytes += chunkSize); + p = (PRWord *) cp; + chunkSize >>= BYTES_PER_WORD_LOG2; + PR_ASSERT(chunkSize != 0); + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, chunkSize); + SET_HBIT(sp, p); + } else { + /* See if the chunk constitutes the entire segment */ + if (chunkSize == segmentSize) { + /* Free up the segment right now */ + if (sp->info->fromMalloc) { + ShrinkGCHeap(sp); + return PR_TRUE; + } + } + + /* Put free chunk into the appropriate bin */ + cp->segment = sp; + cp->chunkSize = chunkSize; + InlineBinNumber(bin, chunkSize) + cp->next = bins[bin]; + bins[bin] = cp; + if (bin < minBin) minBin = bin; + if (bin > maxBin) maxBin = bin; + + /* Zero swept memory now */ + memset(cp+1, 0, chunkSize - sizeof(*cp)); + METER(meter.numFreeChunks++); + totalFree += chunkSize; + } + } + + /* Advance to next object */ + p = np; + } + + PR_ASSERT(totalFree <= segmentSize); + + _pr_gcData.freeMemory += totalFree; + _pr_gcData.busyMemory += (sp->limit - sp->base) - totalFree; + return PR_FALSE; +} + +/************************************************************************/ + +/* This is a list of all the objects that are finalizable. This is not + the list of objects that are awaiting finalization because they + have been collected. */ +PRCList _pr_finalizeableObjects; + +/* This is the list of objects that are awaiting finalization because + they have been collected. */ +PRCList _pr_finalQueue; + +/* Each object that requires finalization has one of these objects + allocated as well. The GCFinal objects are put on the + _pr_finalizeableObjects list until the object is collected at which + point the GCFinal object is moved to the _pr_finalQueue */ +typedef struct GCFinalStr { + PRCList links; + PRWord *object; +} GCFinal; + +/* Find pointer to GCFinal struct from the list linkaged embedded in it */ +#define FinalPtr(_qp) \ + ((GCFinal*) ((char*) (_qp) - offsetof(GCFinal,links))) + +static GCFinal *AllocFinalNode(void) +{ + return PR_NEWZAP(GCFinal); +} + +static void FreeFinalNode(GCFinal *node) +{ + PR_DELETE(node); +} + +/* +** Prepare for finalization. At this point in the GC cycle we have +** identified all of the live objects. For each object on the +** _pr_finalizeableObjects list see if the object is alive or dead. If +** it's dead, resurrect it and move it from the _pr_finalizeableObjects +** list to the _pr_finalQueue (object's only get finalized once). +** +** Once _pr_finalizeableObjects has been processed we can finish the +** GC and free up memory and release the threading lock. After that we +** can invoke the finalization procs for each object that is on the +** _pr_finalQueue. +*/ +static void PrepareFinalize(void) +{ + PRCList *qp; + GCFinal *fp; + PRWord h; + PRWord *p; + void (PR_CALLBACK *livePointer)(void *ptr); +#ifdef DEBUG + CollectorType *ct; +#endif + + /* This must be done under the same lock that the finalizer uses */ + PR_ASSERT( GC_IS_LOCKED() ); + + /* cache this ptr */ + livePointer = _pr_gcData.livePointer; + + /* + * Pass #1: Identify objects that are to be finalized, set their + * FINAL_BIT. + */ + qp = _pr_finalizeableObjects.next; + while (qp != &_pr_finalizeableObjects) { + fp = FinalPtr(qp); + qp = qp->next; + h = fp->object[0]; /* Grab header word */ + if (h & MARK_BIT) { + /* Object is already alive */ + continue; + } + +#ifdef DEBUG + ct = &_pr_collectorTypes[GET_TYPEIX(h)]; + PR_ASSERT((0 != ct->flags) && (0 != ct->gctype.finalize)); +#endif + fp->object[0] |= FINAL_BIT; + _GCTRACE(GC_FINAL, ("moving %p (%d) to finalQueue", + fp->object, OBJ_BYTES(h))); + } + + /* + * Pass #2: For each object that is going to be finalized, move it to + * the finalization queue and resurrect it + */ + qp = _pr_finalizeableObjects.next; + while (qp != &_pr_finalizeableObjects) { + fp = FinalPtr(qp); + qp = qp->next; + h = fp->object[0]; /* Grab header word */ + if ((h & FINAL_BIT) == 0) { + continue; + } + + /* Resurrect the object and any objects it refers to */ + p = &fp->object[1]; + (*livePointer)(p); + PR_REMOVE_LINK(&fp->links); + PR_APPEND_LINK(&fp->links, &_pr_finalQueue); + } +} + +/* +** Scan the finalQ, marking each and every object on it live. This is +** necessary because we might do a GC before objects that are on the +** final queue get finalized. Since there are no other references +** (otherwise they would be on the final queue), we have to scan them. +** This really only does work if we call the GC before the finalizer +** has a chance to do its job. +*/ +extern void PR_CALLBACK _PR_ScanFinalQueue(void *notused) +{ +#ifdef XP_MAC +#pragma unused (notused) +#endif + PRCList *qp; + GCFinal *fp; + PRWord *p; + void ( PR_CALLBACK *livePointer)(void *ptr); + + livePointer = _pr_gcData.livePointer; + qp = _pr_finalQueue.next; + while (qp != &_pr_finalQueue) { + fp = FinalPtr(qp); + _GCTRACE(GC_FINAL, ("marking 0x%x (on final queue)", fp->object)); + p = &fp->object[1]; + (*livePointer)(p); + qp = qp->next; + } +} + +void PR_CALLBACK FinalizerLoop(void* unused) +{ +#ifdef XP_MAC +#pragma unused (unused) +#endif + GCFinal *fp; + PRWord *p; + PRWord h, tix; + CollectorType *ct; + + LOCK_GC(); + for (;;) { + p = 0; h = 0; /* don't let the gc find these pointers */ + while (PR_CLIST_IS_EMPTY(&_pr_finalQueue)) + PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT); + + _GCTRACE(GC_FINAL, ("begin finalization")); + while (_pr_finalQueue.next != &_pr_finalQueue) { + fp = FinalPtr(_pr_finalQueue.next); + PR_REMOVE_LINK(&fp->links); + p = fp->object; + + h = p[0]; /* Grab header word */ + tix = (PRWord)GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + _GCTRACE(GC_FINAL, ("finalize 0x%x (%d)", p, OBJ_BYTES(h))); + + /* + ** Give up the GC lock so that other threads can allocate memory + ** while this finalization method is running. Get it back + ** afterwards so that the list remains thread safe. + */ + UNLOCK_GC(); + FreeFinalNode(fp); + PR_ASSERT(ct->gctype.finalize != 0); + (*ct->gctype.finalize)(p + 1); + LOCK_GC(); + } + _GCTRACE(GC_FINAL, ("end finalization")); + PR_Notify(_pr_gcData.lock); + } +} + +static void NotifyFinalizer(void) +{ + if (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { + PR_ASSERT( GC_IS_LOCKED() ); + PR_Notify(_pr_gcData.lock); + } +} + +void _PR_CreateFinalizer(PRThreadScope scope) +{ + if (!_pr_gcData.finalizer) { + _pr_gcData.finalizer = PR_CreateThreadGCAble(PR_SYSTEM_THREAD, + FinalizerLoop, 0, + PR_PRIORITY_LOW, scope, + PR_UNJOINABLE_THREAD, 0); + + if (_pr_gcData.finalizer == NULL) + /* We are doomed if we can't start the finalizer */ + PR_Abort(); + + } +} + +void pr_FinalizeOnExit(void) +{ +#ifdef DEBUG_warren + OutputDebugString("### Doing finalize-on-exit pass\n"); +#endif + PR_ForceFinalize(); +#ifdef DEBUG_warren + OutputDebugString("### Finalize-on-exit complete. Dumping object left to memory.out\n"); + PR_DumpMemorySummary(); + PR_DumpMemory(PR_TRUE); +#endif +} + +PR_IMPLEMENT(void) PR_ForceFinalize() +{ + LOCK_GC(); + NotifyFinalizer(); + while (!PR_CLIST_IS_EMPTY(&_pr_finalQueue)) { + PR_ASSERT( GC_IS_LOCKED() ); + (void) PR_Wait(_pr_gcData.lock, PR_INTERVAL_NO_TIMEOUT); + } + UNLOCK_GC(); + + /* XXX I don't know how to make it wait (yet) */ +} + +/************************************************************************/ + +typedef struct GCWeakStr { + PRCList links; + PRWord *object; +} GCWeak; + +/* +** Find pointer to GCWeak struct from the list linkaged embedded in it +*/ +#define WeakPtr(_qp) \ + ((GCWeak*) ((char*) (_qp) - offsetof(GCWeak,links))) + +PRCList _pr_weakLinks = PR_INIT_STATIC_CLIST(&_pr_weakLinks); +PRCList _pr_freeWeakLinks = PR_INIT_STATIC_CLIST(&_pr_freeWeakLinks); + +#define WEAK_FREELIST_ISEMPTY() (_pr_freeWeakLinks.next == &_pr_freeWeakLinks) + +/* + * Keep objects referred to by weak free list alive until they can be + * freed + */ +static void PR_CALLBACK ScanWeakFreeList(void *notused) { +#ifdef XP_MAC +#pragma unused (notused) +#endif + PRCList *qp = _pr_freeWeakLinks.next; + while (qp != &_pr_freeWeakLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + ProcessRootPointer(wp->object); + } +} + +/* + * Empty the list of weak objects. Note that we can't call malloc/free + * under the cover of the GC's lock (we might deadlock), so transfer the + * list of free objects to a local list under the cover of the lock, then + * release the lock and free up the memory. + */ +static void EmptyWeakFreeList(void) { + if (!WEAK_FREELIST_ISEMPTY()) { + PRCList *qp, freeLinks; + + PR_INIT_CLIST(&freeLinks); + + /* + * Transfer list of free weak links from the global list to a + * local list. + */ + LOCK_GC(); + qp = _pr_freeWeakLinks.next; + while (qp != &_pr_freeWeakLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + PR_REMOVE_LINK(&wp->links); + PR_APPEND_LINK(&wp->links, &freeLinks); + } + UNLOCK_GC(); + + /* Free up storage now */ + qp = freeLinks.next; + while (qp != &freeLinks) { + GCWeak *wp = WeakPtr(qp); + qp = qp->next; + PR_DELETE(wp); + } + } +} + +/* + * Allocate a new weak node in the weak objects list + */ +static GCWeak *AllocWeakNode(void) +{ + EmptyWeakFreeList(); + return PR_NEWZAP(GCWeak); +} + +static void FreeWeakNode(GCWeak *node) +{ + PR_DELETE(node); +} + +/* + * Check the weak links for validity. Note that the list of weak links is + * itself weak (otherwise we would keep the objects with weak links in + * them alive forever). As we scan the list check the weak link object + * itself and if it's not marked then remove it from the weak link list + */ +static void CheckWeakLinks(void) { + PRCList *qp; + GCWeak *wp; + PRWord *p, h, tix, **weakPtrAddress; + CollectorType *ct; + PRUint32 offset; + + qp = _pr_weakLinks.next; + while (qp != &_pr_weakLinks) { + wp = WeakPtr(qp); + qp = qp->next; + if ((p = wp->object) != 0) { + h = p[0]; /* Grab header word */ + if ((h & MARK_BIT) == 0) { + /* + * The object that has a weak link is no longer being + * referenced; remove it from the chain and let it get + * swept away by the GC. Transfer it to the list of + * free weak links for later freeing. + */ + PR_REMOVE_LINK(&wp->links); + PR_APPEND_LINK(&wp->links, &_pr_freeWeakLinks); + collectorCleanupNeeded = 1; + continue; + } + + /* Examine a live object that contains weak links */ + tix = GET_TYPEIX(h); + ct = &_pr_collectorTypes[tix]; + PR_ASSERT((ct->flags != 0) && (ct->gctype.getWeakLinkOffset != 0)); + if (0 == ct->gctype.getWeakLinkOffset) { + /* Heap is probably corrupted */ + continue; + } + + /* Get offset into the object of where the weak pointer is */ + offset = (*ct->gctype.getWeakLinkOffset)(p + 1); + + /* Check the weak pointer */ + weakPtrAddress = (PRWord**)((char*)(p + 1) + offset); + p = *weakPtrAddress; + if (p != 0) { + h = p[-1]; /* Grab header word for pointed to object */ + if (h & MARK_BIT) { + /* Object can't be dead */ + continue; + } + /* Break weak link to an object that is about to be swept */ + *weakPtrAddress = 0; + } + } + } +} + +/************************************************************************/ + +/* +** Perform a complete garbage collection +*/ + +extern GCLockHook *_pr_GCLockHook; + +static void dogc(void) +{ + RootFinder *rf; + GCLockHook* lhook; + + GCScanQ scanQ; + GCSeg *sp, *esp; + PRInt64 start, end, diff; + +#if defined(GCMETER) || defined(GCTIMINGHOOK) + start = PR_Now(); +#endif + + /* + ** Stop all of the other threads. This also promises to capture the + ** register state of each and every thread + */ + + /* + ** Get all the locks that will be need during GC after SuspendAll. We + ** cannot make any locking/library calls after SuspendAll. + */ + if (_pr_GCLockHook) { + for (lhook = _pr_GCLockHook->next; lhook != _pr_GCLockHook; + lhook = lhook->next) { + (*lhook->func)(PR_GCBEGIN, lhook->arg); + } + } + + PR_SuspendAll(); + +#ifdef GCMETER + /* Reset meter info */ + if (_pr_gcMeter & _GC_METER_STATS) { + fprintf(stderr, + "[GCSTATS: busy:%ld skipped:%ld, alloced:%ld+wasted:%ld+free:%ld = total:%ld]\n", + (long) _pr_gcData.busyMemory, + (long) meter.skippedFreeChunks, + (long) meter.allocBytes, + (long) meter.wastedBytes, + (long) _pr_gcData.freeMemory, + (long) _pr_gcData.allocMemory); + } + memset(&meter, 0, sizeof(meter)); +#endif + + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("begin mark phase; busy=%d free=%d total=%d", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + _pr_gcData.allocMemory)); + + if (_pr_beginGCHook) { + (*_pr_beginGCHook)(_pr_beginGCHookArg); + } + + /* + ** Initialize scanQ to all zero's so that root finder doesn't walk + ** over it... + */ + memset(&scanQ, 0, sizeof(scanQ)); + pScanQ = &scanQ; + + /******************************************/ + /* MARK PHASE */ + + EmptyFreelists(); + + /* Find root's */ + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, + ("begin mark phase; busy=%d free=%d total=%d", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + _pr_gcData.allocMemory)); + METER(_pr_scanDepth = 0); + rf = _pr_rootFinders; + while (rf) { + _GCTRACE(GC_ROOTS, ("finding roots in %s", rf->name)); + (*rf->func)(rf->arg); + rf = rf->next; + } + _GCTRACE(GC_ROOTS, ("done finding roots")); + + /* Scan remaining object's that need scanning */ + ScanScanQ(&scanQ); + PR_ASSERT(pScanQ == &scanQ); + PR_ASSERT(scanQ.queued == 0); + METER({ + if (_pr_scanDepth > _pr_maxScanDepth) { + _pr_maxScanDepth = _pr_scanDepth; + } + }); + + /******************************************/ + /* FINALIZATION PHASE */ + + METER(_pr_scanDepth = 0); + PrepareFinalize(); + + /* Scan any resurrected objects found during finalization */ + ScanScanQ(&scanQ); + PR_ASSERT(pScanQ == &scanQ); + PR_ASSERT(scanQ.queued == 0); + METER({ + if (_pr_scanDepth > _pr_maxScanDepth) { + _pr_maxScanDepth = _pr_scanDepth; + } + }); + pScanQ = 0; + + /******************************************/ + /* SWEEP PHASE */ + + /* + ** Sweep each segment clean. While we are at it, figure out which + ** segment has the most free space and make that the current segment. + */ + CheckWeakLinks(); + _GCTRACE(GC_SWEEP, ("begin sweep phase")); + _pr_gcData.freeMemory = 0; + _pr_gcData.busyMemory = 0; + sp = segs; + esp = sp + nsegs; + while (sp < esp) { + if (SweepSegment(sp)) { + /* + ** Segment is now free and has been replaced with a different + ** segment object. + */ + esp--; + continue; + } + sp++; + } + +#if defined(GCMETER) || defined(GCTIMINGHOOK) + end = PR_Now(); +#endif +#ifdef GCMETER + LL_SUB(diff, end, start); + PR_LOG(GC, PR_LOG_ALWAYS, + ("done; busy=%d free=%d chunks=%d total=%d time=%lldms", + _pr_gcData.busyMemory, _pr_gcData.freeMemory, + meter.numFreeChunks, _pr_gcData.allocMemory, diff)); + if (_pr_gcMeter & _GC_METER_FREE_LIST) { + PRIntn bin; + fprintf(stderr, "Freelist bins:\n"); + for (bin = 0; bin < NUM_BINS; bin++) { + GCFreeChunk *cp = bins[bin]; + while (cp != NULL) { + fprintf(stderr, "%3d: %p %8ld\n", + bin, cp, (long) cp->chunkSize); + cp = cp->next; + } + } + } +#endif + + if (_pr_endGCHook) { + (*_pr_endGCHook)(_pr_endGCHookArg); + } + + /* clear the running total of the bytes allocated via BigAlloc() */ + bigAllocBytes = 0; + + /* And resume multi-threading */ + PR_ResumeAll(); + + if (_pr_GCLockHook) { + for (lhook = _pr_GCLockHook->prev; lhook != _pr_GCLockHook; + lhook = lhook->prev) { + (*lhook->func)(PR_GCEND, lhook->arg); + } + } + + /* Kick finalizer */ + NotifyFinalizer(); +#ifdef GCTIMINGHOOK + if (_pr_gcData.gcTimingHook) { + PRInt32 time; + LL_SUB(diff, end, start); + LL_L2I(time, diff); + _pr_gcData.gcTimingHook(time); + } +#endif +} + +PR_IMPLEMENT(void) PR_GC(void) +{ + LOCK_GC(); + dogc(); + UNLOCK_GC(); + + EmptyWeakFreeList(); +} + +/******************************************************************************* + * Heap Walker + ******************************************************************************/ + +/* +** This is yet another disgusting copy of the body of ProcessRootPointer +** (the other being ProcessRootBlock), but we're not leveraging a single +** function in their cases in interest of performance (avoiding the function +** call). +*/ +static PRInt32 PR_CALLBACK +pr_ConservativeWalkPointer(void* ptr, PRWalkFun walkRootPointer, void* data) +{ + PRWord *p0, *p, *segBase; + GCSeg* sp; + + p0 = (PRWord*) ptr; + + /* + ** XXX: + ** Until Win16 maintains lowSeg and highSeg correctly, + ** (ie. lowSeg=MIN(all segs) and highSeg = MAX(all segs)) + ** Allways scan through the segment list + */ +#if !defined(WIN16) + if (p0 < _pr_gcData.lowSeg) return 0; /* below gc heap */ + if (p0 >= _pr_gcData.highSeg) return 0; /* above gc heap */ +#endif + + /* NOTE: inline expansion of InHeap */ + /* Find segment */ + sp = lastInHeap; + if (!sp || !IN_SEGMENT(sp,p0)) { + GCSeg *esp; + sp = segs; + esp = segs + nsegs; + for (; sp < esp; sp++) { + if (IN_SEGMENT(sp, p0)) { + lastInHeap = sp; + goto find_object; + } + } + return 0; + } + + find_object: + /* NOTE: Inline expansion of FindObject */ + /* Align p to it's proper boundary before we start fiddling with it */ + p = (PRWord*) ((PRWord)p0 & ~(BYTES_PER_WORD-1L)); + segBase = (PRWord *) sp->base; + do { + if (IS_HBIT(sp, p)) { + goto winner; + } + p--; + } while (p >= segBase); + + /* + ** We have a pointer into the heap, but it has no header + ** bit. This means that somehow the very first object in the heap + ** doesn't have a header. This is impossible so when debugging + ** lets abort. + */ +#ifdef DEBUG + PR_Abort(); +#endif + return 0; + + winner: + return walkRootPointer(p, data); +} + +static PRInt32 PR_CALLBACK +pr_ConservativeWalkBlock(void **base, PRInt32 count, + PRWalkFun walkRootPointer, void* data) +{ + PRWord *p0; + while (--count >= 0) { + PRInt32 status; + p0 = (PRWord*) *base++; + status = pr_ConservativeWalkPointer(p0, walkRootPointer, data); + if (status) return status; + } + return 0; +} + +/******************************************************************************/ + +typedef void (*WalkObject_t)(FILE *out, GCType* tp, PRWord *obj, + size_t bytes, PRBool detailed); +typedef void (*WalkUnknown_t)(FILE *out, GCType* tp, PRWord tix, PRWord *p, + size_t bytes, PRBool detailed); +typedef void (*WalkFree_t)(FILE *out, PRWord *p, size_t size, PRBool detailed); +typedef void (*WalkSegment_t)(FILE *out, GCSeg* sp, PRBool detailed); + +static void +pr_WalkSegment(FILE* out, GCSeg* sp, PRBool detailed, + char* enterMsg, char* exitMsg, + WalkObject_t walkObject, WalkUnknown_t walkUnknown, WalkFree_t walkFree) +{ + PRWord *p, *limit; + + p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + if (enterMsg) + fprintf(out, enterMsg, p); + while (p < limit) + { + if (IS_HBIT(sp, p)) /* Is this an object header? */ + { + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + size_t bytes = OBJ_BYTES(h); + PRWord* np = (PRWord*) ((char*)p + bytes); + + GCType* tp = &_pr_collectorTypes[tix].gctype; + if ((0 != tp) && walkObject) + walkObject(out, tp, p, bytes, detailed); + else if (walkUnknown) + walkUnknown(out, tp, tix, p, bytes, detailed); + p = np; + } + else + { + /* Must be a freelist item */ + size_t size = ((GCFreeChunk*)p)->chunkSize; + if (walkFree) + walkFree(out, p, size, detailed); + p = (PRWord*)((char*)p + size); + } + } + if (p != limit) + fprintf(out, "SEGMENT OVERRUN (end should be at 0x%p)\n", limit); + if (exitMsg) + fprintf(out, exitMsg, p); +} + +static void +pr_WalkSegments(FILE *out, WalkSegment_t walkSegment, PRBool detailed) +{ + GCSeg *sp = segs; + GCSeg *esp; + + LOCK_GC(); + esp = sp + nsegs; + while (sp < esp) + { + walkSegment(out, sp, detailed); + sp++; + } + fprintf(out, "End of heap\n"); + UNLOCK_GC(); +} + +/******************************************************************************* + * Heap Dumper + ******************************************************************************/ + +PR_IMPLEMENT(void) +PR_DumpIndent(FILE *out, int indent) +{ + while (--indent >= 0) + fprintf(out, " "); +} + +static void +PR_DumpHexWords(FILE *out, PRWord *p, int nWords, + int indent, int nWordsPerLine) +{ + while (nWords > 0) + { + int i; + + PR_DumpIndent(out, indent); + i = nWordsPerLine; + if (i > nWords) + i = nWords; + nWords -= i; + while (i--) + { + fprintf(out, "0x%.8lX", (long) *p++); + if (i) + fputc(' ', out); + } + fputc('\n', out); + } +} + +static void PR_CALLBACK +pr_DumpObject(FILE *out, GCType* tp, PRWord *p, + size_t bytes, PRBool detailed) +{ + char kindChar = tp->kindChar; + fprintf(out, "0x%p: 0x%.6lX %c ", + p, (long) bytes, kindChar ? kindChar : '?'); + if (tp->dump) + (*tp->dump)(out, (void*) (p + 1), detailed, 0); + if (detailed) + PR_DumpHexWords(out, p, bytes>>2, 22, 4); +} + +static void PR_CALLBACK +pr_DumpUnknown(FILE *out, GCType* tp, PRWord tix, PRWord *p, + size_t bytes, PRBool detailed) +{ + char kindChar = tp->kindChar; + fprintf(out, "0x%p: 0x%.6lX %c ", + p, (long) bytes, kindChar ? kindChar : '?'); + fprintf(out, "UNKNOWN KIND %ld\n", (long) tix); + if (detailed) + PR_DumpHexWords(out, p, bytes>>2, 22, 4); +} + +static void PR_CALLBACK +pr_DumpFree(FILE *out, PRWord *p, size_t size, PRBool detailed) +{ +#if defined(XP_MAC) && XP_MAC +# pragma unused( detailed ) +#endif + + fprintf(out, "0x%p: 0x%.6lX - FREE\n", p, (long) size); +} + +static void PR_CALLBACK +pr_DumpSegment(FILE* out, GCSeg* sp, PRBool detailed) +{ + pr_WalkSegment(out, sp, detailed, + "\n Address: Length\n0x%p: Beginning of segment\n", + "0x%p: End of segment\n\n", + pr_DumpObject, pr_DumpUnknown, pr_DumpFree); +} + +static void pr_DumpRoots(FILE *out); + +/* +** Dump out the GC heap. +*/ +PR_IMPLEMENT(void) +PR_DumpGCHeap(FILE *out, PRBool detailed) +{ + fprintf(out, "\n" + "The kinds are:\n" + " U unscanned block\n" + " W weak link block\n" + " S scanned block\n" + " F scanned and final block\n" + " C class record\n" + " X context record\n" + " - free list item\n" + " ? other\n"); + LOCK_GC(); + pr_WalkSegments(out, pr_DumpSegment, detailed); + if (detailed) + pr_DumpRoots(out); + UNLOCK_GC(); +} + +PR_IMPLEMENT(void) +PR_DumpMemory(PRBool detailed) +{ + PR_DumpToFile("memory.out", "Dumping memory", PR_DumpGCHeap, detailed); +} + +/******************************************************************************/ + +static PRInt32 PR_CALLBACK +pr_DumpRootPointer(PRWord* p, void* data) +{ +#ifdef XP_MAC +#pragma unused(data) +#endif + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + size_t bytes = OBJ_BYTES(h); + + GCType* tp = &_pr_collectorTypes[tix].gctype; + if (0 != tp) + pr_DumpObject(_pr_gcData.dumpOutput, tp, p, bytes, PR_FALSE); + else + pr_DumpUnknown(_pr_gcData.dumpOutput, tp, tix, p, bytes, PR_FALSE); + return 0; +} + +static void PR_CALLBACK +pr_ConservativeDumpRootPointer(void* ptr) +{ + (void)pr_ConservativeWalkPointer(ptr, (PRWalkFun) pr_DumpRootPointer, NULL); +} + +static void PR_CALLBACK +pr_ConservativeDumpRootBlock(void **base, PRInt32 count) +{ + (void)pr_ConservativeWalkBlock(base, count, (PRWalkFun) pr_DumpRootPointer, NULL); +} + +extern int +DumpThreadRoots(PRThread *t, int i, void *notused); + +static void +pr_DumpRoots(FILE *out) +{ + RootFinder *rf; + void (*liveBlock)(void **base, PRInt32 count); + void (*livePointer)(void *ptr); + void (*processRootBlock)(void **base, PRInt32 count); + void (*processRootPointer)(void *ptr); + + LOCK_GC(); + + liveBlock = _pr_gcData.liveBlock; + livePointer = _pr_gcData.livePointer; + processRootBlock = _pr_gcData.processRootBlock; + processRootPointer = _pr_gcData.processRootPointer; + + _pr_gcData.liveBlock = pr_ConservativeDumpRootBlock; + _pr_gcData.livePointer = pr_ConservativeDumpRootPointer; + _pr_gcData.processRootBlock = pr_ConservativeDumpRootBlock; + _pr_gcData.processRootPointer = pr_ConservativeDumpRootPointer; + _pr_gcData.dumpOutput = out; + + rf = _pr_rootFinders; + while (rf) { + fprintf(out, "\n===== Roots for %s\n", rf->name); + (*rf->func)(rf->arg); + rf = rf->next; + } + + _pr_gcData.liveBlock = liveBlock; + _pr_gcData.livePointer = livePointer; + _pr_gcData.processRootBlock = processRootBlock; + _pr_gcData.processRootPointer = processRootPointer; + _pr_gcData.dumpOutput = NULL; + + UNLOCK_GC(); +} + +/******************************************************************************* + * Heap Summary Dumper + ******************************************************************************/ + +PRSummaryPrinter summaryPrinter = NULL; +void* summaryPrinterClosure = NULL; + +PR_IMPLEMENT(void) +PR_RegisterSummaryPrinter(PRSummaryPrinter fun, void* closure) +{ + summaryPrinter = fun; + summaryPrinterClosure = closure; +} + +static void PR_CALLBACK +pr_SummarizeObject(FILE *out, GCType* tp, PRWord *p, + size_t bytes, PRBool detailed) +{ +#if defined(XP_MAC) && XP_MAC +# pragma unused( out, detailed ) +#endif + + if (tp->summarize) + (*tp->summarize)((void GCPTR*)(p + 1), bytes); +} + +static void PR_CALLBACK +pr_DumpSummary(FILE* out, GCSeg* sp, PRBool detailed) +{ + pr_WalkSegment(out, sp, detailed, NULL, NULL, + pr_SummarizeObject, NULL, NULL); +} + +PR_IMPLEMENT(void) +PR_DumpGCSummary(FILE *out, PRBool detailed) +{ + if (summaryPrinter) { + pr_WalkSegments(out, pr_DumpSummary, detailed); + summaryPrinter(out, summaryPrinterClosure); + } +#if 0 + fprintf(out, "\nFinalizable objects:\n"); + { + PRCList *qp; + qp = _pr_pendingFinalQueue.next; + while (qp != &_pr_pendingFinalQueue) { + GCFinal* fp = FinalPtr(qp); + PRWord h = fp->object[0]; /* Grab header word */ + PRWord tix = GET_TYPEIX(h); + GCType* tp = _pr_gcTypes[tix]; + size_t bytes = OBJ_BYTES(h); + pr_DumpObject(out, tp, fp->object, bytes, PR_FALSE); + qp = qp->next; + } + } +#endif +} + +PR_IMPLEMENT(void) +PR_DumpMemorySummary(void) +{ + PR_DumpToFile("memory.out", "Memory Summary", PR_DumpGCSummary, PR_FALSE); +} + +/******************************************************************************* + * End Of Heap Walker + ******************************************************************************/ + +#ifdef GC_TRACEROOTS + +PRInt32 pr_traceGen = 0; + +static PRBool +pr_IsMarked(PRWord* p) +{ + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + PR_ASSERT(end->check == PR_BLOCK_END); + return end->traceGeneration == pr_traceGen; +} + +static void +pr_Mark(PRWord* p) +{ + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + PR_ASSERT(end->check == PR_BLOCK_END); + end->traceGeneration = pr_traceGen; +} + +PRWord* pr_traceObj; /* set this in the debugger, then execute PR_TraceRoot() */ + +static PRInt32 PR_CALLBACK +pr_TraceRootObject(void* obj, void* data); + +static PRInt32 PR_CALLBACK +pr_TraceRootPointer(PRWord *p, void* data) +{ + PRInt32 printTrace = 0; + PRWord h = p[0]; + PRWord tix = GET_TYPEIX(h); + GCType* tp = &_pr_collectorTypes[tix].gctype; + FILE* out = _pr_gcData.dumpOutput; + + PR_ASSERT(tp); + if (pr_IsMarked(p)) + return printTrace; + + pr_Mark(p); + if (p == pr_traceObj) { + fprintf(out, "\n### Found path to:\n"); + printTrace = 1; + } + else { + if (PR_StackSpaceLeft(PR_CurrentThread()) < 512) { + fprintf(out, "\n### Path too deep (giving up):\n"); + printTrace = 1; + } + else if (tp->walk) { + printTrace = tp->walk((void*)(p + 1), pr_TraceRootObject, data); + } + /* else there's no way to walk this object, so we + haven't found what we're looking for */ + } + + if (printTrace == 1) { + PR_ASSERT(tp->dump); + fprintf(out, "0x%p: ", p); + tp->dump(out, (void*)(p + 1), PR_FALSE, 1); + } + return printTrace; +} + +static PRInt32 PR_CALLBACK +pr_TraceRootObject(void* obj, void* data) +{ + /* This version of pr_TraceRootPointer takes object + pointers, instead of gc header pointers. */ + return pr_TraceRootPointer((PRWord*)obj - 1, data); +} + +static void PR_CALLBACK +pr_ConservativeTraceRootPointer(PRWord *p) +{ + PRInt32 status; + ++pr_traceGen; + status = pr_ConservativeWalkPointer(p, pr_TraceRootPointer, NULL); + if (status) { + FILE* out = _pr_gcData.dumpOutput; + fprintf(out, "### from root at 0x%p\n\n", p); + } +} + +static void PR_CALLBACK +pr_ConservativeTraceRootBlock(void **base, PRInt32 count) +{ + PRInt32 status; + ++pr_traceGen; + status = pr_ConservativeWalkBlock(base, count, pr_TraceRootPointer, NULL); + if (status) { + FILE* out = _pr_gcData.dumpOutput; + fprintf(out, "### from root in range 0x%p + 0x%lx\n\n", + base, (long) count); + } +} + +static void +PR_TraceRoot1(FILE* out, PRBool detailed) +{ + RootFinder *rf; + void (*liveBlock)(void **base, PRInt32 count); + void (*livePointer)(void *ptr); + void (*processRootBlock)(void **base, PRInt32 count); + void (*processRootPointer)(void *ptr); + + LOCK_GC(); + + liveBlock = _pr_gcData.liveBlock; + livePointer = _pr_gcData.livePointer; + processRootBlock = _pr_gcData.processRootBlock; + processRootPointer = _pr_gcData.processRootPointer; + + _pr_gcData.liveBlock = pr_ConservativeTraceRootBlock; + _pr_gcData.livePointer = pr_ConservativeTraceRootPointer; + _pr_gcData.processRootBlock = pr_ConservativeTraceRootBlock; + _pr_gcData.processRootPointer = pr_ConservativeTraceRootPointer; + _pr_gcData.dumpOutput = out; + + fprintf(out, "### Looking for paths to 0x%p\n\n", pr_traceObj); + + rf = _pr_rootFinders; + while (rf) { + fprintf(out, "\n===== Roots for %s\n", rf->name); + (*rf->func)(rf->arg); + rf = rf->next; + } + + _pr_gcData.liveBlock = liveBlock; + _pr_gcData.livePointer = livePointer; + _pr_gcData.processRootBlock = processRootBlock; + _pr_gcData.processRootPointer = processRootPointer; + _pr_gcData.dumpOutput = NULL; + + UNLOCK_GC(); +} + +PR_PUBLIC_API(void) +PR_TraceRoot() +{ + /* + ** How this works: + ** Once you find the object you want to trace the roots of, set the + ** global variable pr_traceObj to point to it (the header, not the + ** java handle), and then call this routine (on Windows, you can set + ** a breakpoint at the end of a function that returns void (e.g. dogc) + ** and then do a "set next statement" to point to this routine and go. + ** This will dump a list of the paths from the roots to the object in + ** question to your memory.out file. + */ + PR_DumpToFile("memory.out", "Tracing Roots", PR_TraceRoot1, PR_FALSE); +} + +#endif /* GC_TRACEROOTS */ + +/******************************************************************************/ + +#if defined(DEBUG) && defined(WIN32) +static void DumpApplicationHeap(FILE *out, HANDLE heap) +{ + PROCESS_HEAP_ENTRY entry; + DWORD err; + + if (!HeapLock(heap)) + OutputDebugString("Can't lock the heap.\n"); + entry.lpData = 0; + fprintf(out, " address: size ovhd region\n"); + while (HeapWalk(heap, &entry)) + { + WORD flags = entry.wFlags; + + fprintf(out, "0x%.8X: 0x%.8X 0x%.2X 0x%.2X ", entry.lpData, entry.cbData, + entry.cbOverhead, entry.iRegionIndex); + if (flags & PROCESS_HEAP_REGION) + fprintf(out, "REGION committedSize=0x%.8X uncommittedSize=0x%.8X firstBlock=0x%.8X lastBlock=0x%.8X", + entry.Region.dwCommittedSize, entry.Region.dwUnCommittedSize, + entry.Region.lpFirstBlock, entry.Region.lpLastBlock); + else if (flags & PROCESS_HEAP_UNCOMMITTED_RANGE) + fprintf(out, "UNCOMMITTED"); + else if (flags & PROCESS_HEAP_ENTRY_BUSY) + { + if (flags & PROCESS_HEAP_ENTRY_DDESHARE) + fprintf(out, "DDEShare "); + if (flags & PROCESS_HEAP_ENTRY_MOVEABLE) + fprintf(out, "Moveable Block handle=0x%.8X", entry.Block.hMem); + else + fprintf(out, "Block"); + } + fprintf(out, "\n"); + } + if ((err = GetLastError()) != ERROR_NO_MORE_ITEMS) + fprintf(out, "ERROR %d iterating through the heap\n", err); + if (!HeapUnlock(heap)) + OutputDebugString("Can't unlock the heap.\n"); +} +#endif + +#if defined(DEBUG) && defined(WIN32) +static void DumpApplicationHeaps(FILE *out) +{ + HANDLE mainHeap; + HANDLE heaps[100]; + DWORD nHeaps; + PRInt32 i; + + mainHeap = GetProcessHeap(); + nHeaps = GetProcessHeaps(100, heaps); + if (nHeaps > 100) + nHeaps = 0; + fprintf(out, "%ld heaps:\n", (long) nHeaps); + for (i = 0; ichunkSize; + if (chunkSize < bytes) { + /* Too small; skip it */ + METER(meter.skippedFreeChunks++); + cpp = &cp->next; + continue; + } + + /* We have found a hunk of memory large enough to use */ + p = (PRWord*) cp; + sp = cp->segment; + cpNext = cp->next; +#ifndef IS_64 + if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) { + /* + * We are double aligning the memory and the current free + * chunk is aligned on an even boundary. Because header + * words are one word long we need to discard the first + * word of memory. + */ + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1); + SET_HBIT(sp, p); + p++; + chunkSize -= PR_BYTES_PER_WORD; + bytes -= PR_BYTES_PER_WORD; + PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0); + _pr_gcData.freeMemory -= PR_BYTES_PER_WORD; + _pr_gcData.busyMemory += PR_BYTES_PER_WORD; + } +#endif + np = (PRWord*) ((char*) p + bytes); + remainder = chunkSize - bytes; + if (remainder >= MIN_FREE_CHUNK_BYTES) { + /* The left over memory is large enough to be freed. */ + cp = (GCFreeChunk*) np; + cp->segment = sp; + cp->chunkSize = remainder; + InlineBinNumber(newbin, remainder) + if (newbin != bin) { + *cpp = (GCFreeChunk*) cpNext; /* remove */ + cp->next = bins[newbin]; /* insert */ + bins[newbin] = cp; + if (newbin < minBin) minBin = newbin; + if (newbin > maxBin) maxBin = newbin; + } else { + /* Leave it on the same list */ + cp->next = cpNext; + *cpp = (GCFreeChunk*) np; + } + } else { + /* + * The left over memory is too small to be released. Just + * leave it attached to the chunk of memory being + * returned. + */ + *cpp = cpNext; + bytes = chunkSize; + } + p[0] = MAKE_HEADER(cbix, (bytes >> PR_BYTES_PER_WORD_LOG2)); + SET_HBIT(sp, p); + _pr_gcData.freeMemory -= bytes; + _pr_gcData.busyMemory += bytes; + return p; + } + } + return 0; +} + +/* +** Allocate a piece of memory that is "big" in it's own segment. Make +** the object consume the entire segment to avoid fragmentation. When +** the object is no longer referenced, the segment is freed. +*/ +static PRWord *BigAlloc(int cbix, PRInt32 bytes, int dub) +{ + GCSeg *sp; + PRWord *p, h; + PRInt32 chunkSize; + + /* + ** If the number of bytes allocated via BigAlloc() since the last GC + ** exceeds BIG_ALLOC_GC_SIZE then do a GC Now... + */ + if (bigAllocBytes >= BIG_ALLOC_GC_SIZE) { + dogc(); + } + bigAllocBytes += bytes; + + /* Get a segment to hold this allocation */ + sp = GrowHeapExactly(bytes); + + if (sp) { + p = (PRWord*) sp->base; + chunkSize = sp->limit - sp->base; + + /* All memory is double aligned on 64 bit machines... */ +#ifndef IS_64 + if (dub && (((PRWord)p & (PR_BYTES_PER_DWORD-1)) == 0)) { + /* + ** Consume the first word of the chunk with a dummy + ** unreferenced object. + */ + p[0] = MAKE_HEADER(FREE_MEMORY_TYPEIX, 1); + SET_HBIT(sp, p); + p++; + chunkSize -= PR_BYTES_PER_WORD; + _pr_gcData.freeMemory -= PR_BYTES_PER_WORD; + _pr_gcData.busyMemory += PR_BYTES_PER_WORD; + PR_ASSERT(((PRWord)p & (PR_BYTES_PER_DWORD-1)) != 0); + } +#endif + +#if defined(WIN16) + /* All memory MUST be aligned on 32bit boundaries */ + PR_ASSERT( (((PRWord)p) & (PR_BYTES_PER_WORD-1)) == 0 ); +#endif + + /* Consume the *entire* segment with a single allocation */ + h = MAKE_HEADER(cbix, (chunkSize >> PR_BYTES_PER_WORD_LOG2)); + p[0] = h; + SET_HBIT(sp, p); + _pr_gcData.freeMemory -= chunkSize; + _pr_gcData.busyMemory += chunkSize; + return p; + } + return 0; +} + +/* we disable gc allocation during low memory conditions */ +static PRBool allocationEnabled = PR_TRUE; + +PR_IMPLEMENT(void) PR_EnableAllocation(PRBool yesOrNo) +{ + allocationEnabled = yesOrNo; +} + +static void CollectorCleanup(void) { + while (collectorCleanupNeeded) { + LOCK_GC(); + collectorCleanupNeeded = 0; + UNLOCK_GC(); + if (freeSegs) { + FreeSegments(); + } + if (!WEAK_FREELIST_ISEMPTY()) { + EmptyWeakFreeList(); + } + } +} + +/******************************************************************************/ + +#ifdef GC_CHECK +static PRInt32 allocationCount; + +static void EarthShatteringKaBoom(PRInt32 whichOne) { + long* p = 0; + *p = 0; +} + +/* Check a segment of heap memory. Verify that the object memory + hasn't been overwritten (past the end at least) */ +static void CheckSegment(GCSeg* sp) { + PRWord h, tix; + PRWord *p, *lastp, *np, *limit; + + lastp = p = (PRWord *) sp->base; + limit = (PRWord *) sp->limit; + while (p < limit) { + if (IS_HBIT(sp, p)) { + char *cp, i; + GCBlockEnd* end; + PRWord bytes, requestedBytes; + + h = p[0]; + tix = GET_TYPEIX(h); + bytes = OBJ_BYTES(h); + np = (PRWord *) ((char *)p + bytes); + if (tix != FREE_MEMORY_TYPEIX) { + PRInt32 test; /* msdev get's fooled without this local */ + /* A live object is here. The last word in the object will + contain the objects requestedSize */ + end = (GCBlockEnd*)((char*)(p) + bytes - sizeof(GCBlockEnd)); + test = end->check; + if (test != PR_BLOCK_END) { + PR_ASSERT(test == PR_BLOCK_END); + } + requestedBytes = end->requestedBytes; + if (requestedBytes >= bytes) EarthShatteringKaBoom(0); + cp = (char*)(p + 1) + requestedBytes; + i = (char) 0xff; + while (cp < (char*)end) { + if (*cp != i) EarthShatteringKaBoom(1); + cp++; + i--; + } + } + lastp = p; + p = np; + } else { + /* Must be a freelist item */ + GCFreeChunk *cp = (GCFreeChunk*) p; + if ((PRInt32)cp->chunkSize < (PRInt32)sizeof(GCFreeChunk)) { + EarthShatteringKaBoom(3); + } + lastp = p; + p = (PRWord*) ((char*)p + cp->chunkSize); + } + } +} + +static void CheckHeap(void) { + GCSeg *sp = segs; + GCSeg *esp = sp + nsegs; + while (sp < esp) { + CheckSegment(sp); + sp++; + } +} + +#endif /* GC_CHECK */ + +/******************************************************************************/ + +#ifdef DEBUG +long gc_thrash = -1L; +#endif + +/* +** Allocate memory from the GC Heap. Performs garbage collections if +** memory gets tight and grows the heap as needed. May return NULL if +** memory cannot be found. +*/ +PR_IMPLEMENT(PRWord GCPTR *)PR_AllocMemory( + PRWord requestedBytes, PRInt32 tix, PRWord flags) +{ + PRWord *p; + CollectorType *ct; + PRInt32 bytes; + GCFinal *final = 0; + GCWeak *weak = 0; + int dub = flags & PR_ALLOC_DOUBLE; + PRInt32 objBytes; +#ifdef GC_STATS + PRInt64 allocTime, ldelta; +#endif + + if (!allocationEnabled) return NULL; + + PR_ASSERT(requestedBytes >= 0); + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + +#ifdef DEBUG + if (_pr_do_a_dump) { + /* + ** Collect, pause for a second (lets finalizer run), and then GC + ** again. + */ + PR_GC(); + PR_Sleep(PR_MicrosecondsToInterval(1000000L)); + PR_GC(); + PR_DumpGCHeap(_pr_dump_file, PR_TRUE); + _pr_do_a_dump = 0; + } +#endif + +#ifdef GC_STATS + allocTime = PR_Now(); +#endif + bytes = (PRInt32) requestedBytes; + + /* + ** Align bytes to a multiple of a PRWord, then add in enough space + ** to hold the header word. + ** + ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-( + */ +#if !defined(WIN16) + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2; + bytes <<= PR_BYTES_PER_WORD_LOG2; + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL; + bytes += sizeof(PRWord); +#else + /* + ** For WIN16 the shifts have been broken out into separate statements + ** to prevent the compiler from crashing... + */ + { + PRWord shiftVal; + + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD - 1L; + shiftVal = PR_BYTES_PER_WORD_LOG2; + bytes >>= shiftVal; + bytes <<= shiftVal; + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - sizeof(PRWord)) < bytes ) return NULL; + bytes += sizeof(PRWord); + } +#endif + /* + * Add in an extra word of memory for double-aligned memory. Some + * percentage of the time this will waste a word of memory (too + * bad). Howver, it makes the allocation logic much simpler and + * faster. + */ +#ifndef IS_64 + if (dub) { + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD; + } +#endif + +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Bloat the allocation a bit so that we can lay down + a check pattern that we will validate */ + /* Check for possible overflow of bytes before performing add */ + if ((MAX_INT - PR_BYTES_PER_WORD * 3) < bytes ) return NULL; + bytes += PR_BYTES_PER_WORD * 3; + } +#endif + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + if ((MAX_INT - sizeof(GCBlockEnd)) < bytes ) return NULL; + bytes += sizeof(GCBlockEnd); +#endif + + PR_ASSERT( bytes < MAX_ALLOC_SIZE ); + /* + ** Java can ask for objects bigger than MAX_ALLOC_SIZE, + ** but it won't get them. + */ + if (bytes >= MAX_ALLOC_SIZE) return NULL; + +#ifdef DEBUG + if (gc_thrash == -1L ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")):gc_thrash) PR_GC(); +#endif + + ct = &_pr_collectorTypes[tix]; + if (ct->flags & (_GC_TYPE_FINAL|_GC_TYPE_WEAK)) { + if (0 != ct->gctype.finalize) { + /* + ** Allocate a GCFinal struct for this object in advance. Don't put + ** it on the pending list until we have allocated the object + */ + final = AllocFinalNode(); + if (!final) { + /* XXX THIS IS NOT ACCEPTABLE*/ + PR_ASSERT(0); + return 0; + } + } + if (0 != ct->gctype.getWeakLinkOffset) { + /* + ** Allocate a GCWeak struct for this object in advance. Don't put + ** it on the weak links list until we have allocated the object + */ + weak = AllocWeakNode(); + if (!weak) { + /* XXX THIS IS NOT ACCEPTABLE*/ + if (0 != final) { + FreeFinalNode(final); + } + PR_ASSERT(0); + return 0; + } + } + } + + LOCK_GC(); +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) CheckHeap(); + allocationCount++; +#endif + + /* Check for overflow of maximum size we can handle */ + if (bytes > MAX_ALLOC) goto lost; + + /* Try default allocation */ + p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ? + BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub); + if (0 == p) { +#ifdef GC_STATS + LL_SUB(ldelta, PR_Now(), allocTime); +#endif + /* Collect some memory */ + _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes)); + dogc(); + PR_ASSERT( GC_IS_LOCKED() ); + + /* After a collection we check and see if we should grow the + ** heap. We grow the heap when the amount of memory free is less + ** than a certain percentage of the heap size. We don't check to + ** see if the grow succeeded because our fallback strategy in + ** either case is to try one more time to allocate. */ + if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) + && ((_pr_gcData.freeMemory < + ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L)) + || (_pr_gcData.freeMemory < bytes))) { + GrowHeap(PR_MAX(bytes, segmentSize)); + } +#ifdef GC_STATS + LL_ADD(allocTime, PR_Now(), ldelta); +#endif + + /* Try again */ + p = ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) ? + BigAlloc(tix, bytes, dub) : BinAlloc(tix, bytes, dub); + if (0 == p) { + /* Well that lost big time. Memory must be pretty well fragmented */ + if (!GrowHeap(PR_MAX(bytes, segmentSize))) goto lost; + p = BinAlloc(tix, bytes, dub); + if (0 == p) goto lost; + } + } + + /* Zero out the portion of the object memory that was used by + the GCFreeChunk structure (skip the first word because it + was already overwritten by the gc header word) */ + objBytes = OBJ_BYTES(p[0]); + if (objBytes > sizeof(PRWord)) p[1] = 0; + if (objBytes > sizeof(PRWord)*2) p[2] = 0; + + if (final) { + _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d) final=0x%x", + p, bytes, final)); + final->object = p; + PR_APPEND_LINK(&final->links, &_pr_finalizeableObjects); + } else { + _GCTRACE(GC_ALLOC, ("alloc 0x%x (%d)", p, bytes)); + } + if (weak) { + weak->object = p; + PR_APPEND_LINK(&weak->links, &_pr_weakLinks); + } + METER(meter.allocBytes += bytes); + METER(meter.wastedBytes += (bytes - requestedBytes)); + UNLOCK_GC(); + + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + { + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + end->check = PR_BLOCK_END; + } +#endif +#ifdef GC_STATS + { + PRInt64 now = PR_Now(); + double delta; + PRInt32 bin; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + + end->allocTime = allocTime; + LL_SUB(ldelta, now, allocTime); + LL_L2D(delta, ldelta); + InlineBinNumber(bin, requestedBytes); + end->bin = bin; + gcstats[bin].nallocs++; + gcstats[bin].allocTime += delta; + gcstats[bin].allocTimeVariance += delta * delta; + } +#endif +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Place a pattern in the memory that was allocated that was not + requested. We will check the pattern later. */ + char* cp = (char*)(p + 1) + requestedBytes; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + char i = (char) 0xff; + while (cp < (char*)end) { + *cp++ = i--; + } + end->requestedBytes = requestedBytes; + CheckHeap(); + } +#endif + return p + 1; + + lost: + /* Out of memory */ + UNLOCK_GC(); + if (final) { + FreeFinalNode(final); + } + if (weak) { + FreeWeakNode(weak); + } + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + return 0; +} + +/* Shortcut allocator for objects that do not require finalization or + are weak objects */ +PR_IMPLEMENT(PRWord GCPTR *) +PR_AllocSimpleMemory(PRWord requestedBytes, PRInt32 tix) +{ + PRWord *p; + PRInt32 bytes; + PRInt32 objBytes; +#ifdef GC_STATS + PRInt64 allocTime, ldelta; +#endif + + if (!allocationEnabled) return NULL; + + PR_ASSERT(requestedBytes >= 0); + PR_ASSERT(_pr_collectorTypes[tix].flags != 0); + +#ifdef DEBUG + if (_pr_do_a_dump) { + /* + ** Collect, pause for a second (lets finalizer run), and then GC + ** again. + */ + PR_GC(); + PR_Sleep(PR_MicrosecondsToInterval(1000000L)); + PR_GC(); + PR_DumpGCHeap(_pr_dump_file, PR_TRUE); + _pr_do_a_dump = 0; + } +#endif + +#ifdef GC_STATS + allocTime = PR_NowMS(); +#endif + bytes = (PRInt32) requestedBytes; + + /* + ** Align bytes to a multiple of a PRWord, then add in enough space + ** to hold the header word. + ** + ** MSVC 1.52 crashed on the ff. code because of the "complex" shifting :-( + */ +#if !defined(WIN16) + bytes = (bytes + PR_BYTES_PER_WORD - 1) >> PR_BYTES_PER_WORD_LOG2; + bytes <<= PR_BYTES_PER_WORD_LOG2; + bytes += sizeof(PRWord); +#else + /* + ** For WIN16 the shifts have been broken out into separate statements + ** to prevent the compiler from crashing... + */ + { + PRWord shiftVal; + + bytes += PR_BYTES_PER_WORD - 1L; + shiftVal = PR_BYTES_PER_WORD_LOG2; + bytes >>= shiftVal; + bytes <<= shiftVal; + bytes += sizeof(PRWord); + } +#endif + + /* + * Add in an extra word of memory for double-aligned memory. Some + * percentage of the time this will waste a word of memory (too + * bad). Howver, it makes the allocation logic much simpler and + * faster. + */ +#ifndef IS_64 + bytes += PR_BYTES_PER_WORD; +#endif + +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Bloat the allocation a bit so that we can lay down + a check pattern that we will validate */ + bytes += PR_BYTES_PER_WORD * 2; + } +#endif + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + bytes += sizeof(GCBlockEnd); +#endif + +#if defined(WIN16) + PR_ASSERT( bytes < MAX_ALLOC_SIZE ); +#endif + /* Java can ask for objects bigger than 4M, but it won't get them */ + /* + * This check was added because there is a fundamental limit of + * the size field maintained by the gc code. Going over the 4M + * limit caused some bits to roll over into another bit field, + * violating the max segment size and causing a bug. + */ + if (bytes >= MAX_ALLOC_SIZE) { + return NULL; + } +#ifdef DEBUG + if (gc_thrash == -1L + ? (gc_thrash = (long)PR_GetEnv("GC_THRASH")) + : gc_thrash) { + PR_GC(); + } +#endif + + LOCK_GC(); +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + CheckHeap(); + } + allocationCount++; +#endif + + /* Try default allocation */ + if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) { + p = BigAlloc(tix, bytes, 1); + } else { + p = BinAlloc(tix, bytes, 1); + } + if (0 == p) { +#ifdef GC_STATS + LL_SUB(ldelta, PR_Now(), allocTime); +#endif + /* Collect some memory */ + _GCTRACE(GC_ALLOC, ("force GC: want %d", bytes)); + dogc(); + PR_ASSERT( GC_IS_LOCKED() ); + + /* After a collection we check and see if we should grow the + heap. We grow the heap when the amount of memory free is less + than a certain percentage of the heap size. We don't check to + see if the grow succeeded because our fallback strategy in + either case is to try one more time to allocate. */ + if ((_pr_gcData.allocMemory < _pr_gcData.maxMemory) && + (_pr_gcData.freeMemory < + ((_pr_gcData.allocMemory * MIN_FREE_THRESHOLD_AFTER_GC) / 100L))) { + GrowHeap(PR_MAX(bytes, segmentSize)); + } +#ifdef GC_STATS + LL_ADD(allocTime, PR_Now(), ldelta); +#endif + + /* Try one last time */ + if ((bytes >= BIG_ALLOC) && (nsegs < MAX_SEGS)) { + p = BigAlloc(tix, bytes, 1); + } else { + p = BinAlloc(tix, bytes, 1); + } + if (0 == p) { + /* Well that lost big time. Memory must be pretty well fragmented */ + if (!GrowHeap(PR_MAX(bytes, segmentSize))) { + goto lost; + } + p = BinAlloc(tix, bytes, 1); + if (0 == p) goto lost; + } + } + + /* Zero out the portion of the object memory that was used by + the GCFreeChunk structure (skip the first word because it + was already overwritten by the gc header word) */ + objBytes = OBJ_BYTES(p[0]); + if (objBytes > sizeof(PRWord)) p[1] = 0; + if (objBytes > sizeof(PRWord)*2) p[2] = 0; + + METER(meter.allocBytes += bytes); + METER(meter.wastedBytes += (bytes - requestedBytes)); + UNLOCK_GC(); + + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + +#if defined(GC_CHECK) || defined(GC_STATS) || defined(GC_TRACEROOTS) + { + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + end->check = PR_BLOCK_END; + } +#endif +#ifdef GC_STATS + { + PRInt64 now = PR_Now(); + double delta; + PRInt32 bin; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + + end->allocTime = allocTime; + LL_SUB(ldelta, now, allocTime); + LL_L2D(delta, ldelta); + InlineBinNumber(bin, requestedBytes); + end->bin = bin; + gcstats[bin].nallocs++; + gcstats[bin].allocTime += delta; + gcstats[bin].allocTimeVariance += delta * delta; + } +#endif +#ifdef GC_CHECK + if (_pr_gcData.flags & GC_CHECK) { + /* Place a pattern in the memory that was allocated that was not + requested. We will check the pattern later. */ + char* cp = (char*)(p + 1) + requestedBytes; + GCBlockEnd* end = (GCBlockEnd*)((char*)p + OBJ_BYTES(p[0]) - sizeof(GCBlockEnd)); + char i = (char) 0xff; + while (cp < (char*)end) { + *cp++ = i--; + } + end->requestedBytes = requestedBytes; + CheckHeap(); + } +#endif + return p + 1; + + lost: + /* Out of memory */ + UNLOCK_GC(); + if (collectorCleanupNeeded) { + CollectorCleanup(); + } + return 0; +} + +/************************************************************************/ + +PR_IMPLEMENT(PRWord) PR_GetObjectHeader(void *ptr) { + GCSeg *sp; + PRWord *h; + + if (ptr == 0) return 0; + sp = InHeap(ptr); + if (sp == 0) return 0; + h = (PRWord*)FindObject(sp, (PRWord*)ptr); + return GC_GET_USER_BITS(h[0]); +} + +PR_IMPLEMENT(PRWord) PR_SetObjectHeader(void *ptr, PRWord newUserBits) { + GCSeg *sp; + PRWord *h, rv; + + if (ptr == 0) return 0; + sp = InHeap(ptr); + if (sp == 0) return 0; + h = (PRWord*)FindObject(sp, (PRWord*)ptr); + rv = GC_GET_USER_BITS(h[0]); + h[0] = (h[0] & ~GC_USER_BITS) | + ((newUserBits << GC_USER_BITS_SHIFT) & GC_USER_BITS); + return rv; +} + +PR_IMPLEMENT(void) PR_InitGC( + PRWord flags, PRInt32 initialHeapSize, PRInt32 segSize, PRThreadScope scope) +{ + static char firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + _pr_msgc_lm = PR_NewLogModule("msgc"); + _pr_pageShift = PR_GetPageShift(); + _pr_pageSize = PR_GetPageSize(); + +#if defined(WIN16) + PR_ASSERT( initialHeapSize < MAX_ALLOC_SIZE ); +#endif + + /* Setup initial heap size and initial segment size */ + if (0 != segSize) segmentSize = segSize; +#ifdef DEBUG + GC = PR_NewLogModule("GC"); + { + char *ev = PR_GetEnv("GC_SEGMENT_SIZE"); + if (ev && ev[0]) { + PRInt32 newSegmentSize = atoi(ev); + if (0 != newSegmentSize) segmentSize = newSegmentSize; + } + ev = PR_GetEnv("GC_INITIAL_HEAP_SIZE"); + if (ev && ev[0]) { + PRInt32 newInitialHeapSize = atoi(ev); + if (0 != newInitialHeapSize) initialHeapSize = newInitialHeapSize; + } + ev = PR_GetEnv("GC_FLAGS"); + if (ev && ev[0]) { + flags |= atoi(ev); + } +#ifdef GCMETER + ev = PR_GetEnv("GC_METER"); + if (ev && ev[0]) { + _pr_gcMeter = atoi(ev); + } +#endif + } +#endif + if (0 == initialHeapSize) initialHeapSize = segmentSize; + if (initialHeapSize < segmentSize) initialHeapSize = segmentSize; + + _pr_gcData.maxMemory = MAX_SEGS * segmentSize; + _pr_gcData.liveBlock = ProcessRootBlock; + _pr_gcData.livePointer = ProcessRootPointer; + _pr_gcData.processRootBlock = ProcessRootBlock; + _pr_gcData.processRootPointer = ProcessRootPointer; + _pr_gcData.dumpOutput = NULL; + + PR_INIT_CLIST(&_pr_finalizeableObjects); + PR_INIT_CLIST(&_pr_finalQueue); + _PR_InitGC(flags); + + /* Create finalizer thread */ + _PR_CreateFinalizer(scope); + + /* Allocate the initial segment for the heap */ + minBin = 31; + maxBin = 0; + GrowHeap(initialHeapSize); + PR_RegisterRootFinder(ScanWeakFreeList, "scan weak free list", 0); +} + +#if defined(WIN16) +/* +** For WIN16 the GC_IN_HEAP() macro must call the private InHeap function. +** This public wrapper function makes this possible... +*/ +PR_IMPLEMENT(PRBool) +PR_GC_In_Heap(void *object) +{ + return InHeap( object ) != NULL; +} +#endif + + +/** Added by Vishy for sanity checking a few GC structures **/ +/** Can use SanityCheckGC to debug corrupted GC Heap situations **/ + +#ifdef DEBUG + +static int SegmentOverlaps(int i, int j) +{ + return + (((segs[i].limit > segs[j].base) && (segs[i].base < segs[j].base)) || + ((segs[j].limit > segs[i].base) && (segs[j].base < segs[i].base))); +} + +static void NoSegmentOverlaps(void) +{ + int i,j; + + for (i = 0; i < nsegs; i++) + for (j = i+1 ; j < nsegs ; j++) + PR_ASSERT(!SegmentOverlaps(i,j)); +} + +static void SegInfoCheck(void) +{ + int i; + for (i = 0 ; i < nsegs ; i++) + PR_ASSERT((segs[i].info->hbits) && + (segs[i].info->hbits == segs[i].hbits) && + (segs[i].info->base == segs[i].base) && + (segs[i].info->limit == segs[i].limit)); +} + +static void SanityCheckGC() +{ + NoSegmentOverlaps(); + SegInfoCheck(); +} + +#endif + +#if defined(DEBUG) && defined(WIN32) + +extern void *baseaddr; +extern void *lastaddr; + +PR_IMPLEMENT(void) +PR_PrintGCStats(void) +{ + long reportedSegSpace = _pr_gcData.busyMemory + _pr_gcData.freeMemory; + char* msg; + long largeCount = 0, largeSize = 0; + long segCount = 0, segSize = 0; + long freeCount = 0, freeSize = 0; + GCSeg *sp, *esp; + GCSegInfo* si; + + LOCK_GC(); + + sp = segs; + esp = sp + nsegs; + while (sp < esp) { + long size = sp->info->limit - sp->info->base; + segCount++; + segSize += size; + if (sp->info->fromMalloc) { + largeCount++; + largeSize += size; + } + sp++; + } + + si = freeSegs; + while (si != NULL) { + long size = si->limit - si->base; + freeCount++; + freeSize += size; + si = si->next; + } + + msg = PR_smprintf("\ +# GC Stats:\n\ +# vm space:\n\ +# range: %ld - %ld\n\ +# size: %ld\n\ +# segments:\n\ +# range: %ld - %ld\n\ +# count: %ld (reported: %ld)\n\ +# size: %ld (reported: %ld)\n\ +# free count: %ld\n\ +# free size: %ld\n\ +# busy objs: %ld (%ld%%)\n\ +# free objs: %ld (%ld%%)\n\ +# large blocks:\n\ +# count: %ld\n\ +# total size: %ld (%ld%%)\n\ +# avg size: %ld\n\ +", + /* vm space */ + (long)baseaddr, (long)lastaddr, + (long)lastaddr - (long)baseaddr, + /* segments */ + _pr_gcData.lowSeg, _pr_gcData.highSeg, + segCount, nsegs, + segSize, reportedSegSpace, + freeCount, + freeSize, + _pr_gcData.busyMemory, + (_pr_gcData.busyMemory * 100 / reportedSegSpace), + _pr_gcData.freeMemory, + (_pr_gcData.freeMemory * 100 / reportedSegSpace), + /* large blocks */ + largeCount, + largeSize, (largeSize * 100 / reportedSegSpace), + (largeCount ? largeSize / largeCount : 0) + ); + UNLOCK_GC(); + fprintf(stderr, msg); + OutputDebugString(msg); + PR_smprintf_free(msg); +#ifdef GC_STATS + PR_PrintGCAllocStats(); +#endif +} +#endif + +PR_IMPLEMENT(void) +PR_DumpToFile(char* filename, char* msg, PRFileDumper dump, PRBool detailed) +{ + FILE *out; + OutputDebugString(msg); + out = fopen(filename, "a"); + if (!out) { + char buf[64]; + PR_ASSERT(strlen(filename) < sizeof(buf) - 16); + PR_snprintf(buf, sizeof(buf), "Can't open \"%s\"\n", + filename); + OutputDebugString(buf); + } + else + { + struct tm *newtime; + time_t aclock; + int i; + + time(&aclock); + newtime = localtime(&aclock); + fprintf(out, "%s on %s\n", msg, asctime(newtime)); /* Print current time */ + dump(out, detailed); + fprintf(out, "\n\n"); + for (i = 0; i < 80; i++) + fprintf(out, "="); + fprintf(out, "\n\n"); + fclose(out); + } + OutputDebugString(" done\n"); +} + diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/unixgc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/unixgc.c new file mode 100644 index 00000000..cea4225e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/unixgc.c @@ -0,0 +1,155 @@ +/* -*- 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 "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include "gcint.h" + +#include +#include +#include +#include +#include + +#define _PR_GC_VMBASE 0x40000000 + +#if defined(SOLARIS) +#define _MD_MMAP_FLAGS MAP_SHARED +#elif defined(RELIANTUNIX) +#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED +#else +#define _MD_MMAP_FLAGS MAP_PRIVATE +#endif + +static PRInt32 zero_fd = -1; +static PRLock *zero_fd_lock = NULL; + +void _MD_InitGC(void) +{ +#ifdef DEBUG + /* + * Disable using mmap(2) if NSPR_NO_MMAP is set + */ + if (getenv("NSPR_NO_MMAP")) { + zero_fd = -2; + return; + } +#endif + zero_fd = open("/dev/zero",O_RDWR , 0); + zero_fd_lock = PR_NewLock(); +} + +/* This static variable is used by _MD_GrowGCHeap and _MD_ExtendGCHeap */ +static void *lastaddr = (void*) _PR_GC_VMBASE; + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + PRUint32 size; + + size = *sizep; + + PR_Lock(zero_fd_lock); + if (zero_fd < 0) { + goto mmap_loses; + } + + /* Extend the mapping */ + addr = mmap(lastaddr, size, PROT_READ|PROT_WRITE|PROT_EXEC, + _MD_MMAP_FLAGS, + zero_fd, 0); + if (addr == (void*)-1) { + zero_fd = -1; + goto mmap_loses; + } + lastaddr = ((char*)addr + size); +#ifdef DEBUG + PR_LOG(_pr_msgc_lm, PR_LOG_WARNING, + ("GC: heap extends from %08x to %08x\n", + _PR_GC_VMBASE, + _PR_GC_VMBASE + (char*)lastaddr - (char*)_PR_GC_VMBASE)); +#endif + PR_Unlock(zero_fd_lock); + return addr; + +mmap_loses: + PR_Unlock(zero_fd_lock); + return PR_MALLOC(size); +} + +/* XXX - This is disabled. MAP_FIXED just does not work. */ +#if 0 +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + PRBool rv = PR_FALSE; + void* addr; + PRInt32 allocSize = newSize - oldSize; + + PR_Lock(zero_fd_lock); + addr = mmap(base + oldSize, allocSize, PROT_READ|PROT_WRITE|PROT_EXEC, + _MD_MMAP_FLAGS | MAP_FIXED, zero_fd, 0); + if (addr == (void*)-1) { + goto loser; + } + if (addr != (void*) (base + oldSize)) { + munmap(base + oldSize, allocSize); + goto loser; + } + lastaddr = ((char*)base + newSize); + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap now extends from %p to %p", + base, base + newSize)); + rv = PR_TRUE; + +loser: + PR_Unlock(zero_fd_lock); + return rv; +} +#else +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + return PR_FALSE; +} +#endif + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + if (zero_fd < 0) { + PR_DELETE(base); + } else { + (void) munmap(base, len); + } +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win16gc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win16gc.c new file mode 100644 index 00000000..0af0079b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win16gc.c @@ -0,0 +1,77 @@ +/* -*- 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 ***** */ +#if defined(WIN16) +#include +#endif +#include "prtypes.h" +#include + +#define MAX_SEGMENT_SIZE (65536l - 4096l) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +void _MD_InitGC(void) {} + +extern void * +_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + + if( *sizep > MAX_SEGMENT_SIZE ) { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + +HINSTANCE _pr_hInstance; + +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + _pr_hInstance = hInst; + return TRUE; +} + + diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win32gc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win32gc.c new file mode 100644 index 00000000..eec83774 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/src/win32gc.c @@ -0,0 +1,129 @@ +/* -*- 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 ***** */ + +/* + * GC related routines + * + */ +#include +#include "prlog.h" + +extern PRLogModuleInfo* _pr_msgc_lm; + +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +void *baseaddr = (void*) GC_VMBASE; +void *lastaddr = (void*) GC_VMBASE; + +void _MD_InitGC() {} + +void *_MD_GrowGCHeap(PRUint32 *sizep) +{ + void *addr; + size_t size; + + /* Reserve a block of memory for the GC */ + if( lastaddr == baseaddr ) { + addr = VirtualAlloc( (void *)GC_VMBASE, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE ); + + /* + ** If the GC_VMBASE address is already mapped, then let the OS choose a + ** base address that is available... + */ + if (addr == NULL) { + addr = VirtualAlloc( NULL, GC_VMLIMIT, MEM_RESERVE, PAGE_READWRITE ); + + baseaddr = lastaddr = addr; + if (addr == NULL) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to allocate heap: LastError=%ld", + GetLastError())); + return 0; + } + } + } + size = *sizep; + + /* Extend the mapping */ + addr = VirtualAlloc( lastaddr, size, MEM_COMMIT, PAGE_READWRITE ); + if (addr == NULL) { + return 0; + } + + lastaddr = ((char*)addr + size); + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap extends from %08x to %08x", + baseaddr, (long)baseaddr + (char*)lastaddr - (char*)baseaddr)); + + return addr; +} + +PRBool _MD_ExtendGCHeap(char *base, PRInt32 oldSize, PRInt32 newSize) { + void* addr; + + addr = VirtualAlloc( base + oldSize, newSize - oldSize, + MEM_COMMIT, PAGE_READWRITE ); + if (NULL == addr) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: unable to extend heap: LastError=%ld", + GetLastError())); + return PR_FALSE; + } + if (base + oldSize != (char*)addr) { + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, ("GC: segment extension returned %x instead of %x", + addr, base + oldSize)); + VirtualFree(addr, newSize - oldSize, MEM_DECOMMIT); + return PR_FALSE; + } + lastaddr = base + newSize; + PR_LOG(_pr_msgc_lm, PR_LOG_ALWAYS, + ("GC: heap now extends from %p to %p", + base, base + newSize)); + return PR_TRUE; +} + + +void _MD_FreeGCSegment(void *base, PRInt32 len) +{ + (void)VirtualFree(base, 0, MEM_RELEASE); +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/Makefile.in new file mode 100644 index 00000000..23518e15 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/Makefile.in @@ -0,0 +1,315 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +W16STDIO = $(MOD_DEPTH)/pr/src/md/windows/$(OBJDIR)/w16stdio.$(OBJ_SUFFIX) +endif + +ifeq ($(OS_TARGET), OS2) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CSRCS = gc1.c thrashgc.c + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +NSPR_VERSION = $(MOD_MAJOR_VERSION) +GC_VERSION = $(MOD_MAJOR_VERSION) +LIBPR = -lnspr$(NSPR_VERSION) +LIBPLC = -lplc$(NSPR_VERSION) +LIBGC = -lmsgc$(GC_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(NSPR_VERSION).lib + LIBGC= $(dist_libdir)/msgc$(GC_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).$(LIB_SUFFIX) + LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).$(LIB_SUFFIX) + LIBGC= $(dist_libdir)/libmsgc$(GC_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(NSPR_VERSION).lib + LIBGC= $(dist_libdir)/msgc$(GC_VERSION).lib +else + LDOPTS += -Zomf -Zlinker /PM:VIO +endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -rdata_shared + +# For 6.x machines, include this flag +ifeq ($(basename $(OS_RELEASE)),6) +ifeq ($(USE_N32),1) +LDOPTS += -n32 +else +LDOPTS += -32 +endif +endif + +endif + +ifeq ($(OS_ARCH), OSF1) +# I haven't figured out how to pass -rpath to cc on OSF1 V3.2, so +# we do static linking. +ifeq ($(OS_RELEASE), V3.2) + LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a + LIBGC = $(dist_libdir)/libmsgc$(GC_VERSION).a + EXTRA_LIBS = -lc_r +else + LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -z -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) +LIBPR = -lnspr$(NSPR_VERSION)_shr +LIBPLC = -lplc$(NSPR_VERSION)_shr +LIBGC = -lmsgc$(GC_VERSION)_shr +else +LDOPTS += -brtl +EXTRA_LIBS = -ldl +endif +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +endif +endif + +ifneq ($(LOCAL_THREADS_ONLY),1) +# SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, +# even though we already linked with these system libraries +# when we built libnspr.so. +ifeq ($(OS_RELEASE), 5.4) +EXTRA_LIBS = -lthread +endif + +ifeq ($(OS_RELEASE), 5.5) +ifdef USE_PTHREADS +EXTRA_LIBS = -lpthread +else +EXTRA_LIBS = -lthread +endif +endif +endif # LOCAL_THREADS_ONLY +endif # SunOS + +ifeq ($(OS_ARCH),NEC) +EXTRA_LIBS = $(OS_LIBS) +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).a +LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a +LIBGC = $(dist_libdir)/libmsgc$(GC_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +#export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), Linux) +ifeq ($(OS_RELEASE), 1.2) +EXTRA_LIBS = -ldl +endif +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH),SINIX) +EXTRA_LIBS = -lsocket -lnsl -lresolv -ldl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH),BSD_OS) +EXTRA_LIBS = -ldl +endif + +ifeq ($(OS_ARCH),DGUX) +EXTRA_LIBS = -lsocket -lnsl -ldl +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(NSPR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo name $@ >>w16link + echo option map >>w16link +# echo option CASEEXACT >>w16link + echo option stack=16K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo file >>w16link + echo $< , >>w16link + echo $(W16STDIO) >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo $(LIBGC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) wsock32.lib -out:$@ +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBGC) $(LIBPLC) $(LIBPR) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +export:: install +clean:: + rm -f $(TARGETS) diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/gc1.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/gc1.c new file mode 100644 index 00000000..d6846235 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/gc1.c @@ -0,0 +1,257 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prgc.h" +#include "prinit.h" +#include "prmon.h" +#include "prinrval.h" +#ifndef XP_MAC +#include "private/pprthred.h" +#else +#include "pprthred.h" +#endif + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static PRMonitor *mon; +static PRInt32 threads, waiting, iterations; +static PRInt32 scanCount, finalizeCount, freeCount; + +PRIntn failed_already=0; +PRIntn debug_mode; + + +typedef struct Array { + PRUintn size; + void *body[1]; +} Array; + +int arrayTypeIndex; + +static void PR_CALLBACK ScanArray(void *a) +{ +/* printf ("In ScanArray a = %X size = %d \n", a, a->size); */ + scanCount++; +} + +static void PR_CALLBACK FinalizeArray(void *a) +{ +/* printf ("In FinalizeArray a = %X size = %d \n", a, a->size); */ + finalizeCount++; +} + +static void PR_CALLBACK FreeArray(void *a) +{ +/* printf ("In FreeArray\n"); */ + freeCount++; +} + +static Array *NewArray(PRUintn size) +{ + Array *a; + + a = (Array *)PR_AllocMemory(sizeof(Array) + size*sizeof(void*) - 1*sizeof(void*), + arrayTypeIndex, PR_ALLOC_CLEAN); + +/* printf ("In NewArray a = %X \n", a); */ + + if (a) + a->size = size; + return a; +} + +GCType arrayType = { + ScanArray, + FinalizeArray, + 0, + 0, + FreeArray, + 0 +}; + +static void Initialize(void) +{ + PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD); + arrayTypeIndex = PR_RegisterType(&arrayType); +} + +static void PR_CALLBACK AllocateLikeMad(void *arg) +{ + Array *prev; + PRInt32 i; + PRInt32 count; + + count = (PRInt32)arg; + prev = 0; + for (i = 0; i < count; i++) { + Array *leak = NewArray(i & 511); + if ((i & 1023) == 0) { + prev = 0; /* forget */ + } else { + if (i & 1) { + prev = leak; /* remember */ + } + } + } + PR_EnterMonitor(mon); + waiting++; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +int main(int argc, char **argv) +{ + PRIntervalTime start, stop, usec; + double d; + PRIntn i, totalIterations; + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); + + threads = 10; + iterations = 100; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) { + fprintf(stderr, "Invalid command-line option\n"); + exit(1); + } + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'c': /* iteration count */ + iterations = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + fprintf(stderr, "t is %ld, i is %ld\n", (long) threads, (long) iterations); + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5); + PR_STDIO_INIT(); + Initialize(); + +#ifdef XP_MAC + SetupMacPrintfLog("gc1.log"); + debug_mode = 1; +#endif + + /* Spin all of the allocator threads and then wait for them to exit */ + start = PR_IntervalNow(); + mon = PR_NewMonitor(); + PR_EnterMonitor(mon); + waiting = 0; + for (i = 0; i < threads; i++) { + (void) PR_CreateThreadGCAble(PR_USER_THREAD, + AllocateLikeMad, (void*)iterations, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + } + while (waiting != threads) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + PR_GC(); + PR_ForceFinalize(); + + totalIterations = iterations * threads; +/* + if (scanCount != totalIterations) + printf ("scanCount discrepancy scanCount = %d totalIterations = %d \n", + scanCount, totalIterations); + if (freeCount != totalIterations) + printf ("freeCount discrepancy freeCount = %d totalIterations = %d \n", + freeCount, totalIterations); + if ((finalizeCount != totalIterations) && (finalizeCount != (totalIterations-1))) + printf ("finalizeCount discrepancy finalizeCount = %d totalIterations = %d \n", + finalizeCount,totalIterations); +*/ + + stop = PR_IntervalNow(); + + usec = stop = stop - start; + d = (double)usec; + + if (debug_mode) printf("%40s: %6.2f usec\n", "GC allocation", d / (iterations * threads)); + else { + if (d == 0.0) failed_already = PR_TRUE; + + } + + PR_Cleanup(); + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/thrashgc.c b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/thrashgc.c new file mode 100644 index 00000000..9d49ec19 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/msgc/tests/thrashgc.c @@ -0,0 +1,274 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** Name: thrashgc +** +** Description: test garbace collection functions. +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prthread.h" +#include "prgc.h" +#include "prprf.h" +#include "prinrval.h" +#include "prlock.h" +#include "prinit.h" +#include "prcvar.h" + +#ifndef XP_MAC +#include "private/pprthred.h" +#else +#include "pprthred.h" +#endif + +#include +#include +#include + + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static char* progname; +static PRInt32 loops = 1000; +static int tix1, tix2, tix3; +static GCInfo* gcInfo; +static PRLock* stderrLock; + +typedef struct Type1 Type1; +typedef struct Type2 Type2; + +struct Type1 { + Type2* atwo; + Type1* next; +}; + +struct Type2 { + void* buf; +}; + +static void PR_CALLBACK ScanType1(void *obj) { + gcInfo->livePointer(((Type1 *)obj)->atwo); + gcInfo->livePointer(((Type1 *)obj)->next); +} + +static void PR_CALLBACK ScanType2(void *obj) { + gcInfo->livePointer(((Type2 *)obj)->buf); +} + +static GCType type1 = { + ScanType1 +}; + +static GCType type2 = { + ScanType2 +/* (void (*)(void*)) ScanType2 */ +}; + +static GCType type3 = { + 0 +}; + +Type1* NewType1(void) { + Type1* p = (Type1*) PR_AllocMemory(sizeof(Type1), tix1, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +Type2* NewType2(void) { + Type2* p = (Type2*) PR_AllocMemory(sizeof(Type2), tix2, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +void* NewBuffer(PRInt32 size) { + void* p = PR_AllocMemory(size, tix3, PR_ALLOC_DOUBLE); + PR_ASSERT(p != NULL); + return p; +} + +/* Allocate alot of garbage */ +static void PR_CALLBACK AllocStuff(void *unused) { + PRInt32 i; + void* danglingRefs[50]; + PRIntervalTime start, end; + char msg[100]; + + start = PR_IntervalNow(); + for (i = 0; i < loops; i++) { + void* p; + if (i & 1) { + Type1* t1 = NewType1(); + t1->atwo = NewType2(); + t1->next = NewType1(); + t1->atwo->buf = NewBuffer(100); + p = t1; + } else { + Type2* t2 = NewType2(); + t2->buf = NewBuffer(i & 16383); + p = t2; + } + if ((i % 10) == 0) { + memmove(&danglingRefs[0], &danglingRefs[1], 49*sizeof(void*)); + danglingRefs[49] = p; + } + } + end = PR_IntervalNow(); + if (debug_mode) PR_snprintf(msg, sizeof(msg), "Thread %p: %ld allocations took %ld ms", + PR_GetCurrentThread(), loops, + PR_IntervalToMilliseconds((PRIntervalTime) (end - start))); + PR_Lock(stderrLock); +#ifndef XP_MAC + fprintf(stderr, "%s\n", msg); +#else + if (debug_mode) printf("%s\n", msg); +#endif + PR_Unlock(stderrLock); + } + +static void usage(char *progname) { +#ifndef XP_MAC + fprintf(stderr, "Usage: %s [-t threads] [-l loops]\n", progname); +#else + printf("Usage: %s [-t threads] [-l loops]\n", progname); +#endif + exit(-1); +} + +static int realMain(int argc, char **argv, char *notused) { + int i; + int threads = 0; + +#ifndef XP_MAC + progname = strrchr(argv[0], '/'); + if (progname == 0) progname = argv[0]; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-t") == 0) { + if (i == argc - 1) { + usage(progname); + } + threads = atoi(argv[++i]); + if (threads < 0) threads = 0; + if (threads > 10000) threads = 10000; + continue; + } + if (strcmp(argv[i], "-l") == 0) { + if (i == argc - 1) { + usage(progname); + } + loops = atoi(argv[++i]); + continue; + } + usage(progname); + } +#else + threads = 50; +#endif + + for (i = 0; i < threads; i++) { + PRThread* thread; + + /* XXXXX */ + thread = PR_CreateThreadGCAble(PR_USER_THREAD, /* thread type */ + AllocStuff, /* start function */ + NULL, /* arg */ + PR_PRIORITY_NORMAL, /* priority */ + PR_LOCAL_THREAD, /* thread scope */ + PR_UNJOINABLE_THREAD, /* thread state */ + 0); /* stack size */ + if (thread == 0) { +#ifndef XP_MAC + fprintf(stderr, "%s: no more threads (only %d were created)\n", + progname, i); +#else + printf("%s: no more threads (only %d were created)\n", + progname, i); +#endif + break; + } + } + AllocStuff(NULL); + return 0; +} + +static int padMain(int argc, char **argv) { + char pad[512]; + return realMain(argc, argv, pad); +} + +int main(int argc, char **argv) { + int rv; + + debug_mode = 1; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_SetThreadGCAble(); + +#ifdef XP_MAC + SetupMacPrintfLog("thrashgc.log"); + debug_mode = 1; +#endif + + PR_InitGC(0, 0, 0, PR_GLOBAL_THREAD); + PR_STDIO_INIT(); + stderrLock = PR_NewLock(); + tix1 = PR_RegisterType(&type1); + tix2 = PR_RegisterType(&type2); + tix3 = PR_RegisterType(&type3); + gcInfo = PR_GetGCInfo(); + rv = padMain(argc, argv); + printf("PASS\n"); + PR_Cleanup(); + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/prstreams/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/prstreams/Makefile.in new file mode 100644 index 00000000..5c1311b2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/Makefile.in @@ -0,0 +1,207 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) + ifeq ($(OS_RELEASE),4.1.3_U1) + OPTIMIZER = + else + # The C++ compiler in Workshop 5.0 uses standard + # iostreams as default. -library=iostream will + # allow Workshop 5.0 to work with classic iostreams. + ifndef NS_USE_GCC + CCC_VERSION := $(shell $(CCC) -V 2>&1) + ifneq (,$(findstring 5.0,$(CCC_VERSION))) + CCC_ONLY_FLAGS += -library=iostream + endif + endif + endif +endif + +ifeq ($(OS_ARCH), IRIX) + ifneq ($(OS_RELEASE),5.3) + CCC_ONLY_FLAGS += -exceptions + endif +endif + +ifeq ($(OS_ARCH), BeOS) + CFLAGS += -frtti -fexceptions +endif + +INCLUDES = -I$(dist_includedir) + +HEADERS = $(wildcard $(srcdir)/*.h) + +CSRCS = \ + plvrsion.c \ + $(NULL) + +CXXSRCS = \ + prstrms.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX)) $(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq ($(OS_ARCH), WINNT) + DLLBASE=/BASE:0x30000000 + RES=$(OBJDIR)/prstrms.res + RESNAME=prstrms.rc + OS_LIBS = user32.lib +else + ifeq ($(OS_ARCH),OS2) + ifneq ($(MOZ_OS2_TOOLS),VACPP) + OS_LIBS = -lstdcpp + endif + else + ifeq ($(OS_ARCH), AIX) + ifeq ($(OS_RELEASE), 4.1) + ifeq ($(CLASSIC_NSPR),1) + OS_LIBS += -lC -lc + else + OS_LIBS += -lC_r -lc_r + endif + else + # makeC++SharedLib(_r) is in either /usr/lpp/xlC/bin + # or /usr/ibmcxx/bin. + ifeq ($(CLASSIC_NSPR),1) + MKSHLIB = makeC++SharedLib -p 0 + else + MKSHLIB = makeC++SharedLib_r -p 0 + endif + OS_LIBS += -ldl + endif + endif + endif +endif + +ifeq ($(OS_ARCH),BeOS) + OS_LIBS = -lstdc++.r4 +endif + +ifeq ($(OS_ARCH), UNIXWARE) + OS_LIBS += -lC +endif + +EXTRA_LIBS = $(LIBNSPR) + +# On NCR and SCOOS, we can't link with extra libraries when +# we build a shared library. If we do so, the linker doesn't +# complain, but we would run into weird problems at run-time. +# Therefore on these platforms, we link just the object files. +ifeq ($(OS_ARCH),NCR) + EXTRA_LIBS = +endif +ifeq ($(OS_ARCH),SCOOS) + EXTRA_LIBS = +endif + +ifdef RESOLVE_LINK_SYMBOLS +EXTRA_LIBS += $(OS_LIBS) +endif + +LIBRARY_NAME = prstrms +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +# +# Version information generation (begin) +# +ECHO = echo +TINC = $(OBJDIR)/_pl_bld.h +PROD = $(notdir $(SHARED_LIBRARY)) +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(OS_ARCH), WINNT) + SUF = i64 +else + SUF = LL +endif + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/plvrsion.$(OBJ_SUFFIX): plvrsion.c $(TINC) +ifeq ($(OS_ARCH), WINNT) + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + +export:: $(TARGETS) $(HEADERS) + $(INSTALL) -m 444 $(HEADERS) $(dist_includedir) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifeq ($(OS_ARCH),OS2) + $(INSTALL) -m 444 $(TARGETS) $(dist_bindir) +endif +ifeq ($(OS_ARCH),HP-UX) +ifdef SHARED_LIBRARY + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) +endif +endif diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/plvrsion.c b/src/libs/xpcom18a4/nsprpub/lib/prstreams/plvrsion.c new file mode 100644 index 00000000..87b62e7a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/plvrsion.c @@ -0,0 +1,125 @@ +/* -*- 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 "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#include "_pl_bld.h" +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libprstrms, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* version */ 2, /* this is the only one supported */ + /* buildTime */ _BUILD_TIME, /* usecs since midnight 1/1/1970 GMT */ + /* buildTimeString */ _BUILD_STRING, /* ditto, but human readable */ + /* vMajor */ PR_VMAJOR, /* NSPR's version number */ + /* vMinor */ PR_VMINOR, /* and minor version */ + /* vPatch */ PR_VPATCH, /* and patch */ + /* beta */ PR_BETA, /* beta build boolean */ +#if defined(DEBUG) + /* debug */ PR_TRUE, /* a debug build */ +#else + /* debug */ PR_FALSE, /* an optomized build */ +#endif + /* special */ PR_FALSE, /* they're all special, but ... */ + /* filename */ _PRODUCTION, /* the produced library name */ + /* description */ "Portable runtime", /* what we are */ + /* security */ "N/A", /* not applicable here */ + /* copywrite */ "Copyright (c) 1998 Netscape Communications Corporation. All Rights Reserved", + /* comment */ "http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint() +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* plvrsion.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.cpp b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.cpp new file mode 100644 index 00000000..17b280ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.cpp @@ -0,0 +1,550 @@ +/* -*- 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 ***** */ + +/* + * Robin J. Maxwell 11-22-96 + */ + +#include "prstrms.h" +#include // memmove + +// +// Definition of macros _PRSTR_BP, _PRSTR_DELBUF, and _PRSTR_DELBUF_C. +// +// _PRSTR_BP is the protected member of class ios that is returned +// by the public method rdbuf(). +// +// _PRSTR_DELBUF is the method or data member of class ios, if available, +// with which we can ensure that the ios destructor does not delete +// the associated streambuf. If such a method or data member does not +// exist, define _PRSTR_DELBUF to be empty. +// +// _PRSTR_DELBUF_C is just _PRSTR_DELBUF qualified by a base class. +// + +#if defined(__GNUC__) +#define _PRSTR_BP _strbuf +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(WIN32) +#define _PRSTR_BP bp +#define _PRSTR_DELBUF(x) delbuf(x) +#define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) +#elif defined(VMS) +#undef _PRSTR_BP +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(OSF1) +#define _PRSTR_BP m_psb +#define _PRSTR_DELBUF(x) /* as nothing */ +#define _PRSTR_DELBUF_C(c, x) /* as nothing */ +#elif defined(QNX) +#define PRFSTREAMS_BROKEN +#else +#define _PRSTR_BP bp +// Unix compilers don't believe in encapsulation +// At least on Solaris this is also ignored +#define _PRSTR_DELBUF(x) delbuf = x +#define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) +#endif + +const PRIntn STRM_BUFSIZ = 8192; + +#if !defined (PRFSTREAMS_BROKEN) + +PRfilebuf::PRfilebuf(): +_fd(0), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ +} + +PRfilebuf::PRfilebuf(PRFileDesc *fd): +streambuf(), +_fd(fd), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ +} + +PRfilebuf::PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen): +_fd(fd), +_opened(PR_FALSE), +_allocated(PR_FALSE) +{ + PRfilebuf::setbuf(buffptr, bufflen); +} + +PRfilebuf::~PRfilebuf() +{ + if (_opened){ + close(); + }else + sync(); + if (_allocated) + delete base(); +} + +PRfilebuf* +PRfilebuf::open(const char *name, int mode, int flags) +{ + if (_fd != 0) + return 0; // error if already open + PRIntn PRmode = 0; + // translate mode argument + if (!(mode & ios::nocreate)) + PRmode |= PR_CREATE_FILE; + //if (mode & ios::noreplace) + // PRmode |= O_EXCL; + if (mode & ios::app){ + mode |= ios::out; + PRmode |= PR_APPEND; + } + if (mode & ios::trunc){ + mode |= ios::out; // IMPLIED + PRmode |= PR_TRUNCATE; + } + if (mode & ios::out){ + if (mode & ios::in) + PRmode |= PR_RDWR; + else + PRmode |= PR_WRONLY; + if (!(mode & (ios::in|ios::app|ios::ate|ios::noreplace))){ + mode |= ios::trunc; // IMPLIED + PRmode |= PR_TRUNCATE; + } + }else if (mode & ios::in) + PRmode |= PR_RDONLY; + else + return 0; // error if not ios:in or ios::out + + + // + // The usual portable across unix crap... + // NT gets a hokey piece of junk layer that prevents + // access to the API. +#ifdef WIN32 + _fd = PR_Open(name, PRmode, PRmode); +#else + _fd = PR_Open(name, PRmode, flags); +#endif + if (_fd == 0) + return 0; + _opened = PR_TRUE; + if ((!unbuffered()) && (!ebuf())){ + char * sbuf = new char[STRM_BUFSIZ]; + if (!sbuf) + unbuffered(1); + else{ + _allocated = PR_TRUE; + streambuf::setb(sbuf,sbuf+STRM_BUFSIZ,0); + } + } + if (mode & ios::ate){ + if (seekoff(0,ios::end,mode)==EOF){ + close(); + return 0; + } + } + return this; +} + +PRfilebuf* +PRfilebuf::attach(PRFileDesc *fd) +{ + _opened = PR_FALSE; + _fd = fd; + return this; +} + +int +PRfilebuf::overflow(int c) +{ + if (allocate()==EOF) // make sure there is a reserve area + return EOF; + if (PRfilebuf::sync()==EOF) // sync before new buffer created below + return EOF; + + if (!unbuffered()) + setp(base(),ebuf()); + + if (c!=EOF){ + if ((!unbuffered()) && (pptr() < epptr())) // guard against recursion + sputc(c); + else{ + if (PR_Write(_fd, &c, 1)!=1) + return(EOF); + } + } + return(1); // return something other than EOF if successful +} + +int +PRfilebuf::underflow() +{ + int count; + unsigned char tbuf; + + if (in_avail()) + return (int)(unsigned char) *gptr(); + + if (allocate()==EOF) // make sure there is a reserve area + return EOF; + if (PRfilebuf::sync()==EOF) + return EOF; + + if (unbuffered()) + { + if (PR_Read(_fd,(void *)&tbuf,1)<=0) + return EOF; + return (int)tbuf; + } + + if ((count=PR_Read(_fd,(void *)base(),blen())) <= 0) + return EOF; // reached EOF + setg(base(),base(),base()+count); + return (int)(unsigned char) *gptr(); +} + +streambuf* +PRfilebuf::setbuf(char *buffptr, PRstreambuflen bufflen) +{ + if (is_open() && (ebuf())) + return 0; + if ((!buffptr) || (bufflen <= 0)) + unbuffered(1); + else + setb(buffptr, buffptr+bufflen, 0); + return this; +} + +streampos +PRfilebuf::seekoff(streamoff offset, ios::seek_dir dir, int /* mode */) +{ + if (PR_GetDescType(_fd) == PR_DESC_FILE){ + PRSeekWhence fdir; + PRInt32 retpos; + switch (dir) { + case ios::beg : + fdir = PR_SEEK_SET; + break; + case ios::cur : + fdir = PR_SEEK_CUR; + break; + case ios::end : + fdir = PR_SEEK_END; + break; + default: + // error + return(EOF); + } + + if (PRfilebuf::sync()==EOF) + return EOF; + if ((retpos=PR_Seek(_fd, offset, fdir))==-1L) + return (EOF); + return((streampos)retpos); + }else + return (EOF); +} + + +int +PRfilebuf::sync() +{ + PRInt32 count; + + if (_fd==0) + return(EOF); + + if (!unbuffered()){ + // Sync write area + if ((count=out_waiting())!=0){ + PRInt32 nout; + if ((nout =PR_Write(_fd, + (void *) pbase(), + (unsigned int)count)) != count){ + if (nout > 0) { + // should set _pptr -= nout + pbump(-(int)nout); + memmove(pbase(), pbase()+nout, (int)(count-nout)); + } + return(EOF); + } + } + setp(0,0); // empty put area + + if (PR_GetDescType(_fd) == PR_DESC_FILE){ + // Sockets can't seek; don't need this + if ((count=in_avail()) > 0){ + if (PR_Seek(_fd, -count, PR_SEEK_CUR)!=-1L) + { + return (EOF); + } + } + } + setg(0,0,0); // empty get area + } + return(0); +} + +PRfilebuf * +PRfilebuf::close() +{ + int retval; + if (_fd==0) + return 0; + + retval = sync(); + + if ((PR_Close(_fd)==0) || (retval==EOF)) + return 0; + _fd = 0; + return this; +} + +PRifstream::PRifstream(): +istream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(PRFileDesc *fd): +istream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(PRFileDesc *fd, char *buff, int bufflen): +istream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF(0); +} + +PRifstream::PRifstream(const char * name, int mode, int flags): +istream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); + if (!rdbuf()->open(name, (mode|ios::in), flags)) + clear(rdstate() | ios::failbit); +} + +PRifstream::~PRifstream() +{ + sync(); + + delete rdbuf(); +#ifdef _PRSTR_BP + _PRSTR_BP = 0; +#endif +} + +streambuf * +PRifstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRifstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRifstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|ios::in), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRifstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +PRofstream::PRofstream(): +ostream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(PRFileDesc *fd): +ostream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(PRFileDesc *fd, char *buff, int bufflen): +ostream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF(0); +} + +PRofstream::PRofstream(const char *name, int mode, int flags): +ostream(new PRfilebuf) +{ + _PRSTR_DELBUF(0); + if (!rdbuf()->open(name, (mode|ios::out), flags)) + clear(rdstate() | ios::failbit); +} + +PRofstream::~PRofstream() +{ + flush(); + + delete rdbuf(); +#ifdef _PRSTR_BP + _PRSTR_BP = 0; +#endif +} + +streambuf * +PRofstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRofstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRofstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|ios::out), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRofstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +PRfstream::PRfstream(): +iostream(new PRfilebuf) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(PRFileDesc *fd): +iostream(new PRfilebuf(fd)) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(PRFileDesc *fd, char *buff, int bufflen): +iostream(new PRfilebuf(fd, buff, bufflen)) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); +} + +PRfstream::PRfstream(const char *name, int mode, int flags): +iostream(new PRfilebuf) +{ + _PRSTR_DELBUF_C(istream, 0); + _PRSTR_DELBUF_C(ostream, 0); + if (!rdbuf()->open(name, (mode|(ios::in|ios::out)), flags)) + clear(rdstate() | ios::failbit); +} + +PRfstream::~PRfstream() +{ + sync(); + flush(); + + delete rdbuf(); +#ifdef _PRSTR_BP + istream::_PRSTR_BP = 0; + ostream::_PRSTR_BP = 0; +#endif +} + +streambuf * +PRfstream::setbuf(char * ptr, int len) +{ + if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ + clear(rdstate() | ios::failbit); + return 0; + } + return rdbuf(); +} + +void +PRfstream::attach(PRFileDesc *fd) +{ + if (!(rdbuf()->attach(fd))) + clear(rdstate() | ios::failbit); +} + +void +PRfstream::open(const char * name, int mode, int flags) +{ + if (is_open() || !(rdbuf()->open(name, (mode|(ios::in|ios::out)), flags))) + clear(rdstate() | ios::failbit); +} + +void +PRfstream::close() +{ + clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); +} + +#else + +// fix it sometime + +int fix_prfstreams () { return 0; } + +#endif diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.h b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.h new file mode 100644 index 00000000..a6752fc4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.h @@ -0,0 +1,153 @@ +/* -*- 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 ***** */ + +/* + * Robin J. Maxwell 11-22-96 + */ + +#ifndef _PRSTRMS_H +#define _PRSTRMS_H + +#include "prtypes.h" +#include "prio.h" + +#ifdef _MSC_VER +#pragma warning( disable : 4275) +#endif +#include + +#if defined(AIX) && defined(__64BIT__) +typedef long PRstreambuflen; +#else +typedef int PRstreambuflen; +#endif + +#if defined (PRFSTREAMS_BROKEN) + +// fix it sometime + +#define PRfilebuf streambuf +#define PRifstream ifstream +#define PRofstream ofstream +#define PRfstream fstream + +#else + +class PR_IMPLEMENT(PRfilebuf): public streambuf +{ +public: + PRfilebuf(); + PRfilebuf(PRFileDesc *fd); + PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen); + ~PRfilebuf(); + virtual int overflow(int=EOF); + virtual int underflow(); + virtual streambuf *setbuf(char *buff, PRstreambuflen bufflen); + virtual streampos seekoff(streamoff, ios::seek_dir, int); + virtual int sync(); + PRfilebuf *open(const char *name, int mode, int flags); + PRfilebuf *attach(PRFileDesc *fd); + PRfilebuf *close(); + int is_open() const {return (_fd != 0);} + PRFileDesc *fd(){return _fd;} + +private: + PRFileDesc * _fd; + PRBool _opened; + PRBool _allocated; +}; + +class PR_IMPLEMENT(PRifstream): public istream { +public: + PRifstream(); + PRifstream(const char *, int mode=ios::in, int flags = 0); + PRifstream(PRFileDesc *); + PRifstream(PRFileDesc *, char *, int); + ~PRifstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf(){return (PRfilebuf*) ios::rdbuf(); } + + void attach(PRFileDesc *fd); + PRFileDesc *fd() {return rdbuf()->fd();} + + int is_open(){return rdbuf()->is_open();} + void open(const char *, int mode=ios::in, int flags= 0); + void close(); +}; + +class PR_IMPLEMENT(PRofstream) : public ostream { +public: + PRofstream(); + PRofstream(const char *, int mode=ios::out, int flags = 0); + PRofstream(PRFileDesc *); + PRofstream(PRFileDesc *, char *, int); + ~PRofstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf() { return (PRfilebuf*) ios::rdbuf(); } + + void attach(PRFileDesc *); + PRFileDesc *fd() {return rdbuf()->fd();} + + int is_open(){return rdbuf()->is_open();} + void open(const char *, int =ios::out, int = 0); + void close(); +}; + +class PR_IMPLEMENT(PRfstream) : public iostream { +public: + PRfstream(); + PRfstream(const char *name, int mode, int flags= 0); + PRfstream(PRFileDesc *fd); + PRfstream(PRFileDesc *fd, char *buff, int bufflen); + ~PRfstream(); + + streambuf * setbuf(char *, int); + PRfilebuf* rdbuf(){ return (PRfilebuf*) ostream::rdbuf(); } + + void attach(PRFileDesc *); + PRFileDesc *fd() { return rdbuf()->fd(); } + + int is_open() { return rdbuf()->is_open(); } + void open(const char *, int, int = 0); + void close(); +}; + +#endif + +#endif /* _PRSTRMS_H */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.rc b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.rc new file mode 100644 index 00000000..589a64d1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/prstrms.rc @@ -0,0 +1,102 @@ +/* -*- 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 ***** */ + +#include "prinit.h" +#include + +#define MY_LIBNAME "prstrms" +#define MY_FILEDESCRIPTION "PRSTRMS Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "LegalCopyright", "Copyright \251 1996-2000 Netscape Communications Corporation\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in new file mode 100644 index 00000000..1b682ff8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/Makefile.in @@ -0,0 +1,254 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CXXSRCS = \ + testprstrm.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CXXSRCS:.cpp=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPRSTRMS = -lprstrms$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + ifeq ($(OS_TARGET), WIN95) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPRSTRMS = $(dist_libdir)/libprstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + endif +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO /S:32768 + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPRSTRMS = $(dist_libdir)/prstrms$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) +LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr +LIBPRSTRMS = -lprstrms$(MOD_MAJOR_VERSION)_shr +else +LDOPTS += -brtl +EXTRA_LIBS = -ldl +endif +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +# CC on SunOS 5.4 and 5.5.x need to link with -lthread or -lpthread +# (or use the -mt switch) even though we already linked with these +# system libraries when we built libnspr.so. +ifdef USE_PTHREADS +EXTRA_LIBS = -lpthread +else +EXTRA_LIBS = -lthread +endif # USE_PTHREADS +endif # NS_USE_GCC +endif # 4.1.3_U1 +endif # SunOS + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a +LIBPRSTRMS = $(dist_libdir)/libprstrms$(MOD_MAJOR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +#export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPRSTRMS), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPRSTRMS) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(EXEFLAGS) $(LDOPTS) $< $(LIBPR) $(LIBPRSTRMS) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CCC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPRSTRMS) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + +testlinker: + echo $(LINK) diff --git a/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp new file mode 100644 index 00000000..6e8b8665 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/prstreams/tests/testprstrm/testprstrm.cpp @@ -0,0 +1,204 @@ +/* -*- 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 "prinit.h" +#include "prstrms.h" +#include "prio.h" +#include +#include +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#include +#include +#endif + +const unsigned int MaxCnt = 1; + +void threadwork(void *mytag); + + +typedef struct threadarg { + void *mytag; +} threadarg; + +void +#ifdef XP_OS2_VACPP +_Optlink +#endif +threadmain(void *mytag) +{ + threadarg arg; + + arg.mytag = mytag; + + threadwork(&arg); +} + + +void +threadwork(void *_arg) +{ + threadarg *arg = (threadarg *)_arg; + unsigned int i; + + char fname1[256]; + char fname2[256]; + + strcpy(fname1, (char *)arg->mytag); + strcpy(fname2, (char *)arg->mytag); + strcat(fname2, "2"); + PR_Delete(fname1); + PR_Delete(fname2); + + PRfilebuf *fb[MaxCnt]; + PRifstream *ifs[MaxCnt]; + PRofstream *ofs[MaxCnt]; + int mode = 0; +#ifdef XP_UNIX + mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IRGRP|S_IWOTH|S_IROTH; +#endif + + // + // Allocate a bunch + cout << "Testing unused filebufs ----------------" << endl; + for (i=0; i < MaxCnt; i++){ + fb[i] = new PRfilebuf; + } + // Delete them + for (i=0; i < MaxCnt; i++){ + delete fb[i]; + } + cout << "Unused filebufs complete ---------------" << endl; + + // + // Allocate a bunch + cout << "Testing unused ifstream -----------------" << endl; + for (i=0; i < MaxCnt; i++){ + ifs[i] = new PRifstream; + } + // + // Delete them + for (i=0; i < MaxCnt; i++){ + delete ifs[i]; + } + cout << "Unused ifstream complete ----------------" << endl; + // + // Allocate a bunch + cout << "Testing unused ofstream -----------------" << endl; + for (i=0; i < MaxCnt; i++){ + ofs[i] = new PRofstream; + } + for (i=0; i < MaxCnt; i++){ + *(ofs[i]) << "A"; // Write a bit + delete ofs[i]; // Delete it. + } + cout << "Unused ofstream complete ----------------" << endl; + + cout << "Testing use of ofstream 1 (extra filebuf allocated) ---------" << endl; + PRofstream *aos = new PRofstream(fname1, ios::out|ios::ate, mode); + for (i=0; i < MaxCnt; i++){ + for (int j=0; j < 8192; j++) + *aos << "AaBbCcDdEeFfGg" << endl; + fb[i] = new PRfilebuf; // Allocate as we go to hack at the heap + } + // + // Delete the extra foo we allocated + for (i=0; i < MaxCnt; i++){ + delete fb[i]; + } + aos->flush(); // Explicit flush + delete aos; + cout << "Testing use of ofstream 1 complete (extra filebuf deleted) --" << endl; + cout << "Testing use of ofstream 2 (extra filebuf allocated) ---------" << endl; + PRofstream *aos2 = new PRofstream(fname2, ios::out, mode); + + for (i=0; i < MaxCnt; i++){ + *aos2 << "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + } + // Force flushing in the dtor + delete aos2; + cout << "Testing use of ofstream 2 complete (extra filebuf deleted) --" << endl; + char line[1024]; + cout << "Testing use of ifstream 1 (stack allocation) -------------" << endl; + PRifstream ais(fname1); + for (i=0; i < MaxCnt; i++){ + ais >> line; + } + cout << "Testing use of ifstream 1 complete -----------------------" << endl; + cout << "Testing use of ifstream 2 ----------------------" << endl; + PRifstream *ais2 = new PRifstream(fname2); + char achar; + for (i=0; i < MaxCnt*10; i++){ + *ais2 >> achar; + } + delete ais2; + cout << "Testing use of ifstream 2 complete -------------" << endl; +} + +#define STACKSIZE 1024*1024 +int +main(int argc, char **argv) +{ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 256); + threadmain("TestFile"); + PRThread *thr1 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile1", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + PRThread *thr2 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile2", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + + PRThread *thr3 = PR_CreateThread(PR_SYSTEM_THREAD, + threadmain, + (void *)"TestFile3", + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + STACKSIZE); + PR_JoinThread(thr1); + PR_JoinThread(thr2); + PR_JoinThread(thr3); + return 0; +} + diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/.cvsignore b/src/libs/xpcom18a4/nsprpub/lib/tests/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/Makefile.in b/src/libs/xpcom18a4/nsprpub/lib/tests/Makefile.in new file mode 100644 index 00000000..8c3dc9a8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/Makefile.in @@ -0,0 +1,259 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_ARCH), WINNT) +# DIRS = windows +endif + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CSRCS = \ + arena.c \ + string.c \ + base64t.c + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +CSRCS += arena.c +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPLC = -lplc$(MOD_MAJOR_VERSION) +LIBPLDS = -lplds$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + ifeq ($(OS_TARGET), WIN95) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLC= $(dist_libdir)/plc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLC= $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(dist_libdir)/libplds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + endif +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO /S:32768 + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + LIBPLDS= $(dist_libdir)/plds$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + else + LDOPTS += -Zomf -Zlinker /PM:VIO + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(dist_libdir) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -lpthread +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr +LIBPLC = -lplc$(MOD_MAJOR_VERSION)_shr +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +endif +endif + +# SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, +# even though we already linked with these system libraries +# when we built libnspr.so. +ifeq ($(OS_RELEASE), 5.4) +EXTRA_LIBS = -lthread +endif + +ifeq ($(OS_RELEASE), 5.5) +ifdef USE_PTHREADS +EXTRA_LIBS = -lpthread +else +EXTRA_LIBS = -lthread +endif +endif +endif # SunOS + +ifeq ($(OS_ARCH), NCR) +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket -lnsl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPLC) $(LIBPLDS) $(LIBPR) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(EXEFLAGS) $(LDOPTS) $< $(LIBPLC) $(LIBPLDS) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBPLDS) $(LIBPR) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + + + diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/arena.c b/src/libs/xpcom18a4/nsprpub/lib/tests/arena.c new file mode 100644 index 00000000..9c74479c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/arena.c @@ -0,0 +1,401 @@ +/* -*- 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 ***** */ + +/* +** File: arena.c +** Description: Testing arenas +** +*/ + +#include +#include +#include +#include "nspr.h" +#include "plarena.h" +#include "plgetopt.h" + +PRLogModuleInfo *tLM; +PRIntn threadCount = 0; +PRMonitor *tMon; +PRBool failed_already = PR_FALSE; + +/* Arguments from the command line with default values */ +PRIntn debug_mode = 0; +PRIntn poolMin = 4096; +PRIntn poolMax = (100 * 4096); +PRIntn arenaMin = 40; +PRIntn arenaMax = (100 * 40); +PRIntn stressIterations = 15; +PRIntn maxAlloc = (1024 * 1024); +PRIntn stressThreads = 4; + +void DumpAll( void ) +{ + return; +} + +/* +** Test Arena allocation. +*/ +static void ArenaAllocate( void ) +{ + PLArenaPool ap; + void *ptr; + PRInt32 i; + + PL_InitArenaPool( &ap, "AllocArena", 2048, sizeof(double)); + PR_LOG( tLM, PR_LOG_DEBUG, ("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + + for( i = 0; i < 150; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + PR_LOG( tLM, PR_LOG_DEBUG,( + "AA -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + PL_FreeArenaPool( &ap ); + + for( i = 0; i < 221; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d", + &ap, ap.first, ap.current, ap.arenasize )); + PR_LOG( tLM, PR_LOG_DEBUG,( + "AA -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + PL_FreeArenaPool( &ap ); + + return; +} /* end ArenaGrow() */ +/* +** Test Arena grow. +*/ +static void ArenaGrow( void ) +{ + PLArenaPool ap; + void *ptr; + PRInt32 i; + + PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + + PR_LOG( tLM, PR_LOG_DEBUG, ("Before growth -- Pool: %p. alloc: %p ", &ap, ptr )); + + for( i = 0; i < 10; i++ ) + { + PL_ARENA_GROW( ptr, &ap, 512, 7000 ); + PR_LOG( tLM, PR_LOG_DEBUG, ("After growth -- Pool: %p. alloc: %p ", &ap, ptr )); + } + + + return; +} /* end ArenaGrow() */ + + +/* +** Test arena Mark and Release. +*/ +static void MarkAndRelease( void ) +{ + PLArenaPool ap; + void *ptr = NULL; + void *mark0, *mark1; + PRIntn i; + + PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double)); + mark0 = PL_ARENA_MARK( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0 )); + + for( i = 0; i < 201; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + mark1 = PL_ARENA_MARK( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1 )); + + + for( i = 0; i < 225; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + PL_ARENA_RELEASE( &ap, mark1 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d", + mark1, &ap, ap.first, ap.current, ap.arenasize )); + + for( i = 0; i < 20; i++ ) + { + PL_ARENA_ALLOCATE( ptr, &ap, 512 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + } + + PL_ARENA_RELEASE( &ap, mark1 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_ARENA_RELEASE( &ap, mark0 ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_FreeArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + PL_FinishArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, + ("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p", + &ap, ap.first.next, ap.current, ap.arenasize, ptr )); + + return; +} /* end MarkAndRelease() */ + +/* +** RandSize() returns a random number in the range +** min..max, rounded to the next doubleword +** +*/ +static PRIntn RandSize( PRIntn min, PRIntn max ) +{ + PRIntn sz = (rand() % (max -min)) + min + sizeof(double); + + sz &= ~sizeof(double)-1; + + return(sz); +} + + +/* +** StressThread() +** A bunch of these beat on individual arenas +** This tests the free_list protection. +** +*/ +static void PR_CALLBACK StressThread( void *arg ) +{ + PLArenaPool ap; + PRIntn i; + PRIntn sz; + void *ptr; + PRThread *tp = PR_GetCurrentThread(); + + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread())); + PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double)); + + for ( i = 0; i < stressIterations; i++ ) + { + PRIntn allocated = 0; + + while ( allocated < maxAlloc ) + { + sz = RandSize( arenaMin, arenaMax ); + PL_ARENA_ALLOCATE( ptr, &ap, sz ); + if ( ptr == NULL ) + { + PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated)); + break; + } + allocated += sz; + } + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp)); + PL_FreeArenaPool( &ap ); + } + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp)); + PL_FinishArenaPool( &ap ); + PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp)); + + /* That's all folks! let's quit */ + PR_EnterMonitor(tMon); + threadCount--; + PR_Notify(tMon); + PR_ExitMonitor(tMon); + return; +} + +/* +** Stress() +** Flog the hell out of arenas multi-threaded. +** Do NOT pass an individual arena to another thread. +** +*/ +static void Stress( void ) +{ + PRThread *tt; + PRIntn i; + + tMon = PR_NewMonitor(); + + for ( i = 0 ; i < stressThreads ; i++ ) + { + PR_EnterMonitor(tMon); + tt = PR_CreateThread(PR_USER_THREAD, + StressThread, + NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + threadCount++; + PR_ExitMonitor(tMon); + } + + /* Wait for all threads to exit */ + PR_EnterMonitor(tMon); + while ( threadCount != 0 ) + { + PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(tMon); + PR_DestroyMonitor(tMon); + + return; +} /* end Stress() */ + +/* +** EvaluateResults() +** uses failed_already to display results and set program +** exit code. +*/ +static PRIntn EvaluateResults(void) +{ + PRIntn rc = 0; + + if ( failed_already == PR_TRUE ) + { + PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n")); + rc =1; + } + else + { + PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n")); + } + return(rc); +} /* EvaluateResults() */ + +void Help( void ) +{ + printf("arena [options]\n"); + printf("where options are:\n"); + printf("-p minimum size of an arena pool. Default(%d)\n", poolMin); + printf("-P maximum size of an arena pool. Default(%d)\n", poolMax); + printf("-a minimum size of an arena allocation. Default(%d)\n", arenaMin); + printf("-A maximum size of an arena allocation. Default(%d)\n", arenaMax); + printf("-i number of iterations in a stress thread. Default(%d)\n", stressIterations); + printf("-s maximum allocation for a single stress thread. Default(%d)\n", maxAlloc); + printf("-t number of stress threads. Default(%d)\n", stressThreads ); + printf("-d enable debug mode\n"); + printf("\n"); + exit(1); +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'a': /* arena Min size */ + arenaMin = atol( opt->value ); + break; + case 'A': /* arena Max size */ + arenaMax = atol( opt->value ); + break; + case 'p': /* pool Min size */ + poolMin = atol( opt->value ); + break; + case 'P': /* pool Max size */ + poolMax = atol( opt->value ); + break; + case 'i': /* Iterations in stress tests */ + stressIterations = atol( opt->value ); + break; + case 's': /* storage to get per iteration */ + maxAlloc = atol( opt->value ); + break; + case 't': /* Number of stress threads to create */ + stressThreads = atol( opt->value ); + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'h': /* help */ + default: + Help(); + } /* end switch() */ + } /* end while() */ + PL_DestroyOptState(opt); + + srand( (unsigned)time( NULL ) ); /* seed random number generator */ + tLM = PR_NewLogModule("testcase"); + + +#if 0 + ArenaAllocate(); + ArenaGrow(); +#endif + + MarkAndRelease(); + + Stress(); + + return(EvaluateResults()); +} /* end main() */ + +/* arena.c */ diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/base64t.c b/src/libs/xpcom18a4/nsprpub/lib/tests/base64t.c new file mode 100644 index 00000000..c3c48813 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/base64t.c @@ -0,0 +1,3047 @@ +/* -*- 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 "plbase64.h" +#include "plstr.h" +#include "nspr.h" + +#include + +static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* PL_Base64Encode, single characters */ +PRBool test_001(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 001 (PL_Base64Encode, single characters) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Encode((char *)plain, 1, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, cypher, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, double characters */ +PRBool test_002(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 002 (PL_Base64Encode, double characters) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Encode((char *)plain, 2, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, cypher, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, triple characters */ +PRBool test_003(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 003 (PL_Base64Encode, triple characters) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Encode((char *)plain, 3, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)cypher, result, 4) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, e, f, cypher, result); + return PR_FALSE; + } + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + + static struct + { + const char *plaintext; + const char *cyphertext; + } array[] = + { + /* Cyphertexts generated with uuenview 0.5.13 */ + { " ", "IA==" }, + { ".", "Lg==" }, + { "/", "Lw==" }, + { "C", "Qw==" }, + { "H", "SA==" }, + { "S", "Uw==" }, + { "^", "Xg==" }, + { "a", "YQ==" }, + { "o", "bw==" }, + { "t", "dA==" }, + + { "AB", "QUI=" }, + { "AH", "QUg=" }, + { "AQ", "QVE=" }, + { "BD", "QkQ=" }, + { "CR", "Q1I=" }, + { "CS", "Q1M=" }, + { "DB", "REI=" }, + { "DC", "REM=" }, + { "EK", "RUs=" }, + { "ET", "RVQ=" }, + { "IM", "SU0=" }, + { "JR", "SlI=" }, + { "LO", "TE8=" }, + { "LW", "TFc=" }, + { "ML", "TUw=" }, + { "SB", "U0I=" }, + { "TO", "VE8=" }, + { "VS", "VlM=" }, + { "WP", "V1A=" }, + /* legitimate two-letter words */ + { "ad", "YWQ=" }, + { "ah", "YWg=" }, + { "am", "YW0=" }, + { "an", "YW4=" }, + { "as", "YXM=" }, + { "at", "YXQ=" }, + { "ax", "YXg=" }, + { "be", "YmU=" }, + { "by", "Ynk=" }, + { "do", "ZG8=" }, + { "go", "Z28=" }, + { "he", "aGU=" }, + { "hi", "aGk=" }, + { "if", "aWY=" }, + { "in", "aW4=" }, + { "is", "aXM=" }, + { "it", "aXQ=" }, + { "me", "bWU=" }, + { "my", "bXk=" }, + { "no", "bm8=" }, + { "of", "b2Y=" }, + { "on", "b24=" }, + { "or", "b3I=" }, + { "ox", "b3g=" }, + { "so", "c28=" }, + { "to", "dG8=" }, + { "up", "dXA=" }, + { "us", "dXM=" }, + { "we", "d2U=" }, + /* all three-letter entries in /usr/dict/words */ + { "1st", "MXN0" }, + { "2nd", "Mm5k" }, + { "3rd", "M3Jk" }, + { "4th", "NHRo" }, + { "5th", "NXRo" }, + { "6th", "NnRo" }, + { "7th", "N3Ro" }, + { "8th", "OHRo" }, + { "9th", "OXRo" }, + { "AAA", "QUFB" }, + { "AAU", "QUFV" }, + { "ABA", "QUJB" }, + { "abc", "YWJj" }, + { "Abe", "QWJl" }, + { "Abo", "QWJv" }, + { "ace", "YWNl" }, + { "ACM", "QUNN" }, + { "ACS", "QUNT" }, + { "act", "YWN0" }, + { "Ada", "QWRh" }, + { "add", "YWRk" }, + { "ado", "YWRv" }, + { "aft", "YWZ0" }, + { "age", "YWdl" }, + { "ago", "YWdv" }, + { "aid", "YWlk" }, + { "ail", "YWls" }, + { "aim", "YWlt" }, + { "air", "YWly" }, + { "ala", "YWxh" }, + { "alb", "YWxi" }, + { "ale", "YWxl" }, + { "Ali", "QWxp" }, + { "all", "YWxs" }, + { "alp", "YWxw" }, + { "A&M", "QSZN" }, + { "AMA", "QU1B" }, + { "ami", "YW1p" }, + { "amp", "YW1w" }, + { "Amy", "QW15" }, + { "amy", "YW15" }, + { "ana", "YW5h" }, + { "and", "YW5k" }, + { "ani", "YW5p" }, + { "Ann", "QW5u" }, + { "ant", "YW50" }, + { "any", "YW55" }, + { "A&P", "QSZQ" }, + { "ape", "YXBl" }, + { "Apr", "QXBy" }, + { "APS", "QVBT" }, + { "apt", "YXB0" }, + { "arc", "YXJj" }, + { "are", "YXJl" }, + { "ark", "YXJr" }, + { "arm", "YXJt" }, + { "art", "YXJ0" }, + { "a's", "YSdz" }, + { "ash", "YXNo" }, + { "ask", "YXNr" }, + { "ass", "YXNz" }, + { "ate", "YXRl" }, + { "Aug", "QXVn" }, + { "auk", "YXVr" }, + { "Ave", "QXZl" }, + { "awe", "YXdl" }, + { "awl", "YXds" }, + { "awn", "YXdu" }, + { "axe", "YXhl" }, + { "aye", "YXll" }, + { "bad", "YmFk" }, + { "bag", "YmFn" }, + { "bah", "YmFo" }, + { "bam", "YmFt" }, + { "ban", "YmFu" }, + { "bar", "YmFy" }, + { "bat", "YmF0" }, + { "bay", "YmF5" }, + { "bed", "YmVk" }, + { "bee", "YmVl" }, + { "beg", "YmVn" }, + { "bel", "YmVs" }, + { "Ben", "QmVu" }, + { "bet", "YmV0" }, + { "bey", "YmV5" }, + { "bib", "Ymli" }, + { "bid", "Ymlk" }, + { "big", "Ymln" }, + { "bin", "Ymlu" }, + { "bit", "Yml0" }, + { "biz", "Yml6" }, + { "BMW", "Qk1X" }, + { "boa", "Ym9h" }, + { "bob", "Ym9i" }, + { "bog", "Ym9n" }, + { "bon", "Ym9u" }, + { "boo", "Ym9v" }, + { "bop", "Ym9w" }, + { "bow", "Ym93" }, + { "box", "Ym94" }, + { "boy", "Ym95" }, + { "b's", "Yidz" }, + { "BTL", "QlRM" }, + { "BTU", "QlRV" }, + { "bub", "YnVi" }, + { "bud", "YnVk" }, + { "bug", "YnVn" }, + { "bum", "YnVt" }, + { "bun", "YnVu" }, + { "bus", "YnVz" }, + { "but", "YnV0" }, + { "buy", "YnV5" }, + { "bye", "Ynll" }, + { "cab", "Y2Fi" }, + { "Cal", "Q2Fs" }, + { "cam", "Y2Ft" }, + { "can", "Y2Fu" }, + { "cap", "Y2Fw" }, + { "car", "Y2Fy" }, + { "cat", "Y2F0" }, + { "caw", "Y2F3" }, + { "CBS", "Q0JT" }, + { "CDC", "Q0RD" }, + { "CEQ", "Q0VR" }, + { "chi", "Y2hp" }, + { "CIA", "Q0lB" }, + { "cit", "Y2l0" }, + { "cod", "Y29k" }, + { "cog", "Y29n" }, + { "col", "Y29s" }, + { "con", "Y29u" }, + { "coo", "Y29v" }, + { "cop", "Y29w" }, + { "cos", "Y29z" }, + { "cot", "Y290" }, + { "cow", "Y293" }, + { "cox", "Y294" }, + { "coy", "Y295" }, + { "CPA", "Q1BB" }, + { "cpu", "Y3B1" }, + { "CRT", "Q1JU" }, + { "cry", "Y3J5" }, + { "c's", "Yydz" }, + { "cub", "Y3Vi" }, + { "cud", "Y3Vk" }, + { "cue", "Y3Vl" }, + { "cup", "Y3Vw" }, + { "cur", "Y3Vy" }, + { "cut", "Y3V0" }, + { "dab", "ZGFi" }, + { "dad", "ZGFk" }, + { "dam", "ZGFt" }, + { "Dan", "RGFu" }, + { "Dar", "RGFy" }, + { "day", "ZGF5" }, + { "Dec", "RGVj" }, + { "Dee", "RGVl" }, + { "Del", "RGVs" }, + { "den", "ZGVu" }, + { "Des", "RGVz" }, + { "dew", "ZGV3" }, + { "dey", "ZGV5" }, + { "did", "ZGlk" }, + { "die", "ZGll" }, + { "dig", "ZGln" }, + { "dim", "ZGlt" }, + { "din", "ZGlu" }, + { "dip", "ZGlw" }, + { "Dis", "RGlz" }, + { "DNA", "RE5B" }, + { "DOD", "RE9E" }, + { "doe", "ZG9l" }, + { "dog", "ZG9n" }, + { "don", "ZG9u" }, + { "dot", "ZG90" }, + { "Dow", "RG93" }, + { "dry", "ZHJ5" }, + { "d's", "ZCdz" }, + { "dub", "ZHVi" }, + { "dud", "ZHVk" }, + { "due", "ZHVl" }, + { "dug", "ZHVn" }, + { "dun", "ZHVu" }, + { "dye", "ZHll" }, + { "ear", "ZWFy" }, + { "eat", "ZWF0" }, + { "ebb", "ZWJi" }, + { "EDT", "RURU" }, + { "eel", "ZWVs" }, + { "eft", "ZWZ0" }, + { "e.g", "ZS5n" }, + { "egg", "ZWdn" }, + { "ego", "ZWdv" }, + { "eke", "ZWtl" }, + { "Eli", "RWxp" }, + { "elk", "ZWxr" }, + { "ell", "ZWxs" }, + { "elm", "ZWxt" }, + { "Ely", "RWx5" }, + { "end", "ZW5k" }, + { "Eng", "RW5n" }, + { "EPA", "RVBB" }, + { "era", "ZXJh" }, + { "ere", "ZXJl" }, + { "erg", "ZXJn" }, + { "err", "ZXJy" }, + { "e's", "ZSdz" }, + { "EST", "RVNU" }, + { "eta", "ZXRh" }, + { "etc", "ZXRj" }, + { "Eva", "RXZh" }, + { "eve", "ZXZl" }, + { "ewe", "ZXdl" }, + { "eye", "ZXll" }, + { "FAA", "RkFB" }, + { "fad", "ZmFk" }, + { "fag", "ZmFn" }, + { "fan", "ZmFu" }, + { "far", "ZmFy" }, + { "fat", "ZmF0" }, + { "fay", "ZmF5" }, + { "FBI", "RkJJ" }, + { "FCC", "RkND" }, + { "FDA", "RkRB" }, + { "Feb", "RmVi" }, + { "fed", "ZmVk" }, + { "fee", "ZmVl" }, + { "few", "ZmV3" }, + { "fib", "Zmli" }, + { "fig", "Zmln" }, + { "fin", "Zmlu" }, + { "fir", "Zmly" }, + { "fit", "Zml0" }, + { "fix", "Zml4" }, + { "Flo", "Rmxv" }, + { "flu", "Zmx1" }, + { "fly", "Zmx5" }, + { "FMC", "Rk1D" }, + { "fob", "Zm9i" }, + { "foe", "Zm9l" }, + { "fog", "Zm9n" }, + { "fop", "Zm9w" }, + { "for", "Zm9y" }, + { "fox", "Zm94" }, + { "FPC", "RlBD" }, + { "fro", "ZnJv" }, + { "fry", "ZnJ5" }, + { "f's", "Zidz" }, + { "FTC", "RlRD" }, + { "fum", "ZnVt" }, + { "fun", "ZnVu" }, + { "fur", "ZnVy" }, + { "gab", "Z2Fi" }, + { "gad", "Z2Fk" }, + { "gag", "Z2Fn" }, + { "gal", "Z2Fs" }, + { "gam", "Z2Ft" }, + { "GAO", "R0FP" }, + { "gap", "Z2Fw" }, + { "gar", "Z2Fy" }, + { "gas", "Z2Fz" }, + { "gay", "Z2F5" }, + { "gee", "Z2Vl" }, + { "gel", "Z2Vs" }, + { "gem", "Z2Vt" }, + { "get", "Z2V0" }, + { "gig", "Z2ln" }, + { "Gil", "R2ls" }, + { "gin", "Z2lu" }, + { "GMT", "R01U" }, + { "GNP", "R05Q" }, + { "gnu", "Z251" }, + { "Goa", "R29h" }, + { "gob", "Z29i" }, + { "god", "Z29k" }, + { "gog", "Z29n" }, + { "GOP", "R09Q" }, + { "got", "Z290" }, + { "GPO", "R1BP" }, + { "g's", "Zydz" }, + { "GSA", "R1NB" }, + { "gum", "Z3Vt" }, + { "gun", "Z3Vu" }, + { "Gus", "R3Vz" }, + { "gut", "Z3V0" }, + { "guy", "Z3V5" }, + { "gym", "Z3lt" }, + { "gyp", "Z3lw" }, + { "had", "aGFk" }, + { "Hal", "SGFs" }, + { "ham", "aGFt" }, + { "Han", "SGFu" }, + { "hap", "aGFw" }, + { "hat", "aGF0" }, + { "haw", "aGF3" }, + { "hay", "aGF5" }, + { "hem", "aGVt" }, + { "hen", "aGVu" }, + { "her", "aGVy" }, + { "hew", "aGV3" }, + { "hex", "aGV4" }, + { "hey", "aGV5" }, + { "hid", "aGlk" }, + { "him", "aGlt" }, + { "hip", "aGlw" }, + { "his", "aGlz" }, + { "hit", "aGl0" }, + { "hob", "aG9i" }, + { "hoc", "aG9j" }, + { "hoe", "aG9l" }, + { "hog", "aG9n" }, + { "hoi", "aG9p" }, + { "Hom", "SG9t" }, + { "hop", "aG9w" }, + { "hot", "aG90" }, + { "how", "aG93" }, + { "hoy", "aG95" }, + { "h's", "aCdz" }, + { "hub", "aHVi" }, + { "hue", "aHVl" }, + { "hug", "aHVn" }, + { "huh", "aHVo" }, + { "hum", "aHVt" }, + { "Hun", "SHVu" }, + { "hut", "aHV0" }, + { "Ian", "SWFu" }, + { "IBM", "SUJN" }, + { "Ibn", "SWJu" }, + { "ICC", "SUND" }, + { "ice", "aWNl" }, + { "icy", "aWN5" }, + { "I'd", "SSdk" }, + { "Ida", "SWRh" }, + { "i.e", "aS5l" }, + { "iii", "aWlp" }, + { "Ike", "SWtl" }, + { "ill", "aWxs" }, + { "I'm", "SSdt" }, + { "imp", "aW1w" }, + { "Inc", "SW5j" }, + { "ink", "aW5r" }, + { "inn", "aW5u" }, + { "ion", "aW9u" }, + { "Ira", "SXJh" }, + { "ire", "aXJl" }, + { "irk", "aXJr" }, + { "IRS", "SVJT" }, + { "i's", "aSdz" }, + { "Ito", "SXRv" }, + { "ITT", "SVRU" }, + { "ivy", "aXZ5" }, + { "jab", "amFi" }, + { "jag", "amFn" }, + { "jam", "amFt" }, + { "Jan", "SmFu" }, + { "jar", "amFy" }, + { "jaw", "amF3" }, + { "jay", "amF5" }, + { "Jed", "SmVk" }, + { "jet", "amV0" }, + { "Jew", "SmV3" }, + { "jig", "amln" }, + { "Jim", "Smlt" }, + { "job", "am9i" }, + { "Joe", "Sm9l" }, + { "jog", "am9n" }, + { "Jon", "Sm9u" }, + { "jot", "am90" }, + { "joy", "am95" }, + { "j's", "aidz" }, + { "jug", "anVn" }, + { "jut", "anV0" }, + { "Kay", "S2F5" }, + { "keg", "a2Vn" }, + { "ken", "a2Vu" }, + { "key", "a2V5" }, + { "kid", "a2lk" }, + { "Kim", "S2lt" }, + { "kin", "a2lu" }, + { "kit", "a2l0" }, + { "k's", "aydz" }, + { "lab", "bGFi" }, + { "lac", "bGFj" }, + { "lad", "bGFk" }, + { "lag", "bGFn" }, + { "lam", "bGFt" }, + { "Lao", "TGFv" }, + { "lap", "bGFw" }, + { "law", "bGF3" }, + { "lax", "bGF4" }, + { "lay", "bGF5" }, + { "lea", "bGVh" }, + { "led", "bGVk" }, + { "lee", "bGVl" }, + { "leg", "bGVn" }, + { "Len", "TGVu" }, + { "Leo", "TGVv" }, + { "let", "bGV0" }, + { "Lev", "TGV2" }, + { "Lew", "TGV3" }, + { "lew", "bGV3" }, + { "lid", "bGlk" }, + { "lie", "bGll" }, + { "lim", "bGlt" }, + { "Lin", "TGlu" }, + { "lip", "bGlw" }, + { "lit", "bGl0" }, + { "Liz", "TGl6" }, + { "lob", "bG9i" }, + { "log", "bG9n" }, + { "lop", "bG9w" }, + { "Los", "TG9z" }, + { "lot", "bG90" }, + { "Lou", "TG91" }, + { "low", "bG93" }, + { "loy", "bG95" }, + { "l's", "bCdz" }, + { "LSI", "TFNJ" }, + { "Ltd", "THRk" }, + { "LTV", "TFRW" }, + { "lug", "bHVn" }, + { "lux", "bHV4" }, + { "lye", "bHll" }, + { "Mac", "TWFj" }, + { "mad", "bWFk" }, + { "Mae", "TWFl" }, + { "man", "bWFu" }, + { "Mao", "TWFv" }, + { "map", "bWFw" }, + { "mar", "bWFy" }, + { "mat", "bWF0" }, + { "maw", "bWF3" }, + { "Max", "TWF4" }, + { "max", "bWF4" }, + { "may", "bWF5" }, + { "MBA", "TUJB" }, + { "Meg", "TWVn" }, + { "Mel", "TWVs" }, + { "men", "bWVu" }, + { "met", "bWV0" }, + { "mew", "bWV3" }, + { "mid", "bWlk" }, + { "mig", "bWln" }, + { "min", "bWlu" }, + { "MIT", "TUlU" }, + { "mix", "bWl4" }, + { "mob", "bW9i" }, + { "Moe", "TW9l" }, + { "moo", "bW9v" }, + { "mop", "bW9w" }, + { "mot", "bW90" }, + { "mow", "bW93" }, + { "MPH", "TVBI" }, + { "Mrs", "TXJz" }, + { "m's", "bSdz" }, + { "mud", "bXVk" }, + { "mug", "bXVn" }, + { "mum", "bXVt" }, + { "nab", "bmFi" }, + { "nag", "bmFn" }, + { "Nan", "TmFu" }, + { "nap", "bmFw" }, + { "Nat", "TmF0" }, + { "nay", "bmF5" }, + { "NBC", "TkJD" }, + { "NBS", "TkJT" }, + { "NCO", "TkNP" }, + { "NCR", "TkNS" }, + { "Ned", "TmVk" }, + { "nee", "bmVl" }, + { "net", "bmV0" }, + { "new", "bmV3" }, + { "nib", "bmli" }, + { "NIH", "TklI" }, + { "nil", "bmls" }, + { "nip", "bmlw" }, + { "nit", "bml0" }, + { "NNE", "Tk5F" }, + { "NNW", "Tk5X" }, + { "nob", "bm9i" }, + { "nod", "bm9k" }, + { "non", "bm9u" }, + { "nor", "bm9y" }, + { "not", "bm90" }, + { "Nov", "Tm92" }, + { "now", "bm93" }, + { "NRC", "TlJD" }, + { "n's", "bidz" }, + { "NSF", "TlNG" }, + { "nun", "bnVu" }, + { "nut", "bnV0" }, + { "NYC", "TllD" }, + { "NYU", "TllV" }, + { "oaf", "b2Fm" }, + { "oak", "b2Fr" }, + { "oar", "b2Fy" }, + { "oat", "b2F0" }, + { "Oct", "T2N0" }, + { "odd", "b2Rk" }, + { "ode", "b2Rl" }, + { "off", "b2Zm" }, + { "oft", "b2Z0" }, + { "ohm", "b2ht" }, + { "oil", "b2ls" }, + { "old", "b2xk" }, + { "one", "b25l" }, + { "opt", "b3B0" }, + { "orb", "b3Ji" }, + { "ore", "b3Jl" }, + { "Orr", "T3Jy" }, + { "o's", "bydz" }, + { "Ott", "T3R0" }, + { "our", "b3Vy" }, + { "out", "b3V0" }, + { "ova", "b3Zh" }, + { "owe", "b3dl" }, + { "owl", "b3ds" }, + { "own", "b3du" }, + { "pad", "cGFk" }, + { "pal", "cGFs" }, + { "Pam", "UGFt" }, + { "pan", "cGFu" }, + { "pap", "cGFw" }, + { "par", "cGFy" }, + { "pat", "cGF0" }, + { "paw", "cGF3" }, + { "pax", "cGF4" }, + { "pay", "cGF5" }, + { "Paz", "UGF6" }, + { "PBS", "UEJT" }, + { "PDP", "UERQ" }, + { "pea", "cGVh" }, + { "pee", "cGVl" }, + { "peg", "cGVn" }, + { "pen", "cGVu" }, + { "pep", "cGVw" }, + { "per", "cGVy" }, + { "pet", "cGV0" }, + { "pew", "cGV3" }, + { "PhD", "UGhE" }, + { "phi", "cGhp" }, + { "pie", "cGll" }, + { "pig", "cGln" }, + { "pin", "cGlu" }, + { "pip", "cGlw" }, + { "pit", "cGl0" }, + { "ply", "cGx5" }, + { "pod", "cG9k" }, + { "Poe", "UG9l" }, + { "poi", "cG9p" }, + { "pol", "cG9s" }, + { "pop", "cG9w" }, + { "pot", "cG90" }, + { "pow", "cG93" }, + { "ppm", "cHBt" }, + { "pro", "cHJv" }, + { "pry", "cHJ5" }, + { "p's", "cCdz" }, + { "psi", "cHNp" }, + { "PTA", "UFRB" }, + { "pub", "cHVi" }, + { "PUC", "UFVD" }, + { "pug", "cHVn" }, + { "pun", "cHVu" }, + { "pup", "cHVw" }, + { "pus", "cHVz" }, + { "put", "cHV0" }, + { "PVC", "UFZD" }, + { "QED", "UUVE" }, + { "q's", "cSdz" }, + { "qua", "cXVh" }, + { "quo", "cXVv" }, + { "Rae", "UmFl" }, + { "rag", "cmFn" }, + { "raj", "cmFq" }, + { "ram", "cmFt" }, + { "ran", "cmFu" }, + { "rap", "cmFw" }, + { "rat", "cmF0" }, + { "raw", "cmF3" }, + { "ray", "cmF5" }, + { "RCA", "UkNB" }, + { "R&D", "UiZE" }, + { "reb", "cmVi" }, + { "red", "cmVk" }, + { "rep", "cmVw" }, + { "ret", "cmV0" }, + { "rev", "cmV2" }, + { "Rex", "UmV4" }, + { "rho", "cmhv" }, + { "rib", "cmli" }, + { "rid", "cmlk" }, + { "rig", "cmln" }, + { "rim", "cmlt" }, + { "Rio", "Umlv" }, + { "rip", "cmlw" }, + { "RNA", "Uk5B" }, + { "rob", "cm9i" }, + { "rod", "cm9k" }, + { "roe", "cm9l" }, + { "Ron", "Um9u" }, + { "rot", "cm90" }, + { "row", "cm93" }, + { "Roy", "Um95" }, + { "RPM", "UlBN" }, + { "r's", "cidz" }, + { "rub", "cnVi" }, + { "rue", "cnVl" }, + { "rug", "cnVn" }, + { "rum", "cnVt" }, + { "run", "cnVu" }, + { "rut", "cnV0" }, + { "rye", "cnll" }, + { "sac", "c2Fj" }, + { "sad", "c2Fk" }, + { "sag", "c2Fn" }, + { "Sal", "U2Fs" }, + { "Sam", "U2Ft" }, + { "San", "U2Fu" }, + { "Sao", "U2Fv" }, + { "sap", "c2Fw" }, + { "sat", "c2F0" }, + { "saw", "c2F3" }, + { "sax", "c2F4" }, + { "say", "c2F5" }, + { "Sci", "U2Np" }, + { "SCM", "U0NN" }, + { "sea", "c2Vh" }, + { "sec", "c2Vj" }, + { "see", "c2Vl" }, + { "sen", "c2Vu" }, + { "seq", "c2Vx" }, + { "set", "c2V0" }, + { "sew", "c2V3" }, + { "sex", "c2V4" }, + { "she", "c2hl" }, + { "Shu", "U2h1" }, + { "shy", "c2h5" }, + { "sib", "c2li" }, + { "sic", "c2lj" }, + { "sin", "c2lu" }, + { "sip", "c2lw" }, + { "sir", "c2ly" }, + { "sis", "c2lz" }, + { "sit", "c2l0" }, + { "six", "c2l4" }, + { "ski", "c2tp" }, + { "sky", "c2t5" }, + { "sly", "c2x5" }, + { "sob", "c29i" }, + { "Soc", "U29j" }, + { "sod", "c29k" }, + { "Sol", "U29s" }, + { "son", "c29u" }, + { "sop", "c29w" }, + { "sou", "c291" }, + { "sow", "c293" }, + { "soy", "c295" }, + { "spa", "c3Bh" }, + { "spy", "c3B5" }, + { "Sri", "U3Jp" }, + { "s's", "cydz" }, + { "SSE", "U1NF" }, + { "SST", "U1NU" }, + { "SSW", "U1NX" }, + { "Stu", "U3R1" }, + { "sub", "c3Vi" }, + { "sud", "c3Vk" }, + { "sue", "c3Vl" }, + { "sum", "c3Vt" }, + { "sun", "c3Vu" }, + { "sup", "c3Vw" }, + { "Sus", "U3Vz" }, + { "tab", "dGFi" }, + { "tad", "dGFk" }, + { "tag", "dGFn" }, + { "tam", "dGFt" }, + { "tan", "dGFu" }, + { "tao", "dGFv" }, + { "tap", "dGFw" }, + { "tar", "dGFy" }, + { "tat", "dGF0" }, + { "tau", "dGF1" }, + { "tax", "dGF4" }, + { "tea", "dGVh" }, + { "Ted", "VGVk" }, + { "ted", "dGVk" }, + { "tee", "dGVl" }, + { "Tel", "VGVs" }, + { "ten", "dGVu" }, + { "the", "dGhl" }, + { "thy", "dGh5" }, + { "tic", "dGlj" }, + { "tid", "dGlk" }, + { "tie", "dGll" }, + { "til", "dGls" }, + { "Tim", "VGlt" }, + { "tin", "dGlu" }, + { "tip", "dGlw" }, + { "tit", "dGl0" }, + { "TNT", "VE5U" }, + { "toe", "dG9l" }, + { "tog", "dG9n" }, + { "Tom", "VG9t" }, + { "ton", "dG9u" }, + { "too", "dG9v" }, + { "top", "dG9w" }, + { "tor", "dG9y" }, + { "tot", "dG90" }, + { "tow", "dG93" }, + { "toy", "dG95" }, + { "TRW", "VFJX" }, + { "try", "dHJ5" }, + { "t's", "dCdz" }, + { "TTL", "VFRM" }, + { "TTY", "VFRZ" }, + { "tub", "dHVi" }, + { "tug", "dHVn" }, + { "tum", "dHVt" }, + { "tun", "dHVu" }, + { "TVA", "VFZB" }, + { "TWA", "VFdB" }, + { "two", "dHdv" }, + { "TWX", "VFdY" }, + { "ugh", "dWdo" }, + { "UHF", "VUhG" }, + { "Uri", "VXJp" }, + { "urn", "dXJu" }, + { "U.S", "VS5T" }, + { "u's", "dSdz" }, + { "USA", "VVNB" }, + { "USC", "VVND" }, + { "use", "dXNl" }, + { "USN", "VVNO" }, + { "van", "dmFu" }, + { "vat", "dmF0" }, + { "vee", "dmVl" }, + { "vet", "dmV0" }, + { "vex", "dmV4" }, + { "VHF", "VkhG" }, + { "via", "dmlh" }, + { "vie", "dmll" }, + { "vii", "dmlp" }, + { "vis", "dmlz" }, + { "viz", "dml6" }, + { "von", "dm9u" }, + { "vow", "dm93" }, + { "v's", "didz" }, + { "WAC", "V0FD" }, + { "wad", "d2Fk" }, + { "wag", "d2Fn" }, + { "wah", "d2Fo" }, + { "wan", "d2Fu" }, + { "war", "d2Fy" }, + { "was", "d2Fz" }, + { "wax", "d2F4" }, + { "way", "d2F5" }, + { "web", "d2Vi" }, + { "wed", "d2Vk" }, + { "wee", "d2Vl" }, + { "Wei", "V2Vp" }, + { "wet", "d2V0" }, + { "who", "d2hv" }, + { "why", "d2h5" }, + { "wig", "d2ln" }, + { "win", "d2lu" }, + { "wit", "d2l0" }, + { "woe", "d29l" }, + { "wok", "d29r" }, + { "won", "d29u" }, + { "woo", "d29v" }, + { "wop", "d29w" }, + { "wow", "d293" }, + { "wry", "d3J5" }, + { "w's", "dydz" }, + { "x's", "eCdz" }, + { "yah", "eWFo" }, + { "yak", "eWFr" }, + { "yam", "eWFt" }, + { "yap", "eWFw" }, + { "yaw", "eWF3" }, + { "yea", "eWVh" }, + { "yen", "eWVu" }, + { "yet", "eWV0" }, + { "yin", "eWlu" }, + { "yip", "eWlw" }, + { "yon", "eW9u" }, + { "you", "eW91" }, + { "yow", "eW93" }, + { "y's", "eSdz" }, + { "yuh", "eXVo" }, + { "zag", "emFn" }, + { "Zan", "WmFu" }, + { "zap", "emFw" }, + { "Zen", "WmVu" }, + { "zig", "emln" }, + { "zip", "emlw" }, + { "Zoe", "Wm9l" }, + { "zoo", "em9v" }, + { "z's", "eidz" }, + /* the false rumors file */ + { "\"So when I die, the first thing I will see in heaven is a score list?\"", + "IlNvIHdoZW4gSSBkaWUsIHRoZSBmaXJzdCB0aGluZyBJIHdpbGwgc2VlIGluIGhlYXZlbiBpcyBhIHNjb3JlIGxpc3Q/Ig==" }, + { "1st Law of Hacking: leaving is much more difficult than entering.", + "MXN0IExhdyBvZiBIYWNraW5nOiBsZWF2aW5nIGlzIG11Y2ggbW9yZSBkaWZmaWN1bHQgdGhhbiBlbnRlcmluZy4=" }, + { "2nd Law of Hacking: first in, first out.", + "Mm5kIExhdyBvZiBIYWNraW5nOiBmaXJzdCBpbiwgZmlyc3Qgb3V0Lg==" }, + { "3rd Law of Hacking: the last blow counts most.", + "M3JkIExhdyBvZiBIYWNraW5nOiB0aGUgbGFzdCBibG93IGNvdW50cyBtb3N0Lg==" }, + { "4th Law of Hacking: you will find the exit at the entrance.", + "NHRoIExhdyBvZiBIYWNraW5nOiB5b3Ugd2lsbCBmaW5kIHRoZSBleGl0IGF0IHRoZSBlbnRyYW5jZS4=" }, + { "A chameleon imitating a mail daemon often delivers scrolls of fire.", + "QSBjaGFtZWxlb24gaW1pdGF0aW5nIGEgbWFpbCBkYWVtb24gb2Z0ZW4gZGVsaXZlcnMgc2Nyb2xscyBvZiBmaXJlLg==" }, + { "A cockatrice corpse is guaranteed to be untainted!", + "QSBjb2NrYXRyaWNlIGNvcnBzZSBpcyBndWFyYW50ZWVkIHRvIGJlIHVudGFpbnRlZCE=" }, + { "A dead cockatrice is just a dead lizard.", + "QSBkZWFkIGNvY2thdHJpY2UgaXMganVzdCBhIGRlYWQgbGl6YXJkLg==" }, + { "A dragon is just a snake that ate a scroll of fire.", + "QSBkcmFnb24gaXMganVzdCBhIHNuYWtlIHRoYXQgYXRlIGEgc2Nyb2xsIG9mIGZpcmUu" }, + { "A fading corridor enlightens your insight.", + "QSBmYWRpbmcgY29ycmlkb3IgZW5saWdodGVucyB5b3VyIGluc2lnaHQu" }, + { "A glowing potion is too hot to drink.", + "QSBnbG93aW5nIHBvdGlvbiBpcyB0b28gaG90IHRvIGRyaW5rLg==" }, + { "A good amulet may protect you against guards.", + "QSBnb29kIGFtdWxldCBtYXkgcHJvdGVjdCB5b3UgYWdhaW5zdCBndWFyZHMu" }, + { "A lizard corpse is a good thing to turn undead.", + "QSBsaXphcmQgY29ycHNlIGlzIGEgZ29vZCB0aGluZyB0byB0dXJuIHVuZGVhZC4=" }, + { "A long worm can be defined recursively. So how should you attack it?", + "QSBsb25nIHdvcm0gY2FuIGJlIGRlZmluZWQgcmVjdXJzaXZlbHkuIFNvIGhvdyBzaG91bGQgeW91IGF0dGFjayBpdD8=" }, + { "A monstrous mind is a toy forever.", + "QSBtb25zdHJvdXMgbWluZCBpcyBhIHRveSBmb3JldmVyLg==" }, + { "A nymph will be very pleased if you call her by her real name: Lorelei.", + "QSBueW1waCB3aWxsIGJlIHZlcnkgcGxlYXNlZCBpZiB5b3UgY2FsbCBoZXIgYnkgaGVyIHJlYWwgbmFtZTogTG9yZWxlaS4=" }, + { "A ring of dungeon master control is a great find.", + "QSByaW5nIG9mIGR1bmdlb24gbWFzdGVyIGNvbnRyb2wgaXMgYSBncmVhdCBmaW5kLg==" }, + { "A ring of extra ring finger is useless if not enchanted.", + "QSByaW5nIG9mIGV4dHJhIHJpbmcgZmluZ2VyIGlzIHVzZWxlc3MgaWYgbm90IGVuY2hhbnRlZC4=" }, + { "A rope may form a trail in a maze.", + "QSByb3BlIG1heSBmb3JtIGEgdHJhaWwgaW4gYSBtYXplLg==" }, + { "A staff may recharge if you drop it for awhile.", + "QSBzdGFmZiBtYXkgcmVjaGFyZ2UgaWYgeW91IGRyb3AgaXQgZm9yIGF3aGlsZS4=" }, + { "A visit to the Zoo is very educational; you meet interesting animals.", + "QSB2aXNpdCB0byB0aGUgWm9vIGlzIHZlcnkgZWR1Y2F0aW9uYWw7IHlvdSBtZWV0IGludGVyZXN0aW5nIGFuaW1hbHMu" }, + { "A wand of deaf is a more dangerous weapon than a wand of sheep.", + "QSB3YW5kIG9mIGRlYWYgaXMgYSBtb3JlIGRhbmdlcm91cyB3ZWFwb24gdGhhbiBhIHdhbmQgb2Ygc2hlZXAu" }, + { "A wand of vibration might bring the whole cave crashing about your ears.", + "QSB3YW5kIG9mIHZpYnJhdGlvbiBtaWdodCBicmluZyB0aGUgd2hvbGUgY2F2ZSBjcmFzaGluZyBhYm91dCB5b3VyIGVhcnMu" }, + { "A winner never quits. A quitter never wins.", + "QSB3aW5uZXIgbmV2ZXIgcXVpdHMuIEEgcXVpdHRlciBuZXZlciB3aW5zLg==" }, + { "A wish? Okay, make me a fortune cookie!", + "QSB3aXNoPyBPa2F5LCBtYWtlIG1lIGEgZm9ydHVuZSBjb29raWUh" }, + { "Afraid of mimics? Try to wear a ring of true seeing.", + "QWZyYWlkIG9mIG1pbWljcz8gVHJ5IHRvIHdlYXIgYSByaW5nIG9mIHRydWUgc2VlaW5nLg==" }, + { "All monsters are created evil, but some are more evil than others.", + "QWxsIG1vbnN0ZXJzIGFyZSBjcmVhdGVkIGV2aWwsIGJ1dCBzb21lIGFyZSBtb3JlIGV2aWwgdGhhbiBvdGhlcnMu" }, + { "Always attack a floating eye from behind!", + "QWx3YXlzIGF0dGFjayBhIGZsb2F0aW5nIGV5ZSBmcm9tIGJlaGluZCE=" }, + { "An elven cloak is always the height of fashion.", + "QW4gZWx2ZW4gY2xvYWsgaXMgYWx3YXlzIHRoZSBoZWlnaHQgb2YgZmFzaGlvbi4=" }, + { "Any small object that is accidentally dropped will hide under a larger object.", + "QW55IHNtYWxsIG9iamVjdCB0aGF0IGlzIGFjY2lkZW50YWxseSBkcm9wcGVkIHdpbGwgaGlkZSB1bmRlciBhIGxhcmdlciBvYmplY3Qu" }, + { "Balrogs do not appear above level 20.", + "QmFscm9ncyBkbyBub3QgYXBwZWFyIGFib3ZlIGxldmVsIDIwLg==" }, + { "Banana peels work especially well against Keystone Kops.", + "QmFuYW5hIHBlZWxzIHdvcmsgZXNwZWNpYWxseSB3ZWxsIGFnYWluc3QgS2V5c3RvbmUgS29wcy4=" }, + { "Be careful when eating bananas. Monsters might slip on the peels.", + "QmUgY2FyZWZ1bCB3aGVuIGVhdGluZyBiYW5hbmFzLiBNb25zdGVycyBtaWdodCBzbGlwIG9uIHRoZSBwZWVscy4=" }, + { "Better leave the dungeon; otherwise you might get hurt badly.", + "QmV0dGVyIGxlYXZlIHRoZSBkdW5nZW9uOyBvdGhlcndpc2UgeW91IG1pZ2h0IGdldCBodXJ0IGJhZGx5Lg==" }, + { "Beware of the potion of nitroglycerin -- it's not for the weak of heart.", + "QmV3YXJlIG9mIHRoZSBwb3Rpb24gb2Ygbml0cm9nbHljZXJpbiAtLSBpdCdzIG5vdCBmb3IgdGhlIHdlYWsgb2YgaGVhcnQu" }, + { "Beware: there's always a chance that your wand explodes as you try to zap it!", + "QmV3YXJlOiB0aGVyZSdzIGFsd2F5cyBhIGNoYW5jZSB0aGF0IHlvdXIgd2FuZCBleHBsb2RlcyBhcyB5b3UgdHJ5IHRvIHphcCBpdCE=" }, + { "Beyond the 23rd level lies a happy retirement in a room of your own.", + "QmV5b25kIHRoZSAyM3JkIGxldmVsIGxpZXMgYSBoYXBweSByZXRpcmVtZW50IGluIGEgcm9vbSBvZiB5b3VyIG93bi4=" }, + { "Changing your suit without dropping your sword? You must be kidding!", + "Q2hhbmdpbmcgeW91ciBzdWl0IHdpdGhvdXQgZHJvcHBpbmcgeW91ciBzd29yZD8gWW91IG11c3QgYmUga2lkZGluZyE=" }, + { "Cockatrices might turn themselves to stone faced with a mirror.", + "Q29ja2F0cmljZXMgbWlnaHQgdHVybiB0aGVtc2VsdmVzIHRvIHN0b25lIGZhY2VkIHdpdGggYSBtaXJyb3Iu" }, + { "Consumption of home-made food is strictly forbidden in this dungeon.", + "Q29uc3VtcHRpb24gb2YgaG9tZS1tYWRlIGZvb2QgaXMgc3RyaWN0bHkgZm9yYmlkZGVuIGluIHRoaXMgZHVuZ2Vvbi4=" }, + { "Dark room? Your chance to develop your photographs!", + "RGFyayByb29tPyBZb3VyIGNoYW5jZSB0byBkZXZlbG9wIHlvdXIgcGhvdG9ncmFwaHMh" }, + { "Dark rooms are not *completely* dark: just wait and let your eyes adjust...", + "RGFyayByb29tcyBhcmUgbm90ICpjb21wbGV0ZWx5KiBkYXJrOiBqdXN0IHdhaXQgYW5kIGxldCB5b3VyIGV5ZXMgYWRqdXN0Li4u" }, + { "David London sez, \"Hey guys, *WIELD* a lizard corpse against a cockatrice!\"", + "RGF2aWQgTG9uZG9uIHNleiwgIkhleSBndXlzLCAqV0lFTEQqIGEgbGl6YXJkIGNvcnBzZSBhZ2FpbnN0IGEgY29ja2F0cmljZSEi" }, + { "Death is just life's way of telling you you've been fired.", + "RGVhdGggaXMganVzdCBsaWZlJ3Mgd2F5IG9mIHRlbGxpbmcgeW91IHlvdSd2ZSBiZWVuIGZpcmVkLg==" }, + { "Demi-gods don't need any help from the gods.", + "RGVtaS1nb2RzIGRvbid0IG5lZWQgYW55IGhlbHAgZnJvbSB0aGUgZ29kcy4=" }, + { "Demons *HATE* Priests and Priestesses.", + "RGVtb25zICpIQVRFKiBQcmllc3RzIGFuZCBQcmllc3Rlc3Nlcy4=" }, + { "Didn't you forget to pay?", + "RGlkbid0IHlvdSBmb3JnZXQgdG8gcGF5Pw==" }, + { "Didn't your mother tell you not to eat food off the floor?", + "RGlkbid0IHlvdXIgbW90aGVyIHRlbGwgeW91IG5vdCB0byBlYXQgZm9vZCBvZmYgdGhlIGZsb29yPw==" }, + { "Direct a direct hit on your direct opponent, directing in the right direction.", + "RGlyZWN0IGEgZGlyZWN0IGhpdCBvbiB5b3VyIGRpcmVjdCBvcHBvbmVudCwgZGlyZWN0aW5nIGluIHRoZSByaWdodCBkaXJlY3Rpb24u" }, + { "Do you want to make more money? Sure, we all do! Join the Fort Ludios guard!", + "RG8geW91IHdhbnQgdG8gbWFrZSBtb3JlIG1vbmV5PyBTdXJlLCB3ZSBhbGwgZG8hIEpvaW4gdGhlIEZvcnQgTHVkaW9zIGd1YXJkIQ==" }, + { "Don't eat too much: you might start hiccoughing!", + "RG9uJ3QgZWF0IHRvbyBtdWNoOiB5b3UgbWlnaHQgc3RhcnQgaGljY291Z2hpbmch" }, + { "Don't play hack at your work; your boss might hit you!", + "RG9uJ3QgcGxheSBoYWNrIGF0IHlvdXIgd29yazsgeW91ciBib3NzIG1pZ2h0IGhpdCB5b3Uh" }, + { "Don't tell a soul you found a secret door, otherwise it isn't a secret anymore.", + "RG9uJ3QgdGVsbCBhIHNvdWwgeW91IGZvdW5kIGEgc2VjcmV0IGRvb3IsIG90aGVyd2lzZSBpdCBpc24ndCBhIHNlY3JldCBhbnltb3JlLg==" }, + { "Drinking potions of booze may land you in jail if you are under 21.", + "RHJpbmtpbmcgcG90aW9ucyBvZiBib296ZSBtYXkgbGFuZCB5b3UgaW4gamFpbCBpZiB5b3UgYXJlIHVuZGVyIDIxLg==" }, + { "Drop your vanity and get rid of your jewels! Pickpockets about!", + "RHJvcCB5b3VyIHZhbml0eSBhbmQgZ2V0IHJpZCBvZiB5b3VyIGpld2VscyEgUGlja3BvY2tldHMgYWJvdXQh" }, + { "Eat 10 cloves of garlic and keep all humans at a two-square distance.", + "RWF0IDEwIGNsb3ZlcyBvZiBnYXJsaWMgYW5kIGtlZXAgYWxsIGh1bWFucyBhdCBhIHR3by1zcXVhcmUgZGlzdGFuY2Uu" }, + { "Eels hide under mud. Use a unicorn to clear the water and make them visible.", + "RWVscyBoaWRlIHVuZGVyIG11ZC4gVXNlIGEgdW5pY29ybiB0byBjbGVhciB0aGUgd2F0ZXIgYW5kIG1ha2UgdGhlbSB2aXNpYmxlLg==" }, + { "Engrave your wishes with a wand of wishing.", + "RW5ncmF2ZSB5b3VyIHdpc2hlcyB3aXRoIGEgd2FuZCBvZiB3aXNoaW5nLg==" }, + { "Eventually you will come to admire the swift elegance of a retreating nymph.", + "RXZlbnR1YWxseSB5b3Ugd2lsbCBjb21lIHRvIGFkbWlyZSB0aGUgc3dpZnQgZWxlZ2FuY2Ugb2YgYSByZXRyZWF0aW5nIG55bXBoLg==" }, + { "Ever heard hissing outside? I *knew* you hadn't!", + "RXZlciBoZWFyZCBoaXNzaW5nIG91dHNpZGU/IEkgKmtuZXcqIHlvdSBoYWRuJ3Qh" }, + { "Ever lifted a dragon corpse?", + "RXZlciBsaWZ0ZWQgYSBkcmFnb24gY29ycHNlPw==" }, + { "Ever seen a leocrotta dancing the tengu?", + "RXZlciBzZWVuIGEgbGVvY3JvdHRhIGRhbmNpbmcgdGhlIHRlbmd1Pw==" }, + { "Ever seen your weapon glow plaid?", + "RXZlciBzZWVuIHlvdXIgd2VhcG9uIGdsb3cgcGxhaWQ/" }, + { "Ever tamed a shopkeeper?", + "RXZlciB0YW1lZCBhIHNob3BrZWVwZXI/" }, + { "Ever tried digging through a Vault Guard?", + "RXZlciB0cmllZCBkaWdnaW5nIHRocm91Z2ggYSBWYXVsdCBHdWFyZD8=" }, + { "Ever tried enchanting a rope?", + "RXZlciB0cmllZCBlbmNoYW50aW5nIGEgcm9wZT8=" }, + { "Floating eyes can't stand Hawaiian shirts.", + "RmxvYXRpbmcgZXllcyBjYW4ndCBzdGFuZCBIYXdhaWlhbiBzaGlydHMu" }, + { "For any remedy there is a misery.", + "Rm9yIGFueSByZW1lZHkgdGhlcmUgaXMgYSBtaXNlcnku" }, + { "Giant bats turn into giant vampires.", + "R2lhbnQgYmF0cyB0dXJuIGludG8gZ2lhbnQgdmFtcGlyZXMu" }, + { "Good day for overcoming obstacles. Try a steeplechase.", + "R29vZCBkYXkgZm9yIG92ZXJjb21pbmcgb2JzdGFjbGVzLiBUcnkgYSBzdGVlcGxlY2hhc2Uu" }, + { "Half Moon tonight. (At least it's better than no Moon at all.)", + "SGFsZiBNb29uIHRvbmlnaHQuIChBdCBsZWFzdCBpdCdzIGJldHRlciB0aGFuIG5vIE1vb24gYXQgYWxsLik=" }, + { "Help! I'm being held prisoner in a fortune cookie factory!", + "SGVscCEgSSdtIGJlaW5nIGhlbGQgcHJpc29uZXIgaW4gYSBmb3J0dW5lIGNvb2tpZSBmYWN0b3J5IQ==" }, + { "Housecats have nine lives, kittens only one.", + "SG91c2VjYXRzIGhhdmUgbmluZSBsaXZlcywga2l0dGVucyBvbmx5IG9uZS4=" }, + { "How long can you tread water?", + "SG93IGxvbmcgY2FuIHlvdSB0cmVhZCB3YXRlcj8=" }, + { "Hungry? There is an abundance of food on the next level.", + "SHVuZ3J5PyBUaGVyZSBpcyBhbiBhYnVuZGFuY2Ugb2YgZm9vZCBvbiB0aGUgbmV4dCBsZXZlbC4=" }, + { "I guess you've never hit a mail daemon with the Amulet of Yendor...", + "SSBndWVzcyB5b3UndmUgbmV2ZXIgaGl0IGEgbWFpbCBkYWVtb24gd2l0aCB0aGUgQW11bGV0IG9mIFllbmRvci4uLg==" }, + { "If you are the shopkeeper, you can take things for free.", + "SWYgeW91IGFyZSB0aGUgc2hvcGtlZXBlciwgeW91IGNhbiB0YWtlIHRoaW5ncyBmb3IgZnJlZS4=" }, + { "If you can't learn to do it well, learn to enjoy doing it badly.", + "SWYgeW91IGNhbid0IGxlYXJuIHRvIGRvIGl0IHdlbGwsIGxlYXJuIHRvIGVuam95IGRvaW5nIGl0IGJhZGx5Lg==" }, + { "If you thought the Wizard was bad, just wait till you meet the Warlord!", + "SWYgeW91IHRob3VnaHQgdGhlIFdpemFyZCB3YXMgYmFkLCBqdXN0IHdhaXQgdGlsbCB5b3UgbWVldCB0aGUgV2FybG9yZCE=" }, + { "If you turn blind, don't expect your dog to be turned into a seeing-eye dog.", + "SWYgeW91IHR1cm4gYmxpbmQsIGRvbid0IGV4cGVjdCB5b3VyIGRvZyB0byBiZSB0dXJuZWQgaW50byBhIHNlZWluZy1leWUgZG9nLg==" }, + { "If you want to feel great, you must eat something real big.", + "SWYgeW91IHdhbnQgdG8gZmVlbCBncmVhdCwgeW91IG11c3QgZWF0IHNvbWV0aGluZyByZWFsIGJpZy4=" }, + { "If you want to float, you'd better eat a floating eye.", + "SWYgeW91IHdhbnQgdG8gZmxvYXQsIHlvdSdkIGJldHRlciBlYXQgYSBmbG9hdGluZyBleWUu" }, + { "If your ghost kills a player, it increases your score.", + "SWYgeW91ciBnaG9zdCBraWxscyBhIHBsYXllciwgaXQgaW5jcmVhc2VzIHlvdXIgc2NvcmUu" }, + { "Increase mindpower: Tame your own ghost!", + "SW5jcmVhc2UgbWluZHBvd2VyOiBUYW1lIHlvdXIgb3duIGdob3N0IQ==" }, + { "It furthers one to see the great man.", + "SXQgZnVydGhlcnMgb25lIHRvIHNlZSB0aGUgZ3JlYXQgbWFuLg==" }, + { "It's easy to overlook a monster in a wood.", + "SXQncyBlYXN5IHRvIG92ZXJsb29rIGEgbW9uc3RlciBpbiBhIHdvb2Qu" }, + { "Just below any trapdoor there may be another one. Just keep falling!", + "SnVzdCBiZWxvdyBhbnkgdHJhcGRvb3IgdGhlcmUgbWF5IGJlIGFub3RoZXIgb25lLiBKdXN0IGtlZXAgZmFsbGluZyE=" }, + { "Katanas are very sharp; watch you don't cut yourself.", + "S2F0YW5hcyBhcmUgdmVyeSBzaGFycDsgd2F0Y2ggeW91IGRvbid0IGN1dCB5b3Vyc2VsZi4=" }, + { "Keep a clear mind: quaff clear potions.", + "S2VlcCBhIGNsZWFyIG1pbmQ6IHF1YWZmIGNsZWFyIHBvdGlvbnMu" }, + { "Kicking the terminal doesn't hurt the monsters.", + "S2lja2luZyB0aGUgdGVybWluYWwgZG9lc24ndCBodXJ0IHRoZSBtb25zdGVycy4=" }, + { "Killer bees keep appearing till you kill their queen.", + "S2lsbGVyIGJlZXMga2VlcCBhcHBlYXJpbmcgdGlsbCB5b3Uga2lsbCB0aGVpciBxdWVlbi4=" }, + { "Killer bunnies can be tamed with carrots only.", + "S2lsbGVyIGJ1bm5pZXMgY2FuIGJlIHRhbWVkIHdpdGggY2Fycm90cyBvbmx5Lg==" }, + { "Latest news? Put `rec.games.roguelike.nethack' in your .newsrc!", + "TGF0ZXN0IG5ld3M/IFB1dCBgcmVjLmdhbWVzLnJvZ3VlbGlrZS5uZXRoYWNrJyBpbiB5b3VyIC5uZXdzcmMh" }, + { "Learn how to spell. Play NetHack!", + "TGVhcm4gaG93IHRvIHNwZWxsLiBQbGF5IE5ldEhhY2sh" }, + { "Leprechauns hide their gold in a secret room.", + "TGVwcmVjaGF1bnMgaGlkZSB0aGVpciBnb2xkIGluIGEgc2VjcmV0IHJvb20u" }, + { "Let your fingers do the walking on the yulkjhnb keys.", + "TGV0IHlvdXIgZmluZ2VycyBkbyB0aGUgd2Fsa2luZyBvbiB0aGUgeXVsa2pobmIga2V5cy4=" }, + { "Let's face it: this time you're not going to win.", + "TGV0J3MgZmFjZSBpdDogdGhpcyB0aW1lIHlvdSdyZSBub3QgZ29pbmcgdG8gd2luLg==" }, + { "Let's have a party, drink a lot of booze.", + "TGV0J3MgaGF2ZSBhIHBhcnR5LCBkcmluayBhIGxvdCBvZiBib296ZS4=" }, + { "Liquor sellers do not drink; they hate to see you twice.", + "TGlxdW9yIHNlbGxlcnMgZG8gbm90IGRyaW5rOyB0aGV5IGhhdGUgdG8gc2VlIHlvdSB0d2ljZS4=" }, + { "Lunar eclipse tonight. May as well quit now!", + "THVuYXIgZWNsaXBzZSB0b25pZ2h0LiBNYXkgYXMgd2VsbCBxdWl0IG5vdyE=" }, + { "Meeting your own ghost decreases your luck considerably!", + "TWVldGluZyB5b3VyIG93biBnaG9zdCBkZWNyZWFzZXMgeW91ciBsdWNrIGNvbnNpZGVyYWJseSE=" }, + { "Money to invest? Take it to the local branch of the Magic Memory Vault!", + "TW9uZXkgdG8gaW52ZXN0PyBUYWtlIGl0IHRvIHRoZSBsb2NhbCBicmFuY2ggb2YgdGhlIE1hZ2ljIE1lbW9yeSBWYXVsdCE=" }, + { "Monsters come from nowhere to hit you everywhere.", + "TW9uc3RlcnMgY29tZSBmcm9tIG5vd2hlcmUgdG8gaGl0IHlvdSBldmVyeXdoZXJlLg==" }, + { "Monsters sleep because you are boring, not because they ever get tired.", + "TW9uc3RlcnMgc2xlZXAgYmVjYXVzZSB5b3UgYXJlIGJvcmluZywgbm90IGJlY2F1c2UgdGhleSBldmVyIGdldCB0aXJlZC4=" }, + { "Most monsters prefer minced meat. That's why they are hitting you!", + "TW9zdCBtb25zdGVycyBwcmVmZXIgbWluY2VkIG1lYXQuIFRoYXQncyB3aHkgdGhleSBhcmUgaGl0dGluZyB5b3Uh" }, + { "Most of the bugs in NetHack are on the floor.", + "TW9zdCBvZiB0aGUgYnVncyBpbiBOZXRIYWNrIGFyZSBvbiB0aGUgZmxvb3Iu" }, + { "Much ado Nothing Happens.", + "TXVjaCBhZG8gTm90aGluZyBIYXBwZW5zLg==" }, + { "Multi-player NetHack is a myth.", + "TXVsdGktcGxheWVyIE5ldEhhY2sgaXMgYSBteXRoLg==" }, + { "NetHack is addictive. Too late, you're already hooked.", + "TmV0SGFjayBpcyBhZGRpY3RpdmUuIFRvbyBsYXRlLCB5b3UncmUgYWxyZWFkeSBob29rZWQu" }, + { "Never ask a shopkeeper for a price list.", + "TmV2ZXIgYXNrIGEgc2hvcGtlZXBlciBmb3IgYSBwcmljZSBsaXN0Lg==" }, + { "Never burn a tree, unless you like getting whacked with a +5 shovel.", + "TmV2ZXIgYnVybiBhIHRyZWUsIHVubGVzcyB5b3UgbGlrZSBnZXR0aW5nIHdoYWNrZWQgd2l0aCBhICs1IHNob3ZlbC4=" }, + { "Never eat with glowing hands!", + "TmV2ZXIgZWF0IHdpdGggZ2xvd2luZyBoYW5kcyE=" }, + { "Never mind the monsters hitting you: they just replace the charwomen.", + "TmV2ZXIgbWluZCB0aGUgbW9uc3RlcnMgaGl0dGluZyB5b3U6IHRoZXkganVzdCByZXBsYWNlIHRoZSBjaGFyd29tZW4u" }, + { "Never play leapfrog with a unicorn.", + "TmV2ZXIgcGxheSBsZWFwZnJvZyB3aXRoIGEgdW5pY29ybi4=" }, + { "Never step on a cursed engraving.", + "TmV2ZXIgc3RlcCBvbiBhIGN1cnNlZCBlbmdyYXZpbmcu" }, + { "Never swim with a camera: there's nothing to take pictures of.", + "TmV2ZXIgc3dpbSB3aXRoIGEgY2FtZXJhOiB0aGVyZSdzIG5vdGhpbmcgdG8gdGFrZSBwaWN0dXJlcyBvZi4=" }, + { "Never teach your pet rust monster to fetch.", + "TmV2ZXIgdGVhY2ggeW91ciBwZXQgcnVzdCBtb25zdGVyIHRvIGZldGNoLg==" }, + { "Never trust a random generator in magic fields.", + "TmV2ZXIgdHJ1c3QgYSByYW5kb20gZ2VuZXJhdG9yIGluIG1hZ2ljIGZpZWxkcy4=" }, + { "Never use a wand of death.", + "TmV2ZXIgdXNlIGEgd2FuZCBvZiBkZWF0aC4=" }, + { "No level contains two shops. The maze is no level. So...", + "Tm8gbGV2ZWwgY29udGFpbnMgdHdvIHNob3BzLiBUaGUgbWF6ZSBpcyBubyBsZXZlbC4gU28uLi4=" }, + { "No part of this fortune may be reproduced, stored in a retrieval system, ...", + "Tm8gcGFydCBvZiB0aGlzIGZvcnR1bmUgbWF5IGJlIHJlcHJvZHVjZWQsIHN0b3JlZCBpbiBhIHJldHJpZXZhbCBzeXN0ZW0sIC4uLg==" }, + { "Not all rumors are as misleading as this one.", + "Tm90IGFsbCBydW1vcnMgYXJlIGFzIG1pc2xlYWRpbmcgYXMgdGhpcyBvbmUu" }, + { "Nymphs and nurses like beautiful rings.", + "TnltcGhzIGFuZCBudXJzZXMgbGlrZSBiZWF1dGlmdWwgcmluZ3Mu" }, + { "Nymphs are blondes. Are you a gentleman?", + "TnltcGhzIGFyZSBibG9uZGVzLiBBcmUgeW91IGEgZ2VudGxlbWFuPw==" }, + { "Offering a unicorn a worthless piece of glass might prove to be fatal!", + "T2ZmZXJpbmcgYSB1bmljb3JuIGEgd29ydGhsZXNzIHBpZWNlIG9mIGdsYXNzIG1pZ2h0IHByb3ZlIHRvIGJlIGZhdGFsIQ==" }, + { "Old hackers never die: young ones do.", + "T2xkIGhhY2tlcnMgbmV2ZXIgZGllOiB5b3VuZyBvbmVzIGRvLg==" }, + { "One has to leave shops before closing time.", + "T25lIGhhcyB0byBsZWF2ZSBzaG9wcyBiZWZvcmUgY2xvc2luZyB0aW1lLg==" }, + { "One homunculus a day keeps the doctor away.", + "T25lIGhvbXVuY3VsdXMgYSBkYXkga2VlcHMgdGhlIGRvY3RvciBhd2F5Lg==" }, + { "One level further down somebody is getting killed, right now.", + "T25lIGxldmVsIGZ1cnRoZXIgZG93biBzb21lYm9keSBpcyBnZXR0aW5nIGtpbGxlZCwgcmlnaHQgbm93Lg==" }, + { "Only a wizard can use a magic whistle.", + "T25seSBhIHdpemFyZCBjYW4gdXNlIGEgbWFnaWMgd2hpc3RsZS4=" }, + { "Only adventurers of evil alignment think of killing their dog.", + "T25seSBhZHZlbnR1cmVycyBvZiBldmlsIGFsaWdubWVudCB0aGluayBvZiBraWxsaW5nIHRoZWlyIGRvZy4=" }, + { "Only chaotic evils kill sleeping monsters.", + "T25seSBjaGFvdGljIGV2aWxzIGtpbGwgc2xlZXBpbmcgbW9uc3RlcnMu" }, + { "Only real trappers escape traps.", + "T25seSByZWFsIHRyYXBwZXJzIGVzY2FwZSB0cmFwcy4=" }, + { "Only real wizards can write scrolls.", + "T25seSByZWFsIHdpemFyZHMgY2FuIHdyaXRlIHNjcm9sbHMu" }, + { "Operation OVERKILL has started now.", + "T3BlcmF0aW9uIE9WRVJLSUxMIGhhcyBzdGFydGVkIG5vdy4=" }, + { "PLEASE ignore previous rumor.", + "UExFQVNFIGlnbm9yZSBwcmV2aW91cyBydW1vci4=" }, + { "Polymorph into an ettin; meet your opponents face to face to face.", + "UG9seW1vcnBoIGludG8gYW4gZXR0aW47IG1lZXQgeW91ciBvcHBvbmVudHMgZmFjZSB0byBmYWNlIHRvIGZhY2Uu" }, + { "Praying will frighten demons.", + "UHJheWluZyB3aWxsIGZyaWdodGVuIGRlbW9ucy4=" }, + { "Row (3x) that boat gently down the stream, Charon (4x), death is but a dream.", + "Um93ICgzeCkgdGhhdCBib2F0IGdlbnRseSBkb3duIHRoZSBzdHJlYW0sIENoYXJvbiAoNHgpLCBkZWF0aCBpcyBidXQgYSBkcmVhbS4=" }, + { "Running is good for your legs.", + "UnVubmluZyBpcyBnb29kIGZvciB5b3VyIGxlZ3Mu" }, + { "Screw up your courage! You've screwed up everything else.", + "U2NyZXcgdXAgeW91ciBjb3VyYWdlISBZb3UndmUgc2NyZXdlZCB1cCBldmVyeXRoaW5nIGVsc2Uu" }, + { "Seepage? Leaky pipes? Rising damp? Summon the plumber!", + "U2VlcGFnZT8gTGVha3kgcGlwZXM/IFJpc2luZyBkYW1wPyBTdW1tb24gdGhlIHBsdW1iZXIh" }, + { "Segmentation fault (core dumped).", + "U2VnbWVudGF0aW9uIGZhdWx0IChjb3JlIGR1bXBlZCku" }, + { "Shopkeepers sometimes die from old age.", + "U2hvcGtlZXBlcnMgc29tZXRpbWVzIGRpZSBmcm9tIG9sZCBhZ2Uu" }, + { "Some mazes (especially small ones) have no solutions, says man 6 maze.", + "U29tZSBtYXplcyAoZXNwZWNpYWxseSBzbWFsbCBvbmVzKSBoYXZlIG5vIHNvbHV0aW9ucywgc2F5cyBtYW4gNiBtYXplLg==" }, + { "Some questions the Sphynx asks just *don't* have any answers.", + "U29tZSBxdWVzdGlvbnMgdGhlIFNwaHlueCBhc2tzIGp1c3QgKmRvbid0KiBoYXZlIGFueSBhbnN3ZXJzLg==" }, + { "Sometimes \"mu\" is the answer.", + "U29tZXRpbWVzICJtdSIgaXMgdGhlIGFuc3dlci4=" }, + { "Sorry, no fortune this time. Better luck next cookie!", + "U29ycnksIG5vIGZvcnR1bmUgdGhpcyB0aW1lLiBCZXR0ZXIgbHVjayBuZXh0IGNvb2tpZSE=" }, + { "Spare your scrolls of make-edible until it's really necessary!", + "U3BhcmUgeW91ciBzY3JvbGxzIG9mIG1ha2UtZWRpYmxlIHVudGlsIGl0J3MgcmVhbGx5IG5lY2Vzc2FyeSE=" }, + { "Suddenly, the dungeon will collapse...", + "U3VkZGVubHksIHRoZSBkdW5nZW9uIHdpbGwgY29sbGFwc2UuLi4=" }, + { "Taming a mail daemon may cause a system security violation.", + "VGFtaW5nIGEgbWFpbCBkYWVtb24gbWF5IGNhdXNlIGEgc3lzdGVtIHNlY3VyaXR5IHZpb2xhdGlvbi4=" }, + { "The crowd was so tough, the Stooges won't play the Dungeon anymore, nyuk nyuk.", + "VGhlIGNyb3dkIHdhcyBzbyB0b3VnaCwgdGhlIFN0b29nZXMgd29uJ3QgcGxheSB0aGUgRHVuZ2VvbiBhbnltb3JlLCBueXVrIG55dWsu" }, + { "The leprechauns hide their treasure in a small hidden room.", + "VGhlIGxlcHJlY2hhdW5zIGhpZGUgdGhlaXIgdHJlYXN1cmUgaW4gYSBzbWFsbCBoaWRkZW4gcm9vbS4=" }, + { "The longer the wand the better.", + "VGhlIGxvbmdlciB0aGUgd2FuZCB0aGUgYmV0dGVyLg==" }, + { "The magic word is \"XYZZY\".", + "VGhlIG1hZ2ljIHdvcmQgaXMgIlhZWlpZIi4=" }, + { "The meek shall inherit your bones files.", + "VGhlIG1lZWsgc2hhbGwgaW5oZXJpdCB5b3VyIGJvbmVzIGZpbGVzLg==" }, + { "The mines are dark and deep, and I have levels to go before I sleep.", + "VGhlIG1pbmVzIGFyZSBkYXJrIGFuZCBkZWVwLCBhbmQgSSBoYXZlIGxldmVscyB0byBnbyBiZWZvcmUgSSBzbGVlcC4=" }, + { "The use of dynamite is dangerous.", + "VGhlIHVzZSBvZiBkeW5hbWl0ZSBpcyBkYW5nZXJvdXMu" }, + { "There are no worms in the UNIX version.", + "VGhlcmUgYXJlIG5vIHdvcm1zIGluIHRoZSBVTklYIHZlcnNpb24u" }, + { "There is a trap on this level!", + "VGhlcmUgaXMgYSB0cmFwIG9uIHRoaXMgbGV2ZWwh" }, + { "They say that Demogorgon, Asmodeus, Orcus, Yeenoghu & Juiblex is no law firm.", + "VGhleSBzYXkgdGhhdCBEZW1vZ29yZ29uLCBBc21vZGV1cywgT3JjdXMsIFllZW5vZ2h1ICYgSnVpYmxleCBpcyBubyBsYXcgZmlybS4=" }, + { "They say that Geryon has an evil twin, beware!", + "VGhleSBzYXkgdGhhdCBHZXJ5b24gaGFzIGFuIGV2aWwgdHdpbiwgYmV3YXJlIQ==" }, + { "They say that Medusa would make a terrible pet.", + "VGhleSBzYXkgdGhhdCBNZWR1c2Egd291bGQgbWFrZSBhIHRlcnJpYmxlIHBldC4=" }, + { "They say that NetHack bugs are Seldon planned.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGJ1Z3MgYXJlIFNlbGRvbiBwbGFubmVkLg==" }, + { "They say that NetHack comes in 256 flavors.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGNvbWVzIGluIDI1NiBmbGF2b3JzLg==" }, + { "They say that NetHack is just a computer game.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIGp1c3QgYSBjb21wdXRlciBnYW1lLg==" }, + { "They say that NetHack is more than just a computer game.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIG1vcmUgdGhhbiBqdXN0IGEgY29tcHV0ZXIgZ2FtZS4=" }, + { "They say that NetHack is never what it used to be.", + "VGhleSBzYXkgdGhhdCBOZXRIYWNrIGlzIG5ldmVyIHdoYXQgaXQgdXNlZCB0byBiZS4=" }, + { "They say that a baby dragon is too small to hurt or help you.", + "VGhleSBzYXkgdGhhdCBhIGJhYnkgZHJhZ29uIGlzIHRvbyBzbWFsbCB0byBodXJ0IG9yIGhlbHAgeW91Lg==" }, + { "They say that a black pudding is simply a brown pudding gone bad.", + "VGhleSBzYXkgdGhhdCBhIGJsYWNrIHB1ZGRpbmcgaXMgc2ltcGx5IGEgYnJvd24gcHVkZGluZyBnb25lIGJhZC4=" }, + { "They say that a black sheep has 3 bags full of wool.", + "VGhleSBzYXkgdGhhdCBhIGJsYWNrIHNoZWVwIGhhcyAzIGJhZ3MgZnVsbCBvZiB3b29sLg==" }, + { "They say that a blank scroll is like a blank check.", + "VGhleSBzYXkgdGhhdCBhIGJsYW5rIHNjcm9sbCBpcyBsaWtlIGEgYmxhbmsgY2hlY2su" }, + { "They say that a cat named Morris has nine lives.", + "VGhleSBzYXkgdGhhdCBhIGNhdCBuYW1lZCBNb3JyaXMgaGFzIG5pbmUgbGl2ZXMu" }, + { "They say that a desperate shopper might pay any price in a shop.", + "VGhleSBzYXkgdGhhdCBhIGRlc3BlcmF0ZSBzaG9wcGVyIG1pZ2h0IHBheSBhbnkgcHJpY2UgaW4gYSBzaG9wLg==" }, + { "They say that a diamond dog is everybody's best friend.", + "VGhleSBzYXkgdGhhdCBhIGRpYW1vbmQgZG9nIGlzIGV2ZXJ5Ym9keSdzIGJlc3QgZnJpZW5kLg==" }, + { "They say that a dwarf lord can carry a pick-axe because his armor is light.", + "VGhleSBzYXkgdGhhdCBhIGR3YXJmIGxvcmQgY2FuIGNhcnJ5IGEgcGljay1heGUgYmVjYXVzZSBoaXMgYXJtb3IgaXMgbGlnaHQu" }, + { "They say that a floating eye can defeat Medusa.", + "VGhleSBzYXkgdGhhdCBhIGZsb2F0aW5nIGV5ZSBjYW4gZGVmZWF0IE1lZHVzYS4=" }, + { "They say that a fortune only has 1 line and you can't read between it.", + "VGhleSBzYXkgdGhhdCBhIGZvcnR1bmUgb25seSBoYXMgMSBsaW5lIGFuZCB5b3UgY2FuJ3QgcmVhZCBiZXR3ZWVuIGl0Lg==" }, + { "They say that a fortune only has 1 line, but you can read between it.", + "VGhleSBzYXkgdGhhdCBhIGZvcnR1bmUgb25seSBoYXMgMSBsaW5lLCBidXQgeW91IGNhbiByZWFkIGJldHdlZW4gaXQu" }, + { "They say that a fountain looks nothing like a regularly erupting geyser.", + "VGhleSBzYXkgdGhhdCBhIGZvdW50YWluIGxvb2tzIG5vdGhpbmcgbGlrZSBhIHJlZ3VsYXJseSBlcnVwdGluZyBnZXlzZXIu" }, + { "They say that a gold doubloon is worth more than its weight in gold.", + "VGhleSBzYXkgdGhhdCBhIGdvbGQgZG91Ymxvb24gaXMgd29ydGggbW9yZSB0aGFuIGl0cyB3ZWlnaHQgaW4gZ29sZC4=" }, + { "They say that a grid bug won't pay a shopkeeper for zapping you in a shop.", + "VGhleSBzYXkgdGhhdCBhIGdyaWQgYnVnIHdvbid0IHBheSBhIHNob3BrZWVwZXIgZm9yIHphcHBpbmcgeW91IGluIGEgc2hvcC4=" }, + { "They say that a gypsy could tell your fortune for a price.", + "VGhleSBzYXkgdGhhdCBhIGd5cHN5IGNvdWxkIHRlbGwgeW91ciBmb3J0dW5lIGZvciBhIHByaWNlLg==" }, + { "They say that a hacker named Alice once level teleported by using a mirror.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBBbGljZSBvbmNlIGxldmVsIHRlbGVwb3J0ZWQgYnkgdXNpbmcgYSBtaXJyb3Iu" }, + { "They say that a hacker named David once slew a giant with a sling and a rock.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBEYXZpZCBvbmNlIHNsZXcgYSBnaWFudCB3aXRoIGEgc2xpbmcgYW5kIGEgcm9jay4=" }, + { "They say that a hacker named Dorothy once rode a fog cloud to Oz.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBEb3JvdGh5IG9uY2Ugcm9kZSBhIGZvZyBjbG91ZCB0byBPei4=" }, + { "They say that a hacker named Mary once lost a white sheep in the mazes.", + "VGhleSBzYXkgdGhhdCBhIGhhY2tlciBuYW1lZCBNYXJ5IG9uY2UgbG9zdCBhIHdoaXRlIHNoZWVwIGluIHRoZSBtYXplcy4=" }, + { "They say that a helm of brilliance is not to be taken lightly.", + "VGhleSBzYXkgdGhhdCBhIGhlbG0gb2YgYnJpbGxpYW5jZSBpcyBub3QgdG8gYmUgdGFrZW4gbGlnaHRseS4=" }, + { "They say that a hot dog and a hell hound are the same thing.", + "VGhleSBzYXkgdGhhdCBhIGhvdCBkb2cgYW5kIGEgaGVsbCBob3VuZCBhcmUgdGhlIHNhbWUgdGhpbmcu" }, + { "They say that a lamp named Aladdin's Lamp contains a djinni with 3 wishes.", + "VGhleSBzYXkgdGhhdCBhIGxhbXAgbmFtZWQgQWxhZGRpbidzIExhbXAgY29udGFpbnMgYSBkamlubmkgd2l0aCAzIHdpc2hlcy4=" }, + { "They say that a large dog named Lassie will lead you to the amulet.", + "VGhleSBzYXkgdGhhdCBhIGxhcmdlIGRvZyBuYW1lZCBMYXNzaWUgd2lsbCBsZWFkIHlvdSB0byB0aGUgYW11bGV0Lg==" }, + { "They say that a long sword is not a light sword.", + "VGhleSBzYXkgdGhhdCBhIGxvbmcgc3dvcmQgaXMgbm90IGEgbGlnaHQgc3dvcmQu" }, + { "They say that a manes won't mince words with you.", + "VGhleSBzYXkgdGhhdCBhIG1hbmVzIHdvbid0IG1pbmNlIHdvcmRzIHdpdGggeW91Lg==" }, + { "They say that a mind is a terrible thing to waste.", + "VGhleSBzYXkgdGhhdCBhIG1pbmQgaXMgYSB0ZXJyaWJsZSB0aGluZyB0byB3YXN0ZS4=" }, + { "They say that a plain nymph will only wear a wire ring in one ear.", + "VGhleSBzYXkgdGhhdCBhIHBsYWluIG55bXBoIHdpbGwgb25seSB3ZWFyIGEgd2lyZSByaW5nIGluIG9uZSBlYXIu" }, + { "They say that a plumed hat could be a previously used crested helmet.", + "VGhleSBzYXkgdGhhdCBhIHBsdW1lZCBoYXQgY291bGQgYmUgYSBwcmV2aW91c2x5IHVzZWQgY3Jlc3RlZCBoZWxtZXQu" }, + { "They say that a potion of oil is difficult to grasp.", + "VGhleSBzYXkgdGhhdCBhIHBvdGlvbiBvZiBvaWwgaXMgZGlmZmljdWx0IHRvIGdyYXNwLg==" }, + { "They say that a potion of yogurt is a cancelled potion of sickness.", + "VGhleSBzYXkgdGhhdCBhIHBvdGlvbiBvZiB5b2d1cnQgaXMgYSBjYW5jZWxsZWQgcG90aW9uIG9mIHNpY2tuZXNzLg==" }, + { "They say that a purple worm is not a baby purple dragon.", + "VGhleSBzYXkgdGhhdCBhIHB1cnBsZSB3b3JtIGlzIG5vdCBhIGJhYnkgcHVycGxlIGRyYWdvbi4=" }, + { "They say that a quivering blob tastes different than a gelatinous cube.", + "VGhleSBzYXkgdGhhdCBhIHF1aXZlcmluZyBibG9iIHRhc3RlcyBkaWZmZXJlbnQgdGhhbiBhIGdlbGF0aW5vdXMgY3ViZS4=" }, + { "They say that a runed broadsword named Stormbringer attracts vortices.", + "VGhleSBzYXkgdGhhdCBhIHJ1bmVkIGJyb2Fkc3dvcmQgbmFtZWQgU3Rvcm1icmluZ2VyIGF0dHJhY3RzIHZvcnRpY2VzLg==" }, + { "They say that a scroll of summoning has other names.", + "VGhleSBzYXkgdGhhdCBhIHNjcm9sbCBvZiBzdW1tb25pbmcgaGFzIG90aGVyIG5hbWVzLg==" }, + { "They say that a shaman can bestow blessings but usually doesn't.", + "VGhleSBzYXkgdGhhdCBhIHNoYW1hbiBjYW4gYmVzdG93IGJsZXNzaW5ncyBidXQgdXN1YWxseSBkb2Vzbid0Lg==" }, + { "They say that a shaman will bless you for an eye of newt and wing of bat.", + "VGhleSBzYXkgdGhhdCBhIHNoYW1hbiB3aWxsIGJsZXNzIHlvdSBmb3IgYW4gZXllIG9mIG5ld3QgYW5kIHdpbmcgb2YgYmF0Lg==" }, + { "They say that a shimmering gold shield is not a polished silver shield.", + "VGhleSBzYXkgdGhhdCBhIHNoaW1tZXJpbmcgZ29sZCBzaGllbGQgaXMgbm90IGEgcG9saXNoZWQgc2lsdmVyIHNoaWVsZC4=" }, + { "They say that a spear will hit a neo-otyugh. (Do YOU know what that is?)", + "VGhleSBzYXkgdGhhdCBhIHNwZWFyIHdpbGwgaGl0IGEgbmVvLW90eXVnaC4gKERvIFlPVSBrbm93IHdoYXQgdGhhdCBpcz8p" }, + { "They say that a spotted dragon is the ultimate shape changer.", + "VGhleSBzYXkgdGhhdCBhIHNwb3R0ZWQgZHJhZ29uIGlzIHRoZSB1bHRpbWF0ZSBzaGFwZSBjaGFuZ2VyLg==" }, + { "They say that a stethoscope is no good if you can only hear your heartbeat.", + "VGhleSBzYXkgdGhhdCBhIHN0ZXRob3Njb3BlIGlzIG5vIGdvb2QgaWYgeW91IGNhbiBvbmx5IGhlYXIgeW91ciBoZWFydGJlYXQu" }, + { "They say that a succubus named Suzy will sometimes warn you of danger.", + "VGhleSBzYXkgdGhhdCBhIHN1Y2N1YnVzIG5hbWVkIFN1enkgd2lsbCBzb21ldGltZXMgd2FybiB5b3Ugb2YgZGFuZ2VyLg==" }, + { "They say that a wand of cancellation is not like a wand of polymorph.", + "VGhleSBzYXkgdGhhdCBhIHdhbmQgb2YgY2FuY2VsbGF0aW9uIGlzIG5vdCBsaWtlIGEgd2FuZCBvZiBwb2x5bW9ycGgu" }, + { "They say that a wood golem named Pinocchio would be easy to control.", + "VGhleSBzYXkgdGhhdCBhIHdvb2QgZ29sZW0gbmFtZWQgUGlub2NjaGlvIHdvdWxkIGJlIGVhc3kgdG8gY29udHJvbC4=" }, + { "They say that after killing a dragon it's time for a change of scenery.", + "VGhleSBzYXkgdGhhdCBhZnRlciBraWxsaW5nIGEgZHJhZ29uIGl0J3MgdGltZSBmb3IgYSBjaGFuZ2Ugb2Ygc2NlbmVyeS4=" }, + { "They say that an amulet of strangulation is worse than ring around the collar.", + "VGhleSBzYXkgdGhhdCBhbiBhbXVsZXQgb2Ygc3RyYW5ndWxhdGlvbiBpcyB3b3JzZSB0aGFuIHJpbmcgYXJvdW5kIHRoZSBjb2xsYXIu" }, + { "They say that an attic is the best place to hide your toys.", + "VGhleSBzYXkgdGhhdCBhbiBhdHRpYyBpcyB0aGUgYmVzdCBwbGFjZSB0byBoaWRlIHlvdXIgdG95cy4=" }, + { "They say that an axe named Cleaver once belonged to a hacker named Beaver.", + "VGhleSBzYXkgdGhhdCBhbiBheGUgbmFtZWQgQ2xlYXZlciBvbmNlIGJlbG9uZ2VkIHRvIGEgaGFja2VyIG5hbWVkIEJlYXZlci4=" }, + { "They say that an eye of newt and a wing of bat are double the trouble.", + "VGhleSBzYXkgdGhhdCBhbiBleWUgb2YgbmV3dCBhbmQgYSB3aW5nIG9mIGJhdCBhcmUgZG91YmxlIHRoZSB0cm91YmxlLg==" }, + { "They say that an incubus named Izzy sometimes makes women feel sensitive.", + "VGhleSBzYXkgdGhhdCBhbiBpbmN1YnVzIG5hbWVkIEl6enkgc29tZXRpbWVzIG1ha2VzIHdvbWVuIGZlZWwgc2Vuc2l0aXZlLg==" }, + { "They say that an opulent throne room is rarely a place to wish you'd be in.", + "VGhleSBzYXkgdGhhdCBhbiBvcHVsZW50IHRocm9uZSByb29tIGlzIHJhcmVseSBhIHBsYWNlIHRvIHdpc2ggeW91J2QgYmUgaW4u" }, + { "They say that an unlucky hacker once had a nose bleed at an altar and died.", + "VGhleSBzYXkgdGhhdCBhbiB1bmx1Y2t5IGhhY2tlciBvbmNlIGhhZCBhIG5vc2UgYmxlZWQgYXQgYW4gYWx0YXIgYW5kIGRpZWQu" }, + { "They say that and they say this but they never say never, never!", + "VGhleSBzYXkgdGhhdCBhbmQgdGhleSBzYXkgdGhpcyBidXQgdGhleSBuZXZlciBzYXkgbmV2ZXIsIG5ldmVyIQ==" }, + { "They say that any quantum mechanic knows that speed kills.", + "VGhleSBzYXkgdGhhdCBhbnkgcXVhbnR1bSBtZWNoYW5pYyBrbm93cyB0aGF0IHNwZWVkIGtpbGxzLg==" }, + { "They say that applying a unicorn horn means you've missed the point.", + "VGhleSBzYXkgdGhhdCBhcHBseWluZyBhIHVuaWNvcm4gaG9ybiBtZWFucyB5b3UndmUgbWlzc2VkIHRoZSBwb2ludC4=" }, + { "They say that blue stones are radioactive, beware.", + "VGhleSBzYXkgdGhhdCBibHVlIHN0b25lcyBhcmUgcmFkaW9hY3RpdmUsIGJld2FyZS4=" }, + { "They say that building a dungeon is a team effort.", + "VGhleSBzYXkgdGhhdCBidWlsZGluZyBhIGR1bmdlb24gaXMgYSB0ZWFtIGVmZm9ydC4=" }, + { "They say that chaotic characters never get a kick out of altars.", + "VGhleSBzYXkgdGhhdCBjaGFvdGljIGNoYXJhY3RlcnMgbmV2ZXIgZ2V0IGEga2ljayBvdXQgb2YgYWx0YXJzLg==" }, + { "They say that collapsing a dungeon often creates a panic.", + "VGhleSBzYXkgdGhhdCBjb2xsYXBzaW5nIGEgZHVuZ2VvbiBvZnRlbiBjcmVhdGVzIGEgcGFuaWMu" }, + { "They say that counting your eggs before they hatch shows that you care.", + "VGhleSBzYXkgdGhhdCBjb3VudGluZyB5b3VyIGVnZ3MgYmVmb3JlIHRoZXkgaGF0Y2ggc2hvd3MgdGhhdCB5b3UgY2FyZS4=" }, + { "They say that dipping a bag of tricks in a fountain won't make it an icebox.", + "VGhleSBzYXkgdGhhdCBkaXBwaW5nIGEgYmFnIG9mIHRyaWNrcyBpbiBhIGZvdW50YWluIHdvbid0IG1ha2UgaXQgYW4gaWNlYm94Lg==" }, + { "They say that dipping an eel and brown mold in hot water makes bouillabaisse.", + "VGhleSBzYXkgdGhhdCBkaXBwaW5nIGFuIGVlbCBhbmQgYnJvd24gbW9sZCBpbiBob3Qgd2F0ZXIgbWFrZXMgYm91aWxsYWJhaXNzZS4=" }, + { "They say that donating a doubloon is extremely pious charity.", + "VGhleSBzYXkgdGhhdCBkb25hdGluZyBhIGRvdWJsb29uIGlzIGV4dHJlbWVseSBwaW91cyBjaGFyaXR5Lg==" }, + { "They say that eating royal jelly attracts grizzly owlbears.", + "VGhleSBzYXkgdGhhdCBlYXRpbmcgcm95YWwgamVsbHkgYXR0cmFjdHMgZ3JpenpseSBvd2xiZWFycy4=" }, + { "They say that eggs, pancakes and juice are just a mundane breakfast.", + "VGhleSBzYXkgdGhhdCBlZ2dzLCBwYW5jYWtlcyBhbmQganVpY2UgYXJlIGp1c3QgYSBtdW5kYW5lIGJyZWFrZmFzdC4=" }, + { "They say that everyone knows why Medusa stands alone in the dark.", + "VGhleSBzYXkgdGhhdCBldmVyeW9uZSBrbm93cyB3aHkgTWVkdXNhIHN0YW5kcyBhbG9uZSBpbiB0aGUgZGFyay4=" }, + { "They say that everyone wanted rec.games.hack to undergo a name change.", + "VGhleSBzYXkgdGhhdCBldmVyeW9uZSB3YW50ZWQgcmVjLmdhbWVzLmhhY2sgdG8gdW5kZXJnbyBhIG5hbWUgY2hhbmdlLg==" }, + { "They say that finding a winning strategy is a deliberate move on your part.", + "VGhleSBzYXkgdGhhdCBmaW5kaW5nIGEgd2lubmluZyBzdHJhdGVneSBpcyBhIGRlbGliZXJhdGUgbW92ZSBvbiB5b3VyIHBhcnQu" }, + { "They say that finding worthless glass is worth something.", + "VGhleSBzYXkgdGhhdCBmaW5kaW5nIHdvcnRobGVzcyBnbGFzcyBpcyB3b3J0aCBzb21ldGhpbmcu" }, + { "They say that fortune cookies are food for thought.", + "VGhleSBzYXkgdGhhdCBmb3J0dW5lIGNvb2tpZXMgYXJlIGZvb2QgZm9yIHRob3VnaHQu" }, + { "They say that gold is only wasted on a pet dragon.", + "VGhleSBzYXkgdGhhdCBnb2xkIGlzIG9ubHkgd2FzdGVkIG9uIGEgcGV0IGRyYWdvbi4=" }, + { "They say that good things come to those that wait.", + "VGhleSBzYXkgdGhhdCBnb29kIHRoaW5ncyBjb21lIHRvIHRob3NlIHRoYXQgd2FpdC4=" }, + { "They say that greased objects will slip out of monsters' hands.", + "VGhleSBzYXkgdGhhdCBncmVhc2VkIG9iamVjdHMgd2lsbCBzbGlwIG91dCBvZiBtb25zdGVycycgaGFuZHMu" }, + { "They say that if you can't spell then you'll wish you had a spell book.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgY2FuJ3Qgc3BlbGwgdGhlbiB5b3UnbGwgd2lzaCB5b3UgaGFkIGEgc3BlbGwgYm9vay4=" }, + { "They say that if you live by the sword, you'll die by the sword.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgbGl2ZSBieSB0aGUgc3dvcmQsIHlvdSdsbCBkaWUgYnkgdGhlIHN3b3JkLg==" }, + { "They say that if you play like a monster you'll have a better game.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UgcGxheSBsaWtlIGEgbW9uc3RlciB5b3UnbGwgaGF2ZSBhIGJldHRlciBnYW1lLg==" }, + { "They say that if you sleep with a demon you might awake with a headache.", + "VGhleSBzYXkgdGhhdCBpZiB5b3Ugc2xlZXAgd2l0aCBhIGRlbW9uIHlvdSBtaWdodCBhd2FrZSB3aXRoIGEgaGVhZGFjaGUu" }, + { "They say that if you step on a crack you could break your mother's back.", + "VGhleSBzYXkgdGhhdCBpZiB5b3Ugc3RlcCBvbiBhIGNyYWNrIHlvdSBjb3VsZCBicmVhayB5b3VyIG1vdGhlcidzIGJhY2su" }, + { "They say that if you're invisible you can still be heard!", + "VGhleSBzYXkgdGhhdCBpZiB5b3UncmUgaW52aXNpYmxlIHlvdSBjYW4gc3RpbGwgYmUgaGVhcmQh" }, + { "They say that if you're lucky you can feel the runes on a scroll.", + "VGhleSBzYXkgdGhhdCBpZiB5b3UncmUgbHVja3kgeW91IGNhbiBmZWVsIHRoZSBydW5lcyBvbiBhIHNjcm9sbC4=" }, + { "They say that in the big picture gold is only small change.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgYmlnIHBpY3R1cmUgZ29sZCBpcyBvbmx5IHNtYWxsIGNoYW5nZS4=" }, + { "They say that in the dungeon it's not what you know that really matters.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiBpdCdzIG5vdCB3aGF0IHlvdSBrbm93IHRoYXQgcmVhbGx5IG1hdHRlcnMu" }, + { "They say that in the dungeon moon rocks are really dilithium crystals.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiBtb29uIHJvY2tzIGFyZSByZWFsbHkgZGlsaXRoaXVtIGNyeXN0YWxzLg==" }, + { "They say that in the dungeon the boorish customer is never right.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB0aGUgYm9vcmlzaCBjdXN0b21lciBpcyBuZXZlciByaWdodC4=" }, + { "They say that in the dungeon you don't need a watch to tell time.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3UgZG9uJ3QgbmVlZCBhIHdhdGNoIHRvIHRlbGwgdGltZS4=" }, + { "They say that in the dungeon you need something old, new, burrowed and blue.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3UgbmVlZCBzb21ldGhpbmcgb2xkLCBuZXcsIGJ1cnJvd2VkIGFuZCBibHVlLg==" }, + { "They say that in the dungeon you should always count your blessings.", + "VGhleSBzYXkgdGhhdCBpbiB0aGUgZHVuZ2VvbiB5b3Ugc2hvdWxkIGFsd2F5cyBjb3VudCB5b3VyIGJsZXNzaW5ncy4=" }, + { "They say that iron golem plate mail isn't worth wishing for.", + "VGhleSBzYXkgdGhhdCBpcm9uIGdvbGVtIHBsYXRlIG1haWwgaXNuJ3Qgd29ydGggd2lzaGluZyBmb3Iu" }, + { "They say that it takes four quarterstaffs to make one staff.", + "VGhleSBzYXkgdGhhdCBpdCB0YWtlcyBmb3VyIHF1YXJ0ZXJzdGFmZnMgdG8gbWFrZSBvbmUgc3RhZmYu" }, + { "They say that it's not over till the fat ladies sing.", + "VGhleSBzYXkgdGhhdCBpdCdzIG5vdCBvdmVyIHRpbGwgdGhlIGZhdCBsYWRpZXMgc2luZy4=" }, + { "They say that it's not over till the fat lady shouts `Off with its head'.", + "VGhleSBzYXkgdGhhdCBpdCdzIG5vdCBvdmVyIHRpbGwgdGhlIGZhdCBsYWR5IHNob3V0cyBgT2ZmIHdpdGggaXRzIGhlYWQnLg==" }, + { "They say that kicking a heavy statue is really a dumb move.", + "VGhleSBzYXkgdGhhdCBraWNraW5nIGEgaGVhdnkgc3RhdHVlIGlzIHJlYWxseSBhIGR1bWIgbW92ZS4=" }, + { "They say that kicking a valuable gem doesn't seem to make sense.", + "VGhleSBzYXkgdGhhdCBraWNraW5nIGEgdmFsdWFibGUgZ2VtIGRvZXNuJ3Qgc2VlbSB0byBtYWtlIHNlbnNlLg==" }, + { "They say that leprechauns know Latin and you should too.", + "VGhleSBzYXkgdGhhdCBsZXByZWNoYXVucyBrbm93IExhdGluIGFuZCB5b3Ugc2hvdWxkIHRvby4=" }, + { "They say that minotaurs get lost outside of the mazes.", + "VGhleSBzYXkgdGhhdCBtaW5vdGF1cnMgZ2V0IGxvc3Qgb3V0c2lkZSBvZiB0aGUgbWF6ZXMu" }, + { "They say that most trolls are born again.", + "VGhleSBzYXkgdGhhdCBtb3N0IHRyb2xscyBhcmUgYm9ybiBhZ2Fpbi4=" }, + { "They say that naming your cat Garfield will make you more attractive.", + "VGhleSBzYXkgdGhhdCBuYW1pbmcgeW91ciBjYXQgR2FyZmllbGQgd2lsbCBtYWtlIHlvdSBtb3JlIGF0dHJhY3RpdmUu" }, + { "They say that no one knows everything about everything in the dungeon.", + "VGhleSBzYXkgdGhhdCBubyBvbmUga25vd3MgZXZlcnl0aGluZyBhYm91dCBldmVyeXRoaW5nIGluIHRoZSBkdW5nZW9uLg==" }, + { "They say that no one plays NetHack just for the fun of it.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgcGxheXMgTmV0SGFjayBqdXN0IGZvciB0aGUgZnVuIG9mIGl0Lg==" }, + { "They say that no one really subscribes to rec.games.roguelike.nethack.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgcmVhbGx5IHN1YnNjcmliZXMgdG8gcmVjLmdhbWVzLnJvZ3VlbGlrZS5uZXRoYWNrLg==" }, + { "They say that no one will admit to starting a rumor.", + "VGhleSBzYXkgdGhhdCBubyBvbmUgd2lsbCBhZG1pdCB0byBzdGFydGluZyBhIHJ1bW9yLg==" }, + { "They say that nurses sometimes carry scalpels and never use them.", + "VGhleSBzYXkgdGhhdCBudXJzZXMgc29tZXRpbWVzIGNhcnJ5IHNjYWxwZWxzIGFuZCBuZXZlciB1c2UgdGhlbS4=" }, + { "They say that once you've met one wizard you've met them all.", + "VGhleSBzYXkgdGhhdCBvbmNlIHlvdSd2ZSBtZXQgb25lIHdpemFyZCB5b3UndmUgbWV0IHRoZW0gYWxsLg==" }, + { "They say that one troll is worth 10,000 newts.", + "VGhleSBzYXkgdGhhdCBvbmUgdHJvbGwgaXMgd29ydGggMTAsMDAwIG5ld3RzLg==" }, + { "They say that only David can find the zoo!", + "VGhleSBzYXkgdGhhdCBvbmx5IERhdmlkIGNhbiBmaW5kIHRoZSB6b28h" }, + { "They say that only angels play their harps for their pets.", + "VGhleSBzYXkgdGhhdCBvbmx5IGFuZ2VscyBwbGF5IHRoZWlyIGhhcnBzIGZvciB0aGVpciBwZXRzLg==" }, + { "They say that only big spenders carry gold.", + "VGhleSBzYXkgdGhhdCBvbmx5IGJpZyBzcGVuZGVycyBjYXJyeSBnb2xkLg==" }, + { "They say that orc shamans are healthy, wealthy and wise.", + "VGhleSBzYXkgdGhhdCBvcmMgc2hhbWFucyBhcmUgaGVhbHRoeSwgd2VhbHRoeSBhbmQgd2lzZS4=" }, + { "They say that playing NetHack is like walking into a death trap.", + "VGhleSBzYXkgdGhhdCBwbGF5aW5nIE5ldEhhY2sgaXMgbGlrZSB3YWxraW5nIGludG8gYSBkZWF0aCB0cmFwLg==" }, + { "They say that problem breathing is best treated by a proper diet.", + "VGhleSBzYXkgdGhhdCBwcm9ibGVtIGJyZWF0aGluZyBpcyBiZXN0IHRyZWF0ZWQgYnkgYSBwcm9wZXIgZGlldC4=" }, + { "They say that quaffing many potions of levitation can give you a headache.", + "VGhleSBzYXkgdGhhdCBxdWFmZmluZyBtYW55IHBvdGlvbnMgb2YgbGV2aXRhdGlvbiBjYW4gZ2l2ZSB5b3UgYSBoZWFkYWNoZS4=" }, + { "They say that queen bees get that way by eating royal jelly.", + "VGhleSBzYXkgdGhhdCBxdWVlbiBiZWVzIGdldCB0aGF0IHdheSBieSBlYXRpbmcgcm95YWwgamVsbHku" }, + { "They say that reading a scare monster scroll is the same as saying Elbereth.", + "VGhleSBzYXkgdGhhdCByZWFkaW5nIGEgc2NhcmUgbW9uc3RlciBzY3JvbGwgaXMgdGhlIHNhbWUgYXMgc2F5aW5nIEVsYmVyZXRoLg==" }, + { "They say that real hackers always are controlled.", + "VGhleSBzYXkgdGhhdCByZWFsIGhhY2tlcnMgYWx3YXlzIGFyZSBjb250cm9sbGVkLg==" }, + { "They say that real hackers never sleep.", + "VGhleSBzYXkgdGhhdCByZWFsIGhhY2tlcnMgbmV2ZXIgc2xlZXAu" }, + { "They say that shopkeepers are insured by Croesus himself!", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBhcmUgaW5zdXJlZCBieSBDcm9lc3VzIGhpbXNlbGYh" }, + { "They say that shopkeepers never carry more than 20 gold pieces, at night.", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBuZXZlciBjYXJyeSBtb3JlIHRoYW4gMjAgZ29sZCBwaWVjZXMsIGF0IG5pZ2h0Lg==" }, + { "They say that shopkeepers never sell blessed potions of invisibility.", + "VGhleSBzYXkgdGhhdCBzaG9wa2VlcGVycyBuZXZlciBzZWxsIGJsZXNzZWQgcG90aW9ucyBvZiBpbnZpc2liaWxpdHku" }, + { "They say that soldiers wear kid gloves and silly helmets.", + "VGhleSBzYXkgdGhhdCBzb2xkaWVycyB3ZWFyIGtpZCBnbG92ZXMgYW5kIHNpbGx5IGhlbG1ldHMu" }, + { "They say that some Kops are on the take.", + "VGhleSBzYXkgdGhhdCBzb21lIEtvcHMgYXJlIG9uIHRoZSB0YWtlLg==" }, + { "They say that some guards' palms can be greased.", + "VGhleSBzYXkgdGhhdCBzb21lIGd1YXJkcycgcGFsbXMgY2FuIGJlIGdyZWFzZWQu" }, + { "They say that some monsters may kiss your boots to stop your drum playing.", + "VGhleSBzYXkgdGhhdCBzb21lIG1vbnN0ZXJzIG1heSBraXNzIHlvdXIgYm9vdHMgdG8gc3RvcCB5b3VyIGRydW0gcGxheWluZy4=" }, + { "They say that sometimes you can be the hit of the party when playing a horn.", + "VGhleSBzYXkgdGhhdCBzb21ldGltZXMgeW91IGNhbiBiZSB0aGUgaGl0IG9mIHRoZSBwYXJ0eSB3aGVuIHBsYXlpbmcgYSBob3JuLg==" }, + { "They say that the NetHack gods generally welcome your sacrifices.", + "VGhleSBzYXkgdGhhdCB0aGUgTmV0SGFjayBnb2RzIGdlbmVyYWxseSB3ZWxjb21lIHlvdXIgc2FjcmlmaWNlcy4=" }, + { "They say that the Three Rings are named Vilya, Nenya and Narya.", + "VGhleSBzYXkgdGhhdCB0aGUgVGhyZWUgUmluZ3MgYXJlIG5hbWVkIFZpbHlhLCBOZW55YSBhbmQgTmFyeWEu" }, + { "They say that the Wizard of Yendor has a death wish.", + "VGhleSBzYXkgdGhhdCB0aGUgV2l6YXJkIG9mIFllbmRvciBoYXMgYSBkZWF0aCB3aXNoLg==" }, + { "They say that the `hair of the dog' is sometimes an effective remedy.", + "VGhleSBzYXkgdGhhdCB0aGUgYGhhaXIgb2YgdGhlIGRvZycgaXMgc29tZXRpbWVzIGFuIGVmZmVjdGl2ZSByZW1lZHku" }, + { "They say that the best time to save your game is now before its too late.", + "VGhleSBzYXkgdGhhdCB0aGUgYmVzdCB0aW1lIHRvIHNhdmUgeW91ciBnYW1lIGlzIG5vdyBiZWZvcmUgaXRzIHRvbyBsYXRlLg==" }, + { "They say that the biggest obstacle in NetHack is your mind.", + "VGhleSBzYXkgdGhhdCB0aGUgYmlnZ2VzdCBvYnN0YWNsZSBpbiBOZXRIYWNrIGlzIHlvdXIgbWluZC4=" }, + { "They say that the gods are angry when they hit you with objects.", + "VGhleSBzYXkgdGhhdCB0aGUgZ29kcyBhcmUgYW5ncnkgd2hlbiB0aGV5IGhpdCB5b3Ugd2l0aCBvYmplY3RzLg==" }, + { "They say that the priesthood are specially favored by the gods.", + "VGhleSBzYXkgdGhhdCB0aGUgcHJpZXN0aG9vZCBhcmUgc3BlY2lhbGx5IGZhdm9yZWQgYnkgdGhlIGdvZHMu" }, + { "They say that the way to make a unicorn happy is to give it what it wants.", + "VGhleSBzYXkgdGhhdCB0aGUgd2F5IHRvIG1ha2UgYSB1bmljb3JuIGhhcHB5IGlzIHRvIGdpdmUgaXQgd2hhdCBpdCB3YW50cy4=" }, + { "They say that there are no black or white stones, only gray.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBhcmUgbm8gYmxhY2sgb3Igd2hpdGUgc3RvbmVzLCBvbmx5IGdyYXku" }, + { "They say that there are no skeletons hence there are no skeleton keys.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBhcmUgbm8gc2tlbGV0b25zIGhlbmNlIHRoZXJlIGFyZSBubyBza2VsZXRvbiBrZXlzLg==" }, + { "They say that there is a clever rogue in every hacker just dying to escape.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBhIGNsZXZlciByb2d1ZSBpbiBldmVyeSBoYWNrZXIganVzdCBkeWluZyB0byBlc2NhcGUu" }, + { "They say that there is no such thing as free advice.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBubyBzdWNoIHRoaW5nIGFzIGZyZWUgYWR2aWNlLg==" }, + { "They say that there is only one way to win at NetHack.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBpcyBvbmx5IG9uZSB3YXkgdG8gd2luIGF0IE5ldEhhY2su" }, + { "They say that there once was a fearsome chaotic samurai named Luk No.", + "VGhleSBzYXkgdGhhdCB0aGVyZSBvbmNlIHdhcyBhIGZlYXJzb21lIGNoYW90aWMgc2FtdXJhaSBuYW1lZCBMdWsgTm8u" }, + { "They say that there was a time when cursed holy water wasn't water.", + "VGhleSBzYXkgdGhhdCB0aGVyZSB3YXMgYSB0aW1lIHdoZW4gY3Vyc2VkIGhvbHkgd2F0ZXIgd2Fzbid0IHdhdGVyLg==" }, + { "They say that there's no point in crying over a gray ooze.", + "VGhleSBzYXkgdGhhdCB0aGVyZSdzIG5vIHBvaW50IGluIGNyeWluZyBvdmVyIGEgZ3JheSBvb3plLg==" }, + { "They say that there's only hope left after you've opened Pandora's box.", + "VGhleSBzYXkgdGhhdCB0aGVyZSdzIG9ubHkgaG9wZSBsZWZ0IGFmdGVyIHlvdSd2ZSBvcGVuZWQgUGFuZG9yYSdzIGJveC4=" }, + { "They say that trapdoors should always be marked `Caution: Trap Door'.", + "VGhleSBzYXkgdGhhdCB0cmFwZG9vcnMgc2hvdWxkIGFsd2F5cyBiZSBtYXJrZWQgYENhdXRpb246IFRyYXAgRG9vcicu" }, + { "They say that using an amulet of change isn't a difficult operation.", + "VGhleSBzYXkgdGhhdCB1c2luZyBhbiBhbXVsZXQgb2YgY2hhbmdlIGlzbid0IGEgZGlmZmljdWx0IG9wZXJhdGlvbi4=" }, + { "They say that water walking boots are better if you are fast like Hermes.", + "VGhleSBzYXkgdGhhdCB3YXRlciB3YWxraW5nIGJvb3RzIGFyZSBiZXR0ZXIgaWYgeW91IGFyZSBmYXN0IGxpa2UgSGVybWVzLg==" }, + { "They say that when you wear a circular amulet you might resemble a troll.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdSB3ZWFyIGEgY2lyY3VsYXIgYW11bGV0IHlvdSBtaWdodCByZXNlbWJsZSBhIHRyb2xsLg==" }, + { "They say that when you're hungry you can get a pizza in 30 moves or it's free.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdSdyZSBodW5ncnkgeW91IGNhbiBnZXQgYSBwaXp6YSBpbiAzMCBtb3ZlcyBvciBpdCdzIGZyZWUu" }, + { "They say that when your god is angry you should try another one.", + "VGhleSBzYXkgdGhhdCB3aGVuIHlvdXIgZ29kIGlzIGFuZ3J5IHlvdSBzaG91bGQgdHJ5IGFub3RoZXIgb25lLg==" }, + { "They say that wielding a unicorn horn takes strength.", + "VGhleSBzYXkgdGhhdCB3aWVsZGluZyBhIHVuaWNvcm4gaG9ybiB0YWtlcyBzdHJlbmd0aC4=" }, + { "They say that with speed boots you never worry about hit and run accidents.", + "VGhleSBzYXkgdGhhdCB3aXRoIHNwZWVkIGJvb3RzIHlvdSBuZXZlciB3b3JyeSBhYm91dCBoaXQgYW5kIHJ1biBhY2NpZGVudHMu" }, + { "They say that you can defeat a killer bee with a unicorn horn.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIGRlZmVhdCBhIGtpbGxlciBiZWUgd2l0aCBhIHVuaWNvcm4gaG9ybi4=" }, + { "They say that you can only cross the River Styx in Charon's boat.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkgY3Jvc3MgdGhlIFJpdmVyIFN0eXggaW4gQ2hhcm9uJ3MgYm9hdC4=" }, + { "They say that you can only kill a lich once and then you'd better be careful.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkga2lsbCBhIGxpY2ggb25jZSBhbmQgdGhlbiB5b3UnZCBiZXR0ZXIgYmUgY2FyZWZ1bC4=" }, + { "They say that you can only wish for things you've already had.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIG9ubHkgd2lzaCBmb3IgdGhpbmdzIHlvdSd2ZSBhbHJlYWR5IGhhZC4=" }, + { "They say that you can train a cat by talking gently to it.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRyYWluIGEgY2F0IGJ5IHRhbGtpbmcgZ2VudGx5IHRvIGl0Lg==" }, + { "They say that you can train a dog by talking firmly to it.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRyYWluIGEgZG9nIGJ5IHRhbGtpbmcgZmlybWx5IHRvIGl0Lg==" }, + { "They say that you can trust your gold with the king.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuIHRydXN0IHlvdXIgZ29sZCB3aXRoIHRoZSBraW5nLg==" }, + { "They say that you can't wipe your greasy bare hands on a blank scroll.", + "VGhleSBzYXkgdGhhdCB5b3UgY2FuJ3Qgd2lwZSB5b3VyIGdyZWFzeSBiYXJlIGhhbmRzIG9uIGEgYmxhbmsgc2Nyb2xsLg==" }, + { "They say that you cannot trust scrolls of rumor.", + "VGhleSBzYXkgdGhhdCB5b3UgY2Fubm90IHRydXN0IHNjcm9sbHMgb2YgcnVtb3Iu" }, + { "They say that you could fall head over heels for an energy vortex.", + "VGhleSBzYXkgdGhhdCB5b3UgY291bGQgZmFsbCBoZWFkIG92ZXIgaGVlbHMgZm9yIGFuIGVuZXJneSB2b3J0ZXgu" }, + { "They say that you need a key in order to open locked doors.", + "VGhleSBzYXkgdGhhdCB5b3UgbmVlZCBhIGtleSBpbiBvcmRlciB0byBvcGVuIGxvY2tlZCBkb29ycy4=" }, + { "They say that you need a mirror to notice a mimic in an antique shop.", + "VGhleSBzYXkgdGhhdCB5b3UgbmVlZCBhIG1pcnJvciB0byBub3RpY2UgYSBtaW1pYyBpbiBhbiBhbnRpcXVlIHNob3Au" }, + { "They say that you really can use a pick-axe unless you really can't.", + "VGhleSBzYXkgdGhhdCB5b3UgcmVhbGx5IGNhbiB1c2UgYSBwaWNrLWF4ZSB1bmxlc3MgeW91IHJlYWxseSBjYW4ndC4=" }, + { "They say that you should always store your tools in the cellar.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGFsd2F5cyBzdG9yZSB5b3VyIHRvb2xzIGluIHRoZSBjZWxsYXIu" }, + { "They say that you should be careful while climbing the ladder to success.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGJlIGNhcmVmdWwgd2hpbGUgY2xpbWJpbmcgdGhlIGxhZGRlciB0byBzdWNjZXNzLg==" }, + { "They say that you should call your armor `rustproof'.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIGNhbGwgeW91ciBhcm1vciBgcnVzdHByb29mJy4=" }, + { "They say that you should name your dog Spuds to have a cool pet.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5hbWUgeW91ciBkb2cgU3B1ZHMgdG8gaGF2ZSBhIGNvb2wgcGV0Lg==" }, + { "They say that you should name your weapon after your first monster kill.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5hbWUgeW91ciB3ZWFwb24gYWZ0ZXIgeW91ciBmaXJzdCBtb25zdGVyIGtpbGwu" }, + { "They say that you should never introduce a rope golem to a succubus.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIGludHJvZHVjZSBhIHJvcGUgZ29sZW0gdG8gYSBzdWNjdWJ1cy4=" }, + { "They say that you should never sleep near invisible ring wraiths.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIHNsZWVwIG5lYXIgaW52aXNpYmxlIHJpbmcgd3JhaXRocy4=" }, + { "They say that you should never try to leave the dungeon with a bag of gems.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIHRyeSB0byBsZWF2ZSB0aGUgZHVuZ2VvbiB3aXRoIGEgYmFnIG9mIGdlbXMu" }, + { "They say that you should remove your armor before sitting on a throne.", + "VGhleSBzYXkgdGhhdCB5b3Ugc2hvdWxkIHJlbW92ZSB5b3VyIGFybW9yIGJlZm9yZSBzaXR0aW5nIG9uIGEgdGhyb25lLg==" }, + { "This fortune cookie is copy protected.", + "VGhpcyBmb3J0dW5lIGNvb2tpZSBpcyBjb3B5IHByb3RlY3RlZC4=" }, + { "This fortune cookie is the property of Fortune Cookies, Inc.", + "VGhpcyBmb3J0dW5lIGNvb2tpZSBpcyB0aGUgcHJvcGVydHkgb2YgRm9ydHVuZSBDb29raWVzLCBJbmMu" }, + { "Tired? Try a scroll of charging on yourself.", + "VGlyZWQ/IFRyeSBhIHNjcm9sbCBvZiBjaGFyZ2luZyBvbiB5b3Vyc2VsZi4=" }, + { "To achieve the next higher rating, you need 3 more points.", + "VG8gYWNoaWV2ZSB0aGUgbmV4dCBoaWdoZXIgcmF0aW5nLCB5b3UgbmVlZCAzIG1vcmUgcG9pbnRzLg==" }, + { "To reach heaven, escape the dungeon while wearing a ring of levitation.", + "VG8gcmVhY2ggaGVhdmVuLCBlc2NhcGUgdGhlIGR1bmdlb24gd2hpbGUgd2VhcmluZyBhIHJpbmcgb2YgbGV2aXRhdGlvbi4=" }, + { "Tourists wear shirts loud enough to wake the dead.", + "VG91cmlzdHMgd2VhciBzaGlydHMgbG91ZCBlbm91Z2ggdG8gd2FrZSB0aGUgZGVhZC4=" }, + { "Try calling your katana Moulinette.", + "VHJ5IGNhbGxpbmcgeW91ciBrYXRhbmEgTW91bGluZXR0ZS4=" }, + { "Ulch! That meat was painted!", + "VWxjaCEgVGhhdCBtZWF0IHdhcyBwYWludGVkIQ==" }, + { "Unfortunately, this message was left intentionally blank.", + "VW5mb3J0dW5hdGVseSwgdGhpcyBtZXNzYWdlIHdhcyBsZWZ0IGludGVudGlvbmFsbHkgYmxhbmsu" }, + { "Using a morning star in the evening has no effect.", + "VXNpbmcgYSBtb3JuaW5nIHN0YXIgaW4gdGhlIGV2ZW5pbmcgaGFzIG5vIGVmZmVjdC4=" }, + { "Want a hint? Zap a wand of make invisible on your weapon!", + "V2FudCBhIGhpbnQ/IFphcCBhIHdhbmQgb2YgbWFrZSBpbnZpc2libGUgb24geW91ciB3ZWFwb24h" }, + { "Want to ascend in a hurry? Apply at Gizmonic Institute.", + "V2FudCB0byBhc2NlbmQgaW4gYSBodXJyeT8gQXBwbHkgYXQgR2l6bW9uaWMgSW5zdGl0dXRlLg==" }, + { "Wanted: shopkeepers. Send a scroll of mail to Mage of Yendor/Level 35/Dungeon.", + "V2FudGVkOiBzaG9wa2VlcGVycy4gU2VuZCBhIHNjcm9sbCBvZiBtYWlsIHRvIE1hZ2Ugb2YgWWVuZG9yL0xldmVsIDM1L0R1bmdlb24u" }, + { "Warning: fortune reading can be hazardous to your health.", + "V2FybmluZzogZm9ydHVuZSByZWFkaW5nIGNhbiBiZSBoYXphcmRvdXMgdG8geW91ciBoZWFsdGgu" }, + { "We have new ways of detecting treachery...", + "V2UgaGF2ZSBuZXcgd2F5cyBvZiBkZXRlY3RpbmcgdHJlYWNoZXJ5Li4u" }, + { "Wet towels make great weapons!", + "V2V0IHRvd2VscyBtYWtlIGdyZWF0IHdlYXBvbnMh" }, + { "What a pity, you cannot read it!", + "V2hhdCBhIHBpdHksIHlvdSBjYW5ub3QgcmVhZCBpdCE=" }, + { "When a piercer drops in on you, you will be tempted to hit the ceiling!", + "V2hlbiBhIHBpZXJjZXIgZHJvcHMgaW4gb24geW91LCB5b3Ugd2lsbCBiZSB0ZW1wdGVkIHRvIGhpdCB0aGUgY2VpbGluZyE=" }, + { "When in a maze follow the right wall and you will never get lost.", + "V2hlbiBpbiBhIG1hemUgZm9sbG93IHRoZSByaWdodCB3YWxsIGFuZCB5b3Ugd2lsbCBuZXZlciBnZXQgbG9zdC4=" }, + { "When you have a key, you don't have to wait for the guard.", + "V2hlbiB5b3UgaGF2ZSBhIGtleSwgeW91IGRvbid0IGhhdmUgdG8gd2FpdCBmb3IgdGhlIGd1YXJkLg==" }, + { "Why are you wasting time reading fortunes?", + "V2h5IGFyZSB5b3Ugd2FzdGluZyB0aW1lIHJlYWRpbmcgZm9ydHVuZXM/" }, + { "Wish for a master key and open the Magic Memory Vault!", + "V2lzaCBmb3IgYSBtYXN0ZXIga2V5IGFuZCBvcGVuIHRoZSBNYWdpYyBNZW1vcnkgVmF1bHQh" }, + { "Wizard expects every monster to do its duty.", + "V2l6YXJkIGV4cGVjdHMgZXZlcnkgbW9uc3RlciB0byBkbyBpdHMgZHV0eS4=" }, + { "Wow! You could've had a potion of fruit juice!", + "V293ISBZb3UgY291bGQndmUgaGFkIGEgcG90aW9uIG9mIGZydWl0IGp1aWNlIQ==" }, + { "Yet Another Silly Message (YASM).", + "WWV0IEFub3RoZXIgU2lsbHkgTWVzc2FnZSAoWUFTTSku" }, + { "You are destined to be misled by a fortune.", + "WW91IGFyZSBkZXN0aW5lZCB0byBiZSBtaXNsZWQgYnkgYSBmb3J0dW5lLg==" }, + { "You can get a genuine Amulet of Yendor by doing the following: --More--", + "WW91IGNhbiBnZXQgYSBnZW51aW5lIEFtdWxldCBvZiBZZW5kb3IgYnkgZG9pbmcgdGhlIGZvbGxvd2luZzogLS1Nb3JlLS0=" }, + { "You can protect yourself from black dragons by doing the following: --More--", + "WW91IGNhbiBwcm90ZWN0IHlvdXJzZWxmIGZyb20gYmxhY2sgZHJhZ29ucyBieSBkb2luZyB0aGUgZm9sbG93aW5nOiAtLU1vcmUtLQ==" }, + { "You can't get by the snake.", + "WW91IGNhbid0IGdldCBieSB0aGUgc25ha2Uu" }, + { "You feel like someone is pulling your leg.", + "WW91IGZlZWwgbGlrZSBzb21lb25lIGlzIHB1bGxpbmcgeW91ciBsZWcu" }, + { "You have to outwit the Sphynx or pay her.", + "WW91IGhhdmUgdG8gb3V0d2l0IHRoZSBTcGh5bnggb3IgcGF5IGhlci4=" }, + { "You hear the fortune cookie's hissing!", + "WW91IGhlYXIgdGhlIGZvcnR1bmUgY29va2llJ3MgaGlzc2luZyE=" }, + { "You may get rich selling letters, but beware of being blackmailed!", + "WW91IG1heSBnZXQgcmljaCBzZWxsaW5nIGxldHRlcnMsIGJ1dCBiZXdhcmUgb2YgYmVpbmcgYmxhY2ttYWlsZWQh" }, + { "You offend Shai-Hulud by sheathing your crysknife without having drawn blood.", + "WW91IG9mZmVuZCBTaGFpLUh1bHVkIGJ5IHNoZWF0aGluZyB5b3VyIGNyeXNrbmlmZSB3aXRob3V0IGhhdmluZyBkcmF3biBibG9vZC4=" }, + { "You swallowed the fortune!", + "WW91IHN3YWxsb3dlZCB0aGUgZm9ydHVuZSE=" }, + { "You want to regain strength? Two levels ahead is a guesthouse!", + "WW91IHdhbnQgdG8gcmVnYWluIHN0cmVuZ3RoPyBUd28gbGV2ZWxzIGFoZWFkIGlzIGEgZ3Vlc3Rob3VzZSE=" }, + { "You will encounter a tall, dark, and gruesome creature...", + "WW91IHdpbGwgZW5jb3VudGVyIGEgdGFsbCwgZGFyaywgYW5kIGdydWVzb21lIGNyZWF0dXJlLi4u" }, + + { "The End", "VGhlIEVuZA==" } + }; + +/* PL_Base64Encode, random strings */ +PRBool test_004(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 004 (PL_Base64Encode, random strings) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, plen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].cyphertext, clen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].plaintext, array[i].cyphertext, clen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, single characters, malloc */ +PRBool test_005(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 005 (PL_Base64Encode, single characters, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Encode((char *)plain, 1, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, double characters, malloc */ +PRBool test_006(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 006 (PL_Base64Encode, double characters, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Encode((char *)plain, 2, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, triple characters, malloc */ +PRBool test_007(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 007 (PL_Base64Encode, triple characters, malloc) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Encode((char *)plain, 3, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): no return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)cypher, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.4s.\"\n", + a, b, c, d, e, f, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_008(void) +{ + int i; + + printf("Test 008 (PL_Base64Encode, random strings, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, plen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].cyphertext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].plaintext, array[i].cyphertext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters */ +PRBool test_009(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 009 (PL_Base64Decode, single characters, equals) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 1) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.1s.\"\n", + a, b, plain, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters */ +PRBool test_010(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 010 (PL_Base64Decode, single characters, no equals) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 2, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d): return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 1) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%.1s.\"\n", + a, b, plain, result); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters */ +PRBool test_011(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 011 (PL_Base64Decode, double characters, equals) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 2) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.2s.\"\n", + a, b, c, d, plain, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters */ +PRBool test_012(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 012 (PL_Base64Decode, double characters, no equals) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 3, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d): return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 2) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%.2s.\"\n", + a, b, c, d, cypher, result); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, triple characters */ +PRBool test_013(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char result[ 8 ]; + char *rv; + + printf("Test 013 (PL_Base64Decode, triple characters) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Decode((char *)cypher, 4, result); + if( rv != result ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strncmp((char *)plain, result, 3) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.3s.\"\n", + a, b, c, d, e, f, plain, result); + return PR_FALSE; + } + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_014(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 014 (PL_Base64Decode, random strings, equals) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + PRUint32 plen = (clen * 3) / 4; + + char *rv = PL_Base64Decode(array[i].cyphertext, clen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 == (clen & 3) ) + { + if( '=' == array[i].cyphertext[clen-1] ) + { + if( '=' == array[i].cyphertext[clen-2] ) + { + plen -= 2; + } + else + { + plen -= 1; + } + } + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_015(void) +{ + int i; + char buffer[ 4096 ]; + char result[ 4096 ]; + char *rv; + + printf("Test 015 (PL_Base64Decode, random strings, no equals) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen, plen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + plen = (clen * 3) / 4; + + rv = PL_Base64Decode(buffer, clen, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters, malloc */ +PRBool test_016(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 016 (PL_Base64Decode, single characters, equals, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, single characters, malloc */ +PRBool test_017(void) +{ + PRUint32 a, b; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 017 (PL_Base64Decode, single characters, no equals, malloc) ..."); fflush(stdout); + + plain[1] = plain[2] = plain[3] = (unsigned char)0; + cypher[2] = cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + + for( b = 0; b < 4; b++ ) + { + plain[0] = (unsigned char)(a * 4 + b); + cypher[1] = base[(b * 16)]; + + rv = PL_Base64Decode((char *)cypher, 2, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d): no return value\n", a, b); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters, malloc */ +PRBool test_018(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 018 (PL_Base64Decode, double characters, equals, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)'='; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, double characters, malloc */ +PRBool test_019(void) +{ + PRUint32 a, b, c, d; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 019 (PL_Base64Decode, double characters, no equals, malloc) ..."); fflush(stdout); + + plain[2] = plain[3] = (unsigned char)0; + cypher[3] = (unsigned char)0; + cypher[4] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + cypher[2] = base[d*4]; + + rv = PL_Base64Decode((char *)cypher, 3, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d): no return value\n", a, b, c, d); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d): expected \"%s,\" got \"%s.\"\n", + a, b, c, d, cypher, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, triple characters, malloc */ +PRBool test_020(void) +{ + PRUint32 a, b, c, d, e, f; + unsigned char plain[ 4 ]; + unsigned char cypher[ 5 ]; + char *rv; + + printf("Test 020 (PL_Base64Decode, triple characters, malloc) ..."); fflush(stdout); + + cypher[4] = (unsigned char)0; + plain[3] = (unsigned char)0; + + for( a = 0; a < 64; a++ ) + { + cypher[0] = base[a]; + for( b = 0; b < 4; b++ ) + { + plain[0] = (a*4) + b; + for( c = 0; c < 16; c++ ) + { + cypher[1] = base[b*16 + c]; + for( d = 0; d < 16; d++ ) + { + plain[1] = c*16 + d; + for( e = 0; e < 4; e++ ) + { + cypher[2] = base[d*4 + e]; + for( f = 0; f < 64; f++ ) + { + plain[2] = e * 64 + f; + cypher[3] = base[f]; + + rv = PL_Base64Decode((char *)cypher, 4, (char *)0); + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): no return value\n", a, b, c, d, e, f); + return PR_FALSE; + } + + if( 0 != PL_strcmp((char *)plain, rv) ) + { + printf("FAIL\n\t(%d, %d, %d, %d, %d, %d): expected \"%s,\" got \"%.3s.\"\n", + a, b, c, d, e, f, plain, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings, malloc */ +PRBool test_021(void) +{ + int i; + + printf("Test 021 (PL_Base64Decode, random strings, equals, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + + char *rv = PL_Base64Decode(array[i].cyphertext, clen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_022(void) +{ + int i; + char buffer[ 4096 ]; + char *rv; + + printf("Test 022 (PL_Base64Decode, random strings, no equals, malloc) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + rv = PL_Base64Decode(buffer, clen, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings */ +PRBool test_023(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 023 (PL_Base64Encode, random strings, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].cyphertext, clen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].plaintext, array[i].cyphertext, clen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_024(void) +{ + int i; + + printf("Test 024 (PL_Base64Encode, random strings, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 plen = PL_strlen(array[i].plaintext); + PRUint32 clen = ((plen + 2)/3)*4; + + char *rv = PL_Base64Encode(array[i].plaintext, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].cyphertext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].plaintext, array[i].cyphertext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_025(void) +{ + int i; + char result[ 4096 ]; + + printf("Test 025 (PL_Base64Decode, random strings, equals, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + PRUint32 plen = (clen * 3) / 4; + + char *rv = PL_Base64Decode(array[i].cyphertext, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 == (clen & 3) ) + { + if( '=' == array[i].cyphertext[clen-1] ) + { + if( '=' == array[i].cyphertext[clen-2] ) + { + plen -= 2; + } + else + { + plen -= 1; + } + } + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings */ +PRBool test_026(void) +{ + int i; + char buffer[ 4096 ]; + char result[ 4096 ]; + char *rv; + + printf("Test 026 (PL_Base64Decode, random strings, no equals, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen, plen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + plen = (clen * 3) / 4; + + rv = PL_Base64Decode(buffer, 0, result); + + if( rv != result ) + { + printf("FAIL\n\t(%d): return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strncmp(result, array[i].plaintext, plen) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%.*s.\"\n", + i, array[i].cyphertext, array[i].plaintext, plen, result); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Decode, random strings, malloc */ +PRBool test_027(void) +{ + int i; + + printf("Test 027 (PL_Base64Decode, random strings, equals, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen = PL_strlen(array[i].cyphertext); + + char *rv = PL_Base64Decode(array[i].cyphertext, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + PR_DELETE(rv); + return PR_FALSE; + } + + PR_DELETE(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_Base64Encode, random strings, malloc */ +PRBool test_028(void) +{ + int i; + char buffer[ 4096 ]; + char *rv; + + printf("Test 028 (PL_Base64Decode, random strings, no equals, malloc, strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRUint32 clen; + + PL_strcpy(buffer, array[i].cyphertext); + clen = PL_strlen(buffer); + + if( 0 == (clen & 3) ) + { + if( '=' == buffer[clen-1] ) + { + if( '=' == buffer[clen-2] ) + { + buffer[clen-2] = buffer[clen-1] = (char)0; + clen -= 2; + } + else + { + buffer[clen-1] = (char)0; + clen -= 1; + } + } + } + + rv = PL_Base64Decode(buffer, 0, (char *)0); + + if( (char *)0 == rv ) + { + printf("FAIL\n\t(%d): no return value\n", i); + return PR_FALSE; + } + + if( 0 != PL_strcmp(rv, array[i].plaintext) ) + { + printf("FAIL\n\t(%d, \"%s\"): expected \n\"%s,\" got \n\"%s.\"\n", + i, array[i].cyphertext, array[i].plaintext, rv); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +int +main +( + int argc, + char *argv[] +) +{ + printf("Testing the Portable Library base64 functions:\n"); + printf("(warning: the \"triple characters\" tests are slow)\n"); + + if( 1 + && test_001() + && test_002() + && test_003() + && test_004() + && test_005() + && test_006() + && test_007() + && test_008() + && test_009() + && test_010() + && test_011() + && test_012() + && test_013() + && test_014() + && test_015() + && test_016() + && test_017() + && test_018() + && test_019() + && test_020() + && test_021() + && test_022() + && test_023() + && test_024() + && test_025() + && test_026() + && test_027() + && test_028() + ) + { + printf("Suite passed.\n"); + return 0; + } + else + { + printf("Suite failed.\n"); + return 1; + } + + /*NOTREACHED*/ +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/string.c b/src/libs/xpcom18a4/nsprpub/lib/tests/string.c new file mode 100644 index 00000000..482e17b5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/string.c @@ -0,0 +1,3116 @@ +/* -*- 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 "plstr.h" +#include "nspr.h" + +#include + +/* PL_strlen */ +PRBool test_001(void) +{ + static struct + { + const char *str; + PRUint32 len; + } array[] = + { + { (const char *)0, 0 }, + { "", 0 }, + { "a", 1 }, + { "abcdefg", 7 }, + { "abcdefg\0hijk", 7 } + }; + + int i; + + printf("Test 001 (PL_strlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + if( PL_strlen(array[i].str) != array[i].len ) + { + printf("FAIL (%d: %s->%d, %d)\n", i, + array[i].str ? array[i].str : "(null)", + PL_strlen(array[i].str), array[i].len); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnlen */ +PRBool test_002(void) +{ + static struct + { + const char *str; + PRUint32 max; + PRUint32 len; + } array[] = + { + { (const char *)0, 0, 0 }, + { (const char *)0, 12, 0 }, + { "", 0, 0 }, + { "", 12, 0 }, + { "a", 0, 0 }, + { "a", 1, 1 }, + { "a", 12, 1 }, + { "abcdefg", 0, 0 }, + { "abcdefg", 1, 1 }, + { "abcdefg", 7, 7 }, + { "abcdefg", 12, 7 }, + { "abcdefg\0hijk", 0, 0 }, + { "abcdefg\0hijk", 1, 1 }, + { "abcdefg\0hijk", 7, 7 }, + { "abcdefg\0hijk", 12, 7 }, + }; + + int i; + + printf("Test 002 (PL_strnlen) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + if( PL_strnlen(array[i].str, array[i].max) != array[i].len ) + { + printf("FAIL (%d: %s,%d->%d, %d)\n", i, + array[i].str ? array[i].str : "(null)", array[i].max, + PL_strnlen(array[i].str, array[i].max), array[i].len); + return PR_FALSE; + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcpy */ +PRBool test_003(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + char *dest; + char *rv; + PRBool comp; + } array[] = + { + { (const char *)0, (char *)0, (char *)0, PR_FALSE }, + { (const char *)0, buffer, (char *)0, PR_FALSE }, + { "", (char *)0, (char *)0, PR_FALSE }, + { "", buffer, buffer, PR_TRUE }, + { "a", (char *)0, (char *)0, PR_FALSE }, + { "a", buffer, buffer, PR_TRUE }, + { "abcdefg", (char *)0, (char *)0, PR_FALSE }, + { "abcdefg", buffer, buffer, PR_TRUE }, + { "wxyz\0abcdefg", (char *)0, (char *)0, PR_FALSE }, + { "wxyz\0abcdefg", buffer, buffer, PR_TRUE } + }; + + int i; + + printf("Test 003 (PL_strcpy) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + const char *a = array[i].str; + const char *b = (const char *)array[i].dest; + + rv = PL_strcpy(array[i].dest, array[i].str); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s->%.32s\n", i, + array[i].str ? array[i].str : "(null)", + array[i].dest ? array[i].dest : "(null)"); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncpy */ +PRBool test_004(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + PRUint32 len; + char *dest; + char *rv; + PRBool comp; + const char *result; + PRBool nulled; + } array[] = + { + { (const char *)0, 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 0, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 1, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { (const char *)0, 7, buffer, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "", 1, buffer, buffer, PR_TRUE, "", PR_TRUE }, + { "", 7, buffer, buffer, PR_TRUE, "", PR_TRUE }, + { "a", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "b", 1, buffer, buffer, PR_TRUE, "b", PR_FALSE }, + { "c", 7, buffer, buffer, PR_TRUE, "c", PR_TRUE }, + { "de", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "fg", 1, buffer, buffer, PR_TRUE, "f", PR_FALSE }, + { "hi", 7, buffer, buffer, PR_TRUE, "hi", PR_TRUE }, + { "jklmnopq", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "rstuvwxy", 1, buffer, buffer, PR_TRUE, "r", PR_FALSE }, + { "zABCDEFG", 7, buffer, buffer, PR_TRUE, "zABCDEF", PR_FALSE }, + { "a\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "a\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "b\0XXX", 1, buffer, buffer, PR_TRUE, "b", PR_FALSE }, + { "c\0XXX", 7, buffer, buffer, PR_TRUE, "c", PR_TRUE }, + { "de\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "de\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "fg\0XXX", 1, buffer, buffer, PR_TRUE, "f", PR_FALSE }, + { "hi\0XXX", 7, buffer, buffer, PR_TRUE, "hi", PR_TRUE }, + { "jklmnopq\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 0, buffer, buffer, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "jklmnopq\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0, PR_FALSE }, + { "rstuvwxy\0XXX", 1, buffer, buffer, PR_TRUE, "r", PR_FALSE }, + { "zABCDEFG\0XXX", 7, buffer, buffer, PR_TRUE, "zABCDEF", PR_FALSE }, + }; + + int i; + + printf("Test 004 (PL_strncpy) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + int j; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + rv = PL_strncpy(array[i].dest, array[i].str, array[i].len); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s, %lu)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", array[i].len, rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + const char *a = array[i].result; + const char *b = array[i].dest; + + while( *a ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, + array[i].result, array[i].dest); + return PR_FALSE; + } + + a++; + b++; + } + + if( array[i].nulled ) + { + if( *b != '\0' ) + { + printf("FAIL %d: not terminated\n", i); + return PR_FALSE; + } + } + else + { + if( *b != '-' ) + { + printf("FAIL %d: overstepped\n", i); + return PR_FALSE; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncpyz */ +PRBool test_005(void) +{ + static char buffer[ 1024 ]; + + static struct + { + const char *str; + PRUint32 len; + char *dest; + char *rv; + PRBool comp; + const char *result; + } array[] = + { + { (const char *)0, 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 1, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { (const char *)0, 7, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "", 1, buffer, buffer, PR_TRUE, "" }, + { "", 7, buffer, buffer, PR_TRUE, "" }, + { "a", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "b", 1, buffer, buffer, PR_TRUE, "" }, + { "c", 7, buffer, buffer, PR_TRUE, "c" }, + { "de", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "fg", 1, buffer, buffer, PR_TRUE, "" }, + { "hi", 7, buffer, buffer, PR_TRUE, "hi" }, + { "jklmnopq", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "rstuvwxy", 1, buffer, buffer, PR_TRUE, "" }, + { "zABCDEFG", 7, buffer, buffer, PR_TRUE, "zABCDE" }, + { "a\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "a\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "b\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "c\0XXX", 7, buffer, buffer, PR_TRUE, "c" }, + { "de\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "de\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "fg\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "hi\0XXX", 7, buffer, buffer, PR_TRUE, "hi" }, + { "jklmnopq\0XXX", 0, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 0, buffer, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 1, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "jklmnopq\0XXX", 7, (char *)0, (char *)0, PR_FALSE, (const char *)0 }, + { "rstuvwxy\0XXX", 1, buffer, buffer, PR_TRUE, "" }, + { "zABCDEFG\0XXX", 7, buffer, buffer, PR_TRUE, "zABCDE" }, + }; + + int i; + + printf("Test 005 (PL_strncpyz) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv; + int j; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + rv = PL_strncpyz(array[i].dest, array[i].str, array[i].len); + if( array[i].rv != rv ) + { + printf("FAIL %d: (0x%x, %s, %lu)->0x%x\n", i, array[i].dest, + array[i].str ? array[i].str : "(null)", array[i].len, rv); + return PR_FALSE; + } + + if( array[i].comp ) + { + const char *a = array[i].result; + const char *b = array[i].dest; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, + array[i].result, array[i].dest); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strdup */ +PRBool test_006(void) +{ + static const char *array[] = + { + (const char *)0, + "", + "a", + "abcdefg" + }; + + int i; + + printf("Test 006 (PL_strdup) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strdup(array[i]); + + if( (char *)0 == rv ) + { + printf("FAIL %d: 0x%x -> 0\n", i, array[i]); + return PR_FALSE; + } + + if( (const char *)0 == array[i] ) + { + if( (char)0 != *rv ) + { + printf("FAIL %d: (const char *)0 -> %.32s\n", i, rv); + return PR_FALSE; + } + } + else + { + const char *a = array[i]; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, array[i], rv); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + + } + PL_strfree(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strndup */ +PRBool test_007(void) +{ + static struct + { + const char *str; + PRUint32 len; + const char *result; + } array[] = + { + { (const char *)0, 0, "" }, + { (const char *)0, 1, "" }, + { (const char *)0, 7, "" }, + { "", 0, "" }, + { "", 1, "" }, + { "", 7, "" }, + { "a", 0, "" }, + { "a", 1, "a" }, + { "a", 7, "a" }, + { "ab", 0, "" }, + { "ab", 1, "a" }, + { "ab", 7, "ab" }, + { "abcdefg", 0, "" }, + { "abcdefg", 1, "a" }, + { "abcdefg", 7, "abcdefg" }, + { "abcdefghijk", 0, "" }, + { "abcdefghijk", 1, "a" }, + { "abcdefghijk", 7, "abcdefg" }, + { "abcdef\0ghijk", 0, "" }, + { "abcdef\0ghijk", 1, "a" }, + { "abcdef\0ghijk", 7, "abcdef" } + }; + + int i; + + printf("Test 007 (PL_strndup) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strndup(array[i].str, array[i].len); + const char *a; + const char *b; + + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%lu -> 0\n", i, + array[i].str ? array[i].str : "(null)", array[i].len); + return PR_FALSE; + } + + a = array[i].result; + b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s != %.32s\n", i, array[i].result, rv); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + + free(rv); + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcat */ +PRBool test_008(void) +{ + static struct + { + const char *first; + const char *second; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, (const char *)0 }, + { (const char *)0, "xyz", (const char *)0 }, + { "", (const char *)0, "" }, + { "", "", "" }, + { "ab", "", "ab" }, + { "cd", "ef", "cdef" }, + { "gh\0X", "", "gh" }, + { "ij\0X", "kl", "ijkl" }, + { "mn\0X", "op\0X", "mnop" }, + { "qr", "st\0X", "qrst" }, + { "uv\0X", "wx\0X", "uvwx" } + }; + + int i; + + printf("Test 008 (PL_strcat) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strcat(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].second); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + rv, array[i].result); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncat */ +PRBool test_009(void) +{ + static struct + { + const char *first; + const char *second; + PRUint32 length; + PRBool nulled; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, 0, PR_FALSE, (const char *)0 }, + { (const char *)0, (const char *)0, 1, PR_FALSE, (const char *)0 }, + { (const char *)0, (const char *)0, 7, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 0, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 1, PR_FALSE, (const char *)0 }, + { (const char *)0, "", 7, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 0, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 1, PR_FALSE, (const char *)0 }, + { (const char *)0, "stuff", 7, PR_FALSE, (const char *)0 }, + { "", (const char *)0, 0, PR_TRUE, "" }, + { "", (const char *)0, 1, PR_TRUE, "" }, + { "", (const char *)0, 7, PR_TRUE, "" }, + { "", "", 0, PR_TRUE, "" }, + { "", "", 1, PR_TRUE, "" }, + { "", "", 7, PR_TRUE, "" }, + { "", "abcdefgh", 0, PR_TRUE, "" }, + { "", "abcdefgh", 1, PR_FALSE, "a" }, + { "", "abcdefgh", 7, PR_FALSE, "abcdefg" }, + { "xyz", (const char *)0, 0, PR_TRUE, "xyz" }, + { "xyz", (const char *)0, 1, PR_TRUE, "xyz" }, + { "xyz", (const char *)0, 7, PR_TRUE, "xyz" }, + { "xyz", "", 0, PR_TRUE, "xyz" }, + { "xyz", "", 1, PR_TRUE, "xyz" }, + { "xyz", "", 7, PR_TRUE, "xyz" }, + { "xyz", "abcdefgh", 0, PR_TRUE, "xyz" }, + { "xyz", "abcdefgh", 1, PR_FALSE, "xyza" }, + { "xyz", "abcdefgh", 7, PR_FALSE, "xyzabcdefg" } + }; + + int i; + + printf("Test 009 (PL_strncat) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strncat(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].second, array[i].length); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s/%lu -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( *a ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv, array[i].result); + return PR_FALSE; + } + + a++; + b++; + } + + if( array[i].nulled ) + { + if( (char)0 != *b ) + { + printf("FAIL %d: %s+%s/%lu -> not nulled\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length); + return PR_FALSE; + } + } + else + { + if( (char)0 == *b ) + { + printf("FAIL %d: %s+%s/%lu -> overrun\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length); + return PR_FALSE; + } + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcatn */ +PRBool test_010(void) +{ + static struct + { + const char *first; + const char *second; + PRUint32 length; + const char *result; + } array[] = + { + { (const char *)0, (const char *)0, 0, (const char *)0 }, + { (const char *)0, (const char *)0, 1, (const char *)0 }, + { (const char *)0, (const char *)0, 7, (const char *)0 }, + { (const char *)0, "", 0, (const char *)0 }, + { (const char *)0, "", 1, (const char *)0 }, + { (const char *)0, "", 7, (const char *)0 }, + { (const char *)0, "stuff", 0, (const char *)0 }, + { (const char *)0, "stuff", 1, (const char *)0 }, + { (const char *)0, "stuff", 7, (const char *)0 }, + { "", (const char *)0, 0, "" }, + { "", (const char *)0, 1, "" }, + { "", (const char *)0, 7, "" }, + { "", "", 0, "" }, + { "", "", 1, "" }, + { "", "", 7, "" }, + { "", "abcdefgh", 0, "" }, + { "", "abcdefgh", 1, "" }, + { "", "abcdefgh", 7, "abcdef" }, + { "xyz", (const char *)0, 0, "xyz" }, + { "xyz", (const char *)0, 1, "xyz" }, + { "xyz", (const char *)0, 7, "xyz" }, + { "xyz", "", 0, "xyz" }, + { "xyz", "", 1, "xyz" }, + { "xyz", "", 7, "xyz" }, + { "xyz", "abcdefgh", 0, "xyz" }, + { "xyz", "abcdefgh", 1, "xyz" }, + { "xyz", "abcdefgh", 7, "xyzabc" } + }; + + int i; + + printf("Test 010 (PL_strcatn) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char buffer[ 1024 ]; + int j; + char *rv; + + for( j = 0; j < sizeof(buffer); j++ ) + buffer[j] = '-'; + + if( (const char *)0 != array[i].first ) + (void)PL_strcpy(buffer, array[i].first); + + rv = PL_strcatn(((const char *)0 == array[i].first) ? (char *)0 : buffer, + array[i].length, array[i].second); + + if( (const char *)0 == array[i].result ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not zero\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s+%s/%lu -> null, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, array[i].result); + return PR_FALSE; + } + else + { + const char *a = array[i].result; + const char *b = (const char *)rv; + + while( 1 ) + { + if( *a != *b ) + { + printf("FAIL %d: %s+%s/%lu -> %.32s, not %s\n", i, + array[i].first ? array[i].first : "(null)", + array[i].second ? array[i].second : "(null)", + array[i].length, rv, array[i].result); + return PR_FALSE; + } + + if( (char)0 == *a ) break; + + a++; + b++; + } + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcmp */ +PRBool test_011(void) +{ + static struct + { + const char *one; + const char *two; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0 }, + { (const char *)0, "word", -1 }, + { "word", (const char *)0, 1 }, + { "word", "word", 0 }, + { "aZYXVUT", "bZYXVUT", -1 }, + { "aZYXVUT", "bAAAAAA", -1 }, + { "a", "aa", -1 }, + { "a", "a", 0 }, + { "a", "A", 1 }, + { "aaaaa", "baaaa", -1 }, + { "aaaaa", "abaaa", -1 }, + { "aaaaa", "aabaa", -1 }, + { "aaaaa", "aaaba", -1 }, + { "aaaaa", "aaaab", -1 }, + { "bZYXVUT", "aZYXVUT", 1 }, + { "bAAAAAA", "aZYXVUT", 1 }, + { "aa", "a", 1 }, + { "A", "a", -1 }, + { "baaaa", "aaaaa", 1 }, + { "abaaa", "aaaaa", 1 }, + { "aabaa", "aaaaa", 1 }, + { "aaaba", "aaaaa", 1 }, + { "aaaab", "aaaaa", 1 }, + { "word", "Word", 1 }, + { "word", "wOrd", 1 }, + { "word", "woRd", 1 }, + { "word", "worD", 1 }, + { "WORD", "wORD", -1 }, + { "WORD", "WoRD", -1 }, + { "WORD", "WOrD", -1 }, + { "WORD", "WORd", -1 } + }; + + int i; + + printf("Test 011 (PL_strcmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strcmp(array[i].one, array[i].two); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncmp */ +PRBool test_012(void) +{ + static struct + { + const char *one; + const char *two; + PRUint32 max; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0, 0 }, + { (const char *)0, (const char *)0, 1, 0 }, + { (const char *)0, (const char *)0, 4, 0 }, + { (const char *)0, "word", 0, -1 }, + { (const char *)0, "word", 1, -1 }, + { (const char *)0, "word", 4, -1 }, + { "word", (const char *)0, 0, 1 }, + { "word", (const char *)0, 1, 1 }, + { "word", (const char *)0, 4, 1 }, + { "word", "word", 0, 0 }, + { "word", "word", 1, 0 }, + { "word", "word", 3, 0 }, + { "word", "word", 5, 0 }, + { "aZYXVUT", "bZYXVUT", 0, 0 }, + { "aZYXVUT", "bZYXVUT", 1, -1 }, + { "aZYXVUT", "bZYXVUT", 4, -1 }, + { "aZYXVUT", "bZYXVUT", 9, -1 }, + { "aZYXVUT", "bAAAAAA", 0, 0 }, + { "aZYXVUT", "bAAAAAA", 1, -1 }, + { "aZYXVUT", "bAAAAAA", 4, -1 }, + { "aZYXVUT", "bAAAAAA", 5, -1 }, + { "a", "aa", 0, 0 }, + { "a", "aa", 1, 0 }, + { "a", "aa", 4, -1 }, + { "a", "a", 0, 0 }, + { "a", "a", 1, 0 }, + { "a", "a", 4, 0 }, + { "a", "A", 0, 0 }, + { "a", "A", 1, 1 }, + { "a", "A", 4, 1 }, + { "aaaaa", "baaaa", 0, 0 }, + { "aaaaa", "baaaa", 1, -1 }, + { "aaaaa", "baaaa", 4, -1 }, + { "aaaaa", "abaaa", 0, 0 }, + { "aaaaa", "abaaa", 1, 0 }, + { "aaaaa", "abaaa", 4, -1 }, + { "aaaaa", "aabaa", 0, 0 }, + { "aaaaa", "aabaa", 1, 0 }, + { "aaaaa", "aabaa", 4, -1 }, + { "aaaaa", "aaaba", 0, 0 }, + { "aaaaa", "aaaba", 1, 0 }, + { "aaaaa", "aaaba", 4, -1 }, + { "aaaaa", "aaaab", 0, 0 }, + { "aaaaa", "aaaab", 1, 0 }, + { "aaaaa", "aaaab", 4, 0 }, + { "bZYXVUT", "aZYXVUT", 0, 0 }, + { "bZYXVUT", "aZYXVUT", 1, 1 }, + { "bZYXVUT", "aZYXVUT", 4, 1 }, + { "bAAAAAA", "aZYXVUT", 0, 0 }, + { "bAAAAAA", "aZYXVUT", 1, 1 }, + { "bAAAAAA", "aZYXVUT", 4, 1 }, + { "aa", "a", 0, 0 }, + { "aa", "a", 1, 0 }, + { "aa", "a", 4, 1 }, + { "A", "a", 0, 0 }, + { "A", "a", 1, -1 }, + { "A", "a", 4, -1 }, + { "baaaa", "aaaaa", 0, 0 }, + { "baaaa", "aaaaa", 1, 1 }, + { "baaaa", "aaaaa", 4, 1 }, + { "abaaa", "aaaaa", 0, 0 }, + { "abaaa", "aaaaa", 1, 0 }, + { "abaaa", "aaaaa", 4, 1 }, + { "aabaa", "aaaaa", 0, 0 }, + { "aabaa", "aaaaa", 1, 0 }, + { "aabaa", "aaaaa", 4, 1 }, + { "aaaba", "aaaaa", 0, 0 }, + { "aaaba", "aaaaa", 1, 0 }, + { "aaaba", "aaaaa", 4, 1 }, + { "aaaab", "aaaaa", 0, 0 }, + { "aaaab", "aaaaa", 1, 0 }, + { "aaaab", "aaaaa", 4, 0 }, + { "word", "Word", 0, 0 }, + { "word", "Word", 1, 1 }, + { "word", "Word", 3, 1 }, + { "word", "wOrd", 0, 0 }, + { "word", "wOrd", 1, 0 }, + { "word", "wOrd", 3, 1 }, + { "word", "woRd", 0, 0 }, + { "word", "woRd", 1, 0 }, + { "word", "woRd", 3, 1 }, + { "word", "worD", 0, 0 }, + { "word", "worD", 1, 0 }, + { "word", "worD", 3, 0 }, + { "WORD", "wORD", 0, 0 }, + { "WORD", "wORD", 1, -1 }, + { "WORD", "wORD", 3, -1 }, + { "WORD", "WoRD", 0, 0 }, + { "WORD", "WoRD", 1, 0 }, + { "WORD", "WoRD", 3, -1 }, + { "WORD", "WOrD", 0, 0 }, + { "WORD", "WOrD", 1, 0 }, + { "WORD", "WOrD", 3, -1 }, + { "WORD", "WORd", 0, 0 }, + { "WORD", "WORd", 1, 0 }, + { "WORD", "WORd", 3, 0 } + + }; + + int i; + + printf("Test 012 (PL_strncmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strncmp(array[i].one, array[i].two, array[i].max); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s/%ld -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + array[i].max, rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcasecmp */ +PRBool test_013(void) +{ + static struct + { + const char *one; + const char *two; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0 }, + { (const char *)0, "word", -1 }, + { "word", (const char *)0, 1 }, + { "word", "word", 0 }, + { "aZYXVUT", "bZYXVUT", -1 }, + { "aZYXVUT", "bAAAAAA", -1 }, + { "a", "aa", -1 }, + { "a", "a", 0 }, + { "a", "A", 0 }, + { "aaaaa", "baaaa", -1 }, + { "aaaaa", "abaaa", -1 }, + { "aaaaa", "aabaa", -1 }, + { "aaaaa", "aaaba", -1 }, + { "aaaaa", "aaaab", -1 }, + { "bZYXVUT", "aZYXVUT", 1 }, + { "bAAAAAA", "aZYXVUT", 1 }, + { "aa", "a", 1 }, + { "A", "a", 0 }, + { "baaaa", "aaaaa", 1 }, + { "abaaa", "aaaaa", 1 }, + { "aabaa", "aaaaa", 1 }, + { "aaaba", "aaaaa", 1 }, + { "aaaab", "aaaaa", 1 }, + { "word", "Word", 0 }, + { "word", "wOrd", 0 }, + { "word", "woRd", 0 }, + { "word", "worD", 0 }, + { "WORD", "wORD", 0 }, + { "WORD", "WoRD", 0 }, + { "WORD", "WOrD", 0 }, + { "WORD", "WORd", 0 } + }; + + int i; + + printf("Test 013 (PL_strcasecmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strcasecmp(array[i].one, array[i].two); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncasecmp */ +PRBool test_014(void) +{ + static struct + { + const char *one; + const char *two; + PRUint32 max; + PRIntn sign; + } array[] = + { + { (const char *)0, (const char *)0, 0, 0 }, + { (const char *)0, (const char *)0, 1, 0 }, + { (const char *)0, (const char *)0, 4, 0 }, + { (const char *)0, "word", 0, -1 }, + { (const char *)0, "word", 1, -1 }, + { (const char *)0, "word", 4, -1 }, + { "word", (const char *)0, 0, 1 }, + { "word", (const char *)0, 1, 1 }, + { "word", (const char *)0, 4, 1 }, + { "word", "word", 0, 0 }, + { "word", "word", 1, 0 }, + { "word", "word", 3, 0 }, + { "word", "word", 5, 0 }, + { "aZYXVUT", "bZYXVUT", 0, 0 }, + { "aZYXVUT", "bZYXVUT", 1, -1 }, + { "aZYXVUT", "bZYXVUT", 4, -1 }, + { "aZYXVUT", "bZYXVUT", 9, -1 }, + { "aZYXVUT", "bAAAAAA", 0, 0 }, + { "aZYXVUT", "bAAAAAA", 1, -1 }, + { "aZYXVUT", "bAAAAAA", 4, -1 }, + { "aZYXVUT", "bAAAAAA", 5, -1 }, + { "a", "aa", 0, 0 }, + { "a", "aa", 1, 0 }, + { "a", "aa", 4, -1 }, + { "a", "a", 0, 0 }, + { "a", "a", 1, 0 }, + { "a", "a", 4, 0 }, + { "a", "A", 0, 0 }, + { "a", "A", 1, 0 }, + { "a", "A", 4, 0 }, + { "aaaaa", "baaaa", 0, 0 }, + { "aaaaa", "baaaa", 1, -1 }, + { "aaaaa", "baaaa", 4, -1 }, + { "aaaaa", "abaaa", 0, 0 }, + { "aaaaa", "abaaa", 1, 0 }, + { "aaaaa", "abaaa", 4, -1 }, + { "aaaaa", "aabaa", 0, 0 }, + { "aaaaa", "aabaa", 1, 0 }, + { "aaaaa", "aabaa", 4, -1 }, + { "aaaaa", "aaaba", 0, 0 }, + { "aaaaa", "aaaba", 1, 0 }, + { "aaaaa", "aaaba", 4, -1 }, + { "aaaaa", "aaaab", 0, 0 }, + { "aaaaa", "aaaab", 1, 0 }, + { "aaaaa", "aaaab", 4, 0 }, + { "bZYXVUT", "aZYXVUT", 0, 0 }, + { "bZYXVUT", "aZYXVUT", 1, 1 }, + { "bZYXVUT", "aZYXVUT", 4, 1 }, + { "bAAAAAA", "aZYXVUT", 0, 0 }, + { "bAAAAAA", "aZYXVUT", 1, 1 }, + { "bAAAAAA", "aZYXVUT", 4, 1 }, + { "aa", "a", 0, 0 }, + { "aa", "a", 1, 0 }, + { "aa", "a", 4, 1 }, + { "A", "a", 0, 0 }, + { "A", "a", 1, 0 }, + { "A", "a", 4, 0 }, + { "baaaa", "aaaaa", 0, 0 }, + { "baaaa", "aaaaa", 1, 1 }, + { "baaaa", "aaaaa", 4, 1 }, + { "abaaa", "aaaaa", 0, 0 }, + { "abaaa", "aaaaa", 1, 0 }, + { "abaaa", "aaaaa", 4, 1 }, + { "aabaa", "aaaaa", 0, 0 }, + { "aabaa", "aaaaa", 1, 0 }, + { "aabaa", "aaaaa", 4, 1 }, + { "aaaba", "aaaaa", 0, 0 }, + { "aaaba", "aaaaa", 1, 0 }, + { "aaaba", "aaaaa", 4, 1 }, + { "aaaab", "aaaaa", 0, 0 }, + { "aaaab", "aaaaa", 1, 0 }, + { "aaaab", "aaaaa", 4, 0 }, + { "word", "Word", 0, 0 }, + { "word", "Word", 1, 0 }, + { "word", "Word", 3, 0 }, + { "word", "wOrd", 0, 0 }, + { "word", "wOrd", 1, 0 }, + { "word", "wOrd", 3, 0 }, + { "word", "woRd", 0, 0 }, + { "word", "woRd", 1, 0 }, + { "word", "woRd", 3, 0 }, + { "word", "worD", 0, 0 }, + { "word", "worD", 1, 0 }, + { "word", "worD", 3, 0 }, + { "WORD", "wORD", 0, 0 }, + { "WORD", "wORD", 1, 0 }, + { "WORD", "wORD", 3, 0 }, + { "WORD", "WoRD", 0, 0 }, + { "WORD", "WoRD", 1, 0 }, + { "WORD", "WoRD", 3, 0 }, + { "WORD", "WOrD", 0, 0 }, + { "WORD", "WOrD", 1, 0 }, + { "WORD", "WOrD", 3, 0 }, + { "WORD", "WORd", 0, 0 }, + { "WORD", "WORd", 1, 0 }, + { "WORD", "WORd", 3, 0 } + }; + + int i; + + printf("Test 014 (PL_strncasecmp) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + PRIntn rv = PL_strncasecmp(array[i].one, array[i].two, array[i].max); + + switch( array[i].sign ) + { + case -1: + if( rv < 0 ) continue; + break; + case 1: + if( rv > 0 ) continue; + break; + case 0: + if( 0 == rv ) continue; + break; + default: + PR_NOT_REACHED("static data inconsistancy"); + break; + } + + printf("FAIL %d: %s-%s/%ld -> %d, not %d\n", i, + array[i].one ? array[i].one : "(null)", + array[i].two ? array[i].two : "(null)", + array[i].max, rv, array[i].sign); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strchr */ +PRBool test_015(void) +{ + static struct + { + const char *str; + char chr; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', PR_FALSE, 0 }, + { (const char *)0, '\0', PR_FALSE, 0 }, + { "abcdefg", 'a', PR_TRUE, 0 }, + { "abcdefg", 'b', PR_TRUE, 1 }, + { "abcdefg", 'c', PR_TRUE, 2 }, + { "abcdefg", 'd', PR_TRUE, 3 }, + { "abcdefg", 'e', PR_TRUE, 4 }, + { "abcdefg", 'f', PR_TRUE, 5 }, + { "abcdefg", 'g', PR_TRUE, 6 }, + { "abcdefg", 'h', PR_FALSE, 0 }, + { "abcdefg", '\0', PR_TRUE, 7 }, + { "abcdefg", 'A', PR_FALSE, 0 }, + { "abcdefg", 'B', PR_FALSE, 0 }, + { "abcdefg", 'C', PR_FALSE, 0 }, + { "abcdefg", 'D', PR_FALSE, 0 }, + { "abcdefg", 'E', PR_FALSE, 0 }, + { "abcdefg", 'F', PR_FALSE, 0 }, + { "abcdefg", 'G', PR_FALSE, 0 }, + { "abcdefg", 'H', PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', PR_TRUE, 0 }, + { "abcdefgabcdefg", 'b', PR_TRUE, 1 }, + { "abcdefgabcdefg", 'c', PR_TRUE, 2 }, + { "abcdefgabcdefg", 'd', PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', PR_TRUE, 14 } + }; + + int i; + + printf("Test 015 (PL_strchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strchr(array[i].str, array[i].chr); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c -> %.32s, not zero\n", i, array[i].str, + array[i].chr, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strrchr */ +PRBool test_016(void) +{ + static struct + { + const char *str; + char chr; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', PR_FALSE, 0 }, + { (const char *)0, '\0', PR_FALSE, 0 }, + { "abcdefg", 'a', PR_TRUE, 0 }, + { "abcdefg", 'b', PR_TRUE, 1 }, + { "abcdefg", 'c', PR_TRUE, 2 }, + { "abcdefg", 'd', PR_TRUE, 3 }, + { "abcdefg", 'e', PR_TRUE, 4 }, + { "abcdefg", 'f', PR_TRUE, 5 }, + { "abcdefg", 'g', PR_TRUE, 6 }, + { "abcdefg", 'h', PR_FALSE, 0 }, + { "abcdefg", '\0', PR_TRUE, 7 }, + { "abcdefg", 'A', PR_FALSE, 0 }, + { "abcdefg", 'B', PR_FALSE, 0 }, + { "abcdefg", 'C', PR_FALSE, 0 }, + { "abcdefg", 'D', PR_FALSE, 0 }, + { "abcdefg", 'E', PR_FALSE, 0 }, + { "abcdefg", 'F', PR_FALSE, 0 }, + { "abcdefg", 'G', PR_FALSE, 0 }, + { "abcdefg", 'H', PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', PR_TRUE, 7 }, + { "abcdefgabcdefg", 'b', PR_TRUE, 8 }, + { "abcdefgabcdefg", 'c', PR_TRUE, 9 }, + { "abcdefgabcdefg", 'd', PR_TRUE, 10 }, + { "abcdefgabcdefg", 'e', PR_TRUE, 11 }, + { "abcdefgabcdefg", 'f', PR_TRUE, 12 }, + { "abcdefgabcdefg", 'g', PR_TRUE, 13 }, + { "abcdefgabcdefg", 'h', PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', PR_TRUE, 14 } + }; + + int i; + + printf("Test 016 (PL_strrchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strrchr(array[i].str, array[i].chr); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c -> %.32s, not zero\n", i, array[i].str, + array[i].chr, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnchr */ +PRBool test_017(void) +{ + static struct + { + const char *str; + char chr; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', 2, PR_FALSE, 0 }, + { (const char *)0, '\0', 2, PR_FALSE, 0 }, + { "abcdefg", 'a', 5, PR_TRUE, 0 }, + { "abcdefg", 'b', 5, PR_TRUE, 1 }, + { "abcdefg", 'c', 5, PR_TRUE, 2 }, + { "abcdefg", 'd', 5, PR_TRUE, 3 }, + { "abcdefg", 'e', 5, PR_TRUE, 4 }, + { "abcdefg", 'f', 5, PR_FALSE, 0 }, + { "abcdefg", 'g', 5, PR_FALSE, 0 }, + { "abcdefg", 'h', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 15, PR_TRUE, 7 }, + { "abcdefg", 'A', 5, PR_FALSE, 0 }, + { "abcdefg", 'B', 5, PR_FALSE, 0 }, + { "abcdefg", 'C', 5, PR_FALSE, 0 }, + { "abcdefg", 'D', 5, PR_FALSE, 0 }, + { "abcdefg", 'E', 5, PR_FALSE, 0 }, + { "abcdefg", 'F', 5, PR_FALSE, 0 }, + { "abcdefg", 'G', 5, PR_FALSE, 0 }, + { "abcdefg", 'H', 5, PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', 10, PR_TRUE, 0 }, + { "abcdefgabcdefg", 'b', 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", 'c', 10, PR_TRUE, 2 }, + { "abcdefgabcdefg", 'd', 10, PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', 10, PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 14, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 15, PR_TRUE, 14 } + }; + + int i; + + printf("Test 017 (PL_strnchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnchr(array[i].str, array[i].chr, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c/%lu -> %.32s, not zero\n", i, array[i].str, + array[i].chr, array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c/%lu -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c/%lu -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnrchr */ +PRBool test_018(void) +{ + static struct + { + const char *str; + char chr; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, 'a', 2, PR_FALSE, 0 }, + { (const char *)0, '\0', 2, PR_FALSE, 0 }, + { "abcdefg", 'a', 5, PR_TRUE, 0 }, + { "abcdefg", 'b', 5, PR_TRUE, 1 }, + { "abcdefg", 'c', 5, PR_TRUE, 2 }, + { "abcdefg", 'd', 5, PR_TRUE, 3 }, + { "abcdefg", 'e', 5, PR_TRUE, 4 }, + { "abcdefg", 'f', 5, PR_FALSE, 0 }, + { "abcdefg", 'g', 5, PR_FALSE, 0 }, + { "abcdefg", 'h', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 5, PR_FALSE, 0 }, + { "abcdefg", '\0', 15, PR_TRUE, 7 }, + { "abcdefg", 'A', 5, PR_FALSE, 0 }, + { "abcdefg", 'B', 5, PR_FALSE, 0 }, + { "abcdefg", 'C', 5, PR_FALSE, 0 }, + { "abcdefg", 'D', 5, PR_FALSE, 0 }, + { "abcdefg", 'E', 5, PR_FALSE, 0 }, + { "abcdefg", 'F', 5, PR_FALSE, 0 }, + { "abcdefg", 'G', 5, PR_FALSE, 0 }, + { "abcdefg", 'H', 5, PR_FALSE, 0 }, + { "abcdefgabcdefg", 'a', 10, PR_TRUE, 7 }, + { "abcdefgabcdefg", 'b', 10, PR_TRUE, 8 }, + { "abcdefgabcdefg", 'c', 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", 'd', 10, PR_TRUE, 3 }, + { "abcdefgabcdefg", 'e', 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", 'f', 10, PR_TRUE, 5 }, + { "abcdefgabcdefg", 'g', 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", 'h', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 14, PR_FALSE, 0 }, + { "abcdefgabcdefg", '\0', 15, PR_TRUE, 14 } + }; + + int i; + + printf("Test 018 (PL_strnrchr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnrchr(array[i].str, array[i].chr, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%c/%lu -> %.32s, not zero\n", i, array[i].str, + array[i].chr, array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%c/%lu -> null, not +%lu\n", i, array[i].str, + array[i].chr, array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%c/%lu -> 0x%x, not 0x%x+%lu\n", i, array[i].str, + array[i].chr, array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strpbrk */ +PRBool test_019(void) +{ + static struct + { + const char *str; + const char *chrs; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "abc", PR_FALSE, 0 }, + { "abc", (const char *)0, PR_FALSE, 0 }, + { "abcdefg", "", PR_FALSE, 0 }, + { "", "aeiou", PR_FALSE, 0 }, + { "abcdefg", "ae", PR_TRUE, 0 }, + { "abcdefg", "ei", PR_TRUE, 4 }, + { "abcdefg", "io", PR_FALSE, 0 }, + { "abcdefg", "bcd", PR_TRUE, 1 }, + { "abcdefg", "cbd", PR_TRUE, 1 }, + { "abcdefg", "dbc", PR_TRUE, 1 }, + { "abcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefg", "AE", PR_FALSE, 0 }, + { "abcdefg", "EI", PR_FALSE, 0 }, + { "abcdefg", "IO", PR_FALSE, 0 }, + { "abcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefg", "GHI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", PR_TRUE, 0 }, + { "abcdefgabcdefg", "ei", PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", PR_TRUE, 1 }, + { "abcdefgabcdefg", "cbd", PR_TRUE, 1 }, + { "abcdefgabcdefg", "dbc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", PR_FALSE, 0 } + }; + + int i; + + printf("Test 019 (PL_strpbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strpbrk(array[i].str, array[i].chrs); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strprbrk */ +PRBool test_020(void) +{ + static struct + { + const char *str; + const char *chrs; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "abc", PR_FALSE, 0 }, + { "abc", (const char *)0, PR_FALSE, 0 }, + { "abcdefg", "", PR_FALSE, 0 }, + { "", "aeiou", PR_FALSE, 0 }, + { "abcdefg", "ae", PR_TRUE, 4 }, + { "abcdefg", "ei", PR_TRUE, 4 }, + { "abcdefg", "io", PR_FALSE, 0 }, + { "abcdefg", "bcd", PR_TRUE, 3 }, + { "abcdefg", "cbd", PR_TRUE, 3 }, + { "abcdefg", "dbc", PR_TRUE, 3 }, + { "abcdefg", "ghi", PR_TRUE, 6 }, + { "abcdefg", "AE", PR_FALSE, 0 }, + { "abcdefg", "EI", PR_FALSE, 0 }, + { "abcdefg", "IO", PR_FALSE, 0 }, + { "abcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefg", "GHI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", PR_TRUE, 11 }, + { "abcdefgabcdefg", "ei", PR_TRUE, 11 }, + { "abcdefgabcdefg", "io", PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", PR_TRUE, 10 }, + { "abcdefgabcdefg", "cbd", PR_TRUE, 10 }, + { "abcdefgabcdefg", "dbc", PR_TRUE, 10 }, + { "abcdefgabcdefg", "ghi", PR_TRUE, 13 }, + { "abcdefgabcdefg", "AE", PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", PR_FALSE, 0 } + }; + + int i; + + printf("Test 020 (PL_strprbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strprbrk(array[i].str, array[i].chrs); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnpbrk */ +PRBool test_021(void) +{ + static struct + { + const char *str; + const char *chrs; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 3, PR_FALSE, 0 }, + { (const char *)0, "abc", 3, PR_FALSE, 0 }, + { "abc", (const char *)0, 3, PR_FALSE, 0 }, + { "abcdefg", "", 3, PR_FALSE, 0 }, + { "", "aeiou", 3, PR_FALSE, 0 }, + { "abcdefg", "ae", 0, PR_FALSE, 0 }, + { "abcdefg", "ae", 1, PR_TRUE, 0 }, + { "abcdefg", "ae", 4, PR_TRUE, 0 }, + { "abcdefg", "ae", 5, PR_TRUE, 0 }, + { "abcdefg", "ae", 6, PR_TRUE, 0 }, + { "abcdefg", "ei", 4, PR_FALSE, 0 }, + { "abcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefg", "bcd", 2, PR_TRUE, 1 }, + { "abcdefg", "cbd", 2, PR_TRUE, 1 }, + { "abcdefg", "dbc", 2, PR_TRUE, 1 }, + { "abcdefg", "ghi", 6, PR_FALSE, 0 }, + { "abcdefg", "ghi", 7, PR_TRUE, 6 }, + { "abcdefg", "AE", 9, PR_FALSE, 0 }, + { "abcdefg", "EI", 9, PR_FALSE, 0 }, + { "abcdefg", "IO", 9, PR_FALSE, 0 }, + { "abcdefg", "BCD", 9, PR_FALSE, 0 }, + { "abcdefg", "CBD", 9, PR_FALSE, 0 }, + { "abcdefg", "DBC", 9, PR_FALSE, 0 }, + { "abcdefg", "GHI", 9, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", 10, PR_TRUE, 0 }, + { "abcdefgabcdefg", "ei", 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "cbd", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "dbc", 10, PR_TRUE, 1 }, + { "abcdefgabcdefg", "ghi", 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", 10, PR_FALSE, 0 } + }; + + int i; + + printf("Test 021 (PL_strnpbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnpbrk(array[i].str, array[i].chrs, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnprbrk */ +PRBool test_022(void) +{ + static struct + { + const char *str; + const char *chrs; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 3, PR_FALSE, 0 }, + { (const char *)0, "abc", 3, PR_FALSE, 0 }, + { "abc", (const char *)0, 3, PR_FALSE, 0 }, + { "abcdefg", "", 3, PR_FALSE, 0 }, + { "", "aeiou", 3, PR_FALSE, 0 }, + { "abcdefg", "ae", 0, PR_FALSE, 0 }, + { "abcdefg", "ae", 1, PR_TRUE, 0 }, + { "abcdefg", "ae", 4, PR_TRUE, 0 }, + { "abcdefg", "ae", 5, PR_TRUE, 4 }, + { "abcdefg", "ae", 6, PR_TRUE, 4 }, + { "abcdefg", "ei", 4, PR_FALSE, 0 }, + { "abcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefg", "bcd", 2, PR_TRUE, 1 }, + { "abcdefg", "cbd", 2, PR_TRUE, 1 }, + { "abcdefg", "dbc", 2, PR_TRUE, 1 }, + { "abcdefg", "bcd", 3, PR_TRUE, 2 }, + { "abcdefg", "cbd", 3, PR_TRUE, 2 }, + { "abcdefg", "dbc", 3, PR_TRUE, 2 }, + { "abcdefg", "bcd", 5, PR_TRUE, 3 }, + { "abcdefg", "cbd", 5, PR_TRUE, 3 }, + { "abcdefg", "dbc", 5, PR_TRUE, 3 }, + { "abcdefg", "bcd", 15, PR_TRUE, 3 }, + { "abcdefg", "cbd", 15, PR_TRUE, 3 }, + { "abcdefg", "dbc", 15, PR_TRUE, 3 }, + { "abcdefg", "ghi", 6, PR_FALSE, 0 }, + { "abcdefg", "ghi", 7, PR_TRUE, 6 }, + { "abcdefg", "AE", 9, PR_FALSE, 0 }, + { "abcdefg", "EI", 9, PR_FALSE, 0 }, + { "abcdefg", "IO", 9, PR_FALSE, 0 }, + { "abcdefg", "BCD", 9, PR_FALSE, 0 }, + { "abcdefg", "CBD", 9, PR_FALSE, 0 }, + { "abcdefg", "DBC", 9, PR_FALSE, 0 }, + { "abcdefg", "GHI", 9, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ae", 10, PR_TRUE, 7 }, + { "abcdefgabcdefg", "ei", 10, PR_TRUE, 4 }, + { "abcdefgabcdefg", "io", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "bcd", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "cbd", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "dbc", 10, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ghi", 10, PR_TRUE, 6 }, + { "abcdefgabcdefg", "AE", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "EI", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "IO", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "BCD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "CBD", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "DBC", 10, PR_FALSE, 0 }, + { "abcdefgabcdefg", "GHI", 10, PR_FALSE, 0 } + }; + + int i; + + printf("Test 022 (PL_strnprbrk) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnprbrk(array[i].str, array[i].chrs, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not +%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].chrs ? array[i].chrs : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strstr */ +PRBool test_023(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 0 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 1 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_FALSE, 0 } + }; + + int i; + + printf("Test 023 (PL_strstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strrstr */ +PRBool test_024(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 8 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 5 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", PR_TRUE, 13 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 11 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 7 }, + { "ABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_FALSE, 0 } + }; + + int i; + + printf("Test 024 (PL_strrstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strrstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnstr */ +PRBool test_025(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 0 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefgabcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFG", "a", 5, PR_FALSE, 0 }, + { "ABCDEFG", "c", 5, PR_FALSE, 0 }, + { "ABCDEFG", "e", 5, PR_FALSE, 0 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_FALSE, 0 }, + { "ABCDEFG", "cd", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABC", "bc", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 7, PR_FALSE, }, + { "ABCDEFGABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 8, PR_FALSE, 0 } + }; + + int i; + + printf("Test 025 (PL_strnstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strnrstr */ +PRBool test_026(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 11, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 8 }, + { "blah-de-blah", "blah", 13, PR_TRUE, 8 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 5 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 12, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 13, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 14, PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", 13, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 14, PR_TRUE, 7 }, + { "abcdefgabcdefg", "abcdefg", 15, PR_TRUE, 7 }, + { "ABCDEFG", "a", 5, PR_FALSE, 0 }, + { "ABCDEFG", "c", 5, PR_FALSE, 0 }, + { "ABCDEFG", "e", 5, PR_FALSE, 0 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_FALSE, 0 }, + { "ABCDEFG", "cd", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 6, PR_FALSE, 0 }, + { "ABCDABC", "bc", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "e", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "g", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 13, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 14, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 13, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 14, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 15, PR_FALSE, 0 } + }; + + int i; + + printf("Test 026 (PL_strnrstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strnrstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcasestr */ +PRBool test_027(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 0 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 1 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_TRUE, 1 }, + { "ABCDEFG", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_TRUE, 1 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_TRUE, 0 } + }; + + int i; + + printf("Test 027 (PL_strcasestr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strcasestr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strcaserstr */ +PRBool test_028(void) +{ + static struct + { + const char *str; + const char *sub; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, PR_FALSE, 0 }, + { (const char *)0, "blah", PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", PR_TRUE, 8 }, + { "", "blah", PR_FALSE, 0 }, + { "blah-de-blah", "", PR_FALSE, 0 }, + { "abcdefg", "a", PR_TRUE, 0 }, + { "abcdefg", "c", PR_TRUE, 2 }, + { "abcdefg", "e", PR_TRUE, 4 }, + { "abcdefg", "g", PR_TRUE, 6 }, + { "abcdefg", "i", PR_FALSE, 0 }, + { "abcdefg", "ab", PR_TRUE, 0 }, + { "abcdefg", "cd", PR_TRUE, 2 }, + { "abcdefg", "ef", PR_TRUE, 4 }, + { "abcdefg", "gh", PR_FALSE, 0 }, + { "abcdabc", "bc", PR_TRUE, 5 }, + { "abcdefg", "abcdefg", PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", PR_TRUE, 13 }, + { "abcdefgabcdefg", "i", PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", PR_TRUE, 11 }, + { "abcdefgabcdefg", "gh", PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", PR_TRUE, 7 }, + { "ABCDEFG", "a", PR_TRUE, 0 }, + { "ABCDEFG", "c", PR_TRUE, 2 }, + { "ABCDEFG", "e", PR_TRUE, 4 }, + { "ABCDEFG", "g", PR_TRUE, 6 }, + { "ABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFG", "ab", PR_TRUE, 0 }, + { "ABCDEFG", "cd", PR_TRUE, 2 }, + { "ABCDEFG", "ef", PR_TRUE, 4 }, + { "ABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABC", "bc", PR_TRUE, 5 }, + { "ABCDEFG", "abcdefg", PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "c", PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "e", PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "g", PR_TRUE, 13 }, + { "ABCDEFGABCDEFG", "i", PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "cd", PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "ef", PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "gh", PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", PR_TRUE, 12 }, + { "ABCDEFGABCDEFG", "abcdefg", PR_TRUE, 7 } + }; + + int i; + + printf("Test 028 (PL_strcaserstr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strcaserstr(array[i].str, array[i].sub); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncasestr */ +PRBool test_029(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 0 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 0 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 2 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabcabcdabc", "bc", 7, PR_TRUE, 1 }, + { "abcdefgabcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefgabcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFG", "a", 5, PR_TRUE, 0 }, + { "ABCDEFG", "c", 5, PR_TRUE, 2 }, + { "ABCDEFG", "e", 5, PR_TRUE, 4 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_TRUE, 0 }, + { "ABCDEFG", "cd", 5, PR_TRUE, 2 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABC", "bc", 7, PR_TRUE, 1 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "c", 12, PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "e", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "g", 12, PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_TRUE, 2 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABCABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABCABCDABC", "bc", 7, PR_TRUE, 1 }, + { "ABCDEFGABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 8, PR_TRUE, 0 } + }; + + int i; + + printf("Test 029 (PL_strncasestr) ..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strncasestr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strncaserstr */ +PRBool test_030(void) +{ + static struct + { + const char *str; + const char *sub; + PRUint32 max; + PRBool ret; + PRUint32 off; + } array[] = + { + { (const char *)0, (const char *)0, 12, PR_FALSE, 0 }, + { (const char *)0, "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", (const char *)0, 12, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 0, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 2, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 3, PR_FALSE, 0 }, + { "blah-de-blah", "blah", 4, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 5, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 11, PR_TRUE, 0 }, + { "blah-de-blah", "blah", 12, PR_TRUE, 8 }, + { "blah-de-blah", "blah", 13, PR_TRUE, 8 }, + { "", "blah", 12, PR_FALSE, 0 }, + { "blah-de-blah", "", 12, PR_FALSE, 0 }, + { "abcdefg", "a", 5, PR_TRUE, 0 }, + { "abcdefg", "c", 5, PR_TRUE, 2 }, + { "abcdefg", "e", 5, PR_TRUE, 4 }, + { "abcdefg", "g", 5, PR_FALSE, 0 }, + { "abcdefg", "i", 5, PR_FALSE, 0 }, + { "abcdefg", "ab", 5, PR_TRUE, 0 }, + { "abcdefg", "cd", 5, PR_TRUE, 2 }, + { "abcdefg", "ef", 5, PR_FALSE, 0 }, + { "abcdefg", "gh", 5, PR_FALSE, 0 }, + { "abcdabc", "bc", 5, PR_TRUE, 1 }, + { "abcdabc", "bc", 6, PR_TRUE, 1 }, + { "abcdabc", "bc", 7, PR_TRUE, 5 }, + { "abcdefg", "abcdefg", 6, PR_FALSE, 0 }, + { "abcdefg", "abcdefg", 7, PR_TRUE, 0 }, + { "abcdefg", "abcdefg", 8, PR_TRUE, 0 }, + { "abcdefgabcdefg", "a", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "c", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "e", 12, PR_TRUE, 11 }, + { "abcdefgabcdefg", "g", 12, PR_TRUE, 6 }, + { "abcdefgabcdefg", "i", 12, PR_FALSE, 0 }, + { "abcdefgabcdefg", "ab", 12, PR_TRUE, 7 }, + { "abcdefgabcdefg", "cd", 12, PR_TRUE, 9 }, + { "abcdefgabcdefg", "ef", 12, PR_TRUE, 4 }, + { "abcdefgabcdefg", "gh", 12, PR_FALSE, 0 }, + { "abcdabcabcdabc", "bc", 12, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 13, PR_TRUE, 8 }, + { "abcdabcabcdabc", "bc", 14, PR_TRUE, 12 }, + { "abcdefgabcdefg", "abcdefg", 13, PR_TRUE, 0 }, + { "abcdefgabcdefg", "abcdefg", 14, PR_TRUE, 7 }, + { "abcdefgabcdefg", "abcdefg", 15, PR_TRUE, 7 }, + { "ABCDEFG", "a", 5, PR_TRUE, 0 }, + { "ABCDEFG", "c", 5, PR_TRUE, 2 }, + { "ABCDEFG", "e", 5, PR_TRUE, 4 }, + { "ABCDEFG", "g", 5, PR_FALSE, 0 }, + { "ABCDEFG", "i", 5, PR_FALSE, 0 }, + { "ABCDEFG", "ab", 5, PR_TRUE, 0 }, + { "ABCDEFG", "cd", 5, PR_TRUE, 2 }, + { "ABCDEFG", "ef", 5, PR_FALSE, 0 }, + { "ABCDEFG", "gh", 5, PR_FALSE, 0 }, + { "ABCDABC", "bc", 5, PR_TRUE, 1 }, + { "ABCDABC", "bc", 6, PR_TRUE, 1 }, + { "ABCDABC", "bc", 7, PR_TRUE, 5 }, + { "ABCDEFG", "abcdefg", 6, PR_FALSE, 0 }, + { "ABCDEFG", "abcdefg", 7, PR_TRUE, 0 }, + { "ABCDEFG", "abcdefg", 8, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "a", 12, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "c", 12, PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "e", 12, PR_TRUE, 11 }, + { "ABCDEFGABCDEFG", "g", 12, PR_TRUE, 6 }, + { "ABCDEFGABCDEFG", "i", 12, PR_FALSE, 0 }, + { "ABCDEFGABCDEFG", "ab", 12, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "cd", 12, PR_TRUE, 9 }, + { "ABCDEFGABCDEFG", "ef", 12, PR_TRUE, 4 }, + { "ABCDEFGABCDEFG", "gh", 12, PR_FALSE, 0 }, + { "ABCDABCABCDABC", "bc", 12, PR_TRUE, 8 }, + { "ABCDABCABCDABC", "bc", 13, PR_TRUE, 8 }, + { "ABCDABCABCDABC", "bc", 14, PR_TRUE, 12 }, + { "ABCDEFGABCDEFG", "abcdefg", 13, PR_TRUE, 0 }, + { "ABCDEFGABCDEFG", "abcdefg", 14, PR_TRUE, 7 }, + { "ABCDEFGABCDEFG", "abcdefg", 15, PR_TRUE, 7 } + }; + + int i; + + printf("Test 030 (PL_strncaserstr)..."); fflush(stdout); + + for( i = 0; i < sizeof(array)/sizeof(array[0]); i++ ) + { + char *rv = PL_strncaserstr(array[i].str, array[i].sub, array[i].max); + + if( PR_FALSE == array[i].ret ) + { + if( (char *)0 != rv ) + { + printf("FAIL %d: %s,%s/%lu -> %.32s, not null\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv); + return PR_FALSE; + } + } + else + { + if( (char *)0 == rv ) + { + printf("FAIL %d: %s,%s/%lu -> null, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, array[i].str, array[i].off); + return PR_FALSE; + } + + if( &array[i].str[ array[i].off ] != rv ) + { + printf("FAIL %d: %s,%s/%lu -> 0x%x, not 0x%x+%lu\n", i, + array[i].str ? array[i].str : "(null)", + array[i].sub ? array[i].sub : "(null)", + array[i].max, rv, array[i].str, array[i].off); + return PR_FALSE; + } + } + } + + printf("PASS\n"); + return PR_TRUE; +} + +/* PL_strtok_r */ +PRBool test_031(void) +{ + static const char *tokens[] = { + "wtc", "relyea", "nelsonb", "jpierre", "nicolson", + "ian.mcgreer", "kirk.erickson", "sonja.mirtitsch", "mhein" + }; + + static const char *seps[] = { + ", ", ",", " ", "\t", ",,,", " ,", " ", " \t\t", "," + }; + + static const char s2[] = ", \t"; + + char string[ 1024 ]; + char *s1; + char *token; + char *lasts; + unsigned int i; + + printf("Test 031 (PL_strtok_r) ..."); fflush(stdout); + + /* Build the string. */ + string[0] = '\0'; + for( i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++ ) + { + PL_strcat(string, tokens[i]); + PL_strcat(string, seps[i]); + } + + /* Scan the string for tokens. */ + i = 0; + s1 = string; + while( (token = PL_strtok_r(s1, s2, &lasts)) != NULL) + { + if( PL_strcmp(token, tokens[i]) != 0 ) + { + printf("FAIL wrong token scanned\n"); + return PR_FALSE; + } + i++; + s1 = NULL; + } + if( i != sizeof(tokens)/sizeof(tokens[0]) ) + { + printf("FAIL wrong number of tokens scanned\n"); + return PR_FALSE; + } + + printf("PASS\n"); + return PR_TRUE; +} + +int +main +( + int argc, + char *argv[] +) +{ + printf("Testing the Portable Library string functions:\n"); + + if( 1 + && test_001() + && test_001() + && test_002() + && test_003() + && test_004() + && test_005() + && test_006() + && test_007() + && test_008() + && test_009() + && test_010() + && test_011() + && test_012() + && test_013() + && test_014() + && test_015() + && test_016() + && test_017() + && test_018() + && test_019() + && test_020() + && test_021() + && test_022() + && test_023() + && test_024() + && test_025() + && test_026() + && test_027() + && test_028() + && test_029() + && test_030() + && test_031() + ) + { + printf("Suite passed.\n"); + return 0; + } + else + { + printf("Suite failed.\n"); + return 1; + } + + /*NOTREACHED*/ +} diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/windows/makefile b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/makefile new file mode 100644 index 00000000..1cf2c079 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/makefile @@ -0,0 +1,82 @@ +# +# 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 Netscape are +# Copyright (C) 1998-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +#! gmake + + + +MOD_DEPTH = ../../.. + +include $(MOD_DEPTH)/config/config.mk + +INCLUDES = -I$(DIST)/include + +CSRCS = winevent.c + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(DIST)/lib/nspr$(MOD_VERSION).lib + LIBPLC= $(DIST)/lib/plc$(MOD_VERSION).lib + LIBPLDS= $(DIST)/lib/plds$(MOD_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + ifeq ($(OS_TARGET), WIN95) + LIBPR = $(DIST)/lib/nspr$(MOD_VERSION).$(LIB_SUFFIX) + LIBPLC= $(DIST)/lib/plc$(MOD_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(DIST)/lib/plds$(MOD_VERSION).lib + else + LIBPR = $(DIST)/lib/libnspr$(MOD_VERSION).$(LIB_SUFFIX) + LIBPLC= $(DIST)/lib/libplc$(MOD_VERSION).$(LIB_SUFFIX) + LIBPLDS= $(DIST)/lib/libplds$(MOD_VERSION).lib + endif +endif +endif + +TARGETS = $(OBJDIR)/winevent.exe +OS_CFLAGS = $(OS_EXE_CFLAGS) +LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO +LDFLAGS += -DEBUG +LIBPR += $(LIBPLDS) +LIBPR += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib + +include $(MOD_DEPTH)/config/rules.mk + +$(OBJDIR)/winevent.exe: $(OBJS) + link $(LDOPTS) $< $(LIBPLC) $(LIBPR) wsock32.lib -out:$@ + +export:: $(TARGETS) + +install:: export + +clean:: + rm -rf $(TARGETS) diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/windows/readme.1st b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/readme.1st new file mode 100644 index 00000000..2b756823 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/readme.1st @@ -0,0 +1,37 @@ +readme.1st. + +The files in the lib/tests/WinGUI directory are taken +from "Programming Windows 3.1" by Charles Petzold, +specifically, the programs in chapter 14 related +to the "poppad4" sample application. + +These programs are compiled with nspr20 to test nspr 2.0 +and to demostrate the use of nspr in a gui application. + +Library (DLL) PLDSxx.lib PLDSxx.dll is required to be +linked with this test case. Functions in this dll are +in the source ns/nspr20/lib/ds/plevent.* files. + +Permission to use. + +The source for poppad.c are used under license from +Petzold. The license to use is stated in the book. +The following paragraph of the license grants that +use. + + 5. SAMPLE CODE. If the SOFTWARE includes Sample Code, then + Microsoft grants you a royalty-free right to reproduce and + distribute the sample code of the SOFTWARE provided that you: + (a) distribute the sample code only in conjunction with and + as part of your software product; (b) do not use Microsoft's + or its authors' names, logos, or trademarks to market your + software product; (c) include the copyright notice that appears + on the SOFTWARE on your product label and as a part of the + sign-on message for your software product; and (d) agree to + idemnify, hold harmless, and defend Microsoft and its authors + from and against any claims or lawsuits, including attorneys' + fees, that arise or result from the use or distribution of + your software product. + +lth. 9/24/97. + diff --git a/src/libs/xpcom18a4/nsprpub/lib/tests/windows/winevent.c b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/winevent.c new file mode 100644 index 00000000..d571aed7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/lib/tests/windows/winevent.c @@ -0,0 +1,348 @@ +/* -*- 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 ***** */ + +/* +** File: winevent.c +** Description: Test functions in plevent.c using Windows +** +** The winevent test exercises the PLEvent library in a maner +** similar to how the Mozilla (or NGLayout) Client will use +** it in a Windows environment. +** +** This test is based on ideas taken from Charles Petzold's +** book "Programming Windows 3.1". License to use is in the +** book. It has been ported to Win32. +** +** Operation: +** The initialization is a standard Windows GUI application +** setup. When the main window receives its WM_CREATE +** message, a child window is created, a edit control is +** instantiated in that window. +** +** A thread is created; this thread runs in the function: +** TimerThread(). The new thread sends a message every second +** via the PL_PostEvent() function. The event handler +** HandlePadEvent() sends a windows message to the edit +** control window; these messages are WM_CHAR messages that +** cause the edit control to place a single '.' character in +** the edit control. +** +** After a deterministic number of '.' characters, the +** TimerThread() function is notified via a global variable +** that it's quitting time. +** +** TimerThread() callse TestEvents(), an external function +** that tests additional function of PLEvent. +** +*/ + +#include "nspr.h" +#include "plevent.h" + +#include +#include + +#define ID_EDIT 1 + +/* +** Declarations for NSPR customization +** +*/ +typedef struct PadEvent +{ + PLEvent plEvent; + int unused; +} PadEvent; + +static void PR_CALLBACK TimerThread( void *arg); +static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ); +static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ); + +static PRThread *tThread; +static PLEventQueue *padQueue; +static long ThreadSleepTime = 1000; /* in milli-seconds */ +static long timerCount = 0; +static HWND hDlgModeless ; +static HWND hwndEdit ; +static PRBool testFinished = PR_FALSE; +static HWND hwnd ; + +LRESULT CALLBACK WinProc (HWND, UINT, WPARAM, LPARAM); + +TCHAR appName[] = TEXT ("WinEvent") ; + +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + PSTR szCmdLine, + int iCmdShow + ) +{ + MSG msg ; + WNDCLASS wndclass ; + HANDLE hAccel ; + + PR_Init(0, 0, 0); + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WinProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ); + wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndclass.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH ); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = appName; + + if ( !RegisterClass( &wndclass )) + { + MessageBox( NULL, + TEXT( "This program needs Win32" ), + appName, + MB_ICONERROR ); + return 0; + } + + hwnd = CreateWindow( appName, + appName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + hInstance, + NULL); + + ShowWindow( hwnd, iCmdShow ); + UpdateWindow( hwnd ); + + for(;;) + { + if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE )) + { + if ( GetMessage( &msg, NULL, 0, 0 )) + { + if ( hDlgModeless == NULL || !IsDialogMessage( hDlgModeless, &msg )) + { + if ( !TranslateAccelerator( hwnd, hAccel, &msg )) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } /* end if !TranslateAccelerator */ + } + } + else + { + break; + } /* end if GetMessage() */ + } + else /* !PeekMessage */ + { + PR_Sleep(50); + }/* end if PeekMessage() */ + } /* end for() */ + + PR_JoinThread( tThread ); + PL_DestroyEventQueue( padQueue ); + PR_Cleanup(); + return msg.wParam ; +} + +LRESULT CALLBACK WinProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + switch (message) + { + case WM_CREATE : + hwndEdit = CreateWindow( + TEXT( "edit" ), + NULL, + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | + WS_BORDER | ES_LEFT | ES_MULTILINE | + ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, + hwnd, + (HMENU)ID_EDIT, + ((LPCREATESTRUCT)lParam)->hInstance, + NULL); + + /* Initialize Event Processing for NSPR + ** Retrieve the event queue just created + ** Create the TimerThread + */ + +/* + PL_InitializeEventsLib( "someName" ); + padQueue = PL_GetMainEventQueue(); +*/ + padQueue = PL_CreateEventQueue("MainQueue", PR_GetCurrentThread()); + PR_ASSERT( padQueue != NULL ); + tThread = PR_CreateThread( PR_USER_THREAD, + TimerThread, + NULL, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + return 0 ; + + case WM_SETFOCUS : + SetFocus( hwndEdit ); + return 0; + + case WM_SIZE : + MoveWindow( hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE ); + return 0 ; + + case WM_COMMAND : + if ( LOWORD(wParam) == ID_EDIT ) + if ( HIWORD(wParam ) == EN_ERRSPACE || + HIWORD( wParam ) == EN_MAXTEXT ) + + MessageBox( hwnd, TEXT( "Edit control out of space." ), + appName, MB_OK | MB_ICONSTOP ); + return 0; + + case WM_DESTROY : + PostQuitMessage(0); + return 0; + } + return DefWindowProc( hwnd, message, wParam, lParam ); +} + + + +/* +** TimerThread() -- The Main function of the timer pop thread +** +*/ +static void PR_CALLBACK TimerThread( void *arg ) +{ + PRIntn rc; + + do { + PadEvent *ev; + + /* + ** Create and Post the event the event + */ + PL_ENTER_EVENT_QUEUE_MONITOR( padQueue ); + ev = (PadEvent *) PR_NEW( PadEvent ); + PL_InitEvent( &ev->plEvent, NULL, + (PLHandleEventProc)HandlePadEvent, + (PLDestroyEventProc)DestroyPadEvent ); + PL_PostEvent( padQueue, &ev->plEvent ); + PL_EXIT_EVENT_QUEUE_MONITOR( padQueue ); + + PR_Sleep( PR_MillisecondsToInterval(ThreadSleepTime) ); + } while( testFinished == PR_FALSE ); + + PR_Sleep( PR_SecondsToInterval(4) ); + + /* + ** All done now. This thread can kill the main thread by sending + ** WM_DESTROY message to the main window. + */ + SendMessage( hwnd, WM_DESTROY, 0, 0 ); + return; +} + +static char *startMessage = "Poppad: NSPR Windows GUI and event test program.\n" + "Every 1 second gets a '.'.\n" + "The test self terminates in less than a minute\n" + "You should be able to type in the window.\n\n"; + +static char *stopMessage = "\n\nIf you saw a series of dots being emitted in the window\n" + " at one second intervals, the test worked.\n\n"; + +/* +** HandlePadEvent() -- gets called because of PostEvent +*/ +static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ) +{ + char *cp; + static const long lineLimit = 10; /* limit on number of '.' per line */ + static const long timerLimit = 25; /* limit on timer pop iterations */ + + if ( timerCount++ == 0 ) + { + + for ( cp = startMessage; *cp != 0 ; cp++ ) + { + SendMessage( hwndEdit, WM_CHAR, *cp, 1 ); + } + } + /* + ** Send a WM_CHAR event the edit Window + */ + SendMessage( hwndEdit, WM_CHAR, '.', 1 ); + + /* + ** Limit the number of characters sent via timer pop to lineLimit + */ + if ( (timerCount % lineLimit) == 0) + { + SendMessage( hwndEdit, WM_CHAR, '\n', 1 ); + } + + if ( timerCount >= timerLimit ) + { + for ( cp = stopMessage; *cp != 0 ; cp++ ) + { + SendMessage( hwndEdit, WM_CHAR, *cp, 1 ); + } + testFinished = PR_TRUE; + } + + return; +} + +/* +** DestroyPadEvent() -- Called after HandlePadEvent() +*/ +static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ) +{ + PR_Free( padevent ); + return; +} diff --git a/src/libs/xpcom18a4/nsprpub/makefile.win b/src/libs/xpcom18a4/nsprpub/makefile.win new file mode 100644 index 00000000..97beeabe --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/makefile.win @@ -0,0 +1,127 @@ + +# +# ***** 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 ***** + + +# +# An NMAKE file to set up and adjust NSPR20's build system for +# Client build. Client build should invoke NMAKE on this file +# instead of invoking gmake directly. +# + +DEPTH = .. +include <$(DEPTH)\config\config.mak> + +# +# Backslashes are escape characters to gmake, so flip all backslashes +# in $(MOZ_TOOLS) to forward slashes and pass that to gmake. +# + +GMAKE = $(MOZ_TOOLS)\bin\gmake.exe + +GMAKE_FLAGS = MOZ_TOOLS_FLIPPED=$(MOZ_TOOLS:\=/) PR_CLIENT_BUILD=1 PR_CLIENT_BUILD_WINDOWS=1 + +# +# The Client's debug build uses MSVC's debug runtime library (/MDd). +# + +!ifdef MOZ_DEBUG +!else +GMAKE_FLAGS = $(GMAKE_FLAGS) BUILD_OPT=1 +!endif + +!if "$(MOZ_BITS)" == "16" +GMAKE_FLAGS = $(GMAKE_FLAGS) OS_TARGET=WIN16 +!else + +GMAKE_FLAGS = $(GMAKE_FLAGS) OS_TARGET=WIN95 +!ifdef MOZ_DEBUG +!ifdef MOZ_NO_DEBUG_RTL +!IF "$(CPU)" == "ALPHA" +PR_OBJDIR = WIN954.0ALPHA_DBG.OBJ +!else +PR_OBJDIR = WIN954.0_DBG.OBJ +!endif +!else +GMAKE_FLAGS = $(GMAKE_FLAGS) USE_DEBUG_RTL=1 +!IF "$(CPU)" == "ALPHA" +PR_OBJDIR = WIN954.0ALPHA_DBG.OBJD +!else +PR_OBJDIR = WIN954.0_DBG.OBJD +!endif +!endif +!else +!IF "$(CPU)" == "ALPHA" +PR_OBJDIR = WIN954.0ALPHA_OPT.OBJ +!else +PR_OBJDIR = WIN954.0_OPT.OBJ +!endif +!endif + +!endif + + +# +# The rules. Simply invoke gmake with the same target. +# The default target is 'all'. For Win16, set up the +# environment to use the Watcom compiler, Watcom headers, +# and Watcom libs. +# + +all:: export libs install + +export libs install clobber clobber_all clean depend:: +!if "$(MOZ_BITS)" == "16" + set PATH=%WATCPATH% + set INCLUDE=%WATC_INC% + set LIB=%WATC_LIB% +!endif + $(GMAKE) $(GMAKE_FLAGS) $@ +!if "$(MOZ_BITS)" == "16" + set PATH=%MSVCPATH% + set INCLUDE=%MSVC_INC% + set LIB=%MSVC_LIB% +!endif + +!if "$(MOZ_BITS)" != "16" +export:: + $(MAKE_INSTALL) $(XPDIST)\$(PR_OBJDIR)\include\*.h $(DIST)\include + $(MAKE_INSTALL) $(XPDIST)\$(PR_OBJDIR)\include\obsolete\*.h $(DIST)\include\obsolete + $(MAKE_INSTALL) $(XPDIST)\$(PR_OBJDIR)\include\private\*.h $(DIST)\include\private + $(MAKE_INSTALL) $(XPDIST)\$(PR_OBJDIR)\lib\*.lib $(DIST)\lib + $(MAKE_INSTALL) $(XPDIST)\$(PR_OBJDIR)\lib\*.dll $(DIST)\bin +!endif diff --git a/src/libs/xpcom18a4/nsprpub/pkg/Makefile.in b/src/libs/xpcom18a4/nsprpub/pkg/Makefile.in new file mode 100644 index 00000000..b21d7741 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = +ifeq ($(OS_TARGET),Linux) +DIRS = linux +endif +ifeq ($(OS_TARGET),SunOS) +DIRS = solaris +endif + +publish:: + +$(LOOP_OVER_DIRS) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/nsprpub/pkg/linux/Makefile.in b/src/libs/xpcom18a4/nsprpub/pkg/linux/Makefile.in new file mode 100644 index 00000000..630af186 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/linux/Makefile.in @@ -0,0 +1,44 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.in $" +# + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +NAME = sun-nspr +RELEASE = 1 +TOPDIR = /usr/src/redhat +VERSION = `grep PR_VERSION $(dist_includedir)/prinit.h \ + | sed -e 's/"$$//' -e 's/.*"//' -e 's/ .*//'` + +include $(MOD_DEPTH)/config/autoconf.mk + +publish: + $(MAKE) clean + mkdir -p usr/lib/mps + cp -L $(MOD_DEPTH)/dist/lib/* usr/lib/mps + mkdir -p usr/include/mps + cp -Lr $(MOD_DEPTH)/dist/include/* usr/include/mps + tar czvf $(NAME)-$(VERSION).tar.gz usr + echo "%define name $(NAME)" >$(NAME).spec + echo "%define version $(VERSION)" >>$(NAME).spec + echo "%define release $(RELEASE)" >>$(NAME).spec + + cat $(srcdir)/$(NAME).spec >>$(NAME).spec + cp $(NAME)-$(VERSION).tar.gz $(TOPDIR)/SOURCES + rpm -ba $(NAME).spec + if [ ! -d RPMS ] ; then mkdir -p RPMS ; fi + if [ ! -d SRPMS ] ; then mkdir -p SRPMS ; fi + cp -v $(TOPDIR)/RPMS/i386/$(NAME)-$(VERSION)-* RPMS + cp -v $(TOPDIR)/RPMS/i386/$(NAME)-devel-$(VERSION)-* RPMS + cp -v $(TOPDIR)/SRPMS/$(NAME)-$(VERSION)-* SRPMS + +clean: + rm -rf $(TOPDIR)/BUILD/$(NAME) + rm -rf RPMS SRPMS usr + rm -f $(NAME)-$(VERSION).tar.gz diff --git a/src/libs/xpcom18a4/nsprpub/pkg/linux/sun-nspr.spec b/src/libs/xpcom18a4/nsprpub/pkg/linux/sun-nspr.spec new file mode 100644 index 00000000..1fed5048 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/linux/sun-nspr.spec @@ -0,0 +1,122 @@ +Summary: Netscape Portable Runtime +Name: %{name} +Vendor: Sun Microsystems +Version: %{version} +Release: %{release} +Copyright: MPL/GPL +Group: System Environment/Base +Source: %{name}-%{version}.tar.gz +ExclusiveOS: Linux +BuildRoot: /var/tmp/%{name}-root + +%description + +NSPR provides platform independence for non-GUI operating system +facilities. These facilities include threads, thread synchronization, +normal file and network I/O, interval timing and calendar time, basic +memory management (malloc and free) and shared library linking. + +See: http://www.mozilla.org/projects/nspr/about-nspr.html + +%package devel +Summary: Development Libraries for the Netscape Portable Runtime +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Header files for doing development with the Netscape Portable Runtime. + +%prep +%setup -c + +%build + +%install +rm -rf $RPM_BUILD_ROOT +mkdir $RPM_BUILD_ROOT +cd $RPM_BUILD_ROOT +tar xvzf $RPM_SOURCE_DIR/%{name}-%{version}.tar.gz + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%dir /usr +%dir /usr/lib +%dir /usr/lib/mps +/usr/lib/mps/libnspr4.so +/usr/lib/mps/libplc4.so +/usr/lib/mps/libplds4.so + +%files devel +%defattr(-,root,root) +/usr/lib/mps/libnspr4.a +/usr/lib/mps/libplc4.a +/usr/lib/mps/libplds4.a +%dir /usr +%dir /usr/include +%dir /usr/include/mps +%dir /usr/include/mps/nspr +%dir /usr/include/mps/nspr/obsolete +%dir /usr/include/mps/nspr/private +/usr/include/mps/nspr/private/pprio.h +/usr/include/mps/nspr/private/pprthred.h +/usr/include/mps/nspr/private/prpriv.h +/usr/include/mps/nspr/prcpucfg.h +/usr/include/mps/nspr/obsolete/pralarm.h +/usr/include/mps/nspr/obsolete/probslet.h +/usr/include/mps/nspr/obsolete/protypes.h +/usr/include/mps/nspr/obsolete/prsem.h +/usr/include/mps/nspr/nspr.h +/usr/include/mps/nspr/pratom.h +/usr/include/mps/nspr/prbit.h +/usr/include/mps/nspr/prclist.h +/usr/include/mps/nspr/prcmon.h +/usr/include/mps/nspr/prcountr.h +/usr/include/mps/nspr/prcvar.h +/usr/include/mps/nspr/prdtoa.h +/usr/include/mps/nspr/prenv.h +/usr/include/mps/nspr/prerr.h +/usr/include/mps/nspr/prerror.h +/usr/include/mps/nspr/prinet.h +/usr/include/mps/nspr/prinit.h +/usr/include/mps/nspr/prinrval.h +/usr/include/mps/nspr/prio.h +/usr/include/mps/nspr/pripcsem.h +/usr/include/mps/nspr/prlink.h +/usr/include/mps/nspr/prlock.h +/usr/include/mps/nspr/prlog.h +/usr/include/mps/nspr/prlong.h +/usr/include/mps/nspr/prmem.h +/usr/include/mps/nspr/prmon.h +/usr/include/mps/nspr/prmwait.h +/usr/include/mps/nspr/prnetdb.h +/usr/include/mps/nspr/prolock.h +/usr/include/mps/nspr/prpdce.h +/usr/include/mps/nspr/prprf.h +/usr/include/mps/nspr/prproces.h +/usr/include/mps/nspr/prrng.h +/usr/include/mps/nspr/prrwlock.h +/usr/include/mps/nspr/prshma.h +/usr/include/mps/nspr/prshm.h +/usr/include/mps/nspr/prsystem.h +/usr/include/mps/nspr/prthread.h +/usr/include/mps/nspr/prtime.h +/usr/include/mps/nspr/prtpool.h +/usr/include/mps/nspr/prtrace.h +/usr/include/mps/nspr/prtypes.h +/usr/include/mps/nspr/prvrsion.h +/usr/include/mps/nspr/prwin16.h +/usr/include/mps/nspr/plarenas.h +/usr/include/mps/nspr/plarena.h +/usr/include/mps/nspr/plhash.h +/usr/include/mps/nspr/plbase64.h +/usr/include/mps/nspr/plerror.h +/usr/include/mps/nspr/plgetopt.h +/usr/include/mps/nspr/plresolv.h +/usr/include/mps/nspr/plstr.h + +%changelog +* Sat Jan 18 2003 Kirk Erickson +- http://bugzilla.mozilla.org/show_bug.cgi?id=189501 diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.com b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.com new file mode 100644 index 00000000..32de8a9b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.com @@ -0,0 +1,32 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.com $" +# + +MACH = $(shell mach) + +PUBLISH_ROOT = $(DIST) +ifeq ($(MOD_DEPTH),../..) +ROOT = ROOT +else +ROOT = $(subst ../../,,$(MOD_DEPTH))/ROOT +endif + +PKGARCHIVE = $(dist_libdir)/pkgarchive +DATAFILES = copyright +FILES = $(DATAFILES) pkginfo prototype + +PACKAGE = $(shell basename `pwd`) + +PRODUCT_VERSION = $(shell grep PR_VERSION $(dist_includedir)/prinit.h \ + | sed -e 's/"$$//' -e 's/.*"//' -e 's/ .*//') + +LN = /usr/bin/ln + +CLOBBERFILES = $(FILES) + +include $(topsrcdir)/config/rules.mk + +# vim: ft=make diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.in b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.in new file mode 100644 index 00000000..0c2d2e31 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.in @@ -0,0 +1,60 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.in $" +# + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +%: %.ksh + $(RM) $@ + cp $< $@ + chmod +x $@ + +ifeq ($(USE_64), 1) +DIRS = \ + SUNWprx +else +DIRS = \ + SUNWpr +endif + +PROTO = \ + $(ROOT) \ + $(ROOT)/usr \ + $(ROOT)/usr/lib \ + $(ROOT)/usr/lib/mps + +ifdef USE_64 +PROTO += $(ROOT)/usr/lib/mps/sparcv9 +endif + +include $(srcdir)/Makefile.com + +awk_pkginfo: bld_awk_pkginfo + ./bld_awk_pkginfo -m $(MACH) -p "$(PRODUCT_VERSION)" -o $@ -v $(PRODUCT_VERSION) + +all:: awk_pkginfo $(PROTO) +publish: awk_pkginfo $(PROTO) + +$(LOOP_OVER_DIRS) + +clean clobber:: + $(RM) awk_pkginfo bld_awk_pkginfo + $(RM) -r $(ROOT) + +$(ROOT) $(ROOT)/%: + mkdir -p $@ + +ifdef USE_64 +$(ROOT)/usr/lib/mps/sparcv9: + $(LN) -sf ../../../../$(dist_libdir) $@ +else +$(ROOT)/usr/lib/mps: + $(LN) -sf ../../../$(dist_libdir) $@ +endif diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.targ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.targ new file mode 100644 index 00000000..9c49cf20 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/Makefile.targ @@ -0,0 +1,40 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.targ $" +# + +pkginfo: pkginfo.tmpl ../awk_pkginfo + $(RM) $@; nawk -f ../awk_pkginfo $< > $@ + +# we need to copy prototype_sparc to current too find copyright in current +prototype: $(srcdir)/prototype_com $(srcdir)/prototype_$(MACH) + cat $(srcdir)/prototype_$(MACH) | sed -e \ +'/^!include[ ][ ]*prototype_com/ r ./prototype_com' \ +-e 's/^!include[ ][ ]*prototype_com//g' >prototype + + + +pkg: $(PKGARCHIVE) prototype + cp $(srcdir)/prototype_com . + cp $(srcdir)/prototype_$(MACH) . + cp $(srcdir)/depend . + pkgmk -f prototype_$(MACH) -d $(PKGARCHIVE) -r $(ROOT) -o $(PACKAGE) + +$(PKGARCHIVE): + [ -d $(PKGARCHIVE) ] || mkdir -p $(PKGARCHIVE) + +$(DATAFILES): %: $(srcdir)/../common_files/% + $(RM) $@; cp $(srcdir)/../common_files/$@ $@ + +#$(MACHDATAFILES): %: $(srcdir)/../common_files/%_$(MACH) +# $(RM) $@; cp $(srcdir)/../common_files/$@_$(MACH) $@ +# +#$(MACHDATAFILES): %: $(srcdir)/%_$(MACH) +# $(RM) $@; cp $(srcdir)/$@_$(MACH) $@ + +clobber clean:: + -$(RM) $(CLOBBERFILES) $(CLEANFILES) + +.PHONY: pkg diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/Makefile.in b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/Makefile.in new file mode 100644 index 00000000..ab54db6f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/Makefile.in @@ -0,0 +1,22 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.in $" +# + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(srcdir)/../Makefile.com + +DATAFILES += + +all:: $(FILES) +publish:: all pkg + +include $(srcdir)/../Makefile.targ diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/depend b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/depend new file mode 100644 index 00000000..57bc554e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/depend @@ -0,0 +1,27 @@ +# Copyright 2002 Microsystems, Inc. All Rights Reserved. +# Use is subject to license terms. +# +# $Id: depend $ +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# see pkginfo(4), PKG parameter +# see pkginfo(4), NAME parameter +# see pkginfo(4), VERSION parameter +# see pkginfo(4), ARCH parameter +# +# () +# () +# ... +# +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl new file mode 100644 index 00000000..431ef37a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/pkginfo.tmpl @@ -0,0 +1,34 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: pkginfo.tmpl $" +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWpr" +NAME="Netscape Portable Runtime" +ARCH="ISA" +VERSION="NSPRVERS,REV=0.0.0" +SUNW_PRODNAME="Netscape Portable Runtime" +SUNW_PRODVERS="NSPRVERS" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Netscape Portable Runtime Interface" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +#VSTOCK="" +#ISTATES="" +#RSTATES='' +#ULIMIT="" +#ORDER="" +#PSTAMP="" +#INTONLY="" diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_com b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_com new file mode 100644 index 00000000..e92c4e51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_com @@ -0,0 +1,31 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: prototype_com $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# packaging files +i copyright +i pkginfo +i depend +# +# source locations relative to the prototype file +# +# SUNWpr +# +d none usr 755 root sys +d none usr/lib 755 root bin +d none usr/lib/mps 755 root bin +f none usr/lib/mps/libnspr4.so 755 root bin +f none usr/lib/mps/libplc4.so 755 root bin +f none usr/lib/mps/libplds4.so 755 root bin diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_i386 b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_i386 new file mode 100644 index 00000000..76b92016 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_i386 @@ -0,0 +1,30 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: prototype_i386 $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are i386 specific here +# +# source locations relative to the prototype file +# +# +# SUNWpr +# diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_sparc b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_sparc new file mode 100644 index 00000000..4da58b01 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWpr/prototype_sparc @@ -0,0 +1,33 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: prototype_sparc $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWpr +# +d none usr/lib/mps/cpu 755 root bin +d none usr/lib/mps/cpu/sparcv8plus 755 root bin +f none usr/lib/mps/cpu/sparcv8plus/libnspr_flt4.so 755 root bin diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/Makefile.in b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/Makefile.in new file mode 100644 index 00000000..ab54db6f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/Makefile.in @@ -0,0 +1,22 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: Makefile.in $" +# + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(srcdir)/../Makefile.com + +DATAFILES += + +all:: $(FILES) +publish:: all pkg + +include $(srcdir)/../Makefile.targ diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/depend b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/depend new file mode 100644 index 00000000..5be1ecd9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/depend @@ -0,0 +1,30 @@ +# Copyright 2002 Microsystems, Inc. All Rights Reserved. +# Use is subject to license terms. +# +# $Id: depend $ +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# see pkginfo(4), PKG parameter +# see pkginfo(4), NAME parameter +# see pkginfo(4), VERSION parameter +# see pkginfo(4), ARCH parameter +# +# () +# () +# ... +# +# ... + +P SUNWcar Core Architecture, (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWcarx Core Architecture, (Root) (64-bit) +P SUNWcsxu Core Solaris (Usr) (64-bit) +P SUNWcslx Core Solaris Libraries (64-bit) diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/pkginfo.tmpl b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/pkginfo.tmpl new file mode 100644 index 00000000..0b13c5be --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/pkginfo.tmpl @@ -0,0 +1,35 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: pkginfo.tmpl $" +# +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWprx" +NAME="Netscape Portable Runtime (64-bit)" +ARCH="ISA" +SUNW_ISA="sparcv9" +VERSION="NSPRVERS,REV=0.0.0" +SUNW_PRODNAME="Netscape Portable Runtime" +SUNW_PRODVERS="NSPRVERS" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Netscape Portable Runtime Interface (64-bit)" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +#VSTOCK="" +#ISTATES="" +#RSTATES='' +#ULIMIT="" +#ORDER="" +#PSTAMP="" +#INTONLY="" diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_com b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_com new file mode 100644 index 00000000..700d61ca --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_com @@ -0,0 +1,28 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: prototype_com $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# packaging files +i copyright +i pkginfo +i depend +# +# source locations relative to the prototype file +# +# SUNWprx +# +d none usr 755 root sys +d none usr/lib 755 root bin +d none usr/lib/mps 755 root bin diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_sparc b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_sparc new file mode 100644 index 00000000..cd3da121 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/SUNWprx/prototype_sparc @@ -0,0 +1,35 @@ +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "$Id: prototype_sparc $" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search # where to find pkg objects +#!include # include another 'prototype' file +#!default # default used if not specified on entry +#!= # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWprx +# +s none usr/lib/mps/64=sparcv9 +d none usr/lib/mps/sparcv9 755 root bin +f none usr/lib/mps/sparcv9/libnspr4.so 755 root bin +f none usr/lib/mps/sparcv9/libplc4.so 755 root bin +f none usr/lib/mps/sparcv9/libplds4.so 755 root bin diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh b/src/libs/xpcom18a4/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh new file mode 100755 index 00000000..b01645e4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/bld_awk_pkginfo.ksh @@ -0,0 +1,105 @@ +#!/usr/bin/ksh -p +# +#ident "$Id: bld_awk_pkginfo.ksh $" +# +# Copyright 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# Simple script which builds the awk_pkginfo awk script. This awk script +# is used to convert the pkginfo.tmpl files into pkginfo files +# for the build. +# + +usage() +{ + cat <<-EOF +usage: bld_awk_pkginfo -p -m -o [-v ] +EOF +} + +# +# Awk strings +# +# two VERSION patterns: one for Dewey decimal, one for Dewey plus ,REV=n +# the first has one '=' the second has two or more '=' +# +VERSION1="VERSION=[^=]*$" +VERSION2="VERSION=[^=]*=.*$" +PRODVERS="^SUNW_PRODVERS=" +ARCH='ARCH=\"ISA\"' + +# +# parse command line +# +mach="" +prodver="" +awk_script="" +version="NSPRVERS" + +while getopts o:p:m:v: c +do + case $c in + o) + awk_script=$OPTARG + ;; + m) + mach=$OPTARG + ;; + p) + prodver=$OPTARG + ;; + v) + version=$OPTARG + ;; + \?) + usage + exit 1 + ;; + esac +done + +if [[ ( -z $prodver ) || ( -z $mach ) || ( -z $awk_script ) ]] +then + usage + exit 1 +fi + +if [[ -f $awk_script ]] +then + rm -f $awk_script +fi + +# +# Build REV= field based on date +# +rev=$(date "+%Y.%m.%d.%H.%M") + +# +# Build awk script which will process all the +# pkginfo.tmpl files. +# +# the first VERSION pattern is replaced with a leading quotation mark +# +rm -f $awk_script +cat << EOF > $awk_script +/$VERSION1/ { + sub(/\=[^=]*$/,"=\"$rev\"") + print + next + } +/$VERSION2/ { + sub(/\=[^=]*$/,"=$rev\"") + sub(/NSPRVERS/,"$version") + print + next + } +/$PRODVERS/ { + printf "SUNW_PRODVERS=\"%s\"\n", "$prodver" + next + } +/$ARCH/ { + printf "ARCH=\"%s\"\n", "$mach" + next + } +{ print } +EOF diff --git a/src/libs/xpcom18a4/nsprpub/pkg/solaris/common_files/copyright b/src/libs/xpcom18a4/nsprpub/pkg/solaris/common_files/copyright new file mode 100644 index 00000000..1e0f6ce3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pkg/solaris/common_files/copyright @@ -0,0 +1,28 @@ +The contents of this package are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this package 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 Netscape are Copyright (C) 1998-2000 +Netscape Communications Corporation. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this package may be used under the terms +of the GNU General Public License Version 2 or later (the "GPL"), in +which case the provisions of the GPL are applicable instead of those +above. If you wish to allow use of your version of this package only +under the terms of the GPL and not to allow others to use your version +of this package under the MPL, indicate your decision by deleting the +provisions above and replace them with the notice and other provisions +required by the GPL. If you do not delete the provisions above, a +recipient may use your version of this package under either the MPL or +the GPL. diff --git a/src/libs/xpcom18a4/nsprpub/pr/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/Makefile.in new file mode 100644 index 00000000..e060f195 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = include src + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/include/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/MANIFEST b/src/libs/xpcom18a4/nsprpub/pr/include/MANIFEST new file mode 100644 index 00000000..634968ef --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/MANIFEST @@ -0,0 +1,52 @@ +# +# This is a list of local files which get copied to the mozilla:dist directory +# + +nspr.h +pratom.h +prbit.h +prclist.h +prcmon.h +prcountr.h +prcvar.h +prdtoa.h +prenv.h +prerr.h +prerror.h +prinet.h +prinit.h +prinrval.h +prio.h +pripcsem.h +prlink.h +prlock.h +prlog.h +prlong.h +prmem.h +prmon.h +prmwait.h +prnetdb.h +prolock.h +prpdce.h +prprf.h +prproces.h +prrng.h +prrwlock.h +prshm.h +prshma.h +prsystem.h +prthread.h +prtime.h +prtpool.h +prtrace.h +prtypes.h +prvrsion.h +prwin16.h + +obsolete/protypes.h +obsolete/prsem.h +obsolete/probslet.h + +private/prpriv.h +private/pprio.h +private/pprthred.h diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/include/Makefile.in new file mode 100644 index 00000000..5dc9686d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/Makefile.in @@ -0,0 +1,59 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +DIRS = md private obsolete + +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR) + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir) diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/gencfg.c b/src/libs/xpcom18a4/nsprpub/pr/include/gencfg.c new file mode 100644 index 00000000..e67c1309 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/gencfg.c @@ -0,0 +1,309 @@ +/* -*- 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 + +#if defined(sgi) +#ifndef IRIX + error - IRIX is not defined +#endif +#endif + +#if defined(__sun) +#if defined(__svr4) || defined(__svr4__) || defined(__SVR4) +#ifndef SOLARIS + error - SOLARIS is not defined +#endif +#else +#ifndef SUNOS4 + error - SUNOS4 is not defined +#endif +#endif +#endif + +#if defined(__hpux) +#ifndef HPUX + error - HPUX is not defined +#endif +#endif + +#if defined(__alpha) +#if !(defined(_WIN32)) && !(defined(OSF1)) && !(defined(__linux)) && !(defined(__FreeBSD__)) + error - None of OSF1, _WIN32, __linux, or __FreeBSD__ is defined +#endif +#endif + +#if defined(_IBMR2) +#ifndef AIX + error - AIX is not defined +#endif +#endif + +#if defined(linux) +#ifndef LINUX + error - LINUX is not defined +#endif +#endif + +#if defined(bsdi) +#ifndef BSDI + error - BSDI is not defined +#endif +#endif + +#if defined(M_UNIX) +#ifndef SCO + error - SCO is not defined +#endif +#endif +#if !defined(M_UNIX) && defined(_USLC_) +#ifndef UNIXWARE + error - UNIXWARE is not defined +#endif +#endif + +#if defined(__APPLE__) +#ifndef DARWIN + error - DARWIN is not defined +#endif +#endif + +#if defined(__NeXT__) +#ifndef NEXTSTEP + error - NEXTSTEP is not defined +#endif +#endif + +/************************************************************************/ + +/* Generate cpucfg.h */ + +#ifdef XP_PC +#ifdef WIN32 +#define INT64 _PRInt64 +#else +#define INT64 long +#endif +#else +#if defined(HPUX) || defined(NECSVR4) || defined(SCO) || defined(UNIXWARE) || defined (NCR) +#define INT64 long +#else +#define INT64 long long +#endif +#endif + +struct align_short { + char c; + short a; +}; +struct align_int { + char c; + int a; +}; +struct align_long { + char c; + long a; +}; +struct align_PRInt64 { + char c; + INT64 a; +}; +struct align_fakelonglong { + char c; + struct { + long hi, lo; + } a; +}; +struct align_float { + char c; + float a; +}; +struct align_double { + char c; + double a; +}; +struct align_pointer { + char c; + void *a; +}; + +#define ALIGN_OF(type) \ + (((char*)&(((struct align_##type *)0)->a)) - ((char*)0)) + +int bpb; + +/* Used if shell doesn't support redirection. By default, assume it does. */ +FILE *stream; + +static int Log2(int n) +{ + int log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + +/* We assume that int's are 32 bits */ +static void do64(void) +{ + union { + int i; + char c[4]; + } u; + + u.i = 0x01020304; + if (u.c[0] == 0x01) { + fprintf(stream, "#undef IS_LITTLE_ENDIAN\n"); + fprintf(stream, "#define IS_BIG_ENDIAN 1\n\n"); + } else { + fprintf(stream, "#define IS_LITTLE_ENDIAN 1\n"); + fprintf(stream, "#undef IS_BIG_ENDIAN\n\n"); + } +} + +static void do32(void) +{ + union { + long i; + char c[4]; + } u; + + u.i = 0x01020304; + if (u.c[0] == 0x01) { + fprintf(stream, "#undef IS_LITTLE_ENDIAN\n"); + fprintf(stream, "#define IS_BIG_ENDIAN 1\n\n"); + } else { + fprintf(stream, "#define IS_LITTLE_ENDIAN 1\n"); + fprintf(stream, "#undef IS_BIG_ENDIAN\n\n"); + } +} + +/* +** Concievably this could actually be used; but there is lots of code out +** there with and's and shift's in it that assumes a byte is 8 bits, so +** forget about porting THIS code to those non 8 bit byte machines. +*/ +static void BitsPerByte(void) +{ + bpb = 8; +} + +int main(int argc, char **argv) +{ + BitsPerByte(); + + /* If we got a command line argument, try to use it as the stream. */ + ++argv; + if(*argv) { + if(!(stream = fopen ( *argv, "wt" ))) { + fprintf(stderr, "Could not write to output file %s.\n", *argv); + return 1; + } + } else { + stream = stdout; + } + + fprintf(stream, "#ifndef nspr_cpucfg___\n"); + fprintf(stream, "#define nspr_cpucfg___\n\n"); + + fprintf(stream, "/* AUTOMATICALLY GENERATED - DO NOT EDIT */\n\n"); + + if (sizeof(long) == 8) { + do64(); + } else { + do32(); + } + fprintf(stream, "#define PR_BYTES_PER_BYTE %d\n", sizeof(char)); + fprintf(stream, "#define PR_BYTES_PER_SHORT %d\n", sizeof(short)); + fprintf(stream, "#define PR_BYTES_PER_INT %d\n", sizeof(int)); + fprintf(stream, "#define PR_BYTES_PER_INT64 %d\n", 8); + fprintf(stream, "#define PR_BYTES_PER_LONG %d\n", sizeof(long)); + fprintf(stream, "#define PR_BYTES_PER_FLOAT %d\n", sizeof(float)); + fprintf(stream, "#define PR_BYTES_PER_DOUBLE %d\n\n", sizeof(double)); + + fprintf(stream, "#define PR_BITS_PER_BYTE %d\n", bpb); + fprintf(stream, "#define PR_BITS_PER_SHORT %d\n", bpb * sizeof(short)); + fprintf(stream, "#define PR_BITS_PER_INT %d\n", bpb * sizeof(int)); + fprintf(stream, "#define PR_BITS_PER_INT64 %d\n", bpb * 8); + fprintf(stream, "#define PR_BITS_PER_LONG %d\n", bpb * sizeof(long)); + fprintf(stream, "#define PR_BITS_PER_FLOAT %d\n", bpb * sizeof(float)); + fprintf(stream, "#define PR_BITS_PER_DOUBLE %d\n\n", + bpb * sizeof(double)); + + fprintf(stream, "#define PR_BITS_PER_BYTE_LOG2 %d\n", Log2(bpb)); + fprintf(stream, "#define PR_BITS_PER_SHORT_LOG2 %d\n", + Log2(bpb * sizeof(short))); + fprintf(stream, "#define PR_BITS_PER_INT_LOG2 %d\n", + Log2(bpb * sizeof(int))); + fprintf(stream, "#define PR_BITS_PER_INT64_LOG2 %d\n", 6); + fprintf(stream, "#define PR_BITS_PER_LONG_LOG2 %d\n", + Log2(bpb * sizeof(long))); + fprintf(stream, "#define PR_BITS_PER_FLOAT_LOG2 %d\n", + Log2(bpb * sizeof(float))); + fprintf(stream, "#define PR_BITS_PER_DOUBLE_LOG2 %d\n\n", + Log2(bpb * sizeof(double))); + + fprintf(stream, "#define PR_ALIGN_OF_SHORT %d\n", ALIGN_OF(short)); + fprintf(stream, "#define PR_ALIGN_OF_INT %d\n", ALIGN_OF(int)); + fprintf(stream, "#define PR_ALIGN_OF_LONG %d\n", ALIGN_OF(long)); + if (sizeof(INT64) < 8) { + /* this machine doesn't actually support PRInt64's */ + fprintf(stream, "#define PR_ALIGN_OF_INT64 %d\n", + ALIGN_OF(fakelonglong)); + } else { + fprintf(stream, "#define PR_ALIGN_OF_INT64 %d\n", ALIGN_OF(PRInt64)); + } + fprintf(stream, "#define PR_ALIGN_OF_FLOAT %d\n", ALIGN_OF(float)); + fprintf(stream, "#define PR_ALIGN_OF_DOUBLE %d\n", ALIGN_OF(double)); + fprintf(stream, "#define PR_ALIGN_OF_POINTER %d\n\n", ALIGN_OF(pointer)); + + fprintf(stream, "#endif /* nspr_cpucfg___ */\n"); + fclose(stream); + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/include/md/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/include/md/Makefile.in new file mode 100644 index 00000000..3f3c08bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/Makefile.in @@ -0,0 +1,80 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +HEADERS = $(wildcard $(srcdir)/*.h) +CONFIGS = $(wildcard $(srcdir)/*.cfg) + +include $(topsrcdir)/config/rules.mk + +export:: $(MDCPUCFG_H) + $(INSTALL) -m 444 $(CONFIGS) $(HEADERS) $(dist_includedir)/md + $(INSTALL) -m 444 $(srcdir)/$(MDCPUCFG_H) $(dist_includedir) +ifeq ($(OS_ARCH),OpenVMS) +# On OpenVMS mv updates the file's modified time, so we create a hard link. + cd $(dist_includedir); \ + if test ! -f prcpucfg.h; then \ + dcl set file /enter=prcpucfg.h $(MDCPUCFG_H); \ + fi +else + mv -f $(dist_includedir)/$(MDCPUCFG_H) $(dist_includedir)/prcpucfg.h +endif + +real_install:: + $(NSINSTALL) -D $(DESTDIR)$(includedir)/md + cp $(srcdir)/$(MDCPUCFG_H) $(DESTDIR)$(includedir)/prcpucfg.h + $(NSINSTALL) -t -m 644 $(HEADERS) $(DESTDIR)$(includedir)/md + +release:: export + @echo "Copying machine-dependent prcpucfg.h" + @if test -z "$(BUILD_NUMBER)"; then \ + echo "BUILD_NUMBER must be defined"; \ + false; \ + fi + @if test ! -d $(RELEASE_INCLUDE_DIR); then \ + rm -rf $(RELEASE_INCLUDE_DIR); \ + $(NSINSTALL) -D $(RELEASE_INCLUDE_DIR);\ + fi + cp $(srcdir)/$(MDCPUCFG_H) $(RELEASE_INCLUDE_DIR)/prcpucfg.h diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix.h new file mode 100644 index 00000000..855cb247 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix.h @@ -0,0 +1,254 @@ +/* -*- 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_aix_defs_h___ +#define nspr_aix_defs_h___ + +#include +#if defined(_PR_PTHREADS) || defined(PTHREADS_USER) +#include +#endif + +/* + * To pick up fd_set and the poll events. + */ +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "aix" +#define _PR_SI_SYSNAME "AIX" +#define _PR_SI_ARCHITECTURE "rs6000" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MINIMUM_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define NEED_TIME_R +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#endif +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +/* Timer operations */ +#if defined(AIX_TIMERS) +extern PRIntervalTime _MD_AixGetInterval(void); +#define _MD_GET_INTERVAL _MD_AixGetInterval + +extern PRIntervalTime _MD_AixIntervalPerSec(void); +#define _MD_INTERVAL_PER_SEC _MD_AixIntervalPerSec + +#else /* defined(AIX_TIMERS) */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#endif /* defined(AIX_TIMERS) */ + +#ifdef AIX_HAVE_ATOMIC_OP_H +/* The atomic operations */ +#include +#define _PR_HAVE_ATOMIC_OPS +#ifndef IS_64 +#define _PR_HAVE_ATOMIC_CAS +#endif +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(val) ((PRInt32)fetch_and_add((atomic_p)val, 1) + 1) +#define _MD_ATOMIC_ADD(ptr, val) ((PRInt32)fetch_and_add((atomic_p)ptr, val) + val) +#define _MD_ATOMIC_DECREMENT(val) ((PRInt32)fetch_and_add((atomic_p)val, -1) - 1) +#define _MD_ATOMIC_SET(val, newval) _AIX_AtomicSet(val, newval) +#endif /* AIX_HAVE_ATOMIC_OP_H */ + +#define USE_SETJMP + +#include + +#define _MD_GET_SP(_t) (_t)->md.jb[3] +#define _MD_SET_THR_SP(_t, _sp) ((_t)->md.jb[3] = (int) (_sp - 2 * 64)) +#define PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.jb) +#define SAVE_CONTEXT(_th) _setjmp(CONTEXT(_th)) +#define GOTO_CONTEXT(_th) _longjmp(CONTEXT(_th), 1) + +#ifdef PTHREADS_USER +#include "_nspr_pthread.h" +#else + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (int) (_sp - 2 * 64); \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#if !defined(_PR_PTHREADS) +#define _MD_INIT_LOCKS() +#endif + +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) +#endif /* PTHREADS_USER */ + +#ifdef AIX_RENAME_SELECT +#define _MD_SELECT select +#define _MD_POLL poll +#endif + +extern void _MD_aix_map_sendfile_error(int err); + +#endif /* nspr_aix_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix32.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix32.cfg new file mode 100644 index 00000000..1949862a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix32.cfg @@ -0,0 +1,145 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef AIX +#define AIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#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 + +/* used by protypes.h only */ +#define _PR_AIX_HAVE_BSD_INT_TYPES + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix64.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix64.cfg new file mode 100644 index 00000000..e2c9dc42 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_aix64.cfg @@ -0,0 +1,146 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef AIX +#define AIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 8 + +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#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 + +/* used by protypes.h only */ +#define _PR_AIX_HAVE_BSD_INT_TYPES + +#endif /* NO_NSPR_10_SUPPORT */ + +#endif /* nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.cfg new file mode 100644 index 00000000..d15cf044 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.cfg @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_BEOS +#define XP_BEOS +#undef XP_UNIX +#endif + +#ifndef BEOS +#define BEOS +#endif + +#define PR_AF_INET6 5 /* same as AF_INET6 */ + +#ifdef __powerpc__ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#else +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define HAVE_LONG_LONG +/* + * XXX These two macros need to be investigated for different architectures. + */ +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.h new file mode 100644 index 00000000..40fa86d7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_beos.h @@ -0,0 +1,612 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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_beos_defs_h___ +#define nspr_beos_defs_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prthread.h" +#include "prproces.h" +#include "prmem.h" +#include "obsolete/prsem.h" +#include + +#include +#include +#include + +/* + * Internal configuration macros + */ + +#ifdef BONE_VERSION +#define _PR_HAVE_SOCKADDR_LEN +#endif + +#define PR_LINKER_ARCH "beos" +#define _PR_SI_SYSNAME "BEOS" +#ifdef __powerpc__ +#define _PR_SI_ARCHITECTURE "ppc" +#else +#define _PR_SI_ARCHITECTURE "x86" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define _PR_NO_CLOCK_TIMER + +/* + * The Atomic operations + */ + +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC _MD_AtomicInit +#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement +#define _MD_ATOMIC_ADD _MD_AtomicAdd +#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement +#define _MD_ATOMIC_SET _MD_AtomicSet + +#define HAVE_CVAR_BUILT_ON_SEM +#define _PR_GLOBAL_THREADS_ONLY +#define _PR_BTHREADS +#define _PR_NEED_FAKE_POLL +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (16 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) 1 +#define _PR_CONNECT_DOES_NOT_BIND + +/* Define threading functions and objects as native BeOS */ +struct _MDThread { + thread_id tid; /* BeOS thread handle */ + sem_id joinSem; /* sems used to synchronzie joining */ + PRBool is_joining; /* TRUE if someone is currently waiting to + join this thread */ +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +/* + * Lock and Semaphore related definitions + */ + +struct _MDLock { + sem_id semaphoreID; + int32 benaphoreCount; +}; + +struct _MDCVar { + sem_id sem1; + sem_id sem2; + int16 count; +}; + +struct _MDSemaphore { + sem_id sid; +}; + +/* +** CPU-related definitions +*/ +struct _MDCPU { + int8 unused; +}; + +/* +** Process-related definitions +*/ +struct _MDProcess { + pid_t pid; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* +** File- and directory-related definitions +*/ + +#ifndef BONE_VERSION +#define BE_SOCK_SHUTDOWN_READ 0x01 +#define BE_SOCK_SHUTDOWN_WRITE 0x02 +#endif + +struct _MDFileDesc { + PRInt32 osfd; + PRInt32 sock_state; + PRBool accepted_socket; + PRNetAddr peer_addr; +#ifndef BONE_VERSION + PRBool connectValueValid; + int connectReturnValue; + int connectReturnError; +#endif +}; + +struct _MDDir { + DIR *d; +}; + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" + +#define GETTIMEOFDAY(tp) gettimeofday((tp), NULL) + +/* --- Memory-mapped files stuff --- not implemented on BeOS */ + +struct _MDFileMap { + PRInt8 unused; +}; + +/* + * Network related definitions. + */ + +#ifndef BONE_VERSION +#define IPPROTO_IP 0 +#define AF_UNIX 2 +#define TCP_NODELAY SO_NONBLOCK +#define SO_LINGER -1 +#define SO_ERROR 4 +#endif + +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 + +#ifndef BONE_VERSION +/* these aren't actually used. if they are, we're screwed */ +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +struct protoent* getprotobyname(const char* name); +struct protoent* getprotobynumber(int number); +#endif + +/* + * malloc() related definitions. + */ + +#undef _PR_OVERRIDE_MALLOC + +/* Miscellaneous */ + +#define _MD_ERRNO() (errno) + +#define _MD_CLEANUP_BEFORE_EXIT _MD_cleanup_before_exit +#define _MD_EXIT _MD_exit + +#define _MD_GET_ENV getenv +#define _MD_PUT_ENV putenv + +#define _MD_EARLY_INIT _MD_early_init +#define _MD_FINAL_INIT _MD_final_init + +/* CPU Stuff */ + +#define _MD_INIT_CPUS _MD_init_cpus +#define _MD_WAKEUP_CPUS _MD_wakeup_cpus +#define _MD_START_INTERRUPTS _MD_start_interrupts +#define _MD_STOP_INTERRUPTS _MD_stop_interrupts +#define _MD_DISABLE_CLOCK_INTERRUPTS _MD_disable_clock_interrupts +#define _MD_BLOCK_CLOCK_INTERRUPTS _MD_block_clock_interrupts +#define _MD_UNBLOCK_CLOCK_INTERRUPTS _MD_unblock_clock_interrupts +#define _MD_CLOCK_INTERRUPT _MD_clock_interrupt +#define _MD_INIT_STACK _MD_init_stack +#define _MD_CLEAR_STACK _MD_clear_stack +// #define _MD_GET_INTSOFF _MD_get_intsoff +// #define _MD_SET_INTSOFF _MD_set_intsoff +#define _MD_CURRENT_CPU _MD_current_cpu +#define _MD_SET_CURRENT_CPU _MD_set_current_cpu +#define _MD_INIT_RUNNING_CPU _MD_init_running_cpu +#define _MD_PAUSE_CPU _MD_pause_cpu + +/* Thread stuff */ + +#define _MD_CURRENT_THREAD() PR_GetCurrentThread() +// #define _MD_GET_ATTACHED_THREAD _MD_get_attached_thread +#define _MD_LAST_THREAD _MD_last_thread +#define _MD_SET_CURRENT_THREAD _MD_set_current_THREAD +#define _MD_SET_LAST_THREAD _MD_set_last_thread +#define _MD_INIT_THREAD _MD_init_thread +#define _MD_EXIT_THREAD _MD_exit_thread +#define _MD_INIT_ATTACHED_THREAD _MD_init_attached_thread + +#define _MD_SUSPEND_THREAD _MD_suspend_thread +#define _MD_RESUME_THREAD _MD_resume_thread +#define _MD_SUSPEND_CPU _MD_suspend_cpu +#define _MD_RESUME_CPU _MD_resume_cpu +#define _MD_BEGIN_SUSPEND_ALL _MD_begin_suspend_all +#define _MD_END_SUSPEND_ALL _MD_end_suspend_all +#define _MD_BEGIN_RESUME_ALL _MD_begin_resume_all +#define _MD_END_RESUME_ALL _MD_end_resume_all + +#define _MD_GET_SP _MD_get_sp + +#define _MD_CLEAN_THREAD _MD_clean_thread +#define _MD_CREATE_PRIMORDIAL_USER_THREAD _MD_create_primordial_user_thread +#define _MD_CREATE_USER_THREAD _MD_create_user_thread +#define _MD_INIT_PRIMORDIAL_THREAD _MD_init_primordial_thread +#define _MD_CREATE_THREAD _MD_create_thread +#define _MD_YIELD _MD_yield +#define _MD_SET_PRIORITY _MD_set_priority + +#define _MD_SUSPENDALL _MD_suspendall +#define _MD_RESUMEALL _MD_resumeall + +#define _MD_SWITCH_CONTEXT _MD_switch_context +#define _MD_RESTORE_CONTEXT _MD_restore_context + +#define _MD_WAIT _MD_wait +#define _MD_WAKEUP_WAITER _MD_wakeup_waiter + +#define _MD_SETTHREADAFFINITYMASK _MD_setthreadaffinitymask +#define _MD_GETTHREADAFFINITYMASK _MD_getthreadaffinitymask + +/* Thread Synchronization */ + +#define _MD_INIT_LOCKS _MD_init_locks +#define _MD_NEW_LOCK _MD_new_lock +#define _MD_FREE_LOCK _MD_free_lock +#define _MD_LOCK _MD_lock +#define _MD_TEST_AND_LOCK _MD_test_and_lock +#define _MD_UNLOCK _MD_unlock +#define _MD_IOQ_LOCK _MD_ioq_lock +#define _MD_IOQ_UNLOCK _MD_ioq_unlock +#define _MD_NEW_SEM _MD_new_sem +#define _MD_DESTROY_SEM _MD_destroy_sem +#define _MD_TIMED_WAIT_SEM _MD_timed_wait_sem +#define _MD_WAIT_SEM _MD_wait_sem +#define _MD_POST_SEM _MD_post_sem +// #define _MD_NEW_CV _MD_new_cv +// #define _MD_FREE_CV _MD_free_cv +// #define _MD_WAIT_CV _MD_wait_cv +// #define _MD_NOTIFY_CV _MD_notify_cv +// #define _MD_NOTIFYALL_CV _MD_notifyall_cv + +/* File I/O */ + +/* don't need any I/O initializations */ +#define _MD_INIT_IO() +#define _MD_INIT_FILEDESC(fd) + +#define _MD_OPEN_DIR _MD_open_dir +#define _MD_READ_DIR _MD_read_dir +#define _MD_CLOSE_DIR _MD_close_dir +#define _MD_MAKE_NONBLOCK _MD_make_nonblock +#define _MD_SET_FD_INHERITABLE _MD_set_fd_inheritable +#define _MD_INIT_FD_INHERITABLE _MD_init_fd_inheritable +#define _MD_QUERY_FD_INHERITABLE _MD_query_fd_inheritable +#define _MD_OPEN _MD_open +#define _MD_OPEN_FILE _MD_open +#define _MD_CLOSE_FILE _MD_close_file +#define _MD_READ _MD_read +#define _MD_WRITE _MD_write +#define _MD_WRITEV _MD_writev +#define _MD_LSEEK _MD_lseek +#define _MD_LSEEK64 _MD_lseek64 +#define _MD_FSYNC _MD_fsync +#define _MD_DELETE _MD_delete +#define _MD_GETFILEINFO _MD_getfileinfo +#define _MD_GETFILEINFO64 _MD_getfileinfo64 +#define _MD_GETOPENFILEINFO _MD_getopenfileinfo +#define _MD_GETOPENFILEINFO64 _MD_getopenfileinfo64 +#define _MD_RENAME _MD_rename +#define _MD_ACCESS _MD_access +#define _MD_STAT stat +#define _MD_MKDIR _MD_mkdir +#define _MD_MAKE_DIR _MD_mkdir +#define _MD_RMDIR _MD_rmdir +#define _MD_PR_POLL _MD_pr_poll + +/* Network I/O */ + +#define _MD_CLOSE_SOCKET _MD_close_socket +#define _MD_CONNECT _MD_connect +#define _MD_ACCEPT _MD_accept +#define _MD_BIND _MD_bind +#define _MD_LISTEN _MD_listen +#define _MD_SHUTDOWN _MD_shutdown +#define _MD_RECV _MD_recv +#define _MD_SEND _MD_send +#define _MD_ACCEPT_READ _MD_accept_read +#define _MD_GETSOCKNAME _MD_getsockname +#define _MD_GETPEERNAME _MD_getpeername +#define _MD_GETSOCKOPT _MD_getsockopt +#define _MD_SETSOCKOPT _MD_setsockopt +#define _MD_RECVFROM _MD_recvfrom +#define _MD_SENDTO _MD_sendto +#define _MD_SOCKETPAIR _MD_socketpair +#define _MD_SOCKET _MD_socket +#define _MD_SOCKETAVAILABLE _MD_socketavailable +#define _MD_PIPEAVAILABLE _MD_socketavailable + +#define _MD_GET_SOCKET_ERROR() (errno) +#define _MD_GETHOSTNAME _MD_gethostname + +#define _MD_SELECT select + +/* Process management */ + +#define _MD_CREATE_PROCESS _MD_create_process +#define _MD_DETACH_PROCESS _MD_detach_process +#define _MD_WAIT_PROCESS _MD_wait_process +#define _MD_KILL_PROCESS _MD_kill_process + +/* Atomic data operations */ + +// #define _MD_INIT_ATOMIC _MD_init_atomic +// #define _MD_ATOMIC_INCREMENT _MD_atomic_increment +// #define _MD_ATOMIC_DECREMENT _MD_atomic_decrement +// #define _MD_ATOMIC_SET _MD_atomic_set + +/* memory management */ + +#define _MD_INIT_SEGS _MD_init_segs +#define _MD_ALLOC_SEGMENT _MD_alloc_segment +#define _MD_FREE_SEGMENT _MD_free_segment + +/* Memory mapped file I/O */ + +#define _MD_CREATE_FILE_MAP _MD_create_file_map +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_get_mem_map_alignment +#define _MD_MEM_MAP _MD_mem_map +#define _MD_MEM_UNMAP _MD_mem_unmap +#define _MD_CLOSE_FILE_MAP _MD_close_file_map + +/* Time related */ + +#define _MD_NOW _MD_now +#define _MD_INTERVAL_INIT _MD_interval_init +#define _MD_GET_INTERVAL _MD_get_interval +#define _MD_INTERVAL_PER_SEC _MD_interval_per_sec + +/* File locking */ + +#define _MD_LOCKFILE _MD_lockfile +#define _MD_TLOCKFILE _MD_tlockfile +#define _MD_UNLOCKFILE _MD_unlockfile + +/** + * Prototypes for machine dependent function implementations. (Too bad + * NSPR's MD system blows so much that we have to reiterate every stinking + * thing we implement here in our MD header file.) + */ + +/* Miscellaneous */ + +NSPR_API(void) _MD_cleanup_before_exit(void); +NSPR_API(void) _MD_exit(PRIntn status); + +NSPR_API(char*) _MD_get_env(const char *name); +NSPR_API(PRIntn) _MD_put_env(const char *name); + +NSPR_API(void) _MD_early_init(void); +NSPR_API(void) _MD_final_init(void); + +/* CPU Stuff */ + +NSPR_API(void) _MD_init_cpus(); +NSPR_API(void) _MD_wakeup_cpus(); +NSPR_API(void) _MD_start_interrupts(void); +NSPR_API(void) _MD_stop_interrupts(void); +NSPR_API(void) _MD_disable_clock_interrupts(void); +NSPR_API(void) _MD_block_clock_interrupts(void); +NSPR_API(void) _MD_unblock_clock_interrupts(void); +NSPR_API(void) _MD_clock_interrupt(void); +// NSPR_API(void) _MD_init_stack(PRThreadStack *ts, PRIntn redzone); +// NSPR_API(void) _MD_clear_stack(PRThreadStack* ts); +// NSPR_API(PRInt32) _MD_get_intsoff(void); +// NSPR_API(void) _MD_set_intsoff(PRInt32 _val); +// NSPR_API(_PRCPU*) _MD_current_cpu(void); +// NSPR_API(void) _MD_set_current_cpu(_PRCPU *cpu); +// NSPR_API(void) _MD_init_running_cpu(_PRCPU *cpu); +NSPR_API(PRInt32) _MD_pause_cpu(PRIntervalTime timeout); + +/* Thread stuff */ + +// NSPR_API(PRThread*) _MD_current_thread(void); +NSPR_API(PRThread*) _MD_get_attached_thread(void); +NSPR_API(PRThread*) _MD_last_thread(void); +NSPR_API(void) _MD_set_current_thread(PRThread *thread); +NSPR_API(void) _MD_set_last_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_init_thread(PRThread *thread); +NSPR_API(void) _MD_exit_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_init_attached_thread(PRThread *thread); + +NSPR_API(void) _MD_suspend_thread(PRThread *thread); +NSPR_API(void) _MD_resume_thread(PRThread *thread); +// NSPR_API(void) _MD_suspend_cpu(_PRCPU *cpu); +// NSPR_API(void) _MD_resume_cpu(_PRCPU *cpu); +NSPR_API(void) _MD_begin_suspend_all(void); +NSPR_API(void) _MD_end_suspend_all(void); +NSPR_API(void) _MD_begin_resume_all(void); +NSPR_API(void) _MD_end_resume_all(void); + +NSPR_API(void *) _MD_get_sp(PRThread *thread); + +NSPR_API(void) _MD_clean_thread(PRThread *thread); +NSPR_API(void) _MD_create_primordial_user_thread(PRThread *); +NSPR_API(PRThread*) _MD_create_user_thread(PRUint32 stacksize, void (*start)(void *), void *arg); +NSPR_API(void) _MD_init_primordial_thread(PRThread *thread); +NSPR_API(PRStatus) _MD_create_thread(PRThread *thread, void (*start)(void *), PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize); +NSPR_API(void) _MD_yield(void); +NSPR_API(void) _MD_set_priority(struct _MDThread *md, PRThreadPriority newPri); + +NSPR_API(void) _MD_suspendall(void); +NSPR_API(void) _MD_resumeall(void); + +NSPR_API(void) _MD_init_context(PRThread *thread, char *top, void (*start) (void), PRBool *status); +NSPR_API(void) _MD_switch_context(PRThread *thread); +NSPR_API(void) _MD_restore_context(PRThread *thread); + +NSPR_API(PRStatus) _MD_wait(PRThread *, PRIntervalTime timeout); +NSPR_API(PRStatus) _MD_wakeup_waiter(PRThread *); + +NSPR_API(PRInt32) _MD_setthreadaffinitymask(PRThread *thread, PRUint32 mask ); +NSPR_API(PRInt32) _MD_getthreadaffinitymask(PRThread *thread, PRUint32 *mask); + +/* Thread Synchronization */ + +NSPR_API(void) _MD_init_locks(void); +NSPR_API(PRStatus) _MD_new_lock(struct _MDLock *md); +NSPR_API(void) _MD_free_lock(struct _MDLock *md); +NSPR_API(void) _MD_lock(struct _MDLock *md); +NSPR_API(PRIntn) _MD_test_and_lock(struct _MDLock *md); +NSPR_API(void) _MD_unlock(struct _MDLock *md); +NSPR_API(void) _MD_ioq_lock(void); +NSPR_API(void) _MD_ioq_unlock(void); +NSPR_API(void) _MD_new_sem(struct _MDSemaphore *md, PRUintn value); +NSPR_API(void) _MD_destroy_sem(struct _MDSemaphore *md); +NSPR_API(PRStatus) _MD_timed_wait_sem(struct _MDSemaphore *md, PRIntervalTime timeout); +NSPR_API(PRStatus) _MD_wait_sem(struct _MDSemaphore *md); +NSPR_API(void) _MD_post_sem(struct _MDSemaphore *md); +// NSPR_API(PRInt32) _MD_new_cv(struct _MDCVar *md); +// NSPR_API(void) _MD_free_cv(struct _MDCVar *md); +// NSPR_API(void) _MD_wait_cv(struct _MDCVar *mdCVar, struct _MDLock *mdLock, PRIntervalTime timeout); +// NSPR_API(void) _MD_notify_cv(struct _MDCVar *md, struct _MDLock *lock); +// NSPR_API(void) _MD_notifyall_cv(struct _MDCVar *md, struct _MDLock *lock); + +/* File I/O */ + +// NSPR_API(void) _MD_init_io(void); +NSPR_API(PRStatus) _MD_open_dir(struct _MDDir *md,const char *name); +NSPR_API(char *) _MD_read_dir(struct _MDDir *md, PRIntn flags); +NSPR_API(PRInt32) _MD_close_dir(struct _MDDir *md); +NSPR_API(void) _MD_make_nonblock(PRFileDesc *fd); +NSPR_API(void) _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported); +NSPR_API(void) _MD_query_fd_inheritable(PRFileDesc *fd); +NSPR_API(PRInt32) _MD_open(const char *name, PRIntn osflags, PRIntn mode); +NSPR_API(PRInt32) _MD_close_file(PRInt32 osfd); +NSPR_API(PRInt32) _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount); +NSPR_API(PRInt32) _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount); +NSPR_API(PRInt32) _MD_writev(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_lseek(PRFileDesc *fd, PRInt32 offset, int whence); +NSPR_API(PRInt64) _MD_lseek64(PRFileDesc *fd, PRInt64 offset, int whence); +NSPR_API(PRInt32) _MD_fsync(PRFileDesc *fd); +NSPR_API(PRInt32) _MD_delete(const char *name); +NSPR_API(PRInt32) _MD_getfileinfo(const char *fn, PRFileInfo *info); +NSPR_API(PRInt32) _MD_getfileinfo64(const char *fn, PRFileInfo64 *info); +NSPR_API(PRInt32) _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRInt32) _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info); +NSPR_API(PRInt32) _MD_rename(const char *from, const char *to); +NSPR_API(PRInt32) _MD_access(const char *name, PRIntn how); +NSPR_API(PRInt32) _MD_stat(const char *name, struct stat *buf); +NSPR_API(PRInt32) _MD_mkdir(const char *name, PRIntn mode); +NSPR_API(PRInt32) _MD_rmdir(const char *name); +NSPR_API(PRInt32) _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); + +/* Network I/O */ +NSPR_API(PRInt32) _MD_close_socket(PRInt32 osfd); +NSPR_API(PRInt32) _MD_connect(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +NSPR_API(PRInt32) _MD_listen(PRFileDesc *fd, PRIntn backlog); +NSPR_API(PRInt32) _MD_shutdown(PRFileDesc *fd, PRIntn how); +NSPR_API(PRInt32) _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); +// NSPR_API(PRInt32) _MD_fast_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg); +// NSPR_API(PRInt32) _MD_fast_accept_read(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg); +// NSPR_API(void) _MD_update_accept_context(PRInt32 s, PRInt32 ls); +NSPR_API(PRStatus) _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +NSPR_API(PRStatus) _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +NSPR_API(PRStatus) _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +NSPR_API(PRStatus) _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen); +NSPR_API(PRInt32) _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +NSPR_API(PRInt32) _MD_socketpair(int af, int type, int flags, PRInt32 *osfd); +NSPR_API(PRInt32) _MD_socket(int af, int type, int flags); +NSPR_API(PRInt32) _MD_socketavailable(PRFileDesc *fd); + +// NSPR_API(PRInt32) _MD_get_socket_error(void); +NSPR_API(PRStatus) _MD_gethostname(char *name, PRUint32 namelen); + +/* Process management */ + +NSPR_API(PRProcess *) _MD_create_process(const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr); +NSPR_API(PRStatus) _MD_detach_process(PRProcess *process); +NSPR_API(PRStatus) _MD_wait_process(PRProcess *process, PRInt32 *exitCode); +NSPR_API(PRStatus) _MD_kill_process(PRProcess *process); + +/* Atomic data operations */ + +// NSPR_API(void) _MD_init_atomic(void); +// NSPR_API(PRInt32) _MD_atomic_increment(PRInt32 *); +// NSPR_API(PRInt32) _MD_atomic_decrement(PRInt32 *); +// NSPR_API(PRInt32) _MD_atomic_set(PRInt32 *, PRInt32); + +/* Memory management */ + +NSPR_API(void) _MD_init_segs(void); +NSPR_API(PRStatus) _MD_alloc_segment(PRSegment *seg, PRUint32 size, void *vaddr); +NSPR_API(void) _MD_free_segment(PRSegment *seg); + +/* Memory mapped file I/O */ + +NSPR_API(PRStatus) _MD_create_file_map(PRFileMap *fmap, PRInt64 size); +NSPR_API(PRInt32) _MD_get_mem_map_alignment(void); +NSPR_API(void *) _MD_mem_map(PRFileMap *fmap, PRInt64 offset, PRUint32 len); +NSPR_API(PRStatus) _MD_mem_unmap(void *addr, PRUint32 size); +NSPR_API(PRStatus) _MD_close_file_map(PRFileMap *fmap); + +/* Time related */ + +NSPR_API(PRTime) _MD_now(void); +NSPR_API(void) _MD_interval_init(void); +NSPR_API(PRIntervalTime) _MD_get_interval(void); +NSPR_API(PRIntervalTime) _MD_interval_per_sec(void); + +/* File locking */ + +NSPR_API(PRStatus) _MD_lockfile(PRInt32 osfd); +NSPR_API(PRStatus) _MD_tlockfile(PRInt32 osfd); +NSPR_API(PRStatus) _MD_unlockfile(PRInt32 osfd); + +#endif /* _nspr_beos_defs_h___*/ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.cfg new file mode 100644 index 00000000..843f35f6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.cfg @@ -0,0 +1,198 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef BSDI +#define BSDI +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.h new file mode 100644 index 00000000..b59c9b0f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_bsdi.h @@ -0,0 +1,214 @@ +/* -*- 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_bsdi_defs_h___ +#define nspr_bsdi_defs_h___ + +/* + * Internal configuration macros + */ + +#include /* for _BSDI_VERSION */ + +#define PR_LINKER_ARCH "bsdi" +#define _PR_SI_SYSNAME "BSDI" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#else +#error "Unknown CPU architecture" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define HAVE_BSD_FLOCK +#define NEED_TIME_R +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_NO_LARGE_FILES + +#define USE_SETJMP + +/* BSD/OS 4.3 and newer all have IPv6 support */ +#if _BSDI_VERSION >= 200105 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif + +#ifndef _PR_PTHREADS + +#include + +#if defined(_PR_BSDI_JMPBUF_IS_ARRAY) +#define _MD_GET_SP(_t) (_t)->md.context[2] +#elif defined(_PR_BSDI_JMPBUF_IS_STRUCT) +#define _MD_GET_SP(_t) (_t)->md.context[0].jb_esp +#else +#error "Unknown BSDI jmp_buf type" +#endif + +#define PR_NUM_GCREGS _JBLEN +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (int) (_sp - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#include +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#endif /* nspr_bsdi_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.cfg new file mode 100644 index 00000000..b2965802 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.cfg @@ -0,0 +1,172 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef DARWIN /*bird*/ +#define DARWIN /*bird*/ +#endif /*bird*/ + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#if defined(i386) || defined(__i386__) || defined(__amd64__) || defined(__arm64__) || defined(__arm__) +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#define HAVE_LONG_LONG +#if defined(__amd64__) +#define HAVE_ALIGNED_DOUBLES +#else +#undef HAVE_ALIGNED_DOUBLES +#endif +#define HAVE_ALIGNED_LONGLONGS 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#if defined(__amd64__) +#define PR_BYTES_PER_LONG 8 +#else +#define PR_BYTES_PER_LONG 4 +#endif +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#if defined(__amd64__) +#define PR_BITS_PER_LONG 64 +#else +#define PR_BITS_PER_LONG 32 +#endif +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#if defined(__amd64__) +#define PR_BITS_PER_LONG_LOG2 6 +#else +#define PR_BITS_PER_LONG_LOG2 5 +#endif +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#if defined(__amd64__) +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 8 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#else +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#endif + +#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___ */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.h new file mode 100644 index 00000000..0640a924 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_darwin.h @@ -0,0 +1,306 @@ +/* -*- 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_darwin_defs_h___ +#define nspr_darwin_defs_h___ + +#include "prthread.h" + +#include + +#ifdef XP_MACOSX +#include +#endif + +#define PR_LINKER_ARCH "darwin" +#define _PR_SI_SYSNAME "DARWIN" +#ifdef __i386__ +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__ppc__) +#define _PR_SI_ARCHITECTURE "ppc" +#elif defined(__amd64__) +#define _PR_SI_ARCHITECTURE "amd64" +#elif defined(__arm__) +#define _PR_SI_ARCHITECTURE "arm" +#elif defined(__arm64__) +#define _PR_SI_ARCHITECTURE "arm64" +#else +#error "unknown architecture." +#endif +#define PR_DLL_SUFFIX ".dylib" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_MACH_DYLD +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_HAVE_LARGE_OFF_T +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 /* Mac OS X 10.6 has poll(). */ +# if 0 /* ... but we don't use it because it performs worse on Mt. Lion - WEIRD! */ +# define _PR_POLL_AVAILABLE 1 +# define _PR_USE_POLL 1 +# endif +#endif + +#define _PR_INET6 +/* + * I'd prefer to use getipnodebyname and getipnodebyaddr but the + * getipnodebyname(3) man page on Mac OS X 10.2 says they are not + * thread-safe. AI_V4MAPPED|AI_ADDRCONFIG doesn't work either. + */ +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +/* + * On Mac OS X 10.2, gethostbyaddr fails with h_errno=NO_RECOVERY + * if you pass an IPv4-mapped IPv6 address to it. + */ +#define _PR_GHBA_DISALLOW_V4MAPPED +#ifdef XP_MACOSX +#if !defined(MAC_OS_X_VERSION_10_3) || \ + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 +/* + * socket(AF_INET6) fails with EPROTONOSUPPORT on Mac OS X 10.1. + * IPv6 under OS X 10.2 and below is not complete (see bug 222031). + */ +#define _PR_INET6_PROBE +#endif /* DT < 10.3 */ +#if defined(MAC_OS_X_VERSION_10_2) && \ + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_2 +/* Mac OS X 10.2 has inet_ntop and inet_pton. */ +#define _PR_HAVE_INET_NTOP +#endif /* DT >= 10.2 */ +#endif /* XP_MACOSX */ +#define _PR_IPV6_V6ONLY_PROBE +/* The IPV6_V6ONLY socket option is not defined on Mac OS X 10.1. */ +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR +# include "_iprt_atomic.h" +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +#if defined(__ppc__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_DarwinPPC_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT(val) _PR_DarwinPPC_AtomicIncrement(val) +extern PRInt32 _PR_DarwinPPC_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT(val) _PR_DarwinPPC_AtomicDecrement(val) +extern PRInt32 _PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET(val, newval) _PR_DarwinPPC_AtomicSet(val, newval) +extern PRInt32 _PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD(ptr, val) _PR_DarwinPPC_AtomicAdd(ptr, val) +#elif defined(__i386__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_Darwin_x86_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT(val) _PR_Darwin_x86_AtomicIncrement(val) +extern PRInt32 _PR_Darwin_x86_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT(val) _PR_Darwin_x86_AtomicDecrement(val) +extern PRInt32 _PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET(val, newval) _PR_Darwin_x86_AtomicSet(val, newval) +extern PRInt32 _PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD(ptr, val) _PR_Darwin_x86_AtomicAdd(ptr, val) +#endif /* __i386__ */ +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + +#define USE_SETJMP + +#if !defined(_PR_PTHREADS) + +#include + +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +/* For writev() */ +#include + +#endif /* nspr_darwin_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.cfg new file mode 100644 index 00000000..ed6b93f8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.cfg @@ -0,0 +1,138 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef DGUX +#define DGUX +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.h new file mode 100644 index 00000000..f3f02e82 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_dgux.h @@ -0,0 +1,221 @@ +/* -*- 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_dgux_defs_h___ +#define nspr_dgux_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "dgux" +#define _PR_SI_SYSNAME "DGUX" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +#include +#include +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_dgux_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.cfg new file mode 100644 index 00000000..76d35420 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.cfg @@ -0,0 +1,337 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef FREEBSD +#define FREEBSD +#endif + +#define PR_AF_INET6 28 /* same as AF_INET6 */ + +#ifndef HAVE_LONG_LONG +#define HAVE_LONG_LONG +#endif + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#else + +#error "Unknown CPU architecture" + +#endif + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.h new file mode 100644 index 00000000..7ec7c894 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_freebsd.h @@ -0,0 +1,290 @@ +/* -*- 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_freebsd_defs_h___ +#define nspr_freebsd_defs_h___ + +#include "prthread.h" + +#if __FreeBSD__ >= 2 +#include /* for __FreeBSD_version */ +#endif +#include + +#define PR_LINKER_ARCH "freebsd" +#define _PR_SI_SYSNAME "FREEBSD" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__alpha__) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__ia64__) +#define _PR_SI_ARCHITECTURE "ia64" +#elif defined(__amd64__) +#define _PR_SI_ARCHITECTURE "amd64" +#else +#error "Unknown CPU architecture" +#endif +#if defined(__ELF__) +#define PR_DLL_SUFFIX ".so" +#else +#define PR_DLL_SUFFIX ".so.1.0" +#endif + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_NO_LARGE_FILES + +#if defined(_PR_PTHREADS) +#if __FreeBSD_version >= 400008 +/* + * libc_r before this version of FreeBSD doesn't have poll(). + * Although libc has poll(), it is not thread-safe so we can't + * use it in the pthreads version. + */ +#define _PR_POLL_AVAILABLE +#endif +#else +#if __FreeBSD_version >= 300000 +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#endif +#endif + +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#if __FreeBSD_version >= 400014 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#define _PR_IPV6_V6ONLY_PROBE +#endif + +/* VBOX - START (expect somthing similar to arrive in the mozilla tree) */ +#if (__FreeBSD_version >= 700016) || (__FreeBSD_version < 700000 && __FreeBSD_version >= 601103) +#if defined(_PR_PTHREADS) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_5_ARG_GETPROTO_R +#define _PR_HAVE_GETHOST_R +#define _PR_HAVE_GETHOST_R_INT +#define _PR_HAVE_THREADSAFE_GETHOST +#endif +#endif +/* VBOX - END */ + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#define _MD_GET_SP(_th) (_th)->md.context[0]._sjb[2] +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#endif /* ! _PR_PTHREADS */ + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +#if defined(_PR_POLL_AVAILABLE) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) +#endif + +/* freebsd has INADDR_LOOPBACK defined, but in /usr/include/rpc/types.h, and I didn't + want to be including that.. */ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK (u_long)0x7F000001 +#endif + +/* For writev() */ +#include + +#endif /* nspr_freebsd_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux.h new file mode 100644 index 00000000..73928313 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux.h @@ -0,0 +1,257 @@ +/* -*- 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_xhppa_defs_h___ +#define nspr_xhppa_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "hpux" +#define _PR_SI_SYSNAME "HPUX" +#define _PR_SI_ARCHITECTURE "hppa1.1" +#define PR_DLL_SUFFIX ".sl" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +/* + * _USE_BIG_FDS increases the size of fd_set from 256 bytes to + * about 7500 bytes. PR_Poll allocates three fd_sets on the + * stack, so it is safer to also increase the default thread + * stack size. + */ +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MINIMUM_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define NEED_TIME_R + +#define HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#ifdef IS_64 +#define USE_DLFCN +#else +#define USE_HPSHL +#endif +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +#undef _PR_HAVE_ATOMIC_OPS + +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif + +#if !defined(_PR_PTHREADS) + +#include +#include + +#define USE_SETJMP + +#define _MD_GET_SP(_t) (*((int *)((_t)->md.jb) + 1)) +#define PR_NUM_GCREGS _JBLEN +/* Caveat: This makes jmp_buf full of doubles. */ +#define CONTEXT(_th) ((_th)->md.jb) + + /* Stack needs two frames (64 bytes) at the bottom */ \ +#define _MD_SET_THR_SP(_t, _sp) ((_MD_GET_SP(_t)) = (int) (_sp + 64 *2)) +#define SAVE_CONTEXT(_th) _setjmp(CONTEXT(_th)) +#define GOTO_CONTEXT(_th) _longjmp(CONTEXT(_th), 1) + +#if !defined(PTHREADS_USER) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *(status) = PR_TRUE; \ + if (_setjmp(CONTEXT(_thread))) (*_main)(); \ + /* Stack needs two frames (64 bytes) at the bottom */ \ + (_MD_GET_SP(_thread)) = (int) ((_sp) + 64*2); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. HP-UX has no native threads. */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +#else /* PTHREADS_USER */ + +#include "_nspr_pthread.h" + +#endif /* PTHREADS_USER */ + +#endif /* !defined(_PR_PTHREADS) */ + +#if !defined(PTHREADS_USER) +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#endif + +#if defined(HPUX_LW_TIMER) +extern void _PR_HPUX_LW_IntervalInit(void); +extern PRIntervalTime _PR_HPUX_LW_GetInterval(void); +#define _MD_INTERVAL_INIT _PR_HPUX_LW_IntervalInit +#define _MD_GET_INTERVAL _PR_HPUX_LW_GetInterval +#define _MD_INTERVAL_PER_SEC() 1000 +#else +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#endif + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#ifdef HPUX11 +extern void _MD_hpux_map_sendfile_error(int err); +#endif /* HPUX11 */ + +#endif /* nspr_xhppa_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux32.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux32.cfg new file mode 100644 index 00000000..1213802d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux32.cfg @@ -0,0 +1,142 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef HPUX +#define HPUX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_AF_INET6 22 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux64.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux64.cfg new file mode 100644 index 00000000..17574ade --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_hpux64.cfg @@ -0,0 +1,143 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef HPUX +#define HPUX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_AF_INET6 22 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_iprt_atomic.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_iprt_atomic.h new file mode 100644 index 00000000..c9356ece --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_iprt_atomic.h @@ -0,0 +1,64 @@ +/* $Id: _iprt_atomic.h $ */ +/** @file + * IPRT Atomic Operation, for including into a system config header. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef VBOX_INCLUDED_SRC_md__iprt_atomic_h +#define VBOX_INCLUDED_SRC_md__iprt_atomic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Note! Do not copy this around, put it in a header of its own if reused anywhere! */ +#include +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() do {} while (0) + +DECLINLINE(PRInt32) _PR_IPRT_AtomicIncrement(PRInt32 *pVal) +{ + return ASMAtomicIncS32(pVal); +} +#define _MD_ATOMIC_INCREMENT(pVal) _PR_IPRT_AtomicIncrement(pVal) + +DECLINLINE(PRInt32) _PR_IPRT_AtomicDecrement(PRInt32 *pVal) +{ + return ASMAtomicDecS32(pVal); +} +#define _MD_ATOMIC_DECREMENT(pVal) _PR_IPRT_AtomicDecrement(pVal) + +DECLINLINE(PRInt32) _PR_IPRT_AtomicSet(PRInt32 *pVal, PRInt32 NewVal) +{ + return ASMAtomicXchgS32(pVal, NewVal); +} +#define _MD_ATOMIC_SET(pVal, NewVal) _PR_IPRT_AtomicSet(pVal, NewVal) + +DECLINLINE(PRInt32) _PR_IPRT_AtomicAdd(PRInt32 *pVal, PRInt32 ToAdd) +{ + return ASMAtomicAddS32(pVal, ToAdd) + ToAdd; +} +#define _MD_ATOMIC_ADD(pVal, ToAdd) _PR_IPRT_AtomicAdd(pVal, ToAdd) + +#endif /* !VBOX_INCLUDED_SRC_md__iprt_atomic_h */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix.h new file mode 100644 index 00000000..c38bb4bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix.h @@ -0,0 +1,470 @@ +/* -*- 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_irix_defs_h___ +#define nspr_irix_defs_h___ + +#define _PR_HAVE_ATOMIC_CAS + +/* + * MipsPro assembler defines _LANGUAGE_ASSEMBLY + */ +#ifndef _LANGUAGE_ASSEMBLY + +#include "prclist.h" +#include "prthread.h" +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "irix" +#define _PR_SI_SYSNAME "IRIX" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _PR_NUM_GCREGS 9 +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MIN_STACK_SIZE 16384L + +#undef HAVE_STACK_GROWING_UP +#define HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_ATOMIC_OPS +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM +#define _PR_HAVE_OFF64_T +#define HAVE_POINTER_LOCALTIME_R +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_ACCEPT_INHERIT_NONBLOCK + +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#endif + +/* Initialization entry points */ +NSPR_API(void) _MD_EarlyInit(void); +#define _MD_EARLY_INIT _MD_EarlyInit + +NSPR_API(void) _MD_IrixInit(void); +#define _MD_FINAL_INIT _MD_IrixInit + +#define _MD_INIT_IO() + +/* Timer operations */ +NSPR_API(PRIntervalTime) _MD_IrixGetInterval(void); +#define _MD_GET_INTERVAL _MD_IrixGetInterval + +NSPR_API(PRIntervalTime) _MD_IrixIntervalPerSec(void); +#define _MD_INTERVAL_PER_SEC _MD_IrixIntervalPerSec + +/* GC operations */ +NSPR_API(void *) _MD_GetSP(PRThread *thread); +#define _MD_GET_SP _MD_GetSP + +/* The atomic operations */ +#include +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(val) add_then_test((unsigned long*)val, 1) +#define _MD_ATOMIC_ADD(ptr, val) add_then_test((unsigned long*)ptr, (unsigned long)val) +#define _MD_ATOMIC_DECREMENT(val) add_then_test((unsigned long*)val, 0xffffffff) +#define _MD_ATOMIC_SET(val, newval) test_and_set((unsigned long*)val, newval) + +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + +/************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Data region private to each sproc. This region is setup by calling + * mmap(...,MAP_LOCAL,...). The private data is mapped at the same + * address in every sproc, but every sproc gets a private mapping. + * + * Just make sure that this structure fits in a page, as only one page + * is allocated for the private region. + */ +struct sproc_private_data { + struct PRThread *me; + struct _PRCPU *cpu; + struct PRThread *last; + PRUintn intsOff; + int sproc_pid; +}; + +extern char *_nspr_sproc_private; + +#define _PR_PRDA() ((struct sproc_private_data *) _nspr_sproc_private) +#define _MD_SET_CURRENT_THREAD(_thread) _PR_PRDA()->me = (_thread) +#define _MD_THIS_THREAD() (_PR_PRDA()->me) +#define _MD_LAST_THREAD() (_PR_PRDA()->last) +#define _MD_SET_LAST_THREAD(_thread) _PR_PRDA()->last = (_thread) +#define _MD_CURRENT_CPU() (_PR_PRDA()->cpu) +#define _MD_SET_CURRENT_CPU(_cpu) _PR_PRDA()->cpu = (_cpu) +#define _MD_SET_INTSOFF(_val) (_PR_PRDA()->intsOff = _val) +#define _MD_GET_INTSOFF() (_PR_PRDA()->intsOff) + +#define _MD_SET_SPROC_PID(_val) (_PR_PRDA()->sproc_pid = _val) +#define _MD_GET_SPROC_PID() (_PR_PRDA()->sproc_pid) + +NSPR_API(struct PRThread*) _MD_get_attached_thread(void); +NSPR_API(struct PRThread*) _MD_get_current_thread(void); +#define _MD_GET_ATTACHED_THREAD() _MD_get_attached_thread() +#define _MD_CURRENT_THREAD() _MD_get_current_thread() + +#define _MD_CHECK_FOR_EXIT() { \ + if (_pr_irix_exit_now) { \ + _PR_POST_SEM(_pr_irix_exit_sem); \ + _MD_Wakeup_CPUs(); \ + _exit(0); \ + } \ + } + +#define _MD_ATTACH_THREAD(threadp) + +#define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode; + +extern struct _PRCPU *_pr_primordialCPU; +extern usema_t *_pr_irix_exit_sem; +extern PRInt32 _pr_irix_exit_now; +extern int _pr_irix_primoridal_cpu_fd[]; +extern PRInt32 _pr_irix_process_exit; +extern PRInt32 _pr_irix_process_exit_code; + +/* Thread operations */ +#define _PR_LOCK_HEAP() { \ + PRIntn _is; \ + if (_pr_primordialCPU) { \ + if (_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _MD_GET_ATTACHED_THREAD())) \ + _PR_INTSOFF(_is); \ + _PR_LOCK(_pr_heapLock); \ + } + +#define _PR_UNLOCK_HEAP() if (_pr_primordialCPU) { \ + _PR_UNLOCK(_pr_heapLock); \ + if (_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _MD_GET_ATTACHED_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } + +#define _PR_OPEN_POLL_SEM(_sem) usopenpollsema(_sem, 0666) +#define _PR_WAIT_SEM(_sem) uspsema(_sem) +#define _PR_POST_SEM(_sem) usvsema(_sem) + +#define _MD_CVAR_POST_SEM(threadp) usvsema((threadp)->md.cvar_pollsem) + +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +struct _MDLock { + ulock_t lock; + usptr_t *arena; +}; + +/* + * disable pre-emption for the LOCAL threads when calling the arena lock + * routines + */ + +#define _PR_LOCK(lock) { \ + PRIntn _is; \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_INTSOFF(_is); \ + ussetlock(lock); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_FAST_INTSON(_is); \ + } + +#define _PR_UNLOCK(lock) { \ + PRIntn _is; \ + PRThread *me = _MD_GET_ATTACHED_THREAD(); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_INTSOFF(_is); \ + usunsetlock(lock); \ + if (me && !_PR_IS_NATIVE_THREAD(me)) \ + _PR_FAST_INTSON(_is); \ + } + +NSPR_API(PRStatus) _MD_NEW_LOCK(struct _MDLock *md); +NSPR_API(void) _MD_FREE_LOCK(struct _MDLock *lockp); + +#define _MD_LOCK(_lockp) _PR_LOCK((_lockp)->lock) +#define _MD_UNLOCK(_lockp) _PR_UNLOCK((_lockp)->lock) +#define _MD_TEST_AND_LOCK(_lockp) (uscsetlock((_lockp)->lock, 1) == 0) + +extern ulock_t _pr_heapLock; + +struct _MDThread { + jmp_buf jb; + usptr_t *pollsem_arena; + usema_t *cvar_pollsem; + PRInt32 cvar_pollsemfd; + PRInt32 cvar_pollsem_select; /* acquire sem by calling select */ + PRInt32 cvar_wait; /* if 1, thread is waiting on cvar Q */ + PRInt32 id; + PRInt32 suspending_id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDSemaphore { + usema_t *sem; +}; + +struct _MDCVar { + ulock_t mdcvar_lock; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + + +struct _MDCPU { + PRInt32 id; + PRInt32 suspending_id; + struct _MDCPU_Unix md_unix; +}; + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *jb = (_thread)->md.jb; \ + *status = PR_TRUE; \ + (void) setjmp(jb); \ + (_thread)->md.jb[JB_SP] = (int) ((_sp) - 64); \ + (_thread)->md.jb[JB_PC] = (int) _main; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +* +* XXX RUNQ lock needed before clearing _PR_NO_SCHED flag, because the +* thread may be unr RUNQ? +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!setjmp(_thread->md.jb)) { \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + int *jb = (_newThread)->md.jb; \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + _newThread->no_sched = 1; \ + longjmp(jb, 1); \ + PR_END_MACRO + +NSPR_API(PRStatus) _MD_InitThread(struct PRThread *thread, + PRBool wakeup_parent); +NSPR_API(PRStatus) _MD_InitAttachedThread(struct PRThread *thread, + PRBool wakeup_parent); +#define _MD_INIT_THREAD(thread) _MD_InitThread(thread, PR_TRUE) +#define _MD_INIT_ATTACHED_THREAD(thread) \ + _MD_InitAttachedThread(thread, PR_FALSE) + +NSPR_API(void) _MD_ExitThread(struct PRThread *thread); +#define _MD_EXIT_THREAD _MD_ExitThread + +NSPR_API(void) _MD_SuspendThread(struct PRThread *thread); +#define _MD_SUSPEND_THREAD _MD_SuspendThread + +NSPR_API(void) _MD_ResumeThread(struct PRThread *thread); +#define _MD_RESUME_THREAD _MD_ResumeThread + +NSPR_API(void) _MD_SuspendCPU(struct _PRCPU *thread); +#define _MD_SUSPEND_CPU _MD_SuspendCPU + +NSPR_API(void) _MD_ResumeCPU(struct _PRCPU *thread); +#define _MD_RESUME_CPU _MD_ResumeCPU + +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_RESUME_ALL() + +NSPR_API(void) _MD_InitLocks(void); +#define _MD_INIT_LOCKS _MD_InitLocks + +NSPR_API(void) _MD_CleanThread(struct PRThread *thread); +#define _MD_CLEAN_THREAD _MD_CleanThread + +#define _MD_YIELD() sginap(0) + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +NSPR_API(PRStatus) _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +NSPR_API(void) _PR_MD_primordial_cpu(); +NSPR_API(void) _PR_MD_WAKEUP_PRIMORDIAL_CPU(); + +NSPR_API(PRStatus) _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void ) _MD_exit(PRIntn status); +#define _MD_EXIT _MD_exit + +#include "prthread.h" + +NSPR_API(void) _MD_SetPriority(struct _MDThread *thread, + PRThreadPriority newPri); +#define _MD_SET_PRIORITY _MD_SetPriority + +NSPR_API(PRStatus) _MD_CreateThread( + struct PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +NSPR_API(void) _PR_MD_PRE_CLEANUP(PRThread *me); + + +/* The following defines the unwrapped versions of select() and poll(). */ +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + + +#define HAVE_THREAD_AFFINITY 1 + +NSPR_API(PRInt32) _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask); +#define _MD_GETTHREADAFFINITYMASK _MD_GetThreadAffinityMask + +NSPR_API(void) _MD_InitRunningCPU(struct _PRCPU *cpu); +#define _MD_INIT_RUNNING_CPU _MD_InitRunningCPU + +#endif /* defined(_PR_PTHREADS) */ + +#endif /* _LANGUAGE_ASSEMBLY */ + +#endif /* nspr_irix_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix32.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix32.cfg new file mode 100644 index 00000000..db6ca446 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix32.cfg @@ -0,0 +1,149 @@ +/* -*- 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 _SGI_MP_SOURCE +#define _SGI_MP_SOURCE +#endif + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef IRIX +#define IRIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix64.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix64.cfg new file mode 100644 index 00000000..305317ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_irix64.cfg @@ -0,0 +1,148 @@ +/* -*- 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 _SGI_MP_SOURCE +#define _SGI_MP_SOURCE +#endif + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef IRIX +#define IRIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define IS_64 + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.cfg new file mode 100644 index 00000000..f1d89314 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.cfg @@ -0,0 +1,661 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef LINUX +#define LINUX +#endif + +#define PR_AF_INET6 10 /* same as AF_INET6 */ + +#ifdef __powerpc__ + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__alpha) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__ia64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__x86_64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mc68000__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 +#define PR_ALIGN_OF_WORD 2 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__mips__) + +#ifdef __MIPSEB__ +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#elif defined(__MIPSEL__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#else +#error "Unknown MIPS endianness." +#endif + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__arm__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__hppa__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__s390x__) + +#define IS_BIG_ENDIAN 1 +#undef IS_LITTLE_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error "Unknown CPU architecture" + +#endif + +#define HAVE_LONG_LONG +#if PR_ALIGN_OF_DOUBLE == 8 +#define HAVE_ALIGNED_DOUBLES +#endif +#if PR_ALIGN_OF_INT64 == 8 +#define HAVE_ALIGNED_LONGLONGS +#endif + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.h new file mode 100644 index 00000000..f68dfff1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_linux.h @@ -0,0 +1,501 @@ +/* -*- 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_linux_defs_h___ +#define nspr_linux_defs_h___ + +#include "prthread.h" + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "linux" +#define _PR_SI_SYSNAME "LINUX" +#ifdef __powerpc__ +#define _PR_SI_ARCHITECTURE "ppc" +#elif defined(__alpha) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__ia64__) +#define _PR_SI_ARCHITECTURE "ia64" +#elif defined(__x86_64__) +#define _PR_SI_ARCHITECTURE "x86-64" +#elif defined(__mc68000__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__mips__) +#define _PR_SI_ARCHITECTURE "mips" +#elif defined(__arm__) +#define _PR_SI_ARCHITECTURE "arm" +#elif defined(__hppa__) +#define _PR_SI_ARCHITECTURE "hppa" +#elif defined(__s390__) +#define _PR_SI_ARCHITECTURE "s390" +#elif defined(__s390x__) +#define _PR_SI_ARCHITECTURE "s390x" +#else +#error "Unknown CPU architecture" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP + +/* + * Elf linux supports dl* functions + */ +#define HAVE_DLL +#define USE_DLFCN + +#if defined(__i386__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_x86_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_x86_AtomicIncrement +extern PRInt32 _PR_x86_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_x86_AtomicDecrement +extern PRInt32 _PR_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_x86_AtomicAdd +extern PRInt32 _PR_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_x86_AtomicSet +#endif + +#if defined(__ia64__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_ia64_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_ia64_AtomicIncrement +extern PRInt32 _PR_ia64_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_ia64_AtomicDecrement +extern PRInt32 _PR_ia64_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_ia64_AtomicAdd +extern PRInt32 _PR_ia64_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_ia64_AtomicSet +#endif + +#if defined(__x86_64__) +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +extern PRInt32 _PR_x86_64_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _PR_x86_64_AtomicIncrement +extern PRInt32 _PR_x86_64_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _PR_x86_64_AtomicDecrement +extern PRInt32 _PR_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _PR_x86_64_AtomicAdd +extern PRInt32 _PR_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _PR_x86_64_AtomicSet +#endif + +#define USE_SETJMP +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _PR_POLL_AVAILABLE +#endif +#undef _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#if defined(__alpha) || defined(__ia64__) +#define _PR_HAVE_LARGE_OFF_T +#elif (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _PR_HAVE_OFF64_T +#else +#define _PR_NO_LARGE_FILES +#endif +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#if (__GLIBC__ >= 2) && defined(_PR_PTHREADS) +#define _PR_HAVE_GETHOST_R +#define _PR_HAVE_GETHOST_R_INT +#endif + +#ifdef _PR_PTHREADS + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +#else /* ! _PR_PTHREADS */ + +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#ifdef __powerpc__ +/* + * PowerPC based MkLinux + * + * On the PowerPC, the new style jmp_buf isn't used until glibc + * 2.1. + */ +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_GPR1] +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__misc[0] +#endif /* glibc 2.1 or later */ +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +/* aix = 64, macos = 70 */ +#define PR_NUM_GCREGS 64 + +#elif defined(__alpha) +/* Alpha based Linux */ + +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE long int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +/* XXX not sure if this is correct, or maybe it should be 17? */ +#define PR_NUM_GCREGS 9 + +#elif defined(__ia64__) + +#define _MD_GET_SP(_t) ((long *)((_t)->md.context[0].__jmpbuf)[0]) +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE long int + +#define PR_NUM_GCREGS _JBLEN + +#elif defined(__mc68000__) +/* m68k based Linux */ + +/* + * On the m68k, glibc still uses the old style sigjmp_buf, even + * in glibc 2.0.7. + */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +/* XXX not sure if this is correct, or maybe it should be 17? */ +#define PR_NUM_GCREGS 9 + +#elif defined(__sparc__) +/* Sparc */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +/* + * You need glibc2-2.0.7-25 or later. The libraries that came with + * Red Hat 5.1 are not new enough, but they are in 5.2. + */ +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[JB_FP] = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[JB_FP]) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__fp +#define _MD_SET_FP(_t, val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) ((void *) 0) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#elif defined(__i386__) +/* Intel based Linux */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[JB_SP] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[JB_BP] = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[JB_BP]) +#define _MD_SP_TYPE int +#else +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__bp = val) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) &((_t)->md.context[0].__jmpbuf[0].__bp) +#define _MD_SP_TYPE __ptr_t +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ +#define PR_NUM_GCREGS 6 + +#elif defined(__mips__) +/* Linux/MIPS */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[0].__sp +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[0].__fp = (val)) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[0].__fp) +#define _MD_SP_TYPE __ptr_t +#else +#error "Linux/MIPS pre-glibc2 not supported yet" +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#elif defined(__arm__) +/* ARM/Linux */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 +#define _MD_GET_SP(_t) (_t)->md.context[0].__jmpbuf[20] +#define _MD_SET_FP(_t, val) ((_t)->md.context[0].__jmpbuf[19] = (val)) +#define _MD_GET_SP_PTR(_t) &(_MD_GET_SP(_t)) +#define _MD_GET_FP_PTR(_t) (&(_t)->md.context[0].__jmpbuf[19]) +#define _MD_SP_TYPE __ptr_t +#else +#error "ARM/Linux pre-glibc2 not supported yet" +#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + +#else + +#error "Unknown CPU architecture" + +#endif /*__powerpc__*/ + +/* +** Initialize a thread context to run "_main()" when started +*/ +#ifdef __powerpc__ + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 128); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#elif defined(__mips__) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + (void) sigsetjmp(CONTEXT(_thread), 1); \ + _thread->md.context[0].__jmpbuf[0].__pc = (__ptr_t) _main; \ + _MD_GET_SP(_thread) = (_MD_SP_TYPE) ((_sp) - 64); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#else + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (_MD_SP_TYPE) ((_sp) - 64); \ + _thread->md.sp = _MD_GET_SP_PTR(_thread); \ + _thread->md.fp = _MD_GET_FP_PTR(_thread); \ + _MD_SET_FP(_thread, 0); \ +} + +#endif /*__powerpc__*/ + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + void *sp; + void *fp; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#include /* for FD_SETSIZE */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#endif /* ! _PR_PTHREADS */ + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT __select + +#ifdef _PR_POLL_AVAILABLE +#include +extern int __syscall_poll(struct pollfd *ufds, unsigned long int nfds, + int timeout); +#define _MD_POLL __syscall_poll +#endif + +/* For writev() */ +#include + +extern void _MD_linux_map_sendfile_error(int err); + +#endif /* nspr_linux_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_macos.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_macos.h new file mode 100644 index 00000000..dbcab409 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_macos.h @@ -0,0 +1,725 @@ +/* -*- 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 prmacos_h___ +#define prmacos_h___ + +// +// This file contains all changes and additions which need to be made to the NSPR runtime +// for the Macintosh platform (specifically the Metrowerks environment). This file should +// only be incluced in Macintosh builds. +// + +#define PR_DLL_SUFFIX "" +#define _PR_LOCAL_THREADS_ONLY +#define _PR_NO_PREEMPT 1 +#define _PR_HAVE_ATOMIC_OPS 1 + +#include "prinit.h" +#include "prio.h" +#include "prlong.h" +#include "prlock.h" +#include "prcvar.h" +#include "prsem.h" +#include "prthread.h" +#include "prtime.h" +#include "prproces.h" + +#if !defined(MAC_NSPR_STANDALONE) +#include "macstdlibextras.h" +#endif + +#include +#include + +#include +#include +#include + +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (16 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) 1 + +struct _MDProcess { + PRInt8 notused; +}; + +struct _MDThread { + jmp_buf jb; + int osErrCode; + PRLock * asyncIOLock; + PRCondVar * asyncIOCVar; + PRBool missedIONotify; + PRBool missedAsyncNotify; + PRBool asyncNotifyPending; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +struct _MDCPU { + AbsoluteTime lastThreadSwitch; + AbsoluteTime lastWakeUpProcess; + PRBool trackScheduling; +}; + +typedef struct _MDSocketCallerInfo { + PRThread * thread; + void * cookie; +} _MDSocketCallerInfo; + +struct _MDFileDesc { + PRInt32 osfd; + PRPackedBool orderlyDisconnect; + PRPackedBool readReady; + PRPackedBool writeReady; + PRPackedBool exceptReady; + PRLock * miscLock; + + /* Server sockets: listen bit tells the notifier func what to do */ + PRBool doListen; + + /* stored error for non-blocking connects, as a Unix-style error code */ + OTReason disconnectError; + + _MDSocketCallerInfo misc; + _MDSocketCallerInfo read; + _MDSocketCallerInfo write; +}; + +/* +** Iinitialization Related definitions +*/ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _MD_FinalInit + +/* +** Interrupts Related definitions +*/ + +#define _MD_GET_INTSOFF() (_pr_intsOff) + +#define _MD_INTSOFF(_is) \ + PR_BEGIN_MACRO \ + ENTER_CRITICAL_REGION(); \ + (_is) = _PR_MD_GET_INTSOFF(); \ + _PR_MD_SET_INTSOFF(1); \ + LEAVE_CRITICAL_REGION(); \ + PR_END_MACRO + +#if TARGET_CARBON +extern void _MD_SetIntsOff(PRInt32 ints); +#define _MD_SET_INTSOFF(_val) _MD_SetIntsOff(_val) +#else /* not TARGET_CARBON */ +#define _MD_SET_INTSOFF(_val) (_pr_intsOff = _val) +#endif /* TARGET_CARBON */ + +#define _MD_START_INTERRUPTS _MD_StartInterrupts +#define _MD_STOP_INTERRUPTS _MD_StopInterrupts +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() + +/* +** CPU Related definitions +*/ + +#define _MD_PAUSE_CPU _MD_PauseCPU +#define _MD_CLEANUP_BEFORE_EXIT() +#define _MD_EXIT(status) exit(status) +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) _MD_InitRunningCPU(cpu) + +/* +** Process Related definitions +*/ + +extern struct PRProcess * _MD_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); +#define _MD_CREATE_PROCESS _MD_CreateProcess + +extern PRStatus _MD_DetachProcess(PRProcess *process); +#define _MD_DETACH_PROCESS _MD_DetachProcess + +extern PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode); +#define _MD_WAIT_PROCESS _MD_WaitProcess + +extern PRStatus _MD_KillProcess(PRProcess *process); +#define _MD_KILL_PROCESS _MD_KillProcess + +/* +** Memory Segments Related definitions +*/ + +#define _MD_INIT_SEGS() + +/* +** Thread Stacks Debugging Related definitions +*/ + +#define _MD_INIT_STACK _MD_InitStack +#define _MD_CLEAR_STACK _MD_ClearStack + +/* +** Locks Related definitions +*/ + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) (PR_SUCCESS) +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) + +/* +** Thread Related definitions +*/ + +NSPR_API(PRThread *) PR_GetPrimaryThread(); + +#if defined(powerc) || defined(__powerc) +#define _MD_GET_PC(_t) (*((PRUint32 *)((_t)->md.jb))) +#define _MD_GET_SP(_t) (*((PRUint32 *)((_t)->md.jb) + 2)) +#define _MD_GET_TOC(_t) (*((PRUint32 *)((_t)->md.jb) + 3)) +#define INIT_STACKPTR(stackTop) ((unsigned char*)stackTop - 128) +#define PR_NUM_GCREGS 70 +#else +#define _MD_GET_PC(_t) (*((PRUint32 *)((_t)->md.jb) + 6)) +#define _MD_GET_SP(_t) (*((PRUint32 *)((_t)->md.jb) + 12)) +#define INIT_STACKPTR(stackTop) ((unsigned char*)stackTop - 4) +#define PR_NUM_GCREGS 13 +#endif + +#define _MD_DEFAULT_STACK_SIZE (58 * 1024) +#define _MD_MINIMUM_STACK_SIZE (58 * 1024) + +/* +** Initialize the thread machine dependent data structure +*/ +extern PRStatus _MD_InitThread(PRThread *thread); +#define _MD_INIT_THREAD _MD_InitThread + +/* +** Clean-up the thread machine dependent data structure +*/ +#define _MD_CLEAN_THREAD(_thread) \ + PR_BEGIN_MACRO \ + PR_DestroyCondVar(_thread->md.asyncIOCVar); \ + PR_DestroyLock(_thread->md.asyncIOLock); \ + PR_END_MACRO + + +/* +** Initialize the thread context preparing it to execute _main. +** *sp = 0 zeros out the sp for the first stack frame so that +** stack walking code can find the top of the stack. +*/ +#if defined(powerc) || defined(__powerc) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, _status) \ + PR_BEGIN_MACRO \ + unsigned char *sp; \ + unsigned long *tvect; \ + long **jb = (_thread)->md.jb; \ + *((PRBool *)_status) = PR_TRUE; \ + (void) setjmp(jb); \ + sp = INIT_STACKPTR(_sp); \ + *sp = 0; \ + (_MD_GET_SP(_thread)) = (long) sp; \ + tvect = (unsigned long *)_main; \ + (_MD_GET_PC(_thread)) = (int) *tvect; \ + (_MD_GET_TOC(_thread)) = (int) *(tvect+1); \ + _thread->no_sched = 0; \ + PR_END_MACRO +#else +#define _MD_INIT_CONTEXT(_thread, _sp, _main, _status) \ + PR_BEGIN_MACRO \ + unsigned char *sp; \ + long **jb = (_thread)->md.jb; \ + *((PRBool *)_status) = PR_TRUE; \ + (void) setjmp(jb); \ + sp = INIT_STACKPTR(_sp); \ + (_MD_GET_SP(_thread)) = (long) sp; \ + (_MD_GET_PC(_thread)) = (int) _main; \ + _thread->no_sched = 0; \ + PR_END_MACRO +#endif + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +*/ +/* ResetTimer(); before _PR_Schedule() */ + + +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!setjmp(_thread->md.jb)) { \ + _MD_SET_LAST_THREAD(_thread); \ + if (_PR_MD_CURRENT_CPU()->md.trackScheduling) \ + _PR_MD_CURRENT_CPU()->md.lastThreadSwitch = UpTime(); \ + _PR_Schedule(); \ + } else { \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + long **jb = (_newThread)->md.jb; \ + _MD_SET_CURRENT_THREAD(_newThread); \ + _newThread->no_sched = 1; \ + longjmp(jb, 1); \ + PR_END_MACRO + + +#define _MD_ERRNO() _MD_CURRENT_THREAD()->md.osErrCode + +extern PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +/* +** Combined thread model related definitions +*/ + +#define _MD_CREATE_THREAD(a,b,c,d,e,f) (PR_SUCCESS) +#define _MD_WAKEUP_WAITER(a) +#define _MD_SET_PRIORITY(a,b) + +/* +** File I/O Related definitions +*/ + +extern PRInt32 _PR_MD_WRITE_SYNC(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _PR_MD_WRITE_SYNC _MD_WRITE_SYNC + +struct _MDDir { + short ioVRefNum; + long ioDirID; + short ioFDirIndex; + char *currentEntryName; +}; + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" + +typedef enum IOOperation { + READ_ASYNC, + WRITE_ASYNC +} IOOperation; + + +#define _MD_INIT_IO() + +#define _MD_OPEN _MD_Open +#define _MD_OPEN_FILE _MD_Open +#define _MD_CLOSE_FILE FSClose +#define _MD_READ(fd,buf,amount) ReadWriteProc(fd,buf,amount,READ_ASYNC) +#define _MD_WRITE(fd,buf,amount) ReadWriteProc(fd,buf,amount,WRITE_ASYNC) +#define _MD_WRITE_SYNC(fd,buf,amount) WriteSyncProc(fd,buf,amount) +#define _MD_GET_FILE_ERROR() _PR_MD_CURRENT_THREAD()->md.osErrCode +#define _MD_LSEEK _MD_LSeek +#define _MD_FSYNC _MD_FSync + +/* to be implemented */ +#define _MD_LSEEK64(a,b,c) LL_ZERO +#define _MD_GETOPENFILEINFO64(fd,info) -1 +#define _MD_GETFILEINFO64(fd,info) -1 + +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* +** File Manipulation definitions +*/ + +#define _MD_RENAME _MD_Rename +#define _MD_ACCESS _MD_Access + +#define _MD_GETFILEINFO _MD_GetFileInfo +#define _MD_GETOPENFILEINFO _MD_GetOpenFileInfo + +#define _MD_STAT _MD_Stat + +#define _MD_DELETE _MD_Delete + +extern PRStatus _MD_LockFile(PRInt32 osfd); +#define _MD_LOCKFILE _MD_LockFile +extern PRStatus _MD_TLockFile(PRInt32 osfd); +#define _MD_TLOCKFILE _MD_TLockFile +extern PRStatus _MD_UnlockFile(PRInt32 osfd); +#define _MD_UNLOCKFILE _MD_UnlockFile + +/* +** Directory enumeration related definitions +*/ + +extern PRStatus _MD_OpenDir(struct _MDDir *md,const char *name); +#define _MD_OPEN_DIR _MD_OpenDir + +extern char* _MD_ReadDir(struct _MDDir *md,PRIntn flags); +#define _MD_READ_DIR _MD_ReadDir + +#define _MD_CLOSE_DIR _MD_CloseDir + +#define _MD_MKDIR _MD_MkDir +#define _MD_MAKE_DIR _MD_MkDir +#define _MD_RMDIR _MD_Delete + +/* +** Pipe I/O Related definitions (not implemented) +*/ + +#define _MD_PIPEAVAILABLE(fd) -1 + +/* +** Socket I/O Related definitions +*/ + +#if UNIVERSAL_INTERFACES_VERSION >= 0x0330 +/* In Universal Interfaces 3.3 and later, these are enums. */ +#define IP_TTL IP_TTL +#define IP_TOS IP_TOS +#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +#define IP_MULTICAST_IF IP_MULTICAST_IF +#define IP_MULTICAST_TTL IP_MULTICAST_TTL +#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP +#define TCP_NODELAY TCP_NODELAY +#define TCP_MAXSEG TCP_MAXSEG +#endif + +#define _MD_SOCKET _MD_socket +#define _MD_BIND _MD_bind +#define _MD_LISTEN _MD_listen +#define _MD_GETSOCKNAME _MD_getsockname + +extern PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +#define _MD_GETSOCKOPT _MD_getsockopt + +extern PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen); +#define _MD_SETSOCKOPT _MD_setsockopt + +#define _MD_SOCKETAVAILABLE _MD_socketavailable +#define _MD_ACCEPT _MD_accept +#define _MD_CONNECT _MD_connect +#define _MD_SEND _MD_send +#define _MD_RECV _MD_recv +#define _MD_CLOSE_SOCKET _MD_closesocket +#define _MD_SENDTO _MD_sendto +#define _MD_RECVFROM _MD_recvfrom +#define _MD_PR_POLL _MD_poll +#define _MD_INIT_FILEDESC _MD_initfiledesc +#define _MD_FREE_FILEDESC _MD_freefiledesc +#define _MD_MAKE_NONBLOCK _MD_makenonblock +#define _MD_INIT_FD_INHERITABLE _MD_initfdinheritable +#define _MD_QUERY_FD_INHERITABLE _MD_queryfdinheritable + +#define _MD_GET_SOCKET_ERROR() _PR_MD_CURRENT_THREAD()->md.osErrCode + +#define _PR_MD_MAP_SELECT_ERROR(x) (x) +/* +** Netdb Related definitions +*/ +extern PRStatus _MD_gethostname(char *name, int namelen); +#define _MD_GETHOSTNAME _MD_gethostname +#define _PR_GET_HOST_ADDR_AS_NAME + +/* + XXX _MD_WRITEV, _MD_SHUTDOWN & _MD_GETPEERNAME not done yet!!! +*/ +#define _MD_WRITEV _MD_writev +#define _MD_SHUTDOWN _MD_shutdown +#define _MD_GETPEERNAME _MD_getpeername + + +#ifdef OLD_MACSOCK_LIBRARY +#define _MD_SOCKET macsock_socket +#define _MD_LISTEN macsock_listen +#define _MD_SEND(fd,buf,amount,flags,timeout) macsock_send(fd->secret->md.osfd,buf,amount,flags) +#define _MD_SENDTO(fd,buf,amount,flags,addr,addrlen,timeout) macsock_sendto(fd->secret->md.osfd,buf,amount,flags,(struct sockaddr *)addr,addrlen) +#define _MD_RECV(fd,buf,amount,flags,timeout) macsock_recv(fd->secret->md.osfd,buf,amount,flags) +#define _MD_RECVFROM(fd,buf,amount,flags,addr,addrlen,timeout) macsock_recvfrom(fd->secret->md.osfd,buf,amount,flags,(struct sockaddr *)addr,addrlen) +#define _MD_CLOSE_SOCKET macsock_close +#define _MD_SHUTDOWN(a,b) (0) + +#define _MD_ACCEPT(fd,addr,addrlen,timeout) macsock_accept(fd->secret->md.osfd,(struct sockaddr *)addr,addrlen) +#define _MD_CONNECT(fd,name,namelen,timeout) macsock_connect(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_BIND(fd,name,namelen) macsock_bind(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETSOCKNAME(fd,name,namelen) macsock_getsockname(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETPEERNAME(fd,name,namelen) macsock_getpeername(fd->secret->md.osfd,(struct sockaddr *)name,namelen) +#define _MD_GETSOCKOPT(fd,level,optname,optval,optlen) macsock_getsockopt(fd->secret->md.osfd,level,optname,optval,optlen) +#define _MD_SETSOCKOPT(fd,level,optname,optval,optlen) macsock_setsockopt(fd->secret->md.osfd,level,optname,optval,optlen) +#define _MD_SOCKETAVAILABLE(fd,bytes) macsock_socketavailable(fd->secret->md.osfd,bytes) +#endif + +/* +** Memory Segements Related definitions +*/ + +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +/* +** Time Related definitions +*/ + +#define _MD_GET_INTERVAL _MD_GetInterval +#define _MD_INTERVAL_PER_SEC() PR_MSEC_PER_SEC +#define _MD_INTERVAL_INIT() + +/* +** Environemnt Related definitions +*/ + +extern char *_MD_GetEnv(const char *name); +#define _MD_GET_ENV _MD_GetEnv + +extern int _MD_PutEnv(const char *variableCopy); +#define _MD_PUT_ENV _MD_PutEnv + +/* +** Following is old stuff to be looked at. +*/ + +#define GCPTR +#define CALLBACK +typedef int (*FARPROC)(); + + +#define MAX_NON_PRIMARY_TIME_SLICES 6 + +extern long gTimeSlicesOnNonPrimaryThread; +extern struct PRThread *gPrimaryThread; + +// Errors not found in the Mac StdCLib +#define EACCES 13 // Permission denied +#define ENOENT -43 // No such file or directory +#define _OS_INVALID_FD_VALUE -1 + +#define STDERR_FILENO 2 + +#if !defined(MAC_NSPR_STANDALONE) +#define PATH_SEPARATOR ':' +#define PATH_SEPARATOR_STR ":" +#define DIRECTORY_SEPARATOR '/' +#define DIRECTORY_SEPARATOR_STR "/" +#endif + +#define UNIX_THIS_DIRECTORY_STR "./" +#define UNIX_PARENT_DIRECTORY_STR "../" + + +// Alias a few names +#define getenv PR_GetEnv +#define putenv _MD_PutEnv + +#if defined(MAC_NSPR_STANDALONE) +typedef unsigned char (*MemoryCacheFlusherProc)(size_t size); +typedef void (*PreAllocationHookProc)(void); + +extern char *strdup(const char *source); + +extern void InstallPreAllocationHook(PreAllocationHookProc newHook); +extern void InstallMemoryCacheFlusher(MemoryCacheFlusherProc newFlusher); +#endif + +extern char *PR_GetDLLSearchPath(void); + +#if defined(MAC_NSPR_STANDALONE) +extern int strcmp(const char *str1, const char *str2); +extern int strcasecmp(const char *str1, const char *str2); +#endif + +extern void MapFullToPartialMacFile(char *); +extern char *MapPartialToFullMacFile(const char *); + +extern void ResetTimer(void); +extern void PR_PeriodicIdle(void); +extern void ActivateTimer(void); +extern void DeactivateTimer(void); +extern void PR_InitMemory(void); + +extern struct hostent *gethostbyaddr(const void *addr, int addrlen, int type); + +extern short GetVolumeRefNumFromName(const char *); + +#include // Needed to get FILE typedef +extern FILE *_OS_FOPEN(const char *filename, const char *mode); +// +// Macintosh only private parts. +// + +#define dprintTrace ";dprintf;doTrace" +#define dprintNoTrace ";dprintf" +extern void dprintf(const char *format, ...); + + +// Entry into the memory system's cache flushing +#if defined(MAC_NSPR_STANDALONE) +extern PRUint8 CallCacheFlushers(size_t blockSize); +#endif + +#if defined(MAC_NSPR_STANDALONE) +extern void* reallocSmaller(void* block, size_t newSize); +#endif + + +/* +** PR_GetSystemInfo related definitions +*/ +#define _PR_SI_SYSNAME "MacOS" +#define _PR_SI_ARCHITECTURE "PowerPC" + +/* + * Memory-mapped files + */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +extern void SetLogFileTypeCreator(const char *logFile); +extern int _MD_mac_get_nonblocking_connect_error(PRFileDesc* fd); + + +/* + * Critical section support + */ + +#define MAC_CRITICAL_REGIONS TARGET_CARBON + +#if MAC_CRITICAL_REGIONS + +extern void InitCriticalRegion(); +extern void TermCriticalRegion(); + +extern void EnterCritialRegion(); +extern void LeaveCritialRegion(); + +#define INIT_CRITICAL_REGION() InitCriticalRegion() +#define TERM_CRITICAL_REGION() TermCriticalRegion() + +#define ENTER_CRITICAL_REGION() EnterCritialRegion() +#define LEAVE_CRITICAL_REGION() LeaveCritialRegion() + +#else + +#define INIT_CRITICAL_REGION() +#define TERM_CRITICAL_REGION() + +#define ENTER_CRITICAL_REGION() +#define LEAVE_CRITICAL_REGION() + +#endif + + + +/* + * CPU Idle support + */ + +extern void InitIdleSemaphore(); +extern void TermIdleSemaphore(); + +extern void WaitOnIdleSemaphore(); +extern void SignalIdleSemaphore(); + + +/* + * Atomic operations + */ +#ifdef _PR_HAVE_ATOMIC_OPS + +extern PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval); + +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(val) OTAtomicAdd32(1, (SInt32 *)val) +#define _MD_ATOMIC_ADD(ptr, val) OTAtomicAdd32(val, (SInt32 *)ptr) +#define _MD_ATOMIC_DECREMENT(val) OTAtomicAdd32(-1, (SInt32 *)val) +#define _MD_ATOMIC_SET(val, newval) _MD_AtomicSet(val, newval) + +#endif /* _PR_HAVE_ATOMIC_OPS */ + + +#endif /* prmacos_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.cfg new file mode 100644 index 00000000..c8a32bfb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.cfg @@ -0,0 +1,140 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef NCR +#define NCR +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.h new file mode 100644 index 00000000..d094c2ee --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_ncr.h @@ -0,0 +1,230 @@ +/* -*- 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_unixware_defs_h___ +#define nspr_unixware_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "ncr" +#define _PR_SI_SYSNAME "NCR" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define HAVE_DLL +#define USE_DLFCN +#define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ + +#if !defined (HAVE_STRERROR) +#define HAVE_STRERROR +#endif + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define NEED_LOCALTIME_R +#define NEED_GMTIME_R +#define NEED_ASCTIME_R +#define NEED_STRTOK_R +#define NEED_CTIME_R +#define _PR_NEED_STRCASECMP + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_ncr_defs_h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.cfg new file mode 100644 index 00000000..558a5251 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.cfg @@ -0,0 +1,140 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef NEC +#define NEC +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.h new file mode 100644 index 00000000..ed7e8a36 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nec.h @@ -0,0 +1,196 @@ +/* -*- 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_nec_defs_h___ +#define nspr_nec_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "nec" +#define _PR_SI_SYSNAME "NEC" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_TIME_R +#define NEED_STRFTIME_LOCK +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIM_UNION + +#include +#include + +#define PR_NUM_GCREGS NGREG +#define PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[CXT_SP] + +/* +** Initialize the thread context preparing it to execute "e(o,a)" +*/ +#define _MD_INIT_CONTEXT(thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + getcontext(CONTEXT(thread)); \ + CONTEXT(thread)->uc_stack.ss_sp = (char*) (thread)->stack->stackBottom; \ + CONTEXT(thread)->uc_stack.ss_size = (thread)->stack->stackSize; \ + _MD_GET_SP(thread) = (greg_t) _sp - 64; \ + makecontext(CONTEXT(thread), _main, 0); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!getcontext(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gregs[CXT_V0] = 1; \ + uc->uc_mcontext.gregs[CXT_A3] = 0; \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + setcontext(uc); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#define _MD_SELECT _select +#define _MD_POLL _poll + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#endif /* nspr_nec_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.cfg new file mode 100644 index 00000000..09457192 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.cfg @@ -0,0 +1,289 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef NETBSD +#define NETBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#if defined(__i386__) || defined(__arm32__) || defined(__MIPSEL__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__sparc__) || defined(__MIPSEB__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) || defined(__x86_64__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.h new file mode 100644 index 00000000..cc16f105 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_netbsd.h @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef nspr_netbsd_defs_h___ +#define nspr_netbsd_defs_h___ + +#include +#include /* for __NetBSD_Version__ */ + +#define PR_LINKER_ARCH "netbsd" +#define _PR_SI_SYSNAME "NetBSD" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__alpha__) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__m68k__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__powerpc__) +#define _PR_SI_ARCHITECTURE "powerpc" +#elif defined(__sparc_v9__) +#define _PR_SI_ARCHITECTURE "sparc64" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__mips__) +#define _PR_SI_ARCHITECTURE "mips" +#elif defined(__arm32__) || defined(__arm__) || defined(__armel__) \ + || defined(__armeb__) +#define _PR_SI_ARCHITECTURE "arm" +#endif + +#if defined(__ELF__) +#define PR_DLL_SUFFIX ".so" +#else +#define PR_DLL_SUFFIX ".so.1.0" +#endif + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#if __NetBSD_Version__ >= 105000000 +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#endif + +#if __NetBSD_Version__ >= 106370000 +/* NetBSD 1.6ZK */ +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_INT +#endif + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize a thread context to run "_main()" when started +*/ +#ifdef __i386__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[2] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[0] = (int) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[2] +#endif +#ifdef __sparc_v9__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[1] = (unsigned char*) ((_sp) - 176 - 0x7ff); \ + CONTEXT(_thread)[2] = (long) _main; \ + CONTEXT(_thread)[3] = (long) _main + 4; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) (CONTEXT(_thread)[2]+0x7ff) +#elif defined(__sparc__) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[2] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[3] = (int) _main; \ + CONTEXT(_thread)[4] = (int) _main + 4; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[2] +#endif +#ifdef __powerpc__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[3] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[4] = (int) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[3] +#endif +#ifdef __m68k__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[2] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[5] = (int) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[2] +#endif +#ifdef __mips__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[32] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[2] = (int) _main; \ + CONTEXT(_thread)[28] = (int) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[32] +#endif +#if defined(__arm32__) || defined(__arm__) || defined(__armel__) \ + || defined(__armeb__) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[23] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[24] = (int) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[23] +#endif +#ifdef __alpha__ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + sigsetjmp(CONTEXT(_thread), 1); \ + CONTEXT(_thread)[34] = (unsigned char*) ((_sp) - 128); \ + CONTEXT(_thread)[2] = (long) _main; \ + CONTEXT(_thread)[30] = (long) _main; \ + CONTEXT(_thread)[31] = (long) _main; \ + *status = PR_TRUE; \ +} +#define _MD_GET_SP(_thread) CONTEXT(_thread)[34] +#endif +#ifndef _MD_INIT_CONTEXT +#error "Need to define _MD_INIT_CONTEXT for this platform" +#endif + +#define PR_NUM_GCREGS _JBLEN + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) +#if defined(_PR_POLL_AVAILABLE) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) +#endif + +#if NetBSD1_3 == 1L +typedef unsigned int nfds_t; +#endif + +#endif /* nspr_netbsd_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.cfg new file mode 100644 index 00000000..ce623cb9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.cfg @@ -0,0 +1,255 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef NEXTSTEP +#define NEXTSTEP +#endif + +/* Platform specific +*/ +#if defined(__sparc__) + +/* Check these +*/ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +/* Taken from _solaris.cfg +*/ +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +/* Taken from _solaris.cfg +*/ +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +/* Taken from _solaris.cfg +*/ +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_WORDS_PER_DWORD_LOG2 1 + +#elif defined(__m68k__) + +/* Check these +*/ +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 2 +#define PR_ALIGN_OF_INT64 2 +#define PR_ALIGN_OF_FLOAT 2 +#define PR_ALIGN_OF_DOUBLE 2 +#define PR_ALIGN_OF_POINTER 2 + +#define PR_WORDS_PER_DWORD_LOG2 1 + +#elif defined(__i386__) + +/* Check these +*/ +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 +#define PR_ALIGN_OF_WORD 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 +#endif /* defined(__somearch__) */ + + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.h new file mode 100644 index 00000000..e7e4c055 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nextstep.h @@ -0,0 +1,299 @@ +/* -*- 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_nextstep_defs_h___ +#define nspr_nextstep_defs_h___ + +#include "prthread.h" + +#include +#include + +/* syscall() is not declared in NEXTSTEP's syscall.h ... +*/ +extern int syscall(int number, ...); + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "nextstep" +#define _PR_SI_SYSNAME "NEXTSTEP" +#if defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(__m68k__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#else +error Unknown NEXTSTEP architecture +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP + +#define HAVE_WEAK_MALLOC_SYMBOLS + +#define HAVE_DLL +#define USE_MACH_DYLD +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_NO_LARGE_FILES + +#define USE_SETJMP + +#ifndef _PR_PTHREADS + +#include + +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +/* balazs.pataki@sztaki.hu: +** __sparc__ is checked +** __m68k__ is checked +** __i386__ is a guess (one of the two defines should work) +*/ +#if defined(__sparc__) +#define _MD_GET_SP(_th) (_th)->md.context[2] +#elif defined(__m68k__) +#define _MD_GET_SP(_th) (_th)->md.context[2] +#elif defined(__i386__) +/* One of this two must be OK ... try using sc_onstack +*/ +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +//#define _MD_GET_SP(_th) (_th)->md.context[0].sc_esp +#else +error Unknown NEXTSTEP architecture +#endif + +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#endif /* ! _PR_PTHREADS */ + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +/* For writev() */ +#include + +/* signal.h */ +/* balazs.pataki@sztaki.hu: this is stolen from sunos4.h. The things is that +** NEXTSTEP doesn't support these flags for `struct sigaction's sa_flags, so +** I have to fake them ... +*/ +#define SA_RESTART 0 + +/* mmap */ +/* balazs.pataki@sztaki.hu: NEXTSTEP doesn't have mmap, at least not +** publically. We have sys/mman.h, but it doesn't declare mmap(), and +** PROT_NONE is also missing. syscall.h has entries for mmap, munmap, and +** mprotect so I wrap these in nextstep.c as mmap(), munmap() and mprotect() +** and pray for it to work. +** +*/ +caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off); +int munmap(caddr_t addr, size_t len); +int mprotect(caddr_t addr, size_t len, int prot); + +/* my_mmap() is implemented in nextstep.c and is based on map_fd() of mach. +*/ +caddr_t my_mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off); +int my_munmap(caddr_t addr, size_t len); + + +/* string.h +*/ +/* balazs.pataki@sztaki.hu: this is missing so implemenetd in nextstep.c ... +*/ +char *strdup(const char *s1); + +/* unistd.h +*/ +/* balazs.pataki@sztaki.hu: these functions are hidden, though correctly +** implemented in NEXTSTEP. Here I give the declaration for them to be used +** by prmalloc.c, and I have a wrapped syscall() version of them in nextstep.c +*/ +int brk(void *endds); +void *sbrk(int incr); + +#endif /* nspr_nextstep_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nspr_pthread.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nspr_pthread.h new file mode 100644 index 00000000..b7a0481e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nspr_pthread.h @@ -0,0 +1,283 @@ +/* -*- 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_pthread_defs_h___ +#define nspr_pthread_defs_h___ + +#include +#include "prthread.h" + +#if defined(PTHREADS_USER) +/* +** Thread Local Storage +*/ +extern pthread_key_t current_thread_key; +extern pthread_key_t current_cpu_key; +extern pthread_key_t last_thread_key; +extern pthread_key_t intsoff_key; + +#define _MD_CURRENT_THREAD() \ + ((struct PRThread *) pthread_getspecific(current_thread_key)) +#define _MD_CURRENT_CPU() \ + ((struct _PRCPU *) pthread_getspecific(current_cpu_key)) +#define _MD_LAST_THREAD() \ + ((struct PRThread *) pthread_getspecific(last_thread_key)) + +#define _MD_SET_CURRENT_THREAD(newval) \ + pthread_setspecific(current_thread_key, (void *)newval) + +#define _MD_SET_CURRENT_CPU(newval) \ + pthread_setspecific(current_cpu_key, (void *)newval) + +#define _MD_SET_LAST_THREAD(newval) \ + pthread_setspecific(last_thread_key, (void *)newval) + +#define _MD_SET_INTSOFF(_val) +#define _MD_GET_INTSOFF() 1 + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (SAVE_CONTEXT(_thread)) { \ + (*_main)(); \ + } \ + _MD_SET_THR_SP(_thread, _sp); \ + _thread->no_sched = 0; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + PR_ASSERT(_thread->no_sched); \ + if (!SAVE_CONTEXT(_thread)) { \ + (_thread)->md.errcode = errno; \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + (_MD_LAST_THREAD())->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _thread->no_sched = 1; \ + GOTO_CONTEXT(_thread); \ + PR_END_MACRO + + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; + pthread_t pthread; + pthread_mutex_t pthread_mutex; + pthread_cond_t pthread_cond; + int wait; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + pthread_mutex_t mutex; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + pthread_mutex_t mutex; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + jmp_buf jb; + pthread_t pthread; + struct _MDCPU_Unix md_unix; +}; + +/* +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +*/ + +extern pthread_mutex_t _pr_heapLock; + +#define _PR_LOCK(lock) pthread_mutex_lock(lock) + +#define _PR_UNLOCK(lock) pthread_mutex_unlock(lock) + + +#define _PR_LOCK_HEAP() { \ + if (_pr_primordialCPU) { \ + _PR_LOCK(_pr_heapLock); \ + } + +#define _PR_UNLOCK_HEAP() if (_pr_primordialCPU) { \ + _PR_UNLOCK(_pr_heapLock); \ + } \ + } + +NSPR_API(PRStatus) _MD_NEW_LOCK(struct _MDLock *md); +NSPR_API(void) _MD_FREE_LOCK(struct _MDLock *lockp); + +#define _MD_LOCK(_lockp) _PR_LOCK(&(_lockp)->mutex) +#define _MD_UNLOCK(_lockp) _PR_UNLOCK(&(_lockp)->mutex) + +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() +#define _MD_CHECK_FOR_EXIT() + +NSPR_API(PRStatus) _MD_InitThread(struct PRThread *thread); +#define _MD_INIT_THREAD _MD_InitThread +#define _MD_INIT_ATTACHED_THREAD _MD_InitThread + +NSPR_API(void) _MD_ExitThread(struct PRThread *thread); +#define _MD_EXIT_THREAD _MD_ExitThread + +NSPR_API(void) _MD_SuspendThread(struct PRThread *thread); +#define _MD_SUSPEND_THREAD _MD_SuspendThread + +NSPR_API(void) _MD_ResumeThread(struct PRThread *thread); +#define _MD_RESUME_THREAD _MD_ResumeThread + +NSPR_API(void) _MD_SuspendCPU(struct _PRCPU *thread); +#define _MD_SUSPEND_CPU _MD_SuspendCPU + +NSPR_API(void) _MD_ResumeCPU(struct _PRCPU *thread); +#define _MD_RESUME_CPU _MD_ResumeCPU + +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_RESUME_ALL() + +NSPR_API(void) _MD_EarlyInit(void); +#define _MD_EARLY_INIT _MD_EarlyInit + +#define _MD_FINAL_INIT _PR_UnixInit + +NSPR_API(void) _MD_InitLocks(void); +#define _MD_INIT_LOCKS _MD_InitLocks + +NSPR_API(void) _MD_CleanThread(struct PRThread *thread); +#define _MD_CLEAN_THREAD _MD_CleanThread + +NSPR_API(PRStatus) _MD_CreateThread( + struct PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +extern void _MD_CleanupBeforeExit(void); +#define _MD_CLEANUP_BEFORE_EXIT _MD_CleanupBeforeExit + +NSPR_API(void) _MD_InitRunningCPU(struct _PRCPU *cpu); +#define _MD_INIT_RUNNING_CPU _MD_InitRunningCPU + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +NSPR_API(PRStatus) _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +NSPR_API(PRStatus) _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void) _MD_SetPriority(struct _MDThread *thread, + PRThreadPriority newPri); +#define _MD_SET_PRIORITY _MD_SetPriority + +#endif /* PTHREADS_USER */ + +#endif /* nspr_pthread_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.cfg new file mode 100644 index 00000000..76635729 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.cfg @@ -0,0 +1,150 @@ +/* -*- 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 ***** */ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_UNIX +#define XP_UNIX +#endif + +#ifndef NTO +#define NTO +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#ifdef __i386__ + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#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 4L +#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 + +#else + +#error Undefined CPU Architecture + +#endif + +#define HAVE_LONG_LONG + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.h new file mode 100644 index 00000000..97f4d38f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_nto.h @@ -0,0 +1,221 @@ +/* -*- 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 ***** */ + +#ifndef nspr_nto_defs_h___ +#define nspr_nto_defs_h___ + +/* +** Internal configuration macros +*/ +#define PR_LINKER_ARCH "nto" +#define _PR_SI_SYSNAME "NTO" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MINIMUM_STACK_SIZE 131072L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef _PR_POLL_AVAILABLE +#undef _PR_USE_POLL +#define _PR_HAVE_SOCKADDR_LEN +#undef HAVE_BSD_FLOCK +#define HAVE_FCNTL_FILE_LOCKING +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#define _PR_HAVE_POSIX_SEMAPHORES + +#undef FD_SETSIZE +#define FD_SETSIZE 4096 +#include +#include +#include + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _PR_NUM_GCREGS _JBLEN +#define _MD_GET_SP(_t) (_t)->md.context[7] + +#define CONTEXT(_th) ((_th)->md.context) + + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* +** Machine-dependent (MD) data structures. +*/ +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* +** md-specific cpu structure field +*/ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD], fd_write_cnt[_PR_MD_MAX_OSFD], fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* +** We wrapped the select() call. _MD_SELECT refers to the built-in, +** unwrapped version. +*/ +#define _MD_SELECT select + +#define SA_RESTART 0 + +#endif /* nspr_nto_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.cfg new file mode 100644 index 00000000..0041a242 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.cfg @@ -0,0 +1,387 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef OPENBSD +#define OPENBSD +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#if defined(__i386__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__amd64__) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 +#define PR_ALIGN_OF_WORD 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#elif defined(__sparc_v9__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__sparc__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#elif defined(__alpha__) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#define IS_64 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#elif defined(__powerpc__) || defined(__m68k__) + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#else + +#error Must define constants for type sizes here. + +#endif + + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.h new file mode 100644 index 00000000..ccd75306 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openbsd.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 nspr_openbsd_defs_h___ +#define nspr_openbsd_defs_h___ + +#include + +#define PR_LINKER_ARCH "openbsd" +#define _PR_SI_SYSNAME "OPENBSD" +#if defined(__i386__) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__alpha__) +#define _PR_SI_ARCHITECTURE "alpha" +#elif defined(__amd64__) +#define _PR_SI_ARCHITECTURE "amd64" +#elif defined(__m68k__) +#define _PR_SI_ARCHITECTURE "m68k" +#elif defined(__powerpc__) +#define _PR_SI_ARCHITECTURE "powerpc" +#elif defined(__sparc__) +#define _PR_SI_ARCHITECTURE "sparc" +#endif + +#define PR_DLL_SUFFIX ".so.1.0" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#define _PR_INET6 +#define _PR_HAVE_INET_NTOP +#define _PR_HAVE_GETHOSTBYNAME2 +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE + +#define USE_SETJMP + +#ifndef _PR_PTHREADS +#include + +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.context) + +#if defined(__i386__) || defined(__sparc__) || defined(__m68k__) +#define JB_SP_INDEX 2 +#elif defined(__powerpc__) +#define JB_SP_INDEX 1 +#elif defined(__alpha__) +#define JB_SP_INDEX 34 +#elif defined(__amd64__) +#define JB_SP_INDEX 6 +#else +#error "Need to define SP index in jmp_buf here" +#endif +#define _MD_GET_SP(_th) (_th)->md.context[JB_SP_INDEX] + +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread), 1)) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) +#include +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#if OpenBSD1_3 == 1L +typedef unsigned int nfds_t; +#endif + +#endif /* nspr_openbsd_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.cfg new file mode 100644 index 00000000..84c2a9d4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.cfg @@ -0,0 +1,146 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef VMS +#define VMS +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#ifdef IS_64 +#undef IS_64 +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.h new file mode 100644 index 00000000..1ee7e428 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_openvms.h @@ -0,0 +1,332 @@ +/* -*- 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 is the OpenVMS machine dependant configuration file. It is based +** on the OSF/1 machine dependant file. +*/ + +#ifndef nspr_openvms_defs_h___ +#define nspr_openvms_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "OpenVMS" +#define _PR_SI_SYSNAME "OpenVMS" +#ifdef __alpha +#define _PR_SI_ARCHITECTURE "alpha" +#else +#define _PR_SI_ARCHITECTURE "vax" +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 131072L +#define _MD_MINIMUM_STACK_SIZE 131072L + +/* +** This is not defined on OpenVMS. I believe its only used in GC code, and +** isn't that only used in Java? Anyway, for now, let's keep the compiler +** happy. +*/ +#define SA_RESTART 0 + +/* +** OpenVMS doesn't have these in socket.h. +** Does in later versions! +*/ +#if 0 +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; +#endif + +/* + * OSF1 needs the MAP_FIXED flag to ensure that mmap returns a pointer + * with the upper 32 bits zero. This is because Java sticks a pointer + * into an int. + */ +#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#undef HAVE_BSD_FLOCK + +#define NEED_TIME_R + +#define HAVE_DLL +#define USE_DLFCN + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_NO_LARGE_FILES +#define _PR_STRICT_ADDR_LEN + +/* IPv6 support */ +#ifdef _SOCKADDR_LEN +#define _PR_HAVE_SOCKADDR_LEN +#endif +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x00000002 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define AI_V4MAPPED 0x00000010 +#define AI_ALL 0x00000008 +#define AI_ADDRCONFIG 0x00000020 +#endif + +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* if we have a quadword field defined in the structure, then its length */ +/* will be a multiple of 8, and connect() won't accept 32 (it wants 28) */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + } _S6_un; +}; +struct _md_sockaddr_in6 { + PRUint16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; +}; + +#undef USE_SETJMP + +#include + +/* + * A jmp_buf is actually a struct sigcontext. The sc_sp field of + * struct sigcontext is the stack pointer. + */ +#define _MD_GET_SP(_t) (((struct sigcontext *) (_t)->md.context)->sc_sp) +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) + +/* +** I am ifdef'ing these out because that's the way they are in FT. +*/ +#ifndef __VMS + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (long) ((_sp) - 64); \ + _MD_GET_SP(_thread) &= ~15; \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +#endif /* __VMS */ + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +extern PRIntervalTime _PR_UNIX_GetInterval(void); +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +void _MD_EarlyInit(void); +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#ifdef _VMS_NOT_YET +NSPR_API(void) _PR_InitThreads( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); +#endif +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +extern int __select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT __select + +#ifndef __VMS +#define _MD_POLL __poll +extern int __poll(struct pollfd filedes[], unsigned int nfds, int timeout); +#endif + +#ifdef __VMS +NSPR_API(void) _PR_InitCPUs(void); +NSPR_API(void) _PR_MD_START_INTERRUPTS(void); +#endif + +/* + * Atomic operations + */ +#include +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_ADD(ptr,val) (__ATOMIC_ADD_LONG(ptr,val) + val) +#define _MD_ATOMIC_INCREMENT(val) (__ATOMIC_INCREMENT_LONG(val) + 1) +#define _MD_ATOMIC_DECREMENT(val) (__ATOMIC_DECREMENT_LONG(val) - 1) +#define _MD_ATOMIC_SET(val, newval) __ATOMIC_EXCH_LONG(val, newval) + +extern int thread_suspend(PRThread *thr_id); +extern int thread_resume(PRThread *thr_id); + +#endif /* nspr_openvms_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.cfg new file mode 100644 index 00000000..55bcf93b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.cfg @@ -0,0 +1,151 @@ +/* -*- 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_PC +#define XP_PC +#endif + +#ifndef XP_OS2 +#define XP_OS2 +#endif + +#ifndef OS2 +#define OS2 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#ifdef NO_LONG_LONG +#undef HAVE_LONG_LONG +#else +#define HAVE_LONG_LONG 1 +#endif + +#define PR_AF_INET6 24 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 2 + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.h new file mode 100644 index 00000000..d72af0e5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2.h @@ -0,0 +1,601 @@ +/* -*- 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_os2_defs_h___ +#define nspr_os2_defs_h___ + +#define INCL_DOS +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_WPS +#include +#include + +#include "prio.h" + +#include + +#ifdef XP_OS2_VACPP +/* TODO RAMSEMs need to be written for GCC/EMX */ +#define USE_RAMSEM +#endif + +#ifdef USE_RAMSEM +#pragma pack(4) + +#pragma pack(2) +typedef struct _RAMSEM +{ + ULONG ulTIDPID; + ULONG hevSem; + ULONG cLocks; + USHORT cWaiting; + USHORT cPosts; +} RAMSEM, *PRAMSEM; + +typedef struct _CRITICAL_SECTION +{ + ULONG ulReserved[4]; /* Same size as RAMSEM */ +} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION; +#pragma pack(4) + +APIRET _Optlink SemRequest486(PRAMSEM, ULONG); +APIRET _Optlink SemReleasex86(PRAMSEM, ULONG); +#endif + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "os2" +#define _PR_SI_SYSNAME "OS2" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#define _PR_GLOBAL_THREADS_ONLY +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS +#ifndef TCPV40HDRS /* bird */ +#define _PR_HAVE_SOCKADDR_LEN /* bird */ +#endif /* bird */ + +#define HANDLE unsigned long +#define HINSTANCE HMODULE + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF +typedef int (*FARPROC)(); + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + +struct _MDSemaphore { + HEV sem; +}; + +struct _MDCPU { + int unused; +}; + +struct _MDThread { + HEV blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRBool inCVWaitQueue; /* PR_TRUE if the thread is in the + * wait queue of some cond var. + * PR_FALSE otherwise. */ + TID handle; /* OS/2 thread handle */ + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct PRThread *prev, *next; /* used by the cvar wait queue to + * chain the PRThread structures + * together */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDDir { + HDIR d_hdl; + FILEFINDBUF3 d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +struct _MDCVar { + PRUint32 magic; + struct PRThread *waitHead, *waitTail; /* the wait queue: a doubly- + * linked list of threads + * waiting on this condition + * variable */ + PRIntn nwait; /* number of threads in the + * wait queue */ +}; + +#define _MD_CV_NOTIFIED_LENGTH 6 +typedef struct _MDNotified _MDNotified; +struct _MDNotified { + PRIntn length; /* # of used entries in this + * structure */ + struct { + struct _MDCVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + struct PRThread *notifyHead; /* list of threads to wake up */ + } cv[_MD_CV_NOTIFIED_LENGTH]; + _MDNotified *link; /* link to another of these, or NULL */ +}; + +struct _MDLock { +#ifdef USE_RAMSEM + CRITICAL_SECTION mutex; /* this is recursive on NT */ +#else + HMTX mutex; /* this is recursive on NT */ +#endif + + /* + * When notifying cvars, there is no point in actually + * waking up the threads waiting on the cvars until we've + * released the lock. So, we temporarily record the cvars. + * When doing an unlock, we'll then wake up the waiting threads. + */ + struct _MDNotified notified; /* array of conditions notified */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDFileDesc { + PRInt32 osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using OS/2 handles, + * which is a void*. + * - For sockets, we are using int + */ +}; + +struct _MDProcess { + PID pid; +}; + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- IO stuff --- */ + +#define _MD_OPEN (_PR_MD_OPEN) +#define _MD_OPEN_FILE (_PR_MD_OPEN) +#define _MD_READ (_PR_MD_READ) +#define _MD_WRITE (_PR_MD_WRITE) +#define _MD_WRITEV (_PR_MD_WRITEV) +#define _MD_LSEEK (_PR_MD_LSEEK) +#define _MD_LSEEK64 (_PR_MD_LSEEK64) +extern PRInt32 _MD_CloseFile(PRInt32 osfd); +#define _MD_CLOSE_FILE _MD_CloseFile +#define _MD_GETFILEINFO (_PR_MD_GETFILEINFO) +#define _MD_GETFILEINFO64 (_PR_MD_GETFILEINFO64) +#define _MD_GETOPENFILEINFO (_PR_MD_GETOPENFILEINFO) +#define _MD_GETOPENFILEINFO64 (_PR_MD_GETOPENFILEINFO64) +#define _MD_STAT (_PR_MD_STAT) +#define _MD_RENAME (_PR_MD_RENAME) +#define _MD_ACCESS (_PR_MD_ACCESS) +#define _MD_DELETE (_PR_MD_DELETE) +#define _MD_MKDIR (_PR_MD_MKDIR) +#define _MD_MAKE_DIR (_PR_MD_MKDIR) +#define _MD_RMDIR (_PR_MD_RMDIR) +#define _MD_LOCKFILE (_PR_MD_LOCKFILE) +#define _MD_TLOCKFILE (_PR_MD_TLOCKFILE) +#define _MD_UNLOCKFILE (_PR_MD_UNLOCKFILE) + +/* --- Socket IO stuff --- */ + +/* The ones that don't map directly may need to be re-visited... */ +#ifdef XP_OS2_VACPP +#define EPIPE EBADF +#define EIO ECONNREFUSED +#endif +#define _MD_EACCES EACCES +#define _MD_EADDRINUSE EADDRINUSE +#define _MD_EADDRNOTAVAIL EADDRNOTAVAIL +#define _MD_EAFNOSUPPORT EAFNOSUPPORT +#define _MD_EAGAIN EWOULDBLOCK +#define _MD_EALREADY EALREADY +#define _MD_EBADF EBADF +#define _MD_ECONNREFUSED ECONNREFUSED +#define _MD_ECONNRESET ECONNRESET +#define _MD_EFAULT SOCEFAULT +#define _MD_EINPROGRESS EINPROGRESS +#define _MD_EINTR EINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN EISCONN +#define _MD_ENETUNREACH ENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN ENOTCONN +#define _MD_ENOTSOCK ENOTSOCK +#define _MD_EOPNOTSUPP EOPNOTSUPP +#define _MD_EWOULDBLOCK EWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() sock_errno() +#ifndef INADDR_LOOPBACK /* For some reason this is not defined in OS2 tcpip */ +/* #define INADDR_LOOPBACK INADDR_ANY */ +#endif + +#define _MD_INIT_FILEDESC(fd) +extern void _MD_MakeNonblock(PRFileDesc *f); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock +#define _MD_INIT_FD_INHERITABLE (_PR_MD_INIT_FD_INHERITABLE) +#define _MD_QUERY_FD_INHERITABLE (_PR_MD_QUERY_FD_INHERITABLE) +#define _MD_SHUTDOWN (_PR_MD_SHUTDOWN) +#define _MD_LISTEN _PR_MD_LISTEN +extern PRInt32 _MD_CloseSocket(PRInt32 osfd); +#define _MD_CLOSE_SOCKET _MD_CloseSocket +#define _MD_SENDTO (_PR_MD_SENDTO) +#define _MD_RECVFROM (_PR_MD_RECVFROM) +#ifdef XP_OS2_VACPP +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#else +#define _MD_SOCKETPAIR (_PR_MD_SOCKETPAIR) +#endif +#define _MD_GETSOCKNAME (_PR_MD_GETSOCKNAME) +#define _MD_GETPEERNAME (_PR_MD_GETPEERNAME) +#define _MD_GETSOCKOPT (_PR_MD_GETSOCKOPT) +#define _MD_SETSOCKOPT (_PR_MD_SETSOCKOPT) + +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SET_FD_INHERITABLE (_PR_MD_SET_FD_INHERITABLE) + +#ifdef _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD +#define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT +#define _MD_ATOMIC_SET _PR_MD_ATOMIC_SET +#endif + +#define _MD_INIT_IO (_PR_MD_INIT_IO) +#define _MD_PR_POLL (_PR_MD_PR_POLL) + +#define _MD_SOCKET (_PR_MD_SOCKET) +extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_SocketAvailable +#define _MD_PIPEAVAILABLE _MD_SocketAvailable +#define _MD_CONNECT (_PR_MD_CONNECT) +extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_Accept +#define _MD_BIND (_PR_MD_BIND) +#define _MD_RECV (_PR_MD_RECV) +#define _MD_SEND (_PR_MD_SEND) + +/* --- Scheduler stuff --- */ +/* #define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU */ +#define _MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() errno +#define _MD_OPEN_DIR (_PR_MD_OPEN_DIR) +#define _MD_CLOSE_DIR (_PR_MD_CLOSE_DIR) +#define _MD_READ_DIR (_PR_MD_READ_DIR) + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV (_PR_MD_GET_ENV) +#define _MD_PUT_ENV (_PR_MD_PUT_ENV) + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_INIT_THREAD (_PR_MD_INIT_THREAD) +#define _MD_INIT_ATTACHED_THREAD (_PR_MD_INIT_THREAD) +#define _MD_CREATE_THREAD (_PR_MD_CREATE_THREAD) +#define _MD_YIELD (_PR_MD_YIELD) +#define _MD_SET_PRIORITY (_PR_MD_SET_PRIORITY) +#define _MD_CLEAN_THREAD (_PR_MD_CLEAN_THREAD) +#define _MD_SETTHREADAFFINITYMASK (_PR_MD_SETTHREADAFFINITYMASK) +#define _MD_GETTHREADAFFINITYMASK (_PR_MD_GETTHREADAFFINITYMASK) +#define _MD_EXIT_THREAD (_PR_MD_EXIT_THREAD) +#define _MD_SUSPEND_THREAD (_PR_MD_SUSPEND_THREAD) +#define _MD_RESUME_THREAD (_PR_MD_RESUME_THREAD) +#define _MD_SUSPEND_CPU (_PR_MD_SUSPEND_CPU) +#define _MD_RESUME_CPU (_PR_MD_RESUME_CPU) +#define _MD_WAKEUP_CPUS (_PR_MD_WAKEUP_CPUS) +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK +extern void +md_UnlockAndPostNotifies(struct _MDLock *lock, PRThread *waitThred, struct _MDCVar *waitCV); +#ifdef USE_RAMSEM +#define _MD_NEW_LOCK (_PR_MD_NEW_LOCK) +#define _MD_FREE_LOCK(lock) (DosCloseEventSem(((PRAMSEM)(&((lock)->mutex)))->hevSem)) +#define _MD_LOCK(lock) (SemRequest486(&((lock)->mutex), -1)) +#define _MD_TEST_AND_LOCK(lock) (SemRequest486(&((lock)->mutex), -1),0) +#define _MD_UNLOCK(lock) \ + PR_BEGIN_MACRO \ + if (0 != (lock)->notified.length) { \ + md_UnlockAndPostNotifies((lock), NULL, NULL); \ + } else { \ + SemReleasex86( &(lock)->mutex, 0 ); \ + } \ + PR_END_MACRO +#else +#define _MD_NEW_LOCK (_PR_MD_NEW_LOCK) +#define _MD_FREE_LOCK(lock) (DosCloseMutexSem((lock)->mutex)) +#define _MD_LOCK(lock) (DosRequestMutexSem((lock)->mutex, SEM_INDEFINITE_WAIT)) +#define _MD_TEST_AND_LOCK(lock) (DosRequestMutexSem((lock)->mutex, SEM_INDEFINITE_WAIT),0) +#define _MD_UNLOCK(lock) \ + PR_BEGIN_MACRO \ + if (0 != (lock)->notified.length) { \ + md_UnlockAndPostNotifies((lock), NULL, NULL); \ + } else { \ + DosReleaseMutexSem((lock)->mutex); \ + } \ + PR_END_MACRO +#endif + +/* --- lock and cv waiting --- */ +#define _MD_WAIT (_PR_MD_WAIT) +#define _MD_WAKEUP_WAITER (_PR_MD_WAKEUP_WAITER) + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV (_PR_MD_WAIT_CV) +#define _MD_NEW_CV (_PR_MD_NEW_CV) +#define _MD_FREE_CV (_PR_MD_FREE_CV) +#define _MD_NOTIFY_CV (_PR_MD_NOTIFY_CV ) +#define _MD_NOTIFYALL_CV (_PR_MD_NOTIFYALL_CV) + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +/* extern struct _MDLock _pr_ioq_lock; */ +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +#define _MD_START_INTERRUPTS() +#define _MD_STOP_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_EARLY_INIT (_PR_MD_EARLY_INIT) +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +extern struct PRProcess * _PR_CreateOS2ProcessEx( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr, + PRBool detached +); + +#define _MD_CREATE_PROCESS _PR_CreateOS2Process +extern struct PRProcess * _PR_CreateOS2Process( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachOS2Process +extern PRStatus _PR_DetachOS2Process(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitOS2Process +extern PRStatus _PR_WaitOS2Process(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillOS2Process +extern PRStatus _PR_KillOS2Process(struct PRProcess *process); + +#define _MD_CLEANUP_BEFORE_EXIT() +#define _MD_EXIT (_PR_MD_EXIT) +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT (_PR_MD_INTERVAL_INIT) +#define _MD_GET_INTERVAL (_PR_MD_GET_INTERVAL) +#define _MD_INTERVAL_PER_SEC (_PR_MD_INTERVAL_PER_SEC) +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Native-Thread Specific Definitions ------------------------------- */ + +typedef struct __NSPR_TLS +{ + struct PRThread *_pr_thread_last_run; + struct PRThread *_pr_currentThread; + struct _PRCPU *_pr_currentCPU; +} _NSPR_TLS; + +extern _NSPR_TLS* pThreadLocalStorage; +NSPR_API(void) _PR_MD_ENSURE_TLS(void); + +#define _MD_GET_ATTACHED_THREAD() pThreadLocalStorage->_pr_currentThread +extern struct PRThread * _MD_CURRENT_THREAD(void); +#define _MD_SET_CURRENT_THREAD(_thread) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_currentThread = (_thread) + +#define _MD_LAST_THREAD() pThreadLocalStorage->_pr_thread_last_run +#define _MD_SET_LAST_THREAD(_thread) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_thread_last_run = (_thread) + +#define _MD_CURRENT_CPU() pThreadLocalStorage->_pr_currentCPU +#define _MD_SET_CURRENT_CPU(_cpu) _PR_MD_ENSURE_TLS(); pThreadLocalStorage->_pr_currentCPU = (_cpu) + +/* lth. #define _MD_SET_INTSOFF(_val) (_pr_ints_off = (_val)) */ +/* lth. #define _MD_GET_INTSOFF() _pr_ints_off */ +/* lth. #define _MD_INCREMENT_INTSOFF() (_pr_ints_off++) */ +/* lth. #define _MD_DECREMENT_INTSOFF() (_pr_ints_off--) */ + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- not implemented on OS/2 */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* Some stuff for setting up thread contexts */ +typedef ULONG DWORD, *PDWORD; + +/* The following definitions and two structures are new in OS/2 Warp 4.0. + */ +#ifndef CONTEXT_CONTROL +#define CONTEXT_CONTROL 0x00000001 +#define CONTEXT_INTEGER 0x00000002 +#define CONTEXT_SEGMENTS 0x00000004 +#define CONTEXT_FLOATING_POINT 0x00000008 +#define CONTEXT_FULL 0x0000000F + +#pragma pack(2) +typedef struct _FPREG { + ULONG losig; /* Low 32-bits of the significand. */ + ULONG hisig; /* High 32-bits of the significand. */ + USHORT signexp; /* Sign and exponent. */ +} FPREG; +typedef struct _CONTEXTRECORD { + ULONG ContextFlags; + ULONG ctx_env[7]; + FPREG ctx_stack[8]; + ULONG ctx_SegGs; /* GS register. */ + ULONG ctx_SegFs; /* FS register. */ + ULONG ctx_SegEs; /* ES register. */ + ULONG ctx_SegDs; /* DS register. */ + ULONG ctx_RegEdi; /* EDI register. */ + ULONG ctx_RegEsi; /* ESI register. */ + ULONG ctx_RegEax; /* EAX register. */ + ULONG ctx_RegEbx; /* EBX register. */ + ULONG ctx_RegEcx; /* ECX register. */ + ULONG ctx_RegEdx; /* EDX register. */ + ULONG ctx_RegEbp; /* EBP register. */ + ULONG ctx_RegEip; /* EIP register. */ + ULONG ctx_SegCs; /* CS register. */ + ULONG ctx_EFlags; /* EFLAGS register. */ + ULONG ctx_RegEsp; /* ESP register. */ + ULONG ctx_SegSs; /* SS register. */ +} CONTEXTRECORD, *PCONTEXTRECORD; +#pragma pack() +#endif + +extern APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD); +unsigned long _System _DLL_InitTerm( unsigned long mod_handle, unsigned long flag); + +/* +#define _pr_tid (((PTIB2)_getTIBvalue(offsetof(TIB, tib_ptib2)))->tib2_ultid) +#define _pr_current_Thread (_system_tls[_pr_tid-1].__pr_current_thread) +*/ + +/* Some simple mappings of Windows API's to OS/2 API's to make our lives a + * little bit easier. Only add one here if it is a DIRECT mapping. We are + * not emulating anything. Just mapping. + */ +#define FreeLibrary(x) DosFreeModule((HMODULE)x) +#define OutputDebugString(x) + +extern int _MD_os2_get_nonblocking_connect_error(int osfd); + +#endif /* nspr_os2_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2_errors.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2_errors.h new file mode 100644 index 00000000..628b058a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_os2_errors.h @@ -0,0 +1,162 @@ +/* -*- 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_os2_errors_h___ +#define nspr_os2_errors_h___ + +#include "md/_os2.h" +#ifndef assert + #include +#endif + +NSPR_API(void) _MD_os2_map_default_error(PRInt32 err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_os2_map_default_error + +NSPR_API(void) _MD_os2_map_opendir_error(PRInt32 err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_os2_map_opendir_error + +NSPR_API(void) _MD_os2_map_closedir_error(PRInt32 err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_os2_map_closedir_error + +NSPR_API(void) _MD_os2_readdir_error(PRInt32 err); +#define _PR_MD_MAP_READDIR_ERROR _MD_os2_readdir_error + +NSPR_API(void) _MD_os2_map_delete_error(PRInt32 err); +#define _PR_MD_MAP_DELETE_ERROR _MD_os2_map_delete_error + +NSPR_API(void) _MD_os2_map_stat_error(PRInt32 err); +#define _PR_MD_MAP_STAT_ERROR _MD_os2_map_stat_error + +NSPR_API(void) _MD_os2_map_fstat_error(PRInt32 err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_os2_map_fstat_error + +NSPR_API(void) _MD_os2_map_rename_error(PRInt32 err); +#define _PR_MD_MAP_RENAME_ERROR _MD_os2_map_rename_error + +NSPR_API(void) _MD_os2_map_access_error(PRInt32 err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_os2_map_access_error + +NSPR_API(void) _MD_os2_map_mkdir_error(PRInt32 err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_os2_map_mkdir_error + +NSPR_API(void) _MD_os2_map_rmdir_error(PRInt32 err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_os2_map_rmdir_error + +NSPR_API(void) _MD_os2_map_read_error(PRInt32 err); +#define _PR_MD_MAP_READ_ERROR _MD_os2_map_read_error + +NSPR_API(void) _MD_os2_map_transmitfile_error(PRInt32 err); +#define _PR_MD_MAP_TRANSMITFILE_ERROR _MD_os2_map_transmitfile_error + +NSPR_API(void) _MD_os2_map_write_error(PRInt32 err); +#define _PR_MD_MAP_WRITE_ERROR _MD_os2_map_write_error + +NSPR_API(void) _MD_os2_map_lseek_error(PRInt32 err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_os2_map_lseek_error + +NSPR_API(void) _MD_os2_map_fsync_error(PRInt32 err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_os2_map_fsync_error + +NSPR_API(void) _MD_os2_map_close_error(PRInt32 err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_os2_map_close_error + +NSPR_API(void) _MD_os2_map_socket_error(PRInt32 err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_os2_map_socket_error + +NSPR_API(void) _MD_os2_map_recv_error(PRInt32 err); +#define _PR_MD_MAP_RECV_ERROR _MD_os2_map_recv_error + +NSPR_API(void) _MD_os2_map_recvfrom_error(PRInt32 err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_os2_map_recvfrom_error + +NSPR_API(void) _MD_os2_map_send_error(PRInt32 err); +#define _PR_MD_MAP_SEND_ERROR _MD_os2_map_send_error + +NSPR_API(void) _MD_os2_map_sendto_error(PRInt32 err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_os2_map_sendto_error + +NSPR_API(void) _MD_os2_map_writev_error(int err); +#define _PR_MD_MAP_WRITEV_ERROR _MD_os2_map_writev_error + +NSPR_API(void) _MD_os2_map_accept_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_os2_map_accept_error + +NSPR_API(void) _MD_os2_map_acceptex_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPTEX_ERROR _MD_os2_map_acceptex_error + +NSPR_API(void) _MD_os2_map_connect_error(PRInt32 err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_os2_map_connect_error + +NSPR_API(void) _MD_os2_map_bind_error(PRInt32 err); +#define _PR_MD_MAP_BIND_ERROR _MD_os2_map_bind_error + +NSPR_API(void) _MD_os2_map_listen_error(PRInt32 err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_os2_map_listen_error + +NSPR_API(void) _MD_os2_map_shutdown_error(PRInt32 err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_os2_map_shutdown_error + +#ifndef XP_OS2_VACPP +NSPR_API(void) _MD_os2_map_socketpair_error(int err); +#define _PR_MD_MAP_SOCKETPAIR_ERROR _MD_os2_map_socketpair_error +#endif + +NSPR_API(void) _MD_os2_map_getsockname_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_os2_map_getsockname_error + +NSPR_API(void) _MD_os2_map_getpeername_error(PRInt32 err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_os2_map_getpeername_error + +NSPR_API(void) _MD_os2_map_getsockopt_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_os2_map_getsockopt_error + +NSPR_API(void) _MD_os2_map_setsockopt_error(PRInt32 err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_os2_map_setsockopt_error + +NSPR_API(void) _MD_os2_map_open_error(PRInt32 err); +#define _PR_MD_MAP_OPEN_ERROR _MD_os2_map_open_error + +NSPR_API(void) _MD_os2_map_gethostname_error(PRInt32 err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_os2_map_gethostname_error + +NSPR_API(void) _MD_os2_map_select_error(PRInt32 err); +#define _PR_MD_MAP_SELECT_ERROR _MD_os2_map_select_error + +NSPR_API(void) _MD_os2_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_os2_map_lockf_error + +#endif /* nspr_os2_errors_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.cfg new file mode 100644 index 00000000..ac07b57c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.cfg @@ -0,0 +1,146 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef OSF1 +#define OSF1 +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS +#ifndef IS_64 +#define IS_64 +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 8 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.h new file mode 100644 index 00000000..9767b873 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_osf1.h @@ -0,0 +1,255 @@ +/* -*- 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_osf1_defs_h___ +#define nspr_osf1_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "osf" +#define _PR_SI_SYSNAME "OSF" +#define _PR_SI_ARCHITECTURE "alpha" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 131072L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define HAVE_BSD_FLOCK + +#define NEED_TIME_R +#define USE_DLFCN + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ONLY_ST_ATIME +#define _PR_HAVE_LARGE_OFF_T +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x00000002 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#define AI_V4MAPPED 0x00000010 +#define AI_ALL 0x00000008 +#define AI_ADDRCONFIG 0x00000020 +#endif +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY + +#define USE_SETJMP + +#include + +/* + * A jmp_buf is actually a struct sigcontext. The sc_sp field of + * struct sigcontext is the stack pointer. + */ +#define _MD_GET_SP(_t) (((struct sigcontext *) (_t)->md.context)->sc_sp) +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (long) ((_sp) - 64); \ + _MD_GET_SP(_thread) &= ~15; \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + jmp_buf context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +#include +extern int __select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT __select + +#include +#define _MD_POLL __poll +extern int __poll(struct pollfd filedes[], unsigned int nfds, int timeout); + +/* + * Atomic operations + */ +#ifdef OSF1_HAVE_MACHINE_BUILTINS_H +#include +#define _PR_HAVE_ATOMIC_OPS +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(val) (__ATOMIC_INCREMENT_LONG(val) + 1) +#define _MD_ATOMIC_ADD(ptr, val) (__ATOMIC_ADD_LONG(ptr, val) + val) +#define _MD_ATOMIC_DECREMENT(val) (__ATOMIC_DECREMENT_LONG(val) - 1) +#define _MD_ATOMIC_SET(val, newval) __ATOMIC_EXCH_LONG(val, newval) +#endif /* OSF1_HAVE_MACHINE_BUILTINS_H */ + +#endif /* nspr_osf1_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_pcos.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_pcos.h new file mode 100644 index 00000000..64bd8405 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_pcos.h @@ -0,0 +1,89 @@ +/* -*- 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 prpcos_h___ +#define prpcos_h___ + +#define PR_DLL_SUFFIX ".dll" + +#include + +#define DIRECTORY_SEPARATOR '\\' +#define DIRECTORY_SEPARATOR_STR "\\" +#define PATH_SEPARATOR ';' + +#ifdef WIN16 +#define GCPTR __far +#else +#define GCPTR +#endif + +/* +** Routines for processing command line arguments +*/ +PR_BEGIN_EXTERN_C +#ifndef XP_OS2_EMX +extern char *optarg; +extern int optind; +extern int getopt(int argc, char **argv, char *spec); +#endif +PR_END_EXTERN_C + + +/* +** Definitions of directory structures amd functions +** These definitions are from: +** +*/ +#ifdef XP_OS2_EMX +#include +#endif +#include +#include +#include /* O_BINARY */ + +#ifdef OS2 +extern PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_OS2GetHostName +#else +extern PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_WindowsGetHostName +extern PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _MD_GETSYSINFO _MD_WindowsGetSysInfo +#endif + +#endif /* prpcos_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_pth.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_pth.h new file mode 100644 index 00000000..34ccf713 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_pth.h @@ -0,0 +1,298 @@ +/* -*- 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_pth_defs_h_ +#define nspr_pth_defs_h_ + +/* +** Appropriate definitions of entry points not used in a pthreads world +*/ +#define _PR_MD_BLOCK_CLOCK_INTERRUPTS() +#define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _PR_MD_DISABLE_CLOCK_INTERRUPTS() +#define _PR_MD_ENABLE_CLOCK_INTERRUPTS() + +/* In good standards fashion, the DCE threads (based on posix-4) are not + * quite the same as newer posix implementations. These are mostly name + * changes and small differences, so macros usually do the trick + */ +#ifdef _PR_DCETHREADS +#define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_create +#define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_delete +#define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), a) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (0 == pthread_mutex_trylock(&(m))) +#define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_create +#define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), a) +#define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_delete + +/* Notes about differences between DCE threads and pthreads 10: + * 1. pthread_mutex_trylock returns 1 when it locks the mutex + * 0 when it does not. The latest pthreads has a set of errno-like + * return values. + * 2. return values from pthread_cond_timedwait are different. + * + * + * + */ +#elif defined(BSDI) +/* + * Mutex and condition attributes are not supported. The attr + * argument to pthread_mutex_init() and pthread_cond_init() must + * be passed as NULL. + * + * The memset calls in _PT_PTHREAD_MUTEX_INIT and _PT_PTHREAD_COND_INIT + * are to work around BSDI's using a single bit to indicate a mutex + * or condition variable is initialized. This entire BSDI section + * will go away when BSDI releases updated threads libraries for + * BSD/OS 3.1 and 4.0. + */ +#define _PT_PTHREAD_MUTEXATTR_INIT(x) 0 +#define _PT_PTHREAD_MUTEXATTR_DESTROY(x) /* */ +#define _PT_PTHREAD_MUTEX_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ + pthread_mutex_init(&(m), NULL)) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) +#define _PT_PTHREAD_CONDATTR_INIT(x) 0 +#define _PT_PTHREAD_CONDATTR_DESTROY(x) /* */ +#define _PT_PTHREAD_COND_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ + pthread_cond_init(&(m), NULL)) +#else +#define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_init +#define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_destroy +#define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), &(a)) +#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) +#if defined(DARWIN) +#define _PT_PTHREAD_CONDATTR_INIT(x) 0 +#else +#define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_init +#endif +#define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_destroy +#define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), &(a)) +#endif + +/* The pthreads standard does not specify an invalid value for the + * pthread_t handle. (0 is usually an invalid pthread identifier + * but there are exceptions, for example, DG/UX.) These macros + * define a way to set the handle to or compare the handle with an + * invalid identifier. These macros are not portable and may be + * more of a problem as we adapt to more pthreads implementations. + * They are only used in the PRMonitor functions. Do not use them + * in new code. + * + * Unfortunately some of our clients depend on certain properties + * of our PRMonitor implementation, preventing us from replacing + * it by a portable implementation. + * - High-performance servers like the fact that PR_EnterMonitor + * only calls PR_Lock and PR_ExitMonitor only calls PR_Unlock. + * (A portable implementation would use a PRLock and a PRCondVar + * to implement the recursive lock in a monitor and call both + * PR_Lock and PR_Unlock in PR_EnterMonitor and PR_ExitMonitor.) + * Unfortunately this forces us to read the monitor owner field + * without holding a lock. + * - One way to make it safe to read the monitor owner field + * without holding a lock is to make that field a PRThread* + * (one should be able to read a pointer with a single machine + * instruction). However, PR_GetCurrentThread calls calloc if + * it is called by a thread that was not created by NSPR. The + * malloc tracing tools in the Mozilla client use PRMonitor for + * locking in their malloc, calloc, and free functions. If + * PR_EnterMonitor calls any of these functions, infinite + * recursion ensues. + */ +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) \ + memset(&(t), 0, sizeof(pthread_t)) +#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) \ + (!memcmp(&(t), &pt_zero_tid, sizeof(pthread_t))) +#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) +#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \ + || defined(HPUX) || defined(LINUX) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) || defined(BSDI) \ + || defined(VMS) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) +#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) (t) = 0 +#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) (t) == 0 +#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) +#else +#error "pthreads is not supported for this architecture" +#endif + +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_ATTR_INIT pthread_attr_create +#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_delete +#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, a, f, r) +#define _PT_PTHREAD_KEY_CREATE pthread_keycreate +#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setsched +#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) \ + (*(s) = pthread_attr_getstacksize(*(a)), 0) +#define _PT_PTHREAD_GETSPECIFIC(k, r) \ + pthread_getspecific((k), (pthread_addr_t *) &(r)) +#elif defined(_PR_PTHREADS) +#define _PT_PTHREAD_ATTR_INIT pthread_attr_init +#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_destroy +#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, &a, f, r) +#define _PT_PTHREAD_KEY_CREATE pthread_key_create +#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setschedpolicy +#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) pthread_attr_getstacksize(a, s) +#define _PT_PTHREAD_GETSPECIFIC(k, r) (r) = pthread_getspecific(k) +#else +#error "Cannot determine pthread strategy" +#endif + +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_EXPLICIT_SCHED _PT_PTHREAD_DEFAULT_SCHED +#endif + +/* + * pthread_mutex_trylock returns different values in DCE threads and + * pthreads. + */ +#if defined(_PR_DCETHREADS) +#define PT_TRYLOCK_SUCCESS 1 +#define PT_TRYLOCK_BUSY 0 +#else +#define PT_TRYLOCK_SUCCESS 0 +#define PT_TRYLOCK_BUSY EBUSY +#endif + +/* + * These platforms don't have sigtimedwait() + */ +#if (defined(AIX) && !defined(AIX4_3_PLUS)) || defined(LINUX) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(VMS) || defined(UNIXWARE) \ + || defined(DARWIN) +#define PT_NO_SIGTIMEDWAIT +#endif + +/* + * These platforms don't have pthread_kill() + */ +#if defined(DARWIN) && !defined(_DARWIN_FEATURE_UNIX_CONFORMANCE) +#define pthread_kill(thread, sig) ENOSYS +#endif + +#if defined(OSF1) || defined(VMS) +#define PT_PRIO_MIN PRI_OTHER_MIN +#define PT_PRIO_MAX PRI_OTHER_MAX +#elif defined(IRIX) +#include +#define PT_PRIO_MIN PX_PRIO_MIN +#define PT_PRIO_MAX PX_PRIO_MAX +#elif defined(AIX) +#include +#include +#ifndef PTHREAD_CREATE_JOINABLE +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED +#endif +#define PT_PRIO_MIN DEFAULT_PRIO +#define PT_PRIO_MAX DEFAULT_PRIO +#elif defined(HPUX) + +#if defined(_PR_DCETHREADS) +#define PT_PRIO_MIN PRI_OTHER_MIN +#define PT_PRIO_MAX PRI_OTHER_MAX +#else /* defined(_PR_DCETHREADS) */ +#include +#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) +#define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) +#endif /* defined(_PR_DCETHREADS) */ + +#elif defined(LINUX) || defined(FREEBSD) +#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) +#define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) +#elif defined(NTO) +/* + * Neutrino has functions that return the priority range but + * they return invalid numbers, so I just hard coded these here + * for now. Jerry.Kirk@Nexarecorp.com + */ +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 30 +#elif defined(SOLARIS) +/* + * Solaris doesn't seem to have macros for the min/max priorities. + * The range of 0-127 is mentioned in the pthread_setschedparam(3T) + * man pages, and pthread_setschedparam indeed allows 0-127. However, + * pthread_attr_setschedparam does not allow 0; it allows 1-127. + */ +#define PT_PRIO_MIN 1 +#define PT_PRIO_MAX 127 +#elif defined(OPENBSD) +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 31 +#elif defined(NETBSD) \ + || defined(BSDI) || defined(DARWIN) || defined(UNIXWARE) /* XXX */ +#define PT_PRIO_MIN 0 +#define PT_PRIO_MAX 126 +#else +#error "pthreads is not supported for this architecture" +#endif + +/* + * The _PT_PTHREAD_YIELD function is called from a signal handler. + * Needed for garbage collection -- Look at PR_Suspend/PR_Resume + * implementation. + */ +#if defined(_PR_DCETHREADS) +#define _PT_PTHREAD_YIELD() pthread_yield() +#elif defined(OSF1) || defined(VMS) +/* + * sched_yield can't be called from a signal handler. Must use + * the _np version. + */ +#define _PT_PTHREAD_YIELD() pthread_yield_np() +#elif defined(AIX) +extern int (*_PT_aix_yield_fcn)(); +#define _PT_PTHREAD_YIELD() (*_PT_aix_yield_fcn)() +#elif defined(IRIX) +#include +#define _PT_PTHREAD_YIELD() \ + PR_BEGIN_MACRO \ + struct timespec onemillisec = {0}; \ + onemillisec.tv_nsec = 1000000L; \ + nanosleep(&onemillisec,NULL); \ + PR_END_MACRO +#elif defined(HPUX) || defined(LINUX) || defined(SOLARIS) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) +#define _PT_PTHREAD_YIELD() sched_yield() +#else +#error "Need to define _PT_PTHREAD_YIELD for this platform" +#endif + +#endif /* nspr_pth_defs_h_ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.cfg new file mode 100644 index 00000000..7c5fc3e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.cfg @@ -0,0 +1,96 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef QNX +#define QNX +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 1 +#define PR_ALIGN_OF_INT 1 +#define PR_ALIGN_OF_LONG 1 +#define PR_ALIGN_OF_INT64 1 +#define PR_ALIGN_OF_FLOAT 1 +#define PR_ALIGN_OF_DOUBLE 1 +#define PR_ALIGN_OF_POINTER 1 +#define PR_ALIGN_OF_WORD 1 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 + +#endif /* nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.h new file mode 100644 index 00000000..f7593c6a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_qnx.h @@ -0,0 +1,215 @@ +/* -*- 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_qnx_defs_h___ +#define nspr_qnx_defs_h___ + +/* +** Internal configuration macros +*/ +#define PR_LINKER_ARCH "qnx" +#define _PR_SI_SYSNAME "QNX" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef _PR_POLL_AVAILABLE +#undef _PR_USE_POLL +#define _PR_HAVE_SOCKADDR_LEN +#define HAVE_BSD_FLOCK +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#include + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_DLL +#undef USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR +#endif + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _PR_NUM_GCREGS _JBLEN +#define _MD_GET_SP(_t) (_t)->md.context[7] + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* +** Machine-dependent (MD) data structures. +*/ +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* +** md-specific cpu structure field +*/ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD], fd_write_cnt[_PR_MD_MAX_OSFD], fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* +** We wrapped the select() call. _MD_SELECT refers to the built-in, +** unwrapped version. +*/ +#include +#include +#include +#define _MD_SELECT select + +#define SA_RESTART 0 + +#endif /* nspr_qnx_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.cfg new file mode 100644 index 00000000..f2913d18 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.cfg @@ -0,0 +1,145 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef RELIANTUNIX +#define RELIANTUNIX +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 +#define PR_WORDS_PER_DWORD_LOG2 1 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.h new file mode 100644 index 00000000..a924e2f9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_reliantunix.h @@ -0,0 +1,270 @@ +/* -*- 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 ***** */ + +/* + * reliantunix.h + * 5/18/96 Taken from nec.h -- chrisk@netscape.com + * 3/14/97 Modified for nspr20 -- chrisk@netscape.com + */ +#ifndef nspr_reliantunix_defs_h___ +#define nspr_reliantunix_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "sinix" +#define _PR_SI_SYSNAME "SINIX" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_PRIVATE|MAP_FIXED + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define HAVE_NETCONFIG +#define HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_MALLOC_SYMBOLS +#define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM +#define _PR_NO_LARGE_FILES + +/* + * Mike Patnode indicated that it is possibly safe now to use context-switching + * calls that do not change the signal mask, like setjmp vs. sigsetjmp. + * So we'll use our homegrown, getcontext/setcontext-compatible stuff which + * will save us the getcontext/setcontext system calls at each context switch. + * It already works in FastTrack 2.01, so it should do it here :-) + * - chrisk 040497 + */ +#define USE_SETCXT /* temporarily disabled... */ + +#include + +#ifdef USE_SETCXT +/* use non-syscall machine language replacement */ +#define _GETCONTEXT getcxt +#define _SETCONTEXT setcxt +/* defined in os_ReliantUNIX.s */ +extern int getcxt(ucontext_t *); +extern int setcxt(ucontext_t *); +#else +#define _GETCONTEXT getcontext +#define _SETCONTEXT setcontext +#endif + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gpregs[CXT_SP] +#define _PR_CONTEXT_TYPE ucontext_t +#define _PR_NUM_GCREGS NGREG + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 0 + +/* +** Machine-dependent (MD) data structures. +*/ +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* +** Initialize the thread context preparing it to execute "_main()" +** - get a nice, fresh context +** - set its SP to the stack we allcoated for it +** - set it to start things at "e" +*/ +#define _MD_INIT_CONTEXT(thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + _GETCONTEXT(CONTEXT(thread)); \ + /* this is supposed to point to the stack BASE, not to SP */ \ + CONTEXT(thread)->uc_stack.ss_sp = thread->stack->stackBottom; \ + CONTEXT(thread)->uc_stack.ss_size = thread->stack->stackSize; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_SP] = ((unsigned long)_sp - 128) & 0xfffffff8; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_T9] = _main; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_EPC] = _main; \ + CONTEXT(thread)->uc_mcontext.gpregs[CXT_RA] = 0; \ + thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Save current context as it is scheduled away +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + if (!_GETCONTEXT(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread); \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT or set up +** by _MD_INIT_CONTEXT +** CXT_V0 is the register that holds the return value. +** We must set it to 1 so that we can see if the return from +** getcontext() is the result of calling getcontext() or +** setcontext()... +** setting a context got with getcontext() appears to +** return from getcontext(), too! +** CXT_A3 is the register that holds status when returning +** from a syscall. It is set to 0 to indicate success, +** because we want getcontext() on the other side of the magic +** door to be ok. +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gpregs[CXT_V0] = 1;\ + uc->uc_mcontext.gpregs[CXT_A3] = 0;\ + _MD_RESTORE_ERRNO(_thread); \ + _MD_SET_CURRENT_THREAD(_thread); \ + _SETCONTEXT(uc); \ + PR_END_MACRO + +#define _MD_SAVE_ERRNO(t) (t)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(t) errno = (t)->md.errcode; + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#if !defined(S_ISSOCK) && defined(S_IFSOCK) +#define S_ISSOCK(mode) ((mode&0xF000) == 0xC000) +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +#define S_ISLNK(mode) ((mode&0xA000) == 0xC000) +#endif + +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT(nfds,r,w,e,tv) _select(nfds,r,w,e,tv) +#define _MD_POLL _poll + +#endif /* nspr_reliantunix_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.cfg new file mode 100644 index 00000000..b79e2503 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.cfg @@ -0,0 +1,148 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef RHAPOSDY +#define RHAPOSDY +#endif + +#define PR_AF_INET6 30 /* same as AF_INET6 */ + +#if defined(i386) +#undef IS_BIG_ENDIAN +#define IS_LITTLE_ENDIAN 1 +#else +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#endif + +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#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___ */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.h new file mode 100644 index 00000000..fa9903ed --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_rhapsody.h @@ -0,0 +1,225 @@ +/* -*- 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_rhapsody_defs_h___ +#define nspr_rhapsody_defs_h___ + +#include "prthread.h" + +#include + +#define PR_LINKER_ARCH "rhapsody" +#define _PR_SI_SYSNAME "RHAPSODY" +#ifdef i386 +#define _PR_SI_ARCHITECTURE "x86" +#else +#define _PR_SI_ARCHITECTURE "ppc" +#endif +#define PR_DLL_SUFFIX ".dylib" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_MACH_DYLD +#define _PR_HAVE_SOCKADDR_LEN +#define _PR_STAT_HAS_ST_ATIMESPEC +#define _PR_NO_LARGE_FILES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY + +#define USE_SETJMP + +#if !defined(_PR_PTHREADS) + +#include + +#define PR_CONTEXT_TYPE jmp_buf + +#define CONTEXT(_th) ((_th)->md.context) +#define _MD_GET_SP(_th) (((struct sigcontext *) (_th)->md.context)->sc_onstack) +#define PR_NUM_GCREGS _JBLEN + +/* +** Initialize a thread context to run "_main()" when started +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) { \ + _main(); \ + } \ + _MD_GET_SP(_thread) = (unsigned char*) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +extern PRStatus _MD_InitializeThread(PRThread *thread); + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) _MD_suspend_thread +#define _MD_RESUME_THREAD(thread) _MD_resume_thread +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, PRUintn newPri); +extern PRStatus _MD_WAIT(PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(PRThread *); +extern void _MD_YIELD(void); + +#endif /* ! _PR_PTHREADS */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +extern void _MD_EarlyInit(void); +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) + +/* For writev() */ +#include + +#endif /* nspr_rhapsody_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.cfg new file mode 100644 index 00000000..d7c461ff --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.cfg @@ -0,0 +1,140 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef SCO +#define SCO +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.h new file mode 100644 index 00000000..6efaa7ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_scoos.h @@ -0,0 +1,204 @@ +/* -*- 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_scoos5_defs_h___ +#define nspr_scoos5_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "scoos5" +#define PR_DLL_SUFFIX ".so" + +#define _PR_SI_SYSNAME "SCO" +#define _PR_SI_ARCHITECTURE "x86" +#define _PR_STACK_VMBASE 0x50000000 + +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN + +#if !defined (HAVE_STRERROR) +#define HAVE_STRERROR +#endif + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_RECV_BROKEN /* recv doesn't work on Unix Domain Sockets */ + +#define USE_SETJMP + +#ifdef _PR_LOCAL_THREADS_ONLY +#include + +#define _MD_GET_SP(_t) (_t)->md.jb[4] +#define PR_NUM_GCREGS _SIGJBLEN +#define PR_CONTEXT_TYPE sigjmp_buf + +#define CONTEXT(_th) ((_th)->md.jb) + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if (sigsetjmp(CONTEXT(_thread),1)) { \ + (*_main)(); \ + } \ + _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!sigsetjmp(CONTEXT(_thread), 1)) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->osErrorCode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + siglongjmp(CONTEXT(_thread), 1); \ +} + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +struct _MDThread { + jmp_buf jb; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_SELECT _select +#define _MD_POLL _poll + +#endif /* nspr_scoos5_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris.h new file mode 100644 index 00000000..8f9d121e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris.h @@ -0,0 +1,832 @@ +/* -*- 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_solaris_defs_h___ +#define nspr_solaris_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "solaris" +#define _PR_SI_SYSNAME "SOLARIS" +#ifdef sparc +#define _PR_SI_ARCHITECTURE "sparc" +#elif defined(i386) +#define _PR_SI_ARCHITECTURE "x86" +#elif defined(__x86_64) +#define _PR_SI_ARCHITECTURE "x86-64" +#else +#error unknown processor +#endif +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE (2*65536L) +#define _MD_MMAP_FLAGS MAP_SHARED + +#undef HAVE_STACK_GROWING_UP + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif + +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK + +#if defined(_LARGEFILE64_SOURCE) /* vbox */ +#define _PR_HAVE_OFF64_T /* vbox */ +#elif defined(_LP64) || _FILE_OFFSET_BITS == 32 /* vbox */ +#define _PR_HAVE_LARGE_OFF_T /* vbox */ +#else /* vbox */ +#define _PR_NO_LARGE_FILES /* vbox */ +#endif /* vbox */ + + +/* + * Intel x86 has atomic instructions. + * + * Sparc v8 does not have instructions to efficiently implement + * atomic increment/decrement operations. In the local threads + * only and pthreads versions, we use the default atomic routine + * implementation in pratom.c. The obsolete global threads only + * version uses a global mutex_t to implement the atomic routines + * in solaris.c, which is actually equivalent to the default + * implementation. + * + * 64-bit Solaris requires sparc v9, which has atomic instructions. + */ +#if defined(i386) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(IS_64) +#define _PR_HAVE_ATOMIC_OPS +#endif + +#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS) +/* + * We have assembly language implementation of atomic + * stacks for the 32-bit sparc and x86 architectures only. + * + * Note: We ran into thread starvation problem with the + * 32-bit sparc assembly language implementation of atomic + * stacks, so we do not use it now. (Bugzilla bug 113740) + */ +#if !defined(sparc) && !defined(__x86_64) +#define _PR_HAVE_ATOMIC_CAS +#endif +#endif + +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM +#ifdef SOLARIS2_5 +#define _PR_HAVE_SYSV_SEMAPHORES +#define PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#else +#define _PR_HAVE_POSIX_SEMAPHORES +#define PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#endif +#define _PR_HAVE_GETIPNODEBYNAME +#define _PR_HAVE_GETIPNODEBYADDR +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#define _PR_ACCEPT_INHERIT_NONBLOCK +#if !defined(_XPG4_2) || defined(_XPG6) || defined(__EXTENSIONS__) /* vbox */ +#define _PR_INET6 /* vbox */ +#endif /* vbox */ +#ifdef _PR_INET6 +#define _PR_HAVE_INET_NTOP +#else +#define AF_INET6 26 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#define AI_CANONNAME 0x0010 +#define AI_V4MAPPED 0x0001 +#define AI_ALL 0x0002 +#define AI_ADDRCONFIG 0x0004 +#define _PR_HAVE_MD_SOCKADDR_IN6 +/* isomorphic to struct in6_addr on Solaris 8 */ +struct _md_in6_addr { + union { + PRUint8 _S6_u8[16]; + PRUint32 _S6_u32[4]; + PRUint32 __S6_align; + } _S6_un; +}; +/* isomorphic to struct sockaddr_in6 on Solaris 8 */ +struct _md_sockaddr_in6 { + PRUint16 sin6_family; + PRUint16 sin6_port; + PRUint32 sin6_flowinfo; + struct _md_in6_addr sin6_addr; + PRUint32 sin6_scope_id; + PRUint32 __sin6_src_id; +}; +#endif +#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_PTHREADS) +#define _PR_HAVE_GETHOST_R +#define _PR_HAVE_GETHOST_R_POINTER +#endif + +#include "prinrval.h" +NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void); +#define _MD_GET_INTERVAL _MD_Solaris_GetInterval +NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); +#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond + +#if defined(_PR_HAVE_ATOMIC_OPS) +/* +** Atomic Operations +*/ +#define _MD_INIT_ATOMIC() + +NSPR_API(PRInt32) _MD_AtomicIncrement(PRInt32 *val); +#define _MD_ATOMIC_INCREMENT _MD_AtomicIncrement + +NSPR_API(PRInt32) _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val); +#define _MD_ATOMIC_ADD _MD_AtomicAdd + +NSPR_API(PRInt32) _MD_AtomicDecrement(PRInt32 *val); +#define _MD_ATOMIC_DECREMENT _MD_AtomicDecrement + +NSPR_API(PRInt32) _MD_AtomicSet(PRInt32 *val, PRInt32 newval); +#define _MD_ATOMIC_SET _MD_AtomicSet +#endif /* _PR_HAVE_ATOMIC_OPS */ + +#if defined(_PR_PTHREADS) + +NSPR_API(void) _MD_EarlyInit(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#elif defined(_PR_GLOBAL_THREADS_ONLY) + +#include "prthread.h" + +#include + +/* +** Iinitialization Related definitions +*/ + +NSPR_API(void) _MD_EarlyInit(void); + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit + +#define _MD_GET_SP(threadp) threadp->md.sp + +/* +** Clean-up the thread machine dependent data structure +*/ +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_INIT_ATTACHED_THREAD _MD_InitializeThread + +NSPR_API(PRStatus) _MD_CreateThread(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _MD_CREATE_THREAD _MD_CreateThread + +#define _PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#include +#include +#include + +extern struct PRLock *_pr_schedLock; + +/* +** Thread Local Storage +*/ + +#define THREAD_KEY_T thread_key_t + +extern struct PRThread *_pr_attached_thread_tls(); +extern struct PRThread *_pr_current_thread_tls(); +extern struct _PRCPU *_pr_current_cpu_tls(); +extern struct PRThread *_pr_last_thread_tls(); + +extern THREAD_KEY_T threadid_key; +extern THREAD_KEY_T cpuid_key; +extern THREAD_KEY_T last_thread_key; + +#define _MD_GET_ATTACHED_THREAD() _pr_attached_thread_tls() +#define _MD_CURRENT_THREAD() _pr_current_thread_tls() +#define _MD_CURRENT_CPU() _pr_current_cpu_tls() +#define _MD_LAST_THREAD() _pr_last_thread_tls() + +#define _MD_SET_CURRENT_THREAD(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(threadid_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_SET_CURRENT_CPU(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(cpuid_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_SET_LAST_THREAD(newval) \ + PR_BEGIN_MACRO \ + thr_setspecific(last_thread_key, (void *)newval); \ + PR_END_MACRO + +#define _MD_CLEAN_THREAD(_thread) _MD_cleanup_thread(_thread) +extern void _MD_exit_thread(PRThread *thread); +#define _MD_EXIT_THREAD(thread) _MD_exit_thread(thread) + +#define _MD_SUSPEND_THREAD(thread) _MD_Suspend(thread) +#define _MD_RESUME_THREAD(thread) thr_continue((thread)->md.handle) + +/* XXXX Needs to be defined - Prashant */ +#define _MD_SUSPEND_CPU(cpu) +#define _MD_RESUME_CPU(cpu) + +extern void _MD_Begin_SuspendAll(void); +extern void _MD_End_SuspendAll(void); +extern void _MD_End_ResumeAll(void); +#define _MD_BEGIN_SUSPEND_ALL() _MD_Begin_SuspendAll() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() _MD_End_SuspendAll() +#define _MD_END_RESUME_ALL() _MD_End_ResumeAll() + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(md_lockp) (mutex_init(&((md_lockp)->lock),USYNC_THREAD,NULL) ? PR_FAILURE : PR_SUCCESS) +#define _MD_FREE_LOCK(md_lockp) mutex_destroy(&((md_lockp)->lock)) +#define _MD_UNLOCK(md_lockp) mutex_unlock(&((md_lockp)->lock)) +#define _MD_TEST_AND_LOCK(md_lockp) mutex_trylock(&((md_lockp)->lock)) +struct _MDLock; +NSPR_API(void) _MD_lock(struct _MDLock *md_lock); +#undef PROFILE_LOCKS +#ifndef PROFILE_LOCKS +#define _MD_LOCK(md_lockp) _MD_lock(md_lockp) +#else +#define _MD_LOCK(md_lockp) \ + PR_BEGIN_MACRO \ + int rv = _MD_TEST_AND_LOCK(md_lockp); \ + if (rv == 0) { \ + (md_lockp)->hitcount++; \ + } else { \ + (md_lockp)->misscount++; \ + _MD_lock(md_lockp); \ + } \ + PR_END_MACRO +#endif + +#define _PR_LOCK_HEAP() if (_pr_heapLock) _MD_LOCK(&_pr_heapLock->md) +#define _PR_UNLOCK_HEAP() if (_pr_heapLock) _MD_UNLOCK(&_pr_heapLock->md) + +#define _MD_ATTACH_THREAD(threadp) + + +#define THR_KEYCREATE thr_keycreate +#define THR_SELF thr_self +#define _MD_NEW_CV(condp) cond_init(&((condp)->cv), USYNC_THREAD, 0) +#define COND_WAIT(condp, mutexp) cond_wait(condp, mutexp) +#define COND_TIMEDWAIT(condp, mutexp, tspec) \ + cond_timedwait(condp, mutexp, tspec) +#define _MD_NOTIFY_CV(condp, lockp) cond_signal(&((condp)->cv)) +#define _MD_NOTIFYALL_CV(condp,unused) cond_broadcast(&((condp)->cv)) +#define _MD_FREE_CV(condp) cond_destroy(&((condp)->cv)) +#define _MD_YIELD() thr_yield() +#include +/* + * Because clock_gettime() on Solaris/x86 2.4 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ +#if defined(i386) && defined(SOLARIS2_4) +extern int _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp); +#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt)) +#else +#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt)) +#endif /* i386 && SOLARIS2_4 */ + +#define MUTEX_T mutex_t +#define COND_T cond_t + +#define _MD_NEW_SEM(md_semp,_val) sema_init(&((md_semp)->sem),_val,USYNC_THREAD,NULL) +#define _MD_DESTROY_SEM(md_semp) sema_destroy(&((md_semp)->sem)) +#define _MD_WAIT_SEM(md_semp) sema_wait(&((md_semp)->sem)) +#define _MD_POST_SEM(md_semp) sema_post(&((md_semp)->sem)) + +#define _MD_SAVE_ERRNO(_thread) +#define _MD_RESTORE_ERRNO(_thread) +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) + +extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() _MD_LOCK(&_pr_ioq_lock) +#define _MD_IOQ_UNLOCK() _MD_UNLOCK(&_pr_ioq_lock) + +extern PRStatus _MD_wait(struct PRThread *, PRIntervalTime timeout); +#define _MD_WAIT _MD_wait + +extern PRStatus _MD_WakeupWaiter(struct PRThread *); +#define _MD_WAKEUP_WAITER _MD_WakeupWaiter + +NSPR_API(void) _MD_InitIO(void); +#define _MD_INIT_IO _MD_InitIO + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT(_thread) +#define _MD_RESTORE_CONTEXT(_newThread) + +struct _MDLock { + MUTEX_T lock; +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDCVar { + COND_T cv; +}; + +struct _MDSemaphore { + sema_t sem; +}; + +struct _MDThread { + _PR_CONTEXT_TYPE context; + thread_t handle; + lwpid_t lwpid; + uint_t sp; /* stack pointer */ + uint_t threadID; /* ptr to solaris-internal thread id structures */ + struct _MDSemaphore waiter_sem; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field, common to all Unix platforms + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +/* The following defines the unwrapped versions of select() and poll(). */ +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +PR_BEGIN_EXTERN_C + +/* +** Missing function prototypes +*/ +extern int gethostname (char *name, int namelen); + +PR_END_EXTERN_C + +#else /* _PR_GLOBAL_THREADS_ONLY */ + +/* + * LOCAL_THREADS_ONLY implementation on Solaris + */ + +#include "prthread.h" + +#include +#include +#include +#include + +/* +** Iinitialization Related definitions +*/ + +NSPR_API(void) _MD_EarlyInit(void); +NSPR_API(void) _MD_SolarisInit(); +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _MD_SolarisInit +#define _MD_INIT_THREAD _MD_InitializeThread + +#ifdef USE_SETJMP + +#include + +#define _PR_CONTEXT_TYPE jmp_buf + +#ifdef sparc +#define _MD_GET_SP(_t) (_t)->md.context[2] +#else +#define _MD_GET_SP(_t) (_t)->md.context[4] +#endif + +#define PR_NUM_GCREGS _JBLEN +#define CONTEXT(_thread) (_thread)->md.context + +#else /* ! USE_SETJMP */ + +#ifdef sparc +#define _PR_CONTEXT_TYPE ucontext_t +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[REG_SP] +/* +** Sparc's use register windows. the _MD_GetRegisters for the sparc's +** doesn't actually store anything into the argument buffer; instead the +** register windows are homed to the stack. I assume that the stack +** always has room for the registers to spill to... +*/ +#define PR_NUM_GCREGS 0 +#else +#define _PR_CONTEXT_TYPE unsigned int edi; sigset_t oldMask, blockMask; ucontext_t +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[USP] +#define PR_NUM_GCREGS _JBLEN +#endif + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#endif /* ! USE_SETJMP */ + +#include +/* + * Because clock_gettime() on Solaris/x86 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ +#ifdef i386 +#define GETTIME(tt) _pr_solx86_clock_gettime(CLOCK_REALTIME, (tt)) +#else +#define GETTIME(tt) clock_gettime(CLOCK_REALTIME, (tt)) +#endif /* i386 */ + +#define _MD_SAVE_ERRNO(_thread) (_thread)->md.errcode = errno; +#define _MD_RESTORE_ERRNO(_thread) errno = (_thread)->md.errcode; + +#ifdef sparc + +#ifdef USE_SETJMP +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *context = (_thread)->md.context; \ + *status = PR_TRUE; \ + (void) setjmp(context); \ + (_thread)->md.context[1] = (int) ((_sp) - 64); \ + (_thread)->md.context[2] = (int) _main; \ + (_thread)->md.context[3] = (int) _main + 4; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _MD_SET_CURRENT_THREAD(_thread); \ + _PR_Schedule(); \ + } + +#define _MD_RESTORE_CONTEXT(_newThread) \ +{ \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + longjmp(CONTEXT(_newThread), 1); \ +} + +#else +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + *status = PR_TRUE; \ + getcontext(uc); \ + uc->uc_stack.ss_sp = (char *) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ + uc->uc_stack.ss_size = _thread->stack->stackSize; \ + uc->uc_stack.ss_flags = 0; /* ? */ \ + uc->uc_mcontext.gregs[REG_SP] = (unsigned int) uc->uc_stack.ss_sp; \ + uc->uc_mcontext.gregs[REG_PC] = (unsigned int) _main; \ + uc->uc_mcontext.gregs[REG_nPC] = (unsigned int) ((char*)_main)+4; \ + uc->uc_flags = UC_ALL; \ + _thread->no_sched = 0; \ + PR_END_MACRO + +/* +** Switch away from the current thread context by saving its state and +** calling the thread scheduler. Reload cpu when we come back from the +** context switch because it might have changed. +*/ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + if (!getcontext(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread); \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } \ + PR_END_MACRO + +/* +** Restore a thread context that was saved by _MD_SWITCH_CONTEXT or +** initialized by _MD_INIT_CONTEXT. +*/ +#define _MD_RESTORE_CONTEXT(_newThread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_newThread); \ + uc->uc_mcontext.gregs[11] = 1; \ + _MD_RESTORE_ERRNO(_newThread); \ + _MD_SET_CURRENT_THREAD(_newThread); \ + setcontext(uc); \ + PR_END_MACRO +#endif + +#else /* x86 solaris */ + +#ifdef USE_SETJMP + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + if (setjmp(CONTEXT(_thread))) _main(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 64); \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!setjmp(CONTEXT(_thread))) { \ + _MD_SAVE_ERRNO(_thread) \ + _PR_Schedule(); \ + } + +#define _MD_RESTORE_CONTEXT(_newThread) \ +{ \ + _MD_RESTORE_ERRNO(_newThread) \ + _MD_SET_CURRENT_THREAD(_newThread); \ + longjmp(CONTEXT(_newThread), 1); \ +} + +#else /* USE_SETJMP */ + +#define WINDOWSIZE 0 + +int getedi(void); +void setedi(int); + +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + *status = PR_TRUE; \ + getcontext(uc); \ + /* Force sp to be double aligned! */ \ + uc->uc_mcontext.gregs[USP] = (int) ((unsigned long)(_sp - WINDOWSIZE - SA(MINFRAME)) & 0xfffffff8); \ + uc->uc_mcontext.gregs[PC] = (int) _main; \ + (_thread)->no_sched = 0; \ + PR_END_MACRO + +/* getcontext() may return 1, contrary to what the man page says */ +#define _MD_SWITCH_CONTEXT(_thread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_thread); \ + PR_ASSERT(_thread->no_sched); \ + sigfillset(&((_thread)->md.blockMask)); \ + sigprocmask(SIG_BLOCK, &((_thread)->md.blockMask), \ + &((_thread)->md.oldMask)); \ + (_thread)->md.edi = getedi(); \ + if (! getcontext(uc)) { \ + sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ + uc->uc_mcontext.gregs[EDI] = (_thread)->md.edi; \ + _MD_SAVE_ERRNO(_thread) \ + _MD_SET_LAST_THREAD(_thread); \ + _PR_Schedule(); \ + } else { \ + sigprocmask(SIG_SETMASK, &((_thread)->md.oldMask), NULL); \ + setedi((_thread)->md.edi); \ + PR_ASSERT(_MD_LAST_THREAD() !=_MD_CURRENT_THREAD()); \ + _MD_LAST_THREAD()->no_sched = 0; \ + } \ + PR_END_MACRO + +/* +** Restore a thread context, saved by _PR_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_newthread) \ + PR_BEGIN_MACRO \ + ucontext_t *uc = CONTEXT(_newthread); \ + uc->uc_mcontext.gregs[EAX] = 1; \ + _MD_RESTORE_ERRNO(_newthread) \ + _MD_SET_CURRENT_THREAD(_newthread); \ + (_newthread)->no_sched = 1; \ + setcontext(uc); \ + PR_END_MACRO +#endif /* USE_SETJMP */ + +#endif /* sparc */ + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDThread { + _PR_CONTEXT_TYPE context; + int errcode; + int id; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#ifndef _PR_PTHREADS +#define _MD_INIT_LOCKS() +#endif +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +extern PRStatus _MD_WAIT(struct PRThread *, PRIntervalTime timeout); +extern PRStatus _MD_WAKEUP_WAITER(struct PRThread *); +extern void _MD_YIELD(void); +extern PRStatus _MD_InitializeThread(PRThread *thread); +extern void _MD_SET_PRIORITY(struct _MDThread *thread, + PRThreadPriority newPri); +extern PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start) (void *), + PRThreadPriority priority, PRThreadScope scope, PRThreadState state, + PRUint32 stackSize); + +NSPR_API(PRIntervalTime) _MD_Solaris_GetInterval(void); +#define _MD_GET_INTERVAL _MD_Solaris_GetInterval +NSPR_API(PRIntervalTime) _MD_Solaris_TicksPerSecond(void); +#define _MD_INTERVAL_PER_SEC _MD_Solaris_TicksPerSecond + +/* The following defines the unwrapped versions of select() and poll(). */ +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#include +#include +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +PR_BEGIN_EXTERN_C + +/* +** Missing function prototypes +*/ +extern int gethostname (char *name, int namelen); + +PR_END_EXTERN_C + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +extern void _MD_solaris_map_sendfile_error(int err); + +#endif /* nspr_solaris_defs_h___ */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris32.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris32.cfg new file mode 100644 index 00000000..3902e09c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris32.cfg @@ -0,0 +1,150 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef SOLARIS +#define SOLARIS +#endif + +#if defined(sparc) || defined(__sparc) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#elif defined(i386) || defined(__i386) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_DOUBLE 4 +#else +#error unknown processor +#endif + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 4 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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 /* ifndef nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris64.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris64.cfg new file mode 100644 index 00000000..9d5b6069 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_solaris64.cfg @@ -0,0 +1,151 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef SOLARIS +#define SOLARIS +#endif + +#if defined(sparc) || defined(__sparc) +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#elif defined(__x86_64) || defined(__AMD64) +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_DOUBLE 8 +#else +#error unknown processor +#endif +#define IS_64 + +#define PR_AF_INET6 26 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 8 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 8 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 3 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 64 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 6 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_POINTER 8 + +#define HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#define HAVE_ALIGNED_LONGLONGS + +#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 /* ifndef nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.cfg new file mode 100644 index 00000000..4b8fbff9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.cfg @@ -0,0 +1,140 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef SONY +#define SONY +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.h new file mode 100644 index 00000000..3d17e04d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sony.h @@ -0,0 +1,204 @@ +/* -*- 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_sony_defs_h___ +#define nspr_sony_defs_h___ + +#define PR_LINKER_ARCH "sony" +#define _PR_SI_SYSNAME "SONY" +#define _PR_SI_ARCHITECTURE "mips" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#if defined(_PR_LOCAL_THREADS_ONLY) +#include +#include + +#define PR_NUM_GCREGS NGREG +#define PR_CONTEXT_TYPE ucontext_t + +#define CONTEXT(_thread) (&(_thread)->md.context) + +#define _MD_GET_SP(_t) (_t)->md.context.uc_mcontext.gregs[CXT_SP] + +/* +** Initialize the thread context preparing it to execute _main() +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + getcontext(CONTEXT(_thread)); \ + CONTEXT(_thread)->uc_stack.ss_sp = (char*) (_thread)->stack->stackBottom; \ + CONTEXT(_thread)->uc_stack.ss_size = (_thread)->stack->stackSize; \ + _MD_GET_SP(_thread) = (greg_t) (_sp) - 64; \ + makecontext(CONTEXT(_thread), _main, 0); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!getcontext(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + ucontext_t *uc = CONTEXT(_thread); \ + uc->uc_mcontext.gregs[CXT_V0] = 1; \ + uc->uc_mcontext.gregs[CXT_A3] = 0; \ + _MD_SET_CURRENT_THREAD(_thread); \ + errno = (_thread)->md.errcode; \ + setcontext(uc); \ +} + +/* Machine-dependent (MD) data structures */ + +struct _MDThread { + PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* The following defines unwrapped versions of select() and poll(). */ +extern int _select (int, fd_set *, fd_set *, fd_set *, struct timeval *); +#define _MD_SELECT _select + +#include +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); +#define _MD_POLL _poll + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#undef HAVE_STACK_GROWING_UP +#define HAVE_DLL +#define USE_DLFCN +#define NEED_TIME_R +#define NEED_STRFTIME_LOCK + +/* +** Missing function prototypes +*/ +extern int gethostname(char *name, int namelen); + +#endif /* nspr_sony_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.cfg new file mode 100644 index 00000000..581d4834 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.cfg @@ -0,0 +1,138 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef SUNOS4 +#define SUNOS4 +#endif + +#undef IS_LITTLE_ENDIAN +#define IS_BIG_ENDIAN 1 +#undef HAVE_LONG_LONG +#define HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#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 /* ifndef nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.h new file mode 100644 index 00000000..0d62892e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_sunos4.h @@ -0,0 +1,236 @@ +/* -*- 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_sunos_defs_h___ +#define nspr_sunos_defs_h___ + +#include "md/sunos4.h" + +/* On SunOS 4, memset is declared in memory.h */ +#include +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "sunos" +#define _PR_SI_SYSNAME "SUNOS" +#define _PR_SI_ARCHITECTURE "sparc" +#define PR_DLL_SUFFIX ".so.1.0" + +/* +** For sunos type machines, don't specify an address because the +** NetBSD/SPARC O.S. does the wrong thing. +*/ +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#undef HAVE_STACK_GROWING_UP +#undef HAVE_WEAK_IO_SYMBOLS +#undef HAVE_WEAK_MALLOC_SYMBOLS +#define HAVE_DLL +#define USE_DLFCN +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define HAVE_BSD_FLOCK +#define _PR_NO_LARGE_FILES +#define _PR_STAT_HAS_ONLY_ST_ATIME + +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define USE_SETJMP + +#include + +#define _MD_GET_SP(_t) (_t)->md.context[2] + +#define PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + int *context = (_thread)->md.context; \ + *status = PR_TRUE; \ + asm("ta 3"); \ + (void) setjmp(context); \ + (_thread)->md.context[2] = (int) ((_sp) - 64); \ + (_thread)->md.context[2] &= ~7; \ + (_thread)->md.context[3] = (int) _main; \ + (_thread)->md.context[4] = (int) _main + 4; \ + PR_END_MACRO + +#define _MD_SWITCH_CONTEXT(_thread) \ + asm("ta 3"); \ + if (!setjmp(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + longjmp(CONTEXT(_thread), 1); \ +} + +#pragma unknown_control_flow(longjmp) +#pragma unknown_control_flow(setjmp) +#pragma unknown_control_flow(_PR_Schedule) + +/* +** Missing function prototypes +*/ + +extern int socket (int domain, int type, int protocol); +extern int getsockname (int s, struct sockaddr *name, int *namelen); +extern int getpeername (int s, struct sockaddr *name, int *namelen); +extern int getsockopt (int s, int level, int optname, char* optval, int* optlen); +extern int setsockopt (int s, int level, int optname, const char* optval, int optlen); +extern int accept (int s, struct sockaddr *addr, int *addrlen); +extern int listen (int s, int backlog); +extern int brk(void *); +extern void *sbrk(int); + + +/* Machine-dependent (MD) data structures. SunOS 4 has no native threads. */ + +struct _MDThread { + jmp_buf context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* These are copied from _solaris.h */ + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#define _MD_SELECT(nfds,r,w,e,tv) syscall(SYS_select,nfds,r,w,e,tv) +#define _MD_POLL(fds,nfds,timeout) syscall(SYS_poll,fds,nfds,timeout) + +#endif /* nspr_sparc_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_unix_errors.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unix_errors.h new file mode 100644 index 00000000..28cfc35f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unix_errors.h @@ -0,0 +1,171 @@ +/* -*- 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 prunixerrors_h___ +#define prunixerrors_h___ + +#include +#include + +PR_BEGIN_EXTERN_C + +NSPR_API(void) _MD_unix_map_default_error(int err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_unix_map_default_error + +NSPR_API(void) _MD_unix_map_opendir_error(int err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_unix_map_opendir_error + +NSPR_API(void) _MD_unix_map_closedir_error(int err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_unix_map_closedir_error + +NSPR_API(void) _MD_unix_readdir_error(int err); +#define _PR_MD_MAP_READDIR_ERROR _MD_unix_readdir_error + +NSPR_API(void) _MD_unix_map_unlink_error(int err); +#define _PR_MD_MAP_UNLINK_ERROR _MD_unix_map_unlink_error + +NSPR_API(void) _MD_unix_map_stat_error(int err); +#define _PR_MD_MAP_STAT_ERROR _MD_unix_map_stat_error + +NSPR_API(void) _MD_unix_map_fstat_error(int err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_unix_map_fstat_error + +NSPR_API(void) _MD_unix_map_rename_error(int err); +#define _PR_MD_MAP_RENAME_ERROR _MD_unix_map_rename_error + +NSPR_API(void) _MD_unix_map_access_error(int err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_unix_map_access_error + +NSPR_API(void) _MD_unix_map_mkdir_error(int err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_unix_map_mkdir_error + +NSPR_API(void) _MD_unix_map_rmdir_error(int err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_unix_map_rmdir_error + +NSPR_API(void) _MD_unix_map_read_error(int err); +#define _PR_MD_MAP_READ_ERROR _MD_unix_map_read_error + +NSPR_API(void) _MD_unix_map_write_error(int err); +#define _PR_MD_MAP_WRITE_ERROR _MD_unix_map_write_error + +NSPR_API(void) _MD_unix_map_lseek_error(int err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_unix_map_lseek_error + +NSPR_API(void) _MD_unix_map_fsync_error(int err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_unix_map_fsync_error + +NSPR_API(void) _MD_unix_map_close_error(int err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_unix_map_close_error + +NSPR_API(void) _MD_unix_map_socket_error(int err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_unix_map_socket_error + +NSPR_API(void) _MD_unix_map_socketavailable_error(int err); +#define _PR_MD_MAP_SOCKETAVAILABLE_ERROR _MD_unix_map_socketavailable_error + +NSPR_API(void) _MD_unix_map_recv_error(int err); +#define _PR_MD_MAP_RECV_ERROR _MD_unix_map_recv_error + +NSPR_API(void) _MD_unix_map_recvfrom_error(int err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_unix_map_recvfrom_error + +NSPR_API(void) _MD_unix_map_send_error(int err); +#define _PR_MD_MAP_SEND_ERROR _MD_unix_map_send_error + +NSPR_API(void) _MD_unix_map_sendto_error(int err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_unix_map_sendto_error + +NSPR_API(void) _MD_unix_map_writev_error(int err); +#define _PR_MD_MAP_WRITEV_ERROR _MD_unix_map_writev_error + +NSPR_API(void) _MD_unix_map_accept_error(int err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_unix_map_accept_error + +NSPR_API(void) _MD_unix_map_connect_error(int err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_unix_map_connect_error + +NSPR_API(void) _MD_unix_map_bind_error(int err); +#define _PR_MD_MAP_BIND_ERROR _MD_unix_map_bind_error + +NSPR_API(void) _MD_unix_map_listen_error(int err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_unix_map_listen_error + +NSPR_API(void) _MD_unix_map_shutdown_error(int err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_unix_map_shutdown_error + +NSPR_API(void) _MD_unix_map_socketpair_error(int err); +#define _PR_MD_MAP_SOCKETPAIR_ERROR _MD_unix_map_socketpair_error + +NSPR_API(void) _MD_unix_map_getsockname_error(int err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_unix_map_getsockname_error + +NSPR_API(void) _MD_unix_map_getpeername_error(int err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_unix_map_getpeername_error + +NSPR_API(void) _MD_unix_map_getsockopt_error(int err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_unix_map_getsockopt_error + +NSPR_API(void) _MD_unix_map_setsockopt_error(int err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_unix_map_setsockopt_error + +NSPR_API(void) _MD_unix_map_open_error(int err); +#define _PR_MD_MAP_OPEN_ERROR _MD_unix_map_open_error + +NSPR_API(void) _MD_unix_map_mmap_error(int err); +#define _PR_MD_MAP_MMAP_ERROR _MD_unix_map_mmap_error + +NSPR_API(void) _MD_unix_map_gethostname_error(int err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_unix_map_gethostname_error + +NSPR_API(void) _MD_unix_map_select_error(int err); +#define _PR_MD_MAP_SELECT_ERROR _MD_unix_map_select_error + +NSPR_API(void) _MD_unix_map_poll_error(int err); +#define _PR_MD_MAP_POLL_ERROR _MD_unix_map_poll_error + +NSPR_API(void) _MD_unix_map_poll_revents_error(int err); +#define _PR_MD_MAP_POLL_REVENTS_ERROR _MD_unix_map_poll_revents_error + +NSPR_API(void) _MD_unix_map_flock_error(int err); +#define _PR_MD_MAP_FLOCK_ERROR _MD_unix_map_flock_error + +NSPR_API(void) _MD_unix_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_unix_map_lockf_error + +PR_END_EXTERN_C + +#endif /* prunixerrors_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixos.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixos.h new file mode 100644 index 00000000..60793de1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixos.h @@ -0,0 +1,641 @@ +/* -*- 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 prunixos_h___ +#define prunixos_h___ + +/* + * If FD_SETSIZE is not defined on the command line, set the default value + * before include select.h + */ +/* + * Linux: FD_SETSIZE is defined in /usr/include/sys/select.h and should + * not be redefined. + */ +#if !defined(LINUX) && !defined(DARWIN) && !defined(NEXTSTEP) +#ifndef FD_SETSIZE +#define FD_SETSIZE 4096 +#endif +#endif + +#include +#include +#include +#include +#include + +#include "prio.h" +#include "prmem.h" +#include "prclist.h" + +/* + * For select(), fd_set, and struct timeval. + * + * In The Single UNIX(R) Specification, Version 2, + * the header file for select() is . + * + * fd_set is defined in . Usually + * includes , but on some + * older systems does not include + * , so we include it explicitly. + */ +#include +#include +#if defined(AIX) /* Only pre-4.2 AIX needs it, but for simplicity... */ +#include +#endif + +#define PR_DIRECTORY_SEPARATOR '/' +#define PR_DIRECTORY_SEPARATOR_STR "/" +#define PR_PATH_SEPARATOR ':' +#define PR_PATH_SEPARATOR_STR ":" +#define GCPTR +typedef int (*FARPROC)(); + +/* + * intervals at which GLOBAL threads wakeup to check for pending interrupt + */ +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 +extern PRIntervalTime intr_timeout_ticks; + +/* + * The bit flags for the in_flags and out_flags fields + * of _PR_UnixPollDesc + */ +#ifdef _PR_USE_POLL +#define _PR_UNIX_POLL_READ POLLIN +#define _PR_UNIX_POLL_WRITE POLLOUT +#define _PR_UNIX_POLL_EXCEPT POLLPRI +#define _PR_UNIX_POLL_ERR POLLERR +#define _PR_UNIX_POLL_NVAL POLLNVAL +#define _PR_UNIX_POLL_HUP POLLHUP +#else /* _PR_USE_POLL */ +#define _PR_UNIX_POLL_READ 0x1 +#define _PR_UNIX_POLL_WRITE 0x2 +#define _PR_UNIX_POLL_EXCEPT 0x4 +#define _PR_UNIX_POLL_ERR 0x8 +#define _PR_UNIX_POLL_NVAL 0x10 +#define _PR_UNIX_POLL_HUP 0x20 +#endif /* _PR_USE_POLL */ + +typedef struct _PRUnixPollDesc { + PRInt32 osfd; + PRInt16 in_flags; + PRInt16 out_flags; +} _PRUnixPollDesc; + +typedef struct PRPollQueue { + PRCList links; /* for linking PRPollQueue's together */ + _PRUnixPollDesc *pds; /* array of poll descriptors */ + PRUintn npds; /* length of the array */ + PRPackedBool on_ioq; /* is this on the async i/o work q? */ + PRIntervalTime timeout; /* timeout, in ticks */ + struct PRThread *thr; +} PRPollQueue; + +#define _PR_POLLQUEUE_PTR(_qp) \ + ((PRPollQueue*) ((char*) (_qp) - offsetof(PRPollQueue,links))) + + +extern PRInt32 _PR_WaitForMultipleFDs( + _PRUnixPollDesc *unixpds, + PRInt32 pdcnt, + PRIntervalTime timeout); +extern void _PR_Unblock_IO_Wait(struct PRThread *thr); + +#if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY) +#define _MD_CHECK_FOR_EXIT() +#endif + +extern fd_set _pr_md_read_set, _pr_md_write_set, _pr_md_exception_set; +extern PRInt16 _pr_md_read_cnt[], _pr_md_write_cnt[], _pr_md_exception_cnt[]; +extern PRInt32 _pr_md_ioq_max_osfd; +extern PRUint32 _pr_md_ioq_timeout; + +struct _MDFileDesc { + int osfd; +#if defined(LINUX) && defined(_PR_PTHREADS) + int tcp_nodelay; /* used by pt_LinuxSendFile */ +#endif +}; + +struct _MDDir { + DIR *d; +}; + +struct _PRCPU; +extern void _MD_unix_init_running_cpu(struct _PRCPU *cpu); + +/* +** Make a redzone at both ends of the stack segment. Disallow access +** to those pages of memory. It's ok if the mprotect call's don't +** work - it just means that we don't really have a functional +** redzone. +*/ +#include +#ifndef PROT_NONE +#define PROT_NONE 0x0 +#endif + +#if defined(DEBUG) && !defined(DARWIN) && !defined(NEXTSTEP) +#if !defined(SOLARIS) +#include /* for memset() */ +#define _MD_INIT_STACK(ts,REDZONE) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE); \ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_NONE); \ + /* \ + ** Fill stack memory with something that turns into an illegal \ + ** pointer value. This will sometimes find runtime references to \ + ** uninitialized pointers. We don't do this for solaris because we \ + ** can use purify instead. \ + */ \ + if (_pr_debugStacks) { \ + memset(ts->allocBase + REDZONE, 0xf7, ts->stackSize); \ + } \ + PR_END_MACRO +#else /* !SOLARIS */ +#define _MD_INIT_STACK(ts,REDZONE) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_NONE); \ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_NONE); \ + PR_END_MACRO +#endif /* !SOLARIS */ + +/* + * _MD_CLEAR_STACK + * Allow access to the redzone pages; the access was turned off in + * _MD_INIT_STACK. + */ +#define _MD_CLEAR_STACK(ts) \ + PR_BEGIN_MACRO \ + (void) mprotect((void*)ts->seg->vaddr, REDZONE, PROT_READ|PROT_WRITE);\ + (void) mprotect((void*) ((char*)ts->seg->vaddr + REDZONE + ts->stackSize),\ + REDZONE, PROT_READ|PROT_WRITE); \ + PR_END_MACRO + +#else /* DEBUG */ + +#define _MD_INIT_STACK(ts,REDZONE) +#define _MD_CLEAR_STACK(ts) + +#endif /* DEBUG */ + +#if !defined(SOLARIS) + +#define PR_SET_INTSOFF(newval) + +#endif + +/************************************************************************/ + +extern void _PR_UnixInit(void); + +/************************************************************************/ + +struct _MDProcess { + pid_t pid; +}; + +struct PRProcess; +struct PRProcessAttr; + +/* Create a new process (fork() + exec()) */ +#define _MD_CREATE_PROCESS _MD_CreateUnixProcess +extern struct PRProcess * _MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#ifdef VBOX +/* Create a new detached process (fork() + exec()) */ +#define _MD_CREATE_PROCESS_DETACHED _MD_CreateUnixProcessDetached +extern PRStatus _MD_CreateUnixProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); +#endif /* VBOX */ + +#define _MD_DETACH_PROCESS _MD_DetachUnixProcess +extern PRStatus _MD_DetachUnixProcess(struct PRProcess *process); + +/* Wait for a child process to terminate */ +#define _MD_WAIT_PROCESS _MD_WaitUnixProcess +extern PRStatus _MD_WaitUnixProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _MD_KillUnixProcess +extern PRStatus _MD_KillUnixProcess(struct PRProcess *process); + +/************************************************************************/ + +extern void _MD_EnableClockInterrupts(void); +extern void _MD_DisableClockInterrupts(void); + +#define _MD_START_INTERRUPTS _MD_StartInterrupts +#define _MD_STOP_INTERRUPTS _MD_StopInterrupts +#define _MD_DISABLE_CLOCK_INTERRUPTS _MD_DisableClockInterrupts +#define _MD_ENABLE_CLOCK_INTERRUPTS _MD_EnableClockInterrupts +#define _MD_BLOCK_CLOCK_INTERRUPTS _MD_BlockClockInterrupts +#define _MD_UNBLOCK_CLOCK_INTERRUPTS _MD_UnblockClockInterrupts + +/************************************************************************/ + +extern void _MD_InitCPUS(void); +#define _MD_INIT_CPUS _MD_InitCPUS + +extern void _MD_Wakeup_CPUs(void); +#define _MD_WAKEUP_CPUS _MD_Wakeup_CPUs + +#define _MD_PAUSE_CPU _MD_PauseCPU + +#if defined(_PR_LOCAL_THREADS_ONLY) || defined(_PR_GLOBAL_THREADS_ONLY) +#define _MD_CLEANUP_BEFORE_EXIT() +#endif + +#ifndef IRIX +#define _MD_EXIT(status) _exit(status) +#endif + +/************************************************************************/ + +#define _MD_GET_ENV getenv +#define _MD_PUT_ENV putenv + +/************************************************************************/ + +#define _MD_INIT_FILEDESC(fd) + +extern void _MD_MakeNonblock(PRFileDesc *fd); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock + +/************************************************************************/ + +#if !defined(_PR_PTHREADS) + +extern void _MD_InitSegs(void); +extern PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, + void *vaddr); +extern void _MD_FreeSegment(PRSegment *seg); + +#define _MD_INIT_SEGS _MD_InitSegs +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +#endif /* !defined(_PR_PTHREADS) */ + +/************************************************************************/ + +#if !defined(HPUX_LW_TIMER) +#define _MD_INTERVAL_INIT() +#endif +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/************************************************************************/ + +#define _MD_ERRNO() (errno) +#define _MD_GET_SOCKET_ERROR() (errno) + +/************************************************************************/ + +extern PRInt32 _MD_AvailableSocket(PRInt32 osfd); + +extern void _MD_StartInterrupts(void); +extern void _MD_StopInterrupts(void); +extern void _MD_DisableClockInterrupts(void); +extern void _MD_BlockClockInterrupts(void); +extern void _MD_UnblockClockInterrupts(void); +extern void _MD_PauseCPU(PRIntervalTime timeout); + +extern PRStatus _MD_open_dir(struct _MDDir *, const char *); +extern PRInt32 _MD_close_dir(struct _MDDir *); +extern char * _MD_read_dir(struct _MDDir *, PRIntn); +extern PRInt32 _MD_open(const char *name, PRIntn osflags, PRIntn mode); +extern PRInt32 _MD_delete(const char *name); +extern PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info); +extern PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info); +extern PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info); +extern PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info); +extern PRInt32 _MD_rename(const char *from, const char *to); +extern PRInt32 _MD_access(const char *name, PRAccessHow how); +extern PRInt32 _MD_mkdir(const char *name, PRIntn mode); +extern PRInt32 _MD_rmdir(const char *name); +extern PRInt32 _MD_accept_read(PRInt32 sock, PRInt32 *newSock, + PRNetAddr **raddr, void *buf, PRInt32 amount); +extern PRInt32 _PR_UnixSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +extern PRStatus _MD_LockFile(PRInt32 osfd); +extern PRStatus _MD_TLockFile(PRInt32 osfd); +extern PRStatus _MD_UnlockFile(PRInt32 osfd); + +#define _MD_OPEN_DIR(dir, name) _MD_open_dir(dir, name) +#define _MD_CLOSE_DIR(dir) _MD_close_dir(dir) +#define _MD_READ_DIR(dir, flags) _MD_read_dir(dir, flags) +#define _MD_OPEN(name, osflags, mode) _MD_open(name, osflags, mode) +#define _MD_OPEN_FILE(name, osflags, mode) _MD_open(name, osflags, mode) +extern PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _MD_READ(fd,buf,amount) _MD_read(fd,buf,amount) +extern PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount); +#define _MD_WRITE(fd,buf,amount) _MD_write(fd,buf,amount) +#define _MD_DELETE(name) _MD_delete(name) +#define _MD_GETFILEINFO(fn, info) _MD_getfileinfo(fn, info) +#define _MD_GETFILEINFO64(fn, info) _MD_getfileinfo64(fn, info) +#define _MD_GETOPENFILEINFO(fd, info) _MD_getopenfileinfo(fd, info) +#define _MD_GETOPENFILEINFO64(fd, info) _MD_getopenfileinfo64(fd, info) +#define _MD_RENAME(from, to) _MD_rename(from, to) +#define _MD_ACCESS(name, how) _MD_access(name, how) +#define _MD_MKDIR(name, mode) _MD_mkdir(name, mode) +#define _MD_MAKE_DIR(name, mode) _MD_mkdir(name, mode) +#define _MD_RMDIR(name) _MD_rmdir(name) +#define _MD_ACCEPT_READ(sock, newSock, raddr, buf, amount) _MD_accept_read(sock, newSock, raddr, buf, amount) + +#define _MD_LOCKFILE _MD_LockFile +#define _MD_TLOCKFILE _MD_TLockFile +#define _MD_UNLOCKFILE _MD_UnlockFile + + +extern PRInt32 _MD_socket(int af, int type, int flags); +#define _MD_SOCKET _MD_socket +extern PRInt32 _MD_connect(PRFileDesc *fd, const PRNetAddr *addr, + PRUint32 addrlen, PRIntervalTime timeout); +#define _MD_CONNECT _MD_connect +extern PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_accept +extern PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +#define _MD_BIND _MD_bind +extern PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog); +#define _MD_LISTEN _MD_listen +extern PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how); +#define _MD_SHUTDOWN _MD_shutdown + +extern PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _MD_RECV _MD_recv +extern PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _MD_SEND _MD_send +extern PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout); +#define _MD_RECVFROM _MD_recvfrom +extern PRInt32 _MD_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout); +#define _MD_SENDTO _MD_sendto +extern PRInt32 _MD_writev(PRFileDesc *fd, const struct PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout); +#define _MD_WRITEV _MD_writev + +extern PRInt32 _MD_socketavailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_socketavailable +extern PRInt64 _MD_socketavailable64(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE64 _MD_socketavailable64 + +#define _MD_PIPEAVAILABLE _MD_socketavailable + +extern PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout); +#define _MD_PR_POLL _MD_pr_poll + +extern PRInt32 _MD_close(PRInt32 osfd); +#define _MD_CLOSE_FILE _MD_close +extern PRInt32 _MD_lseek(PRFileDesc*, PRInt32, PRSeekWhence); +#define _MD_LSEEK _MD_lseek +extern PRInt64 _MD_lseek64(PRFileDesc*, PRInt64, PRSeekWhence); +#define _MD_LSEEK64 _MD_lseek64 +extern PRInt32 _MD_fsync(PRFileDesc *fd); +#define _MD_FSYNC _MD_fsync + +extern PRInt32 _MD_socketpair(int af, int type, int flags, PRInt32 *osfd); +#define _MD_SOCKETPAIR _MD_socketpair + +#define _MD_CLOSE_SOCKET _MD_close + +#ifndef NO_NSPR_10_SUPPORT +#define _MD_STAT stat +#endif + +extern PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen); +#define _MD_GETPEERNAME _MD_getpeername +extern PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen); +#define _MD_GETSOCKNAME _MD_getsockname + +extern PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, char* optval, PRInt32* optlen); +#define _MD_GETSOCKOPT _MD_getsockopt +extern PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, const char* optval, PRInt32 optlen); +#define _MD_SETSOCKOPT _MD_setsockopt + +extern PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable); +#define _MD_SET_FD_INHERITABLE _MD_set_fd_inheritable + +extern void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported); +#define _MD_INIT_FD_INHERITABLE _MD_init_fd_inheritable + +extern void _MD_query_fd_inheritable(PRFileDesc *fd); +#define _MD_QUERY_FD_INHERITABLE _MD_query_fd_inheritable + +extern PRStatus _MD_gethostname(char *name, PRUint32 namelen); +#define _MD_GETHOSTNAME _MD_gethostname + +extern PRStatus _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _MD_GETSYSINFO _MD_getsysinfo + +extern int _MD_unix_get_nonblocking_connect_error(int osfd); + +/* Memory-mapped files */ + +struct _MDFileMap { + PRIntn prot; + PRIntn flags; + PRBool isAnonFM; /* when true, PR_CloseFileMap() must close the related fd */ +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +#define _MD_GET_MEM_MAP_ALIGNMENT() PR_GetPageSize() + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* + * The standard (XPG4) gettimeofday() (from BSD) takes two arguments. + * On some SVR4 derivatives, gettimeofday() takes only one argument. + * The GETTIMEOFDAY macro is intended to hide this difference. + */ +#ifdef HAVE_SVID_GETTOD +#define GETTIMEOFDAY(tp) gettimeofday(tp) +#else +#define GETTIMEOFDAY(tp) gettimeofday((tp), NULL) +#endif + +#if defined(_PR_PTHREADS) && !defined(_PR_POLL_AVAILABLE) +#define _PR_NEED_FAKE_POLL +#endif + +#if defined(_PR_NEED_FAKE_POLL) + +/* + * Some platforms don't have poll(), but our pthreads code calls poll(). + * As a temporary measure, I implemented a fake poll() using select(). + * Here are the struct and macro definitions copied from sys/poll.h + * on Solaris 2.5. + */ + +struct pollfd { + int fd; + short events; + short revents; +}; + +/* poll events */ + +#define POLLIN 0x0001 /* fd is readable */ +#define POLLPRI 0x0002 /* high priority info at fd */ +#define POLLOUT 0x0004 /* fd is writeable (won't block) */ +#define POLLRDNORM 0x0040 /* normal data is readable */ +#define POLLWRNORM POLLOUT +#define POLLRDBAND 0x0080 /* out-of-band data is readable */ +#define POLLWRBAND 0x0100 /* out-of-band data is writeable */ + +#define POLLNORM POLLRDNORM + +#define POLLERR 0x0008 /* fd has error condition */ +#define POLLHUP 0x0010 /* fd has been hung up on */ +#define POLLNVAL 0x0020 /* invalid pollfd entry */ + +extern int poll(struct pollfd *, unsigned long, int); + +#endif /* _PR_NEED_FAKE_POLL */ + +/* +** A vector of the UNIX I/O calls we use. These are here to smooth over +** the rough edges needed for large files. All of NSPR's implmentaions +** go through this vector using syntax of the form +** result = _md_iovector.xxx64(args); +*/ + +#if defined(SOLARIS2_5) +/* +** Special case: Solaris 2.5.1 +** Solaris starts to have 64-bit file I/O in 2.6. We build on Solaris +** 2.5.1 so that we can use the same binaries on both Solaris 2.5.1 and +** 2.6. At run time, we detect whether 64-bit file I/O is available by +** looking up the 64-bit file function symbols in libc. At build time, +** we need to define the 64-bit file I/O datatypes that are compatible +** with their definitions on Solaris 2.6. +*/ +typedef PRInt64 off64_t; +typedef PRUint64 ino64_t; +typedef PRInt64 blkcnt64_t; +struct stat64 { + dev_t st_dev; + long st_pad1[3]; + ino64_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + long t_pad2[2]; + off64_t st_size; + timestruc_t st_atim; + timestruc_t st_mtim; + timestruc_t st_ctim; + long st_blksize; + blkcnt64_t st_blocks; + char st_fstype[_ST_FSTYPSZ]; + long st_pad4[8]; +}; +typedef struct stat64 _MDStat64; +typedef off64_t _MDOff64_t; + +#elif defined(_PR_HAVE_OFF64_T) +typedef struct stat64 _MDStat64; +typedef off64_t _MDOff64_t; +#elif defined(_PR_HAVE_LARGE_OFF_T) +typedef struct stat _MDStat64; +typedef off_t _MDOff64_t; +#elif defined(_PR_NO_LARGE_FILES) +typedef struct stat _MDStat64; +typedef PRInt64 _MDOff64_t; +#else +#error "I don't know yet" +#endif + +typedef PRIntn (*_MD_Fstat64)(PRIntn osfd, _MDStat64 *buf); +typedef PRIntn (*_MD_Open64)(const char *path, int oflag, ...); +#if defined(VMS) +typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf, ...); +#else +typedef PRIntn (*_MD_Stat64)(const char *path, _MDStat64 *buf); +#endif +typedef _MDOff64_t (*_MD_Lseek64)(PRIntn osfd, _MDOff64_t, PRIntn whence); +typedef void* (*_MD_Mmap64)( + void *addr, PRSize len, PRIntn prot, PRIntn flags, + PRIntn fildes, _MDOff64_t offset); +struct _MD_IOVector +{ + _MD_Open64 _open64; + _MD_Mmap64 _mmap64; + _MD_Stat64 _stat64; + _MD_Fstat64 _fstat64; + _MD_Lseek64 _lseek64; +}; +extern struct _MD_IOVector _md_iovector; + +#endif /* prunixos_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.cfg new file mode 100644 index 00000000..796e748d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.cfg @@ -0,0 +1,140 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef UNIXWARE +#define UNIXWARE +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#undef HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.h new file mode 100644 index 00000000..bdc084f2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware.h @@ -0,0 +1,219 @@ +/* -*- 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_unixware_defs_h___ +#define nspr_unixware_defs_h___ + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "unixware" +#define _PR_SI_SYSNAME "UnixWare" +#define _PR_SI_ARCHITECTURE "x86" +#define PR_DLL_SUFFIX ".so" + +#define _PR_VMBASE 0x30000000 +#define _PR_STACK_VMBASE 0x50000000 +#define _MD_DEFAULT_STACK_SIZE 65536L +#define _MD_MMAP_FLAGS MAP_PRIVATE + +#ifndef HAVE_WEAK_IO_SYMBOLS +#define HAVE_WEAK_IO_SYMBOLS +#endif +#define _PR_POLL_AVAILABLE +#define _PR_USE_POLL +#define _PR_STAT_HAS_ST_ATIM_UNION + +#undef HAVE_STACK_GROWING_UP +#define HAVE_NETCONFIG +#define HAVE_DLL +#define USE_DLFCN +#define HAVE_STRERROR +#define NEED_STRFTIME_LOCK +#define NEED_TIME_R +#define _PR_NEED_STRCASECMP + +#define USE_SETJMP + +#include + +#define _SETJMP setjmp +#define _LONGJMP longjmp +#define _PR_CONTEXT_TYPE jmp_buf +#define _MD_GET_SP(_t) (_t)->md.context[4] +#define _PR_NUM_GCREGS _JBLEN + +#define CONTEXT(_th) ((_th)->md.context) + +/* +** Initialize the thread context preparing it to execute _main. +*/ +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ +{ \ + *status = PR_TRUE; \ + if(_SETJMP(CONTEXT(_thread))) (*_main)(); \ + _MD_GET_SP(_thread) = (int) ((_sp) - 128); \ +} + +#define _MD_SWITCH_CONTEXT(_thread) \ + if (!_SETJMP(CONTEXT(_thread))) { \ + (_thread)->md.errcode = errno; \ + _PR_Schedule(); \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _MD_RESTORE_CONTEXT(_thread) \ +{ \ + errno = (_thread)->md.errcode; \ + _MD_SET_CURRENT_THREAD(_thread); \ + _LONGJMP(CONTEXT(_thread), 1); \ +} + +/* Machine-dependent (MD) data structures. + * Don't use SVR4 native threads (yet). + */ + +struct _MDThread { + _PR_CONTEXT_TYPE context; + int id; + int errcode; +}; + +struct _MDThreadStack { + PRInt8 notused; +}; + +struct _MDLock { + PRInt8 notused; +}; + +struct _MDSemaphore { + PRInt8 notused; +}; + +struct _MDCVar { + PRInt8 notused; +}; + +struct _MDSegment { + PRInt8 notused; +}; + +/* + * md-specific cpu structure field + */ +#define _PR_MD_MAX_OSFD FD_SETSIZE + +struct _MDCPU_Unix { + PRCList ioQ; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; + PRInt32 ioq_osfd_cnt; +#ifndef _PR_USE_POLL + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; +#else + struct pollfd *ioq_pollfds; + int ioq_pollfds_size; +#endif /* _PR_USE_POLL */ +}; + +#define _PR_IOQ(_cpu) ((_cpu)->md.md_unix.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.md_unix.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.md_unix.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.md_unix.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.md_unix.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.md_unix.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.md_unix.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.md_unix.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.md_unix.ioq_max_osfd) +#define _PR_IOQ_OSFD_CNT(_cpu) ((_cpu)->md.md_unix.ioq_osfd_cnt) +#define _PR_IOQ_POLLFDS(_cpu) ((_cpu)->md.md_unix.ioq_pollfds) +#define _PR_IOQ_POLLFDS_SIZE(_cpu) ((_cpu)->md.md_unix.ioq_pollfds_size) + +#define _PR_IOQ_MIN_POLLFDS_SIZE(_cpu) 32 + +struct _MDCPU { + struct _MDCPU_Unix md_unix; +}; + +#define _MD_INIT_LOCKS() +#define _MD_NEW_LOCK(lock) PR_SUCCESS +#define _MD_FREE_LOCK(lock) +#define _MD_LOCK(lock) +#define _MD_UNLOCK(lock) +#define _MD_INIT_IO() +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + +/* + * The following are copied from _sunos.h, _aix.h. This means + * some of them should probably be moved into _unixos.h. But + * _irix.h seems to be quite different in regard to these macros. + */ +#define _MD_GET_INTERVAL _PR_UNIX_GetInterval +#define _MD_INTERVAL_PER_SEC _PR_UNIX_TicksPerSecond + +#define _MD_EARLY_INIT _MD_EarlyInit +#define _MD_FINAL_INIT _PR_UnixInit +#define _MD_INIT_RUNNING_CPU(cpu) _MD_unix_init_running_cpu(cpu) +#define _MD_INIT_THREAD _MD_InitializeThread +#define _MD_EXIT_THREAD(thread) +#define _MD_SUSPEND_THREAD(thread) +#define _MD_RESUME_THREAD(thread) +#define _MD_CLEAN_THREAD(_thread) + +/* + * We wrapped the select() call. _MD_SELECT refers to the built-in, + * unwrapped version. + */ +#include +#include +#include +extern int _select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *execptfds, struct timeval *timeout); +#define _MD_SELECT _select + +#define _MD_POLL _poll +extern int _poll(struct pollfd *fds, unsigned long nfds, int timeout); + +#endif /* nspr_unixware_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware7.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware7.cfg new file mode 100644 index 00000000..c37bd3c9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_unixware7.cfg @@ -0,0 +1,142 @@ +/* -*- 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_UNIX +#define XP_UNIX +#endif + +#ifndef UNIXWARE +#define UNIXWARE +#endif + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN +#define HAVE_LONG_LONG +#undef HAVE_ALIGNED_DOUBLES +#undef HAVE_ALIGNED_LONGLONGS + +#define PR_AF_INET6 27 /* same as AF_INET6 */ + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 4 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define _PR_POLL_BACKCOMPAT + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_vbox.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_vbox.cfg new file mode 100644 index 00000000..ce3c1dde --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_vbox.cfg @@ -0,0 +1,66 @@ +/* -*- 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): + * innotek + * + * 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_vboxcfg___ +#define nspr_vboxcfg___ + +#ifdef RT_OS_DARWIN +# include +#elif defined(RT_OS_FREEBSD) +# include +#elif defined(RT_OS_L4) +# include +#elif defined(RT_OS_LINUX) +# include +#elif defined(RT_OS_NETBSD) +# include +#elif defined(RT_OS_OPENBSD) +# include +#elif defined(RT_OS_SOLARIS) +# if defined(RT_ARCH_X86) +# include +# else +# include +# endif +#elif defined(RT_OS_OS2) +# include +#else +# error "Define the correct platform identifier / Port me." +#endif + +#endif /* !nspr_vboxcfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.cfg new file mode 100644 index 00000000..330db386 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.cfg @@ -0,0 +1,177 @@ +/* -*- 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 ***** */ + +/* +** _win16.cfg -- prcpucfg.h for win16 +** +** +** lth. 14-Apr-1997. New. Made from _win95.cfg +*/ + +#ifndef nspr_cpucfg___ +#define nspr_cpucfg___ + +#ifndef XP_PC +#define XP_PC +#endif + +#ifndef WIN16 +#define WIN16 +#undef WIN32 +#endif + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 2 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 16 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 4 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 4 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 2 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 2 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 2 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#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 */ + +#undef HAVE_LONG_LONG + +/* +** HAVE_WATCOM_BUG_1 +** When HAVE_WATCOM_BUG_1 is defined, special case code is +** used to circumvent the bug. +** Functions declared __cdecl in DLLs returning floating point types +** generate bad return code and will not return the intended result. +*/ +#define HAVE_WATCOM_BUG_1 + +/* +** HAVE_WATCOM_BUG_2 +** When HAVE_WATCOM_BUG_2 is defined, special case code is +** used to circumvent the bug. +** Functions declared __cdecl in DLLs returning a structure by value +** generate bad return values. +** Yes, similar to Watcom Bug 1. +*/ +#define HAVE_WATCOM_BUG_2 + +#endif /* nspr_cpucfg___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.h new file mode 100644 index 00000000..d7e79c22 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win16.h @@ -0,0 +1,568 @@ +/* -*- 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_win16_defs_h___ +#define nspr_win16_defs_h___ + +#include +#include +#include +#include + +#include "nspr.h" +/* $$ fix this */ +#define Remind(x) + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win16" +#define _PR_SI_SYSNAME "WIN16" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#define _PR_NO_PREEMPT +#define _PR_LOCAL_THREADS_ONLY +#undef _PR_GLOBAL_THREADS_ONLY +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_ATOMIC_OPS + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +extern struct PRLock *_pr_schedLock; +extern char * _pr_top_of_task_stack; + + +/* --- Typedefs --- */ + +#define PR_NUM_GCREGS 9 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + + +typedef struct _PRWin16PollDesc +{ + PRInt32 osfd; + PRInt16 in_flags; + PRInt16 out_flags; +} _PRWin16PollDesc; + +typedef struct PRPollQueue +{ + PRCList links; /* for linking PRPollQueue's together */ + _PRWin16PollDesc *pds; /* array of poll descriptors */ + PRUintn npds; /* length of the array */ + PRPackedBool on_ioq; /* is this on the async i/o work q? */ + PRIntervalTime timeout; /* timeout, in ticks */ + struct PRThread *thr; +} PRPollQueue; + +#define _PR_POLLQUEUE_PTR(_qp) \ + ((PRPollQueue *) ((char*) (_qp) - offsetof(PRPollQueue,links))) + +NSPR_API(PRInt32) _PR_WaitForFD(PRInt32 osfd, PRUintn how, + PRIntervalTime timeout); +NSPR_API(void) _PR_Unblock_IO_Wait(struct PRThread *thr); + +#define _PR_MD_MAX_OSFD FD_SETSIZE +#define _PR_IOQ(_cpu) ((_cpu)->md.ioQ) +#define _PR_ADD_TO_IOQ(_pq, _cpu) PR_APPEND_LINK(&_pq.links, &_PR_IOQ(_cpu)) +#define _PR_FD_READ_SET(_cpu) ((_cpu)->md.fd_read_set) +#define _PR_FD_READ_CNT(_cpu) ((_cpu)->md.fd_read_cnt) +#define _PR_FD_WRITE_SET(_cpu) ((_cpu)->md.fd_write_set) +#define _PR_FD_WRITE_CNT(_cpu) ((_cpu)->md.fd_write_cnt) +#define _PR_FD_EXCEPTION_SET(_cpu) ((_cpu)->md.fd_exception_set) +#define _PR_FD_EXCEPTION_CNT(_cpu) ((_cpu)->md.fd_exception_cnt) +#define _PR_IOQ_TIMEOUT(_cpu) ((_cpu)->md.ioq_timeout) +#define _PR_IOQ_MAX_OSFD(_cpu) ((_cpu)->md.ioq_max_osfd) + +struct _MDCPU { + PRCList ioQ; + fd_set fd_read_set, fd_write_set, fd_exception_set; + PRInt16 fd_read_cnt[_PR_MD_MAX_OSFD],fd_write_cnt[_PR_MD_MAX_OSFD], + fd_exception_cnt[_PR_MD_MAX_OSFD]; + PRUint32 ioq_timeout; + PRInt32 ioq_max_osfd; +}; + +struct _MDThread { + /* The overlapped structure must be first! */ + HANDLE blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRInt32 errcode; /* preserved errno for this thread */ + CATCHBUF context; /* thread context for Throw() */ + void *SP; /* Stack pointer, used only by GarbColl */ + int threadNumber; /* instrumentation: order of creation */ + _PRWin16PollDesc thr_pd; /* poll descriptor for i/o */ + PRPollQueue thr_pq; /* i/o parameters */ + void *exceptionContext; /* mfc exception context */ + char guardBand[24]; /* don't overwrite this */ + PRUint32 magic; /* self identifier, for debug */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ + PRIntn cxByteCount; /* number of stack bytes to move */ + char * stackTop; /* high address on stack */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + + +struct _MDLock { + PRUint32 magic; /* for debugging */ + PRUint32 mutex; +}; + +struct _MDDir { + PRUint32 magic; /* for debugging */ + struct dirent *dir; +}; + +struct _MDCVar { + PRUint32 magic; +}; + +struct _MDSemaphore { + PRInt32 unused; +}; + +struct _MDFileDesc { + PRInt32 osfd; +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + +/* +** Microsoft 'struct _stat' +** ... taken directly from msvc 1.52c's header file sys/stat.h +** see PR_Stat() implemented in w16io.c +** See BugSplat: 98516 +*/ +#pragma pack(push) +#pragma pack(2) + +typedef unsigned short _ino_t; +typedef short _dev_t; +typedef long _off_t; + +typedef struct _MDMSStat { + _dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + _dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +} _MDMSStat; +#pragma pack(pop) + +/* --- Errors --- */ + /* These are NSPR generated error codes which need to be unique from + * OS error codes. + */ +#define _MD_UNIQUEBASE 50000 +#define _MD_EINTERRUPTED _MD_UNIQUEBASE + 1 +#define _MD_ETIMEDOUT _MD_UNIQUEBASE + 2 +#define _MD_EIO _MD_UNIQUEBASE + 3 + +struct PRProcess; +struct PRProcessAttr; + +/* --- Create a new process --- */ +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + + +/* --- Misc stuff --- */ + +#define MD_ASSERTINT( x ) PR_ASSERT( (x) < 65535 ) + +/* --- IO stuff --- */ +#define MAX_PATH 256 +#define _MD_ERRNO() errno +#define GetLastError() errno + +#define _MD_GET_FILE_ERROR() errno +#define _MD_SET_FILE_ERROR(_err) errno = (_err) + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +#define _MD_CLOSE_FILE _PR_MD_CLOSE_FILE +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + + +/* --- Socket IO stuff --- */ +#define _MD_EACCES WSAEACCES +#define _MD_EADDRINUSE WSAEADDRINUSE +#define _MD_EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define _MD_EAFNOSUPPORT WSAEAFNOSUPPORT +#define _MD_EAGAIN WSAEWOULDBLOCK +#define _MD_EALREADY WSAEALREADY +#define _MD_EBADF WSAEBADF +#define _MD_ECONNREFUSED WSAECONNREFUSED +#define _MD_ECONNRESET WSAECONNRESET +#define _MD_EFAULT WSAEFAULT +#define _MD_EINPROGRESS WSAEINPROGRESS +#define _MD_EINTR WSAEINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN WSAEISCONN +#define _MD_ENETUNREACH WSAENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN WSAENOTCONN +#define _MD_ENOTSOCK WSAENOTSOCK +#define _MD_EOPNOTSUPP WSAEOPNOTSUPP +#define _MD_EWOULDBLOCK WSAEWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +#define _MD_MAKE_NONBLOCK _PR_MD_MAKE_NONBLOCK +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +#define _MD_CLOSE_SOCKET _PR_MD_CLOSE_SOCKET +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SELECT select +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SOCKETAVAILABLE _PR_MD_SOCKETAVAILABLE + +#define _MD_INIT_ATOMIC() +#define _MD_ATOMIC_INCREMENT(x) (*x++) +#define _MD_ATOMIC_ADD(ptr, val) ((*x) += val) +#define _MD_ATOMIC_DECREMENT(x) (*x--) +#define _MD_ATOMIC_SET(x,y) (*x, y) + +#define _MD_INIT_IO _PR_MD_INIT_IO + +/* win95 doesn't have async IO */ +#define _MD_SOCKET _PR_MD_SOCKET +#define _MD_CONNECT _PR_MD_CONNECT +#define _MD_ACCEPT _PR_MD_ACCEPT +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND + +#define _MD_CHECK_FOR_EXIT() + +/* --- Scheduler stuff --- */ +#define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT _MD_AllocSegment +#define _MD_FREE_SEGMENT _MD_FreeSegment + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 32767L +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD(t,f,p,sc,st,stsiz) (PR_SUCCESS) +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY(t,p) +#define _MD_CLEAN_THREAD(t) +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +/* +** Win16 does not need MD locks. +*/ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +#define _MD_NEW_LOCK(l) (PR_SUCCESS) +#define _MD_FREE_LOCK(l) +#define _MD_LOCK(l) +#define _MD_TEST_AND_LOCK(l) (-1) +#define _MD_UNLOCK(l) + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER(a) +#define _MD_WAKEUP_CPUS _PR_MD_WAKEUP_CPUS + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV _PR_MD_WAIT_CV +#define _MD_NEW_CV _PR_MD_NEW_CV +#define _MD_FREE_CV _PR_MD_FREE_CV +#define _MD_NOTIFY_CV _PR_MD_NOTIFY_CV +#define _MD_NOTIFYALL_CV _PR_MD_NOTIFYALL_CV + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +NSPR_API(void) _MD_INIT_RUNNING_CPU(struct _PRCPU *cpu ); +#define _MD_START_INTERRUPTS() +#define _MD_STOP_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_EARLY_INIT _PR_MD_EARLY_INIT +#define _MD_FINAL_INIT _PR_MD_FINAL_INIT +#define _MD_INIT_CPUS() + +/* --- User Threading stuff --- */ +#define _MD_EXIT + +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK _PR_MD_INIT_STACK +#define _MD_CLEAR_STACK(stack) + +/* +** Watcom needs to see this to make the linker work. +** +*/ +NSPR_API(void) _PR_NativeDestroyThread(PRThread *thread); +NSPR_API(void) _PR_UserDestroyThread(PRThread *thread); + + +/* +** If thread emulation is used, then setjmp/longjmp stores the register +** state of each thread. +** +** CatchBuf layout: +** context[0] - IP +** context[1] - CS +** context[2] - SP +** context[3] - BP +** context[4] - SI +** context[5] - DI +** context[6] - DS +** context[7] - ?? (maybe flags) +** context[8] - SS +*/ +#define PR_CONTEXT_TYPE CATCHBUF +#define PR_NUM_GCREGS 9 + +#define _MD_GET_SP(thread) ((thread)->md.SP) +#define CONTEXT(_t) ((_t)->md.context) + +/* +** Initialize a thread context to run "e(o,a)" when started +*/ +#define _MD_INIT_CONTEXT(_t, sp, epa, stat ) \ +{ \ + *(stat) = PR_TRUE; \ + Catch((_t)->md.context ); \ + (_t)->md.context[0] = OFFSETOF(epa); \ + (_t)->md.context[1] = SELECTOROF(epa); \ + (_t)->md.context[2] = OFFSETOF(_pr_top_of_task_stack - 64); \ + (_t)->md.context[3] = 0; \ +} + +#define _MD_SWITCH_CONTEXT(_t) \ + if (!Catch((_t)->md.context)) { \ + int garbCollPlaceHolder; \ + (_t)->md.errcode = errno; \ + (_t)->md.SP = &garbCollPlaceHolder; \ + _PR_Schedule(); \ + } + +#define _MD_SAVE_CONTEXT(_t) \ + { \ + int garbCollPlaceHolder; \ + Catch((_t)->md.context); \ + (_t)->md.errcode = errno; \ + (_t)->md.SP = &garbCollPlaceHolder; \ + } + +/* +** Restore a thread context, saved by _MD_SWITCH_CONTEXT +*/ +#define _PR_MD_RESTORE_CONTEXT _MD_RESTORE_CONTEXT + +/* + * Memory-mapped files + */ + +struct _MDFileMap { + PRInt8 unused; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + + +/* --- Error mapping ----------------------------------- */ +extern void _PR_MD_map_error( int err ); + +#define _PR_MD_MAP_OPENDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CLOSEDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_READDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_DELETE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_STAT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_FSTAT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RENAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCESS_ERROR _PR_MD_map_error +#define _PR_MD_MAP_MKDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RMDIR_ERROR _PR_MD_map_error +#define _PR_MD_MAP_READ_ERROR _PR_MD_map_error +#define _PR_MD_MAP_TRANSMITFILE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_WRITE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LSEEK_ERROR _PR_MD_map_error +#define _PR_MD_MAP_FSYNC_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CLOSE_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SOCKET_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RECV_ERROR _PR_MD_map_error +#define _PR_MD_MAP_RECVFROM_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SEND_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SENDTO_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCEPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_ACCEPTEX_ERROR _PR_MD_map_error +#define _PR_MD_MAP_CONNECT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_BIND_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LISTEN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SHUTDOWN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETSOCKNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETPEERNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETSOCKOPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SETSOCKOPT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_OPEN_ERROR _PR_MD_map_error +#define _PR_MD_MAP_GETHOSTNAME_ERROR _PR_MD_map_error +#define _PR_MD_MAP_SELECT_ERROR _PR_MD_map_error +#define _PR_MD_MAP_LOCKF_ERROR _PR_MD_map_error +#define _PR_MD_MAP_WSASTARTUP_ERROR _PR_MD_map_error + +#endif /* nspr_win16_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_win32_errors.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win32_errors.h new file mode 100644 index 00000000..d5d8b714 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win32_errors.h @@ -0,0 +1,154 @@ +/* -*- 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_win32_errors_h___ +#define nspr_win32_errors_h___ + +#include +#include +#include + + +extern void _MD_win32_map_default_error(PRInt32 err); +#define _PR_MD_MAP_DEFAULT_ERROR _MD_win32_map_default_error + +extern void _MD_win32_map_opendir_error(PRInt32 err); +#define _PR_MD_MAP_OPENDIR_ERROR _MD_win32_map_opendir_error + +extern void _MD_win32_map_closedir_error(PRInt32 err); +#define _PR_MD_MAP_CLOSEDIR_ERROR _MD_win32_map_closedir_error + +extern void _MD_unix_readdir_error(PRInt32 err); +#define _PR_MD_MAP_READDIR_ERROR _MD_unix_readdir_error + +extern void _MD_win32_map_delete_error(PRInt32 err); +#define _PR_MD_MAP_DELETE_ERROR _MD_win32_map_delete_error + +extern void _MD_win32_map_stat_error(PRInt32 err); +#define _PR_MD_MAP_STAT_ERROR _MD_win32_map_stat_error + +extern void _MD_win32_map_fstat_error(PRInt32 err); +#define _PR_MD_MAP_FSTAT_ERROR _MD_win32_map_fstat_error + +extern void _MD_win32_map_rename_error(PRInt32 err); +#define _PR_MD_MAP_RENAME_ERROR _MD_win32_map_rename_error + +extern void _MD_win32_map_access_error(PRInt32 err); +#define _PR_MD_MAP_ACCESS_ERROR _MD_win32_map_access_error + +extern void _MD_win32_map_mkdir_error(PRInt32 err); +#define _PR_MD_MAP_MKDIR_ERROR _MD_win32_map_mkdir_error + +extern void _MD_win32_map_rmdir_error(PRInt32 err); +#define _PR_MD_MAP_RMDIR_ERROR _MD_win32_map_rmdir_error + +extern void _MD_win32_map_read_error(PRInt32 err); +#define _PR_MD_MAP_READ_ERROR _MD_win32_map_read_error + +extern void _MD_win32_map_transmitfile_error(PRInt32 err); +#define _PR_MD_MAP_TRANSMITFILE_ERROR _MD_win32_map_transmitfile_error + +extern void _MD_win32_map_write_error(PRInt32 err); +#define _PR_MD_MAP_WRITE_ERROR _MD_win32_map_write_error + +extern void _MD_win32_map_lseek_error(PRInt32 err); +#define _PR_MD_MAP_LSEEK_ERROR _MD_win32_map_lseek_error + +extern void _MD_win32_map_fsync_error(PRInt32 err); +#define _PR_MD_MAP_FSYNC_ERROR _MD_win32_map_fsync_error + +extern void _MD_win32_map_close_error(PRInt32 err); +#define _PR_MD_MAP_CLOSE_ERROR _MD_win32_map_close_error + +extern void _MD_win32_map_socket_error(PRInt32 err); +#define _PR_MD_MAP_SOCKET_ERROR _MD_win32_map_socket_error + +extern void _MD_win32_map_recv_error(PRInt32 err); +#define _PR_MD_MAP_RECV_ERROR _MD_win32_map_recv_error + +extern void _MD_win32_map_recvfrom_error(PRInt32 err); +#define _PR_MD_MAP_RECVFROM_ERROR _MD_win32_map_recvfrom_error + +extern void _MD_win32_map_send_error(PRInt32 err); +#define _PR_MD_MAP_SEND_ERROR _MD_win32_map_send_error + +extern void _MD_win32_map_sendto_error(PRInt32 err); +#define _PR_MD_MAP_SENDTO_ERROR _MD_win32_map_sendto_error + +extern void _MD_win32_map_accept_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPT_ERROR _MD_win32_map_accept_error + +extern void _MD_win32_map_acceptex_error(PRInt32 err); +#define _PR_MD_MAP_ACCEPTEX_ERROR _MD_win32_map_acceptex_error + +extern PRInt32 _MD_win32_map_connect_error(PRInt32 err); +#define _PR_MD_MAP_CONNECT_ERROR _MD_win32_map_connect_error + +extern void _MD_win32_map_bind_error(PRInt32 err); +#define _PR_MD_MAP_BIND_ERROR _MD_win32_map_bind_error + +extern void _MD_win32_map_listen_error(PRInt32 err); +#define _PR_MD_MAP_LISTEN_ERROR _MD_win32_map_listen_error + +extern void _MD_win32_map_shutdown_error(PRInt32 err); +#define _PR_MD_MAP_SHUTDOWN_ERROR _MD_win32_map_shutdown_error + +extern void _MD_win32_map_getsockname_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKNAME_ERROR _MD_win32_map_getsockname_error + +extern void _MD_win32_map_getpeername_error(PRInt32 err); +#define _PR_MD_MAP_GETPEERNAME_ERROR _MD_win32_map_getpeername_error + +extern void _MD_win32_map_getsockopt_error(PRInt32 err); +#define _PR_MD_MAP_GETSOCKOPT_ERROR _MD_win32_map_getsockopt_error + +extern void _MD_win32_map_setsockopt_error(PRInt32 err); +#define _PR_MD_MAP_SETSOCKOPT_ERROR _MD_win32_map_setsockopt_error + +extern void _MD_win32_map_open_error(PRInt32 err); +#define _PR_MD_MAP_OPEN_ERROR _MD_win32_map_open_error + +extern void _MD_win32_map_gethostname_error(PRInt32 err); +#define _PR_MD_MAP_GETHOSTNAME_ERROR _MD_win32_map_gethostname_error + +extern void _MD_win32_map_select_error(PRInt32 err); +#define _PR_MD_MAP_SELECT_ERROR _MD_win32_map_select_error + +extern void _MD_win32_map_lockf_error(int err); +#define _PR_MD_MAP_LOCKF_ERROR _MD_win32_map_lockf_error + +#endif /* nspr_win32_errors_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.cfg new file mode 100644 index 00000000..310fff89 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.cfg @@ -0,0 +1,200 @@ +/* -*- 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_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WIN95 +#define WIN95 +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 2 + +#elif defined(_ALPHA_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#define HAVE_LONG_LONG + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.h new file mode 100644 index 00000000..4e61fdf3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_win95.h @@ -0,0 +1,533 @@ +/* -*- 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_win95_defs_h___ +#define nspr_win95_defs_h___ + +#include "prio.h" + +#include +#include +#include + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win32" +#define _PR_SI_SYSNAME "WIN95" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#undef HAVE_THREAD_AFFINITY +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifndef _PR_INET6 +#define AF_INET6 23 +/* newer ws2tcpip.h provides these */ +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x2 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#endif +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS +#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 +#define _MD_MAGIC_CV 0x66666666 + +struct _MDCPU { + int unused; +}; + +struct _MDThread { + HANDLE blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRBool inCVWaitQueue; /* PR_TRUE if the thread is in the + * wait queue of some cond var. + * PR_FALSE otherwise. */ + HANDLE handle; /* Win32 thread handle */ + PRUint32 id; + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct PRThread *prev, *next; /* used by the cvar wait queue to + * chain the PRThread structures + * together */ + void (*start)(void *); /* used by _PR_MD_CREATE_THREAD to + * pass its 'start' argument to + * pr_root. */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDDir { + HANDLE d_hdl; + WIN32_FIND_DATA d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +#ifdef MOZ_UNICODE +struct _MDDirUTF16 { + HANDLE d_hdl; + WIN32_FIND_DATAW d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFileW()? */ + PRUint32 magic; /* for debugging */ +}; +#endif /* MOZ_UNICODE */ + +struct _MDCVar { + PRUint32 magic; + struct PRThread *waitHead, *waitTail; /* the wait queue: a doubly- + * linked list of threads + * waiting on this condition + * variable */ + PRIntn nwait; /* number of threads in the + * wait queue */ +}; + +#define _MD_CV_NOTIFIED_LENGTH 6 +typedef struct _MDNotified _MDNotified; +struct _MDNotified { + PRIntn length; /* # of used entries in this + * structure */ + struct { + struct _MDCVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + struct PRThread *notifyHead; /* list of threads to wake up */ + } cv[_MD_CV_NOTIFIED_LENGTH]; + _MDNotified *link; /* link to another of these, or NULL */ +}; + +struct _MDLock { + CRITICAL_SECTION mutex; /* this is recursive on NT */ + + /* + * When notifying cvars, there is no point in actually + * waking up the threads waiting on the cvars until we've + * released the lock. So, we temporarily record the cvars. + * When doing an unlock, we'll then wake up the waiting threads. + */ + struct _MDNotified notified; /* array of conditions notified */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDSemaphore { + HANDLE sem; +}; + +struct _MDFileDesc { + PRInt32 osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using Win32 HANDLE, + * which is a void*. + * - For sockets, we are using Winsock SOCKET, which + * is a u_int. + */ +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- NT security stuff --- */ + +extern void _PR_NT_InitSids(void); +extern void _PR_NT_FreeSids(void); +extern PRStatus _PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL +); +extern void _PR_NT_FreeSecurityDescriptorACL( + PSECURITY_DESCRIPTOR pSD, PACL pACL); + +/* --- IO stuff --- */ + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_OPEN_FILE _PR_MD_OPEN_FILE +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +extern PRInt32 _MD_CloseFile(PRInt32 osfd); +#define _MD_CLOSE_FILE _MD_CloseFile +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETFILEINFO64 _PR_MD_GETFILEINFO64 +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_GETOPENFILEINFO64 _PR_MD_GETOPENFILEINFO64 +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_MAKE_DIR _PR_MD_MAKE_DIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + +#ifdef MOZ_UNICODE +/* --- UTF16 IO stuff --- */ +#define _MD_OPEN_FILE_UTF16 _PR_MD_OPEN_FILE_UTF16 +#define _MD_OPEN_DIR_UTF16 _PR_MD_OPEN_DIR_UTF16 +#define _MD_READ_DIR_UTF16 _PR_MD_READ_DIR_UTF16 +#define _MD_CLOSE_DIR_UTF16 _PR_MD_CLOSE_DIR_UTF16 +#define _MD_GETFILEINFO64_UTF16 _PR_MD_GETFILEINFO64_UTF16 +#endif /* MOZ_UNICODE */ + +/* --- Socket IO stuff --- */ +#define _MD_EACCES WSAEACCES +#define _MD_EADDRINUSE WSAEADDRINUSE +#define _MD_EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define _MD_EAFNOSUPPORT WSAEAFNOSUPPORT +#define _MD_EAGAIN WSAEWOULDBLOCK +#define _MD_EALREADY WSAEALREADY +#define _MD_EBADF WSAEBADF +#define _MD_ECONNREFUSED WSAECONNREFUSED +#define _MD_ECONNRESET WSAECONNRESET +#define _MD_EFAULT WSAEFAULT +#define _MD_EINPROGRESS WSAEINPROGRESS +#define _MD_EINTR WSAEINTR +#define _MD_EINVAL EINVAL +#define _MD_EISCONN WSAEISCONN +#define _MD_ENETUNREACH WSAENETUNREACH +#define _MD_ENOENT ENOENT +#define _MD_ENOTCONN WSAENOTCONN +#define _MD_ENOTSOCK WSAENOTSOCK +#define _MD_EOPNOTSUPP WSAEOPNOTSUPP +#define _MD_EWOULDBLOCK WSAEWOULDBLOCK +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +extern void _MD_MakeNonblock(PRFileDesc *f); +#define _MD_MAKE_NONBLOCK _MD_MakeNonblock +#define _MD_INIT_FD_INHERITABLE _PR_MD_INIT_FD_INHERITABLE +#define _MD_QUERY_FD_INHERITABLE _PR_MD_QUERY_FD_INHERITABLE +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +extern PRInt32 _MD_CloseSocket(PRInt32 osfd); +#define _MD_CLOSE_SOCKET _MD_CloseSocket +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SET_FD_INHERITABLE _PR_MD_SET_FD_INHERITABLE +#define _MD_SELECT select +#define _MD_FSYNC _PR_MD_FSYNC +#define READ_FD 1 +#define WRITE_FD 2 + +#define _MD_INIT_ATOMIC() +#if defined(_M_IX86) || defined(_X86_) +#define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD +#define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT +#else /* non-x86 processors */ +#define _MD_ATOMIC_INCREMENT(x) InterlockedIncrement((PLONG)x) +#define _MD_ATOMIC_ADD(ptr,val) (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val) +#define _MD_ATOMIC_DECREMENT(x) InterlockedDecrement((PLONG)x) +#endif /* x86 */ +#define _MD_ATOMIC_SET(x,y) InterlockedExchange((PLONG)x, (LONG)y) + +#define _MD_INIT_IO _PR_MD_INIT_IO + + +/* win95 doesn't have async IO */ +#define _MD_SOCKET _PR_MD_SOCKET +extern PRInt32 _MD_SocketAvailable(PRFileDesc *fd); +#define _MD_SOCKETAVAILABLE _MD_SocketAvailable +#define _MD_PIPEAVAILABLE _PR_MD_PIPEAVAILABLE +#define _MD_CONNECT _PR_MD_CONNECT +extern PRInt32 _MD_Accept(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout); +#define _MD_ACCEPT _MD_Accept +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND +#define _MD_PR_POLL _PR_MD_PR_POLL + +/* --- Scheduler stuff --- */ +// #define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU +#define _MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() GetLastError() +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 0 +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_INIT_ATTACHED_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD _PR_MD_CREATE_THREAD +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY _PR_MD_SET_PRIORITY +#define _MD_CLEAN_THREAD _PR_MD_CLEAN_THREAD +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD _PR_MD_EXIT_THREAD +#define _MD_EXIT _PR_MD_EXIT +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +/* --- Lock stuff --- */ +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +#define _MD_NEW_LOCK(lock) (InitializeCriticalSection(&((lock)->mutex)),(lock)->notified.length=0,(lock)->notified.link=NULL,PR_SUCCESS) +#define _MD_FREE_LOCK(lock) DeleteCriticalSection(&((lock)->mutex)) +#define _MD_LOCK(lock) EnterCriticalSection(&((lock)->mutex)) +#define _MD_TEST_AND_LOCK(lock) (EnterCriticalSection(&((lock)->mutex)),0) +#define _MD_UNLOCK _PR_MD_UNLOCK + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER _PR_MD_WAKEUP_WAITER + +/* --- CVar ------------------- */ +#define _MD_WAIT_CV _PR_MD_WAIT_CV +#define _MD_NEW_CV _PR_MD_NEW_CV +#define _MD_FREE_CV _PR_MD_FREE_CV +#define _MD_NOTIFY_CV _PR_MD_NOTIFY_CV +#define _MD_NOTIFYALL_CV _PR_MD_NOTIFYALL_CV + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +// extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() +#define _MD_IOQ_UNLOCK() + + +/* --- Initialization stuff --- */ +#define _MD_START_INTERRUPTS() +#define _MD_STOP_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_EARLY_INIT _PR_MD_EARLY_INIT +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT +#define _MD_INIT_CONTEXT(_thread, _sp, _main, status) \ + PR_BEGIN_MACRO \ + *status = PR_TRUE; \ + PR_END_MACRO +#define _MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Time --- */ +extern void _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm); + +/* --- Native-Thread Specific Definitions ------------------------------- */ + +extern struct PRThread * _MD_CURRENT_THREAD(void); + +#ifdef _PR_USE_STATIC_TLS +extern __declspec(thread) struct PRThread *_pr_currentThread; +#define _MD_GET_ATTACHED_THREAD() _pr_currentThread +#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread)) + +extern __declspec(thread) struct PRThread *_pr_thread_last_run; +#define _MD_LAST_THREAD() _pr_thread_last_run +#define _MD_SET_LAST_THREAD(_thread) (_pr_thread_last_run = 0) + +extern __declspec(thread) struct _PRCPU *_pr_currentCPU; +#define _MD_CURRENT_CPU() _pr_currentCPU +#define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = 0) +#else /* _PR_USE_STATIC_TLS */ +extern DWORD _pr_currentThreadIndex; +#define _MD_GET_ATTACHED_THREAD() ((PRThread *) TlsGetValue(_pr_currentThreadIndex)) +#define _MD_SET_CURRENT_THREAD(_thread) TlsSetValue(_pr_currentThreadIndex, (_thread)) + +extern DWORD _pr_lastThreadIndex; +#define _MD_LAST_THREAD() ((PRThread *) TlsGetValue(_pr_lastThreadIndex)) +#define _MD_SET_LAST_THREAD(_thread) TlsSetValue(_pr_lastThreadIndex, 0) + +extern DWORD _pr_currentCPUIndex; +#define _MD_CURRENT_CPU() ((struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex)) +#define _MD_SET_CURRENT_CPU(_cpu) TlsSetValue(_pr_currentCPUIndex, 0) +#endif /* _PR_USE_STATIC_TLS */ + +/* --- Scheduler stuff --- */ +#define LOCK_SCHEDULER() 0 +#define UNLOCK_SCHEDULER() 0 +#define _PR_LockSched() 0 +#define _PR_UnlockSched() 0 + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- */ + +struct _MDFileMap { + HANDLE hFileMap; + DWORD dwAccess; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* --- Named semaphores stuff --- */ +#define _PR_HAVE_NAMED_SEMAPHORES +#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE +#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE +#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE +#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE +#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */ + +#endif /* nspr_win32_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.cfg b/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.cfg new file mode 100644 index 00000000..ce077d33 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.cfg @@ -0,0 +1,200 @@ +/* -*- 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_PC +#define XP_PC +#endif + +#ifndef WIN32 +#define WIN32 +#endif + +#ifndef WINNT +#define WINNT +#endif + +#define PR_AF_INET6 23 /* same as AF_INET6 */ + +#if defined(_M_IX86) || defined(_X86_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 +#define PR_BYTES_PER_DOUBLE 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_WORD 32 +#define PR_BITS_PER_DWORD 64 +#define PR_BITS_PER_DOUBLE 64 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_WORD_LOG2 5 +#define PR_BITS_PER_DWORD_LOG2 6 +#define PR_BITS_PER_DOUBLE_LOG2 6 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_WORD 4 +#define PR_ALIGN_OF_DWORD 8 +#define PR_ALIGN_OF_DOUBLE 4 +#define PR_ALIGN_OF_POINTER 4 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 2 + +#elif defined(_ALPHA_) + +#define IS_LITTLE_ENDIAN 1 +#undef IS_BIG_ENDIAN + +#define PR_BYTES_PER_BYTE 1 +#define PR_BYTES_PER_SHORT 2 +#define PR_BYTES_PER_INT 4 +#define PR_BYTES_PER_INT64 8 +#define PR_BYTES_PER_LONG 4 +#define PR_BYTES_PER_FLOAT 4 +#define PR_BYTES_PER_DOUBLE 8 +#define PR_BYTES_PER_WORD 4 +#define PR_BYTES_PER_DWORD 8 + +#define PR_BITS_PER_BYTE 8 +#define PR_BITS_PER_SHORT 16 +#define PR_BITS_PER_INT 32 +#define PR_BITS_PER_INT64 64 +#define PR_BITS_PER_LONG 32 +#define PR_BITS_PER_FLOAT 32 +#define PR_BITS_PER_DOUBLE 64 +#define PR_BITS_PER_WORD 32 + +#define PR_BITS_PER_BYTE_LOG2 3 +#define PR_BITS_PER_SHORT_LOG2 4 +#define PR_BITS_PER_INT_LOG2 5 +#define PR_BITS_PER_INT64_LOG2 6 +#define PR_BITS_PER_LONG_LOG2 5 +#define PR_BITS_PER_FLOAT_LOG2 5 +#define PR_BITS_PER_DOUBLE_LOG2 6 +#define PR_BITS_PER_WORD_LOG2 5 + +#define PR_BYTES_PER_WORD_LOG2 2 +#define PR_BYTES_PER_DWORD_LOG2 3 + +#define PR_ALIGN_OF_SHORT 2 +#define PR_ALIGN_OF_INT 4 +#define PR_ALIGN_OF_LONG 4 +#define PR_ALIGN_OF_INT64 8 +#define PR_ALIGN_OF_FLOAT 4 +#define PR_ALIGN_OF_DOUBLE 8 +#define PR_ALIGN_OF_POINTER 4 + +#else /* defined(_M_IX86) || defined(_X86_) */ + +#error unknown processor architecture + +#endif /* defined(_M_IX86) || defined(_X86_) */ + +#define HAVE_LONG_LONG + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.h new file mode 100644 index 00000000..36cbcfae --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/_winnt.h @@ -0,0 +1,594 @@ +/* -*- 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_win32_defs_h___ +#define nspr_win32_defs_h___ + +/* Need to force service-pack 3 extensions to be defined by +** setting _WIN32_WINNT to NT 4.0 for winsock.h, winbase.h, winnt.h. +*/ +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#elif (_WIN32_WINNT < 0x0400) + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#endif /* _WIN32_WINNT */ + +#include +#include +#ifdef __MINGW32__ +#include +#endif +#include + +#include "prio.h" +#include "prclist.h" + +/* + * Internal configuration macros + */ + +#define PR_LINKER_ARCH "win32" +#define _PR_SI_SYSNAME "WINNT" +#define _PR_SI_ARCHITECTURE "x86" /* XXXMB hardcode for now */ + +#define HAVE_DLL +#define HAVE_CUSTOM_USER_THREADS +#define HAVE_THREAD_AFFINITY +#define _PR_HAVE_GETADDRINFO +#define _PR_INET6_PROBE +#ifndef _PR_INET6 +#define AF_INET6 23 +/* newer ws2tcpip.h provides these */ +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x2 +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct addrinfo *ai_next; +}; +#endif +#endif +#define _PR_HAVE_THREADSAFE_GETHOST +#define _PR_HAVE_ATOMIC_OPS +#define _PR_HAVE_ATOMIC_CAS +#define PR_HAVE_WIN32_NAMED_SHARED_MEMORY +#define _PR_HAVE_PEEK_BUFFER +#define _PR_PEEK_BUFFER_MAX (32 * 1024) +#define _PR_FD_NEED_EMULATE_MSG_PEEK(fd) \ + (!(fd)->secret->nonblocking && (fd)->secret->inheritable != _PR_TRI_TRUE) + +/* --- Common User-Thread/Native-Thread Definitions --------------------- */ + +/* --- Globals --- */ +extern struct PRLock *_pr_schedLock; + +/* --- Typedefs --- */ +typedef void (*FiberFunc)(void *); + +#define PR_NUM_GCREGS 8 +typedef PRInt32 PR_CONTEXT_TYPE[PR_NUM_GCREGS]; +#define GC_VMBASE 0x40000000 +#define GC_VMLIMIT 0x00FFFFFF + +#define _MD_MAGIC_THREAD 0x22222222 +#define _MD_MAGIC_THREADSTACK 0x33333333 +#define _MD_MAGIC_SEGMENT 0x44444444 +#define _MD_MAGIC_DIR 0x55555555 + +struct _MDCPU { + int unused; +}; + +enum _MDIOModel { + _MD_BlockingIO = 0x38, + _MD_MultiWaitIO = 0x49 +}; + +typedef struct _MDOverlapped { + OVERLAPPED overlapped; /* Used for async I/O */ + + enum _MDIOModel ioModel; /* The I/O model to implement + * using overlapped I/O. + */ + union { + struct _MDThread *mdThread; /* For blocking I/O, this structure + * is embedded in the _MDThread + * structure. + */ + struct { + PRCList links; /* for group->io_ready list */ + struct PRRecvWait *desc; /* For multiwait I/O, this structure + * is associated with a PRRecvWait + * structure. + */ + struct PRWaitGroup *group; + struct TimerEvent *timer; + DWORD error; + } mw; + } data; +} _MDOverlapped; + +struct _MDThread { + /* The overlapped structure must be first! */ + struct _MDOverlapped overlapped; /* Used for async IO for this thread */ + void *acceptex_buf; /* Used for AcceptEx() */ + TRANSMIT_FILE_BUFFERS *xmit_bufs; /* Used for TransmitFile() */ + HANDLE blocked_sema; /* Threads block on this when waiting + * for IO or CondVar. + */ + PRInt32 blocked_io_status; /* Status of the completed IO */ + PRInt32 blocked_io_bytes; /* Bytes transferred for completed IO */ + PRInt32 blocked_io_error; /* Save error if status is FALSE */ + HANDLE handle; + PRUint32 id; + void *sp; /* only valid when suspended */ + PRUint32 magic; /* for debugging */ + PR_CONTEXT_TYPE gcContext; /* Thread context for GC */ + struct _PRCPU *thr_bound_cpu; /* thread bound to cpu */ + PRBool interrupt_disabled;/* thread cannot be interrupted */ + HANDLE thr_event; /* For native-threads-only support, + thread blocks on this event */ + + /* The following are used only if this is a fiber */ + void *fiber_id; /* flag whether or not this is a fiber*/ + FiberFunc fiber_fn; /* main fiber routine */ + void *fiber_arg; /* arg to main fiber routine */ + PRUint32 fiber_stacksize; /* stacksize for fiber */ + PRInt32 fiber_last_error; /* last error for the fiber */ + void (*start)(void *); /* used by _PR_MD_CREATE_THREAD to + * pass its 'start' argument to + * pr_root. */ +}; + +struct _MDThreadStack { + PRUint32 magic; /* for debugging */ +}; + +struct _MDSegment { + PRUint32 magic; /* for debugging */ +}; + +#undef PROFILE_LOCKS + +struct _MDLock { + CRITICAL_SECTION mutex; /* this is recursive on NT */ +#ifdef PROFILE_LOCKS + PRInt32 hitcount; + PRInt32 misscount; +#endif +}; + +struct _MDDir { + HANDLE d_hdl; + WIN32_FIND_DATA d_entry; + PRBool firstEntry; /* Is this the entry returned + * by FindFirstFile()? */ + PRUint32 magic; /* for debugging */ +}; + +struct _MDCVar { + PRUint32 unused; +}; + +struct _MDSemaphore { + HANDLE sem; +}; + +struct _MDFileDesc { + PRInt32 osfd; /* The osfd can come from one of three spaces: + * - For stdin, stdout, and stderr, we are using + * the libc file handle (0, 1, 2), which is an int. + * - For files and pipes, we are using Win32 HANDLE, + * which is a void*. + * - For sockets, we are using Winsock SOCKET, which + * is a u_int. + */ + PRBool io_model_committed; /* The io model (blocking or nonblocking) + * for this osfd has been committed and + * cannot be changed. The osfd has been + * either associated with the io + * completion port or made nonblocking. */ + PRBool sync_file_io; /* Use synchronous file I/O on the osfd + * (a file handle) */ + PRBool accepted_socket; /* Is this an accepted socket (on the + * server side)? */ + PRNetAddr peer_addr; /* If this is an accepted socket, cache + * the peer's address returned by + * AcceptEx(). This is to work around + * the bug that getpeername() on an + * socket accepted by AcceptEx() returns + * an all-zero net address. */ +}; + +struct _MDProcess { + HANDLE handle; + DWORD id; +}; + + +/* --- Misc stuff --- */ +#define _MD_GET_SP(thread) (thread)->md.gcContext[6] + +/* --- NT security stuff --- */ + +extern void _PR_NT_InitSids(void); +extern void _PR_NT_FreeSids(void); +extern PRStatus _PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL +); +extern void _PR_NT_FreeSecurityDescriptorACL( + PSECURITY_DESCRIPTOR pSD, PACL pACL); + +/* --- IO stuff --- */ + +extern PRInt32 _md_Associate(HANDLE); +extern PRInt32 _PR_MD_CLOSE(PRInt32 osfd, PRBool socket); + +#define _MD_OPEN _PR_MD_OPEN +#define _MD_OPEN_FILE _PR_MD_OPEN_FILE +#define _MD_READ _PR_MD_READ +#define _MD_WRITE _PR_MD_WRITE +#define _MD_WRITEV _PR_MD_WRITEV +#define _MD_LSEEK _PR_MD_LSEEK +#define _MD_LSEEK64 _PR_MD_LSEEK64 +#define _MD_CLOSE_FILE(f) _PR_MD_CLOSE(f, PR_FALSE) +#define _MD_GETFILEINFO _PR_MD_GETFILEINFO +#define _MD_GETFILEINFO64 _PR_MD_GETFILEINFO64 +#define _MD_GETOPENFILEINFO _PR_MD_GETOPENFILEINFO +#define _MD_GETOPENFILEINFO64 _PR_MD_GETOPENFILEINFO64 +#define _MD_STAT _PR_MD_STAT +#define _MD_RENAME _PR_MD_RENAME +#define _MD_ACCESS _PR_MD_ACCESS +#define _MD_DELETE _PR_MD_DELETE +#define _MD_MKDIR _PR_MD_MKDIR +#define _MD_MAKE_DIR _PR_MD_MAKE_DIR +#define _MD_RMDIR _PR_MD_RMDIR +#define _MD_LOCKFILE _PR_MD_LOCKFILE +#define _MD_TLOCKFILE _PR_MD_TLOCKFILE +#define _MD_UNLOCKFILE _PR_MD_UNLOCKFILE + +/* --- Socket IO stuff --- */ +#define _MD_GET_SOCKET_ERROR() WSAGetLastError() +#define _MD_SET_SOCKET_ERROR(_err) WSASetLastError(_err) + +#define _MD_INIT_FILEDESC(fd) +#define _MD_MAKE_NONBLOCK _PR_MD_MAKE_NONBLOCK +#define _MD_INIT_FD_INHERITABLE _PR_MD_INIT_FD_INHERITABLE +#define _MD_QUERY_FD_INHERITABLE _PR_MD_QUERY_FD_INHERITABLE +#define _MD_SHUTDOWN _PR_MD_SHUTDOWN +#define _MD_LISTEN _PR_MD_LISTEN +#define _MD_CLOSE_SOCKET(s) _PR_MD_CLOSE(s, PR_TRUE) +#define _MD_SENDTO _PR_MD_SENDTO +#define _MD_RECVFROM _PR_MD_RECVFROM +#define _MD_SOCKETPAIR(s, type, proto, sv) -1 +#define _MD_GETSOCKNAME _PR_MD_GETSOCKNAME +#define _MD_GETPEERNAME _PR_MD_GETPEERNAME +#define _MD_GETSOCKOPT _PR_MD_GETSOCKOPT +#define _MD_SETSOCKOPT _PR_MD_SETSOCKOPT +#define _MD_SELECT select +extern int _PR_NTFiberSafeSelect(int, fd_set *, fd_set *, fd_set *, + const struct timeval *); +#define _MD_FSYNC _PR_MD_FSYNC +#define _MD_SOCKETAVAILABLE _PR_MD_SOCKETAVAILABLE +#define _MD_PIPEAVAILABLE _PR_MD_PIPEAVAILABLE +#define _MD_SET_FD_INHERITABLE _PR_MD_SET_FD_INHERITABLE + +#define _MD_INIT_ATOMIC() +#if defined(_M_IX86) || defined(_X86_) +#define _MD_ATOMIC_INCREMENT _PR_MD_ATOMIC_INCREMENT +#define _MD_ATOMIC_ADD _PR_MD_ATOMIC_ADD +#define _MD_ATOMIC_DECREMENT _PR_MD_ATOMIC_DECREMENT +#else /* non-x86 processors */ +#define _MD_ATOMIC_INCREMENT(x) InterlockedIncrement((PLONG)x) +#define _MD_ATOMIC_ADD(ptr,val) (InterlockedExchangeAdd((PLONG)ptr, (LONG)val) + val) +#define _MD_ATOMIC_DECREMENT(x) InterlockedDecrement((PLONG)x) +#endif /* x86 */ +#define _MD_ATOMIC_SET(x,y) InterlockedExchange((PLONG)x, (LONG)y) + +#define _MD_INIT_IO _PR_MD_INIT_IO +#define _MD_SOCKET _PR_MD_SOCKET +#define _MD_CONNECT _PR_MD_CONNECT + +#define _MD_ACCEPT(s, a, l, to) \ + _MD_FAST_ACCEPT(s, a, l, to, PR_FALSE, NULL, NULL) +#define _MD_FAST_ACCEPT(s, a, l, to, fast, cb, cba) \ + _PR_MD_FAST_ACCEPT(s, a, l, to, fast, cb, cba) +#define _MD_ACCEPT_READ(s, ns, ra, buf, l, t) \ + _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, PR_FALSE, NULL, NULL) +#define _MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba) \ + _PR_MD_FAST_ACCEPT_READ(s, ns, ra, buf, l, t, fast, cb, cba) +#define _MD_UPDATE_ACCEPT_CONTEXT _PR_MD_UPDATE_ACCEPT_CONTEXT + +#define _MD_BIND _PR_MD_BIND +#define _MD_RECV _PR_MD_RECV +#define _MD_SEND _PR_MD_SEND +#define _MD_SENDFILE _PR_MD_SENDFILE +#define _MD_PR_POLL _PR_MD_PR_POLL + +/* --- Scheduler stuff --- */ +#define _MD_PAUSE_CPU _PR_MD_PAUSE_CPU + +/* --- DIR stuff --- */ +#define PR_DIRECTORY_SEPARATOR '\\' +#define PR_DIRECTORY_SEPARATOR_STR "\\" +#define PR_PATH_SEPARATOR ';' +#define PR_PATH_SEPARATOR_STR ";" +#define _MD_ERRNO() GetLastError() +#define _MD_OPEN_DIR _PR_MD_OPEN_DIR +#define _MD_CLOSE_DIR _PR_MD_CLOSE_DIR +#define _MD_READ_DIR _PR_MD_READ_DIR + +/* --- Segment stuff --- */ +#define _MD_INIT_SEGS() +#define _MD_ALLOC_SEGMENT(seg, size, vaddr) 0 +#define _MD_FREE_SEGMENT(seg) + +/* --- Environment Stuff --- */ +#define _MD_GET_ENV _PR_MD_GET_ENV +#define _MD_PUT_ENV _PR_MD_PUT_ENV + +/* --- Threading Stuff --- */ +#define _MD_DEFAULT_STACK_SIZE 0 +#define _MD_INIT_THREAD _PR_MD_INIT_THREAD +#define _MD_INIT_ATTACHED_THREAD _PR_MD_INIT_THREAD +#define _MD_CREATE_THREAD _PR_MD_CREATE_THREAD +#define _MD_JOIN_THREAD _PR_MD_JOIN_THREAD +#define _MD_END_THREAD _PR_MD_END_THREAD +#define _MD_YIELD _PR_MD_YIELD +#define _MD_SET_PRIORITY _PR_MD_SET_PRIORITY +#define _MD_CLEAN_THREAD _PR_MD_CLEAN_THREAD +#define _MD_SETTHREADAFFINITYMASK _PR_MD_SETTHREADAFFINITYMASK +#define _MD_GETTHREADAFFINITYMASK _PR_MD_GETTHREADAFFINITYMASK +#define _MD_EXIT_THREAD _PR_MD_EXIT_THREAD +#define _MD_SUSPEND_THREAD _PR_MD_SUSPEND_THREAD +#define _MD_RESUME_THREAD _PR_MD_RESUME_THREAD +#define _MD_SUSPEND_CPU _PR_MD_SUSPEND_CPU +#define _MD_RESUME_CPU _PR_MD_RESUME_CPU +#define _MD_BEGIN_SUSPEND_ALL() +#define _MD_BEGIN_RESUME_ALL() +#define _MD_END_SUSPEND_ALL() +#define _MD_END_RESUME_ALL() + +extern void _PR_Unblock_IO_Wait(PRThread *thr); + +/* --- Lock stuff --- */ +#define _MD_NEW_LOCK(lock) (InitializeCriticalSection(&((lock)->mutex)),PR_SUCCESS) +#define _MD_FREE_LOCK(lock) DeleteCriticalSection(&((lock)->mutex)) +#ifndef PROFILE_LOCKS +#define _MD_LOCK(lock) EnterCriticalSection(&((lock)->mutex)) +#define _MD_TEST_AND_LOCK(lock) (TryEnterCriticalSection(&((lock)->mutex))== FALSE) +#define _MD_UNLOCK(lock) LeaveCriticalSection(&((lock)->mutex)) +#else +#define _MD_LOCK(lock) \ + PR_BEGIN_MACRO \ + BOOL rv = TryEnterCriticalSection(&((lock)->mutex)); \ + if (rv == TRUE) { \ + InterlockedIncrement(&((lock)->hitcount)); \ + } else { \ + InterlockedIncrement(&((lock)->misscount)); \ + EnterCriticalSection(&((lock)->mutex)); \ + } \ + PR_END_MACRO +#define _MD_TEST_AND_LOCK(lock) 0 /* XXXMB */ +#define _MD_UNLOCK(lock) LeaveCriticalSection(&((lock)->mutex)) +#endif +#define _PR_LOCK _MD_LOCK +#define _PR_UNLOCK _MD_UNLOCK + +/* --- lock and cv waiting --- */ +#define _MD_WAIT _PR_MD_WAIT +#define _MD_WAKEUP_WAITER _PR_MD_WAKEUP_WAITER + + /* XXXMB- the IOQ stuff is certainly not working correctly yet. */ +extern struct _MDLock _pr_ioq_lock; +#define _MD_IOQ_LOCK() _MD_LOCK(&_pr_ioq_lock) +#define _MD_IOQ_UNLOCK() _MD_UNLOCK(&_pr_ioq_lock) + + +/* --- Initialization stuff --- */ +#define _MD_START_INTERRUPTS() +#define _MD_STOP_INTERRUPTS() +#define _MD_DISABLE_CLOCK_INTERRUPTS() +#define _MD_ENABLE_CLOCK_INTERRUPTS() +#define _MD_BLOCK_CLOCK_INTERRUPTS() +#define _MD_UNBLOCK_CLOCK_INTERRUPTS() +#define _MD_EARLY_INIT _PR_MD_EARLY_INIT +#define _MD_FINAL_INIT() +#define _MD_INIT_CPUS() +#define _MD_INIT_RUNNING_CPU(cpu) + +struct PRProcess; +struct PRProcessAttr; + +/* --- Create a new process --- */ +#define _MD_CREATE_PROCESS _PR_CreateWindowsProcess +extern struct PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const struct PRProcessAttr *attr +); + +#define _MD_DETACH_PROCESS _PR_DetachWindowsProcess +extern PRStatus _PR_DetachWindowsProcess(struct PRProcess *process); + +/* --- Wait for a child process to terminate --- */ +#define _MD_WAIT_PROCESS _PR_WaitWindowsProcess +extern PRStatus _PR_WaitWindowsProcess(struct PRProcess *process, + PRInt32 *exitCode); + +#define _MD_KILL_PROCESS _PR_KillWindowsProcess +extern PRStatus _PR_KillWindowsProcess(struct PRProcess *process); + +/* --- User Threading stuff --- */ +#define HAVE_FIBERS +#define _MD_CREATE_USER_THREAD _PR_MD_CREATE_USER_THREAD +#define _MD_CREATE_PRIMORDIAL_USER_THREAD _PR_MD_CREATE_PRIMORDIAL_USER_THREAD +#define _MD_CLEANUP_BEFORE_EXIT _PR_MD_CLEANUP_BEFORE_EXIT +#define _MD_EXIT _PR_MD_EXIT +#define _MD_INIT_CONTEXT _PR_MD_INIT_CONTEXT +#define _MD_SWITCH_CONTEXT _PR_MD_SWITCH_CONTEXT +#define _MD_RESTORE_CONTEXT _PR_MD_RESTORE_CONTEXT + +/* --- Intervals --- */ +#define _MD_INTERVAL_INIT _PR_MD_INTERVAL_INIT +#define _MD_GET_INTERVAL _PR_MD_GET_INTERVAL +#define _MD_INTERVAL_PER_SEC _PR_MD_INTERVAL_PER_SEC +#define _MD_INTERVAL_PER_MILLISEC() (_PR_MD_INTERVAL_PER_SEC() / 1000) +#define _MD_INTERVAL_PER_MICROSEC() (_PR_MD_INTERVAL_PER_SEC() / 1000000) + +/* --- Time --- */ +extern void _PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm); + +/* --- Native-Thread Specific Definitions ------------------------------- */ + +extern BOOL _pr_use_static_tls; + +extern __declspec(thread) struct PRThread *_pr_current_fiber; +extern DWORD _pr_currentFiberIndex; + +#define _MD_GET_ATTACHED_THREAD() \ + (_pr_use_static_tls ? _pr_current_fiber \ + : (PRThread *) TlsGetValue(_pr_currentFiberIndex)) + +extern struct PRThread * _MD_CURRENT_THREAD(void); + +#define _MD_SET_CURRENT_THREAD(_thread) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_current_fiber = (_thread); \ + } else { \ + TlsSetValue(_pr_currentFiberIndex, (_thread)); \ + } \ + PR_END_MACRO + +extern __declspec(thread) struct PRThread *_pr_fiber_last_run; +extern DWORD _pr_lastFiberIndex; + +#define _MD_LAST_THREAD() \ + (_pr_use_static_tls ? _pr_fiber_last_run \ + : (PRThread *) TlsGetValue(_pr_lastFiberIndex)) + +#define _MD_SET_LAST_THREAD(_thread) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_fiber_last_run = (_thread); \ + } else { \ + TlsSetValue(_pr_lastFiberIndex, (_thread)); \ + } \ + PR_END_MACRO + +extern __declspec(thread) struct _PRCPU *_pr_current_cpu; +extern DWORD _pr_currentCPUIndex; + +#define _MD_CURRENT_CPU() \ + (_pr_use_static_tls ? _pr_current_cpu \ + : (struct _PRCPU *) TlsGetValue(_pr_currentCPUIndex)) + +#define _MD_SET_CURRENT_CPU(_cpu) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_current_cpu = (_cpu); \ + } else { \ + TlsSetValue(_pr_currentCPUIndex, (_cpu)); \ + } \ + PR_END_MACRO + +extern __declspec(thread) PRUintn _pr_ints_off; +extern DWORD _pr_intsOffIndex; + +#define _MD_GET_INTSOFF() \ + (_pr_use_static_tls ? _pr_ints_off \ + : (PRUintn) TlsGetValue(_pr_intsOffIndex)) + +#define _MD_SET_INTSOFF(_val) \ + PR_BEGIN_MACRO \ + if (_pr_use_static_tls) { \ + _pr_ints_off = (_val); \ + } else { \ + TlsSetValue(_pr_intsOffIndex, (LPVOID) (_val)); \ + } \ + PR_END_MACRO + +/* --- Initialization stuff --- */ +#define _MD_INIT_LOCKS() + +/* --- Stack stuff --- */ +#define _MD_INIT_STACK(stack, redzone) +#define _MD_CLEAR_STACK(stack) + +/* --- Memory-mapped files stuff --- */ + +struct _MDFileMap { + HANDLE hFileMap; + DWORD dwAccess; +}; + +extern PRStatus _MD_CreateFileMap(struct PRFileMap *fmap, PRInt64 size); +#define _MD_CREATE_FILE_MAP _MD_CreateFileMap + +extern PRInt32 _MD_GetMemMapAlignment(void); +#define _MD_GET_MEM_MAP_ALIGNMENT _MD_GetMemMapAlignment + +extern void * _MD_MemMap(struct PRFileMap *fmap, PRInt64 offset, + PRUint32 len); +#define _MD_MEM_MAP _MD_MemMap + +extern PRStatus _MD_MemUnmap(void *addr, PRUint32 size); +#define _MD_MEM_UNMAP _MD_MemUnmap + +extern PRStatus _MD_CloseFileMap(struct PRFileMap *fmap); +#define _MD_CLOSE_FILE_MAP _MD_CloseFileMap + +/* --- Named semaphores stuff --- */ +#define _PR_HAVE_NAMED_SEMAPHORES +#define _MD_OPEN_SEMAPHORE _PR_MD_OPEN_SEMAPHORE +#define _MD_WAIT_SEMAPHORE _PR_MD_WAIT_SEMAPHORE +#define _MD_POST_SEMAPHORE _PR_MD_POST_SEMAPHORE +#define _MD_CLOSE_SEMAPHORE _PR_MD_CLOSE_SEMAPHORE +#define _MD_DELETE_SEMAPHORE(name) PR_SUCCESS /* no op */ + +#endif /* nspr_win32_defs_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/prosdep.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/prosdep.h new file mode 100644 index 00000000..93496520 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/prosdep.h @@ -0,0 +1,166 @@ +/* -*- 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 prosdep_h___ +#define prosdep_h___ + +/* +** Get OS specific header information +*/ +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +#ifdef XP_PC + +#include "md/_pcos.h" +#ifdef WINNT +#include "md/_winnt.h" +#include "md/_win32_errors.h" +#elif defined(WIN95) +#include "md/_win95.h" +#include "md/_win32_errors.h" +#elif defined(WIN16) +#include "md/_win16.h" +#elif defined(OS2) +#include "md/_os2.h" +#include "md/_os2_errors.h" +#else +#error unknown Windows platform +#endif + +#elif defined XP_MAC + +#include "_macos.h" + +#elif defined(XP_UNIX) + +#if defined(AIX) +#include "md/_aix.h" + +#elif defined(FREEBSD) +#include "md/_freebsd.h" + +#elif defined(NETBSD) +#include "md/_netbsd.h" + +#elif defined(OPENBSD) +#include "md/_openbsd.h" + +#elif defined(BSDI) +#include "md/_bsdi.h" + +#elif defined(HPUX) +#include "md/_hpux.h" + +#elif defined(IRIX) +#include "md/_irix.h" + +#elif defined(LINUX) +#include "md/_linux.h" + +#elif defined(OSF1) +#include "md/_osf1.h" + +#elif defined(DARWIN) +#include "md/_darwin.h" + +#elif defined(NEXTSTEP) +#include "md/_nextstep.h" + +#elif defined(SOLARIS) +#include "md/_solaris.h" + +#elif defined(SUNOS4) +#include "md/_sunos4.h" + +#elif defined(SNI) +#include "md/_reliantunix.h" + +#elif defined(SONY) +#include "md/_sony.h" + +#elif defined(NEC) +#include "md/_nec.h" + +#elif defined(SCO) +#include "md/_scoos.h" + +#elif defined(UNIXWARE) +#include "md/_unixware.h" + +#elif defined(NCR) +#include "md/_ncr.h" + +#elif defined(DGUX) +#include "md/_dgux.h" + +#elif defined(QNX) +#include "md/_qnx.h" + +#elif defined(VMS) +#include "md/_openvms.h" + +#elif defined(NTO) +#include "md/_nto.h" + +#else +#error unknown Unix flavor + +#endif + +#include "md/_unixos.h" +#include "md/_unix_errors.h" + +#elif defined(XP_BEOS) + +#include "md/_beos.h" +#include "md/_unix_errors.h" + +#else + +#error "The platform is not BeOS, Unix, Windows, or Mac" + +#endif + +#ifdef _PR_PTHREADS +#include "md/_pth.h" +#endif + +PR_END_EXTERN_C + +#endif /* prosdep_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/md/sunos4.h b/src/libs/xpcom18a4/nsprpub/pr/include/md/sunos4.h new file mode 100644 index 00000000..0a8f36d4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/md/sunos4.h @@ -0,0 +1,164 @@ +/* -*- 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 pr_sunos4_h___ +#define pr_sunos4_h___ + +#ifndef SVR4 + +/* +** Hodge podge of random missing prototypes for the Sunos4 system +*/ +#include +#include +#include +#include +#include + +#define PATH_MAX _POSIX_PATH_MAX + +struct timeval; +struct timezone; +struct itimerval; +struct sockaddr; +struct stat; +struct tm; + +/* ctype.h */ +extern int tolower(int); +extern int toupper(int); + +/* errno.h */ +extern char *sys_errlist[]; +extern int sys_nerr; + +#define strerror(e) sys_errlist[((unsigned)(e) < sys_nerr) ? e : 0] + +extern void perror(const char *); + +/* getopt */ +extern char *optarg; +extern int optind; +extern int getopt(int argc, char **argv, char *spec); + +/* math.h */ +extern int srandom(long val); +extern long random(void); + +/* memory.h */ +#define memmove(to,from,len) bcopy((char*)(from),(char*)(to),len) + +extern void bcopy(const char *, char *, int); + +/* signal.h */ +/* +** SunOS4 sigaction hides interrupts by default, so we can safely define +** SA_RESTART to 0. +*/ +#define SA_RESTART 0 + +/* stdio.h */ +extern int printf(const char *, ...); +extern int fprintf(FILE *, const char *, ...); +extern int vprintf(const char *, va_list); +extern int vfprintf(FILE *, const char *, va_list); +extern char *vsprintf(char *, const char *, va_list); +extern int scanf(const char *, ...); +extern int sscanf(const char *, const char *, ...); +extern int fscanf(FILE *, const char *, ...); +extern int fgetc(FILE *); +extern int fputc(int, FILE *); +extern int fputs(const char *, FILE *); +extern int puts(const char *); +extern int fread(void *, size_t, size_t, FILE *); +extern int fwrite(const char *, int, int, FILE *); +extern int fseek(FILE *, long, int); +extern long ftell(FILE *); +extern int rewind(FILE *); +extern int fflush(FILE *); +extern int _flsbuf(unsigned char, FILE *); +extern int fclose(FILE *); +extern int remove(const char *); +extern int setvbuf(FILE *, char *, int, size_t); +extern int system(const char *); +extern FILE *popen(const char *, const char *); +extern int pclose(FILE *); + +/* stdlib.h */ +#define strtoul strtol + +extern int isatty(int fildes); +extern long strtol(const char *, char **, int); +extern int putenv(const char *); +extern void srand48(long); +extern long lrand48(void); +extern double drand48(void); + +/* string.h */ +extern int strcasecmp(const char *, const char *); +extern int strncasecmp(const char *, const char *, size_t); +extern int strcoll(const char *, const char *); + +/* time.h */ +extern time_t mktime(struct tm *); +extern size_t strftime(char *, size_t, const char *, const struct tm *); +extern int gettimeofday(struct timeval *, struct timezone *); +extern int setitimer(int, struct itimerval *, struct itimerval *); +extern time_t time(time_t *); +extern time_t timegm(struct tm *); +extern struct tm *localtime(const time_t *); +extern struct tm *gmtime(const time_t *); + +/* unistd.h */ +extern int rename(const char *, const char *); +extern int ioctl(int, int, int *arg); +extern int connect(int, struct sockaddr *, int); +extern int readlink(const char *, char *, int); +extern int symlink(const char *, const char *); +extern int ftruncate(int, off_t); +extern int fchmod(int, mode_t); +extern int fchown(int, uid_t, gid_t); +extern int lstat(const char *, struct stat *); +extern int fstat(int, struct stat *); +extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int gethostname(char *, int); +extern char *getwd(char *); +extern int getpagesize(void); + +#endif /* SVR4 */ + +#endif /* pr_sunos4_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/nspr.h b/src/libs/xpcom18a4/nsprpub/pr/include/nspr.h new file mode 100644 index 00000000..cf3bfad7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/nspr.h @@ -0,0 +1,75 @@ +/* -*- 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_h___ +#define nspr_h___ + +#include "pratom.h" +#include "prbit.h" +#include "prclist.h" +#include "prcmon.h" +#include "prcvar.h" +#include "prdtoa.h" +#include "prenv.h" +#include "prerror.h" +#include "prinet.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "pripcsem.h" +#include "prlink.h" +#include "prlock.h" +#include "prlog.h" +#include "prlong.h" +#include "prmem.h" +#include "prmon.h" +#include "prmwait.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prproces.h" +#include "prrng.h" +#include "prrwlock.h" +#include "prshm.h" +#include "prshma.h" +#include "prsystem.h" +#include "prthread.h" +#include "prtime.h" +#include "prtpool.h" +#include "prtrace.h" +#include "prtypes.h" + +#endif /* nspr_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/Makefile.in new file mode 100644 index 00000000..1add4844 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +RELEASE_HEADERS = $(HEADERS) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)/obsolete + +include_subdir = obsolete + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir)/obsolete diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/pralarm.h b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/pralarm.h new file mode 100644 index 00000000..8d34a905 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/pralarm.h @@ -0,0 +1,200 @@ +/* -*- 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 ***** */ + +/* +** File: pralarm.h +** Description: API to periodic alarms. +** +** +** Alarms are defined to invoke some client specified function at +** a time in the future. The notification may be a one time event +** or repeated at a fixed interval. The interval at which the next +** notification takes place may be modified by the client code only +** during the respective notification. +** +** The notification is delivered on a thread that is part of the +** alarm context (PRAlarm). The thread will inherit the priority +** of the Alarm creator. +** +** Any number of periodic alarms (PRAlarmID) may be created within +** the context of a single alarm (PRAlarm). The notifications will be +** scheduled as close to the desired time as possible. +** +** Repeating periodic notifies are expected to run at a fixed rate. +** That rate is expressed as some number of notifies per period where +** the period is much larger than a PRIntervalTime (see prinrval.h). +*/ + +#if !defined(pralarm_h) +#define pralarm_h + +#include "prtypes.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateAlarm VBoxNsprPR_CreateAlarm +#define PR_DestroyAlarm VBoxNsprPR_DestroyAlarm +#define PR_SetAlarm VBoxNsprPR_SetAlarm +#define PR_ResetAlarm VBoxNsprPR_ResetAlarm +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef struct PRAlarm PRAlarm; +typedef struct PRAlarmID PRAlarmID; + +typedef PRBool (PR_CALLBACK *PRPeriodicAlarmFn)( + PRAlarmID *id, void *clientData, PRUint32 late); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_CreateAlarm +** DESCRIPTION: +** Create an alarm context. +** INPUTS: void +** OUTPUTS: None +** RETURN: PRAlarm* +** +** SIDE EFFECTS: +** This creates an alarm context, which is an object used for subsequent +** notification creations. It also creates a thread that will be used to +** deliver the notifications that are expected to be defined. The client +** is resposible for destroying the context when appropriate. +** RESTRICTIONS: +** None. +** MEMORY: The object (PRAlarm) and a thread to support notifications. +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRAlarm*) PR_CreateAlarm(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyAlarm +** DESCRIPTION: +** Destroys the context created by PR_CreateAlarm(). +** INPUTS: PRAlarm* +** OUTPUTS: None +** RETURN: PRStatus +** +** SIDE EFFECTS: +** This destroys the context that was created by PR_CreateAlarm(). +** If there are any active alarms (PRAlarmID), they will be cancelled. +** Once that is done, the thread that was used to deliver the alarms +** will be joined. +** RESTRICTIONS: +** None. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRStatus) PR_DestroyAlarm(PRAlarm *alarm); + +/*********************************************************************** +** FUNCTION: PR_SetAlarm +** DESCRIPTION: +** Creates a periodic notifier that is to be delivered to a specified +** function at some fixed interval. +** INPUTS: PRAlarm *alarm Parent alarm context +** PRIntervalTime period Interval over which the notifies +** are delivered. +** PRUint32 rate The rate within the interval that +** the notifies will be delivered. +** PRPeriodicAlarmFn function Entry point where the notifies +** will be delivered. +** OUTPUTS: None +** RETURN: PRAlarmID* Handle to the notifier just created +** or NULL if the request failed. +** +** SIDE EFFECTS: +** A periodic notifier is created. The notifications will be delivered +** by the alarm's internal thread at a fixed interval whose rate is the +** number of interrupts per interval specified. The first notification +** will be delivered as soon as possible, and they will continue until +** the notifier routine indicates that they should cease of the alarm +** context is destroyed (PR_DestroyAlarm). +** RESTRICTIONS: +** None. +** MEMORY: Memory for the notifier object. +** ALGORITHM: The rate at which notifications are delivered are stated +** to be "'rate' notifies per 'interval'". The exact time of +** the notification is computed based on a epoch established +** when the notifier was set. Each notification is delivered +** not ealier than the epoch plus the fixed rate times the +** notification sequence number. Such notifications have the +** potential to be late by not more than 'interval'/'rate'. +** The amount of lateness of one notification is taken into +** account on the next in an attempt to avoid long term slew. +***********************************************************************/ +NSPR_API(PRAlarmID*) PR_SetAlarm( + PRAlarm *alarm, PRIntervalTime period, PRUint32 rate, + PRPeriodicAlarmFn function, void *clientData); + +/*********************************************************************** +** FUNCTION: PR_ResetAlarm +** DESCRIPTION: +** Resets an existing alarm. +** INPUTS: PRAlarmID *id Identify of the notifier. +** PRIntervalTime period Interval over which the notifies +** are delivered. +** PRUint32 rate The rate within the interval that +** the notifies will be delivered. +** OUTPUTS: None +** RETURN: PRStatus Indication of completion. +** +** SIDE EFFECTS: +** An existing alarm may have its period and rate redefined. The +** additional side effect is that the notifier's epoch is recomputed. +** The first notification delivered by the newly refreshed alarm is +** defined to be 'interval'/'rate' from the time of the reset. +** RESTRICTIONS: +** This function may only be called in the notifier for that alarm. +** MEMORY: N/A. +** ALGORITHM: See PR_SetAlarm(). +***********************************************************************/ +NSPR_API(PRStatus) PR_ResetAlarm( + PRAlarmID *id, PRIntervalTime period, PRUint32 rate); + +PR_END_EXTERN_C + +#endif /* !defined(pralarm_h) */ + +/* prinrval.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/probslet.h b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/probslet.h new file mode 100644 index 00000000..ad346391 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/probslet.h @@ -0,0 +1,188 @@ +/* -*- 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 ***** */ + +/* +** A collection of things thought to be obsolete +*/ + +#if defined(PROBSLET_H) +#else +#define PROBSLET_H + +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_Yield VBoxNsprPR_Yield +#define PR_Select VBoxNsprPR_Select +#define PR_FD_ZERO VBoxNsprPR_FD_ZERO +#define PR_FD_SET VBoxNsprPR_FD_SET +#define PR_FD_CLR VBoxNsprPR_FD_CLR +#define PR_FD_ISSET VBoxNsprPR_FD_ISSET +#define PR_FD_NSET VBoxNsprPR_FD_NSET +#define PR_FD_NCLR VBoxNsprPR_FD_NCLR +#define PR_FD_NISSET VBoxNsprPR_FD_NISSET +#define PR_Stat VBoxNsprPR_Stat +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Yield the current thread. The proper function to use in place of +** PR_Yield() is PR_Sleep() with an argument of PR_INTERVAL_NO_WAIT. +*/ +NSPR_API(PRStatus) PR_Yield(void); + +/************************************************************************/ +/************* The following definitions are for select *****************/ +/************************************************************************/ + +/* +** The following is obsolete and will be deleted in the next release! +** These are provided for compatibility, but are GUARANTEED to be slow. +** +** Override PR_MAX_SELECT_DESC if you need more space in the select set. +*/ +#ifndef PR_MAX_SELECT_DESC +#define PR_MAX_SELECT_DESC 1024 +#endif +typedef struct PR_fd_set { + PRUint32 hsize; + PRFileDesc *harray[PR_MAX_SELECT_DESC]; + PRUint32 nsize; + PRInt32 narray[PR_MAX_SELECT_DESC]; +} PR_fd_set; + +/* +************************************************************************* +** FUNCTION: PR_Select +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** file/socket descriptors or an exceptional condition is pending. A count of the +** number of ready descriptors is returned unless a timeout occurs in which case +** zero is returned. On return, PR_Select replaces the given descriptor sets with +** subsets consisting of those descriptors that are ready for the requested condition. +** The total number of ready descriptors in all the sets is the return value. +** +** INPUTS: +** PRInt32 num +** This argument is unused but is provided for select(unix) interface +** compatability. All input PR_fd_set arguments are self-describing +** with its own maximum number of elements in the set. +** +** PR_fd_set *readfds +** A set describing the io descriptors for which ready for reading +** condition is of interest. +** +** PR_fd_set *writefds +** A set describing the io descriptors for which ready for writing +** condition is of interest. +** +** PR_fd_set *exceptfds +** A set describing the io descriptors for which exception pending +** condition is of interest. +** +** Any of the above readfds, writefds or exceptfds may be given as NULL +** pointers if no descriptors are of interest for that particular condition. +** +** PRIntervalTime timeout +** Amount of time the call will block waiting for I/O to become ready. +** If this time expires without any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: +** PR_fd_set *readfds +** A set describing the io descriptors which are ready for reading. +** +** PR_fd_set *writefds +** A set describing the io descriptors which are ready for writing. +** +** PR_fd_set *exceptfds +** A set describing the io descriptors which have pending exception. +** +** RETURN:PRInt32 +** Number of io descriptors with asked for conditions or zero if the function +** timed out or -1 on failure. The reason for the failure is obtained by +** calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +*/ +NSPR_API(PRInt32) PR_Select( + PRInt32 num, PR_fd_set *readfds, PR_fd_set *writefds, + PR_fd_set *exceptfds, PRIntervalTime timeout); + +/* +** The following are not thread safe for two threads operating on them at the +** same time. +** +** The following routines are provided for manipulating io descriptor sets. +** PR_FD_ZERO(&fdset) initializes a descriptor set fdset to the null set. +** PR_FD_SET(fd, &fdset) includes a particular file descriptor fd in fdset. +** PR_FD_CLR(fd, &fdset) removes a file descriptor fd from fdset. +** PR_FD_ISSET(fd, &fdset) is nonzero if file descriptor fd is a member of +** fdset, zero otherwise. +** +** PR_FD_NSET(osfd, &fdset) includes a particular native file descriptor osfd +** in fdset. +** PR_FD_NCLR(osfd, &fdset) removes a native file descriptor osfd from fdset. +** PR_FD_NISSET(osfd, &fdset) is nonzero if native file descriptor osfd is a member of +** fdset, zero otherwise. +*/ + +NSPR_API(void) PR_FD_ZERO(PR_fd_set *set); +NSPR_API(void) PR_FD_SET(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(void) PR_FD_CLR(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(PRInt32) PR_FD_ISSET(PRFileDesc *fd, PR_fd_set *set); +NSPR_API(void) PR_FD_NSET(PRInt32 osfd, PR_fd_set *set); +NSPR_API(void) PR_FD_NCLR(PRInt32 osfd, PR_fd_set *set); +NSPR_API(PRInt32) PR_FD_NISSET(PRInt32 osfd, PR_fd_set *set); + +#ifndef NO_NSPR_10_SUPPORT +#ifdef XP_MAC +#include +#else +#include +#endif + +NSPR_API(PRInt32) PR_Stat(const char *path, struct stat *buf); +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* defined(PROBSLET_H) */ + +/* probslet.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/protypes.h b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/protypes.h new file mode 100644 index 00000000..0912e497 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/protypes.h @@ -0,0 +1,260 @@ +/* -*- 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 header typedefs the old 'native' types to the new PRs. + * These definitions are scheduled to be eliminated at the earliest + * possible time. The NSPR API is implemented and documented using + * the new definitions. + */ + +#if !defined(PROTYPES_H) +#define PROTYPES_H + +typedef PRUintn uintn; +#ifndef _XP_Core_ +typedef PRIntn intn; +#endif + +/* + * It is trickier to define uint, int8, uint8, int16, uint16, + * int32, uint32, int64, and uint64 because some of these int + * types are defined by standard header files on some platforms. + * Our strategy here is to include all such standard headers + * first, and then define these int types only if they are not + * defined by those standard headers. + */ + +/* + * BeOS defines all the int types below in its standard header + * file SupportDefs.h. + */ +#ifdef XP_BEOS +#include +#endif + +/* + * OpenVMS defines all the int types below in its standard + * header files ints.h and types.h. + */ +#ifdef VMS +#include +#include +#endif + +/* + * SVR4 typedef of uint is commonly found on UNIX machines. + * + * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h) + * defines the types int8, int16, int32, and int64. + */ +#ifdef XP_UNIX +#include +#endif + +/* model.h on HP-UX defines int8, int16, and int32. */ +#ifdef HPUX +#include +#endif + +/* + * uint + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(XP_OS2_EMX) \ + && !defined(XP_UNIX) || defined(NTO) +typedef PRUintn uint; +#endif + +/* + * uint64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && (!defined(__APPLE__) || !defined(_UINT64)) +/* bird: ^^^ cssmconfig.h conflicts on 10.6/amd64; XP_MACOSX isn't always set so check for the compiler. */ +typedef PRUint64 uint64; +# if defined(__APPLE__) /* bird */ +# define _UINT64 /* bird */ +# endif /* bird */ +#endif + +/* + * uint32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRUint32 uint32; +#else +typedef unsigned long uint32; +#endif +#endif + +/* + * uint16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint16 uint16; +#endif + +/* + * uint8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) +typedef PRUint8 uint8; +#endif + +/* + * int64 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) +typedef PRInt64 int64; +#endif + +/* + * int32 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +#if !defined(WIN32) || !defined(_WINSOCK2API_) /* defines its own "int32" */ +#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO) +typedef PRInt32 int32; +#else +typedef long int32; +#endif +#endif +#endif + +/* + * int16 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt16 int16; +#endif + +/* + * int8 + */ + +#if !defined(XP_BEOS) && !defined(VMS) \ + && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \ + && !defined(HPUX) +typedef PRInt8 int8; +#endif + +typedef PRFloat64 float64; +typedef PRUptrdiff uptrdiff_t; +typedef PRUword uprword_t; +typedef PRWord prword_t; + + +/* Re: prbit.h */ +#define TEST_BIT PR_TEST_BIT +#define SET_BIT PR_SET_BIT +#define CLEAR_BIT PR_CLEAR_BIT + +/* Re: prarena.h->plarena.h */ +#define PRArena PLArena +#define PRArenaPool PLArenaPool +#define PRArenaStats PLArenaStats +#define PR_ARENA_ALIGN PL_ARENA_ALIGN +#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL +#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE +#define PR_ARENA_GROW PL_ARENA_GROW +#define PR_ARENA_MARK PL_ARENA_MARK +#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED +#define PR_CLEAR_ARENA PL_CLEAR_ARENA +#define PR_ARENA_RELEASE PL_ARENA_RELEASE +#define PR_COUNT_ARENA PL_COUNT_ARENA +#define PR_ARENA_DESTROY PL_ARENA_DESTROY +#define PR_InitArenaPool PL_InitArenaPool +#define PR_FreeArenaPool PL_FreeArenaPool +#define PR_FinishArenaPool PL_FinishArenaPool +#define PR_CompactArenaPool PL_CompactArenaPool +#define PR_ArenaFinish PL_ArenaFinish +#define PR_ArenaAllocate PL_ArenaAllocate +#define PR_ArenaGrow PL_ArenaGrow +#define PR_ArenaRelease PL_ArenaRelease +#define PR_ArenaCountAllocation PL_ArenaCountAllocation +#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth +#define PR_ArenaCountGrowth PL_ArenaCountGrowth +#define PR_ArenaCountRelease PL_ArenaCountRelease +#define PR_ArenaCountRetract PL_ArenaCountRetract + +/* Re: prhash.h->plhash.h */ +#define PRHashEntry PLHashEntry +#define PRHashTable PLHashTable +#define PRHashNumber PLHashNumber +#define PRHashFunction PLHashFunction +#define PRHashComparator PLHashComparator +#define PRHashEnumerator PLHashEnumerator +#define PRHashAllocOps PLHashAllocOps +#define PR_NewHashTable PL_NewHashTable +#define PR_HashTableDestroy PL_HashTableDestroy +#define PR_HashTableRawLookup PL_HashTableRawLookup +#define PR_HashTableRawAdd PL_HashTableRawAdd +#define PR_HashTableRawRemove PL_HashTableRawRemove +#define PR_HashTableAdd PL_HashTableAdd +#define PR_HashTableRemove PL_HashTableRemove +#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries +#define PR_HashTableLookup PL_HashTableLookup +#define PR_HashTableDump PL_HashTableDump +#define PR_HashString PL_HashString +#define PR_CompareStrings PL_CompareStrings +#define PR_CompareValues PL_CompareValues + +#if defined(XP_MAC) +#ifndef TRUE /* Mac standard is lower case true */ + #define TRUE 1 +#endif +#ifndef FALSE /* Mac standard is lower case false */ + #define FALSE 0 +#endif +#endif + +#endif /* !defined(PROTYPES_H) */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/prsem.h b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/prsem.h new file mode 100644 index 00000000..447027a6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/obsolete/prsem.h @@ -0,0 +1,104 @@ +/* -*- 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 prsem_h___ +#define prsem_h___ + +/* +** API for counting semaphores. Semaphores are counting synchronizing +** variables based on a lock and a condition variable. They are lightweight +** contention control for a given count of resources. +*/ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_NewSem VBoxNsprPR_NewSem +#define PR_DestroySem VBoxNsprPR_DestroySem +#define PR_WaitSem VBoxNsprPR_WaitSem +#define PR_PostSem VBoxNsprPR_PostSem +#define PR_GetValueSem VBoxNsprPR_GetValueSem +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRSemaphore PRSemaphore; + +/* +** Create a new semaphore object. +*/ +NSPR_API(PRSemaphore*) PR_NewSem(PRUintn value); + +/* +** Destroy the given semaphore object. +** +*/ +NSPR_API(void) PR_DestroySem(PRSemaphore *sem); + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon the +** state of the semahore sem. The thread can proceed only if the counter value +** of the semaphore sem is currently greater than 0. If the value of semaphore +** sem is positive, it is decremented by one and the routine returns immediately +** allowing the calling thread to continue. If the value of semaphore sem is 0, +** the calling thread blocks awaiting the semaphore to be released by another +** thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +NSPR_API(PRStatus) PR_WaitSem(PRSemaphore *sem); + +/* +** This routine increments the counter value of the semaphore. If other threads +** are blocked for the semaphore, then the scheduler will determine which ONE +** thread will be unblocked. +*/ +NSPR_API(void) PR_PostSem(PRSemaphore *sem); + +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore vaule +F** at the time of the call, but may not be the actual value when the +** caller inspects it. +*/ +NSPR_API(PRUintn) PR_GetValueSem(PRSemaphore *sem); + +PR_END_EXTERN_C + +#endif /* prsem_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/pratom.h b/src/libs/xpcom18a4/nsprpub/pr/include/pratom.h new file mode 100644 index 00000000..9ea92c36 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/pratom.h @@ -0,0 +1,172 @@ +/* -*- 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 ***** */ + +/* GLOBAL FUNCTIONS: +** DESCRIPTION: +** PR Atomic operations +*/ + +#ifndef pratom_h___ +#define pratom_h___ + +#include "prtypes.h" +#include "prlock.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_AtomicDecrement VBoxNsprPR_AtomicDecrement +#define PR_AtomicIncrement VBoxNsprPR_AtomicIncrement +#define PR_AtomicAdd VBoxNsprPR_AtomicAdd +#define PR_AtomicSet VBoxNsprPR_AtomicSet +#define PR_CreateStack VBoxNsprPR_CreateStack +#define PR_StackPush VBoxNsprPR_StackPush +#define PR_StackPop VBoxNsprPR_StackPop +#define PR_DestroyStack VBoxNsprPR_DestroyStack +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** FUNCTION: PR_AtomicIncrement +** DESCRIPTION: +** Atomically increment a 32 bit value. +** INPUTS: +** val: a pointer to the value to increment +** RETURN: +** the returned value is the result of the increment +*/ +NSPR_API(PRInt32) PR_AtomicIncrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicDecrement +** DESCRIPTION: +** Atomically decrement a 32 bit value. +** INPUTS: +** val: a pointer to the value to decrement +** RETURN: +** the returned value is the result of the decrement +*/ +NSPR_API(PRInt32) PR_AtomicDecrement(PRInt32 *val); + +/* +** FUNCTION: PR_AtomicSet +** DESCRIPTION: +** Atomically set a 32 bit value. +** INPUTS: +** val: A pointer to a 32 bit value to be set +** newval: The newvalue to assign to val +** RETURN: +** Returns the prior value +*/ +NSPR_API(PRInt32) PR_AtomicSet(PRInt32 *val, PRInt32 newval); + +/* +** FUNCTION: PR_AtomicAdd +** DESCRIPTION: +** Atomically add a 32 bit value. +** INPUTS: +** ptr: a pointer to the value to increment +** val: value to be added +** RETURN: +** the returned value is the result of the addition +*/ +NSPR_API(PRInt32) PR_AtomicAdd(PRInt32 *ptr, PRInt32 val); + +/* +** LIFO linked-list (stack) +*/ +typedef struct PRStackElemStr PRStackElem; + +struct PRStackElemStr { + PRStackElem *prstk_elem_next; /* next pointer MUST be at offset 0; + assembly language code relies on this */ +}; + +typedef struct PRStackStr PRStack; + +/* +** FUNCTION: PR_CreateStack +** DESCRIPTION: +** Create a stack, a LIFO linked list +** INPUTS: +** stack_name: a pointer to string containing the name of the stack +** RETURN: +** A pointer to the created stack, if successful, else NULL. +*/ +NSPR_API(PRStack *) PR_CreateStack(const char *stack_name); + +/* +** FUNCTION: PR_StackPush +** DESCRIPTION: +** Push an element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** stack_elem: pointer to the stack element +** RETURN: +** None +*/ +NSPR_API(void) PR_StackPush(PRStack *stack, PRStackElem *stack_elem); + +/* +** FUNCTION: PR_StackPop +** DESCRIPTION: +** Remove the element on the top of the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** A pointer to the stack element removed from the top of the stack, +** if non-empty, +** else NULL +*/ +NSPR_API(PRStackElem *) PR_StackPop(PRStack *stack); + +/* +** FUNCTION: PR_DestroyStack +** DESCRIPTION: +** Destroy the stack +** INPUTS: +** stack: pointer to the stack +** RETURN: +** PR_SUCCESS - if successfully deleted +** PR_FAILURE - if the stack is not empty +** PR_GetError will return +** PR_INVALID_STATE_ERROR - stack is not empty +*/ +NSPR_API(PRStatus) PR_DestroyStack(PRStack *stack); + +PR_END_EXTERN_C + +#endif /* pratom_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prbit.h b/src/libs/xpcom18a4/nsprpub/pr/include/prbit.h new file mode 100644 index 00000000..4b112271 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prbit.h @@ -0,0 +1,117 @@ +/* -*- 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 prbit_h___ +#define prbit_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CeilingLog2 VBoxNsprPR_CeilingLog2 +#define PR_FloorLog2 VBoxNsprPR_FloorLog2 +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** A prbitmap_t is a long integer that can be used for bitmaps +*/ +typedef unsigned long prbitmap_t; + +#define PR_TEST_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] & (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_SET_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] |= (1L << ((_bit) & (PR_BITS_PER_LONG-1)))) +#define PR_CLEAR_BIT(_map,_bit) \ + ((_map)[(_bit)>>PR_BITS_PER_LONG_LOG2] &= ~(1L << ((_bit) & (PR_BITS_PER_LONG-1)))) + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i); + +/* +** Compute the log of the greatest power of 2 less than or equal to n +*/ +NSPR_API(PRIntn) PR_FloorLog2(PRUint32 i); + +/* +** Macro version of PR_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#define PR_CEILING_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO + +/* +** Macro version of PR_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#define PR_FLOOR_LOG2(_log2,_n) \ + PR_BEGIN_MACRO \ + PRUint32 j_ = (PRUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + PR_END_MACRO + +PR_END_EXTERN_C +#endif /* prbit_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prclist.h b/src/libs/xpcom18a4/nsprpub/pr/include/prclist.h new file mode 100644 index 00000000..1680ac17 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prclist.h @@ -0,0 +1,140 @@ +/* -*- 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 prclist_h___ +#define prclist_h___ + +#include "prtypes.h" + +typedef struct PRCListStr PRCList; + +/* +** Circular linked list +*/ +struct PRCListStr { + PRCList *next; + PRCList *prev; +}; + +/* +** Insert element "_e" into the list, before "_l". +*/ +#define PR_INSERT_BEFORE(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + PR_END_MACRO + +/* +** Insert element "_e" into the list, after "_l". +*/ +#define PR_INSERT_AFTER(_e,_l) \ + PR_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + PR_END_MACRO + +/* +** Return the element following element "_e" +*/ +#define PR_NEXT_LINK(_e) \ + ((_e)->next) +/* +** Return the element preceding element "_e" +*/ +#define PR_PREV_LINK(_e) \ + ((_e)->prev) + +/* +** Append an element "_e" to the end of the list "_l" +*/ +#define PR_APPEND_LINK(_e,_l) PR_INSERT_BEFORE(_e,_l) + +/* +** Insert an element "_e" at the head of the list "_l" +*/ +#define PR_INSERT_LINK(_e,_l) PR_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define PR_LIST_HEAD(_l) (_l)->next +#define PR_LIST_TAIL(_l) (_l)->prev + +/* +** Remove the element "_e" from it's circular list. +*/ +#define PR_REMOVE_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + PR_END_MACRO + +/* +** Remove the element "_e" from it's circular list. Also initializes the +** linkage. +*/ +#define PR_REMOVE_AND_INIT_LINK(_e) \ + PR_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + (_e)->next = (_e); \ + (_e)->prev = (_e); \ + PR_END_MACRO + +/* +** Return non-zero if the given circular list "_l" is empty, zero if the +** circular list is not empty +*/ +#define PR_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* +** Initialize a circular list +*/ +#define PR_INIT_CLIST(_l) \ + PR_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + PR_END_MACRO + +#define PR_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + +#endif /* prclist_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prcmon.h b/src/libs/xpcom18a4/nsprpub/pr/include/prcmon.h new file mode 100644 index 00000000..d470da38 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prcmon.h @@ -0,0 +1,107 @@ +/* -*- 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 prcmon_h___ +#define prcmon_h___ + +/* +** Interface to cached monitors. Cached monitors use an address to find a +** given PR monitor. In this way a monitor can be associated with another +** object without preallocating a monitor for all objects. +** +** A hash table is used to quickly map addresses to individual monitors +** and the system automatically grows the hash table as needed. +** +** Cache monitors are about 5 times slower to use than uncached monitors. +*/ +#include "prmon.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CEnterMonitor VBoxNsprPR_CEnterMonitor +#define PR_CExitMonitor VBoxNsprPR_CExitMonitor +#define PR_CNotify VBoxNsprPR_CNotify +#define PR_CWait VBoxNsprPR_CWait +#define PR_CNotifyAll VBoxNsprPR_CNotifyAll +#define PR_CSetOnMonitorRecycle VBoxNsprPR_CSetOnMonitorRecycle +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/** +** Like PR_EnterMonitor except use the "address" to find a monitor in the +** monitor cache. If successful, returns the PRMonitor now associated +** with "address". Note that you must PR_CExitMonitor the address to +** release the monitor cache entry (otherwise the monitor cache will fill +** up). This call will return NULL if the monitor cache needs to be +** expanded and the system is out of memory. +*/ +NSPR_API(PRMonitor*) PR_CEnterMonitor(void *address); + +/* +** Like PR_ExitMonitor except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CExitMonitor(void *address); + +/* +** Like PR_Wait except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CWait(void *address, PRIntervalTime timeout); + +/* +** Like PR_Notify except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotify(void *address); + +/* +** Like PR_NotifyAll except use the "address" to find a monitor in the +** monitor cache. +*/ +NSPR_API(PRStatus) PR_CNotifyAll(void *address); + +/* +** Set a callback to be invoked each time a monitor is recycled from the cache +** freelist, with the monitor's cache-key passed in address. +*/ +NSPR_API(void) PR_CSetOnMonitorRecycle(void (PR_CALLBACK *callback)(void *address)); + +PR_END_EXTERN_C + +#endif /* prcmon_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prcountr.h b/src/libs/xpcom18a4/nsprpub/pr/include/prcountr.h new file mode 100644 index 00000000..016200a4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prcountr.h @@ -0,0 +1,572 @@ +/* -*- 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 prcountr_h___ +#define prcountr_h___ + +/*---------------------------------------------------------------------------- +** prcountr.h -- NSPR Instrumentation counters +** +** The NSPR Counter Feature provides a means to "count +** something." Counters can be dynamically defined, incremented, +** decremented, set, and deleted under application program +** control. +** +** The Counter Feature is intended to be used as instrumentation, +** not as operational data. If you need a counter for operational +** data, use native integral types. +** +** Counters are 32bit unsigned intergers. On overflow, a counter +** will wrap. No exception is recognized or reported. +** +** A counter can be dynamically created using a two level naming +** convention. A "handle" is returned when the counter is +** created. The counter can subsequently be addressed by its +** handle. An API is provided to get an existing counter's handle +** given the names with which it was originally created. +** Similarly, a counter's name can be retrieved given its handle. +** +** The counter naming convention is a two-level hierarchy. The +** QName is the higher level of the hierarchy; RName is the +** lower level. RNames can be thought of as existing within a +** QName. The same RName can exist within multiple QNames. QNames +** are unique. The NSPR Counter is not a near-zero overhead +** feature. Application designers should be aware of +** serialization issues when using the Counter API. Creating a +** counter locks a large asset, potentially causing a stall. This +** suggest that applications should create counters at component +** initialization, for example, and not create and destroy them +** willy-nilly. ... You have been warned. +** +** Incrementing and Adding to counters uses atomic operations. +** The performance of these operations will vary from platform +** to platform. On platforms where atomic operations are not +** supported the overhead may be substantial. +** +** When traversing the counter database with FindNext functions, +** the instantaneous values of any given counter is that at the +** moment of extraction. The state of the entire counter database +** may not be viewed as atomic. +** +** The counter interface may be disabled (No-Op'd) at compile +** time. When DEBUG is defined at compile time, the Counter +** Feature is compiled into NSPR and applications invoking it. +** When DEBUG is not defined, the counter macros compile to +** nothing. To force the Counter Feature to be compiled into an +** optimized build, define FORCE_NSPR_COUNTERS at compile time +** for both NSPR and the application intending to use it. +** +** Application designers should use the macro form of the Counter +** Feature methods to minimize performance impact in optimized +** builds. The macros normally compile to nothing on optimized +** builds. +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Counter Feature macros in expressions. +** +** The Counter Feature is thread-safe and SMP safe. +** +** /lth. 09-Jun-1998. +*/ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateCounter VBoxNsprPR_CreateCounter +#define PR_DestroyCounter VBoxNsprPR_DestroyCounter +#define PR_GetCounterHandleFromName VBoxNsprPR_GetCounterHandleFromName +#define PR_GetCounterNameFromHandle VBoxNsprPR_GetCounterNameFromHandle +#define PR_IncrementCounter VBoxNsprPR_IncrementCounter +#define PR_DecrementCounter VBoxNsprPR_DecrementCounter +#define PR_AddToCounter VBoxNsprPR_AddToCounter +#define PR_SubtractFromCounter VBoxNsprPR_SubtractFromCounter +#define PR_GetCounter VBoxNsprPR_GetCounter +#define PR_SetCounter VBoxNsprPR_SetCounter +#define PR_FindNextCounterQname VBoxNsprPR_FindNextCounterQname +#define PR_FindNextCounterRname VBoxNsprPR_FindNextCounterRname +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Opaque counter handle type. +** ... don't even think of looking in here. +** +*/ +typedef void * PRCounterHandle; + +#define PRCOUNTER_NAME_MAX 31 +#define PRCOUNTER_DESC_MAX 255 + + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_COUNTER() -- Define a PRCounterHandle +** +** DESCRIPTION: PR_DEFINE_COUNTER() is used to define a counter +** handle. +** +*/ +#define PR_DEFINE_COUNTER(name) PRCounterHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_COUNTER_HANDLE() -- Set the value of a PRCounterHandle +** +** DESCRIPTION: +** PR_INIT_COUNTER_HANDLE() sets the value of a PRCounterHandle +** to value. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INIT_COUNTER_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_COUNTER_HANDLE(handle,value) +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateCounter() -- Create a counter +** +** DESCRIPTION: PR_CreateCounter() creates a counter object and +** initializes it to zero. +** +** The macro form takes as its first argument the name of the +** PRCounterHandle to receive the handle returned from +** PR_CreateCounter(). +** +** INPUTS: +** qName: The QName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** rName: The RName for the counter object. The maximum length +** of qName is defined by PRCOUNTER_NAME_MAX +** +** descrioption: The description of the counter object. The +** maximum length of description is defined by +** PRCOUNTER_DESC_MAX. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_CREATE_COUNTER(handle,qName,rName,description)\ + (handle) = PR_CreateCounter((qName),(rName),(description)) +#else +#define PR_CREATE_COUNTER(handle,qName,rName,description) +#endif + +NSPR_API(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyCounter() -- Destroy a counter object. +** +** DESCRIPTION: PR_DestroyCounter() removes a counter and +** unregisters its handle from the counter database. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be destroyed. +** +** OUTPUTS: +** The counter is destroyed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DESTROY_COUNTER(handle) PR_DestroyCounter((handle)) +#else +#define PR_DESTROY_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DestroyCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterHandleFromName() -- Retreive a +** counter's handle give its name. +** +** DESCRIPTION: PR_GetCounterHandleFromName() retreives a +** counter's handle from the counter database, given the name +** the counter was originally created with. +** +** INPUTS: +** qName: Counter's original QName. +** rName: Counter's original RName. +** +** OUTPUTS: +** +** RETURNS: +** PRCounterHandle or PRCounterError. +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetCounterHandleFromName((qName),(rName)) +#else +#define PR_GET_COUNTER_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounterNameFromHandle() -- Retreive a +** counter's name, given its handle. +** +** DESCRIPTION: PR_GetCounterNameFromHandle() retreives a +** counter's name given its handle. +** +** INPUTS: +** qName: Where to store a pointer to qName. +** rName: Where to store a pointer to rName. +** description: Where to store a pointer to description. +** +** OUTPUTS: Pointers to the Counter Feature's copies of the names +** used when the counters were created. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetCounterNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_COUNTER_NAME_FROM_HANDLE(handle,qName,rName,description ) +#endif + +NSPR_API(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_IncrementCounter() -- Add one to the referenced +** counter. +** +** DESCRIPTION: Add one to the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the counter to be incremented +** +** OUTPUTS: The counter is incrementd. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_INCREMENT_COUNTER(handle) PR_IncrementCounter(handle) +#else +#define PR_INCREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_IncrementCounter( + PRCounterHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DecrementCounter() -- Subtract one from the +** referenced counter +** +** DESCRIPTION: Subtract one from the referenced counter. +** +** INPUTS: +** handle: The PRCounterHandle of the coutner to be +** decremented. +** +** OUTPUTS: the counter is decremented. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_DECREMENT_COUNTER(handle) PR_DecrementCounter(handle) +#else +#define PR_DECREMENT_COUNTER(handle) +#endif + +NSPR_API(void) + PR_DecrementCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_AddToCounter() -- Add a value to a counter. +** +** DESCRIPTION: Add value to the counter referenced by handle. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be added to. +** +** value: the value to be added to the counter. +** +** OUTPUTS: new value for counter. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_ADD_TO_COUNTER(handle,value)\ + PR_AddToCounter((handle),(value)) +#else +#define PR_ADD_TO_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SubtractFromCounter() -- A value is subtracted +** from a counter. +** +** DESCRIPTION: +** Subtract a value from a counter. +** +** INPUTS: +** handle: the PRCounterHandle of the counter to be subtracted +** from. +** +** value: the value to be subtracted from the counter. +** +** OUTPUTS: new value for counter +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SUBTRACT_FROM_COUNTER(handle,value)\ + PR_SubtractFromCounter((handle),(value)) +#else +#define PR_SUBTRACT_FROM_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetCounter() -- Retreive the value of a counter +** +** DESCRIPTION: +** Retreive the value of a counter. +** +** INPUTS: +** handle: the PR_CounterHandle of the counter to be retreived +** +** OUTPUTS: +** +** RETURNS: The value of the referenced counter +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_GET_COUNTER(counter,handle)\ + (counter) = PR_GetCounter((handle)) +#else +#define PR_GET_COUNTER(counter,handle) 0 +#endif + +NSPR_API(PRUint32) + PR_GetCounter( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetCounter() -- Replace the content of counter +** with value. +** +** DESCRIPTION: The contents of the referenced counter are +** replaced by value. +** +** INPUTS: +** handle: the PRCounterHandle of the counter whose contents +** are to be replaced. +** +** value: the new value of the counter. +** +** OUTPUTS: +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_SET_COUNTER(handle,value) PR_SetCounter((handle),(value)) +#else +#define PR_SET_COUNTER(handle,value) +#endif + +NSPR_API(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterQname() -- Retreive the next QName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterQname() retreives the first or next Qname +** the counter data base, depending on the value of handle. When +** handle is NULL, the function attempts to retreive the first +** QName handle in the database. When handle is a handle previosly +** retreived QName handle, then the function attempts to retreive +** the next QName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more QName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterQname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle)\ + (next) = PR_FindNextCounterQname((handle)) +#else +#define PR_FIND_NEXT_COUNTER_QNAME(next,handle) NULL +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextCounterRname() -- Retreive the next RName counter +** handle iterator +** +** DESCRIPTION: +** PR_FindNextCounterRname() retreives the first or next RNname +** handle from the counter data base, depending on the +** value of handle. When handle is NULL, the function attempts to +** retreive the first RName handle in the database. When handle is +** a handle previosly retreived RName handle, then the function +** attempts to retreive the next RName handle. +** +** INPUTS: +** handle: PRCounterHandle or NULL. +** qhandle: PRCounterHandle of a previously aquired via +** PR_FIND_NEXT_QNAME_HANDLE() +** +** OUTPUTS: returned +** +** RETURNS: PRCounterHandle or NULL when no more RName counter +** handles are present. +** +** RESTRICTIONS: +** A concurrent PR_CreateCounter() or PR_DestroyCounter() may +** cause unpredictable results. +** +** A PRCounterHandle returned from this function may only be used +** in another PR_FindNextCounterRname() function call; other +** operations may cause unpredictable results. +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_COUNTERS) +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextCounterRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_COUNTER_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +); + +PR_END_EXTERN_C + +#endif /* prcountr_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prcvar.h b/src/libs/xpcom18a4/nsprpub/pr/include/prcvar.h new file mode 100644 index 00000000..a094bb6e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prcvar.h @@ -0,0 +1,134 @@ +/* -*- 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 prcvar_h___ +#define prcvar_h___ + +#include "prlock.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_NewCondVar VBoxNsprPR_NewCondVar +#define PR_DestroyCondVar VBoxNsprPR_DestroyCondVar +#define PR_WaitCondVar VBoxNsprPR_WaitCondVar +#define PR_NotifyCondVar VBoxNsprPR_NotifyCondVar +#define PR_NotifyAllCondVar VBoxNsprPR_NotifyAllCondVar +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRCondVar PRCondVar; + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +NSPR_API(PRCondVar*) PR_NewCondVar(PRLock *lock); + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +NSPR_API(void) PR_DestroyCondVar(PRCondVar *cvar); + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +NSPR_API(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout); + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyCondVar(PRCondVar *cvar); + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +NSPR_API(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* prcvar_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prdtoa.h b/src/libs/xpcom18a4/nsprpub/pr/include/prdtoa.h new file mode 100644 index 00000000..8e21d2b5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prdtoa.h @@ -0,0 +1,96 @@ +/* -*- 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 prdtoa_h___ +#define prdtoa_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_cnvtf VBoxNsprPR_cnvtf +#define PR_dtoa VBoxNsprPR_dtoa +#define PR_strtod VBoxNsprPR_strtod +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** PR_strtod() returns as a double-precision floating-point number +** the value represented by the character string pointed to by +** s00. The string is scanned up to the first unrecognized +** character. +**a +** If the value of se is not (char **)NULL, a pointer to +** the character terminating the scan is returned in the location pointed +** to by se. If no number can be formed, se is set to s00, and +** zero is returned. +*/ +#if defined(HAVE_WATCOM_BUG_1) +/* this is a hack to circumvent a bug in the Watcom C/C++ 11.0 compiler +** When Watcom fixes the bug, remove the special case for Win16 +*/ +PRFloat64 __pascal __loadds __export +#else +NSPR_API(PRFloat64) +#endif +PR_strtod(const char *s00, char **se); + +/* +** PR_cnvtf() +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +*/ +NSPR_API(void) PR_cnvtf(char *buf, PRIntn bufsz, PRIntn prcsn, PRFloat64 fval); + +/* +** PR_dtoa() converts double to a string. +** +** ARGUMENTS: +** If rve is not null, *rve is set to point to the end of the return value. +** If d is +-Infinity or NaN, then *decpt is set to 9999. +** +** mode: +** 0 ==> shortest string that yields d when read in +** and rounded to nearest. +*/ +NSPR_API(PRStatus) PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize); + +PR_END_EXTERN_C + +#endif /* prdtoa_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prenv.h b/src/libs/xpcom18a4/nsprpub/pr/include/prenv.h new file mode 100644 index 00000000..581d5a51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prenv.h @@ -0,0 +1,162 @@ +/* -*- 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 prenv_h___ +#define prenv_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_GetEnv VBoxNsprPR_GetEnv +#define PR_SetEnv VBoxNsprPR_SetEnv +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/*******************************************************************************/ +/*******************************************************************************/ +/****************** THESE FUNCTIONS MAY NOT BE THREAD SAFE *********************/ +/*******************************************************************************/ +/*******************************************************************************/ + +PR_BEGIN_EXTERN_C + +/* +** PR_GetEnv() -- Retrieve value of environment variable +** +** Description: +** PR_GetEnv() is modeled on Unix getenv(). +** +** +** Inputs: +** var -- The name of the environment variable +** +** Returns: +** The value of the environment variable 'var' or NULL if +** the variable is undefined. +** +** Restrictions: +** You'd think that a POSIX getenv(), putenv() would be +** consistently implemented everywhere. Surprise! It is not. On +** some platforms, a putenv() where the argument is of +** the form "name" causes the named environment variable to +** be un-set; that is: a subsequent getenv() returns NULL. On +** other platforms, the putenv() fails, on others, it is a +** no-op. Similarly, a putenv() where the argument is of the +** form "name=" causes the named environment variable to be +** un-set; a subsequent call to getenv() returns NULL. On +** other platforms, a subsequent call to getenv() returns a +** pointer to a null-string (a byte of zero). +** +** PR_GetEnv(), PR_SetEnv() provide a consistent behavior +** across all supported platforms. There are, however, some +** restrictions and some practices you must use to achieve +** consistent results everywhere. +** +** When manipulating the environment there is no way to un-set +** an environment variable across all platforms. We suggest +** you interpret the return of a pointer to null-string to +** mean the same as a return of NULL from PR_GetEnv(). +** +** A call to PR_SetEnv() where the parameter is of the form +** "name" will return PR_FAILURE; the environment remains +** unchanged. A call to PR_SetEnv() where the parameter is +** of the form "name=" may un-set the envrionment variable on +** some platforms; on others it may set the value of the +** environment variable to the null-string. +** +** For example, to test for NULL return or return of the +** null-string from PR_GetEnv(), use the following code +** fragment: +** +** char *val = PR_GetEnv("foo"); +** if ((NULL == val) || ('\0' == *val)) { +** ... interpret this as un-set ... +** } +** +** The caller must ensure that the string passed +** to PR_SetEnv() is persistent. That is: The string should +** not be on the stack, where it can be overwritten +** on return from the function calling PR_SetEnv(). +** Similarly, the string passed to PR_SetEnv() must not be +** overwritten by other actions of the process. ... Some +** platforms use the string by reference rather than copying +** it into the environment space. ... You have been warned! +** +** Use of platform-native functions that manipulate the +** environment (getenv(), putenv(), +** SetEnvironmentVariable(), etc.) must not be used with +** NSPR's similar functions. The platform-native functions +** may not be thread safe and/or may operate on different +** conceptual environment space than that operated upon by +** NSPR's functions or other environment manipulating +** functions on the same platform. (!) +** +*/ +NSPR_API(char*) PR_GetEnv(const char *var); + +/* +** PR_SetEnv() -- set, unset or change an environment variable +** +** Description: +** PR_SetEnv() is modeled on the Unix putenv() function. +** +** Inputs: +** string -- pointer to a caller supplied +** constant, persistent string of the form name=value. Where +** name is the name of the environment variable to be set or +** changed; value is the value assigned to the variable. +** +** Returns: +** PRStatus. +** +** Restrictions: +** See the Restrictions documented in the description of +** PR_GetEnv() in this header file. +** +** +*/ +NSPR_API(PRStatus) PR_SetEnv(const char *string); + +/* +** DEPRECATED. Use PR_SetEnv() instead. +*/ +#ifdef XP_MAC +NSPR_API(PRIntn) PR_PutEnv(const char *string); +#endif + +PR_END_EXTERN_C + +#endif /* prenv_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prerr.h b/src/libs/xpcom18a4/nsprpub/pr/include/prerr.h new file mode 100644 index 00000000..79294847 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prerr.h @@ -0,0 +1,278 @@ +/* -*- 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 prerr_h___ +#define prerr_h___ + +/* + * + * prerr.h + * This file is automatically generated; please do not edit it. + */ + +/* Memory allocation attempt failed */ +#define PR_OUT_OF_MEMORY_ERROR (-6000L) + +/* Invalid file descriptor */ +#define PR_BAD_DESCRIPTOR_ERROR (-5999L) + +/* The operation would have blocked */ +#define PR_WOULD_BLOCK_ERROR (-5998L) + +/* Invalid memory address argument */ +#define PR_ACCESS_FAULT_ERROR (-5997L) + +/* Invalid function for file type */ +#define PR_INVALID_METHOD_ERROR (-5996L) + +/* Invalid memory address argument */ +#define PR_ILLEGAL_ACCESS_ERROR (-5995L) + +/* Some unknown error has occurred */ +#define PR_UNKNOWN_ERROR (-5994L) + +/* Operation interrupted by another thread */ +#define PR_PENDING_INTERRUPT_ERROR (-5993L) + +/* function not implemented */ +#define PR_NOT_IMPLEMENTED_ERROR (-5992L) + +/* I/O function error */ +#define PR_IO_ERROR (-5991L) + +/* I/O operation timed out */ +#define PR_IO_TIMEOUT_ERROR (-5990L) + +/* I/O operation on busy file descriptor */ +#define PR_IO_PENDING_ERROR (-5989L) + +/* The directory could not be opened */ +#define PR_DIRECTORY_OPEN_ERROR (-5988L) + +/* Invalid function argument */ +#define PR_INVALID_ARGUMENT_ERROR (-5987L) + +/* Network address not available (in use?) */ +#define PR_ADDRESS_NOT_AVAILABLE_ERROR (-5986L) + +/* Network address type not supported */ +#define PR_ADDRESS_NOT_SUPPORTED_ERROR (-5985L) + +/* Already connected */ +#define PR_IS_CONNECTED_ERROR (-5984L) + +/* Network address is invalid */ +#define PR_BAD_ADDRESS_ERROR (-5983L) + +/* Local Network address is in use */ +#define PR_ADDRESS_IN_USE_ERROR (-5982L) + +/* Connection refused by peer */ +#define PR_CONNECT_REFUSED_ERROR (-5981L) + +/* Network address is presently unreachable */ +#define PR_NETWORK_UNREACHABLE_ERROR (-5980L) + +/* Connection attempt timed out */ +#define PR_CONNECT_TIMEOUT_ERROR (-5979L) + +/* Network file descriptor is not connected */ +#define PR_NOT_CONNECTED_ERROR (-5978L) + +/* Failure to load dynamic library */ +#define PR_LOAD_LIBRARY_ERROR (-5977L) + +/* Failure to unload dynamic library */ +#define PR_UNLOAD_LIBRARY_ERROR (-5976L) + +/* Symbol not found in any of the loaded dynamic libraries */ +#define PR_FIND_SYMBOL_ERROR (-5975L) + +/* Insufficient system resources */ +#define PR_INSUFFICIENT_RESOURCES_ERROR (-5974L) + +/* A directory lookup on a network address has failed */ +#define PR_DIRECTORY_LOOKUP_ERROR (-5973L) + +/* Attempt to access a TPD key that is out of range */ +#define PR_TPD_RANGE_ERROR (-5972L) + +/* Process open FD table is full */ +#define PR_PROC_DESC_TABLE_FULL_ERROR (-5971L) + +/* System open FD table is full */ +#define PR_SYS_DESC_TABLE_FULL_ERROR (-5970L) + +/* Network operation attempted on non-network file descriptor */ +#define PR_NOT_SOCKET_ERROR (-5969L) + +/* TCP-specific function attempted on a non-TCP file descriptor */ +#define PR_NOT_TCP_SOCKET_ERROR (-5968L) + +/* TCP file descriptor is already bound */ +#define PR_SOCKET_ADDRESS_IS_BOUND_ERROR (-5967L) + +/* Access Denied */ +#define PR_NO_ACCESS_RIGHTS_ERROR (-5966L) + +/* The requested operation is not supported by the platform */ +#define PR_OPERATION_NOT_SUPPORTED_ERROR (-5965L) + +/* The host operating system does not support the protocol requested */ +#define PR_PROTOCOL_NOT_SUPPORTED_ERROR (-5964L) + +/* Access to the remote file has been severed */ +#define PR_REMOTE_FILE_ERROR (-5963L) + +/* The value requested is too large to be stored in the data buffer provided */ +#define PR_BUFFER_OVERFLOW_ERROR (-5962L) + +/* TCP connection reset by peer */ +#define PR_CONNECT_RESET_ERROR (-5961L) + +/* Unused */ +#define PR_RANGE_ERROR (-5960L) + +/* The operation would have deadlocked */ +#define PR_DEADLOCK_ERROR (-5959L) + +/* The file is already locked */ +#define PR_FILE_IS_LOCKED_ERROR (-5958L) + +/* Write would result in file larger than the system allows */ +#define PR_FILE_TOO_BIG_ERROR (-5957L) + +/* The device for storing the file is full */ +#define PR_NO_DEVICE_SPACE_ERROR (-5956L) + +/* Unused */ +#define PR_PIPE_ERROR (-5955L) + +/* Unused */ +#define PR_NO_SEEK_DEVICE_ERROR (-5954L) + +/* Cannot perform a normal file operation on a directory */ +#define PR_IS_DIRECTORY_ERROR (-5953L) + +/* Symbolic link loop */ +#define PR_LOOP_ERROR (-5952L) + +/* File name is too long */ +#define PR_NAME_TOO_LONG_ERROR (-5951L) + +/* File not found */ +#define PR_FILE_NOT_FOUND_ERROR (-5950L) + +/* Cannot perform directory operation on a normal file */ +#define PR_NOT_DIRECTORY_ERROR (-5949L) + +/* Cannot write to a read-only file system */ +#define PR_READ_ONLY_FILESYSTEM_ERROR (-5948L) + +/* Cannot delete a directory that is not empty */ +#define PR_DIRECTORY_NOT_EMPTY_ERROR (-5947L) + +/* Cannot delete or rename a file object while the file system is busy */ +#define PR_FILESYSTEM_MOUNTED_ERROR (-5946L) + +/* Cannot rename a file to a file system on another device */ +#define PR_NOT_SAME_DEVICE_ERROR (-5945L) + +/* The directory object in the file system is corrupted */ +#define PR_DIRECTORY_CORRUPTED_ERROR (-5944L) + +/* Cannot create or rename a filename that already exists */ +#define PR_FILE_EXISTS_ERROR (-5943L) + +/* Directory is full. No additional filenames may be added */ +#define PR_MAX_DIRECTORY_ENTRIES_ERROR (-5942L) + +/* The required device was in an invalid state */ +#define PR_INVALID_DEVICE_STATE_ERROR (-5941L) + +/* The device is locked */ +#define PR_DEVICE_IS_LOCKED_ERROR (-5940L) + +/* No more entries in the directory */ +#define PR_NO_MORE_FILES_ERROR (-5939L) + +/* Encountered end of file */ +#define PR_END_OF_FILE_ERROR (-5938L) + +/* Seek error */ +#define PR_FILE_SEEK_ERROR (-5937L) + +/* The file is busy */ +#define PR_FILE_IS_BUSY_ERROR (-5936L) + +/* The I/O operation was aborted */ +#define PR_OPERATION_ABORTED_ERROR (-5935L) + +/* Operation is still in progress (probably a non-blocking connect) */ +#define PR_IN_PROGRESS_ERROR (-5934L) + +/* Operation has already been initiated (probably a non-blocking connect) */ +#define PR_ALREADY_INITIATED_ERROR (-5933L) + +/* The wait group is empty */ +#define PR_GROUP_EMPTY_ERROR (-5932L) + +/* Object state improper for request */ +#define PR_INVALID_STATE_ERROR (-5931L) + +/* Network is down */ +#define PR_NETWORK_DOWN_ERROR (-5930L) + +/* Socket shutdown */ +#define PR_SOCKET_SHUTDOWN_ERROR (-5929L) + +/* Connection aborted */ +#define PR_CONNECT_ABORTED_ERROR (-5928L) + +/* Host is unreachable */ +#define PR_HOST_UNREACHABLE_ERROR (-5927L) + +/* The library is not loaded */ +#define PR_LIBRARY_NOT_LOADED_ERROR (-5926L) + +/* Placeholder for the end of the list */ +#define PR_MAX_ERROR (-5925L) + +extern void nspr_InitializePRErrorTable(void); +#define ERROR_TABLE_BASE_nspr (-6000L) + +#endif /* prerr_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prerror.h b/src/libs/xpcom18a4/nsprpub/pr/include/prerror.h new file mode 100644 index 00000000..29e69dde --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prerror.h @@ -0,0 +1,339 @@ +/* -*- 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 prerror_h___ +#define prerror_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_SetError VBoxNsprPR_SetError +#define PR_SetErrorText VBoxNsprPR_SetErrorText +#define PR_GetError VBoxNsprPR_GetError +#define PR_GetOSError VBoxNsprPR_GetOSError +#define PR_GetErrorTextLength VBoxNsprPR_GetErrorTextLength +#define PR_GetErrorText VBoxNsprPR_GetErrorText +#define PR_ErrorToString VBoxNsprPR_ErrorToString +#define PR_ErrorToName VBoxNsprPR_ErrorToName +#define PR_ErrorLanguages VBoxNsprPR_ErrorLanguages +#define PR_ErrorInstallTable VBoxNsprPR_ErrorInstallTable +#define PR_ErrorInstallCallback VBoxNsprPR_ErrorInstallCallback +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PR_BEGIN_EXTERN_C + +typedef PRInt32 PRErrorCode; + +#define PR_NSPR_ERROR_BASE -6000 + +#include "prerr.h" + +/* +** Set error will preserve an error condition within a thread context. +** The values stored are the NSPR (platform independent) translation of +** the error. Also, if available, the platform specific oserror is stored. +** If there is no appropriate OS error number, a zero my be supplied. +*/ +NSPR_API(void) PR_SetError(PRErrorCode errorCode, PRInt32 oserr); + +/* +** The text value specified may be NULL. If it is not NULL and the text length +** is zero, the string is assumed to be a null terminated C string. Otherwise +** the text is assumed to be the length specified and possibly include NULL +** characters (e.g., a multi-national string). +** +** The text will be copied into to thread structure and remain there +** until the next call to PR_SetError. +*/ +NSPR_API(void) PR_SetErrorText( + PRIntn textLength, const char *text); + +/* +** Return the current threads last set error code. +*/ +NSPR_API(PRErrorCode) PR_GetError(void); + +/* +** Return the current threads last set os error code. This is used for +** machine specific code that desires the underlying os error. +*/ +NSPR_API(PRInt32) PR_GetOSError(void); + +/* +** Get the length of the error text. If a zero is returned, then there +** is no text. Otherwise, the value returned is sufficient to contain +** the error text currently available. +*/ +NSPR_API(PRInt32) PR_GetErrorTextLength(void); + +/* +** Copy the current threads current error text. Then actual number of bytes +** copied is returned as the result. If the result is zero, the 'text' area +** is unaffected. +*/ +NSPR_API(PRInt32) PR_GetErrorText(char *text); + + +/* +Copyright (C) 1987, 1988 Student Information Processing Board of the +Massachusetts Institute of Technology. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, provided +that the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. M.I.T. and the M.I.T. S.I.P.B. +make no representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied warranty. +*/ + + +/* + * NOTE: + * The interfaces for error-code-translation described in the rest of + * this file are preliminary in the 3.1 release of nspr and are subject + * to change in future releases. + */ + +/* +** Description: Localizable error code to string function. +** +** +** NSPR provides a mechanism for converting an error code to a +** descriptive string, in a caller-specified language. +** +** Error codes themselves are 32 bit (signed) integers. Typically, +** the high order 24 bits are an identifier of which error table the +** error code is from, and the low order 8 bits are a sequential error +** number within the table. NSPR supports error tables whose first +** error code is not a multiple of 256, such error code assignments +** should be avoided when possible. +** +** Error table 0 is defined to match the UNIX system call error table +** (sys_errlist); this allows errno values to be used directly in the +** library. Other error table numbers are typically formed by +** compacting together the first four characters of the error table +** name. The mapping between characters in the name and numeric +** values in the error code are defined in a system-independent +** fashion, so that two systems that can pass integral values between +** them can reliably pass error codes without loss of meaning; this +** should work even if the character sets used are not the +** same. (However, if this is to be done, error table 0 should be +** avoided, since the local system call error tables may differ.) +** +** Libraries defining error codes need only provide a table mapping +** error code numbers to names and default English descriptions, +** calling a routine to install the table, making it ``known'' to NSPR +** library. Once installed, a table may not be removed. Any error +** code the library generates can be converted to the corresponding +** error message. There is also a default format for error codes +** accidentally returned before making the table known, which is of +** the form "unknown code foo 32", where "foo" would be the name of +** the table. +** +** Normally, the error code conversion routine only supports the +** languages "i-default" and "en", returning the error-table-provided +** English description for both languages. The application may +** provide a localization plugin, allowing support for additional +** languages. +** +**/ + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLanguageCode -- + * + * NSPR represents a language code as a non-negative integer. + * Languages 0 is always "i-default" the language you get without + * explicit negotiation. Language 1 is always "en", English + * which has been explicitly negotiated. Additional language + * codes are defined by an application-provided localization plugin. + */ +typedef PRUint32 PRLanguageCode; +#define PR_LANGUAGE_I_DEFAULT 0 /* i-default, the default language */ +#define PR_LANGUAGE_EN 1 /* English, explicitly negotiated */ + +/* + * struct PRErrorMessage -- + * + * An error message in an error table. + */ +struct PRErrorMessage { + const char * name; /* Macro name for error */ + const char * en_text; /* Default English text */ +}; + +/* + * struct PRErrorTable -- + * + * An error table, provided by a library. + */ +struct PRErrorTable { + const struct PRErrorMessage * msgs; /* Array of error information */ + const char *name; /* Name of error table source */ + PRErrorCode base; /* Error code for first error in table */ + int n_msgs; /* Number of codes in table */ +}; + +/* + * struct PRErrorCallbackPrivate -- + * + * A private structure for the localization plugin + */ +struct PRErrorCallbackPrivate; + +/* + * struct PRErrorCallbackTablePrivate -- + * + * A data structure under which the localization plugin may store information, + * associated with an error table, that is private to itself. + */ +struct PRErrorCallbackTablePrivate; + +/* + * PRErrorCallbackLookupFn -- + * + * A function of PRErrorCallbackLookupFn type is a localization + * plugin callback which converts an error code into a description + * in the requested language. The callback is provided the + * appropriate error table, private data for the plugin and the table. + * The callback returns the appropriate UTF-8 encoded description, or NULL + * if no description can be found. + */ +typedef const char * +PRErrorCallbackLookupFn(PRErrorCode code, PRLanguageCode language, + const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private, + struct PRErrorCallbackTablePrivate *table_private); + +/* + * PRErrorCallbackNewTableFn -- + * + * A function PRErrorCallbackNewTableFn type is a localization plugin + * callback which is called once with each error table registered + * with NSPR. The callback is provided with the error table and + * the plugin's private structure. The callback returns any table private + * data it wishes to associate with the error table. Does not need to be thread + * safe. + */ +typedef struct PRErrorCallbackTablePrivate * +PRErrorCallbackNewTableFn(const struct PRErrorTable *table, + struct PRErrorCallbackPrivate *cb_private); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_ErrorToString +** DESCRIPTION: +** Returns the UTF-8 message for an error code in +** the requested language. May return the message +** in the default language if a translation in the requested +** language is not available. The returned string is +** valid for the duration of the process. Never returns NULL. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToString(PRErrorCode code, + PRLanguageCode language); + + +/*********************************************************************** +** FUNCTION: PR_ErrorToName +** DESCRIPTION: +** Returns the macro name for an error code, or NULL +** if the error code is not known. The returned string is +** valid for the duration of the process. +** +** Does not work for error table 0, the system error codes. +** +***********************************************************************/ +NSPR_API(const char *) PR_ErrorToName(PRErrorCode code); + + +/*********************************************************************** +** FUNCTION: PR_ErrorLanguages +** DESCRIPTION: +** Returns the RFC 1766 language tags for the language +** codes PR_ErrorToString() supports. The returned array is valid +** for the duration of the process. Never returns NULL. The first +** item in the returned array is the language tag for PRLanguageCode 0, +** the second is for PRLanguageCode 1, and so on. The array is terminated +** with a null pointer. +** +***********************************************************************/ +NSPR_API(const char * const *) PR_ErrorLanguages(void); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallTable +** DESCRIPTION: +** Registers an error table with NSPR. Must be done exactly once per +** table. Memory pointed to by `table' must remain valid for the life +** of the process. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(PRErrorCode) PR_ErrorInstallTable(const struct PRErrorTable *table); + + +/*********************************************************************** +** FUNCTION: PR_ErrorInstallCallback +** DESCRIPTION: +** Registers an error localization plugin with NSPR. May be called +** at most one time. `languages' contains the language codes supported +** by this plugin. Languages 0 and 1 must be "i-default" and "en" +** respectively. `lookup' and `newtable' contain pointers to +** the plugin callback functions. `cb_private' contains any information +** private to the plugin functions. +** +** NOT THREAD SAFE! +** +***********************************************************************/ +NSPR_API(void) PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private); + +PR_END_EXTERN_C + +#endif /* prerror_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prinet.h b/src/libs/xpcom18a4/nsprpub/pr/include/prinet.h new file mode 100644 index 00000000..2c733b0b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prinet.h @@ -0,0 +1,126 @@ +/* -*- 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 ***** */ + +/* + * File: prinet.h + * Description: + * Header file used to find the system header files for socket support. + * This file serves the following purposes: + * - A cross-platform, "get-everything" socket header file. On + * Unix, socket support is scattered in several header files, + * while Windows and Mac have a "get-everything" socket header + * file. + * - NSPR needs the following macro definitions and function + * prototype declarations from these header files: + * AF_INET + * INADDR_ANY, INADDR_LOOPBACK, INADDR_BROADCAST + * ntohl(), ntohs(), htonl(), ntons(). + * NSPR does not define its own versions of these macros and + * functions. It simply uses the native versions, which have + * the same names on all supported platforms. + * This file is intended to be included by nspr20 public header + * files, such as prio.h. One should not include this file directly. + */ + +#ifndef prinet_h__ +#define prinet_h__ + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef LINUX +#undef __STRICT_ANSI__ +#define __STRICT_ANSI__ +#endif +#include +#include /* AF_INET */ +#include /* INADDR_ANY, ..., ntohl(), ... */ +#ifdef XP_OS2 +#include +#endif +#ifdef XP_UNIX +#ifdef AIX +/* + * On AIX 4.3, the header refers to struct + * ether_addr and struct sockaddr_dl that are not declared. + * The following struct declarations eliminate the compiler + * warnings. + */ +struct ether_addr; +struct sockaddr_dl; +#endif /* AIX */ +#include +#endif /* XP_UNIX */ +#include + +#if defined(FREEBSD) || defined(BSDI) || defined(QNX) +#include /* the only place that defines INADDR_LOOPBACK */ +#endif + +/* + * OS/2 hack. For some reason INADDR_LOOPBACK is not defined in the + * socket headers. + */ +#if defined(OS2) && !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +/* + * Prototypes of ntohl() etc. are declared in + * on these platforms. + */ +#if defined(BSDI) || defined(OSF1) +#include +#endif + +#elif defined(WIN32) + +/* Do not include any system header files. */ + +#elif defined(WIN16) + +#include + +#elif defined(XP_MAC) + +#include "macsocket.h" + +#else + +#error Unknown platform + +#endif + +#endif /* prinet_h__ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prinit.h b/src/libs/xpcom18a4/nsprpub/pr/include/prinit.h new file mode 100644 index 00000000..1f6718ba --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prinit.h @@ -0,0 +1,260 @@ +/* -*- 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 prinit_h___ +#define prinit_h___ + +#include "prthread.h" +#include "prtypes.h" +#include "prwin16.h" +#include + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_Abort VBoxNsprPR_Abort +#define PR_Cleanup VBoxNsprPR_Cleanup +#define PR_DisableClockInterrupts VBoxNsprPR_DisableClockInterrupts +#define PR_EnableClockInterrupts VBoxNsprPR_EnableClockInterrupts +#define PR_BlockClockInterrupts VBoxNsprPR_BlockClockInterrupts +#define PR_UnblockClockInterrupts VBoxNsprPR_UnblockClockInterrupts +#define PR_Init VBoxNsprPR_Init +#define PR_Initialize VBoxNsprPR_Initialize +#define PR_Initialized VBoxNsprPR_Initialized +#define PR_VersionCheck VBoxNsprPR_VersionCheck +#define PR_SetConcurrency VBoxNsprPR_SetConcurrency +#define PR_SetFDCacheSize VBoxNsprPR_SetFDCacheSize +#define PR_ProcessExit VBoxNsprPR_ProcessExit +#define PR_CallOnce VBoxNsprPR_CallOnce +#define PR_CallOnceWithArg VBoxNsprPR_CallOnceWithArg +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ + +/* +** NSPR's name, this should persist until at least the turn of the +** century. +*/ +#define PR_NAME "NSPR" + +/* +** NSPR's version is used to determine the likelihood that the version you +** used to build your component is anywhere close to being compatible with +** what is in the underlying library. +** +** The format of the version string is +** ".[.] []" +*/ +#define PR_VERSION "4.6 Beta" +#define PR_VMAJOR 4 +#define PR_VMINOR 6 +#define PR_VPATCH 0 +#define PR_BETA PR_TRUE + +/* +** PRVersionCheck +** +** The basic signature of the function that is called to provide version +** checking. The result will be a boolean that indicates the likelihood +** that the underling library will perform as the caller expects. +** +** The only argument is a string, which should be the verson identifier +** of the library in question. That string will be compared against an +** equivalent string that represents the actual build version of the +** exporting library. +** +** The result will be the logical union of the directly called library +** and all dependent libraries. +*/ + +typedef PRBool (*PRVersionCheck)(const char*); + +/* +** PR_VersionCheck +** +** NSPR's existance proof of the version check function. +** +** Note that NSPR has no cooperating dependencies. +*/ + +NSPR_API(PRBool) PR_VersionCheck(const char *importedVersion); + + +/************************************************************************/ +/*******************************INITIALIZATION***************************/ +/************************************************************************/ + +/* +** Initialize the runtime. Attach a thread object to the currently +** executing native thread of type "type". +** +** The specificaiton of 'maxPTDs' is ignored. +*/ +NSPR_API(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +/* +** And alternate form of initialization, one that may become the default if +** not the only mechanism, provides a method to get the NSPR runtime init- +** ialized and place NSPR between the caller and the runtime library. This +** allows main() to be treated as any other thread root function, signalling +** its compeletion by returning and allowing the runtime to coordinate the +** completion of the other threads of the runtime. +** +** The priority of the main (or primordial) thread will be PR_PRIORITY_NORMAL. +** The thread may adjust its own priority by using PR_SetPriority(), though +** at this time the support for priorities is somewhat weak. +** +** The specificaiton of 'maxPTDs' is ignored. +** +** The value returned by PR_Initialize is the value returned from the root +** function, 'prmain'. +*/ + +typedef PRIntn (PR_CALLBACK *PRPrimordialFn)(PRIntn argc, char **argv); + +NSPR_API(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs); + +/* +** Return PR_TRUE if PR_Init has already been called. +*/ +NSPR_API(PRBool) PR_Initialized(void); + +/* + * Perform a graceful shutdown of NSPR. PR_Cleanup() may be called by + * the primordial thread near the end of the main() function. + * + * PR_Cleanup() attempts to synchronize the natural termination of + * process. It does that by blocking the caller, if and only if it is + * the primordial thread, until the number of user threads has dropped + * to zero. When the primordial thread returns from main(), the process + * will immediately and silently exit. That is, it will (if necessary) + * forcibly terminate any existing threads and exit without significant + * blocking and there will be no error messages or core files. + * + * PR_Cleanup() returns PR_SUCCESS if NSPR is successfully shutdown, + * or PR_FAILURE if the calling thread of this function is not the + * primordial thread. + */ +NSPR_API(PRStatus) PR_Cleanup(void); + +/* +** Disable Interrupts +** Disables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_DisableClockInterrupts(void); + +/* +** Enables Interrupts +** Enables timer signals used for pre-emptive scheduling. +*/ +NSPR_API(void) PR_EnableClockInterrupts(void); + +/* +** Block Interrupts +** Blocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_BlockClockInterrupts(void); + +/* +** Unblock Interrupts +** Unblocks the timer signal used for pre-emptive scheduling +*/ +NSPR_API(void) PR_UnblockClockInterrupts(void); + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +NSPR_API(void) PR_SetConcurrency(PRUintn numCPUs); + +/* +** Control the method and size of the file descriptor (PRFileDesc*) +** cache used by the runtime. Setting 'high' to zero is for performance, +** any other value probably for debugging (see memo on FD caching). +*/ +NSPR_API(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high); + +/* + * Cause an immediate, nongraceful, forced termination of the process. + * It takes a PRIntn argument, which is the exit status code of the + * process. + */ +NSPR_API(void) PR_ProcessExit(PRIntn status); + +/* +** Abort the process in a non-graceful manner. This will cause a core file, +** call to the debugger or other moral equivalent as well as causing the +** entire process to stop. +*/ +NSPR_API(void) PR_Abort(void); + +/* + **************************************************************** + * + * Module initialization: + * + **************************************************************** + */ + +typedef struct PRCallOnceType { + PRIntn initialized; + PRInt32 inProgress; + PRStatus status; +} PRCallOnceType; + +typedef PRStatus (PR_CALLBACK *PRCallOnceFN)(void); + +typedef PRStatus (PR_CALLBACK *PRCallOnceWithArgFN)(void *arg); + +NSPR_API(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func +); + +NSPR_API(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg +); + + +PR_END_EXTERN_C + +#endif /* prinit_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prinrval.h b/src/libs/xpcom18a4/nsprpub/pr/include/prinrval.h new file mode 100644 index 00000000..83efdfa7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prinrval.h @@ -0,0 +1,186 @@ +/* -*- 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 ***** */ + +/* +** File: prinrval.h +** Description: API to interval timing functions of NSPR. +** +** +** NSPR provides interval times that are independent of network time +** of day values. Interval times are (in theory) accurate regardless +** of host processing requirements and also very cheap to acquire. It +** is expected that getting an interval time while in a synchronized +** function (holding one's lock). +**/ + +#if !defined(prinrval_h) +#define prinrval_h + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_IntervalNow VBoxNsprPR_IntervalNow +#define PR_TicksPerSecond VBoxNsprPR_TicksPerSecond +#define PR_SecondsToInterval VBoxNsprPR_SecondsToInterval +#define PR_MillisecondsToInterval VBoxNsprPR_MillisecondsToInterval +#define PR_MicrosecondsToInterval VBoxNsprPR_MicrosecondsToInterval +#define PR_IntervalToSeconds VBoxNsprPR_IntervalToSeconds +#define PR_IntervalToMilliseconds VBoxNsprPR_IntervalToMilliseconds +#define PR_IntervalToMicroseconds VBoxNsprPR_IntervalToMicroseconds +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +typedef PRUint32 PRIntervalTime; + +/*********************************************************************** +** DEFINES: PR_INTERVAL_MIN +** PR_INTERVAL_MAX +** DESCRIPTION: +** These two constants define the range (in ticks / second) of the +** platform dependent type, PRIntervalTime. These constants bound both +** the period and the resolution of a PRIntervalTime. +***********************************************************************/ +#define PR_INTERVAL_MIN 1000UL +#define PR_INTERVAL_MAX 100000UL + +/*********************************************************************** +** DEFINES: PR_INTERVAL_NO_WAIT +** PR_INTERVAL_NO_TIMEOUT +** DESCRIPTION: +** Two reserved constants are defined in the PRIntervalTime namespace. +** They are used to indicate that the process should wait no time (return +** immediately) or wait forever (never time out), respectively. +***********************************************************************/ +#define PR_INTERVAL_NO_WAIT 0UL +#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_IntervalNow +** DESCRIPTION: +** Return the value of NSPR's free running interval timer. That timer +** can be used to establish epochs and determine intervals (be computing +** the difference between two times). +** INPUTS: void +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** The units of PRIntervalTime are platform dependent. They are chosen +** such that they are appropriate for the host OS, yet provide sufficient +** resolution and period to be useful to clients. +** MEMORY: N/A +** ALGORITHM: Platform dependent +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_IntervalNow(void); + +/*********************************************************************** +** FUNCTION: PR_TicksPerSecond +** DESCRIPTION: +** Return the number of ticks per second for PR_IntervalNow's clock. +** The value will be in the range [PR_INTERVAL_MIN..PR_INTERVAL_MAX]. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** None +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_TicksPerSecond(void); + +/*********************************************************************** +** FUNCTION: PR_SecondsToInterval +** PR_MillisecondsToInterval +** PR_MicrosecondsToInterval +** DESCRIPTION: +** Convert standard clock units to platform dependent intervals. +** INPUTS: PRUint32 +** OUTPUTS: void +** RETURN: PRIntervalTime +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds); +NSPR_API(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli); +NSPR_API(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro); + +/*********************************************************************** +** FUNCTION: PR_IntervalToSeconds +** PR_IntervalToMilliseconds +** PR_IntervalToMicroseconds +** DESCRIPTION: +** Convert platform dependent intervals to standard clock units. +** INPUTS: PRIntervalTime +** OUTPUTS: void +** RETURN: PRUint32 +** +** SIDE EFFECTS: +** None +** RESTRICTIONS: +** Conversion may cause overflow, which is not reported. +** MEMORY: N/A +** ALGORITHM: N/A +***********************************************************************/ +NSPR_API(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks); +NSPR_API(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks); + +PR_END_EXTERN_C + + +#endif /* !defined(prinrval_h) */ + +/* prinrval.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prio.h b/src/libs/xpcom18a4/nsprpub/pr/include/prio.h new file mode 100644 index 00000000..908a88d3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prio.h @@ -0,0 +1,2107 @@ +/* -*- 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 ***** */ + +/* + * File: prio.h + * + * Description: PR i/o related stuff, such as file system access, file + * i/o, socket i/o, etc. + */ + +#ifndef prio_h___ +#define prio_h___ + +#include "prlong.h" +#include "prtime.h" +#include "prinrval.h" +#include "prinet.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_GetInheritedFD VBoxNsprPR_GetInheritedFD +#define PR_SetFDInheritable VBoxNsprPR_SetFDInheritable +#define PR_Access VBoxNsprPR_Access +#define PR_Open VBoxNsprPR_Open +#define PR_Read VBoxNsprPR_Read +#define PR_Write VBoxNsprPR_Write +#define PR_Seek VBoxNsprPR_Seek +#define PR_Seek64 VBoxNsprPR_Seek64 +#define PR_Poll VBoxNsprPR_Poll +#define PR_NewPollableEvent VBoxNsprPR_NewPollableEvent +#define PR_SetPollableEvent VBoxNsprPR_SetPollableEvent +#define PR_WaitForPollableEvent VBoxNsprPR_WaitForPollableEvent +#define PR_DestroyPollableEvent VBoxNsprPR_DestroyPollableEvent +#define PR_Close VBoxNsprPR_Close +#define PR_GetSpecialFD VBoxNsprPR_GetSpecialFD +#define PR_Connect VBoxNsprPR_Connect +#define PR_OpenTCPSocket VBoxNsprPR_OpenTCPSocket +#define PR_SetSocketOption VBoxNsprPR_SetSocketOption +#define PR_Bind VBoxNsprPR_Bind +#define PR_Listen VBoxNsprPR_Listen +#define PR_Accept VBoxNsprPR_Accept +#define PR_AcceptRead VBoxNsprPR_AcceptRead +#define PR_OpenDir VBoxNsprPR_OpenDir +#define PR_ReadDir VBoxNsprPR_ReadDir +#define PR_CloseDir VBoxNsprPR_CloseDir +#define PR_CreatePipe VBoxNsprPR_CreatePipe +#define PR_GetDescType VBoxNsprPR_GetDescType +#define PR_GetSpecialFD VBoxNsprPR_GetSpecialFD +#define PR_GetUniqueIdentity VBoxNsprPR_GetUniqueIdentity +#define PR_GetNameForIdentity VBoxNsprPR_GetNameForIdentity +#define PR_GetLayersIdentity VBoxNsprPR_GetLayersIdentity +#define PR_GetIdentitiesLayer VBoxNsprPR_GetIdentitiesLayer +#define PR_GetDefaultIOMethods VBoxNsprPR_GetDefaultIOMethods +#define PR_CreateIOLayerStub VBoxNsprPR_CreateIOLayerStub +#define PR_CreateIOLayer VBoxNsprPR_CreateIOLayer +#define PR_PushIOLayer VBoxNsprPR_PushIOLayer +#define PR_PopIOLayer VBoxNsprPR_PopIOLayer +#define PR_OpenFile VBoxNsprPR_OpenFile +#define PR_Writev VBoxNsprPR_Writev +#define PR_Delete VBoxNsprPR_Delete +#define PR_Rename VBoxNsprPR_Rename +#define PR_GetFileInfo VBoxNsprPR_GetFileInfo +#define PR_GetFileInfo64 VBoxNsprPR_GetFileInfo64 +#define PR_GetOpenFileInfo VBoxNsprPR_GetOpenFileInfo +#define PR_GetOpenFileInfo64 VBoxNsprPR_GetOpenFileInfo64 +#define PR_Available VBoxNsprPR_Available +#define PR_Available64 VBoxNsprPR_Available64 +#define PR_Sync VBoxNsprPR_Sync +#define PR_MkDir VBoxNsprPR_MkDir +#define PR_MakeDir VBoxNsprPR_MakeDir +#define PR_RmDir VBoxNsprPR_RmDir +#define PR_NewUDPSocket VBoxNsprPR_NewUDPSocket +#define PR_NewTCPSocket VBoxNsprPR_NewTCPSocket +#define PR_OpenUDPSocket VBoxNsprPR_OpenUDPSocket +#define PR_OpenTCPSocket VBoxNsprPR_OpenTCPSocket +#define PR_ConnectContinue VBoxNsprPR_ConnectContinue +#define PR_GetConnectStatus VBoxNsprPR_GetConnectStatus +#define PR_Shutdown VBoxNsprPR_Shutdown +#define PR_Recv VBoxNsprPR_Recv +#define PR_Send VBoxNsprPR_Send +#define PR_RecvFrom VBoxNsprPR_RecvFrom +#define PR_SendTo VBoxNsprPR_SendTo +#define PR_TransmitFile VBoxNsprPR_TransmitFile +#define PR_SendFile VBoxNsprPR_SendFile +#define PR_NewTCPSocketPair VBoxNsprPR_NewTCPSocketPair +#define PR_GetSockName VBoxNsprPR_GetSockName +#define PR_GetPeerName VBoxNsprPR_GetPeerName +#define PR_GetSocketOption VBoxNsprPR_GetSocketOption +#define PR_CreateFileMap VBoxNsprPR_CreateFileMap +#define PR_GetMemMapAlignment VBoxNsprPR_GetMemMapAlignment +#define PR_MemMap VBoxNsprPR_MemMap +#define PR_MemUnmap VBoxNsprPR_MemUnmap +#define PR_CloseFileMap VBoxNsprPR_CloseFileMap +#define PR_CreatePipe VBoxNsprPR_CreatePipe +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* Typedefs */ +typedef struct PRDir PRDir; +typedef struct PRDirEntry PRDirEntry; +#ifdef MOZ_UNICODE +typedef struct PRDirUTF16 PRDirUTF16; +typedef struct PRDirEntryUTF16 PRDirEntryUTF16; +#endif /* MOZ_UNICODE */ +typedef struct PRFileDesc PRFileDesc; +typedef struct PRFileInfo PRFileInfo; +typedef struct PRFileInfo64 PRFileInfo64; +typedef union PRNetAddr PRNetAddr; +typedef struct PRIOMethods PRIOMethods; +typedef struct PRPollDesc PRPollDesc; +typedef struct PRFilePrivate PRFilePrivate; +typedef struct PRSendFileData PRSendFileData; + +/* +*************************************************************************** +** The file descriptor. +** This is the primary structure to represent any active open socket, +** whether it be a normal file or a network connection. Such objects +** are stackable (or layerable). Each layer may have its own set of +** method pointers and context private to that layer. All each layer +** knows about its neighbors is how to get to their method table. +*************************************************************************** +*/ + +typedef PRIntn PRDescIdentity; /* see: Layering file descriptors */ + +struct PRFileDesc { + const PRIOMethods *methods; /* the I/O methods table */ + PRFilePrivate *secret; /* layer dependent data */ + PRFileDesc *lower, *higher; /* pointers to adjacent layers */ + void (PR_CALLBACK *dtor)(PRFileDesc *fd); + /* A destructor function for layer */ + PRDescIdentity identity; /* Identity of this particular layer */ +}; + +/* +*************************************************************************** +** PRTransmitFileFlags +** +** Flags for PR_TransmitFile. Pass PR_TRANSMITFILE_CLOSE_SOCKET to +** PR_TransmitFile if the connection should be closed after the file +** is transmitted. +*************************************************************************** +*/ +typedef enum PRTransmitFileFlags { + PR_TRANSMITFILE_KEEP_OPEN = 0, /* socket is left open after file + * is transmitted. */ + PR_TRANSMITFILE_CLOSE_SOCKET = 1 /* socket is closed after file + * is transmitted. */ +} PRTransmitFileFlags; + +/* +************************************************************************** +** Macros for PRNetAddr +** +** Address families: PR_AF_INET, PR_AF_INET6, PR_AF_LOCAL +** IP addresses: PR_INADDR_ANY, PR_INADDR_LOOPBACK, PR_INADDR_BROADCAST +************************************************************************** +*/ + +#ifdef WIN32 + +#define PR_AF_INET 2 +#define PR_AF_LOCAL 1 +#define PR_INADDR_ANY (unsigned long)0x00000000 +#define PR_INADDR_LOOPBACK 0x7f000001 +#define PR_INADDR_BROADCAST (unsigned long)0xffffffff + +#else /* WIN32 */ + +#define PR_AF_INET AF_INET +#define PR_AF_LOCAL AF_UNIX +#define PR_INADDR_ANY INADDR_ANY +#define PR_INADDR_LOOPBACK INADDR_LOOPBACK +#define PR_INADDR_BROADCAST INADDR_BROADCAST + +#endif /* WIN32 */ + +/* +** Define PR_AF_INET6 in prcpucfg.h with the same +** value as AF_INET6 on platforms with IPv6 support. +** Otherwise define it here. +*/ +#ifndef PR_AF_INET6 +#define PR_AF_INET6 100 +#endif + +#ifndef PR_AF_UNSPEC +#define PR_AF_UNSPEC 0 +#endif + +/* +************************************************************************** +** A network address +** +** Only Internet Protocol (IPv4 and IPv6) addresses are supported. +** The address family must always represent IPv4 (AF_INET, probably == 2) +** or IPv6 (AF_INET6). +************************************************************************** +*************************************************************************/ + +struct PRIPv6Addr { + union { + PRUint8 _S6_u8[16]; + PRUint16 _S6_u16[8]; + PRUint32 _S6_u32[4]; + PRUint64 _S6_u64[2]; + } _S6_un; +}; +#define pr_s6_addr _S6_un._S6_u8 +#define pr_s6_addr16 _S6_un._S6_u16 +#define pr_s6_addr32 _S6_un._S6_u32 +#define pr_s6_addr64 _S6_un._S6_u64 + +typedef struct PRIPv6Addr PRIPv6Addr; + +union PRNetAddr { + struct { + PRUint16 family; /* address family (0x00ff maskable) */ +#ifdef XP_BEOS + char data[10]; /* Be has a smaller structure */ +#else + char data[14]; /* raw address data */ +#endif + } raw; + struct { + PRUint16 family; /* address family (AF_INET) */ + PRUint16 port; /* port number */ + PRUint32 ip; /* The actual 32 bits of address */ +#ifdef XP_BEOS + char pad[4]; /* Be has a smaller structure */ +#else + char pad[8]; +#endif + } inet; + struct { + PRUint16 family; /* address family (AF_INET6) */ + PRUint16 port; /* port number */ + PRUint32 flowinfo; /* routing information */ + PRIPv6Addr ip; /* the actual 128 bits of address */ + PRUint32 scope_id; /* set of interfaces for a scope */ + } ipv6; +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + struct { /* Unix domain socket address */ + PRUint16 family; /* address family (AF_UNIX) */ +#ifdef XP_OS2 + char path[108]; /* null-terminated pathname */ + /* bind fails if size is not 108. */ +#else + char path[104]; /* null-terminated pathname */ +#endif + } local; +#endif +}; + +/* +*************************************************************************** +** PRSockOption +** +** The file descriptors can have predefined options set after they file +** descriptor is created to change their behavior. Only the options in +** the following enumeration are supported. +*************************************************************************** +*/ +typedef enum PRSockOption +{ + PR_SockOpt_Nonblocking, /* nonblocking io */ + PR_SockOpt_Linger, /* linger on close if data present */ + PR_SockOpt_Reuseaddr, /* allow local address reuse */ + PR_SockOpt_Keepalive, /* keep connections alive */ + PR_SockOpt_RecvBufferSize, /* send buffer size */ + PR_SockOpt_SendBufferSize, /* receive buffer size */ + + PR_SockOpt_IpTimeToLive, /* time to live */ + PR_SockOpt_IpTypeOfService, /* type of service and precedence */ + + PR_SockOpt_AddMember, /* add an IP group membership */ + PR_SockOpt_DropMember, /* drop an IP group membership */ + PR_SockOpt_McastInterface, /* multicast interface address */ + PR_SockOpt_McastTimeToLive, /* multicast timetolive */ + PR_SockOpt_McastLoopback, /* multicast loopback */ + + PR_SockOpt_NoDelay, /* don't delay send to coalesce packets */ + PR_SockOpt_MaxSegment, /* maximum segment size */ + PR_SockOpt_Broadcast, /* enable broadcast */ + PR_SockOpt_Last +} PRSockOption; + +typedef struct PRLinger { + PRBool polarity; /* Polarity of the option's setting */ + PRIntervalTime linger; /* Time to linger before closing */ +} PRLinger; + +typedef struct PRMcastRequest { + PRNetAddr mcaddr; /* IP multicast address of group */ + PRNetAddr ifaddr; /* local IP address of interface */ +} PRMcastRequest; + +typedef struct PRSocketOptionData +{ + PRSockOption option; + union + { + PRUintn ip_ttl; /* IP time to live */ + PRUintn mcast_ttl; /* IP multicast time to live */ + PRUintn tos; /* IP type of service and precedence */ + PRBool non_blocking; /* Non-blocking (network) I/O */ + PRBool reuse_addr; /* Allow local address reuse */ + PRBool keep_alive; /* Keep connections alive */ + PRBool mcast_loopback; /* IP multicast loopback */ + PRBool no_delay; /* Don't delay send to coalesce packets */ + PRBool broadcast; /* Enable broadcast */ + PRSize max_segment; /* Maximum segment size */ + PRSize recv_buffer_size; /* Receive buffer size */ + PRSize send_buffer_size; /* Send buffer size */ + PRLinger linger; /* Time to linger on close if data present */ + PRMcastRequest add_member; /* add an IP group membership */ + PRMcastRequest drop_member; /* Drop an IP group membership */ + PRNetAddr mcast_if; /* multicast interface address */ + } value; +} PRSocketOptionData; + +/* +*************************************************************************** +** PRIOVec +** +** The I/O vector is used by the write vector method to describe the areas +** that are affected by the ouput operation. +*************************************************************************** +*/ +typedef struct PRIOVec { + char *iov_base; + int iov_len; +} PRIOVec; + +/* +*************************************************************************** +** Discover what type of socket is being described by the file descriptor. +*************************************************************************** +*/ +typedef enum PRDescType +{ + PR_DESC_FILE = 1, + PR_DESC_SOCKET_TCP = 2, + PR_DESC_SOCKET_UDP = 3, + PR_DESC_LAYERED = 4, + PR_DESC_PIPE = 5 +} PRDescType; + +typedef enum PRSeekWhence { + PR_SEEK_SET = 0, + PR_SEEK_CUR = 1, + PR_SEEK_END = 2 +} PRSeekWhence; + +NSPR_API(PRDescType) PR_GetDescType(PRFileDesc *file); + +/* +*************************************************************************** +** PRIOMethods +** +** The I/O methods table provides procedural access to the functions of +** the file descriptor. It is the responsibility of a layer implementor +** to provide suitable functions at every entry point. If a layer provides +** no functionality, it should call the next lower(higher) function of the +** same name (e.g., return fd->lower->method->close(fd->lower)); +** +** Not all functions are implemented for all types of files. In cases where +** that is true, the function will return a error indication with an error +** code of PR_INVALID_METHOD_ERROR. +*************************************************************************** +*/ + +typedef PRStatus (PR_CALLBACK *PRCloseFN)(PRFileDesc *fd); +typedef PRInt32 (PR_CALLBACK *PRReadFN)(PRFileDesc *fd, void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRWriteFN)(PRFileDesc *fd, const void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRAvailableFN)(PRFileDesc *fd); +typedef PRInt64 (PR_CALLBACK *PRAvailable64FN)(PRFileDesc *fd); +typedef PRStatus (PR_CALLBACK *PRFsyncFN)(PRFileDesc *fd); +typedef PROffset32 (PR_CALLBACK *PRSeekFN)(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how); +typedef PROffset64 (PR_CALLBACK *PRSeek64FN)(PRFileDesc *fd, PROffset64 offset, PRSeekWhence how); +typedef PRStatus (PR_CALLBACK *PRFileInfoFN)(PRFileDesc *fd, PRFileInfo *info); +typedef PRStatus (PR_CALLBACK *PRFileInfo64FN)(PRFileDesc *fd, PRFileInfo64 *info); +typedef PRInt32 (PR_CALLBACK *PRWritevFN)( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectFN)( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRFileDesc* (PR_CALLBACK *PRAcceptFN) ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRBindFN)(PRFileDesc *fd, const PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRListenFN)(PRFileDesc *fd, PRIntn backlog); +typedef PRStatus (PR_CALLBACK *PRShutdownFN)(PRFileDesc *fd, PRIntn how); +typedef PRInt32 (PR_CALLBACK *PRRecvFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendFN) ( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRRecvfromFN)( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt32 (PR_CALLBACK *PRSendtoFN)( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout); +typedef PRInt16 (PR_CALLBACK *PRPollFN)( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); +typedef PRInt32 (PR_CALLBACK *PRAcceptreadFN)( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime t); +typedef PRInt32 (PR_CALLBACK *PRTransmitfileFN)( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime t); +typedef PRStatus (PR_CALLBACK *PRGetsocknameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetpeernameFN)(PRFileDesc *fd, PRNetAddr *addr); +typedef PRStatus (PR_CALLBACK *PRGetsocketoptionFN)( + PRFileDesc *fd, PRSocketOptionData *data); +typedef PRStatus (PR_CALLBACK *PRSetsocketoptionFN)( + PRFileDesc *fd, const PRSocketOptionData *data); +typedef PRInt32 (PR_CALLBACK *PRSendfileFN)( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); +typedef PRStatus (PR_CALLBACK *PRConnectcontinueFN)( + PRFileDesc *fd, PRInt16 out_flags); +typedef PRIntn (PR_CALLBACK *PRReservedFN)(PRFileDesc *fd); + +struct PRIOMethods { + PRDescType file_type; /* Type of file represented (tos) */ + PRCloseFN close; /* close file and destroy descriptor */ + PRReadFN read; /* read up to specified bytes into buffer */ + PRWriteFN write; /* write specified bytes from buffer */ + PRAvailableFN available; /* determine number of bytes available */ + PRAvailable64FN available64; /* ditto, 64 bit */ + PRFsyncFN fsync; /* flush all buffers to permanent store */ + PRSeekFN seek; /* position the file to the desired place */ + PRSeek64FN seek64; /* ditto, 64 bit */ + PRFileInfoFN fileInfo; /* Get information about an open file */ + PRFileInfo64FN fileInfo64; /* ditto, 64 bit */ + PRWritevFN writev; /* Write segments as described by iovector */ + PRConnectFN connect; /* Connect to the specified (net) address */ + PRAcceptFN accept; /* Accept a connection for a (net) peer */ + PRBindFN bind; /* Associate a (net) address with the fd */ + PRListenFN listen; /* Prepare to listen for (net) connections */ + PRShutdownFN shutdown; /* Shutdown a (net) connection */ + PRRecvFN recv; /* Solicit up the the specified bytes */ + PRSendFN send; /* Send all the bytes specified */ + PRRecvfromFN recvfrom; /* Solicit (net) bytes and report source */ + PRSendtoFN sendto; /* Send bytes to (net) address specified */ + PRPollFN poll; /* Test the fd to see if it is ready */ + PRAcceptreadFN acceptread; /* Accept and read on a new (net) fd */ + PRTransmitfileFN transmitfile; /* Transmit at entire file */ + PRGetsocknameFN getsockname; /* Get (net) address associated with fd */ + PRGetpeernameFN getpeername; /* Get peer's (net) address */ + PRReservedFN reserved_fn_6; /* reserved for future use */ + PRReservedFN reserved_fn_5; /* reserved for future use */ + PRGetsocketoptionFN getsocketoption; + /* Get current setting of specified option */ + PRSetsocketoptionFN setsocketoption; + /* Set value of specified option */ + PRSendfileFN sendfile; /* Send a (partial) file with header/trailer*/ + PRConnectcontinueFN connectcontinue; + /* Continue a nonblocking connect */ + PRReservedFN reserved_fn_3; /* reserved for future use */ + PRReservedFN reserved_fn_2; /* reserved for future use */ + PRReservedFN reserved_fn_1; /* reserved for future use */ + PRReservedFN reserved_fn_0; /* reserved for future use */ +}; + +/* + ************************************************************************** + * FUNCTION: PR_GetSpecialFD + * DESCRIPTION: Get the file descriptor that represents the standard input, + * output, or error stream. + * INPUTS: + * PRSpecialFD id + * A value indicating the type of stream desired: + * PR_StandardInput: standard input + * PR_StandardOuput: standard output + * PR_StandardError: standard error + * OUTPUTS: none + * RETURNS: PRFileDesc * + * If the argument is valid, PR_GetSpecialFD returns a file descriptor + * that represents the corresponding standard I/O stream. Otherwise, + * PR_GetSpecialFD returns NULL and sets error PR_INVALID_ARGUMENT_ERROR. + ************************************************************************** + */ + +typedef enum PRSpecialFD +{ + PR_StandardInput, /* standard input */ + PR_StandardOutput, /* standard output */ + PR_StandardError /* standard error */ +} PRSpecialFD; + +NSPR_API(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD id); + +#define PR_STDIN PR_GetSpecialFD(PR_StandardInput) +#define PR_STDOUT PR_GetSpecialFD(PR_StandardOutput) +#define PR_STDERR PR_GetSpecialFD(PR_StandardError) + +/* + ************************************************************************** + * Layering file descriptors + * + * File descriptors may be layered. Each layer has it's own identity. + * Identities are allocated by the runtime and are to be associated + * (by the layer implementor) with all layers that are of that type. + * It is then possible to scan the chain of layers and find a layer + * that one recongizes and therefore predict that it will implement + * a desired protocol. + * + * There are three well-known identities: + * PR_INVALID_IO_LAYER => an invalid layer identity, for error return + * PR_TOP_IO_LAYER => the identity of the top of the stack + * PR_NSPR_IO_LAYER => the identity used by NSPR proper + * PR_TOP_IO_LAYER may be used as a shorthand for identifying the topmost + * layer of an existing stack. Ie., the following two constructs are + * equivalent. + * + * rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, my_layer); + * rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), my_layer) + * + * A string may be associated with the creation of the identity. It + * will be copied by the runtime. If queried the runtime will return + * a reference to that copied string (not yet another copy). There + * is no facility for deleting an identity. + ************************************************************************** + */ + +#define PR_IO_LAYER_HEAD (PRDescIdentity)-3 +#define PR_INVALID_IO_LAYER (PRDescIdentity)-1 +#define PR_TOP_IO_LAYER (PRDescIdentity)-2 +#define PR_NSPR_IO_LAYER (PRDescIdentity)0 + +NSPR_API(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name); +NSPR_API(const char*) PR_GetNameForIdentity(PRDescIdentity ident); +NSPR_API(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd); +NSPR_API(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * PR_GetDefaultIOMethods: Accessing the default methods table. + * You may get a pointer to the default methods table by calling this function. + * You may then select any elements from that table with which to build your + * layer's methods table. You may NOT modify the table directly. + ************************************************************************** + */ +NSPR_API(const PRIOMethods *) PR_GetDefaultIOMethods(void); + +/* + ************************************************************************** + * Creating a layer + * + * A new layer may be allocated by calling PR_CreateIOLayerStub(). The + * file descriptor returned will contain the pointer to the methods table + * provided. The runtime will not modify the table nor test its correctness. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods); + +/* + ************************************************************************** + * Creating a layer + * + * A new stack may be created by calling PR_CreateIOLayer(). The + * file descriptor returned will point to the top of the stack, which has + * the layer 'fd' as the topmost layer. + * + * NOTE: This function creates a new style stack, which has a fixed, dummy + * header. The old style stack, created by a call to PR_PushIOLayer, + * results in modifying contents of the top layer of the stack, when + * pushing and popping layers of the stack. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_CreateIOLayer(PRFileDesc* fd); + +/* + ************************************************************************** + * Pushing a layer + * + * A file descriptor (perhaps allocated using PR_CreateIOLayerStub()) may + * be pushed into an existing stack of file descriptors at any point the + * caller deems appropriate. The new layer will be inserted into the stack + * just above the layer with the indicated identity. + * + * Note: Even if the identity parameter indicates the top-most layer of + * the stack, the value of the file descriptor describing the original + * stack will not change. + ************************************************************************** + */ +NSPR_API(PRStatus) PR_PushIOLayer( + PRFileDesc *fd_stack, PRDescIdentity id, PRFileDesc *layer); + +/* + ************************************************************************** + * Popping a layer + * + * A layer may be popped from a stack by indicating the identity of the + * layer to be removed. If found, a pointer to the removed object will + * be returned to the caller. The object then becomes the responsibility + * of the caller. + * + * Note: Even if the identity indicates the top layer of the stack, the + * reference returned will not be the file descriptor for the stack and + * that file descriptor will remain valid. + ************************************************************************** + */ +NSPR_API(PRFileDesc*) PR_PopIOLayer(PRFileDesc *fd_stack, PRDescIdentity id); + +/* + ************************************************************************** + * FUNCTION: PR_Open + * DESCRIPTION: Open a file for reading, writing, or both. + * INPUTS: + * const char *name + * The path name of the file to be opened + * PRIntn flags + * The file status flags. + * It is a bitwise OR of the following bit flags (only one of + * the first three flags below may be used): + * PR_RDONLY Open for reading only. + * PR_WRONLY Open for writing only. + * PR_RDWR Open for reading and writing. + * PR_CREATE_FILE If the file does not exist, the file is created + * If the file exists, this flag has no effect. + * PR_SYNC If set, each write will wait for both the file data + * and file status to be physically updated. + * PR_APPEND The file pointer is set to the end of + * the file prior to each write. + * PR_TRUNCATE If the file exists, its length is truncated to 0. + * PR_EXCL With PR_CREATE_FILE, if the file does not exist, + * the file is created. If the file already + * exists, no action and NULL is returned + * + * PRIntn mode + * The access permission bits of the file mode, if the file is + * created when PR_CREATE_FILE is on. + * OUTPUTS: None + * RETURNS: PRFileDesc * + * If the file is successfully opened, + * returns a pointer to the PRFileDesc + * created for the newly opened file. + * Returns a NULL pointer if the open + * failed. + * SIDE EFFECTS: + * RESTRICTIONS: + * MEMORY: + * The return value, if not NULL, points to a dynamically allocated + * PRFileDesc object. + * ALGORITHM: + ************************************************************************** + */ + +/* Open flags */ +#define PR_RDONLY 0x01 +#define PR_WRONLY 0x02 +#define PR_RDWR 0x04 +#define PR_CREATE_FILE 0x08 +#define PR_APPEND 0x10 +#define PR_TRUNCATE 0x20 +#define PR_SYNC 0x40 +#define PR_EXCL 0x80 + +/* +** File modes .... +** +** CAVEAT: 'mode' is currently only applicable on UNIX platforms. +** The 'mode' argument may be ignored by PR_Open on other platforms. +** +** 00400 Read by owner. +** 00200 Write by owner. +** 00100 Execute (search if a directory) by owner. +** 00040 Read by group. +** 00020 Write by group. +** 00010 Execute by group. +** 00004 Read by others. +** 00002 Write by others +** 00001 Execute by others. +** +*/ + +NSPR_API(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode); + +/* + ************************************************************************** + * FUNCTION: PR_OpenFile + * DESCRIPTION: + * Open a file for reading, writing, or both. + * PR_OpenFile has the same prototype as PR_Open but implements + * the specified file mode where possible. + ************************************************************************** + */ + +/* File mode bits */ +#define PR_IRWXU 00700 /* read, write, execute/search by owner */ +#define PR_IRUSR 00400 /* read permission, owner */ +#define PR_IWUSR 00200 /* write permission, owner */ +#define PR_IXUSR 00100 /* execute/search permission, owner */ +#define PR_IRWXG 00070 /* read, write, execute/search by group */ +#define PR_IRGRP 00040 /* read permission, group */ +#define PR_IWGRP 00020 /* write permission, group */ +#define PR_IXGRP 00010 /* execute/search permission, group */ +#define PR_IRWXO 00007 /* read, write, execute/search by others */ +#define PR_IROTH 00004 /* read permission, others */ +#define PR_IWOTH 00002 /* write permission, others */ +#define PR_IXOTH 00001 /* execute/search permission, others */ + +NSPR_API(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_Close + * DESCRIPTION: + * Close a file or socket. + * INPUTS: + * PRFileDesc *fd + * a pointer to a PRFileDesc. + * OUTPUTS: + * None. + * RETURN: + * PRStatus + * SIDE EFFECTS: + * RESTRICTIONS: + * None. + * MEMORY: + * The dynamic memory pointed to by the argument fd is freed. + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Close(PRFileDesc *fd); + +/* + ************************************************************************** + * FUNCTION: PR_Read + * DESCRIPTION: + * Read bytes from a file or socket. + * The operation will block until either an end of stream indication is + * encountered, some positive number of bytes are transferred, or there + * is an error. No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * pointer to the PRFileDesc object for the file or socket + * void *buf + * pointer to a buffer to hold the data read in. + * PRInt32 amount + * the size of 'buf' (in bytes) + * OUTPUTS: + * RETURN: + * PRInt32 + * a positive number indicates the number of bytes actually read in. + * 0 means end of file is reached or the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + * SIDE EFFECTS: + * data is written into the buffer pointed to by 'buf'. + * RESTRICTIONS: + * None. + * MEMORY: + * N/A + * ALGORITHM: + * N/A + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Write + * DESCRIPTION: + * Write a specified number of bytes to a file or socket. The thread + * invoking this function blocks until all the data is written. + * INPUTS: + * PRFileDesc *fd + * pointer to a PRFileDesc object that refers to a file or socket + * const void *buf + * pointer to the buffer holding the data + * PRInt32 amount + * amount of data in bytes to be written from the buffer + * OUTPUTS: + * None. + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +NSPR_API(PRInt32) PR_Write(PRFileDesc *fd,const void *buf,PRInt32 amount); + +/* + *************************************************************************** + * FUNCTION: PR_Writev + * DESCRIPTION: + * Write data to a socket. The data is organized in a PRIOVec array. The + * operation will block until all the data is written or the operation + * fails. + * INPUTS: + * PRFileDesc *fd + * Pointer that points to a PRFileDesc object for a socket. + * const PRIOVec *iov + * An array of PRIOVec. PRIOVec is a struct with the following + * two fields: + * char *iov_base; + * int iov_len; + * PRInt32 iov_size + * Number of elements in the iov array. The value of this + * argument must not be greater than PR_MAX_IOVECTOR_SIZE. + * If it is, the method will fail (PR_BUFFER_OVERFLOW_ERROR). + * PRIntervalTime timeout + * Time limit for completion of the entire write operation. + * OUTPUTS: + * None + * RETURN: + * A positive number indicates the number of bytes successfully written. + * A -1 is an indication that the operation failed. The reason + * for the failure is obtained by calling PR_GetError(). + *************************************************************************** + */ + +#define PR_MAX_IOVECTOR_SIZE 16 /* 'iov_size' must be <= */ + +NSPR_API(PRInt32) PR_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout); + +/* + *************************************************************************** + * FUNCTION: PR_Delete + * DESCRIPTION: + * Delete a file from the filesystem. The operation may fail if the + * file is open. + * INPUTS: + * const char *name + * Path name of the file to be deleted. + * OUTPUTS: + * None. + * RETURN: PRStatus + * The function returns PR_SUCCESS if the file is successfully + * deleted, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_Delete(const char *name); + +/**************************************************************************/ + +typedef enum PRFileType +{ + PR_FILE_FILE = 1, + PR_FILE_DIRECTORY = 2, + PR_FILE_OTHER = 3 +} PRFileType; + +struct PRFileInfo { + PRFileType type; /* Type of file */ + PROffset32 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +struct PRFileInfo64 { + PRFileType type; /* Type of file */ + PROffset64 size; /* Size, in bytes, of file's contents */ + PRTime creationTime; /* Creation time per definition of PRTime */ + PRTime modifyTime; /* Last modification time per definition of PRTime */ +}; + +/**************************************************************************** + * FUNCTION: PR_GetFileInfo, PR_GetFileInfo64 + * DESCRIPTION: + * Get the information about the file with the given path name. This is + * applicable only to NSFileDesc describing 'file' types (see + * INPUTS: + * const char *fn + * path name of the file + * OUTPUTS: + * PRFileInfo *info + * Information about the given file is written into the file + * information object pointer to by 'info'. + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************** + * FUNCTION: PR_GetOpenFileInfo, PR_GetOpenFileInfo64 + * DESCRIPTION: + * Get information about an open file referred to by the + * given PRFileDesc object. + * INPUTS: + * const PRFileDesc *fd + * A reference to a valid, open file. + * OUTPUTS: + * Same as PR_GetFileInfo, PR_GetFileInfo64 + * RETURN: PRStatus + * PR_GetFileInfo returns PR_SUCCESS if file information is successfully + * obtained, otherwise it returns PR_FAILURE. + *************************************************************************** + */ + +NSPR_API(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info); +NSPR_API(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info); + +/* + ************************************************************************** + * FUNCTION: PR_Rename + * DESCRIPTION: + * Rename a file from the old name 'from' to the new name 'to'. + * INPUTS: + * const char *from + * The old name of the file to be renamed. + * const char *to + * The new name of the file. + * OUTPUTS: + * None. + * RETURN: PRStatus + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Rename(const char *from, const char *to); + +/* + ************************************************************************* + * FUNCTION: PR_Access + * DESCRIPTION: + * Determine accessibility of a file. + * INPUTS: + * const char *name + * path name of the file + * PRAccessHow how + * specifies which access permission to check for. + * It can be one of the following values: + * PR_ACCESS_READ_OK Test for read permission + * PR_ACCESS_WRITE_OK Test for write permission + * PR_ACCESS_EXISTS Check existence of file + * OUTPUTS: + * None. + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. Additional information + * regarding the reason for the failure may be retrieved from + * PR_GetError(). + ************************************************************************* + */ + +typedef enum PRAccessHow { + PR_ACCESS_EXISTS = 1, + PR_ACCESS_WRITE_OK = 2, + PR_ACCESS_READ_OK = 3 +} PRAccessHow; + +NSPR_API(PRStatus) PR_Access(const char *name, PRAccessHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Seek, PR_Seek64 + * DESCRIPTION: + * Moves read-write file offset + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object. + * PROffset32, PROffset64 offset + * Specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the file pointer. A + * negative value causes seeking in the reverse direction. + * PRSeekWhence whence + * Specifies how to interpret the 'offset' parameter in setting + * the file pointer associated with the 'fd' parameter. + * Values for the 'whence' parameter are: + * PR_SEEK_SET Sets the file pointer to the value of the + * 'offset' parameter + * PR_SEEK_CUR Sets the file pointer to its current location + * plus the value of the offset parameter. + * PR_SEEK_END Sets the file pointer to the size of the + * file plus the value of the offset parameter. + * OUTPUTS: + * None. + * RETURN: PROffset32, PROffset64 + * Upon successful completion, the resulting pointer location, + * measured in bytes from the beginning of the file, is returned. + * If the PR_Seek() function fails, the file offset remains + * unchanged, and the returned value is -1. The error code can + * then be retrieved via PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PROffset32) PR_Seek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +NSPR_API(PROffset64) PR_Seek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence); + +/* + ************************************************************************ + * FUNCTION: PR_Available + * DESCRIPTION: + * Determine the amount of data in bytes available for reading + * in the given file or socket. + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket. + * OUTPUTS: + * None + * RETURN: PRInt32, PRInt64 + * Upon successful completion, PR_Available returns the number of + * bytes beyond the current read pointer that is available for + * reading. Otherwise, it returns a -1 and the reason for the + * failure can be retrieved via PR_GetError(). + ************************************************************************ + */ + +NSPR_API(PRInt32) PR_Available(PRFileDesc *fd); +NSPR_API(PRInt64) PR_Available64(PRFileDesc *fd); + +/* + ************************************************************************ + * FUNCTION: PR_Sync + * DESCRIPTION: + * Sync any buffered data for a fd to its backing device (disk). + * INPUTS: + * PRFileDesc *fd + * Pointer to a PRFileDesc object that refers to a file or + * socket + * OUTPUTS: + * None + * RETURN: PRStatus + * PR_SUCCESS is returned if the requested access is permitted. + * Otherwise, PR_FAILURE is returned. + ************************************************************************ + */ + +NSPR_API(PRStatus) PR_Sync(PRFileDesc *fd); + +/************************************************************************/ + +struct PRDirEntry { + const char *name; /* name of entry, relative to directory name */ +}; + +#ifdef MOZ_UNICODE +struct PRDirEntryUTF16 { + const PRUnichar *name; /* name of entry in UTF16, relative to + * directory name */ +}; +#endif /* MOZ_UNICODE */ + +#if !defined(NO_NSPR_10_SUPPORT) +#define PR_DirName(dirEntry) (dirEntry->name) +#endif + +/* + ************************************************************************* + * FUNCTION: PR_OpenDir + * DESCRIPTION: + * Open the directory by the given name + * INPUTS: + * const char *name + * path name of the directory to be opened + * OUTPUTS: + * None + * RETURN: PRDir * + * If the directory is sucessfully opened, a PRDir object is + * dynamically allocated and a pointer to it is returned. + * If the directory cannot be opened, a NULL pointer is returned. + * MEMORY: + * Upon successful completion, the return value points to + * dynamically allocated memory. + ************************************************************************* + */ + +NSPR_API(PRDir*) PR_OpenDir(const char *name); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_ReadDir + * DESCRIPTION: + * INPUTS: + * PRDir *dir + * pointer to a PRDir object that designates an open directory + * PRDirFlags flags + * PR_SKIP_NONE Do not skip any files + * PR_SKIP_DOT Skip the directory entry "." that + * represents the current directory + * PR_SKIP_DOT_DOT Skip the directory entry ".." that + * represents the parent directory. + * PR_SKIP_BOTH Skip both '.' and '..' + * PR_SKIP_HIDDEN Skip hidden files + * OUTPUTS: + * RETURN: PRDirEntry* + * Returns a pointer to the next entry in the directory. Returns + * a NULL pointer upon reaching the end of the directory or when an + * error occurs. The actual reason can be retrieved via PR_GetError(). + ************************************************************************* + */ + +typedef enum PRDirFlags { + PR_SKIP_NONE = 0x0, + PR_SKIP_DOT = 0x1, + PR_SKIP_DOT_DOT = 0x2, + PR_SKIP_BOTH = 0x3, + PR_SKIP_HIDDEN = 0x4 +} PRDirFlags; + +NSPR_API(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_CloseDir + * DESCRIPTION: + * Close the specified directory. + * INPUTS: + * PRDir *dir + * The directory to be closed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_CloseDir(PRDir *dir); + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This function may be removed in a future release. + */ +NSPR_API(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir); +#endif /* MOZ_UNICODE */ + +/* + ************************************************************************* + * FUNCTION: PR_MkDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * INPUTS: + * const char *name + * The name of the directory to be created. All the path components + * up to but not including the leaf component must already exist. + * PRIntn mode + * See 'mode' definiton in PR_Open(). + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MkDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_MakeDir + * DESCRIPTION: + * Create a new directory with the given name and access mode. + * PR_MakeDir has the same prototype as PR_MkDir but implements + * the specified access mode where possible. + ************************************************************************* + */ + +NSPR_API(PRStatus) PR_MakeDir(const char *name, PRIntn mode); + +/* + ************************************************************************* + * FUNCTION: PR_RmDir + * DESCRIPTION: + * Remove a directory by the given name. + * INPUTS: + * const char *name + * The name of the directory to be removed. All the path components + * must already exist. Only the leaf component will be removed. + * OUTPUTS: + * None + * RETURN: PRStatus + * If successful, will return a status of PR_SUCCESS. Otherwise + * a value of PR_FAILURE. The reason for the failure may be re- + * trieved using PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_RmDir(const char *name); + +/* + ************************************************************************* + * FUNCTION: PR_NewUDPSocket + * DESCRIPTION: + * Create a new UDP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewUDPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_NewTCPSocket + * DESCRIPTION: + * Create a new TCP socket. + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_NewTCPSocket(void); + +/* + ************************************************************************* + * FUNCTION: PR_OpenUDPSocket + * DESCRIPTION: + * Create a new UDP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_OpenUDPSocket returns a pointer + * to the PRFileDesc created for the newly opened UDP socket. + * Returns a NULL pointer if the creation of a new UDP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenUDPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_OpenTCPSocket + * DESCRIPTION: + * Create a new TCP socket of the specified address family. + * INPUTS: + * PRIntn af + * Address family + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_NewTCPSocket returns a pointer + * to the PRFileDesc created for the newly opened TCP socket. + * Returns a NULL pointer if the creation of a new TCP socket failed. + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_OpenTCPSocket(PRIntn af); + +/* + ************************************************************************* + * FUNCTION: PR_Connect + * DESCRIPTION: + * Initiate a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket + * PRNetAddr *addr + * Specifies the address of the socket in its own communication + * space. + * PRIntervalTime timeout + * Time limit for completion of the connect operation. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of connection initiation, PR_Connect + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_ConnectContinue + * DESCRIPTION: + * Continue a nonblocking connect. After a nonblocking connect + * is initiated with PR_Connect() (which fails with + * PR_IN_PROGRESS_ERROR), one should call PR_Poll() on the socket, + * with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. When + * PR_Poll() returns, one calls PR_ConnectContinue() on the + * socket to determine whether the nonblocking connect has + * completed or is still in progress. Repeat the PR_Poll(), + * PR_ConnectContinue() sequence until the nonblocking connect + * has completed. + * INPUTS: + * PRFileDesc *fd + * the file descriptor representing a socket + * PRInt16 out_flags + * the out_flags field of the poll descriptor returned by + * PR_Poll() + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_ConnectContinue returns PR_SUCCESS. If PR_ConnectContinue() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. The caller should poll + * on the file descriptor for the in_flags + * PR_POLL_WRITE|PR_POLL_EXCEPT and retry PR_ConnectContinue + * later when PR_Poll() returns. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_ConnectContinue(PRFileDesc *fd, PRInt16 out_flags); + +/* + ************************************************************************* + * THIS FUNCTION IS DEPRECATED. USE PR_ConnectContinue INSTEAD. + * + * FUNCTION: PR_GetConnectStatus + * DESCRIPTION: + * Get the completion status of a nonblocking connect. After + * a nonblocking connect is initiated with PR_Connect() (which + * fails with PR_IN_PROGRESS_ERROR), one should call PR_Poll() + * on the socket, with the in_flags PR_POLL_WRITE | PR_POLL_EXCEPT. + * When PR_Poll() returns, one calls PR_GetConnectStatus on the + * PRPollDesc structure to determine whether the nonblocking + * connect has succeeded or failed. + * INPUTS: + * const PRPollDesc *pd + * Pointer to a PRPollDesc whose fd member is the socket, + * and in_flags must contain PR_POLL_WRITE and PR_POLL_EXCEPT. + * PR_Poll() should have been called and set the out_flags. + * RETURN: PRStatus + * If the nonblocking connect has successfully completed, + * PR_GetConnectStatus returns PR_SUCCESS. If PR_GetConnectStatus() + * returns PR_FAILURE, call PR_GetError(): + * - PR_IN_PROGRESS_ERROR: the nonblocking connect is still in + * progress and has not completed yet. + * - Other errors: the nonblocking connect has failed with this + * error code. + */ + +NSPR_API(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd); + +/* + ************************************************************************* + * FUNCTION: PR_Accept + * DESCRIPTION: + * Accept a connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing the rendezvous socket + * on which the caller is willing to accept new connections. + * PRIntervalTime timeout + * Time limit for completion of the accept operation. + * OUTPUTS: + * PRNetAddr *addr + * Returns the address of the connecting entity in its own + * communication space. It may be NULL. + * RETURN: PRFileDesc* + * Upon successful acceptance of a connection, PR_Accept + * returns a valid file descriptor. Otherwise, it returns NULL. + * Further failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Bind + * DESCRIPTION: + * Bind an address to a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket. + * PRNetAddr *addr + * Specifies the address to which the socket will be bound. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful binding of an address to a socket, PR_Bind + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr); + +/* + ************************************************************************* + * FUNCTION: PR_Listen + * DESCRIPTION: + * Listen for connections on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a socket that will be + * used to listen for new connections. + * PRIntn backlog + * Specifies the maximum length of the queue of pending connections. + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of listen request, PR_Listen + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog); + +/* + ************************************************************************* + * FUNCTION: PR_Shutdown + * DESCRIPTION: + * Shut down part of a full-duplex connection on a socket. + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object representing a connected socket. + * PRIntn how + * Specifies the kind of disallowed operations on the socket. + * PR_SHUTDOWN_RCV - Further receives will be disallowed + * PR_SHUTDOWN_SEND - Further sends will be disallowed + * PR_SHUTDOWN_BOTH - Further sends and receives will be disallowed + * OUTPUTS: + * None + * RETURN: PRStatus + * Upon successful completion of shutdown request, PR_Shutdown + * returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further + * failure information can be obtained by calling PR_GetError(). + ************************************************************************** + */ + +typedef enum PRShutdownHow +{ + PR_SHUTDOWN_RCV = 0, /* disallow further receives */ + PR_SHUTDOWN_SEND = 1, /* disallow further sends */ + PR_SHUTDOWN_BOTH = 2 /* disallow further receives and sends */ +} PRShutdownHow; + +NSPR_API(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how); + +/* + ************************************************************************* + * FUNCTION: PR_Recv + * DESCRIPTION: + * Receive a specified number of bytes from a connected socket. + * The operation will block until some positive number of bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * must be zero or PR_MSG_PEEK. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +#define PR_MSG_PEEK 0x2 + +NSPR_API(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_Send + * DESCRIPTION: + * Send a specified number of bytes from a connected socket. + * The operation will block until all bytes are + * processed, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully processed. + * This number must always equal 'amount'. A -1 is an indication that the + * operation failed. The reason for the failure is obtained by calling + * PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_RecvFrom + * DESCRIPTION: + * Receive up to a specified number of bytes from socket which may + * or may not be connected. + * The operation will block until one or more bytes are + * transferred, a time out has occurred, or there is an error. + * No more than 'amount' bytes will be transferred. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing a socket. + * void *buf + * pointer to a buffer to hold the data received. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the sending peer. It may be NULL. + * PRIntervalTime timeout + * Time limit for completion of the receive operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * a positive number indicates the number of bytes actually received. + * 0 means the network connection is closed. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_RecvFrom( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRIntervalTime timeout); + +/* + ************************************************************************* + * FUNCTION: PR_SendTo + * DESCRIPTION: + * Send a specified number of bytes from an unconnected socket. + * The operation will block until all bytes are + * sent, a time out has occurred, or there is an error. + * INPUTS: + * PRFileDesc *fd + * points to a PRFileDesc object representing an unconnected socket. + * void *buf + * pointer to a buffer from where the data is sent. + * PRInt32 amount + * the size of 'buf' (in bytes) + * PRIntn flags + * (OBSOLETE - must always be zero) + * PRNetAddr *addr + * Specifies the address of the peer. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. + * OUTPUTS: + * None + * RETURN: PRInt32 + * A positive number indicates the number of bytes successfully sent. + * -1 indicates a failure. The reason for the failure is obtained + * by calling PR_GetError(). + ************************************************************************** + */ + +NSPR_API(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_TransmitFile +** DESCRIPTION: +** Transmitfile sends a complete file (sourceFile) across a socket +** (networkSocket). If headers is non-NULL, the headers will be sent across +** the socket prior to sending the file. +** +** Optionally, the PR_TRANSMITFILE_CLOSE_SOCKET flag may be passed to +** transmitfile. This flag specifies that transmitfile should close the +** socket after sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRFileDesc *sourceFile +** The file to send +** const void *headers +** A pointer to headers to be sent before sending data +** PRInt32 hlen +** length of header buffers in bytes. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the transmit operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +NSPR_API(PRInt32) PR_TransmitFile( + PRFileDesc *networkSocket, PRFileDesc *sourceFile, + const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, + PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_SendFile +** DESCRIPTION: +** PR_SendFile sends data from a file (sendData->fd) across a socket +** (networkSocket). If specified, a header and/or trailer buffer are sent +** before and after the file, respectively. The file offset, number of bytes +** of file data to send, the header and trailer buffers are specified in the +** sendData argument. +** +** Optionally, if the PR_TRANSMITFILE_CLOSE_SOCKET flag is passed, the +** socket is closed after successfully sending the data. +** +** INPUTS: +** PRFileDesc *networkSocket +** The socket to send data over +** PRSendFileData *sendData +** Contains the FD, file offset and length, header and trailer +** buffer specifications. +** PRTransmitFileFlags flags +** If the flags indicate that the connection should be closed, +** it will be done immediately after transferring the file, unless +** the operation is unsuccessful. +.* PRIntervalTime timeout + * Time limit for completion of the send operation. +** +** RETURNS: +** Returns the number of bytes written or -1 if the operation failed. +** If an error occurs while sending the file, the PR_TRANSMITFILE_CLOSE_ +** SOCKET flag is ignored. The reason for the failure is obtained +** by calling PR_GetError(). +************************************************************************** +*/ + +struct PRSendFileData { + PRFileDesc *fd; /* file to send */ + PRUint32 file_offset; /* file offset */ + PRSize file_nbytes; /* number of bytes of file data to send */ + /* if 0, send data from file_offset to */ + /* end-of-file. */ + const void *header; /* header buffer */ + PRInt32 hlen; /* header len */ + const void *trailer; /* trailer buffer */ + PRInt32 tlen; /* trailer len */ +}; + + +NSPR_API(PRInt32) PR_SendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_AcceptRead +** DESCRIPTION: +** AcceptRead accepts a new connection, returns the newly created +** socket's descriptor and also returns the connecting peer's address. +** AcceptRead, as its name suggests, also receives the first block of data +** sent by the peer. +** +** INPUTS: +** PRFileDesc *listenSock +** A socket descriptor that has been called with the PR_Listen() +** function, also known as the rendezvous socket. +** void *buf +** A pointer to a buffer to receive data sent by the client. This +** buffer must be large enough to receive bytes of data +** and two PRNetAddr structures, plus an extra 32 bytes. See: +** PR_ACCEPT_READ_BUF_OVERHEAD. +** PRInt32 amount +** The number of bytes of client data to receive. Does not include +** the size of the PRNetAddr structures. If 0, no data will be read +** from the client. +** PRIntervalTime timeout +** The timeout interval only applies to the read portion of the +** operation. PR_AcceptRead will block indefinitely until the +** connection is accepted; the read will timeout after the timeout +** interval elapses. +** OUTPUTS: +** PRFileDesc **acceptedSock +** The file descriptor for the newly connected socket. This parameter +** will only be valid if the function return does not indicate failure. +** PRNetAddr **peerAddr, +** The address of the remote socket. This parameter will only be +** valid if the function return does not indicate failure. The +** returned address is not guaranteed to be properly aligned. +** +** RETURNS: +** The number of bytes read from the client or -1 on failure. The reason +** for the failure is obtained by calling PR_GetError(). +************************************************************************** +**/ +/* define buffer overhead constant. Add this value to the user's +** data length when allocating a buffer to accept data. +** Example: +** #define USER_DATA_SIZE 10 +** char buf[USER_DATA_SIZE + PR_ACCEPT_READ_BUF_OVERHEAD]; +** bytesRead = PR_AcceptRead( s, fd, &a, &p, USER_DATA_SIZE, ...); +*/ +#define PR_ACCEPT_READ_BUF_OVERHEAD (32+(2*sizeof(PRNetAddr))) + +NSPR_API(PRInt32) PR_AcceptRead( + PRFileDesc *listenSock, PRFileDesc **acceptedSock, + PRNetAddr **peerAddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +************************************************************************* +** FUNCTION: PR_NewTCPSocketPair +** DESCRIPTION: +** Create a new TCP socket pair. The returned descriptors can be used +** interchangeably; they are interconnected full-duplex descriptors: data +** written to one can be read from the other and vice-versa. +** +** INPUTS: +** None +** OUTPUTS: +** PRFileDesc *fds[2] +** The file descriptor pair for the newly created TCP sockets. +** RETURN: PRStatus +** Upon successful completion of TCP socket pair, PR_NewTCPSocketPair +** returns PR_SUCCESS. Otherwise, it returns PR_FAILURE. Further +** failure information can be obtained by calling PR_GetError(). +** XXX can we implement this on windoze and mac? +************************************************************************** +**/ +NSPR_API(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]); + +/* +************************************************************************* +** FUNCTION: PR_GetSockName +** DESCRIPTION: +** Get socket name. Return the network address for this socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the socket. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the socket in its own communication space. +** RETURN: PRStatus +** Upon successful completion, PR_GetSockName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr); + +/* +************************************************************************* +** FUNCTION: PR_GetPeerName +** DESCRIPTION: +** Get name of the connected peer. Return the network address for the +** connected peer socket. +** +** INPUTS: +** PRFileDesc *fd +** Points to a PRFileDesc object representing the connected peer. +** OUTPUTS: +** PRNetAddr *addr +** Returns the address of the connected peer in its own communication +** space. +** RETURN: PRStatus +** Upon successful completion, PR_GetPeerName returns PR_SUCCESS. +** Otherwise, it returns PR_FAILURE. Further failure information can +** be obtained by calling PR_GetError(). +************************************************************************** +**/ +NSPR_API(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +NSPR_API(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +/* + ********************************************************************* + * + * File descriptor inheritance + * + ********************************************************************* + */ + +/* + ************************************************************************ + * FUNCTION: PR_SetFDInheritable + * DESCRIPTION: + * Set the inheritance attribute of a file descriptor. + * + * INPUTS: + * PRFileDesc *fd + * Points to a PRFileDesc object. + * PRBool inheritable + * If PR_TRUE, the file descriptor fd is set to be inheritable + * by a child process. If PR_FALSE, the file descriptor is set + * to be not inheritable by a child process. + * RETURN: PRStatus + * Upon successful completion, PR_SetFDInheritable returns PR_SUCCESS. + * Otherwise, it returns PR_FAILURE. Further failure information can + * be obtained by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable); + +/* + ************************************************************************ + * FUNCTION: PR_GetInheritedFD + * DESCRIPTION: + * Get an inherited file descriptor with the specified name. + * + * INPUTS: + * const char *name + * The name of the inherited file descriptor. + * RETURN: PRFileDesc * + * Upon successful completion, PR_GetInheritedFD returns the + * inherited file descriptor with the specified name. Otherwise, + * it returns NULL. Further failure information can be obtained + * by calling PR_GetError(). + ************************************************************************* + */ +NSPR_API(PRFileDesc *) PR_GetInheritedFD(const char *name); + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +typedef struct PRFileMap PRFileMap; + +/* + * protection options for read and write accesses of a file mapping + */ +typedef enum PRFileMapProtect { + PR_PROT_READONLY, /* read only */ + PR_PROT_READWRITE, /* readable, and write is shared */ + PR_PROT_WRITECOPY /* readable, and write is private (copy-on-write) */ +} PRFileMapProtect; + +NSPR_API(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot); + +/* + * return the alignment (in bytes) of the offset argument to PR_MemMap + */ +NSPR_API(PRInt32) PR_GetMemMapAlignment(void); + +NSPR_API(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, /* must be aligned and sized according to the + * return value of PR_GetMemMapAlignment() */ + PRUint32 len); + +NSPR_API(PRStatus) PR_MemUnmap(void *addr, PRUint32 len); + +NSPR_API(PRStatus) PR_CloseFileMap(PRFileMap *fmap); + +/* + ****************************************************************** + * + * Interprocess communication + * + ****************************************************************** + */ + +/* + * Creates an anonymous pipe and returns file descriptors for the + * read and write ends of the pipe. + */ + +NSPR_API(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +); + +/************************************************************************/ +/************** The following definitions are for poll ******************/ +/************************************************************************/ + +struct PRPollDesc { + PRFileDesc* fd; + PRInt16 in_flags; + PRInt16 out_flags; +}; + +/* +** Bit values for PRPollDesc.in_flags or PRPollDesc.out_flags. Binary-or +** these together to produce the desired poll request. +*/ + +#if defined(_PR_POLL_BACKCOMPAT) + +#include +#define PR_POLL_READ POLLIN +#define PR_POLL_WRITE POLLOUT +#define PR_POLL_EXCEPT POLLPRI +#define PR_POLL_ERR POLLERR /* only in out_flags */ +#define PR_POLL_NVAL POLLNVAL /* only in out_flags when fd is bad */ +#define PR_POLL_HUP POLLHUP /* only in out_flags */ + +#else /* _PR_POLL_BACKCOMPAT */ + +#define PR_POLL_READ 0x1 +#define PR_POLL_WRITE 0x2 +#define PR_POLL_EXCEPT 0x4 +#define PR_POLL_ERR 0x8 /* only in out_flags */ +#define PR_POLL_NVAL 0x10 /* only in out_flags when fd is bad */ +#define PR_POLL_HUP 0x20 /* only in out_flags */ + +#endif /* _PR_POLL_BACKCOMPAT */ + +/* +************************************************************************* +** FUNCTION: PR_Poll +** DESCRIPTION: +** +** The call returns as soon as I/O is ready on one or more of the underlying +** socket objects. A count of the number of ready descriptors is +** returned unless a timeout occurs in which case zero is returned. +** +** PRPollDesc.fd should be set to a pointer to a PRFileDesc object +** representing a socket. This field can be set to NULL to indicate to +** PR_Poll that this PRFileDesc object should be ignored. +** PRPollDesc.in_flags should be set to the desired request +** (read/write/except or some combination). Upon successful return from +** this call PRPollDesc.out_flags will be set to indicate what kind of +** i/o can be performed on the respective descriptor. PR_Poll() uses the +** out_flags fields as scratch variables during the call. If PR_Poll() +** returns 0 or -1, the out_flags fields do not contain meaningful values +** and must not be used. +** +** INPUTS: +** PRPollDesc *pds A pointer to an array of PRPollDesc +** +** PRIntn npds The number of elements in the array +** If this argument is zero PR_Poll is +** equivalent to a PR_Sleep(timeout). +** +** PRIntervalTime timeout Amount of time the call will block waiting +** for I/O to become ready. If this time expires +** w/o any I/O becoming ready, the result will +** be zero. +** +** OUTPUTS: None +** RETURN: +** PRInt32 Number of PRPollDesc's with events or zero +** if the function timed out or -1 on failure. +** The reason for the failure is obtained by +** calling PR_GetError(). +************************************************************************** +*/ +NSPR_API(PRInt32) PR_Poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout); + +/* +************************************************************************** +** +** Pollable events +** +** A pollable event is a special kind of file descriptor. +** The only I/O operation you can perform on a pollable event +** is to poll it with the PR_POLL_READ flag. You can't +** read from or write to a pollable event. +** +** The purpose of a pollable event is to combine event waiting +** with I/O waiting in a single PR_Poll call. Pollable events +** are implemented using a pipe or a pair of TCP sockets +** connected via the loopback address, therefore setting and +** waiting for pollable events are expensive operating system +** calls. Do not use pollable events for general thread +** synchronization. Use condition variables instead. +** +** A pollable event has two states: set and unset. Events +** are not queued, so there is no notion of an event count. +** A pollable event is either set or unset. +** +** A new pollable event is created by a PR_NewPollableEvent +** call and is initially in the unset state. +** +** PR_WaitForPollableEvent blocks the calling thread until +** the pollable event is set, and then it atomically unsets +** the pollable event before it returns. +** +** To set a pollable event, call PR_SetPollableEvent. +** +** One can call PR_Poll with the PR_POLL_READ flag on a pollable +** event. When the pollable event is set, PR_Poll returns with +** the PR_POLL_READ flag set in the out_flags. +** +** To close a pollable event, call PR_DestroyPollableEvent +** (not PR_Close). +** +************************************************************************** +*/ + +NSPR_API(PRFileDesc *) PR_NewPollableEvent(void); + +NSPR_API(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_SetPollableEvent(PRFileDesc *event); + +NSPR_API(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event); + +PR_END_EXTERN_C + +#endif /* prio_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/pripcsem.h b/src/libs/xpcom18a4/nsprpub/pr/include/pripcsem.h new file mode 100644 index 00000000..c7450f3a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/pripcsem.h @@ -0,0 +1,141 @@ +/* -*- 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 ***** */ + +/* + * File: pripcsem.h + * + * Description: named semaphores for interprocess + * synchronization + * + * Unrelated processes obtain access to a shared semaphore + * by specifying its name. + * + * Our goal is to support named semaphores on at least + * Unix and Win32 platforms. The implementation will use + * one of the three native semaphore APIs: POSIX, System V, + * and Win32. + * + * Because POSIX named semaphores have kernel persistence, + * we are forced to have a delete function in this API. + */ + +#ifndef pripcsem_h___ +#define pripcsem_h___ + +#include "prtypes.h" +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_OpenSemaphore VBoxNsprPR_OpenSemaphore +#define PR_WaitSemaphore VBoxNsprPR_WaitSemaphore +#define PR_PostSemaphore VBoxNsprPR_PostSemaphore +#define PR_CloseSemaphore VBoxNsprPR_CloseSemaphore +#define PR_DeleteSemaphore VBoxNsprPR_DeleteSemaphore +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* + * PRSem is an opaque structure that represents a named + * semaphore. + */ +typedef struct PRSem PRSem; + +/* + * PR_OpenSemaphore -- + * + * Create or open a named semaphore with the specified name. + * A handle to the semaphore is returned. + * + * If the named semaphore doesn't exist and the PR_SEM_CREATE + * flag is specified, the named semaphore is created. The + * created semaphore needs to be removed from the system with + * a PR_DeleteSemaphore call. + * + * If PR_SEM_CREATE is specified, the third argument is the + * access permission bits of the new semaphore (same + * interpretation as the mode argument to PR_Open) and the + * fourth argument is the initial value of the new semaphore. + * If PR_SEM_CREATE is not specified, the third and fourth + * arguments are ignored. + */ + +#define PR_SEM_CREATE 0x1 /* create if not exist */ +#define PR_SEM_EXCL 0x2 /* fail if already exists */ + +NSPR_API(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value); + +/* + * PR_WaitSemaphore -- + * + * If the value of the semaphore is > 0, decrement the value and return. + * If the value is 0, sleep until the value becomes > 0, then decrement + * the value and return. + * + * The "test and decrement" operation is performed atomically. + */ + +NSPR_API(PRStatus) PR_WaitSemaphore(PRSem *sem); + +/* + * PR_PostSemaphore -- + * + * Increment the value of the named semaphore by 1. + */ + +NSPR_API(PRStatus) PR_PostSemaphore(PRSem *sem); + +/* + * PR_CloseSemaphore -- + * + * Close a named semaphore handle. + */ + +NSPR_API(PRStatus) PR_CloseSemaphore(PRSem *sem); + +/* + * PR_DeleteSemaphore -- + * + * Remove a named semaphore from the system. + */ + +NSPR_API(PRStatus) PR_DeleteSemaphore(const char *name); + +PR_END_EXTERN_C + +#endif /* pripcsem_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/include/private/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/include/private/Makefile.in new file mode 100644 index 00000000..180393b1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +RELEASE_HEADERS = pprio.h pprthred.h prpriv.h +RELEASE_HEADERS := $(addprefix $(srcdir)/, $(RELEASE_HEADERS)) +RELEASE_HEADERS_DEST = $(RELEASE_INCLUDE_DIR)/private + +HEADERS = $(RELEASE_HEADERS) $(srcdir)/pprmwait.h $(srcdir)/primpl.h + +include_subdir = private + +include $(topsrcdir)/config/rules.mk + +export:: $(RELEASE_HEADERS) + $(INSTALL) -m 444 $(RELEASE_HEADERS) $(dist_includedir)/private diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/pprio.h b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprio.h new file mode 100644 index 00000000..f1d11360 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprio.h @@ -0,0 +1,294 @@ +/* -*- 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 ***** */ + +/* +** File: pprio.h +** +** Description: Private definitions for I/O related structures +*/ + +#ifndef pprio_h___ +#define pprio_h___ + +#include "prtypes.h" +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_GetFileMethods VBoxNsprPR_GetFileMethods +#define PR_GetTCPMethods VBoxNsprPR_GetTCPMethods +#define PR_GetUDPMethods VBoxNsprPR_GetUDPMethods +#define PR_GetPipeMethods VBoxNsprPR_GetPipeMethods +#define PR_FileDesc2NativeHandle VBoxNsprPR_FileDesc2NativeHandle +#define PR_ChangeFileDescNativeHandle VBoxNsprPR_ChangeFileDescNativeHandle +#define PR_AllocFileDesc VBoxNsprPR_AllocFileDesc +#define PR_FreeFileDesc VBoxNsprPR_FreeFileDesc +#define PR_ImportFile VBoxNsprPR_ImportFile +#define PR_ImportPipe VBoxNsprPR_ImportPipe +#define PR_ImportTCPSocket VBoxNsprPR_ImportTCPSocket +#define PR_ImportUDPSocket VBoxNsprPR_ImportUDPSocket +#define PR_CreateSocketPollFd VBoxNsprPR_CreateSocketPollFd +#define PR_DestroySocketPollFd VBoxNsprPR_DestroySocketPollFd +#define PR_Socket VBoxNsprPR_Socket +#define PR_LockFile VBoxNsprPR_LockFile +#define PR_TLockFile VBoxNsprPR_TLockFile +#define PR_UnlockFile VBoxNsprPR_UnlockFile +#define PR_EmulateAcceptRead VBoxNsprPR_EmulateAcceptRead +#define PR_EmulateSendFile VBoxNsprPR_EmulateSendFile +#define PR_NTFast_AcceptRead VBoxNsprPR_NTFast_AcceptRead +#define PR_NTFast_AcceptRead_WithTimeoutCallback VBoxNsprPR_NTFast_AcceptRead_WithTimeoutCallback +#define PR_NTFast_Accept VBoxNsprPR_NTFast_Accept +#define PR_NTFast_UpdateAcceptContext VBoxNsprPR_NTFast_UpdateAcceptContext +#define PR_NT_CancelIo VBoxNsprPR_NT_CancelIo +#define PR_Init_Log VBoxNsprPR_Init_Log +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/************************************************************************/ + +/* Return the method tables for files, tcp sockets and udp sockets */ +NSPR_API(const PRIOMethods*) PR_GetFileMethods(void); +NSPR_API(const PRIOMethods*) PR_GetTCPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetUDPMethods(void); +NSPR_API(const PRIOMethods*) PR_GetPipeMethods(void); + +/* +** Convert a NSPR Socket Handle to a Native Socket handle. +** This function will be obsoleted with the next release; avoid using it. +*/ +NSPR_API(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *); +NSPR_API(void) PR_ChangeFileDescNativeHandle(PRFileDesc *, PRInt32); +NSPR_API(PRFileDesc*) PR_AllocFileDesc(PRInt32 osfd, + const PRIOMethods *methods); +NSPR_API(void) PR_FreeFileDesc(PRFileDesc *fd); +/* +** Import an existing OS file to NSPR. +*/ +NSPR_API(PRFileDesc*) PR_ImportFile(PRInt32 osfd); +NSPR_API(PRFileDesc*) PR_ImportPipe(PRInt32 osfd); +NSPR_API(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd); +NSPR_API(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd); + + +/* + ************************************************************************* + * FUNCTION: PR_CreateSocketPollFd + * DESCRIPTION: + * Create a PRFileDesc wrapper for a native socket handle, for use with + * PR_Poll only + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_CreateSocketPollFd returns a pointer + * to the PRFileDesc created for the native socket handle + * Returns a NULL pointer if the create of a new PRFileDesc failed + * + ************************************************************************** + */ + +NSPR_API(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd); + +/* + ************************************************************************* + * FUNCTION: PR_DestroySocketPollFd + * DESCRIPTION: + * Destroy the PRFileDesc wrapper created by PR_CreateSocketPollFd + * INPUTS: + * None + * OUTPUTS: + * None + * RETURN: PRFileDesc* + * Upon successful completion, PR_DestroySocketPollFd returns + * PR_SUCCESS, else PR_FAILURE + * + ************************************************************************** + */ + +NSPR_API(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd); + + +/* +** Macros for PR_Socket +** +** Socket types: PR_SOCK_STREAM, PR_SOCK_DGRAM +*/ + +#ifdef WIN32 + +#define PR_SOCK_STREAM 1 +#define PR_SOCK_DGRAM 2 + +#else /* WIN32 */ + +#define PR_SOCK_STREAM SOCK_STREAM +#define PR_SOCK_DGRAM SOCK_DGRAM + +#endif /* WIN32 */ + +/* +** Create a new Socket; this function is obsolete. +*/ +NSPR_API(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto); + +/* FUNCTION: PR_LockFile +** DESCRIPTION: +** Lock a file for exclusive access. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_LockFile(PRFileDesc *fd); + +/* FUNCTION: PR_TLockFile +** DESCRIPTION: +** Test and Lock a file for exclusive access. Do not block if the +** file cannot be locked immediately. +** RETURNS: +** PR_SUCCESS when the lock is held +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_TLockFile(PRFileDesc *fd); + +/* FUNCTION: PR_UnlockFile +** DESCRIPTION: +** Unlock a file which has been previously locked successfully by this +** process. +** RETURNS: +** PR_SUCCESS when the lock is released +** PR_FAILURE otherwise +*/ +NSPR_API(PRStatus) PR_UnlockFile(PRFileDesc *fd); + +/* +** Emulate acceptread by accept and recv. +*/ +NSPR_API(PRInt32) PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout); + +/* +** Emulate sendfile by reading from the file and writing to the socket. +** The file is memory-mapped if memory-mapped files are supported. +*/ +NSPR_API(PRInt32) PR_EmulateSendFile( + PRFileDesc *networkSocket, PRSendFileData *sendData, + PRTransmitFileFlags flags, PRIntervalTime timeout); + +#ifdef WIN32 +/* FUNCTION: PR_NTFast_AcceptRead +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_AcceptRead always +** updates the accept context. This version does not. +**/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime t); + +typedef void (*_PR_AcceptTimeoutCallback)(void *); + +/* FUNCTION: PR_NTFast_AcceptRead_WithTimeoutCallback +** DESCRIPTION: +** The AcceptEx call combines the accept with the read function. However, +** our daemon threads need to be able to wakeup and reliably flush their +** log buffers if the Accept times out. However, with the current blocking +** interface to AcceptRead, there is no way for us to timeout the Accept; +** this is because when we timeout the Read, we can close the newly +** socket and continue; but when we timeout the accept itself, there is no +** new socket to timeout. So instead, this version of the function is +** provided. After the initial timeout period elapses on the accept() +** portion of the function, it will call the callback routine and then +** continue the accept. If the timeout occurs on the read, it will +** close the connection and return error. +*/ +NSPR_API(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( + PRFileDesc *sd, + PRFileDesc **nd, + PRNetAddr **raddr, + void *buf, + PRInt32 amount, + PRIntervalTime t, + _PR_AcceptTimeoutCallback callback, + void *callback_arg); + +/* FUNCTION: PR_NTFast_Accept +** DESCRIPTION: +** NT has the notion of an "accept context", which is only needed in +** order to make certain calls. By default, a socket connected via +** AcceptEx can only do a limited number of things without updating +** the acceptcontext. The generic version of PR_Accept always +** updates the accept context. This version does not. +**/ +NSPR_API(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRIntervalTime timeout); + +/* FUNCTION: PR_NTFast_Update +** DESCRIPTION: +** For sockets accepted with PR_NTFast_Accept or PR_NTFastAcceptRead, +** this function will update the accept context for those sockets, +** so that the socket can make general purpose socket calls. +** Without calling this, the only operations supported on the socket +** Are PR_Read, PR_Write, PR_Transmitfile, and PR_Close. +*/ +NSPR_API(void) PR_NTFast_UpdateAcceptContext(PRFileDesc *acceptSock, + PRFileDesc *listenSock); + + +/* FUNCTION: PR_NT_CancelIo +** DESCRIPTION: +** Cancel IO operations on fd. +*/ +NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd); + + +#endif /* WIN32 */ + +/* +** Need external access to this on Mac so we can first set up our faux +** environment vars +*/ +#ifdef XP_MAC +NSPR_API(void) PR_Init_Log(void); +#endif + + +PR_END_EXTERN_C + +#endif /* pprio_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/pprmwait.h b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprmwait.h new file mode 100644 index 00000000..e677f137 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprmwait.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 ***** */ + +#if defined(_PPRMWAIT_H) +#else +#define _PPRMWAIT_H + +#include "prlock.h" +#include "prcvar.h" +#include "prclist.h" +#include "prthread.h" + +#define MAX_POLLING_INTERVAL 100 +#define _PR_POLL_COUNT_FUDGE 64 +#define MAX_POLLING_INTERVAL 100 +#define _PR_DEFAULT_HASH_LENGTH 59 + +/* + * Our hash table resolves collisions by open addressing with + * double hashing. See Cormen, Leiserson, and Rivest, + * Introduction to Algorithms, p. 232, The MIT Press, 1990. + */ + +#define _MW_HASH(a, m) ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m)) +#define _MW_HASH2(a, m) (1 + ((((PRUptrdiff)(a) >> 4) ^ ((PRUptrdiff)(a) >> 10)) % (m - 2))) +#define _MW_ABORTED(_rv) \ + ((PR_FAILURE == (_rv)) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) + +typedef enum {_prmw_success, _prmw_rehash, _prmw_error} _PR_HashStory; + +typedef struct _PRWaiterHash +{ + PRUint16 count; /* current number in hash table */ + PRUint16 length; /* current size of the hash table */ + PRRecvWait *recv_wait; /* hash table of receive wait objects */ +} _PRWaiterHash; + +typedef enum {_prmw_running, _prmw_stopping, _prmw_stopped} PRMWGroupState; + +struct PRWaitGroup +{ + PRCList group_link; /* all groups are linked to each other */ + PRCList io_ready; /* list of I/O requests that are ready */ + PRMWGroupState state; /* state of this group (so we can shut down) */ + + PRLock *ml; /* lock for synchronizing this wait group */ + PRCondVar *io_taken; /* calling threads notify when they take I/O */ + PRCondVar *io_complete; /* calling threads wait here for completions */ + PRCondVar *new_business; /* polling thread waits here more work */ + PRCondVar *mw_manage; /* used to manage group lists */ + PRThread* poller; /* thread that's actually doing the poll() */ + PRUint16 waiting_threads; /* number of threads waiting for recv */ + PRUint16 polling_count; /* number of elements in the polling list */ + PRUint32 p_timestamp; /* pseudo-time group had element removed */ + PRPollDesc *polling_list; /* list poller builds for polling */ + PRIntervalTime last_poll; /* last time we polled */ + _PRWaiterHash *waiter; /* pointer to hash table of wait receive objects */ + +#ifdef WINNT + /* + * On NT, idle threads are responsible for getting completed i/o. + * They need to add completed i/o to the io_ready list. Since + * idle threads cannot use nspr locks, we have to use an md lock + * to protect the io_ready list. + */ + _MDLock mdlock; /* protect io_ready, waiter, and wait_list */ + PRCList wait_list; /* used in place of io_complete. reuse + * waitQLinks in the PRThread structure. */ +#endif /* WINNT */ +}; + +/********************************************************************** +*********************************************************************** +******************** Wait group enumerations ************************** +*********************************************************************** +**********************************************************************/ +typedef struct _PRGlobalState +{ + PRCList group_list; /* master of the group list */ + PRWaitGroup *group; /* the default (NULL) group */ +} _PRGlobalState; + +#ifdef WINNT +extern PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd); +#endif + +typedef enum {_PR_ENUM_UNSEALED=0, _PR_ENUM_SEALED=0x0eadface} _PREnumSeal; + +struct PRMWaitEnumerator +{ + PRWaitGroup *group; /* group this enumerator is bound to */ + PRThread *thread; /* thread in midst of an enumeration */ + _PREnumSeal seal; /* trying to detect deleted objects */ + PRUint32 p_timestamp; /* when enumeration was (re)started */ + PRRecvWait **waiter; /* pointer into hash table */ + PRUintn index; /* position in hash table */ + void *pad[4]; /* some room to grow */ +}; + +#endif /* defined(_PPRMWAIT_H) */ + +/* pprmwait.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/pprthred.h b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprthred.h new file mode 100644 index 00000000..fe6b0529 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/pprthred.h @@ -0,0 +1,414 @@ +/* -*- 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 pprthred_h___ +#define pprthred_h___ + +/* +** API for PR private functions. These calls are to be used by internal +** developers only. +*/ +#include "nspr.h" + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#endif + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_AttachThread VBoxNsprPR_AttachThread +#define PR_DetachThread VBoxNsprPR_DetachThread +#define PR_GetThreadID VBoxNsprPR_GetThreadID +#define PR_SetThreadDumpProc VBoxNsprPR_SetThreadDumpProc +#define PR_GetThreadAffinityMask VBoxNsprPR_GetThreadAffinityMask +#define PR_SetThreadAffinityMask VBoxNsprPR_SetThreadAffinityMask +#define PR_SetCPUAffinityMask VBoxNsprPR_SetCPUAffinityMask +#define PR_ShowStatus VBoxNsprPR_ShowStatus +#define PR_SetThreadRecycleMode VBoxNsprPR_SetThreadRecycleMode +#define PR_CreateThreadGCAble VBoxNsprPR_CreateThreadGCAble +#define PR_AttachThreadGCAble VBoxNsprPR_AttachThreadGCAble +#define PR_SetThreadGCAble VBoxNsprPR_SetThreadGCAble +#define PR_ClearThreadGCAble VBoxNsprPR_ClearThreadGCAble +#define PR_SuspendAll VBoxNsprPR_SuspendAll +#define PR_ResumeAll VBoxNsprPR_ResumeAll +#define PR_GetSP VBoxNsprPR_GetSP +#define PR_GetGCRegisters VBoxNsprPR_GetGCRegisters +#define GetExecutionEnvironment VBoxNsprGetExecutionEnvironment +#define SetExecutionEnvironment VBoxNsprSetExecutionEnvironment +#define PR_EnumerateThreads VBoxNsprPR_EnumerateThreads +#define PR_ThreadScanStackPointers VBoxNsprPR_ThreadScanStackPointers +#define PR_ScanStackPointers VBoxNsprPR_ScanStackPointers +#define PR_GetStackSpaceLeft VBoxNsprPR_GetStackSpaceLeft +#define PR_NewNamedMonitor VBoxNsprPR_NewNamedMonitor +#define PR_TestAndLock VBoxNsprPR_TestAndLock +#define PR_TestAndEnterMonitor VBoxNsprPR_TestAndEnterMonitor +#define PR_GetMonitorEntryCount VBoxNsprPR_GetMonitorEntryCount +#define PR_CTestAndEnterMonitor VBoxNsprPR_CTestAndEnterMonitor +#define PR_Mac_WaitForAsyncNotify VBoxNsprPR_Mac_WaitForAsyncNotify +#define PR_Mac_PostAsyncNotify VBoxNsprPR_Mac_PostAsyncNotify +#define PR_OS2_SetFloatExcpHandler VBoxNsprPR_OS2_SetFloatExcpHandler +#define PR_OS2_UnsetFloatExcpHandler VBoxNsprPR_OS2_UnsetFloatExcpHandler +#define PR_XLock VBoxNsprPR_XLock +#define PR_XUnlock VBoxNsprPR_XUnlock +#define PR_XIsLocked VBoxNsprPR_XIsLocked +#define PR_XWait VBoxNsprPR_XWait +#define PR_XNotify VBoxNsprPR_XNotify +#define PR_XNotifyAll VBoxNsprPR_XNotifyAll +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Associate a thread object with an existing native thread. +** "type" is the type of thread object to attach +** "priority" is the priority to assign to the thread +** "stack" defines the shape of the threads stack +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. This call invokes "start(obj,arg)" and returns when the +** function returns. The thread object is automatically destroyed. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +NSPR_API(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Detach the nspr thread from the currently executing native thread. +** The thread object will be destroyed and all related data attached +** to it. The exit procs will be invoked. +** +** This call is not normally needed unless you create your own native +** thread. PR_Exit will automatially detach the nspr thread object +** created by PR_Init for the primordial thread. +** +** This call returns after the nspr thread object is destroyed. +*/ +NSPR_API(void) PR_DetachThread(void); + +/* +** Get the id of the named thread. Each thread is assigned a unique id +** when it is created or attached. +*/ +NSPR_API(PRUint32) PR_GetThreadID(PRThread *thread); + +/* +** Set the procedure that is called when a thread is dumped. The procedure +** will be applied to the argument, arg, when called. Setting the procedure +** to NULL effectively removes it. +*/ +typedef void (*PRThreadDumpProc)(PRFileDesc *fd, PRThread *t, void *arg); +NSPR_API(void) PR_SetThreadDumpProc( + PRThread* thread, PRThreadDumpProc dump, void *arg); + +/* +** Get this thread's affinity mask. The affinity mask is a 32 bit quantity +** marking a bit for each processor this process is allowed to run on. +** The processor mask is returned in the mask argument. +** The least-significant-bit represents processor 0. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask); + +/* +** Set this thread's affinity mask. +** +** Returns 0 on success, -1 on failure. +*/ +NSPR_API(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ); + +/* +** Set the default CPU Affinity mask. +** +*/ +NSPR_API(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask); + +/* +** Show status of all threads to standard error output. +*/ +NSPR_API(void) PR_ShowStatus(void); + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +NSPR_API(void) PR_SetThreadRecycleMode(PRUint32 flag); + + +/*--------------------------------------------------------------------------- +** THREAD PRIVATE FUNCTIONS FOR GARBAGE COLLECTIBLE THREADS +---------------------------------------------------------------------------*/ + +/* +** Only Garbage collectible threads participate in resume all, suspend all and +** enumeration operations. They are also different during creation when +** platform specific action may be needed (For example, all Solaris GC able +** threads are bound threads). +*/ + +/* +** Same as PR_CreateThread except that the thread is marked as garbage +** collectible. +*/ +NSPR_API(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Same as PR_AttachThread except that the thread being attached is marked as +** garbage collectible. +*/ +NSPR_API(PRThread*) PR_AttachThreadGCAble(PRThreadType type, + PRThreadPriority priority, + PRThreadStack *stack); + +/* +** Mark the thread as garbage collectible. +*/ +NSPR_API(void) PR_SetThreadGCAble(void); + +/* +** Unmark the thread as garbage collectible. +*/ +NSPR_API(void) PR_ClearThreadGCAble(void); + +/* +** This routine prevents all other GC able threads from running. This call is needed by +** the garbage collector. +*/ +NSPR_API(void) PR_SuspendAll(void); + +/* +** This routine unblocks all other GC able threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +NSPR_API(void) PR_ResumeAll(void); + +/* +** Return the thread stack pointer of the given thread. +** Needed by the garbage collector. +*/ +NSPR_API(void *) PR_GetSP(PRThread *thread); + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +** +** This function simply calls the internal function _MD_HomeGCRegisters(). +*/ +NSPR_API(PRWord *) PR_GetGCRegisters(PRThread *t, int isCurrent, int *np); + +/* +** (Get|Set)ExecutionEnvironent +** +** Used by Java to associate it's execution environment so garbage collector +** can find it. If return is NULL, then it's probably not a collectable thread. +** +** There's no locking required around these calls. +*/ +NSPR_API(void*) GetExecutionEnvironment(PRThread *thread); +NSPR_API(void) SetExecutionEnvironment(PRThread* thread, void *environment); + +/* +** Enumeration function that applies "func(thread,i,arg)" to each active +** thread in the process. The enumerator returns PR_SUCCESS if the enumeration +** should continue, any other value is considered failure, and enumeration +** stops, returning the failure value from PR_EnumerateThreads. +** Needed by the garbage collector. +*/ +typedef PRStatus (PR_CALLBACK *PREnumerator)(PRThread *t, int i, void *arg); +NSPR_API(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg); + +/* +** Signature of a thread stack scanning function. It is applied to every +** contiguous group of potential pointers within a thread. Count denotes the +** number of pointers. +*/ +typedef PRStatus +(PR_CALLBACK *PRScanStackFun)(PRThread* t, + void** baseAddr, PRUword count, void* closure); + +/* +** Applies scanFun to all contiguous groups of potential pointers +** within a thread. This includes the stack, registers, and thread-local +** data. If scanFun returns a status value other than PR_SUCCESS the scan +** is aborted, and the status value is returned. +*/ +NSPR_API(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure); + +/* +** Calls PR_ThreadScanStackPointers for every thread. +*/ +NSPR_API(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure); + +/* +** Returns a conservative estimate on the amount of stack space left +** on a thread in bytes, sufficient for making decisions about whether +** to continue recursing or not. +*/ +NSPR_API(PRUword) +PR_GetStackSpaceLeft(PRThread* t); + +/*--------------------------------------------------------------------------- +** THREAD CPU PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Get a pointer to the primordial CPU. +*/ +NSPR_API(struct _PRCPU *) _PR_GetPrimordialCPU(void); + +/*--------------------------------------------------------------------------- +** THREAD SYNCHRONIZATION PRIVATE FUNCTIONS +---------------------------------------------------------------------------*/ + +/* +** Create a new named monitor (named for debugging purposes). +** Monitors are re-entrant locks with a built-in condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewNamedMonitor(const char* name); + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +NSPR_API(PRBool) PR_TestAndLock(PRLock *lock); + +/* +** Test and then enter the mutex associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the mutex at the time of the call. +*/ +NSPR_API(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon); + +/* +** Return the number of times that the current thread has entered the +** mutex. Returns zero if the current thread has not entered the mutex. +*/ +NSPR_API(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon); + +/* +** Just like PR_CEnterMonitor except that if the monitor is owned by +** another thread NULL is returned. +*/ +NSPR_API(PRMonitor*) PR_CTestAndEnterMonitor(void *address); + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC THREAD SYNCHRONIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(XP_MAC) + +NSPR_API(void) PR_Mac_WaitForAsyncNotify(PRIntervalTime timeout); +NSPR_API(void) PR_Mac_PostAsyncNotify(PRThread *thread); + +#endif /* XP_MAC */ + +/*--------------------------------------------------------------------------- +** PLATFORM-SPECIFIC INITIALIZATION FUNCTIONS +---------------------------------------------------------------------------*/ +#if defined(IRIX) +/* +** Irix specific initialization funtion to be called before PR_Init +** is called by the application. Sets the CONF_INITUSERS and CONF_INITSIZE +** attributes of the shared arena set up by nspr. +** +** The environment variables _NSPR_IRIX_INITUSERS and _NSPR_IRIX_INITSIZE +** can also be used to set these arena attributes. If _NSPR_IRIX_INITUSERS +** is set, but not _NSPR_IRIX_INITSIZE, the value of the CONF_INITSIZE +** attribute of the nspr arena is scaled as a function of the +** _NSPR_IRIX_INITUSERS value. +** +** If the _PR_Irix_Set_Arena_Params() is called in addition to setting the +** environment variables, the values of the environment variables are used. +** +*/ +NSPR_API(void) _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize); + +#endif /* IRIX */ + +#if defined(XP_OS2) +/* +** These functions need to be called at the start and end of a thread. +** An EXCEPTIONREGISTRATIONRECORD must be declared on the stack and its +** address passed to the two functions. +*/ +NSPR_API(void) PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +NSPR_API(void) PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* e); +#endif /* XP_OS2 */ + +/* I think PR_GetMonitorEntryCount is useless. All you really want is this... */ +#define PR_InMonitor(m) (PR_GetMonitorEntryCount(m) > 0) + +/*--------------------------------------------------------------------------- +** Special X-Lock hack for client +---------------------------------------------------------------------------*/ + +#ifdef XP_UNIX +extern void PR_XLock(void); +extern void PR_XUnlock(void); +extern PRBool PR_XIsLocked(void); +#endif /* XP_UNIX */ + +PR_END_EXTERN_C + +#endif /* pprthred_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/primpl.h b/src/libs/xpcom18a4/nsprpub/pr/include/private/primpl.h new file mode 100644 index 00000000..cd8e46c4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/primpl.h @@ -0,0 +1,2141 @@ +/* -*- 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 primpl_h___ +#define primpl_h___ + +/* + * HP-UX 10.10's pthread.h (DCE threads) includes dce/cma.h, which + * has: + * #define sigaction _sigaction_sys + * This macro causes chaos if signal.h gets included before pthread.h. + * To be safe, we include pthread.h first. + */ + +#if defined(_PR_PTHREADS) +#include +#endif + +#if defined(_PR_BTHREADS) +#include +#endif + +#ifdef WINNT +/* Need to force service-pack 3 extensions to be defined by +** setting _WIN32_WINNT to NT 4.0 for winsock.h, winbase.h, winnt.h. +*/ +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#elif (_WIN32_WINNT < 0x0400) + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0400 +#endif /* _WIN32_WINNT */ +#endif /* WINNT */ + +#include "nspr.h" +#include "prpriv.h" + +typedef struct PRSegment PRSegment; + +#ifdef XP_MAC +#include "prosdep.h" +#include "probslet.h" +#else +#include "md/prosdep.h" +#include "obsolete/probslet.h" +#endif /* XP_MAC */ + +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#include +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) +#include +#endif + +/************************************************************************* +***** A Word about Model Dependent Function Naming Convention *********** +*************************************************************************/ + +/* +NSPR 2.0 must implement its function across a range of platforms +including: MAC, Windows/16, Windows/95, Windows/NT, and several +variants of Unix. Each implementation shares common code as well +as having platform dependent portions. This standard describes how +the model dependent portions are to be implemented. + +In header file pr/include/primpl.h, each publicly declared +platform dependent function is declared as: + +NSPR_API void _PR_MD_FUNCTION( long arg1, long arg2 ); +#define _PR_MD_FUNCTION _MD_FUNCTION + +In header file pr/include/md//_.h, +each #define'd macro is redefined as one of: + +#define _MD_FUNCTION +#define _MD_FUNCTION +#define _MD_FUNCTION +#define _MD_FUNCTION <_MD_Function> + +Where: + + is no definition at all. In this case, the function is not implemented +and is never called for this platform. +For example: +#define _MD_INIT_CPUS() + + is a C language macro expansion. +For example: +#define _MD_CLEAN_THREAD(_thread) \ + PR_BEGIN_MACRO \ + PR_DestroyCondVar(_thread->md.asyncIOCVar); \ + PR_DestroyLock(_thread->md.asyncIOLock); \ + PR_END_MACRO + + is some function implemented by the host operating system. +For example: +#define _MD_EXIT exit + +<_MD_function> is the name of a function implemented for this platform in +pr/src/md//.c file. +For example: +#define _MD_GETFILEINFO _MD_GetFileInfo + +In .c, the implementation is: +PR_IMPLEMENT(PRInt32) _MD_GetFileInfo(const char *fn, PRFileInfo *info); +*/ + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PT_FPrintStats VBoxNsprPT_FPrintStats +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct _MDLock _MDLock; +typedef struct _MDCVar _MDCVar; +typedef struct _MDSegment _MDSegment; +typedef struct _MDThread _MDThread; +typedef struct _MDThreadStack _MDThreadStack; +typedef struct _MDSemaphore _MDSemaphore; +typedef struct _MDDir _MDDir; +#ifdef MOZ_UNICODE +typedef struct _MDDirUTF16 _MDDirUTF16; +#endif /* MOZ_UNICODE */ +typedef struct _MDFileDesc _MDFileDesc; +typedef struct _MDProcess _MDProcess; +typedef struct _MDFileMap _MDFileMap; + +#if defined(_PR_PTHREADS) + +/* +** The following definitions are unique to implementing NSPR using pthreads. +** Since pthreads defines most of the thread and thread synchronization +** stuff, this is a pretty small set. +*/ + +#define PT_CV_NOTIFIED_LENGTH 6 +typedef struct _PT_Notified _PT_Notified; +struct _PT_Notified +{ + PRIntn length; /* # of used entries in this structure */ + struct + { + PRCondVar *cv; /* the condition variable notified */ + PRIntn times; /* and the number of times notified */ + } cv[PT_CV_NOTIFIED_LENGTH]; + _PT_Notified *link; /* link to another of these | NULL */ +}; + +/* + * bits defined for pthreads 'state' field + */ +#define PT_THREAD_DETACHED 0x01 /* thread can't be joined */ +#define PT_THREAD_GLOBAL 0x02 /* a global thread (unlikely) */ +#define PT_THREAD_SYSTEM 0x04 /* system (not user) thread */ +#define PT_THREAD_PRIMORD 0x08 /* this is the primordial thread */ +#define PT_THREAD_ABORTED 0x10 /* thread has been interrupted */ +#define PT_THREAD_GCABLE 0x20 /* thread is garbage collectible */ +#define PT_THREAD_SUSPENDED 0x40 /* thread has been suspended */ +#define PT_THREAD_FOREIGN 0x80 /* thread is not one of ours */ +#define PT_THREAD_BOUND 0x100 /* a bound-global thread */ + +#define _PT_THREAD_INTERRUPTED(thr) \ + (!(thr->interrupt_blocked) && (thr->state & PT_THREAD_ABORTED)) +#define _PT_THREAD_BLOCK_INTERRUPT(thr) \ + (thr->interrupt_blocked = 1) +#define _PT_THREAD_UNBLOCK_INTERRUPT(thr) \ + (thr->interrupt_blocked = 0) + +#ifdef GC_LEAK_DETECTOR +/* All threads are GCable. */ +#define _PT_IS_GCABLE_THREAD(thr) 1 +#else +#define _PT_IS_GCABLE_THREAD(thr) ((thr)->state & PT_THREAD_GCABLE) +#endif /* GC_LEAK_DETECTOR */ + +/* +** Possible values for thread's suspend field +** Note that the first two can be the same as they are really mutually exclusive, +** i.e. both cannot be happening at the same time. We have two symbolic names +** just as a mnemonic. +**/ +#define PT_THREAD_RESUMED 0x80 /* thread has been resumed */ +#define PT_THREAD_SETGCABLE 0x100 /* set the GCAble flag */ + +#if defined(DEBUG) + +typedef struct PTDebug +{ + PRTime timeStarted; + PRUintn locks_created, locks_destroyed; + PRUintn locks_acquired, locks_released; + PRUintn cvars_created, cvars_destroyed; + PRUintn cvars_notified, delayed_cv_deletes; +} PTDebug; + +#endif /* defined(DEBUG) */ + +NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + +#else /* defined(_PR_PTHREADS) */ + +NSPR_API(void) PT_FPrintStats(PRFileDesc *fd, const char *msg); + +/* +** This section is contains those parts needed to implement NSPR on +** platforms in general. One would assume that the pthreads implementation +** included lots of the same types, at least conceptually. +*/ + +/* + * Local threads only. No multiple CPU support and hence all the + * following routines are no-op. + */ +#ifdef _PR_LOCAL_THREADS_ONLY + +#define _PR_MD_SUSPEND_THREAD(thread) +#define _PR_MD_RESUME_THREAD(thread) +#define _PR_MD_SUSPEND_CPU(cpu) +#define _PR_MD_RESUME_CPU(cpu) +#define _PR_MD_BEGIN_SUSPEND_ALL() +#define _PR_MD_END_SUSPEND_ALL() +#define _PR_MD_BEGIN_RESUME_ALL() +#define _PR_MD_END_RESUME_ALL() +#define _PR_MD_INIT_ATTACHED_THREAD(thread) PR_FAILURE + +#endif + +typedef struct _PRCPUQueue _PRCPUQueue; +typedef struct _PRCPU _PRCPU; +typedef struct _MDCPU _MDCPU; + +struct _PRCPUQueue { + _MDLock runQLock; /* lock for the run + wait queues */ + _MDLock sleepQLock; /* lock for the run + wait queues */ + _MDLock miscQLock; /* lock for the run + wait queues */ + + PRCList runQ[PR_PRIORITY_LAST + 1]; /* run queue for this CPU */ + PRUint32 runQReadyMask; + PRCList sleepQ; + PRIntervalTime sleepQmax; + PRCList pauseQ; + PRCList suspendQ; + PRCList waitingToJoinQ; + + PRUintn numCPUs; /* number of CPUs using this Q */ +}; + +struct _PRCPU { + PRCList links; /* link list of CPUs */ + PRUint32 id; /* id for this CPU */ + + union { + PRInt32 bits; + PRUint8 missed[4]; + } u; + PRIntn where; /* index into u.missed */ + PRPackedBool paused; /* cpu is paused */ + PRPackedBool exit; /* cpu should exit */ + + PRThread *thread; /* native thread for this CPUThread */ + PRThread *idle_thread; /* user-level idle thread for this CPUThread */ + + PRIntervalTime last_clock; /* the last time we went into + * _PR_ClockInterrupt() on this CPU + */ + + _PRCPUQueue *queue; + + _MDCPU md; +}; + +typedef struct _PRInterruptTable { + const char *name; + PRUintn missed_bit; + void (*handler)(void); +} _PRInterruptTable; + +#define _PR_CPU_PTR(_qp) \ + ((_PRCPU*) ((char*) (_qp) - offsetof(_PRCPU,links))) + +#if !defined(IRIX) && !defined(WIN32) && !defined(XP_OS2) \ + && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)) +#define _MD_GET_ATTACHED_THREAD() (_PR_MD_CURRENT_THREAD()) +#endif + +#ifdef _PR_LOCAL_THREADS_ONLY + +NSPR_API(struct _PRCPU *) _pr_currentCPU; +NSPR_API(PRThread *) _pr_currentThread; +NSPR_API(PRThread *) _pr_lastThread; +NSPR_API(PRInt32) _pr_intsOff; + +#define _MD_CURRENT_CPU() (_pr_currentCPU) +#define _MD_SET_CURRENT_CPU(_cpu) (_pr_currentCPU = (_cpu)) +#define _MD_CURRENT_THREAD() (_pr_currentThread) +#define _MD_SET_CURRENT_THREAD(_thread) (_pr_currentThread = (_thread)) +#define _MD_LAST_THREAD() (_pr_lastThread) +#define _MD_SET_LAST_THREAD(t) (_pr_lastThread = t) + +#ifndef XP_MAC +#define _MD_GET_INTSOFF() (_pr_intsOff) +#define _MD_SET_INTSOFF(_val) (_pr_intsOff = _val) +#endif + + +/* The unbalanced curly braces in these two macros are intentional */ +#define _PR_LOCK_HEAP() { PRIntn _is; if (_pr_currentCPU) _PR_INTSOFF(_is); +#define _PR_UNLOCK_HEAP() if (_pr_currentCPU) _PR_INTSON(_is); } + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +extern PRInt32 _native_threads_only; + +#if defined(_PR_GLOBAL_THREADS_ONLY) + +#define _MD_GET_INTSOFF() 0 +#define _MD_SET_INTSOFF(_val) +#define _PR_INTSOFF(_is) +#define _PR_FAST_INTSON(_is) +#define _PR_INTSON(_is) +#define _PR_THREAD_LOCK(_thread) +#define _PR_THREAD_UNLOCK(_thread) +#define _PR_RUNQ_LOCK(cpu) +#define _PR_RUNQ_UNLOCK(cpu) +#define _PR_SLEEPQ_LOCK(thread) +#define _PR_SLEEPQ_UNLOCK(thread) +#define _PR_MISCQ_LOCK(thread) +#define _PR_MISCQ_UNLOCK(thread) +#define _PR_CPU_LIST_LOCK() +#define _PR_CPU_LIST_UNLOCK() + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) +#define _PR_DEL_RUNQ(_thread) +#define _PR_ADD_SLEEPQ(_thread, _timeout) +#define _PR_DEL_SLEEPQ(_thread, _propogate) +#define _PR_ADD_JOINQ(_thread, _cpu) +#define _PR_DEL_JOINQ(_thread) +#define _PR_ADD_SUSPENDQ(_thread, _cpu) +#define _PR_DEL_SUSPENDQ(_thread) + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) + +#define _PR_IS_NATIVE_THREAD(thread) 1 +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1 + +#else + +#ifdef XP_MAC + +#define _PR_INTSOFF(_is) _MD_INTSOFF(_is) + +#else /* XP_MAC */ + +#define _PR_INTSOFF(_is) \ + PR_BEGIN_MACRO \ + (_is) = _PR_MD_GET_INTSOFF(); \ + _PR_MD_SET_INTSOFF(1); \ + PR_END_MACRO + +#endif /* XP_MAC */ + +#define _PR_FAST_INTSON(_is) \ + PR_BEGIN_MACRO \ + _PR_MD_SET_INTSOFF(_is); \ + PR_END_MACRO + +#define _PR_INTSON(_is) \ + PR_BEGIN_MACRO \ + if ((_is == 0) && (_PR_MD_CURRENT_CPU())->u.bits) \ + _PR_IntsOn((_PR_MD_CURRENT_CPU())); \ + _PR_MD_SET_INTSOFF(_is); \ + PR_END_MACRO + +#ifdef _PR_LOCAL_THREADS_ONLY + +#define _PR_IS_NATIVE_THREAD(thread) 0 +#define _PR_THREAD_LOCK(_thread) +#define _PR_THREAD_UNLOCK(_thread) +#define _PR_RUNQ_LOCK(cpu) +#define _PR_RUNQ_UNLOCK(cpu) +#define _PR_SLEEPQ_LOCK(thread) +#define _PR_SLEEPQ_UNLOCK(thread) +#define _PR_MISCQ_LOCK(thread) +#define _PR_MISCQ_UNLOCK(thread) +#define _PR_CPU_LIST_LOCK() +#define _PR_CPU_LIST_UNLOCK() + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \ + PR_BEGIN_MACRO \ + PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \ + _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \ + PR_END_MACRO + +#define _PR_DEL_RUNQ(_thread) \ + PR_BEGIN_MACRO \ + _PRCPU *_cpu = _thread->cpu; \ + PRInt32 _pri = _thread->priority; \ + PR_REMOVE_LINK(&(_thread)->links); \ + if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \ + _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \ + PR_END_MACRO + +#define _PR_ADD_SLEEPQ(_thread, _timeout) \ + _PR_AddSleepQ(_thread, _timeout); + +#define _PR_DEL_SLEEPQ(_thread, _propogate) \ + _PR_DelSleepQ(_thread, _propogate); + +#define _PR_ADD_JOINQ(_thread, _cpu) \ + PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu)); + +#define _PR_DEL_JOINQ(_thread) \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_ADD_SUSPENDQ(_thread, _cpu) \ + PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu)); + +#define _PR_DEL_SUSPENDQ(_thread) \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) + +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 0 + +#else /* _PR_LOCAL_THREADS_ONLY */ + +/* These are for the "combined" thread model */ + +#define _PR_THREAD_LOCK(_thread) \ + _PR_MD_LOCK(&(_thread)->threadLock); + +#define _PR_THREAD_UNLOCK(_thread) \ + _PR_MD_UNLOCK(&(_thread)->threadLock); + +#define _PR_RUNQ_LOCK(_cpu) \ + PR_BEGIN_MACRO \ + _PR_MD_LOCK(&(_cpu)->queue->runQLock );\ + PR_END_MACRO + +#define _PR_RUNQ_UNLOCK(_cpu) \ + PR_BEGIN_MACRO \ + _PR_MD_UNLOCK(&(_cpu)->queue->runQLock );\ + PR_END_MACRO + +#define _PR_SLEEPQ_LOCK(_cpu) \ + _PR_MD_LOCK(&(_cpu)->queue->sleepQLock ); + +#define _PR_SLEEPQ_UNLOCK(_cpu) \ + _PR_MD_UNLOCK(&(_cpu)->queue->sleepQLock ); + +#define _PR_MISCQ_LOCK(_cpu) \ + _PR_MD_LOCK(&(_cpu)->queue->miscQLock ); + +#define _PR_MISCQ_UNLOCK(_cpu) \ + _PR_MD_UNLOCK(&(_cpu)->queue->miscQLock ); + +#define _PR_CPU_LIST_LOCK() _PR_MD_LOCK(&_pr_cpuLock) +#define _PR_CPU_LIST_UNLOCK() _PR_MD_UNLOCK(&_pr_cpuLock) + +#define QUEUE_RUN 0x1 +#define QUEUE_SLEEP 0x2 +#define QUEUE_JOIN 0x4 +#define QUEUE_SUSPEND 0x8 +#define QUEUE_LOCK 0x10 + +#define _PR_ADD_RUNQ(_thread, _cpu, _pri) \ + PR_BEGIN_MACRO \ + PR_APPEND_LINK(&(_thread)->links, &_PR_RUNQ(_cpu)[_pri]); \ + _PR_RUNQREADYMASK(_cpu) |= (1L << _pri); \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_RUN; \ + PR_END_MACRO + +#define _PR_DEL_RUNQ(_thread) \ + PR_BEGIN_MACRO \ + _PRCPU *_cpu = _thread->cpu; \ + PRInt32 _pri = _thread->priority; \ + PR_REMOVE_LINK(&(_thread)->links); \ + if (PR_CLIST_IS_EMPTY(&_PR_RUNQ(_cpu)[_pri])) \ + _PR_RUNQREADYMASK(_cpu) &= ~(1L << _pri); \ + PR_ASSERT((_thread)->queueCount == QUEUE_RUN);\ + (_thread)->queueCount = 0; \ + PR_END_MACRO + +#define _PR_ADD_SLEEPQ(_thread, _timeout) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_SLEEP; \ + _PR_AddSleepQ(_thread, _timeout); + +#define _PR_DEL_SLEEPQ(_thread, _propogate) \ + PR_ASSERT((_thread)->queueCount == QUEUE_SLEEP);\ + (_thread)->queueCount = 0; \ + _PR_DelSleepQ(_thread, _propogate); + +#define _PR_ADD_JOINQ(_thread, _cpu) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_JOIN; \ + PR_APPEND_LINK(&(_thread)->links, &_PR_WAITINGTOJOINQ(_cpu)); + +#define _PR_DEL_JOINQ(_thread) \ + PR_ASSERT((_thread)->queueCount == QUEUE_JOIN);\ + (_thread)->queueCount = 0; \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_ADD_SUSPENDQ(_thread, _cpu) \ + PR_ASSERT((_thread)->queueCount == 0); \ + (_thread)->queueCount = QUEUE_SUSPEND; \ + PR_APPEND_LINK(&(_thread)->links, &_PR_SUSPENDQ(_cpu)); + +#define _PR_DEL_SUSPENDQ(_thread) \ + PR_ASSERT((_thread)->queueCount == QUEUE_SUSPEND);\ + (_thread)->queueCount = 0; \ + PR_REMOVE_LINK(&(_thread)->links); + +#define _PR_THREAD_SWITCH_CPU(_thread, _newCPU) \ + (_thread)->cpu = (_newCPU); + +#define _PR_IS_NATIVE_THREAD(thread) (thread->flags & _PR_GLOBAL_SCOPE) +#define _PR_IS_NATIVE_THREAD_SUPPORTED() 1 + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +#define _PR_SET_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 1 +#define _PR_CLEAR_RESCHED_FLAG() _PR_MD_CURRENT_CPU()->u.missed[3] = 0 + +extern _PRInterruptTable _pr_interruptTable[]; + +/* Bits for _pr_interruptState.u.missed[0,1] */ +#define _PR_MISSED_CLOCK 0x1 +#define _PR_MISSED_IO 0x2 +#define _PR_MISSED_CHILD 0x4 + +extern void _PR_IntsOn(_PRCPU *cpu); + +NSPR_API(void) _PR_WakeupCPU(void); +NSPR_API(void) _PR_PauseCPU(void); + +/************************************************************************/ + +#define _PR_LOCK_LOCK(_lock) \ + _PR_MD_LOCK(&(_lock)->ilock); +#define _PR_LOCK_UNLOCK(_lock) \ + _PR_MD_UNLOCK(&(_lock)->ilock); + +extern void _PR_UnblockLockWaiter(PRLock *lock); + +#define _PR_LOCK_PTR(_qp) \ + ((PRLock*) ((char*) (_qp) - offsetof(PRLock,links))) + +/************************************************************************/ + +#define _PR_CVAR_LOCK(_cvar) \ + _PR_MD_LOCK(&(_cvar)->ilock); +#define _PR_CVAR_UNLOCK(_cvar) \ + _PR_MD_UNLOCK(&(_cvar)->ilock); + +extern PRStatus _PR_WaitCondVar( + PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); +extern PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen); + +NSPR_API(void) _PR_Notify(PRMonitor *mon, PRBool all, PRBool sticky); + +/* PRThread.flags */ +#define _PR_SYSTEM 0x01 +#define _PR_INTERRUPT 0x02 +#define _PR_ATTACHED 0x04 /* created via PR_AttachThread */ +#define _PR_PRIMORDIAL 0x08 /* the thread that called PR_Init */ +#define _PR_ON_SLEEPQ 0x10 /* thread is on the sleepQ */ +#define _PR_ON_PAUSEQ 0x20 /* thread is on the pauseQ */ +#define _PR_SUSPENDING 0x40 /* thread wants to suspend */ +#define _PR_GLOBAL_SCOPE 0x80 /* thread is global scope */ +#define _PR_IDLE_THREAD 0x200 /* this is an idle thread */ +#define _PR_GCABLE_THREAD 0x400 /* this is a collectable thread */ +#define _PR_BOUND_THREAD 0x800 /* a bound thread */ +#define _PR_INTERRUPT_BLOCKED 0x1000 /* interrupts blocked */ + +/* PRThread.state */ +#define _PR_UNBORN 0 +#define _PR_RUNNABLE 1 +#define _PR_RUNNING 2 +#define _PR_LOCK_WAIT 3 +#define _PR_COND_WAIT 4 +#define _PR_JOIN_WAIT 5 +#define _PR_IO_WAIT 6 +#define _PR_SUSPENDED 7 +#define _PR_DEAD_STATE 8 /* for debugging */ + +/* PRThreadStack.flags */ +#define _PR_STACK_VM 0x1 /* using vm instead of malloc */ +#define _PR_STACK_MAPPED 0x2 /* vm is mapped */ +#define _PR_STACK_PRIMORDIAL 0x4 /* stack for primordial thread */ + +/* +** If the default stcksize from the client is zero, we need to pick a machine +** dependent value. This is only for standard user threads. For custom threads, +** 0 has a special meaning. +** Adjust stackSize. Round up to a page boundary. +*/ + +#ifndef _MD_MINIMUM_STACK_SIZE +#define _MD_MINIMUM_STACK_SIZE 0 +#endif + +#if (!defined(HAVE_CUSTOM_USER_THREADS)) +#define _PR_ADJUST_STACKSIZE(stackSize) \ + PR_BEGIN_MACRO \ + if (stackSize == 0) \ + stackSize = _MD_DEFAULT_STACK_SIZE; \ + if (stackSize < _MD_MINIMUM_STACK_SIZE) \ + stackSize = _MD_MINIMUM_STACK_SIZE; \ + stackSize = (stackSize + (1 << _pr_pageShift) - 1) >> _pr_pageShift; \ + stackSize <<= _pr_pageShift; \ + PR_END_MACRO +#else +#define _PR_ADJUST_STACKSIZE(stackSize) +#endif + +#ifdef GC_LEAK_DETECTOR +/* All threads are GCable. */ +#define _PR_IS_GCABLE_THREAD(thr) 1 +#else +#define _PR_IS_GCABLE_THREAD(thr) ((thr)->flags & _PR_GCABLE_THREAD) +#endif /* GC_LEAK_DETECTOR */ + +#define _PR_PENDING_INTERRUPT(thr) \ + (!((thr)->flags & _PR_INTERRUPT_BLOCKED) && ((thr)->flags & _PR_INTERRUPT)) +#define _PR_THREAD_BLOCK_INTERRUPT(thr) \ + (thr->flags |= _PR_INTERRUPT_BLOCKED) +#define _PR_THREAD_UNBLOCK_INTERRUPT(thr) \ + (thr->flags &= ~_PR_INTERRUPT_BLOCKED) + +#define _PR_THREAD_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,links))) + +#define _PR_ACTIVE_THREAD_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,active))) + +#define _PR_THREAD_CONDQ_PTR(_qp) \ + ((PRThread*) ((char*) (_qp) - offsetof(PRThread,waitQLinks))) + +#define _PR_THREAD_MD_TO_PTR(_md) \ + ((PRThread*) ((char*) (_md) - offsetof(PRThread,md))) + +#define _PR_THREAD_STACK_TO_PTR(_stack) \ + ((PRThread*) (_stack->thr)) + +extern PRCList _pr_active_local_threadQ; +extern PRCList _pr_active_global_threadQ; +extern PRCList _pr_cpuQ; +extern _MDLock _pr_cpuLock; +extern PRInt32 _pr_md_idle_cpus; + +#define _PR_ACTIVE_LOCAL_THREADQ() _pr_active_local_threadQ +#define _PR_ACTIVE_GLOBAL_THREADQ() _pr_active_global_threadQ +#define _PR_CPUQ() _pr_cpuQ +#define _PR_RUNQ(_cpu) ((_cpu)->queue->runQ) +#define _PR_RUNQREADYMASK(_cpu) ((_cpu)->queue->runQReadyMask) +#define _PR_SLEEPQ(_cpu) ((_cpu)->queue->sleepQ) +#define _PR_SLEEPQMAX(_cpu) ((_cpu)->queue->sleepQmax) +#define _PR_PAUSEQ(_cpu) ((_cpu)->queue->pauseQ) +#define _PR_SUSPENDQ(_cpu) ((_cpu)->queue->suspendQ) +#define _PR_WAITINGTOJOINQ(_cpu) ((_cpu)->queue->waitingToJoinQ) + +extern PRUint32 _pr_recycleThreads; /* Flag for behavior on thread cleanup */ +extern PRLock *_pr_deadQLock; +extern PRUint32 _pr_numNativeDead; +extern PRUint32 _pr_numUserDead; +extern PRCList _pr_deadNativeQ; +extern PRCList _pr_deadUserQ; +#define _PR_DEADNATIVEQ _pr_deadNativeQ +#define _PR_DEADUSERQ _pr_deadUserQ +#define _PR_DEADQ_LOCK PR_Lock(_pr_deadQLock); +#define _PR_DEADQ_UNLOCK PR_Unlock(_pr_deadQLock); +#define _PR_INC_DEADNATIVE (_pr_numNativeDead++) +#define _PR_DEC_DEADNATIVE (_pr_numNativeDead--) +#define _PR_NUM_DEADNATIVE (_pr_numNativeDead) +#define _PR_INC_DEADUSER (_pr_numUserDead++) +#define _PR_DEC_DEADUSER (_pr_numUserDead--) +#define _PR_NUM_DEADUSER (_pr_numUserDead) + +extern PRUint32 _pr_utid; + +extern struct _PRCPU *_pr_primordialCPU; + +extern PRLock *_pr_activeLock; /* lock for userActive and systemActive */ +extern PRInt32 _pr_userActive; /* number of active user threads */ +extern PRInt32 _pr_systemActive; /* number of active system threads */ +extern PRInt32 _pr_primordialExitCount; /* number of user threads left + * before the primordial thread + * can exit. */ +extern PRCondVar *_pr_primordialExitCVar; /* the condition variable for + * notifying the primordial thread + * when all other user threads + * have terminated. */ + +extern PRUintn _pr_maxPTDs; + +extern PRLock *_pr_terminationCVLock; + +/************************************************************************* +* Internal routines either called by PR itself or from machine-dependent * +* code. * +*************************************************************************/ + +extern void _PR_ClockInterrupt(void); + +extern void _PR_Schedule(void); +extern void _PR_SetThreadPriority( + PRThread* thread, PRThreadPriority priority); + +/*********************************************************************** +** FUNCTION: _PR_NewSegment() +** DESCRIPTION: +** Allocate a memory segment. The "size" value is rounded up to the +** native system page size and a page aligned portion of memory is +** returned. This memory is not part of the malloc heap. If "vaddr" is +** not NULL then PR tries to allocate the segment at the desired virtual +** address. +** INPUTS: size: size of the desired memory segment +** vaddr: address at which the newly aquired segment is to be +** mapped into memory. +** OUTPUTS: a memory segment is allocated, a PRSegment is allocated +** RETURN: pointer to PRSegment +***********************************************************************/ +extern PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr); + +/*********************************************************************** +** FUNCTION: _PR_DestroySegment() +** DESCRIPTION: +** The memory segment and the PRSegment are freed +** INPUTS: seg: pointer to PRSegment to be freed +** OUTPUTS: the the PRSegment and its associated memory segment are freed +** RETURN: void +***********************************************************************/ +extern void _PR_DestroySegment(PRSegment *seg); + +extern PRThreadStack * _PR_NewStack(PRUint32 stackSize); +extern void _PR_FreeStack(PRThreadStack *stack); +extern PRBool _PR_NotifyThread (PRThread *thread, PRThread *me); +extern void _PR_NotifyLockedThread (PRThread *thread); + +NSPR_API(void) _PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout); +NSPR_API(void) _PR_DelSleepQ(PRThread *thread, PRBool propogate_time); + +extern void _PR_AddThreadToRunQ(PRThread *me, PRThread *thread); + +NSPR_API(PRThread*) _PR_CreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags); + +extern void _PR_NativeDestroyThread(PRThread *thread); +extern void _PR_UserDestroyThread(PRThread *thread); + +extern PRThread* _PRI_AttachThread( + PRThreadType type, PRThreadPriority priority, + PRThreadStack *stack, PRUint32 flags); + +extern void _PRI_DetachThread(void); + + +#define _PR_IO_PENDING(_thread) ((_thread)->io_pending) + +NSPR_API(void) _PR_MD_INIT_CPUS(); +#define _PR_MD_INIT_CPUS _MD_INIT_CPUS + +NSPR_API(void) _PR_MD_WAKEUP_CPUS(); +#define _PR_MD_WAKEUP_CPUS _MD_WAKEUP_CPUS + +/* Interrupts related */ + +NSPR_API(void) _PR_MD_START_INTERRUPTS(void); +#define _PR_MD_START_INTERRUPTS _MD_START_INTERRUPTS + +NSPR_API(void) _PR_MD_STOP_INTERRUPTS(void); +#define _PR_MD_STOP_INTERRUPTS _MD_STOP_INTERRUPTS + +NSPR_API(void) _PR_MD_ENABLE_CLOCK_INTERRUPTS(void); +#define _PR_MD_ENABLE_CLOCK_INTERRUPTS _MD_ENABLE_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void); +#define _PR_MD_DISABLE_CLOCK_INTERRUPTS _MD_DISABLE_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void); +#define _PR_MD_BLOCK_CLOCK_INTERRUPTS _MD_BLOCK_CLOCK_INTERRUPTS + +NSPR_API(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void); +#define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS _MD_UNBLOCK_CLOCK_INTERRUPTS + +/* The _PR_MD_WAIT_LOCK and _PR_MD_WAKEUP_WAITER functions put to sleep and + * awaken a thread which is waiting on a lock or cvar. + */ +extern PRStatus _PR_MD_WAIT(PRThread *, PRIntervalTime timeout); +#define _PR_MD_WAIT _MD_WAIT + +extern PRStatus _PR_MD_WAKEUP_WAITER(PRThread *); +#define _PR_MD_WAKEUP_WAITER _MD_WAKEUP_WAITER + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +NSPR_API(void) _PR_MD_CLOCK_INTERRUPT(void); +#define _PR_MD_CLOCK_INTERRUPT _MD_CLOCK_INTERRUPT +#endif + +/* Stack debugging */ +NSPR_API(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone); +#define _PR_MD_INIT_STACK _MD_INIT_STACK + +NSPR_API(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts); +#define _PR_MD_CLEAR_STACK _MD_CLEAR_STACK + +/* CPU related */ +NSPR_API(PRInt32) _PR_MD_GET_INTSOFF(void); +#define _PR_MD_GET_INTSOFF _MD_GET_INTSOFF + +NSPR_API(void) _PR_MD_SET_INTSOFF(PRInt32 _val); +#define _PR_MD_SET_INTSOFF _MD_SET_INTSOFF + +NSPR_API(_PRCPU*) _PR_MD_CURRENT_CPU(void); +#define _PR_MD_CURRENT_CPU _MD_CURRENT_CPU + +NSPR_API(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu); +#define _PR_MD_SET_CURRENT_CPU _MD_SET_CURRENT_CPU + +NSPR_API(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu); +#define _PR_MD_INIT_RUNNING_CPU _MD_INIT_RUNNING_CPU + +/* + * Returns the number of threads awoken or 0 if a timeout occurred; + */ +extern PRInt32 _PR_MD_PAUSE_CPU(PRIntervalTime timeout); +#define _PR_MD_PAUSE_CPU _MD_PAUSE_CPU + +extern void _PR_MD_CLEANUP_BEFORE_EXIT(void); +#define _PR_MD_CLEANUP_BEFORE_EXIT _MD_CLEANUP_BEFORE_EXIT + +extern void _PR_MD_EXIT(PRIntn status); +#define _PR_MD_EXIT _MD_EXIT + +/* Locks related */ + +NSPR_API(void) _PR_MD_INIT_LOCKS(void); +#define _PR_MD_INIT_LOCKS _MD_INIT_LOCKS + +NSPR_API(PRStatus) _PR_MD_NEW_LOCK(_MDLock *md); +#define _PR_MD_NEW_LOCK _MD_NEW_LOCK + +NSPR_API(void) _PR_MD_FREE_LOCK(_MDLock *md); +#define _PR_MD_FREE_LOCK _MD_FREE_LOCK + +NSPR_API(void) _PR_MD_LOCK(_MDLock *md); +#define _PR_MD_LOCK _MD_LOCK + +/* Return 0 on success, a nonzero value on failure. */ +NSPR_API(PRIntn) _PR_MD_TEST_AND_LOCK(_MDLock *md); +#define _PR_MD_TEST_AND_LOCK _MD_TEST_AND_LOCK + +NSPR_API(void) _PR_MD_UNLOCK(_MDLock *md); +#define _PR_MD_UNLOCK _MD_UNLOCK + +NSPR_API(void) _PR_MD_IOQ_LOCK(void); +#define _PR_MD_IOQ_LOCK _MD_IOQ_LOCK + +NSPR_API(void) _PR_MD_IOQ_UNLOCK(void); +#define _PR_MD_IOQ_UNLOCK _MD_IOQ_UNLOCK + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +/* Semaphore related -- only for native threads */ +#ifdef HAVE_CVAR_BUILT_ON_SEM +NSPR_API(void) _PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value); +#define _PR_MD_NEW_SEM _MD_NEW_SEM + +NSPR_API(void) _PR_MD_DESTROY_SEM(_MDSemaphore *md); +#define _PR_MD_DESTROY_SEM _MD_DESTROY_SEM + +NSPR_API(PRStatus) _PR_MD_TIMED_WAIT_SEM( + _MDSemaphore *md, PRIntervalTime timeout); +#define _PR_MD_TIMED_WAIT_SEM _MD_TIMED_WAIT_SEM + +NSPR_API(PRStatus) _PR_MD_WAIT_SEM(_MDSemaphore *md); +#define _PR_MD_WAIT_SEM _MD_WAIT_SEM + +NSPR_API(void) _PR_MD_POST_SEM(_MDSemaphore *md); +#define _PR_MD_POST_SEM _MD_POST_SEM +#endif /* HAVE_CVAR_BUILT_ON_SEM */ + +#endif + +/* Condition Variables related -- only for native threads */ + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ +NSPR_API(PRInt32) _PR_MD_NEW_CV(_MDCVar *md); +#define _PR_MD_NEW_CV _MD_NEW_CV + +NSPR_API(void) _PR_MD_FREE_CV(_MDCVar *md); +#define _PR_MD_FREE_CV _MD_FREE_CV + +NSPR_API(void) _PR_MD_WAIT_CV( + _MDCVar *mdCVar,_MDLock *mdLock,PRIntervalTime timeout); +#define _PR_MD_WAIT_CV _MD_WAIT_CV + +NSPR_API(void) _PR_MD_NOTIFY_CV(_MDCVar *md, _MDLock *lock); +#define _PR_MD_NOTIFY_CV _MD_NOTIFY_CV + +NSPR_API(void) _PR_MD_NOTIFYALL_CV(_MDCVar *md, _MDLock *lock); +#define _PR_MD_NOTIFYALL_CV _MD_NOTIFYALL_CV +#endif /* _PR_LOCAL_THREADS_ONLY */ + +/* Threads related */ +NSPR_API(PRThread*) _PR_MD_CURRENT_THREAD(void); +#define _PR_MD_CURRENT_THREAD _MD_CURRENT_THREAD + +NSPR_API(PRThread*) _PR_MD_GET_ATTACHED_THREAD(void); +#define _PR_MD_GET_ATTACHED_THREAD _MD_GET_ATTACHED_THREAD + +NSPR_API(PRThread*) _PR_MD_LAST_THREAD(void); +#define _PR_MD_LAST_THREAD _MD_LAST_THREAD + +NSPR_API(void) _PR_MD_SET_CURRENT_THREAD(PRThread *thread); +#define _PR_MD_SET_CURRENT_THREAD _MD_SET_CURRENT_THREAD + +NSPR_API(void) _PR_MD_SET_LAST_THREAD(PRThread *thread); +#define _PR_MD_SET_LAST_THREAD _MD_SET_LAST_THREAD + +extern PRStatus _PR_MD_INIT_THREAD(PRThread *thread); +#define _PR_MD_INIT_THREAD _MD_INIT_THREAD + +extern void _PR_MD_EXIT_THREAD(PRThread *thread); +#define _PR_MD_EXIT_THREAD _MD_EXIT_THREAD + +#ifndef _PR_LOCAL_THREADS_ONLY /* not if only local threads supported */ + +NSPR_API(PRStatus) _PR_MD_INIT_ATTACHED_THREAD(PRThread *thread); +#define _PR_MD_INIT_ATTACHED_THREAD _MD_INIT_ATTACHED_THREAD + +extern void _PR_MD_SUSPEND_THREAD(PRThread *thread); +#define _PR_MD_SUSPEND_THREAD _MD_SUSPEND_THREAD + +extern void _PR_MD_RESUME_THREAD(PRThread *thread); +#define _PR_MD_RESUME_THREAD _MD_RESUME_THREAD + +extern void _PR_MD_SUSPEND_CPU(_PRCPU *cpu); +#define _PR_MD_SUSPEND_CPU _MD_SUSPEND_CPU + +extern void _PR_MD_RESUME_CPU(_PRCPU *cpu); +#define _PR_MD_RESUME_CPU _MD_RESUME_CPU + +extern void _PR_MD_BEGIN_SUSPEND_ALL(void); +#define _PR_MD_BEGIN_SUSPEND_ALL _MD_BEGIN_SUSPEND_ALL + +extern void _PR_MD_END_SUSPEND_ALL(void); +#define _PR_MD_END_SUSPEND_ALL _MD_END_SUSPEND_ALL + +extern void _PR_MD_BEGIN_RESUME_ALL(void); +#define _PR_MD_BEGIN_RESUME_ALL _MD_BEGIN_RESUME_ALL + +extern void _PR_MD_END_RESUME_ALL(void); +#define _PR_MD_END_RESUME_ALL _MD_END_RESUME_ALL + +#if defined(IRIX) +NSPR_API(void) _PR_IRIX_CHILD_PROCESS(void); +#endif /* IRIX */ + +#endif /* !_PR_LOCAL_THREADS_ONLY */ + +extern void _PR_MD_CLEAN_THREAD(PRThread *thread); +#define _PR_MD_CLEAN_THREAD _MD_CLEAN_THREAD + +#ifdef HAVE_CUSTOM_USER_THREADS +extern void _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *); +#define _PR_MD_CREATE_PRIMORDIAL_USER_THREAD _MD_CREATE_PRIMORDIAL_USER_THREAD + +extern PRThread* _PR_MD_CREATE_USER_THREAD( + PRUint32 stacksize, + void (*start)(void *), + void *arg); +#define _PR_MD_CREATE_USER_THREAD _MD_CREATE_USER_THREAD +#endif + +extern PRStatus _PR_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); +#define _PR_MD_CREATE_THREAD _MD_CREATE_THREAD + +extern void _PR_MD_JOIN_THREAD(_MDThread *md); +#define _PR_MD_JOIN_THREAD _MD_JOIN_THREAD + +extern void _PR_MD_END_THREAD(void); +#define _PR_MD_END_THREAD _MD_END_THREAD + +extern void _PR_MD_YIELD(void); +#define _PR_MD_YIELD _MD_YIELD + +extern void _PR_MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri); +#define _PR_MD_SET_PRIORITY _MD_SET_PRIORITY + +NSPR_API(void) _PR_MD_SUSPENDALL(void); +#define _PR_MD_SUSPENDALL _MD_SUSPENDALL + +NSPR_API(void) _PR_MD_RESUMEALL(void); +#define _PR_MD_RESUMEALL _MD_RESUMEALL + +extern void _PR_MD_INIT_CONTEXT( + PRThread *thread, char *top, void (*start) (void), PRBool *status); +#define _PR_MD_INIT_CONTEXT _MD_INIT_CONTEXT + +extern void _PR_MD_SWITCH_CONTEXT(PRThread *thread); +#define _PR_MD_SWITCH_CONTEXT _MD_SWITCH_CONTEXT + +extern void _PR_MD_RESTORE_CONTEXT(PRThread *thread); +#define _PR_MD_RESTORE_CONTEXT _MD_RESTORE_CONTEXT + +/* Segment related */ +extern void _PR_MD_INIT_SEGS(void); +#define _PR_MD_INIT_SEGS _MD_INIT_SEGS + +extern PRStatus _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr); +#define _PR_MD_ALLOC_SEGMENT _MD_ALLOC_SEGMENT + +extern void _PR_MD_FREE_SEGMENT(PRSegment *seg); +#define _PR_MD_FREE_SEGMENT _MD_FREE_SEGMENT + +/* Directory enumeration related */ +extern PRStatus _PR_MD_OPEN_DIR(_MDDir *md,const char *name); +#define _PR_MD_OPEN_DIR _MD_OPEN_DIR + +extern char * _PR_MD_READ_DIR(_MDDir *md, PRIntn flags); +#define _PR_MD_READ_DIR _MD_READ_DIR + +extern PRInt32 _PR_MD_CLOSE_DIR(_MDDir *md); +#define _PR_MD_CLOSE_DIR _MD_CLOSE_DIR + +/* Named semaphores related */ +extern PRSem * _PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value); +#define _PR_MD_OPEN_SEMAPHORE _MD_OPEN_SEMAPHORE + +extern PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem); +#define _PR_MD_WAIT_SEMAPHORE _MD_WAIT_SEMAPHORE + +extern PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem); +#define _PR_MD_POST_SEMAPHORE _MD_POST_SEMAPHORE + +extern PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem); +#define _PR_MD_CLOSE_SEMAPHORE _MD_CLOSE_SEMAPHORE + +extern PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname); +#define _PR_MD_DELETE_SEMAPHORE _MD_DELETE_SEMAPHORE + +/* I/O related */ +extern void _PR_MD_INIT_FILEDESC(PRFileDesc *fd); +#define _PR_MD_INIT_FILEDESC _MD_INIT_FILEDESC + +#ifdef XP_MAC +extern void _PR_MD_FREE_FILEDESC(PRFileDesc *fd); +#define _PR_MD_FREE_FILEDESC _MD_FREE_FILEDESC +#endif + +extern void _PR_MD_MAKE_NONBLOCK(PRFileDesc *fd); +#define _PR_MD_MAKE_NONBLOCK _MD_MAKE_NONBLOCK + +/* File I/O related */ +extern PRInt32 _PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN _MD_OPEN + +extern PRInt32 _PR_MD_OPEN_FILE(const char *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN_FILE _MD_OPEN_FILE + +extern PRInt32 _PR_MD_CLOSE_FILE(PRInt32 osfd); +#define _PR_MD_CLOSE_FILE _MD_CLOSE_FILE + +extern PRInt32 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 amount); +#define _PR_MD_READ _MD_READ + +extern PRInt32 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 amount); +#define _PR_MD_WRITE _MD_WRITE + +extern PRInt32 _PR_MD_WRITEV( + PRFileDesc *fd, const struct PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout); +#define _PR_MD_WRITEV _MD_WRITEV + +extern PRInt32 _PR_MD_FSYNC(PRFileDesc *fd); +#define _PR_MD_FSYNC _MD_FSYNC + +extern PRInt32 _PR_MD_DELETE(const char *name); +#define _PR_MD_DELETE _MD_DELETE + +extern PRInt32 _PR_MD_RENAME(const char *from, const char *to); +#define _PR_MD_RENAME _MD_RENAME + +extern PRInt32 _PR_MD_ACCESS(const char *name, PRAccessHow how); +#define _PR_MD_ACCESS _MD_ACCESS + +extern PRInt32 _PR_MD_STAT(const char *name, struct stat *buf); +#define _PR_MD_STAT _MD_STAT + +extern PRInt32 _PR_MD_MKDIR(const char *name, PRIntn mode); +#define _PR_MD_MKDIR _MD_MKDIR + +extern PRInt32 _PR_MD_MAKE_DIR(const char *name, PRIntn mode); +#define _PR_MD_MAKE_DIR _MD_MAKE_DIR + +extern PRInt32 _PR_MD_RMDIR(const char *name); +#define _PR_MD_RMDIR _MD_RMDIR + +#ifdef MOZ_UNICODE +/* UTF16 File I/O related */ +extern PRStatus _PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *md, const PRUnichar *name); +#define _PR_MD_OPEN_DIR_UTF16 _MD_OPEN_DIR_UTF16 + +extern PRInt32 _PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, PRIntn mode); +#define _PR_MD_OPEN_FILE_UTF16 _MD_OPEN_FILE_UTF16 + +extern PRUnichar * _PR_MD_READ_DIR_UTF16(_MDDirUTF16 *md, PRIntn flags); +#define _PR_MD_READ_DIR_UTF16 _MD_READ_DIR_UTF16 + +extern PRInt32 _PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *md); +#define _PR_MD_CLOSE_DIR_UTF16 _MD_CLOSE_DIR_UTF16 + +extern PRInt32 _PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info); +#define _PR_MD_GETFILEINFO64_UTF16 _MD_GETFILEINFO64_UTF16 +#endif /* MOZ_UNICODE */ + +/* Socket I/O related */ +extern void _PR_MD_INIT_IO(void); +#define _PR_MD_INIT_IO _MD_INIT_IO + +extern PRInt32 _PR_MD_CLOSE_SOCKET(PRInt32 osfd); +#define _PR_MD_CLOSE_SOCKET _MD_CLOSE_SOCKET + +extern PRInt32 _PR_MD_CONNECT( + PRFileDesc *fd, const PRNetAddr *addr, + PRUint32 addrlen, PRIntervalTime timeout); +#define _PR_MD_CONNECT _MD_CONNECT + +extern PRInt32 _PR_MD_ACCEPT( + PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout); +#define _PR_MD_ACCEPT _MD_ACCEPT + +extern PRInt32 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen); +#define _PR_MD_BIND _MD_BIND + +extern PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog); +#define _PR_MD_LISTEN _MD_LISTEN + +extern PRInt32 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how); +#define _PR_MD_SHUTDOWN _MD_SHUTDOWN + +extern PRInt32 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout); +#define _PR_MD_RECV _MD_RECV + +extern PRInt32 _PR_MD_SEND( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout); +#define _PR_MD_SEND _MD_SEND + +extern PRInt32 _PR_MD_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, + PRNetAddr **raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout); +#define _PR_MD_ACCEPT_READ _MD_ACCEPT_READ + +#ifdef WIN32 +extern PRInt32 _PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout, + PRBool fast, + _PR_AcceptTimeoutCallback callback, + void *callbackArg); + +extern PRInt32 _PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, + PRNetAddr **raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout, PRBool fast, + _PR_AcceptTimeoutCallback callback, + void *callbackArg); + +extern void _PR_MD_UPDATE_ACCEPT_CONTEXT(PRInt32 s, PRInt32 ls); +#define _PR_MD_UPDATE_ACCEPT_CONTEXT _MD_UPDATE_ACCEPT_CONTEXT +#endif /* WIN32 */ + +extern PRInt32 _PR_MD_SENDFILE( + PRFileDesc *sock, PRSendFileData *sfd, + PRInt32 flags, PRIntervalTime timeout); +#define _PR_MD_SENDFILE _MD_SENDFILE + +extern PRStatus _PR_MD_GETSOCKNAME( + PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +#define _PR_MD_GETSOCKNAME _MD_GETSOCKNAME + +extern PRStatus _PR_MD_GETPEERNAME( + PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen); +#define _PR_MD_GETPEERNAME _MD_GETPEERNAME + +extern PRStatus _PR_MD_GETSOCKOPT( + PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen); +#define _PR_MD_GETSOCKOPT _MD_GETSOCKOPT + +extern PRStatus _PR_MD_SETSOCKOPT( + PRFileDesc *fd, PRInt32 level, PRInt32 optname, + const char* optval, PRInt32 optlen); +#define _PR_MD_SETSOCKOPT _MD_SETSOCKOPT + +extern PRStatus PR_CALLBACK _PR_SocketGetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data); + +extern PRStatus PR_CALLBACK _PR_SocketSetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data); + +extern PRInt32 _PR_MD_RECVFROM( + PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout); +#define _PR_MD_RECVFROM _MD_RECVFROM + +extern PRInt32 _PR_MD_SENDTO( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout); +#define _PR_MD_SENDTO _MD_SENDTO + +extern PRInt32 _PR_MD_SOCKETPAIR(int af, int type, int flags, PRInt32 *osfd); +#define _PR_MD_SOCKETPAIR _MD_SOCKETPAIR + +extern PRInt32 _PR_MD_SOCKET(int af, int type, int flags); +#define _PR_MD_SOCKET _MD_SOCKET + +extern PRInt32 _PR_MD_SOCKETAVAILABLE(PRFileDesc *fd); +#define _PR_MD_SOCKETAVAILABLE _MD_SOCKETAVAILABLE + +extern PRInt32 _PR_MD_PIPEAVAILABLE(PRFileDesc *fd); +#define _PR_MD_PIPEAVAILABLE _MD_PIPEAVAILABLE + +extern PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout); +#define _PR_MD_PR_POLL _MD_PR_POLL + +/* + * Initialize fd->secret->inheritable for a newly created fd. + * If 'imported' is false, the osfd (i.e., fd->secret->md.osfd) + * was created by NSPR and hence has the OS-dependent default + * inheritable attribute. If 'imported' is true, the osfd was + * not created by NSPR and hence a system call is required to + * query its inheritable attribute. Since we may never need to + * know the inheritable attribute of a fd, a platform may choose + * to initialize fd->secret->inheritable of an imported fd to + * _PR_TRI_UNKNOWN and only pay the cost of the system call + * (in _PR_MD_QUERY_FD_INHERITABLE) when necessary. + */ +extern void _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported); +#define _PR_MD_INIT_FD_INHERITABLE _MD_INIT_FD_INHERITABLE + +extern PRStatus _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable); +#define _PR_MD_SET_FD_INHERITABLE _MD_SET_FD_INHERITABLE + + +#define _PR_PROCESS_TIMEOUT_INTERRUPT_ERRORS(me) \ + if (_PR_PENDING_INTERRUPT(me)) { \ + me->flags &= ~_PR_INTERRUPT; \ + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); \ + } else { \ + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); \ + } + +extern void *_PR_MD_GET_SP(PRThread *thread); +#define _PR_MD_GET_SP _MD_GET_SP + +#endif /* defined(_PR_PTHREADS) */ + +/************************************************************************/ +/************************************************************************* +** The remainder of the definitions are shared by pthreads and the classic +** NSPR code. These too may be conditionalized. +*************************************************************************/ +/************************************************************************/ + +extern PROffset32 _PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence); +#define _PR_MD_LSEEK _MD_LSEEK + +extern PROffset64 _PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence); +#define _PR_MD_LSEEK64 _MD_LSEEK64 + +extern PRInt32 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info); +#define _PR_MD_GETFILEINFO _MD_GETFILEINFO + +extern PRInt32 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info); +#define _PR_MD_GETFILEINFO64 _MD_GETFILEINFO64 + +extern PRInt32 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info); +#define _PR_MD_GETOPENFILEINFO _MD_GETOPENFILEINFO + +extern PRInt32 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info); +#define _PR_MD_GETOPENFILEINFO64 _MD_GETOPENFILEINFO64 + + +/*****************************************************************************/ +/************************** File descriptor caching **************************/ +/*****************************************************************************/ +extern void _PR_InitFdCache(void); +extern void _PR_CleanupFdCache(void); +extern PRFileDesc *_PR_Getfd(void); +extern void _PR_Putfd(PRFileDesc *fd); + +/* + * These flags are used by NSPR temporarily in the poll + * descriptor's out_flags field to record the mapping of + * NSPR's poll flags to the system poll flags. + * + * If _PR_POLL_READ_SYS_WRITE bit is set, it means the + * PR_POLL_READ flag specified by the topmost layer is + * mapped to the WRITE flag at the system layer. Similarly + * for the other three _PR_POLL_XXX_SYS_YYY flags. It is + * assumed that the PR_POLL_EXCEPT flag doesn't get mapped + * to other flags. + */ +#define _PR_POLL_READ_SYS_READ 0x1 +#define _PR_POLL_READ_SYS_WRITE 0x2 +#define _PR_POLL_WRITE_SYS_READ 0x4 +#define _PR_POLL_WRITE_SYS_WRITE 0x8 + +/* +** These methods are coerced into file descriptor methods table +** when the intended service is inappropriate for the particular +** type of file descriptor. +*/ +extern PRIntn _PR_InvalidInt(void); +extern PRInt16 _PR_InvalidInt16(void); +extern PRInt64 _PR_InvalidInt64(void); +extern PRStatus _PR_InvalidStatus(void); +extern PRFileDesc *_PR_InvalidDesc(void); + +extern PRIOMethods _pr_faulty_methods; + +/* +** The PR_NETADDR_SIZE macro can only be called on a PRNetAddr union +** whose 'family' field is set. It returns the size of the union +** member corresponding to the specified address family. +*/ + +extern PRUintn _PR_NetAddrSize(const PRNetAddr* addr); + +#if defined(_PR_INET6) + +#define PR_NETADDR_SIZE(_addr) _PR_NetAddrSize(_addr) + +#elif defined(_PR_HAVE_MD_SOCKADDR_IN6) + +/* +** Under the following conditions: +** 1. _PR_INET6 is not defined; +** 2. _PR_INET6_PROBE is defined; +** 3. struct sockaddr_in6 has nonstandard fields at the end +** (e.g., on Solaris 8), +** (_addr)->ipv6 is smaller than struct sockaddr_in6, and +** hence we can't pass sizeof((_addr)->ipv6) to socket +** functions such as connect because they would fail with +** EINVAL. +** +** To pass the correct socket address length to socket +** functions, define the macro _PR_HAVE_MD_SOCKADDR_IN6 and +** define struct _md_sockaddr_in6 to be isomorphic to +** struct sockaddr_in6. +*/ + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : ((_addr)->raw.family == PR_AF_INET6 \ + ? sizeof(struct _md_sockaddr_in6) \ + : sizeof((_addr)->local))) +#else +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : sizeof(struct _md_sockaddr_in6) +#endif /* defined(XP_UNIX) */ + +#else + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : ((_addr)->raw.family == PR_AF_INET6 \ + ? sizeof((_addr)->ipv6) \ + : sizeof((_addr)->local))) +#else +#define PR_NETADDR_SIZE(_addr) \ + ((_addr)->raw.family == PR_AF_INET \ + ? sizeof((_addr)->inet) \ + : sizeof((_addr)->ipv6)) +#endif /* defined(XP_UNIX) */ + +#endif /* defined(_PR_INET6) */ + +extern PRStatus _PR_MapOptionName( + PRSockOption optname, PRInt32 *level, PRInt32 *name); +extern void _PR_InitThreads( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs); + +struct PRLock { +#if defined(_PR_PTHREADS) + pthread_mutex_t mutex; /* the underlying lock */ + _PT_Notified notified; /* array of conditions notified */ + PRBool locked; /* whether the mutex is locked */ + pthread_t owner; /* if locked, current lock owner */ +#elif defined(_PR_BTHREADS) + sem_id semaphoreID; /* the underlying lock */ + int32 benaphoreCount; /* number of people in lock */ + thread_id owner; /* current lock owner */ +#else /* not pthreads or Be threads */ + PRCList links; /* linkage for PRThread.lockList */ + struct PRThread *owner; /* current lock owner */ + PRCList waitQ; /* list of threads waiting for lock */ + PRThreadPriority priority; /* priority of lock */ + PRThreadPriority boostPriority; /* boosted priority of lock owner */ + _MDLock ilock; /* Internal Lock to protect user-level fields */ +#endif +}; + +extern void _PR_InitLocks(void); + +struct PRCondVar { + PRLock *lock; /* associated lock that protects the condition */ +#if defined(_PR_PTHREADS) + pthread_cond_t cv; /* underlying pthreads condition */ + PRInt32 notify_pending; /* CV has destroy pending notification */ +#elif defined(_PR_BTHREADS) + sem_id sem; /* the underlying lock */ + sem_id handshakeSem; /* the lock for 'notify'-threads waiting for confirmation */ + sem_id signalSem; /* the lock for threads waiting for someone to notify */ + volatile int32 nw; /* the number waiting */ + volatile int32 ns; /* the number signalling */ + long signalBenCount; /* the number waiting on the underlying sem */ +#else /* not pthreads or Be threads */ + PRCList condQ; /* Condition variable wait Q */ + _MDLock ilock; /* Internal Lock to protect condQ */ + _MDCVar md; +#endif +}; + +/************************************************************************/ + +struct PRMonitor { + const char* name; /* monitor name for debugging */ +#if defined(_PR_PTHREADS) + PRLock lock; /* the lock structure */ + pthread_t owner; /* the owner of the lock or invalid */ + PRCondVar *cvar; /* condition variable queue */ +#else /* defined(_PR_PTHREADS) */ + PRCondVar *cvar; /* associated lock and condition variable queue */ +#endif /* defined(_PR_PTHREADS) */ + PRUint32 entryCount; /* # of times re-entered */ +}; + +/************************************************************************/ + +struct PRSemaphore { +#if defined(_PR_BTHREADS) + sem_id sem; + int32 benaphoreCount; +#else + PRCondVar *cvar; /* associated lock and condition variable queue */ + PRUintn count; /* the value of the counting semaphore */ + PRUint32 waiters; /* threads waiting on the semaphore */ +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDSemaphore md; +#endif /* defined(_PR_PTHREADS) */ +#endif /* defined(_PR_BTHREADS) */ +}; + +NSPR_API(void) _PR_InitSem(void); + +/*************************************************************************/ + +struct PRSem { +#ifdef _PR_HAVE_POSIX_SEMAPHORES + sem_t *sem; +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + int semid; +#elif defined(WIN32) + HANDLE sem; +#else + PRInt8 notused; +#endif +}; + +/*************************************************************************/ + +struct PRStackStr { + /* head MUST be at offset 0; assembly language code relies on this */ +#if defined(AIX) + volatile PRStackElem prstk_head; +#else + PRStackElem prstk_head; +#endif + + PRLock *prstk_lock; + char *prstk_name; +}; + +/************************************************************************/ + +/* XXX this needs to be exported (sigh) */ +struct PRThreadStack { + PRCList links; + PRUintn flags; + + char *allocBase; /* base of stack's allocated memory */ + PRUint32 allocSize; /* size of stack's allocated memory */ + char *stackBottom; /* bottom of stack from C's point of view */ + char *stackTop; /* top of stack from C's point of view */ + PRUint32 stackSize; /* size of usable portion of the stack */ + + PRSegment *seg; + PRThread* thr; /* back pointer to thread owning this stack */ + +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDThreadStack md; +#endif /* defined(_PR_PTHREADS) */ +}; + +extern void _PR_DestroyThreadPrivate(PRThread*); + +typedef void (PR_CALLBACK *_PRStartFn)(void *); + +struct PRThread { + PRUint32 state; /* thread's creation state */ + PRThreadPriority priority; /* apparent priority, loosly defined */ + + void *arg; /* argument to the client's entry point */ + _PRStartFn startFunc; /* the root of the client's thread */ + + PRThreadStack *stack; /* info about thread's stack (for GC) */ + void *environment; /* pointer to execution environment */ + + PRThreadDumpProc dump; /* dump thread info out */ + void *dumpArg; /* argument for the dump function */ + + /* + ** Per thread private data + */ + PRUint32 tpdLength; /* thread's current vector length */ + void **privateData; /* private data vector or NULL */ + PRErrorCode errorCode; /* current NSPR error code | zero */ + PRInt32 osErrorCode; /* mapping of errorCode | zero */ + PRIntn errorStringLength; /* textLength from last call to PR_SetErrorText() */ + PRInt32 errorStringSize; /* malloc()'d size of buffer | zero */ + char *errorString; /* current error string | NULL */ + +#if defined(_PR_PTHREADS) + pthread_t id; /* pthread identifier for the thread */ + PRBool okToDelete; /* ok to delete the PRThread struct? */ + PRCondVar *waiting; /* where the thread is waiting | NULL */ + void *sp; /* recorded sp for garbage collection */ + PRThread *next, *prev; /* simple linked list of all threads */ + PRUint32 suspend; /* used to store suspend and resume flags */ +#ifdef PT_NO_SIGTIMEDWAIT + pthread_mutex_t suspendResumeMutex; + pthread_cond_t suspendResumeCV; +#endif + PRUint32 interrupt_blocked; /* interrupt blocked */ + struct pollfd *syspoll_list; /* Unix polling list used by PR_Poll */ + PRUint32 syspoll_count; /* number of elements in syspoll_list */ +#if defined(_PR_POLL_WITH_SELECT) + int *selectfd_list; /* Unix fd's that PR_Poll selects on */ + PRUint32 selectfd_count; /* number of elements in selectfd_list */ +#endif +#elif defined(_PR_BTHREADS) + PRUint32 flags; + _MDThread md; + PRBool io_pending; + PRInt32 io_fd; + PRBool io_suspended; +#else /* not pthreads or Be threads */ + _MDLock threadLock; /* Lock to protect thread state variables. + * Protects the following fields: + * state + * priority + * links + * wait + * cpu + */ + PRUint32 queueCount; + PRUint32 waitCount; + + PRCList active; /* on list of all active threads */ + PRCList links; + PRCList waitQLinks; /* when thread is PR_Wait'ing */ + PRCList lockList; /* list of locks currently holding */ + PRIntervalTime sleep; /* sleep time when thread is sleeping */ + struct _wait { + struct PRLock *lock; + struct PRCondVar *cvar; + } wait; + + PRUint32 id; + PRUint32 flags; + PRUint32 no_sched; /* Don't schedule the thread to run. + * This flag has relevance only when + * multiple NSPR CPUs are created. + * When a thread is de-scheduled, there + * is a narrow window of time in which + * the thread is put on the run queue + * but the scheduler is actually using + * the stack of this thread. It is safe + * to run this thread on a different CPU + * only when its stack is not in use on + * any other CPU. The no_sched flag is + * set during this interval to prevent + * the thread from being scheduled on a + * different CPU. + */ + + /* thread termination condition variable for join */ + PRCondVar *term; + + _PRCPU *cpu; /* cpu to which this thread is bound */ + PRUint32 threadAllocatedOnStack;/* boolean */ + + /* When an async IO is in progress and a second async IO cannot be + * initiated, the io_pending flag is set to true. Some platforms will + * not use the io_pending flag. If the io_pending flag is true, then + * io_fd is the OS-file descriptor on which IO is pending. + */ + PRBool io_pending; + PRInt32 io_fd; + + /* If a timeout occurs or if an outstanding IO is interrupted and the + * OS doesn't support a real cancellation (NT or MAC), then the + * io_suspended flag will be set to true. The thread will be resumed + * but may run into trouble issuing additional IOs until the io_pending + * flag can be cleared + */ + PRBool io_suspended; + + _MDThread md; +#endif +}; + +struct PRProcessAttr { + PRFileDesc *stdinFd; + PRFileDesc *stdoutFd; + PRFileDesc *stderrFd; + char *currentDirectory; + char *fdInheritBuffer; + PRSize fdInheritBufferSize; + PRSize fdInheritBufferUsed; +}; + +struct PRProcess { + _MDProcess md; +}; + +struct PRFileMap { + PRFileDesc *fd; + PRFileMapProtect prot; + _MDFileMap md; +}; + +/************************************************************************/ + +/* +** File descriptors of the NSPR layer can be in one of the +** following states (stored in the 'state' field of struct +** PRFilePrivate): +** - _PR_FILEDESC_OPEN: The OS fd is open. +** - _PR_FILEDESC_CLOSED: The OS fd is closed. The PRFileDesc +** is still open but is unusable. The only operation allowed +** on the PRFileDesc is PR_Close(). +** - _PR_FILEDESC_FREED: The OS fd is closed and the PRFileDesc +** structure is freed. +*/ + +#define _PR_FILEDESC_OPEN 0xaaaaaaaa /* 1010101... */ +#define _PR_FILEDESC_CLOSED 0x55555555 /* 0101010... */ +#define _PR_FILEDESC_FREED 0x11111111 + +/* +** A boolean type with an additional "unknown" state +*/ + +typedef enum { + _PR_TRI_TRUE = 1, + _PR_TRI_FALSE = 0, + _PR_TRI_UNKNOWN = -1 +} _PRTriStateBool; + +struct PRFilePrivate { + PRInt32 state; + PRBool nonblocking; + _PRTriStateBool inheritable; + PRFileDesc *next; + PRIntn lockCount; /* 0: not locked + * -1: a native lockfile call is in progress + * > 0: # times the file is locked */ +#ifdef _PR_HAVE_PEEK_BUFFER + char *peekBuffer; + PRInt32 peekBufSize; + PRInt32 peekBytes; +#endif +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + PRBool appendMode; +#endif + _MDFileDesc md; +#ifdef _PR_STRICT_ADDR_LEN + PRUint16 af; /* If the platform requires passing the exact + * length of the sockaddr structure for the + * address family of the socket to socket + * functions like accept(), we need to save + * the address family of the socket. */ +#endif +}; + +struct PRDir { + PRDirEntry d; + _MDDir md; +}; + +#ifdef MOZ_UNICODE +struct PRDirUTF16 { + PRDirEntry d; + _MDDirUTF16 md; +}; +#endif /* MOZ_UNICODE */ + +extern void _PR_InitSegs(void); +extern void _PR_InitStacks(void); +extern void _PR_InitTPD(void); +extern void _PR_InitMem(void); +extern void _PR_InitEnv(void); +extern void _PR_InitCMon(void); +extern void _PR_InitIO(void); +extern void _PR_InitLog(void); +extern void _PR_InitNet(void); +extern void _PR_InitClock(void); +extern void _PR_InitLinker(void); +extern void _PR_InitAtomic(void); +extern void _PR_InitCPUs(void); +extern void _PR_InitDtoa(void); +extern void _PR_InitMW(void); +extern void _PR_InitRWLocks(void); +extern void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me); +extern void _PR_CleanupThread(PRThread *thread); +extern void _PR_CleanupCallOnce(void); +extern void _PR_CleanupMW(void); +extern void _PR_CleanupDtoa(void); +extern void _PR_ShutdownLinker(void); +extern void _PR_CleanupEnv(void); +extern void _PR_CleanupIO(void); +extern void _PR_CleanupNet(void); +extern void _PR_CleanupLayerCache(void); +extern void _PR_CleanupStacks(void); +#ifdef WINNT +extern void _PR_CleanupCPUs(void); +#endif +extern void _PR_CleanupThreads(void); +extern void _PR_CleanupTPD(void); +extern void _PR_Cleanup(void); +extern void _PR_LogCleanup(void); +extern void _PR_InitLayerCache(void); +#ifdef GC_LEAK_DETECTOR +extern void _PR_InitGarbageCollector(void); +#endif + +extern PRBool _pr_initialized; +extern void _PR_ImplicitInitialization(void); +extern PRBool _PR_Obsolete(const char *obsolete, const char *preferred); + +/************************************************************************/ + +struct PRSegment { + void *vaddr; + PRUint32 size; + PRUintn flags; +#if defined(_PR_PTHREADS) +#else /* defined(_PR_PTHREADS) */ + _MDSegment md; +#endif /* defined(_PR_PTHREADS) */ +}; + +/* PRSegment.flags */ +#define _PR_SEG_VM 0x1 + +/************************************************************************/ + +extern PRInt32 _pr_pageSize; +extern PRInt32 _pr_pageShift; + +extern PRLogModuleInfo *_pr_clock_lm; +extern PRLogModuleInfo *_pr_cmon_lm; +extern PRLogModuleInfo *_pr_io_lm; +extern PRLogModuleInfo *_pr_cvar_lm; +extern PRLogModuleInfo *_pr_mon_lm; +extern PRLogModuleInfo *_pr_linker_lm; +extern PRLogModuleInfo *_pr_sched_lm; +extern PRLogModuleInfo *_pr_thread_lm; +extern PRLogModuleInfo *_pr_gc_lm; + +extern PRFileDesc *_pr_stdin; +extern PRFileDesc *_pr_stdout; +extern PRFileDesc *_pr_stderr; + +/* Zone allocator */ +/* +** The zone allocator code has hardcoded pthread types and +** functions, so it can only be used in the pthreads version. +** This can be fixed by replacing the hardcoded pthread types +** and functions with macros that expand to the native thread +** types and functions on each platform. +*/ +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#define _PR_ZONE_ALLOCATOR +#endif + +#ifdef _PR_ZONE_ALLOCATOR +extern void _PR_InitZones(void); +extern void _PR_DestroyZones(void); +#endif + +/* Overriding malloc, free, etc. */ +#if !defined(_PR_NO_PREEMPT) && defined(XP_UNIX) \ + && !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) \ + && !defined(PURIFY) \ + && !defined(DARWIN) \ + && !defined(NEXTSTEP) \ + && !defined(QNX) \ + && !(defined (UNIXWARE) && defined (USE_SVR4_THREADS)) +#define _PR_OVERRIDE_MALLOC +#endif + +/************************************************************************* +* External machine-dependent code provided by each OS. * * +*************************************************************************/ + +/* Initialization related */ +extern void _PR_MD_EARLY_INIT(void); +#define _PR_MD_EARLY_INIT _MD_EARLY_INIT + +extern void _PR_MD_INTERVAL_INIT(void); +#define _PR_MD_INTERVAL_INIT _MD_INTERVAL_INIT + +NSPR_API(void) _PR_MD_FINAL_INIT(void); +#define _PR_MD_FINAL_INIT _MD_FINAL_INIT + +/* Process control */ + +extern PRProcess * _PR_MD_CREATE_PROCESS( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); +#define _PR_MD_CREATE_PROCESS _MD_CREATE_PROCESS + +#ifdef _MD_CREATE_PROCESS_DETACHED +# define _PR_MD_CREATE_PROCESS_DETACHED _MD_CREATE_PROCESS_DETACHED +#endif + +extern PRStatus _PR_MD_DETACH_PROCESS(PRProcess *process); +#define _PR_MD_DETACH_PROCESS _MD_DETACH_PROCESS + +extern PRStatus _PR_MD_WAIT_PROCESS(PRProcess *process, PRInt32 *exitCode); +#define _PR_MD_WAIT_PROCESS _MD_WAIT_PROCESS + +extern PRStatus _PR_MD_KILL_PROCESS(PRProcess *process); +#define _PR_MD_KILL_PROCESS _MD_KILL_PROCESS + +/* Current Time */ +NSPR_API(PRTime) _PR_MD_NOW(void); +#define _PR_MD_NOW _MD_NOW + +/* Environment related */ +extern char* _PR_MD_GET_ENV(const char *name); +#define _PR_MD_GET_ENV _MD_GET_ENV + +extern PRIntn _PR_MD_PUT_ENV(const char *name); +#define _PR_MD_PUT_ENV _MD_PUT_ENV + +/* Atomic operations */ + +extern void _PR_MD_INIT_ATOMIC(void); +#define _PR_MD_INIT_ATOMIC _MD_INIT_ATOMIC + +extern PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *); +#define _PR_MD_ATOMIC_INCREMENT _MD_ATOMIC_INCREMENT + +extern PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *, PRInt32); +#define _PR_MD_ATOMIC_ADD _MD_ATOMIC_ADD + +extern PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *); +#define _PR_MD_ATOMIC_DECREMENT _MD_ATOMIC_DECREMENT + +extern PRInt32 _PR_MD_ATOMIC_SET(PRInt32 *, PRInt32); +#define _PR_MD_ATOMIC_SET _MD_ATOMIC_SET + +/* Garbage collection */ + +/* +** Save the registers that the GC would find interesting into the thread +** "t". isCurrent will be non-zero if the thread state that is being +** saved is the currently executing thread. Return the address of the +** first register to be scanned as well as the number of registers to +** scan in "np". +** +** If "isCurrent" is non-zero then it is allowed for the thread context +** area to be used as scratch storage to hold just the registers +** necessary for scanning. +*/ +extern PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np); + +/* Time intervals */ + +extern PRIntervalTime _PR_MD_GET_INTERVAL(void); +#define _PR_MD_GET_INTERVAL _MD_GET_INTERVAL + +extern PRIntervalTime _PR_MD_INTERVAL_PER_SEC(void); +#define _PR_MD_INTERVAL_PER_SEC _MD_INTERVAL_PER_SEC + +/* Affinity masks */ + +extern PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ); +#define _PR_MD_SETTHREADAFFINITYMASK _MD_SETTHREADAFFINITYMASK + +extern PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask); +#define _PR_MD_GETTHREADAFFINITYMASK _MD_GETTHREADAFFINITYMASK + +/* File locking */ + +extern PRStatus _PR_MD_LOCKFILE(PRInt32 osfd); +#define _PR_MD_LOCKFILE _MD_LOCKFILE + +extern PRStatus _PR_MD_TLOCKFILE(PRInt32 osfd); +#define _PR_MD_TLOCKFILE _MD_TLOCKFILE + +extern PRStatus _PR_MD_UNLOCKFILE(PRInt32 osfd); +#define _PR_MD_UNLOCKFILE _MD_UNLOCKFILE + +/* Memory-mapped files */ + +extern PRStatus _PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size); +#define _PR_MD_CREATE_FILE_MAP _MD_CREATE_FILE_MAP + +extern PRInt32 _PR_MD_GET_MEM_MAP_ALIGNMENT(void); +#define _PR_MD_GET_MEM_MAP_ALIGNMENT _MD_GET_MEM_MAP_ALIGNMENT + +extern void * _PR_MD_MEM_MAP( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len); +#define _PR_MD_MEM_MAP _MD_MEM_MAP + +extern PRStatus _PR_MD_MEM_UNMAP(void *addr, PRUint32 size); +#define _PR_MD_MEM_UNMAP _MD_MEM_UNMAP + +extern PRStatus _PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap); +#define _PR_MD_CLOSE_FILE_MAP _MD_CLOSE_FILE_MAP + +/* Named Shared Memory */ + +/* +** Declare PRSharedMemory. +*/ +struct PRSharedMemory +{ + char *ipcname; /* after conversion to native */ + PRSize size; /* from open */ + PRIntn mode; /* from open */ + PRIntn flags; /* from open */ +#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY) + int id; +#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY) + int id; +#elif defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY) + HANDLE handle; +#else + PRUint32 nothing; /* placeholder, nothing behind here */ +#endif + PRUint32 ident; /* guard word at end of struct */ +#define _PR_SHM_IDENT 0xdeadbad +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +#define _PR_MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ); +#define _PR_MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ); +#define _PR_MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ); +#define _PR_MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory + +extern PRStatus _MD_DeleteSharedMemory( const char *name ); +#define _PR_MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); +#define _PR_MD_OPEN_ANON_FILE_MAP _md_OpenAnonFileMap + +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +); +#define _PR_MD_EXPORT_FILE_MAP_AS_STRING _md_ExportFileMapAsString + +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +); +#define _PR_MD_IMPORT_FILE_MAP_FROM_STRING _md_ImportFileMapFromString + + + +/* Interprocess communications (IPC) */ + +/* + * The maximum length of an NSPR IPC name, including the + * terminating null byte. + */ +#define PR_IPC_NAME_SIZE 1024 + +/* + * Types of NSPR IPC objects + */ +typedef enum { + _PRIPCSem, /* semaphores */ + _PRIPCShm /* shared memory segments */ +} _PRIPCType; + +/* + * Make a native IPC name from an NSPR IPC name. + */ +extern PRStatus _PR_MakeNativeIPCName( + const char *name, /* NSPR IPC name */ + char *result, /* result buffer */ + PRIntn size, /* size of result buffer */ + _PRIPCType type /* type of IPC object */ +); + +/* Socket call error code */ + +NSPR_API(PRInt32) _PR_MD_GET_SOCKET_ERROR(void); +#define _PR_MD_GET_SOCKET_ERROR _MD_GET_SOCKET_ERROR + +/* Get name of current host */ +extern PRStatus _PR_MD_GETHOSTNAME(char *name, PRUint32 namelen); +#define _PR_MD_GETHOSTNAME _MD_GETHOSTNAME + +extern PRStatus _PR_MD_GETSYSINFO(PRSysInfo cmd, char *name, PRUint32 namelen); +#define _PR_MD_GETSYSINFO _MD_GETSYSINFO + +/* File descriptor inheritance */ + +/* + * If fd->secret->inheritable is _PR_TRI_UNKNOWN and we need to + * know the inheritable attribute of the fd, call this function + * to find that out. This typically requires a system call. + */ +extern void _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd); +#define _PR_MD_QUERY_FD_INHERITABLE _MD_QUERY_FD_INHERITABLE + +/* --- PR_GetRandomNoise() related things --- */ + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ); +#define _PR_MD_GET_RANDOM_NOISE(buf,size) _PR_MD_GetRandomNoise((buf),(size)) +extern PRSize _pr_CopyLowBits( void *dest, PRSize dstlen, void *src, PRSize srclen ); + +/* end PR_GetRandomNoise() related */ + +#ifdef XP_BEOS + +extern PRLock *_connectLock; + +typedef struct _ConnectListNode { + PRInt32 osfd; + PRNetAddr addr; + PRUint32 addrlen; + PRIntervalTime timeout; +} ConnectListNode; + +extern ConnectListNode connectList[64]; + +extern PRUint32 connectCount; + +#endif /* XP_BEOS */ + +PR_END_EXTERN_C + +#endif /* primpl_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/private/prpriv.h b/src/libs/xpcom18a4/nsprpub/pr/include/private/prpriv.h new file mode 100644 index 00000000..780376e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/private/prpriv.h @@ -0,0 +1,53 @@ +/* -*- 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 prpriv_h___ +#define prpriv_h___ + +/* + * NSPR 2.0 Private API + */ + +#ifndef XP_MAC +#include "private/pprio.h" +#include "private/pprthred.h" +#else +#include "pprio.h" +#include "pprthred.h" +#endif + +#endif /* prpriv_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prlink.h b/src/libs/xpcom18a4/nsprpub/pr/include/prlink.h new file mode 100644 index 00000000..5bdafec9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prlink.h @@ -0,0 +1,271 @@ +/* -*- 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 prlink_h___ +#define prlink_h___ + +/* +** API to static and dynamic linking. +*/ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_SetLibraryPath VBoxNsprPR_SetLibraryPath +#define PR_GetLibraryPath VBoxNsprPR_GetLibraryPath +#define PR_GetLibraryName VBoxNsprPR_GetLibraryName +#define PR_FreeLibraryName VBoxNsprPR_FreeLibraryName +#define PR_LoadLibrary VBoxNsprPR_LoadLibrary +#define PR_LoadLibraryWithFlags VBoxNsprPR_LoadLibraryWithFlags +#define PR_UnloadLibrary VBoxNsprPR_UnloadLibrary +#define PR_FindSymbol VBoxNsprPR_FindSymbol +#define PR_FindFunctionSymbol VBoxNsprPR_FindFunctionSymbol +#define PR_FindSymbolAndLibrary VBoxNsprPR_FindSymbolAndLibrary +#define PR_FindFunctionSymbolAndLibrary VBoxNsprPR_FindFunctionSymbolAndLibrary +#define PR_LoadStaticLibrary VBoxNsprPR_LoadStaticLibrary +#define PR_GetLibraryFilePathname VBoxNsprPR_GetLibraryFilePathname +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRLibrary PRLibrary; + +typedef struct PRStaticLinkTable { + const char *name; + void (*fp)(); +} PRStaticLinkTable; + +/* +** Change the default library path to the given string. The string is +** copied. This call will fail if it runs out of memory. +** +** The string provided as 'path' is copied. The caller can do whatever is +** convenient with the argument when the function is complete. +*/ +NSPR_API(PRStatus) PR_SetLibraryPath(const char *path); + +/* +** Return a character string which contains the path used to search for +** dynamically loadable libraries. +** +** The returned value is basically a copy of a PR_SetLibraryPath(). +** The storage is allocated by the runtime and becomes the responsibilty +** of the caller. +*/ +NSPR_API(char*) PR_GetLibraryPath(void); + +/* +** Given a directory name "dir" and a library name "lib" construct a full +** path name that will refer to the actual dynamically loaded +** library. This does not test for existance of said file, it just +** constructs the full filename. The name constructed is system dependent +** and prepared for PR_LoadLibrary. The result must be free'd when the +** caller is done with it. +** +** The storage for the result is allocated by the runtime and becomes the +** responsibility of the caller. +*/ +NSPR_API(char*) PR_GetLibraryName(const char *dir, const char *lib); + +/* +** +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +NSPR_API(void) PR_FreeLibraryName(char *mem); + +/* +** Given a library "name" try to load the library. The argument "name" +** is a machine-dependent name for the library, such as the full pathname +** returned by PR_GetLibraryName. If the library is already loaded, +** this function will avoid loading the library twice. +** +** If the library is loaded successfully, then a pointer to the PRLibrary +** structure representing the library is returned. Otherwise, NULL is +** returned. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadLibrary(const char *name); + +/* +** Each operating system has its preferred way of specifying +** a file in the file system. Most operating systems use +** a pathname. Mac OS, on the other hand, uses the FSSpec +** structure to specify a file. PRLibSpec allows NSPR clients +** to use the type of file specification that is most efficient +** for a particular platform. +** +** On some operating systems such as Mac OS, a shared library may +** contain code fragments that can be individually loaded. +** PRLibSpec also allows NSPR clients to identify a code fragment +** in a library, if code fragments are supported by the OS. +** A code fragment can be specified by name or by an integer index. +** +** Right now PRLibSpec supports three types of library specification: +** a pathname, a Mac code fragment by name, and a Mac code fragment +** by index. +*/ + +typedef enum PRLibSpecType { + PR_LibSpec_Pathname, + PR_LibSpec_MacNamedFragment, + PR_LibSpec_MacIndexedFragment +} PRLibSpecType; + +struct FSSpec; /* Mac OS FSSpec */ + +typedef struct PRLibSpec { + PRLibSpecType type; + union { + /* if type is PR_LibSpec_Pathname */ + const char *pathname; + + /* if type is PR_LibSpec_MacNamedFragment */ + struct { + const struct FSSpec *fsspec; + const char *name; + } mac_named_fragment; + + /* if type is PR_LibSpec_MacIndexedFragment */ + struct { + const struct FSSpec *fsspec; + PRUint32 index; + } mac_indexed_fragment; + } value; +} PRLibSpec; + +/* +** The following bit flags may be or'd together and passed +** as the 'flags' argument to PR_LoadLibraryWithFlags. +** Flags not supported by the underlying OS are ignored. +*/ + +#define PR_LD_LAZY 0x1 /* equivalent to RTLD_LAZY on Unix */ +#define PR_LD_NOW 0x2 /* equivalent to RTLD_NOW on Unix */ +#define PR_LD_GLOBAL 0x4 /* equivalent to RTLD_GLOBAL on Unix */ +#define PR_LD_LOCAL 0x8 /* equivalent to RTLD_LOCAL on Unix */ + +/* +** Load the specified library, in the manner specified by 'flags'. +*/ + +NSPR_API(PRLibrary *) +PR_LoadLibraryWithFlags( + PRLibSpec libSpec, /* the shared library */ + PRIntn flags /* flags that affect the loading */ +); + +/* +** Unload a previously loaded library. If the library was a static +** library then the static link table will no longer be referenced. The +** associated PRLibrary object is freed. +** +** PR_FAILURE is returned if the library cannot be unloaded. +** +** This function decrements the reference count of the library. +*/ +NSPR_API(PRStatus) PR_UnloadLibrary(PRLibrary *lib); + +/* +** Given the name of a procedure, return the address of the function that +** implements the procedure, or NULL if no such function can be +** found. This does not find symbols in the main program (the ".exe"); +** use PR_LoadStaticLibrary to register symbols in the main program. +** +** This function does not modify the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbol(PRLibrary *lib, const char *name); + +/* +** Similar to PR_FindSymbol, except that the return value is a pointer to +** a function, and not a pointer to void. Casting between a data pointer +** and a function pointer is not portable according to the C standard. +** Any function pointer can be cast to any other function pointer. +** +** This function does not modify the reference count of the library. +*/ +typedef void (*PRFuncPtr)(); +NSPR_API(PRFuncPtr) PR_FindFunctionSymbol(PRLibrary *lib, const char *name); + +/* +** Finds a symbol in one of the currently loaded libraries. Given the +** name of a procedure, return the address of the function that +** implements the procedure, and return the library that contains that +** symbol, or NULL if no such function can be found. This does not find +** symbols in the main program (the ".exe"); use PR_AddStaticLibrary to +** register symbols in the main program. +** +** This increments the reference count of the library. +*/ +NSPR_API(void*) PR_FindSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Similar to PR_FindSymbolAndLibrary, except that the return value is +** a pointer to a function, and not a pointer to void. Casting between a +** data pointer and a function pointer is not portable according to the C +** standard. Any function pointer can be cast to any other function pointer. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRFuncPtr) PR_FindFunctionSymbolAndLibrary(const char *name, + PRLibrary* *lib); + +/* +** Register a static link table with the runtime under the name +** "name". The symbols present in the static link table will be made +** available to PR_FindSymbol. If "name" is null then the symbols will be +** made available to the library which represents the executable. The +** tables are not copied. +** +** Returns the library object if successful, null otherwise. +** +** This increments the reference count of the library. +*/ +NSPR_API(PRLibrary*) PR_LoadStaticLibrary( + const char *name, const PRStaticLinkTable *table); + +/* +** Return the pathname of the file that the library "name" was loaded +** from. "addr" is the address of a function defined in the library. +** +** The caller is responsible for freeing the result with PR_Free. +*/ +NSPR_API(char *) PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr); + +PR_END_EXTERN_C + +#endif /* prlink_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prlock.h b/src/libs/xpcom18a4/nsprpub/pr/include/prlock.h new file mode 100644 index 00000000..0cf5aa55 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prlock.h @@ -0,0 +1,128 @@ +/* -*- 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 ***** */ + +/* +** File: prlock.h +** Description: API to basic locking functions of NSPR. +** +** +** NSPR provides basic locking mechanisms for thread synchronization. Locks +** are lightweight resource contention controls that prevent multiple threads +** from accessing something (code/data) simultaneously. +**/ + +#ifndef prlock_h___ +#define prlock_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_DestroyLock VBoxNsprPR_DestroyLock +#define PR_Lock VBoxNsprPR_Lock +#define PR_NewLock VBoxNsprPR_NewLock +#define PR_Unlock VBoxNsprPR_Unlock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +/* + * PRLock -- + * + * NSPR represents the lock as an opaque entity to the client of the + * API. All routines operate on a pointer to this opaque entity. + */ + +typedef struct PRLock PRLock; + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/*********************************************************************** +** FUNCTION: PR_NewLock +** DESCRIPTION: +** Returns a pointer to a newly created opaque lock object. +** INPUTS: void +** OUTPUTS: void +** RETURN: PRLock* +** If the lock can not be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRLock*) PR_NewLock(void); + +/*********************************************************************** +** FUNCTION: PR_DestroyLock +** DESCRIPTION: +** Destroys a given opaque lock object. +** INPUTS: PRLock *lock +** Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyLock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Lock +** DESCRIPTION: +** Lock a lock. +** INPUTS: PRLock *lock +** Lock to locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_Lock(PRLock *lock); + +/*********************************************************************** +** FUNCTION: PR_Unlock +** DESCRIPTION: +** Unlock a lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRLock *lock +** Lock to unlocked. +** OUTPUTS: void +** RETURN: PR_STATUS +** Returns PR_FAILURE if the caller does not own the lock. +***********************************************************************/ +NSPR_API(PRStatus) PR_Unlock(PRLock *lock); + +PR_END_EXTERN_C + +#endif /* prlock_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prlog.h b/src/libs/xpcom18a4/nsprpub/pr/include/prlog.h new file mode 100644 index 00000000..7f3369c6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prlog.h @@ -0,0 +1,265 @@ +/* -*- 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 prlog_h___ +#define prlog_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_NewLogModule VBoxNsprPR_NewLogModule +#define PR_SetLogFile VBoxNsprPR_SetLogFile +#define PR_SetLogBuffering VBoxNsprPR_SetLogBuffering +#define PR_LogPrint VBoxNsprPR_LogPrint +#define PR_LogFlush VBoxNsprPR_LogFlush +#define PR_Assert VBoxNsprPR_Assert +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** prlog.h -- Declare interfaces to NSPR's Logging service +** +** NSPR provides a logging service that is used by NSPR itself and is +** available to client programs. +** +** To use the service from a client program, you should create a +** PRLogModuleInfo structure by calling PR_NewLogModule(). After +** creating the LogModule, you can write to the log using the PR_LOG() +** macro. +** +** Initialization of the log service is handled by NSPR initialization. +** +** At execution time, you must enable the log service. To enable the +** log service, set the environment variable: NSPR_LOG_MODULES +** variable. +** +** NSPR_LOG_MODULES variable has the form: +** +** :[, :]* +** +** Where: +** is the name passed to PR_NewLogModule(). +** is a numeric constant, e.g. 5. This value is the maximum +** value of a log event, enumerated by PRLogModuleLevel, that you want +** written to the log. +** +** For example: to record all events of greater value than or equal to +** PR_LOG_ERROR for a LogModule names "gizmo", say: +** +** set NSPR_LOG_MODULES=gizmo:2 +** +** Note that you must specify the numeric value of PR_LOG_ERROR. +** +** Special LogModule names are provided for controlling NSPR's log +** service at execution time. These controls should be set in the +** NSPR_LOG_MODULES environment variable at execution time to affect +** NSPR's log service for your application. +** +** The special LogModule "all" enables all LogModules. To enable all +** LogModule calls to PR_LOG(), say: +** +** set NSPR_LOG_MODULES=all:5 +** +** The special LogModule name "sync" tells the NSPR log service to do +** unbuffered logging. +** +** The special LogModule name "bufsize:" tells NSPR to set the +** log buffer to . +** +** The environment variable NSPR_LOG_FILE specifies the log file to use +** unless the default of "stderr" is acceptable. For MS Windows +** systems, NSPR_LOG_FILE can be set to a special value: "WinDebug" +** (case sensitive). This value causes PR_LOG() output to be written +** using the Windows API OutputDebugString(). OutputDebugString() +** writes to the debugger window; some people find this helpful. +** +** +** To put log messages in your programs, use the PR_LOG macro: +** +** PR_LOG(, , (, *)); +** +** Where is the address of a PRLogModuleInfo structure, and +** is one of the levels defined by the enumeration: +** PRLogModuleLevel. is a printf() style of argument list. That +** is: (fmtstring, ...). +** +** Example: +** +** main() { +** PRIntn one = 1; +** PRLogModuleInfo * myLm = PR_NewLogModule("gizmo"); +** PR_LOG( myLm, PR_LOG_ALWAYS, ("Log this! %d\n", one)); +** return; +** } +** +** Note the use of printf() style arguments as the third agrument(s) to +** PR_LOG(). +** +** After compiling and linking you application, set the environment: +** +** set NSPR_LOG_MODULES=gizmo:5 +** set NSPR_LOG_FILE=logfile.txt +** +** When you execute your application, the string "Log this! 1" will be +** written to the file "logfile.txt". +** +** Note to NSPR engineers: a number of PRLogModuleInfo structures are +** defined and initialized in prinit.c. See this module for ideas on +** what to log where. +** +*/ + +typedef enum PRLogModuleLevel { + PR_LOG_NONE = 0, /* nothing */ + PR_LOG_ALWAYS = 1, /* always printed */ + PR_LOG_ERROR = 2, /* error messages */ + PR_LOG_WARNING = 3, /* warning messages */ + PR_LOG_DEBUG = 4, /* debug messages */ + + PR_LOG_NOTICE = PR_LOG_DEBUG, /* notice messages */ + PR_LOG_WARN = PR_LOG_WARNING, /* warning messages */ + PR_LOG_MIN = PR_LOG_DEBUG, /* minimal debugging messages */ + PR_LOG_MAX = PR_LOG_DEBUG /* maximal debugging messages */ +} PRLogModuleLevel; + +/* +** One of these structures is created for each module that uses logging. +** "name" is the name of the module +** "level" is the debugging level selected for that module +*/ +typedef struct PRLogModuleInfo { + const char *name; + PRLogModuleLevel level; + struct PRLogModuleInfo *next; +} PRLogModuleInfo; + +/* +** Create a new log module. +*/ +NSPR_API(PRLogModuleInfo*) PR_NewLogModule(const char *name); + +/* +** Set the file to use for logging. Returns PR_FALSE if the file cannot +** be created +*/ +NSPR_API(PRBool) PR_SetLogFile(const char *name); + +/* +** Set the size of the logging buffer. If "buffer_size" is zero then the +** logging becomes "synchronous" (or unbuffered). +*/ +NSPR_API(void) PR_SetLogBuffering(PRIntn buffer_size); + +/* +** Print a string to the log. "fmt" is a PR_snprintf format type. All +** messages printed to the log are preceeded by the name of the thread +** and a time stamp. Also, the routine provides a missing newline if one +** is not provided. +*/ +NSPR_API(void) PR_LogPrint(const char *fmt, ...); + +/* +** Flush the log to its file. +*/ +NSPR_API(void) PR_LogFlush(void); + +/* +** Windoze 16 can't support a large static string space for all of the +** various debugging strings so logging is not enabled for it. +*/ +#if (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) +#define PR_LOGGING 1 + +#define PR_LOG_TEST(_module,_level) \ + ((_module)->level >= (_level)) + +/* +** Log something. +** "module" is the address of a PRLogModuleInfo structure +** "level" is the desired logging level +** "args" is a variable length list of arguments to print, in the following +** format: ("printf style format string", ...) +*/ +#define PR_LOG(_module,_level,_args) \ + PR_BEGIN_MACRO \ + if (PR_LOG_TEST(_module,_level)) { \ + PR_LogPrint _args; \ + } \ + PR_END_MACRO + +#else /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */ + +#undef PR_LOGGING +#define PR_LOG_TEST(module,level) 0 +#define PR_LOG(module,level,args) + +#endif /* (defined(DEBUG) || defined(FORCE_PR_LOG)) && !defined(WIN16) */ + +#ifndef NO_NSPR_10_SUPPORT + +#ifdef PR_LOGGING +#define PR_LOG_BEGIN PR_LOG +#define PR_LOG_END PR_LOG +#define PR_LOG_DEFINE PR_NewLogModule +#else +#define PR_LOG_BEGIN(module,level,args) +#define PR_LOG_END(module,level,args) +#define PR_LOG_DEFINE(_name) NULL +#endif /* PR_LOGGING */ + +#endif /* NO_NSPR_10_SUPPORT */ + +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) + +NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln); +#define PR_ASSERT(_expr) \ + ((_expr)?((void)0):PR_Assert(# _expr,__FILE__,__LINE__)) + +#define PR_NOT_REACHED(_reasonStr) \ + PR_Assert(_reasonStr,__FILE__,__LINE__) + +#else + +#define PR_ASSERT(expr) ((void) 0) +#define PR_NOT_REACHED(reasonStr) + +#endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */ + +PR_END_EXTERN_C + +#endif /* prlog_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prlong.h b/src/libs/xpcom18a4/nsprpub/pr/include/prlong.h new file mode 100644 index 00000000..b99dd247 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prlong.h @@ -0,0 +1,440 @@ +/* -*- 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 ***** */ + +/* +** File: prlong.h +** Description: Portable access to 64 bit numerics +** +** Long-long (64-bit signed integer type) support. Some C compilers +** don't support 64 bit integers yet, so we use these macros to +** support both machines that do and don't. +**/ +#ifndef prlong_h___ +#define prlong_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define LL_MaxInt VBoxNsllLL_MaxInt +#define LL_MaxUint VBoxNsllLL_MaxUint +#define LL_MinInt VBoxNsllLL_MinInt +#define LL_Zero VBoxNsllLL_Zero +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/*********************************************************************** +** DEFINES: LL_MaxInt +** LL_MinInt +** LL_Zero +** LL_MaxUint +** DESCRIPTION: +** Various interesting constants and static variable +** initializer +***********************************************************************/ +#if defined(HAVE_WATCOM_BUG_2) +PRInt64 __pascal __loadds __export + LL_MaxInt(void); +PRInt64 __pascal __loadds __export + LL_MinInt(void); +PRInt64 __pascal __loadds __export + LL_Zero(void); +PRUint64 __pascal __loadds __export + LL_MaxUint(void); +#else +NSPR_API(PRInt64) LL_MaxInt(void); +NSPR_API(PRInt64) LL_MinInt(void); +NSPR_API(PRInt64) LL_Zero(void); +NSPR_API(PRUint64) LL_MaxUint(void); +#endif + +#define LL_MAXINT LL_MaxInt() +#define LL_MININT LL_MinInt() +#define LL_ZERO LL_Zero() +#define LL_MAXUINT LL_MaxUint() + +#if defined(HAVE_LONG_LONG) + +#if PR_BYTES_PER_LONG == 8 +#define LL_INIT(hi, lo) ((hi ## L << 32) + lo ## L) +#elif (defined(WIN32) || defined(WIN16)) && !defined(__GNUC__) +#define LL_INIT(hi, lo) ((hi ## i64 << 32) + lo ## i64) +#else +#define LL_INIT(hi, lo) ((hi ## LL << 32) + lo ## LL) +#endif + +/*********************************************************************** +** MACROS: LL_* +** DESCRIPTION: +** The following macros define portable access to the 64 bit +** math facilities. +** +***********************************************************************/ + +/*********************************************************************** +** MACROS: LL_ +** +** LL_IS_ZERO Test for zero +** LL_EQ Test for equality +** LL_NE Test for inequality +** LL_GE_ZERO Test for zero or positive +** LL_CMP Compare two values +***********************************************************************/ +#define LL_IS_ZERO(a) ((a) == 0) +#define LL_EQ(a, b) ((a) == (b)) +#define LL_NE(a, b) ((a) != (b)) +#define LL_GE_ZERO(a) ((a) >= 0) +#define LL_CMP(a, op, b) ((PRInt64)(a) op (PRInt64)(b)) +#define LL_UCMP(a, op, b) ((PRUint64)(a) op (PRUint64)(b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_AND Logical and +** LL_OR Logical or +** LL_XOR Logical exclusion +** LL_OR2 A disgusting deviation +** LL_NOT Negation (one's complement) +***********************************************************************/ +#define LL_AND(r, a, b) ((r) = (a) & (b)) +#define LL_OR(r, a, b) ((r) = (a) | (b)) +#define LL_XOR(r, a, b) ((r) = (a) ^ (b)) +#define LL_OR2(r, a) ((r) = (r) | (a)) +#define LL_NOT(r, a) ((r) = ~(a)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_NEG Negation (two's complement) +** LL_ADD Summation (two's complement) +** LL_SUB Difference (two's complement) +***********************************************************************/ +#define LL_NEG(r, a) ((r) = -(a)) +#define LL_ADD(r, a, b) ((r) = (a) + (b)) +#define LL_SUB(r, a, b) ((r) = (a) - (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_MUL Product (two's complement) +** LL_DIV Quotient (two's complement) +** LL_MOD Modulus (two's complement) +***********************************************************************/ +#define LL_MUL(r, a, b) ((r) = (a) * (b)) +#define LL_DIV(r, a, b) ((r) = (a) / (b)) +#define LL_MOD(r, a, b) ((r) = (a) % (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_SHL Shift left [0..64] bits +** LL_SHR Shift right [0..64] bits with sign extension +** LL_USHR Unsigned shift right [0..64] bits +** LL_ISHL Signed shift left [0..64] bits +***********************************************************************/ +#define LL_SHL(r, a, b) ((r) = (PRInt64)(a) << (b)) +#define LL_SHR(r, a, b) ((r) = (PRInt64)(a) >> (b)) +#define LL_USHR(r, a, b) ((r) = (PRUint64)(a) >> (b)) +#define LL_ISHL(r, a, b) ((r) = (PRInt64)(a) << (b)) + +/*********************************************************************** +** MACROS: LL_ +** +** LL_L2I Convert to signed 32 bit +** LL_L2UI Convert to unsigned 32 bit +** LL_L2F Convert to floating point +** LL_L2D Convert to floating point +** LL_I2L Convert signed to 64 bit +** LL_UI2L Convert unsigned to 64 bit +** LL_F2L Convert float to 64 bit +** LL_D2L Convert float to 64 bit +***********************************************************************/ +#define LL_L2I(i, l) ((i) = (PRInt32)(l)) +#define LL_L2UI(ui, l) ((ui) = (PRUint32)(l)) +#define LL_L2F(f, l) ((f) = (PRFloat64)(l)) +#define LL_L2D(d, l) ((d) = (PRFloat64)(l)) + +#define LL_I2L(l, i) ((l) = (PRInt64)(i)) +#define LL_UI2L(l, ui) ((l) = (PRInt64)(ui)) +#define LL_F2L(l, f) ((l) = (PRInt64)(f)) +#define LL_D2L(l, d) ((l) = (PRInt64)(d)) + +/*********************************************************************** +** MACROS: LL_UDIVMOD +** DESCRIPTION: +** Produce both a quotient and a remainder given an unsigned +** INPUTS: PRUint64 a: The dividend of the operation +** PRUint64 b: The quotient of the operation +** OUTPUTS: PRUint64 *qp: pointer to quotient +** PRUint64 *rp: pointer to remainder +***********************************************************************/ +#define LL_UDIVMOD(qp, rp, a, b) \ + (*(qp) = ((PRUint64)(a) / (b)), \ + *(rp) = ((PRUint64)(a) % (b))) + +#else /* !HAVE_LONG_LONG */ + +#ifdef IS_LITTLE_ENDIAN +#define LL_INIT(hi, lo) {PR_UINT32(lo), PR_UINT32(hi)} +#else +#define LL_INIT(hi, lo) {PR_UINT32(hi), PR_UINT32(lo)} +#endif + +#define LL_IS_ZERO(a) (((a).hi == 0) && ((a).lo == 0)) +#define LL_EQ(a, b) (((a).hi == (b).hi) && ((a).lo == (b).lo)) +#define LL_NE(a, b) (((a).hi != (b).hi) || ((a).lo != (b).lo)) +#define LL_GE_ZERO(a) (((a).hi >> 31) == 0) + +#define LL_CMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((PRInt32)(a).hi op (PRInt32)(b).hi)) +#define LL_UCMP(a, op, b) (((a).hi == (b).hi) ? ((a).lo op (b).lo) : \ + ((a).hi op (b).hi)) + +#define LL_AND(r, a, b) ((r).lo = (a).lo & (b).lo, \ + (r).hi = (a).hi & (b).hi) +#define LL_OR(r, a, b) ((r).lo = (a).lo | (b).lo, \ + (r).hi = (a).hi | (b).hi) +#define LL_XOR(r, a, b) ((r).lo = (a).lo ^ (b).lo, \ + (r).hi = (a).hi ^ (b).hi) +#define LL_OR2(r, a) ((r).lo = (r).lo | (a).lo, \ + (r).hi = (r).hi | (a).hi) +#define LL_NOT(r, a) ((r).lo = ~(a).lo, \ + (r).hi = ~(a).hi) + +#define LL_NEG(r, a) ((r).lo = -(PRInt32)(a).lo, \ + (r).hi = -(PRInt32)(a).hi - ((r).lo != 0)) +#define LL_ADD(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo + _b.lo; \ + (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo); \ +} + +#define LL_SUB(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + (r).lo = _a.lo - _b.lo; \ + (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo); \ +} + +#define LL_MUL(r, a, b) { \ + PRInt64 _a, _b; \ + _a = a; _b = b; \ + LL_MUL32(r, _a.lo, _b.lo); \ + (r).hi += _a.hi * _b.lo + _a.lo * _b.hi; \ +} + +#define _lo16(a) ((a) & PR_BITMASK(16)) +#define _hi16(a) ((a) >> 16) + +#define LL_MUL32(r, a, b) { \ + PRUint32 _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3; \ + _a1 = _hi16(a), _a0 = _lo16(a); \ + _b1 = _hi16(b), _b0 = _lo16(b); \ + _y0 = _a0 * _b0; \ + _y1 = _a0 * _b1; \ + _y2 = _a1 * _b0; \ + _y3 = _a1 * _b1; \ + _y1 += _hi16(_y0); /* can't carry */ \ + _y1 += _y2; /* might carry */ \ + if (_y1 < _y2) \ + _y3 += (PRUint32)(PR_BIT(16)); /* propagate */ \ + (r).lo = (_lo16(_y1) << 16) + _lo16(_y0); \ + (r).hi = _y3 + _hi16(_y1); \ +} + +#define LL_UDIVMOD(qp, rp, a, b) ll_udivmod(qp, rp, a, b) + +NSPR_API(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b); + +#define LL_DIV(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + _negative ^= 1; \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(&(r), 0, _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_MOD(r, a, b) { \ + PRInt64 _a, _b; \ + PRUint32 _negative = (PRInt32)(a).hi < 0; \ + if (_negative) { \ + LL_NEG(_a, a); \ + } else { \ + _a = a; \ + } \ + if ((PRInt32)(b).hi < 0) { \ + LL_NEG(_b, b); \ + } else { \ + _b = b; \ + } \ + LL_UDIVMOD(0, &(r), _a, _b); \ + if (_negative) \ + LL_NEG(r, r); \ +} + +#define LL_SHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = _a.lo << ((b) & 31); \ + (r).hi = (_a.hi << ((b) & 31)) | (_a.lo >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = _a.lo << ((b) & 31); \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +/* a is an PRInt32, b is PRInt32, r is PRInt64 */ +#define LL_ISHL(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a.lo = (a); \ + _a.hi = 0; \ + if ((b) < 32) { \ + (r).lo = (a) << ((b) & 31); \ + (r).hi = ((a) >> (32 - (b))); \ + } else { \ + (r).lo = 0; \ + (r).hi = (a) << ((b) & 31); \ + } \ + } else { \ + (r).lo = (a); \ + (r).hi = 0; \ + } \ +} + +#define LL_SHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = (PRInt32)_a.hi >> ((b) & 31); \ + } else { \ + (r).lo = (PRInt32)_a.hi >> ((b) & 31); \ + (r).hi = (PRInt32)_a.hi >> 31; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_USHR(r, a, b) { \ + if (b) { \ + PRInt64 _a; \ + _a = a; \ + if ((b) < 32) { \ + (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> ((b) & 31)); \ + (r).hi = _a.hi >> ((b) & 31); \ + } else { \ + (r).lo = _a.hi >> ((b) & 31); \ + (r).hi = 0; \ + } \ + } else { \ + (r) = (a); \ + } \ +} + +#define LL_L2I(i, l) ((i) = (l).lo) +#define LL_L2UI(ui, l) ((ui) = (l).lo) +#define LL_L2F(f, l) { double _d; LL_L2D(_d, l); (f) = (PRFloat64)_d; } + +#define LL_L2D(d, l) { \ + int _negative; \ + PRInt64 _absval; \ + \ + _negative = (l).hi >> 31; \ + if (_negative) { \ + LL_NEG(_absval, l); \ + } else { \ + _absval = l; \ + } \ + (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo; \ + if (_negative) \ + (d) = -(d); \ +} + +#define LL_I2L(l, i) { PRInt32 _i = ((PRInt32)(i)) >> 31; (l).lo = (i); (l).hi = _i; } +#define LL_UI2L(l, ui) ((l).lo = (ui), (l).hi = 0) +#define LL_F2L(l, f) { double _d = (double)f; LL_D2L(l, _d); } + +#define LL_D2L(l, d) { \ + int _negative; \ + double _absval, _d_hi; \ + PRInt64 _lo_d; \ + \ + _negative = ((d) < 0); \ + _absval = _negative ? -(d) : (d); \ + \ + (l).hi = _absval / 4.294967296e9; \ + (l).lo = 0; \ + LL_L2D(_d_hi, l); \ + _absval -= _d_hi; \ + _lo_d.hi = 0; \ + if (_absval < 0) { \ + _lo_d.lo = -_absval; \ + LL_SUB(l, l, _lo_d); \ + } else { \ + _lo_d.lo = _absval; \ + LL_ADD(l, l, _lo_d); \ + } \ + \ + if (_negative) \ + LL_NEG(l, l); \ +} + +#endif /* !HAVE_LONG_LONG */ + +PR_END_EXTERN_C + +#endif /* prlong_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prmem.h b/src/libs/xpcom18a4/nsprpub/pr/include/prmem.h new file mode 100644 index 00000000..de4d15fd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prmem.h @@ -0,0 +1,166 @@ +/* -*- 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 ***** */ + +/* +** File: prmem.h +** Description: API to NSPR 2.0 memory management functions +** +*/ +#ifndef prmem_h___ +#define prmem_h___ + +#include "prtypes.h" +#include +#include + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_Malloc VBoxNsprPR_Malloc +#define PR_Calloc VBoxNsprPR_Calloc +#define PR_Realloc VBoxNsprPR_Realloc +#define PR_Free VBoxNsprPR_Free +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Thread safe memory allocation. +** +** NOTE: pr wraps up malloc, free, calloc, realloc so they are already +** thread safe (and are not declared here - look in stdlib.h). +*/ + +/* +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free have the same signatures +** as their libc equivalent malloc, calloc, realloc, and free, and have +** the same semantics. (Note that the argument type size_t is replaced +** by PRUint32.) Memory allocated by PR_Malloc, PR_Calloc, or PR_Realloc +** must be freed by PR_Free. +*/ + +NSPR_API(void *) PR_Malloc(PRUint32 size); + +NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize); + +NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size); + +NSPR_API(void) PR_Free(void *ptr); + +/* +** The following are some convenience macros defined in terms of +** PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free. +*/ + +/*********************************************************************** +** FUNCTION: PR_MALLOC() +** DESCRIPTION: +** PR_NEW() allocates an untyped item of size _size from the heap. +** INPUTS: _size: size in bytes of item to be allocated +** OUTPUTS: untyped pointer to the node allocated +** RETURN: pointer to node or error returned from malloc(). +***********************************************************************/ +#define PR_MALLOC(_bytes) (PR_Malloc((_bytes))) + +/*********************************************************************** +** FUNCTION: PR_NEW() +** DESCRIPTION: +** PR_NEW() allocates an item of type _struct from the heap. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct or error returns from malloc(). +***********************************************************************/ +#define PR_NEW(_struct) ((_struct *) PR_MALLOC(sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_REALLOC() +** DESCRIPTION: +** PR_REALLOC() re-allocates _ptr bytes from the heap as a _size +** untyped item. +** INPUTS: _ptr: pointer to node to reallocate +** _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_REALLOC(_ptr, _size) (PR_Realloc((_ptr), (_size))) + +/*********************************************************************** +** FUNCTION: PR_CALLOC() +** DESCRIPTION: +** PR_CALLOC() allocates a _size bytes untyped item from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _size: size of node to allocate +** OUTPUTS: pointer to node allocated +** RETURN: pointer to node allocated +***********************************************************************/ +#define PR_CALLOC(_size) (PR_Calloc(1, (_size))) + +/*********************************************************************** +** FUNCTION: PR_NEWZAP() +** DESCRIPTION: +** PR_NEWZAP() allocates an item of type _struct from the heap +** and sets the allocated memory to all 0x00. +** INPUTS: _struct: a data type +** OUTPUTS: pointer to _struct +** RETURN: pointer to _struct +***********************************************************************/ +#define PR_NEWZAP(_struct) ((_struct*)PR_Calloc(1, sizeof(_struct))) + +/*********************************************************************** +** FUNCTION: PR_DELETE() +** DESCRIPTION: +** PR_DELETE() unallocates an object previosly allocated via PR_NEW() +** or PR_NEWZAP() to the heap. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_DELETE(_ptr) { PR_Free(_ptr); (_ptr) = NULL; } + +/*********************************************************************** +** FUNCTION: PR_FREEIF() +** DESCRIPTION: +** PR_FREEIF() conditionally unallocates an object previously allocated +** vial PR_NEW() or PR_NEWZAP(). If the pointer to the object is +** equal to zero (0), the object is not released. +** INPUTS: pointer to previously allocated object +** OUTPUTS: the referenced object is conditionally returned to the heap +** RETURN: void +***********************************************************************/ +#define PR_FREEIF(_ptr) if (_ptr) PR_DELETE(_ptr) + +PR_END_EXTERN_C + +#endif /* prmem_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prmon.h b/src/libs/xpcom18a4/nsprpub/pr/include/prmon.h new file mode 100644 index 00000000..ac317708 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prmon.h @@ -0,0 +1,123 @@ +/* -*- 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 prmon_h___ +#define prmon_h___ + +#include "prtypes.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_EnterMonitor VBoxNsprPR_EnterMonitor +#define PR_ExitMonitor VBoxNsprPR_ExitMonitor +#define PR_Notify VBoxNsprPR_Notify +#define PR_NotifyAll VBoxNsprPR_NotifyAll +#define PR_Wait VBoxNsprPR_Wait +#define PR_NewMonitor VBoxNsprPR_NewMonitor +#define PR_DestroyMonitor VBoxNsprPR_DestroyMonitor +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRMonitor PRMonitor; + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +NSPR_API(PRMonitor*) PR_NewMonitor(void); + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the monitor's +** condition variable and that the lock is not held. +** +*/ +NSPR_API(void) PR_DestroyMonitor(PRMonitor *mon); + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +NSPR_API(void) PR_EnterMonitor(PRMonitor *mon); + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_ExitMonitor(PRMonitor *mon); + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +NSPR_API(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks); + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +NSPR_API(PRStatus) PR_Notify(PRMonitor *mon); + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +NSPR_API(PRStatus) PR_NotifyAll(PRMonitor *mon); + +PR_END_EXTERN_C + +#endif /* prmon_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prmwait.h b/src/libs/xpcom18a4/nsprpub/pr/include/prmwait.h new file mode 100644 index 00000000..e116b17a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prmwait.h @@ -0,0 +1,424 @@ +/* -*- 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 ***** */ + +#if defined(_PRMWAIT_H) +#else +#define _PRMWAIT_H + +#include "prio.h" +#include "prtypes.h" +#include "prclist.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_AddWaitFileDesc VBoxNsprPR_AddWaitFileDesc +#define PR_CancelWaitFileDesc VBoxNsprPR_CancelWaitFileDesc +#define PR_CancelWaitGroup VBoxNsprPR_CancelWaitGroup +#define PR_CreateWaitGroup VBoxNsprPR_CreateWaitGroup +#define PR_CreateMWaitEnumerator VBoxNsprPR_CreateMWaitEnumerator +#define PR_DestroyWaitGroup VBoxNsprPR_DestroyWaitGroup +#define PR_DestroyMWaitEnumerator VBoxNsprPR_DestroyMWaitEnumerator +#define PR_EnumerateWaitGroup VBoxNsprPR_EnumerateWaitGroup +#define PR_WaitRecvReady VBoxNsprPR_WaitRecvReady +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/********************************************************************************/ +/********************************************************************************/ +/********************************************************************************/ +/****************************** WARNING ****************************/ +/********************************************************************************/ +/**************************** This is work in progress. *************************/ +/************************** Do not make any assumptions *************************/ +/************************** about the stability of this *************************/ +/************************** API or the underlying imple- ************************/ +/************************** mentation. ************************/ +/********************************************************************************/ +/********************************************************************************/ + +/* +** STRUCTURE: PRWaitGroup +** DESCRIPTION: +** The client may define several wait groups in order to semantically +** tie a collection of file descriptors for a single purpose. This allows +** easier dispatching of threads that returned with active file descriptors +** from the wait function. +*/ +typedef struct PRWaitGroup PRWaitGroup; + +/* +** ENUMERATION: PRMWStatus +** DESCRIPTION: +** This enumeration is used to indicate the completion status of +** a receive wait object. Generally stated, a positive value indicates +** that the operation is not yet complete. A zero value indicates +** success (similar to PR_SUCCESS) and any negative value is an +** indication of failure. The reason for the failure can be retrieved +** by calling PR_GetError(). +** +** PR_MW_PENDING The operation is still pending. None of the other +** fields of the object are currently valid. +** PR_MW_SUCCESS The operation is complete and it was successful. +** PR_MW_FAILURE The operation failed. The reason for the failure +** can be retrieved by calling PR_GetError(). +** PR_MW_TIMEOUT The amount of time allowed for by the object's +** 'timeout' field has expired w/o the operation +** otherwise coming to closure. +** PR_MW_INTERRUPT The operation was cancelled, either by the client +** calling PR_CancelWaitFileDesc() or destroying the +** entire wait group (PR_DestroyWaitGroup()). +*/ +typedef enum PRMWStatus +{ + PR_MW_PENDING = 1, + PR_MW_SUCCESS = 0, + PR_MW_FAILURE = -1, + PR_MW_TIMEOUT = -2, + PR_MW_INTERRUPT = -3 +} PRMWStatus; + +/* +** STRUCTURE: PRMemoryDescriptor +** DESCRIPTION: +** THis is a descriptor for an interval of memory. It contains a +** pointer to the first byte of that memory and the length (in +** bytes) of the interval. +*/ +typedef struct PRMemoryDescriptor +{ + void *start; /* pointer to first byte of memory */ + PRSize length; /* length (in bytes) of memory interval */ +} PRMemoryDescriptor; + +/* +** STRUCTURE: PRMWaitClientData +** DESCRIPTION: +** An opague stucture for which a client MAY give provide a concrete +** definition and associate with a receive descriptor. The NSPR runtime +** does not manage this field. It is completely up to the client. +*/ +typedef struct PRMWaitClientData PRMWaitClientData; + +/* +** STRUCTURE: PRRecvWait +** DESCRIPTION: +** A receive wait object contains the file descriptor that is subject +** to the wait and the amount of time (beginning epoch established +** when the object is presented to the runtime) the the channel should +** block before abandoning the process. +** +** The success of the wait operation will be noted in the object's +** 'outcome' field. The fields are not valid when the NSPR runtime +** is in possession of the object. +** +** The memory descriptor describes an interval of writable memory +** in the caller's address space where data from an initial read +** can be placed. The description may indicate a null interval. +*/ +typedef struct PRRecvWait +{ + PRCList internal; /* internal runtime linkages */ + + PRFileDesc *fd; /* file descriptor associated w/ object */ + PRMWStatus outcome; /* outcome of the current/last operation */ + PRIntervalTime timeout; /* time allowed for entire operation */ + + PRInt32 bytesRecv; /* number of bytes transferred into buffer */ + PRMemoryDescriptor buffer; /* where to store first segment of input data */ + PRMWaitClientData *client; /* pointer to arbitrary client defined data */ +} PRRecvWait; + +/* +** STRUCTURE: PRMWaitEnumerator +** DESCRIPTION: +** An enumeration object is used to store the state of an existing +** enumeration over a wait group. The opaque object must be allocated +** by the client and the reference presented on each call to the +** pseudo-stateless enumerator. The enumeration objects are sharable +** only in serial fashion. +*/ +typedef struct PRMWaitEnumerator PRMWaitEnumerator; + + +/* +** FUNCTION: PR_AddWaitFileDesc +** DESCRIPTION: +** This function will effectively add a file descriptor to the +** list of those waiting for network receive. The new descriptor +** will be semantically tied to the wait group specified. +** +** The ownership for the storage pointed to by 'desc' is temporarily +** passed over the the NSPR runtime. It will be handed back by the +** function PR_WaitRecvReady(). +** +** INPUTS +** group A reference to a PRWaitGroup or NULL. Wait groups are +** created by calling PR_CreateWaitGroup() and are used +** to semantically group various file descriptors by the +** client's application. +** desc A reference to a valid PRRecvWait. The object of the +** reference must be preserved and not be modified +** until its ownership is returned to the client. +** RETURN +** PRStatus An indication of success. If equal to PR_FAILUE details +** of the failure are avaiable via PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** Invalid 'group' identifier or duplicate 'desc' object. +** PR_OUT_OF_MEMORY_ERROR +** Insuffient memory for internal data structures. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_AddWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_WaitRecvReady +** DESCRIPTION: +** PR_WaitRecvReady will block the calling thread until one of the +** file descriptors that have been added via PR_AddWaitFileDesc is +** available for input I/O. +** INPUT +** group A pointer to a valid PRWaitGroup or NULL (the null +** group. The function will block the caller until a +** channel from the wait group becomes ready for receive +** or there is some sort of error. +** RETURN +** PRReciveWait +** When the caller is resumed it is either returned a +** valid pointer to a previously added receive wait or +** a NULL. If the latter, the function has terminated +** for a reason that can be determined by calling +** PR_GetError(). +** If a valid pointer is returned, the reference is to the +** file descriptor contained in the receive wait object. +** The outcome of the wait operation may still fail, and +** if it has, that fact will be noted in the object's +** outcome field. Details can be retrieved from PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' is not known by the runtime. +** PR_PENDING_INTERRUPT_ERROR + The thread was interrupted. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group); + +/* +** FUNCTION: PR_CancelWaitFileDesc +** DESCRIPTION: +** PR_CancelWaitFileDesc is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). If +** the runtime knows of the object, it will be marked as having failed +** because it was interrupted (similar to PR_Interrupt()). The first +** available thread waiting on the group will be made to return the +** PRRecvWait object with the outcome noted. +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** desc A pointer to the wait receive object that is to be +** cancelled. +** RETURN +** PRStatus If the wait receive object was located and associated +** with the specified wait group, the status returned will +** be PR_SUCCESS. There is still a race condition that would +** permit the offected object to complete normally, but it +** is assured that it will complete in the near future. +** If the receive object or wait group are invalid, the +** function will return with a status of PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument is not recognized as a valid group. +** PR_COLLECTION_EMPTY_ERROR +** There are no more receive wait objects in the group's +** collection. +** PR_INVALID_STATE_ERROR +** The group is being destroyed. +*/ +NSPR_API(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc); + +/* +** FUNCTION: PR_CancelWaitGroup +** DESCRIPTION: +** PR_CancelWaitGroup is provided as a means for cancelling operations +** on objects previously submitted by use of PR_AddWaitFileDesc(). Each +** successive call will return a pointer to a PRRecvWait object that +** was previously registered via PR_AddWaitFileDesc(). If no wait +** objects are associated with the wait group, a NULL will be returned. +** This function should be called in a loop until a NULL is returned +** to reclaim all the wait objects prior to calling PR_DestroyWaitGroup(). +** +** INPUTS +** group The wait group under which the wait receive object was +** added. +** RETURN +** PRRecvWait* If the wait group is valid and at least one receive wait +** object is present in the group, that object will be +** marked as PR_MW_INTERRUPT'd and removed from the group's +** queues. Otherwise a NULL will be returned and the reason +** for the NULL may be retrieved by calling PR_GetError(). +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** PR_GROUP_EMPTY_ERROR +*/ +NSPR_API(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateWaitGroup +** DESCRIPTION: +** A wait group is an opaque object that a client may create in order +** to semantically group various wait requests. Each wait group is +** unique, including the default wait group (NULL). A wait request +** that was added under a wait group will only be serviced by a caller +** that specified the same wait group. +** +** INPUT +** size The size of the hash table to be used to contain the +** receive wait objects. This is just the initial size. +** It will grow as it needs to, but to avoid that hassle +** one can suggest a suitable size initially. It should +** be ~30% larger than the maximum number of receive wait +** objects expected. +** RETURN +** PRWaitGroup If successful, the function will return a pointer to an +** object that was allocated by and owned by the runtime. +** The reference remains valid until it is explicitly destroyed +** by calling PR_DestroyWaitGroup(). +** +** ERRORS +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size); + +/* +** FUNCTION: PR_DestroyWaitGroup +** DESCRIPTION: +** Undo the effects of PR_CreateWaitGroup(). Any receive wait operations +** on the group will be treated as if the each had been the target of a +** PR_CancelWaitFileDesc(). +** +** INPUT +** group Reference to a wait group previously allocated using +** PR_CreateWaitGroup(). +** RETURN +** PRStatus Will be PR_SUCCESS if the wait group was valid and there +** are no receive wait objects in that group. Otherwise +** will indicate PR_FAILURE. +** +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_INVALID_STATE_ERROR +** The group still contains receive wait objects. +*/ +NSPR_API(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group); + +/* +** FUNCTION: PR_CreateMWaitEnumerator +** DESCRIPTION: +** The PR_CreateMWaitEnumerator() function returns a reference to an +** opaque PRMWaitEnumerator object. The enumerator object is required +** as an argument for each successive call in the stateless enumeration +** of the indicated wait group. +** +** group The wait group that the enumeration is intended to +** process. It may be be the default wait group (NULL). +** RETURN +** PRMWaitEnumerator* group +** A reference to an object that will be used to store +** intermediate state of enumerations. +** ERRORS +** Errors are indicated by the function returning a NULL. +** PR_INVALID_ARGUMENT_ERROR +** The 'group' argument does not reference a known object. +** PR_OUT_OF_MEMORY_ERROR +*/ +NSPR_API(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group); + +/* +** FUNCTION: PR_DestroyMWaitEnumerator +** DESCRIPTION: +** Destroys the object created by PR_CreateMWaitEnumerator(). The reference +** used as an argument becomes invalid. +** +** INPUT +** PRMWaitEnumerator* enumerator +** The PRMWaitEnumerator object to destroy. +** RETURN +** PRStatus +** PR_SUCCESS if successful, PR_FAILURE otherwise. +** ERRORS +** PR_INVALID_ARGUMENT_ERROR +** The enumerator is invalid. +*/ +NSPR_API(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator); + +/* +** FUNCTION: PR_EnumerateWaitGroup +** DESCRIPTION: +** PR_EnumerateWaitGroup is a thread safe enumerator over a wait group. +** Each call to the enumerator must present a valid PRMWaitEnumerator +** rererence and a pointer to the "previous" element returned from the +** enumeration process or a NULL. +** +** An enumeration is started by passing a NULL as the "previous" value. +** Subsequent calls to the enumerator must pass in the result of the +** previous call. The enumeration end is signaled by the runtime returning +** a NULL as the result. +** +** Modifications to the content of the wait group are allowed during +** an enumeration. The effect is that the enumeration may have to be +** "reset" and that may result in duplicates being returned from the +** enumeration. +** +** An enumeration may be abandoned at any time. The runtime is not +** keeping any state, so there are no issues in that regard. +*/ +NSPR_API(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous); + +PR_END_EXTERN_C + +#endif /* defined(_PRMWAIT_H) */ + +/* prmwait.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prnetdb.h b/src/libs/xpcom18a4/nsprpub/pr/include/prnetdb.h new file mode 100644 index 00000000..bd9a9eff --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prnetdb.h @@ -0,0 +1,524 @@ +/* -*- 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 prnetdb_h___ +#define prnetdb_h___ + +#include "prtypes.h" +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_StringToNetAddr VBoxNsprPR_StringToNetAddr +#define PR_NetAddrToString VBoxNsprPR_NetAddrToString +#define PR_GetHostByName VBoxNsprPR_GetHostByName +#define PR_GetIPNodeByName VBoxNsprPR_GetIPNodeByName +#define PR_GetHostByAddr VBoxNsprPR_GetHostByAddr +#define PR_EnumerateHostEnt VBoxNsprPR_EnumerateHostEnt +#define PR_InitializeNetAddr VBoxNsprPR_InitializeNetAddr +#define PR_SetNetAddr VBoxNsprPR_SetNetAddr +#define PR_IsNetAddrType VBoxNsprPR_IsNetAddrType +#define PR_ConvertIPv4AddrToIPv6 VBoxNsprPR_ConvertIPv4AddrToIPv6 +#define PR_GetProtoByName VBoxNsprPR_GetProtoByName +#define PR_GetProtoByNumber VBoxNsprPR_GetProtoByNumber +#define PR_GetAddrInfoByName VBoxNsprPR_GetAddrInfoByName +#define PR_FreeAddrInfo VBoxNsprPR_FreeAddrInfo +#define PR_EnumerateAddrInfo VBoxNsprPR_EnumerateAddrInfo +#define PR_GetCanonNameFromAddrInfo VBoxNsprPR_GetCanonNameFromAddrInfo +#define PR_htonl VBoxNsprPR_htonl +#define PR_htonll VBoxNsprPR_htonll +#define PR_htons VBoxNsprPR_htons +#define PR_ntohl VBoxNsprPR_ntohl +#define PR_ntohll VBoxNsprPR_ntohll +#define PR_ntohs VBoxNsprPR_ntohs +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + + +/* + ********************************************************************* + * Translate an Internet address to/from a character string + ********************************************************************* + */ +NSPR_API(PRStatus) PR_StringToNetAddr( + const char *string, PRNetAddr *addr); + +NSPR_API(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size); + +/* +** Structures returned by network data base library. All addresses are +** supplied in host order, and returned in network order (suitable for +** use in system calls). +*/ +/* +** Beware that WINSOCK.H defines h_addrtype and h_length as short. +** Client code does direct struct copies of hostent to PRHostEnt and +** hence the ifdef. +*/ +typedef struct PRHostEnt { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ +#if defined(WIN32) || defined(WIN16) + PRInt16 h_addrtype; /* host address type */ + PRInt16 h_length; /* length of address */ +#else + PRInt32 h_addrtype; /* host address type */ + PRInt32 h_length; /* length of address */ +#endif + char **h_addr_list; /* list of addresses from name server */ +} PRHostEnt; + +/* A safe size to use that will mostly work... */ +#if (defined(AIX) && defined(_THREAD_SAFE)) || defined(OSF1) +#define PR_NETDB_BUF_SIZE sizeof(struct protoent_data) +#else +#define PR_NETDB_BUF_SIZE 1024 +#endif + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByName() +** Lookup a host by name. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByName( + const char *hostname, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetIPNodeByName() +** Lookup a host by name. Equivalent to getipnodebyname(AI_DEFAULT) +** of RFC 2553. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af Address family (either PR_AF_INET or PR_AF_INET6) +** PRIntn flags Specifies the types of addresses that are searched +** for and the types of addresses that are returned. +** The only supported flag is PR_AI_DEFAULT. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + + +#define PR_AI_ALL 0x08 +#define PR_AI_V4MAPPED 0x10 +#define PR_AI_ADDRCONFIG 0x20 +#define PR_AI_NOCANONNAME 0x8000 +#define PR_AI_DEFAULT (PR_AI_V4MAPPED | PR_AI_ADDRCONFIG) + +NSPR_API(PRStatus) PR_GetIPNodeByName( + const char *hostname, + PRUint16 af, + PRIntn flags, + char *buf, + PRIntn bufsize, + PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetHostByAddr() +** Lookup a host entry by its network address. +** +** INPUTS: +** char *hostaddr IP address of host in question +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *hostentry +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry); + +/*********************************************************************** +** FUNCTION: PR_EnumerateHostEnt() +** DESCRIPTION: +** A stateless enumerator over a PRHostEnt structure acquired from +** PR_GetHostByName() PR_GetHostByAddr() to evaluate the possible +** network addresses. +** +** INPUTS: +** PRIntn enumIndex Index of the enumeration. The enumeration starts +** and ends with a value of zero. +** +** PRHostEnt *hostEnt A pointer to a host entry struct that was +** previously returned by PR_GetHostByName() or +** PR_GetHostByAddr(). +** +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** +** OUTPUTS: +** PRNetAddr *address A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** +** RETURN: +** PRIntn The value that should be used for the next call +** of the enumerator ('enumIndex'). The enumeration +** is ended if this value is returned zero. +** If a value of -1 is returned, the enumeration +** has failed. The reason for the failure can be +** retrieved by calling PR_GetError(). +***********************************************************************/ +NSPR_API(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address); + +/*********************************************************************** +** FUNCTION: PR_InitializeNetAddr(), +** DESCRIPTION: +** Initialize the fields of a PRNetAddr, assigning well known values as +** appropriate. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +typedef enum PRNetAddrValue +{ + PR_IpAddrNull, /* do NOT overwrite the IP address */ + PR_IpAddrAny, /* assign logical INADDR_ANY to IP address */ + PR_IpAddrLoopback, /* assign logical INADDR_LOOPBACK */ + PR_IpAddrV4Mapped /* IPv4 mapped address */ +} PRNetAddrValue; + +NSPR_API(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: PR_SetNetAddr(), +** DESCRIPTION: +** Set the fields of a PRNetAddr, assigning well known values as +** appropriate. This function is similar to PR_InitializeNetAddr +** but differs in that the address family is specified. +** +** INPUTS +** PRNetAddrValue val The value to be assigned to the IP Address portion +** of the network address. This can only specify the +** special well known values that are equivalent to +** INADDR_ANY and INADDR_LOOPBACK. +** +** PRUint16 af The address family (either PR_AF_INET or PR_AF_INET6) +** +** PRUint16 port The port number to be assigned in the structure. +** +** OUTPUTS: +** PRNetAddr *addr The address to be manipulated. +** +** RETURN: +** PRStatus To indicate success or failure. If the latter, the +** reason for the failure can be retrieved by calling +** PR_GetError(); +***********************************************************************/ +NSPR_API(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_IsNetAddrType() +** Determine if the network address is of the specified type. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** PRNetAddrValue The type of network address +** +** RETURN: +** PRBool PR_TRUE if the network address is of the +** specified type, else PR_FALSE. +***********************************************************************/ +NSPR_API(PRBool) PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_ConvertIPv4AddrToIPv6() +** Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr +** +** INPUTS: +** PRUint32 v4addr IPv4 address +** +** OUTPUTS: +** PRIPv6Addr *v6addr The converted IPv6 address +** +** RETURN: +** void +** +***********************************************************************/ +NSPR_API(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr); + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrFamily() +** Get the 'family' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'family' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrFamily(addr) ((addr)->raw.family) + +/*********************************************************************** +** MACRO: +** DESCRIPTION: PR_NetAddrInetPort() +** Get the 'port' field of a PRNetAddr union. +** +** INPUTS: +** const PRNetAddr *addr A network address. +** +** RETURN: +** PRUint16 The 'port' field of 'addr'. +***********************************************************************/ +#define PR_NetAddrInetPort(addr) \ + ((addr)->raw.family == PR_AF_INET6 ? (addr)->ipv6.port : (addr)->inet.port) + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByName() +** Lookup a protocol entry based on protocol's name +** +** INPUTS: +** char *protocolname Character string of the protocol's name. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ + +typedef struct PRProtoEnt { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ +#if defined(WIN32) || defined(WIN16) + PRInt16 p_num; /* protocol # */ +#else + PRInt32 p_num; /* protocol # */ +#endif +} PRProtoEnt; + +NSPR_API(PRStatus) PR_GetProtoByName( + const char* protocolname, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetProtoByNumber() +** Lookup a protocol entry based on protocol's number +** +** INPUTS: +** PRInt32 protocolnumber +** Number assigned to the protocol. +** char *buf A scratch buffer for the runtime to return result. +** This buffer is allocated by the caller. +** PRIntn bufsize Number of bytes in 'buf'. A recommnded value to +** use is PR_NETDB_BUF_SIZE. +** OUTPUTS: +** PRHostEnt *PRProtoEnt +** This structure is filled in by the runtime if +** the function returns PR_SUCCESS. This structure +** is allocated by the caller. +** RETURN: +** PRStatus PR_SUCCESS if the lookup succeeds. If it fails +** the result will be PR_FAILURE and the reason +** for the failure can be retrieved by PR_GetError(). +***********************************************************************/ +NSPR_API(PRStatus) PR_GetProtoByNumber( + PRInt32 protocolnumber, char* buffer, PRInt32 bufsize, PRProtoEnt* result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetAddrInfoByName() +** Lookup a host by name. Equivalent to getaddrinfo(host, NULL, ...) of +** RFC 3493. +** +** INPUTS: +** char *hostname Character string defining the host name of interest +** PRUint16 af May be PR_AF_UNSPEC or PR_AF_INET. +** PRIntn flags May be either PR_AI_ADDRCONFIG or +** PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include +** PR_AI_NOCANONNAME to suppress the determination of +** the canonical name corresponding to hostname. +** RETURN: +** PRAddrInfo* Handle to a data structure containing the results +** of the host lookup. Use PR_EnumerateAddrInfo to +** inspect the PRNetAddr values stored in this object. +** When no longer needed, this handle must be destroyed +** with a call to PR_FreeAddrInfo. If a lookup error +** occurs, then NULL will be returned. +***********************************************************************/ +typedef struct PRAddrInfo PRAddrInfo; + +NSPR_API(PRAddrInfo*) PR_GetAddrInfoByName( + const char *hostname, PRUint16 af, PRIntn flags); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_FreeAddrInfo() +** Destroy the PRAddrInfo handle allocated by PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The handle resulting from a successful call to +** PR_GetAddrInfoByName(). +** RETURN: +** void +***********************************************************************/ +NSPR_API(void) PR_FreeAddrInfo(PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_EnumerateAddrInfo() +** A stateless enumerator over a PRAddrInfo handle acquired from +** PR_GetAddrInfoByName() to inspect the possible network addresses. +** +** INPUTS: +** void *enumPtr Index pointer of the enumeration. The enumeration +** starts and ends with a value of NULL. +** PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** PRUint16 port The port number to be assigned as part of the +** PRNetAddr. +** OUTPUTS: +** PRNetAddr *result A pointer to an address structure that will be +** filled in by the call to the enumeration if the +** result of the call is greater than zero. +** RETURN: +** void* The value that should be used for the next call +** of the enumerator ('enumPtr'). The enumeration +** is ended if this value is returned NULL. +***********************************************************************/ +NSPR_API(void *) PR_EnumerateAddrInfo( + void *enumPtr, const PRAddrInfo *addrInfo, PRUint16 port, PRNetAddr *result); + +/*********************************************************************** +** FUNCTION: +** DESCRIPTION: PR_GetCanonNameFromAddrInfo() +** Extracts the canonical name of the hostname passed to +** PR_GetAddrInfoByName(). +** +** INPUTS: +** PRAddrInfo *addrInfo +** The PRAddrInfo handle returned by a successful +** call to PR_GetAddrInfoByName(). +** RETURN: +** const char * A const pointer to the canonical hostname stored +** in the given PRAddrInfo handle. This pointer is +** invalidated once the PRAddrInfo handle is destroyed +** by a call to PR_FreeAddrInfo(). +***********************************************************************/ +NSPR_API(const char *) PR_GetCanonNameFromAddrInfo( + const PRAddrInfo *addrInfo); + +/*********************************************************************** +** FUNCTIONS: PR_ntohs, PR_ntohl, PR_ntohll, PR_htons, PR_htonl, PR_htonll +** +** DESCRIPTION: API entries for the common byte ordering routines. +** +** PR_ntohs 16 bit conversion from network to host +** PR_ntohl 32 bit conversion from network to host +** PR_ntohll 64 bit conversion from network to host +** PR_htons 16 bit conversion from host to network +** PR_htonl 32 bit conversion from host to network +** PR_ntonll 64 bit conversion from host to network +** +***********************************************************************/ +NSPR_API(PRUint16) PR_ntohs(PRUint16); +NSPR_API(PRUint32) PR_ntohl(PRUint32); +NSPR_API(PRUint64) PR_ntohll(PRUint64); +NSPR_API(PRUint16) PR_htons(PRUint16); +NSPR_API(PRUint32) PR_htonl(PRUint32); +NSPR_API(PRUint64) PR_htonll(PRUint64); + +PR_END_EXTERN_C + +#endif /* prnetdb_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prolock.h b/src/libs/xpcom18a4/nsprpub/pr/include/prolock.h new file mode 100644 index 00000000..bdb57f88 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prolock.h @@ -0,0 +1,217 @@ +/* -*- 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 prolock_h___ +#define prolock_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateOrderedLock VBoxNsprPR_CreateOrderedLock +#define PR_DestroyOrderedLock VBoxNsprPR_DestroyOrderedLock +#define PR_LockOrderedLock VBoxNsprPR_LockOrderedLock +#define PR_UnlockOrderedLock VBoxNsprPR_UnlockOrderedLock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** A locking mechanism, built on the existing PRLock definiion, +** is provided that will permit applications to define a Lock +** Hierarchy (or Lock Ordering) schema. An application designed +** using the Ordered Lock functions will terminate with a +** diagnostic message when a lock inversion condition is +** detected. +** +** The lock ordering detection is complile-time enabled only. in +** optimized builds of NSPR, the Ordered Lock functions map +** directly to PRLock functions, providing no lock order +** detection. +** +** The Ordered Lock Facility is compiled in when DEBUG is defined at +** compile time. Ordered Lock can be forced on in optimized builds by +** defining FORCE_NSPR_ORDERED_LOCK at compile time. Both the +** application using Ordered Lock and NSPR must be compiled with the +** facility enabled to achieve the desired results. +** +** Application designers should use the macro interfaces to the Ordered +** Lock facility to ensure that it is compiled out in optimized builds. +** +** Application designers are responsible for defining their own +** lock hierarchy. +** +** Ordered Lock is thread-safe and SMP safe. +** +** See Also: prlock.h +** +** /lth. 10-Jun-1998. +** +*/ + +/* +** Opaque type for ordered lock. +** ... Don't even think of looking in here. +** +*/ + +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +typedef void * PROrderedLock; +#else +/* +** Map PROrderedLock and methods onto PRLock when ordered locking +** is not compiled in. +** +*/ +#include "prlock.h" + +typedef PRLock PROrderedLock; +#endif + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateOrderedLock() -- Create an Ordered Lock +** +** DESCRIPTION: PR_CreateOrderedLock() creates an ordered lock. +** +** INPUTS: +** order: user defined order of this lock. +** name: name of the lock. For debugging purposes. +** +** OUTPUTS: returned +** +** RETURNS: PR_OrderedLock pointer +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_CREATE_ORDERED_LOCK(order,name)\ + PR_CreateOrderedLock((order),(name)) +#else +#define PR_CREATE_ORDERED_LOCK(order) PR_NewLock() +#endif + +NSPR_API(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyOrderedLock() -- Destroy an Ordered Lock +** +** DESCRIPTION: PR_DestroyOrderedLock() destroys the ordered lock +** referenced by lock. +** +** INPUTS: lock: pointer to a PROrderedLock +** +** OUTPUTS: the lock is destroyed +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyOrderedLock((lock)) +#else +#define PR_DESTROY_ORDERED_LOCK(lock) PR_DestroyLock((lock)) +#endif + +NSPR_API(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_LockOrderedLock() -- Lock an ordered lock +** +** DESCRIPTION: PR_LockOrderedLock() locks the ordered lock +** referenced by lock. If the order of lock is less than or equal +** to the order of the highest lock held by the locking thread, +** the function asserts. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: The lock is held or the fucntion asserts. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_LOCK_ORDERED_LOCK(lock) PR_LockOrderedLock((lock)) +#else +#define PR_LOCK_ORDERED_LOCK(lock) PR_Lock((lock)) +#endif + +NSPR_API(void) + PR_LockOrderedLock( + PROrderedLock *lock +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_UnlockOrderedLock() -- unlock and Ordered Lock +** +** DESCRIPTION: PR_UnlockOrderedLock() unlocks the lock referenced +** by lock. +** +** INPUTS: lock: a pointer to a PROrderedLock +** +** OUTPUTS: the lock is unlocked +** +** RETURNS: +** PR_SUCCESS +** PR_FAILURE +** +** RESTRICTIONS: +** +*/ +#if defined(DEBUG) || defined(FORCE_NSPR_ORDERED_LOCKS) +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_UnlockOrderedLock((lock)) +#else +#define PR_UNLOCK_ORDERED_LOCK(lock) PR_Unlock((lock)) +#endif + +NSPR_API(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +); + +PR_END_EXTERN_C + +#endif /* prolock_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prpdce.h b/src/libs/xpcom18a4/nsprpub/pr/include/prpdce.h new file mode 100644 index 00000000..434f1ec2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prpdce.h @@ -0,0 +1,127 @@ +/* -*- 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 ***** */ + +/* + * File: prpdce.h + * Description: This file is the API defined to allow for DCE (aka POSIX) + * thread emulation in an NSPR environment. It is not the + * intent that this be a fully supported API. + */ + +#if !defined(PRPDCE_H) +#define PRPDCE_H + +#include "prlock.h" +#include "prcvar.h" +#include "prtypes.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PRP_DestroyNakedCondVar VBoxNsprPRP_DestroyNakedCondVar +#define PRP_NakedBroadcast VBoxNsprPRP_NakedBroadcast +#define PRP_NakedNotify VBoxNsprPRP_NakedNotify +#define PRP_NakedWait VBoxNsprPRP_NakedWait +#define PRP_NewNakedCondVar VBoxNsprPRP_NewNakedCondVar +#define PRP_TryLock VBoxNsprPRP_TryLock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +#define _PR_NAKED_CV_LOCK (PRLock*)0xdce1dce1 + +/* +** Test and acquire a lock. +** +** If the lock is acquired by the calling thread, the +** return value will be PR_SUCCESS. If the lock is +** already held, by another thread or this thread, the +** result will be PR_FAILURE. +*/ +NSPR_API(PRStatus) PRP_TryLock(PRLock *lock); + +/* +** Create a naked condition variable +** +** A "naked" condition variable is one that is not created bound +** to a lock. The CV created with this function is the only type +** that may be used in the subsequent "naked" condition variable +** operations (see PRP_NakedWait, PRP_NakedNotify, PRP_NakedBroadcast); +*/ +NSPR_API(PRCondVar*) PRP_NewNakedCondVar(void); + +/* +** Destroy a naked condition variable +** +** Destroy the condition variable created by PR_NewNakedCondVar. +*/ +NSPR_API(void) PRP_DestroyNakedCondVar(PRCondVar *cvar); + +/* +** Wait on a condition +** +** Wait on the condition variable 'cvar'. It is asserted that +** the lock protecting the condition 'lock' is held by the +** calling thread. If more time expires than that declared in +** 'timeout' the condition will be notified. Waits can be +** interrupted by another thread. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout); + +/* +** Notify a thread waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedNotify(PRCondVar *cvar); + +/* +** Notify all threads waiting on a condition +** +** Notify the condition specified 'cvar'. +** +** NB: The CV ('cvar') must be one created using PR_NewNakedCondVar. +*/ +NSPR_API(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar); + +PR_END_EXTERN_C + +#endif /* PRPDCE_H */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prprf.h b/src/libs/xpcom18a4/nsprpub/pr/include/prprf.h new file mode 100644 index 00000000..69a27b34 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prprf.h @@ -0,0 +1,169 @@ +/* -*- 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 prprf_h___ +#define prprf_h___ + +/* +** API for PR printf like routines. Supports the following formats +** %d - decimal +** %u - unsigned decimal +** %x - unsigned hex +** %X - unsigned uppercase hex +** %o - unsigned octal +** %hd, %hu, %hx, %hX, %ho - 16-bit versions of above +** %ld, %lu, %lx, %lX, %lo - 32-bit versions of above +** %lld, %llu, %llx, %llX, %llo - 64 bit versions of above +** %s - string +** %c - character +** %p - pointer (deals with machine dependent pointer size) +** %f - float +** %g - float +*/ +#include "prtypes.h" +#include "prio.h" +#include +#include + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_snprintf VBoxNsprPR_snprintf +#define PR_vsnprintf VBoxNsprPR_vsnprintf +#define PR_smprintf VBoxNsprPR_smprintf +#define PR_smprintf_free VBoxNsprPR_smprintf_free +#define PR_sprintf_append VBoxNsprPR_sprintf_append +#define PR_sxprintf VBoxNsprPR_sxprintf +#define PR_fprintf VBoxNsprPR_fprintf +#define PR_vsmprintf VBoxNsprPR_vsmprintf +#define PR_vsprintf_append VBoxNsprPR_vsprintf_append +#define PR_vsxprintf VBoxNsprPR_vsxprintf +#define PR_vfprintf VBoxNsprPR_vfprintf +#define PR_sscanf VBoxNsprPR_sscanf +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (PRUint32)-1 if an error occurs. +*/ +NSPR_API(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "PR_smprintf_free" to release +** the memory returned. +*/ +NSPR_API(char*) PR_smprintf(const char *fmt, ...); + +/* +** Free the memory allocated, for the caller, by PR_smprintf +*/ +NSPR_API(void) PR_smprintf_free(char *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +NSPR_API(char*) PR_sprintf_append(char *last, const char *fmt, ...); + +/* +** sprintf into a function. The function "f" is called with a string to +** place into the output. "arg" is an opaque pointer used by the stuff +** function to hold any state needed to do the storage of the output +** data. The return value is a count of the number of characters fed to +** the stuff function, or (PRUint32)-1 if an error occurs. +*/ +typedef PRIntn (*PRStuffFunc)(void *arg, const char *s, PRUint32 slen); + +NSPR_API(PRUint32) PR_sxprintf(PRStuffFunc f, void *arg, const char *fmt, ...); + +/* +** fprintf to a PRFileDesc +*/ +NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...); + +/* +** va_list forms of the above. +*/ +NSPR_API(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen, const char *fmt, va_list ap); +NSPR_API(char*) PR_vsmprintf(const char *fmt, va_list ap); +NSPR_API(char*) PR_vsprintf_append(char *last, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vsxprintf(PRStuffFunc f, void *arg, const char *fmt, va_list ap); +NSPR_API(PRUint32) PR_vfprintf(struct PRFileDesc* fd, const char *fmt, va_list ap); + +/* +*************************************************************************** +** FUNCTION: PR_sscanf +** DESCRIPTION: +** PR_sscanf() scans the input character string, performs data +** conversions, and stores the converted values in the data objects +** pointed to by its arguments according to the format control +** string. +** +** PR_sscanf() behaves the same way as the sscanf() function in the +** Standard C Library (stdio.h), with the following exceptions: +** - PR_sscanf() handles the NSPR integer and floating point types, +** such as PRInt16, PRInt32, PRInt64, and PRFloat64, whereas +** sscanf() handles the standard C types like short, int, long, +** and double. +** - PR_sscanf() has no multibyte character support, while sscanf() +** does. +** INPUTS: +** const char *buf +** a character string holding the input to scan +** const char *fmt +** the format control string for the conversions +** ... +** variable number of arguments, each of them is a pointer to +** a data object in which the converted value will be stored +** OUTPUTS: none +** RETURNS: PRInt32 +** The number of values converted and stored. +** RESTRICTIONS: +** Multibyte characters in 'buf' or 'fmt' are not allowed. +*************************************************************************** +*/ + +NSPR_API(PRInt32) PR_sscanf(const char *buf, const char *fmt, ...); + +PR_END_EXTERN_C + +#endif /* prprf_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prproces.h b/src/libs/xpcom18a4/nsprpub/pr/include/prproces.h new file mode 100644 index 00000000..27999799 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prproces.h @@ -0,0 +1,133 @@ +/* -*- 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 prproces_h___ +#define prproces_h___ + +#include "prtypes.h" +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateProcessDetached VBoxNsprPR_CreateProcessDetached +#define PR_ProcessAttrSetInheritableFD VBoxNsprPR_ProcessAttrSetInheritableFD +#define PR_DestroyProcessAttr VBoxNsprPR_DestroyProcessAttr +#define PR_NewProcessAttr VBoxNsprPR_NewProcessAttr +#define PR_ResetProcessAttr VBoxNsprPR_ResetProcessAttr +#define PR_ProcessAttrSetStdioRedirect VBoxNsprPR_ProcessAttrSetStdioRedirect +#define PR_SetStdioRedirect VBoxNsprPR_SetStdioRedirect +#define PR_ProcessAttrSetCurrentDirectory VBoxNsprPR_ProcessAttrSetCurrentDirectory +#define PR_CreateProcess VBoxNsprPR_CreateProcess +#define PR_DetachProcess VBoxNsprPR_DetachProcess +#define PR_WaitProcess VBoxNsprPR_WaitProcess +#define PR_KillProcess VBoxNsprPR_KillProcess +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/************************************************************************/ +/*****************************PROCESS OPERATIONS*************************/ +/************************************************************************/ + +typedef struct PRProcess PRProcess; +typedef struct PRProcessAttr PRProcessAttr; + +NSPR_API(PRProcessAttr *) PR_NewProcessAttr(void); + +NSPR_API(void) PR_ResetProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_DestroyProcessAttr(PRProcessAttr *attr); + +NSPR_API(void) PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +/* + * OBSOLETE -- use PR_ProcessAttrSetStdioRedirect instead. + */ +NSPR_API(void) PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd +); + +NSPR_API(PRStatus) PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir +); + +NSPR_API(PRStatus) PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name +); + +/* +** Create a new process +** +** Create a new process executing the file specified as 'path' and with +** the supplied arguments and environment. +** +** This function may fail because of illegal access (permissions), +** invalid arguments or insufficient resources. +** +** A process may be created such that the creator can later synchronize its +** termination using PR_WaitProcess(). +*/ + +NSPR_API(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr); + +NSPR_API(PRStatus) PR_DetachProcess(PRProcess *process); + +NSPR_API(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode); + +NSPR_API(PRStatus) PR_KillProcess(PRProcess *process); + +PR_END_EXTERN_C + +#endif /* prproces_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prrng.h b/src/libs/xpcom18a4/nsprpub/pr/include/prrng.h new file mode 100644 index 00000000..90d1a385 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prrng.h @@ -0,0 +1,111 @@ +/* -*- 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 ***** */ + + +/* +** prrng.h -- NSPR Random Number Generator +** +** +** lth. 29-Oct-1999. +*/ + +#ifndef prrng_h___ +#define prrng_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_GetRandomNoise VBoxNsprPR_GetRandomNoise +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** PR_GetRandomNoise() -- Get random noise from the host platform +** +** Description: +** PR_GetRandomNoise() provides, depending on platform, a random value. +** The length of the random value is dependent on platform and the +** platform's ability to provide a random value at that moment. +** +** The intent of PR_GetRandomNoise() is to provide a "seed" value for a +** another random number generator that may be suitable for +** cryptographic operations. This implies that the random value +** provided may not be, by itself, cryptographically secure. The value +** generated by PR_GetRandomNoise() is at best, extremely difficult to +** predict and is as non-deterministic as the underlying platfrom can +** provide. +** +** Inputs: +** buf -- pointer to a caller supplied buffer to contain the +** generated random number. buf must be at least as large as +** is specified in the 'size' argument. +** +** size -- the requested size of the generated random number +** +** Outputs: +** a random number provided in 'buf'. +** +** Returns: +** PRSize value equal to the size of the random number actually +** generated, or zero. The generated size may be less than the size +** requested. A return value of zero means that PR_GetRandomNoise() is +** not implemented on this platform, or there is no available noise +** available to be returned at the time of the call. +** +** Restrictions: +** Calls to PR_GetRandomNoise() may use a lot of CPU on some platforms. +** Some platforms may block for up to a few seconds while they +** accumulate some noise. Busy machines generate lots of noise, but +** care is advised when using PR_GetRandomNoise() frequently in your +** application. +** +** History: +** Parts of the model dependent implementation for PR_GetRandomNoise() +** were taken in whole or part from code previously in Netscape's NSS +** component. +** +*/ +NSPR_API(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +); + +PR_END_EXTERN_C + +#endif /* prrng_h___ */ +/* end prrng.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prrwlock.h b/src/libs/xpcom18a4/nsprpub/pr/include/prrwlock.h new file mode 100644 index 00000000..718bbb12 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prrwlock.h @@ -0,0 +1,128 @@ +/* -*- 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 ***** */ + +/* +** File: prrwlock.h +** Description: API to basic reader-writer lock functions of NSPR. +** +**/ + +#ifndef prrwlock_h___ +#define prrwlock_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_NewRWLock VBoxNsprPR_NewRWLock +#define PR_DestroyRWLock VBoxNsprPR_DestroyRWLock +#define PR_RWLock_Rlock VBoxNsprPR_RWLock_Rlock +#define PR_RWLock_Wlock VBoxNsprPR_RWLock_Wlock +#define PR_RWLock_Unlock VBoxNsprPR_RWLock_Unlock +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* + * PRRWLock -- + * + * The reader writer lock, PRRWLock, is an opaque object to the clients + * of NSPR. All routines operate on a pointer to this opaque entity. + */ + + +typedef struct PRRWLock PRRWLock; + +#define PR_RWLOCK_RANK_NONE 0 + + +/*********************************************************************** +** FUNCTION: PR_NewRWLock +** DESCRIPTION: +** Returns a pointer to a newly created reader-writer lock object. +** INPUTS: Lock rank +** Lock name +** OUTPUTS: void +** RETURN: PRRWLock* +** If the lock cannot be created because of resource constraints, NULL +** is returned. +** +***********************************************************************/ +NSPR_API(PRRWLock*) PR_NewRWLock(PRUint32 lock_rank, const char *lock_name); + +/*********************************************************************** +** FUNCTION: PR_DestroyRWLock +** DESCRIPTION: +** Destroys a given RW lock object. +** INPUTS: PRRWLock *lock - Lock to be freed. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_DestroyRWLock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Rlock +** DESCRIPTION: +** Apply a read lock (non-exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to be read-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Rlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Wlock +** DESCRIPTION: +** Apply a write lock (exclusive) on a RWLock +** INPUTS: PRRWLock *lock - Lock to write-locked. +** OUTPUTS: void +** RETURN: None +***********************************************************************/ +NSPR_API(void) PR_RWLock_Wlock(PRRWLock *lock); + +/*********************************************************************** +** FUNCTION: PR_RWLock_Unlock +** DESCRIPTION: +** Release a RW lock. Unlocking an unlocked lock has undefined results. +** INPUTS: PRRWLock *lock - Lock to unlocked. +** OUTPUTS: void +** RETURN: void +***********************************************************************/ +NSPR_API(void) PR_RWLock_Unlock(PRRWLock *lock); + +PR_END_EXTERN_C + +#endif /* prrwlock_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prshm.h b/src/libs/xpcom18a4/nsprpub/pr/include/prshm.h new file mode 100644 index 00000000..f474d306 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prshm.h @@ -0,0 +1,297 @@ +/* -*- 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 ***** */ + +/* +** prshm.h -- NSPR Shared Memory +** +** NSPR Named Shared Memory API provides a cross-platform named +** shared-memory interface. NSPR Named Shared Memory is modeled on +** similar constructs in Unix and Windows operating systems. Shared +** memory allows multiple processes to access one or more common shared +** memory regions, using it as an inter-process communication channel. +** +** Notes on Platform Independence: +** NSPR Named Shared Memory is built on the native services offered +** by most platforms. The NSPR Named Shared Memory API tries to +** provide a least common denominator interface so that it works +** across all supported platforms. To ensure that it works everywhere, +** some platform considerations must be accomodated and the protocol +** for using NSPR Shared Memory API must be observed. +** +** Protocol: +** Multiple shared memories can be created using NSPR's Shared Memory +** feature. For each named shared memory, as defined by the name +** given in the PR_OpenSharedMemory() call, a protocol for using the +** shared memory API is required to ensure desired behavior. Failing +** to follow the protocol may yield unpredictable results. +** +** PR_OpenSharedMemory() will create the shared memory segment, if it +** does not already exist, or open a connection that the existing +** shared memory segment if it already exists. +** +** PR_AttachSharedMemory() should be called following +** PR_OpenSharedMemory() to map the memory segment to an address in +** the application's address space. +** +** PR_AttachSharedMemory() may be called to re-map a shared memory +** segment after detaching the same PRSharedMemory object. Be +** sure to detach it when done. +** +** PR_DetachSharedMemory() should be called to un-map the shared +** memory segment from the application's address space. +** +** PR_CloseSharedMemory() should be called when no further use of the +** PRSharedMemory object is required within a process. Following a +** call to PR_CloseSharedMemory() the PRSharedMemory object is +** invalid and cannot be reused. +** +** PR_DeleteSharedMemory() should be called before process +** termination. After calling PR_DeleteSharedMemory() any further use +** of the shared memory associated with the name may cause +** unpredictable results. +** +** Files: +** The name passed to PR_OpenSharedMemory() should be a valid filename +** for a unix platform. PR_OpenSharedMemory() creates file using the +** name passed in. Some platforms may mangle the name before creating +** the file and the shared memory. +** +** The unix implementation may use SysV IPC shared memory, Posix +** shared memory, or memory mapped files; the filename may used to +** define the namespace. On Windows, the name is significant, but +** there is no file associated with name. +** +** No assumptions about the persistence of data in the named file +** should be made. Depending on platform, the shared memory may be +** mapped onto system paging space and be discarded at process +** termination. +** +** All names provided to PR_OpenSharedMemory() should be valid +** filename syntax or name syntax for shared memory for the target +** platform. Referenced directories should have permissions +** appropriate for writing. +** +** Limits: +** Different platforms have limits on both the number and size of +** shared memory resources. The default system limits on some +** platforms may be smaller than your requirements. These limits may +** be adjusted on some platforms either via boot-time options or by +** setting the size of the system paging space to accomodate more +** and/or larger shared memory segment(s). +** +** Security: +** On unix platforms, depending on implementation, contents of the +** backing store for the shared memory can be exposed via the file +** system. Set permissions and or access controls at create and attach +** time to ensure you get the desired security. +** +** On windows platforms, no special security measures are provided. +** +** Example: +** The test case pr/tests/nameshm1.c provides an example of use as +** well as testing the operation of NSPR's Named Shared Memory. +** +** lth. 18-Aug-1999. +*/ + +#ifndef prshm_h___ +#define prshm_h___ + +#include "prtypes.h" +#include "prio.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_OpenSharedMemory VBoxNsprPR_OpenSharedMemory +#define PR_AttachSharedMemory VBoxNsprPR_AttachSharedMemory +#define PR_DetachSharedMemory VBoxNsprPR_DetachSharedMemory +#define PR_CloseSharedMemory VBoxNsprPR_CloseSharedMemory +#define PR_DeleteSharedMemory VBoxNsprPR_DeleteSharedMemory +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Declare opaque type PRSharedMemory. +*/ +typedef struct PRSharedMemory PRSharedMemory; + +/* +** FUNCTION: PR_OpenSharedMemory() +** +** DESCRIPTION: +** PR_OpenSharedMemory() creates a new shared-memory segment or +** associates a previously created memory segment with name. +** +** When parameter create is (PR_SHM_EXCL | PR_SHM_CREATE) and the +** shared memory already exists, the function returns NULL with the +** error set to PR_FILE_EXISTS_ERROR. +** +** When parameter create is PR_SHM_CREATE and the shared memory +** already exists, a handle to that memory segment is returned. If +** the segment does not exist, it is created and a pointer to the +** related PRSharedMemory structure is returned. +** +** When parameter create is 0, and the shared memory exists, a +** pointer to a PRSharedMemory is returned. If the shared memory does +** not exist, NULL is returned with the error set to +** PR_FILE_NOT_FOUND_ERROR. +** +** INPUTS: +** name -- the name the shared-memory segment is known as. +** size -- the size of the shared memory segment. +** flags -- Options for creating the shared memory +** mode -- Same as is passed to PR_Open() +** +** OUTPUTS: +** The shared memory is allocated. +** +** RETURNS: Pointer to opaque structure PRSharedMemory or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +*/ +NSPR_API( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +); +/* Define values for PR_OpenShareMemory(...,create) */ +#define PR_SHM_CREATE 0x1 /* create if not exist */ +#define PR_SHM_EXCL 0x2 /* fail if already exists */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +** DESCRIPTION: +** PR_AttachSharedMemory() maps the shared-memory described by +** shm to the current process. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** flags -- options for mapping the shared memory. +** PR_SHM_READONLY causes the memory to be attached +** read-only. +** +** OUTPUTS: +** On success, the shared memory segment represented by shm is mapped +** into the process' address space. +** +** RETURNS: Address where shared memory is mapped, or NULL. +** NULL is returned on error. The reason for the error can be +** retrieved via PR_GetError() and PR_GetOSError(); +** +** +*/ +NSPR_API( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +); +/* Define values for PR_AttachSharedMemory(...,flags) */ +#define PR_SHM_READONLY 0x01 + +/* +** FUNCTION: PR_DetachSharedMemory() +** +** DESCRIPTION: +** PR_DetachSharedMemory() detaches the shared-memory described +** by shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** addr -- The address at which the memory was attached. +** +** OUTPUTS: +** The shared memory mapped to an address via a previous call to +** PR_AttachSharedMemory() is unmapped. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +); + +/* +** FUNCTION: PR_CloseSharedMemory() +** +** DESCRIPTION: +** PR_CloseSharedMemory() closes the shared-memory described by +** shm. +** +** INPUTS: +** shm -- The handle returned from PR_OpenSharedMemory(). +** +** OUTPUTS: +** the shared memory represented by shm is closed +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +); + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +** DESCRIPTION: +** The shared memory resource represented by name is released. +** +** INPUTS: +** name -- the name the shared-memory segment +** +** OUTPUTS: +** depending on platform, resources may be returned to the underlying +** operating system. +** +** RETURNS: PRStatus +** +*/ +NSPR_API( PRStatus ) + PR_DeleteSharedMemory( + const char *name +); + +PR_END_EXTERN_C + +#endif /* prshm_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prshma.h b/src/libs/xpcom18a4/nsprpub/pr/include/prshma.h new file mode 100644 index 00000000..0214e0aa --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prshma.h @@ -0,0 +1,279 @@ +/* -*- 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 ***** */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** NSPR provides an anonymous shared memory based on NSPR's PRFileMap +** type. The anonymous file-mapped shared memory provides an inheritable +** shared memory, as in: the child process inherits the shared memory. +** Compare the file-mapped anonymous shared memory to to a named shared +** memory described in prshm.h. The intent is to provide a shared +** memory that is accessable only by parent and child processes. ... +** It's a security thing. +** +** Depending on the underlying platform, the file-mapped shared memory +** may be backed by a file. ... surprise! ... On some platforms, no +** real file backs the shared memory. On platforms where the shared +** memory is backed by a file, the file's name in the filesystem is +** visible to other processes for only the duration of the creation of +** the file, hopefully a very short time. This restricts processess +** that do not inherit the shared memory from opening the file and +** reading or writing its contents. Further, when all processes +** using an anonymous shared memory terminate, the backing file is +** deleted. ... If you are not paranoid, you're not paying attention. +** +** The file-mapped shared memory requires a protocol for the parent +** process and child process to share the memory. NSPR provides two +** protocols. Use one or the other; don't mix and match. +** +** In the first protocol, the job of passing the inheritable shared +** memory is done via helper-functions with PR_CreateProcess(). In the +** second protocol, the parent process is responsible for creating the +** child process; the parent and child are mutually responsible for +** passing a FileMap string. NSPR provides helper functions for +** extracting data from the PRFileMap object. ... See the examples +** below. +** +** Both sides should adhere strictly to the protocol for proper +** operation. The pseudo-code below shows the use of a file-mapped +** shared memory by a parent and child processes. In the examples, the +** server creates the file-mapped shared memory, the client attaches to +** it. +** +** First protocol. +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** addr = PR_MemMap(fm); +** attr = PR_NewProcessAttr(); +** PR_ProcessAttrSetInheritableFileMap( attr, fm, shmname ); +** PR_CreateProcess(Client); +** PR_DestroyProcessAttr(attr); +** ... yadda ... +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via PR_CreateProcess() +** fm = PR_GetInheritedFileMap( shmname ); +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** Second Protocol: +** Server: +** +** fm = PR_OpenAnonFileMap(dirName, size, FilemapProt); +** fmstring = PR_ExportFileMapAsString( fm ); +** addr = PR_MemMap(fm); +** ... application specific technique to pass fmstring to child +** ... yadda ... Server uses his own magic to create child +** PR_MemUnmap( addr ); +** PR_CloseFileMap(fm); +** +** +** Client: +** ... started by server via his own magic +** ... application specific technique to find fmstring from parent +** fm = PR_ImportFileMapFromString( fmstring ) +** addr = PR_MemMap(fm); +** ... yadda ... +** PR_MemUnmap(addr); +** PR_CloseFileMap(fm); +** +** +** lth. 2-Jul-1999. +** +** Note: The second protocol was requested by NelsonB (7/1999); this is +** to accomodate servers which already create their own child processes +** using platform native methods. +** +*/ + +#ifndef prshma_h___ +#define prshma_h___ + +#include "prtypes.h" +#include "prio.h" +#include "prproces.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_OpenAnonFileMap VBoxNsprPR_OpenAnonFileMap +#define PR_ProcessAttrSetInheritableFileMap VBoxNsprPR_ProcessAttrSetInheritableFileMap +#define PR_GetInheritedFileMap VBoxNsprPR_GetInheritedFileMap +#define PR_ExportFileMapAsString VBoxNsprPR_ExportFileMapAsString +#define PR_ImportFileMapFromString VBoxNsprPR_ImportFileMapFromString +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +** Description: +** PR_OpenAnonFileMap() creates an anonymous shared memory. If the +** shared memory already exists, a handle is returned to that shared +** memory object. +** +** On Unix platforms, PR_OpenAnonFileMap() uses 'dirName' as a +** directory name, without the trailing '/', to contain the anonymous +** file. A filename is generated for the name. +** +** On Windows platforms, dirName is ignored. +** +** Inputs: +** dirName -- A directory name to contain the anonymous file. +** size -- The size of the shared memory +** prot -- How the shared memory is mapped. See prio.h +** +** Outputs: +** PRFileMap * +** +** Returns: +** Pointer to PRFileMap or NULL on error. +** +*/ +NSPR_API( PRFileMap *) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +); + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** Description: +** PR_ProcessAttrSetInheritableFileMap() connects the PRFileMap to +** PRProcessAttr with shmname. A subsequent call to PR_CreateProcess() +** makes the PRFileMap importable by the child process. +** +** Inputs: +** attr -- PRProcessAttr, used to pass data to PR_CreateProcess() +** fm -- PRFileMap structure to be passed to the child process +** shmname -- The name for the PRFileMap; used by child. +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRStatus +** +*/ +NSPR_API(PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +); + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +** Description: +** PR_GetInheritedFileMap() retrieves a PRFileMap object exported from +** its parent process via PR_CreateProcess(). +** +** Inputs: +** shmname -- The name provided to PR_ProcessAttrSetInheritableFileMap() +** +** Outputs: +** PRFileMap * +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +); + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +** Description: +** Creates an identifier, as a string, from a PRFileMap object +** previously created with PR_OpenAnonFileMap(). +** +** Inputs: +** fm -- PRFileMap pointer to be represented as a string. +** bufsize -- sizeof(buf) +** buf -- a buffer of length PR_FILEMAP_STRING_BUFSIZE +** +** Outputs: +** buf contains the stringized PRFileMap identifier +** +** Returns: +** PRStatus +** +*/ +NSPR_API( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufsize, + char *buf +); +#define PR_FILEMAP_STRING_BUFSIZE 128 + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** Description: +** PR_ImportFileMapFromString() creates a PRFileMap object from a +** string previously created by PR_ExportFileMapAsString(). +** +** Inputs: +** fmstring -- string created by PR_ExportFileMapAsString() +** +** Returns: +** PRFileMap pointer or NULL. +** +*/ +NSPR_API( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +); + +PR_END_EXTERN_C +#endif /* prshma_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prsystem.h b/src/libs/xpcom18a4/nsprpub/pr/include/prsystem.h new file mode 100644 index 00000000..2028b709 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prsystem.h @@ -0,0 +1,131 @@ +/* -*- 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 prsystem_h___ +#define prsystem_h___ + +/* +** API to NSPR functions returning system info. +*/ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_GetDirectorySeparator VBoxNsprPR_GetDirectorySeparator +#define PR_GetDirectorySepartor VBoxNsprPR_GetDirectorySepartor +#define PR_GetPathSeparator VBoxNsprPR_GetPathSeparator +#define PR_GetSystemInfo VBoxNsprPR_GetSystemInfo +#define PR_GetPageSize VBoxNsprPR_GetPageSize +#define PR_GetPageShift VBoxNsprPR_GetPageShift +#define PR_GetNumberOfProcessors VBoxNsprPR_GetNumberOfProcessors +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Get the host' directory separator. +** Pathnames are then assumed to be of the form: +** []*() +*/ + +NSPR_API(char) PR_GetDirectorySeparator(void); + +/* +** OBSOLETE -- the function name is misspelled. +** Use PR_GetDirectorySeparator instead. +*/ + +NSPR_API(char) PR_GetDirectorySepartor(void); + +/* +** Get the host' path separator. +** Paths are assumed to be of the form: +** []* +*/ + +NSPR_API(char) PR_GetPathSeparator(void); + +/* Types of information available via PR_GetSystemInfo(...) */ +typedef enum { + PR_SI_HOSTNAME, + PR_SI_SYSNAME, + PR_SI_RELEASE, + PR_SI_ARCHITECTURE +} PRSysInfo; + + +/* +** If successful returns a null termintated string in 'buf' for +** the information indicated in 'cmd'. If unseccussful the reason for +** the failure can be retrieved from PR_GetError(). +** +** The buffer is allocated by the caller and should be at least +** SYS_INFO_BUFFER_LENGTH bytes in length. +*/ + +#define SYS_INFO_BUFFER_LENGTH 256 + +NSPR_API(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen); + +/* +** Return the number of bytes in a page +*/ +NSPR_API(PRInt32) PR_GetPageSize(void); + +/* +** Return log2 of the size of a page +*/ +NSPR_API(PRInt32) PR_GetPageShift(void); + +/* +** PR_GetNumberOfProcessors() -- returns the number of CPUs +** +** Description: +** PR_GetNumberOfProcessors() extracts the number of processors +** (CPUs available in an SMP system) and returns the number. +** +** Parameters: +** none +** +** Returns: +** The number of available processors or -1 on error +** +*/ +NSPR_API(PRInt32) PR_GetNumberOfProcessors( void ); + +PR_END_EXTERN_C + +#endif /* prsystem_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prthread.h b/src/libs/xpcom18a4/nsprpub/pr/include/prthread.h new file mode 100644 index 00000000..bc2be5e1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prthread.h @@ -0,0 +1,305 @@ +/* -*- 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 prthread_h___ +#define prthread_h___ + +/* +** API for NSPR threads. On some architectures (MAC and WIN16 +** notably) pre-emptibility is not guaranteed. Hard priority scheduling +** is not guaranteed, so programming using priority based synchronization +** is a no-no. +** +** NSPR threads are scheduled based loosly on their client set priority. +** In general, a thread of a higher priority has a statistically better +** chance of running relative to threads of lower priority. However, +** NSPR uses multiple strategies to provide execution vehicles for thread +** abstraction of various host platforms. As it turns out, there is little +** NSPR can do to affect the scheduling attributes of "GLOBAL" threads. +** However, a semblance of GLOBAL threads is used to implement "LOCAL" +** threads. An arbitrary number of such LOCAL threads can be assigned to +** a single GLOBAL thread. +** +** For scheduling, NSPR will attempt to run the highest priority LOCAL +** thread associated with a given GLOBAL thread. It is further assumed +** that the host OS will apply some form of "fair" scheduling on the +** GLOBAL threads. +** +** Threads have a "system flag" which when set indicates the thread +** doesn't count for determining when the process should exit (the +** process exits when the last user thread exits). +** +** Threads also have a "scope flag" which controls whether the threads +** are scheduled in the local scope or scheduled by the OS globally. This +** indicates whether a thread is permanently bound to a native OS thread. +** An unbound thread competes for scheduling resources in the same process. +** +** Another flag is "state flag" which control whether the thread is joinable. +** It allows other threads to wait for the created thread to reach completion. +** +** Threads can have "per-thread-data" attached to them. Each thread has a +** per-thread error number and error string which are updated when NSPR +** operations fail. +*/ +#include "prtypes.h" +#include "prinrval.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateThread VBoxNsprPR_CreateThread +#define PR_JoinThread VBoxNsprPR_JoinThread +#define PR_Sleep VBoxNsprPR_Sleep +#define PR_GetCurrentThread VBoxNsprPR_GetCurrentThread +#define PR_GetThreadState VBoxNsprPR_GetThreadState +#define PR_SetThreadPrivate VBoxNsprPR_SetThreadPrivate +#define PR_GetThreadPrivate VBoxNsprPR_GetThreadPrivate +#define PR_NewThreadPrivateIndex VBoxNsprPR_NewThreadPrivateIndex +#define PR_GetThreadPriority VBoxNsprPR_GetThreadPriority +#define PR_SetThreadPriority VBoxNsprPR_SetThreadPriority +#define PR_Interrupt VBoxNsprPR_Interrupt +#define PR_ClearInterrupt VBoxNsprPR_ClearInterrupt +#define PR_BlockInterrupt VBoxNsprPR_BlockInterrupt +#define PR_UnblockInterrupt VBoxNsprPR_UnblockInterrupt +#define PR_GetThreadScope VBoxNsprPR_GetThreadScope +#define PR_GetThreadType VBoxNsprPR_GetThreadType +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRThread PRThread; +typedef struct PRThreadStack PRThreadStack; + +typedef enum PRThreadType { + PR_USER_THREAD, + PR_SYSTEM_THREAD +} PRThreadType; + +typedef enum PRThreadScope { + PR_LOCAL_THREAD, + PR_GLOBAL_THREAD, + PR_GLOBAL_BOUND_THREAD +} PRThreadScope; + +typedef enum PRThreadState { + PR_JOINABLE_THREAD, + PR_UNJOINABLE_THREAD +} PRThreadState; + +typedef enum PRThreadPriority +{ + PR_PRIORITY_FIRST = 0, /* just a placeholder */ + PR_PRIORITY_LOW = 0, /* the lowest possible priority */ + PR_PRIORITY_NORMAL = 1, /* most common expected priority */ + PR_PRIORITY_HIGH = 2, /* slightly more aggressive scheduling */ + PR_PRIORITY_URGENT = 3, /* it does little good to have more than one */ + PR_PRIORITY_LAST = 3 /* this is just a placeholder */ +} PRThreadPriority; + +/* +** Create a new thread: +** "type" is the type of thread to create +** "start(arg)" will be invoked as the threads "main" +** "priority" will be created thread's priority +** "scope" will specify whether the thread is local or global +** "state" will specify whether the thread is joinable or not +** "stackSize" the size of the stack, in bytes. The value can be zero +** and then a machine specific stack size will be chosen. +** +** This can return NULL if some kind of error occurs, such as if memory is +** tight. +** +** If you want the thread to start up waiting for the creator to do +** something, enter a lock before creating the thread and then have the +** threads start routine enter and exit the same lock. When you are ready +** for the thread to run, exit the lock. +** +** If you want to detect the completion of the created thread, the thread +** should be created joinable. Then, use PR_JoinThread to synchrnoize the +** termination of another thread. +** +** When the start function returns the thread exits. If it is the last +** PR_USER_THREAD to exit then the process exits. +*/ +NSPR_API(PRThread*) PR_CreateThread(PRThreadType type, + void (PR_CALLBACK *start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize); + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is blocked until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will operate successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +NSPR_API(PRStatus) PR_JoinThread(PRThread *thread); + +/* +** Return the current thread object for the currently running code. +** Never returns NULL. +*/ +NSPR_API(PRThread*) PR_GetCurrentThread(void); +#ifndef NO_NSPR_10_SUPPORT +#define PR_CurrentThread() PR_GetCurrentThread() /* for nspr1.0 compat. */ +#endif /* NO_NSPR_10_SUPPORT */ + +/* +** Get the priority of "thread". +*/ +NSPR_API(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread); + +/* +** Change the priority of the "thread" to "priority". +*/ +NSPR_API(void) PR_SetThreadPriority(PRThread *thread, PRThreadPriority priority); + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** Each index is associationed with a destructor function ('dtor'). The function +** may be specified as NULL when the index is created. If it is not NULL, the +** function will be called when: +** - the thread exits and the private data for the associated index +** is not NULL, +** - new thread private data is set and the current private data is +** not NULL. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** is NULL, and upon thread creation the value associated with all indices for +** that thread is NULL. +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ +typedef void (PR_CALLBACK *PRThreadPrivateDTOR)(void *priv); + +NSPR_API(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR destructor); + +/* +** Define some per-thread-private data. +** "tpdIndex" is an index into the per-thread private data table +** "priv" is the per-thread-private data +** +** If the per-thread private data table has a previously registered +** destructor function and a non-NULL per-thread-private data value, +** the destructor function is invoked. +** +** This can return PR_FAILURE if the index is invalid. +*/ +NSPR_API(PRStatus) PR_SetThreadPrivate(PRUintn tpdIndex, void *priv); + +/* +** Recover the per-thread-private data for the current thread. "tpdIndex" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +** A thread can only get access to its own thread-specific-data. +*/ +NSPR_API(void*) PR_GetThreadPrivate(PRUintn tpdIndex); + +/* +** This routine sets the interrupt request for a target thread. The interrupt +** request remains in the thread's state until it is delivered exactly once +** or explicitly canceled. +** +** A thread that has been interrupted will fail all NSPR blocking operations +** that return a PRStatus (I/O, waiting on a condition, etc). +** +** PR_Interrupt may itself fail if the target thread is invalid. +*/ +NSPR_API(PRStatus) PR_Interrupt(PRThread *thread); + +/* +** Clear the interrupt request for the calling thread. If no such request +** is pending, this operation is a noop. +*/ +NSPR_API(void) PR_ClearInterrupt(void); + +/* +** Block the interrupt for the calling thread. +*/ +NSPR_API(void) PR_BlockInterrupt(void); + +/* +** Unblock the interrupt for the calling thread. +*/ +NSPR_API(void) PR_UnblockInterrupt(void); + +/* +** Make the current thread sleep until "ticks" time amount of time +** has expired. If "ticks" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to calling PR_Yield. Calling PR_Sleep with an argument +** equivalent to PR_INTERVAL_NO_TIMEOUT is an error and will result +** in a PR_FAILURE error return. +*/ +NSPR_API(PRStatus) PR_Sleep(PRIntervalTime ticks); + +/* +** Get the scoping of this thread. +*/ +NSPR_API(PRThreadScope) PR_GetThreadScope(const PRThread *thread); + +/* +** Get the type of this thread. +*/ +NSPR_API(PRThreadType) PR_GetThreadType(const PRThread *thread); + +/* +** Get the join state of this thread. +*/ +NSPR_API(PRThreadState) PR_GetThreadState(const PRThread *thread); + +PR_END_EXTERN_C + +#endif /* prthread_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prtime.h b/src/libs/xpcom18a4/nsprpub/pr/include/prtime.h new file mode 100644 index 00000000..fe86d365 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prtime.h @@ -0,0 +1,311 @@ +/* -*- 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 ***** */ + +/* + *---------------------------------------------------------------------- + * + * prtime.h -- + * + * NSPR date and time functions + * + *----------------------------------------------------------------------- + */ + +#ifndef prtime_h___ +#define prtime_h___ + +#include "prlong.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_Now VBoxNsprPR_Now +#define PR_ExplodeTime VBoxNsprPR_ExplodeTime +#define PR_ImplodeTime VBoxNsprPR_ImplodeTime +#define PR_NormalizeTime VBoxNsprPR_NormalizeTime +#define PR_LocalTimeParameters VBoxNsprPR_LocalTimeParameters +#define PR_GMTParameters VBoxNsprPR_GMTParameters +#define PR_USPacificTimeParameters VBoxNsprPR_USPacificTimeParameters +#define PR_ParseTimeString VBoxNsprPR_ParseTimeString +#define PR_FormatTime VBoxNsprPR_FormatTime +#define PR_FormatTimeUSEnglish VBoxNsprPR_FormatTimeUSEnglish +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/**********************************************************************/ +/************************* TYPES AND CONSTANTS ************************/ +/**********************************************************************/ + +#define PR_MSEC_PER_SEC 1000UL +#define PR_USEC_PER_SEC 1000000UL +#define PR_NSEC_PER_SEC 1000000000UL +#define PR_USEC_PER_MSEC 1000UL +#define PR_NSEC_PER_MSEC 1000000UL + +/* + * PRTime -- + * + * NSPR represents basic time as 64-bit signed integers relative + * to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT). + * (GMT is also known as Coordinated Universal Time, UTC.) + * The units of time are in microseconds. Negative times are allowed + * to represent times prior to the January 1970 epoch. Such values are + * intended to be exported to other systems or converted to human + * readable form. + * + * Notes on porting: PRTime corresponds to time_t in ANSI C. NSPR 1.0 + * simply uses PRInt64. + */ + +typedef PRInt64 PRTime; + +/* + * Time zone and daylight saving time corrections applied to GMT to + * obtain the local time of some geographic location + */ + +typedef struct PRTimeParameters { + PRInt32 tp_gmt_offset; /* the offset from GMT in seconds */ + PRInt32 tp_dst_offset; /* contribution of DST in seconds */ +} PRTimeParameters; + +/* + * PRExplodedTime -- + * + * Time broken down into human-readable components such as year, month, + * day, hour, minute, second, and microsecond. Time zone and daylight + * saving time corrections may be applied. If they are applied, the + * offsets from the GMT must be saved in the 'tm_params' field so that + * all the information is available to reconstruct GMT. + * + * Notes on porting: PRExplodedTime corrresponds to struct tm in + * ANSI C, with the following differences: + * - an additional field tm_usec; + * - replacing tm_isdst by tm_params; + * - the month field is spelled tm_month, not tm_mon; + * - we use absolute year, AD, not the year since 1900. + * The corresponding type in NSPR 1.0 is called PRTime. Below is + * a table of date/time type correspondence in the three APIs: + * API time since epoch time in components + * ANSI C time_t struct tm + * NSPR 1.0 PRInt64 PRTime + * NSPR 2.0 PRTime PRExplodedTime + */ + +typedef struct PRExplodedTime { + PRInt32 tm_usec; /* microseconds past tm_sec (0-99999) */ + PRInt32 tm_sec; /* seconds past tm_min (0-61, accomodating + up to two leap seconds) */ + PRInt32 tm_min; /* minutes past tm_hour (0-59) */ + PRInt32 tm_hour; /* hours past tm_day (0-23) */ + PRInt32 tm_mday; /* days past tm_mon (1-31, note that it + starts from 1) */ + PRInt32 tm_month; /* months past tm_year (0-11, Jan = 0) */ + PRInt16 tm_year; /* absolute year, AD (note that we do not + count from 1900) */ + + PRInt8 tm_wday; /* calculated day of the week + (0-6, Sun = 0) */ + PRInt16 tm_yday; /* calculated day of the year + (0-365, Jan 1 = 0) */ + + PRTimeParameters tm_params; /* time parameters used by conversion */ +} PRExplodedTime; + +/* + * PRTimeParamFn -- + * + * A function of PRTimeParamFn type returns the time zone and + * daylight saving time corrections for some geographic location, + * given the current time in GMT. The input argument gmt should + * point to a PRExplodedTime that is in GMT, i.e., whose + * tm_params contains all 0's. + * + * For any time zone other than GMT, the computation is intended to + * consist of two steps: + * - Figure out the time zone correction, tp_gmt_offset. This number + * usually depends on the geographic location only. But it may + * also depend on the current time. For example, all of China + * is one time zone right now. But this situation may change + * in the future. + * - Figure out the daylight saving time correction, tp_dst_offset. + * This number depends on both the geographic location and the + * current time. Most of the DST rules are expressed in local + * current time. If so, one should apply the time zone correction + * to GMT before applying the DST rules. + */ + +typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt); + +/**********************************************************************/ +/****************************** FUNCTIONS *****************************/ +/**********************************************************************/ + +/* + * The PR_Now routine returns the current time relative to the + * epoch, midnight, January 1, 1970 UTC. The units of the returned + * value are microseconds since the epoch. + * + * The values returned are not guaranteed to advance in a linear fashion + * due to the application of time correction protocols which synchronize + * computer clocks to some external time source. Consequently it should + * not be depended on for interval timing. + * + * The implementation is machine dependent. + * Cf. time_t time(time_t *tp) in ANSI C. + */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +NSPR_API(PRTime) +#endif +PR_Now(void); + +/* + * Expand time binding it to time parameters provided by PRTimeParamFn. + * The calculation is envisoned to proceed in the following steps: + * - From given PRTime, calculate PRExplodedTime in GMT + * - Apply the given PRTimeParamFn to the GMT that we just calculated + * to obtain PRTimeParameters. + * - Add the PRTimeParameters offsets to GMT to get the local time + * as PRExplodedTime. + */ + +NSPR_API(void) PR_ExplodeTime( + PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded); + +/* Reverse operation of PR_ExplodeTime */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +NSPR_API(PRTime) +#endif +PR_ImplodeTime(const PRExplodedTime *exploded); + +/* + * Adjust exploded time to normalize field overflows after manipulation. + * Note that the following fields of PRExplodedTime should not be + * manipulated: + * - tm_month and tm_year: because the number of days in a month and + * number of days in a year are not constant, it is ambiguous to + * manipulate the month and year fields, although one may be tempted + * to. For example, what does "a month from January 31st" mean? + * - tm_wday and tm_yday: these fields are calculated by NSPR. Users + * should treat them as "read-only". + */ + +NSPR_API(void) PR_NormalizeTime( + PRExplodedTime *exploded, PRTimeParamFn params); + +/**********************************************************************/ +/*********************** TIME PARAMETER FUNCTIONS *********************/ +/**********************************************************************/ + +/* Time parameters that suit current host machine */ +NSPR_API(PRTimeParameters) PR_LocalTimeParameters(const PRExplodedTime *gmt); + +/* Time parameters that represent Greenwich Mean Time */ +NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt); + +/* + * Time parameters that represent the US Pacific Time Zone, with the + * current daylight saving time rules (for testing only) + */ +NSPR_API(PRTimeParameters) PR_USPacificTimeParameters(const PRExplodedTime *gmt); + +/* + * This parses a time/date string into a PRTime + * (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +NSPR_API(PRStatus) PR_ParseTimeString ( + const char *string, + PRBool default_to_gmt, + PRTime *result); + +/* + * FIXME: should we also have a formatting function, such as asctime, ctime, + * and strftime in standard C library? But this would involve + * internationalization issues. Might want to provide a US English version. + */ + +/**********************************************************************/ +/*********************** OLD COMPATIBILITYFUNCTIONS *******************/ +/**********************************************************************/ +#ifndef NO_NSPR_10_SUPPORT + +/* Format a time value into a buffer. Same semantics as strftime() */ +NSPR_API(PRUint32) PR_FormatTime(char *buf, int buflen, const char *fmt, + const PRExplodedTime *tm); + +/* Format a time value into a buffer. Time is always in US English format, regardless + * of locale setting. + */ +NSPR_API(PRUint32) +PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize, + const char* format, const PRExplodedTime* tm ); + +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* prtime_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prtpool.h b/src/libs/xpcom18a4/nsprpub/pr/include/prtpool.h new file mode 100644 index 00000000..bf083ccb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prtpool.h @@ -0,0 +1,130 @@ +/* -*- 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 ***** */ + +#ifndef prtpool_h___ +#define prtpool_h___ + +#include "prtypes.h" +#include "prthread.h" +#include "prio.h" +#include "prerror.h" + +/* + * NOTE: + * THIS API IS A PRELIMINARY VERSION IN NSPR 4.0 AND IS SUBJECT TO + * CHANGE + */ + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateThreadPool VBoxNsprPR_CreateThreadPool +#define PR_QueueJobPR_QueueJob_Read VBoxNsprPR_QueueJobPR_QueueJob_Read +#define PR_QueueJob VBoxNsprPR_QueueJob +#define PR_QueueJob_Read VBoxNsprPR_QueueJob_Read +#define PR_QueueJob_Write VBoxNsprPR_QueueJob_Write +#define PR_QueueJob_Accept VBoxNsprPR_QueueJob_Accept +#define PR_QueueJob_Connect VBoxNsprPR_QueueJob_Connect +#define PR_QueueJob_Timer VBoxNsprPR_QueueJob_Timer +#define PR_CancelJob VBoxNsprPR_CancelJob +#define PR_JoinJob VBoxNsprPR_JoinJob +#define PR_ShutdownThreadPool VBoxNsprPR_ShutdownThreadPool +#define PR_JoinThreadPool VBoxNsprPR_JoinThreadPool +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct PRJobIoDesc { + PRFileDesc *socket; + PRErrorCode error; + PRIntervalTime timeout; +} PRJobIoDesc; + +typedef struct PRThreadPool PRThreadPool; +typedef struct PRJob PRJob; +typedef void (PR_CALLBACK *PRJobFn) (void *arg); + +/* Create thread pool */ +NSPR_API(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize); + +/* queue a job */ +NSPR_API(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable); + +/* queue a job, when a socket is readable */ +NSPR_API(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket is writeable */ +NSPR_API(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a socket has a pending connection */ +NSPR_API(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, + PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when the socket connection to addr succeeds or fails */ +NSPR_API(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable); + +/* queue a job, when a timer exipres */ +NSPR_API(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable); +/* cancel a job */ +NSPR_API(PRStatus) +PR_CancelJob(PRJob *job); + +/* join a job */ +NSPR_API(PRStatus) +PR_JoinJob(PRJob *job); + +/* shutdown pool */ +NSPR_API(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool); + +/* join pool, wait for exit of all threads */ +NSPR_API(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool); + +PR_END_EXTERN_C + +#endif /* prtpool_h___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prtrace.h b/src/libs/xpcom18a4/nsprpub/pr/include/prtrace.h new file mode 100644 index 00000000..4e8a6a5f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prtrace.h @@ -0,0 +1,692 @@ +/* -*- 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 prtrace_h___ +#define prtrace_h___ +/* +** prtrace.h -- NSPR's Trace Facility. +** +** The Trace Facility provides a means to trace application +** program events within a process. When implementing an +** application program an engineer may insert a "Trace" function +** call, passing arguments to be traced. The "Trace" function +** combines the user trace data with identifying data and +** writes this data in time ordered sequence into a circular +** in-memory buffer; when the buffer fills, it wraps. +** +** Functions are provided to set and/or re-configure the size of +** the trace buffer, control what events are recorded in the +** buffer, enable and disable tracing based on specific user +** supplied data and other control functions. Methods are provided +** to record the trace entries in the in-memory trace buffer to +** a file. +** +** Tracing may cause a performance degredation to the application +** depending on the number and placement of calls to the tracing +** facility. When tracing is compiled in and all tracing is +** disabled via the runtime controls, the overhead should be +** minimal. ... Famous last words, eh? +** +** When DEBUG is defined at compile time, the Trace Facility is +** compiled as part of NSPR and any application using NSPR's +** header files will have tracing compiled in. When DEBUG is not +** defined, the Trace Facility is not compiled into NSPR nor +** exported in its header files. If the Trace Facility is +** desired in a non-debug build, then FORCE_NSPR_TRACE may be +** defined at compile time for both the optimized build of NSPR +** and the application. NSPR and any application using NSPR's +** Trace Facility must be compiled with the same level of trace +** conditioning or unresolved references may be realized at link +** time. +** +** For any of the Trace Facility methods that requires a trace +** handle as an input argument, the caller must ensure that the +** trace handle argument is valid. An invalid trace handle +** argument may cause unpredictable results. +** +** Trace Facility methods are thread-safe and SMP safe. +** +** Users of the Trace Facility should use the defined macros to +** invoke trace methods, not the function calls directly. e.g. +** PR_TRACE( h1,0,1,2, ...); not PR_Trace(h1,0,1,2, ...); +** +** Application designers should be aware of the effects of +** debug and optimized build differences when using result of the +** Trace Facility macros in expressions. +** +** See Also: prcountr.h +** +** /lth. 08-Jun-1998. +*/ + +#include "prtypes.h" +#include "prthread.h" +#include "prtime.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_CreateTrace VBoxNsprPR_CreateTrace +#define PR_DestroyTrace VBoxNsprPR_DestroyTrace +#define PR_Trace VBoxNsprPR_Trace +#define PR_SetTraceOption VBoxNsprPR_SetTraceOption +#define PR_GetTraceOption VBoxNsprPR_GetTraceOption +#define PR_GetTraceHandleFromName VBoxNsprPR_GetTraceHandleFromName +#define PR_GetTraceNameFromHandle VBoxNsprPR_GetTraceNameFromHandle +#define PR_FindNextTraceQname VBoxNsprPR_FindNextTraceQname +#define PR_FindNextTraceRname VBoxNsprPR_FindNextTraceRname +#define PR_RecordTraceEntries VBoxNsprPR_RecordTraceEntries +#define PR_GetTraceEntries VBoxNsprPR_GetTraceEntries +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* +** Opaque type for the trace handle +** ... Don't even think about looking in here. +** +*/ +typedef void * PRTraceHandle; + +/* +** PRTraceEntry -- A trace entry in the in-memory trace buffer +** looks like this. +** +*/ +typedef struct PRTraceEntry +{ + PRThread *thread; /* The thread creating the trace entry */ + PRTraceHandle handle; /* PRTraceHandle creating the trace entry */ + PRTime time; /* Value of PR_Now() at time of trace entry */ + PRUint32 userData[8]; /* user supplied trace data */ +} PRTraceEntry; + +/* +** PRTraceOption -- command operands to +** PR_[Set|Get]TraceOption(). See descriptive meanings there. +** +*/ +typedef enum PRTraceOption +{ + PRTraceBufSize, + PRTraceEnable, + PRTraceDisable, + PRTraceSuspend, + PRTraceResume, + PRTraceSuspendRecording, + PRTraceResumeRecording, + PRTraceLockHandles, + PRTraceUnLockHandles, + PRTraceStopRecording +} PRTraceOption; + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DEFINE_TRACE() -- Define a PRTraceHandle +** +** DESCRIPTION: PR_DEFINE_TRACE() is used to define a trace +** handle. +** +*/ +#define PR_DEFINE_TRACE(name) PRTraceHandle name + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_INIT_TRACE_HANDLE() -- Set the value of a PRTraceHandle +** +** DESCRIPTION: +** PR_INIT_TRACE_HANDLE() sets the value of a PRTraceHandle +** to value. e.g. PR_INIT_TRACE_HANDLE( myHandle, NULL ); +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_INIT_TRACE_HANDLE(handle,value)\ + (handle) = (PRCounterHandle)(value) +#else +#define PR_INIT_TRACE_HANDLE(handle,value) +#endif + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_CreateTrace() -- Create a trace handle +** +** DESCRIPTION: +** PR_CreateTrace() creates a new trace handle. Tracing is +** enabled for this handle when it is created. The trace handle +** is intended for use in other Trace Facility calls. +** +** PR_CreateTrace() registers the QName, RName and description +** data so that this data can be retrieved later. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** description: pointer to string. Descriptive data about this +** trace handle. +** +** OUTPUTS: +** Creates the trace handle. +** Registers the QName and RName with the trace facility. +** +** RETURNS: +** PRTraceHandle +** +** RESTRICTIONS: +** qName is limited to 31 characters. +** rName is limited to 31 characters. +** description is limited to 255 characters. +** +*/ +#define PRTRACE_NAME_MAX 31 +#define PRTRACE_DESC_MAX 255 + +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_CREATE_TRACE(handle,qName,rName,description)\ + (handle) = PR_CreateTrace((qName),(rName),(description)) +#else +#define PR_CREATE_TRACE(handle,qName,rName,description) +#endif + +NSPR_API(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_DestroyTrace() -- Destroy a trace handle +** +** DESCRIPTION: +** PR_DestroyTrace() removes the referenced trace handle and +** associated QName, RName and description data from the Trace +** Facility. +** +** INPUTS: handle. A PRTraceHandle +** +** OUTPUTS: +** The trace handle is unregistered. +** The QName, RName and description are removed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_DESTROY_TRACE(handle)\ + PR_DestroyTrace((handle)) +#else +#define PR_DESTROY_TRACE(handle) +#endif + +NSPR_API(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_Trace() -- Make a trace entry in the in-memory trace +** +** DESCRIPTION: +** PR_Trace() makes an entry in the in-memory trace buffer for +** the referenced trace handle. The next logically available +** PRTraceEntry is used; when the next trace entry would overflow +** the trace table, the table wraps. +** +** PR_Trace() for a specific trace handle may be disabled by +** calling PR_SetTraceOption() specifying PRTraceDisable for the +** trace handle to be disabled. +** +** INPUTS: +** handle: PRTraceHandle. The trace handle for this trace. +** +** userData[0..7]: unsigned 32bit integers. user supplied data +** that is copied into the PRTraceEntry +** +** OUTPUTS: +** A PRTraceEntry is (conditionally) formatted in the in-memory +** trace buffer. +** +** RETURNS: void. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7)\ + PR_Trace((handle),(ud0),(ud1),(ud2),(ud3),(ud4),(ud5),(ud6),(ud7)) +#else +#define PR_TRACE(handle,ud0,ud1,ud2,ud3,ud4,ud5,ud6,ud7) +#endif + +NSPR_API(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_SetTraceOption() -- Control the Trace Facility +** +** DESCRIPTION: +** PR_SetTraceOption() controls the Trace Facility. Depending on +** command and value, attributes of the Trace Facility may be +** changed. +** +** INPUTS: +** command: An enumerated value in the set of PRTraceOption. +** value: pointer to the data to be set. Type of the data is +** dependent on command; for each value of command, the type +** and meaning of dereferenced value is shown. +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** PRTraceEnable: PRTraceHandle. The trace handle to be +** enabled. +** +** PRTraceDisable: PRTraceHandle. The trace handle to be +** disabled. +** +** PRTraceSuspend: void. value must be NULL. All tracing is +** suspended. +** +** PRTraceResume: void. value must be NULL. Tracing for all +** previously enabled, prior to a PRTraceSuspend, is resumed. +** +** PRTraceStopRecording: void. value must be NULL. If recording +** (see: ** PR_RecordTraceEntries()) is being done, +** PRTraceStopRecording causes PR_RecordTraceEntries() to return +** to its caller. If recording is not being done, this function +** has no effect. +** +** PRTraceSuspendRecording: void. Must be NULL. If recording is +** being done, PRTraceSuspendRecording causes further writes to +** the trace file to be suspended. Data in the in-memory +** trace buffer that would ordinarily be written to the +** trace file will not be written. Trace entries will continue +** to be entered in the in-memory buffer. If the Trace Facility +** recording is already in a suspended state, the call has no +** effect. +** +** PRTraceResumeRecording: void. value must be NULL. If +** recording for the Trace Facility has been previously been +** suspended, this causes recording to resume. Recording resumes +** with the next in-memory buffer segment that would be written +** if trace recording had not been suspended. If recording is +** not currently suspended, the call has no effect. +** +** PRTraceLockHandles: void. value must be NULL. Locks the +** trace handle lock. While the trace handle lock is held, +** calls to PR_CreateTrace() will block until the lock is +** released. +** +** PRTraceUnlockHandles: void. value must be NULL. Unlocks the +** trace handle lock. +** +** OUTPUTS: +** The operation of the Trace Facility may be changed. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_SET_TRACE_OPTION(command,value)\ + PR_SetTraceOption((command),(value)) +#else +#define PR_SET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceOption() -- Retrieve settings from the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceOption() retrieves the current setting of the +** Trace Facility control depending on command. +** +** +** PRTraceBufSize: unsigned long: the size of the trace buffer, +** in bytes. +** +** +** INPUTS: +** command: one of the enumerated values in PRTraceOptions +** valid for PR_GetTraceOption(). +** +** OUTPUTS: +** dependent on command. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_OPTION(command,value)\ + PR_GetTraceOption((command),(value)) +#else +#define PR_GET_TRACE_OPTION(command,value) +#endif + +NSPR_API(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceHandleFromName() -- Retrieve an existing +** handle by name. +** +** DESCRIPTION: +** PR_GetTraceHandleFromName() retreives an existing tracehandle +** using the name specified by qName and rName. +** +** INPUTS: +** qName: pointer to string. QName for this trace handle. +** +** rName: pointer to string. RName for this trace handle. +** +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle associated with qName and rName or NULL when +** there is no match. +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName)\ + (handle) = PR_GetTraceHandleFromName((qName),(rName)) +#else +#define PR_GET_TRACE_HANDLE_FROM_NAME(handle,qName,rName) +#endif + +NSPR_API(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceNameFromHandle() -- Retreive trace name +** by bandle. +** +** DESCRIPTION: +** PR_GetTraceNameFromHandle() retreives the existing qName, +** rName, and description for the referenced trace handle. +** +** INPUTS: handle: PRTraceHandle. +** +** OUTPUTS: pointers to the Trace Facility's copy of qName, +** rName and description. ... Don't mess with these values. +** They're mine. +** +** RETURNS: void +** +** RESTRICTIONS: +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description)\ + PR_GetTraceNameFromHandle((handle),(qName),(rName),(description)) +#else +#define PR_GET_TRACE_NAME_FROM_HANDLE(handle,qName,rName,description) +#endif + +NSPR_API(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceQname() -- Retrieive a QName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceQname() retreives the first or next trace +** QName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the QName handles in the Trace database. +** +** INPUTS: +** handle: When NULL, PR_FindNextQname() returns the first QName +** handle. When a handle is a valid PRTraceHandle previously +** retreived using PR_FindNextQname() the next QName handle is +** retreived. +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindFirst/FindNext +** should be done under protection of the trace handle lock. +** See: PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_QNAME(next,handle)\ + (next) = PR_FindNextTraceQname((handle)) +#else +#define PR_FIND_NEXT_TRACE_QNAME(next,handle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_FindNextTraceRname() -- Retrieive an RName handle +** iterator. +** +** DESCRIPTION: +** PR_FindNextTraceRname() retreives the first or next trace +** RName handle, depending on the value of handle, from the trace +** database. The PRTraceHandle returned can be used as an +** iterator to traverse the RName handles in the Trace database. +** +** INPUTS: +** rhandle: When NULL, PR_FindNextRname() returns the first +** RName handle. When a handle is a valid PRTraceHandle +** previously retreived using PR_FindNextRname() the next RName +** handle is retreived. +** qhandle: A valid PRTraceHandle retruned from a previous call +** to PR_FIND_NEXT_TRACE_QNAME(). +** +** OUTPUTS: returned. +** +** RETURNS: +** PRTraceHandle or NULL when there are no trace handles. +** +** RESTRICTIONS: +** Iterating thru the trace handles via FindNext should be done +** under protection of the trace handle lock. See: ( +** PR_SetTraceOption( PRLockTraceHandles ). +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle)\ + (next) = PR_FindNextTraceRname((rhandle),(qhandle)) +#else +#define PR_FIND_NEXT_TRACE_RNAME(next,rhandle,qhandle) +#endif + +NSPR_API(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_RecordTraceEntries() -- Write trace entries to external media +** +** DESCRIPTION: +** PR_RecordTraceEntries() causes entries in the in-memory trace +** buffer to be written to external media. +** +** When PR_RecordTraceEntries() is called from an application +** thread, the function appears to block until another thread +** calls PR_SetTraceOption() with the PRTraceStopRecording +** option. This suggests that PR_RecordTraceEntries() should be +** called from a user supplied thread whose only job is to +** record trace entries. +** +** The environment variable NSPR_TRACE_LOG controls the operation +** of this function. When NSPR_TRACE_LOG is not defined in the +** environment, no recording of trace entries occurs. When +** NSPR_TRACE_LOG is defined, the value of its definition must be +** the filename of the file to receive the trace entry buffer. +** +** PR_RecordTraceEntries() attempts to record the in-memory +** buffer to a file, subject to the setting of the environment +** variable NSPR_TRACE_LOG. It is possible because of system +** load, the thread priority of the recording thread, number of +** active trace records being written over time, and other +** variables that some trace records can be lost. ... In other +** words: don't bet the farm on getting everything. +** +** INPUTS: none +** +** OUTPUTS: none +** +** RETURNS: PR_STATUS +** PR_SUCCESS no errors were found. +** PR_FAILURE errors were found. +** +** RESTRICTIONS: +** Only one thread can call PR_RecordTraceEntries() within a +** process. +** +** On error, PR_RecordTraceEntries() may return prematurely. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_RECORD_TRACE_ENTRIES()\ + PR_RecordTraceEntries() +#else +#define PR_RECORD_TRACE_ENTRIES() +#endif + +NSPR_API(void) + PR_RecordTraceEntries( + void +); + +/* ----------------------------------------------------------------------- +** FUNCTION: PR_GetTraceEntries() -- Retreive trace entries from +** the Trace Facility +** +** DESCRIPTION: +** PR_GetTraceEntries() retreives trace entries from the Trace +** Facility. Up to count trace entries are copied from the Trace +** Facility into buffer. Only those trace entries that have not +** been copied via a previous call to PR_GetTraceEntries() are +** copied. The actual number copied is placed in the PRInt32 +** variable pointed to by found. +** +** If more than count trace entries have entered the Trace +** Facility since the last call to PR_GetTraceEntries() +** a lost data condition is returned. In this case, the most +** recent count trace entries are copied into buffer and found is +** set to count. +** +** INPUTS: +** count. The number of trace entries to be copied into buffer. +** +** +** OUTPUTS: +** buffer. An array of PRTraceEntries. The buffer is supplied +** by the caller. +** +** found: 32bit signed integer. The number of PRTraceEntries +** actually copied. found is always less than or equal to count. +** +** RETURNS: +** zero when there is no lost data. +** non-zero when some PRTraceEntries have been lost. +** +** RESTRICTIONS: +** This is a real performance pig. The copy out operation is bad +** enough, but depending on then frequency of calls to the +** function, serious performance impact to the operating +** application may be realized. ... YMMV. +** +*/ +#if defined (DEBUG) || defined (FORCE_NSPR_TRACE) +#define PR_GET_TRACE_ENTRIES(buffer,count,found)\ + PR_GetTraceEntries((buffer),(count),(found)) +#else +#define PR_GET_TRACE_ENTRIES(buffer,count,found) +#endif + +NSPR_API(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +); + +PR_END_EXTERN_C + +#endif /* prtrace_h___ */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prtypes.h b/src/libs/xpcom18a4/nsprpub/pr/include/prtypes.h new file mode 100644 index 00000000..32218fd4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prtypes.h @@ -0,0 +1,570 @@ +/* -*- 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 ***** */ + +/* +** File: prtypes.h +** Description: Definitions of NSPR's basic types +** +** Prototypes and macros used to make up for deficiencies in ANSI environments +** that we have found. +** +** Since we do not wrap and all the other standard headers, authors +** of portable code will not know in general that they need these definitions. +** Instead of requiring these authors to find the dependent uses in their code +** and take the following steps only in those C files, we take steps once here +** for all C files. +**/ + +#ifndef prtypes_h___ +#define prtypes_h___ + +#ifdef MDCPUCFG +#include MDCPUCFG +#else +#include "prcpucfg.h" +#endif + +#include +#include + +/*********************************************************************** +** MACROS: PR_EXTERN +** PR_IMPLEMENT +** DESCRIPTION: +** These are only for externally visible routines and globals. For +** internal routines, just use "extern" for type checking and that +** will not export internal cross-file or forward-declared symbols. +** Define a macro for declaring procedures return types. We use this to +** deal with windoze specific type hackery for DLL definitions. Use +** PR_EXTERN when the prototype for the method is declared. Use +** PR_IMPLEMENT for the implementation of the method. +** +** Example: +** in dowhim.h +** PR_EXTERN( void ) DoWhatIMean( void ); +** in dowhim.c +** PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; } +** +** +***********************************************************************/ +#if defined(WIN32) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_BEOS) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) extern __declspec(dllexport) __type +#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(WIN16) + +#define PR_CALLBACK_DECL __cdecl + +#if defined(_WINDLL) +#define PR_EXPORT(__type) extern __type _cdecl _export _loadds +#define PR_IMPORT(__type) extern __type _cdecl _export _loadds +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export _loadds +#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* this must be .EXE */ +#define PR_EXPORT(__type) extern __type _cdecl _export +#define PR_IMPORT(__type) extern __type _cdecl _export +#define PR_EXPORT_DATA(__type) extern __type _export +#define PR_IMPORT_DATA(__type) extern __type _export + +#define PR_EXTERN(__type) extern __type _cdecl _export +#define PR_IMPLEMENT(__type) __type _cdecl _export +#define PR_EXTERN_DATA(__type) extern __type _export +#define PR_IMPLEMENT_DATA(__type) __type _export + +#define PR_CALLBACK __cdecl __loadds +#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK +#endif /* _WINDLL */ + +#elif defined(XP_MAC) + +#define PR_EXPORT(__type) extern __declspec(export) __type +#define PR_EXPORT_DATA(__type) extern __declspec(export) __type +#define PR_IMPORT(__type) extern __declspec(export) __type +#define PR_IMPORT_DATA(__type) extern __declspec(export) __type + +#define PR_EXTERN(__type) extern __declspec(export) __type +#define PR_IMPLEMENT(__type) __declspec(export) __type +#define PR_EXTERN_DATA(__type) extern __declspec(export) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2) && defined(__declspec) + +#define PR_EXPORT(__type) extern __declspec(dllexport) __type +#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPORT(__type) __declspec(dllimport) __type +#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type + +#define PR_EXTERN(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT(__type) __declspec(dllexport) __type +#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type +#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type + +#define PR_CALLBACK +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x + +#elif defined(XP_OS2_VACPP) + +#define PR_EXPORT(__type) extern __type +#define PR_EXPORT_DATA(__type) extern __type +#define PR_IMPORT(__type) extern __type +#define PR_IMPORT_DATA(__type) extern __type + +#define PR_EXTERN(__type) extern __type +#define PR_IMPLEMENT(__type) __type +#define PR_EXTERN_DATA(__type) extern __type +#define PR_IMPLEMENT_DATA(__type) __type +#define PR_CALLBACK _Optlink +#define PR_CALLBACK_DECL +#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK + +#else /* Unix */ + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define PR_EXPORT(__type) __attribute__((visibility("default"))) extern __type +# define PR_EXPORT_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT(__type) __attribute__((visibility("default"))) __type +# define PR_EXTERN_DATA(__type) __attribute__((visibility("default"))) extern __type +# define PR_IMPLEMENT_DATA(__type) __attribute__((visibility("default"))) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# else +# define PR_EXPORT(__type) extern __type +# define PR_EXPORT_DATA(__type) extern __type +# define PR_IMPORT(__type) extern __type +# define PR_IMPORT_DATA(__type) extern __type +# define PR_EXTERN(__type) extern __type +# define PR_IMPLEMENT(__type) __type +# define PR_EXTERN_DATA(__type) extern __type +# define PR_IMPLEMENT_DATA(__type) __type +# define PR_CALLBACK +# define PR_CALLBACK_DECL +# define PR_STATIC_CALLBACK(__x) static __x +# endif +#endif + +#if defined(_NSPR_BUILD_) +#define NSPR_API(__type) PR_EXPORT(__type) +#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type) +#else +#define NSPR_API(__type) PR_IMPORT(__type) +#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type) +#endif + +/*********************************************************************** +** MACROS: PR_BEGIN_MACRO +** PR_END_MACRO +** DESCRIPTION: +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +***********************************************************************/ +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/*********************************************************************** +** MACROS: PR_BEGIN_EXTERN_C +** PR_END_EXTERN_C +** DESCRIPTION: +** Macro shorthands for conditional C++ extern block delimiters. +***********************************************************************/ +#ifdef __cplusplus +#define PR_BEGIN_EXTERN_C extern "C" { +#define PR_END_EXTERN_C } +#else +#define PR_BEGIN_EXTERN_C +#define PR_END_EXTERN_C +#endif + +/*********************************************************************** +** MACROS: PR_BIT +** PR_BITMASK +** DESCRIPTION: +** Bit masking macros. XXX n must be <= 31 to be portable +***********************************************************************/ +#define PR_BIT(n) ((PRUint32)1 << (n)) +#define PR_BITMASK(n) (PR_BIT(n) - 1) + +/*********************************************************************** +** MACROS: PR_ROUNDUP +** PR_MIN +** PR_MAX +** PR_ABS +** DESCRIPTION: +** Commonly used macros for operations on compatible types. +***********************************************************************/ +#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) +#define PR_MIN(x,y) ((x)<(y)?(x):(y)) +#define PR_MAX(x,y) ((x)>(y)?(x):(y)) +#define PR_ABS(x) ((x)<0?-(x):(x)) + +PR_BEGIN_EXTERN_C + +/************************************************************************ +** TYPES: PRUint8 +** PRInt8 +** DESCRIPTION: +** The int8 types are known to be 8 bits each. There is no type that +** is equivalent to a plain "char". +************************************************************************/ +#if PR_BYTES_PER_BYTE == 1 +typedef unsigned char PRUint8; +/* +** Some cfront-based C++ compilers do not like 'signed char' and +** issue the warning message: +** warning: "signed" not implemented (ignored) +** For these compilers, we have to define PRInt8 as plain 'char'. +** Make sure that plain 'char' is indeed signed under these compilers. +*/ +#if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +#else +typedef signed char PRInt8; +#endif +#else +#error No suitable type for PRInt8/PRUint8 +#endif + +/************************************************************************ + * MACROS: PR_INT8_MAX + * PR_INT8_MIN + * PR_UINT8_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt8 or PRUint8. +************************************************************************/ + +#define PR_INT8_MAX 127 +#define PR_INT8_MIN (-128) +#define PR_UINT8_MAX 255U + +/************************************************************************ +** TYPES: PRUint16 +** PRInt16 +** DESCRIPTION: +** The int16 types are known to be 16 bits each. +************************************************************************/ +#if PR_BYTES_PER_SHORT == 2 +typedef unsigned short PRUint16; +typedef short PRInt16; +#else +#error No suitable type for PRInt16/PRUint16 +#endif + +/************************************************************************ + * MACROS: PR_INT16_MAX + * PR_INT16_MIN + * PR_UINT16_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt16 or PRUint16. +************************************************************************/ + +#define PR_INT16_MAX 32767 +#define PR_INT16_MIN (-32768) +#define PR_UINT16_MAX 65535U + +/************************************************************************ +** TYPES: PRUint32 +** PRInt32 +** DESCRIPTION: +** The int32 types are known to be 32 bits each. +************************************************************************/ +#if PR_BYTES_PER_INT == 4 +typedef unsigned int PRUint32; +typedef int PRInt32; +#define PR_INT32(x) x +#define PR_UINT32(x) x ## U +#elif PR_BYTES_PER_LONG == 4 +typedef unsigned long PRUint32; +typedef long PRInt32; +#define PR_INT32(x) x ## L +#define PR_UINT32(x) x ## UL +#else +#error No suitable type for PRInt32/PRUint32 +#endif + +/************************************************************************ + * MACROS: PR_INT32_MAX + * PR_INT32_MIN + * PR_UINT32_MAX + * DESCRIPTION: + * The maximum and minimum values of a PRInt32 or PRUint32. +************************************************************************/ + +#define PR_INT32_MAX PR_INT32(2147483647) +#define PR_INT32_MIN (-PR_INT32_MAX - 1) +#define PR_UINT32_MAX PR_UINT32(4294967295) + +/************************************************************************ +** TYPES: PRUint64 +** PRInt64 +** DESCRIPTION: +** The int64 types are known to be 64 bits each. Care must be used when +** declaring variables of type PRUint64 or PRInt64. Different hardware +** architectures and even different compilers have varying support for +** 64 bit values. The only guaranteed portability requires the use of +** the LL_ macros (see prlong.h). +************************************************************************/ +#ifdef HAVE_LONG_LONG +#if PR_BYTES_PER_LONG == 8 +typedef long PRInt64; +typedef unsigned long PRUint64; +#elif defined(WIN16) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#elif defined(WIN32) && !defined(__GNUC__) +typedef __int64 PRInt64; +typedef unsigned __int64 PRUint64; +#else +typedef long long PRInt64; +typedef unsigned long long PRUint64; +#endif /* PR_BYTES_PER_LONG == 8 */ +#else /* !HAVE_LONG_LONG */ +typedef struct { +#ifdef IS_LITTLE_ENDIAN + PRUint32 lo, hi; +#else + PRUint32 hi, lo; +#endif +} PRInt64; +typedef PRInt64 PRUint64; +#endif /* !HAVE_LONG_LONG */ + +/************************************************************************ +** TYPES: PRUintn +** PRIntn +** DESCRIPTION: +** The PRIntn types are most appropriate for automatic variables. They are +** guaranteed to be at least 16 bits, though various architectures may +** define them to be wider (e.g., 32 or even 64 bits). These types are +** never valid for fields of a structure. +************************************************************************/ +#if PR_BYTES_PER_INT >= 2 +typedef int PRIntn; +typedef unsigned int PRUintn; +#else +#error 'sizeof(int)' not sufficient for platform use +#endif + +/************************************************************************ +** TYPES: PRFloat64 +** DESCRIPTION: +** NSPR's floating point type is always 64 bits. +************************************************************************/ +typedef double PRFloat64; + +/************************************************************************ +** TYPES: PRSize +** DESCRIPTION: +** A type for representing the size of objects. +************************************************************************/ +typedef size_t PRSize; + + +/************************************************************************ +** TYPES: PROffset32, PROffset64 +** DESCRIPTION: +** A type for representing byte offsets from some location. +************************************************************************/ +typedef PRInt32 PROffset32; +typedef PRInt64 PROffset64; + +/************************************************************************ +** TYPES: PRPtrDiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef ptrdiff_t PRPtrdiff; + +/************************************************************************ +** TYPES: PRUptrdiff +** DESCRIPTION: +** A type for pointer difference. Variables of this type are suitable +** for storing a pointer or pointer sutraction. +************************************************************************/ +typedef unsigned long PRUptrdiff; + +/************************************************************************ +** TYPES: PRBool +** DESCRIPTION: +** Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE +** for clarity of target type in assignments and actual arguments. Use +** 'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans +** juast as you would C int-valued conditions. +************************************************************************/ +typedef PRIntn PRBool; +#define PR_TRUE 1 +#define PR_FALSE 0 + +/************************************************************************ +** TYPES: PRPackedBool +** DESCRIPTION: +** Use PRPackedBOol within structs where bitfields are not desireable +** but minimum and consistant overhead matters. +************************************************************************/ +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +#ifdef MOZ_UNICODE +/* + * EXPERIMENTAL: This type may be removed in a future release. + */ +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ +#if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +#else +typedef PRUint16 PRUnichar; +#endif +#endif +#endif /* MOZ_UNICODE */ + +/* +** WARNING: The undocumented data types PRWord and PRUword are +** only used in the garbage collection and arena code. Do not +** use PRWord and PRUword in new code. +** +** A PRWord is an integer that is the same size as a void*. +** It implements the notion of a "word" in the Java Virtual +** Machine. (See Sec. 3.4 "Words", The Java Virtual Machine +** Specification, Addison-Wesley, September 1996. +** http://java.sun.com/docs/books/vmspec/index.html.) +*/ +typedef long PRWord; +typedef unsigned long PRUword; + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions until pr=>ds transition is done ***/ +/********************** Also, we are still using NSPR 1.0. GC ******************/ +/* +** Fundamental NSPR macros, used nearly everywhere. +*/ + +#define PR_PUBLIC_API PR_IMPLEMENT + +/* +** Macro body brackets so that macros with compound statement definitions +** behave syntactically more like functions when called. +*/ +#define NSPR_BEGIN_MACRO do { +#define NSPR_END_MACRO } while (0) + +/* +** Macro shorthands for conditional C++ extern block delimiters. +*/ +#ifdef NSPR_BEGIN_EXTERN_C +#undef NSPR_BEGIN_EXTERN_C +#endif +#ifdef NSPR_END_EXTERN_C +#undef NSPR_END_EXTERN_C +#endif + +#ifdef __cplusplus +#define NSPR_BEGIN_EXTERN_C extern "C" { +#define NSPR_END_EXTERN_C } +#else +#define NSPR_BEGIN_EXTERN_C +#define NSPR_END_EXTERN_C +#endif + +#ifdef XP_MAC +#include "protypes.h" +#else +#include "obsolete/protypes.h" +#endif + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* prtypes_h___ */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prvrsion.h b/src/libs/xpcom18a4/nsprpub/pr/include/prvrsion.h new file mode 100644 index 00000000..eb8e1e61 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prvrsion.h @@ -0,0 +1,137 @@ +/* -*- 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 ***** */ + + +/* author: jstewart */ + +#if defined(_PRVERSION_H) +#else +#define _PRVERSION_H + +#include "prtypes.h" + +PR_BEGIN_EXTERN_C + +/* All components participating in the PR version protocol must expose + * a structure and a function. The structure is defined below and named + * according to the naming conventions outlined further below. The function + * is called libVersionPoint and returns a pointer to this structure. + */ + +/* on NT, always pack the structure the same. */ +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +typedef struct { + /* + * The first field defines which version of this structure is in use. + * At this time, only version 2 is specified. If this value is not + * 2, you must read no further into the structure. + */ + PRInt32 version; + + /* for Version 2, this is the body format. */ + PRInt64 buildTime; /* 64 bits - usecs since midnight, 1/1/1970 */ + char * buildTimeString;/* a human readable version of the time */ + + PRUint8 vMajor; /* Major version of this component */ + PRUint8 vMinor; /* Minor version of this component */ + PRUint8 vPatch; /* Patch level of this component */ + + PRBool beta; /* true if this is a beta component */ + PRBool debug; /* true if this is a debug component */ + PRBool special; /* true if this component is a special build */ + + char * filename; /* The original filename */ + char * description; /* description of this component */ + char * security; /* level of security in this component */ + char * copyright; /* The copyright for this file */ + char * comment; /* free form field for misc usage */ + char * specialString; /* the special variant for this build */ +} PRVersionDescription; + +/* on NT, restore the previous packing */ +#ifdef _WIN32 +#pragma pack(pop) +#endif + +/* + * All components must define an entrypoint named libVersionPoint which + * is of type versionEntryPointType. + * + * For example, for a library named libfoo, we would have: + * + * PRVersionDescription prVersionDescription_libfoo = + * { + * ... + * }; + * + * PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) + * { + * return &prVersionDescription_libfoo; + * } + */ +typedef const PRVersionDescription *(*versionEntryPointType)(void); + +/* + * Where you declare your libVersionPoint, do it like this: + * PR_IMPLEMENT(const PRVersionDescription *) libVersionPoint(void) { + * fill it in... + * } + */ + +/* + * NAMING CONVENTION FOR struct + * + * all components should also expose a static PRVersionDescription + * The name of the struct should be calculated as follows: + * Take the value of filename. (If filename is not specified, calculate + * a short, unique string.) Convert all non-alphanumeric characters + * to '_'. To this, prepend "PRVersionDescription_". Thus for libfoo.so, + * the symbol name is "PRVersionDescription_libfoo_so". + * so the file should have + * PRVersionDescription PRVersionDescription_libfoo_so { fill it in }; + * on NT, this file should be declspec export. + */ + +PR_END_EXTERN_C + +#endif /* defined(_PRVERSION_H) */ + +/* prvrsion.h */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/include/prwin16.h b/src/libs/xpcom18a4/nsprpub/pr/include/prwin16.h new file mode 100644 index 00000000..215b0514 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/include/prwin16.h @@ -0,0 +1,196 @@ +/* -*- 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 prwin16_h___ +#define prwin16_h___ + +/* +** Condition use of this header on platform. +*/ +#if (defined(XP_PC) && !defined(_WIN32) && !defined(XP_OS2) && defined(MOZILLA_CLIENT)) || defined(WIN16) +#include + +PR_BEGIN_EXTERN_C +/* +** Win16 stdio special case. +** To get stdio to work for Win16, all calls to printf() and related +** things must be called from the environment of the .EXE; calls to +** printf() from the .DLL send output to the bit-bucket. +** +** To make sure that PR_fprintf(), and related functions, work correctly, +** the actual stream I/O to stdout, stderr, stdin must be done in the +** .EXE. To do this, a hack is placed in _MD_Write() such that the +** fd for stdio handles results in a call to the .EXE. +** +** file w16stdio.c contains the functions that get called from NSPR +** to do the actual I/O. w16stdio.o must be statically linked with +** any application needing stdio for Win16. +** +** The address of these functions must be made available to the .DLL +** so he can call back to the .EXE. To do this, function +** PR_MD_RegisterW16StdioCallbacks() is called from the .EXE. +** The arguments are the functions defined in w16stdio.c +** At runtime, MD_Write() calls the registered functions, if any +** were registered. +** +** prinit.h contains a macro PR_STDIO_INIT() that calls the registration +** function for Win16; For other platforms, the macro is a No-Op. +** +** Note that stdio is not operational at all on Win16 GUI applications. +** This special case exists to provide stdio capability from the NSPR +** .DLL for command line applications only. NSPR's test cases are +** almost exclusively command line applications. +** +** See also: w16io.c, w16stdio.c +*/ +typedef PRInt32 (PR_CALLBACK *PRStdinRead)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStdoutWrite)( void *buf, PRInt32 amount); +typedef PRInt32 (PR_CALLBACK *PRStderrWrite)( void *buf, PRInt32 amount); + +NSPR_API(PRStatus) +PR_MD_RegisterW16StdioCallbacks( + PRStdinRead inReadf, /* i: function pointer for stdin read */ + PRStdoutWrite outWritef, /* i: function pointer for stdout write */ + PRStderrWrite errWritef /* i: function pointer for stderr write */ + ); + +NSPR_API(PRInt32) +_PL_W16StdioWrite( void *buf, PRInt32 amount ); + +NSPR_API(PRInt32) +_PL_W16StdioRead( void *buf, PRInt32 amount ); + +#define PR_STDIO_INIT() PR_MD_RegisterW16StdioCallbacks( \ + _PL_W16StdioRead, _PL_W16StdioWrite, _PL_W16StdioWrite ); \ + PR_INIT_CALLBACKS(); + +/* +** Win16 hackery. +** +*/ +struct PRMethodCallbackStr { + int (PR_CALLBACK *auxOutput)(const char *outputString); + size_t (PR_CALLBACK *strftime)(char *s, size_t len, const char *fmt, const struct tm *p); + void * (PR_CALLBACK *malloc)( size_t size ); + void * (PR_CALLBACK *calloc)(size_t n, size_t size ); + void * (PR_CALLBACK *realloc)( void* old_blk, size_t size ); + void (PR_CALLBACK *free)( void *ptr ); + void * (PR_CALLBACK *getenv)( const char *name); + int (PR_CALLBACK *putenv)( const char *assoc); +/* void * (PR_CALLBACK *perror)( const char *prefix ); */ +}; + +NSPR_API(void) PR_MDRegisterCallbacks(struct PRMethodCallbackStr *); + +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ); +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ); +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ); +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ); +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ); +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ); +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ); +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ); + +/* +** Hackery! +** +** These functions are provided as static link points. +** This is to satisfy the quick port of Gromit to NSPR 2.0 +** ... Don't do this! ... alas, It may never go away. +** +*/ +NSPR_API(int) PR_MD_printf(const char *, ...); +NSPR_API(void) PR_MD_exit(int); +NSPR_API(size_t) PR_MD_strftime(char *, size_t, const char *, const struct tm *); +NSPR_API(int) PR_MD_sscanf(const char *, const char *, ...); +NSPR_API(void*) PR_MD_malloc( size_t size ); +NSPR_API(void*) PR_MD_calloc( size_t n, size_t size ); +NSPR_API(void*) PR_MD_realloc( void* old_blk, size_t size ); +NSPR_API(void) PR_MD_free( void *ptr ); +NSPR_API(char*) PR_MD_getenv( const char *name ); +NSPR_API(int) PR_MD_putenv( const char *assoc ); +NSPR_API(int) PR_MD_fprintf(FILE *fPtr, const char *fmt, ...); + +#define PR_INIT_CALLBACKS() \ + { \ + static struct PRMethodCallbackStr cbf = { \ + _PL_W16CallBackPuts, \ + _PL_W16CallBackStrftime, \ + _PL_W16CallBackMalloc, \ + _PL_W16CallBackCalloc, \ + _PL_W16CallBackRealloc, \ + _PL_W16CallBackFree, \ + _PL_W16CallBackGetenv, \ + _PL_W16CallBackPutenv, \ + }; \ + PR_MDRegisterCallbacks( &cbf ); \ + } + + +/* +** Get the exception context for Win16 MFC applications threads +*/ +NSPR_API(void *) PR_W16GetExceptionContext(void); +/* +** Set the exception context for Win16 MFC applications threads +*/ +NSPR_API(void) PR_W16SetExceptionContext(void *context); + +PR_END_EXTERN_C +#else +/* +** For platforms other than Win16, define +** PR_STDIO_INIT() as a No-Op. +*/ +#define PR_STDIO_INIT() +#endif /* WIN16 || MOZILLA_CLIENT */ + +#endif /* prwin16_h___ */ + + + + + + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/.cvsignore new file mode 100644 index 00000000..41a1bd2b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/.cvsignore @@ -0,0 +1,2 @@ +Makefile +_pr_bld.h diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/Makefile.in new file mode 100644 index 00000000..c15e2153 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/Makefile.in @@ -0,0 +1,422 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = io linking malloc md memory misc threads + +# For VAC++ 4 geticcdata rule in config/OS2.mk +ifeq ($(MOZ_OS2_TOOLS),VACPP) +CSRCS = prvrsion.c +endif + +ifeq ($(USE_PTHREADS), 1) + DIRS += pthreads +endif + +ifeq ($(USE_BTHREADS), 1) + DIRS += bthreads +endif + +ifeq ($(USE_CPLUS), 1) + DIRS += cplus +endif + +# +# Define platform-dependent OS_LIBS +# + +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OS_LIBS = -lm +else # 4.1.3_U1 +MAPFILE = $(OBJDIR)/nsprmap.sun +GARBAGE += $(MAPFILE) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +MKSHLIB += -Wl,--version-script,$(MAPFILE) +else +MKSHLIB += -Wl,-M,$(MAPFILE) +endif +else +MKSHLIB += -M $(MAPFILE) +endif +# +# In Solaris 2.6 or earlier, -lrt is called -lposix4. +# +LIBRT_TEST=$(firstword $(sort 5.7 $(OS_RELEASE))) +ifeq (5.7, $(LIBRT_TEST)) +LIBRT=-lrt +else +LIBRT=-lposix4 +endif + +ifdef USE_PTHREADS +OS_LIBS = -lpthread -lthread ${LIBRT} -lsocket -lnsl -ldl -lc +else +ifdef LOCAL_THREADS_ONLY +OS_LIBS = -lsocket -lnsl -ldl -lc +else +OS_LIBS = -lthread ${LIBRT} -lsocket -lnsl -ldl -lc +endif # LOCAL_THREADS_ONLY +endif # USE_PTHREADS +ifeq ($(OS_TEST),sun4u) +ifndef USE_64 +DSO_LDOPTS += -Wl,-f,\$$ORIGIN/cpu/\$$ISALIST/lib$(ULTRASPARC_LIBRARY)$(LIBRARY_VERSION).so +endif +endif # sun4u +endif # 4.1.3_U1 +endif # SunOS + +ifeq ($(OS_ARCH), IRIX) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread +endif +OS_LIBS += -lc +endif + +ifeq ($(OS_ARCH),AIX) +ifeq ($(CLASSIC_NSPR),1) +ifeq ($(OS_RELEASE),4.1) +OS_LIBS = -lsvld -lc +else +OS_LIBS = -ldl -lc +endif +else +ifeq ($(OS_RELEASE),4.1) +OS_LIBS = -lpthreads -lsvld -lC_r -lC -lc_r -lm /usr/lib/libc.a +else +OS_LIBS = -lpthreads -ldl -lC_r -lC -lc_r -lm /usr/lib/libc.a +endif +endif +endif + +# On AIX, we override malloc in non-pthread versions. On AIX 4.2 or +# above, this requires that we use the rtl-enabled version of libc.a. +ifeq ($(OS_ARCH),AIX) +ifneq (,$(filter-out 3.2 4.1,$(OS_RELEASE))) +ifneq ($(USE_PTHREADS),1) +BUILD_AIX_RTL_LIBC = 1 +AIX_RTL_LIBC = $(OBJDIR)/libc.a +endif +endif +endif + +ifeq ($(OS_ARCH),OS2) +MAPFILE = $(OBJDIR)/$(LIBRARY_NAME)$(LIBRARY_VERSION).def +ADD_TO_DEF_FILE = cat $(srcdir)/os2extra.def >> $(MAPFILE) +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif + +ifeq ($(OS_ARCH),OSF1) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread -lrt +endif +ifneq ($(OS_RELEASE),V2.0) +OS_LIBS += -lc_r +endif +endif + +ifeq ($(OS_ARCH),Linux) +ifeq ($(USE_PTHREADS), 1) +OS_LIBS = -lpthread -ldl +else +OS_LIBS = -ldl +endif +endif + +ifeq ($(OS_ARCH),HP-UX) +ifeq ($(USE_PTHREADS), 1) +ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE))) +OS_LIBS = -ldce +else +OS_LIBS = -lpthread -lrt +endif +endif +ifeq ($(PTHREADS_USER), 1) +OS_LIBS = -lpthread +endif +ifeq ($(basename $(OS_RELEASE)),A.09) +OS_LIBS += -ldld -L/lib/pa1.1 -lm +else +OS_LIBS += -ldld -lm -lc +endif +endif + +ifeq ($(OS_ARCH),UNIXWARE) +OS_LIBS = -lsocket -lc +endif + +ifeq ($(OS_ARCH),NEWS-OS) +OS_LIBS = -lsocket -lnsl -lgen -lresolv +endif + +ifeq ($(OS_ARCH),WINNT) +ifdef NS_USE_GCC +OS_LIBS = -ladvapi32 -lwsock32 +else +OS_LIBS = advapi32.lib wsock32.lib +endif +endif + +ifeq ($(OS_TARGET),MacOSX) +OS_LIBS = -framework CoreServices -framework CoreFoundation +endif + +ifdef GC_LEAK_DETECTOR +EXTRA_LIBS = -L$(dist_libdir) -lboehm +endif + +EXTRA_LIBS += $(OS_LIBS) + +# +# Define platform-dependent OBJS +# + +OBJS = \ + $(OBJDIR)/prvrsion.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prfdcach.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prmwait.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prmapopt.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/priometh.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/pripv6.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prlayer.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prlog.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prmmap.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prpolevt.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prprf.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prscanf.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prstdio.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prcmon.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prrwlock.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prtpd.$(OBJ_SUFFIX) \ + linking/$(OBJDIR)/prlink.$(OBJ_SUFFIX) \ + malloc/$(OBJDIR)/prmem.$(OBJ_SUFFIX) \ + md/$(OBJDIR)/prosdep.$(OBJ_SUFFIX) \ + memory/$(OBJDIR)/prshm.$(OBJ_SUFFIX) \ + memory/$(OBJDIR)/prshma.$(OBJ_SUFFIX) \ + memory/$(OBJDIR)/prseg.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pralarm.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pratom.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prcountr.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prdtoa.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prenv.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prerr.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prerror.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prerrortable.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prinit.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prinrval.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pripc.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prlog2.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prlong.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prnetdb.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prolock.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prrng.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prsystem.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prthinfo.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtpool.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtrace.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/prtime.$(OBJ_SUFFIX) + +# ilib now rejects empty objects +ifneq ($(MOZ_OS2_TOOLS),VACPP) +OBJS += malloc/$(OBJDIR)/prmalloc.$(OBJ_SUFFIX) +endif + +ifdef USE_PTHREADS +OBJS += \ + pthreads/$(OBJDIR)/ptsynch.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptio.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptthread.$(OBJ_SUFFIX) \ + pthreads/$(OBJDIR)/ptmisc.$(OBJ_SUFFIX) +else +OBJS += \ + io/$(OBJDIR)/prdir.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prfile.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prio.$(OBJ_SUFFIX) \ + io/$(OBJDIR)/prsocket.$(OBJ_SUFFIX) \ + misc/$(OBJDIR)/pripcsem.$(OBJ_SUFFIX) + +ifndef USE_BTHREADS +OBJS += \ + threads/$(OBJDIR)/prcthr.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prdump.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prmon.$(OBJ_SUFFIX) \ + threads/$(OBJDIR)/prsem.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prucpu.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prucv.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prulock.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/prustack.$(OBJ_SUFFIX) \ + threads/combined/$(OBJDIR)/pruthr.$(OBJ_SUFFIX) +endif + +endif + +ifeq ($(USE_CPLUS), 1) +OBJS += \ + cplus/$(OBJDIR)/rcbase.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rccv.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcfileio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcinrval.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rclock.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcnetdb.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcnetio.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rcthread.$(OBJ_SUFFIX) \ + cplus/$(OBJDIR)/rctime.$(OBJ_SUFFIX) +endif + +ifdef GC_LEAK_DETECTOR +OBJS += memory/$(OBJDIR)/prgcleak.$(OBJ_SUFFIX) +endif + +ifeq ($(OS_ARCH), WINNT) +ifdef NS_USE_GCC +DLLBASE=-Wl,--image-base -Wl,0x30000000 +else +DLLBASE=/BASE:0x30000000 +endif # GCC +RES=$(OBJDIR)/nspr.res +RESNAME=nspr.rc +endif # WINNT + +include $(srcdir)/md/$(PR_MD_ARCH_DIR)/objs.mk +ifdef USE_BTHREADS +include $(srcdir)/bthreads/objs.mk +endif + +LIBRARY_NAME = nspr +LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + +RELEASE_LIBS = $(TARGETS) + +include $(topsrcdir)/config/rules.mk + +ifeq ($(BUILD_AIX_RTL_LIBC),1) +TARGETS += $(AIX_RTL_LIBC) +# XXX is this a shared library? +endif + +# +# Version information generation (begin) +# +ECHO = echo +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private +TINC = $(OBJDIR)/_pr_bld.h + +ifeq ($(OS_TARGET),OS2) +PROD = nspr$(MOD_MAJOR_VERSION).$(DLL_SUFFIX) +else +PROD = $(notdir $(SHARED_LIBRARY)) +endif + +NOW = $(MOD_DEPTH)/config/$(OBJDIR)/now +SH_DATE = $(shell date "+%Y-%m-%d %T") +SH_NOW = $(shell $(NOW)) + +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + SUF = i64 +else + SUF = LL +endif + +DEFINES += -D_NSPR_BUILD_ + +GARBAGE += $(TINC) + +$(TINC): + @$(MAKE_OBJDIR) + @$(ECHO) '#define _BUILD_STRING "$(SH_DATE)"' > $(TINC) + @if test ! -z "$(SH_NOW)"; then \ + $(ECHO) '#define _BUILD_TIME $(SH_NOW)$(SUF)' >> $(TINC); \ + else \ + true; \ + fi + @$(ECHO) '#define _PRODUCTION "$(PROD)"' >> $(TINC) + + +$(OBJDIR)/prvrsion.$(OBJ_SUFFIX): prvrsion.c $(TINC) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else +ifeq ($(MOZ_OS2_TOOLS), VACPP) + $(CC) -Fo$@ -c $(CFLAGS) -I$(OBJDIR) $< +else + $(CC) -o $@ -c $(CFLAGS) -I$(OBJDIR) $< +endif +endif +# +# Version information generation (end) +# + + +# +# The Client build wants the shared libraries in $(dist_bindir) +# so we also install them there. +# + +export:: $(TARGETS) + $(INSTALL) -m 444 $(TARGETS) $(dist_libdir) +ifdef SHARED_LIBRARY +ifeq ($(OS_ARCH),HP-UX) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_libdir) + $(INSTALL) -m 755 $(SHARED_LIBRARY) $(dist_bindir) +else + $(INSTALL) -m 444 $(SHARED_LIBRARY) $(dist_bindir) +endif +endif +ifeq ($(MOZ_BITS),16) + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/lib + $(INSTALL) -m 444 $(TARGETS) $(MOZ_DIST)/bin +endif + +ifeq ($(BUILD_AIX_RTL_LIBC),1) +$(AIX_RTL_LIBC): /usr/ccs/lib/libc.a + rtl_enable -o $@ $< +endif + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/Makefile.in new file mode 100644 index 00000000..285f217d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/Makefile.in @@ -0,0 +1,63 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +include $(srcdir)/bsrcs.mk +CSRCS += $(BTCSRCS) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_NSPR_BUILD_ + +export:: $(TARGETS) + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/bsrcs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/bsrcs.mk new file mode 100644 index 00000000..af01bb7d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/bsrcs.mk @@ -0,0 +1,49 @@ +# +# ***** 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 file lists the source files to be compiled (used in Makefile) and +# then enumerated as object files (in objs.mk) for inclusion in the NSPR +# shared library + +BTCSRCS = \ + btthread.c \ + btlocks.c \ + btcvar.c \ + btmon.c \ + btsem.c \ + btmisc.c \ + $(NULL) diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btcvar.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btcvar.c new file mode 100644 index 00000000..841ec960 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btcvar.c @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 + +#include "primpl.h" + +/* +** Create a new condition variable. +** +** "lock" is the lock used to protect the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. In such cases, a NULL will be returned. +*/ +PR_IMPLEMENT(PRCondVar*) + PR_NewCondVar (PRLock *lock) +{ + PRCondVar *cv = PR_NEW( PRCondVar ); + PR_ASSERT( NULL != lock ); + if( NULL != cv ) + { + cv->lock = lock; + cv->sem = create_sem(0, "CVSem"); + cv->handshakeSem = create_sem(0, "CVHandshake"); + cv->signalSem = create_sem( 0, "CVSignal"); + cv->signalBenCount = 0; + cv->ns = cv->nw = 0; + PR_ASSERT( cv->sem >= B_NO_ERROR ); + PR_ASSERT( cv->handshakeSem >= B_NO_ERROR ); + PR_ASSERT( cv->signalSem >= B_NO_ERROR ); + } + return cv; +} /* PR_NewCondVar */ + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +PR_IMPLEMENT(void) + PR_DestroyCondVar (PRCondVar *cvar) +{ + status_t result = delete_sem( cvar->sem ); + PR_ASSERT( result == B_NO_ERROR ); + + result = delete_sem( cvar->handshakeSem ); + PR_ASSERT( result == B_NO_ERROR ); + + result = delete_sem( cvar->signalSem ); + PR_ASSERT( result == B_NO_ERROR ); + + PR_DELETE( cvar ); +} + +/* +** The thread that waits on a condition is blocked in a "waiting on +** condition" state until another thread notifies the condition or a +** caller specified amount of time expires. The lock associated with +** the condition variable will be released, which must have be held +** prior to the call to wait. +** +** Logically a notified thread is moved from the "waiting on condition" +** state and made "ready." When scheduled, it will attempt to reacquire +** the lock that it held when wait was called. +** +** The timeout has two well known values, PR_INTERVAL_NO_TIMEOUT and +** PR_INTERVAL_NO_WAIT. The former value requires that a condition be +** notified (or the thread interrupted) before it will resume from the +** wait. If the timeout has a value of PR_INTERVAL_NO_WAIT, the effect +** is to release the lock, possibly causing a rescheduling within the +** runtime, then immediately attempting to reacquire the lock and resume. +** +** Any other value for timeout will cause the thread to be rescheduled +** either due to explicit notification or an expired interval. The latter +** must be determined by treating time as one part of the monitored data +** being protected by the lock and tested explicitly for an expired +** interval. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread was interrupted (PR_Interrupt()). +** The particular reason can be extracted with PR_GetError(). +*/ +PR_IMPLEMENT(PRStatus) + PR_WaitCondVar (PRCondVar *cvar, PRIntervalTime timeout) +{ + status_t err; + if( timeout == PR_INTERVAL_NO_WAIT ) + { + PR_Unlock( cvar->lock ); + PR_Lock( cvar->lock ); + return PR_SUCCESS; + } + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + cvar->nw += 1; + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + + PR_Unlock( cvar->lock ); + if( timeout==PR_INTERVAL_NO_TIMEOUT ) + { + err = acquire_sem(cvar->sem); + } + else + { + err = acquire_sem_etc(cvar->sem, 1, B_RELATIVE_TIMEOUT, PR_IntervalToMicroseconds(timeout) ); + } + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + while (acquire_sem(cvar->signalSem) == B_INTERRUPTED); + } + + if (cvar->ns > 0) + { + release_sem(cvar->handshakeSem); + cvar->ns -= 1; + } + cvar->nw -= 1; + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + + PR_Lock( cvar->lock ); + if(err!=B_NO_ERROR) + { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** Notify ONE thread that is currently waiting on 'cvar'. Which thread is +** dependent on the implementation of the runtime. Common sense would dictate +** that all threads waiting on a single condition have identical semantics, +** therefore which one gets notified is not significant. +** +** The calling thead must hold the lock that protects the condition, as +** well as the invariants that are tightly bound to the condition, when +** notify is called. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyCondVar (PRCondVar *cvar) +{ + status_t err ; + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + if (cvar->nw > cvar->ns) + { + cvar->ns += 1; + release_sem(cvar->sem); + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + + while (acquire_sem(cvar->handshakeSem) == B_INTERRUPTED) + { + err = B_INTERRUPTED; + } + } + else + { + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + } + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. The order +** that the threads are notified is indeterminant. The lock that protects +** the condition must be held. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyAllCondVar (PRCondVar *cvar) +{ + int32 handshakes; + status_t err = B_OK; + + if( atomic_add( &cvar->signalBenCount, 1 ) > 0 ) + { + if (acquire_sem(cvar->signalSem) == B_INTERRUPTED) + { + atomic_add( &cvar->signalBenCount, -1 ); + return PR_FAILURE; + } + } + + if (cvar->nw > cvar->ns) + { + handshakes = cvar->nw - cvar->ns; + cvar->ns = cvar->nw; + release_sem_etc(cvar->sem, handshakes, 0); + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + + while (acquire_sem_etc(cvar->handshakeSem, handshakes, 0, 0) == B_INTERRUPTED) + { + err = B_INTERRUPTED; + } + } + else + { + if( atomic_add( &cvar->signalBenCount, -1 ) > 1 ) + { + release_sem(cvar->signalSem); + } + } + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btlocks.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btlocks.c new file mode 100644 index 00000000..c5b62860 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btlocks.c @@ -0,0 +1,116 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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 ***** */ + +/* +** File: btlocks.c +** Description: Implemenation for thread locks using bthreads +** Exports: prlock.h +*/ + +#include "primpl.h" + +#include +#include + +void +_PR_InitLocks (void) +{ +} + +PR_IMPLEMENT(PRLock*) + PR_NewLock (void) +{ + PRLock *lock; + status_t semresult; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock != NULL) { + + lock->benaphoreCount = 0; + lock->semaphoreID = create_sem( 0, "nsprLockSem" ); + if( lock->semaphoreID < B_NO_ERROR ) { + + PR_DELETE( lock ); + lock = NULL; + } + } + + return lock; +} + +PR_IMPLEMENT(void) + PR_DestroyLock (PRLock* lock) +{ + status_t result; + + PR_ASSERT(NULL != lock); + result = delete_sem(lock->semaphoreID); + PR_ASSERT(result == B_NO_ERROR); + PR_DELETE(lock); +} + +PR_IMPLEMENT(void) + PR_Lock (PRLock* lock) +{ + PR_ASSERT(lock != NULL); + + if( atomic_add( &lock->benaphoreCount, 1 ) > 0 ) { + + if( acquire_sem(lock->semaphoreID ) != B_NO_ERROR ) { + + atomic_add( &lock->benaphoreCount, -1 ); + return; + } + } + + lock->owner = find_thread( NULL ); +} + +PR_IMPLEMENT(PRStatus) + PR_Unlock (PRLock* lock) +{ + PR_ASSERT(lock != NULL); + lock->owner = NULL; + if( atomic_add( &lock->benaphoreCount, -1 ) > 1 ) { + + release_sem( lock->semaphoreID ); + } + + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmisc.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmisc.c new file mode 100644 index 00000000..2d678a9d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmisc.c @@ -0,0 +1,104 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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 + +// void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")} +// void _MD_StartInterrupts(void) {PT_LOG("_MD_StartInterrupts")} + +/* this is a total hack.. */ + +struct protoent* getprotobyname(const char* name) +{ + return 0; +} + +struct protoent* getprotobynumber(int number) +{ + return 0; +} + +/* this is needed by prinit for some reason */ +void +_PR_InitStacks (void) +{ +} + +/* this is needed by prinit for some reason */ +void +_PR_InitTPD (void) +{ +} + +/* +** Create extra virtual processor threads. Generally used with MP systems. +*/ +PR_IMPLEMENT(void) + PR_SetConcurrency (PRUintn numCPUs) +{ +} + +/* +** Set thread recycle mode to on (1) or off (0) +*/ +PR_IMPLEMENT(void) + PR_SetThreadRecycleMode (PRUint32 flag) +{ +} + +/* +** Get context registers, return with error for now. +*/ + +PR_IMPLEMENT(PRWord *) +_MD_HomeGCRegisters( PRThread *t, int isCurrent, int *np ) +{ + return 0; +} + +PR_IMPLEMENT(void *) +PR_GetSP( PRThread *t ) +{ + return 0; +} + +PR_IMPLEMENT(PRStatus) +PR_EnumerateThreads( PREnumerator func, void *arg ) +{ + return PR_FAILURE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmon.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmon.c new file mode 100644 index 00000000..f14d1379 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btmon.c @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 + +#include "primpl.h" + +/* +** Create a new monitor. Monitors are re-entrant locks with a single built-in +** condition variable. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +PR_IMPLEMENT(PRMonitor*) + PR_NewMonitor (void) +{ + PRMonitor *mon; + PRCondVar *cvar; + PRLock *lock; + + mon = PR_NEWZAP( PRMonitor ); + if( mon ) + { + lock = PR_NewLock(); + if( !lock ) + { + PR_DELETE( mon ); + return( 0 ); + } + + cvar = PR_NewCondVar( lock ); + if( !cvar ) + { + PR_DestroyLock( lock ); + PR_DELETE( mon ); + return( 0 ); + } + + mon->cvar = cvar; + mon->name = NULL; + } + + return( mon ); +} + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if( mon ) + { + mon->name = name; + } + return mon; +} + +/* +** Destroy a monitor. The caller is responsible for guaranteeing that the +** monitor is no longer in use. There must be no thread waiting on the +** monitor's condition variable and that the lock is not held. +** +*/ +PR_IMPLEMENT(void) + PR_DestroyMonitor (PRMonitor *mon) +{ + PR_DestroyLock( mon->cvar->lock ); + PR_DestroyCondVar( mon->cvar ); + PR_DELETE( mon ); +} + +/* +** Enter the lock associated with the monitor. If the calling thread currently +** is in the monitor, the call to enter will silently succeed. In either case, +** it will increment the entry count by one. +*/ +PR_IMPLEMENT(void) + PR_EnterMonitor (PRMonitor *mon) +{ + if( mon->cvar->lock->owner == find_thread( NULL ) ) + { + mon->entryCount++; + + } else + { + PR_Lock( mon->cvar->lock ); + mon->entryCount = 1; + } +} + +/* +** Decrement the entry count associated with the monitor. If the decremented +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the +** calling thread has not entered the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_ExitMonitor (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + if( --mon->entryCount == 0 ) + { + return( PR_Unlock( mon->cvar->lock ) ); + } + return( PR_SUCCESS ); +} + +/* +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is +** indefinite). +** +** While the thread is waiting it exits the monitor (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" timeout elapses. +** +** Returns PR_FAILURE if the caller has not entered the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_Wait (PRMonitor *mon, PRIntervalTime ticks) +{ + PRUint32 entryCount; + PRUintn status; + PRThread *meThread; + thread_id me = find_thread( NULL ); + meThread = PR_GetCurrentThread(); + + if( mon->cvar->lock->owner != me ) return( PR_FAILURE ); + + entryCount = mon->entryCount; + mon->entryCount = 0; + + status = PR_WaitCondVar( mon->cvar, ticks ); + + mon->entryCount = entryCount; + + return( status ); +} + +/* +** Notify a thread waiting on the monitor's condition variable. If a thread +** is waiting on the condition variable (using PR_Wait) then it is awakened +** and attempts to reenter the monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_Notify (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + + PR_NotifyCondVar( mon->cvar ); + return( PR_SUCCESS ); +} + +/* +** Notify all of the threads waiting on the monitor's condition variable. +** All of threads waiting on the condition are scheduled to reenter the +** monitor. +*/ +PR_IMPLEMENT(PRStatus) + PR_NotifyAll (PRMonitor *mon) +{ + if( mon->cvar->lock->owner != find_thread( NULL ) ) + { + return( PR_FAILURE ); + } + + PR_NotifyAllCondVar( mon->cvar ); + return( PR_SUCCESS ); +} + +PR_IMPLEMENT(PRIntn) + PR_GetMonitorEntryCount(PRMonitor *mon) +{ + return( mon->entryCount ); +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btsem.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btsem.c new file mode 100644 index 00000000..c9f2e641 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btsem.c @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 + +#include "primpl.h" + +/* +** Create a new semaphore object. +*/ +PR_IMPLEMENT(PRSemaphore*) + PR_NewSem (PRUintn value) +{ + PRSemaphore *semaphore; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + semaphore = PR_NEWZAP(PRSemaphore); + if (NULL != semaphore) { + if ((semaphore->sem = create_sem(value, "nspr_sem")) < B_NO_ERROR) + return NULL; + else + return semaphore; + } + return NULL; +} + +/* +** Destroy the given semaphore object. +** +*/ +PR_IMPLEMENT(void) + PR_DestroySem (PRSemaphore *sem) +{ + status_t result; + + PR_ASSERT(sem != NULL); + result = delete_sem(sem->sem); + PR_ASSERT(result == B_NO_ERROR); + PR_DELETE(sem); +} + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon +** the state of the semahore sem. The thread can proceed only if the +** counter value of the semaphore sem is currently greater than 0. If the +** value of semaphore sem is positive, it is decremented by one and the +** routine returns immediately allowing the calling thread to continue. If +** the value of semaphore sem is 0, the calling thread blocks awaiting the +** semaphore to be released by another thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) + PR_WaitSem (PRSemaphore *sem) +{ + PR_ASSERT(sem != NULL); + if (acquire_sem(sem->sem) == B_NO_ERROR) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +/* +** This routine increments the counter value of the semaphore. If other +** threads are blocked for the semaphore, then the scheduler will +** determine which ONE thread will be unblocked. +*/ +PR_IMPLEMENT(void) + PR_PostSem (PRSemaphore *sem) +{ + status_t result; + + PR_ASSERT(sem != NULL); + result = release_sem(sem->sem); + PR_ASSERT(result == B_NO_ERROR); +} + +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore value +** at the time of the call, but may not be the actual value when the +** caller inspects it. +*/ +PR_IMPLEMENT(PRUintn) + PR_GetValueSem (PRSemaphore *sem) +{ + sem_info info; + + PR_ASSERT(sem != NULL); + get_sem_info(sem->sem, &info); + return info.count; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btthread.c b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btthread.c new file mode 100644 index 00000000..814ede29 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/btthread.c @@ -0,0 +1,694 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 +#include + +#include "prlog.h" +#include "primpl.h" +#include "prcvar.h" +#include "prpdce.h" + +#include +#include +#include + +/* values for PRThread.state */ +#define BT_THREAD_PRIMORD 0x01 /* this is the primordial thread */ +#define BT_THREAD_SYSTEM 0x02 /* this is a system thread */ +#define BT_THREAD_JOINABLE 0x04 /* this is a joinable thread */ + +struct _BT_Bookeeping +{ + PRLock *ml; /* a lock to protect ourselves */ + sem_id cleanUpSem; /* the primoridal thread will block on this + sem while waiting for the user threads */ + PRInt32 threadCount; /* user thred count */ + +} bt_book = { NULL, B_ERROR, 0 }; + + +#define BT_TPD_LIMIT 128 /* number of TPD slots we'll provide (arbitrary) */ + +/* these will be used to map an index returned by PR_NewThreadPrivateIndex() + to the corresponding beos native TLS slot number, and to the destructor + for that slot - note that, because it is allocated globally, this data + will be automatically zeroed for us when the program begins */ +static int32 tpd_beosTLSSlots[BT_TPD_LIMIT]; +static PRThreadPrivateDTOR tpd_dtors[BT_TPD_LIMIT]; + +static vint32 tpd_slotsUsed=0; /* number of currently-allocated TPD slots */ +static int32 tls_prThreadSlot; /* TLS slot in which PRThread will be stored */ + +/* this mutex will be used to synchronize access to every + PRThread.md.joinSem and PRThread.md.is_joining (we could + actually allocate one per thread, but that seems a bit excessive, + especially considering that there will probably be little + contention, PR_JoinThread() is allowed to block anyway, and the code + protected by the mutex is short/fast) */ +static PRLock *joinSemLock; + +static PRUint32 _bt_MapNSPRToNativePriority( PRThreadPriority priority ); +static PRThreadPriority _bt_MapNativeToNSPRPriority( PRUint32 priority ); +static void _bt_CleanupThread(void *arg); +static PRThread *_bt_AttachThread(); + +void +_PR_InitThreads (PRThreadType type, PRThreadPriority priority, + PRUintn maxPTDs) +{ + PRThread *primordialThread; + PRUint32 beThreadPriority; + + /* allocate joinSem mutex */ + joinSemLock = PR_NewLock(); + if (joinSemLock == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return; + } + + /* + ** Create and initialize NSPR structure for our primordial thread. + */ + + primordialThread = PR_NEWZAP(PRThread); + if( NULL == primordialThread ) + { + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); + return; + } + + primordialThread->md.joinSem = B_ERROR; + + /* + ** Set the priority to the desired level. + */ + + beThreadPriority = _bt_MapNSPRToNativePriority( priority ); + + set_thread_priority( find_thread( NULL ), beThreadPriority ); + + primordialThread->priority = priority; + + + /* set the thread's state - note that the thread is not joinable */ + primordialThread->state |= BT_THREAD_PRIMORD; + if (type == PR_SYSTEM_THREAD) + primordialThread->state |= BT_THREAD_SYSTEM; + + /* + ** Allocate a TLS slot for the PRThread structure (just using + ** native TLS, as opposed to NSPR TPD, will make PR_GetCurrentThread() + ** somewhat faster, and will leave one more TPD slot for our client) + */ + + tls_prThreadSlot = tls_allocate(); + + /* + ** Stuff our new PRThread structure into our thread specific + ** slot. + */ + + tls_set(tls_prThreadSlot, primordialThread); + + /* allocate lock for bt_book */ + bt_book.ml = PR_NewLock(); + if( NULL == bt_book.ml ) + { + PR_SetError( PR_OUT_OF_MEMORY_ERROR, 0 ); + return; + } +} + +PRUint32 +_bt_MapNSPRToNativePriority( PRThreadPriority priority ) + { + switch( priority ) + { + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); + default: return( B_NORMAL_PRIORITY ); + } +} + +PRThreadPriority +_bt_MapNativeToNSPRPriority(PRUint32 priority) + { + if (priority < B_NORMAL_PRIORITY) + return PR_PRIORITY_LOW; + if (priority < B_DISPLAY_PRIORITY) + return PR_PRIORITY_NORMAL; + if (priority < B_URGENT_DISPLAY_PRIORITY) + return PR_PRIORITY_HIGH; + return PR_PRIORITY_URGENT; +} + +PRUint32 +_bt_mapNativeToNSPRPriority( int32 priority ) +{ + switch( priority ) + { + case PR_PRIORITY_LOW: return( B_LOW_PRIORITY ); + case PR_PRIORITY_NORMAL: return( B_NORMAL_PRIORITY ); + case PR_PRIORITY_HIGH: return( B_DISPLAY_PRIORITY ); + case PR_PRIORITY_URGENT: return( B_URGENT_DISPLAY_PRIORITY ); + default: return( B_NORMAL_PRIORITY ); + } +} + +/* This method is called by all NSPR threads as they exit */ +void _bt_CleanupThread(void *arg) +{ + PRThread *me = PR_GetCurrentThread(); + int32 i; + + /* first, clean up all thread-private data */ + for (i = 0; i < tpd_slotsUsed; i++) + { + void *oldValue = tls_get(tpd_beosTLSSlots[i]); + if ( oldValue != NULL && tpd_dtors[i] != NULL ) + (*tpd_dtors[i])(oldValue); + } + + /* if this thread is joinable, wait for someone to join it */ + if (me->state & BT_THREAD_JOINABLE) + { + /* protect access to our joinSem */ + PR_Lock(joinSemLock); + + if (me->md.is_joining) + { + /* someone is already waiting to join us (they've + allocated a joinSem for us) - let them know we're + ready */ + delete_sem(me->md.joinSem); + + PR_Unlock(joinSemLock); + + } + else + { + /* noone is currently waiting for our demise - it + is our responsibility to allocate the joinSem + and block on it */ + me->md.joinSem = create_sem(0, "join sem"); + + /* we're done accessing our joinSem */ + PR_Unlock(joinSemLock); + + /* wait for someone to join us */ + while (acquire_sem(me->md.joinSem) == B_INTERRUPTED); + } + } + + /* if this is a user thread, we must update our books */ + if ((me->state & BT_THREAD_SYSTEM) == 0) + { + /* synchronize access to bt_book */ + PR_Lock( bt_book.ml ); + + /* decrement the number of currently-alive user threads */ + bt_book.threadCount--; + + if (bt_book.threadCount == 0 && bt_book.cleanUpSem != B_ERROR) { + /* we are the last user thread, and the primordial thread is + blocked in PR_Cleanup() waiting for us to finish - notify + it */ + delete_sem(bt_book.cleanUpSem); + } + + PR_Unlock( bt_book.ml ); + } + + /* finally, delete this thread's PRThread */ + PR_DELETE(me); +} + +/** + * This is a wrapper that all threads invoke that allows us to set some + * things up prior to a thread's invocation and clean up after a thread has + * exited. + */ +static void* +_bt_root (void* arg) + { + PRThread *thred = (PRThread*)arg; + PRIntn rv; + void *privData; + status_t result; + int i; + + /* save our PRThread object into our TLS */ + tls_set(tls_prThreadSlot, thred); + + thred->startFunc(thred->arg); /* run the dang thing */ + + /* clean up */ + _bt_CleanupThread(NULL); + + return 0; +} + +PR_IMPLEMENT(PRThread*) + PR_CreateThread (PRThreadType type, void (*start)(void* arg), void* arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + PRUint32 bePriority; + + PRThread* thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + thred = PR_NEWZAP(PRThread); + if (thred == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + thred->md.joinSem = B_ERROR; + + thred->arg = arg; + thred->startFunc = start; + thred->priority = priority; + + if( state == PR_JOINABLE_THREAD ) + { + thred->state |= BT_THREAD_JOINABLE; + } + + /* keep some books */ + + PR_Lock( bt_book.ml ); + + if (type == PR_USER_THREAD) + { + bt_book.threadCount++; + } + + PR_Unlock( bt_book.ml ); + + bePriority = _bt_MapNSPRToNativePriority( priority ); + + thred->md.tid = spawn_thread((thread_func)_bt_root, "moz-thread", + bePriority, thred); + if (thred->md.tid < B_OK) { + PR_SetError(PR_UNKNOWN_ERROR, thred->md.tid); + PR_DELETE(thred); + return NULL; + } + + if (resume_thread(thred->md.tid) < B_OK) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + PR_DELETE(thred); + return NULL; + } + + return thred; + } + +PR_IMPLEMENT(PRThread*) + PR_AttachThread(PRThreadType type, PRThreadPriority priority, + PRThreadStack *stack) +{ + /* PR_GetCurrentThread() will attach a thread if necessary */ + return PR_GetCurrentThread(); +} + +PR_IMPLEMENT(void) + PR_DetachThread() +{ + /* we don't support detaching */ +} + +PR_IMPLEMENT(PRStatus) + PR_JoinThread (PRThread* thred) +{ + status_t eval, status; + + PR_ASSERT(thred != NULL); + + if ((thred->state & BT_THREAD_JOINABLE) == 0) + { + PR_SetError( PR_INVALID_ARGUMENT_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* synchronize access to the thread's joinSem */ + PR_Lock(joinSemLock); + + if (thred->md.is_joining) + { + /* another thread is already waiting to join the specified + thread - we must fail */ + PR_Unlock(joinSemLock); + return PR_FAILURE; + } + + /* let others know we are waiting to join */ + thred->md.is_joining = PR_TRUE; + + if (thred->md.joinSem == B_ERROR) + { + /* the thread hasn't finished yet - it is our responsibility to + allocate a joinSem and wait on it */ + thred->md.joinSem = create_sem(0, "join sem"); + + /* we're done changing the joinSem now */ + PR_Unlock(joinSemLock); + + /* wait for the thread to finish */ + while (acquire_sem(thred->md.joinSem) == B_INTERRUPTED); + + } + else + { + /* the thread has already finished, and has allocated the + joinSem itself - let it know it can finally die */ + delete_sem(thred->md.joinSem); + + PR_Unlock(joinSemLock); + } + + /* make sure the thread is dead */ + wait_for_thread(thred->md.tid, &eval); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRThread*) + PR_GetCurrentThread () +{ + PRThread* thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + thred = (PRThread *)tls_get( tls_prThreadSlot); + if (thred == NULL) + { + /* this thread doesn't have a PRThread structure (it must be + a native thread not created by the NSPR) - assimilate it */ + thred = _bt_AttachThread(); + } + PR_ASSERT(NULL != thred); + + return thred; +} + +PR_IMPLEMENT(PRThreadScope) + PR_GetThreadScope (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return PR_GLOBAL_THREAD; +} + +PR_IMPLEMENT(PRThreadType) + PR_GetThreadType (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return (thred->state & BT_THREAD_SYSTEM) ? + PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) + PR_GetThreadState (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return (thred->state & BT_THREAD_JOINABLE)? + PR_JOINABLE_THREAD: PR_UNJOINABLE_THREAD; +} + +PR_IMPLEMENT(PRThreadPriority) + PR_GetThreadPriority (const PRThread* thred) +{ + PR_ASSERT(thred != NULL); + return thred->priority; +} /* PR_GetThreadPriority */ + +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, + PRThreadPriority newPri) +{ + PRUint32 bePriority; + + PR_ASSERT( thred != NULL ); + + thred->priority = newPri; + bePriority = _bt_MapNSPRToNativePriority( newPri ); + set_thread_priority( thred->md.tid, bePriority ); +} + +PR_IMPLEMENT(PRStatus) + PR_NewThreadPrivateIndex (PRUintn* newIndex, + PRThreadPrivateDTOR destructor) +{ + int32 index; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* reserve the next available tpd slot */ + index = atomic_add( &tpd_slotsUsed, 1 ); + if (index >= BT_TPD_LIMIT) + { + /* no slots left - decrement value, then fail */ + atomic_add( &tpd_slotsUsed, -1 ); + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* allocate a beos-native TLS slot for this index (the new slot + automatically contains NULL) */ + tpd_beosTLSSlots[index] = tls_allocate(); + + /* remember the destructor */ + tpd_dtors[index] = destructor; + + *newIndex = (PRUintn)index; + + return( PR_SUCCESS ); +} + +PR_IMPLEMENT(PRStatus) + PR_SetThreadPrivate (PRUintn index, void* priv) +{ + void *oldValue; + + /* + ** Sanity checking + */ + + if(index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) + { + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return( PR_FAILURE ); + } + + /* if the old value isn't NULL, and the dtor for this slot isn't + NULL, we must destroy the data */ + oldValue = tls_get(tpd_beosTLSSlots[index]); + if (oldValue != NULL && tpd_dtors[index] != NULL) + (*tpd_dtors[index])(oldValue); + + /* save new value */ + tls_set(tpd_beosTLSSlots[index], priv); + + return( PR_SUCCESS ); + } + +PR_IMPLEMENT(void*) + PR_GetThreadPrivate (PRUintn index) +{ + /* make sure the index is valid */ + if (index < 0 || index >= tpd_slotsUsed || index >= BT_TPD_LIMIT) + { + PR_SetError( PR_TPD_RANGE_ERROR, 0 ); + return NULL; + } + + /* return the value */ + return tls_get( tpd_beosTLSSlots[index] ); + } + + +PR_IMPLEMENT(PRStatus) + PR_Interrupt (PRThread* thred) +{ + PRIntn rv; + + PR_ASSERT(thred != NULL); + + /* + ** there seems to be a bug in beos R5 in which calling + ** resume_thread() on a blocked thread returns B_OK instead + ** of B_BAD_THREAD_STATE (beos bug #20000422-19095). as such, + ** to interrupt a thread, we will simply suspend then resume it + ** (no longer call resume_thread(), check for B_BAD_THREAD_STATE, + ** the suspend/resume to wake up a blocked thread). this wakes + ** up blocked threads properly, and doesn't hurt unblocked threads + ** (they simply get stopped then re-started immediately) + */ + + rv = suspend_thread( thred->md.tid ); + if( rv != B_NO_ERROR ) + { + /* this doesn't appear to be a valid thread_id */ + PR_SetError( PR_UNKNOWN_ERROR, rv ); + return PR_FAILURE; + } + + rv = resume_thread( thred->md.tid ); + if( rv != B_NO_ERROR ) + { + PR_SetError( PR_UNKNOWN_ERROR, rv ); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) + PR_ClearInterrupt () +{ +} + +PR_IMPLEMENT(PRStatus) + PR_Yield () +{ + /* we just sleep for long enough to cause a reschedule (100 + microseconds) */ + snooze(100); +} + +#define BT_MILLION 1000000UL + +PR_IMPLEMENT(PRStatus) + PR_Sleep (PRIntervalTime ticks) +{ + bigtime_t tps; + status_t status; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + tps = PR_IntervalToMicroseconds( ticks ); + + status = snooze(tps); + if (status == B_NO_ERROR) return PR_SUCCESS; + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, status); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) + PR_Cleanup () +{ + PRThread *me = PR_CurrentThread(); + + PR_ASSERT(me->state & BT_THREAD_PRIMORD); + if ((me->state & BT_THREAD_PRIMORD) == 0) { + return PR_FAILURE; + } + + PR_Lock( bt_book.ml ); + + if (bt_book.threadCount != 0) + { + /* we'll have to wait for some threads to finish - create a + sem to block on */ + bt_book.cleanUpSem = create_sem(0, "cleanup sem"); + } + + PR_Unlock( bt_book.ml ); + + /* note that, if all the user threads were already dead, we + wouldn't have created a sem above, so this acquire_sem() + will fail immediately */ + while (acquire_sem(bt_book.cleanUpSem) == B_INTERRUPTED); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) + PR_ProcessExit (PRIntn status) +{ + exit(status); +} + +PRThread *_bt_AttachThread() +{ + PRThread *thread; + thread_info tInfo; + + /* make sure this thread doesn't already have a PRThread structure */ + PR_ASSERT(tls_get(tls_prThreadSlot) == NULL); + + /* allocate a PRThread structure for this thread */ + thread = PR_NEWZAP(PRThread); + if (thread == NULL) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + /* get the native thread's current state */ + get_thread_info(find_thread(NULL), &tInfo); + + /* initialize new PRThread */ + thread->md.tid = tInfo.thread; + thread->md.joinSem = B_ERROR; + thread->priority = _bt_MapNativeToNSPRPriority(tInfo.priority); + + /* attached threads are always non-joinable user threads */ + thread->state = 0; + + /* increment user thread count */ + PR_Lock(bt_book.ml); + bt_book.threadCount++; + PR_Unlock(bt_book.ml); + + /* store this thread's PRThread */ + tls_set(tls_prThreadSlot, thread); + + /* the thread must call _bt_CleanupThread() before it dies, in order + to clean up its PRThread, synchronize with the primordial thread, + etc. */ + on_exit_thread(_bt_CleanupThread, NULL); + + return thread; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/objs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/objs.mk new file mode 100644 index 00000000..60455a37 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/bthreads/objs.mk @@ -0,0 +1,43 @@ +# +# ***** 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 makefile appends to the variable OBJS the bthread object modules +# that will be part of the nspr20 library. + +include $(srcdir)/bthreads/bsrcs.mk + +OBJS += $(BTCSRCS:%.c=bthreads/$(OBJDIR)/%.$(OBJ_SUFFIX)) diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/Makefile.in new file mode 100644 index 00000000..46e62e75 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CXXSRCS = \ + rcbase.cpp \ + rccv.cpp \ + rcfileio.cpp \ + rcinrval.cpp \ + rcio.cpp \ + rclock.cpp \ + rcnetdb.cpp \ + rcnetio.cpp \ + rcthread.cpp \ + rctime.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +HEADERS = $(wildcard $(srcdir)/*.h) + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcascii.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcascii.h new file mode 100644 index 00000000..8476fc49 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcascii.h @@ -0,0 +1,175 @@ +/* -*- 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 ***** */ + +/* +** Class definitions to format ASCII data. +*/ + +#if defined(_RCASCII_H) +#else +#define _RCASCII_H + +/* +** RCFormatStuff +** This class maintains no state - that is the responsibility of +** the class' client. For each call to Sx_printf(), the StuffFunction +** will be called for each embedded "%" in the 'fmt' string and once +** for each interveaning literal. +*/ +class PR_IMPLEMENT(RCFormatStuff) +{ +public: + RCFormatStuff(); + virtual ~RCFormatStuff(); + + /* + ** Process the arbitrary argument list using as indicated by + ** the 'fmt' string. Each segment of the processing the stuff + ** function is called with the relavent translation. + */ + virtual PRInt32 Sx_printf(void *state, const char *fmt, ...); + + /* + ** The 'state' argument is not processed by the runtime. It + ** is merely passed from the Sx_printf() call. It is intended + ** to be used by the client to figure out what to do with the + ** new string. + ** + ** The new string ('stuff') is ASCII translation driven by the + ** Sx_printf()'s 'fmt' string. It is not guaranteed to be a null + ** terminated string. + ** + ** The return value is the number of bytes copied from the 'stuff' + ** string. It is accumulated for each of the calls to the stuff + ** function and returned from the original caller of Sx_printf(). + */ + virtual PRSize StuffFunction( + void *state, const char *stuff, PRSize stufflen) = 0; +}; /* RCFormatStuff */ + + +/* +** RCFormatBuffer +** The caller is supplying the buffer, the runtime is doing all +** the conversion. The object contains no state, so is reusable +** and reentrant. +*/ +class PR_IMPLEMENT(RCFormatBuffer): public RCFormatStuff +{ +public: + RCFormatBuffer(); + virtual ~RCFormatBuffer(); + + /* + ** Format the trailing arguments as indicated by the 'fmt' + ** string. Put the result in 'buffer'. Return the number + ** of bytes moved into 'buffer'. 'buffer' will always be + ** a properly terminated string even if the convresion fails. + */ + virtual PRSize Sn_printf( + char *buffer, PRSize length, const char *fmt, ...); + + virtual char *Sm_append(char *buffer, const char *fmt, ...); + +private: + /* + ** This class overrides the stuff function, does not preserve + ** its virtual-ness and no longer allows the clients to call + ** it in the clear. In other words, it is now the implementation + ** for this class. + */ + PRSize StuffFunction(void*, const char*, PRSize); + +}; /* RCFormatBuffer */ + +/* +** RCFormat +** The runtime is supplying the buffer. The object has state - the +** buffer. Each operation must run to completion before the object +** can be reused. When it is, the buffer is reset (whatever that +** means). The result of a conversion is available via the extractor. +** After extracted, the memory still belongs to the class - if the +** caller wants to retain or modify, it must first be copied. +*/ +class PR_IMPLEMENT(RCFormat): pubic RCFormatBuffer +{ +public: + RCFormat(); + virtual ~RCFormat(); + + /* + ** Translate the trailing arguments according to the 'fmt' + ** string and store the results in the object. + */ + virtual PRSize Sm_printf(const char *fmt, ...); + + /* + ** Extract the latest translation. + ** The object does not surrender the memory occupied by + ** the string. If the caller wishes to modify the data, + ** it must first be copied. + */ + const char*(); + +private: + char *buffer; + + RCFormat(const RCFormat&); + RCFormat& operator=(const RCFormat&); +}; /* RCFormat */ + +/* +** RCPrint +** The output is formatted and then written to an associated file +** descriptor. The client can provide a suitable file descriptor +** or can indicate that the output should be directed to one of +** the well-known "console" devices. +*/ +class PR_IMPLEMENT(RCPrint): public RCFormat +{ + virtual ~RCPrint(); + RCPrint(RCIO* output); + RCPrint(RCFileIO::SpecialFile output); + + virtual PRSize Printf(const char *fmt, ...); +private: + RCPrint(); +}; /* RCPrint */ + +#endif /* defined(_RCASCII_H) */ + +/* RCAscii.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.cpp new file mode 100644 index 00000000..84662d9a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.cpp @@ -0,0 +1,55 @@ +/* -*- 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 ***** */ + +/* +** RCBase.cpp - Mixin class for NSPR C++ wrappers +*/ + +#include "rcbase.h" + +RCBase::~RCBase() { } + +PRSize RCBase::GetErrorTextLength() { return PR_GetErrorTextLength(); } +PRSize RCBase::CopyErrorText(char *text) { return PR_GetErrorText(text); } + +void RCBase::SetError(PRErrorCode error, PRInt32 oserror) + { PR_SetError(error, oserror); } + +void RCBase::SetErrorText(PRSize text_length, const char *text) + { PR_SetErrorText(text_length, text); } + +/* rcbase.cpp */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.h new file mode 100644 index 00000000..0910a158 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcbase.h @@ -0,0 +1,83 @@ +/* -*- 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 ***** */ + +/* +** RCBase.h - Mixin class for NSPR C++ wrappers +*/ + +#if defined(_RCRUNTIME_H) +#else +#define _RCRUNTIME_H + +#include + +/* +** Class: RCBase (mixin) +** +** Generally mixed into every base class. The functions in this class are all +** static. Therefore this entire class is just syntatic sugar. It gives the +** illusion that errors (in particular) are retrieved via the same object +** that just reported a failure. It also (unfortunately) might lead one to +** believe that the errors are persistent in that object. They're not. +*/ + +class PR_IMPLEMENT(RCBase) +{ +public: + virtual ~RCBase(); + + static void AbortSelf(); + + static PRErrorCode GetError(); + static PRInt32 GetOSError(); + + static PRSize GetErrorTextLength(); + static PRSize CopyErrorText(char *text); + + static void SetError(PRErrorCode error, PRInt32 oserror); + static void SetErrorText(PRSize textLength, const char *text); + +protected: + RCBase() { } +}; /* RCObject */ + +inline PRErrorCode RCBase::GetError() { return PR_GetError(); } +inline PRInt32 RCBase::GetOSError() { return PR_GetOSError(); } + +#endif /* defined(_RCRUNTIME_H) */ + +/* rcbase.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.cpp new file mode 100644 index 00000000..5e03ae75 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.cpp @@ -0,0 +1,97 @@ +/* -*- 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 ***** */ + +/* +** RCCondition - C++ wrapper around NSPR's PRCondVar +*/ + +#include "rccv.h" + +#include +#include +#include + +RCCondition::RCCondition(class RCLock *lock): RCBase() +{ + cv = PR_NewCondVar(lock->lock); + PR_ASSERT(NULL != cv); + timeout = PR_INTERVAL_NO_TIMEOUT; +} /* RCCondition::RCCondition */ + +RCCondition::~RCCondition() +{ + if (NULL != cv) PR_DestroyCondVar(cv); +} /* RCCondition::~RCCondition */ + +PRStatus RCCondition::Wait() +{ + PRStatus rv; + PR_ASSERT(NULL != cv); + if (NULL == cv) + { + SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + else + rv = PR_WaitCondVar(cv, timeout.interval); + return rv; +} /* RCCondition::Wait */ + +PRStatus RCCondition::Notify() +{ + return PR_NotifyCondVar(cv); +} /* RCCondition::Notify */ + +PRStatus RCCondition::Broadcast() +{ + return PR_NotifyAllCondVar(cv); +} /* RCCondition::Broadcast */ + +PRStatus RCCondition::SetTimeout(const RCInterval& tmo) +{ + if (NULL == cv) + { + SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + timeout = tmo; + return PR_SUCCESS; +} /* RCCondition::SetTimeout */ + +RCInterval RCCondition::GetTimeout() const { return timeout; } + +/* rccv.cpp */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.h new file mode 100644 index 00000000..56923af1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rccv.h @@ -0,0 +1,96 @@ +/* -*- 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 ***** */ + +/* +** RCCondition - C++ wrapper around NSPR's PRCondVar +** +** Conditions have a notion of timeouts. A thread that waits on a condition +** will resume execution when the condition is notified OR when a specified +** interval of time has expired. +** +** Most applications don't adjust the timeouts on conditions. The literature +** would argue that all threads waiting on a single condition must have the +** same semantics. But if an application wishes to modify the timeout with +** (perhaps) each wait call, that modification should be done consistantly +** and under protection of the condition's associated lock. +** +** The default timeout is infinity. +*/ + +#if defined(_RCCOND_H) +#else +#define _RCCOND_H + +#include "rclock.h" +#include "rcbase.h" +#include "rcinrval.h" + +struct PRCondVar; + +class PR_IMPLEMENT(RCCondition): public RCBase +{ +public: + RCCondition(RCLock*); /* associates CV with a lock and infinite tmo */ + virtual ~RCCondition(); + + virtual PRStatus Wait(); /* applies object's current timeout */ + + virtual PRStatus Notify(); /* perhaps ready one thread */ + virtual PRStatus Broadcast(); /* perhaps ready many threads */ + + virtual PRStatus SetTimeout(const RCInterval&); + /* set object's current timeout value */ + +private: + PRCondVar *cv; + RCInterval timeout; + + RCCondition(); + RCCondition(const RCCondition&); + void operator=(const RCCondition&); + +public: + RCInterval GetTimeout() const; +}; /* RCCondition */ + +inline RCCondition::RCCondition(): RCBase() { } +inline RCCondition::RCCondition(const RCCondition&): RCBase() { } +inline void RCCondition::operator=(const RCCondition&) { } + +#endif /* defined(_RCCOND_H) */ + +/* RCCond.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.cpp new file mode 100644 index 00000000..7646c894 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.cpp @@ -0,0 +1,199 @@ +/* -*- 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 ***** */ + +/* +** Class implementation for normal and special file I/O (ref: prio.h) +*/ + +#include "rcfileio.h" + +#include + +RCFileIO::RCFileIO(): RCIO(RCIO::file) { } + +RCFileIO::~RCFileIO() { if (NULL != fd) (void)Close(); } + +PRInt64 RCFileIO::Available() + { return fd->methods->available(fd); } + +PRStatus RCFileIO::Close() + { PRStatus rv = fd->methods->close(fd); fd = NULL; return rv; } + +PRStatus RCFileIO::Delete(const char* filename) { return PR_Delete(filename); } + +PRStatus RCFileIO::FileInfo(RCFileInfo* info) const + { return fd->methods->fileInfo64(fd, &info->info); } + +PRStatus RCFileIO::FileInfo(const char *name, RCFileInfo* info) + { return PR_GetFileInfo64(name, &info->info); } + +PRStatus RCFileIO::Fsync() + { return fd->methods->fsync(fd); } + +PRStatus RCFileIO::Open(const char *filename, PRIntn flags, PRIntn mode) +{ + fd = PR_Open(filename, flags, mode); + return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; +} /* RCFileIO::Open */ + +PRInt32 RCFileIO::Read(void *buf, PRSize amount) + { return fd->methods->read(fd, buf, amount); } + +PRInt64 RCFileIO::Seek(PRInt64 offset, RCIO::Whence how) +{ + PRSeekWhence whence; + switch (how) + { + case RCFileIO::set: whence = PR_SEEK_SET; break; + case RCFileIO::current: whence = PR_SEEK_CUR; break; + case RCFileIO::end: whence = PR_SEEK_END; break; + default: whence = (PRSeekWhence)-1; + } + return fd->methods->seek64(fd, offset, whence); +} /* RCFileIO::Seek */ + +PRInt32 RCFileIO::Write(const void *buf, PRSize amount) + { return fd->methods->write(fd, buf, amount); } + +PRInt32 RCFileIO::Writev( + const PRIOVec *iov, PRSize size, const RCInterval& timeout) + { return fd->methods->writev(fd, iov, size, timeout); } + +RCIO *RCFileIO::GetSpecialFile(RCFileIO::SpecialFile special) +{ + PRFileDesc* fd; + PRSpecialFD which; + RCFileIO* spec = NULL; + + switch (special) + { + case RCFileIO::input: which = PR_StandardInput; break; + case RCFileIO::output: which = PR_StandardOutput; break; + case RCFileIO::error: which = PR_StandardError; break; + default: which = (PRSpecialFD)-1; + } + fd = PR_GetSpecialFD(which); + if (NULL != fd) + { + spec = new RCFileIO(); + if (NULL != spec) spec->fd = fd; + } + return spec; +} /* RCFileIO::GetSpecialFile */ + + +/* +** The following methods have been made non-virtual and private. These +** default implementations are intended to NEVER be called. They +** are not valid for this type of I/O class (normal and special file). +*/ +PRStatus RCFileIO::Connect(const RCNetAddr&, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetLocalName(RCNetAddr*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetPeerName(RCNetAddr*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::GetSocketOption(PRSocketOptionData*) const +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::Listen(PRIntn) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt16 RCFileIO::Poll(PRInt16, PRInt16*) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return 0; } + +PRInt32 RCFileIO::Recv(void*, PRSize, PRIntn, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Recvfrom(void*, PRSize, PRIntn, RCNetAddr*, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Send( + const void*, PRSize, PRIntn, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRInt32 RCFileIO::Sendto( + const void*, PRSize, PRIntn, const RCNetAddr&, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +RCIO* RCFileIO::Accept(RCNetAddr*, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return NULL; } + +PRStatus RCFileIO::Bind(const RCNetAddr&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt32 RCFileIO::AcceptRead( + RCIO**, RCNetAddr**, void*, PRSize, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +PRStatus RCFileIO::SetSocketOption(const PRSocketOptionData*) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCFileIO::Shutdown(RCIO::ShutdownHow) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt32 RCFileIO::TransmitFile( + RCIO*, const void*, PRSize, RCIO::FileDisposition, const RCInterval&) +{ PR_SetError(PR_INVALID_METHOD_ERROR, 0); return -1; } + +/* +** Class implementation for file information object (ref: prio.h) +*/ + +RCFileInfo::~RCFileInfo() { } + +RCFileInfo::RCFileInfo(const RCFileInfo& her): RCBase() + { info = her.info; } /* RCFileInfo::RCFileInfo */ + +RCTime RCFileInfo::CreationTime() const { return RCTime(info.creationTime); } + +RCTime RCFileInfo::ModifyTime() const { return RCTime(info.modifyTime); } + +RCFileInfo::FileType RCFileInfo::Type() const +{ + RCFileInfo::FileType type; + switch (info.type) + { + case PR_FILE_FILE: type = RCFileInfo::file; break; + case PR_FILE_DIRECTORY: type = RCFileInfo::directory; break; + default: type = RCFileInfo::other; + } + return type; +} /* RCFileInfo::Type */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.h new file mode 100644 index 00000000..576b37df --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcfileio.h @@ -0,0 +1,161 @@ +/* -*- 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 ***** */ + +/* +** Class definitions for normal and special file I/O (ref: prio.h) +*/ + +#if defined(_RCFILEIO_H) +#else +#define _RCFILEIO_H + +#include "rcio.h" +#include "rctime.h" + +/* +** One would normally create a concrete class, such as RCFileIO, but then +** pass around more generic references, ie., RCIO. +** +** This subclass of RCIO hides (makes private) the methods that are not +** applicable to normal files. +*/ + +class RCFileInfo; + +class PR_IMPLEMENT(RCFileIO): public RCIO +{ +public: + RCFileIO(); + virtual ~RCFileIO(); + + virtual PRInt64 Available(); + virtual PRStatus Close(); + static PRStatus Delete(const char *name); + virtual PRStatus FileInfo(RCFileInfo* info) const; + static PRStatus FileInfo(const char *name, RCFileInfo* info); + virtual PRStatus Fsync(); + virtual PRStatus Open(const char *name, PRIntn flags, PRIntn mode); + virtual PRInt32 Read(void *buf, PRSize amount); + virtual PRInt64 Seek(PRInt64 offset, RCIO::Whence how); + virtual PRInt32 Write(const void *buf, PRSize amount); + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout); + +private: + + /* These methods made private are unavailable for this object */ + RCFileIO(const RCFileIO&); + void operator=(const RCFileIO&); + + RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout); + PRInt32 AcceptRead( + RCIO **newfd, RCNetAddr **address, void *buffer, + PRSize amount, const RCInterval& timeout); + PRStatus Bind(const RCNetAddr& addr); + PRStatus Connect(const RCNetAddr& addr, const RCInterval& timeout); + PRStatus GetLocalName(RCNetAddr *addr) const; + PRStatus GetPeerName(RCNetAddr *addr) const; + PRStatus GetSocketOption(PRSocketOptionData *data) const; + PRStatus Listen(PRIntn backlog); + PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags); + PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout); + PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout); + PRStatus SetSocketOption(const PRSocketOptionData *data); + PRStatus Shutdown(RCIO::ShutdownHow how); + PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout); +public: + + /* + ** The following function return a valid normal file object, + ** Such objects can be used for scanned input and console output. + */ + typedef enum { + input = PR_StandardInput, + output = PR_StandardOutput, + error = PR_StandardError + } SpecialFile; + + static RCIO *GetSpecialFile(RCFileIO::SpecialFile special); + +}; /* RCFileIO */ + +class PR_IMPLEMENT(RCFileInfo): public RCBase +{ +public: + typedef enum { + file = PR_FILE_FILE, + directory = PR_FILE_DIRECTORY, + other = PR_FILE_OTHER + } FileType; + +public: + RCFileInfo(); + RCFileInfo(const RCFileInfo&); + + virtual ~RCFileInfo(); + + PRInt64 Size() const; + RCTime CreationTime() const; + RCTime ModifyTime() const; + RCFileInfo::FileType Type() const; + +friend PRStatus RCFileIO::FileInfo(RCFileInfo*) const; +friend PRStatus RCFileIO::FileInfo(const char *name, RCFileInfo*); + +private: + PRFileInfo64 info; +}; /* RCFileInfo */ + +inline RCFileInfo::RCFileInfo(): RCBase() { } +inline PRInt64 RCFileInfo::Size() const { return info.size; } + +#endif /* defined(_RCFILEIO_H) */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.cpp new file mode 100644 index 00000000..ff075a3a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.cpp @@ -0,0 +1,69 @@ +/* -*- 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 ***** */ + +/* +** C++ interval times (ref: prinrval.h) +** +** An interval is a period of time. The start of the interval (epoch) +** must be defined by the application. The unit of time of an interval +** is platform dependent, therefore so is the maximum interval that is +** representable. However, that interval is never less that ~12 hours. +*/ + +#include "rcinrval.h" + +RCInterval::~RCInterval() { } + +RCInterval::RCInterval(RCInterval::RCReservedInterval special): RCBase() +{ + switch (special) + { + case RCInterval::now: + interval = PR_IntervalNow(); + break; + case RCInterval::no_timeout: + interval = PR_INTERVAL_NO_TIMEOUT; + break; + case RCInterval::no_wait: + interval = PR_INTERVAL_NO_WAIT; + break; + default: + break; + } +} /* RCInterval::RCInterval */ + +/* rcinrval.cpp */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.h new file mode 100644 index 00000000..2dc24987 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcinrval.h @@ -0,0 +1,169 @@ +/* -*- 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 ***** */ + +/* +** C++ interval times (ref: prinrval.h) +** +** An interval is a period of time. The start of the interval (epoch) +** must be defined by the application. The unit of time of an interval +** is platform dependent, therefore so is the maximum interval that is +** representable. However, that interval is never less than ~6 hours. +*/ +#if defined(_RCINTERVAL_H) +#else +#define _RCINTERVAL_H + +#include "rcbase.h" +#include + +class PR_IMPLEMENT(RCInterval): public RCBase +{ +public: + typedef enum {now, no_timeout, no_wait} RCReservedInterval; + + virtual ~RCInterval(); + + RCInterval(); + + RCInterval(PRIntervalTime interval); + RCInterval(const RCInterval& copy); + RCInterval(RCReservedInterval special); + + void SetToNow(); + + void operator=(const RCInterval&); + void operator=(PRIntervalTime interval); + + PRBool operator<(const RCInterval&); + PRBool operator>(const RCInterval&); + PRBool operator==(const RCInterval&); + PRBool operator>=(const RCInterval&); + PRBool operator<=(const RCInterval&); + + RCInterval operator+(const RCInterval&); + RCInterval operator-(const RCInterval&); + RCInterval& operator+=(const RCInterval&); + RCInterval& operator-=(const RCInterval&); + + RCInterval operator/(PRUint32); + RCInterval operator*(PRUint32); + RCInterval& operator/=(PRUint32); + RCInterval& operator*=(PRUint32); + + + PRUint32 ToSeconds() const; + PRUint32 ToMilliseconds() const; + PRUint32 ToMicroseconds() const; + operator PRIntervalTime() const; + + static PRIntervalTime FromSeconds(PRUint32 seconds); + static PRIntervalTime FromMilliseconds(PRUint32 milli); + static PRIntervalTime FromMicroseconds(PRUint32 micro); + + friend class RCCondition; + +private: + PRIntervalTime interval; + +}; /* RCInterval */ + + +inline RCInterval::RCInterval(): RCBase() { } + +inline RCInterval::RCInterval(const RCInterval& his): RCBase() + { interval = his.interval; } + +inline RCInterval::RCInterval(PRIntervalTime ticks): RCBase() + { interval = ticks; } + +inline void RCInterval::SetToNow() { interval = PR_IntervalNow(); } + +inline void RCInterval::operator=(const RCInterval& his) + { interval = his.interval; } + +inline void RCInterval::operator=(PRIntervalTime his) + { interval = his; } + +inline PRBool RCInterval::operator==(const RCInterval& his) + { return (interval == his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator<(const RCInterval& his) + { return (interval < his.interval)? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator>(const RCInterval& his) + { return (interval > his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator<=(const RCInterval& his) + { return (interval <= his.interval) ? PR_TRUE : PR_FALSE; } +inline PRBool RCInterval::operator>=(const RCInterval& his) + { return (interval <= his.interval) ? PR_TRUE : PR_FALSE; } + +inline RCInterval RCInterval::operator+(const RCInterval& his) + { return RCInterval((PRIntervalTime)(interval + his.interval)); } +inline RCInterval RCInterval::operator-(const RCInterval& his) + { return RCInterval((PRIntervalTime)(interval - his.interval)); } +inline RCInterval& RCInterval::operator+=(const RCInterval& his) + { interval += his.interval; return *this; } +inline RCInterval& RCInterval::operator-=(const RCInterval& his) + { interval -= his.interval; return *this; } + +inline RCInterval RCInterval::operator/(PRUint32 him) + { return RCInterval((PRIntervalTime)(interval / him)); } +inline RCInterval RCInterval::operator*(PRUint32 him) + { return RCInterval((PRIntervalTime)(interval * him)); } + +inline RCInterval& RCInterval::operator/=(PRUint32 him) + { interval /= him; return *this; } + +inline RCInterval& RCInterval::operator*=(PRUint32 him) + { interval *= him; return *this; } + +inline PRUint32 RCInterval::ToSeconds() const + { return PR_IntervalToSeconds(interval); } +inline PRUint32 RCInterval::ToMilliseconds() const + { return PR_IntervalToMilliseconds(interval); } +inline PRUint32 RCInterval::ToMicroseconds() const + { return PR_IntervalToMicroseconds(interval); } +inline RCInterval::operator PRIntervalTime() const { return interval; } + +inline PRIntervalTime RCInterval::FromSeconds(PRUint32 seconds) + { return PR_SecondsToInterval(seconds); } +inline PRIntervalTime RCInterval::FromMilliseconds(PRUint32 milli) + { return PR_MillisecondsToInterval(milli); } +inline PRIntervalTime RCInterval::FromMicroseconds(PRUint32 micro) + { return PR_MicrosecondsToInterval(micro); } + +#endif /* defined(_RCINTERVAL_H) */ + +/* RCInterval.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.cpp new file mode 100644 index 00000000..27f9e788 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.cpp @@ -0,0 +1,46 @@ +/* -*- 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 ***** */ + +/* +** Base class implmenation for I/O (ref: prio.h) +*/ + +#include "rcio.h" + +RCIO::~RCIO() { } + +RCIO::RCIO(RCIO::RCIOType): RCBase() { } diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.h new file mode 100644 index 00000000..5550a881 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcio.h @@ -0,0 +1,148 @@ +/* -*- 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 ***** */ + +/* +** Base class definitions for I/O (ref: prio.h) +** +** This class is a virtual base class. Construction must be done by a +** subclass, but the I/O operations can be done on a RCIO object reference. +*/ + +#if defined(_RCIO_H) +#else +#define _RCIO_H + +#include "rcbase.h" +#include "rcnetdb.h" +#include "rcinrval.h" + +#include "prio.h" + +class RCFileInfo; + +class PR_IMPLEMENT(RCIO): public RCBase +{ +public: + typedef enum { + open = PR_TRANSMITFILE_KEEP_OPEN, /* socket is left open after file + * is transmitted. */ + close = PR_TRANSMITFILE_CLOSE_SOCKET/* socket is closed after file + * is transmitted. */ + } FileDisposition; + + typedef enum { + set = PR_SEEK_SET, /* Set to value specified */ + current = PR_SEEK_CUR, /* Seek relative to current position */ + end = PR_SEEK_END /* seek past end of current eof */ + } Whence; + + typedef enum { + recv = PR_SHUTDOWN_RCV, /* receives will be disallowed */ + send = PR_SHUTDOWN_SEND, /* sends will be disallowed */ + both = PR_SHUTDOWN_BOTH /* sends & receives will be disallowed */ + } ShutdownHow; + +public: + virtual ~RCIO(); + + virtual RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout) = 0; + virtual PRInt32 AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout) = 0; + virtual PRInt64 Available() = 0; + virtual PRStatus Bind(const RCNetAddr& addr) = 0; + virtual PRStatus Close() = 0; + virtual PRStatus Connect( + const RCNetAddr& addr, + const RCInterval& timeout) = 0; + virtual PRStatus FileInfo(RCFileInfo *info) const = 0; + virtual PRStatus Fsync() = 0; + virtual PRStatus GetLocalName(RCNetAddr *addr) const = 0; + virtual PRStatus GetPeerName(RCNetAddr *addr) const = 0; + virtual PRStatus GetSocketOption(PRSocketOptionData *data) const = 0; + virtual PRStatus Listen(PRIntn backlog) = 0; + virtual PRStatus Open(const char *name, PRIntn flags, PRIntn mode) = 0; + virtual PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags) = 0; + virtual PRInt32 Read(void *buf, PRSize amount) = 0; + virtual PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout) = 0; + virtual PRInt64 Seek(PRInt64 offset, Whence how) = 0; + virtual PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout) = 0; + virtual PRStatus SetSocketOption(const PRSocketOptionData *data) = 0; + virtual PRStatus Shutdown(ShutdownHow how) = 0; + virtual PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout) = 0; + virtual PRInt32 Write(const void *buf, PRSize amount) = 0; + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout) = 0; + +protected: + typedef enum { + file = PR_DESC_FILE, + tcp = PR_DESC_SOCKET_TCP, + udp = PR_DESC_SOCKET_UDP, + layered = PR_DESC_LAYERED} RCIOType; + + RCIO(RCIOType); + + PRFileDesc *fd; /* where the real code hides */ + +private: + /* no default construction and no copies allowed */ + RCIO(); + RCIO(const RCIO&); + +}; /* RCIO */ + +#endif /* defined(_RCIO_H) */ + +/* RCIO.h */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.cpp new file mode 100644 index 00000000..87b326bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.cpp @@ -0,0 +1,72 @@ +/* -*- 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 ***** */ +/* +** C++ access to NSPR locks (PRLock) +*/ + +#include "rclock.h" +#include + +RCLock::RCLock() +{ + lock = PR_NewLock(); /* it might be NULL */ + PR_ASSERT(NULL != lock); +} /* RCLock::RCLock */ + +RCLock::~RCLock() +{ + if (NULL != lock) PR_DestroyLock(lock); + lock = NULL; +} /* RCLock::~RCLock */ + +void RCLock::Acquire() +{ + PR_ASSERT(NULL != lock); + PR_Lock(lock); +} /* RCLock::Acquire */ + +void RCLock::Release() +{ + PRStatus rv; + PR_ASSERT(NULL != lock); + rv = PR_Unlock(lock); + PR_ASSERT(PR_SUCCESS == rv); +} /* RCLock::Release */ + +/* RCLock.cpp */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.h new file mode 100644 index 00000000..9e20ef04 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rclock.h @@ -0,0 +1,98 @@ +/* -*- 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 ***** */ + +/* +** C++ access to NSPR locks (PRLock) +*/ + +#if defined(_RCLOCK_H) +#else +#define _RCLOCK_H + +#include "rcbase.h" + +#include + +class PR_IMPLEMENT(RCLock): public RCBase +{ +public: + RCLock(); + virtual ~RCLock(); + + void Acquire(); /* non-reentrant */ + void Release(); /* should be by owning thread */ + + friend class RCCondition; + +private: + RCLock(const RCLock&); /* can't do that */ + void operator=(const RCLock&); /* nor that */ + + PRLock *lock; +}; /* RCLock */ + +/* +** Class: RCEnter +** +** In scope locks. You can only allocate them on the stack. The language +** will insure that they get released (by calling the destructor) when +** the thread leaves scope, even if via an exception. +*/ +class PR_IMPLEMENT(RCEnter) +{ +public: + ~RCEnter(); /* releases the lock */ + RCEnter(RCLock*); /* acquires the lock */ + +private: + RCLock *lock; + + RCEnter(); + RCEnter(const RCEnter&); + void operator=(const RCEnter&); + + void *operator new(PRSize) { return NULL; } + void operator delete(void*) { } +}; /* RCEnter */ + + +inline RCEnter::RCEnter(RCLock* ml) { lock = ml; lock->Acquire(); } +inline RCEnter::~RCEnter() { lock->Release(); lock = NULL; } + +#endif /* defined(_RCLOCK_H) */ + +/* RCLock.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcmon.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcmon.h new file mode 100644 index 00000000..75b8ca3e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcmon.h @@ -0,0 +1,79 @@ +/* -*- 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 ***** */ + +/* +** Class: RCMonitor (ref prmonitor.h) +** +** RCMonitor.h - C++ wrapper around NSPR's monitors +*/ +#if defined(_RCMONITOR_H) +#else +#define _RCMONITOR_H + +#include "rcbase.h" +#include "rcinrval.h" + +struct PRMonitor; + +class PR_IMPLEMENT(RCMonitor): public RCBase +{ +public: + RCMonitor(); /* timeout is infinity */ + virtual ~RCMonitor(); + + virtual void Enter(); /* reentrant entry */ + virtual void Exit(); + + virtual void Notify(); /* possibly enable one thread */ + virtual void NotifyAll(); /* enable all waiters */ + + virtual void Wait(); /* applies object's timeout */ + + virtual void SetTimeout(const RCInterval& timeout); + +private: + PRMonitor *monitor; + RCInterval timeout; + +public: + RCInterval GetTimeout() const; /* get the current value */ + +}; /* RCMonitor */ + +#endif /* defined(_RCMONITOR_H) */ + +/* RCMonitor.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.cpp new file mode 100644 index 00000000..9890c9ae --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.cpp @@ -0,0 +1,232 @@ +/* -*- 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 ***** */ + +/* +** Base class implementation for network access functions (ref: prnetdb.h) +*/ + +#include "rclock.h" +#include "rcnetdb.h" + +#include +#include +#include + +RCNetAddr::RCNetAddr(const RCNetAddr& his): RCBase() + { address = his.address; } + +RCNetAddr::RCNetAddr(const RCNetAddr& his, PRUint16 port): RCBase() +{ + address = his.address; + switch (address.raw.family) + { + case PR_AF_INET: address.inet.port = port; break; + case PR_AF_INET6: address.ipv6.port = port; break; + default: break; + } +} /* RCNetAddr::RCNetAddr */ + +RCNetAddr::RCNetAddr(RCNetAddr::HostValue host, PRUint16 port): RCBase() +{ + PRNetAddrValue how; + switch (host) + { + case RCNetAddr::any: how = PR_IpAddrAny; break; + case RCNetAddr::loopback: how = PR_IpAddrLoopback; break; + default: PR_ASSERT(!"This can't happen -- and did!"); + } + (void)PR_InitializeNetAddr(how, port, &address); +} /* RCNetAddr::RCNetAddr */ + +RCNetAddr::~RCNetAddr() { } + +void RCNetAddr::operator=(const RCNetAddr& his) { address = his.address; } + +PRStatus RCNetAddr::FromString(const char* string) + { return PR_StringToNetAddr(string, &address); } + +void RCNetAddr::operator=(const PRNetAddr* addr) { address = *addr; } + +PRBool RCNetAddr::operator==(const RCNetAddr& his) const +{ + PRBool rv = EqualHost(his); + if (rv) + { + switch (address.raw.family) + { + case PR_AF_INET: + rv = (address.inet.port == his.address.inet.port); break; + case PR_AF_INET6: + rv = (address.ipv6.port == his.address.ipv6.port); break; + case PR_AF_LOCAL: + default: break; + } + } + return rv; +} /* RCNetAddr::operator== */ + +PRBool RCNetAddr::EqualHost(const RCNetAddr& his) const +{ + PRBool rv; + switch (address.raw.family) + { + case PR_AF_INET: + rv = (address.inet.ip == his.address.inet.ip); break; + case PR_AF_INET6: + rv = (0 == memcmp( + &address.ipv6.ip, &his.address.ipv6.ip, + sizeof(address.ipv6.ip))); + break; +#if defined(XP_UNIX) + case PR_AF_LOCAL: + rv = (0 == strncmp( + address.local.path, his.address.local.path, + sizeof(address.local.path))); + break; +#endif + default: break; + } + return rv; +} /* RCNetAddr::operator== */ + +PRStatus RCNetAddr::ToString(char *string, PRSize size) const + { return PR_NetAddrToString(&address, string, size); } + +/* +** RCHostLookup +*/ + +RCHostLookup::~RCHostLookup() +{ + if (NULL != address) delete [] address; +} /* RCHostLookup::~RCHostLookup */ + +RCHostLookup::RCHostLookup(): RCBase() +{ + address = NULL; + max_index = 0; +} /* RCHostLookup::RCHostLookup */ + +PRStatus RCHostLookup::ByName(const char* name) +{ + PRStatus rv; + PRNetAddr addr; + PRHostEnt hostentry; + PRIntn index = 0, max; + RCNetAddr* vector = NULL; + RCNetAddr* old_vector = NULL; + void* buffer = PR_Malloc(PR_NETDB_BUF_SIZE); + if (NULL == buffer) return PR_FAILURE; + rv = PR_GetHostByName(name, (char*)buffer, PR_NETDB_BUF_SIZE, &hostentry); + if (PR_SUCCESS == rv) + { + for (max = 0, index = 0;; ++max) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + } + if (max > 0) + { + vector = new RCNetAddr[max]; + while (--max > 0) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + vector[index] = &addr; + } + { + RCEnter entry(&ml); + old_vector = address; + address = vector; + max_index = max; + } + if (NULL != old_vector) delete [] old_vector; + } + } + if (NULL != buffer) PR_DELETE(buffer); + return PR_SUCCESS; +} /* RCHostLookup::ByName */ + +PRStatus RCHostLookup::ByAddress(const RCNetAddr& host_addr) +{ + PRStatus rv; + PRNetAddr addr; + PRHostEnt hostentry; + PRIntn index = 0, max; + RCNetAddr* vector = NULL; + RCNetAddr* old_vector = NULL; + char *buffer = (char*)PR_Malloc(PR_NETDB_BUF_SIZE); + if (NULL == buffer) return PR_FAILURE; + rv = PR_GetHostByAddr(host_addr, buffer, PR_NETDB_BUF_SIZE, &hostentry); + if (PR_SUCCESS == rv) + { + for (max = 0, index = 0;; ++max) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + } + if (max > 0) + { + vector = new RCNetAddr[max]; + while (--max > 0) + { + index = PR_EnumerateHostEnt(index, &hostentry, 0, &addr); + if (0 == index) break; + vector[index] = &addr; + } + { + RCEnter entry(&ml); + old_vector = address; + address = vector; + max_index = max; + } + if (NULL != old_vector) delete [] old_vector; + } + } + if (NULL != buffer) PR_DELETE(buffer); + return PR_SUCCESS; +} /* RCHostLookup::ByAddress */ + +const RCNetAddr* RCHostLookup::operator[](PRUintn which) +{ + RCNetAddr* addr = NULL; + if (which < max_index) + addr = &address[which]; + return addr; +} /* RCHostLookup::operator[] */ + +/* RCNetdb.cpp */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.h new file mode 100644 index 00000000..03f5b4f0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetdb.h @@ -0,0 +1,129 @@ +/* -*- 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 ***** */ + +/* +** Base class definitions for network access functions (ref: prnetdb.h) +*/ + +#if defined(_RCNETDB_H) +#else +#define _RCNETDB_H + +#include "rclock.h" +#include "rcbase.h" + +#include + +class PR_IMPLEMENT(RCNetAddr): public RCBase +{ +public: + typedef enum { + any = PR_IpAddrAny, /* assign logical INADDR_ANY */ + loopback = PR_IpAddrLoopback /* assign logical INADDR_LOOPBACK */ + } HostValue; + + RCNetAddr(); /* default constructor is unit'd object */ + RCNetAddr(const RCNetAddr&); /* copy constructor */ + RCNetAddr(HostValue, PRUint16 port);/* init'd w/ 'special' assignments */ + RCNetAddr(const RCNetAddr&, PRUint16 port); + /* copy w/ port reassigment */ + + virtual ~RCNetAddr(); + + void operator=(const RCNetAddr&); + + virtual PRBool operator==(const RCNetAddr&) const; + /* compare of all relavent fields */ + virtual PRBool EqualHost(const RCNetAddr&) const; + /* compare of just host field */ + + +public: + + void operator=(const PRNetAddr*); /* construction from more primitive data */ + operator const PRNetAddr*() const; /* extraction of underlying representation */ + virtual PRStatus FromString(const char* string); + /* initialization from an ASCII string */ + virtual PRStatus ToString(char *string, PRSize size) const; + /* convert internal fromat to a string */ + +private: + + PRNetAddr address; + +}; /* RCNetAddr */ + +/* +** Class: RCHostLookup +** +** Abstractions to look up host names and addresses. +** +** This is a stateful class. One looks up the host by name or by +** address, then enumerates over a possibly empty array of network +** addresses. The storage for the addresses is owned by the class. +*/ + +class RCHostLookup: public RCBase +{ +public: + virtual ~RCHostLookup(); + + RCHostLookup(); + + virtual PRStatus ByName(const char* name); + virtual PRStatus ByAddress(const RCNetAddr&); + + virtual const RCNetAddr* operator[](PRUintn); + +private: + RCLock ml; + PRIntn max_index; + RCNetAddr* address; + + RCHostLookup(const RCHostLookup&); + RCHostLookup& operator=(const RCHostLookup&); +}; + +inline RCNetAddr::RCNetAddr(): RCBase() { } +inline RCNetAddr::operator const PRNetAddr*() const { return &address; } + + +#endif /* defined(_RCNETDB_H) */ + +/* RCNetdb.h */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.cpp new file mode 100644 index 00000000..bdc94309 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.cpp @@ -0,0 +1,195 @@ +/* -*- 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 ***** */ + +/* +** Subclass implementation for streamed network I/O (ref: prio.h) +*/ + +#include "rcnetio.h" + +#include + +RCNetStreamIO::~RCNetStreamIO() + { PRStatus rv = (fd->methods->close)(fd); fd = NULL; } + +RCNetStreamIO::RCNetStreamIO(): RCIO(RCIO::tcp) + { fd = PR_NewTCPSocket(); } + +RCNetStreamIO::RCNetStreamIO(PRIntn protocol): RCIO(RCIO::tcp) + { fd = PR_Socket(PR_AF_INET, PR_SOCK_STREAM, protocol); } + +RCIO* RCNetStreamIO::Accept(RCNetAddr* addr, const RCInterval& timeout) +{ + PRNetAddr peer; + RCNetStreamIO* rcio = NULL; + PRFileDesc* newfd = fd->methods->accept(fd, &peer, timeout); + if (NULL != newfd) + { + rcio = new RCNetStreamIO(); + if (NULL != rcio) + { + *addr = &peer; + rcio->fd = newfd; + } + else + (void)(newfd->methods->close)(newfd); + } + return rcio; +} /* RCNetStreamIO::Accept */ + +PRInt32 RCNetStreamIO::AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout) +{ + PRNetAddr *from; + PRFileDesc *accepted; + PRInt32 rv = (fd->methods->acceptread)( + fd, &accepted, &from, buf, amount, timeout); + if (rv >= 0) + { + RCNetStreamIO *ns = new RCNetStreamIO(); + if (NULL != *nd) ns->fd = accepted; + else {PR_Close(accepted); rv = -1; } + *nd = ns; + } + return rv; +} /* RCNetStreamIO::AcceptRead */ + +PRInt64 RCNetStreamIO::Available() + { return (fd->methods->available64)(fd); } + +PRStatus RCNetStreamIO::Bind(const RCNetAddr& addr) + { return (fd->methods->bind)(fd, addr); } + +PRStatus RCNetStreamIO::Connect(const RCNetAddr& addr, const RCInterval& timeout) + { return (fd->methods->connect)(fd, addr, timeout); } + +PRStatus RCNetStreamIO::GetLocalName(RCNetAddr *addr) const +{ + PRNetAddr local; + PRStatus rv = (fd->methods->getsockname)(fd, &local); + if (PR_SUCCESS == rv) *addr = &local; + return rv; +} /* RCNetStreamIO::GetLocalName */ + +PRStatus RCNetStreamIO::GetPeerName(RCNetAddr *addr) const +{ + PRNetAddr peer; + PRStatus rv = (fd->methods->getpeername)(fd, &peer); + if (PR_SUCCESS == rv) *addr = &peer; + return rv; +} /* RCNetStreamIO::GetPeerName */ + +PRStatus RCNetStreamIO::GetSocketOption(PRSocketOptionData *data) const + { return (fd->methods->getsocketoption)(fd, data); } + +PRStatus RCNetStreamIO::Listen(PRIntn backlog) + { return (fd->methods->listen)(fd, backlog); } + +PRInt16 RCNetStreamIO::Poll(PRInt16 in_flags, PRInt16 *out_flags) + { return (fd->methods->poll)(fd, in_flags, out_flags); } + +PRInt32 RCNetStreamIO::Read(void *buf, PRSize amount) + { return (fd->methods->read)(fd, buf, amount); } + +PRInt32 RCNetStreamIO::Recv( + void *buf, PRSize amount, PRIntn flags, const RCInterval& timeout) + { return (fd->methods->recv)(fd, buf, amount, flags, timeout); } + +PRInt32 RCNetStreamIO::Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout) +{ + PRNetAddr peer; + PRInt32 rv = (fd->methods->recvfrom)( + fd, buf, amount, flags, &peer, timeout); + if (-1 != rv) *addr = &peer; + return rv; +} /* RCNetStreamIO::Recvfrom */ + +PRInt32 RCNetStreamIO::Send( + const void *buf, PRSize amount, PRIntn flags, const RCInterval& timeout) + { return (fd->methods->send)(fd, buf, amount, flags, timeout); } + +PRInt32 RCNetStreamIO::Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, const RCInterval& timeout) + { return (fd->methods->sendto)(fd, buf, amount, flags, addr, timeout); } + +PRStatus RCNetStreamIO::SetSocketOption(const PRSocketOptionData *data) + { return (fd->methods->setsocketoption)(fd, data); } + +PRStatus RCNetStreamIO::Shutdown(RCIO::ShutdownHow how) + { return (fd->methods->shutdown)(fd, (PRIntn)how); } + +PRInt32 RCNetStreamIO::TransmitFile( + RCIO *source, const void *headers, PRSize hlen, + RCIO::FileDisposition flags, const RCInterval& timeout) +{ + RCNetStreamIO *src = (RCNetStreamIO*)source; + return (fd->methods->transmitfile)( + fd, src->fd, headers, hlen, (PRTransmitFileFlags)flags, timeout); } + +PRInt32 RCNetStreamIO::Write(const void *buf, PRSize amount) + { return (fd->methods->write)(fd, buf, amount); } + +PRInt32 RCNetStreamIO::Writev( + const PRIOVec *iov, PRSize size, const RCInterval& timeout) + { return (fd->methods->writev)(fd, iov, size, timeout); } + +/* +** Invalid functions +*/ + +PRStatus RCNetStreamIO::Close() + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCNetStreamIO::FileInfo(RCFileInfo*) const + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRStatus RCNetStreamIO::Fsync() + { return (fd->methods->fsync)(fd); } + +PRStatus RCNetStreamIO::Open(const char*, PRIntn, PRIntn) + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +PRInt64 RCNetStreamIO::Seek(PRInt64, RCIO::Whence) + { PR_SetError(PR_INVALID_METHOD_ERROR, 0); return PR_FAILURE; } + +/* RCNetStreamIO.cpp */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.h new file mode 100644 index 00000000..54ce695f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcnetio.h @@ -0,0 +1,126 @@ +/* -*- 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 ***** */ + +/* +** Subclass definitions for network I/O (ref: prio.h) +*/ + +#if defined(_RCNETIO_H) +#else +#define _RCNETIO_H + +#include "rcbase.h" +#include "rcinrval.h" +#include "rcio.h" +#include "rcnetdb.h" + +#include "prio.h" + +class RCFileInfo; + +/* +** Class: RCNetStreamIO (ref prio.h) +** +** Streamed (reliable) network I/O (e.g., TCP). +** This class hides (makes private) the functions that are not applicable +** to network I/O (i.e., those for file I/O). +*/ + +class PR_IMPLEMENT(RCNetStreamIO): public RCIO +{ + +public: + RCNetStreamIO(); + virtual ~RCNetStreamIO(); + + virtual RCIO* Accept(RCNetAddr* addr, const RCInterval& timeout); + virtual PRInt32 AcceptRead( + RCIO **nd, RCNetAddr **raddr, void *buf, + PRSize amount, const RCInterval& timeout); + virtual PRInt64 Available(); + virtual PRStatus Bind(const RCNetAddr& addr); + virtual PRStatus Connect( + const RCNetAddr& addr, const RCInterval& timeout); + virtual PRStatus GetLocalName(RCNetAddr *addr) const; + virtual PRStatus GetPeerName(RCNetAddr *addr) const; + virtual PRStatus GetSocketOption(PRSocketOptionData *data) const; + virtual PRStatus Listen(PRIntn backlog); + virtual PRInt16 Poll(PRInt16 in_flags, PRInt16 *out_flags); + virtual PRInt32 Read(void *buf, PRSize amount); + virtual PRInt32 Recv( + void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + virtual PRInt32 Recvfrom( + void *buf, PRSize amount, PRIntn flags, + RCNetAddr* addr, const RCInterval& timeout); + virtual PRInt32 Send( + const void *buf, PRSize amount, PRIntn flags, + const RCInterval& timeout); + virtual PRInt32 Sendto( + const void *buf, PRSize amount, PRIntn flags, + const RCNetAddr& addr, + const RCInterval& timeout); + virtual PRStatus SetSocketOption(const PRSocketOptionData *data); + virtual PRStatus Shutdown(ShutdownHow how); + virtual PRInt32 TransmitFile( + RCIO *source, const void *headers, + PRSize hlen, RCIO::FileDisposition flags, + const RCInterval& timeout); + virtual PRInt32 Write(const void *buf, PRSize amount); + virtual PRInt32 Writev( + const PRIOVec *iov, PRSize size, + const RCInterval& timeout); + +private: + /* functions unavailable to this clients of this class */ + RCNetStreamIO(const RCNetStreamIO&); + + PRStatus Close(); + PRStatus Open(const char *name, PRIntn flags, PRIntn mode); + PRStatus FileInfo(RCFileInfo *info) const; + PRStatus Fsync(); + PRInt64 Seek(PRInt64 offset, RCIO::Whence how); + +public: + RCNetStreamIO(PRIntn protocol); +}; /* RCNetIO */ + +#endif /* defined(_RCNETIO_H) */ + +/* RCNetStreamIO.h */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.cpp new file mode 100644 index 00000000..10a7ce92 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.cpp @@ -0,0 +1,220 @@ +/* -*- 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 ***** */ + +/* RCThread.cpp - C++ wrapper on NSPR */ + +#include "rcthread.h" +#include "rcinrval.h" + +#include +#include +#include +#include + +static RCPrimordialThread *primordial = NULL; + +void nas_Root(void *arg) +{ + RCThread *him = (RCThread*)arg; + while (RCThread::ex_unstarted == him->execution) + (void)PR_Sleep(PR_INTERVAL_NO_TIMEOUT); /* wait for Start() */ + him->RootFunction(); /* he gets a self reference */ + if (PR_UNJOINABLE_THREAD == PR_GetThreadState(him->identity)) + delete him; +} /* nas_Root */ + +RCThread::~RCThread() { } + +RCThread::RCThread(): RCBase() { } + +RCThread::RCThread(const RCThread&): RCBase() +{ + PR_NOT_REACHED("Cannot call thread copy constructor"); +} /* RCThread::RCThread */ + +RCThread::RCThread( + RCThread::Scope scope, RCThread::State join, PRUint32 stackSize): + RCBase() +{ + execution = ex_unstarted; + identity = PR_CreateThread( + PR_USER_THREAD, nas_Root, this, + PR_GetThreadPriority(PR_CurrentThread()), + (PRThreadScope)scope, (PRThreadState)join, stackSize); +} /* RCThread::RCThread */ + +void RCThread::operator=(const RCThread&) +{ + PR_NOT_REACHED("Cannot call thread assignment operator"); +} /* RCThread::operator= */ + + +PRStatus RCThread::Start() +{ + PRStatus rv; + /* This is an unsafe check, but not too critical */ + if (RCThread::ex_unstarted == execution) + { + execution = RCThread::ex_started; + rv = PR_Interrupt(identity); + PR_ASSERT(PR_SUCCESS == rv); + } + else + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + return rv; +} /* RCThread::Start */ + +PRStatus RCThread::Join() +{ + PRStatus rv; + if (RCThread::ex_unstarted == execution) + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + else rv = PR_JoinThread(identity); + if (PR_SUCCESS == rv) delete this; + return rv; +} /* RCThread::Join */ + +PRStatus RCThread::Interrupt() +{ + PRStatus rv; + if (RCThread::ex_unstarted == execution) + { + rv = PR_FAILURE; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + } + else rv = PR_Interrupt(identity); + return rv; +} /* RCThread::Interrupt */ + +void RCThread::ClearInterrupt() { PR_ClearInterrupt(); } + +void RCThread::SetPriority(RCThread::Priority new_priority) + { PR_SetThreadPriority(identity, (PRThreadPriority)new_priority); } + +PRThread *RCThread::Self() + { return PR_CurrentThread(); } + +RCThread::Scope RCThread::GetScope() const + { return (RCThread::Scope)PR_GetThreadScope(identity); } + +RCThread::State RCThread::GetState() const + { return (RCThread::State)PR_GetThreadState(identity); } + +RCThread::Priority RCThread::GetPriority() const + { return (RCThread::Priority)PR_GetThreadPriority(identity); } + +static void _rc_PDDestructor(RCThreadPrivateData* privateData) +{ + PR_ASSERT(NULL != privateData); + privateData->Release(); +} + +static PRThreadPrivateDTOR _tpd_dtor = (PRThreadPrivateDTOR)_rc_PDDestructor; + +PRStatus RCThread::NewPrivateIndex(PRUintn* index) + { return PR_NewThreadPrivateIndex(index, _tpd_dtor); } + +PRStatus RCThread::SetPrivateData(PRUintn index) + { return PR_SetThreadPrivate(index, NULL); } + +PRStatus RCThread::SetPrivateData(PRUintn index, RCThreadPrivateData* data) +{ + return PR_SetThreadPrivate(index, data); +} + +RCThreadPrivateData* RCThread::GetPrivateData(PRUintn index) + { return (RCThreadPrivateData*)PR_GetThreadPrivate(index); } + +PRStatus RCThread::Sleep(const RCInterval& ticks) + { PRIntervalTime tmo = ticks; return PR_Sleep(tmo); } + +RCPrimordialThread *RCThread::WrapPrimordialThread() +{ + /* + ** This needs to take more care in insuring that the thread + ** being wrapped is really the primordial thread. This code + ** is assuming that the caller is the primordial thread, and + ** there's nothing to insure that. + */ + if (NULL == primordial) + { + /* it doesn't have to be perfect */ + RCPrimordialThread *me = new RCPrimordialThread(); + PR_ASSERT(NULL != me); + if (NULL == primordial) + { + primordial = me; + me->execution = RCThread::ex_started; + me->identity = PR_GetCurrentThread(); + } + else delete me; /* somebody beat us to it */ + } + return primordial; +} /* RCThread::WrapPrimordialThread */ + +RCPrimordialThread::RCPrimordialThread(): RCThread() { } + +RCPrimordialThread::~RCPrimordialThread() { } + +void RCPrimordialThread::RootFunction() +{ + PR_NOT_REACHED("Primordial thread calling root function"); +} /* RCPrimordialThread::RootFunction */ + +PRStatus RCPrimordialThread::Cleanup() { return PR_Cleanup(); } + +PRStatus RCPrimordialThread::SetVirtualProcessors(PRIntn count) +{ + PR_SetConcurrency(count); + return PR_SUCCESS; +} /* SetVirutalProcessors */ + +RCThreadPrivateData::RCThreadPrivateData() { } + +RCThreadPrivateData::RCThreadPrivateData( + const RCThreadPrivateData& him) { } + +RCThreadPrivateData::~RCThreadPrivateData() { } + +/* RCThread.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.h new file mode 100644 index 00000000..2b000564 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rcthread.h @@ -0,0 +1,227 @@ +/* -*- 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 ***** */ + +/* RCThread.h */ + +#if defined(_RCTHREAD_H) +#else +#define _RCTHREAD_H + +#include "rcbase.h" + +#include + +class RCInterval; + +class PR_IMPLEMENT(RCThreadPrivateData) +{ +public: + RCThreadPrivateData(); + RCThreadPrivateData(const RCThreadPrivateData&); + + virtual ~RCThreadPrivateData(); + + virtual void Release() = 0; + +}; /* RCThreadPrivateData */ + +class PR_IMPLEMENT(RCThread): public RCBase +{ +public: + + typedef enum + { + local = PR_LOCAL_THREAD, global = PR_GLOBAL_THREAD + } Scope; + + typedef enum + { + joinable = PR_JOINABLE_THREAD, unjoinable = PR_UNJOINABLE_THREAD + } State; + + typedef enum + { + first = PR_PRIORITY_FIRST, + low = PR_PRIORITY_LOW, + normal = PR_PRIORITY_NORMAL, + high = PR_PRIORITY_HIGH, + urgent = PR_PRIORITY_URGENT, + last = PR_PRIORITY_LAST + } Priority; + + /* + * Create a new thread, providing scope and joinability state. + */ + RCThread(Scope scope, State state, PRUint32 stackSize=0); + + /* + * New threads are created in a suspended state. It must be 'started" + * before it begins execution in the class' defined 'RootFunction()'. + */ + virtual PRStatus Start(); + + /* + * If a thread is created joinable, then the thread's object exists + * until join is called. The thread that calls join will block until + * the target thread returns from it's root function. + */ + virtual PRStatus Join(); + + /* + * The priority of a newly created thread is the same as the creator. + * The priority may be changed either by the new thread itself, by + * the creator or any other arbitrary thread. + */ + virtual void SetPriority(Priority newPriority); + + + /* + * Interrupt another thread, causing it to stop what it + * is doing and return with a well known error code. + */ + virtual PRStatus Interrupt(); + + /* + * And in case a thread was interrupted and didn't get a chance + * to have the notification delivered, a way to cancel the pending + * status. + */ + static void ClearInterrupt(); + + /* + * Methods to discover the attributes of an existing thread. + */ + static PRThread *Self(); + Scope GetScope() const; + State GetState() const; + Priority GetPriority() const; + + /* + * Thread private data + */ + static PRStatus NewPrivateIndex(PRUintn* index); + + /* + * Getting it - if you want to modify, make a copy + */ + static RCThreadPrivateData* GetPrivateData(PRUintn index); + + /* + * Setting it to - deletes existing data + */ + static PRStatus SetPrivateData(PRUintn index); + + /* + * Setting it - runtime will make a copy, freeing old iff necessary + */ + static PRStatus SetPrivateData(PRUintn index, RCThreadPrivateData* data); + + /* + * Scheduling control + */ + static PRStatus Sleep(const RCInterval& ticks); + + friend void nas_Root(void*); + friend class RCPrimordialThread; +protected: + + /* + * The instantiator of a class must not call the destructor. The base + * implementation of Join will, and if the thread is created unjoinable, + * then the code that called the RootFunction will call the desctructor. + */ + virtual ~RCThread(); + +private: + + /* + * This is where a newly created thread begins execution. Returning + * from this function is equivalent to terminating the thread. + */ + virtual void RootFunction() = 0; + + PRThread *identity; + + /* Threads are unstarted until started - pretty startling */ + enum {ex_unstarted, ex_started} execution; + + /* There is no public default constructor or copy constructor */ + RCThread(); + RCThread(const RCThread&); + + /* And there is no assignment operator */ + void operator=(const RCThread&); + +public: + static RCPrimordialThread *WrapPrimordialThread(); + + }; + +/* +** class RCPrimordialThread +*/ +class PR_IMPLEMENT(RCPrimordialThread): public RCThread +{ +public: + /* + ** The primordial thread can (optionally) wait for all created + ** threads to terminate before allowing the process to exit. + ** Not calling Cleanup() before returning from main() will cause + ** the immediate termination of the entire process, including + ** any running threads. + */ + static PRStatus Cleanup(); + + /* + ** Only the primordial thread is allowed to adjust the number of + ** virtual processors of the runtime. It's a lame security thing. + */ + static PRStatus SetVirtualProcessors(PRIntn count=10); + +friend class RCThread; +private: + /* + ** None other than the runtime can create of destruct + ** a primordial thread. It is fabricated by the runtime + ** to wrap the thread that initiated the application. + */ + RCPrimordialThread(); + ~RCPrimordialThread(); + void RootFunction(); +}; /* RCPrimordialThread */ + + #endif /* defined(_RCTHREAD_H) */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.cpp new file mode 100644 index 00000000..6f02b413 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.cpp @@ -0,0 +1,66 @@ +/* -*- 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 ***** */ + +/* +** Class implementation for calendar time routines (ref: prtime.h) +*/ + +#include "rctime.h" + +RCTime::~RCTime() { } + +RCTime::RCTime(PRTime time): RCBase() { gmt = time; } +RCTime::RCTime(const RCTime& his): RCBase() { gmt = his.gmt; } +RCTime::RCTime(RCTime::Current): RCBase() { gmt = PR_Now(); } +RCTime::RCTime(const PRExplodedTime& time): RCBase() +{ gmt = PR_ImplodeTime(&time); } + +void RCTime::operator=(const PRExplodedTime& time) +{ gmt = PR_ImplodeTime(&time); } + +RCTime RCTime::operator+(const RCTime& his) +{ RCTime sum(gmt + his.gmt); return sum; } + +RCTime RCTime::operator-(const RCTime& his) +{ RCTime difference(gmt - his.gmt); return difference; } + +RCTime RCTime::operator/(PRUint64 his) +{ RCTime quotient(gmt / his); return quotient; } + +RCTime RCTime::operator*(PRUint64 his) +{ RCTime product(gmt * his); return product; } + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.h b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.h new file mode 100644 index 00000000..f0b900a2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/rctime.h @@ -0,0 +1,138 @@ +/* -*- 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 ***** */ + +/* +** Class definitions for calendar time routines (ref: prtime.h) +*/ + +#if defined(_RCTIME_H) +#else +#define _RCTIME_H + +#include "rcbase.h" + +#include + +/* +** Class: RCTime (ref: prtime.h) +** +** RCTimes are objects that are intended to be used to represent calendar +** times. They maintain units internally as microseconds since the defined +** epoch (midnight, January 1, 1970, GMT). Conversions to and from external +** formats (PRExplodedTime) are available. +** +** In general, NCTimes possess normal algebretic capabilities. +*/ + +class PR_IMPLEMENT(RCTime): public RCBase +{ +public: + typedef enum {now} Current; + + RCTime(); /* leaves the object unitialized */ + RCTime(Current); /* initializes to current system time */ + RCTime(const RCTime&); /* copy constructor */ + RCTime(const PRExplodedTime&); /* construction from exploded representation */ + + virtual ~RCTime(); + + /* assignment operators */ + void operator=(const RCTime&); + void operator=(const PRExplodedTime&); + + /* comparitive operators */ + PRBool operator<(const RCTime&); + PRBool operator>(const RCTime&); + PRBool operator<=(const RCTime&); + PRBool operator>=(const RCTime&); + PRBool operator==(const RCTime&); + + /* associative operators */ + RCTime operator+(const RCTime&); + RCTime operator-(const RCTime&); + RCTime& operator+=(const RCTime&); + RCTime& operator-=(const RCTime&); + + /* multiply and divide operators */ + RCTime operator/(PRUint64); + RCTime operator*(PRUint64); + RCTime& operator/=(PRUint64); + RCTime& operator*=(PRUint64); + + void Now(); /* assign current time to object */ + +private: + PRTime gmt; + +public: + + RCTime(PRTime); /* construct from raw PRTime */ + void operator=(PRTime); /* assign from raw PRTime */ + operator PRTime() const; /* extract internal representation */ +}; /* RCTime */ + +inline RCTime::RCTime(): RCBase() { } + +inline void RCTime::Now() { gmt = PR_Now(); } +inline RCTime::operator PRTime() const { return gmt; } + +inline void RCTime::operator=(PRTime his) { gmt = his; } +inline void RCTime::operator=(const RCTime& his) { gmt = his.gmt; } + +inline PRBool RCTime::operator<(const RCTime& his) + { return (gmt < his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator>(const RCTime& his) + { return (gmt > his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator<=(const RCTime& his) + { return (gmt <= his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator>=(const RCTime& his) + { return (gmt >= his.gmt) ? PR_TRUE : PR_FALSE; } +inline PRBool RCTime::operator==(const RCTime& his) + { return (gmt == his.gmt) ? PR_TRUE : PR_FALSE; } + +inline RCTime& RCTime::operator+=(const RCTime& his) + { gmt += his.gmt; return *this; } +inline RCTime& RCTime::operator-=(const RCTime& his) + { gmt -= his.gmt; return *this; } +inline RCTime& RCTime::operator/=(PRUint64 his) + { gmt /= his; return *this; } +inline RCTime& RCTime::operator*=(PRUint64 his) + { gmt *= his; return *this; } + +#endif /* defined(_RCTIME_H) */ + +/* RCTime.h */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/Makefile.in new file mode 100644 index 00000000..e786d585 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/Makefile.in @@ -0,0 +1,288 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + +CXXSRCS = \ + ranfile.cpp \ + thread.cpp \ + interval.cpp \ + time.cpp \ + fileio.cpp \ + switch.cpp \ + tpd.cpp \ + $(NULL) + +OBJS = $(addprefix $(OBJDIR)/,$(CXXSRCS:.cpp=.$(OBJ_SUFFIX))) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CXXSRCS:.cpp=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) $(OBJS) + +INCLUDES = -I.. -I$(dist_includedir) + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(MOD_MAJOR_VERSION) +LIBPL = -lplc$(MOD_MAJOR_VERSION) + +ifeq ($(OS_ARCH), IRIX) + LDOPTS += -rpath $(PWD)/$(dist_libdir) -rdata_shared + # For 6.x machines, include this flag + ifeq ($(basename $(OS_RELEASE)),6) + ifeq ($(USE_N32),1) + LDOPTS += -n32 + else + LDOPTS += -32 + endif + + ifeq ($(USE_PTHREADS), 1) + ifeq ($(OS_RELEASE), 6.2) + LDOPTS += -Wl,-woff,85 + endif + endif + endif +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) + ifneq ($(OS_RELEASE), 4.1.3_U1) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) + else + LDOPTS += -R $(PWD)/$(dist_libdir) + endif + endif + + ifneq ($(LOCAL_THREADS_ONLY),1) +# SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, +# even though we already linked with these system libraries +# when we built libnspr.so. + ifeq ($(OS_RELEASE), 5.4) + EXTRA_LIBS = -lthread + endif + + ifeq ($(OS_RELEASE), 5.5) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread + else + EXTRA_LIBS = -lthread + endif + endif + endif # LOCAL_THREADS_ONLY +endif # SunOS + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPL = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib +else + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) + LIBPL = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib + LIBPLC = $(dist_libdir)/plc$(MOD_MAJOR_VERSION).lib + else + LDOPTS += -Zomf -Zlinker /PM:VIO -lstdcpp + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), HP-UX) + LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) + LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib + ifeq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LIBPR = -lnspr$(MOD_MAJOR_VERSION)_shr + LIBPLC = -lplc$(MOD_MAJOR_VERSION)_shr + else + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(PWD)/$(dist_libdir) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a +LIBPL = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +#export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), SCO_SV) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPL), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPL) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBGC) $(LIBPLC) $(LIBPR) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CCC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPL) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/fileio.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/fileio.cpp new file mode 100644 index 00000000..a01ea5eb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/fileio.cpp @@ -0,0 +1,65 @@ +/* -*- 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 ***** */ + +/* fileio.cpp - a test program */ + +#include "rcfileio.h" + +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + RCFileIO fd; + RCFileInfo info; + rv = fd.Open("filio.dat", PR_CREATE_FILE, 0666); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.FileInfo(&info); + PR_ASSERT(PR_SUCCESS == rv); + rv = fd.Delete("filio.dat"); + PR_ASSERT(PR_SUCCESS == rv); + fd.Close(); + PR_ASSERT(PR_SUCCESS == rv); + + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/interval.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/interval.cpp new file mode 100644 index 00000000..1223d67a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/interval.cpp @@ -0,0 +1,133 @@ +/* -*- 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 ***** */ + +/* interval.cpp - a test program */ + +#include "rclock.h" +#include "rcthread.h" +#include "rcinrval.h" +#include "rccv.h" + +#include +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCLock ml; + PRStatus rv; + RCCondition cv(&ml); + + RCInterval now, timeout, epoch, elapsed; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + PRIntn msecs, seconds, loops, iterations = DEFAULT_ITERATIONS; + + /* slow, agonizing waits */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Waiting %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* more slow, agonizing sleeps */ + for (seconds = 0; seconds < 10; ++seconds) + { + timeout = RCInterval::FromSeconds(seconds); + { + epoch.SetToNow(); + + rv = RCThread::Sleep(timeout); + PR_ASSERT(PR_SUCCESS == rv); + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + + PR_fprintf( + output, "Sleeping %u seconds took %s%u milliseconds\n", + seconds, ((elapsed < timeout)? "**" : ""), + elapsed.ToMilliseconds()); + } + + /* fast, spritely little devils */ + for (msecs = 10; msecs < 100; msecs += 10) + { + timeout = RCInterval::FromMilliseconds(msecs); + cv.SetTimeout(timeout); + { + RCEnter lock(&ml); + + epoch.SetToNow(); + + for (loops = 0; loops < iterations; ++loops) + { + rv = cv.Wait(); + PR_ASSERT(PR_SUCCESS == rv); + } + + now = RCInterval(RCInterval::now); + elapsed = now - epoch; + } + elapsed /= iterations; + + PR_fprintf( + output, "Waiting %u msecs took %s%u milliseconds average\n", + msecs, ((elapsed < timeout)? "**" : ""), elapsed.ToMilliseconds()); + } + return 0; +} /* main */ + +/* interval.cpp */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/ranfile.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/ranfile.cpp new file mode 100644 index 00000000..b745b15c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/ranfile.cpp @@ -0,0 +1,432 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Contact: AOF +** +** Name: ranfile.c +** +** Description: Test to hammer on various components of NSPR +** Modification History: +** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include +#include +#include + +#include "rccv.h" +#include "rcthread.h" +#include "rcfileio.h" +#include "rclock.h" + +#include +#include +#include + +static PRFileDesc *output; +static PRIntn debug_mode = 0; +static PRIntn failed_already = 0; + +class HammerData +{ +public: + typedef enum { + sg_go, sg_stop, sg_done} Action; + typedef enum { + sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem; + + virtual ~HammerData(); + HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip); + virtual PRUint32 Random(); + + Action action; + Problem problem; + PRUint32 writes; + RCInterval timein; +friend class Hammer; +private: + RCLock *ml; + RCCondition *cv; + PRUint32 limit; + + PRFloat64 seed; +}; /* HammerData */ + +class Hammer: public HammerData, public RCThread +{ +public: + virtual ~Hammer(); + Hammer(RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip); + +private: + void RootFunction(); + +}; + +static PRInt32 pageSize = 1024; +static const char* baseName = "./"; +static const char *programName = "Random File"; + +/*********************************************************************** +** PRIVATE FUNCTION: Random +** DESCRIPTION: +** Generate a pseudo-random number +** INPUTS: None +** OUTPUTS: None +** RETURN: A pseudo-random unsigned number, 32-bits wide +** SIDE EFFECTS: +** Updates random seed (a static) +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** Uses the current interval timer value, promoted to a 64 bit +** float as a multiplier for a static residue (which begins +** as an uninitialized variable). The result is bits [16..48) +** of the product. Seed is then updated with the return value +** promoted to a float-64. +***********************************************************************/ +PRUint32 HammerData::Random() +{ + PRUint32 rv; + PRUint64 shift; + RCInterval now = RCInterval(RCInterval::now); + PRFloat64 random = seed * (PRFloat64)((PRIntervalTime)now); + LL_USHR(shift, *((PRUint64*)&random), 16); + LL_L2UI(rv, shift); + seed = (PRFloat64)rv; + return rv; +} /* HammerData::Random */ + +Hammer::~Hammer() { } + +Hammer::Hammer( + RCThread::Scope scope, RCLock* lock, RCCondition *cond, PRUint32 clip): + HammerData(lock, cond, clip), RCThread(scope, RCThread::joinable, 0) { } + +HammerData::~HammerData() { } + +HammerData::HammerData(RCLock* lock, RCCondition *cond, PRUint32 clip) +{ + ml = lock; + cv = cond; + writes = 0; + limit = clip; + seed = 0x58a9382; + action = HammerData::sg_go; + problem = HammerData::sg_okay; + timein = RCInterval(RCInterval::now); +} /* HammerData::HammerData */ + + +/*********************************************************************** +** PRIVATE FUNCTION: Hammer::RootFunction +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: A pointer to the thread's private data +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes a file +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** This function is a root of a thread +** 1) Creates a (hopefully) unique file in /usr/tmp/ +** 2) Writes a zero to a random number of sequential pages +** 3) Closes the file +** 4) Reopens the file +** 5) Seeks to a random page within the file +** 6) Writes a one byte on that page +** 7) Repeat steps [5..6] for each page in the file +** 8) Close and delete the file +** 9) Repeat steps [1..8] until told to stop +** 10) Notify complete and return +***********************************************************************/ +void Hammer::RootFunction() +{ + PRUint32 index; + RCFileIO file; + char filename[30]; + const char zero = 0; + PRStatus rv = PR_SUCCESS; + + limit = (Random() % limit) + 1; + + (void)sprintf(filename, "%ssg%04p.dat", baseName, this); + + if (debug_mode) PR_fprintf(output, "Starting work on %s\n", filename); + + while (PR_TRUE) + { + PRUint64 bytes; + PRUint32 minor = (Random() % limit) + 1; + PRUint32 random = (Random() % limit) + 1; + PRUint32 pages = (Random() % limit) + 10; + while (minor-- > 0) + { + problem = sg_okay; + if (action != sg_go) goto finished; + problem = sg_open; + rv = file.Open(filename, PR_RDWR|PR_CREATE_FILE, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + + problem = sg_okay; + if (action != sg_go) goto purge; + + problem = sg_open; + rv = file.Open(filename, PR_RDWR, 0666); + if (PR_FAILURE == rv) goto finished; + for (index = 0; index < pages; index++) + { + problem = sg_okay; + if (action != sg_go) goto close; + problem = sg_seek; + bytes = file.Seek(pageSize * index, RCFileIO::set); + if (bytes != pageSize * index) goto close; + problem = sg_write; + bytes = file.Write(&zero, sizeof(zero)); + if (bytes <= 0) goto close; + writes += 1; + random = (random + 511) % pages; + } + problem = sg_close; + rv = file.Close(); + if (rv != PR_SUCCESS) goto purge; + problem = sg_delete; + rv = file.Delete(filename); + if (rv != PR_SUCCESS) goto finished; + } + } + +close: + (void)file.Close(); +purge: + (void)file.Delete(filename); +finished: + RCEnter scope(ml); + action = HammerData::sg_done; + cv->Notify(); + + if (debug_mode) PR_fprintf(output, "Ending work on %s\n", filename); + + return; +} /* Hammer::RootFunction */ + +static Hammer* hammer[100]; +/*********************************************************************** +** PRIVATE FUNCTION: main +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: The usual argc and argv +** argv[0] - program name (not used) +** argv[1] - the number of virtual_procs to execute the major loop +** argv[2] - the number of threads to toss into the batch +** argv[3] - the clipping number applied to randoms +** default values: max_virtual_procs = 2, threads = 10, limit = 57 +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes lots of files +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** 1) Fork a "Thread()" +** 2) Wait for 'interleave' seconds +** 3) For [0..'threads') repeat [1..2] +** 4) Mark all objects to stop +** 5) Collect the threads, accumulating the results +** 6) For [0..'max_virtual_procs') repeat [1..5] +** 7) Print accumulated results and exit +** +** Characteristic output (from IRIX) +** Random File: Using max_virtual_procs = 2, threads = 10, limit = 57 +** Random File: [min [avg] max] writes/sec average +***********************************************************************/ +PRIntn main (PRIntn argc, char *argv[]) +{ + RCLock ml; + PLOptStatus os; + RCCondition cv(&ml); + PRUint32 writesMax = 0, durationTot = 0; + RCThread::Scope thread_scope = RCThread::local; + PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0; + PRIntn active, poll, limit = 0, max_virtual_procs = 0, threads = 0, virtual_procs; + RCInterval interleave(RCInterval::FromMilliseconds(10000)), duration(0); + + const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; + + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + baseName = opt->value; + break; + case 'G': /* global threads */ + thread_scope = RCThread::global; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* limiting number */ + limit = atoi(opt->value); + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'i': /* iteration counter */ + max_virtual_procs = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + output = PR_GetSpecialFD(PR_StandardOutput); + + /* main test */ + + cv.SetTimeout(interleave); + + if (max_virtual_procs == 0) max_virtual_procs = 2; + if (limit == 0) limit = 57; + if (threads == 0) threads = 10; + + if (debug_mode) PR_fprintf(output, + "%s: Using %d virtual processors, %d threads, limit = %d and %s threads\n", + programName, max_virtual_procs, threads, limit, + (thread_scope == RCThread::local) ? "LOCAL" : "GLOBAL"); + + for (virtual_procs = 0; virtual_procs < max_virtual_procs; ++virtual_procs) + { + if (debug_mode) + PR_fprintf(output, + "%s: Setting number of virtual processors to %d\n", + programName, virtual_procs + 1); + RCPrimordialThread::SetVirtualProcessors(virtual_procs + 1); + for (active = 0; active < threads; active++) + { + hammer[active] = new Hammer(thread_scope, &ml, &cv, limit); + hammer[active]->Start(); /* then make it roll */ + RCThread::Sleep(interleave); /* start them slowly */ + } + + /* + * The last thread started has had the opportunity to run for + * 'interleave' seconds. Now gather them all back in. + */ + { + RCEnter scope(&ml); + for (poll = 0; poll < threads; poll++) + { + if (hammer[poll]->action == HammerData::sg_go) /* don't overwrite done */ + hammer[poll]->action = HammerData::sg_stop; /* ask him to stop */ + } + } + + while (active > 0) + { + for (poll = 0; poll < threads; poll++) + { + ml.Acquire(); + while (hammer[poll]->action < HammerData::sg_done) cv.Wait(); + ml.Release(); + + if (hammer[poll]->problem == HammerData::sg_okay) + { + duration = RCInterval(RCInterval::now) - hammer[poll]->timein; + writes = hammer[poll]->writes * 1000 / duration; + if (writes < writesMin) writesMin = writes; + if (writes > writesMax) writesMax = writes; + writesTot += hammer[poll]->writes; + durationTot += duration; + } + else + { + if (debug_mode) PR_fprintf(output, + "%s: test failed %s after %ld seconds\n", + programName, where[hammer[poll]->problem], duration); + else failed_already=1; + } + active -= 1; /* this is another one down */ + (void)hammer[poll]->Join(); + hammer[poll] = NULL; + } + } + if (debug_mode) PR_fprintf(output, + "%s: [%ld [%ld] %ld] writes/sec average\n", + programName, writesMin, + writesTot * 1000 / durationTot, writesMax); + } + + failed_already |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL\n" : "PASS\n"); + return failed_already; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/switch.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/switch.cpp new file mode 100644 index 00000000..fddc5808 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/switch.cpp @@ -0,0 +1,266 @@ +/* -*- 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 ***** */ + +/* +** File: switch.cpp +** Description: trying to time context switches +*/ + +#include "rccv.h" +#include "rcinrval.h" +#include "rclock.h" +#include "rcthread.h" + +#include +#include +#include +#include +#include + +#include + +#define INNER_LOOPS 100 +#define DEFAULT_LOOPS 100 +#define DEFAULT_THREADS 10 + +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; + +class Home: public RCCondition +{ +public: + virtual ~Home(); + Home(Home *link, RCLock* ml); + +public: + Home *next; + RCLock* ml; + PRBool twiddle; +}; /* Home */ + +Home::~Home() { } + +Home::Home(Home *link, RCLock* lock): RCCondition(lock) +{ + ml = lock; + next = link; + twiddle = PR_FALSE; +} /* Home::Home */ + +class Shared: public Home, public RCThread +{ +public: + Shared(RCThread::Scope scope, Home* link, RCLock* ml); + +private: + ~Shared(); + void RootFunction(); +}; /* Shared */ + +Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock): + Home(link, lock), RCThread(scope, RCThread::joinable) { } + +Shared::~Shared() { } + +void Shared::RootFunction() +{ + PRStatus status = PR_SUCCESS; + while (PR_SUCCESS == status) + { + RCEnter entry(ml); + while (twiddle && (PR_SUCCESS == status)) status = Wait(); + if (verbosity) PR_fprintf(debug_out, "+"); + twiddle = PR_TRUE; + next->twiddle = PR_FALSE; + next->Notify(); + } +} /* Shared::RootFunction */ + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n"); + PR_fprintf( + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); + PR_fprintf( + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); + PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRStatus status; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + RCThread::Scope thread_scope = RCThread::local; + PRUintn thread_count, inner_count, loop_count, average; + PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* verbose mode */ + verbosity = PR_TRUE; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + loop_limit = atoi(opt->value); + break; + case 't': /* thread limit */ + thread_limit = atoi(opt->value); + break; + case 'C': /* Concurrency limit */ + concurrency = atoi(opt->value); + break; + case 'G': /* global threads only */ + thread_scope = RCThread::global; + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) return -1; + + if (PR_TRUE == debug_mode) + { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); + PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf( + debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + /* + ** The interesting part starts here + */ + RCLock lock; + Shared* shared; + Home home(NULL, &lock); + Home* link = &home; + RCInterval timein, timeout = 0; + + /* Build up the string of objects */ + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + shared = new Shared(thread_scope, link, &lock); + shared->Start(); /* make it run */ + link = (Home*)shared; + } + + /* Pass the message around the horn a few times */ + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) + { + timein.SetToNow(); + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) + { + RCEnter entry(&lock); + home.twiddle = PR_TRUE; + shared->twiddle = PR_FALSE; + shared->Notify(); + while (home.twiddle) + { + failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE; + } + } + timeout += (RCInterval(RCInterval::now) - timein); + } + + /* Figure out how well we did */ + if (debug_mode) + { + average = timeout.ToMicroseconds() + / (INNER_LOOPS * loop_limit * thread_count); + PR_fprintf( + debug_out, "Average switch times %d usecs for %d threads\n", + average, thread_limit); + } + + /* Start reclamation process */ + link = shared; + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + if (&home == link) break; + status = ((Shared*)link)->Interrupt(); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to interrupt"); + } + link = link->next; + } + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + link = shared->next; + status = shared->Join(); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to join"); + } + if (&home == link) break; + shared = (Shared*)link; + } + + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); + + failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup()); + + return ((failed) ? 1 : 0); +} /* main */ + +/* switch.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/thread.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/thread.cpp new file mode 100644 index 00000000..801eee0d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/thread.cpp @@ -0,0 +1,140 @@ +/* -*- 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 ***** */ + +/* thread.cpp - a test program */ + +#include "rcthread.h" + +#include + +#include + +class TestThread: public RCThread +{ +public: + TestThread(RCThread::State state, PRIntn count); + + virtual void RootFunction(); + +protected: + virtual ~TestThread(); + +private: + PRUint32 mydata; +}; + +TestThread::~TestThread() { } + +TestThread::TestThread(RCThread::State state, PRIntn count): + RCThread(RCThread::global, state, 0) { mydata = count; } + +void TestThread::RootFunction() +{ + SetPriority(RCThread::high); + printf("TestThread::RootFunction %d did it\n", mydata); +} /* TestThread::RootFunction */ + +class Foo1 +{ +public: + Foo1(); + virtual ~Foo1(); + + TestThread *thread; + PRIntn data; +}; + +Foo1::Foo1() +{ + data = 0xafaf; + thread = new TestThread(RCThread::joinable, 0xafaf); + thread->Start(); +} + +Foo1::~Foo1() +{ + PRStatus rv = thread->Join(); + PR_ASSERT(PR_SUCCESS == rv); +} /* Foo1::~Foo1 */ + +PRIntn main(PRIntn argc, char **agrv) +{ + PRStatus status; + PRIntn count = 100; + RCThread *thread[10]; + while (--count > 0) + { + TestThread *thread = new TestThread(RCThread::joinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + status = thread->Join(); /* this should work */ + PR_ASSERT(PR_SUCCESS == status); + } + while (++count < 100) + { + TestThread *thread = new TestThread(RCThread::unjoinable, count); + status = thread->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + + { + Foo1 *foo1 = new Foo1(); + PR_ASSERT(NULL != foo1); + delete foo1; + } + + { + for (count = 0; count < 10; ++count) + { + thread[count] = new TestThread( RCThread::joinable, count); + status = thread[count]->Start(); /* have to remember to start it */ + PR_ASSERT(PR_SUCCESS == status); + } + for (count = 0; count < 10; ++count) + { + PRStatus rv = thread[count]->Join(); + PR_ASSERT(PR_SUCCESS == rv); + } + } + + (void)RCPrimordialThread::Cleanup(); + + return 0; +} /* main */ + +/* thread.cpp */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/time.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/time.cpp new file mode 100644 index 00000000..c0a9c3e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/time.cpp @@ -0,0 +1,61 @@ +/* -*- 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 ***** */ + +/* time.cpp - a test program */ + +#include "rctime.h" + +#include +#include + +#define DEFAULT_ITERATIONS 100 + +PRIntn main(PRIntn argc, char **argv) +{ + RCTime unitialized; + RCTime now(PR_Now()); + RCTime current(RCTime::now); + PRTime time = current; + + unitialized = now; + now.Now(); + + return 0; +} /* main */ + +/* time.cpp */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/tpd.cpp b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/tpd.cpp new file mode 100644 index 00000000..6e3dd953 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/cplus/tests/tpd.cpp @@ -0,0 +1,368 @@ +/* -*- 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 ***** */ + +/* +** File: tpd.cpp +** Description: Exercising the thread private data bailywick. +*/ + +#include "prlog.h" +#include "prprf.h" +#include "rcthread.h" + +#include + +#include "plgetopt.h" + +/* +** class MyThread +*/ +class MyThread: public RCThread +{ +public: + MyThread(); + +private: + ~MyThread(); + void RootFunction(); +}; /* MyThread */ + +/* +** class MyPrivateData +*/ +class MyPrivateData: public RCThreadPrivateData +{ +public: + virtual ~MyPrivateData(); + + MyPrivateData(); + MyPrivateData(char*); + MyPrivateData(const MyPrivateData&); + + void Release(); + +private: + char *string; +}; /* MyPrivateData */ + +static PRUintn key[128]; +static PRIntn debug = 0; +static PRBool failed = PR_FALSE; +static PRBool should = PR_TRUE; +static PRBool did = PR_TRUE; +static PRFileDesc *fout = NULL; + +static void PrintProgress(PRIntn line) +{ + failed = failed || (should && !did); + failed = failed || (!should && did); + if (debug > 0) + { + PR_fprintf( + fout, "@ line %d destructor should %shave been called and was%s\n", + line, ((should) ? "" : "NOT "), ((did) ? "" : " NOT")); + } +} /* PrintProgress */ + +static void MyAssert(const char *expr, const char *file, PRIntn line) +{ + if (debug > 0) + (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line); +} /* MyAssert */ + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__)) + +int main(PRIntn argc, char *argv[]) +{ + PRStatus rv; + PRUintn keys; + MyThread *thread; + const RCThreadPrivateData *pd; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + RCThread *primordial = RCThread::WrapPrimordialThread(); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + fout = PR_STDOUT; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + key[keys + 4] = key[keys] + 4; + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* the first four should be bu null, the last four undefined and null */ + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* initially set private data for new keys */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* re-assign the private data, albeit the same content */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL != pd); + rv = RCThread::SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set private to */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* should all be null now */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + pd = RCThread::GetPrivateData(key[keys]); + PR_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + /* allocate another batch of keys and assign data to them */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::NewPrivateIndex(&key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + rv = RCThread::SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to */ + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + /* set all the extended slots to again (noop) */ + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = RCThread::SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + + if (debug) PR_fprintf(fout, "Creating thread\n"); + thread = new MyThread(); + if (debug) PR_fprintf(fout, "Starting thread\n"); + thread->Start(); + if (debug) PR_fprintf(fout, "Joining thread\n"); + (void)thread->Join(); + if (debug) PR_fprintf(fout, "Joined thread\n"); + + failed |= (PR_FAILURE == RCPrimordialThread::Cleanup()); + + (void)PR_fprintf( + fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); + + return (failed) ? 1 : 0; + +} /* main */ + +/* +** class MyPrivateData +*/ +MyPrivateData::~MyPrivateData() +{ + PR_fprintf( + fout, "MyPrivateData::~MyPrivateData[%s]\n", + (NULL != string) ? string : "NULL"); +} /* MyPrivateData::~MyPrivateData */ + +MyPrivateData::MyPrivateData(): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData()\n"); + string = NULL; +} /* MyPrivateData::MyPrivateData */ + +MyPrivateData::MyPrivateData(char* data): RCThreadPrivateData() +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(char* data)\n"); + string = data; +} /* MyPrivateData:: MyPrivateData */ + +MyPrivateData::MyPrivateData(const MyPrivateData& him): RCThreadPrivateData(him) +{ + PR_fprintf(fout, "MyPrivateData::MyPrivateData(const MyPrivateData& him)\n"); + string = him.string; +} /* MyPrivateData:: MyPrivateData */ + +void MyPrivateData::Release() +{ + if (should) did = PR_TRUE; + else failed = PR_TRUE; +} /* MyPrivateData::operator= */ + +/* +** class MyThread +*/ +MyThread::~MyThread() { } +MyThread::MyThread(): RCThread(RCThread::global, RCThread::joinable) { } + + +void MyThread::RootFunction() +{ + PRStatus rv; + PRUintn keys; + const RCThreadPrivateData *pd; + + MyPrivateData extension = MyPrivateData("EXTENSION"); + MyPrivateData key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = GetPrivateData(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + +#if !defined(DEBUG) + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = SetPrivateData(keys, &key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); +#endif + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys], &key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys], &extension); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = SetPrivateData(key[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } +} /* MyThread::RootFunction */ + +/* tpd.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/io/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/io/Makefile.in new file mode 100644 index 00000000..40dc6ded --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/Makefile.in @@ -0,0 +1,97 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + prfdcach.c \ + prmwait.c \ + priometh.c \ + pripv6.c \ + prmapopt.c \ + prlayer.c \ + prlog.c \ + prmmap.c \ + prpolevt.c \ + prprf.c \ + prscanf.c \ + prstdio.c \ + $(NULL) + +ifndef USE_PTHREADS + CSRCS += \ + prdir.c \ + prfile.c \ + prio.c \ + prsocket.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +# An OS/2 Optimization bug causes PR_snprintf() to produce wrong result. +# This suppresses optimization for this single compilation unit. +ifeq ($(MOZ_OS2_TOOLS),VACPP) +$(OBJDIR)/prprf.obj: prprf.c + @$(MAKE_OBJDIR) + $(CC) -Fo$@ -c $(filter-out /O+, $(CFLAGS)) $< +endif + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prdir.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prdir.c new file mode 100644 index 00000000..8679c9d5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prdir.c @@ -0,0 +1,164 @@ +/* -*- 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): + * Roy Yokoyama + * + * 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" + +PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name) +{ + PRDir *dir; + PRStatus sts; + + dir = PR_NEW(PRDir); + if (dir) { + sts = _PR_MD_OPEN_DIR(&dir->md,name); + if (sts != PR_SUCCESS) { + PR_DELETE(dir); + return NULL; + } + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return dir; +} + +PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags) +{ + /* _MD_READ_DIR return a char* to the name; allocation in machine-dependent code */ + char* name = _PR_MD_READ_DIR(&dir->md, flags); + dir->d.name = name; + return name ? &dir->d : NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir) +{ +PRInt32 rv; + + if (dir) { + rv = _PR_MD_CLOSE_DIR(&dir->md); + PR_DELETE(dir); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode) +{ +PRInt32 rv; + + rv = _PR_MD_MKDIR(name, mode); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode) +{ +PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_MAKE_DIR(name, mode); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name) +{ +PRInt32 rv; + + rv = _PR_MD_RMDIR(name); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +#ifdef MOZ_UNICODE +/* + * UTF16 Interface + */ +PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name) +{ + PRDirUTF16 *dir; + PRStatus sts; + + dir = PR_NEW(PRDirUTF16); + if (dir) { + sts = _PR_MD_OPEN_DIR_UTF16(&dir->md,name); + if (sts != PR_SUCCESS) { + PR_DELETE(dir); + return NULL; + } + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return dir; +} + +PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags) +{ + /* + * _MD_READ_DIR_UTF16 return a PRUnichar* to the name; allocation in + * machine-dependent code + */ + PRUnichar* name = _PR_MD_READ_DIR_UTF16(&dir->md, flags); + dir->d.name = name; + return name ? &dir->d : NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDirUTF16 *dir) +{ + PRInt32 rv; + + if (dir) { + rv = _PR_MD_CLOSE_DIR_UTF16(&dir->md); + PR_DELETE(dir); + if (rv < 0) + return PR_FAILURE; + else + return PR_SUCCESS; + } + return PR_SUCCESS; +} + +#endif /* MOZ_UNICODE */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prfdcach.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prfdcach.c new file mode 100644 index 00000000..aea19dff --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prfdcach.c @@ -0,0 +1,311 @@ +/* -*- 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 + +/*****************************************************************************/ +/*****************************************************************************/ +/************************** File descriptor caching **************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +/* +** This code is built into debuggable versions of NSPR to assist in +** finding misused file descriptors. Since file descritors (PRFileDesc) +** are identified by a pointer to their structure, they can be the +** target of dangling references. Furthermore, NSPR caches and tries +** to aggressively reuse file descriptors, leading to more ambiguity. +** The following code will allow a debugging client to set environment +** variables and control the number of file descriptors that will be +** preserved before they are recycled. The environment variables are +** NSPR_FD_CACHE_SIZE_LOW and NSPR_FD_CACHE_SIZE_HIGH. The former sets +** the number of descriptors NSPR will allocate before beginning to +** recycle. The latter is the maximum number permitted in the cache +** (exclusive of those in use) at a time. +*/ +typedef struct _PR_Fd_Cache +{ + PRLock *ml; + PRIntn count; + PRStack *stack; + PRFileDesc *head, *tail; + PRIntn limit_low, limit_high; +} _PR_Fd_Cache; + +static _PR_Fd_Cache _pr_fd_cache; +static PRFileDesc **stack2fd = &(((PRFileDesc*)NULL)->higher); + + +/* +** Get a FileDescriptor from the cache if one exists. If not allocate +** a new one from the heap. +*/ +PRFileDesc *_PR_Getfd(void) +{ + PRFileDesc *fd; + /* + ** $$$ + ** This may look a little wasteful. We'll see. Right now I want to + ** be able to toggle between caching and not at runtime to measure + ** the differences. If it isn't too annoying, I'll leave it in. + ** $$$$ + ** + ** The test is against _pr_fd_cache.limit_high. If that's zero, + ** we're not doing the extended cache but going for performance. + */ + if (0 == _pr_fd_cache.limit_high) + { + PRStackElem *pop; + PR_ASSERT(NULL != _pr_fd_cache.stack); + pop = PR_StackPop(_pr_fd_cache.stack); + if (NULL == pop) goto allocate; + fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + } + else + { + do + { + if (NULL == _pr_fd_cache.head) goto allocate; /* nothing there */ + if (_pr_fd_cache.count < _pr_fd_cache.limit_low) goto allocate; + + /* we "should" be able to extract an fd from the cache */ + PR_Lock(_pr_fd_cache.ml); /* need the lock to do this safely */ + fd = _pr_fd_cache.head; /* protected extraction */ + if (NULL == fd) /* unexpected, but not fatal */ + { + PR_ASSERT(0 == _pr_fd_cache.count); + PR_ASSERT(NULL == _pr_fd_cache.tail); + } + else + { + _pr_fd_cache.count -= 1; + _pr_fd_cache.head = fd->higher; + if (NULL == _pr_fd_cache.head) + { + PR_ASSERT(0 == _pr_fd_cache.count); + _pr_fd_cache.tail = NULL; + } + PR_ASSERT(&_pr_faulty_methods == fd->methods); + PR_ASSERT(PR_INVALID_IO_LAYER == fd->identity); + PR_ASSERT(_PR_FILEDESC_FREED == fd->secret->state); + } + PR_Unlock(_pr_fd_cache.ml); + + } while (NULL == fd); /* then go around and allocate a new one */ + } + +finished: + fd->dtor = NULL; + fd->lower = fd->higher = NULL; + fd->identity = PR_NSPR_IO_LAYER; + memset(fd->secret, 0, sizeof(PRFilePrivate)); + return fd; + +allocate: + fd = PR_NEW(PRFileDesc); + if (NULL != fd) + { + fd->secret = PR_NEW(PRFilePrivate); + if (NULL == fd->secret) PR_DELETE(fd); + } + if (NULL != fd) goto finished; + else return NULL; + +} /* _PR_Getfd */ + +/* +** Return a file descriptor to the cache unless there are too many in +** there already. If put in cache, clear the fields first. +*/ +void _PR_Putfd(PRFileDesc *fd) +{ + PR_ASSERT(PR_NSPR_IO_LAYER == fd->identity); + fd->methods = &_pr_faulty_methods; + fd->identity = PR_INVALID_IO_LAYER; + fd->secret->state = _PR_FILEDESC_FREED; + + if (0 == _pr_fd_cache.limit_high) + { + PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher)); + } + else + { + if (_pr_fd_cache.count > _pr_fd_cache.limit_high) + { + PR_Free(fd->secret); + PR_Free(fd); + } + else + { + PR_Lock(_pr_fd_cache.ml); + if (NULL == _pr_fd_cache.tail) + { + PR_ASSERT(0 == _pr_fd_cache.count); + PR_ASSERT(NULL == _pr_fd_cache.head); + _pr_fd_cache.head = _pr_fd_cache.tail = fd; + } + else + { + PR_ASSERT(NULL == _pr_fd_cache.tail->higher); + _pr_fd_cache.tail->higher = fd; + _pr_fd_cache.tail = fd; /* new value */ + } + fd->higher = NULL; /* always so */ + _pr_fd_cache.count += 1; /* count the new entry */ + PR_Unlock(_pr_fd_cache.ml); + } + } +} /* _PR_Putfd */ + +PR_IMPLEMENT(PRStatus) PR_SetFDCacheSize(PRIntn low, PRIntn high) +{ + /* + ** This can be called at any time, may adjust the cache sizes, + ** turn the caches off, or turn them on. It is not dependent + ** on the compilation setting of DEBUG. + */ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (low > high) low = high; /* sanity check the params */ + + PR_Lock(_pr_fd_cache.ml); + if (0 == high) /* shutting down or staying down */ + { + if (0 != _pr_fd_cache.limit_high) /* shutting down */ + { + _pr_fd_cache.limit_high = 0; /* stop use */ + /* + ** Hold the lock throughout - nobody's going to want it + ** other than another caller to this routine. Just don't + ** let that happen. + ** + ** Put all the cached fds onto the new cache. + */ + while (NULL != _pr_fd_cache.head) + { + PRFileDesc *fd = _pr_fd_cache.head; + _pr_fd_cache.head = fd->higher; + PR_StackPush(_pr_fd_cache.stack, (PRStackElem*)(&fd->higher)); + } + _pr_fd_cache.limit_low = 0; + _pr_fd_cache.tail = NULL; + _pr_fd_cache.count = 0; + } + } + else /* starting up or just adjusting parameters */ + { + PRBool was_using_stack = (0 == _pr_fd_cache.limit_high); + _pr_fd_cache.limit_low = low; + _pr_fd_cache.limit_high = high; + if (was_using_stack) /* was using stack - feed into cache */ + { + PRStackElem *pop; + while (NULL != (pop = PR_StackPop(_pr_fd_cache.stack))) + { + PRFileDesc *fd = (PRFileDesc*) + ((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + if (NULL == _pr_fd_cache.tail) _pr_fd_cache.tail = fd; + fd->higher = _pr_fd_cache.head; + _pr_fd_cache.head = fd; + _pr_fd_cache.count += 1; + } + } + } + PR_Unlock(_pr_fd_cache.ml); + return PR_SUCCESS; +} /* PR_SetFDCacheSize */ + +void _PR_InitFdCache(void) +{ + /* + ** The fd caching is enabled by default for DEBUG builds, + ** disabled by default for OPT builds. That default can + ** be overridden at runtime using environment variables + ** or a super-wiz-bang API. + */ + const char *low = PR_GetEnv("NSPR_FD_CACHE_SIZE_LOW"); + const char *high = PR_GetEnv("NSPR_FD_CACHE_SIZE_HIGH"); + + /* + ** _low is allowed to be zero, _high is not. + ** If _high is zero, we're not doing the caching. + */ + + _pr_fd_cache.limit_low = 0; +#if defined(DEBUG) + _pr_fd_cache.limit_high = FD_SETSIZE; +#else + _pr_fd_cache.limit_high = 0; +#endif /* defined(DEBUG) */ + + if (NULL != low) _pr_fd_cache.limit_low = atoi(low); + if (NULL != high) _pr_fd_cache.limit_high = atoi(high); + + if (_pr_fd_cache.limit_high < _pr_fd_cache.limit_low) + _pr_fd_cache.limit_high = _pr_fd_cache.limit_low; + + _pr_fd_cache.ml = PR_NewLock(); + PR_ASSERT(NULL != _pr_fd_cache.ml); + _pr_fd_cache.stack = PR_CreateStack("FD"); + PR_ASSERT(NULL != _pr_fd_cache.stack); + +} /* _PR_InitFdCache */ + +void _PR_CleanupFdCache(void) +{ + PRFileDesc *fd, *next; + PRStackElem *pop; + + for (fd = _pr_fd_cache.head; fd != NULL; fd = next) + { + next = fd->higher; + PR_DELETE(fd->secret); + PR_DELETE(fd); + } + PR_DestroyLock(_pr_fd_cache.ml); + while ((pop = PR_StackPop(_pr_fd_cache.stack)) != NULL) + { + fd = (PRFileDesc*)((PRPtrdiff)pop - (PRPtrdiff)stack2fd); + PR_DELETE(fd->secret); + PR_DELETE(fd); + } + PR_DestroyStack(_pr_fd_cache.stack); +} /* _PR_CleanupFdCache */ + +/* prfdcach.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prfile.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prfile.c new file mode 100644 index 00000000..caf1bb88 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prfile.c @@ -0,0 +1,861 @@ +/* -*- 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 +#include + +#ifdef XP_UNIX +#if defined(AIX) || defined(QNX) +/* To pick up sysconf */ +#include +#else +/* To pick up getrlimit, setrlimit */ +#include +#include +#endif +#endif /* XP_UNIX */ + +extern PRLock *_pr_flock_lock; +extern PRCondVar *_pr_flock_cv; + +static PRInt32 PR_CALLBACK FileRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PRInt32 rv = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + rv = -1; + } + if (rv == -1) + return rv; + + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("read: fd=%p osfd=%d buf=%p amount=%d", + fd, fd ? fd->secret->md.osfd : 0, buf, amount)); + + rv = _PR_MD_READ(fd, buf, amount); + if (rv < 0) { + PR_ASSERT(rv == -1); + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("read -> %d", rv)); + return rv; +} + +static PRInt32 PR_CALLBACK FileWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 rv = 0; + PRInt32 temp, count; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + rv = -1; + } + if (rv != 0) + return rv; + + count = 0; +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + if ( PR_TRUE == fd->secret->appendMode ) { + rv = PR_Seek(fd, 0, PR_SEEK_END ); + if ( -1 == rv ) { + return rv; + } + } /* if (fd->secret->appendMode...) */ +#endif /* XP_UNIX */ + while (amount > 0) { + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("write: fd=%p osfd=%d buf=%p amount=%d", + fd, fd ? fd->secret->md.osfd : 0, buf, amount)); + temp = _PR_MD_WRITE(fd, buf, amount); + if (temp < 0) { + count = -1; + break; + } + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + amount -= temp; + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("write -> %d", count)); + return count; +} + +static PROffset32 PR_CALLBACK FileSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + PROffset32 result; + + result = _PR_MD_LSEEK(fd, offset, whence); + return result; +} + +static PROffset64 PR_CALLBACK FileSeek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ +#ifdef XP_MAC +#pragma unused( fd, offset, whence ) +#endif + PROffset64 result; + + result = _PR_MD_LSEEK64(fd, offset, whence); + return result; +} + +static PRInt32 PR_CALLBACK FileAvailable(PRFileDesc *fd) +{ + PRInt32 result, cur, end; + + cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR); + + if (cur >= 0) + end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END); + + if ((cur < 0) || (end < 0)) { + return -1; + } + + result = end - cur; + _PR_MD_LSEEK(fd, cur, PR_SEEK_SET); + + return result; +} + +static PRInt64 PR_CALLBACK FileAvailable64(PRFileDesc *fd) +{ +#ifdef XP_MAC +#pragma unused( fd ) +#endif + PRInt64 result, cur, end; + PRInt64 minus_one; + + LL_I2L(minus_one, -1); + cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR); + + if (LL_GE_ZERO(cur)) + end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END); + + if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one; + + LL_SUB(result, end, cur); + (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET); + + return result; +} + +static PRInt32 PR_CALLBACK PipeAvailable(PRFileDesc *fd) +{ + PRInt32 rv; + rv = _PR_MD_PIPEAVAILABLE(fd); + return rv; +} + +static PRInt64 PR_CALLBACK PipeAvailable64(PRFileDesc *fd) +{ + PRInt64 rv; + LL_I2L(rv, _PR_MD_PIPEAVAILABLE(fd)); + return rv; +} + +static PRStatus PR_CALLBACK PipeSync(PRFileDesc *fd) +{ +#if defined(XP_MAC) +#pragma unused (fd) +#endif + + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileGetInfo(PRFileDesc *fd, PRFileInfo *info) +{ + PRInt32 rv; + + rv = _PR_MD_GETOPENFILEINFO(fd, info); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileGetInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused( fd, info ) +#endif + /* $$$$ NOT YET IMPLEMENTED */ + PRInt32 rv; + + rv = _PR_MD_GETOPENFILEINFO64(fd, info); + if (rv < 0) return PR_FAILURE; + else return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileSync(PRFileDesc *fd) +{ + PRInt32 result; + result = _PR_MD_FSYNC(fd); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK FileClose(PRFileDesc *fd) +{ + if (!fd || !fd->secret + || (fd->secret->state != _PR_FILEDESC_OPEN + && fd->secret->state != _PR_FILEDESC_CLOSED)) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + + if (fd->secret->state == _PR_FILEDESC_OPEN) { + if (_PR_MD_CLOSE_FILE(fd->secret->md.osfd) < 0) { + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + } + PR_FreeFileDesc(fd); + return PR_SUCCESS; +} + +static PRInt16 PR_CALLBACK FilePoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ +#ifdef XP_MAC +#pragma unused( fd, in_flags ) +#endif + *out_flags = 0; + return in_flags; +} /* FilePoll */ + +static PRIOMethods _pr_fileMethods = { + PR_DESC_FILE, + FileClose, + FileRead, + FileWrite, + FileAvailable, + FileAvailable64, + FileSync, + FileSeek, + FileSeek64, + FileGetInfo, + FileGetInfo64, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + FilePoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) +{ + return &_pr_fileMethods; +} + +static PRIOMethods _pr_pipeMethods = { + PR_DESC_PIPE, + FileClose, + FileRead, + FileWrite, + PipeAvailable, + PipeAvailable64, + PipeSync, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + FilePoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) +{ + return &_pr_pipeMethods; +} + +PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode) +{ + PRInt32 osfd; + PRFileDesc *fd = 0; +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + + osfd = _PR_MD_OPEN(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +PR_IMPLEMENT(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode) +{ + PRInt32 osfd; + PRFileDesc *fd = 0; +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + + osfd = _PR_MD_OPEN_FILE(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +static PRInt32 PR_GetSysfdTableMax(void) +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PRInt32 PR_GetSysfdTableMax(void) +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) + struct rlimit rlim; + + if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) { + /* XXX need to call PR_SetError() */ + return -1; + } + + return rlim.rlim_max; +#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) + return sysconf(_SC_OPEN_MAX); +#elif defined(WIN32) + /* + * There is a systemwide limit of 65536 user handles. + */ + return 16384; +#elif defined (WIN16) + return FOPEN_MAX; +#elif defined(XP_OS2) + ULONG ulReqCount = 0; + ULONG ulCurMaxFH = 0; + DosSetRelMaxFH(&ulReqCount, &ulCurMaxFH); + return ulCurMaxFH; +#elif defined (XP_MAC) || defined(XP_BEOS) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#else + write me; +#endif +} + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +static PRInt32 PR_SetSysfdTableSize(int table_size) +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PRInt32 PR_SetSysfdTableSize(int table_size) +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) + struct rlimit rlim; + PRInt32 tableMax = PR_GetSysfdTableMax(); + + if (tableMax < 0) + return -1; + + if (tableMax > FD_SETSIZE) + tableMax = FD_SETSIZE; + + rlim.rlim_max = tableMax; + + /* Grow as much as we can; even if too big */ + if ( rlim.rlim_max < table_size ) + rlim.rlim_cur = rlim.rlim_max; + else + rlim.rlim_cur = table_size; + + if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) { + /* XXX need to call PR_SetError() */ + return -1; + } + + return rlim.rlim_cur; +#elif defined(XP_OS2) + PRInt32 tableMax = PR_GetSysfdTableMax(); + if (table_size > tableMax) { + APIRET rc = NO_ERROR; + rc = DosSetMaxFH(table_size); + if (rc == NO_ERROR) + return table_size; + else + return -1; + } + return tableMax; +#elif defined(AIX) || defined(NEXTSTEP) || defined(QNX) \ + || defined(WIN32) || defined(WIN16) || defined(XP_BEOS) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#elif defined (XP_MAC) +#pragma unused (table_size) + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +#else + write me; +#endif +} + +PR_IMPLEMENT(PRStatus) PR_Delete(const char *name) +{ + PRInt32 rv; + + rv = _PR_MD_DELETE(name); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv; + + rv = _PR_MD_GETFILEINFO(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused (fn, info) +#endif + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else { + return PR_SUCCESS; + } +} + +PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to) +{ + PRInt32 rv; + + rv = _PR_MD_RENAME(from, to); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how) +{ +PRInt32 rv; + + rv = _PR_MD_ACCESS(name, how); + if (rv < 0) { + return PR_FAILURE; + } else + return PR_SUCCESS; +} + +/* +** Import an existing OS file to NSPR +*/ +PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) +{ + PRFileDesc *fd = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if( !fd ) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { + _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); + } + + return fd; +} + +/* +** Import an existing OS pipe to NSPR +*/ +PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) +{ + PRFileDesc *fd = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = PR_AllocFileDesc(osfd, &_pr_pipeMethods); + if( !fd ) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { + _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); +#ifdef WINNT + fd->secret->md.sync_file_io = PR_TRUE; +#endif + } + + return fd; +} + +#ifndef NO_NSPR_10_SUPPORT +/* +** PR_Stat() for Win16 is defined in w16io.c +** it is a hack to circumvent problems in Gromit and Java +** See also: BugSplat: 98516. +*/ +#if !defined(WIN16) +/* + * This function is supposed to be for backward compatibility with + * nspr 1.0. Therefore, it still uses the nspr 1.0 error-reporting + * mechanism -- returns a PRInt32, which is the error code when the call + * fails. + * + * If we need this function in nspr 2.0, it should be changed to + * return PRStatus, as follows: + * + * PR_IMPLEMENT(PRStatus) PR_Stat(const char *name, struct stat *buf) + * { + * PRInt32 rv; + * + * rv = _PR_MD_STAT(name, buf); + * if (rv < 0) + * return PR_FAILURE; + * else + * return PR_SUCCESS; + * } + * + * -- wtc, 2/14/97. + */ +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) +{ + PRInt32 rv; + + rv = _PR_MD_STAT(name, buf); + return rv; +} + +#endif /* !defined(WIN16) */ +#endif /* ! NO_NSPR_10_SUPPORT */ + +PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + +#ifdef WINNT + if (!fd->secret->md.io_model_committed) { + PRInt32 rv; + rv = _md_Associate((HANDLE)fd->secret->md.osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } +#endif + + PR_Lock(_pr_flock_lock); + while (fd->secret->lockCount == -1) + PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT); + if (fd->secret->lockCount == 0) { + fd->secret->lockCount = -1; + PR_Unlock(_pr_flock_lock); + status = _PR_MD_LOCKFILE(fd->secret->md.osfd); + PR_Lock(_pr_flock_lock); + fd->secret->lockCount = (status == PR_SUCCESS) ? 1 : 0; + PR_NotifyAllCondVar(_pr_flock_cv); + } else { + fd->secret->lockCount++; + } + PR_Unlock(_pr_flock_lock); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + +#ifdef WINNT + if (!fd->secret->md.io_model_committed) { + PRInt32 rv; + rv = _md_Associate((HANDLE)fd->secret->md.osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } +#endif + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 0) { + status = _PR_MD_TLOCKFILE(fd->secret->md.osfd); + PR_ASSERT(status == PR_SUCCESS || fd->secret->lockCount == 0); + if (status == PR_SUCCESS) + fd->secret->lockCount = 1; + } else { + fd->secret->lockCount++; + } + PR_Unlock(_pr_flock_lock); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd) +{ + PRStatus rv = PR_SUCCESS; + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 1) { + rv = _PR_MD_UNLOCKFILE(fd->secret->md.osfd); + if (rv == PR_SUCCESS) + fd->secret->lockCount = 0; + } else { + fd->secret->lockCount--; + } + PR_Unlock(_pr_flock_lock); + + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +) +{ +#if defined(XP_MAC) +#pragma unused (readPipe, writePipe) +#endif + +#ifdef WIN32 + HANDLE readEnd, writeEnd; + SECURITY_ATTRIBUTES pipeAttributes; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + ZeroMemory(&pipeAttributes, sizeof(pipeAttributes)); + pipeAttributes.nLength = sizeof(pipeAttributes); + pipeAttributes.bInheritHandle = TRUE; + if (CreatePipe(&readEnd, &writeEnd, &pipeAttributes, 0) == 0) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + *readPipe = PR_AllocFileDesc((PRInt32)readEnd, &_pr_pipeMethods); + if (NULL == *readPipe) { + CloseHandle(readEnd); + CloseHandle(writeEnd); + return PR_FAILURE; + } + *writePipe = PR_AllocFileDesc((PRInt32)writeEnd, &_pr_pipeMethods); + if (NULL == *writePipe) { + PR_Close(*readPipe); + CloseHandle(writeEnd); + return PR_FAILURE; + } +#ifdef WINNT + (*readPipe)->secret->md.sync_file_io = PR_TRUE; + (*writePipe)->secret->md.sync_file_io = PR_TRUE; +#endif + (*readPipe)->secret->inheritable = _PR_TRI_TRUE; + (*writePipe)->secret->inheritable = _PR_TRI_TRUE; + return PR_SUCCESS; +#elif defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#ifdef XP_OS2 + HFILE pipefd[2]; +#else + int pipefd[2]; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#ifdef XP_OS2 + if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) { +#else + if (pipe(pipefd) == -1) { +#endif + /* XXX map pipe error */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + return PR_FAILURE; + } + *readPipe = PR_AllocFileDesc(pipefd[0], &_pr_pipeMethods); + if (NULL == *readPipe) { + close(pipefd[0]); + close(pipefd[1]); + return PR_FAILURE; + } + *writePipe = PR_AllocFileDesc(pipefd[1], &_pr_pipeMethods); + if (NULL == *writePipe) { + PR_Close(*readPipe); + close(pipefd[1]); + return PR_FAILURE; + } +#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */ + _PR_MD_MAKE_NONBLOCK(*readPipe); +#endif + _PR_MD_INIT_FD_INHERITABLE(*readPipe, PR_FALSE); +#ifndef XP_BEOS /* Pipes are nonblocking on BeOS */ + _PR_MD_MAKE_NONBLOCK(*writePipe); +#endif + _PR_MD_INIT_FD_INHERITABLE(*writePipe, PR_FALSE); + return PR_SUCCESS; +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +#ifdef MOZ_UNICODE +/* ================ UTF16 Interfaces ================================ */ +PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode) +{ + PRInt32 osfd; + PRFileDesc *fd = 0; +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + PRBool appendMode = ( PR_APPEND & flags )? PR_TRUE : PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* Map pr open flags and mode to os specific flags */ + osfd = _PR_MD_OPEN_FILE_UTF16(name, flags, mode); + if (osfd != -1) { + fd = PR_AllocFileDesc(osfd, &_pr_fileMethods); + if (!fd) { + (void) _PR_MD_CLOSE_FILE(osfd); + } else { +#if !defined(XP_UNIX) /* BugZilla: 4090 */ + fd->secret->appendMode = appendMode; +#endif + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); + } + } + return fd; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ +#ifdef XP_MAC +#pragma unused (fn, info) +#endif + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64_UTF16(fn, info); + if (rv < 0) { + return PR_FAILURE; + } else { + return PR_SUCCESS; + } +} + +/* ================ UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prio.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prio.c new file mode 100644 index 00000000..908bfd61 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prio.c @@ -0,0 +1,202 @@ +/* -*- 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 /* for memset() */ + + +/************************************************************************/ + +PRLock *_pr_flock_lock; +PRCondVar *_pr_flock_cv; + +void _PR_InitIO(void) +{ + const PRIOMethods *methods = PR_GetFileMethods(); + + _PR_InitFdCache(); + + _pr_flock_lock = PR_NewLock(); + _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); + +#ifdef WIN32 + _pr_stdin = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_INPUT_HANDLE), + methods); + _pr_stdout = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_OUTPUT_HANDLE), + methods); + _pr_stderr = PR_AllocFileDesc((PRInt32)GetStdHandle(STD_ERROR_HANDLE), + methods); +#ifdef WINNT + _pr_stdin->secret->md.sync_file_io = PR_TRUE; + _pr_stdout->secret->md.sync_file_io = PR_TRUE; + _pr_stderr->secret->md.sync_file_io = PR_TRUE; +#endif +#else + _pr_stdin = PR_AllocFileDesc(0, methods); + _pr_stdout = PR_AllocFileDesc(1, methods); + _pr_stderr = PR_AllocFileDesc(2, methods); +#endif + _PR_MD_INIT_FD_INHERITABLE(_pr_stdin, PR_TRUE); + _PR_MD_INIT_FD_INHERITABLE(_pr_stdout, PR_TRUE); + _PR_MD_INIT_FD_INHERITABLE(_pr_stderr, PR_TRUE); + + _PR_MD_INIT_IO(); +} + +void _PR_CleanupIO(void) +{ + PR_FreeFileDesc(_pr_stdin); + _pr_stdin = NULL; + PR_FreeFileDesc(_pr_stdout); + _pr_stdout = NULL; + PR_FreeFileDesc(_pr_stderr); + _pr_stderr = NULL; + + if (_pr_flock_cv) { + PR_DestroyCondVar(_pr_flock_cv); + _pr_flock_cv = NULL; + } + if (_pr_flock_lock) { + PR_DestroyLock(_pr_flock_lock); + _pr_flock_lock = NULL; + } + + _PR_CleanupFdCache(); +} + +PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) +{ + PRFileDesc *result = NULL; + PR_ASSERT((int) osfd >= PR_StandardInput && osfd <= PR_StandardError); + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch (osfd) + { + case PR_StandardInput: result = _pr_stdin; break; + case PR_StandardOutput: result = _pr_stdout; break; + case PR_StandardError: result = _pr_stderr; break; + default: + (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + } + return result; +} + +PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( + PRInt32 osfd, const PRIOMethods *methods) +{ + PRFileDesc *fd; + +#ifdef XP_UNIX + /* + * Assert that the file descriptor is small enough to fit in the + * fd_set passed to select + */ + PR_ASSERT(osfd < FD_SETSIZE); +#endif + fd = _PR_Getfd(); + if (fd) { + /* Initialize the members of PRFileDesc and PRFilePrivate */ + fd->methods = methods; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->secret->md.osfd = osfd; + _PR_MD_INIT_FILEDESC(fd); + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + + return fd; +} + +PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd) +{ + PR_ASSERT(fd); +#ifdef XP_MAC + _PR_MD_FREE_FILEDESC(fd); +#endif + _PR_Putfd(fd); +} + +/* +** Wait for some i/o to finish on one or more more poll descriptors. +*/ +PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + return(_PR_MD_PR_POLL(pds, npds, timeout)); +} + +/* +** Set the inheritance attribute of a file descriptor. +*/ +PR_IMPLEMENT(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable) +{ +#if defined(XP_UNIX) || defined(WIN32) || defined(XP_OS2) || defined(XP_BEOS) + /* + * Only a non-layered, NSPR file descriptor can be inherited + * by a child process. + */ + if (fd->identity != PR_NSPR_IO_LAYER) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable != inheritable) { + if (_PR_MD_SET_FD_INHERITABLE(fd, inheritable) == PR_FAILURE) { + return PR_FAILURE; + } + fd->secret->inheritable = inheritable; + } + return PR_SUCCESS; +#else +#ifdef XP_MAC +#pragma unused (fd, inheritable) +#endif + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +/* +** This function only has a useful implementation in the debug build of +** the pthreads version. +*/ +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + /* do nothing */ +} /* PT_FPrintStats */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/priometh.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/priometh.c new file mode 100644 index 00000000..1ca474f0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/priometh.c @@ -0,0 +1,628 @@ +/* -*- 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 + +/*****************************************************************************/ +/************************** Invalid I/O method object ************************/ +/*****************************************************************************/ +PRIOMethods _pr_faulty_methods = { + (PRDescType)0, + (PRCloseFN)_PR_InvalidStatus, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + (PRPollFN)_PR_InvalidInt16, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PRIntn _PR_InvalidInt(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return -1; +} /* _PR_InvalidInt */ + +PRInt16 _PR_InvalidInt16(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return -1; +} /* _PR_InvalidInt */ + +PRInt64 _PR_InvalidInt64(void) +{ + PRInt64 rv; + LL_I2L(rv, -1); + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return rv; +} /* _PR_InvalidInt */ + +/* + * An invalid method that returns PRStatus + */ + +PRStatus _PR_InvalidStatus(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return PR_FAILURE; +} /* _PR_InvalidDesc */ + +/* + * An invalid method that returns a pointer + */ + +PRFileDesc *_PR_InvalidDesc(void) +{ + PR_ASSERT(!"I/O method is invalid"); + PR_SetError(PR_INVALID_METHOD_ERROR, 0); + return NULL; +} /* _PR_InvalidDesc */ + +PR_IMPLEMENT(PRDescType) PR_GetDescType(PRFileDesc *file) +{ + return file->methods->file_type; +} + +PR_IMPLEMENT(PRStatus) PR_Close(PRFileDesc *fd) +{ + return (fd->methods->close)(fd); +} + +PR_IMPLEMENT(PRInt32) PR_Read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return((fd->methods->read)(fd,buf,amount)); +} + +PR_IMPLEMENT(PRInt32) PR_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return((fd->methods->write)(fd,buf,amount)); +} + +PR_IMPLEMENT(PRInt32) PR_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + return((fd->methods->seek)(fd, offset, whence)); +} + +PR_IMPLEMENT(PRInt64) PR_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ + return((fd->methods->seek64)(fd, offset, whence)); +} + +PR_IMPLEMENT(PRInt32) PR_Available(PRFileDesc *fd) +{ + return((fd->methods->available)(fd)); +} + +PR_IMPLEMENT(PRInt64) PR_Available64(PRFileDesc *fd) +{ + return((fd->methods->available64)(fd)); +} + +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo(PRFileDesc *fd, PRFileInfo *info) +{ + return((fd->methods->fileInfo)(fd, info)); +} + +PR_IMPLEMENT(PRStatus) PR_GetOpenFileInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ + return((fd->methods->fileInfo64)(fd, info)); +} + +PR_IMPLEMENT(PRStatus) PR_Sync(PRFileDesc *fd) +{ + return((fd->methods->fsync)(fd)); +} + +PR_IMPLEMENT(PRStatus) PR_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->connect)(fd,addr,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_ConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + return((fd->methods->connectcontinue)(fd,out_flags)); +} + +PR_IMPLEMENT(PRFileDesc*) PR_Accept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + return((fd->methods->accept)(fd,addr,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_Bind(PRFileDesc *fd, const PRNetAddr *addr) +{ + return((fd->methods->bind)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_Shutdown(PRFileDesc *fd, PRShutdownHow how) +{ + return((fd->methods->shutdown)(fd,how)); +} + +PR_IMPLEMENT(PRStatus) PR_Listen(PRFileDesc *fd, PRIntn backlog) +{ + return((fd->methods->listen)(fd,backlog)); +} + +PR_IMPLEMENT(PRInt32) PR_Recv(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + return((fd->methods->recv)(fd,buf,amount,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + return((fd->methods->send)(fd,buf,amount,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_Writev(PRFileDesc *fd, const PRIOVec *iov, +PRInt32 iov_size, PRIntervalTime timeout) +{ + if (iov_size > PR_MAX_IOVECTOR_SIZE) + { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return -1; + } + return((fd->methods->writev)(fd,iov,iov_size,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->recvfrom)(fd,buf,amount,flags,addr,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_SendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + return((fd->methods->sendto)(fd,buf,amount,flags,addr,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_TransmitFile( + PRFileDesc *sd, PRFileDesc *fd, const void *hdr, PRInt32 hlen, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return((sd->methods->transmitfile)(sd,fd,hdr,hlen,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_AcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return((sd->methods->acceptread)(sd, nd, raddr, buf, amount,timeout)); +} + +PR_IMPLEMENT(PRStatus) PR_GetSockName(PRFileDesc *fd, PRNetAddr *addr) +{ + return((fd->methods->getsockname)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + return((fd->methods->getpeername)(fd,addr)); +} + +PR_IMPLEMENT(PRStatus) PR_GetSocketOption( + PRFileDesc *fd, PRSocketOptionData *data) +{ + return((fd->methods->getsocketoption)(fd, data)); +} + +PR_IMPLEMENT(PRStatus) PR_SetSocketOption( + PRFileDesc *fd, const PRSocketOptionData *data) +{ + return((fd->methods->setsocketoption)(fd, data)); +} + +PR_IMPLEMENT(PRInt32) PR_SendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return((sd->methods->sendfile)(sd,sfd,flags,timeout)); +} + +PR_IMPLEMENT(PRInt32) PR_EmulateAcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + PRInt32 rv = -1; + PRNetAddr remote; + PRFileDesc *accepted = NULL; + + /* + ** The timeout does not apply to the accept portion of the + ** operation - it waits indefinitely. + */ + accepted = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT); + if (NULL == accepted) return rv; + + rv = PR_Recv(accepted, buf, amount, 0, timeout); + if (rv >= 0) + { + /* copy the new info out where caller can see it */ +#define AMASK ((PRPtrdiff)7) /* mask for alignment of PRNetAddr */ + PRPtrdiff aligned = (PRPtrdiff)buf + amount + AMASK; + *raddr = (PRNetAddr*)(aligned & ~AMASK); + memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote)); + *nd = accepted; + return rv; + } + + PR_Close(accepted); + return rv; +} + +/* + * PR_EmulateSendFile + * + * Send file sfd->fd across socket sd. If header/trailer are specified + * they are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + */ + +#if defined(XP_UNIX) || defined(WIN32) + +/* + * An implementation based on memory-mapped files + */ + +#define SENDFILE_MMAP_CHUNK (256 * 1024) + +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv, count = 0; + PRInt32 len, file_bytes, index = 0; + PRFileInfo info; + PRIOVec iov[3]; + PRFileMap *mapHandle = NULL; + void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */ + PRUint32 file_mmap_offset, alignment; + PRInt64 zero64; + PROffset64 file_mmap_offset64; + PRUint32 addr_offset, mmap_len; + + /* Get file size */ + if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { + count = -1; + goto done; + } + if (sfd->file_nbytes && + (info.size < (sfd->file_offset + sfd->file_nbytes))) { + /* + * there are fewer bytes in file to send than specified + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + count = -1; + goto done; + } + if (sfd->file_nbytes) + file_bytes = sfd->file_nbytes; + else + file_bytes = info.size - sfd->file_offset; + + alignment = PR_GetMemMapAlignment(); + + /* number of initial bytes to skip in mmap'd segment */ + addr_offset = sfd->file_offset % alignment; + + /* find previous mmap alignment boundary */ + file_mmap_offset = sfd->file_offset - addr_offset; + + /* + * If the file is large, mmap and send the file in chunks so as + * to not consume too much virtual address space + */ + mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); + len = mmap_len - addr_offset; + + /* + * Map in (part of) file. Take care of zero-length files. + */ + if (len) { + LL_I2L(zero64, 0); + mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY); + if (!mapHandle) { + count = -1; + goto done; + } + LL_I2L(file_mmap_offset64, file_mmap_offset); + addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len); + if (!addr) { + count = -1; + goto done; + } + } + /* + * send headers first, followed by the file + */ + if (sfd->hlen) { + iov[index].iov_base = (char *) sfd->header; + iov[index].iov_len = sfd->hlen; + index++; + } + if (len) { + iov[index].iov_base = (char*)addr + addr_offset; + iov[index].iov_len = len; + index++; + } + if ((file_bytes == len) && (sfd->tlen)) { + /* + * all file data is mapped in; send the trailer too + */ + iov[index].iov_base = (char *) sfd->trailer; + iov[index].iov_len = sfd->tlen; + index++; + } + rv = PR_Writev(sd, iov, index, timeout); + if (len) + PR_MemUnmap(addr, mmap_len); + if (rv < 0) { + count = -1; + goto done; + } + + PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); + + file_bytes -= len; + count += rv; + if (!file_bytes) /* header, file and trailer are sent */ + goto done; + + /* + * send remaining bytes of the file, if any + */ + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); + while (len > 0) { + /* + * Map in (part of) file + */ + file_mmap_offset = sfd->file_offset + count - sfd->hlen; + PR_ASSERT((file_mmap_offset % alignment) == 0); + + LL_I2L(file_mmap_offset64, file_mmap_offset); + addr = PR_MemMap(mapHandle, file_mmap_offset64, len); + if (!addr) { + count = -1; + goto done; + } + rv = PR_Send(sd, addr, len, 0, timeout); + PR_MemUnmap(addr, len); + if (rv < 0) { + count = -1; + goto done; + } + + PR_ASSERT(rv == len); + file_bytes -= rv; + count += rv; + len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); + } + PR_ASSERT(0 == file_bytes); + if (sfd->tlen) { + rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); + if (rv >= 0) { + PR_ASSERT(rv == sfd->tlen); + count += rv; + } else + count = -1; + } +done: + if (mapHandle) + PR_CloseFileMap(mapHandle); + if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) + PR_Close(sd); + return count; +} + +#else + +PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv, count = 0; + PRInt32 rlen; + const void * buffer; + PRInt32 buflen; + PRInt32 sendbytes, readbytes; + char *buf; + +#define _SENDFILE_BUFSIZE (16 * 1024) + + buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE); + if (buf == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + + /* + * send header first + */ + buflen = sfd->hlen; + buffer = sfd->header; + while (buflen) { + rv = PR_Send(sd, buffer, buflen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + buffer = (const void*) ((const char*)buffer + rv); + buflen -= rv; + } + } + + /* + * send file next + */ + if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) { + rv = -1; + goto done; + } + sendbytes = sfd->file_nbytes; + if (sendbytes == 0) { + /* send entire file */ + while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) { + while (rlen) { + char *bufptr = buf; + + rv = PR_Send(sd, bufptr, rlen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + bufptr = ((char*)bufptr + rv); + rlen -= rv; + } + } + } + if (rlen < 0) { + /* PR_Read() has invoked PR_SetError(). */ + rv = -1; + goto done; + } + } else { + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); + while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) { + while (rlen) { + char *bufptr = buf; + + rv = PR_Send(sd, bufptr, rlen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + sendbytes -= rv; + bufptr = ((char*)bufptr + rv); + rlen -= rv; + } + } + readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); + } + if (rlen < 0) { + /* PR_Read() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else if (sendbytes != 0) { + /* + * there are fewer bytes in file to send than specified + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + } + + /* + * send trailer last + */ + buflen = sfd->tlen; + buffer = sfd->trailer; + while (buflen) { + rv = PR_Send(sd, buffer, buflen, 0, timeout); + if (rv < 0) { + /* PR_Send() has invoked PR_SetError(). */ + rv = -1; + goto done; + } else { + count += rv; + buffer = (const void*) ((const char*)buffer + rv); + buflen -= rv; + } + } + rv = count; + +done: + if (buf) + PR_DELETE(buf); + if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) + PR_Close(sd); + return rv; +} + +#endif + +/* priometh.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c new file mode 100644 index 00000000..9f953534 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/pripv6.c @@ -0,0 +1,382 @@ +/* -*- 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 ***** */ + +/* +** File: pripv6.c +** Description: Support for various functions unique to IPv6 +*/ +#include "primpl.h" +#include + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) + +static PRIOMethods ipv6_to_v4_tcpMethods; +static PRIOMethods ipv6_to_v4_udpMethods; +static PRDescIdentity _pr_ipv6_to_ipv4_id; +extern PRBool IsValidNetAddr(const PRNetAddr *addr); +extern PRIPv6Addr _pr_in6addr_any; +extern PRIPv6Addr _pr_in6addr_loopback; + +/* + * convert an IPv4-mapped IPv6 addr to an IPv4 addr + */ +static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr, + PRNetAddr *dst_v4addr) +{ +const PRUint8 *srcp; + + PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family); + + if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) { + srcp = src_v6addr->ipv6.ip.pr_s6_addr; + memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4); + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) { + dst_v4addr->inet.ip = htonl(INADDR_ANY); + } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) { + dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK); + } + dst_v4addr->inet.family = PR_AF_INET; + dst_v4addr->inet.port = src_v6addr->ipv6.port; +} + +/* + * convert an IPv4 addr to an IPv4-mapped IPv6 addr + */ +static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr, + PRNetAddr *dst_v6addr) +{ +PRUint8 *dstp; + + PR_ASSERT(PR_AF_INET == src_v4addr->inet.family); + dst_v6addr->ipv6.family = PR_AF_INET6; + dst_v6addr->ipv6.port = src_v4addr->inet.port; + + if (htonl(INADDR_ANY) == src_v4addr->inet.ip) { + dst_v6addr->ipv6.ip = _pr_in6addr_any; + } else { + dstp = dst_v6addr->ipv6.ip.pr_s6_addr; + memset(dstp, 0, 10); + memset(dstp + 10, 0xff, 2); + memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4); + } +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd, + const PRNetAddr *addr) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + PRFileDesc *lo = fd->lower; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrAny)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return((lo->methods->bind)(lo,tmp_addrp)); +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout); +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + const PRNetAddr *tmp_addrp; + + if (PR_AF_INET6 != addr->raw.family) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || + PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { + _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); + tmp_addrp = &tmp_ipv4addr; + } else { + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); + return PR_FAILURE; + } + return (fd->lower->methods->sendto)( + fd->lower, buf, amount, flags, tmp_addrp, timeout); +} + +static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd; + PRFileDesc *newstack; + PRNetAddr tmp_ipv4addr; + PRNetAddr *addrlower = NULL; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + + if (addr) + addrlower = &tmp_ipv4addr; + newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout); + if (NULL == newfd) + { + PR_DELETE(newstack); + return NULL; + } + if (addr) + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr); + + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd, + PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount, + PRIntervalTime timeout) +{ + PRInt32 nbytes; + PRStatus rv; + PRNetAddr tmp_ipv4addr; + PRFileDesc *newstack; + + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + *newstack = *sd; /* make a copy of the accepting layer */ + + nbytes = sd->lower->methods->acceptread( + sd->lower, nd, ipv6_raddr, buf, amount, timeout); + if (-1 == nbytes) + { + PR_DELETE(newstack); + return nbytes; + } + tmp_ipv4addr = **ipv6_raddr; /* copy */ + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr); + + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return nbytes; +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd, + PRNetAddr *ipv6addr) +{ + PRStatus result; + PRNetAddr tmp_ipv4addr; + + result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr); + if (PR_SUCCESS == result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd, + PRNetAddr *ipv6addr) +{ + PRStatus result; + PRNetAddr tmp_ipv4addr; + + result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr); + if (PR_SUCCESS == result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf, + PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr, + PRIntervalTime timeout) +{ + PRNetAddr tmp_ipv4addr; + PRInt32 result; + + result = (fd->lower->methods->recvfrom)( + fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout); + if (-1 != result) { + _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); + PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); + } + return result; +} + +#if defined(_PR_INET6_PROBE) +PRBool _pr_ipv6_is_present; +extern PRBool _pr_test_ipv6_socket(void); + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) +extern PRStatus _pr_find_getipnodebyname(void); +#endif + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) +extern PRStatus _pr_find_getaddrinfo(void); +#endif + +static PRBool +_pr_probe_ipv6_presence(void) +{ +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_find_getipnodebyname() != PR_SUCCESS) + return PR_FALSE; +#endif + +#if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) + if (_pr_find_getaddrinfo() != PR_SUCCESS) + return PR_FALSE; +#endif + + return _pr_test_ipv6_socket(); +} +#endif /* _PR_INET6_PROBE */ + +PRStatus _pr_init_ipv6() +{ + const PRIOMethods *stubMethods; + +#if defined(_PR_INET6_PROBE) + _pr_ipv6_is_present = _pr_probe_ipv6_presence(); + if (PR_TRUE == _pr_ipv6_is_present) + return PR_SUCCESS; +#endif + + _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer"); + PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id); + + stubMethods = PR_GetDefaultIOMethods(); + + ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */ + /* then override the ones we care about */ + ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect; + ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind; + ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept; + ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead; + ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; + ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; +/* + ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; + ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; +*/ + ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */ + /* then override the ones we care about */ + ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect; + ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind; + ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo; + ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom; + ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; + ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; +/* + ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; + ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; +*/ + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd) +{ + PRFileDesc *ipv6_fd = NULL; + + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (fd->methods->file_type == PR_DESC_SOCKET_TCP) + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, + &ipv6_to_v4_tcpMethods); + else + ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, + &ipv6_to_v4_udpMethods); + if (NULL == ipv6_fd) { + goto errorExit; + } + ipv6_fd->secret = NULL; + + if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) { + goto errorExit; + } + + return PR_SUCCESS; +errorExit: + + if (ipv6_fd) + ipv6_fd->dtor(ipv6_fd); + return PR_FAILURE; +} + +#endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c new file mode 100644 index 00000000..65b67a09 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c @@ -0,0 +1,769 @@ +/* -*- 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 ***** */ + +/* +** File: prlayer.c +** Description: Routines for handling pushable protocol modules on sockets. +*/ + +#include "primpl.h" +#include "prerror.h" +#include "prmem.h" +#include "prlock.h" +#include "prlog.h" +#include "prio.h" + +#include /* for memset() */ +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack); + +void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + if (NULL != fd->lower) fd->lower->higher = fd->higher; + if (NULL != fd->higher) fd->higher->lower = fd->lower; + PR_DELETE(fd); +} + +/* +** Default methods that just call down to the next fd. +*/ +static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd) +{ + PRFileDesc *top, *lower; + PRStatus rv; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + PR_ASSERT(fd->secret == NULL); + PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED); + + if (PR_IO_LAYER_HEAD == fd->identity) { + /* + * new style stack; close all the layers, before deleting the + * stack head + */ + rv = fd->lower->methods->close(fd->lower); + _PR_DestroyIOLayer(fd); + return rv; + } else if ((fd->higher) && (PR_IO_LAYER_HEAD == fd->higher->identity)) { + /* + * lower layers of new style stack + */ + lower = fd->lower; + /* + * pop and cleanup current layer + */ + top = PR_PopIOLayer(fd->higher, PR_TOP_IO_LAYER); + top->dtor(top); + /* + * then call lower layer + */ + return (lower->methods->close(lower)); + } else { + /* old style stack */ + top = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); + top->dtor(top); + return (fd->methods->close)(fd); + } +} + +static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->read)(fd->lower, buf, amount); +} + +static PRInt32 PR_CALLBACK pl_DefWrite ( + PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->write)(fd->lower, buf, amount); +} + +static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->available)(fd->lower); +} + +static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->available64)(fd->lower); +} + +static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fsync)(fd->lower); +} + +static PRInt32 PR_CALLBACK pl_DefSeek ( + PRFileDesc *fd, PRInt32 offset, PRSeekWhence how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->seek)(fd->lower, offset, how); +} + +static PRInt64 PR_CALLBACK pl_DefSeek64 ( + PRFileDesc *fd, PRInt64 offset, PRSeekWhence how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->seek64)(fd->lower, offset, how); +} + +static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fileInfo)(fd->lower, info); +} + +static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->fileInfo64)(fd->lower, info); +} + +static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, const PRIOVec *iov, + PRInt32 size, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->writev)(fd->lower, iov, size, timeout); +} + +static PRStatus PR_CALLBACK pl_DefConnect ( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->connect)(fd->lower, addr, timeout); +} + +static PRStatus PR_CALLBACK pl_DefConnectcontinue ( + PRFileDesc *fd, PRInt16 out_flags) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->connectcontinue)(fd->lower, out_flags); +} + +static PRFileDesc* PR_CALLBACK pl_TopAccept ( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd, *layer = fd; + PRFileDesc *newstack; + PRBool newstyle_stack = PR_FALSE; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + /* test for new style stack */ + while (NULL != layer->higher) + layer = layer->higher; + newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE; + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + + newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); + if (NULL == newfd) + { + PR_DELETE(newstack); + return NULL; + } + + if (newstyle_stack) { + newstack->lower = newfd; + newfd->higher = newstack; + return newstack; + } else { + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ + } +} + +static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->bind)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->listen)(fd->lower, backlog); +} + +static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->shutdown)(fd->lower, how); +} + +static PRInt32 PR_CALLBACK pl_DefRecv ( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->recv)( + fd->lower, buf, amount, flags, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefSend ( + PRFileDesc *fd, const void *buf, + PRInt32 amount, PRIntn flags, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefRecvfrom ( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->recvfrom)( + fd->lower, buf, amount, flags, addr, timeout); +} + +static PRInt32 PR_CALLBACK pl_DefSendto ( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRIntervalTime timeout) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->sendto)( + fd->lower, buf, amount, flags, addr, timeout); +} + +static PRInt16 PR_CALLBACK pl_DefPoll ( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); +} + +static PRInt32 PR_CALLBACK pl_DefAcceptread ( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf, + PRInt32 amount, PRIntervalTime t) +{ + PRInt32 nbytes; + PRStatus rv; + PRFileDesc *newstack; + PRFileDesc *layer = sd; + PRBool newstyle_stack = PR_FALSE; + + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + /* test for new style stack */ + while (NULL != layer->higher) + layer = layer->higher; + newstyle_stack = (PR_IO_LAYER_HEAD == layer->identity) ? PR_TRUE : PR_FALSE; + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + *newstack = *sd; /* make a copy of the accepting layer */ + + nbytes = sd->lower->methods->acceptread( + sd->lower, nd, raddr, buf, amount, t); + if (-1 == nbytes) + { + PR_DELETE(newstack); + return nbytes; + } + if (newstyle_stack) { + newstack->lower = *nd; + (*nd)->higher = newstack; + *nd = newstack; + return nbytes; + } else { + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return nbytes; + } +} + +static PRInt32 PR_CALLBACK pl_DefTransmitfile ( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen, + PRTransmitFileFlags flags, PRIntervalTime t) +{ + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + return sd->lower->methods->transmitfile( + sd->lower, fd, headers, hlen, flags, t); +} + +static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getsockname)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getpeername)(fd->lower, addr); +} + +static PRStatus PR_CALLBACK pl_DefGetsocketoption ( + PRFileDesc *fd, PRSocketOptionData *data) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->getsocketoption)(fd->lower, data); +} + +static PRStatus PR_CALLBACK pl_DefSetsocketoption ( + PRFileDesc *fd, const PRSocketOptionData *data) +{ + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + return (fd->lower->methods->setsocketoption)(fd->lower, data); +} + +static PRInt32 PR_CALLBACK pl_DefSendfile ( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PR_ASSERT(sd != NULL); + PR_ASSERT(sd->lower != NULL); + + return sd->lower->methods->sendfile( + sd->lower, sfd, flags, timeout); +} + +/* Methods for the top of the stack. Just call down to the next fd. */ +static PRIOMethods pl_methods = { + PR_DESC_LAYERED, + pl_TopClose, + pl_DefRead, + pl_DefWrite, + pl_DefAvailable, + pl_DefAvailable64, + pl_DefFsync, + pl_DefSeek, + pl_DefSeek64, + pl_DefFileInfo, + pl_DefFileInfo64, + pl_DefWritev, + pl_DefConnect, + pl_TopAccept, + pl_DefBind, + pl_DefListen, + pl_DefShutdown, + pl_DefRecv, + pl_DefSend, + pl_DefRecvfrom, + pl_DefSendto, + pl_DefPoll, + pl_DefAcceptread, + pl_DefTransmitfile, + pl_DefGetsockname, + pl_DefGetpeername, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pl_DefGetsocketoption, + pl_DefSetsocketoption, + pl_DefSendfile, + pl_DefConnectcontinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetDefaultIOMethods(void) +{ + return &pl_methods; +} /* PR_GetDefaultIOMethods */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub( + PRDescIdentity ident, const PRIOMethods *methods) +{ + PRFileDesc *fd = NULL; + PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident)); + if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident)) + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + else + { + fd = PR_NEWZAP(PRFileDesc); + if (NULL == fd) + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->methods = methods; + fd->dtor = pl_FDDestructor; + fd->identity = ident; + } + } + return fd; +} /* PR_CreateIOLayerStub */ + +/* + * PR_CreateIOLayer + * Create a new style stack, where the stack top is a dummy header. + * Unlike the old style stacks, the contents of the stack head + * are not modified when a layer is pushed onto or popped from a new + * style stack. + */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayer(PRFileDesc *top) +{ + PRFileDesc *fd = NULL; + + fd = PR_NEWZAP(PRFileDesc); + if (NULL == fd) + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->methods = &pl_methods; + fd->dtor = pl_FDDestructor; + fd->identity = PR_IO_LAYER_HEAD; + fd->higher = NULL; + fd->lower = top; + top->higher = fd; + top->lower = NULL; + } + return fd; +} /* PR_CreateIOLayer */ + +/* + * _PR_DestroyIOLayer + * Delete the stack head of a new style stack. + */ + +static PRStatus _PR_DestroyIOLayer(PRFileDesc *stack) +{ + if (NULL == stack) + return PR_FAILURE; + else { + PR_DELETE(stack); + return PR_SUCCESS; + } +} /* _PR_DestroyIOLayer */ + +PR_IMPLEMENT(PRStatus) PR_PushIOLayer( + PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd) +{ + PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id); + + PR_ASSERT(fd != NULL); + PR_ASSERT(stack != NULL); + PR_ASSERT(insert != NULL); + PR_ASSERT(PR_IO_LAYER_HEAD != id); + if ((NULL == stack) || (NULL == fd) || (NULL == insert)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + if (stack == insert) + { + /* going on top of the stack */ + /* old-style stack */ + PRFileDesc copy = *stack; + *stack = *fd; + *fd = copy; + fd->higher = stack; + stack->lower = fd; + stack->higher = NULL; + } else { + /* + * going somewhere in the middle of the stack for both old and new + * style stacks, or going on top of stack for new style stack + */ + fd->lower = insert; + fd->higher = insert->higher; + + insert->higher->lower = fd; + insert->higher = fd; + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id) +{ + PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id); + + PR_ASSERT(0 != id); + PR_ASSERT(NULL != stack); + PR_ASSERT(NULL != extract); + if ((NULL == stack) || (0 == id) || (NULL == extract)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + if (extract == stack) { + /* popping top layer of the stack */ + /* old style stack */ + PRFileDesc copy = *stack; + extract = stack->lower; + *stack = *extract; + *extract = copy; + stack->higher = NULL; + } else if ((PR_IO_LAYER_HEAD == stack->identity) && + (extract == stack->lower) && (extract->lower == NULL)) { + /* + * new style stack + * popping the only layer in the stack; delete the stack too + */ + stack->lower = NULL; + _PR_DestroyIOLayer(stack); + } else { + /* for both kinds of stacks */ + extract->lower->higher = extract->higher; + extract->higher->lower = extract->lower; + } + extract->higher = extract->lower = NULL; + return extract; +} /* PR_PopIOLayer */ + +#define ID_CACHE_INCREMENT 16 +typedef struct _PRIdentity_cache +{ + PRLock *ml; + char **name; + PRIntn length; + PRDescIdentity ident; +} _PRIdentity_cache; + +static _PRIdentity_cache identity_cache; + +PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name) +{ + PRDescIdentity identity, length; + char **names = NULL, *name = NULL, **old = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident); + + if (NULL != layer_name) + { + name = (char*)PR_Malloc(strlen(layer_name) + 1); + if (NULL == name) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_INVALID_IO_LAYER; + } + strcpy(name, layer_name); + } + + /* this initial code runs unsafe */ +retry: + PR_ASSERT(NULL == names); + length = identity_cache.length; + if (length < (identity_cache.ident + 1)) + { + length += ID_CACHE_INCREMENT; + names = (char**)PR_CALLOC(length * sizeof(char*)); + if (NULL == names) + { + if (NULL != name) PR_DELETE(name); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_INVALID_IO_LAYER; + } + } + + /* now we get serious about thread safety */ + PR_Lock(identity_cache.ml); + PR_ASSERT(identity_cache.ident <= identity_cache.length); + identity = identity_cache.ident + 1; + if (identity > identity_cache.length) /* there's no room */ + { + /* we have to do something - hopefully it's already done */ + if ((NULL != names) && (length >= identity)) + { + /* what we did is still okay */ + if (identity_cache.length) + memcpy( + names, identity_cache.name, + identity_cache.length * sizeof(char*)); + old = identity_cache.name; + identity_cache.name = names; + identity_cache.length = length; + names = NULL; + } + else + { + PR_ASSERT(identity_cache.ident <= identity_cache.length); + PR_Unlock(identity_cache.ml); + if (NULL != names) PR_DELETE(names); + goto retry; + } + } + if (NULL != name) /* there's a name to be stored */ + { + identity_cache.name[identity] = name; + } + identity_cache.ident = identity; + PR_ASSERT(identity_cache.ident <= identity_cache.length); + PR_Unlock(identity_cache.ml); + + if (NULL != old) PR_DELETE(old); + if (NULL != names) PR_DELETE(names); + + return identity; +} /* PR_GetUniqueIdentity */ + +PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_TOP_IO_LAYER == ident) return NULL; + + PR_ASSERT(ident <= identity_cache.ident); + return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident]; +} /* PR_GetNameForIdentity */ + +PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd) +{ + PR_ASSERT(NULL != fd); + if (PR_IO_LAYER_HEAD == fd->identity) { + PR_ASSERT(NULL != fd->lower); + return fd->lower->identity; + } else + return fd->identity; +} /* PR_GetLayersIdentity */ + +PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id) +{ + PRFileDesc *layer = fd; + + if (PR_TOP_IO_LAYER == id) { + if (PR_IO_LAYER_HEAD == fd->identity) + return fd->lower; + else + return fd; + } + + for (layer = fd; layer != NULL; layer = layer->lower) + { + if (id == layer->identity) return layer; + } + for (layer = fd; layer != NULL; layer = layer->higher) + { + if (id == layer->identity) return layer; + } + return NULL; +} /* PR_GetIdentitiesLayer */ + +void _PR_InitLayerCache(void) +{ + memset(&identity_cache, 0, sizeof(identity_cache)); + identity_cache.ml = PR_NewLock(); + PR_ASSERT(NULL != identity_cache.ml); +} /* _PR_InitLayerCache */ + +void _PR_CleanupLayerCache(void) +{ + if (identity_cache.ml) + { + PR_DestroyLock(identity_cache.ml); + identity_cache.ml = NULL; + } + + if (identity_cache.name) + { + PRDescIdentity ident; + + for (ident = 0; ident <= identity_cache.ident; ident++) + PR_DELETE(identity_cache.name[ident]); + + PR_DELETE(identity_cache.name); + } +} /* _PR_CleanupLayerCache */ + +/* prlayer.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prlog.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlog.c new file mode 100644 index 00000000..faac606a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlog.c @@ -0,0 +1,617 @@ +/* -*- 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 ***** */ + +/* + * Contributors: + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per + * MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/10/2000 IBM Corp. Added DebugBreak() definitions for OS/2 + */ + +#if defined(VBOX) && defined(DEBUG) +# include /* for RTR3InitDll */ +# include +#endif +#ifdef VBOX_USE_IPRT_IN_NSPR +# include +#endif + +#include "primpl.h" +#include "prenv.h" +#include "prprf.h" +#include + +/* + * Lock used to lock the log. + * + * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may + * contain assertions. We have to avoid assertions in _PR_LOCK_LOG + * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG. + * This can lead to infinite recursion. + */ +static PRLock *_pr_logLock; +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) +#define _PR_LOCK_LOG() PR_Lock(_pr_logLock); +#define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock); +#elif defined(_PR_GLOBAL_THREADS_ONLY) +#define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock) +#define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); } +#else + +#define _PR_LOCK_LOG() \ +{ \ + PRIntn _is; \ + PRThread *_me = _PR_MD_CURRENT_THREAD(); \ + if (!_PR_IS_NATIVE_THREAD(_me)) \ + _PR_INTSOFF(_is); \ + _PR_LOCK_LOCK(_pr_logLock) + +#define _PR_UNLOCK_LOG() \ + _PR_LOCK_UNLOCK(_pr_logLock); \ + PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \ + if (!_PR_IS_NATIVE_THREAD(_me)) \ + _PR_INTSON(_is); \ +} + +#endif + +#if defined(XP_PC) +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +/* + * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE, + * because every asynchronous file io operation leads to a fiber context + * switch. So we define _PUT_LOG as fputs (from stdio.h). A side + * benefit is that fputs handles the LF->CRLF translation. This + * code can also be used on other platforms with file stream io. + */ +#if defined(WIN32) || defined(XP_OS2) +#define _PR_USE_STDIO_FOR_LOGGING +#endif + +/* +** Coerce Win32 log output to use OutputDebugString() when +** NSPR_LOG_FILE is set to "WinDebug". +*/ +#if defined(XP_PC) +#define WIN32_DEBUG_FILE (FILE*)-2 +#endif + +/* +** Use the IPRT logging facility when +** NSPR_LOG_FILE is set to "WinDebug". The default IPRT log instance +** and the "default" log group will be used for logging. +*/ +#if defined(VBOX) && defined(DEBUG) +#if defined(_PR_USE_STDIO_FOR_LOGGING) +#define IPRT_DEBUG_FILE (FILE*)-3 +#else +#define IPRT_DEBUG_FILE (PRFileDesc*)-3 +#endif +#endif + +/* Macros used to reduce #ifdef pollution */ + +#if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC) +#define __PUT_LOG(fd, buf, nb) \ + PR_BEGIN_MACRO \ + if (fd == WIN32_DEBUG_FILE) { \ + char savebyte = buf[nb]; \ + buf[nb] = '\0'; \ + OutputDebugString(buf); \ + buf[nb] = savebyte; \ + } else { \ + fwrite(buf, 1, nb, fd); \ + fflush(fd); \ + } \ + PR_END_MACRO +#elif defined(_PR_USE_STDIO_FOR_LOGGING) +#define __PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);} +#elif defined(_PR_PTHREADS) +#define __PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb) +#elif defined(XP_MAC) +#define __PUT_LOG(fd, buf, nb) _PR_MD_WRITE_SYNC(fd, buf, nb) +#else +#define __PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb) +#endif + +#if defined(VBOX) && defined(DEBUG) +#define _PUT_LOG(fd, buf, nb) \ + PR_BEGIN_MACRO \ + if (fd == IPRT_DEBUG_FILE) { \ + Log(("%*.*S", nb, nb, buf)); \ + } else { \ + __PUT_LOG(fd, buf, nb); \ + } \ + PR_END_MACRO +#else +#define _PUT_LOG(fd, buf, nb) __PUT_LOG(fd, buf, nb) +#endif + +/************************************************************************/ + +static PRLogModuleInfo *logModules; + +static char *logBuf = NULL; +static char *logp; +static char *logEndp; +#ifdef _PR_USE_STDIO_FOR_LOGGING +static FILE *logFile = NULL; +#else +static PRFileDesc *logFile = 0; +#endif + +#define LINE_BUF_SIZE 512 +#define DEFAULT_BUF_SIZE 16384 + +#ifdef _PR_NEED_STRCASECMP + +/* + * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms + * such as NCR and Unixware. Linking with both libc and libucb + * may cause some problem, so I just provide our own implementation + * of strcasecmp here. + */ + +static const unsigned char uc[] = +{ + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + ' ', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '{', '|', '}', '~', '\177' +}; + +PRIntn strcasecmp(const char *a, const char *b) +{ + const unsigned char *ua = (const unsigned char *)a; + const unsigned char *ub = (const unsigned char *)b; + + if( ((const char *)0 == a) || (const char *)0 == b ) + return (PRIntn)(a-b); + + while( (uc[*ua] == uc[*ub]) && ('\0' != *a) ) + { + a++; + ua++; + ub++; + } + + return (PRIntn)(uc[*ua] - uc[*ub]); +} + +#endif /* _PR_NEED_STRCASECMP */ + +void _PR_InitLog(void) +{ + char *ev; + + _pr_logLock = PR_NewLock(); + + ev = PR_GetEnv("NSPR_LOG_MODULES"); + if (ev && ev[0]) { + char module[64]; /* Security-Critical: If you change this + * size, you must also change the sscanf + * format string to be size-1. + */ + PRBool isSync = PR_FALSE; + PRIntn evlen = strlen(ev), pos = 0; + PRInt32 bufSize = DEFAULT_BUF_SIZE; + while (pos < evlen) { + PRIntn level = 1, count = 0, delta = 0; + count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n", + module, &delta, &level, &delta); + pos += delta; + if (count == 0) break; + + /* + ** If count == 2, then we got module and level. If count + ** == 1, then level defaults to 1 (module enabled). + */ + if (strcasecmp(module, "sync") == 0) { + isSync = PR_TRUE; + } else if (strcasecmp(module, "bufsize") == 0) { + if (level >= LINE_BUF_SIZE) { + bufSize = level; + } + } else { + PRLogModuleInfo *lm = logModules; + PRBool skip_modcheck = + (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE; + + while (lm != NULL) { + if (skip_modcheck) lm -> level = (PRLogModuleLevel)level; + else if (strcasecmp(module, lm->name) == 0) { + lm->level = (PRLogModuleLevel)level; + break; + } + lm = lm->next; + } + } + /*found:*/ + count = sscanf(&ev[pos], " , %n", &delta); + pos += delta; + if (count == EOF) break; + } + PR_SetLogBuffering(isSync ? bufSize : 0); + + ev = PR_GetEnv("NSPR_LOG_FILE"); + if (ev && ev[0]) { + if (!PR_SetLogFile(ev)) { +#ifdef XP_PC + char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev); + if (str) { + OutputDebugString(str); + PR_smprintf_free(str); + } +#else + fprintf(stderr, "Unable to create nspr log file '%s'\n", ev); +#endif + } + } else { +#ifdef _PR_USE_STDIO_FOR_LOGGING + logFile = stderr; +#else + logFile = _pr_stderr; +#endif + } + } +} + +void _PR_LogCleanup(void) +{ + PRLogModuleInfo *lm = logModules; + + PR_LogFlush(); + +#ifdef _PR_USE_STDIO_FOR_LOGGING + if (logFile + && logFile != stdout + && logFile != stderr +#if defined(VBOX) && defined(DEBUG) + && logFile != IPRT_DEBUG_FILE +#endif +#ifdef XP_PC + && logFile != WIN32_DEBUG_FILE +#endif + ) { + fclose(logFile); + } +#else + if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { + PR_Close(logFile); + } +#endif + + while (lm != NULL) { + PRLogModuleInfo *next = lm->next; +#ifdef VBOX_USE_IPRT_IN_NSPR + RTStrFree((/*const*/ char *)lm->name); +#else + free((/*const*/ char *)lm->name); +#endif + PR_Free(lm); + lm = next; + } + logModules = NULL; + + if (_pr_logLock) { + PR_DestroyLock(_pr_logLock); + _pr_logLock = NULL; + } +} + +static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm ) +{ + char *ev; + + ev = PR_GetEnv("NSPR_LOG_MODULES"); + if (ev && ev[0]) { + char module[64]; /* Security-Critical: If you change this + * size, you must also change the sscanf + * format string to be size-1. + */ + PRIntn evlen = strlen(ev), pos = 0; + while (pos < evlen) { + PRIntn level = 1, count = 0, delta = 0; + + count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789]%n:%d%n", + module, &delta, &level, &delta); + pos += delta; + if (count == 0) break; + + /* + ** If count == 2, then we got module and level. If count + ** == 1, then level defaults to 1 (module enabled). + */ + if (lm != NULL) + { + if ((strcasecmp(module, "all") == 0) + || (strcasecmp(module, lm->name) == 0)) + { + lm->level = (PRLogModuleLevel)level; + } + } + count = sscanf(&ev[pos], " , %n", &delta); + pos += delta; + if (count == EOF) break; + } + } +} /* end _PR_SetLogModuleLevel() */ + +PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name) +{ + PRLogModuleInfo *lm; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lm = PR_NEWZAP(PRLogModuleInfo); + if (lm) { +#ifdef VBOX_USE_IPRT_IN_NSPR + lm->name = RTStrDup(name); +#else + lm->name = strdup(name); +#endif + lm->level = PR_LOG_NONE; + lm->next = logModules; + logModules = lm; + _PR_SetLogModuleLevel(lm); + } + return lm; +} + +PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file) +{ +#ifdef _PR_USE_STDIO_FOR_LOGGING + + FILE *newLogFile; + +#if defined(VBOX) && defined(DEBUG) + if (strcmp(file, "IPRT") == 0) { + /* initialize VBox Runtime */ + RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + newLogFile = IPRT_DEBUG_FILE; + } + else +#endif +#ifdef XP_PC + if (strcmp(file, "WinDebug") == 0) { + newLogFile = WIN32_DEBUG_FILE; + } + else +#endif + { + newLogFile = fopen(file, "w"); + if (!newLogFile) + return PR_FALSE; + + /* We do buffering ourselves. */ + setvbuf(newLogFile, NULL, _IONBF, 0); + } + if (logFile + && logFile != stdout + && logFile != stderr +#if defined(VBOX) && defined(DEBUG) + && logFile != IPRT_DEBUG_FILE +#endif +#ifdef XP_PC + && logFile != WIN32_DEBUG_FILE +#endif + ) { + fclose(logFile); + } + logFile = newLogFile; + return PR_TRUE; + +#else /* _PR_USE_STDIO_FOR_LOGGING */ + + PRFileDesc *newLogFile; + +#if defined(VBOX) && defined(DEBUG) + if (strcmp(file, "IPRT") == 0) { + /* initialize VBox Runtime */ + RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + logFile = IPRT_DEBUG_FILE; + return PR_TRUE; + } +#endif + + newLogFile = PR_Open(file, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0666); + if (newLogFile) { + if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) { + PR_Close(logFile); + } + logFile = newLogFile; +#if defined(XP_MAC) + SetLogFileTypeCreator(file); +#endif + } + return (PRBool) (newLogFile != 0); + +#endif /* _PR_USE_STDIO_FOR_LOGGING */ +} + +PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size) +{ + PR_LogFlush(); + + if (logBuf) + PR_DELETE(logBuf); + + if (buffer_size >= LINE_BUF_SIZE) { + logp = logBuf = (char*) PR_MALLOC(buffer_size); + logEndp = logp + buffer_size; + } +} + +PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...) +{ + va_list ap; + char line[LINE_BUF_SIZE]; + PRUint32 nb; + PRThread *me; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!logFile) { + return; + } + + va_start(ap, fmt); + me = PR_GetCurrentThread(); + nb = PR_snprintf(line, sizeof(line)-1, "%ld[%p]: ", +#if defined(_PR_DCETHREADS) + /* The problem is that for _PR_DCETHREADS, pthread_t is not a + * pointer, but a structure; so you can't easily print it... + */ + me ? &(me->id): 0L, me); +#elif defined(_PR_BTHREADS) + me, me); +#else + me ? me->id : 0L, me); +#endif + + nb += PR_vsnprintf(line+nb, sizeof(line)-nb-1, fmt, ap); + if (nb > 0) { + if (line[nb-1] != '\n') { +#ifndef XP_MAC + line[nb++] = '\n'; +#else + line[nb++] = '\015'; +#endif + line[nb] = '\0'; + } else { +#ifdef XP_MAC + line[nb-1] = '\015'; +#endif + } + } + va_end(ap); + + _PR_LOCK_LOG(); + if (logBuf == 0) { + _PUT_LOG(logFile, line, nb); + } else { + if (logp + nb > logEndp) { + _PUT_LOG(logFile, logBuf, logp - logBuf); + logp = logBuf; + } + memcpy(logp, line, nb); + logp += nb; + } + _PR_UNLOCK_LOG(); + PR_LogFlush(); +} + +PR_IMPLEMENT(void) PR_LogFlush(void) +{ + if (logBuf && logFile) { + _PR_LOCK_LOG(); + if (logp > logBuf) { + _PUT_LOG(logFile, logBuf, logp - logBuf); + logp = logBuf; + } + _PR_UNLOCK_LOG(); + } +} + +PR_IMPLEMENT(void) PR_Abort(void) +{ + PR_LogPrint("Aborting"); + abort(); +} + +#if defined(XP_OS2) +/* + * Added definitions for DebugBreak() for 2 different OS/2 compilers. + * Doing the int3 on purpose for Visual Age so that a developer can + * step over the instruction if so desired. Not always possible if + * trapping due to exception handling IBM-AKR + */ +#if defined(XP_OS2_VACPP) +#include +static void DebugBreak(void) { _interrupt(3); } +#elif defined(XP_OS2_EMX) +static void DebugBreak(void) { asm("int $3"); } +#else +static void DebugBreak(void) { } +#endif +#endif /* XP_OS2 */ + +PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln) +{ + PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln); +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) + fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); +#endif +#ifdef XP_MAC + dprintf("Assertion failure: %s, at %s:%d\n", s, file, ln); +#endif +#if defined(WIN32) || defined(XP_OS2) + DebugBreak(); +#endif +#ifndef XP_MAC + abort(); +#endif +} + +#ifdef XP_MAC +PR_IMPLEMENT(void) PR_Init_Log(void) +{ + _PR_InitLog(); +} +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prmapopt.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmapopt.c new file mode 100644 index 00000000..e4811e57 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmapopt.c @@ -0,0 +1,517 @@ +/* -*- 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 file defines _PR_MapOptionName(). The purpose of putting + * _PR_MapOptionName() in a separate file is to work around a Winsock + * header file problem on Windows NT. + * + * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order + * to use Service Pack 3 extensions), windows.h includes winsock2.h + * (instead of winsock.h), which doesn't define many socket options + * defined in winsock.h. + * + * We need the socket options defined in winsock.h. So this file + * includes winsock.h, with _WIN32_WINNT undefined. + */ + +#if defined(WINNT) || defined(__MINGW32__) +#include +#endif + +/* MinGW doesn't define these in its winsock.h. */ +#ifdef __MINGW32__ +#ifndef IP_TTL +#define IP_TTL 7 +#endif +#ifndef IP_TOS +#define IP_TOS 8 +#endif +#endif + +#include "primpl.h" + +#if defined(NEXTSTEP) +/* NEXTSTEP is special: this must come before netinet/tcp.h. */ +#include /* n_short, n_long, n_time */ +#endif + +#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION)) +#include /* TCP_NODELAY, TCP_MAXSEG */ +#endif + +#ifndef _PR_PTHREADS + +PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) +{ + PRStatus rv; + PRInt32 length; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a getsockopt() call + */ + if (PR_SockOpt_Nonblocking == data->option) + { + data->value.non_blocking = fd->secret->nonblocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { +#if !defined(XP_BEOS) || defined(BONE_VERSION) + struct linger linger; + length = sizeof(linger); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char *) &linger, &length); + if (PR_SUCCESS == rv) + { + PR_ASSERT(sizeof(linger) == length); + data->value.linger.polarity = + (linger.l_onoff) ? PR_TRUE : PR_FALSE; + data->value.linger.linger = + PR_SecondsToInterval(linger.l_linger); + } + break; +#else + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +#endif + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { +#ifdef WIN32 /* Winsock */ + BOOL value; +#else + PRIntn value; +#endif + length = sizeof(value); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&value, &length); + if (PR_SUCCESS == rv) + data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_McastLoopback: + { +#ifdef WIN32 /* Winsock */ + BOOL bool; +#else + PRUint8 bool; +#endif + length = sizeof(bool); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&bool, &length); + if (PR_SUCCESS == rv) + data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value; + length = sizeof(value); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&value, &length); + if (PR_SUCCESS == rv) + data->value.recv_buffer_size = value; + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + /* These options should really be an int (or PRIntn). */ + length = sizeof(PRUintn); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&data->value.ip_ttl, &length); + break; + } + case PR_SockOpt_McastTimeToLive: + { +#ifdef WIN32 /* Winsock */ + int ttl; +#else + PRUint8 ttl; +#endif + length = sizeof(ttl); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&ttl, &length); + if (PR_SUCCESS == rv) + data->value.mcast_ttl = ttl; + break; + } +#ifdef IP_ADD_MEMBERSHIP + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + length = sizeof(mreq); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, (char*)&mreq, &length); + if (PR_SUCCESS == rv) + { + data->value.add_member.mcaddr.inet.ip = + mreq.imr_multiaddr.s_addr; + data->value.add_member.ifaddr.inet.ip = + mreq.imr_interface.s_addr; + } + break; + } +#endif /* IP_ADD_MEMBERSHIP */ + case PR_SockOpt_McastInterface: + { + /* This option is a struct in_addr. */ + length = sizeof(data->value.mcast_if.inet.ip); + rv = _PR_MD_GETSOCKOPT( + fd, level, name, + (char*)&data->value.mcast_if.inet.ip, &length); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + } + return rv; +} /* _PR_SocketGetSocketOption */ + +PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data) +{ + PRStatus rv; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a setsockopt call. + */ + if (PR_SockOpt_Nonblocking == data->option) + { +#ifdef WINNT + PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE) + || (fd->secret->nonblocking == data->value.non_blocking)); + if (fd->secret->md.io_model_committed + && (fd->secret->nonblocking != data->value.non_blocking)) + { + /* + * On NT, once we have associated a socket with the io + * completion port, we can't disassociate it. So we + * can't change the nonblocking option of the socket + * afterwards. + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } +#endif + fd->secret->nonblocking = data->value.non_blocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { +#if !defined(XP_BEOS) || defined(BONE_VERSION) + struct linger linger; + linger.l_onoff = data->value.linger.polarity; + linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&linger, sizeof(linger)); + break; +#else + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +#endif + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { +#ifdef WIN32 /* Winsock */ + BOOL value; +#else + PRIntn value; +#endif + value = (data->value.reuse_addr) ? 1 : 0; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&value, sizeof(value)); + break; + } + case PR_SockOpt_McastLoopback: + { +#ifdef WIN32 /* Winsock */ + BOOL bool; +#else + PRUint8 bool; +#endif + bool = data->value.mcast_loopback ? 1 : 0; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&bool, sizeof(bool)); + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value = data->value.recv_buffer_size; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&value, sizeof(value)); + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + /* These options should really be an int (or PRIntn). */ + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn)); + break; + } + case PR_SockOpt_McastTimeToLive: + { +#ifdef WIN32 /* Winsock */ + int ttl; +#else + PRUint8 ttl; +#endif + ttl = data->value.mcast_ttl; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&ttl, sizeof(ttl)); + break; + } +#ifdef IP_ADD_MEMBERSHIP + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = + data->value.add_member.mcaddr.inet.ip; + mreq.imr_interface.s_addr = + data->value.add_member.ifaddr.inet.ip; + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&mreq, sizeof(mreq)); + break; + } +#endif /* IP_ADD_MEMBERSHIP */ + case PR_SockOpt_McastInterface: + { + /* This option is a struct in_addr. */ + rv = _PR_MD_SETSOCKOPT( + fd, level, name, (char*)&data->value.mcast_if.inet.ip, + sizeof(data->value.mcast_if.inet.ip)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + } + return rv; +} /* _PR_SocketSetSocketOption */ + +#endif /* ! _PR_PTHREADS */ + +/* + ********************************************************************* + ********************************************************************* + ** + ** Make sure that the following is at the end of this file, + ** because we will be playing with macro redefines. + ** + ********************************************************************* + ********************************************************************* + */ + +#if defined(VMS) +/* +** Sad but true. The DEC C header files define the following socket options +** differently to what UCX is expecting. The values that UCX expects are +** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values +** that UCX expects. Note that UCX V4.x will only accept these values while +** UCX V5.x will accept either. So in theory this hack can be removed once +** UCX V5 is the minimum. +*/ +#undef IP_MULTICAST_IF +#undef IP_MULTICAST_TTL +#undef IP_MULTICAST_LOOP +#undef IP_ADD_MEMBERSHIP +#undef IP_DROP_MEMBERSHIP +#include +#define IP_MULTICAST_IF UCX$C_IP_MULTICAST_IF +#define IP_MULTICAST_TTL UCX$C_IP_MULTICAST_TTL +#define IP_MULTICAST_LOOP UCX$C_IP_MULTICAST_LOOP +#define IP_ADD_MEMBERSHIP UCX$C_IP_ADD_MEMBERSHIP +#define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP +#endif + +/* + * Not every platform has all the socket options we want to + * support. Some older operating systems such as SunOS 4.1.3 + * don't have the IP multicast socket options. Win32 doesn't + * have TCP_MAXSEG. + * + * To deal with this problem, we define the missing socket + * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with + * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not + * available on the platform is requested. + */ + +/* + * Sanity check. SO_LINGER and TCP_NODELAY should be available + * on all platforms. Just to make sure we have included the + * appropriate header files. Then any undefined socket options + * are really missing. + */ + +#if !defined(SO_LINGER) +#error "SO_LINGER is not defined" +#endif + +/* + * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined + * in + */ +#if !defined(NCR) +#if !defined(TCP_NODELAY) +#error "TCP_NODELAY is not defined" +#endif +#endif + +/* + * Make sure the value of _PR_NO_SUCH_SOCKOPT is not + * a valid socket option. + */ +#define _PR_NO_SUCH_SOCKOPT -1 + +#ifndef SO_KEEPALIVE +#define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_SNDBUF +#define SO_SNDBUF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_RCVBUF +#define SO_RCVBUF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_IF /* set/get IP multicast interface */ +#define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */ +#define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */ +#define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */ +#define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */ +#define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_TTL /* set/get IP Time To Live */ +#define IP_TTL _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef IP_TOS /* set/get IP Type Of Service */ +#define IP_TOS _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef TCP_NODELAY /* don't delay to coalesce data */ +#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef TCP_MAXSEG /* maxumum segment size for tcp */ +#define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT +#endif + +#ifndef SO_BROADCAST /* enable broadcast on udp sockets */ +#define SO_BROADCAST _PR_NO_SUCH_SOCKOPT +#endif + +PRStatus _PR_MapOptionName( + PRSockOption optname, PRInt32 *level, PRInt32 *name) +{ + static PRInt32 socketOptions[PR_SockOpt_Last] = + { + 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF, + IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, + IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, + TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST + }; + static PRInt32 socketLevels[PR_SockOpt_Last] = + { + 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, + IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET + }; + + if ((optname < PR_SockOpt_Linger) + || (optname >= PR_SockOpt_Last)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT) + { + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; + } + *name = socketOptions[optname]; + *level = socketLevels[optname]; + return PR_SUCCESS; +} /* _PR_MapOptionName */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prmmap.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmmap.c new file mode 100644 index 00000000..e5c1e5dc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmmap.c @@ -0,0 +1,93 @@ +/* -*- 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 ***** */ + +/* + ********************************************************************* + * + * Memory-mapped files + * + ********************************************************************* + */ + +#include "primpl.h" + +PR_IMPLEMENT(PRFileMap *) PR_CreateFileMap( + PRFileDesc *fd, + PRInt64 size, + PRFileMapProtect prot) +{ + PRFileMap *fmap; + + PR_ASSERT(prot == PR_PROT_READONLY || prot == PR_PROT_READWRITE + || prot == PR_PROT_WRITECOPY); + fmap = PR_NEWZAP(PRFileMap); + if (NULL == fmap) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + fmap->fd = fd; + fmap->prot = prot; + if (_PR_MD_CREATE_FILE_MAP(fmap, size) == PR_SUCCESS) { + return fmap; + } else { + PR_DELETE(fmap); + return NULL; + } +} + +PR_IMPLEMENT(PRInt32) PR_GetMemMapAlignment(void) +{ + return _PR_MD_GET_MEM_MAP_ALIGNMENT(); +} + +PR_IMPLEMENT(void *) PR_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ + return _PR_MD_MEM_MAP(fmap, offset, len); +} + +PR_IMPLEMENT(PRStatus) PR_MemUnmap(void *addr, PRUint32 len) +{ + return _PR_MD_MEM_UNMAP(addr, len); +} + +PR_IMPLEMENT(PRStatus) PR_CloseFileMap(PRFileMap *fmap) +{ + return _PR_MD_CLOSE_FILE_MAP(fmap); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prmwait.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmwait.c new file mode 100644 index 00000000..8c2e5f98 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prmwait.c @@ -0,0 +1,1491 @@ +/* -*- 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 "pprmwait.h" + +#define _MW_REHASH_MAX 11 + +static PRLock *mw_lock = NULL; +static _PRGlobalState *mw_state = NULL; + +static PRIntervalTime max_polling_interval; + +#ifdef WINNT + +typedef struct TimerEvent { + PRIntervalTime absolute; + void (*func)(void *); + void *arg; + LONG ref_count; + PRCList links; +} TimerEvent; + +#define TIMER_EVENT_PTR(_qp) \ + ((TimerEvent *) ((char *) (_qp) - offsetof(TimerEvent, links))) + +struct { + PRLock *ml; + PRCondVar *new_timer; + PRCondVar *cancel_timer; + PRThread *manager_thread; + PRCList timer_queue; +} tm_vars; + +static PRStatus TimerInit(void); +static void TimerManager(void *arg); +static TimerEvent *CreateTimer(PRIntervalTime timeout, + void (*func)(void *), void *arg); +static PRBool CancelTimer(TimerEvent *timer); + +static void TimerManager(void *arg) +{ + PRIntervalTime now; + PRIntervalTime timeout; + PRCList *head; + TimerEvent *timer; + + PR_Lock(tm_vars.ml); + while (1) + { + if (PR_CLIST_IS_EMPTY(&tm_vars.timer_queue)) + { + PR_WaitCondVar(tm_vars.new_timer, PR_INTERVAL_NO_TIMEOUT); + } + else + { + now = PR_IntervalNow(); + head = PR_LIST_HEAD(&tm_vars.timer_queue); + timer = TIMER_EVENT_PTR(head); + if ((PRInt32) (now - timer->absolute) >= 0) + { + PR_REMOVE_LINK(head); + /* + * make its prev and next point to itself so that + * it's obvious that it's not on the timer_queue. + */ + PR_INIT_CLIST(head); + PR_ASSERT(2 == timer->ref_count); + PR_Unlock(tm_vars.ml); + timer->func(timer->arg); + PR_Lock(tm_vars.ml); + timer->ref_count -= 1; + if (0 == timer->ref_count) + { + PR_NotifyAllCondVar(tm_vars.cancel_timer); + } + } + else + { + timeout = (PRIntervalTime)(timer->absolute - now); + PR_WaitCondVar(tm_vars.new_timer, timeout); + } + } + } + PR_Unlock(tm_vars.ml); +} + +static TimerEvent *CreateTimer( + PRIntervalTime timeout, + void (*func)(void *), + void *arg) +{ + TimerEvent *timer; + PRCList *links, *tail; + TimerEvent *elem; + + timer = PR_NEW(TimerEvent); + if (NULL == timer) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return timer; + } + timer->absolute = PR_IntervalNow() + timeout; + timer->func = func; + timer->arg = arg; + timer->ref_count = 2; + PR_Lock(tm_vars.ml); + tail = links = PR_LIST_TAIL(&tm_vars.timer_queue); + while (links->prev != tail) + { + elem = TIMER_EVENT_PTR(links); + if ((PRInt32)(timer->absolute - elem->absolute) >= 0) + { + break; + } + links = links->prev; + } + PR_INSERT_AFTER(&timer->links, links); + PR_NotifyCondVar(tm_vars.new_timer); + PR_Unlock(tm_vars.ml); + return timer; +} + +static PRBool CancelTimer(TimerEvent *timer) +{ + PRBool canceled = PR_FALSE; + + PR_Lock(tm_vars.ml); + timer->ref_count -= 1; + if (timer->links.prev == &timer->links) + { + while (timer->ref_count == 1) + { + PR_WaitCondVar(tm_vars.cancel_timer, PR_INTERVAL_NO_TIMEOUT); + } + } + else + { + PR_REMOVE_LINK(&timer->links); + canceled = PR_TRUE; + } + PR_Unlock(tm_vars.ml); + PR_DELETE(timer); + return canceled; +} + +static PRStatus TimerInit(void) +{ + tm_vars.ml = PR_NewLock(); + if (NULL == tm_vars.ml) + { + goto failed; + } + tm_vars.new_timer = PR_NewCondVar(tm_vars.ml); + if (NULL == tm_vars.new_timer) + { + goto failed; + } + tm_vars.cancel_timer = PR_NewCondVar(tm_vars.ml); + if (NULL == tm_vars.cancel_timer) + { + goto failed; + } + PR_INIT_CLIST(&tm_vars.timer_queue); + tm_vars.manager_thread = PR_CreateThread( + PR_SYSTEM_THREAD, TimerManager, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + if (NULL == tm_vars.manager_thread) + { + goto failed; + } + return PR_SUCCESS; + +failed: + if (NULL != tm_vars.cancel_timer) + { + PR_DestroyCondVar(tm_vars.cancel_timer); + } + if (NULL != tm_vars.new_timer) + { + PR_DestroyCondVar(tm_vars.new_timer); + } + if (NULL != tm_vars.ml) + { + PR_DestroyLock(tm_vars.ml); + } + return PR_FAILURE; +} + +#endif /* WINNT */ + +/******************************************************************/ +/******************************************************************/ +/************************ The private portion *********************/ +/******************************************************************/ +/******************************************************************/ +void _PR_InitMW(void) +{ +#ifdef WINNT + /* + * We use NT 4's InterlockedCompareExchange() to operate + * on PRMWStatus variables. + */ + PR_ASSERT(sizeof(PVOID) == sizeof(PRMWStatus)); + TimerInit(); +#endif + mw_lock = PR_NewLock(); + PR_ASSERT(NULL != mw_lock); + mw_state = PR_NEWZAP(_PRGlobalState); + PR_ASSERT(NULL != mw_state); + PR_INIT_CLIST(&mw_state->group_list); + max_polling_interval = PR_MillisecondsToInterval(MAX_POLLING_INTERVAL); +} /* _PR_InitMW */ + +void _PR_CleanupMW(void) +{ + PR_DestroyLock(mw_lock); + mw_lock = NULL; + if (mw_state->group) { + PR_DestroyWaitGroup(mw_state->group); + /* mw_state->group is set to NULL as a side effect. */ + } + PR_DELETE(mw_state); +} /* _PR_CleanupMW */ + +static PRWaitGroup *MW_Init2(void) +{ + PRWaitGroup *group = mw_state->group; /* it's the null group */ + if (NULL == group) /* there is this special case */ + { + group = PR_CreateWaitGroup(_PR_DEFAULT_HASH_LENGTH); + if (NULL == group) goto failed_alloc; + PR_Lock(mw_lock); + if (NULL == mw_state->group) + { + mw_state->group = group; + group = NULL; + } + PR_Unlock(mw_lock); + if (group != NULL) (void)PR_DestroyWaitGroup(group); + group = mw_state->group; /* somebody beat us to it */ + } +failed_alloc: + return group; /* whatever */ +} /* MW_Init2 */ + +static _PR_HashStory MW_AddHashInternal(PRRecvWait *desc, _PRWaiterHash *hash) +{ + /* + ** The entries are put in the table using the fd (PRFileDesc*) of + ** the receive descriptor as the key. This allows us to locate + ** the appropriate entry aqain when the poll operation finishes. + ** + ** The pointer to the file descriptor object is first divided by + ** the natural alignment of a pointer in the belief that object + ** will have at least that many zeros in the low order bits. + ** This may not be a good assuption. + ** + ** We try to put the entry in by rehashing _MW_REHASH_MAX times. After + ** that we declare defeat and force the table to be reconstructed. + ** Since some fds might be added more than once, won't that cause + ** collisions even in an empty table? + */ + PRIntn rehash = _MW_REHASH_MAX; + PRRecvWait **waiter; + PRUintn hidx = _MW_HASH(desc->fd, hash->length); + PRUintn hoffset = 0; + + while (rehash-- > 0) + { + waiter = &hash->recv_wait; + if (NULL == waiter[hidx]) + { + waiter[hidx] = desc; + hash->count += 1; +#if 0 + printf("Adding 0x%x->0x%x ", desc, desc->fd); + printf( + "table[%u:%u:*%u]: 0x%x->0x%x\n", + hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd); +#endif + return _prmw_success; + } + if (desc == waiter[hidx]) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); /* desc already in table */ + return _prmw_error; + } +#if 0 + printf("Failing 0x%x->0x%x ", desc, desc->fd); + printf( + "table[*%u:%u:%u]: 0x%x->0x%x\n", + hidx, hash->count, hash->length, waiter[hidx], waiter[hidx]->fd); +#endif + if (0 == hoffset) + { + hoffset = _MW_HASH2(desc->fd, hash->length); + PR_ASSERT(0 != hoffset); + } + hidx = (hidx + hoffset) % (hash->length); + } + return _prmw_rehash; +} /* MW_AddHashInternal */ + +static _PR_HashStory MW_ExpandHashInternal(PRWaitGroup *group) +{ + PRRecvWait **desc; + PRUint32 pidx, length; + _PRWaiterHash *newHash, *oldHash = group->waiter; + PRBool retry; + _PR_HashStory hrv; + + static const PRInt32 prime_number[] = { + _PR_DEFAULT_HASH_LENGTH, 179, 521, 907, 1427, + 2711, 3917, 5021, 8219, 11549, 18911, 26711, 33749, 44771}; + PRUintn primes = (sizeof(prime_number) / sizeof(PRInt32)); + + /* look up the next size we'd like to use for the hash table */ + for (pidx = 0; pidx < primes; ++pidx) + { + if (prime_number[pidx] == oldHash->length) + { + break; + } + } + /* table size must be one of the prime numbers */ + PR_ASSERT(pidx < primes); + + /* if pidx == primes - 1, we can't expand the table any more */ + while (pidx < primes - 1) + { + /* next size */ + ++pidx; + length = prime_number[pidx]; + + /* allocate the new hash table and fill it in with the old */ + newHash = (_PRWaiterHash*)PR_CALLOC( + sizeof(_PRWaiterHash) + (length * sizeof(PRRecvWait*))); + if (NULL == newHash) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return _prmw_error; + } + + newHash->length = length; + retry = PR_FALSE; + for (desc = &oldHash->recv_wait; + newHash->count < oldHash->count; ++desc) + { + PR_ASSERT(desc < &oldHash->recv_wait + oldHash->length); + if (NULL != *desc) + { + hrv = MW_AddHashInternal(*desc, newHash); + PR_ASSERT(_prmw_error != hrv); + if (_prmw_success != hrv) + { + PR_DELETE(newHash); + retry = PR_TRUE; + break; + } + } + } + if (retry) continue; + + PR_DELETE(group->waiter); + group->waiter = newHash; + group->p_timestamp += 1; + return _prmw_success; + } + + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return _prmw_error; /* we're hosed */ +} /* MW_ExpandHashInternal */ + +#ifndef WINNT +static void _MW_DoneInternal( + PRWaitGroup *group, PRRecvWait **waiter, PRMWStatus outcome) +{ + /* + ** Add this receive wait object to the list of finished I/O + ** operations for this particular group. If there are other + ** threads waiting on the group, notify one. If not, arrange + ** for this thread to return. + */ + +#if 0 + printf("Removing 0x%x->0x%x\n", *waiter, (*waiter)->fd); +#endif + (*waiter)->outcome = outcome; + PR_APPEND_LINK(&((*waiter)->internal), &group->io_ready); + PR_NotifyCondVar(group->io_complete); + PR_ASSERT(0 != group->waiter->count); + group->waiter->count -= 1; + *waiter = NULL; +} /* _MW_DoneInternal */ +#endif /* WINNT */ + +static PRRecvWait **_MW_LookupInternal(PRWaitGroup *group, PRFileDesc *fd) +{ + /* + ** Find the receive wait object corresponding to the file descriptor. + ** Only search the wait group specified. + */ + PRRecvWait **desc; + PRIntn rehash = _MW_REHASH_MAX; + _PRWaiterHash *hash = group->waiter; + PRUintn hidx = _MW_HASH(fd, hash->length); + PRUintn hoffset = 0; + + while (rehash-- > 0) + { + desc = (&hash->recv_wait) + hidx; + if ((*desc != NULL) && ((*desc)->fd == fd)) return desc; + if (0 == hoffset) + { + hoffset = _MW_HASH2(fd, hash->length); + PR_ASSERT(0 != hoffset); + } + hidx = (hidx + hoffset) % (hash->length); + } + return NULL; +} /* _MW_LookupInternal */ + +#ifndef WINNT +static PRStatus _MW_PollInternal(PRWaitGroup *group) +{ + PRRecvWait **waiter; + PRStatus rv = PR_FAILURE; + PRInt32 count, count_ready; + PRIntervalTime polling_interval; + + group->poller = PR_GetCurrentThread(); + + while (PR_TRUE) + { + PRIntervalTime now, since_last_poll; + PRPollDesc *poll_list; + + while (0 == group->waiter->count) + { + PRStatus st; + st = PR_WaitCondVar(group->new_business, PR_INTERVAL_NO_TIMEOUT); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (_MW_ABORTED(st)) goto aborted; + } + + /* + ** There's something to do. See if our existing polling list + ** is large enough for what we have to do? + */ + + while (group->polling_count < group->waiter->count) + { + PRUint32 old_count = group->waiter->count; + PRUint32 new_count = PR_ROUNDUP(old_count, _PR_POLL_COUNT_FUDGE); + PRSize new_size = sizeof(PRPollDesc) * new_count; + PRPollDesc *old_polling_list = group->polling_list; + + PR_Unlock(group->ml); + poll_list = (PRPollDesc*)PR_CALLOC(new_size); + if (NULL == poll_list) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + PR_Lock(group->ml); + goto failed_alloc; + } + if (NULL != old_polling_list) + PR_DELETE(old_polling_list); + PR_Lock(group->ml); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + group->polling_list = poll_list; + group->polling_count = new_count; + } + + now = PR_IntervalNow(); + polling_interval = max_polling_interval; + since_last_poll = now - group->last_poll; + + waiter = &group->waiter->recv_wait; + poll_list = group->polling_list; + for (count = 0; count < group->waiter->count; ++waiter) + { + PR_ASSERT(waiter < &group->waiter->recv_wait + + group->waiter->length); + if (NULL != *waiter) /* a live one! */ + { + if ((PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) + && (since_last_poll >= (*waiter)->timeout)) + _MW_DoneInternal(group, waiter, PR_MW_TIMEOUT); + else + { + if (PR_INTERVAL_NO_TIMEOUT != (*waiter)->timeout) + { + (*waiter)->timeout -= since_last_poll; + if ((*waiter)->timeout < polling_interval) + polling_interval = (*waiter)->timeout; + } + PR_ASSERT(poll_list < group->polling_list + + group->polling_count); + poll_list->fd = (*waiter)->fd; + poll_list->in_flags = PR_POLL_READ; + poll_list->out_flags = 0; +#if 0 + printf( + "Polling 0x%x[%d]: [fd: 0x%x, tmo: %u]\n", + poll_list, count, poll_list->fd, (*waiter)->timeout); +#endif + poll_list += 1; + count += 1; + } + } + } + + PR_ASSERT(count == group->waiter->count); + + /* + ** If there are no more threads waiting for completion, + ** we need to return. + */ + if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) + && (1 == group->waiting_threads)) break; + + if (0 == count) continue; /* wait for new business */ + + group->last_poll = now; + + PR_Unlock(group->ml); + + count_ready = PR_Poll(group->polling_list, count, polling_interval); + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (-1 == count_ready) + { + goto failed_poll; /* that's a shame */ + } + else if (0 < count_ready) + { + for (poll_list = group->polling_list; count > 0; + poll_list++, count--) + { + PR_ASSERT( + poll_list < group->polling_list + group->polling_count); + if (poll_list->out_flags != 0) + { + waiter = _MW_LookupInternal(group, poll_list->fd); + /* + ** If 'waiter' is NULL, that means the wait receive + ** descriptor has been canceled. + */ + if (NULL != waiter) + _MW_DoneInternal(group, waiter, PR_MW_SUCCESS); + } + } + } + /* + ** If there are no more threads waiting for completion, + ** we need to return. + ** This thread was "borrowed" to do the polling, but it really + ** belongs to the client. + */ + if ((!PR_CLIST_IS_EMPTY(&group->io_ready)) + && (1 == group->waiting_threads)) break; + } + + rv = PR_SUCCESS; + +aborted: +failed_poll: +failed_alloc: + group->poller = NULL; /* we were that, not we ain't */ + if ((_prmw_running == group->state) && (group->waiting_threads > 1)) + { + /* Wake up one thread to become the new poller. */ + PR_NotifyCondVar(group->io_complete); + } + return rv; /* we return with the lock held */ +} /* _MW_PollInternal */ +#endif /* !WINNT */ + +static PRMWGroupState MW_TestForShutdownInternal(PRWaitGroup *group) +{ + PRMWGroupState rv = group->state; + /* + ** Looking at the group's fields is safe because + ** once the group's state is no longer running, it + ** cannot revert and there is a safe check on entry + ** to make sure no more threads are made to wait. + */ + if ((_prmw_stopping == rv) + && (0 == group->waiting_threads)) + { + rv = group->state = _prmw_stopped; + PR_NotifyCondVar(group->mw_manage); + } + return rv; +} /* MW_TestForShutdownInternal */ + +#ifndef WINNT +static void _MW_InitialRecv(PRCList *io_ready) +{ + PRRecvWait *desc = (PRRecvWait*)io_ready; + if ((NULL == desc->buffer.start) + || (0 == desc->buffer.length)) + desc->bytesRecv = 0; + else + { + desc->bytesRecv = desc->fd->methods->recv( + desc->fd, desc->buffer.start, + desc->buffer.length, 0, desc->timeout); + if (desc->bytesRecv < 0) /* SetError should already be there */ + desc->outcome = PR_MW_FAILURE; + } +} /* _MW_InitialRecv */ +#endif + +#ifdef WINNT +static void NT_TimeProc(void *arg) +{ + _MDOverlapped *overlapped = (_MDOverlapped *)arg; + PRRecvWait *desc = overlapped->data.mw.desc; + PRFileDesc *bottom; + + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_TIMEOUT, (PVOID)PR_MW_PENDING) != (PVOID)PR_MW_PENDING) + { + /* This wait recv descriptor has already completed. */ + return; + } + + /* close the osfd to abort the outstanding async io request */ + /* $$$$ + ** Little late to be checking if NSPR's on the bottom of stack, + ** but if we don't check, we can't assert that the private data + ** is what we think it is. + ** $$$$ + */ + bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL != bottom) /* now what!?!?! */ + { + bottom->secret->state = _PR_FILEDESC_CLOSED; + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); + PR_ASSERT(!"What shall I do?"); + } + } + return; +} /* NT_TimeProc */ + +static PRStatus NT_HashRemove(PRWaitGroup *group, PRFileDesc *fd) +{ + PRRecvWait **waiter; + + _PR_MD_LOCK(&group->mdlock); + waiter = _MW_LookupInternal(group, fd); + if (NULL != waiter) + { + group->waiter->count -= 1; + *waiter = NULL; + } + _PR_MD_UNLOCK(&group->mdlock); + return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE; +} + +PRStatus NT_HashRemoveInternal(PRWaitGroup *group, PRFileDesc *fd) +{ + PRRecvWait **waiter; + + waiter = _MW_LookupInternal(group, fd); + if (NULL != waiter) + { + group->waiter->count -= 1; + *waiter = NULL; + } + return (NULL != waiter) ? PR_SUCCESS : PR_FAILURE; +} +#endif /* WINNT */ + +/******************************************************************/ +/******************************************************************/ +/********************** The public API portion ********************/ +/******************************************************************/ +/******************************************************************/ +PR_IMPLEMENT(PRStatus) PR_AddWaitFileDesc( + PRWaitGroup *group, PRRecvWait *desc) +{ + _PR_HashStory hrv; + PRStatus rv = PR_FAILURE; +#ifdef WINNT + _MDOverlapped *overlapped; + HANDLE hFile; + BOOL bResult; + DWORD dwError; + PRFileDesc *bottom; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if ((NULL == group) && (NULL == (group = MW_Init2()))) + { + return rv; + } + + PR_ASSERT(NULL != desc->fd); + + desc->outcome = PR_MW_PENDING; /* nice, well known value */ + desc->bytesRecv = 0; /* likewise, though this value is ambiguious */ + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + /* Not allowed to add after cancelling the group */ + desc->outcome = PR_MW_INTERRUPT; + PR_SetError(PR_INVALID_STATE_ERROR, 0); + PR_Unlock(group->ml); + return rv; + } + +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); +#endif + + /* + ** If the waiter count is zero at this point, there's no telling + ** how long we've been idle. Therefore, initialize the beginning + ** of the timing interval. As long as the list doesn't go empty, + ** it will maintain itself. + */ + if (0 == group->waiter->count) + group->last_poll = PR_IntervalNow(); + + do + { + hrv = MW_AddHashInternal(desc, group->waiter); + if (_prmw_rehash != hrv) break; + hrv = MW_ExpandHashInternal(group); /* gruesome */ + if (_prmw_success != hrv) break; + } while (PR_TRUE); + +#ifdef WINNT + _PR_MD_UNLOCK(&group->mdlock); +#endif + + PR_NotifyCondVar(group->new_business); /* tell the world */ + rv = (_prmw_success == hrv) ? PR_SUCCESS : PR_FAILURE; + PR_Unlock(group->ml); + +#ifdef WINNT + overlapped = PR_NEWZAP(_MDOverlapped); + if (NULL == overlapped) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + NT_HashRemove(group, desc->fd); + return rv; + } + overlapped->ioModel = _MD_MultiWaitIO; + overlapped->data.mw.desc = desc; + overlapped->data.mw.group = group; + if (desc->timeout != PR_INTERVAL_NO_TIMEOUT) + { + overlapped->data.mw.timer = CreateTimer( + desc->timeout, + NT_TimeProc, + overlapped); + if (0 == overlapped->data.mw.timer) + { + NT_HashRemove(group, desc->fd); + PR_DELETE(overlapped); + /* + * XXX It appears that a maximum of 16 timer events can + * be outstanding. GetLastError() returns 0 when I try it. + */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, GetLastError()); + return PR_FAILURE; + } + } + + /* Reach to the bottom layer to get the OS fd */ + bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + hFile = (HANDLE)bottom->secret->md.osfd; + if (!bottom->secret->md.io_model_committed) + { + PRInt32 st; + st = _md_Associate(hFile); + PR_ASSERT(0 != st); + bottom->secret->md.io_model_committed = PR_TRUE; + } + bResult = ReadFile(hFile, + desc->buffer.start, + (DWORD)desc->buffer.length, + NULL, + &overlapped->overlapped); + if (FALSE == bResult && (dwError = GetLastError()) != ERROR_IO_PENDING) + { + if (desc->timeout != PR_INTERVAL_NO_TIMEOUT) + { + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_FAILURE, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) + { + CancelTimer(overlapped->data.mw.timer); + } + NT_HashRemove(group, desc->fd); + PR_DELETE(overlapped); + } + _PR_MD_MAP_READ_ERROR(dwError); + rv = PR_FAILURE; + } +#endif + + return rv; +} /* PR_AddWaitFileDesc */ + +PR_IMPLEMENT(PRRecvWait*) PR_WaitRecvReady(PRWaitGroup *group) +{ + PRCList *io_ready = NULL; +#ifdef WINNT + PRThread *me = _PR_MD_CURRENT_THREAD(); + _MDOverlapped *overlapped; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if ((NULL == group) && (NULL == (group = MW_Init2()))) goto failed_init; + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto invalid_state; + } + + group->waiting_threads += 1; /* the polling thread is counted */ + +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); + while (PR_CLIST_IS_EMPTY(&group->io_ready)) + { + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + PR_APPEND_LINK(&me->waitQLinks, &group->wait_list); + if (!_PR_IS_NATIVE_THREAD(me)) + { + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT); + _PR_SLEEPQ_UNLOCK(me->cpu); + } + _PR_THREAD_UNLOCK(me); + _PR_MD_UNLOCK(&group->mdlock); + PR_Unlock(group->ml); + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + me->state = _PR_RUNNING; + PR_Lock(group->ml); + _PR_MD_LOCK(&group->mdlock); + if (_PR_PENDING_INTERRUPT(me)) { + PR_REMOVE_LINK(&me->waitQLinks); + _PR_MD_UNLOCK(&group->mdlock); + me->flags &= ~_PR_INTERRUPT; + me->io_suspended = PR_FALSE; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + goto aborted; + } + } + io_ready = PR_LIST_HEAD(&group->io_ready); + PR_ASSERT(io_ready != NULL); + PR_REMOVE_LINK(io_ready); + _PR_MD_UNLOCK(&group->mdlock); + overlapped = (_MDOverlapped *) + ((char *)io_ready - offsetof(_MDOverlapped, data)); + io_ready = &overlapped->data.mw.desc->internal; +#else + do + { + /* + ** If the I/O ready list isn't empty, have this thread + ** return with the first receive wait object that's available. + */ + if (PR_CLIST_IS_EMPTY(&group->io_ready)) + { + /* + ** Is there a polling thread yet? If not, grab this thread + ** and use it. + */ + if (NULL == group->poller) + { + /* + ** This thread will stay do polling until it becomes the only one + ** left to service a completion. Then it will return and there will + ** be none left to actually poll or to run completions. + ** + ** The polling function should only return w/ failure or + ** with some I/O ready. + */ + if (PR_FAILURE == _MW_PollInternal(group)) goto failed_poll; + } + else + { + /* + ** There are four reasons a thread can be awakened from + ** a wait on the io_complete condition variable. + ** 1. Some I/O has completed, i.e., the io_ready list + ** is nonempty. + ** 2. The wait group is canceled. + ** 3. The thread is interrupted. + ** 4. The current polling thread has to leave and needs + ** a replacement. + ** The logic to find a new polling thread is made more + ** complicated by all the other possible events. + ** I tried my best to write the logic clearly, but + ** it is still full of if's with continue and goto. + */ + PRStatus st; + do + { + st = PR_WaitCondVar(group->io_complete, PR_INTERVAL_NO_TIMEOUT); + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + goto aborted; + } + if (_MW_ABORTED(st) || (NULL == group->poller)) break; + } while (PR_CLIST_IS_EMPTY(&group->io_ready)); + + /* + ** The thread is interrupted and has to leave. It might + ** have also been awakened to process ready i/o or be the + ** new poller. To be safe, if either condition is true, + ** we awaken another thread to take its place. + */ + if (_MW_ABORTED(st)) + { + if ((NULL == group->poller + || !PR_CLIST_IS_EMPTY(&group->io_ready)) + && group->waiting_threads > 1) + PR_NotifyCondVar(group->io_complete); + goto aborted; + } + + /* + ** A new poller is needed, but can I be the new poller? + ** If there is no i/o ready, sure. But if there is any + ** i/o ready, it has a higher priority. I want to + ** process the ready i/o first and wake up another + ** thread to be the new poller. + */ + if (NULL == group->poller) + { + if (PR_CLIST_IS_EMPTY(&group->io_ready)) + continue; + if (group->waiting_threads > 1) + PR_NotifyCondVar(group->io_complete); + } + } + PR_ASSERT(!PR_CLIST_IS_EMPTY(&group->io_ready)); + } + io_ready = PR_LIST_HEAD(&group->io_ready); + PR_NotifyCondVar(group->io_taken); + PR_ASSERT(io_ready != NULL); + PR_REMOVE_LINK(io_ready); + } while (NULL == io_ready); + +failed_poll: + +#endif + +aborted: + + group->waiting_threads -= 1; +invalid_state: + (void)MW_TestForShutdownInternal(group); + PR_Unlock(group->ml); + +failed_init: + if (NULL != io_ready) + { + /* If the operation failed, record the reason why */ + switch (((PRRecvWait*)io_ready)->outcome) + { + case PR_MW_PENDING: + PR_ASSERT(0); + break; + case PR_MW_SUCCESS: +#ifndef WINNT + _MW_InitialRecv(io_ready); +#endif + break; +#ifdef WINNT + case PR_MW_FAILURE: + _PR_MD_MAP_READ_ERROR(overlapped->data.mw.error); + break; +#endif + case PR_MW_TIMEOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_MW_INTERRUPT: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + break; + default: break; + } +#ifdef WINNT + if (NULL != overlapped->data.mw.timer) + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + != overlapped->data.mw.desc->timeout); + CancelTimer(overlapped->data.mw.timer); + } + else + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + == overlapped->data.mw.desc->timeout); + } + PR_DELETE(overlapped); +#endif + } + return (PRRecvWait*)io_ready; +} /* PR_WaitRecvReady */ + +PR_IMPLEMENT(PRStatus) PR_CancelWaitFileDesc(PRWaitGroup *group, PRRecvWait *desc) +{ +#if !defined(WINNT) + PRRecvWait **recv_wait; +#endif + PRStatus rv = PR_SUCCESS; + if (NULL == group) group = mw_state->group; + PR_ASSERT(NULL != group); + if (NULL == group) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + PR_Lock(group->ml); + + if (_prmw_running != group->state) + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + rv = PR_FAILURE; + goto unlock; + } + +#ifdef WINNT + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)PR_MW_INTERRUPT, (PVOID)PR_MW_PENDING) == (PVOID)PR_MW_PENDING) + { + PRFileDesc *bottom = PR_GetIdentitiesLayer(desc->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + goto unlock; + } + bottom->secret->state = _PR_FILEDESC_CLOSED; +#if 0 + fprintf(stderr, "cancel wait recv: closing socket\n"); +#endif + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError()); + exit(1); + } + } +#else + if (NULL != (recv_wait = _MW_LookupInternal(group, desc->fd))) + { + /* it was in the wait table */ + _MW_DoneInternal(group, recv_wait, PR_MW_INTERRUPT); + goto unlock; + } + if (!PR_CLIST_IS_EMPTY(&group->io_ready)) + { + /* is it already complete? */ + PRCList *head = PR_LIST_HEAD(&group->io_ready); + do + { + PRRecvWait *done = (PRRecvWait*)head; + if (done == desc) goto unlock; + head = PR_NEXT_LINK(head); + } while (head != &group->io_ready); + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + +#endif +unlock: + PR_Unlock(group->ml); + return rv; +} /* PR_CancelWaitFileDesc */ + +PR_IMPLEMENT(PRRecvWait*) PR_CancelWaitGroup(PRWaitGroup *group) +{ + PRRecvWait **desc; + PRRecvWait *recv_wait = NULL; +#ifdef WINNT + _MDOverlapped *overlapped; + PRRecvWait **end; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#endif + + if (NULL == group) group = mw_state->group; + PR_ASSERT(NULL != group); + if (NULL == group) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + PR_Lock(group->ml); + if (_prmw_stopped != group->state) + { + if (_prmw_running == group->state) + group->state = _prmw_stopping; /* so nothing new comes in */ + if (0 == group->waiting_threads) /* is there anybody else? */ + group->state = _prmw_stopped; /* we can stop right now */ + else + { + PR_NotifyAllCondVar(group->new_business); + PR_NotifyAllCondVar(group->io_complete); + } + while (_prmw_stopped != group->state) + (void)PR_WaitCondVar(group->mw_manage, PR_INTERVAL_NO_TIMEOUT); + } + +#ifdef WINNT + _PR_MD_LOCK(&group->mdlock); +#endif + /* make all the existing descriptors look done/interrupted */ +#ifdef WINNT + end = &group->waiter->recv_wait + group->waiter->length; + for (desc = &group->waiter->recv_wait; desc < end; ++desc) + { + if (NULL != *desc) + { + if (InterlockedCompareExchange((PVOID *)&(*desc)->outcome, + (PVOID)PR_MW_INTERRUPT, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) + { + PRFileDesc *bottom = PR_GetIdentitiesLayer( + (*desc)->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + goto invalid_arg; + } + bottom->secret->state = _PR_FILEDESC_CLOSED; +#if 0 + fprintf(stderr, "cancel wait group: closing socket\n"); +#endif + if (closesocket(bottom->secret->md.osfd) == SOCKET_ERROR) + { + fprintf(stderr, "closesocket failed: %d\n", + WSAGetLastError()); + exit(1); + } + } + } + } + while (group->waiter->count > 0) + { + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + PR_APPEND_LINK(&me->waitQLinks, &group->wait_list); + if (!_PR_IS_NATIVE_THREAD(me)) + { + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, PR_INTERVAL_NO_TIMEOUT); + _PR_SLEEPQ_UNLOCK(me->cpu); + } + _PR_THREAD_UNLOCK(me); + _PR_MD_UNLOCK(&group->mdlock); + PR_Unlock(group->ml); + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + me->state = _PR_RUNNING; + PR_Lock(group->ml); + _PR_MD_LOCK(&group->mdlock); + } +#else + for (desc = &group->waiter->recv_wait; group->waiter->count > 0; ++desc) + { + PR_ASSERT(desc < &group->waiter->recv_wait + group->waiter->length); + if (NULL != *desc) + _MW_DoneInternal(group, desc, PR_MW_INTERRUPT); + } +#endif + + /* take first element of finished list and return it or NULL */ + if (PR_CLIST_IS_EMPTY(&group->io_ready)) + PR_SetError(PR_GROUP_EMPTY_ERROR, 0); + else + { + PRCList *head = PR_LIST_HEAD(&group->io_ready); + PR_REMOVE_AND_INIT_LINK(head); +#ifdef WINNT + overlapped = (_MDOverlapped *) + ((char *)head - offsetof(_MDOverlapped, data)); + head = &overlapped->data.mw.desc->internal; + if (NULL != overlapped->data.mw.timer) + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + != overlapped->data.mw.desc->timeout); + CancelTimer(overlapped->data.mw.timer); + } + else + { + PR_ASSERT(PR_INTERVAL_NO_TIMEOUT + == overlapped->data.mw.desc->timeout); + } + PR_DELETE(overlapped); +#endif + recv_wait = (PRRecvWait*)head; + } +#ifdef WINNT +invalid_arg: + _PR_MD_UNLOCK(&group->mdlock); +#endif + PR_Unlock(group->ml); + + return recv_wait; +} /* PR_CancelWaitGroup */ + +PR_IMPLEMENT(PRWaitGroup*) PR_CreateWaitGroup(PRInt32 size /* ignored */) +{ +#ifdef XP_MAC +#pragma unused (size) +#endif + PRWaitGroup *wg; + + if (NULL == (wg = PR_NEWZAP(PRWaitGroup))) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto failed; + } + /* the wait group itself */ + wg->ml = PR_NewLock(); + if (NULL == wg->ml) goto failed_lock; + wg->io_taken = PR_NewCondVar(wg->ml); + if (NULL == wg->io_taken) goto failed_cvar0; + wg->io_complete = PR_NewCondVar(wg->ml); + if (NULL == wg->io_complete) goto failed_cvar1; + wg->new_business = PR_NewCondVar(wg->ml); + if (NULL == wg->new_business) goto failed_cvar2; + wg->mw_manage = PR_NewCondVar(wg->ml); + if (NULL == wg->mw_manage) goto failed_cvar3; + + PR_INIT_CLIST(&wg->group_link); + PR_INIT_CLIST(&wg->io_ready); + + /* the waiters sequence */ + wg->waiter = (_PRWaiterHash*)PR_CALLOC( + sizeof(_PRWaiterHash) + + (_PR_DEFAULT_HASH_LENGTH * sizeof(PRRecvWait*))); + if (NULL == wg->waiter) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto failed_waiter; + } + wg->waiter->count = 0; + wg->waiter->length = _PR_DEFAULT_HASH_LENGTH; + +#ifdef WINNT + _PR_MD_NEW_LOCK(&wg->mdlock); + PR_INIT_CLIST(&wg->wait_list); +#endif /* WINNT */ + + PR_Lock(mw_lock); + PR_APPEND_LINK(&wg->group_link, &mw_state->group_list); + PR_Unlock(mw_lock); + return wg; + +failed_waiter: + PR_DestroyCondVar(wg->mw_manage); +failed_cvar3: + PR_DestroyCondVar(wg->new_business); +failed_cvar2: + PR_DestroyCondVar(wg->io_complete); +failed_cvar1: + PR_DestroyCondVar(wg->io_taken); +failed_cvar0: + PR_DestroyLock(wg->ml); +failed_lock: + PR_DELETE(wg); + wg = NULL; + +failed: + return wg; +} /* MW_CreateWaitGroup */ + +PR_IMPLEMENT(PRStatus) PR_DestroyWaitGroup(PRWaitGroup *group) +{ + PRStatus rv = PR_SUCCESS; + if (NULL == group) group = mw_state->group; + PR_ASSERT(NULL != group); + if (NULL != group) + { + PR_Lock(group->ml); + if ((group->waiting_threads == 0) + && (group->waiter->count == 0) + && PR_CLIST_IS_EMPTY(&group->io_ready)) + { + group->state = _prmw_stopped; + } + else + { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + rv = PR_FAILURE; + } + PR_Unlock(group->ml); + if (PR_FAILURE == rv) return rv; + + PR_Lock(mw_lock); + PR_REMOVE_LINK(&group->group_link); + PR_Unlock(mw_lock); + +#ifdef WINNT + /* + * XXX make sure wait_list is empty and waiter is empty. + * These must be checked while holding mdlock. + */ + _PR_MD_FREE_LOCK(&group->mdlock); +#endif + + PR_DELETE(group->waiter); + PR_DELETE(group->polling_list); + PR_DestroyCondVar(group->mw_manage); + PR_DestroyCondVar(group->new_business); + PR_DestroyCondVar(group->io_complete); + PR_DestroyCondVar(group->io_taken); + PR_DestroyLock(group->ml); + if (group == mw_state->group) mw_state->group = NULL; + PR_DELETE(group); + } + else + { + /* The default wait group is not created yet. */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* PR_DestroyWaitGroup */ + +/********************************************************************** +*********************************************************************** +******************** Wait group enumerations ************************** +*********************************************************************** +**********************************************************************/ + +PR_IMPLEMENT(PRMWaitEnumerator*) PR_CreateMWaitEnumerator(PRWaitGroup *group) +{ + PRMWaitEnumerator *enumerator = PR_NEWZAP(PRMWaitEnumerator); + if (NULL == enumerator) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + enumerator->group = group; + enumerator->seal = _PR_ENUM_SEALED; + } + return enumerator; +} /* PR_CreateMWaitEnumerator */ + +PR_IMPLEMENT(PRStatus) PR_DestroyMWaitEnumerator(PRMWaitEnumerator* enumerator) +{ + PR_ASSERT(NULL != enumerator); + PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal); + if ((NULL == enumerator) || (_PR_ENUM_SEALED != enumerator->seal)) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + enumerator->seal = _PR_ENUM_UNSEALED; + PR_Free(enumerator); + return PR_SUCCESS; +} /* PR_DestroyMWaitEnumerator */ + +PR_IMPLEMENT(PRRecvWait*) PR_EnumerateWaitGroup( + PRMWaitEnumerator *enumerator, const PRRecvWait *previous) +{ + PRRecvWait *result = NULL; + + /* entry point sanity checking */ + PR_ASSERT(NULL != enumerator); + PR_ASSERT(_PR_ENUM_SEALED == enumerator->seal); + if ((NULL == enumerator) + || (_PR_ENUM_SEALED != enumerator->seal)) goto bad_argument; + + /* beginning of enumeration */ + if (NULL == previous) + { + if (NULL == enumerator->group) + { + enumerator->group = mw_state->group; + if (NULL == enumerator->group) + { + PR_SetError(PR_GROUP_EMPTY_ERROR, 0); + return NULL; + } + } + enumerator->waiter = &enumerator->group->waiter->recv_wait; + enumerator->p_timestamp = enumerator->group->p_timestamp; + enumerator->thread = PR_GetCurrentThread(); + enumerator->index = 0; + } + /* continuing an enumeration */ + else + { + PRThread *me = PR_GetCurrentThread(); + PR_ASSERT(me == enumerator->thread); + if (me != enumerator->thread) goto bad_argument; + + /* need to restart the enumeration */ + if (enumerator->p_timestamp != enumerator->group->p_timestamp) + return PR_EnumerateWaitGroup(enumerator, NULL); + } + + /* actually progress the enumeration */ +#if defined(WINNT) + _PR_MD_LOCK(&enumerator->group->mdlock); +#else + PR_Lock(enumerator->group->ml); +#endif + while (enumerator->index++ < enumerator->group->waiter->length) + { + if (NULL != (result = *(enumerator->waiter)++)) break; + } +#if defined(WINNT) + _PR_MD_UNLOCK(&enumerator->group->mdlock); +#else + PR_Unlock(enumerator->group->ml); +#endif + + return result; /* what we live for */ + +bad_argument: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; /* probably ambiguous */ +} /* PR_EnumerateWaitGroup */ + +/* prmwait.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prpolevt.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prpolevt.c new file mode 100644 index 00000000..de5f991c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prpolevt.c @@ -0,0 +1,530 @@ +/* -*- 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 ***** */ + +/* + ********************************************************************* + * + * Pollable events + * + * Pollable events are implemented using layered I/O. The only + * I/O methods that are implemented for pollable events are poll + * and close. No other methods can be invoked on a pollable + * event. + * + * A pipe or socket pair is created and the pollable event layer + * is pushed onto the read end. A pointer to the write end is + * saved in the PRFilePrivate structure of the pollable event. + * + ********************************************************************* + */ + +#include "prinit.h" +#include "prio.h" +#include "prmem.h" +#include "prerror.h" +#include "prlog.h" + +#ifdef VMS + +/* + * On OpenVMS we use an event flag instead of a pipe or a socket since + * event flags are much more efficient on OpenVMS. + */ +#include "pprio.h" +#include +#include +#include + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + unsigned int status; + int flag = -1; + PRFileDesc *event; + + /* + ** Allocate an event flag and clear it. + */ + status = lib$get_ef(&flag); + if ((!$VMS_STATUS_SUCCESS(status)) || (flag == -1)) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, status); + return NULL; + } + sys$clref(flag); + + /* + ** Give NSPR the event flag's negative value. We do this because our + ** select interprets a negative fd as an event flag rather than a + ** regular file fd. + */ + event = PR_CreateSocketPollFd(-flag); + if (NULL == event) { + lib$free_ef(&flag); + return NULL; + } + + return event; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + int flag = -PR_FileDesc2NativeHandle(event); + PR_DestroySocketPollFd(event); + lib$free_ef(&flag); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + /* + ** Just set the event flag. + */ + unsigned int status; + status = sys$setef(-PR_FileDesc2NativeHandle(event)); + if (!$VMS_STATUS_SUCCESS(status)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, status); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + /* + ** Just clear the event flag. + */ + unsigned int status; + status = sys$clref(-PR_FileDesc2NativeHandle(event)); + if (!$VMS_STATUS_SUCCESS(status)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, status); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#elif defined (XP_MAC) + +#include "primpl.h" + +/* + * On Mac, local sockets cannot be used, because the networking stack + * closes them when the machine goes to sleep. Instead, we'll use a simple + * flag. + */ + + +/* + * PRFilePrivate structure for the NSPR pollable events layer + */ +typedef struct PRPollableDesc { + PRBool gotEvent; + PRThread *pollingThread; +} PRPollableDesc; + +static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd); + +static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); + +static PRIOMethods _pr_mac_polevt_methods = { + PR_DESC_LAYERED, + _pr_MacPolEvtClose, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + _pr_MacPolEvtPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRDescIdentity _pr_mac_polevt_id; +static PRCallOnceType _pr_mac_polevt_once_control; +static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void); + +static PRInt16 PR_CALLBACK _pr_MacPolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret; + PR_ASSERT(pollDesc); + + // set the current thread so that we can wake up the poll thread + pollDesc->pollingThread = PR_GetCurrentThread(); + + if ((in_flags & PR_POLL_READ) && pollDesc->gotEvent) + *out_flags = PR_POLL_READ; + else + *out_flags = 0; + return pollDesc->gotEvent ? 1 : 0; +} + +static PRStatus PR_CALLBACK _pr_MacPolEvtInit(void) +{ + _pr_mac_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); + if (PR_INVALID_IO_LAYER == _pr_mac_polevt_id) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK _pr_MacPolEvtClose(PRFileDesc *fd) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)fd->secret; + PR_ASSERT(NULL == fd->higher && NULL == fd->lower); + PR_ASSERT(pollDesc); + PR_DELETE(pollDesc); + fd->dtor(fd); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + PRFileDesc *event; + PRPollableDesc *pollDesc; + + if (PR_CallOnce(&_pr_mac_polevt_once_control, _pr_MacPolEvtInit) == PR_FAILURE) { + return NULL; + } + + event = PR_CreateIOLayerStub(_pr_mac_polevt_id, &_pr_mac_polevt_methods); + if (NULL == event) { + return NULL; + } + + /* + ** Allocate an event flag and clear it. + */ + pollDesc = PR_NEW(PRPollableDesc); + if (!pollDesc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + pollDesc->gotEvent = PR_FALSE; + pollDesc->pollingThread = NULL; + + event->secret = (PRFilePrivate*)pollDesc; + return event; + +errorExit: + + if (event) { + PR_DELETE(event->secret); + event->dtor(event); + } + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + return PR_Close(event); +} + +/* from macsockotpt.c. I wish there was a cleaner way */ +extern void WakeUpNotifiedThread(PRThread *thread, OTResult result); + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret; + PR_ASSERT(pollDesc); + PR_ASSERT(pollDesc->pollingThread->state != _PR_DEAD_STATE); + + if (pollDesc->pollingThread->state == _PR_DEAD_STATE) + return PR_FAILURE; + + pollDesc->gotEvent = PR_TRUE; + + if (pollDesc->pollingThread) + WakeUpNotifiedThread(pollDesc->pollingThread, noErr); + + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + PRPollableDesc *pollDesc = (PRPollableDesc *)event->secret; + PRStatus status; + PR_ASSERT(pollDesc); + + /* + FIXME: Danger Will Robinson! + + The current implementation of PR_WaitForPollableEvent is somewhat + bogus; it makes the assumption that, in Mozilla, this will only + ever be called when PR_Poll has returned, telling us that an + event has been set. + */ + + PR_ASSERT(pollDesc->gotEvent); + + status = (pollDesc->gotEvent) ? PR_SUCCESS : PR_FAILURE; + pollDesc->gotEvent = PR_FALSE; + return status; +} + +#else /* VMS */ + +/* + * These internal functions are declared in primpl.h, + * but we can't include primpl.h because the definition + * of struct PRFilePrivate in this file (for the pollable + * event layer) will conflict with the definition of + * struct PRFilePrivate in primpl.h (for the NSPR layer). + */ +extern PRIntn _PR_InvalidInt(void); +extern PRInt64 _PR_InvalidInt64(void); +extern PRStatus _PR_InvalidStatus(void); +extern PRFileDesc *_PR_InvalidDesc(void); + +/* + * PRFilePrivate structure for the NSPR pollable events layer + */ +struct PRFilePrivate { + PRFileDesc *writeEnd; /* the write end of the pipe/socketpair */ +}; + +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd); + +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); + +static PRIOMethods _pr_polevt_methods = { + PR_DESC_LAYERED, + _pr_PolEvtClose, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + _pr_PolEvtPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRDescIdentity _pr_polevt_id; +static PRCallOnceType _pr_polevt_once_control; +static PRStatus PR_CALLBACK _pr_PolEvtInit(void); + +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); +} + +static PRStatus PR_CALLBACK _pr_PolEvtInit(void) +{ + _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); + if (PR_INVALID_IO_LAYER == _pr_polevt_id) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#if !defined(XP_UNIX) +#define USE_TCP_SOCKETPAIR +#endif + +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) +{ + PRFileDesc *event; + PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */ +#ifdef USE_TCP_SOCKETPAIR + PRSocketOptionData socket_opt; + PRStatus rv; +#endif + + fd[0] = fd[1] = NULL; + + if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) { + return NULL; + } + + event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods); + if (NULL == event) { + goto errorExit; + } + event->secret = PR_NEW(PRFilePrivate); + if (event->secret == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + +#ifndef USE_TCP_SOCKETPAIR + if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) { + fd[0] = fd[1] = NULL; + goto errorExit; + } +#else + if (PR_NewTCPSocketPair(fd) == PR_FAILURE) { + fd[0] = fd[1] = NULL; + goto errorExit; + } + /* + * set the TCP_NODELAY option to reduce notification latency + */ + socket_opt.option = PR_SockOpt_NoDelay; + socket_opt.value.no_delay = PR_TRUE; + rv = PR_SetSocketOption(fd[1], &socket_opt); + PR_ASSERT(PR_SUCCESS == rv); +#endif + + event->secret->writeEnd = fd[1]; + if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) { + goto errorExit; + } + + return fd[0]; + +errorExit: + if (fd[0]) { + PR_Close(fd[0]); + PR_Close(fd[1]); + } + if (event) { + PR_DELETE(event->secret); + event->dtor(event); + } + return NULL; +} + +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd) +{ + PRFileDesc *event; + + event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); + PR_ASSERT(NULL == event->higher && NULL == event->lower); + PR_Close(fd); + PR_Close(event->secret->writeEnd); + PR_DELETE(event->secret); + event->dtor(event); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) +{ + return PR_Close(event); +} + +static const char magicChar = '\x38'; + +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) +{ + if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) +{ + char buf[1024]; + PRInt32 nBytes; +#ifdef DEBUG + PRIntn i; +#endif + + nBytes = PR_Read(event->lower, buf, sizeof(buf)); + if (nBytes == -1) { + return PR_FAILURE; + } + +#ifdef DEBUG + /* + * Make sure people do not write to the pollable event fd + * directly. + */ + for (i = 0; i < nBytes; i++) { + PR_ASSERT(buf[i] == magicChar); + } +#endif + + return PR_SUCCESS; +} + +#endif /* VMS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prprf.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prprf.c new file mode 100644 index 00000000..c68e7382 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prprf.c @@ -0,0 +1,1229 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 ***** */ + +/* +** Portable safe sprintf code. +** +** Author: Kipp E.B. Hickman +*/ +#include +#include +#include +#include +#include "primpl.h" +#include "prprf.h" +#include "prlong.h" +#include "prlog.h" +#include "prmem.h" + +/* +** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it) +*/ + +/* +** XXX This needs to be internationalized! +*/ + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len); + + char *base; + char *cur; + PRUint32 maxlen; + + int (*func)(void *arg, const char *sp, PRUint32 len); + void *arg; +}; + +/* +** Numbered Argument +*/ +struct NumArg { + int type; /* type of the numbered argument */ + union { /* the numbered argument */ + int i; + unsigned int ui; + PRInt32 i32; + PRUint32 ui32; + PRInt64 ll; + PRUint64 ull; + double d; + const char *s; + int *ip; + } u; +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgument array */ + + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_UNKNOWN 20 + +#define FLAG_LEFT 0x1 +#define FLAG_SIGNED 0x2 +#define FLAG_SPACED 0x4 +#define FLAG_ZEROS 0x8 +#define FLAG_NEG 0x10 + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const char *src, int srclen, int width, + int flags) +{ + char space = ' '; + int rv; + + width -= srclen; + if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */ + if (flags & FLAG_ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + + if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */ + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const char *src, int srclen, int width, + int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + char sign; + + if ((type & 1) == 0) { + if (flags & FLAG_NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & FLAG_SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & FLAG_SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + precwidth = prec - srclen; /* Need zero filling */ + cvtwidth += precwidth; + } + } + + if ((flags & FLAG_ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + zerowidth = width - cvtwidth; /* Zero filling */ + cvtwidth += zerowidth; + } + } + + if (flags & FLAG_LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, "0", 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix, + int type, int flags, const char *hexp) +{ + char cvtbuf[100]; + char *cvt; + int digits; + PRInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (LL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + LL_I2L(rad, radix); + cvt = cvtbuf + sizeof(cvtbuf); + digits = 0; + while (!LL_IS_ZERO(num)) { + PRInt32 digit; + PRInt64 quot, rem; + LL_UDIVMOD(", &rem, num, rad); + LL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +** +** XXX stop using snprintf to convert floating point +*/ +static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1) +{ + char fin[20]; + char fout[300]; + int amount = fmt1 - fmt0; + + if (amount <= 0 || amount >= sizeof(fin)) { + /* Totally bogus % command to snprintf. Just ignore it */ + return 0; + } + memcpy(fin, fmt0, amount); + fin[amount] = 0; + + /* Convert floating point using the native snprintf code */ +#ifdef DEBUG + { + const char *p = fin; + while (*p) { + PR_ASSERT(*p != 'L'); + p++; + } + } +#endif + memset(fout, 0, sizeof(fout)); + snprintf(fout, sizeof(fout), fin, d); + /* Explicitly null-terminate fout because on Windows snprintf doesn't + * append a null-terminator if the buffer is too small. */ + fout[sizeof(fout) - 1] = '\0'; + + return (*ss->stuff)(ss, fout, strlen(fout)); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *s, int width, int prec, + int flags) +{ + int slen; + + if (prec == 0) + return 0; + + /* Limit string length by precision value */ + slen = s ? strlen(s) : 6; + if (prec > 0) { + if (prec < slen) { + slen = prec; + } + } + + /* and away we go */ + return fill2(ss, s ? s : "(null)", slen, width, flags); +} + +/* +** BiuldArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray ) +{ + int number = 0, cn = 0, i; + const char* p; + char c; + struct NumArg* nas; + + + /* + ** first pass: + ** detemine how many legal % I have got, then allocate space + */ + + p = fmt; + *rv = 0; + i = 0; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) + continue; + if( ( c = *p++ ) == '%' ) /* skip %% case */ + continue; + + while( c != 0 ){ + if( c > '9' || c < '0' ){ + if( c == '$' ){ /* numbered argument case */ + if( i > 0 ){ + *rv = -1; + return NULL; + } + number++; + } else{ /* non-numbered argument case */ + if( number > 0 ){ + *rv = -1; + return NULL; + } + i = 1; + } + break; + } + + c = *p++; + } + } + + if( number == 0 ){ + return NULL; + } + + + if( number > NAS_DEFAULT_NUM ){ + nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) ); + if( !nas ){ + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for( i = 0; i < number; i++ ){ + nas[i].type = TYPE_UNKNOWN; + } + + + /* + ** second pass: + ** set nas[].type + */ + + p = fmt; + while( ( c = *p++ ) != 0 ){ + if( c != '%' ) continue; + c = *p++; + if( c == '%' ) continue; + + cn = 0; + while( c && c != '$' ){ /* should imporve error check later */ + cn = cn*10 + c - '0'; + c = *p++; + } + + if( !c || cn < 1 || cn > number ){ + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */ + cn--; + if( nas[cn].type != TYPE_UNKNOWN ) + continue; + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } + + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[ cn ].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(PRInt32)) { + nas[ cn ].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + nas[ cn ].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(PRIntn)) { + nas[ cn ].type = TYPE_UINTN; + } else { + nas[ cn ].type = TYPE_UNKNOWN; + } + break; + + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + PR_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + + case 's': + nas[ cn ].type = TYPE_STRING; + break; + + case 'n': + nas[ cn ].type = TYPE_INTSTR; + break; + + default: + PR_ASSERT(0); + nas[ cn ].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if( nas[ cn ].type == TYPE_UNKNOWN ){ + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + + if( *rv < 0 ){ + if( nas != nasArray ) + PR_DELETE( nas ); + return NULL; + } + + cn = 0; + while( cn < number ){ + if( nas[cn].type == TYPE_UNKNOWN ){ + cn++; + continue; + } + + switch( nas[cn].type ){ + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + nas[cn].u.i = va_arg( ap, int ); + break; + + case TYPE_UINTN: + nas[cn].u.ui = va_arg( ap, unsigned int ); + break; + + case TYPE_INT32: + nas[cn].u.i32 = va_arg( ap, PRInt32 ); + break; + + case TYPE_UINT32: + nas[cn].u.ui32 = va_arg( ap, PRUint32 ); + break; + + case TYPE_INT64: + nas[cn].u.ll = va_arg( ap, PRInt64 ); + break; + + case TYPE_UINT64: + nas[cn].u.ull = va_arg( ap, PRUint64 ); + break; + + case TYPE_STRING: + nas[cn].u.s = va_arg( ap, char* ); + break; + + case TYPE_INTSTR: + nas[cn].u.ip = va_arg( ap, int* ); + break; + + case TYPE_DOUBLE: + nas[cn].u.d = va_arg( ap, double ); + break; + + default: + if( nas != nasArray ) + PR_DELETE( nas ); + *rv = -1; + return NULL; + } + + cn++; + } + + + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const char *fmt, va_list ap) +{ + char c; + int flags, width, prec, radix, type; + union { + char ch; + int i; + long l; + PRInt64 ll; + double d; + const char *s; + int *ip; + } u; + const char *fmt0; + static char *hex = "0123456789abcdef"; + static char *HEX = "0123456789ABCDEF"; + char *hexp; + int rv, i; + struct NumArg* nas = NULL; + struct NumArg* nap; + struct NumArg nasArray[ NAS_DEFAULT_NUM ]; + char pattern[20]; + const char* dolPt = NULL; /* in "%4$.2f", dolPt will point to . */ + + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + + nas = BuildArgArray( fmt, ap, &rv, nasArray ); + if( rv < 0 ){ + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + PR_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if( nas != NULL ){ + /* the fmt contains the Numbered Arguments feature */ + i = 0; + while( c && c != '$' ){ /* should imporve error check later */ + i = ( i * 10 ) + ( c - '0' ); + c = *fmt++; + } + + if( nas[i-1].type == TYPE_UNKNOWN ){ + if( nas && ( nas != nasArray ) ) + PR_DELETE( nas ); + return -1; + } + + nap = &nas[i-1]; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ +#ifdef VBOX + /* this is not expected so just ignore this flags */ + while (c == '#') + c = *fmt++; +#endif + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= FLAG_LEFT; + if (c == '+') flags |= FLAG_SIGNED; + if (c == ' ') flags |= FLAG_SPACED; + if (c == '0') flags |= FLAG_ZEROS; + c = *fmt++; + } + if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED; + if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex; + switch (c) { + case 'd': case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX; + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = nas ? nap->u.i : va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = nas ? nap->u.i : va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int)); + goto do_long; + + case TYPE_INT32: + u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= FLAG_NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32)); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64); + if (!LL_GE_ZERO(u.ll)) { + LL_NEG(u.ll, u.ll); + flags |= FLAG_NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + u.d = nas ? nap->u.d : va_arg(ap, double); + if( nas != NULL ){ + i = fmt - dolPt; + if( i < sizeof( pattern ) ){ + pattern[0] = '%'; + memcpy( &pattern[1], dolPt, i ); + rv = cvt_f(ss, u.d, pattern, &pattern[i+1] ); + } + } else + rv = cvt_f(ss, u.d, fmt0, fmt); + + if (rv < 0) { + return rv; + } + break; + + case 'c': + u.ch = nas ? nap->u.i : va_arg(ap, int); + if ((flags & FLAG_LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + rv = (*ss->stuff)(ss, &u.ch, 1); + if (rv < 0) { + return rv; + } + if (flags & FLAG_LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, " ", 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(PRInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + PR_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + case 'S': + case 'E': + case 'G': + /* XXX not supported I suppose */ + PR_ASSERT(0); + break; +#endif + + case 's': + u.s = nas ? nap->u.s : va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = nas ? nap->u.ip : va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + PR_ASSERT(0); +#endif + rv = (*ss->stuff)(ss, "%", 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + rv = (*ss->stuff)(ss, "\0", 1); + + if( nas && ( nas != nasArray ) ){ + PR_DELETE( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + int rv; + + rv = (*ss->func)(ss->arg, sp, len); + if (rv < 0) { + return rv; + } + ss->maxlen += len; + return 0; +} + +PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg, + const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = PR_vsxprintf(func, arg, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg, + const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = FuncStuff; + ss.func = func; + ss.arg = arg; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + return (rv < 0) ? (PRUint32)-1 : ss.maxlen; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + ptrdiff_t off; + char *newbase; + PRUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (char*) PR_REALLOC(ss->base, newlen); + } else { + newbase = (char*) PR_MALLOC(newlen); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = PR_vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by PR_smprintf +*/ +PR_IMPLEMENT(void) PR_smprintf_free(char *mem) +{ + PR_DELETE(mem); +} + +PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len) +{ + PRUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = PR_vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt, + va_list ap) +{ + SprintfState ss; + PRUint32 n; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) + *(ss.cur - 1) = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...) +{ + va_list ap; + char *rv; + + va_start(ap, fmt); + rv = PR_vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prscanf.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prscanf.c new file mode 100644 index 00000000..6fad0f70 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prscanf.c @@ -0,0 +1,669 @@ +/* -*- 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 ***** */ + +/* + * Scan functions for NSPR types + * + * Author: Wan-Teh Chang + * + * Acknowledgment: The implementation is inspired by the source code + * in P.J. Plauger's "The Standard C Library," Prentice-Hall, 1992. + */ + +#include +#include +#include +#include +#ifdef SUNOS4 +#include "md/sunos4.h" /* for strtoul */ +#endif +#include "prprf.h" +#include "prdtoa.h" +#include "prlog.h" +#include "prerror.h" + +/* + * A function that reads a character from 'stream'. + * Returns the character read, or EOF if end of stream is reached. + */ +typedef int (*_PRGetCharFN)(void *stream); + +/* + * A function that pushes the character 'ch' back to 'stream'. + */ +typedef void (*_PRUngetCharFN)(void *stream, int ch); + +/* + * The size specifier for the integer and floating point number + * conversions in format control strings. + */ +typedef enum { + _PR_size_none, /* No size specifier is given */ + _PR_size_h, /* The 'h' specifier, suggesting "short" */ + _PR_size_l, /* The 'l' specifier, suggesting "long" */ + _PR_size_L, /* The 'L' specifier, meaning a 'long double' */ + _PR_size_ll /* The 'll' specifier, suggesting "long long" */ +} _PRSizeSpec; + +/* + * The collection of data that is passed between the scan function + * and its subordinate functions. The fields of this structure + * serve as the input or output arguments for these functions. + */ +typedef struct { + _PRGetCharFN get; /* get a character from input stream */ + _PRUngetCharFN unget; /* unget (push back) a character */ + void *stream; /* argument for get and unget */ + va_list ap; /* the variable argument list */ + int nChar; /* number of characters read from 'stream' */ + + PRBool assign; /* assign, or suppress assignment? */ + int width; /* field width */ + _PRSizeSpec sizeSpec; /* 'h', 'l', 'L', or 'll' */ + + PRBool converted; /* is the value actually converted? */ +} ScanfState; + +#define GET(state) ((state)->nChar++, (state)->get((state)->stream)) +#define UNGET(state, ch) \ + ((state)->nChar--, (state)->unget((state)->stream, ch)) + +/* + * The following two macros, GET_IF_WITHIN_WIDTH and WITHIN_WIDTH, + * are always used together. + * + * GET_IF_WITHIN_WIDTH calls the GET macro and assigns its return + * value to 'ch' only if we have not exceeded the field width of + * 'state'. Therefore, after GET_IF_WITHIN_WIDTH, the value of + * 'ch' is valid only if the macro WITHIN_WIDTH evaluates to true. + */ + +#define GET_IF_WITHIN_WIDTH(state, ch) \ + if (--(state)->width >= 0) { \ + (ch) = GET(state); \ + } +#define WITHIN_WIDTH(state) ((state)->width >= 0) + +/* + * _pr_strtoull: + * Convert a string to an unsigned 64-bit integer. The string + * 'str' is assumed to be a representation of the integer in + * base 'base'. + * + * Warning: + * - Only handle base 8, 10, and 16. + * - No overflow checking. + */ + +static PRUint64 +_pr_strtoull(const char *str, char **endptr, int base) +{ + static const int BASE_MAX = 16; + static const char digits[] = "0123456789abcdef"; + char *digitPtr; + PRUint64 x; /* return value */ + PRInt64 base64; + const char *cPtr; + PRBool negative; + const char *digitStart; + + PR_ASSERT(base == 0 || base == 8 || base == 10 || base == 16); + if (base < 0 || base == 1 || base > BASE_MAX) { + if (endptr) { + *endptr = (char *) str; + return LL_ZERO; + } + } + + cPtr = str; + while (isspace(*cPtr)) { + ++cPtr; + } + + negative = PR_FALSE; + if (*cPtr == '-') { + negative = PR_TRUE; + cPtr++; + } else if (*cPtr == '+') { + cPtr++; + } + + if (base == 16) { + if (*cPtr == '0' && (cPtr[1] == 'x' || cPtr[1] == 'X')) { + cPtr += 2; + } + } else if (base == 0) { + if (*cPtr != '0') { + base = 10; + } else if (cPtr[1] == 'x' || cPtr[1] == 'X') { + base = 16; + cPtr += 2; + } else { + base = 8; + } + } + PR_ASSERT(base != 0); + LL_I2L(base64, base); + digitStart = cPtr; + + /* Skip leading zeros */ + while (*cPtr == '0') { + cPtr++; + } + + LL_I2L(x, 0); + while ((digitPtr = (char*)memchr(digits, tolower(*cPtr), base)) != NULL) { + PRUint64 d; + + LL_I2L(d, (digitPtr - digits)); + LL_MUL(x, x, base64); + LL_ADD(x, x, d); + cPtr++; + } + + if (cPtr == digitStart) { + if (endptr) { + *endptr = (char *) str; + } + return LL_ZERO; + } + + if (negative) { +#ifdef HAVE_LONG_LONG + /* The cast to a signed type is to avoid a compiler warning */ + x = -(PRInt64)x; +#else + LL_NEG(x, x); +#endif + } + + if (endptr) { + *endptr = (char *) cPtr; + } + return x; +} + +/* + * The maximum field width (in number of characters) that is enough + * (may be more than necessary) to represent a 64-bit integer or + * floating point number. + */ +#define FMAX 31 +#define DECIMAL_POINT '.' + +static PRStatus +GetInt(ScanfState *state, int code) +{ + char buf[FMAX + 1], *p; + int ch; + static const char digits[] = "0123456789abcdefABCDEF"; + PRBool seenDigit = PR_FALSE; + int base; + int dlen; + + switch (code) { + case 'd': case 'u': + base = 10; + break; + case 'i': + base = 0; + break; + case 'x': case 'X': case 'p': + base = 16; + break; + case 'o': + base = 8; + break; + default: + return PR_FAILURE; + } + if (state->width == 0 || state->width > FMAX) { + state->width = FMAX; + } + p = buf; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + if (WITHIN_WIDTH(state) && ch == '0') { + seenDigit = PR_TRUE; + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) + && (ch == 'x' || ch == 'X') + && (base == 0 || base == 16)) { + base = 16; + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } else if (base == 0) { + base = 8; + } + } + if (base == 0 || base == 10) { + dlen = 10; + } else if (base == 8) { + dlen = 8; + } else { + PR_ASSERT(base == 16); + dlen = 16 + 6; /* 16 digits, plus 6 in uppercase */ + } + while (WITHIN_WIDTH(state) && memchr(digits, ch, dlen)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + if (WITHIN_WIDTH(state)) { + UNGET(state, ch); + } + if (!seenDigit) { + return PR_FAILURE; + } + *p = '\0'; + if (state->assign) { + if (code == 'd' || code == 'i') { + if (state->sizeSpec == _PR_size_ll) { + PRInt64 llval = _pr_strtoull(buf, NULL, base); + *va_arg(state->ap, PRInt64 *) = llval; + } else { + long lval = strtol(buf, NULL, base); + + if (state->sizeSpec == _PR_size_none) { + *va_arg(state->ap, PRIntn *) = lval; + } else if (state->sizeSpec == _PR_size_h) { + *va_arg(state->ap, PRInt16 *) = (PRInt16)lval; + } else if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRInt32 *) = lval; + } else { + return PR_FAILURE; + } + } + } else { + if (state->sizeSpec == _PR_size_ll) { + PRUint64 llval = _pr_strtoull(buf, NULL, base); + *va_arg(state->ap, PRUint64 *) = llval; + } else { + unsigned long lval = strtoul(buf, NULL, base); + + if (state->sizeSpec == _PR_size_none) { + *va_arg(state->ap, PRUintn *) = lval; + } else if (state->sizeSpec == _PR_size_h) { + *va_arg(state->ap, PRUint16 *) = (PRUint16)lval; + } else if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRUint32 *) = lval; + } else { + return PR_FAILURE; + } + } + } + state->converted = PR_TRUE; + } + return PR_SUCCESS; +} + +static PRStatus +GetFloat(ScanfState *state) +{ + char buf[FMAX + 1], *p; + int ch; + PRBool seenDigit = PR_FALSE; + + if (state->width == 0 || state->width > FMAX) { + state->width = FMAX; + } + p = buf; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + if (WITHIN_WIDTH(state) && ch == DECIMAL_POINT) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + seenDigit = PR_TRUE; + } + } + + /* + * This is not robust. For example, "1.2e+" would confuse + * the code below to read 'e' and '+', only to realize that + * it should have stopped at "1.2". But we can't push back + * more than one character, so there is nothing I can do. + */ + + /* Parse exponent */ + if (WITHIN_WIDTH(state) && (ch == 'e' || ch == 'E') && seenDigit) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + if (WITHIN_WIDTH(state) && (ch == '+' || ch == '-')) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + while (WITHIN_WIDTH(state) && isdigit(ch)) { + *p++ = ch; + GET_IF_WITHIN_WIDTH(state, ch); + } + } + if (WITHIN_WIDTH(state)) { + UNGET(state, ch); + } + if (!seenDigit) { + return PR_FAILURE; + } + *p = '\0'; + if (state->assign) { + PRFloat64 dval = PR_strtod(buf, NULL); + + state->converted = PR_TRUE; + if (state->sizeSpec == _PR_size_l) { + *va_arg(state->ap, PRFloat64 *) = dval; + } else if (state->sizeSpec == _PR_size_L) { +#if defined(OSF1) || defined(IRIX) + *va_arg(state->ap, double *) = dval; +#else + *va_arg(state->ap, long double *) = dval; +#endif + } else { + *va_arg(state->ap, float *) = (float) dval; + } + } + return PR_SUCCESS; +} + +/* + * Convert, and return the end of the conversion spec. + * Return NULL on error. + */ + +static const char * +Convert(ScanfState *state, const char *fmt) +{ + const char *cPtr; + int ch; + char *cArg = NULL; + + state->converted = PR_FALSE; + cPtr = fmt; + if (*cPtr != 'c' && *cPtr != 'n' && *cPtr != '[') { + do { + ch = GET(state); + } while (isspace(ch)); + UNGET(state, ch); + } + switch (*cPtr) { + case 'c': + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + if (state->width == 0) { + state->width = 1; + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if (ch == EOF) { + return NULL; + } else if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + state->converted = PR_TRUE; + } + break; + case 'p': + case 'd': case 'i': case 'o': + case 'u': case 'x': case 'X': + if (GetInt(state, *cPtr) == PR_FAILURE) { + return NULL; + } + break; + case 'e': case 'E': case 'f': + case 'g': case 'G': + if (GetFloat(state) == PR_FAILURE) { + return NULL; + } + break; + case 'n': + /* do not consume any input */ + if (state->assign) { + switch (state->sizeSpec) { + case _PR_size_none: + *va_arg(state->ap, PRIntn *) = state->nChar; + break; + case _PR_size_h: + *va_arg(state->ap, PRInt16 *) = state->nChar; + break; + case _PR_size_l: + *va_arg(state->ap, PRInt32 *) = state->nChar; + break; + case _PR_size_ll: + LL_I2L(*va_arg(state->ap, PRInt64 *), state->nChar); + break; + default: + PR_ASSERT(0); + } + } + break; + case 's': + if (state->width == 0) { + state->width = INT_MAX; + } + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if ((ch == EOF) || isspace(ch)) { + UNGET(state, ch); + break; + } + if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + *cArg = '\0'; + state->converted = PR_TRUE; + } + break; + case '%': + ch = GET(state); + if (ch != '%') { + UNGET(state, ch); + return NULL; + } + break; + case '[': + { + PRBool complement = PR_FALSE; + const char *closeBracket; + size_t n; + + if (*++cPtr == '^') { + complement = PR_TRUE; + cPtr++; + } + closeBracket = strchr(*cPtr == ']' ? cPtr + 1 : cPtr, ']'); + if (closeBracket == NULL) { + return NULL; + } + n = closeBracket - cPtr; + if (state->width == 0) { + state->width = INT_MAX; + } + if (state->assign) { + cArg = va_arg(state->ap, char *); + } + for (; state->width > 0; state->width--) { + ch = GET(state); + if ((ch == EOF) + || (!complement && !memchr(cPtr, ch, n)) + || (complement && memchr(cPtr, ch, n))) { + UNGET(state, ch); + break; + } + if (state->assign) { + *cArg++ = ch; + } + } + if (state->assign) { + *cArg = '\0'; + state->converted = PR_TRUE; + } + cPtr = closeBracket; + } + break; + default: + return NULL; + } + return cPtr; +} + +static PRInt32 +DoScanf(ScanfState *state, const char *fmt) +{ + PRInt32 nConverted = 0; + const char *cPtr; + int ch; + + state->nChar = 0; + cPtr = fmt; + while (1) { + if (isspace(*cPtr)) { + /* white space: skip */ + do { + cPtr++; + } while (isspace(*cPtr)); + do { + ch = GET(state); + } while (isspace(ch)); + UNGET(state, ch); + } else if (*cPtr == '%') { + /* format spec: convert */ + cPtr++; + state->assign = PR_TRUE; + if (*cPtr == '*') { + cPtr++; + state->assign = PR_FALSE; + } + for (state->width = 0; isdigit(*cPtr); cPtr++) { + state->width = state->width * 10 + *cPtr - '0'; + } + state->sizeSpec = _PR_size_none; + if (*cPtr == 'h') { + cPtr++; + state->sizeSpec = _PR_size_h; + } else if (*cPtr == 'l') { + cPtr++; + if (*cPtr == 'l') { + cPtr++; + state->sizeSpec = _PR_size_ll; + } else { + state->sizeSpec = _PR_size_l; + } + } else if (*cPtr == 'L') { + cPtr++; + state->sizeSpec = _PR_size_L; + } + cPtr = Convert(state, cPtr); + if (cPtr == NULL) { + return (nConverted > 0 ? nConverted : EOF); + } + if (state->converted) { + nConverted++; + } + cPtr++; + } else { + /* others: must match */ + if (*cPtr == '\0') { + return nConverted; + } + ch = GET(state); + if (ch != *cPtr) { + UNGET(state, ch); + return nConverted; + } + cPtr++; + } + } +} + +static int +StringGetChar(void *stream) +{ + char *cPtr = *((char **) stream); + + if (*cPtr == '\0') { + return EOF; + } else { + *((char **) stream) = cPtr + 1; + return *cPtr; + } +} + +static void +StringUngetChar(void *stream, int ch) +{ + char *cPtr = *((char **) stream); + + if (ch != EOF) { + *((char **) stream) = cPtr - 1; + } +} + +PR_IMPLEMENT(PRInt32) +PR_sscanf(const char *buf, const char *fmt, ...) +{ + PRInt32 rv; + ScanfState state; + + state.get = &StringGetChar; + state.unget = &StringUngetChar; + state.stream = (void *) &buf; + va_start(state.ap, fmt); + rv = DoScanf(&state, fmt); + va_end(state.ap); + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prsocket.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prsocket.c new file mode 100644 index 00000000..8be198fa --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prsocket.c @@ -0,0 +1,1842 @@ +/* -*- 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 + +/************************************************************************/ + +/* These two functions are only used in assertions. */ +#if defined(DEBUG) + +PRBool IsValidNetAddr(const PRNetAddr *addr) +{ + if ((addr != NULL) +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && (addr->raw.family != PR_AF_LOCAL) +#endif + && (addr->raw.family != PR_AF_INET6) + && (addr->raw.family != PR_AF_INET)) { + return PR_FALSE; + } + return PR_TRUE; +} + +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) +{ + /* + * The definition of the length of a Unix domain socket address + * is not uniform, so we don't check it. + */ + if ((addr != NULL) +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && (addr->raw.family != AF_UNIX) +#endif + && (PR_NETADDR_SIZE(addr) != addr_len)) { +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 + /* + * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 + * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id + * field and is 28 bytes. It is possible for socket functions + * to return an addr_len greater than sizeof(struct sockaddr_in6). + * We need to allow that. (Bugzilla bug #77264) + */ + if ((PR_AF_INET6 == addr->raw.family) + && (sizeof(addr->ipv6) == addr_len)) { + return PR_TRUE; + } +#endif + /* + * The accept(), getsockname(), etc. calls on some platforms + * do not set the actual socket address length on return. + * In this case, we verifiy addr_len is still the value we + * passed in (i.e., sizeof(PRNetAddr)). + */ +#if defined(QNX) + if (sizeof(PRNetAddr) == addr_len) { + return PR_TRUE; + } +#endif + return PR_FALSE; + } + return PR_TRUE; +} + +#endif /* DEBUG */ + +static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov, +PRInt32 iov_size, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + int w = 0; + const PRIOVec *tmp_iov; +#define LOCAL_MAXIOV 8 + PRIOVec local_iov[LOCAL_MAXIOV]; + PRIOVec *iov_copy = NULL; + int tmp_out; + int index, iov_cnt; + int count=0, sz = 0; /* 'count' is the return value. */ + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + /* + * Assume the first writev will succeed. Copy iov's only on + * failure. + */ + tmp_iov = iov; + for (index = 0; index < iov_size; index++) + sz += iov[index].iov_len; + + iov_cnt = iov_size; + + while (sz > 0) { + + w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); + if (w < 0) { + count = -1; + break; + } + count += w; + if (fd->secret->nonblocking) { + break; + } + sz -= w; + + if (sz > 0) { + /* find the next unwritten vector */ + for ( index = 0, tmp_out = count; + tmp_out >= iov[index].iov_len; + tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */ + + if (tmp_iov == iov) { + /* + * The first writev failed so we + * must copy iov's around. + * Avoid calloc/free if there + * are few enough iov's. + */ + if (iov_size - index <= LOCAL_MAXIOV) + iov_copy = local_iov; + else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) * + sizeof *iov_copy)) == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + tmp_iov = iov_copy; + } + + PR_ASSERT(tmp_iov == iov_copy); + + /* fill in the first partial read */ + iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]); + iov_copy[0].iov_len = iov[index].iov_len - tmp_out; + index++; + + /* copy the remaining vectors */ + for (iov_cnt=1; indexsecret->md.osfd = osfd; + fd->secret->inheritable = _PR_TRI_FALSE; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->methods = PR_GetSocketPollFdMethods(); + } + + return fd; +} /* PR_CreateSocketPollFD */ + +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd) +{ + if (NULL == fd) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + _PR_Putfd(fd); + return PR_SUCCESS; +} /* PR_DestroySocketPollFd */ + +static PRStatus PR_CALLBACK SocketConnect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 rv; /* Return value of _PR_MD_CONNECT */ + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return PR_FAILURE; + } +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + + rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout); + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); + if (rv == 0) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +static PRStatus PR_CALLBACK SocketConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + PRInt32 osfd; + int err; + + if (out_flags & PR_POLL_NVAL) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { + PR_ASSERT(out_flags == 0); + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; + } + + osfd = fd->secret->md.osfd; + +#if defined(XP_UNIX) + + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + +#elif defined(WIN32) || defined(WIN16) + +#if defined(WIN32) + /* + * The sleep circumvents a bug in Win32 WinSock. + * See Microsoft Knowledge Base article ID: Q165989. + */ + Sleep(0); +#endif /* WIN32 */ + + if (out_flags & PR_POLL_EXCEPT) { + int len = sizeof(err); + if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len) + == SOCKET_ERROR) { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + } else { + PR_SetError(PR_UNKNOWN_ERROR, 0); + } + return PR_FAILURE; + } + + PR_ASSERT(out_flags & PR_POLL_WRITE); + return PR_SUCCESS; + +#elif defined(XP_OS2) + + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + +#elif defined(XP_MAC) + + err = _MD_mac_get_nonblocking_connect_error(fd); + if (err == -1) + return PR_FAILURE; + else + return PR_SUCCESS; + +#elif defined(XP_BEOS) + +#ifdef BONE_VERSION /* bug 122364 */ + /* temporary workaround until getsockopt(SO_ERROR) works in BONE */ + if (out_flags & PR_POLL_EXCEPT) { + PR_SetError(PR_CONNECT_REFUSED_ERROR, 0); + return PR_FAILURE; + } + PR_ASSERT(out_flags & PR_POLL_WRITE); + return PR_SUCCESS; +#else + err = _MD_beos_get_nonblocking_connect_error(fd); + if( err != 0 ) { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + else + return PR_SUCCESS; +#endif /* BONE_VERSION */ + +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +#endif +} + +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) +{ + /* Find the NSPR layer and invoke its connectcontinue method */ + PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + + if (NULL == bottom) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return SocketConnectContinue(bottom, pd->out_flags); +} + +static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + PRInt32 osfd; + PRFileDesc *fd2; + PRUint32 al; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#ifdef WINNT + PRNetAddr addrCopy; +#endif + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return 0; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return 0; + } + +#ifdef WINNT + if (addr == NULL) { + addr = &addrCopy; + } +#endif + al = sizeof(PRNetAddr); + osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout); + if (osfd == -1) + return 0; + + fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + if (!fd2) { + _PR_MD_CLOSE_SOCKET(osfd); + return NULL; + } + + fd2->secret->nonblocking = fd->secret->nonblocking; + fd2->secret->inheritable = fd->secret->inheritable; +#ifdef WINNT + if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) { + /* + * The new socket has been associated with an I/O + * completion port. There is no going back. + */ + fd2->secret->md.io_model_committed = PR_TRUE; + } + PR_ASSERT(al == PR_NETADDR_SIZE(addr)); + fd2->secret->md.accepted_socket = PR_TRUE; + memcpy(&fd2->secret->md.peer_addr, addr, al); +#endif + + /* + * On some platforms, the new socket created by accept() + * inherits the nonblocking (or overlapped io) attribute + * of the listening socket. As an optimization, these + * platforms can skip the following _PR_MD_MAKE_NONBLOCK + * call. + * + * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK + * (which maps to _MD_makenonblock, see macsockotpt.c) + * installs the async notifier routine needed to make blocking + * I/O work properly. + */ +#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT) + _PR_MD_MAKE_NONBLOCK(fd2); +#endif + +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE); + + return fd2; +} + +#ifdef WINNT +PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, +PRIntervalTime timeout) +{ + PRInt32 osfd; + PRFileDesc *fd2; + PRIntn al; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr addrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return 0; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return 0; + } + + if (addr == NULL) { + addr = &addrCopy; + } + al = PR_NETADDR_SIZE(addr); + osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL); + if (osfd == -1) { + return 0; + } + + fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + if (!fd2) { + _PR_MD_CLOSE_SOCKET(osfd); + } else { + fd2->secret->nonblocking = fd->secret->nonblocking; + fd2->secret->md.io_model_committed = PR_TRUE; + PR_ASSERT(al == PR_NETADDR_SIZE(addr)); + fd2->secret->md.accepted_socket = PR_TRUE; + memcpy(&fd2->secret->md.peer_addr, addr, al); +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + } + return fd2; +} +#endif /* WINNT */ + + +static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr) +{ + PRInt32 result; + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + +#ifdef XP_UNIX + if (addr->raw.family == AF_UNIX) { + /* Disallow relative pathnames */ + if (addr->local.path[0] != '/') { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + } +#endif /* XP_UNIX */ + +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr)); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 result; + + result = _PR_MD_LISTEN(fd, backlog); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how) +{ + PRInt32 result; + + result = _PR_MD_SHUTDOWN(fd, how); + if (result < 0) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, +PRIntervalTime timeout) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ((flags != 0) && (flags != PR_MSG_PEEK)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d flags=%d", + fd, fd->secret->md.osfd, buf, amount, flags)); + +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + rv = (amount < fd->secret->peekBytes) ? + amount : fd->secret->peekBytes; + memcpy(buf, fd->secret->peekBuffer, rv); + if (flags == 0) { + /* consume the bytes in the peek buffer */ + fd->secret->peekBytes -= rv; + if (fd->secret->peekBytes != 0) { + memmove(fd->secret->peekBuffer, + fd->secret->peekBuffer + rv, + fd->secret->peekBytes); + } + } + return rv; + } + + /* allocate peek buffer, if necessary */ + if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { + PR_ASSERT(0 == fd->secret->peekBytes); + /* impose a max size on the peek buffer */ + if (amount > _PR_PEEK_BUFFER_MAX) { + amount = _PR_PEEK_BUFFER_MAX; + } + if (fd->secret->peekBufSize < amount) { + if (fd->secret->peekBuffer) { + PR_Free(fd->secret->peekBuffer); + } + fd->secret->peekBufSize = amount; + fd->secret->peekBuffer = PR_Malloc(amount); + if (NULL == fd->secret->peekBuffer) { + fd->secret->peekBufSize = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + } +#endif + + rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d", + rv, PR_GetError(), PR_GetOSError())); + +#ifdef _PR_HAVE_PEEK_BUFFER + if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { + if (rv > 0) { + memcpy(fd->secret->peekBuffer, buf, rv); + fd->secret->peekBytes = rv; + } + } +#endif + + return rv; +} + +static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} + +static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount, +PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 temp, count; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + count = 0; + while (amount > 0) { + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("send: fd=%p osfd=%d buf=%p amount=%d", + fd, fd->secret->md.osfd, buf, amount)); + temp = _PR_MD_SEND(fd, buf, amount, flags, timeout); + if (temp < 0) { + count = -1; + break; + } + + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + + amount -= temp; + } + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count)); + return count; +} + +static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} + +static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd) +{ + if (!fd || !fd->secret + || (fd->secret->state != _PR_FILEDESC_OPEN + && fd->secret->state != _PR_FILEDESC_CLOSED)) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + + if (fd->secret->state == _PR_FILEDESC_OPEN) { + if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) { + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + } + +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBuffer) { + PR_ASSERT(fd->secret->peekBufSize > 0); + PR_DELETE(fd->secret->peekBuffer); + fd->secret->peekBufSize = 0; + fd->secret->peekBytes = 0; + } +#endif + + PR_FreeFileDesc(fd); + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd) +{ + PRInt32 rv; +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + return fd->secret->peekBytes; + } +#endif + rv = _PR_MD_SOCKETAVAILABLE(fd); + return rv; +} + +static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd) +{ + PRInt64 rv; +#ifdef _PR_HAVE_PEEK_BUFFER + if (fd->secret->peekBytes != 0) { + LL_I2L(rv, fd->secret->peekBytes); + return rv; + } +#endif + LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd)); + return rv; +} + +static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd) +{ +#if defined(XP_MAC) +#pragma unused (fd) +#endif + + return PR_SUCCESS; +} + +static PRInt32 PR_CALLBACK SocketSendTo( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 temp, count; + const PRNetAddr *addrp = addr; +#if defined(_PR_INET6) + PRNetAddr addrCopy; +#endif + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; + } +#endif + + count = 0; + while (amount > 0) { + temp = _PR_MD_SENDTO(fd, buf, amount, flags, + addrp, PR_NETADDR_SIZE(addr), timeout); + if (temp < 0) { + count = -1; + break; + } + count += temp; + if (fd->secret->nonblocking) { + break; + } + buf = (const void*) ((const char*)buf + temp); + amount -= temp; + } + return count; +} + +static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRInt32 rv; + PRUint32 al; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + + al = sizeof(PRNetAddr); + rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout); +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + return rv; +} + +static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + *nd = NULL; + +#if defined(WINNT) + { + PRInt32 newSock; + PRNetAddr *raddrCopy; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif + } + } + } +#else + rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); +#endif + return rv; +} + +#ifdef WINNT +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout) +{ + PRInt32 rv; + PRInt32 newSock; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr *raddrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + *nd = NULL; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, + timeout, PR_TRUE, NULL, NULL); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif + } + } + return rv; +} + +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( +PRFileDesc *sd, PRFileDesc **nd, +PRNetAddr **raddr, void *buf, PRInt32 amount, +PRIntervalTime timeout, +_PR_AcceptTimeoutCallback callback, +void *callbackArg) +{ + PRInt32 rv; + PRInt32 newSock; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRNetAddr *raddrCopy; + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + *nd = NULL; + + if (raddr == NULL) { + raddr = &raddrCopy; + } + rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, + timeout, PR_TRUE, callback, callbackArg); + if (rv < 0) { + rv = -1; + } else { + /* Successfully accepted and read; create the new PRFileDesc */ + *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); + if (*nd == 0) { + _PR_MD_CLOSE_SOCKET(newSock); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + rv = -1; + } else { + (*nd)->secret->md.io_model_committed = PR_TRUE; + (*nd)->secret->md.accepted_socket = PR_TRUE; + memcpy(&(*nd)->secret->md.peer_addr, *raddr, + PR_NETADDR_SIZE(*raddr)); +#ifdef _PR_INET6 + if (AF_INET6 == *raddr->raw.family) + *raddr->raw.family = PR_AF_INET6; +#endif + } + } + return rv; +} +#endif /* WINNT */ + +#ifdef WINNT +PR_IMPLEMENT(void) +PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket) +{ + _PR_MD_UPDATE_ACCEPT_CONTEXT( + socket->secret->md.osfd, acceptSocket->secret->md.osfd); +} +#endif /* WINNT */ + +static PRInt32 PR_CALLBACK SocketSendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (_PR_IO_PENDING(me)) { + PR_SetError(PR_IO_PENDING_ERROR, 0); + return -1; + } + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } +#if defined(WINNT) + rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout); + if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { + /* + * This should be kept the same as SocketClose, except + * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should + * not be called because the socket will be recycled. + */ + PR_FreeFileDesc(sd); + } +#else + rv = PR_EmulateSendFile(sd, sfd, flags, timeout); +#endif /* WINNT */ + + return rv; +} + +static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, +const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, +PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + + return(SocketSendFile(sd, &sfd, flags, timeout)); +} + +static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRInt32 result; + PRUint32 addrlen; + + addrlen = sizeof(PRNetAddr); + result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen); + if (result < 0) { + return PR_FAILURE; + } +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); + return PR_SUCCESS; +} + +static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRInt32 result; + PRUint32 addrlen; + + addrlen = sizeof(PRNetAddr); + result = _PR_MD_GETPEERNAME(fd, addr, &addrlen); + if (result < 0) { + return PR_FAILURE; + } +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); + return PR_SUCCESS; +} + +static PRInt16 PR_CALLBACK SocketPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ +#ifdef XP_MAC +#pragma unused( fd, in_flags ) +#endif + *out_flags = 0; + return in_flags; +} /* SocketPoll */ + +static PRIOMethods tcpMethods = { + PR_DESC_SOCKET_TCP, + SocketClose, + SocketRead, + SocketWrite, + SocketAvailable, + SocketAvailable64, + SocketSync, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + SocketWritev, + SocketConnect, + SocketAccept, + SocketBind, + SocketListen, + SocketShutdown, + SocketRecv, + SocketSend, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + SocketPoll, + SocketAcceptRead, + SocketTransmitFile, + SocketGetName, + SocketGetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + _PR_SocketGetSocketOption, + _PR_SocketSetSocketOption, + SocketSendFile, + SocketConnectContinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods udpMethods = { + PR_DESC_SOCKET_UDP, + SocketClose, + SocketRead, + SocketWrite, + SocketAvailable, + SocketAvailable64, + SocketSync, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + SocketWritev, + SocketConnect, + (PRAcceptFN)_PR_InvalidDesc, + SocketBind, + SocketListen, + SocketShutdown, + SocketRecv, + SocketSend, + SocketRecvFrom, + SocketSendTo, + SocketPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + SocketGetName, + SocketGetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + _PR_SocketGetSocketOption, + _PR_SocketSetSocketOption, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + + +static PRIOMethods socketpollfdMethods = { + (PRDescType) 0, + (PRCloseFN)_PR_InvalidStatus, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + SocketPoll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods() +{ + return &tcpMethods; +} + +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() +{ + return &udpMethods; +} + +static const PRIOMethods* PR_GetSocketPollFdMethods() +{ + return &socketpollfdMethods; +} /* PR_GetSocketPollFdMethods */ + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd); + +#if defined(_PR_INET6_PROBE) + +PR_EXTERN(PRBool) _pr_ipv6_is_present; + +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() +{ +PRInt32 osfd; + + osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + _PR_MD_CLOSE_SOCKET(osfd); + return PR_TRUE; + } + return PR_FALSE; +} +#endif /* _PR_INET6_PROBE */ + +#endif + +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRInt32 osfd; + PRFileDesc *fd; + PRInt32 tmp_domain = domain; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (PR_AF_INET != domain + && PR_AF_INET6 != domain +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + && PR_AF_LOCAL != domain +#endif + ) { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return NULL; + } + +#if defined(_PR_INET6_PROBE) + if (PR_AF_INET6 == domain) { + if (_pr_ipv6_is_present == PR_FALSE) + domain = AF_INET; + else + domain = AF_INET6; + } +#elif defined(_PR_INET6) + if (PR_AF_INET6 == domain) + domain = AF_INET6; +#else + if (PR_AF_INET6 == domain) + domain = AF_INET; +#endif /* _PR_INET6 */ + osfd = _PR_MD_SOCKET(domain, type, proto); + if (osfd == -1) { + return 0; + } + if (type == SOCK_STREAM) + fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); + else + fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); + /* + * Make the sockets non-blocking + */ + if (fd != NULL) { + _PR_MD_MAKE_NONBLOCK(fd); + _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { + if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { + PR_Close(fd); + fd = NULL; + } + } +#endif + } else + _PR_MD_CLOSE_SOCKET(osfd); + + return fd; +} + +PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void) +{ + PRInt32 domain = AF_INET; + + return PR_Socket(domain, SOCK_STREAM, 0); +} + +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) +{ + PRInt32 domain = AF_INET; + + return PR_Socket(domain, SOCK_DGRAM, 0); +} + +PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_STREAM, 0); +} + +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_DGRAM, 0); +} + +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[]) +{ +#ifdef XP_UNIX + PRInt32 rv, osfd[2]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd); + if (rv == -1) { + return PR_FAILURE; + } + + f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); + if (!f[0]) { + _PR_MD_CLOSE_SOCKET(osfd[0]); + _PR_MD_CLOSE_SOCKET(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); + if (!f[1]) { + PR_Close(f[0]); + _PR_MD_CLOSE_SOCKET(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + _PR_MD_MAKE_NONBLOCK(f[0]); + _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); + _PR_MD_MAKE_NONBLOCK(f[1]); + _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); + return PR_SUCCESS; +#elif defined(WINNT) + /* + * A socket pair is often used for interprocess communication, + * so we need to make sure neither socket is associated with + * the I/O completion port; otherwise it can't be used by a + * child process. + * + * The default implementation below cannot be used for NT + * because PR_Accept would have associated the I/O completion + * port with the listening and accepted sockets. + */ + SOCKET listenSock; + SOCKET osfd[2]; + struct sockaddr_in selfAddr, peerAddr; + int addrLen; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + osfd[0] = osfd[1] = INVALID_SOCKET; + listenSock = socket(AF_INET, SOCK_STREAM, 0); + if (listenSock == INVALID_SOCKET) { + goto failed; + } + selfAddr.sin_family = AF_INET; + selfAddr.sin_port = 0; + selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */ + addrLen = sizeof(selfAddr); + if (bind(listenSock, (struct sockaddr *) &selfAddr, + addrLen) == SOCKET_ERROR) { + goto failed; + } + if (getsockname(listenSock, (struct sockaddr *) &selfAddr, + &addrLen) == SOCKET_ERROR) { + goto failed; + } + if (listen(listenSock, 5) == SOCKET_ERROR) { + goto failed; + } + osfd[0] = socket(AF_INET, SOCK_STREAM, 0); + if (osfd[0] == INVALID_SOCKET) { + goto failed; + } + selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + /* + * Only a thread is used to do the connect and accept. + * I am relying on the fact that connect returns + * successfully as soon as the connect request is put + * into the listen queue (but before accept is called). + * This is the behavior of the BSD socket code. If + * connect does not return until accept is called, we + * will need to create another thread to call connect. + */ + if (connect(osfd[0], (struct sockaddr *) &selfAddr, + addrLen) == SOCKET_ERROR) { + goto failed; + } + /* + * A malicious local process may connect to the listening + * socket, so we need to verify that the accepted connection + * is made from our own socket osfd[0]. + */ + if (getsockname(osfd[0], (struct sockaddr *) &selfAddr, + &addrLen) == SOCKET_ERROR) { + goto failed; + } + osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen); + if (osfd[1] == INVALID_SOCKET) { + goto failed; + } + if (peerAddr.sin_port != selfAddr.sin_port) { + /* the connection we accepted is not from osfd[0] */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + goto failed; + } + closesocket(listenSock); + + f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); + if (!f[0]) { + closesocket(osfd[0]); + closesocket(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); + if (!f[1]) { + PR_Close(f[0]); + closesocket(osfd[1]); + /* PR_AllocFileDesc() has invoked PR_SetError(). */ + return PR_FAILURE; + } + _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); + _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); + return PR_SUCCESS; + +failed: + if (listenSock != INVALID_SOCKET) { + closesocket(listenSock); + } + if (osfd[0] != INVALID_SOCKET) { + closesocket(osfd[0]); + } + if (osfd[1] != INVALID_SOCKET) { + closesocket(osfd[1]); + } + return PR_FAILURE; +#else /* not Unix or NT */ + /* + * default implementation + */ + PRFileDesc *listenSock; + PRNetAddr selfAddr, peerAddr; + PRUint16 port; + + f[0] = f[1] = NULL; + listenSock = PR_NewTCPSocket(); + if (listenSock == NULL) { + goto failed; + } + PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ + if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { + goto failed; + } + if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { + goto failed; + } + port = ntohs(selfAddr.inet.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + goto failed; + } + f[0] = PR_NewTCPSocket(); + if (f[0] == NULL) { + goto failed; + } +#ifdef _PR_CONNECT_DOES_NOT_BIND + /* + * If connect does not implicitly bind the socket (e.g., on + * BeOS), we have to bind the socket so that we can get its + * port with getsockname later. + */ + PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); + if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { + goto failed; + } +#endif + PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); + + /* + * Only a thread is used to do the connect and accept. + * I am relying on the fact that PR_Connect returns + * successfully as soon as the connect request is put + * into the listen queue (but before PR_Accept is called). + * This is the behavior of the BSD socket code. If + * connect does not return until accept is called, we + * will need to create another thread to call connect. + */ + if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) + == PR_FAILURE) { + goto failed; + } + /* + * A malicious local process may connect to the listening + * socket, so we need to verify that the accepted connection + * is made from our own socket f[0]. + */ + if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { + goto failed; + } + f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); + if (f[1] == NULL) { + goto failed; + } + if (peerAddr.inet.port != selfAddr.inet.port) { + /* the connection we accepted is not from f[0] */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + goto failed; + } + PR_Close(listenSock); + return PR_SUCCESS; + +failed: + if (listenSock) { + PR_Close(listenSock); + } + if (f[0]) { + PR_Close(f[0]); + } + if (f[1]) { + PR_Close(f[1]); + } + return PR_FAILURE; +#endif +} + +PR_IMPLEMENT(PRInt32) +PR_FileDesc2NativeHandle(PRFileDesc *fd) +{ + if (fd) { + fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); + } + if (!fd) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + return fd->secret->md.osfd; +} + +PR_IMPLEMENT(void) +PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle) +{ + if (fd) + fd->secret->md.osfd = handle; +} + +/* +** Select compatibility +** +*/ + +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set) +{ + memset(set, 0, sizeof(PR_fd_set)); +} + +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set) +{ + PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC ); + + set->harray[set->hsize++] = fh; +} + +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index, index2; + + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + for (index2=index; index2 < (set->hsize-1); index2++) { + set->harray[index2] = set->harray[index2+1]; + } + set->hsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index; + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + return 1; + } + return 0; +} + +PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set) +{ + PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC ); + + set->narray[set->nsize++] = fd; +} + +PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index, index2; + + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + for (index2=index; index2 < (set->nsize-1); index2++) { + set->narray[index2] = set->narray[index2+1]; + } + set->nsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index; + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + return 1; + } + return 0; +} + + +#if !defined(NEED_SELECT) +#if !defined(XP_MAC) +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#define PD_INCR 20 + +static PRPollDesc *_pr_setfd( + PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc) +{ + PRUintn fsidx, pdidx; + PRPollDesc *poll = polldesc; + + if (NULL == set) return poll; + + /* First set the pr file handle osfds */ + for (fsidx = 0; fsidx < set->hsize; fsidx++) + { + for (pdidx = 0; 1; pdidx++) + { + if ((PRFileDesc*)-1 == poll[pdidx].fd) + { + /* our vector is full - extend and condition it */ + poll = (PRPollDesc*)PR_Realloc( + poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc)); + if (NULL == poll) goto out_of_memory; + memset( + poll + pdidx * sizeof(PRPollDesc), + 0, PD_INCR * sizeof(PRPollDesc)); + poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1; + } + if ((NULL == poll[pdidx].fd) + || (poll[pdidx].fd == set->harray[fsidx])) + { + /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */ + /* either empty or prevously defined */ + poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */ + poll[pdidx].in_flags |= flags; /* possibly redundant */ + break; + } + } + } + +#if 0 + /* Second set the native osfds */ + for (fsidx = 0; fsidx < set->nsize; fsidx++) + { + for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++) + { + if ((PRFileDesc*)-1 == poll[pdidx].fd) + { + /* our vector is full - extend and condition it */ + poll = PR_Realloc( + poll, (pdidx + PD_INCR) * sizeof(PRPollDesc)); + if (NULL == poll) goto out_of_memory; + memset( + poll + pdidx * sizeof(PRPollDesc), + 0, PD_INCR * sizeof(PRPollDesc)); + poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1; + } + if ((NULL == poll[pdidx].fd) + || (poll[pdidx].fd == set->narray[fsidx])) + { + /* either empty or prevously defined */ + poll[pdidx].fd = set->narray[fsidx]; + PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); + poll[pdidx].in_flags |= flags; + break; + } + } + } +#endif /* 0 */ + + return poll; + +out_of_memory: + if (NULL != polldesc) PR_DELETE(polldesc); + return NULL; +} /* _pr_setfd */ + +#endif /* !defined(NEED_SELECT) */ + +PR_IMPLEMENT(PRInt32) PR_Select( + PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, + PR_fd_set *pr_ex, PRIntervalTime timeout) +{ + +#if !defined(NEED_SELECT) + PRInt32 npds = 0; + /* + ** Find out how many fds are represented in the three lists. + ** Then allocate a polling descriptor for the logical union + ** (there can't be any overlapping) and call PR_Poll(). + */ + + PRPollDesc *copy, *poll; + + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()"); + + /* try to get an initial guesss at how much space we need */ + npds = 0; + if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0)) + npds = pr_rd->hsize + pr_rd->nsize; + if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0)) + npds = pr_wr->hsize + pr_wr->nsize; + if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0)) + npds = pr_ex->hsize + pr_ex->nsize; + + if (0 == npds) + { + PR_Sleep(timeout); + return 0; + } + + copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc)); + if (NULL == poll) goto out_of_memory; + poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1; + + poll = _pr_setfd(pr_rd, PR_POLL_READ, poll); + if (NULL == poll) goto out_of_memory; + poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll); + if (NULL == poll) goto out_of_memory; + poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll); + if (NULL == poll) goto out_of_memory; + unused = 0; + while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) + { + ++unused; + } + + PR_ASSERT(unused > 0); + npds = PR_Poll(poll, unused, timeout); + + if (npds > 0) + { + /* Copy the results back into the fd sets */ + if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0; + if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0; + if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0; + for (copy = &poll[unused - 1]; copy >= poll; --copy) + { + if (copy->out_flags & PR_POLL_NVAL) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + npds = -1; + break; + } + if (copy->out_flags & PR_POLL_READ) + if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd; + if (copy->out_flags & PR_POLL_WRITE) + if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd; + if (copy->out_flags & PR_POLL_EXCEPT) + if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd; + } + } + PR_DELETE(poll); + + return npds; +out_of_memory: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + +#endif /* !defined(NEED_SELECT) */ + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prstdio.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prstdio.c new file mode 100644 index 00000000..0b7ecd89 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prstdio.c @@ -0,0 +1,103 @@ +/* -*- 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 + +/* +** fprintf to a PRFileDesc +*/ +PR_IMPLEMENT(PRUint32) PR_fprintf(PRFileDesc* fd, const char *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = PR_vfprintf(fd, fmt, ap); + va_end(ap); + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_vfprintf(PRFileDesc* fd, const char *fmt, va_list ap) +{ + /* XXX this could be better */ + PRUint32 rv, len; + char* msg = PR_vsmprintf(fmt, ap); + len = strlen(msg); +#ifdef XP_OS2 + /* + * OS/2 really needs a \r for every \n. + * In the future we should try to use scatter-gather instead of a + * succession of PR_Write. + */ + if (isatty(PR_FileDesc2NativeHandle(fd))) { + PRUint32 last = 0, idx; + PRInt32 tmp; + rv = 0; + for (idx = 0; idx < len+1; idx++) { + if ((idx - last > 0) && (('\n' == msg[idx]) || (idx == len))) { + tmp = PR_Write(fd, msg + last, idx - last); + if (tmp >= 0) { + rv += tmp; + } + last = idx; + } + /* + * if current character is \n, and + * previous character isn't \r, and + * next character isn't \r + */ + if (('\n' == msg[idx]) && + ((0 == idx) || ('\r' != msg[idx-1])) && + ('\r' != msg[idx+1])) { + /* add extra \r */ + tmp = PR_Write(fd, "\r", 1); + if (tmp >= 0) { + rv += tmp; + } + } + } + } else { + rv = PR_Write(fd, msg, len); + } +#else + rv = PR_Write(fd, msg, len); +#endif + PR_DELETE(msg); + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/linking/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/linking/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/linking/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/linking/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/linking/Makefile.in new file mode 100644 index 00000000..71fbf571 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/linking/Makefile.in @@ -0,0 +1,80 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + prlink.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +# For Dl_info and dladdr. +ifeq ($(OS_TARGET),Linux) +DEFINES += -D_GNU_SOURCE +endif + +# On Mac OS X use flat #includes. +ifeq ($(OS_TARGET),MacOSX) +INCLUDES += -I$(NEXT_ROOT)/Developer/Headers/FlatCarbon +endif + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/linking/prlink.c b/src/libs/xpcom18a4/nsprpub/pr/src/linking/prlink.c new file mode 100644 index 00000000..faad8af2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/linking/prlink.c @@ -0,0 +1,2147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Steve Streeter (Hewlett-Packard Company) + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "primpl.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_FindLibrary VBoxNsprPR_FindLibrary +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +#include + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR +# include +# include +# include + +# if defined(XP_MACOSX) /** @todo Add some equivalent to PR_GetLibraryFilePathname. */ +# include +# endif + +# ifdef XP_MAC +# error "Misconfiguration: XP_MAC && VBOX_USE_MORE_IPRT_IN_NSPR are not intended to work together" +# endif + +#else /* ! VBOX_USE_MORE_IPRT_IN_NSPR */ + +#ifdef XP_BEOS +#include +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) +#include +#include +#include +#include + +#if TARGET_CARBON +#include +#include +#include +#include +#include +#endif + +#if defined(XP_MACOSX) +#define PStrFromCStr(src, dst) c2pstrcpy(dst, src) +#else +#include "macdll.h" +#include "mdmac.h" +#endif /* XP_MACOSX */ +#endif + +#ifdef XP_UNIX +#ifdef USE_DLFCN +#include +/* Define these on systems that don't have them. */ +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#ifndef RTLD_LAZY +#define RTLD_LAZY RTLD_NOW +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif +#ifdef AIX +#include +#endif +#ifdef OSF1 +#include +#include +#endif +#elif defined(USE_HPSHL) +#include +#elif defined(USE_MACH_DYLD) +#include +#endif +#endif /* XP_UNIX */ + +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +#ifdef VBOX_USE_IPRT_IN_NSPR +# include +# include +# undef strdup +# define strdup(str) RTStrDup(str) +#endif + +#define _PR_DEFAULT_LD_FLAGS PR_LD_LAZY + +#ifdef VMS +/* These are all require for the PR_GetLibraryFilePathname implementation */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma __nostandard +#pragma __member_alignment __save +#pragma __nomember_alignment +#ifdef __INITIAL_POINTER_SIZE +#pragma __required_pointer_size __save +#pragma __required_pointer_size __short +#endif + +typedef struct _imcb { + struct _imcb *imcb$l_flink; + struct _imcb *imcb$l_blink; + unsigned short int imcb$w_size; + unsigned char imcb$b_type; + char imcb$b_resv_1; + unsigned char imcb$b_access_mode; + unsigned char imcb$b_act_code; + unsigned short int imcb$w_chan; + unsigned int imcb$l_flags; + char imcb$t_image_name [40]; + unsigned int imcb$l_symvec_size; + unsigned __int64 imcb$q_ident; + void *imcb$l_starting_address; + void *imcb$l_end_address; +} IMCB; + +#pragma __member_alignment __restore +#ifdef __INITIAL_POINTER_SIZE +#pragma __required_pointer_size __restore +#endif +#pragma __standard + +typedef struct { + short buflen; + short itmcode; + void *buffer; + void *retlen; +} ITMLST; + +typedef struct { + short cond; + short count; + int rest; +} IOSB; + +typedef unsigned long int ulong_t; + +struct _imcb *IAC$GL_IMAGE_LIST = NULL; + +#define MAX_DEVNAM 64 +#define MAX_FILNAM 255 +#endif /* VMS */ + +/* + * On these platforms, symbols have a leading '_'. + */ +#ifndef VBOX_USE_MORE_IPRT_IN_NSPR /* RTLdr hides this. */ +#if defined(SUNOS4) || defined(DARWIN) || defined(NEXTSTEP) \ + || defined(WIN16) || defined(XP_OS2) \ + || ((defined(OPENBSD) || defined(NETBSD)) && !defined(__ELF__)) +#define NEED_LEADING_UNDERSCORE +#endif +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + +#ifdef XP_PC +typedef PRStaticLinkTable *NODL_PROC(void); +#endif + +/************************************************************************/ + +struct PRLibrary { + char* name; /* Our own copy of the name string */ + PRLibrary* next; + int refCount; + const PRStaticLinkTable* staticTable; + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR + RTLDRMOD dlh; +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + +#ifdef XP_PC +#ifdef XP_OS2 + HMODULE dlh; +#else + HINSTANCE dlh; +#endif +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) + CFragConnectionID connection; + +#if TARGET_CARBON + CFBundleRef bundle; +#endif + + Ptr main; + +#if defined(XP_MACOSX) + CFMutableDictionaryRef wrappers; + const struct mach_header* image; +#endif /* XP_MACOSX */ +#endif + +#ifdef XP_UNIX +#if defined(USE_HPSHL) + shl_t dlh; +#elif defined(USE_MACH_DYLD) + NSModule dlh; +#else + void* dlh; +#endif +#endif + +#ifdef XP_BEOS + void* dlh; + void* stub_dlh; +#endif +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +}; + +static PRLibrary *pr_loadmap; +static PRLibrary *pr_exe_loadmap; +static PRMonitor *pr_linker_lock; +static char* _pr_currentLibPath = NULL; + +static PRLibrary *pr_LoadLibraryByPathname(const char *name, PRIntn flags); +#ifdef XP_MAC +static PRLibrary *pr_Mac_LoadNamedFragment(const FSSpec *fileSpec, + const char* fragmentName); +static PRLibrary *pr_Mac_LoadIndexedFragment(const FSSpec *fileSpec, + PRUint32 fragIndex); +#endif /* XP_MAC */ + +/************************************************************************/ + +#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) && !defined(VBOX_USE_MORE_IPRT_IN_NSPR) +static char* errStrBuf = NULL; +#define ERR_STR_BUF_LENGTH 20 +static char* errno_string(PRIntn oserr) +{ + if (errStrBuf == NULL) + errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH); + PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %d", oserr); + return errStrBuf; +} +#endif + +static void DLLErrorInternal(PRIntn oserr) +/* +** This whole function, and most of the code in this file, are run +** with a big hairy lock wrapped around it. Not the best of situations, +** but will eventually come up with the right answer. +*/ +{ + const char *error = NULL; +#ifdef USE_DLFCN + error = dlerror(); /* $$$ That'll be wrong some of the time - AOF */ +#elif defined(HAVE_STRERROR) + error = strerror(oserr); /* this should be okay */ +#else + error = errno_string(oserr); +#endif + if (NULL != error) + PR_SetErrorText(strlen(error), error); +} /* DLLErrorInternal */ + +void _PR_InitLinker(void) +{ +#if (!defined(XP_MAC) && !defined(XP_BEOS)) || defined(VBOX_USE_MORE_IPRT_IN_NSPR) + PRLibrary *lm; +#endif +#ifdef XP_UNIX + void *h; +#endif + + if (!pr_linker_lock) { + pr_linker_lock = PR_NewNamedMonitor("linker-lock"); + } + PR_EnterMonitor(pr_linker_lock); + +#if defined(XP_PC) || defined(VBOX_USE_MORE_IPRT_IN_NSPR) + lm = PR_NEWZAP(PRLibrary); + lm->name = strdup("Executable"); +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR + lm->dlh = NIL_RTLDRMOD; +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + /* + ** In WIN32, GetProcAddress(...) expects a module handle in order to + ** get exported symbols from the executable... + ** + ** However, in WIN16 this is accomplished by passing NULL to + ** GetProcAddress(...) + */ +#if defined(_WIN32) + lm->dlh = GetModuleHandle(NULL); +#else + lm->dlh = (HINSTANCE)NULL; +#endif /* ! _WIN32 */ +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + + lm->refCount = 1; + lm->staticTable = NULL; + pr_exe_loadmap = lm; + pr_loadmap = lm; + +#elif defined(XP_UNIX) +#ifdef HAVE_DLL +#ifdef USE_DLFCN + h = dlopen(0, RTLD_LAZY); + if (!h) { + char *error; + + DLLErrorInternal(_MD_ERRNO()); + error = (char*)PR_MALLOC(PR_GetErrorTextLength()); + (void) PR_GetErrorText(error); + fprintf(stderr, "failed to initialize shared libraries [%s]\n", + error); + PR_DELETE(error); + abort();/* XXX */ + } +#elif defined(USE_HPSHL) + h = NULL; + /* don't abort with this NULL */ +#elif defined(USE_MACH_DYLD) + h = NULL; /* XXXX toshok */ +#else +#error no dll strategy +#endif /* USE_DLFCN */ + + lm = PR_NEWZAP(PRLibrary); + if (lm) { + lm->name = strdup("a.out"); + lm->refCount = 1; + lm->dlh = h; + lm->staticTable = NULL; + } + pr_exe_loadmap = lm; + pr_loadmap = lm; +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ + +#if !defined(XP_MAC) && !defined(XP_BEOS) || defined(VBOX_USE_MORE_IPRT_IN_NSPR) + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (init)", lm?lm->name:"NULL")); +#endif + + PR_ExitMonitor(pr_linker_lock); +} + +#if defined(WIN16) +/* + * _PR_ShutdownLinker unloads all dlls loaded by the application via + * calls to PR_LoadLibrary + */ +void _PR_ShutdownLinker(void) +{ + PR_EnterMonitor(pr_linker_lock); + + while (pr_loadmap) { + if (pr_loadmap->refCount > 1) { +#ifdef DEBUG + fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n", + pr_loadmap->name, pr_loadmap->refCount); +#endif + pr_loadmap->refCount = 1; + } + PR_UnloadLibrary(pr_loadmap); + } + + PR_ExitMonitor(pr_linker_lock); + + PR_DestroyMonitor(pr_linker_lock); + pr_linker_lock = NULL; +} +#else +/* + * _PR_ShutdownLinker was originally only used on WIN16 (see above), + * but I think it should also be used on other platforms. However, + * I disagree with the original implementation's unloading the dlls + * for the application. Any dlls that still remain on the pr_loadmap + * list when NSPR shuts down are application programming errors. The + * only exception is pr_exe_loadmap, which was added to the list by + * NSPR and hence should be cleaned up by NSPR. + */ +void _PR_ShutdownLinker(void) +{ + /* FIXME: pr_exe_loadmap should be destroyed. */ + + PR_DestroyMonitor(pr_linker_lock); + pr_linker_lock = NULL; + + if (_pr_currentLibPath) { +#ifdef VBOX_USE_IPRT_IN_NSPR + RTStrFree(_pr_currentLibPath); +#else + free(_pr_currentLibPath); +#endif + _pr_currentLibPath = NULL; + } + +#if !defined(USE_DLFCN) && !defined(HAVE_STRERROR) && !defined(VBOX_USE_MORE_IPRT_IN_NSPR) + PR_DELETE(errStrBuf); +#endif +} +#endif + +/******************************************************************************/ + +PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_EnterMonitor(pr_linker_lock); + if (_pr_currentLibPath) { +#ifdef VBOX_USE_IPRT_IN_NSPR + RTStrFree(_pr_currentLibPath); +#else + free(_pr_currentLibPath); +#endif + } + if (path) { + _pr_currentLibPath = strdup(path); + if (!_pr_currentLibPath) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + rv = PR_FAILURE; + } + } else { + _pr_currentLibPath = 0; + } + PR_ExitMonitor(pr_linker_lock); + return rv; +} + +/* +** Return the library path for finding shared libraries. +*/ +PR_IMPLEMENT(char *) +PR_GetLibraryPath(void) +{ + char *ev; + char *copy = NULL; /* a copy of _pr_currentLibPath */ + + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_EnterMonitor(pr_linker_lock); + if (_pr_currentLibPath != NULL) { + goto exit; + } + + /* initialize pr_currentLibPath */ + +#ifdef XP_PC + ev = getenv("LD_LIBRARY_PATH"); + if (!ev) { + ev = ".;\\lib"; + } + ev = strdup(ev); +#endif + +#ifdef XP_MAC + { + char *p; + int len; + + ev = getenv("LD_LIBRARY_PATH"); + + if (!ev) + ev = ""; + + len = strlen(ev) + 1; /* +1 for the null */ +# ifdef VBOX_USE_IPRT_IN_NSPR + p = (char*) RTStrAlloc(len); +# else + p = (char*) malloc(len); +# endif + if (p) { + strcpy(p, ev); + } + ev = p; + } +#endif + +#if defined(XP_UNIX) || defined(XP_BEOS) +#if defined(USE_DLFCN) || defined(USE_MACH_DYLD) || defined(XP_BEOS) + { + char *p=NULL; + int len; + +#ifdef XP_BEOS + ev = getenv("LIBRARY_PATH"); + if (!ev) { + ev = "%A/lib:/boot/home/config/lib:/boot/beos/system/lib"; + } +#else +# if defined(VBOX) && defined(XP_MACOSX) + ev = getenv("DYLD_LIBRARY_PATH"); +# else + ev = getenv("LD_LIBRARY_PATH"); +# endif + if (!ev) { + ev = "/usr/lib:/lib"; + } +#endif + len = strlen(ev) + 1; /* +1 for the null */ + +# ifdef VBOX_USE_IPRT_IN_NSPR + p = (char*) RTStrAlloc(len); +# else + p = (char*) malloc(len); +# endif + if (p) { + strcpy(p, ev); + } /* if (p) */ + ev = p; + PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev)); + + } +#else + /* AFAIK there isn't a library path with the HP SHL interface --Rob */ + ev = strdup(""); +# endif +#endif + + /* + * If ev is NULL, we have run out of memory + */ + _pr_currentLibPath = ev; + + exit: + if (_pr_currentLibPath) { +#ifdef VBOX_USE_IPRT_IN_NSPR + copy = RTMemDup(_pr_currentLibPath, strlen(_pr_currentLibPath) + 1); +#else + copy = strdup(_pr_currentLibPath); +#endif + } + PR_ExitMonitor(pr_linker_lock); + if (!copy) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return copy; +} + +/* +** Build library name from path, lib and extensions +*/ +PR_IMPLEMENT(char*) +PR_GetLibraryName(const char *path, const char *lib) +{ + char *fullname; + +#ifdef XP_PC + if (strstr(lib, PR_DLL_SUFFIX) == NULL) + { + if (path) { + fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX); + } else { + fullname = PR_smprintf("%s%s", lib, PR_DLL_SUFFIX); + } + } else { + if (path) { + fullname = PR_smprintf("%s\\%s", path, lib); + } else { + fullname = PR_smprintf("%s", lib); + } + } +#endif /* XP_PC */ +#ifdef XP_MAC + if (path) { + fullname = PR_smprintf("%s%s", path, lib); + } else { + fullname = PR_smprintf("%s", lib); + } +#endif +#if defined(XP_UNIX) || defined(XP_BEOS) + if (strstr(lib, PR_DLL_SUFFIX) == NULL) + { + if (path) { + fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX); + } else { + fullname = PR_smprintf("lib%s%s", lib, PR_DLL_SUFFIX); + } + } else { + if (path) { + fullname = PR_smprintf("%s/%s", path, lib); + } else { + fullname = PR_smprintf("%s", lib); + } + } +#endif /* XP_UNIX || XP_BEOS */ + return fullname; +} + +/* +** Free the memory allocated, for the caller, by PR_GetLibraryName +*/ +PR_IMPLEMENT(void) +PR_FreeLibraryName(char *mem) +{ + PR_smprintf_free(mem); +} + +static PRLibrary* +pr_UnlockedFindLibrary(const char *name) +{ + PRLibrary* lm = pr_loadmap; + const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR); + np = np ? np + 1 : name; + while (lm) { + const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR); + cp = cp ? cp + 1 : lm->name; +#ifdef WIN32 + /* Windows DLL names are case insensitive... */ + if (strcmpi(np, cp) == 0) +#elif defined(XP_OS2) + if (stricmp(np, cp) == 0) +#else + if (strcmp(np, cp) == 0) +#endif + { + /* found */ + lm->refCount++; + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s incr => %d (find lib)", + lm->name, lm->refCount)); + return lm; + } + lm = lm->next; + } + return NULL; +} + +PR_IMPLEMENT(PRLibrary*) +PR_LoadLibraryWithFlags(PRLibSpec libSpec, PRIntn flags) +{ + if (flags == 0) { + flags = _PR_DEFAULT_LD_FLAGS; + } + switch (libSpec.type) { + case PR_LibSpec_Pathname: + return pr_LoadLibraryByPathname(libSpec.value.pathname, flags); +#ifdef XP_MAC + case PR_LibSpec_MacNamedFragment: + return pr_Mac_LoadNamedFragment( + libSpec.value.mac_named_fragment.fsspec, + libSpec.value.mac_named_fragment.name); + case PR_LibSpec_MacIndexedFragment: + return pr_Mac_LoadIndexedFragment( + libSpec.value.mac_indexed_fragment.fsspec, + libSpec.value.mac_indexed_fragment.index); +#endif /* XP_MAC */ + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } +} + +PR_IMPLEMENT(PRLibrary*) +PR_LoadLibrary(const char *name) +{ + PRLibSpec libSpec; + + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = name; + return PR_LoadLibraryWithFlags(libSpec, 0); +} + +#ifndef VBOX_USE_MORE_IPRT_IN_NSPR /* exclude big chunk */ +#if defined(USE_MACH_DYLD) +static NSModule +pr_LoadMachDyldModule(const char *name) +{ + NSObjectFileImage ofi; + NSModule h = NULL; + if (NSCreateObjectFileImageFromFile(name, &ofi) + == NSObjectFileImageSuccess) { + h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE + | NSLINKMODULE_OPTION_RETURN_ON_ERROR); + /* + * TODO: If NSLinkModule fails, use NSLinkEditError to retrieve + * error information. + */ + if (NSDestroyObjectFileImage(ofi) == FALSE) { + if (h) { + (void)NSUnLinkModule(h, NSUNLINKMODULE_OPTION_NONE); + h = NULL; + } + } + } + return h; +} +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) + +#ifdef XP_MACOSX +static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) +{ + static uint32 glue[6] = { 0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420 }; + uint32* newGlue = NULL; + + if (tvp != NULL) { + CFStringRef nameRef = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII); + if (nameRef) { + CFMutableDataRef glueData = (CFMutableDataRef) CFDictionaryGetValue(dict, nameRef); + if (glueData == NULL) { + glueData = CFDataCreateMutable(NULL, sizeof(glue)); + if (glueData != NULL) { + newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); + memcpy(newGlue, glue, sizeof(glue)); + newGlue[0] |= ((UInt32)tvp >> 16); + newGlue[1] |= ((UInt32)tvp & 0xFFFF); + MakeDataExecutable(newGlue, sizeof(glue)); + CFDictionaryAddValue(dict, nameRef, glueData); + CFRelease(glueData); + + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name)); + } + } else { + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name)); + + newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); + } + CFRelease(nameRef); + } + } + + return newGlue; +} +#endif + +/* +** macLibraryLoadProc is a function definition for a Mac shared library +** loading method. The "name" param is the same full or partial pathname +** that was passed to pr_LoadLibraryByPathName. The function must fill +** in the fields of "lm" which apply to its library type. Returns +** PR_SUCCESS if successful. +*/ + +typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm); + +static PRStatus +pr_LoadViaCFM(const char *name, PRLibrary *lm) +{ + OSErr err; + char cName[64]; + Str255 errName; + +#if !defined(XP_MACOSX) + Str255 pName; + /* + * Algorithm: The "name" passed in could be either a shared + * library name that we should look for in the normal library + * search paths, or a full path name to a specific library on + * disk. Since the full path will always contain a ":" + * (shortest possible path is "Volume:File"), and since a + * library name can not contain a ":", we can test for the + * presence of a ":" to see which type of library we should load. + * or its a full UNIX path which we for now assume is Java + * enumerating all the paths (see below) + */ + if (strchr(name, PR_PATH_SEPARATOR) == NULL) { + if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { + /* + * The name did not contain a ":", so it must be a + * library name. Convert the name to a Pascal string + * and try to find the library. + */ + } else { + /* + * name contained a "/" which means we need to suck off + * the last part of the path and pass that on the + * NSGetSharedLibrary. this may not be what we really + * want to do .. because Java could be iterating through + * the whole LD path, and we'll find it if it's anywhere + * on that path -- it appears that's what UNIX and the + * PC do too...so we'll emulate but it could be wrong. + */ + name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1; + } + + PStrFromCStr(name, pName); + + /* + * beard: NSGetSharedLibrary was so broken that I just decided to + * use GetSharedLibrary for now. This will need to change for + * plugins, but those should go in the Extensions folder anyhow. + */ + err = GetSharedLibrary(pName, kCompiledCFragArch, kReferenceCFrag, + &lm->connection, &lm->main, errName); + if (err != noErr) + return PR_FAILURE; + } + else +#endif + { + /* + * The name did contain a ":", so it must be a full path name. + * Now we have to do a lot of work to convert the path name to + * an FSSpec (silly, since we were probably just called from the + * MacFE plug-in code that already knew the FSSpec and converted + * it to a full path just to pass to us). Make an FSSpec from + * the full path and call GetDiskFragment. + */ + FSSpec fileSpec; + Boolean tempUnusedBool; + +#if defined(XP_MACOSX) + { + /* Use direct conversion of POSIX path to FSRef to FSSpec. */ + FSRef ref; + err = FSPathMakeRef((const UInt8*)name, &ref, NULL); + if (err == noErr) + err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, + &fileSpec, NULL); + } +#else + PStrFromCStr(name, pName); + err = FSMakeFSSpec(0, 0, pName, &fileSpec); +#endif + if (err != noErr) + return PR_FAILURE; + + /* Resolve an alias if this was one */ + err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, + &tempUnusedBool); + if (err != noErr) + return PR_FAILURE; + + /* Finally, try to load the library */ + err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, + kLoadCFrag, &lm->connection, &lm->main, errName); + +#if TARGET_CARBON + p2cstrcpy(cName, fileSpec.name); +#else + memcpy(cName, fileSpec.name + 1, fileSpec.name[0]); + cName[fileSpec.name[0]] = '\0'; +#endif + +#ifdef XP_MACOSX + if (err == noErr && lm->connection) { + /* + * if we're a mach-o binary, need to wrap all CFM function + * pointers. need a hash-table of already seen function + * pointers, etc. + */ + lm->wrappers = CFDictionaryCreateMutable(NULL, 16, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (lm->wrappers) { + lm->main = TV2FP(lm->wrappers, "main", lm->main); + } else + err = memFullErr; + } +#endif + } + return (err == noErr) ? PR_SUCCESS : PR_FAILURE; +} + +/* +** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle +** directory. The caller is responsible for calling CFRelease() to +** deallocate. +*/ + +#if TARGET_CARBON +static PRStatus +pr_LoadCFBundle(const char *name, PRLibrary *lm) +{ + CFURLRef bundleURL; + CFBundleRef bundle = NULL; + +#ifdef XP_MACOSX + char pathBuf[PATH_MAX]; + const char *resolvedPath; + CFStringRef pathRef; + + /* Takes care of relative paths and symlinks */ + resolvedPath = realpath(name, pathBuf); + if (!resolvedPath) + return PR_FAILURE; + + pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8); + if (pathRef) { + bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, + kCFURLPOSIXPathStyle, true); + if (bundleURL) { + bundle = CFBundleCreate(NULL, bundleURL); + CFRelease(bundleURL); + } + CFRelease(pathRef); + } +#else + OSErr err; + Str255 pName; + FSSpec fsSpec; + FSRef fsRef; + + if ((UInt32)(CFURLCreateFromFSRef) == kUnresolvedCFragSymbolAddress) + return PR_FAILURE; + PStrFromCStr(name, pName); + err = FSMakeFSSpec(0, 0, pName, &fsSpec); + if (err != noErr) + return PR_FAILURE; + err = FSpMakeFSRef(&fsSpec, &fsRef); + if (err != noErr) + return PR_FAILURE; + bundleURL = CFURLCreateFromFSRef(NULL, &fsRef); + if (bundleURL) { + bundle = CFBundleCreate(NULL, bundleURL); + CFRelease(bundleURL); + } +#endif + + lm->bundle = bundle; + return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE; +} +#endif + +#ifdef XP_MACOSX +static PRStatus +pr_LoadViaDyld(const char *name, PRLibrary *lm) +{ + lm->dlh = pr_LoadMachDyldModule(name); + if (lm->dlh == NULL) { + lm->image = NSAddImage(name, NSADDIMAGE_OPTION_RETURN_ON_ERROR + | NSADDIMAGE_OPTION_WITH_SEARCHING); + /* + * TODO: If NSAddImage fails, use NSLinkEditError to retrieve + * error information. + */ + } + return (lm->dlh != NULL || lm->image != NULL) ? PR_SUCCESS : PR_FAILURE; +} +#endif + +#endif /* defined(XP_MAC) || defined(XP_MACOSX) */ +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + +/* +** Dynamically load a library. Only load libraries once, so scan the load +** map first. +*/ +static PRLibrary* +pr_LoadLibraryByPathname(const char *name, PRIntn flags) +{ + PRLibrary *lm; + PRLibrary* result; + PRInt32 oserr; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + result = pr_UnlockedFindLibrary(name); + if (result != NULL) goto unlock; + + lm = PR_NEWZAP(PRLibrary); + if (lm == NULL) { + oserr = _MD_ERRNO(); + goto unlock; + } + lm->staticTable = NULL; + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR + oserr = RTLdrLoad(name, &lm->dlh); + if (RT_FAILURE(oserr)) + goto unlock; + lm->name = strdup(name); + lm->refCount = 1; + lm->next = pr_loadmap; + pr_loadmap = lm; + +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +#ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ + { + HMODULE h; + UCHAR pszError[_MAX_PATH]; + ULONG ulRc = NO_ERROR; + + ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); + if (ulRc != NO_ERROR) { + oserr = ulRc; + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif /* XP_OS2 */ + +#if defined(WIN32) || defined(WIN16) + { + HINSTANCE h; + NODL_PROC *pfn; + + h = LoadLibrary(name); + if (h < (HINSTANCE)HINSTANCE_ERROR) { + oserr = _MD_ERRNO(); + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; + + /* + ** Try to load a table of "static functions" provided by the DLL + */ + + pfn = (NODL_PROC *)GetProcAddress(h, "NODL_TABLE"); + if (pfn != NULL) { + lm->staticTable = (*pfn)(); + } + } +#endif /* WIN32 || WIN16 */ + +#if defined(XP_MAC) || defined(XP_MACOSX) + { + int i; + PRStatus status; + + static const macLibraryLoadProc loadProcs[] = { +#if defined(XP_MACOSX) + pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM +#elif TARGET_CARBON + pr_LoadViaCFM, pr_LoadCFBundle +#else + pr_LoadViaCFM +#endif + }; + + for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { + if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) + break; + } + if (status != PR_SUCCESS) { + oserr = cfragNoLibraryErr; + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) +#ifdef HAVE_DLL + { +#if defined(USE_DLFCN) +#ifdef NTO + /* Neutrino needs RTLD_GROUP to load Netscape plugins. (bug 71179) */ + int dl_flags = RTLD_GROUP; +#elif defined(AIX) + /* AIX needs RTLD_MEMBER to load an archive member. (bug 228899) */ + int dl_flags = RTLD_MEMBER; +#else + int dl_flags = 0; +#endif + void *h; + + if (flags & PR_LD_LAZY) { + dl_flags |= RTLD_LAZY; + } + if (flags & PR_LD_NOW) { + dl_flags |= RTLD_NOW; + } + if (flags & PR_LD_GLOBAL) { + dl_flags |= RTLD_GLOBAL; + } + if (flags & PR_LD_LOCAL) { + dl_flags |= RTLD_LOCAL; + } + h = dlopen(name, dl_flags); +#elif defined(USE_HPSHL) + int shl_flags = 0; + shl_t h; + + /* + * Use the DYNAMIC_PATH flag only if 'name' is a plain file + * name (containing no directory) to match the behavior of + * dlopen(). + */ + if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL) { + shl_flags |= DYNAMIC_PATH; + } + if (flags & PR_LD_LAZY) { + shl_flags |= BIND_DEFERRED; + } + if (flags & PR_LD_NOW) { + shl_flags |= BIND_IMMEDIATE; + } + /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ + h = shl_load(name, shl_flags, 0L); +#elif defined(USE_MACH_DYLD) + NSModule h = pr_LoadMachDyldModule(name); +#else +#error Configuration error +#endif + if (!h) { + oserr = _MD_ERRNO(); +#ifdef DEBUG + fprintf(stderr, "pr_LoadLibraryByPathname(): Failed to load '%s'\n", name); +#endif + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ + + lm->refCount = 1; + +#ifdef XP_BEOS + { + image_info info; + int32 cookie = 0; + image_id imageid = B_ERROR; + image_id stubid = B_ERROR; + PRLibrary *p; + + for (p = pr_loadmap; p != NULL; p = p->next) { + /* hopefully, our caller will always use the same string + to refer to the same library */ + if (strcmp(name, p->name) == 0) { + /* we've already loaded this library */ + imageid = info.id; + lm->refCount++; + break; + } + } + + if(imageid == B_ERROR) { + /* it appears the library isn't yet loaded - load it now */ + char stubName [B_PATH_NAME_LENGTH + 1]; + + /* the following is a work-around to a "bug" in the beos - + the beos system loader allows only 32M (system-wide) + to be used by code loaded as "add-ons" (code loaded + through the 'load_add_on()' system call, which includes + mozilla components), but allows 256M to be used by + shared libraries. + + unfortunately, mozilla is too large to fit into the + "add-on" space, so we must trick the loader into + loading some of the components as shared libraries. this + is accomplished by creating a "stub" add-on (an empty + shared object), and linking it with the component + (the actual .so file generated by the build process, + without any modifications). when this stub is loaded + by load_add_on(), the loader will automatically load the + component into the shared library space. + */ + + strcpy(stubName, name); + strcat(stubName, ".stub"); + + /* first, attempt to load the stub (thereby loading the + component as a shared library */ + if ((stubid = load_add_on(stubName)) > B_ERROR) { + /* the stub was loaded successfully. */ + imageid = B_FILE_NOT_FOUND; + + cookie = 0; + while (get_next_image_info(0, &cookie, &info) == B_OK) { + const char *endOfSystemName = strrchr(info.name, '/'); + const char *endOfPassedName = strrchr(name, '/'); + if( 0 == endOfSystemName ) + endOfSystemName = info.name; + else + endOfSystemName++; + if( 0 == endOfPassedName ) + endOfPassedName = name; + else + endOfPassedName++; + if (strcmp(endOfSystemName, endOfPassedName) == 0) { + /* this is the actual component - remember it */ + imageid = info.id; + break; + } + } + + } else { + /* we failed to load the "stub" - try to load the + component directly as an add-on */ + stubid = B_ERROR; + imageid = load_add_on(name); + } + } + + if (imageid <= B_ERROR) { + oserr = imageid; + PR_DELETE( lm ); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = (void*)imageid; + lm->stub_dlh = (void*)stubid; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + + result = lm; /* success */ + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); + + unlock: + if (result == NULL) { + PR_SetError(PR_LOAD_LIBRARY_ERROR, oserr); + DLLErrorInternal(oserr); /* sets error text */ + } + PR_ExitMonitor(pr_linker_lock); + return result; +} + +PR_IMPLEMENT(PRLibrary*) +PR_FindLibrary(const char *name) +{ + PRLibrary* result; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_EnterMonitor(pr_linker_lock); + result = pr_UnlockedFindLibrary(name); + PR_ExitMonitor(pr_linker_lock); + return result; +} + + +#ifdef XP_MAC + +static PRLibrary* +pr_Mac_LoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName) +{ + PRLibrary* newLib = NULL; + PRLibrary* result; + FSSpec resolvedSpec = *fileSpec; + CFragConnectionID connectionID = 0; + Boolean isFolder, wasAlias; + OSErr err = noErr; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + result = pr_UnlockedFindLibrary(fragmentName); + if (result != NULL) goto unlock; + + newLib = PR_NEWZAP(PRLibrary); + if (newLib == NULL) goto unlock; + newLib->staticTable = NULL; + + + /* Resolve an alias if this was one */ + err = ResolveAliasFile(&resolvedSpec, true, &isFolder, &wasAlias); + if (err != noErr) + goto unlock; + + if (isFolder) + { + err = fnfErr; + goto unlock; + } + + /* Finally, try to load the library */ + err = NSLoadNamedFragment(&resolvedSpec, fragmentName, &connectionID); + if (err != noErr) + goto unlock; + + newLib->name = strdup(fragmentName); + newLib->connection = connectionID; + newLib->next = pr_loadmap; + pr_loadmap = newLib; + + result = newLib; /* success */ + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", newLib->name)); + +unlock: + if (result == NULL) { + if (newLib != NULL) + PR_DELETE(newLib); + PR_SetError(PR_LOAD_LIBRARY_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); /* sets error text */ + } + PR_ExitMonitor(pr_linker_lock); + return result; +} + + +static PRLibrary* +pr_Mac_LoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragIndex) +{ + PRLibrary* newLib = NULL; + PRLibrary* result; + FSSpec resolvedSpec = *fileSpec; + char* fragmentName = NULL; + UInt32 fragOffset, fragLength; + CFragConnectionID connectionID = 0; + Boolean isFolder, wasAlias; + OSErr err = noErr; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + /* Resolve an alias if this was one */ + err = ResolveAliasFile(&resolvedSpec, true, &isFolder, &wasAlias); + if (err != noErr) + goto unlock; + + if (isFolder) + { + err = fnfErr; + goto unlock; + } + err = GetIndexedFragmentOffsets(&resolvedSpec, fragIndex, &fragOffset, &fragLength, &fragmentName); + if (err != noErr) goto unlock; + + result = pr_UnlockedFindLibrary(fragmentName); + free(fragmentName); + fragmentName = NULL; + if (result != NULL) goto unlock; + + newLib = PR_NEWZAP(PRLibrary); + if (newLib == NULL) goto unlock; + newLib->staticTable = NULL; + + /* Finally, try to load the library */ + err = NSLoadIndexedFragment(&resolvedSpec, fragIndex, &fragmentName, &connectionID); + if (err != noErr) { + PR_DELETE(newLib); + goto unlock; + } + + newLib->name = fragmentName; /* was malloced in NSLoadIndexedFragment */ + newLib->connection = connectionID; + newLib->next = pr_loadmap; + pr_loadmap = newLib; + + result = newLib; /* success */ + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", newLib->name)); + +unlock: + if (result == NULL) { + if (newLib != NULL) + PR_DELETE(newLib); + PR_SetError(PR_LOAD_LIBRARY_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); /* sets error text */ + } + PR_ExitMonitor(pr_linker_lock); + return result; +} + + +#endif + +/* +** Unload a shared library which was loaded via PR_LoadLibrary +*/ +PR_IMPLEMENT(PRStatus) +PR_UnloadLibrary(PRLibrary *lib) +{ + int result = 0; + PRStatus status = PR_SUCCESS; + + if ((lib == 0) || (lib->refCount <= 0)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + + PR_EnterMonitor(pr_linker_lock); + if (--lib->refCount > 0) { + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s decr => %d", + lib->name, lib->refCount)); + goto done; + } + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR + result = RTLdrClose(lib->dlh); + lib->dlh = NIL_RTLDRMOD; + +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +#ifdef XP_BEOS + if(((image_id)lib->stub_dlh) == B_ERROR) + unload_add_on( (image_id) lib->dlh ); + else + unload_add_on( (image_id) lib->stub_dlh); +#endif + +#ifdef XP_UNIX +#ifdef HAVE_DLL +#ifdef USE_DLFCN + result = dlclose(lib->dlh); +#elif defined(USE_HPSHL) + result = shl_unload(lib->dlh); +#elif defined(USE_MACH_DYLD) + result = NSUnLinkModule(lib->dlh, NSUNLINKMODULE_OPTION_NONE) ? 0 : -1; +#else +#error Configuration error +#endif +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ +#ifdef XP_PC + if (lib->dlh) { + FreeLibrary((HINSTANCE)(lib->dlh)); + lib->dlh = (HINSTANCE)NULL; + } +#endif /* XP_PC */ + +#if defined(XP_MAC) || defined(XP_MACOSX) + /* Close the connection */ + if (lib->connection) + CloseConnection(&(lib->connection)); +#if TARGET_CARBON + if (lib->bundle) + CFRelease(lib->bundle); +#endif +#if defined(XP_MACOSX) + if (lib->wrappers) + CFRelease(lib->wrappers); + /* No way to unload an image (lib->image) */ +#endif +#endif +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + + /* unlink from library search list */ + if (pr_loadmap == lib) + pr_loadmap = pr_loadmap->next; + else if (pr_loadmap != NULL) { + PRLibrary* prev = pr_loadmap; + PRLibrary* next = pr_loadmap->next; + while (next != NULL) { + if (next == lib) { + prev->next = next->next; + goto freeLib; + } + prev = next; + next = next->next; + } + /* + * fail (the library is not on the _pr_loadmap list), + * but don't wipe out an error from dlclose/shl_unload. + */ + PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent"); + if (result == 0) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } + } + /* + * We free the PRLibrary structure whether dlclose/shl_unload + * succeeds or not. + */ + + freeLib: + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name)); +#ifdef VBOX_USE_IPRT_IN_NSPR + RTStrFree(lib->name); +#else + free(lib->name); +#endif + lib->name = NULL; + PR_DELETE(lib); + if (result != 0) { + PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + status = PR_FAILURE; + } + +done: + PR_ExitMonitor(pr_linker_lock); + return status; +} + +static void* +pr_FindSymbolInLib(PRLibrary *lm, const char *name) +{ + void *f = NULL; +#ifdef XP_OS2 + int rc; +#endif + + if (lm->staticTable != NULL) { + const PRStaticLinkTable* tp; + for (tp = lm->staticTable; tp->name; tp++) { + if (strcmp(name, tp->name) == 0) { + return (void*) tp->fp; + } + } + /* + ** If the symbol was not found in the static table then check if + ** the symbol was exported in the DLL... Win16 only!! + */ +#if !defined(WIN16) && !defined(XP_BEOS) + PR_SetError(PR_FIND_SYMBOL_ERROR, 0); + return (void*)NULL; +#endif + } + +#ifdef VBOX_USE_MORE_IPRT_IN_NSPR + if (RT_FAILURE(RTLdrGetSymbol(lm->dlh, name, &f))) + f = NULL; + +#else /* !VBOX_USE_MORE_IPRT_IN_NSPR */ +#ifdef XP_OS2 + rc = DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); +#if defined(NEED_LEADING_UNDERSCORE) + /* + * Older plugins (not built using GCC) will have symbols that are not + * underscore prefixed. We check for that here. + */ + if (rc != NO_ERROR) { + name++; + DosQueryProcAddr(lm->dlh, 0, (PSZ) name, (PFN *) &f); + } +#endif +#endif /* XP_OS2 */ + +#if defined(WIN32) || defined(WIN16) + f = GetProcAddress(lm->dlh, name); +#endif /* WIN32 || WIN16 */ + +#if defined(XP_MAC) || defined(XP_MACOSX) +#if defined(NEED_LEADING_UNDERSCORE) +#define SYM_OFFSET 1 +#else +#define SYM_OFFSET 0 +#endif +#if TARGET_CARBON + if (lm->bundle) { + CFStringRef nameRef = CFStringCreateWithCString(NULL, name + SYM_OFFSET, kCFStringEncodingASCII); + if (nameRef) { + f = CFBundleGetFunctionPointerForName(lm->bundle, nameRef); + CFRelease(nameRef); + } + } +#endif + if (lm->connection) { + Ptr symAddr; + CFragSymbolClass symClass; + Str255 pName; + + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); + + PStrFromCStr(name + SYM_OFFSET, pName); + +#if defined(XP_MACOSX) + f = (FindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; +#else + f = (NSFindSymbol(lm->connection, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL; +#endif + +#if defined(XP_MACOSX) + /* callers expect mach-o function pointers, so must wrap tvectors with glue. */ + if (f && symClass == kTVectorCFragSymbol) { + f = TV2FP(lm->wrappers, name + SYM_OFFSET, f); + } +#endif + + if (f == NULL && strcmp(name + SYM_OFFSET, "main") == 0) f = lm->main; + } +#if defined(XP_MACOSX) + if (lm->image) { + NSSymbol symbol; + symbol = NSLookupSymbolInImage(lm->image, name, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); + if (symbol != NULL) + f = NSAddressOfSymbol(symbol); + else + f = NULL; + } +#endif +#undef SYM_OFFSET +#endif /* XP_MAC */ + +#ifdef XP_BEOS + if( B_NO_ERROR != get_image_symbol( (image_id)lm->dlh, name, B_SYMBOL_TYPE_TEXT, &f ) ) { + f = NULL; + } +#endif + +#ifdef XP_UNIX +#ifdef HAVE_DLL +#ifdef USE_DLFCN + f = dlsym(lm->dlh, name); +#elif defined(USE_HPSHL) + if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1) { + f = NULL; + } +#elif defined(USE_MACH_DYLD) + if (lm->dlh) { + NSSymbol symbol; + symbol = NSLookupSymbolInModule(lm->dlh, name); + if (symbol != NULL) + f = NSAddressOfSymbol(symbol); + else + f = NULL; + } +#endif +#endif /* HAVE_DLL */ +#endif /* XP_UNIX */ +#endif /* !VBOX_USE_MORE_IPRT_IN_NSPR */ + if (f == NULL) { + PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + } + return f; +} + +/* +** Called by class loader to resolve missing native's +*/ +PR_IMPLEMENT(void*) +PR_FindSymbol(PRLibrary *lib, const char *raw_name) +{ + void *f = NULL; +#if defined(NEED_LEADING_UNDERSCORE) + char *name; +#else + const char *name; +#endif + /* + ** Mangle the raw symbol name in any way that is platform specific. + */ +#if defined(NEED_LEADING_UNDERSCORE) + /* Need a leading _ */ + name = PR_smprintf("_%s", raw_name); +#elif defined(AIX) + /* + ** AIX with the normal linker put's a "." in front of the symbol + ** name. When use "svcc" and "svld" then the "." disappears. Go + ** figure. + */ + name = raw_name; +#else + name = raw_name; +#endif + + PR_EnterMonitor(pr_linker_lock); + PR_ASSERT(lib != NULL); + f = pr_FindSymbolInLib(lib, name); + +#if defined(NEED_LEADING_UNDERSCORE) + PR_smprintf_free(name); +#endif + + PR_ExitMonitor(pr_linker_lock); + return f; +} + +/* +** Return the address of the function 'raw_name' in the library 'lib' +*/ +PR_IMPLEMENT(PRFuncPtr) +PR_FindFunctionSymbol(PRLibrary *lib, const char *raw_name) +{ + return ((PRFuncPtr) PR_FindSymbol(lib, raw_name)); +} + +PR_IMPLEMENT(void*) +PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) +{ + void *f = NULL; +#if defined(NEED_LEADING_UNDERSCORE) + char *name; +#else + const char *name; +#endif + PRLibrary* lm; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + /* + ** Mangle the raw symbol name in any way that is platform specific. + */ +#if defined(NEED_LEADING_UNDERSCORE) + /* Need a leading _ */ + name = PR_smprintf("_%s", raw_name); +#elif defined(AIX) + /* + ** AIX with the normal linker put's a "." in front of the symbol + ** name. When use "svcc" and "svld" then the "." disappears. Go + ** figure. + */ + name = raw_name; +#else + name = raw_name; +#endif + + PR_EnterMonitor(pr_linker_lock); + + /* search all libraries */ + for (lm = pr_loadmap; lm != NULL; lm = lm->next) { + f = pr_FindSymbolInLib(lm, name); + if (f != NULL) { + *lib = lm; + lm->refCount++; + PR_LOG(_pr_linker_lm, PR_LOG_MIN, + ("%s incr => %d (for %s)", + lm->name, lm->refCount, name)); + break; + } + } +#if defined(NEED_LEADING_UNDERSCORE) + PR_smprintf_free(name); +#endif + + PR_ExitMonitor(pr_linker_lock); + return f; +} + +PR_IMPLEMENT(PRFuncPtr) +PR_FindFunctionSymbolAndLibrary(const char *raw_name, PRLibrary* *lib) +{ + return ((PRFuncPtr) PR_FindSymbolAndLibrary(raw_name, lib)); +} + +/* +** Add a static library to the list of loaded libraries. If LoadLibrary +** is called with the name then we will pretend it was already loaded +*/ +PR_IMPLEMENT(PRLibrary*) +PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt) +{ + PRLibrary *lm=NULL; + PRLibrary* result = NULL; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + /* If the lbrary is already loaded, then add the static table information... */ + result = pr_UnlockedFindLibrary(name); + if (result != NULL) { + PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) ); + result->staticTable = slt; + goto unlock; + } + + /* Add library to list...Mark it static */ + lm = PR_NEWZAP(PRLibrary); + if (lm == NULL) goto unlock; + + lm->name = strdup(name); + lm->refCount = 1; +#if defined(XP_MAC) && !defined(VBOX_USE_MORE_IPRT_IN_NSPR) + lm->connection = pr_exe_loadmap ? pr_exe_loadmap->connection : 0; +#else + lm->dlh = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0; +#endif + lm->staticTable = slt; + lm->next = pr_loadmap; + pr_loadmap = lm; + + result = lm; /* success */ + PR_ASSERT(lm->refCount == 1); + unlock: + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name)); + PR_ExitMonitor(pr_linker_lock); + return result; +} + +PR_IMPLEMENT(char *) +PR_GetLibraryFilePathname(const char *name, PRFuncPtr addr) +{ +#if defined(SOLARIS) || defined(LINUX) || defined(FREEBSD) + Dl_info dli; + char *result; + + if (dladdr((void *)addr, &dli) == 0) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(dli.dli_fname)+1); + if (result != NULL) { + strcpy(result, dli.dli_fname); + } + return result; +#elif defined(USE_MACH_DYLD) + char *result; + char const *image_name; + int i, count = _dyld_image_count(); + + for (i = 0; i < count; i++) { + image_name = _dyld_get_image_name(i); + if (strstr(image_name, name) != NULL) { + result = PR_Malloc(strlen(image_name)+1); + if (result != NULL) { + strcpy(result, image_name); + } + return result; + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(AIX) + char *result; +#define LD_INFO_INCREMENT 64 + struct ld_info *info; + unsigned int info_length = LD_INFO_INCREMENT * sizeof(struct ld_info); + struct ld_info *infop; + + for (;;) { + info = PR_Malloc(info_length); + if (info == NULL) { + return NULL; + } + /* If buffer is too small, loadquery fails with ENOMEM. */ + if (loadquery(L_GETINFO, info, info_length) != -1) { + break; + } + PR_Free(info); + if (errno != ENOMEM) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + /* retry with a larger buffer */ + info_length += LD_INFO_INCREMENT * sizeof(struct ld_info); + } + + for (infop = info; + ; + infop = (struct ld_info *)((char *)infop + infop->ldinfo_next)) { + if (strstr(infop->ldinfo_filename, name) != NULL) { + result = PR_Malloc(strlen(infop->ldinfo_filename)+1); + if (result != NULL) { + strcpy(result, infop->ldinfo_filename); + } + break; + } + if (!infop->ldinfo_next) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + result = NULL; + break; + } + } + PR_Free(info); + return result; +#elif defined(OSF1) + /* Contributed by Steve Streeter of HP */ + ldr_process_t process, ldr_my_process(); + ldr_module_t mod_id; + ldr_module_info_t info; + ldr_region_t regno; + ldr_region_info_t reginfo; + size_t retsize; + int rv; + char *result; + + /* Get process for which dynamic modules will be listed */ + + process = ldr_my_process(); + + /* Attach to process */ + + rv = ldr_xattach(process); + if (rv) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + + /* Print information for list of modules */ + + mod_id = LDR_NULL_MODULE; + + for (;;) { + + /* Get information for the next module in the module list. */ + + ldr_next_module(process, &mod_id); + if (ldr_inq_module(process, mod_id, &info, sizeof(info), + &retsize) != 0) { + /* No more modules */ + break; + } + if (retsize < sizeof(info)) { + continue; + } + + /* + * Get information for each region in the module and check if any + * contain the address of this function. + */ + + for (regno = 0; ; regno++) { + if (ldr_inq_region(process, mod_id, regno, ®info, + sizeof(reginfo), &retsize) != 0) { + /* No more regions */ + break; + } + if (((unsigned long)reginfo.lri_mapaddr <= + (unsigned long)addr) && + (((unsigned long)reginfo.lri_mapaddr + reginfo.lri_size) > + (unsigned long)addr)) { + /* Found it. */ + result = PR_Malloc(strlen(info.lmi_name)+1); + if (result != NULL) { + strcpy(result, info.lmi_name); + } + return result; + } + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(VMS) + /* Contributed by Colin Blake of HP */ + struct _imcb *icb; + ulong_t status; + char device_name[MAX_DEVNAM]; + int device_name_len; + $DESCRIPTOR (device_name_desc, device_name); + struct fibdef fib; + struct dsc$descriptor_s fib_desc = + { sizeof(struct fibdef), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&fib } ; + IOSB iosb; + ITMLST devlst[2] = { + {MAX_DEVNAM, DVI$_ALLDEVNAM, device_name, &device_name_len}, + {0,0,0,0}}; + short file_name_len; + char file_name[MAX_FILNAM+1]; + char *result = NULL; + struct dsc$descriptor_s file_name_desc = + { MAX_FILNAM, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char *) &file_name[0] } ; + + /* + ** The address for the process image list could change in future versions + ** of the operating system. 7FFD0688 is valid for V7.2 and V7.3 releases, + ** so we use that for the default, but allow an environment variable + ** (logical name) to override. + */ + if (IAC$GL_IMAGE_LIST == NULL) { + char *p = getenv("MOZILLA_IAC_GL_IMAGE_LIST"); + if (p) + IAC$GL_IMAGE_LIST = (struct _imcb *) strtol(p,NULL,0); + else + IAC$GL_IMAGE_LIST = (struct _imcb *) 0x7FFD0688; + } + + for (icb = IAC$GL_IMAGE_LIST->imcb$l_flink; + icb != IAC$GL_IMAGE_LIST; + icb = icb->imcb$l_flink) { + if (((void *)addr >= icb->imcb$l_starting_address) && + ((void *)addr <= icb->imcb$l_end_address)) { + /* + ** This is the correct image. + ** Get the device name. + */ + status = sys$getdviw(0,icb->imcb$w_chan,0,&devlst,0,0,0,0); + if ($VMS_STATUS_SUCCESS(status)) + device_name_desc.dsc$w_length = device_name_len; + + /* + ** Get the FID. + */ + memset(&fib,0,sizeof(struct fibdef)); + status = sys$qiow(0,icb->imcb$w_chan,IO$_ACCESS,&iosb, + 0,0,&fib_desc,0,0,0,0,0); + + /* + ** If we got the FID, now look up its name (if for some reason + ** we didn't get the device name, this call will fail). + */ + if (($VMS_STATUS_SUCCESS(status)) && ($VMS_STATUS_SUCCESS(iosb.cond))) { + status = lib$fid_to_name ( + &device_name_desc, + &fib.fib$w_fid, + &file_name_desc, + &file_name_len, + 0, 0); + + /* + ** If we succeeded then remove the version number and + ** return a copy of the UNIX format version of the file name. + */ + if ($VMS_STATUS_SUCCESS(status)) { + char *p, *result; + file_name[file_name_len] = 0; + p = strrchr(file_name,';'); + if (p) *p = 0; + p = decc$translate_vms(&file_name[0]); + result = PR_Malloc(strlen(p)+1); + if (result != NULL) { + strcpy(result, p); + } + return result; + } + } + } + } + + /* Didn't find it */ + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; + +#elif defined(HPUX) && defined(USE_HPSHL) + int index; + struct shl_descriptor desc; + char *result; + + for (index = 0; shl_get_r(index, &desc) == 0; index++) { + if (strstr(desc.filename, name) != NULL) { + result = PR_Malloc(strlen(desc.filename)+1); + if (result != NULL) { + strcpy(result, desc.filename); + } + return result; + } + } + /* + * Since the index value of a library is decremented if + * a library preceding it in the shared library search + * list was unloaded, it is possible that we missed some + * libraries as we went up the list. So we should go + * down the list to be sure that we not miss anything. + */ + for (index--; index >= 0; index--) { + if ((shl_get_r(index, &desc) == 0) + && (strstr(desc.filename, name) != NULL)) { + result = PR_Malloc(strlen(desc.filename)+1); + if (result != NULL) { + strcpy(result, desc.filename); + } + return result; + } + } + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, 0); + return NULL; +#elif defined(HPUX) && defined(USE_DLFCN) + struct load_module_desc desc; + char *result; + const char *module_name; + + if (dlmodinfo((unsigned long)addr, &desc, sizeof desc, NULL, 0, 0) == 0) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + module_name = dlgetname(&desc, sizeof desc, NULL, 0, 0); + if (module_name == NULL) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#elif defined(WIN32) + HMODULE handle; + char module_name[MAX_PATH]; + char *result; + + handle = GetModuleHandle(name); + if (handle == NULL) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + if (GetModuleFileName(handle, module_name, sizeof module_name) == 0) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#elif defined(XP_OS2) + HMODULE module = NULL; + char module_name[_MAX_PATH]; + char *result; + APIRET ulrc = DosQueryModFromEIP(&module, NULL, 0, NULL, NULL, (ULONG) addr); + if ((NO_ERROR != ulrc) || (NULL == module) ) { + PR_SetError(PR_LIBRARY_NOT_LOADED_ERROR, _MD_ERRNO()); + DLLErrorInternal(_MD_ERRNO()); + return NULL; + } + ulrc = DosQueryModuleName(module, sizeof module_name, module_name); + if (NO_ERROR != ulrc) { + /* should not happen */ + _PR_MD_MAP_DEFAULT_ERROR(_MD_ERRNO()); + return NULL; + } + result = PR_Malloc(strlen(module_name)+1); + if (result != NULL) { + strcpy(result, module_name); + } + return result; +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/malloc/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/malloc/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/Makefile.in new file mode 100644 index 00000000..981ec462 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/Makefile.in @@ -0,0 +1,67 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +CSRCS = prmalloc.c prmem.c + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmalloc.c b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmalloc.c new file mode 100644 index 00000000..10e9cf78 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmalloc.c @@ -0,0 +1,1174 @@ +/* -*- 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" + +/* +** We override malloc etc. on any platform which has preemption + +** nspr20 user level threads. When we're debugging, we can make our +** version of malloc fail occasionally. +*/ +#ifdef _PR_OVERRIDE_MALLOC + +/* +** Thread safe version of malloc, calloc, realloc, free +*/ +#include + +#ifdef DEBUG +#define SANITY +#define EXTRA_SANITY +#else +#undef SANITY +#undef EXTRA_SANITY +#endif + +/* Forward decls */ +void *_PR_UnlockedMalloc(size_t size); +void _PR_UnlockedFree(void *ptr); +void *_PR_UnlockedRealloc(void *ptr, size_t size); +void *_PR_UnlockedCalloc(size_t n, size_t elsize); + +/************************************************************************/ + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + */ + +/* + * Defining SANITY will enable some checks which will tell you if the users + * program did botch something + */ + +/* + * Defining EXTRA_SANITY will enable some checks which are mostly related + * to internal conditions in malloc.c + */ + +/* + * Very verbose progress on stdout... + */ +#if 0 +# define TRACE(foo) printf foo +static int malloc_event; +#else +# define TRACE(foo) +#endif + +/* XXX Pick a number, any number */ +# define malloc_pagesize 4096UL +# define malloc_pageshift 12UL + +#ifdef XP_UNIX +#include +#include +#include +#include +#include +#include +#include +#endif + +/* + * This structure describes a page's worth of chunks. + */ + +struct pginfo { + struct pginfo *next; /* next on the free list */ + char *page; /* Pointer to the page */ + u_short size; /* size of this page's chunks */ + u_short shift; /* How far to shift for this size chunks */ + u_short free; /* How many free chunks */ + u_short total; /* How many chunk */ + u_long bits[1]; /* Which chunks are free */ +}; + +struct pgfree { + struct pgfree *next; /* next run of free pages */ + struct pgfree *prev; /* prev run of free pages */ + char *page; /* pointer to free pages */ + char *end; /* pointer to end of free pages */ + u_long size; /* number of bytes free */ +}; + +/* + * How many bits per u_long in the bitmap. + * Change only if not 8 bits/byte + */ +#define MALLOC_BITS (8*sizeof(u_long)) + +/* + * Magic values to put in the page_directory + */ +#define MALLOC_NOT_MINE ((struct pginfo*) 0) +#define MALLOC_FREE ((struct pginfo*) 1) +#define MALLOC_FIRST ((struct pginfo*) 2) +#define MALLOC_FOLLOW ((struct pginfo*) 3) +#define MALLOC_MAGIC ((struct pginfo*) 4) + +/* + * Set to one when malloc_init has been called + */ +static unsigned initialized; + +/* + * The size of a page. + * Must be a integral multiplum of the granularity of mmap(2). + * Your toes will curl if it isn't a power of two + */ +#define malloc_pagemask ((malloc_pagesize)-1) + +/* + * The size of the largest chunk. + * Half a page. + */ +#define malloc_maxsize ((malloc_pagesize)>>1) + +/* + * malloc_pagesize == 1 << malloc_pageshift + */ +#ifndef malloc_pageshift +static unsigned malloc_pageshift; +#endif /* malloc_pageshift */ + +/* + * The smallest allocation we bother about. + * Must be power of two + */ +#ifndef malloc_minsize +static unsigned malloc_minsize; +#endif /* malloc_minsize */ + +/* + * The largest chunk we care about. + * Must be smaller than pagesize + * Must be power of two + */ +#ifndef malloc_maxsize +static unsigned malloc_maxsize; +#endif /* malloc_maxsize */ + +#ifndef malloc_cache +static unsigned malloc_cache; +#endif /* malloc_cache */ + +/* + * The offset from pagenumber to index into the page directory + */ +static u_long malloc_origo; + +/* + * The last index in the page directory we care about + */ +static u_long last_index; + +/* + * Pointer to page directory. + * Allocated "as if with" malloc + */ +static struct pginfo **page_dir; + +/* + * How many slots in the page directory + */ +static unsigned malloc_ninfo; + +/* + * Free pages line up here + */ +static struct pgfree free_list; + +/* + * Abort() if we fail to get VM ? + */ +static int malloc_abort; + +#ifdef SANITY +/* + * Are we trying to die ? + */ +static int suicide; +#endif + +/* + * dump statistics + */ +static int malloc_stats; + +/* + * always realloc ? + */ +static int malloc_realloc; + +/* + * my last break. + */ +static void *malloc_brk; + +/* + * one location cache for free-list holders + */ +static struct pgfree *px; + +static int set_pgdir(void *ptr, struct pginfo *info); +static int extend_page_directory(u_long index); + +#ifdef SANITY +void +malloc_dump(FILE *fd) +{ + struct pginfo **pd; + struct pgfree *pf; + int j; + + pd = page_dir; + + /* print out all the pages */ + for(j=0;j<=last_index;j++) { + fprintf(fd,"%08lx %5d ",(j+malloc_origo) << malloc_pageshift,j); + if (pd[j] == MALLOC_NOT_MINE) { + for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) + ; + j--; + fprintf(fd,".. %5d not mine\n", j); + } else if (pd[j] == MALLOC_FREE) { + for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) + ; + j--; + fprintf(fd,".. %5d free\n", j); + } else if (pd[j] == MALLOC_FIRST) { + for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) + ; + j--; + fprintf(fd,".. %5d in use\n", j); + } else if (pd[j] < MALLOC_MAGIC) { + fprintf(fd,"(%p)\n", pd[j]); + } else { + fprintf(fd,"%p %d (of %d) x %d @ %p --> %p\n", + pd[j],pd[j]->free, pd[j]->total, + pd[j]->size, pd[j]->page, pd[j]->next); + } + } + + for(pf=free_list.next; pf; pf=pf->next) { + fprintf(fd,"Free: @%p [%p...%p[ %ld ->%p <-%p\n", + pf,pf->page,pf->end,pf->size,pf->prev,pf->next); + if (pf == pf->next) { + fprintf(fd,"Free_list loops.\n"); + break; + } + } + + /* print out various info */ + fprintf(fd,"Minsize\t%d\n",malloc_minsize); + fprintf(fd,"Maxsize\t%ld\n",malloc_maxsize); + fprintf(fd,"Pagesize\t%ld\n",malloc_pagesize); + fprintf(fd,"Pageshift\t%ld\n",malloc_pageshift); + fprintf(fd,"FirstPage\t%ld\n",malloc_origo); + fprintf(fd,"LastPage\t%ld %lx\n",last_index+malloc_pageshift, + (last_index + malloc_pageshift) << malloc_pageshift); + fprintf(fd,"Break\t%ld\n",(u_long)sbrk(0) >> malloc_pageshift); +} + +static void wrterror(char *fmt, ...) +{ + char *q = "malloc() error: "; + char buf[100]; + va_list ap; + + suicide = 1; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fputs(q, stderr); + fputs(buf, stderr); + + malloc_dump(stderr); + PR_Abort(); +} + +static void wrtwarning(char *fmt, ...) +{ + char *q = "malloc() warning: "; + char buf[100]; + va_list ap; + + va_start(ap, fmt); + PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fputs(q, stderr); + fputs(buf, stderr); +} +#endif /* SANITY */ + + +/* + * Allocate a number of pages from the OS + */ +static caddr_t +map_pages(int pages, int update) +{ + caddr_t result,tail; + + result = ((caddr_t)sbrk(0)) + malloc_pagemask - 1; + result = (caddr_t) ((u_long)result & ~malloc_pagemask); + tail = result + (pages << malloc_pageshift); + if (!brk(tail)) { + last_index = ((u_long)tail >> malloc_pageshift) - malloc_origo -1; + malloc_brk = tail; + TRACE(("%6d S %p .. %p\n",malloc_event++, result, tail)); + if (!update || last_index < malloc_ninfo || + extend_page_directory(last_index)) + return result; + } + TRACE(("%6d s %d %p %d\n",malloc_event++,pages,sbrk(0),errno)); +#ifdef EXTRA_SANITY + wrterror("map_pages fails\n"); +#endif + return 0; +} + +#define set_bit(_pi,_bit) \ + (_pi)->bits[(_bit)/MALLOC_BITS] |= 1L<<((_bit)%MALLOC_BITS) + +#define clr_bit(_pi,_bit) \ + (_pi)->bits[(_bit)/MALLOC_BITS] &= ~(1L<<((_bit)%MALLOC_BITS)); + +#define tst_bit(_pi,_bit) \ + ((_pi)->bits[(_bit)/MALLOC_BITS] & (1L<<((_bit)%MALLOC_BITS))) + +/* + * Extend page directory + */ +static int +extend_page_directory(u_long index) +{ + struct pginfo **young, **old; + int i; + + TRACE(("%6d E %lu\n",malloc_event++,index)); + + /* Make it this many pages */ + i = index * sizeof *page_dir; + i /= malloc_pagesize; + i += 2; + + /* Get new pages, if you used this much mem you don't care :-) */ + young = (struct pginfo**) map_pages(i,0); + if (!young) + return 0; + + /* Copy the old stuff */ + memset(young, 0, i * malloc_pagesize); + memcpy(young, page_dir, + malloc_ninfo * sizeof *page_dir); + + /* register the new size */ + malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; + + /* swap the pointers */ + old = page_dir; + page_dir = young; + + /* Mark the pages */ + index = ((u_long)young >> malloc_pageshift) - malloc_origo; + page_dir[index] = MALLOC_FIRST; + while (--i) { + page_dir[++index] = MALLOC_FOLLOW; + } + + /* Now free the old stuff */ + _PR_UnlockedFree(old); + return 1; +} + +/* + * Set entry in page directory. + * Extend page directory if need be. + */ +static int +set_pgdir(void *ptr, struct pginfo *info) +{ + u_long index = ((u_long)ptr >> malloc_pageshift) - malloc_origo; + + if (index >= malloc_ninfo && !extend_page_directory(index)) + return 0; + page_dir[index] = info; + return 1; +} + +/* + * Initialize the world + */ +static void +malloc_init (void) +{ + int i; + char *p; + + TRACE(("%6d I\n",malloc_event++)); +#ifdef DEBUG + for (p=getenv("MALLOC_OPTIONS"); p && *p; p++) { + switch (*p) { + case 'a': malloc_abort = 0; break; + case 'A': malloc_abort = 1; break; + case 'd': malloc_stats = 0; break; + case 'D': malloc_stats = 1; break; + case 'r': malloc_realloc = 0; break; + case 'R': malloc_realloc = 1; break; + default: + wrtwarning("Unknown chars in MALLOC_OPTIONS\n"); + break; + } + } +#endif + +#ifndef malloc_pagesize + /* determine our pagesize */ + malloc_pagesize = getpagesize(); +#endif /* malloc_pagesize */ + +#ifndef malloc_pageshift + /* determine how much we shift by to get there */ + for (i = malloc_pagesize; i > 1; i >>= 1) + malloc_pageshift++; +#endif /* malloc_pageshift */ + +#ifndef malloc_cache + malloc_cache = 50 << malloc_pageshift; +#endif /* malloc_cache */ + +#ifndef malloc_minsize + /* + * find the smallest size allocation we will bother about. + * this is determined as the smallest allocation that can hold + * it's own pginfo; + */ + i = 2; + for(;;) { + int j; + + /* Figure out the size of the bits */ + j = malloc_pagesize/i; + j /= 8; + if (j < sizeof(u_long)) + j = sizeof (u_long); + if (sizeof(struct pginfo) + j - sizeof (u_long) <= i) + break; + i += i; + } + malloc_minsize = i; +#endif /* malloc_minsize */ + + + /* Allocate one page for the page directory */ + page_dir = (struct pginfo **) map_pages(1,0); +#ifdef SANITY + if (!page_dir) + wrterror("fatal: my first mmap failed. (check limits ?)\n"); +#endif + + /* + * We need a maximum of malloc_pageshift buckets, steal these from the + * front of the page_directory; + */ + malloc_origo = (u_long) page_dir >> malloc_pageshift; + malloc_origo -= malloc_pageshift; + + /* Clear it */ + memset(page_dir,0,malloc_pagesize); + + /* Find out how much it tells us */ + malloc_ninfo = malloc_pagesize / sizeof *page_dir; + + /* Plug the page directory into itself */ + i = set_pgdir(page_dir,MALLOC_FIRST); +#ifdef SANITY + if (!i) + wrterror("fatal: couldn't set myself in the page directory\n"); +#endif + + /* Been here, done that */ + initialized++; +} + +/* + * Allocate a number of complete pages + */ +static void *malloc_pages(size_t size) +{ + void *p,*delay_free = 0; + int i; + struct pgfree *pf; + u_long index; + + /* How many pages ? */ + size += (malloc_pagesize-1); + size &= ~malloc_pagemask; + + p = 0; + /* Look for free pages before asking for more */ + for(pf = free_list.next; pf; pf = pf->next) { +#ifdef EXTRA_SANITY + if (pf->page == pf->end) + wrterror("zero entry on free_list\n"); + if (pf->page > pf->end) { + TRACE(("%6d !s %p %p %p <%d>\n",malloc_event++, + pf,pf->page,pf->end,__LINE__)); + wrterror("sick entry on free_list\n"); + } + if ((void*)pf->page >= (void*)sbrk(0)) + wrterror("entry on free_list past brk\n"); + if (page_dir[((u_long)pf->page >> malloc_pageshift) - malloc_origo] + != MALLOC_FREE) { + TRACE(("%6d !f %p %p %p <%d>\n",malloc_event++, + pf,pf->page,pf->end,__LINE__)); + wrterror("non-free first page on free-list\n"); + } + if (page_dir[((u_long)pf->end >> malloc_pageshift) - 1 - malloc_origo] + != MALLOC_FREE) + wrterror("non-free last page on free-list\n"); +#endif /* EXTRA_SANITY */ + if (pf->size < size) + continue; + else if (pf->size == size) { + p = pf->page; + if (pf->next) + pf->next->prev = pf->prev; + pf->prev->next = pf->next; + delay_free = pf; + break; + } else { + p = pf->page; + pf->page += size; + pf->size -= size; + break; + } + } +#ifdef EXTRA_SANITY + if (p && page_dir[((u_long)p >> malloc_pageshift) - malloc_origo] + != MALLOC_FREE) { + wrterror("allocated non-free page on free-list\n"); + } +#endif /* EXTRA_SANITY */ + + size >>= malloc_pageshift; + + /* Map new pages */ + if (!p) + p = map_pages(size,1); + + if (p) { + /* Mark the pages in the directory */ + index = ((u_long)p >> malloc_pageshift) - malloc_origo; + page_dir[index] = MALLOC_FIRST; + for (i=1;i> bits)+MALLOC_BITS-1) / MALLOC_BITS); + if ((1<<(bits)) <= l+l) { + bp = (struct pginfo *)pp; + } else { + bp = (struct pginfo *)_PR_UnlockedMalloc(l); + } + if (!bp) + return 0; + bp->size = (1<shift = bits; + bp->total = bp->free = malloc_pagesize >> bits; + bp->next = page_dir[bits]; + bp->page = (char*)pp; + i = set_pgdir(pp,bp); + if (!i) + return 0; + + /* We can safely assume that there is nobody in this chain */ + page_dir[bits] = bp; + + /* set all valid bits in the bits */ + k = bp->total; + i = 0; +/* + for(;k-i >= MALLOC_BITS; i += MALLOC_BITS) + bp->bits[i / MALLOC_BITS] = ~0; +*/ + for(; i < k; i++) + set_bit(bp,i); + + if (bp != pp) + return 1; + + /* We may have used the first ones already */ + for(i=0;l > 0;i++) { + clr_bit(bp,i); + bp->free--; + bp->total--; + l -= (1 << bits); + } + return 1; +} + +/* + * Allocate a fragment + */ +static void *malloc_bytes(size_t size) +{ + size_t s; + int j; + struct pginfo *bp; + int k; + u_long *lp, bf; + + /* Don't bother with anything less than this */ + if (size < malloc_minsize) { + size = malloc_minsize; + } + + /* Find the right bucket */ + j = 1; + s = size - 1; + while (s >>= 1) { + j++; + } + + /* If it's empty, make a page more of that size chunks */ + if (!page_dir[j] && !malloc_make_chunks(j)) + return 0; + + /* Find first word of bitmap which isn't empty */ + bp = page_dir[j]; + for (lp = bp->bits; !*lp; lp++) + ; + + /* Find that bit */ + bf = *lp; + k = 0; + while ((bf & 1) == 0) { + bf >>= 1; + k++; + } + + *lp ^= 1L<free--; + if (!bp->free) { + page_dir[j] = bp->next; + bp->next = 0; + } + k += (lp - bp->bits)*MALLOC_BITS; + return bp->page + (k << bp->shift); +} + +void *_PR_UnlockedMalloc(size_t size) +{ + void *result; + + /* Round up to a multiple of 8 bytes */ + if (size & 7) { + size = size + 8 - (size & 7); + } + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + if (size <= malloc_maxsize) + result = malloc_bytes(size); + else + result = malloc_pages(size); +#ifdef SANITY + if (malloc_abort && !result) + wrterror("malloc() returns NULL\n"); +#endif + TRACE(("%6d M %p %d\n",malloc_event++,result,size)); + + return result; +} + +void *_PR_UnlockedMemalign(size_t alignment, size_t size) +{ + void *result; + + /* + * alignment has to be a power of 2 + */ + + if ((size <= alignment) && (alignment <= malloc_maxsize)) + size = alignment; + else + size += alignment - 1; + + /* Round up to a multiple of 8 bytes */ + if (size & 7) { + size = size + 8 - (size & 7); + } + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + abort(); +#endif + + if (size <= malloc_maxsize) + result = malloc_bytes(size); + else + result = malloc_pages(size); +#ifdef SANITY + if (malloc_abort && !result) + wrterror("malloc() returns NULL\n"); +#endif + TRACE(("%6d A %p %d\n",malloc_event++,result,size)); + + if ((u_long)result & (alignment - 1)) + return ((void *)(((u_long)result + alignment) & ~(alignment - 1))); + else + return result; +} + +void *_PR_UnlockedCalloc(size_t n, size_t nelem) +{ + void *p; + + /* Compute total size and then round up to a double word amount */ + n *= nelem; + if (n & 7) { + n = n + 8 - (n & 7); + } + + /* Get the memory */ + p = _PR_UnlockedMalloc(n); + if (p) { + /* Zero it */ + memset(p, 0, n); + } + return p; +} + +/* + * Change an allocation's size + */ +void *_PR_UnlockedRealloc(void *ptr, size_t size) +{ + void *p; + u_long osize,page,index,tmp_index; + struct pginfo **mp; + + if (!initialized) + malloc_init(); + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + /* used as free() */ + TRACE(("%6d R %p %d\n",malloc_event++, ptr, size)); + if (ptr && !size) { + _PR_UnlockedFree(ptr); + return _PR_UnlockedMalloc (1); + } + + /* used as malloc() */ + if (!ptr) { + p = _PR_UnlockedMalloc(size); + return p; + } + + /* Find the page directory entry for the page in question */ + page = (u_long)ptr >> malloc_pageshift; + index = page - malloc_origo; + + /* + * check if memory was allocated by memalign + */ + tmp_index = index; + while (page_dir[tmp_index] == MALLOC_FOLLOW) + tmp_index--; + if (tmp_index != index) { + /* + * memalign-allocated memory + */ + index = tmp_index; + page = index + malloc_origo; + ptr = (void *) (page << malloc_pageshift); + } + TRACE(("%6d R2 %p %d\n",malloc_event++, ptr, size)); + + /* make sure it makes sense in some fashion */ + if (index < malloc_pageshift || index > last_index) { +#ifdef SANITY + wrtwarning("junk pointer passed to realloc()\n"); +#endif + return 0; + } + + /* find the size of that allocation, and see if we need to relocate */ + mp = &page_dir[index]; + if (*mp == MALLOC_FIRST) { + osize = malloc_pagesize; + while (mp[1] == MALLOC_FOLLOW) { + osize += malloc_pagesize; + mp++; + } + if (!malloc_realloc && + size < osize && + size > malloc_maxsize && + size > (osize - malloc_pagesize)) { + return ptr; + } + } else if (*mp >= MALLOC_MAGIC) { + osize = (*mp)->size; + if (!malloc_realloc && + size < osize && + (size > (*mp)->size/2 || (*mp)->size == malloc_minsize)) { + return ptr; + } + } else { +#ifdef SANITY + wrterror("realloc() of wrong page.\n"); +#endif + } + + /* try to reallocate */ + p = _PR_UnlockedMalloc(size); + + if (p) { + /* copy the lesser of the two sizes */ + if (osize < size) + memcpy(p,ptr,osize); + else + memcpy(p,ptr,size); + _PR_UnlockedFree(ptr); + } +#ifdef DEBUG + else if (malloc_abort) + wrterror("realloc() returns NULL\n"); +#endif + + return p; +} + +/* + * Free a sequence of pages + */ + +static void +free_pages(char *ptr, u_long page, int index, struct pginfo *info) +{ + int i; + struct pgfree *pf,*pt; + u_long l; + char *tail; + + TRACE(("%6d FP %p %d\n",malloc_event++, ptr, page)); + /* Is it free already ? */ + if (info == MALLOC_FREE) { +#ifdef SANITY + wrtwarning("freeing free page at %p.\n", ptr); +#endif + return; + } + +#ifdef SANITY + /* Is it not the right place to begin ? */ + if (info != MALLOC_FIRST) + wrterror("freeing wrong page.\n"); + + /* Is this really a pointer to a page ? */ + if ((u_long)ptr & malloc_pagemask) + wrterror("freeing messed up page pointer.\n"); +#endif + + /* Count how many pages it is anyway */ + page_dir[index] = MALLOC_FREE; + for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) + page_dir[index + i] = MALLOC_FREE; + + l = i << malloc_pageshift; + + tail = ptr+l; + + /* add to free-list */ + if (!px) + px = (struct pgfree*)_PR_UnlockedMalloc(sizeof *pt); + /* XXX check success */ + px->page = ptr; + px->end = tail; + px->size = l; + if (!free_list.next) { + px->next = free_list.next; + px->prev = &free_list; + free_list.next = px; + pf = px; + px = 0; + } else { + tail = ptr+l; + for(pf = free_list.next; pf->next && pf->end < ptr; pf = pf->next) + ; + for(; pf; pf = pf->next) { + if (pf->end == ptr ) { + /* append to entry */ + pf->end += l; + pf->size += l; + if (pf->next && pf->end == pf->next->page ) { + pt = pf->next; + pf->end = pt->end; + pf->size += pt->size; + pf->next = pt->next; + if (pf->next) + pf->next->prev = pf; + _PR_UnlockedFree(pt); + } + } else if (pf->page == tail) { + /* prepend to entry */ + pf->size += l; + pf->page = ptr; + } else if (pf->page > ptr) { + px->next = pf; + px->prev = pf->prev; + pf->prev = px; + px->prev->next = px; + pf = px; + px = 0; + } else if (!pf->next) { + px->next = 0; + px->prev = pf; + pf->next = px; + pf = px; + px = 0; + } else { + continue; + } + break; + } + } + if (!pf->next && + pf->size > malloc_cache && + pf->end == malloc_brk && + malloc_brk == (void*)sbrk(0)) { + pf->end = pf->page + malloc_cache; + pf->size = malloc_cache; + TRACE(("%6d U %p %d\n",malloc_event++,pf->end,pf->end - pf->page)); + brk(pf->end); + malloc_brk = pf->end; + /* Find the page directory entry for the page in question */ + page = (u_long)pf->end >> malloc_pageshift; + index = page - malloc_origo; + /* Now update the directory */ + for(i=index;i <= last_index;) + page_dir[i++] = MALLOC_NOT_MINE; + last_index = index - 1; + } +} + +/* + * Free a chunk, and possibly the page it's on, if the page becomes empty. + */ + +static void +free_bytes(void *ptr, u_long page, int index, struct pginfo *info) +{ + int i; + struct pginfo **mp; + void *vp; + + /* Make sure that pointer is multiplum of chunk-size */ +#ifdef SANITY + if ((u_long)ptr & (info->size - 1)) + wrterror("freeing messed up chunk pointer\n"); +#endif + + /* Find the chunk number on the page */ + i = ((u_long)ptr & malloc_pagemask) >> info->shift; + + /* See if it's free already */ + if (tst_bit(info,i)) { +#ifdef SANITY + wrtwarning("freeing free chunk at %p\n", ptr); +#endif + return; + } + + /* Mark it free */ + set_bit(info,i); + info->free++; + + /* If the page was full before, we need to put it on the queue now */ + if (info->free == 1) { + mp = page_dir + info->shift; + while (*mp && (*mp)->next && (*mp)->next->page < info->page) + mp = &(*mp)->next; + info->next = *mp; + *mp = info; + return; + } + + /* If this page isn't empty, don't do anything. */ + if (info->free != info->total) + return; + + /* We may want to keep at least one page of each size chunks around. */ + mp = page_dir + info->shift; + if (0 && (*mp == info) && !info->next) + return; + + /* Find & remove this page in the queue */ + while (*mp != info) { + mp = &((*mp)->next); +#ifdef EXTRA_SANITY + if (!*mp) { + TRACE(("%6d !q %p\n",malloc_event++,info)); + wrterror("Not on queue\n"); + } +#endif + } + *mp = info->next; + + /* Free the page & the info structure if need be */ + set_pgdir(info->page,MALLOC_FIRST); + if((void*)info->page == (void*)info) { + _PR_UnlockedFree(info->page); + } else { + vp = info->page; + _PR_UnlockedFree(info); + _PR_UnlockedFree(vp); + } +} + +void _PR_UnlockedFree(void *ptr) +{ + u_long page; + struct pginfo *info; + int index, tmp_index; + + TRACE(("%6d F %p\n",malloc_event++,ptr)); + /* This is legal */ + if (!ptr) + return; + +#ifdef SANITY + /* There wouldn't be anything to free */ + if (!initialized) { + wrtwarning("free() called before malloc() ever got called\n"); + return; + } +#endif + +#ifdef SANITY + if (suicide) + PR_Abort(); +#endif + + /* Find the page directory entry for the page in question */ + page = (u_long)ptr >> malloc_pageshift; + index = page - malloc_origo; + + /* + * check if memory was allocated by memalign + */ + tmp_index = index; + while (page_dir[tmp_index] == MALLOC_FOLLOW) + tmp_index--; + if (tmp_index != index) { + /* + * memalign-allocated memory + */ + index = tmp_index; + page = index + malloc_origo; + ptr = (void *) (page << malloc_pageshift); + } + /* make sure it makes sense in some fashion */ + if (index < malloc_pageshift) { +#ifdef SANITY + wrtwarning("junk pointer %p (low) passed to free()\n", ptr); +#endif + return; + } + if (index > last_index) { +#ifdef SANITY + wrtwarning("junk pointer %p (high) passed to free()\n", ptr); +#endif + return; + } + + /* handle as page-allocation or chunk allocation */ + info = page_dir[index]; + if (info < MALLOC_MAGIC) + free_pages((char*)ptr, page, index, info); + else + free_bytes(ptr,page,index,info); + return; +} +#endif /* _PR_OVERRIDE_MALLOC */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmem.c b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmem.c new file mode 100644 index 00000000..d29bc1fb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/malloc/prmem.c @@ -0,0 +1,762 @@ +/* -*- 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 ***** */ + +/* +** Thread safe versions of malloc, free, realloc, calloc and cfree. +*/ + +#include "primpl.h" +#ifdef VBOX_USE_IPRT_IN_NSPR +# include +#endif + +#ifdef _PR_ZONE_ALLOCATOR + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PR_FPrintZoneStats VBoxNsprPR_FPrintZoneStats +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* +** The zone allocator code must use native mutexes and cannot +** use PRLocks because PR_NewLock calls PR_Calloc, resulting +** in cyclic dependency of initialization. +*/ + +#include + +union memBlkHdrUn; + +typedef struct MemoryZoneStr { + union memBlkHdrUn *head; /* free list */ + pthread_mutex_t lock; + size_t blockSize; /* size of blocks on this free list */ + PRUint32 locked; /* current state of lock */ + PRUint32 contention; /* counter: had to wait for lock */ + PRUint32 hits; /* allocated from free list */ + PRUint32 misses; /* had to call malloc */ + PRUint32 elements; /* on free list */ +} MemoryZone; + +typedef union memBlkHdrUn { + unsigned char filler[48]; /* fix the size of this beast */ + struct memBlkHdrStr { + union memBlkHdrUn *next; + MemoryZone *zone; + size_t blockSize; + size_t requestedSize; + PRUint32 magic; + } s; +} MemBlockHdr; + +#define MEM_ZONES 7 +#define THREAD_POOLS 11 /* prime number for modulus */ +#define ZONE_MAGIC 0x0BADC0DE + +static MemoryZone zones[MEM_ZONES][THREAD_POOLS]; + +static PRBool use_zone_allocator = PR_FALSE; + +static void pr_ZoneFree(void *ptr); + +void +_PR_DestroyZones(void) +{ + int i, j; + + if (!use_zone_allocator) + return; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + pthread_mutex_destroy(&mz->lock); + while (mz->head) { + MemBlockHdr *hdr = mz->head; + mz->head = hdr->s.next; /* unlink it */ +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(hdr); +#else + free(hdr); +#endif + mz->elements--; + } + } + } + use_zone_allocator = PR_FALSE; +} + +/* +** pr_FindSymbolInProg +** +** Find the specified data symbol in the program and return +** its address. +*/ + +#ifdef USE_DLFCN + +#include + +static void * +pr_FindSymbolInProg(const char *name) +{ + void *h; + void *sym; + + h = dlopen(0, RTLD_LAZY); + if (h == NULL) + return NULL; + sym = dlsym(h, name); + (void)dlclose(h); + return sym; +} + +#elif defined(USE_HPSHL) + +#include + +static void * +pr_FindSymbolInProg(const char *name) +{ + shl_t h = NULL; + void *sym; + + if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1) + return NULL; + return sym; +} + +#elif defined(USE_MACH_DYLD) + +static void * +pr_FindSymbolInProg(const char *name) +{ + /* FIXME: not implemented */ + return NULL; +} + +#else + +#error "The zone allocator is not supported on this platform" + +#endif + +void +_PR_InitZones(void) +{ + int i, j; + char *envp; + PRBool *sym; + + if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) { + use_zone_allocator = *sym; + } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) { + use_zone_allocator = (atoi(envp) == 1); + } + + if (!use_zone_allocator) + return; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + int rv = pthread_mutex_init(&mz->lock, NULL); + PR_ASSERT(0 == rv); + if (rv != 0) { + goto loser; + } + mz->blockSize = 16 << ( 2 * i); + } + } + return; + +loser: + _PR_DestroyZones(); + return; +} + +PR_IMPLEMENT(void) +PR_FPrintZoneStats(PRFileDesc *debug_out) +{ + int i, j; + + for (j = 0; j < THREAD_POOLS; j++) { + for (i = 0; i < MEM_ZONES; i++) { + MemoryZone *mz = &zones[i][j]; + MemoryZone zone = *mz; + if (zone.elements || zone.misses || zone.hits) { + PR_fprintf(debug_out, +"pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n", + j, i, zone.blockSize, zone.elements, + zone.hits, zone.misses, zone.contention); + } + } + } +} + +static void * +pr_ZoneMalloc(PRUint32 size) +{ + void *rv; + unsigned int zone; + size_t blockSize; + MemBlockHdr *mb, *mt; + MemoryZone *mz; + + /* Always allocate a non-zero amount of bytes */ + if (size < 1) { + size = 1; + } + for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) { + if (size <= blockSize) { + break; + } + } + if (zone < MEM_ZONES) { + pthread_t me = pthread_self(); + unsigned int pool = (PRUptrdiff)me % THREAD_POOLS; + PRUint32 wasLocked; + mz = &zones[zone][pool]; + wasLocked = mz->locked; + pthread_mutex_lock(&mz->lock); + mz->locked = 1; + if (wasLocked) + mz->contention++; + if (mz->head) { + mb = mz->head; + PR_ASSERT(mb->s.magic == ZONE_MAGIC); + PR_ASSERT(mb->s.zone == mz); + PR_ASSERT(mb->s.blockSize == blockSize); + PR_ASSERT(mz->blockSize == blockSize); + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mz); + PR_ASSERT(mt->s.blockSize == blockSize); + + mz->hits++; + mz->elements--; + mz->head = mb->s.next; /* take off free list */ + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); + + mt->s.next = mb->s.next = NULL; + mt->s.requestedSize = mb->s.requestedSize = size; + + rv = (void *)(mb + 1); + return rv; + } + + mz->misses++; + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); + +#ifdef VBOX_USE_IPRT_IN_NSPR + mb = (MemBlockHdr *)RTMemAlloc(blockSize + 2 * (sizeof *mb)); +#else + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); +#endif + if (!mb) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mb->s.next = NULL; + mb->s.zone = mz; + mb->s.magic = ZONE_MAGIC; + mb->s.blockSize = blockSize; + mb->s.requestedSize = size; + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + memcpy(mt, mb, sizeof *mb); + + rv = (void *)(mb + 1); + return rv; + } + + /* size was too big. Create a block with no zone */ + blockSize = (size & 15) ? size + 16 - (size & 15) : size; +#ifdef VBOX_USE_IPRT_IN_NSPR + mb = (MemBlockHdr *)RTMemAlloc(blockSize + 2 * (sizeof *mb)); +#else + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); +#endif + if (!mb) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mb->s.next = NULL; + mb->s.zone = NULL; + mb->s.magic = ZONE_MAGIC; + mb->s.blockSize = blockSize; + mb->s.requestedSize = size; + + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + memcpy(mt, mb, sizeof *mb); + + rv = (void *)(mb + 1); + return rv; +} + + +static void * +pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize) +{ + PRUint32 size = nelem * elsize; + void *p = pr_ZoneMalloc(size); + if (p) { + memset(p, 0, size); + } + return p; +} + +static void * +pr_ZoneRealloc(void *oldptr, PRUint32 bytes) +{ + void *rv; + MemBlockHdr *mb; + int ours; + MemBlockHdr phony; + + if (!oldptr) + return pr_ZoneMalloc(bytes); + mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb)); + PR_ASSERT(mb->s.magic == ZONE_MAGIC); + if (mb->s.magic != ZONE_MAGIC) { + /* Maybe this just came from ordinary malloc */ +#ifdef DEBUG + fprintf(stderr, + "Warning: reallocing memory block %p from ordinary malloc\n", + oldptr); +#endif + /* We don't know how big it is. But we can fix that. */ +#ifdef VBOX_USE_IPRT_IN_NSPR + oldptr = RTMemRealloc(oldptr, bytes); +#else + oldptr = realloc(oldptr, bytes); +#endif + if (!oldptr) { + if (bytes) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return oldptr; + } + } + phony.s.requestedSize = bytes; + mb = &phony; + ours = 0; + } else { + size_t blockSize = mb->s.blockSize; + MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mb->s.zone); + PR_ASSERT(mt->s.blockSize == blockSize); + + if (bytes <= blockSize) { + /* The block is already big enough. */ + mt->s.requestedSize = mb->s.requestedSize = bytes; + return oldptr; + } + ours = 1; + } + + rv = pr_ZoneMalloc(bytes); + if (rv) { + if (oldptr && mb->s.requestedSize) + memcpy(rv, oldptr, mb->s.requestedSize); + if (ours) + pr_ZoneFree(oldptr); + else if (oldptr) +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(oldptr); +#else + free(oldptr); +#endif + } + return rv; +} + +static void +pr_ZoneFree(void *ptr) +{ + MemBlockHdr *mb, *mt; + MemoryZone *mz; + size_t blockSize; + PRUint32 wasLocked; + + if (!ptr) + return; + + mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb)); + + if (mb->s.magic != ZONE_MAGIC) { + /* maybe this came from ordinary malloc */ +#ifdef DEBUG + fprintf(stderr, + "Warning: freeing memory block %p from ordinary malloc\n", ptr); +#endif +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(ptr); +#else + free(ptr); +#endif + return; + } + + blockSize = mb->s.blockSize; + mz = mb->s.zone; + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); + PR_ASSERT(mt->s.magic == ZONE_MAGIC); + PR_ASSERT(mt->s.zone == mz); + PR_ASSERT(mt->s.blockSize == blockSize); + if (!mz) { + PR_ASSERT(blockSize > 65536); + /* This block was not in any zone. Just free it. */ +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(mb); +#else + free(mb); +#endif + return; + } + PR_ASSERT(mz->blockSize == blockSize); + wasLocked = mz->locked; + pthread_mutex_lock(&mz->lock); + mz->locked = 1; + if (wasLocked) + mz->contention++; + mt->s.next = mb->s.next = mz->head; /* put on head of list */ + mz->head = mb; + mz->elements++; + mz->locked = 0; + pthread_mutex_unlock(&mz->lock); +} + +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#ifdef VBOX_USE_IPRT_IN_NSPR + return use_zone_allocator ? pr_ZoneMalloc(size) : RTMemAlloc(RT_MAX(size, 1)); +#else + return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size); +#endif +} + +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + return use_zone_allocator ? +#ifdef VBOX_USE_IPRT_IN_NSPR + pr_ZoneCalloc(nelem, elsize) : RTMemAllocZ(RT_MAX(nelem * (size_t)elsize, 1)); +#else + pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize); +#endif +} + +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#ifdef VBOX_USE_IPRT_IN_NSPR + return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : RTMemRealloc(ptr, size); +#else + return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size); +#endif +} + +PR_IMPLEMENT(void) PR_Free(void *ptr) +{ + if (use_zone_allocator) + pr_ZoneFree(ptr); + else +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(ptr); +#else + free(ptr); +#endif +} + +#else /* !defined(_PR_ZONE_ALLOCATOR) */ + +/* +** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply +** call their libc equivalents now. This may seem redundant, but it +** ensures that we are calling into the same runtime library. On +** Win32, it is possible to have multiple runtime libraries (e.g., +** objects compiled with /MD and /MDd) in the same process, and +** they maintain separate heaps, which cannot be mixed. +*/ +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) +{ +#if defined (WIN16) + return PR_MD_malloc( (size_t) size); +#else +# ifdef VBOX_USE_IPRT_IN_NSPR + return RTMemAlloc(RT_MAX(size, 1)); +# else + return malloc(size); +# endif +#endif +} + +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) +{ +#if defined (WIN16) + return PR_MD_calloc( (size_t)nelem, (size_t)elsize ); + +#else +# ifdef VBOX_USE_IPRT_IN_NSPR + return RTMemAllocZ(RT_MAX(nelem * (size_t)elsize, 1)); +# else + return calloc(nelem, elsize); +# endif +#endif +} + +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) +{ +#if defined (WIN16) + return PR_MD_realloc( ptr, (size_t) size); +#else +# ifdef VBOX_USE_IPRT_IN_NSPR + return RTMemRealloc(ptr, size); +# else + return realloc(ptr, size); +# endif +#endif +} + +PR_IMPLEMENT(void) PR_Free(void *ptr) +{ +#if defined (WIN16) + PR_MD_free( ptr ); +#else +# ifdef VBOX_USE_IPRT_IN_NSPR + RTMemFree(ptr); +# else + free(ptr); +# endif +#endif +} + +#endif /* _PR_ZONE_ALLOCATOR */ + +/* +** Complexity alert! +** +** If malloc/calloc/free (etc.) were implemented to use pr lock's then +** the entry points could block when called if some other thread had the +** lock. +** +** Most of the time this isn't a problem. However, in the case that we +** are using the thread safe malloc code after PR_Init but before +** PR_AttachThread has been called (on a native thread that nspr has yet +** to be told about) we could get royally screwed if the lock was busy +** and we tried to context switch the thread away. In this scenario +** PR_CURRENT_THREAD() == NULL +** +** To avoid this unfortunate case, we use the low level locking +** facilities for malloc protection instead of the slightly higher level +** locking. This makes malloc somewhat faster so maybe it's a good thing +** anyway. +*/ +#ifdef _PR_OVERRIDE_MALLOC + +/* Imports */ +extern void *_PR_UnlockedMalloc(size_t size); +extern void *_PR_UnlockedMemalign(size_t alignment, size_t size); +extern void _PR_UnlockedFree(void *ptr); +extern void *_PR_UnlockedRealloc(void *ptr, size_t size); +extern void *_PR_UnlockedCalloc(size_t n, size_t elsize); + +static PRBool _PR_malloc_initialised = PR_FALSE; + +#ifdef _PR_PTHREADS +static pthread_mutex_t _PR_MD_malloc_crustylock; + +#define _PR_Lock_Malloc() { \ + if(PR_TRUE == _PR_malloc_initialised) { \ + PRStatus rv; \ + rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \ + PR_ASSERT(0 == rv); \ + } + +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ + PRStatus rv; \ + rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \ + PR_ASSERT(0 == rv); \ + } \ + } +#else /* _PR_PTHREADS */ +static _MDLock _PR_MD_malloc_crustylock; + +#ifdef IRIX +#define _PR_Lock_Malloc() { \ + PRIntn _is; \ + if(PR_TRUE == _PR_malloc_initialised) { \ + if (_PR_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_GET_ATTACHED_THREAD())) \ + _PR_INTSOFF(_is); \ + _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \ + } + +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ + _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \ + if (_PR_MD_GET_ATTACHED_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_GET_ATTACHED_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } +#else /* IRIX */ +#define _PR_Lock_Malloc() { \ + PRIntn _is; \ + if(PR_TRUE == _PR_malloc_initialised) { \ + if (_PR_MD_CURRENT_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_CURRENT_THREAD())) \ + _PR_INTSOFF(_is); \ + _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \ + } + +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ + _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \ + if (_PR_MD_CURRENT_THREAD() && \ + !_PR_IS_NATIVE_THREAD( \ + _PR_MD_CURRENT_THREAD())) \ + _PR_INTSON(_is); \ + } \ + } +#endif /* IRIX */ +#endif /* _PR_PTHREADS */ + +PR_IMPLEMENT(PRStatus) _PR_MallocInit(void) +{ + PRStatus rv = PR_SUCCESS; + + if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS; + +#ifdef _PR_PTHREADS + { + int status; + pthread_mutexattr_t mattr; + + status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr); + PR_ASSERT(0 == status); + status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr); + PR_ASSERT(0 == status); + status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr); + PR_ASSERT(0 == status); + } +#else /* _PR_PTHREADS */ + _MD_NEW_LOCK(&_PR_MD_malloc_crustylock); +#endif /* _PR_PTHREADS */ + + if( PR_SUCCESS == rv ) + { + _PR_malloc_initialised = PR_TRUE; + } + + return rv; +} + +void *malloc(size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedMalloc(size); + _PR_Unlock_Malloc(); + return p; +} + +#if defined(IRIX) +void *memalign(size_t alignment, size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedMemalign(alignment, size); + _PR_Unlock_Malloc(); + return p; +} + +void *valloc(size_t size) +{ + return(memalign(sysconf(_SC_PAGESIZE),size)); +} +#endif /* IRIX */ + +void free(void *ptr) +{ + _PR_Lock_Malloc(); + _PR_UnlockedFree(ptr); + _PR_Unlock_Malloc(); +} + +void *realloc(void *ptr, size_t size) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedRealloc(ptr, size); + _PR_Unlock_Malloc(); + return p; +} + +void *calloc(size_t n, size_t elsize) +{ + void *p; + _PR_Lock_Malloc(); + p = _PR_UnlockedCalloc(n, elsize); + _PR_Unlock_Malloc(); + return p; +} + +void cfree(void *p) +{ + _PR_Lock_Malloc(); + _PR_UnlockedFree(p); + _PR_Unlock_Malloc(); +} + +void _PR_InitMem(void) +{ + PRStatus rv; + rv = _PR_MallocInit(); + PR_ASSERT(PR_SUCCESS == rv); +} + +#endif /* _PR_OVERRIDE_MALLOC */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/md/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/md/Makefile.in new file mode 100644 index 00000000..2b8d4778 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/Makefile.in @@ -0,0 +1,64 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = $(PR_MD_ARCH_DIR) + +CSRCS = \ + prosdep.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/Makefile.in new file mode 100644 index 00000000..fca5cf2c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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 ***** + + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +include $(srcdir)/bsrcs.mk +CSRCS += $(MDCSRCS) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bcpu.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bcpu.c new file mode 100644 index 00000000..548df8c2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bcpu.c @@ -0,0 +1,55 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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" + +PR_EXTERN(void) _PR_MD_INIT_CPUS(); +PR_EXTERN(void) _PR_MD_WAKEUP_CPUS(); +PR_EXTERN(void) _PR_MD_START_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_STOP_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_DISABLE_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_BLOCK_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(void); +PR_EXTERN(void) _PR_MD_CLOCK_INTERRUPT(void); +PR_EXTERN(void) _PR_MD_INIT_STACK(PRThreadStack *ts, PRIntn redzone); +PR_EXTERN(void) _PR_MD_CLEAR_STACK(PRThreadStack* ts); +PR_EXTERN(PRInt32) _PR_MD_GET_INTSOFF(void); +PR_EXTERN(void) _PR_MD_SET_INTSOFF(PRInt32 _val); +PR_EXTERN(_PRCPU*) _PR_MD_CURRENT_CPU(void); +PR_EXTERN(void) _PR_MD_SET_CURRENT_CPU(_PRCPU *cpu); +PR_EXTERN(void) _PR_MD_INIT_RUNNING_CPU(_PRCPU *cpu); +PR_EXTERN(PRInt32) _PR_MD_PAUSE_CPU(PRIntervalTime timeout); diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos.c new file mode 100644 index 00000000..dba9ae24 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos.c @@ -0,0 +1,264 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#define _PRSockLen_t int + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +/* + * Variables used by the GC code, initialized in _MD_InitSegs(). + * _pr_zero_fd should be a static variable. Unfortunately, there is + * still some Unix-specific code left in function PR_GrowSegment() + * in file memory/prseg.c that references it, so it needs + * to be a global variable for now. + */ +PRInt32 _pr_zero_fd = -1; +static PRLock *_pr_md_lock = NULL; + +sigset_t timer_set; + +void _PR_UnixInit() +{ + struct sigaction sigact; + int rv; + + sigemptyset(&timer_set); + + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + rv = sigaction(SIGPIPE, &sigact, 0); + PR_ASSERT(0 == rv); + + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + _pr_Xfe_mon = PR_NewMonitor(); + PR_ASSERT(NULL != _pr_Xfe_mon); +} + +/* + *----------------------------------------------------------------------- + * + * 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 Unix + * implementation. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + struct timeval tv; + PRInt64 s, us, s2us; + + GETTIMEOFDAY(&tv); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, tv.tv_sec); + LL_I2L(us, tv.tv_usec); + LL_MUL(s, s, s2us); + LL_ADD(s, s, us); + return s; +} + +PRIntervalTime +_PR_UNIX_GetInterval() +{ + struct timeval time; + PRIntervalTime ticks; + + (void)GETTIMEOFDAY(&time); /* fallicy of course */ + ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */ + ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ + return ticks; +} /* _PR_SUNOS_GetInterval */ + +PRIntervalTime _PR_UNIX_TicksPerSecond() +{ + return 1000; /* this needs some work :) */ +} + +/************************************************************************/ + +/* +** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread +** safe. Unfortunately, neither is mozilla. To make these programs work +** in a pre-emptive threaded environment, we need to use a lock. +*/ + +void PR_XLock() +{ + PR_EnterMonitor(_pr_Xfe_mon); +} + +void PR_XUnlock() +{ + PR_ExitMonitor(_pr_Xfe_mon); +} + +PRBool PR_XIsLocked() +{ + return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; +} + +void PR_XWait(int ms) +{ + PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); +} + +void PR_XNotify(void) +{ + PR_Notify(_pr_Xfe_mon); +} + +void PR_XNotifyAll(void) +{ + PR_NotifyAll(_pr_Xfe_mon); +} + +#if !defined(BEOS) +#ifdef HAVE_BSD_FLOCK + +#include + +PR_IMPLEMENT(PRStatus) +_MD_LOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_EX); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_TLOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_EX|LOCK_NB); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_UNLOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_UN); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} +#else + +PR_IMPLEMENT(PRStatus) +_MD_LOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_LOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_TLOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_TLOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_UNLOCKFILE (PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_ULOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} +#endif + +PR_IMPLEMENT(PRStatus) + _MD_GETHOSTNAME (char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos_errors.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos_errors.c new file mode 100644 index 00000000..4882594b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/beos_errors.c @@ -0,0 +1,1525 @@ +/* -*- 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 "prtypes.h" +#include "md/_unix_errors.h" +#include "prerror.h" +#include + +void _MD_unix_map_opendir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_closedir_error(int err) +{ + switch (err) { + case EINVAL: + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_readdir_error(int err) +{ + + switch (err) { + case ENOENT: + PR_SetError(PR_NO_MORE_FILES_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef IRIX +#ifdef IRIX5_3 +#else + case EDIRCORRUPTED: + PR_SetError(PR_DIRECTORY_CORRUPTED_ERROR, err); + break; +#endif +#endif +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_IO_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_unlink_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_stat_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fstat_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ETIMEDOUT: +#ifdef ENOLINK + case ENOLINK: +#endif + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#ifdef EOVERFLOW + case EOVERFLOW: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rename_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_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 EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EXDEV: + PR_SetError(PR_NOT_SAME_DEVICE_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_access_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_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 ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mkdir_error(int err) +{ + switch (err) { + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMLINK: + PR_SetError(PR_MAX_DIRECTORY_ENTRIES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_rmdir_error(int err) +{ + + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_FILESYSTEM_MOUNTED_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_DIRECTORY_NOT_EMPTY_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_read_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef EBADMSG + case EBADMSG: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + case EDEADLK: + PR_SetError(PR_DEADLOCK_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_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_write_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_DEADLOCK_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EFBIG: + PR_SetError(PR_FILE_TOO_BIG_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case ENOLCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ENXIO: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ERANGE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef EDQUOT + case EDQUOT: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#endif +#ifdef ENOLINK + case ENOLINK: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lseek_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ESPIPE: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_fsync_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_METHOD_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_close_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; +#ifdef ENOLINK + case ENOLINK: +#endif + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EIO: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socket_error(int err) +{ + switch (err) { + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketavailable_error(int err) +{ + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); +} + +void _MD_unix_map_recv_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_recvfrom_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_send_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_sendto_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EMSGSIZE: +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif /* !defined(SCO) */ + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_writev_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ECONNRESET: + case EPIPE: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_accept_error(int err) +{ + switch (err) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + case ENODEV: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif +#ifdef EPROTO + case EPROTO: + PR_SetError(PR_IO_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_connect_error(int err) +{ + switch (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 EALREADY: + PR_SetError(PR_ALREADY_INITIATED_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_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; + /* + * UNIX domain sockets are not supported in NSPR + */ + case EACCES: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_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: +#if defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * On some platforms, if we connect to a port on + * the local host (the loopback address) that no + * process is listening on, we get EIO instead + * of ECONNREFUSED. + */ + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); +#else + PR_SetError(PR_IO_ERROR, err); +#endif + break; + case ELOOP: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case ENOENT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + case ENXIO: + PR_SetError(PR_IO_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_bind_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + /* + * UNIX domain sockets are not supported in NSPR + */ + case EIO: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EROFS: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_listen_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif +#if !defined(BEOS) + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_shutdown_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_socketpair_error(int err) +{ + switch (err) { + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EAFNOSUPPORT: + case EPROTONOSUPPORT: +#if !defined(BEOS) + case EOPNOTSUPP: +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockname_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getpeername_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#if !defined(SCO) + case ENOBUFS: +#endif /* !defined(SCO) */ + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_getsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_setsockopt_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; +#if !defined(BEOS) + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#endif + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case ENOMEM: +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_open_error(int err) +{ + switch (err) { + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EBUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case EEXIST: + PR_SetError(PR_FILE_EXISTS_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 EISDIR: + PR_SetError(PR_IS_DIRECTORY_ERROR, err); + break; + case ELOOP: + PR_SetError(PR_LOOP_ERROR, err); + break; + case EMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case ENAMETOOLONG: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ENFILE: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ENODEV: + case ENOENT: + case ENXIO: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; +#ifdef ENOSR + case ENOSR: +#endif + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ENOTDIR: + PR_SetError(PR_NOT_DIRECTORY_ERROR, err); + break; + case EPERM: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ETIMEDOUT: + PR_SetError(PR_REMOTE_FILE_ERROR, err); + break; + case EROFS: + PR_SetError(PR_READ_ONLY_FILESYSTEM_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_mmap_error(int err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EAGAIN: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ENOMEM: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_gethostname_error(int err) +{ + switch (err) { + case EFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_select_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_poll_error(int err) +{ + PRErrorCode prerror; + switch (err) { + case EAGAIN: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, err); +} + +void _MD_unix_map_flock_error(int err) +{ + switch (err) { + case EBADF: + case EINVAL: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EWOULDBLOCK: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_unix_map_lockf_error(int err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EACCES: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case EDEADLK: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +#ifdef HPUX11 +void _MD_hpux_map_sendfile_error(int oserror) +{ + PRErrorCode prerror; + + switch (oserror) { + case ENOTSOCK: + prerror = PR_NOT_SOCKET_ERROR; + break; + case EFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; + case ENOBUFS: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case ENOTCONN: + prerror = PR_NOT_CONNECTED_ERROR; + break; + case EPIPE: + prerror = PR_CONNECT_RESET_ERROR; + break; + case ENOMEM: + prerror = PR_OUT_OF_MEMORY_ERROR; + break; + case EOPNOTSUPP: + prerror = PR_NOT_TCP_SOCKET_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, oserror); +} +#endif /* HPUX11 */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bfile.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bfile.c new file mode 100644 index 00000000..95206f30 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bfile.c @@ -0,0 +1,892 @@ +/* -*- Mode: C++; tab-width: 8; c-basic-offset: 8 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "primpl.h" + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; + +void +_MD_InitIO (void) +{ +} + +PRStatus +_MD_open_dir (_MDDir *md,const char *name) +{ +int err; + + md->d = opendir(name); + if (!md->d) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPENDIR_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +char* +_MD_read_dir (_MDDir *md, PRIntn flags) +{ +struct dirent *de; +int err; + + for (;;) { + /* + * XXX: readdir() is not MT-safe + */ + de = readdir(md->d); + + if (!de) { + err = _MD_ERRNO(); + _PR_MD_MAP_READDIR_ERROR(err); + return 0; + } + + if ((flags & PR_SKIP_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == 0)) + continue; + + if ((flags & PR_SKIP_DOT_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == '.') && + (de->d_name[2] == 0)) + continue; + + if ((flags & PR_SKIP_HIDDEN) && (de->d_name[1] == '.')) + continue; + + break; + } + return de->d_name; +} + + +PRInt32 +_MD_close_dir (_MDDir *md) +{ +int rv = 0, err; + + if (md->d) { + rv = closedir(md->d); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSEDIR_ERROR(err); + } + } + return(rv); +} + +void +_MD_make_nonblock (PRFileDesc *fd) +{ + int blocking = 1; + setsockopt(fd->secret->md.osfd, SOL_SOCKET, SO_NONBLOCK, &blocking, sizeof(blocking)); + +} + +PRStatus +_MD_set_fd_inheritable (PRFileDesc *fd, PRBool inheritable) +{ + int rv; + + rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); + if (-1 == rv) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_MD_init_fd_inheritable (PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + if (flags == -1) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return; + } + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_TRUE : _PR_TRI_FALSE; + } +} + +void +_MD_query_fd_inheritable (PRFileDesc *fd) +{ + int flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(-1 != flags); + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_FALSE : _PR_TRI_TRUE; +} + +PRInt32 +_MD_open (const char *name, PRIntn flags, PRIntn mode) +{ + PRInt32 osflags; + PRInt32 rv, err; + + if (flags & PR_RDWR) { + osflags = O_RDWR; + } else if (flags & PR_WRONLY) { + osflags = O_WRONLY; + } else { + osflags = O_RDONLY; + } + + if (flags & PR_APPEND) + osflags |= O_APPEND; + if (flags & PR_TRUNCATE) + osflags |= O_TRUNC; + if (flags & PR_SYNC) { +/* Ummmm. BeOS doesn't appear to + support sync in any way shape or + form. */ + return PR_NOT_IMPLEMENTED_ERROR; + } + + /* + ** On creations we hold the 'create' lock in order to enforce + ** the semantics of PR_Rename. (see the latter for more details) + */ + if (flags & PR_CREATE_FILE) + { + osflags |= O_CREAT ; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + rv = open(name, osflags, mode); + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPEN_ERROR(err); + } + + if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRInt32 +_MD_close_file (PRInt32 osfd) +{ +PRInt32 rv, err; + + rv = close(osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return(rv); +} + +PRInt32 +_MD_read (PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PRInt32 rv, err; + PRInt32 osfd = fd->secret->md.osfd; + + rv = read( osfd, buf, amount ); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_READ_ERROR(err); + } + return(rv); +} + +PRInt32 +_MD_write (PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 rv, err; + PRInt32 osfd = fd->secret->md.osfd; + + rv = write( osfd, buf, amount ); + + if( rv < 0 ) { + + err = _MD_ERRNO(); + _PR_MD_MAP_WRITE_ERROR(err); + } + return( rv ); +} + +#ifndef BONE_VERSION /* Writev moves to bnet.c with BONE */ +PRInt32 +_MD_writev (PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} +#endif + +PRInt32 +_MD_lseek (PRFileDesc *fd, PRInt32 offset, int whence) +{ +PRInt32 rv, err; + + rv = lseek (fd->secret->md.osfd, offset, whence); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(err); + } + return( rv ); +} + +PRInt64 +_MD_lseek64 (PRFileDesc *fd, PRInt64 offset, int whence) +{ +PRInt32 rv, err; + +/* According to the BeOS headers, lseek accepts a + * variable of type off_t for the offset, and off_t + * is defined to be a 64-bit value. So no special + * cracking needs to be done on "offset". + */ + + rv = lseek (fd->secret->md.osfd, offset, whence); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(err); + } + return( rv ); +} + +PRInt32 +_MD_fsync (PRFileDesc *fd) +{ +PRInt32 rv, err; + + rv = fsync(fd->secret->md.osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_FSYNC_ERROR(err); + } + return(rv); +} + +PRInt32 +_MD_delete (const char *name) +{ +PRInt32 rv, err; + + rv = unlink(name); + if (rv == -1) + { + err = _MD_ERRNO(); + _PR_MD_MAP_UNLINK_ERROR(err); + } + return (rv); +} + +PRInt32 +_MD_getfileinfo (const char *fn, PRFileInfo *info) +{ +struct stat sb; +PRInt32 rv, err; +PRInt64 s, s2us; + + rv = stat(fn, &sb); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_STAT_ERROR(err); + } else if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + + /* Must truncate file size for the 32 bit + version */ + info->size = (sb.st_size & 0xffffffff); + LL_I2L(s, sb.st_mtime); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + } + return rv; +} + +PRInt32 +_MD_getfileinfo64 (const char *fn, PRFileInfo64 *info) +{ +struct stat sb; +PRInt32 rv, err; +PRInt64 s, s2us; + + rv = stat(fn, &sb); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_STAT_ERROR(err); + } else if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + + /* For the 64 bit version we can use + * the native st_size without modification + */ + info->size = sb.st_size; + LL_I2L(s, sb.st_mtime); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + } + return rv; +} + +PRInt32 +_MD_getopenfileinfo (const PRFileDesc *fd, PRFileInfo *info) +{ + struct stat sb; + PRInt64 s, s2us; + PRInt32 rv, err; + + rv = fstat(fd->secret->md.osfd, &sb); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_FSTAT_ERROR(err); + } else if (info) { + if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE ; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + /* Use lower 32 bits of file size */ + info->size = ( sb.st_size & 0xffffffff); + LL_I2L(s, sb.st_mtime); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + } + } + return rv; +} + +PRInt32 +_MD_getopenfileinfo64 (const PRFileDesc *fd, PRFileInfo64 *info) +{ + struct stat sb; + PRInt64 s, s2us; + PRInt32 rv, err; + + rv = fstat(fd->secret->md.osfd, &sb); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_FSTAT_ERROR(err); + } else if (info) { + if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE ; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + info->size = sb.st_size; + LL_I2L(s, sb.st_mtime); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + } + } + return rv; +} + +PRInt32 +_MD_rename (const char *from, const char *to) +{ + PRInt32 rv = -1, err; + + /* + ** This is trying to enforce the semantics of WINDOZE' rename + ** operation. That means one is not allowed to rename over top + ** of an existing file. Holding a lock across these two function + ** and the open function is known to be a bad idea, but .... + */ + if (NULL != _pr_rename_lock) + PR_Lock(_pr_rename_lock); + if (0 == access(to, F_OK)) + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + else + { + rv = rename(from, to); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_RENAME_ERROR(err); + } + } + if (NULL != _pr_rename_lock) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRInt32 +_MD_access (const char *name, PRIntn how) +{ +PRInt32 rv, err; +int amode; + + switch (how) { + case PR_ACCESS_WRITE_OK: + amode = W_OK; + break; + case PR_ACCESS_READ_OK: + amode = R_OK; + break; + case PR_ACCESS_EXISTS: + amode = F_OK; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + rv = access(name, amode); + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_ACCESS_ERROR(err); + } + +done: + return(rv); +} + +PRInt32 +_MD_stat (const char *name, struct stat *buf) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRInt32 +_MD_mkdir (const char *name, PRIntn mode) +{ + status_t rv; + int err; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. Look there for more fun details. + */ + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + + rv = mkdir(name, mode); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_MKDIR_ERROR(err); + } + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRInt32 +_MD_rmdir (const char *name) +{ +int rv, err; + + rv = rmdir(name); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_RMDIR_ERROR(err); + } + return rv; +} + +PRInt32 +_MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 rv = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); + /* + * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). + */ + fd_set rd, wt, ex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; + + struct timeval tv, *tvp = NULL; + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + if (0 == npds) { + PR_Sleep(timeout); + return rv; + } + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + 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))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + PRInt32 osfd = bottom->secret->md.osfd; + if (osfd > maxfd) maxfd = osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) return ready; /* no need to block */ + + remaining = timeout; + start = PR_IntervalNow(); + + retry: + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); + tvp = &tv; + } + + ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); + + if (ready == -1 && errno == EINTR) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + goto retry; + } + } + } + + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + PRInt32 osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = bottom->secret->md.osfd; + + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; + +/* Workaround for nonblocking connects under net_server */ +#ifndef BONE_VERSION + if (out_flags) + { + /* check if it is a pending connect */ + int i = 0, j = 0; + PR_Lock( _connectLock ); + for( i = 0; i < connectCount; i++ ) + { + if(connectList[i].osfd == osfd) + { + int connectError; + int connectResult; + + connectResult = connect(connectList[i].osfd, + &connectList[i].addr, + connectList[i].addrlen); + connectError = errno; + + if(connectResult < 0 ) + { + if(connectError == EINTR || connectError == EWOULDBLOCK || + connectError == EINPROGRESS || connectError == EALREADY) + { + break; + } + } + + if(i == (connectCount - 1)) + { + connectList[i].osfd = -1; + } else { + for(j = i; j < connectCount; j++ ) + { + memcpy( &connectList[j], &connectList[j+1], + sizeof(connectList[j])); + } + } + connectCount--; + + bottom->secret->md.connectReturnValue = connectResult; + bottom->secret->md.connectReturnError = connectError; + bottom->secret->md.connectValueValid = PR_TRUE; + break; + } + } + PR_Unlock( _connectLock ); + } +#endif + } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready < 0) + { + err = _MD_ERRNO(); + if (err == EBADF) + { + /* Find the bad fds */ + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + PR_ASSERT(ready > 0); + } + else _PR_MD_MAP_SELECT_ERROR(err); + } + + return ready; +} /* _MD_pr_poll */ + +/* + * File locking. + */ + +PRStatus +_MD_lockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_SETLKW, &linfo); + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_tlockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_SETLK, &linfo); + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PRStatus +_MD_unlockfile (PRInt32 osfd) +{ + PRInt32 rv; + struct flock linfo; + + linfo.l_type = + linfo.l_whence = SEEK_SET; + linfo.l_start = 0; + linfo.l_len = 0; + + rv = fcntl(osfd, F_UNLCK, &linfo); + + if (rv == 0) + return PR_SUCCESS; + + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmemory.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmemory.c new file mode 100644 index 00000000..17c73325 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmemory.c @@ -0,0 +1,42 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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" + +PR_EXTERN(void) _PR_MD_INIT_SEGS(void); +PR_EXTERN(PRStatus) _PR_MD_ALLOC_SEGMENT(PRSegment *seg, PRUint32 size, void *vaddr); +PR_EXTERN(void) _PR_MD_FREE_SEGMENT(PRSegment *seg); diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmisc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmisc.c new file mode 100644 index 00000000..429cd7be --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmisc.c @@ -0,0 +1,123 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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 + +PRLock *_connectLock = NULL; + +#ifndef BONE_VERSION +/* Workaround for nonblocking connects under net_server */ +PRUint32 connectCount = 0; +ConnectListNode connectList[64]; +#endif + +void +_MD_cleanup_before_exit (void) +{ +} + +void +_MD_exit (PRIntn status) +{ + exit(status); +} + +void +_MD_early_init (void) +{ +} + +static PRLock *monitor = NULL; + +void +_MD_final_init (void) +{ + _connectLock = PR_NewLock(); + PR_ASSERT(NULL != _connectLock); +#ifndef BONE_VERSION + /* Workaround for nonblocking connects under net_server */ + connectCount = 0; +#endif +} + +void +_MD_AtomicInit (void) +{ + if (monitor == NULL) { + monitor = PR_NewLock(); + } +} + +/* +** This is exceedingly messy. atomic_add returns the last value, NSPR expects the new value. +** We just add or subtract 1 from the result. The actual memory update is atomic. +*/ + +PRInt32 +_MD_AtomicAdd( PRInt32 *ptr, PRInt32 val ) +{ + return( ( atomic_add( (long *)ptr, val ) ) + val ); +} + +PRInt32 +_MD_AtomicIncrement( PRInt32 *val ) +{ + return( ( atomic_add( (long *)val, 1 ) ) + 1 ); +} + +PRInt32 +_MD_AtomicDecrement( PRInt32 *val ) +{ + return( ( atomic_add( (long *)val, -1 ) ) - 1 ); +} + +PRInt32 +_MD_AtomicSet( PRInt32 *val, PRInt32 newval ) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(monitor); + rv = *val; + *val = newval; + PR_Unlock(monitor); + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmmap.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmmap.c new file mode 100644 index 00000000..9edd0673 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bmmap.c @@ -0,0 +1,73 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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" + +PR_EXTERN(PRStatus) +_PR_MD_CREATE_FILE_MAP(PRFileMap *fmap, PRInt64 size) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} + +PR_EXTERN(PRInt32) +_PR_MD_GET_MEM_MAP_ALIGNMENT(void) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return -1; +} + +PR_EXTERN(void *) +_PR_MD_MEM_MAP(PRFileMap *fmap, PRInt64 offset, PRUint32 len) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return 0; +} + +PR_EXTERN(PRStatus) +_PR_MD_MEM_UNMAP(void *addr, PRUint32 size) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} + +PR_EXTERN(PRStatus) +_PR_MD_CLOSE_FILE_MAP(PRFileMap *fmap) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bnet.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bnet.c new file mode 100644 index 00000000..9b10509e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bnet.c @@ -0,0 +1,929 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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 +#include +#include +#include +#include +#include +#include +#include + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#define _PRSockLen_t int + + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +#define READ_FD 1 +#define WRITE_FD 2 + +/* +** This is a support routine to handle "deferred" i/o on sockets. +** It uses "select", so it is subject to all of the BeOS limitations +** (only READ notification, only sockets) +*/ + +/* + * socket_io_wait -- + * + * wait for socket i/o, periodically checking for interrupt + * + */ + +static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; + fd_set rd_wr; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + do { + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { +#ifdef BONE_VERSION + _PR_MD_MAP_SELECT_ERROR(syserror); +#else + if (syserror == EBADF) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + } else { + PR_SetError(PR_UNKNOWN_ERROR, syserror); + } +#endif + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; + FD_ZERO(&rd_wr); + do { + /* + * We block in _MD_SELECT for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { +#ifdef BONE_VERSION + _PR_MD_MAP_SELECT_ERROR(syserror); +#else + if (syserror == EBADF) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + } else { + PR_SetError(PR_UNKNOWN_ERROR, syserror); + } +#endif + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if _MD_SELECT timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If _MD_SELECT timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); + } + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); +} + +PRInt32 +_MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + +#ifndef BONE_VERSION + if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) { + _PR_MD_MAP_RECV_ERROR(EPIPE); + return -1; + } +#endif + +#ifdef BONE_VERSION + /* + ** Gah, stupid hack. If reading a zero amount, instantly return success. + ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of + ** mozilla use to check for socket availability. + */ + + if( 0 == amount ) return(0); +#endif + + while ((rv = recv(osfd, buf, amount, flags)) == -1) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + /* If socket was supposed to be blocking, + wait a while for the condition to be + satisfied. */ + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + + } else + break; + } + + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } + +done: + return(rv); +} + +PRInt32 +_MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr *) addr, + (_PRSockLen_t *)addrlen)) == -1)) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + } else { + break; + } + } + + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } + +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + +#ifndef BONE_VERSION + if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE) + { + _PR_MD_MAP_SEND_ERROR(EPIPE); + return -1; + } +#endif + + while ((rv = send(osfd, buf, amount, flags)) == -1) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + +#ifndef BONE_VERSION + if( _PR_PENDING_INTERRUPT(me)) { + + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + /* in UNIX implementations, you could do a socket_io_wait here. + * but since BeOS doesn't yet support WRITE notification in select, + * you're spanked. + */ + snooze( 10000L ); + continue; +#else /* BONE_VERSION */ + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; +#endif + + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + + } else { + break; + } + } + +#ifdef BONE_VERSION + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } +#endif /* BONE_VERSION */ + + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } + +#ifdef BONE_VERSION +done: +#endif + return(rv); +} + +PRInt32 +_MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) &addrCopy, addrlen)) == -1) { +#else + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { +#endif + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + +#ifdef BONE_VERSION + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; +#endif + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + + } else { + break; + } + } + + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } + +#ifdef BONE_VERSION +done: +#endif + return(rv); +} + +#ifdef BONE_VERSION + +PRInt32 _MD_writev( + PRFileDesc *fd, const PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 index, amount = 0; + PRInt32 osfd = fd->secret->md.osfd; + + /* + * Calculate the total number of bytes to be sent; needed for + * optimization later. + * We could avoid this if this number was passed in; but it is + * probably not a big deal because iov_size is usually small (less than + * 3) + */ + if (!fd->secret->nonblocking) { + for (index=0; indexsecret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + goto done; + + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } + + + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +#endif /* BONE_VERSION */ + +PRInt32 +_MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = accept(osfd, (struct sockaddr *) addr, + (_PRSockLen_t *)addrlen)) == -1) { + err = _MD_ERRNO(); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + /* If it's SUPPOSED to be a blocking thread, wait + * a while to see if the triggering condition gets + * satisfied. + */ + /* Assume that we're always using a native thread */ + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) { + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } else if (addr != NULL) { + /* bug 134099 */ + err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* Mask off the first byte of struct sockaddr (the length field) */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; + +#ifndef BONE_VERSION + fd->secret->md.connectValueValid = PR_FALSE; +#endif +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; +#endif + + /* (Copied from unix.c) + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: +#ifdef _PR_HAVE_SOCKADDR_LEN + if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { +#else + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { +#endif + err = _MD_ERRNO(); +#ifndef BONE_VERSION + fd->secret->md.connectReturnValue = rv; + fd->secret->md.connectReturnError = err; + fd->secret->md.connectValueValid = PR_TRUE; +#endif + if( err == EINTR ) { + + if( _PR_PENDING_INTERRUPT(me)) { + + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } +#ifndef BONE_VERSION + snooze( 100000L ); +#endif + goto retry; + } + +#ifndef BONE_VERSION + if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) { + + /* + ** There's no timeout on this connect, but that's not + ** a big deal, since the connect times out anyways + ** after 30 seconds. Just sleep for 1/10th of a second + ** and retry until we go through or die. + */ + + if( _PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + goto retry; + } + + if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) { + PR_Lock(_connectLock); + if (connectCount < sizeof(connectList)/sizeof(connectList[0])) { + connectList[connectCount].osfd = osfd; + memcpy(&connectList[connectCount].addr, addr, addrlen); + connectList[connectCount].addrlen = addrlen; + connectList[connectCount].timeout = timeout; + connectCount++; + PR_Unlock(_connectLock); + _PR_MD_MAP_CONNECT_ERROR(err); + } else { + PR_Unlock(_connectLock); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + return rv; + } +#else /* BONE_VERSION */ + if(!fd->secret->nonblocking && (err == EINTR)) { + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_beos_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } +#endif + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} + +PRInt32 +_MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv, err; +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); +#else + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); +#endif + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_BIND_ERROR(err); + } + + return(rv); +} + +PRInt32 +_MD_listen (PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + +#ifndef BONE_VERSION + /* Bug workaround! Setting listen to 0 on Be accepts no connections. + ** On most UN*Xes this sets the default. + */ + + if( backlog == 0 ) backlog = 5; +#endif + + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_LISTEN_ERROR(err); + } + + return(rv); +} + +PRInt32 +_MD_shutdown (PRFileDesc *fd, PRIntn how) +{ + PRInt32 rv, err; + +#ifndef BONE_VERSION + if (how == PR_SHUTDOWN_SEND) + fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE; + else if (how == PR_SHUTDOWN_RCV) + fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ; + else if (how == PR_SHUTDOWN_BOTH) { + fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ); + } + + return 0; +#else /* BONE_VERSION */ + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SHUTDOWN_ERROR(err); + } + return(rv); +#endif +} + +PRInt32 +_MD_socketpair (int af, int type, int flags, PRInt32 *osfd) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRInt32 +_MD_close_socket (PRInt32 osfd) +{ +#ifdef BONE_VERSION + close( osfd ); +#else + closesocket( osfd ); +#endif +} + +PRStatus +_MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); + +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_MD_getsockopt (PRFileDesc *fd, PRInt32 level, + PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv, err; + + rv = getsockopt(fd->secret->md.osfd, level, optname, + optval, (_PRSockLen_t *)optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); + } + + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_MD_setsockopt (PRFileDesc *fd, PRInt32 level, + PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv, err; + + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRInt32 +_MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +#ifndef BONE_VERSION +PRInt32 +_MD_socket (int af, int type, int flags) +{ + PRInt32 osfd, err; + + osfd = socket( af, type, 0 ); + + if( -1 == osfd ) { + + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR( err ); + } + + return( osfd ); +} +#else +PRInt32 +_MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, proto); + + if (osfd == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR(err); + } + + return(osfd); +} +#endif + +PRInt32 +_MD_socketavailable (PRFileDesc *fd) +{ +#ifdef BONE_VERSION + PRInt32 result; + + if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { + _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); + return -1; + } + return result; +#else + return PR_NOT_IMPLEMENTED_ERROR; +#endif +} + +PRInt32 +_MD_get_socket_error (void) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PRStatus +_MD_gethostname (char *name, PRUint32 namelen) +{ + PRInt32 rv, err; + + rv = gethostname(name, namelen); + if (rv == 0) + { + err = _MD_ERRNO(); + _PR_MD_MAP_GETHOSTNAME_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#ifndef BONE_VERSION +PRInt32 +_MD_beos_get_nonblocking_connect_error(PRFileDesc *fd) +{ + int rv; + int flags = 0; + + rv = recv(fd->secret->md.osfd, NULL, 0, flags); + PR_ASSERT(-1 == rv || 0 == rv); + if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { + return errno; + } + return 0; /* no error */ +} +#else +PRInt32 +_MD_beos_get_nonblocking_connect_error(int osfd) +{ + return PR_NOT_IMPLEMENTED_ERROR; + // int err; + // _PRSockLen_t optlen = sizeof(err); + // if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { + // return errno; + // } else { + // return err; + // } +} +#endif /* BONE_VERSION */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bproc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bproc.c new file mode 100644 index 00000000..f21e9465 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bproc.c @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 8; c-basic-offset: 8 -*- */ +/* ***** 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 +#include + +#define _PR_SIGNALED_EXITSTATUS 256 + +PRProcess* +_MD_create_process (const char *path, char *const *argv, + char *const *envp, const PRProcessAttr *attr) +{ + PRProcess *process; + int nEnv, idx; + char *const *childEnvp; + char **newEnvp = NULL; + int flags; + + process = PR_NEW(PRProcess); + if (!process) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + childEnvp = envp; + if (attr && attr->fdInheritBuffer) { + if (NULL == childEnvp) { + childEnvp = environ; + } + for (nEnv = 0; childEnvp[nEnv]; nEnv++) { + } + newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); + if (NULL == newEnvp) { + PR_DELETE(process); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + for (idx = 0; idx < nEnv; idx++) { + newEnvp[idx] = childEnvp[idx]; + } + newEnvp[idx++] = attr->fdInheritBuffer; + newEnvp[idx] = NULL; + childEnvp = newEnvp; + } + + process->md.pid = fork(); + + if ((pid_t) -1 == process->md.pid) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + return NULL; + } else if (0 == process->md.pid) { /* the child process */ + /* + * If the child process needs to exit, it must call _exit(). + * Do not call exit(), because exit() will flush and close + * the standard I/O file descriptors, and hence corrupt + * the parent process's standard I/O data structures. + */ + + if (attr) { + /* the osfd's to redirect stdin, stdout, and stderr to */ + int in_osfd = -1, out_osfd = -1, err_osfd = -1; + + if (attr->stdinFd + && attr->stdinFd->secret->md.osfd != 0) { + in_osfd = attr->stdinFd->secret->md.osfd; + if (dup2(in_osfd, 0) != 0) { + _exit(1); /* failed */ + } + flags = fcntl(0, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(0, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stdoutFd + && attr->stdoutFd->secret->md.osfd != 1) { + out_osfd = attr->stdoutFd->secret->md.osfd; + if (dup2(out_osfd, 1) != 1) { + _exit(1); /* failed */ + } + flags = fcntl(1, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(1, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stderrFd + && attr->stderrFd->secret->md.osfd != 2) { + err_osfd = attr->stderrFd->secret->md.osfd; + if (dup2(err_osfd, 2) != 2) { + _exit(1); /* failed */ + } + flags = fcntl(2, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(2, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (in_osfd != -1) { + close(in_osfd); + } + if (out_osfd != -1 && out_osfd != in_osfd) { + close(out_osfd); + } + if (err_osfd != -1 && err_osfd != in_osfd + && err_osfd != out_osfd) { + close(err_osfd); + } + if (attr->currentDirectory) { + if (chdir(attr->currentDirectory) < 0) { + _exit(1); /* failed */ + } + } + } + + if (childEnvp) { + (void)execve(path, argv, childEnvp); + } else { + /* Inherit the environment of the parent. */ + (void)execv(path, argv); + } + /* Whoops! It returned. That's a bad sign. */ + _exit(1); + } + + if (newEnvp) { + PR_DELETE(newEnvp); + } + + return process; +} + +PRStatus +_MD_detach_process (PRProcess *process) +{ + /* If we kept a process table like unix does, + * we'd remove the entry here. + * Since we dont', just delete the process variable + */ + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus +_MD_wait_process (PRProcess *process, PRInt32 *exitCode) +{ + PRStatus retVal = PR_SUCCESS; + int ret, status; + + /* Ignore interruptions */ + do { + ret = waitpid(process->md.pid, &status, 0); + } while (ret == -1 && errno == EINTR); + + /* + * waitpid() cannot return 0 because we did not invoke it + * with the WNOHANG option. + */ + PR_ASSERT(0 != ret); + + if (ret < 0) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + + /* If child process exited normally, return child exit code */ + if (WIFEXITED(status)) { + *exitCode = WEXITSTATUS(status); + } else { + PR_ASSERT(WIFSIGNALED(status)); + *exitCode = _PR_SIGNALED_EXITSTATUS; + } + + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus +_MD_kill_process (PRProcess *process) +{ + PRErrorCode prerror; + PRInt32 oserror; + + if (kill(process->md.pid, SIGKILL) == 0) { + return PR_SUCCESS; + } + oserror = errno; + switch (oserror) { + case EPERM: + prerror = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ESRCH: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, oserror); + return PR_FAILURE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/brng.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/brng.c new file mode 100644 index 00000000..0aba8da3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/brng.c @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1999-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "primpl.h" + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + struct timeval tv; + int n = 0; + int s; + + GETTIMEOFDAY(&tv); + + if ( size >= 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + if ( size >= 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + + return n; +} /* end _PR_MD_GetRandomNoise() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bseg.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bseg.c new file mode 100644 index 00000000..b6b3b67b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bseg.c @@ -0,0 +1,54 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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" + +PR_IMPLEMENT(void) + _MD_init_segs (void) +{ +} + +PR_IMPLEMENT(PRStatus) + _MD_alloc_segment (PRSegment *seg, PRUint32 size, void *vaddr) +{ + return PR_NOT_IMPLEMENTED_ERROR; +} + +PR_IMPLEMENT(void) + _MD_free_segment (PRSegment *seg) +{ +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bsrcs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bsrcs.mk new file mode 100644 index 00000000..c6eb6fe1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/bsrcs.mk @@ -0,0 +1,54 @@ +# +# ***** 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 file lists the source files to be compiled (used in Makefile) and +# then enumerated as object files (in objs.mk) for inclusion in the NSPR +# shared library + +MDCSRCS = \ + beos.c \ + beos_errors.c \ + bfile.c \ + bmisc.c \ + bnet.c \ + bproc.c \ + brng.c \ + bseg.c \ + btime.c \ + bmmap.c \ + $(NULL) diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/btime.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/btime.c new file mode 100644 index 00000000..aaaa9d27 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/btime.c @@ -0,0 +1,75 @@ +/* -*- Mode: C++; c-basic-offset: 4 -*- */ +/* ***** 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 + +static bigtime_t start; + +PRTime +_MD_now (void) +{ + return (PRTime)real_time_clock_usecs(); +} + +void +_MD_interval_init (void) +{ + /* grab the base interval time */ + start = real_time_clock_usecs(); +} + +PRIntervalTime +_MD_get_interval (void) +{ + return( (PRIntervalTime) real_time_clock_usecs() / 10 ); + +#if 0 + /* return the number of tens of microseconds that have elapsed since + we were initialized */ + bigtime_t now = real_time_clock_usecs(); + now -= start; + now /= 10; + return (PRIntervalTime)now; +#endif +} + +PRIntervalTime +_MD_interval_per_sec (void) +{ + return 100000L; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/objs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/objs.mk new file mode 100644 index 00000000..163c5d9c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/beos/objs.mk @@ -0,0 +1,43 @@ +# +# ***** 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 makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +include $(srcdir)/md/beos/bsrcs.mk + +OBJS += $(MDCSRCS:%.c=md/beos/$(OBJDIR)/%.$(OBJ_SUFFIX)) 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 + +/**/ +/********************************************************************* + +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 + + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/************************************************************************************** + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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 + +/**/ +/********************************************************************* + +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) + + +/**/ +/********************************************************************/ +#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 + +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 ); + ** 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 +#include +#include +#include +#include +#include +#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 +#include // All the internet typedefs +#include // 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 + +#include +#include +#include +#include + +#define GESTALT_OPEN_TPT_PRESENT gestaltOpenTptPresentMask +#define GESTALT_OPEN_TPT_TCP_PRESENT gestaltOpenTptTCPPresentMask + +#include // 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; indexsecret->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 + +#include +#include +#include +#include +#include +#include +#include + +#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 /* 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 +#include + +#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 + * + * 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 + +/* + 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 + * + * 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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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___ */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/Makefile.in new file mode 100644 index 00000000..299cf662 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/Makefile.in @@ -0,0 +1,85 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), OS2) +CSRCS = \ + os2misc.c \ + os2sem.c \ + os2inrval.c \ + os2gc.c \ + os2thred.c \ + os2io.c \ + os2cv.c \ + os2sock.c \ + os2_errors.c \ + os2poll.c \ + os2rng.c \ + $(NULL) +endif + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +ASFILES = os2vacpp.asm +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +ASFILES = os2emx.s os2vaclegacy.s +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/objs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/objs.mk new file mode 100644 index 00000000..008c2525 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/objs.mk @@ -0,0 +1,65 @@ +# +# ***** 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 makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +CSRCS = \ + os2io.c \ + os2sock.c \ + os2thred.c \ + os2cv.c \ + os2gc.c \ + os2misc.c \ + os2inrval.c \ + os2sem.c \ + os2_errors.c \ + os2poll.c \ + os2rng.c \ + $(NULL) + +ifeq ($(MOZ_OS2_TOOLS),VACPP) +ASFILES = os2vacpp.asm +endif + +ifeq ($(MOZ_OS2_TOOLS),EMX) +ASFILES = os2emx.s os2vaclegacy.s +endif + +OBJS += $(addprefix md/os2/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/os2/$(OBJDIR)/,$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2_errors.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2_errors.c new file mode 100644 index 00000000..59784d0c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2_errors.c @@ -0,0 +1,1129 @@ +/* -*- 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 "prerror.h" +#include "primpl.h" + +void _MD_os2_map_default_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} +void _MD_os2_map_opendir_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + case ERROR_INVALID_ACCESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + case ERROR_INVALID_PARAMETER: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + case ERROR_NOT_DOS_DISK: + case ERROR_NOT_READY: + case ERROR_OPEN_FAILED: + case ERROR_PATH_BUSY: + case ERROR_CANNOT_MAKE: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_DEVICE_IN_USE: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_SHARING_BUFFER_EXCEEDED: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_closedir_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_readdir_error(PRInt32 err) +{ + + switch (err) { + case ERROR_NO_MORE_FILES: + PR_SetError(PR_NO_MORE_FILES_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_DOS_DISK: + case ERROR_LOCK_VIOLATION: + case ERROR_BROKEN_PIPE: + case ERROR_NOT_READY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_delete_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* The error code for stat() is in errno. */ +void _MD_os2_map_stat_error(PRInt32 err) +{ + switch (err) { + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + } +} + +void _MD_os2_map_fstat_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_rename_error(PRInt32 err) +{ + switch (err) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* The error code for access() is in errno. */ +void _MD_os2_map_access_error(PRInt32 err) +{ + switch (err) { + case ENOENT: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + } +} + +void _MD_os2_map_mkdir_error(PRInt32 err) +{ + switch (err) { + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_rmdir_error(PRInt32 err) +{ + + switch (err) { + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_read_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_transmitfile_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_write_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + case ENOSPC: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_lseek_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_SEEK_ON_DEVICE: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_fsync_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_close_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_socket_error(PRInt32 err) +{ + switch (err) { + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_recv_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_recvfrom_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_send_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EMSGSIZE: + case EINVAL: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ERROR_NETNAME_DELETED: + PR_SetError(PR_CONNECT_RESET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_sendto_error(PRInt32 err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_writev_error(int err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_accept_error(PRInt32 err) +{ + _MD_os2_map_default_error(err); +} + +void _MD_os2_map_acceptex_error(PRInt32 err) +{ + switch (err) { + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +/* + * An error code of 0 means that the nonblocking connect succeeded. + */ + +int _MD_os2_get_nonblocking_connect_error(int osfd) +{ + int err; + int len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == -1) { + return sock_errno(); + } else { + return err; + } +} + +void _MD_os2_map_connect_error(PRInt32 err) +{ + switch (err) { + case EWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + case EINPROGRESS: + PR_SetError(PR_IN_PROGRESS_ERROR, err); + break; + case EALREADY: + case EINVAL: + PR_SetError(PR_ALREADY_INITIATED_ERROR, err); + break; + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_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 EISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_bind_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case EADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case EACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case EINVAL: + PR_SetError(PR_SOCKET_ADDRESS_IS_BOUND_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_listen_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_shutdown_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +#ifndef XP_OS2_VACPP +void _MD_os2_map_socketpair_error(PRInt32 err) +{ + switch (err) { + case ENOMEM: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case EAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case EPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case EOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case EPROTOTYPE: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + default: + _MD_os2_map_default_error(err); + return; + } +} +#endif + +void _MD_os2_map_getsockname_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_getpeername_error(PRInt32 err) +{ + + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_getsockopt_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_setsockopt_error(PRInt32 err) +{ + switch (err) { + case EBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case ENOPROTOOPT: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case EINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_open_error(PRInt32 err) +{ + switch (err) { + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + PR_SetError(PR_FILE_EXISTS_ERROR, err); + break; + case ERROR_FILE_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_INVALID_NAME: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case ERROR_NOT_READY: + case ERROR_OPEN_FAILED: + case ERROR_PATH_BUSY: + PR_SetError(PR_IO_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_FILENAME_EXCED_RANGE: + PR_SetError(PR_NAME_TOO_LONG_ERROR, err); + break; + case ERROR_TOO_MANY_OPEN_FILES: + PR_SetError(PR_SYS_DESC_TABLE_FULL_ERROR, err); + break; + case ERROR_PATH_NOT_FOUND: + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case ERROR_DISK_FULL: + case ERROR_HANDLE_DISK_FULL: + PR_SetError(PR_NO_DEVICE_SPACE_ERROR, err); + break; + case ERROR_WRITE_PROTECT: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_gethostname_error(PRInt32 err) +{ + switch (err) { +#ifdef SOCEFAULT + case SOCEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; +#endif + case ENETDOWN: + case EINPROGRESS: + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} + +void _MD_os2_map_select_error(PRInt32 err) +{ + PRErrorCode prerror; + + switch (err) { + /* + * OS/2 select() only works on sockets. So in this + * context, ENOTSOCK is equivalent to EBADF on Unix. + */ + case ENOTSOCK: + prerror = PR_BAD_DESCRIPTOR_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; +#ifdef SOCEFAULT + case SOCEFAULT: + prerror = PR_ACCESS_FAULT_ERROR; + break; +#endif + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, err); +} + +void _MD_os2_map_lockf_error(PRInt32 err) +{ + switch (err) { + case ERROR_ACCESS_DENIED: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case ERROR_INVALID_HANDLE: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case ERROR_INVALID_ADDRESS: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case ERROR_DRIVE_LOCKED: + case ERROR_LOCKED: + case ERROR_SHARING_VIOLATION: + PR_SetError(PR_FILE_IS_LOCKED_ERROR, err); + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_MORE_DATA: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + default: + PR_SetError(PR_UNKNOWN_ERROR, err); + break; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2cv.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2cv.c new file mode 100644 index 00000000..7e80993b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2cv.c @@ -0,0 +1,432 @@ +/* -*- 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 ***** */ + +/* + * os2cv.c -- OS/2 Machine-Dependent Code for Condition Variables + * + * We implement our own condition variable wait queue. Each thread + * has a semaphore object (thread->md.blocked_sema) to block on while + * waiting on a condition variable. + * + * We use a deferred condition notify algorithm. When PR_NotifyCondVar + * or PR_NotifyAllCondVar is called, the condition notifies are simply + * recorded in the _MDLock structure. We defer the condition notifies + * until right after we unlock the lock. This way the awakened threads + * have a better chance to reaquire the lock. + */ + +#include "primpl.h" + +#ifdef USE_RAMSEM +ULONG _Far16 _Pascal Dos16GetInfoSeg(PSEL pselGlobal, PSEL pselLocal); + +#ifdef XP_OS2_EMX +typedef unsigned short BOOL16; +#endif + +typedef struct _LINFOSEG +{ + USHORT pidCurrent; + USHORT pidParent; + USHORT prtyCurrent; + USHORT tidCurrent; + USHORT sgCurrent; + UCHAR rfProcStatus; + UCHAR dummy1; + BOOL16 fForeground; + UCHAR typProcess; + UCHAR dummy2; + SEL selEnvironment; + USHORT offCmdLine; + USHORT cbDataSegment; + USHORT cbStack; + USHORT cbHeap; + USHORT hmod; + SEL selDS; + SEL selPack; + SEL selPackShr; + SEL selPackPck; + ULONG ulReserved; +} LINFOSEG; +typedef LINFOSEG FAR *PLINFOSEG; + +PLINFOSEG plisCurrent = NULL; +#endif + +/* + * AddThreadToCVWaitQueueInternal -- + * + * Add the thread to the end of the condition variable's wait queue. + * The CV's lock must be locked when this function is called. + */ + +static void +AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv) +{ + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait += 1; + thred->md.inCVWaitQueue = PR_TRUE; + thred->md.next = NULL; + thred->md.prev = cv->waitTail; + if (cv->waitHead == NULL) { + cv->waitHead = thred; + } else { + cv->waitTail->md.next = thred; + } + cv->waitTail = thred; +} + +/* + * md_UnlockAndPostNotifies -- + * + * Unlock the lock, and then do the deferred condition notifies. + * If waitThred and waitCV are not NULL, waitThred is added to + * the wait queue of waitCV before the lock is unlocked. + * + * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK, + * the two places where a lock is unlocked. + */ +void +md_UnlockAndPostNotifies( + _MDLock *lock, + PRThread *waitThred, + _MDCVar *waitCV) +{ + PRIntn index; + _MDNotified post; + _MDNotified *notified, *prev = NULL; + + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + memset(&lock->notified, 0, sizeof(_MDNotified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* + * Figure out how many threads we need to wake up. + */ + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + _MDCVar *cv = notified->cv[index].cv; + PRThread *thred; + int i; + + /* Fast special case: no waiting threads */ + if (cv->waitHead == NULL) { + notified->cv[index].notifyHead = NULL; + continue; + } + + /* General case */ + if (-1 == notified->cv[index].times) { + /* broadcast */ + thred = cv->waitHead; + while (thred != NULL) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = cv->waitTail = NULL; + cv->nwait = 0; + } else { + thred = cv->waitHead; + i = notified->cv[index].times; + while (thred != NULL && i > 0) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + i--; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = thred; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + if (cv->waitHead->md.prev != NULL) { + cv->waitHead->md.prev->md.next = NULL; + cv->waitHead->md.prev = NULL; + } + } + cv->nwait -= notified->cv[index].times - i; + } + } + notified = notified->link; + } while (NULL != notified); + + if (waitThred) { + AddThreadToCVWaitQueueInternal(waitThred, waitCV); + } + + /* Release the lock before notifying */ +#ifdef USE_RAMSEM + SemReleasex86(&lock->mutex, 0); +#else + DosReleaseMutexSem(lock->mutex); +#endif + + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + PRThread *thred; + PRThread *next; + + thred = notified->cv[index].notifyHead; + while (thred != NULL) { + BOOL rv; + + next = thred->md.next; + thred->md.prev = thred->md.next = NULL; + rv = DosPostEventSem(thred->md.blocked_sema); + PR_ASSERT(rv == NO_ERROR); + thred = next; + } + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock, + PRBool broadcast) +{ + PRIntn index = 0; + _MDNotified *notified = &lock->notified; + + while (1) { + for (index = 0; index < notified->length; ++index) { + if (notified->cv[index].cv == cvar) { + if (broadcast) { + notified->cv[index].times = -1; + } else if (-1 != notified->cv[index].times) { + notified->cv[index].times += 1; + } + return; + } + } + /* if not full, enter new CV in this array */ + if (notified->length < _MD_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) { + notified->link = PR_NEWZAP(_MDNotified); + } + + notified = notified->link; + } + + /* A brand new entry in the array */ + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; +} + +/* + * _PR_MD_NEW_CV() -- Creating new condition variable + * ... Solaris uses cond_init() in similar function. + * + * returns: -1 on failure + * 0 when it succeeds. + * + */ +PRInt32 +_PR_MD_NEW_CV(_MDCVar *cv) +{ + cv->magic = _MD_MAGIC_CV; + /* + * The waitHead, waitTail, and nwait fields are zeroed + * when the PRCondVar structure is created. + */ + return 0; +} + +void _PR_MD_FREE_CV(_MDCVar *cv) +{ + cv->magic = (PRUint32)-1; + return; +} + +/* + * _PR_MD_WAIT_CV() -- Wait on condition variable + */ +void +_PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) +{ + PRThread *thred = _PR_MD_CURRENT_THREAD(); + ULONG rv, count; + ULONG msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ? + SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(timeout); + + /* + * If we have pending notifies, post them now. + */ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, thred, cv); + } else { + AddThreadToCVWaitQueueInternal(thred, cv); +#ifdef USE_RAMSEM + SemReleasex86( &lock->mutex, 0 ); +#else + DosReleaseMutexSem(lock->mutex); +#endif + } + + /* Wait for notification or timeout; don't really care which */ + rv = DosWaitEventSem(thred->md.blocked_sema, msecs); + if (rv == NO_ERROR) { + DosResetEventSem(thred->md.blocked_sema, &count); + } + +#ifdef USE_RAMSEM + SemRequest486(&(lock->mutex), -1); +#else + DosRequestMutexSem((lock->mutex), SEM_INDEFINITE_WAIT); +#endif + + PR_ASSERT(rv == NO_ERROR || rv == ERROR_TIMEOUT || rv == ERROR_INTERRUPT); + + if(rv == ERROR_TIMEOUT || rv == ERROR_INTERRUPT) + { + if (thred->md.inCVWaitQueue) { + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait -= 1; + thred->md.inCVWaitQueue = PR_FALSE; + if (cv->waitHead == thred) { + cv->waitHead = thred->md.next; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + cv->waitHead->md.prev = NULL; + } + } else { + PR_ASSERT(thred->md.prev != NULL); + thred->md.prev->md.next = thred->md.next; + if (thred->md.next != NULL) { + thred->md.next->md.prev = thred->md.prev; + } else { + PR_ASSERT(cv->waitTail == thred); + cv->waitTail = thred->md.prev; + } + } + thred->md.next = thred->md.prev = NULL; + } else { + /* + * This thread must have been notified, but the + * SemRelease call happens after SemRequest + * times out. Wait on the semaphore again to make it + * non-signaled. We assume this wait won't take long. + */ + rv = DosWaitEventSem(thred->md.blocked_sema, SEM_INDEFINITE_WAIT); + if (rv == NO_ERROR) { + DosResetEventSem(thred->md.blocked_sema, &count); + } + PR_ASSERT(rv == NO_ERROR); + } + } + PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE); + return; +} /* --- end _PR_MD_WAIT_CV() --- */ + +void +_PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_FALSE); + return; +} + +PRStatus +_PR_MD_NEW_LOCK(_MDLock *lock) +{ +#ifdef USE_RAMSEM + // It's better if this API traps when pCriticalSect is not a valid + // pointer, because we can't return an error code and if we just return + // the API caller will have nasty bugs that are hard to find. + + PRAMSEM pramsem = (PRAMSEM)(&(lock->mutex)); + /* First time, set up addresses of processor specific functions + */ + if (plisCurrent == NULL) + { + SEL selGlobal = 0, selLocal = 0; + + /* Convert 16 bit global information segment to 32 bit address + * by performing CRMA on the 16 bit address: "shift" operation + * to convert sel to flat, "and" operation to mask the address + * to 32-bit + */ + Dos16GetInfoSeg(&selGlobal, &selLocal); + plisCurrent = (PLINFOSEG)(((ULONG)selLocal << 13) & + (ULONG)0x1fff0000); + + } + + memset(pramsem, 0, sizeof(pramsem)); + DosCreateEventSem(0, &pramsem->hevSem, DC_SEM_SHARED, 0); + + lock->notified.length=0; + lock->notified.link=NULL; + return PR_SUCCESS; +#else + DosCreateMutexSem(0, &(lock->mutex), 0, 0); + (lock)->notified.length=0; + (lock)->notified.link=NULL; + return PR_SUCCESS; +#endif +} + +void +_PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_TRUE); + return; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2emx.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2emx.s new file mode 100644 index 00000000..4dd81e39 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2emx.s @@ -0,0 +1,111 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ 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 Netscape are +/ Copyright (C) 2000 Netscape Communications Corporation. All +/ Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the +/ terms of the GNU General Public License Version 2 or later (the +/ "GPL"), in which case the provisions of the GPL are applicable +/ instead of those above. If you wish to allow use of your +/ version of this file only under the terms of the GPL and not to +/ allow others to use your version of this file under the MPL, +/ indicate your decision by deleting the provisions above and +/ replace them with the notice and other provisions required by +/ the GPL. If you do not delete the provisions above, a recipient +/ may use your version of this file under either the MPL or the +/ GPL. +/ + +/ PRInt32 __PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl __PR_MD_ATOMIC_INCREMENT + .align 4 +__PR_MD_ATOMIC_INCREMENT: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 __PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl __PR_MD_ATOMIC_DECREMENT + .align 4 +__PR_MD_ATOMIC_DECREMENT: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 __PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl __PR_MD_ATOMIC_SET +/ .align 4 +/__PR_MD_ATOMIC_SET: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl __PR_MD_ATOMIC_SET + .align 4 +__PR_MD_ATOMIC_SET: + movl 4(%esp), %ecx + movl 8(%esp), %eax + lock + xchgl %eax, (%ecx) + ret + +/ PRInt32 __PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl __PR_MD_ATOMIC_ADD + .align 4 +__PR_MD_ATOMIC_ADD: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2gc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2gc.c new file mode 100644 index 00000000..d9f76466 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2gc.c @@ -0,0 +1,90 @@ +/* -*- 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 ***** */ + +/* + * GC related routines + * + */ +#include "primpl.h" + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + CONTEXTRECORD context; + context.ContextFlags = CONTEXT_INTEGER; + + if (_PR_IS_NATIVE_THREAD(t)) { + context.ContextFlags |= CONTEXT_CONTROL; + if (QueryThreadContext(t->md.handle, CONTEXT_CONTROL, &context)) { + t->md.gcContext[0] = context.ctx_RegEax; + t->md.gcContext[1] = context.ctx_RegEbx; + t->md.gcContext[2] = context.ctx_RegEcx; + t->md.gcContext[3] = context.ctx_RegEdx; + t->md.gcContext[4] = context.ctx_RegEsi; + t->md.gcContext[5] = context.ctx_RegEdi; + t->md.gcContext[6] = context.ctx_RegEsp; + t->md.gcContext[7] = context.ctx_RegEbp; + *np = PR_NUM_GCREGS; + } else { + PR_ASSERT(0);/* XXX */ + } + } + return (PRWord *)&t->md.gcContext; +} + +/* This function is not used right now, but is left as a reference. + * If you ever need to get the fiberID from the currently running fiber, + * this is it. + */ +void * +GetMyFiberID() +{ + void *fiberData = 0; + + /* A pointer to our tib entry is found at FS:[18] + * At offset 10h is the fiberData pointer. The context of the + * fiber is stored in there. + */ +#ifdef HAVE_ASM + __asm { + mov EDX, FS:[18h] + mov EAX, DWORD PTR [EDX+10h] + mov [fiberData], EAX + } +#endif + + return fiberData; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2inrval.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2inrval.c new file mode 100644 index 00000000..aa928ed3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2inrval.c @@ -0,0 +1,103 @@ +/* -*- 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 ***** */ + +/* + * OS/2 interval timers + * + */ + +#include "primpl.h" + +static PRBool useHighResTimer = PR_FALSE; +PRIntervalTime _os2_ticksPerSec = -1; +PRIntn _os2_bitShift = 0; +PRInt32 _os2_highMask = 0; + +void +_PR_MD_INTERVAL_INIT() +{ + ULONG timerFreq = 0; /* OS/2 high-resolution timer frequency in Hz */ + APIRET rc = DosTmrQueryFreq(&timerFreq); + if (NO_ERROR == rc) { + useHighResTimer = PR_TRUE; + PR_ASSERT(timerFreq != 0); + while (timerFreq > PR_INTERVAL_MAX) { + timerFreq >>= 1; + _os2_bitShift++; + _os2_highMask = (_os2_highMask << 1)+1; + } + + _os2_ticksPerSec = timerFreq; + PR_ASSERT(_os2_ticksPerSec > PR_INTERVAL_MIN); + } +} + +PRIntervalTime +_PR_MD_GET_INTERVAL() +{ + if (useHighResTimer) { + QWORD timestamp; + PRInt32 top; + APIRET rc = DosTmrQueryTime(×tamp); + if (NO_ERROR != rc) { + return -1; + } + /* Sadly, nspr requires the interval to range from 1000 ticks per + * second to only 100000 ticks per second. DosTmrQueryTime is too + * high resolution... + */ + top = timestamp.ulHi & _os2_highMask; + top = top << (32 - _os2_bitShift); + timestamp.ulLo = timestamp.ulLo >> _os2_bitShift; + timestamp.ulLo = timestamp.ulLo + top; + return (PRUint32)timestamp.ulLo; + } else { + ULONG msCount = -1; + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &msCount, sizeof(msCount)); + return msCount; + } +} + +PRIntervalTime +_PR_MD_INTERVAL_PER_SEC() +{ + if (useHighResTimer) { + return _os2_ticksPerSec; + } else { + return 1000; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2io.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2io.c new file mode 100644 index 00000000..6a90ed51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2io.c @@ -0,0 +1,907 @@ +/* -*- 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/23/2000 IBM Corp. Changed write() to DosWrite(). EMX i/o + * calls cannot be intermixed with DosXXX + * calls since EMX remaps file/socket + * handles. + * 04/27/2000 IBM Corp. Changed open file to be more like NT and + * better handle PR_TRUNCATE | PR_CREATE_FILE + * and also fixed _PR_MD_SET_FD_INHERITABLE + */ + +/* OS2 IO module + * + * Assumes synchronous I/O. + * + */ + +#include "primpl.h" +#include "prio.h" +#include +#include +#ifdef XP_OS2_VACPP +#include +#else +#include +#include +#include +#include +#endif + +struct _MDLock _pr_ioq_lock; + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PRInt32 rv; + ULONG count; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks); + rv = DosWaitEventSem(thread->md.blocked_sema, msecs); + DosResetEventSem(thread->md.blocked_sema, &count); + switch(rv) + { + case NO_ERROR: + return PR_SUCCESS; + break; + case ERROR_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + ; + } else { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This led to us being notified twice. + * call SemRequest() to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = DosWaitEventSem(thread->md.blocked_sema, 0); + DosResetEventSem(thread->md.blocked_sema, &count); + PR_ASSERT(rv == NO_ERROR); + } + } + return PR_SUCCESS; + break; + default: + break; + } + return PR_FAILURE; +} +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) ) + { + if (DosPostEventSem(thread->md.blocked_sema) != NO_ERROR) + return PR_FAILURE; + else + return PR_SUCCESS; + } +} + + +/* --- FILE IO ----------------------------------------------------------- */ +/* + * _PR_MD_OPEN() -- Open a file + * + * returns: a fileHandle + * + * The NSPR open flags (osflags) are translated into flags for OS/2 + * + * Mode seems to be passed in as a unix style file permissions argument + * as in 0666, in the case of opening the logFile. + * + */ +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + HFILE file; + PRInt32 access = OPEN_SHARE_DENYNONE; + PRInt32 flags = 0L; + APIRET rc = 0; + PRUword actionTaken; + + ULONG fattr; + + if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH; + + /* we don't want to let children inherit file handles by default */ + access |= OPEN_FLAGS_NOINHERIT; + + if (osflags & PR_RDONLY) + access |= OPEN_ACCESS_READONLY; + else if (osflags & PR_WRONLY) + access |= OPEN_ACCESS_WRITEONLY; + else if(osflags & PR_RDWR) + access |= OPEN_ACCESS_READWRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + { + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS; + } + else if (osflags & PR_CREATE_FILE) + { + if (osflags & PR_TRUNCATE) + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; + else + flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + } + else + { + if (osflags & PR_TRUNCATE) + flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS; + else + flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; + } + + if (isxdigit(mode) == 0) /* file attribs are hex, UNIX modes octal */ + fattr = ((ULONG)mode == FILE_HIDDEN) ? FILE_HIDDEN : FILE_NORMAL; + else fattr = FILE_NORMAL; + + do { + rc = DosOpen((char*)name, + &file, /* file handle if successful */ + &actionTaken, /* reason for failure */ + 0, /* initial size of new file */ + fattr, /* file system attributes */ + flags, /* Open flags */ + access, /* Open mode and rights */ + 0); /* OS/2 Extended Attributes */ + if (rc == ERROR_TOO_MANY_OPEN_FILES) { + ULONG CurMaxFH = 0; + LONG ReqCount = 20; + APIRET rc2; + rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); + if (rc2 != NO_ERROR) { + break; + } + } + } while (rc == ERROR_TOO_MANY_OPEN_FILES); + + if (rc != NO_ERROR) { + _PR_MD_MAP_OPEN_ERROR(rc); + return -1; + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + ULONG bytes; + int rv; + + rv = DosRead((HFILE)fd->secret->md.osfd, + (PVOID)buf, + len, + &bytes); + + if (rv != NO_ERROR) + { + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(rv != ERROR_HANDLE_EOF); + if (rv == ERROR_BROKEN_PIPE) + return 0; + else { + _PR_MD_MAP_READ_ERROR(rv); + return -1; + } + } + return (PRInt32)bytes; +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 bytes; + int rv; + + rv = DosWrite((HFILE)fd->secret->md.osfd, + (PVOID)buf, + len, + (PULONG)&bytes); + + if (rv != NO_ERROR) + { + _PR_MD_MAP_WRITE_ERROR(rv); + return -1; + } + + if (len != bytes) { + rv = ERROR_DISK_FULL; + _PR_MD_MAP_WRITE_ERROR(rv); + return -1; + } + + return bytes; +} /* --- end _PR_MD_WRITE() --- */ + +PRInt32 +_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + PRInt32 rv; + PRUword newLocation; + + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation); + + if (rv != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rv); + return -1; + } else + return newLocation; +} + +PRInt64 +_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ +#ifdef NO_LONG_LONG + PRInt64 result; + PRInt32 rv, low = offset.lo, hi = offset.hi; + PRUword newLocation; + + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation); + rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation); + + if (rv != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rv); + hi = newLocation = -1; + } + + result.lo = newLocation; + result.hi = hi; + return result; + +#else + PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32); + PRUint64 rv; + PRUint32 newLocation, uhi; + + switch (whence) + { + case PR_SEEK_SET: + where = FILE_BEGIN; + break; + case PR_SEEK_CUR: + where = FILE_CURRENT; + break; + case PR_SEEK_END: + where = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; +} + + rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation); + + if (rc != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(rc); + return -1; + } + + uhi = (PRUint32)hi; + PR_ASSERT((PRInt32)uhi >= 0); + rv = uhi; + PR_ASSERT((PRInt64)rv >= 0); + rv = (rv << 32); + PR_ASSERT((PRInt64)rv >= 0); + rv += newLocation; + PR_ASSERT((PRInt64)rv >= 0); + return (PRInt64)rv; +#endif +} + +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd); + + if (rc != NO_ERROR) { + if (rc != ERROR_ACCESS_DENIED) { + _PR_MD_MAP_FSYNC_ERROR(rc); + return -1; + } + } + return 0; +} + +PRInt32 +_MD_CloseFile(PRInt32 osfd) +{ + PRInt32 rv; + + rv = DosClose((HFILE)osfd); + if (rv != NO_ERROR) + _PR_MD_MAP_CLOSE_ERROR(rv); + return rv; +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.achName +#define GetFileAttr(d) (d)->d_entry.attrFile + +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp++; + } +} + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VAC RTL. +** +*/ + +PRInt32 +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + PRInt32 rc; + + if ( d ) { + rc = DosFindClose(d->d_hdl); + if(rc == NO_ERROR){ + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(rc); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ CCHMAXPATH ]; + PRUword numEntries, rc; + + numEntries = 1; + + PR_snprintf(filename, CCHMAXPATH, "%s%s%s", + name, PR_DIRECTORY_SEPARATOR_STR, "*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = HDIR_CREATE; + + rc = DosFindFirst( filename, + &d->d_hdl, + FILE_DIRECTORY | FILE_HIDDEN, + &(d->d_entry), + sizeof(d->d_entry), + &numEntries, + FIL_STANDARD); + if ( rc != NO_ERROR ) { + _PR_MD_MAP_OPENDIR_ERROR(rc); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRUword numFiles = 1; + BOOL rv; + char *fileName; + USHORT fileAttr; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = NO_ERROR; + } else { + rv = DosFindNext(d->d_hdl, + &(d->d_entry), + sizeof(d->d_entry), + &numFiles); + } + if (rv != NO_ERROR) { + break; + } + fileName = GetFileFromDIR(d); + fileAttr = GetFileAttr(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + /* + * XXX + * Is this the correct definition of a hidden file on OS/2? + */ + if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN)) + return fileName; + else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN)) + continue; + return fileName; + } + PR_ASSERT(NO_ERROR != rv); + _PR_MD_MAP_READDIR_ERROR(rv); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + PRInt32 rc = DosDelete((char*)name); + if(rc == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + char filename[CCHMAXPATH]; + + PR_snprintf(filename, CCHMAXPATH, "%s", fn); + FlipSlashes(filename, strlen(filename)); + + rv = _stat((char*)filename, info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + * + * Not sure if this happens on OS/2 or not, + * but it doesn't hurt to be careful. + */ + + int len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + struct stat sb; + PRInt32 rv; + PRInt64 s, s2us; + + if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) { + if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE ; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + info->size = sb.st_size; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, sb.st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + PRFileInfo info32; + PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); + if (0 == rv) + { + info->type = info32.type; + LL_UI2L(info->size,info32.size); + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + } + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + /* For once, the VAC compiler/library did a nice thing. + * The file handle used by the C runtime is the same one + * returned by the OS when you call DosOpen(). This means + * that you can take an OS HFILE and use it with C file + * functions. The only caveat is that you have to call + * _setmode() first to initialize some junk. This is + * immensely useful because I did not have a clue how to + * implement this function otherwise. The windows folks + * took the source from the Microsoft C library source, but + * IBM wasn't kind enough to ship the source with VAC. + * On second thought, the needed function could probably + * be gotten from the OS/2 GNU library source, but the + * point is now moot. + */ + struct stat hinfo; + PRInt64 s, s2us; + + _setmode(fd->secret->md.osfd, O_BINARY); + if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + + if (hinfo.st_mode & S_IFDIR) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.st_size; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, hinfo.st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, hinfo.st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + PRFileInfo info32; + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); + if (0 == rv) + { + info->type = info32.type; + LL_UI2L(info->size,info32.size); + + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + } + return rv; +} + + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + PRInt32 rc; + /* Does this work with dot-relative pathnames? */ + if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ + PRInt32 rv; + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = access(name, 04); + break; + case PR_ACCESS_EXISTS: + return access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) + _PR_MD_MAP_ACCESS_ERROR(errno); + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + PRInt32 rc; + /* XXXMB - how to translate the "mode"??? */ + if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(rc); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + PRInt32 rc; + if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(rc); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRInt32 rv; + FILELOCK lock, unlock; + + lock.lOffset = 0; + lock.lRange = 0xffffffff; + unlock.lOffset = 0; + unlock.lRange = 0; + + /* + * loop trying to DosSetFileLocks(), + * pause for a few miliseconds when can't get the lock + * and try again + */ + for( rv = FALSE; rv == FALSE; /* do nothing */ ) + { + + rv = DosSetFileLocks( (HFILE) f, + &unlock, &lock, + 0, 0); + if ( rv != NO_ERROR ) + { + DosSleep( 50 ); /* Sleep() a few milisecs and try again. */ + } + } /* end for() */ + return PR_SUCCESS; +} /* end _PR_MD_LOCKFILE() */ + +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + return _PR_MD_LOCKFILE(f); +} /* end _PR_MD_TLOCKFILE() */ + + +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv; + FILELOCK lock, unlock; + + lock.lOffset = 0; + lock.lRange = 0; + unlock.lOffset = 0; + unlock.lRange = 0xffffffff; + + rv = DosSetFileLocks( (HFILE) f, + &unlock, &lock, + 0, 0); + + if ( rv != NO_ERROR ) + { + return PR_SUCCESS; + } + else + { + return PR_FAILURE; + } +} /* end _PR_MD_UNLOCKFILE() */ + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + APIRET rc = 0; + ULONG flags; + switch (fd->methods->file_type) + { + case PR_DESC_PIPE: + case PR_DESC_FILE: + rc = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags); + if (rc != NO_ERROR) { + PR_SetError(PR_UNKNOWN_ERROR, rc); + return PR_FAILURE; + } + + if (inheritable) + flags &= ~OPEN_FLAGS_NOINHERIT; + else + flags |= OPEN_FLAGS_NOINHERIT; + + /* Mask off flags DosSetFHState don't want. */ + flags &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); + rc = DosSetFHState((HFILE)fd->secret->md.osfd, flags); + if (rc != NO_ERROR) { + PR_SetError(PR_UNKNOWN_ERROR, rc); + return PR_FAILURE; + } + break; + + case PR_DESC_LAYERED: + /* XXX what to do here? */ + PR_SetError(PR_UNKNOWN_ERROR, 87 /*ERROR_INVALID_PARAMETER*/); + return PR_FAILURE; + + case PR_DESC_SOCKET_TCP: + case PR_DESC_SOCKET_UDP: + { +#ifdef XP_OS2_EMX + int rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); + if (-1 == rv) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#else + /* In VAC, socket() FDs are global. */ +#endif + break; + } + } + + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + /* for imported handles, we'll determine the inheritance state later + * in _PR_MD_QUERY_FD_INHERITABLE */ + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + switch (fd->methods->file_type) + { + case PR_DESC_PIPE: + /* On OS/2, pipe handles created by NPSR (PR_CreatePipe) are + * inheritable by default */ + fd->secret->inheritable = _PR_TRI_TRUE; + break; + case PR_DESC_FILE: + /* On OS/2, file handles created by NPSR (_MD_OPEN) are + * made non-inheritable by default */ + fd->secret->inheritable = _PR_TRI_FALSE; + break; + + case PR_DESC_LAYERED: + /* XXX what to do here? */ + break; + + case PR_DESC_SOCKET_TCP: + case PR_DESC_SOCKET_UDP: +#ifdef XP_OS2_EMX + /* In EMX/GCC, sockets opened by NSPR (_PR_MD_SOCKET) are + * made non-inheritedable by default */ + fd->secret->inheritable = _PR_TRI_FALSE; +#else + /* In VAC, socket() FDs are global. */ + fd->secret->inheritable = _PR_TRI_TRUE; +#endif + break; + } + } +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + + switch (fd->methods->file_type) + { + case PR_DESC_PIPE: + case PR_DESC_FILE: + { + ULONG flags; + if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) { + if (flags & OPEN_FLAGS_NOINHERIT) { + fd->secret->inheritable = _PR_TRI_FALSE; + } else { + fd->secret->inheritable = _PR_TRI_TRUE; + } + } + break; + } + + case PR_DESC_LAYERED: + /* XXX what to do here? */ + break; + + case PR_DESC_SOCKET_TCP: + case PR_DESC_SOCKET_UDP: + { +#ifdef XP_OS2_EMX + /* In EMX/GCC, socket() FDs are inherited by default. */ + int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + if (FD_CLOEXEC == flags) { + fd->secret->inheritable = _PR_TRI_FALSE; + } else { + fd->secret->inheritable = _PR_TRI_TRUE; + } +#else + /* In VAC, socket() FDs are global. */ +#endif + break; + } + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c new file mode 100644 index 00000000..9ea8df74 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2misc.c @@ -0,0 +1,666 @@ +/* -*- 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 ***** */ + +/* + * os2misc.c + * + */ +#include +#include "primpl.h" + +extern int _CRT_init(void); +extern void _CRT_term(void); +extern void __ctordtorInit(int flag); +extern void __ctordtorTerm(int flag); + +char * +_PR_MD_GET_ENV(const char *name) +{ + return getenv(name); +} + +PRIntn +_PR_MD_PUT_ENV(const char *name) +{ + return putenv(name); +} + + +/* see assembleEnvBlock() below */ +#define USE_DOSALLOCMEM + + +/* + ************************************************************************** + ************************************************************************** + ** + ** Date and time routines + ** + ************************************************************************** + ************************************************************************** + */ + +#include +/* + *----------------------------------------------------------------------- + * + * 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 + * implementation for OS/2. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + PRInt64 s, ms, ms2us, s2us; + struct timeb b; + + ftime(&b); + LL_I2L(ms2us, PR_USEC_PER_MSEC); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, b.time); + LL_I2L(ms, b.millitm); + LL_MUL(ms, ms, ms2us); + LL_MUL(s, s, s2us); + LL_ADD(s, s, ms); + return s; +} + + +/* + *********************************************************************** + *********************************************************************** + * + * Process creation routines + * + *********************************************************************** + *********************************************************************** + */ + +/* + * Assemble the command line by concatenating the argv array. + * On success, this function returns 0 and the resulting command + * line is returned in *cmdLine. On failure, it returns -1. + */ +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + int cmdLineSize; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 1; /* final null */ + for (arg = argv+1; *arg; arg++) { + cmdLineSize += strlen(*arg) + 1; /* space in between */ + } + *cmdLine = PR_MALLOC(cmdLineSize); + if (*cmdLine == NULL) { + return -1; + } + + (*cmdLine)[0] = '\0'; + + for (arg = argv+1; *arg; arg++) { + if (arg > argv +1) { + strcat(*cmdLine, " "); + } + strcat(*cmdLine, *arg); + } + return 0; +} + +/* + * Assemble the environment block by concatenating the envp array + * (preserving the terminating null byte in each array element) + * and adding a null byte at the end. + * + * Returns 0 on success. The resulting environment block is returned + * in *envBlock. Note that if envp is NULL, a NULL pointer is returned + * in *envBlock. Returns -1 on failure. + */ +static int assembleEnvBlock(char **envp, char **envBlock) +{ + char *p; + char *q; + char **env; + char *curEnv; + char *cwdStart, *cwdEnd; + int envBlockSize; + + PPIB ppib = NULL; + PTIB ptib = NULL; + + if (envp == NULL) { + *envBlock = NULL; + return 0; + } + + if(DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) + return -1; + + curEnv = ppib->pib_pchenv; + + cwdStart = curEnv; + while (*cwdStart) { + if (cwdStart[0] == '=' && cwdStart[1] != '\0' + && cwdStart[2] == ':' && cwdStart[3] == '=') { + break; + } + cwdStart += strlen(cwdStart) + 1; + } + cwdEnd = cwdStart; + if (*cwdEnd) { + cwdEnd += strlen(cwdEnd) + 1; + while (*cwdEnd) { + if (cwdEnd[0] != '=' || cwdEnd[1] == '\0' + || cwdEnd[2] != ':' || cwdEnd[3] != '=') { + break; + } + cwdEnd += strlen(cwdEnd) + 1; + } + } + envBlockSize = cwdEnd - cwdStart; + + for (env = envp; *env; env++) { + envBlockSize += strlen(*env) + 1; + } + envBlockSize++; + + /* It seems that the Environment parameter of DosStartSession() and/or + * DosExecPgm() wants a memory block that is completely within the 64K + * memory object; otherwise we will get the environment truncated on the + * 64K boundary in the child process. PR_MALLOC() cannot guarantee this, + * so use DosAllocMem directly. */ +#ifdef USE_DOSALLOCMEM + DosAllocMem((PPVOID) envBlock, envBlockSize, PAG_COMMIT | PAG_READ | PAG_WRITE); + p = *envBlock; +#else + p = *envBlock = PR_MALLOC(envBlockSize); +#endif + if (p == NULL) { + return -1; + } + + q = cwdStart; + while (q < cwdEnd) { + *p++ = *q++; + } + + for (env = envp; *env; env++) { + q = *env; + while (*q) { + *p++ = *q++; + } + *p++ = '\0'; + } + *p = '\0'; + return 0; +} + +/* + * For qsort. We sort (case-insensitive) the environment strings + * before generating the environment block. + */ +static int compare(const void *arg1, const void *arg2) +{ + return stricmp(* (char**)arg1, * (char**)arg2); +} + +/* + * On OS/2, a process can be detached only when it is started -- you cannot + * make it detached afterwards. This is why _PR_CreateOS2ProcessEx() is + * necessary. This function is called directly from + * PR_CreateProcessDetached(). */ +PRProcess * _PR_CreateOS2ProcessEx( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr, + PRBool detached) +{ + PRProcess *proc = NULL; + char *cmdLine = NULL; + char **newEnvp = NULL; + char *envBlock = NULL; + + APIRET rc; + ULONG ulAppType = 0; + PID pid = 0; + char *pEnvWPS = NULL; + char *pszComSpec; + char pszEXEName[CCHMAXPATH] = ""; + char pszFormatString[CCHMAXPATH]; + char pszObjectBuffer[CCHMAXPATH]; + char *pszFormatResult = NULL; + char *pszArg0 = NULL; + + proc = PR_NEW(PRProcess); + if (!proc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + if (assembleCmdLine(argv, &cmdLine) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + /* the 0th argument to the program (by convention, the program name, as + * entered by user) */ + pszArg0 = argv[0]; + + /* + * If attr->fdInheritBuffer is not NULL, we need to insert + * it into the envp array, so envp cannot be NULL. + */ + if (envp == NULL && attr && attr->fdInheritBuffer) { + envp = environ; + } + + if (envp != NULL) { + int idx; + int numEnv; + int newEnvpSize; + + numEnv = 0; + while (envp[numEnv]) { + numEnv++; + } + newEnvpSize = numEnv + 1; /* terminating null pointer */ + if (attr && attr->fdInheritBuffer) { + newEnvpSize++; + } + newEnvp = (char **) PR_MALLOC(newEnvpSize * sizeof(char *)); + for (idx = 0; idx < numEnv; idx++) { + newEnvp[idx] = envp[idx]; + } + if (attr && attr->fdInheritBuffer) { + newEnvp[idx++] = attr->fdInheritBuffer; + } + newEnvp[idx] = NULL; + qsort((void *) newEnvp, (size_t) (newEnvpSize - 1), + sizeof(char *), compare); + } + if (assembleEnvBlock(newEnvp, &envBlock) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + if (attr) { + if (attr->stdinFd || attr->stdoutFd || attr->stderrFd) + PR_ASSERT(!"Stdin/stdout redirection is not implemented"); + if (attr->currentDirectory) + PR_ASSERT(!"Setting current directory is not implemented"); + } + + rc = DosQueryAppType(path, &ulAppType); + if (rc != NO_ERROR) { + char *pszDot = strrchr(path, '.'); + if (pszDot) { + /* If it is a CMD file, launch the users command processor */ + if (!stricmp(pszDot, ".cmd")) { + rc = DosScanEnv("COMSPEC", &pszComSpec); + if (!rc) { + strcpy(pszFormatString, "/C %s %s"); + strcpy(pszEXEName, pszComSpec); + pszArg0 = pszEXEName; + ulAppType = FAPPTYP_WINDOWCOMPAT; + } + } + } + } + if (ulAppType == 0) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + goto errorExit; + } + + /* We don't want to use DosExecPgm for detached processes because + * they won't have stdin/stderr/stdout by default which will hang up + * the child process if it tries to write/read from there. Instead, + * we will detach console processes by starting them using the PM session + * (yes, it requires PM, but the whole XPCOM does so too). + */ +#if 0 + if (detached) { + /* we don't care about parent/child process type matching, + * DosExecPgm() should complain if there is a mismatch. */ + + size_t cbArg0 = strlen(pszArg0); + char *pszArgs = NULL; + + if (pszEXEName[0]) { + pszFormatResult = PR_MALLOC(cbArg0 + 1 + + strlen(pszFormatString) + + strlen(path) + strlen(cmdLine) + 1 + 1); + if (!pszFormatResult) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + pszArgs = pszFormatResult + cbArg0 + 1; + sprintf(pszArgs, pszFormatString, path, cmdLine); + } else { + strcpy(pszEXEName, path); + pszFormatResult = PR_MALLOC(cbArg0 + 1 + + strlen(cmdLine) + 1 + 1); + if (!pszFormatResult) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + pszArgs = pszFormatResult + cbArg0 + 1; + strcpy(pszArgs, cmdLine); + } + + strcpy(pszFormatResult, pszArg0); + /* add final NULL */ + pszArgs[strlen(pszArgs) + 1] = '\0'; + + RESULTCODES res = {0}; + rc = DosExecPgm(pszObjectBuffer, CCHMAXPATH, EXEC_BACKGROUND, + pszFormatResult, envBlock, &res, pszEXEName); + + if (rc != NO_ERROR) { + PR_SetError(PR_UNKNOWN_ERROR, rc); + goto errorExit; + } + + /* use 0 to indicate the detached process in the internal + * process structure (I believe no process may have pid of 0) */ + proc->md.pid = 0 /* res.codeTerminate */; + } + else +#endif + { + STARTDATA startData = {0}; + + if ((ulAppType & FAPPTYP_WINDOWAPI) == FAPPTYP_WINDOWAPI) { + startData.SessionType = SSF_TYPE_PM; + } + else if (ulAppType & FAPPTYP_WINDOWCOMPAT) { + startData.SessionType = detached ? SSF_TYPE_PM + : SSF_TYPE_WINDOWABLEVIO; + } + else if (ulAppType & FAPPTYP_NOTWINDOWCOMPAT) { + startData.SessionType = detached ? SSF_TYPE_PM + : SSF_TYPE_DEFAULT; + } + else { + startData.SessionType = SSF_TYPE_DEFAULT; + } + + if (ulAppType & (FAPPTYP_WINDOWSPROT31 | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL)) + { + strcpy(pszEXEName, "WINOS2.COM"); + startData.SessionType = PROG_31_STDSEAMLESSVDM; + strcpy(pszFormatString, "/3 %s %s"); + } + + startData.InheritOpt = SSF_INHERTOPT_PARENT; + + if (pszEXEName[0]) { + pszFormatResult = PR_MALLOC(strlen(pszFormatString)+strlen(path)+strlen(cmdLine)); + sprintf(pszFormatResult, pszFormatString, path, cmdLine); + startData.PgmInputs = pszFormatResult; + } else { + strcpy(pszEXEName, path); + startData.PgmInputs = cmdLine; + } + startData.PgmName = pszEXEName; + + startData.Related = detached ? SSF_RELATED_INDEPENDENT : SSF_RELATED_CHILD; + + startData.Length = sizeof(startData); + startData.ObjectBuffer = pszObjectBuffer; + startData.ObjectBuffLen = CCHMAXPATH; + startData.Environment = envBlock; + + rc = DosStartSession(&startData, &ulAppType, &pid); + + if ((rc != NO_ERROR) && (rc != ERROR_SMG_START_IN_BACKGROUND)) { + PR_SetError(PR_UNKNOWN_ERROR, rc); + goto errorExit; + } + + /* if Related is SSF_RELATED_INDEPENDENT, we don't get pid of the started + * process and use 0 to indicate the detached process in the internal + * process structure (I believe no process may have pid of 0). + */ + proc->md.pid = detached ? 0 : pid; + } + + if (pszFormatResult) { + PR_DELETE(pszFormatResult); + } + if (cmdLine) { + PR_DELETE(cmdLine); + } + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { +#ifdef USE_DOSALLOCMEM + DosFreeMem(envBlock); +#else + PR_DELETE(envBlock); +#endif + } + return proc; + +errorExit: + if (pszFormatResult) { + PR_DELETE(pszFormatResult); + } + if (cmdLine) { + PR_DELETE(cmdLine); + } + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { +#ifdef USE_DOSALLOCMEM + DosFreeMem(envBlock); +#else + PR_DELETE(envBlock); +#endif + } + if (proc) { + PR_DELETE(proc); + } + return NULL; +} /* _PR_CreateOS2ProcessEx */ + +PRProcess * _PR_CreateOS2Process( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + return _PR_CreateOS2ProcessEx(path, argv, envp, attr, PR_FALSE); +} + +PRStatus _PR_DetachOS2Process(PRProcess *process) +{ + /* On OS/2, a process is either created as a child or not. + * You can't 'detach' it later on. + */ + if (process->md.pid == 0) { + /* this is a detached process, just free memory */ + PR_DELETE(process); + return PR_SUCCESS; + } + /* For a normal child process, we can't complete the request. Note that + * terminating the parent process w/o calling PR_WaitProcess() on the + * child will terminate the child as well (since it is not detached). + */ + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); + return PR_FAILURE; +} + +/* + * XXX: This will currently only work on a child process. + */ +PRStatus _PR_WaitOS2Process(PRProcess *process, + PRInt32 *exitCode) +{ + ULONG ulRetVal; + RESULTCODES results; + PID pidEnded = 0; + + ulRetVal = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, + &results, + &pidEnded, process->md.pid); + + if (ulRetVal != NO_ERROR) { + printf("\nDosWaitChild rc = %lu\n", ulRetVal); + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); + return PR_FAILURE; + } + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus _PR_KillOS2Process(PRProcess *process) +{ + ULONG ulRetVal; + if ((ulRetVal = DosKillProcess(DKP_PROCESS, process->md.pid)) == NO_ERROR) { + return PR_SUCCESS; + } + PR_SetError(PR_UNKNOWN_ERROR, ulRetVal); + return PR_FAILURE; +} + +PRStatus _MD_OS2GetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(sock_errno()); + return PR_FAILURE; +} + +void +_PR_MD_WAKEUP_CPUS( void ) +{ + return; +} + + +/* + ********************************************************************** + * + * Memory-mapped files are not supported on OS/2 (or Win16). + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 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) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +/* + * Automatically set apptype switch for interactive and other + * tests that create an invisible plevent window. + */ +unsigned long _System _DLL_InitTerm( unsigned long mod_handle, unsigned long flag) +{ + unsigned long rc = 0; /* failure */ + + if( !flag) + { + /* init */ + if( _CRT_init() == 0) + { + PPIB pPib; + PTIB pTib; + + /* probably superfluous, but can't hurt */ + __ctordtorInit(0); + + DosGetInfoBlocks( &pTib, &pPib); + pPib->pib_ultype = 3; /* PM */ + + rc = 1; + } + } + else + { + __ctordtorTerm(0); + _CRT_term(); + rc = 1; + } + + return rc; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2poll.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2poll.c new file mode 100644 index 00000000..ff87491b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2poll.c @@ -0,0 +1,382 @@ +/* -*- 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 file implements _PR_MD_PR_POLL for OS/2. + */ + +#ifdef XP_OS2_EMX + #include /* For timeval. */ +#endif + +#include "primpl.h" + +#ifndef BSD_SELECT +/* Utility functions called when using OS/2 select */ + +PRBool IsSocketSet( PRInt32 osfd, int* socks, int start, int count ) +{ + int i; + PRBool isSet = PR_FALSE; + + for( i = start; i < start+count; i++ ) + { + if( socks[i] == osfd ) + isSet = PR_TRUE; + } + + return isSet; +} +#endif + +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ +#ifdef BSD_SELECT + fd_set rd, wt, ex; +#else + int rd, wt, ex; + int* socks; + unsigned long msecs; + int i, j; +#endif + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; + +#ifdef BSD_SELECT + struct timeval tv, *tvp = NULL; + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); +#else + rd = 0; + wt = 0; + ex = 0; + socks = (int *) PR_MALLOC( npds * 3 * sizeof(int) ); + + if (!socks) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } +#endif + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + 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))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) && + (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + PRInt32 osfd = bottom->secret->md.osfd; + if (osfd > maxfd) + maxfd = osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; +#ifdef BSD_SELECT + FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; +#ifdef BSD_SELECT + FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; +#ifdef BSD_SELECT + FD_SET(osfd, &rd); +#else + socks[rd] = osfd; + rd++; +#endif + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; +#ifdef BSD_SELECT + FD_SET(osfd, &wt); +#else + socks[npds+wt] = osfd; + wt++; +#endif + } + if (pd->in_flags & PR_POLL_EXCEPT) + { +#ifdef BSD_SELECT + FD_SET(osfd, &ex); +#else + socks[npds*2+ex] = osfd; + ex++; +#endif + } + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) + { +#ifndef BSD_SELECT + PR_Free(socks); +#endif + return ready; /* no need to block */ + } + + remaining = timeout; + start = PR_IntervalNow(); + +retry: +#ifdef BSD_SELECT + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); + tvp = &tv; + } + + ready = bsdselect(maxfd + 1, &rd, &wt, &ex, tvp); +#else + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: + msecs = 0; + break; + case PR_INTERVAL_NO_TIMEOUT: + msecs = -1; + break; + default: + msecs = PR_IntervalToMilliseconds(remaining); + } + + /* compact array */ + for( i = rd, j = npds; j < npds+wt; i++,j++ ) + socks[i] = socks[j]; + for( i = rd+wt, j = npds*2; j < npds*2+ex; i++,j++ ) + socks[i] = socks[j]; + + ready = os2_select(socks, rd, wt, ex, msecs); +#endif + + if (ready == -1 && errno == EINTR) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) + goto retry; + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) + ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + goto retry; + } + } + } + + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + PRInt32 osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = bottom->secret->md.osfd; + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &rd)) +#else + if( IsSocketSet(osfd, socks, 0, rd) ) +#endif + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &wt)) +#else + if( IsSocketSet(osfd, socks, rd, wt) ) +#endif + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + +#ifdef BSD_SELECT + if (FD_ISSET(osfd, &ex)) +#else + if( IsSocketSet(osfd, socks, rd+wt, ex) ) +#endif + { + out_flags |= PR_POLL_EXCEPT; + } + } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready < 0) + { + err = _MD_ERRNO(); + if (err == EBADF) + { + /* Find the bad fds */ + int optval; + int optlen = sizeof(optval); + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) + { + PR_ASSERT(sock_errno() == ENOTSOCK); + if (sock_errno() == ENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + } + PR_ASSERT(ready > 0); + } + else + _PR_MD_MAP_SELECT_ERROR(err); + } + +#ifndef BSD_SELECT + PR_Free(socks); +#endif + return ready; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2rng.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2rng.c new file mode 100644 index 00000000..ae0c66cf --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2rng.c @@ -0,0 +1,111 @@ +/* -*- 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 ***** */ + + +#define INCL_DOS +#define INCL_DOSERRORS +#include +#include +#include +#include +#include "primpl.h" + +static BOOL clockTickTime(unsigned long *phigh, unsigned long *plow) +{ + APIRET rc = NO_ERROR; + QWORD qword = {0,0}; + + rc = DosTmrQueryTime(&qword); + if (rc != NO_ERROR) + return FALSE; + + *phigh = qword.ulHi; + *plow = qword.ulLo; + + return TRUE; +} + +extern PRSize _PR_MD_GetRandomNoise(void *buf, PRSize size ) +{ + unsigned long high = 0; + unsigned long low = 0; + clock_t val = 0; + int n = 0; + int nBytes = 0; + time_t sTime; + + if (size <= 0) + return 0; + + clockTickTime(&high, &low); + + /* get the maximally changing bits first */ + nBytes = sizeof(low) > size ? size : sizeof(low); + memcpy(buf, &low, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + nBytes = sizeof(high) > size ? size : sizeof(high); + memcpy(((char *)buf) + n, &high, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + /* get the number of milliseconds that have elapsed since application started */ + val = clock(); + + nBytes = sizeof(val) > size ? size : sizeof(val); + memcpy(((char *)buf) + n, &val, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + /* get the time in seconds since midnight Jan 1, 1970 */ + time(&sTime); + nBytes = sizeof(sTime) > size ? size : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sem.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sem.c new file mode 100644 index 00000000..20b57a82 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sem.c @@ -0,0 +1,93 @@ +/* -*- 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 ***** */ + +/* + * OS/2-specific semaphore handling code. + * + */ + +#include "primpl.h" + + +void +_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value) +{ + int rv; + + /* Our Sems don't support a value > 1 */ + PR_ASSERT(value <= 1); + + rv = DosCreateEventSem(NULL, &md->sem, 0, 0); + PR_ASSERT(rv == NO_ERROR); +} + +void +_PR_MD_DESTROY_SEM(_MDSemaphore *md) +{ + int rv; + rv = DosCloseEventSem(md->sem); + PR_ASSERT(rv == NO_ERROR); + +} + +PRStatus +_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks) +{ + int rv; + rv = DosWaitEventSem(md->sem, PR_IntervalToMilliseconds(ticks)); + + if (rv == NO_ERROR) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +PRStatus +_PR_MD_WAIT_SEM(_MDSemaphore *md) +{ + return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT); +} + +void +_PR_MD_POST_SEM(_MDSemaphore *md) +{ + int rv; + rv = DosPostEventSem(md->sem); + PR_ASSERT(rv == NO_ERROR); +} + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sock.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sock.c new file mode 100644 index 00000000..c0ada2a4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2sock.c @@ -0,0 +1,733 @@ +/* -*- 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 ***** */ + +/* OS/2 Sockets module + * + */ + +/*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */ +/*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */ +/*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */ +/*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */ +/*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */ + +#include "primpl.h" + +#ifdef XP_OS2_EMX + #include /* For timeval. */ +#endif + +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 +#define READ_FD 1 +#define WRITE_FD 2 + +#ifdef XP_OS2_VACPP +#define _OS2_WRITEV writev +#define _OS2_IOCTL ioctl +#define _OS2_const const +#else +#define _OS2_WRITEV so_writev +#define _OS2_IOCTL so_ioctl +#define _OS2_const +#endif + +void +_PR_MD_INIT_IO() +{ + sock_init(); +} + +/* --- SOCKET IO --------------------------------------------------------- */ + + +PRInt32 +_PR_MD_SOCKET(int domain, int type, int flags) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, flags); + + if (osfd == -1) + { + err = sock_errno(); + _PR_MD_MAP_SOCKET_ERROR(err); + } + +#ifdef XP_OS2_EMX + /* Disable inheritance of socket FDs by default to avoid side effects */ + err = fcntl(osfd, F_SETFD, FD_CLOEXEC); + if (-1 == err) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + soclose(osfd); + return -1; + } +#endif + + return(osfd); +} + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_MD_CloseSocket(PRInt32 osfd) +{ + PRInt32 rv, err; + + rv = soclose(osfd); + if (rv == -1) { + err = sock_errno(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return rv; +} + +PRInt32 +_MD_SocketAvailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (_OS2_IOCTL(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno()); + return -1; + } + return result; +} + +static PRInt32 +socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout ) +{ + PRInt32 rv = -1; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; +#ifdef BSD_SELECT + struct timeval tv; + fd_set rd_wr; +#else + int socks[1]; + long lTimeout; +#endif + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ +#ifdef BSD_SELECT + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + do { + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv); +#else + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + do { + socks[0] = osfd; + if (fd_type == READ_FD) + rv = os2_select(socks, 1, 0, 0, lTimeout); + else + rv = os2_select(socks, 0, 1, 0, lTimeout); +#endif + if (rv == -1 && (syserror = sock_errno()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; +#ifdef BSD_SELECT + FD_ZERO(&rd_wr); +#endif + do { + /* + * We block in select for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ +#ifdef BSD_SELECT + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv); +#else + wait_for_remaining = PR_TRUE; + lTimeout = PR_IntervalToMilliseconds(remaining); + if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + wait_for_remaining = PR_FALSE; + lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + } + socks[0] = osfd; + if (fd_type == READ_FD) + rv = os2_select(socks, 1, 0, 0, lTimeout); + else + rv = os2_select(socks, 0, 1, 0, lTimeout); +#endif + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = sock_errno()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if select timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If select timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { +#ifdef BSD_SELECT + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); +#else + now += PR_MillisecondsToInterval(lTimeout); +#endif + } + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); +} + +PRInt32 +_MD_Accept(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK) || (err == ECONNABORTED)) + { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + if (rv != -1 && addr) /* ignore the sa_len field of struct sockaddr */ + addr->raw.family = ((struct sockaddr *) addr)->sa_family; +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + PRNetAddr addrCopy = *addr; + ((struct sockaddr *)&addrCopy)->sa_len = addrlen; + ((struct sockaddr *)&addrCopy)->sa_family = addr->raw.family; + addr = &addrCopy; +#endif + + /* + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) + { + err = sock_errno(); + + if (err == EINTR) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + goto retry; + } + + if (!fd->secret->nonblocking && (err == EINPROGRESS)) + { + /* + * socket_io_wait() may return -1 or 1. + */ + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_os2_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} /* _MD_connect */ + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv, err; +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + PRNetAddr addrCopy = *addr; + ((struct sockaddr *)&addrCopy)->sa_len = addrlen; + ((struct sockaddr *)&addrCopy)->sa_family = addr->raw.family; + addr = &addrCopy; +#endif + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_BIND_ERROR(err); + } + return(rv); +} + + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_DEFAULT_ERROR(err); + } + return(rv); +} + + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = recv(osfd,buf,amount,flags)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = send(osfd,buf,amount,flags)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next send() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) + { + if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { + rv = -1; + goto done; + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + PRNetAddr addrCopy = *addr; + ((struct sockaddr *)&addrCopy)->sa_len = addrlen; + ((struct sockaddr *)&addrCopy)->sa_family = addr->raw.family; + addr = &addrCopy; +#endif + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) + { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while( (*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr *) addr, (int *)addrlen)) == -1)) + { + err = sock_errno(); + if ((err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + if (rv != -1 && addr) /* ignore the sa_len field of struct sockaddr */ + addr->raw.family = ((struct sockaddr *) addr)->sa_family; +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, + PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 index, amount = 0; + PRInt32 osfd = fd->secret->md.osfd; + + /* + * Calculate the total number of bytes to be sent; needed for + * optimization later. + * We could avoid this if this number was passed in; but it is + * probably not a big deal because iov_size is usually small (less than + * 3) + */ + if (!fd->secret->nonblocking) { + for (index=0; indexsecret->nonblocking) { + break; + } + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + goto done; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ + PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno()); + return rv; +} + +#ifndef XP_OS2_VACPP +PRInt32 +_PR_MD_SOCKETPAIR(int af, int type, int flags, PRInt32 *osfd) +{ + PRInt32 rv, err; + + rv = socketpair(af, type, flags, osfd); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKETPAIR_ERROR(err); + } + return rv; +} +#endif + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + if (rv == 0 && addr) /* ignore the sa_len field of struct sockaddr */ + addr->raw.family = ((struct sockaddr *) addr)->sa_family; +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (int *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN /* bird - !TCPV40HDRS */ + if (rv == 0 && addr) /* ignore the sa_len field of struct sockaddr */ + addr->raw.family = ((struct sockaddr *) addr)->sa_family; +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + char* optval, PRInt32* optlen) +{ + PRInt32 rv, err; + + rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, + const char* optval, PRInt32 optlen) +{ + PRInt32 rv, err; + + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = sock_errno(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +void +_MD_MakeNonblock(PRFileDesc *fd) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 err; + PRUint32 one = 1; + + if (osfd <= 2) { + /* Don't mess around with stdin, stdout or stderr */ + return; + } + + err = _OS2_IOCTL( osfd, FIONBIO, (char *) &one, sizeof(one)); + if ( err != 0 ) + { + err = sock_errno(); + _PR_MD_MAP_SOCKET_ERROR(err); + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2thred.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2thred.c new file mode 100644 index 00000000..69f06aa0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2thred.c @@ -0,0 +1,407 @@ +/* -*- 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 /* for _beginthread() */ + +#ifdef XP_OS2_VACPP +#include /* for _tzset() */ +#endif + +#ifdef XP_OS2_EMX +#include +#endif + +#include + +/* --- globals ------------------------------------------------ */ +_NSPR_TLS* pThreadLocalStorage = 0; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; +APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD); + +void +_PR_MD_ENSURE_TLS(void) +{ + if(!pThreadLocalStorage) + { + /* Allocate thread local storage (TLS). Note, that only 32 bytes can + * be allocated at a time. + */ + int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage); + PR_ASSERT(rc == NO_ERROR); + memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS)); + } +} + +void +_PR_MD_EARLY_INIT() +{ + HMODULE hmod; + + if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0) + DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT", + (PFN *)&QueryThreadContext); + +#ifdef XP_OS2_VACPP + _tzset(); +#endif +} + +static void +_pr_SetThreadMDHandle(PRThread *thread) +{ + PTIB ptib; + PPIB ppib; + PRUword rc; + + rc = DosGetInfoBlocks(&ptib, &ppib); + + thread->md.handle = ptib->tib_ptib2->tib2_ultid; +} + +/* On OS/2, some system function calls seem to change the FPU control word, + * such that we crash with a floating underflow exception. The FIX_FPU() call + * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the + * OS/2 system call that horks the FPU control word. So, we set an exception + * handler that covers any floating point exceptions and resets the FPU CW to + * the required value. + */ +static ULONG +_System OS2_FloatExcpHandler(PEXCEPTIONREPORTRECORD p1, + PEXCEPTIONREGISTRATIONRECORD p2, + PCONTEXTRECORD p3, + PVOID pv) +{ +#ifdef DEBUG_pedemonte + printf("Entering exception handler; ExceptionNum = %x\n", p1->ExceptionNum); + switch(p1->ExceptionNum) { + case XCPT_FLOAT_DENORMAL_OPERAND: + printf("got XCPT_FLOAT_DENORMAL_OPERAND\n"); + break; + case XCPT_FLOAT_DIVIDE_BY_ZERO: + printf("got XCPT_FLOAT_DIVIDE_BY_ZERO\n"); + break; + case XCPT_FLOAT_INEXACT_RESULT: + printf("got XCPT_FLOAT_INEXACT_RESULT\n"); + break; + case XCPT_FLOAT_INVALID_OPERATION: + printf("got XCPT_FLOAT_INVALID_OPERATION\n"); + break; + case XCPT_FLOAT_OVERFLOW: + printf("got XCPT_FLOAT_OVERFLOW\n"); + break; + case XCPT_FLOAT_STACK_CHECK: + printf("got XCPT_FLOAT_STACK_CHECK\n"); + break; + case XCPT_FLOAT_UNDERFLOW: + printf("got XCPT_FLOAT_UNDERFLOW\n"); + break; + } +#endif + + switch(p1->ExceptionNum) { + case XCPT_FLOAT_DENORMAL_OPERAND: + case XCPT_FLOAT_DIVIDE_BY_ZERO: + case XCPT_FLOAT_INEXACT_RESULT: + case XCPT_FLOAT_INVALID_OPERATION: + case XCPT_FLOAT_OVERFLOW: + case XCPT_FLOAT_STACK_CHECK: + case XCPT_FLOAT_UNDERFLOW: + { + unsigned cw = p3->ctx_env[0]; + if ((cw & MCW_EM) != MCW_EM) { + /* Mask out all floating point exceptions */ + p3->ctx_env[0] |= MCW_EM; + /* Following two lines set precision to 53 bit mantissa. See jsnum.c */ + p3->ctx_env[0] &= ~MCW_PC; + p3->ctx_env[0] |= PC_53; + return XCPT_CONTINUE_EXECUTION; + } + } + } + return XCPT_CONTINUE_SEARCH; +} + +PR_IMPLEMENT(void) +PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) +{ + /* setup the exception handler for the thread */ + APIRET rv; + excpreg->ExceptionHandler = OS2_FloatExcpHandler; + excpreg->prev_structure = NULL; + rv = DosSetExceptionHandler(excpreg); + PR_ASSERT(rv == NO_ERROR); +} + +PR_IMPLEMENT(void) +PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) +{ + /* unset exception handler */ + APIRET rv = DosUnsetExceptionHandler(excpreg); + PR_ASSERT(rv == NO_ERROR); +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + APIRET rv; + + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _pr_SetThreadMDHandle(thread); + } + + /* Create the blocking IO semaphore */ + rv = DosCreateEventSem(NULL, &(thread->md.blocked_sema), 0, 0); + return (rv == NO_ERROR) ? PR_SUCCESS : PR_FAILURE; +} + +typedef struct param_store +{ + void (*start)(void *); + PRThread* thread; +} PARAMSTORE; + +/* This is a small intermediate function that sets/unsets the exception + handler before calling the initial thread function */ +static void +ExcpStartFunc(void* arg) +{ + EXCEPTIONREGISTRATIONRECORD excpreg; + PARAMSTORE params, *pParams = arg; + + PR_OS2_SetFloatExcpHandler(&excpreg); + + params = *pParams; + PR_Free(pParams); + params.start(params.thread); + + PR_OS2_UnsetFloatExcpHandler(&excpreg); +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PARAMSTORE* params = PR_Malloc(sizeof(PARAMSTORE)); + params->start = start; + params->thread = thread; +#ifdef XP_OS2_VACPP /* No exception handler for VACPP */ + thread->md.handle = thread->id = (TID) _beginthread( + (void(* _Optlink)(void*))start, + NULL, + thread->stack->stackSize, + thread); +#else + thread->md.handle = thread->id = (TID) _beginthread(ExcpStartFunc, + NULL, + thread->stack->stackSize, + params); +#endif + if(thread->md.handle == -1) { + return PR_FAILURE; + } + + /* + * On OS/2, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL + */ + + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + return PR_SUCCESS; +} + +void +_PR_MD_YIELD(void) +{ + /* Isn't there some problem with DosSleep(0) on OS/2? */ + DosSleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + nativePri = PRTYC_IDLETIME; + break; + case PR_PRIORITY_NORMAL: + nativePri = PRTYC_REGULAR; + break; + case PR_PRIORITY_HIGH: + nativePri = PRTYC_FOREGROUNDSERVER; + break; + case PR_PRIORITY_URGENT: + nativePri = PRTYC_TIMECRITICAL; + } + rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle); + PR_ASSERT(rv == NO_ERROR); + if (rv != NO_ERROR) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + APIRET rv; + + if (thread->md.blocked_sema) { + rv = DosCloseEventSem(thread->md.blocked_sema); + PR_ASSERT(rv == NO_ERROR); + thread->md.blocked_sema = 0; + } + + if (thread->md.handle) { + thread->md.handle = 0; + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + _PR_MD_CLEAN_THREAD(thread); + _PR_MD_SET_CURRENT_THREAD(NULL); +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +#ifdef HAVE_THREAD_AFFINITY +PR_EXTERN(PRInt32) +_PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + /* Can we do this on OS/2? Only on SMP versions? */ + PR_ASSERT(!"Not implemented"); + return 0; + + /* This is what windows does: + int rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; + */ +} + +PR_EXTERN(PRInt32) +_PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + /* Can we do this on OS/2? Only on SMP versions? */ + PR_ASSERT(!"Not implemented"); + return 0; + + /* This is what windows does: + PRInt32 rv, system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); + + return rv?0:-1; + */ +} +#endif /* HAVE_THREAD_AFFINITY */ + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + APIRET rc; + + /* XXXMB - DosSuspendThread() is not a blocking call; how do we + * know when the thread is *REALLY* suspended? + */ + rc = DosSuspendThread(thread->md.handle); + PR_ASSERT(rc == NO_ERROR); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DosResumeThread(thread->md.handle); + } +} + + +PRThread* +_MD_CURRENT_THREAD(void) +{ + PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + + PR_ASSERT(thread != NULL); + return thread; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vaclegacy.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vaclegacy.s new file mode 100644 index 00000000..05310f91 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vaclegacy.s @@ -0,0 +1,73 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ 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 innotek. +/ Portions created by the Initial Developer are Copyright (C) 2003 +/ the Initial Developer. All Rights Reserved. +/ +/ Contributor(s): +/ innotek GmbH / Knut St. Osmundsen +/ +/ Alternatively, the contents of this file may be used under the +/ terms of the GNU General Public License Version 2 or later (the +/ "GPL"), in which case the provisions of the GPL are applicable +/ instead of those above. If you wish to allow use of your +/ version of this file only under the terms of the GPL and not to +/ allow others to use your version of this file under the MPL, +/ indicate your decision by deleting the provisions above and +/ replace them with the notice and other provisions required by +/ the GPL. If you do not delete the provisions above, a recipient +/ may use your version of this file under either the MPL or the +/ GPL. +/ + + .text + .align 4 + .globl PR_NewMonitor +PR_NewMonitor: + jmp _PR_NewMonitor + + .align 4 + .globl PR_EnterMonitor +PR_EnterMonitor: + mov %eax, 4(%esp) + jmp _PR_EnterMonitor + + .align 4 + .globl PR_ExitMonitor +PR_ExitMonitor: + mov %eax, 4(%esp) + jmp _PR_ExitMonitor + + + + .align 4 + .globl PR_AttachThread +PR_AttachThread: + mov %eax, 4(%esp) + mov %edx, 8(%esp) + mov %ecx, 12(%esp) + jmp _PR_AttachThread + + .align 4 + .globl PR_DetachThread +PR_DetachThread: + jmp _PR_DetachThread + + .align 4 + .globl PR_GetCurrentThread +PR_GetCurrentThread: + jmp _PR_GetCurrentThread + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vacpp.asm b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vacpp.asm new file mode 100644 index 00000000..0f07f2f6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/os2/os2vacpp.asm @@ -0,0 +1,293 @@ +COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + ***** 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 mozilla.org Code. + + The Initial Developer of the Original Code is + Netscape Communications Corporation. + Portions created by the Initial Developer are Copyright (C) 2001 + 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 ***** + 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 IBM Corporation. + Portions created by IBM are Copyright (C) 2001 IBM Corporation. + All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License Version 2 or later (the + "GPL"), in which case the provisions of the GPL are applicable + instead of those above. If you wish to allow use of your + version of this file only under the terms of the GPL and not to + allow others to use your version of this file under the MPL, + indicate your decision by deleting the provisions above and + replace them with the notice and other provisions required by + the GPL. If you do not delete the provisions above, a recipient + may use your version of this file under either the MPL or the + GPL. + + Windows uses inline assembly for their atomic functions, so we have + created an assembly file for VACPP on OS/2. + + This assembly file also contains an implementation of RAM semaphores. + + Notes: + The ulTIDPID element of the RAMSEM structure is overloaded in the 386 + implementation to hold the TID:PID in the lower 31 bits and the lock + bit in the high bit + | + page ,132 + + .486P + ASSUME CS:FLAT, DS:FLAT, SS:FLAT, ES:FLAT, FS:FLAT + + EXTRN Dos32PostEventSem:PROC + EXTRN Dos32WaitEventSem:PROC + EXTRN Dos32ResetEventSem:PROC + +ramsem STRUC + ramsem_ulTIDPID DD ? + ramsem_hevSem DD ? + ramsem_cLocks DD ? + ramsem_cWaiting DW ? + ramsem_cPosts DW ? +ramsem ENDS + +ERROR_SEM_TIMEOUT equ 121 +ERROR_NOT_OWNER equ 288 +SEM_RELEASE_UNOWNED equ 1 +SEM_RELEASE_ALL equ 2 +TS_LOCKBIT equ 31 + + +DATA SEGMENT DWORD USE32 PUBLIC 'DATA' + + EXTRN plisCurrent:DWORD + +DATA ENDS + +CODE32 SEGMENT USE32 PUBLIC 'CODE' + + PUBLIC SemRequest486 + PUBLIC SemReleasex86 + + PUBLIC _PR_MD_ATOMIC_SET + PUBLIC _PR_MD_ATOMIC_ADD + PUBLIC _PR_MD_ATOMIC_INCREMENT + PUBLIC _PR_MD_ATOMIC_DECREMENT + +;;;--------------------------------------------------------------------------- +;;; APIRET _Optlink SemRequest(PRAMSEM pramsem, ULONG ulTimeout); +;;; +;;; Registers: +;;; EAX - packed TID:PID word +;;; ECX - address of RAMSEM structure +;;; EDX - length of timeout in milli-seconds +;;;--------------------------------------------------------------------------- + + ALIGN 10H +SemRequest486 PROC + push ebx ; Save ebx (volatile) + mov ecx, eax ; PRAMSEM must be in ecx, + ; not eax, for cmpxchg + + mov ebx, dword ptr [plisCurrent] + mov eax, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov ax, word ptr [ebx] ; word + mov ebx,eax + +req486_test: + xor eax,eax + cmp (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx ; If we own the sem, just + jz short req486_inc_exit ; increment the use count + + lock inc (ramsem PTR [ecx]).ramsem_cWaiting ; inc waiting flag + +; lock ; Uncomment for SMP + DB 0F0h +; cmpxchg (ramsem PTR [ecx]).ramsem_ulTIDPID, ebx +; (byte 3 is the offset of ulProcessThread into the RAMSEM structure) + DB 00Fh + DB 0B1h + DB 019h + jnz short req486_sleep + +req486_inc_exit: + lock inc (ramsem PTR [ecx]).ramsem_cLocks + +req486_exit: + pop ebx ; Restore ebx + ret + +req486_sleep: + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + push edx ; timeout + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32WaitEventSem + add esp, 8 + pop edx ; restore edx + pop ecx ; restore ecx + or eax, eax + jne req486_exit ; Exit, if error + + push ecx ; Save ecx (volatile) + push edx ; Save edx (volatile) + sub esp, 4 ; Use stack space for + push esp ; dummy pulPostCt + push (ramsem PTR [ecx]).ramsem_hevSem + call Dos32ResetEventSem + add esp, 12 + pop edx ; restore edx + pop ecx ; restore ecx + jmp req486_test ; Retry the semaphore + +SemRequest486 ENDP + +;;;--------------------------------------------------------------------- +;;; APIRET _Optlink SemReleasex86(PRAMSEM pramsem, ULONG flFlags); +;;; +;;; Registers: +;;; EAX - address of RAMSEM structure +;;; ECX - temporary variable +;;; EDX - flags +;;;--------------------------------------------------------------------- + + ALIGN 10H +SemReleasex86 PROC + test edx, SEM_RELEASE_UNOWNED ; If set, don't bother + jnz short rel_ownerok ; getting/checking PID/TID + + push ebx ; Save ebx (volatile) + mov ebx, dword ptr [plisCurrent] + mov ecx, dword ptr [ebx+4] ; Place thread id in high + ; word, process id in low + mov cx, word ptr [ebx] ; word + pop ebx ; Restore ebx + + sub ecx, (ramsem PTR [eax]).ramsem_ulTIDPID ; This thread the owner? + shl ecx,1 ; Don't compare top bit + jnz short rel_notowner + +rel_ownerok: + test edx, SEM_RELEASE_ALL + jnz short rel_clear + + lock dec (ramsem PTR [eax]).ramsem_cLocks + jnz short rel_exit + +rel_disown: + mov (ramsem PTR [eax]).ramsem_ulTIDPID, 0 + + lock inc (ramsem PTR [eax]).ramsem_cPosts + mov cx, (ramsem PTR [eax]).ramsem_cWaiting + cmp (ramsem PTR [eax]).ramsem_cPosts, cx + jne short rel_post + +rel_exit: + xor eax, eax + ret + +rel_clear: + lock mov (ramsem PTR [eax]).ramsem_cLocks,0 + jmp rel_disown + +rel_notowner: + mov eax, ERROR_NOT_OWNER + ret + +rel_post: + mov (ramsem PTR [eax]).ramsem_cPosts, cx + push (ramsem PTR [eax]).ramsem_hevSem + call Dos32PostEventSem + add esp,4 + xor eax,eax + ret +SemReleasex86 ENDP + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_SET proc + lock xchg dword ptr [eax],edx + mov eax, edx; + ret +_PR_MD_ATOMIC_SET endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_ADD proc + mov ecx, edx + lock xadd dword ptr [eax], edx + mov eax, edx + add eax, ecx + ret +_PR_MD_ATOMIC_ADD endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_INCREMENT(PRInt32* val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_INCREMENT proc + mov edx, 1 + lock xadd dword ptr [eax], edx + mov eax, edx + inc eax + ret +_PR_MD_ATOMIC_INCREMENT endp + +;;;--------------------------------------------------------------------- +;;; PRInt32 _Optlink _PR_MD_ATOMIC_DECREMENT(PRInt32* val) +;;;--------------------------------------------------------------------- + ALIGN 10H +_PR_MD_ATOMIC_DECREMENT proc + mov edx, 0ffffffffh + lock xadd dword ptr [eax], edx + mov eax, edx + dec eax + ret +_PR_MD_ATOMIC_DECREMENT endp + +CODE32 ENDS +END diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/prosdep.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/prosdep.c new file mode 100644 index 00000000..9ae80965 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/prosdep.c @@ -0,0 +1,114 @@ +/* -*- 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 "prbit.h" +#include "prsystem.h" + +#ifdef XP_UNIX +#include +#endif +#ifdef SUNOS4 +#include "md/sunos4.h" +#endif +#ifdef _WIN32 +#include +#endif +#ifdef XP_BEOS +#include +#endif + +PRInt32 _pr_pageShift; +PRInt32 _pr_pageSize; + +/* +** Get system page size +*/ +static void GetPageSize(void) +{ + PRInt32 pageSize; + + /* Get page size */ +#ifdef XP_UNIX +#if defined SUNOS4 || defined LINUX || defined BSDI || defined AIX \ + || defined FREEBSD || defined NETBSD || defined OPENBSD \ + || defined DARWIN || defined NEXTSTEP + _pr_pageSize = getpagesize(); +#elif defined(HPUX) + /* I have no idea. Don't get me started. --Rob */ + _pr_pageSize = sysconf(_SC_PAGE_SIZE); +#else + _pr_pageSize = sysconf(_SC_PAGESIZE); +#endif +#endif /* XP_UNIX */ + +#ifdef XP_MAC + _pr_pageSize = 4096; +#endif /* XP_MAC */ + +#ifdef XP_BEOS + _pr_pageSize = B_PAGE_SIZE; +#endif + +#ifdef XP_PC +#ifdef _WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + _pr_pageSize = info.dwPageSize; +#else + _pr_pageSize = 4096; +#endif +#endif /* XP_PC */ + + pageSize = _pr_pageSize; + PR_CEILING_LOG2(_pr_pageShift, pageSize); +} + +PR_IMPLEMENT(PRInt32) PR_GetPageShift(void) +{ + if (!_pr_pageSize) { + GetPageSize(); + } + return _pr_pageShift; +} + +PR_IMPLEMENT(PRInt32) PR_GetPageSize(void) +{ + if (!_pr_pageSize) { + GetPageSize(); + } + return _pr_pageSize; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/Makefile.in new file mode 100644 index 00000000..1c4c071c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/Makefile.in @@ -0,0 +1,135 @@ +# +# ***** 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 ***** + + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = \ + unix.c \ + unix_errors.c \ + uxproces.c \ + uxrng.c \ + uxshm.c \ + uxwrap.c \ + $(NULL) + +ifneq ($(USE_PTHREADS),1) +CSRCS += uxpoll.c +endif + +ifeq ($(PTHREADS_USER),1) +CSRCS += pthreads_user.c +endif + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +TARGETS = $(OBJS) + +ifeq ($(OS_ARCH),SunOS) + ifneq ($(OS_RELEASE),4.1.3_U1) + ifeq ($(OS_TEST),sun4u) + ifdef USE_64 + ULTRASPARC_ASFILES = os_SunOS_sparcv9.s + ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX))) + else + LIBRARY_NAME = $(ULTRASPARC_LIBRARY) + LIBRARY_VERSION = $(MOD_MAJOR_VERSION) + ULTRASPARC_ASFILES = os_SunOS_ultrasparc.s + ULTRASPARC_ASOBJS = $(addprefix $(OBJDIR)/,$(ULTRASPARC_ASFILES:.s=.$(OBJ_SUFFIX))) + TARGETS += $(ULTRASPARC_ASOBJS) $(SHARED_LIBRARY) + RELEASE_LIBS = $(SHARED_LIBRARY) + RELEASE_LIBS_DEST = $(RELEASE_LIB_DIR)/cpu/sparcv8plus + lib_subdir = cpu/sparcv8plus + endif + endif + endif +endif + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + +ifeq ($(OS_ARCH),SunOS) +ifneq ($(OS_RELEASE),4.1.3_U1) +ifeq ($(OS_TEST),sun4u) + +ifdef USE_64 +$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES) + /usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v9 $< +else +$(SHARED_LIBRARY): $(ULTRASPARC_ASOBJS) + $(LD) -G -z text -z endfiltee -o $@ $(ULTRASPARC_ASOBJS) + $(INSTALL) -m 444 $@ $(dist_libdir)/cpu/sparcv8plus + $(INSTALL) -m 444 $@ $(dist_bindir)/cpu/sparcv8plus +# +# The -f $(ORIGIN)/... linker flag uses the real file, after symbolic links +# are resolved, as the origin. If NSDISTMODE is not "copy", libnspr4.so +# will be installed as a symbolic link in $(dist_libdir), pointing to the +# real libnspr4.so file in pr/src. Therefore we need to install an +# additional copy of libnspr_flt4.so in pr/src/cpu/sparcv8plus. +# +ifneq ($(NSDISTMODE),copy) + $(INSTALL) -m 444 $@ ../../cpu/sparcv8plus +endif + +ifneq ($(NSDISTMODE),copy) +clobber realclean clobber_all distclean:: + rm -rf ../../cpu +endif + +$(ULTRASPARC_ASOBJS): $(ULTRASPARC_ASFILES) + /usr/ccs/bin/as -o $@ -K PIC -P -D_ASM -D__STDC__=0 -xarch=v8plus $< + +clean:: + rm -rf $(ULTRASPARC_ASOBJS) +endif + +endif +endif +endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aix.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aix.c new file mode 100644 index 00000000..ae945b1b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aix.c @@ -0,0 +1,333 @@ +/* -*- 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" + +#ifdef AIX_HAVE_ATOMIC_OP_H +#include + +PRInt32 _AIX_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + PRIntn oldval; + boolean_t stored; + oldval = fetch_and_add((atomic_p)val, 0); + do + { + stored = compare_and_swap((atomic_p)val, &oldval, newval); + } while (!stored); + return oldval; +} /* _AIX_AtomicSet */ +#endif /* AIX_HAVE_ATOMIC_OP_H */ + +#if defined(AIX_TIMERS) + +#include + +static PRUint32 _aix_baseline_epoch; + +static void _MD_AixIntervalInit(void) +{ + timebasestruct_t real_time; + read_real_time(&real_time, TIMEBASE_SZ); + (void)time_base_to_time(&real_time, TIMEBASE_SZ); + _aix_baseline_epoch = real_time.tb_high; +} /* _MD_AixIntervalInit */ + +PRIntervalTime _MD_AixGetInterval(void) +{ + PRIntn rv; + PRUint64 temp; + timebasestruct_t real_time; + read_real_time(&real_time, TIMEBASE_SZ); + (void)time_base_to_time(&real_time, TIMEBASE_SZ); + /* tb_high is in seconds, tb_low in 10(-9)seconds */ + temp = 1000000000ULL * (PRUint64)(real_time.tb_high - _aix_baseline_epoch); + temp += (PRUint64)real_time.tb_low; /* everything's 10(-9) seconds */ + temp >>= 16; /* now it's something way different */ + return (PRIntervalTime)temp; +} /* _MD_AixGetInterval */ + +PRIntervalTime _MD_AixIntervalPerSec(void) +{ + return 1000000000ULL >> 16; /* that's 15258, I think */ +} /* _MD_AixIntervalPerSec */ + +#endif /* defined(AIX_TIMERS) */ + +#if !defined(PTHREADS_USER) + +#if defined(_PR_PTHREADS) + +/* + * AIX 4.3 has sched_yield(). AIX 4.2 has pthread_yield(). + * So we look up the appropriate function pointer at run time. + */ + +#include + +int (*_PT_aix_yield_fcn)() = NULL; +int _pr_aix_send_file_use_disabled = 0; + +void _MD_EarlyInit(void) +{ + void *main_app_handle; + char *evp; + + main_app_handle = dlopen(NULL, RTLD_NOW); + PR_ASSERT(NULL != main_app_handle); + + _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle, "sched_yield"); + if (!_PT_aix_yield_fcn) { + _PT_aix_yield_fcn = (int(*)())dlsym(main_app_handle,"pthread_yield"); + PR_ASSERT(NULL != _PT_aix_yield_fcn); + } + dlclose(main_app_handle); + + if (evp = getenv("NSPR_AIX_SEND_FILE_USE_DISABLED")) { + if (1 == atoi(evp)) + _pr_aix_send_file_use_disabled = 1; + } + +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif +} + +#else /* _PR_PTHREADS */ + +void _MD_EarlyInit(void) +{ +#if defined(AIX_TIMERS) + _MD_AixIntervalInit(); +#endif +} + +#endif /* _PR_PTHREADS */ + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +PR_IMPLEMENT(void) +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PR_IMPLEMENT(PRStatus) +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for AIX */ +PR_IMPLEMENT(void) +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); +} + +PR_IMPLEMENT(PRStatus) +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for AIX."); +} +#endif /* _PR_PTHREADS */ +#endif /* PTHREADS_USER */ + +/* + * NSPR 2.0 overrides the system select() and poll() functions. + * On AIX 4.2, we use dlopen("/unix", RTLD_NOW) and dlsym() to get + * at the original system select() and poll() functions. + */ + +#if !defined(AIX_RENAME_SELECT) + +#include +#include +#include + +static int (*aix_select_fcn)() = NULL; +static int (*aix_poll_fcn)() = NULL; + +int _MD_SELECT(int width, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) +{ + int rv; + + if (!aix_select_fcn) { + void *aix_handle; + + aix_handle = dlopen("/unix", RTLD_NOW); + if (!aix_handle) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + aix_select_fcn = (int(*)())dlsym(aix_handle,"select"); + dlclose(aix_handle); + if (!aix_select_fcn) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + } + rv = (*aix_select_fcn)(width, r, w, e, t); + return rv; +} + +int _MD_POLL(void *listptr, unsigned long nfds, long timeout) +{ + int rv; + + if (!aix_poll_fcn) { + void *aix_handle; + + aix_handle = dlopen("/unix", RTLD_NOW); + if (!aix_handle) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + aix_poll_fcn = (int(*)())dlsym(aix_handle,"poll"); + dlclose(aix_handle); + if (!aix_poll_fcn) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + } + rv = (*aix_poll_fcn)(listptr, nfds, timeout); + return rv; +} + +#else + +/* + * In AIX versions prior to 4.2, we use the two-step rename/link trick. + * The binary must contain at least one "poll" symbol for linker's rename + * to work. So we must have this dummy function that references poll(). + */ +#include +void _pr_aix_dummy() +{ + poll(0,0,0); +} + +#endif /* !defined(AIX_RENAME_SELECT) */ + +#ifdef _PR_HAVE_ATOMIC_CAS + +#include "pratom.h" + +#define _PR_AIX_ATOMIC_LOCK -1 + +PR_IMPLEMENT(void) +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +PRStackElem *addr; +boolean_t locked = TRUE; + + /* Is it safe to cast a pointer to an int? */ + PR_ASSERT(sizeof(int) == sizeof(PRStackElem *)); + do { + while ((addr = stack->prstk_head.prstk_elem_next) == + (PRStackElem *)_PR_AIX_ATOMIC_LOCK) + ; + locked = _check_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int) addr, _PR_AIX_ATOMIC_LOCK); + } while (locked == TRUE); + stack_elem->prstk_elem_next = addr; + _clear_lock((atomic_p)&stack->prstk_head.prstk_elem_next, (int)stack_elem); + return; +} + +PR_IMPLEMENT(PRStackElem *) +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; +boolean_t locked = TRUE; + + /* Is it safe to cast a pointer to an int? */ + PR_ASSERT(sizeof(int) == sizeof(PRStackElem *)); + do { + while ((element = stack->prstk_head.prstk_elem_next) == + (PRStackElem *) _PR_AIX_ATOMIC_LOCK) + ; + locked = _check_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int)element, _PR_AIX_ATOMIC_LOCK); + } while (locked == TRUE); + + if (element == NULL) { + _clear_lock((atomic_p) &stack->prstk_head.prstk_elem_next, NULL); + } else { + _clear_lock((atomic_p) &stack->prstk_head.prstk_elem_next, + (int) element->prstk_elem_next); + } + return element; +} + +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aixwrap.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aixwrap.c new file mode 100644 index 00000000..d829710a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/aixwrap.c @@ -0,0 +1,65 @@ +/* -*- 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 ***** */ + +/* + * File: aixwrap.c + * Description: + * This file contains a single function, _MD_SELECT(), which simply + * invokes the select() function. This file is used in an ugly + * hack to override the system select() function on AIX releases + * prior to 4.2. (On AIX 4.2, we use a different mechanism to + * override select().) + */ + +#ifndef AIX_RENAME_SELECT +#error aixwrap.c should only be used on AIX 3.2 or 4.1 +#else + +#include +#include + +int _MD_SELECT(int width, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) +{ + return select(width, r, w, e, t); +} + +int _MD_POLL(void *listptr, unsigned long nfds, long timeout) +{ + return poll(listptr, nfds, timeout); +} + +#endif /* AIX_RENAME_SELECT */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/bsdi.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/bsdi.c new file mode 100644 index 00000000..64676633 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/bsdi.c @@ -0,0 +1,119 @@ +/* -*- 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 + +void _MD_EarlyInit(void) +{ + /* + * Ignore FPE because coercion of a NaN to an int causes SIGFPE + * to be raised. + */ + struct sigaction act; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + sigaction(SIGFPE, &act, 0); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for BSDI */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for BSDI."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for BSDI."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/darwin.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/darwin.c new file mode 100644 index 00000000..3a1329e7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/darwin.c @@ -0,0 +1,110 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if !defined(_PR_PTHREADS) + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#if !defined(_PR_PTHREADS) +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Darwin */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Darwin."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Darwin."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ + +/* darwin.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/dgux.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/dgux.c new file mode 100644 index 00000000..2874d9ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/dgux.c @@ -0,0 +1,109 @@ +/* -*- 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" + +/* + * using only NSPR threads here + * + * Copied from the UnixWare implementation. Should be kept in sync + * with ../../../include/md/_dgux.h. + */ + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for DG/UX */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for DG/UX."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for DG/UX."); +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/freebsd.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/freebsd.c new file mode 100644 index 00000000..dce244a3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/freebsd.c @@ -0,0 +1,119 @@ +/* -*- 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 + +void _MD_EarlyInit(void) +{ + /* + * Ignore FPE because coercion of a NaN to an int causes SIGFPE + * to be raised. + */ + struct sigaction act; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + sigaction(SIGFPE, &act, 0); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) sigsetjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for FreeBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for FreeBSD."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for FreeBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/hpux.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/hpux.c new file mode 100644 index 00000000..cf43e05e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/hpux.c @@ -0,0 +1,261 @@ +/* -*- 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 + +#if defined(HPUX_LW_TIMER) + +#include +#include +#include +#include +#include + +int __lw_get_thread_times(int which, int64_t *sample, int64_t *time); + +static double msecond_per_itick; + +void _PR_HPUX_LW_IntervalInit(void) +{ + struct pst_processor psp; + int iticksperclktick, clk_tck; + int rv; + + rv = pstat_getprocessor(&psp, sizeof(psp), 1, 0); + PR_ASSERT(rv != -1); + + iticksperclktick = psp.psp_iticksperclktick; + clk_tck = sysconf(_SC_CLK_TCK); + msecond_per_itick = (1000.0)/(double)(iticksperclktick * clk_tck); +} + +PRIntervalTime _PR_HPUX_LW_GetInterval(void) +{ + int64_t time, sample; + + __lw_get_thread_times(1, &sample, &time); + /* + * Division is slower than float multiplication. + * return (time / iticks_per_msecond); + */ + return (time * msecond_per_itick); +} +#endif /* HPUX_LW_TIMER */ + +#if !defined(PTHREADS_USER) + +void _MD_EarlyInit(void) +{ +#ifndef _PR_PTHREADS + /* + * The following piece of code is taken from ns/nspr/src/md_HP-UX.c. + * In the comment for revision 1.6, dated 1995/09/11 23:33:34, + * robm says: + * This version has some problems which need to be addressed. + * First, intercept all system calls and prevent them from + * executing the library code which performs stack switches + * before normal system call invocation. In order for library + * calls which make system calls to work (like stdio), however, + * we must also allocate our own stack and switch the primordial + * stack to use it. This isn't so bad, except that I fudged the + * backtrace length when copying the old stack to the new one. + * + * This is the original comment of robm in the code: + * XXXrobm Horrific. To avoid a problem with HP's system call + * code, we allocate a new stack for the primordial thread and + * use it. However, we don't know how far back the original stack + * goes. We should create a routine that performs a backtrace and + * finds out just how much we need to copy. As a temporary measure, + * I just copy an arbitrary guess. + * + * In an email to servereng dated 2 Jan 1997, Mike Patnode (mikep) + * suggests that this only needs to be done for HP-UX 9. + */ +#ifdef HPUX9 +#define PIDOOMA_STACK_SIZE 524288 +#define BACKTRACE_SIZE 8192 + { + jmp_buf jb; + char *newstack; + char *oldstack; + + if(!setjmp(jb)) { + newstack = (char *) PR_MALLOC(PIDOOMA_STACK_SIZE); + oldstack = (char *) (*(((int *) jb) + 1) - BACKTRACE_SIZE); + memcpy(newstack, oldstack, BACKTRACE_SIZE); + *(((int *) jb) + 1) = (int) (newstack + BACKTRACE_SIZE); + longjmp(jb, 1); + } + } +#endif /* HPUX9 */ +#endif /* !_PR_PTHREADS */ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for HP-UX */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for HP-UX."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for HP-UX."); +} +#endif /* _PR_PTHREADS */ + +void +_MD_suspend_thread(PRThread *thread) +{ +#ifdef _PR_PTHREADS +#endif +} + +void +_MD_resume_thread(PRThread *thread) +{ +#ifdef _PR_PTHREADS +#endif +} +#endif /* PTHREADS_USER */ + +/* + * The HP version of strchr is buggy. It looks past the end of the + * string and causes a segmentation fault when our (NSPR) version + * of malloc is used. + * + * A better solution might be to put a cushion in our malloc just in + * case HP's version of strchr somehow gets used instead of this one. + */ +char * +strchr(const char *s, int c) +{ + char ch; + + if (!s) { + return NULL; + } + + ch = (char) c; + + while ((*s) && ((*s) != ch)) { + s++; + } + + if ((*s) == ch) { + return (char *) s; + } + + return NULL; +} + +/* + * Implemementation of memcmp in HP-UX (verified on releases A.09.03, + * A.09.07, and B.10.10) dumps core if called with: + * 1. First operand with address = 1(mod 4). + * 2. Size = 1(mod 4) + * 3. Last byte of the second operand is the last byte of the page and + * next page is not accessible(not mapped or protected) + * Thus, using the following naive version (tons of optimizations are + * possible;^) + */ + +int memcmp(const void *s1, const void *s2, size_t n) +{ + register unsigned char *p1 = (unsigned char *) s1, + *p2 = (unsigned char *) s2; + + while (n-- > 0) { + register int r = ((int) ((unsigned int) *p1)) + - ((int) ((unsigned int) *p2)); + if (r) return r; + p1++; p2++; + } + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/irix.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/irix.c new file mode 100644 index 00000000..758e54d2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/irix.c @@ -0,0 +1,1680 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void _MD_IrixIntervalInit(void); + +#if defined(_PR_PTHREADS) +/* + * for compatibility with classic nspr + */ +void _PR_IRIX_CHILD_PROCESS() +{ +} +#else /* defined(_PR_PTHREADS) */ + +static void irix_detach_sproc(void); +char *_nspr_sproc_private; /* ptr. to private region in every sproc */ + +extern PRUintn _pr_numCPU; + +typedef struct nspr_arena { + PRCList links; + usptr_t *usarena; +} nspr_arena; + +#define ARENA_PTR(qp) \ + ((nspr_arena *) ((char*) (qp) - offsetof(nspr_arena , links))) + +static usptr_t *alloc_new_arena(void); + +PRCList arena_list = PR_INIT_STATIC_CLIST(&arena_list); +ulock_t arena_list_lock; +nspr_arena first_arena; +int _nspr_irix_arena_cnt = 1; + +PRCList sproc_list = PR_INIT_STATIC_CLIST(&sproc_list); +ulock_t sproc_list_lock; + +typedef struct sproc_data { + void (*entry) (void *, size_t); + unsigned inh; + void *arg; + caddr_t sp; + size_t len; + int *pid; + int creator_pid; +} sproc_data; + +typedef struct sproc_params { + PRCList links; + sproc_data sd; +} sproc_params; + +#define SPROC_PARAMS_PTR(qp) \ + ((sproc_params *) ((char*) (qp) - offsetof(sproc_params , links))) + +long _nspr_irix_lock_cnt = 0; +long _nspr_irix_sem_cnt = 0; +long _nspr_irix_pollsem_cnt = 0; + +usptr_t *_pr_usArena; +ulock_t _pr_heapLock; + +usema_t *_pr_irix_exit_sem; +PRInt32 _pr_irix_exit_now = 0; +PRInt32 _pr_irix_process_exit_code = 0; /* exit code for PR_ProcessExit */ +PRInt32 _pr_irix_process_exit = 0; /* process exiting due to call to + PR_ProcessExit */ + +int _pr_irix_primoridal_cpu_fd[2] = { -1, -1 }; +static void (*libc_exit)(int) = NULL; +static void *libc_handle = NULL; + +#define _NSPR_DEF_INITUSERS 100 /* default value of CONF_INITUSERS */ +#define _NSPR_DEF_INITSIZE (4 * 1024 * 1024) /* 4 MB */ + +int _irix_initusers = _NSPR_DEF_INITUSERS; +int _irix_initsize = _NSPR_DEF_INITSIZE; + +PRIntn _pr_io_in_progress, _pr_clock_in_progress; + +PRInt32 _pr_md_irix_sprocs_created, _pr_md_irix_sprocs_failed; +PRInt32 _pr_md_irix_sprocs = 1; +PRCList _pr_md_irix_sproc_list = +PR_INIT_STATIC_CLIST(&_pr_md_irix_sproc_list); + +sigset_t ints_off; +extern sigset_t timer_set; + +#if !defined(PR_SETABORTSIG) +#define PR_SETABORTSIG 18 +#endif +/* + * terminate the entire application if any sproc exits abnormally + */ +PRBool _nspr_terminate_on_error = PR_TRUE; + +/* + * exported interface to set the shared arena parameters + */ +void _PR_Irix_Set_Arena_Params(PRInt32 initusers, PRInt32 initsize) +{ + _irix_initusers = initusers; + _irix_initsize = initsize; +} + +static usptr_t *alloc_new_arena() +{ + return(usinit("/dev/zero")); +} + +static PRStatus new_poll_sem(struct _MDThread *mdthr, int val) +{ +PRIntn _is; +PRStatus rv = PR_SUCCESS; +usema_t *sem = NULL; +PRCList *qp; +nspr_arena *arena; +usptr_t *irix_arena; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + _PR_LOCK(arena_list_lock); + for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { + arena = ARENA_PTR(qp); + sem = usnewpollsema(arena->usarena, val); + if (sem != NULL) { + mdthr->cvar_pollsem = sem; + mdthr->pollsem_arena = arena->usarena; + break; + } + } + if (sem == NULL) { + /* + * If no space left in the arena allocate a new one. + */ + if (errno == ENOMEM) { + arena = PR_NEWZAP(nspr_arena); + if (arena != NULL) { + irix_arena = alloc_new_arena(); + if (irix_arena) { + PR_APPEND_LINK(&arena->links, &arena_list); + _nspr_irix_arena_cnt++; + arena->usarena = irix_arena; + sem = usnewpollsema(arena->usarena, val); + if (sem != NULL) { + mdthr->cvar_pollsem = sem; + mdthr->pollsem_arena = arena->usarena; + } else + rv = PR_FAILURE; + } else { + PR_DELETE(arena); + rv = PR_FAILURE; + } + + } else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + } + _PR_UNLOCK(arena_list_lock); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + if (rv == PR_SUCCESS) + _MD_ATOMIC_INCREMENT(&_nspr_irix_pollsem_cnt); + return rv; +} + +static void free_poll_sem(struct _MDThread *mdthr) +{ +PRIntn _is; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + usfreepollsema(mdthr->cvar_pollsem, mdthr->pollsem_arena); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + _MD_ATOMIC_DECREMENT(&_nspr_irix_pollsem_cnt); +} + +static PRStatus new_lock(struct _MDLock *lockp) +{ +PRIntn _is; +PRStatus rv = PR_SUCCESS; +ulock_t lock = NULL; +PRCList *qp; +nspr_arena *arena; +usptr_t *irix_arena; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + _PR_LOCK(arena_list_lock); + for (qp = arena_list.next; qp != &arena_list; qp = qp->next) { + arena = ARENA_PTR(qp); + lock = usnewlock(arena->usarena); + if (lock != NULL) { + lockp->lock = lock; + lockp->arena = arena->usarena; + break; + } + } + if (lock == NULL) { + /* + * If no space left in the arena allocate a new one. + */ + if (errno == ENOMEM) { + arena = PR_NEWZAP(nspr_arena); + if (arena != NULL) { + irix_arena = alloc_new_arena(); + if (irix_arena) { + PR_APPEND_LINK(&arena->links, &arena_list); + _nspr_irix_arena_cnt++; + arena->usarena = irix_arena; + lock = usnewlock(irix_arena); + if (lock != NULL) { + lockp->lock = lock; + lockp->arena = arena->usarena; + } else + rv = PR_FAILURE; + } else { + PR_DELETE(arena); + rv = PR_FAILURE; + } + + } else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + } + _PR_UNLOCK(arena_list_lock); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + if (rv == PR_SUCCESS) + _MD_ATOMIC_INCREMENT(&_nspr_irix_lock_cnt); + return rv; +} + +static void free_lock(struct _MDLock *lockp) +{ +PRIntn _is; +PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + usfreelock(lockp->lock, lockp->arena); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); + _MD_ATOMIC_DECREMENT(&_nspr_irix_lock_cnt); +} + +void _MD_FREE_LOCK(struct _MDLock *lockp) +{ + PRIntn _is; + PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + free_lock(lockp); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); +} + +/* + * _MD_get_attached_thread + * Return the thread pointer of the current thread if it is attached. + * + * This function is needed for Irix because the thread-local-storage is + * implemented by mmapin'g a page with the MAP_LOCAL flag. This causes the + * sproc-private page to inherit contents of the page of the caller of sproc(). + */ +PRThread *_MD_get_attached_thread(void) +{ + + if (_MD_GET_SPROC_PID() == get_pid()) + return _MD_THIS_THREAD(); + else + return 0; +} + +/* + * _MD_get_current_thread + * Return the thread pointer of the current thread (attaching it if + * necessary) + */ +PRThread *_MD_get_current_thread(void) +{ +PRThread *me; + + me = _MD_GET_ATTACHED_THREAD(); + if (NULL == me) { + me = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(me != NULL); + return(me); +} + +/* + * irix_detach_sproc + * auto-detach a sproc when it exits + */ +void irix_detach_sproc(void) +{ +PRThread *me; + + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) { + _PRI_DetachThread(); + } +} + + +PRStatus _MD_NEW_LOCK(struct _MDLock *lockp) +{ + PRStatus rv; + PRIntn is; + PRThread *me = _MD_GET_ATTACHED_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + rv = new_lock(lockp); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return rv; +} + +static void +sigchld_handler(int sig) +{ + pid_t pid; + int status; + + /* + * If an sproc exited abnormally send a SIGKILL signal to all the + * sprocs in the process to terminate the application + */ + while ((pid = waitpid(0, &status, WNOHANG)) > 0) { + if (WIFSIGNALED(status) && ((WTERMSIG(status) == SIGSEGV) || + (WTERMSIG(status) == SIGBUS) || + (WTERMSIG(status) == SIGABRT) || + (WTERMSIG(status) == SIGILL))) { + + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } + } +} + +static void save_context_and_block(int sig) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +_PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + /* + * save context + */ + (void) setjmp(me->md.jb); + /* + * unblock the suspending thread + */ + if (me->cpu) { + /* + * I am a cpu thread, not a user-created GLOBAL thread + */ + unblockproc(cpu->md.suspending_id); + } else { + unblockproc(me->md.suspending_id); + } + /* + * now, block current thread + */ + blockproc(getpid()); +} + +/* +** The irix kernel has a bug in it which causes async connect's which are +** interrupted by a signal to fail terribly (EADDRINUSE is returned). +** We work around the bug by blocking signals during the async connect +** attempt. +*/ +PRInt32 _MD_irix_connect( + PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout) +{ + PRInt32 rv; + sigset_t oldset; + + sigprocmask(SIG_BLOCK, &ints_off, &oldset); + rv = connect(osfd, addr, addrlen); + sigprocmask(SIG_SETMASK, &oldset, 0); + + return(rv); +} + +#include "prprf.h" + +/********************************************************************/ +/********************************************************************/ +/*************** Various thread like things for IRIX ****************/ +/********************************************************************/ +/********************************************************************/ + +void *_MD_GetSP(PRThread *t) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + void *sp; + + if (me == t) + (void) setjmp(t->md.jb); + + sp = (void *)(t->md.jb[JB_SP]); + PR_ASSERT((sp >= (void *) t->stack->stackBottom) && + (sp <= (void *) (t->stack->stackBottom + t->stack->stackSize))); + return(sp); +} + +void _MD_InitLocks() +{ + char buf[200]; + char *init_users, *init_size; + + PR_snprintf(buf, sizeof(buf), "/dev/zero"); + + if (init_users = getenv("_NSPR_IRIX_INITUSERS")) + _irix_initusers = atoi(init_users); + + if (init_size = getenv("_NSPR_IRIX_INITSIZE")) + _irix_initsize = atoi(init_size); + + usconfig(CONF_INITUSERS, _irix_initusers); + usconfig(CONF_INITSIZE, _irix_initsize); + usconfig(CONF_AUTOGROW, 1); + usconfig(CONF_AUTORESV, 1); + if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) { + perror("PR_Init: unable to config mutex arena"); + exit(-1); + } + + _pr_usArena = usinit(buf); + if (!_pr_usArena) { + fprintf(stderr, + "PR_Init: Error - unable to create lock/monitor arena\n"); + exit(-1); + } + _pr_heapLock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; + + arena_list_lock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; + + sproc_list_lock = usnewlock(_pr_usArena); + _nspr_irix_lock_cnt++; + + _pr_irix_exit_sem = usnewsema(_pr_usArena, 0); + _nspr_irix_sem_cnt = 1; + + first_arena.usarena = _pr_usArena; + PR_INIT_CLIST(&first_arena.links); + PR_APPEND_LINK(&first_arena.links, &arena_list); +} + +/* _PR_IRIX_CHILD_PROCESS is a private API for Server group */ +void _PR_IRIX_CHILD_PROCESS() +{ +extern PRUint32 _pr_global_threads; + + PR_ASSERT(_PR_MD_CURRENT_CPU() == _pr_primordialCPU); + PR_ASSERT(_pr_numCPU == 1); + PR_ASSERT(_pr_global_threads == 0); + /* + * save the new pid + */ + _pr_primordialCPU->md.id = getpid(); + _MD_SET_SPROC_PID(getpid()); +} + +static PRStatus pr_cvar_wait_sem(PRThread *thread, PRIntervalTime timeout) +{ + int rv; + +#ifdef _PR_USE_POLL + struct pollfd pfd; + int msecs; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) + msecs = -1; + else + msecs = PR_IntervalToMilliseconds(timeout); +#else + struct timeval tv, *tvp; + fd_set rd; + + if(timeout == PR_INTERVAL_NO_TIMEOUT) + tvp = NULL; + else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&rd); + FD_SET(thread->md.cvar_pollsemfd, &rd); +#endif + + /* + * call uspsema only if a previous select call on this semaphore + * did not timeout + */ + if (!thread->md.cvar_pollsem_select) { + rv = _PR_WAIT_SEM(thread->md.cvar_pollsem); + PR_ASSERT(rv >= 0); + } else + rv = 0; +again: + if(!rv) { +#ifdef _PR_USE_POLL + pfd.events = POLLIN; + pfd.fd = thread->md.cvar_pollsemfd; + rv = _MD_POLL(&pfd, 1, msecs); +#else + rv = _MD_SELECT(thread->md.cvar_pollsemfd + 1, &rd, NULL,NULL,tvp); +#endif + if ((rv == -1) && (errno == EINTR)) { + rv = 0; + goto again; + } + PR_ASSERT(rv >= 0); + } + + if (rv > 0) { + /* + * acquired the semaphore, call uspsema next time + */ + thread->md.cvar_pollsem_select = 0; + return PR_SUCCESS; + } else { + /* + * select timed out; must call select, not uspsema, when trying + * to acquire the semaphore the next time + */ + thread->md.cvar_pollsem_select = 1; + return PR_FAILURE; + } +} + +PRStatus _MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + _MD_CHECK_FOR_EXIT(); + if (pr_cvar_wait_sem(thread, ticks) == PR_FAILURE) { + _MD_CHECK_FOR_EXIT(); + /* + * wait timed out + */ + _PR_THREAD_LOCK(thread); + if (thread->wait.cvar) { + /* + * The thread will remove itself from the waitQ + * of the cvar in _PR_WaitCondVar + */ + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + _PR_THREAD_UNLOCK(thread); + /* + * This thread was woken up by a notifying thread + * at the same time as a timeout; so, consume the + * extra post operation on the semaphore + */ + _MD_CHECK_FOR_EXIT(); + pr_cvar_wait_sem(thread, PR_INTERVAL_NO_TIMEOUT); + } + _MD_CHECK_FOR_EXIT(); + } + } else { + _PR_MD_SWITCH_CONTEXT(thread); + } + return PR_SUCCESS; +} + +PRStatus _MD_WakeupWaiter(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + PR_ASSERT(_pr_md_idle_cpus >= 0); + if (thread == NULL) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else if (!_PR_IS_NATIVE_THREAD(thread)) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else { + PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _MD_CVAR_POST_SEM(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + } + return PR_SUCCESS; +} + +void create_sproc (void (*entry) (void *, size_t), unsigned inh, + void *arg, caddr_t sp, size_t len, int *pid) +{ +sproc_params sparams; +char data; +int rv; +PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { + *pid = sprocsp(entry, /* startup func */ + inh, /* attribute flags */ + arg, /* thread param */ + sp, /* stack address */ + len); /* stack size */ + } else { + sparams.sd.entry = entry; + sparams.sd.inh = inh; + sparams.sd.arg = arg; + sparams.sd.sp = sp; + sparams.sd.len = len; + sparams.sd.pid = pid; + sparams.sd.creator_pid = getpid(); + _PR_LOCK(sproc_list_lock); + PR_APPEND_LINK(&sparams.links, &sproc_list); + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); + _PR_UNLOCK(sproc_list_lock); + blockproc(getpid()); + } +} + +/* + * _PR_MD_WAKEUP_PRIMORDIAL_CPU + * + * wakeup cpu 0 + */ + +void _PR_MD_WAKEUP_PRIMORDIAL_CPU() +{ +char data = '0'; +int rv; + + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); +} + +/* + * _PR_MD_primordial_cpu + * + * process events that need to executed by the primordial cpu on each + * iteration through the idle loop + */ + +void _PR_MD_primordial_cpu() +{ +PRCList *qp; +sproc_params *sp; +int pid; + + _PR_LOCK(sproc_list_lock); + while ((qp = sproc_list.next) != &sproc_list) { + sp = SPROC_PARAMS_PTR(qp); + PR_REMOVE_LINK(&sp->links); + pid = sp->sd.creator_pid; + (*(sp->sd.pid)) = sprocsp(sp->sd.entry, /* startup func */ + sp->sd.inh, /* attribute flags */ + sp->sd.arg, /* thread param */ + sp->sd.sp, /* stack address */ + sp->sd.len); /* stack size */ + unblockproc(pid); + } + _PR_UNLOCK(sproc_list_lock); +} + +PRStatus _MD_CreateThread(PRThread *thread, +void (*start)(void *), +PRThreadPriority priority, +PRThreadScope scope, +PRThreadState state, +PRUint32 stackSize) +{ + typedef void (*SprocEntry) (void *, size_t); + SprocEntry spentry = (SprocEntry)start; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 pid; + PRStatus rv; + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + thread->md.cvar_pollsem_select = 0; + thread->flags |= _PR_GLOBAL_SCOPE; + + thread->md.cvar_pollsemfd = -1; + if (new_poll_sem(&thread->md,0) == PR_FAILURE) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + thread->md.cvar_pollsemfd = + _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); + if ((thread->md.cvar_pollsemfd < 0)) { + free_poll_sem(&thread->md); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + create_sproc(spentry, /* startup func */ + PR_SALL, /* attribute flags */ + (void *)thread, /* thread param */ + NULL, /* stack address */ + stackSize, &pid); /* stack size */ + if (pid > 0) { + _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_created); + _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs); + rv = PR_SUCCESS; + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return rv; + } else { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; + _MD_ATOMIC_INCREMENT(&_pr_md_irix_sprocs_failed); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } +} + +void _MD_CleanThread(PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; + } +} + +void _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) +{ + return; +} + +extern void _MD_unix_terminate_waitpid_daemon(void); + +void +_MD_CleanupBeforeExit(void) +{ + extern PRInt32 _pr_cpus_exit; + + _MD_unix_terminate_waitpid_daemon(); + + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + /* + * Set a global flag, and wakeup all cpus which will notice the flag + * and exit. + */ + _pr_cpus_exit = getpid(); + _MD_Wakeup_CPUs(); + while(_pr_numCPU > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _pr_numCPU--; + } + } + /* + * cause global threads on the recycle list to exit + */ + _PR_DEADQ_LOCK; + if (_PR_NUM_DEADNATIVE != 0) { + PRThread *thread; + PRCList *ptr; + + ptr = _PR_DEADNATIVEQ.next; + while( ptr != &_PR_DEADNATIVEQ ) { + thread = _PR_THREAD_PTR(ptr); + _MD_CVAR_POST_SEM(thread); + ptr = ptr->next; + } + } + _PR_DEADQ_UNLOCK; + while(_PR_NUM_DEADNATIVE > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _PR_DEC_DEADNATIVE; + } +} + +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK +extern void __sgi_prda_procmask(int); +#endif + +PRStatus +_MD_InitAttachedThread(PRThread *thread, PRBool wakeup_parent) +{ + PRStatus rv = PR_SUCCESS; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + if (new_poll_sem(&thread->md,0) == PR_FAILURE) { + return PR_FAILURE; + } + thread->md.cvar_pollsemfd = + _PR_OPEN_POLL_SEM(thread->md.cvar_pollsem); + if ((thread->md.cvar_pollsemfd < 0)) { + free_poll_sem(&thread->md); + return PR_FAILURE; + } + if (_MD_InitThread(thread, PR_FALSE) == PR_FAILURE) { + close(thread->md.cvar_pollsemfd); + thread->md.cvar_pollsemfd = -1; + free_poll_sem(&thread->md); + thread->md.cvar_pollsem = NULL; + return PR_FAILURE; + } + } + return rv; +} + +PRStatus +_MD_InitThread(PRThread *thread, PRBool wakeup_parent) +{ + struct sigaction sigact; + PRStatus rv = PR_SUCCESS; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + thread->md.id = getpid(); + setblockproccnt(thread->md.id, 0); + _MD_SET_SPROC_PID(getpid()); +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK + /* + * enable user-level processing of sigprocmask(); this is an + * undocumented feature available in Irix 6.2, 6.3, 6.4 and 6.5 + */ + __sgi_prda_procmask(USER_LEVEL); +#endif + /* + * set up SIGUSR1 handler; this is used to save state + */ + sigact.sa_handler = save_context_and_block; + sigact.sa_flags = SA_RESTART; + /* + * Must mask clock interrupts + */ + sigact.sa_mask = timer_set; + sigaction(SIGUSR1, &sigact, 0); + + + /* + * PR_SETABORTSIG is a new command implemented in a patch to + * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all + * sprocs in the process when one of them terminates abnormally + * + */ + if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { + /* + * if (errno == EINVAL) + * + * PR_SETABORTSIG not supported under this OS. + * You may want to get a recent kernel rollup patch that + * supports this feature. + */ + } + /* + * SIGCLD handler for detecting abormally-terminating + * sprocs and for reaping sprocs + */ + sigact.sa_handler = sigchld_handler; + sigact.sa_flags = SA_RESTART; + sigact.sa_mask = ints_off; + sigaction(SIGCLD, &sigact, NULL); + } + return rv; +} + +/* + * PR_Cleanup should be executed on the primordial sproc; migrate the thread + * to the primordial cpu + */ + +void _PR_MD_PRE_CLEANUP(PRThread *me) +{ +PRIntn is; +_PRCPU *cpu = _pr_primordialCPU; + + PR_ASSERT(cpu); + + me->flags |= _PR_BOUND_THREAD; + + if (me->cpu->id != 0) { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, me->priority); + _PR_RUNQ_UNLOCK(cpu); + _MD_Wakeup_CPUs(); + + _PR_MD_SWITCH_CONTEXT(me); + + _PR_FAST_INTSON(is); + PR_ASSERT(me->cpu->id == 0); + } +} + +/* + * process exiting + */ +PR_EXTERN(void ) _MD_exit(PRIntn status) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); + + /* + * the exit code of the process is the exit code of the primordial + * sproc + */ + if (!_PR_IS_NATIVE_THREAD(me) && (_PR_MD_CURRENT_CPU()->id == 0)) { + /* + * primordial sproc case: call _exit directly + * Cause SIGKILL to be sent to other sprocs + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } else { + int rv; + char data; + sigset_t set; + + /* + * non-primordial sproc case: cause the primordial sproc, cpu 0, + * to wakeup and call _exit + */ + _pr_irix_process_exit = 1; + _pr_irix_process_exit_code = status; + rv = write(_pr_irix_primoridal_cpu_fd[1], &data, 1); + PR_ASSERT(rv == 1); + /* + * block all signals and wait for SIGKILL to terminate this sproc + */ + sigfillset(&set); + sigsuspend(&set); + /* + * this code doesn't (shouldn't) execute + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(status); + } +} + +/* + * Override the exit() function in libc to cause the process to exit + * when the primodial/main nspr thread calls exit. Calls to exit by any + * other thread simply result in a call to the exit function in libc. + * The exit code of the process is the exit code of the primordial + * sproc. + */ + +void exit(int status) +{ +PRThread *me, *thr; +PRCList *qp; + + if (!_pr_initialized) { + if (!libc_exit) { + + if (!libc_handle) + libc_handle = dlopen("libc.so",RTLD_NOW); + if (libc_handle) + libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); + } + if (libc_exit) + (*libc_exit)(status); + else + _exit(status); + } + + me = _PR_MD_CURRENT_THREAD(); + + if (me == NULL) /* detached thread */ + (*libc_exit)(status); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || + (_PR_MD_CURRENT_CPU())->id == me->cpu->id); + + if (me->flags & _PR_PRIMORDIAL) { + + me->flags |= _PR_BOUND_THREAD; + + PR_ASSERT((_PR_MD_CURRENT_CPU())->id == me->cpu->id); + if (me->cpu->id != 0) { + _PRCPU *cpu = _pr_primordialCPU; + PRIntn is; + + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, me->priority); + _PR_RUNQ_UNLOCK(cpu); + _MD_Wakeup_CPUs(); + + _PR_MD_SWITCH_CONTEXT(me); + + _PR_FAST_INTSON(is); + } + + PR_ASSERT((_PR_MD_CURRENT_CPU())->id == 0); + + if (prctl(PR_GETNSHARE) > 1) { +#define SPROC_EXIT_WAIT_TIME 5 + int sleep_cnt = SPROC_EXIT_WAIT_TIME; + + /* + * sprocs still running; caue cpus and recycled global threads + * to exit + */ + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + _MD_Wakeup_CPUs(); + } + _PR_DEADQ_LOCK; + if (_PR_NUM_DEADNATIVE != 0) { + PRThread *thread; + PRCList *ptr; + + ptr = _PR_DEADNATIVEQ.next; + while( ptr != &_PR_DEADNATIVEQ ) { + thread = _PR_THREAD_PTR(ptr); + _MD_CVAR_POST_SEM(thread); + ptr = ptr->next; + } + } + + while (sleep_cnt-- > 0) { + if (waitpid(0, NULL, WNOHANG) >= 0) + sleep(1); + else + break; + } + prctl(PR_SETEXITSIG, SIGKILL); + } + (*libc_exit)(status); + } else { + /* + * non-primordial thread; simply call exit in libc. + */ + (*libc_exit)(status); + } +} + + +void +_MD_InitRunningCPU(_PRCPU *cpu) +{ + extern int _pr_md_pipefd[2]; + + _MD_unix_init_running_cpu(cpu); + cpu->md.id = getpid(); + _MD_SET_SPROC_PID(getpid()); + if (_pr_md_pipefd[0] >= 0) { + _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0]; +#ifndef _PR_USE_POLL + FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu)); +#endif + } +} + +void +_MD_ExitThread(PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_ATOMIC_DECREMENT(&_pr_md_irix_sprocs); + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); + } +} + +void +_MD_SuspendCPU(_PRCPU *cpu) +{ + PRInt32 rv; + + cpu->md.suspending_id = getpid(); + rv = kill(cpu->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); + +} + +void +_MD_ResumeCPU(_PRCPU *cpu) +{ + unblockproc(cpu->md.id); +} + +#if 0 +/* + * save the register context of a suspended sproc + */ +void get_context(PRThread *thr) +{ + int len, fd; + char pidstr[24]; + char path[24]; + + /* + * open the file corresponding to this process in procfs + */ + sprintf(path,"/proc/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",thr->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + (void) ioctl(fd, PIOCGREG, thr->md.gregs); + close(fd); + } + return; +} +#endif /* 0 */ + +void +_MD_SuspendThread(PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); + + thread->md.suspending_id = getpid(); + rv = kill(thread->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +} + +void +_MD_ResumeThread(PRThread *thread) +{ + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); + (void)unblockproc(thread->md.id); +} + +/* + * return the set of processors available for scheduling procs in the + * "mask" argument + */ +PRInt32 _MD_GetThreadAffinityMask(PRThread *unused, PRUint32 *mask) +{ + PRInt32 nprocs, rv; + struct pda_stat *pstat; +#define MAX_PROCESSORS 32 + + nprocs = sysmp(MP_NPROCS); + if (nprocs < 0) + return(-1); + pstat = (struct pda_stat*)PR_MALLOC(sizeof(struct pda_stat) * nprocs); + if (pstat == NULL) + return(-1); + rv = sysmp(MP_STAT, pstat); + if (rv < 0) { + PR_DELETE(pstat); + return(-1); + } + /* + * look at the first 32 cpus + */ + nprocs = (nprocs > MAX_PROCESSORS) ? MAX_PROCESSORS : nprocs; + *mask = 0; + while (nprocs) { + if ((pstat->p_flags & PDAF_ENABLED) && + !(pstat->p_flags & PDAF_ISOLATED)) { + *mask |= (1 << pstat->p_cpuid); + } + nprocs--; + pstat++; + } + return 0; +} + +static char *_thr_state[] = { + "UNBORN", + "RUNNABLE", + "RUNNING", + "LOCK_WAIT", + "COND_WAIT", + "JOIN_WAIT", + "IO_WAIT", + "SUSPENDED", + "DEAD" +}; + +void _PR_List_Threads() +{ + PRThread *thr; + void *handle; + struct _PRCPU *cpu; + PRCList *qp; + int len, fd; + char pidstr[24]; + char path[24]; + prpsinfo_t pinfo; + + + printf("\n%s %-s\n"," ","LOCAL Threads"); + printf("%s %-s\n"," ","----- -------"); + printf("%s %-14s %-10s %-12s %-3s %-10s %-10s %-12s\n\n"," ", + "Thread", "State", "Wait-Handle", + "Cpu","Stk-Base","Stk-Sz","SP"); + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + thr = _PR_ACTIVE_THREAD_PTR(qp); + printf("%s 0x%-12x %-10s "," ",thr,_thr_state[thr->state]); + if (thr->state == _PR_LOCK_WAIT) + handle = thr->wait.lock; + else if (thr->state == _PR_COND_WAIT) + handle = thr->wait.cvar; + else + handle = NULL; + if (handle) + printf("0x%-10x ",handle); + else + printf("%-12s "," "); + printf("%-3d ",thr->cpu->id); + printf("0x%-8x ",thr->stack->stackBottom); + printf("0x%-8x ",thr->stack->stackSize); + printf("0x%-10x\n",thr->md.jb[JB_SP]); + } + + printf("\n%s %-s\n"," ","GLOBAL Threads"); + printf("%s %-s\n"," ","------ -------"); + printf("%s %-14s %-6s %-12s %-12s %-12s %-12s\n\n"," ","Thread", + "Pid","State","Wait-Handle", + "Stk-Base","Stk-Sz"); + + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + thr = _PR_ACTIVE_THREAD_PTR(qp); + if (thr->cpu != NULL) + continue; /* it is a cpu thread */ + printf("%s 0x%-12x %-6d "," ",thr,thr->md.id); + /* + * check if the sproc is still running + * first call prctl(PR_GETSHMASK,pid) to check if + * the process is part of the share group (the pid + * could have been recycled by the OS) + */ + if (prctl(PR_GETSHMASK,thr->md.id) < 0) { + printf("%-12s\n","TERMINATED"); + continue; + } + /* + * Now, check if the sproc terminated and is in zombie + * state + */ + sprintf(path,"/proc/pinfo/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",thr->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) + printf("%-12s ","TERMINATED"); + else if (pinfo.pr_zomb) + printf("%-12s ","TERMINATED"); + else + printf("%-12s ",_thr_state[thr->state]); + close(fd); + } else { + printf("%-12s ","TERMINATED"); + } + + if (thr->state == _PR_LOCK_WAIT) + handle = thr->wait.lock; + else if (thr->state == _PR_COND_WAIT) + handle = thr->wait.cvar; + else + handle = NULL; + if (handle) + printf("%-12x ",handle); + else + printf("%-12s "," "); + printf("0x%-10x ",thr->stack->stackBottom); + printf("0x%-10x\n",thr->stack->stackSize); + } + + printf("\n%s %-s\n"," ","CPUs"); + printf("%s %-s\n"," ","----"); + printf("%s %-14s %-6s %-12s \n\n"," ","Id","Pid","State"); + + + for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { + cpu = _PR_CPU_PTR(qp); + printf("%s %-14d %-6d "," ",cpu->id,cpu->md.id); + /* + * check if the sproc is still running + * first call prctl(PR_GETSHMASK,pid) to check if + * the process is part of the share group (the pid + * could have been recycled by the OS) + */ + if (prctl(PR_GETSHMASK,cpu->md.id) < 0) { + printf("%-12s\n","TERMINATED"); + continue; + } + /* + * Now, check if the sproc terminated and is in zombie + * state + */ + sprintf(path,"/proc/pinfo/%s","00000"); + len = strlen(path); + sprintf(pidstr,"%d",cpu->md.id); + len -= strlen(pidstr); + sprintf(path + len,"%s",pidstr); + fd = open(path,O_RDONLY); + if (fd >= 0) { + if (ioctl(fd, PIOCPSINFO, &pinfo) < 0) + printf("%-12s\n","TERMINATED"); + else if (pinfo.pr_zomb) + printf("%-12s\n","TERMINATED"); + else + printf("%-12s\n","RUNNING"); + close(fd); + } else { + printf("%-12s\n","TERMINATED"); + } + + } + fflush(stdout); +} +#endif /* defined(_PR_PTHREADS) */ + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if !defined(_PR_PTHREADS) + if (isCurrent) { + (void) setjmp(t->md.jb); + } + *np = sizeof(t->md.jb) / sizeof(PRWord); + return (PRWord *) (t->md.jb); +#else + *np = 0; + return NULL; +#endif +} + +void _MD_EarlyInit(void) +{ +#if !defined(_PR_PTHREADS) + char *eval; + int fd; + extern int __ateachexit(void (*func)(void)); + + sigemptyset(&ints_off); + sigaddset(&ints_off, SIGALRM); + sigaddset(&ints_off, SIGIO); + sigaddset(&ints_off, SIGCLD); + + if (eval = getenv("_NSPR_TERMINATE_ON_ERROR")) + _nspr_terminate_on_error = (0 == atoi(eval) == 0) ? PR_FALSE : PR_TRUE; + + fd = open("/dev/zero",O_RDWR , 0); + if (fd < 0) { + perror("open /dev/zero failed"); + exit(1); + } + /* + * Set up the sproc private data area. + * This region exists at the same address, _nspr_sproc_private, for + * every sproc, but each sproc gets a private copy of the region. + */ + _nspr_sproc_private = (char*)mmap(0, _pr_pageSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE| MAP_LOCAL, fd, 0); + if (_nspr_sproc_private == (void*)-1) { + perror("mmap /dev/zero failed"); + exit(1); + } + _MD_SET_SPROC_PID(getpid()); + close(fd); + __ateachexit(irix_detach_sproc); +#endif + _MD_IrixIntervalInit(); +} /* _MD_EarlyInit */ + +void _MD_IrixInit(void) +{ +#if !defined(_PR_PTHREADS) + struct sigaction sigact; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int rv; + +#ifdef _PR_HAVE_SGI_PRDA_PROCMASK + /* + * enable user-level processing of sigprocmask(); this is an undocumented + * feature available in Irix 6.2, 6.3, 6.4 and 6.5 + */ + __sgi_prda_procmask(USER_LEVEL); +#endif + + /* + * set up SIGUSR1 handler; this is used to save state + * during PR_SuspendAll + */ + sigact.sa_handler = save_context_and_block; + sigact.sa_flags = SA_RESTART; + sigact.sa_mask = ints_off; + sigaction(SIGUSR1, &sigact, 0); + + /* + * Change the name of the core file from core to core.pid, + * This is inherited by the sprocs created by this process + */ +#ifdef PR_COREPID + prctl(PR_COREPID, 0, 1); +#endif + /* + * Irix-specific terminate on error processing + */ + /* + * PR_SETABORTSIG is a new command implemented in a patch to + * Irix 6.2, 6.3 and 6.4. This causes a signal to be sent to all + * sprocs in the process when one of them terminates abnormally + * + */ + if (prctl(PR_SETABORTSIG, SIGKILL) < 0) { + /* + * if (errno == EINVAL) + * + * PR_SETABORTSIG not supported under this OS. + * You may want to get a recent kernel rollup patch that + * supports this feature. + * + */ + } + /* + * PR_SETEXITSIG - send the SIGCLD signal to the parent + * sproc when any sproc terminates + * + * This is used to cause the entire application to + * terminate when any sproc terminates abnormally by + * receipt of a SIGSEGV, SIGBUS or SIGABRT signal. + * If this is not done, the application may seem + * "hung" to the user because the other sprocs may be + * waiting for resources held by the + * abnormally-terminating sproc. + */ + prctl(PR_SETEXITSIG, 0); + + sigact.sa_handler = sigchld_handler; + sigact.sa_flags = SA_RESTART; + sigact.sa_mask = ints_off; + sigaction(SIGCLD, &sigact, NULL); + + /* + * setup stack fields for the primordial thread + */ + me->stack->stackSize = prctl(PR_GETSTACKSIZE); + me->stack->stackBottom = me->stack->stackTop - me->stack->stackSize; + + rv = pipe(_pr_irix_primoridal_cpu_fd); + PR_ASSERT(rv == 0); +#ifndef _PR_USE_POLL + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; + FD_SET(_pr_irix_primoridal_cpu_fd[0], &_PR_FD_READ_SET(me->cpu)); +#endif + + libc_handle = dlopen("libc.so",RTLD_NOW); + PR_ASSERT(libc_handle != NULL); + libc_exit = (void (*)(int)) dlsym(libc_handle, "exit"); + PR_ASSERT(libc_exit != NULL); + /* dlclose(libc_handle); */ + +#endif /* _PR_PTHREADS */ + + _PR_UnixInit(); +} + +/**************************************************************************/ +/************** code and such for NSPR 2.0's interval times ***************/ +/**************************************************************************/ + +#define PR_PSEC_PER_SEC 1000000000000ULL /* 10^12 */ + +#ifndef SGI_CYCLECNTR_SIZE +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ +#endif + +static PRIntn mmem_fd = -1; +static PRIntn clock_width = 0; +static void *iotimer_addr = NULL; +static PRUint32 pr_clock_mask = 0; +static PRUint32 pr_clock_shift = 0; +static PRIntervalTime pr_ticks = 0; +static PRUint32 pr_clock_granularity = 1; +static PRUint32 pr_previous = 0, pr_residual = 0; +static PRUint32 pr_ticks_per_second = 0; + +extern PRIntervalTime _PR_UNIX_GetInterval(void); +extern PRIntervalTime _PR_UNIX_TicksPerSecond(void); + +static void _MD_IrixIntervalInit(void) +{ + /* + * As much as I would like, the service available through this + * interface on R3000's (aka, IP12) just isn't going to make it. + * The register is only 24 bits wide, and rolls over at a verocious + * rate. + */ + PRUint32 one_tick = 0; + struct utsname utsinfo; + uname(&utsinfo); + if ((strncmp("IP12", utsinfo.machine, 4) != 0) + && ((mmem_fd = open("/dev/mmem", O_RDONLY)) != -1)) + { + int poffmask = getpagesize() - 1; + __psunsigned_t phys_addr, raddr, cycleval; + + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); + raddr = phys_addr & ~poffmask; + iotimer_addr = mmap( + 0, poffmask, PROT_READ, MAP_PRIVATE, mmem_fd, (__psint_t)raddr); + + clock_width = syssgi(SGI_CYCLECNTR_SIZE); + if (clock_width < 0) + { + /* + * We must be executing on a 6.0 or earlier system, since the + * SGI_CYCLECNTR_SIZE call is not supported. + * + * The only pre-6.1 platforms with 64-bit counters are + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). + */ + if (!strncmp(utsinfo.machine, "IP19", 4) || + !strncmp(utsinfo.machine, "IP21", 4)) + clock_width = 64; + else + clock_width = 32; + } + + /* + * 'cycleval' is picoseconds / increment of the counter. + * I'm pushing for a tick to be 100 microseconds, 10^(-4). + * That leaves 10^(-8) left over, or 10^8 / cycleval. + * Did I do that right? + */ + + one_tick = 100000000UL / cycleval ; /* 100 microseconds */ + + while (0 != one_tick) + { + pr_clock_shift += 1; + one_tick = one_tick >> 1; + pr_clock_granularity = pr_clock_granularity << 1; + } + pr_clock_mask = pr_clock_granularity - 1; /* to make a mask out of it */ + pr_ticks_per_second = PR_PSEC_PER_SEC + / ((PRUint64)pr_clock_granularity * (PRUint64)cycleval); + + iotimer_addr = (void*) + ((__psunsigned_t)iotimer_addr + (phys_addr & poffmask)); + } + else + { + pr_ticks_per_second = _PR_UNIX_TicksPerSecond(); + } +} /* _MD_IrixIntervalInit */ + +PRIntervalTime _MD_IrixIntervalPerSec(void) +{ + return pr_ticks_per_second; +} + +PRIntervalTime _MD_IrixGetInterval(void) +{ + if (mmem_fd != -1) + { + if (64 == clock_width) + { + PRUint64 temp = *(PRUint64*)iotimer_addr; + pr_ticks = (PRIntervalTime)(temp >> pr_clock_shift); + } + else + { + PRIntervalTime ticks = pr_ticks; + PRUint32 now = *(PRUint32*)iotimer_addr, temp; + PRUint32 residual = pr_residual, previous = pr_previous; + + temp = now - previous + residual; + residual = temp & pr_clock_mask; + ticks += temp >> pr_clock_shift; + + pr_previous = now; + pr_residual = residual; + pr_ticks = ticks; + } + } + else + { + /* + * No fast access. Use the time of day clock. This isn't the + * right answer since this clock can get set back, tick at odd + * rates, and it's expensive to acqurie. + */ + pr_ticks = _PR_UNIX_GetInterval(); + } + return pr_ticks; +} /* _MD_IrixGetInterval */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/linux.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/linux.c new file mode 100644 index 00000000..c22618d7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/linux.c @@ -0,0 +1,123 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifdef _PR_PTHREADS + +extern void _MD_unix_terminate_waitpid_daemon(void); + +void _MD_CleanupBeforeExit(void) +{ + _MD_unix_terminate_waitpid_daemon(); +} + +#else /* ! _PR_PTHREADS */ + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + /* + * set the pointers to the stack-pointer and frame-pointer words in the + * context structure; this is for debugging use. + */ + thread->md.sp = _MD_GET_SP_PTR(thread); + thread->md.fp = _MD_GET_FP_PTR(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Linux */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Linux."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Linux."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/ncr.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/ncr.c new file mode 100644 index 00000000..909b09e6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/ncr.c @@ -0,0 +1,395 @@ +/* -*- 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 ***** */ + +/* + * NCR 3.0 - cloned from UnixWare by ruslan + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + + +void +_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); + return PR_FAILURE; +} + +/* + This is temp. replacement for localtime_r. Normally PR_ExplodeTime should + be used as to my understanding +*/ + +/* +** $$$$$ THEN WHY ARE WE DOING THIS? - AOF $$$$$ +*/ + +#define NEED_LOCALTIME_R +#define NEED_GMTIME_R +#define NEED_ASCTIME_R +#define NEED_STRTOK_R +#define NEED_CTIME_R + +#if defined (NEED_LOCALTIME_R) || defined (NEED_CTIME_R) || defined (NEED_ASCTIME_R) || defined (NEED_GMTIME_R) || defined (NEED_STRTOK_R) +#include "prlock.h" +#endif + +#if defined (NEED_LOCALTIME_R) + +static PRLock *localtime_r_monitor = NULL; + +struct tm *localtime_r (const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (localtime_r_monitor == NULL) { + + localtime_r_monitor = PR_NewLock(); + } + PR_Lock(localtime_r_monitor); + } + + /* + * On Windows, localtime() returns a NULL pointer if 'clock' + * represents a time before midnight January 1, 1970. In + * that case, we also return a NULL pointer and the struct tm + * object pointed to by 'result' is not modified. + */ + + tmPtr = localtime(clock); + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } + + if (needLock) PR_Unlock(localtime_r_monitor); + + return result; +} + +#endif + +#if defined (NEED_GMTIME_R) + +static PRLock *gmtime_r_monitor = NULL; + +struct tm *gmtime_r (const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (gmtime_r_monitor == NULL) { + gmtime_r_monitor = PR_NewLock(); + } + PR_Lock(gmtime_r_monitor); + } + + tmPtr = gmtime(clock); + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } + + if (needLock) PR_Unlock(gmtime_r_monitor); + + return result; +} + +#endif + +#if defined (NEED_CTIME_R) + +static PRLock *ctime_r_monitor = NULL; + +char *ctime_r (const time_t *clock, char *buf, int buflen) +{ + char *cbuf; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + + if (ctime_r_monitor == NULL) { + ctime_r_monitor = PR_NewLock(); + } + PR_Lock(ctime_r_monitor); + } + + cbuf = ctime (clock); + if (cbuf) { + strncpy (buf, cbuf, buflen - 1); + buf[buflen - 1] = 0; + } + + if (needLock) PR_Unlock(ctime_r_monitor); + + return cbuf; +} + +#endif + +#if defined (NEED_ASCTIME_R) + +static PRLock *asctime_r_monitor = NULL; + + +char *asctime_r (const struct tm *tm, char *buf, int buflen) +{ + char *cbuf; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (asctime_r_monitor == NULL) { + asctime_r_monitor = PR_NewLock(); + } + PR_Lock(asctime_r_monitor); + } + + cbuf = asctime (tm); + if (cbuf) { + strncpy (buf, cbuf, buflen - 1); + buf[buflen - 1] = 0; + } + + if (needLock) PR_Unlock(asctime_r_monitor); + + return cbuf; + +} +#endif + +#if defined (NEED_STRTOK_R) + +char * +strtok_r (s, delim, last) + register char *s; + register const char *delim; + register char **last; +{ + register char *spanp; + register int c, sc; + char *tok; + + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + + else + s[-1] = 0; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nec.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nec.c new file mode 100644 index 00000000..8c97b757 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nec.c @@ -0,0 +1,100 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for NEC */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NEC."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for NEC."); + return PR_FAILURE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/netbsd.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/netbsd.c new file mode 100644 index 00000000..fdef8d7b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/netbsd.c @@ -0,0 +1,121 @@ +/* -*- 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 +#include +#include + +void _MD_EarlyInit(void) +{ + /* + * Ignore FPE because coercion of a NaN to an int causes SIGFPE + * to be raised. + */ + struct sigaction act; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + sigaction(SIGFPE, &act, 0); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) sigsetjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for NetBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NetBSD."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for NetBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nextstep.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nextstep.c new file mode 100644 index 00000000..3f87815a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nextstep.c @@ -0,0 +1,284 @@ +/* -*- 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" + +#import +#import +#import +#include +#include +#include +#include +#include + + + +/* These functions are hidden in NEXTSTEP, but beacuse they have syscall() +** entries I can wrap these into their corresponding missing function. +*/ +caddr_t +mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + return (caddr_t) syscall (SYS_mmap, addr, len, prot, flags, fildes, off); +} + +int +munmap(caddr_t addr, size_t len) +{ + return syscall (SYS_munmap, addr, len); +} + +int +mprotect(caddr_t addr, size_t len, int prot) +{ + return syscall (SYS_mprotect, addr, len, prot); +} + + +/* If found the brk() symbol in the sahred libraries but no syscall() entry ... +** I don't know whether it will work ... +int brk(void *endds) +{ + return syscall (); +} +*/ + +void *sbrk(int incr) +{ + return (void *) syscall (SYS_sbrk, incr); +} + +/* These are my mach based versions, untested and probably bad ... +*/ +caddr_t my_mmap(caddr_t addr, size_t len, int prot, int flags, + int fildes, off_t off) +{ + kern_return_t ret_val; + + /* First map ... + */ + ret_val = map_fd ( fildes, /* fd */ + (vm_offset_t) off, /* offset */ + (vm_offset_t*)&addr, /* address */ + TRUE, /* find_space */ + (vm_size_t) len); /* size */ + + if (ret_val != KERN_SUCCESS) { + mach_error("Error calling map_fd() in mmap", ret_val ); + return (caddr_t)0; + } + + /* ... then protect (this is probably bad) + */ + ret_val = vm_protect( task_self(), /* target_task */ + (vm_address_t)addr, /* address */ + (vm_size_t) len, /* size */ + FALSE, /* set_maximum */ + (vm_prot_t) prot); /* new_protection */ + if (ret_val != KERN_SUCCESS) { + mach_error("vm_protect in mmap()", ret_val ); + return (caddr_t)0; + } + + return addr; +} + +int my_munmap(caddr_t addr, size_t len) +{ + kern_return_t ret_val; + + ret_val = vm_deallocate(task_self(), + (vm_address_t) addr, + (vm_size_t) len); + + if (ret_val != KERN_SUCCESS) { + mach_error("vm_deallocate in munmap()", ret_val); + return -1; + } + + return 0; +} + +int my_mprotect(caddr_t addr, size_t len, int prot) +{ + vm_prot_t mach_prot; + kern_return_t ret_val; + + switch (prot) { + case PROT_READ: mach_prot = VM_PROT_READ; break; + case PROT_WRITE: mach_prot = VM_PROT_WRITE; break; + case PROT_EXEC: mach_prot = VM_PROT_EXECUTE; break; + case PROT_NONE: mach_prot = VM_PROT_NONE; break; + } + + ret_val = vm_protect(task_self(), /* target_task */ + (vm_address_t)addr, /* address */ + (vm_size_t) len, /* size */ + FALSE, /* set_maximum */ + (vm_prot_t) prot); /* new_protection */ + + if (ret_val != KERN_SUCCESS) { + mach_error("vm_protect in mprotect()", ret_val); + return -1; + } + + return 0; +} + +char *strdup(const char *s1) +{ + int len = strlen (s1); + char *copy = (char*) malloc (len+1); + + if (copy == (char*)0) + return (char*)0; + + strcpy (copy, s1); + + return copy; +} + +/* Stub rld functions +*/ +extern NSObjectFileImageReturnCode NSCreateObjectFileImageFromFile( + const char *pathName, + NSObjectFileImage *objectFileImage) +{ + return NSObjectFileImageFailure; +} + +extern void * NSAddressOfSymbol( + NSSymbol symbol) +{ + return NULL; +} + +extern NSModule NSLinkModule( + NSObjectFileImage objectFileImage, + const char *moduleName, /* can be NULL */ + enum bool bindNow) +{ + return NULL; +} + +extern NSSymbol NSLookupAndBindSymbol( + const char *symbolName) +{ + return NULL; +} + +extern enum bool NSUnLinkModule( + NSModule module, + enum bool keepMemoryMapped) +{ + return 0; +} + + + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) sigsetjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for NEXTSTEP */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for NEXTSTEP."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for NEXTSTEP."); + return PR_FAILURE; +} + +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nto.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nto.c new file mode 100644 index 00000000..352d93e9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/nto.c @@ -0,0 +1,66 @@ +/* -*- 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 ***** */ + +#include "primpl.h" + +#include + +/* Fake this out */ +int socketpair (int foo, int foo2, int foo3, int sv[2]) +{ + printf("error in socketpair\n"); + exit (-1); +} + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/objs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/objs.mk new file mode 100644 index 00000000..13f2d7d2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/objs.mk @@ -0,0 +1,63 @@ +# +# ***** 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 makefile appends to the variable OBJS the platform-dependent +# object modules that will be part of the nspr20 library. + +CSRCS = \ + unix.c \ + unix_errors.c \ + uxproces.c \ + uxrng.c \ + uxshm.c \ + uxwrap.c \ + $(NULL) + +ifneq ($(USE_PTHREADS),1) +CSRCS += uxpoll.c +endif + +ifeq ($(PTHREADS_USER),1) +CSRCS += pthreads_user.c +endif + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +OBJS += $(addprefix md/unix/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/unix/$(OBJDIR)/,$(ASFILES:.s=.$(OBJ_SUFFIX))) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openbsd.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openbsd.c new file mode 100644 index 00000000..1103377f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openbsd.c @@ -0,0 +1,121 @@ +/* -*- 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 +#include +#include + +void _MD_EarlyInit(void) +{ + /* + * Ignore FPE because coercion of a NaN to an int causes SIGFPE + * to be raised. + */ + struct sigaction act; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + sigaction(SIGFPE, &act, 0); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) sigsetjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for OpenBSD */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OpenBSD."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for OpenBSD."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openvms.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openvms.c new file mode 100644 index 00000000..20b4f708 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/openvms.c @@ -0,0 +1,286 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for OSF1 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OSF1."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for OSF1."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ + +#ifdef _PR_HAVE_ATOMIC_CAS + +#include + +#define _PR_OSF_ATOMIC_LOCK 1 + +void +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +long locked; + + do { + while ((long) stack->prstk_head.prstk_elem_next == + _PR_OSF_ATOMIC_LOCK) + ; + locked = __ATOMIC_EXCH_QUAD(&stack->prstk_head.prstk_elem_next, + _PR_OSF_ATOMIC_LOCK); + + } while (locked == _PR_OSF_ATOMIC_LOCK); + stack_elem->prstk_elem_next = (PRStackElem *) locked; + /* + * memory-barrier instruction + */ + asm("mb"); + stack->prstk_head.prstk_elem_next = stack_elem; +} + +PRStackElem * +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; +long locked; + + do { + while ((long)stack->prstk_head.prstk_elem_next == _PR_OSF_ATOMIC_LOCK) + ; + locked = __ATOMIC_EXCH_QUAD(&stack->prstk_head.prstk_elem_next, + _PR_OSF_ATOMIC_LOCK); + + } while (locked == _PR_OSF_ATOMIC_LOCK); + + element = (PRStackElem *) locked; + + if (element == NULL) { + stack->prstk_head.prstk_elem_next = NULL; + } else { + stack->prstk_head.prstk_elem_next = + element->prstk_elem_next; + } + /* + * memory-barrier instruction + */ + asm("mb"); + return element; +} +#endif /* _PR_HAVE_ATOMIC_CAS */ + + +/* +** thread_suspend and thread_resume are used by the gc code +** in nsprpub/pr/src/pthreads/ptthread.c +** +** These routines are never called for the current thread, and +** there is no check for that - so beware! +*/ +int thread_suspend(PRThread *thr_id) { + + extern int pthread_suspend_np ( + pthread_t thread, + __pthreadLongUint_t *regs, + void *spare); + + __pthreadLongUint_t regs[34]; + int res; + + /* + ** A return res < 0 indicates that the thread was suspended + ** but register information could not be obtained + */ + + res = pthread_suspend_np(thr_id->id,®s[0],0); + if (res==0) + thr_id->sp = (void *) regs[30]; + + thr_id->suspend |= PT_THREAD_SUSPENDED; + + /* Always succeeds */ + return 0; +} + +int thread_resume(PRThread *thr_id) { + extern int pthread_resume_np(pthread_t thread); + int res; + + res = pthread_resume_np (thr_id->id); + + thr_id->suspend |= PT_THREAD_RESUMED; + + return 0; +} + +/* +** Stubs for nspr_symvec.opt +** +** PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended +** (defined in ptthread.c) used to be exported by mistake +** (because they look like public functions). They have been +** converted into static functions. +** +** There is an existing third-party binary that uses NSPR: the +** Java plugin for Mozilla. Because it is part of the Java +** SDK, we have no control over its releases. So we need these +** stub functions to occupy the slots that used to be occupied +** by PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended +** in the symbol vector so that LIBNSPR4 is backward compatible. +** +** The Java plugin was also using PR_CreateThread which we didn't +** realise and hadn't "nailed down". So we now need to nail it down +** to its Mozilla 1.1 position and have to insert 51 additional stubs +** in order to achive this (stubs 4-54). +** +** Over time some of these stubs will get reused by new symbols. +** - Stub54 is replaced by LL_MaxUint +*/ + +void PR_VMS_Stub1(void) { } +void PR_VMS_Stub2(void) { } +void PR_VMS_Stub3(void) { } +void PR_VMS_Stub4(void) { } +void PR_VMS_Stub5(void) { } +void PR_VMS_Stub6(void) { } +void PR_VMS_Stub7(void) { } +void PR_VMS_Stub8(void) { } +void PR_VMS_Stub9(void) { } +void PR_VMS_Stub10(void) { } +void PR_VMS_Stub11(void) { } +void PR_VMS_Stub12(void) { } +void PR_VMS_Stub13(void) { } +void PR_VMS_Stub14(void) { } +void PR_VMS_Stub15(void) { } +void PR_VMS_Stub16(void) { } +void PR_VMS_Stub17(void) { } +void PR_VMS_Stub18(void) { } +void PR_VMS_Stub19(void) { } +void PR_VMS_Stub20(void) { } +void PR_VMS_Stub21(void) { } +void PR_VMS_Stub22(void) { } +void PR_VMS_Stub23(void) { } +void PR_VMS_Stub24(void) { } +void PR_VMS_Stub25(void) { } +void PR_VMS_Stub26(void) { } +void PR_VMS_Stub27(void) { } +void PR_VMS_Stub28(void) { } +void PR_VMS_Stub29(void) { } +void PR_VMS_Stub30(void) { } +void PR_VMS_Stub31(void) { } +void PR_VMS_Stub32(void) { } +void PR_VMS_Stub33(void) { } +void PR_VMS_Stub34(void) { } +void PR_VMS_Stub35(void) { } +void PR_VMS_Stub36(void) { } +void PR_VMS_Stub37(void) { } +void PR_VMS_Stub38(void) { } +void PR_VMS_Stub39(void) { } +void PR_VMS_Stub40(void) { } +void PR_VMS_Stub41(void) { } +void PR_VMS_Stub42(void) { } +void PR_VMS_Stub43(void) { } +void PR_VMS_Stub44(void) { } +void PR_VMS_Stub45(void) { } +void PR_VMS_Stub46(void) { } +void PR_VMS_Stub47(void) { } +void PR_VMS_Stub48(void) { } +void PR_VMS_Stub49(void) { } +void PR_VMS_Stub50(void) { } +void PR_VMS_Stub51(void) { } +void PR_VMS_Stub52(void) { } +void PR_VMS_Stub53(void) { } diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_AIX.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_AIX.s new file mode 100644 index 00000000..8911a75e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_AIX.s @@ -0,0 +1,119 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# 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 Netscape are +# Copyright (C) 1998-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +.set r0,0; .set SP,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.longjmp{TC},"longjmp" + + .lglobl H.10.NO_SYMBOL{PR} + .globl .longjmp + .globl longjmp{DS} + .extern .sigcleanup + .extern .jmprestfpr + +# .text section + + .csect H.10.NO_SYMBOL{PR} +.longjmp: + mr r13,r3 + mr r14,r4 + stu SP,-56(SP) + bl .sigcleanup + l RTOC,0x14(SP) + cal SP,0x38(SP) + mr r3,r13 + mr r4,r14 + l r5,0x8(r3) + l SP,0xc(r3) + l r7,0xf8(r3) + st r7,0x0(SP) + l RTOC,0x10(r3) + bl .jmprestfpr +# 1 == cr0 in disassembly + cmpi 1,r4,0x0 + mtlr r5 + lm r13,0x14(r3) + l r5,0x60(r3) + mtcrf 0x38,r5 + mr r3,r4 + bne __L1 + lil r3,0x1 +__L1: + br + +# traceback table + .long 0x00000000 + .byte 0x00 # VERSION=0 + .byte 0x00 # LANG=TB_C + .byte 0x20 # IS_GL=0,IS_EPROL=0,HAS_TBOFF=1 + # INT_PROC=0,HAS_CTL=0,TOCLESS=0 + # FP_PRESENT=0,LOG_ABORT=0 + .byte 0x40 # INT_HNDL=0,NAME_PRESENT=1 + # USES_ALLOCA=0,CL_DIS_INV=WALK_ONCOND + # SAVES_CR=0,SAVES_LR=0 + .byte 0x80 # STORES_BC=1,FPR_SAVED=0 + .byte 0x00 # GPR_SAVED=0 + .byte 0x02 # FIXEDPARMS=2 + .byte 0x01 # FLOATPARMS=0,PARMSONSTK=1 + .long 0x00000000 # + .long 0x00000014 # TB_OFFSET + .short 7 # NAME_LEN + .byte "longjmp" + .byte 0 # padding + .byte 0 # padding + .byte 0 # padding +# End of traceback table + .long 0x00000000 # "\0\0\0\0" + +# .data section + + .toc # 0x00000038 +T.18.longjmp: + .tc H.18.longjmp{TC},longjmp{DS} + + .csect longjmp{DS} + .long .longjmp # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect longjmp{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_BSD_386_2.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_BSD_386_2.s new file mode 100644 index 00000000..aadf0df2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_BSD_386_2.s @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* +* 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 Netscape are +* Copyright (C) 1998-2000 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU General Public License Version 2 or later (the +* "GPL"), in which case the provisions of the GPL are applicable +* instead of those above. If you wish to allow use of your +* version of this file only under the terms of the GPL and not to +* allow others to use your version of this file under the MPL, +* indicate your decision by deleting the provisions above and +* replace them with the notice and other provisions required by +* the GPL. If you do not delete the provisions above, a recipient +* may use your version of this file under either the MPL or the +* GPL. +*/ + +/* + * os_BSD_386_2.s + * We need to define our own setjmp/longjmp on BSDI 2.x because libc's + * implementation does some sanity checking that defeats user level threads. + * This should no longer be necessary in BSDI 3.0. + */ + +.globl _setjmp +.align 2 +_setjmp: + movl 4(%esp),%eax + movl 0(%esp),%edx + movl %edx, 0(%eax) /* rta */ + movl %ebx, 4(%eax) + movl %esp, 8(%eax) + movl %ebp,12(%eax) + movl %esi,16(%eax) + movl %edi,20(%eax) + movl $0,%eax + ret + +.globl _longjmp +.align 2 +_longjmp: + movl 4(%esp),%edx + movl 8(%esp),%eax + movl 0(%edx),%ecx + movl 4(%edx),%ebx + movl 8(%edx),%esp + movl 12(%edx),%ebp + movl 16(%edx),%esi + movl 20(%edx),%edi + cmpl $0,%eax + jne 1f + movl $1,%eax +1: movl %ecx,0(%esp) + ret diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_ppc.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_ppc.s new file mode 100644 index 00000000..f38ac644 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_ppc.s @@ -0,0 +1,92 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# +# 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 Netscape are +# Copyright (C) 2003 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +# +# Based on the programming examples in The PowerPC Architecture: +# A Specification for A New Family of RISC Processors, 2nd Ed., +# Book I, Section E.1, "Synchronization," pp. 249-256, May 1994. +# + +.text + +# +# PRInt32 __PR_DarwinPPC_AtomicIncrement(PRInt32 *val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicIncrement +__PR_DarwinPPC_AtomicIncrement: + lwarx r4,0,r3 + addi r0,r4,1 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicIncrement + mr r3,r0 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicDecrement(PRInt32 *val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicDecrement +__PR_DarwinPPC_AtomicDecrement: + lwarx r4,0,r3 + addi r0,r4,-1 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicDecrement + mr r3,r0 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicSet(PRInt32 *val, PRInt32 newval); +# + .align 2 + .globl __PR_DarwinPPC_AtomicSet +__PR_DarwinPPC_AtomicSet: + lwarx r5,0,r3 + stwcx. r4,0,r3 + bne- __PR_DarwinPPC_AtomicSet + mr r3,r5 + blr + +# +# PRInt32 __PR_DarwinPPC_AtomicAdd(PRInt32 *ptr, PRInt32 val); +# + .align 2 + .globl __PR_DarwinPPC_AtomicAdd +__PR_DarwinPPC_AtomicAdd: + lwarx r5,0,r3 + add r0,r4,r5 + stwcx. r0,0,r3 + bne- __PR_DarwinPPC_AtomicAdd + mr r3,r0 + blr diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_x86.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_x86.s new file mode 100644 index 00000000..276b16e0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Darwin_x86.s @@ -0,0 +1,109 @@ +# -*- 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) 2003 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Josh Aas +# +# 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 ***** + +# +# Based on os_Linux_x86.s +# + +# +# PRInt32 __PR_Darwin_x86_AtomicIncrement(PRInt32 *val); +# +# Atomically increment the integer pointed to by 'val' and return +# the result of the increment. +# + .text + .globl __PR_Darwin_x86_AtomicIncrement + .align 4 +__PR_Darwin_x86_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicDecrement(PRInt32 *val); +# +# Atomically decrement the integer pointed to by 'val' and return +# the result of the decrement. +# + .text + .globl __PR_Darwin_x86_AtomicDecrement + .align 4 +__PR_Darwin_x86_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicSet(PRInt32 *val, PRInt32 newval); +# +# Atomically set the integer pointed to by 'val' to the new +# value 'newval' and return the old value. +# + .text + .globl __PR_Darwin_x86_AtomicSet + .align 4 +__PR_Darwin_x86_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + xchgl %eax, (%ecx) + ret + +# +# PRInt32 __PR_Darwin_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val); +# +# Atomically add 'val' to the integer pointed to by 'ptr' +# and return the result of the addition. +# + .text + .globl __PR_Darwin_x86_AtomicAdd + .align 4 +__PR_Darwin_x86_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_HPUX.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_HPUX.s new file mode 100644 index 00000000..375cb256 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_HPUX.s @@ -0,0 +1,54 @@ +; +; 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 Netscape are +; Copyright (C) 1998-2000 Netscape Communications Corporation. All +; Rights Reserved. +; +; Contributor(s): +; +; Alternatively, the contents of this file may be used under the +; terms of the GNU General Public License Version 2 or later (the +; "GPL"), in which case the provisions of the GPL are applicable +; instead of those above. If you wish to allow use of your +; version of this file only under the terms of the GPL and not to +; allow others to use your version of this file under the MPL, +; indicate your decision by deleting the provisions above and +; replace them with the notice and other provisions required by +; the GPL. If you do not delete the provisions above, a recipient +; may use your version of this file under either the MPL or the +; GPL. +; + +#ifdef __LP64__ + .LEVEL 2.0W +#else + .LEVEL 1.1 +#endif + + .CODE ; equivalent to the following two lines +; .SPACE $TEXT$,SORT=8 +; .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 + +ret_cr16 + .PROC + .CALLINFO FRAME=0, NO_CALLS + .EXPORT ret_cr16,ENTRY + .ENTER +; BV %r0(%rp) + BV 0(%rp) + MFCTL %cr16,%ret0 + .LEAVE + .PROCEND + .END diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Irix.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Irix.s new file mode 100644 index 00000000..7a4b186f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Irix.s @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* +* 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 Netscape are +* Copyright (C) 1998-2000 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU General Public License Version 2 or later (the +* "GPL"), in which case the provisions of the GPL are applicable +* instead of those above. If you wish to allow use of your +* version of this file only under the terms of the GPL and not to +* allow others to use your version of this file under the MPL, +* indicate your decision by deleting the provisions above and +* replace them with the notice and other provisions required by +* the GPL. If you do not delete the provisions above, a recipient +* may use your version of this file under either the MPL or the +* GPL. +*/ + +/* + * Atomically add a new element to the top of the stack + * + * usage : PR_StackPush(listp, elementp); + * ----------------------- + */ + +#include "md/_irix.h" +#ifdef _PR_HAVE_ATOMIC_CAS + +#include +#include + +LEAF(PR_StackPush) + +retry_push: +.set noreorder + lw v0,0(a0) + li t1,1 + beq v0,t1,retry_push + move t0,a1 + + ll v0,0(a0) + beq v0,t1,retry_push + nop + sc t1,0(a0) + beq t1,0,retry_push + nop + sw v0,0(a1) + sync + sw t0,0(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + jr ra + nop + +END(PR_StackPush) + +/* + * + * Atomically remove the element at the top of the stack + * + * usage : elemep = PR_StackPop(listp); + * + */ + +LEAF(PR_StackPop) +retry_pop: +.set noreorder + + + lw v0,0(a0) + li t1,1 + beq v0,0,done + nop + beq v0,t1,retry_pop + nop + + ll v0,0(a0) + beq v0,0,done + nop + beq v0,t1,retry_pop + nop + sc t1,0(a0) + beq t1,0,retry_pop + nop + lw t0,0(v0) + sw t0,0(a0) +done: + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + jr ra + nop + +END(PR_StackPop) + +#endif /* _PR_HAVE_ATOMIC_CAS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_ia64.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_ia64.s new file mode 100644 index 00000000..bf5b03fc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_ia64.s @@ -0,0 +1,80 @@ +// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// +// 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 Netscape are +// Copyright (C) 2000 Netscape Communications Corporation. All +// Rights Reserved. +// +// Contributor(s): +// +// Alternatively, the contents of this file may be used under the +// terms of the GNU General Public License Version 2 or later (the +// "GPL"), in which case the provisions of the GPL are applicable +// instead of those above. If you wish to allow use of your +// version of this file only under the terms of the GPL and not to +// allow others to use your version of this file under the MPL, +// indicate your decision by deleting the provisions above and +// replace them with the notice and other provisions required by +// the GPL. If you do not delete the provisions above, a recipient +// may use your version of this file under either the MPL or the +// GPL. +// + +.text + .align 16 + .global _PR_ia64_AtomicIncrement# + .proc _PR_ia64_AtomicIncrement# +_PR_ia64_AtomicIncrement: + fetchadd4.acq r8 = [r32], 1 + ;; + adds r8 = 1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicIncrement# +// + .align 16 + .global _PR_ia64_AtomicDecrement# + .proc _PR_ia64_AtomicDecrement# +_PR_ia64_AtomicDecrement: + fetchadd4.rel r8 = [r32], -1 + ;; + adds r8 = -1, r8 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicDecrement# +// + .align 16 + .global _PR_ia64_AtomicAdd# + .proc _PR_ia64_AtomicAdd# +_PR_ia64_AtomicAdd: + ld4 r15 = [r32] + ;; +.L3: + mov r14 = r15 + mov ar.ccv = r15 + add r8 = r15, r33 + ;; + cmpxchg4.acq r15 = [r32], r8, ar.ccv + ;; + cmp4.ne p6, p7 = r15, r14 + (p6) br.cond.dptk .L3 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicAdd# +// + .align 16 + .global _PR_ia64_AtomicSet# + .proc _PR_ia64_AtomicSet# +_PR_ia64_AtomicSet: + xchg4 r8 = [r32], r33 + br.ret.sptk.many b0 + .endp _PR_ia64_AtomicSet# diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86.s new file mode 100644 index 00000000..d691badd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86.s @@ -0,0 +1,114 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ 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 Netscape are +/ Copyright (C) 2000 Netscape Communications Corporation. All +/ Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the +/ terms of the GNU General Public License Version 2 or later (the +/ "GPL"), in which case the provisions of the GPL are applicable +/ instead of those above. If you wish to allow use of your +/ version of this file only under the terms of the GPL and not to +/ allow others to use your version of this file under the MPL, +/ indicate your decision by deleting the provisions above and +/ replace them with the notice and other provisions required by +/ the GPL. If you do not delete the provisions above, a recipient +/ may use your version of this file under either the MPL or the +/ GPL. +/ + +/ PRInt32 _PR_x86_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _PR_x86_AtomicIncrement + .align 4 +_PR_x86_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 _PR_x86_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _PR_x86_AtomicDecrement + .align 4 +_PR_x86_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 _PR_x86_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl _PR_x86_AtomicSet +/ .align 4 +/_PR_x86_AtomicSet: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl _PR_x86_AtomicSet + .align 4 +_PR_x86_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + lock + xchgl %eax, (%ecx) + ret + +/ PRInt32 _PR_x86_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _PR_x86_AtomicAdd + .align 4 +_PR_x86_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret + +/ Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86_64.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86_64.s new file mode 100644 index 00000000..567ae12d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_Linux_x86_64.s @@ -0,0 +1,95 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ 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 Netscape are +/ Copyright (C) 2004 Netscape Communications Corporation. All +/ Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the +/ terms of the GNU General Public License Version 2 or later (the +/ "GPL"), in which case the provisions of the GPL are applicable +/ instead of those above. If you wish to allow use of your +/ version of this file only under the terms of the GPL and not to +/ allow others to use your version of this file under the MPL, +/ indicate your decision by deleting the provisions above and +/ replace them with the notice and other provisions required by +/ the GPL. If you do not delete the provisions above, a recipient +/ may use your version of this file under either the MPL or the +/ GPL. +/ + +/ PRInt32 _PR_x86_64_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _PR_x86_64_AtomicIncrement + .align 4 +_PR_x86_64_AtomicIncrement: + movl $1, %eax + lock + xaddl %eax, (%rdi) + incl %eax + ret + +/ PRInt32 _PR_x86_64_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _PR_x86_64_AtomicDecrement + .align 4 +_PR_x86_64_AtomicDecrement: + movl $-1, %eax + lock + xaddl %eax, (%rdi) + decl %eax + ret + +/ PRInt32 _PR_x86_64_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ + .text + .globl _PR_x86_64_AtomicSet + .align 4 +_PR_x86_64_AtomicSet: + movl %esi, %eax + lock + xchgl %eax, (%rdi) + ret + +/ PRInt32 _PR_x86_64_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _PR_x86_64_AtomicAdd + .align 4 +_PR_x86_64_AtomicAdd: + movl %esi, %eax + lock + xaddl %eax, (%rdi) + addl %esi, %eax + ret + +/ Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_ReliantUNIX.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_ReliantUNIX.s new file mode 100644 index 00000000..769160bf --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_ReliantUNIX.s @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* +* 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 Netscape are +* Copyright (C) 1998-2000 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU General Public License Version 2 or later (the +* "GPL"), in which case the provisions of the GPL are applicable +* instead of those above. If you wish to allow use of your +* version of this file only under the terms of the GPL and not to +* allow others to use your version of this file under the MPL, +* indicate your decision by deleting the provisions above and +* replace them with the notice and other provisions required by +* the GPL. If you do not delete the provisions above, a recipient +* may use your version of this file under either the MPL or the +* GPL. +*/ + +/* We want position independent code */ +#define PIC + +#include +#include +#include + + .file 1 "os_ReliantUNIX.s" + .option pic2 + .text + + .align 2 + .globl getcxt + .ent getcxt +getcxt: + .frame sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0 + # saved integer regs + sw ra,180(a0) # gpregs[CXT_EPC] + sw gp,152(a0) # gpregs[CXT_GP] + sw sp,156(a0) # gpregs[CXT_SP] + sw s8,160(a0) # gpregs[CXT_S8] + sw s0,104(a0) # gpregs[CXT_S0] + sw s1,108(a0) # gpregs[CXT_S1] + sw s2,112(a0) # gpregs[CXT_S2] + sw s3,116(a0) # gpregs[CXT_S3] + sw s4,120(a0) # gpregs[CXT_S4] + sw s5,124(a0) # gpregs[CXT_S5] + sw s6,128(a0) # gpregs[CXT_S6] + sw s7,132(a0) # gpregs[CXT_S7] + # csr + cfc1 v0,$31 + # saved float regs + s.d $f20,264(a0) # fpregs.fp_r.fp_dregs[10] + s.d $f22,272(a0) # fpregs.fp_r.fp_dregs[11] + s.d $f24,280(a0) # fpregs.fp_r.fp_dregs[12] + s.d $f26,288(a0) # fpregs.fp_r.fp_dregs[13] + s.d $f28,296(a0) # fpregs.fp_r.fp_dregs[14] + s.d $f30,304(a0) # fpregs.fp_r.fp_dregs[15] + sw v0,312(a0) # fpregs.fp_csr + + # give no illusions about the contents + li v0,0x0c # UC_CPU | UC_MAU + sw v0,0(a0) # uc_flags + + move v0,zero + j ra + .end getcxt + + .align 2 + .globl setcxt + .ent setcxt +setcxt: + .frame sp,0,$31 # vars= 0, regs= 0/0, args= 0, extra= 0 + lw v0,312(a0) # fpregs.fp_csr + li v1,0xfffc0fff # mask out exception cause bits + and v0,v0,v1 + # saved integer regs + lw t9,180(a0) # gpregs[CXT_EPC] + lw ra,180(a0) # gpregs[CXT_EPC] + lw gp,152(a0) # gpregs[CXT_GP] + lw sp,156(a0) # gpregs[CXT_SP] + ctc1 v0,$31 # fp_csr + lw s8,160(a0) # gpregs[CXT_S8] + lw s0,104(a0) # gpregs[CXT_S0] + lw s1,108(a0) # gpregs[CXT_S1] + lw s2,112(a0) # gpregs[CXT_S2] + lw s3,116(a0) # gpregs[CXT_S3] + lw s4,120(a0) # gpregs[CXT_S4] + lw s5,124(a0) # gpregs[CXT_S5] + lw s6,128(a0) # gpregs[CXT_S6] + lw s7,132(a0) # gpregs[CXT_S7] + # saved float regs + l.d $f20,264(a0) # fpregs.fp_r.fp_dregs[10] + l.d $f22,272(a0) # fpregs.fp_r.fp_dregs[11] + l.d $f24,280(a0) # fpregs.fp_r.fp_dregs[12] + l.d $f26,288(a0) # fpregs.fp_r.fp_dregs[13] + l.d $f28,296(a0) # fpregs.fp_r.fp_dregs[14] + l.d $f30,304(a0) # fpregs.fp_r.fp_dregs[15] + + # load these, too + # they were not saved, but maybe the user modified them... + lw v0,48(a0) + lw v1,52(a0) + lw a1,60(a0) + lw a2,64(a0) + lw a3,68(a0) + lw a0,56(a0) # there is no way back + + j ra + + .end setcxt diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS.s new file mode 100644 index 00000000..49306862 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS.s @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* +* 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 Netscape are +* Copyright (C) 1998-2000 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU General Public License Version 2 or later (the +* "GPL"), in which case the provisions of the GPL are applicable +* instead of those above. If you wish to allow use of your +* version of this file only under the terms of the GPL and not to +* allow others to use your version of this file under the MPL, +* indicate your decision by deleting the provisions above and +* replace them with the notice and other provisions required by +* the GPL. If you do not delete the provisions above, a recipient +* may use your version of this file under either the MPL or the +* GPL. +*/ + + .text + +/* + * sol_getsp() + * + * Return the current sp (for debugging) + */ + .global sol_getsp +sol_getsp: + retl + mov %sp, %o0 + + +/* + * sol_curthread() + * + * Return a unique identifier for the currently active thread. + */ + .global sol_curthread +sol_curthread: + retl + mov %g7, %o0 + + + .global __MD_FlushRegisterWindows + .global _MD_FlushRegisterWindows + +__MD_FlushRegisterWindows: +_MD_FlushRegisterWindows: + + ta 3 + ret + restore + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_32.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_32.s new file mode 100644 index 00000000..dd8bdd4b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_32.s @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* +* 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 Netscape are +* Copyright (C) 1998-2000 Netscape Communications Corporation. All +* Rights Reserved. +* +* Contributor(s): +* +* Alternatively, the contents of this file may be used under the +* terms of the GNU General Public License Version 2 or later (the +* "GPL"), in which case the provisions of the GPL are applicable +* instead of those above. If you wish to allow use of your +* version of this file only under the terms of the GPL and not to +* allow others to use your version of this file under the MPL, +* indicate your decision by deleting the provisions above and +* replace them with the notice and other provisions required by +* the GPL. If you do not delete the provisions above, a recipient +* may use your version of this file under either the MPL or the +* GPL. +*/ + +! ====================================================================== +! +! Atomically add a new element to the top of the stack +! +! usage : PR_StackPush(listp, elementp); +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created. +! +! So, the registers used are: +! %o0 [input] - the address of the stack +! %o1 [input] - the address of the element to be added to the stack +! ----------------------- + + .section ".text" + .global PR_StackPush + +PR_StackPush: + +pulock: ld [%o0],%o3 ! + cmp %o3,-1 ! check if stack is locked + be pulock ! loop, if locked + mov -1,%o3 ! use delay-slot + swap [%o0],%o3 ! atomically lock the stack and get + ! the pointer to stack head + cmp %o3,-1 ! check, if the stack is locked + be pulock ! loop, if so + nop + st %o3,[%o1] + retl ! return back to the caller + st %o1,[%o0] ! + + .size PR_StackPush,(.-PR_StackPush) + + +! end +! ====================================================================== + +! ====================================================================== +! +! Atomically remove the element at the top of the stack +! +! usage : elemep = PR_StackPop(listp); +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created. +! +! So, the registers used are: +! %o0 [input] - the address of the stack +! %o1 [input] - work register (top element) +! ----------------------- + + .section ".text" + .global PR_StackPop + +PR_StackPop: + +polock: ld [%o0],%o1 ! + cmp %o1,-1 ! check if stack is locked + be polock ! loop, if locked + mov -1,%o1 ! use delay-slot + swap [%o0],%o1 ! atomically lock the stack and get + ! the pointer to stack head + cmp %o1,-1 ! check, if the stack is locked + be polock ! loop, if so + nop + tst %o1 ! test for empty stack + be,a empty ! is empty + st %g0,[%o0] + ld [%o1], %o2 ! load the second element + st %o2,[%o0] ! set stack head to second + st %g0,[%o1] ! reset the next pointer; for + ! debugging +empty: + retl ! return back to the caller + mov %o1, %o0 ! return the first element + + .size PR_StackPop,(.-PR_StackPop) + +! end +! ====================================================================== diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s new file mode 100644 index 00000000..a4bb3b79 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_sparcv9.s @@ -0,0 +1,201 @@ +! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +! +! 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 Netscape are +! Copyright (C) 1998-2000 Netscape Communications Corporation. All +! Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the +! terms of the GNU General Public License Version 2 or later (the +! "GPL"), in which case the provisions of the GPL are applicable +! instead of those above. If you wish to allow use of your +! version of this file only under the terms of the GPL and not to +! allow others to use your version of this file under the MPL, +! indicate your decision by deleting the provisions above and +! replace them with the notice and other provisions required by +! the GPL. If you do not delete the provisions above, a recipient +! may use your version of this file under either the MPL or the +! GPL. +! + +! +! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) +! using CAS (compare-and-swap) atomic instructions +! +! this MUST be compiled with an ultrasparc-aware assembler +! +! standard asm linkage macros; this module must be compiled +! with the -P option (use C preprocessor) + +#include + +! ====================================================================== +! +! Perform the sequence a = a + 1 atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : val = PR_AtomicIncrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicIncrement) ! standard assembler/ELF prologue + +retryAI: + ld [%o0], %o2 ! set o2 to the current value + add %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAI ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(_MD_AtomicIncrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a - 1 atomically with respect to other +! fetch-and-decs to location a in a wait-free fashion. +! +! usage : val = PR_AtomicDecrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicDecrement) ! standard assembler/ELF prologue + +retryAD: + ld [%o0], %o2 ! set o2 to the current value + sub %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAD ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(_MD_AtomicDecrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = b atomically with respect to other +! fetch-and-stores to location a in a wait-free fashion. +! +! usage : old_val = PR_AtomicSet(address, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the new value to set for [%o0] +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(_MD_AtomicSet) ! standard assembler/ELF prologue + +retryAS: + ld [%o0], %o2 ! set o2 to the current value + mov %o1, %o3 ! set up the new value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAS ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o3, %o0 ! set the return code to the prev value + + SET_SIZE(_MD_AtomicSet) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a + b atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : newval = PR_AtomicAdd(address, val) +! return: the value after addition +! + ENTRY(_MD_AtomicAdd) ! standard assembler/ELF prologue + +retryAA: + ld [%o0], %o2 ! set o2 to the current value + add %o2, %o1, %o3 ! calc the new value + mov %o3, %o4 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAA ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o4, %o0 ! set the return code to the new value + + SET_SIZE(_MD_AtomicAdd) ! standard assembler/ELF epilogue + +! +! end +! diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s new file mode 100644 index 00000000..03776f5b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_ultrasparc.s @@ -0,0 +1,201 @@ +! -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +! +! 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 Netscape are +! Copyright (C) 1998-2000 Netscape Communications Corporation. All +! Rights Reserved. +! +! Contributor(s): +! +! Alternatively, the contents of this file may be used under the +! terms of the GNU General Public License Version 2 or later (the +! "GPL"), in which case the provisions of the GPL are applicable +! instead of those above. If you wish to allow use of your +! version of this file only under the terms of the GPL and not to +! allow others to use your version of this file under the MPL, +! indicate your decision by deleting the provisions above and +! replace them with the notice and other provisions required by +! the GPL. If you do not delete the provisions above, a recipient +! may use your version of this file under either the MPL or the +! GPL. +! + +! +! atomic increment, decrement and swap routines for V8+ sparc (ultrasparc) +! using CAS (compare-and-swap) atomic instructions +! +! this MUST be compiled with an ultrasparc-aware assembler +! +! standard asm linkage macros; this module must be compiled +! with the -P option (use C preprocessor) + +#include + +! ====================================================================== +! +! Perform the sequence a = a + 1 atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : val = PR_AtomicIncrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicIncrement) ! standard assembler/ELF prologue + +retryAI: + ld [%o0], %o2 ! set o2 to the current value + add %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAI ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicIncrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a - 1 atomically with respect to other +! fetch-and-decs to location a in a wait-free fashion. +! +! usage : val = PR_AtomicDecrement(address) +! return: current value (you'd think this would be old val) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [local] - work register +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicDecrement) ! standard assembler/ELF prologue + +retryAD: + ld [%o0], %o2 ! set o2 to the current value + sub %o2, 0x1, %o3 ! calc the new value + mov %o3, %o1 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAD ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o1, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicDecrement) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = b atomically with respect to other +! fetch-and-stores to location a in a wait-free fashion. +! +! usage : old_val = PR_AtomicSet(address, newval) +! +! ----------------------- +! Note on REGISTER USAGE: +! as this is a LEAF procedure, a new stack frame is not created; +! we use the caller's stack frame so what would normally be %i (input) +! registers are actually %o (output registers). Also, we must not +! overwrite the contents of %l (local) registers as they are not +! assumed to be volatile during calls. +! +! So, the registers used are: +! %o0 [input] - the address of the value to increment +! %o1 [input] - the new value to set for [%o0] +! %o2 [local] - work register +! %o3 [local] - work register +! ----------------------- + + ENTRY(PR_AtomicSet) ! standard assembler/ELF prologue + +retryAS: + ld [%o0], %o2 ! set o2 to the current value + mov %o1, %o3 ! set up the new value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAS ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o3, %o0 ! set the return code to the prev value + + SET_SIZE(PR_AtomicSet) ! standard assembler/ELF epilogue + +! +! end +! +! ====================================================================== +! + +! ====================================================================== +! +! Perform the sequence a = a + b atomically with respect to other +! fetch-and-adds to location a in a wait-free fashion. +! +! usage : newval = PR_AtomicAdd(address, val) +! return: the value after addition +! + ENTRY(PR_AtomicAdd) ! standard assembler/ELF prologue + +retryAA: + ld [%o0], %o2 ! set o2 to the current value + add %o2, %o1, %o3 ! calc the new value + mov %o3, %o4 ! save the return value + cas [%o0], %o2, %o3 ! atomically set if o0 hasn't changed + cmp %o2, %o3 ! see if we set the value + bne retryAA ! if not, try again + nop ! empty out the branch pipeline + retl ! return back to the caller + mov %o4, %o0 ! set the return code to the new value + + SET_SIZE(PR_AtomicAdd) ! standard assembler/ELF epilogue + +! +! end +! diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86.s new file mode 100644 index 00000000..a64c4d5a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86.s @@ -0,0 +1,249 @@ +/ -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/ +/ 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 Netscape are +/ Copyright (C) 1998-2000 Netscape Communications Corporation. All +/ Rights Reserved. +/ +/ Contributor(s): +/ +/ Alternatively, the contents of this file may be used under the +/ terms of the GNU General Public License Version 2 or later (the +/ "GPL"), in which case the provisions of the GPL are applicable +/ instead of those above. If you wish to allow use of your +/ version of this file only under the terms of the GPL and not to +/ allow others to use your version of this file under the MPL, +/ indicate your decision by deleting the provisions above and +/ replace them with the notice and other provisions required by +/ the GPL. If you do not delete the provisions above, a recipient +/ may use your version of this file under either the MPL or the +/ GPL. +/ + + .text + + .globl getedi +getedi: + movl %edi,%eax + ret + .type getedi,@function + .size getedi,.-getedi + + .globl setedi +setedi: + movl 4(%esp),%edi + ret + .type setedi,@function + .size setedi,.-setedi + + .globl __MD_FlushRegisterWindows + .globl _MD_FlushRegisterWindows + +__MD_FlushRegisterWindows: +_MD_FlushRegisterWindows: + + ret + +/ +/ sol_getsp() +/ +/ Return the current sp (for debugging) +/ + .globl sol_getsp +sol_getsp: + movl %esp, %eax + ret + +/ +/ sol_curthread() +/ +/ Return a unique identifier for the currently active thread. +/ + .globl sol_curthread +sol_curthread: + movl %ecx, %eax + ret + +/ PRInt32 _MD_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _MD_AtomicIncrement + .align 4 +_MD_AtomicIncrement: + movl 4(%esp), %ecx + movl $1, %eax + lock + xaddl %eax, (%ecx) + incl %eax + ret + +/ PRInt32 _MD_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _MD_AtomicDecrement + .align 4 +_MD_AtomicDecrement: + movl 4(%esp), %ecx + movl $-1, %eax + lock + xaddl %eax, (%ecx) + decl %eax + ret + +/ PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ +/ An alternative implementation: +/ .text +/ .globl _MD_AtomicSet +/ .align 4 +/_MD_AtomicSet: +/ movl 4(%esp), %ecx +/ movl 8(%esp), %edx +/ movl (%ecx), %eax +/retry: +/ lock +/ cmpxchgl %edx, (%ecx) +/ jne retry +/ ret +/ + .text + .globl _MD_AtomicSet + .align 4 +_MD_AtomicSet: + movl 4(%esp), %ecx + movl 8(%esp), %eax + lock + xchgl %eax, (%ecx) + ret + +/ PRInt32 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _MD_AtomicAdd + .align 4 +_MD_AtomicAdd: + movl 4(%esp), %ecx + movl 8(%esp), %eax + movl %eax, %edx + lock + xaddl %eax, (%ecx) + addl %edx, %eax + ret + +/ +/ PR_StackPush(listp, elementp) +/ +/ Atomically push ElementP onto linked list ListP. +/ + .text +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + .globl VBoxNsprPR_StackPush +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + .globl PR_StackPush +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + .align 4 +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +VBoxNsprPR_StackPush: +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PR_StackPush: +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + movl 4(%esp), %ecx + movl $-1,%eax +pulock: +/ Already locked? + cmpl %eax,(%ecx) + je pulock + +/ Attempt to lock it + lock + xchgl %eax, (%ecx) + +/ Did we set the lock? + cmpl $-1, %eax + je pulock + +/ We now have the lock. Update pointers + movl 8(%esp), %edx + movl %eax, (%edx) + movl %edx, (%ecx) + +/ Done + ret + + +/ +/ elementp = PR_StackPop(listp) +/ +/ Atomically pop ElementP off linked list ListP +/ + .text +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + .globl VBoxNsprPR_StackPop +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + .globl PR_StackPop +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + .align 4 +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +VBoxNsprPR_StackPop: +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PR_StackPop: +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + movl 4(%esp), %ecx + movl $-1, %eax +polock: +/ Already locked? + cmpl %eax, (%ecx) + je polock + +/ Attempt to lock it + lock + xchgl %eax, (%ecx) + +/ Did we set the lock? + cmpl $-1, %eax + je polock + +/ We set the lock so now update pointers + +/ Was it empty? + movl $0, %edx + cmpl %eax,%edx + je empty + +/ Get element "next" pointer + movl (%eax), %edx + +/ Write NULL to the element "next" pointer + movl $0, (%eax) + +empty: +/ Put elements previous "next" value into listp +/ NOTE: This also unlocks the listp + movl %edx, (%ecx) + +/ Return previous listp value (already in eax) + ret diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s new file mode 100644 index 00000000..3c5ac393 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s @@ -0,0 +1,95 @@ +/ -*- 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) 2004 +/ 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 ***** + +/ PRInt32 _MD_AtomicIncrement(PRInt32 *val) +/ +/ Atomically increment the integer pointed to by 'val' and return +/ the result of the increment. +/ + .text + .globl _MD_AtomicIncrement + .align 4 +_MD_AtomicIncrement: + movl $1, %eax + lock + xaddl %eax, (%rdi) + incl %eax + ret + +/ PRInt32 _MD_AtomicDecrement(PRInt32 *val) +/ +/ Atomically decrement the integer pointed to by 'val' and return +/ the result of the decrement. +/ + .text + .globl _MD_AtomicDecrement + .align 4 +_MD_AtomicDecrement: + movl $-1, %eax + lock + xaddl %eax, (%rdi) + decl %eax + ret + +/ PRInt32 _MD_AtomicSet(PRInt32 *val, PRInt32 newval) +/ +/ Atomically set the integer pointed to by 'val' to the new +/ value 'newval' and return the old value. +/ + .text + .globl _MD_AtomicSet + .align 4 +_MD_AtomicSet: + movl %esi, %eax + xchgl %eax, (%rdi) + ret + +/ PRInt32 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +/ +/ Atomically add 'val' to the integer pointed to by 'ptr' +/ and return the result of the addition. +/ + .text + .globl _MD_AtomicAdd + .align 4 +_MD_AtomicAdd: + movl %esi, %eax + lock + xaddl %eax, (%rdi) + addl %esi, %eax + ret diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/osf1.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/osf1.c new file mode 100644 index 00000000..a4cd6a51 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/osf1.c @@ -0,0 +1,107 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for OSF1 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for OSF1."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for OSF1."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/pthreads_user.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/pthreads_user.c new file mode 100644 index 00000000..21e5f0b8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/pthreads_user.c @@ -0,0 +1,480 @@ +/* -*- 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 +#include +#include +#include + + +sigset_t ints_off; +pthread_mutex_t _pr_heapLock; +pthread_key_t current_thread_key; +pthread_key_t current_cpu_key; +pthread_key_t last_thread_key; +pthread_key_t intsoff_key; + + +PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed; +PRInt32 _pr_md_pthreads = 1; + +void _MD_EarlyInit(void) +{ +extern PRInt32 _nspr_noclock; + + if (pthread_key_create(¤t_thread_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(¤t_cpu_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(&last_thread_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + if (pthread_key_create(&intsoff_key, NULL) != 0) { + perror("pthread_key_create failed"); + exit(1); + } + + sigemptyset(&ints_off); + sigaddset(&ints_off, SIGALRM); + sigaddset(&ints_off, SIGIO); + sigaddset(&ints_off, SIGCLD); + + /* + * disable clock interrupts + */ + _nspr_noclock = 1; + +} + +void _MD_InitLocks() +{ + if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) { + perror("pthread_mutex_init failed"); + exit(1); + } +} + +PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp) +{ + PRIntn _is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(_is); + pthread_mutex_destroy(&lockp->mutex); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(_is); +} + + + +PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp) +{ + PRStatus rv; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + rv = pthread_mutex_init(&lockp->mutex, NULL); + if (me && !_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; +} + + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +PR_IMPLEMENT(void) +_MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) +{ + /* + * XXX - to be implemented + */ + return; +} + +PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread) +{ + struct sigaction sigact; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + thread->md.pthread = pthread_self(); +#if 0 + /* + * set up SIGUSR1 handler; this is used to save state + * during PR_SuspendAll + */ + sigact.sa_handler = save_context_and_block; + sigact.sa_flags = SA_RESTART; + /* + * Must mask clock interrupts + */ + sigact.sa_mask = timer_set; + sigaction(SIGUSR1, &sigact, 0); +#endif + } + + return PR_SUCCESS; +} + +PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); + } +} + +PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread) +{ + if (thread->flags & _PR_GLOBAL_SCOPE) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + } +} + +PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); +#if 0 + thread->md.suspending_id = getpid(); + rv = kill(thread->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +#endif +} + +PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread) +{ + PRInt32 rv; + + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && + _PR_IS_GCABLE_THREAD(thread)); +#if 0 + rv = unblockproc(thread->md.id); +#endif +} + +PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread) +{ + PRInt32 rv; + +#if 0 + cpu->md.suspending_id = getpid(); + rv = kill(cpu->md.id, SIGUSR1); + PR_ASSERT(rv == 0); + /* + * now, block the current thread/cpu until woken up by the suspended + * thread from it's SIGUSR1 signal handler + */ + blockproc(getpid()); +#endif +} + +PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread) +{ +#if 0 + unblockproc(cpu->md.id); +#endif +} + + +#define PT_NANOPERMICRO 1000UL +#define PT_BILLION 1000000000UL + +PR_IMPLEMENT(PRStatus) +_pt_wait(PRThread *thread, PRIntervalTime timeout) +{ +int rv; +struct timeval now; +struct timespec tmo; +PRUint32 ticks = PR_TicksPerSecond(); + + + if (timeout != PR_INTERVAL_NO_TIMEOUT) { + tmo.tv_sec = timeout / ticks; + tmo.tv_nsec = timeout - (tmo.tv_sec * ticks); + tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO * + tmo.tv_nsec); + + /* pthreads wants this in absolute time, off we go ... */ + (void)GETTIMEOFDAY(&now); + /* that one's usecs, this one's nsecs - grrrr! */ + tmo.tv_sec += now.tv_sec; + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; + tmo.tv_nsec %= PT_BILLION; + } + + pthread_mutex_lock(&thread->md.pthread_mutex); + thread->md.wait--; + if (thread->md.wait < 0) { + if (timeout != PR_INTERVAL_NO_TIMEOUT) { + rv = pthread_cond_timedwait(&thread->md.pthread_cond, + &thread->md.pthread_mutex, &tmo); + } + else + rv = pthread_cond_wait(&thread->md.pthread_cond, + &thread->md.pthread_mutex); + if (rv != 0) { + thread->md.wait++; + } + } else + rv = 0; + pthread_mutex_unlock(&thread->md.pthread_mutex); + + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + _MD_CHECK_FOR_EXIT(); + if (_pt_wait(thread, ticks) == PR_FAILURE) { + _MD_CHECK_FOR_EXIT(); + /* + * wait timed out + */ + _PR_THREAD_LOCK(thread); + if (thread->wait.cvar) { + /* + * The thread will remove itself from the waitQ + * of the cvar in _PR_WaitCondVar + */ + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT); + _PR_THREAD_UNLOCK(thread); + } + } + } else { + _PR_MD_SWITCH_CONTEXT(thread); + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +_MD_WakeupWaiter(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 pid, rv; + PRIntn is; + + PR_ASSERT(_pr_md_idle_cpus >= 0); + if (thread == NULL) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } else if (!_PR_IS_NATIVE_THREAD(thread)) { + /* + * If the thread is on my cpu's runq there is no need to + * wakeup any cpus + */ + if (!_PR_IS_NATIVE_THREAD(me)) { + if (me->cpu != thread->cpu) { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } + } else { + if (_pr_md_idle_cpus) + _MD_Wakeup_CPUs(); + } + } else { + PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + pthread_mutex_lock(&thread->md.pthread_mutex); + thread->md.wait++; + rv = pthread_cond_signal(&thread->md.pthread_cond); + PR_ASSERT(rv == 0); + pthread_mutex_unlock(&thread->md.pthread_mutex); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + } + return PR_SUCCESS; +} + +/* These functions should not be called for AIX */ +PR_IMPLEMENT(void) +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); +} + +PR_IMPLEMENT(PRStatus) +_MD_CreateThread( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PRIntn is; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + pthread_attr_t attr; + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + thread->flags |= _PR_GLOBAL_SCOPE; + + pthread_attr_init(&attr); /* initialize attr with default attributes */ + if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + pthread_attr_destroy(&attr); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_FAILURE; + } + + thread->md.wait = 0; + rv = pthread_create(&thread->md.pthread, &attr, start, (void *)thread); + if (0 == rv) { + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created); + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return PR_SUCCESS; + } else { + pthread_mutex_destroy(&thread->md.pthread_mutex); + pthread_cond_destroy(&thread->md.pthread_cond); + pthread_attr_destroy(&attr); + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, rv); + return PR_FAILURE; + } +} + +PR_IMPLEMENT(void) +_MD_InitRunningCPU(struct _PRCPU *cpu) +{ + extern int _pr_md_pipefd[2]; + + _MD_unix_init_running_cpu(cpu); + cpu->md.pthread = pthread_self(); + if (_pr_md_pipefd[0] >= 0) { + _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0]; +#ifndef _PR_USE_POLL + FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu)); +#endif + } +} + + +void +_MD_CleanupBeforeExit(void) +{ +#if 0 + extern PRInt32 _pr_cpus_exit; + + _pr_irix_exit_now = 1; + if (_pr_numCPU > 1) { + /* + * Set a global flag, and wakeup all cpus which will notice the flag + * and exit. + */ + _pr_cpus_exit = getpid(); + _MD_Wakeup_CPUs(); + while(_pr_numCPU > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _pr_numCPU--; + } + } + /* + * cause global threads on the recycle list to exit + */ + _PR_DEADQ_LOCK; + if (_PR_NUM_DEADNATIVE != 0) { + PRThread *thread; + PRCList *ptr; + + ptr = _PR_DEADNATIVEQ.next; + while( ptr != &_PR_DEADNATIVEQ ) { + thread = _PR_THREAD_PTR(ptr); + _MD_CVAR_POST_SEM(thread); + ptr = ptr->next; + } + } + _PR_DEADQ_UNLOCK; + while(_PR_NUM_DEADNATIVE > 1) { + _PR_WAIT_SEM(_pr_irix_exit_sem); + _PR_DEC_DEADNATIVE; + } +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/qnx.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/qnx.c new file mode 100644 index 00000000..be86e5b9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/qnx.c @@ -0,0 +1,102 @@ +/* -*- 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 + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); + return PR_FAILURE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/reliantunix.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/reliantunix.c new file mode 100644 index 00000000..efe21086 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/reliantunix.c @@ -0,0 +1,133 @@ +/* -*- 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 ***** */ + +/* + * SINIX (ReliantUNIX) 5.4 - copied from unixware.c by chrisk 040497 + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) _GETCONTEXT(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for SINIX */ +/* Why? Just copied it from UNIXWARE... flying-by-night, chrisk 040497 */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SINIX."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SINIX."); +#if defined(SNI) && !defined(__GNUC__) + /* make compiler happy */ + return (PRStatus)NULL; +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/rhapsody.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/rhapsody.c new file mode 100644 index 00000000..5df3c199 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/rhapsody.c @@ -0,0 +1,137 @@ +/* -*- 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" + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if !defined(_PR_PTHREADS) + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#if !defined(_PR_PTHREADS) +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Rhapsody */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Rhapsody."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Rhapsody."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ + +#if defined(_PR_PTHREADS) + +/* +** Stubs for unimplemented functions +*/ + +int pthread_condattr_init(pthread_condattr_t *attr) +{ + return 0; +} + +int pthread_kill(pthread_t thread, int sig) +{ + return ENOSYS; +} + +typedef struct siginfo_t siginfo_t; + +int sigtimedwait(const sigset_t *set, siginfo_t *info, + const struct timespec *timeout) +{ + errno = ENOSYS; + return -1; +} + +#endif /* _PR_PTHREADS */ + +/* rhapsody.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/scoos.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/scoos.c new file mode 100644 index 00000000..766bf917 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/scoos.c @@ -0,0 +1,181 @@ +/* -*- 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 ***** */ + +/* + * SCO ODT 5.0 - originally created by mikep + */ +#include "primpl.h" + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for SCO */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SCO."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SCO."); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/solaris.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/solaris.c new file mode 100644 index 00000000..2ec3bd1e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/solaris.c @@ -0,0 +1,889 @@ +/* -*- 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" + + +extern PRBool suspendAllOn; +extern PRThread *suspendAllThread; + +extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri); + +PRIntervalTime _MD_Solaris_TicksPerSecond(void) +{ + /* + * Ticks have a 10-microsecond resolution. So there are + * 100000 ticks per second. + */ + return 100000UL; +} + +/* Interval timers, implemented using gethrtime() */ + +PRIntervalTime _MD_Solaris_GetInterval(void) +{ + union { + hrtime_t hrt; /* hrtime_t is a 64-bit (long long) integer */ + PRInt64 pr64; + } time; + PRInt64 resolution; + PRIntervalTime ticks; + + time.hrt = gethrtime(); /* in nanoseconds */ + /* + * Convert from nanoseconds to ticks. A tick's resolution is + * 10 microseconds, or 10000 nanoseconds. + */ + LL_I2L(resolution, 10000); + LL_DIV(time.pr64, time.pr64, resolution); + LL_L2UI(ticks, time.pr64); + return ticks; +} + +#ifdef _PR_PTHREADS +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + *np = 0; + return NULL; +} +#endif /* _PR_PTHREADS */ + +#if !defined(i386) && !defined(IS_64) +#if defined(_PR_HAVE_ATOMIC_OPS) +/* NOTE: + * SPARC v9 (Ultras) do have an atomic test-and-set operation. But + * SPARC v8 doesn't. We should detect in the init if we are running on + * v8 or v9, and then use assembly where we can. + * + * This code uses the Solaris threads API. It can be used in both the + * pthreads and Solaris threads versions of nspr20 because "POSIX threads + * and Solaris threads are fully compatible even within the same process", + * to quote from pthread_create(3T). + */ + +#include +#include + +static mutex_t _solaris_atomic = DEFAULTMUTEX; + +PRInt32 +_MD_AtomicIncrement(PRInt32 *val) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = ++(*val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +PRInt32 +_MD_AtomicAdd(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = ((*ptr) += val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +PRInt32 +_MD_AtomicDecrement(PRInt32 *val) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = --(*val); + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} + +PRInt32 +_MD_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + if (mutex_lock(&_solaris_atomic) != 0) + PR_ASSERT(0); + + rv = *val; + *val = newval; + + if (mutex_unlock(&_solaris_atomic) != 0)\ + PR_ASSERT(0); + + return rv; +} +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif /* !defined(i386) */ + +#if defined(_PR_GLOBAL_THREADS_ONLY) +#include +#include +#include +#include + +#include +#include +#include +extern int syscall(); /* not declared in sys/syscall.h */ + +static sigset_t old_mask; /* store away original gc thread sigmask */ +static PRIntn gcprio; /* store away original gc thread priority */ + +THREAD_KEY_T threadid_key; +THREAD_KEY_T cpuid_key; +THREAD_KEY_T last_thread_key; +static sigset_t set, oldset; + +static void +threadid_key_destructor(void *value) +{ + PRThread *me = (PRThread *)value; + PR_ASSERT(me != NULL); + /* the thread could be PRIMORDIAL (thus not ATTACHED) */ + if (me->flags & _PR_ATTACHED) { + /* + * The Solaris thread library sets the thread specific + * data (the current thread) to NULL before invoking + * the destructor. We need to restore it to prevent the + * _PR_MD_CURRENT_THREAD() call in _PRI_DetachThread() + * from attaching the thread again. + */ + _PR_MD_SET_CURRENT_THREAD(me); + _PRI_DetachThread(); + } +} + +void _MD_EarlyInit(void) +{ + THR_KEYCREATE(&threadid_key, threadid_key_destructor); + THR_KEYCREATE(&cpuid_key, NULL); + THR_KEYCREATE(&last_thread_key, NULL); + sigemptyset(&set); + sigaddset(&set, SIGALRM); +} + +PRStatus _MD_CreateThread(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PRInt32 flags; + + /* mask out SIGALRM for native thread creation */ + thr_sigsetmask(SIG_BLOCK, &set, &oldset); + + /* + * Note that we create joinable threads with the THR_DETACHED + * flag. The reasons why we don't use thr_join to implement + * PR_JoinThread are: + * - We use a termination condition variable in the PRThread + * structure to implement PR_JoinThread across all classic + * nspr implementation strategies. + * - The native threads may be recycled by NSPR to run other + * new NSPR threads, so the native threads may not terminate + * when the corresponding NSPR threads terminate. + */ + flags = THR_SUSPENDED|THR_DETACHED; + if (_PR_IS_GCABLE_THREAD(thread) || (thread->flags & _PR_BOUND_THREAD) || + (scope == PR_GLOBAL_BOUND_THREAD)) + flags |= THR_BOUND; + + if (thr_create(NULL, thread->stack->stackSize, + (void *(*)(void *)) start, (void *) thread, + flags, + &thread->md.handle)) { + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + return PR_FAILURE; + } + + /* When the thread starts running, then the lwpid is set to the right + * value. Until then we want to mark this as 'uninit' so that + * its register state is initialized properly for GC */ + + thread->md.lwpid = -1; + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + + if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) { + thread->flags |= _PR_GLOBAL_SCOPE; + } + + _MD_SET_PRIORITY(&(thread->md), priority); + + /* Activate the thread */ + if (thr_continue( thread->md.handle ) ) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_cleanup_thread(PRThread *thread) +{ + thread_t hdl; + + hdl = thread->md.handle; + + /* + ** First, suspend the thread (unless it's the active one) + ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to + ** prevent both of us modifying the thread structure at the same time. + */ + if ( thread != _PR_MD_CURRENT_THREAD() ) { + thr_suspend(hdl); + } + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[DestroyThread]\n", thread)); + + _MD_DESTROY_SEM(&thread->md.waiter_sem); +} + +void _MD_exit_thread(PRThread *thread) +{ + _MD_CLEAN_THREAD(thread); + _MD_SET_CURRENT_THREAD(NULL); +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, + PRThreadPriority newPri) +{ + PRIntn nativePri; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + /* Solaris priorities are from 0 to 127 */ + nativePri = newPri * 127 / PR_PRIORITY_LAST; + if(thr_setprio((thread_t)md_thread->handle, nativePri)) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_SetThreadPriority: can't set thread priority\n")); + } +} + +void _MD_WAIT_CV( + struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout) +{ + struct timespec tt; + PRUint32 msec; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT((!suspendAllOn) || (suspendAllThread != me)); + + if (PR_INTERVAL_NO_TIMEOUT == timeout) { + COND_WAIT(&md_cv->cv, &md_lock->lock); + } else { + msec = PR_IntervalToMilliseconds(timeout); + + GETTIME(&tt); + tt.tv_sec += msec / PR_MSEC_PER_SEC; + tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC; + /* Check for nsec overflow - otherwise we'll get an EINVAL */ + if (tt.tv_nsec >= PR_NSEC_PER_SEC) { + tt.tv_sec++; + tt.tv_nsec -= PR_NSEC_PER_SEC; + } + COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt); + } +} + +void _MD_lock(struct _MDLock *md_lock) +{ +#ifdef DEBUG + /* This code was used for GC testing to make sure that we didn't attempt + * to grab any locks while threads are suspended. + */ + PRLock *lock; + + if ((suspendAllOn) && (suspendAllThread == _PR_MD_CURRENT_THREAD())) { + lock = ((PRLock *) ((char*) (md_lock) - offsetof(PRLock,ilock))); + PR_ASSERT(lock->owner == NULL); + return; + } +#endif /* DEBUG */ + + mutex_lock(&md_lock->lock); +} + +PRThread *_pr_attached_thread_tls() +{ + PRThread *ret; + + thr_getspecific(threadid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_current_thread_tls() +{ + PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(thread != NULL); + + return thread; +} + +PRStatus +_MD_wait(PRThread *thread, PRIntervalTime ticks) +{ + _MD_WAIT_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +PRStatus +_MD_WakeupWaiter(PRThread *thread) +{ + if (thread == NULL) { + return PR_SUCCESS; + } + _MD_POST_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +_PRCPU *_pr_current_cpu_tls() +{ + _PRCPU *ret; + + thr_getspecific(cpuid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_last_thread_tls() +{ + PRThread *ret; + + thr_getspecific(last_thread_key, (void **)&ret); + return ret; +} + +_MDLock _pr_ioq_lock; + +void +_MD_InitIO(void) +{ + _MD_NEW_LOCK(&_pr_ioq_lock); +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + if (!_PR_IS_NATIVE_THREAD(thread)) + return PR_SUCCESS; + /* sol_curthread is an asm routine which grabs GR7; GR7 stores an internal + * thread structure ptr used by solaris. We'll use this ptr later + * with suspend/resume to find which threads are running on LWPs. + */ + thread->md.threadID = sol_curthread(); + /* prime the sp; substract 4 so we don't hit the assert that + * curr sp > base_stack + */ + thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long); + thread->md.lwpid = _lwp_self(); + thread->md.handle = THR_SELF(); + + /* all threads on Solaris are global threads from NSPR's perspective + * since all of them are mapped to Solaris threads. + */ + thread->flags |= _PR_GLOBAL_SCOPE; + + /* For primordial/attached thread, we don't create an underlying native thread. + * So, _MD_CREATE_THREAD() does not get called. We need to do initialization + * like allocating thread's synchronization variables and set the underlying + * native thread's priority. + */ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + _MD_SET_PRIORITY(&(thread->md), thread->priority); + } + return PR_SUCCESS; +} + +/* Sleep for n milliseconds, n < 1000 */ +void solaris_msec_sleep(int n) +{ + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 1000000*n; + if (syscall(SYS_nanosleep, &ts, 0, 0) < 0) { + PR_ASSERT(0); + } +} + +#define VALID_SP(sp, bottom, top) \ + (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top))) + +void solaris_record_regs(PRThread *t, prstatus_t *lwpstatus) +{ +#ifdef sparc + long *regs = (long *)&t->md.context.uc_mcontext.gregs[0]; + + PR_ASSERT(_PR_IS_GCABLE_THREAD(t)); + PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[REG_G7]); + + t->md.sp = lwpstatus->pr_reg[REG_SP]; + PR_ASSERT(VALID_SP(t->md.sp, t->stack->stackBottom, t->stack->stackTop)); + + regs[0] = lwpstatus->pr_reg[R_G1]; + regs[1] = lwpstatus->pr_reg[R_G2]; + regs[2] = lwpstatus->pr_reg[R_G3]; + regs[3] = lwpstatus->pr_reg[R_G4]; + regs[4] = lwpstatus->pr_reg[R_O0]; + regs[5] = lwpstatus->pr_reg[R_O1]; + regs[6] = lwpstatus->pr_reg[R_O2]; + regs[7] = lwpstatus->pr_reg[R_O3]; + regs[8] = lwpstatus->pr_reg[R_O4]; + regs[9] = lwpstatus->pr_reg[R_O5]; + regs[10] = lwpstatus->pr_reg[R_O6]; + regs[11] = lwpstatus->pr_reg[R_O7]; +#elif defined(i386) + /* + * To be implemented and tested + */ + PR_ASSERT(0); + PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[GS]); + t->md.sp = lwpstatus->pr_reg[UESP]; +#endif +} + +void solaris_preempt_off() +{ + sigset_t set; + + (void)sigfillset(&set); + syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask); +} + +void solaris_preempt_on() +{ + syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL); +} + +int solaris_open_main_proc_fd() +{ + char buf[30]; + int fd; + + /* Not locked, so must be created while threads coming up */ + PR_snprintf(buf, sizeof(buf), "/proc/%ld", getpid()); + if ( (fd = syscall(SYS_open, buf, O_RDONLY)) < 0) { + return -1; + } + return fd; +} + +/* Return a file descriptor for the /proc entry corresponding to the + * given lwp. + */ +int solaris_open_lwp(lwpid_t id, int lwp_main_proc_fd) +{ + int result; + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCOPENLWP, &id)) <0) + return -1; /* exited??? */ + + return result; +} +void _MD_Begin_SuspendAll() +{ + solaris_preempt_off(); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n")); + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + suspendAllOn = PR_TRUE; + suspendAllThread = _PR_MD_CURRENT_THREAD(); +} + +void _MD_End_SuspendAll() +{ +} + +void _MD_End_ResumeAll() +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n")); + thr_setprio(thr_self(), gcprio); + solaris_preempt_on(); + suspendAllThread = NULL; + suspendAllOn = PR_FALSE; +} + +void _MD_Suspend(PRThread *thr) +{ + int lwp_fd, result; + prstatus_t lwpstatus; + int lwp_main_proc_fd = 0; + + if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){ + /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend + * during that time we can't call any thread lib or libc calls. Hence + * make sure that no suspension is requested for Non gcable thread + * during suspendAllOn */ + PR_ASSERT(!suspendAllOn); + thr_suspend(thr->md.handle); + return; + } + + /* XXX Primordial thread can't be bound to an lwp, hence there is no + * way we can assume that we can get the lwp status for primordial + * thread reliably. Hence we skip this for primordial thread, hoping + * that the SP is saved during lock and cond. wait. + * XXX - Again this is concern only for java interpreter, not for the + * server, 'cause primordial thread in the server does not do java work + */ + if (thr->flags & _PR_PRIMORDIAL) + return; + + /* XXX Important Note: If the start function of a thread is not called, + * lwpid is -1. Then, skip this thread. This thread will get caught + * in PR_NativeRunThread before calling the start function, because + * we hold the pr_activeLock during suspend/resume */ + + /* if the thread is not started yet then don't do anything */ + if (!suspendAllOn || thr->md.lwpid == -1) + return; + + if (_lwp_suspend(thr->md.lwpid) < 0) { + PR_ASSERT(0); + return; + } + + if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) { + PR_ASSERT(0); + return; /* XXXMB ARGH, we're hosed! */ + } + + if ( (lwp_fd = solaris_open_lwp(thr->md.lwpid, lwp_main_proc_fd)) < 0) { + PR_ASSERT(0); + close(lwp_main_proc_fd); + return; + } + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + /* Hopefully the thread just died... */ + close(lwp_fd); + close(lwp_main_proc_fd); + return; + } + while ( !(lwpstatus.pr_flags & PR_STOPPED) ) { + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + PR_ASSERT(0); /* ARGH SOMETHING WRONG! */ + break; + } + solaris_msec_sleep(1); + } + solaris_record_regs(thr, &lwpstatus); + close(lwp_fd); + close(lwp_main_proc_fd); +} + +#ifdef OLD_CODE + +void _MD_SuspendAll() +{ + /* On solaris there are threads, and there are LWPs. + * Calling _PR_DoSingleThread would freeze all of the threads bound to LWPs + * but not necessarily stop all LWPs (for example if someone did + * an attachthread of a thread which was not bound to an LWP). + * So now go through all the LWPs for this process and freeze them. + * + * Note that if any thread which is capable of having the GC run on it must + * had better be a LWP with a single bound thread on it. Otherwise, this + * might not stop that thread from being run. + */ + PRThread *current = _PR_MD_CURRENT_THREAD(); + prstatus_t status, lwpstatus; + int result, index, lwp_fd; + lwpid_t me = _lwp_self(); + int err; + int lwp_main_proc_fd; + + solaris_preempt_off(); + + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + + current->md.sp = (uint_t)&me; /* set my own stack pointer */ + + if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) { + PR_ASSERT(0); + solaris_preempt_on(); + return; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCSTATUS, &status)) < 0) { + err = errno; + PR_ASSERT(0); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + num_lwps = status.pr_nlwp; + + if ( (all_lwps = (lwpid_t *)PR_MALLOC((num_lwps+1) * sizeof(lwpid_t)))==NULL) { + PR_ASSERT(0); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCLWPIDS, all_lwps)) < 0) { + PR_ASSERT(0); + PR_DELETE(all_lwps); + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + for (index=0; index< num_lwps; index++) { + if (all_lwps[index] != me) { + if (_lwp_suspend(all_lwps[index]) < 0) { + /* could happen if lwp exited */ + all_lwps[index] = me; /* dummy it up */ + } + } + } + + /* Turns out that lwp_suspend is not a blocking call. + * Go through the list and make sure they are all stopped. + */ + for (index=0; index< num_lwps; index++) { + if (all_lwps[index] != me) { + if ( (lwp_fd = solaris_open_lwp(all_lwps[index], lwp_main_proc_fd)) < 0) { + PR_ASSERT(0); + PR_DELETE(all_lwps); + all_lwps = NULL; + goto failure; /* XXXMB ARGH, we're hosed! */ + } + + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + /* Hopefully the thread just died... */ + close(lwp_fd); + continue; + } + while ( !(lwpstatus.pr_flags & PR_STOPPED) ) { + if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) { + PR_ASSERT(0); /* ARGH SOMETHING WRONG! */ + break; + } + solaris_msec_sleep(1); + } + solaris_record_regs(&lwpstatus); + close(lwp_fd); + } + } + + close(lwp_main_proc_fd); + + return; +failure: + solaris_preempt_on(); + thr_setprio(thr_self(), gcprio); + close(lwp_main_proc_fd); + return; +} + +void _MD_ResumeAll() +{ + int i; + lwpid_t me = _lwp_self(); + + for (i=0; i < num_lwps; i++) { + if (all_lwps[i] == me) + continue; + if ( _lwp_continue(all_lwps[i]) < 0) { + PR_ASSERT(0); /* ARGH, we are hosed! */ + } + } + + /* restore priority and sigmask */ + thr_setprio(thr_self(), gcprio); + solaris_preempt_on(); + PR_DELETE(all_lwps); + all_lwps = NULL; +} +#endif /* OLD_CODE */ + +#ifdef USE_SETJMP +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} +#else +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); + } + *np = NGREG; + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} +#endif /* USE_SETJMP */ + +#else /* _PR_GLOBAL_THREADS_ONLY */ + +#if defined(_PR_LOCAL_THREADS_ONLY) + +void _MD_EarlyInit(void) +{ +} + +void _MD_SolarisInit() +{ + _PR_UnixInit(); +} + +void +_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + PR_ASSERT((thread == NULL) || (!(thread->flags & _PR_GLOBAL_SCOPE))); + return PR_SUCCESS; +} + +/* These functions should not be called for Solaris */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Solaris"); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Solaris"); + return(PR_FAILURE); +} + +#ifdef USE_SETJMP +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} +#else +PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); + } + *np = NGREG; + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} +#endif /* USE_SETJMP */ + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +#ifndef _PR_PTHREADS +#if defined(i386) && defined(SOLARIS2_4) +/* + * Because clock_gettime() on Solaris/x86 2.4 always generates a + * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(), + * which is implemented using gettimeofday(). + */ + +int +_pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + struct timeval tv; + + if (clock_id != CLOCK_REALTIME) { + errno = EINVAL; + return -1; + } + + gettimeofday(&tv, NULL); + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return 0; +} +#endif /* i386 && SOLARIS2_4 */ +#endif /* _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sony.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sony.c new file mode 100644 index 00000000..dacb4fd5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sony.c @@ -0,0 +1,109 @@ +/* -*- 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 + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#ifndef _PR_PTHREADS + if (isCurrent) { + (void) setjmp(CONTEXT(t), 1); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +#else + *np = 0; + return NULL; +#endif +} + +#ifndef _PR_PTHREADS +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Sony */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SONY."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SONY."); + return PR_FAILURE; +} +#endif /* ! _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sunos4.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sunos4.c new file mode 100644 index 00000000..d3b40c15 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/sunos4.c @@ -0,0 +1,96 @@ +/* -*- 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 +#include "primpl.h" + +void _MD_EarlyInit(void) +{ +} + +PRStatus _MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SunOS 4.1.3."); + return PR_FAILURE; +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri) +{ + PR_NOT_REACHED("_MD_SET_PRIORITY should not be called for user-level threads."); +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for SunOS 4.1.3."); +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix.c new file mode 100644 index 00000000..5901a476 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix.c @@ -0,0 +1,3738 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "primpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _PR_POLL_AVAILABLE +#include +#endif + +/* To get FIONREAD */ +#if defined(NCR) || defined(UNIXWARE) || defined(NEC) || defined(SNI) \ + || defined(SONY) +#include +#endif + +#if defined(NTO) +#include +#endif + +#ifdef VBOX +# include +#endif + +/* + * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or + * PRInt32* pointer to a _PRSockLen_t* pointer. + */ +#if defined(HAVE_SOCKLEN_T) \ + || (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2) +#define _PRSockLen_t socklen_t +#elif defined(IRIX) || defined(HPUX) || defined(OSF1) || defined(SOLARIS) \ + || defined(AIX4_1) || defined(LINUX) || defined(SONY) \ + || defined(BSDI) || defined(SCO) || defined(NEC) || defined(SNI) \ + || defined(SUNOS4) || defined(NCR) || defined(DARWIN) \ + || defined(NEXTSTEP) || defined(QNX) +#define _PRSockLen_t int +#elif (defined(AIX) && !defined(AIX4_1)) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) || defined(UNIXWARE) \ + || defined(DGUX) || defined(VMS) || defined(NTO) +#define _PRSockLen_t size_t +#else +#error "Cannot determine architecture" +#endif + +/* +** Global lock variable used to bracket calls into rusty libraries that +** aren't thread safe (like libc, libX, etc). +*/ +static PRLock *_pr_rename_lock = NULL; +static PRMonitor *_pr_Xfe_mon = NULL; + +static PRInt64 minus_one; + +sigset_t timer_set; + +#if !defined(_PR_PTHREADS) + +static sigset_t empty_set; + +#ifdef SOLARIS +#include +#include +#endif + +#ifndef PIPE_BUF +#define PIPE_BUF 512 +#endif + +/* + * _nspr_noclock - if set clock interrupts are disabled + */ +int _nspr_noclock = 1; + +#ifdef IRIX +extern PRInt32 _nspr_terminate_on_error; +#endif + +/* + * There is an assertion in this code that NSPR's definition of PRIOVec + * is bit compatible with UNIX' definition of a struct iovec. This is + * applicable to the 'writev()' operations where the types are casually + * cast to avoid warnings. + */ + +int _pr_md_pipefd[2] = { -1, -1 }; +static char _pr_md_pipebuf[PIPE_BUF]; +static PRInt32 local_io_wait(PRInt32 osfd, PRInt32 wait_flag, + PRIntervalTime timeout); + +_PRInterruptTable _pr_interruptTable[] = { + { + "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, + { + 0 } +}; + +PR_IMPLEMENT(void) _MD_unix_init_running_cpu(_PRCPU *cpu) +{ + PR_INIT_CLIST(&(cpu->md.md_unix.ioQ)); + cpu->md.md_unix.ioq_max_osfd = -1; + cpu->md.md_unix.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; +} + +PRStatus _MD_open_dir(_MDDir *d, const char *name) +{ +int err; + + d->d = opendir(name); + if (!d->d) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPENDIR_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRInt32 _MD_close_dir(_MDDir *d) +{ +int rv = 0, err; + + if (d->d) { + rv = closedir(d->d); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSEDIR_ERROR(err); + } + } + return rv; +} + +char * _MD_read_dir(_MDDir *d, PRIntn flags) +{ +struct dirent *de; +int err; + + for (;;) { + /* + * XXX: readdir() is not MT-safe. There is an MT-safe version + * readdir_r() on some systems. + */ + de = readdir(d->d); + if (!de) { + err = _MD_ERRNO(); + _PR_MD_MAP_READDIR_ERROR(err); + return 0; + } + if ((flags & PR_SKIP_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == 0)) + continue; + if ((flags & PR_SKIP_DOT_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == '.') && + (de->d_name[2] == 0)) + continue; + if ((flags & PR_SKIP_HIDDEN) && (de->d_name[0] == '.')) + continue; + break; + } + return de->d_name; +} + +PRInt32 _MD_delete(const char *name) +{ +PRInt32 rv, err; +#ifdef UNIXWARE + sigset_t set, oset; +#endif + +#ifdef UNIXWARE + sigfillset(&set); + sigprocmask(SIG_SETMASK, &set, &oset); +#endif + rv = unlink(name); +#ifdef UNIXWARE + sigprocmask(SIG_SETMASK, &oset, NULL); +#endif + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_UNLINK_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_rename(const char *from, const char *to) +{ + PRInt32 rv = -1, err; + + /* + ** This is trying to enforce the semantics of WINDOZE' rename + ** operation. That means one is not allowed to rename over top + ** of an existing file. Holding a lock across these two function + ** and the open function is known to be a bad idea, but .... + */ + if (NULL != _pr_rename_lock) + PR_Lock(_pr_rename_lock); + if (0 == access(to, F_OK)) + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + else + { + rv = rename(from, to); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_RENAME_ERROR(err); + } + } + if (NULL != _pr_rename_lock) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRInt32 _MD_access(const char *name, PRAccessHow how) +{ +PRInt32 rv, err; +int amode; + + switch (how) { + case PR_ACCESS_WRITE_OK: + amode = W_OK; + break; + case PR_ACCESS_READ_OK: + amode = R_OK; + break; + case PR_ACCESS_EXISTS: + amode = F_OK; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + rv = access(name, amode); + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_ACCESS_ERROR(err); + } + +done: + return(rv); +} + +PRInt32 _MD_mkdir(const char *name, PRIntn mode) +{ +int rv, err; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. Look there for more fun details. + */ + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + rv = mkdir(name, mode); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_MKDIR_ERROR(err); + } + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRInt32 _MD_rmdir(const char *name) +{ +int rv, err; + + rv = rmdir(name); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_RMDIR_ERROR(err); + } + return rv; +} + +PRInt32 _MD_read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +PRInt32 rv, err; +#ifndef _PR_USE_POLL +fd_set rd; +#else +struct pollfd pfd; +#endif /* _PR_USE_POLL */ +PRInt32 osfd = fd->secret->md.osfd; + +#ifndef _PR_USE_POLL + FD_ZERO(&rd); + FD_SET(osfd, &rd); +#else + pfd.fd = osfd; + pfd.events = POLLIN; +#endif /* _PR_USE_POLL */ + while ((rv = read(osfd,buf,amount)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, + PR_INTERVAL_NO_TIMEOUT)) < 0) + goto done; + } else { +#ifndef _PR_USE_POLL + while ((rv = _MD_SELECT(osfd + 1, &rd, NULL, NULL, NULL)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_SELECT() if it is interrupted */ + } +#else /* _PR_USE_POLL */ + while ((rv = _MD_POLL(&pfd, 1, -1)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_POLL() if it is interrupted */ + } +#endif /* _PR_USE_POLL */ + if (rv == -1) { + break; + } + } + if (_PR_PENDING_INTERRUPT(me)) + break; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + _PR_MD_MAP_READ_ERROR(err); + } + } +done: + return(rv); +} + +PRInt32 _MD_write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ +PRThread *me = _PR_MD_CURRENT_THREAD(); +PRInt32 rv, err; +#ifndef _PR_USE_POLL +fd_set wd; +#else +struct pollfd pfd; +#endif /* _PR_USE_POLL */ +PRInt32 osfd = fd->secret->md.osfd; + +#ifndef _PR_USE_POLL + FD_ZERO(&wd); + FD_SET(osfd, &wd); +#else + pfd.fd = osfd; + pfd.events = POLLOUT; +#endif /* _PR_USE_POLL */ + while ((rv = write(osfd,buf,amount)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, + PR_INTERVAL_NO_TIMEOUT)) < 0) + goto done; + } else { +#ifndef _PR_USE_POLL + while ((rv = _MD_SELECT(osfd + 1, NULL, &wd, NULL, NULL)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_SELECT() if it is interrupted */ + } +#else /* _PR_USE_POLL */ + while ((rv = _MD_POLL(&pfd, 1, -1)) + == -1 && (err = _MD_ERRNO()) == EINTR) { + /* retry _MD_POLL() if it is interrupted */ + } +#endif /* _PR_USE_POLL */ + if (rv == -1) { + break; + } + } + if (_PR_PENDING_INTERRUPT(me)) + break; + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + _PR_MD_MAP_WRITE_ERROR(err); + } + } +done: + return(rv); +} + +PRInt32 _MD_fsync(PRFileDesc *fd) +{ +PRInt32 rv, err; + + rv = fsync(fd->secret->md.osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_FSYNC_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_close(PRInt32 osfd) +{ +PRInt32 rv, err; + + rv = close(osfd); + if (rv == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_CLOSE_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRInt32 osfd, err; + + osfd = socket(domain, type, proto); + + if (osfd == -1) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKET_ERROR(err); + return(osfd); + } + + return(osfd); +} + +PRInt32 _MD_socketavailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) { + _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO()); + return -1; + } + return result; +} + +PRInt64 _MD_socketavailable64(PRFileDesc *fd) +{ + PRInt64 result; + LL_I2L(result, _MD_socketavailable(fd)); + return result; +} /* _MD_socketavailable64 */ + +#define READ_FD 1 +#define WRITE_FD 2 + +/* + * socket_io_wait -- + * + * wait for socket i/o, periodically checking for interrupt + * + * The first implementation uses select(), for platforms without + * poll(). The second (preferred) implementation uses poll(). + */ + +#ifndef _PR_USE_POLL + +static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; + fd_set rd_wr; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + do { + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; + FD_ZERO(&rd_wr); + do { + /* + * We block in _MD_SELECT for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + if (fd_type == READ_FD) + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + else + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_SELECT_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if _MD_SELECT timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If _MD_SELECT timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { + now += PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); + } + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); +} + +#else /* _PR_USE_POLL */ + +static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + int msecs; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRInt32 syserror; + struct pollfd pfd; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + pfd.fd = osfd; + if (fd_type == READ_FD) { + pfd.events = POLLIN; + } else { + pfd.events = POLLOUT; + } + do { + rv = _MD_POLL(&pfd, 1, msecs); + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_POLL_ERROR(syserror); + break; + } + /* + * If POLLERR is set, don't process it; retry the operation + */ + if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { + rv = -1; + _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = timeout; + pfd.fd = osfd; + if (fd_type == READ_FD) { + pfd.events = POLLIN; + } else { + pfd.events = POLLOUT; + } + do { + /* + * We block in _MD_POLL for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + wait_for_remaining = PR_TRUE; + msecs = PR_IntervalToMilliseconds(remaining); + if (msecs > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) { + wait_for_remaining = PR_FALSE; + msecs = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000; + } + rv = _MD_POLL(&pfd, 1, msecs); + /* + * we don't consider EINTR a real error + */ + if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) { + _PR_MD_MAP_POLL_ERROR(syserror); + break; + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * If POLLERR is set, don't process it; retry the operation + */ + if ((rv == 1) && (pfd.revents & (POLLHUP | POLLNVAL))) { + rv = -1; + _PR_MD_MAP_POLL_REVENTS_ERROR(pfd.revents); + break; + } + /* + * We loop again if _MD_POLL timed out or got interrupted + * by a signal, and the timeout deadline has not passed yet. + */ + if (rv == 0 || (rv == -1 && syserror == EINTR)) { + /* + * If _MD_POLL timed out, we know how much time + * we spent in blocking, so we can avoid a + * PR_IntervalNow() call. + */ + if (rv == 0) { + if (wait_for_remaining) { + now += remaining; + } else { + now += PR_MillisecondsToInterval(msecs); + } + } else { + now = PR_IntervalNow(); + } + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= timeout) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = timeout - elapsed; + } + } + } while (rv == 0 || (rv == -1 && syserror == EINTR)); + break; + } + return(rv); +} + +#endif /* _PR_USE_POLL */ + +static PRInt32 local_io_wait( + PRInt32 osfd, + PRInt32 wait_flag, + PRIntervalTime timeout) +{ + _PRUnixPollDesc pd; + PRInt32 rv; + + PR_LOG(_pr_io_lm, PR_LOG_MIN, + ("waiting to %s on osfd=%d", + (wait_flag == _PR_UNIX_POLL_READ) ? "read" : "write", + osfd)); + + if (timeout == PR_INTERVAL_NO_WAIT) return 0; + + pd.osfd = osfd; + pd.in_flags = wait_flag; + pd.out_flags = 0; + + rv = _PR_WaitForMultipleFDs(&pd, 1, timeout); + + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + } + return rv; +} + + +PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, + PRInt32 flags, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + +/* + * Many OS's (Solaris, Unixware) have a broken recv which won't read + * from socketpairs. As long as we don't use flags on socketpairs, this + * is a decent fix. - mikep + */ +#if defined(UNIXWARE) || defined(SOLARIS) || defined(NCR) + while ((rv = read(osfd,buf,amount)) == -1) { +#else + while ((rv = recv(osfd,buf,amount,flags)) == -1) { +#endif + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd,_PR_UNIX_POLL_READ,timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen)) == -1)) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +PRInt32 _MD_send(PRFileDesc *fd, const void *buf, PRInt32 amount, + PRInt32 flags, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#if defined(SOLARIS) + PRInt32 tmp_amount = amount; +#endif + + /* + * On pre-2.6 Solaris, send() is much slower than write(). + * On 2.6 and beyond, with in-kernel sockets, send() and + * write() are fairly equivalent in performance. + */ +#if defined(SOLARIS) + PR_ASSERT(0 == flags); + while ((rv = write(osfd,buf,tmp_amount)) == -1) { +#else + while ((rv = send(osfd,buf,amount,flags)) == -1) { +#endif + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE + * error on occasion. Try to write in smaller chunks to workaround + * this bug. + */ + if (err == ERANGE) { + if (tmp_amount > 1) { + tmp_amount = tmp_amount/2; /* half the bytes */ + continue; + } + } +#endif + break; + } + } + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next send() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (_PR_IS_NATIVE_THREAD(me)) { + if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) { + rv = -1; + goto done; + } + } else { + if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; + } + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_sendto( + PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) &addrCopy, addrlen)) == -1) { +#else + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { +#endif + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_writev( + PRFileDesc *fd, const PRIOVec *iov, + PRInt32 iov_size, PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 index, amount = 0; + PRInt32 osfd = fd->secret->md.osfd; + + /* + * Calculate the total number of bytes to be sent; needed for + * optimization later. + * We could avoid this if this number was passed in; but it is + * probably not a big deal because iov_size is usually small (less than + * 3) + */ + if (!fd->secret->nonblocking) { + for (index=0; indexsecret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + /* + * optimization; if bytes sent is less than "amount" call + * select before returning. This is because it is likely that + * the next writev() call will return EWOULDBLOCK. + */ + if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount) + && (timeout != PR_INTERVAL_NO_WAIT)) { + if (_PR_IS_NATIVE_THREAD(me)) { + if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) { + rv = -1; + goto done; + } + } else { + if (local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout) < 0) { + rv = -1; + goto done; + } + } + } + if (rv < 0) { + _PR_MD_MAP_WRITEV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + while ((rv = accept(osfd, (struct sockaddr *) addr, + (_PRSockLen_t *)addrlen)) == -1) { + err = _MD_ERRNO(); + if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == ECONNABORTED)) { + if (fd->secret->nonblocking) { + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) { + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_READ, timeout)) < 0) + goto done; + } else { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + goto done; + } + } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } +done: +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv != -1) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + return(rv); +} + +extern int _connect (int s, const struct sockaddr *name, int namelen); +PRInt32 _MD_connect( + PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 osfd = fd->secret->md.osfd; +#ifdef IRIX +extern PRInt32 _MD_irix_connect( + PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, PRIntervalTime timeout); +#endif +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; +#endif + + /* + * We initiate the connection setup by making a nonblocking connect() + * call. If the connect() call fails, there are two cases we handle + * specially: + * 1. The connect() call was interrupted by a signal. In this case + * we simply retry connect(). + * 2. The NSPR socket is nonblocking and connect() fails with + * EINPROGRESS. We first wait until the socket becomes writable. + * Then we try to find out whether the connection setup succeeded + * or failed. + */ + +retry: +#ifdef IRIX + if ((rv = _MD_irix_connect(osfd, addr, addrlen, timeout)) == -1) { +#else +#ifdef _PR_HAVE_SOCKADDR_LEN + if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) { +#else + if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { +#endif +#endif + err = _MD_ERRNO(); + + if (err == EINTR) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + goto retry; + } + + if (!fd->secret->nonblocking && (err == EINPROGRESS)) { + if (!_PR_IS_NATIVE_THREAD(me)) { + + if ((rv = local_io_wait(osfd, _PR_UNIX_POLL_WRITE, timeout)) < 0) + return -1; + } else { + /* + * socket_io_wait() may return -1 or 1. + */ + + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv == -1) { + return -1; + } + } + + PR_ASSERT(rv == 1); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + return 0; + } + + _PR_MD_MAP_CONNECT_ERROR(err); + } + + return rv; +} /* _MD_connect */ + +PRInt32 _MD_bind(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv, err; +#ifdef _PR_HAVE_SOCKADDR_LEN + PRNetAddr addrCopy; + + addrCopy = *addr; + ((struct sockaddr *) &addrCopy)->sa_len = addrlen; + ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family; + rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen); +#else + rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen); +#endif + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_BIND_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv, err; + + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_LISTEN_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how) +{ + PRInt32 rv, err; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SHUTDOWN_ERROR(err); + } + return(rv); +} + +PRInt32 _MD_socketpair(int af, int type, int flags, + PRInt32 *osfd) +{ + PRInt32 rv, err; + + rv = socketpair(af, type, flags, osfd); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SOCKETPAIR_ERROR(err); + } + return rv; +} + +PRStatus _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getsockname(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, + PRUint32 *addrlen) +{ + PRInt32 rv, err; + + rv = getpeername(fd->secret->md.osfd, + (struct sockaddr *) addr, (_PRSockLen_t *)addrlen); +#ifdef _PR_HAVE_SOCKADDR_LEN + if (rv == 0) { + /* ignore the sa_len field of struct sockaddr */ + if (addr) { + addr->raw.family = ((struct sockaddr *) addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETPEERNAME_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv, err; + + rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (_PRSockLen_t *)optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_GETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, + PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv, err; + + rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen); + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_SETSOCKOPT_ERROR(err); + } + return rv==0?PR_SUCCESS:PR_FAILURE; +} + +PRStatus _MD_set_fd_inheritable(PRFileDesc *fd, PRBool inheritable) +{ + int rv; + + rv = fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC); + if (-1 == rv) { + PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_init_fd_inheritable(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + /* By default, a Unix fd is not closed on exec. */ +#ifdef DEBUG + { + int flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(0 == flags); + } +#endif + fd->secret->inheritable = _PR_TRI_TRUE; + } +} + +/************************************************************************/ +#if !defined(_PR_USE_POLL) + +/* +** Scan through io queue and find any bad fd's that triggered the error +** from _MD_SELECT +*/ +static void FindBadFDs(void) +{ + PRCList *q; + PRThread *me = _MD_CURRENT_THREAD(); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); + q = (_PR_IOQ(me->cpu)).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + pds->out_flags = 0; + PR_ASSERT(osfd >= 0 || pds->in_flags == 0); + if (pds->in_flags == 0) { + continue; /* skip this fd */ + } + if (fcntl(osfd, F_GETFL, 0) == -1) { + /* Found a bad descriptor, remove it from the fd_sets. */ + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("file descriptor %d is bad", osfd)); + pds->out_flags = _PR_UNIX_POLL_NVAL; + notify = PR_TRUE; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + + if (notify) { + PRIntn pri; + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq + */ + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + + _PR_THREAD_LOCK(pq->thr); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = pq->thr->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } + } + _PR_THREAD_UNLOCK(pq->thr); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; + } +} +#endif /* !defined(_PR_USE_POLL) */ + +/************************************************************************/ + +/* +** Called by the scheduler when there is nothing to do. This means that +** all threads are blocked on some monitor somewhere. +** +** Note: this code doesn't release the scheduler lock. +*/ +/* +** Pause the current CPU. longjmp to the cpu's pause stack +** +** This must be called with the scheduler locked +*/ +void _MD_PauseCPU(PRIntervalTime ticks) +{ + PRThread *me = _MD_CURRENT_THREAD(); +#ifdef _PR_USE_POLL + int timeout; + struct pollfd *pollfds; /* an array of pollfd structures */ + struct pollfd *pollfdPtr; /* a pointer that steps through the array */ + unsigned long npollfds; /* number of pollfd structures in array */ + unsigned long pollfds_size; + int nfd; /* to hold the return value of poll() */ +#else + struct timeval timeout, *tvp; + fd_set r, w, e; + fd_set *rp, *wp, *ep; + PRInt32 max_osfd, nfd; +#endif /* _PR_USE_POLL */ + PRInt32 rv; + PRCList *q; + PRUint32 min_timeout; + sigset_t oldset; +#ifdef IRIX +extern sigset_t ints_off; +#endif + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + _PR_MD_IOQ_LOCK(); + +#ifdef _PR_USE_POLL + /* Build up the pollfd structure array to wait on */ + + /* Find out how many pollfd structures are needed */ + npollfds = _PR_IOQ_OSFD_CNT(me->cpu); + PR_ASSERT(npollfds >= 0); + + /* + * We use a pipe to wake up a native thread. An fd is needed + * for the pipe and we poll it for reading. + */ + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + npollfds++; +#ifdef IRIX + /* + * On Irix, a second pipe is used to cause the primordial cpu to + * wakeup and exit, when the process is exiting because of a call + * to exit/PR_ProcessExit. + */ + if (me->cpu->id == 0) { + npollfds++; + } +#endif + } + + /* + * if the cpu's pollfd array is not big enough, release it and allocate a new one + */ + if (npollfds > _PR_IOQ_POLLFDS_SIZE(me->cpu)) { + if (_PR_IOQ_POLLFDS(me->cpu) != NULL) + PR_DELETE(_PR_IOQ_POLLFDS(me->cpu)); + pollfds_size = PR_MAX(_PR_IOQ_MIN_POLLFDS_SIZE(me->cpu), npollfds); + pollfds = (struct pollfd *) PR_MALLOC(pollfds_size * sizeof(struct pollfd)); + _PR_IOQ_POLLFDS(me->cpu) = pollfds; + _PR_IOQ_POLLFDS_SIZE(me->cpu) = pollfds_size; + } else { + pollfds = _PR_IOQ_POLLFDS(me->cpu); + } + pollfdPtr = pollfds; + + /* + * If we need to poll the pipe for waking up a native thread, + * the pipe's fd is the first element in the pollfds array. + */ + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + pollfdPtr->fd = _pr_md_pipefd[0]; + pollfdPtr->events = POLLIN; + pollfdPtr++; +#ifdef IRIX + /* + * On Irix, the second element is the exit pipe + */ + if (me->cpu->id == 0) { + pollfdPtr->fd = _pr_irix_primoridal_cpu_fd[0]; + pollfdPtr->events = POLLIN; + pollfdPtr++; + } +#endif + } + + min_timeout = PR_INTERVAL_NO_TIMEOUT; + for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + + if (pq->timeout < min_timeout) { + min_timeout = pq->timeout; + } + for (; pds < epds; pds++, pollfdPtr++) { + /* + * Assert that the pollfdPtr pointer does not go + * beyond the end of the pollfds array + */ + PR_ASSERT(pollfdPtr < pollfds + npollfds); + pollfdPtr->fd = pds->osfd; + /* direct copy of poll flags */ + pollfdPtr->events = pds->in_flags; + } + } + _PR_IOQ_TIMEOUT(me->cpu) = min_timeout; +#else + /* + * assigment of fd_sets + */ + r = _PR_FD_READ_SET(me->cpu); + w = _PR_FD_WRITE_SET(me->cpu); + e = _PR_FD_EXCEPTION_SET(me->cpu); + + rp = &r; + wp = &w; + ep = &e; + + max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; + min_timeout = _PR_IOQ_TIMEOUT(me->cpu); +#endif /* _PR_USE_POLL */ + /* + ** Compute the minimum timeout value: make it the smaller of the + ** timeouts specified by the i/o pollers or the timeout of the first + ** sleeping thread. + */ + q = _PR_SLEEPQ(me->cpu).next; + + if (q != &_PR_SLEEPQ(me->cpu)) { + PRThread *t = _PR_THREAD_PTR(q); + + if (t->sleep < min_timeout) { + min_timeout = t->sleep; + } + } + if (min_timeout > ticks) { + min_timeout = ticks; + } + +#ifdef _PR_USE_POLL + if (min_timeout == PR_INTERVAL_NO_TIMEOUT) + timeout = -1; + else + timeout = PR_IntervalToMilliseconds(min_timeout); +#else + if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + timeout.tv_sec = PR_IntervalToSeconds(min_timeout); + timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) + % PR_USEC_PER_SEC; + tvp = &timeout; + } +#endif /* _PR_USE_POLL */ + + _PR_MD_IOQ_UNLOCK(); + _MD_CHECK_FOR_EXIT(); + /* + * check for i/o operations + */ +#ifndef _PR_NO_CLOCK_TIMER + /* + * Disable the clock interrupts while we are in select, if clock interrupts + * are enabled. Otherwise, when the select/poll calls are interrupted, the + * timer value starts ticking from zero again when the system call is restarted. + */ +#ifdef IRIX + /* + * SIGCHLD signal is used on Irix to detect he termination of an + * sproc by SIGSEGV, SIGBUS or SIGABRT signals when + * _nspr_terminate_on_error is set. + */ + if ((!_nspr_noclock) || (_nspr_terminate_on_error)) +#else + if (!_nspr_noclock) +#endif /* IRIX */ +#ifdef IRIX + sigprocmask(SIG_BLOCK, &ints_off, &oldset); +#else + PR_ASSERT(sigismember(&timer_set, SIGALRM)); + sigprocmask(SIG_BLOCK, &timer_set, &oldset); +#endif /* IRIX */ +#endif /* !_PR_NO_CLOCK_TIMER */ + +#ifndef _PR_USE_POLL + PR_ASSERT(FD_ISSET(_pr_md_pipefd[0],rp)); + nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); +#else + nfd = _MD_POLL(pollfds, npollfds, timeout); +#endif /* !_PR_USE_POLL */ + +#ifndef _PR_NO_CLOCK_TIMER +#ifdef IRIX + if ((!_nspr_noclock) || (_nspr_terminate_on_error)) +#else + if (!_nspr_noclock) +#endif /* IRIX */ + sigprocmask(SIG_SETMASK, &oldset, 0); +#endif /* !_PR_NO_CLOCK_TIMER */ + + _MD_CHECK_FOR_EXIT(); + +#ifdef IRIX + _PR_MD_primordial_cpu(); +#endif + + _PR_MD_IOQ_LOCK(); + /* + ** Notify monitors that are associated with the selected descriptors. + */ +#ifdef _PR_USE_POLL + if (nfd > 0) { + pollfdPtr = pollfds; + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + /* + * Assert that the pipe is the first element in the + * pollfds array. + */ + PR_ASSERT(pollfds[0].fd == _pr_md_pipefd[0]); + if ((pollfds[0].revents & POLLIN) && (nfd == 1)) { + /* + * woken up by another thread; read all the data + * in the pipe to empty the pipe + */ + while ((rv = read(_pr_md_pipefd[0], _pr_md_pipebuf, + PIPE_BUF)) == PIPE_BUF){ + } + PR_ASSERT((rv > 0) || ((rv == -1) && (errno == EAGAIN))); + } + pollfdPtr++; +#ifdef IRIX + /* + * On Irix, check to see if the primordial cpu needs to exit + * to cause the process to terminate + */ + if (me->cpu->id == 0) { + PR_ASSERT(pollfds[1].fd == _pr_irix_primoridal_cpu_fd[0]); + if (pollfdPtr->revents & POLLIN) { + if (_pr_irix_process_exit) { + /* + * process exit due to a call to PR_ProcessExit + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(_pr_irix_process_exit_code); + } else { + while ((rv = read(_pr_irix_primoridal_cpu_fd[0], + _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { + } + PR_ASSERT(rv > 0); + } + } + pollfdPtr++; + } +#endif + } + for (q = _PR_IOQ(me->cpu).next; q != &_PR_IOQ(me->cpu); q = q->next) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + + for (; pds < epds; pds++, pollfdPtr++) { + /* + * Assert that the pollfdPtr pointer does not go beyond + * the end of the pollfds array. + */ + PR_ASSERT(pollfdPtr < pollfds + npollfds); + /* + * Assert that the fd's in the pollfds array (stepped + * through by pollfdPtr) are in the same order as + * the fd's in _PR_IOQ() (stepped through by q and pds). + * This is how the pollfds array was created earlier. + */ + PR_ASSERT(pollfdPtr->fd == pds->osfd); + pds->out_flags = pollfdPtr->revents; + /* Negative fd's are ignored by poll() */ + if (pds->osfd >= 0 && pds->out_flags) { + notify = PR_TRUE; + } + } + if (notify) { + PRIntn pri; + PRThread *thred; + + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + thred = pq->thr; + _PR_THREAD_LOCK(thred); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = pq->thr->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (_pr_md_idle_cpus > 1) + _PR_MD_WAKEUP_WAITER(thred); + } + } + _PR_THREAD_UNLOCK(thred); + _PR_IOQ_OSFD_CNT(me->cpu) -= pq->npds; + PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); + } + } + } else if (nfd == -1) { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("poll() failed with errno %d", errno)); + } + +#else + if (nfd > 0) { + q = _PR_IOQ(me->cpu).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PRInt16 out_flags = 0; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if ((in_flags & _PR_UNIX_POLL_READ) && FD_ISSET(osfd, rp)) { + out_flags |= _PR_UNIX_POLL_READ; + } + if ((in_flags & _PR_UNIX_POLL_WRITE) && FD_ISSET(osfd, wp)) { + out_flags |= _PR_UNIX_POLL_WRITE; + } + if ((in_flags & _PR_UNIX_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { + out_flags |= _PR_UNIX_POLL_EXCEPT; + } + pds->out_flags = out_flags; + if (out_flags) { + notify = PR_TRUE; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + if (notify == PR_TRUE) { + PRIntn pri; + PRThread *thred; + + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq + */ + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + + /* + * Because this thread can run on a different cpu right + * after being added to the run queue, do not dereference + * pq + */ + thred = pq->thr; + _PR_THREAD_LOCK(thred); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = thred->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + if (pq->thr->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; + * a Resume operation on the thread + * will move it to the runQ + */ + pq->thr->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(pq->thr->cpu); + _PR_ADD_SUSPENDQ(pq->thr, pq->thr->cpu); + _PR_MISCQ_UNLOCK(pq->thr->cpu); + } else { + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + pq->thr->cpu = cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (_pr_md_idle_cpus > 1) + _PR_MD_WAKEUP_WAITER(thred); + } + } + _PR_THREAD_UNLOCK(thred); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if ((FD_ISSET(_pr_md_pipefd[0], rp)) && (nfd == 1)) { + /* + * woken up by another thread; read all the data + * in the pipe to empty the pipe + */ + while ((rv = + read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) + == PIPE_BUF){ + } + PR_ASSERT((rv > 0) || + ((rv == -1) && (errno == EAGAIN))); + } + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; +#ifdef IRIX + if ((me->cpu->id == 0) && + (FD_ISSET(_pr_irix_primoridal_cpu_fd[0], rp))) { + if (_pr_irix_process_exit) { + /* + * process exit due to a call to PR_ProcessExit + */ + prctl(PR_SETEXITSIG, SIGKILL); + _exit(_pr_irix_process_exit_code); + } else { + while ((rv = read(_pr_irix_primoridal_cpu_fd[0], + _pr_md_pipebuf, PIPE_BUF)) == PIPE_BUF) { + } + PR_ASSERT(rv > 0); + } + } + if (me->cpu->id == 0) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_irix_primoridal_cpu_fd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_irix_primoridal_cpu_fd[0]; + } +#endif + } + } else if (nfd < 0) { + if (errno == EBADF) { + FindBadFDs(); + } else { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", + errno)); + } + } else { + PR_ASSERT(nfd == 0); + /* + * compute the new value of _PR_IOQ_TIMEOUT + */ + q = _PR_IOQ(me->cpu).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + _PRUnixPollDesc *pds = pq->pds; + _PRUnixPollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + if (pds->osfd > pq_max_osfd) { + pq_max_osfd = pds->osfd; + } + } + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + if (_PR_IS_NATIVE_THREAD_SUPPORTED()) { + if (_PR_IOQ_MAX_OSFD(me->cpu) < _pr_md_pipefd[0]) + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; + } + } +#endif /* _PR_USE_POLL */ + _PR_MD_IOQ_UNLOCK(); +} + +void _MD_Wakeup_CPUs() +{ + PRInt32 rv, data; + + data = 0; + rv = write(_pr_md_pipefd[1], &data, 1); + + while ((rv < 0) && (errno == EAGAIN)) { + /* + * pipe full, read all data in pipe to empty it + */ + while ((rv = + read(_pr_md_pipefd[0], _pr_md_pipebuf, PIPE_BUF)) + == PIPE_BUF) { + } + PR_ASSERT((rv > 0) || + ((rv == -1) && (errno == EAGAIN))); + rv = write(_pr_md_pipefd[1], &data, 1); + } +} + + +void _MD_InitCPUS() +{ + PRInt32 rv, flags; + PRThread *me = _MD_CURRENT_THREAD(); + + rv = pipe(_pr_md_pipefd); + PR_ASSERT(rv == 0); + _PR_IOQ_MAX_OSFD(me->cpu) = _pr_md_pipefd[0]; +#ifndef _PR_USE_POLL + FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(me->cpu)); +#endif + + flags = fcntl(_pr_md_pipefd[0], F_GETFL, 0); + fcntl(_pr_md_pipefd[0], F_SETFL, flags | O_NONBLOCK); + flags = fcntl(_pr_md_pipefd[1], F_GETFL, 0); + fcntl(_pr_md_pipefd[1], F_SETFL, flags | O_NONBLOCK); +} + +/* +** Unix SIGALRM (clock) signal handler +*/ +static void ClockInterruptHandler() +{ + int olderrno; + PRUintn pri; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRThread *me = _MD_CURRENT_THREAD(); + +#ifdef SOLARIS + if (!me || _PR_IS_NATIVE_THREAD(me)) { + _pr_primordialCPU->u.missed[_pr_primordialCPU->where] |= _PR_MISSED_CLOCK; + return; + } +#endif + + if (_PR_MD_GET_INTSOFF() != 0) { + cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; + return; + } + _PR_MD_SET_INTSOFF(1); + + olderrno = errno; + _PR_ClockInterrupt(); + errno = olderrno; + + /* + ** If the interrupt wants a resched or if some other thread at + ** the same priority needs the cpu, reschedule. + */ + pri = me->priority; + if ((cpu->u.missed[3] || (_PR_RUNQREADYMASK(me->cpu) >> pri))) { +#ifdef _PR_NO_PREEMPT + cpu->resched = PR_TRUE; + if (pr_interruptSwitchHook) { + (*pr_interruptSwitchHook)(pr_interruptSwitchHookArg); + } +#else /* _PR_NO_PREEMPT */ + /* + ** Re-enable unix interrupts (so that we can use + ** setjmp/longjmp for context switching without having to + ** worry about the signal state) + */ + sigprocmask(SIG_SETMASK, &empty_set, 0); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock caused context switch")); + + if(!(me->flags & _PR_IDLE_THREAD)) { + _PR_THREAD_LOCK(me); + me->state = _PR_RUNNABLE; + me->cpu = cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(me); + } else + me->state = _PR_RUNNABLE; + _MD_SWITCH_CONTEXT(me); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("clock back from context switch")); +#endif /* _PR_NO_PREEMPT */ + } + /* + * Because this thread could be running on a different cpu after + * a context switch the current cpu should be accessed and the + * value of the 'cpu' variable should not be used. + */ + _PR_MD_SET_INTSOFF(0); +} + +/* + * On HP-UX 9, we have to use the sigvector() interface to restart + * interrupted system calls, because sigaction() does not have the + * SA_RESTART flag. + */ + +#ifdef HPUX9 +static void HPUX9_ClockInterruptHandler( + int sig, + int code, + struct sigcontext *scp) +{ + ClockInterruptHandler(); + scp->sc_syscall_action = SIG_RESTART; +} +#endif /* HPUX9 */ + +/* # of milliseconds per clock tick that we will use */ +#define MSEC_PER_TICK 50 + + +void _MD_StartInterrupts() +{ + char *eval; + + if ((eval = getenv("NSPR_NOCLOCK")) != NULL) { + if (atoi(eval) == 0) + _nspr_noclock = 0; + else + _nspr_noclock = 1; + } + +#ifndef _PR_NO_CLOCK_TIMER + if (!_nspr_noclock) { + _MD_EnableClockInterrupts(); + } +#endif +} + +void _MD_StopInterrupts() +{ + sigprocmask(SIG_BLOCK, &timer_set, 0); +} + +void _MD_EnableClockInterrupts() +{ + struct itimerval itval; + extern PRUintn _pr_numCPU; +#ifdef HPUX9 + struct sigvec vec; + + vec.sv_handler = (void (*)()) HPUX9_ClockInterruptHandler; + vec.sv_mask = 0; + vec.sv_flags = 0; + sigvector(SIGALRM, &vec, 0); +#else + struct sigaction vtact; + + vtact.sa_handler = (void (*)()) ClockInterruptHandler; + sigemptyset(&vtact.sa_mask); + vtact.sa_flags = SA_RESTART; + sigaction(SIGALRM, &vtact, 0); +#endif /* HPUX9 */ + + PR_ASSERT(_pr_numCPU == 1); + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_usec = MSEC_PER_TICK * PR_USEC_PER_MSEC; + itval.it_value = itval.it_interval; + setitimer(ITIMER_REAL, &itval, 0); +} + +void _MD_DisableClockInterrupts() +{ + struct itimerval itval; + extern PRUintn _pr_numCPU; + + PR_ASSERT(_pr_numCPU == 1); + itval.it_interval.tv_sec = 0; + itval.it_interval.tv_usec = 0; + itval.it_value = itval.it_interval; + setitimer(ITIMER_REAL, &itval, 0); +} + +void _MD_BlockClockInterrupts() +{ + sigprocmask(SIG_BLOCK, &timer_set, 0); +} + +void _MD_UnblockClockInterrupts() +{ + sigprocmask(SIG_UNBLOCK, &timer_set, 0); +} + +void _MD_MakeNonblock(PRFileDesc *fd) +{ + PRInt32 osfd = fd->secret->md.osfd; + int flags; + + if (osfd <= 2) { + /* Don't mess around with stdin, stdout or stderr */ + return; + } + flags = fcntl(osfd, F_GETFL, 0); + + /* + * Use O_NONBLOCK (POSIX-style non-blocking I/O) whenever possible. + * On SunOS 4, we must use FNDELAY (BSD-style non-blocking I/O), + * otherwise connect() still blocks and can be interrupted by SIGALRM. + */ + +#ifdef SUNOS4 + fcntl(osfd, F_SETFL, flags | FNDELAY); +#else + fcntl(osfd, F_SETFL, flags | O_NONBLOCK); +#endif + } + +PRInt32 _MD_open(const char *name, PRIntn flags, PRIntn mode) +{ + PRInt32 osflags; + PRInt32 rv, err; + + if (flags & PR_RDWR) { + osflags = O_RDWR; + } else if (flags & PR_WRONLY) { + osflags = O_WRONLY; + } else { + osflags = O_RDONLY; + } + + if (flags & PR_EXCL) + osflags |= O_EXCL; + if (flags & PR_APPEND) + osflags |= O_APPEND; + if (flags & PR_TRUNCATE) + osflags |= O_TRUNC; + if (flags & PR_SYNC) { +#if defined(O_SYNC) + osflags |= O_SYNC; +#elif defined(O_FSYNC) + osflags |= O_FSYNC; +#else +#error "Neither O_SYNC nor O_FSYNC is defined on this platform" +#endif + } + + /* + ** On creations we hold the 'create' lock in order to enforce + ** the semantics of PR_Rename. (see the latter for more details) + */ + if (flags & PR_CREATE_FILE) + { + osflags |= O_CREAT; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + rv = _md_iovector._open64(name, osflags, mode); + + if (rv < 0) { + err = _MD_ERRNO(); + _PR_MD_MAP_OPEN_ERROR(err); + } + + if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) + PR_Unlock(_pr_rename_lock); + return rv; +} + +PRIntervalTime intr_timeout_ticks; + +#if defined(SOLARIS) || defined(IRIX) +static void sigsegvhandler() { + fprintf(stderr,"Received SIGSEGV\n"); + fflush(stderr); + pause(); +} + +static void sigaborthandler() { + fprintf(stderr,"Received SIGABRT\n"); + fflush(stderr); + pause(); +} + +static void sigbushandler() { + fprintf(stderr,"Received SIGBUS\n"); + fflush(stderr); + pause(); +} +#endif /* SOLARIS, IRIX */ + +#endif /* !defined(_PR_PTHREADS) */ + +void _MD_query_fd_inheritable(PRFileDesc *fd) +{ + int flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + flags = fcntl(fd->secret->md.osfd, F_GETFD, 0); + PR_ASSERT(-1 != flags); + fd->secret->inheritable = (flags & FD_CLOEXEC) ? + _PR_TRI_FALSE : _PR_TRI_TRUE; +} + +PROffset32 _MD_lseek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + PROffset32 rv, where; + + switch (whence) { + case PR_SEEK_SET: + where = SEEK_SET; + break; + case PR_SEEK_CUR: + where = SEEK_CUR; + break; + case PR_SEEK_END: + where = SEEK_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = -1; + goto done; + } + rv = lseek(fd->secret->md.osfd,offset,where); + if (rv == -1) + { + PRInt32 syserr = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(syserr); + } +done: + return(rv); +} + +PROffset64 _MD_lseek64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + PRInt32 where; + PROffset64 rv; + + switch (whence) + { + case PR_SEEK_SET: + where = SEEK_SET; + break; + case PR_SEEK_CUR: + where = SEEK_CUR; + break; + case PR_SEEK_END: + where = SEEK_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = minus_one; + goto done; + } + rv = _md_iovector._lseek64(fd->secret->md.osfd, offset, where); + if (LL_EQ(rv, minus_one)) + { + PRInt32 syserr = _MD_ERRNO(); + _PR_MD_MAP_LSEEK_ERROR(syserr); + } +done: + return rv; +} /* _MD_lseek64 */ + +/* +** _MD_set_fileinfo_times -- +** Set the modifyTime and creationTime of the PRFileInfo +** structure using the values in struct stat. +** +** _MD_set_fileinfo64_times -- +** Set the modifyTime and creationTime of the PRFileInfo64 +** structure using the values in _MDStat64. +*/ + +#if defined(_PR_STAT_HAS_ST_ATIM) +/* +** struct stat has st_atim, st_mtim, and st_ctim fields of +** type timestruc_t. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#elif defined(_PR_STAT_HAS_ST_ATIM_UNION) +/* +** The st_atim, st_mtim, and st_ctim fields in struct stat are +** unions with a st__tim union member of type timestruc_t. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtim.st__tim.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtim.st__tim.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctim.st__tim.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctim.st__tim.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#elif defined(_PR_STAT_HAS_ST_ATIMESPEC) +/* +** struct stat has st_atimespec, st_mtimespec, and st_ctimespec +** fields of type struct timespec. +*/ +#if defined(_PR_TIMESPEC_HAS_TS_SEC) +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.ts_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.ts_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.ts_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.ts_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#else /* _PR_TIMESPEC_HAS_TS_SEC */ +/* +** The POSIX timespec structure has tv_sec and tv_nsec. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 us, s2us; + + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(info->modifyTime, sb->st_mtimespec.tv_sec); + LL_MUL(info->modifyTime, info->modifyTime, s2us); + LL_I2L(us, sb->st_mtimespec.tv_nsec / 1000); + LL_ADD(info->modifyTime, info->modifyTime, us); + LL_I2L(info->creationTime, sb->st_ctimespec.tv_sec); + LL_MUL(info->creationTime, info->creationTime, s2us); + LL_I2L(us, sb->st_ctimespec.tv_nsec / 1000); + LL_ADD(info->creationTime, info->creationTime, us); +} +#endif /* _PR_TIMESPEC_HAS_TS_SEC */ +#elif defined(_PR_STAT_HAS_ONLY_ST_ATIME) +/* +** struct stat only has st_atime, st_mtime, and st_ctime fields +** of type time_t. +*/ +static void _MD_set_fileinfo_times( + const struct stat *sb, + PRFileInfo *info) +{ + PRInt64 s, s2us; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, sb->st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb->st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; +} + +static void _MD_set_fileinfo64_times( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + PRInt64 s, s2us; + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, sb->st_mtime); + LL_MUL(s, s, s2us); + info->modifyTime = s; + LL_I2L(s, sb->st_ctime); + LL_MUL(s, s, s2us); + info->creationTime = s; +} +#else +#error "I don't know yet" +#endif + +static int _MD_convert_stat_to_fileinfo( + const struct stat *sb, + PRFileInfo *info) +{ + if (S_IFREG & sb->st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb->st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + +#if defined(_PR_HAVE_LARGE_OFF_T) + if (0x7fffffffL < sb->st_size) + { + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + return -1; + } +#endif /* defined(_PR_HAVE_LARGE_OFF_T) */ + info->size = sb->st_size; + + _MD_set_fileinfo_times(sb, info); + return 0; +} /* _MD_convert_stat_to_fileinfo */ + +static int _MD_convert_stat64_to_fileinfo64( + const _MDStat64 *sb, + PRFileInfo64 *info) +{ + if (S_IFREG & sb->st_mode) + info->type = PR_FILE_FILE; + else if (S_IFDIR & sb->st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + + LL_I2L(info->size, sb->st_size); + + _MD_set_fileinfo64_times(sb, info); + return 0; +} /* _MD_convert_stat64_to_fileinfo64 */ + +PRInt32 _MD_getfileinfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv; + struct stat sb; + + rv = stat(fn, &sb); + if (rv < 0) + _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat_to_fileinfo(&sb, info); + return rv; +} + +PRInt32 _MD_getfileinfo64(const char *fn, PRFileInfo64 *info) +{ + _MDStat64 sb; + PRInt32 rv = _md_iovector._stat64(fn, &sb); + if (rv < 0) + _PR_MD_MAP_STAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat64_to_fileinfo64(&sb, info); + return rv; +} + +PRInt32 _MD_getopenfileinfo(const PRFileDesc *fd, PRFileInfo *info) +{ + struct stat sb; + PRInt32 rv = fstat(fd->secret->md.osfd, &sb); + if (rv < 0) + _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat_to_fileinfo(&sb, info); + return rv; +} + +PRInt32 _MD_getopenfileinfo64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + _MDStat64 sb; + PRInt32 rv = _md_iovector._fstat64(fd->secret->md.osfd, &sb); + if (rv < 0) + _PR_MD_MAP_FSTAT_ERROR(_MD_ERRNO()); + else if (NULL != info) + rv = _MD_convert_stat64_to_fileinfo64(&sb, info); + return rv; +} + +struct _MD_IOVector _md_iovector = { open }; + +/* +** These implementations are to emulate large file routines on systems that +** don't have them. Their goal is to check in case overflow occurs. Otherwise +** they will just operate as normal using 32-bit file routines. +** +** The checking might be pre- or post-op, depending on the semantics. +*/ + +#if defined(SOLARIS2_5) + +static PRIntn _MD_solaris25_fstat64(PRIntn osfd, _MDStat64 *buf) +{ + PRInt32 rv; + struct stat sb; + + rv = fstat(osfd, &sb); + if (rv >= 0) + { + /* + ** I'm only copying the fields that are immediately needed. + ** If somebody else calls this function, some of the fields + ** may not be defined. + */ + (void)memset(buf, 0, sizeof(_MDStat64)); + buf->st_mode = sb.st_mode; + buf->st_ctim = sb.st_ctim; + buf->st_mtim = sb.st_mtim; + buf->st_size = sb.st_size; + } + return rv; +} /* _MD_solaris25_fstat64 */ + +static PRIntn _MD_solaris25_stat64(const char *fn, _MDStat64 *buf) +{ + PRInt32 rv; + struct stat sb; + + rv = stat(fn, &sb); + if (rv >= 0) + { + /* + ** I'm only copying the fields that are immediately needed. + ** If somebody else calls this function, some of the fields + ** may not be defined. + */ + (void)memset(buf, 0, sizeof(_MDStat64)); + buf->st_mode = sb.st_mode; + buf->st_ctim = sb.st_ctim; + buf->st_mtim = sb.st_mtim; + buf->st_size = sb.st_size; + } + return rv; +} /* _MD_solaris25_stat64 */ +#endif /* defined(SOLARIS2_5) */ + +#if defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) + +static PROffset64 _MD_Unix_lseek64(PRIntn osfd, PROffset64 offset, PRIntn whence) +{ + PRUint64 maxoff; + PROffset64 rv = minus_one; + LL_I2L(maxoff, 0x7fffffff); + if (LL_CMP(offset, <=, maxoff)) + { + off_t off; + LL_L2I(off, offset); + LL_I2L(rv, lseek(osfd, off, whence)); + } + else errno = EFBIG; /* we can't go there */ + return rv; +} /* _MD_Unix_lseek64 */ + +static void* _MD_Unix_mmap64( + void *addr, PRSize len, PRIntn prot, PRIntn flags, + PRIntn fildes, PRInt64 offset) +{ + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + return NULL; +} /* _MD_Unix_mmap64 */ +#endif /* defined(_PR_NO_LARGE_FILES) || defined(SOLARIS2_5) */ + +#if defined(OSF1) && defined(__GNUC__) + +/* + * On OSF1 V5.0A, defines stat and fstat as + * macros when compiled under gcc, so it is rather tricky to + * take the addresses of the real functions the macros expend + * to. A simple solution is to define forwarder functions + * and take the addresses of the forwarder functions instead. + */ + +static int stat_forwarder(const char *path, struct stat *buffer) +{ + return stat(path, buffer); +} + +static int fstat_forwarder(int filedes, struct stat *buffer) +{ + return fstat(filedes, buffer); +} + +#endif + +static void _PR_InitIOV(void) +{ +#if defined(SOLARIS2_5) + PRLibrary *lib; + void *open64_func; + + open64_func = PR_FindSymbolAndLibrary("open64", &lib); + if (NULL != open64_func) + { + PR_ASSERT(NULL != lib); + _md_iovector._open64 = (_MD_Open64)open64_func; + _md_iovector._mmap64 = (_MD_Mmap64)PR_FindSymbol(lib, "mmap64"); + _md_iovector._fstat64 = (_MD_Fstat64)PR_FindSymbol(lib, "fstat64"); + _md_iovector._stat64 = (_MD_Stat64)PR_FindSymbol(lib, "stat64"); + _md_iovector._lseek64 = (_MD_Lseek64)PR_FindSymbol(lib, "lseek64"); + (void)PR_UnloadLibrary(lib); + } + else + { + _md_iovector._open64 = open; + _md_iovector._mmap64 = _MD_Unix_mmap64; + _md_iovector._fstat64 = _MD_solaris25_fstat64; + _md_iovector._stat64 = _MD_solaris25_stat64; + _md_iovector._lseek64 = _MD_Unix_lseek64; + } +#elif defined(_PR_NO_LARGE_FILES) + _md_iovector._open64 = open; + _md_iovector._mmap64 = _MD_Unix_mmap64; + _md_iovector._fstat64 = fstat; + _md_iovector._stat64 = stat; + _md_iovector._lseek64 = _MD_Unix_lseek64; +#elif defined(_PR_HAVE_OFF64_T) +#if defined(IRIX5_3) + _md_iovector._open64 = open; +#else + _md_iovector._open64 = open64; +#endif + _md_iovector._mmap64 = mmap64; + _md_iovector._fstat64 = fstat64; + _md_iovector._stat64 = stat64; + _md_iovector._lseek64 = lseek64; +#elif defined(_PR_HAVE_LARGE_OFF_T) + _md_iovector._open64 = open; + _md_iovector._mmap64 = mmap; +#if defined(OSF1) && defined(__GNUC__) + _md_iovector._fstat64 = fstat_forwarder; + _md_iovector._stat64 = stat_forwarder; +#else + _md_iovector._fstat64 = fstat; + _md_iovector._stat64 = stat; +#endif + _md_iovector._lseek64 = lseek; +#else +#error "I don't know yet" +#endif + LL_I2L(minus_one, -1); +} /* _PR_InitIOV */ + +void _PR_UnixInit(void) +{ + struct sigaction sigact; + int rv; + + sigemptyset(&timer_set); + +#if !defined(_PR_PTHREADS) + + sigaddset(&timer_set, SIGALRM); + sigemptyset(&empty_set); + intr_timeout_ticks = + PR_SecondsToInterval(_PR_INTERRUPT_CHECK_INTERVAL_SECS); + +#if defined(SOLARIS) || defined(IRIX) + + if (getenv("NSPR_SIGSEGV_HANDLE")) { + sigact.sa_handler = sigsegvhandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGSEGV, &sigact, 0); + } + + if (getenv("NSPR_SIGABRT_HANDLE")) { + sigact.sa_handler = sigaborthandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGABRT, &sigact, 0); + } + + if (getenv("NSPR_SIGBUS_HANDLE")) { + sigact.sa_handler = sigbushandler; + sigact.sa_flags = 0; + sigact.sa_mask = timer_set; + sigaction(SIGBUS, &sigact, 0); + } + +#endif +#endif /* !defined(_PR_PTHREADS) */ + + /* + * Under HP-UX DCE threads, sigaction() installs a per-thread + * handler, so we use sigvector() to install a process-wide + * handler. + */ +#if defined(HPUX) && defined(_PR_DCETHREADS) + { + struct sigvec vec; + + vec.sv_handler = SIG_IGN; + vec.sv_mask = 0; + vec.sv_flags = 0; + rv = sigvector(SIGPIPE, &vec, NULL); + PR_ASSERT(0 == rv); + } +#else + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + rv = sigaction(SIGPIPE, &sigact, 0); + PR_ASSERT(0 == rv); +#endif /* HPUX && _PR_DCETHREADS */ + + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + _pr_Xfe_mon = PR_NewMonitor(); + PR_ASSERT(NULL != _pr_Xfe_mon); +#ifdef VBOX + RTMEM_MAY_LEAK(_pr_rename_lock); + RTMEM_MAY_LEAK(_pr_Xfe_mon); +#endif + + _PR_InitIOV(); /* one last hack */ +} + +#if !defined(_PR_PTHREADS) + +/* + * Variables used by the GC code, initialized in _MD_InitSegs(). + */ +static PRInt32 _pr_zero_fd = -1; +static PRLock *_pr_md_lock = NULL; + +/* + * _MD_InitSegs -- + * + * This is Unix's version of _PR_MD_INIT_SEGS(), which is + * called by _PR_InitSegs(), which in turn is called by + * PR_Init(). + */ +void _MD_InitSegs(void) +{ +#ifdef DEBUG + /* + ** Disable using mmap(2) if NSPR_NO_MMAP is set + */ + if (getenv("NSPR_NO_MMAP")) { + _pr_zero_fd = -2; + return; + } +#endif + _pr_zero_fd = open("/dev/zero",O_RDWR , 0); + /* Prevent the fd from being inherited by child processes */ + fcntl(_pr_zero_fd, F_SETFD, FD_CLOEXEC); + _pr_md_lock = PR_NewLock(); +} + +PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr) +{ + static char *lastaddr = (char*) _PR_STACK_VMBASE; + PRStatus retval = PR_SUCCESS; + int prot; + void *rv; + + PR_ASSERT(seg != 0); + PR_ASSERT(size != 0); + + PR_Lock(_pr_md_lock); + if (_pr_zero_fd < 0) { +from_heap: + seg->vaddr = PR_MALLOC(size); + if (!seg->vaddr) { + retval = PR_FAILURE; + } + else { + seg->size = size; + } + goto exit; + } + + prot = PROT_READ|PROT_WRITE; + /* + * On Alpha Linux, the user-level thread stack needs + * to be made executable because longjmp/signal seem + * to put machine instructions on the stack. + */ +#if defined(LINUX) && defined(__alpha) + prot |= PROT_EXEC; +#endif + rv = mmap((vaddr != 0) ? vaddr : lastaddr, size, prot, + _MD_MMAP_FLAGS, + _pr_zero_fd, 0); + if (rv == (void*)-1) { + goto from_heap; + } + lastaddr += size; + seg->vaddr = rv; + seg->size = size; + seg->flags = _PR_SEG_VM; + +exit: + PR_Unlock(_pr_md_lock); + return retval; +} + +void _MD_FreeSegment(PRSegment *seg) +{ + if (seg->flags & _PR_SEG_VM) + (void) munmap(seg->vaddr, seg->size); + else + PR_DELETE(seg->vaddr); +} + +#endif /* _PR_PTHREADS */ + +/* + *----------------------------------------------------------------------- + * + * 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 Unix + * implementation. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + struct timeval tv; + PRInt64 s, us, s2us; + + GETTIMEOFDAY(&tv); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, tv.tv_sec); + LL_I2L(us, tv.tv_usec); + LL_MUL(s, s, s2us); + LL_ADD(s, s, us); + return s; +} + +PRIntervalTime _PR_UNIX_GetInterval() +{ + struct timeval time; + PRIntervalTime ticks; + + (void)GETTIMEOFDAY(&time); /* fallicy of course */ + ticks = (PRUint32)time.tv_sec * PR_MSEC_PER_SEC; /* that's in milliseconds */ + ticks += (PRUint32)time.tv_usec / PR_USEC_PER_MSEC; /* so's that */ + return ticks; +} /* _PR_SUNOS_GetInterval */ + +PRIntervalTime _PR_UNIX_TicksPerSecond() +{ + return 1000; /* this needs some work :) */ +} + +#if !defined(_PR_PTHREADS) +/* + * Wait for I/O on multiple descriptors. + * + * Return 0 if timed out, return -1 if interrupted, + * else return the number of ready descriptors. + */ +PRInt32 _PR_WaitForMultipleFDs( + _PRUnixPollDesc *unixpds, + PRInt32 pdcnt, + PRIntervalTime timeout) +{ + PRPollQueue pq; + PRIntn is; + PRInt32 rv; + _PRCPU *io_cpu; + _PRUnixPollDesc *unixpd, *eunixpd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + pq.pds = unixpds; + pq.npds = pdcnt; + + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + _PR_THREAD_LOCK(me); + + pq.thr = me; + io_cpu = me->cpu; + pq.on_ioq = PR_TRUE; + pq.timeout = timeout; + _PR_ADD_TO_IOQ(pq, me->cpu); + +#if !defined(_PR_USE_POLL) + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + PRInt32 osfd = unixpd->osfd; + if (unixpd->in_flags & _PR_UNIX_POLL_READ) { + FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); + _PR_FD_READ_CNT(me->cpu)[osfd]++; + } + if (unixpd->in_flags & _PR_UNIX_POLL_WRITE) { + FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); + (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; + } + if (unixpd->in_flags & _PR_UNIX_POLL_EXCEPT) { + FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; + } + if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) { + _PR_IOQ_MAX_OSFD(me->cpu) = osfd; + } + } +#endif /* !defined(_PR_USE_POLL) */ + + if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) { + _PR_IOQ_TIMEOUT(me->cpu) = timeout; + } + + _PR_IOQ_OSFD_CNT(me->cpu) += pdcnt; + + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, timeout); + me->state = _PR_IO_WAIT; + me->io_pending = PR_TRUE; + me->io_suspended = PR_FALSE; + _PR_SLEEPQ_UNLOCK(me->cpu); + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + + _PR_MD_WAIT(me, timeout); + + me->io_pending = PR_FALSE; + me->io_suspended = PR_FALSE; + + /* + * This thread should run on the same cpu on which it was blocked; when + * the IO request times out the fd sets and fd counts for the + * cpu are updated below. + */ + PR_ASSERT(me->cpu == io_cpu); + + /* + ** If we timed out the pollq might still be on the ioq. Remove it + ** before continuing. + */ + if (pq.on_ioq) { + _PR_MD_IOQ_LOCK(); + /* + * Need to check pq.on_ioq again + */ + if (pq.on_ioq) { + PR_REMOVE_LINK(&pq.links); +#ifndef _PR_USE_POLL + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + PRInt32 osfd = unixpd->osfd; + PRInt16 in_flags = unixpd->in_flags; + + if (in_flags & _PR_UNIX_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & _PR_UNIX_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } +#endif /* _PR_USE_POLL */ + PR_ASSERT(pq.npds == pdcnt); + _PR_IOQ_OSFD_CNT(me->cpu) -= pdcnt; + PR_ASSERT(_PR_IOQ_OSFD_CNT(me->cpu) >= 0); + } + _PR_MD_IOQ_UNLOCK(); + } + /* XXX Should we use _PR_FAST_INTSON or _PR_INTSON? */ + if (1 == pdcnt) { + _PR_FAST_INTSON(is); + } else { + _PR_INTSON(is); + } + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + rv = 0; + if (pq.on_ioq == PR_FALSE) { + /* Count the number of ready descriptors */ + while (--pdcnt >= 0) { + if (unixpds->out_flags != 0) { + rv++; + } + unixpds++; + } + } + + return rv; +} + +/* + * Unblock threads waiting for I/O + * used when interrupting threads + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + int pri = thr->priority; + _PRCPU *cpu = thr->cpu; + + /* + * GLOBAL threads wakeup periodically to check for interrupt + */ + if (_PR_IS_NATIVE_THREAD(thr)) { + _PR_THREAD_UNLOCK(thr); + return; + } + + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + thr->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thr); + _PR_MD_WAKEUP_WAITER(thr); +} +#endif /* !defined(_PR_PTHREADS) */ + +/* + * When a nonblocking connect has completed, determine whether it + * succeeded or failed, and if it failed, what the error code is. + * + * The function returns the error code. An error code of 0 means + * that the nonblocking connect succeeded. + */ + +int _MD_unix_get_nonblocking_connect_error(int osfd) +{ +#if defined(NTO) + /* Neutrino does not support the SO_ERROR socket option */ + PRInt32 rv; + PRNetAddr addr; + _PRSockLen_t addrlen = sizeof(addr); + + /* Test to see if we are using the Tiny TCP/IP Stack or the Full one. */ + struct statvfs superblock; + rv = fstatvfs(osfd, &superblock); + if (rv == 0) { + if (strcmp(superblock.f_basetype, "ttcpip") == 0) { + /* Using the Tiny Stack! */ + rv = getpeername(osfd, (struct sockaddr *) &addr, + (_PRSockLen_t *) &addrlen); + if (rv == -1) { + int errno_copy = errno; /* make a copy so I don't + * accidentally reset */ + + if (errno_copy == ENOTCONN) { + struct stat StatInfo; + rv = fstat(osfd, &StatInfo); + if (rv == 0) { + time_t current_time = time(NULL); + + /* + * this is a real hack, can't explain why it + * works it just does + */ + if (abs(current_time - StatInfo.st_atime) < 5) { + return ECONNREFUSED; + } else { + return ETIMEDOUT; + } + } else { + return ECONNREFUSED; + } + } else { + return errno_copy; + } + } else { + /* No Error */ + return 0; + } + } else { + /* Have the FULL Stack which supports SO_ERROR */ + /* Hasn't been written yet, never been tested! */ + /* Jerry.Kirk@Nexwarecorp.com */ + + int err; + _PRSockLen_t optlen = sizeof(err); + + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &optlen) == -1) { + return errno; + } else { + return err; + } + } + } else { + return ECONNREFUSED; + } +#elif defined(NCR) || defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * getsockopt() fails with EPIPE, so use getmsg() instead. + */ + + int rv; + int flags = 0; + rv = getmsg(osfd, NULL, NULL, &flags); + PR_ASSERT(-1 == rv || 0 == rv); + if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) { + return errno; + } + return 0; /* no error */ +#else + int err; + _PRSockLen_t optlen = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) { + return errno; + } else { + return err; + } +#endif +} + +/************************************************************************/ + +/* +** Special hacks for xlib. Xlib/Xt/Xm is not re-entrant nor is it thread +** safe. Unfortunately, neither is mozilla. To make these programs work +** in a pre-emptive threaded environment, we need to use a lock. +*/ + +void PR_XLock(void) +{ + PR_EnterMonitor(_pr_Xfe_mon); +} + +void PR_XUnlock(void) +{ + PR_ExitMonitor(_pr_Xfe_mon); +} + +PRBool PR_XIsLocked(void) +{ + return (PR_InMonitor(_pr_Xfe_mon)) ? PR_TRUE : PR_FALSE; +} + +void PR_XWait(int ms) +{ + PR_Wait(_pr_Xfe_mon, PR_MillisecondsToInterval(ms)); +} + +void PR_XNotify(void) +{ + PR_Notify(_pr_Xfe_mon); +} + +void PR_XNotifyAll(void) +{ + PR_NotifyAll(_pr_Xfe_mon); +} + +#if defined(HAVE_FCNTL_FILE_LOCKING) + +PR_IMPLEMENT(PRStatus) +_MD_LockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_WRLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLKW, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_TLockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_WRLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLK, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_UnlockFile(PRInt32 f) +{ + PRInt32 rv; + struct flock arg; + + arg.l_type = F_UNLCK; + arg.l_whence = SEEK_SET; + arg.l_start = 0; + arg.l_len = 0; /* until EOF */ + rv = fcntl(f, F_SETLK, &arg); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +#elif defined(HAVE_BSD_FLOCK) + +#include + +PR_IMPLEMENT(PRStatus) +_MD_LockFile(PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_EX); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_TLockFile(PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_EX|LOCK_NB); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_UnlockFile(PRInt32 f) +{ + PRInt32 rv; + rv = flock(f, LOCK_UN); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_FLOCK_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} +#else + +PR_IMPLEMENT(PRStatus) +_MD_LockFile(PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_LOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_TLockFile(PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_TLOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) +_MD_UnlockFile(PRInt32 f) +{ + PRInt32 rv; + rv = lockf(f, F_ULOCK, 0); + if (rv == 0) + return PR_SUCCESS; + _PR_MD_MAP_LOCKF_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} +#endif + +PR_IMPLEMENT(PRStatus) _MD_gethostname(char *name, PRUint32 namelen) +{ + PRIntn rv; + + rv = gethostname(name, namelen); + if (0 == rv) { + return PR_SUCCESS; + } + _PR_MD_MAP_GETHOSTNAME_ERROR(_MD_ERRNO()); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) _MD_getsysinfo(PRSysInfo cmd, char *name, PRUint32 namelen) +{ + struct utsname info; + + PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); + + if (uname(&info) == -1) { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, info.sysname); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, info.release); + else + return PR_FAILURE; + return PR_SUCCESS; +} + +/* + ******************************************************************* + * + * Memory-mapped files + * + ******************************************************************* + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + PRFileInfo info; + PRUint32 sz; + + LL_L2UI(sz, size); + if (sz) { + if (PR_GetOpenFileInfo(fmap->fd, &info) == PR_FAILURE) { + return PR_FAILURE; + } + if (sz > info.size) { + /* + * Need to extend the file + */ + if (fmap->prot != PR_PROT_READWRITE) { + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); + return PR_FAILURE; + } + if (PR_Seek(fmap->fd, sz - 1, PR_SEEK_SET) == -1) { + return PR_FAILURE; + } + if (PR_Write(fmap->fd, "", 1) != 1) { + return PR_FAILURE; + } + } + } + if (fmap->prot == PR_PROT_READONLY) { + fmap->md.prot = PROT_READ; +#ifdef OSF1V4_MAP_PRIVATE_BUG + /* + * Use MAP_SHARED to work around a bug in OSF1 V4.0D + * (QAR 70220 in the OSF_QAR database) that results in + * corrupted data in the memory-mapped region. This + * bug is fixed in V5.0. + */ + fmap->md.flags = MAP_SHARED; +#else + fmap->md.flags = MAP_PRIVATE; +#endif + } else if (fmap->prot == PR_PROT_READWRITE) { + fmap->md.prot = PROT_READ | PROT_WRITE; + fmap->md.flags = MAP_SHARED; + } else { + PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); + fmap->md.prot = PROT_READ | PROT_WRITE; + fmap->md.flags = MAP_PRIVATE; + } + return PR_SUCCESS; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PRInt64 offset, + PRUint32 len) +{ + PRInt32 off; + void *addr; + + LL_L2I(off, offset); + if ((addr = mmap(0, len, fmap->md.prot, fmap->md.flags, + fmap->fd->secret->md.osfd, off)) == (void *) -1) { + _PR_MD_MAP_MMAP_ERROR(_MD_ERRNO()); + addr = NULL; + } + return addr; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + if (munmap(addr, len) == 0) { + return PR_SUCCESS; + } else { + if (errno == EINVAL) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, errno); + } else { + PR_SetError(PR_UNKNOWN_ERROR, errno); + } + return PR_FAILURE; + } +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + if ( PR_TRUE == fmap->md.isAnonFM ) { + PRStatus rc = PR_Close( fmap->fd ); + if ( PR_FAILURE == rc ) { + PR_LOG( _pr_io_lm, PR_LOG_DEBUG, + ("_MD_CloseFileMap(): error closing anonymnous file map osfd")); + return PR_FAILURE; + } + } + PR_DELETE(fmap); + return PR_SUCCESS; +} + +#if defined(_PR_NEED_FAKE_POLL) + +/* + * Some platforms don't have poll(). For easier porting of code + * that calls poll(), we emulate poll() using select(). + */ + +int poll(struct pollfd *filedes, unsigned long nfds, int timeout) +{ + int i; + int rv; + int maxfd; + fd_set rd, wr, ex; + struct timeval tv, *tvp; + + if (timeout < 0 && timeout != -1) { + errno = EINVAL; + return -1; + } + + if (timeout == -1) { + tvp = NULL; + } else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tvp = &tv; + } + + maxfd = -1; + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + for (i = 0; i < nfds; i++) { + int osfd = filedes[i].fd; + int events = filedes[i].events; + PRBool fdHasEvent = PR_FALSE; + + if (osfd < 0) { + continue; /* Skip this osfd. */ + } + + /* + * Map the poll events to the select fd_sets. + * POLLIN, POLLRDNORM ===> readable + * POLLOUT, POLLWRNORM ===> writable + * POLLPRI, POLLRDBAND ===> exception + * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) + * are ignored. + * + * The output events POLLERR and POLLHUP are never turned on. + * POLLNVAL may be turned on. + */ + + if (events & (POLLIN | POLLRDNORM)) { + FD_SET(osfd, &rd); + fdHasEvent = PR_TRUE; + } + if (events & (POLLOUT | POLLWRNORM)) { + FD_SET(osfd, &wr); + fdHasEvent = PR_TRUE; + } + if (events & (POLLPRI | POLLRDBAND)) { + FD_SET(osfd, &ex); + fdHasEvent = PR_TRUE; + } + if (fdHasEvent && osfd > maxfd) { + maxfd = osfd; + } + } + + rv = select(maxfd + 1, &rd, &wr, &ex, tvp); + + /* Compute poll results */ + if (rv > 0) { + rv = 0; + for (i = 0; i < nfds; i++) { + PRBool fdHasEvent = PR_FALSE; + + filedes[i].revents = 0; + if (filedes[i].fd < 0) { + continue; + } + if (FD_ISSET(filedes[i].fd, &rd)) { + if (filedes[i].events & POLLIN) { + filedes[i].revents |= POLLIN; + } + if (filedes[i].events & POLLRDNORM) { + filedes[i].revents |= POLLRDNORM; + } + fdHasEvent = PR_TRUE; + } + if (FD_ISSET(filedes[i].fd, &wr)) { + if (filedes[i].events & POLLOUT) { + filedes[i].revents |= POLLOUT; + } + if (filedes[i].events & POLLWRNORM) { + filedes[i].revents |= POLLWRNORM; + } + fdHasEvent = PR_TRUE; + } + if (FD_ISSET(filedes[i].fd, &ex)) { + if (filedes[i].events & POLLPRI) { + filedes[i].revents |= POLLPRI; + } + if (filedes[i].events & POLLRDBAND) { + filedes[i].revents |= POLLRDBAND; + } + fdHasEvent = PR_TRUE; + } + if (fdHasEvent) { + rv++; + } + } + PR_ASSERT(rv > 0); + } else if (rv == -1 && errno == EBADF) { + rv = 0; + for (i = 0; i < nfds; i++) { + filedes[i].revents = 0; + if (filedes[i].fd < 0) { + continue; + } + if (fcntl(filedes[i].fd, F_GETFL, 0) == -1) { + filedes[i].revents = POLLNVAL; + rv++; + } + } + PR_ASSERT(rv > 0); + } + PR_ASSERT(-1 != timeout || rv != 0); + + return rv; +} +#endif /* _PR_NEED_FAKE_POLL */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix_errors.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix_errors.c new file mode 100644 index 00000000..0facbae5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unix_errors.c @@ -0,0 +1,862 @@ +/* -*- 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" +#if defined(_PR_POLL_AVAILABLE) +#include +#endif +#include + +void _MD_unix_map_default_error(int err) +{ + PRErrorCode prError; + + switch (err ) { + case EACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case EADDRINUSE: + prError = PR_ADDRESS_IN_USE_ERROR; + break; + case EADDRNOTAVAIL: + prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; + break; + case EAFNOSUPPORT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case EAGAIN: + prError = PR_WOULD_BLOCK_ERROR; + break; + /* + * On QNX and Neutrino, EALREADY is defined as EBUSY. + */ +#if EALREADY != EBUSY + case EALREADY: + prError = PR_ALREADY_INITIATED_ERROR; + break; +#endif + case EBADF: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; +#ifdef EBADMSG + case EBADMSG: + prError = PR_IO_ERROR; + break; +#endif + case EBUSY: + prError = PR_FILESYSTEM_MOUNTED_ERROR; + break; + case ECONNABORTED: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case ECONNREFUSED: + prError = PR_CONNECT_REFUSED_ERROR; + break; + case ECONNRESET: + prError = PR_CONNECT_RESET_ERROR; + break; + case EDEADLK: + prError = PR_DEADLOCK_ERROR; + break; +#ifdef EDIRCORRUPTED + case EDIRCORRUPTED: + prError = PR_DIRECTORY_CORRUPTED_ERROR; + break; +#endif +#ifdef EDQUOT + case EDQUOT: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; +#endif + case EEXIST: + prError = PR_FILE_EXISTS_ERROR; + break; + case EFAULT: + prError = PR_ACCESS_FAULT_ERROR; + break; + case EFBIG: + prError = PR_FILE_TOO_BIG_ERROR; + break; + case EHOSTUNREACH: + prError = PR_HOST_UNREACHABLE_ERROR; + break; + case EINPROGRESS: + prError = PR_IN_PROGRESS_ERROR; + break; + case EINTR: + prError = PR_PENDING_INTERRUPT_ERROR; + break; + case EINVAL: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case EIO: + prError = PR_IO_ERROR; + break; + case EISCONN: + prError = PR_IS_CONNECTED_ERROR; + break; + case EISDIR: + prError = PR_IS_DIRECTORY_ERROR; + break; + case ELOOP: + prError = PR_LOOP_ERROR; + break; + case EMFILE: + prError = PR_PROC_DESC_TABLE_FULL_ERROR; + break; + case EMLINK: + prError = PR_MAX_DIRECTORY_ENTRIES_ERROR; + break; + case EMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; +#ifdef EMULTIHOP + case EMULTIHOP: + prError = PR_REMOTE_FILE_ERROR; + break; +#endif + case ENAMETOOLONG: + prError = PR_NAME_TOO_LONG_ERROR; + break; + case ENETUNREACH: + prError = PR_NETWORK_UNREACHABLE_ERROR; + break; + case ENFILE: + prError = PR_SYS_DESC_TABLE_FULL_ERROR; + break; + /* + * On SCO OpenServer 5, ENOBUFS is defined as ENOSR. + */ +#if defined(ENOBUFS) && (ENOBUFS != ENOSR) + case ENOBUFS: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#endif + case ENODEV: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOENT: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOLCK: + prError = PR_FILE_IS_LOCKED_ERROR; + break; +#ifdef ENOLINK + case ENOLINK: + prError = PR_REMOTE_FILE_ERROR; + break; +#endif + case ENOMEM: + prError = PR_OUT_OF_MEMORY_ERROR; + break; + case ENOPROTOOPT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ENOSPC: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; +#ifdef ENOSR + case ENOSR: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#endif + case ENOTCONN: + prError = PR_NOT_CONNECTED_ERROR; + break; + case ENOTDIR: + prError = PR_NOT_DIRECTORY_ERROR; + break; + case ENOTSOCK: + prError = PR_NOT_SOCKET_ERROR; + break; + case ENXIO: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case EOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; +#endif + case EPERM: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case EPIPE: + prError = PR_CONNECT_RESET_ERROR; + break; +#ifdef EPROTO + case EPROTO: + prError = PR_IO_ERROR; + break; +#endif + case EPROTONOSUPPORT: + prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; + break; + case EPROTOTYPE: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ERANGE: + prError = PR_INVALID_METHOD_ERROR; + break; + case EROFS: + prError = PR_READ_ONLY_FILESYSTEM_ERROR; + break; + case ESPIPE: + prError = PR_INVALID_METHOD_ERROR; + break; + case ETIMEDOUT: + prError = PR_IO_TIMEOUT_ERROR; + break; +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: + prError = PR_WOULD_BLOCK_ERROR; + break; +#endif + case EXDEV: + prError = PR_NOT_SAME_DEVICE_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_opendir_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_closedir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_readdir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOENT: + prError = PR_NO_MORE_FILES_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_IO_ERROR; + break; +#endif + case EINVAL: + prError = PR_IO_ERROR; + break; + case ENXIO: + prError = PR_IO_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_unlink_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EPERM: + prError = PR_IS_DIRECTORY_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_stat_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_fstat_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_rename_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EEXIST: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_access_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_mkdir_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_rmdir_error(int err) +{ + PRErrorCode prError; + + switch (err) { + /* + * On AIX 4.3, ENOTEMPTY is defined as EEXIST. + */ +#if ENOTEMPTY != EEXIST + case ENOTEMPTY: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; +#endif + case EEXIST: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + case EINVAL: + prError = PR_DIRECTORY_NOT_EMPTY_ERROR; + break; + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_read_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + case ENXIO: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_write_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + case ENXIO: + prError = PR_INVALID_METHOD_ERROR; + break; + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_lseek_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_fsync_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + case EINVAL: + prError = PR_INVALID_METHOD_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_close_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_socket_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_socketavailable_error(int err) +{ + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); +} + +void _MD_unix_map_recv_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_recvfrom_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_send_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_sendto_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_writev_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_accept_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENODEV: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_connect_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; +#if defined(UNIXWARE) || defined(SNI) || defined(NEC) + /* + * On some platforms, if we connect to a port on the local host + * (the loopback address) that no process is listening on, we get + * EIO instead of ECONNREFUSED. + */ + case EIO: + prError = PR_CONNECT_REFUSED_ERROR; + break; +#endif + case ELOOP: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ENOENT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case ENXIO: + prError = PR_IO_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_bind_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; + break; + /* + * UNIX domain sockets are not supported in NSPR + */ + case EIO: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EROFS: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_listen_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_shutdown_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_socketpair_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getsockname_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getpeername_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_getsockopt_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_setsockopt_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_open_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EBUSY: + prError = PR_IO_ERROR; + break; + case ENODEV: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ENOMEM: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; +#ifdef EOVERFLOW + case EOVERFLOW: + prError = PR_FILE_TOO_BIG_ERROR; + break; +#endif + case ETIMEDOUT: + prError = PR_REMOTE_FILE_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_mmap_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EMFILE: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ENODEV: + prError = PR_OPERATION_NOT_SUPPORTED_ERROR; + break; + case ENXIO: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_gethostname_error(int err) +{ + _MD_unix_map_default_error(err); +} + +void _MD_unix_map_select_error(int err) +{ + _MD_unix_map_default_error(err); +} + +#if defined(_PR_POLL_AVAILABLE) || defined(_PR_NEED_FAKE_POLL) +void _MD_unix_map_poll_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EAGAIN: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_poll_revents_error(int err) +{ + if (err & POLLNVAL) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF); + else if (err & POLLHUP) + PR_SetError(PR_CONNECT_RESET_ERROR, EPIPE); + else if (err & POLLERR) + PR_SetError(PR_IO_ERROR, EIO); + else + PR_SetError(PR_UNKNOWN_ERROR, err); +} +#endif /* _PR_POLL_AVAILABLE || _PR_NEED_FAKE_POLL */ + + +void _MD_unix_map_flock_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EINVAL: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case EWOULDBLOCK: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_unix_map_lockf_error(int err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case EDEADLK: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + default: + _MD_unix_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +#ifdef AIX +void _MD_aix_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err); +} +#endif /* AIX */ + +#ifdef HPUX11 +void _MD_hpux_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err); +} +#endif /* HPUX11 */ + +#ifdef SOLARIS +void _MD_solaris_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err) ; +} +#endif /* SOLARIS */ + +#ifdef LINUX +void _MD_linux_map_sendfile_error(int err) +{ + _MD_unix_map_default_error(err) ; +} +#endif /* LINUX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unixware.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unixware.c new file mode 100644 index 00000000..cbcbb3eb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/unixware.c @@ -0,0 +1,583 @@ +/* -*- 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" + +#if !defined (USE_SVR4_THREADS) + +/* + * using only NSPR threads here + */ + +#include + +void _MD_EarlyInit(void) +{ +} + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) setjmp(CONTEXT(t)); + } + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); + return (PRWord *) CONTEXT(t); +} + +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ + +PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _connect(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); +} + +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 rv; + + _MD_BLOCK_CLOCK_INTERRUPTS(); + rv = _accept(osfd,addr,addrlen); + _MD_UNBLOCK_CLOCK_INTERRUPTS(); + return(rv); +} +#endif + +/* + * These are also implemented in pratom.c using NSPR locks. Any reason + * this might be better or worse? If you like this better, define + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h + */ +#ifdef _PR_HAVE_ATOMIC_OPS +/* Atomic operations */ +#include +static FILE *_uw_semf; + +void +_MD_INIT_ATOMIC(void) +{ + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ + if ((_uw_semf = tmpfile()) == NULL) + PR_ASSERT(0); + + return; +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)++; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + flockfile(_uw_semf); + (*ptr) += val; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + flockfile(_uw_semf); + (*val)--; + unflockfile(_uw_semf); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + flockfile(_uw_semf); + *val = newval; + unflockfile(_uw_semf); +} +#endif + +void +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) +{ + return; +} + +PRStatus +_MD_InitializeThread(PRThread *thread) +{ + return PR_SUCCESS; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + _PR_MD_SWITCH_CONTEXT(thread); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread) { + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); + } + return PR_SUCCESS; +} + +/* These functions should not be called for Unixware */ +void +_MD_YIELD(void) +{ + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); +} + +PRStatus +_MD_CREATE_THREAD( + PRThread *thread, + void (*start) (void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); +} + +#else /* USE_SVR4_THREADS */ + +/* NOTE: + * SPARC v9 (Ultras) do have an atomic test-and-set operation. But + * SPARC v8 doesn't. We should detect in the init if we are running on + * v8 or v9, and then use assembly where we can. + */ + +#include +#include + +static mutex_t _unixware_atomic = DEFAULTMUTEX; + +#define TEST_THEN_ADD(where, inc) \ + if (mutex_lock(&_unixware_atomic) != 0)\ + PR_ASSERT(0);\ + *where += inc;\ + if (mutex_unlock(&_unixware_atomic) != 0)\ + PR_ASSERT(0); + +#define TEST_THEN_SET(where, val) \ + if (mutex_lock(&_unixware_atomic) != 0)\ + PR_ASSERT(0);\ + *where = val;\ + if (mutex_unlock(&_unixware_atomic) != 0)\ + PR_ASSERT(0); + +void +_MD_INIT_ATOMIC(void) +{ +} + +void +_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + TEST_THEN_ADD(val, 1); +} + +void +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + TEST_THEN_ADD(ptr, val); +} + +void +_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + TEST_THEN_ADD(val, 0xffffffff); +} + +void +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + TEST_THEN_SET(val, newval); +} + +#include +#include +#include + +#include +#include +#include + + +THREAD_KEY_T threadid_key; +THREAD_KEY_T cpuid_key; +THREAD_KEY_T last_thread_key; +static sigset_t set, oldset; + +void _MD_EarlyInit(void) +{ + THR_KEYCREATE(&threadid_key, NULL); + THR_KEYCREATE(&cpuid_key, NULL); + THR_KEYCREATE(&last_thread_key, NULL); + sigemptyset(&set); + sigaddset(&set, SIGALRM); +} + +PRStatus _MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + long flags; + + /* mask out SIGALRM for native thread creation */ + thr_sigsetmask(SIG_BLOCK, &set, &oldset); + + flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/ + : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/); + if (_PR_IS_GCABLE_THREAD(thread) || + (scope == PR_GLOBAL_BOUND_THREAD)) + flags |= THR_BOUND; + + if (thr_create(NULL, thread->stack->stackSize, + (void *(*)(void *)) start, (void *) thread, + flags, + &thread->md.handle)) { + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + return PR_FAILURE; + } + + + /* When the thread starts running, then the lwpid is set to the right + * value. Until then we want to mark this as 'uninit' so that + * its register state is initialized properly for GC */ + + thread->md.lwpid = -1; + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + + if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) { + thread->flags |= _PR_GLOBAL_SCOPE; + } + + /* + ** Set the thread priority. This will also place the thread on + ** the runQ. + ** + ** Force PR_SetThreadPriority to set the priority by + ** setting thread->priority to 100. + */ + { + int pri; + pri = thread->priority; + thread->priority = 100; + PR_SetThreadPriority( thread, pri ); + + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[Start]: on to runq at priority %d", + thread, thread->priority)); + } + + /* Activate the thread */ + if (thr_continue( thread->md.handle ) ) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void _MD_cleanup_thread(PRThread *thread) +{ + thread_t hdl; + PRMonitor *mon; + + hdl = thread->md.handle; + + /* + ** First, suspend the thread (unless it's the active one) + ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to + ** prevent both of us modifying the thread structure at the same time. + */ + if ( thread != _PR_MD_CURRENT_THREAD() ) { + thr_suspend(hdl); + } + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("(0X%x)[DestroyThread]\n", thread)); + + _MD_DESTROY_SEM(&thread->md.waiter_sem); +} + +void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri) +{ + if(thr_setprio((thread_t)md_thread->handle, newPri)) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_SetThreadPriority: can't set thread priority\n")); + } +} + +void _MD_WAIT_CV( + struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout) +{ + struct timespec tt; + PRUint32 msec; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + msec = PR_IntervalToMilliseconds(timeout); + + GETTIME (&tt); + + tt.tv_sec += msec / PR_MSEC_PER_SEC; + tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC; + /* Check for nsec overflow - otherwise we'll get an EINVAL */ + if (tt.tv_nsec >= PR_NSEC_PER_SEC) { + tt.tv_sec++; + tt.tv_nsec -= PR_NSEC_PER_SEC; + } + me->md.sp = unixware_getsp(); + + + /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason + * hence ignore EINTR for now */ + + COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt); +} + +void _MD_lock(struct _MDLock *md_lock) +{ + mutex_lock(&md_lock->lock); +} + +void _MD_unlock(struct _MDLock *md_lock) +{ + mutex_unlock(&((md_lock)->lock)); +} + + +PRThread *_pr_current_thread_tls() +{ + PRThread *ret; + + thr_getspecific(threadid_key, (void **)&ret); + return ret; +} + +PRStatus +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + _MD_WAIT_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +PRStatus +_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread == NULL) { + return PR_SUCCESS; + } + _MD_POST_SEM(&thread->md.waiter_sem); + return PR_SUCCESS; +} + +_PRCPU *_pr_current_cpu_tls() +{ + _PRCPU *ret; + + thr_getspecific(cpuid_key, (void **)&ret); + return ret; +} + +PRThread *_pr_last_thread_tls() +{ + PRThread *ret; + + thr_getspecific(last_thread_key, (void **)&ret); + return ret; +} + +_MDLock _pr_ioq_lock; + +void _MD_INIT_IO (void) +{ + _MD_NEW_LOCK(&_pr_ioq_lock); +} + +PRStatus _MD_InitializeThread(PRThread *thread) +{ + if (!_PR_IS_NATIVE_THREAD(thread)) + return; + /* prime the sp; substract 4 so we don't hit the assert that + * curr sp > base_stack + */ + thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long); + thread->md.lwpid = _lwp_self(); + thread->md.handle = THR_SELF(); + + /* all threads on Solaris are global threads from NSPR's perspective + * since all of them are mapped to Solaris threads. + */ + thread->flags |= _PR_GLOBAL_SCOPE; + + /* For primordial/attached thread, we don't create an underlying native thread. + * So, _MD_CREATE_THREAD() does not get called. We need to do initialization + * like allocating thread's synchronization variables and set the underlying + * native thread's priority. + */ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + _MD_NEW_SEM(&thread->md.waiter_sem, 0); + _MD_SET_PRIORITY(&(thread->md), thread->priority); + } + return PR_SUCCESS; +} + +static sigset_t old_mask; /* store away original gc thread sigmask */ +static int gcprio; /* store away original gc thread priority */ +static lwpid_t *all_lwps=NULL; /* list of lwps that we suspended */ +static int num_lwps ; +static int suspendAllOn = 0; + +#define VALID_SP(sp, bottom, top) \ + (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top))) + +void unixware_preempt_off() +{ + sigset_t set; + (void)sigfillset(&set); + sigprocmask (SIG_SETMASK, &set, &old_mask); +} + +void unixware_preempt_on() +{ + sigprocmask (SIG_SETMASK, &old_mask, NULL); +} + +void _MD_Begin_SuspendAll() +{ + unixware_preempt_off(); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n")); + /* run at highest prio so I cannot be preempted */ + thr_getprio(thr_self(), &gcprio); + thr_setprio(thr_self(), 0x7fffffff); + suspendAllOn = 1; +} + +void _MD_End_SuspendAll() +{ +} + +void _MD_End_ResumeAll() +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n")); + thr_setprio(thr_self(), gcprio); + unixware_preempt_on(); + suspendAllOn = 0; +} + +void _MD_Suspend(PRThread *thr) +{ + int lwp_fd, result; + int lwp_main_proc_fd = 0; + + thr_suspend(thr->md.handle); + if (!_PR_IS_GCABLE_THREAD(thr)) + return; + /* XXX Primordial thread can't be bound to an lwp, hence there is no + * way we can assume that we can get the lwp status for primordial + * thread reliably. Hence we skip this for primordial thread, hoping + * that the SP is saved during lock and cond. wait. + * XXX - Again this is concern only for java interpreter, not for the + * server, 'cause primordial thread in the server does not do java work + */ + if (thr->flags & _PR_PRIMORDIAL) + return; + + /* if the thread is not started yet then don't do anything */ + if (!suspendAllOn || thr->md.lwpid == -1) + return; + +} +void _MD_Resume(PRThread *thr) +{ + if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){ + /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend + * during that time we can't call any thread lib or libc calls. Hence + * make sure that no resume is requested for Non gcable thread + * during suspendAllOn */ + PR_ASSERT(!suspendAllOn); + thr_continue(thr->md.handle); + return; + } + if (thr->md.lwpid == -1) + return; + + if ( _lwp_continue(thr->md.lwpid) < 0) { + PR_ASSERT(0); /* ARGH, we are hosed! */ + } +} + + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) { + (void) getcontext(CONTEXT(t)); /* XXX tune me: set md_IRIX.c */ + } + *np = NGREG; + if (t->md.lwpid == -1) + memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord)); + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; +} + +int +_pr_unixware_clock_gettime (struct timespec *tp) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + tp->tv_sec = tv.tv_sec; + tp->tv_nsec = tv.tv_usec * 1000; + return 0; +} + + +#endif /* USE_SVR4_THREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxpoll.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxpoll.c new file mode 100644 index 00000000..aa026568 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxpoll.c @@ -0,0 +1,708 @@ +/* -*- 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 ***** */ + +#if defined(_PR_PTHREADS) + +#error "This file should not be compiled" + +#else /* defined(_PR_PTHREADS) */ + +#include "primpl.h" + +#include + +#include +#ifdef _PR_USE_POLL +#include +#endif + +#if defined(_PR_USE_POLL) +static PRInt32 NativeThreadPoll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + /* + * This function is mostly duplicated from ptio.s's PR_Poll(). + */ + PRInt32 ready = 0; + /* + * For restarting poll() if it is interrupted by a signal. + * We use these variables to figure out how much time has + * elapsed and how much of the timeout still remains. + */ + PRIntn index, msecs; + struct pollfd *syspoll = NULL; + PRIntervalTime start, elapsed, remaining; + + syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); + if (NULL == syspoll) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + for (index = 0; index < npds; ++index) + { + PRFileDesc *bottom; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (pds[index].in_flags & PR_POLL_READ) + { + in_flags_read = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_WRITE, + &out_flags_read); + } + if (pds[index].in_flags & PR_POLL_WRITE) + { + in_flags_write = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_READ, + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one is ready right now */ + if (0 == ready) + { + /* + * We will return without calling the system + * poll function. So zero the out_flags + * fields of all the poll descriptors before + * this one. + */ + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; + pds[index].out_flags = out_flags_read | out_flags_write; + } + else + { + pds[index].out_flags = 0; /* pre-condition */ + /* now locate the NSPR layer at the bottom of the stack */ + bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + syspoll[index].fd = bottom->secret->md.osfd; + syspoll[index].events = 0; /* pre-condition */ + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + syspoll[index].events |= POLLPRI; + } + } + else + { + if (0 == ready) + { + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pds[index].out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + /* make poll() ignore this entry */ + syspoll[index].fd = -1; + syspoll[index].events = 0; + pds[index].out_flags = 0; + } + } + + if (0 == ready) + { + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: msecs = 0; break; + case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; + default: + msecs = PR_IntervalToMilliseconds(timeout); + start = PR_IntervalNow(); + } + +retry: + ready = _MD_POLL(syspoll, npds, msecs); + if (-1 == ready) + { + PRIntn oserror = errno; + + if (EINTR == oserror) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0; + else + { + elapsed = (PRIntervalTime)(PR_IntervalNow() - start); + if (elapsed > timeout) ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + msecs = PR_IntervalToMilliseconds(remaining); + goto retry; + } + } + } + else _PR_MD_MAP_POLL_ERROR(oserror); + } + else if (ready > 0) + { + for (index = 0; index < npds; ++index) + { + PRInt16 out_flags = 0; + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (0 != syspoll[index].revents) + { + /* + ** Set up the out_flags so that it contains the + ** bits that the highest layer thinks are nice + ** to have. Then the client of that layer will + ** call the appropriate I/O function and maybe + ** the protocol will make progress. + */ + if (syspoll[index].revents & POLLIN) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_READ) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_READ) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLOUT) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_WRITE) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_WRITE) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLPRI) + out_flags |= PR_POLL_EXCEPT; + if (syspoll[index].revents & POLLERR) + out_flags |= PR_POLL_ERR; + if (syspoll[index].revents & POLLNVAL) + out_flags |= PR_POLL_NVAL; + if (syspoll[index].revents & POLLHUP) + out_flags |= PR_POLL_HUP; + } + } + pds[index].out_flags = out_flags; + } + } + } + + PR_DELETE(syspoll); + return ready; + +} /* NativeThreadPoll */ +#endif /* defined(_PR_USE_POLL) */ + +#if !defined(_PR_USE_POLL) +static PRInt32 NativeThreadSelect( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + /* + * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). + */ + fd_set rd, wt, ex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRInt32 maxfd = -1, ready, err; + PRIntervalTime remaining, elapsed, start; + + struct timeval tv, *tvp = NULL; + + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + 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))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + PRInt32 osfd = bottom->secret->md.osfd; + if (osfd > maxfd) maxfd = osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + } + if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) return ready; /* no need to block */ + + remaining = timeout; + start = PR_IntervalNow(); + +retry: + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = remaining / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); + tvp = &tv; + } + + ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); + + if (ready == -1 && errno == EINTR) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + goto retry; + } + } + } + + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + PRInt32 osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = bottom->secret->md.osfd; + + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; + } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready < 0) + { + err = _MD_ERRNO(); + if (err == EBADF) + { + /* Find the bad fds */ + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + PR_ASSERT(ready > 0); + } + else _PR_MD_MAP_SELECT_ERROR(err); + } + + return ready; +} /* NativeThreadSelect */ +#endif /* !defined(_PR_USE_POLL) */ + +static PRInt32 LocalThreads( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRPollDesc *pd, *epd; + PRInt32 ready, pdcnt; + _PRUnixPollDesc *unixpds, *unixpd; + + /* + * XXX + * PRPollDesc has a PRFileDesc field, fd, while the IOQ + * is a list of PRPollQueue structures, each of which contains + * a _PRUnixPollDesc. A _PRUnixPollDesc struct contains + * the OS file descriptor, osfd, and not a PRFileDesc. + * So, we have allocate memory for _PRUnixPollDesc structures, + * copy the flags information from the pds list and have pq + * point to this list of _PRUnixPollDesc structures. + * + * It would be better if the memory allocation can be avoided. + */ + + unixpd = unixpds = (_PRUnixPollDesc*) + PR_MALLOC(npds * sizeof(_PRUnixPollDesc)); + if (NULL == unixpds) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + + ready = 0; + for (pdcnt = 0, pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRFileDesc *bottom; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + 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))) + { + /* this one's ready right now */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + unixpd->osfd = bottom->secret->md.osfd; + unixpd->in_flags = 0; + if (in_flags_read & PR_POLL_READ) + { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + pd->out_flags |= _PR_POLL_READ_SYS_READ; + } + if (in_flags_read & PR_POLL_WRITE) + { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + } + if (in_flags_write & PR_POLL_READ) + { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + } + if (in_flags_write & PR_POLL_WRITE) + { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + } + if ((in_flags_read | in_flags_write) & PR_POLL_EXCEPT) + { + unixpd->in_flags |= _PR_UNIX_POLL_EXCEPT; + } + unixpd++; pdcnt++; + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + } + + if (0 != ready) + { + /* no need to block */ + PR_DELETE(unixpds); + return ready; + } + + ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); + + /* + * Copy the out_flags from the _PRUnixPollDesc structures to the + * user's PRPollDesc structures and free the allocated memory + */ + unixpd = unixpds; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + /* + * take errors from the poll operation, + * the R/W bits from the request + */ + if (0 != unixpd->out_flags) + { + if (unixpd->out_flags & _PR_UNIX_POLL_READ) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) + out_flags |= PR_POLL_EXCEPT; + if (unixpd->out_flags & _PR_UNIX_POLL_ERR) + out_flags |= PR_POLL_ERR; + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) + out_flags |= PR_POLL_NVAL; + if (unixpd->out_flags & _PR_UNIX_POLL_HUP) + out_flags |= PR_POLL_HUP; + } + unixpd++; + } + pd->out_flags = out_flags; + } + + PR_DELETE(unixpds); + + return ready; +} /* LocalThreads */ + +#if defined(_PR_USE_POLL) +#define NativeThreads NativeThreadPoll +#else +#define NativeThreads NativeThreadSelect +#endif + +PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 rv = 0; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + if (0 == npds) PR_Sleep(timeout); + else if (_PR_IS_NATIVE_THREAD(me)) + rv = NativeThreads(pds, npds, timeout); + else rv = LocalThreads(pds, npds, timeout); + + return rv; +} /* _MD_pr_poll */ + +#endif /* defined(_PR_PTHREADS) */ + +/* uxpoll.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c new file mode 100644 index 00000000..ff825772 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c @@ -0,0 +1,1118 @@ +/* -*- 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 +#include +#include +#include +#include +#if defined(AIX) +#include /* For dlopen, dlsym, dlclose */ +#endif + +#if defined(DARWIN) +#include +#else +extern char **environ; +#endif + +/* + * HP-UX 9 doesn't have the SA_RESTART flag. + */ +#ifndef SA_RESTART +#define SA_RESTART 0 +#endif + +#if defined(VMS) +static PRLock *_pr_vms_fork_lock = NULL; +#endif + +#ifdef VBOX +#include +#include +#include +#include +#endif + +/* + ********************************************************************** + * + * The Unix process routines + * + ********************************************************************** + */ + +#define _PR_SIGNALED_EXITSTATUS 256 + +typedef enum pr_PidState { + _PR_PID_DETACHED, + _PR_PID_REAPED, + _PR_PID_WAITING +} pr_PidState; + +typedef struct pr_PidRecord { + pid_t pid; + int exitStatus; + pr_PidState state; + PRCondVar *reapedCV; + struct pr_PidRecord *next; +} pr_PidRecord; + +/* + * Irix sprocs and LinuxThreads are actually a kind of processes + * that can share the virtual address space and file descriptors. + */ +#if (defined(IRIX) && !defined(_PR_PTHREADS)) \ + || (defined(LINUX) && defined(_PR_PTHREADS)) +#define _PR_SHARE_CLONES +#endif + +/* + * The macro _PR_NATIVE_THREADS indicates that we are + * using native threads only, so waitpid() blocks just the + * calling thread, not the process. In this case, the waitpid + * daemon thread can safely block in waitpid(). So we don't + * need to catch SIGCHLD, and the pipe to unblock PR_Poll() is + * also not necessary. + */ + +#if defined(_PR_GLOBAL_THREADS_ONLY) \ + || (defined(_PR_PTHREADS) && !defined(LINUX)) +#define _PR_NATIVE_THREADS +#endif + +/* + * All the static variables used by the Unix process routines are + * collected in this structure. + */ + +static struct { + PRCallOnceType once; + PRThread *thread; + PRLock *ml; +#if defined(_PR_NATIVE_THREADS) + PRInt32 numProcs; + PRCondVar *cv; +#else + int pipefd[2]; +#endif + pr_PidRecord **pidTable; + +#ifdef _PR_SHARE_CLONES + struct pr_CreateProcOp *opHead, *opTail; +#endif + +#ifdef AIX + pid_t (*forkptr)(void); /* Newer versions of AIX (starting in 4.3.2) + * have f_fork, which is faster than the + * regular fork in a multithreaded process + * because it skips calling the fork handlers. + * So we look up the f_fork symbol to see if + * it's available and fall back on fork. + */ +#endif /* AIX */ +} pr_wp; + +#ifdef _PR_SHARE_CLONES +static int pr_waitpid_daemon_exit; + +void +_MD_unix_terminate_waitpid_daemon(void) +{ + if (pr_wp.thread) { + pr_waitpid_daemon_exit = 1; + write(pr_wp.pipefd[1], "", 1); + PR_JoinThread(pr_wp.thread); + } +} +#endif + +static PRStatus _MD_InitProcesses(void); +#if !defined(_PR_NATIVE_THREADS) +static void pr_InstallSigchldHandler(void); +#ifdef VBOX +static void (*old_sig_handler)(int) = NULL; +#endif /* VBOX */ +#endif + +static PRProcess * +ForkAndExec( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PRProcess *process; + int nEnv, idx; + char *const *childEnvp; + char **newEnvp = NULL; + int flags; +#ifdef VMS + char VMScurdir[FILENAME_MAX+1] = { '\0' } ; +#endif + + process = PR_NEW(PRProcess); + if (!process) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + childEnvp = envp; + if (attr && attr->fdInheritBuffer) { + if (NULL == childEnvp) { +#ifdef DARWIN + childEnvp = *(_NSGetEnviron()); +#else + childEnvp = environ; +#endif + } + for (nEnv = 0; childEnvp[nEnv]; nEnv++) { + } + newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); + if (NULL == newEnvp) { + PR_DELETE(process); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + for (idx = 0; idx < nEnv; idx++) { + newEnvp[idx] = childEnvp[idx]; + } + newEnvp[idx++] = attr->fdInheritBuffer; + newEnvp[idx] = NULL; + childEnvp = newEnvp; + } + +#ifdef VMS +/* +** Since vfork/exec is implemented VERY differently on OpenVMS, we have to +** handle the setting up of the standard streams very differently. And since +** none of this code can ever execute in the context of the child, we have +** to perform the chdir in the parent so the child is born into the correct +** directory (and then switch the parent back again). +*/ +{ + int decc$set_child_standard_streams(int,int,int); + int n, fd_stdin=0, fd_stdout=1, fd_stderr=2; + + /* Set up any standard streams we are given, assuming defaults */ + if (attr) { + if (attr->stdinFd) + fd_stdin = attr->stdinFd->secret->md.osfd; + if (attr->stdoutFd) + fd_stdout = attr->stdoutFd->secret->md.osfd; + if (attr->stderrFd) + fd_stderr = attr->stderrFd->secret->md.osfd; + } + + /* + ** Put a lock around anything that isn't going to be thread-safe. + */ + PR_Lock(_pr_vms_fork_lock); + + /* + ** Prepare the child's streams. We always do this in case a previous fork + ** has left the stream assignments in some non-standard way. + */ + n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr); + if (n == -1) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + PR_Unlock(_pr_vms_fork_lock); + return NULL; + } + + /* Switch directory if we have to */ + if (attr) { + if (attr->currentDirectory) { + if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) || + (chdir(attr->currentDirectory) < 0) ) { + PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + PR_Unlock(_pr_vms_fork_lock); + return NULL; + } + } + } +} +#endif /* VMS */ + +#ifdef AIX + process->md.pid = (*pr_wp.forkptr)(); +#elif defined(NTO) + /* + * fork() & exec() does not work in a multithreaded process. + * Use spawn() instead. + */ + { + int fd_map[3] = { 0, 1, 2 }; + + if (attr) { + if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { + fd_map[0] = dup(attr->stdinFd->secret->md.osfd); + flags = fcntl(fd_map[0], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK); + } + if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { + fd_map[1] = dup(attr->stdoutFd->secret->md.osfd); + flags = fcntl(fd_map[1], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK); + } + if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { + fd_map[2] = dup(attr->stderrFd->secret->md.osfd); + flags = fcntl(fd_map[2], F_GETFL, 0); + if (flags & O_NONBLOCK) + fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK); + } + + PR_ASSERT(attr->currentDirectory == NULL); /* not implemented */ + } + + process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp); + + if (fd_map[0] != 0) + close(fd_map[0]); + if (fd_map[1] != 1) + close(fd_map[1]); + if (fd_map[2] != 2) + close(fd_map[2]); + } +#else + process->md.pid = fork(); +#endif + if ((pid_t) -1 == process->md.pid) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + return NULL; + } else if (0 == process->md.pid) { /* the child process */ + /* + * If the child process needs to exit, it must call _exit(). + * Do not call exit(), because exit() will flush and close + * the standard I/O file descriptors, and hence corrupt + * the parent process's standard I/O data structures. + */ + +#if !defined(NTO) +#ifdef VMS + /* OpenVMS has already handled all this above */ +#else + if (attr) { + /* the osfd's to redirect stdin, stdout, and stderr to */ + int in_osfd = -1, out_osfd = -1, err_osfd = -1; + + if (attr->stdinFd + && attr->stdinFd->secret->md.osfd != 0) { + in_osfd = attr->stdinFd->secret->md.osfd; + if (dup2(in_osfd, 0) != 0) { + _exit(1); /* failed */ + } + flags = fcntl(0, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(0, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stdoutFd + && attr->stdoutFd->secret->md.osfd != 1) { + out_osfd = attr->stdoutFd->secret->md.osfd; + if (dup2(out_osfd, 1) != 1) { + _exit(1); /* failed */ + } + flags = fcntl(1, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(1, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (attr->stderrFd + && attr->stderrFd->secret->md.osfd != 2) { + err_osfd = attr->stderrFd->secret->md.osfd; + if (dup2(err_osfd, 2) != 2) { + _exit(1); /* failed */ + } + flags = fcntl(2, F_GETFL, 0); + if (flags & O_NONBLOCK) { + fcntl(2, F_SETFL, flags & ~O_NONBLOCK); + } + } + if (in_osfd != -1) { + close(in_osfd); + } + if (out_osfd != -1 && out_osfd != in_osfd) { + close(out_osfd); + } + if (err_osfd != -1 && err_osfd != in_osfd + && err_osfd != out_osfd) { + close(err_osfd); + } + if (attr->currentDirectory) { + if (chdir(attr->currentDirectory) < 0) { + _exit(1); /* failed */ + } + } + } +#endif /* !VMS */ + + if (childEnvp) { + (void)execve(path, argv, childEnvp); + } else { + /* Inherit the environment of the parent. */ + (void)execv(path, argv); + } + /* Whoops! It returned. That's a bad sign. */ +#ifdef VMS + /* + ** On OpenVMS we are still in the context of the parent, and so we + ** can (and should!) perform normal error handling. + */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + PR_DELETE(process); + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (VMScurdir[0] != '\0') + chdir(VMScurdir); + PR_Unlock(_pr_vms_fork_lock); + return NULL; +#else + _exit(1); +#endif /* VMS */ +#endif /* !NTO */ + } + + if (newEnvp) { + PR_DELETE(newEnvp); + } +#ifdef VMS + /* If we switched directories, then remember to switch back */ + if (VMScurdir[0] != '\0') { + chdir(VMScurdir); /* can't do much if it fails */ + } + PR_Unlock(_pr_vms_fork_lock); +#endif /* VMS */ + +#if defined(_PR_NATIVE_THREADS) + PR_Lock(pr_wp.ml); + if (0 == pr_wp.numProcs++) { + PR_NotifyCondVar(pr_wp.cv); + } + PR_Unlock(pr_wp.ml); +#endif + return process; +} + +#ifdef _PR_SHARE_CLONES + +struct pr_CreateProcOp { + const char *path; + char *const *argv; + char *const *envp; + const PRProcessAttr *attr; + PRProcess *process; + PRErrorCode prerror; + PRInt32 oserror; + PRBool done; + PRCondVar *doneCV; + struct pr_CreateProcOp *next; +}; + +PRProcess * +_MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ +#ifdef VBOX + /* 2010-10-11 Block this for good. */ + return NULL; +#endif + struct pr_CreateProcOp *op; + PRProcess *proc; + int rv; + + if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) { + return NULL; + } + + op = PR_NEW(struct pr_CreateProcOp); + if (NULL == op) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + op->path = path; + op->argv = argv; + op->envp = envp; + op->attr = attr; + op->done = PR_FALSE; + op->doneCV = PR_NewCondVar(pr_wp.ml); + if (NULL == op->doneCV) { + PR_DELETE(op); + return NULL; + } + PR_Lock(pr_wp.ml); + + /* add to the tail of op queue */ + op->next = NULL; + if (pr_wp.opTail) { + pr_wp.opTail->next = op; + pr_wp.opTail = op; + } else { + PR_ASSERT(NULL == pr_wp.opHead); + pr_wp.opHead = pr_wp.opTail = op; + } + + /* wake up the daemon thread */ + do { + rv = write(pr_wp.pipefd[1], "", 1); + } while (-1 == rv && EINTR == errno); + + while (op->done == PR_FALSE) { + PR_WaitCondVar(op->doneCV, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + PR_DestroyCondVar(op->doneCV); + proc = op->process; + if (!proc) { + PR_SetError(op->prerror, op->oserror); + } + PR_DELETE(op); + return proc; +} + +#else /* ! _PR_SHARE_CLONES */ + +PRProcess * +_MD_CreateUnixProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ +#ifdef VBOX + /* 2010-10-11 Block this for good. */ + return NULL; +#endif + if (PR_CallOnce(&pr_wp.once, _MD_InitProcesses) == PR_FAILURE) { + return NULL; + } + return ForkAndExec(path, argv, envp, attr); +} /* _MD_CreateUnixProcess */ + +#endif /* _PR_SHARE_CLONES */ + +#ifdef VBOX +PRStatus +_MD_CreateUnixProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + int vrc; + int nEnv, idx; + RTENV childEnv; + RTENV newEnv = RTENV_DEFAULT; + + /* this code doesn't support all attributes */ + PR_ASSERT(!attr || !attr->currentDirectory); + /* no custom environment, please */ + PR_ASSERT(!envp); + + childEnv = RTENV_DEFAULT; + if (attr && attr->fdInheritBuffer) { + vrc = RTEnvClone(&newEnv, childEnv); + if (RT_FAILURE(vrc)) + return PR_FAILURE; + vrc = RTEnvPutEx(newEnv, attr->fdInheritBuffer); + if (RT_FAILURE(vrc)) + { + RTEnvDestroy(newEnv); + return PR_FAILURE; + } + childEnv = newEnv; + } + + PRTHANDLE pStdIn = NULL, pStdOut = NULL, pStdErr = NULL; + RTHANDLE hStdIn, hStdOut, hStdErr; + if (attr && attr->stdinFd) + { + hStdIn.enmType = RTHANDLETYPE_FILE; + RTFileFromNative(&hStdIn.u.hFile, attr->stdinFd->secret->md.osfd); + pStdIn = &hStdIn; + } + if (attr && attr->stdoutFd) + { + hStdOut.enmType = RTHANDLETYPE_FILE; + RTFileFromNative(&hStdOut.u.hFile, attr->stdoutFd->secret->md.osfd); + pStdOut = &hStdOut; + } + if (attr && attr->stderrFd) + { + hStdErr.enmType = RTHANDLETYPE_FILE; + RTFileFromNative(&hStdErr.u.hFile, attr->stderrFd->secret->md.osfd); + pStdErr = &hStdErr; + } + + vrc = RTProcCreateEx(path, (const char **)argv, childEnv, + RTPROC_FLAGS_DETACHED, pStdIn, pStdOut, pStdErr, + NULL /* pszAsUser */, NULL /* pszPassword */, NULL /* pExtraData */, + NULL /* phProcess */); + if (newEnv != RTENV_DEFAULT) { + RTEnvDestroy(newEnv); + } + if (RT_SUCCESS(vrc)) + return PR_SUCCESS; + else + return PR_FAILURE; +} /* _MD_CreateUnixProcessDetached */ +#endif + +/* + * The pid table is a hashtable. + * + * The number of buckets in the hashtable (NBUCKETS) must be a power of 2. + */ +#define NBUCKETS_LOG2 6 +#define NBUCKETS (1 << NBUCKETS_LOG2) +#define PID_HASH_MASK ((pid_t) (NBUCKETS - 1)) + +static pr_PidRecord * +FindPidTable(pid_t pid) +{ + pr_PidRecord *pRec; + int keyHash = (int) (pid & PID_HASH_MASK); + + pRec = pr_wp.pidTable[keyHash]; + while (pRec) { + if (pRec->pid == pid) { + break; + } + pRec = pRec->next; + } + return pRec; +} + +static void +InsertPidTable(pr_PidRecord *pRec) +{ + int keyHash = (int) (pRec->pid & PID_HASH_MASK); + + pRec->next = pr_wp.pidTable[keyHash]; + pr_wp.pidTable[keyHash] = pRec; +} + +static void +DeletePidTable(pr_PidRecord *pRec) +{ + int keyHash = (int) (pRec->pid & PID_HASH_MASK); + + if (pr_wp.pidTable[keyHash] == pRec) { + pr_wp.pidTable[keyHash] = pRec->next; + } else { + pr_PidRecord *pred, *cur; /* predecessor and current */ + + pred = pr_wp.pidTable[keyHash]; + cur = pred->next; + while (cur) { + if (cur == pRec) { + pred->next = cur->next; + break; + } + pred = cur; + cur = cur->next; + } + PR_ASSERT(cur != NULL); + } +} + +static int +ExtractExitStatus(int rawExitStatus) +{ + /* + * We did not specify the WCONTINUED and WUNTRACED options + * for waitpid, so these two events should not be reported. + */ + PR_ASSERT(!WIFSTOPPED(rawExitStatus)); +#ifdef WIFCONTINUED + PR_ASSERT(!WIFCONTINUED(rawExitStatus)); +#endif + if (WIFEXITED(rawExitStatus)) { + return WEXITSTATUS(rawExitStatus); + } else { + PR_ASSERT(WIFSIGNALED(rawExitStatus)); + return _PR_SIGNALED_EXITSTATUS; + } +} + +static void +ProcessReapedChildInternal(pid_t pid, int status) +{ + pr_PidRecord *pRec; + + pRec = FindPidTable(pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + pRec->pid = pid; + pRec->state = _PR_PID_REAPED; + pRec->exitStatus = ExtractExitStatus(status); + pRec->reapedCV = NULL; + InsertPidTable(pRec); + } else { +#ifdef VBOX + /* In the context of VirtualBox processes get created (right now + * exclusively via Machine::openRemoteSession) which xpcom doesn't know + * about, and thus would trigger assertions or (even worse) could + * crash VBoxSVC as the code below would notify a NULL condition + * variable. Treat it like a detached process. The proper fix would be + * to port the NSPR to use IPRT, as currently this races with getting + * the exit code, but that's pretty harmless. */ + /* Since 2010-10-11 this code cannot be reached as IPRT took over + * what we need, and the rest is blocked. */ + if (_PR_PID_REAPED == pRec->state) { + DeletePidTable(pRec); + PR_DELETE(pRec); + } else +#else /* !VBOX */ + PR_ASSERT(pRec->state != _PR_PID_REAPED); +#endif /* !VBOX */ + if (_PR_PID_DETACHED == pRec->state) { + PR_ASSERT(NULL == pRec->reapedCV); + DeletePidTable(pRec); + PR_DELETE(pRec); + } else { + PR_ASSERT(_PR_PID_WAITING == pRec->state); + PR_ASSERT(NULL != pRec->reapedCV); + pRec->exitStatus = ExtractExitStatus(status); + pRec->state = _PR_PID_REAPED; + PR_NotifyCondVar(pRec->reapedCV); + } + } +} + +#if defined(_PR_NATIVE_THREADS) + +/* + * If all the threads are native threads, the daemon thread is + * simpler. We don't need to catch the SIGCHLD signal. We can + * just have the daemon thread block in waitpid(). + */ + +static void WaitPidDaemonThread(void *unused) +{ + pid_t pid; + int status; + + while (1) { + PR_Lock(pr_wp.ml); + while (0 == pr_wp.numProcs) { + PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + + while (1) { + do { +#ifdef VBOX + /* + * make sure we wait only for child of our group + * to ensure we do not interfere with RT + */ + /* Since 2010-10-11 this code cannot be reached as IPRT took over + * what we need, and the rest is blocked. */ + pid = waitpid((pid_t) 0, &status, 0); +#else + pid = waitpid((pid_t) -1, &status, 0); +#endif + } while ((pid_t) -1 == pid && EINTR == errno); + + /* + * waitpid() cannot return 0 because we did not invoke it + * with the WNOHANG option. + */ + PR_ASSERT(0 != pid); + + /* + * The only possible error code is ECHILD. But if we do + * our accounting correctly, we should only call waitpid() + * when there is a child process to wait for. + */ + PR_ASSERT((pid_t) -1 != pid); + if ((pid_t) -1 == pid) { + break; + } + + PR_Lock(pr_wp.ml); + ProcessReapedChildInternal(pid, status); + pr_wp.numProcs--; + while (0 == pr_wp.numProcs) { + PR_WaitCondVar(pr_wp.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(pr_wp.ml); + } + } +} + +#else /* _PR_NATIVE_THREADS */ + +static void WaitPidDaemonThread(void *unused) +{ + PRPollDesc pd; + PRFileDesc *fd; + int rv; + char buf[128]; + pid_t pid; + int status; +#ifdef _PR_SHARE_CLONES + struct pr_CreateProcOp *op; +#endif + +#ifdef _PR_SHARE_CLONES + pr_InstallSigchldHandler(); +#endif + + fd = PR_ImportFile(pr_wp.pipefd[0]); + PR_ASSERT(NULL != fd); + pd.fd = fd; + pd.in_flags = PR_POLL_READ; + + while (1) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(1 == rv); + +#ifdef _PR_SHARE_CLONES + if (pr_waitpid_daemon_exit) { + return; + } + PR_Lock(pr_wp.ml); +#endif + + do { + rv = read(pr_wp.pipefd[0], buf, sizeof(buf)); + } while (sizeof(buf) == rv || (-1 == rv && EINTR == errno)); + +#ifdef _PR_SHARE_CLONES + PR_Unlock(pr_wp.ml); + while ((op = pr_wp.opHead) != NULL) { + op->process = ForkAndExec(op->path, op->argv, + op->envp, op->attr); + if (NULL == op->process) { + op->prerror = PR_GetError(); + op->oserror = PR_GetOSError(); + } + PR_Lock(pr_wp.ml); + pr_wp.opHead = op->next; + if (NULL == pr_wp.opHead) { + pr_wp.opTail = NULL; + } + op->done = PR_TRUE; + PR_NotifyCondVar(op->doneCV); + PR_Unlock(pr_wp.ml); + } +#endif + + while (1) { + do { +#ifdef VBOX + /* + * make sure we wait only for child of our group + * to ensure we do not interfere with RT + */ + /* Since 2010-10-11 this code cannot be reached as IPRT took over + * what we need, and the rest is blocked. */ + pid = waitpid((pid_t) 0, &status, WNOHANG); +#else + pid = waitpid((pid_t) -1, &status, WNOHANG); +#endif + } while ((pid_t) -1 == pid && EINTR == errno); + if (0 == pid) break; + if ((pid_t) -1 == pid) { + /* must be because we have no child processes */ + PR_ASSERT(ECHILD == errno); + break; + } + + PR_Lock(pr_wp.ml); + ProcessReapedChildInternal(pid, status); + PR_Unlock(pr_wp.ml); + } + } +} + +static void pr_SigchldHandler(int sig) +{ + int errnoCopy; + int rv; + + errnoCopy = errno; + + do { + rv = write(pr_wp.pipefd[1], "", 1); + } while (-1 == rv && EINTR == errno); + +#ifdef DEBUG + if (-1 == rv && EAGAIN != errno && EWOULDBLOCK != errno) { + char *msg = "cannot write to pipe\n"; + write(2, msg, strlen(msg) + 1); + _exit(1); + } +#endif + + errno = errnoCopy; +#ifdef VBOX + /** @todo: check if the sig handler fix is proper here */ + if(old_sig_handler && old_sig_handler != SIG_IGN) + old_sig_handler(sig); +#endif /* VBOX */ +} + +static void pr_InstallSigchldHandler() +{ +#if defined(HPUX) && defined(_PR_DCETHREADS) +#error "HP-UX DCE threads have their own SIGCHLD handler" +#endif + + struct sigaction act, oact; + int rv; + + act.sa_handler = pr_SigchldHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_NOCLDSTOP | SA_RESTART; + rv = sigaction(SIGCHLD, &act, &oact); + PR_ASSERT(0 == rv); +#ifdef VBOX + old_sig_handler = oact.sa_handler; +#endif /* VBOX */ + /* Make sure we are not overriding someone else's SIGCHLD handler */ +#ifndef _PR_SHARE_CLONES + PR_ASSERT(oact.sa_handler == SIG_DFL); +#endif +} + +#endif /* !defined(_PR_NATIVE_THREADS) */ + +static PRStatus _MD_InitProcesses(void) +{ +#if !defined(_PR_NATIVE_THREADS) + int rv; + int flags; +#endif +#ifdef SUNOS4 +#define _PR_NBIO_FLAG FNDELAY +#else +#define _PR_NBIO_FLAG O_NONBLOCK +#endif + +#ifdef AIX + { + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + pr_wp.forkptr = (pid_t (*)(void)) dlsym(handle, "f_fork"); + if (!pr_wp.forkptr) { + pr_wp.forkptr = fork; + } + dlclose(handle); + } +#endif /* AIX */ + + pr_wp.ml = PR_NewLock(); + PR_ASSERT(NULL != pr_wp.ml); + +#if defined(VMS) + _pr_vms_fork_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_vms_fork_lock); +#endif + +#if defined(_PR_NATIVE_THREADS) + pr_wp.numProcs = 0; + pr_wp.cv = PR_NewCondVar(pr_wp.ml); + PR_ASSERT(NULL != pr_wp.cv); +#else + rv = pipe(pr_wp.pipefd); + PR_ASSERT(0 == rv); + flags = fcntl(pr_wp.pipefd[0], F_GETFL, 0); + fcntl(pr_wp.pipefd[0], F_SETFL, flags | _PR_NBIO_FLAG); + flags = fcntl(pr_wp.pipefd[1], F_GETFL, 0); + fcntl(pr_wp.pipefd[1], F_SETFL, flags | _PR_NBIO_FLAG); + +#ifndef _PR_SHARE_CLONES + pr_InstallSigchldHandler(); +#endif +#endif /* !_PR_NATIVE_THREADS */ + + pr_wp.thread = PR_CreateThread(PR_SYSTEM_THREAD, + WaitPidDaemonThread, NULL, PR_PRIORITY_NORMAL, +#ifdef _PR_SHARE_CLONES + PR_GLOBAL_THREAD, +#else + PR_LOCAL_THREAD, +#endif + PR_JOINABLE_THREAD, 0); + PR_ASSERT(NULL != pr_wp.thread); + + pr_wp.pidTable = (pr_PidRecord**)PR_CALLOC(NBUCKETS * sizeof(pr_PidRecord *)); + PR_ASSERT(NULL != pr_wp.pidTable); + return PR_SUCCESS; +} + +PRStatus _MD_DetachUnixProcess(PRProcess *process) +{ + PRStatus retVal = PR_SUCCESS; + pr_PidRecord *pRec; + + PR_Lock(pr_wp.ml); + pRec = FindPidTable(process->md.pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + if (NULL == pRec) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + retVal = PR_FAILURE; + goto done; + } + pRec->pid = process->md.pid; + pRec->state = _PR_PID_DETACHED; + pRec->reapedCV = NULL; + InsertPidTable(pRec); + } else { + PR_ASSERT(_PR_PID_REAPED == pRec->state); + if (_PR_PID_REAPED != pRec->state) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + retVal = PR_FAILURE; + } else { + DeletePidTable(pRec); + PR_ASSERT(NULL == pRec->reapedCV); + PR_DELETE(pRec); + } + } + PR_DELETE(process); + +done: + PR_Unlock(pr_wp.ml); + return retVal; +} + +PRStatus _MD_WaitUnixProcess( + PRProcess *process, + PRInt32 *exitCode) +{ + pr_PidRecord *pRec; + PRStatus retVal = PR_SUCCESS; + PRBool interrupted = PR_FALSE; + + PR_Lock(pr_wp.ml); + pRec = FindPidTable(process->md.pid); + if (NULL == pRec) { + pRec = PR_NEW(pr_PidRecord); + if (NULL == pRec) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + retVal = PR_FAILURE; + goto done; + } + pRec->pid = process->md.pid; + pRec->state = _PR_PID_WAITING; + pRec->reapedCV = PR_NewCondVar(pr_wp.ml); + if (NULL == pRec->reapedCV) { + PR_DELETE(pRec); + retVal = PR_FAILURE; + goto done; + } + InsertPidTable(pRec); + while (!interrupted && _PR_PID_REAPED != pRec->state) { + if (PR_WaitCondVar(pRec->reapedCV, + PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE + && PR_GetError() == PR_PENDING_INTERRUPT_ERROR) { + interrupted = PR_TRUE; + } + } + if (_PR_PID_REAPED == pRec->state) { + if (exitCode) { + *exitCode = pRec->exitStatus; + } + } else { + PR_ASSERT(interrupted); + retVal = PR_FAILURE; + } + DeletePidTable(pRec); + PR_DestroyCondVar(pRec->reapedCV); + PR_DELETE(pRec); + } else { + PR_ASSERT(_PR_PID_REAPED == pRec->state); + PR_ASSERT(NULL == pRec->reapedCV); + DeletePidTable(pRec); + if (exitCode) { + *exitCode = pRec->exitStatus; + } + PR_DELETE(pRec); + } + PR_DELETE(process); + +done: + PR_Unlock(pr_wp.ml); + return retVal; +} /* _MD_WaitUnixProcess */ + +PRStatus _MD_KillUnixProcess(PRProcess *process) +{ + PRErrorCode prerror; + PRInt32 oserror; + + if (kill(process->md.pid, SIGKILL) == 0) { + return PR_SUCCESS; + } + oserror = errno; + switch (oserror) { + case EPERM: + prerror = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ESRCH: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, oserror); + return PR_FAILURE; +} /* _MD_KillUnixProcess */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxrng.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxrng.c new file mode 100644 index 00000000..9099c5ff --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxrng.c @@ -0,0 +1,340 @@ +/* -*- 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 ***** */ + + +#include "primpl.h" + +#include +#include +#include +#include + + +#if defined(SOLARIS) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + hrtime_t t; + t = gethrtime(); + if (t) { + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); + } + return 0; +} + +#elif defined(SUNOS4) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(HPUX) + +#ifdef __ia64 +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + PRUint64 t; + + t = _Asm_mov_from_ar(_AREG44); + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} +#else +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + extern int ret_cr16(); + int cr16val; + + cr16val = ret_cr16(); + return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val))); +} +#endif + +#elif defined(OSF1) + +#include + +/* + * Use the "get the cycle counter" instruction on the alpha. + * The low 32 bits completely turn over in less than a minute. + * The high 32 bits are some non-counter gunk that changes sometimes. + */ +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + unsigned long t; + +#ifdef __GNUC__ + __asm__("rpcc %0" : "=r" (t)); +#else + t = asm("rpcc %v0"); +#endif + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} + +#elif defined(VMS) + +#include + +/* + * Use the "get the cycle counter" instruction on the alpha. + * The low 32 bits completely turn over in less than a minute. + * The high 32 bits are some non-counter gunk that changes sometimes. + */ +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + uint64 t; + + t = __RPCC(); + return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} + +#elif defined(AIX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif (defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD)) +#include +#include +#include + +static int fdDevRandom; +static PRCallOnceType coOpenDevRandom; + +static PRStatus OpenDevRandom( void ) +{ + fdDevRandom = open( "/dev/random", O_RDONLY ); + return((-1 == fdDevRandom)? PR_FAILURE : PR_SUCCESS ); +} /* end OpenDevRandom() */ + +static size_t GetDevRandom( void *buf, size_t size ) +{ + int bytesIn; + int rc; + + rc = PR_CallOnce( &coOpenDevRandom, OpenDevRandom ); + if ( PR_FAILURE == rc ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + return(0); + } + + bytesIn = read( fdDevRandom, buf, size ); + if ( -1 == bytesIn ) { + _PR_MD_MAP_READ_ERROR( errno ); + return(0); + } + + return( bytesIn ); +} /* end GetDevRandom() */ + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return(GetDevRandom( buf, maxbytes )); +} + +#elif defined(NCR) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(IRIX) +#include +#undef PRIVATE +#include +#include +#include +#include +#include + +static size_t GetHighResClock(void *buf, size_t maxbuf) +{ + unsigned phys_addr, raddr, cycleval; + static volatile unsigned *iotimer_addr = NULL; + static int tries = 0; + static int cntr_size; + int mfd; + unsigned s0[2]; + +#ifndef SGI_CYCLECNTR_SIZE +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ +#endif + + if (iotimer_addr == NULL) { + if (tries++ > 1) { + /* Don't keep trying if it didn't work */ + return 0; + } + + /* + ** For SGI machines we can use the cycle counter, if it has one, + ** to generate some truly random numbers + */ + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); + if (phys_addr) { + int pgsz = getpagesize(); + int pgoffmask = pgsz - 1; + + raddr = phys_addr & ~pgoffmask; + mfd = open("/dev/mmem", O_RDONLY); + if (mfd < 0) { + return 0; + } + iotimer_addr = (unsigned *) + mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); + if (iotimer_addr == (unsigned*)-1) { + close(mfd); + iotimer_addr = NULL; + return 0; + } + iotimer_addr = (unsigned*) + ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); + /* + * The file 'mfd' is purposefully not closed. + */ + cntr_size = syssgi(SGI_CYCLECNTR_SIZE); + if (cntr_size < 0) { + struct utsname utsinfo; + + /* + * We must be executing on a 6.0 or earlier system, since the + * SGI_CYCLECNTR_SIZE call is not supported. + * + * The only pre-6.1 platforms with 64-bit counters are + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). + */ + uname(&utsinfo); + if (!strncmp(utsinfo.machine, "IP19", 4) || + !strncmp(utsinfo.machine, "IP21", 4)) + cntr_size = 64; + else + cntr_size = 32; + } + cntr_size /= 8; /* Convert from bits to bytes */ + } + } + + s0[0] = *iotimer_addr; + if (cntr_size > 4) + s0[1] = *(iotimer_addr + 1); + memcpy(buf, (char *)&s0[0], cntr_size); + return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size); +} + +#elif defined(SONY) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +#elif defined(SNI) +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} + +#elif defined(NEC) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} +#elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \ + || defined(QNX) || defined(DARWIN) +#include + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} +#else +#error! Platform undefined +#endif /* defined(SOLARIS) */ + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + struct timeval tv; + int n = 0; + int s; + + n += GetHighResClock(buf, size); + size -= n; + + GETTIMEOFDAY(&tv); + + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + if ( size > 0 ) { + s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec)); + size -= s; + n += s; + } + + return n; +} /* end _PR_MD_GetRandomNoise() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxshm.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxshm.c new file mode 100644 index 00000000..6f3192fd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxshm.c @@ -0,0 +1,658 @@ +/* -*- 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 ***** */ + +/* +** uxshm.c -- Unix Implementations NSPR Named Shared Memory +** +** +** lth. Jul-1999. +** +*/ +#include +#include +#include +#include +#include "primpl.h" +#include + +extern PRLogModuleInfo *_pr_shm_lm; + + +#define NSPR_IPC_SHM_KEY 'b' +/* +** Implementation for System V +*/ +#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY +#include +#include +#include +#include + +#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory +#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory +#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory +#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory +#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + PRStatus rc = PR_SUCCESS; + key_t key; + PRSharedMemory *shm; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return( NULL ); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return( NULL ); + } + + shm->ipcname = (char*)PR_MALLOC( strlen( ipcname ) + 1 ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + return( NULL ); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + /* create the file first */ + if ( flags & PR_SHM_CREATE ) { + int osfd = open( shm->ipcname, (O_RDWR | O_CREAT), shm->mode ); + if ( -1 == osfd ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + if ( close(osfd) == -1 ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + } + + /* hash the shm.name to an ID */ + key = ftok( shm->ipcname, NSPR_IPC_SHM_KEY ); + if ( -1 == key ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): ftok() failed on name: %s", shm->ipcname)); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return( NULL ); + } + + /* get the shared memory */ + if ( flags & PR_SHM_CREATE ) { + shm->id = shmget( key, shm->size, ( shm->mode | IPC_CREAT|IPC_EXCL)); + if ( shm->id >= 0 ) { + return( shm ); + } + if ((errno == EEXIST) && (flags & PR_SHM_EXCL)) { + PR_SetError( PR_FILE_EXISTS_ERROR, errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shmget() exclusive failed, errno: %d", errno)); + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + return(NULL); + } + } + + shm->id = shmget( key, shm->size, shm->mode ); + if ( -1 == shm->id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shmget() failed, errno: %d", errno)); + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + return(NULL); + } + + return( shm ); +} /* end _MD_OpenSharedMemory() */ + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + void *addr; + PRUint32 aFlags = shm->mode; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + aFlags |= (flags & PR_SHM_READONLY )? SHM_RDONLY : 0; + + addr = shmat( shm->id, NULL, aFlags ); + if ( (void*)-1 == addr ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): shmat() failed on name: %s, OsError: %d", + shm->ipcname, PR_GetOSError() )); + addr = NULL; + } + + return addr; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + PRIntn urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = shmdt( addr ); + if ( -1 == urc ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DetachSharedMemory(): shmdt() failed on name: %s", shm->ipcname )); + } + + return rc; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + PR_FREEIF(shm->ipcname); + PR_DELETE(shm); + + return PR_SUCCESS; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PRStatus rc = PR_SUCCESS; + key_t key; + int id; + PRIntn urc; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return(PR_FAILURE); + } + + /* create the file first */ + { + int osfd = open( ipcname, (O_RDWR | O_CREAT), 0666 ); + if ( -1 == osfd ) { + _PR_MD_MAP_OPEN_ERROR( errno ); + return( PR_FAILURE ); + } + if ( close(osfd) == -1 ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + return( PR_FAILURE ); + } + } + + /* hash the shm.name to an ID */ + key = ftok( ipcname, NSPR_IPC_SHM_KEY ); + if ( -1 == key ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): ftok() failed on name: %s", ipcname)); + } + + id = shmget( key, 0, 0 ); + if ( -1 == id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shmget() failed, errno: %d", errno)); + return(PR_FAILURE); + } + + urc = shmctl( id, IPC_RMID, NULL ); + if ( -1 == urc ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shmctl() failed on name: %s", ipcname )); + return(PR_FAILURE); + } + + urc = unlink( ipcname ); + if ( -1 == urc ) { + _PR_MD_MAP_UNLINK_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): unlink() failed: %s", ipcname )); + return(PR_FAILURE); + } + + return rc; +} /* end _MD_DeleteSharedMemory() */ + +/* +** Implementation for Posix +*/ +#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY +#include + +#define _MD_OPEN_SHARED_MEMORY _MD_OpenSharedMemory +#define _MD_ATTACH_SHARED_MEMORY _MD_AttachSharedMemory +#define _MD_DETACH_SHARED_MEMORY _MD_DetachSharedMemory +#define _MD_CLOSE_SHARED_MEMORY _MD_CloseSharedMemory +#define _MD_DELETE_SHARED_MEMORY _MD_DeleteSharedMemory + +struct _MDSharedMemory { + int handle; +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + PRStatus rc = PR_SUCCESS; + PRInt32 end; + PRSharedMemory *shm; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return( NULL ); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return( NULL ); + } + + shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + return( NULL ); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + /* + ** Create the shared memory + */ + if ( flags & PR_SHM_CREATE ) { + int oflag = (O_CREAT | O_RDWR); + + if ( flags & PR_SHM_EXCL ) + oflag |= O_EXCL; + shm->id = shm_open( shm->ipcname, oflag, shm->mode ); + } else { + shm->id = shm_open( shm->ipcname, O_RDWR, shm->mode ); + } + + if ( -1 == shm->id ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): shm_open failed: %s, OSError: %d", + shm->ipcname, PR_GetOSError())); + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } + + end = ftruncate( shm->id, shm->size ); + if ( -1 == end ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): ftruncate failed, OSError: %d", + PR_GetOSError())); + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } + + return(shm); +} /* end _MD_OpenSharedMemory() */ + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + void *addr; + PRIntn prot = (PROT_READ | PROT_WRITE); + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + if ( PR_SHM_READONLY == flags) + prot ^= PROT_WRITE; + + addr = mmap( (void*)0, shm->size, prot, MAP_SHARED, shm->id, 0 ); + if ((void*)-1 == addr ) + { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): mmap failed: %s, errno: %d", + shm->ipcname, PR_GetOSError())); + addr = NULL; + } else { + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_AttachSharedMemory(): name: %s, attached at: %p", shm->ipcname, addr)); + } + + return addr; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + PRIntn urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = munmap( addr, shm->size ); + if ( -1 == urc ) + { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DetachSharedMemory(): munmap failed: %s, errno: %d", + shm->ipcname, PR_GetOSError())); + } + return rc; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + int urc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + urc = close( shm->id ); + if ( -1 == urc ) { + _PR_MD_MAP_CLOSE_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_CloseSharedMemory(): close() failed, error: %d", PR_GetOSError())); + return(PR_FAILURE); + } + PR_DELETE( shm->ipcname ); + PR_DELETE( shm ); + return PR_SUCCESS; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PRStatus rc = PR_SUCCESS; + PRUintn urc; + char ipcname[PR_IPC_NAME_SIZE]; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError( PR_UNKNOWN_ERROR , errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_OpenSharedMemory(): _PR_MakeNativeIPCName() failed: %s", name )); + return rc; + } + + urc = shm_unlink( ipcname ); + if ( -1 == urc ) { + rc = PR_FAILURE; + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): shm_unlink failed: %s, errno: %d", + ipcname, PR_GetOSError())); + } else { + PR_LOG( _pr_shm_lm, PR_LOG_DEBUG, + ("_MD_DeleteSharedMemory(): %s, success", ipcname)); + } + + return rc; +} /* end _MD_DeleteSharedMemory() */ +#endif + + + +/* +** Unix implementation for anonymous memory (file) mapping +*/ +extern PRLogModuleInfo *_pr_shma_lm; + +#include + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + PRFileMap *fm = NULL; + PRFileDesc *fd; + int osfd; + PRIntn urc; + PRIntn mode = 0600; + char *genName; + pid_t pid = getpid(); /* for generating filename */ + PRThread *tid = PR_GetCurrentThread(); /* for generating filename */ + int incr; /* for generating filename */ + const int maxTries = 20; /* maximum # attempts at a unique filename */ + PRInt64 size64; /* 64-bit version of 'size' */ + + /* + ** generate a filename from input and runtime environment + ** open the file, unlink the file. + ** make maxTries number of attempts at uniqueness in the filename + */ + for ( incr = 0; incr < maxTries ; incr++ ) { + genName = PR_smprintf( "%s/.NSPR-AFM-%d-%p.%d", + dirName, (int) pid, tid, incr ); + if ( NULL == genName ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_snprintf(): failed, generating filename")); + goto Finished; + } + + /* create the file */ + osfd = open( genName, (O_CREAT | O_EXCL | O_RDWR), mode ); + if ( -1 == osfd ) { + if ( EEXIST == errno ) { + PR_smprintf_free( genName ); + continue; /* name exists, try again */ + } else { + _PR_MD_MAP_OPEN_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): open(): failed, filename: %s, errno: %d", + genName, PR_GetOSError())); + PR_smprintf_free( genName ); + goto Finished; + } + } + break; /* name generation and open successful, break; */ + } /* end for() */ + + if ( incr == maxTries ) { + PR_ASSERT( -1 == osfd ); + PR_ASSERT( EEXIST == errno ); + _PR_MD_MAP_OPEN_ERROR( errno ); + goto Finished; + } + + urc = unlink( genName ); + if ( -1 == urc ) { + _PR_MD_MAP_UNLINK_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): failed on unlink(), errno: %d", errno)); + PR_smprintf_free( genName ); + close( osfd ); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): unlink(): %s", genName )); + + PR_smprintf_free( genName ); + + fd = PR_ImportFile( osfd ); + if ( NULL == fd ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_ImportFile(): failed")); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): fd: %p", fd )); + + urc = ftruncate( fd->secret->md.osfd, size ); + if ( -1 == urc ) { + _PR_MD_MAP_DEFAULT_ERROR( errno ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): failed on ftruncate(), errno: %d", errno)); + PR_Close( fd ); + goto Finished; + } + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): ftruncate(): size: %d", size )); + + LL_UI2L(size64, size); /* PRSize (size_t) is unsigned */ + fm = PR_CreateFileMap( fd, size64, prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("PR_OpenAnonFileMap(): failed")); + PR_Close( fd ); + goto Finished; + } + fm->md.isAnonFM = PR_TRUE; /* set fd close */ + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_CreateFileMap(): fm: %p", fm )); + +Finished: + return(fm); +} /* end md_OpenAnonFileMap() */ + +/* +** _md_ExportFileMapAsString() +** +** +*/ +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + PRIntn written; + PRIntn prot = (PRIntn)fm->prot; + + written = PR_snprintf( buf, bufSize, "%ld:%d", + fm->fd->secret->md.osfd, prot ); + + return((written == -1)? PR_FAILURE : PR_SUCCESS); +} /* end _md_ExportFileMapAsString() */ + + +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +) +{ + PRStatus rc; + PRInt32 osfd; + PRIntn prot; /* really: a PRFileMapProtect */ + PRFileDesc *fd; + PRFileMap *fm = NULL; /* default return value */ + PRFileInfo64 info; + + PR_sscanf( fmstring, "%ld:%d", &osfd, &prot ); + + /* import the os file descriptor */ + fd = PR_ImportFile( osfd ); + if ( NULL == fd ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_ImportFile() failed")); + goto Finished; + } + + rc = PR_GetOpenFileInfo64( fd, &info ); + if ( PR_FAILURE == rc ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_GetOpenFileInfo64() failed")); + goto Finished; + } + + fm = PR_CreateFileMap( fd, info.size, (PRFileMapProtect)prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_CreateFileMap() failed")); + } + +Finished: + return(fm); +} /* end _md_ImportFileMapFromString() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxwrap.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxwrap.c new file mode 100644 index 00000000..8f69de86 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxwrap.c @@ -0,0 +1,548 @@ +/* -*- 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 ***** */ + +/* + *------------------------------------------------------------------------ + * File: uxwrap.c + * + * Our wrapped versions of the Unix select() and poll() system calls. + * + *------------------------------------------------------------------------ + */ + +#include "primpl.h" + +#if defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) || defined(QNX) +/* Do not wrap select() and poll(). */ +#else /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ +/* The include files for select() */ +#ifdef IRIX +#include +#include +#endif + +#include +#include +#include + +#define ZAP_SET(_to, _width) \ + PR_BEGIN_MACRO \ + memset(_to, 0, \ + ((_width + 8*sizeof(int)-1) / (8*sizeof(int))) \ + * sizeof(int) \ + ); \ + PR_END_MACRO + +/* see comments in ns/cmd/xfe/mozilla.c (look for "PR_XGetXtHackFD") */ +static int _pr_xt_hack_fd = -1; + +int PR_XGetXtHackFD(void) +{ + int fds[2]; + + if (_pr_xt_hack_fd == -1) { + if (!pipe(fds)) { + _pr_xt_hack_fd = fds[0]; + } + } + return _pr_xt_hack_fd; +} + +static int (*_pr_xt_hack_okayToReleaseXLock)(void) = 0; + +void PR_SetXtHackOkayToReleaseXLockFn(int (*fn)(void)) +{ + _pr_xt_hack_okayToReleaseXLock = fn; +} + + +/* + *----------------------------------------------------------------------- + * select() -- + * + * Wrap up the select system call so that we can deschedule + * a thread that tries to wait for i/o. + * + *----------------------------------------------------------------------- + */ + +#if defined(HPUX9) +int select(size_t width, int *rl, int *wl, int *el, const struct timeval *tv) +#elif defined(NEXTSTEP) +int wrap_select(int width, fd_set *rd, fd_set *wr, fd_set *ex, + const struct timeval *tv) +#elif defined(AIX_RENAME_SELECT) +int wrap_select(unsigned long width, void *rl, void *wl, void *el, + struct timeval *tv) +#elif defined(_PR_SELECT_CONST_TIMEVAL) +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, + const struct timeval *tv) +#else +int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) +#endif +{ + int osfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRInt32 pdcnt; + PRIntervalTime timeout; + int retVal; +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) + fd_set *rd = (fd_set*) rl; + fd_set *wr = (fd_set*) wl; + fd_set *ex = (fd_set*) el; +#endif + +#if 0 + /* + * Easy special case: zero timeout. Simply call the native + * select() with no fear of blocking. + */ + if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) { +#if defined(HPUX9) || defined(AIX_RENAME_SELECT) + return _MD_SELECT(width, rl, wl, el, tv); +#else + return _MD_SELECT(width, rd, wr, ex, tv); +#endif + } +#endif + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { + return _MD_SELECT(width, rd, wr, ex, tv); + } +#endif + + if (width < 0 || width > FD_SETSIZE) { + errno = EINVAL; + return -1; + } + + /* Compute timeout */ + if (tv) { + /* + * These acceptable ranges for t_sec and t_usec are taken + * from the select() man pages. + */ + if (tv->tv_sec < 0 || tv->tv_sec > 100000000 + || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { + errno = EINVAL; + return -1; + } + + /* Convert microseconds to ticks */ + timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec); + } else { + /* tv being a NULL pointer means blocking indefinitely */ + timeout = PR_INTERVAL_NO_TIMEOUT; + } + + /* Check for no descriptors case (just doing a timeout) */ + if ((!rd && !wr && !ex) || !width) { + PR_Sleep(timeout); + return 0; + } + + /* + * Set up for PR_Poll(). The PRPollDesc array is allocated + * dynamically. If this turns out to have high performance + * penalty, one can change to use a large PRPollDesc array + * on the stack, and allocate dynamically only when it turns + * out to be not large enough. + * + * I allocate an array of size 'width', which is the maximum + * number of fds we may need to poll. + */ + unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc)); + if (!unixpds) { + errno = ENOMEM; + return -1; + } + + pdcnt = 0; + unixpd = unixpds; + for (osfd = 0; osfd < width; osfd++) { + int in_flags = 0; + if (rd && FD_ISSET(osfd, rd)) { + in_flags |= _PR_UNIX_POLL_READ; + } + if (wr && FD_ISSET(osfd, wr)) { + in_flags |= _PR_UNIX_POLL_WRITE; + } + if (ex && FD_ISSET(osfd, ex)) { + in_flags |= _PR_UNIX_POLL_EXCEPT; + } + if (in_flags) { + unixpd->osfd = osfd; + unixpd->in_flags = in_flags; + unixpd->out_flags = 0; + unixpd++; + pdcnt++; + } + } + + /* + * see comments in mozilla/cmd/xfe/mozilla.c (look for + * "PR_XGetXtHackFD") + */ + { + int needToLockXAgain; + + needToLockXAgain = 0; + if (rd && (_pr_xt_hack_fd != -1) + && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked() + && (!_pr_xt_hack_okayToReleaseXLock + || _pr_xt_hack_okayToReleaseXLock())) { + PR_XUnlock(); + needToLockXAgain = 1; + } + + /* This is the potentially blocking step */ + retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); + + if (needToLockXAgain) { + PR_XLock(); + } + } + + if (retVal > 0) { + /* Compute select results */ + if (rd) ZAP_SET(rd, width); + if (wr) ZAP_SET(wr, width); + if (ex) ZAP_SET(ex, width); + + /* + * The return value can be either the number of ready file + * descriptors or the number of set bits in the three fd_set's. + */ + retVal = 0; /* we're going to recompute */ + eunixpd = unixpds + pdcnt; + for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { + if (unixpd->out_flags) { + int nbits = 0; /* The number of set bits on for this fd */ + + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { + errno = EBADF; + PR_LOG(_pr_io_lm, PR_LOG_ERROR, + ("select returns EBADF for %d", unixpd->osfd)); + retVal = -1; + break; + } + /* + * If a socket has a pending error, it is considered + * both readable and writable. (See W. Richard Stevens, + * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3, + * pp. 153-154.) We also consider a socket readable if + * it has a hangup condition. + */ + if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ) + && (unixpd->out_flags & (_PR_UNIX_POLL_READ + | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) { + FD_SET(unixpd->osfd, rd); + nbits++; + } + if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) + && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE + | _PR_UNIX_POLL_ERR))) { + FD_SET(unixpd->osfd, wr); + nbits++; + } + if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) + && (unixpd->out_flags & PR_POLL_EXCEPT)) { + FD_SET(unixpd->osfd, ex); + nbits++; + } + PR_ASSERT(nbits > 0); +#if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX) + retVal += nbits; +#else /* IRIX */ + retVal += 1; +#endif + } + } + } + + PR_ASSERT(tv || retVal != 0); + PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal)); + PR_DELETE(unixpds); + + return retVal; +} + +/* + * Redefine poll, when supported on platforms, for local threads + */ + +/* + * I am commenting out the poll() wrapper for Linux for now + * because it is difficult to define _MD_POLL that works on all + * Linux varieties. People reported that glibc 2.0.7 on Debian + * 2.0 Linux machines doesn't have the __syscall_poll symbol + * defined. (WTC 30 Nov. 1998) + */ +#if defined(_PR_POLL_AVAILABLE) && !defined(LINUX) + +/* + *----------------------------------------------------------------------- + * poll() -- + * + * RETURN VALUES: + * -1: fails, errno indicates the error. + * 0: timed out, the revents bitmasks are not set. + * positive value: the number of file descriptors for which poll() + * has set the revents bitmask. + * + *----------------------------------------------------------------------- + */ + +#include + +#if defined(AIX_RENAME_SELECT) +int wrap_poll(void *listptr, unsigned long nfds, long timeout) +#elif (defined(AIX) && !defined(AIX_RENAME_SELECT)) +int poll(void *listptr, unsigned long nfds, long timeout) +#elif defined(OSF1) || (defined(HPUX) && !defined(HPUX9)) +int poll(struct pollfd filedes[], unsigned int nfds, int timeout) +#elif defined(HPUX9) +int poll(struct pollfd filedes[], int nfds, int timeout) +#elif defined(NETBSD) +int poll(struct pollfd *filedes, nfds_t nfds, int timeout) +#elif defined(OPENBSD) +int poll(struct pollfd *filedes, int nfds, int timeout) +#elif defined(FREEBSD) +int poll(struct pollfd *filedes, unsigned nfds, int timeout) +#else +int poll(struct pollfd *filedes, unsigned long nfds, int timeout) +#endif +{ +#ifdef AIX + struct pollfd *filedes = (struct pollfd *) listptr; +#endif + struct pollfd *pfd, *epfd; + _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; + PRIntervalTime ticks; + PRInt32 pdcnt; + int ready; + + /* + * Easy special case: zero timeout. Simply call the native + * poll() with no fear of blocking. + */ + if (timeout == 0) { +#if defined(AIX) + return _MD_POLL(listptr, nfds, timeout); +#else + return _MD_POLL(filedes, nfds, timeout); +#endif + } + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { + return _MD_POLL(filedes, nfds, timeout); + } +#endif + + /* We do not support the pollmsg structures on AIX */ +#ifdef AIX + PR_ASSERT((nfds & 0xff00) == 0); +#endif + + if (timeout < 0 && timeout != -1) { + errno = EINVAL; + return -1; + } + + /* Convert timeout from miliseconds to ticks */ + if (timeout == -1) { + ticks = PR_INTERVAL_NO_TIMEOUT; + } else { + ticks = PR_MillisecondsToInterval(timeout); + } + + /* Check for no descriptor case (just do a timeout) */ + if (nfds == 0) { + PR_Sleep(ticks); + return 0; + } + + unixpds = (_PRUnixPollDesc *) + PR_MALLOC(nfds * sizeof(_PRUnixPollDesc)); + if (NULL == unixpds) { + errno = EAGAIN; + return -1; + } + + pdcnt = 0; + epfd = filedes + nfds; + unixpd = unixpds; + for (pfd = filedes; pfd < epfd; pfd++) { + /* + * poll() ignores negative fd's. + */ + if (pfd->fd >= 0) { + unixpd->osfd = pfd->fd; +#ifdef _PR_USE_POLL + unixpd->in_flags = pfd->events; +#else + /* + * Map the poll events to one of the three that can be + * represented by the select fd_sets: + * POLLIN, POLLRDNORM ===> readable + * POLLOUT, POLLWRNORM ===> writable + * POLLPRI, POLLRDBAND ===> exception + * POLLNORM, POLLWRBAND (and POLLMSG on some platforms) + * are ignored. + * + * The output events POLLERR and POLLHUP are never turned on. + * POLLNVAL may be turned on. + */ + unixpd->in_flags = 0; + if (pfd->events & (POLLIN +#ifdef POLLRDNORM + | POLLRDNORM +#endif + )) { + unixpd->in_flags |= _PR_UNIX_POLL_READ; + } + if (pfd->events & (POLLOUT +#ifdef POLLWRNORM + | POLLWRNORM +#endif + )) { + unixpd->in_flags |= _PR_UNIX_POLL_WRITE; + } + if (pfd->events & (POLLPRI +#ifdef POLLRDBAND + | POLLRDBAND +#endif + )) { + unixpd->in_flags |= PR_POLL_EXCEPT; + } +#endif /* _PR_USE_POLL */ + unixpd->out_flags = 0; + unixpd++; + pdcnt++; + } + } + + ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, ticks); + if (-1 == ready) { + if (PR_GetError() == PR_PENDING_INTERRUPT_ERROR) { + errno = EINTR; /* XXX we aren't interrupted by a signal, but... */ + } else { + errno = PR_GetOSError(); + } + } + if (ready <= 0) { + goto done; + } + + /* + * Copy the out_flags from the _PRUnixPollDesc structures to the + * user's pollfd structures and free the allocated memory + */ + unixpd = unixpds; + for (pfd = filedes; pfd < epfd; pfd++) { + pfd->revents = 0; + if (pfd->fd >= 0) { +#ifdef _PR_USE_POLL + pfd->revents = unixpd->out_flags; +#else + if (0 != unixpd->out_flags) { + if (unixpd->out_flags & _PR_UNIX_POLL_READ) { + if (pfd->events & POLLIN) { + pfd->revents |= POLLIN; + } +#ifdef POLLRDNORM + if (pfd->events & POLLRDNORM) { + pfd->revents |= POLLRDNORM; + } +#endif + } + if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) { + if (pfd->events & POLLOUT) { + pfd->revents |= POLLOUT; + } +#ifdef POLLWRNORM + if (pfd->events & POLLWRNORM) { + pfd->revents |= POLLWRNORM; + } +#endif + } + if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) { + if (pfd->events & POLLPRI) { + pfd->revents |= POLLPRI; + } +#ifdef POLLRDBAND + if (pfd->events & POLLRDBAND) { + pfd->revents |= POLLRDBAND; + } +#endif + } + if (unixpd->out_flags & _PR_UNIX_POLL_ERR) { + pfd->revents |= POLLERR; + } + if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { + pfd->revents |= POLLNVAL; + } + if (unixpd->out_flags & _PR_UNIX_POLL_HUP) { + pfd->revents |= POLLHUP; + } + } +#endif /* _PR_USE_POLL */ + unixpd++; + } + } + +done: + PR_DELETE(unixpds); + return ready; +} + +#endif /* !defined(LINUX) */ + +#endif /* defined(_PR_PTHREADS) || defined(_PR_GLOBAL_THREADS_ONLY) */ + +/* uxwrap.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/Makefile.in new file mode 100644 index 00000000..c97c9821 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/Makefile.in @@ -0,0 +1,121 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +CSRCS = \ + w16null.c \ + w16thred.c \ + w16proc.c \ + w16fmem.c \ + w16sock.c \ + w16mem.c \ + w16io.c \ + w16gc.c \ + w16error.c \ + w16stdio.c \ + w16callb.c \ + ntinrval.c \ + $(NULL) +else +ifeq ($(OS_TARGET), WIN95) +CSRCS = \ + ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + w95thred.c \ + w95io.c \ + w95cv.c \ + w32rng.c \ + w95sock.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32shm.c \ + w95dllmain.c \ + $(NULL) +else +CSRCS = \ + ntdllmn.c \ + ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + ntthread.c \ + ntio.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c \ + $(NULL) +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + +# Bug 122433 workaround: disable global optimization (-Og-) on ntio.c. +ifdef BUILD_OPT +ifeq ($(OS_TARGET), WINNT) +ifndef NS_USE_GCC +$(OBJDIR)/ntio.$(OBJ_SUFFIX): ntio.c + @$(MAKE_OBJDIR) + $(CC) -Fo$@ -c $(CFLAGS) -Og- $< +endif +endif +endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntdllmn.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntdllmn.c new file mode 100644 index 00000000..fa8d25f6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntdllmn.c @@ -0,0 +1,88 @@ +/* -*- 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 ***** */ + +/* + * The DLL entry point (DllMain) for NSPR. + * + * The only reason we use DLLMain() now is to find out whether + * the NSPR DLL is statically or dynamically loaded. When + * dynamically loaded, we cannot use static thread-local storage. + * However, static TLS is faster than the TlsXXX() functions. + * So we want to use static TLS whenever we can. A global + * variable _pr_use_static_tls is set in DllMain() during process + * attachment to indicate whether it is safe to use static TLS + * or not. + */ + +#include +#include + +extern BOOL _pr_use_static_tls; /* defined in ntthread.c */ + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ +PRThread *me; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + /* + * If lpvReserved is NULL, we are dynamically loaded + * and therefore can't use static thread-local storage. + */ + if (lpvReserved == NULL) { + _pr_use_static_tls = FALSE; + } else { + _pr_use_static_tls = TRUE; + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + if (_pr_initialized) { + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + } + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntgc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntgc.c new file mode 100644 index 00000000..12af4846 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntgc.c @@ -0,0 +1,126 @@ +/* -*- 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 ***** */ + +/* + * GC related routines + * + */ +#include +#include "primpl.h" + +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ +#if defined(_X86_) + CONTEXT context; + context.ContextFlags = CONTEXT_INTEGER; + + if (_PR_IS_NATIVE_THREAD(t)) { + context.ContextFlags |= CONTEXT_CONTROL; + if (GetThreadContext(t->md.handle, &context)) { + t->md.gcContext[0] = context.Eax; + t->md.gcContext[1] = context.Ebx; + t->md.gcContext[2] = context.Ecx; + t->md.gcContext[3] = context.Edx; + t->md.gcContext[4] = context.Esi; + t->md.gcContext[5] = context.Edi; + t->md.gcContext[6] = context.Esp; + t->md.gcContext[7] = context.Ebp; + *np = PR_NUM_GCREGS; + } else { + PR_ASSERT(0);/* XXX */ + } + } else { + /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * This code is extremely machine dependant and completely + * undocumented by MS. Its only known to work experimentally. + * Ready for a walk on the wild * side? + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ + +#if !defined WIN95 // Win95 does not have fibers + int *fiberData = t->md.fiber_id; + + /* I found these offsets by disassembling SwitchToFiber(). + * Are your palms sweating yet? + */ + + /* + ** EAX is on the stack (ESP+0) + ** EDX is on the stack (ESP+4) + ** ECX is on the stack (ESP+8) + */ + t->md.gcContext[0] = 0; /* context.Eax */ + t->md.gcContext[1] = fiberData[0x2e]; /* context.Ebx */ + t->md.gcContext[2] = 0; /* context.Ecx */ + t->md.gcContext[2] = 0; /* context.Edx */ + t->md.gcContext[4] = fiberData[0x2d]; /* context.Esi */ + t->md.gcContext[5] = fiberData[0x2c]; /* context.Edi */ + t->md.gcContext[6] = fiberData[0x36]; /* context.Esp */ + t->md.gcContext[7] = fiberData[0x32]; /* context.Ebp */ + *np = PR_NUM_GCREGS; +#endif + } + return (PRWord *)&t->md.gcContext; +#elif defined(_ALPHA_) +#endif /* defined(_X86_) */ +} + +/* This function is not used right now, but is left as a reference. + * If you ever need to get the fiberID from the currently running fiber, + * this is it. + */ +void * +GetMyFiberID() +{ +#if defined(_X86_) && !defined(__MINGW32__) + void *fiberData; + + /* A pointer to our tib entry is found at FS:[18] + * At offset 10h is the fiberData pointer. The context of the + * fiber is stored in there. + */ + __asm { + mov EDX, FS:[18h] + mov EAX, DWORD PTR [EDX+10h] + mov [fiberData], EAX + } + + return fiberData; +#elif defined(_ALPHA_) +#endif /* defined(_X86_) */ +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntinrval.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntinrval.c new file mode 100644 index 00000000..494f6e83 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntinrval.c @@ -0,0 +1,124 @@ +/* -*- 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 ***** */ + +/* + * NT interval timers + * + */ + +#include "primpl.h" + +#if defined(WIN16) +#include +#define QueryPerformanceFrequency(x) FALSE +#define QueryPerformanceCounter(x) FALSE +#endif + +static PRIntn _nt_bitShift = 0; +static PRInt32 _nt_ticksPerSec = -1; + +void +_PR_MD_INTERVAL_INIT() +{ + LARGE_INTEGER count; + + if (QueryPerformanceFrequency(&count)) { + /* + * HighPart is signed (LONG). Assert that its sign bit is 0 + * because we will be right shifting it. LowPart is unsigned + * (DWORD). + */ + PR_ASSERT(count.HighPart >= 0); + while(count.HighPart) { + count.LowPart = (count.HighPart << 31) + (count.LowPart >> 1); + count.HighPart >>= 1; + _nt_bitShift++; + } + while(count.LowPart > PR_INTERVAL_MAX) { + count.LowPart >>= 1; + _nt_bitShift++; + } + + /* + * We can't use the performance counter if after + * normalization we are left with fewer than 32 bits. + */ + if (_nt_bitShift <= 32) { + _nt_ticksPerSec = count.LowPart; + PR_ASSERT(_nt_ticksPerSec > PR_INTERVAL_MIN); + return; + } + } + _nt_ticksPerSec = -1; +} + +PRIntervalTime +_PR_MD_GET_INTERVAL() +{ + LARGE_INTEGER count; + + /* Sadly; nspr requires the interval to range from 1000 ticks per second + * to only 100000 ticks per second; QueryPerformanceCounter is too high + * resolution... + */ + if (_nt_ticksPerSec != -1) { + (void)QueryPerformanceCounter(&count); + PR_ASSERT(_nt_bitShift <= 32); + if (_nt_bitShift == 32) { + return (PRUint32)count.HighPart; + } else { + return (PRUint32)((count.HighPart << (32 - _nt_bitShift)) + + (count.LowPart >> _nt_bitShift)); + } + } else +#if defined(__MINGW32__) + return time(); +#elif defined(WIN16) + return clock(); /* milliseconds since application start */ +#else + return GetTickCount(); /* milliseconds since system start */ +#endif +} + +PRIntervalTime +_PR_MD_INTERVAL_PER_SEC() +{ + if (_nt_ticksPerSec != -1) + return _nt_ticksPerSec; + else + return 1000; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntio.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntio.c new file mode 100644 index 00000000..defaae4d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntio.c @@ -0,0 +1,4684 @@ +/* -*- 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 ***** */ + +/* Windows NT IO module + * + * This module handles IO for LOCAL_SCOPE and GLOBAL_SCOPE threads. + * For LOCAL_SCOPE threads, we're using NT fibers. For GLOBAL_SCOPE threads + * we're using NT-native threads. + * + * When doing IO, we want to use completion ports for optimal performance + * with fibers. But if we use completion ports for all IO, it is difficult + * to project a blocking model with GLOBAL_SCOPE threads. To handle this + * we create an extra thread for completing IO for GLOBAL_SCOPE threads. + * We don't really want to complete IO on a separate thread for LOCAL_SCOPE + * threads because it means extra context switches, which are really slow + * on NT... Since we're using a single completion port, some IO will + * be incorrectly completed on the GLOBAL_SCOPE IO thread; this will mean + * extra context switching; but I don't think there is anything I can do + * about it. + */ + +#include "primpl.h" +#include "pprmwait.h" +#include +#include + +static HANDLE _pr_completion_port; +static PRThread *_pr_io_completion_thread; + +#define RECYCLE_SIZE 512 +static struct _MDLock _pr_recycle_lock; +static PRInt32 _pr_recycle_array[RECYCLE_SIZE]; +static PRInt32 _pr_recycle_tail = 0; + +__declspec(thread) PRThread *_pr_io_restarted_io = NULL; +DWORD _pr_io_restartedIOIndex; /* The thread local storage slot for each + * thread is initialized to NULL. */ + +PRBool _nt_version_gets_lockfile_completion; + +struct _MDLock _pr_ioq_lock; +extern _MDLock _nt_idleLock; +extern PRCList _nt_idleList; +extern PRUint32 _nt_idleCount; + +#define CLOSE_TIMEOUT PR_SecondsToInterval(5) + +/* + * NSPR-to-NT access right mapping table for files. + */ +static DWORD fileAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE +}; + +/* + * NSPR-to-NT access right mapping table for directories. + */ +static DWORD dirAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE|FILE_DELETE_CHILD, + FILE_GENERIC_EXECUTE +}; + +/* + * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME. + * We store the value in a PRTime variable for convenience. + * This constant is used by _PR_FileTimeToPRTime(). + */ +#ifdef __GNUC__ +static const PRTime _pr_filetime_offset = 116444736000000000LL; +#else +static const PRTime _pr_filetime_offset = 116444736000000000i64; +#endif + +#define _NEED_351_FILE_LOCKING_HACK +#ifdef _NEED_351_FILE_LOCKING_HACK +#define _PR_LOCAL_FILE 1 +#define _PR_REMOTE_FILE 2 +PRBool IsFileLocalInit(); +PRInt32 IsFileLocal(HANDLE hFile); +#endif /* _NEED_351_FILE_LOCKING_HACK */ + +static PRInt32 _md_MakeNonblock(HANDLE); + +static PRInt32 _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr *addr, int *addrlen, PRIntervalTime); +static PRInt32 _nt_nonblock_connect(PRFileDesc *fd, struct sockaddr *addr, int addrlen, PRIntervalTime); +static PRInt32 _nt_nonblock_recv(PRFileDesc *fd, char *buf, int len, int flags, PRIntervalTime); +static PRInt32 _nt_nonblock_send(PRFileDesc *fd, char *buf, int len, PRIntervalTime); +static PRInt32 _nt_nonblock_writev(PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime); +static PRInt32 _nt_nonblock_sendto(PRFileDesc *, const char *, int, const struct sockaddr *, int, PRIntervalTime); +static PRInt32 _nt_nonblock_recvfrom(PRFileDesc *, char *, int, struct sockaddr *, int *, PRIntervalTime); + +/* + * We cannot associate a fd (a socket) with an I/O completion port + * if the fd is nonblocking or inheritable. + * + * Nonblocking socket I/O won't work if the socket is associated with + * an I/O completion port. + * + * An inheritable fd cannot be associated with an I/O completion port + * because the completion notification of async I/O initiated by the + * child process is still posted to the I/O completion port in the + * parent process. + */ +#define _NT_USE_NB_IO(fd) \ + ((fd)->secret->nonblocking || (fd)->secret->inheritable == _PR_TRI_TRUE) + +/* + * UDP support + * + * UDP is supported on NT by the continuation thread mechanism. + * The code is borrowed from ptio.c in pthreads nspr, hence the + * PT and pt prefixes. This mechanism is in fact general and + * not limited to UDP. For now, only UDP's recvfrom and sendto + * go through the continuation thread if they get WSAEWOULDBLOCK + * on first try. Recv and send on a connected UDP socket still + * goes through asychronous io. + */ + +#define PT_DEFAULT_SELECT_MSEC 100 + +typedef struct pt_Continuation pt_Continuation; +typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revent); + +typedef enum pr_ContuationStatus +{ + pt_continuation_sumbitted, + pt_continuation_inprogress, + pt_continuation_abort, + pt_continuation_done +} pr_ContuationStatus; + +struct pt_Continuation +{ + /* These objects are linked in ascending timeout order */ + pt_Continuation *next, *prev; /* self linked list of these things */ + + /* The building of the continuation operation */ + ContinuationFn function; /* what function to continue */ + union { SOCKET osfd; } arg1; /* #1 - the op's fd */ + union { void* buffer; } arg2; /* #2 - primary transfer buffer */ + union { PRIntn amount; } arg3; /* #3 - size of 'buffer' */ + union { PRIntn flags; } arg4; /* #4 - read/write flags */ + union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */ + + PRIntervalTime timeout; /* representation of the timeout */ + + PRIntn event; /* flags for select()'s events */ + + /* + ** The representation and notification of the results of the operation. + ** These function can either return an int return code or a pointer to + ** some object. + */ + union { PRIntn code; void *object; } result; + + PRIntn syserrno; /* in case it failed, why (errno) */ + pr_ContuationStatus status; /* the status of the operation */ + PRCondVar *complete; /* to notify the initiating thread */ +}; + +static struct pt_TimedQueue +{ + PRLock *ml; /* a little protection */ + PRThread *thread; /* internal thread's identification */ + PRCondVar *new_op; /* new operation supplied */ + PRCondVar *finish_op; /* an existing operation finished */ + PRUintn op_count; /* number of operations in the list */ + pt_Continuation *head, *tail; /* head/tail of list of operations */ + + pt_Continuation *op; /* timed operation furthest in future */ + PRIntervalTime epoch; /* the epoch of 'timed' */ +} pt_tq; + +#if defined(DEBUG) +static struct pt_debug_s +{ + PRIntn predictionsFoiled; + PRIntn pollingListMax; + PRIntn continuationsServed; +} pt_debug; +#endif /* DEBUG */ + +static void ContinuationThread(void *arg); +static PRInt32 pt_SendTo( + SOCKET osfd, const void *buf, + PRInt32 amount, PRInt32 flags, const PRNetAddr *addr, + PRIntn addrlen, PRIntervalTime timeout); +static PRInt32 pt_RecvFrom(SOCKET osfd, void *buf, PRInt32 amount, + PRInt32 flags, PRNetAddr *addr, PRIntn *addr_len, PRIntervalTime timeout); + + +/* The key returned from GetQueuedCompletionStatus() is used to determine what + * type of completion we have. We differentiate between IO completions and + * CVAR completions. + */ +#define KEY_IO 0xaaaaaaaa +#define KEY_CVAR 0xbbbbbbbb + +PRInt32 +_PR_MD_PAUSE_CPU(PRIntervalTime ticks) +{ + int awoken = 0; + unsigned long bytes, key; + int rv; + LPOVERLAPPED olp; + _MDOverlapped *mdOlp; + PRUint32 timeout; + + if (_nt_idleCount > 0) { + PRThread *deadThread; + + _MD_LOCK(&_nt_idleLock); + while( !PR_CLIST_IS_EMPTY(&_nt_idleList) ) { + deadThread = _PR_THREAD_PTR(PR_LIST_HEAD(&_nt_idleList)); + PR_REMOVE_LINK(&deadThread->links); + + PR_ASSERT(deadThread->state == _PR_DEAD_STATE); + + /* XXXMB - cleanup to do here? */ + if ( !_PR_IS_NATIVE_THREAD(deadThread) ){ + /* Spinlock while user thread is still running. + * There is no way to use a condition variable here. The thread + * is dead, and we have to wait until we switch off the dead + * thread before we can kill the fiber completely. + */ + while ( deadThread->no_sched) + ; + + DeleteFiber(deadThread->md.fiber_id); + } + memset(deadThread, 0xa, sizeof(PRThread)); /* debugging */ + if (!deadThread->threadAllocatedOnStack) + PR_DELETE(deadThread); + _nt_idleCount--; + } + _MD_UNLOCK(&_nt_idleLock); + } + + if (ticks == PR_INTERVAL_NO_TIMEOUT) +#if 0 + timeout = INFINITE; +#else + /* + * temporary hack to poll the runq every 5 seconds because of bug in + * native threads creating user threads and not poking the right cpu. + * + * A local thread that was interrupted is bound to its current + * cpu but there is no easy way for the interrupter to poke the + * right cpu. This is a hack to poll the runq every 5 seconds. + */ + timeout = 5000; +#endif + else + timeout = PR_IntervalToMilliseconds(ticks); + + /* + * The idea of looping here is to complete as many IOs as possible before + * returning. This should minimize trips to the idle thread. + */ + while(1) { + rv = GetQueuedCompletionStatus( + _pr_completion_port, + &bytes, + &key, + &olp, + timeout); + if (rv == 0 && olp == NULL) { + /* Error in GetQueuedCompetionStatus */ + if (GetLastError() != WAIT_TIMEOUT) { + /* ARGH - what can we do here? Log an error? XXXMB */ + return -1; + } else { + /* If awoken == 0, then we just had a timeout */ + return awoken; + } + } + + if (olp == NULL) + return 0; + + mdOlp = (_MDOverlapped *)olp; + + if (mdOlp->ioModel == _MD_MultiWaitIO) { + PRRecvWait *desc; + PRWaitGroup *group; + PRThread *thred = NULL; + PRMWStatus mwstatus; + + desc = mdOlp->data.mw.desc; + PR_ASSERT(desc != NULL); + mwstatus = rv ? PR_MW_SUCCESS : PR_MW_FAILURE; + if (InterlockedCompareExchange((PVOID *)&desc->outcome, + (PVOID)mwstatus, (PVOID)PR_MW_PENDING) + == (PVOID)PR_MW_PENDING) { + if (mwstatus == PR_MW_SUCCESS) { + desc->bytesRecv = bytes; + } else { + mdOlp->data.mw.error = GetLastError(); + } + } + group = mdOlp->data.mw.group; + PR_ASSERT(group != NULL); + + _PR_MD_LOCK(&group->mdlock); + PR_APPEND_LINK(&mdOlp->data.mw.links, &group->io_ready); + PR_ASSERT(desc->fd != NULL); + NT_HashRemoveInternal(group, desc->fd); + if (!PR_CLIST_IS_EMPTY(&group->wait_list)) { + thred = _PR_THREAD_CONDQ_PTR(PR_LIST_HEAD(&group->wait_list)); + PR_REMOVE_LINK(&thred->waitQLinks); + } + _PR_MD_UNLOCK(&group->mdlock); + + if (thred) { + if (!_PR_IS_NATIVE_THREAD(thred)) { + int pri = thred->priority; + _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU(); + _PR_THREAD_LOCK(thred); + if (thred->flags & _PR_ON_PAUSEQ) { + _PR_SLEEPQ_LOCK(thred->cpu); + _PR_DEL_SLEEPQ(thred, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thred->cpu); + _PR_THREAD_UNLOCK(thred); + thred->cpu = lockedCPU; + thred->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(lockedCPU); + _PR_ADD_RUNQ(thred, lockedCPU, pri); + _PR_RUNQ_UNLOCK(lockedCPU); + } else { + /* + * The thread was just interrupted and moved + * from the pause queue to the run queue. + */ + _PR_THREAD_UNLOCK(thred); + } + } else { + _PR_THREAD_LOCK(thred); + thred->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(thred); + ReleaseSemaphore(thred->md.blocked_sema, 1, NULL); + } + } + } else { + PRThread *completed_io; + + PR_ASSERT(mdOlp->ioModel == _MD_BlockingIO); + completed_io = _PR_THREAD_MD_TO_PTR(mdOlp->data.mdThread); + completed_io->md.blocked_io_status = rv; + if (rv == 0) + completed_io->md.blocked_io_error = GetLastError(); + completed_io->md.blocked_io_bytes = bytes; + + if ( !_PR_IS_NATIVE_THREAD(completed_io) ) { + int pri = completed_io->priority; + _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU(); + + /* The KEY_CVAR notification only occurs when a native thread + * is notifying a user thread. For user-user notifications + * the wakeup occurs by having the notifier place the thread + * on the runq directly; for native-native notifications the + * wakeup occurs by calling ReleaseSemaphore. + */ + if ( key == KEY_CVAR ) { + PR_ASSERT(completed_io->io_pending == PR_FALSE); + PR_ASSERT(completed_io->io_suspended == PR_FALSE); + PR_ASSERT(completed_io->md.thr_bound_cpu == NULL); + + /* Thread has already been deleted from sleepQ */ + + /* Switch CPU and add to runQ */ + completed_io->cpu = lockedCPU; + completed_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(lockedCPU); + _PR_ADD_RUNQ(completed_io, lockedCPU, pri); + _PR_RUNQ_UNLOCK(lockedCPU); + } else { + PR_ASSERT(key == KEY_IO); + PR_ASSERT(completed_io->io_pending == PR_TRUE); + + _PR_THREAD_LOCK(completed_io); + + completed_io->io_pending = PR_FALSE; + + /* If io_suspended is true, then this IO has already resumed. + * We don't need to do anything; because the thread is + * already running. + */ + if (completed_io->io_suspended == PR_FALSE) { + if (completed_io->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) { + _PR_SLEEPQ_LOCK(completed_io->cpu); + _PR_DEL_SLEEPQ(completed_io, PR_TRUE); + _PR_SLEEPQ_UNLOCK(completed_io->cpu); + + _PR_THREAD_UNLOCK(completed_io); + + /* + * If an I/O operation is suspended, the thread + * must be running on the same cpu on which the + * I/O operation was issued. + */ + PR_ASSERT(!completed_io->md.thr_bound_cpu || + (completed_io->cpu == completed_io->md.thr_bound_cpu)); + + if (!completed_io->md.thr_bound_cpu) + completed_io->cpu = lockedCPU; + completed_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(completed_io->cpu); + _PR_ADD_RUNQ(completed_io, completed_io->cpu, pri); + _PR_RUNQ_UNLOCK(completed_io->cpu); + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } + } else { + /* For native threads, they are only notified through this loop + * when completing IO. So, don't worry about this being a CVAR + * notification, because that is not possible. + */ + _PR_THREAD_LOCK(completed_io); + completed_io->io_pending = PR_FALSE; + if (completed_io->io_suspended == PR_FALSE) { + completed_io->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(completed_io); + rv = ReleaseSemaphore(completed_io->md.blocked_sema, + 1, NULL); + PR_ASSERT(0 != rv); + } else { + _PR_THREAD_UNLOCK(completed_io); + } + } + } + + awoken++; + timeout = 0; /* Don't block on subsequent trips through the loop */ + } + + /* never reached */ + return 0; +} + +static PRStatus +_native_thread_md_wait(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + + /* + * thread waiting for a cvar or a joining thread + */ + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + PR_ASSERT (thread->state != _PR_IO_WAIT); + if (thread->wait.cvar != NULL) { + PR_ASSERT(thread->state == _PR_COND_WAIT); + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This left the semaphore in the + * signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } + + return PR_SUCCESS; +} + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + + if (_native_threads_only) { + return(_native_thread_md_wait(thread, ticks)); + } + if ( thread->flags & _PR_GLOBAL_SCOPE ) { + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + if (thread->io_pending == PR_TRUE) { + thread->state = _PR_RUNNING; + thread->io_suspended = PR_TRUE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the timeout + * occurred. This left the semaphore in the signaled + * state. Call WaitForSingleObject() to clear the + * semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } else { + if (thread->wait.cvar != NULL) { + PR_ASSERT(thread->state == _PR_COND_WAIT); + thread->wait.cvar = NULL; + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This left the semaphore in the + * signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } + } else { + PRInt32 is; + + _PR_INTSOFF(is); + _PR_MD_SWITCH_CONTEXT(thread); + } + + return PR_SUCCESS; +} + +static void +_native_thread_io_nowait( + PRThread *thread, + int rv, + int bytes) +{ + int rc; + + PR_ASSERT(rv != 0); + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + PR_ASSERT(thread->io_suspended == PR_FALSE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->state = _PR_RUNNING; + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the + * thread was interrupted. This left the semaphore + * in the signaled state. Call WaitForSingleObject() + * to clear the semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + rc = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rc == WAIT_OBJECT_0); + } + + thread->md.blocked_io_status = rv; + thread->md.blocked_io_bytes = bytes; + rc = ResetEvent(thread->md.thr_event); + PR_ASSERT(rc != 0); + return; +} + +static PRStatus +_native_thread_io_wait(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv, bytes; +#define _NATIVE_IO_WAIT_HANDLES 2 +#define _NATIVE_WAKEUP_EVENT_INDEX 0 +#define _NATIVE_IO_EVENT_INDEX 1 + + HANDLE wait_handles[_NATIVE_IO_WAIT_HANDLES]; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + + PR_ASSERT(thread->flags & _PR_GLOBAL_SCOPE); + + wait_handles[0] = thread->md.blocked_sema; + wait_handles[1] = thread->md.thr_event; + rv = WaitForMultipleObjects(_NATIVE_IO_WAIT_HANDLES, wait_handles, + FALSE, msecs); + + switch(rv) { + case WAIT_OBJECT_0 + _NATIVE_IO_EVENT_INDEX: + /* + * I/O op completed + */ + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + + PR_ASSERT(thread->io_suspended == PR_FALSE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->state = _PR_RUNNING; + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } else { + /* The IO completed just at the same time the + * thread was interrupted. This led to us being + * notified twice. Call WaitForSingleObject() + * to clear the semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + PR_ASSERT(thread->io_pending == PR_TRUE); + thread->io_pending = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, + INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + + rv = GetOverlappedResult((HANDLE) thread->io_fd, + &thread->md.overlapped.overlapped, &bytes, FALSE); + + thread->md.blocked_io_status = rv; + if (rv != 0) { + thread->md.blocked_io_bytes = bytes; + } else { + thread->md.blocked_io_error = GetLastError(); + PR_ASSERT(ERROR_IO_PENDING != thread->md.blocked_io_error); + } + rv = ResetEvent(thread->md.thr_event); + PR_ASSERT(rv != 0); + break; + case WAIT_OBJECT_0 + _NATIVE_WAKEUP_EVENT_INDEX: + /* + * I/O interrupted; + */ +#ifdef DEBUG + _PR_THREAD_LOCK(thread); + PR_ASSERT(thread->io_suspended == PR_TRUE); + _PR_THREAD_UNLOCK(thread); +#endif + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + thread->state = _PR_RUNNING; + thread->io_suspended = PR_TRUE; + _PR_THREAD_UNLOCK(thread); + } else { + /* + * The thread was interrupted just as the timeout + * occurred. This left the semaphore in the signaled + * state. Call WaitForSingleObject() to clear the + * semaphore. + */ + PR_ASSERT(thread->io_suspended == PR_TRUE); + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + break; + default: + return PR_FAILURE; + break; + } + + return PR_SUCCESS; +} + + +static PRStatus +_NT_IO_WAIT(PRThread *thread, PRIntervalTime timeout) +{ + PRBool fWait = PR_TRUE; + + if (_native_threads_only) { + return(_native_thread_io_wait(thread, timeout)); + } + if (!_PR_IS_NATIVE_THREAD(thread)) { + + _PR_THREAD_LOCK(thread); + + /* The IO may have already completed; if so, don't add to sleepQ, + * since we are already on the runQ! + */ + if (thread->io_pending == PR_TRUE) { + _PR_SLEEPQ_LOCK(thread->cpu); + _PR_ADD_SLEEPQ(thread, timeout); + _PR_SLEEPQ_UNLOCK(thread->cpu); + } else + fWait = PR_FALSE; + _PR_THREAD_UNLOCK(thread); + } + if (fWait) + return _PR_MD_WAIT(thread, timeout); + else + return PR_SUCCESS; +} + +/* + * Unblock threads waiting for I/O + * used when interrupting threads + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + PRStatus rv; + _PRCPU *cpu = thr->cpu; + + PR_ASSERT(thr->state == _PR_IO_WAIT); + /* + * A thread for which an I/O timed out or was interrupted cannot be + * in an IO_WAIT state except as a result of calling PR_Close or + * PR_NT_CancelIo for the FD. For these two cases, _PR_IO_WAIT state + * is not interruptible + */ + if (thr->md.interrupt_disabled == PR_TRUE) { + _PR_THREAD_UNLOCK(thr); + return; + } + thr->io_suspended = PR_TRUE; + thr->state = _PR_RUNNABLE; + + if (!_PR_IS_NATIVE_THREAD(thr)) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + /* + * this thread will continue to run on the same cpu until the + * I/O is aborted by closing the FD or calling CancelIO + */ + thr->md.thr_bound_cpu = cpu; + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + _PR_AddThreadToRunQ(me, thr); + } + _PR_THREAD_UNLOCK(thr); + rv = _PR_MD_WAKEUP_WAITER(thr); + PR_ASSERT(PR_SUCCESS == rv); +} + +/* Resume an outstanding IO; requires that after the switch, we disable */ +static PRStatus +_NT_ResumeIO(PRThread *thread, PRIntervalTime ticks) +{ + PRBool fWait = PR_TRUE; + + if (!_PR_IS_NATIVE_THREAD(thread)) { + if (_pr_use_static_tls) { + _pr_io_restarted_io = thread; + } else { + TlsSetValue(_pr_io_restartedIOIndex, thread); + } + } else { + _PR_THREAD_LOCK(thread); + if (!thread->io_pending) + fWait = PR_FALSE; + thread->io_suspended = PR_FALSE; + + _PR_THREAD_UNLOCK(thread); + } + /* We don't put ourselves back on the sleepQ yet; until we + * set the suspended bit to false, we can't do that. Just save + * the sleep time here, and then continue. The restarted_io handler + * will add us to the sleepQ if needed. + */ + thread->sleep = ticks; + + if (fWait) { + if (!_PR_IS_NATIVE_THREAD(thread)) + return _PR_MD_WAIT(thread, ticks); + else + return _NT_IO_WAIT(thread, ticks); + } + return PR_SUCCESS; +} + +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if (thread == NULL) { + /* If thread is NULL, we aren't waking a thread, we're just poking + * idle thread + */ + if ( PostQueuedCompletionStatus(_pr_completion_port, 0, + KEY_CVAR, NULL) == FALSE) + return PR_FAILURE; + return PR_SUCCESS; + } + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) + return PR_FAILURE; + else + return PR_SUCCESS; + } else { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + /* When a Native thread has to awaken a user thread, it has to poke + * the completion port because all user threads might be idle, and + * thus the CPUs are just waiting for a completion. + * + * XXXMB - can we know when we are truely idle (and not checking + * the runq)? + */ + if ((_PR_IS_NATIVE_THREAD(me) || (thread->cpu != me->cpu)) && + (!thread->md.thr_bound_cpu)) { + /* The thread should not be in any queue */ + PR_ASSERT(thread->queueCount == 0); + if ( PostQueuedCompletionStatus(_pr_completion_port, 0, + KEY_CVAR, &(thread->md.overlapped.overlapped)) == FALSE) + return PR_FAILURE; + } + return PR_SUCCESS; + } +} + +void +_PR_MD_INIT_IO() +{ + WORD WSAVersion = 0x0101; + WSADATA WSAData; + int err; + OSVERSIONINFO OSversion; + + err = WSAStartup( WSAVersion, &WSAData ); + PR_ASSERT(0 == err); + + _pr_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, + 0, + 0); + + _MD_NEW_LOCK(&_pr_recycle_lock); + _MD_NEW_LOCK(&_pr_ioq_lock); + + OSversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx(&OSversion)) { + _nt_version_gets_lockfile_completion = PR_FALSE; + if (OSversion.dwMajorVersion >= 4) { + _nt_version_gets_lockfile_completion = PR_TRUE; + } + } else + PR_ASSERT(0); + + IsFileLocalInit(); + + /* + * UDP support: start up the continuation thread + */ + + pt_tq.op_count = 0; + pt_tq.head = pt_tq.tail = NULL; + pt_tq.ml = PR_NewLock(); + PR_ASSERT(NULL != pt_tq.ml); + pt_tq.new_op = PR_NewCondVar(pt_tq.ml); + PR_ASSERT(NULL != pt_tq.new_op); +#if defined(DEBUG) + memset(&pt_debug, 0, sizeof(struct pt_debug_s)); +#endif + + pt_tq.thread = PR_CreateThread( + PR_SYSTEM_THREAD, ContinuationThread, NULL, + PR_PRIORITY_URGENT, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_ASSERT(NULL != pt_tq.thread); + +#ifdef DEBUG + /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ + { + SYSTEMTIME systime; + union { + PRTime prt; + FILETIME ft; + } filetime; + BOOL rv; + + systime.wYear = 1970; + systime.wMonth = 1; + /* wDayOfWeek is ignored */ + systime.wDay = 1; + systime.wHour = 0; + systime.wMinute = 0; + systime.wSecond = 0; + systime.wMilliseconds = 0; + + rv = SystemTimeToFileTime(&systime, &filetime.ft); + PR_ASSERT(0 != rv); + PR_ASSERT(filetime.prt == _pr_filetime_offset); + } +#endif /* DEBUG */ + + _PR_NT_InitSids(); +} + +/* --- SOCKET IO --------------------------------------------------------- */ + +/* _md_get_recycled_socket() + * Get a socket from the recycle bin; if no sockets are in the bin, + * create one. The socket will be passed to AcceptEx() as the + * second argument. + */ +static SOCKET +_md_get_recycled_socket() +{ + SOCKET rv; + int af = AF_INET; + + _MD_LOCK(&_pr_recycle_lock); + if (_pr_recycle_tail) { + _pr_recycle_tail--; + rv = _pr_recycle_array[_pr_recycle_tail]; + _MD_UNLOCK(&_pr_recycle_lock); + return rv; + } + _MD_UNLOCK(&_pr_recycle_lock); + + rv = _PR_MD_SOCKET(af, SOCK_STREAM, 0); + if (rv != INVALID_SOCKET && _md_Associate((HANDLE)rv) == 0) { + closesocket(rv); + return INVALID_SOCKET; + } + return rv; +} + +/* _md_put_recycled_socket() + * Add a socket to the recycle bin. + */ +static void +_md_put_recycled_socket(SOCKET newsock) +{ + PR_ASSERT(_pr_recycle_tail >= 0); + + _MD_LOCK(&_pr_recycle_lock); + if (_pr_recycle_tail < RECYCLE_SIZE) { + _pr_recycle_array[_pr_recycle_tail] = newsock; + _pr_recycle_tail++; + _MD_UNLOCK(&_pr_recycle_lock); + } else { + _MD_UNLOCK(&_pr_recycle_lock); + closesocket(newsock); + } + + return; +} + +/* _md_Associate() + * Associates a file with the completion port. + * Returns 0 on failure, 1 on success. + */ +PRInt32 +_md_Associate(HANDLE file) +{ + HANDLE port; + + if (!_native_threads_only) { + port = CreateIoCompletionPort((HANDLE)file, + _pr_completion_port, + KEY_IO, + 0); + + /* XXX should map error codes on failures */ + return (port == _pr_completion_port); + } else { + return 1; + } +} + +/* + * _md_MakeNonblock() + * Make a socket nonblocking. + * Returns 0 on failure, 1 on success. + */ +static PRInt32 +_md_MakeNonblock(HANDLE file) +{ + int rv; + u_long one = 1; + + rv = ioctlsocket((SOCKET)file, FIONBIO, &one); + /* XXX should map error codes on failures */ + return (rv == 0); +} + +static int missing_completions = 0; +static int max_wait_loops = 0; + +static PRInt32 +_NT_IO_ABORT(PRInt32 sock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool fWait; + PRInt32 rv; + int loop_count; + + /* This is a clumsy way to abort the IO, but it is all we can do. + * It looks a bit racy, but we handle all the cases. + * case 1: IO completes before calling closesocket + * case 1a: fWait is set to PR_FALSE + * This should e the most likely case. We'll properly + * not wait call _NT_IO_WAIT, since the closesocket() + * won't be forcing a completion. + * case 1b: fWait is set to PR_TRUE + * This hopefully won't happen much. When it does, this + * thread will timeout in _NT_IO_WAIT for CLOSE_INTERVAL + * before cleaning up. + * case 2: IO does not complete before calling closesocket + * case 2a: IO never completes + * This is the likely case. We'll close it and wait + * for the completion forced by the close. Return should + * be immediate. + * case 2b: IO completes just after calling closesocket + * Since the closesocket is issued, we'll either get a + * completion back for the real IO or for the close. We + * don't really care. It may not even be possible to get + * a real completion here. In any event, we'll awaken + * from NT_IO_WAIT immediately. + */ + + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + if (fWait) { + /* + * If there's still I/O pending, it should have already timed + * out once before this function is called. + */ + PR_ASSERT(me->io_suspended == PR_TRUE); + + /* Set up to wait for I/O completion again */ + me->state = _PR_IO_WAIT; + me->io_suspended = PR_FALSE; + me->md.interrupt_disabled = PR_TRUE; + } + _PR_THREAD_UNLOCK(me); + + /* Close the socket if there is one */ + if (sock != INVALID_SOCKET) { + rv = closesocket((SOCKET)sock); + } + + /* If there was I/O pending before the close, wait for it to complete */ + if (fWait) { + + /* Wait and wait for the I/O to complete */ + for (loop_count = 0; fWait; ++loop_count) { + + _NT_IO_WAIT(me, CLOSE_TIMEOUT); + + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + if (fWait) { + PR_ASSERT(me->io_suspended == PR_TRUE); + me->state = _PR_IO_WAIT; + me->io_suspended = PR_FALSE; + } + _PR_THREAD_UNLOCK(me); + + if (loop_count > max_wait_loops) { + max_wait_loops = loop_count; + } + } + + if (loop_count > 1) { + ++missing_completions; + } + + me->md.interrupt_disabled = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + + return rv; +} + + +PRInt32 +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET) { + _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + } + + return (PRInt32)sock; +} + +struct connect_data_s { + PRInt32 status; + PRInt32 error; + PRInt32 osfd; + struct sockaddr *addr; + PRUint32 addrlen; + PRIntervalTime timeout; +}; + +void +_PR_MD_connect_thread(void *cdata) +{ + struct connect_data_s *cd = (struct connect_data_s *)cdata; + + cd->status = connect(cd->osfd, cd->addr, cd->addrlen); + + if (cd->status == SOCKET_ERROR) + cd->error = WSAGetLastError(); + + return; +} + + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + u_long nbio; + PRInt32 rc; + + if (fd->secret->nonblocking) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + + if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) { + err = WSAGetLastError(); + _PR_MD_MAP_CONNECT_ERROR(err); + } + return rv; + } + + /* + * Temporarily make the socket non-blocking so that we can + * initiate a non-blocking connect and wait for its completion + * (with a timeout) in select. + */ + PR_ASSERT(!fd->secret->md.io_model_committed); + nbio = 1; + rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio); + PR_ASSERT(0 == rv); + + rc = _nt_nonblock_connect(fd, (struct sockaddr *) addr, addrlen, timeout); + + /* Set the socket back to blocking. */ + nbio = 0; + rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio); + PR_ASSERT(0 == rv); + + return rc; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; +#if 0 + int one = 1; +#endif + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + +#if 0 + /* Disable nagle- so far unknown if this is good or not... + */ + rv = setsockopt(fd->secret->md.osfd, + SOL_SOCKET, + TCP_NODELAY, + (const char *)&one, + sizeof(one)); + PR_ASSERT(rv == 0); +#endif + + return 0; +} + +void _PR_MD_UPDATE_ACCEPT_CONTEXT(PRInt32 accept_sock, PRInt32 listen_sock) +{ + /* Sockets accept()'d with AcceptEx need to call this setsockopt before + * calling anything other than ReadFile(), WriteFile(), send(), recv(), + * Transmitfile(), and closesocket(). In order to call any other + * winsock functions, we have to make this setsockopt call. + * + * XXXMB - For the server, we *NEVER* need this in + * the "normal" code path. But now we have to call it. This is a waste + * of a system call. We'd like to only call it before calling the + * obscure socket calls, but since we don't know at that point what the + * original socket was (or even if it is still alive) we can't do it + * at that point... + */ + setsockopt((SOCKET)accept_sock, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char *)&listen_sock, + sizeof(listen_sock)); + +} + +#define INET_ADDR_PADDED (sizeof(PRNetAddr) + 16) +PRInt32 +_PR_MD_FAST_ACCEPT(PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, + PRIntervalTime timeout, PRBool fast, + _PR_AcceptTimeoutCallback callback, void *callbackArg) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + SOCKET accept_sock; + int bytes; + PRNetAddr *Laddr; + PRNetAddr *Raddr; + PRUint32 llen, err; + int rv; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + /* + * The accepted socket inherits the nonblocking and + * inheritable (HANDLE_FLAG_INHERIT) attributes of + * the listening socket. + */ + accept_sock = _nt_nonblock_accept(fd, (struct sockaddr *)raddr, rlen, timeout); + if (!fd->secret->nonblocking) { + u_long zero = 0; + + rv = ioctlsocket(accept_sock, FIONBIO, &zero); + PR_ASSERT(0 == rv); + } + return accept_sock; + } + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + + if (!me->md.acceptex_buf) { + me->md.acceptex_buf = PR_MALLOC(2*INET_ADDR_PADDED); + if (!me->md.acceptex_buf) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + + accept_sock = _md_get_recycled_socket(); + if (accept_sock == INVALID_SOCKET) + return -1; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + closesocket(accept_sock); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = AcceptEx((SOCKET)osfd, + accept_sock, + me->md.acceptex_buf, + 0, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + &bytes, + &(me->md.overlapped.overlapped)); + + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) { + /* Argh! The IO failed */ + closesocket(accept_sock); + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_ACCEPTEX_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + closesocket(accept_sock); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + closesocket(accept_sock); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + closesocket(accept_sock); + _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error); + return -1; + } + + if (!fast) + _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)accept_sock, (SOCKET)osfd); + + /* IO is done */ + GetAcceptExSockaddrs( + me->md.acceptex_buf, + 0, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + (LPSOCKADDR *)&(Laddr), + &llen, + (LPSOCKADDR *)&(Raddr), + (unsigned int *)rlen); + + if (raddr != NULL) + memcpy((char *)raddr, (char *)&Raddr->inet, *rlen); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return accept_sock; +} + +PRInt32 +_PR_MD_FAST_ACCEPT_READ(PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout, + PRBool fast, _PR_AcceptTimeoutCallback callback, + void *callbackArg) +{ + PRInt32 sock = sd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + PRNetAddr *Laddr; + PRUint32 llen, rlen, err; + int rv; + PRBool isConnected; + PRBool madeCallback = PR_FALSE; + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + if (!sd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)sock); + PR_ASSERT(0 != rv); + sd->secret->md.io_model_committed = PR_TRUE; + } + + *newSock = _md_get_recycled_socket(); + if (*newSock == INVALID_SOCKET) + return -1; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + closesocket(*newSock); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = sock; + + rv = AcceptEx((SOCKET)sock, + *newSock, + buf, + amount, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + &bytes, + &(me->md.overlapped.overlapped)); + + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) { + closesocket(*newSock); + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_ACCEPTEX_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + closesocket(*newSock); + return -1; + } + +retry: + if (me->io_suspended) { + PRInt32 err; + INT seconds; + INT bytes = sizeof(seconds); + + PR_ASSERT(timeout != PR_INTERVAL_NO_TIMEOUT); + + err = getsockopt(*newSock, + SOL_SOCKET, + SO_CONNECT_TIME, + (char *)&seconds, + (PINT)&bytes); + if ( err == NO_ERROR ) { + PRIntervalTime elapsed = PR_SecondsToInterval(seconds); + + if (seconds == 0xffffffff) + isConnected = PR_FALSE; + else + isConnected = PR_TRUE; + + if (!isConnected) { + if (madeCallback == PR_FALSE && callback) + callback(callbackArg); + madeCallback = PR_TRUE; + me->state = _PR_IO_WAIT; + if (_NT_ResumeIO(me, timeout) == PR_FAILURE) { + closesocket(*newSock); + return -1; + } + goto retry; + } + + if (elapsed < timeout) { + /* Socket is connected but time not elapsed, RESUME IO */ + timeout -= elapsed; + me->state = _PR_IO_WAIT; + if (_NT_ResumeIO(me, timeout) == PR_FAILURE) { + closesocket(*newSock); + return -1; + } + goto retry; + } + } else { + /* What to do here? Assume socket not open?*/ + PR_ASSERT(0); + isConnected = PR_FALSE; + } + + rv = _NT_IO_ABORT(*newSock); + + PR_ASSERT(me->io_pending == PR_FALSE); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->md.thr_bound_cpu == NULL); + /* If the IO is still suspended, it means we didn't get any + * completion from NT_IO_WAIT. This is not disasterous, I hope, + * but it may mean we still have an IO outstanding... Try to + * recover by just allowing ourselves to continue. + */ + me->io_suspended = PR_FALSE; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + me->state = _PR_RUNNING; + closesocket(*newSock); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->md.thr_bound_cpu == NULL); + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error); + closesocket(*newSock); + return -1; + } + + if (!fast) + _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)*newSock, (SOCKET)sock); + + /* IO is done */ + GetAcceptExSockaddrs( + buf, + amount, + INET_ADDR_PADDED, + INET_ADDR_PADDED, + (LPSOCKADDR *)&(Laddr), + &llen, + (LPSOCKADDR *)(raddr), + (unsigned int *)&rlen); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SENDFILE(PRFileDesc *sock, PRSendFileData *sfd, + PRInt32 flags, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 tflags; + int rv, err; + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + if (!sock->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)sock->secret->md.osfd); + PR_ASSERT(0 != rv); + sock->secret->md.io_model_committed = PR_TRUE; + } + if (!me->md.xmit_bufs) { + me->md.xmit_bufs = PR_NEW(TRANSMIT_FILE_BUFFERS); + if (!me->md.xmit_bufs) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + } + me->md.xmit_bufs->Head = (void *)sfd->header; + me->md.xmit_bufs->HeadLength = sfd->hlen; + me->md.xmit_bufs->Tail = (void *)sfd->trailer; + me->md.xmit_bufs->TailLength = sfd->tlen; + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + me->md.overlapped.overlapped.Offset = sfd->file_offset; + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + tflags = 0; + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) + tflags = TF_DISCONNECT | TF_REUSE_SOCKET; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = sock->secret->md.osfd; + + rv = TransmitFile((SOCKET)sock->secret->md.osfd, + (HANDLE)sfd->fd->secret->md.osfd, + (DWORD)sfd->file_nbytes, + (DWORD)0, + (LPOVERLAPPED)&(me->md.overlapped.overlapped), + (TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs, + (DWORD)tflags); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_TRANSMITFILE_ERROR(err); + return -1; + } + + if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_TRANSMITFILE_ERROR(me->md.blocked_io_error); + return -1; + } + + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + _md_put_recycled_socket(sock->secret->md.osfd); + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + int rv, err; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + return _nt_nonblock_recv(fd, buf, amount, flags, timeout); + } + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = ReadFile((HANDLE)osfd, + buf, + amount, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + if ((err = GetLastError()) == ERROR_HANDLE_EOF) + return 0; + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + if (me->md.blocked_io_error == ERROR_HANDLE_EOF) + return 0; + _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + int bytes; + int rv, err; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + return _nt_nonblock_send(fd, (char *)buf, amount, timeout); + } + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = osfd; + + rv = WriteFile((HANDLE)osfd, + buf, + amount, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_WRITE_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv; + + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_NT_USE_NB_IO(fd)) + return _nt_nonblock_sendto(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout); + else + return pt_SendTo(osfd, buf, amount, flags, addr, addrlen, timeout); +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv; + + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_NT_USE_NB_IO(fd)) + return _nt_nonblock_recvfrom(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout); + else + return pt_RecvFrom(osfd, buf, amount, flags, addr, addrlen, timeout); +} + +/* XXXMB - for now this is a sockets call only */ +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + int index; + int sent = 0; + int rv; + + if (_NT_USE_NB_IO(fd)) { + if (!fd->secret->md.io_model_committed) { + rv = _md_MakeNonblock((HANDLE)osfd); + PR_ASSERT(0 != rv); + fd->secret->md.io_model_committed = PR_TRUE; + } + return _nt_nonblock_writev(fd, iov, iov_size, timeout); + } + + for (index=0; index 0) + sent += rv; + if ( rv != iov[index].iov_len ) { + if (sent <= 0) + return -1; + return -1; + } + } + + return sent; +} + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv; + + rv = listen(fd->secret->md.osfd, backlog); + if (rv < 0) + _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError()); + return(rv); +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ + PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError()); + return(rv); +} + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + /* + * NT has a bug that, when invoked on a socket accepted by + * AcceptEx(), getpeername() returns an all-zero peer address. + * To work around this bug, we store the peer's address (returned + * by AcceptEx()) with the socket fd and use the cached peer + * address if the socket is an accepted socket. + */ + + if (fd->secret->md.accepted_socket) { + INT seconds; + INT bytes = sizeof(seconds); + + /* + * Determine if the socket is connected. + */ + + rv = getsockopt(fd->secret->md.osfd, + SOL_SOCKET, + SO_CONNECT_TIME, + (char *) &seconds, + (PINT) &bytes); + if (rv == NO_ERROR) { + if (seconds == 0xffffffff) { + PR_SetError(PR_NOT_CONNECTED_ERROR, 0); + return PR_FAILURE; + } + *len = PR_NETADDR_SIZE(&fd->secret->md.peer_addr); + memcpy(addr, &fd->secret->md.peer_addr, *len); + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } + } else { + rv = getpeername((SOCKET)fd->secret->md.osfd, + (struct sockaddr *) addr, len); + if (rv == 0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv; + + rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv; + + rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +/* --- FILE IO ----------------------------------------------------------- */ + +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, PRIntn mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) + flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS; + else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING; + else flags = OPEN_EXISTING; + + + flag6 |= FILE_FLAG_OVERLAPPED; + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + flags, + flag6, + NULL); + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + if (osflags & PR_APPEND) { + if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + CloseHandle(file); + return -1; + } + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, PRIntn mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) + flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS; + else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING; + else flags = OPEN_EXISTING; + + + flag6 |= FILE_FLAG_OVERLAPPED; + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + if (osflags & PR_APPEND) { + if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + CloseHandle(file); + return -1; + } + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PRInt32 f = fd->secret->md.osfd; + PRUint32 bytes; + int rv, err; + LONG hiOffset = 0; + LONG loOffset; + + if (!fd->secret->md.sync_file_io) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT); + PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR)); + + if (fd->secret->inheritable == _PR_TRI_TRUE) { + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + rv = GetOverlappedResult((HANDLE)f, + &me->md.overlapped.overlapped, &bytes, TRUE); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + } + if (err == ERROR_HANDLE_EOF) { + return 0; + } else { + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + } else { + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)f); + PR_ASSERT(rv != 0); + fd->secret->md.io_model_committed = PR_TRUE; + } + + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = f; + + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + if (err == ERROR_HANDLE_EOF) { + return 0; + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + if (me->md.blocked_io_error == ERROR_HANDLE_EOF) { + return 0; + } + _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error); + return -1; + } + + SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; + } + } else { + + rv = ReadFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + NULL); + if (rv == 0) { + err = GetLastError(); + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(err != ERROR_HANDLE_EOF); + if (err == ERROR_BROKEN_PIPE) { + /* The write end of the pipe has been closed. */ + return 0; + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + return bytes; + } +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 f = fd->secret->md.osfd; + PRInt32 bytes; + int rv, err; + LONG hiOffset = 0; + LONG loOffset; + LARGE_INTEGER offset; /* use for the calculation of the new offset */ + + if (!fd->secret->md.sync_file_io) { + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return -1; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT); + PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR)); + + if (fd->secret->inheritable == _PR_TRI_TRUE) { + rv = WriteFile((HANDLE)f, + (LPVOID)buf, + len, + &bytes, + &me->md.overlapped.overlapped); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + rv = GetOverlappedResult((HANDLE)f, + &me->md.overlapped.overlapped, &bytes, TRUE); + if (rv != 0) { + loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT); + PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR)); + return bytes; + } + err = GetLastError(); + } + _PR_MD_MAP_READ_ERROR(err); + return -1; + } else { + if (!fd->secret->md.io_model_committed) { + rv = _md_Associate((HANDLE)f); + PR_ASSERT(rv != 0); + fd->secret->md.io_model_committed = PR_TRUE; + } + if (_native_threads_only) + me->md.overlapped.overlapped.hEvent = me->md.thr_event; + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + me->io_fd = f; + + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + &(me->md.overlapped.overlapped)); + if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_WRITE_ERROR(err); + return -1; + } + + if (_native_threads_only && rv) { + _native_thread_io_nowait(me, rv, bytes); + } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + PR_ASSERT(0); + return -1; + } + + PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE); + + if (me->io_suspended) { + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + } else { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + return -1; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error); + return -1; + } + + /* + * Moving the file pointer by a relative offset (FILE_CURRENT) + * does not work with a file on a network drive exported by a + * Win2K system. We still don't know why. A workaround is to + * move the file pointer by an absolute offset (FILE_BEGIN). + * (Bugzilla bug 70765) + */ + offset.LowPart = me->md.overlapped.overlapped.Offset; + offset.HighPart = me->md.overlapped.overlapped.OffsetHigh; + offset.QuadPart += me->md.blocked_io_bytes; + + SetFilePointer((HANDLE)f, offset.LowPart, &offset.HighPart, FILE_BEGIN); + + PR_ASSERT(me->io_pending == PR_FALSE); + + return me->md.blocked_io_bytes; + } + } else { + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + NULL); + if (rv == 0) { + _PR_MD_MAP_WRITE_ERROR(GetLastError()); + return -1; + } + return bytes; + } +} + +PRInt32 +_PR_MD_SOCKETAVAILABLE(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + +PRInt32 +_PR_MD_PIPEAVAILABLE(PRFileDesc *fd) +{ + if (NULL == fd) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +PROffset32 +_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + PROffset32 rv; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); + + /* + * If the lpDistanceToMoveHigh argument (third argument) is + * NULL, SetFilePointer returns 0xffffffff on failure. + */ + if (-1 == rv) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + } + return rv; +} + +PROffset64 +_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + LARGE_INTEGER li; + DWORD err; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + li.QuadPart = offset; + li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, + li.LowPart, &li.HighPart, moveMethod); + + if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(err); + li.QuadPart = -1; + } + return li.QuadPart; +} + +/* + * This is documented to succeed on read-only files, but Win32's + * FlushFileBuffers functions fails with "access denied" in such a + * case. So we only signal an error if the error is *not* "access + * denied". + */ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + /* + * From the documentation: + * + * On Windows NT, the function FlushFileBuffers fails if hFile + * is a handle to console output. That is because console + * output is not buffered. The function returns FALSE, and + * GetLastError returns ERROR_INVALID_HANDLE. + * + * On the other hand, on Win95, it returns without error. I cannot + * assume that 0, 1, and 2 are console, because if someone closes + * System.out and then opens a file, they might get file descriptor + * 1. An error on *that* version of 1 should be reported, whereas + * an error on System.out (which was the original 1) should be + * ignored. So I use isatty() to ensure that such an error was + * because of this, and if it was, I ignore the error. + */ + + BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); + + if (!ok) { + DWORD err = GetLastError(); + + if (err != ERROR_ACCESS_DENIED) { /* from winerror.h */ + _PR_MD_MAP_FSYNC_ERROR(err); + return -1; + } + } + return 0; +} + +PRInt32 +_PR_MD_CLOSE(PRInt32 osfd, PRBool socket) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (socket) { + rv = closesocket((SOCKET)osfd); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + } else { + rv = CloseHandle((HANDLE)osfd)?0:-1; + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + } + + if (rv == 0 && me->io_suspended) { + if (me->io_fd == osfd) { + PRBool fWait; + + _PR_THREAD_LOCK(me); + me->state = _PR_IO_WAIT; + /* The IO could have completed on another thread just after + * calling closesocket while the io_suspended flag was true. + * So we now grab the lock to do a safe check on io_pending to + * see if we need to wait or not. + */ + fWait = me->io_pending; + me->io_suspended = PR_FALSE; + me->md.interrupt_disabled = PR_TRUE; + _PR_THREAD_UNLOCK(me); + + if (fWait) + _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->io_pending == PR_FALSE); + /* + * I/O operation is no longer pending; the thread can now + * run on any cpu + */ + _PR_THREAD_LOCK(me); + me->md.interrupt_disabled = PR_FALSE; + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + } + } + return rv; +} + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + BOOL rv; + + if (fd->secret->md.io_model_committed) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + rv = SetHandleInformation( + (HANDLE)fd->secret->md.osfd, + HANDLE_FLAG_INHERIT, + inheritable ? HANDLE_FLAG_INHERIT : 0); + if (0 == rv) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + DWORD flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + if (fd->secret->md.io_model_committed) { + return; + } + if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { + if (flags & HANDLE_FLAG_INHERIT) { + fd->secret->inheritable = _PR_TRI_TRUE; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } + } +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName +#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp = _mbsinc(cp); + } +} /* end FlipSlashes() */ + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VC RTL. +** +*/ + +PRStatus +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + if ( d ) { + if (FindClose( d->d_hdl )) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ MAX_PATH ]; + int len; + + len = strlen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + strcpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (filename[len - 1] == '/' || filename[len - 1] == '\\') { + len--; + } + strcpy(&filename[len], "\\*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = FindFirstFile( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + char *fileName; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = FindNextFile(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + if (DeleteFile(name)) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(GetLastError()); + return -1; + } +} + +void +_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) +{ + PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); + CopyMemory(prtm, filetime, sizeof(PRTime)); +#ifdef __GNUC__ + *prtm = (*prtm - _pr_filetime_offset) / 10LL; +#else + *prtm = (*prtm - _pr_filetime_offset) / 10i64; +#endif + +#ifdef DEBUG + /* Doublecheck our calculation. */ + { + SYSTEMTIME systime; + PRExplodedTime etm; + PRTime cmp; /* for comparison */ + BOOL rv; + + rv = FileTimeToSystemTime(filetime, &systime); + PR_ASSERT(0 != rv); + + /* + * PR_ImplodeTime ignores wday and yday. + */ + etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; + etm.tm_sec = systime.wSecond; + etm.tm_min = systime.wMinute; + etm.tm_hour = systime.wHour; + etm.tm_mday = systime.wDay; + etm.tm_month = systime.wMonth - 1; + etm.tm_year = systime.wYear; + /* + * It is not well-documented what time zone the FILETIME's + * are in. WIN32_FIND_DATA is documented to be in UTC (GMT). + * But BY_HANDLE_FILE_INFORMATION is unclear about this. + * By our best judgement, we assume that FILETIME is in UTC. + */ + etm.tm_params.tp_gmt_offset = 0; + etm.tm_params.tp_dst_offset = 0; + cmp = PR_ImplodeTime(&etm); + + /* + * SYSTEMTIME is in milliseconds precision, so we convert PRTime's + * microseconds to milliseconds before doing the comparison. + */ + PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); + } +#endif /* DEBUG */ +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + */ + + int len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, (struct _stat *)info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') + +/* + * IsRootDirectory -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The char buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn'. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectory(char *fn, size_t buflen) +{ + char *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { + return PR_TRUE; + } + + if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) + && fn[3] == '\0') { + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p++; + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (*p == '\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p++; + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (_PR_IS_SLASH(*p) && p[1] != '\0') { + return PR_FALSE; + } + if (*p == '\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = '\\'; + *p = '\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = '\0'; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + HANDLE hFindFile; + WIN32_FIND_DATA findFileData; + char pathbuf[MAX_PATH + 1]; + + if (NULL == fn || '\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + /* + * FindFirstFile() expands wildcard characters. So + * we make sure the pathname contains no wildcard. + */ + if (NULL != _mbspbrk(fn, "?*")) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); + return -1; + } + + hFindFile = FindFirstFile(fn, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + DWORD len; + char *filePart; + + /* + * FindFirstFile() does not work correctly on root directories. + * It also doesn't work correctly on a pathname that ends in a + * slash. So we first check to see if the pathname specifies a + * root directory. If not, and if the pathname ends in a slash, + * we remove the final slash and try again. + */ + + /* + * If the pathname does not contain ., \, and /, it cannot be + * a root directory or a pathname that ends in a slash. + */ + if (NULL == _mbspbrk(fn, ".\\/")) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + len = GetFullPathName(fn, sizeof(pathbuf), pathbuf, + &filePart); + if (0 == len) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + if (len > sizeof(pathbuf)) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return -1; + } + if (IsRootDirectory(pathbuf, sizeof(pathbuf))) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + /* + * These timestamps don't make sense for root directories. + */ + info->modifyTime = 0; + info->creationTime = 0; + return 0; + } + if (!_PR_IS_SLASH(pathbuf[len - 1])) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } else { + pathbuf[len - 1] = '\0'; + hFindFile = FindFirstFile(pathbuf, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + } + } + + FindClose(hFindFile); + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + PRFileInfo64 info64; + PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); + if (0 == rv) + { + info->type = info64.type; + info->size = (PRUint32) info64.size; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + } + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeHigh; + info->size = (info->size << 32) + hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + /* Does this work with dot-relative pathnames? */ + if (MoveFile(from, to)) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ + PRInt32 rv; + + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = _access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = _access(name, 04); + break; + case PR_ACCESS_EXISTS: + rv = _access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) { + _PR_MD_MAP_ACCESS_ERROR(errno); + } + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + /* XXXMB - how to translate the "mode"??? */ + if (CreateDirectory(name, NULL)) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_MAKE_DIR(const char *name, PRIntn mode) +{ + BOOL rv; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + rv = CreateDirectory(name, lpSA); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (rv) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + if (RemoveDirectory(name)) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(GetLastError()); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + + rv = LockFileEx((HANDLE)f, + LOCKFILE_EXCLUSIVE_LOCK, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + + if (_native_threads_only) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + if (rv == FALSE) { + err = GetLastError(); + PR_ASSERT(err != ERROR_IO_PENDING); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + } + + /* HACK AROUND NT BUG + * NT 3.51 has a bug. In NT 3.51, if LockFileEx returns true, you + * don't get any completion on the completion port. This is a bug. + * + * They fixed it on NT4.0 so that you do get a completion. + * + * If we pretend we won't get a completion, NSPR gets confused later + * when the unexpected completion arrives. If we assume we do get + * a completion, we hang on 3.51. Worse, Microsoft informs me that the + * behavior varies on 3.51 depending on if you are using a network + * file system or a local disk! + * + * Solution: For now, _nt_version_gets_lockfile_completion is set + * depending on whether or not this system is EITHER + * - running NT 4.0 + * - running NT 3.51 with a service pack greater than 5. + * + * In the meantime, this code may not work on network file systems. + * + */ + + if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +#ifdef _NEED_351_FILE_LOCKING_HACK + else if (rv) { + /* If this is NT 3.51 and the file is local, then we won't get a + * completion back from LockFile when it succeeded. + */ + if (_nt_version_gets_lockfile_completion == PR_FALSE) { + if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) { + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + return PR_SUCCESS; + } + } + } +#endif /* _NEED_351_FILE_LOCKING_HACK */ + + if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + PRInt32 rv, err; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + _PR_THREAD_LOCK(me); + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return -1; + } + me->io_pending = PR_TRUE; + me->state = _PR_IO_WAIT; + _PR_THREAD_UNLOCK(me); + + rv = LockFileEx((HANDLE)f, + LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + if (_native_threads_only) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + if (rv == FALSE) { + err = GetLastError(); + PR_ASSERT(err != ERROR_IO_PENDING); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; + } + if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +#ifdef _NEED_351_FILE_LOCKING_HACK + else if (rv) { + /* If this is NT 3.51 and the file is local, then we won't get a + * completion back from LockFile when it succeeded. + */ + if (_nt_version_gets_lockfile_completion == PR_FALSE) { + if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + return PR_SUCCESS; + } + } + } +#endif /* _NEED_351_FILE_LOCKING_HACK */ + + if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + _PR_THREAD_LOCK(me); + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + return PR_FAILURE; + } + _PR_THREAD_UNLOCK(me); + + return PR_FAILURE; + } + + if (me->md.blocked_io_status == 0) { + _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + + +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->io_suspended) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED)); + + rv = UnlockFileEx((HANDLE)f, + 0, + 0x7fffffff, + 0, + &me->md.overlapped.overlapped); + + if (rv) + return PR_SUCCESS; + else { + int err = GetLastError(); + _PR_MD_MAP_LOCKF_ERROR(err); + return PR_FAILURE; + } +} + +void +_PR_MD_MAKE_NONBLOCK(PRFileDesc *f) +{ + /* + * On NT, we either call _md_Associate() or _md_MakeNonblock(), + * depending on whether the socket is blocking or not. + * + * Once we associate a socket with the io completion port, + * there is no way to disassociate it from the io completion + * port. So we have to call _md_Associate/_md_MakeNonblock + * lazily. + */ +} + +#ifdef _NEED_351_FILE_LOCKING_HACK +/*************** +** +** Lockfile hacks +** +** The following code is a hack to work around a microsoft bug with lockfile. +** The problem is that on NT 3.51, if LockFileEx() succeeds, you never +** get a completion back for files that are on local disks. So, we need to +** know if a file is local or remote so we can tell if we should expect +** a completion. +** +** The only way to check if a file is local or remote based on the handle is +** to get the serial number for the volume it is mounted on and then to +** compare that with mounted drives. This code caches the volume numbers of +** fixed disks and does a relatively quick check. +** +** Locking: Since the only thing we ever do when multithreaded is a 32bit +** assignment, we probably don't need locking. It is included just +** case anyway. +** +** Limitations: Does not work on floppies because they are too slow +** Unknown if it will work on wierdo 3rd party file systems +** +**************** +*/ + +/* There can only be 26 drive letters on NT */ +#define _PR_MAX_DRIVES 26 + +_MDLock cachedVolumeLock; +DWORD dwCachedVolumeSerialNumbers[_PR_MAX_DRIVES] = {0}; +DWORD dwLastCachedDrive = 0; +DWORD dwRemoveableDrivesToCheck = 0; /* bitmask for removeable drives */ + +PRBool IsFileLocalInit() +{ + TCHAR lpBuffer[_PR_MAX_DRIVES*5]; + DWORD nBufferLength = _PR_MAX_DRIVES*5; + DWORD nBufferNeeded = GetLogicalDriveStrings(0, NULL); + DWORD dwIndex = 0; + DWORD dwDriveType; + DWORD dwVolumeSerialNumber; + DWORD dwDriveIndex = 0; + DWORD oldmode = (DWORD) -1; + + _MD_NEW_LOCK(&cachedVolumeLock); + + nBufferNeeded = GetLogicalDriveStrings(nBufferLength, lpBuffer); + if (nBufferNeeded == 0 || nBufferNeeded > nBufferLength) + return PR_FALSE; + + // Calling GetVolumeInformation on a removeable drive where the + // disk is currently removed will cause a dialog box to the + // console. This is not good. + // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the + // damn dialog. + + dwCachedVolumeSerialNumbers[dwDriveIndex] = 0; + oldmode = SetErrorMode(SEM_FAILCRITICALERRORS); + + // now loop through the logical drives + while(lpBuffer[dwIndex] != TEXT('\0')) + { + // skip the floppy drives. This is *SLOW* + if ((lpBuffer[dwIndex] == TEXT('A')) || (lpBuffer[dwIndex] == TEXT('B'))) + /* Skip over floppies */; + else + { + dwDriveIndex = (lpBuffer[dwIndex] - TEXT('A')); + + dwDriveType = GetDriveType(&lpBuffer[dwIndex]); + + switch(dwDriveType) + { + // Ignore these drive types + case 0: + case 1: + case DRIVE_REMOTE: + default: // If the drive type is unknown, ignore it. + break; + + // Removable media drives can have different serial numbers + // at different times, so cache the current serial number + // but keep track of them so they can be rechecked if necessary. + case DRIVE_REMOVABLE: + + // CDROM is a removable media + case DRIVE_CDROM: + + // no idea if ramdisks can change serial numbers or not + // but it doesn't hurt to treat them as removable. + + case DRIVE_RAMDISK: + + + // Here is where we keep track of removable drives. + dwRemoveableDrivesToCheck |= 1 << dwDriveIndex; + + // removable drives fall through to fixed drives and get cached. + + case DRIVE_FIXED: + + // cache volume serial numbers. + if (GetVolumeInformation( + &lpBuffer[dwIndex], + NULL, 0, + &dwVolumeSerialNumber, + NULL, NULL, NULL, 0) + ) + { + if (dwLastCachedDrive < dwDriveIndex) + dwLastCachedDrive = dwDriveIndex; + dwCachedVolumeSerialNumbers[dwDriveIndex] = dwVolumeSerialNumber; + } + + break; + } + } + + dwIndex += lstrlen(&lpBuffer[dwIndex]) +1; + } + + if (oldmode != (DWORD) -1) { + SetErrorMode(oldmode); + oldmode = (DWORD) -1; + } + + return PR_TRUE; +} + +PRInt32 IsFileLocal(HANDLE hFile) +{ + DWORD dwIndex = 0, dwMask; + BY_HANDLE_FILE_INFORMATION Info; + TCHAR szDrive[4] = TEXT("C:\\"); + DWORD dwVolumeSerialNumber; + DWORD oldmode = (DWORD) -1; + int rv = _PR_REMOTE_FILE; + + if (!GetFileInformationByHandle(hFile, &Info)) + return -1; + + // look to see if the volume serial number has been cached. + _MD_LOCK(&cachedVolumeLock); + while(dwIndex <= dwLastCachedDrive) + if (dwCachedVolumeSerialNumbers[dwIndex++] == Info.dwVolumeSerialNumber) + return _PR_LOCAL_FILE; + _MD_UNLOCK(&cachedVolumeLock); + + // volume serial number not found in the cache. Check removable files. + // removable drives are noted as a bitmask. If the bit associated with + // a specific drive is set, then we should query its volume serial number + // as its possible it has changed. + dwMask = dwRemoveableDrivesToCheck; + dwIndex = 0; + + while(dwMask) + { + while(!(dwMask & 1)) + { + dwIndex++; + dwMask = dwMask >> 1; + } + + szDrive[0] = TEXT('A')+ (TCHAR) dwIndex; + + // Calling GetVolumeInformation on a removeable drive where the + // disk is currently removed will cause a dialog box to the + // console. This is not good. + // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the + // dialog. + + oldmode = SetErrorMode(SEM_FAILCRITICALERRORS); + + if (GetVolumeInformation( + szDrive, + NULL, 0, + &dwVolumeSerialNumber, + NULL, NULL, NULL, 0) + ) + { + if (dwVolumeSerialNumber == Info.dwVolumeSerialNumber) + { + _MD_LOCK(&cachedVolumeLock); + if (dwLastCachedDrive < dwIndex) + dwLastCachedDrive = dwIndex; + dwCachedVolumeSerialNumbers[dwIndex] = dwVolumeSerialNumber; + _MD_UNLOCK(&cachedVolumeLock); + rv = _PR_LOCAL_FILE; + } + } + if (oldmode != (DWORD) -1) { + SetErrorMode(oldmode); + oldmode = (DWORD) -1; + } + + if (rv == _PR_LOCAL_FILE) + return _PR_LOCAL_FILE; + + dwIndex++; + dwMask = dwMask >> 1; + } + + return _PR_REMOTE_FILE; +} +#endif /* _NEED_351_FILE_LOCKING_HACK */ + +PR_IMPLEMENT(PRStatus) PR_NT_CancelIo(PRFileDesc *fd) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool fWait; + PRFileDesc *bottom; + + bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); + if (!me->io_suspended || (NULL == bottom) || + (me->io_fd != bottom->secret->md.osfd)) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + /* + * The CancelIO operation has to be issued by the same NT thread that + * issued the I/O operation + */ + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || (me->cpu == me->md.thr_bound_cpu)); + if (me->io_pending) { + if (!CancelIo((HANDLE)bottom->secret->md.osfd)) { + PR_SetError(PR_INVALID_STATE_ERROR, GetLastError()); + return PR_FAILURE; + } + } + _PR_THREAD_LOCK(me); + fWait = me->io_pending; + me->io_suspended = PR_FALSE; + me->state = _PR_IO_WAIT; + me->md.interrupt_disabled = PR_TRUE; + _PR_THREAD_UNLOCK(me); + if (fWait) + _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(me->io_suspended == PR_FALSE); + PR_ASSERT(me->io_pending == PR_FALSE); + + _PR_THREAD_LOCK(me); + me->md.interrupt_disabled = PR_FALSE; + me->md.thr_bound_cpu = NULL; + me->io_suspended = PR_FALSE; + me->io_pending = PR_FALSE; + me->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(me); + return PR_SUCCESS; +} + +static PRInt32 _nt_nonblock_accept(PRFileDesc *fd, struct sockaddr *addr, int *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + fd_set rd; + struct timeval tv, *tvp; + + FD_ZERO(&rd); + FD_SET((SOCKET)osfd, &rd); + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + while ((rv = accept(osfd, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, + NULL)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + break; + } + } + } else if (timeout == PR_INTERVAL_NO_WAIT) { + if ((rv = accept(osfd, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + } + } + } else { +retry: + if ((rv = accept(osfd, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + + rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, tvp); + if (rv > 0) { + goto retry; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + } else { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + } + } else { + _PR_MD_MAP_ACCEPT_ERROR(err); + } + } + } + return(rv); +} + +static PRInt32 _nt_nonblock_connect(PRFileDesc *fd, struct sockaddr *addr, int addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv; + int err; + fd_set wr, ex; + struct timeval tv, *tvp; + int len; + + if ((rv = connect(osfd, addr, addrlen)) == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) { + if ( timeout == PR_INTERVAL_NO_TIMEOUT ) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&wr); + FD_ZERO(&ex); + FD_SET((SOCKET)osfd, &wr); + FD_SET((SOCKET)osfd, &ex); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wr, &ex, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return rv; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + /* Call Sleep(0) to work around a Winsock timeing bug. */ + Sleep(0); + if (FD_ISSET((SOCKET)osfd, &ex)) { + len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) == SOCKET_ERROR) { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return -1; + } + _PR_MD_MAP_CONNECT_ERROR(err); + return -1; + } + PR_ASSERT(FD_ISSET((SOCKET)osfd, &wr)); + rv = 0; + } else { + _PR_MD_MAP_CONNECT_ERROR(err); + } + } + return rv; +} + +static PRInt32 _nt_nonblock_recv(PRFileDesc *fd, char *buf, int len, int flags, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set rd; + int osflags; + + if (0 == flags) { + osflags = 0; + } else { + PR_ASSERT(PR_MSG_PEEK == flags); + osflags = MSG_PEEK; + } + while ((rv = recv(osfd,buf,len,osflags)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + FD_ZERO(&rd); + FD_SET((SOCKET)osfd, &rd); + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } + } else { + _PR_MD_MAP_RECV_ERROR(err); + break; + } + } + return(rv); +} + +static PRInt32 _nt_nonblock_send(PRFileDesc *fd, char *buf, int len, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set wd; + PRInt32 bytesSent = 0; + + while(bytesSent < len) { + while ((rv = send(osfd,buf,len,0)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + if ( timeout == PR_INTERVAL_NO_TIMEOUT ) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&wd); + FD_SET((SOCKET)osfd, &wd); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } else { + _PR_MD_MAP_SEND_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) { + break; + } + if (bytesSent < len) { + if ( timeout == PR_INTERVAL_NO_TIMEOUT ) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&wd); + FD_SET((SOCKET)osfd, &wd); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } + } + return bytesSent; +} + +static PRInt32 _nt_nonblock_writev(PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index 0) + sent += rv; + if ( rv != iov[index].iov_len ) { + if (rv < 0) { + if (fd->secret->nonblocking + && (PR_GetError() == PR_WOULD_BLOCK_ERROR) + && (sent > 0)) { + return sent; + } else { + return -1; + } + } + /* Only a nonblocking socket can have partial sends */ + PR_ASSERT(fd->secret->nonblocking); + return sent; + } + } + + return sent; +} + +static PRInt32 _nt_nonblock_sendto( + PRFileDesc *fd, const char *buf, int len, + const struct sockaddr *addr, int addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set wd; + PRInt32 bytesSent = 0; + + while(bytesSent < len) { + while ((rv = sendto(osfd,buf,len,0, addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + if ( timeout == PR_INTERVAL_NO_TIMEOUT ) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&wd); + FD_SET((SOCKET)osfd, &wd); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } else { + _PR_MD_MAP_SENDTO_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) { + break; + } + if (bytesSent < len) { + if ( timeout == PR_INTERVAL_NO_TIMEOUT ) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&wd); + FD_SET((SOCKET)osfd, &wd); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + return -1; + } + if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + return -1; + } + } + } + return bytesSent; +} + +static PRInt32 _nt_nonblock_recvfrom(PRFileDesc *fd, char *buf, int len, struct sockaddr *addr, int *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + struct timeval tv, *tvp; + fd_set rd; + + while ((rv = recvfrom(osfd,buf,len,0,addr, addrlen)) == -1) { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) { + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + } + FD_ZERO(&rd); + FD_SET((SOCKET)osfd, &rd); + if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, + tvp)) == -1) { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } else if (rv == 0) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } + } else { + _PR_MD_MAP_RECVFROM_ERROR(err); + break; + } + } + return(rv); +} + +/* + * UDP support: the continuation thread functions and recvfrom and sendto. + */ + +static void pt_InsertTimedInternal(pt_Continuation *op) +{ + PRInt32 delta = 0; + pt_Continuation *t_op = NULL; + PRIntervalTime now = PR_IntervalNow(), op_tmo, qd_tmo; + + /* + * If this element operation isn't timed, it gets queued at the + * end of the list (just after pt_tq.tail) and we're + * finishd early. + */ + if (PR_INTERVAL_NO_TIMEOUT == op->timeout) + { + t_op = pt_tq.tail; /* put it at the end */ + goto done; + } + + /* + * The rest of this routine actaully deals with timed ops. + */ + + if (NULL != pt_tq.op) + { + /* + * To find where in the list to put the new operation, form + * the absolute time the operations in question will expire. + * + * The new operation ('op') will expire at now() + op->timeout. + * + * The operation that will time out furthest in the future will + * do so at pt_tq.epoch + pt_tq.op->timeout. + * + * Subsequently earlier timeouts are computed based on the latter + * knowledge by subracting the timeout deltas that are stored in + * the operation list. There are operation[n]->timeout ticks + * between the expiration of operation[n-1] and operation[n].e e + * + * Therefore, the operation[n-1] will expire operation[n]->timeout + * ticks prior to operation[n]. + * + * This should be easy! + */ + t_op = pt_tq.op; /* running pointer to queued op */ + op_tmo = now + op->timeout; /* that's in absolute ticks */ + qd_tmo = pt_tq.epoch + t_op->timeout; /* likewise */ + + do + { + /* + * If 'op' expires later than t_op, then insert 'op' just + * ahead of t_op. Otherwise, compute when operation[n-1] + * expires and try again. + * + * The actual different between the expiriation of 'op' + * and the current operation what becomes the new operaton's + * timeout interval. That interval is also subtracted from + * the interval of the operation immediately following where + * we stick 'op' (unless the next one isn't timed). The new + * timeout assigned to 'op' takes into account the values of + * now() and when the previous intervals were compured. + */ + delta = op_tmo - qd_tmo; + if (delta >= 0) + { + op->timeout += (now - pt_tq.epoch); + goto done; + } + + qd_tmo -= t_op->timeout; /* previous operaton expiration */ + t_op = t_op->prev; /* point to previous operation */ + if (NULL != t_op) qd_tmo += t_op->timeout; + } while (NULL != t_op); + + /* + * If we got here we backed off the head of the list. That means that + * this timed entry has to go at the head of the list. This is just + * about like having an empty timer list. + */ + delta = op->timeout; /* $$$ is this right? */ + } + +done: + + /* + * Insert 'op' into the queue just after t_op or if t_op is null, + * at the head of the list. + * + * If t_op is NULL, the list is currently empty and this is pretty + * easy. + */ + if (NULL == t_op) + { + op->prev = NULL; + op->next = pt_tq.head; + pt_tq.head = op; + if (NULL == pt_tq.tail) pt_tq.tail = op; + else op->next->prev = op; + } + else + { + op->prev = t_op; + op->next = t_op->next; + if (NULL != op->prev) + op->prev->next = op; + if (NULL != op->next) + op->next->prev = op; + if (t_op == pt_tq.tail) + pt_tq.tail = op; + } + + /* + * Are we adjusting our epoch, etc? Are we replacing + * what was previously the element due to expire furthest + * out in the future? Is this even a timed operation? + */ + if (PR_INTERVAL_NO_TIMEOUT != op->timeout) + { + if ((NULL == pt_tq.op) /* we're the one and only */ + || (t_op == pt_tq.op)) /* we're replacing */ + { + pt_tq.op = op; + pt_tq.epoch = now; + } + } + + pt_tq.op_count += 1; + +} /* pt_InsertTimedInternal */ + +/* + * function: pt_FinishTimed + * + * Takes the finished operation out of the timed queue. It + * notifies the initiating thread that the opertions is + * complete and returns to the caller the value of the next + * operation in the list (or NULL). + */ +static pt_Continuation *pt_FinishTimedInternal(pt_Continuation *op) +{ + pt_Continuation *next; + + /* remove this one from the list */ + if (NULL == op->prev) pt_tq.head = op->next; + else op->prev->next = op->next; + if (NULL == op->next) pt_tq.tail = op->prev; + else op->next->prev = op->prev; + + /* did we happen to hit the timed op? */ + if (op == pt_tq.op) pt_tq.op = op->prev; + + next = op->next; + op->next = op->prev = NULL; + op->status = pt_continuation_done; + + pt_tq.op_count -= 1; +#if defined(DEBUG) + pt_debug.continuationsServed += 1; +#endif + PR_NotifyCondVar(op->complete); + + return next; +} /* pt_FinishTimedInternal */ + +static void ContinuationThread(void *arg) +{ + /* initialization */ + fd_set readSet, writeSet, exceptSet; + struct timeval tv; + SOCKET *pollingList = 0; /* list built for polling */ + PRIntn pollingListUsed; /* # entries used in the list */ + PRIntn pollingListNeeded; /* # entries needed this time */ + PRIntn pollingSlotsAllocated = 0; /* # entries available in list */ + PRIntervalTime mx_select_ticks = PR_MillisecondsToInterval(PT_DEFAULT_SELECT_MSEC); + + /* do some real work */ + while (1) + { + PRIntn rv; + PRStatus status; + PRIntn pollIndex; + pt_Continuation *op; + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + PR_Lock(pt_tq.ml); + while (NULL == pt_tq.head) + { + status = PR_WaitCondVar(pt_tq.new_op, PR_INTERVAL_NO_TIMEOUT); + if ((PR_FAILURE == status) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + } + pollingListNeeded = pt_tq.op_count; + PR_Unlock(pt_tq.ml); + + /* Okay. We're history */ + if ((PR_FAILURE == status) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + + /* + * We are not holding the pt_tq.ml lock now, so more items may + * get added to pt_tq during this window of time. We hope + * that 10 more spaces in the polling list should be enough. + */ + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_ZERO(&exceptSet); + pollingListNeeded += 10; + if (pollingListNeeded > pollingSlotsAllocated) + { + if (NULL != pollingList) PR_DELETE(pollingList); + pollingList = PR_MALLOC(pollingListNeeded * sizeof(PRPollDesc)); + PR_ASSERT(NULL != pollingList); + pollingSlotsAllocated = pollingListNeeded; + } + +#if defined(DEBUG) + if (pollingListNeeded > pt_debug.pollingListMax) + pt_debug.pollingListMax = pollingListUsed; +#endif + + /* + * Build up a polling list. + * This list is sorted on time. Operations that have been + * interrupted are completed and not included in the list. + * There is an assertion that the operation is in progress. + */ + pollingListUsed = 0; + PR_Lock(pt_tq.ml); + + for (op = pt_tq.head; NULL != op;) + { + if (pt_continuation_abort == op->status) + { + op->result.code = -1; + op->syserrno = WSAEINTR; + op = pt_FinishTimedInternal(op); + } + else + { + PR_ASSERT(pt_continuation_done != op->status); + op->status = pt_continuation_inprogress; + if (op->event & PR_POLL_READ) { + FD_SET(op->arg1.osfd, &readSet); + } + if (op->event & PR_POLL_WRITE) { + FD_SET(op->arg1.osfd, &writeSet); + } + if (op->event & PR_POLL_EXCEPT) { + FD_SET(op->arg1.osfd, &exceptSet); + } + pollingList[pollingListUsed] = op->arg1.osfd; + pollingListUsed += 1; + if (pollingListUsed == pollingSlotsAllocated) break; + op = op->next; + } + } + + PR_Unlock(pt_tq.ml); + + /* + * If 'op' isn't NULL at this point, then we didn't get to + * the end of the list. That means that more items got added + * to the list than we anticipated. So, forget this iteration, + * go around the horn again. + * One would hope this doesn't happen all that often. + */ + if (NULL != op) + { +#if defined(DEBUG) + pt_debug.predictionsFoiled += 1; /* keep track */ +#endif + continue; /* make it rethink things */ + } + + /* there's a chance that all ops got blown away */ + if (NULL == pt_tq.head) continue; + /* if not, we know this is the shortest timeout */ + timeout = pt_tq.head->timeout; + + /* + * We don't want to wait forever on this poll. So keep + * the interval down. The operations, if they are timed, + * still have to timeout, while those that are not timed + * should persist forever. But they may be aborted. That's + * what this anxiety is all about. + */ + if (timeout > mx_select_ticks) timeout = mx_select_ticks; + + if (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout) + pt_tq.head->timeout -= timeout; + tv.tv_sec = PR_IntervalToSeconds(timeout); + tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC; + + rv = select(0, &readSet, &writeSet, &exceptSet, &tv); + + if (0 == rv) /* poll timed out - what about leading op? */ + { + if (0 == pt_tq.head->timeout) + { + /* + * The leading element of the timed queue has timed + * out. Get rid of it. In any case go around the + * loop again, computing the polling list, checking + * for interrupted operations. + */ + PR_Lock(pt_tq.ml); + do + { + pt_tq.head->result.code = -1; + pt_tq.head->syserrno = WSAETIMEDOUT; + op = pt_FinishTimedInternal(pt_tq.head); + } while ((NULL != op) && (0 == op->timeout)); + PR_Unlock(pt_tq.ml); + } + continue; + } + + if (-1 == rv && (WSAGetLastError() == WSAEINTR + || WSAGetLastError() == WSAEINPROGRESS)) + { + continue; /* go around the loop again */ + } + + /* + * select() says that something in our list is ready for some more + * action or is an invalid fd. Find it, load up the operation and + * see what happens. + */ + + PR_ASSERT(rv > 0 || WSAGetLastError() == WSAENOTSOCK); + + + /* + * $$$ There's a problem here. I'm running the operations list + * and I'm not holding any locks. I don't want to hold the lock + * and do the operation, so this is really messed up.. + * + * This may work out okay. The rule is that only this thread, + * the continuation thread, can remove elements from the list. + * Therefore, the list is at worst, longer than when we built + * the polling list. + */ + op = pt_tq.head; + for (pollIndex = 0; pollIndex < pollingListUsed; ++pollIndex) + { + PRInt16 revents = 0; + + PR_ASSERT(NULL != op); + + /* + * This one wants attention. Redo the operation. + * We know that there can only be more elements + * in the op list than we knew about when we created + * the poll list. Therefore, we might have to skip + * a few ops to find the right one to operation on. + */ + while (pollingList[pollIndex] != op->arg1.osfd ) + { + op = op->next; + PR_ASSERT(NULL != op); + } + + if (FD_ISSET(op->arg1.osfd, &readSet)) { + revents |= PR_POLL_READ; + } + if (FD_ISSET(op->arg1.osfd, &writeSet)) { + revents |= PR_POLL_WRITE; + } + if (FD_ISSET(op->arg1.osfd, &exceptSet)) { + revents |= PR_POLL_EXCEPT; + } + + /* + * Sip over all those not in progress. They'll be + * pruned next time we build a polling list. Call + * the continuation function. If it reports completion, + * finish off the operation. + */ + if (revents && (pt_continuation_inprogress == op->status) + && (op->function(op, revents))) + { + PR_Lock(pt_tq.ml); + op = pt_FinishTimedInternal(op); + PR_Unlock(pt_tq.ml); + } + } + } + if (NULL != pollingList) PR_DELETE(pollingList); +} /* ContinuationThread */ + +static int pt_Continue(pt_Continuation *op) +{ + PRStatus rv; + /* Finish filling in the blank slots */ + op->status = pt_continuation_sumbitted; + op->complete = PR_NewCondVar(pt_tq.ml); + + PR_Lock(pt_tq.ml); /* we provide the locking */ + + pt_InsertTimedInternal(op); /* insert in the structure */ + + PR_NotifyCondVar(pt_tq.new_op); /* notify the continuation thread */ + + while (pt_continuation_done != op->status) /* wait for completion */ + { + rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT); + /* + * If we get interrupted, we set state the continuation thread will + * see and allow it to finish the I/O operation w/ error. That way + * the rule that only the continuation thread is removing elements + * from the list is still valid. + * + * Don't call interrupt on the continuation thread. That'll just + * piss him off. He's cycling around at least every mx_select_ticks + * anyhow and should notice the request in there. + */ + if ((PR_FAILURE == rv) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) + op->status = pt_continuation_abort; /* our status */ + } + + PR_Unlock(pt_tq.ml); /* we provide the locking */ + + PR_DestroyCondVar(op->complete); + + return op->result.code; /* and the primary answer */ +} /* pt_Continue */ + +static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes = sendto( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, + (struct sockaddr*)op->arg5.addr, sizeof(*(op->arg5.addr))); + op->syserrno = WSAGetLastError(); + if (bytes > 0) /* this is progress */ + { + char *bp = op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else return ((-1 == bytes) && (WSAEWOULDBLOCK == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_sendto_cont */ + +static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn addr_len = sizeof(*(op->arg5.addr)); + op->result.code = recvfrom( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, + op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len); + op->syserrno = WSAGetLastError(); + return ((-1 == op->result.code) && (WSAEWOULDBLOCK == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_recvfrom_cont */ + +static PRInt32 pt_SendTo( + SOCKET osfd, const void *buf, + PRInt32 amount, PRInt32 flags, const PRNetAddr *addr, + PRIntn addrlen, PRIntervalTime timeout) +{ + PRInt32 bytes = -1, err; + PRBool fNeedContinue = PR_FALSE; + + bytes = sendto( + osfd, buf, amount, flags, + (struct sockaddr*)addr, PR_NETADDR_SIZE(addr)); + if (bytes == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) + fNeedContinue = PR_TRUE; + else + _PR_MD_MAP_SENDTO_ERROR(err); + } + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = (PRNetAddr*)addr; + op.timeout = timeout; + op.result.code = 0; /* initialize the number sent */ + op.function = pt_sendto_cont; + op.event = PR_POLL_WRITE | PR_POLL_EXCEPT; + bytes = pt_Continue(&op); + if (bytes < 0) { + WSASetLastError(op.syserrno); + _PR_MD_MAP_SENDTO_ERROR(op.syserrno); + } + } + return bytes; +} /* pt_SendTo */ + +static PRInt32 pt_RecvFrom(SOCKET osfd, void *buf, PRInt32 amount, + PRInt32 flags, PRNetAddr *addr, PRIntn *addr_len, PRIntervalTime timeout) +{ + PRInt32 bytes = -1, err; + PRBool fNeedContinue = PR_FALSE; + + bytes = recvfrom( + osfd, buf, amount, flags, + (struct sockaddr*)addr, addr_len); + if (bytes == -1) { + if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) + fNeedContinue = PR_TRUE; + else + _PR_MD_MAP_RECVFROM_ERROR(err); + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = addr; + op.timeout = timeout; + op.function = pt_recvfrom_cont; + op.event = PR_POLL_READ | PR_POLL_EXCEPT; + bytes = pt_Continue(&op); + if (bytes < 0) { + WSASetLastError(op.syserrno); + _PR_MD_MAP_RECVFROM_ERROR(op.syserrno); + } + } + return bytes; +} /* pt_RecvFrom */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntmisc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntmisc.c new file mode 100644 index 00000000..849bbbe0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntmisc.c @@ -0,0 +1,929 @@ +/* -*- 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 ***** */ + +/* + * ntmisc.c + * + */ + +#include "primpl.h" + +char *_PR_MD_GET_ENV(const char *name) +{ + return getenv(name); +} + +/* +** _PR_MD_PUT_ENV() -- add or change environment variable +** +** +*/ +PRIntn _PR_MD_PUT_ENV(const char *name) +{ + return(putenv(name)); +} + + +/* + ************************************************************************** + ************************************************************************** + ** + ** Date and time routines + ** + ************************************************************************** + ************************************************************************** + */ + +#include + +/* + *----------------------------------------------------------------------- + * + * 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 + * implementation for Windows. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRTime) +PR_Now(void) +{ + PRTime prt; + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + _PR_FileTimeToPRTime(&ft, &prt); + return prt; +} + +/* + * The following code works around a bug in NT (Netscape Bugsplat + * Defect ID 47942). + * + * In Windows NT 3.51 and 4.0, if the local time zone does not practice + * daylight savings time, e.g., Arizona, Taiwan, and Japan, the global + * variables that _ftime() and localtime() depend on have the wrong + * default values: + * _tzname[0] "PST" + * _tzname[1] "PDT" + * _daylight 1 + * _timezone 28800 + * + * So at startup time, we need to invoke _PR_Win32InitTimeZone(), which + * on NT sets these global variables to the correct values (obtained by + * calling GetTimeZoneInformation(). + */ + +#include /* for _tzname, _daylight, _timezone */ + +void +_PR_Win32InitTimeZone(void) +{ + OSVERSIONINFO version; + TIME_ZONE_INFORMATION tzinfo; + + version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx(&version) != FALSE) { + /* Only Windows NT needs this hack */ + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) { + return; + } + } + + if (GetTimeZoneInformation(&tzinfo) == 0xffffffff) { + return; /* not much we can do if this failed */ + } + + /* + * I feel nervous about modifying these globals. I hope that no + * other thread is reading or modifying these globals simultaneously + * during nspr initialization. + * + * I am assuming that _tzname[0] and _tzname[1] point to static buffers + * and that the buffers are at least 32 byte long. My experiments show + * this is true, but of course this is undocumented. --wtc + * + * Convert time zone names from WCHAR to CHAR and copy them to + * the static buffers pointed to by _tzname[0] and _tzname[1]. + * Ignore conversion errors, because it is _timezone and _daylight + * that _ftime() and localtime() really depend on. + */ + + WideCharToMultiByte(CP_ACP, 0, tzinfo.StandardName, -1, _tzname[0], + 32, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, tzinfo.DaylightName, -1, _tzname[1], + 32, NULL, NULL); + + /* _timezone is in seconds. tzinfo.Bias is in minutes. */ + + _timezone = tzinfo.Bias * 60; + _daylight = tzinfo.DaylightBias ? 1 : 0; + return; +} + +/* + *********************************************************************** + *********************************************************************** + * + * Process creation routines + * + *********************************************************************** + *********************************************************************** + */ + +/* + * Assemble the command line by concatenating the argv array. + * On success, this function returns 0 and the resulting command + * line is returned in *cmdLine. On failure, it returns -1. + */ +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + char *p, *q; + int cmdLineSize; + int numBackslashes; + int i; + int argNeedQuotes; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 0; + for (arg = argv; *arg; arg++) { + /* + * \ and " need to be escaped by a \. In the worst case, + * every character is a \ or ", so the string of length + * may double. If we quote an argument, that needs two ". + * Finally, we need a space between arguments, and + * a null byte at the end of command line. + */ + cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */ + + 2 /* we quote every argument */ + + 1; /* space in between, or final null */ + } + p = *cmdLine = PR_MALLOC(cmdLineSize); + if (p == NULL) { + return -1; + } + + for (arg = argv; *arg; arg++) { + /* Add a space to separates the arguments */ + if (arg != argv) { + *p++ = ' '; + } + q = *arg; + numBackslashes = 0; + argNeedQuotes = 0; + + /* If the argument contains white space, it needs to be quoted. */ + if (strpbrk(*arg, " \f\n\r\t\v")) { + argNeedQuotes = 1; + } + + if (argNeedQuotes) { + *p++ = '"'; + } + while (*q) { + if (*q == '\\') { + numBackslashes++; + q++; + } else if (*q == '"') { + if (numBackslashes) { + /* + * Double the backslashes since they are followed + * by a quote + */ + for (i = 0; i < 2 * numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + /* To escape the quote */ + *p++ = '\\'; + *p++ = *q++; + } else { + if (numBackslashes) { + /* + * Backslashes are not followed by a quote, so + * don't need to double the backslashes. + */ + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + *p++ = *q++; + } + } + + /* Now we are at the end of this argument */ + if (numBackslashes) { + /* + * Double the backslashes if we have a quote string + * delimiter at the end. + */ + if (argNeedQuotes) { + numBackslashes *= 2; + } + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + } + if (argNeedQuotes) { + *p++ = '"'; + } + } + + *p = '\0'; + return 0; +} + +/* + * Assemble the environment block by concatenating the envp array + * (preserving the terminating null byte in each array element) + * and adding a null byte at the end. + * + * Returns 0 on success. The resulting environment block is returned + * in *envBlock. Note that if envp is NULL, a NULL pointer is returned + * in *envBlock. Returns -1 on failure. + */ +static int assembleEnvBlock(char **envp, char **envBlock) +{ + char *p; + char *q; + char **env; + char *curEnv; + char *cwdStart, *cwdEnd; + int envBlockSize; + + if (envp == NULL) { + *envBlock = NULL; + return 0; + } + + curEnv = GetEnvironmentStrings(); + + cwdStart = curEnv; + while (*cwdStart) { + if (cwdStart[0] == '=' && cwdStart[1] != '\0' + && cwdStart[2] == ':' && cwdStart[3] == '=') { + break; + } + cwdStart += strlen(cwdStart) + 1; + } + cwdEnd = cwdStart; + if (*cwdEnd) { + cwdEnd += strlen(cwdEnd) + 1; + while (*cwdEnd) { + if (cwdEnd[0] != '=' || cwdEnd[1] == '\0' + || cwdEnd[2] != ':' || cwdEnd[3] != '=') { + break; + } + cwdEnd += strlen(cwdEnd) + 1; + } + } + envBlockSize = cwdEnd - cwdStart; + + for (env = envp; *env; env++) { + envBlockSize += strlen(*env) + 1; + } + envBlockSize++; + + p = *envBlock = PR_MALLOC(envBlockSize); + if (p == NULL) { + FreeEnvironmentStrings(curEnv); + return -1; + } + + q = cwdStart; + while (q < cwdEnd) { + *p++ = *q++; + } + FreeEnvironmentStrings(curEnv); + + for (env = envp; *env; env++) { + q = *env; + while (*q) { + *p++ = *q++; + } + *p++ = '\0'; + } + *p = '\0'; + return 0; +} + +/* + * For qsort. We sort (case-insensitive) the environment strings + * before generating the environment block. + */ +static int compare(const void *arg1, const void *arg2) +{ + return _stricmp(* (char**)arg1, * (char**)arg2); +} + +PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + STARTUPINFO startupInfo; + PROCESS_INFORMATION procInfo; + BOOL retVal; + char *cmdLine = NULL; + char *envBlock = NULL; + char **newEnvp = NULL; + const char *cwd = NULL; /* current working directory */ + PRProcess *proc = NULL; + + proc = PR_NEW(PRProcess); + if (!proc) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + if (assembleCmdLine(argv, &cmdLine) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + /* + * If attr->fdInheritBuffer is not NULL, we need to insert + * it into the envp array, so envp cannot be NULL. + */ + if ((envp == NULL) && attr && attr->fdInheritBuffer) { + envp = environ; + } + + if (envp != NULL) { + int idx; + int numEnv; + int newEnvpSize; + + numEnv = 0; + while (envp[numEnv]) { + numEnv++; + } + newEnvpSize = numEnv + 1; /* terminating null pointer */ + if (attr && attr->fdInheritBuffer) { + newEnvpSize++; + } + newEnvp = (char **) PR_MALLOC(newEnvpSize * sizeof(char *)); + for (idx = 0; idx < numEnv; idx++) { + newEnvp[idx] = envp[idx]; + } + if (attr && attr->fdInheritBuffer) { + newEnvp[idx++] = attr->fdInheritBuffer; + } + newEnvp[idx] = NULL; + qsort((void *) newEnvp, (size_t) (newEnvpSize - 1), + sizeof(char *), compare); + } + if (assembleEnvBlock(newEnvp, &envBlock) == -1) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto errorExit; + } + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + if (attr) { + PRBool redirected = PR_FALSE; + + /* + * XXX the default value for stdin, stdout, and stderr + * should probably be the console input and output, not + * those of the parent process. + */ + startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (attr->stdinFd) { + startupInfo.hStdInput = (HANDLE) attr->stdinFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (attr->stdoutFd) { + startupInfo.hStdOutput = (HANDLE) attr->stdoutFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (attr->stderrFd) { + startupInfo.hStdError = (HANDLE) attr->stderrFd->secret->md.osfd; + redirected = PR_TRUE; + } + if (redirected) { + startupInfo.dwFlags |= STARTF_USESTDHANDLES; + } + cwd = attr->currentDirectory; + } + + retVal = CreateProcess(NULL, + cmdLine, + NULL, /* security attributes for the new + * process */ + NULL, /* security attributes for the primary + * thread in the new process */ + TRUE, /* inherit handles */ + 0, /* creation flags */ + envBlock, /* an environment block, consisting + * of a null-terminated block of + * null-terminated strings. Each + * string is in the form: + * name=value + * XXX: usually NULL */ + cwd, /* current drive and directory */ + &startupInfo, + &procInfo + ); + if (retVal == FALSE) { + /* XXX what error code? */ + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + goto errorExit; + } + + CloseHandle(procInfo.hThread); + proc->md.handle = procInfo.hProcess; + proc->md.id = procInfo.dwProcessId; + + PR_DELETE(cmdLine); + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + return proc; + +errorExit: + if (cmdLine) { + PR_DELETE(cmdLine); + } + if (newEnvp) { + PR_DELETE(newEnvp); + } + if (envBlock) { + PR_DELETE(envBlock); + } + if (proc) { + PR_DELETE(proc); + } + return NULL; +} /* _PR_CreateWindowsProcess */ + +PRStatus _PR_DetachWindowsProcess(PRProcess *process) +{ + CloseHandle(process->md.handle); + PR_DELETE(process); + return PR_SUCCESS; +} + +/* + * XXX: This implementation is a temporary quick solution. + * It can be called by native threads only (not by fibers). + */ +PRStatus _PR_WaitWindowsProcess(PRProcess *process, + PRInt32 *exitCode) +{ + DWORD dwRetVal; + + dwRetVal = WaitForSingleObject(process->md.handle, INFINITE); + if (dwRetVal == WAIT_FAILED) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + PR_ASSERT(dwRetVal == WAIT_OBJECT_0); + if (exitCode != NULL && + GetExitCodeProcess(process->md.handle, exitCode) == FALSE) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + CloseHandle(process->md.handle); + PR_DELETE(process); + return PR_SUCCESS; +} + +PRStatus _PR_KillWindowsProcess(PRProcess *process) +{ + /* + * On Unix, if a process terminates normally, its exit code is + * between 0 and 255. So here on Windows, we use the exit code + * 256 to indicate that the process is killed. + */ + if (TerminateProcess(process->md.handle, 256)) { + return PR_SUCCESS; + } + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; +} + +PRStatus _MD_WindowsGetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + PRInt32 syserror; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + syserror = WSAGetLastError(); + PR_ASSERT(WSANOTINITIALISED != syserror); + _PR_MD_MAP_GETHOSTNAME_ERROR(syserror); + return PR_FAILURE; +} + +PRStatus _MD_WindowsGetSysInfo(PRSysInfo cmd, char *name, PRUint32 namelen) +{ + OSVERSIONINFO osvi; + + PR_ASSERT((cmd == PR_SI_SYSNAME) || (cmd == PR_SI_RELEASE)); + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (! GetVersionEx (&osvi) ) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, "Windows_NT"); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + break; + case VER_PLATFORM_WIN32_WINDOWS: + if (PR_SI_SYSNAME == cmd) { + if ((osvi.dwMajorVersion > 4) || + ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0))) + (void)PR_snprintf(name, namelen, "Windows_98"); + else + (void)PR_snprintf(name, namelen, "Windows_95"); + } else if (PR_SI_RELEASE == cmd) { + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + } + break; + default: + if (PR_SI_SYSNAME == cmd) + (void)PR_snprintf(name, namelen, "Windows_Unknown"); + else if (PR_SI_RELEASE == cmd) + (void)PR_snprintf(name, namelen, "%d.%d",0,0); + break; + } + return PR_SUCCESS; +} + +PRStatus _MD_WindowsGetReleaseName(char *name, PRUint32 namelen) +{ + OSVERSIONINFO osvi; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + if (! GetVersionEx (&osvi) ) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + + switch (osvi.dwPlatformId) { + case VER_PLATFORM_WIN32_NT: + case VER_PLATFORM_WIN32_WINDOWS: + (void)PR_snprintf(name, namelen, "%d.%d",osvi.dwMajorVersion, + osvi.dwMinorVersion); + break; + default: + (void)PR_snprintf(name, namelen, "%d.%d",0,0); + break; + } + return PR_SUCCESS; +} + +/* + ********************************************************************** + * + * Memory-mapped files + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + DWORD dwHi, dwLo; + DWORD flProtect; + PRUint32 osfd; + + osfd = ( fmap->fd == (PRFileDesc*)-1 )? -1 : fmap->fd->secret->md.osfd; + + dwLo = (DWORD) (size & 0xffffffff); + dwHi = (DWORD) (((PRUint64) size >> 32) & 0xffffffff); + + if (fmap->prot == PR_PROT_READONLY) { + flProtect = PAGE_READONLY; + fmap->md.dwAccess = FILE_MAP_READ; + } else if (fmap->prot == PR_PROT_READWRITE) { + flProtect = PAGE_READWRITE; + fmap->md.dwAccess = FILE_MAP_WRITE; + } else { + PR_ASSERT(fmap->prot == PR_PROT_WRITECOPY); + flProtect = PAGE_WRITECOPY; + fmap->md.dwAccess = FILE_MAP_COPY; + } + + fmap->md.hFileMap = CreateFileMapping( + (HANDLE) osfd, + NULL, + flProtect, + dwHi, + dwLo, + NULL); + + if (fmap->md.hFileMap == NULL) { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + return info.dwAllocationGranularity; +} + +#include "prlog.h" +extern PRLogModuleInfo *_pr_shma_lm; +void * _MD_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ + DWORD dwHi, dwLo; + void *addr; + + dwLo = (DWORD) (offset & 0xffffffff); + dwHi = (DWORD) (((PRUint64) offset >> 32) & 0xffffffff); + if ((addr = MapViewOfFile(fmap->md.hFileMap, fmap->md.dwAccess, + dwHi, dwLo, len)) == NULL) { + { + LPVOID lpMsgBuf; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, ("md_memmap(): %s", lpMsgBuf )); + } + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + } + return addr; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + if (UnmapViewOfFile(addr)) { + return PR_SUCCESS; + } else { + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; + } +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + CloseHandle(fmap->md.hFileMap); + PR_DELETE(fmap); + return PR_SUCCESS; +} + +/* + *********************************************************************** + * + * Atomic increment and decrement operations for x86 processors + * + * We don't use InterlockedIncrement and InterlockedDecrement + * because on NT 3.51 and Win95, they return a number with + * the same sign as the incremented/decremented result, rather + * than the result itself. On NT 4.0 these functions do return + * the incremented/decremented result. + * + * The result is returned in the eax register by the inline + * assembly code. We disable the harmless "no return value" + * warning (4035) for these two functions. + * + *********************************************************************** + */ + +#if defined(_M_IX86) || defined(_X86_) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ +#if defined(__GNUC__) + PRInt32 result; + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*val) + : "0"(1), "m"(*val)); + return result + 1; +#else + __asm + { + mov ecx, val + mov eax, 1 + lock xadd dword ptr [ecx], eax + inc eax + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ +#if defined(__GNUC__) + PRInt32 result; + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*val) + : "0"(-1), "m"(*val)); + //asm volatile("lock ; xadd %0, %1" : "=m" (val), "=a" (result) : "-1" (1)); + return result - 1; +#else + __asm + { + mov ecx, val + mov eax, 0ffffffffh + lock xadd dword ptr [ecx], eax + dec eax + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRInt32 _PR_MD_ATOMIC_ADD(PRInt32 *intp, PRInt32 val) +{ +#if defined(__GNUC__) + PRInt32 result; + //asm volatile("lock ; xadd %1, %0" : "=m" (intp), "=a" (result) : "1" (val)); + asm volatile ("lock ; xadd %0, %1" + : "=r"(result), "=m"(*intp) + : "0"(val), "m"(*intp)); + return result + val; +#else + __asm + { + mov ecx, intp + mov eax, val + mov edx, eax + lock xadd dword ptr [ecx], eax + add eax, edx + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#ifdef _PR_HAVE_ATOMIC_CAS + +#pragma warning(disable: 4035) +void +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ +#if defined(__GNUC__) + void **tos = (void **) stack; + void *tmp; + + retry: + if (*tos == (void *) -1) + goto retry; + + __asm__("lock xchg %0,%1" + : "=r" (tmp), "=m"(*tos) + : "0" (-1), "m"(*tos)); + + if (tmp == (void *) -1) + goto retry; + + *(void **)stack_elem = tmp; + __asm__("" : : : "memory"); + *tos = stack_elem; +#else + __asm + { + mov ebx, stack + mov ecx, stack_elem +retry: mov eax,[ebx] + cmp eax,-1 + je retry + mov eax,-1 + xchg dword ptr [ebx], eax + cmp eax,-1 + je retry + mov [ecx],eax + mov [ebx],ecx + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#pragma warning(disable: 4035) +PRStackElem * +PR_StackPop(PRStack *stack) +{ +#if defined(__GNUC__) + void **tos = (void **) stack; + void *tmp; + + retry: + if (*tos == (void *) -1) + goto retry; + + __asm__("lock xchg %0,%1" + : "=r" (tmp), "=m"(*tos) + : "0" (-1), "m"(*tos)); + + if (tmp == (void *) -1) + goto retry; + + if (tmp != (void *) 0) + { + void *next = *(void **)tmp; + *tos = next; + *(void **)tmp = 0; + } + else + *tos = tmp; + + return tmp; +#else + __asm + { + mov ebx, stack +retry: mov eax,[ebx] + cmp eax,-1 + je retry + mov eax,-1 + xchg dword ptr [ebx], eax + cmp eax,-1 + je retry + cmp eax,0 + je empty + mov ecx,[eax] + mov [ebx],ecx + mov [eax],0 + jmp done +empty: + mov [ebx],eax +done: + } +#endif /* __GNUC__ */ +} +#pragma warning(default: 4035) + +#endif /* _PR_HAVE_ATOMIC_CAS */ + +#endif /* x86 processors */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsec.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsec.c new file mode 100644 index 00000000..89ac1dfb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsec.c @@ -0,0 +1,279 @@ +/* -*- 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) 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" + +/* + * ntsec.c + * + * Implement the POSIX-style mode bits (access permissions) for + * files and other securable objects in Windows NT using Windows + * NT's security descriptors with appropriate discretionary + * access-control lists. + */ + +/* + * The security identifiers (SIDs) for owner, primary group, + * and the Everyone (World) group. + * + * These SIDs are looked up during NSPR initialization and + * saved in this global structure (see _PR_NT_InitSids) so + * that _PR_NT_MakeSecurityDescriptorACL doesn't need to + * look them up every time. + */ +static struct { + PSID owner; + PSID group; + PSID everyone; +} _pr_nt_sids; + +/* + * Initialize the SIDs for owner, primary group, and the Everyone + * group in the _pr_nt_sids structure. + * + * This function needs to be called by NSPR initialization. + */ +void _PR_NT_InitSids(void) +{ + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + HANDLE hToken = NULL; /* initialized to an arbitrary value to + * silence a Purify UMR warning */ + UCHAR infoBuffer[1024]; + PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) infoBuffer; + PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup + = (PTOKEN_PRIMARY_GROUP) infoBuffer; + DWORD dwLength; + BOOL rv; + + /* + * Look up and make a copy of the owner and primary group + * SIDs in the access token of the calling process. + */ + rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); + if (rv == 0) { + /* + * On non-NT systems, this function is not implemented + * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are + * the other security functions. There is no point in + * going further. + * + * A process with insufficient access permissions may fail + * with the error code ERROR_ACCESS_DENIED. + */ + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d", + GetLastError())); + return; + } + + rv = GetTokenInformation(hToken, TokenOwner, infoBuffer, + sizeof(infoBuffer), &dwLength); + PR_ASSERT(rv != 0); + dwLength = GetLengthSid(pTokenOwner->Owner); + _pr_nt_sids.owner = (PSID) PR_Malloc(dwLength); + PR_ASSERT(_pr_nt_sids.owner != NULL); + rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner); + PR_ASSERT(rv != 0); + + rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer, + sizeof(infoBuffer), &dwLength); + PR_ASSERT(rv != 0); + dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup); + _pr_nt_sids.group = (PSID) PR_Malloc(dwLength); + PR_ASSERT(_pr_nt_sids.group != NULL); + rv = CopySid(dwLength, _pr_nt_sids.group, + pTokenPrimaryGroup->PrimaryGroup); + PR_ASSERT(rv != 0); + + rv = CloseHandle(hToken); + PR_ASSERT(rv != 0); + + /* Create a well-known SID for the Everyone group. */ + rv = AllocateAndInitializeSid(&SIDAuthWorld, 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &_pr_nt_sids.everyone); + PR_ASSERT(rv != 0); +} + +/* + * Free the SIDs for owner, primary group, and the Everyone group + * in the _pr_nt_sids structure. + * + * This function needs to be called by NSPR cleanup. + */ +void +_PR_NT_FreeSids(void) +{ + if (_pr_nt_sids.owner) { + PR_Free(_pr_nt_sids.owner); + } + if (_pr_nt_sids.group) { + PR_Free(_pr_nt_sids.group); + } + if (_pr_nt_sids.everyone) { + FreeSid(_pr_nt_sids.everyone); + } +} + +/* + * Construct a security descriptor whose discretionary access-control + * list implements the specified mode bits. The SIDs for owner, group, + * and everyone are obtained from the global _pr_nt_sids structure. + * Both the security descriptor and access-control list are returned + * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call. + * + * The accessTable array maps NSPR's read, write, and execute access + * rights to the corresponding NT access rights for the securable + * object. + */ +PRStatus +_PR_NT_MakeSecurityDescriptorACL( + PRIntn mode, + DWORD accessTable[], + PSECURITY_DESCRIPTOR *resultSD, + PACL *resultACL) +{ + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + DWORD cbACL; /* size of ACL */ + DWORD accessMask; + + if (_pr_nt_sids.owner == NULL) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; + } + + pSD = (PSECURITY_DESCRIPTOR) PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); + if (pSD == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + /* + * Construct a discretionary access-control list with three + * access-control entries, one each for owner, primary group, + * and Everyone. + */ + + cbACL = sizeof(ACL) + + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + + GetLengthSid(_pr_nt_sids.owner) + + GetLengthSid(_pr_nt_sids.group) + + GetLengthSid(_pr_nt_sids.everyone); + pACL = (PACL) PR_Malloc(cbACL); + if (pACL == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00400) accessMask |= accessTable[0]; + if (mode & 00200) accessMask |= accessTable[1]; + if (mode & 00100) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.owner)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00040) accessMask |= accessTable[0]; + if (mode & 00020) accessMask |= accessTable[1]; + if (mode & 00010) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.group)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + accessMask = 0; + if (mode & 00004) accessMask |= accessTable[0]; + if (mode & 00002) accessMask |= accessTable[1]; + if (mode & 00001) accessMask |= accessTable[2]; + if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, + _pr_nt_sids.everyone)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + goto failed; + } + + *resultSD = pSD; + *resultACL = pACL; + return PR_SUCCESS; + +failed: + if (pSD) { + PR_Free(pSD); + } + if (pACL) { + PR_Free(pACL); + } + return PR_FAILURE; +} + +/* + * Free the specified security descriptor and access-control list + * previously created by _PR_NT_MakeSecurityDescriptorACL. + */ +void +_PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL) +{ + if (pSD) { + PR_Free(pSD); + } + if (pACL) { + PR_Free(pACL); + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsem.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsem.c new file mode 100644 index 00000000..b25fac62 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntsem.c @@ -0,0 +1,84 @@ +/* -*- 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 ***** */ + +/* + * NT-specific semaphore handling code. + * + */ + + +#include "primpl.h" + + +void +_PR_MD_NEW_SEM(_MDSemaphore *md, PRUintn value) +{ + md->sem = CreateSemaphore(NULL, value, 0x7fffffff, NULL); +} + +void +_PR_MD_DESTROY_SEM(_MDSemaphore *md) +{ + CloseHandle(md->sem); +} + +PRStatus +_PR_MD_TIMED_WAIT_SEM(_MDSemaphore *md, PRIntervalTime ticks) +{ + int rv; + + rv = WaitForSingleObject(md->sem, PR_IntervalToMilliseconds(ticks)); + + if (rv == WAIT_OBJECT_0) + return PR_SUCCESS; + else + return PR_FAILURE; +} + +PRStatus +_PR_MD_WAIT_SEM(_MDSemaphore *md) +{ + return _PR_MD_TIMED_WAIT_SEM(md, PR_INTERVAL_NO_TIMEOUT); +} + +void +_PR_MD_POST_SEM(_MDSemaphore *md) +{ + int old_count; + + ReleaseSemaphore(md->sem, 1, &old_count); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntthread.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntthread.c new file mode 100644 index 00000000..e53b3ab9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/ntthread.c @@ -0,0 +1,563 @@ +/* -*- 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 /* for _beginthreadex() */ + +extern void _PR_Win32InitTimeZone(void); /* defined in ntmisc.c */ + +/* --- globals ------------------------------------------------ */ +PRLock *_pr_schedLock = NULL; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +BOOL _pr_use_static_tls = TRUE; +__declspec(thread) PRThread *_pr_current_fiber; +__declspec(thread) PRThread *_pr_fiber_last_run; +__declspec(thread) _PRCPU *_pr_current_cpu; +__declspec(thread) PRUintn _pr_ints_off; +DWORD _pr_currentFiberIndex; +DWORD _pr_lastFiberIndex; +DWORD _pr_currentCPUIndex; +DWORD _pr_intsOffIndex; + +_MDLock _nt_idleLock; +PRCList _nt_idleList; +PRUint32 _nt_idleCount; + +extern __declspec(thread) PRThread *_pr_io_restarted_io; +extern DWORD _pr_io_restartedIOIndex; + +/* Must check the restarted_io *before* decrementing no_sched to 0 */ +#define POST_SWITCH_WORK() \ + PR_BEGIN_MACRO \ + PRThread *restarted_io = \ + (_pr_use_static_tls ? _pr_io_restarted_io \ + : (PRThread *) TlsGetValue(_pr_io_restartedIOIndex)); \ + if (restarted_io) { \ + _nt_handle_restarted_io(restarted_io); \ + } \ + _PR_MD_LAST_THREAD()->no_sched = 0; \ + PR_END_MACRO + +void +_nt_handle_restarted_io(PRThread *restarted_io) +{ + /* After the switch we can resume an IO if needed. + * XXXMB - this needs to be done in create thread, since that could + * be the result for a context switch too.. + */ + PR_ASSERT(restarted_io->io_suspended == PR_TRUE); + PR_ASSERT(restarted_io->md.thr_bound_cpu == restarted_io->cpu); + + _PR_THREAD_LOCK(restarted_io); + if (restarted_io->io_pending == PR_FALSE) { + + /* The IO already completed, put us back on the runq. */ + int pri = restarted_io->priority; + + restarted_io->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(restarted_io->cpu); + _PR_ADD_RUNQ(restarted_io, restarted_io->cpu, pri); + _PR_RUNQ_UNLOCK(restarted_io->cpu); + } else { + _PR_SLEEPQ_LOCK(restarted_io->cpu); + _PR_ADD_SLEEPQ(restarted_io, restarted_io->sleep); + _PR_SLEEPQ_UNLOCK(restarted_io->cpu); + } + restarted_io->io_suspended = PR_FALSE; + restarted_io->md.thr_bound_cpu = NULL; + + _PR_THREAD_UNLOCK(restarted_io); + + if (_pr_use_static_tls) { + _pr_io_restarted_io = NULL; + } else { + TlsSetValue(_pr_io_restartedIOIndex, NULL); + } +} + +void +_PR_MD_EARLY_INIT() +{ + _MD_NEW_LOCK( &_nt_idleLock ); + _nt_idleCount = 0; + PR_INIT_CLIST(&_nt_idleList); + _PR_Win32InitTimeZone(); + +#if 0 + /* Make the clock tick at least once per millisecond */ + if ( timeBeginPeriod(1) == TIMERR_NOCANDO) { + /* deep yoghurt; clock doesn't tick fast enough! */ + PR_ASSERT(0); + } +#endif + + if (!_pr_use_static_tls) { + _pr_currentFiberIndex = TlsAlloc(); + _pr_lastFiberIndex = TlsAlloc(); + _pr_currentCPUIndex = TlsAlloc(); + _pr_intsOffIndex = TlsAlloc(); + _pr_io_restartedIOIndex = TlsAlloc(); + } +} + +void _PR_MD_CLEANUP_BEFORE_EXIT(void) +{ + _PR_NT_FreeSids(); + + WSACleanup(); + + if (!_pr_use_static_tls) { + TlsFree(_pr_currentFiberIndex); + TlsFree(_pr_lastFiberIndex); + TlsFree(_pr_currentCPUIndex); + TlsFree(_pr_intsOffIndex); + TlsFree(_pr_io_restartedIOIndex); + } +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + thread->md.overlapped.ioModel = _MD_BlockingIO; + thread->md.overlapped.data.mdThread = &thread->md; + + if (thread->flags & _PR_GLOBAL_SCOPE) { + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + /* + ** Warning: + ** -------- + ** NSPR requires a real handle to every thread. + ** GetCurrentThread() returns a pseudo-handle which + ** is not suitable for some thread operations (e.g., + ** suspending). Therefore, get a real handle from + ** the pseudo handle via DuplicateHandle(...) + */ + DuplicateHandle( + GetCurrentProcess(), /* Process of source handle */ + GetCurrentThread(), /* Pseudo Handle to dup */ + GetCurrentProcess(), /* Process of handle */ + &(thread->md.handle), /* resulting handle */ + 0L, /* access flags */ + FALSE, /* Inheritable */ + DUPLICATE_SAME_ACCESS); /* Options */ + } + + /* Create the blocking IO semaphore */ + thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); + if (thread->md.blocked_sema == NULL) { + return PR_FAILURE; + } + if (_native_threads_only) { + /* Create the blocking IO semaphore */ + thread->md.thr_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (thread->md.thr_event == NULL) { + return PR_FAILURE; + } + } + } + + return PR_SUCCESS; +} + +static unsigned __stdcall +pr_root(void *arg) +{ + PRThread *thread = (PRThread *)arg; + thread->md.start(thread); + return 0; +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + + thread->md.start = start; + thread->md.handle = (HANDLE) _beginthreadex( + NULL, + thread->stack->stackSize, + pr_root, + (void *)thread, + CREATE_SUSPENDED, + &(thread->id)); + if(!thread->md.handle) { + PRErrorCode prerror; + thread->md.fiber_last_error = GetLastError(); + switch (errno) { + case ENOMEM: + prerror = PR_OUT_OF_MEMORY_ERROR; + break; + case EAGAIN: + prerror = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case EINVAL: + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, errno); + return PR_FAILURE; + } + + thread->md.id = thread->id; + /* + * On windows, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL. + */ + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + /* Activate the thread */ + if ( ResumeThread( thread->md.handle ) != -1) + return PR_SUCCESS; + + PR_SetError(PR_UNKNOWN_ERROR, GetLastError()); + return PR_FAILURE; +} + +void +_PR_MD_JOIN_THREAD(_MDThread *md) +{ + DWORD rv; + + rv = WaitForSingleObject(md->handle, INFINITE); + PR_ASSERT(WAIT_OBJECT_0 == rv); +} + +void +_PR_MD_END_THREAD(void) +{ + _endthreadex(0); +} + +void +_PR_MD_YIELD(void) +{ + /* Can NT really yield at all? */ + Sleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + nativePri = THREAD_PRIORITY_BELOW_NORMAL; + break; + case PR_PRIORITY_NORMAL: + nativePri = THREAD_PRIORITY_NORMAL; + break; + case PR_PRIORITY_HIGH: + nativePri = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case PR_PRIORITY_URGENT: + nativePri = THREAD_PRIORITY_HIGHEST; + } + rv = SetThreadPriority(thread->handle, nativePri); + PR_ASSERT(rv); + if (!rv) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.acceptex_buf) { + PR_DELETE(thread->md.acceptex_buf); + } + + if (thread->md.xmit_bufs) { + PR_DELETE(thread->md.xmit_bufs); + } + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + if (_native_threads_only) { + if (thread->md.thr_event) { + rv = CloseHandle(thread->md.thr_event); + PR_ASSERT(rv); + thread->md.thr_event = 0; + } + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } + + /* Don't call DeleteFiber on current fiber or we'll kill the whole thread. + * Don't call free(thread) until we've switched off the thread. + * So put this fiber (or thread) on a list to be deleted by the idle + * fiber next time we have a chance. + */ + if (!(thread->flags & (_PR_ATTACHED|_PR_GLOBAL_SCOPE))) { + _MD_LOCK(&_nt_idleLock); + _nt_idleCount++; + PR_APPEND_LINK(&thread->links, &_nt_idleList); + _MD_UNLOCK(&_nt_idleLock); + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.acceptex_buf) { + PR_DELETE(thread->md.acceptex_buf); + } + + if (thread->md.xmit_bufs) { + PR_DELETE(thread->md.xmit_bufs); + } + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + + if (_native_threads_only) { + if (thread->md.thr_event) { + rv = CloseHandle(thread->md.thr_event); + PR_ASSERT(rv); + thread->md.thr_event = 0; + } + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } + + if (thread->flags & _PR_GLOBAL_SCOPE) { + _MD_SET_CURRENT_THREAD(NULL); + } +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +#ifdef HAVE_FIBERS + +void +_pr_fiber_mainline(void *unused) +{ + PRThread *fiber = _PR_MD_CURRENT_THREAD(); + + POST_SWITCH_WORK(); + + fiber->md.fiber_fn(fiber->md.fiber_arg); +} + +PRThread *_PR_MD_CREATE_USER_THREAD( + PRUint32 stacksize, void (*start)(void *), void *arg) +{ + PRThread *thread; + + if ( (thread = PR_NEW(PRThread)) == NULL ) { + return NULL; + } + + memset(thread, 0, sizeof(PRThread)); + thread->md.fiber_fn = start; + thread->md.fiber_arg = arg; + thread->md.fiber_stacksize = stacksize; + return thread; +} + +void +_PR_MD_CREATE_PRIMORDIAL_USER_THREAD(PRThread *thread) +{ + thread->md.fiber_id = ConvertThreadToFiber(NULL); + PR_ASSERT(thread->md.fiber_id); + _MD_SET_CURRENT_THREAD(thread); + _MD_SET_LAST_THREAD(thread); + thread->no_sched = 1; + return; +} + +void +_PR_MD_INIT_CONTEXT(PRThread *thread, char *top, void (*start) (void), PRBool *status) +{ + thread->md.fiber_fn = (void (*)(void *))start; + thread->md.fiber_id = CreateFiber(thread->md.fiber_stacksize, + (LPFIBER_START_ROUTINE)_pr_fiber_mainline, NULL); + if (thread->md.fiber_id != 0) + *status = PR_TRUE; + else { + DWORD oserror = GetLastError(); + PRErrorCode prerror; + if (oserror == ERROR_NOT_ENOUGH_MEMORY) { + prerror = PR_OUT_OF_MEMORY_ERROR; + } else { + prerror = PR_UNKNOWN_ERROR; + } + PR_SetError(prerror, oserror); + *status = PR_FALSE; + } +} + +void +_PR_MD_SWITCH_CONTEXT(PRThread *thread) +{ + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + thread->md.fiber_last_error = GetLastError(); + _PR_Schedule(); +} + +void +_PR_MD_RESTORE_CONTEXT(PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + /* The user-level code for yielding will happily add ourselves to the runq + * and then switch to ourselves; the NT fibers can't handle switching to + * ourselves. + */ + if (thread != me) { + SetLastError(thread->md.fiber_last_error); + _MD_SET_CURRENT_THREAD(thread); + _PR_MD_SET_LAST_THREAD(me); + thread->no_sched = 1; + SwitchToFiber(thread->md.fiber_id); + POST_SWITCH_WORK(); + } +} + + +#endif /* HAVE_FIBERS */ + +PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + int rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; +} + +PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + PRInt32 rv, system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); + + return rv?0:-1; +} + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + /* + ** There seems to be some doubt about whether or not SuspendThread + ** is a synchronous function. The test afterwards is to help veriry + ** that it is, which is what Microsoft says it is. + */ + PRUintn rv = SuspendThread(thread->md.handle); + PR_ASSERT(0xffffffffUL != rv); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + ResumeThread(thread->md.handle); + } +} + +PRThread* +_MD_CURRENT_THREAD(void) +{ +PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(thread != NULL); + return thread; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/objs.mk b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/objs.mk new file mode 100644 index 00000000..36f21a44 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/objs.mk @@ -0,0 +1,94 @@ +# +# ***** 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 ***** + + +ifeq ($(OS_TARGET),WINNT) +CSRCS = ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + ntio.c \ + ntthread.c \ + ntdllmn.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c +else +ifeq ($(OS_TARGET),WIN95) +CSRCS = ntmisc.c \ + ntsec.c \ + ntsem.c \ + ntinrval.c \ + ntgc.c \ + w95thred.c \ + w95io.c \ + w95cv.c \ + w95sock.c \ + win32_errors.c \ + w32ipcsem.c \ + w32poll.c \ + w32rng.c \ + w32shm.c \ + w95dllmain.c +else +ifeq ($(OS_TARGET),WIN16) +CSRCS = w16null.c \ + w16thred.c \ + w16proc.c \ + w16fmem.c \ + w16sock.c \ + w16mem.c \ + w16io.c \ + w16gc.c \ + w16error.c \ + w16stdio.c \ + w16callb.c \ + ntinrval.c +endif # win16 +endif # win95 +endif # winnt + +CSRCS += $(PR_MD_CSRCS) +ASFILES += $(PR_MD_ASFILES) + +OBJS += $(addprefix md/windows/$(OBJDIR)/,$(CSRCS:.c=.$(OBJ_SUFFIX))) \ + $(addprefix md/windows/$(OBJDIR)/,$(ASFILES:.s=.$(OBJ_SUFFIX))) + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16callb.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16callb.c new file mode 100644 index 00000000..3f7b4eea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16callb.c @@ -0,0 +1,262 @@ +/* -*- 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 ***** */ + +/* +** w16callb.c -- Implement Win16 Callback functions +** +** Functions here are to replace functions normally in +** LIBC which are not implemented in MSVC's LIBC. +** Some clients of NSPR expect to statically link +** to NSPR and get these functions. +** +** Some are implemented as callbacks to the .EXE +** some are implemented directly in this module. +** +*/ + +#include "primpl.h" +#include "windowsx.h" + +/* +** _pr_callback_funcs -- This is where clients register the +** callback function structure. +*/ +struct PRMethodCallbackStr * _pr_callback_funcs; + +/* +** PR_MDInitWin16() -- Register the PRMethodCallback table pointer +** +*/ +void PR_MDRegisterCallbacks(struct PRMethodCallbackStr *f) +{ + _pr_callback_funcs = f; +} + +/* +** NSPR re-implenentations of various C runtime functions: +*/ + +/* +** PR_MD_printf() -- exported as printf() +** +*/ +int PR_MD_printf(const char *fmt, ...) +{ + char buffer[1024]; + int ret = 0; + va_list args; + + va_start(args, fmt); + +#ifdef DEBUG + PR_vsnprintf(buffer, sizeof(buffer), fmt, args); + { + if (_pr_callback_funcs != NULL && _pr_callback_funcs->auxOutput != NULL) { + (* _pr_callback_funcs->auxOutput)(buffer); + } else { + OutputDebugString(buffer); + } + } +#endif + + va_end(args); + return ret; +} + +/* +** PR_MD_sscanf() -- exported as sscanf() +** +*/ +int PR_MD_sscanf(const char *buf, const char *fmt, ...) +{ + int retval; + va_list arglist; + + va_start(arglist, fmt); + retval = vsscanf((const unsigned char *)buf, (const unsigned char *)fmt, arglist); + va_end(arglist); + return retval; +} + +/* +** PR_MD_strftime() -- exported as strftime +** +*/ +size_t PR_MD_strftime(char *s, size_t len, const char *fmt, const struct tm *p) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->strftime)(s, len, fmt, p); + } else { + PR_ASSERT(0); + return 0; + } +} + + +/* +** PR_MD_malloc() -- exported as malloc() +** +*/ +void *PR_MD_malloc( size_t size ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->malloc)( size ); + } else { + return GlobalAllocPtr(GPTR, (DWORD)size); + } +} /* end malloc() */ + +/* +** PR_MD_calloc() -- exported as calloc() +** +*/ +void *PR_MD_calloc( size_t n, size_t size ) +{ + void *p; + size_t sz; + + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->calloc)( n, size ); + } else { + sz = n * size; + p = GlobalAllocPtr(GPTR, (DWORD)sz ); + memset( p, 0x00, sz ); + return p; + } +} /* end calloc() */ + +/* +** PR_MD_realloc() -- exported as realloc() +** +*/ +void *PR_MD_realloc( void* old_blk, size_t size ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->realloc)( old_blk, size ); + } else { + return GlobalReAllocPtr( old_blk, (DWORD)size, GPTR); + } +} /* end realloc */ + +/* +** PR_MD_free() -- exported as free() +** +*/ +void PR_MD_free( void *ptr ) +{ + if( _pr_callback_funcs ) { + (*_pr_callback_funcs->free)( ptr ); + return; + } else { + GlobalFreePtr( ptr ); + return; + } +} /* end free() */ + +/* +** PR_MD_getenv() -- exported as getenv() +** +*/ +char *PR_MD_getenv( const char *name ) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->getenv)( name ); + } else { + return 0; + } +} /* end getenv() */ + + +/* +** PR_MD_perror() -- exported as perror() +** +** well, not really (lth. 12/5/97). +** XXX hold this thought. +** +*/ +void PR_MD_perror( const char *prefix ) +{ + return; +} /* end perror() */ + +/* +** PR_MD_putenv() -- exported as putenv() +** +*/ +int PR_MD_putenv(const char *assoc) +{ + if( _pr_callback_funcs ) { + return (*_pr_callback_funcs->putenv)(assoc); + } else { + PR_ASSERT(0); + return NULL; + } +} + +/* +** PR_MD_fprintf() -- exported as fprintf() +** +*/ +int PR_MD_fprintf(FILE *fPtr, const char *fmt, ...) +{ + char buffer[1024]; + va_list args; + + va_start(args, fmt); + PR_vsnprintf(buffer, sizeof(buffer), fmt, args); + + if (fPtr == NULL) + { + if (_pr_callback_funcs != NULL && _pr_callback_funcs->auxOutput != NULL) + { + (* _pr_callback_funcs->auxOutput)(buffer); + } + else + { + OutputDebugString(buffer); + } + } + else + { + fwrite(buffer, 1, strlen(buffer), fPtr); /* XXX Is this a sec. hole? */ + } + + va_end(args); + return 0; +} + +/* end w16callb.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16error.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16error.c new file mode 100644 index 00000000..72d1725b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16error.c @@ -0,0 +1,252 @@ +/* -*- 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 ***** */ + +/* +** Note: A single error mapping function is provided. +** +*/ +#include "prerror.h" +#include +#include + + +void _PR_MD_map_error( int err ) +{ + + switch ( err ) + { + case ENOENT: /* No such file or directory */ + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + break; + case E2BIG: /* Argument list too big */ + PR_SetError( PR_INVALID_ARGUMENT_ERROR, err ); + break; + case ENOEXEC: /* Exec format error */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EBADF: /* Bad file number */ + PR_SetError( PR_BAD_DESCRIPTOR_ERROR, err ); + break; + case ENOMEM: /* Not enough Memory */ + PR_SetError( PR_OUT_OF_MEMORY_ERROR, err ); + break; + case EACCES: /* Permission denied */ + PR_SetError( PR_NO_ACCESS_RIGHTS_ERROR, err ); + break; + case EEXIST: /* File exists */ + + /* RESTART here */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EXDEV: /* Cross device link */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EINVAL: /* Invalid argument */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENFILE: /* File table overflow */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EMFILE: /* Too many open files */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOSPC: /* No space left on device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* math errors */ + case EDOM: /* Argument too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ERANGE: /* Result too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* file locking error */ + case EDEADLK: /* Resource deadlock would occur */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EINTR: /* Interrupt */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ECHILD: /* Child does not exist */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + /* POSIX errors */ + case EAGAIN: /* Resource unavailable, try again */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EBUSY: /* Device or Resource is busy */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EFBIG: /* File too large */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EIO: /* I/O error */ + PR_SetError( PR_IO_ERROR, err ); + break; + case EISDIR: /* Is a directory */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTDIR: /* Not a directory */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EMLINK: /* Too many links */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTBLK: /* Block device required */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTTY: /* Not a character device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENXIO: /* No such device or address */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EPERM: /* Not owner */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EPIPE: /* Broken pipe */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EROFS: /* Read only file system */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ESPIPE: /* Illegal seek */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ESRCH: /* No such process */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ETXTBSY: /* Text file busy */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case EFAULT: /* Bad address */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENAMETOOLONG: /* Name too long */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENODEV: /* No such device */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOLCK: /* No locks available on system */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOSYS: /* Unknown system call */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + case ENOTEMPTY: /* Directory not empty */ + /* Normative Addendum error */ + case EILSEQ: /* Multibyte/widw character encoding error */ + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + + /* WinSock errors */ + case WSAEACCES: + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, err); + break; + case WSAEADDRINUSE: + PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); + break; + case WSAEADDRNOTAVAIL: + PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); + break; + case WSAEAFNOSUPPORT: + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); + break; + case WSAEBADF: + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); + break; + case WSAECONNREFUSED: + PR_SetError(PR_CONNECT_REFUSED_ERROR, err); + break; + case WSAEFAULT: + PR_SetError(PR_ACCESS_FAULT_ERROR, err); + break; + case WSAEINVAL: + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, err); + break; + case WSAEISCONN: + PR_SetError(PR_IS_CONNECTED_ERROR, err); + break; + case WSAEMFILE: + PR_SetError(PR_PROC_DESC_TABLE_FULL_ERROR, err); + break; + case WSAENETDOWN: + case WSAENETUNREACH: + PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); + break; + case WSAENOBUFS: + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, err); + break; + case WSAENOPROTOOPT: + case WSAEMSGSIZE: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); + break; + case WSAENOTCONN: + PR_SetError(PR_NOT_CONNECTED_ERROR, err); + break; + case WSAENOTSOCK: + PR_SetError(PR_NOT_SOCKET_ERROR, err); + break; + case WSAEOPNOTSUPP: + PR_SetError(PR_NOT_TCP_SOCKET_ERROR, err); + break; + case WSAEPROTONOSUPPORT: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case WSAETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, err); + break; + case WSAEINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, err ); + break; + case WSASYSNOTREADY: + case WSAVERNOTSUPPORTED: + PR_SetError(PR_PROTOCOL_NOT_SUPPORTED_ERROR, err); + break; + case WSAEWOULDBLOCK: + PR_SetError(PR_WOULD_BLOCK_ERROR, err); + break; + + default: + PR_SetError( PR_UNKNOWN_ERROR, err ); + break; + } + return; +} /* end _MD_map_win16_error() */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16fmem.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16fmem.c new file mode 100644 index 00000000..55df5128 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16fmem.c @@ -0,0 +1,85 @@ +/* -*- 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" + +/* + ********************************************************************** + * + * Memory-mapped files are not implemented on Win16. + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PRInt64 offset, + PRUint32 len) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16gc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16gc.c new file mode 100644 index 00000000..cd3a6528 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16gc.c @@ -0,0 +1,86 @@ +/* -*- 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 + +PRWord * +_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) +{ + if (isCurrent) + { + _MD_SAVE_CONTEXT(t); + } + /* + ** In Win16 because the premption is "cooperative" it can never be the + ** case that a register holds the sole reference to an object. It + ** will always have been pushed onto the stack before the thread + ** switch... So don't bother to scan the registers... + */ + *np = 0; + + return (PRWord *) CONTEXT(t); +} + +#if 0 +#ifndef SPORT_MODEL + +#define MAX_SEGMENT_SIZE (65536l - 4096l) + +/************************************************************************/ +/* +** Machine dependent GC Heap management routines: +** _MD_GrowGCHeap +*/ +/************************************************************************/ + +extern void * +_MD_GrowGCHeap(uint32 *sizep) +{ + void *addr; + + if( *sizep > MAX_SEGMENT_SIZE ) { + *sizep = MAX_SEGMENT_SIZE; + } + + addr = malloc((size_t)*sizep); + return addr; +} + +#endif /* SPORT_MODEL */ +#endif /* 0 */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16io.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16io.c new file mode 100644 index 00000000..6089d399 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16io.c @@ -0,0 +1,855 @@ +/* -*- 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 +#include +#include +#include + + +/* +** Sleep this many milliseconds on each I/O operation +** to cause an intentional thread switch. +*/ +#define _PR_MD_WIN16_DELAY 1 + + +/* +** PR_MD_RegisterW16StdioCallbacks() -- Register Win16 stdio callback functions +** +** This public function call is unique to Win16. +** ... Sigh ... So much for platform independence. +** +** To get stdio to work from a command line executable, the stdio stream +** calls must be issued from the .EXE file; calling them from the .DLL +** sends the output to the bit-bucket. Therefore, the .EXE wanting to +** do stdio to the console window (must be built as a "quickwin" application) +** must have the wrapper functions defined in this module statically linked +** into the .EXE. +** +** There appears to be nothing you can do to get stdio to work from a +** Win16 GUI application. Oh Well! +** +*/ +PRStdinRead _pr_md_read_stdin = 0; +PRStdoutWrite _pr_md_write_stdout = 0; +PRStderrWrite _pr_md_write_stderr = 0; + +PRStatus +PR_MD_RegisterW16StdioCallbacks( PRStdinRead inReadf, PRStdoutWrite outWritef, PRStderrWrite errWritef ) +{ + _pr_md_write_stdout = outWritef; + _pr_md_write_stderr = errWritef; + _pr_md_read_stdin = inReadf; + + return(PR_SUCCESS); +} /* end PR_MD_RegisterW16StdioCallbacks() */ + + +/* +** _PR_MD_OPEN() -- Open a file +** +** Returns: a fileHandle or -1 +** +** +*/ +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + PRInt32 file; + int access = O_BINARY; + int rights = 0; + + + /* + ** Map NSPR open flags to os open flags + */ + if (osflags & PR_RDONLY ) + access |= O_RDONLY; + if (osflags & PR_WRONLY ) + access |= O_WRONLY; + if (osflags & PR_RDWR ) + access |= O_RDWR; + if (osflags & PR_CREATE_FILE ) + { + access |= O_CREAT; + rights |= S_IRWXU; + } + if (osflags & PR_TRUNCATE) + access |= O_TRUNC; + if (osflags & PR_APPEND) + access |= O_APPEND; + else + access |= O_RDONLY; + + /* + ** Open the file + */ + file = (PRInt32) sopen( name, access, SH_DENYNO, rights ); + if ( -1 == (PRInt32)file ) + { + _PR_MD_MAP_OPEN_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return file; +} + +/* +** _PR_MD_READ() - Read something +** +** Returns: bytes read or -1 +** +*/ +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PRInt32 rv; + + if ( (PR_GetDescType(fd) == PR_DESC_FILE) && + ( fd->secret->md.osfd == PR_StandardInput ) && + ( _pr_md_write_stdout )) + { + rv = (*_pr_md_read_stdin)( buf, len); + } + else + { + rv = read( fd->secret->md.osfd, buf, len ); + } + + if ( rv == -1) + { + _PR_MD_MAP_READ_ERROR( errno ); + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + +/* +** _PR_MD_WRITE() - Write something +** +** Returns: bytes written or -1 +** +** Note: for file handles 1 and 2 (stdout and stderr) +** call the Win16 NSPR stdio callback functions, if they are +** registered. +** +*/ +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 rv; + + if ( (PR_GetDescType(fd) == PR_DESC_FILE)) + { + switch ( fd->secret->md.osfd ) + { + case PR_StandardOutput : + if ( _pr_md_write_stdout ) + rv = (*_pr_md_write_stdout)( (void *)buf, len); + else + rv = len; /* fake success */ + break; + + case PR_StandardError : + if ( _pr_md_write_stderr ) + rv = (*_pr_md_write_stderr)( (void *)buf, len); + else + rv = len; /* fake success */ + break; + + default: + rv = write( fd->secret->md.osfd, buf, len ); + if ( rv == -1 ) + { + _PR_MD_MAP_WRITE_ERROR( errno ); + } + break; + } + } + else + { + rv = write( fd->secret->md.osfd, buf, len ); + if ( rv == -1 ) + { + _PR_MD_MAP_WRITE_ERROR( errno ); + } + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* --- end _PR_MD_WRITE() --- */ + +/* +** _PR_MD_LSEEK() - Seek to position in a file +** +** Note: 'whence' maps directly to PR_... +** +** Returns: +** +*/ +PRInt32 +_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence) +{ + PRInt32 rv; + + rv = lseek( fd->secret->md.osfd, offset, whence ); + if ( rv == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_LSEEK64() -- Seek to position in file, 64bit offset. +** +*/ +PRInt64 +_PR_MD_LSEEK64( PRFileDesc *fd, PRInt64 offset, int whence ) +{ + PRInt64 test; + PRInt32 rv, off; + LL_SHR(test, offset, 32); + if (!LL_IS_ZERO(test)) + { + PR_SetError(PR_FILE_TOO_BIG_ERROR, 0); + LL_I2L(test, -1); + return test; + } + LL_L2I(off, offset); + rv = _PR_MD_LSEEK(fd, off, whence); + LL_I2L(test, rv); + return test; +} /* end _PR_MD_LSEEK64() */ + +/* +** _PR_MD_FSYNC() - Flush file buffers. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + PRInt32 rv; + + rv = (PRInt32) fsync( fd->secret->md.osfd ); + if ( rv == -1 ) + { + _PR_MD_MAP_FSYNC_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_CLOSE() - Close an open file handle +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_CLOSE_FILE(PRInt32 osfd) +{ + PRInt32 rv; + + rv = (PRInt32) close( osfd ); + if ( rv == -1 ) + { + _PR_MD_MAP_CLOSE_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} /* --- end _MD_CloseFile() --- */ + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName + +/* +** FlipSlashes() - Make forward slashes ('/') into backslashes +** +** Returns: void +** +** +*/ +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp++; + } +} + + +/* +** _PR_MD_OPEN_DIR() - Open a Directory. +** +** Returns: +** +** +*/ +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + d->dir = opendir( name ); + + if ( d->dir == NULL ) + { + _PR_MD_MAP_OPENDIR_ERROR( errno ); + return( PR_FAILURE ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( PR_SUCCESS ); +} + + +/* +** _PR_MD_READ_DIR() - read next directory entry +** +** +*/ +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + struct dirent *de; + int err; + + for (;;) + { + de = readdir( d->dir ); + if ( de == NULL ) { + _PR_MD_MAP_READDIR_ERROR( errno); + return 0; + } + if ((flags & PR_SKIP_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == 0)) + continue; + if ((flags & PR_SKIP_DOT_DOT) && + (de->d_name[0] == '.') && (de->d_name[1] == '.') && + (de->d_name[2] == 0)) + continue; + break; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return de->d_name; +} + +/* +** _PR_MD_CLOSE_DIR() - Close a directory. +** +** +*/ +PRInt32 +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + PRInt32 rv; + + if ( d->dir ) + { + rv = closedir( d->dir ); + if (rv != 0) + { + _PR_MD_MAP_CLOSEDIR_ERROR( errno ); + } + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + + +/* +** _PR_MD_DELETE() - Delete a file. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_DELETE(const char *name) +{ + PRInt32 rv; + + rv = (PRInt32) remove( name ); + if ( rv != 0 ) + { + _PR_MD_MAP_DELETE_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + + +/* +** _PR_MD_STAT() - Get file attributes by filename +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if ( rv == -1 ) + { + _PR_MD_MAP_STAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_GETFILEINFO() - Get file attributes by filename +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + struct _stat sb; + PRInt32 rv; + + if ( (rv = _stat(fn, &sb)) == 0 ) { + if (info) { + if (S_IFREG & sb.st_mode) + info->type = PR_FILE_FILE ; + else if (S_IFDIR & sb.st_mode) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + info->size = sb.st_size; + LL_I2L(info->modifyTime, sb.st_mtime); + LL_I2L(info->creationTime, sb.st_ctime); + } + } + else + { + _PR_MD_MAP_STAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + PRFileInfo info32; + + PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32); + if (0 == rv) + { + info->type = info32.type; + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + LL_I2L(info->size, info32.size); + } + return(rv); +} + +/* +** _PR_MD_GETOPENFILEINFO() - Get file attributes from an open file handle +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + struct stat statBuf; + PRInt32 rv = PR_SUCCESS; + + rv = fstat( fd->secret->md.osfd, &statBuf ); + if ( rv == 0) + { + if (statBuf.st_mode & S_IFREG ) + info->type = PR_FILE_FILE; + else if ( statBuf.st_mode & S_IFDIR ) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_OTHER; + info->size = statBuf.st_size; + LL_I2L(info->modifyTime, statBuf.st_mtime); + LL_I2L(info->creationTime, statBuf.st_ctime); + + } + else + { + _PR_MD_MAP_FSTAT_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + PRFileInfo info32; + + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32); + if (0 == rv) + { + info->type = info32.type; + info->modifyTime = info32.modifyTime; + info->creationTime = info32.creationTime; + LL_I2L(info->size, info32.size); + } + return(rv); +} + +/* +** _PR_MD_RENAME() - Rename a file +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + PRInt32 rv; + + rv = rename( from, to ); + if ( rv == -1 ) + { + _PR_MD_MAP_RENAME_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return( rv ); +} + +/* +** _PR_MD_ACCESS() - Return file acesss attribute. +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_ACCESS(const char *name, PRIntn how) +{ + PRInt32 rv; + int mode = 0; + + if ( how & PR_ACCESS_WRITE_OK ) + mode |= W_OK; + if ( how & PR_ACCESS_READ_OK ) + mode |= R_OK; + + rv = (PRInt32) access( name, mode ); + if ( rv == -1 ) + { + _PR_MD_MAP_ACCESS_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_MKDIR() - Make a directory +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + PRInt32 rv; + + rv = mkdir( name ); + if ( rv == 0 ) + { + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_SUCCESS; + } + else + { + _PR_MD_MAP_MKDIR_ERROR( errno ); + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_FAILURE; + } +} + +/* +** _PR_MD_RMDIR() - Delete a directory +** +** Returns: +** +** +*/ +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + PRInt32 rv; + + rv = (PRInt32) rmdir( name ); + if ( rv == -1 ) + { + _PR_MD_MAP_RMDIR_ERROR( errno ); + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return(rv); +} + +/* +** _PR_MD_LOCKFILE() - Lock a file. +** +** The _locking() call locks relative to the current file pointer. +** This function is required to lock all of the file, so, +** 1. Seek to the beginning of the file, preserving the original position. +** 2. Lock the file, pausing if it is locked by someone else, and +** try again. +** 3. Re-position to the original position in the file. +** +** For unlocking, a similar protocol of positioning is required. +** +*/ +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return to our caller */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* what the system call returns to us */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Attempt to lock the file. + ** If someone else has it, Sleep-a-while and try again. + */ + for( rc = -1; rc != 0; ) + { + rc = _locking( f, _LK_NBLCK , 0x7fffffff ); + if ( rc == -1 ) + { + if ( errno == EACCES ) + { + PR_Sleep( 100 ); + continue; + } + else + { + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + break; + } + } + } /* end for() */ + + /* + ** Now that the file is locked, re-position to + ** the original file position. + ** + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return PR_SUCCESS; +} /* end _PR_MD_LOCKFILE() */ + +/* +** _PR_MD_TLOCKFILE() - Test and Lock file. +** +** The _locking() call locks relative to the current file pointer. +** This function is required to lock all of the file, so, +** 1. Seek to the beginning of the file, preserving the original position. +** 2. Attempt to Lock the file. +** If the file is locked by someone else, try NO MORE. +** 3. Re-position to the original position in the file. +** +** See the discussion of _PR_MD_LOCKFILE +** +** +*/ +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* return value from system call */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Attempt to lock the file. One ping; one ping only, Vasily. + ** If someone else has it, Reposition and return failure. + */ + rc = _locking( f, _LK_NBLCK , 0x7fffffff ); + if ( rc == -1 ) + { + if ( errno != EACCES ) + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + } + + /* + ** Now that the file is locked, maybe, re-position to + ** the original file position. + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* end _PR_MD_TLOCKFILE() */ + + +/* +** _PR_MD_UNLOCKFILE() - Unlock a file. +** +** See the discussion of _PR_MD_LOCKFILE +** +*/ +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv = PR_SUCCESS; /* What we return */ + long seekOrigin; /* original position in file */ + PRInt32 rc; /* return value from system call */ + + /* + ** Seek to beginning of file, saving original position. + */ + seekOrigin = lseek( f, 0l, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + return( PR_FAILURE ); + } + + /* + ** Unlock the file. + */ + rc = _locking( f, _LK_UNLCK , 0x7fffffff ); + if ( rc == -1 ) + { + _PR_MD_MAP_LOCKF_ERROR( errno ); + rv = PR_FAILURE; + } + + /* + ** Now that the file is unlocked, re-position to + ** the original file position. + */ + rc = lseek( f, seekOrigin, SEEK_SET ); + if ( rc == -1 ) + { + _PR_MD_MAP_LSEEK_ERROR( errno ); + rv = PR_FAILURE; + } + PR_Sleep( _PR_MD_WIN16_DELAY ); + return rv; +} /* end _PR_MD_UNLOCKFILE() */ + +/* +** PR_Stat() -- Return status on a file +** +** This is a hack! ... See BugSplat: 98516 +** Basically, this hack takes a name and stat buffer as input. +** The input stat buffer is presumed to be a Microsoft stat buffer. +** The functions does a Watcom stat() then maps the result to +** the MS stat buffer. ... +** +*/ +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) +{ + PRInt32 rv; + _MDMSStat *mssb = (_MDMSStat*) buf; /* this is Microsoft's stat buffer */ + struct stat statBuf; /* this is Watcom's stat buffer */ + + /* First, get Watcom's idea of stat + ** then reformat it into a Microsoft idea of stat + */ + rv = (PRInt32) _stat( name, &statBuf); + if (rv == 0l ) + { + mssb->st_dev = statBuf.st_dev; + mssb->st_ino = statBuf.st_ino; /* not used, really */ + mssb->st_mode = statBuf.st_mode; + mssb->st_nlink = 1; /* always 1, says MS */ + mssb->st_uid = statBuf.st_uid; + mssb->st_gid = statBuf.st_gid; + mssb->st_rdev = statBuf.st_rdev; /* please Gh0d! Let these be the same */ + mssb->st_size = statBuf.st_size; + mssb->st_atime = statBuf.st_atime; + mssb->st_mtime = statBuf.st_mtime; + mssb->st_ctime = statBuf.st_ctime; + } + return rv; +} /* end PR_Stat() */ + + + +/* $$ end W16io.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16mem.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16mem.c new file mode 100644 index 00000000..1c07099d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16mem.c @@ -0,0 +1,84 @@ +/* -*- 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 ***** */ + +/******************************************************************* +** w16mem.c -- Implement memory segment functions. +** +** +******************************************************************** +*/ +#include "primpl.h" + + +/* +** Allocate a new memory segment. +** +** Return the segment's access rights and size. +*/ +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. + */ + + seg->vaddr = (char *)malloc(size); + + if (seg->vaddr == NULL) { + return PR_FAILURE; + } + + seg->size = size; + + return PR_SUCCESS; +} /* --- end _MD_AllocSegment() --- */ + + +/* +** 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 ); + return; +} /* --- end _MD_FreeSegment() --- */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16null.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16null.c new file mode 100644 index 00000000..7f4c5fc1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16null.c @@ -0,0 +1,116 @@ +/* -*- 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 + + +struct _MDLock _pr_ioq_lock; +HINSTANCE _pr_hInstance = NULL; +char * _pr_top_of_task_stack; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +/* + *----------------------------------------------------------------------- + * + * 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 + * implementation for Windows. + * Cf. time_t time(time_t *tp) + * + *----------------------------------------------------------------------- + */ + +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +PR_IMPLEMENT(PRTime) +#endif +PR_Now(void) +{ + PRInt64 s, ms, ms2us, s2us; + struct timeb b; + + ftime(&b); + LL_I2L(ms2us, PR_USEC_PER_MSEC); + LL_I2L(s2us, PR_USEC_PER_SEC); + LL_I2L(s, b.time); + LL_I2L(ms, (PRInt32)b.millitm); + LL_MUL(ms, ms, ms2us); + LL_MUL(s, s, s2us); + LL_ADD(s, s, ms); + return s; +} + + + +char *_PR_MD_GET_ENV(const char *name) +{ + return NULL; +} + +PRIntn +_PR_MD_PUT_ENV(const char *name) +{ + return NULL; +} + +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + _pr_hInstance = hInst; + return TRUE; +} + + + +void +_PR_MD_EARLY_INIT() +{ + _tzset(); + return; +} + +void +_PR_MD_WAKEUP_CPUS( void ) +{ + return; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16proc.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16proc.c new file mode 100644 index 00000000..f1a9eab8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16proc.c @@ -0,0 +1,77 @@ +/* -*- 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 + + +/* +** Create Process. +*/ +PRProcess * _PR_CreateWindowsProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _PR_DetachWindowsProcess(PRProcess *process) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_WaitWindowsProcess(PRProcess *process, + PRInt32 *exitCode) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_KillWindowsProcess(PRProcess *process) +{ + PR_ASSERT(!"Not implemented"); + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16sock.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16sock.c new file mode 100644 index 00000000..78e95906 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16sock.c @@ -0,0 +1,1170 @@ +/* -*- 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" + +static int winsockNotPresent = 0; + +void +_PR_MD_INIT_IO() +{ + int rv; + + WORD WSAVersion = 0x0101; + WSADATA WSAData; + + rv = WSAStartup( WSAVersion, &WSAData ); + if ( rv != 0 ) + { + _PR_MD_MAP_WSASTARTUP_ERROR(WSAGetLastError()); + winsockNotPresent = 1; + } + return; +} + +void +_PR_MD_CLEANUP_BEFORE_EXIT(void) +{ + int rv; + int err; + + rv = WSACleanup(); + if ( rv == SOCKET_ERROR ) + { + err = WSAGetLastError(); + PR_ASSERT(0); + } + return; +} /* end _PR_MD_CLEANUP_BEFORE_EXIT() */ + +/* --- SOCKET IO --------------------------------------------------------- */ + +PRStatus +_MD_WindowsGetHostName(char *name, PRUint32 namelen) +{ + PRIntn rv; + PRInt32 syserror; + + rv = gethostname(name, (PRInt32) namelen); + if (0 == rv) { + return PR_SUCCESS; + } + syserror = WSAGetLastError(); + PR_ASSERT(WSANOTINITIALISED != syserror); + _PR_MD_MAP_GETHOSTNAME_ERROR(syserror); + return PR_FAILURE; +} + + +PRInt32 +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + PRUint32 one = 1; + PRInt32 rv; + PRInt32 err; + + if ( winsockNotPresent ) + return( (PRInt32)INVALID_SOCKET ); + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET ) + { + int rv = GetLastError(); + closesocket(sock); + _PR_MD_MAP_SOCKET_ERROR(rv); + return (PRInt32)INVALID_SOCKET; + } + + /* + ** Make the socket Non-Blocking + */ + rv = ioctlsocket( sock, FIONBIO, &one); + if ( rv != 0 ) + { + err = WSAGetLastError(); + return -1; + } + + return (PRInt32)sock; +} + + +PRInt32 +_PR_MD_SOCKETAVAILABLE(PRFileDesc *fd) +{ + PRUint32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_PR_MD_CLOSE_SOCKET(PRInt32 osfd) +{ + PRInt32 rv; + + rv = closesocket((SOCKET) osfd ); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + + return rv; +} + +PRInt32 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + int rv, err; + + rv = listen(fd->secret->md.osfd, backlog); + if ( rv == SOCKET_ERROR ) { + _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError()); + return(-1); + } + return(rv); +} + +PRInt32 +_PR_MD_ACCEPT(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, + PRIntervalTime timeout ) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 err; + PRIntn rv; + + MD_ASSERTINT( *addrlen ); + + while ((rv = (SOCKET)accept(osfd, (struct sockaddr *) addr, + (int *)addrlen)) == INVALID_SOCKET ) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_ACCEPT_ERROR(err); + } +done: + if ( rv == INVALID_SOCKET ) + return(-1 ); + else + return(rv); +} /* end _MD_Accept() */ + + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) { + err = WSAGetLastError(); + if (err == WSAEISCONN) { + rv = 0; + break; + } + /* for winsock1.1, it reports EALREADY as EINVAL */ + if ((err == WSAEWOULDBLOCK) + ||(err == WSAEALREADY) + || (err = WSAEINVAL)) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + + if (rv < 0) { + _PR_MD_MAP_CONNECT_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; + int one = 1; + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = recv(osfd,buf,amount,flags)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECV_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = send(osfd,buf,amount,flags)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SEND_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc*fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((rv = sendto(osfd, buf, amount, flags, + (struct sockaddr *) addr, addrlen)) == -1) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_WRITE, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_SENDTO_ERROR(err); + } +done: + return rv; +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRInt32 rv, err; + + while ((*addrlen = PR_NETADDR_SIZE(addr)), + ((rv = recvfrom(osfd, buf, amount, flags, + (struct sockaddr FAR *) addr,(int FAR *)addrlen)) == -1)) { + err = WSAGetLastError(); + if ( err == WSAEWOULDBLOCK ) { + if (fd->secret->nonblocking) { + break; + } + if (_PR_WaitForFD(osfd, PR_POLL_READ, timeout) == 0) { + if ( _PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + } else + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + } + rv = -1; + goto done; + } else if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + goto done; + } + } else if ((err == WSAEINTR) && (!_PR_PENDING_INTERRUPT(me))){ + continue; + } else { + break; + } + } + if (rv < 0) { + _PR_MD_MAP_RECVFROM_ERROR(err); + } +done: + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index < iov_size; index++) + { + +/* + * XXX To be fixed + * should call PR_Send + */ + + rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout); + if (rv > 0) + sent += rv; + if ( rv != iov[index].iov_len ) + { + if (sent <= 0) + return -1; + return -1; + } + } + return sent; +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ +PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError()); + return rv; +} + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int *)len); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, (int*)len); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv; + + rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, (int*)optlen); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv; + + rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); + if (rv==0) + return PR_SUCCESS; + else { + _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +void +_PR_MD_MAKE_NONBLOCK(PRFileDesc *f) +{ + return; // do nothing! +} + +/* +** Wait for I/O on a single descriptor. + * + * return 0, if timed-out, else return 1 +*/ +PRInt32 +_PR_WaitForFD(PRInt32 osfd, PRUintn how, PRIntervalTime timeout) +{ + _PRWin16PollDesc *pd; + PRPollQueue *pq; + PRIntn is; + PRInt32 rv = 1; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); + + pd = &me->md.thr_pd; + pq = &me->md.thr_pq; + if (timeout == PR_INTERVAL_NO_WAIT) return 0; + + pd->osfd = osfd; + pd->in_flags = how; + pd->out_flags = 0; + + pq->pds = pd; + pq->npds = 1; + + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + _PR_THREAD_LOCK(me); + + if (_PR_PENDING_INTERRUPT(me)) { + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + return 0; + } + + pq->thr = me; + pq->on_ioq = PR_TRUE; + pq->timeout = timeout; + _PR_ADD_TO_IOQ((*pq), me->cpu); + if (how == PR_POLL_READ) { + FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); + (_PR_FD_READ_CNT(me->cpu))[osfd]++; + } else if (how == PR_POLL_WRITE) { + FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); + (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; + } else { + FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; + } + if (_PR_IOQ_MAX_OSFD(me->cpu) < osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = osfd; + if (_PR_IOQ_TIMEOUT(me->cpu) > timeout) + _PR_IOQ_TIMEOUT(me->cpu) = timeout; + + _PR_THREAD_LOCK(me); + + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, timeout); + me->state = _PR_IO_WAIT; + me->io_pending = PR_TRUE; + me->io_suspended = PR_FALSE; + _PR_SLEEPQ_UNLOCK(me->cpu); + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + + _PR_MD_WAIT(me, timeout); + me->io_pending = PR_FALSE; + me->io_suspended = PR_FALSE; + + /* + ** If we timed out the pollq might still be on the ioq. Remove it + ** before continuing. + */ + if (pq->on_ioq) { + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + /* + * Need to check pq.on_ioq again + */ + if (pq->on_ioq) { + PR_REMOVE_LINK(&pq->links); + if (how == PR_POLL_READ) { + if ((--(_PR_FD_READ_CNT(me->cpu))[osfd]) == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + + } else if (how == PR_POLL_WRITE) { + if ((--(_PR_FD_WRITE_CNT(me->cpu))[osfd]) == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } else { + if ((--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]) == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + _PR_MD_IOQ_UNLOCK(); + rv = 0; + } + _PR_FAST_INTSON(is); + return(rv); +} + +/* + * Unblock threads waiting for I/O + * used when interrupting threads + * + * NOTE: The thread lock should held when this function is called. + * On return, the thread lock is released. + */ +void _PR_Unblock_IO_Wait(PRThread *thr) +{ + int pri = thr->priority; + _PRCPU *cpu = thr->cpu; + + PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ)); + _PR_SLEEPQ_LOCK(cpu); + _PR_DEL_SLEEPQ(thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD)); + thr->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thr); + _PR_MD_WAKEUP_WAITER(thr); +} + +/* +** Scan through io queue and find any bad fd's that triggered the error +** from _MD_SELECT +*/ +static void FindBadFDs(void) +{ + PRCList *q; + PRThread *me = _MD_CURRENT_THREAD(); + int sockOpt; + int sockOptLen = sizeof(sockOpt); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(me)); + q = (_PR_IOQ(me->cpu)).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRWin16PollDesc *pds = pq->pds; + _PRWin16PollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + pds->out_flags = 0; + PR_ASSERT(osfd >= 0 || pds->in_flags == 0); + if (pds->in_flags == 0) { + continue; /* skip this fd */ + } + if ( getsockopt(osfd, + (int)SOL_SOCKET, + SO_TYPE, + (char*)&sockOpt, + &sockOptLen) == SOCKET_ERROR ) + { + if ( WSAGetLastError() == WSAENOTSOCK ) + { + PR_LOG(_pr_io_lm, PR_LOG_MAX, + ("file descriptor %d is bad", osfd)); + pds->out_flags = PR_POLL_NVAL; + notify = PR_TRUE; + } + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + + if (notify) { + PRIntn pri; + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq + */ + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & PR_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & PR_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & PR_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + + _PR_THREAD_LOCK(pq->thr); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = pq->thr->cpu; + + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } + _PR_THREAD_UNLOCK(pq->thr); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + } +} /* end FindBadFDs() */ + +/* +** Called by the scheduler when there is nothing to do. This means that +** all threads are blocked on some monitor somewhere. +** +** Pause the current CPU. longjmp to the cpu's pause stack +*/ +PRInt32 _PR_MD_PAUSE_CPU( PRIntervalTime ticks) +{ + PRThread *me = _MD_CURRENT_THREAD(); + struct timeval timeout, *tvp; + fd_set r, w, e; + fd_set *rp, *wp, *ep; + PRInt32 max_osfd, nfd; + PRInt32 rv; + PRCList *q; + PRUint32 min_timeout; + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + /* + * assigment of fd_sets + */ + r = _PR_FD_READ_SET(me->cpu); + w = _PR_FD_WRITE_SET(me->cpu); + e = _PR_FD_EXCEPTION_SET(me->cpu); + + rp = &r; + wp = &w; + ep = &e; + + max_osfd = _PR_IOQ_MAX_OSFD(me->cpu) + 1; + min_timeout = _PR_IOQ_TIMEOUT(me->cpu); + /* + ** Compute the minimum timeout value: make it the smaller of the + ** timeouts specified by the i/o pollers or the timeout of the first + ** sleeping thread. + */ + q = _PR_SLEEPQ(me->cpu).next; + + if (q != &_PR_SLEEPQ(me->cpu)) { + PRThread *t = _PR_THREAD_PTR(q); + + if (t->sleep < min_timeout) { + min_timeout = t->sleep; + } + } + if (min_timeout > ticks) { + min_timeout = ticks; + } + + if (min_timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + timeout.tv_sec = PR_IntervalToSeconds(min_timeout); + timeout.tv_usec = PR_IntervalToMicroseconds(min_timeout) + % PR_USEC_PER_SEC; + tvp = &timeout; + } + + _PR_MD_IOQ_UNLOCK(); + _MD_CHECK_FOR_EXIT(); + /* + * check for i/o operations + */ + + nfd = _MD_SELECT(max_osfd, rp, wp, ep, tvp); + + _MD_CHECK_FOR_EXIT(); + _PR_MD_IOQ_LOCK(); + /* + ** Notify monitors that are associated with the selected descriptors. + */ + if (nfd > 0) { + q = _PR_IOQ(me->cpu).next; + _PR_IOQ_MAX_OSFD(me->cpu) = -1; + _PR_IOQ_TIMEOUT(me->cpu) = PR_INTERVAL_NO_TIMEOUT; + while (q != &_PR_IOQ(me->cpu)) { + PRPollQueue *pq = _PR_POLLQUEUE_PTR(q); + PRBool notify = PR_FALSE; + _PRWin16PollDesc *pds = pq->pds; + _PRWin16PollDesc *epds = pds + pq->npds; + PRInt32 pq_max_osfd = -1; + + q = q->next; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PRInt16 out_flags = 0; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if ((in_flags & PR_POLL_READ) && FD_ISSET(osfd, rp)) { + out_flags |= PR_POLL_READ; + } + if ((in_flags & PR_POLL_WRITE) && FD_ISSET(osfd, wp)) { + out_flags |= PR_POLL_WRITE; + } + if ((in_flags & PR_POLL_EXCEPT) && FD_ISSET(osfd, ep)) { + out_flags |= PR_POLL_EXCEPT; + } + pds->out_flags = out_flags; + if (out_flags) { + notify = PR_TRUE; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + if (notify == PR_TRUE) { + PRIntn pri; + PRThread *thred; + + PR_REMOVE_LINK(&pq->links); + pq->on_ioq = PR_FALSE; + + /* + * Decrement the count of descriptors for each desciptor/event + * because this I/O request is being removed from the + * ioq + */ + pds = pq->pds; + for (; pds < epds; pds++) { + PRInt32 osfd = pds->osfd; + PRInt16 in_flags = pds->in_flags; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & PR_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & PR_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & PR_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + thred = pq->thr; + _PR_THREAD_LOCK(thred); + if (pq->thr->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + _PRCPU *cpu = thred->cpu; + _PR_SLEEPQ_LOCK(pq->thr->cpu); + _PR_DEL_SLEEPQ(pq->thr, PR_TRUE); + _PR_SLEEPQ_UNLOCK(pq->thr->cpu); + + pri = pq->thr->priority; + pq->thr->state = _PR_RUNNABLE; + + pq->thr->cpu = cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(pq->thr, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (_pr_md_idle_cpus > 1) + _PR_MD_WAKEUP_WAITER(thred); + } + _PR_THREAD_UNLOCK(thred); + } else { + if (pq->timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = pq->timeout; + if (_PR_IOQ_MAX_OSFD(me->cpu) < pq_max_osfd) + _PR_IOQ_MAX_OSFD(me->cpu) = pq_max_osfd; + } + } + } else if (nfd < 0) { + if ( WSAGetLastError() == WSAENOTSOCK ) + { + FindBadFDs(); + } else { + PR_LOG(_pr_io_lm, PR_LOG_MAX, ("select() failed with errno %d", + errno)); + } + } + _PR_MD_IOQ_UNLOCK(); + return(0); + +} /* end _PR_MD_PAUSE_CPU() */ + + +/* +** _MD_pr_poll() -- Implement MD polling +** +** The function was snatched (re-used) from the unix implementation. +** +** The native thread stuff was deleted. +** The pollqueue is instantiated on the mdthread structure +** to keep the stack frame from being corrupted when this +** thread is waiting on the poll. +** +*/ +extern PRInt32 +_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, + PRIntervalTime timeout) +{ + PRPollDesc *pd, *epd; + PRInt32 n, err, pdcnt; + PRIntn is; + _PRWin16PollDesc *spds, *spd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRPollQueue *pq; + + pq = &me->md.thr_pq; + + /* + * XXX + * PRPollDesc has a PRFileDesc field, fd, while the IOQ + * is a list of PRPollQueue structures, each of which contains + * a _PRWin16PollDesc. A _PRWin16PollDesc struct contains + * the OS file descriptor, osfd, and not a PRFileDesc. + * So, we have allocate memory for _PRWin16PollDesc structures, + * copy the flags information from the pds list and have pq + * point to this list of _PRWin16PollDesc structures. + * + * It would be better if the memory allocation can be avoided. + */ + + spds = (_PRWin16PollDesc*) PR_MALLOC(npds * sizeof(_PRWin16PollDesc)); + if (!spds) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + spd = spds; + + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + _PR_THREAD_LOCK(me); + + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + PR_DELETE(spds); + return -1; + } + + pdcnt = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) { + PRInt32 osfd; + PRInt16 in_flags = pd->in_flags; + PRFileDesc *bottom = pd->fd; + + if ((NULL == bottom) || (in_flags == 0)) { + continue; + } + while (bottom->lower != NULL) { + bottom = bottom->lower; + } + osfd = bottom->secret->md.osfd; + + PR_ASSERT(osfd >= 0 || in_flags == 0); + + spd->osfd = osfd; + spd->in_flags = pd->in_flags; + spd++; + pdcnt++; + + if (in_flags & PR_POLL_READ) { + FD_SET(osfd, &_PR_FD_READ_SET(me->cpu)); + _PR_FD_READ_CNT(me->cpu)[osfd]++; + } + if (in_flags & PR_POLL_WRITE) { + FD_SET(osfd, &_PR_FD_WRITE_SET(me->cpu)); + (_PR_FD_WRITE_CNT(me->cpu))[osfd]++; + } + if (in_flags & PR_POLL_EXCEPT) { + FD_SET(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + (_PR_FD_EXCEPTION_CNT(me->cpu))[osfd]++; + } + if (osfd > _PR_IOQ_MAX_OSFD(me->cpu)) + _PR_IOQ_MAX_OSFD(me->cpu) = osfd; + } + if (timeout < _PR_IOQ_TIMEOUT(me->cpu)) + _PR_IOQ_TIMEOUT(me->cpu) = timeout; + + + pq->pds = spds; + pq->npds = pdcnt; + + pq->thr = me; + pq->on_ioq = PR_TRUE; + pq->timeout = timeout; + _PR_ADD_TO_IOQ((*pq), me->cpu); + _PR_SLEEPQ_LOCK(me->cpu); + _PR_ADD_SLEEPQ(me, timeout); + me->state = _PR_IO_WAIT; + me->io_pending = PR_TRUE; + me->io_suspended = PR_FALSE; + _PR_SLEEPQ_UNLOCK(me->cpu); + _PR_THREAD_UNLOCK(me); + _PR_MD_IOQ_UNLOCK(); + + _PR_MD_WAIT(me, timeout); + + me->io_pending = PR_FALSE; + me->io_suspended = PR_FALSE; + + /* + * Copy the out_flags from the _PRWin16PollDesc structures to the + * user's PRPollDesc structures and free the allocated memory + */ + spd = spds; + for (pd = pds, epd = pd + npds; pd < epd; pd++) { + if ((NULL == pd->fd) || (pd->in_flags == 0)) { + pd->out_flags = 0; + continue; + } + pd->out_flags = spd->out_flags; + spd++; + } + PR_DELETE(spds); + + /* + ** If we timed out the pollq might still be on the ioq. Remove it + ** before continuing. + */ + if (pq->on_ioq) { + _PR_INTSOFF(is); + _PR_MD_IOQ_LOCK(); + /* + * Need to check pq.on_ioq again + */ + if (pq->on_ioq == PR_TRUE) { + PR_REMOVE_LINK(&pq->links); + for (pd = pds, epd = pd + npds; pd < epd; pd++) { + PRInt32 osfd; + PRInt16 in_flags = pd->in_flags; + PRFileDesc *bottom = pd->fd; + + if ((NULL == bottom) || (in_flags == 0)) { + continue; + } + while (bottom->lower != NULL) { + bottom = bottom->lower; + } + osfd = bottom->secret->md.osfd; + PR_ASSERT(osfd >= 0 || in_flags == 0); + if (in_flags & PR_POLL_READ) { + if (--(_PR_FD_READ_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_READ_SET(me->cpu)); + } + if (in_flags & PR_POLL_WRITE) { + if (--(_PR_FD_WRITE_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_WRITE_SET(me->cpu)); + } + if (in_flags & PR_POLL_EXCEPT) { + if (--(_PR_FD_EXCEPTION_CNT(me->cpu))[osfd] == 0) + FD_CLR(osfd, &_PR_FD_EXCEPTION_SET(me->cpu)); + } + } + } + _PR_MD_IOQ_UNLOCK(); + _PR_INTSON(is); + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } else { + n = 0; + if (pq->on_ioq == PR_FALSE) { + /* Count the number of ready descriptors */ + while (--npds >= 0) { + if (pds->out_flags) { + n++; + } + pds++; + } + } + return n; + } +} /* end _MD_pr_poll() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16stdio.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16stdio.c new file mode 100644 index 00000000..52d34cfe --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16stdio.c @@ -0,0 +1,169 @@ +/* -*- 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 ***** */ + +/* +** w16stdio.c -- Callback functions for Win16 stdio read/write. +** +** +*/ +#include "primpl.h" + +/* +** _PL_MDStdioWrite() -- Win16 hackery to get console output +** +** Returns: number of bytes written. +** +*/ +PRInt32 +_PL_W16StdioWrite( void *buf, PRInt32 amount ) +{ + int rc; + + rc = fputs( buf, stdout ); + if ( rc == EOF ) + { + // something about errno + return(PR_FAILURE); + } + return( strlen(buf)); +} /* end _PL_fputs() */ + +/* +** _PL_W16StdioRead() -- Win16 hackery to get console input +** +*/ +PRInt32 +_PL_W16StdioRead( void *buf, PRInt32 amount ) +{ + char *bp; + + bp = fgets( buf, (int) amount, stdin ); + if ( bp == NULL ) + { + // something about errno + return(PR_FAILURE); + } + + return( strlen(buf)); +} /* end _PL_fgets() */ +/* --- end w16stdio.c --- */ + +/* +** Wrappers, linked into the client, that call +** functions in LibC +** +*/ + +/* +** _PL_W16CallBackPuts() -- Wrapper for puts() +** +*/ +int PR_CALLBACK _PL_W16CallBackPuts( const char *outputString ) +{ + return( puts( outputString )); +} /* end _PL_W16CallBackPuts() */ + +/* +** _PL_W16CallBackStrftime() -- Wrapper for strftime() +** +*/ +size_t PR_CALLBACK _PL_W16CallBackStrftime( + char *s, + size_t len, + const char *fmt, + const struct tm *p ) +{ + return( strftime( s, len, fmt, p )); +} /* end _PL_W16CallBackStrftime() */ + +/* +** _PL_W16CallBackMalloc() -- Wrapper for malloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackMalloc( size_t size ) +{ + return( malloc( size )); +} /* end _PL_W16CallBackMalloc() */ + +/* +** _PL_W16CallBackCalloc() -- Wrapper for calloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackCalloc( size_t n, size_t size ) +{ + return( calloc( n, size )); +} /* end _PL_W16CallBackCalloc() */ + +/* +** _PL_W16CallBackRealloc() -- Wrapper for realloc() +** +*/ +void * PR_CALLBACK _PL_W16CallBackRealloc( + void *old_blk, + size_t size ) +{ + return( realloc( old_blk, size )); +} /* end _PL_W16CallBackRealloc() */ + +/* +** _PL_W16CallBackFree() -- Wrapper for free() +** +*/ +void PR_CALLBACK _PL_W16CallBackFree( void *ptr ) +{ + free( ptr ); + return; +} /* end _PL_W16CallBackFree() */ + +/* +** _PL_W16CallBackGetenv() -- Wrapper for getenv() +** +*/ +void * PR_CALLBACK _PL_W16CallBackGetenv( const char *name ) +{ + return( getenv( name )); +} /* end _PL_W16CallBackGetenv */ + + +/* +** _PL_W16CallBackPutenv() -- Wrapper for putenv() +** +*/ +int PR_CALLBACK _PL_W16CallBackPutenv( const char *assoc ) +{ + return( putenv( assoc )); +} /* end _PL_W16CallBackGetenv */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16thred.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16thred.c new file mode 100644 index 00000000..85531318 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w16thred.c @@ -0,0 +1,426 @@ +/* -*- 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 +#include + +/* +** DispatchTrace -- define a thread dispatch trace entry +** +** The DispatchTrace oject(s) are instantiated in a single +** array. Think of the array as a push-down stack; entry +** zero is the most recent, entry one the next most recent, etc. +** For each time PR_MD_RESTORE_CONTEXT() is called, the array +** is Pushed down and entry zero is overwritten with data +** for the newly dispatched thread. +** +** Function TraceDispatch() manages the DispatchTrace array. +** +*/ +typedef struct DispatchTrace +{ + PRThread * thread; + PRUint32 state; + PRInt16 mdThreadNumber; + PRInt16 unused; + PRThreadPriority priority; + +} DispatchTrace, *DispatchTracePtr ; + +static void TraceDispatch( PRThread *thread ); + + +PRThread *_pr_primordialThread; + +/* +** Note: the static variables must be on the data-segment because +** the stack is destroyed during shadow-stack copy operations. +** +*/ +static char * pSource; /* ptr to sourc of a "shadow-stack" copy */ +static char * pTarget; /* ptr to target of a "shadow-stack" copy */ +static int cxByteCount; /* number of bytes for "shadow-stack" copy */ +static int bytesMoved; /* instrumentation: WRT "shadow-stack" copy */ +static FILE * file1 = 0; /* instrumentation: WRT debug */ + +#define NUM_DISPATCHTRACE_OBJECTS 24 +static DispatchTrace dt[NUM_DISPATCHTRACE_OBJECTS] = {0}; /* instrumentation: WRT dispatch */ +static PRUint32 dispatchCount = 0; /* instrumentation: number of thread dispatches */ + +static int OldPriorityOfPrimaryThread = -1; +static int TimeSlicesOnNonPrimaryThread = 0; +static PRUint32 threadNumber = 1; /* Instrumentation: monotonically increasing number */ + + + +/* +** _PR_MD_FINAL_INIT() -- Final MD Initialization +** +** Poultry Problems! ... The stack, as allocated by PR_NewStack() +** is called from here, late in initialization, because PR_NewStack() +** requires lots of things working. When some elements of the +** primordial thread are created, early in initialization, the +** shadow stack is not one of these things. The "shadow stack" is +** created here, late in initiailization using PR_NewStack(), to +** ensure consistency in creation of the related objects. +** +** A new ThreadStack, and all its affiliated structures, is allocated +** via the call to PR_NewStack(). The PRThread structure in the +** new stack is ignored; the old PRThread structure is used (why?). +** The old PRThreadStack structure is abandoned. +** +*/ +void +_PR_MD_FINAL_INIT() +{ + PRThreadStack * stack = 0; + PRInt32 stacksize = 0; + PRThread * me = _PR_MD_CURRENT_THREAD(); + + _PR_ADJUST_STACKSIZE( stacksize ); + stack = _PR_NewStack( stacksize ); + + me->stack = stack; + stack->thr = me; + + return; +} /* --- end _PR_MD_FINAL_INIT() --- */ + + +void +_MD_INIT_RUNNING_CPU( struct _PRCPU *cpu ) +{ + PR_INIT_CLIST(&(cpu->md.ioQ)); + cpu->md.ioq_max_osfd = -1; + cpu->md.ioq_timeout = PR_INTERVAL_NO_TIMEOUT; +} + + +void +_PR_MD_YIELD( void ) +{ + PR_ASSERT(0); +} + +/* +** _PR_MD_INIT_STACK() -- Win16 specific Stack initialization. +** +** +*/ + +void +_PR_MD_INIT_STACK( PRThreadStack *ts, PRIntn redzone ) +{ + ts->md.stackTop = ts->stackTop - sizeof(PRThread); + ts->md.cxByteCount = 0; + + return; +} /* --- end _PR_MD_INIT_STACK() --- */ + +/* +** _PR_MD_INIT_THREAD() -- Win16 specific Thread initialization. +** +*/ +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + if ( thread->flags & _PR_PRIMORDIAL) + { + _pr_primordialThread = thread; + thread->md.threadNumber = 1; + } + else + { + thread->md.threadNumber = ++threadNumber; + } + + thread->md.magic = _MD_MAGIC_THREAD; + strcpy( thread->md.guardBand, "GuardBand" ); + + return PR_SUCCESS; +} + + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + _MD_SWITCH_CONTEXT( thread ); + + return( PR_SUCCESS ); +} + +void *PR_W16GetExceptionContext(void) +{ + return _MD_CURRENT_THREAD()->md.exceptionContext; +} + +void +PR_W16SetExceptionContext(void *context) +{ + _MD_CURRENT_THREAD()->md.exceptionContext = context; +} + + + + +/* +** _MD_RESTORE_CONTEXT() -- Resume execution of thread 't'. +** +** Win16 threading is based on the NSPR 2.0 general model of +** user threads. It differs from the general model in that a +** single "real" stack segment is used for execution of all +** threads. The context of the suspended threads is preserved +** in the md.context [and related members] of the PRThread +** structure. The stack context of the suspended thread is +** preserved in a "shadow stack" object. +** +** _MD_RESTORE_CONTEXT() implements most of the thread switching +** for NSPR's implementation of Win16 theads. +** +** Operations Notes: +** +** Function PR_NewStack() in prustack.c allocates a new +** PRThreadStack, PRStack, PRSegment, and a "shadow" stack +** for a thread. These structures are wired together to +** form the basis of Win16 threads. The thread and shadow +** stack structures are created as part of PR_CreateThread(). +** +** Note! Some special "magic" is applied to the "primordial" +** thread. The physical layout of the PRThread, PRThreadStack, +** shadow stack, ... is somewhat different. Watch yourself when +** mucking around with it. ... See _PR_MD_FINAL_INIT() for most +** of the special treatment of the primordial thread. +** +** Function _PR_MD_INIT_STACK() initializes the value of +** PRThreadStack member md.cxByteCount to zero; there +** is no context to be restored for a thread's initial +** dispatch. The value of member md.stackTop is set to +** point to the highest usable address on the shadow stack. +** This point corresponds to _pr_top_of_task_stack on the +** system's operating stack. +** +** _pr_top_of_task_stack points to a place on the system stack +** considered to be "close to the top". Stack context is preserved +** relative to this point. +** +** Reminder: In x86 architecture, the stack grows "down". +** That is: the stack pointer (SP register) is decremented +** to push objects onto the stack or when a call is made. +** +** Function _PR_MD_WAIT() invokes macro _MD_SWITCH_CONTEXT(); +** this causes the hardware registers to be preserved in a +** CATCHBUF structure using function Catch() [see _win16.h], +** then calls PR_Schedule() to select a new thread for dispatch. +** PR_Schedule() calls _MD_RESTORE_CONTEXT() to cause the thread +** being suspended's stack to be preserved, to restore the +** stack of the to-be-dispactched thread, and to restore the +** to-be-dispactched thread's hardware registers. +** +** At the moment _PR_MD_RESTORE_CONTEXT() is called, the stack +** pointer (SP) is less than the reference pointer +** _pr_top_of_task_stack. The distance difference between the SP and +** _pr_top_of_task_stack is the amount of stack that must be preserved. +** This value, cxByteCount, is calculated then preserved in the +** PRThreadStack.md.cxByteCount for later use (size of stack +** context to restore) when this thread is dispatched again. +** +** A C language for() loop is used to copy, byte-by-byte, the +** stack data being preserved starting at the "address of t" +** [Note: 't' is the argument passed to _PR_MD_RESTORE_CONTEXT()] +** for the length of cxByteCount. +** +** variables pSource and pTarget are the calculated source and +** destination pointers for the stack copy operation. These +** variables are static scope because they cannot be instantiated +** on the stack itself, since the stack is clobbered by restoring +** the to-be-dispatched thread's stack context. +** +** After preserving the suspended thread's stack and architectural +** context, the to-be-dispatched thread's stack context is copied +** from its shadow stack to the system operational stack. The copy +** is done in a small fragment of in-line assembly language. Note: +** In NSPR 1.0, a while() loop was used to do the copy; when compiled +** with the MS C 1.52c compiler, the short while loop used no +** stack variables. The Watcom compiler, specified for use on NSPR 2.0, +** uses stack variables to implement the same while loop. This is +** a no-no! The copy operation clobbers these variables making the +** results of the copy ... unpredictable ... So, a short piece of +** inline assembly language is used to effect the copy. +** +** Following the restoration of the to-be-dispatched thread's +** stack context, another short inline piece of assemble language +** is used to set the SP register to correspond to what it was +** when the to-be-dispatched thread was suspended. This value +** uses the thread's stack->md.cxByteCount as a negative offset +** from _pr_top_of_task_stack as the new value of SP. +** +** Finally, Function Throw() is called to restore the architectural +** context of the to-be-dispatched thread. +** +** At this point, the newly dispatched thread appears to resume +** execution following the _PR_MD_SWITCH_CONTEXT() macro. +** +** OK, this ain't rocket-science, but it can confuse you easily. +** If you have to work on this stuff, please take the time to +** draw, on paper, the structures (PRThread, PRThreadStack, +** PRSegment, the "shadow stack", the system stack and the related +** global variables). Hand step it thru the debugger to make sure +** you understand it very well before making any changes. ... +** YMMV. +** +*/ +void _MD_RESTORE_CONTEXT(PRThread *t) +{ + dispatchCount++; + TraceDispatch( t ); + /* + ** This is a good opportunity to make sure that the main + ** mozilla thread actually gets some time. If interrupts + ** are on, then we know it is safe to check if the main + ** thread is being starved. If moz has not been scheduled + ** for a long time, then then temporarily bump the fe priority + ** up so that it gets to run at least one. + */ +// #if 0 // lth. condition off for debug. + if (_pr_primordialThread == t) { + if (OldPriorityOfPrimaryThread != -1) { + PR_SetThreadPriority(_pr_primordialThread, OldPriorityOfPrimaryThread); + OldPriorityOfPrimaryThread = -1; + } + TimeSlicesOnNonPrimaryThread = 0; + } else { + TimeSlicesOnNonPrimaryThread++; + } + + if ((TimeSlicesOnNonPrimaryThread >= 20) && (OldPriorityOfPrimaryThread == -1)) { + OldPriorityOfPrimaryThread = PR_GetThreadPriority(_pr_primordialThread); + PR_SetThreadPriority(_pr_primordialThread, 31); + TimeSlicesOnNonPrimaryThread = 0; + } +// #endif + /* + ** Save the Task Stack into the "shadow stack" of the current thread + */ + cxByteCount = (int) ((PRUint32) _pr_top_of_task_stack - (PRUint32) &t ); + pSource = (char *) &t; + pTarget = (char *)((PRUint32)_pr_currentThread->stack->md.stackTop + - (PRUint32)cxByteCount ); + _pr_currentThread->stack->md.cxByteCount = cxByteCount; + + for( bytesMoved = 0; bytesMoved < cxByteCount; bytesMoved++ ) + *(pTarget + bytesMoved ) = *(pSource + bytesMoved ); + + /* Mark the new thread as the current thread */ + _pr_currentThread = t; + + /* + ** Now copy the "shadow stack" of the new thread into the Task Stack + ** + ** REMEMBER: + ** After the stack has been copied, ALL local variables in this function + ** are invalid !! + */ + cxByteCount = t->stack->md.cxByteCount; + pSource = t->stack->md.stackTop - cxByteCount; + pTarget = _pr_top_of_task_stack - cxByteCount; + + errno = (_pr_currentThread)->md.errcode; + + __asm + { + mov cx, cxByteCount + mov si, WORD PTR [pSource] + mov di, WORD PTR [pTarget] + mov ax, WORD PTR [pTarget + 2] + mov es, ax + mov ax, WORD PTR [pSource + 2] + mov bx, ds + mov ds, ax + rep movsb + mov ds, bx + } + + /* + ** IMPORTANT: + ** ---------- + ** SS:SP is now invalid :-( This means that all local variables and + ** function arguments are invalid and NO function calls can be + ** made !!! We must fix up SS:SP so that function calls can safely + ** be made... + */ + + __asm { + mov ax, WORD PTR [_pr_top_of_task_stack] + sub ax, cxByteCount + mov sp, ax + }; + + /* + ** Resume execution of thread: t by restoring the thread's context. + ** + */ + Throw((_pr_currentThread)->md.context, 1); +} /* --- end MD_RESTORE_CONTEXT() --- */ + + +static void TraceDispatch( PRThread *thread ) +{ + int i; + + /* + ** push all DispatchTrace objects to down one slot. + ** Note: the last entry is lost; last-1 becomes last, etc. + */ + for( i = NUM_DISPATCHTRACE_OBJECTS -2; i >= 0; i-- ) + { + dt[i +1] = dt[i]; + } + + /* + ** Build dt[0] from t + */ + dt->thread = thread; + dt->state = thread->state; + dt->mdThreadNumber = thread->md.threadNumber; + dt->priority = thread->priority; + + return; +} /* --- end TraceDispatch() --- */ + + +/* $$ end W16thred.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32ipcsem.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32ipcsem.c new file mode 100644 index 00000000..82201a80 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32ipcsem.c @@ -0,0 +1,227 @@ +/* -*- 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 ***** */ + +/* + * File: w32ipcsem.c + * Description: implements named semaphores for NT and WIN95. + */ + +#include "primpl.h" + +/* + * NSPR-to-NT access right mapping table for semaphore objects. + * + * The SYNCHRONIZE access is required by WaitForSingleObject. + * The SEMAPHORE_MODIFY_STATE access is required by ReleaseSemaphore. + * The OR of these three access masks must equal SEMAPHORE_ALL_ACCESS. + * This is because if a semaphore object with the specified name + * exists, CreateSemaphore requests SEMAPHORE_ALL_ACCESS access to + * the existing object. + */ +static DWORD semAccessTable[] = { + STANDARD_RIGHTS_REQUIRED|0x1, /* read (0x1 is "query state") */ + STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, /* write */ + 0 /* execute */ +}; + +#ifndef _PR_GLOBAL_THREADS_ONLY + +/* + * A fiber cannot call WaitForSingleObject because that + * will block the other fibers running on the same thread. + * If a fiber needs to wait on a (semaphore) handle, we + * create a native thread to call WaitForSingleObject and + * have the fiber join the native thread. + */ + +/* + * Arguments, return value, and error code for WaitForSingleObject + */ +struct WaitSingleArg { + HANDLE handle; + DWORD timeout; + DWORD rv; + DWORD error; +}; + +static void WaitSingleThread(void *arg) +{ + struct WaitSingleArg *warg = (struct WaitSingleArg *) arg; + + warg->rv = WaitForSingleObject(warg->handle, warg->timeout); + if (warg->rv == WAIT_FAILED) { + warg->error = GetLastError(); + } +} + +static DWORD FiberSafeWaitForSingleObject( + HANDLE hHandle, + DWORD dwMilliseconds +) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_PR_IS_NATIVE_THREAD(me)) { + return WaitForSingleObject(hHandle, dwMilliseconds); + } else { + PRThread *waitThread; + struct WaitSingleArg warg; + PRStatus rv; + + warg.handle = hHandle; + warg.timeout = dwMilliseconds; + waitThread = PR_CreateThread( + PR_USER_THREAD, WaitSingleThread, &warg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (waitThread == NULL) { + return WAIT_FAILED; + } + + rv = PR_JoinThread(waitThread); + PR_ASSERT(rv == PR_SUCCESS); + if (rv == PR_FAILURE) { + return WAIT_FAILED; + } + if (warg.rv == WAIT_FAILED) { + SetLastError(warg.error); + } + return warg.rv; + } +} + +#endif /* !_PR_GLOBAL_THREADS_ONLY */ + +PRSem *_PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value) +{ + PRSem *sem; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + sem = PR_NEW(PRSem); + if (sem == NULL) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + if (flags & PR_SEM_CREATE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, semAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + sem->sem = CreateSemaphore(lpSA, value, 0x7fffffff, osname); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (sem->sem == NULL) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + PR_DELETE(sem); + return NULL; + } + if ((flags & PR_SEM_EXCL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { + PR_SetError(PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS); + CloseHandle(sem->sem); + PR_DELETE(sem); + return NULL; + } + } else { + sem->sem = OpenSemaphore( + SEMAPHORE_MODIFY_STATE|SYNCHRONIZE, FALSE, osname); + if (sem->sem == NULL) { + DWORD err = GetLastError(); + + /* + * If we open a nonexistent named semaphore, NT + * returns ERROR_FILE_NOT_FOUND, while Win95 + * returns ERROR_INVALID_NAME + */ + if (err == ERROR_INVALID_NAME) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, err); + } else { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + } + PR_DELETE(sem); + return NULL; + } + } + return sem; +} + +PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) +{ + DWORD rv; + +#ifdef _PR_GLOBAL_THREADS_ONLY + rv = WaitForSingleObject(sem->sem, INFINITE); +#else + rv = FiberSafeWaitForSingleObject(sem->sem, INFINITE); +#endif + PR_ASSERT(rv == WAIT_FAILED || rv == WAIT_OBJECT_0); + if (rv == WAIT_FAILED) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + if (rv != WAIT_OBJECT_0) { + /* Should not happen */ + PR_SetError(PR_UNKNOWN_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) +{ + if (ReleaseSemaphore(sem->sem, 1, NULL) == FALSE) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) +{ + if (CloseHandle(sem->sem) == FALSE) { + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + return PR_FAILURE; + } + PR_DELETE(sem); + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32poll.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32poll.c new file mode 100644 index 00000000..0bf5203a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32poll.c @@ -0,0 +1,351 @@ +/* -*- 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 file implements _PR_MD_PR_POLL for Win32. + */ + +/* The default value of FD_SETSIZE is 64. */ +#define FD_SETSIZE 1024 + +#include "primpl.h" + +#if !defined(_PR_GLOBAL_THREADS_ONLY) + +struct select_data_s { + PRInt32 status; + PRInt32 error; + fd_set *rd, *wt, *ex; + const struct timeval *tv; +}; + +static void +_PR_MD_select_thread(void *cdata) +{ + struct select_data_s *cd = (struct select_data_s *)cdata; + + cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv); + + if (cd->status == SOCKET_ERROR) { + cd->error = WSAGetLastError(); + } +} + +int _PR_NTFiberSafeSelect( + int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + const struct timeval *timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + int ready; + + if (_PR_IS_NATIVE_THREAD(me)) { + ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout); + } + else + { + /* + ** Creating a new thread on each call!! + ** I guess web server doesn't use non-block I/O. + */ + PRThread *selectThread; + struct select_data_s data; + data.status = 0; + data.error = 0; + data.rd = readfds; + data.wt = writefds; + data.ex = exceptfds; + data.tv = timeout; + + selectThread = PR_CreateThread( + PR_USER_THREAD, _PR_MD_select_thread, &data, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (selectThread == NULL) return -1; + + PR_JoinThread(selectThread); + ready = data.status; + if (ready == SOCKET_ERROR) WSASetLastError(data.error); + } + return ready; +} + +#endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */ + +PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + int ready, err; + fd_set rd, wt, ex; + fd_set *rdp, *wtp, *exp; + int nrd, nwt, nex; + PRFileDesc *bottom; + PRPollDesc *pd, *epd; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + struct timeval tv, *tvp = NULL; + + if (_PR_PENDING_INTERRUPT(me)) + { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + return -1; + } + + /* + ** Is it an empty set? If so, just sleep for the timeout and return + */ + if (0 == npds) + { + PR_Sleep(timeout); + return 0; + } + + nrd = nwt = nex = 0; + FD_ZERO(&rd); + FD_ZERO(&wt); + FD_ZERO(&ex); + + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + SOCKET osfd; + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + if (pd->in_flags & PR_POLL_READ) + { + in_flags_read = (pd->fd->methods->poll)( + pd->fd, (PRInt16)(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, (PRInt16)(pd->in_flags & ~PR_POLL_READ), + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one's ready right now (buffered input) */ + if (0 == ready) + { + /* + * We will have to return without calling the + * system poll/select function. So zero the + * out_flags fields of all the poll descriptors + * before this one. + */ + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; + pd->out_flags = out_flags_read | out_flags_write; + } + else + { + pd->out_flags = 0; /* pre-condition */ + /* make sure this is an NSPR supported stack */ + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + osfd = (SOCKET) bottom->secret->md.osfd; + if (in_flags_read & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_READ_SYS_READ; + FD_SET(osfd, &rd); + nrd++; + } + if (in_flags_read & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_READ_SYS_WRITE; + FD_SET(osfd, &wt); + nwt++; + } + if (in_flags_write & PR_POLL_READ) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_READ; + FD_SET(osfd, &rd); + nrd++; + } + if (in_flags_write & PR_POLL_WRITE) + { + pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; + FD_SET(osfd, &wt); + nwt++; + } + if (pd->in_flags & PR_POLL_EXCEPT) { + FD_SET(osfd, &ex); + nex++; + } + } + } + else + { + if (0 == ready) + { + PRPollDesc *prev; + for (prev = pds; prev < pd; prev++) + { + prev->out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pd->out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + pd->out_flags = 0; + } + } + + if (0 != ready) return ready; /* no need to block */ + + if ((nrd > FD_SETSIZE) || (nwt > FD_SETSIZE) || (nex > FD_SETSIZE)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rdp = (0 == nrd) ? NULL : &rd; + wtp = (0 == nwt) ? NULL : &wt; + exp = (0 == nex) ? NULL : &ex; + + if ((NULL == rdp) && (NULL == wtp) && (NULL == exp)) { + PR_Sleep(timeout); + return 0; + } + + if (timeout != PR_INTERVAL_NO_TIMEOUT) + { + PRInt32 ticksPerSecond = PR_TicksPerSecond(); + tv.tv_sec = timeout / ticksPerSecond; + tv.tv_usec = PR_IntervalToMicroseconds( timeout % ticksPerSecond ); + tvp = &tv; + } + +#if defined(_PR_GLOBAL_THREADS_ONLY) + ready = _MD_SELECT(0, rdp, wtp, exp, tvp); +#else + ready = _PR_NTFiberSafeSelect(0, rdp, wtp, exp, tvp); +#endif + + /* + ** Now to unravel the select sets back into the client's poll + ** descriptor list. Is this possibly an area for pissing away + ** a few cycles or what? + */ + if (ready > 0) + { + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + PRInt16 out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + SOCKET osfd; + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); + + osfd = (SOCKET) bottom->secret->md.osfd; + + if (FD_ISSET(osfd, &rd)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_READ) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &wt)) + { + if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) + out_flags |= PR_POLL_READ; + if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) + out_flags |= PR_POLL_WRITE; + } + if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; + } + pd->out_flags = out_flags; + if (out_flags) ready++; + } + PR_ASSERT(ready > 0); + } + else if (ready == SOCKET_ERROR) + { + err = WSAGetLastError(); + if (err == WSAENOTSOCK) + { + /* Find the bad fds */ + int optval; + int optlen = sizeof(optval); + ready = 0; + for (pd = pds, epd = pd + npds; pd < epd; pd++) + { + pd->out_flags = 0; + if ((NULL != pd->fd) && (0 != pd->in_flags)) + { + bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, + SO_TYPE, (char *) &optval, &optlen) == -1) + { + PR_ASSERT(WSAGetLastError() == WSAENOTSOCK); + if (WSAGetLastError() == WSAENOTSOCK) + { + pd->out_flags = PR_POLL_NVAL; + ready++; + } + } + } + } + PR_ASSERT(ready > 0); + } + else _PR_MD_MAP_SELECT_ERROR(err); + } + + return ready; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32rng.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32rng.c new file mode 100644 index 00000000..2ad6ed86 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32rng.c @@ -0,0 +1,107 @@ +/* -*- 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 ***** */ + +#include +#include +#include +#include +#include +#include +#include + +static BOOL +CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow) +{ + LARGE_INTEGER liCount; + + if (!QueryPerformanceCounter(&liCount)) + return FALSE; + + *lpdwHigh = liCount.u.HighPart; + *lpdwLow = liCount.u.LowPart; + return TRUE; +} + +extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size ) +{ + DWORD dwHigh, dwLow, dwVal; + int n = 0; + int nBytes; + time_t sTime; + + if (size <= 0) + return 0; + + CurrentClockTickTime(&dwHigh, &dwLow); + + // get the maximally changing bits first + nBytes = sizeof(dwLow) > size ? size : sizeof(dwLow); + memcpy((char *)buf, &dwLow, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + nBytes = sizeof(dwHigh) > size ? size : sizeof(dwHigh); + memcpy(((char *)buf) + n, &dwHigh, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + // get the number of milliseconds that have elapsed since Windows started + dwVal = GetTickCount(); + + nBytes = sizeof(dwVal) > size ? size : sizeof(dwVal); + memcpy(((char *)buf) + n, &dwVal, nBytes); + n += nBytes; + size -= nBytes; + + if (size <= 0) + return n; + + // get the time in seconds since midnight Jan 1, 1970 + time(&sTime); + nBytes = sizeof(sTime) > size ? size : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32shm.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32shm.c new file mode 100644 index 00000000..705f62f1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w32shm.c @@ -0,0 +1,356 @@ +/* -*- 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 +#include +#include +#include +#include + +#if defined(PR_HAVE_WIN32_NAMED_SHARED_MEMORY) + +extern PRLogModuleInfo *_pr_shm_lm; + +/* + * NSPR-to-NT access right mapping table for file-mapping objects. + * + * The OR of these three access masks must equal FILE_MAP_ALL_ACCESS. + * This is because if a file-mapping object with the specified name + * exists, CreateFileMapping requests full access to the existing + * object. + */ +static DWORD filemapAccessTable[] = { + FILE_MAP_ALL_ACCESS & ~FILE_MAP_WRITE, /* read */ + FILE_MAP_ALL_ACCESS & ~FILE_MAP_READ, /* write */ + 0 /* execute */ +}; + +extern PRSharedMemory * _MD_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + char ipcname[PR_IPC_NAME_SIZE]; + PRStatus rc = PR_SUCCESS; + DWORD dwHi, dwLo; + PRSharedMemory *shm; + DWORD flProtect = ( PAGE_READWRITE ); + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + rc = _PR_MakeNativeIPCName( name, ipcname, PR_IPC_NAME_SIZE, _PRIPCShm ); + if ( PR_FAILURE == rc ) + { + PR_SetError(PR_UNKNOWN_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: name is invalid")); + return(NULL); + } + + shm = PR_NEWZAP( PRSharedMemory ); + if ( NULL == shm ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New PRSharedMemory out of memory")); + return(NULL); + } + + shm->ipcname = PR_MALLOC( strlen( ipcname ) + 1 ); + if ( NULL == shm->ipcname ) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0 ); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, ( "PR_OpenSharedMemory: New shm->ipcname out of memory")); + PR_DELETE(shm); + return(NULL); + } + + /* copy args to struct */ + strcpy( shm->ipcname, ipcname ); + shm->size = size; + shm->mode = mode; + shm->flags = flags; + shm->ident = _PR_SHM_IDENT; + + if (flags & PR_SHM_CREATE ) { + /* XXX: Not 64bit safe. Fix when WinNT goes 64bit. */ + dwHi = 0; + dwLo = shm->size; + + if (_PR_NT_MakeSecurityDescriptorACL(mode, filemapAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + shm->handle = CreateFileMapping( + (HANDLE)-1 , + lpSA, + flProtect, + dwHi, + dwLo, + shm->ipcname); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + + if ( NULL == shm->handle ) { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: CreateFileMapping() failed: %s", + shm->ipcname )); + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_FREEIF( shm->ipcname ) + PR_DELETE( shm ); + return(NULL); + } else { + if (( flags & PR_SHM_EXCL) && ( GetLastError() == ERROR_ALREADY_EXISTS )) { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: Request exclusive & already exists", + shm->ipcname )); + PR_SetError( PR_FILE_EXISTS_ERROR, ERROR_ALREADY_EXISTS ); + CloseHandle( shm->handle ); + PR_FREEIF( shm->ipcname ) + PR_DELETE( shm ); + return(NULL); + } else { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: CreateFileMapping() success: %s, handle: %d", + shm->ipcname, shm->handle )); + return(shm); + } + } + } else { + shm->handle = OpenFileMapping( FILE_MAP_WRITE, TRUE, shm->ipcname ); + if ( NULL == shm->handle ) { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: OpenFileMapping() failed: %s, error: %d", + shm->ipcname, PR_GetOSError())); + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + return(NULL); + } else { + PR_LOG(_pr_shm_lm, PR_LOG_DEBUG, + ( "PR_OpenSharedMemory: OpenFileMapping() success: %s, handle: %d", + shm->ipcname, shm->handle )); + return(shm); + } + } + /* returns from separate paths */ +} + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + PRUint32 access = FILE_MAP_WRITE; + void *addr; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + if ( PR_SHM_READONLY & flags ) + access = FILE_MAP_READ; + + addr = MapViewOfFile( shm->handle, + access, + 0, 0, + shm->size ); + + if ( NULL == addr ) { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_AttachSharedMemory: MapViewOfFile() failed. OSerror: %d", PR_GetOSError())); + } + + return( addr ); +} /* end _MD_ATTACH_SHARED_MEMORY() */ + + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PRStatus rc = PR_SUCCESS; + BOOL wrc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + wrc = UnmapViewOfFile( addr ); + if ( FALSE == wrc ) + { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_DetachSharedMemory: UnmapViewOfFile() failed. OSerror: %d", PR_GetOSError())); + rc = PR_FAILURE; + } + + return( rc ); +} + + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PRStatus rc = PR_SUCCESS; + BOOL wrc; + + PR_ASSERT( shm->ident == _PR_SHM_IDENT ); + + wrc = CloseHandle( shm->handle ); + if ( FALSE == wrc ) + { + _PR_MD_MAP_DEFAULT_ERROR( GetLastError()); + PR_LOG( _pr_shm_lm, PR_LOG_ERROR, + ("_MD_CloseSharedMemory: CloseHandle() failed. OSerror: %d", PR_GetOSError())); + rc = PR_FAILURE; + } + PR_FREEIF( shm->ipcname ); + PR_DELETE( shm ); + + return( rc ); +} /* end _MD_CLOSE_SHARED_MEMORY() */ + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + return( PR_SUCCESS ); +} + + +/* +** Windows implementation of anonymous memory (file) map +*/ +extern PRLogModuleInfo *_pr_shma_lm; + +extern PRFileMap* _md_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + PRFileMap *fm; + HANDLE hFileMap; + + fm = PR_CreateFileMap( (PRFileDesc*)-1, size, prot ); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): PR_CreateFileMap(): failed")); + goto Finished; + } + + /* + ** Make fm->md.hFileMap inheritable. We can't use + ** GetHandleInformation and SetHandleInformation + ** because these two functions fail with + ** ERROR_CALL_NOT_IMPLEMENTED on Win95. + */ + if (DuplicateHandle(GetCurrentProcess(), fm->md.hFileMap, + GetCurrentProcess(), &hFileMap, + 0, TRUE /* inheritable */, + DUPLICATE_SAME_ACCESS) == FALSE) { + PR_SetError( PR_UNKNOWN_ERROR, GetLastError() ); + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_OpenAnonFileMap(): DuplicateHandle(): failed")); + PR_CloseFileMap( fm ); + fm = NULL; + goto Finished; + } + CloseHandle(fm->md.hFileMap); + fm->md.hFileMap = hFileMap; + +Finished: + return(fm); +} /* end md_OpenAnonFileMap() */ + +/* +** _md_ExportFileMapAsString() +** +*/ +extern PRStatus _md_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + PRIntn written; + + written = PR_snprintf( buf, bufSize, "%d:%ld:%ld", + (PRIntn)fm->prot, (PRInt32)fm->md.hFileMap, (PRInt32)fm->md.dwAccess ); + /* Watch out on the above snprintf(). Windows HANDLE assumes 32bits; windows calls it void* */ + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ExportFileMapAsString(): prot: %x, hFileMap: %x, dwAccess: %x", + fm->prot, fm->md.hFileMap, fm->md.dwAccess )); + + return((written == -1)? PR_FAILURE : PR_SUCCESS); +} /* end _md_ExportFileMapAsString() */ + + +/* +** _md_ImportFileMapFromString() +** +*/ +extern PRFileMap * _md_ImportFileMapFromString( + const char *fmstring +) +{ + PRIntn prot; + PRInt32 hFileMap; + PRInt32 dwAccess; + PRFileMap *fm = NULL; + + PR_sscanf( fmstring, "%d:%ld:%ld", &prot, &hFileMap, &dwAccess ); + + fm = PR_NEWZAP(PRFileMap); + if ( NULL == fm ) { + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): PR_NEWZAP(): Failed")); + return(fm); + } + + fm->prot = (PRFileMapProtect)prot; + fm->md.hFileMap = (HANDLE)hFileMap; /* Assumes HANDLE is 32bit */ + fm->md.dwAccess = (DWORD)dwAccess; + fm->fd = (PRFileDesc*)-1; + + PR_LOG( _pr_shma_lm, PR_LOG_DEBUG, + ("_md_ImportFileMapFromString(): fm: %p, prot: %d, hFileMap: %8.8x, dwAccess: %8.8x, fd: %x", + fm, prot, fm->md.hFileMap, fm->md.dwAccess, fm->fd)); + return(fm); +} /* end _md_ImportFileMapFromString() */ + +#else +Error! Why is PR_HAVE_WIN32_NAMED_SHARED_MEMORY not defined? +#endif /* PR_HAVE_WIN32_NAMED_SHARED_MEMORY */ +/* --- end w32shm.c --- */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95cv.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95cv.c new file mode 100644 index 00000000..975ac4b0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95cv.c @@ -0,0 +1,347 @@ +/* -*- 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 ***** */ + +/* + * w95cv.c -- Windows 95 Machine-Dependent Code for Condition Variables + * + * We implement our own condition variable wait queue. Each thread + * has a semaphore object (thread->md.blocked_sema) to block on while + * waiting on a condition variable. + * + * We use a deferred condition notify algorithm. When PR_NotifyCondVar + * or PR_NotifyAllCondVar is called, the condition notifies are simply + * recorded in the _MDLock structure. We defer the condition notifies + * until right after we unlock the lock. This way the awakened threads + * have a better chance to reaquire the lock. + */ + +#include "primpl.h" + +/* + * AddThreadToCVWaitQueueInternal -- + * + * Add the thread to the end of the condition variable's wait queue. + * The CV's lock must be locked when this function is called. + */ + +static void +AddThreadToCVWaitQueueInternal(PRThread *thred, struct _MDCVar *cv) +{ + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait += 1; + thred->md.inCVWaitQueue = PR_TRUE; + thred->md.next = NULL; + thred->md.prev = cv->waitTail; + if (cv->waitHead == NULL) { + cv->waitHead = thred; + } else { + cv->waitTail->md.next = thred; + } + cv->waitTail = thred; +} + +/* + * md_UnlockAndPostNotifies -- + * + * Unlock the lock, and then do the deferred condition notifies. + * If waitThred and waitCV are not NULL, waitThred is added to + * the wait queue of waitCV before the lock is unlocked. + * + * This function is called by _PR_MD_WAIT_CV and _PR_MD_UNLOCK, + * the two places where a lock is unlocked. + */ +static void +md_UnlockAndPostNotifies( + _MDLock *lock, + PRThread *waitThred, + _MDCVar *waitCV) +{ + PRIntn index; + _MDNotified post; + _MDNotified *notified, *prev = NULL; + + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + ZeroMemory(&lock->notified, sizeof(_MDNotified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* + * Figure out how many threads we need to wake up. + */ + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + _MDCVar *cv = notified->cv[index].cv; + PRThread *thred; + int i; + + /* Fast special case: no waiting threads */ + if (cv->waitHead == NULL) { + notified->cv[index].notifyHead = NULL; + continue; + } + + /* General case */ + if (-1 == notified->cv[index].times) { + /* broadcast */ + thred = cv->waitHead; + while (thred != NULL) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = cv->waitTail = NULL; + cv->nwait = 0; + } else { + thred = cv->waitHead; + i = notified->cv[index].times; + while (thred != NULL && i > 0) { + thred->md.inCVWaitQueue = PR_FALSE; + thred = thred->md.next; + i--; + } + notified->cv[index].notifyHead = cv->waitHead; + cv->waitHead = thred; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + if (cv->waitHead->md.prev != NULL) { + cv->waitHead->md.prev->md.next = NULL; + cv->waitHead->md.prev = NULL; + } + } + cv->nwait -= notified->cv[index].times - i; + } + } + notified = notified->link; + } while (NULL != notified); + + if (waitThred) { + AddThreadToCVWaitQueueInternal(waitThred, waitCV); + } + + /* Release the lock before notifying */ + LeaveCriticalSection(&lock->mutex); + + notified = &post; /* this is where we start */ + do { + for (index = 0; index < notified->length; ++index) { + PRThread *thred; + PRThread *next; + + thred = notified->cv[index].notifyHead; + while (thred != NULL) { + BOOL rv; + + next = thred->md.next; + thred->md.prev = thred->md.next = NULL; + + rv = ReleaseSemaphore(thred->md.blocked_sema, 1, NULL); + PR_ASSERT(rv != 0); + thred = next; + } + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void md_PostNotifyToCvar(_MDCVar *cvar, _MDLock *lock, + PRBool broadcast) +{ + PRIntn index = 0; + _MDNotified *notified = &lock->notified; + + while (1) { + for (index = 0; index < notified->length; ++index) { + if (notified->cv[index].cv == cvar) { + if (broadcast) { + notified->cv[index].times = -1; + } else if (-1 != notified->cv[index].times) { + notified->cv[index].times += 1; + } + return; + } + } + /* if not full, enter new CV in this array */ + if (notified->length < _MD_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) { + notified->link = PR_NEWZAP(_MDNotified); + } + + notified = notified->link; + } + + /* A brand new entry in the array */ + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; +} + +/* + * _PR_MD_NEW_CV() -- Creating new condition variable + * ... Solaris uses cond_init() in similar function. + * + * returns: -1 on failure + * 0 when it succeeds. + * + */ +PRInt32 +_PR_MD_NEW_CV(_MDCVar *cv) +{ + cv->magic = _MD_MAGIC_CV; + /* + * The waitHead, waitTail, and nwait fields are zeroed + * when the PRCondVar structure is created. + */ + return 0; +} + +void _PR_MD_FREE_CV(_MDCVar *cv) +{ + cv->magic = (PRUint32)-1; + return; +} + +/* + * _PR_MD_WAIT_CV() -- Wait on condition variable + */ +void _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout ) +{ + PRThread *thred = _PR_MD_CURRENT_THREAD(); + DWORD rv; + DWORD msecs = (timeout == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(timeout); + + /* + * If we have pending notifies, post them now. + */ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, thred, cv); + } else { + AddThreadToCVWaitQueueInternal(thred, cv); + LeaveCriticalSection(&lock->mutex); + } + + /* Wait for notification or timeout; don't really care which */ + rv = WaitForSingleObject(thred->md.blocked_sema, msecs); + + EnterCriticalSection(&(lock->mutex)); + + PR_ASSERT(rv != WAIT_ABANDONED); + PR_ASSERT(rv != WAIT_FAILED); + PR_ASSERT(rv != WAIT_OBJECT_0 || thred->md.inCVWaitQueue == PR_FALSE); + + if (rv == WAIT_TIMEOUT) { + if (thred->md.inCVWaitQueue) { + PR_ASSERT((cv->waitTail != NULL && cv->waitHead != NULL) + || (cv->waitTail == NULL && cv->waitHead == NULL)); + cv->nwait -= 1; + thred->md.inCVWaitQueue = PR_FALSE; + if (cv->waitHead == thred) { + cv->waitHead = thred->md.next; + if (cv->waitHead == NULL) { + cv->waitTail = NULL; + } else { + cv->waitHead->md.prev = NULL; + } + } else { + PR_ASSERT(thred->md.prev != NULL); + thred->md.prev->md.next = thred->md.next; + if (thred->md.next != NULL) { + thred->md.next->md.prev = thred->md.prev; + } else { + PR_ASSERT(cv->waitTail == thred); + cv->waitTail = thred->md.prev; + } + } + thred->md.next = thred->md.prev = NULL; + } else { + /* + * This thread must have been notified, but the + * ReleaseSemaphore call happens after WaitForSingleObject + * times out. Wait on the semaphore again to make it + * non-signaled. We assume this wait won't take long. + */ + rv = WaitForSingleObject(thred->md.blocked_sema, INFINITE); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + PR_ASSERT(thred->md.inCVWaitQueue == PR_FALSE); + return; +} /* --- end _PR_MD_WAIT_CV() --- */ + +void _PR_MD_NOTIFY_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_FALSE); + return; +} + +void _PR_MD_NOTIFYALL_CV(_MDCVar *cv, _MDLock *lock) +{ + md_PostNotifyToCvar(cv, lock, PR_TRUE); + return; +} + +void _PR_MD_UNLOCK(_MDLock *lock) +{ + if (0 != lock->notified.length) { + md_UnlockAndPostNotifies(lock, NULL, NULL); + } else { + LeaveCriticalSection(&lock->mutex); + } + return; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95dllmain.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95dllmain.c new file mode 100644 index 00000000..1dafe7a2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95dllmain.c @@ -0,0 +1,71 @@ +/* -*- 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 ***** */ + +/* + * The DLL entry point (DllMain) for NSPR. + * + * This is used to detach threads that were automatically attached by + * nspr. + */ + +#include +#include + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ +PRThread *me; + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + if (_pr_initialized) { + me = _MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + } + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95io.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95io.c new file mode 100644 index 00000000..5d483cea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95io.c @@ -0,0 +1,1511 @@ +/* -*- 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 ***** */ + +/* Windows 95 IO module + * + * Assumes synchronous I/O. + * + */ + +#include "primpl.h" +#include +#include +#ifdef MOZ_UNICODE +#include +#endif /* MOZ_UNICODE */ + + +struct _MDLock _pr_ioq_lock; + +/* + * NSPR-to-NT access right mapping table for files. + */ +static DWORD fileAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE, + FILE_GENERIC_EXECUTE +}; + +/* + * NSPR-to-NT access right mapping table for directories. + */ +static DWORD dirAccessTable[] = { + FILE_GENERIC_READ, + FILE_GENERIC_WRITE|FILE_DELETE_CHILD, + FILE_GENERIC_EXECUTE +}; + +/* + * The NSPR epoch (00:00:00 1 Jan 1970 UTC) in FILETIME. + * We store the value in a PRTime variable for convenience. + * This constant is used by _PR_FileTimeToPRTime(). + */ +#if defined(__MINGW32__) +static const PRTime _pr_filetime_offset = 116444736000000000LL; +#else +static const PRTime _pr_filetime_offset = 116444736000000000i64; +#endif + +#ifdef MOZ_UNICODE +static void InitUnicodeSupport(void); +#endif + +void +_PR_MD_INIT_IO() +{ + WORD WSAVersion = 0x0101; + WSADATA WSAData; + int err; + + err = WSAStartup( WSAVersion, &WSAData ); + PR_ASSERT(0 == err); + +#ifdef DEBUG + /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */ + { + SYSTEMTIME systime; + union { + PRTime prt; + FILETIME ft; + } filetime; + BOOL rv; + + systime.wYear = 1970; + systime.wMonth = 1; + /* wDayOfWeek is ignored */ + systime.wDay = 1; + systime.wHour = 0; + systime.wMinute = 0; + systime.wSecond = 0; + systime.wMilliseconds = 0; + + rv = SystemTimeToFileTime(&systime, &filetime.ft); + PR_ASSERT(0 != rv); + PR_ASSERT(filetime.prt == _pr_filetime_offset); + } +#endif /* DEBUG */ + + _PR_NT_InitSids(); + +#ifdef MOZ_UNICODE + InitUnicodeSupport(); +#endif +} + +PRStatus +_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks) +{ + DWORD rv; + + PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ? + INFINITE : PR_IntervalToMilliseconds(ticks); + rv = WaitForSingleObject(thread->md.blocked_sema, msecs); + switch(rv) + { + case WAIT_OBJECT_0: + return PR_SUCCESS; + break; + case WAIT_TIMEOUT: + _PR_THREAD_LOCK(thread); + if (thread->state == _PR_IO_WAIT) { + ; + } else { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + } else { + /* The CVAR was notified just as the timeout + * occurred. This led to us being notified twice. + * call WaitForSingleObject() to clear the semaphore. + */ + _PR_THREAD_UNLOCK(thread); + rv = WaitForSingleObject(thread->md.blocked_sema, 0); + PR_ASSERT(rv == WAIT_OBJECT_0); + } + } + return PR_SUCCESS; + break; + default: + return PR_FAILURE; + break; + } +} +PRStatus +_PR_MD_WAKEUP_WAITER(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) ) + { + if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE) + return PR_FAILURE; + else + return PR_SUCCESS; + } +} + + +/* --- FILE IO ----------------------------------------------------------- */ +/* + * _PR_MD_OPEN() -- Open a file + * + * returns: a fileHandle + * + * The NSPR open flags (osflags) are translated into flags for Win95 + * + * Mode seems to be passed in as a unix style file permissions argument + * as in 0666, in the case of opening the logFile. + * + */ +PRInt32 +_PR_MD_OPEN(const char *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + flags, + flag6, + NULL); + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_OPEN_FILE(const char *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = CreateFile(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PRInt32)file; +} + +PRInt32 +_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len) +{ + PRUint32 bytes; + int rv, err; + + rv = ReadFile((HANDLE)fd->secret->md.osfd, + (LPVOID)buf, + len, + &bytes, + NULL); + + if (rv == 0) + { + err = GetLastError(); + /* ERROR_HANDLE_EOF can only be returned by async io */ + PR_ASSERT(err != ERROR_HANDLE_EOF); + if (err == ERROR_BROKEN_PIPE) + return 0; + else { + _PR_MD_MAP_READ_ERROR(err); + return -1; + } + } + return bytes; +} + +PRInt32 +_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len) +{ + PRInt32 f = fd->secret->md.osfd; + PRInt32 bytes; + int rv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + rv = WriteFile((HANDLE)f, + buf, + len, + &bytes, + NULL ); + + if (rv == 0) + { + _PR_MD_MAP_WRITE_ERROR(GetLastError()); + return -1; + } + return bytes; +} /* --- end _PR_MD_WRITE() --- */ + +PROffset32 +_PR_MD_LSEEK(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + PROffset32 rv; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod); + + /* + * If the lpDistanceToMoveHigh argument (third argument) is + * NULL, SetFilePointer returns 0xffffffff on failure. + */ + if (-1 == rv) { + _PR_MD_MAP_LSEEK_ERROR(GetLastError()); + } + return rv; +} + +PROffset64 +_PR_MD_LSEEK64(PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence) +{ + DWORD moveMethod; + LARGE_INTEGER li; + DWORD err; + + switch (whence) { + case PR_SEEK_SET: + moveMethod = FILE_BEGIN; + break; + case PR_SEEK_CUR: + moveMethod = FILE_CURRENT; + break; + case PR_SEEK_END: + moveMethod = FILE_END; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + li.QuadPart = offset; + li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd, + li.LowPart, &li.HighPart, moveMethod); + + if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) { + _PR_MD_MAP_LSEEK_ERROR(err); + li.QuadPart = -1; + } + return li.QuadPart; +} + +/* + * This is documented to succeed on read-only files, but Win32's + * FlushFileBuffers functions fails with "access denied" in such a + * case. So we only signal an error if the error is *not* "access + * denied". + */ +PRInt32 +_PR_MD_FSYNC(PRFileDesc *fd) +{ + /* + * From the documentation: + * + * On Windows NT, the function FlushFileBuffers fails if hFile + * is a handle to console output. That is because console + * output is not buffered. The function returns FALSE, and + * GetLastError returns ERROR_INVALID_HANDLE. + * + * On the other hand, on Win95, it returns without error. I cannot + * assume that 0, 1, and 2 are console, because if someone closes + * System.out and then opens a file, they might get file descriptor + * 1. An error on *that* version of 1 should be reported, whereas + * an error on System.out (which was the original 1) should be + * ignored. So I use isatty() to ensure that such an error was due + * to this bogosity, and if it was, I ignore the error. + */ + + BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd); + + if (!ok) { + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) { // from winerror.h + _PR_MD_MAP_FSYNC_ERROR(err); + return -1; + } + } + return 0; +} + +PRInt32 +_MD_CloseFile(PRInt32 osfd) +{ + PRInt32 rv; + + rv = (CloseHandle((HANDLE)osfd))?0:-1; + if (rv == -1) + _PR_MD_MAP_CLOSE_ERROR(GetLastError()); + return rv; +} + + +/* --- DIR IO ------------------------------------------------------------ */ +#define GetFileFromDIR(d) (d)->d_entry.cFileName +#define FileIsHidden(d) ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + +void FlipSlashes(char *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == '/') { + cp[0] = PR_DIRECTORY_SEPARATOR; + } + cp = _mbsinc(cp); + } +} /* end FlipSlashes() */ + + +/* +** +** Local implementations of standard Unix RTL functions which are not provided +** by the VC RTL. +** +*/ + +PRStatus +_PR_MD_CLOSE_DIR(_MDDir *d) +{ + if ( d ) { + if (FindClose(d->d_hdl)) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + + +PRStatus +_PR_MD_OPEN_DIR(_MDDir *d, const char *name) +{ + char filename[ MAX_PATH ]; + int len; + + len = strlen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + strcpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (filename[len - 1] == '/' || filename[len - 1] == '\\') { + len--; + } + strcpy(&filename[len], "\\*.*"); + FlipSlashes( filename, strlen(filename) ); + + d->d_hdl = FindFirstFile( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +char * +_PR_MD_READ_DIR(_MDDir *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + char *fileName; + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = FindNextFile(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == '.') && (fileName[1] == '\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == '.') && (fileName[1] == '.') && + (fileName[2] == '\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRInt32 +_PR_MD_DELETE(const char *name) +{ + if (DeleteFile(name)) { + return 0; + } else { + _PR_MD_MAP_DELETE_ERROR(GetLastError()); + return -1; + } +} + +void +_PR_FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm) +{ + PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime)); + CopyMemory(prtm, filetime, sizeof(PRTime)); +#if defined(__MINGW32__) + *prtm = (*prtm - _pr_filetime_offset) / 10LL; +#else + *prtm = (*prtm - _pr_filetime_offset) / 10i64; +#endif + +#ifdef DEBUG + /* Doublecheck our calculation. */ + { + SYSTEMTIME systime; + PRExplodedTime etm; + PRTime cmp; /* for comparison */ + BOOL rv; + + rv = FileTimeToSystemTime(filetime, &systime); + PR_ASSERT(0 != rv); + + /* + * PR_ImplodeTime ignores wday and yday. + */ + etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC; + etm.tm_sec = systime.wSecond; + etm.tm_min = systime.wMinute; + etm.tm_hour = systime.wHour; + etm.tm_mday = systime.wDay; + etm.tm_month = systime.wMonth - 1; + etm.tm_year = systime.wYear; + /* + * It is not well-documented what time zone the FILETIME's + * are in. WIN32_FIND_DATA is documented to be in UTC (GMT). + * But BY_HANDLE_FILE_INFORMATION is unclear about this. + * By our best judgement, we assume that FILETIME is in UTC. + */ + etm.tm_params.tp_gmt_offset = 0; + etm.tm_params.tp_dst_offset = 0; + cmp = PR_ImplodeTime(&etm); + + /* + * SYSTEMTIME is in milliseconds precision, so we convert PRTime's + * microseconds to milliseconds before doing the comparison. + */ + PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC)); + } +#endif /* DEBUG */ +} + +PRInt32 +_PR_MD_STAT(const char *fn, struct stat *info) +{ + PRInt32 rv; + + rv = _stat(fn, (struct _stat *)info); + if (-1 == rv) { + /* + * Check for MSVC runtime library _stat() bug. + * (It's really a bug in FindFirstFile().) + * If a pathname ends in a backslash or slash, + * e.g., c:\temp\ or c:/temp/, _stat() will fail. + * Note: a pathname ending in a slash (e.g., c:/temp/) + * can be handled by _stat() on NT but not on Win95. + * + * We remove the backslash or slash at the end and + * try again. + */ + + int len = strlen(fn); + if (len > 0 && len <= _MAX_PATH + && (fn[len - 1] == '\\' || fn[len - 1] == '/')) { + char newfn[_MAX_PATH + 1]; + + strcpy(newfn, fn); + newfn[len - 1] = '\0'; + rv = _stat(newfn, (struct _stat *)info); + } + } + + if (-1 == rv) { + _PR_MD_MAP_STAT_ERROR(errno); + } + return rv; +} + +#define _PR_IS_SLASH(ch) ((ch) == '/' || (ch) == '\\') + +/* + * IsRootDirectory -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The char buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn'. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectory(char *fn, size_t buflen) +{ + char *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') { + return PR_TRUE; + } + + if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2]) + && fn[3] == '\0') { + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p++; + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (*p == '\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == '\0' || _PR_IS_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p++; + } while (*p != '\0' && !_PR_IS_SLASH(*p)); + if (_PR_IS_SLASH(*p) && p[1] != '\0') { + return PR_FALSE; + } + if (*p == '\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = '\\'; + *p = '\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = '\0'; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info) +{ + HANDLE hFindFile; + WIN32_FIND_DATA findFileData; + char pathbuf[MAX_PATH + 1]; + + if (NULL == fn || '\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + /* + * FindFirstFile() expands wildcard characters. So + * we make sure the pathname contains no wildcard. + */ + if (NULL != _mbspbrk(fn, "?*")) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); + return -1; + } + + hFindFile = FindFirstFile(fn, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + DWORD len; + char *filePart; + + /* + * FindFirstFile() does not work correctly on root directories. + * It also doesn't work correctly on a pathname that ends in a + * slash. So we first check to see if the pathname specifies a + * root directory. If not, and if the pathname ends in a slash, + * we remove the final slash and try again. + */ + + /* + * If the pathname does not contain ., \, and /, it cannot be + * a root directory or a pathname that ends in a slash. + */ + if (NULL == _mbspbrk(fn, ".\\/")) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + len = GetFullPathName(fn, sizeof(pathbuf), pathbuf, + &filePart); + if (0 == len) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + if (len > sizeof(pathbuf)) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return -1; + } + if (IsRootDirectory(pathbuf, sizeof(pathbuf))) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + /* + * These timestamps don't make sense for root directories. + */ + info->modifyTime = 0; + info->creationTime = 0; + return 0; + } + if (!_PR_IS_SLASH(pathbuf[len - 1])) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } else { + pathbuf[len - 1] = '\0'; + hFindFile = FindFirstFile(pathbuf, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + } + } + + FindClose(hFindFile); + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} + +PRInt32 +_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info) +{ + PRFileInfo64 info64; + PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64); + if (0 == rv) + { + info->type = info64.type; + info->size = (PRUint32) info64.size; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + } + return rv; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info) +{ + int rv; + + BY_HANDLE_FILE_INFORMATION hinfo; + + rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo); + if (rv == FALSE) { + _PR_MD_MAP_FSTAT_ERROR(GetLastError()); + return -1; + } + + if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + info->type = PR_FILE_DIRECTORY; + else + info->type = PR_FILE_FILE; + + info->size = hinfo.nFileSizeHigh; + info->size = (info->size << 32) + hinfo.nFileSizeLow; + + _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) ); + _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) ); + + return 0; +} + +PRInt32 +_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info) +{ + PRFileInfo64 info64; + int rv = _PR_MD_GETOPENFILEINFO64(fd, &info64); + if (0 == rv) + { + info->type = info64.type; + info->modifyTime = info64.modifyTime; + info->creationTime = info64.creationTime; + LL_L2I(info->size, info64.size); + } + return rv; +} + +PRStatus +_PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable) +{ + BOOL rv; + + /* + * The SetHandleInformation function fails with the + * ERROR_CALL_NOT_IMPLEMENTED error on Win95. + */ + rv = SetHandleInformation( + (HANDLE)fd->secret->md.osfd, + HANDLE_FLAG_INHERIT, + inheritable ? HANDLE_FLAG_INHERIT : 0); + if (0 == rv) { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +void +_PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported) +{ + if (imported) { + fd->secret->inheritable = _PR_TRI_UNKNOWN; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } +} + +void +_PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd) +{ + DWORD flags; + + PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable); + if (GetHandleInformation((HANDLE)fd->secret->md.osfd, &flags)) { + if (flags & HANDLE_FLAG_INHERIT) { + fd->secret->inheritable = _PR_TRI_TRUE; + } else { + fd->secret->inheritable = _PR_TRI_FALSE; + } + } +} + +PRInt32 +_PR_MD_RENAME(const char *from, const char *to) +{ + /* Does this work with dot-relative pathnames? */ + if (MoveFile(from, to)) { + return 0; + } else { + _PR_MD_MAP_RENAME_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_ACCESS(const char *name, PRAccessHow how) +{ +PRInt32 rv; + switch (how) { + case PR_ACCESS_WRITE_OK: + rv = _access(name, 02); + break; + case PR_ACCESS_READ_OK: + rv = _access(name, 04); + break; + case PR_ACCESS_EXISTS: + return _access(name, 00); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + if (rv < 0) + _PR_MD_MAP_ACCESS_ERROR(errno); + return rv; +} + +PRInt32 +_PR_MD_MKDIR(const char *name, PRIntn mode) +{ + /* XXXMB - how to translate the "mode"??? */ + if (CreateDirectory(name, NULL)) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_MAKE_DIR(const char *name, PRIntn mode) +{ + BOOL rv; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + rv = CreateDirectory(name, lpSA); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (rv) { + return 0; + } else { + _PR_MD_MAP_MKDIR_ERROR(GetLastError()); + return -1; + } +} + +PRInt32 +_PR_MD_RMDIR(const char *name) +{ + if (RemoveDirectory(name)) { + return 0; + } else { + _PR_MD_MAP_RMDIR_ERROR(GetLastError()); + return -1; + } +} + +PRStatus +_PR_MD_LOCKFILE(PRInt32 f) +{ + PRStatus rc = PR_SUCCESS; + DWORD rv; + + rv = LockFile( (HANDLE)f, + 0l, 0l, + 0x0l, 0xffffffffl ); + if ( rv == 0 ) { + DWORD rc = GetLastError(); + PR_LOG( _pr_io_lm, PR_LOG_ERROR, + ("_PR_MD_LOCKFILE() failed. Error: %d", rc )); + rc = PR_FAILURE; + } + + return rc; +} /* end _PR_MD_LOCKFILE() */ + +PRStatus +_PR_MD_TLOCKFILE(PRInt32 f) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return PR_FAILURE; +} /* end _PR_MD_TLOCKFILE() */ + + +PRStatus +_PR_MD_UNLOCKFILE(PRInt32 f) +{ + PRInt32 rv; + + rv = UnlockFile( (HANDLE) f, + 0l, 0l, + 0x0l, 0xffffffffl ); + + if ( rv ) + { + return PR_SUCCESS; + } + else + { + _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); + return PR_FAILURE; + } +} /* end _PR_MD_UNLOCKFILE() */ + +PRInt32 +_PR_MD_PIPEAVAILABLE(PRFileDesc *fd) +{ + if (NULL == fd) + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +#ifdef MOZ_UNICODE + +typedef HANDLE (WINAPI *CreateFileWFn) (LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); +static CreateFileWFn createFileW = NULL; +typedef HANDLE (WINAPI *FindFirstFileWFn) (LPCWSTR, LPWIN32_FIND_DATAW); +static FindFirstFileWFn findFirstFileW = NULL; +typedef BOOL (WINAPI *FindNextFileWFn) (HANDLE, LPWIN32_FIND_DATAW); +static FindNextFileWFn findNextFileW = NULL; +typedef DWORD (WINAPI *GetFullPathNameWFn) (LPCWSTR, DWORD, LPWSTR, LPWSTR *); +static GetFullPathNameWFn getFullPathNameW = NULL; +typedef UINT (WINAPI *GetDriveTypeWFn) (LPCWSTR); +static GetDriveTypeWFn getDriveTypeW = NULL; + +static void InitUnicodeSupport(void) +{ + HMODULE module; + + /* + * The W functions do not exist on Win9x. NSPR won't run on Win9x + * if we call the W functions directly. Use GetProcAddress() to + * look up their addresses at run time. + */ + + module = GetModuleHandle("Kernel32.dll"); + if (!module) { + return; + } + + createFileW = (CreateFileWFn)GetProcAddress(module, "CreateFileW"); + findFirstFileW = (FindFirstFileWFn)GetProcAddress(module, "FindFirstFileW"); + findNextFileW = (FindNextFileWFn)GetProcAddress(module, "FindNextFileW"); + getDriveTypeW = (GetDriveTypeWFn)GetProcAddress(module, "GetDriveTypeW"); + getFullPathNameW = (GetFullPathNameWFn)GetProcAddress(module, "GetFullPathNameW"); +} + +/* ================ UTF16 Interfaces ================================ */ +void FlipSlashesW(PRUnichar *cp, int len) +{ + while (--len >= 0) { + if (cp[0] == L'/') { + cp[0] = L'\\'; + } + cp++; + } +} /* end FlipSlashesW() */ + +PRInt32 +_PR_MD_OPEN_FILE_UTF16(const PRUnichar *name, PRIntn osflags, int mode) +{ + HANDLE file; + PRInt32 access = 0; + PRInt32 flags = 0; + PRInt32 flag6 = 0; + SECURITY_ATTRIBUTES sa; + LPSECURITY_ATTRIBUTES lpSA = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + PACL pACL = NULL; + + if (!createFileW) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; + } + + if (osflags & PR_CREATE_FILE) { + if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable, + &pSD, &pACL) == PR_SUCCESS) { + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = FALSE; + lpSA = &sa; + } + } + + if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH; + + if (osflags & PR_RDONLY || osflags & PR_RDWR) + access |= GENERIC_READ; + if (osflags & PR_WRONLY || osflags & PR_RDWR) + access |= GENERIC_WRITE; + + if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL ) + flags = CREATE_NEW; + else if (osflags & PR_CREATE_FILE) { + if (osflags & PR_TRUNCATE) + flags = CREATE_ALWAYS; + else + flags = OPEN_ALWAYS; + } else { + if (osflags & PR_TRUNCATE) + flags = TRUNCATE_EXISTING; + else + flags = OPEN_EXISTING; + } + + file = createFileW(name, + access, + FILE_SHARE_READ|FILE_SHARE_WRITE, + lpSA, + flags, + flag6, + NULL); + if (lpSA != NULL) { + _PR_NT_FreeSecurityDescriptorACL(pSD, pACL); + } + if (file == INVALID_HANDLE_VALUE) { + _PR_MD_MAP_OPEN_ERROR(GetLastError()); + return -1; + } + + return (PRInt32)file; +} + +PRStatus +_PR_MD_OPEN_DIR_UTF16(_MDDirUTF16 *d, const PRUnichar *name) +{ + PRUnichar filename[ MAX_PATH ]; + int len; + + if (!findFirstFileW) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; + } + + len = wcslen(name); + /* Need 5 bytes for \*.* and the trailing null byte. */ + if (len + 5 > MAX_PATH) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return PR_FAILURE; + } + wcscpy(filename, name); + + /* + * If 'name' ends in a slash or backslash, do not append + * another backslash. + */ + if (filename[len - 1] == L'/' || filename[len - 1] == L'\\') { + len--; + } + wcscpy(&filename[len], L"\\*.*"); + FlipSlashesW( filename, wcslen(filename) ); + + d->d_hdl = findFirstFileW( filename, &(d->d_entry) ); + if ( d->d_hdl == INVALID_HANDLE_VALUE ) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + d->firstEntry = PR_TRUE; + d->magic = _MD_MAGIC_DIR; + return PR_SUCCESS; +} + +PRUnichar * +_PR_MD_READ_DIR_UTF16(_MDDirUTF16 *d, PRIntn flags) +{ + PRInt32 err; + BOOL rv; + PRUnichar *fileName; + + if (!findNextFileW) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; + } + + if ( d ) { + while (1) { + if (d->firstEntry) { + d->firstEntry = PR_FALSE; + rv = 1; + } else { + rv = findNextFileW(d->d_hdl, &(d->d_entry)); + } + if (rv == 0) { + break; + } + fileName = GetFileFromDIR(d); + if ( (flags & PR_SKIP_DOT) && + (fileName[0] == L'.') && (fileName[1] == L'\0')) + continue; + if ( (flags & PR_SKIP_DOT_DOT) && + (fileName[0] == L'.') && (fileName[1] == L'.') && + (fileName[2] == L'\0')) + continue; + if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d)) + continue; + return fileName; + } + err = GetLastError(); + PR_ASSERT(NO_ERROR != err); + _PR_MD_MAP_READDIR_ERROR(err); + return NULL; + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; +} + +PRStatus +_PR_MD_CLOSE_DIR_UTF16(_MDDirUTF16 *d) +{ + if ( d ) { + if (FindClose(d->d_hdl)) { + d->magic = (PRUint32)-1; + return PR_SUCCESS; + } else { + _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError()); + return PR_FAILURE; + } + } + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; +} + +#define _PR_IS_W_SLASH(ch) ((ch) == L'/' || (ch) == L'\\') + +/* + * IsRootDirectoryW -- + * + * Return PR_TRUE if the pathname 'fn' is a valid root directory, + * else return PR_FALSE. The PRUnichar buffer pointed to by 'fn' must + * be writable. During the execution of this function, the contents + * of the buffer pointed to by 'fn' may be modified, but on return + * the original contents will be restored. 'buflen' is the size of + * the buffer pointed to by 'fn', in PRUnichars. + * + * Root directories come in three formats: + * 1. / or \, meaning the root directory of the current drive. + * 2. C:/ or C:\, where C is a drive letter. + * 3. \\\\ or + * \\\, meaning the root directory + * of a UNC (Universal Naming Convention) name. + */ + +static PRBool +IsRootDirectoryW(PRUnichar *fn, size_t buflen) +{ + PRUnichar *p; + PRBool slashAdded = PR_FALSE; + PRBool rv = PR_FALSE; + + if (_PR_IS_W_SLASH(fn[0]) && fn[1] == L'\0') { + return PR_TRUE; + } + + if (iswalpha(fn[0]) && fn[1] == L':' && _PR_IS_W_SLASH(fn[2]) + && fn[3] == L'\0') { + rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; + return rv; + } + + /* The UNC root directory */ + + if (_PR_IS_W_SLASH(fn[0]) && _PR_IS_W_SLASH(fn[1])) { + /* The 'server' part should have at least one character. */ + p = &fn[2]; + if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the next slash */ + do { + p++; + } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); + if (*p == L'\0') { + return PR_FALSE; + } + + /* The 'share' part should have at least one character. */ + p++; + if (*p == L'\0' || _PR_IS_W_SLASH(*p)) { + return PR_FALSE; + } + + /* look for the final slash */ + do { + p++; + } while (*p != L'\0' && !_PR_IS_W_SLASH(*p)); + if (_PR_IS_W_SLASH(*p) && p[1] != L'\0') { + return PR_FALSE; + } + if (*p == L'\0') { + /* + * GetDriveType() doesn't work correctly if the + * path is of the form \\server\share, so we add + * a final slash temporarily. + */ + if ((p + 1) < (fn + buflen)) { + *p++ = L'\\'; + *p = L'\0'; + slashAdded = PR_TRUE; + } else { + return PR_FALSE; /* name too long */ + } + } + rv = getDriveTypeW(fn) > 1 ? PR_TRUE : PR_FALSE; + /* restore the 'fn' buffer */ + if (slashAdded) { + *--p = L'\0'; + } + } + return rv; +} + +PRInt32 +_PR_MD_GETFILEINFO64_UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ + HANDLE hFindFile; + WIN32_FIND_DATAW findFileData; + PRUnichar pathbuf[MAX_PATH + 1]; + + if (!findFirstFileW || !getFullPathNameW || !getDriveTypeW) { + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; + } + + if (NULL == fn || L'\0' == *fn) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } + + /* + * FindFirstFile() expands wildcard characters. So + * we make sure the pathname contains no wildcard. + */ + if (NULL != wcspbrk(fn, L"?*")) { + PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0); + return -1; + } + + hFindFile = findFirstFileW(fn, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + DWORD len; + PRUnichar *filePart; + + /* + * FindFirstFile() does not work correctly on root directories. + * It also doesn't work correctly on a pathname that ends in a + * slash. So we first check to see if the pathname specifies a + * root directory. If not, and if the pathname ends in a slash, + * we remove the final slash and try again. + */ + + /* + * If the pathname does not contain ., \, and /, it cannot be + * a root directory or a pathname that ends in a slash. + */ + if (NULL == wcspbrk(fn, L".\\/")) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + len = getFullPathNameW(fn, sizeof(pathbuf)/sizeof(pathbuf[0]), pathbuf, + &filePart); + if (0 == len) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + if (len > sizeof(pathbuf)/sizeof(pathbuf[0])) { + PR_SetError(PR_NAME_TOO_LONG_ERROR, 0); + return -1; + } + if (IsRootDirectoryW(pathbuf, sizeof(pathbuf)/sizeof(pathbuf[0]))) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + /* + * These timestamps don't make sense for root directories. + */ + info->modifyTime = 0; + info->creationTime = 0; + return 0; + } + if (!_PR_IS_W_SLASH(pathbuf[len - 1])) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } else { + pathbuf[len - 1] = L'\0'; + hFindFile = findFirstFileW(pathbuf, &findFileData); + if (INVALID_HANDLE_VALUE == hFindFile) { + _PR_MD_MAP_OPENDIR_ERROR(GetLastError()); + return -1; + } + } + } + + FindClose(hFindFile); + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + info->type = PR_FILE_DIRECTORY; + } else { + info->type = PR_FILE_FILE; + } + + info->size = findFileData.nFileSizeHigh; + info->size = (info->size << 32) + findFileData.nFileSizeLow; + + _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime); + + if (0 == findFileData.ftCreationTime.dwLowDateTime && + 0 == findFileData.ftCreationTime.dwHighDateTime) { + info->creationTime = info->modifyTime; + } else { + _PR_FileTimeToPRTime(&findFileData.ftCreationTime, + &info->creationTime); + } + + return 0; +} +/* ================ end of UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95sock.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95sock.c new file mode 100644 index 00000000..01c25258 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95sock.c @@ -0,0 +1,658 @@ +/* -*- 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 ***** */ + +/* Win95 Sockets module + * + */ + +#include "primpl.h" + +#define READ_FD 1 +#define WRITE_FD 2 +#define CONNECT_FD 3 + +static PRInt32 socket_io_wait( + PRInt32 osfd, + PRInt32 fd_type, + PRIntervalTime timeout); + + +/* --- SOCKET IO --------------------------------------------------------- */ + + +PRInt32 +_PR_MD_SOCKET(int af, int type, int flags) +{ + SOCKET sock; + u_long one = 1; + + sock = socket(af, type, flags); + + if (sock == INVALID_SOCKET ) + { + _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError()); + return (PRInt32)sock; + } + + /* + ** Make the socket Non-Blocking + */ + if (ioctlsocket( sock, FIONBIO, &one) != 0) + { + PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError()); + closesocket(sock); + return -1; + } + + return (PRInt32)sock; +} + +/* +** _MD_CloseSocket() -- Close a socket +** +*/ +PRInt32 +_MD_CloseSocket(PRInt32 osfd) +{ + PRInt32 rv; + + rv = closesocket((SOCKET) osfd ); + if (rv < 0) + _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError()); + + return rv; +} + +PRInt32 +_MD_SocketAvailable(PRFileDesc *fd) +{ + PRInt32 result; + + if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError()); + return -1; + } + return result; +} + +PRInt32 _MD_Accept( + PRFileDesc *fd, + PRNetAddr *raddr, + PRUint32 *rlen, + PRIntervalTime timeout ) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + + while ((rv = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1) + { + err = WSAGetLastError(); + if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking)) + { + if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0) + { + return(-1); + } + } + else + { + _PR_MD_MAP_ACCEPT_ERROR(err); + break; + } + } + return(rv); +} /* end _MD_accept() */ + +PRInt32 +_PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv; + int err; + + if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) + { + err = WSAGetLastError(); + if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK)) + { + rv = socket_io_wait(osfd, CONNECT_FD, timeout); + if ( rv < 0 ) + { + return(-1); + } + else + { + PR_ASSERT(rv > 0); + /* it's connected */ + return(0); + } + } + _PR_MD_MAP_CONNECT_ERROR(err); + } + return rv; +} + +PRInt32 +_PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen) +{ + PRInt32 rv; + + rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_BIND_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + +PRInt32 +_PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog) +{ + PRInt32 rv; + + rv = listen(fd->secret->md.osfd, backlog); + + if (rv == SOCKET_ERROR) { + _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError()); + return -1; + } + + return 0; +} + +PRInt32 +_PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + int osflags; + + if (0 == flags) { + osflags = 0; + } else { + PR_ASSERT(PR_MSG_PEEK == flags); + osflags = MSG_PEEK; + } + while ((rv = recv( osfd, buf, amount, osflags)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_RECV_ERROR(err); + break; + } + } /* end while() */ + return(rv); +} + +PRInt32 +_PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRInt32 bytesSent = 0; + + while(bytesSent < amount ) + { + while ((rv = send( osfd, buf, amount, 0 )) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_SEND_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) + { + break; + } + if (bytesSent < amount) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, + const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + PRInt32 bytesSent = 0; + + while(bytesSent < amount) + { + while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr, + addrlen)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if ( rv < 0 ) + { + return -1; + } + } + else + { + _PR_MD_MAP_SENDTO_ERROR(err); + return -1; + } + } + bytesSent += rv; + if (fd->secret->nonblocking) + { + break; + } + if (bytesSent < amount) + { + rv = socket_io_wait(osfd, WRITE_FD, timeout); + if (rv < 0) + { + return -1; + } + } + } + return bytesSent; +} + +PRInt32 +_PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, + PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) +{ + PRInt32 osfd = fd->secret->md.osfd; + PRInt32 rv, err; + + while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr, + addrlen)) == -1) + { + if (((err = WSAGetLastError()) == WSAEWOULDBLOCK) + && (!fd->secret->nonblocking)) + { + rv = socket_io_wait(osfd, READ_FD, timeout); + if ( rv < 0) + { + return -1; + } + } + else + { + _PR_MD_MAP_RECVFROM_ERROR(err); + break; + } + } + return(rv); +} + +PRInt32 +_PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) +{ + int index; + int sent = 0; + int rv; + + for (index=0; index < iov_size; index++) + { + rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout); + if (rv > 0) + sent += rv; + if ( rv != iov[index].iov_len ) + { + if (rv < 0) + { + if (fd->secret->nonblocking + && (PR_GetError() == PR_WOULD_BLOCK_ERROR) + && (sent > 0)) + { + return sent; + } + else + { + return -1; + } + } + /* Only a nonblocking socket can have partial sends */ + PR_ASSERT(fd->secret->nonblocking); + return sent; + } + } + return sent; +} + +PRInt32 +_PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how) +{ +PRInt32 rv; + + rv = shutdown(fd->secret->md.osfd, how); + if (rv < 0) + _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError()); + return rv; +} + +PRStatus +_PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len); + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len) +{ + PRInt32 rv; + + rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len); + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) +{ + PRInt32 rv; + + rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +PRStatus +_PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) +{ + PRInt32 rv; + + rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen); + if (rv==0) { + return PR_SUCCESS; + } else { + _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError()); + return PR_FAILURE; + } +} + +void +_MD_MakeNonblock(PRFileDesc *f) +{ + return; /* do nothing */ +} + + + +/* + * socket_io_wait -- + * + * Wait for socket i/o, periodically checking for interrupt. + * + * This function returns 1 on success. On failure, it returns + * -1 and sets the error codes. It never returns 0. + */ +#define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5 + +static PRInt32 socket_io_wait( + PRInt32 osfd, + PRInt32 fd_type, + PRIntervalTime timeout) +{ + PRInt32 rv = -1; + struct timeval tv; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntervalTime elapsed, remaining; + PRBool wait_for_remaining; + fd_set rd_wr, ex; + int err, len; + + switch (timeout) { + case PR_INTERVAL_NO_WAIT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + break; + case PR_INTERVAL_NO_TIMEOUT: + /* + * This is a special case of the 'default' case below. + * Please see the comments there. + */ + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + FD_ZERO(&rd_wr); + FD_ZERO(&ex); + do { + FD_SET(osfd, &rd_wr); + FD_SET(osfd, &ex); + switch( fd_type ) + { + case READ_FD: + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv); + break; + default: + PR_ASSERT(0); + break; + } /* end switch() */ + if (rv == -1 ) + { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + if ( rv > 0 && fd_type == CONNECT_FD ) + { + /* + * Call Sleep(0) to work around a Winsock timing bug. + */ + Sleep(0); + if (FD_ISSET((SOCKET)osfd, &ex)) + { + len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) == SOCKET_ERROR) + { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return -1; + } + if (err != 0) + _PR_MD_MAP_CONNECT_ERROR(err); + else + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + if (FD_ISSET((SOCKET)osfd, &rd_wr)) + { + /* it's connected */ + return 1; + } + PR_ASSERT(0); + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + } while (rv == 0); + break; + default: + remaining = timeout; + FD_ZERO(&rd_wr); + FD_ZERO(&ex); + do { + /* + * We block in _MD_SELECT for at most + * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, + * so that there is an upper limit on the delay + * before the interrupt bit is checked. + */ + wait_for_remaining = PR_TRUE; + tv.tv_sec = PR_IntervalToSeconds(remaining); + if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { + wait_for_remaining = PR_FALSE; + tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; + tv.tv_usec = 0; + } else { + tv.tv_usec = PR_IntervalToMicroseconds( + remaining - + PR_SecondsToInterval(tv.tv_sec)); + } + FD_SET(osfd, &rd_wr); + FD_SET(osfd, &ex); + switch( fd_type ) + { + case READ_FD: + rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv); + break; + case WRITE_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv); + break; + case CONNECT_FD: + rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, &ex, &tv); + break; + default: + PR_ASSERT(0); + break; + } /* end switch() */ + if (rv == -1) + { + _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); + break; + } + if ( rv > 0 && fd_type == CONNECT_FD ) + { + /* + * Call Sleep(0) to work around a Winsock timing bug. + */ + Sleep(0); + if (FD_ISSET((SOCKET)osfd, &ex)) + { + len = sizeof(err); + if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, + (char *) &err, &len) == SOCKET_ERROR) + { + _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); + return -1; + } + if (err != 0) + _PR_MD_MAP_CONNECT_ERROR(err); + else + PR_SetError(PR_UNKNOWN_ERROR, 0); + return -1; + } + if (FD_ISSET((SOCKET)osfd, &rd_wr)) + { + /* it's connected */ + return 1; + } + PR_ASSERT(0); + } + if (_PR_PENDING_INTERRUPT(me)) { + me->flags &= ~_PR_INTERRUPT; + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + rv = -1; + break; + } + /* + * We loop again if _MD_SELECT timed out and the + * timeout deadline has not passed yet. + */ + if (rv == 0 ) + { + if (wait_for_remaining) { + elapsed = remaining; + } else { + elapsed = PR_SecondsToInterval(tv.tv_sec) + + PR_MicrosecondsToInterval(tv.tv_usec); + } + if (elapsed >= remaining) { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + rv = -1; + break; + } else { + remaining = remaining - elapsed; + } + } + } while (rv == 0 ); + break; + } + return(rv); +} /* end socket_io_wait() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95thred.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95thred.c new file mode 100644 index 00000000..8671d825 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/w95thred.c @@ -0,0 +1,295 @@ +/* -*- 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 /* for _beginthreadex() */ + +extern void _PR_Win32InitTimeZone(void); /* defined in ntmisc.c */ + +/* --- globals ------------------------------------------------ */ +#ifdef _PR_USE_STATIC_TLS +__declspec(thread) struct PRThread *_pr_thread_last_run; +__declspec(thread) struct PRThread *_pr_currentThread; +__declspec(thread) struct _PRCPU *_pr_currentCPU; +#else +DWORD _pr_currentThreadIndex; +DWORD _pr_lastThreadIndex; +DWORD _pr_currentCPUIndex; +#endif +int _pr_intsOff = 0; +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; + +void +_PR_MD_EARLY_INIT() +{ + _PR_Win32InitTimeZone(); + +#ifndef _PR_USE_STATIC_TLS + _pr_currentThreadIndex = TlsAlloc(); + _pr_lastThreadIndex = TlsAlloc(); + _pr_currentCPUIndex = TlsAlloc(); +#endif +} + +void _PR_MD_CLEANUP_BEFORE_EXIT(void) +{ + _PR_NT_FreeSids(); + + WSACleanup(); + +#ifndef _PR_USE_STATIC_TLS + TlsFree(_pr_currentThreadIndex); + TlsFree(_pr_lastThreadIndex); + TlsFree(_pr_currentCPUIndex); +#endif +} + +PRStatus +_PR_MD_INIT_THREAD(PRThread *thread) +{ + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { + /* + ** Warning: + ** -------- + ** NSPR requires a real handle to every thread. + ** GetCurrentThread() returns a pseudo-handle which + ** is not suitable for some thread operations (e.g., + ** suspending). Therefore, get a real handle from + ** the pseudo handle via DuplicateHandle(...) + */ + DuplicateHandle( + GetCurrentProcess(), /* Process of source handle */ + GetCurrentThread(), /* Pseudo Handle to dup */ + GetCurrentProcess(), /* Process of handle */ + &(thread->md.handle), /* resulting handle */ + 0L, /* access flags */ + FALSE, /* Inheritable */ + DUPLICATE_SAME_ACCESS); /* Options */ + } + + /* Create the blocking IO semaphore */ + thread->md.blocked_sema = CreateSemaphore(NULL, 0, 1, NULL); + if (thread->md.blocked_sema == NULL) + return PR_FAILURE; + else + return PR_SUCCESS; +} + +static unsigned __stdcall +pr_root(void *arg) +{ + PRThread *thread = (PRThread *)arg; + thread->md.start(thread); + return 0; +} + +PRStatus +_PR_MD_CREATE_THREAD(PRThread *thread, + void (*start)(void *), + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + + thread->md.start = start; + thread->md.handle = (HANDLE) _beginthreadex( + NULL, + thread->stack->stackSize, + pr_root, + (void *)thread, + CREATE_SUSPENDED, + &(thread->id)); + if(!thread->md.handle) { + return PR_FAILURE; + } + + thread->md.id = thread->id; + /* + * On windows, a thread is created with a thread priority of + * THREAD_PRIORITY_NORMAL. + */ + if (priority != PR_PRIORITY_NORMAL) { + _PR_MD_SET_PRIORITY(&(thread->md), priority); + } + + /* Activate the thread */ + if ( ResumeThread( thread->md.handle ) != -1) + return PR_SUCCESS; + + return PR_FAILURE; +} + +void +_PR_MD_YIELD(void) +{ + /* Can NT really yield at all? */ + Sleep(0); +} + +void +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) +{ + int nativePri; + BOOL rv; + + if (newPri < PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } else if (newPri > PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } + switch (newPri) { + case PR_PRIORITY_LOW: + nativePri = THREAD_PRIORITY_BELOW_NORMAL; + break; + case PR_PRIORITY_NORMAL: + nativePri = THREAD_PRIORITY_NORMAL; + break; + case PR_PRIORITY_HIGH: + nativePri = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case PR_PRIORITY_URGENT: + nativePri = THREAD_PRIORITY_HIGHEST; + } + rv = SetThreadPriority(thread->handle, nativePri); + PR_ASSERT(rv); + if (!rv) { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: can't set thread priority\n")); + } + return; +} + +void +_PR_MD_CLEAN_THREAD(PRThread *thread) +{ + BOOL rv; + + if (thread->md.blocked_sema) { + rv = CloseHandle(thread->md.blocked_sema); + PR_ASSERT(rv); + thread->md.blocked_sema = 0; + } + + if (thread->md.handle) { + rv = CloseHandle(thread->md.handle); + PR_ASSERT(rv); + thread->md.handle = 0; + } +} + +void +_PR_MD_EXIT_THREAD(PRThread *thread) +{ + _PR_MD_CLEAN_THREAD(thread); + _PR_MD_SET_CURRENT_THREAD(NULL); +} + + +void +_PR_MD_EXIT(PRIntn status) +{ + _exit(status); +} + +PRInt32 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) +{ + int rv; + + rv = SetThreadAffinityMask(thread->md.handle, mask); + + return rv?0:-1; +} + +PRInt32 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) +{ + PRInt32 rv, system_mask; + + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); + + return rv?0:-1; +} + +void +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) +{ + _PR_MD_SUSPEND_THREAD(cpu->thread); +} + +void +_PR_MD_RESUME_CPU(_PRCPU *cpu) +{ + _PR_MD_RESUME_THREAD(cpu->thread); +} + +void +_PR_MD_SUSPEND_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DWORD previousSuspendCount; + /* XXXMB - SuspendThread() is not a blocking call; how do we + * know when the thread is *REALLY* suspended? + */ + previousSuspendCount = SuspendThread(thread->md.handle); + PR_ASSERT(previousSuspendCount == 0); + } +} + +void +_PR_MD_RESUME_THREAD(PRThread *thread) +{ + if (_PR_IS_NATIVE_THREAD(thread)) { + DWORD previousSuspendCount; + previousSuspendCount = ResumeThread(thread->md.handle); + PR_ASSERT(previousSuspendCount == 1); + } +} + +PRThread* +_MD_CURRENT_THREAD(void) +{ +PRThread *thread; + + thread = _MD_GET_ATTACHED_THREAD(); + + if (NULL == thread) { + thread = _PRI_AttachThread( + PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); + } + PR_ASSERT(thread != NULL); + return thread; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/win32_errors.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/win32_errors.c new file mode 100644 index 00000000..0cf1bb58 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/windows/win32_errors.c @@ -0,0 +1,562 @@ +/* -*- 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 "prerror.h" +#include "prlog.h" +#include +#include + +/* + * On Win32, we map three kinds of error codes: + * - GetLastError(): for Win32 functions + * - WSAGetLastError(): for Winsock functions + * - errno: for standard C library functions + * + * GetLastError() and WSAGetLastError() return error codes in + * non-overlapping ranges, so their error codes (ERROR_* and + * WSAE*) can be mapped by the same function. On the other hand, + * errno and GetLastError() have overlapping ranges, so we need + * to use a separate function to map errno. + * + * We do not check for WSAEINPROGRESS and WSAEINTR because we do not + * use blocking Winsock 1.1 calls. + * + * Except for the 'socket' call, we do not check for WSAEINITIALISED. + * It is assumed that if Winsock is not initialized, that fact will + * be detected at the time we create new sockets. + */ + +static void _MD_win32_map_default_errno(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case EACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ENOENT: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_default_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case ERROR_ACCESS_DENIED: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case ERROR_ALREADY_EXISTS: + prError = PR_FILE_EXISTS_ERROR; + break; + case ERROR_DISK_CORRUPT: + prError = PR_IO_ERROR; + break; + case ERROR_DISK_FULL: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; + case ERROR_DISK_OPERATION_FAILED: + prError = PR_IO_ERROR; + break; + case ERROR_DRIVE_LOCKED: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case ERROR_FILENAME_EXCED_RANGE: + prError = PR_NAME_TOO_LONG_ERROR; + break; + case ERROR_FILE_CORRUPT: + prError = PR_IO_ERROR; + break; + case ERROR_FILE_EXISTS: + prError = PR_FILE_EXISTS_ERROR; + break; + case ERROR_FILE_INVALID: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case ERROR_FILE_NOT_FOUND: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ERROR_HANDLE_DISK_FULL: + prError = PR_NO_DEVICE_SPACE_ERROR; + break; + case ERROR_INVALID_ADDRESS: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_INVALID_HANDLE: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case ERROR_INVALID_NAME: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ERROR_INVALID_PARAMETER: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case ERROR_INVALID_USER_BUFFER: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_LOCKED: + prError = PR_FILE_IS_LOCKED_ERROR; + break; + case ERROR_NETNAME_DELETED: + prError = PR_CONNECT_RESET_ERROR; + break; + case ERROR_NOACCESS: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_NOT_ENOUGH_MEMORY: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_NOT_ENOUGH_QUOTA: + prError = PR_OUT_OF_MEMORY_ERROR; + break; + case ERROR_NOT_READY: + prError = PR_IO_ERROR; + break; + case ERROR_NO_MORE_FILES: + prError = PR_NO_MORE_FILES_ERROR; + break; + case ERROR_OPEN_FAILED: + prError = PR_IO_ERROR; + break; + case ERROR_OPEN_FILES: + prError = PR_IO_ERROR; + break; + case ERROR_OPERATION_ABORTED: + prError = PR_OPERATION_ABORTED_ERROR; + break; + case ERROR_OUTOFMEMORY: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case ERROR_PATH_BUSY: + prError = PR_IO_ERROR; + break; + case ERROR_PATH_NOT_FOUND: + prError = PR_FILE_NOT_FOUND_ERROR; + break; + case ERROR_SEEK_ON_DEVICE: + prError = PR_IO_ERROR; + break; + case ERROR_SHARING_VIOLATION: + prError = PR_FILE_IS_BUSY_ERROR; + break; + case ERROR_STACK_OVERFLOW: + prError = PR_ACCESS_FAULT_ERROR; + break; + case ERROR_TOO_MANY_OPEN_FILES: + prError = PR_SYS_DESC_TABLE_FULL_ERROR; + break; + case ERROR_WRITE_PROTECT: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case WSAEACCES: + prError = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case WSAEADDRINUSE: + prError = PR_ADDRESS_IN_USE_ERROR; + break; + case WSAEADDRNOTAVAIL: + prError = PR_ADDRESS_NOT_AVAILABLE_ERROR; + break; + case WSAEAFNOSUPPORT: + prError = PR_ADDRESS_NOT_SUPPORTED_ERROR; + break; + case WSAEALREADY: + prError = PR_ALREADY_INITIATED_ERROR; + break; + case WSAEBADF: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + case WSAECONNABORTED: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAECONNREFUSED: + prError = PR_CONNECT_REFUSED_ERROR; + break; + case WSAECONNRESET: + prError = PR_CONNECT_RESET_ERROR; + break; + case WSAEDESTADDRREQ: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAEFAULT: + prError = PR_ACCESS_FAULT_ERROR; + break; + case WSAEHOSTUNREACH: + prError = PR_HOST_UNREACHABLE_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAEISCONN: + prError = PR_IS_CONNECTED_ERROR; + break; + case WSAEMFILE: + prError = PR_PROC_DESC_TABLE_FULL_ERROR; + break; + case WSAEMSGSIZE: + prError = PR_BUFFER_OVERFLOW_ERROR; + break; + case WSAENETDOWN: + prError = PR_NETWORK_DOWN_ERROR; + break; + case WSAENETRESET: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAENETUNREACH: + prError = PR_NETWORK_UNREACHABLE_ERROR; + break; + case WSAENOBUFS: + prError = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case WSAENOPROTOOPT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAENOTCONN: + prError = PR_NOT_CONNECTED_ERROR; + break; + case WSAENOTSOCK: + prError = PR_NOT_SOCKET_ERROR; + break; + case WSAEOPNOTSUPP: + prError = PR_OPERATION_NOT_SUPPORTED_ERROR; + break; + case WSAEPROTONOSUPPORT: + prError = PR_PROTOCOL_NOT_SUPPORTED_ERROR; + break; + case WSAEPROTOTYPE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAESHUTDOWN: + prError = PR_SOCKET_SHUTDOWN_ERROR; + break; + case WSAESOCKTNOSUPPORT: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + case WSAETIMEDOUT: + prError = PR_CONNECT_ABORTED_ERROR; + break; + case WSAEWOULDBLOCK: + prError = PR_WOULD_BLOCK_ERROR; + break; + default: + prError = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_opendir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_closedir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_unix_readdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_delete_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* The error code for stat() is in errno. */ +void _MD_win32_map_stat_error(PRInt32 err) +{ + _MD_win32_map_default_errno(err); +} + +void _MD_win32_map_fstat_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_rename_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* The error code for access() is in errno. */ +void _MD_win32_map_access_error(PRInt32 err) +{ + _MD_win32_map_default_errno(err); +} + +void _MD_win32_map_mkdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_rmdir_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_read_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_transmitfile_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_write_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_lseek_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_fsync_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* + * For both CloseHandle() and closesocket(). + */ +void _MD_win32_map_close_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_socket_error(PRInt32 err) +{ + PR_ASSERT(err != WSANOTINITIALISED); + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_recv_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_recvfrom_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_send_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_sendto_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEMSGSIZE: + prError = PR_INVALID_ARGUMENT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_accept_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_acceptex_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_connect_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEWOULDBLOCK: + prError = PR_IN_PROGRESS_ERROR; + break; + case WSAEINVAL: + prError = PR_ALREADY_INITIATED_ERROR; + break; + case WSAETIMEDOUT: + prError = PR_IO_TIMEOUT_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_bind_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEINVAL: + prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_listen_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEOPNOTSUPP: + prError = PR_NOT_TCP_SOCKET_ERROR; + break; + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_shutdown_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_getsockname_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAEINVAL: + prError = PR_INVALID_STATE_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_getpeername_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_getsockopt_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_setsockopt_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_open_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +void _MD_win32_map_gethostname_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} + +/* Win32 select() only works on sockets. So in this +** context, WSAENOTSOCK is equivalent to EBADF on Unix. +*/ +void _MD_win32_map_select_error(PRInt32 err) +{ + PRErrorCode prError; + + switch (err) { + case WSAENOTSOCK: + prError = PR_BAD_DESCRIPTOR_ERROR; + break; + default: + _MD_win32_map_default_error(err); + return; + } + PR_SetError(prError, err); +} + +void _MD_win32_map_lockf_error(PRInt32 err) +{ + _MD_win32_map_default_error(err); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/memory/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/memory/Makefile.in new file mode 100644 index 00000000..6ba0ba78 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/Makefile.in @@ -0,0 +1,69 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = prseg.c prshm.c prshma.c + +ifdef GC_LEAK_DETECTOR +CSRCS += prgcleak.c +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +ifdef GC_LEAK_DETECTOR +INCLUDES += -I$(dist_includedir)/.. -I$(dist_includedir)/../boehm +endif + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/prgcleak.c b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prgcleak.c new file mode 100644 index 00000000..414b3851 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prgcleak.c @@ -0,0 +1,122 @@ +/* -*- 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): + * Patrick Beard + * + * 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 ***** */ + +/* + * prgcleak.c + */ + +#ifdef GC_LEAK_DETECTOR + +/* for FILE */ +#include + +/* NSPR stuff */ +#include "generic_threads.h" +#include "primpl.h" + +extern FILE *GC_stdout, *GC_stderr; + +extern void GC_gcollect(void); +extern void GC_clear_roots(void); + +static PRStatus PR_CALLBACK scanner(PRThread* t, void** baseAddr, + PRUword count, void* closure) +{ + if (count) { + char* begin = (char*)baseAddr; + char* end = (char*)(baseAddr + count); + GC_mark_range_proc marker = (GC_mark_range_proc) closure; + marker(begin, end); + } + return PR_SUCCESS; +} + +static void mark_all_stacks(GC_mark_range_proc marker) +{ + PR_ScanStackPointers(&scanner, (void *)marker); +} + +#if defined(_PR_PTHREADS) +#define _PR_MD_CURRENT_CPU() 1 +#endif + +static void locker(void* mutex) +{ + if (_PR_MD_CURRENT_CPU()) + PR_EnterMonitor(mutex); +} + +static void unlocker(void* mutex) +{ + if (_PR_MD_CURRENT_CPU()) + PR_ExitMonitor(mutex); +} + +static void stopper(void* unused) +{ + if (_PR_MD_CURRENT_CPU()) + PR_SuspendAll(); +} + +static void starter(void* unused) +{ + if (_PR_MD_CURRENT_CPU()) + PR_ResumeAll(); +} + +void _PR_InitGarbageCollector() +{ + void* mutex; + + /* redirect GC's stderr to catch startup leaks. */ + GC_stderr = fopen("StartupLeaks", "w"); + + mutex = PR_NewMonitor(); + PR_ASSERT(mutex != NULL); + + GC_generic_init_threads(&mark_all_stacks, mutex, + &locker, &unlocker, + &stopper, &starter); +} + +void _PR_ShutdownGarbageCollector() +{ + /* do anything you need to shut down the collector. */ +} + +#endif /* GC_LEAK_DETECTOR */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/prseg.c b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prseg.c new file mode 100644 index 00000000..14de6668 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prseg.c @@ -0,0 +1,93 @@ +/* -*- 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" + +#if defined(_PR_PTHREADS) + +/* +** The pthreads version doesn't use these functions. +*/ +void _PR_InitSegs(void) +{ +} + +#else /* _PR_PTHREADS */ + +void _PR_InitSegs(void) +{ + _PR_MD_INIT_SEGS(); +} + +/* +** Allocate a memory segment. The size value is rounded up to the native +** system page size and a page aligned portion of memory is returned. +** This memory is not part of the malloc heap. If "vaddr" is not NULL +** then PR tries to allocate the segment at the desired virtual address. +*/ +PRSegment* _PR_NewSegment(PRUint32 size, void *vaddr) +{ + PRSegment *seg; + + /* calloc the data structure for the segment */ + seg = PR_NEWZAP(PRSegment); + + if (seg) { + size = ((size + _pr_pageSize - 1) >> _pr_pageShift) << _pr_pageShift; + /* + ** Now, allocate the actual segment memory (or map under some OS) + ** The OS specific code decides from where or how to allocate memory. + */ + if (_PR_MD_ALLOC_SEGMENT(seg, size, vaddr) != PR_SUCCESS) { + PR_DELETE(seg); + return NULL; + } + } + + return seg; +} + +/* +** Free a memory segment. +*/ +void _PR_DestroySegment(PRSegment *seg) +{ + _PR_MD_FREE_SEGMENT(seg); + PR_DELETE(seg); +} + +#endif /* _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshm.c b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshm.c new file mode 100644 index 00000000..ac633952 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshm.c @@ -0,0 +1,156 @@ +/* -*- 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 ***** */ + +/* +** prshm.c -- NSPR Named Shared Memory +** +** lth. Jul-1999. +*/ +#include +#include "primpl.h" + +extern PRLogModuleInfo *_pr_shm_lm; + + +#if defined PR_HAVE_SYSV_NAMED_SHARED_MEMORY +/* SysV implementation is in pr/src/md/unix/uxshm.c */ +#elif defined PR_HAVE_POSIX_NAMED_SHARED_MEMORY +/* Posix implementation is in pr/src/md/unix/uxshm.c */ +#elif defined PR_HAVE_WIN32_NAMED_SHARED_MEMORY +/* Win32 implementation is in pr/src/md/windows/w32shm.c */ +#else +/* +** there is no named_shared_memory +*/ +extern PRSharedMemory* _MD_OpenSharedMemory( const char *name, PRSize size, PRIntn flags, PRIntn mode ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +extern void * _MD_AttachSharedMemory( PRSharedMemory *shm, PRIntn flags ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +extern PRStatus _MD_DetachSharedMemory( PRSharedMemory *shm, void *addr ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +extern PRStatus _MD_CloseSharedMemory( PRSharedMemory *shm ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +extern PRStatus _MD_DeleteSharedMemory( const char *name ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +#endif /* HAVE_SYSV_NAMED_SHARED_MEMORY */ + +/* +** FUNCTION: PR_OpenSharedMemory() +** +*/ +PR_IMPLEMENT( PRSharedMemory * ) + PR_OpenSharedMemory( + const char *name, + PRSize size, + PRIntn flags, + PRIntn mode +) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return( _PR_MD_OPEN_SHARED_MEMORY( name, size, flags, mode )); +} /* end PR_OpenSharedMemory() */ + +/* +** FUNCTION: PR_AttachSharedMemory() +** +*/ +PR_IMPLEMENT( void * ) + PR_AttachSharedMemory( + PRSharedMemory *shm, + PRIntn flags +) +{ + return( _PR_MD_ATTACH_SHARED_MEMORY( shm, flags )); +} /* end PR_AttachSharedMemory() */ + +/* +** FUNCTION: PR_DetachSharedMemory() +** +*/ +PR_IMPLEMENT( PRStatus ) + PR_DetachSharedMemory( + PRSharedMemory *shm, + void *addr +) +{ + return( _PR_MD_DETACH_SHARED_MEMORY( shm, addr )); +} /* end PR_DetachSharedMemory() */ + +/* +** FUNCTION: PR_CloseSharedMemory() +** +*/ +PR_IMPLEMENT( PRStatus ) + PR_CloseSharedMemory( + PRSharedMemory *shm +) +{ + return( _PR_MD_CLOSE_SHARED_MEMORY( shm )); +} /* end PR_CloseSharedMemory() */ + +/* +** FUNCTION: PR_DeleteSharedMemory() +** +*/ +PR_EXTERN( PRStatus ) + PR_DeleteSharedMemory( + const char *name +) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return(_PR_MD_DELETE_SHARED_MEMORY( name )); +} /* end PR_DestroySharedMemory() */ +/* end prshm.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshma.c b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshma.c new file mode 100644 index 00000000..fbc22578 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/memory/prshma.c @@ -0,0 +1,142 @@ +/* -*- 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 ***** */ + +/* +** prshma.h -- NSPR Anonymous Shared Memory +** +** +*/ + +#include "primpl.h" + +extern PRLogModuleInfo *_pr_shma_lm; + +#if defined(XP_UNIX) +/* defined in pr/src/md/unix/uxshm.c */ +#elif defined(WIN32) +/* defined in pr/src/md/windows/w32shm.c */ +#else +extern PRFileMap * _PR_MD_OPEN_ANON_FILE_MAP( const char *dirName, PRSize size, PRFileMapProtect prot ) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} +extern PRStatus _PR_MD_EXPORT_FILE_MAP_AS_STRING(PRFileMap *fm, PRSize bufSize, char *buf) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +extern PRFileMap * _PR_MD_IMPORT_FILE_MAP_FROM_STRING(const char *fmstring) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} +#endif + +/* +** PR_OpenAnonFileMap() -- Creates an anonymous file-mapped shared memory +** +*/ +PR_IMPLEMENT(PRFileMap*) +PR_OpenAnonFileMap( + const char *dirName, + PRSize size, + PRFileMapProtect prot +) +{ + return(_PR_MD_OPEN_ANON_FILE_MAP( dirName, size, prot )); +} /* end PR_OpenAnonFileMap() */ + +/* +** PR_ProcessAttrSetInheritableFileMap() -- Prepare FileMap for export +** to my children processes via PR_CreateProcess() +** +** +*/ +PR_IMPLEMENT( PRStatus) +PR_ProcessAttrSetInheritableFileMap( + PRProcessAttr *attr, + PRFileMap *fm, + const char *shmname +) +{ + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return( PR_FAILURE); +} /* end PR_ProcessAttrSetInheritableFileMap() */ + +/* +** PR_GetInheritedFileMap() -- Import a PRFileMap previously exported +** by my parent process via PR_CreateProcess() +** +*/ +PR_IMPLEMENT( PRFileMap *) +PR_GetInheritedFileMap( + const char *shmname +) +{ + PRFileMap *fm = NULL; + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); + return( fm ); +} /* end PR_GetInhteritedFileMap() */ + +/* +** PR_ExportFileMapAsString() -- Creates a string identifying a PRFileMap +** +*/ +PR_IMPLEMENT( PRStatus ) +PR_ExportFileMapAsString( + PRFileMap *fm, + PRSize bufSize, + char *buf +) +{ + return( _PR_MD_EXPORT_FILE_MAP_AS_STRING( fm, bufSize, buf )); +} /* end PR_ExportFileMapAsString() */ + +/* +** PR_ImportFileMapFromString() -- Creates a PRFileMap from the identifying string +** +** +*/ +PR_IMPLEMENT( PRFileMap * ) +PR_ImportFileMapFromString( + const char *fmstring +) +{ + return( _PR_MD_IMPORT_FILE_MAP_FROM_STRING(fmstring)); +} /* end PR_ImportFileMapFromString() */ +/* end prshma.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/misc/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/misc/Makefile.in new file mode 100644 index 00000000..2ac8e257 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/Makefile.in @@ -0,0 +1,107 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +CSRCS = \ + pralarm.c \ + pratom.c \ + prcountr.c \ + prdtoa.c \ + prenv.c \ + prerr.c \ + prerror.c \ + prerrortable.c \ + prinit.c \ + prinrval.c \ + pripc.c \ + prlog2.c \ + prlong.c \ + prnetdb.c \ + prolock.c \ + prrng.c \ + prsystem.c \ + prtime.c \ + prthinfo.c \ + prtpool.c \ + prtrace.c \ + $(NULL) + +ifndef USE_PTHREADS +CSRCS += \ + pripcsem.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +RELEASE_BINS = $(srcdir)/compile-et.pl $(srcdir)/prerr.properties + +include $(topsrcdir)/config/rules.mk + +# Prevent floating point errors caused by MSVC 6.0 Processor Pack +# optimizations (bug 207421). This disables optimizations that +# could change the precision of floating-point calculations for +# this single compilation unit. +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) +$(OBJDIR)/prdtoa.$(OBJ_SUFFIX): prdtoa.c + @$(MAKE_OBJDIR) + $(CC) -Fo$@ -c $(CFLAGS) -Op $(call abspath,$<) +endif + +# +# Generate prerr.h, prerr.c, and prerr.properties from prerr.et. +# +build_prerr: + cd $(srcdir); $(PERL) compile-et.pl prerr.et + +export:: $(TARGETS) + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/compile-et.pl b/src/libs/xpcom18a4/nsprpub/pr/src/misc/compile-et.pl new file mode 100755 index 00000000..9f0d90bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/compile-et.pl @@ -0,0 +1,140 @@ +#!/usr/bin/perl + +# usage: compile-et input.et + +# +# ***** 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 ***** + +sub header +{ + local($filename, $comment) = @_; + +< 0x7fffff); + $base*256; +} + +sub code { + local($macro, $text) = @_; + $code = $table_base + $table_item_count; + + print H "\n"; + print H "/* ", $text, " */\n"; + printf H "#define %-40s (%dL)\n", $macro, $code; + + print C "\t{\"", $macro, "\", \"", $text, "\"},\n"; + + print PROPERTIES $macro, "=", $text, "\n"; + + $table_item_count++; +} + + +$filename = $ARGV[0]; +open(INPUT, "< $filename") || die "Can't read $filename: $!\n"; + +$base = "$filename"; +$base =~ s/\.et$//; +$base =~ s#.*/##; + +open(H, "> ${base}.h") || die "Can't write ${base}.h\n"; +open(C, "> ${base}.c") || die "Can't write ${base}.c\n"; +open(PROPERTIES, "> ${base}.properties") || die "Can't write ${base}.properties\n"; + +print H "/*\n", &header("${base}.h", " *"), " */\n"; +print C "/*\n", &header("${base}.c", " *"), " */\n"; +print PROPERTIES &header("${base}.properties", "#"); + +$skipone = 0; + +while ($_ = ) { + next if /^#/; + + if (/^[ \t]*(error_table|et)[ \t]+([a-zA-Z][a-zA-Z0-9_]+) *(-?[0-9]*)/) { + $table_name = $2; + if ($3) { + $table_base = $3; + } + else { + $table_base = &table_base($table_name); + } + $table_item_count = 0; + + print C "#include \"prerror.h\"\n"; + print C "static const struct PRErrorMessage text[] = {\n"; + } + elsif (/^[ \t]*(error_code|ec)[ \t]+([A-Z_0-9]+),[ \t]*$/) { + $skipone = 1; + $macro = $2; + } + elsif (/^[ \t]*(error_code|ec)[ \t]+([A-Z_0-9]+),[ \t]*"(.*)"[ \t]*$/) { + &code($2, $3); + } + elsif ($skipone && /^[ \t]*"(.*)"[ \t]*$/) { + &code($macro, $1); + } +} + +print H "\n"; +print H "extern void ", $table_name, "_InitializePRErrorTable","(void);\n"; +printf H "#define ERROR_TABLE_BASE_%s (%dL)\n", $table_name, $table_base; + +print C "\t{0, 0}\n"; +print C "};\n\n"; +printf C "static const struct PRErrorTable et = { text, \"%s\", %dL, %d };\n", + $base, $table_base, $table_item_count; +print C "\n"; +print C "void ", $table_name, "_InitializePRErrorTable", "(void) {\n"; +print C " PR_ErrorInstallTable(&et);\n"; +print C "}\n"; + +0; diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/pralarm.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pralarm.c new file mode 100644 index 00000000..9323bab6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pralarm.c @@ -0,0 +1,282 @@ +/* -*- 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" + +/**********************************************************************/ +/******************************* PRALARM ******************************/ +/**********************************************************************/ + +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif + +struct PRAlarmID { /* typedef'd in pralarm.h */ + PRCList list; /* circular list linkage */ + PRAlarm *alarm; /* back pointer to owning alarm */ + PRPeriodicAlarmFn function; /* function to call for notify */ + void *clientData; /* opaque client context */ + PRIntervalTime period; /* the client defined period */ + PRUint32 rate; /* rate of notification */ + + PRUint32 accumulator; /* keeps track of # notifies */ + PRIntervalTime epoch; /* when timer was started */ + PRIntervalTime nextNotify; /* when we'll next do our thing */ + PRIntervalTime lastNotify; /* when we last did our thing */ +}; + +typedef enum {alarm_active, alarm_inactive} _AlarmState; + +struct PRAlarm { /* typedef'd in pralarm.h */ + PRCList timers; /* base of alarm ids list */ + PRLock *lock; /* lock used to protect data */ + PRCondVar *cond; /* condition that used to wait */ + PRThread *notifier; /* thread to deliver notifies */ + PRAlarmID *current; /* current alarm being served */ + _AlarmState state; /* used to delete the alarm */ +}; + +static PRAlarmID *pr_getNextAlarm(PRAlarm *alarm, PRAlarmID *id) +{ +/* + * Puts 'id' back into the sorted list iff it's not NULL. + * Removes the first element from the list and returns it (or NULL). + * List is "assumed" to be short. + * + * NB: Caller is providing locking + */ + PRCList *timer; + PRAlarmID *result = id; + PRIntervalTime now = PR_IntervalNow(); + + if (!PR_CLIST_IS_EMPTY(&alarm->timers)) + { + if (id != NULL) /* have to put this id back in */ + { + PRIntervalTime idDelta = now - id->nextNotify; + timer = alarm->timers.next; + do + { + result = (PRAlarmID*)timer; + if ((PRIntervalTime)(now - result->nextNotify) > idDelta) + { + PR_INSERT_BEFORE(&id->list, &alarm->timers); + break; + } + timer = timer->next; + } while (timer != &alarm->timers); + } + result = (PRAlarmID*)(timer = PR_LIST_HEAD(&alarm->timers)); + PR_REMOVE_LINK(timer); /* remove it from the list */ + } + + return result; +} /* pr_getNextAlarm */ + +static PRIntervalTime pr_PredictNextNotifyTime(PRAlarmID *id) +{ + PRIntervalTime delta; + PRFloat64 baseRate = (PRFloat64)id->period / (PRFloat64)id->rate; + PRFloat64 offsetFromEpoch = (PRFloat64)id->accumulator * baseRate; + + id->accumulator += 1; /* every call advances to next period */ + id->lastNotify = id->nextNotify; /* just keeping track of things */ + id->nextNotify = (PRIntervalTime)(offsetFromEpoch + 0.5); + + delta = id->nextNotify - id->lastNotify; + return delta; +} /* pr_PredictNextNotifyTime */ + +static void PR_CALLBACK pr_alarmNotifier(void *arg) +{ + /* + * This is the root of the notifier thread. There is one such thread + * for each PRAlarm. It may service an arbitrary (though assumed to be + * small) number of alarms using the same thread and structure. It + * continues to run until the alarm is destroyed. + */ + PRAlarmID *id = NULL; + PRAlarm *alarm = (PRAlarm*)arg; + enum {notify, abort, scan} why = scan; + + while (why != abort) + { + PRIntervalTime pause; + + PR_Lock(alarm->lock); + while (why == scan) + { + alarm->current = NULL; /* reset current id */ + if (alarm->state == alarm_inactive) why = abort; /* we're toast */ + else if (why == scan) /* the dominant case */ + { + id = pr_getNextAlarm(alarm, id); /* even if it's the same */ + if (id == NULL) /* there are no alarms set */ + (void)PR_WaitCondVar(alarm->cond, PR_INTERVAL_NO_TIMEOUT); + else + { + pause = id->nextNotify - (PR_IntervalNow() - id->epoch); + if ((PRInt32)pause <= 0) /* is this one's time up? */ + { + why = notify; /* set up to do our thing */ + alarm->current = id; /* id we're about to schedule */ + } + else + (void)PR_WaitCondVar(alarm->cond, pause); /* dally */ + } + } + } + PR_Unlock(alarm->lock); + + if (why == notify) + { + (void)pr_PredictNextNotifyTime(id); + if (!id->function(id, id->clientData, ~pause)) + { + /* + * Notified function decided not to continue. Free + * the alarm id to make sure it doesn't get back on + * the list. + */ + PR_DELETE(id); /* free notifier object */ + id = NULL; /* so it doesn't get back into the list */ + } + why = scan; /* so we can cycle through the loop again */ + } + } + +} /* pr_alarm_notifier */ + +PR_IMPLEMENT(PRAlarm*) PR_CreateAlarm(void) +{ + PRAlarm *alarm = PR_NEWZAP(PRAlarm); + if (alarm != NULL) + { + if ((alarm->lock = PR_NewLock()) == NULL) goto done; + if ((alarm->cond = PR_NewCondVar(alarm->lock)) == NULL) goto done; + alarm->state = alarm_active; + PR_INIT_CLIST(&alarm->timers); + alarm->notifier = PR_CreateThread( + PR_USER_THREAD, pr_alarmNotifier, alarm, + PR_GetThreadPriority(PR_GetCurrentThread()), + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (alarm->notifier == NULL) goto done; + } + return alarm; + +done: + if (alarm->cond != NULL) PR_DestroyCondVar(alarm->cond); + if (alarm->lock != NULL) PR_DestroyLock(alarm->lock); + PR_DELETE(alarm); + return NULL; +} /* CreateAlarm */ + +PR_IMPLEMENT(PRStatus) PR_DestroyAlarm(PRAlarm *alarm) +{ + PRStatus rv; + + PR_Lock(alarm->lock); + alarm->state = alarm_inactive; + rv = PR_NotifyCondVar(alarm->cond); + PR_Unlock(alarm->lock); + + if (rv == PR_SUCCESS) + rv = PR_JoinThread(alarm->notifier); + if (rv == PR_SUCCESS) + { + PR_DestroyCondVar(alarm->cond); + PR_DestroyLock(alarm->lock); + PR_DELETE(alarm); + } + return rv; +} /* PR_DestroyAlarm */ + +PR_IMPLEMENT(PRAlarmID*) PR_SetAlarm( + PRAlarm *alarm, PRIntervalTime period, PRUint32 rate, + PRPeriodicAlarmFn function, void *clientData) +{ + /* + * Create a new periodic alarm an existing current structure. + * Set up the context and compute the first notify time (immediate). + * Link the new ID into the head of the list (since it's notifying + * immediately). + */ + + PRAlarmID *id = PR_NEWZAP(PRAlarmID); + + if (!id) + return NULL; + + id->alarm = alarm; + PR_INIT_CLIST(&id->list); + id->function = function; + id->clientData = clientData; + id->period = period; + id->rate = rate; + id->epoch = id->nextNotify = PR_IntervalNow(); + (void)pr_PredictNextNotifyTime(id); + + PR_Lock(alarm->lock); + PR_INSERT_BEFORE(&id->list, &alarm->timers); + PR_NotifyCondVar(alarm->cond); + PR_Unlock(alarm->lock); + + return id; +} /* PR_SetAlarm */ + +PR_IMPLEMENT(PRStatus) PR_ResetAlarm( + PRAlarmID *id, PRIntervalTime period, PRUint32 rate) +{ + /* + * Can only be called from within the notify routine. Doesn't + * need locking because it can only be called from within the + * notify routine. + */ + if (id != id->alarm->current) + return PR_FAILURE; + id->period = period; + id->rate = rate; + id->accumulator = 1; + id->epoch = PR_IntervalNow(); + (void)pr_PredictNextNotifyTime(id); + return PR_SUCCESS; +} /* PR_ResetAlarm */ + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/pratom.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pratom.c new file mode 100644 index 00000000..24028e56 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pratom.c @@ -0,0 +1,409 @@ +/* -*- 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 ***** */ + +/* +** PR Atomic operations +*/ + + +#include "pratom.h" +#include "primpl.h" + +#include + +/* + * The following is a fallback implementation that emulates + * atomic operations for platforms without atomic operations. + * If a platform has atomic operations, it should define the + * macro _PR_HAVE_ATOMIC_OPS, and the following will not be + * compiled in. + */ + +#if !defined(_PR_HAVE_ATOMIC_OPS) + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +/* + * PR_AtomicDecrement() is used in NSPR's thread-specific data + * destructor. Because thread-specific data destructors may be + * invoked after a PR_Cleanup() call, we need an implementation + * of the atomic routines that doesn't need NSPR to be initialized. + */ + +/* + * We use a set of locks for all the emulated atomic operations. + * By hashing on the address of the integer to be locked the + * contention between multiple threads should be lessened. + * + * The number of atomic locks can be set by the environment variable + * NSPR_ATOMIC_HASH_LOCKS + */ + +/* + * lock counts should be a power of 2 + */ +#define DEFAULT_ATOMIC_LOCKS 16 /* should be in sync with the number of initializers + below */ +#define MAX_ATOMIC_LOCKS (4 * 1024) + +static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = { + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; + +#ifdef DEBUG +static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS]; +static PRInt32 *hash_lock_counts = static_hash_lock_counts; +#endif + +static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS; +static pthread_mutex_t *atomic_locks = static_atomic_locks; +static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1; + +#define _PR_HASH_FOR_LOCK(ptr) \ + ((PRUint32) (((PRUptrdiff) (ptr) >> 2) ^ \ + ((PRUptrdiff) (ptr) >> 8)) & \ + atomic_hash_mask) + +void _PR_MD_INIT_ATOMIC() +{ +char *eval; +int index; + + + PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) == + PR_CeilingLog2(MAX_ATOMIC_LOCKS)); + + PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) == + PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS)); + + if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL) && + ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) { + + if (num_atomic_locks > MAX_ATOMIC_LOCKS) + num_atomic_locks = MAX_ATOMIC_LOCKS; + else { + num_atomic_locks = PR_FloorLog2(num_atomic_locks); + num_atomic_locks = 1L << num_atomic_locks; + } + atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) * + num_atomic_locks); + if (atomic_locks) { + for (index = 0; index < num_atomic_locks; index++) { + if (pthread_mutex_init(&atomic_locks[index], NULL)) { + PR_DELETE(atomic_locks); + atomic_locks = NULL; + break; + } + } + } +#ifdef DEBUG + if (atomic_locks) { + hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32)); + if (hash_lock_counts == NULL) { + PR_DELETE(atomic_locks); + atomic_locks = NULL; + } + } +#endif + if (atomic_locks == NULL) { + /* + * Use statically allocated locks + */ + atomic_locks = static_atomic_locks; + num_atomic_locks = DEFAULT_ATOMIC_LOCKS; + #ifdef DEBUG + hash_lock_counts = static_hash_lock_counts; + #endif + } + atomic_hash_mask = num_atomic_locks - 1; + } + PR_ASSERT(PR_FloorLog2(num_atomic_locks) == + PR_CeilingLog2(num_atomic_locks)); +} + +PRInt32 +_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = ++(*val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(ptr); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = ((*ptr) += val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = --(*val); +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + PRInt32 idx = _PR_HASH_FOR_LOCK(val); + + pthread_mutex_lock(&atomic_locks[idx]); + rv = *val; + *val = newval; +#ifdef DEBUG + hash_lock_counts[idx]++; +#endif + pthread_mutex_unlock(&atomic_locks[idx]); + return rv; +} +#else /* _PR_PTHREADS && !_PR_DCETHREADS */ +/* + * We use a single lock for all the emulated atomic operations. + * The lock contention should be acceptable. + */ +static PRLock *atomic_lock = NULL; +void _PR_MD_INIT_ATOMIC(void) +{ + if (atomic_lock == NULL) { + atomic_lock = PR_NewLock(); + } +} + +PRInt32 +_PR_MD_ATOMIC_INCREMENT(PRInt32 *val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = ++(*val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = ((*ptr) += val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_DECREMENT(PRInt32 *val) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = --(*val); + PR_Unlock(atomic_lock); + return rv; +} + +PRInt32 +_PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) +{ + PRInt32 rv; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + PR_Lock(atomic_lock); + rv = *val; + *val = newval; + PR_Unlock(atomic_lock); + return rv; +} +#endif /* _PR_PTHREADS && !_PR_DCETHREADS */ + +#endif /* !_PR_HAVE_ATOMIC_OPS */ + +void _PR_InitAtomic(void) +{ + _PR_MD_INIT_ATOMIC(); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicIncrement(PRInt32 *val) +{ + return _PR_MD_ATOMIC_INCREMENT(val); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicDecrement(PRInt32 *val) +{ + return _PR_MD_ATOMIC_DECREMENT(val); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicSet(PRInt32 *val, PRInt32 newval) +{ + return _PR_MD_ATOMIC_SET(val, newval); +} + +PR_IMPLEMENT(PRInt32) +PR_AtomicAdd(PRInt32 *ptr, PRInt32 val) +{ + return _PR_MD_ATOMIC_ADD(ptr, val); +} +/* + * For platforms, which don't support the CAS (compare-and-swap) instruction + * (or an equivalent), the stack operations are implemented by use of PRLock + */ + +PR_IMPLEMENT(PRStack *) +PR_CreateStack(const char *stack_name) +{ +PRStack *stack; + + if (!_pr_initialized) { + _PR_ImplicitInitialization(); + } + + if ((stack = PR_NEW(PRStack)) == NULL) { + return NULL; + } + if (stack_name) { + stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1); + if (stack->prstk_name == NULL) { + PR_DELETE(stack); + return NULL; + } + strcpy(stack->prstk_name, stack_name); + } else + stack->prstk_name = NULL; + +#ifndef _PR_HAVE_ATOMIC_CAS + stack->prstk_lock = PR_NewLock(); + if (stack->prstk_lock == NULL) { + PR_Free(stack->prstk_name); + PR_DELETE(stack); + return NULL; + } +#endif /* !_PR_HAVE_ATOMIC_CAS */ + + stack->prstk_head.prstk_elem_next = NULL; + + return stack; +} + +PR_IMPLEMENT(PRStatus) +PR_DestroyStack(PRStack *stack) +{ + if (stack->prstk_head.prstk_elem_next != NULL) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return PR_FAILURE; + } + + if (stack->prstk_name) + PR_Free(stack->prstk_name); +#ifndef _PR_HAVE_ATOMIC_CAS + PR_DestroyLock(stack->prstk_lock); +#endif /* !_PR_HAVE_ATOMIC_CAS */ + PR_DELETE(stack); + + return PR_SUCCESS; +} + +#ifndef _PR_HAVE_ATOMIC_CAS + +PR_IMPLEMENT(void) +PR_StackPush(PRStack *stack, PRStackElem *stack_elem) +{ + PR_Lock(stack->prstk_lock); + stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next; + stack->prstk_head.prstk_elem_next = stack_elem; + PR_Unlock(stack->prstk_lock); + return; +} + +PR_IMPLEMENT(PRStackElem *) +PR_StackPop(PRStack *stack) +{ +PRStackElem *element; + + PR_Lock(stack->prstk_lock); + element = stack->prstk_head.prstk_elem_next; + if (element != NULL) { + stack->prstk_head.prstk_elem_next = element->prstk_elem_next; + element->prstk_elem_next = NULL; /* debugging aid */ + } + PR_Unlock(stack->prstk_lock); + return element; +} +#endif /* !_PR_HAVE_ATOMIC_CAS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prcountr.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prcountr.c new file mode 100644 index 00000000..a4e4f6cc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prcountr.c @@ -0,0 +1,506 @@ +/* -*- 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 ***** */ + +/* +** prcountr.c -- NSPR Instrumentation Counters +** +** Implement the interface defined in prcountr.h +** +** Design Notes: +** +** The Counter Facility (CF) has a single anchor: qNameList. +** The anchor is a PRCList. qNameList is a list of links in QName +** structures. From qNameList any QName structure and its +** associated RName structure can be located. +** +** For each QName, a list of RName structures is anchored at +** rnLink in the QName structure. +** +** The counter itself is embedded in the RName structure. +** +** For manipulating the counter database, single lock is used to +** protect the entire list: counterLock. +** +** A PRCounterHandle, defined in prcountr.h, is really a pointer +** to a RName structure. References by PRCounterHandle are +** dead-reconed to the RName structure. The PRCounterHandle is +** "overloaded" for traversing the QName structures; only the +** function PR_FindNextQnameHandle() uses this overloading. +** +** +** ToDo (lth): decide on how to lock or atomically update +** individual counters. Candidates are: the global lock; a lock +** per RName structure; Atomic operations (Note that there are +** not adaquate atomic operations (yet) to achieve this goal). At +** this writing (6/19/98) , the update of the counter variable in +** a QName structure is unprotected. +** +*/ + +#include "prcountr.h" +#include "prclist.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include + +/* +** +*/ +typedef struct QName +{ + PRCList link; + PRCList rNameList; + char name[PRCOUNTER_NAME_MAX+1]; +} QName; + +/* +** +*/ +typedef struct RName +{ + PRCList link; + QName *qName; + PRLock *lock; + volatile PRUint32 counter; + char name[PRCOUNTER_NAME_MAX+1]; + char desc[PRCOUNTER_DESC_MAX+1]; +} RName; + + +/* +** Define the Counter Facility database +*/ +static PRLock *counterLock; +static PRCList qNameList; +static PRLogModuleInfo *lm; + +/* +** _PR_CounterInitialize() -- Initialize the Counter Facility +** +*/ +static void _PR_CounterInitialize( void ) +{ + /* + ** This function should be called only once + */ + PR_ASSERT( counterLock == NULL ); + + counterLock = PR_NewLock(); + PR_INIT_CLIST( &qNameList ); + lm = PR_NewLogModule("counters"); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Initialization complete")); + + return; +} /* end _PR_CounterInitialize() */ + +/* +** PR_CreateCounter() -- Create a counter +** +** ValidateArguments +** Lock +** if (qName not already in database) +** NewQname +** if (rName already in database ) +** Assert +** else NewRname +** NewCounter +** link 'em up +** Unlock +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_CreateCounter( + const char *qName, + const char *rName, + const char *description +) +{ + QName *qnp; + RName *rnp; + PRBool matchQname = PR_FALSE; + + /* Self initialize, if necessary */ + if ( counterLock == NULL ) + _PR_CounterInitialize(); + + /* Validate input arguments */ + PR_ASSERT( strlen(qName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(rName) <= PRCOUNTER_NAME_MAX ); + PR_ASSERT( strlen(description) <= PRCOUNTER_DESC_MAX ); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* Do we already have a matching QName? */ + if (!PR_CLIST_IS_EMPTY( &qNameList )) + { + qnp = (QName *) PR_LIST_HEAD( &qNameList ); + do { + if ( strcmp(qnp->name, qName) == 0) + { + matchQname = PR_TRUE; + break; + } + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + } while( qnp != (QName *)PR_LIST_HEAD( &qNameList )); + } + /* + ** If we did not find a matching QName, + ** allocate one and initialize it. + ** link it onto the qNameList. + ** + */ + if ( matchQname != PR_TRUE ) + { + qnp = PR_NEWZAP( QName ); + PR_ASSERT( qnp != NULL ); + PR_INIT_CLIST( &qnp->link ); + PR_INIT_CLIST( &qnp->rNameList ); + strcpy( qnp->name, qName ); + PR_APPEND_LINK( &qnp->link, &qNameList ); + } + + /* Do we already have a matching RName? */ + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) + { + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); + do { + /* + ** No duplicate RNames are allowed within a QName + ** + */ + PR_ASSERT( strcmp(rnp->name, rName)); + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList )); + } + + /* Get a new RName structure; initialize its members */ + rnp = PR_NEWZAP( RName ); + PR_ASSERT( rnp != NULL ); + PR_INIT_CLIST( &rnp->link ); + strcpy( rnp->name, rName ); + strcpy( rnp->desc, description ); + rnp->lock = PR_NewLock(); + if ( rnp->lock == NULL ) + { + PR_ASSERT(0); + } + + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ + rnp->qName = qnp; /* point the RName to the QName */ + + /* Unlock the Facility */ + PR_Unlock( counterLock ); + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Create: QName: %s %p, RName: %s %p\n\t", + qName, qnp, rName, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_CreateCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DestroyCounter( + PRCounterHandle handle +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting: QName: %s, RName: %s", + qnp->name, rnp->name)); + + /* Lock the Facility */ + PR_Lock( counterLock ); + + /* + ** Remove RName from the list of RNames in QName + ** and free RName + */ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting RName: %s, %p", + rnp->name, rnp)); + PR_REMOVE_LINK( &rnp->link ); + PR_Free( rnp->lock ); + PR_DELETE( rnp ); + + /* + ** If this is the last RName within QName + ** remove QName from the qNameList and free it + */ + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) + { + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Deleting unused QName: %s, %p", + qnp->name, qnp)); + PR_REMOVE_LINK( &qnp->link ); + PR_DELETE( qnp ); + } + + /* Unlock the Facility */ + PR_Unlock( counterLock ); + return; +} /* end PR_DestroyCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_GetCounterHandleFromName( + const char *qName, + const char *rName +) +{ + const char *qn, *rn, *desc; + PRCounterHandle qh, rh = NULL; + RName *rnp = NULL; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounterHandleFromName:\n\t" + "QName: %s, RName: %s", qName, rName )); + + qh = PR_FindNextCounterQname( NULL ); + while (qh != NULL) + { + rh = PR_FindNextCounterRname( NULL, qh ); + while ( rh != NULL ) + { + PR_GetCounterNameFromHandle( rh, &qn, &rn, &desc ); + if ( (strcmp( qName, qn ) == 0) + && (strcmp( rName, rn ) == 0 )) + { + rnp = (RName *)rh; + goto foundIt; + } + rh = PR_FindNextCounterRname( rh, qh ); + } + qh = PR_FindNextCounterQname( NULL ); + } + +foundIt: + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); + return(rh); +} /* end PR_GetCounterHandleFromName() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetCounterNameFromHandle( + PRCounterHandle handle, + const char **qName, + const char **rName, + const char **description +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + *qName = qnp->name; + *rName = rnp->name; + *description = rnp->desc; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterNameFromHandle: " + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", + qnp, rnp, qnp->name, rnp->name, rnp->desc )); + + return; +} /* end PR_GetCounterNameFromHandle() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_IncrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter++; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Increment: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_IncrementCounter() */ + + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DecrementCounter( + PRCounterHandle handle +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter--; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: Decrement: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_DecrementCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_AddToCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter += value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: AddToCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_AddToCounter() */ + + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SubtractFromCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + PR_Lock(((RName *)handle)->lock); + ((RName *)handle)->counter -= value; + PR_Unlock(((RName *)handle)->lock); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SubtractFromCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SubtractFromCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRUint32) + PR_GetCounter( + PRCounterHandle handle +) +{ + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return(((RName *)handle)->counter); +} /* end PR_GetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SetCounter( + PRCounterHandle handle, + PRUint32 value +) +{ + ((RName *)handle)->counter = value; + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: SetCounter: %p, %ld", + handle, ((RName *)handle)->counter )); + + return; +} /* end PR_SetCounter() */ + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterQname( + PRCounterHandle handle +) +{ + QName *qnp = (QName *)handle; + + if ( PR_CLIST_IS_EMPTY( &qNameList )) + qnp = NULL; + else if ( qnp == NULL ) + qnp = (QName *)PR_LIST_HEAD( &qNameList ); + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) + qnp = NULL; + else + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextQname: Handle: %p, Returns: %p", + handle, qnp )); + + return((PRCounterHandle)qnp); +} /* end PR_FindNextCounterQname() */ + + +/* +** +*/ +PR_IMPLEMENT(PRCounterHandle) + PR_FindNextCounterRname( + PRCounterHandle rhandle, + PRCounterHandle qhandle +) +{ + RName *rnp = (RName *)rhandle; + QName *qnp = (QName *)qhandle; + + + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) + rnp = NULL; + else if ( rnp == NULL ) + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) + rnp = NULL; + else + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", + rhandle, qhandle, rnp )); + + return((PRCounterHandle)rnp); +} /* end PR_FindNextCounterRname() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prdtoa.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prdtoa.c new file mode 100644 index 00000000..13e03853 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prdtoa.c @@ -0,0 +1,3519 @@ +/* -*- 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" + +#define MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) PR_Lock(dtoa_lock[n]) +#define FREE_DTOA_LOCK(n) PR_Unlock(dtoa_lock[n]) + +static PRLock *dtoa_lock[2]; + +void _PR_InitDtoa(void) +{ + dtoa_lock[0] = PR_NewLock(); + dtoa_lock[1] = PR_NewLock(); +} + +void _PR_CleanupDtoa(void) +{ + PR_DestroyLock(dtoa_lock[0]); + dtoa_lock[0] = NULL; + PR_DestroyLock(dtoa_lock[1]); + dtoa_lock[1] = NULL; + + /* FIXME: deal with freelist and p5s. */ +} + +#if defined(__arm) || defined(__arm__) || defined(__arm26__) \ + || defined(__arm32__) +#define IEEE_ARM +#elif defined(IS_LITTLE_ENDIAN) +#define IEEE_8087 +#else +#define IEEE_MC68k +#endif + +#define Long PRInt32 +#define ULong PRUint32 +#define NO_LONG_LONG + +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define IEEE_ARM for IEEE-arithmetic machines where the two words + * in a double are stored in big endian order but the two shorts + * in a word are still stored in little endian order. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define INFNAN_CHECK on IEEE systems to cause strtod to check for + * Infinity and NaN (case insensitively). On some systems (e.g., + * some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define YES_ALIAS to permit aliasing certain double values with + * arrays of ULongs. This leads to slightly better code with + * some compilers and was always used prior to 19990916, but it + * is not strictly legal and can cause trouble with aggressively + * optimizing compilers (e.g., gcc 2.95.1 under -O2). + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + */ + +#ifndef Long +#define Long long +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +# ifdef VBOX_USE_IPRT_IN_NSPR +# include +# define MALLOC RTMemAlloc +# else +#define MALLOC malloc +# endif +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif +#ifdef IEEE_ARM +#define IEEE_Arith +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +/* + * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function + * which does not exist on 10.1. We can safely #define it to 1 here + * to allow 10.2 builds to run on 10.1, since we can't use fesetround() + * (which does not exist on 10.1 either). + */ +#if defined(MACOS_DEPLOYMENT_TARGET) && (MACOS_DEPLOYMENT_TARGET < 100200) +#undef FLT_ROUNDS +#define FLT_ROUNDS 1 +#endif +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, IEEE_ARM, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef YES_ALIAS +#define dval(x) x +#ifdef IEEE_8087 +#define word0(x) ((ULong *)&x)[1] +#define word1(x) ((ULong *)&x)[0] +#else +#define word0(x) ((ULong *)&x)[0] +#define word1(x) ((ULong *)&x)[1] +#endif +#else +#ifdef IEEE_8087 +#define word0(x) ((U*)&x)->L[1] +#define word1(x) ((U*)&x)->L[0] +#else +#define word0(x) ((U*)&x)->L[0] +#define word1(x) ((U*)&x)->L[1] +#endif +#define dval(x) ((U*)&x)->d +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(IEEE_ARM) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 15 + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif + + ACQUIRE_DTOA_LOCK(0); + if (rv = freelist[k]) { + freelist[k] = rv->next; + } + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9; +#else + (CONST char *s, int nd0, int nd, ULong y9) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s++; + } + else + s += 10; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) register ULong x; +#else + (register ULong x) +#endif +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + if (i = k & 3) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + if (!(p5 = p5s)) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p5 = p5s)) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + if (!(p51 = p5->next)) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + if (!(p51 = p5->next)) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) double x; +#else + (double x) +#endif +{ + register Long L; + double a; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + double d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> Ebits - k; + w = xa > xa0 ? *--xa : 0; + d1 = y << (32-Ebits) + k | w >> Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> 32 - k; + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> 32 - k; + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) double d; int *e, *bits; +#else + (double d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if (de = (int)(d0 >> Exp_shift)) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if (y = d1) { + if (k = lo0bits(&y)) { + x[0] = y | z << 32 - k; + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + double da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#ifndef IEEE_Arith +#undef INFNAN_CHECK +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (CONST char **sp, char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + while(d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) double *rvp; CONST char **sp; +#else + (double *rvp, CONST char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + while(c = *(CONST unsigned char*)++s) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + + PR_IMPLEMENT(double) +PR_strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (CONST char *s00, char **se) +#endif +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1, adj, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + CONST char *s2; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + sign = nz0 = nz = 0; + dval(rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv = -rv; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if (i = e1 & 15) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: +#ifndef NO_ERRNO + PR_SetError(PR_RANGE_ERROR, 0); +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if (i = e1 & 15) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << j-32; + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { + undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + PR_SetError(PR_RANGE_ERROR, 0); +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(dval(rv)); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(dval(rv)); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(dval(rv)); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(dval(rv)); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = aadj1 = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(Rounding) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (Flt_Rounds == 0) + aadj1 += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = aadj) <= 0) + z = 1; + aadj = z; + aadj1 = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 + && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!dsign) + aadj1 = -aadj1; + } + adj = aadj1 * ulp(dval(rv)); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + PR_SetError(PR_RANGE_ERROR, 0); +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif + retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); + ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + while(*t = *s++) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + static char * +dtoa +#ifdef KR_headers + (d, mode, ndigits, decpt, sign, rve) + double d; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double d, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo, *mhi, *S; + double d2, ds, eps; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(dval(d), &be, &bbits); +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32 + : word1(d) << 32 - i; + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + switch(mode) { + case 0: + case 1: + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if (j1 = -k) { + dval(d) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for(i = 0;;) { + L = dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while(*--s == '0'); + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || dval(d) == ds && L & 1) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + if (j = b5 - m5) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) + i = 32 - i; +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + ) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || j1 == 0 && dig & 1) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || j == 0 && dig & 1) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { + trimzeros: + while(*--s == '0'); + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } +#ifdef __cplusplus +} +#endif + +PR_IMPLEMENT(PRStatus) +PR_dtoa(PRFloat64 d, PRIntn mode, PRIntn ndigits, + PRIntn *decpt, PRIntn *sign, char **rve, char *buf, PRSize bufsize) +{ + char *result; + PRSize resultlen; + PRStatus rv = PR_FAILURE; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (mode < 0 || mode > 3) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + result = dtoa(d, mode, ndigits, decpt, sign, rve); + if (!result) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + resultlen = strlen(result)+1; + if (bufsize < resultlen) { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + } else { + memcpy(buf, result, resultlen); + if (rve) { + *rve = buf + (*rve - result); + } + rv = PR_SUCCESS; + } + freedtoa(result); + return rv; +} + +/* +** conversion routines for floating point +** prcsn - number of digits of precision to generate floating +** point value. +** This should be reparameterized so that you can send in a +** prcn for the positive and negative ranges. For now, +** conform to the ECMA JavaScript spec which says numbers +** less than 1e-6 are in scientific notation. +** Also, the ECMA spec says that there should always be a +** '+' or '-' after the 'e' in scientific notation +*/ +PR_IMPLEMENT(void) +PR_cnvtf(char *buf,int bufsz, int prcsn,double fval) +{ + PRIntn decpt, sign, numdigits; + char *num, *nump; + char *bufp = buf; + char *endnum; + + /* If anything fails, we store an empty string in 'buf' */ + num = (char*)PR_MALLOC(bufsz); + if (num == NULL) { + buf[0] = '\0'; + return; + } + /* XXX Why use mode 1? */ + if (PR_dtoa(dval(fval),1,prcsn,&decpt,&sign,&endnum,num,bufsz) + == PR_FAILURE) { + buf[0] = '\0'; + goto done; + } + numdigits = endnum - num; + nump = num; + + if (sign && + !(word0(fval) == Sign_bit && word1(fval) == 0) && + !((word0(fval) & Exp_mask) == Exp_mask && + (word1(fval) || (word0(fval) & 0xfffff)))) { + *bufp++ = '-'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */ + goto done; + } + + if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) { + *bufp++ = *nump++; + if (numdigits != 1) { + *bufp++ = '.'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = 'e'; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1); + } else if (decpt >= 0) { + if (decpt == 0) { + *bufp++ = '0'; + } else { + while (decpt--) { + if (*nump != '\0') { + *bufp++ = *nump++; + } else { + *bufp++ = '0'; + } + } + } + if (*nump != '\0') { + *bufp++ = '.'; + while (*nump != '\0') { + *bufp++ = *nump++; + } + } + *bufp++ = '\0'; + } else if (decpt < 0) { + *bufp++ = '0'; + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = '\0'; + } +done: + PR_DELETE(num); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prenv.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prenv.c new file mode 100644 index 00000000..7f9d5ab3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prenv.c @@ -0,0 +1,109 @@ +/* -*- 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 +#include "primpl.h" + +/* Lock used to lock the environment */ +#if defined(_PR_NO_PREEMPT) +#define _PR_NEW_LOCK_ENV() +#define _PR_DELETE_LOCK_ENV() +#define _PR_LOCK_ENV() +#define _PR_UNLOCK_ENV() +#elif defined(_PR_LOCAL_THREADS_ONLY) +extern _PRCPU * _pr_primordialCPU; +static PRIntn _is; +#define _PR_NEW_LOCK_ENV() +#define _PR_DELETE_LOCK_ENV() +#define _PR_LOCK_ENV() if (_pr_primordialCPU) _PR_INTSOFF(_is); +#define _PR_UNLOCK_ENV() if (_pr_primordialCPU) _PR_INTSON(_is); +#else +static PRLock *_pr_envLock = NULL; +#define _PR_NEW_LOCK_ENV() {_pr_envLock = PR_NewLock();} +#define _PR_DELETE_LOCK_ENV() \ + { if (_pr_envLock) { PR_DestroyLock(_pr_envLock); _pr_envLock = NULL; } } +#define _PR_LOCK_ENV() { if (_pr_envLock) PR_Lock(_pr_envLock); } +#define _PR_UNLOCK_ENV() { if (_pr_envLock) PR_Unlock(_pr_envLock); } +#endif + +/************************************************************************/ + +void _PR_InitEnv(void) +{ + _PR_NEW_LOCK_ENV(); +} + +void _PR_CleanupEnv(void) +{ + _PR_DELETE_LOCK_ENV(); +} + +PR_IMPLEMENT(char*) PR_GetEnv(const char *var) +{ + char *ev; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PR_LOCK_ENV(); + ev = _PR_MD_GET_ENV(var); + _PR_UNLOCK_ENV(); + return ev; +} + +PR_IMPLEMENT(PRStatus) PR_SetEnv(const char *string) +{ + PRIntn result; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if ( !strchr(string, '=')) return(PR_FAILURE); + + _PR_LOCK_ENV(); + result = _PR_MD_PUT_ENV((char*)string); + _PR_UNLOCK_ENV(); + return (result)? PR_FAILURE : PR_SUCCESS; +} + +/* +** DEPRECATED. Use PR_SetEnv() instead. +*/ +#ifdef XP_MAC +PR_IMPLEMENT(PRIntn) PR_PutEnv(const char *string) +{ + return (PR_SetEnv(string) == PR_SUCCESS) ? PR_TRUE : PR_FALSE; +} +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.c new file mode 100644 index 00000000..81baadf3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.c @@ -0,0 +1,128 @@ +/* -*- 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 ***** */ + +/* + * + * prerr.c + * This file is automatically generated; please do not edit it. + */ +#include "prerror.h" +static const struct PRErrorMessage text[] = { + {"PR_OUT_OF_MEMORY_ERROR", "Memory allocation attempt failed"}, + {"PR_BAD_DESCRIPTOR_ERROR", "Invalid file descriptor"}, + {"PR_WOULD_BLOCK_ERROR", "The operation would have blocked"}, + {"PR_ACCESS_FAULT_ERROR", "Invalid memory address argument"}, + {"PR_INVALID_METHOD_ERROR", "Invalid function for file type"}, + {"PR_ILLEGAL_ACCESS_ERROR", "Invalid memory address argument"}, + {"PR_UNKNOWN_ERROR", "Some unknown error has occurred"}, + {"PR_PENDING_INTERRUPT_ERROR", "Operation interrupted by another thread"}, + {"PR_NOT_IMPLEMENTED_ERROR", "function not implemented"}, + {"PR_IO_ERROR", "I/O function error"}, + {"PR_IO_TIMEOUT_ERROR", "I/O operation timed out"}, + {"PR_IO_PENDING_ERROR", "I/O operation on busy file descriptor"}, + {"PR_DIRECTORY_OPEN_ERROR", "The directory could not be opened"}, + {"PR_INVALID_ARGUMENT_ERROR", "Invalid function argument"}, + {"PR_ADDRESS_NOT_AVAILABLE_ERROR", "Network address not available (in use?)"}, + {"PR_ADDRESS_NOT_SUPPORTED_ERROR", "Network address type not supported"}, + {"PR_IS_CONNECTED_ERROR", "Already connected"}, + {"PR_BAD_ADDRESS_ERROR", "Network address is invalid"}, + {"PR_ADDRESS_IN_USE_ERROR", "Local Network address is in use"}, + {"PR_CONNECT_REFUSED_ERROR", "Connection refused by peer"}, + {"PR_NETWORK_UNREACHABLE_ERROR", "Network address is presently unreachable"}, + {"PR_CONNECT_TIMEOUT_ERROR", "Connection attempt timed out"}, + {"PR_NOT_CONNECTED_ERROR", "Network file descriptor is not connected"}, + {"PR_LOAD_LIBRARY_ERROR", "Failure to load dynamic library"}, + {"PR_UNLOAD_LIBRARY_ERROR", "Failure to unload dynamic library"}, + {"PR_FIND_SYMBOL_ERROR", "Symbol not found in any of the loaded dynamic libraries"}, + {"PR_INSUFFICIENT_RESOURCES_ERROR", "Insufficient system resources"}, + {"PR_DIRECTORY_LOOKUP_ERROR", "A directory lookup on a network address has failed"}, + {"PR_TPD_RANGE_ERROR", "Attempt to access a TPD key that is out of range"}, + {"PR_PROC_DESC_TABLE_FULL_ERROR", "Process open FD table is full"}, + {"PR_SYS_DESC_TABLE_FULL_ERROR", "System open FD table is full"}, + {"PR_NOT_SOCKET_ERROR", "Network operation attempted on non-network file descriptor"}, + {"PR_NOT_TCP_SOCKET_ERROR", "TCP-specific function attempted on a non-TCP file descriptor"}, + {"PR_SOCKET_ADDRESS_IS_BOUND_ERROR", "TCP file descriptor is already bound"}, + {"PR_NO_ACCESS_RIGHTS_ERROR", "Access Denied"}, + {"PR_OPERATION_NOT_SUPPORTED_ERROR", "The requested operation is not supported by the platform"}, + {"PR_PROTOCOL_NOT_SUPPORTED_ERROR", "The host operating system does not support the protocol requested"}, + {"PR_REMOTE_FILE_ERROR", "Access to the remote file has been severed"}, + {"PR_BUFFER_OVERFLOW_ERROR", "The value requested is too large to be stored in the data buffer provided"}, + {"PR_CONNECT_RESET_ERROR", "TCP connection reset by peer"}, + {"PR_RANGE_ERROR", "Unused"}, + {"PR_DEADLOCK_ERROR", "The operation would have deadlocked"}, + {"PR_FILE_IS_LOCKED_ERROR", "The file is already locked"}, + {"PR_FILE_TOO_BIG_ERROR", "Write would result in file larger than the system allows"}, + {"PR_NO_DEVICE_SPACE_ERROR", "The device for storing the file is full"}, + {"PR_PIPE_ERROR", "Unused"}, + {"PR_NO_SEEK_DEVICE_ERROR", "Unused"}, + {"PR_IS_DIRECTORY_ERROR", "Cannot perform a normal file operation on a directory"}, + {"PR_LOOP_ERROR", "Symbolic link loop"}, + {"PR_NAME_TOO_LONG_ERROR", "File name is too long"}, + {"PR_FILE_NOT_FOUND_ERROR", "File not found"}, + {"PR_NOT_DIRECTORY_ERROR", "Cannot perform directory operation on a normal file"}, + {"PR_READ_ONLY_FILESYSTEM_ERROR", "Cannot write to a read-only file system"}, + {"PR_DIRECTORY_NOT_EMPTY_ERROR", "Cannot delete a directory that is not empty"}, + {"PR_FILESYSTEM_MOUNTED_ERROR", "Cannot delete or rename a file object while the file system is busy"}, + {"PR_NOT_SAME_DEVICE_ERROR", "Cannot rename a file to a file system on another device"}, + {"PR_DIRECTORY_CORRUPTED_ERROR", "The directory object in the file system is corrupted"}, + {"PR_FILE_EXISTS_ERROR", "Cannot create or rename a filename that already exists"}, + {"PR_MAX_DIRECTORY_ENTRIES_ERROR", "Directory is full. No additional filenames may be added"}, + {"PR_INVALID_DEVICE_STATE_ERROR", "The required device was in an invalid state"}, + {"PR_DEVICE_IS_LOCKED_ERROR", "The device is locked"}, + {"PR_NO_MORE_FILES_ERROR", "No more entries in the directory"}, + {"PR_END_OF_FILE_ERROR", "Encountered end of file"}, + {"PR_FILE_SEEK_ERROR", "Seek error"}, + {"PR_FILE_IS_BUSY_ERROR", "The file is busy"}, + {"PR_OPERATION_ABORTED_ERROR", "The I/O operation was aborted"}, + {"PR_IN_PROGRESS_ERROR", "Operation is still in progress (probably a non-blocking connect)"}, + {"PR_ALREADY_INITIATED_ERROR", "Operation has already been initiated (probably a non-blocking connect)"}, + {"PR_GROUP_EMPTY_ERROR", "The wait group is empty"}, + {"PR_INVALID_STATE_ERROR", "Object state improper for request"}, + {"PR_NETWORK_DOWN_ERROR", "Network is down"}, + {"PR_SOCKET_SHUTDOWN_ERROR", "Socket shutdown"}, + {"PR_CONNECT_ABORTED_ERROR", "Connection aborted"}, + {"PR_HOST_UNREACHABLE_ERROR", "Host is unreachable"}, + {"PR_LIBRARY_NOT_LOADED_ERROR", "The library is not loaded"}, + {"PR_MAX_ERROR", "Placeholder for the end of the list"}, + {0, 0} +}; + +static const struct PRErrorTable et = { text, "prerr", -6000L, 76 }; + +void nspr_InitializePRErrorTable(void) { + PR_ErrorInstallTable(&et); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.et b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.et new file mode 100644 index 00000000..9281ee6e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.et @@ -0,0 +1,135 @@ +# +# 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 Netscape are +# Copyright (C) 1998-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +et nspr -6000 + +ec PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed" +ec PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor" +ec PR_WOULD_BLOCK_ERROR, "The operation would have blocked" +ec PR_ACCESS_FAULT_ERROR, "Invalid memory address argument" +ec PR_INVALID_METHOD_ERROR, "Invalid function for file type" +ec PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument" +ec PR_UNKNOWN_ERROR, "Some unknown error has occurred" +ec PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread" +ec PR_NOT_IMPLEMENTED_ERROR, "function not implemented" +ec PR_IO_ERROR, "I/O function error" +ec PR_IO_TIMEOUT_ERROR, "I/O operation timed out" +ec PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor" +ec PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened" +ec PR_INVALID_ARGUMENT_ERROR, "Invalid function argument" +ec PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)" +ec PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported" +ec PR_IS_CONNECTED_ERROR, "Already connected" +ec PR_BAD_ADDRESS_ERROR, "Network address is invalid" +ec PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use" +ec PR_CONNECT_REFUSED_ERROR, "Connection refused by peer" +ec PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable" +ec PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out" +ec PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected" +ec PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library" +ec PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library" +ec PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries" +ec PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources" +ec PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed" +ec PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range" +ec PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full" +ec PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full" +ec PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor" +ec PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor" +ec PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound" +ec PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied" +ec PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform" +ec PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested" +ec PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed" +ec PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided" +ec PR_CONNECT_RESET_ERROR, "TCP connection reset by peer" +ec PR_RANGE_ERROR, "Unused" +ec PR_DEADLOCK_ERROR, "The operation would have deadlocked" +ec PR_FILE_IS_LOCKED_ERROR, "The file is already locked" +ec PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows" +ec PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full" +ec PR_PIPE_ERROR, "Unused" +ec PR_NO_SEEK_DEVICE_ERROR, "Unused" +ec PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory" +ec PR_LOOP_ERROR, "Symbolic link loop" +ec PR_NAME_TOO_LONG_ERROR, "File name is too long" +ec PR_FILE_NOT_FOUND_ERROR, "File not found" +ec PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file" +ec PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system" +ec PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty" +ec PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy" +ec PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device" +ec PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted" +ec PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists" +ec PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added" +ec PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state" +ec PR_DEVICE_IS_LOCKED_ERROR, "The device is locked" +ec PR_NO_MORE_FILES_ERROR, "No more entries in the directory" +ec PR_END_OF_FILE_ERROR, "Encountered end of file" +ec PR_FILE_SEEK_ERROR, "Seek error" +ec PR_FILE_IS_BUSY_ERROR, "The file is busy" +ec PR_OPERATION_ABORTED_ERROR, "The I/O operation was aborted" +ec PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)" +ec PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)" +ec PR_GROUP_EMPTY_ERROR, "The wait group is empty" +ec PR_INVALID_STATE_ERROR, "Object state improper for request" +ec PR_NETWORK_DOWN_ERROR, "Network is down" +ec PR_SOCKET_SHUTDOWN_ERROR, "Socket shutdown" +ec PR_CONNECT_ABORTED_ERROR, "Connection aborted" +ec PR_HOST_UNREACHABLE_ERROR, "Host is unreachable" +ec PR_LIBRARY_NOT_LOADED_ERROR, "The library is not loaded" + +ec PR_MAX_ERROR, "Placeholder for the end of the list" + +end diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.properties b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.properties new file mode 100644 index 00000000..c10f7c8b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerr.properties @@ -0,0 +1,116 @@ +# +# ***** 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 ***** + +# +# prerr.properties +# This file is automatically generated; please do not edit it. +PR_OUT_OF_MEMORY_ERROR=Memory allocation attempt failed +PR_BAD_DESCRIPTOR_ERROR=Invalid file descriptor +PR_WOULD_BLOCK_ERROR=The operation would have blocked +PR_ACCESS_FAULT_ERROR=Invalid memory address argument +PR_INVALID_METHOD_ERROR=Invalid function for file type +PR_ILLEGAL_ACCESS_ERROR=Invalid memory address argument +PR_UNKNOWN_ERROR=Some unknown error has occurred +PR_PENDING_INTERRUPT_ERROR=Operation interrupted by another thread +PR_NOT_IMPLEMENTED_ERROR=function not implemented +PR_IO_ERROR=I/O function error +PR_IO_TIMEOUT_ERROR=I/O operation timed out +PR_IO_PENDING_ERROR=I/O operation on busy file descriptor +PR_DIRECTORY_OPEN_ERROR=The directory could not be opened +PR_INVALID_ARGUMENT_ERROR=Invalid function argument +PR_ADDRESS_NOT_AVAILABLE_ERROR=Network address not available (in use?) +PR_ADDRESS_NOT_SUPPORTED_ERROR=Network address type not supported +PR_IS_CONNECTED_ERROR=Already connected +PR_BAD_ADDRESS_ERROR=Network address is invalid +PR_ADDRESS_IN_USE_ERROR=Local Network address is in use +PR_CONNECT_REFUSED_ERROR=Connection refused by peer +PR_NETWORK_UNREACHABLE_ERROR=Network address is presently unreachable +PR_CONNECT_TIMEOUT_ERROR=Connection attempt timed out +PR_NOT_CONNECTED_ERROR=Network file descriptor is not connected +PR_LOAD_LIBRARY_ERROR=Failure to load dynamic library +PR_UNLOAD_LIBRARY_ERROR=Failure to unload dynamic library +PR_FIND_SYMBOL_ERROR=Symbol not found in any of the loaded dynamic libraries +PR_INSUFFICIENT_RESOURCES_ERROR=Insufficient system resources +PR_DIRECTORY_LOOKUP_ERROR=A directory lookup on a network address has failed +PR_TPD_RANGE_ERROR=Attempt to access a TPD key that is out of range +PR_PROC_DESC_TABLE_FULL_ERROR=Process open FD table is full +PR_SYS_DESC_TABLE_FULL_ERROR=System open FD table is full +PR_NOT_SOCKET_ERROR=Network operation attempted on non-network file descriptor +PR_NOT_TCP_SOCKET_ERROR=TCP-specific function attempted on a non-TCP file descriptor +PR_SOCKET_ADDRESS_IS_BOUND_ERROR=TCP file descriptor is already bound +PR_NO_ACCESS_RIGHTS_ERROR=Access Denied +PR_OPERATION_NOT_SUPPORTED_ERROR=The requested operation is not supported by the platform +PR_PROTOCOL_NOT_SUPPORTED_ERROR=The host operating system does not support the protocol requested +PR_REMOTE_FILE_ERROR=Access to the remote file has been severed +PR_BUFFER_OVERFLOW_ERROR=The value requested is too large to be stored in the data buffer provided +PR_CONNECT_RESET_ERROR=TCP connection reset by peer +PR_RANGE_ERROR=Unused +PR_DEADLOCK_ERROR=The operation would have deadlocked +PR_FILE_IS_LOCKED_ERROR=The file is already locked +PR_FILE_TOO_BIG_ERROR=Write would result in file larger than the system allows +PR_NO_DEVICE_SPACE_ERROR=The device for storing the file is full +PR_PIPE_ERROR=Unused +PR_NO_SEEK_DEVICE_ERROR=Unused +PR_IS_DIRECTORY_ERROR=Cannot perform a normal file operation on a directory +PR_LOOP_ERROR=Symbolic link loop +PR_NAME_TOO_LONG_ERROR=File name is too long +PR_FILE_NOT_FOUND_ERROR=File not found +PR_NOT_DIRECTORY_ERROR=Cannot perform directory operation on a normal file +PR_READ_ONLY_FILESYSTEM_ERROR=Cannot write to a read-only file system +PR_DIRECTORY_NOT_EMPTY_ERROR=Cannot delete a directory that is not empty +PR_FILESYSTEM_MOUNTED_ERROR=Cannot delete or rename a file object while the file system is busy +PR_NOT_SAME_DEVICE_ERROR=Cannot rename a file to a file system on another device +PR_DIRECTORY_CORRUPTED_ERROR=The directory object in the file system is corrupted +PR_FILE_EXISTS_ERROR=Cannot create or rename a filename that already exists +PR_MAX_DIRECTORY_ENTRIES_ERROR=Directory is full. No additional filenames may be added +PR_INVALID_DEVICE_STATE_ERROR=The required device was in an invalid state +PR_DEVICE_IS_LOCKED_ERROR=The device is locked +PR_NO_MORE_FILES_ERROR=No more entries in the directory +PR_END_OF_FILE_ERROR=Encountered end of file +PR_FILE_SEEK_ERROR=Seek error +PR_FILE_IS_BUSY_ERROR=The file is busy +PR_OPERATION_ABORTED_ERROR=The I/O operation was aborted +PR_IN_PROGRESS_ERROR=Operation is still in progress (probably a non-blocking connect) +PR_ALREADY_INITIATED_ERROR=Operation has already been initiated (probably a non-blocking connect) +PR_GROUP_EMPTY_ERROR=The wait group is empty +PR_INVALID_STATE_ERROR=Object state improper for request +PR_NETWORK_DOWN_ERROR=Network is down +PR_SOCKET_SHUTDOWN_ERROR=Socket shutdown +PR_CONNECT_ABORTED_ERROR=Connection aborted +PR_HOST_UNREACHABLE_ERROR=Host is unreachable +PR_LIBRARY_NOT_LOADED_ERROR=The library is not loaded +PR_MAX_ERROR=Placeholder for the end of the list diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerror.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerror.c new file mode 100644 index 00000000..f578f2d2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerror.c @@ -0,0 +1,107 @@ +/* -*- 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 +#include + +PR_IMPLEMENT(PRErrorCode) PR_GetError(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->errorCode; +} + +PR_IMPLEMENT(PRInt32) PR_GetOSError(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->osErrorCode; +} + +PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr) +{ + PRThread *thread = PR_GetCurrentThread(); + thread->errorCode = code; + thread->osErrorCode = osErr; + thread->errorStringLength = 0; +} + +PR_IMPLEMENT(void) PR_SetErrorText(PRIntn textLength, const char *text) +{ + PRThread *thread = PR_GetCurrentThread(); + + if (0 == textLength) + { + if (NULL != thread->errorString) + PR_DELETE(thread->errorString); + thread->errorStringSize = 0; + } + else + { + PRIntn size = textLength + 31; /* actual length to allocate. Plus a little extra */ + if (thread->errorStringSize < textLength+1) /* do we have room? */ + { + if (NULL != thread->errorString) + PR_DELETE(thread->errorString); + thread->errorString = (char*)PR_MALLOC(size); + if ( NULL == thread->errorString ) { + thread->errorStringSize = 0; + thread->errorStringLength = 0; + return; + } + thread->errorStringSize = size; + } + memcpy(thread->errorString, text, textLength+1 ); + } + thread->errorStringLength = textLength; +} + +PR_IMPLEMENT(PRInt32) PR_GetErrorTextLength(void) +{ + PRThread *thread = PR_GetCurrentThread(); + return thread->errorStringLength; +} /* PR_GetErrorTextLength */ + +PR_IMPLEMENT(PRInt32) PR_GetErrorText(char *text) +{ + PRThread *thread = PR_GetCurrentThread(); + if (0 != thread->errorStringLength) + memcpy(text, thread->errorString, thread->errorStringLength+1); + return thread->errorStringLength; +} /* PR_GetErrorText */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerrortable.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerrortable.c new file mode 100644 index 00000000..a51b4e8f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prerrortable.c @@ -0,0 +1,240 @@ +/* ***** 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 ***** */ + + + + +/* + +Copyright 1987, 1988 by the Student Information Processing Board + of the Massachusetts Institute of Technology + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is +hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, +and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. +M.I.T. and the M.I.T. S.I.P.B. make no representations about +the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + +*/ + +#include +#ifdef SUNOS4 +#include "md/sunos4.h" /* for strerror */ +#endif +#include +#include +#include "prmem.h" +#include "prerror.h" + +#define ERRCODE_RANGE 8 /* # of bits to shift table number */ +#define BITS_PER_CHAR 6 /* # bits to shift per character in name */ + +#ifdef NEED_SYS_ERRLIST +extern char const * const sys_errlist[]; +extern const int sys_nerr; +#endif + +/* List of error tables */ +struct PRErrorTableList { + struct PRErrorTableList *next; + const struct PRErrorTable *table; + struct PRErrorCallbackTablePrivate *table_private; +}; +static struct PRErrorTableList * Table_List = (struct PRErrorTableList *) NULL; + +/* Supported languages */ +static const char * default_languages[] = { "i-default", "en", 0 }; +static const char * const * callback_languages = default_languages; + +/* Callback info */ +static struct PRErrorCallbackPrivate *callback_private = 0; +static PRErrorCallbackLookupFn *callback_lookup = 0; +static PRErrorCallbackNewTableFn *callback_newtable = 0; + + +static const char char_set[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; + +static const char * +error_table_name (PRErrorCode num) +{ + static char buf[6]; /* only used if internal code problems exist */ + + long ch; + int i; + char *p; + + /* num = aa aaa abb bbb bcc ccc cdd ddd d?? ??? ??? */ + p = buf; + num >>= ERRCODE_RANGE; + /* num = ?? ??? ??? aaa aaa bbb bbb ccc ccc ddd ddd */ + num &= 077777777; + /* num = 00 000 000 aaa aaa bbb bbb ccc ccc ddd ddd */ + for (i = 4; i >= 0; i--) { + ch = (num >> BITS_PER_CHAR * i) & ((1 << BITS_PER_CHAR) - 1); + if (ch != 0) + *p++ = char_set[ch-1]; + } + *p = '\0'; + return(buf); +} + +PR_IMPLEMENT(const char *) +PR_ErrorToString(PRErrorCode code, PRLanguageCode language) +{ + /* static buffer only used if code is using inconsistent error message + * numbers, so just ignore the possible thread contention + */ + static char buffer[25]; + + const char *msg; + int offset; + PRErrorCode table_num; + struct PRErrorTableList *et; + int started = 0; + char *cp; + + for (et = Table_List; et; et = et->next) { + if (et->table->base <= code && + et->table->base + et->table->n_msgs > code) { + /* This is the right table */ + if (callback_lookup) { + msg = callback_lookup(code, language, et->table, + callback_private, et->table_private); + if (msg) return msg; + } + + return(et->table->msgs[code - et->table->base].en_text); + } + } + + if (code >= 0 && code < 256) { + return strerror(code); + } + + offset = (int) (code & ((1<= 100) { + *cp++ = (char)('0' + offset / 100); + offset %= 100; + started++; + } + if (started || offset >= 10) { + *cp++ = (char)('0' + offset / 10); + offset %= 10; + } + *cp++ = (char)('0' + offset); + *cp = '\0'; + return(buffer); +} + +PR_IMPLEMENT(const char *) +PR_ErrorToName(PRErrorCode code) +{ + struct PRErrorTableList *et; + + for (et = Table_List; et; et = et->next) { + if (et->table->base <= code && + et->table->base + et->table->n_msgs > code) { + /* This is the right table */ + return(et->table->msgs[code - et->table->base].name); + } + } + + return 0; +} + +PR_IMPLEMENT(const char * const *) +PR_ErrorLanguages(void) +{ + return callback_languages; +} + +PR_IMPLEMENT(PRErrorCode) +PR_ErrorInstallTable(const struct PRErrorTable *table) +{ + struct PRErrorTableList * new_et; + + new_et = (struct PRErrorTableList *) + PR_Malloc(sizeof(struct PRErrorTableList)); + if (!new_et) + return errno; /* oops */ + new_et->table = table; + if (callback_newtable) { + new_et->table_private = callback_newtable(table, callback_private); + } else { + new_et->table_private = 0; + } + new_et->next = Table_List; + Table_List = new_et; + return 0; +} + +PR_IMPLEMENT(void) +PR_ErrorInstallCallback(const char * const * languages, + PRErrorCallbackLookupFn *lookup, + PRErrorCallbackNewTableFn *newtable, + struct PRErrorCallbackPrivate *cb_private) +{ + struct PRErrorTableList *et; + + assert(strcmp(languages[0], "i-default") == 0); + assert(strcmp(languages[1], "en") == 0); + + callback_languages = languages; + callback_lookup = lookup; + callback_newtable = newtable; + callback_private = cb_private; + + if (callback_newtable) { + for (et = Table_List; et; et = et->next) { + et->table_private = callback_newtable(et->table, callback_private); + } + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinit.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinit.c new file mode 100644 index 00000000..eef45968 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinit.c @@ -0,0 +1,880 @@ +/* -*- 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 +#include +#ifdef VBOX_USE_IPRT_IN_NSPR +# include +#endif + +PRLogModuleInfo *_pr_clock_lm; +PRLogModuleInfo *_pr_cmon_lm; +PRLogModuleInfo *_pr_io_lm; +PRLogModuleInfo *_pr_cvar_lm; +PRLogModuleInfo *_pr_mon_lm; +PRLogModuleInfo *_pr_linker_lm; +PRLogModuleInfo *_pr_sched_lm; +PRLogModuleInfo *_pr_thread_lm; +PRLogModuleInfo *_pr_gc_lm; +PRLogModuleInfo *_pr_shm_lm; +PRLogModuleInfo *_pr_shma_lm; + +PRFileDesc *_pr_stdin; +PRFileDesc *_pr_stdout; +PRFileDesc *_pr_stderr; + +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + +PRCList _pr_active_local_threadQ = + PR_INIT_STATIC_CLIST(&_pr_active_local_threadQ); +PRCList _pr_active_global_threadQ = + PR_INIT_STATIC_CLIST(&_pr_active_global_threadQ); + +_MDLock _pr_cpuLock; /* lock for the CPU Q */ +PRCList _pr_cpuQ = PR_INIT_STATIC_CLIST(&_pr_cpuQ); + +PRUint32 _pr_utid; + +PRInt32 _pr_userActive; +PRInt32 _pr_systemActive; +PRUintn _pr_maxPTDs; + +#ifdef _PR_LOCAL_THREADS_ONLY + +struct _PRCPU *_pr_currentCPU; +PRThread *_pr_currentThread; +PRThread *_pr_lastThread; +PRInt32 _pr_intsOff; + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +/* Lock protecting all "termination" condition variables of all threads */ +PRLock *_pr_terminationCVLock; + +#endif /* !defined(_PR_PTHREADS) */ + +PRLock *_pr_sleeplock; /* used in PR_Sleep(), classic and pthreads */ + +static void _PR_InitCallOnce(void); + +PRBool _pr_initialized = PR_FALSE; + + +PR_IMPLEMENT(PRBool) PR_VersionCheck(const char *importedVersion) +{ + /* + ** This is the secret handshake algorithm. + ** + ** This release has a simple version compatibility + ** check algorithm. This release is not backward + ** compatible with previous major releases. It is + ** not compatible with future major, minor, or + ** patch releases. + */ + int vmajor = 0, vminor = 0, vpatch = 0; + const char *ptr = importedVersion; + + while (isdigit(*ptr)) { + vmajor = 10 * vmajor + *ptr - '0'; + ptr++; + } + if (*ptr == '.') { + ptr++; + while (isdigit(*ptr)) { + vminor = 10 * vminor + *ptr - '0'; + ptr++; + } + if (*ptr == '.') { + ptr++; + while (isdigit(*ptr)) { + vpatch = 10 * vpatch + *ptr - '0'; + ptr++; + } + } + } + + if (vmajor != PR_VMAJOR) { + return PR_FALSE; + } + if (vmajor == PR_VMAJOR && vminor > PR_VMINOR) { + return PR_FALSE; + } + if (vmajor == PR_VMAJOR && vminor == PR_VMINOR && vpatch > PR_VPATCH) { + return PR_FALSE; + } + return PR_TRUE; +} /* PR_VersionCheck */ + + +PR_IMPLEMENT(PRBool) PR_Initialized(void) +{ + return _pr_initialized; +} + +PRInt32 _native_threads_only = 0; + +#ifdef WINNT +static void _pr_SetNativeThreadsOnlyMode(void) +{ + HMODULE mainExe; + PRBool *globalp; + char *envp; + + mainExe = GetModuleHandle(NULL); + PR_ASSERT(NULL != mainExe); + globalp = (PRBool *) GetProcAddress(mainExe, "nspr_native_threads_only"); + if (globalp) { + _native_threads_only = (*globalp != PR_FALSE); + } else if (envp = getenv("NSPR_NATIVE_THREADS_ONLY")) { + _native_threads_only = (atoi(envp) == 1); + } +} +#endif + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) +extern PRStatus _pr_init_ipv6(void); +#endif + +static void _PR_InitStuff(void) +{ + + if (_pr_initialized) return; + _pr_initialized = PR_TRUE; +#ifdef VBOX_USE_IPRT_IN_NSPR + RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +#endif +#ifdef _PR_ZONE_ALLOCATOR + _PR_InitZones(); +#endif +#ifdef WINNT + _pr_SetNativeThreadsOnlyMode(); +#endif + + + (void) PR_GetPageSize(); + + _pr_clock_lm = PR_NewLogModule("clock"); + _pr_cmon_lm = PR_NewLogModule("cmon"); + _pr_io_lm = PR_NewLogModule("io"); + _pr_mon_lm = PR_NewLogModule("mon"); + _pr_linker_lm = PR_NewLogModule("linker"); + _pr_cvar_lm = PR_NewLogModule("cvar"); + _pr_sched_lm = PR_NewLogModule("sched"); + _pr_thread_lm = PR_NewLogModule("thread"); + _pr_gc_lm = PR_NewLogModule("gc"); + _pr_shm_lm = PR_NewLogModule("shm"); + _pr_shma_lm = PR_NewLogModule("shma"); + + /* NOTE: These init's cannot depend on _PR_MD_CURRENT_THREAD() */ + _PR_MD_EARLY_INIT(); + + _PR_InitLocks(); + _PR_InitAtomic(); + _PR_InitSegs(); + _PR_InitStacks(); + _PR_InitTPD(); + _PR_InitEnv(); + _PR_InitLayerCache(); + _PR_InitClock(); + + _pr_sleeplock = PR_NewLock(); + PR_ASSERT(NULL != _pr_sleeplock); + +#ifdef GC_LEAK_DETECTOR + _PR_InitGarbageCollector(); +#endif + + _PR_InitThreads(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + +#ifdef WIN16 + { + PRInt32 top; /* artificial top of stack, win16 */ + _pr_top_of_task_stack = (char *) ⊤ + } +#endif + +#ifndef _PR_GLOBAL_THREADS_ONLY + _PR_InitCPUs(); +#endif + +/* + * XXX: call _PR_InitMem only on those platforms for which nspr implements + * malloc, for now. + */ +#ifdef _PR_OVERRIDE_MALLOC + _PR_InitMem(); +#endif + + _PR_InitCMon(); + _PR_InitIO(); + _PR_InitNet(); + _PR_InitLog(); + _PR_InitLinker(); + _PR_InitCallOnce(); + _PR_InitDtoa(); + _PR_InitMW(); + _PR_InitRWLocks(); + + nspr_InitializePRErrorTable(); + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) + _pr_init_ipv6(); +#endif + + _PR_MD_FINAL_INIT(); +} + +void _PR_ImplicitInitialization(void) +{ + _PR_InitStuff(); + + /* Enable interrupts */ +#if !defined(_PR_PTHREADS) && !defined(_PR_GLOBAL_THREADS_ONLY) + _PR_MD_START_INTERRUPTS(); +#endif + +} + +PR_IMPLEMENT(void) PR_DisableClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + if (!_pr_initialized) { + _PR_InitStuff(); + } else { + _PR_MD_DISABLE_CLOCK_INTERRUPTS(); + } +#endif +} + +PR_IMPLEMENT(void) PR_EnableClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + if (!_pr_initialized) { + _PR_InitStuff(); + } + _PR_MD_ENABLE_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_BlockClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + _PR_MD_BLOCK_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_UnblockClockInterrupts(void) +{ +#if !defined(_PR_PTHREADS) && !defined(_PR_BTHREADS) + _PR_MD_UNBLOCK_CLOCK_INTERRUPTS(); +#endif +} + +PR_IMPLEMENT(void) PR_Init( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (type, priority, maxPTDs) +#endif + + _PR_ImplicitInitialization(); +} + +PR_IMPLEMENT(PRIntn) PR_Initialize( + PRPrimordialFn prmain, PRIntn argc, char **argv, PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (maxPTDs) +#endif + + PRIntn rv; + _PR_ImplicitInitialization(); + rv = prmain(argc, argv); + PR_Cleanup(); + return rv; +} /* PR_Initialize */ + +/* + *----------------------------------------------------------------------- + * + * _PR_CleanupBeforeExit -- + * + * Perform the cleanup work before exiting the process. + * We first do the cleanup generic to all platforms. Then + * we call _PR_MD_CLEANUP_BEFORE_EXIT(), where platform-dependent + * cleanup is done. This function is used by PR_Cleanup(). + * + * See also: PR_Cleanup(). + * + *----------------------------------------------------------------------- + */ +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else +static void +_PR_CleanupBeforeExit(void) +{ +/* +Do not make any calls here other than to destroy resources. For example, +do not make any calls that eventually may end up in PR_Lock. Because the +thread is destroyed, can not access current thread any more. +*/ + _PR_CleanupTPD(); + if (_pr_terminationCVLock) + /* + * In light of the comment above, this looks real suspicious. + * I'd go so far as to say it's just a problem waiting to happen. + */ + PR_DestroyLock(_pr_terminationCVLock); + + _PR_MD_CLEANUP_BEFORE_EXIT(); +} +#endif /* defined(_PR_PTHREADS) */ + +/* + *---------------------------------------------------------------------- + * + * PR_Cleanup -- + * + * Perform a graceful shutdown of the NSPR runtime. PR_Cleanup() may + * only be called from the primordial thread, typically at the + * end of the main() function. It returns when it has completed + * its platform-dependent duty and the process must not make any other + * NSPR library calls prior to exiting from main(). + * + * PR_Cleanup() first blocks the primordial thread until all the + * other user (non-system) threads, if any, have terminated. + * Then it performs cleanup in preparation for exiting the process. + * PR_Cleanup() does not exit the primordial thread (which would + * in turn exit the process). + * + * PR_Cleanup() only responds when it is called by the primordial + * thread. Calls by any other thread are silently ignored. + * + * See also: PR_ExitProcess() + * + *---------------------------------------------------------------------- + */ +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else + +PR_IMPLEMENT(PRStatus) PR_Cleanup() +{ + PRThread *me = PR_GetCurrentThread(); + PR_ASSERT((NULL != me) && (me->flags & _PR_PRIMORDIAL)); + if ((NULL != me) && (me->flags & _PR_PRIMORDIAL)) + { + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); + + /* + * No more recycling of threads + */ + _pr_recycleThreads = 0; + + /* + * Wait for all other user (non-system/daemon) threads + * to terminate. + */ + PR_Lock(_pr_activeLock); + while (_pr_userActive > _pr_primordialExitCount) { + PR_WaitCondVar(_pr_primordialExitCVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(_pr_activeLock); + +#ifdef IRIX + _PR_MD_PRE_CLEANUP(me); + /* + * The primordial thread must now be running on the primordial cpu + */ + PR_ASSERT((_PR_IS_NATIVE_THREAD(me)) || (me->cpu->id == 0)); +#endif + + _PR_CleanupMW(); + _PR_CleanupDtoa(); + _PR_CleanupCallOnce(); + _PR_ShutdownLinker(); + /* Release the primordial thread's private data, etc. */ + _PR_CleanupThread(me); + + _PR_MD_STOP_INTERRUPTS(); + + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_Cleanup: clean up before destroying thread")); + _PR_LogCleanup(); + + /* + * This part should look like the end of _PR_NativeRunThread + * and _PR_UserRunThread. + */ + if (_PR_IS_NATIVE_THREAD(me)) { + _PR_MD_EXIT_THREAD(me); + _PR_NativeDestroyThread(me); + } else { + _PR_UserDestroyThread(me); + PR_DELETE(me->stack); + PR_DELETE(me); + } + + /* + * XXX: We are freeing the heap memory here so that Purify won't + * complain, but we should also free other kinds of resources + * that are allocated by the _PR_InitXXX() functions. + * Ideally, for each _PR_InitXXX(), there should be a corresponding + * _PR_XXXCleanup() that we can call here. + */ + _PR_CleanupNet(); + _PR_CleanupIO(); +#ifdef WINNT + _PR_CleanupCPUs(); +#endif + _PR_CleanupThreads(); + PR_DestroyLock(_pr_sleeplock); + _pr_sleeplock = NULL; + _PR_CleanupLayerCache(); + _PR_CleanupEnv(); + _PR_CleanupStacks(); + _PR_CleanupBeforeExit(); + _pr_initialized = PR_FALSE; + return PR_SUCCESS; + } + return PR_FAILURE; +} +#endif /* defined(_PR_PTHREADS) */ + +/* + *------------------------------------------------------------------------ + * PR_ProcessExit -- + * + * Cause an immediate, nongraceful, forced termination of the process. + * It takes a PRIntn argument, which is the exit status code of the + * process. + * + * See also: PR_Cleanup() + * + *------------------------------------------------------------------------ + */ + +#if defined(_PR_PTHREADS) || defined(_PR_BTHREADS) + /* see ptthread.c */ +#else +PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) +{ + _PR_MD_EXIT(status); +} + +#endif /* defined(_PR_PTHREADS) */ + +PR_IMPLEMENT(PRProcessAttr *) +PR_NewProcessAttr(void) +{ + PRProcessAttr *attr; + + attr = PR_NEWZAP(PRProcessAttr); + if (!attr) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return attr; +} + +PR_IMPLEMENT(void) +PR_ResetProcessAttr(PRProcessAttr *attr) +{ + PR_FREEIF(attr->currentDirectory); + PR_FREEIF(attr->fdInheritBuffer); + memset(attr, 0, sizeof(*attr)); +} + +PR_IMPLEMENT(void) +PR_DestroyProcessAttr(PRProcessAttr *attr) +{ + PR_FREEIF(attr->currentDirectory); + PR_FREEIF(attr->fdInheritBuffer); + PR_DELETE(attr); +} + +PR_IMPLEMENT(void) +PR_ProcessAttrSetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd) +{ + switch (stdioFd) { + case PR_StandardInput: + attr->stdinFd = redirectFd; + break; + case PR_StandardOutput: + attr->stdoutFd = redirectFd; + break; + case PR_StandardError: + attr->stderrFd = redirectFd; + break; + default: + PR_ASSERT(0); + } +} + +/* + * OBSOLETE + */ +PR_IMPLEMENT(void) +PR_SetStdioRedirect( + PRProcessAttr *attr, + PRSpecialFD stdioFd, + PRFileDesc *redirectFd) +{ +#if defined(DEBUG) + static PRBool warn = PR_TRUE; + if (warn) { + warn = _PR_Obsolete("PR_SetStdioRedirect()", + "PR_ProcessAttrSetStdioRedirect()"); + } +#endif + PR_ProcessAttrSetStdioRedirect(attr, stdioFd, redirectFd); +} + +PR_IMPLEMENT(PRStatus) +PR_ProcessAttrSetCurrentDirectory( + PRProcessAttr *attr, + const char *dir) +{ + PR_FREEIF(attr->currentDirectory); + attr->currentDirectory = (char *) PR_MALLOC(strlen(dir) + 1); + if (!attr->currentDirectory) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + strcpy(attr->currentDirectory, dir); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) +PR_ProcessAttrSetInheritableFD( + PRProcessAttr *attr, + PRFileDesc *fd, + const char *name) +{ + /* We malloc the fd inherit buffer in multiples of this number. */ +#define FD_INHERIT_BUFFER_INCR 128 + /* The length of "NSPR_INHERIT_FDS=" */ +#define NSPR_INHERIT_FDS_STRLEN 17 + /* The length of osfd (PRInt32) printed in hexadecimal with 0x prefix */ +#define OSFD_STRLEN 10 + /* The length of fd type (PRDescType) printed in decimal */ +#define FD_TYPE_STRLEN 1 + PRSize newSize; + int remainder; + char *newBuffer; + int nwritten; + char *cur; + int freeSize; + + if (fd->identity != PR_NSPR_IO_LAYER) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable == _PR_TRI_UNKNOWN) { + _PR_MD_QUERY_FD_INHERITABLE(fd); + } + if (fd->secret->inheritable != _PR_TRI_TRUE) { + PR_SetError(PR_NO_ACCESS_RIGHTS_ERROR, 0); + return PR_FAILURE; + } + + /* + * We also need to account for the : separators and the + * terminating null byte. + */ + if (NULL == attr->fdInheritBuffer) { + /* The first time, we print "NSPR_INHERIT_FDS=::" */ + newSize = NSPR_INHERIT_FDS_STRLEN + strlen(name) + + FD_TYPE_STRLEN + OSFD_STRLEN + 2 + 1; + } else { + /* At other times, we print ":::" */ + newSize = attr->fdInheritBufferUsed + strlen(name) + + FD_TYPE_STRLEN + OSFD_STRLEN + 3 + 1; + } + if (newSize > attr->fdInheritBufferSize) { + /* Make newSize a multiple of FD_INHERIT_BUFFER_INCR */ + remainder = newSize % FD_INHERIT_BUFFER_INCR; + if (remainder != 0) { + newSize += (FD_INHERIT_BUFFER_INCR - remainder); + } + if (NULL == attr->fdInheritBuffer) { + newBuffer = (char *) PR_MALLOC(newSize); + } else { + newBuffer = (char *) PR_REALLOC(attr->fdInheritBuffer, newSize); + } + if (NULL == newBuffer) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + attr->fdInheritBuffer = newBuffer; + attr->fdInheritBufferSize = newSize; + } + cur = attr->fdInheritBuffer + attr->fdInheritBufferUsed; + freeSize = attr->fdInheritBufferSize - attr->fdInheritBufferUsed; + if (0 == attr->fdInheritBufferUsed) { + nwritten = PR_snprintf(cur, freeSize, + "NSPR_INHERIT_FDS=%s:%d:0x%lx", + name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); + } else { + nwritten = PR_snprintf(cur, freeSize, ":%s:%d:0x%lx", + name, (PRIntn)fd->methods->file_type, fd->secret->md.osfd); + } + attr->fdInheritBufferUsed += nwritten; + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRFileDesc *) PR_GetInheritedFD( + const char *name) +{ + PRFileDesc *fd; + const char *envVar; + const char *ptr; + int len = strlen(name); + PRInt32 osfd; + int nColons; + PRIntn fileType; + + envVar = PR_GetEnv("NSPR_INHERIT_FDS"); + if (NULL == envVar || '\0' == envVar[0]) { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return NULL; + } + + ptr = envVar; + while (1) { + if ((strncmp(ptr, name, len) == 0) && (ptr[len] == ':')) { + ptr += len + 1; + PR_sscanf(ptr, "%d:0x%lx", &fileType, &osfd); + switch ((PRDescType)fileType) { + case PR_DESC_FILE: + fd = PR_ImportFile(osfd); + break; + case PR_DESC_PIPE: + fd = PR_ImportPipe(osfd); + break; + case PR_DESC_SOCKET_TCP: + fd = PR_ImportTCPSocket(osfd); + break; + case PR_DESC_SOCKET_UDP: + fd = PR_ImportUDPSocket(osfd); + break; + default: + PR_ASSERT(0); + PR_SetError(PR_UNKNOWN_ERROR, 0); + fd = NULL; + break; + } + if (fd) { + /* + * An inherited FD is inheritable by default. + * The child process needs to call PR_SetFDInheritable + * to make it non-inheritable if so desired. + */ + fd->secret->inheritable = _PR_TRI_TRUE; + } + return fd; + } + /* Skip three colons */ + nColons = 0; + while (*ptr) { + if (*ptr == ':') { + if (++nColons == 3) { + break; + } + } + ptr++; + } + if (*ptr == '\0') { + PR_SetError(PR_UNKNOWN_ERROR, 0); + return NULL; + } + ptr++; + } +} + +PR_IMPLEMENT(PRProcess*) PR_CreateProcess( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ + return _PR_MD_CREATE_PROCESS(path, argv, envp, attr); +} /* PR_CreateProcess */ + +PR_IMPLEMENT(PRStatus) PR_CreateProcessDetached( + const char *path, + char *const *argv, + char *const *envp, + const PRProcessAttr *attr) +{ +#ifndef _PR_MD_CREATE_PROCESS_DETACHED + PRProcess *process; + PRStatus rv; +s +#ifdef XP_OS2 + process = _PR_CreateOS2ProcessEx(path, argv, envp, attr, PR_TRUE); +#else + process = PR_CreateProcess(path, argv, envp, attr); +#endif + if (NULL == process) { + return PR_FAILURE; + } + rv = PR_DetachProcess(process); + PR_ASSERT(PR_SUCCESS == rv); + if (rv == PR_FAILURE) { + PR_DELETE(process); + return PR_FAILURE; + } + return PR_SUCCESS; +#else /* _PR_MD_CREATE_PROCESS_DETACHED */ + return _PR_MD_CREATE_PROCESS_DETACHED(path, argv, envp, attr); +#endif /* _PR_MD_CREATE_PROCESS_DETACHED */ +} + +PR_IMPLEMENT(PRStatus) PR_DetachProcess(PRProcess *process) +{ + return _PR_MD_DETACH_PROCESS(process); +} + +PR_IMPLEMENT(PRStatus) PR_WaitProcess(PRProcess *process, PRInt32 *exitCode) +{ + return _PR_MD_WAIT_PROCESS(process, exitCode); +} /* PR_WaitProcess */ + +PR_IMPLEMENT(PRStatus) PR_KillProcess(PRProcess *process) +{ + return _PR_MD_KILL_PROCESS(process); +} + +/* + ******************************************************************** + * + * Module initialization + * + ******************************************************************** + */ + +static struct { + PRLock *ml; + PRCondVar *cv; +} mod_init; + +static void _PR_InitCallOnce(void) { + mod_init.ml = PR_NewLock(); + PR_ASSERT(NULL != mod_init.ml); + mod_init.cv = PR_NewCondVar(mod_init.ml); + PR_ASSERT(NULL != mod_init.cv); +} + +void _PR_CleanupCallOnce() +{ + PR_DestroyLock(mod_init.ml); + mod_init.ml = NULL; + PR_DestroyCondVar(mod_init.cv); + mod_init.cv = NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CallOnce( + PRCallOnceType *once, + PRCallOnceFN func) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!once->initialized) { + if (PR_AtomicSet(&once->inProgress, 1) == 0) { + once->status = (*func)(); + PR_Lock(mod_init.ml); + once->initialized = 1; + PR_NotifyAllCondVar(mod_init.cv); + PR_Unlock(mod_init.ml); + } else { + PR_Lock(mod_init.ml); + while (!once->initialized) { + PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mod_init.ml); + } + } + return once->status; +} + +PR_IMPLEMENT(PRStatus) PR_CallOnceWithArg( + PRCallOnceType *once, + PRCallOnceWithArgFN func, + void *arg) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (!once->initialized) { + if (PR_AtomicSet(&once->inProgress, 1) == 0) { + once->status = (*func)(arg); + PR_Lock(mod_init.ml); + once->initialized = 1; + PR_NotifyAllCondVar(mod_init.cv); + PR_Unlock(mod_init.ml); + } else { + PR_Lock(mod_init.ml); + while (!once->initialized) { + PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mod_init.ml); + } + } + return once->status; +} + +PRBool _PR_Obsolete(const char *obsolete, const char *preferred) +{ +#if defined(DEBUG) +#ifndef XP_MAC + PR_fprintf( + PR_STDERR, "'%s' is obsolete. Use '%s' instead.\n", + obsolete, (NULL == preferred) ? "something else" : preferred); +#else +#pragma unused (obsolete, preferred) +#endif +#endif + return PR_FALSE; +} /* _PR_Obsolete */ + +/* prinit.c */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinrval.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinrval.c new file mode 100644 index 00000000..17229e80 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prinrval.c @@ -0,0 +1,157 @@ +/* -*- 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 ***** */ + +/* + * file: prinrval.c + * description: implementation for the kernel interval timing functions + */ + +#include "primpl.h" + +/* + *----------------------------------------------------------------------- + * + * _PR_InitClock -- + * + * + *----------------------------------------------------------------------- + */ + +void _PR_InitClock(void) +{ + _PR_MD_INTERVAL_INIT(); +#ifdef DEBUG + { + PRIntervalTime ticksPerSec = PR_TicksPerSecond(); + + PR_ASSERT(ticksPerSec >= PR_INTERVAL_MIN); + PR_ASSERT(ticksPerSec <= PR_INTERVAL_MAX); + } +#endif /* DEBUG */ +} + +/* + * This version of interval times is based on the time of day + * capability offered by system. This isn't valid for two reasons: + * 1) The time of day is neither linear nor montonically increasing + * 2) The units here are milliseconds. That's not appropriate for our use. + */ + +PR_IMPLEMENT(PRIntervalTime) PR_IntervalNow(void) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_GET_INTERVAL(); +} /* PR_IntervalNow */ + +PR_EXTERN(PRUint32) PR_TicksPerSecond(void) +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_INTERVAL_PER_SEC(); +} /* PR_TicksPerSecond */ + +PR_IMPLEMENT(PRIntervalTime) PR_SecondsToInterval(PRUint32 seconds) +{ + return seconds * PR_TicksPerSecond(); +} /* PR_SecondsToInterval */ + +PR_IMPLEMENT(PRIntervalTime) PR_MillisecondsToInterval(PRUint32 milli) +{ + PRIntervalTime ticks; + PRUint64 tock, tps, msecPerSec, rounding; + LL_UI2L(tock, milli); + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_I2L(rounding, (PR_MSEC_PER_SEC >> 1)); + LL_I2L(tps, PR_TicksPerSecond()); + LL_MUL(tock, tock, tps); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, msecPerSec); + LL_L2UI(ticks, tock); + return ticks; +} /* PR_MillisecondsToInterval */ + +PR_IMPLEMENT(PRIntervalTime) PR_MicrosecondsToInterval(PRUint32 micro) +{ + PRIntervalTime ticks; + PRUint64 tock, tps, usecPerSec, rounding; + LL_UI2L(tock, micro); + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(rounding, (PR_USEC_PER_SEC >> 1)); + LL_I2L(tps, PR_TicksPerSecond()); + LL_MUL(tock, tock, tps); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, usecPerSec); + LL_L2UI(ticks, tock); + return ticks; +} /* PR_MicrosecondsToInterval */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToSeconds(PRIntervalTime ticks) +{ + return ticks / PR_TicksPerSecond(); +} /* PR_IntervalToSeconds */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToMilliseconds(PRIntervalTime ticks) +{ + PRUint32 milli; + PRUint64 tock, tps, msecPerSec, rounding; + LL_UI2L(tock, ticks); + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_I2L(tps, PR_TicksPerSecond()); + LL_USHR(rounding, tps, 1); + LL_MUL(tock, tock, msecPerSec); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, tps); + LL_L2UI(milli, tock); + return milli; +} /* PR_IntervalToMilliseconds */ + +PR_IMPLEMENT(PRUint32) PR_IntervalToMicroseconds(PRIntervalTime ticks) +{ + PRUint32 micro; + PRUint64 tock, tps, usecPerSec, rounding; + LL_UI2L(tock, ticks); + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_I2L(tps, PR_TicksPerSecond()); + LL_USHR(rounding, tps, 1); + LL_MUL(tock, tock, usecPerSec); + LL_ADD(tock, tock, rounding); + LL_DIV(tock, tock, tps); + LL_L2UI(micro, tock); + return micro; +} /* PR_IntervalToMicroseconds */ + +/* prinrval.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripc.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripc.c new file mode 100644 index 00000000..cb16aad9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripc.c @@ -0,0 +1,132 @@ +/* -*- 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 ***** */ + +/* + * File: pripc.c + * + * Description: functions for IPC support + */ + +#include "primpl.h" + +#include + +/* + * A POSIX IPC name must begin with a '/'. + * A POSIX IPC name on Solaris cannot contain any '/' except + * the required leading '/'. + * A POSIX IPC name on HP-UX and OSF1 must be a valid pathname + * in the file system. + * + * The ftok() function for System V IPC requires a valid pathname + * in the file system. + * + * A Win32 IPC name cannot contain '\'. + */ + +static void _pr_ConvertSemName(char *result) +{ +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#if defined(SOLARIS) + char *p; + + /* Convert '/' to '_' except for the leading '/' */ + for (p = result+1; *p; p++) { + if (*p == '/') { + *p = '_'; + } + } + return; +#else + return; +#endif +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + return; +#elif defined(WIN32) + return; +#endif +} + +static void _pr_ConvertShmName(char *result) +{ +#if defined(PR_HAVE_POSIX_NAMED_SHARED_MEMORY) +#if defined(SOLARIS) + char *p; + + /* Convert '/' to '_' except for the leading '/' */ + for (p = result+1; *p; p++) { + if (*p == '/') { + *p = '_'; + } + } + return; +#else + return; +#endif +#elif defined(PR_HAVE_SYSV_NAMED_SHARED_MEMORY) + return; +#elif defined(WIN32) + return; +#else + return; +#endif +} + +PRStatus _PR_MakeNativeIPCName( + const char *name, + char *result, + PRIntn size, + _PRIPCType type) +{ + if (strlen(name) >= (PRSize)size) { + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return PR_FAILURE; + } + strcpy(result, name); + switch (type) { + case _PRIPCSem: + _pr_ConvertSemName(result); + break; + case _PRIPCShm: + _pr_ConvertShmName(result); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripcsem.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripcsem.c new file mode 100644 index 00000000..c6c59ec9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/pripcsem.c @@ -0,0 +1,130 @@ +/* -*- 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 ***** */ + +/* + * File: pripcsem.c + * + * Description: implements the named semaphores API in prsemipc.h + * for classic NSPR. If _PR_HAVE_NAMED_SEMAPHORES is not defined, + * the named semaphore functions all fail with the error code + * PR_NOT_IMPLEMENTED_ERROR. + */ + +#include "primpl.h" + +#ifdef _PR_PTHREADS + +#error "This file should not be compiled for the pthreads version" + +#else + +#ifndef _PR_HAVE_NAMED_SEMAPHORES + +PRSem * _PR_MD_OPEN_SEMAPHORE( + const char *osname, PRIntn flags, PRIntn mode, PRUintn value) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _PR_MD_WAIT_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_POST_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_CLOSE_SEMAPHORE(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _PR_MD_DELETE_SEMAPHORE(const char *osname) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +#endif /* !_PR_HAVE_NAMED_SEMAPHORES */ + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, PRIntn flags, PRIntn mode, PRUintn value) +{ + char osname[PR_IPC_NAME_SIZE]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) { + return NULL; + } + return _PR_MD_OPEN_SEMAPHORE(osname, flags, mode, value); +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + return _PR_MD_WAIT_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + return _PR_MD_POST_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + return _PR_MD_CLOSE_SEMAPHORE(sem); +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + char osname[PR_IPC_NAME_SIZE]; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) { + return PR_FAILURE; + } + return _PR_MD_DELETE_SEMAPHORE(osname); +} + +#endif /* _PR_PTHREADS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlog2.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlog2.c new file mode 100644 index 00000000..d1a688ad --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlog2.c @@ -0,0 +1,81 @@ +/* -*- 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 "prbit.h" + +/* +** Compute the log of the least power of 2 greater than or equal to n +*/ +PR_IMPLEMENT(PRIntn) PR_CeilingLog2(PRUint32 n) +{ + PRIntn log2 = 0; + + if (n & (n-1)) + log2++; + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} + +/* +** Compute the log of the greatest power of 2 less than or equal to n. +** This really just finds the highest set bit in the word. +*/ +PR_IMPLEMENT(PRIntn) PR_FloorLog2(PRUint32 n) +{ + PRIntn log2 = 0; + + if (n >> 16) + log2 += 16, n >>= 16; + if (n >> 8) + log2 += 8, n >>= 8; + if (n >> 4) + log2 += 4, n >>= 4; + if (n >> 2) + log2 += 2, n >>= 2; + if (n >> 1) + log2++; + return log2; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlong.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlong.c new file mode 100644 index 00000000..ad1c2a0d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prlong.c @@ -0,0 +1,282 @@ +/* -*- 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" + +static PRInt64 ll_zero = LL_INIT( 0x00000000,0x00000000 ); +static PRInt64 ll_maxint = LL_INIT( 0x7fffffff, 0xffffffff ); +static PRInt64 ll_minint = LL_INIT( 0x80000000, 0x00000000 ); +static PRUint64 ll_maxuint = LL_INIT( 0xffffffff, 0xffffffff ); + +#if defined(HAVE_WATCOM_BUG_2) +PRInt64 __pascal __loadds __export + LL_Zero(void) { return ll_zero; } +PRInt64 __pascal __loadds __export + LL_MaxInt(void) { return ll_maxint; } +PRInt64 __pascal __loadds __export + LL_MinInt(void) { return ll_minint; } +PRUint64 __pascal __loadds __export + LL_MaxUint(void) { return ll_maxuint; } +#else +PR_IMPLEMENT(PRInt64) LL_Zero(void) { return ll_zero; } +PR_IMPLEMENT(PRInt64) LL_MaxInt(void) { return ll_maxint; } +PR_IMPLEMENT(PRInt64) LL_MinInt(void) { return ll_minint; } +PR_IMPLEMENT(PRUint64) LL_MaxUint(void) { return ll_maxuint; } +#endif + +#ifndef HAVE_LONG_LONG +/* +** Divide 64-bit a by 32-bit b, which must be normalized so its high bit is 1. +*/ +static void norm_udivmod32(PRUint32 *qp, PRUint32 *rp, PRUint64 a, PRUint32 b) +{ + PRUint32 d1, d0, q1, q0; + PRUint32 r1, r0, m; + + d1 = _hi16(b); + d0 = _lo16(b); + r1 = a.hi % d1; + q1 = a.hi / d1; + m = q1 * d0; + r1 = (r1 << 16) | _hi16(a.lo); + if (r1 < m) { + q1--, r1 += b; + if (r1 >= b /* i.e., we didn't get a carry when adding to r1 */ + && r1 < m) { + q1--, r1 += b; + } + } + r1 -= m; + r0 = r1 % d1; + q0 = r1 / d1; + m = q0 * d0; + r0 = (r0 << 16) | _lo16(a.lo); + if (r0 < m) { + q0--, r0 += b; + if (r0 >= b + && r0 < m) { + q0--, r0 += b; + } + } + *qp = (q1 << 16) | q0; + *rp = r0 - m; +} + +static PRUint32 CountLeadingZeros(PRUint32 a) +{ + PRUint32 t; + PRUint32 r = 32; + + if ((t = a >> 16) != 0) + r -= 16, a = t; + if ((t = a >> 8) != 0) + r -= 8, a = t; + if ((t = a >> 4) != 0) + r -= 4, a = t; + if ((t = a >> 2) != 0) + r -= 2, a = t; + if ((t = a >> 1) != 0) + r -= 1, a = t; + if (a & 1) + r--; + return r; +} + +PR_IMPLEMENT(void) ll_udivmod(PRUint64 *qp, PRUint64 *rp, PRUint64 a, PRUint64 b) +{ + PRUint32 n0, n1, n2; + PRUint32 q0, q1; + PRUint32 rsh, lsh; + + n0 = a.lo; + n1 = a.hi; + + if (b.hi == 0) { + if (b.lo > n1) { + /* (0 q0) = (n1 n0) / (0 D0) */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh) { + /* + * Normalize, i.e. make the most significant bit of the + * denominator be set. + */ + b.lo = b.lo << lsh; + n1 = (n1 << lsh) | (n0 >> (32 - lsh)); + n0 = n0 << lsh; + } + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + q1 = 0; + + /* remainder is in n0 >> lsh */ + } else { + /* (q1 q0) = (n1 n0) / (0 d0) */ + + if (b.lo == 0) /* user wants to divide by zero! */ + b.lo = 1 / b.lo; /* so go ahead and crash */ + + lsh = CountLeadingZeros(b.lo); + + if (lsh == 0) { + /* + * From (n1 >= b.lo) + * && (the most significant bit of b.lo is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the leading quotient digit q1 = 1). + * + * This special case is necessary, not an optimization + * (Shifts counts of 32 are undefined). + */ + n1 -= b.lo; + q1 = 1; + } else { + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q1, &n1, a, b.lo); + } + + /* n1 != b.lo... */ + + a.lo = n0, a.hi = n1; + norm_udivmod32(&q0, &n0, a, b.lo); + + /* remainder in n0 >> lsh */ + } + + if (rp) { + rp->lo = n0 >> lsh; + rp->hi = 0; + } + } else { + if (b.hi > n1) { + /* (0 0) = (n1 n0) / (D1 d0) */ + + q0 = 0; + q1 = 0; + + /* remainder in (n1 n0) */ + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + /* (0 q0) = (n1 n0) / (d1 d0) */ + + lsh = CountLeadingZeros(b.hi); + if (lsh == 0) { + /* + * From (n1 >= b.hi) + * && (the most significant bit of b.hi is set), + * conclude that + * (the most significant bit of n1 is set) + * && (the quotient digit q0 = 0 or 1). + * + * This special case is necessary, not an optimization. + */ + + /* + * The condition on the next line takes advantage of that + * n1 >= b.hi (true due to control flow). + */ + if (n1 > b.hi || n0 >= b.lo) { + q0 = 1; + a.lo = n0, a.hi = n1; + LL_SUB(a, a, b); + } else { + q0 = 0; + } + q1 = 0; + + if (rp) { + rp->lo = n0; + rp->hi = n1; + } + } else { + PRInt64 m; + + /* + * Normalize. + */ + rsh = 32 - lsh; + + b.hi = (b.hi << lsh) | (b.lo >> rsh); + b.lo = b.lo << lsh; + n2 = n1 >> rsh; + n1 = (n1 << lsh) | (n0 >> rsh); + n0 = n0 << lsh; + + a.lo = n1, a.hi = n2; + norm_udivmod32(&q0, &n1, a, b.hi); + LL_MUL32(m, q0, b.lo); + + if ((m.hi > n1) || ((m.hi == n1) && (m.lo > n0))) { + q0--; + LL_SUB(m, m, b); + } + + q1 = 0; + + /* Remainder is ((n1 n0) - (m1 m0)) >> lsh */ + if (rp) { + a.lo = n0, a.hi = n1; + LL_SUB(a, a, m); + rp->lo = (a.hi << rsh) | (a.lo >> lsh); + rp->hi = a.hi >> lsh; + } + } + } + } + + if (qp) { + qp->lo = q0; + qp->hi = q1; + } +} +#endif /* !HAVE_LONG_LONG */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prnetdb.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prnetdb.c new file mode 100644 index 00000000..c47d2abd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prnetdb.c @@ -0,0 +1,2189 @@ +/* -*- 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 + +/* + * On Unix, the error code for gethostbyname() and gethostbyaddr() + * is returned in the global variable h_errno, instead of the usual + * errno. + */ +#if defined(XP_UNIX) +#if defined(_PR_NEED_H_ERRNO) +extern int h_errno; +#endif +#define _MD_GETHOST_ERRNO() h_errno +#else +#define _MD_GETHOST_ERRNO() _MD_ERRNO() +#endif + +/* + * The meaning of the macros related to gethostbyname, gethostbyaddr, + * and gethostbyname2 is defined below. + * - _PR_HAVE_THREADSAFE_GETHOST: the gethostbyXXX functions return + * the result in thread specific storage. For example, AIX, HP-UX, + * and OSF1. + * - _PR_HAVE_GETHOST_R: have the gethostbyXXX_r functions. See next + * two macros. + * - _PR_HAVE_GETHOST_R_INT: the gethostbyXXX_r functions return an + * int. For example, Linux glibc. + * - _PR_HAVE_GETHOST_R_POINTER: the gethostbyXXX_r functions return + * a struct hostent* pointer. For example, Solaris and IRIX. + */ +#if defined(_PR_NO_PREEMPT) || defined(_PR_HAVE_GETHOST_R) \ + || defined(_PR_HAVE_THREADSAFE_GETHOST) +#define _PR_NO_DNS_LOCK +#endif + +#if defined(_PR_NO_DNS_LOCK) +#define LOCK_DNS() +#define UNLOCK_DNS() +#else +PRLock *_pr_dnsLock = NULL; +#define LOCK_DNS() PR_Lock(_pr_dnsLock) +#define UNLOCK_DNS() PR_Unlock(_pr_dnsLock) +#endif /* defined(_PR_NO_DNS_LOCK) */ + +/* + * Some platforms have the reentrant getprotobyname_r() and + * getprotobynumber_r(). However, they come in two flavors. + * Some return a pointer to struct protoent, others return + * an int. + */ +#if defined(XP_BEOS) && defined(BONE_VERSION) +#include /* pick up define for inet_addr */ +#include +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_POINTER +#endif + +#if defined(SOLARIS) || (defined(BSDI) && defined(_REENTRANT)) \ + || (defined(LINUX) && defined(_REENTRANT) \ + && !(defined(__GLIBC__) && __GLIBC__ >= 2)) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_POINTER +#endif + +#if defined(OSF1) \ + || defined(AIX4_3_PLUS) || (defined(AIX) && defined(_THREAD_SAFE)) \ + || (defined(HPUX10_10) && defined(_REENTRANT)) \ + || (defined(HPUX10_20) && defined(_REENTRANT)) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_GETPROTO_R_INT +#endif + +#if (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2) +#define _PR_HAVE_GETPROTO_R +#define _PR_HAVE_5_ARG_GETPROTO_R +#endif + +#if !defined(_PR_HAVE_GETPROTO_R) +PRLock* _getproto_lock = NULL; +#endif + +#if defined(_PR_INET6_PROBE) +PR_EXTERN(PRBool) _pr_ipv6_is_present; +#endif + +#define _PR_IN6_IS_ADDR_UNSPECIFIED(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0) && \ + ((a)->pr_s6_addr32[3] == 0)) + +#define _PR_IN6_IS_ADDR_LOOPBACK(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0) && \ + ((a)->pr_s6_addr[12] == 0) && \ + ((a)->pr_s6_addr[13] == 0) && \ + ((a)->pr_s6_addr[14] == 0) && \ + ((a)->pr_s6_addr[15] == 0x1U)) + +const PRIPv6Addr _pr_in6addr_any = {{{ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 }}}; + +const PRIPv6Addr _pr_in6addr_loopback = {{{ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0x1U }}}; +/* + * The values at bytes 10 and 11 are compared using pointers to + * 8-bit fields, and not 32-bit fields, to make the comparison work on + * both big-endian and little-endian systems + */ + +#define _PR_IN6_IS_ADDR_V4MAPPED(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr[8] == 0) && \ + ((a)->pr_s6_addr[9] == 0) && \ + ((a)->pr_s6_addr[10] == 0xff) && \ + ((a)->pr_s6_addr[11] == 0xff)) + +#define _PR_IN6_IS_ADDR_V4COMPAT(a) \ + (((a)->pr_s6_addr32[0] == 0) && \ + ((a)->pr_s6_addr32[1] == 0) && \ + ((a)->pr_s6_addr32[2] == 0)) + +#define _PR_IN6_V4MAPPED_TO_IPADDR(a) ((a)->pr_s6_addr32[3]) + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + +/* + * The _pr_QueryNetIfs() function finds out if the system has + * IPv4 or IPv6 source addresses configured and sets _pr_have_inet_if + * and _pr_have_inet6_if accordingly. + * + * We have an implementation using SIOCGIFCONF ioctl and a + * default implementation that simply sets _pr_have_inet_if + * and _pr_have_inet6_if to true. A better implementation + * would be to use the routing sockets (see Chapter 17 of + * W. Richard Stevens' Unix Network Programming, Vol. 1, 2nd. Ed.) + */ + +static PRLock *_pr_query_ifs_lock = NULL; +static PRBool _pr_have_inet_if = PR_FALSE; +static PRBool _pr_have_inet6_if = PR_FALSE; + +#undef DEBUG_QUERY_IFS + +#if defined(AIX) \ + || (defined(DARWIN) && (!defined(HAVE_GETIFADDRS) \ + || (defined(MACOS_DEPLOYMENT_TARGET) \ + && MACOS_DEPLOYMENT_TARGET < 100200))) + +/* + * Use SIOCGIFCONF ioctl on platforms that don't have routing + * sockets. Warning: whether SIOCGIFCONF ioctl returns AF_INET6 + * network interfaces is not portable. + * + * The _pr_QueryNetIfs() function is derived from the code in + * src/lib/libc/net/getifaddrs.c in BSD Unix and the code in + * Section 16.6 of W. Richard Stevens' Unix Network Programming, + * Vol. 1, 2nd. Ed. + */ + +#include +#include +#include +#include + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfreq(struct ifreq *ifr) +{ + PRNetAddr addr; + struct sockaddr *sa; + const char* family; + char addrstr[64]; + + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + memcpy(&addr.inet.ip, &sin->sin_addr, sizeof(sin->sin_addr)); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + memcpy(&addr.ipv6.ip, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + addr.raw.family = sa->sa_family; + PR_NetAddrToString(&addr, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifr->ifr_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + int sock; + int rv; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq *lifr; + PRUint32 len, lastlen; + char *buf; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + return; + } + + /* Issue SIOCGIFCONF request in a loop. */ + lastlen = 0; + len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ + for (;;) { + buf = (char *)PR_Malloc(len); + if (NULL == buf) { + close(sock); + return; + } + ifc.ifc_buf = buf; + ifc.ifc_len = len; + rv = ioctl(sock, SIOCGIFCONF, &ifc); + if (rv < 0) { + if (errno != EINVAL || lastlen != 0) { + close(sock); + PR_Free(buf); + return; + } + } else { + if (ifc.ifc_len == lastlen) + break; /* success, len has not changed */ + lastlen = ifc.ifc_len; + } + len += 10 * sizeof(struct ifreq); /* increment */ + PR_Free(buf); + } + close(sock); + + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + int sa_len; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfreq(ifr); +#endif + sa = &ifr->ifr_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = PR_TRUE; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = PR_TRUE; + } + } + +#ifdef _PR_HAVE_SOCKADDR_LEN + sa_len = PR_MAX(sa->sa_len, sizeof(struct sockaddr)); +#else + switch (sa->sa_family) { +#ifdef AF_LINK + case AF_LINK: + sa_len = sizeof(struct sockaddr_dl); + break; +#endif + case AF_INET6: + sa_len = sizeof(struct sockaddr_in6); + break; + default: + sa_len = sizeof(struct sockaddr); + break; + } +#endif + ifr = (struct ifreq *)(((char *)sa) + sa_len); + } + PR_Free(buf); +} + +#elif (defined(DARWIN) && defined(HAVE_GETIFADDRS)) || defined(FREEBSD) \ + || defined(NETBSD) || defined(OPENBSD) + +/* + * Use the BSD getifaddrs function. + */ + +#include +#include +#include +#include + +#ifdef DEBUG_QUERY_IFS +static void +_pr_PrintIfaddrs(struct ifaddrs *ifa) +{ + struct sockaddr *sa; + const char* family; + void *addrp; + char addrstr[64]; + + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + family = "inet"; + addrp = &sin->sin_addr; + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + family = "inet6"; + addrp = &sin6->sin6_addr; + } else { + return; /* skip if not AF_INET or AF_INET6 */ + } + inet_ntop(sa->sa_family, addrp, addrstr, sizeof(addrstr)); + printf("%s: %s %s\n", ifa->ifa_name, family, addrstr); +} +#endif + +static void +_pr_QueryNetIfs(void) +{ + struct ifaddrs *ifp; + struct ifaddrs *ifa; + + if (getifaddrs(&ifp) == -1) { + return; + } + for (ifa = ifp; ifa; ifa = ifa->ifa_next) { + struct sockaddr *sa; + +#ifdef DEBUG_QUERY_IFS + _pr_PrintIfaddrs(ifa); +#endif + sa = ifa->ifa_addr; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + _pr_have_inet_if = 1; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + if (!IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + _pr_have_inet6_if = 1; + } + } + } + freeifaddrs(ifp); +} + +#else /* default */ + +/* + * Emulate the code in NSPR 4.2 or older. PR_GetIPNodeByName behaves + * as if the system had both IPv4 and IPv6 source addresses configured. + */ +static void +_pr_QueryNetIfs(void) +{ + _pr_have_inet_if = PR_TRUE; + _pr_have_inet6_if = PR_TRUE; +} + +#endif + +#endif /* _PR_INET6 && _PR_HAVE_GETHOSTBYNAME2 */ + +void _PR_InitNet(void) +{ +#if defined(XP_UNIX) +#ifdef HAVE_NETCONFIG + /* + * This one-liner prevents the endless re-open's and re-read's of + * /etc/netconfig on EACH and EVERY call to accept(), connect(), etc. + */ + (void)setnetconfig(); +#endif +#endif +#if !defined(_PR_NO_DNS_LOCK) + _pr_dnsLock = PR_NewLock(); +#endif +#if !defined(_PR_HAVE_GETPROTO_R) + _getproto_lock = PR_NewLock(); +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + _pr_query_ifs_lock = PR_NewLock(); +#endif +} + +void _PR_CleanupNet(void) +{ +#if !defined(_PR_NO_DNS_LOCK) + if (_pr_dnsLock) { + PR_DestroyLock(_pr_dnsLock); + _pr_dnsLock = NULL; + } +#endif +#if !defined(_PR_HAVE_GETPROTO_R) + if (_getproto_lock) { + PR_DestroyLock(_getproto_lock); + _getproto_lock = NULL; + } +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + if (_pr_query_ifs_lock) { + PR_DestroyLock(_pr_query_ifs_lock); + _pr_query_ifs_lock = NULL; + } +#endif +} + +/* +** Allocate space from the buffer, aligning it to "align" before doing +** the allocation. "align" must be a power of 2. +*/ +static char *Alloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align) +{ + char *buf = *bufp; + PRIntn buflen = *buflenp; + + if (align && ((long)buf & (align - 1))) { + PRIntn skip = align - ((ptrdiff_t)buf & (align - 1)); + if (buflen < skip) { + return 0; + } + buf += skip; + buflen -= skip; + } + if (buflen < amount) { + return 0; + } + *bufp = buf + amount; + *buflenp = buflen - amount; + return buf; +} + +typedef enum _PRIPAddrConversion { + _PRIPAddrNoConversion, + _PRIPAddrIPv4Mapped, + _PRIPAddrIPv4Compat +} _PRIPAddrConversion; + +/* +** Convert an IPv4 address (v4) to an IPv4-mapped IPv6 address (v6). +*/ +static void MakeIPv4MappedAddr(const char *v4, char *v6) +{ + memset(v6, 0, 10); + memset(v6 + 10, 0xff, 2); + memcpy(v6 + 12, v4, 4); +} + +/* +** Convert an IPv4 address (v4) to an IPv4-compatible IPv6 address (v6). +*/ +static void MakeIPv4CompatAddr(const char *v4, char *v6) +{ + memset(v6, 0, 12); + memcpy(v6 + 12, v4, 4); +} + +/* +** Copy a hostent, and all of the memory that it refers to into +** (hopefully) stacked buffers. +*/ +static PRStatus CopyHostent( + struct hostent *from, + char **buf, + PRIntn *bufsize, + _PRIPAddrConversion conversion, + PRHostEnt *to) +{ + PRIntn len, na; + char **ap; + + if (conversion != _PRIPAddrNoConversion + && from->h_addrtype == AF_INET) { + PR_ASSERT(from->h_length == 4); + to->h_addrtype = PR_AF_INET6; + to->h_length = 16; + } else { +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) + if (AF_INET6 == from->h_addrtype) + to->h_addrtype = PR_AF_INET6; + else +#endif + to->h_addrtype = from->h_addrtype; + to->h_length = from->h_length; + } + + /* Copy the official name */ + if (!from->h_name) return PR_FAILURE; + len = strlen(from->h_name) + 1; + to->h_name = Alloc(len, buf, bufsize, 0); + if (!to->h_name) return PR_FAILURE; + memcpy(to->h_name, from->h_name, len); + + /* Count the aliases, then allocate storage for the pointers */ + if (!from->h_aliases) { + na = 1; + } else { + for (na = 1, ap = from->h_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ + } + to->h_aliases = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!to->h_aliases) return PR_FAILURE; + + /* Copy the aliases, one at a time */ + if (!from->h_aliases) { + to->h_aliases[0] = 0; + } else { + for (na = 0, ap = from->h_aliases; *ap != 0; na++, ap++) { + len = strlen(*ap) + 1; + to->h_aliases[na] = Alloc(len, buf, bufsize, 0); + if (!to->h_aliases[na]) return PR_FAILURE; + memcpy(to->h_aliases[na], *ap, len); + } + to->h_aliases[na] = 0; + } + + /* Count the addresses, then allocate storage for the pointers */ + for (na = 1, ap = from->h_addr_list; *ap != 0; na++, ap++){;} /* nothing to execute */ + to->h_addr_list = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!to->h_addr_list) return PR_FAILURE; + + /* Copy the addresses, one at a time */ + for (na = 0, ap = from->h_addr_list; *ap != 0; na++, ap++) { + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); + if (!to->h_addr_list[na]) return PR_FAILURE; + if (conversion != _PRIPAddrNoConversion + && from->h_addrtype == AF_INET) { + if (conversion == _PRIPAddrIPv4Mapped) { + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); + } else { + PR_ASSERT(conversion == _PRIPAddrIPv4Compat); + MakeIPv4CompatAddr(*ap, to->h_addr_list[na]); + } + } else { + memcpy(to->h_addr_list[na], *ap, to->h_length); + } + } + to->h_addr_list[na] = 0; + return PR_SUCCESS; +} + +#if !defined(_PR_HAVE_GETPROTO_R) +/* +** Copy a protoent, and all of the memory that it refers to into +** (hopefully) stacked buffers. +*/ +static PRStatus CopyProtoent( + struct protoent *from, char *buf, PRIntn bufsize, PRProtoEnt *to) +{ + PRIntn len, na; + char **ap; + + /* Do the easy stuff */ + to->p_num = from->p_proto; + + /* Copy the official name */ + if (!from->p_name) return PR_FAILURE; + len = strlen(from->p_name) + 1; + to->p_name = Alloc(len, &buf, &bufsize, 0); + if (!to->p_name) return PR_FAILURE; + memcpy(to->p_name, from->p_name, len); + + /* Count the aliases, then allocate storage for the pointers */ + for (na = 1, ap = from->p_aliases; *ap != 0; na++, ap++){;} /* nothing to execute */ + to->p_aliases = (char**)Alloc( + na * sizeof(char*), &buf, &bufsize, sizeof(char**)); + if (!to->p_aliases) return PR_FAILURE; + + /* Copy the aliases, one at a time */ + for (na = 0, ap = from->p_aliases; *ap != 0; na++, ap++) { + len = strlen(*ap) + 1; + to->p_aliases[na] = Alloc(len, &buf, &bufsize, 0); + if (!to->p_aliases[na]) return PR_FAILURE; + memcpy(to->p_aliases[na], *ap, len); + } + to->p_aliases[na] = 0; + + return PR_SUCCESS; +} +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ + +/* + * ################################################################# + * NOTE: tmphe, tmpbuf, bufsize, h, and h_err are local variables + * or arguments of PR_GetHostByName, PR_GetIPNodeByName, and + * PR_GetHostByAddr. DO NOT CHANGE THE NAMES OF THESE LOCAL + * VARIABLES OR ARGUMENTS. + * ################################################################# + */ +#if defined(_PR_HAVE_GETHOST_R_INT) + +#define GETHOSTBYNAME(name) \ + (gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h, &h_err), h) +#define GETHOSTBYNAME2(name, af) \ + (gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h, &h_err), h) +#define GETHOSTBYADDR(addr, addrlen, af) \ + (gethostbyaddr_r(addr, addrlen, af, \ + &tmphe, tmpbuf, bufsize, &h, &h_err), h) + +#elif defined(_PR_HAVE_GETHOST_R_POINTER) + +#define GETHOSTBYNAME(name) \ + gethostbyname_r(name, &tmphe, tmpbuf, bufsize, &h_err) +#define GETHOSTBYNAME2(name, af) \ + gethostbyname2_r(name, af, &tmphe, tmpbuf, bufsize, &h_err) +#define GETHOSTBYADDR(addr, addrlen, af) \ + gethostbyaddr_r(addr, addrlen, af, &tmphe, tmpbuf, bufsize, &h_err) + +#else + +#define GETHOSTBYNAME(name) gethostbyname(name) +#define GETHOSTBYNAME2(name, af) gethostbyname2(name, af) +#define GETHOSTBYADDR(addr, addrlen, af) gethostbyaddr(addr, addrlen, af) + +#endif /* definition of GETHOSTBYXXX */ + +PR_IMPLEMENT(PRStatus) PR_GetHostByName( + const char *name, char *buf, PRIntn bufsize, PRHostEnt *hp) +{ + struct hostent *h; + PRStatus rv = PR_FAILURE; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + LOCK_DNS(); + +#ifdef XP_OS2_VACPP + h = GETHOSTBYNAME((char *)name); +#else + h = GETHOSTBYNAME(name); +#endif + + if (NULL == h) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + UNLOCK_DNS(); +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + return rv; +} + +#if !defined(_PR_INET6) && \ + defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) +typedef struct hostent * (*_pr_getipnodebyname_t)(const char *, int, + int, int *); +typedef struct hostent * (*_pr_getipnodebyaddr_t)(const void *, size_t, + int, int *); +typedef void (*_pr_freehostent_t)(struct hostent *); +static void * _pr_getipnodebyname_fp; +static void * _pr_getipnodebyaddr_fp; +static void * _pr_freehostent_fp; + +/* + * Look up the addresses of getipnodebyname, getipnodebyaddr, + * and freehostent. + */ +PRStatus +_pr_find_getipnodebyname(void) +{ + PRLibrary *lib; + PRStatus rv; +#if defined(VMS) +#define GETIPNODEBYNAME getenv("GETIPNODEBYNAME") +#define GETIPNODEBYADDR getenv("GETIPNODEBYADDR") +#define FREEHOSTENT getenv("FREEHOSTENT") +#else +#define GETIPNODEBYNAME "getipnodebyname" +#define GETIPNODEBYADDR "getipnodebyaddr" +#define FREEHOSTENT "freehostent" +#endif + _pr_getipnodebyname_fp = PR_FindSymbolAndLibrary(GETIPNODEBYNAME, &lib); + if (NULL != _pr_getipnodebyname_fp) { + _pr_freehostent_fp = PR_FindSymbol(lib, FREEHOSTENT); + if (NULL != _pr_freehostent_fp) { + _pr_getipnodebyaddr_fp = PR_FindSymbol(lib, GETIPNODEBYADDR); + if (NULL != _pr_getipnodebyaddr_fp) + rv = PR_SUCCESS; + else + rv = PR_FAILURE; + } else + rv = PR_FAILURE; + (void)PR_UnloadLibrary(lib); + } else + rv = PR_FAILURE; + return rv; +} +#endif + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) +/* +** Append the V4 addresses to the end of the list +*/ +static PRStatus AppendV4AddrsToHostent( + struct hostent *from, + char **buf, + PRIntn *bufsize, + PRHostEnt *to) +{ + PRIntn na, na_old; + char **ap; + char **new_addr_list; + + /* Count the addresses, then grow storage for the pointers */ + for (na_old = 0, ap = to->h_addr_list; *ap != 0; na_old++, ap++) + {;} /* nothing to execute */ + for (na = na_old + 1, ap = from->h_addr_list; *ap != 0; na++, ap++) + {;} /* nothing to execute */ + new_addr_list = (char**)Alloc( + na * sizeof(char*), buf, bufsize, sizeof(char**)); + if (!new_addr_list) return PR_FAILURE; + + /* Copy the V6 addresses, one at a time */ + for (na = 0, ap = to->h_addr_list; *ap != 0; na++, ap++) { + new_addr_list[na] = to->h_addr_list[na]; + } + to->h_addr_list = new_addr_list; + + /* Copy the V4 addresses, one at a time */ + for (ap = from->h_addr_list; *ap != 0; na++, ap++) { + to->h_addr_list[na] = Alloc(to->h_length, buf, bufsize, 0); + if (!to->h_addr_list[na]) return PR_FAILURE; + MakeIPv4MappedAddr(*ap, to->h_addr_list[na]); + } + to->h_addr_list[na] = 0; + return PR_SUCCESS; +} +#endif + +PR_IMPLEMENT(PRStatus) PR_GetIPNodeByName( + const char *name, PRUint16 af, PRIntn flags, + char *buf, PRIntn bufsize, PRHostEnt *hp) +{ + struct hostent *h = 0; + PRStatus rv = PR_FAILURE; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif +#if defined(_PR_HAVE_GETIPNODEBYNAME) + PRUint16 md_af = af; + int error_num; + int tmp_flags = 0; +#endif +#if defined(_PR_HAVE_GETHOSTBYNAME2) + PRBool did_af_inet = PR_FALSE; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (af != PR_AF_INET && af != PR_AF_INET6) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + PR_Lock(_pr_query_ifs_lock); + /* + * Keep querying the presence of IPv4 and IPv6 interfaces until + * at least one is up. This allows us to detect the local + * machine going from offline to online. + */ + if (!_pr_have_inet_if && !_pr_have_inet6_if) { + _pr_QueryNetIfs(); +#ifdef DEBUG_QUERY_IFS + if (_pr_have_inet_if) + printf("Have IPv4 source address\n"); + if (_pr_have_inet6_if) + printf("Have IPv6 source address\n"); +#endif + } + PR_Unlock(_pr_query_ifs_lock); +#endif + +#if defined(_PR_HAVE_GETIPNODEBYNAME) + if (flags & PR_AI_V4MAPPED) + tmp_flags |= AI_V4MAPPED; + if (flags & PR_AI_ADDRCONFIG) + tmp_flags |= AI_ADDRCONFIG; + if (flags & PR_AI_ALL) + tmp_flags |= AI_ALL; + if (af == PR_AF_INET6) + md_af = AF_INET6; + else + md_af = af; +#endif + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + /* Do not need to lock the DNS lock if getipnodebyname() is called */ +#ifdef _PR_INET6 +#ifdef _PR_HAVE_GETHOSTBYNAME2 + LOCK_DNS(); + if (af == PR_AF_INET6) + { + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet6_if) + { +#ifdef _PR_INET6_PROBE + if (_pr_ipv6_is_present == PR_TRUE) +#endif + h = GETHOSTBYNAME2(name, AF_INET6); + } + if ((NULL == h) && (flags & PR_AI_V4MAPPED) + && ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if)) + { + did_af_inet = PR_TRUE; + h = GETHOSTBYNAME2(name, AF_INET); + } + } + else + { + if ((flags & PR_AI_ADDRCONFIG) == 0 || _pr_have_inet_if) + { + did_af_inet = PR_TRUE; + h = GETHOSTBYNAME2(name, af); + } + } +#elif defined(_PR_HAVE_GETIPNODEBYNAME) + h = getipnodebyname(name, md_af, tmp_flags, &error_num); +#else +#error "Unknown name-to-address translation function" +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present == PR_TRUE) + { +#ifdef PR_GETIPNODE_NOT_THREADSAFE + LOCK_DNS(); +#endif + h = (*((_pr_getipnodebyname_t)_pr_getipnodebyname_fp))(name, md_af, tmp_flags, &error_num); + } + else + { + LOCK_DNS(); + h = GETHOSTBYNAME(name); + } +#else /* _PR_INET6 */ + LOCK_DNS(); +#ifdef XP_OS2_VACPP + h = GETHOSTBYNAME((char *)name); +#else + h = GETHOSTBYNAME(name); +#endif +#endif /* _PR_INET6 */ + + if (NULL == h) + { +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present == PR_TRUE) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); + else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#endif + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + + if (af == PR_AF_INET6) conversion = _PRIPAddrIPv4Mapped; + rv = CopyHostent(h, &buf, &bufsize, conversion, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) + freehostent(h); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) + if (_pr_ipv6_is_present == PR_TRUE) + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); +#endif +#if defined(_PR_INET6) && defined(_PR_HAVE_GETHOSTBYNAME2) + if ((PR_SUCCESS == rv) && (flags & PR_AI_V4MAPPED) + && ((flags & PR_AI_ALL) + || ((flags & PR_AI_ADDRCONFIG) && _pr_have_inet_if)) + && !did_af_inet && (h = GETHOSTBYNAME2(name, AF_INET)) != 0) { + rv = AppendV4AddrsToHostent(h, &buf, &bufsize, hp); + if (PR_SUCCESS != rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } +#endif + } + + /* Must match the convoluted logic above for LOCK_DNS() */ +#ifdef _PR_INET6 +#ifdef _PR_HAVE_GETHOSTBYNAME2 + UNLOCK_DNS(); +#endif /* _PR_HAVE_GETHOSTBYNAME2 */ +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYNAME) +#ifdef PR_GETIPNODE_NOT_THREADSAFE + UNLOCK_DNS(); +#else + if (_pr_ipv6_is_present == PR_FALSE) + UNLOCK_DNS(); +#endif +#else /* _PR_INET6 */ + UNLOCK_DNS(); +#endif /* _PR_INET6 */ + +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_GetHostByAddr( + const PRNetAddr *hostaddr, char *buf, PRIntn bufsize, PRHostEnt *hostentry) +{ + struct hostent *h; + PRStatus rv = PR_FAILURE; + const void *addr; + PRUint32 tmp_ip; + int addrlen; + PRInt32 af; +#if defined(_PR_HAVE_GETHOST_R) + char localbuf[PR_NETDB_BUF_SIZE]; + char *tmpbuf; + struct hostent tmphe; + int h_err; +#endif +#if defined(_PR_HAVE_GETIPNODEBYADDR) + int error_num; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (hostaddr->raw.family == PR_AF_INET6) + { +#if defined(_PR_INET6_PROBE) + if (_pr_ipv6_is_present == PR_TRUE) + af = AF_INET6; + else + af = AF_INET; +#elif defined(_PR_INET6) + af = AF_INET6; +#else + af = AF_INET; +#endif +#if defined(_PR_GHBA_DISALLOW_V4MAPPED) + if (_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) + af = AF_INET; +#endif + } + else + { + PR_ASSERT(hostaddr->raw.family == AF_INET); + af = AF_INET; + } + if (hostaddr->raw.family == PR_AF_INET6) { +#if defined(_PR_INET6) || defined(_PR_INET6_PROBE) + if (af == AF_INET6) { + addr = &hostaddr->ipv6.ip; + addrlen = sizeof(hostaddr->ipv6.ip); + } + else +#endif + { + PR_ASSERT(af == AF_INET); + if (!_PR_IN6_IS_ADDR_V4MAPPED(&hostaddr->ipv6.ip)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + tmp_ip = _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *) + &hostaddr->ipv6.ip); + addr = &tmp_ip; + addrlen = sizeof(tmp_ip); + } + } else { + PR_ASSERT(hostaddr->raw.family == AF_INET); + PR_ASSERT(af == AF_INET); + addr = &hostaddr->inet.ip; + addrlen = sizeof(hostaddr->inet.ip); + } + +#if defined(_PR_HAVE_GETHOST_R) + tmpbuf = localbuf; + if (bufsize > sizeof(localbuf)) + { + tmpbuf = (char *)PR_Malloc(bufsize); + if (NULL == tmpbuf) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return rv; + } + } +#endif + + /* Do not need to lock the DNS lock if getipnodebyaddr() is called */ +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) + h = getipnodebyaddr(addr, addrlen, af, &error_num); +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) + if (_pr_ipv6_is_present == PR_TRUE) + { +#ifdef PR_GETIPNODE_NOT_THREADSAFE + LOCK_DNS(); +#endif + h = (*((_pr_getipnodebyaddr_t)_pr_getipnodebyaddr_fp))(addr, addrlen, + af, &error_num); + } + else + { + LOCK_DNS(); + h = GETHOSTBYADDR(addr, addrlen, af); + } +#else /* _PR_HAVE_GETIPNODEBYADDR */ + LOCK_DNS(); +#ifdef XP_OS2_VACPP + h = GETHOSTBYADDR((char *)addr, addrlen, af); +#else + h = GETHOSTBYADDR(addr, addrlen, af); +#endif +#endif /* _PR_HAVE_GETIPNODEBYADDR */ + if (NULL == h) + { +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) + if (_pr_ipv6_is_present == PR_TRUE) + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, error_num); + else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#else + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_GETHOST_ERRNO()); +#endif + } + else + { + _PRIPAddrConversion conversion = _PRIPAddrNoConversion; + if (hostaddr->raw.family == PR_AF_INET6) { + if (af == AF_INET) { + if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr*) + &hostaddr->ipv6.ip)) { + conversion = _PRIPAddrIPv4Mapped; + } else if (_PR_IN6_IS_ADDR_V4COMPAT((PRIPv6Addr *) + &hostaddr->ipv6.ip)) { + conversion = _PRIPAddrIPv4Compat; + } + } + } + rv = CopyHostent(h, &buf, &bufsize, conversion, hostentry); + if (PR_SUCCESS != rv) { + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } +#if defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYADDR) + freehostent(h); +#elif defined(_PR_INET6_PROBE) && defined(_PR_HAVE_GETIPNODEBYADDR) + if (_pr_ipv6_is_present == PR_TRUE) + (*((_pr_freehostent_t)_pr_freehostent_fp))(h); +#endif + } + + /* Must match the convoluted logic above for LOCK_DNS() */ +#if defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6) +#elif defined(_PR_HAVE_GETIPNODEBYADDR) && defined(_PR_INET6_PROBE) +#ifdef PR_GETIPNODE_NOT_THREADSAFE + UNLOCK_DNS(); +#else + if (_pr_ipv6_is_present == PR_FALSE) + UNLOCK_DNS(); +#endif +#else /* _PR_HAVE_GETIPNODEBYADDR */ + UNLOCK_DNS(); +#endif /* _PR_HAVE_GETIPNODEBYADDR */ + +#if defined(_PR_HAVE_GETHOST_R) + if (tmpbuf != localbuf) + PR_Free(tmpbuf); +#endif + + return rv; +} + +/******************************************************************************/ +/* + * Some systems define a reentrant version of getprotobyname(). Too bad + * the signature isn't always the same. But hey, they tried. If there + * is such a definition, use it. Otherwise, grab a lock and do it here. + */ +/******************************************************************************/ + +#if !defined(_PR_HAVE_GETPROTO_R) +/* + * This may seem like a silly thing to do, but the compiler SHOULD + * complain if getprotobyname_r() is implemented on some system and + * we're not using it. For sure these signatures are different than + * any usable implementation. + */ + +static struct protoent *getprotobyname_r(const char* name) +{ +#ifdef XP_OS2_VACPP + return getprotobyname((char *)name); +#else + return getprotobyname(name); +#endif +} /* getprotobyname_r */ + +static struct protoent *getprotobynumber_r(PRInt32 number) +{ + return getprotobynumber(number); +} /* getprotobynumber_r */ + +#endif /* !defined(_PR_HAVE_GETPROTO_R) */ + +PR_IMPLEMENT(PRStatus) PR_GetProtoByName( + const char* name, char* buffer, PRInt32 buflen, PRProtoEnt* result) +{ + PRStatus rv = PR_SUCCESS; +#if defined(_PR_HAVE_GETPROTO_R) + struct protoent* res = (struct protoent*)result; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETPROTO_R_INT) + { + /* + ** The protoent_data has a pointer as the first field. + ** That implies the buffer better be aligned, and char* + ** doesn't promise much. + */ + PRUptrdiff aligned = (PRUptrdiff)buffer; + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) + { + aligned += sizeof(struct protoent_data*) - 1; + aligned &= ~(sizeof(struct protoent_data*) - 1); + buflen -= (aligned - (PRUptrdiff)buffer); + buffer = (char*)aligned; + } + } +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ + + if (PR_NETDB_BUF_SIZE > buflen) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_HAVE_GETPROTO_R_POINTER) + if (NULL == getprotobyname_r(name, res, buffer, buflen)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_GETPROTO_R_INT) + /* + ** The buffer needs to be zero'd, and it should be + ** at least the size of a struct protoent_data. + */ + memset(buffer, 0, buflen); + if (-1 == getprotobyname_r(name, res, (struct protoent_data*)buffer)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) + /* The 5th argument for getprotobyname_r() cannot be NULL */ + if (-1 == getprotobyname_r(name, res, buffer, buflen, &res)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#else /* do it the hard way */ + { + struct protoent *staticBuf; + PR_Lock(_getproto_lock); + staticBuf = getprotobyname_r(name); + if (NULL == staticBuf) + { + rv = PR_FAILURE; + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + } + else + { + rv = CopyProtoent(staticBuf, buffer, buflen, result); + if (PR_FAILURE == rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + PR_Unlock(_getproto_lock); + } +#endif /* all that */ + return rv; +} + +PR_IMPLEMENT(PRStatus) PR_GetProtoByNumber( + PRInt32 number, char* buffer, PRInt32 buflen, PRProtoEnt* result) +{ + PRStatus rv = PR_SUCCESS; +#if defined(_PR_HAVE_GETPROTO_R) + struct protoent* res = (struct protoent*)result; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if defined(_PR_HAVE_GETPROTO_R_INT) + { + /* + ** The protoent_data has a pointer as the first field. + ** That implies the buffer better be aligned, and char* + ** doesn't promise much. + */ + PRUptrdiff aligned = (PRUptrdiff)buffer; + if (0 != (aligned & (sizeof(struct protoent_data*) - 1))) + { + aligned += sizeof(struct protoent_data*) - 1; + aligned &= ~(sizeof(struct protoent_data*) - 1); + buflen -= (aligned - (PRUptrdiff)buffer); + buffer = (char*)aligned; + } + } +#endif /* defined(_PR_HAVE_GETPROTO_R_INT) */ + + if (PR_NETDB_BUF_SIZE > buflen) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + +#if defined(_PR_HAVE_GETPROTO_R_POINTER) + if (NULL == getprotobynumber_r(number, res, buffer, buflen)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } + +#elif defined(_PR_HAVE_GETPROTO_R_INT) + /* + ** The buffer needs to be zero'd for these OS's. + */ + memset(buffer, 0, buflen); + if (-1 == getprotobynumber_r(number, res, (struct protoent_data*)buffer)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#elif defined(_PR_HAVE_5_ARG_GETPROTO_R) + /* The 5th argument for getprotobynumber_r() cannot be NULL */ + if (-1 == getprotobynumber_r(number, res, buffer, buflen, &res)) + { + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + return PR_FAILURE; + } +#else /* do it the hard way */ + { + struct protoent *staticBuf; + PR_Lock(_getproto_lock); + staticBuf = getprotobynumber_r(number); + if (NULL == staticBuf) + { + rv = PR_FAILURE; + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, _MD_ERRNO()); + } + else + { + rv = CopyProtoent(staticBuf, buffer, buflen, result); + if (PR_FAILURE == rv) + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + } + PR_Unlock(_getproto_lock); + } +#endif /* all that crap */ + return rv; + +} + +PRUintn _PR_NetAddrSize(const PRNetAddr* addr) +{ + PRUintn addrsize; + + /* + * RFC 2553 added a new field (sin6_scope_id) to + * struct sockaddr_in6. PRNetAddr's ipv6 member has a + * scope_id field to match the new field. In order to + * work with older implementations supporting RFC 2133, + * we take the size of struct sockaddr_in6 instead of + * addr->ipv6. + */ + if (AF_INET == addr->raw.family) + addrsize = sizeof(addr->inet); + else if (PR_AF_INET6 == addr->raw.family) +#if defined(_PR_INET6) + addrsize = sizeof(struct sockaddr_in6); +#else + addrsize = sizeof(addr->ipv6); +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + else if (AF_UNIX == addr->raw.family) + addrsize = sizeof(addr->local); +#endif + else addrsize = 0; + + return addrsize; +} /* _PR_NetAddrSize */ + +PR_IMPLEMENT(PRIntn) PR_EnumerateHostEnt( + PRIntn enumIndex, const PRHostEnt *hostEnt, PRUint16 port, PRNetAddr *address) +{ + void *addr = hostEnt->h_addr_list[enumIndex++]; + memset(address, 0, sizeof(PRNetAddr)); + if (NULL == addr) enumIndex = 0; + else + { + address->raw.family = hostEnt->h_addrtype; + if (PR_AF_INET6 == hostEnt->h_addrtype) + { + address->ipv6.port = htons(port); + address->ipv6.flowinfo = 0; + address->ipv6.scope_id = 0; + memcpy(&address->ipv6.ip, addr, hostEnt->h_length); + } + else + { + PR_ASSERT(AF_INET == hostEnt->h_addrtype); + address->inet.port = htons(port); + memcpy(&address->inet.ip, addr, hostEnt->h_length); + } + } + return enumIndex; +} /* PR_EnumerateHostEnt */ + +PR_IMPLEMENT(PRStatus) PR_InitializeNetAddr( + PRNetAddrValue val, PRUint16 port, PRNetAddr *addr) +{ + PRStatus rv = PR_SUCCESS; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); + addr->inet.family = AF_INET; + addr->inet.port = htons(port); + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->inet.ip = htonl(INADDR_ANY); + break; + case PR_IpAddrLoopback: + addr->inet.ip = htonl(INADDR_LOOPBACK); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* PR_InitializeNetAddr */ + +PR_IMPLEMENT(PRStatus) PR_SetNetAddr( + PRNetAddrValue val, PRUint16 af, PRUint16 port, PRNetAddr *addr) +{ + PRStatus rv = PR_SUCCESS; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (af == PR_AF_INET6) + { + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->ipv6)); + addr->ipv6.family = af; + addr->ipv6.port = htons(port); + addr->ipv6.flowinfo = 0; + addr->ipv6.scope_id = 0; + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->ipv6.ip = _pr_in6addr_any; + break; + case PR_IpAddrLoopback: + addr->ipv6.ip = _pr_in6addr_loopback; + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + } + else + { + if (val != PR_IpAddrNull) memset(addr, 0, sizeof(addr->inet)); + addr->inet.family = af; + addr->inet.port = htons(port); + switch (val) + { + case PR_IpAddrNull: + break; /* don't overwrite the address */ + case PR_IpAddrAny: + addr->inet.ip = htonl(INADDR_ANY); + break; + case PR_IpAddrLoopback: + addr->inet.ip = htonl(INADDR_LOOPBACK); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + rv = PR_FAILURE; + } + } + return rv; +} /* PR_SetNetAddr */ + +PR_IMPLEMENT(PRBool) +PR_IsNetAddrType(const PRNetAddr *addr, PRNetAddrValue val) +{ + if (addr->raw.family == PR_AF_INET6) { + if (val == PR_IpAddrAny) { + if (_PR_IN6_IS_ADDR_UNSPECIFIED((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) + == htonl(INADDR_ANY)) { + return PR_TRUE; + } + } else if (val == PR_IpAddrLoopback) { + if (_PR_IN6_IS_ADDR_LOOPBACK((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } else if (_PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip) + && _PR_IN6_V4MAPPED_TO_IPADDR((PRIPv6Addr *)&addr->ipv6.ip) + == htonl(INADDR_LOOPBACK)) { + return PR_TRUE; + } + } else if (val == PR_IpAddrV4Mapped + && _PR_IN6_IS_ADDR_V4MAPPED((PRIPv6Addr *)&addr->ipv6.ip)) { + return PR_TRUE; + } + } else { + if (addr->raw.family == AF_INET) { + if (val == PR_IpAddrAny && addr->inet.ip == htonl(INADDR_ANY)) { + return PR_TRUE; + } else if (val == PR_IpAddrLoopback + && addr->inet.ip == htonl(INADDR_LOOPBACK)) { + return PR_TRUE; + } + } + } + return PR_FALSE; +} + +#ifndef _PR_HAVE_INET_NTOP +#define XX 127 +static const unsigned char index_hex[256] = { + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, +}; + +/* + * StringToV6Addr() returns 1 if the conversion succeeds, + * or 0 if the input is not a valid IPv6 address string. + * (Same as inet_pton(AF_INET6, string, addr).) + */ +static int StringToV6Addr(const char *string, PRIPv6Addr *addr) +{ + const unsigned char *s = (const unsigned char *)string; + int section = 0; /* index of the current section (a 16-bit + * piece of the address */ + int double_colon = -1; /* index of the section after the first + * 16-bit group of zeros represented by + * the double colon */ + unsigned int val; + int len; + + /* Handle initial (double) colon */ + if (*s == ':') { + if (s[1] != ':') return 0; + s += 2; + addr->pr_s6_addr16[0] = 0; + section = double_colon = 1; + } + + while (*s) { + if (section == 8) return 0; /* too long */ + if (*s == ':') { + if (double_colon != -1) return 0; /* two double colons */ + addr->pr_s6_addr16[section++] = 0; + double_colon = section; + s++; + continue; + } + for (len = val = 0; len < 4 && index_hex[*s] != XX; len++) { + val = (val << 4) + index_hex[*s++]; + } + if (*s == '.') { + if (len == 0) return 0; /* nothing between : and . */ + break; + } + if (*s == ':') { + s++; + if (!*s) return 0; /* cannot end with single colon */ + } else if (*s) { + return 0; /* bad character */ + } + addr->pr_s6_addr16[section++] = htons((unsigned short)val); + } + + if (*s == '.') { + /* Have a trailing v4 format address */ + if (section > 6) return 0; /* not enough room */ + + /* + * The number before the '.' is decimal, but we parsed it + * as hex. That means it is in BCD. Check it for validity + * and convert it to binary. + */ + if (val > 0x0255 || (val & 0xf0) > 0x90 || (val & 0xf) > 9) return 0; + val = (val >> 8) * 100 + ((val >> 4) & 0xf) * 10 + (val & 0xf); + addr->pr_s6_addr[2 * section] = val; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section + 1] = val; + section++; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s != '.') return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section] = val; + + s++; + val = index_hex[*s++]; + if (val > 9) return 0; + while (*s >= '0' && *s <= '9') { + val = val * 10 + *s++ - '0'; + if (val > 255) return 0; + } + if (*s) return 0; /* must have exactly 4 decimal numbers */ + addr->pr_s6_addr[2 * section + 1] = val; + section++; + } + + if (double_colon != -1) { + /* Stretch the double colon */ + int tosection; + int ncopy = section - double_colon; + for (tosection = 7; ncopy--; tosection--) { + addr->pr_s6_addr16[tosection] = + addr->pr_s6_addr16[double_colon + ncopy]; + } + while (tosection >= double_colon) { + addr->pr_s6_addr16[tosection--] = 0; + } + } else if (section != 8) { + return 0; /* too short */ + } + return 1; +} +#undef XX + +static const char *basis_hex = "0123456789abcdef"; + +/* + * V6AddrToString() returns a pointer to the buffer containing + * the text string if the conversion succeeds, and NULL otherwise. + * (Same as inet_ntop(AF_INET6, addr, buf, size), except that errno + * is not set on failure.) + */ +static const char *V6AddrToString( + const PRIPv6Addr *addr, char *buf, PRUint32 size) +{ +#define STUFF(c) do { \ + if (!size--) return NULL; \ + *buf++ = (c); \ +} while (0) + + int double_colon = -1; /* index of the first 16-bit + * group of zeros represented + * by the double colon */ + int double_colon_length = 1; /* use double colon only if + * there are two or more 16-bit + * groups of zeros */ + int zero_length; + int section; + unsigned int val; + const char *bufcopy = buf; + + /* Scan to find the placement of the double colon */ + for (section = 0; section < 8; section++) { + if (addr->pr_s6_addr16[section] == 0) { + zero_length = 1; + section++; + while (section < 8 && addr->pr_s6_addr16[section] == 0) { + zero_length++; + section++; + } + /* Select the longest sequence of zeros */ + if (zero_length > double_colon_length) { + double_colon = section - zero_length; + double_colon_length = zero_length; + } + } + } + + /* Now start converting to a string */ + section = 0; + + if (double_colon == 0) { + if (double_colon_length == 6 || + (double_colon_length == 5 && addr->pr_s6_addr16[5] == 0xffff)) { + /* ipv4 format address */ + STUFF(':'); + STUFF(':'); + if (double_colon_length == 5) { + STUFF('f'); + STUFF('f'); + STUFF('f'); + STUFF('f'); + STUFF(':'); + } + if (addr->pr_s6_addr[12] > 99) STUFF(addr->pr_s6_addr[12]/100 + '0'); + if (addr->pr_s6_addr[12] > 9) STUFF((addr->pr_s6_addr[12]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[12]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[13] > 99) STUFF(addr->pr_s6_addr[13]/100 + '0'); + if (addr->pr_s6_addr[13] > 9) STUFF((addr->pr_s6_addr[13]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[13]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[14] > 99) STUFF(addr->pr_s6_addr[14]/100 + '0'); + if (addr->pr_s6_addr[14] > 9) STUFF((addr->pr_s6_addr[14]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[14]%10 + '0'); + STUFF('.'); + if (addr->pr_s6_addr[15] > 99) STUFF(addr->pr_s6_addr[15]/100 + '0'); + if (addr->pr_s6_addr[15] > 9) STUFF((addr->pr_s6_addr[15]%100)/10 + '0'); + STUFF(addr->pr_s6_addr[15]%10 + '0'); + STUFF('\0'); + return bufcopy; + } + } + + while (section < 8) { + if (section == double_colon) { + STUFF(':'); + STUFF(':'); + section += double_colon_length; + continue; + } + val = ntohs(addr->pr_s6_addr16[section]); + if (val > 0xfff) { + STUFF(basis_hex[val >> 12]); + } + if (val > 0xff) { + STUFF(basis_hex[(val >> 8) & 0xf]); + } + if (val > 0xf) { + STUFF(basis_hex[(val >> 4) & 0xf]); + } + STUFF(basis_hex[val & 0xf]); + section++; + if (section < 8 && section != double_colon) STUFF(':'); + } + STUFF('\0'); + return bufcopy; +#undef STUFF +} + +#endif /* !_PR_HAVE_INET_NTOP */ + +PR_IMPLEMENT(PRStatus) PR_StringToNetAddr(const char *string, PRNetAddr *addr) +{ + PRStatus status = PR_SUCCESS; + PRIntn rv; + +#if defined(_PR_HAVE_INET_NTOP) + rv = inet_pton(AF_INET6, string, &addr->ipv6.ip); + if (1 == rv) + { + addr->raw.family = PR_AF_INET6; + } + else + { + PR_ASSERT(0 == rv); + /* clean up after the failed inet_pton() call */ + memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip)); + rv = inet_pton(AF_INET, string, &addr->inet.ip); + if (1 == rv) + { + addr->raw.family = AF_INET; + } + else + { + PR_ASSERT(0 == rv); + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } + } +#else /* _PR_HAVE_INET_NTOP */ + rv = StringToV6Addr(string, &addr->ipv6.ip); + if (1 == rv) { + addr->raw.family = PR_AF_INET6; + return PR_SUCCESS; + } + PR_ASSERT(0 == rv); + /* clean up after the failed StringToV6Addr() call */ + memset(&addr->ipv6.ip, 0, sizeof(addr->ipv6.ip)); + + addr->inet.family = AF_INET; +#ifdef XP_OS2_VACPP + addr->inet.ip = inet_addr((char *)string); +#else + addr->inet.ip = inet_addr(string); +#endif + if ((PRUint32) -1 == addr->inet.ip) + { + /* + * The string argument is a malformed address string. + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + status = PR_FAILURE; + } +#endif /* _PR_HAVE_INET_NTOP */ + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_NetAddrToString( + const PRNetAddr *addr, char *string, PRUint32 size) +{ + if (PR_AF_INET6 == addr->raw.family) + { +#if defined(_PR_HAVE_INET_NTOP) + if (NULL == inet_ntop(AF_INET6, &addr->ipv6.ip, string, size)) +#else + if (NULL == V6AddrToString(&addr->ipv6.ip, string, size)) +#endif + { + /* the size of the result buffer is inadequate */ + PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0); + return PR_FAILURE; + } + } + else + { + if (size < 16) goto failed; + if (AF_INET != addr->raw.family) goto failed; + else + { + unsigned char *byte = (unsigned char*)&addr->inet.ip; + PR_snprintf(string, size, "%u.%u.%u.%u", + byte[0], byte[1], byte[2], byte[3]); + } + } + + return PR_SUCCESS; + +failed: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + +} /* PR_NetAddrToString */ + +/* + * Convert an IPv4 addr to an (IPv4-mapped) IPv6 addr + */ +PR_IMPLEMENT(void) PR_ConvertIPv4AddrToIPv6(PRUint32 v4addr, PRIPv6Addr *v6addr) +{ + PRUint8 *dstp; + dstp = v6addr->pr_s6_addr; + memset(dstp, 0, 10); + memset(dstp + 10, 0xff, 2); + memcpy(dstp + 12,(char *) &v4addr, 4); +} + +PR_IMPLEMENT(PRUint16) PR_ntohs(PRUint16 n) { return ntohs(n); } +PR_IMPLEMENT(PRUint32) PR_ntohl(PRUint32 n) { return ntohl(n); } +PR_IMPLEMENT(PRUint16) PR_htons(PRUint16 n) { return htons(n); } +PR_IMPLEMENT(PRUint32) PR_htonl(PRUint32 n) { return htonl(n); } +PR_IMPLEMENT(PRUint64) PR_ntohll(PRUint64 n) +{ +#ifdef IS_BIG_ENDIAN + return n; +#else + PRUint64 tmp; + PRUint32 hi, lo; + LL_L2UI(lo, n); + LL_SHR(tmp, n, 32); + LL_L2UI(hi, tmp); + hi = PR_ntohl(hi); + lo = PR_ntohl(lo); + LL_UI2L(n, lo); + LL_SHL(n, n, 32); + LL_UI2L(tmp, hi); + LL_ADD(n, n, tmp); + return n; +#endif +} /* ntohll */ + +PR_IMPLEMENT(PRUint64) PR_htonll(PRUint64 n) +{ +#ifdef IS_BIG_ENDIAN + return n; +#else + PRUint64 tmp; + PRUint32 hi, lo; + LL_L2UI(lo, n); + LL_SHR(tmp, n, 32); + LL_L2UI(hi, tmp); + hi = htonl(hi); + lo = htonl(lo); + LL_UI2L(n, lo); + LL_SHL(n, n, 32); + LL_UI2L(tmp, hi); + LL_ADD(n, n, tmp); + return n; +#endif +} /* htonll */ + + +/* + * Implementation of PR_GetAddrInfoByName and friends + * + * Compile-time options: + * + * _PR_HAVE_GETADDRINFO Define this macro if the target system provides + * getaddrinfo. With this defined, NSPR will require + * getaddrinfo at run time. If this if not defined, + * then NSPR will attempt to dynamically resolve + * getaddrinfo, falling back to PR_GetHostByName if + * getaddrinfo does not exist on the target system. + * + * Since getaddrinfo is a relatively new system call on many systems, + * we are forced to dynamically resolve it at run time in most cases. + * The exception includes any system (such as Mac OS X) that is known to + * provide getaddrinfo in all versions that NSPR cares to support. + */ + +#if defined(_PR_HAVE_GETADDRINFO) + +#if defined(_PR_INET6) + +typedef struct addrinfo PRADDRINFO; +#define GETADDRINFO getaddrinfo +#define FREEADDRINFO freeaddrinfo + +#elif defined(_PR_INET6_PROBE) + +typedef struct addrinfo PRADDRINFO; + +/* getaddrinfo/freeaddrinfo prototypes */ +#if defined(WIN32) +#define FUNC_MODIFIER __stdcall +#else +#define FUNC_MODIFIER +#endif +typedef int (FUNC_MODIFIER * FN_GETADDRINFO) + (const char *nodename, + const char *servname, + const PRADDRINFO *hints, + PRADDRINFO **res); +typedef int (FUNC_MODIFIER * FN_FREEADDRINFO) + (PRADDRINFO *ai); + +/* global state */ +static FN_GETADDRINFO _pr_getaddrinfo = NULL; +static FN_FREEADDRINFO _pr_freeaddrinfo = NULL; + +#if defined(VMS) +#define GETADDRINFO_SYMBOL getenv("GETADDRINFO") +#define FREEADDRINFO_SYMBOL getenv("FREEADDRINFO") +#else +#define GETADDRINFO_SYMBOL "getaddrinfo" +#define FREEADDRINFO_SYMBOL "freeaddrinfo" +#endif + +PRStatus +_pr_find_getaddrinfo(void) +{ + PRLibrary *lib; +#ifdef WIN32 + /* + * On windows, we need to search ws2_32.dll for getaddrinfo and + * freeaddrinfo. This library might not be loaded yet. + */ + lib = PR_LoadLibrary("ws2_32.dll"); + if (!lib) { + return PR_FAILURE; + } + _pr_getaddrinfo = (FN_GETADDRINFO) + PR_FindFunctionSymbol(lib, GETADDRINFO_SYMBOL); + _pr_freeaddrinfo = (FN_FREEADDRINFO) + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); + if (!_pr_getaddrinfo || !_pr_freeaddrinfo) { + PR_UnloadLibrary(lib); + return PR_FAILURE; + } + /* Keep ws2_32.dll loaded. */ + return PR_SUCCESS; +#else + /* + * Resolve getaddrinfo by searching all loaded libraries. Then + * search library containing getaddrinfo for freeaddrinfo. + */ + _pr_getaddrinfo = (FN_GETADDRINFO) + PR_FindFunctionSymbolAndLibrary(GETADDRINFO_SYMBOL, &lib); + if (!_pr_getaddrinfo) { + return PR_FAILURE; + } + _pr_freeaddrinfo = (FN_FREEADDRINFO) + PR_FindFunctionSymbol(lib, FREEADDRINFO_SYMBOL); + PR_UnloadLibrary(lib); + if (!_pr_freeaddrinfo) { + return PR_FAILURE; + } + return PR_SUCCESS; +#endif +} + +#define GETADDRINFO (*_pr_getaddrinfo) +#define FREEADDRINFO (*_pr_freeaddrinfo) + +#endif /* _PR_INET6 */ + +#endif /* _PR_HAVE_GETADDRINFO */ + +/* + * If getaddrinfo does not exist, then we will fall back on + * PR_GetHostByName, which requires that we allocate a buffer for the + * PRHostEnt data structure and its members. + */ +typedef struct PRAddrInfoFB { + char buf[PR_NETDB_BUF_SIZE]; + PRHostEnt hostent; + PRBool has_cname; +} PRAddrInfoFB; + +static PRAddrInfo * +pr_GetAddrInfoByNameFB(const char *hostname, + PRUint16 af, + PRIntn flags) +{ + PRStatus rv; + PRAddrInfoFB *ai; + /* fallback on PR_GetHostByName */ + ai = PR_NEW(PRAddrInfoFB); + if (!ai) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + rv = PR_GetHostByName(hostname, ai->buf, sizeof ai->buf, &ai->hostent); + if (rv == PR_FAILURE) { + PR_Free(ai); + return NULL; + } + ai->has_cname = !(flags & PR_AI_NOCANONNAME); + + return (PRAddrInfo *) ai; +} + +PR_IMPLEMENT(PRAddrInfo *) PR_GetAddrInfoByName(const char *hostname, + PRUint16 af, + PRIntn flags) +{ + /* restrict input to supported values */ + if ((af != PR_AF_INET && af != PR_AF_UNSPEC) || + (flags & ~ PR_AI_NOCANONNAME) != PR_AI_ADDRCONFIG) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + if (!_pr_initialized) _PR_ImplicitInitialization(); + +#if !defined(_PR_HAVE_GETADDRINFO) + return pr_GetAddrInfoByNameFB(hostname, af, flags); +#else +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present) { + return pr_GetAddrInfoByNameFB(hostname, af, flags); + } +#endif + { + PRADDRINFO *res, hints; + PRStatus rv; + + /* + * we assume a RFC 2553 compliant getaddrinfo. this may at some + * point need to be customized as platforms begin to adopt the + * RFC 3493. + */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = (flags & PR_AI_NOCANONNAME) ? 0: AI_CANONNAME; + hints.ai_family = (af == PR_AF_INET) ? AF_INET : AF_UNSPEC; + + /* + * it is important to select a socket type in the hints, otherwise we + * will get back repetitive entries: one for each socket type. since + * we do not expose ai_socktype through our API, it is okay to do this + * here. the application may still choose to create a socket of some + * other type. + */ + hints.ai_socktype = SOCK_STREAM; + + rv = GETADDRINFO(hostname, NULL, &hints, &res); + if (rv == 0) + return (PRAddrInfo *) res; + + PR_SetError(PR_DIRECTORY_LOOKUP_ERROR, rv); + } + return NULL; +#endif +} + +PR_IMPLEMENT(void) PR_FreeAddrInfo(PRAddrInfo *ai) +{ +#if defined(_PR_HAVE_GETADDRINFO) +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present) + PR_Free((PRAddrInfoFB *) ai); + else +#endif + FREEADDRINFO((PRADDRINFO *) ai); +#else + PR_Free((PRAddrInfoFB *) ai); +#endif +} + +PR_IMPLEMENT(void *) PR_EnumerateAddrInfo(void *iterPtr, + const PRAddrInfo *base, + PRUint16 port, + PRNetAddr *result) +{ +#if defined(_PR_HAVE_GETADDRINFO) + PRADDRINFO *ai; +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present) { + /* using PRAddrInfoFB */ + PRIntn iter = (PRIntn)(uintptr_t)iterPtr; + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); + if (iter < 0) + iter = 0; + return (void *)(uintptr_t)iter; + } +#endif + + if (iterPtr) + ai = ((PRADDRINFO *) iterPtr)->ai_next; + else + ai = (PRADDRINFO *) base; + + if (ai) { + /* copy sockaddr to PRNetAddr */ + memcpy(result, ai->ai_addr, ai->ai_addrlen); + result->raw.family = ai->ai_addr->sa_family; + if (ai->ai_addrlen < sizeof(PRNetAddr)) + memset(((char*)result)+ai->ai_addrlen, 0, sizeof(PRNetAddr) - ai->ai_addrlen); + + if (result->raw.family == PR_AF_INET) + result->inet.port = htons(port); + else + result->ipv6.port = htons(port); + } + + return ai; +#else + /* using PRAddrInfoFB */ + PRIntn iter = (PRIntn) iterPtr; + iter = PR_EnumerateHostEnt(iter, &((PRAddrInfoFB *) base)->hostent, port, result); + if (iter < 0) + iter = 0; + return (void *) iter; +#endif +} + +PR_IMPLEMENT(const char *) PR_GetCanonNameFromAddrInfo(const PRAddrInfo *ai) +{ +#if defined(_PR_HAVE_GETADDRINFO) +#if defined(_PR_INET6_PROBE) + if (!_pr_ipv6_is_present) { + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; + return fb->has_cname ? fb->hostent.h_name : NULL; + } +#endif + return ((const PRADDRINFO *) ai)->ai_canonname; +#else + const PRAddrInfoFB *fb = (const PRAddrInfoFB *) ai; + return fb->has_cname ? fb->hostent.h_name : NULL; +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prolock.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prolock.c new file mode 100644 index 00000000..f7339bac --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prolock.c @@ -0,0 +1,100 @@ +/* -*- 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 ***** */ + +/* +** prolock.c -- NSPR Ordered Lock +** +** Implement the API defined in prolock.h +** +*/ +#include "prolock.h" +#include "prlog.h" +#include "prerror.h" + +PR_IMPLEMENT(PROrderedLock *) + PR_CreateOrderedLock( + PRInt32 order, + const char *name +) +{ +#ifdef XP_MAC +#pragma unused( order, name ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} /* end PR_CreateOrderedLock() */ + + +PR_IMPLEMENT(void) + PR_DestroyOrderedLock( + PROrderedLock *lock +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_DestroyOrderedLock() */ + + +PR_IMPLEMENT(void) + PR_LockOrderedLock( + PROrderedLock *lock +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); +} /* end PR_LockOrderedLock() */ + + +PR_IMPLEMENT(PRStatus) + PR_UnlockOrderedLock( + PROrderedLock *lock +) +{ +#ifdef XP_MAC +#pragma unused( lock ) +#endif + PR_ASSERT(!"Not implemented"); /* Not implemented yet */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} /* end PR_UnlockOrderedLock() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prrng.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prrng.c new file mode 100644 index 00000000..6cd7e239 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prrng.c @@ -0,0 +1,76 @@ +/* -*- 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" + +/* + * We were not including in optimized builds. On AIX this + * caused libnspr4.so to export memcpy and some binaries linked with + * libnspr4.so resolved their memcpy references with libnspr4.so. To + * be backward compatible with old libnspr4.so binaries, we do not + * include in optimized builds for AIX. (bug 200561) + */ +#if !(defined(AIX) && !defined(DEBUG)) +#include +#endif + +PRSize _pr_CopyLowBits( + void *dst, + PRSize dstlen, + void *src, + PRSize srclen ) +{ + if (srclen <= dstlen) { + memcpy(dst, src, srclen); + return srclen; + } +#if defined IS_BIG_ENDIAN + memcpy(dst, (char*)src + (srclen - dstlen), dstlen); +#else + memcpy(dst, src, dstlen); +#endif + return dstlen; +} + +PR_IMPLEMENT(PRSize) PR_GetRandomNoise( + void *buf, + PRSize size +) +{ + return( _PR_MD_GET_RANDOM_NOISE( buf, size )); +} /* end PR_GetRandomNoise() */ +/* end prrng.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prsystem.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prsystem.c new file mode 100644 index 00000000..4da19ba2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prsystem.c @@ -0,0 +1,233 @@ +/* -*- 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 "prsystem.h" +#include "prprf.h" + +#if defined(BEOS) +#include +#endif + +#if defined(OS2) +#define INCL_DOS +#include +/* define the required constant if it is not already defined in the headers */ +#ifndef QSV_NUMPROCESSORS +#define QSV_NUMPROCESSORS 26 +#endif +#endif + +/* BSD-derived systems use sysctl() to get the number of processors */ +#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \ + || defined(OPENBSD) || defined(DARWIN) +#define _PR_HAVE_SYSCTL +#include +#include +#endif + +#if defined(HPUX) +#include +#endif + +#if defined(XP_UNIX) +#include +#include +#endif + +PR_IMPLEMENT(char) PR_GetDirectorySeparator(void) +{ + return PR_DIRECTORY_SEPARATOR; +} /* PR_GetDirectorySeparator */ + +/* +** OBSOLETE -- the function name is misspelled. +*/ +PR_IMPLEMENT(char) PR_GetDirectorySepartor(void) +{ +#if defined(DEBUG) + static PRBool warn = PR_TRUE; + if (warn) { + warn = _PR_Obsolete("PR_GetDirectorySepartor()", + "PR_GetDirectorySeparator()"); + } +#endif + return PR_GetDirectorySeparator(); +} /* PR_GetDirectorySepartor */ + +PR_IMPLEMENT(char) PR_GetPathSeparator(void) +{ + return PR_PATH_SEPARATOR; +} /* PR_GetPathSeparator */ + +PR_IMPLEMENT(PRStatus) PR_GetSystemInfo(PRSysInfo cmd, char *buf, PRUint32 buflen) +{ + PRUintn len = 0; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch(cmd) + { + case PR_SI_HOSTNAME: + if (PR_FAILURE == _PR_MD_GETHOSTNAME(buf, (PRUintn)buflen)) + return PR_FAILURE; + /* + * On some platforms a system does not have a hostname and + * its IP address is returned instead. The following code + * should be skipped on those platforms. + */ +#ifndef _PR_GET_HOST_ADDR_AS_NAME + /* Return the unqualified hostname */ + while ((len < buflen) && buf[len]) { + if (buf[len] == '.') { + buf[len] = '\0'; + break; + } + len += 1; + } +#endif + break; + + case PR_SI_SYSNAME: + /* Return the operating system name */ +#if defined(XP_UNIX) || defined(WIN32) + if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) + return PR_FAILURE; +#else + (void)PR_snprintf(buf, buflen, _PR_SI_SYSNAME); +#endif + break; + + case PR_SI_RELEASE: + /* Return the version of the operating system */ +#if defined(XP_UNIX) || defined(WIN32) + if (PR_FAILURE == _PR_MD_GETSYSINFO(cmd, buf, (PRUintn)buflen)) + return PR_FAILURE; +#endif +#if defined(XP_OS2) + { + ULONG os2ver[2] = {0}; + DosQuerySysInfo(QSV_VERSION_MINOR, QSV_VERSION_REVISION, + &os2ver, sizeof(os2ver)); + /* Formatting for normal usage (2.11, 3.0, 4.0, 4.5); officially, + Warp 4 is version 2.40.00, WSeB 2.45.00 */ + if (os2ver[0] < 30) + (void)PR_snprintf(buf, buflen, "%s%lu", + "2.", os2ver[0]); + else if (os2ver[0] < 45) + (void)PR_snprintf(buf, buflen, "%lu%s%lu", + os2ver[0]/10, ".", os2ver[1]); + else + (void)PR_snprintf(buf, buflen, "%.1f", + os2ver[0]/10.0); + } +#endif /* OS2 */ + break; + + case PR_SI_ARCHITECTURE: + /* Return the architecture of the machine (ie. x86, mips, alpha, ...)*/ + (void)PR_snprintf(buf, buflen, _PR_SI_ARCHITECTURE); + break; + default: + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** PR_GetNumberOfProcessors() +** +** Implementation notes: +** Every platform does it a bit different. +** numCpus is the returned value. +** for each platform's "if defined" section +** declare your local variable +** do your thing, assign to numCpus +** order of the if defined()s may be important, +** especially for unix variants. Do platform +** specific implementations before XP_UNIX. +** +*/ +PR_IMPLEMENT(PRInt32) PR_GetNumberOfProcessors( void ) +{ + PRInt32 numCpus; +#if defined(WIN32) + SYSTEM_INFO info; + + GetSystemInfo( &info ); + numCpus = info.dwNumberOfProcessors; +#elif defined(XP_MAC) +/* Hard-code the number of processors to 1 on the Mac +** MacOS/9 will always be 1. The MPProcessors() call is for +** MacOS/X, when issued. Leave it commented out for now. */ +/* numCpus = MPProcessors(); */ + numCpus = 1; +#elif defined(BEOS) + system_info sysInfo; + + get_system_info(&sysInfo); + numCpus = sysInfo.cpu_count; +#elif defined(OS2) + DosQuerySysInfo( QSV_NUMPROCESSORS, QSV_NUMPROCESSORS, &numCpus, sizeof(numCpus)); +#elif defined(_PR_HAVE_SYSCTL) + int mib[2]; + int rc; + size_t len = sizeof(numCpus); + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + rc = sysctl( mib, 2, &numCpus, &len, NULL, 0 ); + if ( -1 == rc ) { + numCpus = -1; /* set to -1 for return value on error */ + _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() ); + } +#elif defined(HPUX) + numCpus = mpctl( MPC_GETNUMSPUS, 0, 0 ); + if ( numCpus < 1 ) { + numCpus = -1; /* set to -1 for return value on error */ + _PR_MD_MAP_DEFAULT_ERROR( _MD_ERRNO() ); + } +#elif defined(IRIX) + numCpus = sysconf( _SC_NPROC_ONLN ); +#elif defined(XP_UNIX) + numCpus = sysconf( _SC_NPROCESSORS_ONLN ); +#else +#error "An implementation is required" +#endif + return(numCpus); +} /* end PR_GetNumberOfProcessors() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prthinfo.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prthinfo.c new file mode 100644 index 00000000..25cbd185 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prthinfo.c @@ -0,0 +1,247 @@ +/* -*- 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 "prlog.h" +#include "prthread.h" +#ifdef XP_MAC +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif +#include "primpl.h" + +PR_IMPLEMENT(PRWord *) +PR_GetGCRegisters(PRThread *t, int isCurrent, int *np) +{ + return _MD_HomeGCRegisters(t, isCurrent, np); +} + +PR_IMPLEMENT(PRStatus) +PR_ThreadScanStackPointers(PRThread* t, + PRScanStackFun scanFun, void* scanClosure) +{ + PRThread* current = PR_GetCurrentThread(); + PRWord *sp, *esp, *p0; + int n; + void **ptd; + PRStatus status; + PRUint32 index; + int stack_end; + + /* + ** Store the thread's registers in the thread structure so the GC + ** can scan them. Then scan them. + */ + p0 = _MD_HomeGCRegisters(t, t == current, &n); + status = scanFun(t, (void**)p0, n, scanClosure); + if (status != PR_SUCCESS) + return status; + + /* Scan the C stack for pointers into the GC heap */ +#if defined(XP_PC) && defined(WIN16) + /* + ** Under WIN16, the stack of the current thread is always mapped into + ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan + ** the "task stack". Otherwise, scan the "cached stack" of the inactive + ** thread... + */ + if (t == current) { + sp = (PRWord*) &stack_end; + esp = (PRWord*) _pr_top_of_task_stack; + + PR_ASSERT(sp <= esp); + } else { + sp = (PRWord*) PR_GetSP(t); + esp = (PRWord*) t->stack->stackTop; + + PR_ASSERT((t->stack->stackSize == 0) || + ((sp > (PRWord*)t->stack->stackBottom) && + (sp <= (PRWord*)t->stack->stackTop))); + } +#else /* ! WIN16 */ +#ifdef HAVE_STACK_GROWING_UP + if (t == current) { + esp = (PRWord*) &stack_end; + } else { + esp = (PRWord*) PR_GetSP(t); + } + sp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((esp > (PRWord*)t->stack->stackTop) && + (esp < (PRWord*)t->stack->stackBottom)); + } +#else /* ! HAVE_STACK_GROWING_UP */ + if (t == current) { + sp = (PRWord*) &stack_end; + } else { + sp = (PRWord*) PR_GetSP(t); + } + esp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) && + (sp < (PRWord*)t->stack->stackTop)); + } +#endif /* ! HAVE_STACK_GROWING_UP */ +#endif /* ! WIN16 */ + +#if defined(WIN16) + { + prword_t scan; + prword_t limit; + + scan = (prword_t) sp; + limit = (prword_t) esp; + while (scan < limit) { + prword_t *test; + + test = *((prword_t **)scan); + status = scanFun(t, (void**)&test, 1, scanClosure); + if (status != PR_SUCCESS) + return status; + scan += sizeof(char); + } + } +#else + if (sp < esp) { + status = scanFun(t, (void**)sp, esp - sp, scanClosure); + if (status != PR_SUCCESS) + return status; + } +#endif + + /* + ** Mark all of the per-thread-data items attached to this thread + ** + ** The execution environment better be accounted for otherwise it + ** will be collected + */ + status = scanFun(t, (void**)&t->environment, 1, scanClosure); + if (status != PR_SUCCESS) + return status; + +#ifndef GC_LEAK_DETECTOR + /* if thread is not allocated on stack, this is redundant. */ + ptd = t->privateData; + for (index = 0; index < t->tpdLength; index++, ptd++) { + status = scanFun(t, (void**)ptd, 1, scanClosure); + if (status != PR_SUCCESS) + return status; + } +#endif + + return PR_SUCCESS; +} + +/* transducer for PR_EnumerateThreads */ +typedef struct PRScanStackData { + PRScanStackFun scanFun; + void* scanClosure; +} PRScanStackData; + +static PRStatus PR_CALLBACK +pr_ScanStack(PRThread* t, int i, void* arg) +{ +#if defined(XP_MAC) +#pragma unused (i) +#endif + PRScanStackData* data = (PRScanStackData*)arg; + return PR_ThreadScanStackPointers(t, data->scanFun, data->scanClosure); +} + +PR_IMPLEMENT(PRStatus) +PR_ScanStackPointers(PRScanStackFun scanFun, void* scanClosure) +{ + PRScanStackData data; + data.scanFun = scanFun; + data.scanClosure = scanClosure; + return PR_EnumerateThreads(pr_ScanStack, &data); +} + +PR_IMPLEMENT(PRUword) +PR_GetStackSpaceLeft(PRThread* t) +{ + PRThread *current = PR_CurrentThread(); + PRWord *sp, *esp; + int stack_end; + +#if defined(WIN16) + /* + ** Under WIN16, the stack of the current thread is always mapped into + ** the "task stack" (at SS:xxxx). So, if t is the current thread, scan + ** the "task stack". Otherwise, scan the "cached stack" of the inactive + ** thread... + */ + if (t == current) { + sp = (PRWord*) &stack_end; + esp = (PRWord*) _pr_top_of_task_stack; + + PR_ASSERT(sp <= esp); + } else { + sp = (PRWord*) PR_GetSP(t); + esp = (PRWord*) t->stack->stackTop; + + PR_ASSERT((t->stack->stackSize == 0) || + ((sp > (PRWord*)t->stack->stackBottom) && + (sp <= (PRWord*)t->stack->stackTop))); + } +#else /* ! WIN16 */ +#ifdef HAVE_STACK_GROWING_UP + if (t == current) { + esp = (PRWord*) &stack_end; + } else { + esp = (PRWord*) PR_GetSP(t); + } + sp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((esp > (PRWord*)t->stack->stackTop) && + (esp < (PRWord*)t->stack->stackBottom)); + } +#else /* ! HAVE_STACK_GROWING_UP */ + if (t == current) { + sp = (PRWord*) &stack_end; + } else { + sp = (PRWord*) PR_GetSP(t); + } + esp = (PRWord*) t->stack->stackTop; + if (t->stack->stackSize) { + PR_ASSERT((sp > (PRWord*)t->stack->stackBottom) && + (sp < (PRWord*)t->stack->stackTop)); + } +#endif /* ! HAVE_STACK_GROWING_UP */ +#endif /* ! WIN16 */ + return (PRUword)t->stack->stackSize - ((PRWord)esp - (PRWord)sp); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtime.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtime.c new file mode 100644 index 00000000..0a2892e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtime.c @@ -0,0 +1,1973 @@ +/* -*- 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 ***** */ + +/* + * prtime.c -- + * + * NSPR date and time functions + * + */ + +#include "prinit.h" +#include "prtime.h" +#include "prlock.h" +#include "prprf.h" +#include "prlog.h" + +#include +#include + +#ifdef XP_MAC +#include +#endif + + + + +/* + * Static variables used by functions in this file + */ + +/* + * The following array contains the day of year for the last day of + * each month, where index 1 is January, and day 0 is January 1. + */ + +static const int lastDayOfMonth[2][13] = { + {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, + {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365} +}; + +/* + * The number of days in a month + */ + +static const PRInt8 nDays[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + +/* + * Declarations for internal functions defined later in this file. + */ + +static void ComputeGMT(PRTime time, PRExplodedTime *gmt); +static int IsLeapYear(PRInt16 year); +static void ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset); + +/* + *------------------------------------------------------------------------ + * + * ComputeGMT -- + * + * Caveats: + * - we ignore leap seconds + * - our leap-year calculation is only correct for years 1901-2099 + * + *------------------------------------------------------------------------ + */ + +static void +ComputeGMT(PRTime time, PRExplodedTime *gmt) +{ + PRInt32 tmp, rem; + PRInt32 numDays; + PRInt64 numDays64, rem64; + int isLeap; + PRInt64 sec; + PRInt64 usec; + PRInt64 usecPerSec; + PRInt64 secPerDay; + + /* + * We first do the usec, sec, min, hour thing so that we do not + * have to do LL arithmetic. + */ + + LL_I2L(usecPerSec, 1000000L); + LL_DIV(sec, time, usecPerSec); + LL_MOD(usec, time, usecPerSec); + LL_L2I(gmt->tm_usec, usec); + /* Correct for weird mod semantics so the remainder is always positive */ + if (gmt->tm_usec < 0) { + PRInt64 one; + + LL_I2L(one, 1L); + LL_SUB(sec, sec, one); + gmt->tm_usec += 1000000L; + } + + LL_I2L(secPerDay, 86400L); + LL_DIV(numDays64, sec, secPerDay); + LL_MOD(rem64, sec, secPerDay); + /* We are sure both of these numbers can fit into PRInt32 */ + LL_L2I(numDays, numDays64); + LL_L2I(rem, rem64); + if (rem < 0) { + numDays--; + rem += 86400L; + } + + /* Compute day of week. Epoch started on a Thursday. */ + + gmt->tm_wday = (numDays + 4) % 7; + if (gmt->tm_wday < 0) { + gmt->tm_wday += 7; + } + + /* Compute the time of day. */ + + gmt->tm_hour = rem / 3600; + rem %= 3600; + gmt->tm_min = rem / 60; + gmt->tm_sec = rem % 60; + + /* Compute the four-year span containing the specified time */ + + tmp = numDays / (4 * 365 + 1); + rem = numDays % (4 * 365 + 1); + + if (rem < 0) { + tmp--; + rem += (4 * 365 + 1); + } + + /* + * Compute the year after 1900 by taking the four-year span and + * adjusting for the remainder. This works because 2000 is a + * leap year, and 1900 and 2100 are out of the range. + */ + + tmp = (tmp * 4) + 1970; + isLeap = 0; + + /* + * 1970 has 365 days + * 1971 has 365 days + * 1972 has 366 days (leap year) + * 1973 has 365 days + */ + + if (rem >= 365) { /* 1971, etc. */ + tmp++; + rem -= 365; + if (rem >= 365) { /* 1972, etc. */ + tmp++; + rem -= 365; + if (rem >= 366) { /* 1973, etc. */ + tmp++; + rem -= 366; + } else { + isLeap = 1; + } + } + } + + gmt->tm_year = tmp; + gmt->tm_yday = rem; + + /* Compute the month and day of month. */ + + for (tmp = 1; lastDayOfMonth[isLeap][tmp] < gmt->tm_yday; tmp++) { + } + gmt->tm_month = --tmp; + gmt->tm_mday = gmt->tm_yday - lastDayOfMonth[isLeap][tmp]; + + gmt->tm_params.tp_gmt_offset = 0; + gmt->tm_params.tp_dst_offset = 0; +} + + +/* + *------------------------------------------------------------------------ + * + * PR_ExplodeTime -- + * + * Cf. struct tm *gmtime(const time_t *tp) and + * struct tm *localtime(const time_t *tp) + * + *------------------------------------------------------------------------ + */ + +PR_IMPLEMENT(void) +PR_ExplodeTime( + PRTime usecs, + PRTimeParamFn params, + PRExplodedTime *exploded) +{ + ComputeGMT(usecs, exploded); + exploded->tm_params = params(exploded); + ApplySecOffset(exploded, exploded->tm_params.tp_gmt_offset + + exploded->tm_params.tp_dst_offset); +} + + +/* + *------------------------------------------------------------------------ + * + * PR_ImplodeTime -- + * + * Cf. time_t mktime(struct tm *tp) + * Note that 1 year has < 2^25 seconds. So an PRInt32 is large enough. + * + *------------------------------------------------------------------------ + */ +#if defined(HAVE_WATCOM_BUG_2) +PRTime __pascal __export __loadds +#else +PR_IMPLEMENT(PRTime) +#endif +PR_ImplodeTime(const PRExplodedTime *exploded) +{ + PRExplodedTime copy; + PRTime retVal; + PRInt64 secPerDay, usecPerSec; + PRInt64 temp; + PRInt64 numSecs64; + PRInt32 fourYears; + PRInt32 remainder; + PRInt32 numDays; + PRInt32 numSecs; + + /* Normalize first. Do this on our copy */ + copy = *exploded; + PR_NormalizeTime(©, PR_GMTParameters); + + fourYears = (copy.tm_year - 1970) / 4; + remainder = (copy.tm_year - 1970) % 4; + if (remainder < 0) { + remainder += 4; + fourYears--; + } + numDays = fourYears * (4 * 365 + 1); + switch (remainder) { + case 0: + break; + case 1: /* 1970 */ + numDays += 365; + break; + case 2: /* 1970-1 */ + numDays += 365 * 2; + break; + case 3: /* 1970-2 */ + numDays += 365 * 3 + 1; + break; + } + + numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600 + + copy.tm_min * 60 + copy.tm_sec; + + LL_I2L(temp, numDays); + LL_I2L(secPerDay, 86400); + LL_MUL(temp, temp, secPerDay); + LL_I2L(numSecs64, numSecs); + LL_ADD(numSecs64, numSecs64, temp); + + /* apply the GMT and DST offsets */ + LL_I2L(temp, copy.tm_params.tp_gmt_offset); + LL_SUB(numSecs64, numSecs64, temp); + LL_I2L(temp, copy.tm_params.tp_dst_offset); + LL_SUB(numSecs64, numSecs64, temp); + + LL_I2L(usecPerSec, 1000000L); + LL_MUL(temp, numSecs64, usecPerSec); + LL_I2L(retVal, copy.tm_usec); + LL_ADD(retVal, retVal, temp); + + return retVal; +} + +/* + *------------------------------------------------------------------------- + * + * IsLeapYear -- + * + * Returns 1 if the year is a leap year, 0 otherwise. + * + *------------------------------------------------------------------------- + */ + +static int IsLeapYear(PRInt16 year) +{ + if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) + return 1; + else + return 0; +} + +/* + * 'secOffset' should be less than 86400 (i.e., a day). + * 'time' should point to a normalized PRExplodedTime. + */ + +static void +ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset) +{ + time->tm_sec += secOffset; + + /* Note that in this implementation we do not count leap seconds */ + if (time->tm_sec < 0 || time->tm_sec >= 60) { + time->tm_min += time->tm_sec / 60; + time->tm_sec %= 60; + if (time->tm_sec < 0) { + time->tm_sec += 60; + time->tm_min--; + } + } + + if (time->tm_min < 0 || time->tm_min >= 60) { + time->tm_hour += time->tm_min / 60; + time->tm_min %= 60; + if (time->tm_min < 0) { + time->tm_min += 60; + time->tm_hour--; + } + } + + if (time->tm_hour < 0) { + /* Decrement mday, yday, and wday */ + time->tm_hour += 24; + time->tm_mday--; + time->tm_yday--; + if (time->tm_mday < 1) { + time->tm_month--; + if (time->tm_month < 0) { + time->tm_month = 11; + time->tm_year--; + if (IsLeapYear(time->tm_year)) + time->tm_yday = 365; + else + time->tm_yday = 364; + } + time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } + time->tm_wday--; + if (time->tm_wday < 0) + time->tm_wday = 6; + } else if (time->tm_hour > 23) { + /* Increment mday, yday, and wday */ + time->tm_hour -= 24; + time->tm_mday++; + time->tm_yday++; + if (time->tm_mday > + nDays[IsLeapYear(time->tm_year)][time->tm_month]) { + time->tm_mday = 1; + time->tm_month++; + if (time->tm_month > 11) { + time->tm_month = 0; + time->tm_year++; + time->tm_yday = 0; + } + } + time->tm_wday++; + if (time->tm_wday > 6) + time->tm_wday = 0; + } +} + +PR_IMPLEMENT(void) +PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params) +{ + int daysInMonth; + PRInt32 fourYears; + PRInt32 remainder; + PRInt32 numDays; + + /* Get back to GMT */ + time->tm_sec -= time->tm_params.tp_gmt_offset + + time->tm_params.tp_dst_offset; + time->tm_params.tp_gmt_offset = 0; + time->tm_params.tp_dst_offset = 0; + + /* Now normalize GMT */ + + if (time->tm_usec < 0 || time->tm_usec >= 1000000) { + time->tm_sec += time->tm_usec / 1000000; + time->tm_usec %= 1000000; + if (time->tm_usec < 0) { + time->tm_usec += 1000000; + time->tm_sec--; + } + } + + /* Note that we do not count leap seconds in this implementation */ + if (time->tm_sec < 0 || time->tm_sec >= 60) { + time->tm_min += time->tm_sec / 60; + time->tm_sec %= 60; + if (time->tm_sec < 0) { + time->tm_sec += 60; + time->tm_min--; + } + } + + if (time->tm_min < 0 || time->tm_min >= 60) { + time->tm_hour += time->tm_min / 60; + time->tm_min %= 60; + if (time->tm_min < 0) { + time->tm_min += 60; + time->tm_hour--; + } + } + + if (time->tm_hour < 0 || time->tm_hour >= 24) { + time->tm_mday += time->tm_hour / 24; + time->tm_hour %= 24; + if (time->tm_hour < 0) { + time->tm_hour += 24; + time->tm_mday--; + } + } + + /* Normalize month and year before mday */ + if (time->tm_month < 0 || time->tm_month >= 12) { + time->tm_year += time->tm_month / 12; + time->tm_month %= 12; + if (time->tm_month < 0) { + time->tm_month += 12; + time->tm_year--; + } + } + + /* Now that month and year are in proper range, normalize mday */ + + if (time->tm_mday < 1) { + /* mday too small */ + do { + /* the previous month */ + time->tm_month--; + if (time->tm_month < 0) { + time->tm_month = 11; + time->tm_year--; + } + time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } while (time->tm_mday < 1); + } else { + daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + while (time->tm_mday > daysInMonth) { + /* mday too large */ + time->tm_mday -= daysInMonth; + time->tm_month++; + if (time->tm_month > 11) { + time->tm_month = 0; + time->tm_year++; + } + daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month]; + } + } + + /* Recompute yday and wday */ + time->tm_yday = time->tm_mday + + lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month]; + fourYears = (time->tm_year - 1970) / 4; + remainder = (time->tm_year - 1970) % 4; + if (remainder < 0) { + remainder += 4; + fourYears--; + } + numDays = fourYears * (4 * 365 + 1); + switch (remainder) { + case 0: + break; + case 1: + numDays += 365; /* 1970 */ + break; + case 2: + numDays += 365 + 365; /* 1970 and 1971 */ + break; + case 3: + numDays += 365 + 365 + 366; /* 1970-2 */ + } + numDays += time->tm_yday; + time->tm_wday = (numDays + 4) % 7; + if (time->tm_wday < 0) { + time->tm_wday += 7; + } + + /* Recompute time parameters */ + + time->tm_params = params(time); + + ApplySecOffset(time, time->tm_params.tp_gmt_offset + + time->tm_params.tp_dst_offset); +} + + +/* + *------------------------------------------------------------------------- + * + * PR_LocalTimeParameters -- + * + * returns the time parameters for the local time zone + * + * The following uses localtime() from the standard C library. + * (time.h) This is our fallback implementation. Unix and PC + * use this version. Mac has its own machine-dependent + * implementation of this function. + * + *------------------------------------------------------------------------- + */ + +#include + +#if defined(HAVE_INT_LOCALTIME_R) + +/* + * In this case we could define the macro as + * #define MT_safe_localtime(timer, result) \ + * (localtime_r(timer, result) == 0 ? result : NULL) + * I chose to compare the return value of localtime_r with -1 so + * that I can catch the cases where localtime_r returns a pointer + * to struct tm. The macro definition above would not be able to + * detect such mistakes because it is legal to compare a pointer + * with 0. + */ + +#define MT_safe_localtime(timer, result) \ + (localtime_r(timer, result) == -1 ? NULL: result) + +#elif defined(HAVE_POINTER_LOCALTIME_R) + +#define MT_safe_localtime localtime_r + +#else + +#if defined(XP_MAC) +extern struct tm *Maclocaltime(const time_t * t); +#endif + +static PRLock *monitor = NULL; + +static struct tm *MT_safe_localtime(const time_t *clock, struct tm *result) +{ + struct tm *tmPtr; + int needLock = PR_Initialized(); /* We need to use a lock to protect + * against NSPR threads only when the + * NSPR thread system is activated. */ + + if (needLock) { + if (monitor == NULL) { + monitor = PR_NewLock(); + } + PR_Lock(monitor); + } + + /* + * Microsoft (all flavors) localtime() returns a NULL pointer if 'clock' + * represents a time before midnight January 1, 1970. In + * that case, we also return a NULL pointer and the struct tm + * object pointed to by 'result' is not modified. + * + * Watcom C/C++ 11.0 localtime() treats time_t as unsigned long + * hence, does not recognize negative values of clock as pre-1/1/70. + * We have to manually check (WIN16 only) for negative value of + * clock and return NULL. + * + * With negative values of clock, emx returns the struct tm for + * clock plus ULONG_MAX. So we also have to check for the invalid + * structs returned for timezones west of Greenwich when clock == 0. + */ + +#if defined(XP_MAC) + tmPtr = Maclocaltime(clock); +#else + tmPtr = localtime(clock); +#endif + +#if defined(WIN16) || defined(XP_OS2_EMX) + if ( (PRInt32) *clock < 0 || + ( (PRInt32) *clock == 0 && tmPtr->tm_year != 70)) + result = NULL; + else + *result = *tmPtr; +#else + if (tmPtr) { + *result = *tmPtr; + } else { + result = NULL; + } +#endif /* WIN16 */ + + if (needLock) PR_Unlock(monitor); + + return result; +} + +#endif /* definition of MT_safe_localtime() */ + +#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS) + +PR_IMPLEMENT(PRTimeParameters) +PR_LocalTimeParameters(const PRExplodedTime *gmt) +{ + + PRTimeParameters retVal; + struct tm localTime; + time_t secs; + PRTime secs64; + PRInt64 usecPerSec; + PRInt64 maxInt32; + PRInt64 minInt32; + PRInt32 dayOffset; + PRInt32 offset2Jan1970; + PRInt32 offsetNew; + int isdst2Jan1970; + + /* + * Calculate the GMT offset. First, figure out what is + * 00:00:00 Jan. 2, 1970 GMT (which is exactly a day, or 86400 + * seconds, since the epoch) in local time. Then we calculate + * the difference between local time and GMT in seconds: + * gmt_offset = local_time - GMT + * + * Caveat: the validity of this calculation depends on two + * assumptions: + * 1. Daylight saving time was not in effect on Jan. 2, 1970. + * 2. The time zone of the geographic location has not changed + * since Jan. 2, 1970. + */ + + secs = 86400L; + (void) MT_safe_localtime(&secs, &localTime); + + /* GMT is 00:00:00, 2nd of Jan. */ + + offset2Jan1970 = (PRInt32)localTime.tm_sec + + 60L * (PRInt32)localTime.tm_min + + 3600L * (PRInt32)localTime.tm_hour + + 86400L * (PRInt32)((PRInt32)localTime.tm_mday - 2L); + + isdst2Jan1970 = localTime.tm_isdst; + + /* + * Now compute DST offset. We calculate the overall offset + * of local time from GMT, similar to above. The overall + * offset has two components: gmt offset and dst offset. + * We subtract gmt offset from the overall offset to get + * the dst offset. + * overall_offset = local_time - GMT + * overall_offset = gmt_offset + dst_offset + * ==> dst_offset = local_time - GMT - gmt_offset + */ + + secs64 = PR_ImplodeTime(gmt); /* This is still in microseconds */ + LL_I2L(usecPerSec, PR_USEC_PER_SEC); + LL_DIV(secs64, secs64, usecPerSec); /* Convert to seconds */ + LL_I2L(maxInt32, PR_INT32_MAX); + LL_I2L(minInt32, PR_INT32_MIN); + if (LL_CMP(secs64, >, maxInt32) || LL_CMP(secs64, <, minInt32)) { + /* secs64 is too large or too small for time_t (32-bit integer) */ + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = 0; + return retVal; + } + LL_L2I(secs, secs64); + + /* + * On Windows, localtime() (and our MT_safe_localtime() too) + * returns a NULL pointer for time before midnight January 1, + * 1970 GMT. In that case, we just use the GMT offset for + * Jan 2, 1970 and assume that DST was not in effect. + */ + + if (MT_safe_localtime(&secs, &localTime) == NULL) { + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = 0; + return retVal; + } + + /* + * dayOffset is the offset between local time and GMT in + * the day component, which can only be -1, 0, or 1. We + * use the day of the week to compute dayOffset. + */ + + dayOffset = (PRInt32) localTime.tm_wday - gmt->tm_wday; + + /* + * Need to adjust for wrapping around of day of the week from + * 6 back to 0. + */ + + if (dayOffset == -6) { + /* Local time is Sunday (0) and GMT is Saturday (6) */ + dayOffset = 1; + } else if (dayOffset == 6) { + /* Local time is Saturday (6) and GMT is Sunday (0) */ + dayOffset = -1; + } + + offsetNew = (PRInt32)localTime.tm_sec - gmt->tm_sec + + 60L * ((PRInt32)localTime.tm_min - gmt->tm_min) + + 3600L * ((PRInt32)localTime.tm_hour - gmt->tm_hour) + + 86400L * (PRInt32)dayOffset; + + if (localTime.tm_isdst <= 0) { + /* DST is not in effect */ + retVal.tp_gmt_offset = offsetNew; + retVal.tp_dst_offset = 0; + } else { + /* DST is in effect */ + if (isdst2Jan1970 <=0) { + /* + * DST was not in effect back in 2 Jan. 1970. + * Use the offset back then as the GMT offset, + * assuming the time zone has not changed since then. + */ + retVal.tp_gmt_offset = offset2Jan1970; + retVal.tp_dst_offset = offsetNew - offset2Jan1970; + } else { + /* + * DST was also in effect back in 2 Jan. 1970. + * Then our clever trick (or rather, ugly hack) fails. + * We will just assume DST offset is an hour. + */ + retVal.tp_gmt_offset = offsetNew - 3600; + retVal.tp_dst_offset = 3600; + } + } + + return retVal; +} + +#endif /* defined(XP_UNIX) !! defined(XP_PC) */ + +/* + *------------------------------------------------------------------------ + * + * PR_USPacificTimeParameters -- + * + * The time parameters function for the US Pacific Time Zone. + * + *------------------------------------------------------------------------ + */ + +PR_IMPLEMENT(PRTimeParameters) +PR_USPacificTimeParameters(const PRExplodedTime *gmt) +{ + PRTimeParameters retVal; + PRExplodedTime st; + + /* + * Based on geographic location and GMT, figure out offset of + * standard time from GMT. In this example implementation, we + * assume the local time zone is US Pacific Time. + */ + + retVal.tp_gmt_offset = -8L * 3600L; + + /* + * Make a copy of GMT. Note that the tm_params field of this copy + * is ignored. + */ + + st.tm_usec = gmt->tm_usec; + st.tm_sec = gmt->tm_sec; + st.tm_min = gmt->tm_min; + st.tm_hour = gmt->tm_hour; + st.tm_mday = gmt->tm_mday; + st.tm_month = gmt->tm_month; + st.tm_year = gmt->tm_year; + st.tm_wday = gmt->tm_wday; + st.tm_yday = gmt->tm_yday; + + /* Apply the offset to GMT to obtain the local standard time */ + ApplySecOffset(&st, retVal.tp_gmt_offset); + + /* + * Apply the rules on standard time or GMT to obtain daylight saving + * time offset. In this implementation, we use the US DST rule. + */ + if (st.tm_month < 3) { + retVal.tp_dst_offset = 0L; + } else if (st.tm_month == 3) { + if (st.tm_wday == 0) { + /* A Sunday */ + if (st.tm_mday <= 7) { + /* First Sunday */ + /* 01:59:59 PST -> 03:00:00 PDT */ + if (st.tm_hour < 2) { + retVal.tp_dst_offset = 0L; + } else { + retVal.tp_dst_offset = 3600L; + } + } else { + /* Not first Sunday */ + retVal.tp_dst_offset = 3600L; + } + } else { + /* Not a Sunday. See if before first Sunday or after */ + if (st.tm_wday + 1 <= st.tm_mday) { + /* After first Sunday */ + retVal.tp_dst_offset = 3600L; + } else { + /* Before first Sunday */ + retVal.tp_dst_offset = 0L; + } + } + } else if (st.tm_month < 9) { + retVal.tp_dst_offset = 3600L; + } else if (st.tm_month == 9) { + if (st.tm_wday == 0) { + if (31 - st.tm_mday < 7) { + /* Last Sunday */ + /* 01:59:59 PDT -> 01:00:00 PST */ + if (st.tm_hour < 1) { + retVal.tp_dst_offset = 3600L; + } else { + retVal.tp_dst_offset = 0L; + } + } else { + /* Not last Sunday */ + retVal.tp_dst_offset = 3600L; + } + } else { + /* See if before or after last Sunday */ + if (7 - st.tm_wday <= 31 - st.tm_mday) { + /* before last Sunday */ + retVal.tp_dst_offset = 3600L; + } else { + retVal.tp_dst_offset = 0L; + } + } + } else { + retVal.tp_dst_offset = 0L; + } + return retVal; +} + +/* + *------------------------------------------------------------------------ + * + * PR_GMTParameters -- + * + * Returns the PRTimeParameters for Greenwich Mean Time. + * Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0. + * + *------------------------------------------------------------------------ + */ + +PR_IMPLEMENT(PRTimeParameters) +PR_GMTParameters(const PRExplodedTime *gmt) +{ +#if defined(XP_MAC) +#pragma unused (gmt) +#endif + + PRTimeParameters retVal = { 0, 0 }; + return retVal; +} + +/* + * The following code implements PR_ParseTimeString(). It is based on + * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski . + */ + +/* + * We only recognize the abbreviations of a small subset of time zones + * in North America, Europe, and Japan. + * + * PST/PDT: Pacific Standard/Daylight Time + * MST/MDT: Mountain Standard/Daylight Time + * CST/CDT: Central Standard/Daylight Time + * EST/EDT: Eastern Standard/Daylight Time + * AST: Atlantic Standard Time + * NST: Newfoundland Standard Time + * GMT: Greenwich Mean Time + * BST: British Summer Time + * MET: Middle Europe Time + * EET: Eastern Europe Time + * JST: Japan Standard Time + */ + +typedef enum +{ + TT_UNKNOWN, + + TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT, + + TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN, + TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC, + + TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT, + TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST +} TIME_TOKEN; + +/* + * This parses a time/date string into a PRTime + * (microseconds after "1-Jan-1970 00:00:00 GMT"). + * It returns PR_SUCCESS on success, and PR_FAILURE + * if the time/date string can't be parsed. + * + * Many formats are handled, including: + * + * 14 Apr 89 03:20:12 + * 14 Apr 89 03:20 GMT + * Fri, 17 Mar 89 4:01:33 + * Fri, 17 Mar 89 4:01 GMT + * Mon Jan 16 16:12 PDT 1989 + * Mon Jan 16 16:12 +0130 1989 + * 6 May 1992 16:41-JST (Wednesday) + * 22-AUG-1993 10:59:12.82 + * 22-AUG-1993 10:59pm + * 22-AUG-1993 12:59am + * 22-AUG-1993 12:59 PM + * Friday, August 04, 1995 3:54 PM + * 06/21/95 04:24:34 PM + * 20/06/95 21:07 + * 95-06-08 19:32:48 EDT + * + * If the input string doesn't contain a description of the timezone, + * we consult the `default_to_gmt' to decide whether the string should + * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE). + * The correct value for this argument depends on what standard specified + * the time string which you are parsing. + */ + +PR_IMPLEMENT(PRStatus) +PR_ParseTimeString( + const char *string, + PRBool default_to_gmt, + PRTime *result) +{ + PRExplodedTime tm; + TIME_TOKEN dotw = TT_UNKNOWN; + TIME_TOKEN month = TT_UNKNOWN; + TIME_TOKEN zone = TT_UNKNOWN; + int zone_offset = -1; + int date = -1; + PRInt32 year = -1; + int hour = -1; + int min = -1; + int sec = -1; + + const char *rest = string; + +#ifdef DEBUG + int iterations = 0; +#endif + + PR_ASSERT(string && result); + if (!string || !result) return PR_FAILURE; + + while (*rest) + { + +#ifdef DEBUG + if (iterations++ > 1000) + { + PR_ASSERT(0); + return PR_FAILURE; + } +#endif + + switch (*rest) + { + case 'a': case 'A': + if (month == TT_UNKNOWN && + (rest[1] == 'p' || rest[1] == 'P') && + (rest[2] == 'r' || rest[2] == 'R')) + month = TT_APR; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_AST; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'g' || rest[2] == 'G')) + month = TT_AUG; + break; + case 'b': case 'B': + if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_BST; + break; + case 'c': case 'C': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_CDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_CST; + break; + case 'd': case 'D': + if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'c' || rest[2] == 'C')) + month = TT_DEC; + break; + case 'e': case 'E': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EET; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_EST; + break; + case 'f': case 'F': + if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'b' || rest[2] == 'B')) + month = TT_FEB; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'r' || rest[1] == 'R') && + (rest[2] == 'i' || rest[2] == 'I')) + dotw = TT_FRI; + break; + case 'g': case 'G': + if (zone == TT_UNKNOWN && + (rest[1] == 'm' || rest[1] == 'M') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_GMT; + break; + case 'j': case 'J': + if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'n' || rest[2] == 'N')) + month = TT_JAN; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_JST; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'l' || rest[2] == 'L')) + month = TT_JUL; + else if (month == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'n' || rest[2] == 'N')) + month = TT_JUN; + break; + case 'm': case 'M': + if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'r' || rest[2] == 'R')) + month = TT_MAR; + else if (month == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 'y' || rest[2] == 'Y')) + month = TT_MAY; + else if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MET; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'o' || rest[1] == 'O') && + (rest[2] == 'n' || rest[2] == 'N')) + dotw = TT_MON; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_MST; + break; + case 'n': case 'N': + if (month == TT_UNKNOWN && + (rest[1] == 'o' || rest[1] == 'O') && + (rest[2] == 'v' || rest[2] == 'V')) + month = TT_NOV; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_NST; + break; + case 'o': case 'O': + if (month == TT_UNKNOWN && + (rest[1] == 'c' || rest[1] == 'C') && + (rest[2] == 't' || rest[2] == 'T')) + month = TT_OCT; + break; + case 'p': case 'P': + if (zone == TT_UNKNOWN && + (rest[1] == 'd' || rest[1] == 'D') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_PDT; + else if (zone == TT_UNKNOWN && + (rest[1] == 's' || rest[1] == 'S') && + (rest[2] == 't' || rest[2] == 'T')) + zone = TT_PST; + break; + case 's': case 'S': + if (dotw == TT_UNKNOWN && + (rest[1] == 'a' || rest[1] == 'A') && + (rest[2] == 't' || rest[2] == 'T')) + dotw = TT_SAT; + else if (month == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'p' || rest[2] == 'P')) + month = TT_SEP; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'n' || rest[2] == 'N')) + dotw = TT_SUN; + break; + case 't': case 'T': + if (dotw == TT_UNKNOWN && + (rest[1] == 'h' || rest[1] == 'H') && + (rest[2] == 'u' || rest[2] == 'U')) + dotw = TT_THU; + else if (dotw == TT_UNKNOWN && + (rest[1] == 'u' || rest[1] == 'U') && + (rest[2] == 'e' || rest[2] == 'E')) + dotw = TT_TUE; + break; + case 'u': case 'U': + if (zone == TT_UNKNOWN && + (rest[1] == 't' || rest[1] == 'T') && + !(rest[2] >= 'A' && rest[2] <= 'Z') && + !(rest[2] >= 'a' && rest[2] <= 'z')) + /* UT is the same as GMT but UTx is not. */ + zone = TT_GMT; + break; + case 'w': case 'W': + if (dotw == TT_UNKNOWN && + (rest[1] == 'e' || rest[1] == 'E') && + (rest[2] == 'd' || rest[2] == 'D')) + dotw = TT_WED; + break; + + case '+': case '-': + { + const char *end; + int sign; + if (zone_offset != -1) + { + /* already got one... */ + rest++; + break; + } + if (zone != TT_UNKNOWN && zone != TT_GMT) + { + /* GMT+0300 is legal, but PST+0300 is not. */ + rest++; + break; + } + + sign = ((*rest == '+') ? 1 : -1); + rest++; /* move over sign */ + end = rest; + while (*end >= '0' && *end <= '9') + end++; + if (rest == end) /* no digits here */ + break; + + if ((end - rest) == 4) + /* offset in HHMM */ + zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) + + (((rest[2]-'0')*10) + (rest[3]-'0'))); + else if ((end - rest) == 2) + /* offset in hours */ + zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60; + else if ((end - rest) == 1) + /* offset in hours */ + zone_offset = (rest[0]-'0') * 60; + else + /* 3 or >4 */ + break; + + zone_offset *= sign; + zone = TT_GMT; + break; + } + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int tmp_hour = -1; + int tmp_min = -1; + int tmp_sec = -1; + const char *end = rest + 1; + while (*end >= '0' && *end <= '9') + end++; + + /* end is now the first character after a range of digits. */ + + if (*end == ':') + { + if (hour >= 0 && min >= 0) /* already got it */ + break; + + /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */ + if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_hour = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_hour = (rest[0]-'0'); + + while (*rest && *rest != ':') + rest++; + rest++; + + /* move over the colon, and parse minutes */ + + end = rest + 1; + while (*end >= '0' && *end <= '9') + end++; + + if (end == rest) + /* no digits after first colon? */ + break; + else if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_min = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_min = (rest[0]-'0'); + + /* now go for seconds */ + rest = end; + if (*rest == ':') + rest++; + end = rest; + while (*end >= '0' && *end <= '9') + end++; + + if (end == rest) + /* no digits after second colon - that's ok. */ + ; + else if ((end - rest) > 2) + /* it is [0-9][0-9][0-9]+: */ + break; + else if ((end - rest) == 2) + tmp_sec = ((rest[0]-'0')*10 + + (rest[1]-'0')); + else + tmp_sec = (rest[0]-'0'); + + /* If we made it here, we've parsed hour and min, + and possibly sec, so it worked as a unit. */ + + /* skip over whitespace and see if there's an AM or PM + directly following the time. + */ + if (tmp_hour <= 12) + { + const char *s = end; + while (*s && (*s == ' ' || *s == '\t')) + s++; + if ((s[0] == 'p' || s[0] == 'P') && + (s[1] == 'm' || s[1] == 'M')) + /* 10:05pm == 22:05, and 12:05pm == 12:05 */ + tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12); + else if (tmp_hour == 12 && + (s[0] == 'a' || s[0] == 'A') && + (s[1] == 'm' || s[1] == 'M')) + /* 12:05am == 00:05 */ + tmp_hour = 0; + } + + hour = tmp_hour; + min = tmp_min; + sec = tmp_sec; + rest = end; + break; + } + else if ((*end == '/' || *end == '-') && + end[1] >= '0' && end[1] <= '9') + { + /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95 + or even 95-06-05... + #### But it doesn't handle 1995-06-22. + */ + int n1, n2, n3; + const char *s; + + if (month != TT_UNKNOWN) + /* if we saw a month name, this can't be. */ + break; + + s = rest; + + n1 = (*s++ - '0'); /* first 1 or 2 digits */ + if (*s >= '0' && *s <= '9') + n1 = n1*10 + (*s++ - '0'); + + if (*s != '/' && *s != '-') /* slash */ + break; + s++; + + if (*s < '0' || *s > '9') /* second 1 or 2 digits */ + break; + n2 = (*s++ - '0'); + if (*s >= '0' && *s <= '9') + n2 = n2*10 + (*s++ - '0'); + + if (*s != '/' && *s != '-') /* slash */ + break; + s++; + + if (*s < '0' || *s > '9') /* third 1, 2, or 4 digits */ + break; + n3 = (*s++ - '0'); + if (*s >= '0' && *s <= '9') + n3 = n3*10 + (*s++ - '0'); + + if (*s >= '0' && *s <= '9') /* optional digits 3 and 4 */ + { + n3 = n3*10 + (*s++ - '0'); + if (*s < '0' || *s > '9') + break; + n3 = n3*10 + (*s++ - '0'); + } + + if ((*s >= '0' && *s <= '9') || /* followed by non-alphanum */ + (*s >= 'A' && *s <= 'Z') || + (*s >= 'a' && *s <= 'z')) + break; + + /* Ok, we parsed three 1-2 digit numbers, with / or - + between them. Now decide what the hell they are + (DD/MM/YY or MM/DD/YY or YY/MM/DD.) + */ + + if (n1 > 31 || n1 == 0) /* must be YY/MM/DD */ + { + if (n2 > 12) break; + if (n3 > 31) break; + year = n1; + if (year < 70) + year += 2000; + else if (year < 100) + year += 1900; + month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1); + date = n3; + rest = s; + break; + } + + if (n1 > 12 && n2 > 12) /* illegal */ + { + rest = s; + break; + } + + if (n3 < 70) + n3 += 2000; + else if (n3 < 100) + n3 += 1900; + + if (n1 > 12) /* must be DD/MM/YY */ + { + date = n1; + month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1); + year = n3; + } + else /* assume MM/DD/YY */ + { + /* #### In the ambiguous case, should we consult the + locale to find out the local default? */ + month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1); + date = n2; + year = n3; + } + rest = s; + } + else if ((*end >= 'A' && *end <= 'Z') || + (*end >= 'a' && *end <= 'z')) + /* Digits followed by non-punctuation - what's that? */ + ; + else if ((end - rest) == 4) /* four digits is a year */ + year = (year < 0 + ? ((rest[0]-'0')*1000L + + (rest[1]-'0')*100L + + (rest[2]-'0')*10L + + (rest[3]-'0')) + : year); + else if ((end - rest) == 2) /* two digits - date or year */ + { + int n = ((rest[0]-'0')*10 + + (rest[1]-'0')); + /* If we don't have a date (day of the month) and we see a number + less than 32, then assume that is the date. + + Otherwise, if we have a date and not a year, assume this is the + year. If it is less than 70, then assume it refers to the 21st + century. If it is two digits (>= 70), assume it refers to this + century. Otherwise, assume it refers to an unambiguous year. + + The world will surely end soon. + */ + if (date < 0 && n < 32) + date = n; + else if (year < 0) + { + if (n < 70) + year = 2000 + n; + else if (n < 100) + year = 1900 + n; + else + year = n; + } + /* else what the hell is this. */ + } + else if ((end - rest) == 1) /* one digit - date */ + date = (date < 0 ? (rest[0]-'0') : date); + /* else, three or more than four digits - what's that? */ + + break; + } + } + + /* Skip to the end of this token, whether we parsed it or not. + Tokens are delimited by whitespace, or ,;-/ + But explicitly not :+-. + */ + while (*rest && + *rest != ' ' && *rest != '\t' && + *rest != ',' && *rest != ';' && + *rest != '-' && *rest != '+' && + *rest != '/' && + *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']') + rest++; + /* skip over uninteresting chars. */ + SKIP_MORE: + while (*rest && + (*rest == ' ' || *rest == '\t' || + *rest == ',' || *rest == ';' || *rest == '/' || + *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']')) + rest++; + + /* "-" is ignored at the beginning of a token if we have not yet + parsed a year (e.g., the second "-" in "30-AUG-1966"), or if + the character after the dash is not a digit. */ + if (*rest == '-' && ((rest > string && isalpha(rest[-1]) && year < 0) + || rest[1] < '0' || rest[1] > '9')) + { + rest++; + goto SKIP_MORE; + } + + } + + if (zone != TT_UNKNOWN && zone_offset == -1) + { + switch (zone) + { + case TT_PST: zone_offset = -8 * 60; break; + case TT_PDT: zone_offset = -7 * 60; break; + case TT_MST: zone_offset = -7 * 60; break; + case TT_MDT: zone_offset = -6 * 60; break; + case TT_CST: zone_offset = -6 * 60; break; + case TT_CDT: zone_offset = -5 * 60; break; + case TT_EST: zone_offset = -5 * 60; break; + case TT_EDT: zone_offset = -4 * 60; break; + case TT_AST: zone_offset = -4 * 60; break; + case TT_NST: zone_offset = -3 * 60 - 30; break; + case TT_GMT: zone_offset = 0 * 60; break; + case TT_BST: zone_offset = 1 * 60; break; + case TT_MET: zone_offset = 1 * 60; break; + case TT_EET: zone_offset = 2 * 60; break; + case TT_JST: zone_offset = 9 * 60; break; + default: + PR_ASSERT (0); + break; + } + } + + /* If we didn't find a year, month, or day-of-the-month, we can't + possibly parse this, and in fact, mktime() will do something random + (I'm seeing it return "Tue Feb 5 06:28:16 2036", which is no doubt + a numerologically significant date... */ + if (month == TT_UNKNOWN || date == -1 || year == -1) + return PR_FAILURE; + + memset(&tm, 0, sizeof(tm)); + if (sec != -1) + tm.tm_sec = sec; + if (min != -1) + tm.tm_min = min; + if (hour != -1) + tm.tm_hour = hour; + if (date != -1) + tm.tm_mday = date; + if (month != TT_UNKNOWN) + tm.tm_month = (((int)month) - ((int)TT_JAN)); + if (year != -1) + tm.tm_year = year; + if (dotw != TT_UNKNOWN) + tm.tm_wday = (((int)dotw) - ((int)TT_SUN)); + + if (zone == TT_UNKNOWN && default_to_gmt) + { + /* No zone was specified, so pretend the zone was GMT. */ + zone = TT_GMT; + zone_offset = 0; + } + + if (zone_offset == -1) + { + /* no zone was specified, and we're to assume that everything + is local. */ + struct tm localTime; + time_t secs; + + PR_ASSERT(tm.tm_month > -1 + && tm.tm_mday > 0 + && tm.tm_hour > -1 + && tm.tm_min > -1 + && tm.tm_sec > -1); + + /* + * To obtain time_t from a tm structure representing the local + * time, we call mktime(). However, we need to see if we are + * on 1-Jan-1970 or before. If we are, we can't call mktime() + * because mktime() will crash on win16. In that case, we + * calculate zone_offset based on the zone offset at + * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the + * date we are parsing to transform the date to GMT. We also + * do so if mktime() returns (time_t) -1 (time out of range). + */ + + /* month, day, hours, mins and secs are always non-negative + so we dont need to worry about them. */ + if(tm.tm_year >= 1970) + { + PRInt64 usec_per_sec; + + localTime.tm_sec = tm.tm_sec; + localTime.tm_min = tm.tm_min; + localTime.tm_hour = tm.tm_hour; + localTime.tm_mday = tm.tm_mday; + localTime.tm_mon = tm.tm_month; + localTime.tm_year = tm.tm_year - 1900; + /* Set this to -1 to tell mktime "I don't care". If you set + it to 0 or 1, you are making assertions about whether the + date you are handing it is in daylight savings mode or not; + and if you're wrong, it will "fix" it for you. */ + localTime.tm_isdst = -1; + secs = mktime(&localTime); + if (secs != (time_t) -1) + { +#if defined(XP_MAC) && (__MSL__ < 0x6000) + /* + * The mktime() routine in MetroWerks MSL C + * Runtime library returns seconds since midnight, + * 1 Jan. 1900, not 1970 - in versions of MSL (Metrowerks Standard + * Library) prior to version 6. Only for older versions of + * MSL do we adjust the value of secs to the NSPR epoch + */ + secs -= ((365 * 70UL) + 17) * 24 * 60 * 60; +#endif + LL_I2L(*result, secs); + LL_I2L(usec_per_sec, PR_USEC_PER_SEC); + LL_MUL(*result, *result, usec_per_sec); + return PR_SUCCESS; + } + } + + /* So mktime() can't handle this case. We assume the + zone_offset for the date we are parsing is the same as + the zone offset on 00:00:00 2 Jan 1970 GMT. */ + secs = 86400; + (void) MT_safe_localtime(&secs, &localTime); + zone_offset = localTime.tm_min + + 60 * localTime.tm_hour + + 1440 * (localTime.tm_mday - 2); + } + + /* Adjust the hours and minutes before handing them to + PR_ImplodeTime(). Note that it's ok for them to be <0 or >24/60 + + We adjust the time to GMT before going into PR_ImplodeTime(). + The zone_offset represents the difference between the time + zone parsed and GMT + */ + tm.tm_hour -= (zone_offset / 60); + tm.tm_min -= (zone_offset % 60); + + *result = PR_ImplodeTime(&tm); + + return PR_SUCCESS; +} + +/* + ******************************************************************* + ******************************************************************* + ** + ** OLD COMPATIBILITY FUNCTIONS + ** + ******************************************************************* + ******************************************************************* + */ + + +/* + *----------------------------------------------------------------------- + * + * PR_FormatTime -- + * + * Format a time value into a buffer. Same semantics as strftime(). + * + *----------------------------------------------------------------------- + */ + +PR_IMPLEMENT(PRUint32) +PR_FormatTime(char *buf, int buflen, const char *fmt, const PRExplodedTime *tm) +{ + struct tm a; + a.tm_sec = tm->tm_sec; + a.tm_min = tm->tm_min; + a.tm_hour = tm->tm_hour; + a.tm_mday = tm->tm_mday; + a.tm_mon = tm->tm_month; + a.tm_wday = tm->tm_wday; + a.tm_year = tm->tm_year - 1900; + a.tm_yday = tm->tm_yday; + a.tm_isdst = tm->tm_params.tp_dst_offset ? 1 : 0; + +/* + * On some platforms, for example SunOS 4, struct tm has two additional + * fields: tm_zone and tm_gmtoff. + */ + +#if defined(SUNOS4) || (__GLIBC__ >= 2) || defined(XP_BEOS) \ + || defined(NETBSD) || defined(OPENBSD) || defined(FREEBSD) \ + || defined(DARWIN) + a.tm_zone = NULL; + a.tm_gmtoff = tm->tm_params.tp_gmt_offset + tm->tm_params.tp_dst_offset; +#endif + + return strftime(buf, buflen, fmt, &a); +} + + +/* + * The following string arrays and macros are used by PR_FormatTimeUSEnglish(). + */ + +static const char* abbrevDays[] = +{ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" +}; + +static const char* days[] = +{ + "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" +}; + +static const char* abbrevMonths[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static const char* months[] = +{ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; + + +/* + * Add a single character to the given buffer, incrementing the buffer pointer + * and decrementing the buffer size. Return 0 on error. + */ +#define ADDCHAR( buf, bufSize, ch ) \ +do \ +{ \ + if( bufSize < 1 ) \ + { \ + *(--buf) = '\0'; \ + return 0; \ + } \ + *buf++ = ch; \ + bufSize--; \ +} \ +while(0) + + +/* + * Add a string to the given buffer, incrementing the buffer pointer + * and decrementing the buffer size appropriately. Return 0 on error. + */ +#define ADDSTR( buf, bufSize, str ) \ +do \ +{ \ + PRUint32 strSize = strlen( str ); \ + if( strSize > bufSize ) \ + { \ + if( bufSize==0 ) \ + *(--buf) = '\0'; \ + else \ + *buf = '\0'; \ + return 0; \ + } \ + memcpy(buf, str, strSize); \ + buf += strSize; \ + bufSize -= strSize; \ +} \ +while(0) + +/* Needed by PR_FormatTimeUSEnglish() */ +static unsigned int pr_WeekOfYear(const PRExplodedTime* time, + unsigned int firstDayOfWeek); + + +/*********************************************************************************** + * + * Description: + * This is a dumbed down version of strftime that will format the date in US + * English regardless of the setting of the global locale. This functionality is + * needed to write things like MIME headers which must always be in US English. + * + **********************************************************************************/ + +PR_IMPLEMENT(PRUint32) +PR_FormatTimeUSEnglish( char* buf, PRUint32 bufSize, + const char* format, const PRExplodedTime* time ) +{ + char* bufPtr = buf; + const char* fmtPtr; + char tmpBuf[ 40 ]; + const int tmpBufSize = sizeof( tmpBuf ); + + + for( fmtPtr=format; *fmtPtr != '\0'; fmtPtr++ ) + { + if( *fmtPtr != '%' ) + { + ADDCHAR( bufPtr, bufSize, *fmtPtr ); + } + else + { + switch( *(++fmtPtr) ) + { + case '%': + /* escaped '%' character */ + ADDCHAR( bufPtr, bufSize, '%' ); + break; + + case 'a': + /* abbreviated weekday name */ + ADDSTR( bufPtr, bufSize, abbrevDays[ time->tm_wday ] ); + break; + + case 'A': + /* full weekday name */ + ADDSTR( bufPtr, bufSize, days[ time->tm_wday ] ); + break; + + case 'b': + /* abbreviated month name */ + ADDSTR( bufPtr, bufSize, abbrevMonths[ time->tm_month ] ); + break; + + case 'B': + /* full month name */ + ADDSTR(bufPtr, bufSize, months[ time->tm_month ] ); + break; + + case 'c': + /* Date and time. */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%a %b %d %H:%M:%S %Y", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'd': + /* day of month ( 01 - 31 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_mday ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'H': + /* hour ( 00 - 23 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_hour ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'I': + /* hour ( 01 - 12 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld", + (time->tm_hour%12) ? time->tm_hour%12 : (PRInt32) 12 ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'j': + /* day number of year ( 001 - 366 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.3d",time->tm_yday + 1); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'm': + /* month number ( 01 - 12 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_month+1); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'M': + /* minute ( 00 - 59 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_min ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'p': + /* locale's equivalent of either AM or PM */ + ADDSTR( bufPtr, bufSize, (time->tm_hour<12)?"AM":"PM" ); + break; + + case 'S': + /* seconds ( 00 - 61 ), allows for leap seconds */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2ld",time->tm_sec ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'U': + /* week number of year ( 00 - 53 ), Sunday is the first day of week 1 */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 0 ) ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'w': + /* weekday number ( 0 - 6 ), Sunday = 0 */ + PR_snprintf(tmpBuf,tmpBufSize,"%d",time->tm_wday ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'W': + /* Week number of year ( 00 - 53 ), Monday is the first day of week 1 */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d", pr_WeekOfYear( time, 1 ) ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'x': + /* Date representation */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%m/%d/%y", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'X': + /* Time representation. */ + PR_FormatTimeUSEnglish( tmpBuf, tmpBufSize, "%H:%M:%S", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'y': + /* year within century ( 00 - 99 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.2d",time->tm_year % 100 ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'Y': + /* year as ccyy ( for example 1986 ) */ + PR_snprintf(tmpBuf,tmpBufSize,"%.4d",time->tm_year ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + case 'Z': + /* Time zone name or no characters if no time zone exists. + * Since time zone name is supposed to be independant of locale, we + * defer to PR_FormatTime() for this option. + */ + PR_FormatTime( tmpBuf, tmpBufSize, "%Z", time ); + ADDSTR( bufPtr, bufSize, tmpBuf ); + break; + + default: + /* Unknown format. Simply copy format into output buffer. */ + ADDCHAR( bufPtr, bufSize, '%' ); + ADDCHAR( bufPtr, bufSize, *fmtPtr ); + break; + + } + } + } + + ADDCHAR( bufPtr, bufSize, '\0' ); + return (PRUint32)(bufPtr - buf - 1); +} + + + +/*********************************************************************************** + * + * Description: + * Returns the week number of the year (0-53) for the given time. firstDayOfWeek + * is the day on which the week is considered to start (0=Sun, 1=Mon, ...). + * Week 1 starts the first time firstDayOfWeek occurs in the year. In other words, + * a partial week at the start of the year is considered week 0. + * + **********************************************************************************/ + +static unsigned int +pr_WeekOfYear(const PRExplodedTime* time, unsigned int firstDayOfWeek) +{ + int dayOfWeek; + int dayOfYear; + + /* Get the day of the year for the given time then adjust it to represent the + * first day of the week containing the given time. + */ + dayOfWeek = time->tm_wday - firstDayOfWeek; + if (dayOfWeek < 0) + dayOfWeek += 7; + + dayOfYear = time->tm_yday - dayOfWeek; + + + if( dayOfYear <= 0 ) + { + /* If dayOfYear is <= 0, it is in the first partial week of the year. */ + return 0; + } + else + { + /* Count the number of full weeks ( dayOfYear / 7 ) then add a week if there + * are any days left over ( dayOfYear % 7 ). Because we are only counting to + * the first day of the week containing the given time, rather than to the + * actual day representing the given time, any days in week 0 will be "absorbed" + * as extra days in the given week. + */ + return (dayOfYear / 7) + ( (dayOfYear % 7) == 0 ? 0 : 1 ); + } +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtpool.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtpool.c new file mode 100644 index 00000000..fbedd7de --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtpool.c @@ -0,0 +1,1217 @@ +/* -*- 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 ***** */ + +#include "nspr.h" + +/* + * Thread pools + * Thread pools create and manage threads to provide support for + * scheduling jobs onto one or more threads. + * + */ +#ifdef OPT_WINNT +#include +#endif + +/* + * worker thread + */ +typedef struct wthread { + PRCList links; + PRThread *thread; +} wthread; + +/* + * queue of timer jobs + */ +typedef struct timer_jobq { + PRCList list; + PRLock *lock; + PRCondVar *cv; + PRInt32 cnt; + PRCList wthreads; +} timer_jobq; + +/* + * queue of jobs + */ +typedef struct tp_jobq { + PRCList list; + PRInt32 cnt; + PRLock *lock; + PRCondVar *cv; + PRCList wthreads; +#ifdef OPT_WINNT + HANDLE nt_completion_port; +#endif +} tp_jobq; + +/* + * queue of IO jobs + */ +typedef struct io_jobq { + PRCList list; + PRPollDesc *pollfds; + PRInt32 npollfds; + PRJob **polljobs; + PRLock *lock; + PRInt32 cnt; + PRFileDesc *notify_fd; + PRCList wthreads; +} io_jobq; + +/* + * Threadpool + */ +struct PRThreadPool { + PRInt32 init_threads; + PRInt32 max_threads; + PRInt32 current_threads; + PRInt32 idle_threads; + PRUint32 stacksize; + tp_jobq jobq; + io_jobq ioq; + timer_jobq timerq; + PRLock *join_lock; /* used with jobp->join_cv */ + PRCondVar *shutdown_cv; + PRBool shutdown; +}; + +typedef enum io_op_type + { JOB_IO_READ, JOB_IO_WRITE, JOB_IO_CONNECT, JOB_IO_ACCEPT } io_op_type; + +#ifdef OPT_WINNT +typedef struct NT_notifier { + OVERLAPPED overlapped; /* must be first */ + PRJob *jobp; +} NT_notifier; +#endif + +struct PRJob { + PRCList links; /* for linking jobs */ + PRBool on_ioq; /* job on ioq */ + PRBool on_timerq; /* job on timerq */ + PRJobFn job_func; + void *job_arg; + PRCondVar *join_cv; + PRBool join_wait; /* == PR_TRUE, when waiting to join */ + PRCondVar *cancel_cv; /* for cancelling IO jobs */ + PRBool cancel_io; /* for cancelling IO jobs */ + PRThreadPool *tpool; /* back pointer to thread pool */ + PRJobIoDesc *iod; + io_op_type io_op; + PRInt16 io_poll_flags; + PRNetAddr *netaddr; + PRIntervalTime timeout; /* relative value */ + PRIntervalTime absolute; +#ifdef OPT_WINNT + NT_notifier nt_notifier; +#endif +}; + +#define JOB_LINKS_PTR(_qp) \ + ((PRJob *) ((char *) (_qp) - offsetof(PRJob, links))) + +#define WTHREAD_LINKS_PTR(_qp) \ + ((wthread *) ((char *) (_qp) - offsetof(wthread, links))) + +#define JOINABLE_JOB(_jobp) (NULL != (_jobp)->join_cv) + +#define JOIN_NOTIFY(_jobp) \ + PR_BEGIN_MACRO \ + PR_Lock(_jobp->tpool->join_lock); \ + _jobp->join_wait = PR_FALSE; \ + PR_NotifyCondVar(_jobp->join_cv); \ + PR_Unlock(_jobp->tpool->join_lock); \ + PR_END_MACRO + +#define CANCEL_IO_JOB(jobp) \ + PR_BEGIN_MACRO \ + jobp->cancel_io = PR_FALSE; \ + jobp->on_ioq = PR_FALSE; \ + PR_REMOVE_AND_INIT_LINK(&jobp->links); \ + tp->ioq.cnt--; \ + PR_NotifyCondVar(jobp->cancel_cv); \ + PR_END_MACRO + +static void delete_job(PRJob *jobp); +static PRThreadPool * alloc_threadpool(void); +static PRJob * alloc_job(PRBool joinable, PRThreadPool *tp); +static void notify_ioq(PRThreadPool *tp); +static void notify_timerq(PRThreadPool *tp); + +/* + * locks are acquired in the following order + * + * tp->ioq.lock,tp->timerq.lock + * | + * V + * tp->jobq->lock + */ + +/* + * worker thread function + */ +static void wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +PRCList *head; + + /* + * execute jobs until shutdown + */ + while (!tp->shutdown) { + PRJob *jobp; +#ifdef OPT_WINNT + BOOL rv; + DWORD unused, shutdown; + LPOVERLAPPED olp; + + PR_Lock(tp->jobq.lock); + tp->idle_threads++; + PR_Unlock(tp->jobq.lock); + rv = GetQueuedCompletionStatus(tp->jobq.nt_completion_port, + &unused, &shutdown, &olp, INFINITE); + + PR_ASSERT(rv); + if (shutdown) + break; + jobp = ((NT_notifier *) olp)->jobp; + PR_Lock(tp->jobq.lock); + tp->idle_threads--; + tp->jobq.cnt--; + PR_Unlock(tp->jobq.lock); +#else + + PR_Lock(tp->jobq.lock); + while (PR_CLIST_IS_EMPTY(&tp->jobq.list) && (!tp->shutdown)) { + tp->idle_threads++; + PR_WaitCondVar(tp->jobq.cv, PR_INTERVAL_NO_TIMEOUT); + tp->idle_threads--; + } + if (tp->shutdown) { + PR_Unlock(tp->jobq.lock); + break; + } + head = PR_LIST_HEAD(&tp->jobq.list); + /* + * remove job from queue + */ + PR_REMOVE_AND_INIT_LINK(head); + tp->jobq.cnt--; + jobp = JOB_LINKS_PTR(head); + PR_Unlock(tp->jobq.lock); +#endif + + jobp->job_func(jobp->job_arg); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + } + PR_Lock(tp->jobq.lock); + tp->current_threads--; + PR_Unlock(tp->jobq.lock); +} + +/* + * add a job to the work queue + */ +static void +add_to_jobq(PRThreadPool *tp, PRJob *jobp) +{ + /* + * add to jobq + */ +#ifdef OPT_WINNT + PR_Lock(tp->jobq.lock); + tp->jobq.cnt++; + PR_Unlock(tp->jobq.lock); + /* + * notify worker thread(s) + */ + PostQueuedCompletionStatus(tp->jobq.nt_completion_port, 0, + FALSE, &jobp->nt_notifier.overlapped); +#else + PR_Lock(tp->jobq.lock); + PR_APPEND_LINK(&jobp->links,&tp->jobq.list); + tp->jobq.cnt++; + if ((tp->idle_threads < tp->jobq.cnt) && + (tp->current_threads < tp->max_threads)) { + wthread *wthrp; + /* + * increment thread count and unlock the jobq lock + */ + tp->current_threads++; + PR_Unlock(tp->jobq.lock); + /* create new worker thread */ + wthrp = PR_NEWZAP(wthread); + if (wthrp) { + wthrp->thread = PR_CreateThread(PR_USER_THREAD, wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,tp->stacksize); + if (NULL == wthrp->thread) { + PR_DELETE(wthrp); /* this sets wthrp to NULL */ + } + } + PR_Lock(tp->jobq.lock); + if (NULL == wthrp) { + tp->current_threads--; + } else { + PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads); + } + } + /* + * wakeup a worker thread + */ + PR_NotifyCondVar(tp->jobq.cv); + PR_Unlock(tp->jobq.lock); +#endif +} + +/* + * io worker thread function + */ +static void io_wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +int pollfd_cnt, pollfds_used; +int rv; +PRCList *qp; +PRPollDesc *pollfds; +PRJob **polljobs; +int poll_timeout; +PRIntervalTime now; + + /* + * scan io_jobq + * construct poll list + * call PR_Poll + * for all fds, for which poll returns true, move the job to + * jobq and wakeup worker thread. + */ + while (!tp->shutdown) { + PRJob *jobp; + + pollfd_cnt = tp->ioq.cnt + 10; + if (pollfd_cnt > tp->ioq.npollfds) { + + /* + * re-allocate pollfd array if the current one is not large + * enough + */ + if (NULL != tp->ioq.pollfds) + PR_Free(tp->ioq.pollfds); + tp->ioq.pollfds = (PRPollDesc *) PR_Malloc(pollfd_cnt * + (sizeof(PRPollDesc) + sizeof(PRJob *))); + PR_ASSERT(NULL != tp->ioq.pollfds); + /* + * array of pollfds + */ + pollfds = tp->ioq.pollfds; + tp->ioq.polljobs = (PRJob **) (&tp->ioq.pollfds[pollfd_cnt]); + /* + * parallel array of jobs + */ + polljobs = tp->ioq.polljobs; + tp->ioq.npollfds = pollfd_cnt; + } + + pollfds_used = 0; + /* + * add the notify fd; used for unblocking io thread(s) + */ + pollfds[pollfds_used].fd = tp->ioq.notify_fd; + pollfds[pollfds_used].in_flags = PR_POLL_READ; + pollfds[pollfds_used].out_flags = 0; + polljobs[pollfds_used] = NULL; + pollfds_used++; + /* + * fill in the pollfd array + */ + PR_Lock(tp->ioq.lock); + for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = qp->next) { + jobp = JOB_LINKS_PTR(qp); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + continue; + } + if (pollfds_used == (pollfd_cnt)) + break; + pollfds[pollfds_used].fd = jobp->iod->socket; + pollfds[pollfds_used].in_flags = jobp->io_poll_flags; + pollfds[pollfds_used].out_flags = 0; + polljobs[pollfds_used] = jobp; + + pollfds_used++; + } + if (!PR_CLIST_IS_EMPTY(&tp->ioq.list)) { + qp = tp->ioq.list.next; + jobp = JOB_LINKS_PTR(qp); + if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) + poll_timeout = PR_INTERVAL_NO_TIMEOUT; + else if (PR_INTERVAL_NO_WAIT == jobp->timeout) + poll_timeout = PR_INTERVAL_NO_WAIT; + else { + poll_timeout = jobp->absolute - PR_IntervalNow(); + if (poll_timeout <= 0) /* already timed out */ + poll_timeout = PR_INTERVAL_NO_WAIT; + } + } else { + poll_timeout = PR_INTERVAL_NO_TIMEOUT; + } + PR_Unlock(tp->ioq.lock); + + /* + * XXXX + * should retry if more jobs have been added to the queue? + * + */ + PR_ASSERT(pollfds_used <= pollfd_cnt); + rv = PR_Poll(tp->ioq.pollfds, pollfds_used, poll_timeout); + + if (tp->shutdown) { + break; + } + + if (rv > 0) { + /* + * at least one io event is set + */ + PRStatus rval_status; + PRInt32 index; + + PR_ASSERT(pollfds[0].fd == tp->ioq.notify_fd); + /* + * reset the pollable event, if notified + */ + if (pollfds[0].out_flags & PR_POLL_READ) { + rval_status = PR_WaitForPollableEvent(tp->ioq.notify_fd); + PR_ASSERT(PR_SUCCESS == rval_status); + } + + for(index = 1; index < (pollfds_used); index++) { + PRInt16 events = pollfds[index].in_flags; + PRInt16 revents = pollfds[index].out_flags; + jobp = polljobs[index]; + + if ((revents & PR_POLL_NVAL) || /* busted in all cases */ + (revents & PR_POLL_ERR) || + ((events & PR_POLL_WRITE) && + (revents & PR_POLL_HUP))) { /* write op & hup */ + PR_Lock(tp->ioq.lock); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + PR_Unlock(tp->ioq.lock); + continue; + } + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + PR_Unlock(tp->ioq.lock); + + /* set error */ + if (PR_POLL_NVAL & revents) + jobp->iod->error = PR_BAD_DESCRIPTOR_ERROR; + else if (PR_POLL_HUP & revents) + jobp->iod->error = PR_CONNECT_RESET_ERROR; + else + jobp->iod->error = PR_IO_ERROR; + + /* + * add to jobq + */ + add_to_jobq(tp, jobp); + } else if (revents) { + /* + * add to jobq + */ + PR_Lock(tp->ioq.lock); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + PR_Unlock(tp->ioq.lock); + continue; + } + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + PR_Unlock(tp->ioq.lock); + + if (jobp->io_op == JOB_IO_CONNECT) { + if (PR_GetConnectStatus(&pollfds[index]) == PR_SUCCESS) + jobp->iod->error = 0; + else + jobp->iod->error = PR_GetError(); + } else + jobp->iod->error = 0; + + add_to_jobq(tp, jobp); + } + } + } + /* + * timeout processing + */ + now = PR_IntervalNow(); + PR_Lock(tp->ioq.lock); + for (qp = tp->ioq.list.next; qp != &tp->ioq.list; qp = qp->next) { + jobp = JOB_LINKS_PTR(qp); + if (jobp->cancel_io) { + CANCEL_IO_JOB(jobp); + continue; + } + if (PR_INTERVAL_NO_TIMEOUT == jobp->timeout) + break; + if ((PR_INTERVAL_NO_WAIT != jobp->timeout) && + ((PRInt32)(jobp->absolute - now) > 0)) + break; + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->ioq.cnt--; + jobp->on_ioq = PR_FALSE; + jobp->iod->error = PR_IO_TIMEOUT_ERROR; + add_to_jobq(tp, jobp); + } + PR_Unlock(tp->ioq.lock); + } +} + +/* + * timer worker thread function + */ +static void timer_wstart(void *arg) +{ +PRThreadPool *tp = (PRThreadPool *) arg; +PRCList *qp; +PRIntervalTime timeout; +PRIntervalTime now; + + /* + * call PR_WaitCondVar with minimum value of all timeouts + */ + while (!tp->shutdown) { + PRJob *jobp; + + PR_Lock(tp->timerq.lock); + if (PR_CLIST_IS_EMPTY(&tp->timerq.list)) { + timeout = PR_INTERVAL_NO_TIMEOUT; + } else { + PRCList *qp; + + qp = tp->timerq.list.next; + jobp = JOB_LINKS_PTR(qp); + + timeout = jobp->absolute - PR_IntervalNow(); + if (timeout <= 0) + timeout = PR_INTERVAL_NO_WAIT; /* already timed out */ + } + if (PR_INTERVAL_NO_WAIT != timeout) + PR_WaitCondVar(tp->timerq.cv, timeout); + if (tp->shutdown) { + PR_Unlock(tp->timerq.lock); + break; + } + /* + * move expired-timer jobs to jobq + */ + now = PR_IntervalNow(); + while (!PR_CLIST_IS_EMPTY(&tp->timerq.list)) { + qp = tp->timerq.list.next; + jobp = JOB_LINKS_PTR(qp); + + if ((PRInt32)(jobp->absolute - now) > 0) { + break; + } + /* + * job timed out + */ + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->timerq.cnt--; + jobp->on_timerq = PR_FALSE; + add_to_jobq(tp, jobp); + } + PR_Unlock(tp->timerq.lock); + } +} + +static void +delete_threadpool(PRThreadPool *tp) +{ + if (NULL != tp) { + if (NULL != tp->shutdown_cv) + PR_DestroyCondVar(tp->shutdown_cv); + if (NULL != tp->jobq.cv) + PR_DestroyCondVar(tp->jobq.cv); + if (NULL != tp->jobq.lock) + PR_DestroyLock(tp->jobq.lock); + if (NULL != tp->join_lock) + PR_DestroyLock(tp->join_lock); +#ifdef OPT_WINNT + if (NULL != tp->jobq.nt_completion_port) + CloseHandle(tp->jobq.nt_completion_port); +#endif + /* Timer queue */ + if (NULL != tp->timerq.cv) + PR_DestroyCondVar(tp->timerq.cv); + if (NULL != tp->timerq.lock) + PR_DestroyLock(tp->timerq.lock); + + if (NULL != tp->ioq.lock) + PR_DestroyLock(tp->ioq.lock); + if (NULL != tp->ioq.pollfds) + PR_Free(tp->ioq.pollfds); + if (NULL != tp->ioq.notify_fd) + PR_DestroyPollableEvent(tp->ioq.notify_fd); + PR_Free(tp); + } + return; +} + +static PRThreadPool * +alloc_threadpool(void) +{ +PRThreadPool *tp; + + tp = (PRThreadPool *) PR_CALLOC(sizeof(*tp)); + if (NULL == tp) + goto failed; + tp->jobq.lock = PR_NewLock(); + if (NULL == tp->jobq.lock) + goto failed; + tp->jobq.cv = PR_NewCondVar(tp->jobq.lock); + if (NULL == tp->jobq.cv) + goto failed; + tp->join_lock = PR_NewLock(); + if (NULL == tp->join_lock) + goto failed; +#ifdef OPT_WINNT + tp->jobq.nt_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, 0, 0); + if (NULL == tp->jobq.nt_completion_port) + goto failed; +#endif + + tp->ioq.lock = PR_NewLock(); + if (NULL == tp->ioq.lock) + goto failed; + + /* Timer queue */ + + tp->timerq.lock = PR_NewLock(); + if (NULL == tp->timerq.lock) + goto failed; + tp->timerq.cv = PR_NewCondVar(tp->timerq.lock); + if (NULL == tp->timerq.cv) + goto failed; + + tp->shutdown_cv = PR_NewCondVar(tp->jobq.lock); + if (NULL == tp->shutdown_cv) + goto failed; + tp->ioq.notify_fd = PR_NewPollableEvent(); + if (NULL == tp->ioq.notify_fd) + goto failed; + return tp; +failed: + delete_threadpool(tp); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; +} + +/* Create thread pool */ +PR_IMPLEMENT(PRThreadPool *) +PR_CreateThreadPool(PRInt32 initial_threads, PRInt32 max_threads, + PRUint32 stacksize) +{ +PRThreadPool *tp; +PRThread *thr; +int i; +wthread *wthrp; + + tp = alloc_threadpool(); + if (NULL == tp) + return NULL; + + tp->init_threads = initial_threads; + tp->max_threads = max_threads; + tp->stacksize = stacksize; + PR_INIT_CLIST(&tp->jobq.list); + PR_INIT_CLIST(&tp->ioq.list); + PR_INIT_CLIST(&tp->timerq.list); + PR_INIT_CLIST(&tp->jobq.wthreads); + PR_INIT_CLIST(&tp->ioq.wthreads); + PR_INIT_CLIST(&tp->timerq.wthreads); + tp->shutdown = PR_FALSE; + + PR_Lock(tp->jobq.lock); + for(i=0; i < initial_threads; ++i) { + + thr = PR_CreateThread(PR_USER_THREAD, wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->jobq.wthreads); + } + tp->current_threads = initial_threads; + + thr = PR_CreateThread(PR_USER_THREAD, io_wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->ioq.wthreads); + + thr = PR_CreateThread(PR_USER_THREAD, timer_wstart, + tp, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD,PR_JOINABLE_THREAD,stacksize); + PR_ASSERT(thr); + wthrp = PR_NEWZAP(wthread); + PR_ASSERT(wthrp); + wthrp->thread = thr; + PR_APPEND_LINK(&wthrp->links, &tp->timerq.wthreads); + + PR_Unlock(tp->jobq.lock); + return tp; +} + +static void +delete_job(PRJob *jobp) +{ + if (NULL != jobp) { + if (NULL != jobp->join_cv) { + PR_DestroyCondVar(jobp->join_cv); + jobp->join_cv = NULL; + } + if (NULL != jobp->cancel_cv) { + PR_DestroyCondVar(jobp->cancel_cv); + jobp->cancel_cv = NULL; + } + PR_DELETE(jobp); + } +} + +static PRJob * +alloc_job(PRBool joinable, PRThreadPool *tp) +{ + PRJob *jobp; + + jobp = PR_NEWZAP(PRJob); + if (NULL == jobp) + goto failed; + if (joinable) { + jobp->join_cv = PR_NewCondVar(tp->join_lock); + jobp->join_wait = PR_TRUE; + if (NULL == jobp->join_cv) + goto failed; + } else { + jobp->join_cv = NULL; + } +#ifdef OPT_WINNT + jobp->nt_notifier.jobp = jobp; +#endif + return jobp; +failed: + delete_job(jobp); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; +} + +/* queue a job */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob(PRThreadPool *tpool, PRJobFn fn, void *arg, PRBool joinable) +{ + PRJob *jobp; + + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) + return NULL; + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + + add_to_jobq(tpool, jobp); + return jobp; +} + +/* queue a job, when a socket is readable or writeable */ +static PRJob * +queue_io_job(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, + PRBool joinable, io_op_type op) +{ + PRJob *jobp; + PRIntervalTime now; + + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) { + return NULL; + } + + /* + * Add a new job to io_jobq + * wakeup io worker thread + */ + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + jobp->iod = iod; + if (JOB_IO_READ == op) { + jobp->io_op = JOB_IO_READ; + jobp->io_poll_flags = PR_POLL_READ; + } else if (JOB_IO_WRITE == op) { + jobp->io_op = JOB_IO_WRITE; + jobp->io_poll_flags = PR_POLL_WRITE; + } else if (JOB_IO_ACCEPT == op) { + jobp->io_op = JOB_IO_ACCEPT; + jobp->io_poll_flags = PR_POLL_READ; + } else if (JOB_IO_CONNECT == op) { + jobp->io_op = JOB_IO_CONNECT; + jobp->io_poll_flags = PR_POLL_WRITE|PR_POLL_EXCEPT; + } else { + delete_job(jobp); + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + + jobp->timeout = iod->timeout; + if ((PR_INTERVAL_NO_TIMEOUT == iod->timeout) || + (PR_INTERVAL_NO_WAIT == iod->timeout)) { + jobp->absolute = iod->timeout; + } else { + now = PR_IntervalNow(); + jobp->absolute = now + iod->timeout; + } + + + PR_Lock(tpool->ioq.lock); + + if (PR_CLIST_IS_EMPTY(&tpool->ioq.list) || + (PR_INTERVAL_NO_TIMEOUT == iod->timeout)) { + PR_APPEND_LINK(&jobp->links,&tpool->ioq.list); + } else if (PR_INTERVAL_NO_WAIT == iod->timeout) { + PR_INSERT_LINK(&jobp->links,&tpool->ioq.list); + } else { + PRCList *qp; + PRJob *tmp_jobp; + /* + * insert into the timeout-sorted ioq + */ + for (qp = tpool->ioq.list.prev; qp != &tpool->ioq.list; + qp = qp->prev) { + tmp_jobp = JOB_LINKS_PTR(qp); + if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { + break; + } + } + PR_INSERT_AFTER(&jobp->links,qp); + } + + jobp->on_ioq = PR_TRUE; + tpool->ioq.cnt++; + /* + * notify io worker thread(s) + */ + PR_Unlock(tpool->ioq.lock); + notify_ioq(tpool); + return jobp; +} + +/* queue a job, when a socket is readable */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Read(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, void * arg, + PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_READ)); +} + +/* queue a job, when a socket is writeable */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Write(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn,void * arg, + PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_WRITE)); +} + + +/* queue a job, when a socket has a pending connection */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Accept(PRThreadPool *tpool, PRJobIoDesc *iod, PRJobFn fn, + void * arg, PRBool joinable) +{ + return (queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_ACCEPT)); +} + +/* queue a job, when a socket can be connected */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Connect(PRThreadPool *tpool, PRJobIoDesc *iod, + const PRNetAddr *addr, PRJobFn fn, void * arg, PRBool joinable) +{ + PRStatus rv; + PRErrorCode err; + + rv = PR_Connect(iod->socket, addr, PR_INTERVAL_NO_WAIT); + if ((rv == PR_FAILURE) && ((err = PR_GetError()) == PR_IN_PROGRESS_ERROR)){ + /* connection pending */ + return(queue_io_job(tpool, iod, fn, arg, joinable, JOB_IO_CONNECT)); + } else { + /* + * connection succeeded or failed; add to jobq right away + */ + if (rv == PR_FAILURE) + iod->error = err; + else + iod->error = 0; + return(PR_QueueJob(tpool, fn, arg, joinable)); + } +} + +/* queue a job, when a timer expires */ +PR_IMPLEMENT(PRJob *) +PR_QueueJob_Timer(PRThreadPool *tpool, PRIntervalTime timeout, + PRJobFn fn, void * arg, PRBool joinable) +{ + PRIntervalTime now; + PRJob *jobp; + + if (PR_INTERVAL_NO_TIMEOUT == timeout) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + if (PR_INTERVAL_NO_WAIT == timeout) { + /* + * no waiting; add to jobq right away + */ + return(PR_QueueJob(tpool, fn, arg, joinable)); + } + jobp = alloc_job(joinable, tpool); + if (NULL == jobp) { + return NULL; + } + + /* + * Add a new job to timer_jobq + * wakeup timer worker thread + */ + + jobp->job_func = fn; + jobp->job_arg = arg; + jobp->tpool = tpool; + jobp->timeout = timeout; + + now = PR_IntervalNow(); + jobp->absolute = now + timeout; + + + PR_Lock(tpool->timerq.lock); + jobp->on_timerq = PR_TRUE; + if (PR_CLIST_IS_EMPTY(&tpool->timerq.list)) + PR_APPEND_LINK(&jobp->links,&tpool->timerq.list); + else { + PRCList *qp; + PRJob *tmp_jobp; + /* + * insert into the sorted timer jobq + */ + for (qp = tpool->timerq.list.prev; qp != &tpool->timerq.list; + qp = qp->prev) { + tmp_jobp = JOB_LINKS_PTR(qp); + if ((PRInt32)(jobp->absolute - tmp_jobp->absolute) >= 0) { + break; + } + } + PR_INSERT_AFTER(&jobp->links,qp); + } + tpool->timerq.cnt++; + /* + * notify timer worker thread(s) + */ + notify_timerq(tpool); + PR_Unlock(tpool->timerq.lock); + return jobp; +} + +static void +notify_timerq(PRThreadPool *tp) +{ + /* + * wakeup the timer thread(s) + */ + PR_NotifyCondVar(tp->timerq.cv); +} + +static void +notify_ioq(PRThreadPool *tp) +{ +PRStatus rval_status; + + /* + * wakeup the io thread(s) + */ + rval_status = PR_SetPollableEvent(tp->ioq.notify_fd); + PR_ASSERT(PR_SUCCESS == rval_status); +} + +/* + * cancel a job + * + * XXXX: is this needed? likely to be removed + */ +PR_IMPLEMENT(PRStatus) +PR_CancelJob(PRJob *jobp) { + + PRStatus rval = PR_FAILURE; + PRThreadPool *tp; + + if (jobp->on_timerq) { + /* + * now, check again while holding the timerq lock + */ + tp = jobp->tpool; + PR_Lock(tp->timerq.lock); + if (jobp->on_timerq) { + jobp->on_timerq = PR_FALSE; + PR_REMOVE_AND_INIT_LINK(&jobp->links); + tp->timerq.cnt--; + PR_Unlock(tp->timerq.lock); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + rval = PR_SUCCESS; + } else + PR_Unlock(tp->timerq.lock); + } else if (jobp->on_ioq) { + /* + * now, check again while holding the ioq lock + */ + tp = jobp->tpool; + PR_Lock(tp->ioq.lock); + if (jobp->on_ioq) { + jobp->cancel_cv = PR_NewCondVar(tp->ioq.lock); + if (NULL == jobp->cancel_cv) { + PR_Unlock(tp->ioq.lock); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return PR_FAILURE; + } + /* + * mark job 'cancelled' and notify io thread(s) + * XXXX: + * this assumes there is only one io thread; when there + * are multiple threads, the io thread processing this job + * must be notified. + */ + jobp->cancel_io = PR_TRUE; + PR_Unlock(tp->ioq.lock); /* release, reacquire ioq lock */ + notify_ioq(tp); + PR_Lock(tp->ioq.lock); + while (jobp->cancel_io) + PR_WaitCondVar(jobp->cancel_cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(tp->ioq.lock); + PR_ASSERT(!jobp->on_ioq); + if (!JOINABLE_JOB(jobp)) { + delete_job(jobp); + } else { + JOIN_NOTIFY(jobp); + } + rval = PR_SUCCESS; + } else + PR_Unlock(tp->ioq.lock); + } + if (PR_FAILURE == rval) + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return rval; +} + +/* join a job, wait until completion */ +PR_IMPLEMENT(PRStatus) +PR_JoinJob(PRJob *jobp) +{ + if (!JOINABLE_JOB(jobp)) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + PR_Lock(jobp->tpool->join_lock); + while(jobp->join_wait) + PR_WaitCondVar(jobp->join_cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(jobp->tpool->join_lock); + delete_job(jobp); + return PR_SUCCESS; +} + +/* shutdown threadpool */ +PR_IMPLEMENT(PRStatus) +PR_ShutdownThreadPool(PRThreadPool *tpool) +{ +PRStatus rval = PR_SUCCESS; + + PR_Lock(tpool->jobq.lock); + tpool->shutdown = PR_TRUE; + PR_NotifyAllCondVar(tpool->shutdown_cv); + PR_Unlock(tpool->jobq.lock); + + return rval; +} + +/* + * join thread pool + * wait for termination of worker threads + * reclaim threadpool resources + */ +PR_IMPLEMENT(PRStatus) +PR_JoinThreadPool(PRThreadPool *tpool) +{ +PRStatus rval = PR_SUCCESS; +PRCList *head; +PRStatus rval_status; + + PR_Lock(tpool->jobq.lock); + while (!tpool->shutdown) + PR_WaitCondVar(tpool->shutdown_cv, PR_INTERVAL_NO_TIMEOUT); + + /* + * wakeup worker threads + */ +#ifdef OPT_WINNT + /* + * post shutdown notification for all threads + */ + { + int i; + for(i=0; i < tpool->current_threads; i++) { + PostQueuedCompletionStatus(tpool->jobq.nt_completion_port, 0, + TRUE, NULL); + } + } +#else + PR_NotifyAllCondVar(tpool->jobq.cv); +#endif + + /* + * wakeup io thread(s) + */ + notify_ioq(tpool); + + /* + * wakeup timer thread(s) + */ + PR_Lock(tpool->timerq.lock); + notify_timerq(tpool); + PR_Unlock(tpool->timerq.lock); + + while (!PR_CLIST_IS_EMPTY(&tpool->jobq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->jobq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + PR_Unlock(tpool->jobq.lock); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + PR_Lock(tpool->jobq.lock); + } + PR_Unlock(tpool->jobq.lock); + while (!PR_CLIST_IS_EMPTY(&tpool->ioq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->ioq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + } + + while (!PR_CLIST_IS_EMPTY(&tpool->timerq.wthreads)) { + wthread *wthrp; + + head = PR_LIST_HEAD(&tpool->timerq.wthreads); + PR_REMOVE_AND_INIT_LINK(head); + wthrp = WTHREAD_LINKS_PTR(head); + rval_status = PR_JoinThread(wthrp->thread); + PR_ASSERT(PR_SUCCESS == rval_status); + PR_DELETE(wthrp); + } + + /* + * Delete queued jobs + */ + while (!PR_CLIST_IS_EMPTY(&tpool->jobq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->jobq.list); + PR_REMOVE_AND_INIT_LINK(head); + jobp = JOB_LINKS_PTR(head); + tpool->jobq.cnt--; + delete_job(jobp); + } + + /* delete io jobs */ + while (!PR_CLIST_IS_EMPTY(&tpool->ioq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->ioq.list); + PR_REMOVE_AND_INIT_LINK(head); + tpool->ioq.cnt--; + jobp = JOB_LINKS_PTR(head); + delete_job(jobp); + } + + /* delete timer jobs */ + while (!PR_CLIST_IS_EMPTY(&tpool->timerq.list)) { + PRJob *jobp; + + head = PR_LIST_HEAD(&tpool->timerq.list); + PR_REMOVE_AND_INIT_LINK(head); + tpool->timerq.cnt--; + jobp = JOB_LINKS_PTR(head); + delete_job(jobp); + } + + PR_ASSERT(0 == tpool->jobq.cnt); + PR_ASSERT(0 == tpool->ioq.cnt); + PR_ASSERT(0 == tpool->timerq.cnt); + + delete_threadpool(tpool); + return rval; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtrace.c b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtrace.c new file mode 100644 index 00000000..d26f5027 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/misc/prtrace.c @@ -0,0 +1,922 @@ +/* -*- 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 ***** */ + +/* +** prtrace.c -- NSPR Trace Instrumentation +** +** Implement the API defined in prtrace.h +** +** +** +*/ + +#include +#include "prtrace.h" +#include "prclist.h" +#include "prlock.h" +#include "prcvar.h" +#include "prio.h" +#include "prlog.h" +#include "prenv.h" +#include "prmem.h" +#include "prerror.h" + + +#define DEFAULT_TRACE_BUFSIZE ( 1024 * 1024 ) +#define DEFAULT_BUFFER_SEGMENTS 2 + +/* +** Enumerate states in a RName structure +*/ +typedef enum TraceState +{ + Running = 1, + Suspended = 2 +} TraceState; + +/* +** Define QName structure +*/ +typedef struct QName +{ + PRCList link; + PRCList rNameList; + char name[PRTRACE_NAME_MAX+1]; +} QName; + +/* +** Define RName structure +*/ +typedef struct RName +{ + PRCList link; + PRLock *lock; + QName *qName; + TraceState state; + char name[PRTRACE_NAME_MAX+1]; + char desc[PRTRACE_DESC_MAX+1]; +} RName; + + +/* +** The Trace Facility database +** +*/ +static PRLogModuleInfo *lm; + +static PRLock *traceLock; /* Facility Lock */ +static PRCList qNameList; /* anchor to all QName structures */ +static TraceState traceState = Running; + +/* +** in-memory trace buffer controls +*/ +static PRTraceEntry *tBuf; /* pointer to buffer */ +static PRInt32 bufSize; /* size of buffer, in bytes, rounded up to sizeof(PRTraceEntry) */ +static volatile PRInt32 next; /* index to next PRTraceEntry */ +static PRInt32 last; /* index of highest numbered trace entry */ + +/* +** Real-time buffer capture controls +*/ +static PRInt32 fetchLastSeen = 0; +static PRBool fetchLostData = PR_FALSE; + +/* +** Buffer write-to-file controls +*/ +static PRLock *logLock; /* Sync lock */ +static PRCondVar *logCVar; /* Sync Condidtion Variable */ +/* +** Inter-thread state communication. +** Controling thread writes to logOrder under protection of logCVar +** the logging thread reads logOrder and sets logState on Notify. +** +** logSegments, logCount, logLostData must be read and written under +** protection of logLock, logCVar. +** +*/ +static enum LogState +{ + LogNotRunning, /* Initial state */ + LogReset, /* Causes logger to re-calc controls */ + LogActive, /* Logging in progress, set only by log thread */ + LogSuspend, /* Suspend Logging */ + LogResume, /* Resume Logging => LogActive */ + LogStop /* Stop the log thread */ +} logOrder, logState, localState; /* controlling state variables */ +static PRInt32 logSegments; /* Number of buffer segments */ +static PRInt32 logEntries; /* number of Trace Entries in the buffer */ +static PRInt32 logEntriesPerSegment; /* number of PRTraceEntries per buffer segment */ +static PRInt32 logSegSize; /* size of buffer segment */ +static PRInt32 logCount; /* number of segments pending output */ +static PRInt32 logLostData; /* number of lost log buffer segments */ + +/* +** end Trace Database +** +*/ + +/* +** _PR_InitializeTrace() -- Initialize the trace facility +*/ +static void NewTraceBuffer( PRInt32 size ) +{ + /* + ** calculate the size of the buffer + ** round down so that each segment has the same number of + ** trace entries + */ + logSegments = DEFAULT_BUFFER_SEGMENTS; + logEntries = size / sizeof(PRTraceEntry); + logEntriesPerSegment = logEntries / logSegments; + logEntries = logSegments * logEntriesPerSegment; + bufSize = logEntries * sizeof(PRTraceEntry); + logSegSize = logEntriesPerSegment * sizeof(PRTraceEntry); + PR_ASSERT( bufSize != 0); + PR_LOG( lm, PR_LOG_ERROR, + ("NewTraceBuffer: logSegments: %ld, logEntries: %ld, logEntriesPerSegment: %ld, logSegSize: %ld", + logSegments, logEntries, logEntriesPerSegment, logSegSize )); + + + tBuf = PR_Malloc( bufSize ); + if ( tBuf == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("PRTrace: Failed to get trace buffer")); + PR_ASSERT( 0 ); + } + else + { + PR_LOG( lm, PR_LOG_NOTICE, + ("PRTrace: Got trace buffer of size: %ld, at %p", bufSize, tBuf)); + } + + next = 0; + last = logEntries -1; + logCount = 0; + logLostData = PR_TRUE; /* not really on first call */ + logOrder = LogReset; + +} /* end NewTraceBuffer() */ + +/* +** _PR_InitializeTrace() -- Initialize the trace facility +*/ +static void _PR_InitializeTrace( void ) +{ + /* The lock pointer better be null on this call */ + PR_ASSERT( traceLock == NULL ); + + traceLock = PR_NewLock(); + PR_ASSERT( traceLock != NULL ); + + PR_Lock( traceLock ); + + PR_INIT_CLIST( &qNameList ); + + lm = PR_NewLogModule("trace"); + + bufSize = DEFAULT_TRACE_BUFSIZE; + NewTraceBuffer( bufSize ); + + /* Initialize logging controls */ + logLock = PR_NewLock(); + logCVar = PR_NewCondVar( logLock ); + + PR_Unlock( traceLock ); + return; +} /* end _PR_InitializeTrace() */ + +/* +** Create a Trace Handle +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_CreateTrace( + const char *qName, /* QName for this trace handle */ + const char *rName, /* RName for this trace handle */ + const char *description /* description for this trace handle */ +) +{ + QName *qnp; + RName *rnp; + PRBool matchQname = PR_FALSE; + + /* Self initialize, if necessary */ + if ( traceLock == NULL ) + _PR_InitializeTrace(); + + /* Validate input arguments */ + PR_ASSERT( strlen(qName) <= PRTRACE_NAME_MAX ); + PR_ASSERT( strlen(rName) <= PRTRACE_NAME_MAX ); + PR_ASSERT( strlen(description) <= PRTRACE_DESC_MAX ); + + PR_LOG( lm, PR_LOG_DEBUG, + ("PRTRACE: CreateTrace: Qname: %s, RName: %s", qName, rName)); + + /* Lock the Facility */ + PR_Lock( traceLock ); + + /* Do we already have a matching QName? */ + if (!PR_CLIST_IS_EMPTY( &qNameList )) + { + qnp = (QName *) PR_LIST_HEAD( &qNameList ); + do { + if ( strcmp(qnp->name, qName) == 0) + { + matchQname = PR_TRUE; + break; + } + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + } while( qnp != (QName *)PR_LIST_HEAD( &qNameList )); + } + /* + ** If we did not find a matching QName, + ** allocate one and initialize it. + ** link it onto the qNameList. + ** + */ + if ( matchQname != PR_TRUE ) + { + qnp = PR_NEWZAP( QName ); + PR_ASSERT( qnp != NULL ); + PR_INIT_CLIST( &qnp->link ); + PR_INIT_CLIST( &qnp->rNameList ); + strcpy( qnp->name, qName ); + PR_APPEND_LINK( &qnp->link, &qNameList ); + } + + /* Do we already have a matching RName? */ + if (!PR_CLIST_IS_EMPTY( &qnp->rNameList )) + { + rnp = (RName *) PR_LIST_HEAD( &qnp->rNameList ); + do { + /* + ** No duplicate RNames are allowed within a QName + ** + */ + PR_ASSERT( strcmp(rnp->name, rName)); + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + } while( rnp != (RName *)PR_LIST_HEAD( &qnp->rNameList )); + } + + /* Get a new RName structure; initialize its members */ + rnp = PR_NEWZAP( RName ); + PR_ASSERT( rnp != NULL ); + PR_INIT_CLIST( &rnp->link ); + strcpy( rnp->name, rName ); + strcpy( rnp->desc, description ); + rnp->lock = PR_NewLock(); + rnp->state = Running; + if ( rnp->lock == NULL ) + { + PR_ASSERT(0); + } + + PR_APPEND_LINK( &rnp->link, &qnp->rNameList ); /* add RName to QName's rnList */ + rnp->qName = qnp; /* point the RName to the QName */ + + /* Unlock the Facility */ + PR_Unlock( traceLock ); + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Create: QName: %s %p, RName: %s %p\n\t", + qName, qnp, rName, rnp )); + + return((PRTraceHandle)rnp); +} /* end PR_CreateTrace() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_DestroyTrace( + PRTraceHandle handle /* Handle to be destroyed */ +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting: QName: %s, RName: %s", + qnp->name, rnp->name)); + + /* Lock the Facility */ + PR_Lock( traceLock ); + + /* + ** Remove RName from the list of RNames in QName + ** and free RName + */ + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting RName: %s, %p", + rnp->name, rnp)); + PR_REMOVE_LINK( &rnp->link ); + PR_Free( rnp->lock ); + PR_DELETE( rnp ); + + /* + ** If this is the last RName within QName + ** remove QName from the qNameList and free it + */ + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList ) ) + { + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: Deleting unused QName: %s, %p", + qnp->name, qnp)); + PR_REMOVE_LINK( &qnp->link ); + PR_DELETE( qnp ); + } + + /* Unlock the Facility */ + PR_Unlock( traceLock ); + return; +} /* end PR_DestroyTrace() */ + +/* +** Create a TraceEntry in the trace buffer +*/ +PR_IMPLEMENT(void) + PR_Trace( + PRTraceHandle handle, /* use this trace handle */ + PRUint32 userData0, /* User supplied data word 0 */ + PRUint32 userData1, /* User supplied data word 1 */ + PRUint32 userData2, /* User supplied data word 2 */ + PRUint32 userData3, /* User supplied data word 3 */ + PRUint32 userData4, /* User supplied data word 4 */ + PRUint32 userData5, /* User supplied data word 5 */ + PRUint32 userData6, /* User supplied data word 6 */ + PRUint32 userData7 /* User supplied data word 7 */ +) +{ + PRTraceEntry *tep; + PRInt32 mark; + + if ( (traceState == Suspended ) + || ( ((RName *)handle)->state == Suspended )) + return; + + /* + ** Get the next trace entry slot w/ minimum delay + */ + PR_Lock( traceLock ); + + tep = &tBuf[next++]; + if ( next > last ) + next = 0; + if ( fetchLostData == PR_FALSE && next == fetchLastSeen ) + fetchLostData = PR_TRUE; + + mark = next; + + PR_Unlock( traceLock ); + + /* + ** We have a trace entry. Fill it in. + */ + tep->thread = PR_GetCurrentThread(); + tep->handle = handle; + tep->time = PR_Now(); + tep->userData[0] = userData0; + tep->userData[1] = userData1; + tep->userData[2] = userData2; + tep->userData[3] = userData3; + tep->userData[4] = userData4; + tep->userData[5] = userData5; + tep->userData[6] = userData6; + tep->userData[7] = userData7; + + /* When buffer segment is full, signal trace log thread to run */ + if (( mark % logEntriesPerSegment) == 0 ) + { + PR_Lock( logLock ); + logCount++; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + /* + ** Gh0D! This is awful! + ** Anyway, to minimize lost trace data segments, + ** I inserted the PR_Sleep(0) to cause a context switch + ** so that the log thread could run. + ** I know, it perturbs the universe and may cause + ** funny things to happen in the optimized builds. + ** Take it out, loose data; leave it in risk Heisenberg. + */ + /* PR_Sleep(0); */ + } + + return; +} /* end PR_Trace() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_SetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +) +{ + RName * rnp; + + switch ( command ) + { + case PRTraceBufSize : + PR_Lock( traceLock ); + PR_Free( tBuf ); + bufSize = *(PRInt32 *)value; + NewTraceBuffer( bufSize ); + PR_Unlock( traceLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceBufSize: %ld", bufSize)); + break; + + case PRTraceEnable : + rnp = *(RName **)value; + rnp->state = Running; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceEnable: %p", rnp)); + break; + + case PRTraceDisable : + rnp = *(RName **)value; + rnp->state = Suspended; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceDisable: %p", rnp)); + break; + + case PRTraceSuspend : + traceState = Suspended; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceSuspend")); + break; + + case PRTraceResume : + traceState = Running; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceResume")); + break; + + case PRTraceSuspendRecording : + PR_Lock( logLock ); + logOrder = LogSuspend; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceSuspendRecording")); + break; + + case PRTraceResumeRecording : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceResumeRecording")); + if ( logState != LogSuspend ) + break; + PR_Lock( logLock ); + logOrder = LogResume; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + break; + + case PRTraceStopRecording : + PR_Lock( logLock ); + logOrder = LogStop; + PR_NotifyCondVar( logCVar ); + PR_Unlock( logLock ); + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceStopRecording")); + break; + + case PRTraceLockHandles : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceLockTraceHandles")); + PR_Lock( traceLock ); + break; + + case PRTraceUnLockHandles : + PR_LOG( lm, PR_LOG_DEBUG, + ("PRSetTraceOption: PRTraceUnLockHandles")); + PR_Lock( traceLock ); + break; + + default: + PR_LOG( lm, PR_LOG_ERROR, + ("PRSetTraceOption: Invalid command %ld", command )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return; +} /* end PR_SetTraceOption() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetTraceOption( + PRTraceOption command, /* One of the enumerated values */ + void *value /* command value or NULL */ +) +{ + switch ( command ) + { + case PRTraceBufSize : + *((PRInt32 *)value) = bufSize; + PR_LOG( lm, PR_LOG_DEBUG, + ("PRGetTraceOption: PRTraceBufSize: %ld", bufSize )); + break; + + default: + PR_LOG( lm, PR_LOG_ERROR, + ("PRGetTraceOption: Invalid command %ld", command )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return; +} /* end PR_GetTraceOption() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_GetTraceHandleFromName( + const char *qName, /* QName search argument */ + const char *rName /* RName search argument */ +) +{ + const char *qn, *rn, *desc; + PRTraceHandle qh, rh = NULL; + RName *rnp = NULL; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetTraceHandleFromName:\n\t" + "QName: %s, RName: %s", qName, rName )); + + qh = PR_FindNextTraceQname( NULL ); + while (qh != NULL) + { + rh = PR_FindNextTraceRname( NULL, qh ); + while ( rh != NULL ) + { + PR_GetTraceNameFromHandle( rh, &qn, &rn, &desc ); + if ( (strcmp( qName, qn ) == 0) + && (strcmp( rName, rn ) == 0 )) + { + rnp = (RName *)rh; + goto foundIt; + } + rh = PR_FindNextTraceRname( rh, qh ); + } + qh = PR_FindNextTraceQname( NULL ); + } + +foundIt: + PR_LOG( lm, PR_LOG_DEBUG, ("PR_Counter: GetConterHandleFromName: %p", rnp )); + return(rh); +} /* end PR_GetTraceHandleFromName() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_GetTraceNameFromHandle( + PRTraceHandle handle, /* handle as search argument */ + const char **qName, /* pointer to associated QName */ + const char **rName, /* pointer to associated RName */ + const char **description /* pointer to associated description */ +) +{ + RName *rnp = (RName *)handle; + QName *qnp = rnp->qName; + + *qName = qnp->name; + *rName = rnp->name; + *description = rnp->desc; + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: GetConterNameFromHandle: " + "QNp: %p, RNp: %p,\n\tQName: %s, RName: %s, Desc: %s", + qnp, rnp, qnp->name, rnp->name, rnp->desc )); + + return; +} /* end PR_GetTraceNameFromHandle() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_FindNextTraceQname( + PRTraceHandle handle +) +{ + QName *qnp = (QName *)handle; + + if ( PR_CLIST_IS_EMPTY( &qNameList )) + qnp = NULL; + else if ( qnp == NULL ) + qnp = (QName *)PR_LIST_HEAD( &qNameList ); + else if ( PR_NEXT_LINK( &qnp->link ) == &qNameList ) + qnp = NULL; + else + qnp = (QName *)PR_NEXT_LINK( &qnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextQname: Handle: %p, Returns: %p", + handle, qnp )); + + return((PRTraceHandle)qnp); +} /* end PR_FindNextTraceQname() */ + +/* +** +*/ +PR_IMPLEMENT(PRTraceHandle) + PR_FindNextTraceRname( + PRTraceHandle rhandle, + PRTraceHandle qhandle +) +{ + RName *rnp = (RName *)rhandle; + QName *qnp = (QName *)qhandle; + + + if ( PR_CLIST_IS_EMPTY( &qnp->rNameList )) + rnp = NULL; + else if ( rnp == NULL ) + rnp = (RName *)PR_LIST_HEAD( &qnp->rNameList ); + else if ( PR_NEXT_LINK( &rnp->link ) == &qnp->rNameList ) + rnp = NULL; + else + rnp = (RName *)PR_NEXT_LINK( &rnp->link ); + + PR_LOG( lm, PR_LOG_DEBUG, ("PRTrace: FindNextRname: Rhandle: %p, QHandle: %p, Returns: %p", + rhandle, qhandle, rnp )); + + return((PRTraceHandle)rnp); +} /* end PR_FindNextTraceRname() */ + +/* +** +*/ +static PRFileDesc * InitializeRecording( void ) +{ + char *logFileName; + PRFileDesc *logFile; + + /* Self initialize, if necessary */ + if ( traceLock == NULL ) + _PR_InitializeTrace(); + + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: begins")); + + logLostData = 0; /* reset at entry */ + logState = LogReset; + + /* Get the filename for the logfile from the environment */ + logFileName = PR_GetEnv( "NSPR_TRACE_LOG" ); + if ( logFileName == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Environment variable not defined. Exiting")); + return NULL; + } + + /* Open the logfile */ + logFile = PR_Open( logFileName, PR_WRONLY | PR_CREATE_FILE, 0666 ); + if ( logFile == NULL ) + { + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Cannot open %s as trace log file. OS error: %ld", + logFileName, PR_GetOSError())); + return NULL; + } + return logFile; +} /* end InitializeRecording() */ + +/* +** +*/ +static void ProcessOrders( void ) +{ + switch ( logOrder ) + { + case LogReset : + logOrder = logState = localState; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogReset")); + break; + + case LogSuspend : + localState = logOrder = logState = LogSuspend; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogSuspend")); + break; + + case LogResume : + localState = logOrder = logState = LogActive; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogResume")); + break; + + case LogStop : + logOrder = logState = LogStop; + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: LogStop")); + break; + + default : + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: Invalid logOrder: %ld", logOrder )); + PR_ASSERT( 0 ); + break; + } /* end switch() */ + return ; +} /* end ProcessOrders() */ + +/* +** +*/ +static void WriteTraceSegment( PRFileDesc *logFile, void *buf, PRInt32 amount ) +{ + PRInt32 rc; + + + PR_LOG( lm, PR_LOG_ERROR, + ("WriteTraceSegment: Buffer: %p, Amount: %ld", buf, amount)); + rc = PR_Write( logFile, buf , amount ); + if ( rc == -1 ) + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: PR_Write() failed. Error: %ld", PR_GetError() )); + else if ( rc != amount ) + PR_LOG( lm, PR_LOG_ERROR, + ("RecordTraceEntries: PR_Write() Tried to write: %ld, Wrote: %ld", amount, rc)); + else + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: PR_Write(): Buffer: %p, bytes: %ld", buf, amount)); + + return; +} /* end WriteTraceSegment() */ + +/* +** +*/ +PR_IMPLEMENT(void) + PR_RecordTraceEntries( + void +) +{ + PRFileDesc *logFile; + PRInt32 lostSegments; + PRInt32 currentSegment = 0; + void *buf; + PRBool doWrite; + + logFile = InitializeRecording(); + if ( logFile == NULL ) + { + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: Failed to initialize")); + return; + } + + /* Do this until told to stop */ + while ( logState != LogStop ) + { + + PR_Lock( logLock ); + + while ( (logCount == 0) && ( logOrder == logState ) ) + PR_WaitCondVar( logCVar, PR_INTERVAL_NO_TIMEOUT ); + + /* Handle state transitions */ + if ( logOrder != logState ) + ProcessOrders(); + + /* recalculate local controls */ + if ( logCount ) + { + lostSegments = logCount - logSegments; + if ( lostSegments > 0 ) + { + logLostData += ( logCount - logSegments ); + logCount = (logCount % logSegments); + currentSegment = logCount; + PR_LOG( lm, PR_LOG_DEBUG, + ("PR_RecordTraceEntries: LostData segments: %ld", logLostData)); + } + else + { + logCount--; + } + + buf = tBuf + ( logEntriesPerSegment * currentSegment ); + if (++currentSegment >= logSegments ) + currentSegment = 0; + doWrite = PR_TRUE; + } + else + doWrite = PR_FALSE; + + PR_Unlock( logLock ); + + if ( doWrite == PR_TRUE ) + { + if ( localState != LogSuspend ) + WriteTraceSegment( logFile, buf, logSegSize ); + else + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: PR_Write(): is suspended" )); + } + + } /* end while(logState...) */ + + PR_Close( logFile ); + PR_LOG( lm, PR_LOG_DEBUG, + ("RecordTraceEntries: exiting")); + return; +} /* end PR_RecordTraceEntries() */ + +/* +** +*/ +PR_IMPLEMENT(PRIntn) + PR_GetTraceEntries( + PRTraceEntry *buffer, /* where to write output */ + PRInt32 count, /* number to get */ + PRInt32 *found /* number you got */ +) +{ + PRInt32 rc; + PRInt32 copied = 0; + + PR_Lock( traceLock ); + + /* + ** Depending on where the LastSeen and Next indices are, + ** copy the trace buffer in one or two pieces. + */ + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Next: %ld, LastSeen: %ld", next, fetchLastSeen)); + + if ( fetchLastSeen <= next ) + { + while (( count-- > 0 ) && (fetchLastSeen < next )) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + } + else /* copy in 2 parts */ + { + while ( count-- > 0 && fetchLastSeen <= last ) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + fetchLastSeen = 0; + + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + + while ( count-- > 0 && fetchLastSeen < next ) + { + *(buffer + copied++) = *(tBuf + fetchLastSeen++); + } + PR_LOG( lm, PR_LOG_ERROR, + ("PR_GetTraceEntries: Copied: %ld, LastSeen: %ld", copied, fetchLastSeen)); + } + + *found = copied; + rc = ( fetchLostData == PR_TRUE )? 1 : 0; + fetchLostData = PR_FALSE; + + PR_Unlock( traceLock ); + return rc; +} /* end PR_GetTraceEntries() */ + +/* end prtrace.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/nspr.def b/src/libs/xpcom18a4/nsprpub/pr/src/nspr.def new file mode 100644 index 00000000..144df2ca --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/nspr.def @@ -0,0 +1,457 @@ +;+# +;+# 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 Netscape are +;+# Copyright (C) 2002-2003 Netscape Communications Corporation. All +;+# Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the +;+# terms of the GNU General Public License Version 2 or later (the +;+# "GPL"), in which case the provisions of the GPL are applicable +;+# instead of those above. If you wish to allow use of your +;+# version of this file only under the terms of the GPL and not to +;+# allow others to use your version of this file under the MPL, +;+# indicate your decision by deleting the provisions above and +;+# replace them with the notice and other provisions required by +;+# the GPL. If you do not delete the provisions above, a recipient +;+# may use your version of this file under either the MPL or the +;+# GPL. +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+# +;+NSPR_4.0 { +;+ global: +LIBRARY nspr4 ;- +EXPORTS ;- + LL_MaxInt; + LL_MinInt; + LL_Zero; + PR_Abort; + PR_AddToCounter; + PR_Accept; + PR_AcceptRead; + PR_Access; + PR_AddWaitFileDesc; + PR_AllocFileDesc; + PR_Assert; + PR_AtomicAdd; + PR_AtomicDecrement; + PR_AtomicIncrement; + PR_AtomicSet; + PR_AttachSharedMemory; + PR_AttachThread; + PR_Available; + PR_Available64; + PR_Bind; + PR_BlockClockInterrupts; + PR_BlockInterrupt; + PR_CEnterMonitor; + PR_CExitMonitor; + PR_CNotify; + PR_CNotifyAll; + PR_CSetOnMonitorRecycle; + PR_CWait; + PR_CallOnce; + PR_Calloc; + PR_CancelJob; + PR_CancelWaitFileDesc; + PR_CancelWaitGroup; + PR_CeilingLog2; + PR_ChangeFileDescNativeHandle; + PR_Cleanup; + PR_ClearInterrupt; + PR_ClearThreadGCAble; + PR_Close; + PR_CloseDir; + PR_CloseFileMap; + PR_CloseSemaphore; + PR_CloseSharedMemory; + PR_Connect; + PR_CreateCounter; + PR_ConvertIPv4AddrToIPv6; + PR_CreateAlarm; + PR_CreateFileMap; + PR_CreateIOLayerStub; + PR_CreateOrderedLock; + PR_CreateMWaitEnumerator; + PR_CreatePipe; + PR_CreateProcess; + PR_CreateProcessDetached; + PR_CreateSocketPollFd; + PR_CreateStack; + PR_CreateThread; + PR_CreateThreadGCAble; + PR_CreateTrace; + PR_CreateThreadPool; + PR_DecrementCounter; + PR_CreateWaitGroup; + PR_Delete; + PR_DeleteSemaphore; + PR_DeleteSharedMemory; + PR_DestroyAlarm; + PR_DestroyCounter; + PR_DestroyCondVar; + PR_DestroyLock; + PR_DestroyMWaitEnumerator; + PR_DestroyOrderedLock; + PR_DestroyMonitor; + PR_DestroyPollableEvent; + PR_DestroyProcessAttr; + PR_DestroyRWLock; + PR_DestroySem; + PR_DestroySocketPollFd; + PR_DestroyTrace; + PR_DestroyStack; + PR_DestroyWaitGroup; + PR_DetachProcess; + PR_DetachSharedMemory; + PR_DetachThread; + PR_DisableClockInterrupts; + PR_EnableClockInterrupts; + PR_EnterMonitor; + PR_EnumerateHostEnt; + PR_EnumerateThreads; + PR_EnumerateWaitGroup; + PR_ErrorInstallCallback; + PR_ErrorInstallTable; + PR_ErrorLanguages; + PR_ErrorToName; + PR_ErrorToString; + PR_ExitMonitor; + PR_ExplodeTime; + PR_ExportFileMapAsString; + PR_FD_CLR; + PR_FD_ISSET; + PR_FD_NCLR; + PR_FD_NISSET; + PR_FD_NSET; + PR_FD_SET; + PR_FD_ZERO; + PR_FileDesc2NativeHandle; + PR_FindSymbol; + PR_FindSymbolAndLibrary; + PR_FloorLog2; + PR_FormatTime; + PR_FindNextCounterQname; + PR_FindNextCounterRname; + PR_FindNextTraceQname; + PR_FindNextTraceRname; + PR_FormatTimeUSEnglish; + PR_Free; + PR_FreeLibraryName; + PR_GMTParameters; + PR_GetConnectStatus; + PR_GetCurrentThread; + PR_GetDefaultIOMethods; + PR_GetDescType; + PR_GetDirectorySeparator; + PR_GetCounter; + PR_GetCounterHandleFromName; + PR_GetCounterNameFromHandle; + PR_GetDirectorySepartor; + PR_GetEnv; + PR_GetError; + PR_GetErrorText; + PR_GetErrorTextLength; + PR_GetFileInfo; + PR_GetFileInfo64; + PR_GetFileMethods; + PR_GetGCRegisters; + PR_GetHostByAddr; + PR_GetHostByName; + PR_GetIPNodeByName; + PR_GetIdentitiesLayer; + PR_GetInheritedFD; + PR_GetInheritedFileMap; + PR_GetLayersIdentity; + PR_GetLibraryName; + PR_GetLibraryPath; + PR_GetMonitorEntryCount; + PR_GetNameForIdentity; + PR_GetOSError; + PR_GetOpenFileInfo; + PR_GetOpenFileInfo64; + PR_GetPageShift; + PR_GetPageSize; + PR_GetPeerName; + PR_GetPipeMethods; + PR_GetProtoByName; + PR_GetProtoByNumber; + PR_GetRandomNoise; + PR_GetSP; + PR_GetSockName; + PR_GetSocketOption; + PR_GetSpecialFD; + PR_GetStackSpaceLeft; + PR_GetSysfdTableMax; + PR_GetSystemInfo; + PR_GetTCPMethods; + PR_GetThreadAffinityMask; + PR_GetThreadID; + PR_GetThreadPriority; + PR_GetThreadPrivate; + PR_GetThreadScope; + PR_GetThreadState; + PR_GetThreadType; + PR_GetUDPMethods; + PR_GetUniqueIdentity; + PR_ImplodeTime; + PR_ImportFile; + PR_ImportFileMapFromString; + PR_ImportTCPSocket; + PR_ImportUDPSocket; + PR_GetTraceEntries; + PR_GetTraceHandleFromName; + PR_GetTraceNameFromHandle; + PR_GetTraceOption; + PR_Init; + PR_Initialize; + PR_InitializeNetAddr; + PR_Initialized; + PR_Interrupt; + PR_IntervalNow; + PR_IntervalToMicroseconds; + PR_IntervalToMilliseconds; + PR_IncrementCounter; + PR_IntervalToSeconds; + PR_IsNetAddrType; + PR_JoinJob; + PR_JoinThread; + PR_JoinThreadPool; + PR_KillProcess; + PR_Listen; + PR_LoadLibrary; + PR_LoadLibraryWithFlags; + PR_LoadStaticLibrary; + PR_LocalTimeParameters; + PR_Lock; + PR_LockFile; + PR_LogFlush; + PR_LogPrint; + PR_MakeDir; + PR_Malloc; + PR_MemMap; + PR_MemUnmap; + PR_MicrosecondsToInterval; + PR_MillisecondsToInterval; + PR_LockOrderedLock; + PR_MkDir; + PR_NetAddrToString; + PR_NewCondVar; + PR_NewLock; + PR_NewLogModule; + PR_NewMonitor; + PR_NewNamedMonitor; + PR_NewPollableEvent; + PR_NewProcessAttr; + PR_NewRWLock; + PR_NewSem; + PR_NewTCPSocket; + PR_NewTCPSocketPair; + PR_NewThreadPrivateIndex; + PR_NewUDPSocket; + PR_NormalizeTime; + PR_Notify; + PR_NotifyAll; + PR_NotifyAllCondVar; + PR_NotifyCondVar; + PR_Now; + PR_Open; + PR_OpenAnonFileMap; + PR_OpenDir; + PR_OpenFile; + PR_OpenSemaphore; + PR_OpenSharedMemory; + PR_OpenTCPSocket; + PR_OpenUDPSocket; + PR_ParseTimeString; + PR_Poll; + PR_PopIOLayer; + PR_PostSem; + PR_PostSemaphore; + PR_ProcessAttrSetCurrentDirectory; + PR_ProcessAttrSetInheritableFD; + PR_ProcessAttrSetInheritableFileMap; + PR_ProcessAttrSetStdioRedirect; + PR_ProcessExit; + PR_PushIOLayer; + PR_QueueJob; + PR_QueueJob_Accept; + PR_QueueJob_Connect; + PR_QueueJob_Read; + PR_QueueJob_Timer; + PR_QueueJob_Write; + PR_RWLock_Rlock; + PR_RWLock_Unlock; + PR_RWLock_Wlock; + PR_Read; + PR_ReadDir; + PR_Realloc; + PR_Recv; + PR_RecvFrom; + PR_Rename; + PR_ResetAlarm; + PR_ResetProcessAttr; + PR_ResumeAll; + PR_RmDir; + PR_ScanStackPointers; + PR_RecordTraceEntries; + PR_SecondsToInterval; + PR_Seek; + PR_Seek64; + PR_Select; + PR_Send; + PR_SendFile; + PR_SendTo; + PR_SetAlarm; + PR_SetConcurrency; + PR_SetError; + PR_SetErrorText; + PR_SetFDCacheSize; + PR_SetFDInheritable; + PR_SetLibraryPath; + PR_SetLogBuffering; + PR_SetLogFile; + PR_SetNetAddr; + PR_SetPollableEvent; + PR_SetSocketOption; + PR_SetCounter; + PR_SetStdioRedirect; + PR_SetSysfdTableSize; + PR_SetThreadAffinityMask; + PR_SetThreadDumpProc; + PR_SetThreadGCAble; + PR_SetThreadPriority; + PR_SetThreadPrivate; + PR_SetThreadRecycleMode; + PR_Shutdown; + PR_ShutdownThreadPool; + PR_Sleep; + PR_Socket; + PR_StackPop; + PR_StackPush; + PR_Stat; + PR_StringToNetAddr; + PR_SuspendAll; + PR_Sync; + PR_TLockFile; + PR_ThreadScanStackPointers; + PR_SetTraceOption; + PR_TicksPerSecond; + PR_TransmitFile; + PR_USPacificTimeParameters; + PR_UnblockClockInterrupts; + PR_UnblockInterrupt; + PR_UnloadLibrary; + PR_SubtractFromCounter; + PR_Unlock; + PR_UnlockFile; + PR_VersionCheck; + PR_Wait; + PR_WaitCondVar; + PR_WaitForPollableEvent; + PR_Trace; + PR_WaitProcess; + PR_WaitRecvReady; + PR_WaitSem; + PR_WaitSemaphore; + PR_Write; + PR_Writev; + PR_Yield; + PR_UnlockOrderedLock; + PR_cnvtf; + PR_dtoa; + PR_fprintf; + PR_htonl; + PR_htonll; + PR_htons; + PR_ntohl; + PR_ntohll; + PR_ntohs; + PR_smprintf; + PR_smprintf_free; + PR_snprintf; + PR_sprintf_append; + PR_sscanf; + PR_strtod; + PR_sxprintf; + PR_vfprintf; + PR_vsmprintf; + PR_vsnprintf; + PR_vsprintf_append; + PR_vsxprintf; + PRP_DestroyNakedCondVar; + PRP_NakedBroadcast; + PRP_NakedNotify; + PRP_NakedWait; + PRP_NewNakedCondVar; + PRP_TryLock; + libVersionPoint; +;+ local: *; +;+}; +;+ +;+NSPRprivate { +;+ global: + GetExecutionEnvironment; + PT_FPrintStats; + SetExecutionEnvironment; +;+ local: *; +;+}; +;+ +;+NSPR_4.1 { +;+ global: + PR_ConnectContinue; + PR_CreateIOLayer; + PR_EmulateAcceptRead; + PR_EmulateSendFile; + PR_FindFunctionSymbol; + PR_FindFunctionSymbolAndLibrary; + PR_GetMemMapAlignment; + PR_GetNumberOfProcessors; + PR_ImportPipe; + PR_SetEnv; +;+} NSPR_4.0; +;+ +;+NSPR_4.3 { +;+ global: + LL_MaxUint; + PR_CallOnceWithArg; + PR_GetLibraryFilePathname; +;+} NSPR_4.1; +;+ +;+NSPR_4.4 { +;+ global: + PR_GetPathSeparator; +;+} NSPR_4.3; +;+ +;+NSPR_4.5 { +;+ global: + PR_EnumerateAddrInfo; + PR_FreeAddrInfo; + PR_GetAddrInfoByName; + PR_GetCanonNameFromAddrInfo; +;+} NSPR_4.4; diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/nspr.rc b/src/libs/xpcom18a4/nsprpub/pr/src/nspr.rc new file mode 100644 index 00000000..d3cc2ef3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/nspr.rc @@ -0,0 +1,102 @@ +/* -*- 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 "prinit.h" +#include + +#define MY_LIBNAME "nspr" +#define MY_FILEDESCRIPTION "NSPR Library" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define PR_VMAJOR_STR STRINGIZE2(PR_VMAJOR) + +#ifdef _DEBUG +#define MY_DEBUG_STR " (debug)" +#define MY_FILEFLAGS_1 VS_FF_DEBUG +#else +#define MY_DEBUG_STR "" +#define MY_FILEFLAGS_1 0x0L +#endif +#if PR_BETA +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE +#else +#define MY_FILEFLAGS_2 MY_FILEFLAGS_1 +#endif + +#ifdef WINNT +#define MY_FILEOS VOS_NT_WINDOWS32 +#define MY_INTERNAL_NAME "lib" MY_LIBNAME PR_VMAJOR_STR +#else +#define MY_FILEOS VOS__WINDOWS32 +#define MY_INTERNAL_NAME MY_LIBNAME PR_VMAJOR_STR +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// Version-information resource +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + PRODUCTVERSION PR_VMAJOR,PR_VMINOR,PR_VPATCH,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS MY_FILEFLAGS_2 + FILEOS MY_FILEOS + FILETYPE VFT_DLL + FILESUBTYPE 0x0L // not used + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" // Lang=US English, CharSet=Unicode + BEGIN + VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" + VALUE "FileVersion", PR_VERSION "\0" + VALUE "InternalName", MY_INTERNAL_NAME "\0" + VALUE "LegalCopyright", "Copyright \251 1996-2000 Netscape Communications Corporation\0" + VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" + VALUE "ProductName", "Netscape Portable Runtime\0" + VALUE "ProductVersion", PR_VERSION "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/nspr_symvec.opt b/src/libs/xpcom18a4/nsprpub/pr/src/nspr_symvec.opt new file mode 100644 index 00000000..b6441372 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/nspr_symvec.opt @@ -0,0 +1,500 @@ +! Fixed section of symbol vector for LIBNSPR4 (non-debug) +! +GSMATCH=LEQUAL,2,7 +case_sensitive=YES +! +! -------------------------------------------------------------------------- +! Ident 2,1 introduced for Mozilla 0.9.4 +! Based on NSPR 4.1.2 +! -------------------------------------------------------------------------- +! Ident 2,2 introduced for Mozilla 1.2 +! Based on NSPR 4.2.2? +! PR_ResumeSet, PR_ResumeTest, and PR_SuspendAllSuspended has been "removed". +! Only we can't remove the entry points because OJI is linked against NSPR so +! we have to make an upwardly compatible change: +! PR_ResumeSet is now PR_VMS_Stub1 +! PR_ResumeTest is now PR_VMS_Stub2 +! PR_SuspendAllSuspended is PR_VMS_Stub3 +! These are stub functions (defined in openvms.c) solely for the purpose of +! occupying the slots in our fixed section of the symbol table. +! -------------------------------------------------------------------------- +! Ident 2,3 introduced for Mozilla 1.3 +! Previously we were missing some symbols from NSPR 4.0 and 4.1, so now we +! include everything that's specified in nspr.def. +! -------------------------------------------------------------------------- +! Ident 2,4 introduced for Mozilla 1.3 final. +! 2,3 was still missing some symbols, in particular PR_CreateThread, which +! is used by OJI. So insert stubs to force the PR_CreateThread entry down +! to its Mozilla 1.1 (and Java 1.4-0) location so that everyone can play +! together and be happy. +! -------------------------------------------------------------------------- +! Ident 2,5 introduced for post Mozilla 1.3. +! LL_MaxUint introduced. Replaces Stub54. +! -------------------------------------------------------------------------- +! Ident 2,6 introduced for post Mozilla 1.4. +! PR_GetPathSeparator introduced in NSPR 4.4. +! This replaces stub 53 +! -------------------------------------------------------------------------- +! Ident 2,7 introduced for post Mozilla 1.4. +! PR_GetAddrInfoByName, PR_FreeAddrInfo, PR_EnumerateAddrInfo and +! PR_GetCanonNameFromAddrInfo introduced in NSPR 4.5. +! These replace stubs 49-52 +! -------------------------------------------------------------------------- +! +SYMBOL_VECTOR=(PR_Accept=PROCEDURE) +SYMBOL_VECTOR=(PR_AcceptRead=PROCEDURE) +SYMBOL_VECTOR=(PR_Access=PROCEDURE) +SYMBOL_VECTOR=(PR_AllocFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_Assert=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicAdd=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicDecrement=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicSet=PROCEDURE) +SYMBOL_VECTOR=(PR_AttachSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_AttachThread=PROCEDURE) +SYMBOL_VECTOR=(PR_Available64=PROCEDURE) +SYMBOL_VECTOR=(PR_Available=PROCEDURE) +SYMBOL_VECTOR=(PR_Bind=PROCEDURE) +SYMBOL_VECTOR=(PR_BlockClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_BlockInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_CExitMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_CNotify=PROCEDURE) +SYMBOL_VECTOR=(PR_CNotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_CSetOnMonitorRecycle=PROCEDURE) +SYMBOL_VECTOR=(PR_CWait=PROCEDURE) +SYMBOL_VECTOR=(PR_CallOnce=PROCEDURE) +SYMBOL_VECTOR=(PR_Calloc=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelJob=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelWaitFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_CancelWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_ChangeFileDescNativeHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_Cleanup=PROCEDURE) +SYMBOL_VECTOR=(PR_ClearInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_ClearThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_Close=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseDir=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_CloseSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_Connect=PROCEDURE) +SYMBOL_VECTOR=(PR_ConnectContinue=PROCEDURE) +SYMBOL_VECTOR=(PR_ConvertIPv4AddrToIPv6=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateIOLayerStub=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateMWaitEnumerator=PROCEDURE) +SYMBOL_VECTOR=(PR_CreatePipe=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateProcessDetached=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateSocketPollFd=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateStack=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_Delete=PROCEDURE) +SYMBOL_VECTOR=(PR_DeleteSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_DeleteSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyMWaitEnumerator=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyRWLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroySem=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroySocketPollFd=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyStack=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_DetachThread=PROCEDURE) +SYMBOL_VECTOR=(PR_DisableClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_EmulateAcceptRead=PROCEDURE) +SYMBOL_VECTOR=(PR_EmulateSendFile=PROCEDURE) +SYMBOL_VECTOR=(PR_EnableClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_EnterMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateHostEnt=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateThreads=PROCEDURE) +SYMBOL_VECTOR=(PR_EnumerateWaitGroup=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorInstallCallback=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorInstallTable=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorLanguages=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorToName=PROCEDURE) +SYMBOL_VECTOR=(PR_ExitMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_ExportFileMapAsString=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_CLR=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_ISSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NCLR=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NISSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_NSET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_SET=PROCEDURE) +SYMBOL_VECTOR=(PR_FD_ZERO=PROCEDURE) +SYMBOL_VECTOR=(PR_FileDesc2NativeHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_FindFunctionSymbol=PROCEDURE) +SYMBOL_VECTOR=(PR_FindFunctionSymbolAndLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_FindLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_FindSymbol=PROCEDURE) +SYMBOL_VECTOR=(PR_FindSymbolAndLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_FloorLog2=PROCEDURE) +SYMBOL_VECTOR=(PR_FormatTime=PROCEDURE) +SYMBOL_VECTOR=(PR_FormatTimeUSEnglish=PROCEDURE) +SYMBOL_VECTOR=(PR_Free=PROCEDURE) +SYMBOL_VECTOR=(PR_FreeLibraryName=PROCEDURE) +SYMBOL_VECTOR=(PR_GMTParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_GetConnectStatus=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCurrentThread=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDefaultIOMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDirectorySepartor=PROCEDURE) +SYMBOL_VECTOR=(PR_GetError=PROCEDURE) +SYMBOL_VECTOR=(PR_GetErrorText=PROCEDURE) +SYMBOL_VECTOR=(PR_GetErrorTextLength=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileInfo64=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetFileMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetHostByAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_GetHostByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetIPNodeByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetIdentitiesLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_GetInheritedFD=PROCEDURE) +SYMBOL_VECTOR=(PR_GetInheritedFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLayersIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryPath=PROCEDURE) +SYMBOL_VECTOR=(PR_GetMemMapAlignment=PROCEDURE) +SYMBOL_VECTOR=(PR_GetMonitorEntryCount=PROCEDURE) +SYMBOL_VECTOR=(PR_GetNameForIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetNumberOfProcessors=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOSError=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOpenFileInfo64=PROCEDURE) +SYMBOL_VECTOR=(PR_GetOpenFileInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPageShift=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPeerName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPipeMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetProtoByName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetProtoByNumber=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSP=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSockName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSocketOption=PROCEDURE) +SYMBOL_VECTOR=(PR_GetStackSpaceLeft=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSysfdTableMax=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSystemInfo=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTCPMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadAffinityMask=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadID=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadPriority=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadPrivate=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadScope=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadState=PROCEDURE) +SYMBOL_VECTOR=(PR_GetThreadType=PROCEDURE) +SYMBOL_VECTOR=(PR_GetUDPMethods=PROCEDURE) +SYMBOL_VECTOR=(PR_ImplodeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportFile=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportFileMapFromString=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportPipe=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_ImportUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_Init=PROCEDURE) +SYMBOL_VECTOR=(PR_Initialize=PROCEDURE) +SYMBOL_VECTOR=(PR_InitializeNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_Initialized=PROCEDURE) +SYMBOL_VECTOR=(PR_Interrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToMicroseconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToMilliseconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalToSeconds=PROCEDURE) +SYMBOL_VECTOR=(PR_IsNetAddrType=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinJob=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinThread=PROCEDURE) +SYMBOL_VECTOR=(PR_JoinThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_KillProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_Listen=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadLibraryWithFlags=PROCEDURE) +SYMBOL_VECTOR=(PR_LoadStaticLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_LocalTimeParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_Lock=PROCEDURE) +SYMBOL_VECTOR=(PR_LockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_LogFlush=PROCEDURE) +SYMBOL_VECTOR=(PR_LogPrint=PROCEDURE) +SYMBOL_VECTOR=(PR_MakeDir=PROCEDURE) +SYMBOL_VECTOR=(PR_MemMap=PROCEDURE) +SYMBOL_VECTOR=(PR_MemUnmap=PROCEDURE) +SYMBOL_VECTOR=(PR_MicrosecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_MillisecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_MkDir=PROCEDURE) +SYMBOL_VECTOR=(PR_NetAddrToString=PROCEDURE) +SYMBOL_VECTOR=(PR_NewCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_NewLogModule=PROCEDURE) +SYMBOL_VECTOR=(PR_NewMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_NewNamedMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_NewProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_NewSem=PROCEDURE) +SYMBOL_VECTOR=(PR_NewTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_NewTCPSocketPair=PROCEDURE) +SYMBOL_VECTOR=(PR_NewUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_NormalizeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_Notify=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyAllCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_NotifyCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_Open=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenDir=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenFile=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenTCPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenUDPSocket=PROCEDURE) +SYMBOL_VECTOR=(PR_ParseTimeString=PROCEDURE) +SYMBOL_VECTOR=(PR_Poll=PROCEDURE) +SYMBOL_VECTOR=(PR_PopIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_PostSem=PROCEDURE) +SYMBOL_VECTOR=(PR_PostSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessAttrSetCurren1sb1r7b$=PROCEDURE) ! PR_ProcessAttrSetCurrentDirectory +SYMBOL_VECTOR=(PR_ProcessAttrSetInheri3dpg1d0$=PROCEDURE) ! PR_ProcessAttrSetInheritableFileMap +SYMBOL_VECTOR=(PR_ProcessAttrSetInheritableFD=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessAttrSetStdioRedirect=PROCEDURE) +SYMBOL_VECTOR=(PR_ProcessExit=PROCEDURE) +SYMBOL_VECTOR=(PR_PushIOLayer=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Accept=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Connect=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Read=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Timer=PROCEDURE) +SYMBOL_VECTOR=(PR_QueueJob_Write=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Rlock=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Unlock=PROCEDURE) +SYMBOL_VECTOR=(PR_RWLock_Wlock=PROCEDURE) +SYMBOL_VECTOR=(PR_Read=PROCEDURE) +SYMBOL_VECTOR=(PR_ReadDir=PROCEDURE) +SYMBOL_VECTOR=(PR_Realloc=PROCEDURE) +SYMBOL_VECTOR=(PR_Recv=PROCEDURE) +SYMBOL_VECTOR=(PR_RecvFrom=PROCEDURE) +SYMBOL_VECTOR=(PR_Rename=PROCEDURE) +SYMBOL_VECTOR=(PR_ResetAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_ResetProcessAttr=PROCEDURE) +SYMBOL_VECTOR=(PR_ResumeAll=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub1=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub2=PROCEDURE) +SYMBOL_VECTOR=(PR_RmDir=PROCEDURE) +SYMBOL_VECTOR=(PR_ScanStackPointers=PROCEDURE) +SYMBOL_VECTOR=(PR_SecondsToInterval=PROCEDURE) +SYMBOL_VECTOR=(PR_Seek64=PROCEDURE) +SYMBOL_VECTOR=(PR_Seek=PROCEDURE) +SYMBOL_VECTOR=(PR_Select=PROCEDURE) +SYMBOL_VECTOR=(PR_Send=PROCEDURE) +SYMBOL_VECTOR=(PR_SendFile=PROCEDURE) +SYMBOL_VECTOR=(PR_SendTo=PROCEDURE) +SYMBOL_VECTOR=(PR_SetAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_SetEnv=PROCEDURE) +SYMBOL_VECTOR=(PR_SetErrorText=PROCEDURE) +SYMBOL_VECTOR=(PR_SetFDInheritable=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLogBuffering=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLogFile=PROCEDURE) +SYMBOL_VECTOR=(PR_SetNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_SetPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_SetSocketOption=PROCEDURE) +SYMBOL_VECTOR=(PR_SetStdioRedirect=PROCEDURE) +SYMBOL_VECTOR=(PR_SetSysfdTableSize=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadAffinityMask=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadDumpProc=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadGCAble=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadPriority=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadPrivate=PROCEDURE) +SYMBOL_VECTOR=(PR_SetThreadRecycleMode=PROCEDURE) +SYMBOL_VECTOR=(PR_Shutdown=PROCEDURE) +SYMBOL_VECTOR=(PR_ShutdownThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_Sleep=PROCEDURE) +SYMBOL_VECTOR=(PR_Socket=PROCEDURE) +SYMBOL_VECTOR=(PR_StackPop=PROCEDURE) +SYMBOL_VECTOR=(PR_StackPush=PROCEDURE) +SYMBOL_VECTOR=(PR_Stat=PROCEDURE) +SYMBOL_VECTOR=(PR_SuspendAll=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub3=PROCEDURE) +SYMBOL_VECTOR=(PR_Sync=PROCEDURE) +SYMBOL_VECTOR=(PR_TLockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_ThreadScanStackPointers=PROCEDURE) +SYMBOL_VECTOR=(PR_TicksPerSecond=PROCEDURE) +SYMBOL_VECTOR=(PR_TransmitFile=PROCEDURE) +SYMBOL_VECTOR=(PR_USPacificTimeParameters=PROCEDURE) +SYMBOL_VECTOR=(PR_UnblockClockInterrupts=PROCEDURE) +SYMBOL_VECTOR=(PR_UnblockInterrupt=PROCEDURE) +SYMBOL_VECTOR=(PR_UnloadLibrary=PROCEDURE) +SYMBOL_VECTOR=(PR_Unlock=PROCEDURE) +SYMBOL_VECTOR=(PR_UnlockFile=PROCEDURE) +SYMBOL_VECTOR=(PR_Wait=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitCondVar=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitForPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitProcess=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitRecvReady=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitSem=PROCEDURE) +SYMBOL_VECTOR=(PR_WaitSemaphore=PROCEDURE) +SYMBOL_VECTOR=(PR_Write=PROCEDURE) +SYMBOL_VECTOR=(PR_Writev=PROCEDURE) +SYMBOL_VECTOR=(PR_XIsLocked=PROCEDURE) +SYMBOL_VECTOR=(PR_XLock=PROCEDURE) +SYMBOL_VECTOR=(PR_XNotify=PROCEDURE) +SYMBOL_VECTOR=(PR_XNotifyAll=PROCEDURE) +SYMBOL_VECTOR=(PR_XUnlock=PROCEDURE) +SYMBOL_VECTOR=(PR_XWait=PROCEDURE) +SYMBOL_VECTOR=(PR_Yield=PROCEDURE) +SYMBOL_VECTOR=(PR_cnvtf=PROCEDURE) +SYMBOL_VECTOR=(PR_dtoa=PROCEDURE) +SYMBOL_VECTOR=(PR_htonl=PROCEDURE) +SYMBOL_VECTOR=(PR_htonll=PROCEDURE) +SYMBOL_VECTOR=(PR_htons=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohl=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohll=PROCEDURE) +SYMBOL_VECTOR=(PR_ntohs=PROCEDURE) +SYMBOL_VECTOR=(PR_smprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_smprintf_free=PROCEDURE) +SYMBOL_VECTOR=(PR_sprintf_append=PROCEDURE) +SYMBOL_VECTOR=(PR_sxprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vfprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsmprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsnprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_vsprintf_append=PROCEDURE) +SYMBOL_VECTOR=(PR_vsxprintf=PROCEDURE) +! +! Start of 2,3 additions +! +SYMBOL_VECTOR=(LL_MaxInt=PROCEDURE) +SYMBOL_VECTOR=(LL_MinInt=PROCEDURE) +SYMBOL_VECTOR=(LL_Zero=PROCEDURE) +SYMBOL_VECTOR=(PR_Abort=PROCEDURE) +SYMBOL_VECTOR=(PR_AddToCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_AddWaitFileDesc=PROCEDURE) +SYMBOL_VECTOR=(PR_AtomicIncrement=PROCEDURE) +SYMBOL_VECTOR=(PR_CEnterMonitor=PROCEDURE) +SYMBOL_VECTOR=(PR_CeilingLog2=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateAlarm=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateTrace=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThreadPool=PROCEDURE) +SYMBOL_VECTOR=(PR_DecrementCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_DestroyTrace=PROCEDURE) +SYMBOL_VECTOR=(PR_ErrorToString=PROCEDURE) +SYMBOL_VECTOR=(PR_ExplodeTime=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextCounterQname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextCounterRname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextTraceQname=PROCEDURE) +SYMBOL_VECTOR=(PR_FindNextTraceRname=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDescType=PROCEDURE) +SYMBOL_VECTOR=(PR_GetDirectorySeparator=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounterHandleFromName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetCounterNameFromHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_GetEnv=PROCEDURE) +SYMBOL_VECTOR=(PR_GetGCRegisters=PROCEDURE) +SYMBOL_VECTOR=(PR_GetPageSize=PROCEDURE) +SYMBOL_VECTOR=(PR_GetRandomNoise=PROCEDURE) +SYMBOL_VECTOR=(PR_GetSpecialFD=PROCEDURE) +SYMBOL_VECTOR=(PR_GetUniqueIdentity=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceEntries=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceHandleFromName=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceNameFromHandle=PROCEDURE) +SYMBOL_VECTOR=(PR_GetTraceOption=PROCEDURE) +SYMBOL_VECTOR=(PR_IntervalNow=PROCEDURE) +SYMBOL_VECTOR=(PR_IncrementCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_Malloc=PROCEDURE) +SYMBOL_VECTOR=(PR_LockOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewPollableEvent=PROCEDURE) +SYMBOL_VECTOR=(PR_NewRWLock=PROCEDURE) +SYMBOL_VECTOR=(PR_NewThreadPrivateIndex=PROCEDURE) +SYMBOL_VECTOR=(PR_Now=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenAnonFileMap=PROCEDURE) +SYMBOL_VECTOR=(PR_OpenSharedMemory=PROCEDURE) +SYMBOL_VECTOR=(PR_RecordTraceEntries=PROCEDURE) +SYMBOL_VECTOR=(PR_SetConcurrency=PROCEDURE) +SYMBOL_VECTOR=(PR_SetFDCacheSize=PROCEDURE) +SYMBOL_VECTOR=(PR_SetLibraryPath=PROCEDURE) +SYMBOL_VECTOR=(PR_SetCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_StringToNetAddr=PROCEDURE) +SYMBOL_VECTOR=(PR_SetTraceOption=PROCEDURE) +SYMBOL_VECTOR=(PR_SubtractFromCounter=PROCEDURE) +SYMBOL_VECTOR=(PR_VersionCheck=PROCEDURE) +SYMBOL_VECTOR=(PR_Trace=PROCEDURE) +SYMBOL_VECTOR=(PR_UnlockOrderedLock=PROCEDURE) +SYMBOL_VECTOR=(PR_fprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_snprintf=PROCEDURE) +SYMBOL_VECTOR=(PR_sscanf=PROCEDURE) +SYMBOL_VECTOR=(PR_strtod=PROCEDURE) +SYMBOL_VECTOR=(PRP_DestroyNakedCondVar=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedBroadcast=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedNotify=PROCEDURE) +SYMBOL_VECTOR=(PRP_NakedWait=PROCEDURE) +SYMBOL_VECTOR=(PRP_NewNakedCondVar=PROCEDURE) +SYMBOL_VECTOR=(PRP_TryLock=PROCEDURE) +SYMBOL_VECTOR=(libVersionPoint=PROCEDURE) +! +! NSPR private +! +SYMBOL_VECTOR=(GetExecutionEnvironment=PROCEDURE) +SYMBOL_VECTOR=(PT_FPrintStats=PROCEDURE) +SYMBOL_VECTOR=(SetExecutionEnvironment=PROCEDURE) +! +! Start of 2,4 additions +! 51 stubs (4 thru 54) so that PR_CreateThread ends up at 1B70. +! Over time some of these stubs will get replaced by new symbols. +! +SYMBOL_VECTOR=(PR_VMS_Stub4=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub5=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub6=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub7=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub8=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub9=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub10=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub11=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub12=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub13=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub14=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub15=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub16=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub17=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub18=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub19=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub20=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub21=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub22=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub23=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub24=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub25=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub26=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub27=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub28=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub29=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub30=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub31=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub32=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub33=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub34=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub35=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub36=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub37=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub38=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub39=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub40=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub41=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub42=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub43=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub44=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub45=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub46=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub47=PROCEDURE) +SYMBOL_VECTOR=(PR_VMS_Stub48=PROCEDURE) +SYMBOL_VECTOR=(PR_GetAddrInfoByName=PROCEDURE) ! was Stub49 +SYMBOL_VECTOR=(PR_FreeAddrInfo=PROCEDURE) ! was Stub50 +SYMBOL_VECTOR=(PR_EnumerateAddrInfo=PROCEDURE) ! was Stub51 +SYMBOL_VECTOR=(PR_GetCanonNameFromAddrInfo=PROCEDURE) ! was Stub52 +SYMBOL_VECTOR=(PR_GetPathSeparator=PROCEDURE) ! was Stub53 +SYMBOL_VECTOR=(LL_MaxUint=PROCEDURE) ! was Stub54 +! +SYMBOL_VECTOR=(PR_CallOnceWithArg=PROCEDURE) +SYMBOL_VECTOR=(PR_GetLibraryFilePathname=PROCEDURE) +SYMBOL_VECTOR=(PR_SetError=PROCEDURE) +SYMBOL_VECTOR=(PR_CreateThread=PROCEDURE) +! +! -------------------------------------------------------------------------- +! End of fixed section +! -------------------------------------------------------------------------- +! diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/os2extra.def b/src/libs/xpcom18a4/nsprpub/pr/src/os2extra.def new file mode 100644 index 00000000..8dbb34da --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/os2extra.def @@ -0,0 +1,16 @@ + ; + ; Support plugins that were explicitly linked to the Visual Age + ; version of nspr4.dll. + ; + PR_NewMonitor + PR_EnterMonitor + PR_ExitMonitor + PR_GetCurrentThread + PR_AttachThread + PR_DetachThread + ; + ; Exception handler functions that are used by nsAppRunner.cpp + ; + _PR_OS2_SetFloatExcpHandler + _PR_OS2_UnsetFloatExcpHandler + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/prvrsion.c b/src/libs/xpcom18a4/nsprpub/pr/src/prvrsion.c new file mode 100644 index 00000000..b8f4916d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/prvrsion.c @@ -0,0 +1,127 @@ +/* -*- 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 "prinit.h" +#include "prvrsion.h" + +/************************************************************************/ +/**************************IDENTITY AND VERSIONING***********************/ +/************************************************************************/ +#ifndef XP_MAC +#include "_pr_bld.h" +#endif +#if !defined(_BUILD_TIME) +#ifdef HAVE_LONG_LONG +#define _BUILD_TIME 0 +#else +#define _BUILD_TIME {0, 0} +#endif +#endif +#if !defined(_BUILD_STRING) +#define _BUILD_STRING "" +#endif +#if !defined(_PRODUCTION) +#define _PRODUCTION "" +#endif +#if defined(DEBUG) +#define _DEBUG_STRING " (debug)" +#else +#define _DEBUG_STRING "" +#endif + +/* + * A trick to expand the PR_VMAJOR macro before concatenation. + */ +#define CONCAT(x, y) x ## y +#define CONCAT2(x, y) CONCAT(x, y) +#define VERSION_DESC_NAME CONCAT2(prVersionDescription_libnspr, PR_VMAJOR) + +PRVersionDescription VERSION_DESC_NAME = +{ + /* version */ 2, /* this is the only one supported */ + /* buildTime */ _BUILD_TIME, /* usecs since midnight 1/1/1970 GMT */ + /* buildTimeString */ _BUILD_STRING, /* ditto, but human readable */ + /* vMajor */ PR_VMAJOR, /* NSPR's version number */ + /* vMinor */ PR_VMINOR, /* and minor version */ + /* vPatch */ PR_VPATCH, /* and patch */ + /* beta */ PR_BETA, /* beta build boolean */ +#if defined(DEBUG) + /* debug */ PR_TRUE, /* a debug build */ +#else + /* debug */ PR_FALSE, /* an optomized build */ +#endif + /* special */ PR_FALSE, /* they're all special, but ... */ + /* filename */ _PRODUCTION, /* the produced library name */ + /* description */ "Portable runtime", /* what we are */ + /* security */ "N/A", /* not applicable here */ + /* copywrite */ "Copyright (c) 1998 Netscape Communications Corporation. All Rights Reserved", + /* comment */ "License information: http://www.mozilla.org/MPL/", + /* specialString */ "" +}; + +#ifdef XP_UNIX + +/* + * Version information for the 'ident' and 'what commands + * + * NOTE: the first component of the concatenated rcsid string + * must not end in a '$' to prevent rcs keyword substitution. + */ +static char rcsid[] = "$Header: NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING " $"; +static char sccsid[] = "@(#)NSPR " PR_VERSION _DEBUG_STRING + " " _BUILD_STRING; + +#endif /* XP_UNIX */ + +PR_IMPLEMENT(const PRVersionDescription*) libVersionPoint(void) +{ +#ifdef XP_UNIX + /* + * Add dummy references to rcsid and sccsid to prevent them + * from being optimized away as unused variables. + */ + const char *dummy; + + dummy = rcsid; + dummy = sccsid; +#endif + return &VERSION_DESC_NAME; +} /* versionEntryPointType */ + +/* prvrsion.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/Makefile.in new file mode 100644 index 00000000..ddda7091 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/Makefile.in @@ -0,0 +1,79 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = \ + ptio.c \ + ptsynch.c \ + ptthread.c \ + ptmisc.c \ + $(NULL) + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +ifeq ($(OS_ARCH),Linux) +# for pthread_mutexattr_settype +DEFINES += -D_XOPEN_SOURCE=500 +endif + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptio.c b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptio.c new file mode 100644 index 00000000..11b7d904 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptio.c @@ -0,0 +1,4920 @@ +/* -*- 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 ***** */ + +/* +** File: ptio.c +** Descritpion: Implemenation of I/O methods for pthreads +*/ + +#if defined(_PR_PTHREADS) + +#if defined(_PR_POLL_WITH_SELECT) +#if !(defined(HPUX) && defined(_USE_BIG_FDS)) +/* set fd limit for select(), before including system header files */ +#define FD_SETSIZE (16 * 1024) +#endif +#endif + +#include +#include /* for memset() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(DARWIN) +#include /* for uname */ +#endif +#if defined(SOLARIS) || defined(UNIXWARE) +#include /* to pick up FIONREAD */ +#endif +#ifdef _PR_POLL_AVAILABLE +#include +#endif +#ifdef AIX +/* To pick up sysconf() */ +#include +#include /* for dlopen */ +#else +/* To pick up getrlimit() etc. */ +#include +#include +#endif + +#ifdef SOLARIS +/* + * Define HAVE_SENDFILEV if the system has the sendfilev() system call. + * Code built this way won't run on a system without sendfilev(). + * We can define HAVE_SENDFILEV by default when the minimum release + * of Solaris that NSPR supports has sendfilev(). + */ +#ifdef HAVE_SENDFILEV + +#include + +#define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d)) + +#else + +#include /* for dlopen */ + +/* + * Match the definitions in . + */ +typedef struct sendfilevec { + int sfv_fd; /* input fd */ + uint_t sfv_flag; /* flags */ + off_t sfv_off; /* offset to start reading from */ + size_t sfv_len; /* amount of data */ +} sendfilevec_t; + +#define SFV_FD_SELF (-2) + +/* + * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *); + */ +static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL; + +#define SOLARIS_SENDFILEV(a, b, c, d) \ + (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d)) + +#endif /* HAVE_SENDFILEV */ +#endif /* SOLARIS */ + +/* + * The send_file() system call is available in AIX 4.3.2 or later. + * If this file is compiled on an older AIX system, it attempts to + * look up the send_file symbol at run time to determine whether + * we can use the faster PR_SendFile/PR_TransmitFile implementation based on + * send_file(). On AIX 4.3.2 or later, we can safely skip this + * runtime function dispatching and just use the send_file based + * implementation. + */ +#ifdef AIX +#ifdef SF_CLOSE +#define HAVE_SEND_FILE +#endif + +#ifdef HAVE_SEND_FILE + +#define AIX_SEND_FILE(a, b, c) send_file(a, b, c) + +#else /* HAVE_SEND_FILE */ + +/* + * The following definitions match those in + * on AIX 4.3.2. + */ + +/* + * Structure for the send_file() system call + */ +struct sf_parms { + /* --------- header parms ---------- */ + void *header_data; /* Input/Output. Points to header buf */ + uint_t header_length; /* Input/Output. Length of the header */ + /* --------- file parms ------------ */ + int file_descriptor; /* Input. File descriptor of the file */ + unsigned long long file_size; /* Output. Size of the file */ + unsigned long long file_offset; /* Input/Output. Starting offset */ + long long file_bytes; /* Input/Output. no. of bytes to send */ + /* --------- trailer parms --------- */ + void *trailer_data; /* Input/Output. Points to trailer buf */ + uint_t trailer_length; /* Input/Output. Length of the trailer */ + /* --------- return info ----------- */ + unsigned long long bytes_sent; /* Output. no. of bytes sent */ +}; + +/* + * Flags for the send_file() system call + */ +#define SF_CLOSE 0x00000001 /* close the socket after completion */ +#define SF_REUSE 0x00000002 /* reuse socket. not supported */ +#define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */ +#define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */ + +/* + * prototype: size_t send_file(int *, struct sf_parms *, uint_t); + */ +static ssize_t (*pt_aix_sendfile_fptr)() = NULL; + +#define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c) + +#endif /* HAVE_SEND_FILE */ +#endif /* AIX */ + +#ifdef LINUX +#include +#endif + +#include "primpl.h" + +#if defined(VBOX) && defined(_PR_POLL_AVAILABLE) +# include +#endif + +#include /* TCP_NODELAY, TCP_MAXSEG */ +#ifdef LINUX +/* TCP_CORK is not defined in on Red Hat Linux 6.0 */ +#ifndef TCP_CORK +#define TCP_CORK 3 +#endif +#endif + +#ifdef DARWIN +static PRBool _pr_ipv6_v6only_on_by_default; +/* The IPV6_V6ONLY socket option is not defined on Mac OS X 10.1. */ +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif +#endif + +#if defined(SOLARIS) +#define _PRSockOptVal_t char * +#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(HPUX) \ + || defined(LINUX) || defined(FREEBSD) || defined(BSDI) || defined(VMS) \ + || defined(NTO) || defined(OPENBSD) || defined(DARWIN) \ + || defined(UNIXWARE) || defined(NETBSD) +#define _PRSockOptVal_t void * +#else +#error "Cannot determine architecture" +#endif + +#if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11)) +#define _PRSelectFdSetArg_t int * +#elif defined(AIX4_1) +#define _PRSelectFdSetArg_t void * +#elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \ + || defined(OSF1) || defined(SOLARIS) \ + || defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) \ + || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ + || defined(BSDI) || defined(VMS) || defined(NTO) || defined(DARWIN) \ + || defined(UNIXWARE) +#define _PRSelectFdSetArg_t fd_set * +#else +#error "Cannot determine architecture" +#endif + +static PRFileDesc *pt_SetMethods( + PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported); + +static PRLock *_pr_flock_lock; /* For PR_LockFile() etc. */ +static PRCondVar *_pr_flock_cv; /* For PR_LockFile() etc. */ +static PRLock *_pr_rename_lock; /* For PR_Rename() */ + +/**************************************************************************/ + +/* These two functions are only used in assertions. */ +#if defined(DEBUG) + +PRBool IsValidNetAddr(const PRNetAddr *addr) +{ + if ((addr != NULL) + && (addr->raw.family != AF_UNIX) + && (addr->raw.family != PR_AF_INET6) + && (addr->raw.family != AF_INET)) { + return PR_FALSE; + } + return PR_TRUE; +} + +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) +{ + /* + * The definition of the length of a Unix domain socket address + * is not uniform, so we don't check it. + */ + if ((addr != NULL) + && (addr->raw.family != AF_UNIX) + && (PR_NETADDR_SIZE(addr) != addr_len)) { +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 + /* + * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 + * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id + * field and is 28 bytes. It is possible for socket functions + * to return an addr_len greater than sizeof(struct sockaddr_in6). + * We need to allow that. (Bugzilla bug #77264) + */ + if ((PR_AF_INET6 == addr->raw.family) + && (sizeof(addr->ipv6) == addr_len)) { + return PR_TRUE; + } +#endif + return PR_FALSE; + } + return PR_TRUE; +} + +#endif /* DEBUG */ + +/*****************************************************************************/ +/************************* I/O Continuation machinery ************************/ +/*****************************************************************************/ + +/* + * The polling interval defines the maximum amount of time that a thread + * might hang up before an interrupt is noticed. + */ +#define PT_DEFAULT_POLL_MSEC 5000 +#if defined(_PR_POLL_WITH_SELECT) +#define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC) +#define PT_DEFAULT_SELECT_USEC \ + ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC) +#endif + +/* + * pt_SockLen is the type for the length of a socket address + * structure, used in the address length argument to bind, + * connect, accept, getsockname, getpeername, etc. Posix.1g + * defines this type as socklen_t. It is size_t or int on + * most current systems. + */ +#if defined(HAVE_SOCKLEN_T) \ + || (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2) +typedef socklen_t pt_SockLen; +#elif (defined(AIX) && !defined(AIX4_1)) \ + || defined(VMS) +typedef PRSize pt_SockLen; +#else +typedef PRIntn pt_SockLen; +#endif + +typedef struct pt_Continuation pt_Continuation; +typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents); + +typedef enum pr_ContuationStatus +{ + pt_continuation_pending, + pt_continuation_done +} pr_ContuationStatus; + +struct pt_Continuation +{ + /* The building of the continuation operation */ + ContinuationFn function; /* what function to continue */ + union { PRIntn osfd; } arg1; /* #1 - the op's fd */ + union { void* buffer; } arg2; /* #2 - primary transfer buffer */ + union { + PRSize amount; /* #3 - size of 'buffer', or */ + pt_SockLen *addr_len; /* - length of address */ +#ifdef HPUX11 + /* + * For sendfile() + */ + struct file_spec { + off_t offset; /* offset in file to send */ + size_t nbytes; /* length of file data to send */ + size_t st_size; /* file size */ + } file_spec; +#endif + } arg3; + union { PRIntn flags; } arg4; /* #4 - read/write flags */ + union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */ + +#ifdef HPUX11 + /* + * For sendfile() + */ + int filedesc; /* descriptor of file to send */ + int nbytes_to_send; /* size of header and file */ +#endif /* HPUX11 */ + +#ifdef SOLARIS + /* + * For sendfilev() + */ + int nbytes_to_send; /* size of header and file */ +#endif /* SOLARIS */ + +#ifdef LINUX + /* + * For sendfile() + */ + int in_fd; /* descriptor of file to send */ + off_t offset; + size_t count; +#endif /* LINUX */ + + PRIntervalTime timeout; /* client (relative) timeout */ + + PRInt16 event; /* flags for poll()'s events */ + + /* + ** The representation and notification of the results of the operation. + ** These function can either return an int return code or a pointer to + ** some object. + */ + union { PRSize code; void *object; } result; + + PRIntn syserrno; /* in case it failed, why (errno) */ + pr_ContuationStatus status; /* the status of the operation */ +}; + +#if defined(DEBUG) + +PTDebug pt_debug; /* this is shared between several modules */ + +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + PTDebug stats; + char buffer[100]; + PRExplodedTime tod; + PRInt64 elapsed, aMil; + stats = pt_debug; /* a copy */ + PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); + + LL_SUB(elapsed, PR_Now(), stats.timeStarted); + LL_I2L(aMil, 1000000); + LL_DIV(elapsed, elapsed, aMil); + + if (NULL != msg) PR_fprintf(debug_out, "%s", msg); + PR_fprintf( + debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed); + PR_fprintf( + debug_out, "\tlocks [created: %u, destroyed: %u]\n", + stats.locks_created, stats.locks_destroyed); + PR_fprintf( + debug_out, "\tlocks [acquired: %u, released: %u]\n", + stats.locks_acquired, stats.locks_released); + PR_fprintf( + debug_out, "\tcvars [created: %u, destroyed: %u]\n", + stats.cvars_created, stats.cvars_destroyed); + PR_fprintf( + debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n", + stats.cvars_notified, stats.delayed_cv_deletes); +} /* PT_FPrintStats */ + +#else + +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg) +{ + /* do nothing */ +} /* PT_FPrintStats */ + +#endif /* DEBUG */ + +#if defined(_PR_POLL_WITH_SELECT) +/* + * OSF1 and HPUX report the POLLHUP event for a socket when the + * shutdown(SHUT_WR) operation is called for the remote end, even though + * the socket is still writeable. Use select(), instead of poll(), to + * workaround this problem. + */ +static void pt_poll_now_with_select(pt_Continuation *op) +{ + PRInt32 msecs; + fd_set rd, wr, *rdp, *wrp; + struct timeval tv; + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRThread *self = PR_GetCurrentThread(); + + PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); + PR_ASSERT(op->arg1.osfd < FD_SETSIZE); + + switch (op->timeout) { + case PR_INTERVAL_NO_TIMEOUT: + tv.tv_sec = PT_DEFAULT_SELECT_SEC; + tv.tv_usec = PT_DEFAULT_SELECT_USEC; + do + { + PRIntn rv; + + if (op->event & POLLIN) { + FD_ZERO(&rd); + FD_SET(op->arg1.osfd, &rd); + rdp = &rd; + } else + rdp = NULL; + if (op->event & POLLOUT) { + FD_ZERO(&wr); + FD_SET(op->arg1.osfd, &wr); + wrp = ≀ + } else + wrp = NULL; + + rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) + continue; /* go around the loop again */ + + if (rv > 0) + { + PRInt16 revents = 0; + + if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) + revents |= POLLIN; + if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) + revents |= POLLOUT; + + if (op->function(op, revents)) + op->status = pt_continuation_done; + } else if (rv == -1) { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + /* else, select timed out */ + } while (pt_continuation_done != op->status); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = op->timeout; + do + { + PRIntn rv; + + if (op->event & POLLIN) { + FD_ZERO(&rd); + FD_SET(op->arg1.osfd, &rd); + rdp = &rd; + } else + rdp = NULL; + if (op->event & POLLOUT) { + FD_ZERO(&wr); + FD_SET(op->arg1.osfd, &wr); + wrp = ≀ + } else + wrp = NULL; + + wait_for_remaining = PR_TRUE; + msecs = (PRInt32)PR_IntervalToMilliseconds(remaining); + if (msecs > PT_DEFAULT_POLL_MSEC) { + wait_for_remaining = PR_FALSE; + msecs = PT_DEFAULT_POLL_MSEC; + } + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC; + rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if (rv > 0) { + PRInt16 revents = 0; + + if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) + revents |= POLLIN; + if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) + revents |= POLLOUT; + + if (op->function(op, revents)) + op->status = pt_continuation_done; + + } else if ((rv == 0) || + ((errno == EINTR) || (errno == EAGAIN))) { + if (rv == 0) { /* select timed out */ + if (wait_for_remaining) + now += remaining; + else + now += PR_MillisecondsToInterval(msecs); + } else + now = PR_IntervalNow(); + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= op->timeout) { + op->result.code = -1; + op->syserrno = ETIMEDOUT; + op->status = pt_continuation_done; + } else + remaining = op->timeout - elapsed; + } else { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + } while (pt_continuation_done != op->status); + break; + } + +} /* pt_poll_now_with_select */ + +#endif /* _PR_POLL_WITH_SELECT */ + +static void pt_poll_now(pt_Continuation *op) +{ + PRInt32 msecs; + PRIntervalTime epoch, now, elapsed, remaining; + PRBool wait_for_remaining; + PRThread *self = PR_GetCurrentThread(); + + PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout); +#if defined (_PR_POLL_WITH_SELECT) + /* + * If the fd is small enough call the select-based poll operation + */ + if (op->arg1.osfd < FD_SETSIZE) { + pt_poll_now_with_select(op); + return; + } +#endif + + switch (op->timeout) { + case PR_INTERVAL_NO_TIMEOUT: + msecs = PT_DEFAULT_POLL_MSEC; + do + { + PRIntn rv; + struct pollfd tmp_pfd; + + tmp_pfd.revents = 0; + tmp_pfd.fd = op->arg1.osfd; + tmp_pfd.events = op->event; + + rv = poll(&tmp_pfd, 1, msecs); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) + continue; /* go around the loop again */ + + if (rv > 0) + { + PRInt16 events = tmp_pfd.events; + PRInt16 revents = tmp_pfd.revents; + + if ((revents & POLLNVAL) /* busted in all cases */ + || ((events & POLLOUT) && (revents & POLLHUP))) + /* write op & hup */ + { + op->result.code = -1; + if (POLLNVAL & revents) op->syserrno = EBADF; + else if (POLLHUP & revents) op->syserrno = EPIPE; + op->status = pt_continuation_done; + } else { + if (op->function(op, revents)) + op->status = pt_continuation_done; + } + } else if (rv == -1) { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + /* else, poll timed out */ + } while (pt_continuation_done != op->status); + break; + default: + now = epoch = PR_IntervalNow(); + remaining = op->timeout; + do + { + PRIntn rv; + struct pollfd tmp_pfd; + + tmp_pfd.revents = 0; + tmp_pfd.fd = op->arg1.osfd; + tmp_pfd.events = op->event; + + wait_for_remaining = PR_TRUE; + msecs = (PRInt32)PR_IntervalToMilliseconds(remaining); + if (msecs > PT_DEFAULT_POLL_MSEC) + { + wait_for_remaining = PR_FALSE; + msecs = PT_DEFAULT_POLL_MSEC; + } + rv = poll(&tmp_pfd, 1, msecs); + + if (self->state & PT_THREAD_ABORTED) + { + self->state &= ~PT_THREAD_ABORTED; + op->result.code = -1; + op->syserrno = EINTR; + op->status = pt_continuation_done; + return; + } + + if (rv > 0) + { + PRInt16 events = tmp_pfd.events; + PRInt16 revents = tmp_pfd.revents; + + if ((revents & POLLNVAL) /* busted in all cases */ + || ((events & POLLOUT) && (revents & POLLHUP))) + /* write op & hup */ + { + op->result.code = -1; + if (POLLNVAL & revents) op->syserrno = EBADF; + else if (POLLHUP & revents) op->syserrno = EPIPE; + op->status = pt_continuation_done; + } else { + if (op->function(op, revents)) + { + op->status = pt_continuation_done; + } + } + } else if ((rv == 0) || + ((errno == EINTR) || (errno == EAGAIN))) { + if (rv == 0) /* poll timed out */ + { + if (wait_for_remaining) + now += remaining; + else + now += PR_MillisecondsToInterval(msecs); + } + else + now = PR_IntervalNow(); + elapsed = (PRIntervalTime) (now - epoch); + if (elapsed >= op->timeout) { + op->result.code = -1; + op->syserrno = ETIMEDOUT; + op->status = pt_continuation_done; + } else + remaining = op->timeout - elapsed; + } else { + op->result.code = -1; + op->syserrno = errno; + op->status = pt_continuation_done; + } + } while (pt_continuation_done != op->status); + break; + } + +} /* pt_poll_now */ + +static PRIntn pt_Continue(pt_Continuation *op) +{ + op->status = pt_continuation_pending; /* set default value */ + /* + * let each thread call poll directly + */ + pt_poll_now(op); + PR_ASSERT(pt_continuation_done == op->status); + return op->result.code; +} /* pt_Continue */ + +/*****************************************************************************/ +/*********************** specific continuation functions *********************/ +/*****************************************************************************/ +static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents) +{ + op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd); + if (op->syserrno != 0) { + op->result.code = -1; + } else { + op->result.code = 0; + } + return PR_TRUE; /* this one is cooked */ +} /* pt_connect_cont */ + +static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents) +{ + op->syserrno = 0; + op->result.code = accept( + op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len); + if (-1 == op->result.code) + { + op->syserrno = errno; + if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno) + return PR_FALSE; /* do nothing - this one ain't finished */ + } + return PR_TRUE; +} /* pt_accept_cont */ + +static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents) +{ + /* + * Any number of bytes will complete the operation. It need + * not (and probably will not) satisfy the request. The only + * error we continue is EWOULDBLOCK|EAGAIN. + */ + op->result.code = read( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + op->syserrno = errno; + return ((-1 == op->result.code) && + (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_read_cont */ + +static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents) +{ + /* + * Any number of bytes will complete the operation. It need + * not (and probably will not) satisfy the request. The only + * error we continue is EWOULDBLOCK|EAGAIN. + */ +#if defined(SOLARIS) + if (0 == op->arg4.flags) + op->result.code = read( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + else + op->result.code = recv( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#else + op->result.code = recv( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#endif + op->syserrno = errno; + return ((-1 == op->result.code) && + (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_recv_cont */ + +static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes; +#if defined(SOLARIS) + PRInt32 tmp_amount = op->arg3.amount; +#endif + /* + * We want to write the entire amount out, no matter how many + * tries it takes. Keep advancing the buffer and the decrementing + * the amount until the amount goes away. Return the total bytes + * (which should be the original amount) when finished (or an + * error). + */ +#if defined(SOLARIS) +retry: + bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount); +#else + bytes = send( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags); +#endif + op->syserrno = errno; + +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE error + * on occasion. Try to write in smaller chunks to workaround this bug. + */ + if ((bytes == -1) && (op->syserrno == ERANGE)) + { + if (tmp_amount > 1) + { + tmp_amount = tmp_amount/2; /* half the bytes */ + goto retry; + } + } +#endif + + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_send_cont */ + +static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes; + /* + * We want to write the entire amount out, no matter how many + * tries it takes. Keep advancing the buffer and the decrementing + * the amount until the amount goes away. Return the total bytes + * (which should be the original amount) when finished (or an + * error). + */ + bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_write_cont */ + +static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes; + struct iovec *iov = (struct iovec*)op->arg2.buffer; + /* + * Same rules as write, but continuing seems to be a bit more + * complicated. As the number of bytes sent grows, we have to + * redefine the vector we're pointing at. We might have to + * modify an individual vector parms or we might have to eliminate + * a pair altogether. + */ + bytes = writev(op->arg1.osfd, iov, op->arg3.amount); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + PRIntn iov_index; + op->result.code += bytes; /* accumulate the number sent */ + for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index) + { + /* how much progress did we make in the i/o vector? */ + if (bytes < iov[iov_index].iov_len) + { + /* this element's not done yet */ + char **bp = (char**)&(iov[iov_index].iov_base); + iov[iov_index].iov_len -= bytes; /* there's that much left */ + *bp += bytes; /* starting there */ + break; /* go off and do that */ + } + bytes -= iov[iov_index].iov_len; /* that element's consumed */ + } + op->arg2.buffer = &iov[iov_index]; /* new start of array */ + op->arg3.amount -= iov_index; /* and array length */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_writev_cont */ + +static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents) +{ + PRIntn bytes = sendto( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags, + (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr)); + op->syserrno = errno; + if (bytes >= 0) /* this is progress */ + { + char *bp = (char*)op->arg2.buffer; + bp += bytes; /* adjust the buffer pointer */ + op->arg2.buffer = bp; + op->result.code += bytes; /* accumulate the number sent */ + op->arg3.amount -= bytes; /* and reduce the required count */ + return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE; + } + else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) + { + op->result.code = -1; + return PR_TRUE; + } + else return PR_FALSE; +} /* pt_sendto_cont */ + +static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents) +{ + pt_SockLen addr_len = sizeof(PRNetAddr); + op->result.code = recvfrom( + op->arg1.osfd, op->arg2.buffer, op->arg3.amount, + op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len); + op->syserrno = errno; + return ((-1 == op->result.code) && + (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ? + PR_FALSE : PR_TRUE; +} /* pt_recvfrom_cont */ + +#ifdef AIX +static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer; + ssize_t rv; + unsigned long long saved_file_offset; + long long saved_file_bytes; + + saved_file_offset = sf_struct->file_offset; + saved_file_bytes = sf_struct->file_bytes; + sf_struct->bytes_sent = 0; + + if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0)) + PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <= + sf_struct->file_size); + rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags); + op->syserrno = errno; + + if (rv != -1) { + op->result.code += sf_struct->bytes_sent; + /* + * A bug in AIX 4.3.2 prevents the 'file_bytes' field from + * being updated. So, 'file_bytes' is maintained by NSPR to + * avoid conflict when this bug is fixed in AIX, in the future. + */ + if (saved_file_bytes != -1) + saved_file_bytes -= (sf_struct->file_offset - saved_file_offset); + sf_struct->file_bytes = saved_file_bytes; + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + } else { + return PR_FALSE; + } + + if (rv == 1) { /* more data to send */ + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* AIX */ + +#ifdef HPUX11 +static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct iovec *hdtrl = (struct iovec *) op->arg2.buffer; + int count; + + count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset, + op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags); + PR_ASSERT(count <= op->nbytes_to_send); + op->syserrno = errno; + + if (count != -1) { + op->result.code += count; + } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + } else { + return PR_FALSE; + } + if (count != -1 && count < op->nbytes_to_send) { + if (count < hdtrl[0].iov_len) { + /* header not sent */ + + hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count; + hdtrl[0].iov_len -= count; + + } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) { + /* header sent, file not sent */ + PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len; + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + + op->arg3.file_spec.offset += file_nbytes_sent; + op->arg3.file_spec.nbytes -= file_nbytes_sent; + } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes + + hdtrl[1].iov_len)) { + PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len + + op->arg3.file_spec.nbytes); + + /* header sent, file sent, trailer not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + /* + * set file offset and len so that no more file data is + * sent + */ + op->arg3.file_spec.offset = op->arg3.file_spec.st_size; + op->arg3.file_spec.nbytes = 0; + + hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent; + hdtrl[1].iov_len -= trailer_nbytes_sent; + } + op->nbytes_to_send -= count; + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* HPUX11 */ + +#ifdef SOLARIS +static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer; + size_t xferred; + ssize_t count; + + count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred); + op->syserrno = errno; + PR_ASSERT((count == -1) || (count == xferred)); + + if (count == -1) { + if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN + && op->syserrno != EINTR) { + op->result.code = -1; + return PR_TRUE; + } + count = xferred; + } + PR_ASSERT(count <= op->nbytes_to_send); + + op->result.code += count; + if (count < op->nbytes_to_send) { + op->nbytes_to_send -= count; + + while (count >= vec->sfv_len) { + count -= vec->sfv_len; + vec++; + op->arg3.amount--; + } + PR_ASSERT(op->arg3.amount > 0); + + vec->sfv_off += count; + vec->sfv_len -= count; + PR_ASSERT(vec->sfv_len > 0); + op->arg2.buffer = vec; + + return PR_FALSE; + } + + return PR_TRUE; +} +#endif /* SOLARIS */ + +#ifdef LINUX +static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents) +{ + ssize_t rv; + off_t oldoffset; + + oldoffset = op->offset; + rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count); + op->syserrno = errno; + + if (rv == -1) { + if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) { + op->result.code = -1; + return PR_TRUE; + } + rv = 0; + } + PR_ASSERT(rv == op->offset - oldoffset); + op->result.code += rv; + if (rv < op->count) { + op->count -= rv; + return PR_FALSE; + } + return PR_TRUE; +} +#endif /* LINUX */ + +void _PR_InitIO(void) +{ +#if defined(DEBUG) + memset(&pt_debug, 0, sizeof(PTDebug)); + pt_debug.timeStarted = PR_Now(); +#endif + + _pr_flock_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_flock_lock); + _pr_flock_cv = PR_NewCondVar(_pr_flock_lock); + PR_ASSERT(NULL != _pr_flock_cv); + _pr_rename_lock = PR_NewLock(); + PR_ASSERT(NULL != _pr_rename_lock); + + _PR_InitFdCache(); /* do that */ + + _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE); + _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE); + _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE); + PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr); + +#ifdef DARWIN + /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option + * is turned on by default, contrary to what RFC 3493, Section + * 5.3 says. So we have to turn it off. Find out whether we + * are running on such a system. + */ + { + int osfd; + osfd = socket(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + int on; + int optlen = sizeof(on); + if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, + &on, &optlen) == 0) { + _pr_ipv6_v6only_on_by_default = on; + } + close(osfd); + } + } +#endif +} /* _PR_InitIO */ + +void _PR_CleanupIO(void) +{ + _PR_Putfd(_pr_stdin); + _pr_stdin = NULL; + _PR_Putfd(_pr_stdout); + _pr_stdout = NULL; + _PR_Putfd(_pr_stderr); + _pr_stderr = NULL; + + _PR_CleanupFdCache(); + + if (_pr_flock_cv) + { + PR_DestroyCondVar(_pr_flock_cv); + _pr_flock_cv = NULL; + } + if (_pr_flock_lock) + { + PR_DestroyLock(_pr_flock_lock); + _pr_flock_lock = NULL; + } + if (_pr_rename_lock) + { + PR_DestroyLock(_pr_rename_lock); + _pr_rename_lock = NULL; + } +} /* _PR_CleanupIO */ + +PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) +{ + PRFileDesc *result = NULL; + PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError); + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + switch (osfd) + { + case PR_StandardInput: result = _pr_stdin; break; + case PR_StandardOutput: result = _pr_stdout; break; + case PR_StandardError: result = _pr_stderr; break; + default: + (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + } + return result; +} /* PR_GetSpecialFD */ + +/*****************************************************************************/ +/***************************** I/O private methods ***************************/ +/*****************************************************************************/ + +static PRBool pt_TestAbort(void) +{ + PRThread *me = PR_CurrentThread(); + if(_PT_THREAD_INTERRUPTED(me)) + { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + me->state &= ~PT_THREAD_ABORTED; + return PR_TRUE; + } + return PR_FALSE; +} /* pt_TestAbort */ + +static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) +{ + switch (syserrno) + { + case EINTR: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break; + case ETIMEDOUT: + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; + default: + mapper(syserrno); + } +} /* pt_MapError */ + +static PRStatus pt_Close(PRFileDesc *fd) +{ + if ((NULL == fd) || (NULL == fd->secret) + || ((_PR_FILEDESC_OPEN != fd->secret->state) + && (_PR_FILEDESC_CLOSED != fd->secret->state))) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + if (pt_TestAbort()) return PR_FAILURE; + + if (_PR_FILEDESC_OPEN == fd->secret->state) + { + if (-1 == close(fd->secret->md.osfd)) + { +#ifdef OSF1 + /* + * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close() + * system call, when called to close a TCP socket, may + * return -1 with errno set to EINVAL but the system call + * does close the socket successfully. An application + * may safely ignore the EINVAL error. This bug is fixed + * on Tru64 UNIX V5.1A and later. The defect tracking + * number is QAR 81431. + */ + if (PR_DESC_SOCKET_TCP != fd->methods->file_type + || EINVAL != errno) + { + pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); + return PR_FAILURE; + } +#else + pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno); + return PR_FAILURE; +#endif + } + fd->secret->state = _PR_FILEDESC_CLOSED; + } + _PR_Putfd(fd); + return PR_SUCCESS; +} /* pt_Close */ + +static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + PRInt32 syserrno, bytes = -1; + + if (pt_TestAbort()) return bytes; + + bytes = read(fd->secret->md.osfd, buf, amount); + syserrno = errno; + + if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking)) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.timeout = PR_INTERVAL_NO_TIMEOUT; + op.function = pt_read_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno); + return bytes; +} /* pt_Read */ + +static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; + + if (pt_TestAbort()) return bytes; + + bytes = write(fd->secret->md.osfd, buf, amount); + syserrno = errno; + + if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) ) + { + buf = (char *) buf + bytes; + amount -= bytes; + fNeedContinue = PR_TRUE; + } + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + bytes = 0; + fNeedContinue = PR_TRUE; + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.timeout = PR_INTERVAL_NO_TIMEOUT; + op.result.code = bytes; /* initialize the number sent */ + op.function = pt_write_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes == -1) + pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno); + return bytes; +} /* pt_Write */ + +static PRInt32 pt_Writev( + PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout) +{ + PRIntn iov_index; + PRBool fNeedContinue = PR_FALSE; + PRInt32 syserrno, bytes, rv = -1; + struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov; + int osiov_len; + + if (pt_TestAbort()) return rv; + + /* Ensured by PR_Writev */ + PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE); + + /* + * We can't pass iov to writev because PRIOVec and struct iovec + * may not be binary compatible. Make osiov a copy of iov and + * pass osiov to writev. We can modify osiov if we need to + * continue the operation. + */ + osiov = osiov_local; + osiov_len = iov_len; + for (iov_index = 0; iov_index < osiov_len; iov_index++) + { + osiov[iov_index].iov_base = iov[iov_index].iov_base; + osiov[iov_index].iov_len = iov[iov_index].iov_len; + } + + rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len); + syserrno = errno; + + if (!fd->secret->nonblocking) + { + if (bytes >= 0) + { + /* + * If we moved some bytes, how does that implicate the + * i/o vector list? In other words, exactly where are + * we within that array? What are the parameters for + * resumption? Maybe we're done! + */ + for ( ;osiov_len > 0; osiov++, osiov_len--) + { + if (bytes < osiov->iov_len) + { + /* this one's not done yet */ + osiov->iov_base = (char*)osiov->iov_base + bytes; + osiov->iov_len -= bytes; + break; /* go off and do that */ + } + bytes -= osiov->iov_len; /* this one's done cooked */ + } + PR_ASSERT(osiov_len > 0 || bytes == 0); + if (osiov_len > 0) + { + if (PR_INTERVAL_NO_WAIT == timeout) + { + rv = -1; + syserrno = ETIMEDOUT; + } + else fNeedContinue = PR_TRUE; + } + } + else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + rv = 0; + fNeedContinue = PR_TRUE; + } + } + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)osiov; + op.arg3.amount = osiov_len; + op.timeout = timeout; + op.result.code = rv; + op.function = pt_writev_cont; + op.event = POLLOUT | POLLPRI; + rv = pt_Continue(&op); + syserrno = op.syserrno; + } + if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno); + return rv; +} /* pt_Writev */ + +static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence) +{ + return _PR_MD_LSEEK(fd, offset, whence); +} /* pt_Seek */ + +static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence) +{ + return _PR_MD_LSEEK64(fd, offset, whence); +} /* pt_Seek64 */ + +static PRInt32 pt_Available_f(PRFileDesc *fd) +{ + PRInt32 result, cur, end; + + cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR); + + if (cur >= 0) + end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END); + + if ((cur < 0) || (end < 0)) { + return -1; + } + + result = end - cur; + _PR_MD_LSEEK(fd, cur, PR_SEEK_SET); + + return result; +} /* pt_Available_f */ + +static PRInt64 pt_Available64_f(PRFileDesc *fd) +{ + PRInt64 result, cur, end; + PRInt64 minus_one; + + LL_I2L(minus_one, -1); + cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR); + + if (LL_GE_ZERO(cur)) + end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END); + + if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one; + + LL_SUB(result, end, cur); + (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET); + + return result; +} /* pt_Available64_f */ + +static PRInt32 pt_Available_s(PRFileDesc *fd) +{ + PRInt32 rv, bytes = -1; + if (pt_TestAbort()) return bytes; + + rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes); + + if (rv == -1) + pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno); + return bytes; +} /* pt_Available_s */ + +static PRInt64 pt_Available64_s(PRFileDesc *fd) +{ + PRInt64 rv; + LL_I2L(rv, pt_Available_s(fd)); + return rv; +} /* pt_Available64_s */ + +static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info) +{ + PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_FileInfo */ + +static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info) +{ + PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_FileInfo64 */ + +static PRStatus pt_Synch(PRFileDesc *fd) +{ + return (NULL == fd) ? PR_FAILURE : PR_SUCCESS; +} /* pt_Synch */ + +static PRStatus pt_Fsync(PRFileDesc *fd) +{ + PRIntn rv = -1; + if (pt_TestAbort()) return PR_FAILURE; + + rv = fsync(fd->secret->md.osfd); + if (rv < 0) { + pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Fsync */ + +static PRStatus pt_Connect( + PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) +{ + PRIntn rv = -1, syserrno; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return PR_FAILURE; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + addr_len = PR_NETADDR_SIZE(addr); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + rv = connect(fd->secret->md.osfd, (struct sockaddr*)&addrCopy, addr_len); +#else + rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); +#endif + syserrno = errno; + if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking)) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; +#ifdef _PR_HAVE_SOCKADDR_LEN + op.arg2.buffer = (void*)&addrCopy; +#else + op.arg2.buffer = (void*)addr; +#endif + op.arg3.amount = addr_len; + op.timeout = timeout; + op.function = pt_connect_cont; + op.event = POLLOUT | POLLPRI; + rv = pt_Continue(&op); + syserrno = op.syserrno; + } + } + if (-1 == rv) { + pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Connect */ + +static PRStatus pt_ConnectContinue( + PRFileDesc *fd, PRInt16 out_flags) +{ + int err; + PRInt32 osfd; + + if (out_flags & PR_POLL_NVAL) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) + { + PR_ASSERT(out_flags == 0); + PR_SetError(PR_IN_PROGRESS_ERROR, 0); + return PR_FAILURE; + } + + osfd = fd->secret->md.osfd; + + err = _MD_unix_get_nonblocking_connect_error(osfd); + if (err != 0) + { + _PR_MD_MAP_CONNECT_ERROR(err); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_ConnectContinue */ + +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) +{ + /* Find the NSPR layer and invoke its connectcontinue method */ + PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); + + if (NULL == bottom) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + return pt_ConnectContinue(bottom, pd->out_flags); +} /* PR_GetConnectStatus */ + +static PRFileDesc* pt_Accept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRFileDesc *newfd = NULL; + PRIntn syserrno, osfd = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return newfd; + +#ifdef _PR_STRICT_ADDR_LEN + if (addr) + { + /* + * Set addr->raw.family just so that we can use the + * PR_NETADDR_SIZE macro. + */ + addr->raw.family = fd->secret->af; + addr_len = PR_NETADDR_SIZE(addr); + } +#endif + + osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + syserrno = errno; + + if (osfd == -1) + { + if (fd->secret->nonblocking) goto failed; + + if (EWOULDBLOCK != syserrno && EAGAIN != syserrno + && ECONNABORTED != syserrno) + goto failed; + else + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = addr; + op.arg3.addr_len = &addr_len; + op.timeout = timeout; + op.function = pt_accept_cont; + op.event = POLLIN | POLLPRI; + osfd = pt_Continue(&op); + syserrno = op.syserrno; + } + if (osfd < 0) goto failed; + } + } +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE); + if (newfd == NULL) close(osfd); /* $$$ whoops! this doesn't work $$$ */ + else + { + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); +#ifdef LINUX + /* + * On Linux, experiments showed that the accepted sockets + * inherit the TCP_NODELAY socket option of the listening + * socket. + */ + newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay; +#endif + } + return newfd; + +failed: + pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno); + return NULL; +} /* pt_Accept */ + +static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr) +{ + PRIntn rv; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return PR_FAILURE; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + if (addr->raw.family == AF_UNIX) + { + /* Disallow relative pathnames */ + if (addr->local.path[0] != '/') + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + } + +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + + addr_len = PR_NETADDR_SIZE(addr); +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + rv = bind(fd->secret->md.osfd, (struct sockaddr*)&addrCopy, addr_len); +#else + rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len); +#endif + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_BIND_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Bind */ + +static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog) +{ + PRIntn rv; + + if (pt_TestAbort()) return PR_FAILURE; + + rv = listen(fd->secret->md.osfd, backlog); + if (rv == -1) { + pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Listen */ + +static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how) +{ + PRIntn rv = -1; + if (pt_TestAbort()) return PR_FAILURE; + + rv = shutdown(fd->secret->md.osfd, how); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* pt_Shutdown */ + +static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + *out_flags = 0; + return in_flags; +} /* pt_Poll */ + +static PRInt32 pt_Recv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRIntn osflags; + + if (0 == flags) + osflags = 0; + else if (PR_MSG_PEEK == flags) + osflags = MSG_PEEK; + else + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return bytes; + } + + if (pt_TestAbort()) return bytes; + + /* recv() is a much slower call on pre-2.6 Solaris than read(). */ +#if defined(SOLARIS) + if (0 == osflags) + bytes = read(fd->secret->md.osfd, buf, amount); + else + bytes = recv(fd->secret->md.osfd, buf, amount, osflags); +#else + bytes = recv(fd->secret->md.osfd, buf, amount, osflags); +#endif + syserrno = errno; + + if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking)) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = osflags; + op.timeout = timeout; + op.function = pt_recv_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno); + return bytes; +} /* pt_Recv */ + +static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount) +{ + return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} /* pt_SocketRead */ + +static PRInt32 pt_Send( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; +#if defined(SOLARIS) + PRInt32 tmp_amount = amount; +#endif + + /* + * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h, + * which has the following: + * # define send cma_send + * extern int cma_send (int , void *, int, int ); + * So we need to cast away the 'const' of argument #2 for send(). + */ +#if defined (HPUX) && defined(_PR_DCETHREADS) +#define PT_SENDBUF_CAST (void *) +#else +#define PT_SENDBUF_CAST +#endif + + if (pt_TestAbort()) return bytes; + + /* + * On pre-2.6 Solaris, send() is much slower than write(). + * On 2.6 and beyond, with in-kernel sockets, send() and + * write() are fairly equivalent in performance. + */ +#if defined(SOLARIS) + PR_ASSERT(0 == flags); +retry: + bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount); +#else + bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags); +#endif + syserrno = errno; + +#if defined(SOLARIS) + /* + * The write system call has been reported to return the ERANGE error + * on occasion. Try to write in smaller chunks to workaround this bug. + */ + if ((bytes == -1) && (syserrno == ERANGE)) + { + if (tmp_amount > 1) + { + tmp_amount = tmp_amount/2; /* half the bytes */ + goto retry; + } + } +#endif + + if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) + { + bytes = -1; + syserrno = ETIMEDOUT; + } + else + { + buf = (char *) buf + bytes; + amount -= bytes; + fNeedContinue = PR_TRUE; + } + } + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else + { + bytes = 0; + fNeedContinue = PR_TRUE; + } + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.timeout = timeout; + op.result.code = bytes; /* initialize the number sent */ + op.function = pt_send_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes == -1) + pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno); + return bytes; +} /* pt_Send */ + +static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount) +{ + return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); +} /* pt_SocketWrite */ + +static PRInt32 pt_SendTo( + PRFileDesc *fd, const void *buf, + PRInt32 amount, PRIntn flags, const PRNetAddr *addr, + PRIntervalTime timeout) +{ + PRInt32 syserrno, bytes = -1; + PRBool fNeedContinue = PR_FALSE; + pt_SockLen addr_len; + const PRNetAddr *addrp = addr; +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6) + PRUint16 md_af = addr->raw.family; + PRNetAddr addrCopy; +#endif + + if (pt_TestAbort()) return bytes; + + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); +#if defined(_PR_INET6) + if (addr->raw.family == PR_AF_INET6) { + md_af = AF_INET6; +#ifndef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + addrCopy.raw.family = AF_INET6; + addrp = &addrCopy; +#endif + } +#endif + + addr_len = PR_NETADDR_SIZE(addr); +#ifdef _PR_HAVE_SOCKADDR_LEN + addrCopy = *addr; + ((struct sockaddr*)&addrCopy)->sa_len = addr_len; + ((struct sockaddr*)&addrCopy)->sa_family = md_af; + bytes = sendto( + fd->secret->md.osfd, buf, amount, flags, + (struct sockaddr*)&addrCopy, addr_len); +#else + bytes = sendto( + fd->secret->md.osfd, buf, amount, flags, + (struct sockaddr*)addrp, addr_len); +#endif + syserrno = errno; + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else fNeedContinue = PR_TRUE; + } + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = (void*)buf; + op.arg3.amount = amount; + op.arg4.flags = flags; +#ifdef _PR_HAVE_SOCKADDR_LEN + op.arg5.addr = (PRNetAddr*)&addrCopy; +#else + op.arg5.addr = (PRNetAddr*)addr; +#endif + op.timeout = timeout; + op.result.code = 0; /* initialize the number sent */ + op.function = pt_sendto_cont; + op.event = POLLOUT | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } + if (bytes < 0) + pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno); + return bytes; +} /* pt_SendTo */ + +static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRBool fNeedContinue = PR_FALSE; + PRInt32 syserrno, bytes = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return bytes; + + bytes = recvfrom( + fd->secret->md.osfd, buf, amount, flags, + (struct sockaddr*)addr, &addr_len); + syserrno = errno; + + if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) + && (!fd->secret->nonblocking) ) + { + if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT; + else fNeedContinue = PR_TRUE; + } + + if (fNeedContinue == PR_TRUE) + { + pt_Continuation op; + op.arg1.osfd = fd->secret->md.osfd; + op.arg2.buffer = buf; + op.arg3.amount = amount; + op.arg4.flags = flags; + op.arg5.addr = addr; + op.timeout = timeout; + op.function = pt_recvfrom_cont; + op.event = POLLIN | POLLPRI; + bytes = pt_Continue(&op); + syserrno = op.syserrno; + } +#ifdef _PR_HAVE_SOCKADDR_LEN + if (bytes >= 0) + { + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (addr && (AF_INET6 == addr->raw.family)) + addr->raw.family = PR_AF_INET6; +#endif + if (bytes < 0) + pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno); + return bytes; +} /* pt_RecvFrom */ + +#ifdef AIX +#ifndef HAVE_SEND_FILE +static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT; + +static void pt_aix_sendfile_init_routine(void) +{ + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file"); + dlclose(handle); +} + +/* + * pt_AIXDispatchSendFile + */ +static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + int rv; + + rv = pthread_once(&pt_aix_sendfile_once_block, + pt_aix_sendfile_init_routine); + PR_ASSERT(0 == rv); + if (pt_aix_sendfile_fptr) { + return pt_AIXSendFile(sd, sfd, flags, timeout); + } else { + return PR_EmulateSendFile(sd, sfd, flags, timeout); + } +} +#endif /* !HAVE_SEND_FILE */ + + +/* + * pt_AIXSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the send_file() system + * call available in AIX 4.3.2. + */ + +static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct sf_parms sf_struct; + uint_t send_flags; + ssize_t rv; + int syserrno; + PRInt32 count; + unsigned long long saved_file_offset; + long long saved_file_bytes; + + sf_struct.header_data = (void *) sfd->header; /* cast away the 'const' */ + sf_struct.header_length = sfd->hlen; + sf_struct.file_descriptor = sfd->fd->secret->md.osfd; + sf_struct.file_size = 0; + sf_struct.file_offset = sfd->file_offset; + if (sfd->file_nbytes == 0) + sf_struct.file_bytes = -1; + else + sf_struct.file_bytes = sfd->file_nbytes; + sf_struct.trailer_data = (void *) sfd->trailer; + sf_struct.trailer_length = sfd->tlen; + sf_struct.bytes_sent = 0; + + saved_file_offset = sf_struct.file_offset; + saved_file_bytes = sf_struct.file_bytes; + + send_flags = 0; /* flags processed at the end */ + + /* The first argument to send_file() is int*. */ + PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd)); + do { + rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags); + } while (rv == -1 && (syserrno = errno) == EINTR); + + if (rv == -1) { + if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) { + count = 0; /* Not a real error. Need to continue. */ + } else { + count = -1; + } + } else { + count = sf_struct.bytes_sent; + /* + * A bug in AIX 4.3.2 prevents the 'file_bytes' field from + * being updated. So, 'file_bytes' is maintained by NSPR to + * avoid conflict when this bug is fixed in AIX, in the future. + */ + if (saved_file_bytes != -1) + saved_file_bytes -= (sf_struct.file_offset - saved_file_offset); + sf_struct.file_bytes = saved_file_bytes; + } + + if ((rv == 1) || ((rv == -1) && (count == 0))) { + pt_Continuation op; + + op.arg1.osfd = sd->secret->md.osfd; + op.arg2.buffer = &sf_struct; + op.arg4.flags = send_flags; + op.result.code = count; + op.timeout = timeout; + op.function = pt_aix_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + + if (count == -1) { + pt_MapError(_MD_aix_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == (sfd->hlen + sfd->tlen + + ((sfd->file_nbytes == 0) ? + sf_struct.file_size - sfd->file_offset : + sfd->file_nbytes))); + return count; +} +#endif /* AIX */ + +#ifdef HPUX11 +/* + * pt_HPUXSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfile() system + * call available in HP-UX B.11.00. + */ + +static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t nbytes_to_send, file_nbytes_to_send; + struct iovec hdtrl[2]; /* optional header and trailer buffers */ + int send_flags; + PRInt32 count; + int syserrno; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; + + hdtrl[0].iov_base = (void *) sfd->header; /* cast away the 'const' */ + hdtrl[0].iov_len = sfd->hlen; + hdtrl[1].iov_base = (void *) sfd->trailer; + hdtrl[1].iov_len = sfd->tlen; + /* + * SF_DISCONNECT seems to close the socket even if sendfile() + * only does a partial send on a nonblocking socket. This + * would prevent the subsequent sendfile() calls on that socket + * from working. So we don't use the SD_DISCONNECT flag. + */ + send_flags = 0; + + do { + count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, + sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags); + } while (count == -1 && (syserrno = errno) == EINTR); + + if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) { + count = 0; + } + if (count != -1 && count < nbytes_to_send) { + pt_Continuation op; + + if (count < sfd->hlen) { + /* header not sent */ + + hdtrl[0].iov_base = ((char *) sfd->header) + count; + hdtrl[0].iov_len = sfd->hlen - count; + op.arg3.file_spec.offset = sfd->file_offset; + op.arg3.file_spec.nbytes = file_nbytes_to_send; + } else if (count < (sfd->hlen + file_nbytes_to_send)) { + /* header sent, file not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + + op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen; + op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen); + } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) { + PRUint32 trailer_nbytes_sent; + + /* header sent, file sent, trailer not sent */ + + hdtrl[0].iov_base = NULL; + hdtrl[0].iov_len = 0; + /* + * set file offset and len so that no more file data is + * sent + */ + op.arg3.file_spec.offset = statbuf.st_size; + op.arg3.file_spec.nbytes = 0; + + trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send; + hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent; + hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent; + } + + op.arg1.osfd = sd->secret->md.osfd; + op.filedesc = sfd->fd->secret->md.osfd; + op.arg2.buffer = hdtrl; + op.arg3.file_spec.st_size = statbuf.st_size; + op.arg4.flags = send_flags; + op.nbytes_to_send = nbytes_to_send - count; + op.result.code = count; + op.timeout = timeout; + op.function = pt_hpux_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + + if (count == -1) { + pt_MapError(_MD_hpux_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == nbytes_to_send); + return count; +} + +#endif /* HPUX11 */ + +#ifdef SOLARIS + +/* + * pt_SolarisSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfilev() system + * call available in Solaris 8. + */ + +static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t nbytes_to_send, file_nbytes_to_send; + struct sendfilevec sfv_struct[3]; + int sfvcnt = 0; + size_t xferred; + PRInt32 count; + int syserrno; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + + nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send; + + if (sfd->hlen != 0) { + sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; + sfv_struct[sfvcnt].sfv_len = sfd->hlen; + sfvcnt++; + } + + if (file_nbytes_to_send != 0) { + sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = sfd->file_offset; + sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send; + sfvcnt++; + } + + if (sfd->tlen != 0) { + sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF; + sfv_struct[sfvcnt].sfv_flag = 0; + sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; + sfv_struct[sfvcnt].sfv_len = sfd->tlen; + sfvcnt++; + } + + if (0 == sfvcnt) { + count = 0; + goto done; + } + + /* + * Strictly speaking, we may have sent some bytes when the + * sendfilev() is interrupted and we should retry it from an + * updated offset. We are not doing that here. + */ + count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct, + sfvcnt, &xferred); + + PR_ASSERT((count == -1) || (count == xferred)); + + if (count == -1) { + syserrno = errno; + if (syserrno == EINTR + || syserrno == EAGAIN || syserrno == EWOULDBLOCK) { + count = xferred; + } + } + + if (count != -1 && count < nbytes_to_send) { + pt_Continuation op; + struct sendfilevec *vec = sfv_struct; + PRInt32 rem = count; + + while (rem >= vec->sfv_len) { + rem -= vec->sfv_len; + vec++; + sfvcnt--; + } + PR_ASSERT(sfvcnt > 0); + + vec->sfv_off += rem; + vec->sfv_len -= rem; + PR_ASSERT(vec->sfv_len > 0); + + op.arg1.osfd = sd->secret->md.osfd; + op.arg2.buffer = vec; + op.arg3.amount = sfvcnt; + op.arg4.flags = 0; + op.nbytes_to_send = nbytes_to_send - count; + op.result.code = count; + op.timeout = timeout; + op.function = pt_solaris_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + } + +done: + if (count == -1) { + pt_MapError(_MD_solaris_map_sendfile_error, syserrno); + return -1; + } + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == nbytes_to_send); + return count; +} + +#ifndef HAVE_SENDFILEV +static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT; + +static void pt_solaris_sendfilev_init_routine(void) +{ + void *handle; + PRBool close_it = PR_FALSE; + + /* + * We do not want to unload libsendfile.so. This handle is leaked + * intentionally. + */ + handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlopen(libsendfile.so) returns %p", handle)); + + if (NULL == handle) { + /* + * The dlopen(0, mode) call is to allow for the possibility that + * sendfilev() may become part of a standard system library in a + * future Solaris release. + */ + handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlopen(0) returns %p", handle)); + close_it = PR_TRUE; + } + pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev"); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, + ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr)); + + if (close_it) { + dlclose(handle); + } +} + +/* + * pt_SolarisDispatchSendFile + */ +static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + int rv; + + rv = pthread_once(&pt_solaris_sendfilev_once_block, + pt_solaris_sendfilev_init_routine); + PR_ASSERT(0 == rv); + if (pt_solaris_sendfilev_fptr) { + return pt_SolarisSendFile(sd, sfd, flags, timeout); + } else { + return PR_EmulateSendFile(sd, sfd, flags, timeout); + } +} +#endif /* !HAVE_SENDFILEV */ + +#endif /* SOLARIS */ + +#ifdef LINUX +/* + * pt_LinuxSendFile + * + * Send file sfd->fd across socket sd. If specified, header and trailer + * buffers are sent before and after the file, respectively. + * + * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file + * + * return number of bytes sent or -1 on error + * + * This implementation takes advantage of the sendfile() system + * call available in Linux kernel 2.2 or higher. + */ + +static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + struct stat statbuf; + size_t file_nbytes_to_send; + PRInt32 count = 0; + ssize_t rv; + int syserrno; + off_t offset; + PRBool tcp_cork_enabled = PR_FALSE; + int tcp_cork; + + if (sfd->file_nbytes == 0) { + /* Get file size */ + if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) { + _PR_MD_MAP_FSTAT_ERROR(errno); + return -1; + } + file_nbytes_to_send = statbuf.st_size - sfd->file_offset; + } else { + file_nbytes_to_send = sfd->file_nbytes; + } + + if ((sfd->hlen != 0 || sfd->tlen != 0) + && sd->secret->md.tcp_nodelay == 0) { + tcp_cork = 1; + if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, + &tcp_cork, sizeof tcp_cork) == 0) { + tcp_cork_enabled = PR_TRUE; + } else { + syserrno = errno; + if (syserrno != EINVAL) { + _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno); + return -1; + } + /* + * The most likely reason for the EINVAL error is that + * TCP_NODELAY is set (with a function other than + * PR_SetSocketOption). This is not fatal, so we keep + * on going. + */ + PR_LOG(_pr_io_lm, PR_LOG_WARNING, + ("pt_LinuxSendFile: " + "setsockopt(TCP_CORK) failed with EINVAL\n")); + } + } + + if (sfd->hlen != 0) { + count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout); + if (count == -1) { + goto failed; + } + } + + if (file_nbytes_to_send != 0) { + offset = sfd->file_offset; + do { + rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, + &offset, file_nbytes_to_send); + } while (rv == -1 && (syserrno = errno) == EINTR); + if (rv == -1) { + if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) { + _MD_linux_map_sendfile_error(syserrno); + count = -1; + goto failed; + } + rv = 0; + } + PR_ASSERT(rv == offset - sfd->file_offset); + count += rv; + + if (rv < file_nbytes_to_send) { + pt_Continuation op; + + op.arg1.osfd = sd->secret->md.osfd; + op.in_fd = sfd->fd->secret->md.osfd; + op.offset = offset; + op.count = file_nbytes_to_send - rv; + op.result.code = count; + op.timeout = timeout; + op.function = pt_linux_sendfile_cont; + op.event = POLLOUT | POLLPRI; + count = pt_Continue(&op); + syserrno = op.syserrno; + if (count == -1) { + pt_MapError(_MD_linux_map_sendfile_error, syserrno); + goto failed; + } + } + } + + if (sfd->tlen != 0) { + rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); + if (rv == -1) { + count = -1; + goto failed; + } + count += rv; + } + +failed: + if (tcp_cork_enabled) { + tcp_cork = 0; + if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, + &tcp_cork, sizeof tcp_cork) == -1 && count != -1) { + _PR_MD_MAP_SETSOCKOPT_ERROR(errno); + count = -1; + } + } + if (count != -1) { + if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) { + PR_Close(sd); + } + PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send); + } + return count; +} +#endif /* LINUX */ + +#ifdef AIX +extern int _pr_aix_send_file_use_disabled; +#endif + +static PRInt32 pt_SendFile( + PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + if (pt_TestAbort()) return -1; + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return -1; + } +#ifdef HPUX11 + return(pt_HPUXSendFile(sd, sfd, flags, timeout)); +#elif defined(AIX) +#ifdef HAVE_SEND_FILE + /* + * A bug in AIX 4.3.2 results in corruption of data transferred by + * send_file(); AIX patch PTF U463956 contains the fix. A user can + * disable the use of send_file function in NSPR, when this patch is + * not installed on the system, by setting the envionment variable + * NSPR_AIX_SEND_FILE_USE_DISABLED to 1. + */ + if (_pr_aix_send_file_use_disabled) + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); + else + return(pt_AIXSendFile(sd, sfd, flags, timeout)); +#else + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); + /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/ +#endif /* HAVE_SEND_FILE */ +#elif defined(SOLARIS) +#ifdef HAVE_SENDFILEV + return(pt_SolarisSendFile(sd, sfd, flags, timeout)); +#else + return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout)); +#endif /* HAVE_SENDFILEV */ +#elif defined(LINUX) + return(pt_LinuxSendFile(sd, sfd, flags, timeout)); +#else + return(PR_EmulateSendFile(sd, sfd, flags, timeout)); +#endif +} + +static PRInt32 pt_TransmitFile( + PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + + return(pt_SendFile(sd, &sfd, flags, timeout)); +} /* pt_TransmitFile */ + +static PRInt32 pt_AcceptRead( + PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, + void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + PRInt32 rv = -1; + + if (pt_TestAbort()) return rv; + /* The socket must be in blocking mode. */ + if (sd->secret->nonblocking) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return rv; + } + + rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); + return rv; +} /* pt_AcceptRead */ + +static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRIntn rv = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = getsockname( + fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + if (rv == -1) { + pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno); + return PR_FAILURE; + } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); + return PR_SUCCESS; + } +} /* pt_GetSockName */ + +static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr) +{ + PRIntn rv = -1; + pt_SockLen addr_len = sizeof(PRNetAddr); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = getpeername( + fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno); + return PR_FAILURE; + } else { +#ifdef _PR_HAVE_SOCKADDR_LEN + /* ignore the sa_len field of struct sockaddr */ + if (addr) + { + addr->raw.family = ((struct sockaddr*)addr)->sa_family; + } +#endif /* _PR_HAVE_SOCKADDR_LEN */ +#ifdef _PR_INET6 + if (AF_INET6 == addr->raw.family) + addr->raw.family = PR_AF_INET6; +#endif + PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); + PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE); + return PR_SUCCESS; + } +} /* pt_GetPeerName */ + +static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) +{ + PRIntn rv; + pt_SockLen length; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a getsockopt() call + */ + if (PR_SockOpt_Nonblocking == data->option) + { + data->value.non_blocking = fd->secret->nonblocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { + struct linger linger; + length = sizeof(linger); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char *) &linger, &length); + PR_ASSERT((-1 == rv) || (sizeof(linger) == length)); + data->value.linger.polarity = + (linger.l_onoff) ? PR_TRUE : PR_FALSE; + data->value.linger.linger = + PR_SecondsToInterval(linger.l_linger); + break; + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { + PRIntn value; + length = sizeof(PRIntn); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&value, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_McastLoopback: + { + PRUint8 xbool; + length = sizeof(xbool); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&xbool, &length); + PR_ASSERT((-1 == rv) || (sizeof(xbool) == length)); + data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE; + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value; + length = sizeof(PRIntn); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&value, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + data->value.recv_buffer_size = value; + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + length = sizeof(PRUintn); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.ip_ttl, &length); + PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length)); + break; + } + case PR_SockOpt_McastTimeToLive: + { + PRUint8 ttl; + length = sizeof(ttl); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&ttl, &length); + PR_ASSERT((-1 == rv) || (sizeof(ttl) == length)); + data->value.mcast_ttl = ttl; + break; + } + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + length = sizeof(mreq); + rv = getsockopt( + fd->secret->md.osfd, level, name, (char*)&mreq, &length); + PR_ASSERT((-1 == rv) || (sizeof(mreq) == length)); + data->value.add_member.mcaddr.inet.ip = + mreq.imr_multiaddr.s_addr; + data->value.add_member.ifaddr.inet.ip = + mreq.imr_interface.s_addr; + break; + } + case PR_SockOpt_McastInterface: + { + length = sizeof(data->value.mcast_if.inet.ip); + rv = getsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.mcast_if.inet.ip, &length); + PR_ASSERT((-1 == rv) + || (sizeof(data->value.mcast_if.inet.ip) == length)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno); + } + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_GetSocketOption */ + +static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data) +{ + PRIntn rv; + PRInt32 level, name; + + /* + * PR_SockOpt_Nonblocking is a special case that does not + * translate to a setsockopt call. + */ + if (PR_SockOpt_Nonblocking == data->option) + { + fd->secret->nonblocking = data->value.non_blocking; + return PR_SUCCESS; + } + + rv = _PR_MapOptionName(data->option, &level, &name); + if (PR_SUCCESS == rv) + { + switch (data->option) + { + case PR_SockOpt_Linger: + { + struct linger linger; + linger.l_onoff = data->value.linger.polarity; + linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); + rv = setsockopt( + fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger)); + break; + } + case PR_SockOpt_Reuseaddr: + case PR_SockOpt_Keepalive: + case PR_SockOpt_NoDelay: + case PR_SockOpt_Broadcast: + { + PRIntn value = (data->value.reuse_addr) ? 1 : 0; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&value, sizeof(PRIntn)); +#ifdef LINUX + /* for pt_LinuxSendFile */ + if (name == TCP_NODELAY && rv == 0) { + fd->secret->md.tcp_nodelay = value; + } +#endif + break; + } + case PR_SockOpt_McastLoopback: + { + PRUint8 xbool = data->value.mcast_loopback ? 1 : 0; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&xbool, sizeof(xbool)); + break; + } + case PR_SockOpt_RecvBufferSize: + case PR_SockOpt_SendBufferSize: + case PR_SockOpt_MaxSegment: + { + PRIntn value = data->value.recv_buffer_size; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&value, sizeof(PRIntn)); + break; + } + case PR_SockOpt_IpTimeToLive: + case PR_SockOpt_IpTypeOfService: + { + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.ip_ttl, sizeof(PRUintn)); + break; + } + case PR_SockOpt_McastTimeToLive: + { + PRUint8 ttl = data->value.mcast_ttl; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&ttl, sizeof(ttl)); + break; + } + case PR_SockOpt_AddMember: + case PR_SockOpt_DropMember: + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = + data->value.add_member.mcaddr.inet.ip; + mreq.imr_interface.s_addr = + data->value.add_member.ifaddr.inet.ip; + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&mreq, sizeof(mreq)); + break; + } + case PR_SockOpt_McastInterface: + { + rv = setsockopt( + fd->secret->md.osfd, level, name, + (char*)&data->value.mcast_if.inet.ip, + sizeof(data->value.mcast_if.inet.ip)); + break; + } + default: + PR_NOT_REACHED("Unknown socket option"); + break; + } + if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno); + } + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* pt_SetSocketOption */ + +/*****************************************************************************/ +/****************************** I/O method objects ***************************/ +/*****************************************************************************/ + +static PRIOMethods _pr_file_methods = { + PR_DESC_FILE, + pt_Close, + pt_Read, + pt_Write, + pt_Available_f, + pt_Available64_f, + pt_Fsync, + pt_Seek, + pt_Seek64, + pt_FileInfo, + pt_FileInfo64, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_pipe_methods = { + PR_DESC_PIPE, + pt_Close, + pt_Read, + pt_Write, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_tcp_methods = { + PR_DESC_SOCKET_TCP, + pt_Close, + pt_SocketRead, + pt_SocketWrite, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + pt_Writev, + pt_Connect, + pt_Accept, + pt_Bind, + pt_Listen, + pt_Shutdown, + pt_Recv, + pt_Send, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + pt_Poll, + pt_AcceptRead, + pt_TransmitFile, + pt_GetSockName, + pt_GetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pt_GetSocketOption, + pt_SetSocketOption, + pt_SendFile, + pt_ConnectContinue, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_udp_methods = { + PR_DESC_SOCKET_UDP, + pt_Close, + pt_SocketRead, + pt_SocketWrite, + pt_Available_s, + pt_Available64_s, + pt_Synch, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + pt_Writev, + pt_Connect, + (PRAcceptFN)_PR_InvalidDesc, + pt_Bind, + pt_Listen, + pt_Shutdown, + pt_Recv, + pt_Send, + pt_RecvFrom, + pt_SendTo, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + pt_GetSockName, + pt_GetPeerName, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + pt_GetSocketOption, + pt_SetSocketOption, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +static PRIOMethods _pr_socketpollfd_methods = { + (PRDescType) 0, + (PRCloseFN)_PR_InvalidStatus, + (PRReadFN)_PR_InvalidInt, + (PRWriteFN)_PR_InvalidInt, + (PRAvailableFN)_PR_InvalidInt, + (PRAvailable64FN)_PR_InvalidInt64, + (PRFsyncFN)_PR_InvalidStatus, + (PRSeekFN)_PR_InvalidInt, + (PRSeek64FN)_PR_InvalidInt64, + (PRFileInfoFN)_PR_InvalidStatus, + (PRFileInfo64FN)_PR_InvalidStatus, + (PRWritevFN)_PR_InvalidInt, + (PRConnectFN)_PR_InvalidStatus, + (PRAcceptFN)_PR_InvalidDesc, + (PRBindFN)_PR_InvalidStatus, + (PRListenFN)_PR_InvalidStatus, + (PRShutdownFN)_PR_InvalidStatus, + (PRRecvFN)_PR_InvalidInt, + (PRSendFN)_PR_InvalidInt, + (PRRecvfromFN)_PR_InvalidInt, + (PRSendtoFN)_PR_InvalidInt, + pt_Poll, + (PRAcceptreadFN)_PR_InvalidInt, + (PRTransmitfileFN)_PR_InvalidInt, + (PRGetsocknameFN)_PR_InvalidStatus, + (PRGetpeernameFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRGetsocketoptionFN)_PR_InvalidStatus, + (PRSetsocketoptionFN)_PR_InvalidStatus, + (PRSendfileFN)_PR_InvalidInt, + (PRConnectcontinueFN)_PR_InvalidStatus, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt, + (PRReservedFN)_PR_InvalidInt +}; + +#if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \ + || defined(AIX) || defined(LINUX) || defined(FREEBSD) || defined(NETBSD) \ + || defined(OPENBSD) || defined(BSDI) || defined(VMS) || defined(NTO) \ + || defined(DARWIN) || defined(UNIXWARE) +#define _PR_FCNTL_FLAGS O_NONBLOCK +#else +#error "Can't determine architecture" +#endif + +/* + * Put a Unix file descriptor in non-blocking mode. + */ +static void pt_MakeFdNonblock(PRIntn osfd) +{ + PRIntn flags; + flags = fcntl(osfd, F_GETFL, 0); + flags |= _PR_FCNTL_FLAGS; + (void)fcntl(osfd, F_SETFL, flags); +} + +/* + * Put a Unix socket fd in non-blocking mode that can + * ideally be inherited by an accepted socket. + * + * Why doesn't pt_MakeFdNonblock do? This is to deal with + * the special case of HP-UX. HP-UX has three kinds of + * non-blocking modes for sockets: the fcntl() O_NONBLOCK + * and O_NDELAY flags and ioctl() FIOSNBIO request. Only + * the ioctl() FIOSNBIO form of non-blocking mode is + * inherited by an accepted socket. + * + * Other platforms just use the generic pt_MakeFdNonblock + * to put a socket in non-blocking mode. + */ +#ifdef HPUX +static void pt_MakeSocketNonblock(PRIntn osfd) +{ + PRIntn one = 1; + (void)ioctl(osfd, FIOSNBIO, &one); +} +#else +#define pt_MakeSocketNonblock pt_MakeFdNonblock +#endif + +static PRFileDesc *pt_SetMethods( + PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported) +{ + PRFileDesc *fd = _PR_Getfd(); + + if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->secret->md.osfd = osfd; + fd->secret->state = _PR_FILEDESC_OPEN; + if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN; + else + { + /* By default, a Unix fd is not closed on exec. */ + PRIntn flags; + flags = fcntl(osfd, F_GETFD, 0); + fd->secret->inheritable = flags & FD_CLOEXEC ? _PR_TRI_FALSE : _PR_TRI_TRUE; + } + switch (type) + { + case PR_DESC_FILE: + fd->methods = PR_GetFileMethods(); + break; + case PR_DESC_SOCKET_TCP: + fd->methods = PR_GetTCPMethods(); +#ifdef _PR_ACCEPT_INHERIT_NONBLOCK + if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd); +#else + pt_MakeSocketNonblock(osfd); +#endif + break; + case PR_DESC_SOCKET_UDP: + fd->methods = PR_GetUDPMethods(); + pt_MakeFdNonblock(osfd); + break; + case PR_DESC_PIPE: + fd->methods = PR_GetPipeMethods(); + pt_MakeFdNonblock(osfd); + break; + default: + break; + } + } + return fd; +} /* pt_SetMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) +{ + return &_pr_file_methods; +} /* PR_GetFileMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) +{ + return &_pr_pipe_methods; +} /* PR_GetPipeMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void) +{ + return &_pr_tcp_methods; +} /* PR_GetTCPMethods */ + +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void) +{ + return &_pr_udp_methods; +} /* PR_GetUDPMethods */ + +static const PRIOMethods* PR_GetSocketPollFdMethods(void) +{ + return &_pr_socketpollfd_methods; +} /* PR_GetSocketPollFdMethods */ + +PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc( + PRInt32 osfd, const PRIOMethods *methods) +{ + PRFileDesc *fd = _PR_Getfd(); + + if (NULL == fd) goto failed; + + fd->methods = methods; + fd->secret->md.osfd = osfd; + /* Make fd non-blocking */ + if (osfd > 2) + { + /* Don't mess around with stdin, stdout or stderr */ + if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd); + else pt_MakeFdNonblock(osfd); + } + fd->secret->state = _PR_FILEDESC_OPEN; + fd->secret->inheritable = _PR_TRI_UNKNOWN; + return fd; + +failed: + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return fd; +} /* PR_AllocFileDesc */ + +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd); +#if defined(_PR_INET6_PROBE) +PR_EXTERN(PRBool) _pr_ipv6_is_present; +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() +{ +PRInt32 osfd; + +#if defined(DARWIN) + /* + * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3). IPv6 on + * lesser versions is not ready for general use (see bug 222031). + */ + { + struct utsname u; + if (uname(&u) != 0 || atoi(u.release) < 7) + return PR_FALSE; + } +#endif + + /* + * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001) + * suggests that we call open("/dev/ip6", O_RDWR) to determine + * whether IPv6 APIs and the IPv6 stack are on the system. + * Our portable test below seems to work fine, so I am using it. + */ + osfd = socket(AF_INET6, SOCK_STREAM, 0); + if (osfd != -1) { + close(osfd); + return PR_TRUE; + } + return PR_FALSE; +} +#endif /* _PR_INET6_PROBE */ +#endif + +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) +{ + PRIntn osfd; + PRDescType ftype; + PRFileDesc *fd = NULL; + PRInt32 tmp_domain = domain; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return NULL; + + if (PF_INET != domain + && PR_AF_INET6 != domain + && PF_UNIX != domain) + { + PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return fd; + } + if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP; + else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP; + else + { + (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); + return fd; + } +#if defined(_PR_INET6_PROBE) + if (PR_AF_INET6 == domain) { + if (_pr_ipv6_is_present == PR_FALSE) + domain = AF_INET; + else + domain = AF_INET6; + } +#elif defined(_PR_INET6) + if (PR_AF_INET6 == domain) + domain = AF_INET6; +#else + if (PR_AF_INET6 == domain) + domain = AF_INET; +#endif + + osfd = socket(domain, type, proto); + if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno); + else + { +#ifdef DARWIN + if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default) + { + int on = 0; + (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, + &on, sizeof(on)); + } +#endif + fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE); + if (fd == NULL) close(osfd); + } +#ifdef _PR_STRICT_ADDR_LEN + if (fd != NULL) fd->secret->af = domain; +#endif +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) + if (fd != NULL) { + /* + * For platforms with no support for IPv6 + * create layered socket for IPv4-mapped IPv6 addresses + */ + if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { + if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { + PR_Close(fd); + fd = NULL; + } + } + } +#endif + return fd; +} /* PR_Socket */ + +/*****************************************************************************/ +/****************************** I/O public methods ***************************/ +/*****************************************************************************/ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenFile( + const char *name, PRIntn flags, PRIntn mode) +{ + PRFileDesc *fd = NULL; + PRIntn syserrno, osfd = -1, osflags = 0;; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return NULL; + + if (flags & PR_RDONLY) osflags |= O_RDONLY; + if (flags & PR_WRONLY) osflags |= O_WRONLY; + if (flags & PR_RDWR) osflags |= O_RDWR; + if (flags & PR_APPEND) osflags |= O_APPEND; + if (flags & PR_TRUNCATE) osflags |= O_TRUNC; + if (flags & PR_EXCL) osflags |= O_EXCL; + if (flags & PR_SYNC) + { +#if defined(O_SYNC) + osflags |= O_SYNC; +#elif defined(O_FSYNC) + osflags |= O_FSYNC; +#else +#error "Neither O_SYNC nor O_FSYNC is defined on this platform" +#endif + } + + /* + ** We have to hold the lock across the creation in order to + ** enforce the sematics of PR_Rename(). (see the latter for + ** more details) + */ + if (flags & PR_CREATE_FILE) + { + osflags |= O_CREAT; + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + } + + osfd = _md_iovector._open64(name, osflags, mode); + syserrno = errno; + + if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock)) + PR_Unlock(_pr_rename_lock); + + if (osfd == -1) + pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno); + else + { + fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE); + if (fd == NULL) close(osfd); /* $$$ whoops! this is bad $$$ */ + } + return fd; +} /* PR_OpenFile */ + +PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode) +{ + return PR_OpenFile(name, flags, mode); +} /* PR_Open */ + +PR_IMPLEMENT(PRStatus) PR_Delete(const char *name) +{ + PRIntn rv = -1; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (pt_TestAbort()) return PR_FAILURE; + + rv = unlink(name); + + if (rv == -1) { + pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno); + return PR_FAILURE; + } else + return PR_SUCCESS; +} /* PR_Delete */ + +PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how) +{ + PRIntn rv; + + if (pt_TestAbort()) return PR_FAILURE; + + switch (how) + { + case PR_ACCESS_READ_OK: + rv = access(name, R_OK); + break; + case PR_ACCESS_WRITE_OK: + rv = access(name, W_OK); + break; + case PR_ACCESS_EXISTS: + default: + rv = access(name, F_OK); + } + if (0 == rv) return PR_SUCCESS; + pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno); + return PR_FAILURE; + +} /* PR_Access */ + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info) +{ + PRInt32 rv = _PR_MD_GETFILEINFO(fn, info); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_GetFileInfo */ + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info) +{ + PRInt32 rv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + rv = _PR_MD_GETFILEINFO64(fn, info); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_GetFileInfo64 */ + +PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to) +{ + PRIntn rv = -1; + + if (pt_TestAbort()) return PR_FAILURE; + + /* + ** We have to acquire a lock here to stiffle anybody trying to create + ** a new file at the same time. And we have to hold that lock while we + ** test to see if the file exists and do the rename. The other place + ** where the lock is held is in PR_Open() when possibly creating a + ** new file. + */ + + PR_Lock(_pr_rename_lock); + rv = access(to, F_OK); + if (0 == rv) + { + PR_SetError(PR_FILE_EXISTS_ERROR, 0); + rv = -1; + } + else + { + rv = rename(from, to); + if (rv == -1) + pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno); + } + PR_Unlock(_pr_rename_lock); + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* PR_Rename */ + +PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir) +{ + if (pt_TestAbort()) return PR_FAILURE; + + if (NULL != dir->md.d) + { + if (closedir(dir->md.d) == -1) + { + _PR_MD_MAP_CLOSEDIR_ERROR(errno); + return PR_FAILURE; + } + dir->md.d = NULL; + PR_DELETE(dir); + } + return PR_SUCCESS; +} /* PR_CloseDir */ + +PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode) +{ + PRInt32 rv = -1; + + if (pt_TestAbort()) return PR_FAILURE; + + /* + ** This lock is used to enforce rename semantics as described + ** in PR_Rename. + */ + if (NULL !=_pr_rename_lock) + PR_Lock(_pr_rename_lock); + rv = mkdir(name, mode); + if (-1 == rv) + pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno); + if (NULL !=_pr_rename_lock) + PR_Unlock(_pr_rename_lock); + + return (-1 == rv) ? PR_FAILURE : PR_SUCCESS; +} /* PR_Makedir */ + +PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode) +{ + return PR_MakeDir(name, mode); +} /* PR_Mkdir */ + +PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name) +{ + PRInt32 rv; + + if (pt_TestAbort()) return PR_FAILURE; + + rv = rmdir(name); + if (0 == rv) { + return PR_SUCCESS; + } else { + pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno); + return PR_FAILURE; + } +} /* PR_Rmdir */ + + +PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name) +{ + DIR *osdir; + PRDir *dir = NULL; + + if (pt_TestAbort()) return dir; + + osdir = opendir(name); + if (osdir == NULL) + pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno); + else + { + dir = PR_NEWZAP(PRDir); + dir->md.d = osdir; + } + return dir; +} /* PR_OpenDir */ + +static PRInt32 _pr_poll_with_poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 ready = 0; + /* + * For restarting poll() if it is interrupted by a signal. + * We use these variables to figure out how much time has + * elapsed and how much of the timeout still remains. + */ + PRIntervalTime start, elapsed, remaining; + + if (pt_TestAbort()) return -1; + + if (0 == npds) PR_Sleep(timeout); + else + { +#define STACK_POLL_DESC_COUNT 64 + struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT]; + struct pollfd *syspoll; + PRIntn index, msecs; + + if (npds <= STACK_POLL_DESC_COUNT) + { + syspoll = stack_syspoll; + } + else + { + PRThread *me = PR_GetCurrentThread(); + if (npds > me->syspoll_count) + { + PR_Free(me->syspoll_list); + me->syspoll_list = + (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); + if (NULL == me->syspoll_list) + { + me->syspoll_count = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + me->syspoll_count = npds; + } + syspoll = me->syspoll_list; + } + + for (index = 0; index < npds; ++index) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (pds[index].in_flags & PR_POLL_READ) + { + in_flags_read = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_WRITE, + &out_flags_read); + } + if (pds[index].in_flags & PR_POLL_WRITE) + { + in_flags_write = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_READ, + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one is ready right now */ + if (0 == ready) + { + /* + * We will return without calling the system + * poll function. So zero the out_flags + * fields of all the poll descriptors before + * this one. + */ + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; + pds[index].out_flags = out_flags_read | out_flags_write; + } + else + { + /* now locate the NSPR layer at the bottom of the stack */ + PRFileDesc *bottom = PR_GetIdentitiesLayer( + pds[index].fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + pds[index].out_flags = 0; /* pre-condition */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + syspoll[index].fd = bottom->secret->md.osfd; + syspoll[index].events = 0; + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + syspoll[index].events |= POLLIN; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + syspoll[index].events |= POLLOUT; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + syspoll[index].events |= POLLPRI; + } + } + else + { + if (0 == ready) + { + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pds[index].out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + /* make poll() ignore this entry */ + syspoll[index].fd = -1; + syspoll[index].events = 0; + pds[index].out_flags = 0; + } + } + if (0 == ready) + { + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: msecs = 0; break; + case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; + default: + msecs = PR_IntervalToMilliseconds(timeout); + start = PR_IntervalNow(); + } + +retry: + ready = poll(syspoll, npds, msecs); + if (-1 == ready) + { + PRIntn oserror = errno; + + if (EINTR == oserror) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) + goto retry; + else if (timeout == PR_INTERVAL_NO_WAIT) + ready = 0; /* don't retry, just time out */ + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() + - start); + if (elapsed > timeout) + ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + msecs = PR_IntervalToMilliseconds(remaining); + goto retry; + } + } + } + else + { + _PR_MD_MAP_POLL_ERROR(oserror); + } + } + else if (ready > 0) + { + for (index = 0; index < npds; ++index) + { + PRInt16 out_flags = 0; + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (0 != syspoll[index].revents) + { + if (syspoll[index].revents & POLLIN) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_READ) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_READ) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLOUT) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_WRITE) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_WRITE) + { + out_flags |= PR_POLL_WRITE; + } + } + if (syspoll[index].revents & POLLPRI) + out_flags |= PR_POLL_EXCEPT; + if (syspoll[index].revents & POLLERR) + out_flags |= PR_POLL_ERR; + if (syspoll[index].revents & POLLNVAL) + out_flags |= PR_POLL_NVAL; + if (syspoll[index].revents & POLLHUP) + out_flags |= PR_POLL_HUP; + } + } + pds[index].out_flags = out_flags; + } + } + } + } + return ready; + +} /* _pr_poll_with_poll */ + +#if defined(_PR_POLL_WITH_SELECT) +/* + * OSF1 and HPUX report the POLLHUP event for a socket when the + * shutdown(SHUT_WR) operation is called for the remote end, even though + * the socket is still writeable. Use select(), instead of poll(), to + * workaround this problem. + */ +static PRInt32 _pr_poll_with_select( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ + PRInt32 ready = 0; + /* + * For restarting select() if it is interrupted by a signal. + * We use these variables to figure out how much time has + * elapsed and how much of the timeout still remains. + */ + PRIntervalTime start, elapsed, remaining; + + if (pt_TestAbort()) return -1; + + if (0 == npds) PR_Sleep(timeout); + else + { +#define STACK_POLL_DESC_COUNT 64 + int stack_selectfd[STACK_POLL_DESC_COUNT]; + int *selectfd; + fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL; + struct timeval tv, *tvp; + PRIntn index, msecs, maxfd = 0; + + if (npds <= STACK_POLL_DESC_COUNT) + { + selectfd = stack_selectfd; + } + else + { + PRThread *me = PR_GetCurrentThread(); + if (npds > me->selectfd_count) + { + PR_Free(me->selectfd_list); + me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int)); + if (NULL == me->selectfd_list) + { + me->selectfd_count = 0; + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return -1; + } + me->selectfd_count = npds; + } + selectfd = me->selectfd_list; + } + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + for (index = 0; index < npds; ++index) + { + PRInt16 in_flags_read = 0, in_flags_write = 0; + PRInt16 out_flags_read = 0, out_flags_write = 0; + + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (pds[index].in_flags & PR_POLL_READ) + { + in_flags_read = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_WRITE, + &out_flags_read); + } + if (pds[index].in_flags & PR_POLL_WRITE) + { + in_flags_write = (pds[index].fd->methods->poll)( + pds[index].fd, + pds[index].in_flags & ~PR_POLL_READ, + &out_flags_write); + } + if ((0 != (in_flags_read & out_flags_read)) + || (0 != (in_flags_write & out_flags_write))) + { + /* this one is ready right now */ + if (0 == ready) + { + /* + * We will return without calling the system + * poll function. So zero the out_flags + * fields of all the poll descriptors before + * this one. + */ + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; + pds[index].out_flags = out_flags_read | out_flags_write; + } + else + { + /* now locate the NSPR layer at the bottom of the stack */ + PRFileDesc *bottom = PR_GetIdentitiesLayer( + pds[index].fd, PR_NSPR_IO_LAYER); + PR_ASSERT(NULL != bottom); /* what to do about that? */ + pds[index].out_flags = 0; /* pre-condition */ + if ((NULL != bottom) + && (_PR_FILEDESC_OPEN == bottom->secret->state)) + { + if (0 == ready) + { + PRBool add_to_rd = PR_FALSE; + PRBool add_to_wr = PR_FALSE; + PRBool add_to_ex = PR_FALSE; + + selectfd[index] = bottom->secret->md.osfd; + if (in_flags_read & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_READ; + add_to_rd = PR_TRUE; + } + if (in_flags_read & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_READ_SYS_WRITE; + add_to_wr = PR_TRUE; + } + if (in_flags_write & PR_POLL_READ) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_READ; + add_to_rd = PR_TRUE; + } + if (in_flags_write & PR_POLL_WRITE) + { + pds[index].out_flags |= + _PR_POLL_WRITE_SYS_WRITE; + add_to_wr = PR_TRUE; + } + if (pds[index].in_flags & PR_POLL_EXCEPT) + { + add_to_ex = PR_TRUE; + } + if ((selectfd[index] > maxfd) && + (add_to_rd || add_to_wr || add_to_ex)) + { + maxfd = selectfd[index]; + /* + * If maxfd is too large to be used with + * select, fall back to calling poll. + */ + if (maxfd >= FD_SETSIZE) + break; + } + if (add_to_rd) + { + FD_SET(bottom->secret->md.osfd, &rd); + rdp = &rd; + } + if (add_to_wr) + { + FD_SET(bottom->secret->md.osfd, &wr); + wrp = ≀ + } + if (add_to_ex) + { + FD_SET(bottom->secret->md.osfd, &ex); + exp = &ex; + } + } + } + else + { + if (0 == ready) + { + int i; + for (i = 0; i < index; i++) + { + pds[i].out_flags = 0; + } + } + ready += 1; /* this will cause an abrupt return */ + pds[index].out_flags = PR_POLL_NVAL; /* bogii */ + } + } + } + else + { + pds[index].out_flags = 0; + } + } + if (0 == ready) + { + if (maxfd >= FD_SETSIZE) + { + /* + * maxfd too large to be used with select, fall back to + * calling poll + */ + return(_pr_poll_with_poll(pds, npds, timeout)); + } + switch (timeout) + { + case PR_INTERVAL_NO_WAIT: + tv.tv_sec = 0; + tv.tv_usec = 0; + tvp = &tv; + break; + case PR_INTERVAL_NO_TIMEOUT: + tvp = NULL; + break; + default: + msecs = PR_IntervalToMilliseconds(timeout); + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC; + tvp = &tv; + start = PR_IntervalNow(); + } + +retry: + ready = select(maxfd + 1, rdp, wrp, exp, tvp); + if (-1 == ready) + { + PRIntn oserror = errno; + + if ((EINTR == oserror) || (EAGAIN == oserror)) + { + if (timeout == PR_INTERVAL_NO_TIMEOUT) + goto retry; + else if (timeout == PR_INTERVAL_NO_WAIT) + ready = 0; /* don't retry, just time out */ + else + { + elapsed = (PRIntervalTime) (PR_IntervalNow() + - start); + if (elapsed > timeout) + ready = 0; /* timed out */ + else + { + remaining = timeout - elapsed; + msecs = PR_IntervalToMilliseconds(remaining); + tv.tv_sec = msecs/PR_MSEC_PER_SEC; + tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * + PR_USEC_PER_MSEC; + goto retry; + } + } + } else if (EBADF == oserror) + { + /* find all the bad fds */ + ready = 0; + for (index = 0; index < npds; ++index) + { + pds[index].out_flags = 0; + if ((NULL != pds[index].fd) && + (0 != pds[index].in_flags)) + { + if (fcntl(selectfd[index], F_GETFL, 0) == -1) + { + pds[index].out_flags = PR_POLL_NVAL; + ready++; + } + } + } + } else + _PR_MD_MAP_SELECT_ERROR(oserror); + } + else if (ready > 0) + { + for (index = 0; index < npds; ++index) + { + PRInt16 out_flags = 0; + if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) + { + if (FD_ISSET(selectfd[index], &rd)) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_READ) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_READ) + { + out_flags |= PR_POLL_WRITE; + } + } + if (FD_ISSET(selectfd[index], &wr)) + { + if (pds[index].out_flags + & _PR_POLL_READ_SYS_WRITE) + { + out_flags |= PR_POLL_READ; + } + if (pds[index].out_flags + & _PR_POLL_WRITE_SYS_WRITE) + { + out_flags |= PR_POLL_WRITE; + } + } + if (FD_ISSET(selectfd[index], &ex)) + out_flags |= PR_POLL_EXCEPT; + } + pds[index].out_flags = out_flags; + } + } + } + } + return ready; + +} /* _pr_poll_with_select */ +#endif /* _PR_POLL_WITH_SELECT */ + +PR_IMPLEMENT(PRInt32) PR_Poll( + PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) +{ +#if defined(_PR_POLL_WITH_SELECT) + return(_pr_poll_with_select(pds, npds, timeout)); +#else + return(_pr_poll_with_poll(pds, npds, timeout)); +#endif +} + +PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags) +{ + struct dirent *dp; + + if (pt_TestAbort()) return NULL; + + for (;;) + { + dp = readdir(dir->md.d); + if (NULL == dp) return NULL; + if ((flags & PR_SKIP_DOT) + && ('.' == dp->d_name[0]) + && (0 == dp->d_name[1])) continue; + if ((flags & PR_SKIP_DOT_DOT) + && ('.' == dp->d_name[0]) + && ('.' == dp->d_name[1]) + && (0 == dp->d_name[2])) continue; + if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0])) + continue; + break; + } + dir->d.name = dp->d_name; + return &dir->d; +} /* PR_ReadDir */ + +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) +{ + PRIntn domain = PF_INET; + + return PR_Socket(domain, SOCK_DGRAM, 0); +} /* PR_NewUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) +{ + PRIntn domain = PF_INET; + + return PR_Socket(domain, SOCK_STREAM, 0); +} /* PR_NewTCPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_DGRAM, 0); +} /* PR_NewUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) +{ + return PR_Socket(af, SOCK_STREAM, 0); +} /* PR_NewTCPSocket */ + +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2]) +{ + PRInt32 osfd[2]; + + if (pt_TestAbort()) return PR_FAILURE; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) { + pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno); + return PR_FAILURE; + } + + fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); + if (fds[0] == NULL) { + close(osfd[0]); + close(osfd[1]); + return PR_FAILURE; + } + fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE); + if (fds[1] == NULL) { + PR_Close(fds[0]); + close(osfd[1]); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* PR_NewTCPSocketPair */ + +PR_IMPLEMENT(PRStatus) PR_CreatePipe( + PRFileDesc **readPipe, + PRFileDesc **writePipe +) +{ + int pipefd[2]; + + if (pt_TestAbort()) return PR_FAILURE; + + if (pipe(pipefd) == -1) + { + /* XXX map pipe error */ + PR_SetError(PR_UNKNOWN_ERROR, errno); + return PR_FAILURE; + } + fcntl(pipefd[0], F_SETFD, FD_CLOEXEC); + fcntl(pipefd[1], F_SETFD, FD_CLOEXEC); + *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE); + if (NULL == *readPipe) + { + close(pipefd[0]); + close(pipefd[1]); + return PR_FAILURE; + } + *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE); + if (NULL == *writePipe) + { + PR_Close(*readPipe); + close(pipefd[1]); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* +** Set the inheritance attribute of a file descriptor. +*/ +PR_IMPLEMENT(PRStatus) PR_SetFDInheritable( + PRFileDesc *fd, + PRBool inheritable) +{ + /* + * Only a non-layered, NSPR file descriptor can be inherited + * by a child process. + */ + if (fd->identity != PR_NSPR_IO_LAYER) + { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return PR_FAILURE; + } + if (fd->secret->inheritable != inheritable) + { + if (fcntl(fd->secret->md.osfd, F_SETFD, + inheritable ? 0 : FD_CLOEXEC) == -1) + { + return PR_FAILURE; + } + fd->secret->inheritable = (_PRTriStateBool) inheritable; + } + return PR_SUCCESS; +} + +/*****************************************************************************/ +/***************************** I/O friends methods ***************************/ +/*****************************************************************************/ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); + return fd; +} /* PR_ImportFile */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); + return fd; +} /* PR_ImportPipe */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE); + if (NULL == fd) close(osfd); +#ifdef _PR_STRICT_ADDR_LEN + if (NULL != fd) fd->secret->af = PF_INET; +#endif + return fd; +} /* PR_ImportTCPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE); + if (NULL != fd) close(osfd); + return fd; +} /* PR_ImportUDPSocket */ + +PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd) +{ + PRFileDesc *fd; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + fd = _PR_Getfd(); + + if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + else + { + fd->secret->md.osfd = osfd; + fd->secret->inheritable = _PR_TRI_FALSE; + fd->secret->state = _PR_FILEDESC_OPEN; + fd->methods = PR_GetSocketPollFdMethods(); + } + + return fd; +} /* PR_CreateSocketPollFD */ + +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd) +{ + if (NULL == fd) + { + PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); + return PR_FAILURE; + } + fd->secret->state = _PR_FILEDESC_CLOSED; + _PR_Putfd(fd); + return PR_SUCCESS; +} /* PR_DestroySocketPollFd */ + +PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom) +{ + PRInt32 osfd = -1; + bottom = (NULL == bottom) ? + NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER); + if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + else osfd = bottom->secret->md.osfd; + return osfd; +} /* PR_FileDesc2NativeHandle */ + +PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd, + PRInt32 handle) +{ + if (fd) fd->secret->md.osfd = handle; +} /* PR_ChangeFileDescNativeHandle*/ + +PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + while (-1 == fd->secret->lockCount) + PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT); + if (0 == fd->secret->lockCount) + { + fd->secret->lockCount = -1; + PR_Unlock(_pr_flock_lock); + status = _PR_MD_LOCKFILE(fd->secret->md.osfd); + PR_Lock(_pr_flock_lock); + fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0; + PR_NotifyAllCondVar(_pr_flock_cv); + } + else + { + fd->secret->lockCount += 1; + } + PR_Unlock(_pr_flock_lock); + + return status; +} /* PR_LockFile */ + +PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + if (0 == fd->secret->lockCount) + { + status = _PR_MD_TLOCKFILE(fd->secret->md.osfd); + if (PR_SUCCESS == status) fd->secret->lockCount = 1; + } + else fd->secret->lockCount += 1; + PR_Unlock(_pr_flock_lock); + + return status; +} /* PR_TLockFile */ + +PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd) +{ + PRStatus status = PR_SUCCESS; + + if (pt_TestAbort()) return PR_FAILURE; + + PR_Lock(_pr_flock_lock); + if (fd->secret->lockCount == 1) + { + status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd); + if (PR_SUCCESS == status) fd->secret->lockCount = 0; + } + else fd->secret->lockCount -= 1; + PR_Unlock(_pr_flock_lock); + + return status; +} + +/* + * The next two entry points should not be in the API, but they are + * defined here for historical (or hysterical) reasons. + */ + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +static PRInt32 PR_GetSysfdTableMax(void) +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PRInt32 PR_GetSysfdTableMax(void) +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(VMS) + struct rlimit rlim; + + if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + + return rlim.rlim_max; +#elif defined(AIX) || defined(VMS) + return sysconf(_SC_OPEN_MAX); +#endif +} + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +static PRInt32 PR_SetSysfdTableSize(PRIntn table_size) +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +PRInt32 PR_SetSysfdTableSize(PRIntn table_size) +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ +{ +#if defined(XP_UNIX) && !defined(AIX) && !defined(VMS) + struct rlimit rlim; + PRInt32 tableMax = PR_GetSysfdTableMax(); + + if (tableMax < 0) return -1; + rlim.rlim_max = tableMax; + + /* Grow as much as we can; even if too big */ + if ( rlim.rlim_max < table_size ) + rlim.rlim_cur = rlim.rlim_max; + else + rlim.rlim_cur = table_size; + + if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + + return rlim.rlim_cur; +#elif defined(AIX) || defined(VMS) + return -1; +#endif +} + +/* + * PR_Stat is supported for backward compatibility; some existing Java + * code uses it. New code should use PR_GetFileInfo. + */ + +#ifndef NO_NSPR_10_SUPPORT +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo"); + + if (pt_TestAbort()) return -1; + + if (-1 == stat(name, buf)) { + pt_MapError(_PR_MD_MAP_STAT_ERROR, errno); + return -1; + } else { + return 0; + } +} +#endif /* ! NO_NSPR_10_SUPPORT */ + + +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll"); + memset(set, 0, sizeof(PR_fd_set)); +} + +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll"); + PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC ); + + set->harray[set->hsize++] = fh; +} + +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index, index2; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll"); + + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + for (index2=index; index2 < (set->hsize-1); index2++) { + set->harray[index2] = set->harray[index2+1]; + } + set->hsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set) +{ + PRUint32 index; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll"); + for (index = 0; indexhsize; index++) + if (set->harray[index] == fh) { + return 1; + } + return 0; +} + +PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll"); + PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC ); + + set->narray[set->nsize++] = fd; +} + +PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index, index2; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll"); + + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + for (index2=index; index2 < (set->nsize-1); index2++) { + set->narray[index2] = set->narray[index2+1]; + } + set->nsize--; + break; + } +} + +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set) +{ + PRUint32 index; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll"); + for (index = 0; indexnsize; index++) + if (set->narray[index] == fd) { + return 1; + } + return 0; +} + +#include +#include +#if !defined(SUNOS4) && !defined(HPUX) && !defined(LINUX) +#include +#endif + +static PRInt32 +_PR_getset(PR_fd_set *pr_set, fd_set *set) +{ + PRUint32 index; + PRInt32 max = 0; + + if (!pr_set) + return 0; + + FD_ZERO(set); + + /* First set the pr file handle osfds */ + for (index=0; indexhsize; index++) { + FD_SET(pr_set->harray[index]->secret->md.osfd, set); + if (pr_set->harray[index]->secret->md.osfd > max) + max = pr_set->harray[index]->secret->md.osfd; + } + /* Second set the native osfds */ + for (index=0; indexnsize; index++) { + FD_SET(pr_set->narray[index], set); + if (pr_set->narray[index] > max) + max = pr_set->narray[index]; + } + return max; +} + +static void +_PR_setset(PR_fd_set *pr_set, fd_set *set) +{ + PRUint32 index, last_used; + + if (!pr_set) + return; + + for (last_used=0, index=0; indexhsize; index++) { + if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) { + pr_set->harray[last_used++] = pr_set->harray[index]; + } + } + pr_set->hsize = last_used; + + for (last_used=0, index=0; indexnsize; index++) { + if ( FD_ISSET(pr_set->narray[index], set) ) { + pr_set->narray[last_used++] = pr_set->narray[index]; + } + } + pr_set->nsize = last_used; +} + +PR_IMPLEMENT(PRInt32) PR_Select( + PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, + PR_fd_set *pr_ex, PRIntervalTime timeout) +{ + fd_set rd, wr, ex; + struct timeval tv, *tvp; + PRInt32 max, max_fd; + PRInt32 rv; + /* + * For restarting select() if it is interrupted by a Unix signal. + * We use these variables to figure out how much time has elapsed + * and how much of the timeout still remains. + */ + PRIntervalTime start, elapsed, remaining; + + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll"); + + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + + max_fd = _PR_getset(pr_rd, &rd); + max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd; + max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + tvp = NULL; + } else { + tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout); + tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( + timeout - PR_SecondsToInterval(tv.tv_sec)); + tvp = &tv; + start = PR_IntervalNow(); + } + +retry: + rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd, + (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp); + + if (rv == -1 && errno == EINTR) { + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + goto retry; + } else { + elapsed = (PRIntervalTime) (PR_IntervalNow() - start); + if (elapsed > timeout) { + rv = 0; /* timed out */ + } else { + remaining = timeout - elapsed; + tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining); + tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds( + remaining - PR_SecondsToInterval(tv.tv_sec)); + goto retry; + } + } + } + + if (rv > 0) { + _PR_setset(pr_rd, &rd); + _PR_setset(pr_wr, &wr); + _PR_setset(pr_ex, &ex); + } else if (rv == -1) { + pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno); + } + return rv; +} +#endif /* defined(_PR_PTHREADS) */ + +#ifdef MOZ_UNICODE +/* ================ UTF16 Interfaces ================================ */ +PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16( + const PRUnichar *name, PRIntn flags, PRIntn mode) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} +/* ================ UTF16 Interfaces ================================ */ +#endif /* MOZ_UNICODE */ + +/* ptio.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptmisc.c b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptmisc.c new file mode 100644 index 00000000..920d00db --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptmisc.c @@ -0,0 +1,71 @@ +/* -*- 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 ***** */ + +/* +** File: ptmisc.c +** Descritpion: Implemenation of miscellaneous methods for pthreads +*/ + +#if defined(_PR_PTHREADS) + +#include "primpl.h" + +#include +#ifdef SOLARIS +#include +#endif + +#define PT_LOG(f) + +void _PR_InitCPUs(void) {PT_LOG("_PR_InitCPUs")} +void _PR_InitStacks(void) {PT_LOG("_PR_InitStacks")} + +PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) +{ +#ifdef SOLARIS + thr_setconcurrency(numCPUs); +#else + PT_LOG("PR_SetConcurrency"); +#endif +} + +PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 flag) + {PT_LOG("PR_SetThreadRecycleMode")} + +#endif /* defined(_PR_PTHREADS) */ + +/* ptmisc.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c new file mode 100644 index 00000000..50f756bc --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptsynch.c @@ -0,0 +1,1126 @@ +/* -*- 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 ***** */ + +/* +** File: ptsynch.c +** Descritpion: Implemenation for thread synchronization using pthreads +** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h +*/ + +#if defined(_PR_PTHREADS) + +#include "primpl.h" +#include "obsolete/prsem.h" + +#include +#include +#include + +static pthread_mutexattr_t _pt_mattr; +static pthread_condattr_t _pt_cvar_attr; + +#if defined(DEBUG) +extern PTDebug pt_debug; /* this is shared between several modules */ + +#if defined(_PR_DCETHREADS) +static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct + * in DCE threads) to compare with */ +#endif /* defined(_PR_DCETHREADS) */ +#endif /* defined(DEBUG) */ + +/**************************************************************/ +/**************************************************************/ +/*****************************LOCKS****************************/ +/**************************************************************/ +/**************************************************************/ + +void _PR_InitLocks(void) +{ + int rv; + rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); + PR_ASSERT(0 == rv); + +#ifdef LINUX +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) + rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP); + PR_ASSERT(0 == rv); +#endif +#endif + + rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); + PR_ASSERT(0 == rv); +} + +static void pt_PostNotifies(PRLock *lock, PRBool unlock) +{ + PRIntn index, rv; + _PT_Notified post; + _PT_Notified *notified, *prev = NULL; + /* + * Time to actually notify any conditions that were affected + * while the lock was held. Get a copy of the list that's in + * the lock structure and then zero the original. If it's + * linked to other such structures, we own that storage. + */ + post = lock->notified; /* a safe copy; we own the lock */ + +#if defined(DEBUG) + memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */ +#else + lock->notified.length = 0; /* these are really sufficient */ + lock->notified.link = NULL; +#endif + + /* should (may) we release lock before notifying? */ + if (unlock) + { + rv = pthread_mutex_unlock(&lock->mutex); + PR_ASSERT(0 == rv); + } + + notified = &post; /* this is where we start */ + do + { + for (index = 0; index < notified->length; ++index) + { + PRCondVar *cv = notified->cv[index].cv; + PR_ASSERT(NULL != cv); + PR_ASSERT(0 != notified->cv[index].times); + if (-1 == notified->cv[index].times) + { + rv = pthread_cond_broadcast(&cv->cv); + PR_ASSERT(0 == rv); + } + else + { + while (notified->cv[index].times-- > 0) + { + rv = pthread_cond_signal(&cv->cv); + PR_ASSERT(0 == rv); + } + } +#if defined(DEBUG) + pt_debug.cvars_notified += 1; + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + { + pt_debug.delayed_cv_deletes += 1; + PR_DestroyCondVar(cv); + } +#else /* defined(DEBUG) */ + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + PR_DestroyCondVar(cv); +#endif /* defined(DEBUG) */ + } + prev = notified; + notified = notified->link; + if (&post != prev) PR_DELETE(prev); + } while (NULL != notified); +} /* pt_PostNotifies */ + +PR_IMPLEMENT(PRLock*) PR_NewLock(void) +{ + PRIntn rv; + PRLock *lock; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock != NULL) + { + rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); + PR_ASSERT(0 == rv); + } +#if defined(DEBUG) + pt_debug.locks_created += 1; +#endif + return lock; +} /* PR_NewLock */ + +PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) +{ + PRIntn rv; + PR_ASSERT(NULL != lock); + PR_ASSERT(PR_FALSE == lock->locked); + PR_ASSERT(0 == lock->notified.length); + PR_ASSERT(NULL == lock->notified.link); + rv = pthread_mutex_destroy(&lock->mutex); + PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(lock, 0xaf, sizeof(PRLock)); + pt_debug.locks_destroyed += 1; +#endif + PR_DELETE(lock); +} /* PR_DestroyLock */ + +PR_IMPLEMENT(void) PR_Lock(PRLock *lock) +{ + PRIntn rv; + PR_ASSERT(lock != NULL); + rv = pthread_mutex_lock(&lock->mutex); + PR_ASSERT(0 == rv); + PR_ASSERT(0 == lock->notified.length); + PR_ASSERT(NULL == lock->notified.link); + PR_ASSERT(PR_FALSE == lock->locked); + lock->locked = PR_TRUE; + lock->owner = pthread_self(); +#if defined(DEBUG) + pt_debug.locks_acquired += 1; +#endif +} /* PR_Lock */ + +PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) +{ + PRIntn rv; + + PR_ASSERT(lock != NULL); + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); + PR_ASSERT(PR_TRUE == lock->locked); + PR_ASSERT(pthread_equal(lock->owner, pthread_self())); + + if (!lock->locked || !pthread_equal(lock->owner, pthread_self())) + return PR_FAILURE; + + lock->locked = PR_FALSE; + if (0 == lock->notified.length) /* shortcut */ + { + rv = pthread_mutex_unlock(&lock->mutex); + PR_ASSERT(0 == rv); + } + else pt_PostNotifies(lock, PR_TRUE); + +#if defined(DEBUG) + pt_debug.locks_released += 1; +#endif + return PR_SUCCESS; +} /* PR_Unlock */ + + +/**************************************************************/ +/**************************************************************/ +/***************************CONDITIONS*************************/ +/**************************************************************/ +/**************************************************************/ + + +/* + * This code is used to compute the absolute time for the wakeup. + * It's moderately ugly, so it's defined here and called in a + * couple of places. + */ +#define PT_NANOPERMICRO 1000UL +#define PT_BILLION 1000000000UL + +static PRIntn pt_TimedWait( + pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout) +{ + int rv; + struct timeval now; + struct timespec tmo; + PRUint32 ticks = PR_TicksPerSecond(); + + tmo.tv_sec = (PRInt32)(timeout / ticks); + tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks)); + tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec); + + /* pthreads wants this in absolute time, off we go ... */ + (void)GETTIMEOFDAY(&now); + /* that one's usecs, this one's nsecs - grrrr! */ + tmo.tv_sec += now.tv_sec; + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; + tmo.tv_nsec %= PT_BILLION; + + rv = pthread_cond_timedwait(cv, ml, &tmo); + + /* NSPR doesn't report timeouts */ +#ifdef _PR_DCETHREADS + if (rv == -1) return (errno == EAGAIN) ? 0 : errno; + else return rv; +#else + return (rv == ETIMEDOUT) ? 0 : rv; +#endif +} /* pt_TimedWait */ + + +/* + * Notifies just get posted to the protecting mutex. The + * actual notification is done when the lock is released so that + * MP systems don't contend for a lock that they can't have. + */ +static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast) +{ + PRIntn index = 0; + _PT_Notified *notified = &cvar->lock->notified; + + PR_ASSERT(PR_TRUE == cvar->lock->locked); + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); + + while (1) + { + for (index = 0; index < notified->length; ++index) + { + if (notified->cv[index].cv == cvar) + { + if (broadcast) + notified->cv[index].times = -1; + else if (-1 != notified->cv[index].times) + notified->cv[index].times += 1; + goto finished; /* we're finished */ + } + } + /* if not full, enter new CV in this array */ + if (notified->length < PT_CV_NOTIFIED_LENGTH) break; + + /* if there's no link, create an empty array and link it */ + if (NULL == notified->link) + notified->link = PR_NEWZAP(_PT_Notified); + notified = notified->link; + } + + /* A brand new entry in the array */ + (void)PR_AtomicIncrement(&cvar->notify_pending); + notified->cv[index].times = (broadcast) ? -1 : 1; + notified->cv[index].cv = cvar; + notified->length += 1; + +finished: + PR_ASSERT(PR_TRUE == cvar->lock->locked); + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); +} /* pt_PostNotifyToCvar */ + +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) +{ + PRCondVar *cv = PR_NEW(PRCondVar); + PR_ASSERT(lock != NULL); + if (cv != NULL) + { + int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + cv->lock = lock; + cv->notify_pending = 0; +#if defined(DEBUG) + pt_debug.cvars_created += 1; +#endif + } + return cv; +} /* PR_NewCondVar */ + +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) +{ + if (0 > PR_AtomicDecrement(&cvar->notify_pending)) + { + PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(cvar, 0xaf, sizeof(PRCondVar)); + pt_debug.cvars_destroyed += 1; +#endif + PR_DELETE(cvar); + } +} /* PR_DestroyCondVar */ + +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) +{ + PRIntn rv; + PRThread *thred = PR_CurrentThread(); + + PR_ASSERT(cvar != NULL); + /* We'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); + PR_ASSERT(PR_TRUE == cvar->lock->locked); + /* and it better be by us */ + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); + + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; + + /* + * The thread waiting is used for PR_Interrupt + */ + thred->waiting = cvar; /* this is where we're waiting */ + + /* + * If we have pending notifies, post them now. + * + * This is not optimal. We're going to post these notifies + * while we're holding the lock. That means on MP systems + * that they are going to collide for the lock that we will + * hold until we actually wait. + */ + if (0 != cvar->lock->notified.length) + pt_PostNotifies(cvar->lock, PR_FALSE); + + /* + * We're surrendering the lock, so clear out the locked field. + */ + cvar->lock->locked = PR_FALSE; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) + rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); + else + rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout); + + /* We just got the lock back - this better be empty */ + PR_ASSERT(PR_FALSE == cvar->lock->locked); + cvar->lock->locked = PR_TRUE; + cvar->lock->owner = pthread_self(); + + PR_ASSERT(0 == cvar->lock->notified.length); + thred->waiting = NULL; /* and now we're not */ + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; + if (rv != 0) + { + _PR_MD_MAP_DEFAULT_ERROR(rv); + return PR_FAILURE; + } + return PR_SUCCESS; + +aborted: + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thred->state &= ~PT_THREAD_ABORTED; + return PR_FAILURE; +} /* PR_WaitCondVar */ + +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar != NULL); + pt_PostNotifyToCvar(cvar, PR_FALSE); + return PR_SUCCESS; +} /* PR_NotifyCondVar */ + +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar != NULL); + pt_PostNotifyToCvar(cvar, PR_TRUE); + return PR_SUCCESS; +} /* PR_NotifyAllCondVar */ + +/**************************************************************/ +/**************************************************************/ +/***************************MONITORS***************************/ +/**************************************************************/ +/**************************************************************/ + +PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) +{ + PRMonitor *mon; + PRCondVar *cvar; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + cvar = PR_NEWZAP(PRCondVar); + if (NULL == cvar) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + mon = PR_NEWZAP(PRMonitor); + if (mon != NULL) + { + int rv; + rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); + PR_ASSERT(0 == rv); + + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); + + mon->cvar = cvar; + rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + mon->entryCount = 0; + mon->cvar->lock = &mon->lock; + if (0 != rv) + { + PR_DELETE(mon); + PR_DELETE(cvar); + mon = NULL; + } + } + return mon; +} /* PR_NewMonitor */ + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if (mon) + mon->name = name; + return mon; +} + +PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) +{ + int rv; + PR_ASSERT(mon != NULL); + PR_DestroyCondVar(mon->cvar); + rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(mon, 0xaf, sizeof(PRMonitor)); +#endif + PR_DELETE(mon); +} /* PR_DestroyMonitor */ + + +/* The GC uses this; it is quite arguably a bad interface. I'm just + * duplicating it for now - XXXMB + */ +PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + if (pthread_equal(mon->owner, self)) + return mon->entryCount; + return 0; +} + +PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + + PR_ASSERT(mon != NULL); + /* + * This is safe only if mon->owner (a pthread_t) can be + * read in one instruction. Perhaps mon->owner should be + * a "PRThread *"? + */ + if (!pthread_equal(mon->owner, self)) + { + PR_Lock(&mon->lock); + /* and now I have the lock */ + PR_ASSERT(0 == mon->entryCount); + PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); + _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); + } + mon->entryCount += 1; +} /* PR_EnterMonitor */ + +PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) +{ + pthread_t self = pthread_self(); + + PR_ASSERT(mon != NULL); + /* The lock better be that - locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* we'd better be the owner */ + PR_ASSERT(pthread_equal(mon->owner, self)); + if (!pthread_equal(mon->owner, self)) + return PR_FAILURE; + + /* if it's locked and we have it, then the entries should be > 0 */ + PR_ASSERT(mon->entryCount > 0); + mon->entryCount -= 1; /* reduce by one */ + if (mon->entryCount == 0) + { + /* and if it transitioned to zero - unlock */ + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknown */ + PR_Unlock(&mon->lock); + } + return PR_SUCCESS; +} /* PR_ExitMonitor */ + +PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) +{ + PRStatus rv; + PRInt16 saved_entries; + pthread_t saved_owner; + + PR_ASSERT(mon != NULL); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + /* tuck these away 'till later */ + saved_entries = mon->entryCount; + mon->entryCount = 0; + _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); + + rv = PR_WaitCondVar(mon->cvar, timeout); + + /* reinstate the intresting information */ + mon->entryCount = saved_entries; + _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); + + return rv; +} /* PR_Wait */ + +PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) +{ + PR_ASSERT(NULL != mon); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + pt_PostNotifyToCvar(mon->cvar, PR_FALSE); + + return PR_SUCCESS; +} /* PR_Notify */ + +PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) +{ + PR_ASSERT(mon != NULL); + /* we'd better be locked */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); + /* and the entries better be positive */ + PR_ASSERT(mon->entryCount > 0); + /* and it better be by us */ + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); + + pt_PostNotifyToCvar(mon->cvar, PR_TRUE); + + return PR_SUCCESS; +} /* PR_NotifyAll */ + +/**************************************************************/ +/**************************************************************/ +/**************************SEMAPHORES**************************/ +/**************************************************************/ +/**************************************************************/ +PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_PostSem", "locks & condition variables"); + PR_Lock(semaphore->cvar->lock); + PR_NotifyCondVar(semaphore->cvar); + semaphore->count += 1; + PR_Unlock(semaphore->cvar->lock); +} /* PR_PostSem */ + +PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore) +{ + PRStatus status = PR_SUCCESS; + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_WaitSem", "locks & condition variables"); + PR_Lock(semaphore->cvar->lock); + while ((semaphore->count == 0) && (PR_SUCCESS == status)) + status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == status) semaphore->count -= 1; + PR_Unlock(semaphore->cvar->lock); + return status; +} /* PR_WaitSem */ + +PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore) +{ + static PRBool unwarned = PR_TRUE; + if (unwarned) unwarned = _PR_Obsolete( + "PR_DestroySem", "locks & condition variables"); + PR_DestroyLock(semaphore->cvar->lock); + PR_DestroyCondVar(semaphore->cvar); + PR_DELETE(semaphore); +} /* PR_DestroySem */ + +PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) +{ + PRSemaphore *semaphore; + static PRBool unwarned = PR_TRUE; + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (unwarned) unwarned = _PR_Obsolete( + "PR_NewSem", "locks & condition variables"); + + semaphore = PR_NEWZAP(PRSemaphore); + if (NULL != semaphore) + { + PRLock *lock = PR_NewLock(); + if (NULL != lock) + { + semaphore->cvar = PR_NewCondVar(lock); + if (NULL != semaphore->cvar) + { + semaphore->count = value; + return semaphore; + } + PR_DestroyLock(lock); + } + PR_DELETE(semaphore); + } + return NULL; +} + +/* + * Define the interprocess named semaphore functions. + * There are three implementations: + * 1. POSIX semaphore based; + * 2. System V semaphore based; + * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR). + */ + +#ifdef _PR_HAVE_POSIX_SEMAPHORES +#include + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PRSem *sem; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return NULL; + } + + sem = PR_NEW(PRSem); + if (NULL == sem) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + if (flags & PR_SEM_CREATE) + { + int oflag = O_CREAT; + + if (flags & PR_SEM_EXCL) oflag |= O_EXCL; + sem->sem = sem_open(osname, oflag, mode, value); + } + else + { +#ifdef HPUX + /* Pass 0 as the mode and value arguments to work around a bug. */ + sem->sem = sem_open(osname, 0, 0, 0); +#else + sem->sem = sem_open(osname, 0); +#endif + } + if ((sem_t *) -1 == sem->sem) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + return sem; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + int rv; + rv = sem_wait(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + int rv; + rv = sem_post(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + int rv; + rv = sem_close(sem->sem); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + PR_DELETE(sem); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + int rv; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return PR_FAILURE; + } + rv = sem_unlink(osname); + if (0 != rv) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) + +#include +#include + +/* + * From the semctl(2) man page in glibc 2.0 + */ +#if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \ + || defined(OPENBSD) || defined(BSDI) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short *array; +}; +#endif + +/* + * 'a' (97) is the final closing price of NSCP stock. + */ +#define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */ + +#define NSPR_SEM_MODE 0666 + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PRSem *sem; + key_t key; + union semun arg; + struct sembuf sop; + struct semid_ds seminfo; +#define MAX_TRIES 60 + PRIntn i; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return NULL; + } + + /* Make sure the file exists before calling ftok. */ + if (flags & PR_SEM_CREATE) + { + int osfd = open(osname, O_RDWR|O_CREAT, mode); + if (-1 == osfd) + { + _PR_MD_MAP_OPEN_ERROR(errno); + return NULL; + } + if (close(osfd) == -1) + { + _PR_MD_MAP_CLOSE_ERROR(errno); + return NULL; + } + } + key = ftok(osname, NSPR_IPC_KEY_ID); + if ((key_t)-1 == key) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return NULL; + } + + sem = PR_NEW(PRSem); + if (NULL == sem) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + if (flags & PR_SEM_CREATE) + { + sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL); + if (sem->semid >= 0) + { + /* creator of a semaphore is responsible for initializing it */ + arg.val = 0; + if (semctl(sem->semid, 0, SETVAL, arg) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + /* call semop to set sem_otime to nonzero */ + sop.sem_num = 0; + sop.sem_op = value; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + return sem; + } + + if (errno != EEXIST || flags & PR_SEM_EXCL) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + } + + sem->semid = semget(key, 1, NSPR_SEM_MODE); + if (sem->semid == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + PR_DELETE(sem); + return NULL; + } + for (i = 0; i < MAX_TRIES; i++) + { + arg.buf = &seminfo; + semctl(sem->semid, 0, IPC_STAT, arg); + if (seminfo.sem_otime != 0) break; + sleep(1); + } + if (i == MAX_TRIES) + { + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); + PR_DELETE(sem); + return NULL; + } + return sem; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + struct sembuf sop; + + sop.sem_num = 0; + sop.sem_op = -1; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + struct sembuf sop; + + sop.sem_num = 0; + sop.sem_op = 1; + sop.sem_flg = 0; + if (semop(sem->semid, &sop, 1) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + PR_DELETE(sem); + return PR_SUCCESS; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + key_t key; + int semid; + /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */ + union semun unused; + char osname[PR_IPC_NAME_SIZE]; + + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) + == PR_FAILURE) + { + return PR_FAILURE; + } + key = ftok(osname, NSPR_IPC_KEY_ID); + if ((key_t) -1 == key) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + if (unlink(osname) == -1) + { + _PR_MD_MAP_UNLINK_ERROR(errno); + return PR_FAILURE; + } + semid = semget(key, 1, NSPR_SEM_MODE); + if (-1 == semid) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + unused.val = 0; + if (semctl(semid, 0, IPC_RMID, unused) == -1) + { + _PR_MD_MAP_DEFAULT_ERROR(errno); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +#else /* neither POSIX nor System V semaphores are available */ + +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( + const char *name, + PRIntn flags, + PRIntn mode, + PRUintn value) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +#endif /* end of interprocess named semaphore functions */ + +/**************************************************************/ +/**************************************************************/ +/******************ROUTINES FOR DCE EMULATION******************/ +/**************************************************************/ +/**************************************************************/ + +#include "prpdce.h" + +PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) +{ + PRIntn rv = pthread_mutex_trylock(&lock->mutex); + if (rv == PT_TRYLOCK_SUCCESS) + { + PR_ASSERT(PR_FALSE == lock->locked); + lock->locked = PR_TRUE; + lock->owner = pthread_self(); + } + /* XXX set error code? */ + return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PRP_TryLock */ + +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) +{ + PRCondVar *cv; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + cv = PR_NEW(PRCondVar); + if (cv != NULL) + { + int rv; + rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); + PR_ASSERT(0 == rv); + cv->lock = _PR_NAKED_CV_LOCK; + } + return cv; +} /* PRP_NewNakedCondVar */ + +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) +{ + int rv; + rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); +#if defined(DEBUG) + memset(cvar, 0xaf, sizeof(PRCondVar)); +#endif + PR_DELETE(cvar); +} /* PRP_DestroyNakedCondVar */ + +PR_IMPLEMENT(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout) +{ + PRIntn rv; + PR_ASSERT(cvar != NULL); + /* XXX do we really want to assert this in a naked wait? */ + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex)); + if (timeout == PR_INTERVAL_NO_TIMEOUT) + rv = pthread_cond_wait(&cvar->cv, &ml->mutex); + else + rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout); + if (rv != 0) + { + _PR_MD_MAP_DEFAULT_ERROR(rv); + return PR_FAILURE; + } + return PR_SUCCESS; +} /* PRP_NakedWait */ + +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) +{ + int rv; + PR_ASSERT(cvar != NULL); + rv = pthread_cond_signal(&cvar->cv); + PR_ASSERT(0 == rv); + return PR_SUCCESS; +} /* PRP_NakedNotify */ + +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) +{ + int rv; + PR_ASSERT(cvar != NULL); + rv = pthread_cond_broadcast(&cvar->cv); + PR_ASSERT(0 == rv); + return PR_SUCCESS; +} /* PRP_NakedBroadcast */ + +#endif /* defined(_PR_PTHREADS) */ + +/* ptsynch.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c new file mode 100644 index 00000000..0a16f5d1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/pthreads/ptthread.c @@ -0,0 +1,1610 @@ +/* -*- 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 ***** */ + +/* +** File: ptthread.c +** Descritpion: Implemenation for threds using pthreds +** Exports: ptthread.h +*/ + +#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) + +#include "prlog.h" +#include "primpl.h" +#include "prpdce.h" + +#include +#include +#include +#include + +#ifdef VBOX_USE_IPRT_IN_NSPR +# include +# include +# include +# include +#endif /* VBOX_USE_IPRT_IN_NSPR */ + +/* + * Record whether or not we have the privilege to set the scheduling + * policy and priority of threads. 0 means that privilege is available. + * EPERM means that privilege is not available. + */ + +static PRIntn pt_schedpriv = 0; +extern PRLock *_pr_sleeplock; + +static struct _PT_Bookeeping +{ + PRLock *ml; /* a lock to protect ourselves */ + PRCondVar *cv; /* used to signal global things */ + PRInt32 system, user; /* a count of the two different types */ + PRUintn this_many; /* number of threads allowed for exit */ + pthread_key_t key; /* private private data key */ + PRThread *first, *last; /* list of threads we know about */ +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + PRInt32 minPrio, maxPrio; /* range of scheduling priorities */ +#endif +} pt_book = {0}; + +static void _pt_thread_death(void *arg); +static void init_pthread_gc_support(void); + +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +static PRIntn pt_PriorityMap(PRThreadPriority pri) +{ +#ifdef NTO + /* This priority algorithm causes lots of problems on Neutrino + * for now I have just hard coded everything to run at priority 10 + * until I can come up with a new algorithm. + * Jerry.Kirk@Nexwarecorp.com + */ + return 10; +#else + return pt_book.minPrio + + pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST; +#endif +} +#endif + +#if defined(GC_LEAK_DETECTOR) && (__GLIBC__ >= 2) && defined(__i386__) + +#include + +typedef struct stack_frame stack_frame; + +struct stack_frame { + stack_frame* next; + void* pc; +}; + +static stack_frame* GetStackFrame() +{ + jmp_buf jb; + stack_frame* currentFrame; + setjmp(jb); + currentFrame = (stack_frame*)(jb[0].__jmpbuf[JB_BP]); + currentFrame = currentFrame->next; + return currentFrame; +} + +static void* GetStackTop() +{ + stack_frame* frame; + frame = GetStackFrame(); + while (frame != NULL) + { + ptrdiff_t pc = (ptrdiff_t)frame->pc; + if ((pc < 0x08000000) || (pc > 0x7fffffff) || (frame->next < frame)) + return frame; + frame = frame->next; + } + return NULL; +} +#endif /* GC_LEAK_DETECTOR && (__GLIBC__ >= 2) && __i386__ */ + +/* +** Initialize a stack for a native pthread thread +*/ +static void _PR_InitializeStack(PRThreadStack *ts) +{ + if( ts && (ts->stackTop == 0) ) { + ts->allocBase = (char *) &ts; + ts->allocSize = ts->stackSize; + + /* + ** Setup stackTop and stackBottom values. + */ +#ifdef HAVE_STACK_GROWING_UP + ts->stackBottom = ts->allocBase + ts->stackSize; + ts->stackTop = ts->allocBase; +#else +#ifdef GC_LEAK_DETECTOR + ts->stackTop = GetStackTop(); + ts->stackBottom = ts->stackTop - ts->stackSize; +#else + ts->stackTop = ts->allocBase; + ts->stackBottom = ts->allocBase - ts->stackSize; +#endif +#endif + } +} + +static void *_pt_root(void *arg) +{ + PRIntn rv; + PRThread *thred = (PRThread*)arg; + PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE; + + /* + * Both the parent thread and this new thread set thred->id. + * The new thread must ensure that thred->id is set before + * it executes its startFunc. The parent thread must ensure + * that thred->id is set before PR_CreateThread() returns. + * Both threads set thred->id without holding a lock. Since + * they are writing the same value, this unprotected double + * write should be safe. + */ + thred->id = pthread_self(); + + /* + ** DCE Threads can't detach during creation, so do it late. + ** I would like to do it only here, but that doesn't seem + ** to work. + */ +#if defined(_PR_DCETHREADS) + if (detached) + { + /* pthread_detach() modifies its argument, so we must pass a copy */ + pthread_t self = thred->id; + rv = pthread_detach(&self); + PR_ASSERT(0 == rv); + } +#endif /* defined(_PR_DCETHREADS) */ + + /* Set up the thread stack information */ + _PR_InitializeStack(thred->stack); + + /* + * Set within the current thread the pointer to our object. + * This object will be deleted when the thread termintates, + * whether in a join or detached (see _PR_InitThreads()). + */ + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + + /* make the thread visible to the rest of the runtime */ + PR_Lock(pt_book.ml); + + /* If this is a GCABLE thread, set its state appropriately */ + if (thred->suspend & PT_THREAD_SETGCABLE) + thred->state |= PT_THREAD_GCABLE; + thred->suspend = 0; + + thred->prev = pt_book.last; + pt_book.last->next = thred; + thred->next = NULL; + pt_book.last = thred; + PR_Unlock(pt_book.ml); + + thred->startFunc(thred->arg); /* make visible to the client */ + + /* unhook the thread from the runtime */ + PR_Lock(pt_book.ml); + /* + * At this moment, PR_CreateThread() may not have set thred->id yet. + * It is safe for a detached thread to free thred only after + * PR_CreateThread() has set thred->id. + */ + if (detached) + { + while (!thred->okToDelete) + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); + } + + if (thred->state & PT_THREAD_SYSTEM) + pt_book.system -= 1; + else if (--pt_book.user == pt_book.this_many) + PR_NotifyAllCondVar(pt_book.cv); + thred->prev->next = thred->next; + if (NULL == thred->next) + pt_book.last = thred->prev; + else + thred->next->prev = thred->prev; + PR_Unlock(pt_book.ml); + + /* + * Here we set the pthread's backpointer to the PRThread to NULL. + * Otherwise the desctructor would get called eagerly as the thread + * returns to the pthread runtime. The joining thread would them be + * the proud possessor of a dangling reference. However, this is the + * last chance to delete the object if the thread is detached, so + * just let the destuctor do the work. + */ + if (PR_FALSE == detached) + { + rv = pthread_setspecific(pt_book.key, NULL); + PR_ASSERT(0 == rv); + } + + return NULL; +} /* _pt_root */ + +#ifdef VBOX_USE_IPRT_IN_NSPR +static DECLCALLBACK(int) _pt_iprt_root( + RTTHREAD Thread, void *pvUser) +{ + PRThread *thred = (PRThread *)pvUser; + _pt_root(thred); + return VINF_SUCCESS; +} +#endif /* VBOX_USE_IPRT_IN_NSPR */ + +static PRThread* pt_AttachThread(void) +{ + PRThread *thred = NULL; + + /* + * NSPR must have been initialized when PR_AttachThread is called. + * We cannot have PR_AttachThread call implicit initialization + * because if multiple threads call PR_AttachThread simultaneously, + * NSPR may be initialized more than once. + * We can't call any function that calls PR_GetCurrentThread() + * either (e.g., PR_SetError()) as that will result in infinite + * recursion. + */ + if (!_pr_initialized) return NULL; + + /* PR_NEWZAP must not call PR_GetCurrentThread() */ + thred = PR_NEWZAP(PRThread); + if (NULL != thred) + { + int rv; + + thred->priority = PR_PRIORITY_NORMAL; + thred->id = pthread_self(); + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + + thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN; + PR_Lock(pt_book.ml); + + /* then put it into the list */ + thred->prev = pt_book.last; + pt_book.last->next = thred; + thred->next = NULL; + pt_book.last = thred; + PR_Unlock(pt_book.ml); + + } + return thred; /* may be NULL */ +} /* pt_AttachThread */ + +static PRThread* _PR_CreateThread( + PRThreadType type, void (*start)(void *arg), + void *arg, PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize, PRBool isGCAble) +{ + int rv; + PRThread *thred; +#ifndef VBOX_USE_IPRT_IN_NSPR + pthread_attr_t tattr; +#else + static uint32_t volatile s_iThread = 0; + RTTHREADTYPE enmType; + RTTHREAD hThread; + uint32_t fFlags = 0; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority) + priority = PR_PRIORITY_FIRST; + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority) + priority = PR_PRIORITY_LAST; + +#ifndef VBOX_USE_IPRT_IN_NSPR + rv = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + if (EPERM != pt_schedpriv) + { +#if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + struct sched_param schedule; +#endif + +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED); + PR_ASSERT(0 == rv); +#endif + + /* Use the default scheduling policy */ + +#if defined(_PR_DCETHREADS) + rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority)); + PR_ASSERT(0 == rv); +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_getschedparam(&tattr, &schedule); + PR_ASSERT(0 == rv); + schedule.sched_priority = pt_PriorityMap(priority); + rv = pthread_attr_setschedparam(&tattr, &schedule); + PR_ASSERT(0 == rv); +#ifdef NTO + rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */ + PR_ASSERT(0 == rv); +#endif +#endif /* !defined(_PR_DCETHREADS) */ + } +#else /* VBOX_USE_IPRT_IN_NSPR */ + /* calc priority */ + switch (priority) + { + default: + case PR_PRIORITY_NORMAL: enmType = RTTHREADTYPE_DEFAULT; break; + case PR_PRIORITY_LOW: enmType = RTTHREADTYPE_MAIN_HEAVY_WORKER; break; + case PR_PRIORITY_HIGH: enmType = RTTHREADTYPE_MAIN_WORKER; break; + case PR_PRIORITY_URGENT: enmType = RTTHREADTYPE_IO; break; + } +#endif /* VBOX_USE_IPRT_IN_NSPR */ + +#ifndef VBOX_USE_IPRT_IN_NSPR + /* + * DCE threads can't set detach state before creating the thread. + * AIX can't set detach late. Why can't we all just get along? + */ +#if !defined(_PR_DCETHREADS) + rv = pthread_attr_setdetachstate(&tattr, + ((PR_JOINABLE_THREAD == state) ? + PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED)); + PR_ASSERT(0 == rv); +#endif /* !defined(_PR_DCETHREADS) */ +#else + if (state == PR_JOINABLE_THREAD) + fFlags |= RTTHREADFLAGS_WAITABLE; +#endif /* !VBOX_USE_IPRT_IN_NSPR */ + +#ifndef VBOX_USE_IPRT_IN_NSPR /* We let stackSize stay zero and let IPRT choose a default size. */ + if (0 == stackSize) stackSize = (64 * 1024); /* default == 64K */ +#ifdef _MD_MINIMUM_STACK_SIZE + if (stackSize < _MD_MINIMUM_STACK_SIZE) stackSize = _MD_MINIMUM_STACK_SIZE; +#endif + /* + * Linux doesn't have pthread_attr_setstacksize. + */ +#ifndef LINUX + rv = pthread_attr_setstacksize(&tattr, stackSize); + PR_ASSERT(0 == rv); +#endif +#endif /* !VBOX_USE_IPRT_IN_NSPR */ + + thred = PR_NEWZAP(PRThread); + if (NULL == thred) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno); + goto done; + } + else + { + pthread_t id; + + thred->arg = arg; + thred->startFunc = start; + thred->priority = priority; + if (PR_UNJOINABLE_THREAD == state) + thred->state |= PT_THREAD_DETACHED; + + if (PR_LOCAL_THREAD == scope) + scope = PR_GLOBAL_THREAD; + +#ifndef VBOX_USE_IPRT_IN_NSPR + if (PR_GLOBAL_BOUND_THREAD == scope) { +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); + if (rv) { + /* + * system scope not supported + */ + scope = PR_GLOBAL_THREAD; + /* + * reset scope + */ + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); + PR_ASSERT(0 == rv); + } +#endif + } +#endif /* !VBOX_USE_IPRT_IN_NSPR */ + if (PR_GLOBAL_THREAD == scope) + thred->state |= PT_THREAD_GLOBAL; + else if (PR_GLOBAL_BOUND_THREAD == scope) + thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND); + else /* force it global */ + thred->state |= PT_THREAD_GLOBAL; + if (PR_SYSTEM_THREAD == type) + thred->state |= PT_THREAD_SYSTEM; + + thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0; + + thred->stack = PR_NEWZAP(PRThreadStack); + if (thred->stack == NULL) { + PRIntn oserr = errno; + PR_Free(thred); /* all that work ... poof! */ + PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr); + thred = NULL; /* and for what? */ + goto done; + } + thred->stack->stackSize = stackSize; + thred->stack->thr = thred; + +#ifdef PT_NO_SIGTIMEDWAIT + pthread_mutex_init(&thred->suspendResumeMutex,NULL); + pthread_cond_init(&thred->suspendResumeCV,NULL); +#endif + + /* make the thread counted to the rest of the runtime */ + PR_Lock(pt_book.ml); + if (PR_SYSTEM_THREAD == type) + pt_book.system += 1; + else pt_book.user += 1; + PR_Unlock(pt_book.ml); + + /* + * We pass a pointer to a local copy (instead of thred->id) + * to pthread_create() because who knows what wacky things + * pthread_create() may be doing to its argument. + */ +#ifndef VBOX_USE_IPRT_IN_NSPR + rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); + +#if !defined(_PR_DCETHREADS) + if (EPERM == rv) + { +#if defined(IRIX) + if (PR_GLOBAL_BOUND_THREAD == scope) { + /* + * SCOPE_SYSTEM requires appropriate privilege + * reset to process scope and try again + */ + rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS); + PR_ASSERT(0 == rv); + thred->state &= ~PT_THREAD_BOUND; + } +#else + /* Remember that we don't have thread scheduling privilege. */ + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("_PR_CreateThread: no thread scheduling privilege")); + /* Try creating the thread again without setting priority. */ +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED); + PR_ASSERT(0 == rv); +#endif +#endif /* IRIX */ + rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred); + } +#endif +#else /* VBOX_USE_IPRT_IN_NSPR */ + rv = RTThreadCreateF(&hThread, _pt_iprt_root, thred, stackSize, enmType, fFlags, "nspr-%u", ASMAtomicIncU32(&s_iThread)); + if (RT_SUCCESS(rv)) { +#ifdef VBOX_USE_IPRT_IN_NSPR + RTMEM_WILL_LEAK(hThread); +#endif + id = (pthread_t)RTThreadGetNative(hThread); + rv = 0; + } +#endif /* VBOX_USE_IPRT_IN_NSPR */ + + if (0 != rv) + { +#if defined(_PR_DCETHREADS) + PRIntn oserr = errno; +#else + PRIntn oserr = rv; +#endif + PR_Lock(pt_book.ml); + if (thred->state & PT_THREAD_SYSTEM) + pt_book.system -= 1; + else if (--pt_book.user == pt_book.this_many) + PR_NotifyAllCondVar(pt_book.cv); + PR_Unlock(pt_book.ml); + + PR_Free(thred->stack); + PR_Free(thred); /* all that work ... poof! */ + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr); + thred = NULL; /* and for what? */ + goto done; + } + + /* + * Both the parent thread and this new thread set thred->id. + * The parent thread must ensure that thred->id is set before + * PR_CreateThread() returns. (See comments in _pt_root().) + */ + thred->id = id; + + /* + * If the new thread is detached, tell it that PR_CreateThread() + * has set thred->id so it's ok to delete thred. + */ + if (PR_UNJOINABLE_THREAD == state) + { + PR_Lock(pt_book.ml); + thred->okToDelete = PR_TRUE; + PR_NotifyAllCondVar(pt_book.cv); + PR_Unlock(pt_book.ml); + } + } + +done: +#ifndef VBOX_USE_IPRT_IN_NSPR + rv = _PT_PTHREAD_ATTR_DESTROY(&tattr); + PR_ASSERT(0 == rv); +#endif + + return thred; +} /* _PR_CreateThread */ + +PR_IMPLEMENT(PRThread*) PR_CreateThread( + PRThreadType type, void (*start)(void *arg), void *arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + return _PR_CreateThread( + type, start, arg, priority, scope, state, stackSize, PR_FALSE); +} /* PR_CreateThread */ + +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble( + PRThreadType type, void (*start)(void *arg), void *arg, + PRThreadPriority priority, PRThreadScope scope, + PRThreadState state, PRUint32 stackSize) +{ + return _PR_CreateThread( + type, start, arg, priority, scope, state, stackSize, PR_TRUE); +} /* PR_CreateThreadGCAble */ + +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred) +{ + return thred->environment; +} /* GetExecutionEnvironment */ + +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env) +{ + thred->environment = env; +} /* SetExecutionEnvironment */ + +PR_IMPLEMENT(PRThread*) PR_AttachThread( + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) +{ + return PR_GetCurrentThread(); +} /* PR_AttachThread */ + + +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred) +{ + int rv = -1; + void *result = NULL; + PR_ASSERT(thred != NULL); + + if ((0xafafafaf == thred->state) + || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state)) + || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state))) + { + /* + * This might be a bad address, but if it isn't, the state should + * either be an unjoinable thread or it's already had the object + * deleted. However, the client that called join on a detached + * thread deserves all the rath I can muster.... + */ + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + PR_LogPrint( + "PR_JoinThread: 0x%X not joinable | already smashed\n", thred); + } + else + { +#ifndef VBOX_USE_IPRT_IN_NSPR + pthread_t id = thred->id; + rv = pthread_join(id, &result); + PR_ASSERT(rv == 0 && result == NULL); + if (0 == rv) + { +#ifdef _PR_DCETHREADS + rv = pthread_detach(&id); + PR_ASSERT(0 == rv); +#endif + _pt_thread_death(thred); + } + else + { + PRErrorCode prerror; + switch (rv) + { + case EINVAL: /* not a joinable thread */ + case ESRCH: /* no thread with given ID */ + prerror = PR_INVALID_ARGUMENT_ERROR; + break; + case EDEADLK: /* a thread joining with itself */ + prerror = PR_DEADLOCK_ERROR; + break; + default: + prerror = PR_UNKNOWN_ERROR; + break; + } + PR_SetError(prerror, rv); + } +#else /* VBOX_USE_IPRT_IN_NSPR */ + rv = VERR_INVALID_HANDLE; + RTTHREAD hThread = RTThreadFromNative((RTNATIVETHREAD)thred->id); + if (hThread != NIL_RTTHREAD) + { + int rcThread = 0; + rv = RTThreadWait(hThread, RT_INDEFINITE_WAIT, &rcThread); + PR_ASSERT(RT_SUCCESS(rv) && rcThread == VINF_SUCCESS); + if (RT_SUCCESS(rv)) + { + rv = 0; + _pt_thread_death(thred); + } + else + PR_SetError(rv == VERR_THREAD_NOT_WAITABLE + ? PR_INVALID_ARGUMENT_ERROR + : PR_UNKNOWN_ERROR, + rv); + } +#endif /* VBOX_USE_IPRT_IN_NSPR */ + } + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; +} /* PR_JoinThread */ + +PR_IMPLEMENT(void) PR_DetachThread(void) { } /* PR_DetachThread */ + +PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void) +{ + void *thred; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred); + if (NULL == thred) thred = pt_AttachThread(); + PR_ASSERT(NULL != thred); + return (PRThread*)thred; +} /* PR_GetCurrentThread */ + +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred) +{ + return (thred->state & PT_THREAD_BOUND) ? + PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD; +} /* PR_GetThreadScope() */ + +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred) +{ + return (thred->state & PT_THREAD_SYSTEM) ? + PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred) +{ + return (thred->state & PT_THREAD_DETACHED) ? + PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; +} /* PR_GetThreadState */ + +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred) +{ + PR_ASSERT(thred != NULL); + return thred->priority; +} /* PR_GetThreadPriority */ + +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri) +{ + PRIntn rv = -1; + + PR_ASSERT(NULL != thred); + + if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri) + newPri = PR_PRIORITY_FIRST; + else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri) + newPri = PR_PRIORITY_LAST; + +#if defined(_PR_DCETHREADS) + rv = pthread_setprio(thred->id, pt_PriorityMap(newPri)); + /* pthread_setprio returns the old priority */ +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + if (EPERM != pt_schedpriv) + { + int policy; + struct sched_param schedule; + + rv = pthread_getschedparam(thred->id, &policy, &schedule); + if(0 == rv) { + schedule.sched_priority = pt_PriorityMap(newPri); + rv = pthread_setschedparam(thred->id, policy, &schedule); + if (EPERM == rv) + { + pt_schedpriv = EPERM; + PR_LOG(_pr_thread_lm, PR_LOG_MIN, + ("PR_SetThreadPriority: no thread scheduling privilege")); + } + } + if (rv != 0) + rv = -1; + } +#endif + + thred->priority = newPri; +} /* PR_SetThreadPriority */ + +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred) +{ + /* + ** If the target thread indicates that it's waiting, + ** find the condition and broadcast to it. Broadcast + ** since we don't know which thread (if there are more + ** than one). This sounds risky, but clients must + ** test their invariants when resumed from a wait and + ** I don't expect very many threads to be waiting on + ** a single condition and I don't expect interrupt to + ** be used very often. + ** + ** I don't know why I thought this would work. Must have + ** been one of those weaker momements after I'd been + ** smelling the vapors. + ** + ** Even with the followng changes it is possible that + ** the pointer to the condition variable is pointing + ** at a bogus value. Will the unerlying code detect + ** that? + */ + PRCondVar *cv; + PR_ASSERT(NULL != thred); + if (NULL == thred) return PR_FAILURE; + + thred->state |= PT_THREAD_ABORTED; + + cv = thred->waiting; + if ((NULL != cv) && !thred->interrupt_blocked) + { + PRIntn rv; + (void)PR_AtomicIncrement(&cv->notify_pending); + rv = pthread_cond_broadcast(&cv->cv); + PR_ASSERT(0 == rv); + if (0 > PR_AtomicDecrement(&cv->notify_pending)) + PR_DestroyCondVar(cv); + } + return PR_SUCCESS; +} /* PR_Interrupt */ + +PR_IMPLEMENT(void) PR_ClearInterrupt(void) +{ + PRThread *me = PR_CurrentThread(); + me->state &= ~PT_THREAD_ABORTED; +} /* PR_ClearInterrupt */ + +PR_IMPLEMENT(void) PR_BlockInterrupt(void) +{ + PRThread *me = PR_CurrentThread(); + _PT_THREAD_BLOCK_INTERRUPT(me); +} /* PR_BlockInterrupt */ + +PR_IMPLEMENT(void) PR_UnblockInterrupt(void) +{ + PRThread *me = PR_CurrentThread(); + _PT_THREAD_UNBLOCK_INTERRUPT(me); +} /* PR_UnblockInterrupt */ + +PR_IMPLEMENT(PRStatus) PR_Yield(void) +{ + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); + return PR_Sleep(PR_INTERVAL_NO_WAIT); +} + +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_INTERVAL_NO_WAIT == ticks) + { + _PT_PTHREAD_YIELD(); + } + else + { + PRCondVar *cv; + PRIntervalTime timein; + + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); + PR_ASSERT(cv != NULL); + PR_Lock(_pr_sleeplock); + do + { + PRIntervalTime now = PR_IntervalNow(); + PRIntervalTime delta = now - timein; + if (delta > ticks) break; + rv = PR_WaitCondVar(cv, ticks - delta); + } while (PR_SUCCESS == rv); + PR_Unlock(_pr_sleeplock); + PR_DestroyCondVar(cv); + } + return rv; +} /* PR_Sleep */ + +static void _pt_thread_death(void *arg) +{ + PRThread *thred = (PRThread*)arg; + + if (thred->state & PT_THREAD_FOREIGN) + { + PR_Lock(pt_book.ml); + thred->prev->next = thred->next; + if (NULL == thred->next) + pt_book.last = thred->prev; + else + thred->next->prev = thred->prev; + PR_Unlock(pt_book.ml); + } + _PR_DestroyThreadPrivate(thred); + PR_Free(thred->privateData); + if (NULL != thred->errorString) + PR_Free(thred->errorString); + PR_Free(thred->stack); + if (NULL != thred->syspoll_list) + PR_Free(thred->syspoll_list); +#if defined(_PR_POLL_WITH_SELECT) + if (NULL != thred->selectfd_list) + PR_Free(thred->selectfd_list); +#endif +#if defined(DEBUG) + memset(thred, 0xaf, sizeof(PRThread)); +#endif /* defined(DEBUG) */ + PR_Free(thred); +} /* _pt_thread_death */ + +void _PR_InitThreads( + PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs) +{ + int rv; + PRThread *thred; + +#ifdef _PR_NEED_PTHREAD_INIT + /* + * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily + * initialized, but pthread_self() fails to initialize + * pthreads and hence returns a null thread ID if invoked + * by the primordial thread before any other pthread call. + * So we explicitly initialize pthreads here. + */ + pthread_init(); +#endif + +#if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +#if defined(FREEBSD) + { + pthread_attr_t attr; + int policy; + /* get the min and max priorities of the default policy */ + pthread_attr_init(&attr); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_getschedpolicy(&attr, &policy); + pt_book.minPrio = sched_get_priority_min(policy); + PR_ASSERT(-1 != pt_book.minPrio); + pt_book.maxPrio = sched_get_priority_max(policy); + PR_ASSERT(-1 != pt_book.maxPrio); + pthread_attr_destroy(&attr); + } +#else + /* + ** These might be function evaluations + */ + pt_book.minPrio = PT_PRIO_MIN; + pt_book.maxPrio = PT_PRIO_MAX; +#endif +#endif + + PR_ASSERT(NULL == pt_book.ml); + pt_book.ml = PR_NewLock(); + PR_ASSERT(NULL != pt_book.ml); + pt_book.cv = PR_NewCondVar(pt_book.ml); + PR_ASSERT(NULL != pt_book.cv); + thred = PR_NEWZAP(PRThread); + PR_ASSERT(NULL != thred); + thred->arg = NULL; + thred->startFunc = NULL; + thred->priority = priority; + thred->id = pthread_self(); + + thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD); + if (PR_SYSTEM_THREAD == type) + { + thred->state |= PT_THREAD_SYSTEM; + pt_book.system += 1; + pt_book.this_many = 0; + } + else + { + pt_book.user += 1; + pt_book.this_many = 1; + } + thred->next = thred->prev = NULL; + pt_book.first = pt_book.last = thred; + + thred->stack = PR_NEWZAP(PRThreadStack); + PR_ASSERT(thred->stack != NULL); + thred->stack->stackSize = 0; + thred->stack->thr = thred; + _PR_InitializeStack(thred->stack); + + /* + * Create a key for our use to store a backpointer in the pthread + * to our PRThread object. This object gets deleted when the thread + * returns from its root in the case of a detached thread. Other + * threads delete the objects in Join. + * + * NB: The destructor logic seems to have a bug so it isn't used. + * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998. + * More info - the problem is that pthreads calls the destructor + * eagerly as the thread returns from its root, rather than lazily + * after the thread is joined. Therefore, threads that are joining + * and holding PRThread references are actually holding pointers to + * nothing. + */ + rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death); + PR_ASSERT(0 == rv); + rv = pthread_setspecific(pt_book.key, thred); + PR_ASSERT(0 == rv); + PR_SetThreadPriority(thred, priority); +} /* _PR_InitThreads */ + +PR_IMPLEMENT(PRStatus) PR_Cleanup(void) +{ + PRThread *me = PR_CurrentThread(); + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR")); + PR_ASSERT(me->state & PT_THREAD_PRIMORD); + if (me->state & PT_THREAD_PRIMORD) + { + PR_Lock(pt_book.ml); + while (pt_book.user > pt_book.this_many) + PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(pt_book.ml); + + _PR_CleanupMW(); + _PR_CleanupDtoa(); + _PR_CleanupCallOnce(); + _PR_ShutdownLinker(); + _PR_LogCleanup(); + _PR_CleanupNet(); + /* Close all the fd's before calling _PR_CleanupIO */ + _PR_CleanupIO(); + + /* + * I am not sure if it's safe to delete the cv and lock here, + * since there may still be "system" threads around. If this + * call isn't immediately prior to exiting, then there's a + * problem. + */ + if (0 == pt_book.system) + { + PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL; + PR_DestroyLock(pt_book.ml); pt_book.ml = NULL; + } + _pt_thread_death(me); + PR_DestroyLock(_pr_sleeplock); + _pr_sleeplock = NULL; + _PR_CleanupLayerCache(); + _PR_CleanupEnv(); +#ifdef _PR_ZONE_ALLOCATOR + _PR_DestroyZones(); +#endif + _pr_initialized = PR_FALSE; + return PR_SUCCESS; + } + return PR_FAILURE; +} /* PR_Cleanup */ + +PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status) +{ + _exit(status); +} + +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred) +{ +#if defined(_PR_DCETHREADS) + return (PRUint32)&thred->id; /* this is really a sham! */ +#else + return (PRUint32)thred->id; /* and I don't know what they will do with it */ +#endif +} + +/* + * $$$ + * The following two thread-to-processor affinity functions are not + * yet implemented for pthreads. By the way, these functions should return + * PRStatus rather than PRInt32 to indicate the success/failure status. + * $$$ + */ + +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) +{ + return 0; /* not implemented */ +} + +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) +{ + return 0; /* not implemented */ +} + +PR_IMPLEMENT(void) +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg) +{ + thread->dump = dump; + thread->dumpArg = arg; +} + +/* + * Garbage collection support follows. + */ + +#if defined(_PR_DCETHREADS) + +/* + * statics for Garbage Collection support. We don't need to protect these + * signal masks since the garbage collector itself is protected by a lock + * and multiple threads will not be garbage collecting at the same time. + */ +static sigset_t javagc_vtalarm_sigmask; +static sigset_t javagc_intsoff_sigmask; + +#else /* defined(_PR_DCETHREADS) */ + +/* a bogus signal mask for forcing a timed wait */ +/* Not so bogus in AIX as we really do a sigwait */ +static sigset_t sigwait_set; + +static struct timespec onemillisec = {0, 1000000L}; +#ifndef PT_NO_SIGTIMEDWAIT +static struct timespec hundredmillisec = {0, 100000000L}; +#endif + +static void suspend_signal_handler(PRIntn sig); + +#ifdef PT_NO_SIGTIMEDWAIT +static void null_signal_handler(PRIntn sig); +#endif + +#endif /* defined(_PR_DCETHREADS) */ + +/* + * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which + * conflict with the use of these two signals in our GC support. + * So we don't know how to support GC on Linux pthreads. + */ +static void init_pthread_gc_support(void) +{ + PRIntn rv; + +#if defined(_PR_DCETHREADS) + rv = sigemptyset(&javagc_vtalarm_sigmask); + PR_ASSERT(0 == rv); + rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM); + PR_ASSERT(0 == rv); +#else /* defined(_PR_DCETHREADS) */ + { + struct sigaction sigact_usr2; + + sigact_usr2.sa_handler = suspend_signal_handler; + sigact_usr2.sa_flags = SA_RESTART; + sigemptyset (&sigact_usr2.sa_mask); + + rv = sigaction (SIGUSR2, &sigact_usr2, NULL); + PR_ASSERT(0 == rv); + + sigemptyset (&sigwait_set); +#if defined(PT_NO_SIGTIMEDWAIT) + sigaddset (&sigwait_set, SIGUSR1); +#else + sigaddset (&sigwait_set, SIGUSR2); +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ + } +#if defined(PT_NO_SIGTIMEDWAIT) + { + struct sigaction sigact_null; + sigact_null.sa_handler = null_signal_handler; + sigact_null.sa_flags = SA_RESTART; + sigemptyset (&sigact_null.sa_mask); + rv = sigaction (SIGUSR1, &sigact_null, NULL); + PR_ASSERT(0 ==rv); + } +#endif /* defined(PT_NO_SIGTIMEDWAIT) */ +#endif /* defined(_PR_DCETHREADS) */ +} + +PR_IMPLEMENT(void) PR_SetThreadGCAble(void) +{ + PR_Lock(pt_book.ml); + PR_CurrentThread()->state |= PT_THREAD_GCABLE; + PR_Unlock(pt_book.ml); +} + +PR_IMPLEMENT(void) PR_ClearThreadGCAble(void) +{ + PR_Lock(pt_book.ml); + PR_CurrentThread()->state &= (~PT_THREAD_GCABLE); + PR_Unlock(pt_book.ml); +} + +#if defined(DEBUG) +static PRBool suspendAllOn = PR_FALSE; +#endif + +static PRBool suspendAllSuspended = PR_FALSE; + +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg) +{ + PRIntn count = 0; + PRStatus rv = PR_SUCCESS; + PRThread* thred = pt_book.first; + PRThread *me = PR_CurrentThread(); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n")); + /* + * $$$ + * Need to suspend all threads other than me before doing this. + * This is really a gross and disgusting thing to do. The only + * good thing is that since all other threads are suspended, holding + * the lock during a callback seems like child's play. + * $$$ + */ + PR_ASSERT(suspendAllOn); + + while (thred != NULL) + { + /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking + * qp->next after applying the function "func". In particular, "func" + * might remove the thread from the queue and put it into another one in + * which case qp->next no longer points to the next entry in the original + * queue. + * + * To get around this problem, we save qp->next in qp_next before applying + * "func" and use that saved value as the next value after applying "func". + */ + PRThread* next = thred->next; + + if (_PT_IS_GCABLE_THREAD(thred)) + { +#if !defined(_PR_DCETHREADS) + PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED)); +#endif + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("In PR_EnumerateThreads callback thread %X thid = %X\n", + thred, thred->id)); + + rv = func(thred, count++, arg); + if (rv != PR_SUCCESS) + return rv; + } + thred = next; + } + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End PR_EnumerateThreads count = %d \n", count)); + return rv; +} /* PR_EnumerateThreads */ + +/* + * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy + * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend. + * The signal handler will record the stack pointer and will block until resumed by + * the resume call. Since the signal handler is the last routine called for the + * suspended thread, the stack pointer will also serve as a place where all the + * registers have been saved on the stack for the previously executing routines. + * + * Through global variables, we also make sure that PR_Suspend and PR_Resume does not + * proceed until the thread is suspended or resumed. + */ + +#if !defined(_PR_DCETHREADS) + +/* + * In the signal handler, we can not use condition variable notify or wait. + * This does not work consistently across all pthread platforms. We also can not + * use locking since that does not seem to work reliably across platforms. + * Only thing we can do is yielding while testing for a global condition + * to change. This does work on pthread supported platforms. We may have + * to play with priortities if there are any problems detected. + */ + + /* + * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps + * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no + * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually + * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java, + * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal + * handler as all synchronization mechanisms just break down. + */ + +#if defined(PT_NO_SIGTIMEDWAIT) +static void null_signal_handler(PRIntn sig) +{ + return; +} +#endif + +static void suspend_signal_handler(PRIntn sig) +{ + PRThread *me = PR_CurrentThread(); + + PR_ASSERT(me != NULL); + PR_ASSERT(_PT_IS_GCABLE_THREAD(me)); + PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin suspend_signal_handler thred %X thread id = %X\n", + me, me->id)); + + /* + * save stack pointer + */ + me->sp = &me; + + /* + At this point, the thread's stack pointer has been saved, + And it is going to enter a wait loop until it is resumed. + So it is _really_ suspended + */ + + me->suspend |= PT_THREAD_SUSPENDED; + + /* + * now, block current thread + */ +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_cond_signal(&me->suspendResumeCV); + while (me->suspend & PT_THREAD_SUSPENDED) + { +#if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \ + && !defined(BSDI) && !defined(VMS) && !defined(UNIXWARE) && !defined(DARWIN) /*XXX*/ + PRIntn rv; + sigwait(&sigwait_set, &rv); +#endif + } + me->suspend |= PT_THREAD_RESUMED; + pthread_cond_signal(&me->suspendResumeCV); +#else /* defined(PT_NO_SIGTIMEDWAIT) */ + while (me->suspend & PT_THREAD_SUSPENDED) + { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec); + PR_ASSERT(-1 == rv); + } + me->suspend |= PT_THREAD_RESUMED; +#endif + + /* + * At this point, thread has been resumed, so set a global condition. + * The ResumeAll needs to know that this has really been resumed. + * So the signal handler sets a flag which PR_ResumeAll will reset. + * The PR_ResumeAll must reset this flag ... + */ + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End suspend_signal_handler thred = %X tid = %X\n", me, me->id)); +} /* suspend_signal_handler */ + +static void pt_SuspendSet(PRThread *thred) +{ + PRIntn rv; + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("pt_SuspendSet thred %X thread id = %X\n", thred, thred->id)); + + + /* + * Check the thread state and signal the thread to suspend + */ + + PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0); + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("doing pthread_kill in pt_SuspendSet thred %X tid = %X\n", + thred, thred->id)); +#if defined(VMS) + rv = thread_suspend(thred); +#else + rv = pthread_kill (thred->id, SIGUSR2); +#endif + PR_ASSERT(0 == rv); +} + +static void pt_SuspendTest(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin pt_SuspendTest thred %X thread id = %X\n", thred, thred->id)); + + + /* + * Wait for the thread to be really suspended. This happens when the + * suspend signal handler stores the stack pointer and sets the state + * to suspended. + */ + +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_mutex_lock(&thred->suspendResumeMutex); + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) + { + pthread_cond_timedwait( + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); + } + pthread_mutex_unlock(&thred->suspendResumeMutex); +#else + while ((thred->suspend & PT_THREAD_SUSPENDED) == 0) + { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); + PR_ASSERT(-1 == rv); + } +#endif + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End pt_SuspendTest thred %X tid %X\n", thred, thred->id)); +} /* pt_SuspendTest */ + +static void pt_ResumeSet(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("pt_ResumeSet thred %X thread id = %X\n", thred, thred->id)); + + /* + * Clear the global state and set the thread state so that it will + * continue past yield loop in the suspend signal handler + */ + + PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED); + + + thred->suspend &= ~PT_THREAD_SUSPENDED; + +#if defined(PT_NO_SIGTIMEDWAIT) +#if defined(VMS) + thread_resume(thred); +#else + pthread_kill(thred->id, SIGUSR1); +#endif +#endif + +} /* pt_ResumeSet */ + +static void pt_ResumeTest(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("Begin pt_ResumeTest thred %X thread id = %X\n", thred, thred->id)); + + /* + * Wait for the threads resume state to change + * to indicate it is really resumed + */ +#if defined(PT_NO_SIGTIMEDWAIT) + pthread_mutex_lock(&thred->suspendResumeMutex); + while ((thred->suspend & PT_THREAD_RESUMED) == 0) + { + pthread_cond_timedwait( + &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec); + } + pthread_mutex_unlock(&thred->suspendResumeMutex); +#else + while ((thred->suspend & PT_THREAD_RESUMED) == 0) { + PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec); + PR_ASSERT(-1 == rv); + } +#endif + + thred->suspend &= ~PT_THREAD_RESUMED; + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ( + "End pt_ResumeTest thred %X tid %X\n", thred, thred->id)); +} /* pt_ResumeTest */ + +static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT; + +PR_IMPLEMENT(void) PR_SuspendAll(void) +{ +#ifdef DEBUG + PRIntervalTime stime, etime; +#endif + PRThread* thred = pt_book.first; + PRThread *me = PR_CurrentThread(); + int rv; + + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); + PR_ASSERT(0 == rv); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); + /* + * Stop all threads which are marked GC able. + */ + PR_Lock(pt_book.ml); +#ifdef DEBUG + suspendAllOn = PR_TRUE; + stime = PR_IntervalNow(); +#endif + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_SuspendSet(thred); + thred = thred->next; + } + + /* Wait till they are really suspended */ + thred = pt_book.first; + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_SuspendTest(thred); + thred = thred->next; + } + + suspendAllSuspended = PR_TRUE; + +#ifdef DEBUG + etime = PR_IntervalNow(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\ + ("End PR_SuspendAll (time %dms)\n", + PR_IntervalToMilliseconds(etime - stime))); +#endif +} /* PR_SuspendAll */ + +PR_IMPLEMENT(void) PR_ResumeAll(void) +{ +#ifdef DEBUG + PRIntervalTime stime, etime; +#endif + PRThread* thred = pt_book.first; + PRThread *me = PR_CurrentThread(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); + /* + * Resume all previously suspended GC able threads. + */ + suspendAllSuspended = PR_FALSE; +#ifdef DEBUG + stime = PR_IntervalNow(); +#endif + + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_ResumeSet(thred); + thred = thred->next; + } + + thred = pt_book.first; + while (thred != NULL) + { + if ((thred != me) && _PT_IS_GCABLE_THREAD(thred)) + pt_ResumeTest(thred); + thred = thred->next; + } + + PR_Unlock(pt_book.ml); +#ifdef DEBUG + suspendAllOn = PR_FALSE; + etime = PR_IntervalNow(); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("End PR_ResumeAll (time %dms)\n", + PR_IntervalToMilliseconds(etime - stime))); +#endif +} /* PR_ResumeAll */ + +/* Return the stack pointer for the given thread- used by the GC */ +PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred) +{ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, + ("in PR_GetSP thred %X thid = %X, sp = %X \n", + thred, thred->id, thred->sp)); + return thred->sp; +} /* PR_GetSP */ + +#else /* !defined(_PR_DCETHREADS) */ + +static pthread_once_t pt_gc_support_control = pthread_once_init; + +/* + * For DCE threads, there is no pthread_kill or a way of suspending or resuming a + * particular thread. We will just disable the preemption (virtual timer alarm) and + * let the executing thread finish the garbage collection. This stops all other threads + * (GC able or not) and is very inefficient but there is no other choice. + */ +PR_IMPLEMENT(void) PR_SuspendAll() +{ + PRIntn rv; + + rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support); + PR_ASSERT(0 == rv); /* returns -1 on failure */ +#ifdef DEBUG + suspendAllOn = PR_TRUE; +#endif + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n")); + /* + * turn off preemption - i.e add virtual alarm signal to the set of + * blocking signals + */ + rv = sigprocmask( + SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask); + PR_ASSERT(0 == rv); + suspendAllSuspended = PR_TRUE; + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n")); +} /* PR_SuspendAll */ + +PR_IMPLEMENT(void) PR_ResumeAll() +{ + PRIntn rv; + + suspendAllSuspended = PR_FALSE; + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n")); + /* turn on preemption - i.e re-enable virtual alarm signal */ + + rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL); + PR_ASSERT(0 == rv); +#ifdef DEBUG + suspendAllOn = PR_FALSE; +#endif + + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n")); +} /* PR_ResumeAll */ + +/* Return the stack pointer for the given thread- used by the GC */ +PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred) +{ + pthread_t tid = thred->id; + char *thread_tcb, *top_sp; + + /* + * For HPUX DCE threads, pthread_t is a struct with the + * following three fields (see pthread.h, dce/cma.h): + * cma_t_address field1; + * short int field2; + * short int field3; + * where cma_t_address is typedef'd to be either void* + * or char*. + */ + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n")); + thread_tcb = (char*)tid.field1; + top_sp = *(char**)(thread_tcb + 128); + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %X \n", top_sp)); + return top_sp; +} /* PR_GetSP */ + +#endif /* !defined(_PR_DCETHREADS) */ + +#endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */ + +/* ptthread.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/threads/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/threads/Makefile.in new file mode 100644 index 00000000..5e6731c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/Makefile.in @@ -0,0 +1,94 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifdef USE_PTHREADS + DIRS = +else +ifdef USE_BTHREADS + DIRS = +else + DIRS = combined +endif +endif + +ifdef USE_PTHREADS +CSRCS = \ + prcmon.c \ + prrwlock.c \ + prtpd.c \ + $(NULL) +else +ifdef USE_BTHREADS +CSRCS = \ + prcmon.c \ + prrwlock.c \ + prtpd.c \ + $(NULL) +else +CSRCS = \ + prcmon.c \ + prdump.c \ + prmon.c \ + prsem.c \ + prrwlock.c \ + prcthr.c \ + prtpd.c \ + $(NULL) +endif +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/Makefile.in new file mode 100644 index 00000000..476c6c9a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/Makefile.in @@ -0,0 +1,79 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +ifdef USE_PTHREADS +CSRCS = \ + $(NULL) +else +CSRCS = \ + prucpu.c \ + prucv.c \ + prulock.c \ + pruthr.c \ + prustack.c \ + $(NULL) +endif + +TARGETS = $(OBJS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +DEFINES += -D_NSPR_BUILD_ + +include $(topsrcdir)/config/rules.mk + +export:: $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/README b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/README new file mode 100644 index 00000000..aa266652 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/README @@ -0,0 +1,62 @@ +NSPR 2.0 evolution +------------------ + + +Phase 1- today + +Currently (Oct 10, 1996) NSPR 2.0 has two modes. Either _PR_NTHREAD +is defined, in which case the PR_CreateThread() call always creates a +native kernel thread, or _PR_NTHREAD is not defined and PR_CreateThread() +always creates user level threads within the single, original process. This +source code is reflected in two directories, nspr20/pr/src/threads/native, and +nspr20/pr/src/threads/user. Although the PR_CreateThread() function has +a paramter to specify the "scope" of a thread, this parameter is not yet +used- except on solaris where it uses it to specify bound vs unbound threads. + +Phase 2 - next week + +The next step is to provide a combination of user and native threads. The +idea, of course, is to have some small number of native threads and each of +those threads be able to run user level threads. The number of native +threads created will most likely be proportional to the number of CPUs in +the system. For this reason, the specific set of native threads which are +used to run the user-level threads will be called "CPU" threads. + +The user level threads which will be run on the CPU threads are able to +run on any of the CPU threads available, and over the course of a user-level +thread's lifetime, it may drift from one CPU thread to another. All +user-level threads will compete for processing time via a single run queue. + +Creation of a CPU thread will be primarily controlled by NSPR itself or by +the user running a function PR_Concurrency(). The details of PR_Concurrency() +have not yet been worked out; but the idea is that the user can specify to +NSPR how many CPU threads are desired. + +In this system, user-level threads are created by using PR_CreateThread() and +specifying the PR_LOCAL_SCOPE option. LOCAL_SCOPE indicates that the thread +will be under the control of the "local" scheduler. Creating threads with +GLOBAL_SCOPE, on the other hand will create a thread which is under the +control of the system's scheduler. In otherwords, this creates a native thread +which is not a CPU thread; it runs a single thread task and never has more +than one task to run. LOCAL_SCOPE is much like creating a Solaris unbound +thread, while GLOBAL_SCOPE is similar to creating a Solaris bound thread. + +To implement this architecture, the source code will still maintain the "user" +and "native" directories which is has today. However a third directory +"combined" will also exist. To compile a version of NSPR which only creates +native threads, the user can define _PR_NTHREAD. For exclusive user-level +threads, do not define _PR_NTHREAD. To get the combined threads, define +_PR_NTHREAD and _PR_USE_CPUS. + + +Phase 3 - later than next week + +The goal is to eliminate the 3 directories. Once these three models are in +place, the remaining work will be to eliminate the native and user thread +directories for all platforms, so that the entire thread model is contained +within what is today called the "combined" model. This new and glorious +source code will attempt to make the "combined" model on any platforms which +provide the necessary underlying native threading, but will also be +capable of using exclusive user-level threads on systems which don't have +native threads. + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucpu.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucpu.c new file mode 100644 index 00000000..a3938b1f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucpu.c @@ -0,0 +1,440 @@ +/* -*- 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" + +_PRCPU *_pr_primordialCPU = NULL; + +PRInt32 _pr_md_idle_cpus; /* number of idle cpus */ +/* + * The idle threads in MxN models increment/decrement _pr_md_idle_cpus. + * If _PR_HAVE_ATOMIC_OPS is not defined, they can't use the atomic + * increment/decrement routines (which are based on PR_Lock/PR_Unlock), + * because PR_Lock asserts that the calling thread is not an idle thread. + * So we use a _MDLock to protect _pr_md_idle_cpus. + */ +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifndef _PR_HAVE_ATOMIC_OPS +static _MDLock _pr_md_idle_cpus_lock; +#endif +#endif +PRUintn _pr_numCPU; +PRInt32 _pr_cpus_exit; +PRInt32 _pr_cpu_affinity_mask = 0; + +#if !defined (_PR_GLOBAL_THREADS_ONLY) + +static PRUintn _pr_cpuID; + +static void PR_CALLBACK _PR_CPU_Idle(void *); + +static _PRCPU *_PR_CreateCPU(void); +static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread); + +#if !defined(_PR_LOCAL_THREADS_ONLY) +static void _PR_RunCPU(void *arg); +#endif + +void _PR_InitCPUs() +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (_native_threads_only) + return; + + _pr_cpuID = 0; + _MD_NEW_LOCK( &_pr_cpuLock); +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifndef _PR_HAVE_ATOMIC_OPS + _MD_NEW_LOCK(&_pr_md_idle_cpus_lock); +#endif +#endif + +#ifdef _PR_LOCAL_THREADS_ONLY + +#ifdef HAVE_CUSTOM_USER_THREADS + _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me); +#endif + + /* Now start the first CPU. */ + _pr_primordialCPU = _PR_CreateCPU(); + _pr_numCPU = 1; + _PR_StartCPU(_pr_primordialCPU, me); + + _PR_MD_SET_CURRENT_CPU(_pr_primordialCPU); + + /* Initialize cpu for current thread (could be different from me) */ + _PR_MD_CURRENT_THREAD()->cpu = _pr_primordialCPU; + + _PR_MD_SET_LAST_THREAD(me); + +#else /* Combined MxN model */ + + _pr_primordialCPU = _PR_CreateCPU(); + _pr_numCPU = 1; + _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_RunCPU, + _pr_primordialCPU, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + +#endif /* _PR_LOCAL_THREADS_ONLY */ + + _PR_MD_INIT_CPUS(); +} + +#ifdef WINNT +/* + * Right now this function merely stops the CPUs and does + * not do any other cleanup. + * + * It is only implemented for WINNT because bug 161998 only + * affects the WINNT version of NSPR, but it would be nice + * to implement this function for other platforms too. + */ +void _PR_CleanupCPUs(void) +{ + PRUintn i; + PRCList *qp; + _PRCPU *cpu; + + _pr_cpus_exit = 1; + for (i = 0; i < _pr_numCPU; i++) { + _PR_MD_WAKEUP_WAITER(NULL); + } + for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { + cpu = _PR_CPU_PTR(qp); + _PR_MD_JOIN_THREAD(&cpu->thread->md); + } +} +#endif + +static _PRCPUQueue *_PR_CreateCPUQueue(void) +{ + PRInt32 index; + _PRCPUQueue *cpuQueue; + cpuQueue = PR_NEWZAP(_PRCPUQueue); + + _MD_NEW_LOCK( &cpuQueue->runQLock ); + _MD_NEW_LOCK( &cpuQueue->sleepQLock ); + _MD_NEW_LOCK( &cpuQueue->miscQLock ); + + for (index = 0; index < PR_PRIORITY_LAST + 1; index++) + PR_INIT_CLIST( &(cpuQueue->runQ[index]) ); + PR_INIT_CLIST( &(cpuQueue->sleepQ) ); + PR_INIT_CLIST( &(cpuQueue->pauseQ) ); + PR_INIT_CLIST( &(cpuQueue->suspendQ) ); + PR_INIT_CLIST( &(cpuQueue->waitingToJoinQ) ); + + cpuQueue->numCPUs = 1; + + return cpuQueue; +} + +/* + * Create a new CPU. + * + * This function initializes enough of the _PRCPU structure so + * that it can be accessed safely by a global thread or another + * CPU. This function does not create the native thread that + * will run the CPU nor does it initialize the parts of _PRCPU + * that must be initialized by that native thread. + * + * The reason we cannot simply have the native thread create + * and fully initialize a new CPU is that we need to be able to + * create a usable _pr_primordialCPU in _PR_InitCPUs without + * assuming that the primordial CPU thread we created can run + * during NSPR initialization. For example, on Windows while + * new threads can be created by DllMain, they won't be able + * to run during DLL initialization. If NSPR is initialized + * by DllMain, the primordial CPU thread won't run until DLL + * initialization is finished. + */ +static _PRCPU *_PR_CreateCPU(void) +{ + _PRCPU *cpu; + + cpu = PR_NEWZAP(_PRCPU); + if (cpu) { + cpu->queue = _PR_CreateCPUQueue(); + if (!cpu->queue) { + PR_DELETE(cpu); + return NULL; + } + } + return cpu; +} + +/* + * Start a new CPU. + * + * 'cpu' is a _PRCPU structure created by _PR_CreateCPU(). + * 'thread' is the native thread that will run the CPU. + * + * If this function fails, 'cpu' is destroyed. + */ +static PRStatus _PR_StartCPU(_PRCPU *cpu, PRThread *thread) +{ + /* + ** Start a new cpu. The assumption this code makes is that the + ** underlying operating system creates a stack to go with the new + ** native thread. That stack will be used by the cpu when pausing. + */ + + PR_ASSERT(!_native_threads_only); + + cpu->last_clock = PR_IntervalNow(); + + /* Before we create any threads on this CPU we have to + * set the current CPU + */ + _PR_MD_SET_CURRENT_CPU(cpu); + _PR_MD_INIT_RUNNING_CPU(cpu); + thread->cpu = cpu; + + cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_CPU_Idle, + (void *)cpu, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + + if (!cpu->idle_thread) { + /* didn't clean up CPU queue XXXMB */ + PR_DELETE(cpu); + return PR_FAILURE; + } + PR_ASSERT(cpu->idle_thread->cpu == cpu); + + cpu->idle_thread->no_sched = 0; + + cpu->thread = thread; + + if (_pr_cpu_affinity_mask) + PR_SetThreadAffinityMask(thread, _pr_cpu_affinity_mask); + + /* Created and started a new CPU */ + _PR_CPU_LIST_LOCK(); + cpu->id = _pr_cpuID++; + PR_APPEND_LINK(&cpu->links, &_PR_CPUQ()); + _PR_CPU_LIST_UNLOCK(); + + return PR_SUCCESS; +} + +#if !defined(_PR_GLOBAL_THREADS_ONLY) && !defined(_PR_LOCAL_THREADS_ONLY) +/* +** This code is used during a cpu's initial creation. +*/ +static void _PR_RunCPU(void *arg) +{ + _PRCPU *cpu = (_PRCPU *)arg; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(NULL != me); + + /* + * _PR_StartCPU calls _PR_CreateThread to create the + * idle thread. Because _PR_CreateThread calls PR_Lock, + * the current thread has to remain a global thread + * during the _PR_StartCPU call so that it can wait for + * the lock if the lock is held by another thread. If + * we clear the _PR_GLOBAL_SCOPE flag in + * _PR_MD_CREATE_PRIMORDIAL_THREAD, the current thread + * will be treated as a local thread and have trouble + * waiting for the lock because the CPU is not fully + * constructed yet. + * + * After the CPU is started, it is safe to mark the + * current thread as a local thread. + */ + +#ifdef HAVE_CUSTOM_USER_THREADS + _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me); +#endif + + me->no_sched = 1; + _PR_StartCPU(cpu, me); + +#ifdef HAVE_CUSTOM_USER_THREADS + me->flags &= (~_PR_GLOBAL_SCOPE); +#endif + + _PR_MD_SET_CURRENT_CPU(cpu); + _PR_MD_SET_CURRENT_THREAD(cpu->thread); + me->cpu = cpu; + + while(1) { + PRInt32 is; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_MD_START_INTERRUPTS(); + _PR_MD_SWITCH_CONTEXT(me); + } +} +#endif + +static void PR_CALLBACK _PR_CPU_Idle(void *_cpu) +{ + _PRCPU *cpu = (_PRCPU *)_cpu; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(NULL != me); + + me->cpu = cpu; + cpu->idle_thread = me; + if (_MD_LAST_THREAD()) + _MD_LAST_THREAD()->no_sched = 0; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_MD_SET_INTSOFF(0); + while(1) { + PRInt32 is; + PRIntervalTime timeout; + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + + _PR_RUNQ_LOCK(cpu); +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifdef _PR_HAVE_ATOMIC_OPS + _PR_MD_ATOMIC_INCREMENT(&_pr_md_idle_cpus); +#else + _PR_MD_LOCK(&_pr_md_idle_cpus_lock); + _pr_md_idle_cpus++; + _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock); +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif + /* If someone on runq; do a nonblocking PAUSECPU */ + if (_PR_RUNQREADYMASK(me->cpu) != 0) { + _PR_RUNQ_UNLOCK(cpu); + timeout = PR_INTERVAL_NO_WAIT; + } else { + _PR_RUNQ_UNLOCK(cpu); + + _PR_SLEEPQ_LOCK(cpu); + if (PR_CLIST_IS_EMPTY(&_PR_SLEEPQ(me->cpu))) { + timeout = PR_INTERVAL_NO_TIMEOUT; + } else { + PRThread *wakeThread; + wakeThread = _PR_THREAD_PTR(_PR_SLEEPQ(me->cpu).next); + timeout = wakeThread->sleep; + } + _PR_SLEEPQ_UNLOCK(cpu); + } + + /* Wait for an IO to complete */ + (void)_PR_MD_PAUSE_CPU(timeout); + +#ifdef WINNT + if (_pr_cpus_exit) { + /* _PR_CleanupCPUs tells us to exit */ + _PR_MD_END_THREAD(); + } +#endif + +#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY) +#ifdef _PR_HAVE_ATOMIC_OPS + _PR_MD_ATOMIC_DECREMENT(&_pr_md_idle_cpus); +#else + _PR_MD_LOCK(&_pr_md_idle_cpus_lock); + _pr_md_idle_cpus--; + _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock); +#endif /* _PR_HAVE_ATOMIC_OPS */ +#endif + + _PR_ClockInterrupt(); + + /* Now schedule any thread that is on the runq + * INTS must be OFF when calling PR_Schedule() + */ + me->state = _PR_RUNNABLE; + _PR_MD_SWITCH_CONTEXT(me); + if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is); + } +} +#endif /* _PR_GLOBAL_THREADS_ONLY */ + +PR_IMPLEMENT(void) PR_SetConcurrency(PRUintn numCPUs) +{ +#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY) +#ifdef XP_MAC +#pragma unused(numCPUs) +#endif + + /* do nothing */ + +#else /* combined, MxN thread model */ + + PRUintn newCPU; + _PRCPU *cpu; + PRThread *thr; + + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (_native_threads_only) + return; + + _PR_CPU_LIST_LOCK(); + if (_pr_numCPU < numCPUs) { + newCPU = numCPUs - _pr_numCPU; + _pr_numCPU = numCPUs; + } else newCPU = 0; + _PR_CPU_LIST_UNLOCK(); + + for (; newCPU; newCPU--) { + cpu = _PR_CreateCPU(); + thr = _PR_CreateThread(PR_SYSTEM_THREAD, + _PR_RunCPU, + cpu, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, + _PR_IDLE_THREAD); + } +#endif +} + +PR_IMPLEMENT(_PRCPU *) _PR_GetPrimordialCPU(void) +{ + if (_pr_primordialCPU) + return _pr_primordialCPU; + else + return _PR_MD_CURRENT_CPU(); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucv.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucv.c new file mode 100644 index 00000000..80d919b8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prucv.c @@ -0,0 +1,681 @@ +/* -*- 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 "prinrval.h" +#include "prtypes.h" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +/* +** Notify one thread that it has finished waiting on a condition variable +** Caller must hold the _PR_CVAR_LOCK(cv) +*/ +PRBool _PR_NotifyThread (PRThread *thread, PRThread *me) +{ + PRBool rv; + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + _PR_THREAD_LOCK(thread); + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + if (thread->wait.cvar != NULL) { + thread->wait.cvar = NULL; + + _PR_SLEEPQ_LOCK(thread->cpu); + /* The notify and timeout can collide; in which case both may + * attempt to delete from the sleepQ; only let one do it. + */ + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) + _PR_DEL_SLEEPQ(thread, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thread->cpu); + + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will move it to the runQ + */ + thread->state = _PR_SUSPENDED; + _PR_MISCQ_LOCK(thread->cpu); + _PR_ADD_SUSPENDQ(thread, thread->cpu); + _PR_MISCQ_UNLOCK(thread->cpu); + _PR_THREAD_UNLOCK(thread); + } else { + /* Make thread runnable */ + thread->state = _PR_RUNNABLE; + _PR_THREAD_UNLOCK(thread); + + _PR_AddThreadToRunQ(me, thread); + _PR_MD_WAKEUP_WAITER(thread); + } + + rv = PR_TRUE; + } else { + /* Thread has already been notified */ + _PR_THREAD_UNLOCK(thread); + rv = PR_FALSE; + } + } else { /* If the thread is a native thread */ + if (thread->wait.cvar) { + thread->wait.cvar = NULL; + + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will enable the thread to run + */ + thread->state = _PR_SUSPENDED; + } else + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + _PR_MD_WAKEUP_WAITER(thread); + rv = PR_TRUE; + } else { + _PR_THREAD_UNLOCK(thread); + rv = PR_FALSE; + } + } + + return rv; +} + +/* + * Notify thread waiting on cvar; called when thread is interrupted + * The thread lock is held on entry and released before return + */ +void _PR_NotifyLockedThread (PRThread *thread) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCondVar *cvar; + PRThreadPriority pri; + + if ( !_PR_IS_NATIVE_THREAD(me)) + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + cvar = thread->wait.cvar; + thread->wait.cvar = NULL; + _PR_THREAD_UNLOCK(thread); + + _PR_CVAR_LOCK(cvar); + _PR_THREAD_LOCK(thread); + + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_SLEEPQ_LOCK(thread->cpu); + /* The notify and timeout can collide; in which case both may + * attempt to delete from the sleepQ; only let one do it. + */ + if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) + _PR_DEL_SLEEPQ(thread, PR_TRUE); + _PR_SLEEPQ_UNLOCK(thread->cpu); + + /* Make thread runnable */ + pri = thread->priority; + thread->state = _PR_RUNNABLE; + + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + + _PR_AddThreadToRunQ(me, thread); + _PR_THREAD_UNLOCK(thread); + + _PR_MD_WAKEUP_WAITER(thread); + } else { + if (thread->flags & _PR_SUSPENDING) { + /* + * set thread state to SUSPENDED; a Resume operation + * on the thread will enable the thread to run + */ + thread->state = _PR_SUSPENDED; + } else + thread->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(thread); + _PR_MD_WAKEUP_WAITER(thread); + } + + _PR_CVAR_UNLOCK(cvar); + return; +} + +/* +** Make the given thread wait for the given condition variable +*/ +PRStatus _PR_WaitCondVar( + PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) +{ + PRIntn is; + PRStatus rv = PR_SUCCESS; + + PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + +#ifdef _PR_GLOBAL_THREADS_ONLY + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + thread->wait.cvar = cvar; + lock->owner = NULL; + _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout); + thread->wait.cvar = NULL; + lock->owner = thread; + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSOFF(is); + + _PR_CVAR_LOCK(cvar); + _PR_THREAD_LOCK(thread); + + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + _PR_CVAR_UNLOCK(cvar); + _PR_THREAD_UNLOCK(thread); + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSON(is); + return PR_FAILURE; + } + + thread->state = _PR_COND_WAIT; + thread->wait.cvar = cvar; + + /* + ** Put the caller thread on the condition variable's wait Q + */ + PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ); + + /* Note- for global scope threads, we don't put them on the + * global sleepQ, so each global thread must put itself + * to sleep only for the time it wants to. + */ + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_SLEEPQ_LOCK(thread->cpu); + _PR_ADD_SLEEPQ(thread, timeout); + _PR_SLEEPQ_UNLOCK(thread->cpu); + } + _PR_CVAR_UNLOCK(cvar); + _PR_THREAD_UNLOCK(thread); + + /* + ** Release lock protecting the condition variable and thereby giving time + ** to the next thread which can potentially notify on the condition variable + */ + PR_Unlock(lock); + + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, + ("PR_Wait: cvar=%p waiting for %d", cvar, timeout)); + + rv = _PR_MD_WAIT(thread, timeout); + + _PR_CVAR_LOCK(cvar); + PR_REMOVE_LINK(&thread->waitQLinks); + _PR_CVAR_UNLOCK(cvar); + + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, + ("PR_Wait: cvar=%p done waiting", cvar)); + + if ( !_PR_IS_NATIVE_THREAD(thread)) + _PR_INTSON(is); + + /* Acquire lock again that we had just relinquished */ + PR_Lock(lock); + + if (_PR_PENDING_INTERRUPT(thread)) { + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); + thread->flags &= ~_PR_INTERRUPT; + return PR_FAILURE; + } + + return rv; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me) +{ +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock); +#else /* _PR_GLOBAL_THREADS_ONLY */ + + PRCList *q; + PRIntn is; + + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + _PR_CVAR_LOCK(cvar); + q = cvar->condQ.next; + while (q != &cvar->condQ) { +#ifndef XP_MAC + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar)); +#endif + if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar) { + if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE) + break; + } + q = q->next; + } + _PR_CVAR_UNLOCK(cvar); + + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Cndition variable debugging log info. +*/ +PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen) +{ + PRUint32 nb; + + if (cvar->lock->owner) { + nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]", + cvar, cvar->lock->owner->id, cvar->lock->owner); + } else { + nb = PR_snprintf(buf, buflen, "[%p]", cvar); + } + return nb; +} + +/* +** Expire condition variable waits that are ready to expire. "now" is the current +** time. +*/ +void _PR_ClockInterrupt(void) +{ + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = me->cpu; + PRIntervalTime elapsed, now; + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + /* Figure out how much time elapsed since the last clock tick */ + now = PR_IntervalNow(); + elapsed = now - cpu->last_clock; + cpu->last_clock = now; + +#ifndef XP_MAC + PR_LOG(_pr_clock_lm, PR_LOG_MAX, + ("ExpireWaits: elapsed=%lld usec", elapsed)); +#endif + + while(1) { + _PR_SLEEPQ_LOCK(cpu); + if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) { + _PR_SLEEPQ_UNLOCK(cpu); + break; + } + + thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next); + PR_ASSERT(thread->cpu == cpu); + + if (elapsed < thread->sleep) { + thread->sleep -= elapsed; + _PR_SLEEPQMAX(thread->cpu) -= elapsed; + _PR_SLEEPQ_UNLOCK(cpu); + break; + } + _PR_SLEEPQ_UNLOCK(cpu); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + + _PR_THREAD_LOCK(thread); + + if (thread->cpu != cpu) { + /* + ** The thread was switched to another CPU + ** between the time we unlocked the sleep + ** queue and the time we acquired the thread + ** lock, so it is none of our business now. + */ + _PR_THREAD_UNLOCK(thread); + continue; + } + + /* + ** Consume this sleeper's amount of elapsed time from the elapsed + ** time value. The next remaining piece of elapsed time will be + ** available for the next sleeping thread's timer. + */ + _PR_SLEEPQ_LOCK(cpu); + PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ)); + if (thread->flags & _PR_ON_SLEEPQ) { + _PR_DEL_SLEEPQ(thread, PR_FALSE); + elapsed -= thread->sleep; + _PR_SLEEPQ_UNLOCK(cpu); + } else { + /* Thread was already handled; Go get another one */ + _PR_SLEEPQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(thread); + continue; + } + + /* Notify the thread waiting on the condition variable */ + if (thread->flags & _PR_SUSPENDING) { + PR_ASSERT((thread->state == _PR_IO_WAIT) || + (thread->state == _PR_COND_WAIT)); + /* + ** Thread is suspended and its condition timeout + ** expired. Transfer thread from sleepQ to suspendQ. + */ + thread->wait.cvar = NULL; + _PR_MISCQ_LOCK(cpu); + thread->state = _PR_SUSPENDED; + _PR_ADD_SUSPENDQ(thread, cpu); + _PR_MISCQ_UNLOCK(cpu); + } else { + if (thread->wait.cvar) { + PRThreadPriority pri; + + /* Do work very similar to what _PR_NotifyThread does */ + PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) ); + + /* Make thread runnable */ + pri = thread->priority; + thread->state = _PR_RUNNABLE; + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + + PR_ASSERT(thread->cpu == cpu); + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + + if (pri > me->priority) + _PR_SET_RESCHED_FLAG(); + + thread->wait.cvar = NULL; + + _PR_MD_WAKEUP_WAITER(thread); + + } else if (thread->io_pending == PR_TRUE) { + /* Need to put IO sleeper back on runq */ + int pri = thread->priority; + + thread->io_suspended = PR_TRUE; +#ifdef WINNT + /* + * For NT, record the cpu on which I/O was issued + * I/O cancellation is done on the same cpu + */ + thread->md.thr_bound_cpu = cpu; +#endif + + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + PR_ASSERT(thread->cpu == cpu); + thread->state = _PR_RUNNABLE; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } + } + _PR_THREAD_UNLOCK(thread); + } +} + +/************************************************************************/ + +/* +** Create a new condition variable. +** "lock" is the lock to use with the condition variable. +** +** Condition variables are synchronization objects that threads can use +** to wait for some condition to occur. +** +** This may fail if memory is tight or if some operating system resource +** is low. +*/ +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) +{ + PRCondVar *cvar; + + PR_ASSERT(lock != NULL); + + cvar = PR_NEWZAP(PRCondVar); + if (cvar) { +#ifdef _PR_GLOBAL_THREADS_ONLY + if(_PR_MD_NEW_CV(&cvar->md)) { + PR_DELETE(cvar); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } +#endif + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) { + PR_DELETE(cvar); + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } + cvar->lock = lock; + PR_INIT_CLIST(&cvar->condQ); + + } else { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + } + return cvar; +} + +/* +** Destroy a condition variable. There must be no thread +** waiting on the condvar. The caller is responsible for guaranteeing +** that the condvar is no longer in use. +** +*/ +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar->condQ.next == &cvar->condQ); + +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_FREE_CV(&cvar->md); +#endif + _PR_MD_FREE_LOCK(&(cvar->ilock)); + + PR_DELETE(cvar); +} + +/* +** Wait for a notify on the condition variable. Sleep for "tiemout" amount +** of ticks (if "timeout" is zero then the sleep is indefinite). While +** the thread is waiting it unlocks lock. When the wait has +** finished the thread regains control of the condition variable after +** locking the associated lock. +** +** The thread waiting on the condvar will be resumed when the condvar is +** notified (assuming the thread is the next in line to receive the +** notify) or when the timeout elapses. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable or the thread has been interrupted. +*/ +extern PRThread *suspendAllThread; +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + PR_ASSERT(me != suspendAllThread); + if (cvar->lock->owner != me) return PR_FAILURE; + + return _PR_WaitCondVar(me, cvar, cvar->lock, timeout); +} + +/* +** Notify the highest priority thread waiting on the condition +** variable. If a thread is waiting on the condition variable (using +** PR_Wait) then it is awakened and begins waiting on the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + PR_ASSERT(me != suspendAllThread); + if (cvar->lock->owner != me) return PR_FAILURE; + + _PR_NotifyCondVar(cvar, me); + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. All of +** threads are notified in turn. The highest priority thread will +** probably acquire the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) +{ + PRCList *q; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(cvar->lock->owner == me); + if (cvar->lock->owner != me) return PR_FAILURE; + +#ifdef _PR_GLOBAL_THREADS_ONLY + _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock); + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + if ( !_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_CVAR_LOCK(cvar); + q = cvar->condQ.next; + while (q != &cvar->condQ) { + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); + q = q->next; + } + _PR_CVAR_UNLOCK(cvar); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + + +/*********************************************************************/ +/*********************************************************************/ +/********************ROUTINES FOR DCE EMULATION***********************/ +/*********************************************************************/ +/*********************************************************************/ +#include "prpdce.h" + +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) +{ + PRCondVar *cvar = PR_NEWZAP(PRCondVar); + if (NULL != cvar) + { + if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) + { + PR_DELETE(cvar); cvar = NULL; + } + else + { + PR_INIT_CLIST(&cvar->condQ); + cvar->lock = _PR_NAKED_CV_LOCK; + } + + } + return cvar; +} + +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) +{ + PR_ASSERT(cvar->condQ.next == &cvar->condQ); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + _PR_MD_FREE_LOCK(&(cvar->ilock)); + + PR_DELETE(cvar); +} + +PR_IMPLEMENT(PRStatus) PRP_NakedWait( + PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + return _PR_WaitCondVar(me, cvar, lock, timeout); +} /* PRP_NakedWait */ + +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + _PR_NotifyCondVar(cvar, me); + + return PR_SUCCESS; +} /* PRP_NakedNotify */ + +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) +{ + PRCList *q; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_MD_LOCK( &(cvar->ilock) ); + q = cvar->condQ.next; + while (q != &cvar->condQ) { + PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar)); + _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me); + q = q->next; + } + _PR_MD_UNLOCK( &(cvar->ilock) ); + if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); + + return PR_SUCCESS; +} /* PRP_NakedBroadcast */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prulock.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prulock.c new file mode 100644 index 00000000..5ede1c7b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prulock.c @@ -0,0 +1,463 @@ +/* -*- 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" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +void _PR_InitLocks(void) +{ + _PR_MD_INIT_LOCKS(); +} + +/* +** Deal with delayed interrupts/requested reschedule during interrupt +** re-enables. +*/ +void _PR_IntsOn(_PRCPU *cpu) +{ + PRUintn missed, pri, i; + _PRInterruptTable *it; + PRThread *me; + + PR_ASSERT(cpu); /* Global threads don't have CPUs */ + PR_ASSERT(_PR_MD_GET_INTSOFF() > 0); + me = _PR_MD_CURRENT_THREAD(); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + + /* + ** Process delayed interrupts. This logic is kinda scary because we + ** need to avoid losing an interrupt (it's ok to delay an interrupt + ** until later). + ** + ** There are two missed state words. _pr_ints.where indicates to the + ** interrupt handler which state word is currently safe for + ** modification. + ** + ** This code scans both interrupt state words, using the where flag + ** to indicate to the interrupt which state word is safe for writing. + ** If an interrupt comes in during a scan the other word will be + ** modified. This modification will be noticed during the next + ** iteration of the loop or during the next call to this routine. + */ + for (i = 0; i < 2; i++) { + cpu->where = (1 - i); + missed = cpu->u.missed[i]; + if (missed != 0) { + cpu->u.missed[i] = 0; + for (it = _pr_interruptTable; it->name; it++) { + if (missed & it->missed_bit) { +#ifndef XP_MAC + PR_LOG(_pr_sched_lm, PR_LOG_MIN, + ("IntsOn[0]: %s intr", it->name)); +#endif + (*it->handler)(); + } + } + } + } + + if (cpu->u.missed[3] != 0) { + _PRCPU *cpu; + + _PR_THREAD_LOCK(me); + me->state = _PR_RUNNABLE; + pri = me->priority; + + cpu = me->cpu; + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + _PR_THREAD_UNLOCK(me); + _PR_MD_SWITCH_CONTEXT(me); + } +} + +/* +** Unblock the first runnable waiting thread. Skip over +** threads that are trying to be suspended +** Note: Caller must hold _PR_LOCK_LOCK() +*/ +void _PR_UnblockLockWaiter(PRLock *lock) +{ + PRThread *t = NULL; + PRThread *me; + PRCList *q; + + q = lock->waitQ.next; + PR_ASSERT(q != &lock->waitQ); + while (q != &lock->waitQ) { + /* Unblock first waiter */ + t = _PR_THREAD_CONDQ_PTR(q); + + /* + ** We are about to change the thread's state to runnable and for local + ** threads, we are going to assign a cpu to it. So, protect thread's + ** data structure. + */ + _PR_THREAD_LOCK(t); + + if (t->flags & _PR_SUSPENDING) { + q = q->next; + _PR_THREAD_UNLOCK(t); + continue; + } + + /* Found a runnable thread */ + PR_ASSERT(t->state == _PR_LOCK_WAIT); + PR_ASSERT(t->wait.lock == lock); + t->wait.lock = 0; + PR_REMOVE_LINK(&t->waitQLinks); /* take it off lock's waitQ */ + + /* + ** If this is a native thread, nothing else to do except to wake it + ** up by calling the machine dependent wakeup routine. + ** + ** If this is a local thread, we need to assign it a cpu and + ** put the thread on that cpu's run queue. There are two cases to + ** take care of. If the currently running thread is also a local + ** thread, we just assign our own cpu to that thread and put it on + ** the cpu's run queue. If the the currently running thread is a + ** native thread, we assign the primordial cpu to it (on NT, + ** MD_WAKEUP handles the cpu assignment). + */ + + if ( !_PR_IS_NATIVE_THREAD(t) ) { + + t->state = _PR_RUNNABLE; + + me = _PR_MD_CURRENT_THREAD(); + + _PR_AddThreadToRunQ(me, t); + _PR_THREAD_UNLOCK(t); + } else { + t->state = _PR_RUNNING; + _PR_THREAD_UNLOCK(t); + } + _PR_MD_WAKEUP_WAITER(t); + break; + } + return; +} + +/************************************************************************/ + + +PR_IMPLEMENT(PRLock*) PR_NewLock(void) +{ + PRLock *lock; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + lock = PR_NEWZAP(PRLock); + if (lock) { + if (_PR_MD_NEW_LOCK(&lock->ilock) == PR_FAILURE) { + PR_DELETE(lock); + return(NULL); + } + PR_INIT_CLIST(&lock->links); + PR_INIT_CLIST(&lock->waitQ); + } + return lock; +} + +/* +** Destroy the given lock "lock". There is no point in making this race +** free because if some other thread has the pointer to this lock all +** bets are off. +*/ +PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) +{ + PR_ASSERT(lock->owner == 0); + _PR_MD_FREE_LOCK(&lock->ilock); + PR_DELETE(lock); +} + +extern PRThread *suspendAllThread; +/* +** Lock the lock. +*/ +PR_IMPLEMENT(void) PR_Lock(PRLock *lock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + PRThread *t; + PRCList *q; + + PR_ASSERT(me != suspendAllThread); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + PR_ASSERT(lock != NULL); +#ifdef _PR_GLOBAL_THREADS_ONLY + PR_ASSERT(lock->owner != me); + _PR_MD_LOCK(&lock->ilock); + lock->owner = me; + return; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if (_native_threads_only) { + PR_ASSERT(lock->owner != me); + _PR_MD_LOCK(&lock->ilock); + lock->owner = me; + return; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + +retry: + _PR_LOCK_LOCK(lock); + if (lock->owner == 0) { + /* Just got the lock */ + lock->owner = me; + lock->priority = me->priority; + /* Add the granted lock to this owning thread's lock list */ + PR_APPEND_LINK(&lock->links, &me->lockList); + _PR_LOCK_UNLOCK(lock); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_FAST_INTSON(is); + return; + } + + /* If this thread already owns this lock, then it is a deadlock */ + PR_ASSERT(lock->owner != me); + + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + +#if 0 + if (me->priority > lock->owner->priority) { + /* + ** Give the lock owner a priority boost until we get the + ** lock. Record the priority we boosted it to. + */ + lock->boostPriority = me->priority; + _PR_SetThreadPriority(lock->owner, me->priority); + } +#endif + + /* + Add this thread to the asked for lock's list of waiting threads. We + add this thread thread in the right priority order so when the unlock + occurs, the thread with the higher priority will get the lock. + */ + q = lock->waitQ.next; + if (q == &lock->waitQ || _PR_THREAD_CONDQ_PTR(q)->priority == + _PR_THREAD_CONDQ_PTR(lock->waitQ.prev)->priority) { + /* + * If all the threads in the lock waitQ have the same priority, + * then avoid scanning the list: insert the element at the end. + */ + q = &lock->waitQ; + } else { + /* Sort thread into lock's waitQ at appropriate point */ + /* Now scan the list for where to insert this entry */ + while (q != &lock->waitQ) { + t = _PR_THREAD_CONDQ_PTR(lock->waitQ.next); + if (me->priority > t->priority) { + /* Found a lower priority thread to insert in front of */ + break; + } + q = q->next; + } + } + PR_INSERT_BEFORE(&me->waitQLinks, q); + + /* + Now grab the threadLock since we are about to change the state. We have + to do this since a PR_Suspend or PR_SetThreadPriority type call that takes + a PRThread* as an argument could be changing the state of this thread from + a thread running on a different cpu. + */ + + _PR_THREAD_LOCK(me); + me->state = _PR_LOCK_WAIT; + me->wait.lock = lock; + _PR_THREAD_UNLOCK(me); + + _PR_LOCK_UNLOCK(lock); + + _PR_MD_WAIT(me, PR_INTERVAL_NO_TIMEOUT); + goto retry; + +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Unlock the lock. +*/ +PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) +{ + PRCList *q; + PRThreadPriority pri, boost; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(lock != NULL); + PR_ASSERT(lock->owner == me); + PR_ASSERT(me != suspendAllThread); +#if !defined(XP_MAC) + PR_ASSERT(!(me->flags & _PR_IDLE_THREAD)); +#endif + if (lock->owner != me) { + return PR_FAILURE; + } + +#ifdef _PR_GLOBAL_THREADS_ONLY + lock->owner = 0; + _PR_MD_UNLOCK(&lock->ilock); + return PR_SUCCESS; +#else /* _PR_GLOBAL_THREADS_ONLY */ + + if (_native_threads_only) { + lock->owner = 0; + _PR_MD_UNLOCK(&lock->ilock); + return PR_SUCCESS; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_LOCK_LOCK(lock); + + /* Remove the lock from the owning thread's lock list */ + PR_REMOVE_LINK(&lock->links); + pri = lock->priority; + boost = lock->boostPriority; + if (boost > pri) { + /* + ** We received a priority boost during the time we held the lock. + ** We need to figure out what priority to move to by scanning + ** down our list of lock's that we are still holding and using + ** the highest boosted priority found. + */ + q = me->lockList.next; + while (q != &me->lockList) { + PRLock *ll = _PR_LOCK_PTR(q); + if (ll->boostPriority > pri) { + pri = ll->boostPriority; + } + q = q->next; + } + if (pri != me->priority) { + _PR_SetThreadPriority(me, pri); + } + } + + /* Unblock the first waiting thread */ + q = lock->waitQ.next; + if (q != &lock->waitQ) + _PR_UnblockLockWaiter(lock); + lock->boostPriority = PR_PRIORITY_LOW; + lock->owner = 0; + _PR_LOCK_UNLOCK(lock); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Test and then lock the lock if it's not already locked by some other +** thread. Return PR_FALSE if some other thread owned the lock at the +** time of the call. +*/ +PR_IMPLEMENT(PRBool) PR_TestAndLock(PRLock *lock) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRBool rv = PR_FALSE; + PRIntn is; + +#ifdef _PR_GLOBAL_THREADS_ONLY + is = _PR_MD_TEST_AND_LOCK(&lock->ilock); + if (is == 0) { + lock->owner = me; + return PR_TRUE; + } + return PR_FALSE; +#else /* _PR_GLOBAL_THREADS_ONLY */ + +#ifndef _PR_LOCAL_THREADS_ONLY + if (_native_threads_only) { + is = _PR_MD_TEST_AND_LOCK(&lock->ilock); + if (is == 0) { + lock->owner = me; + return PR_TRUE; + } + return PR_FALSE; + } +#endif + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + _PR_LOCK_LOCK(lock); + if (lock->owner == 0) { + /* Just got the lock */ + lock->owner = me; + lock->priority = me->priority; + /* Add the granted lock to this owning thread's lock list */ + PR_APPEND_LINK(&lock->links, &me->lockList); + rv = PR_TRUE; + } + _PR_LOCK_UNLOCK(lock); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return rv; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/************************************************************************/ +/************************************************************************/ +/***********************ROUTINES FOR DCE EMULATION***********************/ +/************************************************************************/ +/************************************************************************/ +PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) + { return (PR_TestAndLock(lock)) ? PR_SUCCESS : PR_FAILURE; } diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prustack.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prustack.c new file mode 100644 index 00000000..fe15843c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/prustack.c @@ -0,0 +1,206 @@ +/* -*- 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" + +/* List of free stack virtual memory chunks */ +PRLock *_pr_stackLock; +PRCList _pr_freeStacks = PR_INIT_STATIC_CLIST(&_pr_freeStacks); +PRIntn _pr_numFreeStacks; +PRIntn _pr_maxFreeStacks = 4; + +#ifdef DEBUG +/* +** A variable that can be set via the debugger... +*/ +PRBool _pr_debugStacks = PR_FALSE; +#endif + +/* How much space to leave between the stacks, at each end */ +#define REDZONE (2 << _pr_pageShift) + +#define _PR_THREAD_STACK_PTR(_qp) \ + ((PRThreadStack*) ((char*) (_qp) - offsetof(PRThreadStack,links))) + +void _PR_InitStacks(void) +{ + _pr_stackLock = PR_NewLock(); +} + +void _PR_CleanupStacks(void) +{ + if (_pr_stackLock) { + PR_DestroyLock(_pr_stackLock); + _pr_stackLock = NULL; + } +} + +/* +** Allocate a stack for a thread. +*/ +PRThreadStack *_PR_NewStack(PRUint32 stackSize) +{ + PRCList *qp; + PRThreadStack *ts; + PRThread *thr; + + /* + ** Trim the list of free stacks. Trim it backwards, tossing out the + ** oldest stack found first (this way more recent stacks have a + ** chance of being present in the data cache). + */ + PR_Lock(_pr_stackLock); + qp = _pr_freeStacks.prev; + while ((_pr_numFreeStacks > _pr_maxFreeStacks) && (qp != &_pr_freeStacks)) { + ts = _PR_THREAD_STACK_PTR(qp); + thr = _PR_THREAD_STACK_TO_PTR(ts); + qp = qp->prev; + /* + * skip stacks which are still being used + */ + if (thr->no_sched) + continue; + PR_REMOVE_LINK(&ts->links); + + /* Give platform OS to clear out the stack for debugging */ + _PR_MD_CLEAR_STACK(ts); + + _pr_numFreeStacks--; + _PR_DestroySegment(ts->seg); + PR_DELETE(ts); + } + + /* + ** Find a free thread stack. This searches the list of free'd up + ** virtually mapped thread stacks. + */ + qp = _pr_freeStacks.next; + ts = 0; + while (qp != &_pr_freeStacks) { + ts = _PR_THREAD_STACK_PTR(qp); + thr = _PR_THREAD_STACK_TO_PTR(ts); + qp = qp->next; + /* + * skip stacks which are still being used + */ + if ((!(thr->no_sched)) && ((ts->allocSize - 2*REDZONE) >= stackSize)) { + /* + ** Found a stack that is not in use and is big enough. Change + ** stackSize to fit it. + */ + stackSize = ts->allocSize - 2*REDZONE; + PR_REMOVE_LINK(&ts->links); + _pr_numFreeStacks--; + ts->links.next = 0; + ts->links.prev = 0; + PR_Unlock(_pr_stackLock); + goto done; + } + ts = 0; + } + PR_Unlock(_pr_stackLock); + + if (!ts) { + /* Make a new thread stack object. */ + ts = PR_NEWZAP(PRThreadStack); + if (!ts) { + return NULL; + } + + /* + ** Assign some of the virtual space to the new stack object. We + ** may not get that piece of VM, but if nothing else we will + ** advance the pointer so we don't collide (unless the OS screws + ** up). + */ + ts->allocSize = stackSize + 2*REDZONE; + ts->seg = _PR_NewSegment(ts->allocSize, 0); + if (!ts->seg) { + PR_DELETE(ts); + return NULL; + } + } + + done: + ts->allocBase = (char*)ts->seg->vaddr; + ts->flags = _PR_STACK_MAPPED; + ts->stackSize = stackSize; + +#ifdef HAVE_STACK_GROWING_UP + ts->stackTop = ts->allocBase + REDZONE; + ts->stackBottom = ts->stackTop + stackSize; +#else + ts->stackBottom = ts->allocBase + REDZONE; + ts->stackTop = ts->stackBottom + stackSize; +#endif + + PR_LOG(_pr_thread_lm, PR_LOG_NOTICE, + ("thread stack: base=0x%x limit=0x%x bottom=0x%x top=0x%x\n", + ts->allocBase, ts->allocBase + ts->allocSize - 1, + ts->allocBase + REDZONE, + ts->allocBase + REDZONE + stackSize - 1)); + + _PR_MD_INIT_STACK(ts,REDZONE); + + return ts; +} + +/* +** Free the stack for the current thread +*/ +void _PR_FreeStack(PRThreadStack *ts) +{ + if (!ts) { + return; + } + if (ts->flags & _PR_STACK_PRIMORDIAL) { + PR_DELETE(ts); + return; + } + + /* + ** Put the stack on the free list. This is done because we are still + ** using the stack. Next time a thread is created we will trim the + ** list down; it's safe to do it then because we will have had to + ** context switch to a live stack before another thread can be + ** created. + */ + PR_Lock(_pr_stackLock); + PR_APPEND_LINK(&ts->links, _pr_freeStacks.prev); + _pr_numFreeStacks++; + PR_Unlock(_pr_stackLock); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/pruthr.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/pruthr.c new file mode 100644 index 00000000..7e31b56b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/combined/pruthr.c @@ -0,0 +1,1918 @@ +/* -*- 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 +#include + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +#if defined(XP_MAC) +#include +#endif + +/* _pr_activeLock protects the following global variables */ +PRLock *_pr_activeLock; +PRInt32 _pr_primordialExitCount; /* In PR_Cleanup(), the primordial thread + * waits until all other user (non-system) + * threads have terminated before it exits. + * So whenever we decrement _pr_userActive, + * it is compared with + * _pr_primordialExitCount. + * If the primordial thread is a system + * thread, then _pr_primordialExitCount + * is 0. If the primordial thread is + * itself a user thread, then + * _pr_primordialThread is 1. + */ +PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to + * _pr_primordialExitCount, this condition + * variable is notified. + */ + +PRLock *_pr_deadQLock; +PRUint32 _pr_numNativeDead; +PRUint32 _pr_numUserDead; +PRCList _pr_deadNativeQ; +PRCList _pr_deadUserQ; + +PRUint32 _pr_join_counter; + +PRUint32 _pr_local_threads; +PRUint32 _pr_global_threads; + +PRBool suspendAllOn = PR_FALSE; +PRThread *suspendAllThread = NULL; + +extern PRCList _pr_active_global_threadQ; +extern PRCList _pr_active_local_threadQ; + +static void _PR_DecrActiveThreadCount(PRThread *thread); +static PRThread *_PR_AttachThread(PRThreadType, PRThreadPriority, PRThreadStack *); +static void _PR_InitializeNativeStack(PRThreadStack *ts); +static void _PR_InitializeRecycledThread(PRThread *thread); +static void _PR_UserRunThread(void); + +void _PR_InitThreads(PRThreadType type, PRThreadPriority priority, + PRUintn maxPTDs) +{ +#if defined(XP_MAC) +#pragma unused (maxPTDs) +#endif + + PRThread *thread; + PRThreadStack *stack; + + _pr_terminationCVLock = PR_NewLock(); + _pr_activeLock = PR_NewLock(); + +#ifndef HAVE_CUSTOM_USER_THREADS + stack = PR_NEWZAP(PRThreadStack); +#ifdef HAVE_STACK_GROWING_UP + stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift) + << _pr_pageShift); +#else +#if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS) + stack->stackTop = (char*) &thread; +#elif defined(XP_MAC) + stack->stackTop = (char*) LMGetCurStackBase(); +#else + stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1) + >> _pr_pageShift) << _pr_pageShift); +#endif +#endif +#else + /* If stack is NULL, we're using custom user threads like NT fibers. */ + stack = PR_NEWZAP(PRThreadStack); + if (stack) { + stack->stackSize = 0; + _PR_InitializeNativeStack(stack); + } +#endif /* HAVE_CUSTOM_USER_THREADS */ + + thread = _PR_AttachThread(type, priority, stack); + if (thread) { + _PR_MD_SET_CURRENT_THREAD(thread); + + if (type == PR_SYSTEM_THREAD) { + thread->flags = _PR_SYSTEM; + _pr_systemActive++; + _pr_primordialExitCount = 0; + } else { + _pr_userActive++; + _pr_primordialExitCount = 1; + } + thread->no_sched = 1; + _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock); + } + + if (!thread) PR_Abort(); +#ifdef _PR_LOCAL_THREADS_ONLY + thread->flags |= _PR_PRIMORDIAL; +#else + thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE; +#endif + + /* + * Needs _PR_PRIMORDIAL flag set before calling + * _PR_MD_INIT_THREAD() + */ + if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { + /* + * XXX do what? + */ + } + + if (_PR_IS_NATIVE_THREAD(thread)) { + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); + _pr_global_threads++; + } else { + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); + _pr_local_threads++; + } + + _pr_recycleThreads = 0; + _pr_deadQLock = PR_NewLock(); + _pr_numNativeDead = 0; + _pr_numUserDead = 0; + PR_INIT_CLIST(&_pr_deadNativeQ); + PR_INIT_CLIST(&_pr_deadUserQ); +} + +void _PR_CleanupThreads(void) +{ + if (_pr_terminationCVLock) { + PR_DestroyLock(_pr_terminationCVLock); + _pr_terminationCVLock = NULL; + } + if (_pr_activeLock) { + PR_DestroyLock(_pr_activeLock); + _pr_activeLock = NULL; + } + if (_pr_primordialExitCVar) { + PR_DestroyCondVar(_pr_primordialExitCVar); + _pr_primordialExitCVar = NULL; + } + /* TODO _pr_dead{Native,User}Q need to be deleted */ + if (_pr_deadQLock) { + PR_DestroyLock(_pr_deadQLock); + _pr_deadQLock = NULL; + } +} + +/* +** Initialize a stack for a native thread +*/ +static void _PR_InitializeNativeStack(PRThreadStack *ts) +{ + if( ts && (ts->stackTop == 0) ) { + ts->allocSize = ts->stackSize; + + /* + ** Setup stackTop and stackBottom values. + */ +#ifdef HAVE_STACK_GROWING_UP + ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift) + << _pr_pageShift); + ts->stackBottom = ts->allocBase + ts->stackSize; + ts->stackTop = ts->allocBase; +#else + ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1) + >> _pr_pageShift) << _pr_pageShift); + ts->stackTop = ts->allocBase; + ts->stackBottom = ts->allocBase - ts->stackSize; +#endif + } +} + +void _PR_NotifyJoinWaiters(PRThread *thread) +{ + /* + ** Handle joinable threads. Change the state to waiting for join. + ** Remove from our run Q and put it on global waiting to join Q. + ** Notify on our "termination" condition variable so that joining + ** thread will know about our termination. Switch our context and + ** come back later on to continue the cleanup. + */ + PR_ASSERT(thread == _PR_MD_CURRENT_THREAD()); + if (thread->term != NULL) { + PR_Lock(_pr_terminationCVLock); + _PR_THREAD_LOCK(thread); + thread->state = _PR_JOIN_WAIT; + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_MISCQ_LOCK(thread->cpu); + _PR_ADD_JOINQ(thread, thread->cpu); + _PR_MISCQ_UNLOCK(thread->cpu); + } + _PR_THREAD_UNLOCK(thread); + PR_NotifyCondVar(thread->term); + PR_Unlock(_pr_terminationCVLock); + _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(thread->state != _PR_JOIN_WAIT); + } + +} + +/* + * Zero some of the data members of a recycled thread. + * + * Note that we can do this either when a dead thread is added to + * the dead thread queue or when it is reused. Here, we are doing + * this lazily, when the thread is reused in _PR_CreateThread(). + */ +static void _PR_InitializeRecycledThread(PRThread *thread) +{ + /* + * Assert that the following data members are already zeroed + * by _PR_CleanupThread(). + */ +#ifdef DEBUG + if (thread->privateData) { + unsigned int i; + for (i = 0; i < thread->tpdLength; i++) { + PR_ASSERT(thread->privateData[i] == NULL); + } + } +#endif + PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0); + PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0); + PR_ASSERT(thread->errorStringLength == 0); + + /* Reset data members in thread structure */ + thread->errorCode = thread->osErrorCode = 0; + thread->io_pending = thread->io_suspended = PR_FALSE; + thread->environment = 0; + PR_INIT_CLIST(&thread->lockList); +} + +PRStatus _PR_RecycleThread(PRThread *thread) +{ + if ( _PR_IS_NATIVE_THREAD(thread) && + _PR_NUM_DEADNATIVE < _pr_recycleThreads) { + _PR_DEADQ_LOCK; + PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ); + _PR_INC_DEADNATIVE; + _PR_DEADQ_UNLOCK; + return (PR_SUCCESS); + } else if ( !_PR_IS_NATIVE_THREAD(thread) && + _PR_NUM_DEADUSER < _pr_recycleThreads) { + _PR_DEADQ_LOCK; + PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ); + _PR_INC_DEADUSER; + _PR_DEADQ_UNLOCK; + return (PR_SUCCESS); + } + return (PR_FAILURE); +} + +/* + * Decrement the active thread count, either _pr_systemActive or + * _pr_userActive, depending on whether the thread is a system thread + * or a user thread. If all the user threads, except possibly + * the primordial thread, have terminated, we notify the primordial + * thread of this condition. + * + * Since this function will lock _pr_activeLock, do not call this + * function while holding the _pr_activeLock lock, as this will result + * in a deadlock. + */ + +static void +_PR_DecrActiveThreadCount(PRThread *thread) +{ + PR_Lock(_pr_activeLock); + if (thread->flags & _PR_SYSTEM) { + _pr_systemActive--; + } else { + _pr_userActive--; + if (_pr_userActive == _pr_primordialExitCount) { + PR_NotifyCondVar(_pr_primordialExitCVar); + } + } + PR_Unlock(_pr_activeLock); +} + +/* +** Detach thread structure +*/ +static void +_PR_DestroyThread(PRThread *thread) +{ + _PR_MD_FREE_LOCK(&thread->threadLock); + PR_DELETE(thread); +} + +void +_PR_NativeDestroyThread(PRThread *thread) +{ + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + if (NULL != thread->privateData) { + PR_ASSERT(0 != thread->tpdLength); + PR_DELETE(thread->privateData); + thread->tpdLength = 0; + } + PR_DELETE(thread->stack); + _PR_DestroyThread(thread); +} + +void +_PR_UserDestroyThread(PRThread *thread) +{ + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + if (NULL != thread->privateData) { + PR_ASSERT(0 != thread->tpdLength); + PR_DELETE(thread->privateData); + thread->tpdLength = 0; + } + _PR_MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) { + _PR_MD_CLEAN_THREAD(thread); + /* + * Because the no_sched field is set, this thread/stack will + * will not be re-used until the flag is cleared by the thread + * we will context switch to. + */ + _PR_FreeStack(thread->stack); + } else { +#ifdef WINNT + _PR_MD_CLEAN_THREAD(thread); +#else + /* + * This assertion does not apply to NT. On NT, every fiber + * has its threadAllocatedOnStack equal to 0. Elsewhere, + * only the primordial thread has its threadAllocatedOnStack + * equal to 0. + */ + PR_ASSERT(thread->flags & _PR_PRIMORDIAL); +#endif + } +} + + +/* +** Run a thread's start function. When the start function returns the +** thread is done executing and no longer needs the CPU. If there are no +** more user threads running then we can exit the program. +*/ +void _PR_NativeRunThread(void *arg) +{ + PRThread *thread = (PRThread *)arg; + + _PR_MD_SET_CURRENT_THREAD(thread); + + _PR_MD_SET_CURRENT_CPU(NULL); + + /* Set up the thread stack information */ + _PR_InitializeNativeStack(thread->stack); + + /* Set up the thread md information */ + if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { + /* + * thread failed to initialize itself, possibly due to + * failure to allocate per-thread resources + */ + return; + } + + while(1) { + thread->state = _PR_RUNNING; + + /* + * Add to list of active threads + */ + PR_Lock(_pr_activeLock); + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ()); + _pr_global_threads++; + PR_Unlock(_pr_activeLock); + + (*thread->startFunc)(thread->arg); + + /* + * The following two assertions are meant for NT asynch io. + * + * The thread should have no asynch io in progress when it + * exits, otherwise the overlapped buffer, which is part of + * the thread structure, would become invalid. + */ + PR_ASSERT(thread->io_pending == PR_FALSE); + /* + * This assertion enforces the programming guideline that + * if an io function times out or is interrupted, the thread + * should close the fd to force the asynch io to abort + * before it exits. Right now, closing the fd is the only + * way to clear the io_suspended flag. + */ + PR_ASSERT(thread->io_suspended == PR_FALSE); + + /* + * remove thread from list of active threads + */ + PR_Lock(_pr_activeLock); + PR_REMOVE_LINK(&thread->active); + _pr_global_threads--; + PR_Unlock(_pr_activeLock); + + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); + + /* All done, time to go away */ + _PR_CleanupThread(thread); + + _PR_NotifyJoinWaiters(thread); + + _PR_DecrActiveThreadCount(thread); + + thread->state = _PR_DEAD_STATE; + + if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == + PR_FAILURE)) { + /* + * thread not recycled + * platform-specific thread exit processing + * - for stuff like releasing native-thread resources, etc. + */ + _PR_MD_EXIT_THREAD(thread); + /* + * Free memory allocated for the thread + */ + _PR_NativeDestroyThread(thread); + /* + * thread gone, cannot de-reference thread now + */ + return; + } + + /* Now wait for someone to activate us again... */ + _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT); + } +} + +static void _PR_UserRunThread(void) +{ + PRThread *thread = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + if (_MD_LAST_THREAD()) + _MD_LAST_THREAD()->no_sched = 0; + +#ifdef HAVE_CUSTOM_USER_THREADS + if (thread->stack == NULL) { + thread->stack = PR_NEWZAP(PRThreadStack); + _PR_InitializeNativeStack(thread->stack); + } +#endif /* HAVE_CUSTOM_USER_THREADS */ + + while(1) { + /* Run thread main */ + if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0); + + /* + * Add to list of active threads + */ + if (!(thread->flags & _PR_IDLE_THREAD)) { + PR_Lock(_pr_activeLock); + PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ()); + _pr_local_threads++; + PR_Unlock(_pr_activeLock); + } + + (*thread->startFunc)(thread->arg); + + /* + * The following two assertions are meant for NT asynch io. + * + * The thread should have no asynch io in progress when it + * exits, otherwise the overlapped buffer, which is part of + * the thread structure, would become invalid. + */ + PR_ASSERT(thread->io_pending == PR_FALSE); + /* + * This assertion enforces the programming guideline that + * if an io function times out or is interrupted, the thread + * should close the fd to force the asynch io to abort + * before it exits. Right now, closing the fd is the only + * way to clear the io_suspended flag. + */ + PR_ASSERT(thread->io_suspended == PR_FALSE); + + PR_Lock(_pr_activeLock); + /* + * remove thread from list of active threads + */ + if (!(thread->flags & _PR_IDLE_THREAD)) { + PR_REMOVE_LINK(&thread->active); + _pr_local_threads--; + } + PR_Unlock(_pr_activeLock); + PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting")); + + /* All done, time to go away */ + _PR_CleanupThread(thread); + + _PR_INTSOFF(is); + + _PR_NotifyJoinWaiters(thread); + + _PR_DecrActiveThreadCount(thread); + + thread->state = _PR_DEAD_STATE; + + if (!_pr_recycleThreads || (_PR_RecycleThread(thread) == + PR_FAILURE)) { + /* + ** Destroy the thread resources + */ + _PR_UserDestroyThread(thread); + } + + /* + ** Find another user thread to run. This cpu has finished the + ** previous threads main and is now ready to run another thread. + */ + { + PRInt32 is; + _PR_INTSOFF(is); + _PR_MD_SWITCH_CONTEXT(thread); + } + + /* Will land here when we get scheduled again if we are recycling... */ + } +} + +void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRIntn is; + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + _PR_MD_SET_PRIORITY(&(thread->md), newPri); + return; + } + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + if (newPri != thread->priority) { + _PRCPU *cpu = thread->cpu; + + switch (thread->state) { + case _PR_RUNNING: + /* Change my priority */ + + _PR_RUNQ_LOCK(cpu); + thread->priority = newPri; + if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); + } + _PR_RUNQ_UNLOCK(cpu); + break; + + case _PR_RUNNABLE: + + _PR_RUNQ_LOCK(cpu); + /* Move to different runQ */ + _PR_DEL_RUNQ(thread); + thread->priority = newPri; + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + _PR_ADD_RUNQ(thread, cpu, newPri); + _PR_RUNQ_UNLOCK(cpu); + + if (newPri > me->priority) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); + } + + break; + + case _PR_LOCK_WAIT: + case _PR_COND_WAIT: + case _PR_IO_WAIT: + case _PR_SUSPENDED: + + thread->priority = newPri; + break; + } + } + _PR_THREAD_UNLOCK(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); +} + +/* +** Suspend the named thread and copy its gc registers into regBuf +*/ +static void _PR_Suspend(PRThread *thread) +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(thread != me); + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu)); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + switch (thread->state) { + case _PR_RUNNABLE: + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_RUNQ_LOCK(thread->cpu); + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(thread->cpu); + + _PR_MISCQ_LOCK(thread->cpu); + _PR_ADD_SUSPENDQ(thread, thread->cpu); + _PR_MISCQ_UNLOCK(thread->cpu); + } else { + /* + * Only LOCAL threads are suspended by _PR_Suspend + */ + PR_ASSERT(0); + } + thread->state = _PR_SUSPENDED; + break; + + case _PR_RUNNING: + /* + * The thread being suspended should be a LOCAL thread with + * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state + */ + PR_ASSERT(0); + break; + + case _PR_LOCK_WAIT: + case _PR_IO_WAIT: + case _PR_COND_WAIT: + if (_PR_IS_NATIVE_THREAD(thread)) { + _PR_MD_SUSPEND_THREAD(thread); + } + thread->flags |= _PR_SUSPENDING; + break; + + default: + PR_Abort(); + } + _PR_THREAD_UNLOCK(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); +} + +static void _PR_Resume(PRThread *thread) +{ + PRThreadPriority pri; + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + _PR_THREAD_LOCK(thread); + switch (thread->state) { + case _PR_SUSPENDED: + thread->state = _PR_RUNNABLE; + thread->flags &= ~_PR_SUSPENDING; + if (!_PR_IS_NATIVE_THREAD(thread)) { + _PR_MISCQ_LOCK(thread->cpu); + _PR_DEL_SUSPENDQ(thread); + _PR_MISCQ_UNLOCK(thread->cpu); + + pri = thread->priority; + + _PR_RUNQ_LOCK(thread->cpu); + _PR_ADD_RUNQ(thread, thread->cpu, pri); + _PR_RUNQ_UNLOCK(thread->cpu); + + if (pri > _PR_MD_CURRENT_THREAD()->priority) { + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_SET_RESCHED_FLAG(); + } + } else { + PR_ASSERT(0); + } + break; + + case _PR_IO_WAIT: + case _PR_COND_WAIT: + thread->flags &= ~_PR_SUSPENDING; +/* PR_ASSERT(thread->wait.monitor->stickyCount == 0); */ + break; + + case _PR_LOCK_WAIT: + { + PRLock *wLock = thread->wait.lock; + + thread->flags &= ~_PR_SUSPENDING; + + _PR_LOCK_LOCK(wLock); + if (thread->wait.lock->owner == 0) { + _PR_UnblockLockWaiter(thread->wait.lock); + } + _PR_LOCK_UNLOCK(wLock); + break; + } + case _PR_RUNNABLE: + break; + case _PR_RUNNING: + /* + * The thread being suspended should be a LOCAL thread with + * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state + */ + PR_ASSERT(0); + break; + + default: + /* + * thread should have been in one of the above-listed blocked states + * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE) + */ + PR_Abort(); + } + _PR_THREAD_UNLOCK(thread); + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + +} + +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) +static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus) +{ + PRThread *thread; + PRIntn pri; + PRUint32 r; + PRCList *qp; + PRIntn priMin, priMax; + + _PR_RUNQ_LOCK(cpu); + r = _PR_RUNQREADYMASK(cpu); + if (r==0) { + priMin = priMax = PR_PRIORITY_FIRST; + } else if (r == (1<= priMin ; pri-- ) { + if (r & (1 << pri)) { + for (qp = _PR_RUNQ(cpu)[pri].next; + qp != &_PR_RUNQ(cpu)[pri]; + qp = qp->next) { + thread = _PR_THREAD_PTR(qp); + /* + * skip non-schedulable threads + */ + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); + if (thread->no_sched) { + thread = NULL; + /* + * Need to wakeup cpus to avoid missing a + * runnable thread + * Waking up all CPU's need happen only once. + */ + + *wakeup_cpus = PR_TRUE; + continue; + } else if (thread->flags & _PR_BOUND_THREAD) { + /* + * Thread bound to cpu 0 + */ + + thread = NULL; +#ifdef IRIX + _PR_MD_WAKEUP_PRIMORDIAL_CPU(); +#endif + continue; + } else if (thread->io_pending == PR_TRUE) { + /* + * A thread that is blocked for I/O needs to run + * on the same cpu on which it was blocked. This is because + * the cpu's ioq is accessed without lock protection and scheduling + * the thread on a different cpu would preclude this optimization. + */ + thread = NULL; + continue; + } else { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + return(thread); + } + } + } + thread = NULL; + } + _PR_RUNQ_UNLOCK(cpu); + return(thread); +} +#endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) */ + +/* +** Schedule this native thread by finding the highest priority nspr +** thread that is ready to run. +** +** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls +** PR_Schedule() rather than calling PR_Schedule. Otherwise if there +** is initialization required for switching from SWITCH_CONTEXT, +** it will not get done! +*/ +void _PR_Schedule(void) +{ + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRIntn pri; + PRUint32 r; + PRCList *qp; + PRIntn priMin, priMax; +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) + PRBool wakeup_cpus; +#endif + + /* Interrupts must be disabled */ + PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0); + + /* Since we are rescheduling, we no longer want to */ + _PR_CLEAR_RESCHED_FLAG(); + + /* + ** Find highest priority thread to run. Bigger priority numbers are + ** higher priority threads + */ + _PR_RUNQ_LOCK(cpu); + /* + * if we are in SuspendAll mode, can schedule only the thread + * that called PR_SuspendAll + * + * The thread may be ready to run now, after completing an I/O + * operation, for example + */ + if ((thread = suspendAllThread) != 0) { + if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + goto found_thread; + } else { + thread = NULL; + _PR_RUNQ_UNLOCK(cpu); + goto idle_thread; + } + } + r = _PR_RUNQREADYMASK(cpu); + if (r==0) { + priMin = priMax = PR_PRIORITY_FIRST; + } else if (r == (1<= priMin ; pri-- ) { + if (r & (1 << pri)) { + for (qp = _PR_RUNQ(cpu)[pri].next; + qp != &_PR_RUNQ(cpu)[pri]; + qp = qp->next) { + thread = _PR_THREAD_PTR(qp); + /* + * skip non-schedulable threads + */ +#if !defined(XP_MAC) + PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD)); +#endif + if ((thread->no_sched) && (me != thread)){ + thread = NULL; + continue; + } else { + /* Pull thread off of its run queue */ + _PR_DEL_RUNQ(thread); + _PR_RUNQ_UNLOCK(cpu); + goto found_thread; + } + } + } + thread = NULL; + } + _PR_RUNQ_UNLOCK(cpu); + +#if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) + + wakeup_cpus = PR_FALSE; + _PR_CPU_LIST_LOCK(); + for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) { + if (cpu != _PR_CPU_PTR(qp)) { + if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus)) + != NULL) { + thread->cpu = cpu; + _PR_CPU_LIST_UNLOCK(); + if (wakeup_cpus == PR_TRUE) + _PR_MD_WAKEUP_CPUS(); + goto found_thread; + } + } + } + _PR_CPU_LIST_UNLOCK(); + if (wakeup_cpus == PR_TRUE) + _PR_MD_WAKEUP_CPUS(); + +#endif /* _PR_LOCAL_THREADS_ONLY */ + +idle_thread: + /* + ** There are no threads to run. Switch to the idle thread + */ + PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing")); + thread = _PR_MD_CURRENT_CPU()->idle_thread; + +found_thread: + PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) && + (!(thread->no_sched)))); + + /* Resume the thread */ + PR_LOG(_pr_sched_lm, PR_LOG_MAX, + ("switching to %d[%p]", thread->id, thread)); + PR_ASSERT(thread->state != _PR_RUNNING); + thread->state = _PR_RUNNING; + + /* If we are on the runq, it just means that we went to sleep on some + * resource, and by the time we got here another real native thread had + * already given us the resource and put us back on the runqueue + */ + PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU()); + if (thread != me) + _PR_MD_RESTORE_CONTEXT(thread); +#if 0 + /* XXXMB; with setjmp/longjmp it is impossible to land here, but + * it is not with fibers... Is this a bad thing? I believe it is + * still safe. + */ + PR_NOT_REACHED("impossible return from schedule"); +#endif +} + +/* +** Attaches a thread. +** Does not set the _PR_MD_CURRENT_THREAD. +** Does not specify the scope of the thread. +*/ +static PRThread * +_PR_AttachThread(PRThreadType type, PRThreadPriority priority, + PRThreadStack *stack) +{ +#if defined(XP_MAC) +#pragma unused (type) +#endif + + PRThread *thread; + char *mem; + + if (priority > PR_PRIORITY_LAST) { + priority = PR_PRIORITY_LAST; + } else if (priority < PR_PRIORITY_FIRST) { + priority = PR_PRIORITY_FIRST; + } + + mem = (char*) PR_CALLOC(sizeof(PRThread)); + if (mem) { + thread = (PRThread*) mem; + thread->priority = priority; + thread->stack = stack; + thread->state = _PR_RUNNING; + PR_INIT_CLIST(&thread->lockList); + if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { + PR_DELETE(thread); + return 0; + } + + return thread; + } + return 0; +} + + + +PR_IMPLEMENT(PRThread*) +_PR_NativeCreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags) +{ +#if defined(XP_MAC) +#pragma unused (scope) +#endif + + PRThread *thread; + + thread = _PR_AttachThread(type, priority, NULL); + + if (thread) { + PR_Lock(_pr_activeLock); + thread->flags = (flags | _PR_GLOBAL_SCOPE); + thread->id = ++_pr_utid; + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + PR_Unlock(_pr_activeLock); + + thread->stack = PR_NEWZAP(PRThreadStack); + if (!thread->stack) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + goto done; + } + thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE; + thread->stack->thr = thread; + thread->startFunc = start; + thread->arg = arg; + + /* + Set thread flags related to scope and joinable state. If joinable + thread, allocate a "termination" conidition variable. + */ + if (state == PR_JOINABLE_THREAD) { + thread->term = PR_NewCondVar(_pr_terminationCVLock); + if (thread->term == NULL) { + PR_DELETE(thread->stack); + goto done; + } + } + + thread->state = _PR_RUNNING; + if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority, + scope,state,stackSize) == PR_SUCCESS) { + return thread; + } + if (thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = NULL; + } + PR_DELETE(thread->stack); + } + +done: + if (thread) { + _PR_DecrActiveThreadCount(thread); + _PR_DestroyThread(thread); + } + return NULL; +} + +/************************************************************************/ + +PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, + PRUint32 flags) +{ + PRThread *me; + PRThread *thread = NULL; + PRThreadStack *stack; + char *top; + PRIntn is; + PRIntn native = 0; + PRIntn useRecycled = 0; + PRBool status; + + /* + First, pin down the priority. Not all compilers catch passing out of + range enum here. If we let bad values thru, priority queues won't work. + */ + if (priority > PR_PRIORITY_LAST) { + priority = PR_PRIORITY_LAST; + } else if (priority < PR_PRIORITY_FIRST) { + priority = PR_PRIORITY_FIRST; + } + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (! (flags & _PR_IDLE_THREAD)) + me = _PR_MD_CURRENT_THREAD(); + +#if defined(_PR_GLOBAL_THREADS_ONLY) + /* + * can create global threads only + */ + if (scope == PR_LOCAL_THREAD) + scope = PR_GLOBAL_THREAD; +#endif + + if (_native_threads_only) + scope = PR_GLOBAL_THREAD; + + native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD)) + && _PR_IS_NATIVE_THREAD_SUPPORTED()); + + _PR_ADJUST_STACKSIZE(stackSize); + + if (native) { + /* + * clear the IDLE_THREAD flag which applies to LOCAL + * threads only + */ + flags &= ~_PR_IDLE_THREAD; + flags |= _PR_GLOBAL_SCOPE; + if (_PR_NUM_DEADNATIVE > 0) { + _PR_DEADQ_LOCK; + + if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */ + _PR_DEADQ_UNLOCK; + } else { + thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next); + PR_REMOVE_LINK(&thread->links); + _PR_DEC_DEADNATIVE; + _PR_DEADQ_UNLOCK; + + _PR_InitializeRecycledThread(thread); + thread->startFunc = start; + thread->arg = arg; + thread->flags = (flags | _PR_GLOBAL_SCOPE); + if (type == PR_SYSTEM_THREAD) + { + thread->flags |= _PR_SYSTEM; + PR_AtomicIncrement(&_pr_systemActive); + } + else PR_AtomicIncrement(&_pr_userActive); + + if (state == PR_JOINABLE_THREAD) { + if (!thread->term) + thread->term = PR_NewCondVar(_pr_terminationCVLock); + } + else { + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + } + + thread->priority = priority; + _PR_MD_SET_PRIORITY(&(thread->md), priority); + /* XXX what about stackSize? */ + thread->state = _PR_RUNNING; + _PR_MD_WAKEUP_WAITER(thread); + return thread; + } + } + thread = _PR_NativeCreateThread(type, start, arg, priority, + scope, state, stackSize, flags); + } else { + if (_PR_NUM_DEADUSER > 0) { + _PR_DEADQ_LOCK; + + if (_PR_NUM_DEADUSER == 0) { /* thread safe check */ + _PR_DEADQ_UNLOCK; + } else { + PRCList *ptr; + + /* Go down list checking for a recycled thread with a + * large enough stack. XXXMB - this has a bad degenerate case. + */ + ptr = _PR_DEADUSERQ.next; + while( ptr != &_PR_DEADUSERQ ) { + thread = _PR_THREAD_PTR(ptr); + if ((thread->stack->stackSize >= stackSize) && + (!thread->no_sched)) { + PR_REMOVE_LINK(&thread->links); + _PR_DEC_DEADUSER; + break; + } else { + ptr = ptr->next; + thread = NULL; + } + } + + _PR_DEADQ_UNLOCK; + + if (thread) { + _PR_InitializeRecycledThread(thread); + thread->startFunc = start; + thread->arg = arg; + thread->priority = priority; + if (state == PR_JOINABLE_THREAD) { + if (!thread->term) + thread->term = PR_NewCondVar(_pr_terminationCVLock); + } else { + if(thread->term) { + PR_DestroyCondVar(thread->term); + thread->term = 0; + } + } + useRecycled++; + } + } + } + if (thread == NULL) { +#ifndef HAVE_CUSTOM_USER_THREADS + stack = _PR_NewStack(stackSize); + if (!stack) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + + /* Allocate thread object and per-thread data off the top of the stack*/ + top = stack->stackTop; +#ifdef HAVE_STACK_GROWING_UP + thread = (PRThread*) top; + top = top + sizeof(PRThread); + /* + * Make stack 64-byte aligned + */ + if ((PRUptrdiff)top & 0x3f) { + top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f); + } +#else + top = top - sizeof(PRThread); + thread = (PRThread*) top; + /* + * Make stack 64-byte aligned + */ + if ((PRUptrdiff)top & 0x3f) { + top = (char*)((PRUptrdiff)top & ~0x3f); + } +#endif +#if defined(GC_LEAK_DETECTOR) + /* + * sorry, it is not safe to allocate the thread on the stack, + * because we assign to this object before the GC can learn + * about this thread. we'll just leak thread objects instead. + */ + thread = PR_NEW(PRThread); +#endif + stack->thr = thread; + memset(thread, 0, sizeof(PRThread)); + thread->threadAllocatedOnStack = 1; +#else + thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg); + if (!thread) { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + thread->threadAllocatedOnStack = 0; + stack = NULL; + top = NULL; +#endif + + /* Initialize thread */ + thread->tpdLength = 0; + thread->privateData = NULL; + thread->stack = stack; + thread->priority = priority; + thread->startFunc = start; + thread->arg = arg; + PR_INIT_CLIST(&thread->lockList); + + if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) { + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread); + } + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } + + if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) { + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); + return NULL; + } + + _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status); + + if (status == PR_FALSE) { + _PR_MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + return NULL; + } + + /* + Set thread flags related to scope and joinable state. If joinable + thread, allocate a "termination" condition variable. + */ + if (state == PR_JOINABLE_THREAD) { + thread->term = PR_NewCondVar(_pr_terminationCVLock); + if (thread->term == NULL) { + _PR_MD_FREE_LOCK(&thread->threadLock); + if (thread->threadAllocatedOnStack == 1) + _PR_FreeStack(thread->stack); + else { + PR_DELETE(thread->privateData); + PR_DELETE(thread); + } + return NULL; + } + } + + } + + /* Update thread type counter */ + PR_Lock(_pr_activeLock); + thread->flags = flags; + thread->id = ++_pr_utid; + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + + /* Make thread runnable */ + thread->state = _PR_RUNNABLE; + /* + * Add to list of active threads + */ + PR_Unlock(_pr_activeLock); + + if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) ) + thread->cpu = _PR_GetPrimordialCPU(); + else + thread->cpu = _PR_MD_CURRENT_CPU(); + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + + if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(thread->cpu); + _PR_ADD_RUNQ(thread, thread->cpu, priority); + _PR_RUNQ_UNLOCK(thread->cpu); + } + + if (thread->flags & _PR_IDLE_THREAD) { + /* + ** If the creating thread is a kernel thread, we need to + ** awaken the user thread idle thread somehow; potentially + ** it could be sleeping in its idle loop, and we need to poke + ** it. To do so, wake the idle thread... + */ + _PR_MD_WAKEUP_WAITER(NULL); + } else if (_PR_IS_NATIVE_THREAD(me)) { + _PR_MD_WAKEUP_WAITER(thread); + } + if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) ) + _PR_INTSON(is); + } + + return thread; +} + +PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, 0); +} + +/* +** Associate a thread object with an existing native thread. +** "type" is the type of thread object to attach +** "priority" is the priority to assign to the thread +** "stack" defines the shape of the threads stack +** +** This can return NULL if some kind of error occurs, or if memory is +** tight. +** +** This call is not normally needed unless you create your own native +** thread. PR_Init does this automatically for the primordial thread. +*/ +PRThread* _PRI_AttachThread(PRThreadType type, + PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags) +{ + PRThread *thread; + + if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) { + return thread; + } + _PR_MD_SET_CURRENT_THREAD(NULL); + + /* Clear out any state if this thread was attached before */ + _PR_MD_SET_CURRENT_CPU(NULL); + + thread = _PR_AttachThread(type, priority, stack); + if (thread) { + PRIntn is; + + _PR_MD_SET_CURRENT_THREAD(thread); + + thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED; + + if (!stack) { + thread->stack = PR_NEWZAP(PRThreadStack); + if (!thread->stack) { + _PR_DestroyThread(thread); + return NULL; + } + thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE; + } + PR_INIT_CLIST(&thread->links); + + if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) { + PR_DELETE(thread->stack); + _PR_DestroyThread(thread); + return NULL; + } + + _PR_MD_SET_CURRENT_CPU(NULL); + + if (_PR_MD_CURRENT_CPU()) { + _PR_INTSOFF(is); + PR_Lock(_pr_activeLock); + } + if (type == PR_SYSTEM_THREAD) { + thread->flags |= _PR_SYSTEM; + _pr_systemActive++; + } else { + _pr_userActive++; + } + if (_PR_MD_CURRENT_CPU()) { + PR_Unlock(_pr_activeLock); + _PR_INTSON(is); + } + } + return thread; +} + +PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type, + PRThreadPriority priority, PRThreadStack *stack) +{ +#ifdef XP_MAC +#pragma unused( type, priority, stack ) +#endif + return PR_GetCurrentThread(); +} + +PR_IMPLEMENT(void) PR_DetachThread(void) +{ + /* + * On IRIX, Solaris, and Windows, foreign threads are detached when + * they terminate. + */ +#if !defined(IRIX) && !defined(WIN32) \ + && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY)) + PRThread *me; + if (_pr_initialized) { + me = _PR_MD_GET_ATTACHED_THREAD(); + if ((me != NULL) && (me->flags & _PR_ATTACHED)) + _PRI_DetachThread(); + } +#endif +} + +void _PRI_DetachThread(void) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (me->flags & _PR_PRIMORDIAL) { + /* + * ignore, if primordial thread + */ + return; + } + PR_ASSERT(me->flags & _PR_ATTACHED); + PR_ASSERT(_PR_IS_NATIVE_THREAD(me)); + _PR_CleanupThread(me); + PR_DELETE(me->privateData); + + _PR_DecrActiveThreadCount(me); + + _PR_MD_CLEAN_THREAD(me); + _PR_MD_SET_CURRENT_THREAD(NULL); + if (!me->threadAllocatedOnStack) + PR_DELETE(me->stack); + _PR_MD_FREE_LOCK(&me->threadLock); + PR_DELETE(me); +} + +/* +** Wait for thread termination: +** "thread" is the target thread +** +** This can return PR_FAILURE if no joinable thread could be found +** corresponding to the specified target thread. +** +** The calling thread is suspended until the target thread completes. +** Several threads cannot wait for the same thread to complete; one thread +** will complete successfully and others will terminate with an error PR_FAILURE. +** The calling thread will not be blocked if the target thread has already +** terminated. +*/ +PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread) +{ + PRIntn is; + PRCondVar *term; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + term = thread->term; + /* can't join a non-joinable thread */ + if (term == NULL) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + goto ErrorExit; + } + + /* multiple threads can't wait on the same joinable thread */ + if (term->condQ.next != &term->condQ) { + goto ErrorExit; + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + /* wait for the target thread's termination cv invariant */ + PR_Lock (_pr_terminationCVLock); + while (thread->state != _PR_JOIN_WAIT) { + (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT); + } + (void) PR_Unlock (_pr_terminationCVLock); + + /* + Remove target thread from global waiting to join Q; make it runnable + again and put it back on its run Q. When it gets scheduled later in + _PR_RunThread code, it will clean up its stack. + */ + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + thread->state = _PR_RUNNABLE; + if ( !_PR_IS_NATIVE_THREAD(thread) ) { + _PR_THREAD_LOCK(thread); + + _PR_MISCQ_LOCK(thread->cpu); + _PR_DEL_JOINQ(thread); + _PR_MISCQ_UNLOCK(thread->cpu); + + _PR_AddThreadToRunQ(me, thread); + _PR_THREAD_UNLOCK(thread); + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + + _PR_MD_WAKEUP_WAITER(thread); + + return PR_SUCCESS; + +ErrorExit: + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); + return PR_FAILURE; +} + +PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread, + PRThreadPriority newPri) +{ + + /* + First, pin down the priority. Not all compilers catch passing out of + range enum here. If we let bad values thru, priority queues won't work. + */ + if ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) { + newPri = PR_PRIORITY_LAST; + } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) { + newPri = PR_PRIORITY_FIRST; + } + + if ( _PR_IS_NATIVE_THREAD(thread) ) { + thread->priority = newPri; + _PR_MD_SET_PRIORITY(&(thread->md), newPri); + } else _PR_SetThreadPriority(thread, newPri); +} + + +/* +** This routine prevents all other threads from running. This call is needed by +** the garbage collector. +*/ +PR_IMPLEMENT(void) PR_SuspendAll(void) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCList *qp; + + /* + * Stop all user and native threads which are marked GC able. + */ + PR_Lock(_pr_activeLock); + suspendAllOn = PR_TRUE; + suspendAllThread = _PR_MD_CURRENT_THREAD(); + _PR_MD_BEGIN_SUSPEND_ALL(); + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) { + _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); + PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING); + } + } + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */ + _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); + } + _PR_MD_END_SUSPEND_ALL(); +} + +/* +** This routine unblocks all other threads that were suspended from running by +** PR_SuspendAll(). This call is needed by the garbage collector. +*/ +PR_IMPLEMENT(void) PR_ResumeAll(void) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + PRCList *qp; + + /* + * Resume all user and native threads which are marked GC able. + */ + _PR_MD_BEGIN_RESUME_ALL(); + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp)); + } + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) { + if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && + _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) + _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); + } + _PR_MD_END_RESUME_ALL(); + suspendAllThread = NULL; + suspendAllOn = PR_FALSE; + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg) +{ + PRCList *qp, *qp_next; + PRIntn i = 0; + PRStatus rv = PR_SUCCESS; + PRThread* t; + + /* + ** Currently Enumerate threads happen only with suspension and + ** pr_activeLock held + */ + PR_ASSERT(suspendAllOn); + + /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking + * qp->next after applying the function "func". In particular, "func" + * might remove the thread from the queue and put it into another one in + * which case qp->next no longer points to the next entry in the original + * queue. + * + * To get around this problem, we save qp->next in qp_next before applying + * "func" and use that saved value as the next value after applying "func". + */ + + /* + * Traverse the list of local and global threads + */ + for (qp = _PR_ACTIVE_LOCAL_THREADQ().next; + qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next) + { + qp_next = qp->next; + t = _PR_ACTIVE_THREAD_PTR(qp); + if (_PR_IS_GCABLE_THREAD(t)) + { + rv = (*func)(t, i, arg); + if (rv != PR_SUCCESS) + return rv; + i++; + } + } + for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next; + qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next) + { + qp_next = qp->next; + t = _PR_ACTIVE_THREAD_PTR(qp); + if (_PR_IS_GCABLE_THREAD(t)) + { + rv = (*func)(t, i, arg); + if (rv != PR_SUCCESS) + return rv; + i++; + } + } + return rv; +} + +/* FUNCTION: _PR_AddSleepQ +** DESCRIPTION: +** Adds a thread to the sleep/pauseQ. +** RESTRICTIONS: +** Caller must have the RUNQ lock. +** Caller must be a user level thread +*/ +PR_IMPLEMENT(void) +_PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout) +{ + _PRCPU *cpu = thread->cpu; + + if (timeout == PR_INTERVAL_NO_TIMEOUT) { + /* append the thread to the global pause Q */ + PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu)); + thread->flags |= _PR_ON_PAUSEQ; + } else { + PRIntervalTime sleep; + PRCList *q; + PRThread *t; + + /* sort onto global sleepQ */ + sleep = timeout; + + /* Check if we are longest timeout */ + if (timeout >= _PR_SLEEPQMAX(cpu)) { + PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu)); + thread->sleep = timeout - _PR_SLEEPQMAX(cpu); + _PR_SLEEPQMAX(cpu) = timeout; + } else { + /* Sort thread into global sleepQ at appropriate point */ + q = _PR_SLEEPQ(cpu).next; + + /* Now scan the list for where to insert this entry */ + while (q != &_PR_SLEEPQ(cpu)) { + t = _PR_THREAD_PTR(q); + if (sleep < t->sleep) { + /* Found sleeper to insert in front of */ + break; + } + sleep -= t->sleep; + q = q->next; + } + thread->sleep = sleep; + PR_INSERT_BEFORE(&thread->links, q); + + /* + ** Subtract our sleep time from the sleeper that follows us (there + ** must be one) so that they remain relative to us. + */ + PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu)); + + t = _PR_THREAD_PTR(thread->links.next); + PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread); + t->sleep -= sleep; + } + + thread->flags |= _PR_ON_SLEEPQ; + } +} + +/* FUNCTION: _PR_DelSleepQ +** DESCRIPTION: +** Removes a thread from the sleep/pauseQ. +** INPUTS: +** If propogate_time is true, then the thread following the deleted +** thread will be get the time from the deleted thread. This is used +** when deleting a sleeper that has not timed out. +** RESTRICTIONS: +** Caller must have the RUNQ lock. +** Caller must be a user level thread +*/ +PR_IMPLEMENT(void) +_PR_DelSleepQ(PRThread *thread, PRBool propogate_time) +{ + _PRCPU *cpu = thread->cpu; + + /* Remove from pauseQ/sleepQ */ + if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) { + if (thread->flags & _PR_ON_SLEEPQ) { + PRCList *q = thread->links.next; + if (q != &_PR_SLEEPQ(cpu)) { + if (propogate_time == PR_TRUE) { + PRThread *after = _PR_THREAD_PTR(q); + after->sleep += thread->sleep; + } else + _PR_SLEEPQMAX(cpu) -= thread->sleep; + } else { + /* Check if prev is the beggining of the list; if so, + * we are the only element on the list. + */ + if (thread->links.prev != &_PR_SLEEPQ(cpu)) + _PR_SLEEPQMAX(cpu) -= thread->sleep; + else + _PR_SLEEPQMAX(cpu) = 0; + } + thread->flags &= ~_PR_ON_SLEEPQ; + } else { + thread->flags &= ~_PR_ON_PAUSEQ; + } + PR_REMOVE_LINK(&thread->links); + } else + PR_ASSERT(0); +} + +void +_PR_AddThreadToRunQ( + PRThread *me, /* the current thread */ + PRThread *thread) /* the local thread to be added to a run queue */ +{ + PRThreadPriority pri = thread->priority; + _PRCPU *cpu = thread->cpu; + + PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread)); + +#if defined(WINNT) + /* + * On NT, we can only reliably know that the current CPU + * is not idle. We add the awakened thread to the run + * queue of its CPU if its CPU is the current CPU. + * For any other CPU, we don't really know whether it + * is busy or idle. So in all other cases, we just + * "post" the awakened thread to the IO completion port + * for the next idle CPU to execute (this is done in + * _PR_MD_WAKEUP_WAITER). + * Threads with a suspended I/O operation remain bound to + * the same cpu until I/O is cancelled + * + * NOTE: the boolean expression below must be the exact + * opposite of the corresponding boolean expression in + * _PR_MD_WAKEUP_WAITER. + */ + if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) || + (thread->md.thr_bound_cpu)) { + PR_ASSERT(!thread->md.thr_bound_cpu || + (thread->md.thr_bound_cpu == cpu)); + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + } +#else + _PR_RUNQ_LOCK(cpu); + _PR_ADD_RUNQ(thread, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) { + if (pri > me->priority) { + _PR_SET_RESCHED_FLAG(); + } + } +#endif +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcmon.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcmon.c new file mode 100644 index 00000000..277b7235 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcmon.c @@ -0,0 +1,413 @@ +/* -*- 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 +#include + +/* Lock used to lock the monitor cache */ +#ifdef _PR_NO_PREEMPT +#define _PR_NEW_LOCK_MCACHE() +#define _PR_LOCK_MCACHE() +#define _PR_UNLOCK_MCACHE() +#else +#ifdef _PR_LOCAL_THREADS_ONLY +#define _PR_NEW_LOCK_MCACHE() +#define _PR_LOCK_MCACHE() { PRIntn _is; _PR_INTSOFF(_is) +#define _PR_UNLOCK_MCACHE() _PR_INTSON(_is); } +#else +PRLock *_pr_mcacheLock; +#define _PR_NEW_LOCK_MCACHE() (_pr_mcacheLock = PR_NewLock()) +#define _PR_LOCK_MCACHE() PR_Lock(_pr_mcacheLock) +#define _PR_UNLOCK_MCACHE() PR_Unlock(_pr_mcacheLock) +#endif +#endif + +/************************************************************************/ + +typedef struct MonitorCacheEntryStr MonitorCacheEntry; + +struct MonitorCacheEntryStr { + MonitorCacheEntry* next; + void* address; + PRMonitor* mon; + long cacheEntryCount; +}; + +static PRUint32 hash_mask; +static PRUintn num_hash_buckets; +static PRUintn num_hash_buckets_log2; +static MonitorCacheEntry **hash_buckets; +static MonitorCacheEntry *free_entries; +static PRUintn num_free_entries; +static PRBool expanding; +int _pr_mcache_ready; + +static void (*OnMonitorRecycle)(void *address); + +#define HASH(address) \ + ((PRUint32) ( ((PRUptrdiff)(address) >> 2) ^ \ + ((PRUptrdiff)(address) >> 10) ) \ + & hash_mask) + +/* +** Expand the monitor cache. This grows the hash buckets and allocates a +** new chunk of cache entries and throws them on the free list. We keep +** as many hash buckets as there are entries. +** +** Because we call malloc and malloc may need the monitor cache, we must +** ensure that there are several free monitor cache entries available for +** malloc to get. FREE_THRESHOLD is used to prevent monitor cache +** starvation during monitor cache expansion. +*/ + +#define FREE_THRESHOLD 5 + +static PRStatus ExpandMonitorCache(PRUintn new_size_log2) +{ + MonitorCacheEntry **old_hash_buckets, *p; + PRUintn i, entries, old_num_hash_buckets, added; + MonitorCacheEntry **new_hash_buckets, *new_entries; + + entries = 1L << new_size_log2; + + /* + ** Expand the monitor-cache-entry free list + */ + new_entries = (MonitorCacheEntry*) + PR_CALLOC(entries * sizeof(MonitorCacheEntry)); + if (NULL == new_entries) return PR_FAILURE; + + /* + ** Allocate system monitors for the new monitor cache entries. If we + ** run out of system monitors, break out of the loop. + */ + for (i = 0, added = 0, p = new_entries; i < entries; i++, p++, added++) { + p->mon = PR_NewMonitor(); + if (!p->mon) + break; + } + if (added != entries) { + if (added == 0) { + /* Totally out of system monitors. Lossage abounds */ + PR_DELETE(new_entries); + return PR_FAILURE; + } + + /* + ** We were able to allocate some of the system monitors. Use + ** realloc to shrink down the new_entries memory + */ + p = (MonitorCacheEntry*) + PR_REALLOC(new_entries, added * sizeof(MonitorCacheEntry)); + if (p == 0) { + /* + ** Total lossage. We just leaked a bunch of system monitors + ** all over the floor. This should never ever happen. + */ + PR_ASSERT(p != 0); + return PR_FAILURE; + } +#ifdef VBOX + new_entries = p; +#endif + } + + /* + ** Now that we have allocated all of the system monitors, build up + ** the new free list. We can just update the free_list because we own + ** the mcache-lock and we aren't calling anyone who might want to use + ** it. + */ + for (i = 0, p = new_entries; i < added - 1; i++, p++) + p->next = p + 1; + p->next = free_entries; + free_entries = new_entries; + num_free_entries += added; + + /* Try to expand the hash table */ + new_hash_buckets = (MonitorCacheEntry**) + PR_CALLOC(entries * sizeof(MonitorCacheEntry*)); + if (NULL == new_hash_buckets) { + /* + ** Partial lossage. In this situation we don't get any more hash + ** buckets, which just means that the table lookups will take + ** longer. This is bad, but not fatal + */ + PR_LOG(_pr_cmon_lm, PR_LOG_WARNING, + ("unable to grow monitor cache hash buckets")); + return PR_SUCCESS; + } + + /* + ** Compute new hash mask value. This value is used to mask an address + ** until it's bits are in the right spot for indexing into the hash + ** table. + */ + hash_mask = entries - 1; + + /* + ** Expand the hash table. We have to rehash everything in the old + ** table into the new table. + */ + old_hash_buckets = hash_buckets; + old_num_hash_buckets = num_hash_buckets; + for (i = 0; i < old_num_hash_buckets; i++) { + p = old_hash_buckets[i]; + while (p) { + MonitorCacheEntry *next = p->next; + + /* Hash based on new table size, and then put p in the new table */ + PRUintn hash = HASH(p->address); + p->next = new_hash_buckets[hash]; + new_hash_buckets[hash] = p; + + p = next; + } + } + + /* + ** Switch over to new hash table and THEN call free of the old + ** table. Since free might re-enter _pr_mcache_lock, things would + ** break terribly if it used the old hash table. + */ + hash_buckets = new_hash_buckets; + num_hash_buckets = entries; + num_hash_buckets_log2 = new_size_log2; + PR_DELETE(old_hash_buckets); + + PR_LOG(_pr_cmon_lm, PR_LOG_NOTICE, + ("expanded monitor cache to %d (buckets %d)", + num_free_entries, entries)); + + return PR_SUCCESS; +} /* ExpandMonitorCache */ + +/* +** Lookup a monitor cache entry by address. Return a pointer to the +** pointer to the monitor cache entry on success, null on failure. +*/ +static MonitorCacheEntry **LookupMonitorCacheEntry(void *address) +{ + PRUintn hash; + MonitorCacheEntry **pp, *p; + + hash = HASH(address); + pp = hash_buckets + hash; + while ((p = *pp) != 0) { + if (p->address == address) { + if (p->cacheEntryCount > 0) + return pp; + return NULL; + } + pp = &p->next; + } + return NULL; +} + +/* +** Try to create a new cached monitor. If it's already in the cache, +** great - return it. Otherwise get a new free cache entry and set it +** up. If the cache free space is getting low, expand the cache. +*/ +static PRMonitor *CreateMonitor(void *address) +{ + PRUintn hash; + MonitorCacheEntry **pp, *p; + + hash = HASH(address); + pp = hash_buckets + hash; + while ((p = *pp) != 0) { + if (p->address == address) goto gotit; + + pp = &p->next; + } + + /* Expand the monitor cache if we have run out of free slots in the table */ + if (num_free_entries < FREE_THRESHOLD) { + /* Expand monitor cache */ + + /* + ** This function is called with the lock held. So what's the 'expanding' + ** boolean all about? Seems a bit redundant. + */ + if (!expanding) { + PRStatus rv; + + expanding = PR_TRUE; + rv = ExpandMonitorCache(num_hash_buckets_log2 + 1); + expanding = PR_FALSE; + if (PR_FAILURE == rv) return NULL; + + /* redo the hash because it'll be different now */ + hash = HASH(address); + } else { + /* + ** We are in process of expanding and we need a cache + ** monitor. Make sure we have enough! + */ + PR_ASSERT(num_free_entries > 0); + } + } + + /* Make a new monitor */ + p = free_entries; + free_entries = p->next; + num_free_entries--; + if (OnMonitorRecycle && p->address) + OnMonitorRecycle(p->address); + p->address = address; + p->next = hash_buckets[hash]; + hash_buckets[hash] = p; + PR_ASSERT(p->cacheEntryCount == 0); + + gotit: + p->cacheEntryCount++; + return p->mon; +} + +/* +** Initialize the monitor cache +*/ +void _PR_InitCMon(void) +{ + _PR_NEW_LOCK_MCACHE(); + ExpandMonitorCache(3); + _pr_mcache_ready = 1; +} + +/* +** Create monitor for address. Don't enter the monitor while we have the +** mcache locked because we might block! +*/ +PR_IMPLEMENT(PRMonitor*) PR_CEnterMonitor(void *address) +{ + PRMonitor *mon; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PR_LOCK_MCACHE(); + mon = CreateMonitor(address); + _PR_UNLOCK_MCACHE(); + + if (!mon) return NULL; + + PR_EnterMonitor(mon); + return mon; +} + +PR_IMPLEMENT(PRStatus) PR_CExitMonitor(void *address) +{ + MonitorCacheEntry **pp, *p; + PRStatus status = PR_SUCCESS; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + if (pp != NULL) { + p = *pp; + if (--p->cacheEntryCount == 0) { + /* + ** Nobody is using the system monitor. Put it on the cached free + ** list. We are safe from somebody trying to use it because we + ** have the mcache locked. + */ + p->address = 0; /* defensive move */ + *pp = p->next; /* unlink from hash_buckets */ + p->next = free_entries; /* link into free list */ + free_entries = p; + num_free_entries++; /* count it as free */ + } + status = PR_ExitMonitor(p->mon); + } else { + status = PR_FAILURE; + } + _PR_UNLOCK_MCACHE(); + + return status; +} + +PR_IMPLEMENT(PRStatus) PR_CWait(void *address, PRIntervalTime ticks) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_Wait(mon, ticks); +} + +PR_IMPLEMENT(PRStatus) PR_CNotify(void *address) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_Notify(mon); +} + +PR_IMPLEMENT(PRStatus) PR_CNotifyAll(void *address) +{ + MonitorCacheEntry **pp; + PRMonitor *mon; + + _PR_LOCK_MCACHE(); + pp = LookupMonitorCacheEntry(address); + mon = pp ? ((*pp)->mon) : NULL; + _PR_UNLOCK_MCACHE(); + + if (mon == NULL) + return PR_FAILURE; + return PR_NotifyAll(mon); +} + +PR_IMPLEMENT(void) +PR_CSetOnMonitorRecycle(void (*callback)(void *address)) +{ + OnMonitorRecycle = callback; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcthr.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcthr.c new file mode 100644 index 00000000..1e2f469c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prcthr.c @@ -0,0 +1,446 @@ +/* -*- 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" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + + +extern PRLock *_pr_sleeplock; /* allocated and initialized in prinit */ +/* +** Routines common to both native and user threads. +** +** +** Clean up a thread object, releasing all of the attached data. Do not +** free the object itself (it may not have been malloc'd) +*/ +void _PR_CleanupThread(PRThread *thread) +{ + /* Free up per-thread-data */ + _PR_DestroyThreadPrivate(thread); + + /* Free any thread dump procs */ + if (thread->dumpArg) { + PR_DELETE(thread->dumpArg); + } + thread->dump = 0; + + PR_DELETE(thread->errorString); + thread->errorStringSize = 0; + thread->errorStringLength = 0; + thread->environment = NULL; +} + +PR_IMPLEMENT(PRStatus) PR_Yield() +{ + static PRBool warning = PR_TRUE; + if (warning) warning = _PR_Obsolete( + "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)"); + return (PR_Sleep(PR_INTERVAL_NO_WAIT)); +} + +/* +** Make the current thread sleep until "timeout" ticks amount of time +** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is +** equivalent to a yield. Waiting for an infinite amount of time is +** allowed in the expectation that another thread will interrupt(). +** +** A single lock is used for all threads calling sleep. Each caller +** does get its own condition variable since each is expected to have +** a unique 'timeout'. +*/ +PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime timeout) +{ + PRStatus rv = PR_SUCCESS; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (PR_INTERVAL_NO_WAIT == timeout) + { + /* + ** This is a simple yield, nothing more, nothing less. + */ + PRIntn is; + PRThread *me = PR_GetCurrentThread(); + PRUintn pri = me->priority; + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + if ( _PR_IS_NATIVE_THREAD(me) ) _PR_MD_YIELD(); + else + { + _PR_INTSOFF(is); + _PR_RUNQ_LOCK(cpu); + if (_PR_RUNQREADYMASK(cpu) >> pri) { + me->cpu = cpu; + me->state = _PR_RUNNABLE; + _PR_ADD_RUNQ(me, cpu, pri); + _PR_RUNQ_UNLOCK(cpu); + + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: yielding")); + _PR_MD_SWITCH_CONTEXT(me); + PR_LOG(_pr_sched_lm, PR_LOG_MIN, ("PR_Yield: done")); + + _PR_FAST_INTSON(is); + } + else + { + _PR_RUNQ_UNLOCK(cpu); + _PR_INTSON(is); + } + } + } + else + { + /* + ** This is waiting for some finite period of time. + ** A thread in this state is interruptible (PR_Interrupt()), + ** but the lock and cvar used are local to the implementation + ** and not visible to the caller, therefore not notifiable. + */ + PRCondVar *cv; + PRIntervalTime timein; + + timein = PR_IntervalNow(); + cv = PR_NewCondVar(_pr_sleeplock); + PR_ASSERT(cv != NULL); + PR_Lock(_pr_sleeplock); + do + { + PRIntervalTime delta = PR_IntervalNow() - timein; + if (delta > timeout) break; + rv = PR_WaitCondVar(cv, timeout - delta); + } while (rv == PR_SUCCESS); + PR_Unlock(_pr_sleeplock); + PR_DestroyCondVar(cv); + } + return rv; +} + +PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thread) +{ + return thread->id; +} + +PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thread) +{ + return (PRThreadPriority) thread->priority; +} + +PR_IMPLEMENT(PRThread *) PR_GetCurrentThread() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + return _PR_MD_CURRENT_THREAD(); +} + +/* +** Set the interrupt flag for a thread. The thread will be unable to +** block in i/o functions when this happens. Also, any PR_Wait's in +** progress will be undone. The interrupt remains in force until +** PR_ClearInterrupt is called. +*/ +PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thread) +{ +#ifdef _PR_GLOBAL_THREADS_ONLY + PRCondVar *victim; + + _PR_THREAD_LOCK(thread); + thread->flags |= _PR_INTERRUPT; + victim = thread->wait.cvar; + _PR_THREAD_UNLOCK(thread); + if ((NULL != victim) && (!(thread->flags & _PR_INTERRUPT_BLOCKED))) { + int haveLock = (victim->lock->owner == _PR_MD_CURRENT_THREAD()); + + if (!haveLock) PR_Lock(victim->lock); + PR_NotifyAllCondVar(victim); + if (!haveLock) PR_Unlock(victim->lock); + } + return PR_SUCCESS; +#else /* ! _PR_GLOBAL_THREADS_ONLY */ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSOFF(is); + + _PR_THREAD_LOCK(thread); + thread->flags |= _PR_INTERRUPT; + switch (thread->state) { + case _PR_COND_WAIT: + /* + * call is made with thread locked; + * on return lock is released + */ + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) + _PR_NotifyLockedThread(thread); + break; + case _PR_IO_WAIT: + /* + * Need to hold the thread lock when calling + * _PR_Unblock_IO_Wait(). On return lock is + * released. + */ +#if defined(XP_UNIX) || defined(WINNT) || defined(WIN16) + if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) + _PR_Unblock_IO_Wait(thread); +#else + _PR_THREAD_UNLOCK(thread); +#endif + break; + case _PR_RUNNING: + case _PR_RUNNABLE: + case _PR_LOCK_WAIT: + default: + _PR_THREAD_UNLOCK(thread); + break; + } + if (!_PR_IS_NATIVE_THREAD(me)) + _PR_INTSON(is); + return PR_SUCCESS; +#endif /* _PR_GLOBAL_THREADS_ONLY */ +} + +/* +** Clear the interrupt flag for self. +*/ +PR_IMPLEMENT(void) PR_ClearInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + me->flags &= ~_PR_INTERRUPT; + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} + +PR_IMPLEMENT(void) PR_BlockInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + _PR_THREAD_BLOCK_INTERRUPT(me); + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} /* PR_BlockInterrupt */ + +PR_IMPLEMENT(void) PR_UnblockInterrupt() +{ + PRIntn is; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is); + _PR_THREAD_LOCK(me); + _PR_THREAD_UNBLOCK_INTERRUPT(me); + _PR_THREAD_UNLOCK(me); + if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is); +} /* PR_UnblockInterrupt */ + +/* +** Return the thread stack pointer of the given thread. +*/ +PR_IMPLEMENT(void *) PR_GetSP(PRThread *thread) +{ + return (void *)_PR_MD_GET_SP(thread); +} + +PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thread) +{ + return thread->environment; +} + +PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thread, void *env) +{ + thread->environment = env; +} + + +PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask) +{ +#ifdef HAVE_THREAD_AFFINITY + return _PR_MD_GETTHREADAFFINITYMASK(thread, mask); +#else + +#if defined(XP_MAC) +#pragma unused (thread, mask) +#endif + + return 0; +#endif +} + +PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask ) +{ +#ifdef HAVE_THREAD_AFFINITY +#ifndef IRIX + return _PR_MD_SETTHREADAFFINITYMASK(thread, mask); +#else + return 0; +#endif +#else + +#if defined(XP_MAC) +#pragma unused (thread, mask) +#endif + + return 0; +#endif +} + +/* This call is thread unsafe if another thread is calling SetConcurrency() + */ +PR_IMPLEMENT(PRInt32) PR_SetCPUAffinityMask(PRUint32 mask) +{ +#ifdef HAVE_THREAD_AFFINITY + PRCList *qp; + extern PRUint32 _pr_cpu_affinity_mask; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _pr_cpu_affinity_mask = mask; + + qp = _PR_CPUQ().next; + while(qp != &_PR_CPUQ()) { + _PRCPU *cpu; + + cpu = _PR_CPU_PTR(qp); + PR_SetThreadAffinityMask(cpu->thread, mask); + + qp = qp->next; + } +#endif + +#if defined(XP_MAC) +#pragma unused (mask) +#endif + + return 0; +} + +PRUint32 _pr_recycleThreads = 0; +PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count) +{ + _pr_recycleThreads = count; +} + +PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, _PR_GCABLE_THREAD); +} + +#ifdef SOLARIS +PR_IMPLEMENT(PRThread*) PR_CreateThreadBound(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRUintn priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize) +{ + return _PR_CreateThread(type, start, arg, priority, scope, state, + stackSize, _PR_BOUND_THREAD); +} +#endif + + +PR_IMPLEMENT(PRThread*) PR_AttachThreadGCAble( + PRThreadType type, PRThreadPriority priority, PRThreadStack *stack) +{ +#ifdef XP_MAC +#pragma unused (type, priority, stack) +#endif + /* $$$$ not sure how to finese this one */ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PR_IMPLEMENT(void) PR_SetThreadGCAble() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_Lock(_pr_activeLock); + _PR_MD_CURRENT_THREAD()->flags |= _PR_GCABLE_THREAD; + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(void) PR_ClearThreadGCAble() +{ + if (!_pr_initialized) _PR_ImplicitInitialization(); + PR_Lock(_pr_activeLock); + _PR_MD_CURRENT_THREAD()->flags &= (~_PR_GCABLE_THREAD); + PR_Unlock(_pr_activeLock); +} + +PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thread) +{ +#ifdef XP_MAC +#pragma unused( thread ) +#endif + if (!_pr_initialized) _PR_ImplicitInitialization(); + + if (_PR_IS_NATIVE_THREAD(thread)) { + return (thread->flags & _PR_BOUND_THREAD) ? PR_GLOBAL_BOUND_THREAD : + PR_GLOBAL_THREAD; + } else + return PR_LOCAL_THREAD; +} + +PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thread) +{ + return (thread->flags & _PR_SYSTEM) ? PR_SYSTEM_THREAD : PR_USER_THREAD; +} + +PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thread) +{ + return (NULL == thread->term) ? PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD; +} /* PR_GetThreadState */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prdump.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prdump.c new file mode 100644 index 00000000..3ea884d2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prdump.c @@ -0,0 +1,153 @@ +/* -*- 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" + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +/* XXX use unbuffered nspr stdio */ + +PRFileDesc *_pr_dumpOut; + +PRUint32 _PR_DumpPrintf(PRFileDesc *fd, const char *fmt, ...) +{ + char buf[100]; + PRUint32 nb; + va_list ap; + + va_start(ap, fmt); + nb = PR_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + PR_Write(fd, buf, nb); + + return nb; +} + +void _PR_DumpThread(PRFileDesc *fd, PRThread *thread) +{ + +#ifndef _PR_GLOBAL_THREADS_ONLY + _PR_DumpPrintf(fd, "%05d[%08p] pri=%2d flags=0x%02x", + thread->id, thread, thread->priority, thread->flags); + switch (thread->state) { + case _PR_RUNNABLE: + case _PR_RUNNING: + break; + case _PR_LOCK_WAIT: + _PR_DumpPrintf(fd, " lock=%p", thread->wait.lock); + break; + case _PR_COND_WAIT: + _PR_DumpPrintf(fd, " condvar=%p sleep=%lldms", + thread->wait.cvar, thread->sleep); + break; + case _PR_SUSPENDED: + _PR_DumpPrintf(fd, " suspended"); + break; + } + PR_Write(fd, "\n", 1); +#endif + + /* Now call dump routine */ + if (thread->dump) { + thread->dump(fd, thread, thread->dumpArg); + } +} + +static void DumpThreadQueue(PRFileDesc *fd, PRCList *list) +{ +#ifndef _PR_GLOBAL_THREADS_ONLY + PRCList *q; + + q = list->next; + while (q != list) { + PRThread *t = _PR_THREAD_PTR(q); + _PR_DumpThread(fd, t); + q = q->next; + } +#endif +} + +void _PR_DumpThreads(PRFileDesc *fd) +{ + PRThread *t; + PRIntn i; + + _PR_DumpPrintf(fd, "Current Thread:\n"); + t = _PR_MD_CURRENT_THREAD(); + _PR_DumpThread(fd, t); + + _PR_DumpPrintf(fd, "Runnable Threads:\n"); + for (i = 0; i < 32; i++) { + DumpThreadQueue(fd, &_PR_RUNQ(t->cpu)[i]); + } + + _PR_DumpPrintf(fd, "CondVar timed wait Threads:\n"); + DumpThreadQueue(fd, &_PR_SLEEPQ(t->cpu)); + + _PR_DumpPrintf(fd, "CondVar wait Threads:\n"); + DumpThreadQueue(fd, &_PR_PAUSEQ(t->cpu)); + + _PR_DumpPrintf(fd, "Suspended Threads:\n"); + DumpThreadQueue(fd, &_PR_SUSPENDQ(t->cpu)); +} + +PR_IMPLEMENT(void) PR_ShowStatus(void) +{ + PRIntn is; + + if ( _PR_MD_CURRENT_THREAD() + && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_INTSOFF(is); + _pr_dumpOut = _pr_stderr; + _PR_DumpThreads(_pr_dumpOut); + if ( _PR_MD_CURRENT_THREAD() + && !_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) _PR_FAST_INTSON(is); +} + +PR_IMPLEMENT(void) +PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg) +{ + thread->dump = dump; + thread->dumpArg = arg; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prmon.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prmon.c new file mode 100644 index 00000000..69d0f655 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prmon.c @@ -0,0 +1,222 @@ +/* -*- 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" + +/************************************************************************/ + +/* +** Create a new monitor. +*/ +PR_IMPLEMENT(PRMonitor*) PR_NewMonitor() +{ + PRMonitor *mon; + PRCondVar *cvar; + PRLock *lock; + + mon = PR_NEWZAP(PRMonitor); + if (mon) { + lock = PR_NewLock(); + if (!lock) { + PR_DELETE(mon); + return 0; + } + + cvar = PR_NewCondVar(lock); + if (!cvar) { + PR_DestroyLock(lock); + PR_DELETE(mon); + return 0; + } + mon->cvar = cvar; + mon->name = NULL; + } + return mon; +} + +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); + if (mon) + mon->name = name; + return mon; +} + +/* +** Destroy a monitor. There must be no thread waiting on the monitor's +** condition variable. The caller is responsible for guaranteeing that the +** monitor is no longer in use. +*/ +PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) +{ + PR_DestroyLock(mon->cvar->lock); + PR_DestroyCondVar(mon->cvar); + PR_DELETE(mon); +} + +/* +** Enter the lock associated with the monitor. +*/ +PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) { + mon->entryCount++; + } else { + PR_Lock(mon->cvar->lock); + mon->entryCount = 1; + } +} + +/* +** Test and then enter the lock associated with the monitor if it's not +** already entered by some other thread. Return PR_FALSE if some other +** thread owned the lock at the time of the call. +*/ +PR_IMPLEMENT(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) { + mon->entryCount++; + return PR_TRUE; + } else { + if (PR_TestAndLock(mon->cvar->lock)) { + mon->entryCount = 1; + return PR_TRUE; + } + } + return PR_FALSE; +} + +/* +** Exit the lock associated with the monitor once. +*/ +PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) +{ + if (mon->cvar->lock->owner != _PR_MD_CURRENT_THREAD()) { + return PR_FAILURE; + } + if (--mon->entryCount == 0) { + return PR_Unlock(mon->cvar->lock); + } + return PR_SUCCESS; +} + +/* +** Return the number of times that the current thread has entered the +** lock. Returns zero if the current thread has not entered the lock. +*/ +PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) +{ + return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ? + mon->entryCount : 0; +} + +/* +** Wait for a notify on the condition variable. Sleep for "ticks" amount +** of time (if "tick" is 0 then the sleep is indefinite). While +** the thread is waiting it exits the monitors lock (as if it called +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When +** the wait has finished the thread regains control of the monitors lock +** with the same entry count as before the wait began. +** +** The thread waiting on the monitor will be resumed when the monitor is +** notified (assuming the thread is the next in line to receive the +** notify) or when the "ticks" elapses. +** +** Returns PR_FAILURE if the caller has not locked the lock associated +** with the condition variable. +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks) +{ + PRUintn entryCount; + PRStatus status; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (mon->cvar->lock->owner != me) return PR_FAILURE; + + entryCount = mon->entryCount; + mon->entryCount = 0; + + status = _PR_WaitCondVar(me, mon->cvar, mon->cvar->lock, ticks); + + mon->entryCount = entryCount; + + return status; +} + +/* +** Notify the highest priority thread waiting on the condition +** variable. If a thread is waiting on the condition variable (using +** PR_Wait) then it is awakened and begins waiting on the monitor's lock. +*/ +PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + if (mon->cvar->lock->owner != me) return PR_FAILURE; + PR_NotifyCondVar(mon->cvar); + return PR_SUCCESS; +} + +/* +** Notify all of the threads waiting on the condition variable. All of +** threads are notified in turn. The highest priority thread will +** probably acquire the monitor first when the monitor is exited. +*/ +PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) +{ + PRThread *me = _PR_MD_CURRENT_THREAD(); + if (mon->cvar->lock->owner != me) return PR_FAILURE; + PR_NotifyAllCondVar(mon->cvar); + return PR_SUCCESS; +} + +/************************************************************************/ + +PRUint32 _PR_MonitorToString(PRMonitor *mon, char *buf, PRUint32 buflen) +{ + PRUint32 nb; + + if (mon->cvar->lock->owner) { + nb = PR_snprintf(buf, buflen, "[%p] owner=%d[%p] count=%ld", + mon, mon->cvar->lock->owner->id, + mon->cvar->lock->owner, mon->entryCount); + } else { + nb = PR_snprintf(buf, buflen, "[%p]", mon); + } + return nb; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prrwlock.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prrwlock.c new file mode 100644 index 00000000..35e0e3e7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prrwlock.c @@ -0,0 +1,512 @@ +/* -*- 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 + +#if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + +#include +#define HAVE_UNIX98_RWLOCK +#define RWLOCK_T pthread_rwlock_t +#define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL) +#define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock) +#define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock) +#define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock) +#define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock) + +#elif defined(SOLARIS) && (defined(_PR_PTHREADS) \ + || defined(_PR_GLOBAL_THREADS_ONLY)) + +#include +#define HAVE_UI_RWLOCK +#define RWLOCK_T rwlock_t +#define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL) +#define RWLOCK_DESTROY(lock) rwlock_destroy(lock) +#define RWLOCK_RDLOCK(lock) rw_rdlock(lock) +#define RWLOCK_WRLOCK(lock) rw_wrlock(lock) +#define RWLOCK_UNLOCK(lock) rw_unlock(lock) + +#endif + +/* + * Reader-writer lock + */ +struct PRRWLock { + char *rw_name; /* lock name */ + PRUint32 rw_rank; /* rank of the lock */ + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + RWLOCK_T rw_lock; +#else + PRLock *rw_lock; + PRInt32 rw_lock_cnt; /* == 0, if unlocked */ + /* == -1, if write-locked */ + /* > 0 , # of read locks */ + PRUint32 rw_reader_cnt; /* number of waiting readers */ + PRUint32 rw_writer_cnt; /* number of waiting writers */ + PRCondVar *rw_reader_waitq; /* cvar for readers */ + PRCondVar *rw_writer_waitq; /* cvar for writers */ +#ifdef DEBUG + PRThread *rw_owner; /* lock owner for write-lock */ +#endif +#endif +}; + +#ifdef DEBUG +#define _PR_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using + rank-order for locks + */ +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + +static PRUintn pr_thread_rwlock_key; /* TPD key for lock stack */ +static PRUintn pr_thread_rwlock_alloc_failed; + +#define _PR_RWLOCK_RANK_ORDER_LIMIT 10 + +typedef struct thread_rwlock_stack { + PRInt32 trs_index; /* top of stack */ + PRRWLock *trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock + pointers */ + +} thread_rwlock_stack; + +static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock); +static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void); +static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock); +static void _PR_RELEASE_LOCK_STACK(void *lock_stack); + +#endif + +/* + * Reader/Writer Locks + */ + +/* + * PR_NewRWLock + * Create a reader-writer lock, with the given lock rank and lock name + * + */ + +PR_IMPLEMENT(PRRWLock *) +PR_NewRWLock(PRUint32 lock_rank, const char *lock_name) +{ + PRRWLock *rwlock; +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + int err; +#endif + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + rwlock = PR_NEWZAP(PRRWLock); + if (rwlock == NULL) + return NULL; + + rwlock->rw_rank = lock_rank; + if (lock_name != NULL) { + rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1); + if (rwlock->rw_name == NULL) { + PR_DELETE(rwlock); + return(NULL); + } + strcpy(rwlock->rw_name, lock_name); + } else { + rwlock->rw_name = NULL; + } + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_INIT(&rwlock->rw_lock); + if (err != 0) { + PR_SetError(PR_UNKNOWN_ERROR, err); + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); + return NULL; + } + return rwlock; +#else + rwlock->rw_lock = PR_NewLock(); + if (rwlock->rw_lock == NULL) { + goto failed; + } + rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock); + if (rwlock->rw_reader_waitq == NULL) { + goto failed; + } + rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock); + if (rwlock->rw_writer_waitq == NULL) { + goto failed; + } + rwlock->rw_reader_cnt = 0; + rwlock->rw_writer_cnt = 0; + rwlock->rw_lock_cnt = 0; + return rwlock; + +failed: + if (rwlock->rw_reader_waitq != NULL) { + PR_DestroyCondVar(rwlock->rw_reader_waitq); + } + if (rwlock->rw_lock != NULL) { + PR_DestroyLock(rwlock->rw_lock); + } + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); + return NULL; +#endif +} + +/* +** Destroy the given RWLock "lock". +*/ +PR_IMPLEMENT(void) +PR_DestroyRWLock(PRRWLock *rwlock) +{ +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + int err; + err = RWLOCK_DESTROY(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_ASSERT(rwlock->rw_reader_cnt == 0); + PR_DestroyCondVar(rwlock->rw_reader_waitq); + PR_DestroyCondVar(rwlock->rw_writer_waitq); + PR_DestroyLock(rwlock->rw_lock); +#endif + if (rwlock->rw_name != NULL) + PR_Free(rwlock->rw_name); + PR_DELETE(rwlock); +} + +/* +** Read-lock the RWLock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Rlock(PRRWLock *rwlock) +{ +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * assert that rank ordering is not violated; the rank of 'rwlock' should + * be equal to or greater than the highest rank of all the locks held by + * the thread. + */ + PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || + (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK())); +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_RDLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * wait if write-locked or if a writer is waiting; preference for writers + */ + while ((rwlock->rw_lock_cnt < 0) || + (rwlock->rw_writer_cnt > 0)) { + rwlock->rw_reader_cnt++; + PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT); + rwlock->rw_reader_cnt--; + } + /* + * Increment read-lock count + */ + rwlock->rw_lock_cnt++; + + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_SET_THREAD_RWLOCK_RANK(rwlock); +#endif +} + +/* +** Write-lock the RWLock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Wlock(PRRWLock *rwlock) +{ +#if defined(DEBUG) +PRThread *me = PR_GetCurrentThread(); +#endif +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * assert that rank ordering is not violated; the rank of 'rwlock' should + * be equal to or greater than the highest rank of all the locks held by + * the thread. + */ + PR_ASSERT((rwlock->rw_rank == PR_RWLOCK_RANK_NONE) || + (rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK())); +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_WRLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * wait if read locked + */ + while (rwlock->rw_lock_cnt != 0) { + rwlock->rw_writer_cnt++; + PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT); + rwlock->rw_writer_cnt--; + } + /* + * apply write lock + */ + rwlock->rw_lock_cnt--; + PR_ASSERT(rwlock->rw_lock_cnt == -1); +#ifdef DEBUG + PR_ASSERT(me != NULL); + rwlock->rw_owner = me; +#endif + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_SET_THREAD_RWLOCK_RANK(rwlock); +#endif +} + +/* +** Unlock the RW lock. +*/ +PR_IMPLEMENT(void) +PR_RWLock_Unlock(PRRWLock *rwlock) +{ +#if defined(DEBUG) +PRThread *me = PR_GetCurrentThread(); +#endif +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) +int err; +#endif + +#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK) + err = RWLOCK_UNLOCK(&rwlock->rw_lock); + PR_ASSERT(err == 0); +#else + PR_Lock(rwlock->rw_lock); + /* + * lock must be read or write-locked + */ + PR_ASSERT(rwlock->rw_lock_cnt != 0); + if (rwlock->rw_lock_cnt > 0) { + + /* + * decrement read-lock count + */ + rwlock->rw_lock_cnt--; + if (rwlock->rw_lock_cnt == 0) { + /* + * lock is not read-locked anymore; wakeup a waiting writer + */ + if (rwlock->rw_writer_cnt > 0) + PR_NotifyCondVar(rwlock->rw_writer_waitq); + } + } else { + PR_ASSERT(rwlock->rw_lock_cnt == -1); + + rwlock->rw_lock_cnt = 0; +#ifdef DEBUG + PR_ASSERT(rwlock->rw_owner == me); + rwlock->rw_owner = NULL; +#endif + /* + * wakeup a writer, if present; preference for writers + */ + if (rwlock->rw_writer_cnt > 0) + PR_NotifyCondVar(rwlock->rw_writer_waitq); + /* + * else, wakeup all readers, if any + */ + else if (rwlock->rw_reader_cnt > 0) + PR_NotifyAllCondVar(rwlock->rw_reader_waitq); + } + PR_Unlock(rwlock->rw_lock); +#endif + +#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG + /* + * update thread's lock rank + */ + _PR_UNSET_THREAD_RWLOCK_RANK(rwlock); +#endif + return; +} + +#ifndef _PR_RWLOCK_RANK_ORDER_DEBUG + +void _PR_InitRWLocks(void) { } + +#else + +void _PR_InitRWLocks(void) +{ + /* + * allocated thread-private-data index for rwlock list + */ + if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key, + _PR_RELEASE_LOCK_STACK) == PR_FAILURE) { + pr_thread_rwlock_alloc_failed = 1; + return; + } +} + +/* + * _PR_SET_THREAD_RWLOCK_RANK + * Set a thread's lock rank, which is the highest of the ranks of all + * the locks held by the thread. Pointers to the locks are added to a + * per-thread list, which is anchored off a thread-private data key. + */ + +static void +_PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock) +{ +thread_rwlock_stack *lock_stack; +PRStatus rv; + + /* + * allocate a lock stack + */ + if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) { + lock_stack = (thread_rwlock_stack *) + PR_CALLOC(1 * sizeof(thread_rwlock_stack)); + if (lock_stack) { + rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack); + if (rv == PR_FAILURE) { + PR_DELETE(lock_stack); + pr_thread_rwlock_alloc_failed = 1; + return; + } + } else { + pr_thread_rwlock_alloc_failed = 1; + return; + } + } + /* + * add rwlock to lock stack, if limit is not exceeded + */ + if (lock_stack) { + if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT) + lock_stack->trs_stack[lock_stack->trs_index++] = rwlock; + } +} + +static void +_PR_RELEASE_LOCK_STACK(void *lock_stack) +{ + PR_ASSERT(lock_stack); + PR_DELETE(lock_stack); +} + +/* + * _PR_GET_THREAD_RWLOCK_RANK + * + * return thread's lock rank. If thread-private-data for the lock + * stack is not allocated, return PR_RWLOCK_RANK_NONE. + */ + +static PRUint32 +_PR_GET_THREAD_RWLOCK_RANK(void) +{ + thread_rwlock_stack *lock_stack; + + if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) + return (PR_RWLOCK_RANK_NONE); + else + return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank); +} + +/* + * _PR_UNSET_THREAD_RWLOCK_RANK + * + * remove the rwlock from the lock stack. Since locks may not be + * unlocked in a FIFO order, the entire lock stack is searched. + */ + +static void +_PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock) +{ + thread_rwlock_stack *lock_stack; + int new_index = 0, index, done = 0; + + lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key); + + PR_ASSERT(lock_stack != NULL); + + index = lock_stack->trs_index - 1; + while (index-- >= 0) { + if ((lock_stack->trs_stack[index] == rwlock) && !done) { + /* + * reset the slot for rwlock + */ + lock_stack->trs_stack[index] = NULL; + done = 1; + } + /* + * search for the lowest-numbered empty slot, above which there are + * no non-empty slots + */ + if ((lock_stack->trs_stack[index] != NULL) && !new_index) + new_index = index + 1; + if (done && new_index) + break; + } + /* + * set top of stack to highest numbered empty slot + */ + lock_stack->trs_index = new_index; + +} + +#endif /* _PR_RWLOCK_RANK_ORDER_DEBUG */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prsem.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prsem.c new file mode 100644 index 00000000..692bc0e9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prsem.c @@ -0,0 +1,174 @@ +/* -*- 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" +#if defined(XP_MAC) +#include "prsem.h" +#else +#include "obsolete/prsem.h" +#endif + +/************************************************************************/ + +/* +** Create a new semaphore. +*/ +PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) +{ + PRSemaphore *sem; + PRCondVar *cvar; + PRLock *lock; + + sem = PR_NEWZAP(PRSemaphore); + if (sem) { +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_NEW_SEM(&sem->md, value); +#else + lock = PR_NewLock(); + if (!lock) { + PR_DELETE(sem); + return NULL; + } + + cvar = PR_NewCondVar(lock); + if (!cvar) { + PR_DestroyLock(lock); + PR_DELETE(sem); + return NULL; + } + sem->cvar = cvar; + sem->count = value; +#endif + } + return sem; +} + +/* +** Destroy a semaphore. There must be no thread waiting on the semaphore. +** The caller is responsible for guaranteeing that the semaphore is +** no longer in use. +*/ +PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *sem) +{ +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_DESTROY_SEM(&sem->md); +#else + PR_ASSERT(sem->waiters == 0); + + PR_DestroyLock(sem->cvar->lock); + PR_DestroyCondVar(sem->cvar); +#endif + PR_DELETE(sem); +} + +/* +** Wait on a Semaphore. +** +** This routine allows a calling thread to wait or proceed depending upon the +** state of the semahore sem. The thread can proceed only if the counter value +** of the semaphore sem is currently greater than 0. If the value of semaphore +** sem is positive, it is decremented by one and the routine returns immediately +** allowing the calling thread to continue. If the value of semaphore sem is 0, +** the calling thread blocks awaiting the semaphore to be released by another +** thread. +** +** This routine can return PR_PENDING_INTERRUPT if the waiting thread +** has been interrupted. +*/ +PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *sem) +{ + PRStatus status = PR_SUCCESS; + +#ifdef HAVE_CVAR_BUILT_ON_SEM + return _PR_MD_WAIT_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + while (sem->count == 0) { + sem->waiters++; + status = PR_WaitCondVar(sem->cvar, PR_INTERVAL_NO_TIMEOUT); + sem->waiters--; + if (status != PR_SUCCESS) + break; + } + if (status == PR_SUCCESS) + sem->count--; + PR_Unlock(sem->cvar->lock); +#endif + + return (status); +} + +/* +** This routine increments the counter value of the semaphore. If other threads +** are blocked for the semaphore, then the scheduler will determine which ONE +** thread will be unblocked. +*/ +PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *sem) +{ +#ifdef HAVE_CVAR_BUILT_ON_SEM + _PR_MD_POST_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + if (sem->waiters) + PR_NotifyCondVar(sem->cvar); + sem->count++; + PR_Unlock(sem->cvar->lock); +#endif +} + +#if DEBUG +/* +** Returns the value of the semaphore referenced by sem without affecting +** the state of the semaphore. The value represents the semaphore vaule +** at the time of the call, but may not be the actual value when the +** caller inspects it. (FOR DEBUGGING ONLY) +*/ +PR_IMPLEMENT(PRUintn) PR_GetValueSem(PRSemaphore *sem) +{ + PRUintn rv; + +#ifdef HAVE_CVAR_BUILT_ON_SEM + rv = _PR_MD_GET_VALUE_SEM(&sem->md); +#else + PR_Lock(sem->cvar->lock); + rv = sem->count; + PR_Unlock(sem->cvar->lock); +#endif + + return rv; +} +#endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/threads/prtpd.c b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prtpd.c new file mode 100644 index 00000000..168c6601 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/threads/prtpd.c @@ -0,0 +1,280 @@ +/* -*- 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 ***** */ + +/* +** Thread Private Data +** +** There is an aribitrary limit on the number of keys that will be allocated +** by the runtime. It's largish, so it is intended to be a sanity check, not +** an impediment. +** +** There is a counter, initialized to zero and incremented every time a +** client asks for a new key, that holds the high water mark for keys. All +** threads logically have the same high water mark and are permitted to +** ask for TPD up to that key value. +** +** The vector to hold the TPD are allocated when PR_SetThreadPrivate() is +** called. The size of the vector will be some value greater than or equal +** to the current high water mark. Each thread has its own TPD length and +** vector. +** +** Threads that get private data for keys they have not set (or perhaps +** don't even exist for that thread) get a NULL return. If the key is +** beyond the high water mark, an error will be returned. +*/ + +/* +** As of this time, BeOS has its own TPD implementation. Integrating +** this standard one is a TODO for anyone with a bit of spare time on +** their hand. For now, we just #ifdef out this whole file and use +** the routines in pr/src/btthreads/ +*/ + +#ifndef XP_BEOS + +#include "primpl.h" + +#include + +#if defined(WIN95) +/* +** Some local variables report warnings on Win95 because the code paths +** using them are conditioned on HAVE_CUSTOME_USER_THREADS. +** The pragma suppresses the warning. +** +*/ +#pragma warning(disable : 4101) +#endif + +#define _PR_TPD_LIMIT 128 /* arbitary limit on the TPD slots */ +static PRInt32 _pr_tpd_length = 0; /* current length of destructor vector */ +static PRInt32 _pr_tpd_highwater = 0; /* next TPD key to be assigned */ +static PRThreadPrivateDTOR *_pr_tpd_destructors = NULL; + /* the destructors are associated with + the keys, therefore asserting that + the TPD key depicts the data's 'type' */ + +/* +** Initialize the thread private data manipulation +*/ +void _PR_InitTPD(void) +{ + _pr_tpd_destructors = (PRThreadPrivateDTOR*) + PR_CALLOC(_PR_TPD_LIMIT * sizeof(PRThreadPrivateDTOR*)); + PR_ASSERT(NULL != _pr_tpd_destructors); + _pr_tpd_length = _PR_TPD_LIMIT; +} + +/* +** Clean up the thread private data manipulation +*/ +void _PR_CleanupTPD(void) +{ +} /* _PR_CleanupTPD */ + +/* +** This routine returns a new index for per-thread-private data table. +** The index is visible to all threads within a process. This index can +** be used with the PR_SetThreadPrivate() and PR_GetThreadPrivate() routines +** to save and retrieve data associated with the index for a thread. +** +** The index independently maintains specific values for each binding thread. +** A thread can only get access to its own thread-specific-data. +** +** Upon a new index return the value associated with the index for all threads +** is NULL, and upon thread creation the value associated with all indices for +** that thread is NULL. +** +** "dtor" is the destructor function to invoke when the private +** data is set or destroyed +** +** Returns PR_FAILURE if the total number of indices will exceed the maximun +** allowed. +*/ + +PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex( + PRUintn *newIndex, PRThreadPrivateDTOR dtor) +{ + PRStatus rv; + PRInt32 index; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + PR_ASSERT(NULL != newIndex); + PR_ASSERT(NULL != _pr_tpd_destructors); + + index = PR_AtomicIncrement(&_pr_tpd_highwater) - 1; /* allocate index */ + if (_PR_TPD_LIMIT <= index) + { + PR_SetError(PR_TPD_RANGE_ERROR, 0); + rv = PR_FAILURE; /* that's just wrong */ + } + else + { + _pr_tpd_destructors[index] = dtor; /* record destructor @index */ + *newIndex = (PRUintn)index; /* copy into client's location */ + rv = PR_SUCCESS; /* that's okay */ + } + + return rv; +} + +/* +** Define some per-thread-private data. +** "index" is an index into the per-thread private data table +** "priv" is the per-thread-private data +** +** If the per-thread private data table has a previously registered +** destructor function and a non-NULL per-thread-private data value, +** the destructor function is invoked. +** +** This can return PR_FAILURE if index is invalid (ie., beyond the current +** high water mark) or memory is insufficient to allocate an exanded vector. +*/ + +PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv) +{ + PRThread *self = PR_GetCurrentThread(); + + /* + ** The index being set might not have a sufficient vector in this + ** thread. But if the index has been allocated, it's okay to go + ** ahead and extend this one now. + */ + if ((index >= _PR_TPD_LIMIT) || (index >= _pr_tpd_highwater)) + { + PR_SetError(PR_TPD_RANGE_ERROR, 0); + return PR_FAILURE; + } + + PR_ASSERT(((NULL == self->privateData) && (0 == self->tpdLength)) + || ((NULL != self->privateData) && (0 != self->tpdLength))); + + if ((NULL == self->privateData) || (self->tpdLength <= index)) + { + void *extension = PR_CALLOC(_pr_tpd_length * sizeof(void*)); + if (NULL == extension) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return PR_FAILURE; + } + if (self->privateData) { + (void)memcpy( + extension, self->privateData, + self->tpdLength * sizeof(void*)); + PR_DELETE(self->privateData); + } + self->tpdLength = _pr_tpd_length; + self->privateData = (void**)extension; + } + /* + ** There wasn't much chance of having to call the destructor + ** unless the slot already existed. + */ + else if (self->privateData[index] && _pr_tpd_destructors[index]) + { + void *data = self->privateData[index]; + self->privateData[index] = NULL; + (*_pr_tpd_destructors[index])(data); + } + + PR_ASSERT(index < self->tpdLength); + self->privateData[index] = priv; + + return PR_SUCCESS; +} + +/* +** Recover the per-thread-private data for the current thread. "index" is +** the index into the per-thread private data table. +** +** The returned value may be NULL which is indistinguishable from an error +** condition. +** +*/ + +PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index) +{ + PRThread *self = PR_GetCurrentThread(); + void *tpd = ((NULL == self->privateData) || (index >= self->tpdLength)) ? + NULL : self->privateData[index]; + + return tpd; +} + +/* +** Destroy the thread's private data, if any exists. This is called at +** thread termination time only. There should be no threading issues +** since this is being called by the thread itself. +*/ +void _PR_DestroyThreadPrivate(PRThread* self) +{ +#define _PR_TPD_DESTRUCTOR_ITERATIONS 4 + + if (NULL != self->privateData) /* we have some */ + { + PRBool clean; + PRUint32 index; + PRInt32 passes = _PR_TPD_DESTRUCTOR_ITERATIONS; + PR_ASSERT(0 != self->tpdLength); + do + { + clean = PR_TRUE; + for (index = 0; index < self->tpdLength; ++index) + { + void *priv = self->privateData[index]; /* extract */ + if (NULL != priv) /* we have data at this index */ + { + if (NULL != _pr_tpd_destructors[index]) + { + self->privateData[index] = NULL; /* precondition */ + (*_pr_tpd_destructors[index])(priv); /* destroy */ + clean = PR_FALSE; /* unknown side effects */ + } + } + } + } while ((--passes > 0) && !clean); /* limit # of passes */ + /* + ** We give up after a fixed number of passes. Any non-NULL + ** thread-private data value with a registered destructor + ** function is not destroyed. + */ + memset(self->privateData, 0, self->tpdLength * sizeof(void*)); + } +} /* _PR_DestroyThreadPrivate */ + +#endif /* !XP_BEOS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/tests/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/tests/Makefile.in new file mode 100644 index 00000000..88f26e9d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/Makefile.in @@ -0,0 +1,571 @@ +# +# ***** 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 ***** + + +#! gmake + +MOD_DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +DIRS = dll + +CSRCS = \ + accept.c \ + acceptread.c \ + acceptreademu.c \ + addrstr.c \ + affinity.c \ + alarm.c \ + anonfm.c \ + append.c \ + atomic.c \ + attach.c \ + bigfile.c \ + bigfile2.c \ + bigfile3.c \ + cleanup.c \ + cltsrv.c \ + concur.c \ + cvar.c \ + cvar2.c \ + dceemu.c \ + dlltest.c \ + dtoa.c \ + env.c \ + errcodes.c \ + errset.c \ + exit.c \ + fdcach.c \ + fileio.c \ + foreign.c \ + forktest.c \ + formattm.c \ + fsync.c \ + getai.c \ + gethost.c \ + getproto.c \ + i2l.c \ + initclk.c \ + inrval.c \ + instrumt.c \ + intrio.c \ + intrupt.c \ + io_timeout.c \ + ioconthr.c \ + ipv6.c \ + join.c \ + joinkk.c \ + joinku.c \ + joinuk.c \ + joinuu.c \ + layer.c \ + lazyinit.c \ + libfilename.c \ + lltest.c \ + lock.c \ + lockfile.c \ + logger.c \ + makedir.c \ + mbcs.c \ + multiacc.c \ + multiwait.c \ + many_cv.c \ + nameshm1.c \ + nbconn.c \ + nblayer.c \ + nonblock.c \ + ntioto.c \ + ntoh.c \ + obsints.c \ + op_2long.c \ + op_excl.c \ + op_filnf.c \ + op_filok.c \ + op_noacc.c \ + op_nofil.c \ + openfile.c \ + parent.c \ + peek.c \ + perf.c \ + pipeping.c \ + pipeping2.c \ + pipepong.c \ + pipepong2.c \ + pipeself.c \ + poll_er.c \ + poll_nm.c \ + poll_to.c \ + pollable.c \ + prftest.c \ + prftest1.c \ + prftest2.c \ + primblok.c \ + priotest.c \ + provider.c \ + prpoll.c \ + prpollml.c \ + ranfile.c \ + randseed.c \ + rmdir.c \ + rwlocktest.c \ + sel_spd.c \ + selct_er.c \ + selct_nm.c \ + selct_to.c \ + select2.c \ + selintr.c \ + sem.c \ + sema.c \ + semaerr.c \ + semaerr1.c \ + semaping.c \ + semapong.c \ + sendzlf.c \ + server_test.c \ + servr_kk.c \ + servr_ku.c \ + servr_uk.c \ + servr_uu.c \ + short_thread.c \ + sigpipe.c \ + socket.c \ + sockopt.c \ + sockping.c \ + sockpong.c \ + sprintf.c \ + sproc_ch.c \ + sproc_p.c \ + stack.c \ + stdio.c \ + str2addr.c \ + strod.c \ + suspend.c \ + switch.c \ + system.c \ + testbit.c \ + testfile.c \ + thrpool_server.c \ + thrpool_client.c \ + threads.c \ + thruput.c \ + timemac.c \ + timetest.c \ + tmoacc.c \ + tmocon.c \ + tpd.c \ + vercheck.c \ + version.c \ + udpsrv.c \ + writev.c \ + xnotify.c \ + y2k.c \ + y2ktmo.c \ + zerolen.c \ + $(NULL) + +ifeq ($(OS_TARGET),OS2) +CSRCS += \ + sleep.c \ + stat.c \ + yield.c \ + $(NULL) +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) + +INCLUDES = -I$(dist_includedir) -I$(topsrcdir)/pr/include -I$(topsrcdir)/pr/include/private + +ifeq ($(OS_ARCH), WINNT) +ifdef NS_USE_GCC + EXTRA_LIBS += -lwsock32 +else + EXTRA_LIBS += wsock32.lib + LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO + ifdef PROFILE + LDOPTS += -PROFILE -MAP + endif # profile +endif # NS_USE_GCC +endif + +ifeq ($(OS_ARCH),OS2) +ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO +else + EXTRA_LIBS = $(OS_LIBS) + LDOPTS = -Zomf -Zlinker /PM:VIO -Zlinker /ST:0x64000 +endif +endif + +ifneq ($(OS_ARCH), WINNT) +# Use an absolute pathname as the runtime library path (for the -R +# or -rpath linker option or the LD_RUN_PATH environment variable). +ifeq (,$(patsubst /%,,$(DIST))) +# $(DIST) is already an absolute pathname. +ABSOLUTE_LIB_DIR = $(dist_libdir) +else +# $(DIST) is a relative pathname: prepend the current directory. +PWD = $(shell pwd) +ABSOLUTE_LIB_DIR = $(PWD)/$(dist_libdir) +endif +endif + +ifeq ($(OS_ARCH), IRIX) + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -rpath $(ABSOLUTE_LIB_DIR) + ifdef NS_USE_GCC + LDOPTS += -Wl,-rdata_shared + else + LDOPTS += -rdata_shared + endif +# For 6.x machines, include this flag + ifeq ($(basename $(OS_RELEASE)),6) + ifndef NS_USE_GCC + ifeq ($(USE_N32),1) + LDOPTS += -n32 + else + LDOPTS += -32 + endif + + ifeq ($(USE_PTHREADS), 1) + ifeq ($(OS_RELEASE), 6.2) + LDOPTS += -Wl,-woff,85 + endif + endif + endif + endif +endif + +ifeq ($(OS_ARCH), OSF1) + ifeq ($(USE_CPLUS), 1) + CC = cxx + endif +# I haven't figured out how to pass -rpath to cc on OSF1 V3.2, so +# we do static linking. + ifeq (,$(filter-out V2.0 V3.2,$(OS_RELEASE))) + LIBNSPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a + EXTRA_LIBS = -lc_r + else + LDOPTS += -rpath $(ABSOLUTE_LIB_DIR) + endif +endif + +ifeq ($(OS_ARCH), HP-UX) + LDOPTS += -z -Wl,+s,+b,$(ABSOLUTE_LIB_DIR) + ifeq ($(USE_64),1) + LDOPTS += +DD64 + endif + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = $(LIBPTHREAD) + endif +endif + +# AIX +ifeq ($(OS_ARCH),AIX) + LDOPTS += -blibpath:$(ABSOLUTE_LIB_DIR):/usr/lib:/lib + ifneq ($(OS_ARCH)$(OS_RELEASE),AIX4.1) + LDOPTS += -brtl + EXTRA_LIBS = -ldl + endif +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) + ifneq ($(OS_RELEASE), 4.1.3_U1) + ifdef NS_USE_GCC + LDOPTS += -Xlinker -R -Xlinker $(ABSOLUTE_LIB_DIR) + else + ifeq ($(USE_CPLUS), 1) + CC = CC + endif + LDOPTS += -R $(ABSOLUTE_LIB_DIR) + endif + endif + + ifneq ($(LOCAL_THREADS_ONLY),1) + ifdef USE_PTHREADS + EXTRA_LIBS = -lpthread -lthread + else + EXTRA_LIBS = -lthread + endif + endif # LOCAL_THREADS_ONLY +endif # SunOS + +ifeq ($(OS_ARCH), NEC) + EXTRA_LIBS = $(OS_LIBS) +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. + export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH), NCR) +# NCR needs to link against -lsocket -lnsl -ldl (and -lc, which is +# linked implicitly by $(CC)). Note that we did not link with these +# system libraries when we built libnspr.so. + EXTRA_LIBS = -lsocket -lnsl -ldl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. + export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH), NEXTSTEP) +# balazs.pataki@sztaki.hu: linkage is done in a different pass in the `tests' +# modeul, so we have to pass the `-posix' flag by "hand" to `ld' +LDOPTS += -posix +endif + +ifeq ($(OS_ARCH), NEWS-OS) +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +#export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) + LIBNSPR = $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + LIBPLC = $(dist_libdir)/libplc$(MOD_MAJOR_VERSION).a + EXTRA_LIBS = -lsocket -lnsl -lgen -lresolv +endif + +ifeq ($(OS_ARCH), Linux) + ifeq ($(OS_RELEASE), 1.2) + EXTRA_LIBS = -ldl + else + LDOPTS += -Xlinker -rpath $(ABSOLUTE_LIB_DIR) + ifeq ($(USE_PTHREADS),1) + EXTRA_LIBS = -lpthread + endif + endif +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),SINIX) +EXTRA_LIBS = -lsocket -lnsl -lresolv -ldl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),OpenUNIX) +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +endif + +ifeq ($(OS_ARCH), UNIXWARE) +export LD_RUN_PATH = $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),FreeBSD) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +LDOPTS += -Xlinker -R $(ABSOLUTE_LIB_DIR) +endif + +ifeq ($(OS_ARCH),OpenBSD) +ifeq ($(USE_PTHREADS),1) +LDOPTS += -pthread +endif +endif + +ifeq ($(OS_ARCH),BSD_OS) +ifneq ($(OS_RELEASE),1.1) +EXTRA_LIBS = -ldl +endif +endif + +ifeq ($(USE_PTHREADS),1) +LIBPTHREAD = -lpthread +ifeq ($(OS_ARCH),AIX) +LIBPTHREAD = -lpthreads +endif +ifeq (,$(filter-out FreeBSD OpenBSD BSD_OS QNX Darwin OpenUNIX,$(OS_ARCH))) +LIBPTHREAD = +endif +ifeq ($(OS_ARCH)$(basename $(OS_RELEASE)),HP-UXB.10) +LIBPTHREAD = -ldce +endif +endif + + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifeq ($(OS_RELEASE),4.1) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(MOD_MAJOR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(NS_USE_GCC)_$(OS_ARCH),_WINNT) + link $(LDOPTS) $(EXTRA_LDOPTS) $< $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -out:$@ +else +ifeq ($(MOZ_OS2_TOOLS),VACPP) + $(LD) $(EXEFLAGS) $(LDOPTS) $< $(LIBPLC) $(LIBNSPR) $(OS_LIBS) $(EXTRA_LIBS) +else + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(EXTRA_LIBS) -o $@ +endif # OS/2 +endif # WINNT +endif # AIX_PRE_4_2 + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + +# The following tests call BSD socket functions, so they need to link +# with -lsocket on some platforms. +ifeq ($(OS_ARCH),SunOS) +ifneq ($(OS_RELEASE),4.1.3_U1) +ifeq ($(USE_IPV6),1) +$(OBJDIR)/gethost: $(OBJDIR)/gethost.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@ +endif +$(OBJDIR)/prpoll: $(OBJDIR)/prpoll.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) -lsocket $(EXTRA_LIBS) -o $@ +endif +endif + +ifeq ($(USE_PTHREADS), 1) +$(OBJDIR)/attach: $(OBJDIR)/attach.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/foreign: $(OBJDIR)/foreign.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/provider: $(OBJDIR)/provider.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/socket: $(OBJDIR)/socket.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +$(OBJDIR)/testfile: $(OBJDIR)/testfile.o + $(PURE) $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPLC) $(LIBNSPR) $(LIBPTHREAD) $(EXTRA_LIBS) -o $@ +endif + +# +# Run the test programs with no arguments +# +# Test output goes to the file pointed to by the environment variable +# NSPR_TEST_LOGFILE, if set, else to /dev/null +# +ECHO = echo +PROGRAMS = $(notdir $(PROGS)) +ifdef NSPR_TEST_LOGFILE +LOGFILE = $(NSPR_TEST_LOGFILE) +else +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +LOGFILE = nul +else +LOGFILE = /dev/null +endif +endif + +ifeq ($(OS_TARGET),Linux) +ECHO = /bin/echo +endif + +ALWAYS: + +runtests:: $(PROGS) ALWAYS + @$(ECHO) "\nNSPR Test Results - $(OBJDIR)\n" + @$(ECHO) "BEGIN\t\t\t`date`" + @$(ECHO) "NSPR_TEST_LOGFILE\t$(LOGFILE)\n" + @$(ECHO) "Test\t\t\tResult\n" + @cd $(OBJDIR); for i in $(PROGRAMS); do \ + $(ECHO) "$$i\c"; \ + ./$$i >> $(LOGFILE) 2>&1 ; \ + if [ 0 = $$? ] ; then \ + $(ECHO) "\t\t\tPassed"; \ + else \ + $(ECHO) "\t\t\tFAILED"; \ + fi; \ + done + @$(ECHO) "\nEND\t\t`date`\n" diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/README.TXT b/src/libs/xpcom18a4/nsprpub/pr/tests/README.TXT new file mode 100644 index 00000000..eeb1dd0d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/README.TXT @@ -0,0 +1,434 @@ +File: pr/tests/readme + +This document describes the test cases in the NSPR directory +pr/tests. + +===================================================================== +There are some sub-directories here: + +dll + sources for the .dll(.so) used by test dlltest.c + +macbuild + MacIntosh project files + +server + an empty directory. Does anyone remember why? + +w16gui + Sources for a modified version of the poppad application from + Charles Petzold's book "Programming Windows 3.1". These + sources were modified to test the library lib/ds/PLEvent. + These files are obsolete and will not be maintained. + + This test was superceded by lib/tests/windows/winevent.c and + lib/event.c and is now owned by CPD. + +===================================================================== +The individual files are described here. + +The script 'runtests.ksh' enumerates and runs test cases that are +expected to run on all platforms. + + +accept.c + Tests PR_Accept() and related socket functions. + +acceptread.c + Tests PR_AcceptRead() + +alarm.c + Tests alarm functions declared in obsolete/pralarm.h. + The alarm functions are obsolete, so is this test. + +atomic.c + Tests Atomic operations defined in pratom.h + +attach.c + Test PR_AttachThread() + Note: This is an NSPR private function. + +bigfile.c + Test 64bit file offset functions declared in prio.h + +bug1test.c + Demonstrates a bug on NT. + +cleanup.c + Tests PR_Cleanup() declared in prinit.h + +cltsrv.c + Tests many socket functions. + +concur.c + Tests threading functions and concurrent operations. + +cvar.c + Tests condition variables. + +cvar2.c + Tests condition variables. A rather abusive test. + +dbmalloc.c + Obsolete. Originally for testing debug builds of NSPR's malloc. + +dbmalloc1.c + Obsolete. Originally for testing debug builds of NSPR's malloc. + +dceemu.c + Tests special functions for DCE emulation. + +depend.c + Obsoltet. Tests early spec for library dependency. + +dlltest.c + Tests dynamic library fucntions. Used with dll/my.c + +dtoa.c + Tests conversions of double to string. + +exit.c + Tests PR_ProcessExit() declared in prinit.h + +fileio.c + Tests NSPR semaphores a bit of file i/o and threading + functions. + +foreign.c + Test auto-attach of a thread created by something other than + NSPR. + +forktest.c + Limited use. Tests unix fork() and related functions. + +fsync.c + Tests use of PR_Sync() declared in prio.h + +getproto.c + Tests socket functions PR_GetProtoByName(), etc. + +i2l.c + Tests LongLong functions for converting 32bit integer to 64bit + integer. + +initclk.c + Tests timing on minimal use of condition variable + +inrval.c + Tests interval timing functions. + +instrumt.c + Tests instrumentation functions. prcountr.h prtrace.h + +intrupt.c + Tests PR_Interrupt() + +ioconthr.c + Tests i/o continuation mechanism in pthreads. + +io_timeout.c + Test socket i/o timeouts. + +io_timeoutk.c + Obsolete. Subsumed in io_timeout.c + +io_timeoutu.c + Obsolete. Subsumed in io_timeout.c + +ipv6.c + Tests IPv6. IPv6 is not used by NSPR clients. + +join.c + Tests PR_JoinThread() + +joinkk.c + Tests PR_JoinThread() + +joinku.c + Tests PR_JoinThread() + +joinuk.c + Tests PR_JoinThread() + +joinuu.c + Tests PR_JoinThread() + +layer.c + Tests layered I/O. + +lazyinit.c + Tests implicit initialization. + +lltest.c + Tests LongLong (64bit integer) arithmentic and conversions. + +lock.c + Tests PR_Lock() in heavily threaded environment. + +lockfile.c + Test PR_Lockfile(). + +logger.c + Tests PR_LOG() + +makefile + The makefile that builds all the tests + +many_cv.c + Tests aquiring a large number of condition variables. + +multiwait.c + ??? + +nbconn.c + Test non-blocking connect. + +nblayer.c + Tests NSPR's layered I/O capability. + +nonblock.c + Tests operations on non-blocking socket. + +op_2long.c + Tests PR_Open() where filename is too long. + +op_filnf.c + Tests PR_Open() where filename is NotFound. + +op_filok.c + Tests PR_Open() where filename is accessable. + +op_noacc.c + Tests PR_Open() where file permissions are wrong. + Limited use. Windows has no concept of Unix style file permissions. + +op_nofil.c + Tests PR_Open() where filename does not exist. + +parent.c + Test parent/child process capability + +perf.c + Tests and measures context switch times for various thread + syncronization functions. + +pipeping.c + Tests inter-process pipes. Run with pipepong.c + +pipepong.c + Tests inter-process pipes. Run with pipeping.c + +pipeself.c + Tests inter-thread pipes. + +pollable.c + Tests pollable events. prio.h + +poll_er.c + Tests PR_Poll() where an error is expected. + +poll_nm.c + Tests PR_Poll() where normal operation is expected. + +poll_to.c + Tests PR_Poll() where timeout is expected. + +prftest.c + Tests printf-like formatting. + +prftest1.c + Obsolete. Subsumed in prftest.c + +prftest2.c + Obsolete. Subsumed in prftest.c + +priotest.c + Limited use. Tests NSPR thread dispatching priority. + +provider.c + +prpoll.c + Tests PR_Poll(). + +prselect.c + Obsolete. PR_Select() is obsolete. + +prttools.h + Unused file. + +ranfile.c + Tests random file access. + +readme + This file. + +runtests.ksh + A korn shell script that runs a set of tests that should run + on any of the NSPR supported platforms. + +runtests.pl + A perl script to run the test cases. This srcipt runs tests + common to all platforms and runs tests applicable to specific + platforms. Uses file runtests.txt to control execution. + +runtests.txt + Control file for perl script: runtests.pl + +rwlocktest.c + Tests Reader/Writer lock + +selct_er.c + Obsolete. PR_Select() is obsolete. + +selct_nm.c + Obsolete. PR_Select() is obsolete. + +selct_to.c + Obsolete. PR_Select() is obsolete. + +select2.c + Obsolete. PR_Select() is obsolete. + +sel_spd.c + Obsolete. PR_Select() is obsolete. + +sem.c + Obsolete. Semaphores are not supported. + +server_test.c + Tests sockets by simulating a server in loopback mode. + Makes its own client threads. + +servr_kk.c + Tests client/server sockets, threads using system threads. + +servr_ku.c + Tests client/server sockets, threads using system and user threads. + +servr_uk.c + Tests client/server sockets, threads using system and user threads. + +servr_uu.c + Tests client/server sockets, threads user threads. + +short_thread.c + Tests short-running threads. Useful for testing for race conditions. + +sigpipe.c + Tests NSPR's SIGPIPE handler. Unix only. + +sleep.c + Limited use. Tests sleep capability of platform. + +socket.c + Tests many socket functions. + +sockopt.c + Tests setting and getting socket options. + +sprintf.c + Tests sprintf. + +sproc_ch.c + Obsolete. Tests IRIX sproc-based threads. + +sproc_p.c + Obsolete. Tests IRIX sproc-based threads. + +stack.c + Test atomic stack operations. + +stat.c + Tests performance of getfileinfo() vs. stat() + +stdio.c + Tests NSPR's handling of stdin, stdout, stderr. + +strod.c + Tests formatting of double precision floating point. + +suspend.c + Private interfaces PR_SuspendAll(), PR_ResumeAll(), etc. + +switch.c + Tests thread switching + +system.c + Tests PR_GetSystemInfo() + +testbit.c + Tests bit arrays. + +testfile.c + Tests many file I/O functions. + +threads.c + Tests thread caching. + +thruput.c + Tests socket thruput. Must be run by hand as client/server. + Does not self terminate. + +time.c + Incomplete. Limited use. + +timemac.c + Test time and date functions. Originally for Mac. + +timetest.c + Tests time conversion over a wide range of dates. + +tmoacc.c + Server to tmocon.c and writev.c + Do not run it by itself. + +tmocon.c + Client thread to tmoacc.c + +tpd.c + Tests thread private data. + +udpsrv.c + Tests UDP socket functions. + +ut_ttools.h + unused file. + +version.c + Extract and print library version data. + +vercheck.c + Test PR_VersionCheck(). + +writev.c + Tests gather-write on a socket. Requires tmoacc.c + +xnotify.c + Tests cached monitors. + +yield.c + Limited use + +y2k.c + Test to verify NSPR's date functions as Y2K compliant. + +dll\Makefile + makefile for mygetval.c, mysetval.c + +dll\mygetval.c + Dynamic library test. See also dlltest.c + +dll\mysetval.c + Dynamic library test. See also dlltest.c + +w16gui\Makefile + Obsolete. Tests for lib/ds/PLEvent on Windows 3.1. +w16gui\popfile.c +w16gui\popfind.c +w16gui\popfont.c +w16gui\poppad.c +w16gui\poppad.h +w16gui\poppad.ico +w16gui\poppad.rc +w16gui\popprnt0.c +w16gui\readme.1st diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/accept.c b/src/libs/xpcom18a4/nsprpub/pr/tests/accept.c new file mode 100644 index 00000000..4fada1aa --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/accept.c @@ -0,0 +1,524 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: accept.c +** +** Description: Run accept() sucessful connection tests. +** +** Modification History: +** 04-Jun-97 AGarcia - Reconvert test file to return a 0 for PASS and a 1 for FAIL +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include + +#include "plgetopt.h" +#include "plerror.h" + +#define BASE_PORT 10000 + +#define CLIENT_DATA 128 + +#define ACCEPT_NORMAL 0x1 +#define ACCEPT_FAST 0x2 +#define ACCEPT_READ 0x3 +#define ACCEPT_READ_FAST 0x4 +#define ACCEPT_READ_FAST_CB 0x5 + +#define CLIENT_NORMAL 0x1 +#define CLIENT_TIMEOUT_ACCEPT 0x2 +#define CLIENT_TIMEOUT_SEND 0x3 + +#define SERVER_MAX_BIND_COUNT 100 + +#if defined(XP_MAC) || defined(XP_OS2) +#define TIMEOUTSECS 10 +#else +#define TIMEOUTSECS 2 +#endif +PRIntervalTime timeoutTime; + +static PRInt32 count = 1; +static PRFileDesc *output; +static PRNetAddr serverAddr; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; +static PRInt32 clientCommand; +static PRInt32 iterations; +static PRStatus rv; +static PRFileDesc *listenSock; +static PRFileDesc *clientSock = NULL; +static PRNetAddr listenAddr; +static PRNetAddr clientAddr; +static PRThread *clientThread; +static PRNetAddr *raddr; +static char buf[4096 + 2*sizeof(PRNetAddr) + 32]; +static PRInt32 status; +static PRInt32 bytesRead; + +PRIntn failed_already=0; +PRIntn debug_mode; + +void Test_Assert(const char *msg, const char *file, PRIntn line) +{ + failed_already=1; + if (debug_mode) { + PR_fprintf(output, "@%s:%d ", file, line); + PR_fprintf(output, msg); + } +} /* Test_Assert */ + +#define TEST_ASSERT(expr) \ + if (!(expr)) Test_Assert(#expr, __FILE__, __LINE__) + +#ifdef WINNT +#define CALLBACK_MAGIC 0x12345678 + +void timeout_callback(void *magic) +{ + TEST_ASSERT(magic == (void *)CALLBACK_MAGIC); + if (debug_mode) + PR_fprintf(output, "timeout callback called okay\n"); +} +#endif + + +static void PR_CALLBACK +ClientThread(void *_action) +{ + PRInt32 action = * (PRInt32 *) _action; + PRInt32 iterations = count; + PRFileDesc *sock = NULL; + + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = listenAddr.inet.port; + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + for (; iterations--;) { + PRInt32 rv; + char buf[CLIENT_DATA]; + + memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */ + sock = PR_NewTCPSocket(); + if (!sock) { + if (!debug_mode) + failed_already=1; + else + PR_fprintf(output, "client: unable to create socket\n"); + return; + } + + if (action != CLIENT_TIMEOUT_ACCEPT) { + + if ((rv = PR_Connect(sock, &serverAddr, + timeoutTime)) < 0) { + if (!debug_mode) + failed_already=1; + else + PR_fprintf(output, + "client: unable to connect to server (%ld, %ld, %ld, %ld)\n", + iterations, rv, PR_GetError(), PR_GetOSError()); + goto ErrorExit; + } + + if (action != CLIENT_TIMEOUT_SEND) { + if ((rv = PR_Send(sock, buf, CLIENT_DATA, + 0, timeoutTime))< 0) { + if (!debug_mode) + failed_already=1; + else + PR_fprintf(output, + "client: unable to send to server (%d, %ld, %ld)\n", + CLIENT_DATA, rv, PR_GetError()); + goto ErrorExit; + } + } else { + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); + } + } else { + PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); + } + if (debug_mode) + PR_fprintf(output, "."); + PR_Close(sock); + sock = NULL; + } + if (debug_mode) + PR_fprintf(output, "\n"); + +ErrorExit: + if (sock != NULL) + PR_Close(sock); +} + + +static void +RunTest(PRInt32 acceptType, PRInt32 clientAction) +{ +int i; + + /* First bind to the socket */ + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "unable to create listen socket\n"); + return; + } + memset(&listenAddr, 0 , sizeof(listenAddr)); + listenAddr.inet.family = PR_AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT); + listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + listenAddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + failed_already=1; + if (debug_mode) + PR_fprintf(output,"accept: ERROR - PR_Bind failed\n"); + return; + } + + + rv = PR_Listen(listenSock, 100); + if (rv == PR_FAILURE) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "unable to listen\n"); + return; + } + + clientCommand = clientAction; + clientThread = PR_CreateThread(PR_USER_THREAD, ClientThread, + (void *)&clientCommand, PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + if (!clientThread) { + failed_already=1; + if (debug_mode) + PR_fprintf(output, "error creating client thread\n"); + return; + } + + iterations = count; + for (;iterations--;) { + switch (acceptType) { + case ACCEPT_NORMAL: + clientSock = PR_Accept(listenSock, &clientAddr, + timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + TEST_ASSERT(clientSock == 0); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + case ACCEPT_READ: + status = PR_AcceptRead(listenSock, &clientSock, + &raddr, buf, CLIENT_DATA, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; +#ifdef WINNT + case ACCEPT_FAST: + clientSock = PR_NTFast_Accept(listenSock, + &clientAddr, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + TEST_ASSERT(clientSock == 0); + if (debug_mode) + PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError()); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock); + bytesRead = PR_Recv(clientSock, + buf, CLIENT_DATA, 0, timeoutTime); + TEST_ASSERT(bytesRead == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + break; + case ACCEPT_READ_FAST: + status = PR_NTFast_AcceptRead(listenSock, + &clientSock, &raddr, buf, 4096, timeoutTime); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + TEST_ASSERT(clientSock == NULL); + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; + case ACCEPT_READ_FAST_CB: + status = PR_NTFast_AcceptRead_WithTimeoutCallback( + listenSock, &clientSock, &raddr, buf, 4096, + timeoutTime, timeout_callback, (void *)CALLBACK_MAGIC); + switch(clientAction) { + case CLIENT_TIMEOUT_ACCEPT: + /* Invalid test case */ + TEST_ASSERT(0); + break; + case CLIENT_NORMAL: + TEST_ASSERT(clientSock); + TEST_ASSERT(status == CLIENT_DATA); + break; + case CLIENT_TIMEOUT_SEND: + if (debug_mode) + PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock); + TEST_ASSERT(clientSock == NULL); + TEST_ASSERT(status == -1); + TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); + break; + } + break; +#endif + } + if (clientSock != NULL) { + PR_Close(clientSock); + clientSock = NULL; + } + } + PR_Close(listenSock); + + PR_JoinThread(clientThread); +} + + +void AcceptUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_NORMAL); +} +void AcceptNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_NORMAL); +} +void AcceptReadTest(void) +{ + RunTest(ACCEPT_READ, CLIENT_NORMAL); +} +void AcceptReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_READ_FAST, CLIENT_NORMAL); +} +void AcceptReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_NORMAL); +} + +void TimeoutAcceptUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_ACCEPT); +} +void TimeoutAcceptNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_ACCEPT); +} +void TimeoutAcceptReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_ACCEPT); +} + +void TimeoutReadUpdatedTest(void) +{ + RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadTest(void) +{ + RunTest(ACCEPT_READ, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadNotUpdatedTest(void) +{ + RunTest(ACCEPT_READ_FAST, CLIENT_TIMEOUT_SEND); +} +void TimeoutReadReadCallbackTest(void) +{ + RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_SEND); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + if (debug_mode) + PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count); + +} + +int main(int argc, char **argv) +{ + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-c n] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdc:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + output = PR_STDERR; + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("accept.log"); + debug_mode = 1; +#endif + + timeoutTime = PR_SecondsToInterval(TIMEOUTSECS); + if (debug_mode) + PR_fprintf(output, "\nRun accept() sucessful connection tests\n"); + + Measure(AcceptUpdatedTest, "PR_Accept()"); + Measure(AcceptReadTest, "PR_AcceptRead()"); +#ifdef WINNT + Measure(AcceptNotUpdatedTest, "PR_NTFast_Accept()"); + Measure(AcceptReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); + Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); +#endif + if (debug_mode) + PR_fprintf(output, "\nRun accept() timeout in the accept tests\n"); +#ifdef WINNT + Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); +#endif + Measure(TimeoutReadUpdatedTest, "PR_Accept()"); + if (debug_mode) + PR_fprintf(output, "\nRun accept() timeout in the read tests\n"); + Measure(TimeoutReadReadTest, "PR_AcceptRead()"); +#ifdef WINNT + Measure(TimeoutReadNotUpdatedTest, "PR_NTFast_Accept()"); + Measure(TimeoutReadReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); + Measure(TimeoutReadReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); +#endif + PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS"); + return failed_already; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/acceptread.c b/src/libs/xpcom18a4/nsprpub/pr/tests/acceptread.c new file mode 100644 index 00000000..ceb445d0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/acceptread.c @@ -0,0 +1,272 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include + +#include + +#define DEFAULT_PORT 12273 +#define GET "GET / HTTP/1.0\n\n" +static PRFileDesc *std_out, *err_out; +static PRIntervalTime write_dally, accept_timeout; + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[100]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err_out, "PR_NetAddrToString"); + else PR_fprintf( + std_out, "Accepted connection from (0x%p)%s:%d\n", + address, buffer, address->inet.port); + return rv; +} /* PrintAddress */ + +static void ConnectingThread(void *arg) +{ + PRInt32 nbytes; + char buf[1024]; + PRFileDesc *sock; + PRNetAddr peer_addr, *addr; + + addr = (PRNetAddr*)arg; + + sock = PR_NewTCPSocket(); + if (sock == NULL) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed"); + PR_ProcessExit(1); + } + + if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_Connect (client) failed"); + PR_ProcessExit(1); + } + if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetPeerName (client) failed"); + PR_ProcessExit(1); + } + + /* + ** Then wait between the connection coming up and sending the expected + ** data. At some point in time, the server should fail due to a timeou + ** on the AcceptRead() operation, which according to the document is + ** only due to the read() portion. + */ + PR_Sleep(write_dally); + + nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Send (client) failed"); + + nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Recv (client) failed"); + else + { + PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes); + buf[sizeof(buf) - 1] = '\0'; + PR_fprintf(std_out, "%s\n", buf); + } + + if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) + PL_FPrintError(err_out, "PR_Shutdown (client) failed"); + + if (PR_FAILURE == PR_Close(sock)) + PL_FPrintError(err_out, "PR_Close (client) failed"); + + return; +} /* ConnectingThread */ + +#define BUF_SIZE 117 +static void AcceptingThread(void *arg) +{ + PRStatus rv; + PRInt32 bytes; + PRSize buf_size = BUF_SIZE; + PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32]; + PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg; + PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket(); + PRSocketOptionData sock_opt; + + if (NULL == listen_sock) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed"); + PR_ProcessExit(1); + } + sock_opt.option = PR_SockOpt_Reuseaddr; + sock_opt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(listen_sock, &sock_opt); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_SetSocketOption (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Bind(listen_sock, listen_addr); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Bind (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Listen(listen_sock, 10); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Listen (server) failed"); + PR_ProcessExit(1); + } + bytes = PR_AcceptRead( + listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout); + + if (-1 == bytes) PL_FPrintError(err_out, "PR_AcceptRead (server) failed"); + else + { + PrintAddress(accept_addr); + PR_fprintf( + std_out, "(Server) read [0x%p..0x%p) %s\n", + buf, &buf[BUF_SIZE], buf); + bytes = PR_Write(accept_sock, buf, bytes); + rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Shutdown (server) failed"); + } + + if (-1 != bytes) + { + rv = PR_Close(accept_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); + } + + rv = PR_Close(listen_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); +} /* AcceptingThread */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRHostEnt he; + PRStatus status; + PRIntn next_index; + PRUint16 port_number; + char netdb_buf[PR_NETDB_BUF_SIZE]; + PRNetAddr client_addr, server_addr; + PRThread *client_thread, *server_thread; + PRIntervalTime delta = PR_MillisecondsToInterval(500); + + err_out = PR_STDERR; + std_out = PR_STDOUT; + accept_timeout = PR_SecondsToInterval(2); + + if (argc != 2 && argc != 3) port_number = DEFAULT_PORT; + else port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]); + + status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + if (argc < 3) + { + status = PR_InitializeNetAddr( + PR_IpAddrLoopback, port_number, &client_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + } + else + { + status = PR_GetHostByName( + argv[1], netdb_buf, sizeof(netdb_buf), &he); + if (status == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetHostByName failed"); + PR_ProcessExit(1); + } + next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr); + if (next_index == -1) + { + PL_FPrintError(err_out, "PR_EnumerateHostEnt failed"); + PR_ProcessExit(1); + } + } + + for ( + write_dally = 0; + write_dally < accept_timeout + (2 * delta); + write_dally += delta) + { + PR_fprintf( + std_out, "Testing w/ write_dally = %d msec\n", + PR_IntervalToMilliseconds(write_dally)); + server_thread = PR_CreateThread( + PR_USER_THREAD, AcceptingThread, &server_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (server_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (server) failed"); + PR_ProcessExit(1); + } + + PR_Sleep(delta); /* let the server pot thicken */ + + client_thread = PR_CreateThread( + PR_USER_THREAD, ConnectingThread, &client_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (client_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (client) failed"); + PR_ProcessExit(1); + } + + if (PR_JoinThread(client_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (client) failed"); + + if (PR_JoinThread(server_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (server) failed"); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/acceptreademu.c b/src/libs/xpcom18a4/nsprpub/pr/tests/acceptreademu.c new file mode 100644 index 00000000..8d17f31a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/acceptreademu.c @@ -0,0 +1,302 @@ +/* -*- 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 test is the same as acceptread.c except that it uses the + * emulated acceptread method instead of the regular acceptread. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define DEFAULT_PORT 12273 +#define GET "GET / HTTP/1.0\n\n" +static PRFileDesc *std_out, *err_out; +static PRIntervalTime write_dally, accept_timeout; +static PRDescIdentity emu_layer_ident; +static PRIOMethods emu_layer_methods; + +/* the acceptread method in emu_layer_methods */ +static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, + PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout) +{ + return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); +} + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[100]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err_out, "PR_NetAddrToString"); + else PR_fprintf( + std_out, "Accepted connection from (0x%p)%s:%d\n", + address, buffer, address->inet.port); + return rv; +} /* PrintAddress */ + +static void ConnectingThread(void *arg) +{ + PRInt32 nbytes; + char buf[1024]; + PRFileDesc *sock; + PRNetAddr peer_addr, *addr; + + addr = (PRNetAddr*)arg; + + sock = PR_NewTCPSocket(); + if (sock == NULL) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed"); + PR_ProcessExit(1); + } + + if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_Connect (client) failed"); + PR_ProcessExit(1); + } + if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetPeerName (client) failed"); + PR_ProcessExit(1); + } + + /* + ** Then wait between the connection coming up and sending the expected + ** data. At some point in time, the server should fail due to a timeou + ** on the AcceptRead() operation, which according to the document is + ** only due to the read() portion. + */ + PR_Sleep(write_dally); + + nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Send (client) failed"); + + nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes == -1) PL_FPrintError(err_out, "PR_Recv (client) failed"); + else + { + PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes); + buf[sizeof(buf) - 1] = '\0'; + PR_fprintf(std_out, "%s\n", buf); + } + + if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) + PL_FPrintError(err_out, "PR_Shutdown (client) failed"); + + if (PR_FAILURE == PR_Close(sock)) + PL_FPrintError(err_out, "PR_Close (client) failed"); + + return; +} /* ConnectingThread */ + +#define BUF_SIZE 117 +static void AcceptingThread(void *arg) +{ + PRStatus rv; + PRInt32 bytes; + PRSize buf_size = BUF_SIZE; + PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32]; + PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg; + PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket(); + PRFileDesc *layer; + PRSocketOptionData sock_opt; + + if (NULL == listen_sock) + { + PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed"); + PR_ProcessExit(1); + } + layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods); + if (NULL == layer) + { + PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed"); + PR_ProcessExit(1); + } + if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_PushIOLayer (server) failed"); + PR_ProcessExit(1); + } + sock_opt.option = PR_SockOpt_Reuseaddr; + sock_opt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(listen_sock, &sock_opt); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_SetSocketOption (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Bind(listen_sock, listen_addr); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Bind (server) failed"); + PR_ProcessExit(1); + } + rv = PR_Listen(listen_sock, 10); + if (PR_FAILURE == rv) + { + PL_FPrintError(err_out, "PR_Listen (server) failed"); + PR_ProcessExit(1); + } + bytes = PR_AcceptRead( + listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout); + + if (-1 == bytes) PL_FPrintError(err_out, "PR_AcceptRead (server) failed"); + else + { + PrintAddress(accept_addr); + PR_fprintf( + std_out, "(Server) read [0x%p..0x%p) %s\n", + buf, &buf[BUF_SIZE], buf); + bytes = PR_Write(accept_sock, buf, bytes); + rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Shutdown (server) failed"); + } + + if (-1 != bytes) + { + rv = PR_Close(accept_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); + } + + rv = PR_Close(listen_sock); + if (PR_FAILURE == rv) + PL_FPrintError(err_out, "PR_Close (server) failed"); +} /* AcceptingThread */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRHostEnt he; + PRStatus status; + PRIntn next_index; + PRUint16 port_number; + char netdb_buf[PR_NETDB_BUF_SIZE]; + PRNetAddr client_addr, server_addr; + PRThread *client_thread, *server_thread; + PRIntervalTime delta = PR_MillisecondsToInterval(500); + + err_out = PR_STDERR; + std_out = PR_STDOUT; + accept_timeout = PR_SecondsToInterval(2); + emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead"); + emu_layer_methods = *PR_GetDefaultIOMethods(); + emu_layer_methods.acceptread = emu_AcceptRead; + + if (argc != 2 && argc != 3) port_number = DEFAULT_PORT; + else port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]); + + status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + if (argc < 3) + { + status = PR_InitializeNetAddr( + PR_IpAddrLoopback, port_number, &client_addr); + if (PR_SUCCESS != status) + { + PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); + PR_ProcessExit(1); + } + } + else + { + status = PR_GetHostByName( + argv[1], netdb_buf, sizeof(netdb_buf), &he); + if (status == PR_FAILURE) + { + PL_FPrintError(err_out, "PR_GetHostByName failed"); + PR_ProcessExit(1); + } + next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr); + if (next_index == -1) + { + PL_FPrintError(err_out, "PR_EnumerateHostEnt failed"); + PR_ProcessExit(1); + } + } + + for ( + write_dally = 0; + write_dally < accept_timeout + (2 * delta); + write_dally += delta) + { + PR_fprintf( + std_out, "Testing w/ write_dally = %d msec\n", + PR_IntervalToMilliseconds(write_dally)); + server_thread = PR_CreateThread( + PR_USER_THREAD, AcceptingThread, &server_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (server_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (server) failed"); + PR_ProcessExit(1); + } + + PR_Sleep(delta); /* let the server pot thicken */ + + client_thread = PR_CreateThread( + PR_USER_THREAD, ConnectingThread, &client_addr, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (client_thread == NULL) + { + PL_FPrintError(err_out, "PR_CreateThread (client) failed"); + PR_ProcessExit(1); + } + + if (PR_JoinThread(client_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (client) failed"); + + if (PR_JoinThread(server_thread) == PR_FAILURE) + PL_FPrintError(err_out, "PR_JoinThread (server) failed"); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/addrstr.c b/src/libs/xpcom18a4/nsprpub/pr/tests/addrstr.c new file mode 100644 index 00000000..a18f9a8c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/addrstr.c @@ -0,0 +1,114 @@ +/* -*- 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) 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 "prnetdb.h" + +#include +#include +#include + +const char *testaddrs[] = { + "::", "::", + "::1", "::1", + "::ffff", "::ffff", + "::1:0", "::0.1.0.0", + "::127.0.0.1", "::127.0.0.1", + "::FFFF:127.0.0.1", "::ffff:127.0.0.1", + "::FFFE:9504:3501", "::fffe:9504:3501", + "0:0:1:0:35c:0:0:0", "0:0:1:0:35c::", + "0:0:3f4c:0:0:4552:0:0", "::3f4c:0:0:4552:0:0", + "0:0:1245:0:0:0:0567:0", "0:0:1245::567:0", + "0:1:2:3:4:5:6:7", "0:1:2:3:4:5:6:7", + "1:2:3:0:4:5:6:7", "1:2:3:0:4:5:6:7", + "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:0", + "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8", + "1:2:3:4:5:6::7", "1:2:3:4:5:6:0:7", + 0 +}; + +const char *badaddrs[] = { + "::.1.2.3", + "ffff::.1.2.3", + "1:2:3:4:5:6:7::8", + "1:2:3:4:5:6::7:8", + "::ff99.2.3.4", + 0 +}; + +int failed_already = 0; + +int main() +{ + const char **nexttestaddr = testaddrs; + const char **nextbadaddr = badaddrs; + const char *in, *expected_out; + PRNetAddr addr; + char buf[256]; + PRStatus rv; + + while ((in = *nexttestaddr++) != 0) { + expected_out = *nexttestaddr++; + rv = PR_StringToNetAddr(in, &addr); + if (rv) { + printf("cannot convert %s to addr: %d\n", in, rv); + failed_already = 1; + continue; + } + rv = PR_NetAddrToString(&addr, buf, sizeof(buf)); + if (rv) { + printf("cannot convert %s back to string: %d\n", in, rv); + failed_already = 1; + continue; + } + if (strcmp(buf, expected_out)) { + /* This is not necessarily an error */ + printf("%s expected %s got %s\n", in, expected_out, buf); + } + } + while ((in = *nextbadaddr++) != 0) { + if (PR_StringToNetAddr(in, &addr) == PR_SUCCESS) { + printf("converted bad addr %s\n", in); + failed_already = 1; + } + } + if (failed_already) { + printf("FAIL\n"); + return 1; + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/affinity.c b/src/libs/xpcom18a4/nsprpub/pr/tests/affinity.c new file mode 100644 index 00000000..46f159bf --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/affinity.c @@ -0,0 +1,124 @@ +/* -*- 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 "nspr.h" +#include "pprthred.h" +#include "plgetopt.h" + +#include +#include +#include + +#ifndef XP_BEOS + +/* + * Test PR_GetThreadAffinityMask + * The function is called by each of local, global and global bound threads + * The test should be run on both single and multi-cpu systems + */ +static void PR_CALLBACK thread_start(void *arg) +{ +PRUint32 mask = 0; + + if (PR_GetThreadAffinityMask(PR_GetCurrentThread(), &mask)) + printf("\tthread_start: PR_GetCurrentThreadAffinityMask failed\n"); + else + printf("\tthread_start: AffinityMask = 0x%x\n",mask); + +} + +int main(int argc, char **argv) +{ + PRThread *t; + + printf("main: creating local thread\n"); + + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create local thread\n"); + exit(1); + } + + PR_JoinThread(t); + + printf("main: creating global thread\n"); + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create global thread\n"); + exit(1); + } + + PR_JoinThread(t); + + printf("main: creating global bound thread\n"); + t = PR_CreateThread(PR_USER_THREAD, + thread_start, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_BOUND_THREAD, + PR_JOINABLE_THREAD, + 0); + + if (NULL == t) { + printf("main: cannot create global bound thread\n"); + exit(1); + } + + PR_JoinThread(t); + + return 0; +} + +#else /* !XP_BEOS */ + +int main() +{ + printf( "This test is not supported on the BeOS\n" ); + return 0; +} +#endif /* !XP_BEOS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/alarm.c b/src/libs/xpcom18a4/nsprpub/pr/tests/alarm.c new file mode 100644 index 00000000..7af2ed4c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/alarm.c @@ -0,0 +1,569 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: alarmtst.c +** +** Description: Test alarms +** +** Modification History: +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "prlog.h" +#include "prinit.h" +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif +#include "prlock.h" +#include "prlong.h" +#include "prcvar.h" +#include "prinrval.h" +#include "prtime.h" + +/* Used to get the command line option */ +#include "plgetopt.h" +#include +#include + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static PRIntn debug_mode; +static PRIntn failed_already=0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct notifyData { + PRLock *ml; + PRCondVar *child; + PRCondVar *parent; + PRBool pending; + PRUint32 counter; +} NotifyData; + +static void Notifier(void *arg) +{ + NotifyData *notifyData = (NotifyData*)arg; + PR_Lock(notifyData->ml); + while (notifyData->counter > 0) + { + while (!notifyData->pending) + PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT); + notifyData->counter -= 1; + notifyData->pending = PR_FALSE; + PR_NotifyCondVar(notifyData->parent); + } + PR_Unlock(notifyData->ml); +} /* Notifier */ +/*********************************************************************** +** PRIVATE FUNCTION: ConditionNotify +** DESCRIPTION: +** +** INPUTS: loops +** OUTPUTS: None +** RETURN: overhead +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** +***********************************************************************/ + + +static PRIntervalTime ConditionNotify(PRUint32 loops) +{ + PRThread *thread; + NotifyData notifyData; + PRIntervalTime timein, overhead; + + timein = PR_IntervalNow(); + + notifyData.counter = loops; + notifyData.ml = PR_NewLock(); + notifyData.child = PR_NewCondVar(notifyData.ml); + notifyData.parent = PR_NewCondVar(notifyData.ml); + thread = PR_CreateThread( + PR_USER_THREAD, Notifier, ¬ifyData, + PR_GetThreadPriority(PR_GetCurrentThread()), + thread_scope, PR_JOINABLE_THREAD, 0); + + overhead = PR_IntervalNow() - timein; /* elapsed so far */ + + PR_Lock(notifyData.ml); + while (notifyData.counter > 0) + { + notifyData.pending = PR_TRUE; + PR_NotifyCondVar(notifyData.child); + while (notifyData.pending) + PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(notifyData.ml); + + timein = PR_IntervalNow(); + + (void)PR_JoinThread(thread); + PR_DestroyCondVar(notifyData.child); + PR_DestroyCondVar(notifyData.parent); + PR_DestroyLock(notifyData.ml); + + overhead += (PR_IntervalNow() - timein); /* more overhead */ + + return overhead; +} /* ConditionNotify */ + +static PRIntervalTime ConditionTimeout(PRUint32 loops) +{ + PRUintn count; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + PRIntervalTime interval = PR_MillisecondsToInterval(50); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + for (count = 0; count < loops; ++count) + { + overhead += interval; + PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS); + } + PR_Unlock(ml); + + timein = PR_IntervalNow(); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + overhead += (PR_IntervalNow() - timein); + + return overhead; +} /* ConditionTimeout */ + +typedef struct AlarmData { + PRLock *ml; + PRCondVar *cv; + PRUint32 rate, late, times; + PRIntervalTime duration, timein, period; +} AlarmData; + +static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late) +{ + PRStatus rv = PR_SUCCESS; + PRBool keepGoing, resetAlarm; + PRIntervalTime interval, now = PR_IntervalNow(); + AlarmData *ad = (AlarmData*)clientData; + + PR_Lock(ad->ml); + ad->late += late; + ad->times += 1; + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? + PR_TRUE : PR_FALSE; + if (!keepGoing) + rv = PR_NotifyCondVar(ad->cv); + resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE; + + interval = (ad->period + ad->rate - 1) / ad->rate; + if (!late && (interval > 10)) + { + interval &= (now & 0x03) + 1; + PR_WaitCondVar(ad->cv, interval); + } + + PR_Unlock(ad->ml); + + if (rv != PR_SUCCESS) + { + if (!debug_mode) failed_already=1; + else + printf("AlarmFn: notify status: FAIL\n"); + + } + + if (resetAlarm) + { + ad->rate += 3; + ad->late = ad->times = 0; + if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("AlarmFn: Resetting alarm status: FAIL\n"); + + keepGoing = PR_FALSE; + } + + } + + return keepGoing; +} /* AlarmFn1 */ + +static PRIntervalTime Alarms1(PRUint32 loops) +{ + PRAlarm *alarm; + AlarmData ad; + PRIntervalTime overhead, timein = PR_IntervalNow(); + PRIntervalTime duration = PR_SecondsToInterval(3); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + ad.ml = ml; + ad.cv = cv; + ad.rate = 1; + ad.times = loops; + ad.late = ad.times = 0; + ad.duration = duration; + ad.timein = PR_IntervalNow(); + ad.period = PR_SecondsToInterval(1); + + alarm = PR_CreateAlarm(); + + (void)PR_SetAlarm( + alarm, ad.period, ad.rate, AlarmFn1, &ad); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + timein = PR_IntervalNow(); + (void)PR_DestroyAlarm(alarm); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + overhead += (PR_IntervalNow() - timein); + + return duration + overhead; +} /* Alarms1 */ + +static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late) +{ +#if defined(XP_MAC) +#pragma unused (id) +#endif + + PRBool keepGoing; + PRStatus rv = PR_SUCCESS; + AlarmData *ad = (AlarmData*)clientData; + PRIntervalTime interval, now = PR_IntervalNow(); + + PR_Lock(ad->ml); + ad->times += 1; + keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ? + PR_TRUE : PR_FALSE; + interval = (ad->period + ad->rate - 1) / ad->rate; + + if (!late && (interval > 10)) + { + interval &= (now & 0x03) + 1; + PR_WaitCondVar(ad->cv, interval); + } + + if (!keepGoing) rv = PR_NotifyCondVar(ad->cv); + + PR_Unlock(ad->ml); + + + if (rv != PR_SUCCESS) + failed_already=1;; + + return keepGoing; +} /* AlarmFn2 */ + +static PRIntervalTime Alarms2(PRUint32 loops) +{ + PRStatus rv; + PRAlarm *alarm; + PRIntervalTime overhead, timein = PR_IntervalNow(); + AlarmData ad; + PRIntervalTime duration = PR_SecondsToInterval(30); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + ad.ml = ml; + ad.cv = cv; + ad.rate = 1; + ad.times = loops; + ad.late = ad.times = 0; + ad.duration = duration; + ad.timein = PR_IntervalNow(); + ad.period = PR_SecondsToInterval(1); + + alarm = PR_CreateAlarm(); + + (void)PR_SetAlarm( + alarm, ad.period, ad.rate, AlarmFn2, &ad); + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + timein = PR_IntervalNow(); + + rv = PR_DestroyAlarm(alarm); + if (rv != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("***Destroying alarm status: FAIL\n"); + } + + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + overhead += (PR_IntervalNow() - timein); + + return duration + overhead; +} /* Alarms2 */ + +static PRIntervalTime Alarms3(PRUint32 loops) +{ + PRIntn i; + PRStatus rv; + PRAlarm *alarm; + AlarmData ad[3]; + PRIntervalTime duration = PR_SecondsToInterval(30); + PRIntervalTime overhead, timein = PR_IntervalNow(); + + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + + for (i = 0; i < 3; ++i) + { + ad[i].ml = ml; + ad[i].cv = cv; + ad[i].rate = 1; + ad[i].times = loops; + ad[i].duration = duration; + ad[i].late = ad[i].times = 0; + ad[i].timein = PR_IntervalNow(); + ad[i].period = PR_SecondsToInterval(1); + + /* more loops, faster rate => same elapsed time */ + ad[i].times = (i + 1) * loops; + ad[i].rate = (i + 1) * 10; + } + + alarm = PR_CreateAlarm(); + + for (i = 0; i < 3; ++i) + { + (void)PR_SetAlarm( + alarm, ad[i].period, ad[i].rate, + AlarmFn2, &ad[i]); + } + + overhead = PR_IntervalNow() - timein; + + PR_Lock(ml); + for (i = 0; i < 3; ++i) + { + while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(ml); + + timein = PR_IntervalNow(); + + if (debug_mode) + printf + ("Alarms3 finished at %u, %u, %u\n", + ad[0].timein, ad[1].timein, ad[2].timein); + + rv = PR_DestroyAlarm(alarm); + if (rv != PR_SUCCESS) + { + if (!debug_mode) + failed_already=1; + else + printf("***Destroying alarm status: FAIL\n"); + } + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + overhead += (duration / 3); + overhead += (PR_IntervalNow() - timein); + + return overhead; +} /* Alarms3 */ + +static PRUint32 TimeThis( + const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops) +{ + PRUint32 overhead, usecs; + PRIntervalTime predicted, timein, timeout, ticks; + + if (debug_mode) + printf("Testing %s ...", msg); + + timein = PR_IntervalNow(); + predicted = func(loops); + timeout = PR_IntervalNow(); + + if (debug_mode) + printf(" done\n"); + + ticks = timeout - timein; + usecs = PR_IntervalToMicroseconds(ticks); + overhead = PR_IntervalToMicroseconds(predicted); + + if(ticks < predicted) + { + if (debug_mode) { + printf("\tFinished in negative time\n"); + printf("\tpredicted overhead was %d usecs\n", overhead); + printf("\ttest completed in %d usecs\n\n", usecs); + } + } + else + { + if (debug_mode) + printf( + "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n", + usecs, overhead, ((double)(usecs - overhead) / (double)loops)); + } + + return overhead; +} /* TimeThis */ + +int prmain(int argc, char** argv) +{ + PRUint32 cpu, cpus = 0, loops = 0; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* GLOBAL threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* loop count */ + loops = atoi(opt->value); + break; + case 'c': /* concurrency limit */ + cpus = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + + if (cpus == 0) cpus = 1; + if (loops == 0) loops = 4; + + if (debug_mode) + printf("Alarm: Using %d loops\n", loops); + + if (debug_mode) + printf("Alarm: Using %d cpu(s)\n", cpus); +#ifdef XP_MAC + SetupMacPrintfLog("alarm.log"); + debug_mode = 1; +#endif + + for (cpu = 1; cpu <= cpus; ++cpu) + { + if (debug_mode) + printf("\nAlarm: Using %d CPU(s)\n", cpu); + + PR_SetConcurrency(cpu); + + /* some basic time test */ + (void)TimeThis("ConditionNotify", ConditionNotify, loops); + (void)TimeThis("ConditionTimeout", ConditionTimeout, loops); + (void)TimeThis("Alarms1", Alarms1, loops); + (void)TimeThis("Alarms2", Alarms2, loops); + (void)TimeThis("Alarms3", Alarms3, loops); + } + return 0; +} + +int main(int argc, char** argv) +{ + PR_Initialize(prmain, argc, argv, 0); + PR_STDIO_INIT(); + if (failed_already) return 1; + else return 0; + +} /* main */ + + +/* alarmtst.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/anonfm.c b/src/libs/xpcom18a4/nsprpub/pr/tests/anonfm.c new file mode 100644 index 00000000..aeab86b1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/anonfm.c @@ -0,0 +1,343 @@ +/* -*- 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 ***** */ + +/* +** File: anonfm.c +** Description: Test anonymous file map +** +** Synopsis: anonfm [options] [dirName] +** +** Options: +** -d enable debug mode +** -h display a help message +** -s size of the anonymous memory map, in KBytes. default: 100KBytes. +** -C 1 Operate this process as ClientOne() +** -C 2 Operate this process as ClientTwo() +** +** anonfn.c contains two tests, corresponding to the two protocols for +** passing an anonymous file map to a child process. +** +** ServerOne()/ClientOne() tests the passing of "raw" file map; it uses +** PR_CreateProcess() [for portability of the test case] to create the +** child process, but does not use the PRProcessAttr structure for +** passing the file map data. +** +** ServerTwo()/ClientTwo() tests the passing of the file map using the +** PRProcessAttr structure. +** +*/ +#include +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRUint32 failed_already = 0; + +PRIntn debug = 0; +PRIntn client = 0; /* invoke client, style */ +char dirName[512] = "."; /* directory name to contain anon mapped file */ +PRSize fmSize = (100 * 1024 ); +PRUint32 fmMode = 0600; +PRFileMapProtect fmProt = PR_PROT_READWRITE; +const char *fmEnvName = "nsprFileMapEnvVariable"; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("anonfm [options] [dirName]\n"); + printf("-d -- enable debug mode\n"); + printf("dirName is alternate directory name. Default: . (current directory)\n"); + exit(1); +} /* end Help() */ + + +/* +** ClientOne() -- +*/ +static void ClientOne( void ) +{ + PRFileMap *fm; + char *fmString; + char *addr; + PRStatus rc; + + PR_LOG(lm, msgLevel, + ("ClientOne() starting")); + + fmString = PR_GetEnv( fmEnvName ); + if ( NULL == fmString ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_Getenv() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_Getenv(): found: %s", fmString)); + + fm = PR_ImportFileMapFromString( fmString ); + if ( NULL == fm ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_ImportFileMapFromString() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_ImportFileMapFromString(): fm: %p", fm )); + + addr = PR_MemMap( fm, LL_ZERO, fmSize ); + if ( NULL == addr ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemMap() failed, OSError: %d", PR_GetOSError() )); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemMap(): addr: %p", addr )); + + /* write to memory map to release server */ + *addr = 1; + + rc = PR_MemUnmap( addr, fmSize ); + PR_ASSERT( rc == PR_SUCCESS ); + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemUnap(): success" )); + + rc = PR_CloseFileMap( fm ); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_MemUnap() failed, OSError: %d", PR_GetOSError() )); + return; + } + PR_LOG(lm, msgLevel, + ("ClientOne(): PR_CloseFileMap(): success" )); + + return; +} /* end ClientOne() */ + +/* +** ClientTwo() -- +*/ +static void ClientTwo( void ) +{ + failed_already = 1; +} /* end ClientTwo() */ + +/* +** ServerOne() -- +*/ +static void ServerOne( void ) +{ + PRFileMap *fm; + PRStatus rc; + PRIntn i; + char *addr; + char fmString[256]; + char envBuf[256]; + char *child_argv[8]; + PRProcess *proc; + PRInt32 exit_status; + + PR_LOG(lm, msgLevel, + ("ServerOne() starting")); + + fm = PR_OpenAnonFileMap( dirName, fmSize, fmProt ); + if ( NULL == fm ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_OpenAnonFileMap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): FileMap: %p", fm )); + + rc = PR_ExportFileMapAsString( fm, sizeof(fmString), fmString ); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_ExportFileMap() failed")); + return; + } + + /* + ** put the string into the environment + */ + PR_snprintf( envBuf, sizeof(envBuf), "%s=%s", fmEnvName, fmString); + putenv( envBuf ); + + addr = PR_MemMap( fm, LL_ZERO, fmSize ); + if ( NULL == addr ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_MemMap() failed")); + return; + } + + /* set initial value for client */ + for (i = 0; i < (PRIntn)fmSize ; i++ ) + *(addr+i) = 0x00; + + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_MemMap(): addr: %p", addr )); + + /* + ** set arguments for child process + */ + child_argv[0] = "anonfm"; + child_argv[1] = "-C"; + child_argv[2] = "1"; + child_argv[3] = NULL; + + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + PR_ASSERT( proc ); + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_CreateProcess(): proc: %x", proc )); + + /* + ** ClientOne() will set the memory to 1 + */ + PR_LOG(lm, msgLevel, + ("ServerOne(): waiting on Client, *addr: %x", *addr )); + while( *addr == 0x00 ) { + if ( debug ) + fprintf(stderr, "."); + PR_Sleep(PR_MillisecondsToInterval(300)); + } + if ( debug ) + fprintf(stderr, "\n"); + PR_LOG(lm, msgLevel, + ("ServerOne(): Client responded" )); + + rc = PR_WaitProcess( proc, &exit_status ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_MemUnmap( addr, fmSize); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_MemUnmap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_MemUnmap(): success" )); + + rc = PR_CloseFileMap(fm); + if ( PR_FAILURE == rc ) { + failed_already = 1; + PR_LOG(lm, msgLevel, + ("PR_CloseFileMap() failed")); + return; + } + PR_LOG(lm, msgLevel, + ("ServerOne(): PR_CloseFileMap() success" )); + + return; +} /* end ServerOne() */ + +/* +** ServerTwo() -- +*/ +static void ServerTwo( void ) +{ + PR_LOG(lm, msgLevel, + ("ServerTwo(): Not implemented yet" )); +} /* end ServerTwo() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdC:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'C': /* Client style */ + client = atol(opt->value); + break; + case 's': /* file size */ + fmSize = atol( opt->value ) * 1024; + break; + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'h': /* help message */ + Help(); + break; + default: + strcpy(dirName, opt->value); + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + if ( client == 1 ) { + ClientOne(); + } else if ( client == 2 ) { + ClientTwo(); + } else { + ServerOne(); + if ( failed_already ) goto Finished; + ServerTwo(); + } + +Finished: + if ( debug ) + printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end anonfm.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/append.c b/src/libs/xpcom18a4/nsprpub/pr/tests/append.c new file mode 100644 index 00000000..3800e2fb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/append.c @@ -0,0 +1,158 @@ +/* -*- 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 ***** */ + +/* +** File: append.c +** Description: Testing File writes where PR_APPEND was used on open +** +** append attempts to verify that a file opened with PR_APPEND +** will always append to the end of file, regardless where the +** current file pointer is positioned. To do this, PR_Seek() is +** called before each write with the position set to beginning of +** file. Subsequent writes should always append. +** The file is read back, summing the integer data written to the +** file. If the expected result is equal, the test passes. +** +** See BugSplat: 4090 +*/ +#include "plgetopt.h" +#include "nspr.h" + +#include +#include + +PRIntn debug = 0; +PRIntn verbose = 0; +PRBool failedAlready = PR_FALSE; +const PRInt32 addedBytes = 1000; +const PRInt32 buf = 1; /* constant written to fd, addedBytes times */ +PRInt32 inBuf; /* read it back into here */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRStatus rc; + PRInt32 rv; + PRFileDesc *fd; + PRIntn i; + PRInt32 sum = 0; + + { /* Get command line options */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + break; + case 'v': /* verbose */ + verbose = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } /* end block "Get command line options" */ +/* ---------------------------------------------------------------------- */ + fd = PR_Open( "/tmp/nsprAppend", (PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE | PR_WRONLY), 0666 ); + if ( NULL == fd ) { + if (debug) printf("PR_Open() failed for writing: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + + for ( i = 0; i < addedBytes ; i++ ) { + rv = PR_Write( fd, &buf, sizeof(buf)); + if ( sizeof(buf) != rv ) { + if (debug) printf("PR_Write() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + rv = PR_Seek( fd, 0 , PR_SEEK_SET ); + if ( -1 == rv ) { + if (debug) printf("PR_Seek() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + } + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + if (debug) printf("PR_Close() failed after writing: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } +/* ---------------------------------------------------------------------- */ + fd = PR_Open( "/tmp/nsprAppend", PR_RDONLY, 0 ); + if ( NULL == fd ) { + if (debug) printf("PR_Open() failed for reading: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + + for ( i = 0; i < addedBytes ; i++ ) { + rv = PR_Read( fd, &inBuf, sizeof(inBuf)); + if ( sizeof(inBuf) != rv) { + if (debug) printf("PR_Write() failed: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + sum += inBuf; + } + + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + if (debug) printf("PR_Close() failed after reading: %d\n", PR_GetError()); + failedAlready = PR_TRUE; + goto Finished; + } + if ( sum != addedBytes ) { + if (debug) printf("Uh Oh! addedBytes: %d. Sum: %d\n", addedBytes, sum); + failedAlready = PR_TRUE; + goto Finished; + } + +/* ---------------------------------------------------------------------- */ +Finished: + if (debug || verbose) printf("%s\n", (failedAlready)? "FAILED" : "PASSED" ); + return( (failedAlready)? 1 : 0 ); +} /* main() */ + +/* append.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/atomic.c b/src/libs/xpcom18a4/nsprpub/pr/tests/atomic.c new file mode 100644 index 00000000..1295b297 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/atomic.c @@ -0,0 +1,126 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "pratom.h" + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 rv, oldval, test, result = 0; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + + oldval = test = -2; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicIncrement(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicIncrement(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + + oldval = test = -2; + rv = PR_AtomicAdd(&test,1); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, 1, rv, (rv == -1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicAdd(&test, 4); + result = result | ((rv == 3) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, 4, rv, (rv == 3) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicAdd(&test, -6); + result = result | ((rv == -3) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicAdd(%d,%d) == %d: %s\n", + oldval, -6, rv, (rv == -3) ? "PASSED" : "FAILED"); + + oldval = test = 2; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == 1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == 1) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == 0) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == 0) ? "PASSED" : "FAILED"); + oldval = test; + rv = PR_AtomicDecrement(&test); + result = result | ((rv == -1) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicDecrement(%d) == %d: %s\n", + oldval, rv, (rv == -1) ? "PASSED" : "FAILED"); + + /* set to a different value */ + oldval = test = -2; + rv = PR_AtomicSet(&test, 2); + result = result | (((rv == -2) && (test == 2)) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicSet(%d, %d) == %d: %s\n", + oldval, 2, rv, ((rv == -2) && (test == 2)) ? "PASSED" : "FAILED"); + + /* set to the same value */ + oldval = test = -2; + rv = PR_AtomicSet(&test, -2); + result = result | (((rv == -2) && (test == -2)) ? 0 : 1); + PR_fprintf( + output, "PR_AtomicSet(%d, %d) == %d: %s\n", + oldval, -2, rv, ((rv == -2) && (test == -2)) ? "PASSED" : "FAILED"); + + PR_fprintf( + output, "Atomic operations test %s\n", + (result == 0) ? "PASSED" : "FAILED"); + return result; +} /* main */ + +/* atomic.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/attach.c b/src/libs/xpcom18a4/nsprpub/pr/tests/attach.c new file mode 100644 index 00000000..20da8ec3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/attach.c @@ -0,0 +1,392 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: attach.c +** +** Description: Platform-specific code to create a native thread. The native thread will +** repeatedly call PR_AttachThread and PR_DetachThread. The +** primordial thread waits for this new thread to finish. +** +** Modification History: +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +/* Used to get the command line option */ +#include "nspr.h" +#include "pprthred.h" +#include "plgetopt.h" + +#include + +#ifdef WIN32 +#include +#include +#elif defined(_PR_PTHREADS) +#include +#include "md/_pth.h" +#elif defined(IRIX) +#include +#include +#include +#include +#elif defined(SOLARIS) +#include +#elif defined(OS2) +#define INCL_DOS +#define INCL_ERRORS +#include +#include +#elif defined(XP_BEOS) +#include +#endif + +#define DEFAULT_COUNT 1000 +PRIntn failed_already=0; +PRIntn debug_mode; + + +int count; + + +static void +AttachDetach(void) +{ + PRThread *me; + PRInt32 index; + + for (index=0;indexoption) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#if defined(WIN16) + printf("attach: This test is not valid for Win16\n"); + goto exit_now; +#endif + + if(0 == count) count = DEFAULT_COUNT; + + /* + * To force the implicit initialization of nspr20 + */ + PR_SetError(0, 0); + PR_STDIO_INIT(); + + /* + * Platform-specific code to create a native thread. The native + * thread will repeatedly call PR_AttachThread and PR_DetachThread. + * The primordial thread waits for this new thread to finish. + */ + +#ifdef _PR_PTHREADS + + rv = _PT_PTHREAD_ATTR_INIT(&attr); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + +#ifndef _PR_DCETHREADS + rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } +#endif /* !_PR_DCETHREADS */ + rv = _PT_PTHREAD_CREATE(&threadID, attr, threadStartFunc, NULL); + if (rv != 0) { + fprintf(stderr, "thread creation failed: error code %d\n", rv); + failed_already=1; + goto exit_now; + } + else { + if (debug_mode) + printf ("thread creation succeeded \n"); + + } + rv = _PT_PTHREAD_ATTR_DESTROY(&attr); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + rv = pthread_join(threadID, NULL); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) { + failed_already=1; + goto exit_now; + } + +#elif defined(SOLARIS) + + rv = thr_create(NULL, 0, threadStartFunc, NULL, 0, &threadID); + if (rv != 0) { + if(!debug_mode) { + failed_already=1; + goto exit_now; + } else + fprintf(stderr, "thread creation failed: error code %d\n", rv); + } + rv = thr_join(threadID, NULL, NULL); + if (debug_mode) PR_ASSERT(0 == rv); + else if (0 != rv) + { + failed_already=1; + goto exit_now; + } + + +#elif defined(WIN32) + + hThread = (HANDLE) _beginthreadex(NULL, 0, threadStartFunc, NULL, + 0, &threadID); + if (hThread == 0) { + fprintf(stderr, "thread creation failed: error code %d\n", + GetLastError()); + failed_already=1; + goto exit_now; + } + rv = WaitForSingleObject(hThread, INFINITE); + if (debug_mode)PR_ASSERT(rv != WAIT_FAILED); + else if (rv == WAIT_FAILED) { + failed_already=1; + goto exit_now; + } + +#elif defined(IRIX) + + threadID = sproc(threadStartFunc, PR_SALL, NULL); + if (threadID == -1) { + + fprintf(stderr, "thread creation failed: error code %d\n", + errno); + failed_already=1; + goto exit_now; + + } + else { + if (debug_mode) + printf ("thread creation succeeded \n"); + sleep(3); + goto exit_now; + } + rv = waitpid(threadID, NULL, 0); + if (debug_mode) PR_ASSERT(rv != -1); + else if (rv != -1) { + failed_already=1; + goto exit_now; + } + +#elif defined(OS2) + +# ifdef __EMX__ + threadID = (TID) _beginthread((void *)threadStartFunc, NULL, + 32768, NULL); +# else + threadID = (TID) _beginthread((void(* _Optlink)(void*))threadStartFunc, NULL, + 32768, NULL); +# endif + if (threadID == -1) { + fprintf(stderr, "thread creation failed: error code %d\n", errno); + failed_already=1; + goto exit_now; + } + rv = DosWaitThread(&threadID, DCWW_WAIT); + if (debug_mode) { + PR_ASSERT(rv == NO_ERROR); + } else if (rv != NO_ERROR) { + failed_already=1; + goto exit_now; + } + +#elif defined(XP_BEOS) + + threadID = spawn_thread(threadStartFunc, NULL, B_NORMAL_PRIORITY, NULL); + if (threadID <= B_ERROR) { + fprintf(stderr, "thread creation failed: error code %08lx\n", threadID); + failed_already = 1; + goto exit_now; + } + if (resume_thread(threadID) != B_OK) { + fprintf(stderr, "failed starting thread: error code %08lx\n", threadID); + failed_already = 1; + goto exit_now; + } + + waitRV = wait_for_thread(threadID, &threadRV); + if (debug_mode) + PR_ASSERT(waitRV == B_OK); + else if (waitRV != B_OK) { + failed_already = 1; + goto exit_now; + } + +#else + if (!debug_mode) + failed_already=1; + else + printf("The attach test does not apply to this platform because\n" + "either this platform does not have native threads or the\n" + "test needs to be written for this platform.\n"); + goto exit_now; +#endif + +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile.c new file mode 100644 index 00000000..19c0a7f9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile.c @@ -0,0 +1,318 @@ +/* -*- 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 "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prinit.h" +#include "prerror.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" + +#define DEFAULT_COUNT 10 +#define DEFAULT_FILESIZE 1 +#define BUFFER_SIZE 1000000 + +typedef enum {v_silent, v_whisper, v_shout} Verbosity; +static void Verbose(Verbosity, const char*, const char*, PRIntn); + +#define VERBOSE(_l, _m) Verbose(_l, _m, __FILE__, __LINE__) + +static PRIntn test_result = 2; +static PRFileDesc *output = NULL; +static PRIntn verbose = v_silent; +static PRIntn filesize = DEFAULT_FILESIZE; + +static PRIntn Usage(void) +{ + PR_fprintf(output, "Bigfile test usage:\n"); + PR_fprintf(output, ">bigfile [-G] [-d] [-v[*v]] [-s ] \n"); + PR_fprintf(output, "\td\tdebug mode (equivalent to -vvv)\t(false)\n"); + PR_fprintf(output, "\tv\tAdditional levels of output\t(none)\n"); + PR_fprintf(output, "\tk\tKeep data file after exit\t(false)\n"); + PR_fprintf(output, "\ts \tFile size in megabytes\t\t(1 megabyte)\n"); + PR_fprintf(output, "\t\tName of test file\t(none)\n"); + return 2; /* nothing happened */ +} /* Usage */ + +static PRStatus DeleteIfFound(const char *filename) +{ + PRStatus rv; + VERBOSE(v_shout, "Checking for existing file"); + rv = PR_Access(filename, PR_ACCESS_WRITE_OK); + if (PR_SUCCESS == rv) + { + VERBOSE(v_shout, "Deleting existing file"); + rv = PR_Delete(filename); + if (PR_FAILURE == rv) VERBOSE(v_shout, "Cannot delete big file"); + } + else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError()) + VERBOSE(v_shout, "Cannot access big file"); + else rv = PR_SUCCESS; + return rv; +} /* DeleteIfFound */ + +static PRIntn Error(const char *msg, const char *filename) +{ + PRInt32 error = PR_GetError(); + if (NULL != msg) + { + if (0 == error) PR_fprintf(output, msg); + else PL_FPrintError(output, msg); + } + (void)DeleteIfFound(filename); + if (v_shout == verbose) PR_Abort(); + return 1; +} /* Error */ + +static void Verbose( + Verbosity level, const char *msg, const char *file, PRIntn line) +{ + if (level <= verbose) + PR_fprintf(output, "[%s : %d]: %s\n", file, line, msg); +} /* Verbose */ + +static void PrintInfo(PRFileInfo64 *info, const char *filename) +{ + PRExplodedTime tm; + char ctime[40], mtime[40]; + static const char *types[] = {"FILE", "DIRECTORY", "OTHER"}; + PR_fprintf( + output, "[%s : %d]: File info for %s\n", + __FILE__, __LINE__, filename); + PR_fprintf( + output, " type: %s, size: %llu bytes,\n", + types[info->type - 1], info->size); + + PR_ExplodeTime(info->creationTime, PR_GMTParameters, &tm); + (void)PR_FormatTime(ctime, sizeof(ctime), "%c GMT", &tm); + PR_ExplodeTime(info->modifyTime, PR_GMTParameters, &tm); + (void)PR_FormatTime(mtime, sizeof(mtime), "%c GMT", &tm); + + PR_fprintf( + output, " creation: %s,\n modify: %s\n", ctime, mtime); +} /* PrintInfo */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + char *buffer; + PLOptStatus os; + PRInt32 loop, bytes; + PRFileInfo small_info; + PRFileInfo64 big_info; + PRBool keep = PR_FALSE; + PRFileDesc *file = NULL; + const char *filename = NULL; + PRIntn count = DEFAULT_COUNT; + PRInt64 filesize64, big_answer, big_size, one_meg, zero_meg, big_fragment; + PRInt64 sevenFox = LL_INIT(0,0x7fffffff); + + PLOptState *opt = PL_CreateOptState(argc, argv, "dtvhs:"); + + output = PR_GetSpecialFD(PR_StandardError); + PR_STDIO_INIT(); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + filename = opt->value; + break; + case 'd': /* debug mode */ + verbose = v_shout; + break; + case 'k': /* keep file */ + keep = PR_TRUE; + break; + case 'v': /* verbosity */ + if (v_shout > verbose) verbose += 1; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 's': /* filesize */ + filesize = atoi(opt->value); + break; + case 'h': /* confused */ + default: + return Usage(); + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + if (0 == filesize) filesize = DEFAULT_FILESIZE; + if (NULL == filename) + { + if (DEFAULT_FILESIZE != filesize) return Usage(); + else filename = "bigfile.dat"; + } + + if (PR_FAILURE == DeleteIfFound(filename)) return 1; + + test_result = 0; + + LL_I2L(zero_meg, 0); + LL_I2L(one_meg, 1000000); + LL_I2L(filesize64, filesize); + buffer = (char*)PR_MALLOC(BUFFER_SIZE); + LL_I2L(big_fragment, BUFFER_SIZE); + LL_MUL(filesize64, filesize64, one_meg); + + for (loop = 0; loop < BUFFER_SIZE; ++loop) buffer[loop] = (char)loop; + + VERBOSE(v_whisper, "Creating big file"); + file = PR_Open(filename, PR_CREATE_FILE | PR_WRONLY, 0666); + if (NULL == file) return Error("PR_Open()", filename); + + VERBOSE(v_whisper, "Testing available space in empty file"); + big_answer = file->methods->available64(file); + if (!LL_IS_ZERO(big_answer)) return Error("empty available64()", filename); + + LL_SUB(big_size, filesize64, one_meg); + VERBOSE(v_whisper, "Creating sparse big file by seeking to end"); + big_answer = file->methods->seek64(file, big_size, PR_SEEK_SET); + if (!LL_EQ(big_answer, big_size)) return Error("seek", filename); + + VERBOSE(v_whisper, "Writing block at end of sparse file"); + bytes = file->methods->write(file, buffer, BUFFER_SIZE); + if (bytes != BUFFER_SIZE) return Error("write", filename); + + VERBOSE(v_whisper, "Testing available space at end of sparse file"); + big_answer = file->methods->available64(file); + if (!LL_IS_ZERO(big_answer)) return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Getting big info on sparse big file"); + rv = file->methods->fileInfo64(file, &big_info); + if (PR_FAILURE == rv) return Error("fileInfo64()", filename); + if (v_shout <= verbose) PrintInfo(&big_info, filename); + + VERBOSE(v_whisper, "Getting small info on sparse big file"); + rv = file->methods->fileInfo(file, &small_info); + if (LL_CMP(sevenFox, <, filesize64) && (PR_SUCCESS == rv)) + { + VERBOSE(v_whisper, "Should have failed and didn't"); + return Error("fileInfo()", filename); + } + else if (LL_CMP(sevenFox, >, filesize64) && (PR_FAILURE == rv)) + { + VERBOSE(v_whisper, "Should have succeeded and didn't"); + return Error("fileInfo()", filename); + } + + VERBOSE(v_whisper, "Rewinding big file"); + big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); + if (!LL_IS_ZERO(big_answer)) return Error("rewind seek64()", filename); + + VERBOSE(v_whisper, "Establishing available space in rewound file"); + big_answer = file->methods->available64(file); + if (LL_NE(filesize64, big_answer)) + return Error("bof available64()", filename); + + VERBOSE(v_whisper, "Closing big file"); + rv = file->methods->close(file); + if (PR_FAILURE == rv) return Error("close()", filename); + + VERBOSE(v_whisper, "Reopening big file"); + file = PR_Open(filename, PR_RDWR, 0666); + if (NULL == file) return Error("open failed", filename); + + VERBOSE(v_whisper, "Checking available data in reopened file"); + big_answer = file->methods->available64(file); + if (LL_NE(filesize64, big_answer)) + return Error("reopened available64()", filename); + + big_answer = zero_meg; + VERBOSE(v_whisper, "Rewriting every byte of big file data"); + do + { + bytes = file->methods->write(file, buffer, BUFFER_SIZE); + if (bytes != BUFFER_SIZE) + return Error("write", filename); + LL_ADD(big_answer, big_answer, big_fragment); + } while (LL_CMP(big_answer, <, filesize64)); + + VERBOSE(v_whisper, "Checking position at eof"); + big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_CUR); + if (LL_NE(big_answer, filesize64)) + return Error("file size error", filename); + + VERBOSE(v_whisper, "Testing available space at eof"); + big_answer = file->methods->available64(file); + if (!LL_IS_ZERO(big_answer)) + return Error("eof available64()", filename); + + VERBOSE(v_whisper, "Rewinding full file"); + big_answer = file->methods->seek64(file, zero_meg, PR_SEEK_SET); + if (!LL_IS_ZERO(big_answer)) return Error("bof seek64()", filename); + + VERBOSE(v_whisper, "Testing available space in rewound file"); + big_answer = file->methods->available64(file); + if (LL_NE(big_answer, filesize64)) return Error("bof available64()", filename); + + VERBOSE(v_whisper, "Seeking to end of big file"); + big_answer = file->methods->seek64(file, filesize64, PR_SEEK_SET); + if (LL_NE(big_answer, filesize64)) return Error("eof seek64()", filename); + + VERBOSE(v_whisper, "Getting info on big file while it's open"); + rv = file->methods->fileInfo64(file, &big_info); + if (PR_FAILURE == rv) return Error("fileInfo64()", filename); + if (v_shout <= verbose) PrintInfo(&big_info, filename); + + VERBOSE(v_whisper, "Closing big file"); + rv = file->methods->close(file); + if (PR_FAILURE == rv) return Error("close()", filename); + + VERBOSE(v_whisper, "Getting info on big file after it's closed"); + rv = PR_GetFileInfo64(filename, &big_info); + if (PR_FAILURE == rv) return Error("fileInfo64()", filename); + if (v_shout <= verbose) PrintInfo(&big_info, filename); + + VERBOSE(v_whisper, "Deleting big file"); + rv = PR_Delete(filename); + if (PR_FAILURE == rv) return Error("PR_Delete()", filename); + + PR_DELETE(buffer); + return test_result; +} /* main */ + +/* bigfile.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile2.c new file mode 100644 index 00000000..3e8beeeb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile2.c @@ -0,0 +1,127 @@ +/* -*- 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 "nspr.h" + +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#define TEST_FILE_NAME "bigfile2.txt" + +#define MESSAGE "Hello world!" +#define MESSAGE_SIZE 13 + +int main(int argc, char **argv) +{ + PRFileDesc *fd; + PRInt64 offset, position; + PRInt32 nbytes; + char buf[MESSAGE_SIZE]; +#ifdef _WIN32 + HANDLE hFile; + LARGE_INTEGER li; +#endif /* _WIN32 */ + + LL_I2L(offset, 1); + LL_SHL(offset, offset, 32); + + fd = PR_Open(TEST_FILE_NAME, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + position = PR_Seek64(fd, offset, PR_SEEK_SET); + if (!LL_GE_ZERO(position)) { + fprintf(stderr, "PR_Seek64 failed\n"); + exit(1); + } + PR_ASSERT(LL_EQ(position, offset)); + strcpy(buf, MESSAGE); + nbytes = PR_Write(fd, buf, sizeof(buf)); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + +#ifdef _WIN32 + hFile = CreateFile(TEST_FILE_NAME, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "CreateFile failed\n"); + exit(1); + } + li.QuadPart = offset; + li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + fprintf(stderr, "SetFilePointer failed\n"); + exit(1); + } + PR_ASSERT(li.QuadPart == offset); + if (ReadFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) { + fprintf(stderr, "ReadFile failed\n"); + exit(1); + } + PR_ASSERT(nbytes == sizeof(buf)); + if (strcmp(buf, MESSAGE)) { + fprintf(stderr, "corrupt data:$%s$\n", buf); + exit(1); + } + if (CloseHandle(hFile) == 0) { + fprintf(stderr, "CloseHandle failed\n"); + exit(1); + } +#endif /* _WIN32 */ + + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile3.c b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile3.c new file mode 100644 index 00000000..6fa25ca6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/bigfile3.c @@ -0,0 +1,125 @@ +/* -*- 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 "nspr.h" + +#include +#include +#ifdef _WIN32 +#include +#endif + +#define TEST_FILE_NAME "bigfile3.txt" + +#define MESSAGE "Hello world!" +#define MESSAGE_SIZE 13 + +int main(int argc, char **argv) +{ + PRFileDesc *fd; + PRInt64 offset, position; + PRInt32 nbytes; + char buf[MESSAGE_SIZE]; +#ifdef _WIN32 + HANDLE hFile; + LARGE_INTEGER li; +#endif /* _WIN32 */ + + LL_I2L(offset, 1); + LL_SHL(offset, offset, 32); + +#ifdef _WIN32 + hFile = CreateFile(TEST_FILE_NAME, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + fprintf(stderr, "CreateFile failed\n"); + exit(1); + } + li.QuadPart = offset; + li.LowPart = SetFilePointer(hFile, li.LowPart, &li.HighPart, FILE_BEGIN); + if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + fprintf(stderr, "SetFilePointer failed\n"); + exit(1); + } + PR_ASSERT(li.QuadPart == offset); + strcpy(buf, MESSAGE); + if (WriteFile(hFile, buf, sizeof(buf), &nbytes, NULL) == 0) { + fprintf(stderr, "WriteFile failed\n"); + exit(1); + } + PR_ASSERT(nbytes == sizeof(buf)); + if (CloseHandle(hFile) == 0) { + fprintf(stderr, "CloseHandle failed\n"); + exit(1); + } +#endif /* _WIN32 */ + + memset(buf, 0, sizeof(buf)); + + fd = PR_Open(TEST_FILE_NAME, PR_RDONLY, 0666); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + position = PR_Seek64(fd, offset, PR_SEEK_SET); + if (!LL_GE_ZERO(position)) { + fprintf(stderr, "PR_Seek64 failed\n"); + exit(1); + } + PR_ASSERT(LL_EQ(position, offset)); + nbytes = PR_Read(fd, buf, sizeof(buf)); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + if (strcmp(buf, MESSAGE)) { + fprintf(stderr, "corrupt data:$%s$\n", buf); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/bug1test.c b/src/libs/xpcom18a4/nsprpub/pr/tests/bug1test.c new file mode 100644 index 00000000..fa7d591f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/bug1test.c @@ -0,0 +1,257 @@ +/* -*- 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 ***** */ + +/* +Attached is a test program that uses the nspr1 to demonstrate a bug +under NT4.0. The fix has already been mentioned (add a ResetEvent just +before leaving the critical section in _PR_CondWait in hwmon.c). +*/ + +#include "prthread.h" +#include "prtypes.h" +#include "prinit.h" +#include "prmon.h" +#include "prlog.h" + +typedef struct Arg_s +{ + PRInt32 a, b; +} Arg_t; + +PRMonitor* gMonitor; // the monitor +PRInt32 gReading; // number of read locks +PRInt32 gWriteWaiting; // number of threads waiting for write lock +PRInt32 gReadWaiting; // number of threads waiting for read lock + +PRInt32 gCounter; // a counter + + // stats +PRInt32 gReads; // number of successful reads +PRInt32 gMaxReads; // max number of simultaneous reads +PRInt32 gMaxWriteWaits; // max number of writes that waited for read +PRInt32 gMaxReadWaits; // max number of reads that waited for write wait + + +void spin (PRInt32 aDelay) +{ + PRInt32 index; + PRInt32 delay = aDelay * 1000; + + PR_Sleep(0); + + // randomize delay a bit + delay = (delay / 2) + (PRInt32)((float)delay * + ((float)rand () / (float)RAND_MAX)); + + for (index = 0; index < delay * 10; index++) + // consume a bunch of cpu cycles + ; + PR_Sleep(0); +} + +void doWriteThread (void* arg) +{ + PRInt32 last; + Arg_t *args = (Arg_t*)arg; + PRInt32 aWorkDelay = args->a, aWaitDelay = args->b; + PR_Sleep(0); + + while (1) + { + // -- enter write lock + PR_EnterMonitor (gMonitor); + + if (0 < gReading) // wait for read locks to go away + { + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + + gWriteWaiting++; + if (gWriteWaiting > gMaxWriteWaits) // stats + gMaxWriteWaits = gWriteWaiting; + while (0 < gReading) + PR_Wait (gMonitor, fiveSecs); + gWriteWaiting--; + } + // -- write lock entered + + last = gCounter; + gCounter++; + + spin (aWorkDelay); + + PR_ASSERT (gCounter == (last + 1)); // test invariance + + // -- exit write lock +// if (0 < gReadWaiting) // notify waiting reads (do it anyway to show off the CondWait bug) + PR_NotifyAll (gMonitor); + + PR_ExitMonitor (gMonitor); + // -- write lock exited + + spin (aWaitDelay); + } +} + +void doReadThread (void* arg) +{ + PRInt32 last; + Arg_t *args = (Arg_t*)arg; + PRInt32 aWorkDelay = args->a, aWaitDelay = args->b; + PR_Sleep(0); + + while (1) + { + // -- enter read lock + PR_EnterMonitor (gMonitor); + + if (0 < gWriteWaiting) // give up the monitor to waiting writes + { + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + + gReadWaiting++; + if (gReadWaiting > gMaxReadWaits) // stats + gMaxReadWaits = gReadWaiting; + while (0 < gWriteWaiting) + PR_Wait (gMonitor, fiveSecs); + gReadWaiting--; + } + + gReading++; + + gReads++; // stats + if (gReading > gMaxReads) // stats + gMaxReads = gReading; + + PR_ExitMonitor (gMonitor); + // -- read lock entered + + last = gCounter; + + spin (aWorkDelay); + + PR_ASSERT (gCounter == last); // test invariance + + // -- exit read lock + PR_EnterMonitor (gMonitor); // read unlock + gReading--; + +// if ((0 == gReading) && (0 < gWriteWaiting)) // notify waiting writes (do it anyway to show off the CondWait bug) + PR_NotifyAll (gMonitor); + PR_ExitMonitor (gMonitor); + // -- read lock exited + + spin (aWaitDelay); + } +} + + +void fireThread ( + char* aName, void (*aProc)(void *arg), Arg_t *aArg) +{ + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, aProc, aArg, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); +} + +int pseudoMain (int argc, char** argv, char *pad) +{ + PRInt32 lastWriteCount = gCounter; + PRInt32 lastReadCount = gReads; + Arg_t a1 = {500, 250}; + Arg_t a2 = {500, 500}; + Arg_t a3 = {250, 500}; + Arg_t a4 = {750, 250}; + Arg_t a5 = {100, 750}; + Arg_t a6 = {100, 500}; + Arg_t a7 = {100, 750}; + + gMonitor = PR_NewMonitor (); + + fireThread ("R1", doReadThread, &a1); + fireThread ("R2", doReadThread, &a2); + fireThread ("R3", doReadThread, &a3); + fireThread ("R4", doReadThread, &a4); + + fireThread ("W1", doWriteThread, &a5); + fireThread ("W2", doWriteThread, &a6); + fireThread ("W3", doWriteThread, &a7); + + fireThread ("R5", doReadThread, &a1); + fireThread ("R6", doReadThread, &a2); + fireThread ("R7", doReadThread, &a3); + fireThread ("R8", doReadThread, &a4); + + fireThread ("W4", doWriteThread, &a5); + fireThread ("W5", doWriteThread, &a6); + fireThread ("W6", doWriteThread, &a7); + + while (1) + { + PRInt32 writeCount, readCount; + PRIntervalTime fiveSecs = PR_SecondsToInterval(5); + PR_Sleep (fiveSecs); // get out of the way + + // print some stats, not threadsafe, informative only + writeCount = gCounter; + readCount = gReads; + printf ("\ntick %d writes (+%d), %d reads (+%d) [max %d, %d, %d]", + writeCount, writeCount - lastWriteCount, + readCount, readCount - lastReadCount, + gMaxReads, gMaxWriteWaits, gMaxReadWaits); + lastWriteCount = writeCount; + lastReadCount = readCount; + gMaxReads = gMaxWriteWaits = gMaxReadWaits = 0; + } + return 0; +} + + +static void padStack (int argc, char** argv) +{ + char pad[512]; /* Work around bug in nspr on windoze */ + pseudoMain (argc, argv, pad); +} + +void main (int argc, char **argv) +{ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + padStack (argc, argv); +} + + +/* bug1test.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/cleanup.c b/src/libs/xpcom18a4/nsprpub/pr/tests/cleanup.c new file mode 100644 index 00000000..e94979e9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/cleanup.c @@ -0,0 +1,131 @@ +/* -*- 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 "prprf.h" +#include "prio.h" +#include "prinit.h" +#include "prthread.h" +#include "prinrval.h" + +#include "plgetopt.h" + +#include + +static void PR_CALLBACK Thread(void *sleep) +{ + PR_Sleep(PR_SecondsToInterval((PRUint32)sleep)); + printf("Thread exiting\n"); +} + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "Cleanup usage: [-g] [-s n] [-t n] [-c n] [-h]\n"); + PR_fprintf(err, "\t-c Call cleanup before exiting (default: false)\n"); + PR_fprintf(err, "\t-G Use global threads only (default: local)\n"); + PR_fprintf(err, "\t-t n Number of threads involved (default: 1)\n"); + PR_fprintf(err, "\t-s n Seconds thread(s) should dally (defaut: 10)\n"); + PR_fprintf(err, "\t-S n Seconds main() should dally (defaut: 5)\n"); + PR_fprintf(err, "\t-C n Value to set concurrency (default 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRBool cleanup = PR_FALSE; + PRThreadScope type = PR_LOCAL_THREAD; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "Ghs:S:t:cC:"); + PRIntn concurrency = 1, child_sleep = 10, main_sleep = 5, threads = 1; + + PR_STDIO_INIT(); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'c': /* call PR_Cleanup() before exiting */ + cleanup = PR_TRUE; + break; + case 'G': /* local vs global threads */ + type = PR_GLOBAL_THREAD; + break; + case 's': /* time to sleep */ + child_sleep = atoi(opt->value); + break; + case 'S': /* time to sleep */ + main_sleep = atoi(opt->value); + break; + case 'C': /* number of cpus to create */ + concurrency = atoi(opt->value); + break; + case 't': /* number of threads to create */ + threads = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Cleanup settings\n"); + PR_fprintf(err, "\tThread type: %s\n", + (PR_LOCAL_THREAD == type) ? "LOCAL" : "GLOBAL"); + PR_fprintf(err, "\tConcurrency: %d\n", concurrency); + PR_fprintf(err, "\tNumber of threads: %d\n", threads); + PR_fprintf(err, "\tThread sleep: %d\n", child_sleep); + PR_fprintf(err, "\tMain sleep: %d\n", main_sleep); + PR_fprintf(err, "\tCleanup will %sbe called\n\n", (cleanup) ? "" : "NOT "); + + PR_SetConcurrency(concurrency); + + while (threads-- > 0) + (void)PR_CreateThread( + PR_USER_THREAD, Thread, (void*)child_sleep, PR_PRIORITY_NORMAL, + type, PR_UNJOINABLE_THREAD, 0); + PR_Sleep(PR_SecondsToInterval(main_sleep)); + + if (cleanup) PR_Cleanup(); + + PR_fprintf(err, "main() exiting\n"); + return 0; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/cltsrv.c b/src/libs/xpcom18a4/nsprpub/pr/tests/cltsrv.c new file mode 100644 index 00000000..96027843 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/cltsrv.c @@ -0,0 +1,1226 @@ +/* -*- 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 ***** */ + +/* + * + * Notes: + * [1] lth. The call to Sleep() is a hack to get the test case to run + * on Windows 95. Without it, the test case fails with an error + * WSAECONNRESET following a recv() call. The error is caused by the + * server side thread termination without a shutdown() or closesocket() + * call. Windows docmunentation suggests that this is predicted + * behavior; that other platforms get away with it is ... serindipity. + * The test case should shutdown() or closesocket() before + * thread termination. I didn't have time to figure out where or how + * to do it. The Sleep() call inserts enough delay to allow the + * client side to recv() all his data before the server side thread + * terminates. Whew! ... + * + ** Modification History: + * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. + * The debug mode will print all of the printfs associated with this test. + * The regress mode will be the default mode. Since the regress tool limits + * the output to a one line status:PASS or FAIL,all of the printf statements + * have been handled with an if (debug_mode) statement. + */ + +#include "prclist.h" +#include "prcvar.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prtime.h" +#include "prmem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prthread.h" + +#include "pprio.h" +#include "primpl.h" + +#include "plstr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include +#include + + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +/* +** This is the beginning of the test +*/ + +#define RECV_FLAGS 0 +#define SEND_FLAGS 0 +#define DEFAULT_LOW 0 +#define DEFAULT_HIGH 0 +#define BUFFER_SIZE 1024 +#define DEFAULT_BACKLOG 5 +#define DEFAULT_PORT 12849 +#define DEFAULT_CLIENTS 1 +#define ALLOWED_IN_ACCEPT 1 +#define DEFAULT_CLIPPING 1000 +#define DEFAULT_WORKERS_MIN 1 +#define DEFAULT_WORKERS_MAX 1 +#define DEFAULT_SERVER "localhost" +#define DEFAULT_EXECUTION_TIME 10 +#define DEFAULT_CLIENT_TIMEOUT 4000 +#define DEFAULT_SERVER_TIMEOUT 4000 +#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH + +typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t; + +static void PR_CALLBACK Worker(void *arg); +typedef struct CSPool_s CSPool_t; +typedef struct CSWorker_s CSWorker_t; +typedef struct CSServer_s CSServer_t; +typedef enum Verbosity +{ + TEST_LOG_ALWAYS, + TEST_LOG_ERROR, + TEST_LOG_WARNING, + TEST_LOG_NOTICE, + TEST_LOG_INFO, + TEST_LOG_STATUS, + TEST_LOG_VERBOSE +} Verbosity; + +static PRInt32 domain = AF_INET; +static PRInt32 protocol = 6; /* TCP */ +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE; +static PRBool pthread_stats = PR_FALSE; +static Verbosity verbosity = TEST_LOG_ALWAYS; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +struct CSWorker_s +{ + PRCList element; /* list of the server's workers */ + + PRThread *thread; /* this worker objects thread */ + CSServer_t *server; /* back pointer to server structure */ +}; + +struct CSPool_s +{ + PRCondVar *exiting; + PRCondVar *acceptComplete; + PRUint32 accepting, active, workers; +}; + +struct CSServer_s +{ + PRCList list; /* head of worker list */ + + PRLock *ml; + PRThread *thread; /* the main server thread */ + PRCondVar *stateChange; + + PRUint16 port; /* port we're listening on */ + PRUint32 backlog; /* size of our listener backlog */ + PRFileDesc *listener; /* the fd accepting connections */ + + CSPool_t pool; /* statistics on worker threads */ + CSState_t state; /* the server's state */ + struct /* controlling worker counts */ + { + PRUint32 minimum, maximum, accepting; + } workers; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +}; + +typedef struct CSDescriptor_s +{ + PRInt32 size; /* size of transfer */ + char filename[60]; /* filename, null padded */ +} CSDescriptor_t; + +typedef struct CSClient_s +{ + PRLock *ml; + PRThread *thread; + PRCondVar *stateChange; + PRNetAddr serverAddress; + + CSState_t state; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +} CSClient_t; + +#define TEST_LOG(l, p, a) \ + do { \ + if (debug_mode || (p <= verbosity)) printf a; \ + } while (0) + +PRLogModuleInfo *cltsrv_log_file = NULL; + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +#define TEST_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +static void _MY_Assert(const char *s, const char *file, PRIntn ln) +{ + PL_PrintError(NULL); +#if DEBUG + PR_Assert(s, file, ln); +#endif +} /* _MW_Assert */ + +static PRBool Aborted(PRStatus rv) +{ + return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ? + PR_TRUE : PR_FALSE; +} + +static void TimeOfDayMessage(const char *msg, PRThread* me) +{ + char buffer[100]; + PRExplodedTime tod; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("%s(0x%p): %s\n", msg, me, buffer)); +} /* TimeOfDayMessage */ + + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRIntn index; + char buffer[1024]; + PRFileDesc *fd = NULL; + PRUintn clipping = DEFAULT_CLIPPING; + PRThread *me = PR_CurrentThread(); + CSClient_t *client = (CSClient_t*)arg; + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT); + + + for (index = 0; index < sizeof(buffer); ++index) + buffer[index] = (char)index; + + client->started = PR_IntervalNow(); + + PR_Lock(client->ml); + client->state = cs_run; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + + TimeOfDayMessage("Client started at", me); + + while (cs_run == client->state) + { + PRInt32 bytes, descbytes, filebytes, netbytes; + + (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); + TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); + + fd = PR_Socket(domain, SOCK_STREAM, protocol); + TEST_ASSERT(NULL != fd); + rv = PR_Connect(fd, &client->serverAddress, timeout); + if (PR_FAILURE == rv) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): conection failed (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + + memset(descriptor, 0, sizeof(*descriptor)); + descriptor->size = PR_htonl(descbytes = rand() % clipping); + PR_snprintf( + descriptor->filename, sizeof(descriptor->filename), + "CS%p%p-%p.dat", client->started, me, client->operations); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); + bytes = PR_Send( + fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); + if (sizeof(CSDescriptor_t) != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send descriptor timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(sizeof(*descriptor) == bytes); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send data timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(bytes == filebytes); + netbytes += bytes; + } + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + if (Aborted(PR_FAILURE)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data aborted\n", me)); + goto aborted; + } + else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto retry; + } + if (0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tClient(0x%p): unexpected end of stream\n", + PR_CurrentThread())); + break; + } + filebytes += bytes; + } + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); +retry: + (void)PR_Close(fd); fd = NULL; + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): disconnected from server\n", me)); + + PR_Lock(client->ml); + client->operations += 1; + client->bytesTransferred += 2 * descbytes; + rv = PR_WaitCondVar(client->stateChange, rand() % clipping); + PR_Unlock(client->ml); + if (Aborted(rv)) break; + } + +aborted: + client->stopped = PR_IntervalNow(); + + PR_ClearInterrupt(); + if (NULL != fd) rv = PR_Close(fd); + + PR_Lock(client->ml); + client->state = cs_exit; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + PR_DELETE(descriptor); + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tClient(0x%p): stopped after %u operations and %u bytes\n", + PR_CurrentThread(), client->operations, client->bytesTransferred)); + +} /* Client */ + +static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) +{ + PRStatus drv, rv; + char buffer[1024]; + PRFileDesc *file = NULL; + PRThread * me = PR_CurrentThread(); + PRInt32 bytes, descbytes, netbytes, filebytes = 0; + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receiving desciptor\n", me)); + bytes = PR_Recv( + fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto exit; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): receive timeout\n", me)); + } + goto exit; + } + if (0 == bytes) + { + rv = PR_FAILURE; + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): unexpected end of file\n", me)); + goto exit; + } + descbytes = PR_ntohl(descriptor->size); + TEST_ASSERT(sizeof(*descriptor) == bytes); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", + me, descbytes, descriptor->filename)); + + file = PR_Open( + descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): open file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(NULL != file); + + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): receive data timeout\n", me)); + goto aborted; + } + /* + * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED) + * on NT here. This is equivalent to ECONNRESET on Unix. + * -wtc + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + if(0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me)); + rv = PR_FAILURE; + goto aborted; + } + filebytes += bytes; + netbytes = bytes; + /* The byte count for PR_Write should be positive */ + MY_ASSERT(netbytes > 0); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes)); + bytes = PR_Write(file, buffer, netbytes); + if (netbytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): write file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->operations += 1; + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Close(file); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + file = NULL; + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename)); + file = PR_Open(descriptor->filename, PR_RDONLY, 0); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): open file timeout\n", + PR_CurrentThread())); + goto aborted; + } + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(NULL != file); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes)); + bytes = PR_Read(file, buffer, filebytes); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): read file timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(bytes > 0); + netbytes += bytes; + filebytes = bytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): send data timeout\n", me)); + goto aborted; + } + break; + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + + rv = PR_Close(file); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + file = NULL; + +aborted: + PR_ClearInterrupt(); + if (NULL != file) PR_Close(file); + drv = PR_Delete(descriptor->filename); + TEST_ASSERT(PR_SUCCESS == drv); +exit: + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): Finished\n", me)); + + PR_DELETE(descriptor); + +#if defined(WIN95) + PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */ +#endif + return rv; +} /* ProcessRequest */ + +static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) +{ + CSWorker_t *worker = PR_NEWZAP(CSWorker_t); + worker->server = server; + PR_INIT_CLIST(&worker->element); + worker->thread = PR_CreateThread( + PR_USER_THREAD, Worker, worker, + DEFAULT_SERVER_PRIORITY, thread_scope, + PR_UNJOINABLE_THREAD, 0); + if (NULL == worker->thread) + { + PR_DELETE(worker); + return PR_FAILURE; + } + + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", + PR_CurrentThread(), worker->thread)); + + return PR_SUCCESS; +} /* CreateWorker */ + +static void PR_CALLBACK Worker(void *arg) +{ + PRStatus rv; + PRNetAddr from; + PRFileDesc *fd = NULL; + PRThread *me = PR_CurrentThread(); + CSWorker_t *worker = (CSWorker_t*)arg; + CSServer_t *server = worker->server; + CSPool_t *pool = &server->pool; + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1)); + + PR_Lock(server->ml); + PR_APPEND_LINK(&worker->element, &server->list); + pool->workers += 1; /* define our existance */ + + while (cs_run == server->state) + { + while (pool->accepting >= server->workers.accepting) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): waiting for accept slot[%d]\n", + me, pool->accepting)); + rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT); + if (Aborted(rv) || (cs_run != server->state)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tWorker(0x%p): has been %s\n", + me, (Aborted(rv) ? "interrupted" : "stopped"))); + goto exit; + } + } + pool->accepting += 1; /* how many are really in accept */ + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): calling accept\n", me)); + fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT); + + PR_Lock(server->ml); + pool->accepting -= 1; + PR_NotifyCondVar(pool->acceptComplete); + + if ((NULL == fd) && Aborted(PR_FAILURE)) + { + if (NULL != server->listener) + { + PR_Close(server->listener); + server->listener = NULL; + } + goto exit; + } + + if (NULL != fd) + { + /* + ** Create another worker of the total number of workers is + ** less than the minimum specified or we have none left in + ** accept() AND we're not over the maximum. + ** This sort of presumes that the number allowed in accept + ** is at least as many as the minimum. Otherwise we'll keep + ** creating new threads and deleting them soon after. + */ + PRBool another = + ((pool->workers < server->workers.minimum) || + ((0 == pool->accepting) + && (pool->workers < server->workers.maximum))) ? + PR_TRUE : PR_FALSE; + pool->active += 1; + PR_Unlock(server->ml); + + if (another) (void)CreateWorker(server, pool); + + rv = ProcessRequest(fd, server); + if (PR_SUCCESS != rv) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tWorker(0x%p): server process ended abnormally\n", me)); + (void)PR_Close(fd); fd = NULL; + + PR_Lock(server->ml); + pool->active -= 1; + } + } + +exit: + PR_ClearInterrupt(); + PR_Unlock(server->ml); + + if (NULL != fd) + { + (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + (void)PR_Close(fd); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers)); + + PR_Lock(server->ml); + pool->workers -= 1; /* undefine our existance */ + PR_REMOVE_AND_INIT_LINK(&worker->element); + PR_NotifyCondVar(pool->exiting); + PR_Unlock(server->ml); + + PR_DELETE(worker); /* destruction of the "worker" object */ + +} /* Worker */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRNetAddr serverAddress; + PRThread *me = PR_CurrentThread(); + CSServer_t *server = (CSServer_t*)arg; + PRSocketOptionData sockOpt; + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(server->listener, &sockOpt); + TEST_ASSERT(PR_SUCCESS == rv); + + memset(&serverAddress, 0, sizeof(serverAddress)); + if (PR_AF_INET6 != domain) + rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); + else + rv = PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, DEFAULT_PORT, + &serverAddress); + rv = PR_Bind(server->listener, &serverAddress); + TEST_ASSERT(PR_SUCCESS == rv); + + rv = PR_Listen(server->listener, server->backlog); + TEST_ASSERT(PR_SUCCESS == rv); + + server->started = PR_IntervalNow(); + TimeOfDayMessage("Server started at", me); + + PR_Lock(server->ml); + server->state = cs_run; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + /* + ** Create the first worker (actually, a thread that accepts + ** connections and then processes the work load as needed). + ** From this point on, additional worker threads are created + ** as they are needed by existing worker threads. + */ + rv = CreateWorker(server, &server->pool); + TEST_ASSERT(PR_SUCCESS == rv); + + /* + ** From here on this thread is merely hanging around as the contact + ** point for the main test driver. It's just waiting for the driver + ** to declare the test complete. + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): waiting for state change\n", me)); + + PR_Lock(server->ml); + while ((cs_run == server->state) && !Aborted(rv)) + { + rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(server->ml); + PR_ClearInterrupt(); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tServer(0x%p): shutting down workers\n", me)); + + /* + ** Get all the worker threads to exit. They know how to + ** clean up after themselves, so this is just a matter of + ** waiting for clorine in the pool to take effect. During + ** this stage we're ignoring interrupts. + */ + server->workers.minimum = server->workers.maximum = 0; + + PR_Lock(server->ml); + while (!PR_CLIST_IS_EMPTY(&server->list)) + { + PRCList *head = PR_LIST_HEAD(&server->list); + CSWorker_t *worker = (CSWorker_t*)head; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); + rv = PR_Interrupt(worker->thread); + TEST_ASSERT(PR_SUCCESS == rv); + PR_REMOVE_AND_INIT_LINK(head); + } + + while (server->pool.workers > 0) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tServer(0x%p): waiting for %u workers to exit\n", + me, server->pool.workers)); + (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); + } + + server->state = cs_exit; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tServer(0x%p): stopped after %u operations and %u bytes\n", + me, server->operations, server->bytesTransferred)); + + if (NULL != server->listener) PR_Close(server->listener); + server->stopped = PR_IntervalNow(); + +} /* Server */ + +static void WaitForCompletion(PRIntn execution) +{ + while (execution > 0) + { + PRIntn dally = (execution > 30) ? 30 : execution; + PR_Sleep(PR_SecondsToInterval(dally)); + if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + execution -= dally; + } +} /* WaitForCompletion */ + +static void Help(void) +{ + PR_fprintf(debug_out, "cltsrv test program usage:\n"); + PR_fprintf(debug_out, "\t-a threads allowed in accept (5)\n"); + PR_fprintf(debug_out, "\t-b backlock for listen (5)\n"); + PR_fprintf(debug_out, "\t-c number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-f low water mark for fd caching (0)\n"); + PR_fprintf(debug_out, "\t-F high water mark for fd caching (0)\n"); + PR_fprintf(debug_out, "\t-w minimal number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-W maximum number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-e duration of the test in seconds (10)\n"); + PR_fprintf(debug_out, "\t-s dsn name of server (localhost)\n"); + PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n"); + PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n"); + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); + PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n"); + PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n"); + PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n"); + PR_fprintf(debug_out, "\t-h this message\n"); +} /* Help */ + +static Verbosity IncrementVerbosity(void) +{ + PRIntn verboge = (PRIntn)verbosity + 1; + return (Verbosity)verboge; +} /* IncrementVerbosity */ + +PRIntn main(PRIntn argc, char** argv) +{ + PRUintn index; + PRBool boolean; + CSClient_t *client; + PRStatus rv, joinStatus; + CSServer_t *server = NULL; + + PRUintn backlog = DEFAULT_BACKLOG; + PRUintn clients = DEFAULT_CLIENTS; + const char *serverName = DEFAULT_SERVER; + PRBool serverIsLocal = PR_TRUE; + PRUintn accepting = ALLOWED_IN_ACCEPT; + PRUintn workersMin = DEFAULT_WORKERS_MIN; + PRUintn workersMax = DEFAULT_WORKERS_MAX; + PRIntn execution = DEFAULT_EXECUTION_TIME; + PRIntn low = DEFAULT_LOW, high = DEFAULT_HIGH; + + /* + * -G use global threads + * -a threads allowed in accept + * -b backlock for listen + * -c number of clients to create + * -f low water mark for caching FDs + * -F high water mark for caching FDs + * -w minimal number of server threads + * -W maximum number of server threads + * -e duration of the test in seconds + * -s dsn name of server (implies no server here) + * -v verbosity + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:f:F:w:W:e:s:vdhp"); + + debug_out = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'X': /* use XTP as transport */ + protocol = 36; + break; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + case 'a': /* the value for accepting */ + accepting = atoi(opt->value); + break; + case 'b': /* the value for backlock */ + backlog = atoi(opt->value); + break; + case 'c': /* number of client threads */ + clients = atoi(opt->value); + break; + case 'f': /* low water fd cache */ + low = atoi(opt->value); + break; + case 'F': /* low water fd cache */ + high = atoi(opt->value); + break; + case 'w': /* minimum server worker threads */ + workersMin = atoi(opt->value); + break; + case 'W': /* maximum server worker threads */ + workersMax = atoi(opt->value); + break; + case 'e': /* program execution time in seconds */ + execution = atoi(opt->value); + break; + case 's': /* server's address */ + serverName = opt->value; + break; + case 'v': /* verbosity */ + verbosity = IncrementVerbosity(); + break; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'p': /* pthread mode */ + pthread_stats = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE; + if (0 == execution) execution = DEFAULT_EXECUTION_TIME; + if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX; + if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN; + if (0 == accepting) accepting = ALLOWED_IN_ACCEPT; + if (0 == backlog) backlog = DEFAULT_BACKLOG; + + if (workersMin > accepting) accepting = workersMin; + + PR_STDIO_INIT(); + TimeOfDayMessage("Client/Server started at", PR_CurrentThread()); + + cltsrv_log_file = PR_NewLogModule("cltsrv_log"); + MY_ASSERT(NULL != cltsrv_log_file); + boolean = PR_SetLogFile("cltsrv.log"); + MY_ASSERT(boolean); + +#ifdef XP_MAC + debug_mode = PR_TRUE; +#endif + + rv = PR_SetFDCacheSize(low, high); + PR_ASSERT(PR_SUCCESS == rv); + + if (serverIsLocal) + { + /* Establish the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): starting server\n", PR_CurrentThread())); + + server = PR_NEWZAP(CSServer_t); + PR_INIT_CLIST(&server->list); + server->state = cs_init; + server->ml = PR_NewLock(); + server->backlog = backlog; + server->port = DEFAULT_PORT; + server->workers.minimum = workersMin; + server->workers.maximum = workersMax; + server->workers.accepting = accepting; + server->stateChange = PR_NewCondVar(server->ml); + server->pool.exiting = PR_NewCondVar(server->ml); + server->pool.acceptComplete = PR_NewCondVar(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): creating server thread\n", PR_CurrentThread())); + + server->thread = PR_CreateThread( + PR_USER_THREAD, Server, server, PR_PRIORITY_HIGH, + thread_scope, PR_JOINABLE_THREAD, 0); + TEST_ASSERT(NULL != server->thread); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): waiting for server init\n", PR_CurrentThread())); + + PR_Lock(server->ml); + while (server->state == cs_init) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): server init complete (port #%d)\n", + PR_CurrentThread(), server->port)); + } + + if (clients != 0) + { + /* Create all of the clients */ + PRHostEnt host; + char buffer[BUFFER_SIZE]; + client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t)); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): creating %d client threads\n", + PR_CurrentThread(), clients)); + + if (!serverIsLocal) + { + rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host); + if (PR_SUCCESS != rv) + { + PL_FPrintError(PR_STDERR, "PR_GetHostByName"); + return 2; + } + } + + for (index = 0; index < clients; ++index) + { + client[index].state = cs_init; + client[index].ml = PR_NewLock(); + if (serverIsLocal) + { + if (PR_AF_INET6 != domain) + (void)PR_InitializeNetAddr( + PR_IpAddrLoopback, DEFAULT_PORT, + &client[index].serverAddress); + else + rv = PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, + DEFAULT_PORT, &client[index].serverAddress); + } + else + { + (void)PR_EnumerateHostEnt( + 0, &host, DEFAULT_PORT, &client[index].serverAddress); + } + client[index].stateChange = PR_NewCondVar(client[index].ml); + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): creating client threads\n", PR_CurrentThread())); + client[index].thread = PR_CreateThread( + PR_USER_THREAD, Client, &client[index], PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + TEST_ASSERT(NULL != client[index].thread); + PR_Lock(client[index].ml); + while (cs_init == client[index].state) + PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(client[index].ml); + } + } + + /* Then just let them go at it for a bit */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): waiting for execution interval (%d seconds)\n", + PR_CurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_CurrentThread()); + + if (clients != 0) + { + for (index = 0; index < clients; ++index) + { + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("main(0x%p): notifying client(0x%p) to stop\n", + PR_CurrentThread(), client[index].thread)); + + PR_Lock(client[index].ml); + if (cs_run == client[index].state) + { + client[index].state = cs_stop; + PR_Interrupt(client[index].thread); + while (cs_stop == client[index].state) + PR_WaitCondVar( + client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(client[index].ml); + + TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): joining client(0x%p)\n", + PR_CurrentThread(), client[index].thread)); + + joinStatus = PR_JoinThread(client[index].thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + PR_DestroyCondVar(client[index].stateChange); + PR_DestroyLock(client[index].ml); + } + PR_DELETE(client); + } + + if (NULL != server) + { + /* All clients joined - retrieve the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): notifying server(0x%p) to stop\n", + PR_CurrentThread(), server->thread)); + + PR_Lock(server->ml); + server->state = cs_stop; + PR_Interrupt(server->thread); + while (cs_exit != server->state) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): joining server(0x%p)\n", + PR_CurrentThread(), server->thread)); + joinStatus = PR_JoinThread(server->thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + + PR_DestroyCondVar(server->stateChange); + PR_DestroyCondVar(server->pool.exiting); + PR_DestroyCondVar(server->pool.acceptComplete); + PR_DestroyLock(server->ml); + PR_DELETE(server); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): test complete\n", PR_CurrentThread())); + + PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + + TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + PR_Cleanup(); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/concur.c b/src/libs/xpcom18a4/nsprpub/pr/tests/concur.c new file mode 100644 index 00000000..225b2d28 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/concur.c @@ -0,0 +1,193 @@ +/* -*- 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 ***** */ + +/* +** File: concur.c +** Description: test of adding and removing concurrency options +*/ + +#include "prcvar.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prprf.h" +#include "prmem.h" +#include "prlog.h" + +#include "plgetopt.h" + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include + +#define DEFAULT_RANGE 10 +#define DEFAULT_LOOPS 100 + +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct Context +{ + PRLock *ml; + PRCondVar *cv; + PRIntn want, have; +} Context; + + +/* +** Make the instance of 'context' static (not on the stack) +** for Win16 threads +*/ +static Context context = {NULL, NULL, 0, 0}; + +static void PR_CALLBACK Dull(void *arg) +{ + Context *context = (Context*)arg; + PR_Lock(context->ml); + context->have += 1; + while (context->want >= context->have) + PR_WaitCondVar(context->cv, PR_INTERVAL_NO_TIMEOUT); + context->have -= 1; + PR_Unlock(context->ml); +} /* Dull */ + +PRIntn PR_CALLBACK Concur(PRIntn argc, char **argv) +{ + PRUintn cpus; + PLOptStatus os; + PRThread **threads; + PRBool debug = PR_FALSE; + PRUintn range = DEFAULT_RANGE; + PRStatus rc; + PRUintn cnt; + PRUintn loops = DEFAULT_LOOPS; + PRIntervalTime hundredMills = PR_MillisecondsToInterval(100); + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:r:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* GLOBAL threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + case 'r': /* range limit */ + range = atoi(opt->value); + break; + case 'l': /* loop counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == range) range = DEFAULT_RANGE; + if (0 == loops) loops = DEFAULT_LOOPS; + + context.ml = PR_NewLock(); + context.cv = PR_NewCondVar(context.ml); + + if (debug) + PR_fprintf( + PR_STDERR, "Testing with %d CPUs and %d interations\n", range, loops); + + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * range); + while (--loops > 0) + { + for (cpus = 1; cpus <= range; ++cpus) + { + PR_SetConcurrency(cpus); + context.want = cpus; + + threads[cpus - 1] = PR_CreateThread( + PR_USER_THREAD, Dull, &context, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + } + + PR_Sleep(hundredMills); + + for (cpus = range; cpus > 0; cpus--) + { + PR_SetConcurrency(cpus); + context.want = cpus - 1; + + PR_Lock(context.ml); + PR_NotifyCondVar(context.cv); + PR_Unlock(context.ml); + } + for(cnt = 0; cnt < range; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } + } + + + if (debug) + PR_fprintf( + PR_STDERR, "Waiting for %d thread(s) to exit\n", context.have); + + while (context.have > 0) PR_Sleep(hundredMills); + + if (debug) + PR_fprintf( + PR_STDERR, "Finished [want: %d, have: %d]\n", + context.want, context.have); + + PR_DestroyLock(context.ml); + PR_DestroyCondVar(context.cv); + PR_DELETE(threads); + + PR_fprintf(PR_STDERR, "PASSED\n"); + + return 0; +} /* Concur */ + +PRIntn main(PRIntn argc, char **argv) +{ + PR_STDIO_INIT(); + return PR_Initialize(Concur, argc, argv, 0); +} /* main */ + +/* concur.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/cvar.c b/src/libs/xpcom18a4/nsprpub/pr/tests/cvar.c new file mode 100644 index 00000000..32d9f1be --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/cvar.c @@ -0,0 +1,334 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: cvar.c +** +** Description: Tests Condition Variable Operations +** +** Modification History: +** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ + +#include "nspr.h" + +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +#define DEFAULT_COUNT 1000 +PRInt32 count = 0; +PRIntn debug_mode; + +#define kQSIZE 1 + +typedef struct { + PRLock *bufLock; + int startIdx; + int numFull; + PRCondVar *notFull; + PRCondVar *notEmpty; + void *data[kQSIZE]; +} CircBuf; + +static PRBool failed = PR_FALSE; + +/* +** NewCB creates and initializes a new circular buffer. +*/ +static CircBuf* NewCB(void) +{ + CircBuf *cbp; + + cbp = PR_NEW(CircBuf); + if (cbp == NULL) + return (NULL); + + cbp->bufLock = PR_NewLock(); + cbp->startIdx = 0; + cbp->numFull = 0; + cbp->notFull = PR_NewCondVar(cbp->bufLock); + cbp->notEmpty = PR_NewCondVar(cbp->bufLock); + + return (cbp); +} + +/* +** DeleteCB frees a circular buffer. +*/ +static void DeleteCB(CircBuf *cbp) +{ + PR_DestroyLock(cbp->bufLock); + PR_DestroyCondVar(cbp->notFull); + PR_DestroyCondVar(cbp->notEmpty); + PR_DELETE(cbp); +} + + +/* +** PutCBData puts new data on the queue. If the queue is full, it waits +** until there is room. +*/ +static void PutCBData(CircBuf *cbp, void *data) +{ + PR_Lock(cbp->bufLock); + /* wait while the buffer is full */ + while (cbp->numFull == kQSIZE) + PR_WaitCondVar(cbp->notFull,PR_INTERVAL_NO_TIMEOUT); + cbp->data[(cbp->startIdx + cbp->numFull) % kQSIZE] = data; + cbp->numFull += 1; + + /* let a waiting reader know that there is data */ + PR_NotifyCondVar(cbp->notEmpty); + PR_Unlock(cbp->bufLock); + +} + + +/* +** GetCBData gets the oldest data on the queue. If the queue is empty, it waits +** until new data appears. +*/ +static void* GetCBData(CircBuf *cbp) +{ + void *data; + + PR_Lock(cbp->bufLock); + /* wait while the buffer is empty */ + while (cbp->numFull == 0) + PR_WaitCondVar(cbp->notEmpty,PR_INTERVAL_NO_TIMEOUT); + data = cbp->data[cbp->startIdx]; + cbp->startIdx =(cbp->startIdx + 1) % kQSIZE; + cbp->numFull -= 1; + + /* let a waiting writer know that there is room */ + PR_NotifyCondVar(cbp->notFull); + PR_Unlock(cbp->bufLock); + + return (data); +} + + +/************************************************************************/ + +static int alive; + +static void PR_CALLBACK CXReader(void *arg) +{ + CircBuf *cbp = (CircBuf *)arg; + PRInt32 i, n; + void *data; + + n = count / 2; + for (i = 0; i < n; i++) { + data = GetCBData(cbp); + if ((int)data != i) + if (debug_mode) printf("data mismatch at for i = %d usec\n", i); + } + + PR_EnterMonitor(mon); + --alive; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void PR_CALLBACK CXWriter(void *arg) +{ + CircBuf *cbp = (CircBuf *)arg; + PRInt32 i, n; + + n = count / 2; + for (i = 0; i < n; i++) + PutCBData(cbp, (void *)i); + + PR_EnterMonitor(mon); + --alive; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void CondWaitContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + CircBuf *cbp; + + PR_EnterMonitor(mon); + + alive = 2; + + cbp = NewCB(); + + t1 = PR_CreateThread(PR_USER_THREAD, + CXReader, cbp, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + t2 = PR_CreateThread(PR_USER_THREAD, + CXWriter, cbp, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + + DeleteCB(cbp); + + PR_ExitMonitor(mon); +} + +static void CondWaitContextSwitchUU(void) +{ + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void CondWaitContextSwitchUK(void) +{ + CondWaitContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void CondWaitContextSwitchKK(void) +{ + CondWaitContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("%40s: %6.2f usec\n", msg, d / count); + + if (0 == d) failed = PR_TRUE; +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-c n] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + +#ifdef XP_MAC + SetupMacPrintfLog("cvar.log"); + debug_mode = 1; +#endif + + mon = PR_NewMonitor(); + + Measure(CondWaitContextSwitchUU, "cond var wait context switch- user/user"); + Measure(CondWaitContextSwitchUK, "cond var wait context switch- user/kernel"); + Measure(CondWaitContextSwitchKK, "cond var wait context switch- kernel/kernel"); + + PR_DestroyMonitor(mon); + + if (debug_mode) printf("%s\n", (failed) ? "FAILED" : "PASSED"); + + if(failed) + return 1; + else + return 0; +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/cvar2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/cvar2.c new file mode 100644 index 00000000..4b01cb4b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/cvar2.c @@ -0,0 +1,1008 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** Name: cvar2.c +** +** Description: Simple test creates several local and global threads; +** half use a single,shared condvar, and the +** other half have their own condvar. The main thread then loops +** notifying them to wakeup. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +#include "nspr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include +#include +#include + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define DEFAULT_COUNT 100 +#define DEFAULT_THREADS 5 +PRInt32 count = DEFAULT_COUNT; + +typedef struct threadinfo { + PRThread *thread; + PRInt32 id; + PRBool internal; + PRInt32 *tcount; + PRLock *lock; + PRCondVar *cvar; + PRIntervalTime timeout; + PRInt32 loops; + + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *exitcount; +} threadinfo; + +/* +** Make exitcount, tcount static. for Win16. +*/ +static PRInt32 exitcount=0; +static PRInt32 tcount=0; + + +/* Thread that gets notified; many threads share the same condvar */ +void PR_CALLBACK +SharedCondVarThread(void *_info) +{ + threadinfo *info = (threadinfo *)_info; + PRInt32 index; + + for (index=0; indexloops; index++) { + PR_Lock(info->lock); + if (*info->tcount == 0) + PR_WaitCondVar(info->cvar, info->timeout); +#if 0 + printf("shared thread %ld notified in loop %ld\n", info->id, index); +#endif + (*info->tcount)--; + PR_Unlock(info->lock); + + PR_Lock(info->exitlock); + (*info->exitcount)++; + PR_NotifyCondVar(info->exitcvar); + PR_Unlock(info->exitlock); + } +#if 0 + printf("shared thread %ld terminating\n", info->id); +#endif +} + +/* Thread that gets notified; no other threads use the same condvar */ +void PR_CALLBACK +PrivateCondVarThread(void *_info) +{ + threadinfo *info = (threadinfo *)_info; + PRInt32 index; + + for (index=0; indexloops; index++) { + PR_Lock(info->lock); + if (*info->tcount == 0) { + DPRINTF(("PrivateCondVarThread: thread 0x%lx waiting on cvar = 0x%lx\n", + PR_GetCurrentThread(), info->cvar)); + PR_WaitCondVar(info->cvar, info->timeout); + } +#if 0 + printf("solo thread %ld notified in loop %ld\n", info->id, index); +#endif + (*info->tcount)--; + PR_Unlock(info->lock); + + PR_Lock(info->exitlock); + (*info->exitcount)++; + PR_NotifyCondVar(info->exitcvar); +DPRINTF(("PrivateCondVarThread: thread 0x%lx notified exitcvar = 0x%lx cnt = %ld\n", + PR_GetCurrentThread(), info->exitcvar,(*info->exitcount))); + PR_Unlock(info->exitlock); + } +#if 0 + printf("solo thread %ld terminating\n", info->id); +#endif +} + +void +CreateTestThread(threadinfo *info, + PRInt32 id, + PRLock *lock, + PRCondVar *cvar, + PRInt32 loops, + PRIntervalTime timeout, + PRInt32 *tcount, + PRLock *exitlock, + PRCondVar *exitcvar, + PRInt32 *exitcount, + PRBool shared, + PRThreadScope scope) +{ + info->id = id; + info->internal = (shared) ? PR_FALSE : PR_TRUE; + info->lock = lock; + info->cvar = cvar; + info->loops = loops; + info->timeout = timeout; + info->tcount = tcount; + info->exitlock = exitlock; + info->exitcvar = exitcvar; + info->exitcount = exitcount; + info->thread = PR_CreateThread( + PR_USER_THREAD, + shared?SharedCondVarThread:PrivateCondVarThread, + info, + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + if (!info->thread) + PL_PrintError("error creating thread\n"); +} + + +void +CondVarTestSUU(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) + PR_JoinThread(list[index].thread); + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarTestSUK(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + exitcount=0; + tcount=0; + + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); +#if 0 + printf("threads ready\n"); +#endif + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) + PR_JoinThread(list[index].thread); + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarTestPUU(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *tcount, *saved_tcount; + + exitcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) { + DPRINTF(("CondVarTestPUU: joining thread 0x%lx\n",list[index].thread)); + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_tcount); +} + +void +CondVarTestPUK(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *tcount, *saved_tcount; + + exitcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_tcount = tcount = (PRInt32 *)PR_CALLOC(sizeof(*tcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg); + exitcount -= arg; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_tcount); +} + +void +CondVarTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *ptcount, *saved_ptcount; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + saved_ptcount = ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); +#if 0 + printf("threads ready\n"); +#endif + } + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); + PR_DELETE(saved_ptcount); +} + +void +CondVarTimeoutTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); + } + + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + PR_DestroyCondVar(exitcvar); + PR_DestroyLock(exitlock); + + PR_DELETE(list); +} + +void +CondVarMixedTest(void *_arg) +{ + PRInt32 arg = (PRInt32)_arg; + PRInt32 index, loops; + threadinfo *list; + PRLock *sharedlock; + PRCondVar *sharedcvar; + PRLock *exitlock; + PRCondVar *exitcvar; + PRInt32 *ptcount; + + exitcount=0; + tcount=0; + list = (threadinfo *)PR_MALLOC(sizeof(threadinfo) * (arg * 4)); + ptcount = (PRInt32 *)PR_CALLOC(sizeof(*ptcount) * (arg * 4)); + + sharedlock = PR_NewLock(); + sharedcvar = PR_NewCondVar(sharedlock); + exitlock = PR_NewLock(); + exitcvar = PR_NewCondVar(exitlock); + + /* Create the threads */ + for(index=0; index= arg*4); + exitcount -= arg*4; + PR_Unlock(exitlock); + } + + /* Join all the threads */ + for(index=0; index<(arg*4); index++) { + PR_JoinThread(list[index].thread); + if (list[index].internal) { + PR_Lock(list[index].lock); + PR_DestroyCondVar(list[index].cvar); + PR_Unlock(list[index].lock); + PR_DestroyLock(list[index].lock); + } + } + + PR_DestroyCondVar(sharedcvar); + PR_DestroyLock(sharedlock); + + PR_DELETE(list); +} + +void +CondVarCombinedTest(void *arg) +{ + PRThread *threads[3]; + + threads[0] = PR_CreateThread(PR_USER_THREAD, + CondVarTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + threads[1] = PR_CreateThread(PR_USER_THREAD, + CondVarTimeoutTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + threads[2] = PR_CreateThread(PR_USER_THREAD, + CondVarMixedTest, + (void *)arg, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + PR_JoinThread(threads[0]); + PR_JoinThread(threads[1]); + PR_JoinThread(threads[2]); +} + +/************************************************************************/ + +static void Measure(void (*func)(void *), PRInt32 arg, const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)((void *)arg); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + printf("%40s: %6.2f usec\n", msg, d / count); +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + PRInt32 threads, default_threads = DEFAULT_THREADS; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vc:t:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* debug mode */ + _debug_on = 1; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 't': /* number of threads involved */ + default_threads = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + if (0 == default_threads) default_threads = DEFAULT_THREADS; + +#ifdef XP_MAC + SetupMacPrintfLog("cvar2.log"); +#endif + + printf("\n\ +CondVar Test: \n\ + \n\ +Simple test creates several local and global threads; half use a single,\n\ +shared condvar, and the other half have their own condvar. The main \n\ +thread then loops notifying them to wakeup. \n\ + \n\ +The timeout test is very similar except that the threads are not \n\ +notified. They will all wakeup on a 1 second timeout. \n\ + \n\ +The mixed test combines the simple test and the timeout test; every \n\ +third thread is notified, the other threads are expected to timeout \n\ +correctly. \n\ + \n\ +Lastly, the combined test creates a thread for each of the above three \n\ +cases and they all run simultaneously. \n\ + \n\ +This test is run with %d, %d, %d, and %d threads of each type.\n\n", +default_threads, default_threads*2, default_threads*3, default_threads*4); + + PR_SetConcurrency(2); + + for (threads = default_threads; threads < default_threads*5; threads+=default_threads) { + printf("\n%ld Thread tests\n", threads); + Measure(CondVarTestSUU, threads, "Condvar simple test shared UU"); + Measure(CondVarTestSUK, threads, "Condvar simple test shared UK"); + Measure(CondVarTestPUU, threads, "Condvar simple test priv UU"); + Measure(CondVarTestPUK, threads, "Condvar simple test priv UK"); +#ifdef XP_MAC + /* Mac heaps can't handle thread*4 stack allocations at a time for (10, 15, 20)*4 */ + Measure(CondVarTest, 5, "Condvar simple test All"); + Measure(CondVarTimeoutTest, 5, "Condvar timeout test"); +#else + Measure(CondVarTest, threads, "Condvar simple test All"); + Measure(CondVarTimeoutTest, threads, "Condvar timeout test"); +#endif +#if 0 + Measure(CondVarMixedTest, threads, "Condvar mixed timeout test"); + Measure(CondVarCombinedTest, threads, "Combined condvar test"); +#endif + } + + printf("PASS\n"); + + return 0; +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc.c new file mode 100644 index 00000000..4295d0c0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc.c @@ -0,0 +1,347 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc.c +** +** Description: Testing malloc (OBSOLETE) +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ +#include +#include +#include +#include +#include "nspr.h" + +void +usage +( + void +) +{ + fprintf(stderr, "Usage: dbmalloc ('-m'|'-s') '-f' num_fails ('-d'|'-n') filename [...]\n"); + exit(0); +} + +typedef struct node_struct +{ + struct node_struct *next, *prev; + int line; + char value[4]; +} + node_t, + *node_pt; + +node_pt get_node(const char *line) +{ + node_pt rv; + int l = strlen(line); + rv = (node_pt)PR_MALLOC(sizeof(node_t) + l + 1 - 4); + if( (node_pt)0 == rv ) return (node_pt)0; + memcpy(&rv->value[0], line, l+1); + rv->next = rv->prev = (node_pt)0; + return rv; +} + +void +dump +( + const char *name, + node_pt node, + int mf, + int debug +) +{ + if( (node_pt)0 != node->prev ) dump(name, node->prev, mf, debug); + if( 0 != debug ) printf("[%s]: %6d: %s", name, node->line, node->value); + if( node->line == mf ) fprintf(stderr, "[%s]: Line %d was allocated!\n", name, node->line); + if( (node_pt)0 != node->next ) dump(name, node->next, mf, debug); + return; +} + +void +release +( + node_pt node +) +{ + if( (node_pt)0 != node->prev ) release(node->prev); + if( (node_pt)0 != node->next ) release(node->next); + PR_DELETE(node); +} + +int +t2 +( + const char *name, + int mf, + int debug +) +{ + int rv; + FILE *fp; + int l = 0; + node_pt head = (node_pt)0; + char buffer[ BUFSIZ ]; + + fp = fopen(name, "r"); + if( (FILE *)0 == fp ) + { + fprintf(stderr, "[%s]: Cannot open \"%s.\"\n", name, name); + return -1; + } + + /* fgets mallocs a buffer, first time through. */ + if( (char *)0 == fgets(buffer, BUFSIZ, fp) ) + { + fprintf(stderr, "[%s]: \"%s\" is empty.\n", name, name); + (void)fclose(fp); + return -1; + } + + rewind(fp); + + if( PR_SUCCESS != PR_ClearMallocCount() ) + { + fprintf(stderr, "[%s]: Cannot clear malloc count.\n", name); + (void)fclose(fp); + return -1; + } + + if( PR_SUCCESS != PR_SetMallocCountdown(mf) ) + { + fprintf(stderr, "[%s]: Cannot set malloc countdown to %d\n", name, mf); + (void)fclose(fp); + return -1; + } + + while( fgets(buffer, BUFSIZ, fp) ) + { + node_pt n; + node_pt *w = &head; + + if( (strlen(buffer) == (BUFSIZ-1)) && (buffer[BUFSIZ-2] != '\n') ) + buffer[BUFSIZ-2] == '\n'; + + l++; + + n = get_node(buffer); + if( (node_pt)0 == n ) + { + printf("[%s]: Line %d: malloc failure!\n", name, l); + continue; + } + + n->line = l; + + while( 1 ) + { + int comp; + + if( (node_pt)0 == *w ) + { + *w = n; + break; + } + + comp = strcmp((*w)->value, n->value); + if( comp < 0 ) w = &(*w)->next; + else w = &(*w)->prev; + } + } + + (void)fclose(fp); + + dump(name, head, mf, debug); + + rv = PR_GetMallocCount(); + PR_ClearMallocCountdown(); + + release(head); + + return rv; +} + +int nf = 0; +int debug = 0; + +void +test +( + const char *name +) +{ + int n, i; + + extern int nf, debug; + + printf("[%s]: starting test 0\n", name); + n = t2(name, 0, debug); + if( -1 == n ) return; + printf("[%s]: test 0 had %ld allocations.\n", name, n); + + if( 0 >= n ) return; + + for( i = 0; i < nf; i++ ) + { + int which = rand() % n; + if( 0 == which ) printf("[%s]: starting test %d -- no allocation should fail\n", name, i+1); + else printf("[%s]: starting test %d -- allocation %d should fail\n", name, i+1, which); + (void)t2(name, which, debug); + printf("[%s]: test %d done.\n", name, i+1); + } + + return; +} + +int +main +( + int argc, + char *argv[] +) +{ + int okay = 0; + int multithread = 0; + + struct threadlist + { + struct threadlist *next; + PRThread *thread; + } + *threadhead = (struct threadlist *)0; + + extern int nf, debug; + + srand(time(0)); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + printf("[main]: We %s using the debugging malloc.\n", + PR_IsDebuggingMalloc() ? "ARE" : "ARE NOT"); + + while( argv++, --argc ) + { + if( '-' == argv[0][0] ) + { + switch( argv[0][1] ) + { + case 'f': + nf = atoi(argv[0][2] ? &argv[0][2] : + --argc ? *++argv : "0"); + break; + case 'd': + debug = 1; + break; + case 'n': + debug = 0; + break; + case 'm': + multithread = 1; + break; + case 's': + multithread = 0; + break; + default: + usage(); + break; + } + } + else + { + FILE *fp = fopen(*argv, "r"); + if( (FILE *)0 == fp ) + { + fprintf(stderr, "Cannot open \"%s.\"\n", *argv); + continue; + } + + okay++; + (void)fclose(fp); + if( multithread ) + { + struct threadlist *n; + + n = (struct threadlist *)malloc(sizeof(struct threadlist)); + if( (struct threadlist *)0 == n ) + { + fprintf(stderr, "This is getting tedious. \"%s\"\n", *argv); + continue; + } + + n->next = threadhead; + n->thread = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))test, + *argv, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, + 0); + if( (PRThread *)0 == n->thread ) + { + fprintf(stderr, "Can't create thread for \"%s.\"\n", *argv); + continue; + } + else + { + threadhead = n; + } + } + else + { + test(*argv); + } + } + } + + if( okay == 0 ) usage(); + else while( (struct threadlist *)0 != threadhead ) + { + struct threadlist *x = threadhead->next; + (void)PR_JoinThread(threadhead->thread); + PR_DELETE(threadhead); + threadhead = x; + } + + return 0; +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc1.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc1.c new file mode 100644 index 00000000..ca1b4cb1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dbmalloc1.c @@ -0,0 +1,141 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c (OBSOLETE) +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** +** 12-June-97 AGarcia Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +#include +#include +#include "nspr.h" + +PRIntn failed_already=0; +PRIntn debug_mode; + +/* variable used for both r1 and r2 tests */ +int should_fail =0; +int actually_failed=0; + + +void +r1 +( + void +) +{ + int i; + actually_failed=0; + for( i = 0; i < 5; i++ ) + { + void *x = PR_MALLOC(128); + if( (void *)0 == x ) { + if (debug_mode) printf("\tMalloc %d failed.\n", i+1); + actually_failed = 1; + } + PR_DELETE(x); + } + + if (((should_fail != actually_failed) & (!debug_mode))) failed_already=1; + + + return; +} + +void +r2 +( + void +) +{ + int i; + + for( i = 0; i <= 5; i++ ) + { + should_fail =0; + if( 0 == i ) { + if (debug_mode) printf("No malloc should fail:\n"); + } + else { + if (debug_mode) printf("Malloc %d should fail:\n", i); + should_fail = 1; + } + PR_SetMallocCountdown(i); + r1(); + PR_ClearMallocCountdown(); + } +} + +int +main +( + int argc, + char *argv[] +) +{ + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + r2(); + + if(failed_already) + return 1; + else + return 0; + + +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dceemu.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dceemu.c new file mode 100644 index 00000000..bc037c83 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dceemu.c @@ -0,0 +1,132 @@ +/* -*- 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 ***** */ + +/* +** File: dceemu.c +** Description: testing the DCE emulation api +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete). +**/ + +/*********************************************************************** +** Includes +***********************************************************************/ + + +#if defined(_PR_DCETHREADS) + +#include "prlog.h" +#include "prinit.h" +#include "prpdce.h" + +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode=0; + +static PRIntn prmain(PRIntn argc, char **argv) +{ + PRStatus rv; + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PRP_NewNakedCondVar(); + PRIntervalTime tenmsecs = PR_MillisecondsToInterval(10); + + rv = PRP_TryLock(ml); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_TryLock(ml); + PR_ASSERT(PR_FAILURE == rv); + if ((rv != PR_FAILURE) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedNotify(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedBroadcast(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedWait(cv, ml, tenmsecs); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + PR_Unlock(ml); + + rv = PRP_NakedNotify(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + rv = PRP_NakedBroadcast(cv); + PR_ASSERT(PR_SUCCESS == rv); + if ((rv != PR_SUCCESS) & (!debug_mode)) failed_already=1; + + PRP_DestroyNakedCondVar(cv); + PR_DestroyLock(ml); + + if (debug_mode) printf("Test succeeded\n"); + + return 0; + +} /* prmain */ + +#endif /* #if defined(_PR_DCETHREADS) */ + +int main(int argc, char **argv) +{ + +#if defined(_PR_DCETHREADS) + PR_Initialize(prmain, argc, argv, 0); + if(failed_already) + return 1; + else + return 0; +#else + return 0; +#endif +} /* main */ + + +/* decemu.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/depend.c b/src/libs/xpcom18a4/nsprpub/pr/tests/depend.c new file mode 100644 index 00000000..e3fb691e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/depend.c @@ -0,0 +1,153 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1996 - Netscape Communications Corporation +** +** +** Name: depend.c +** Description: Test to enumerate the dependencies +* +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ +#include "prinit.h" + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include + +static void PrintVersion( + const char *msg, const PRVersion* info, PRIntn tab) +{ + static const len = 20; + static const char *tabs = {" "}; + + tab *= 2; + if (tab > len) tab = len; + printf("%s", &tabs[len - tab]); + printf("%s ", msg); + printf("%s ", info->id); + printf("%d.%d", info->major, info->minor); + if (0 != info->patch) + printf(".p%d", info->patch); + printf("\n"); +} /* PrintDependency */ + +static void ChaseDependents(const PRVersionInfo *info, PRIntn tab) +{ + PrintVersion("exports", &info->selfExport, tab); + if (NULL != info->importEnumerator) + { + const PRDependencyInfo *dependent = NULL; + while (NULL != (dependent = info->importEnumerator(dependent))) + { + const PRVersionInfo *import = dependent->exportInfoFn(); + PrintVersion("imports", &dependent->importNeeded, tab); + ChaseDependents(import, tab + 1); + } + } +} /* ChaseDependents */ + +static PRVersionInfo hack_export; +static PRVersionInfo dummy_export; +static PRDependencyInfo dummy_imports[2]; + +static const PRVersionInfo *HackExportInfo(void) +{ + hack_export.selfExport.major = 11; + hack_export.selfExport.minor = 10; + hack_export.selfExport.patch = 200; + hack_export.selfExport.id = "Hack"; + hack_export.importEnumerator = NULL; + return &hack_export; +} + +static const PRDependencyInfo *DummyImports( + const PRDependencyInfo *previous) +{ + if (NULL == previous) return &dummy_imports[0]; + else if (&dummy_imports[0] == previous) return &dummy_imports[1]; + else if (&dummy_imports[1] == previous) return NULL; +} /* DummyImports */ + +static const PRVersionInfo *DummyLibVersion(void) +{ + dummy_export.selfExport.major = 1; + dummy_export.selfExport.minor = 0; + dummy_export.selfExport.patch = 0; + dummy_export.selfExport.id = "Dumbass application"; + dummy_export.importEnumerator = DummyImports; + + dummy_imports[0].importNeeded.major = 2; + dummy_imports[0].importNeeded.minor = 0; + dummy_imports[0].importNeeded.patch = 0; + dummy_imports[0].importNeeded.id = "Netscape Portable Runtime"; + dummy_imports[0].exportInfoFn = PR_ExportInfo; + + dummy_imports[1].importNeeded.major = 5; + dummy_imports[1].importNeeded.minor = 1; + dummy_imports[1].importNeeded.patch = 2; + dummy_imports[1].importNeeded.id = "Hack Library"; + dummy_imports[1].exportInfoFn = HackExportInfo; + + return &dummy_export; +} /* DummyLibVersion */ + +int main(int argc, char **argv) +{ + PRIntn tab = 0; + const PRVersionInfo *info = DummyLibVersion(); + const char *buildDate = __DATE__, *buildTime = __TIME__; + + printf("Depend.c build time is %s %s\n", buildDate, buildTime); + + if (NULL != info) ChaseDependents(info, tab); + + return 0; +} /* main */ + +/* depend.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dll/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dll/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/Makefile.in new file mode 100644 index 00000000..62a214f4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/Makefile.in @@ -0,0 +1,121 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +# Disable optimization of the nspr on SunOS4.1.3 +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_RELEASE),4.1.3_U1) +OPTIMIZER = +endif +endif + +CSRCS = mygetval.c mysetval.c + +INCLUDES = -I$(dist_includedir) + +OBJS = $(OBJDIR)/mygetval.$(OBJ_SUFFIX) \ + $(OBJDIR)/mysetval.$(OBJ_SUFFIX) + +ifeq ($(OS_TARGET), WIN16) +W16OBJS = $(subst $(space),$(comma)$(space),$(OBJS)) +endif + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) +# do nothing +else +ifdef NS_USE_GCC +DLLBASE=-Wl,--image-base -Wl,0x30000000 +else +DLLBASE=/BASE:0x30000000 +endif +RES=$(OBJDIR)/my.res +RESNAME=../../../pr/src/nspr.rc +endif +endif + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +IMPORT_LIBRARY = $(OBJDIR)/my.$(LIB_SUFFIX) +SHARED_LIBRARY = $(OBJDIR)/my.dll +ifeq ($(OS_ARCH), OS2) +MAPFILE = $(OBJDIR)/my.def +GARBAGE += $(MAPFILE) +MKSHLIB += $(MAPFILE) +endif +TARGETS = $(SHARED_LIBRARY) $(IMPORT_LIBRARY) +else +ifdef MKSHLIB +SHARED_LIBRARY = $(OBJDIR)/libmy.$(DLL_SUFFIX) +endif +TARGETS = $(SHARED_LIBRARY) +endif + +# +# To create a loadable module on Rhapsody, we must override +# -dynamiclib with -bundle. +# +ifeq ($(OS_ARCH),Darwin) +DSO_LDOPTS = -bundle +endif + +include $(topsrcdir)/config/rules.mk + +ifeq ($(OS_TARGET), WIN16) +# Note: The Win16 target: my.dll requires these macros +# to be overridden to build the test .dll +# default values in win16...mk are for release targets. +# +OS_DLL_OPTION = NOCASEEXACT +OS_LIB_FLAGS = -irn +endif + +ifdef SHARED_LIBRARY +export:: $(TARGETS) + +clean:: + rm -rf $(TARGETS) +endif diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dll/my.def b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/my.def new file mode 100644 index 00000000..4423c0f0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/my.def @@ -0,0 +1,53 @@ +;+# +;+# 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 Netscape are +;+# Copyright (C) 2002-2003 Netscape Communications Corporation. All +;+# Rights Reserved. +;+# +;+# Contributor(s): +;+# +;+# Alternatively, the contents of this file may be used under the +;+# terms of the GNU General Public License Version 2 or later (the +;+# "GPL"), in which case the provisions of the GPL are applicable +;+# instead of those above. If you wish to allow use of your +;+# version of this file only under the terms of the GPL and not to +;+# allow others to use your version of this file under the MPL, +;+# indicate your decision by deleting the provisions above and +;+# replace them with the notice and other provisions required by +;+# the GPL. If you do not delete the provisions above, a recipient +;+# may use your version of this file under either the MPL or the +;+# GPL. +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX, OS/2 and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+# +;+MY_1.0 { +;+ global: +LIBRARY my ;- +EXPORTS ;- + My_GetValue; + My_SetValue; +;+ local: *; +;+}; diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mygetval.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mygetval.c new file mode 100644 index 00000000..17f36792 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mygetval.c @@ -0,0 +1,58 @@ +/* -*- 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 ***** */ + + +#if defined(WIN16) +#include +#endif +#include "prtypes.h" + +extern PRIntn my_global; + +PR_IMPLEMENT(PRIntn) My_GetValue() +{ + return my_global; +} + +#if defined(WIN16) +int CALLBACK LibMain( HINSTANCE hInst, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpszCmdLine ) +{ + return TRUE; +} +#endif /* WIN16 */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mysetval.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mysetval.c new file mode 100644 index 00000000..982f0776 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dll/mysetval.c @@ -0,0 +1,45 @@ +/* -*- 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 "prtypes.h" + +PRIntn my_global = 0; + +PR_IMPLEMENT(void) My_SetValue(PRIntn val) +{ + my_global = val; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dlltest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dlltest.c new file mode 100644 index 00000000..f8a5f53b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dlltest.c @@ -0,0 +1,221 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dlltest.c +** +** Description: test dll functionality. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prinit.h" +#include "prlink.h" +#include "prmem.h" +#include "prerror.h" + +#include "plstr.h" + +#include +#include + +typedef PRIntn (PR_CALLBACK *GetFcnType)(void); +typedef void (PR_CALLBACK *SetFcnType)(PRIntn); + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char** argv) +{ + PRLibrary *lib, *lib2; /* two handles to the same library */ + GetFcnType getFcn; + SetFcnType setFcn; + PRIntn value; + PRStatus status; + char *libName; + + if (argc >= 2 && PL_strcmp(argv[1], "-d") == 0) { + debug_mode = 1; + } + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + /* + * Test 1: load the library, look up the symbols, call the functions, + * and check the results. + */ + + libName = PR_GetLibraryName("dll", "my"); + if (debug_mode) printf("Loading library %s\n", libName); + lib = PR_LoadLibrary(libName); + PR_FreeLibraryName(libName); + if (lib == NULL) { + PRInt32 textLength = PR_GetErrorTextLength(); + char *text = (char*)PR_MALLOC(textLength); + (void)PR_GetErrorText(text); + fprintf( + stderr, "PR_LoadLibrary failed (%d, %d, %s)\n", + PR_GetError(), PR_GetOSError(), text); + if (!debug_mode) failed_already=1; + } + getFcn = (GetFcnType) PR_FindSymbol(lib, "My_GetValue"); + setFcn = (SetFcnType) PR_FindFunctionSymbol(lib, "My_SetValue"); + (*setFcn)(888); + value = (*getFcn)(); + if (value != 888) { + fprintf(stderr, "Test 1 failed: set value to 888, but got %d\n", value); + if (!debug_mode) failed_already=1; + } + if (debug_mode) printf("Test 1 passed\n"); + + /* + * Test 2: get a second handle to the same library (this should increment + * the reference count), look up the symbols, call the functions, and + * check the results. + */ + + getFcn = (GetFcnType) PR_FindSymbolAndLibrary("My_GetValue", &lib2); + if (NULL == getFcn || lib != lib2) { + fprintf(stderr, "Test 2 failed: handles for the same library are not " + "equal: handle 1: %p, handle 2: %p\n", lib, lib2); + if (!debug_mode) failed_already=1; + } + setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue"); + value = (*getFcn)(); + if (value != 888) { + fprintf(stderr, "Test 2 failed: value should be 888, but got %d\n", + value); + if (!debug_mode) failed_already=1; + } + (*setFcn)(777); + value = (*getFcn)(); + if (value != 777) { + fprintf(stderr, "Test 2 failed: set value to 777, but got %d\n", value); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (debug_mode) printf("Test 2 passed\n"); + + /* + * Test 3: unload the library. The library should still be accessible + * via the second handle. do the same things as above. + */ + + status = PR_UnloadLibrary(lib); + if (PR_FAILURE == status) { + fprintf(stderr, "Test 3 failed: cannot unload library: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + if (!debug_mode) failed_already=1; + goto exit_now; + } + getFcn = (GetFcnType) PR_FindFunctionSymbol(lib2, "My_GetValue"); + setFcn = (SetFcnType) PR_FindSymbol(lib2, "My_SetValue"); + (*setFcn)(666); + value = (*getFcn)(); + if (value != 666) { + fprintf(stderr, "Test 3 failed: set value to 666, but got %d\n", value); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (debug_mode) printf("Test 3 passed\n"); + + /* + * Test 4: unload the library, testing the reference count mechanism. + */ + + status = PR_UnloadLibrary(lib2); + if (PR_FAILURE == status) { + fprintf(stderr, "Test 4 failed: cannot unload library: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + if (!debug_mode) failed_already=1; + goto exit_now; + } + getFcn = (GetFcnType) PR_FindFunctionSymbolAndLibrary("My_GetValue", &lib2); + if (NULL != getFcn) { + fprintf(stderr, "Test 4 failed: how can we find a symbol " + "in an already unloaded library?\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (debug_mode) { + printf("Test 4 passed\n"); + } + + /* + ** Test 5: LoadStaticLibrary() + */ + { + PRStaticLinkTable slt[10]; + PRLibrary *lib; + + lib = PR_LoadStaticLibrary( "my.dll", slt ); + if ( lib == NULL ) + { + fprintf(stderr, "Test 5: LoadStatiLibrary() failed\n" ); + goto exit_now; + } + if (debug_mode) + { + printf("Test 5 passed\n"); + } + } + + goto exit_now; +exit_now: + PR_Cleanup(); + + if (failed_already) { + printf("FAILED\n"); + return 1; + } else { + printf("PASSED\n"); + return 0; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/dtoa.c b/src/libs/xpcom18a4/nsprpub/pr/tests/dtoa.c new file mode 100644 index 00000000..a9258c02 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/dtoa.c @@ -0,0 +1,217 @@ +/* -*- 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 file contains a test program for the function conversion functions + * for double precision code: + * PR_strtod + * PR_dtoa + * PR_cnvtf + * + * This file was ns/nspr/tests/dtoa.c, created by rrj on 1996/06/22. + * + *****************************************************************************/ +#include +#include +#include +#include +#include "prprf.h" +#include "prdtoa.h" + +static int failed_already = 0; + +int main( int argc, char* argv[] ) +{ + double num; + double num1; + double zero = 0.0; + char cnvt[50]; + + num = 1e24; + num1 = PR_strtod("1e24",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1e24"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1e+24",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 0.001e7; + num1 = PR_strtod("0.001e7",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","0.001e7"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("10000",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 0.0000000000000753; + num1 = PR_strtod("0.0000000000000753",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "0.0000000000000753"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("7.53e-14",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 1.867e73; + num1 = PR_strtod("1.867e73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1.867e73"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1.867e+73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + + num = -1.867e73; + num1 = PR_strtod("-1.867e73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e73"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.867e+73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = -1.867e-73; + num1 = PR_strtod("-1.867e-73",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e-73"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.867e-73",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + /* Testing for infinity */ + num = 1.0 / zero; + num1 = PR_strtod("1.867e765",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","1.867e765"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("Infinity",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = -1.0 / zero; + num1 = PR_strtod("-1.867e765",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n","-1.867e765"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-Infinity",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + /* Testing for NaN. PR_strtod can't parse "NaN" and "Infinity" */ + num = zero / zero; + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("NaN",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = - zero / zero; + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("NaN",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + num = 1.0000000001e21; + num1 = PR_strtod("1.0000000001e21",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "1.0000000001e21"); + failed_already = 1; + } + + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("1.0000000001e+21",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + + + num = -1.0000000001e-21; + num1 = PR_strtod("-1.0000000001e-21",NULL); + if(num1 != num){ + fprintf(stderr,"Failed to convert numeric value %s\n", + "-1.0000000001e-21"); + failed_already = 1; + } + PR_cnvtf(cnvt,sizeof(cnvt),20,num); + if(strcmp("-1.0000000001e-21",cnvt) != 0){ + fprintf(stderr,"Failed to convert numeric value %lf %s\n",num,cnvt); + failed_already = 1; + } + if (failed_already) { + printf("FAILED\n"); + } else { + printf("PASSED\n"); + } + return failed_already; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/env.c b/src/libs/xpcom18a4/nsprpub/pr/tests/env.c new file mode 100644 index 00000000..7f82fe08 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/env.c @@ -0,0 +1,221 @@ +/* -*- 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 ***** */ + +/* +** File: env.c +** Description: Testing environment variable operations +** +*/ +#include "prenv.h" +#include "plgetopt.h" + +#include +#include + +PRIntn debug = 0; +PRIntn verbose = 0; +PRBool failedAlready = PR_FALSE; + +#define ENVNAME "NSPR_ENVIRONMENT_TEST_VARIABLE" +#define ENVVALUE "The expected result" +#define ENVBUFSIZE 256 + +char *envBuf; /* buffer pointer. We leak memory here on purpose! */ + +static char * NewBuffer( size_t size ) +{ + char *buf = malloc( size ); + if ( NULL == buf ) { + printf("env: NewBuffer() failed\n"); + exit(1); + } + return(buf); +} /* end NewBuffer() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + char *value; + PRStatus rc; + + { /* Get command line options */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "vd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + break; + case 'v': /* verbose */ + verbose = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } /* end block "Get command line options" */ + +#if 0 + { + /* + ** This uses Windows native environment manipulation + ** as an experiment. Note the separation of namespace! + */ + BOOL rv; + DWORD size; + rv = SetEnvironmentVariable( ENVNAME, ENVVALUE ); + if ( rv == 0 ) { + if (debug) printf("env: Shit! SetEnvironmentVariable() failed\n"); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: SetEnvironmentVariable() worked\n"); + + size = GetEnvironmentVariable( ENVNAME, envBuf, ENVBUFSIZE ); + if ( size == 0 ) { + if (debug) printf("env: Shit! GetEnvironmentVariable() failed. Found: %s\n", envBuf ); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: GetEnvironmentVariable() worked. Found: %s\n", envBuf); + + value = PR_GetEnv( ENVNAME ); + if ( (NULL == value ) || (strcmp( value, ENVVALUE))) { + if (debug) printf( "env: PR_GetEnv() failed retrieving WinNative. Found: %s\n", value); + failedAlready = PR_TRUE; + } + if (verbose) printf("env: PR_GetEnv() worked. Found: %s\n", value); + } +#endif + + /* set an environment variable, read it back */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ENVVALUE ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed setting\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() worked.\n"); + } + + value = PR_GetEnv( ENVNAME ); + if ( (NULL == value ) || (strcmp( value, ENVVALUE))) { + if (debug) printf( "env: PR_GetEnv() Failed after setting\n" ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value ); + } + +/* ---------------------------------------------------------------------- */ + /* un-set the variable, using RAW name... should not work */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (verbose) printf( "env: PR_SetEnv() not un-set using RAW name. Good!\n"); + } else { + if (debug) printf("env: PR_SetEnv() un-set using RAW name. Bad!\n" ); + failedAlready = PR_TRUE; + } + + value = PR_GetEnv( ENVNAME ); + if ( NULL == value ) { + if (debug) printf("env: PR_GetEnv() after un-set using RAW name. Bad!\n" ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf( "env: PR_GetEnv() after RAW un-set found: %s\n", value ); + } + +/* ---------------------------------------------------------------------- */ + /* set it again ... */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ENVVALUE ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed setting the second time.\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() worked.\n"); + } + + /* un-set the variable using the form name= */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "=" ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" ); + } + + value = PR_GetEnv( ENVNAME ); + if (( NULL == value ) || ( 0x00 == *value )) { + if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" ); + } else { + if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value ); + failedAlready = PR_TRUE; + } +/* ---------------------------------------------------------------------- */ + /* un-set the variable using the form name= */ + envBuf = NewBuffer( ENVBUFSIZE ); + sprintf( envBuf, ENVNAME "999=" ); + rc = PR_SetEnv( envBuf ); + if ( PR_FAILURE == rc ) { + if (debug) printf( "env: PR_SetEnv() failed un-setting using name=\n"); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_SetEnv() un-set using name= worked\n" ); + } + + value = PR_GetEnv( ENVNAME "999" ); + if (( NULL == value ) || ( 0x00 == *value )) { + if (verbose) printf("env: PR_GetEnv() after un-set using name= worked\n" ); + } else { + if (debug) printf( "env: PR_GetEnv() after un-set using name=. Found: %s\n", value ); + failedAlready = PR_TRUE; + } + +/* ---------------------------------------------------------------------- */ + if (debug || verbose) printf("\n%s\n", (failedAlready)? "FAILED" : "PASSED" ); + return( (failedAlready)? 1 : 0 ); +} /* main() */ + +/* env.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/errcodes.c b/src/libs/xpcom18a4/nsprpub/pr/tests/errcodes.c new file mode 100644 index 00000000..76156848 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/errcodes.c @@ -0,0 +1,167 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: errcodes.c +** +** Description: print nspr error codes +** +*/ +#include "prerror.h" +#include "plgetopt.h" + +#include + +static int _debug_on = 0; + +struct errinfo { + PRErrorCode errcode; + char *errname; +}; + +struct errinfo errcodes[] = { +{PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"}, +{PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"}, +{PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"}, +{PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"}, +{PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"}, +{PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"}, +{PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"}, +{PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"}, +{PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"}, +{PR_IO_ERROR, "PR_IO_ERROR"}, +{PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"}, +{PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"}, +{PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"}, +{PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"}, +{PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"}, +{PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"}, +{PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"}, +{PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"}, +{PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"}, +{PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"}, +{PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"}, +{PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"}, +{PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"}, +{PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"}, +{PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"}, +{PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"}, +{PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"}, +{PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"}, +{PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"}, +{PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"}, +{PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"}, +{PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"}, +{PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"}, +{PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"}, +{PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"}, +{PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"}, +{PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"}, +{PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"}, +{PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"}, +{PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"}, +{PR_RANGE_ERROR, "PR_RANGE_ERROR"}, +{PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"}, +{PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"}, +{PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"}, +{PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"}, +{PR_PIPE_ERROR, "PR_PIPE_ERROR"}, +{PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"}, +{PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"}, +{PR_LOOP_ERROR, "PR_LOOP_ERROR"}, +{PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"}, +{PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"}, +{PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"}, +{PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"}, +{PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"}, +{PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"}, +{PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"}, +{PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"}, +{PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"}, +{PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"}, +{PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"}, +{PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"}, +{PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"}, +{PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"}, +{PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"}, +{PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"}, +{PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"}, +{PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"}, +{PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"}, +{PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"}, +{PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"}, +{PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"}, +{PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"}, +{PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"} +}; + +int +main(int argc, char **argv) +{ + + int count, errnum; + + /* + * -d debug mode + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + count = sizeof(errcodes)/sizeof(errcodes[0]); + printf("\nNumber of error codes = %d\n\n",count); + for (errnum = 0; errnum < count; errnum++) { + printf("%-40s = %d\n",errcodes[errnum].errname, + errcodes[errnum].errcode); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/errset.c b/src/libs/xpcom18a4/nsprpub/pr/tests/errset.c new file mode 100644 index 00000000..7d025f12 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/errset.c @@ -0,0 +1,186 @@ +/* -*- 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 security libraries. + * + * 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 ***** */ + +/*********************************************************************** +** +** Name: errset.c +** +** Description: errset.c exercises the functions in prerror.c. +** This code is a unit test of the prerror.c capability. +** +** Note: There's some fluff in here. The guts of the test +** were plagerized from another test. So, sue me. +** +** +*/ +#include "prerror.h" +#include "plgetopt.h" +#include "prlog.h" + +#include +#include + +static int _debug_on = 0; + +struct errinfo { + PRErrorCode errcode; + char *errname; +}; + +struct errinfo errcodes[] = { +{PR_OUT_OF_MEMORY_ERROR, "PR_OUT_OF_MEMORY_ERROR"}, +{PR_UNKNOWN_ERROR, "An intentionally long error message text intended to force a delete of the current errorString buffer and get another one."}, +{PR_BAD_DESCRIPTOR_ERROR, "PR_BAD_DESCRIPTOR_ERROR"}, +{PR_WOULD_BLOCK_ERROR, "PR_WOULD_BLOCK_ERROR"}, +{PR_ACCESS_FAULT_ERROR, "PR_ACCESS_FAULT_ERROR"}, +{PR_INVALID_METHOD_ERROR, "PR_INVALID_METHOD_ERROR"}, +{PR_ILLEGAL_ACCESS_ERROR, "PR_ILLEGAL_ACCESS_ERROR"}, +{PR_UNKNOWN_ERROR, "PR_UNKNOWN_ERROR"}, +{PR_PENDING_INTERRUPT_ERROR, "PR_PENDING_INTERRUPT_ERROR"}, +{PR_NOT_IMPLEMENTED_ERROR, "PR_NOT_IMPLEMENTED_ERROR"}, +{PR_IO_ERROR, "PR_IO_ERROR"}, +{PR_IO_TIMEOUT_ERROR, "PR_IO_TIMEOUT_ERROR"}, +{PR_IO_PENDING_ERROR, "PR_IO_PENDING_ERROR"}, +{PR_DIRECTORY_OPEN_ERROR, "PR_DIRECTORY_OPEN_ERROR"}, +{PR_INVALID_ARGUMENT_ERROR, "PR_INVALID_ARGUMENT_ERROR"}, +{PR_ADDRESS_NOT_AVAILABLE_ERROR, "PR_ADDRESS_NOT_AVAILABLE_ERROR"}, +{PR_ADDRESS_NOT_SUPPORTED_ERROR, "PR_ADDRESS_NOT_SUPPORTED_ERROR"}, +{PR_IS_CONNECTED_ERROR, "PR_IS_CONNECTED_ERROR"}, +{PR_BAD_ADDRESS_ERROR, "PR_BAD_ADDRESS_ERROR"}, +{PR_ADDRESS_IN_USE_ERROR, "PR_ADDRESS_IN_USE_ERROR"}, +{PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR"}, +{PR_NETWORK_UNREACHABLE_ERROR, "PR_NETWORK_UNREACHABLE_ERROR"}, +{PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR"}, +{PR_NOT_CONNECTED_ERROR, "PR_NOT_CONNECTED_ERROR"}, +{PR_LOAD_LIBRARY_ERROR, "PR_LOAD_LIBRARY_ERROR"}, +{PR_UNLOAD_LIBRARY_ERROR, "PR_UNLOAD_LIBRARY_ERROR"}, +{PR_FIND_SYMBOL_ERROR, "PR_FIND_SYMBOL_ERROR"}, +{PR_INSUFFICIENT_RESOURCES_ERROR, "PR_INSUFFICIENT_RESOURCES_ERROR"}, +{PR_DIRECTORY_LOOKUP_ERROR, "PR_DIRECTORY_LOOKUP_ERROR"}, +{PR_TPD_RANGE_ERROR, "PR_TPD_RANGE_ERROR"}, +{PR_PROC_DESC_TABLE_FULL_ERROR, "PR_PROC_DESC_TABLE_FULL_ERROR"}, +{PR_SYS_DESC_TABLE_FULL_ERROR, "PR_SYS_DESC_TABLE_FULL_ERROR"}, +{PR_NOT_SOCKET_ERROR, "PR_NOT_SOCKET_ERROR"}, +{PR_NOT_TCP_SOCKET_ERROR, "PR_NOT_TCP_SOCKET_ERROR"}, +{PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "PR_SOCKET_ADDRESS_IS_BOUND_ERROR"}, +{PR_NO_ACCESS_RIGHTS_ERROR, "PR_NO_ACCESS_RIGHTS_ERROR"}, +{PR_OPERATION_NOT_SUPPORTED_ERROR, "PR_OPERATION_NOT_SUPPORTED_ERROR"}, +{PR_PROTOCOL_NOT_SUPPORTED_ERROR, "PR_PROTOCOL_NOT_SUPPORTED_ERROR"}, +{PR_REMOTE_FILE_ERROR, "PR_REMOTE_FILE_ERROR"}, +{PR_BUFFER_OVERFLOW_ERROR, "PR_BUFFER_OVERFLOW_ERROR"}, +{PR_CONNECT_RESET_ERROR, "PR_CONNECT_RESET_ERROR"}, +{PR_RANGE_ERROR, "PR_RANGE_ERROR"}, +{PR_DEADLOCK_ERROR, "PR_DEADLOCK_ERROR"}, +{PR_FILE_IS_LOCKED_ERROR, "PR_FILE_IS_LOCKED_ERROR"}, +{PR_FILE_TOO_BIG_ERROR, "PR_FILE_TOO_BIG_ERROR"}, +{PR_NO_DEVICE_SPACE_ERROR, "PR_NO_DEVICE_SPACE_ERROR"}, +{PR_PIPE_ERROR, "PR_PIPE_ERROR"}, +{PR_NO_SEEK_DEVICE_ERROR, "PR_NO_SEEK_DEVICE_ERROR"}, +{PR_IS_DIRECTORY_ERROR, "PR_IS_DIRECTORY_ERROR"}, +{PR_LOOP_ERROR, "PR_LOOP_ERROR"}, +{PR_NAME_TOO_LONG_ERROR, "PR_NAME_TOO_LONG_ERROR"}, +{PR_FILE_NOT_FOUND_ERROR, "PR_FILE_NOT_FOUND_ERROR"}, +{PR_NOT_DIRECTORY_ERROR, "PR_NOT_DIRECTORY_ERROR"}, +{PR_READ_ONLY_FILESYSTEM_ERROR, "PR_READ_ONLY_FILESYSTEM_ERROR"}, +{PR_DIRECTORY_NOT_EMPTY_ERROR, "PR_DIRECTORY_NOT_EMPTY_ERROR"}, +{PR_FILESYSTEM_MOUNTED_ERROR, "PR_FILESYSTEM_MOUNTED_ERROR"}, +{PR_NOT_SAME_DEVICE_ERROR, "PR_NOT_SAME_DEVICE_ERROR"}, +{PR_DIRECTORY_CORRUPTED_ERROR, "PR_DIRECTORY_CORRUPTED_ERROR"}, +{PR_FILE_EXISTS_ERROR, "PR_FILE_EXISTS_ERROR"}, +{PR_MAX_DIRECTORY_ENTRIES_ERROR, "PR_MAX_DIRECTORY_ENTRIES_ERROR"}, +{PR_INVALID_DEVICE_STATE_ERROR, "PR_INVALID_DEVICE_STATE_ERROR"}, +{PR_DEVICE_IS_LOCKED_ERROR, "PR_DEVICE_IS_LOCKED_ERROR"}, +{PR_NO_MORE_FILES_ERROR, "PR_NO_MORE_FILES_ERROR"}, +{PR_END_OF_FILE_ERROR, "PR_END_OF_FILE_ERROR"}, +{PR_FILE_SEEK_ERROR, "PR_FILE_SEEK_ERROR"}, +{PR_FILE_IS_BUSY_ERROR, "PR_FILE_IS_BUSY_ERROR"}, +{PR_IN_PROGRESS_ERROR, "PR_IN_PROGRESS_ERROR"}, +{PR_ALREADY_INITIATED_ERROR, "PR_ALREADY_INITIATED_ERROR"}, +{PR_GROUP_EMPTY_ERROR, "PR_GROUP_EMPTY_ERROR"}, +{PR_INVALID_STATE_ERROR, "PR_INVALID_STATE_ERROR"}, +{PR_NETWORK_DOWN_ERROR, "PR_NETWORK_DOWN_ERROR"}, +{PR_SOCKET_SHUTDOWN_ERROR, "PR_SOCKET_SHUTDOWN_ERROR"}, +{PR_CONNECT_ABORTED_ERROR, "PR_CONNECT_ABORTED_ERROR"}, +{PR_HOST_UNREACHABLE_ERROR, "PR_HOST_UNREACHABLE_ERROR"} +}; + +int +main(int argc, char **argv) +{ + + int count, errnum; + + /* + * -d debug mode + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + count = sizeof(errcodes)/sizeof(errcodes[0]); + printf("\nNumber of error codes = %d\n\n",count); + for (errnum = 0; errnum < count; errnum++) { + PRInt32 len1, len2, err; + char msg[256]; + + PR_SetError( errnum, -5 ); + err = PR_GetError(); + PR_ASSERT( err == errnum ); + err = PR_GetOSError(); + PR_ASSERT( err == -5 ); + PR_SetErrorText( strlen(errcodes[errnum].errname), errcodes[errnum].errname ); + len1 = PR_GetErrorTextLength(); + len2 = PR_GetErrorText( msg ); + PR_ASSERT( len1 == len2 ); + printf("%5.5d -- %s\n", errnum, msg ); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/exit.c b/src/libs/xpcom18a4/nsprpub/pr/tests/exit.c new file mode 100644 index 00000000..6ccbe86d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/exit.c @@ -0,0 +1,137 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "prinit.h" +#include "prthread.h" +#include "prproces.h" +#include "prinrval.h" + +#include "plgetopt.h" + +#include + +static PRInt32 dally = 0; +static PRFileDesc *err = NULL; +static PRBool verbose = PR_FALSE, force = PR_FALSE; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-t s] [-h]\n"); + PR_fprintf(err, "\t-d Verbose output (default: FALSE)\n"); + PR_fprintf(err, "\t-x Forced termination (default: FALSE)\n"); + PR_fprintf(err, "\t-t Time for thread to block (default: 10 seconds)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static void Dull(void *arg) +{ + PR_Sleep(PR_SecondsToInterval(dally)); + if (verbose && force) + PR_fprintf(err, "If you see this, the test failed\n"); +} /* Dull */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "ht:dx"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* verbosity */ + verbose = PR_TRUE; + break; + case 'x': /* force exit */ + force = PR_TRUE; + break; + case 't': /* seconds to dally in child */ + dally = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (0 == dally) dally = 10; + + /* + * Create LOCAL and GLOBAL threads + */ + (void)PR_CreateThread( + PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + (void)PR_CreateThread( + PR_USER_THREAD, Dull, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + if (verbose) + PR_fprintf( + err, "Main is exiting now. Program should exit %s.\n", + (force) ? "immediately" : "after child dally time"); + + if (force) + { + PR_ProcessExit(0); + if (verbose) + { + PR_fprintf(err, "You should not have gotten here.\n"); + return 1; + } + } + return 0; + +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/fdcach.c b/src/libs/xpcom18a4/nsprpub/pr/tests/fdcach.c new file mode 100644 index 00000000..33382fa8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/fdcach.c @@ -0,0 +1,259 @@ +/* -*- 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 ***** */ + +/* + * File: fdcach.c + * Description: + * This test verifies that the fd cache and stack are working + * correctly. + */ + +#include "nspr.h" + +#include +#include + +/* + * Define ORDER_PRESERVED if the implementation of PR_SetFDCacheSize + * preserves the ordering of the fd's when moving them between the + * cache and the stack. + */ +#define ORDER_PRESERVED 1 + +/* + * NUM_FDS must be <= FD_CACHE_SIZE. + */ +#define FD_CACHE_SIZE 1024 +#define NUM_FDS 20 + +int main(int argc, char **argv) +{ + int i; + PRFileDesc *fds[NUM_FDS]; + PRFileDesc *savefds[NUM_FDS]; + int numfds = sizeof(fds)/sizeof(fds[0]); + + /* + * Switch between cache and stack when they are empty. + * Then start with the fd cache. + */ + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + PR_SetFDCacheSize(0, 0); + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + + /* Add some fd's to the fd cache. */ + for (i = 0; i < numfds; i++) { + savefds[i] = PR_NewTCPSocket(); + if (NULL == savefds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* + * Create some fd's. These fd's should come from + * the fd cache. Verify the FIFO ordering of the fd + * cache. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } + } + /* Put the fd's back to the fd cache. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd stack. */ + PR_SetFDCacheSize(0, 0); + + /* + * Create some fd's. These fd's should come from + * the fd stack. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } +#else + savefds[numfds-1-i] = fds[i]; +#endif + } + /* Put the fd's back to the fd stack. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* + * Now create some fd's and verify the LIFO ordering of + * the fd stack. + */ + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } + } + /* Put the fd's back to the fd stack. */ + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd cache. */ + PR_SetFDCacheSize(0, FD_CACHE_SIZE); + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } +#else + savefds[i] = fds[i]; +#endif + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[i]) { + fprintf(stderr, "fd cache malfunctioned\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + /* Switch to the fd stack. */ + PR_SetFDCacheSize(0, 0); + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } +#ifdef ORDER_PRESERVED + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } +#else + savefds[numfds-1-i]; +#endif + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + for (i = 0; i < numfds; i++) { + fds[i] = PR_NewTCPSocket(); + if (NULL == fds[i]) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (fds[i] != savefds[numfds-1-i]) { + fprintf(stderr, "fd stack malfunctioned\n"); + exit(1); + } + } + for (i = 0; i < numfds; i++) { + if (PR_Close(savefds[i]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + + PR_Cleanup(); + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/fileio.c b/src/libs/xpcom18a4/nsprpub/pr/tests/fileio.c new file mode 100644 index 00000000..0b154047 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/fileio.c @@ -0,0 +1,250 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: fileio.c +** +** Description: Program to copy one file to another. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +#include "prinit.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmon.h" +#include "prmem.h" +#include "prio.h" +#include "prlog.h" + +#include + +#ifdef XP_MAC +#include "prsem.h" +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + + +#define TBSIZE 1024 + +static PRUint8 tbuf[TBSIZE]; + +static PRFileDesc *t1, *t2; + +PRIntn failed_already=0; +PRIntn debug_mode; +static void InitialSetup(void) +{ + PRUintn i; + PRInt32 nWritten, rv; + + t1 = PR_Open("t1.tmp", PR_CREATE_FILE | PR_RDWR, 0); + PR_ASSERT(t1 != NULL); + + for (i=0; i= 0) { + buf[i].nbytes = nbytes; + PR_PostSem(fullBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +static void PR_CALLBACK writer(void *arg) +{ + PRUintn i = 0; + PRInt32 nbytes; + + do { + (void) PR_WaitSem(fullBufs); + nbytes = buf[i].nbytes; + if (nbytes > 0) { + nbytes = PR_Write((PRFileDesc*)arg, buf[i].data, nbytes); + PR_PostSem(emptyBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +int main(int argc, char **argv) +{ + PRThread *r, *w; + + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("fileio.log"); + debug_mode = 1; +#endif + + emptyBufs = PR_NewSem(2); /* two empty buffers */ + + fullBufs = PR_NewSem(0); /* zero full buffers */ + + /* Create initial temp file setup */ + InitialSetup(); + + /* create the reader thread */ + + r = PR_CreateThread(PR_USER_THREAD, + reader, t1, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + w = PR_CreateThread(PR_USER_THREAD, + writer, t2, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + /* Do the joining for both threads */ + (void) PR_JoinThread(r); + (void) PR_JoinThread(w); + + /* Do the verification and clean up */ + VerifyAndCleanup(); + + PR_DestroySem(emptyBufs); + PR_DestroySem(fullBufs); + + PR_Cleanup(); + + if(failed_already) + { + printf("Fail\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/foreign.c b/src/libs/xpcom18a4/nsprpub/pr/tests/foreign.c new file mode 100644 index 00000000..37f154e1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/foreign.c @@ -0,0 +1,416 @@ +/* -*- 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 ***** */ + +/* +** File: foreign.c +** Description: Testing various functions w/ foreign threads +** +** We create a thread and get it to call exactly one runtime function. +** The thread is allowed to be created by some other environment that +** NSPR, but it does not announce itself to the runtime prior to calling +** in. +** +** The goal: try to survive. +** +*/ + +#include "prcvar.h" +#include "prenv.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" +#include "prthread.h" +#include "prtypes.h" +#include "prprf.h" +#include "plgetopt.h" + +#include +#include + +static enum { + thread_nspr, thread_pthread, thread_uithread, thread_sproc, thread_win32 +} thread_provider; + +typedef void (*StartFn)(void*); +typedef struct StartObject +{ + StartFn start; + void *arg; +} StartObject; + +static PRFileDesc *output; + +static int _debug_on = 0; + +#define DEFAULT_THREAD_COUNT 10 + +#define DPRINTF(arg) if (_debug_on) PR_fprintf arg + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#include "md/_pth.h" +static void *pthread_start(void *arg) +{ + StartFn start = ((StartObject*)arg)->start; + void *data = ((StartObject*)arg)->arg; + PR_Free(arg); + start(data); + return NULL; +} /* pthread_start */ +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) +#include +static void *uithread_start(void *arg) +{ + StartFn start = ((StartObject*)arg)->start; + void *data = ((StartObject*)arg)->arg; + PR_Free(arg); + start(data); + return NULL; +} /* uithread_start */ +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include +#include +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + +#if defined(WIN32) +#include /* for _beginthreadex() */ + +static PRUintn __stdcall windows_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return 0; +} /* windows_start */ +#endif /* defined(WIN32) */ + +static PRStatus CreateThread(StartFn start, void *arg) +{ + PRStatus rv; + + switch (thread_provider) + { + case thread_nspr: + { + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, start, arg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; + } + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + { + int rv; + pthread_t id; + pthread_attr_t tattr; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + rv = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)_PT_PTHREAD_ATTR_DESTROY(&tattr); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + break; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + + case thread_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + { + int rv; + thread_t id; + long flags; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + flags = THR_DETACHED; + + rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + break; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + break; + case thread_win32: +#if defined(WIN32) + { + void *th; + PRUintn id; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + th = (void*)_beginthreadex( + NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */ + 0U, /* DWORD - initial thread stack size, in bytes */ + windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */ + start_object, /* LPVOID - argument for new thread */ + 0U, /*DWORD dwCreationFlags - creation flags */ + &id /* LPDWORD - pointer to returned thread identifier */ ); + + rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif + break; + default: + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* CreateThread */ + +static void PR_CALLBACK lazyEntry(void *arg) +{ + PR_ASSERT(NULL == arg); +} /* lazyEntry */ + + +static void OneShot(void *arg) +{ + PRUintn pdkey; + PRLock *lock; + PRFileDesc *fd; + PRDir *dir; + PRFileDesc *pair[2]; + PRIntn test = (PRIntn)arg; + + for (test = 0; test < 12; ++test) { + + switch (test) + { + case 0: + lock = PR_NewLock(); + DPRINTF((output,"Thread[0x%x] called PR_NewLock\n", + PR_GetCurrentThread())); + PR_DestroyLock(lock); + break; + + case 1: + (void)PR_SecondsToInterval(1); + DPRINTF((output,"Thread[0x%x] called PR_SecondsToInterval\n", + PR_GetCurrentThread())); + break; + + case 2: (void)PR_CreateThread( + PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_UNJOINABLE_THREAD, 0); + DPRINTF((output,"Thread[0x%x] called PR_CreateThread\n", + PR_GetCurrentThread())); + break; + + case 3: + fd = PR_Open("foreign.tmp", PR_CREATE_FILE | PR_RDWR, 0666); + DPRINTF((output,"Thread[0x%x] called PR_Open\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 4: + fd = PR_NewUDPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewUDPSocket\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 5: + fd = PR_NewTCPSocket(); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocket\n", + PR_GetCurrentThread())); + PR_Close(fd); + break; + + case 6: + dir = PR_OpenDir("/tmp/"); + DPRINTF((output,"Thread[0x%x] called PR_OpenDir\n", + PR_GetCurrentThread())); + PR_CloseDir(dir); + break; + + case 7: + (void)PR_NewThreadPrivateIndex(&pdkey, NULL); + DPRINTF((output,"Thread[0x%x] called PR_NewThreadPrivateIndex\n", + PR_GetCurrentThread())); + break; + + case 8: + (void)PR_GetEnv("PATH"); + DPRINTF((output,"Thread[0x%x] called PR_GetEnv\n", + PR_GetCurrentThread())); + break; + + case 9: + (void)PR_NewTCPSocketPair(pair); + DPRINTF((output,"Thread[0x%x] called PR_NewTCPSocketPair\n", + PR_GetCurrentThread())); + PR_Close(pair[0]); + PR_Close(pair[1]); + break; + + case 10: + PR_SetConcurrency(2); + DPRINTF((output,"Thread[0x%x] called PR_SetConcurrency\n", + PR_GetCurrentThread())); + break; + + case 11: + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH); + DPRINTF((output,"Thread[0x%x] called PR_SetThreadPriority\n", + PR_GetCurrentThread())); + break; + + default: + break; + } /* switch() */ + } +} /* OneShot */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRInt32 thread_cnt = DEFAULT_THREAD_COUNT; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); + +#if defined(WIN32) + thread_provider = thread_win32; +#elif defined(_PR_PTHREADS) + thread_provider = thread_pthread; +#elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + thread_provider = thread_uithread; +#elif defined(IRIX) + thread_provider = thread_sproc; +#else + thread_provider = thread_nspr; +#endif + + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 't': /* thread count */ + thread_cnt = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(2); + + output = PR_GetSpecialFD(PR_StandardOutput); + + while (thread_cnt-- > 0) + { + rv = CreateThread(OneShot, (void*)thread_cnt); + PR_ASSERT(PR_SUCCESS == rv); + PR_Sleep(PR_MillisecondsToInterval(5)); + } + PR_Sleep(PR_SecondsToInterval(3)); + return (PR_SUCCESS == PR_Cleanup()) ? 0 : 1; +} /* main */ + +/* foreign.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/forktest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/forktest.c new file mode 100644 index 00000000..ad260ad7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/forktest.c @@ -0,0 +1,346 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: forktest.c +** +** Description: UNIX test for fork functions. +** +** Modification History: +** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** 12-June-97 AGarcic - Revert to return code 0 and 1, remove debug option (obsolete). +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include +#include +#include + +PRIntn failed_already=0; + +#ifdef XP_UNIX + +#include +#include +#include +#include + +static char *message = "Hello world!"; + +static void +ClientThreadFunc(void *arg) +{ + PRNetAddr addr; + PRFileDesc *sock = NULL; + PRInt32 tmp = (PRInt32)arg; + + /* + * Make sure the PR_Accept call will block + */ + + printf("Wait one second before connect\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = 0; + if ((sock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "failed to create TCP socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_Bind(sock, &addr) != PR_SUCCESS) { + fprintf(stderr, "PR_Bind failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + addr.inet.ip = PR_htonl(INADDR_LOOPBACK); + addr.inet.port = PR_htons((PRInt16)tmp); + printf("Connecting to port %hu\n", PR_ntohs(addr.inet.port)); + fflush(stdout); + if (PR_Connect(sock, &addr, PR_SecondsToInterval(5)) != + PR_SUCCESS) { + fprintf(stderr, "PR_Connect failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + printf("Writing message \"%s\"\n", message); + fflush(stdout); + if (PR_Send(sock, message, strlen(message) + 1, 0, PR_INTERVAL_NO_TIMEOUT) == + -1) { + fprintf(stderr, "PR_Send failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } +finish: + if (sock) { + PR_Close(sock); + } + return; +} + +/* + * DoIO -- + * This function creates a thread that acts as a client and itself. + * acts as a server. Then it joins the client thread. + */ +static void +DoIO(void) +{ + PRThread *clientThread; + PRFileDesc *listenSock = NULL; + PRFileDesc *sock = NULL; + PRNetAddr addr; + PRInt32 nBytes; + char buf[128]; + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + fprintf(stderr, "failed to create a TCP socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = 0; + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "failed to bind socket: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "failed to get socket port number: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + clientThread = PR_CreateThread( PR_USER_THREAD, ClientThreadFunc, + (void *) PR_ntohs(addr.inet.port), PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "Cannot create client thread: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already = 1; + goto finish; + } + printf("Accepting connection at port %hu\n", PR_ntohs(addr.inet.port)); + fflush(stdout); + sock = PR_Accept(listenSock, &addr, PR_SecondsToInterval(5)); + if (!sock) { + fprintf(stderr, "PR_Accept failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + nBytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (nBytes == -1) { + fprintf(stderr, "PR_Recv failed: error code %d\n", + PR_GetError()); + failed_already = 1; + goto finish; + } + + /* + * Make sure it has proper null byte to mark end of string + */ + + buf[sizeof(buf) - 1] = '\0'; + printf("Received \"%s\" from the client\n", buf); + fflush(stdout); + if (!strcmp(buf, message)) { + PR_JoinThread(clientThread); + + printf("The message is received correctly\n"); + fflush(stdout); + } else { + fprintf(stderr, "The message should be \"%s\"\n", + message); + failed_already = 1; + } + +finish: + if (listenSock) { + PR_Close(listenSock); + } + if (sock) { + PR_Close(sock); + } + return; +} + +#ifdef _PR_DCETHREADS + +#include + +pid_t PR_UnixFork1(void) +{ + pid_t parent = getpid(); + int rv = syscall(SYS_fork); + + if (rv == -1) { + return (pid_t) -1; + } else { + /* For each process, rv is the pid of the other process */ + if (rv == parent) { + /* the child */ + return 0; + } else { + /* the parent */ + return rv; + } + } +} + +#elif defined(SOLARIS) + +/* + * It seems like that in Solaris 2.4 one must call fork1() if the + * the child process is going to use thread functions. Solaris 2.5 + * doesn't have this problem. Calling fork() also works. + */ + +pid_t PR_UnixFork1(void) +{ + return fork1(); +} + +#else + +pid_t PR_UnixFork1(void) +{ + return fork(); +} + +#endif /* PR_DCETHREADS */ + +int main( +int argc, +char *argv[] +) +{ + pid_t pid; + int rv; + + /* main test program */ + + DoIO(); + + pid = PR_UnixFork1(); + + if (pid == (pid_t) -1) { + fprintf(stderr, "Fork failed: errno %d\n", errno); + failed_already=1; + return 1; + } else if (pid > 0) { + int childStatus; + + printf("Fork succeeded. Parent process continues.\n"); + DoIO(); + if ((rv = waitpid(pid, &childStatus, 0)) != pid) { +#if defined(IRIX) && !defined(_PR_PTHREADS) + /* + * nspr may handle SIGCLD signal + */ + if ((rv < 0) && (errno == ECHILD)) { + } else +#endif + { + fprintf(stderr, "waitpid failed: %d\n", errno); + failed_already = 1; + } + } else if (!WIFEXITED(childStatus) + || WEXITSTATUS(childStatus) != 0) { + failed_already = 1; + } + printf("Parent process exits.\n"); + if (!failed_already) { + printf("PASSED\n"); + } else { + printf("FAILED\n"); + } + return failed_already; + } else { +#if defined(IRIX) && !defined(_PR_PTHREADS) + extern void _PR_IRIX_CHILD_PROCESS(void); + _PR_IRIX_CHILD_PROCESS(); +#endif + printf("Fork succeeded. Child process continues.\n"); + DoIO(); + printf("Child process exits.\n"); + return failed_already; + } +} + +#else /* XP_UNIX */ + +int main( int argc, +char *argv[] +) +{ + + printf("The fork test is applicable to Unix only.\n"); + return 0; + +} + +#endif /* XP_UNIX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/formattm.c b/src/libs/xpcom18a4/nsprpub/pr/tests/formattm.c new file mode 100644 index 00000000..c3c758b5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/formattm.c @@ -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) 2003 + * 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 ***** */ + +/* A test program for PR_FormatTime and PR_FormatTimeUSEnglish */ + +#include "prtime.h" + +#include + +int main() +{ + char buffer[256]; + PRTime now; + PRExplodedTime tod; + + now = PR_Now(); + PR_ExplodeTime(now, PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), + "%a %b %d %H:%M:%S %Z %Y", &tod); + printf("%s\n", buffer); + (void)PR_FormatTimeUSEnglish(buffer, sizeof(buffer), + "%a %b %d %H:%M:%S %Z %Y", &tod); + printf("%s\n", buffer); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/freeif.c b/src/libs/xpcom18a4/nsprpub/pr/tests/freeif.c new file mode 100644 index 00000000..7aa16b49 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/freeif.c @@ -0,0 +1,75 @@ +/* -*- 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) 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 ***** */ + +/* + * A test to see if the macros PR_DELETE and PR_FREEIF are + * properly defined. (See Bugzilla bug #39110.) + */ + +#include "nspr.h" + +#include +#include + +static void Noop(void) { } + +static void Fail(void) +{ + printf("FAIL\n"); + exit(1); +} + +int main() +{ + int foo = 1; + char *ptr = NULL; + + /* this fails to compile with the old definition of PR_DELETE */ + if (foo) + PR_DELETE(ptr); + else + Noop(); + + /* this nests incorrectly with the old definition of PR_FREEIF */ + if (foo) + PR_FREEIF(ptr); + else + Fail(); + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/fsync.c b/src/libs/xpcom18a4/nsprpub/pr/tests/fsync.c new file mode 100644 index 00000000..cea298b3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/fsync.c @@ -0,0 +1,155 @@ +/* -*- 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 "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prinrval.h" + +#include "plerror.h" +#include "plgetopt.h" + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-S] [-K ] [-h] \n"); + PR_fprintf(err, "\t-c Nuber of iterations (default: 10)\n"); + PR_fprintf(err, "\t-S Sync the file (default: FALSE)\n"); + PR_fprintf(err, "\t-K Size of file (K bytes) (default: 10)\n"); + PR_fprintf(err, "\t Name of file to write (default: /usr/tmp/sync.dat)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRUint8 *buffer; + PRFileDesc *file = NULL; + const char *filename = "sync.dat"; + PRUint32 index, loops, iterations = 10, filesize = 10; + PRIntn flags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; + PLOptState *opt = PL_CreateOptState(argc, argv, "hSK:c:"); + PRIntervalTime time, total = 0, shortest = 0x7fffffff, longest = 0; + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of file to create */ + filename = opt->value; + break; + case 'S': /* Use sych option on file */ + flags |= PR_SYNC; + break; + case 'K': /* Size of file to write */ + filesize = atoi(opt->value); + break; + case 'c': /* Number of iterations */ + iterations = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: /* user needs some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + file = PR_Open(filename, flags, 0666); + if (NULL == file) + { + PL_FPrintError(err, "Failed to open file"); + return 1; + } + + buffer = (PRUint8*)PR_CALLOC(1024); + if (NULL == buffer) + { + PL_FPrintError(err, "Cannot allocate buffer"); + return 1; + } + + for (index = 0; index < sizeof(buffer); ++index) + buffer[index] = (PRUint8)index; + + for (loops = 0; loops < iterations; ++loops) + { + time = PR_IntervalNow(); + for (index = 0; index < filesize; ++index) + { + PR_Write(file, buffer, 1024); + } + time = (PR_IntervalNow() - time); + + total += time; + if (time < shortest) shortest = time; + else if (time > longest) longest = time; + if (0 != PR_Seek(file, 0, PR_SEEK_SET)) + { + PL_FPrintError(err, "Rewinding file"); + return 1; + } + } + + total = total / iterations; + PR_fprintf( + err, "%u iterations over a %u kbyte %sfile: %u [%u] %u\n", + iterations, filesize, ((flags & PR_SYNC) ? "SYNCH'd " : ""), + PR_IntervalToMicroseconds(shortest), + PR_IntervalToMicroseconds(total), + PR_IntervalToMicroseconds(longest)); + + PR_DELETE(buffer); + rv = PR_Close(file); + if (PR_SUCCESS != rv) + { + PL_FPrintError(err, "Closing file failed"); + return 1; + } + rv = PR_Delete(filename); + if (PR_SUCCESS != rv) + { + PL_FPrintError(err, "Deleting file failed"); + return 1; + } + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/getai.c b/src/libs/xpcom18a4/nsprpub/pr/tests/getai.c new file mode 100644 index 00000000..bc4a59a7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/getai.c @@ -0,0 +1,64 @@ +/* -*- 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) 2003 + * 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 "nspr.h" + +#include +#include + +int main(int argc, char *argv[]) +{ + PRAddrInfo *ai; + void *iter; + PRNetAddr addr; + + ai = PR_GetAddrInfoByName(argv[1], PR_AF_UNSPEC, PR_AI_ADDRCONFIG); + if (ai == NULL) { + fprintf(stderr, "PR_GetAddrInfoByName failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("%s\n", PR_GetCanonNameFromAddrInfo(ai)); + iter = NULL; + while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) { + char buf[128]; + PR_NetAddrToString(&addr, buf, sizeof buf); + printf("%s\n", buf); + } + PR_FreeAddrInfo(ai); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/gethost.c b/src/libs/xpcom18a4/nsprpub/pr/tests/gethost.c new file mode 100644 index 00000000..3af41a3f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/gethost.c @@ -0,0 +1,291 @@ +/* -*- 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 ***** */ + +/* + * File: gethost.c + * + * Description: tests various functions in prnetdb.h + * + * Usage: gethost [-6] [hostname] + */ + +#include "prio.h" +#include "prnetdb.h" +#include "plgetopt.h" + +#include +#include + +#define DEFAULT_HOST_NAME "mcom.com" + +static void Help(void) +{ + fprintf(stderr, "Usage: gethost [-h] [hostname]\n"); + fprintf(stderr, "\t-h help\n"); + fprintf(stderr, "\thostname Name of host (default: %s)\n", + DEFAULT_HOST_NAME); +} /* Help */ + +/* + * Prints the contents of a PRHostEnt structure + */ +void PrintHostent(const PRHostEnt *he) +{ + int i; + int j; + + printf("h_name: %s\n", he->h_name); + for (i = 0; he->h_aliases[i]; i++) { + printf("h_aliases[%d]: %s\n", i, he->h_aliases[i]); + } + printf("h_addrtype: %d\n", he->h_addrtype); + printf("h_length: %d\n", he->h_length); + for (i = 0; he->h_addr_list[i]; i++) { + printf("h_addr_list[%d]: ", i); + for (j = 0; j < he->h_length; j++) { + if (j != 0) printf("."); + printf("%u", (unsigned char)he->h_addr_list[i][j]); + } + printf("\n"); + } +} + +int main(int argc, char **argv) +{ + const char *hostName = DEFAULT_HOST_NAME; + PRHostEnt he, reversehe; + char buf[PR_NETDB_BUF_SIZE]; + char reversebuf[PR_NETDB_BUF_SIZE]; + PRIntn idx; + PRNetAddr addr; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 0: /* naked */ + hostName = opt->value; + break; + case 'h': /* Help message */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_GetHostByName(hostName, buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByName failed\n"); + exit(1); + } + PrintHostent(&he); + idx = 0; + while (1) { + idx = PR_EnumerateHostEnt(idx, &he, 0, &addr); + if (idx == -1) { + fprintf(stderr, "PR_EnumerateHostEnt failed\n"); + exit(1); + } + if (idx == 0) break; /* normal loop termination */ + printf("reverse lookup\n"); + if (PR_GetHostByAddr(&addr, reversebuf, sizeof(reversebuf), + &reversehe) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByAddr failed\n"); + exit(1); + } + PrintHostent(&reversehe); + } + + printf("PR_GetIPNodeByName with PR_AF_INET\n"); + if (PR_GetIPNodeByName(hostName, PR_AF_INET, PR_AI_DEFAULT, + buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetIPNodeByName failed\n"); + exit(1); + } + PrintHostent(&he); + printf("PR_GetIPNodeByName with PR_AF_INET6\n"); + if (PR_GetIPNodeByName(hostName, PR_AF_INET6, PR_AI_DEFAULT, + buf, sizeof(buf), &he) == PR_FAILURE) { + fprintf(stderr, "PR_GetIPNodeByName failed\n"); + exit(1); + } + PrintHostent(&he); + idx = 0; + printf("PR_GetHostByAddr with PR_AF_INET6\n"); + while (1) { + idx = PR_EnumerateHostEnt(idx, &he, 0, &addr); + if (idx == -1) { + fprintf(stderr, "PR_EnumerateHostEnt failed\n"); + exit(1); + } + if (idx == 0) break; /* normal loop termination */ + printf("reverse lookup\n"); + if (PR_GetHostByAddr(&addr, reversebuf, sizeof(reversebuf), + &reversehe) == PR_FAILURE) { + fprintf(stderr, "PR_GetHostByAddr failed\n"); + exit(1); + } + PrintHostent(&reversehe); + } + printf("PR_GetHostByAddr with PR_AF_INET6 done\n"); + + PR_StringToNetAddr("::1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_TRUE) { + fprintf(stderr, "addr should not be ipv4 mapped address\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + PR_StringToNetAddr("127.0.0.1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + PR_StringToNetAddr("::FFFF:127.0.0.1", &addr); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped) == PR_FALSE) { + fprintf(stderr, "addr should be ipv4 mapped address\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv4 INADDRANY: %s\n", buf); + } + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv4 LOOPBACK: %s\n", buf); + } + + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrAny) == PR_FALSE) { + fprintf(stderr, "addr should be unspecified address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv6 INADDRANY: %s\n", buf); + } + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_IsNetAddrType(&addr, PR_IpAddrLoopback) == PR_FALSE) { + fprintf(stderr, "addr should be loopback address\n"); + exit(1); + } + { + char buf[256]; + PR_NetAddrToString(&addr, buf, 256); + printf("IPv6 LOOPBACK: %s\n", buf); + } + { + PRIPv6Addr v6addr; + char tmp_buf[256]; + + PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET, 0, &addr); + + PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &v6addr); + PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr); + addr.ipv6.ip = v6addr; + PR_NetAddrToString(&addr, tmp_buf, 256); + printf("IPv4-mapped IPv6 LOOPBACK: %s\n", tmp_buf); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/getproto.c b/src/libs/xpcom18a4/nsprpub/pr/tests/getproto.c new file mode 100644 index 00000000..7381bbd8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/getproto.c @@ -0,0 +1,114 @@ +/* -*- 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 ***** */ + +/* + ************************************************************************* + * + * File: getproto.c + * + * A test program for PR_GetProtoByName and PR_GetProtoByNumber + * + ************************************************************************* + */ + +#include "plstr.h" +#include "plerror.h" +#include "prinit.h" +#include "prprf.h" +#include "prnetdb.h" +#include "prerror.h" + +int main() +{ + PRFileDesc *prstderr = PR_GetSpecialFD(PR_StandardError); + PRBool failed = PR_FALSE; + PRProtoEnt proto; + char buf[2048]; + PRStatus rv; + + PR_STDIO_INIT(); + rv = PR_GetProtoByName("tcp", buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByName failed"); + } + else if (6 != proto.p_num) { + PR_fprintf( + prstderr,"tcp is usually 6, but is %d on this machine\n", + proto.p_num); + } + else PR_fprintf(prstderr, "tcp is protocol number %d\n", proto.p_num); + + rv = PR_GetProtoByName("udp", buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByName failed"); + } + else if (17 != proto.p_num) { + PR_fprintf( + prstderr, "udp is usually 17, but is %d on this machine\n", + proto.p_num); + } + else PR_fprintf(prstderr, "udp is protocol number %d\n", proto.p_num); + + rv = PR_GetProtoByNumber(6, buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByNumber failed"); + } + else if (PL_strcmp("tcp", proto.p_name)) { + PR_fprintf( + prstderr, "Protocol number 6 is usually tcp, but is %s" + " on this platform\n", proto.p_name); + } + else PR_fprintf(prstderr, "Protocol number 6 is %s\n", proto.p_name); + + rv = PR_GetProtoByNumber(17, buf, sizeof(buf), &proto); + if (PR_FAILURE == rv) { + failed = PR_TRUE; + PL_FPrintError(prstderr, "PR_GetProtoByNumber failed"); + } + else if (PL_strcmp("udp", proto.p_name)) { + PR_fprintf( + prstderr, "Protocol number 17 is usually udp, but is %s" + " on this platform\n", proto.p_name); + } + else PR_fprintf(prstderr, "Protocol number 17 is %s\n", proto.p_name); + + PR_fprintf(prstderr, (failed) ? "FAILED\n" : "PASSED\n"); + return (failed) ? 1 : 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/i2l.c b/src/libs/xpcom18a4/nsprpub/pr/tests/i2l.c new file mode 100644 index 00000000..4ff67bc0 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/i2l.c @@ -0,0 +1,133 @@ +/* -*- 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 + +#include "prio.h" +#include "prinit.h" +#include "prprf.h" +#include "prlong.h" + +#include "plerror.h" +#include "plgetopt.h" + +typedef union Overlay_i +{ + PRInt32 i; + PRInt64 l; +} Overlay_i; + +typedef union Overlay_u +{ + PRUint32 i; + PRUint64 l; +} Overlay_u; + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: -i n | -u n | -h\n"); + PR_fprintf(err, "\t-i n treat following number as signed integer\n"); + PR_fprintf(err, "\t-u n treat following number as unsigned integer\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + Overlay_i si; + Overlay_u ui; + PLOptStatus os; + PRBool bsi = PR_FALSE, bui = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "hi:u:"); + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'i': /* signed integer */ + si.i = (PRInt32)atoi(opt->value); + bsi = PR_TRUE; + break; + case 'u': /* unsigned */ + ui.i = (PRUint32)atoi(opt->value); + bui = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + +#if defined(HAVE_LONG_LONG) + PR_fprintf(err, "We have long long\n"); +#else + PR_fprintf(err, "We don't have long long\n"); +#endif + + if (bsi) + { + PR_fprintf(err, "Converting %ld: ", si.i); + LL_I2L(si.l, si.i); + PR_fprintf(err, "%lld\n", si.l); + } + + if (bui) + { + PR_fprintf(err, "Converting %lu: ", ui.i); + LL_I2L(ui.l, ui.i); + PR_fprintf(err, "%llu\n", ui.l); + } + return 0; + +} /* main */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + +/* i2l.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/initclk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/initclk.c new file mode 100644 index 00000000..ba306d20 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/initclk.c @@ -0,0 +1,108 @@ +/* -*- 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 is a regression test for the bug that the interval timer + * is not initialized when _PR_CreateCPU calls PR_IntervalNow. + * The bug would make this test program finish prematurely, + * when the SHORT_TIMEOUT period expires. The correct behavior + * is for the test to finish when the LONG_TIMEOUT period expires. + */ + +#include "prlock.h" +#include "prcvar.h" +#include "prthread.h" +#include "prinrval.h" +#include "prlog.h" +#include + +/* The timeouts, in milliseconds */ +#define SHORT_TIMEOUT 1000 +#define LONG_TIMEOUT 3000 + +PRLock *lock1, *lock2; +PRCondVar *cv1, *cv2; + +void ThreadFunc(void *arg) +{ + PR_Lock(lock1); + PR_WaitCondVar(cv1, PR_MillisecondsToInterval(SHORT_TIMEOUT)); + PR_Unlock(lock1); +} + +int main() +{ + PRThread *thread; + PRIntervalTime start, end; + PRUint32 elapsed_ms; + + lock1 = PR_NewLock(); + PR_ASSERT(NULL != lock1); + cv1 = PR_NewCondVar(lock1); + PR_ASSERT(NULL != cv1); + lock2 = PR_NewLock(); + PR_ASSERT(NULL != lock2); + cv2 = PR_NewCondVar(lock2); + PR_ASSERT(NULL != cv2); + start = PR_IntervalNow(); + thread = PR_CreateThread( + PR_USER_THREAD, + ThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + PR_ASSERT(NULL != thread); + PR_Lock(lock2); + PR_WaitCondVar(cv2, PR_MillisecondsToInterval(LONG_TIMEOUT)); + PR_Unlock(lock2); + PR_JoinThread(thread); + end = PR_IntervalNow(); + elapsed_ms = PR_IntervalToMilliseconds((PRIntervalTime)(end - start)); + /* Allow 100ms imprecision */ + if (elapsed_ms < LONG_TIMEOUT - 100 || elapsed_ms > LONG_TIMEOUT + 100) { + printf("Elapsed time should be %u ms but is %u ms\n", + LONG_TIMEOUT, elapsed_ms); + printf("FAIL\n"); + exit(1); + } + printf("Elapsed time: %u ms, expected time: %u ms\n", + LONG_TIMEOUT, elapsed_ms); + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/inrval.c b/src/libs/xpcom18a4/nsprpub/pr/tests/inrval.c new file mode 100644 index 00000000..b057c685 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/inrval.c @@ -0,0 +1,242 @@ +/* -*- 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 ***** */ + +/* +** file: inrval.c +** description: Interval conversion test. +** Modification History: +** 15-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +**/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#ifdef XP_MAC +#include "pralarm.h" +#else +#include "obsolete/pralarm.h" +#endif + +#include "prio.h" +#include "prprf.h" +#include "prlock.h" +#include "prlong.h" +#include "prcvar.h" +#include "prinrval.h" +#include "prtime.h" + +#include "plgetopt.h" + +#include +#include + +static PRIntn debug_mode; +static PRFileDesc *output; + + +static void TestConversions(void) +{ + PRIntervalTime ticks = PR_TicksPerSecond(); + + if (debug_mode) { + PR_fprintf(output, "PR_TicksPerSecond: %ld\n\n", ticks); + PR_fprintf(output, "PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1)); + PR_fprintf(output, "PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000)); + PR_fprintf(output, "PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000)); + + PR_fprintf(output, "PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3)); + PR_fprintf(output, "PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000)); + PR_fprintf(output, "PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000)); + + PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); + PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); + PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + + ticks *= 3; + PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); + PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); + PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); + } /*end debug mode */ +} /* TestConversions */ + +static void TestIntervalOverhead(void) +{ + /* Hopefully the optimizer won't delete this function */ + PRUint32 elapsed, per_call, loops = 1000000; + + PRIntervalTime timeout, timein = PR_IntervalNow(); + while (--loops > 0) + timeout = PR_IntervalNow(); + + elapsed = 1000U * PR_IntervalToMicroseconds(timeout - timein); + per_call = elapsed / 1000000U; + PR_fprintf( + output, "Overhead of 'PR_IntervalNow()' is %u nsecs\n\n", per_call); +} /* TestIntervalOverhead */ + +static void TestNowOverhead(void) +{ + PRTime timeout, timein; + PRInt32 overhead, loops = 1000000; + PRInt64 elapsed, per_call, ten23rd, ten26th; + + LL_I2L(ten23rd, 1000); + LL_I2L(ten26th, 1000000); + + timein = PR_Now(); + while (--loops > 0) + timeout = PR_Now(); + + LL_SUB(elapsed, timeout, timein); + LL_MUL(elapsed, elapsed, ten23rd); + LL_DIV(per_call, elapsed, ten26th); + LL_L2I(overhead, per_call); + PR_fprintf( + output, "Overhead of 'PR_Now()' is %u nsecs\n\n", overhead); +} /* TestNowOverhead */ + +static void TestIntervals(void) +{ + PRStatus rv; + PRUint32 delta; + PRInt32 seconds; + PRUint64 elapsed, thousand; + PRTime timein, timeout; + PRLock *ml = PR_NewLock(); + PRCondVar *cv = PR_NewCondVar(ml); + for (seconds = 0; seconds < 10; ++seconds) + { + PRIntervalTime ticks = PR_SecondsToInterval(seconds); + PR_Lock(ml); + timein = PR_Now(); + rv = PR_WaitCondVar(cv, ticks); + timeout = PR_Now(); + PR_Unlock(ml); + LL_SUB(elapsed, timeout, timein); + LL_I2L(thousand, 1000); + LL_DIV(elapsed, elapsed, thousand); + LL_L2UI(delta, elapsed); + if (debug_mode) PR_fprintf(output, + "TestIntervals: %swaiting %ld seconds took %ld msecs\n", + ((rv == PR_SUCCESS) ? "" : "FAILED "), seconds, delta); + } + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + if (debug_mode) PR_fprintf(output, "\n"); +} /* TestIntervals */ + +static PRIntn PR_CALLBACK RealMain(int argc, char** argv) +{ + PRUint32 vcpu, cpus = 0, loops = 1000; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + /* main test */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl:c:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'c': /* concurrency counter */ + cpus = atoi(opt->value); + break; + case 'l': /* loop counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + output = PR_GetSpecialFD(PR_StandardOutput); + PR_fprintf(output, "inrval: Examine stdout to determine results.\n"); + + if (cpus == 0) cpus = 8; + if (loops == 0) loops = 1000; + + if (debug_mode > 0) + { + PR_fprintf(output, "Inrval: Using %d loops\n", loops); + PR_fprintf(output, "Inrval: Using 1 and %d cpu(s)\n", cpus); + } + + for (vcpu = 1; vcpu <= cpus; vcpu += cpus - 1) + { + if (debug_mode) + PR_fprintf(output, "\nInrval: Using %d CPU(s)\n\n", vcpu); + PR_SetConcurrency(vcpu); + + TestNowOverhead(); + TestIntervalOverhead(); + TestConversions(); + TestIntervals(); + } + + return 0; +} + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/instrumt.c b/src/libs/xpcom18a4/nsprpub/pr/tests/instrumt.c new file mode 100644 index 00000000..f1577609 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/instrumt.c @@ -0,0 +1,507 @@ +/* -*- 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 ***** */ + +/* +** File: instrumt.c +** Description: This test is for the NSPR debug aids defined in +** prcountr.h, prtrace.h, prolock.h +** +** The test case tests the three debug aids in NSPR: +** +** Diagnostic messages can be enabled using "instrumt -v 6" +** This sets the msgLevel to something that PR_LOG() likes. +** Also define in the environment "NSPR_LOG_MODULES=Test:6" +** +** CounterTest() tests the counter facility. This test +** creates 4 threads. Each thread either increments, decrements, +** adds to or subtracts from a counter, depending on an argument +** passed to the thread at thread-create time. Each of these threads +** does COUNT_LIMIT iterations doing its thing. When all 4 threads +** are done, the result of the counter is evaluated. If all was atomic, +** the the value of the counter should be zero. +** +** TraceTest(): +** This test mingles with the counter test. Counters trace. +** A thread to extract trace entries on the fly is started. +** A thread to dump trace entries to a file is started. +** +** OrderedLockTest(): +** +** +** +** +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COUNT_LIMIT (10 * ( 1024)) + +#define SMALL_TRACE_BUFSIZE ( 60 * 1024 ) + +typedef enum +{ + CountLoop = 1, + TraceLoop = 2, + TraceFlow = 3 +} TraceTypes; + + +PRLogModuleLevel msgLevel = PR_LOG_ALWAYS; + +PRBool help = PR_FALSE; +PRBool failed = PR_FALSE; + + +PRLogModuleInfo *lm; +PRMonitor *mon; +PRInt32 activeThreads = 0; +PR_DEFINE_COUNTER( hCounter ); +PR_DEFINE_TRACE( hTrace ); + +static void Help(void) +{ + printf("Help? ... Ha!\n"); +} + +static void ListCounters(void) +{ + PR_DEFINE_COUNTER( qh ); + PR_DEFINE_COUNTER( rh ); + const char *qn, *rn, *dn; + const char **qname = &qn, **rname = &rn, **desc = &dn; + PRUint32 tCtr; + + PR_INIT_COUNTER_HANDLE( qh, NULL ); + PR_FIND_NEXT_COUNTER_QNAME(qh, qh ); + while ( qh != NULL ) + { + PR_INIT_COUNTER_HANDLE( rh, NULL ); + PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh ); + while ( rh != NULL ) + { + PR_GET_COUNTER_NAME_FROM_HANDLE( rh, qname, rname, desc ); + tCtr = PR_GET_COUNTER(tCtr, rh); + PR_LOG( lm, msgLevel, + ( "QName: %s RName: %s Desc: %s Value: %ld\n", + qn, rn, dn, tCtr )); + PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh ); + } + PR_FIND_NEXT_COUNTER_QNAME(qh, qh); + } + return; +} /* end ListCounters() */ + +static void ListTraces(void) +{ + PR_DEFINE_TRACE( qh ); + PR_DEFINE_TRACE( rh ); + const char *qn, *rn, *dn; + const char **qname = &qn, **rname = &rn, **desc = &dn; + + PR_INIT_TRACE_HANDLE( qh, NULL ); + PR_FIND_NEXT_TRACE_QNAME(qh, qh ); + while ( qh != NULL ) + { + PR_INIT_TRACE_HANDLE( rh, NULL ); + PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh ); + while ( rh != NULL ) + { + PR_GET_TRACE_NAME_FROM_HANDLE( rh, qname, rname, desc ); + PR_LOG( lm, msgLevel, + ( "QName: %s RName: %s Desc: %s", + qn, rn, dn )); + PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh ); + } + PR_FIND_NEXT_TRACE_QNAME(qh, qh); + } + return; +} /* end ListCounters() */ + + +static PRInt32 one = 1; +static PRInt32 two = 2; +static PRInt32 three = 3; +static PRInt32 four = 4; + +/* +** Thread to iteratively count something. +*/ +static void PR_CALLBACK CountSomething( void *arg ) +{ + PRInt32 switchVar = *((PRInt32 *)arg); + PRInt32 i; + + PR_LOG( lm, msgLevel, + ("CountSomething: begin thread %ld", switchVar )); + + for ( i = 0; i < COUNT_LIMIT ; i++) + { + switch ( switchVar ) + { + case 1 : + PR_INCREMENT_COUNTER( hCounter ); + break; + case 2 : + PR_DECREMENT_COUNTER( hCounter ); + break; + case 3 : + PR_ADD_TO_COUNTER( hCounter, 1 ); + break; + case 4 : + PR_SUBTRACT_FROM_COUNTER( hCounter, 1 ); + break; + default : + PR_ASSERT( 0 ); + break; + } + PR_TRACE( hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0 ); + } /* end for() */ + + PR_LOG( lm, msgLevel, + ("CounterSomething: end thread %ld", switchVar )); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + return; +} /* end CountSomething() */ + +/* +** Create the counter threads. +*/ +static void CounterTest( void ) +{ + PRThread *t1, *t2, *t3, *t4; + PRIntn i = 0; + PR_DEFINE_COUNTER( tc ); + PR_DEFINE_COUNTER( zCounter ); + + PR_LOG( lm, msgLevel, + ("Begin CounterTest")); + + /* + ** Test Get and Set of a counter. + ** + */ + PR_CREATE_COUNTER( zCounter, "Atomic", "get/set test", "test get and set of counter" ); + PR_SET_COUNTER( zCounter, 9 ); + PR_GET_COUNTER( i, zCounter ); + if ( i != 9 ) + { + failed = PR_TRUE; + PR_LOG( lm, msgLevel, + ("Counter set/get failed")); + } + + activeThreads += 4; + PR_CREATE_COUNTER( hCounter, "Atomic", "SMP Tests", "test atomic nature of counter" ); + + PR_GET_COUNTER_HANDLE_FROM_NAME( tc, "Atomic", "SMP Tests" ); + PR_ASSERT( tc == hCounter ); + + t1 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &one, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + + t2 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &two, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + t3 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &three, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t3); + + t4 = PR_CreateThread(PR_USER_THREAD, + CountSomething, &four, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t4); + + PR_LOG( lm, msgLevel, + ("Counter Threads started")); + + ListCounters(); + return; +} /* end CounterTest() */ + +/* +** Thread to dump trace buffer to a file. +*/ +static void PR_CALLBACK RecordTrace(void *arg ) +{ + PR_RECORD_TRACE_ENTRIES(); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + return; +} /* end RecordTrace() */ + + + +#define NUM_TRACE_RECORDS ( 10000 ) +/* +** Thread to extract and print trace entries from the buffer. +*/ +static void PR_CALLBACK SampleTrace( void *arg ) +{ +#if defined(DEBUG) || defined(FORCE_NSPR_TRACE) + PRInt32 found, rc; + PRTraceEntry *foundEntries; + PRInt32 i; + + foundEntries = (PRTraceEntry *)PR_Malloc( NUM_TRACE_RECORDS * sizeof(PRTraceEntry)); + PR_ASSERT(foundEntries != NULL ); + + do + { + rc = PR_GetTraceEntries( foundEntries, NUM_TRACE_RECORDS, &found); + PR_LOG( lm, msgLevel, + ("SampleTrace: Lost Data: %ld found: %ld", rc, found )); + + if ( found != 0) + { + for ( i = 0 ; i < found; i++ ) + { + PR_LOG( lm, msgLevel, + ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, UD2: %8.8ld", + (foundEntries +i)->thread, + (foundEntries +i)->time, + (foundEntries +i)->userData[0], + (foundEntries +i)->userData[1], + (foundEntries +i)->userData[2] )); + } + } + PR_Sleep(PR_MillisecondsToInterval(50)); + } + while( found != 0 && activeThreads >= 1 ); + + PR_Free( foundEntries ); + + PR_EnterMonitor(mon); + --activeThreads; + PR_Notify( mon ); + PR_ExitMonitor(mon); + + PR_LOG( lm, msgLevel, + ("SampleTrace(): exiting")); + +#endif + return; +} /* end RecordTrace() */ + +/* +** Basic trace test. +*/ +static void TraceTest( void ) +{ + PRInt32 i; + PRInt32 size; + PR_DEFINE_TRACE( th ); + PRThread *t1, *t2; + + PR_LOG( lm, msgLevel, + ("Begin TraceTest")); + + size = SMALL_TRACE_BUFSIZE; + PR_SET_TRACE_OPTION( PRTraceBufSize, &size ); + PR_GET_TRACE_OPTION( PRTraceBufSize, &i ); + + PR_CREATE_TRACE( th, "TraceTest", "tt2", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt3", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt4", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt5", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt6", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt7", "A description for the trace test" ); + PR_CREATE_TRACE( th, "TraceTest", "tt8", "A description for the trace test" ); + + PR_CREATE_TRACE( th, "Trace Test", "tt0", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt1", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt2", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt3", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt4", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt5", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt6", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt7", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt8", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt9", "QName is Trace Test, not TraceTest" ); + PR_CREATE_TRACE( th, "Trace Test", "tt10", "QName is Trace Test, not TraceTest" ); + + + + activeThreads += 2; + t1 = PR_CreateThread(PR_USER_THREAD, + RecordTrace, NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t1); + + t2 = PR_CreateThread(PR_USER_THREAD, + SampleTrace, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + PR_ASSERT(t2); + + ListTraces(); + + PR_GET_TRACE_HANDLE_FROM_NAME( th, "TraceTest","tt1" ); + PR_ASSERT( th == hTrace ); + + PR_LOG( lm, msgLevel, + ("End TraceTest")); + return; +} /* end TraceTest() */ + + +/* +** Ordered lock test. +*/ +static void OrderedLockTest( void ) +{ + PR_LOG( lm, msgLevel, + ("Begin OrderedLockTest")); + + +} /* end OrderedLockTest() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ +#if defined(DEBUG) || defined(FORCE_NSPR_TRACE) + PRUint32 counter; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdv:"); + lm = PR_NewLogModule("Test"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* verbose mode */ + msgLevel = (PRLogModuleLevel)atol( opt->value); + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_CREATE_TRACE( hTrace, "TraceTest", "tt1", "A description for the trace test" ); + mon = PR_NewMonitor(); + PR_EnterMonitor( mon ); + + TraceTest(); + CounterTest(); + OrderedLockTest(); + + /* Wait for all threads to exit */ + while ( activeThreads > 0 ) { + if ( activeThreads == 1 ) + PR_SET_TRACE_OPTION( PRTraceStopRecording, NULL ); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + PR_GET_COUNTER( counter, hCounter ); + } + PR_ExitMonitor( mon ); + + /* + ** Evaluate results + */ + PR_GET_COUNTER( counter, hCounter ); + if ( counter != 0 ) + { + failed = PR_TRUE; + PR_LOG( lm, msgLevel, + ("Expected counter == 0, found: %ld", counter)); + printf("FAIL\n"); + } + else + { + printf("PASS\n"); + } + + + PR_DESTROY_COUNTER( hCounter ); + + PR_DestroyMonitor( mon ); + + PR_TRACE( hTrace, TraceFlow, 0xfff,0,0,0,0,0,0); + PR_DESTROY_TRACE( hTrace ); +#else + printf("Test not defined\n"); +#endif + return 0; +} /* main() */ +/* end instrumt.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/intrio.c b/src/libs/xpcom18a4/nsprpub/pr/tests/intrio.c new file mode 100644 index 00000000..e1dcf661 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/intrio.c @@ -0,0 +1,169 @@ +/* -*- 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) 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 ***** */ + +/* + * File: intrio.c + * Purpose: testing i/o interrupts (see Bugzilla bug #31120) + */ + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +/* for synchronization between the main thread and iothread */ +static PRLock *lock; +static PRCondVar *cvar; +static PRBool iothread_ready; + +static void PR_CALLBACK AbortIO(void *arg) +{ + PRStatus rv; + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt((PRThread*)arg); + PR_ASSERT(PR_SUCCESS == rv); +} /* AbortIO */ + +static void PR_CALLBACK IOThread(void *arg) +{ + PRFileDesc *sock, *newsock; + PRNetAddr addr; + + sock = PR_OpenTCPSocket(PR_AF_INET6); + if (sock == NULL) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + /* tell the main thread that we are ready */ + PR_Lock(lock); + iothread_ready = PR_TRUE; + PR_NotifyCondVar(cvar); + PR_Unlock(lock); + newsock = PR_Accept(sock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (newsock != NULL) { + fprintf(stderr, "PR_Accept shouldn't have succeeded\n"); + exit(1); + } + if (PR_GetError() != PR_PENDING_INTERRUPT_ERROR) { + fprintf(stderr, "PR_Accept failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("PR_Accept() is interrupted as expected\n"); + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void Test(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *iothread, *abortio; + + printf("A %s thread will be interrupted by a %s thread\n", + (scope1 == PR_LOCAL_THREAD ? "local" : "global"), + (scope2 == PR_LOCAL_THREAD ? "local" : "global")); + iothread_ready = PR_FALSE; + iothread = PR_CreateThread( + PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL, + scope1, PR_JOINABLE_THREAD, 0); + if (iothread == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + PR_Lock(lock); + while (!iothread_ready) + PR_WaitCondVar(cvar, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(lock); + abortio = PR_CreateThread( + PR_USER_THREAD, AbortIO, iothread, PR_PRIORITY_NORMAL, + scope2, PR_JOINABLE_THREAD, 0); + if (abortio == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + if (PR_JoinThread(iothread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(abortio) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } +} + +PRIntn main(PRIntn argc, char **argv) +{ + PR_STDIO_INIT(); + lock = PR_NewLock(); + if (lock == NULL) { + fprintf(stderr, "PR_NewLock failed\n"); + exit(1); + } + cvar = PR_NewCondVar(lock); + if (cvar == NULL) { + fprintf(stderr, "PR_NewCondVar failed\n"); + exit(1); + } + /* test all four combinations */ + Test(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + Test(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + Test(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + Test(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + printf("PASSED\n"); + return 0; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/intrupt.c b/src/libs/xpcom18a4/nsprpub/pr/tests/intrupt.c new file mode 100644 index 00000000..f6f38105 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/intrupt.c @@ -0,0 +1,373 @@ +/* -*- 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 ***** */ + +/* + * File: intrupt.c + * Purpose: testing thread interrupts + */ + +#include "plgetopt.h" +#include "prcvar.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prtypes.h" +#include "prnetdb.h" + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define DEFAULT_TCP_PORT 12500 + +static PRLock *ml = NULL; +static PRCondVar *cv = NULL; + +static PRBool passed = PR_TRUE; +static PRBool debug_mode = PR_FALSE; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +static void PR_CALLBACK AbortCV(void *arg) +{ + PRStatus rv; + PRThread *me = PR_CurrentThread(); + + /* some other thread (main) is doing the interrupt */ + PR_Lock(ml); + rv = PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + if (debug_mode) printf( "Expected interrupt on wait CV and "); + if (PR_FAILURE == rv) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("got random error\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("got a successful completion\n"); + passed = PR_FALSE; + } + + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf( + "Expected success on wait CV and %s\n", + (PR_SUCCESS == rv) ? "got it" : "failed"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + /* interrupt myself, then clear */ + PR_Interrupt(me); + PR_ClearInterrupt(); + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf("Expected success on wait CV and "); + if (PR_FAILURE == rv) + { + printf( + "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? + "got interrupted" : "a random failure"); + } + printf("got it\n"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + /* set, then wait - interrupt - then wait again */ + PR_Interrupt(me); + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) printf( "Expected interrupt on wait CV and "); + if (PR_FAILURE == rv) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("got a successful completion\n"); + passed = PR_FALSE; + } + + rv = PR_WaitCondVar(cv, 10); + if (debug_mode) + { + printf( + "Expected success on wait CV and %s\n", + (PR_SUCCESS == rv) ? "got it" : "failed"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + PR_Unlock(ml); + +} /* AbortCV */ + +static void PR_CALLBACK AbortIO(void *arg) +{ + PRStatus rv; + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt((PRThread*)arg); + PR_ASSERT(PR_SUCCESS == rv); +} /* AbortIO */ + +static void PR_CALLBACK AbortJoin(void *arg) +{ +} /* AbortJoin */ + +static void setup_listen_socket(PRFileDesc **listner, PRNetAddr *netaddr) +{ + PRStatus rv; + PRInt16 port = DEFAULT_TCP_PORT; + + *listner = PR_NewTCPSocket(); + PR_ASSERT(*listner != NULL); + memset(netaddr, 0, sizeof(*netaddr)); + (*netaddr).inet.ip = PR_htonl(PR_INADDR_ANY); + (*netaddr).inet.family = PR_AF_INET; + do + { + (*netaddr).inet.port = PR_htons(port); + rv = PR_Bind(*listner, netaddr); + port += 1; + PR_ASSERT(port < (DEFAULT_TCP_PORT + 10)); + } while (PR_FAILURE == rv); + + rv = PR_Listen(*listner, 5); + + if (PR_GetSockName(*listner, netaddr) < 0) { + if (debug_mode) printf("intrupt: ERROR - PR_GetSockName failed\n"); + passed = PR_FALSE; + return; + } + +} + +static void PR_CALLBACK IntrBlock(void *arg) +{ + PRStatus rv; + PRNetAddr netaddr; + PRFileDesc *listner; + + /* some other thread (main) is doing the interrupt */ + /* block the interrupt */ + PR_BlockInterrupt(); + PR_Lock(ml); + rv = PR_WaitCondVar(cv, PR_SecondsToInterval(4)); + PR_Unlock(ml); + if (debug_mode) + { + printf("Expected success on wait CV and "); + if (PR_FAILURE == rv) + { + printf( + "%s\n", (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) ? + "got interrupted" : "got a random failure"); + } else + printf("got it\n"); + } + passed = ((PR_TRUE == passed) && (PR_SUCCESS == rv)) ? PR_TRUE : PR_FALSE; + + setup_listen_socket(&listner, &netaddr); + PR_UnblockInterrupt(); + if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) + { + PRInt32 error = PR_GetError(); + if (debug_mode) printf("Expected interrupt on PR_Accept() and "); + if (PR_PENDING_INTERRUPT_ERROR == error) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); + passed = PR_FALSE; + } + + (void)PR_Close(listner); listner = NULL; +} /* TestIntrBlock */ + +void PR_CALLBACK Intrupt(void *arg) +{ + PRStatus rv; + PRNetAddr netaddr; + PRFileDesc *listner; + PRThread *abortCV, *abortIO, *abortJoin, *intrBlock; + + ml = PR_NewLock(); + cv = PR_NewCondVar(ml); + +#ifdef XP_MAC + SetupMacPrintfLog("intrupt.log"); + debug_mode = PR_TRUE; +#endif + + /* Part I */ + if (debug_mode) printf("Part I\n"); + abortCV = PR_CreateThread( + PR_USER_THREAD, AbortCV, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt(abortCV); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(abortCV); + PR_ASSERT(PR_SUCCESS == rv); + + /* Part II */ + if (debug_mode) printf("Part II\n"); + abortJoin = PR_CreateThread( + PR_USER_THREAD, AbortJoin, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + PR_Sleep(PR_SecondsToInterval(2)); + if (debug_mode) printf("Expecting to interrupt an exited thread "); + rv = PR_Interrupt(abortJoin); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(abortJoin); + PR_ASSERT(PR_SUCCESS == rv); + if (debug_mode) printf("and succeeded\n"); + + /* Part III */ + if (debug_mode) printf("Part III\n"); + setup_listen_socket(&listner, &netaddr); + abortIO = PR_CreateThread( + PR_USER_THREAD, AbortIO, PR_CurrentThread(), PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + if (PR_Accept(listner, &netaddr, PR_INTERVAL_NO_TIMEOUT) == NULL) + { + PRInt32 error = PR_GetError(); + if (debug_mode) printf("Expected interrupt on PR_Accept() and "); + if (PR_PENDING_INTERRUPT_ERROR == error) + { + if (debug_mode) printf("got it\n"); + } + else + { + if (debug_mode) printf("failed\n"); + passed = PR_FALSE; + } + } + else + { + if (debug_mode) printf("Failed to interrupt PR_Accept()\n"); + passed = PR_FALSE; + } + + (void)PR_Close(listner); listner = NULL; + + rv = PR_JoinThread(abortIO); + PR_ASSERT(PR_SUCCESS == rv); + /* Part VI */ + if (debug_mode) printf("Part VI\n"); + intrBlock = PR_CreateThread( + PR_USER_THREAD, IntrBlock, 0, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Sleep(PR_SecondsToInterval(2)); + rv = PR_Interrupt(intrBlock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(intrBlock); + PR_ASSERT(PR_SUCCESS == rv); + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); +} /* Intrupt */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRThread *intrupt; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dG"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + intrupt = PR_CreateThread( + PR_USER_THREAD, Intrupt, NULL, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (intrupt == NULL) { + fprintf(stderr, "cannot create thread\n"); + passed = PR_FALSE; + } else { + PRStatus rv; + rv = PR_JoinThread(intrupt); + PR_ASSERT(rv == PR_SUCCESS); + } + printf("%s\n", ((passed) ? "PASSED" : "FAILED")); + return ((passed) ? 0 : 1); +} /* main */ + +/* intrupt.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeout.c b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeout.c new file mode 100644 index 00000000..2a680aa5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeout.c @@ -0,0 +1,299 @@ +/* -*- 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 ***** */ + +/* +** Test socket IO timeouts +** +** +** +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; + +PRIntn failed_already = 0; +PRIntn debug_mode = 0; + +#define LOCAL_SCOPE_STRING "LOCAL scope" +#define GLOBAL_SCOPE_STRING "GLOBAL scope" +#define GLOBAL_BOUND_SCOPE_STRING "GLOBAL_BOUND scope" + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + PRThreadScope tscope; + char *scope_str; + + + if (debug_mode) + printf("thread %d is alive\n", info->id); + tscope = PR_GetThreadScope(PR_GetCurrentThread()); + + switch(tscope) { + case PR_LOCAL_THREAD: + scope_str = LOCAL_SCOPE_STRING; + break; + case PR_GLOBAL_THREAD: + scope_str = GLOBAL_SCOPE_STRING; + break; + case PR_GLOBAL_BOUND_THREAD: + scope_str = GLOBAL_BOUND_SCOPE_STRING; + break; + default: + PR_ASSERT(!"Invalid thread scope"); + break; + } + printf("thread id %d, scope %s\n", info->id, scope_str); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) + printf("unable to create listen socket\n"); + failed_already=1; + goto dead; + } + + listenAddr.inet.family = PR_AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) + printf("unable to bind\n"); + failed_already=1; + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) + printf("unable to listen\n"); + failed_already=1; + goto dead; + } + + if (debug_mode) + printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) { + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST PASSED! PR_Accept() returned error %d\n", + PR_IO_TIMEOUT_ERROR); + } + } else { + if (debug_mode) + printf("TEST FAILED! PR_Accept() returned error %d\n", + PR_GetError()); + failed_already=1; + } + } else { + if (debug_mode) + printf ("TEST FAILED! PR_Accept() succeeded?\n"); + failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) + printf("thread %d is dead\n", info->id); + + PR_Free(info); +} + +void +thread_test(PRThreadScope scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) + printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)PR_Malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + printf("Failed to create thread, error = %d(%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) + printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); + + PR_DestroyCondVar(dead_cv); + PR_DestroyLock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads = 0; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name [-d] [-t ] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 't': /* threads to involve */ + num_threads = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (0 == num_threads) + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("io_timeout.log"); + debug_mode = 1; +#endif + + printf("test with global bound thread\n"); + thread_test(PR_GLOBAL_BOUND_THREAD, num_threads); + + printf("test with local thread\n"); + thread_test(PR_LOCAL_THREAD, num_threads); + + printf("test with global thread\n"); + thread_test(PR_GLOBAL_THREAD, num_threads); + + PR_Cleanup(); + + if (failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutk.c new file mode 100644 index 00000000..26e3beeb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutk.c @@ -0,0 +1,233 @@ +/* -*- 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 ***** */ + +/* +** name io_timeoutk.c +** Description:Test socket IO timeouts (kernel level) +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; + +PRIntn failed_already=0; +PRIntn debug_mode; + + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + + if (debug_mode) printf("thread %d is alive\n", info->id); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) printf("unable to create listen socket\n"); + goto dead; + } + + listenAddr.inet.family = AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to bind\n"); + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to listen\n"); + goto dead; + } + + if (debug_mode) printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept(listenSock, &clientAddr, PR_SecondsToInterval(info->accept_timeout +info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST FAILED! PR_Accept() returned error %d\n", + PR_GetError()); + } + else failed_already=1; + } else { + if (debug_mode) printf ("TEST FAILED! PR_Accept() succeeded?\n"); + else failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) printf("thread %d is dead\n", info->id); +} + +void +thread_test(PRInt32 scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (argc > 2) + num_threads = atoi(argv[2]); + else + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + + if (debug_mode) printf("kernel level test\n"); + thread_test(PR_GLOBAL_THREAD, num_threads); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutu.c b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutu.c new file mode 100644 index 00000000..c17a93f7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/io_timeoutu.c @@ -0,0 +1,234 @@ +/* -*- 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 ***** */ + + +/* +** name io_timeoutu.c +** Description: Test socket IO timeouts (user level) +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include +#include "nspr.h" + +#define NUM_THREADS 1 +#define BASE_PORT 8000 +#define DEFAULT_ACCEPT_TIMEOUT 2 + +typedef struct threadInfo { + PRInt16 id; + PRInt16 accept_timeout; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 *alive; +} threadInfo; +PRIntn failed_already=0; +PRIntn debug_mode; + +void +thread_main(void *_info) +{ + threadInfo *info = (threadInfo *)_info; + PRNetAddr listenAddr; + PRNetAddr clientAddr; + PRFileDesc *listenSock = NULL; + PRFileDesc *clientSock; + PRStatus rv; + + if (debug_mode) printf("thread %d is alive\n", info->id); + + listenSock = PR_NewTCPSocket(); + if (!listenSock) { + if (debug_mode) printf("unable to create listen socket\n"); + goto dead; + } + + listenAddr.inet.family = AF_INET; + listenAddr.inet.port = PR_htons(BASE_PORT + info->id); + listenAddr.inet.ip = PR_htonl(INADDR_ANY); + rv = PR_Bind(listenSock, &listenAddr); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to bind\n"); + goto dead; + } + + rv = PR_Listen(listenSock, 4); + if (rv == PR_FAILURE) { + if (debug_mode) printf("unable to listen\n"); + goto dead; + } + + if (debug_mode) printf("thread %d going into accept for %d seconds\n", + info->id, info->accept_timeout + info->id); + + clientSock = PR_Accept( + listenSock, &clientAddr, PR_SecondsToInterval( + info->accept_timeout + info->id)); + + if (clientSock == NULL) { + if (PR_GetError() == PR_IO_TIMEOUT_ERROR) + if (debug_mode) { + printf("PR_Accept() timeout worked!\n"); + printf("TEST FAILED! PR_Accept() returned error %d\n", + } + PR_GetError()); + else failed_already=1; + } else { + if (debug_mode) printf ("TEST FAILED! PR_Accept() succeeded?\n"); + else failed_already=1; + PR_Close(clientSock); + } + +dead: + if (listenSock) { + PR_Close(listenSock); + } + PR_Lock(info->dead_lock); + (*info->alive)--; + PR_NotifyCondVar(info->dead_cv); + PR_Unlock(info->dead_lock); + + if (debug_mode) printf("thread %d is dead\n", info->id); +} + +void +thread_test(PRInt32 scope, PRInt32 num_threads) +{ + PRInt32 index; + PRThread *thr; + PRLock *dead_lock; + PRCondVar *dead_cv; + PRInt32 alive; + + if (debug_mode) printf("IO Timeout test started with %d threads\n", num_threads); + + dead_lock = PR_NewLock(); + dead_cv = PR_NewCondVar(dead_lock); + alive = num_threads; + + for (index = 0; index < num_threads; index++) { + threadInfo *info = (threadInfo *)malloc(sizeof(threadInfo)); + + info->id = index; + info->dead_lock = dead_lock; + info->dead_cv = dead_cv; + info->alive = &alive; + info->accept_timeout = DEFAULT_ACCEPT_TIMEOUT; + + thr = PR_CreateThread( PR_USER_THREAD, + thread_main, + (void *)info, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0); + + if (!thr) { + PR_Lock(dead_lock); + alive--; + PR_Unlock(dead_lock); + } + } + + PR_Lock(dead_lock); + while(alive) { + if (debug_mode) printf("main loop awake; alive = %d\n", alive); + PR_WaitCondVar(dead_cv, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(dead_lock); +} + +int main(int argc, char **argv) +{ + PRInt32 num_threads; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + if (argc > 2) + num_threads = atoi(argv[2]); + else + num_threads = NUM_THREADS; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_LOW, 0); + PR_STDIO_INIT(); + + if (debug_mode) printf("user level test\n"); + thread_test(PR_LOCAL_THREAD, num_threads); + + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; + + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ioconthr.c b/src/libs/xpcom18a4/nsprpub/pr/tests/ioconthr.c new file mode 100644 index 00000000..2e39522d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ioconthr.c @@ -0,0 +1,146 @@ +/* -*- 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 is a test for the io continuation thread machinery + * in pthreads. + */ + +#include "nspr.h" +#include + +int num_threads = 10; /* must be an even number */ +PRThreadScope thread_scope = PR_GLOBAL_THREAD; + +void ThreadFunc(void *arg) +{ + PRFileDesc *fd = (PRFileDesc *) arg; + char buf[1024]; + PRInt32 nbytes; + PRErrorCode err; + + nbytes = PR_Recv(fd, buf, sizeof(buf), 0, PR_SecondsToInterval(20)); + if (nbytes == -1) { + err = PR_GetError(); + if (err != PR_PENDING_INTERRUPT_ERROR) { + fprintf(stderr, "PR_Recv failed: (%d, %d)\n", + err, PR_GetOSError()); + PR_ProcessExit(1); + } + /* + * After getting an I/O interrupt, this thread must + * close the fd before it exits due to a limitation + * of our NT implementation. + */ + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + PR_ProcessExit(1); + } + } else { + fprintf(stderr, "PR_Recv received %d bytes!?\n", nbytes); + PR_ProcessExit(1); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc **fds; + PRThread **threads; + PRIntervalTime start, elapsed; + int index; + + fds = (PRFileDesc **) PR_MALLOC(2 * num_threads * sizeof(PRFileDesc *)); + PR_ASSERT(fds != NULL); + threads = (PRThread **) PR_MALLOC(num_threads * sizeof(PRThread *)); + PR_ASSERT(threads != NULL); + + for (index = 0; index < num_threads; index++) { + if (PR_NewTCPSocketPair(&fds[2 * index]) == PR_FAILURE) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + PR_ProcessExit(1); + } + threads[index] = PR_CreateThread( + PR_USER_THREAD, ThreadFunc, fds[2 * index], + PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == threads[index]) { + fprintf(stderr, "PR_CreateThread failed\n"); + PR_ProcessExit(1); + } + } + + /* Let the threads block in PR_Recv */ + PR_Sleep(PR_SecondsToInterval(2)); + + printf("Interrupting the threads\n"); + fflush(stdout); + start = PR_IntervalNow(); + for (index = 0; index < num_threads; index++) { + if (PR_Interrupt(threads[index]) == PR_FAILURE) { + fprintf(stderr, "PR_Interrupt failed\n"); + PR_ProcessExit(1); + } + } + for (index = 0; index < num_threads; index++) { + if (PR_JoinThread(threads[index]) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + PR_ProcessExit(1); + } + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start); + printf("Threads terminated in %d milliseconds\n", + PR_IntervalToMilliseconds(elapsed)); + fflush(stdout); + + /* We are being very generous and allow 10 seconds. */ + if (elapsed >= PR_SecondsToInterval(10)) { + fprintf(stderr, "Interrupting threads took longer than 10 seconds!!\n"); + PR_ProcessExit(1); + } + + for (index = 0; index < num_threads; index++) { + /* fds[2 * index] was passed to and closed by threads[index]. */ + if (PR_Close(fds[2 * index + 1]) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + PR_ProcessExit(1); + } + } + PR_DELETE(threads); + PR_DELETE(fds); + printf("PASS\n"); + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ipv6.c b/src/libs/xpcom18a4/nsprpub/pr/tests/ipv6.c new file mode 100644 index 00000000..742239ae --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ipv6.c @@ -0,0 +1,248 @@ +/* -*- 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 "prio.h" +#include "prenv.h" +#include "prmem.h" +#include "prlink.h" +#include "prsystem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prvrsion.h" + +#include "plerror.h" +#include "plgetopt.h" +#include "obsolete/probslet.h" + +#include + +#define DNS_BUFFER 100 +#define ADDR_BUFFER 100 +#define HOST_BUFFER 1024 +#define PROTO_BUFFER 1500 + +#define NETADDR_SIZE(addr) \ + (PR_AF_INET == (addr)->raw.family ? \ + sizeof((addr)->inet) : sizeof((addr)->ipv6)) + +static PRFileDesc *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-V] [-h]\n"); + PR_fprintf(err, "\t Name of host to lookup (default: self)\n"); + PR_fprintf(err, "\t-V Display runtime version info (default: FALSE)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static void DumpAddr(const PRNetAddr* address, const char *msg) +{ + PRUint32 *word = (PRUint32*)address; + PRUint32 addr_len = sizeof(PRNetAddr); + PR_fprintf(err, "%s[%d]\t", msg, NETADDR_SIZE(address)); + while (addr_len > 0) + { + PR_fprintf(err, " %08x", *word++); + addr_len -= sizeof(PRUint32); + } + PR_fprintf(err, "\n"); +} /* DumpAddr */ + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + PRNetAddr translation; + char buffer[ADDR_BUFFER]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_NetAddrToString"); + else + { + PR_fprintf(err, "\t%s\n", buffer); + memset(&translation, 0, sizeof(translation)); + rv = PR_StringToNetAddr(buffer, &translation); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_StringToNetAddr"); + else + { + PRSize addr_len = NETADDR_SIZE(address); + if (0 != memcmp(address, &translation, addr_len)) + { + PR_fprintf(err, "Address translations do not match\n"); + DumpAddr(address, "original"); + DumpAddr(&translation, "translate"); + rv = PR_FAILURE; + } + } + } + return rv; +} /* PrintAddress */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRHostEnt host; + PRProtoEnt proto; + const char *name = NULL; + PRBool failed = PR_FALSE, version = PR_FALSE; + PLOptState *opt = PL_CreateOptState(argc, argv, "Vh"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of host to lookup */ + name = opt->value; + break; + case 'V': /* Do version discovery */ + version = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (version) + { +#if defined(WINNT) +#define NSPR_LIB "libnspr4" +#else +#define NSPR_LIB "nspr4" +#endif + const PRVersionDescription *version_info; + char *nspr_path = PR_GetEnv("LD_LIBRARY_PATH"); + char *nspr_name = PR_GetLibraryName(nspr_path, NSPR_LIB); + PRLibrary *runtime = PR_LoadLibrary(nspr_name); + if (NULL == runtime) + PL_FPrintError(err, "PR_LoadLibrary"); + else + { + versionEntryPointType versionPoint = (versionEntryPointType) + PR_FindSymbol(runtime, "libVersionPoint"); + if (NULL == versionPoint) + PL_FPrintError(err, "PR_FindSymbol"); + else + { + char buffer[100]; + PRExplodedTime exploded; + version_info = versionPoint(); + (void)PR_fprintf(err, "Runtime library version information\n"); + PR_ExplodeTime( + version_info->buildTime, PR_GMTParameters, &exploded); + (void)PR_FormatTime( + buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded); + (void)PR_fprintf(err, " Build time: %s GMT\n", buffer); + (void)PR_fprintf( + err, " Build time: %s\n", version_info->buildTimeString); + (void)PR_fprintf( + err, " %s V%u.%u.%u (%s%s%s)\n", + version_info->description, + version_info->vMajor, + version_info->vMinor, + version_info->vPatch, + (version_info->beta ? " beta " : ""), + (version_info->debug ? " debug " : ""), + (version_info->special ? " special" : "")); + (void)PR_fprintf(err, " filename: %s\n", version_info->filename); + (void)PR_fprintf(err, " security: %s\n", version_info->security); + (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright); + (void)PR_fprintf(err, " comment: %s\n", version_info->comment); + } + } + if (NULL != nspr_name) PR_FreeLibraryName(nspr_name); + } + + { + if (NULL == name) + { + char *me = (char*)PR_MALLOC(DNS_BUFFER); + rv = PR_GetSystemInfo(PR_SI_HOSTNAME, me, DNS_BUFFER); + if (PR_FAILURE == rv) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_GetSystemInfo"); + return 2; + } + name = me; /* just leak the storage */ + } + } + + { + char buffer[HOST_BUFFER]; + PR_fprintf(err, "Translating the name %s ...", name); + + rv = PR_GetHostByName(name, buffer, sizeof(buffer), &host); + if (PR_FAILURE == rv) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_GetHostByName"); + } + else + { + PRIntn index = 0; + PRNetAddr address; + memset(&address, 0, sizeof(PRNetAddr)); + PR_fprintf(err, "success .. enumerating results\n"); + do + { + index = PR_EnumerateHostEnt(index, &host, 0, &address); + if (index > 0) PrintAddress(&address); + else if (-1 == index) + { + failed = PR_TRUE; + PL_FPrintError(err, "PR_EnumerateHostEnt"); + } + } while (index > 0); + } + } + + + { + char buffer[PROTO_BUFFER]; + /* + ** Get Proto by name/number + */ + rv = PR_GetProtoByName("tcp", &buffer[1], sizeof(buffer) - 1, &proto); + rv = PR_GetProtoByNumber(6, &buffer[3], sizeof(buffer) - 3, &proto); + } + + return (failed) ? 1 : 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/join.c b/src/libs/xpcom18a4/nsprpub/pr/tests/join.c new file mode 100644 index 00000000..73d7eb83 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/join.c @@ -0,0 +1,264 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); + exit (1); +} + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void PR_CALLBACK lowPriority(void *arg) +{ +} + +static void PR_CALLBACK highPriority(void *arg) +{ +} + +static void PR_CALLBACK unjoinable(void *arg) +{ + PR_Sleep(PR_INTERVAL_NO_TIMEOUT); +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else Test_Result(FAIL); + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else Test_Result(FAIL); + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else Test_Result (FAIL); + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +void joinWithUnjoinable(void) +{ + PRThread *thread; + + /* create the unjoinable thread */ + + thread = PR_CreateThread(PR_USER_THREAD, + unjoinable, 0, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (!thread) { + if (debug_mode) printf("\tcannot create unjoinable thread\n"); + else Test_Result(FAIL); + return; + } + + if (PR_JoinThread(thread) == PR_SUCCESS) { + if (debug_mode) printf("\tsuccessfully joined with unjoinable thread?!\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tcannot join with unjoinable thread, as expected\n"); + if (PR_GetError() != PR_INVALID_ARGUMENT_ERROR) { + if (debug_mode) printf("\tWrong error code\n"); + else Test_Result(FAIL); + return; + } + } + if (PR_Interrupt(thread) == PR_FAILURE) { + if (debug_mode) printf("\tcannot interrupt unjoinable thread\n"); + else Test_Result(FAIL); + return; + } else { + if (debug_mode) printf("\tinterrupted unjoinable thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC + SetupMacPrintfLog("join.log"); + debug_mode = 1; +#endif + + + + /* main test */ + printf("User-User test\n"); + runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + printf("User-Kernel test\n"); + runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + printf("Kernel-User test\n"); + runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + printf("Kernel-Kernel test\n"); + runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + printf("Join with unjoinable thread\n"); + joinWithUnjoinable(); + + printf("PASSED\n"); + + return 0; +} + + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/joinkk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/joinkk.c new file mode 100644 index 00000000..0fd991e5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/joinkk.c @@ -0,0 +1,193 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC + SetupMacPrintfLog("join.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("Kernel-Kernel test\n"); + runTest(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + +} + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/joinku.c b/src/libs/xpcom18a4/nsprpub/pr/tests/joinku.c new file mode 100644 index 00000000..ecaa24c9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/joinku.c @@ -0,0 +1,199 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Tests PR_SetMallocCountdown PR_ClearMallocCountdown functions. +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinku.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("Kernel-User test\n"); + runTest(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); + + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } + +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/joinuk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/joinuk.c new file mode 100644 index 00000000..1564731d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/joinuk.c @@ -0,0 +1,195 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: joinuk.c +** +** Description: Join kernel - user +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinuk.log"); +#endif + + + + /* main test */ + + if (debug_mode) printf("User-Kernel test\n"); + runTest(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); + + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } else + { + printf("PASS\n"); + return 0; + } +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/joinuu.c b/src/libs/xpcom18a4/nsprpub/pr/tests/joinuu.c new file mode 100644 index 00000000..ea0d2d70 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/joinuu.c @@ -0,0 +1,197 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: dbmalloc1.c +** +** Description: Join tests user - user +** +** Modification History: +** +** 19-May-97 AGarcia - separate the four join tests into different unit test modules. +** AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif +PRIntn failed_already=0; +PRIntn debug_mode; + + +/* + Program to test joining of threads. Two threads are created. One + to be waited upon until it has started. The other to join after it has + completed. +*/ + + +static void lowPriority(void *arg) +{ +} + +static void highPriority(void *arg) +{ +} + +void runTest(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *low,*high; + + /* create the low and high priority threads */ + + low = PR_CreateThread(PR_USER_THREAD, + lowPriority, 0, + PR_PRIORITY_LOW, + scope1, + PR_JOINABLE_THREAD, + 0); + if (!low) { + if (debug_mode) printf("\tcannot create low priority thread\n"); + else failed_already=1; + return; + } + + high = PR_CreateThread(PR_USER_THREAD, + highPriority, 0, + PR_PRIORITY_HIGH, + scope2, + PR_JOINABLE_THREAD, + 0); + if (!high) { + if (debug_mode) printf("\tcannot create high priority thread\n"); + else failed_already=1; + return; + } + + /* Do the joining for both threads */ + if (PR_JoinThread(low) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join low priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined low priority thread\n"); + } + if (PR_JoinThread(high) == PR_FAILURE) { + if (debug_mode) printf("\tcannot join high priority thread\n"); + else failed_already=1; + return; + } else { + if (debug_mode) printf("\tjoined high priority thread\n"); + } +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("joinuu.log"); +#endif + + + + /* main test */ + if (debug_mode) printf("User-User test\n"); + runTest(PR_LOCAL_THREAD, PR_LOCAL_THREAD); + + if(failed_already) + { + printf("FAIL\n"); + return 1; + } else + { + printf("PASS\n"); + return 0; + } + + +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/layer.c b/src/libs/xpcom18a4/nsprpub/pr/tests/layer.c new file mode 100644 index 00000000..7eae46a2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/layer.c @@ -0,0 +1,465 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "prlog.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" +#include "prwin16.h" + +#include + +/* +** Testing layering of I/O +** +** The layered server +** A thread that acts as a server. It creates a TCP listener with a dummy +** layer pushed on top. Then listens for incoming connections. Each connection +** request for connection will be layered as well, accept one request, echo +** it back and close. +** +** The layered client +** Pretty much what you'd expect. +*/ + +static PRFileDesc *logFile; +static PRDescIdentity identity; +static PRNetAddr server_address; + +static PRIOMethods myMethods; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRIntn minor_iterations = 5; +static PRIntn major_iterations = 1; +static Verbosity verbosity = quiet; +static PRUint16 default_port = 12273; + +static PRFileDesc *PushLayer(PRFileDesc *stack) +{ + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); + PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); + PR_ASSERT(PR_SUCCESS == rv); + return stack; +} /* PushLayer */ + +static PRFileDesc *PushNewLayers(PRFileDesc *stack) +{ + PRDescIdentity tmp_identity; + PRFileDesc *layer; + PRStatus rv; + + /* push a dummy layer */ + tmp_identity = PR_GetUniqueIdentity("Dummy 1"); + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + + /* push a data procesing layer */ + layer = PR_CreateIOLayerStub(identity, &myMethods); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + + /* push another dummy layer */ + tmp_identity = PR_GetUniqueIdentity("Dummy 2"); + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, + stack); + PR_ASSERT(PR_SUCCESS == rv); + return stack; +} /* PushLayer */ + +#if 0 +static PRFileDesc *PopLayer(PRFileDesc *stack) +{ + PRFileDesc *popped = PR_PopIOLayer(stack, identity); + if (verbosity > quiet) + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); + popped->dtor(popped); + + return stack; +} /* PopLayer */ +#endif + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRUint8 buffer[100]; + PRIntn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(PR_SUCCESS == rv); + while (minor_iterations-- > 0) + { + bytes_sent = PR_Send( + stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(sizeof(buffer) == bytes_sent); + if (verbosity > chatty) + PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent); + bytes_read = PR_Recv( + stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + } + + if (verbosity > quiet) + PR_fprintf(logFile, "Client shutting down stack\n"); + + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); +} /* Client */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRUint8 buffer[100]; + PRFileDesc *service; + PRUintn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + PRNetAddr client_address; + + service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > quiet) + PR_fprintf(logFile, "Server accepting connection\n"); + + do + { + bytes_read = PR_Recv( + service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (0 != bytes_read) + { + if (verbosity > chatty) + PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read); + PR_ASSERT(bytes_read > 0); + bytes_sent = PR_Send( + service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent); + PR_ASSERT(bytes_read == bytes_sent); + } + + } while (0 != bytes_read); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server shutting down and closing stack\n"); + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + +} /* Server */ + +static PRInt32 PR_CALLBACK MyRecv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b = (char*)buf; + PRFileDesc *lo = fd->lower; + PRInt32 rv, readin = 0, request = 0; + rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout); + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv sending permission for %d bytes\n", request); + if (0 < rv) + { + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv received permission request for %d bytes\n", request); + rv = lo->methods->send( + lo, &request, sizeof(request), flags, timeout); + if (0 < rv) + { + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv sending permission for %d bytes\n", request); + while (readin < request) + { + rv = lo->methods->recv( + lo, b + readin, amount - readin, flags, timeout); + if (rv <= 0) break; + if (verbosity > chatty) PR_fprintf( + logFile, "MyRecv received %d bytes\n", rv); + readin += rv; + } + rv = readin; + } + } + return rv; +} /* MyRecv */ + +static PRInt32 PR_CALLBACK MySend( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + PRFileDesc *lo = fd->lower; + const char *b = (const char*)buf; + PRInt32 rv, wroteout = 0, request; + if (verbosity > chatty) PR_fprintf( + logFile, "MySend asking permission to send %d bytes\n", amount); + rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout); + if (0 < rv) + { + rv = lo->methods->recv( + lo, &request, sizeof(request), flags, timeout); + if (0 < rv) + { + PR_ASSERT(request == amount); + if (verbosity > chatty) PR_fprintf( + logFile, "MySend got permission to send %d bytes\n", request); + while (wroteout < request) + { + rv = lo->methods->send( + lo, b + wroteout, request - wroteout, flags, timeout); + if (rv <= 0) break; + if (verbosity > chatty) PR_fprintf( + logFile, "MySend wrote %d bytes\n", rv); + wroteout += rv; + } + rv = amount; + } + } + return rv; +} /* MySend */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity + delta; + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; + return (Verbosity)verbage; +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn mits; + PLOptStatus os; + PRFileDesc *client, *service; + PRFileDesc *client_stack, *service_stack; + PRNetAddr any_address; + const char *server_name = NULL; + const PRIOMethods *stubMethods; + PRThread *client_thread, *server_thread; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + server_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'C': /* number of threads waiting */ + major_iterations = atoi(opt->value); + break; + case 'c': /* number of client threads */ + minor_iterations = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + logFile = PR_GetSpecialFD(PR_StandardError); + + identity = PR_GetUniqueIdentity("Dummy"); + stubMethods = PR_GetDefaultIOMethods(); + + /* + ** The protocol we're going to implement is one where in order to initiate + ** a send, the sender must first solicit permission. Therefore, every + ** send is really a send - receive - send sequence. + */ + myMethods = *stubMethods; /* first get the entire batch */ + myMethods.recv = MyRecv; /* then override the ones we care about */ + myMethods.send = MySend; /* then override the ones we care about */ + + if (NULL == server_name) + rv = PR_InitializeNetAddr( + PR_IpAddrLoopback, default_port, &server_address); + else + { + rv = PR_StringToNetAddr(server_name, &server_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_InitializeNetAddr( + PR_IpAddrNull, default_port, &server_address); + } + PR_ASSERT(PR_SUCCESS == rv); + + /* one type w/o layering */ + + mits = minor_iterations; + while (major_iterations-- > 0) + { + if (verbosity > silent) + PR_fprintf(logFile, "Beginning non-layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > silent) + PR_fprintf(logFile, "Ending non-layered test\n"); + + /* with layering */ + if (verbosity > silent) + PR_fprintf(logFile, "Beginning layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + PushLayer(client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + PushLayer(service); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + /* with layering, using new style stack */ + if (verbosity > silent) + PR_fprintf(logFile, + "Beginning layered test with new style stack\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + client_stack = PR_CreateIOLayer(client); + PushNewLayers(client_stack); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + service_stack = PR_CreateIOLayer(service); + PushNewLayers(service_stack); + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + minor_iterations = mits; + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service_stack, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client_stack, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > silent) + PR_fprintf(logFile, "Ending layered test\n"); + } + return 0; +} /* main */ + +/* layer.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/lazyinit.c b/src/libs/xpcom18a4/nsprpub/pr/tests/lazyinit.c new file mode 100644 index 00000000..09f0b6fa --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/lazyinit.c @@ -0,0 +1,139 @@ +/* -*- 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 ***** */ + +/* +** File: lazyinit.c +** Description: Testing lazy initialization +** +** Since you only get to initialize once, you have to rerun the test +** for each test case. The test cases are numbered. If you want to +** add more tests, take the next number and add it to the switch +** statement. +** +** This test is problematic on systems that don't support the notion +** of console output. The workarounds to emulate that feature include +** initializations themselves, which defeats the purpose here. +*/ + +#include "prcvar.h" +#include "prenv.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prtypes.h" + +#include +#include + +static void PR_CALLBACK lazyEntry(void *arg) +{ + PR_ASSERT(NULL == arg); +} /* lazyEntry */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRUintn pdkey; + PRStatus status; + char *path = NULL; + PRDir *dir = NULL; + PRLock *ml = NULL; + PRCondVar *cv = NULL; + PRThread *thread = NULL; + PRIntervalTime interval = 0; + PRFileDesc *file, *udp, *tcp, *pair[2]; + PRIntn test; + + if ( argc < 2) + { + test = 0; + } + else + test = atoi(argv[1]); + + switch (test) + { + case 0: ml = PR_NewLock(); + break; + + case 1: interval = PR_SecondsToInterval(1); + break; + + case 2: thread = PR_CreateThread( + PR_USER_THREAD, lazyEntry, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + break; + + case 3: file = PR_Open("/usr/tmp/", PR_RDONLY, 0); + break; + + case 4: udp = PR_NewUDPSocket(); + break; + + case 5: tcp = PR_NewTCPSocket(); + break; + + case 6: dir = PR_OpenDir("/usr/tmp/"); + break; + + case 7: (void)PR_NewThreadPrivateIndex(&pdkey, NULL); + break; + + case 8: path = PR_GetEnv("PATH"); + break; + + case 9: status = PR_NewTCPSocketPair(pair); + break; + + case 10: PR_SetConcurrency(2); + break; + + default: + printf( + "lazyinit: unrecognized command line argument: %s\n", + argv[1] ); + printf( "FAIL\n" ); + exit( 1 ); + break; + } /* switch() */ + return 0; +} /* Lazy */ + +/* lazyinit.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/libfilename.c b/src/libs/xpcom18a4/nsprpub/pr/tests/libfilename.c new file mode 100644 index 00000000..ab482936 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/libfilename.c @@ -0,0 +1,129 @@ +/* -*- 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) 2003 + * 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 ***** */ + +/*********************************************************************** +** +** Name: libfilename.c +** +** Description: test PR_GetLibraryFilePathname. +** +***********************************************************************/ + +#include "nspr.h" +#include "pprio.h" +#include +#include +#include + +PRBool debug_mode = PR_FALSE; + +static PRStatus RunTest(const char *name, PRFuncPtr addr) +{ + char *pathname; + PRFileDesc *fd; + + pathname = PR_GetLibraryFilePathname(name, addr); + if (pathname == NULL) { + fprintf(stderr, "PR_GetLibraryFilePathname failed\n"); + /* we let this test pass if this function is not implemented */ + if (PR_GetError() == PR_NOT_IMPLEMENTED_ERROR) { + return PR_SUCCESS; + } + return PR_FAILURE; + } + + if (debug_mode) printf("Pathname is %s\n", pathname); + fd = PR_OpenFile(pathname, PR_RDONLY, 0); + if (fd == NULL) { + fprintf(stderr, "PR_Open failed: %d\n", (int)PR_GetError()); + return PR_FAILURE; + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed: %d\n", (int)PR_GetError()); + return PR_FAILURE; + } + PR_Free(pathname); + return PR_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + char *name; + PRFuncPtr addr; + PRLibrary *lib; + PRBool failed = PR_FALSE; + + if (argc >= 2 && strcmp(argv[1], "-d") == 0) { + debug_mode = PR_TRUE; + } + + /* First test a library that is implicitly linked. */ +#ifdef WINNT + name = PR_Malloc(strlen("libnspr4.dll")+1); + strcpy(name, "libnspr4.dll"); +#else + name = PR_GetLibraryName(NULL, "nspr4"); +#endif + addr = (PRFuncPtr)PR_GetTCPMethods()->close; + if (RunTest(name, addr) == PR_FAILURE) { + failed = PR_TRUE; + } + PR_FreeLibraryName(name); + + /* Next test a library that is dynamically loaded. */ + name = PR_GetLibraryName("dll", "my"); + if (debug_mode) printf("Loading library %s\n", name); + lib = PR_LoadLibrary(name); + if (!lib) { + fprintf(stderr, "PR_LoadLibrary failed\n"); + exit(1); + } + PR_FreeLibraryName(name); + name = PR_GetLibraryName(NULL, "my"); + addr = PR_FindFunctionSymbol(lib, "My_GetValue"); + if (RunTest(name, addr) == PR_FAILURE) { + failed = PR_TRUE; + } + PR_FreeLibraryName(name); + PR_UnloadLibrary(lib); + if (failed) { + printf("FAIL\n"); + return 1; + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/lltest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/lltest.c new file mode 100644 index 00000000..f8ce4c6a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/lltest.c @@ -0,0 +1,859 @@ +/* -*- 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 ***** */ + +/* +** testll.c -- test suite for 64bit integer (longlong) operations +** +** Summary: testll [-d] | [-h] +** +** Where: +** -d set debug mode on; displays individual test failures +** -v verbose mode; displays progress in test, plus -d +** -h gives usage message. +** +** Description: +** lltest.c tests the functions defined in NSPR 2.0's prlong.h. +** +** Successive tests begin to depend on other LL functions working +** correctly. So, ... Do not change the order of the tests as run +** from main(). +** +** Caveats: +** Do not even begin to think that this is an exhaustive test! +** +** These tests try a little of everything, but not all boundary +** conditions and limits are tested. +** You want better coverage? ... Add it. +** +** --- +** Author: Lawrence Hardiman . +** --- +** Revision History: +** 01-Oct-1997. Original implementation. +** +*/ + +#include "nspr.h" +#include "plgetopt.h" + +/* --- Local Definitions --- */ +#define ReportProgress(m) if (verboseMode) PR_fprintf(output, (m)); + + +/* --- Global variables --- */ +static PRIntn failedAlready = 0; +static PRFileDesc* output = NULL; +static PRBool debugMode = PR_FALSE; +static PRBool verboseMode = PR_FALSE; + +/* +** Constants used in tests. +*/ +const PRInt64 bigZero = LL_INIT( 0, 0 ); +const PRInt64 bigOne = LL_INIT( 0, 1 ); +const PRInt64 bigTwo = LL_INIT( 0, 2 ); +const PRInt64 bigSixTeen = LL_INIT( 0, 16 ); +const PRInt64 bigThirtyTwo = LL_INIT( 0, 32 ); +const PRInt64 bigMinusOne = LL_INIT( 0xffffffff, 0xffffffff ); +const PRInt64 bigMinusTwo = LL_INIT( 0xffffffff, 0xfffffffe ); +const PRInt64 bigNumber = LL_INIT( 0x7fffffff, 0xffffffff ); +const PRInt64 bigMinusNumber = LL_INIT( 0x80000000, 0x00000001 ); +const PRInt64 bigMaxInt32 = LL_INIT( 0x00000000, 0x7fffffff ); +const PRInt64 big2To31 = LL_INIT( 0x00000000, 0x80000000 ); +const PRUint64 bigZeroFox = LL_INIT( 0x00000000, 0xffffffff ); +const PRUint64 bigFoxFox = LL_INIT( 0xffffffff, 0xffffffff ); +const PRUint64 bigFoxZero = LL_INIT( 0xffffffff, 0x00000000 ); +const PRUint64 bigEightZero = LL_INIT( 0x80000000, 0x00000000 ); +const PRUint64 big64K = LL_INIT( 0x00000000, 0x00010000 ); +const PRInt64 bigInt0 = LL_INIT( 0x01a00000, 0x00001000 ); +const PRInt64 bigInt1 = LL_INIT( 0x01a00000, 0x00001100 ); +const PRInt64 bigInt2 = LL_INIT( 0x01a00000, 0x00000100 ); +const PRInt64 bigInt3 = LL_INIT( 0x01a00001, 0x00001000 ); +const PRInt64 bigInt4 = LL_INIT( 0x01a00001, 0x00001100 ); +const PRInt64 bigInt5 = LL_INIT( 0x01a00001, 0x00000100 ); +const PRInt64 bigInt6 = LL_INIT( 0xb1a00000, 0x00001000 ); +const PRInt64 bigInt7 = LL_INIT( 0xb1a00000, 0x00001100 ); +const PRInt64 bigInt8 = LL_INIT( 0xb1a00000, 0x00000100 ); +const PRInt64 bigInt9 = LL_INIT( 0xb1a00001, 0x00001000 ); +const PRInt64 bigInt10 = LL_INIT( 0xb1a00001, 0x00001100 ); +const PRInt64 bigInt11 = LL_INIT( 0xb1a00001, 0x00000100 ); +const PRInt32 one = 1l; +const PRInt32 minusOne = -1l; +const PRInt32 sixteen = 16l; +const PRInt32 thirtyTwo = 32l; +const PRInt32 sixtyThree = 63l; + +/* +** SetFailed() -- Report individual test failure +** +*/ +static void +SetFailed( char *what, char *how ) +{ + failedAlready = 1; + if ( debugMode ) + PR_fprintf(output, "%s: failed: %s\n", what, how ); + return; +} + +static void +ResultFailed( char *what, char *how, PRInt64 expected, PRInt64 got) +{ + if ( debugMode) + { + SetFailed( what, how ); + PR_fprintf(output, "Expected: 0x%llx Got: 0x%llx\n", expected, got ); + } + return; +} + + +/* +** TestAssignment() -- Test the assignment +*/ +static void TestAssignment( void ) +{ + PRInt64 zero = LL_Zero(); + PRInt64 min = LL_MinInt(); + PRInt64 max = LL_MaxInt(); + if (!LL_EQ(zero, bigZero)) + SetFailed("LL_EQ(zero, bigZero)", "!="); + if (!LL_CMP(max, >, min)) + SetFailed("LL_CMP(max, >, min)", "!>"); +} + +/* +** TestComparisons() -- Test the longlong comparison operations +*/ +static void +TestComparisons( void ) +{ + ReportProgress("Testing Comparisons Operations\n"); + + /* test for zero */ + if ( !LL_IS_ZERO( bigZero )) + SetFailed( "LL_IS_ZERO", "Zero is not zero" ); + + if ( LL_IS_ZERO( bigOne )) + SetFailed( "LL_IS_ZERO", "One tests as zero" ); + + if ( LL_IS_ZERO( bigMinusOne )) + SetFailed( "LL_IS_ZERO", "Minus One tests as zero" ); + + /* test equal */ + if ( !LL_EQ( bigZero, bigZero )) + SetFailed( "LL_EQ", "zero EQ zero"); + + if ( !LL_EQ( bigOne, bigOne )) + SetFailed( "LL_EQ", "one EQ one" ); + + if ( !LL_EQ( bigNumber, bigNumber )) + SetFailed( "LL_EQ", "bigNumber EQ bigNumber" ); + + if ( !LL_EQ( bigMinusOne, bigMinusOne )) + SetFailed( "LL_EQ", "minus one EQ minus one"); + + if ( LL_EQ( bigZero, bigOne )) + SetFailed( "LL_EQ", "zero EQ one"); + + if ( LL_EQ( bigOne, bigZero )) + SetFailed( "LL_EQ", "one EQ zero" ); + + if ( LL_EQ( bigMinusOne, bigOne )) + SetFailed( "LL_EQ", "minus one EQ one"); + + if ( LL_EQ( bigNumber, bigOne )) + SetFailed( "LL_EQ", "bigNumber EQ one"); + + /* test not equal */ + if ( LL_NE( bigZero, bigZero )) + SetFailed( "LL_NE", "0 NE 0"); + + if ( LL_NE( bigOne, bigOne )) + SetFailed( "LL_NE", "1 NE 1"); + + if ( LL_NE( bigMinusOne, bigMinusOne )) + SetFailed( "LL_NE", "-1 NE -1"); + + if ( LL_NE( bigNumber, bigNumber )) + SetFailed( "LL_NE", "n NE n"); + + if ( LL_NE( bigMinusNumber, bigMinusNumber )) + SetFailed( "LL_NE", "-n NE -n"); + + if ( !LL_NE( bigZero, bigOne)) + SetFailed( "LL_NE", "0 NE 1"); + + if ( !LL_NE( bigOne, bigMinusNumber)) + SetFailed( "LL_NE", "1 NE -n"); + + /* Greater than or equal to zero */ + if ( !LL_GE_ZERO( bigZero )) + SetFailed( "LL_GE_ZERO", "0"); + + if ( !LL_GE_ZERO( bigOne )) + SetFailed( "LL_GE_ZERO", "1"); + + if ( !LL_GE_ZERO( bigNumber )) + SetFailed( "LL_GE_ZERO", "n"); + + if ( LL_GE_ZERO( bigMinusOne )) + SetFailed( "LL_GE_ZERO", "-1"); + + if ( LL_GE_ZERO( bigMinusNumber )) + SetFailed( "LL_GE_ZERO", "-n"); + + /* Algebraic Compare two values */ + if ( !LL_CMP( bigZero, ==, bigZero )) + SetFailed( "LL_CMP", "0 == 0"); + + if ( LL_CMP( bigZero, >, bigZero )) + SetFailed( "LL_CMP", "0 > 0"); + + if ( LL_CMP( bigZero, <, bigZero )) + SetFailed( "LL_CMP", "0 < 0"); + + if ( LL_CMP( bigNumber, <, bigOne )) + SetFailed( "LL_CMP", "n < 1"); + + if ( !LL_CMP( bigNumber, >, bigOne )) + SetFailed( "LL_CMP", "n <= 1"); + + if ( LL_CMP( bigOne, >, bigNumber )) + SetFailed( "LL_CMP", "1 > n"); + + if ( LL_CMP( bigMinusNumber, >, bigNumber )) + SetFailed( "LL_CMP", "-n > n"); + + if ( LL_CMP( bigNumber, !=, bigNumber)) + SetFailed( "LL_CMP", "n != n"); + + if ( !LL_CMP( bigMinusOne, >, bigMinusTwo )) + SetFailed( "LL_CMP", "-1 <= -2"); + + if ( !LL_CMP( bigMaxInt32, <, big2To31 )) + SetFailed( "LL_CMP", "Max 32-bit signed int >= 2^31"); + + /* Two positive numbers */ + if ( !LL_CMP( bigInt0, <=, bigInt0 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt1 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt2 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt3 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt4 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt0, <=, bigInt5 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* Two negative numbers */ + if ( !LL_CMP( bigInt6, <=, bigInt6 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt7 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt6, <=, bigInt8 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt9 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt10 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( !LL_CMP( bigInt6, <=, bigInt11 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* One positive, one negative */ + if ( LL_CMP( bigInt0, <=, bigInt6 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt7 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + if ( LL_CMP( bigInt0, <=, bigInt8 )) + SetFailed( "LL_CMP", "LL_CMP(<=) failed"); + + /* Bitwise Compare two numbers */ + if ( !LL_UCMP( bigZero, ==, bigZero )) + SetFailed( "LL_UCMP", "0 == 0"); + + if ( LL_UCMP( bigZero, >, bigZero )) + SetFailed( "LL_UCMP", "0 > 0"); + + if ( LL_UCMP( bigZero, <, bigZero )) + SetFailed( "LL_UCMP", "0 < 0"); + + if ( LL_UCMP( bigNumber, <, bigOne )) + SetFailed( "LL_UCMP", "n < 1"); + + if ( !LL_UCMP( bigNumber, >, bigOne )) + SetFailed( "LL_UCMP", "n < 1"); + + if ( LL_UCMP( bigOne, >, bigNumber )) + SetFailed( "LL_UCMP", "1 > n"); + + if ( LL_UCMP( bigMinusNumber, <, bigNumber )) + SetFailed( "LL_UCMP", "-n < n"); + + /* Two positive numbers */ + if ( !LL_UCMP( bigInt0, <=, bigInt0 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt1 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( LL_UCMP( bigInt0, <=, bigInt2 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt3 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt4 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt5 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + /* Two negative numbers */ + if ( !LL_UCMP( bigInt6, <=, bigInt6 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt7 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( LL_UCMP( bigInt6, <=, bigInt8 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt9 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt10 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt6, <=, bigInt11 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + /* One positive, one negative */ + if ( !LL_UCMP( bigInt0, <=, bigInt6 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt7 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + if ( !LL_UCMP( bigInt0, <=, bigInt8 )) + SetFailed( "LL_UCMP", "LL_UCMP(<=) failed"); + + return; +} + +/* +** TestLogicalOperations() -- Tests for AND, OR, ... +** +*/ +static void +TestLogicalOperations( void ) +{ + PRUint64 result, result2; + + ReportProgress("Testing Logical Operations\n"); + + /* Test AND */ + LL_AND( result, bigZero, bigZero ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "0 & 0", bigZero, result ); + + LL_AND( result, bigOne, bigOne ); + if ( LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "1 & 1", bigOne, result ); + + LL_AND( result, bigZero, bigOne ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_AND", "1 & 1", bigZero, result ); + + LL_AND( result, bigMinusOne, bigMinusOne ); + if ( !LL_UCMP( result, ==, bigMinusOne )) + ResultFailed( "LL_AND", "-1 & -1", bigMinusOne, result ); + + /* test OR */ + LL_OR( result, bigZero, bigZero ); + if ( !LL_IS_ZERO( result )) + ResultFailed( "LL_OR", "0 | 1", bigZero, result); + + LL_OR( result, bigZero, bigOne ); + if ( LL_IS_ZERO( result )) + ResultFailed( "LL_OR", "0 | 1", bigOne, result ); + + LL_OR( result, bigZero, bigMinusNumber ); + if ( !LL_UCMP( result, ==, bigMinusNumber )) + ResultFailed( "LL_OR", "0 | -n", bigMinusNumber, result); + + LL_OR( result, bigMinusNumber, bigZero ); + if ( !LL_UCMP( result, ==, bigMinusNumber )) + ResultFailed( "LL_OR", "-n | 0", bigMinusNumber, result ); + + /* test XOR */ + LL_XOR( result, bigZero, bigZero ); + if ( LL_UCMP( result, !=, bigZero )) + ResultFailed( "LL_XOR", "0 ^ 0", bigZero, result); + + LL_XOR( result, bigOne, bigZero ); + if ( LL_UCMP( result, !=, bigOne )) + ResultFailed( "LL_XOR", "1 ^ 0", bigZero, result ); + + LL_XOR( result, bigMinusNumber, bigZero ); + if ( LL_UCMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_XOR", "-n ^ 0", bigMinusNumber, result ); + + LL_XOR( result, bigMinusNumber, bigMinusNumber ); + if ( LL_UCMP( result, !=, bigZero )) + ResultFailed( "LL_XOR", "-n ^ -n", bigMinusNumber, result); + + /* test OR2. */ + result = bigZero; + LL_OR2( result, bigOne ); + if ( LL_UCMP( result, !=, bigOne )) + ResultFailed( "LL_OR2", "(r=0) |= 1", bigOne, result); + + result = bigOne; + LL_OR2( result, bigNumber ); + if ( LL_UCMP( result, !=, bigNumber )) + ResultFailed( "LL_OR2", "(r=1) |= n", bigNumber, result); + + result = bigMinusNumber; + LL_OR2( result, bigMinusNumber ); + if ( LL_UCMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_OR2", "(r=-n) |= -n", bigMinusNumber, result); + + /* test NOT */ + LL_NOT( result, bigMinusNumber); + LL_NOT( result2, result); + if ( LL_UCMP( result2, !=, bigMinusNumber )) + ResultFailed( "LL_NOT", "r != ~(~-n)", bigMinusNumber, result); + + /* test Negation */ + LL_NEG( result, bigMinusNumber ); + LL_NEG( result2, result ); + if ( LL_CMP( result2, !=, bigMinusNumber )) + ResultFailed( "LL_NEG", "r != -(-(-n))", bigMinusNumber, result); + + return; +} + + + +/* +** TestConversion() -- Test Conversion Operations +** +*/ +static void +TestConversion( void ) +{ + PRInt64 result; + PRInt64 resultU; + PRInt32 result32; + PRUint32 resultU32; + float resultF; + PRFloat64 resultD; + + ReportProgress("Testing Conversion Operations\n"); + + /* LL_L2I -- Convert to signed 32bit */ + LL_L2I(result32, bigOne ); + if ( result32 != one ) + SetFailed( "LL_L2I", "r != 1"); + + LL_L2I(result32, bigMinusOne ); + if ( result32 != minusOne ) + SetFailed( "LL_L2I", "r != -1"); + + /* LL_L2UI -- Convert 64bit to unsigned 32bit */ + LL_L2UI( resultU32, bigMinusOne ); + if ( resultU32 != (PRUint32) minusOne ) + SetFailed( "LL_L2UI", "r != -1"); + + LL_L2UI( resultU32, bigOne ); + if ( resultU32 != (PRUint32) one ) + SetFailed( "LL_L2UI", "r != 1"); + + /* LL_L2F -- Convert to 32bit floating point */ + LL_L2F( resultF, bigOne ); + if ( resultF != 1.0 ) + SetFailed( "LL_L2F", "r != 1.0"); + + LL_L2F( resultF, bigMinusOne ); + if ( resultF != -1.0 ) + SetFailed( "LL_L2F", "r != 1.0"); + + /* LL_L2D -- Convert to 64bit floating point */ + LL_L2D( resultD, bigOne ); + if ( resultD != 1.0L ) + SetFailed( "LL_L2D", "r != 1.0"); + + LL_L2D( resultD, bigMinusOne ); + if ( resultD != -1.0L ) + SetFailed( "LL_L2D", "r != -1.0"); + + /* LL_I2L -- Convert 32bit signed to 64bit signed */ + LL_I2L( result, one ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_I2L", "r != 1"); + + LL_I2L( result, minusOne ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_I2L", "r != -1"); + + /* LL_UI2L -- Convert 32bit unsigned to 64bit unsigned */ + LL_UI2L( resultU, (PRUint32) one ); + if ( LL_CMP(resultU, !=, bigOne )) + SetFailed( "LL_UI2L", "r != 1"); + + /* [lth.] This did not behave as expected, but it is correct + */ + LL_UI2L( resultU, (PRUint32) minusOne ); + if ( LL_CMP(resultU, !=, bigZeroFox )) + ResultFailed( "LL_UI2L", "r != -1", bigZeroFox, resultU); + + /* LL_F2L -- Convert 32bit float to 64bit signed */ + LL_F2L( result, 1.0 ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_F2L", "r != 1"); + + LL_F2L( result, -1.0 ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_F2L", "r != -1"); + + /* LL_D2L -- Convert 64bit Float to 64bit signed */ + LL_D2L( result, 1.0L ); + if ( LL_CMP(result, !=, bigOne )) + SetFailed( "LL_D2L", "r != 1"); + + LL_D2L( result, -1.0L ); + if ( LL_CMP(result, !=, bigMinusOne )) + SetFailed( "LL_D2L", "r != -1"); + + return; +} + +static void ShiftCompileOnly() +{ + /* + ** This function is only compiled, never called. + ** The real test is to see if it compiles w/o + ** warnings. This is no small feat, by the way. + */ + PRInt64 ia, ib; + PRUint64 ua, ub; + LL_SHR(ia, ib, 32); + LL_SHL(ia, ib, 32); + + LL_USHR(ua, ub, 32); + LL_ISHL(ia, 49, 32); + +} /* ShiftCompileOnly */ + + +/* +** TestShift() -- Test Shifting Operations +** +*/ +static void +TestShift( void ) +{ + static const PRInt64 largeTwoZero = LL_INIT( 0x00000002, 0x00000000 ); + PRInt64 result; + PRUint64 resultU; + + ReportProgress("Testing Shifting Operations\n"); + + /* LL_SHL -- Shift left algebraic */ + LL_SHL( result, bigOne, one ); + if ( LL_CMP( result, !=, bigTwo )) + ResultFailed( "LL_SHL", "r != 2", bigOne, result ); + + LL_SHL( result, bigTwo, thirtyTwo ); + if ( LL_CMP( result, !=, largeTwoZero )) + ResultFailed( "LL_SHL", "r != twoZero", largeTwoZero, result); + + /* LL_SHR -- Shift right algebraic */ + LL_SHR( result, bigFoxZero, thirtyTwo ); + if ( LL_CMP( result, !=, bigMinusOne )) + ResultFailed( "LL_SHR", "r != -1", bigMinusOne, result); + + LL_SHR( result, bigTwo, one ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_SHR", "r != 1", bigOne, result); + + LL_SHR( result, bigFoxFox, thirtyTwo ); + if ( LL_CMP( result, !=, bigMinusOne )) + ResultFailed( "LL_SHR", "r != -1 (was ff,ff)", bigMinusOne, result); + + /* LL_USHR -- Logical shift right */ + LL_USHR( resultU, bigZeroFox, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigZero )) + ResultFailed( "LL_USHR", "r != 0 ", bigZero, result); + + LL_USHR( resultU, bigFoxFox, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigZeroFox )) + ResultFailed( "LL_USHR", "r != 0 ", bigZeroFox, result); + + /* LL_ISHL -- Shift a 32bit integer into a 64bit result */ + LL_ISHL( resultU, minusOne, thirtyTwo ); + if ( LL_UCMP( resultU, !=, bigFoxZero )) + ResultFailed( "LL_ISHL", "r != ff,00 ", bigFoxZero, result); + + LL_ISHL( resultU, one, sixtyThree ); + if ( LL_UCMP( resultU, !=, bigEightZero )) + ResultFailed( "LL_ISHL", "r != 80,00 ", bigEightZero, result); + + LL_ISHL( resultU, one, sixteen ); + if ( LL_UCMP( resultU, !=, big64K )) + ResultFailed( "LL_ISHL", "r != 64K ", big64K, resultU); + + return; +} + + +/* +** TestArithmetic() -- Test arithmetic operations. +** +*/ +static void +TestArithmetic( void ) +{ + PRInt64 largeVal = LL_INIT( 0x00000001, 0xffffffff ); + PRInt64 largeValPlusOne = LL_INIT( 0x00000002, 0x00000000 ); + PRInt64 largeValTimesTwo = LL_INIT( 0x00000003, 0xfffffffe ); + PRInt64 largeMultCand = LL_INIT( 0x00000000, 0x7fffffff ); + PRInt64 largeMinusMultCand = LL_INIT( 0xffffffff, 0x10000001 ); + PRInt64 largeMultCandx64K = LL_INIT( 0x00007fff, 0xffff0000 ); + PRInt64 largeNumSHL5 = LL_INIT( 0x0000001f, 0xffffffe0 ); + PRInt64 result, result2; + + /* Addition */ + LL_ADD( result, bigOne, bigOne ); + if ( LL_CMP( result, !=, bigTwo )) + ResultFailed( "LL_ADD", "r != 1 + 1", bigTwo, result); + + LL_ADD( result, bigMinusOne, bigOne ); + if ( LL_CMP( result, !=, bigZero )) + ResultFailed( "LL_ADD", "r != -1 + 1", bigOne, result); + + LL_ADD( result, largeVal, bigOne ); + if ( LL_CMP( result, !=, largeValPlusOne )) + ResultFailed( "LL_ADD", "lVP1 != lV + 1", largeValPlusOne, result); + + /* Subtraction */ + LL_SUB( result, bigOne, bigOne ); + if ( LL_CMP( result, !=, bigZero )) + ResultFailed( "LL_SUB", "r != 1 - 1", bigZero, result); + + LL_SUB( result, bigTwo, bigOne ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_SUB", "r != 2 - 1", bigOne, result); + + LL_SUB( result, largeValPlusOne, bigOne ); + if ( LL_CMP( result, !=, largeVal )) + ResultFailed( "LL_SUB", "r != lVP1 - 1", largeVal, result); + + + /* Multiply */ + LL_MUL( result, largeVal, bigTwo ); + if ( LL_CMP( result, !=, largeValTimesTwo )) + ResultFailed( "LL_MUL", "r != lV*2", largeValTimesTwo, result); + + LL_MUL( result, largeMultCand, big64K ); + if ( LL_CMP( result, !=, largeMultCandx64K )) + ResultFailed( "LL_MUL", "r != lV*64K", largeMultCandx64K, result); + + LL_NEG( result2, largeMultCand ); + LL_MUL( result, largeMultCand, bigMinusOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_MUL", "r != -lMC", result2, result); + + LL_SHL( result2, bigZeroFox, 5); + LL_MUL( result, bigZeroFox, bigThirtyTwo ); + if ( LL_CMP( result, !=, largeNumSHL5 )) + ResultFailed( "LL_MUL", "r != 0f<<5", largeNumSHL5, result ); + + + + /* LL_DIV() Division */ + LL_DIV( result, bigOne, bigOne); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_DIV", "1 != 1", bigOne, result); + + LL_DIV( result, bigNumber, bigOne ); + if ( LL_CMP( result, !=, bigNumber )) + ResultFailed( "LL_DIV", "r != n / 1", bigNumber, result); + + LL_DIV( result, bigNumber, bigMinusOne ); + if ( LL_CMP( result, !=, bigMinusNumber )) + ResultFailed( "LL_DIV", "r != n / -1", bigMinusNumber, result); + + LL_DIV( result, bigMinusNumber, bigMinusOne ); + if ( LL_CMP( result, !=, bigNumber )) + ResultFailed( "LL_DIV", "r != -n / -1", bigNumber, result); + + LL_SHL( result2, bigZeroFox, 5 ); + LL_DIV( result, result2, bigOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "0f<<5 != 0f<<5", result2, result); + + LL_SHL( result2, bigZeroFox, 5 ); + LL_NEG( result2, result2 ); + LL_DIV( result, result2, bigOne ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "-0f<<5 != -0f<<5", result2, result); + + LL_SHL( result2, bigZeroFox, 17 ); + LL_DIV( result, result2, bigMinusOne ); + LL_NEG( result2, result2 ); + if ( LL_CMP( result, !=, result2 )) + ResultFailed( "LL_DIV", "-0f<<17 != -0f<<17", result2, result); + + + /* LL_MOD() Modulo Division */ + LL_ADD( result2, bigThirtyTwo, bigOne ); + LL_MOD( result, result2, bigSixTeen ); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_MOD", "r != 1", bigSixTeen, result); + + + LL_MUL( result2, bigZeroFox, bigThirtyTwo ); + LL_ADD( result2, result2, bigSixTeen); + LL_MOD( result, result2, bigThirtyTwo ); + if ( LL_CMP( result, !=, bigSixTeen )) + ResultFailed( "LL_MOD", "r != 16", bigSixTeen, result); + + /* LL_UDIVMOD */ + LL_DIV( result, bigOne, bigOne); + if ( LL_CMP( result, !=, bigOne )) + ResultFailed( "LL_DIV", "r != 16", bigSixTeen, result); + + + return; +} + +static void TestWellknowns(void) +{ + PRInt64 max = LL_MAXINT, min = LL_MININT, zero = LL_ZERO; + PRInt64 mmax = LL_MaxInt(), mmin = LL_MinInt(), mzero = LL_Zero(); + if (LL_NE(max, mmax)) + ResultFailed( "max, mmax", "max != mmax", max, mmax); + if (LL_NE(min, mmin)) + ResultFailed( "min, mmin", "min != mmin", max, mmin); + if (LL_NE(zero, mzero)) + ResultFailed( "zero, mzero", "zero != mzero", zero, mzero); +} /* TestWellknowns */ + +/* +** Initialize() -- Initialize the test case +** +** Parse command line options +** +*/ +static PRIntn +Initialize( PRIntn argc, char **argv ) +{ + PLOptState *opt = PL_CreateOptState(argc, argv, "dvh"); + PLOptStatus os; + + /* + ** Parse command line options + */ + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* set debug mode */ + debugMode = PR_TRUE; + break; + + case 'v': /* set verbose mode */ + verboseMode = PR_TRUE; + debugMode = PR_TRUE; + break; + + case 'h': /* user wants some guidance */ + default: + PR_fprintf(output, "You get help.\n"); + return(1); + } + } + PL_DestroyOptState(opt); + return(0); +} + +PRIntn main( int argc, char **argv ) +{ + PR_STDIO_INIT(); + output = PR_GetSpecialFD(PR_StandardError); + + if ( Initialize( argc, argv )) + return(1); + + TestAssignment(); + TestComparisons(); + TestLogicalOperations(); + TestConversion(); + TestShift(); + TestArithmetic(); + TestWellknowns(); + + /* + ** That's all folks! + */ + if ( failedAlready ) + { + PR_fprintf(output, "FAIL\n");\ + } + else + { + PR_fprintf(output, "PASS\n");\ + } + return failedAlready; +} /* end main() */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/lock.c b/src/libs/xpcom18a4/nsprpub/pr/tests/lock.c new file mode 100644 index 00000000..e0e23d01 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/lock.c @@ -0,0 +1,547 @@ +/* -*- 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 ***** */ + +/* +** File: lock.c +** Purpose: test basic locking functions +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +** +** 11-Aug-97 LarryH. Win16 port of NSPR. +** - Added "PASS", "FAIL" messages on completion. +** - Change stack variables to static scope variables +** because of shadow-stack use by Win16 +** - Added PR_CALLBACK attribute to functions called by NSPR +** - Added command line arguments: +** - l to control the number of loops +** - c to control the number of CPUs. +** (was positional argv). +** +** +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prio.h" +#include "prcmon.h" +#include "prinit.h" +#include "prinrval.h" +#include "prprf.h" +#include "prlock.h" +#include "prlog.h" +#include "prmon.h" +#include "prmem.h" +#include "prthread.h" +#include "prtypes.h" + +#include "plstr.h" + +#include + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static PRIntn failed_already=0; +static PRFileDesc *std_err = NULL; +static PRBool verbosity = PR_FALSE; +static PRBool debug_mode = PR_FALSE; + +const static PRIntervalTime contention_interval = 50; + +typedef struct LockContentious_s { + PRLock *ml; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; + PRIntervalTime overhead; + PRIntervalTime interval; +} LockContentious_t; + +typedef struct MonitorContentious_s { + PRMonitor *ml; + PRInt32 loops; + PRUint32 contender; + PRUint32 contentious; + PRIntervalTime overhead; + PRIntervalTime interval; +} MonitorContentious_t; + + +static PRIntervalTime Sleeper(PRUint32 loops) +{ + PRIntervalTime predicted = 0; + while (loops-- > 0) + { + predicted += contention_interval; + (void)PR_Sleep(contention_interval); + } + return predicted; +} /* Sleeper */ + +/* +** BASIC LOCKS +*/ +static PRIntervalTime MakeLock(PRUint32 loops) +{ + PRLock *ml = NULL; + while (loops-- > 0) + { + ml = PR_NewLock(); + PR_DestroyLock(ml); + ml = NULL; + } + return 0; +} /* MakeLock */ + +static PRIntervalTime NonContentiousLock(PRUint32 loops) +{ + PRLock *ml = NULL; + ml = PR_NewLock(); + while (loops-- > 0) + { + PR_Lock(ml); + PR_Unlock(ml); + } + PR_DestroyLock(ml); + return 0; +} /* NonContentiousLock */ + +static void PR_CALLBACK LockContender(void *arg) +{ + LockContentious_t *contention = (LockContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_Lock(contention->ml); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_Unlock(contention->ml); + } +} /* LockContender */ + +static PRIntervalTime ContentiousLock(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + LockContentious_t * contention; + PRIntervalTime rv, overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(LockContentious_t); + contention->loops = loops; + contention->overhead = 0; + contention->ml = PR_NewLock(); + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, LockContender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_Lock(contention->ml); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_Unlock(contention->ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + PR_DestroyLock(contention->ml); + overhead += (PR_IntervalNow() - timein); + rv = overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); + PR_Free(contention); + return rv; +} /* ContentiousLock */ + +/* +** MONITORS +*/ +static PRIntervalTime MakeMonitor(PRUint32 loops) +{ + PRMonitor *ml = NULL; + while (loops-- > 0) + { + ml = PR_NewMonitor(); + PR_DestroyMonitor(ml); + ml = NULL; + } + return 0; +} /* MakeMonitor */ + +static PRIntervalTime NonContentiousMonitor(PRUint32 loops) +{ + PRMonitor *ml = NULL; + ml = PR_NewMonitor(); + while (loops-- > 0) + { + PR_EnterMonitor(ml); + PR_ExitMonitor(ml); + } + PR_DestroyMonitor(ml); + return 0; +} /* NonContentiousMonitor */ + +static void PR_CALLBACK TryEntry(void *arg) +{ + PRMonitor *ml = (PRMonitor*)arg; + if (debug_mode) PR_fprintf(std_err, "Reentrant thread created\n"); + PR_EnterMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread acquired monitor\n"); + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Reentrant thread released monitor\n"); +} /* TryEntry */ + +static PRIntervalTime ReentrantMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread; + PRMonitor *ml = PR_NewMonitor(); + if (debug_mode) PR_fprintf(std_err, "\nMonitor created for reentrant test\n"); + + PR_EnterMonitor(ml); + PR_EnterMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor acquired twice\n"); + + thread = PR_CreateThread( + PR_USER_THREAD, TryEntry, ml, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + PR_Sleep(PR_SecondsToInterval(1)); + + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor released first time\n"); + + PR_ExitMonitor(ml); + if (debug_mode) PR_fprintf(std_err, "Monitor released second time\n"); + + status = PR_JoinThread(thread); + if (debug_mode) PR_fprintf(std_err, + "Reentrant thread joined %s\n", + (status == PR_SUCCESS) ? "successfully" : "in error"); + + PR_DestroyMonitor(ml); + return 0; +} /* ReentrantMonitor */ + +static void PR_CALLBACK MonitorContender(void *arg) +{ + MonitorContentious_t *contention = (MonitorContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_EnterMonitor(contention->ml); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_ExitMonitor(contention->ml); + } +} /* MonitorContender */ + +static PRUint32 ContentiousMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + MonitorContentious_t * contention; + PRIntervalTime rv, overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(MonitorContentious_t); + contention->loops = loops; + contention->overhead = 0; + contention->ml = PR_NewMonitor(); + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, MonitorContender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_EnterMonitor(contention->ml); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_ExitMonitor(contention->ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + PR_DestroyMonitor(contention->ml); + overhead += (PR_IntervalNow() - timein); + rv = overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); + PR_Free(contention); + return rv; +} /* ContentiousMonitor */ + +/* +** CACHED MONITORS +*/ +static PRIntervalTime NonContentiousCMonitor(PRUint32 loops) +{ + MonitorContentious_t contention; + while (loops-- > 0) + { + PR_CEnterMonitor(&contention); + PR_CExitMonitor(&contention); + } + return 0; +} /* NonContentiousCMonitor */ + +static void PR_CALLBACK Contender(void *arg) +{ + MonitorContentious_t *contention = (MonitorContentious_t*)arg; + while (contention->loops-- > 0) + { + PR_CEnterMonitor(contention); + contention->contender+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_CExitMonitor(contention); + } +} /* Contender */ + +static PRIntervalTime ContentiousCMonitor(PRUint32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + MonitorContentious_t * contention; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + contention = PR_NEWZAP(MonitorContentious_t); + contention->ml = NULL; + contention->loops = loops; + contention->interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, Contender, contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention->loops-- > 0) + { + PR_CEnterMonitor(contention); + contention->contentious+= 1; + contention->overhead += contention->interval; + PR_Sleep(contention->interval); + PR_CExitMonitor(contention); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + overhead += (PR_IntervalNow() - timein); + overhead += overhead + contention->overhead; + if (verbosity) + PR_fprintf( + std_err, "Access ratio: %u to %u\n", + contention->contentious, contention->contender); + PR_Free(contention); + return overhead; +} /* ContentiousCMonitor */ + +static PRIntervalTime Test( + const char* msg, PRUint32 (*test)(PRUint32 loops), + PRUint32 loops, PRIntervalTime overhead) +{ + /* + * overhead - overhead not measured by the test. + * duration - wall clock time it took to perform test. + * predicted - extra time test says should not be counted + * + * Time accountable to the test is duration - overhead - predicted + * All times are Intervals and accumulated for all iterations. + */ + PRFloat64 elapsed; + PRIntervalTime accountable, duration; + PRUintn spaces = PL_strlen(msg); + PRIntervalTime timeout, timein = PR_IntervalNow(); + PRIntervalTime predicted = test(loops); + timeout = PR_IntervalNow(); + duration = timeout - timein; + + if (debug_mode) + { + accountable = duration - predicted; + accountable -= overhead; + elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); + PR_fprintf(PR_STDOUT, "%s:", msg); + while (spaces++ < 50) PR_fprintf(PR_STDOUT, " "); + if ((PRInt32)accountable < 0) + PR_fprintf(PR_STDOUT, "*****.** usecs/iteration\n"); + else + PR_fprintf(PR_STDOUT, "%8.2f usecs/iteration\n", elapsed/loops); + } + return duration; +} /* Test */ + +int main(int argc, char **argv) +{ + PRBool rv = PR_TRUE; + PRIntervalTime duration; + PRUint32 cpu, cpus = 2, loops = 100; + + + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + { + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Command line argument -l sets the number of loops. + Command line argument -c sets the number of cpus. + Usage: lock [-d] [-l ] [-c ] + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dvl:c:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'v': /* debug mode */ + verbosity = PR_TRUE; + break; + case 'l': /* number of loops */ + loops = atoi(opt->value); + break; + case 'c': /* number of cpus */ + cpus = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + /* main test */ + PR_SetConcurrency(8); + +#ifdef XP_MAC + SetupMacPrintfLog("lock.log"); + debug_mode = 1; +#endif + + if (loops == 0) loops = 100; + if (debug_mode) + { + std_err = PR_STDERR; + PR_fprintf(std_err, "Lock: Using %d loops\n", loops); + } + + if (cpus == 0) cpus = 2; + if (debug_mode) PR_fprintf(std_err, "Lock: Using %d cpu(s)\n", cpus); + + (void)Sleeper(10); /* try filling in the caches */ + + for (cpu = 1; cpu <= cpus; ++cpu) + { + if (debug_mode) PR_fprintf(std_err, "\nLock: Using %d CPU(s)\n", cpu); + PR_SetConcurrency(cpu); + + duration = Test("Overhead of PR_Sleep", Sleeper, loops, 0); + duration = 0; + + (void)Test("Lock creation/deletion", MakeLock, loops, 0); + (void)Test("Lock non-contentious locking/unlocking", NonContentiousLock, loops, 0); + (void)Test("Lock contentious locking/unlocking", ContentiousLock, loops, duration); + (void)Test("Monitor creation/deletion", MakeMonitor, loops, 0); + (void)Test("Monitor non-contentious locking/unlocking", NonContentiousMonitor, loops, 0); + (void)Test("Monitor contentious locking/unlocking", ContentiousMonitor, loops, duration); + + (void)Test("Cached monitor non-contentious locking/unlocking", NonContentiousCMonitor, loops, 0); + (void)Test("Cached monitor contentious locking/unlocking", ContentiousCMonitor, loops, duration); + + (void)ReentrantMonitor(loops); + } + + if (debug_mode) + PR_fprintf( + std_err, "%s: test %s\n", "Lock(mutex) test", + ((rv) ? "passed" : "failed")); + else { + if (!rv) + failed_already=1; + } + + if(failed_already) + { + PR_fprintf(PR_STDOUT, "FAIL\n"); + return 1; + } + else + { + PR_fprintf(PR_STDOUT, "PASS\n"); + return 0; + } + +} /* main */ + +/* testlock.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/lockfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/lockfile.c new file mode 100644 index 00000000..27f8821e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/lockfile.c @@ -0,0 +1,276 @@ +/* -*- 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 ***** */ + +/* +** File: lockfile.c +** Purpose: test basic locking functions +** Just because this times stuff, don't think its a perforamnce +** test!!! +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prcmon.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prmon.h" +#include "prthread.h" +#include "prtypes.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +const static PRIntervalTime contention_interval = 50; + +typedef struct LockContentious_s { + PRLock *ml; + PRInt32 loops; + PRIntervalTime overhead; + PRIntervalTime interval; +} LockContentious_t; + +#define LOCKFILE "prlock.fil" + + + +static PRIntervalTime NonContentiousLock(PRInt32 loops) +{ + PRFileDesc *_lockfile; + while (loops-- > 0) + { + _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); + if (!_lockfile) { + if (debug_mode) printf( + "could not create lockfile: %d [%d]\n", + PR_GetError(), PR_GetOSError()); + return PR_INTERVAL_NO_TIMEOUT; + } + PR_LockFile(_lockfile); + PR_UnlockFile(_lockfile); + PR_Close(_lockfile); + } + return 0; +} /* NonContentiousLock */ + +static void PR_CALLBACK LockContender(void *arg) +{ + LockContentious_t *contention = (LockContentious_t*)arg; + PRFileDesc *_lockfile; + while (contention->loops-- > 0) + { + _lockfile = PR_Open(LOCKFILE, PR_CREATE_FILE|PR_RDWR, 0666); + if (!_lockfile) { + if (debug_mode) printf( + "could not create lockfile: %d [%d]\n", + PR_GetError(), PR_GetOSError()); + break; + } + PR_LockFile(_lockfile); + PR_Sleep(contention->interval); + PR_UnlockFile(_lockfile); + PR_Close(_lockfile); + } + +} /* LockContender */ + +/* +** Win16 requires things passed to Threads not be on the stack +*/ +static LockContentious_t contention; + +static PRIntervalTime ContentiousLock(PRInt32 loops) +{ + PRStatus status; + PRThread *thread = NULL; + PRIntervalTime overhead, timein = PR_IntervalNow(); + + contention.loops = loops; + contention.overhead = 0; + contention.ml = PR_NewLock(); + contention.interval = contention_interval; + thread = PR_CreateThread( + PR_USER_THREAD, LockContender, &contention, + PR_PRIORITY_LOW, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_ASSERT(thread != NULL); + + overhead = PR_IntervalNow() - timein; + + while (contention.loops > 0) + { + PR_Lock(contention.ml); + contention.overhead += contention.interval; + PR_Sleep(contention.interval); + PR_Unlock(contention.ml); + } + + timein = PR_IntervalNow(); + status = PR_JoinThread(thread); + PR_DestroyLock(contention.ml); + overhead += (PR_IntervalNow() - timein); + return overhead + contention.overhead; +} /* ContentiousLock */ + +static PRIntervalTime Test( + const char* msg, PRIntervalTime (*test)(PRInt32 loops), + PRInt32 loops, PRIntervalTime overhead) +{ + /* + * overhead - overhead not measured by the test. + * duration - wall clock time it took to perform test. + * predicted - extra time test says should not be counted + * + * Time accountable to the test is duration - overhead - predicted + * All times are Intervals and accumulated for all iterations. + */ + PRFloat64 elapsed; + PRIntervalTime accountable, duration; + PRUintn spaces = strlen(msg); + PRIntervalTime timeout, timein = PR_IntervalNow(); + PRIntervalTime predicted = test(loops); + timeout = PR_IntervalNow(); + duration = timeout - timein; + accountable = duration - predicted; + accountable -= overhead; + elapsed = (PRFloat64)PR_IntervalToMicroseconds(accountable); + if (debug_mode) printf("%s:", msg); + while (spaces++ < 50) if (debug_mode) printf(" "); + if ((PRInt32)accountable < 0) { + if (debug_mode) printf("*****.** usecs/iteration\n"); + } else { + if (debug_mode) printf("%8.2f usecs/iteration\n", elapsed/loops); + } + return duration; +} /* Test */ + +int main(int argc, char **argv) +{ + PRIntervalTime duration; + PRUint32 cpu, cpus = 2; + PRInt32 loops = 100; + + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("lockfile.log"); + debug_mode = 1; +#endif + + if (argc > 1) loops = atoi(argv[1]); + if (loops == 0) loops = 100; + if (debug_mode) printf("Lock: Using %d loops\n", loops); + + cpus = (argc < 3) ? 2 : atoi(argv[2]); + if (cpus == 0) cpus = 2; + if (debug_mode) printf("Lock: Using %d cpu(s)\n", cpus); + + + for (cpu = 1; cpu <= cpus; ++cpu) + { + if (debug_mode) printf("\nLockFile: Using %d CPU(s)\n", cpu); + PR_SetConcurrency(cpu); + + duration = Test("LockFile non-contentious locking/unlocking", NonContentiousLock, loops, 0); + (void)Test("LockFile contentious locking/unlocking", ContentiousLock, loops, duration); + } + + PR_Delete(LOCKFILE); /* try to get rid of evidence */ + + if (debug_mode) printf("%s: test %s\n", "Lock(mutex) test", ((failed_already) ? "failed" : "passed")); + if(failed_already) + return 1; + else + return 0; +} /* main */ + +/* testlock.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/logger.c b/src/libs/xpcom18a4/nsprpub/pr/tests/logger.c new file mode 100644 index 00000000..58c55d3e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/logger.c @@ -0,0 +1,167 @@ +/* -*- 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 ***** */ + +/* + * File: logger.c + * Description: test program for logging's basic functions + */ + +#include "prinit.h" +#include "prlog.h" +#include "prlock.h" +#include "prcvar.h" +#include "prthread.h" +#include "prinrval.h" + +#include + +#ifdef XP_MAC +extern void SetupMacPrintfLog(char *logFile); +#endif + +/* lth. re-define PR_LOG() */ +#if 0 +#undef PR_LOG_TEST +#undef PR_LOG +#define PR_LOG_TEST(_module,_level) ((_module)->level <= (_level)) +#define PR_LOG(_module,_level,_args) \ + { \ + if (PR_LOG_TEST(_module,_level)) \ + PR_LogPrint _args ; \ + } +#endif + + +static void Error(const char* msg) +{ + printf("\t%s\n", msg); +} /* Error */ + +static void PR_CALLBACK forked(void *arg) +{ + PRIntn i; + PRLock *ml; + PRCondVar *cv; + + PR_LogPrint("%s logging creating mutex\n", (const char*)arg); + ml = PR_NewLock(); + PR_LogPrint("%s logging creating condition variable\n", (const char*)arg); + cv = PR_NewCondVar(ml); + + PR_LogPrint("%s waiting on condition timeout 10 times\n", (const char*)arg); + for (i = 0; i < 10; ++i) + { + PR_Lock(ml); + PR_WaitCondVar(cv, PR_SecondsToInterval(1)); + PR_Unlock(ml); + } + + PR_LogPrint("%s logging destroying condition variable\n", (const char*)arg); + PR_DestroyCondVar(cv); + PR_LogPrint("%s logging destroying mutex\n", (const char*)arg); + PR_DestroyLock(ml); + PR_LogPrint("%s forked thread exiting\n", (const char*)arg); +} + +static void UserLogStuff( void ) +{ + PRLogModuleInfo *myLM; + PRIntn i; + + myLM = PR_NewLogModule( "userStuff" ); + if (! myLM ) + { + printf("UserLogStuff(): can't create new log module\n" ); + return; + } + + PR_LOG( myLM, PR_LOG_NOTICE, ("Log a Notice %d\n", 1 )); + + for (i = 0; i < 10 ; i++ ) + { + PR_LOG( myLM, PR_LOG_DEBUG, ("Log Debug number: %d\n", i)); + PR_Sleep( 300 ); + } + +} /* end UserLogStuff() */ + +int main(PRIntn argc, const char **argv) +{ + PRThread *thread; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifndef XP_MAC + if (argc > 1) + { + if (!PR_SetLogFile(argv[1])) + { + Error("Access: Cannot create log file"); + goto exit; + } + } +#else + SetupMacPrintfLog("logger.log"); +#endif + + /* Start logging something here */ + PR_LogPrint("%s logging into %s\n", argv[0], argv[1]); + + PR_LogPrint("%s creating new thread\n", argv[0]); + + /* + ** Now change buffering. + */ + PR_SetLogBuffering( 65500 ); + thread = PR_CreateThread( + PR_USER_THREAD, forked, (void*)argv[0], PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + PR_LogPrint("%s joining thread\n", argv[0]); + + UserLogStuff(); + + PR_JoinThread(thread); + + PR_LogFlush(); + return 0; + +exit: + return -1; +} + +/* logger.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/makedir.c b/src/libs/xpcom18a4/nsprpub/pr/tests/makedir.c new file mode 100644 index 00000000..2720f13e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/makedir.c @@ -0,0 +1,99 @@ +/* -*- 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) 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 test calls PR_MakeDir to create a bunch of directories + * with various mode bits. + */ + +#include "prio.h" + +#include +#include + +int main() +{ + if (PR_MakeDir("tdir0400", 0400) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0200", 0200) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0100", 0100) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0500", 0500) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0600", 0600) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0300", 0300) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0700", 0700) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0640", 0640) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0660", 0660) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0644", 0644) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0664", 0664) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + if (PR_MakeDir("tdir0666", 0666) == PR_FAILURE) { + fprintf(stderr, "PR_MakeDir failed\n"); + exit(1); + } + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/many_cv.c b/src/libs/xpcom18a4/nsprpub/pr/tests/many_cv.c new file mode 100644 index 00000000..c61b714d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/many_cv.c @@ -0,0 +1,150 @@ +/* -*- 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 "prinit.h" +#include "prprf.h" +#include "prthread.h" +#include "prcvar.h" +#include "prlock.h" +#include "prlog.h" +#include "prmem.h" + +#include "primpl.h" + +#include "plgetopt.h" + +#include + +static PRInt32 Random(void) +{ + PRInt32 ran = rand() >> 16; + return ran; +} /* Random */ + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "many_cv usage: [-c n] [-l n] [-h]\n"); + PR_fprintf(err, "\t-c n Number of conditions per lock (default: 10)\n"); + PR_fprintf(err, "\t-l n Number of times to loop the test (default: 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PLOptStatus os; + PRIntn index, nl; + PRLock *ml = NULL; + PRCondVar **cv = NULL; + PRBool stats = PR_FALSE; + PRIntn nc, loops = 1, cvs = 10; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "hsc:l:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 's': /* number of CVs to association with lock */ + stats = PR_TRUE; + break; + case 'c': /* number of CVs to association with lock */ + cvs = atoi(opt->value); + break; + case 'l': /* number of times to run the tests */ + loops = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Settings\n"); + PR_fprintf(err, "\tConditions / lock: %d\n", cvs); + PR_fprintf(err, "\tLoops to run test: %d\n", loops); + + ml = PR_NewLock(); + PR_ASSERT(NULL != ml); + + cv = (PRCondVar**)PR_CALLOC(sizeof(PRCondVar*) * cvs); + PR_ASSERT(NULL != cv); + + for (index = 0; index < cvs; ++index) + { + cv[index] = PR_NewCondVar(ml); + PR_ASSERT(NULL != cv[index]); + } + + for (index = 0; index < loops; ++index) + { + PR_Lock(ml); + for (nl = 0; nl < cvs; ++nl) + { + PRInt32 ran = Random() % 8; + if (0 == ran) PR_NotifyAllCondVar(cv[nl]); + else for (nc = 0; nc < ran; ++nc) + PR_NotifyCondVar(cv[nl]); + } + PR_Unlock(ml); + } + + for (index = 0; index < cvs; ++index) + PR_DestroyCondVar(cv[index]); + + PR_DELETE(cv); + + PR_DestroyLock(ml); + + printf("PASS\n"); + + PT_FPrintStats(err, "\nPThread Statistics\n"); + return 0; +} + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/mbcs.c b/src/libs/xpcom18a4/nsprpub/pr/tests/mbcs.c new file mode 100644 index 00000000..7ab89118 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/mbcs.c @@ -0,0 +1,187 @@ +/* -*- 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 ***** */ + +/* +** File: mbcs.c +** +** Synopsis: mbcs {dirName} +** +** where dirName is the directory to be traversed. dirName is required. +** +** Description: +** mbcs.c tests use of multi-byte characters, as would be passed to +** NSPR funtions by internationalized applications. +** +** mbcs.c, when run on any single-byte platform, should run correctly. +** In truth, running the mbcs test on a single-byte platform is +** really meaningless. mbcs.c, nor any NSPR library or test is not +** intended for use with any wide character set, including Unicode. +** mbcs.c should not be included in runtests.ksh because it requires +** extensive user intervention to set-up and run. +** +** mbcs.c should be run on a platform using some form of multi-byte +** characters. The initial platform for this test is a Japanese +** language Windows NT 4.0 machine. ... Thank you Noriko Hoshi. +** +** To run mbcs.c, the tester should create a directory tree containing +** some files in the same directory from which the test is run; i.e. +** the current working directory. The directory and files should be +** named such that when represented in the local multi-byte character +** set, one or more characters of the name is longer than a single +** byte. +** +*/ + +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +char *dirName = NULL; /* directory name to traverse */ + +/* +** Traverse directory +*/ +static void TraverseDirectory( unsigned char *dir ) +{ + PRDir *cwd; + PRDirEntry *dirEntry; + PRFileInfo info; + PRStatus rc; + PRInt32 err; + PRFileDesc *fd; + char nextDir[256]; + char file[256]; + + printf("Directory: %s\n", dir ); + cwd = PR_OpenDir( dir ); + if ( NULL == cwd ) { + printf("PR_OpenDir() failed on directory: %s, with error: %d, %d\n", + dir, PR_GetError(), PR_GetOSError()); + exit(1); + } + while( NULL != (dirEntry = PR_ReadDir( cwd, PR_SKIP_BOTH | PR_SKIP_HIDDEN ))) { + sprintf( file, "%s/%s", dir, dirEntry->name ); + rc = PR_GetFileInfo( file, &info ); + if ( PR_FAILURE == rc ) { + printf("PR_GetFileInfo() failed on file: %s, with error: %d, %d\n", + dirEntry->name, PR_GetError(), PR_GetOSError()); + exit(1); + } + if ( PR_FILE_FILE == info.type ) { + printf("File: %s \tsize: %ld\n", dirEntry->name, info.size ); + fd = PR_Open( file, PR_RDONLY, 0 ); + if ( NULL == fd ) { + printf("PR_Open() failed. Error: %ld, OSError: %ld\n", + PR_GetError(), PR_GetOSError()); + } + rc = PR_Close( fd ); + if ( PR_FAILURE == rc ) { + printf("PR_Close() failed. Error: %ld, OSError: %ld\n", + PR_GetError(), PR_GetOSError()); + } + } else if ( PR_FILE_DIRECTORY == info.type ) { + sprintf( nextDir, "%s/%s", dir, dirEntry->name ); + TraverseDirectory(nextDir); + } else { + printf("type is not interesting for file: %s\n", dirEntry->name ); + /* keep going */ + } + } + /* assume end-of-file, actually could be error */ + + rc = PR_CloseDir( cwd ); + if ( PR_FAILURE == rc ) { + printf("PR_CloseDir() failed on directory: %s, with error: %d, %d\n", + dir, PR_GetError(), PR_GetOSError()); + } + +} /* end TraverseDirectory() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + { /* get command line options */ + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dv"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + msgLevel = PR_LOG_DEBUG; + break; + default: + dirName = strdup(opt->value); + break; + } + } + PL_DestroyOptState(opt); + } /* end get command line options */ + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + + if ( dirName == NULL ) { + printf("you gotta specify a directory as an operand!\n"); + exit(1); + } + + TraverseDirectory( dirName ); + + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end template.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/multiacc.c b/src/libs/xpcom18a4/nsprpub/pr/tests/multiacc.c new file mode 100644 index 00000000..ccae270b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/multiacc.c @@ -0,0 +1,252 @@ +/* -*- 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 ***** */ + +/* + * File: multiacc.c + * + * Description: + * This test creates multiple threads that accept on the + * same listening socket. + */ + +#include "nspr.h" + +#include +#include +#include + +#define NUM_SERVER_THREADS 10 + +static int num_server_threads = NUM_SERVER_THREADS; +static PRThreadScope thread_scope = PR_GLOBAL_THREAD; +static PRBool exit_flag = PR_FALSE; + +static void ServerThreadFunc(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *acceptSock; + PRErrorCode err; + PRStatus status; + + while (!exit_flag) { + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + err = PR_GetError(); + if (PR_PENDING_INTERRUPT_ERROR == err) { + printf("server thread is interrupted\n"); + fflush(stdout); + continue; + } + fprintf(stderr, "PR_Accept failed: %d\n", err); + exit(1); + } + status = PR_Close(acceptSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } +} + +int main(int argc, char **argv) +{ + PRNetAddr serverAddr; + PRFileDesc *dummySock; + PRFileDesc *listenSock; + PRFileDesc *clientSock; + PRThread *dummyThread; + PRThread **serverThreads; + PRStatus status; + PRUint16 port; + int idx; + PRInt32 nbytes; + char buf[1024]; + + serverThreads = (PRThread **) + PR_Malloc(num_server_threads * sizeof(PRThread *)); + if (NULL == serverThreads) { + fprintf(stderr, "PR_Malloc failed\n"); + exit(1); + } + + /* + * Create a dummy listening socket and have the first + * (dummy) thread listen on it. This is to ensure that + * the first thread becomes the I/O continuation thread + * in the pthreads implementation (see ptio.c) and remains + * so throughout the test, so that we never have to + * recycle the I/O continuation thread. + */ + dummySock = PR_NewTCPSocket(); + if (NULL == dummySock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&serverAddr, 0, sizeof(serverAddr)); + status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + status = PR_Bind(dummySock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + status = PR_Listen(dummySock, 5); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&serverAddr, 0, sizeof(serverAddr)); + status = PR_InitializeNetAddr(PR_IpAddrAny, 0, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + status = PR_Bind(listenSock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + status = PR_GetSockName(listenSock, &serverAddr); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + port = PR_ntohs(serverAddr.inet.port); + status = PR_Listen(listenSock, 5); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + printf("creating dummy thread\n"); + fflush(stdout); + dummyThread = PR_CreateThread(PR_USER_THREAD, + ServerThreadFunc, dummySock, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == dummyThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + printf("sleeping one second before creating server threads\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + for (idx = 0; idx < num_server_threads; idx++) { + serverThreads[idx] = PR_CreateThread(PR_USER_THREAD, + ServerThreadFunc, listenSock, PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (NULL == serverThreads[idx]) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + } + + memset(&serverAddr, 0, sizeof(serverAddr)); + PR_InitializeNetAddr(PR_IpAddrLoopback, port, &serverAddr); + clientSock = PR_NewTCPSocket(); + if (NULL == clientSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + printf("sleeping one second before connecting\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + status = PR_Connect(clientSock, &serverAddr, PR_INTERVAL_NO_TIMEOUT); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + nbytes = PR_Read(clientSock, buf, sizeof(buf)); + if (nbytes != 0) { + fprintf(stderr, "expected 0 bytes but got %d bytes\n", nbytes); + exit(1); + } + status = PR_Close(clientSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("sleeping one second before shutting down server threads\n"); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(1)); + + exit_flag = PR_TRUE; + status = PR_Interrupt(dummyThread); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Interrupt failed\n"); + exit(1); + } + status = PR_JoinThread(dummyThread); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + for (idx = 0; idx < num_server_threads; idx++) { + status = PR_Interrupt(serverThreads[idx]); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Interrupt failed\n"); + exit(1); + } + status = PR_JoinThread(serverThreads[idx]); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + } + PR_Free(serverThreads); + status = PR_Close(dummySock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(listenSock); + if (PR_FAILURE == status) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/multiwait.c b/src/libs/xpcom18a4/nsprpub/pr/tests/multiwait.c new file mode 100644 index 00000000..10e22dad --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/multiwait.c @@ -0,0 +1,725 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "prlog.h" +#include "prmem.h" +#include "pratom.h" +#include "prlock.h" +#include "prmwait.h" +#include "prclist.h" +#include "prerror.h" +#include "prinrval.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plstr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include + +typedef struct Shared +{ + const char *title; + PRLock *list_lock; + PRWaitGroup *group; + PRIntervalTime timeout; +} Shared; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRFileDesc *debug = NULL; +static PRInt32 desc_allocated = 0; +static PRUint16 default_port = 12273; +static enum Verbosity verbosity = quiet; +static PRInt32 ops_required = 1000, ops_done = 0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; +static PRIntn client_threads = 20, worker_threads = 2, wait_objects = 50; + +#if defined(DEBUG) +#define MW_ASSERT(_expr) \ + ((_expr)?((void)0):_MW_Assert(# _expr,__FILE__,__LINE__)) +static void _MW_Assert(const char *s, const char *file, PRIntn ln) +{ + if (NULL != debug) PL_FPrintError(debug, NULL); + PR_Assert(s, file, ln); +} /* _MW_Assert */ +#else +#define MW_ASSERT(_expr) +#endif + +static void PrintRecvDesc(PRRecvWait *desc, const char *msg) +{ + const char *tag[] = { + "PR_MW_INTERRUPT", "PR_MW_TIMEOUT", + "PR_MW_FAILURE", "PR_MW_SUCCESS", "PR_MW_PENDING"}; + PR_fprintf( + debug, "%s: PRRecvWait(@0x%x): {fd: 0x%x, outcome: %s, tmo: %u}\n", + msg, desc, desc->fd, tag[desc->outcome + 3], desc->timeout); +} /* PrintRecvDesc */ + +static Shared *MakeShared(const char *title) +{ + Shared *shared = PR_NEWZAP(Shared); + shared->group = PR_CreateWaitGroup(1); + shared->timeout = PR_SecondsToInterval(1); + shared->list_lock = PR_NewLock(); + shared->title = title; + return shared; +} /* MakeShared */ + +static void DestroyShared(Shared *shared) +{ + PRStatus rv; + if (verbosity > quiet) + PR_fprintf(debug, "%s: destroying group\n", shared->title); + rv = PR_DestroyWaitGroup(shared->group); + MW_ASSERT(PR_SUCCESS == rv); + PR_DestroyLock(shared->list_lock); + PR_DELETE(shared); +} /* DestroyShared */ + +static PRRecvWait *CreateRecvWait(PRFileDesc *fd, PRIntervalTime timeout) +{ + PRRecvWait *desc_out = PR_NEWZAP(PRRecvWait); + MW_ASSERT(NULL != desc_out); + + MW_ASSERT(NULL != fd); + desc_out->fd = fd; + desc_out->timeout = timeout; + desc_out->buffer.length = 120; + desc_out->buffer.start = PR_CALLOC(120); + + PR_AtomicIncrement(&desc_allocated); + + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Allocated"); + return desc_out; +} /* CreateRecvWait */ + +static void DestroyRecvWait(PRRecvWait *desc_out) +{ + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Destroying"); + PR_Close(desc_out->fd); + if (NULL != desc_out->buffer.start) + PR_DELETE(desc_out->buffer.start); + PR_Free(desc_out); + (void)PR_AtomicDecrement(&desc_allocated); +} /* DestroyRecvWait */ + +static void CancelGroup(Shared *shared) +{ + PRRecvWait *desc_out; + + if (verbosity > quiet) + PR_fprintf(debug, "%s Reclaiming wait descriptors\n", shared->title); + + do + { + desc_out = PR_CancelWaitGroup(shared->group); + if (NULL != desc_out) DestroyRecvWait(desc_out); + } while (NULL != desc_out); + + MW_ASSERT(0 == desc_allocated); + MW_ASSERT(PR_GROUP_EMPTY_ERROR == PR_GetError()); +} /* CancelGroup */ + +static void PR_CALLBACK ClientThread(void* arg) +{ + PRStatus rv; + PRInt32 bytes; + PRIntn empty_flags = 0; + PRNetAddr server_address; + unsigned char buffer[100]; + Shared *shared = (Shared*)arg; + PRFileDesc *server = PR_NewTCPSocket(); + if ((NULL == server) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) return; + MW_ASSERT(NULL != server); + + if (verbosity > chatty) + PR_fprintf(debug, "%s: Server socket @0x%x\n", shared->title, server); + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: Client opening connection\n", shared->title); + rv = PR_Connect(server, &server_address, PR_INTERVAL_NO_TIMEOUT); + + if (PR_FAILURE == rv) + { + if (verbosity > silent) PL_FPrintError(debug, "Client connect failed"); + return; + } + + while (ops_done < ops_required) + { + bytes = PR_Send( + server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + MW_ASSERT(sizeof(buffer) == bytes); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Client sent %d bytes\n", + shared->title, sizeof(buffer)); + bytes = PR_Recv( + server, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Client received %d bytes\n", + shared->title, sizeof(buffer)); + if ((-1 == bytes) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + MW_ASSERT(sizeof(buffer) == bytes); + PR_Sleep(shared->timeout); + } + rv = PR_Close(server); + MW_ASSERT(PR_SUCCESS == rv); + +} /* ClientThread */ + +static void OneInThenCancelled(Shared *shared) +{ + PRStatus rv; + PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait); + + shared->timeout = PR_INTERVAL_NO_TIMEOUT; + + desc_in->fd = PR_NewTCPSocket(); + desc_in->timeout = shared->timeout; + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc"); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Cancelling"); + rv = PR_CancelWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(desc_out == desc_in); + MW_ASSERT(PR_MW_INTERRUPT == desc_out->outcome); + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + rv = PR_Close(desc_in->fd); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: destroying group\n", shared->title); + + PR_DELETE(desc_in); +} /* OneInThenCancelled */ + +static void OneOpOneThread(Shared *shared) +{ + PRStatus rv; + PRRecvWait *desc_out, *desc_in = PR_NEWZAP(PRRecvWait); + + desc_in->fd = PR_NewTCPSocket(); + desc_in->timeout = shared->timeout; + + if (verbosity > chatty) PrintRecvDesc(desc_in, "Adding desc"); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(desc_out == desc_in); + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + rv = PR_Close(desc_in->fd); + MW_ASSERT(PR_SUCCESS == rv); + + PR_DELETE(desc_in); +} /* OneOpOneThread */ + +static void ManyOpOneThread(Shared *shared) +{ + PRStatus rv; + PRIntn index; + PRRecvWait *desc_in; + PRRecvWait *desc_out; + + if (verbosity > quiet) + PR_fprintf(debug, "%s: adding %d descs\n", shared->title, wait_objects); + + for (index = 0; index < wait_objects; ++index) + { + desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout); + + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + + while (ops_done < ops_required) + { + desc_out = PR_WaitRecvReady(shared->group); + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready/readding"); + rv = PR_AddWaitFileDesc(shared->group, desc_out); + MW_ASSERT(PR_SUCCESS == rv); + (void)PR_AtomicIncrement(&ops_done); + } + + CancelGroup(shared); +} /* ManyOpOneThread */ + +static void PR_CALLBACK SomeOpsThread(void *arg) +{ + PRRecvWait *desc_out; + PRStatus rv = PR_SUCCESS; + Shared *shared = (Shared*)arg; + do /* until interrupted */ + { + desc_out = PR_WaitRecvReady(shared->group); + if (NULL == desc_out) + { + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + if (verbosity > quiet) PR_fprintf(debug, "Aborted\n"); + break; + } + MW_ASSERT(PR_MW_TIMEOUT == desc_out->outcome); + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + if (verbosity > chatty) PrintRecvDesc(desc_out, "Ready"); + + if (verbosity > chatty) PrintRecvDesc(desc_out, "Re-Adding"); + desc_out->timeout = shared->timeout; + rv = PR_AddWaitFileDesc(shared->group, desc_out); + PR_AtomicIncrement(&ops_done); + if (ops_done > ops_required) break; + } while (PR_SUCCESS == rv); + MW_ASSERT(PR_SUCCESS == rv); +} /* SomeOpsThread */ + +static void SomeOpsSomeThreads(Shared *shared) +{ + PRStatus rv; + PRThread **thread; + PRIntn index; + PRRecvWait *desc_in; + + thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads); + + /* Create some threads */ + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + thread[index] = PR_CreateThread( + PR_USER_THREAD, SomeOpsThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + /* then create some operations */ + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating desc\n", shared->title); + for (index = 0; index < wait_objects; ++index) + { + desc_in = CreateRecvWait(PR_NewTCPSocket(), shared->timeout); + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + + if (verbosity > quiet) + PR_fprintf(debug, "%s: sleeping\n", shared->title); + while (ops_done < ops_required) PR_Sleep(shared->timeout); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + rv = PR_Interrupt(thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(thread); + + CancelGroup(shared); +} /* SomeOpsSomeThreads */ + +static PRStatus ServiceRequest(Shared *shared, PRRecvWait *desc) +{ + PRInt32 bytes_out; + + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Service received %d bytes\n", + shared->title, desc->bytesRecv); + + if (0 == desc->bytesRecv) goto quitting; + if ((-1 == desc->bytesRecv) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted; + + bytes_out = PR_Send( + desc->fd, desc->buffer.start, desc->bytesRecv, 0, shared->timeout); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Service sent %d bytes\n", + shared->title, bytes_out); + + if ((-1 == bytes_out) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) goto aborted; + MW_ASSERT(bytes_out == desc->bytesRecv); + + return PR_SUCCESS; + +aborted: +quitting: + return PR_FAILURE; +} /* ServiceRequest */ + +static void PR_CALLBACK ServiceThread(void *arg) +{ + PRStatus rv = PR_SUCCESS; + PRRecvWait *desc_out = NULL; + Shared *shared = (Shared*)arg; + do /* until interrupted */ + { + if (NULL != desc_out) + { + desc_out->timeout = PR_INTERVAL_NO_TIMEOUT; + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Service re-adding"); + rv = PR_AddWaitFileDesc(shared->group, desc_out); + MW_ASSERT(PR_SUCCESS == rv); + } + + desc_out = PR_WaitRecvReady(shared->group); + if (NULL == desc_out) + { + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + break; + } + + switch (desc_out->outcome) + { + case PR_MW_SUCCESS: + { + PR_AtomicIncrement(&ops_done); + if (verbosity > chatty) + PrintRecvDesc(desc_out, "Service ready"); + rv = ServiceRequest(shared, desc_out); + break; + } + case PR_MW_INTERRUPT: + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + rv = PR_FAILURE; /* if interrupted, then exit */ + break; + case PR_MW_TIMEOUT: + MW_ASSERT(PR_IO_TIMEOUT_ERROR == PR_GetError()); + case PR_MW_FAILURE: + if (verbosity > silent) + PL_FPrintError(debug, "RecvReady failure"); + break; + default: + break; + } + } while (PR_SUCCESS == rv); + + if (NULL != desc_out) DestroyRecvWait(desc_out); + +} /* ServiceThread */ + +static void PR_CALLBACK EnumerationThread(void *arg) +{ + PRStatus rv; + PRIntn count; + PRRecvWait *desc; + Shared *shared = (Shared*)arg; + PRIntervalTime five_seconds = PR_SecondsToInterval(5); + PRMWaitEnumerator *enumerator = PR_CreateMWaitEnumerator(shared->group); + MW_ASSERT(NULL != enumerator); + + while (PR_SUCCESS == PR_Sleep(five_seconds)) + { + count = 0; + desc = NULL; + while (NULL != (desc = PR_EnumerateWaitGroup(enumerator, desc))) + { + if (verbosity > chatty) PrintRecvDesc(desc, shared->title); + count += 1; + } + if (verbosity > silent) + PR_fprintf(debug, + "%s Enumerated %d objects\n", shared->title, count); + } + + MW_ASSERT(PR_PENDING_INTERRUPT_ERROR == PR_GetError()); + + + rv = PR_DestroyMWaitEnumerator(enumerator); + MW_ASSERT(PR_SUCCESS == rv); +} /* EnumerationThread */ + +static void PR_CALLBACK ServerThread(void *arg) +{ + PRStatus rv; + PRIntn index; + PRRecvWait *desc_in; + PRThread **worker_thread; + Shared *shared = (Shared*)arg; + PRFileDesc *listener, *service; + PRNetAddr server_address, client_address; + + worker_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * worker_threads); + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server creating worker_threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + worker_thread[index] = PR_CreateThread( + PR_USER_THREAD, ServiceThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &server_address); + MW_ASSERT(PR_SUCCESS == rv); + + listener = PR_NewTCPSocket(); MW_ASSERT(NULL != listener); + if (verbosity > chatty) + PR_fprintf( + debug, "%s: Server listener socket @0x%x\n", + shared->title, listener); + rv = PR_Bind(listener, &server_address); MW_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(listener, 10); MW_ASSERT(PR_SUCCESS == rv); + while (ops_done < ops_required) + { + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server accepting connection\n", shared->title); + service = PR_Accept(listener, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (NULL == service) + { + if (PR_PENDING_INTERRUPT_ERROR == PR_GetError()) break; + PL_PrintError("Accept failed"); + MW_ASSERT(!"Accept failed"); + } + else + { + desc_in = CreateRecvWait(service, shared->timeout); + desc_in->timeout = PR_INTERVAL_NO_TIMEOUT; + if (verbosity > chatty) + PrintRecvDesc(desc_in, "Service adding"); + rv = PR_AddWaitFileDesc(shared->group, desc_in); + MW_ASSERT(PR_SUCCESS == rv); + } + } + + if (verbosity > quiet) + PR_fprintf(debug, "%s: Server interrupting worker_threads\n", shared->title); + for (index = 0; index < worker_threads; ++index) + { + rv = PR_Interrupt(worker_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(worker_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(worker_thread); + + PR_Close(listener); + + CancelGroup(shared); + +} /* ServerThread */ + +static void RealOneGroupIO(Shared *shared) +{ + /* + ** Create a server that listens for connections and then services + ** requests that come in over those connections. The server never + ** deletes a connection and assumes a basic RPC model of operation. + ** + ** Use worker_threads threads to service how every many open ports + ** there might be. + ** + ** Oh, ya. Almost forget. Create (some) clients as well. + */ + PRStatus rv; + PRIntn index; + PRThread *server_thread, *enumeration_thread, **client_thread; + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating server_thread\n", shared->title); + + server_thread = PR_CreateThread( + PR_USER_THREAD, ServerThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating enumeration_thread\n", shared->title); + + enumeration_thread = PR_CreateThread( + PR_USER_THREAD, EnumerationThread, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: snoozing before creating clients\n", shared->title); + PR_Sleep(5 * shared->timeout); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: creating client_threads\n", shared->title); + client_thread = (PRThread**)PR_CALLOC(sizeof(PRThread*) * client_threads); + for (index = 0; index < client_threads; ++index) + { + client_thread[index] = PR_CreateThread( + PR_USER_THREAD, ClientThread, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + } + + while (ops_done < ops_required) PR_Sleep(shared->timeout); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining client_threads\n", shared->title); + for (index = 0; index < client_threads; ++index) + { + rv = PR_Interrupt(client_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(client_thread[index]); + MW_ASSERT(PR_SUCCESS == rv); + } + PR_DELETE(client_thread); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining enumeration_thread\n", shared->title); + rv = PR_Interrupt(enumeration_thread); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(enumeration_thread); + MW_ASSERT(PR_SUCCESS == rv); + + if (verbosity > quiet) + PR_fprintf(debug, "%s: interrupting/joining server_thread\n", shared->title); + rv = PR_Interrupt(server_thread); + MW_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + MW_ASSERT(PR_SUCCESS == rv); +} /* RealOneGroupIO */ + +static void RunThisOne( + void (*func)(Shared*), const char *name, const char *test_name) +{ + Shared *shared; + if ((NULL == test_name) || (0 == PL_strcmp(name, test_name))) + { + if (verbosity > silent) + PR_fprintf(debug, "%s()\n", name); + shared = MakeShared(name); + ops_done = 0; + func(shared); /* run the test */ + MW_ASSERT(0 == desc_allocated); + DestroyShared(shared); + } +} /* RunThisOne */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity; + return (Verbosity)(verbage += delta); +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + const char *test_name = NULL; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGc:o:p:t:w:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + test_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'c': /* number of client threads */ + client_threads = atoi(opt->value); + break; + case 'o': /* operations to compelete */ + ops_required = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + case 't': /* number of threads waiting */ + worker_threads = atoi(opt->value); + break; + case 'w': /* number of wait objects */ + wait_objects = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (verbosity > 0) + debug = PR_GetSpecialFD(PR_StandardError); + + RunThisOne(OneInThenCancelled, "OneInThenCancelled", test_name); + RunThisOne(OneOpOneThread, "OneOpOneThread", test_name); + RunThisOne(ManyOpOneThread, "ManyOpOneThread", test_name); + RunThisOne(SomeOpsSomeThreads, "SomeOpsSomeThreads", test_name); + RunThisOne(RealOneGroupIO, "RealOneGroupIO", test_name); + return 0; +} /* main */ + +/* multwait.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/nameshm1.c b/src/libs/xpcom18a4/nsprpub/pr/tests/nameshm1.c new file mode 100644 index 00000000..e70f0e2a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/nameshm1.c @@ -0,0 +1,599 @@ +/* -*- 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 ***** */ + +/* +** File: nameshm1.c -- Test Named Shared Memory +** +** Description: +** nameshm1 tests Named Shared Memory. nameshm1 performs two tests of +** named shared memory. +** +** The first test is a basic test. The basic test operates as a single +** process. The process exercises all the API elements of the facility. +** This test also attempts to write to all locations in the shared +** memory. +** +** The second test is a client-server test. The client-server test +** creates a new instance of nameshm1, passing the -C argument to the +** new process; this creates the client-side process. The server-side +** (the instance of nameshm1 created from the command line) and the +** client-side interact via inter-process semaphores to verify that the +** shared memory segment can be read and written by both sides in a +** synchronized maner. +** +** Note: Because this test runs in two processes, the log files created +** by the test are not in chronological sequence; makes it hard to read. +** As a temporary circumvention, I changed the definition(s) of the +** _PUT_LOG() macro in prlog.c to force a flushall(), or equivalent. +** This causes the log entries to be emitted in true chronological +** order. +** +** Synopsis: nameshm1 [options] [name] +** +** Options: +** -d Enables debug trace via PR_LOG() +** -v Enables verbose mode debug trace via PR_LOG() +** -w Causes the basic test to attempt to write to the segment +** mapped as read-only. When this option is specified, the +** test should crash with a seg-fault; this is a destructive +** test and is considered successful when it seg-faults. +** +** -C Causes nameshm1 to start as the client-side of a +** client-server pair of processes. Only the instance +** of nameshm1 operating as the server-side process should +** specify the -C option when creating the client-side process; +** the -C option should not be specified at the command line. +** The client-side uses the shared memory segment created by +** the server-side to communicate with the server-side +** process. +** +** -p Specify the number of iterations the client-server tests +** should perform. Default: 1000. +** +** -s Size, in KBytes (1024), of the shared memory segment. +** Default: (10 * 1024) +** +** -i Number of client-side iterations. Default: 3 +** +** name specifies the name of the shared memory segment to be used. +** Default: /tmp/xxxNSPRshm +** +** +** See also: prshm.h +** +** /lth. Aug-1999. +*/ + +#include +#include +#include +#include +#include + +#define SEM_NAME1 "/tmp/nameshmSEM1" +#define SEM_NAME2 "/tmp/nameshmSEM2" +#define SEM_MODE 0666 +#define SHM_MODE 0666 + +#define NameSize (1024) + +PRIntn debug = 0; +PRIntn failed_already = 0; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRLogModuleInfo *lm; + +/* command line options */ +PRIntn optDebug = 0; +PRIntn optVerbose = 0; +PRUint32 optWriteRO = 0; /* test write to read-only memory. should crash */ +PRUint32 optClient = 0; +PRUint32 optCreate = 1; +PRUint32 optAttachRW = 1; +PRUint32 optAttachRO = 1; +PRUint32 optClose = 1; +PRUint32 optDelete = 1; +PRInt32 optPing = 1000; +PRUint32 optSize = (10 * 1024 ); +PRInt32 optClientIterations = 3; +char optName[NameSize] = "/tmp/xxxNSPRshm"; + +char buf[1024] = ""; + + +static void BasicTest( void ) +{ + PRSharedMemory *shm; + char *addr; /* address of shared memory segment */ + PRUint32 i; + PRInt32 rc; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin BasicTest" )); + + if ( PR_FAILURE == PR_DeleteSharedMemory( optName )) { + PR_LOG( lm, msgLevel, + ("nameshm1: Initial PR_DeleteSharedMemory() failed. No problem")); + } else + PR_LOG( lm, msgLevel, + ("nameshm1: Initial PR_DeleteSharedMemory() success")); + + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE ); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Attach: success: %p", addr )); + + /* fill memory with i */ + for ( i = 0; i < optSize ; i++ ) + { + *(addr + i) = i; + } + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Delete: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RW Delete: success: " )); + + PR_LOG( lm, msgLevel, + ("nameshm1: BasicTest(): Passed")); + + return; +} /* end BasicTest() */ + +static void ReadOnlyTest( void ) +{ + PRSharedMemory *shm; + char *roAddr; /* read-only address of shared memory segment */ + PRInt32 rc; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin ReadOnlyTest" )); + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Create: success: %p", shm )); + + + roAddr = PR_AttachSharedMemory( shm , PR_SHM_READONLY ); + if ( NULL == roAddr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Attach: success: %p", roAddr )); + + if ( optWriteRO ) + { + *roAddr = 0x00; /* write to read-only memory */ + failed_already = 1; + PR_LOG( lm, msgLevel, ("nameshm1: Wrote to read-only memory segment!")); + return; + } + + rc = PR_DetachSharedMemory( shm, roAddr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Detach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Close: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Destroy: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: RO Destroy: success: " )); + + PR_LOG( lm, msgLevel, + ("nameshm1: ReadOnlyTest(): Passed")); + + return; +} /* end ReadOnlyTest() */ + +static void DoClient( void ) +{ + PRStatus rc; + PRSem *sem1, *sem2; + PRSharedMemory *shm; + PRUint32 *addr; + PRInt32 i; + + PR_LOG( lm, msgLevel, + ("nameshm1: DoClient(): Starting")); + + sem1 = PR_OpenSemaphore( SEM_NAME1, 0, 0, 0 ); + PR_ASSERT( sem1 ); + + sem2 = PR_OpenSemaphore( SEM_NAME2, 0, 0, 0 ); + PR_ASSERT( sem1 ); + + shm = PR_OpenSharedMemory( optName, optSize, 0, SHM_MODE ); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Create: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Attach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Attach: success: %p", addr )); + + PR_LOG( lm, msgLevel, + ( "Client found: %s", addr)); + + PR_Sleep(PR_SecondsToInterval(4)); + for ( i = 0 ; i < optPing ; i++ ) + { + rc = PR_WaitSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + (*addr)++; + PR_ASSERT( (*addr % 2) == 0 ); + if ( optVerbose ) + PR_LOG( lm, msgLevel, + ( "nameshm1: Client ping: %d, i: %d", *addr, i)); + + rc = PR_PostSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + } + + rc = PR_CloseSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Detach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Close: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: DoClient(): Close: success: " )); + + return; +} /* end DoClient() */ + +static void ClientServerTest( void ) +{ + PRStatus rc; + PRSem *sem1, *sem2; + PRProcess *proc; + PRInt32 exit_status; + PRSharedMemory *shm; + PRUint32 *addr; + PRInt32 i; + char *child_argv[8]; + char buf[24]; + + PR_LOG( lm, msgLevel, + ( "nameshm1: Begin ClientServerTest" )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: failed. No problem")); + } else + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: success" )); + + + shm = PR_OpenSharedMemory( optName, optSize, (PR_SHM_CREATE | PR_SHM_EXCL), SHM_MODE); + if ( NULL == shm ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Create: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Create: success: %p", shm )); + + addr = PR_AttachSharedMemory( shm , 0 ); + if ( NULL == addr ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Attach: Error: %ld. OSError: %ld", PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Attach: success: %p", addr )); + + sem1 = PR_OpenSemaphore( SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0 ); + PR_ASSERT( sem1 ); + + sem2 = PR_OpenSemaphore( SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 1 ); + PR_ASSERT( sem1 ); + + strcpy( (char*)addr, "FooBar" ); + + child_argv[0] = "nameshm1"; + child_argv[1] = "-C"; + child_argv[2] = "-p"; + sprintf( buf, "%d", optPing ); + child_argv[3] = buf; + child_argv[4] = optName; + child_argv[5] = NULL; + + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + PR_ASSERT( proc ); + + PR_Sleep( PR_SecondsToInterval(4)); + + *addr = 1; + for ( i = 0 ; i < optPing ; i++ ) + { + rc = PR_WaitSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + (*addr)++; + PR_ASSERT( (*addr % 2) == 1 ); + if ( optVerbose ) + PR_LOG( lm, msgLevel, + ( "nameshm1: Server pong: %d, i: %d", *addr, i)); + + + rc = PR_PostSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + } + + rc = PR_WaitProcess( proc, &exit_status ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_CloseSemaphore( sem2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DeleteSemaphore( SEM_NAME1 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DeleteSemaphore( SEM_NAME2 ); + PR_ASSERT( PR_FAILURE != rc ); + + rc = PR_DetachSharedMemory( shm, addr ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Detach: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Detach: success: " )); + + rc = PR_CloseSharedMemory( shm ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Close: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Close: success: " )); + + rc = PR_DeleteSharedMemory( optName ); + if ( PR_FAILURE == rc ) + { + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: Error: %ld. OSError: %ld", + PR_GetError(), PR_GetOSError())); + failed_already = 1; + return; + } + PR_LOG( lm, msgLevel, + ( "nameshm1: Server: Destroy: success" )); + + return; +} /* end ClientServerTest() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Cdvw:s:p:i:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* debug mode */ + optVerbose = 1; + /* no break! fall into debug option */ + case 'd': /* debug mode */ + debug = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'w': /* try writing to memory mapped read-only */ + optWriteRO = 1; + break; + case 'C': + optClient = 1; + break; + case 's': + optSize = atol(opt->value) * 1024; + break; + case 'p': + optPing = atol(opt->value); + break; + case 'i': + optClientIterations = atol(opt->value); + break; + default: + strcpy( optName, opt->value ); + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + PR_LOG( lm, msgLevel, + ( "nameshm1: Starting" )); + + if ( optClient ) + { + DoClient(); + } else { + BasicTest(); + if ( failed_already != 0 ) + goto Finished; + ReadOnlyTest(); + if ( failed_already != 0 ) + goto Finished; + ClientServerTest(); + } + +Finished: + if ( debug ) printf("%s\n", (failed_already)? "FAIL" : "PASS" ); + return( (failed_already)? 1 : 0 ); +} /* main() */ +/* end instrumt.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/nbconn.c b/src/libs/xpcom18a4/nsprpub/pr/tests/nbconn.c new file mode 100644 index 00000000..d2fe6093 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/nbconn.c @@ -0,0 +1,591 @@ +/* -*- 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 ***** */ + +/* + * A test for nonblocking connect. Functions tested include PR_Connect, + * PR_Poll, and PR_GetConnectStatus. + * + * The test should be invoked with a host name, for example: + * nbconn www.netscape.com + * It will do a nonblocking connect to port 80 (HTTP) on that host, + * and when connected, issue the "GET /" HTTP command. + * + * You should run this test in three ways: + * 1. To a known web site, such as www.netscape.com. The HTML of the + * top-level page at the web site should be printed. + * 2. To a machine not running a web server at port 80. This test should + * fail. Ideally the error code should be PR_CONNECT_REFUSED_ERROR. + * But it is possible to return PR_UNKNOWN_ERROR on certain platforms. + * 3. To an unreachable machine, for example, a machine that is off line. + * The test should fail after the connect times out. Ideally the + * error code should be PR_IO_TIMEOUT_ERROR, but it is possible to + * return PR_UNKNOWN_ERROR on certain platforms. + */ + +#include "nspr.h" +#include "plgetopt.h" +#include + +#ifdef XP_MAC +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +static char *hosts[4] = {"cynic", "warp", "gandalf", "neon"}; +#endif + +#define SERVER_MAX_BIND_COUNT 100 +#define DATA_BUF_SIZE 256 +#define TCP_SERVER_PORT 10000 +#define TCP_UNUSED_PORT 211 + +typedef struct Server_Param { + PRFileDesc *sp_fd; /* server port */ +} Server_Param; +static void PR_CALLBACK TCP_Server(void *arg); + +int _debug_on; +#define DPRINTF(arg) if (_debug_on) printf arg + +static PRIntn connection_success_test(); +static PRIntn connection_failure_test(); + +int main(int argc, char **argv) +{ + PRHostEnt he; + char buf[1024]; + PRNetAddr addr; + PRPollDesc pd; + PRStatus rv; + PRSocketOptionData optData; + const char *hostname = NULL; + PRIntn default_case, n, bytes_read, bytes_sent; + PRInt32 failed_already = 0; +#ifdef XP_MAC + int index; + PRIntervalTime timeout; +#endif + + /* + * -d debug mode + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* debug mode */ + hostname = opt->value; + break; + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + +#ifdef XP_MAC + SetupMacPrintfLog("nbconn.log"); + for (index=0; index<4; index++) { + argv[1] = hosts[index]; + timeout = PR_INTERVAL_NO_TIMEOUT; + if (index == 3) + timeout = PR_SecondsToInterval(10UL); +#endif + + + PR_STDIO_INIT(); +#ifndef XP_MAC + if (hostname) + default_case = 0; + else + default_case = 1; +#endif + + if (default_case) { + + /* + * In the default case the following tests are executed: + * 1. successful connection: a server thread accepts a connection + * from the main thread + * 2. unsuccessful connection: the main thread tries to connect to a + * non-existent port and expects to get an error + */ + rv = connection_success_test(); + if (rv == 0) + rv = connection_failure_test(); + return rv; + } else { + PRFileDesc *sock; + + if (PR_GetHostByName(argv[1], buf, sizeof(buf), &he) == PR_FAILURE) { + printf( "Unknown host: %s\n", argv[1]); + exit(1); + } else { + printf( "host: %s\n", buf); + } + PR_EnumerateHostEnt(0, &he, 80, &addr); + + sock = PR_NewTCPSocket(); + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(sock, &optData); + rv = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { + printf( "Connect in progress\n"); + } + + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); +#endif + if (n == -1) { + printf( "PR_Poll failed\n"); + exit(1); + } + printf( "PR_Poll returns %d\n", n); + if (pd.out_flags & PR_POLL_READ) { + printf( "PR_POLL_READ\n"); + } + if (pd.out_flags & PR_POLL_WRITE) { + printf( "PR_POLL_WRITE\n"); + } + if (pd.out_flags & PR_POLL_EXCEPT) { + printf( "PR_POLL_EXCEPT\n"); + } + if (pd.out_flags & PR_POLL_ERR) { + printf( "PR_POLL_ERR\n"); + } + if (pd.out_flags & PR_POLL_NVAL) { + printf( "PR_POLL_NVAL\n"); + } + + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + printf("PR_GetConnectStatus: connect succeeded\n"); + /* Mac and Win16 have trouble printing to the console. */ +#if !defined(XP_MAC) && !defined(WIN16) + PR_Write(sock, "GET /\r\n\r\n", 9); + PR_Shutdown(sock, PR_SHUTDOWN_SEND); + pd.in_flags = PR_POLL_READ; + while (1) { + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + printf( "poll returns %d\n", n); + n = PR_Read(sock, buf, sizeof(buf)); + printf( "read returns %d\n", n); + if (n <= 0) { + break; + } + PR_Write(PR_STDOUT, buf, n); + } +#endif + } else { + if (PR_GetError() == PR_IN_PROGRESS_ERROR) { + printf( "PR_GetConnectStatus: connect still in progress\n"); + exit(1); + } + printf( "PR_GetConnectStatus: connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + } + PR_Close(sock); +#ifdef XP_MAC + } /* end of for loop */ +#endif + printf( "PASS\n"); + return 0; + + } +} + + +/* + * TCP Server + * Server Thread + * Accept a connection from the client and write some data + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRFileDesc *sockfd, *newsockfd; + char data_buf[DATA_BUF_SIZE]; + PRIntn rv, bytes_read; + + sockfd = sp->sp_fd; + if ((newsockfd = PR_Accept(sockfd, NULL, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"ERROR - PR_Accept failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + return; + } + bytes_read = 0; + while (bytes_read != DATA_BUF_SIZE) { + rv = PR_Read(newsockfd, data_buf + bytes_read , + DATA_BUF_SIZE - bytes_read); + if (rv < 0) { + fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(newsockfd); + return; + } + PR_ASSERT(rv != 0); + bytes_read += rv; + } + DPRINTF(("Bytes read from client - %d\n",bytes_read)); + rv = PR_Write(newsockfd, data_buf,DATA_BUF_SIZE); + if (rv < 0) { + fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(newsockfd); + return; + } + PR_ASSERT(rv == DATA_BUF_SIZE); + DPRINTF(("Bytes written to client - %d\n",rv)); + PR_Close(newsockfd); +} + + +/* + * test for successful connection using a non-blocking socket + */ +static PRIntn +connection_success_test() +{ + PRFileDesc *sockfd = NULL, *conn_fd = NULL; + PRNetAddr netaddr; + PRInt32 i, rv; + PRPollDesc pd; + PRSocketOptionData optData; + PRThread *thr = NULL; + Server_Param sp; + char send_buf[DATA_BUF_SIZE], recv_buf[DATA_BUF_SIZE]; + PRIntn default_case, n, bytes_read, bytes_sent; + PRIntn failed_already = 0; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"ERROR - PR_Listen failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if ((conn_fd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(conn_fd, &optData); + rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE) { + if (PR_GetError() == PR_IN_PROGRESS_ERROR) { + DPRINTF(("Connect in progress\n")); + } else { + fprintf(stderr,"Error - PR_Connect failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + } + /* + * Now create a thread to accept a connection + */ + sp.sp_fd = sockfd; + thr = PR_CreateThread(PR_USER_THREAD, TCP_Server, (void *)&sp, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (thr == NULL) { + fprintf(stderr,"Error - PR_CreateThread failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + DPRINTF(("Created TCP_Server thread [0x%x]\n",thr)); + pd.fd = conn_fd; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); +#endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + PRInt32 rv; + + DPRINTF(("Connection successful\n")); + + /* + * Write some data, read it back and check data integrity to + * make sure the connection is good + */ + pd.in_flags = PR_POLL_WRITE; + bytes_sent = 0; + memset(send_buf, 'a', DATA_BUF_SIZE); + while (bytes_sent != DATA_BUF_SIZE) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv < 0) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_WRITE)); + rv = PR_Write(conn_fd, send_buf + bytes_sent, + DATA_BUF_SIZE - bytes_sent); + if (rv < 0) { + fprintf(stderr,"Error - PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT(rv > 0); + bytes_sent += rv; + } + DPRINTF(("Bytes written to server - %d\n",bytes_sent)); + PR_Shutdown(conn_fd, PR_SHUTDOWN_SEND); + pd.in_flags = PR_POLL_READ; + bytes_read = 0; + memset(recv_buf, 0, DATA_BUF_SIZE); + while (bytes_read != DATA_BUF_SIZE) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv < 0) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT((rv == 1) && (pd.out_flags == PR_POLL_READ)); + rv = PR_Read(conn_fd, recv_buf + bytes_read , + DATA_BUF_SIZE - bytes_read); + if (rv < 0) { + fprintf(stderr,"Error - PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + PR_ASSERT(rv != 0); + bytes_read += rv; + } + DPRINTF(("Bytes read from server - %d\n",bytes_read)); + /* + * verify the data read + */ + if (memcmp(send_buf, recv_buf, DATA_BUF_SIZE) != 0) { + fprintf(stderr,"ERROR - data corruption\n"); + failed_already=1; + goto def_exit; + } + DPRINTF(("Data integrity verified\n")); + } else { + fprintf(stderr,"PR_GetConnectStatus: connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already = 1; + goto def_exit; + } +def_exit: + if (thr) { + PR_JoinThread(thr); + thr = NULL; + } + if (sockfd) { + PR_Close(sockfd); + sockfd = NULL; + } + if (conn_fd) { + PR_Close(conn_fd); + conn_fd = NULL; + } + if (failed_already) + return 1; + else + return 0; + +} + +/* + * test for connection to a non-existent port using a non-blocking socket + */ +static PRIntn +connection_failure_test() +{ + PRFileDesc *sockfd = NULL, *conn_fd = NULL; + PRNetAddr netaddr; + PRInt32 i, rv; + PRPollDesc pd; + PRSocketOptionData optData; + PRIntn n, failed_already = 0; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"ERROR - PR_Bind failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"ERROR - PR_GetSockName failed: (%d,%d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } +#ifdef AIX + /* + * On AIX, set to unused/reserved port + */ + netaddr.inet.port = PR_htons(TCP_UNUSED_PORT); +#endif + if ((conn_fd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"Error - PR_NewTCPSocket failed\n"); + failed_already=1; + goto def_exit; + } + optData.option = PR_SockOpt_Nonblocking; + optData.value.non_blocking = PR_TRUE; + PR_SetSocketOption(conn_fd, &optData); + rv = PR_Connect(conn_fd, &netaddr, PR_INTERVAL_NO_TIMEOUT); + if (rv == PR_FAILURE) { + DPRINTF(("PR_Connect to a non-listen port failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError())); + } else { + PR_ASSERT(rv == PR_SUCCESS); + fprintf(stderr,"Error - PR_Connect succeeded, expected to fail\n"); + failed_already=1; + goto def_exit; + } + pd.fd = conn_fd; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; +#ifndef XP_MAC + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); +#else + n = PR_Poll(&pd, 1, timeout); +#endif + if (n == -1) { + fprintf(stderr,"Error - PR_Poll failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + goto def_exit; + } + if (PR_GetConnectStatus(&pd) == PR_SUCCESS) { + PRInt32 rv; + fprintf(stderr,"PR_GetConnectStatus succeeded, expected to fail\n"); + failed_already = 1; + goto def_exit; + } + rv = PR_GetError(); + DPRINTF(("Connection failed, successfully with PR_Error %d\n",rv)); +def_exit: + if (sockfd) { + PR_Close(sockfd); + sockfd = NULL; + } + if (conn_fd) { + PR_Close(conn_fd); + conn_fd = NULL; + } + if (failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/nblayer.c b/src/libs/xpcom18a4/nsprpub/pr/tests/nblayer.c new file mode 100644 index 00000000..4ecc955c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/nblayer.c @@ -0,0 +1,707 @@ +/* -*- 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 "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prlog.h" +#include "prerror.h" +#include "prnetdb.h" +#include "prthread.h" + +#include "plerror.h" +#include "plgetopt.h" +#include "prwin16.h" + +#include +#include + +/* +** Testing layering of I/O +** +** The layered server +** A thread that acts as a server. It creates a TCP listener with a dummy +** layer pushed on top. Then listens for incoming connections. Each connection +** request for connection will be layered as well, accept one request, echo +** it back and close. +** +** The layered client +** Pretty much what you'd expect. +*/ + +static PRFileDesc *logFile; +static PRDescIdentity identity; +static PRNetAddr server_address; + +static PRIOMethods myMethods; + +typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState; +typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState; + +struct PRFilePrivate +{ + RcvState rcvstate; + XmtState xmtstate; + PRInt32 rcvreq, rcvinprogress; + PRInt32 xmtreq, xmtinprogress; +}; + +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; + +static PRIntn minor_iterations = 5; +static PRIntn major_iterations = 1; +static Verbosity verbosity = quiet; +static PRUint16 default_port = 12273; + +static PRFileDesc *PushLayer(PRFileDesc *stack) +{ + PRStatus rv; + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); + layer->secret = PR_NEWZAP(PRFilePrivate); + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); + PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > quiet) + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); + return stack; +} /* PushLayer */ + +static PRFileDesc *PopLayer(PRFileDesc *stack) +{ + PRFileDesc *popped = PR_PopIOLayer(stack, identity); + if (verbosity > quiet) + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); + PR_DELETE(popped->secret); + popped->dtor(popped); + return stack; +} /* PopLayer */ + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRIntn mits; + PRInt32 ready; + PRUint8 buffer[100]; + PRPollDesc polldesc; + PRIntn empty_flags = 0; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + + /* Initialize the buffer so that Purify won't complain */ + memset(buffer, 0, sizeof(buffer)); + + rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); + if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError())) + { + if (verbosity > quiet) + PR_fprintf(logFile, "Client connect 'in progress'\n"); + do + { + polldesc.fd = stack; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + if (verbosity > quiet) + PR_fprintf( + logFile, "Client connect 'in progress' [0x%x]\n", + polldesc.out_flags); + rv = PR_GetConnectStatus(&polldesc); + if ((PR_FAILURE == rv) + && (PR_IN_PROGRESS_ERROR != PR_GetError())) break; + } while (PR_FAILURE == rv); + } + PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > chatty) + PR_fprintf(logFile, "Client created connection\n"); + + for (mits = 0; mits < minor_iterations; ++mits) + { + bytes_sent = 0; + if (verbosity > quiet) + PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer)); + do + { + if (verbosity > chatty) + PR_fprintf( + logFile, "Client sending %d bytes\n", + sizeof(buffer) - bytes_sent); + ready = PR_Send( + stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent, + empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Client send status [%d]\n", ready); + if (0 < ready) bytes_sent += ready; + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = stack; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_WRITE; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + } + else break; + } while (bytes_sent < sizeof(buffer)); + PR_ASSERT(sizeof(buffer) == bytes_sent); + + bytes_read = 0; + do + { + if (verbosity > chatty) + PR_fprintf( + logFile, "Client receiving %d bytes\n", + bytes_sent - bytes_read); + ready = PR_Recv( + stack, buffer + bytes_read, bytes_sent - bytes_read, + empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf( + logFile, "Client receive status [%d]\n", ready); + if (0 < ready) bytes_read += ready; + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = stack; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_READ; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + } + else break; + } while (bytes_read < bytes_sent); + if (verbosity > chatty) + PR_fprintf(logFile, "Client received %d bytes\n", bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + } + + if (verbosity > quiet) + PR_fprintf(logFile, "Client shutting down stack\n"); + + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); +} /* Client */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRInt32 ready; + PRUint8 buffer[100]; + PRFileDesc *service; + PRUintn empty_flags = 0; + struct PRPollDesc polldesc; + PRIntn bytes_read, bytes_sent; + PRFileDesc *stack = (PRFileDesc*)arg; + PRNetAddr client_address; + + do + { + if (verbosity > chatty) + PR_fprintf(logFile, "Server accepting connection\n"); + service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Server accept status [0x%p]\n", service); + if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = stack; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + } + } while (NULL == service); + PR_ASSERT(NULL != service); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server accepting connection\n"); + + do + { + bytes_read = 0; + do + { + if (verbosity > chatty) + PR_fprintf( + logFile, "Server receiving %d bytes\n", + sizeof(buffer) - bytes_read); + ready = PR_Recv( + service, buffer + bytes_read, sizeof(buffer) - bytes_read, + empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (verbosity > chatty) + PR_fprintf(logFile, "Server receive status [%d]\n", ready); + if (0 < ready) bytes_read += ready; + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = service; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_READ; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + } + else break; + } while (bytes_read < sizeof(buffer)); + + if (0 != bytes_read) + { + if (verbosity > chatty) + PR_fprintf(logFile, "Server received %d bytes\n", bytes_read); + PR_ASSERT(bytes_read > 0); + + bytes_sent = 0; + do + { + ready = PR_Send( + service, buffer + bytes_sent, bytes_read - bytes_sent, + empty_flags, PR_INTERVAL_NO_TIMEOUT); + if (0 < ready) + { + bytes_sent += ready; + } + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) + { + polldesc.fd = service; + polldesc.out_flags = 0; + polldesc.in_flags = PR_POLL_WRITE; + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); + if ((1 != ready) /* if not 1, then we're dead */ + || (0 == (polldesc.in_flags & polldesc.out_flags))) + { PR_ASSERT(!"Whoa!"); break; } + } + else break; + } while (bytes_sent < bytes_read); + PR_ASSERT(bytes_read == bytes_sent); + if (verbosity > chatty) + PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent); + } + } while (0 != bytes_read); + + if (verbosity > quiet) + PR_fprintf(logFile, "Server shutting down stack\n"); + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + +} /* Server */ + +static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd) +{ + PR_DELETE(fd->secret); /* manage my secret file object */ + return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */ +} /* MyClose */ + +static PRInt16 PR_CALLBACK MyPoll( + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) +{ + PRInt16 my_flags, new_flags; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + if (0 != (PR_POLL_READ & in_flags)) + { + /* client thinks he's reading */ + switch (mine->rcvstate) + { + case rcv_send_credit: + my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE; + break; + case rcv_data: + case rcv_get_debit: + my_flags = in_flags; + default: break; + } + } + else if (0 != (PR_POLL_WRITE & in_flags)) + { + /* client thinks he's writing */ + switch (mine->xmtstate) + { + case xmt_recv_credit: + my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ; + break; + case xmt_send_debit: + case xmt_data: + my_flags = in_flags; + default: break; + } + } + else PR_ASSERT(!"How'd I get here?"); + new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); + if (verbosity > chatty) + PR_fprintf( + logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", + in_flags, my_flags, *out_flags, new_flags); + return new_flags; +} /* MyPoll */ + +static PRFileDesc * PR_CALLBACK MyAccept( + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) +{ + PRStatus rv; + PRFileDesc *newfd, *layer = fd; + PRFileDesc *newstack; + PRFilePrivate *newsecret; + + PR_ASSERT(fd != NULL); + PR_ASSERT(fd->lower != NULL); + + newstack = PR_NEW(PRFileDesc); + if (NULL == newstack) + { + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + newsecret = PR_NEW(PRFilePrivate); + if (NULL == newsecret) + { + PR_DELETE(newstack); + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); + return NULL; + } + *newstack = *fd; /* make a copy of the accepting layer */ + *newsecret = *fd->secret; + newstack->secret = newsecret; + + newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); + if (NULL == newfd) + { + PR_DELETE(newsecret); + PR_DELETE(newstack); + return NULL; + } + + /* this PR_PushIOLayer call cannot fail */ + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); + PR_ASSERT(PR_SUCCESS == rv); + return newfd; /* that's it */ +} + +static PRInt32 PR_CALLBACK MyRecv( + PRFileDesc *fd, void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b; + PRInt32 rv; + PRFileDesc *lo = fd->lower; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + + do + { + switch (mine->rcvstate) + { + case rcv_get_debit: + b = (char*)&mine->rcvreq; + mine->rcvreq = amount; + rv = lo->methods->recv( + lo, b + mine->rcvinprogress, + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); + if (0 == rv) goto closed; + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ + mine->rcvstate = rcv_send_credit; + mine->rcvinprogress = 0; + case rcv_send_credit: + b = (char*)&mine->rcvreq; + rv = lo->methods->send( + lo, b + mine->rcvinprogress, + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ + mine->rcvstate = rcv_data; + mine->rcvinprogress = 0; + case rcv_data: + b = (char*)buf; + rv = lo->methods->recv( + lo, b + mine->rcvinprogress, + mine->rcvreq - mine->rcvinprogress, flags, timeout); + if (0 == rv) goto closed; + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->rcvinprogress += rv; /* accumulate the read */ + if (mine->rcvinprogress < amount) break; /* loop */ + mine->rcvstate = rcv_get_debit; + mine->rcvinprogress = 0; + return mine->rcvreq; /* << -- that's it! */ + default: + break; + } + } while (-1 != rv); + return rv; +closed: + mine->rcvinprogress = 0; + mine->rcvstate = rcv_get_debit; + return 0; +} /* MyRecv */ + +static PRInt32 PR_CALLBACK MySend( + PRFileDesc *fd, const void *buf, PRInt32 amount, + PRIntn flags, PRIntervalTime timeout) +{ + char *b; + PRInt32 rv; + PRFileDesc *lo = fd->lower; + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; + + do + { + switch (mine->xmtstate) + { + case xmt_send_debit: + b = (char*)&mine->xmtreq; + mine->xmtreq = amount; + rv = lo->methods->send( + lo, b - mine->xmtinprogress, + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; + mine->xmtstate = xmt_recv_credit; + mine->xmtinprogress = 0; + case xmt_recv_credit: + b = (char*)&mine->xmtreq; + rv = lo->methods->recv( + lo, b + mine->xmtinprogress, + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; + mine->xmtstate = xmt_data; + mine->xmtinprogress = 0; + case xmt_data: + b = (char*)buf; + rv = lo->methods->send( + lo, b + mine->xmtinprogress, + mine->xmtreq - mine->xmtinprogress, flags, timeout); + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; + mine->xmtinprogress += rv; + if (mine->xmtinprogress < amount) break; + mine->xmtstate = xmt_send_debit; + mine->xmtinprogress = 0; + return mine->xmtreq; /* <<-- That's the one! */ + default: + break; + } + } while (-1 != rv); + return rv; +} /* MySend */ + +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) +{ + PRIntn verbage = (PRIntn)verbosity + delta; + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; + return (Verbosity)verbage; +} /* ChangeVerbosity */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PLOptStatus os; + PRFileDesc *client, *service; + PRNetAddr any_address; + const char *server_name = NULL; + const PRIOMethods *stubMethods; + PRThread *client_thread, *server_thread; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRSocketOptionData socket_noblock, socket_nodelay; + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: + server_name = opt->value; + break; + case 'd': /* debug mode */ + if (verbosity < noisy) + verbosity = ChangeVerbosity(verbosity, 1); + break; + case 'q': /* debug mode */ + if (verbosity > silent) + verbosity = ChangeVerbosity(verbosity, -1); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'C': /* number of threads waiting */ + major_iterations = atoi(opt->value); + break; + case 'c': /* number of client threads */ + minor_iterations = atoi(opt->value); + break; + case 'p': /* default port */ + default_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + logFile = PR_GetSpecialFD(PR_StandardError); + identity = PR_GetUniqueIdentity("Dummy"); + stubMethods = PR_GetDefaultIOMethods(); + + /* + ** The protocol we're going to implement is one where in order to initiate + ** a send, the sender must first solicit permission. Therefore, every + ** send is really a send - receive - send sequence. + */ + myMethods = *stubMethods; /* first get the entire batch */ + myMethods.accept = MyAccept; /* then override the ones we care about */ + myMethods.recv = MyRecv; /* then override the ones we care about */ + myMethods.send = MySend; /* then override the ones we care about */ + myMethods.close = MyClose; /* then override the ones we care about */ + myMethods.poll = MyPoll; /* then override the ones we care about */ + + if (NULL == server_name) + rv = PR_InitializeNetAddr( + PR_IpAddrLoopback, default_port, &server_address); + else + { + rv = PR_StringToNetAddr(server_name, &server_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_InitializeNetAddr( + PR_IpAddrNull, default_port, &server_address); + } + PR_ASSERT(PR_SUCCESS == rv); + + socket_noblock.value.non_blocking = PR_TRUE; + socket_noblock.option = PR_SockOpt_Nonblocking; + socket_nodelay.value.no_delay = PR_TRUE; + socket_nodelay.option = PR_SockOpt_NoDelay; + + /* one type w/o layering */ + + while (major_iterations-- > 0) + { + if (verbosity > silent) + PR_fprintf(logFile, "Beginning non-layered test\n"); + + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + + rv = PR_SetSocketOption(client, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(client, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > silent) + PR_fprintf(logFile, "Ending non-layered test\n"); + + /* with layering */ + if (verbosity > silent) + PR_fprintf(logFile, "Beginning layered test\n"); + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); + + rv = PR_SetSocketOption(client, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_noblock); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(client, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_SetSocketOption(service, &socket_nodelay); + PR_ASSERT(PR_SUCCESS == rv); + + PushLayer(client); + PushLayer(service); + + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); + + server_thread = PR_CreateThread( + PR_USER_THREAD, Server, service, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != server_thread); + + client_thread = PR_CreateThread( + PR_USER_THREAD, Client, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 16 * 1024); + PR_ASSERT(NULL != client_thread); + + rv = PR_JoinThread(client_thread); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_JoinThread(server_thread); + PR_ASSERT(PR_SUCCESS == rv); + + rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv); + if (verbosity > silent) + PR_fprintf(logFile, "Ending layered test\n"); + } + return 0; +} /* main */ + +/* nblayer.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/nonblock.c b/src/libs/xpcom18a4/nsprpub/pr/tests/nonblock.c new file mode 100644 index 00000000..102fd84b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/nonblock.c @@ -0,0 +1,273 @@ +/* -*- 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 "nspr.h" +#include "prio.h" +#include "prerror.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" +#include "plerror.h" +#ifndef XP_MAC +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#include +#include +#include + +#define NUMBER_ROUNDS 5 + +#if defined(WIN16) +/* +** Make win16 unit_time interval 300 milliseconds, others get 100 +*/ +#define UNIT_TIME 200 /* unit time in milliseconds */ +#else +#define UNIT_TIME 100 /* unit time in milliseconds */ +#endif +#define CHUNK_SIZE 10 +#undef USE_PR_SELECT /* If defined, we use PR_Select. + * If not defined, use PR_Poll instead. */ + +#if defined(USE_PR_SELECT) +#include "pprio.h" +#endif + +#ifdef XP_MAC +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static void PR_CALLBACK +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn)arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[CHUNK_SIZE]; + int i; + PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); + PRSocketOptionData optval; + PRStatus retVal; + PRInt32 nBytes; + + /* Initialize the buffer so that Purify won't complain */ + memset(buf, 0, sizeof(buf)); + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((PRUint16)port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.ip); + + /* time 1 */ + PR_Sleep(unitTime); + sock = PR_NewTCPSocket(); + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(sock, &optval); + retVal = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + if (retVal == PR_FAILURE && PR_GetError() == PR_IN_PROGRESS_ERROR) { +#if !defined(USE_PR_SELECT) + PRPollDesc pd; + PRInt32 n; + fprintf(stderr, "connect: EWOULDBLOCK, good\n"); + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE; + n = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(n == 1); + PR_ASSERT(pd.out_flags == PR_POLL_WRITE); +#else + PR_fd_set writeSet; + PRInt32 n; + fprintf(stderr, "connect: EWOULDBLOCK, good\n"); + PR_FD_ZERO(&writeSet); + PR_FD_SET(sock, &writeSet); + n = PR_Select(0, NULL, &writeSet, NULL, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(n == 1); + PR_ASSERT(PR_FD_ISSET(sock, &writeSet)); +#endif + } + printf("client connected\n"); + fflush(stdout); + + /* time 4, 7, 11, etc. */ + for (i = 0; i < NUMBER_ROUNDS; i++) { + PR_Sleep(3 * unitTime); + nBytes = PR_Write(sock, buf, sizeof(buf)); + if (nBytes == -1) { + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "write: EWOULDBLOCK\n"); + exit(1); + } else { + fprintf(stderr, "write: failed\n"); + } + } + printf("client sent %d bytes\n", nBytes); + fflush(stdout); + } + + PR_Close(sock); +} + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PRFileDesc *listenSock, *sock; + PRUint16 listenPort; + PRNetAddr addr; + char buf[CHUNK_SIZE]; + PRThread *clientThread; + PRInt32 retVal; + PRSocketOptionData optval; + PRIntn i; + PRIntervalTime unitTime = PR_MillisecondsToInterval(UNIT_TIME); + +#ifdef XP_MAC + SetupMacPrintfLog("nonblock.log"); +#endif + + /* Create a listening socket */ + if ((listenSock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on port %hu\n\n", + listenPort); + printf("%s", buf); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + printf("client thread created.\n"); + + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(listenSock, &optval); + /* time 0 */ + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock != NULL || PR_GetError() != PR_WOULD_BLOCK_ERROR) { + PL_PrintError("First Accept\n"); + fprintf(stderr, "First PR_Accept() xxx\n" ); + exit(1); + } + printf("accept: EWOULDBLOCK, good\n"); + fflush(stdout); + /* time 2 */ + PR_Sleep(2 * unitTime); + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + PL_PrintError("Second Accept\n"); + fprintf(stderr, "Second PR_Accept() failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("accept: succeeded, good\n"); + fflush(stdout); + PR_Close(listenSock); + + PR_SetSocketOption(sock, &optval); + + /* time 3, 5, 6, 8, etc. */ + for (i = 0; i < NUMBER_ROUNDS; i++) { + PR_Sleep(unitTime); + retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_WOULD_BLOCK_ERROR) { + PL_PrintError("First Receive:\n"); + fprintf(stderr, "First PR_Recv: retVal: %ld, Error: %ld\n", + retVal, PR_GetError()); + exit(1); + } + printf("read: EWOULDBLOCK, good\n"); + fflush(stdout); + PR_Sleep(2 * unitTime); + retVal = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); + if (retVal != CHUNK_SIZE) { + PL_PrintError("Second Receive:\n"); + fprintf(stderr, "Second PR_Recv: retVal: %ld, Error: %ld\n", + retVal, PR_GetError()); + exit(1); + } + printf("read: %d bytes, good\n", retVal); + fflush(stdout); + } + PR_Close(sock); + + printf("All tests finished\n"); + printf("PASS\n"); + return 0; +} + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ntioto.c b/src/libs/xpcom18a4/nsprpub/pr/tests/ntioto.c new file mode 100644 index 00000000..44e2a608 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ntioto.c @@ -0,0 +1,317 @@ +/* -*- 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 ***** */ + +/* +** File: ntioto.c +** Description: +** This test, ntioto.c, was designed to reproduce a bug reported by NES +** on WindowsNT (fibers implementation). NSPR was asserting in ntio.c +** after PR_AcceptRead() had timed out. I/O performed subsequent to the +** call to PR_AcceptRead() could complete on a CPU other than the one +** on which it was started. The assert in ntio.c detected this, then +** asserted. +** +** Design: +** This test will fail with an assert in ntio.c if the problem it was +** designed to catch occurs. It returns 0 otherwise. +** +** The main() thread initializes and tears things down. A file is +** opened for writing; this file will be written to by AcceptThread() +** and JitterThread(). Main() creates a socket for reading, listens +** and binds the socket. +** +** ConnectThread() connects to the socket created by main, then polls +** the "state" variable. When state is AllDone, ConnectThread() exits. +** +** AcceptThread() calls PR_AcceptRead() on the socket. He fully expects +** it to time out. After the timeout, AccpetThread() interacts with +** JitterThread() via a common condition variable and the state +** variable. The two threads ping-pong back and forth, each thread +** writes the the file opened by main. This should provoke the +** condition reported by NES (if we didn't fix it). +** +** The failure is not solid. It may fail within a few ping-pongs between +** AcceptThread() and JitterThread() or may take a while. The default +** iteration count, jitter, is set by DEFAULT_JITTER. This may be +** modified at the command line with the -j option. +** +*/ + +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRIntn verbose = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +/* JITTER_DEFAULT: the number of times AcceptThread() and JitterThread() ping-pong */ +#define JITTER_DEFAULT 100000 +#define BASE_PORT 9867 + +PRIntervalTime timeout; +PRNetAddr listenAddr; +PRFileDesc *listenSock; +PRLock *ml; +PRCondVar *cv; +volatile enum { + RunJitter, + RunAcceptRead, + AllDone +} state = RunAcceptRead; +PRFileDesc *file1; +PRIntn iCounter = 0; +PRIntn jitter = JITTER_DEFAULT; +PRBool resume = PR_FALSE; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("Template: Help(): display your help message(s) here"); + exit(1); +} /* end Help() */ + + +/* +** static computation of PR_AcceptRead() buffer size. +*/ +#define ACCEPT_READ_DATASIZE 10 +#define ACCEPT_READ_BUFSIZE (PR_ACCEPT_READ_BUF_OVERHEAD + ACCEPT_READ_DATASIZE) + +static void AcceptThread(void *arg) +{ + PRIntn bytesRead; + char dataBuf[ACCEPT_READ_BUFSIZE]; + PRFileDesc *arSock; + PRNetAddr *arAddr; + + bytesRead = PR_AcceptRead( listenSock, + &arSock, + &arAddr, + dataBuf, + ACCEPT_READ_DATASIZE, + PR_SecondsToInterval(1)); + + if ( bytesRead == -1 && PR_GetError() == PR_IO_TIMEOUT_ERROR ) + if ( debug ) printf("AcceptRead timed out\n"); + else + if ( debug ) printf("Oops! read: %d, error: %d\n", bytesRead, PR_GetError()); + + while( state != AllDone ) { + PR_Lock( ml ); + while( state != RunAcceptRead ) + PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT ); + if ( ++iCounter >= jitter ) + state = AllDone; + else + state = RunJitter; + if ( verbose ) printf("."); + PR_NotifyCondVar( cv ); + PR_Unlock( ml ); + PR_Write( file1, ".", 1 ); + } + + return; +} /* end AcceptThread() */ + +static void JitterThread(void *arg) +{ + while( state != AllDone ) { + PR_Lock( ml ); + while( state != RunJitter && state != AllDone ) + PR_WaitCondVar( cv, PR_INTERVAL_NO_TIMEOUT ); + if ( state != AllDone) + state = RunAcceptRead; + if ( verbose ) printf("+"); + PR_NotifyCondVar( cv ); + PR_Unlock( ml ); + PR_Write( file1, "+", 1 ); + } + return; +} /* end Goofy() */ + +static void ConnectThread( void *arg ) +{ + PRStatus rv; + PRFileDesc *clientSock; + PRNetAddr serverAddress; + clientSock = PR_NewTCPSocket(); + + PR_ASSERT(clientSock); + + if ( resume ) { + if ( debug ) printf("pausing 3 seconds before connect\n"); + PR_Sleep( PR_SecondsToInterval(3)); + } + + memset(&serverAddress, 0, sizeof(serverAddress)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddress); + PR_ASSERT( PR_SUCCESS == rv ); + rv = PR_Connect( clientSock, + &serverAddress, + PR_SecondsToInterval(1)); + PR_ASSERT( PR_SUCCESS == rv ); + + /* that's all we do. ... Wait for the acceptread() to timeout */ + while( state != AllDone ) + PR_Sleep( PR_SecondsToInterval(1)); + return; +} /* end ConnectThread() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRThread *tJitter; + PRThread *tAccept; + PRThread *tConnect; + PRStatus rv; + /* This test if valid for WinNT only! */ + +#if !defined(WINNT) + return 0; +#endif + + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdrvj:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + verbose = 1; + msgLevel = PR_LOG_DEBUG; + break; + case 'j': + jitter = atoi(opt->value); + if ( jitter == 0) + jitter = JITTER_DEFAULT; + break; + case 'r': + resume = PR_TRUE; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + /* set concurrency */ + PR_SetConcurrency( 4 ); + + /* setup thread synchronization mechanics */ + ml = PR_NewLock(); + cv = PR_NewCondVar( ml ); + + /* setup a tcp socket */ + memset(&listenAddr, 0, sizeof(listenAddr)); + rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr); + PR_ASSERT( PR_SUCCESS == rv ); + + listenSock = PR_NewTCPSocket(); + PR_ASSERT( listenSock ); + + rv = PR_Bind( listenSock, &listenAddr); + PR_ASSERT( PR_SUCCESS == rv ); + + rv = PR_Listen( listenSock, 5 ); + PR_ASSERT( PR_SUCCESS == rv ); + + /* open a file for writing, provoke bug */ + file1 = PR_Open("xxxTestFile", PR_CREATE_FILE | PR_RDWR, 666); + + /* create Connect thread */ + tConnect = PR_CreateThread( + PR_USER_THREAD, ConnectThread, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tConnect ); + + /* create jitter off thread */ + tJitter = PR_CreateThread( + PR_USER_THREAD, JitterThread, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tJitter ); + + /* create acceptread thread */ + tAccept = PR_CreateThread( + PR_USER_THREAD, AcceptThread, NULL, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, 0 ); + PR_ASSERT( tAccept ); + + /* wait for all threads to quit, then terminate gracefully */ + PR_JoinThread( tConnect ); + PR_JoinThread( tAccept ); + PR_JoinThread( tJitter ); + PR_Close( listenSock ); + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + PR_Close( file1 ); + PR_Delete( "xxxTestFile"); + + /* test return and exit */ + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end ntioto.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ntoh.c b/src/libs/xpcom18a4/nsprpub/pr/tests/ntoh.c new file mode 100644 index 00000000..e424f548 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ntoh.c @@ -0,0 +1,125 @@ +/* -*- 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) 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 ***** */ + +/* + * A test program for PR_htons, PR_ntohs, PR_htonl, PR_ntohl, + * PR_htonll, and PR_ntohll. + */ + +#include "prnetdb.h" + +#include +#include +#include + +/* Byte sequence in network byte order */ +static unsigned char bytes_n[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + +/* Integers in host byte order */ +static PRUint16 s_h = 0x0102; +static PRUint32 l_h = 0x01020304; +static PRUint64 ll_h = LL_INIT(0x01020304, 0x05060708); + +int main() +{ + union { + PRUint16 s; + PRUint32 l; + PRUint64 ll; + unsigned char bytes[8]; + } un; + + un.s = s_h; + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + un.s = PR_htons(un.s); + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + if (memcmp(un.bytes, bytes_n, 2)) { + fprintf(stderr, "PR_htons failed\n"); + exit(1); + } + un.s = PR_ntohs(un.s); + printf("%u %u\n", + un.bytes[0], un.bytes[1]); + if (un.s != s_h) { + fprintf(stderr, "PR_ntohs failed\n"); + exit(1); + } + + un.l = l_h; + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + un.l = PR_htonl(un.l); + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + if (memcmp(un.bytes, bytes_n, 4)) { + fprintf(stderr, "PR_htonl failed\n"); + exit(1); + } + un.l = PR_ntohl(un.l); + printf("%u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3]); + if (un.l != l_h) { + fprintf(stderr, "PR_ntohl failed\n"); + exit(1); + } + + un.ll = ll_h; + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + un.ll = PR_htonll(un.ll); + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + if (memcmp(un.bytes, bytes_n, 8)) { + fprintf(stderr, "PR_htonll failed\n"); + exit(1); + } + un.ll = PR_ntohll(un.ll); + printf("%u %u %u %u %u %u %u %u\n", + un.bytes[0], un.bytes[1], un.bytes[2], un.bytes[3], + un.bytes[4], un.bytes[5], un.bytes[6], un.bytes[7]); + if (LL_NE(un.ll, ll_h)) { + fprintf(stderr, "PR_ntohll failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/obsints.c b/src/libs/xpcom18a4/nsprpub/pr/tests/obsints.c new file mode 100644 index 00000000..87182f55 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/obsints.c @@ -0,0 +1,83 @@ +/* -*- 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) 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 ***** */ + +/* + * Test: obsints.c + * + * Description: make sure that protypes.h defines the obsolete integer + * types intn, uintn, uint, int8, uint8, int16, uint16, int32, uint32, + * int64, and uint64. + */ + +#include + +#ifdef NO_NSPR_10_SUPPORT + +/* nothing to do */ +int main() +{ + printf("PASS\n"); + return 0; +} + +#else /* NO_NSPR_10_SUPPORT */ + +#include "prtypes.h" /* which includes protypes.h */ + +int main() +{ + /* + * Compilation fails if any of these integer types are not + * defined by protypes.h. + */ + intn in; + uintn uin; + uint ui; + int8 i8; + uint8 ui8; + int16 i16; + uint16 ui16; + int32 i32; + uint32 ui32; + int64 i64; + uint64 ui64; + + printf("PASS\n"); + return 0; +} + +#endif /* NO_NSPR_10_SUPPORT */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_2long.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_2long.c new file mode 100644 index 00000000..27f64d79 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_2long.c @@ -0,0 +1,117 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_2long.c +** +** Description: Test Program to verify the PR_NAME_TOO_LONG_ERROR +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plerror.h" +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +static PRFileDesc *t1; +PRIntn error_code; + +/* + * should exceed any system's maximum file name length + * Note: was set at 4096. This is legal on some unix (Linux 2.1+) platforms. + * + */ +#define TOO_LONG 5000 + +int main(int argc, char **argv) +{ + char nameTooLong[TOO_LONG]; + int i; + + /* Generate a really long pathname */ + for (i = 0; i < TOO_LONG - 1; i++) { + if (i % 10 == 0) { + nameTooLong[i] = '/'; + } else { + nameTooLong[i] = 'a'; + } + } + nameTooLong[TOO_LONG - 1] = 0; + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + t1 = PR_Open(nameTooLong, PR_RDWR, 0666); + if (t1 == NULL) { + if (PR_GetError() == PR_NAME_TOO_LONG_ERROR) { + PL_PrintError("error code is"); + printf ("PASS\n"); + return 0; + } + else { + PL_PrintError("error code is"); + printf ("FAIL\n"); + return 1; + } + } + + else { + printf ("Test passed\n"); + return 0; + } + + + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_excl.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_excl.c new file mode 100644 index 00000000..b0bb6ace --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_excl.c @@ -0,0 +1,156 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_excl.c +** +** Description: Test Program to verify function of PR_EXCL open flag +** +** Modification History: +** 27-Oct-1999 lth. Initial version +***********************************************************************/ + +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("op_excl: Help"); + printf("op_excl [-d]"); + printf("-d enables debug messages"); + exit(1); +} /* end Help() */ + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRFileDesc *fd; + PRStatus rv; + PRInt32 written; + char outBuf[] = "op_excl.c test file"; +#define OUT_SIZE sizeof(outBuf) +#define NEW_FILENAME "xxxExclNewFile" + + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hd"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + + /* + ** First, open a file, PR_EXCL, we believe not to exist + */ + fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 ); + if ( NULL == fd ) { + if (debug) fprintf( stderr, "Open exclusive. Expected success, got failure\n"); + failed_already = 1; + goto Finished; + } + + written = PR_Write( fd, outBuf, OUT_SIZE ); + if ( OUT_SIZE != written ) { + if (debug) fprintf( stderr, "Write after open exclusive failed\n"); + failed_already = 1; + goto Finished; + } + + rv = PR_Close(fd); + if ( PR_FAILURE == rv ) { + if (debug) fprintf( stderr, "Close after open exclusive failed\n"); + failed_already = 1; + goto Finished; + } + + /* + ** Second, open the same file, PR_EXCL, expect it to fail + */ + fd = PR_Open( NEW_FILENAME, PR_CREATE_FILE | PR_EXCL | PR_WRONLY, 0666 ); + if ( NULL != fd ) { + if (debug) fprintf( stderr, "Open exclusive. Expected failure, got success\n"); + failed_already = 1; + PR_Close(fd); + } + + rv = PR_Delete( NEW_FILENAME ); + if ( PR_FAILURE == rv ) { + if (debug) fprintf( stderr, "PR_Delete() failed\n"); + failed_already = 1; + } + +Finished: + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end op_excl.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_filnf.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_filnf.c new file mode 100644 index 00000000..aeb2014d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_filnf.c @@ -0,0 +1,91 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_filnf.c +** +** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR +** This test program also uses the TRUNCATE option +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +static PRFileDesc *t1; +PRIntn error_code; + +int main(int argc, char **argv) +{ + + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + + PR_STDIO_INIT(); + t1 = PR_Open("/usr/tmp/ttools/err03.tmp", PR_TRUNCATE | PR_RDWR, 0666); + if (t1 == NULL) + if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { + printf ("error code is %d \n", PR_GetError()); + printf ("PASS\n"); + return 0; + } + else { + printf ("error code is %d \n", PR_GetError()); + printf ("FAIL\n"); + return 1; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_filok.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_filok.c new file mode 100644 index 00000000..acb86a7e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_filok.c @@ -0,0 +1,110 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_filok.c +** +** Description: Test Program to verify the PR_Open finding an existing file. +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +/* + * The name of a file that is guaranteed to exist + * on every machine of a particular OS. + */ +#ifdef VMS +#define EXISTING_FILENAME "SYS$LOGIN:LOGIN.COM" +#elif XP_UNIX +#define EXISTING_FILENAME "/bin/sh" +#elif defined(WIN32) +#define EXISTING_FILENAME "c:/autoexec.bat" +#elif defined(OS2) +#define EXISTING_FILENAME "c:/config.sys" +#elif defined(BEOS) +#define EXISTING_FILENAME "/boot/beos/bin/sh" +#else +#error "Unknown OS" +#endif + +static PRFileDesc *t1; + +int main(int argc, char **argv) +{ + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + + t1 = PR_Open(EXISTING_FILENAME, PR_RDONLY, 0666); + + if (t1 == NULL) { + printf ("error code is %d \n", PR_GetError()); + printf ("File %s should be found\n", + EXISTING_FILENAME); + return 1; + } else { + if (PR_Close(t1) == PR_SUCCESS) { + printf ("Test passed \n"); + return 0; + } else { + printf ("cannot close file\n"); + printf ("error code is %d\n", PR_GetError()); + return 1; + } + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_noacc.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_noacc.c new file mode 100644 index 00000000..ab1254de --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_noacc.c @@ -0,0 +1,94 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_noacc.c +** +** Description: Test Program to verify the PR_NO_ACCESS_RIGHTS_ERROR in PR_Open +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +static PRFileDesc *err01; +PRIntn error_code; + +int main(int argc, char **argv) +{ + + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + +#ifdef XP_PC + printf("op_noacc: Test not valid on MS-Windows.\n\tNo concept of 'mode' on Open() call\n"); + return(0); +#endif + + + PR_STDIO_INIT(); + err01 = PR_Open("err01.tmp", PR_CREATE_FILE | PR_RDWR, 0); + if (err01 == NULL) + if (PR_GetError() == PR_NO_ACCESS_RIGHTS_ERROR) { + printf ("error code is %d\n",PR_GetError()); + printf ("PASS\n"); + return 0; + } + else { + printf ("FAIL\n"); + return 1; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/op_nofil.c b/src/libs/xpcom18a4/nsprpub/pr/tests/op_nofil.c new file mode 100644 index 00000000..20bc11e1 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/op_nofil.c @@ -0,0 +1,99 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: op_nofil.c +** +** Description: Test Program to verify the PR_FILE_NOT_FOUND_ERROR +** +** Modification History: +** 03-June-97 AGarcia- Initial version +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "prinit.h" +#include "prmem.h" +#include "prio.h" +#include "prerror.h" +#include +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#else +#endif + +/* + * A file name that cannot exist + */ +#define NO_SUCH_FILE "/no/such/file.tmp" + +static PRFileDesc *t1; + +int main(int argc, char **argv) +{ + +#ifdef XP_MAC + SetupMacPrintfLog("pr_open_re.log"); +#endif + + PR_STDIO_INIT(); + t1 = PR_Open(NO_SUCH_FILE, PR_RDONLY, 0666); + if (t1 == NULL) { + if (PR_GetError() == PR_FILE_NOT_FOUND_ERROR) { + printf ("error code is PR_FILE_NOT_FOUND_ERROR, as expected\n"); + printf ("PASS\n"); + return 0; + } else { + printf ("error code is %d \n", PR_GetError()); + printf ("FAIL\n"); + return 1; + } + } + printf ("File %s exists on this machine!?\n", NO_SUCH_FILE); + if (PR_Close(t1) == PR_FAILURE) { + printf ("cannot close file\n"); + printf ("error code is %d \n", PR_GetError()); + } + printf ("FAIL\n"); + return 1; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/openfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/openfile.c new file mode 100644 index 00000000..8f863c06 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/openfile.c @@ -0,0 +1,145 @@ +/* -*- 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) 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 test calls PR_OpenFile to create a bunch of files + * with various file modes. + */ + +#include "prio.h" +#include "prerror.h" +#include "prinit.h" + +#include +#include + +#define TEMPLATE_FILE_NAME "template.txt" + +int main() +{ + FILE *template; + char buf[32]; + PRInt32 nbytes; + PRFileDesc *fd; + + + /* Write in text mode. Let stdio deal with line endings. */ + template = fopen(TEMPLATE_FILE_NAME, "w"); + fputs("line 1\nline 2\n", template); + fclose(template); + + /* Read in binary mode */ + fd = PR_OpenFile(TEMPLATE_FILE_NAME, PR_RDONLY, 0666); + nbytes = PR_Read(fd, buf, sizeof(buf)); + PR_Close(fd); + PR_Delete(TEMPLATE_FILE_NAME); + + fd = PR_OpenFile("tfil0700.txt", PR_RDWR | PR_CREATE_FILE, 0700); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0500.txt", PR_RDWR | PR_CREATE_FILE, 0500); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0400.txt", PR_RDWR | PR_CREATE_FILE, 0400); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0644.txt", PR_RDWR | PR_CREATE_FILE, 0644); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0664.txt", PR_RDWR | PR_CREATE_FILE, 0664); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0660.txt", PR_RDWR | PR_CREATE_FILE, 0660); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0666.txt", PR_RDWR | PR_CREATE_FILE, 0666); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + fd = PR_OpenFile("tfil0640.txt", PR_RDWR | PR_CREATE_FILE, 0640); + if (NULL == fd) { + fprintf(stderr, "PR_OpenFile failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + PR_Write(fd, buf, nbytes); + PR_Close(fd); + + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/parent.c b/src/libs/xpcom18a4/nsprpub/pr/tests/parent.c new file mode 100644 index 00000000..a81d5ec6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/parent.c @@ -0,0 +1,157 @@ +/* -*- 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 ***** */ + +/* +** file: parent.c +** description: test the process machinery +*/ + +#include "prmem.h" +#include "prprf.h" +#include "prinit.h" +#include "prproces.h" +#include "prinrval.h" + +typedef struct Child +{ + const char *name; + char **argv; + PRProcess *process; + PRProcessAttr *attr; +} Child; + +/* for the default test 'cvar -c 2000' */ +static char *default_argv[] = {"cvar", "-c", "2000", NULL}; + +static void PrintUsage(void) +{ + PR_fprintf(PR_GetSpecialFD(PR_StandardError), + "Usage: parent [-d] child [options]\n"); +} + +PRIntn main (PRIntn argc, char **argv) +{ + PRStatus rv; + PRInt32 test_status = 1; + PRIntervalTime t_start, t_elapsed; + PRFileDesc *debug = NULL; + Child *child = PR_NEWZAP(Child); + + if (1 == argc) + { + /* no command-line arguments: run the default test */ + child->argv = default_argv; + } + else + { + argv += 1; /* don't care about our program name */ + while (*argv != NULL && argv[0][0] == '-') + { + if (argv[0][1] == 'd') + debug = PR_GetSpecialFD(PR_StandardError); + else + { + PrintUsage(); + return 2; /* not sufficient */ + } + argv += 1; + } + child->argv = argv; + } + + if (NULL == *child->argv) + { + PrintUsage(); + return 2; + } + + child->name = *child->argv; + if (NULL != debug) PR_fprintf(debug, "Forking %s\n", child->name); + + child->attr = PR_NewProcessAttr(); + PR_ProcessAttrSetStdioRedirect( + child->attr, PR_StandardOutput, + PR_GetSpecialFD(PR_StandardOutput)); + PR_ProcessAttrSetStdioRedirect( + child->attr, PR_StandardError, + PR_GetSpecialFD(PR_StandardError)); + + t_start = PR_IntervalNow(); + child->process = PR_CreateProcess( + child->name, child->argv, NULL, child->attr); + t_elapsed = (PRIntervalTime) (PR_IntervalNow() - t_start); + + PR_DestroyProcessAttr(child->attr); + + test_status = (NULL == child->process) ? 1 : 0; + if (NULL != debug) + { + PR_fprintf( + debug, "Child was %sforked\n", + (0 == test_status) ? "" : "NOT "); + if (0 == test_status) + PR_fprintf( + debug, "PR_CreateProcess took %lu microseconds\n", + PR_IntervalToMicroseconds(t_elapsed)); + } + + if (0 == test_status) + { + if (NULL != debug) PR_fprintf(debug, "Waiting for child to exit\n"); + rv = PR_WaitProcess(child->process, &test_status); + if (PR_SUCCESS == rv) + { + if (NULL != debug) + PR_fprintf( + debug, "Child exited %s\n", + (0 == test_status) ? "successfully" : "with error"); + } + else + { + test_status = 1; + if (NULL != debug) + PR_fprintf(debug, "PR_WaitProcess failed\n"); + } + } + PR_DELETE(child); + PR_Cleanup(); + return test_status; + +} /* main */ + +/* parent.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/peek.c b/src/libs/xpcom18a4/nsprpub/pr/tests/peek.c new file mode 100644 index 00000000..22fcfec6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/peek.c @@ -0,0 +1,392 @@ +/* -*- 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 ***** */ + +/* + * A test case for the PR_MSG_PEEK flag of PR_Recv(). + * + * Test both blocking and non-blocking sockets. + */ + +#include "nspr.h" + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +static int iterations = 10; + +/* + * In iteration i, recv_amount[i] is the number of bytes we + * wish to receive, and send_amount[i] is the number of bytes + * we actually send. Therefore, the number of elements in the + * recv_amount or send_amount array should equal to 'iterations'. + * For this test to pass we need to ensure that + * recv_amount[i] <= BUFFER_SIZE, + * send_amount[i] <= BUFFER_SIZE, + * send_amount[i] <= recv_amount[i]. + */ +static PRInt32 recv_amount[10] = { + 16, 128, 256, 1024, 512, 512, 128, 256, 32, 32}; +static PRInt32 send_amount[10] = { + 16, 64, 128, 1024, 512, 256, 128, 64, 16, 32}; + +/* Blocking I/O */ +static void ServerB(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *sock; + char buf[BUFFER_SIZE]; + PRInt32 nbytes; + int i; + int j; + + sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == sock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + + for (i = 0; i < iterations; i++) { + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i, buf[j]); + exit(1); + } + } + fprintf(stderr, "server: received expected data\n"); + + PR_Sleep(PR_SecondsToInterval(1)); + memset(buf, 2*i+1, send_amount[i]); + nbytes = PR_Send(sock, buf, send_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Send failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); + exit(1); + } + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +/* Non-blocking I/O */ +static void ClientNB(void *arg) +{ + PRFileDesc *sock; + PRSocketOptionData opt; + PRUint16 port = (PRUint16) arg; + PRNetAddr addr; + char buf[BUFFER_SIZE]; + PRPollDesc pd; + PRInt32 npds; + PRInt32 nbytes; + int i; + int j; + + sock = PR_OpenTCPSocket(PR_AF_INET6); + if (NULL == sock) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) { + fprintf(stderr, "PR_SetSocketOption failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr) + == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + if (PR_GetError() != PR_IN_PROGRESS_ERROR) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + if (PR_GetConnectStatus(&pd) == PR_FAILURE) { + fprintf(stderr, "PR_GetConnectStatus failed\n"); + exit(1); + } + } + + for (i = 0; i < iterations; i++) { + PR_Sleep(PR_SecondsToInterval(1)); + memset(buf, 2*i, send_amount[i]); + while ((nbytes = PR_Send(sock, buf, send_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT)) == -1) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "PR_Send failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_WRITE; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); + exit(1); + } + + memset(buf, 0, sizeof(buf)); + while ((nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT)) == -1) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_READ; + npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (-1 == npds) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + if (1 != npds) { + fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); + exit(1); + } + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: peeked expected data\n"); + + memset(buf, 0, sizeof(buf)); + nbytes = PR_Recv(sock, buf, recv_amount[i], + 0, PR_INTERVAL_NO_TIMEOUT); + if (-1 == nbytes) { + fprintf(stderr, "PR_Recv failed\n"); + exit(1); + } + if (send_amount[i] != nbytes) { + fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); + exit(1); + } + for (j = 0; j < nbytes; j++) { + if (buf[j] != 2*i+1) { + fprintf(stderr, "byte %d should be %d but is %d\n", + j, 2*i+1, buf[j]); + exit(1); + } + } + fprintf(stderr, "client: received expected data\n"); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void +RunTest(PRThreadScope scope, PRFileDesc *listenSock, PRUint16 port) +{ + PRThread *server, *client; + + server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == server) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + client = PR_CreateThread( + PR_USER_THREAD, ClientNB, (void *) port, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == client) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + if (PR_JoinThread(server) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(client) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock; + PRNetAddr addr; + PRUint16 port; + + listenSock = PR_OpenTCPSocket(PR_AF_INET6); + if (NULL == listenSock) { + fprintf(stderr, "PR_OpenTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_SetNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + port = PR_ntohs(addr.ipv6.port); + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + fprintf(stderr, "Running the test with local threads\n"); + RunTest(PR_LOCAL_THREAD, listenSock, port); + fprintf(stderr, "Running the test with global threads\n"); + RunTest(PR_GLOBAL_THREAD, listenSock, port); + + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/perf.c b/src/libs/xpcom18a4/nsprpub/pr/tests/perf.c new file mode 100644 index 00000000..edd3a6ef --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/perf.c @@ -0,0 +1,485 @@ +/* -*- 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 "nspr.h" +#include "plgetopt.h" + +#include +#include +#include + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +PRLock *lock; +PRMonitor *mon; +PRMonitor *mon2; + +#define DEFAULT_COUNT 1000 + +PRInt32 count; + +static void nop(int a, int b, int c) +{ +} + +static void LocalProcedureCall(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + nop(i, i, 5); + } +} + +static void DLLProcedureCall(void) +{ + PRInt32 i; + PRThreadState state; + PRThread *self = PR_CurrentThread(); + + for (i = 0; i < count; i++) { + state = PR_GetThreadState(self); + } +} + +static void Now(void) +{ + PRInt32 i; + PRTime time; + + for (i = 0; i < count; i++) { + time = PR_Now(); + } +} + +static void Interval(void) +{ + PRInt32 i; + PRIntervalTime time; + + for (i = 0; i < count; i++) { + time = PR_IntervalNow(); + } +} + +static void IdleLock(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + PR_Lock(lock); + PR_Unlock(lock); + } +} + +static void IdleMonitor(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + PR_EnterMonitor(mon); + PR_ExitMonitor(mon); + } +} + +static void IdleCMonitor(void) +{ + PRInt32 i; + + for (i = 0; i < count; i++) { + PR_CEnterMonitor((void*)7); + PR_CExitMonitor((void*)7); + } +} + +/************************************************************************/ + +static void PR_CALLBACK dull(void *arg) +{ +} + +static void CDThread(void) +{ + PRInt32 i; + int num_threads = count; + + /* + * Cannot create too many threads + */ + if (num_threads > 1000) + num_threads = 1000; + + for (i = 0; i < num_threads; i++) { + PRThread *t = PR_CreateThread(PR_USER_THREAD, + dull, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t) { + fprintf(stderr, "CDThread: cannot create thread %3d\n", i); + } else { + DPRINTF(("CDThread: created thread %3d \n",i)); + } + PR_Sleep(0); + } +} + +static int alive; +static int cxq; + +static void PR_CALLBACK CXReader(void *arg) +{ + PRInt32 i, n; + + PR_EnterMonitor(mon); + n = count / 2; + for (i = 0; i < n; i++) { + while (cxq == 0) { + DPRINTF(("CXReader: thread = 0x%lx waiting\n", + PR_GetCurrentThread())); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + --cxq; + PR_Notify(mon); + } + PR_ExitMonitor(mon); + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("CXReader: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static void PR_CALLBACK CXWriter(void *arg) +{ + PRInt32 i, n; + + PR_EnterMonitor(mon); + n = count / 2; + for (i = 0; i < n; i++) { + while (cxq == 1) { + DPRINTF(("CXWriter: thread = 0x%lx waiting\n", + PR_GetCurrentThread())); + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + ++cxq; + PR_Notify(mon); + } + PR_ExitMonitor(mon); + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("CXWriter: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static void ContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + + PR_EnterMonitor(mon2); + alive = 2; + cxq = 0; + + t1 = PR_CreateThread(PR_USER_THREAD, + CXReader, 0, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t1) { + fprintf(stderr, "ContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", + (scope1 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t1)); + } + t2 = PR_CreateThread(PR_USER_THREAD, + CXWriter, 0, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t2) { + fprintf(stderr, "ContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("ContextSwitch: created %s thread = 0x%lx\n", + (scope2 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t2)); + } + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon2); +} + +static void ContextSwitchUU(void) +{ + ContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void ContextSwitchUK(void) +{ + ContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void ContextSwitchKU(void) +{ + ContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); +} + +static void ContextSwitchKK(void) +{ + ContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + +/************************************************************************/ + +static void PR_CALLBACK SemaThread(void *argSema) +{ + PRSemaphore **sem = (PRSemaphore **)argSema; + PRInt32 i, n; + + n = count / 2; + for (i = 0; i < n; i++) { + DPRINTF(("SemaThread: thread = 0x%lx waiting on sem = 0x%lx\n", + PR_GetCurrentThread(), sem[0])); + PR_WaitSem(sem[0]); + DPRINTF(("SemaThread: thread = 0x%lx posting on sem = 0x%lx\n", + PR_GetCurrentThread(), sem[1])); + PR_PostSem(sem[1]); + } + + PR_EnterMonitor(mon2); + --alive; + PR_Notify(mon2); + PR_ExitMonitor(mon2); + DPRINTF(("SemaThread: thread = 0x%lx exiting\n", PR_GetCurrentThread())); +} + +static PRSemaphore *sem_set1[2]; +static PRSemaphore *sem_set2[2]; + +static void SemaContextSwitch(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *t1, *t2; + sem_set1[0] = PR_NewSem(1); + sem_set1[1] = PR_NewSem(0); + sem_set2[0] = sem_set1[1]; + sem_set2[1] = sem_set1[0]; + + PR_EnterMonitor(mon2); + alive = 2; + cxq = 0; + + t1 = PR_CreateThread(PR_USER_THREAD, + SemaThread, + sem_set1, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t1) { + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", + (scope1 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t1)); + } + t2 = PR_CreateThread(PR_USER_THREAD, + SemaThread, + sem_set2, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0); + if (NULL == t2) { + fprintf(stderr, "SemaContextSwitch: cannot create thread\n"); + } else { + DPRINTF(("SemaContextSwitch: created %s thread = 0x%lx\n", + (scope2 == PR_GLOBAL_THREAD ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD"), + t2)); + } + + /* Wait for both of the threads to exit */ + while (alive) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon2); + + PR_DestroySem(sem_set1[0]); + PR_DestroySem(sem_set1[1]); +} + +static void SemaContextSwitchUU(void) +{ + SemaContextSwitch(PR_LOCAL_THREAD, PR_LOCAL_THREAD); +} + +static void SemaContextSwitchUK(void) +{ + SemaContextSwitch(PR_LOCAL_THREAD, PR_GLOBAL_THREAD); +} + +static void SemaContextSwitchKU(void) +{ + SemaContextSwitch(PR_GLOBAL_THREAD, PR_LOCAL_THREAD); +} + +static void SemaContextSwitchKK(void) +{ + SemaContextSwitch(PR_GLOBAL_THREAD, PR_GLOBAL_THREAD); +} + + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow() - start; + d = (double)PR_IntervalToMicroseconds(stop); + + printf("%40s: %6.2f usec\n", msg, d / count); +} + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 'c': /* loop count */ + count = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == count) count = DEFAULT_COUNT; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_BlockClockInterrupts(); + PR_UnblockClockInterrupts(); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("perf.log"); +#endif + + lock = PR_NewLock(); + mon = PR_NewMonitor(); + mon2 = PR_NewMonitor(); + + Measure(LocalProcedureCall, "local procedure call overhead"); + Measure(DLLProcedureCall, "DLL procedure call overhead"); + Measure(Now, "current calendar time"); + Measure(Interval, "interval time"); + Measure(IdleLock, "idle lock lock/unlock pair"); + Measure(IdleMonitor, "idle monitor entry/exit pair"); + Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); + Measure(CDThread, "create/destroy thread pair"); + Measure(ContextSwitchUU, "context switch - user/user"); + Measure(ContextSwitchUK, "context switch - user/kernel"); + Measure(ContextSwitchKU, "context switch - kernel/user"); + Measure(ContextSwitchKK, "context switch - kernel/kernel"); + Measure(SemaContextSwitchUU, "sema context switch - user/user"); + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); + + printf("--------------\n"); + printf("Adding 7 additional CPUs\n"); + + PR_SetConcurrency(8); + printf("--------------\n"); + + Measure(LocalProcedureCall, "local procedure call overhead"); + Measure(DLLProcedureCall, "DLL procedure call overhead"); + Measure(Now, "current calendar time"); + Measure(Interval, "interval time"); + Measure(IdleLock, "idle lock lock/unlock pair"); + Measure(IdleMonitor, "idle monitor entry/exit pair"); + Measure(IdleCMonitor, "idle cache monitor entry/exit pair"); + Measure(CDThread, "create/destroy thread pair"); + Measure(ContextSwitchUU, "context switch - user/user"); + Measure(ContextSwitchUK, "context switch - user/kernel"); + Measure(ContextSwitchKU, "context switch - kernel/user"); + Measure(ContextSwitchKK, "context switch - kernel/kernel"); + Measure(SemaContextSwitchUU, "sema context switch - user/user"); + Measure(SemaContextSwitchUK, "sema context switch - user/kernel"); + Measure(SemaContextSwitchKU, "sema context switch - kernel/user"); + Measure(SemaContextSwitchKK, "sema context switch - kernel/kernel"); + + PR_DestroyLock(lock); + PR_DestroyMonitor(mon); + PR_DestroyMonitor(mon2); + + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping.c new file mode 100644 index 00000000..dd18eb6f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping.c @@ -0,0 +1,190 @@ +/* -*- 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 ***** */ + +/* + * File: pipeping.c + * + * Description: + * This test runs in conjunction with the pipepong test. + * This test creates two pipes and redirects the stdin and + * stdout of the pipepong test to the pipes. Then this + * test writes "ping" to the pipepong test and the pipepong + * test writes "pong" back. To run this pair of tests, + * just invoke pipeping. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance, standard I/O redirection. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#ifdef XP_OS2 +static char *child_argv[] = { "pipepong.exe", NULL }; +#else +static char *child_argv[] = { "pipepong", NULL }; +#endif + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *in_pipe[2]; + PRFileDesc *out_pipe[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(in_pipe[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(in_pipe[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[0], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[1], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, out_pipe[0]); + PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, in_pipe[1]); + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(out_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(out_pipe[1], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(in_pipe[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(in_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping2.c new file mode 100644 index 00000000..b1f2b420 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeping2.c @@ -0,0 +1,192 @@ +/* -*- 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) 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 ***** */ + +/* + * File: pipeping2.c + * + * Description: + * This test runs in conjunction with the pipepong2 test. + * This test creates two pipes and passes two pipe fd's + * to the pipepong2 test. Then this test writes "ping" to + * to the pipepong2 test and the pipepong2 test writes "pong" + * back. To run this pair of tests, just invoke pipeping2. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static char *child_argv[] = { "pipepong2", NULL }; + +int main() +{ + PRFileDesc *in_pipe[2]; + PRFileDesc *out_pipe[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_CreatePipe(&in_pipe[0], &in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&out_pipe[0], &out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(in_pipe[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(in_pipe[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[0], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + status = PR_SetFDInheritable(out_pipe[1], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + status = PR_ProcessAttrSetInheritableFD(attr, out_pipe[0], "PIPE_READ"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + status = PR_ProcessAttrSetInheritableFD(attr, in_pipe[1], "PIPE_WRITE"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(out_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(in_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(out_pipe[1], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(in_pipe[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(in_pipe[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(out_pipe[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong.c new file mode 100644 index 00000000..66771601 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong.c @@ -0,0 +1,92 @@ +/* -*- 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 ***** */ + +/* + * File: pipepong.c + * + * Description: + * This test runs in conjunction with the pipeping test. + * The pipeping test creates two pipes and redirects the + * stdin and stdout of this test to the pipes. Then the + * pipeping test writes "ping" to this test and this test + * writes "pong" back. Note that this test does not depend + * on NSPR at all. To run this pair of tests, just invoke + * pipeping. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance, standard I/O redirection. + */ + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + char buf[1024]; + size_t nBytes; + int idx; + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = fread(buf, 1, 5, stdin); + fprintf(stderr, "pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + fprintf(stderr, "pong process: sending \"%s\"\n", buf); + nBytes = fwrite(buf, 1, 5, stdout); + if (nBytes != 5) { + fprintf(stderr, "pong process: fwrite failed\n"); + exit(1); + } + fflush(stdout); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong2.c new file mode 100644 index 00000000..19494bbd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pipepong2.c @@ -0,0 +1,130 @@ +/* -*- 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) 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 ***** */ + +/* + * File: pipepong2.c + * + * Description: + * This test runs in conjunction with the pipeping2 test. + * The pipeping2 test creates two pipes and passes two + * pipe fd's to this test. Then the pipeping2 test writes + * "ping" to this test and this test writes "pong" back. + * To run this pair of tests, just invoke pipeping2. + * + * Tested areas: process creation, pipes, file descriptor + * inheritance. + */ + +#include "prerror.h" +#include "prio.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *pipe_read, *pipe_write; + PRStatus status; + char buf[1024]; + PRInt32 nBytes; + int idx; + + pipe_read = PR_GetInheritedFD("PIPE_READ"); + if (pipe_read == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(pipe_read, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + pipe_write = PR_GetInheritedFD("PIPE_WRITE"); + if (pipe_write == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(pipe_write, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(pipe_read, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + printf("pong process: sending \"%s\"\n", buf); + nBytes = PR_Write(pipe_write, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + } + + status = PR_Close(pipe_read); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(pipe_write); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pipeself.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeself.c new file mode 100644 index 00000000..5bb9791a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pipeself.c @@ -0,0 +1,260 @@ +/* -*- 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 ***** */ + +/* + * File: pipeself.c + * + * Description: + * This test has two threads communicating with each other using + * two unidirectional pipes. The primordial thread is the ping + * thread and the other thread is the pong thread. The ping + * thread writes "ping" to the pong thread and the pong thread + * writes "pong" back. + */ + +#include "prio.h" +#include "prerror.h" +#include "prthread.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static PRFileDesc *ping_in, *ping_out; +static PRFileDesc *pong_in, *pong_out; + +static void PongThreadFunc(void *arg) +{ + char buf[1024]; + int idx; + PRInt32 nBytes; + PRStatus status; + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(pong_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("pong thread: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong thread: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong thread: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + strcpy(buf, "pong"); + printf("pong thread: sending \"%s\"\n", buf); + nBytes = PR_Write(pong_out, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + } + + status = PR_Close(pong_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(pong_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +int main() +{ + PRStatus status; + PRThread *pongThread; + char buf[1024]; + PRInt32 nBytes; + int idx; + + status = PR_CreatePipe(&ping_in, &pong_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + status = PR_CreatePipe(&pong_in, &ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + + pongThread = PR_CreateThread(PR_USER_THREAD, PongThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (pongThread == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping thread: sending \"%s\"\n", buf); + nBytes = PR_Write(ping_out, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(ping_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + printf("ping thread: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping thread: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping thread: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(ping_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_JoinThread(pongThread); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + +#ifdef XP_UNIX + /* + * Test PR_Available for pipes + */ + status = PR_CreatePipe(&ping_in, &ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_CreatePipe failed\n"); + exit(1); + } + nBytes = PR_Write(ping_out, buf, 250); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != 250) { + fprintf(stderr, "PR_Available: expected 250 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n",250, nBytes); + /* read some data */ + nBytes = PR_Read(ping_in, buf, 7); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + /* check available data */ + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != (250 - 7)) { + fprintf(stderr, "PR_Available: expected 243 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n",243, nBytes); + /* read all data */ + nBytes = PR_Read(ping_in, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } else if (nBytes != 243) { + fprintf(stderr, "PR_Read failed: expected %d, got %d bytes\n", + 243, nBytes); + exit(1); + } + /* check available data */ + nBytes = PR_Available(ping_in); + if (nBytes < 0) { + fprintf(stderr, "PR_Available failed: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } else if (nBytes != 0) { + fprintf(stderr, "PR_Available: expected 0 bytes but got %d bytes\n", + nBytes); + exit(1); + } + printf("PR_Available: expected %d, got %d bytes\n", 0, nBytes); + + status = PR_Close(ping_in); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_Close(ping_out); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +#endif /* XP_UNIX */ + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/poll_er.c b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_er.c new file mode 100644 index 00000000..b68c7986 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_er.c @@ -0,0 +1,244 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: prpoll_err.c +** +** Description: This program tests PR_Poll with sockets. +** error reporting operation is tested +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "primpl.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void +ClientThreadFunc(void *arg) +{ + PRFileDesc *badFD = (PRFileDesc *) arg; + /* + * Make the fd invalid + */ +#if defined(XP_UNIX) + close(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_OS2) + soclose(PR_FileDesc2NativeHandle(badFD)); +#elif defined(WIN32) || defined(WIN16) + closesocket(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_MAC) + _PR_MD_CLOSE_SOCKET(PR_FileDesc2NativeHandle(badFD)); +#else +#error "Unknown architecture" +#endif +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("error reporting is tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + npds = 2; + + + /* Testing bad fd */ + if (debug_mode) printf("PR_Poll should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + goto exit_now; + } + + pds[2].fd = badFD; + pds[2].in_flags = PR_POLL_READ; + npds = 3; + + if (PR_CreateThread(PR_USER_THREAD, ClientThreadFunc, + badFD, PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0) == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Poll returns %d, out_flags is 0x%hx\n", + retVal, pds[2].out_flags); + failed_already=1; + goto exit_now; + } + if (debug_mode) printf("PR_Poll detected the bad fd. Test passed.\n\n"); + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; +} + +#endif /* XP_BEOS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/poll_nm.c b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_nm.c new file mode 100644 index 00000000..63a64a63 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_nm.c @@ -0,0 +1,399 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: prpoll_norm.c +** +** Description: This program tests PR_Poll with sockets. +** Normal operation are tested +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" +#ifndef XP_MAC +#include "obsolete/probslet.h" +#else +#include "probslet.h" +#endif + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode; + +#define NUM_ITERATIONS 5 + +#ifdef XP_MAC +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +static void PR_CALLBACK +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + PRStatus sts; + PRInt32 n; + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((PRUint16)port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + memset(buf, 0, sizeof(buf)); + PR_snprintf(buf, sizeof(buf), "%hu", port); + + for (i = 0; i < NUM_ITERATIONS; i++) { + sock = PR_NewTCPSocket(); + PR_ASSERT(sock != NULL); + + sts = PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(sts == PR_SUCCESS); + + n = PR_Write(sock, buf, sizeof(buf)); + PR_ASSERT(n >= 0); + + sts = PR_Close(sock); + PR_ASSERT(sts == PR_SUCCESS); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRThread *clientThread; + PRPollDesc pds0[20], pds1[20], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + PRIntn i, j; + PRSocketOptionData optval; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + debug_mode = 1; + SetupMacPrintfLog("poll_nm.log"); +#endif + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("Normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + optval.option = PR_SockOpt_Nonblocking; + optval.value.non_blocking = PR_TRUE; + PR_SetSocketOption(listenSock1, &optval); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + PR_SetSocketOption(listenSock2, &optval); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + /* Add some unused entries to test if they are ignored by PR_Poll() */ + memset(&pds[2], 0, sizeof(pds[2])); + memset(&pds[3], 0, sizeof(pds[3])); + memset(&pds[4], 0, sizeof(pds[4])); + npds = 5; + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + if (debug_mode) { + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + } + + /* two clients, three events per iteration: accept, read, close */ + i = 0; + while (i < 2 * 3 * NUM_ITERATIONS) { + PRPollDesc *tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Poll failed\n"); + failed_already=1; + goto exit_now; + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_pds[j] = pds[j]; + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + failed_already=1; + goto exit_now; + } + other_pds[nextIndex].fd = sock; + other_pds[nextIndex].in_flags = PR_POLL_READ; + nextIndex++; + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + failed_already=1; + goto exit_now; + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", + PR_FileDesc2NativeHandle(pds[j].fd)); + failed_already=1; + goto exit_now; + } + } + + for (j = 2; j < npds; j++) { + if (NULL == pds[j].fd) { + /* + * Keep the unused entries in the poll descriptor array + * for testing purposes. + */ + other_pds[nextIndex] = pds[j]; + nextIndex++; + continue; + } + + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRInt32 nAvail; + PRInt32 nRead; + + nEvents++; + nAvail = PR_Available(pds[j].fd); + nRead = PR_Read(pds[j].fd, buf, sizeof(buf)); + PR_ASSERT(nAvail == nRead); + if (nRead == -1) { + fprintf(stderr, "PR_Read() failed\n"); + failed_already=1; + goto exit_now; + } else if (nRead == 0) { + PR_Close(pds[j].fd); + continue; + } else { + /* Just to be safe */ + buf[127] = '\0'; + if (debug_mode) printf("The server received \"%s\" from a client\n", buf); + } + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + failed_already=1; + goto exit_now; + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); + failed_already=1; + goto exit_now; + } + other_pds[nextIndex] = pds[j]; + nextIndex++; + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = pds; + pds = other_pds; + other_pds = tmp; + npds = nextIndex; + i += nEvents; + } + + if (debug_mode) printf("Tests passed\n"); + +exit_now: + + if (listenSock1) { + PR_Close(listenSock1); + } + if (listenSock2) { + PR_Close(listenSock2); + } + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/poll_to.c b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_to.c new file mode 100644 index 00000000..93fcc79d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/poll_to.c @@ -0,0 +1,216 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: prpoll_to.c +** +** Description: This program tests PR_Poll with sockets. +** Timeout operation is tested +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#include +#include +#include +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1 = NULL, *listenSock2 = NULL; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[128]; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Poll with sockets.\n"); + printf("Timeout is tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + pds[0].fd = listenSock1; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = listenSock2; + pds[1].in_flags = PR_POLL_READ; + npds = 2; + + /* Testing timeout */ + if (debug_mode) printf("PR_Poll should time out in 5 seconds\n"); + retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Poll should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (!debug_mode) failed_already=1; + goto exit_now; + } + if (debug_mode) printf("PR_Poll timed out. Test passed.\n\n"); + +exit_now: + + if (listenSock1) { + PR_Close(listenSock1); + } + if (listenSock2) { + PR_Close(listenSock2); + } + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/pollable.c b/src/libs/xpcom18a4/nsprpub/pr/tests/pollable.c new file mode 100644 index 00000000..20da55a3 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/pollable.c @@ -0,0 +1,293 @@ +/* -*- 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 ***** */ + +/* + * A test for the pollable events. + * + * A number of threads are in a ring configuration, each waiting on + * a pollable event that is set by its upstream neighbor. + */ + +#include "prinit.h" +#include "prio.h" +#include "prthread.h" +#include "prerror.h" +#include "prmem.h" +#include "prlog.h" +#include "prprf.h" + +#include "plgetopt.h" + +#include + +#define DEFAULT_THREADS 10 +#define DEFAULT_LOOPS 100 + +PRIntn numThreads = DEFAULT_THREADS; +PRIntn numIterations = DEFAULT_LOOPS; +PRIntervalTime dally = PR_INTERVAL_NO_WAIT; +PRFileDesc *debug_out = NULL; +PRBool debug_mode = PR_FALSE; +PRBool verbosity = PR_FALSE; + +typedef struct ThreadData { + PRFileDesc *event; + int index; + struct ThreadData *next; +} ThreadData; + +void ThreadRoutine(void *arg) +{ + ThreadData *data = (ThreadData *) arg; + PRIntn i; + PRPollDesc pd; + PRInt32 rv; + + pd.fd = data->event; + pd.in_flags = PR_POLL_READ; + + for (i = 0; i < numIterations; i++) { + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv == -1) { + PR_fprintf(PR_STDERR, "PR_Poll failed\n"); + exit(1); + } + if (verbosity) { + PR_fprintf(debug_out, "thread %d awakened\n", data->index); + } + PR_ASSERT(rv != 0); + PR_ASSERT(pd.out_flags & PR_POLL_READ); + if (PR_WaitForPollableEvent(data->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "consume event failed\n"); + exit(1); + } + if (dally != PR_INTERVAL_NO_WAIT) { + PR_Sleep(dally); + } + if (verbosity) { + PR_fprintf(debug_out, "thread %d posting event\n", data->index); + } + if (PR_SetPollableEvent(data->next->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "post event failed\n"); + exit(1); + } + } +} + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: pollable [-c n] [-t n] [-d] [-v] [-G] [-C n] [-D n]\n"); + PR_fprintf( + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); + PR_fprintf( + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); + PR_fprintf(debug_out, "-D n\tdally setting (msecs) (default: 0)\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + ThreadData selfData; + ThreadData *data; + PRThread **thread; + void *block; + PRIntn i; + PRIntervalTime timeStart, timeEnd; + PRPollDesc pd; + PRInt32 rv; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + PRUintn average; + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + + opt = PL_CreateOptState(argc, argv, "hdvc:t:C:GD:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) { + continue; + } + switch (opt->option) { + case 'v': /* verbose mode */ + verbosity = PR_TRUE; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + numIterations = atoi(opt->value); + break; + case 't': /* thread limit */ + numThreads = atoi(opt->value); + break; + case 'C': /* Concurrency limit */ + concurrency = atoi(opt->value); + break; + case 'G': /* global threads only */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'D': /* dally */ + dally = PR_MillisecondsToInterval(atoi(opt->value)); + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) { + return 1; + } + + if (concurrency > 1) { + PR_SetConcurrency(concurrency); + } + + if (PR_TRUE == debug_mode) { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", numThreads); + PR_fprintf(debug_out, "\tIteration limit: %d\n", numIterations); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf(debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + /* + * Malloc a block of memory and divide it into data and thread. + */ + block = PR_MALLOC(numThreads * (sizeof(ThreadData) + sizeof(PRThread *))); + if (block == NULL) { + PR_fprintf(PR_STDERR, "cannot malloc, failed\n"); + exit(1); + } + data = (ThreadData *) block; + thread = (PRThread **) &data[numThreads]; + + /* Pollable event */ + selfData.event = PR_NewPollableEvent(); + if (selfData.event == NULL) { + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + selfData.next = &data[0]; + for (i = 0; i < numThreads; i++) { + data[i].event = PR_NewPollableEvent(); + if (data[i].event == NULL) { + PR_fprintf(PR_STDERR, "cannot create event: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + data[i].index = i; + if (i != numThreads - 1) { + data[i].next = &data[i + 1]; + } else { + data[i].next = &selfData; + } + + thread[i] = PR_CreateThread(PR_USER_THREAD, + ThreadRoutine, &data[i], PR_PRIORITY_NORMAL, + thread_scope, PR_JOINABLE_THREAD, 0); + if (thread[i] == NULL) { + PR_fprintf(PR_STDERR, "cannot create thread\n"); + exit(1); + } + } + + timeStart = PR_IntervalNow(); + pd.fd = selfData.event; + pd.in_flags = PR_POLL_READ; + for (i = 0; i < numIterations; i++) { + if (dally != PR_INTERVAL_NO_WAIT) { + PR_Sleep(dally); + } + if (verbosity) { + PR_fprintf(debug_out, "main thread posting event\n"); + } + if (PR_SetPollableEvent(selfData.next->event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "set event failed\n"); + exit(1); + } + rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + if (rv == -1) { + PR_fprintf(PR_STDERR, "wait failed\n"); + exit(1); + } + PR_ASSERT(rv != 0); + PR_ASSERT(pd.out_flags & PR_POLL_READ); + if (verbosity) { + PR_fprintf(debug_out, "main thread awakened\n"); + } + if (PR_WaitForPollableEvent(selfData.event) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "consume event failed\n"); + exit(1); + } + } + timeEnd = PR_IntervalNow(); + + if (debug_mode) { + average = PR_IntervalToMicroseconds(timeEnd - timeStart) + / (numIterations * numThreads); + PR_fprintf(debug_out, "Average switch times %d usecs for %d threads\n", + average, numThreads); + } + + for (i = 0; i < numThreads; i++) { + if (PR_JoinThread(thread[i]) == PR_FAILURE) { + PR_fprintf(PR_STDERR, "join thread failed\n"); + exit(1); + } + PR_DestroyPollableEvent(data[i].event); + } + PR_DELETE(block); + PR_DestroyPollableEvent(selfData.event); + + PR_fprintf(PR_STDOUT, "PASSED\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prftest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest.c new file mode 100644 index 00000000..d3e7407d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest.c @@ -0,0 +1,97 @@ +/* -*- 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 ***** */ + +/* + * File: prftest.c + * Description: + * This is a simple test of the PR_snprintf() function defined + * in prprf.c. + */ + +#include "prlong.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +int main() { + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + char answer[BUF_SIZE]; + int i, rv = 0; + + i16 = -1; + n = -1; + i32 = -1; + LL_I2L(i64, i32); + + PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64); + strcpy(answer, "ffff "); + for (i = PR_BYTES_PER_INT * 2; i; i--) { + strcat(answer, "f"); + } + strcat(answer, " ffffffff ffffffffffffffff"); + + if (!strcmp(buf, answer)) { + printf("PR_snprintf test 1 passed\n"); + } else { + printf("PR_snprintf test 1 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be %s\n", answer); + rv = 1; + } + + i16 = -32; + n = 30; + i32 = 64; + LL_I2L(i64, 333); + PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32); + if (!strcmp(buf, "30 -32 333 64")) { + printf("PR_snprintf test 2 passed\n"); + } else { + printf("PR_snprintf test 2 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be 30 -32 333 64\n"); + rv = 1; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prftest1.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest1.c new file mode 100644 index 00000000..5ea26f65 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest1.c @@ -0,0 +1,152 @@ +/* -*- 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 ***** */ + +/* +** File: prftest1.c +** Description: +** This is a simple test of the PR_snprintf() function defined +** in prprf.c. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + +#include "prinit.h" +#include "prlong.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); +} + +int main( int argc, char *argv[]) +{ + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + char answer[BUF_SIZE]; + int i; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + PR_STDIO_INIT(); + + i16 = -1; + n = -1; + i32 = -1; + LL_I2L(i64, i32); + + PR_snprintf(buf, BUF_SIZE, "%hx %x %lx %llx", i16, n, i32, i64); + strcpy(answer, "ffff "); + for (i = PR_BYTES_PER_INT * 2; i; i--) { + strcat(answer, "f"); + } + strcat(answer, " ffffffff ffffffffffffffff"); + + if (!strcmp(buf, answer)) { + if (debug_mode) printf("PR_snprintf test 1 passed\n"); + else Test_Result (PASS); + } else { + if (debug_mode) { + printf("PR_snprintf test 1 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be %s\n", answer); + } + else + Test_Result (FAIL); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prftest2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest2.c new file mode 100644 index 00000000..0e5b2244 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prftest2.c @@ -0,0 +1,129 @@ +/* -*- 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 ***** */ + +/* +** File: prftest2.c +** Description: +** This is a simple test of the PR_snprintf() function defined +** in prprf.c. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prlong.h" +#include "prinit.h" +#include "prprf.h" + +#include + +#define BUF_SIZE 128 + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main( int argc, char *argv[]) +{ + PRInt16 i16; + PRIntn n; + PRInt32 i32; + PRInt64 i64; + char buf[BUF_SIZE]; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + + PR_STDIO_INIT(); + i16 = -32; + n = 30; + i32 = 64; + LL_I2L(i64, 333); + PR_snprintf(buf, BUF_SIZE, "%d %hd %lld %ld", n, i16, i64, i32); + if (!strcmp(buf, "30 -32 333 64")) { + if (debug_mode) printf("PR_snprintf test 2 passed\n"); + } else { + if (debug_mode) { + printf("PR_snprintf test 2 failed\n"); + printf("Converted string is %s\n", buf); + printf("Should be 30 -32 333 64\n"); + } + else failed_already=1; + } + if(failed_already) + { + printf("FAILED\n"); + return 1; + } + else + { + printf("PASSED\n"); + return 0; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/primblok.c b/src/libs/xpcom18a4/nsprpub/pr/tests/primblok.c new file mode 100644 index 00000000..8a188834 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/primblok.c @@ -0,0 +1,148 @@ +/* -*- 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) 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 ***** */ + +/* + * File: primblok.c + * Purpose: testing whether the primordial thread can block in a + * native blocking function without affecting the correct + * functioning of NSPR I/O functions (Bugzilla bug #30746) + */ + +#if !defined(WINNT) + +#include + +int main() +{ + printf("This test is not relevant on this platform\n"); + return 0; +} + +#else /* WINNT */ + +#include "nspr.h" + +#include +#include +#include +#include + +#define TEST_FILE_NAME "primblok.dat" + +/* use InterlockedExchange to update this variable */ +static LONG iothread_done; + +static void PR_CALLBACK IOThread(void *arg) +{ + PRFileDesc *fd; + char buf[32]; + PRInt32 nbytes; + + /* Give the primordial thread one second to block */ + Sleep(1000); + + /* + * See if our PR_Write call will hang when the primordial + * thread is blocking in a native blocking function. + */ + fd = PR_Open(TEST_FILE_NAME, PR_WRONLY|PR_CREATE_FILE, 0666); + if (NULL == fd) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + memset(buf, 0xaf, sizeof(buf)); + fprintf(stderr, "iothread: calling PR_Write\n"); + nbytes = PR_Write(fd, buf, sizeof(buf)); + fprintf(stderr, "iothread: PR_Write returned\n"); + if (nbytes != sizeof(buf)) { + fprintf(stderr, "PR_Write returned %d\n", nbytes); + exit(1); + } + if (PR_Close(fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Delete(TEST_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } + + /* Tell the main thread that we are done */ + InterlockedExchange(&iothread_done, 1); +} + +int main() +{ + PRThread *iothread; + + /* Must be a global thread */ + iothread = PR_CreateThread( + PR_USER_THREAD, IOThread, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (iothread == NULL) { + fprintf(stderr, "cannot create thread\n"); + exit(1); + } + + /* + * Block in a native blocking function. + * Give iothread 5 seconds to finish its task. + */ + Sleep(5000); + + /* + * Is iothread done or is it hung? + * + * I'm actually only interested in reading the value + * of iothread_done. I'm using InterlockedExchange as + * a thread-safe way to read iothread_done. + */ + if (InterlockedExchange(&iothread_done, 1) == 0) { + fprintf(stderr, "iothread is hung\n"); + fprintf(stderr, "FAILED\n"); + exit(1); + } + + if (PR_JoinThread(iothread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + printf("PASSED\n"); + return 0; +} /* main */ + +#endif /* WINNT */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/priotest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/priotest.c new file mode 100644 index 00000000..16def03d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/priotest.c @@ -0,0 +1,233 @@ +/* -*- 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 ***** */ + +/* + * File: priotest.c + * Purpose: testing priorities + */ + +#ifdef XP_MAC +#error "This test does not run on Macintosh" +#else + + +#include "prcmon.h" +#include "prinit.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prmon.h" +#include "prprf.h" +#include "prthread.h" +#include "prtypes.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include +#include + +#define DEFAULT_DURATION 5 + +static PRBool failed = PR_FALSE; +static PRIntervalTime oneSecond; +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE; + +static PRUint32 PerSecond(PRIntervalTime timein) +{ + PRUint32 loop = 0; + while (((PRIntervalTime)(PR_IntervalNow()) - timein) < oneSecond) + loop += 1; + return loop; +} /* PerSecond */ + +static void PR_CALLBACK Low(void *arg) +{ + PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg; + while (1) + { + t0 = PerSecond(PR_IntervalNow()); + *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8; + t3 = t2; t2 = t1; t1 = t0; + } +} /* Low */ + +static void PR_CALLBACK High(void *arg) +{ + PRUint32 t3 = 0, t2 = 0, t1 = 0, t0, *tn = (PRUint32*)arg; + while (1) + { + PRIntervalTime timein = PR_IntervalNow(); + PR_Sleep(oneSecond >> 2); /* 0.25 seconds */ + t0 = PerSecond(timein); + *tn = (t3 + 3 * t2 + 3 * t1 + t0) / 8; + t3 = t2; t2 = t1; t1 = t0; + } +} /* High */ + +static void Help(void) +{ + PR_fprintf( + debug_out, "Usage: priotest [-d] [-c n]\n"); + PR_fprintf( + debug_out, "-c n\tduration of test in seconds (default: %d)\n", DEFAULT_DURATION); + PR_fprintf( + debug_out, "-d\tturn on debugging output (default: FALSE)\n"); +} /* Help */ + +static void RudimentaryTests(void) +{ + /* + ** Try some rudimentary tests like setting valid priority and + ** getting it back, or setting invalid priorities and getting + ** back a valid answer. + */ + PRThreadPriority priority; + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_URGENT != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_URGENT != priority)) + { + PR_fprintf(debug_out, "PR_[S/G]etThreadPriority() failed\n"); + } + + + PR_SetThreadPriority( + PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_FIRST - 1)); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_FIRST != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_FIRST != priority)) + { + PR_fprintf(debug_out, "PR_SetThreadPriority(-1) failed\n"); + } + + PR_SetThreadPriority( + PR_GetCurrentThread(), (PRThreadPriority)(PR_PRIORITY_LAST + 1)); + priority = PR_GetThreadPriority(PR_GetCurrentThread()); + failed = ((PR_TRUE == failed) || (PR_PRIORITY_LAST != priority)) + ? PR_TRUE : PR_FALSE; + if (debug_mode && (PR_PRIORITY_LAST != priority)) + { + PR_fprintf(debug_out, "PR_SetThreadPriority(+1) failed\n"); + } + +} /* RudimentataryTests */ + +static void CreateThreads(PRUint32 *lowCount, PRUint32 *highCount) +{ + (void)PR_CreateThread( + PR_USER_THREAD, Low, lowCount, PR_PRIORITY_LOW, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + (void)PR_CreateThread( + PR_USER_THREAD, High, highCount, PR_PRIORITY_HIGH, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); +} /* CreateThreads */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRIntn duration = DEFAULT_DURATION; + PRUint32 totalCount, highCount = 0, lowCount = 0; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdc:"); + + debug_out = PR_STDOUT; + oneSecond = PR_SecondsToInterval(1); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* test duration */ + duration = atoi(opt->value); + break; + case 'h': /* help message */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + + if (duration == 0) duration = DEFAULT_DURATION; + + RudimentaryTests(); + + printf("Priority test: running for %d seconds\n\n", duration); + + (void)PerSecond(PR_IntervalNow()); + totalCount = PerSecond(PR_IntervalNow()); + + PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_URGENT); + + if (debug_mode) + { + PR_fprintf(debug_out, + "The high priority thread should get approximately three\n"); + PR_fprintf( debug_out, + "times what the low priority thread manages. A maximum of \n"); + PR_fprintf( debug_out, "%d cycles are available.\n\n", totalCount); + } + + duration = (duration + 4) / 5; + CreateThreads(&lowCount, &highCount); + while (duration--) + { + PRIntn loop = 5; + while (loop--) PR_Sleep(oneSecond); + if (debug_mode) + PR_fprintf(debug_out, "high : low :: %d : %d\n", highCount, lowCount); + } + + + PR_ProcessExit((failed) ? 1 : 0); + + PR_ASSERT(!"You can't get here -- but you did!"); + return 1; /* or here */ + +} /* main */ + +#endif /* ifdef XP_MAC */ + +/* priotest.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/provider.c b/src/libs/xpcom18a4/nsprpub/pr/tests/provider.c new file mode 100644 index 00000000..54b3a53c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/provider.c @@ -0,0 +1,1447 @@ +/* -*- 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 ***** */ + +/* + * + * Notes: + * [1] lth. The call to Sleep() is a hack to get the test case to run + * on Windows 95. Without it, the test case fails with an error + * WSAECONNRESET following a recv() call. The error is caused by the + * server side thread termination without a shutdown() or closesocket() + * call. Windows docmunentation suggests that this is predicted + * behavior; that other platforms get away with it is ... serindipity. + * The test case should shutdown() or closesocket() before + * thread termination. I didn't have time to figure out where or how + * to do it. The Sleep() call inserts enough delay to allow the + * client side to recv() all his data before the server side thread + * terminates. Whew! ... + * + ** Modification History: + * 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. + * The debug mode will print all of the printfs associated with this test. + * The regress mode will be the default mode. Since the regress tool limits + * the output to a one line status:PASS or FAIL,all of the printf statements + * have been handled with an if (debug_mode) statement. + */ + +#include "prclist.h" +#include "prcvar.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prio.h" +#include "prlock.h" +#include "prlog.h" +#include "prtime.h" +#include "prmem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prthread.h" + +#include "pprio.h" +#include "primpl.h" + +#include "plstr.h" +#include "plerror.h" +#include "plgetopt.h" + +#include +#include + + +#if defined(XP_UNIX) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +/* +** This is the beginning of the test +*/ + +#define RECV_FLAGS 0 +#define SEND_FLAGS 0 +#define BUFFER_SIZE 1024 +#define DEFAULT_BACKLOG 5 +#define DEFAULT_PORT 13000 +#define DEFAULT_CLIENTS 1 +#define ALLOWED_IN_ACCEPT 1 +#define DEFAULT_CLIPPING 1000 +#define DEFAULT_WORKERS_MIN 1 +#define DEFAULT_WORKERS_MAX 1 +#define DEFAULT_SERVER "localhost" +#define DEFAULT_EXECUTION_TIME 10 +#define DEFAULT_CLIENT_TIMEOUT 4000 +#define DEFAULT_SERVER_TIMEOUT 4000 +#define DEFAULT_SERVER_PRIORITY PR_PRIORITY_HIGH + +typedef enum CSState_e {cs_init, cs_run, cs_stop, cs_exit} CSState_t; + +static void PR_CALLBACK Worker(void *arg); +typedef struct CSPool_s CSPool_t; +typedef struct CSWorker_s CSWorker_t; +typedef struct CSServer_s CSServer_t; +typedef enum Verbosity +{ + TEST_LOG_ALWAYS, + TEST_LOG_ERROR, + TEST_LOG_WARNING, + TEST_LOG_NOTICE, + TEST_LOG_INFO, + TEST_LOG_STATUS, + TEST_LOG_VERBOSE +} Verbosity; + +static enum { + thread_nspr, thread_pthread, thread_uithread, thread_sproc, thread_win32 +} thread_provider; + +static PRInt32 domain = AF_INET; +static PRInt32 protocol = 6; /* TCP */ +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE; +static PRBool pthread_stats = PR_FALSE; +static Verbosity verbosity = TEST_LOG_ALWAYS; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +struct CSWorker_s +{ + PRCList element; /* list of the server's workers */ + + PRThread *thread; /* this worker objects thread */ + CSServer_t *server; /* back pointer to server structure */ +}; + +struct CSPool_s +{ + PRCondVar *exiting; + PRCondVar *acceptComplete; + PRUint32 accepting, active, workers; +}; + +struct CSServer_s +{ + PRCList list; /* head of worker list */ + + PRLock *ml; + PRThread *thread; /* the main server thread */ + PRCondVar *stateChange; + + PRUint16 port; /* port we're listening on */ + PRUint32 backlog; /* size of our listener backlog */ + PRFileDesc *listener; /* the fd accepting connections */ + + CSPool_t pool; /* statistics on worker threads */ + CSState_t state; /* the server's state */ + struct /* controlling worker counts */ + { + PRUint32 minimum, maximum, accepting; + } workers; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +}; + +typedef struct CSDescriptor_s +{ + PRInt32 size; /* size of transfer */ + char filename[60]; /* filename, null padded */ +} CSDescriptor_t; + +typedef struct CSClient_s +{ + PRLock *ml; + PRThread *thread; + PRCondVar *stateChange; + PRNetAddr serverAddress; + + CSState_t state; + + /* statistics */ + PRIntervalTime started, stopped; + PRUint32 operations, bytesTransferred; +} CSClient_t; + +#define TEST_LOG(l, p, a) \ + do { \ + if (debug_mode || (p <= verbosity)) printf a; \ + } while (0) + +PRLogModuleInfo *cltsrv_log_file = NULL; + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +#define TEST_ASSERT(_expr) \ + ((_expr)?((void)0):_MY_Assert(# _expr,__FILE__,__LINE__)) + +static void _MY_Assert(const char *s, const char *file, PRIntn ln) +{ + PL_PrintError(NULL); +#if DEBUG + PR_Assert(s, file, ln); +#endif +} /* _MW_Assert */ + +static PRBool Aborted(PRStatus rv) +{ + return ((PR_FAILURE == rv) && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) ? + PR_TRUE : PR_FALSE; +} + +static void TimeOfDayMessage(const char *msg, PRThread* me) +{ + char buffer[100]; + PRExplodedTime tod; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &tod); + (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("%s(0x%p): %s\n", msg, me, buffer)); +} /* TimeOfDayMessage */ + + +static void PR_CALLBACK Client(void *arg) +{ + PRStatus rv; + PRIntn index; + char buffer[1024]; + PRFileDesc *fd = NULL; + PRUintn clipping = DEFAULT_CLIPPING; + CSClient_t *client = (CSClient_t*)arg; + PRThread *me = client->thread = PR_CurrentThread(); + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_CLIENT_TIMEOUT); + + + for (index = 0; index < sizeof(buffer); ++index) + buffer[index] = (char)index; + + client->started = PR_IntervalNow(); + + PR_Lock(client->ml); + client->state = cs_run; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + + TimeOfDayMessage("Client started at", me); + + while (cs_run == client->state) + { + PRInt32 bytes, descbytes, filebytes, netbytes; + + (void)PR_NetAddrToString(&client->serverAddress, buffer, sizeof(buffer)); + TEST_LOG(cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): connecting to server at %s\n", me, buffer)); + + fd = PR_Socket(domain, SOCK_STREAM, protocol); + TEST_ASSERT(NULL != fd); + rv = PR_Connect(fd, &client->serverAddress, timeout); + if (PR_FAILURE == rv) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): conection failed\n", me)); + goto aborted; + } + + memset(descriptor, 0, sizeof(*descriptor)); + descriptor->size = PR_htonl(descbytes = rand() % clipping); + PR_snprintf( + descriptor->filename, sizeof(descriptor->filename), + "CS%p%p-%p.dat", client->started, me, client->operations); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending descriptor for %u bytes\n", me, descbytes)); + bytes = PR_Send( + fd, descriptor, sizeof(*descriptor), SEND_FLAGS, timeout); + if (sizeof(CSDescriptor_t) != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send descriptor timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(sizeof(*descriptor) == bytes); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + if (Aborted(PR_FAILURE)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): send data timeout\n", me)); + goto retry; + } + } + TEST_ASSERT(bytes == filebytes); + netbytes += bytes; + } + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tClient(0x%p): receiving %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + if (Aborted(PR_FAILURE)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data aborted\n", me)); + goto aborted; + } + else if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive data timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tClient(0x%p): receive error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto retry; + } + if (0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tClient(0x%p): unexpected end of stream\n", + PR_CurrentThread())); + break; + } + filebytes += bytes; + } + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); +retry: + (void)PR_Close(fd); fd = NULL; + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tClient(0x%p): disconnected from server\n", me)); + + PR_Lock(client->ml); + client->operations += 1; + client->bytesTransferred += 2 * descbytes; + rv = PR_WaitCondVar(client->stateChange, rand() % clipping); + PR_Unlock(client->ml); + if (Aborted(rv)) break; + } + +aborted: + client->stopped = PR_IntervalNow(); + + PR_ClearInterrupt(); + if (NULL != fd) rv = PR_Close(fd); + + PR_Lock(client->ml); + client->state = cs_exit; + PR_NotifyCondVar(client->stateChange); + PR_Unlock(client->ml); + PR_DELETE(descriptor); + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tClient(0x%p): stopped after %u operations and %u bytes\n", + PR_CurrentThread(), client->operations, client->bytesTransferred)); + +} /* Client */ + +static PRStatus ProcessRequest(PRFileDesc *fd, CSServer_t *server) +{ + PRStatus drv, rv; + char buffer[1024]; + PRFileDesc *file = NULL; + PRThread * me = PR_CurrentThread(); + PRInt32 bytes, descbytes, netbytes, filebytes = 0; + CSDescriptor_t *descriptor = PR_NEW(CSDescriptor_t); + PRIntervalTime timeout = PR_MillisecondsToInterval(DEFAULT_SERVER_TIMEOUT); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receiving desciptor\n", me)); + bytes = PR_Recv( + fd, descriptor, sizeof(*descriptor), RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto exit; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): receive timeout\n", me)); + } + goto exit; + } + if (0 == bytes) + { + rv = PR_FAILURE; + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): unexpected end of file\n", me)); + goto exit; + } + descbytes = PR_ntohl(descriptor->size); + TEST_ASSERT(sizeof(*descriptor) == bytes); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): read descriptor {%d, %s}\n", + me, descbytes, descriptor->filename)); + + file = PR_Open( + descriptor->filename, (PR_CREATE_FILE | PR_WRONLY), 0666); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\tProcessRequest(0x%p): open file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(NULL != file); + + filebytes = 0; + while (filebytes < descbytes) + { + netbytes = sizeof(buffer); + if ((descbytes - filebytes) < netbytes) + netbytes = descbytes - filebytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): receive %d bytes\n", me, netbytes)); + bytes = PR_Recv(fd, buffer, netbytes, RECV_FLAGS, timeout); + if (-1 == bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): receive data timeout\n", me)); + goto aborted; + } + /* + * XXX: I got (PR_CONNECT_RESET_ERROR, ERROR_NETNAME_DELETED) + * on NT here. This is equivalent to ECONNRESET on Unix. + * -wtc + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + if(0 == bytes) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_WARNING, + ("\t\tProcessRequest(0x%p): unexpected end of stream\n", me)); + rv = PR_FAILURE; + goto aborted; + } + filebytes += bytes; + netbytes = bytes; + /* The byte count for PR_Write should be positive */ + MY_ASSERT(netbytes > 0); + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): write %d bytes to file\n", me, netbytes)); + bytes = PR_Write(file, buffer, netbytes); + if (netbytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): write file timeout\n", me)); + goto aborted; + } + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->operations += 1; + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Close(file); file = NULL; + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): opening %s\n", me, descriptor->filename)); + file = PR_Open(descriptor->filename, PR_RDONLY, 0); + if (NULL == file) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): open file timeout\n", + PR_CurrentThread())); + goto aborted; + } + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file open error (%u, %u)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(NULL != file); + + netbytes = 0; + while (netbytes < descbytes) + { + filebytes = sizeof(buffer); + if ((descbytes - netbytes) < filebytes) + filebytes = descbytes - netbytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tProcessRequest(0x%p): read %d bytes from file\n", me, filebytes)); + bytes = PR_Read(file, buffer, filebytes); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): read file timeout\n", me)); + else + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): other file error (%d, %d)\n", + me, PR_GetError(), PR_GetOSError())); + goto aborted; + } + TEST_ASSERT(bytes > 0); + netbytes += bytes; + filebytes = bytes; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): sending %d bytes\n", me, filebytes)); + bytes = PR_Send(fd, buffer, filebytes, SEND_FLAGS, timeout); + if (filebytes != bytes) + { + rv = PR_FAILURE; + if (Aborted(rv)) goto aborted; + if (PR_IO_TIMEOUT_ERROR == PR_GetError()) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tProcessRequest(0x%p): send data timeout\n", me)); + goto aborted; + } + break; + } + TEST_ASSERT(bytes > 0); + } + + PR_Lock(server->ml); + server->bytesTransferred += filebytes; + PR_Unlock(server->ml); + + rv = PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + if (Aborted(rv)) goto aborted; + + rv = PR_Close(file); file = NULL; + if (Aborted(rv)) goto aborted; + TEST_ASSERT(PR_SUCCESS == rv); + +aborted: + PR_ClearInterrupt(); + if (NULL != file) PR_Close(file); + drv = PR_Delete(descriptor->filename); + TEST_ASSERT(PR_SUCCESS == drv); +exit: + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tProcessRequest(0x%p): Finished\n", me)); + + PR_DELETE(descriptor); + +#if defined(WIN95) + PR_Sleep(PR_MillisecondsToInterval(200)); /* lth. see note [1] */ +#endif + return rv; +} /* ProcessRequest */ + +typedef void (*StartFn)(void*); +typedef struct StartObject +{ + StartFn start; + void *arg; +} StartObject; + +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include "md/_pth.h" +#include + +static void *pthread_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return NULL; +} /* pthread_start */ +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) +#include + +static void *uithread_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return NULL; +} /* uithread_start */ +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + +#if defined(IRIX) && !defined(_PR_PTHREADS) +#include +#include +static void sproc_start(void *arg, PRSize size) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); +} /* sproc_start */ +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + +#if defined(WIN32) +#include /* for _beginthreadex() */ + +static PRUintn __stdcall windows_start(void *arg) +{ + StartObject *so = (StartObject*)arg; + StartFn start = so->start; + void *data = so->arg; + PR_Free(so); + start(data); + return 0; +} /* windows_start */ +#endif /* defined(WIN32) */ + +static PRStatus JoinThread(PRThread *thread) +{ + PRStatus rv; + switch (thread_provider) + { + case thread_nspr: + rv = PR_JoinThread(thread); + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + rv = PR_SUCCESS; + break; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + case thread_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + rv = PR_SUCCESS; + break; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + case thread_win32: +#if defined(WIN32) + rv = PR_SUCCESS; + break; +#endif + default: + rv = PR_FAILURE; + break; + } + return rv; +} /* JoinThread */ + +static PRStatus NewThread( + StartFn start, void *arg, PRThreadPriority prio, PRThreadState state) +{ + PRStatus rv; + + switch (thread_provider) + { + case thread_nspr: + { + PRThread *thread = PR_CreateThread( + PR_USER_THREAD, start, arg, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0); + rv = (NULL == thread) ? PR_FAILURE : PR_SUCCESS; + } + break; + case thread_pthread: +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + { + int rv; + pthread_t id; + pthread_attr_t tattr; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + rv = _PT_PTHREAD_ATTR_INIT(&tattr); + PR_ASSERT(0 == rv); + + rv = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + PR_ASSERT(0 == rv); + +#if !defined(LINUX) + rv = pthread_attr_setstacksize(&tattr, 64 * 1024); + PR_ASSERT(0 == rv); +#endif + + rv = _PT_PTHREAD_CREATE(&id, tattr, pthread_start, start_object); + (void)_PT_PTHREAD_ATTR_DESTROY(&tattr); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */ + break; + + case thread_uithread: +#if defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + { + int rv; + thread_t id; + long flags; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + + flags = THR_DETACHED; + + rv = thr_create(NULL, NULL, uithread_start, start_object, flags, &id); + return (0 == rv) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) */ + break; + + case thread_sproc: +#if defined(IRIX) && !defined(_PR_PTHREADS) + { + PRInt32 pid; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + pid = sprocsp( + sproc_start, PR_SALL, start_object, NULL, 64 * 1024); + rv = (0 < pid) ? PR_SUCCESS : PR_FAILURE; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif /* defined(IRIX) && !defined(_PR_PTHREADS) */ + break; + case thread_win32: +#if defined(WIN32) + { + void *th; + PRUintn id; + StartObject *start_object; + start_object = PR_NEW(StartObject); + PR_ASSERT(NULL != start_object); + start_object->start = start; + start_object->arg = arg; + th = (void*)_beginthreadex( + NULL, /* LPSECURITY_ATTRIBUTES - pointer to thread security attributes */ + 0U, /* DWORD - initial thread stack size, in bytes */ + windows_start, /* LPTHREAD_START_ROUTINE - pointer to thread function */ + start_object, /* LPVOID - argument for new thread */ + 0U, /*DWORD dwCreationFlags - creation flags */ + &id /* LPDWORD - pointer to returned thread identifier */ ); + + rv = (NULL == th) ? PR_FAILURE : PR_SUCCESS; + } +#else + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; +#endif + break; + default: + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + rv = PR_FAILURE; + } + return rv; +} /* NewThread */ + +static PRStatus CreateWorker(CSServer_t *server, CSPool_t *pool) +{ + PRStatus rv; + CSWorker_t *worker = PR_NEWZAP(CSWorker_t); + worker->server = server; + PR_INIT_CLIST(&worker->element); + rv = NewThread( + Worker, worker, DEFAULT_SERVER_PRIORITY, PR_UNJOINABLE_THREAD); + if (PR_FAILURE == rv) PR_DELETE(worker); + + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("\tCreateWorker(0x%p): create new worker (0x%p)\n", + PR_CurrentThread(), worker->thread)); + + return rv; +} /* CreateWorker */ + +static void PR_CALLBACK Worker(void *arg) +{ + PRStatus rv; + PRNetAddr from; + PRFileDesc *fd = NULL; + CSWorker_t *worker = (CSWorker_t*)arg; + CSServer_t *server = worker->server; + CSPool_t *pool = &server->pool; + + PRThread *me = worker->thread = PR_CurrentThread(); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): started [%u]\n", me, pool->workers + 1)); + + PR_Lock(server->ml); + PR_APPEND_LINK(&worker->element, &server->list); + pool->workers += 1; /* define our existance */ + + while (cs_run == server->state) + { + while (pool->accepting >= server->workers.accepting) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): waiting for accept slot[%d]\n", + me, pool->accepting)); + rv = PR_WaitCondVar(pool->acceptComplete, PR_INTERVAL_NO_TIMEOUT); + if (Aborted(rv) || (cs_run != server->state)) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tWorker(0x%p): has been %s\n", + me, (Aborted(rv) ? "interrupted" : "stopped"))); + goto exit; + } + } + pool->accepting += 1; /* how many are really in accept */ + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\t\tWorker(0x%p): calling accept\n", me)); + fd = PR_Accept(server->listener, &from, PR_INTERVAL_NO_TIMEOUT); + + PR_Lock(server->ml); + pool->accepting -= 1; + PR_NotifyCondVar(pool->acceptComplete); + + if ((NULL == fd) && Aborted(PR_FAILURE)) + { + if (NULL != server->listener) + { + PR_Close(server->listener); + server->listener = NULL; + } + goto exit; + } + + if (NULL != fd) + { + /* + ** Create another worker of the total number of workers is + ** less than the minimum specified or we have none left in + ** accept() AND we're not over the maximum. + ** This sort of presumes that the number allowed in accept + ** is at least as many as the minimum. Otherwise we'll keep + ** creating new threads and deleting them soon after. + */ + PRBool another = + ((pool->workers < server->workers.minimum) || + ((0 == pool->accepting) + && (pool->workers < server->workers.maximum))) ? + PR_TRUE : PR_FALSE; + pool->active += 1; + PR_Unlock(server->ml); + + if (another) (void)CreateWorker(server, pool); + + rv = ProcessRequest(fd, server); + if (PR_SUCCESS != rv) + TEST_LOG( + cltsrv_log_file, TEST_LOG_ERROR, + ("\t\tWorker(0x%p): server process ended abnormally\n", me)); + (void)PR_Close(fd); fd = NULL; + + PR_Lock(server->ml); + pool->active -= 1; + } + } + +exit: + PR_ClearInterrupt(); + PR_Unlock(server->ml); + + if (NULL != fd) + { + (void)PR_Shutdown(fd, PR_SHUTDOWN_BOTH); + (void)PR_Close(fd); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\t\tWorker(0x%p): exiting [%u]\n", PR_CurrentThread(), pool->workers)); + + PR_Lock(server->ml); + pool->workers -= 1; /* undefine our existance */ + PR_REMOVE_AND_INIT_LINK(&worker->element); + PR_NotifyCondVar(pool->exiting); + PR_Unlock(server->ml); + + PR_DELETE(worker); /* destruction of the "worker" object */ + +} /* Worker */ + +static void PR_CALLBACK Server(void *arg) +{ + PRStatus rv; + PRNetAddr serverAddress; + CSServer_t *server = (CSServer_t*)arg; + PRThread *me = server->thread = PR_CurrentThread(); + PRSocketOptionData sockOpt; + + server->listener = PR_Socket(domain, SOCK_STREAM, protocol); + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(server->listener, &sockOpt); + TEST_ASSERT(PR_SUCCESS == rv); + + memset(&serverAddress, 0, sizeof(serverAddress)); + rv = PR_InitializeNetAddr(PR_IpAddrAny, DEFAULT_PORT, &serverAddress); + + rv = PR_Bind(server->listener, &serverAddress); + TEST_ASSERT(PR_SUCCESS == rv); + + rv = PR_Listen(server->listener, server->backlog); + TEST_ASSERT(PR_SUCCESS == rv); + + server->started = PR_IntervalNow(); + TimeOfDayMessage("Server started at", me); + + PR_Lock(server->ml); + server->state = cs_run; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + /* + ** Create the first worker (actually, a thread that accepts + ** connections and then processes the work load as needed). + ** From this point on, additional worker threads are created + ** as they are needed by existing worker threads. + */ + rv = CreateWorker(server, &server->pool); + TEST_ASSERT(PR_SUCCESS == rv); + + /* + ** From here on this thread is merely hanging around as the contact + ** point for the main test driver. It's just waiting for the driver + ** to declare the test complete. + */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): waiting for state change\n", me)); + + PR_Lock(server->ml); + while ((cs_run == server->state) && !Aborted(rv)) + { + rv = PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(server->ml); + PR_ClearInterrupt(); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("\tServer(0x%p): shutting down workers\n", me)); + + /* + ** Get all the worker threads to exit. They know how to + ** clean up after themselves, so this is just a matter of + ** waiting for clorine in the pool to take effect. During + ** this stage we're ignoring interrupts. + */ + server->workers.minimum = server->workers.maximum = 0; + + PR_Lock(server->ml); + while (!PR_CLIST_IS_EMPTY(&server->list)) + { + PRCList *head = PR_LIST_HEAD(&server->list); + CSWorker_t *worker = (CSWorker_t*)head; + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("\tServer(0x%p): interrupting worker(0x%p)\n", me, worker)); + rv = PR_Interrupt(worker->thread); + TEST_ASSERT(PR_SUCCESS == rv); + PR_REMOVE_AND_INIT_LINK(head); + } + + while (server->pool.workers > 0) + { + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("\tServer(0x%p): waiting for %u workers to exit\n", + me, server->pool.workers)); + (void)PR_WaitCondVar(server->pool.exiting, PR_INTERVAL_NO_TIMEOUT); + } + + server->state = cs_exit; + PR_NotifyCondVar(server->stateChange); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("\tServer(0x%p): stopped after %u operations and %u bytes\n", + me, server->operations, server->bytesTransferred)); + + if (NULL != server->listener) PR_Close(server->listener); + server->stopped = PR_IntervalNow(); + +} /* Server */ + +static void WaitForCompletion(PRIntn execution) +{ + while (execution > 0) + { + PRIntn dally = (execution > 30) ? 30 : execution; + PR_Sleep(PR_SecondsToInterval(dally)); + if (pthread_stats) PT_FPrintStats(debug_out, "\nPThread Statistics\n"); + execution -= dally; + } +} /* WaitForCompletion */ + +static void Help(void) +{ + PR_fprintf(debug_out, "cltsrv test program usage:\n"); + PR_fprintf(debug_out, "\t-a threads allowed in accept (5)\n"); + PR_fprintf(debug_out, "\t-b backlock for listen (5)\n"); + PR_fprintf(debug_out, "\t-c number of clients to create (1)\n"); + PR_fprintf(debug_out, "\t-w minimal number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-W maximum number of server threads (1)\n"); + PR_fprintf(debug_out, "\t-e duration of the test in seconds (10)\n"); + PR_fprintf(debug_out, "\t-s dsn name of server (localhost)\n"); + PR_fprintf(debug_out, "\t-G use GLOBAL threads (LOCAL)\n"); + PR_fprintf(debug_out, "\t-T thread provider ('n' | 'p' | 'u' | 'w')(n)\n"); + PR_fprintf(debug_out, "\t-X use XTP as transport (TCP)\n"); + PR_fprintf(debug_out, "\t-6 Use IPv6 (IPv4)\n"); + PR_fprintf(debug_out, "\t-v verbosity (accumulative) (0)\n"); + PR_fprintf(debug_out, "\t-p pthread statistics (FALSE)\n"); + PR_fprintf(debug_out, "\t-d debug mode (FALSE)\n"); + PR_fprintf(debug_out, "\t-h this message\n"); +} /* Help */ + +static Verbosity IncrementVerbosity(void) +{ + PRIntn verboge = (PRIntn)verbosity + 1; + return (Verbosity)verboge; +} /* IncrementVerbosity */ + +PRIntn main(PRIntn argc, char** argv) +{ + PRUintn index; + PRBool boolean; + CSClient_t *client; + PRStatus rv, joinStatus; + CSServer_t *server = NULL; + char *thread_type; + + PRUintn backlog = DEFAULT_BACKLOG; + PRUintn clients = DEFAULT_CLIENTS; + const char *serverName = DEFAULT_SERVER; + PRBool serverIsLocal = PR_TRUE; + PRUintn accepting = ALLOWED_IN_ACCEPT; + PRUintn workersMin = DEFAULT_WORKERS_MIN; + PRUintn workersMax = DEFAULT_WORKERS_MAX; + PRIntn execution = DEFAULT_EXECUTION_TIME; + + /* + * -G use global threads + * -a threads allowed in accept + * -b backlock for listen + * -c number of clients to create + * -w minimal number of server threads + * -W maximum number of server threads + * -e duration of the test in seconds + * -s dsn name of server (implies no server here) + * -v verbosity + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "GX6b:a:c:w:W:e:s:T:vdhp"); + +#if defined(WIN32) + thread_provider = thread_win32; +#elif defined(_PR_PTHREADS) + thread_provider = thread_pthread; +#elif defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY) + thread_provider = thread_uithread; +#elif defined(IRIX) + thread_provider = thread_sproc; +#else + thread_provider = thread_nspr; +#endif + + debug_out = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'X': /* use XTP as transport */ + protocol = 36; + break; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + case 'a': /* the value for accepting */ + accepting = atoi(opt->value); + break; + case 'b': /* the value for backlock */ + backlog = atoi(opt->value); + break; + case 'T': /* the thread provider */ + if ('n' == *opt->value) thread_provider = thread_nspr; + else if ('p' == *opt->value) thread_provider = thread_pthread; + else if ('u' == *opt->value) thread_provider = thread_uithread; + else if ('w' == *opt->value) thread_provider = thread_win32; + else {Help(); return 2; } + break; + case 'c': /* number of client threads */ + clients = atoi(opt->value); + break; + case 'w': /* minimum server worker threads */ + workersMin = atoi(opt->value); + break; + case 'W': /* maximum server worker threads */ + workersMax = atoi(opt->value); + break; + case 'e': /* program execution time in seconds */ + execution = atoi(opt->value); + break; + case 's': /* server's address */ + serverName = opt->value; + break; + case 'v': /* verbosity */ + verbosity = IncrementVerbosity(); + break; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'p': /* pthread mode */ + pthread_stats = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (0 != PL_strcmp(serverName, DEFAULT_SERVER)) serverIsLocal = PR_FALSE; + if (0 == execution) execution = DEFAULT_EXECUTION_TIME; + if (0 == workersMax) workersMax = DEFAULT_WORKERS_MAX; + if (0 == workersMin) workersMin = DEFAULT_WORKERS_MIN; + if (0 == accepting) accepting = ALLOWED_IN_ACCEPT; + if (0 == backlog) backlog = DEFAULT_BACKLOG; + + if (workersMin > accepting) accepting = workersMin; + + PR_STDIO_INIT(); + TimeOfDayMessage("Client/Server started at", PR_CurrentThread()); + + cltsrv_log_file = PR_NewLogModule("cltsrv_log"); + MY_ASSERT(NULL != cltsrv_log_file); + boolean = PR_SetLogFile("cltsrv.log"); + MY_ASSERT(boolean); + +#ifdef XP_MAC + debug_mode = PR_TRUE; +#endif + + if (serverIsLocal) + { + /* Establish the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): starting server\n", PR_CurrentThread())); + + server = PR_NEWZAP(CSServer_t); + PR_INIT_CLIST(&server->list); + server->state = cs_init; + server->ml = PR_NewLock(); + server->backlog = backlog; + server->port = DEFAULT_PORT; + server->workers.minimum = workersMin; + server->workers.maximum = workersMax; + server->workers.accepting = accepting; + server->stateChange = PR_NewCondVar(server->ml); + server->pool.exiting = PR_NewCondVar(server->ml); + server->pool.acceptComplete = PR_NewCondVar(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): creating server thread\n", PR_CurrentThread())); + + rv = NewThread( + Server, server, PR_PRIORITY_HIGH, PR_JOINABLE_THREAD); + TEST_ASSERT(PR_SUCCESS == rv); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): waiting for server init\n", PR_CurrentThread())); + + PR_Lock(server->ml); + while (server->state == cs_init) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): server init complete (port #%d)\n", + PR_CurrentThread(), server->port)); + } + + if (clients != 0) + { + /* Create all of the clients */ + PRHostEnt host; + char buffer[BUFFER_SIZE]; + client = (CSClient_t*)PR_CALLOC(clients * sizeof(CSClient_t)); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): creating %d client threads\n", + PR_CurrentThread(), clients)); + + if (!serverIsLocal) + { + rv = PR_GetHostByName(serverName, buffer, BUFFER_SIZE, &host); + if (PR_SUCCESS != rv) + { + PL_FPrintError(PR_STDERR, "PR_GetHostByName"); + return 2; + } + } + + for (index = 0; index < clients; ++index) + { + client[index].state = cs_init; + client[index].ml = PR_NewLock(); + if (serverIsLocal) + { + (void)PR_InitializeNetAddr( + PR_IpAddrLoopback, DEFAULT_PORT, + &client[index].serverAddress); + } + else + { + (void)PR_EnumerateHostEnt( + 0, &host, DEFAULT_PORT, &client[index].serverAddress); + } + client[index].stateChange = PR_NewCondVar(client[index].ml); + TEST_LOG( + cltsrv_log_file, TEST_LOG_INFO, + ("main(0x%p): creating client threads\n", PR_CurrentThread())); + rv = NewThread( + Client, &client[index], PR_PRIORITY_NORMAL, PR_JOINABLE_THREAD); + TEST_ASSERT(PR_SUCCESS == rv); + PR_Lock(client[index].ml); + while (cs_init == client[index].state) + PR_WaitCondVar(client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(client[index].ml); + } + } + + /* Then just let them go at it for a bit */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): waiting for execution interval (%d seconds)\n", + PR_CurrentThread(), execution)); + + WaitForCompletion(execution); + + TimeOfDayMessage("Shutting down", PR_CurrentThread()); + + if (clients != 0) + { + for (index = 0; index < clients; ++index) + { + TEST_LOG(cltsrv_log_file, TEST_LOG_STATUS, + ("main(0x%p): notifying client(0x%p) to stop\n", + PR_CurrentThread(), client[index].thread)); + + PR_Lock(client[index].ml); + if (cs_run == client[index].state) + { + client[index].state = cs_stop; + PR_Interrupt(client[index].thread); + while (cs_stop == client[index].state) + PR_WaitCondVar( + client[index].stateChange, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(client[index].ml); + + TEST_LOG(cltsrv_log_file, TEST_LOG_VERBOSE, + ("main(0x%p): joining client(0x%p)\n", + PR_CurrentThread(), client[index].thread)); + + joinStatus = JoinThread(client[index].thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + PR_DestroyCondVar(client[index].stateChange); + PR_DestroyLock(client[index].ml); + } + PR_DELETE(client); + } + + if (NULL != server) + { + /* All clients joined - retrieve the server */ + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): notifying server(0x%p) to stop\n", + PR_CurrentThread(), server->thread)); + + PR_Lock(server->ml); + server->state = cs_stop; + PR_Interrupt(server->thread); + while (cs_exit != server->state) + PR_WaitCondVar(server->stateChange, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(server->ml); + + TEST_LOG( + cltsrv_log_file, TEST_LOG_NOTICE, + ("main(0x%p): joining server(0x%p)\n", + PR_CurrentThread(), server->thread)); + joinStatus = JoinThread(server->thread); + TEST_ASSERT(PR_SUCCESS == joinStatus); + + PR_DestroyCondVar(server->stateChange); + PR_DestroyCondVar(server->pool.exiting); + PR_DestroyCondVar(server->pool.acceptComplete); + PR_DestroyLock(server->ml); + PR_DELETE(server); + } + + TEST_LOG( + cltsrv_log_file, TEST_LOG_ALWAYS, + ("main(0x%p): test complete\n", PR_CurrentThread())); + + if (thread_provider == thread_win32) + thread_type = "\nWin32 Thread Statistics\n"; + else if (thread_provider == thread_pthread) + thread_type = "\npthread Statistics\n"; + else if (thread_provider == thread_uithread) + thread_type = "\nUnix International (UI) Thread Statistics\n"; + else if (thread_provider == thread_sproc) + thread_type = "\nsproc Statistics\n"; + else { + PR_ASSERT(thread_provider == thread_nspr); + thread_type = "\nPRThread Statistics\nn"; + } + + PT_FPrintStats(debug_out, thread_type); + + TimeOfDayMessage("Test exiting at", PR_CurrentThread()); + PR_Cleanup(); + return 0; +} /* main */ + +/* cltsrv.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prpoll.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prpoll.c new file mode 100644 index 00000000..5e4893f9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prpoll.c @@ -0,0 +1,373 @@ +/* -*- 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 ***** */ + +#ifdef WIN32 +#include +#endif + +#ifdef XP_OS2_VACPP +#include /* for close() */ +#endif + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifndef XP_MAC +#include "private/pprio.h" +#else +#include "pprio.h" +#endif + +#define CLIENT_LOOPS 5 +#define BUF_SIZE 128 + +#include +#include +#include + +static void +clientThreadFunc(void *arg) +{ + PRUint16 port = (PRUint16) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[BUF_SIZE]; + int i; + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons(port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + char buf[BUF_SIZE]; + PRThread *clientThread; + PRPollDesc pds0[10], pds1[10], *pds, *other_pds; + PRIntn npds; + PRInt32 retVal; + PRInt32 sd, rv; + struct sockaddr_in saddr; + PRIntn saddr_len; + PRUint16 listenPort3; + PRFileDesc *socket_poll_fd; + PRIntn i, j; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + printf("This program tests PR_Poll with sockets.\n"); + printf("Timeout, error reporting, and normal operation are tested.\n\n"); + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + exit(1); + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + exit(1); + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + exit(1); + } + /* Set up the poll descriptor array */ + pds = pds0; + other_pds = pds1; + memset(pds, 0, sizeof(pds)); + npds = 0; + pds[npds].fd = listenSock1; + pds[npds].in_flags = PR_POLL_READ; + npds++; + pds[npds].fd = listenSock2; + pds[npds].in_flags = PR_POLL_READ; + npds++; + + sd = socket(AF_INET, SOCK_STREAM, 0); + PR_ASSERT(sd >= 0); + memset((char *) &saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(0); + + rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); + PR_ASSERT(rv == 0); + saddr_len = sizeof(saddr); + rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len); + PR_ASSERT(rv == 0); + listenPort3 = ntohs(saddr.sin_port); + + rv = listen(sd, 5); + PR_ASSERT(rv == 0); + pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd); + PR_ASSERT(pds[npds].fd); + pds[npds].in_flags = PR_POLL_READ; + npds++; + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu, %hu and %hu\n\n", + listenPort1, listenPort2, listenPort3); + printf("%s", buf); + + /* Testing timeout */ + printf("PR_Poll should time out in 5 seconds\n"); + retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Poll should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + exit(1); + } + printf("PR_Poll timed out. Test passed.\n\n"); + + /* Testing bad fd */ + printf("PR_Poll should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + exit(1); + } + + pds[npds].fd = badFD; + pds[npds].in_flags = PR_POLL_READ; + npds++; + PR_Close(badFD); /* make the fd bad */ +#if 0 + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Poll returns %d, out_flags is 0x%hx\n", + retVal, pds[npds - 1].out_flags); + exit(1); + } + printf("PR_Poll detected the bad fd. Test passed.\n\n"); +#endif + npds--; + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort3, + PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + + printf("Three client threads are created. Each of them will\n"); + printf("send data to one of the three ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + + /* 30 events total */ + i = 0; + while (i < 30) { + PRPollDesc *tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Poll failed\n"); + exit(1); + } + + nextIndex = 3; + /* the three listening sockets */ + for (j = 0; j < 3; j++) { + other_pds[j] = pds[j]; + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRFileDesc *sock; + + nEvents++; + if (j == 2) { + int newsd; + newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0); + if (newsd == -1) { + fprintf(stderr, "accept() failed\n"); + exit(1); + } + other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd); + PR_ASSERT(other_pds[nextIndex].fd); + other_pds[nextIndex].in_flags = PR_POLL_READ; + } else { + sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + exit(1); + } + other_pds[nextIndex].fd = sock; + other_pds[nextIndex].in_flags = PR_POLL_READ; + } + nextIndex++; + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + exit(1); + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n", + PR_FileDesc2NativeHandle(pds[j].fd)); + exit(1); + } + } + + for (j = 3; j < npds; j++) { + PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0 + && (pds[j].out_flags & PR_POLL_EXCEPT) == 0); + if (pds[j].out_flags & PR_POLL_READ) { + PRInt32 nBytes; + + nEvents++; + /* XXX: This call is a hack and should be fixed */ + if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) { + nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf, + sizeof(buf), 0); + if (nBytes == -1) { + fprintf(stderr, "recv() failed\n"); + exit(1); + } + printf("Server read %d bytes from native fd %d\n",nBytes, + PR_FileDesc2NativeHandle(pds[j].fd)); +#ifdef WIN32 + closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd)); +#else + close(PR_FileDesc2NativeHandle(pds[j].fd)); +#endif + PR_DestroySocketPollFd(pds[j].fd); + } else { + nBytes = PR_Read(pds[j].fd, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + exit(1); + } + PR_Close(pds[j].fd); + } + /* Just to be safe */ + buf[BUF_SIZE - 1] = '\0'; + printf("The server received \"%s\" from a client\n", buf); + } else if (pds[j].out_flags & PR_POLL_ERR) { + fprintf(stderr, "PR_Poll() indicates that an fd has error\n"); + exit(1); + } else if (pds[j].out_flags & PR_POLL_NVAL) { + fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n"); + exit(1); + } else { + other_pds[nextIndex] = pds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = pds; + pds = other_pds; + other_pds = tmp; + npds = nextIndex; + i += nEvents; + } + PR_DestroySocketPollFd(socket_poll_fd); + + printf("All tests finished\n"); + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prpollml.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prpollml.c new file mode 100644 index 00000000..720b525c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prpollml.c @@ -0,0 +1,162 @@ +/* -*- 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) 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 test exercises the code that allocates and frees the syspoll_list + * array of PRThread in the pthreads version. This test is intended to be + * run under Purify to verify that there is no memory leak. + */ + +#include "nspr.h" + +#include +#include +#include + +#define POLL_DESC_COUNT 256 /* This should be greater than the + * STACK_POLL_DESC_COUNT macro in + * ptio.c to cause syspoll_list to + * be created. */ + +static PRPollDesc pd[POLL_DESC_COUNT]; + +static void Test(void) +{ + int i; + PRInt32 rv; + PRIntervalTime timeout; + + timeout = PR_MillisecondsToInterval(10); + /* cause syspoll_list to grow */ + for (i = 1; i <= POLL_DESC_COUNT; i++) { + rv = PR_Poll(pd, i, timeout); + if (rv != 0) { + fprintf(stderr, + "PR_Poll should time out but returns %d (%d, %d)\n", + rv, PR_GetError(), PR_GetOSError()); + exit(1); + } + } + /* syspoll_list should be large enough for all these */ + for (i = POLL_DESC_COUNT; i >= 1; i--) { + rv = PR_Poll(pd, i, timeout); + if (rv != 0) { + fprintf(stderr, "PR_Poll should time out but returns %d\n", rv); + exit(1); + } + } +} + +static void ThreadFunc(void *arg) +{ + Test(); +} + +int main(int argc, char **argv) +{ + int i; + PRThread *thread; + PRFileDesc *sock; + PRNetAddr addr; + + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons(0); + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + for (i = 0; i < POLL_DESC_COUNT; i++) { + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + pd[i].fd = sock; + pd[i].in_flags = PR_POLL_READ; + } + + /* first run the test on the primordial thread */ + Test(); + + /* then run the test on all three kinds of threads */ + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + thread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + for (i = 0; i < POLL_DESC_COUNT; i++) { + if (PR_Close(pd[i].fd) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + } + PR_Cleanup(); + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prselect.c b/src/libs/xpcom18a4/nsprpub/pr/tests/prselect.c new file mode 100644 index 00000000..ff6ebdc6 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prselect.c @@ -0,0 +1,372 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_err.c +** +** Description: tests PR_Select with sockets Error condition functions. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" + + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prerror.h" +#include "prnetdb.h" + +#include +#include +#include + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static Test_Result (int result) +{ + if (result == PASS) + printf ("PASS\n"); + else + printf ("FAIL\n"); +} + +static void +clientThreadFunc(void *arg) +{ + PRUint16 port = (PRUint16) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + + addr.inet.family = AF_INET; + addr.inet.port = PR_htons(port); + addr.inet.ip = PR_htonl(INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds; + PRIntn nfds; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRThread *clientThread; + PRInt32 retVal; + PRIntn i, j; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Timeout, error\n"); + printf("reporting, and normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + if (!debug_mode) Test_Result(FAIL); + exit(1); + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* Testing timeout */ + if (debug_mode) printf("PR_Select should time out in 5 seconds\n"); + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Select should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + if (!debug_mode) Test_Result(FAIL); + } + exit(1); + } + if (debug_mode) printf("PR_Select timed out. Test passed.\n\n"); + else Test_Result(PASS); + + /* Testing bad fd */ + printf("PR_Select should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + exit(1); + } + + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + PR_FD_SET(badFD, &readFdSet); + PR_Close(badFD); /* make the fd bad */ + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Select returns %d\n", retVal); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + } + exit(1); + } + printf("PR_Select detected a bad fd. Test passed.\n\n"); + PR_FD_CLR(badFD, &readFdSet); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + exit(1); + } + + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + + /* set up the fd array */ + fds = fds0; + other_fds = fds1; + fds[0] = listenSock1; + fds[1] = listenSock2; + nfds = 2; + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* 20 events total */ + i = 0; + while (i < 20) { + PRFileDesc **tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + exit(1); + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_fds[j] = fds[j]; + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + exit(1); + } + other_fds[nextIndex] = sock; + PR_FD_SET(sock, &readFdSet); + nextIndex++; + } + PR_FD_SET(fds[j], &readFdSet); + } + + for (j = 2; j < nfds; j++) { + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRInt32 nBytes; + + PR_FD_CLR(fds[j], &readFdSet); + nEvents++; + nBytes = PR_Read(fds[j], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + exit(1); + } + /* Just to be safe */ + buf[127] = '\0'; + PR_Close(fds[j]); + printf("The server received \"%s\" from a client\n", buf); + } else { + PR_FD_SET(fds[j], &readFdSet); + other_fds[nextIndex] = fds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = fds; + fds = other_fds; + other_fds = tmp; + nfds = nextIndex; + i += nEvents; + } + + printf("All tests finished\n"); + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/prttools.h b/src/libs/xpcom18a4/nsprpub/pr/tests/prttools.h new file mode 100644 index 00000000..dc38f316 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/prttools.h @@ -0,0 +1,43 @@ +/* -*- 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 ***** */ + +/* Used in Regress Tool */ +#define NOSTATUS 2 +#define PASS 1 +#define FAIL 0 + +PRIntn debug_mode=0; diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/randseed.c b/src/libs/xpcom18a4/nsprpub/pr/tests/randseed.c new file mode 100644 index 00000000..df80bb8f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/randseed.c @@ -0,0 +1,162 @@ +/* -*- 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 ***** */ + +/* +** File: rngseed.c +** Description: +** Test NSPR's Random Number Seed generator +** +** Initial test: Just make sure it outputs some data. +** +** ... more? ... check some iterations to ensure it is random (no dupes) +** ... more? ... histogram distribution of random numbers +*/ + +#include +#include +#include +#include +#include + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +PRIntn optRandCount = 30; +char buf[40]; +PRSize bufSize = sizeof(buf); +PRSize rSize; +PRIntn i; + +/* +** Emit help text for this test +*/ +static void Help( void ) +{ + printf("Template: Help(): display your help message(s) here"); + exit(1); +} /* end Help() */ + +static void PrintRand( void *buf, PRIntn size ) +{ + PRUint32 *rp = buf; + PRIntn i; + + printf("%4.4d--\n", size ); + while (size > 0 ) { + switch( size ) { + case 1 : + printf("%2.2X\n", *(rp++) ); + size -= 4; + break; + case 2 : + printf("%4.4X\n", *(rp++) ); + size -= 4; + break; + case 3 : + printf("%6.6X\n", *(rp++) ); + size -= 4; + break; + default: + while ( size >= 4) { + PRIntn i = 3; + do { + printf("%8.8X ", *(rp++) ); + size -= 4; + } while( i-- ); + i = 3; + printf("\n"); + } + break; + } /* end switch() */ + } /* end while() */ +} /* end PrintRand() */ + + +PRIntn main(PRIntn argc, char *argv[]) +{ + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdv"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + msgLevel = PR_LOG_DEBUG; + break; + case 'h': /* help message */ + Help(); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + lm = PR_NewLogModule("Test"); /* Initialize logging */ + for ( i = 0; i < optRandCount ; i++ ) { + memset( buf, 0, bufSize ); + rSize = PR_GetRandomNoise( buf, bufSize ); + if (!rSize) { + fprintf(stderr, "Not implemented\n" ); + failed_already = PR_TRUE; + break; + } + if (debug) PrintRand( buf, rSize ); + } + + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end template.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ranfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/ranfile.c new file mode 100644 index 00000000..a024bcd8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ranfile.c @@ -0,0 +1,433 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Contact: AOF +** +** Name: ranfile.c +** +** Description: Test to hammer on various components of NSPR +** Modification History: +** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmem.h" +#include "prinrval.h" +#include "prio.h" + +#include +#include + +static PRIntn debug_mode = 0; +static PRIntn failed_already=0; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef enum {sg_go, sg_stop, sg_done} Action; +typedef enum {sg_okay, sg_open, sg_close, sg_delete, sg_write, sg_seek} Problem; + +typedef struct Hammer_s { + PRLock *ml; + PRCondVar *cv; + PRUint32 id; + PRUint32 limit; + PRUint32 writes; + PRThread *thread; + PRIntervalTime timein; + Action action; + Problem problem; +} Hammer_t; + +#define DEFAULT_LIMIT 10 +#define DEFAULT_THREADS 2 +#define DEFAULT_LOOPS 1 + +static PRInt32 pageSize = 1024; +static const char* baseName = "./"; +static const char *programName = "Random File"; + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +/*********************************************************************** +** PRIVATE FUNCTION: Random +** DESCRIPTION: +** Generate a pseudo-random number +** INPUTS: None +** OUTPUTS: None +** RETURN: A pseudo-random unsigned number, 32-bits wide +** SIDE EFFECTS: +** Updates random seed (a static) +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: +** Uses the current interval timer value, promoted to a 64 bit +** float as a multiplier for a static residue (which begins +** as an uninitialized variable). The result is bits [16..48) +** of the product. Seed is then updated with the return value +** promoted to a float-64. +***********************************************************************/ +static PRUint32 Random(void) +{ + PRUint32 rv; + PRUint64 shift; + static PRFloat64 seed = 0x58a9382; /* Just make sure it isn't 0! */ + PRFloat64 random = seed * (PRFloat64)PR_IntervalNow(); + LL_USHR(shift, *((PRUint64*)&random), 16); + LL_L2UI(rv, shift); + seed = (PRFloat64)rv; + return rv; +} /* Random */ + +/*********************************************************************** +** PRIVATE FUNCTION: Thread +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: A pointer to the thread's private data +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes a file +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** This function is a root of a thread +** 1) Creates a (hopefully) unique file in /usr/tmp/ +** 2) Writes a zero to a random number of sequential pages +** 3) Closes the file +** 4) Reopens the file +** 5) Seeks to a random page within the file +** 6) Writes a one byte on that page +** 7) Repeat steps [5..6] for each page in the file +** 8) Close and delete the file +** 9) Repeat steps [1..8] until told to stop +** 10) Notify complete and return +***********************************************************************/ +static void PR_CALLBACK Thread(void *arg) +{ + PRUint32 index; + char filename[30]; + const char zero = 0; + PRFileDesc *file = NULL; + PRStatus rv = PR_SUCCESS; + Hammer_t *cd = (Hammer_t*)arg; + + (void)sprintf(filename, "%ssg%04ld.dat", baseName, cd->id); + + if (debug_mode) printf("Starting work on %s\n", filename); + + while (PR_TRUE) + { + PRUint32 bytes; + PRUint32 minor = (Random() % cd->limit) + 1; + PRUint32 random = (Random() % cd->limit) + 1; + PRUint32 pages = (Random() % cd->limit) + 10; + while (minor-- > 0) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto finished; + cd->problem = sg_open; + file = PR_Open(filename, PR_RDWR|PR_CREATE_FILE, 0666); + if (file == NULL) goto finished; + for (index = 0; index < pages; index++) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto close; + cd->problem = sg_seek; + bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET); + if (bytes != pageSize * index) goto close; + cd->problem = sg_write; + bytes = PR_Write(file, &zero, sizeof(zero)); + if (bytes <= 0) goto close; + cd->writes += 1; + } + cd->problem = sg_close; + rv = PR_Close(file); + if (rv != PR_SUCCESS) goto purge; + + cd->problem = sg_okay; + if (cd->action != sg_go) goto purge; + + cd->problem = sg_open; + file = PR_Open(filename, PR_RDWR, 0666); + for (index = 0; index < pages; index++) + { + cd->problem = sg_okay; + if (cd->action != sg_go) goto close; + cd->problem = sg_seek; + bytes = PR_Seek(file, pageSize * index, PR_SEEK_SET); + if (bytes != pageSize * index) goto close; + cd->problem = sg_write; + bytes = PR_Write(file, &zero, sizeof(zero)); + if (bytes <= 0) goto close; + cd->writes += 1; + random = (random + 511) % pages; + } + cd->problem = sg_close; + rv = PR_Close(file); + if (rv != PR_SUCCESS) goto purge; + cd->problem = sg_delete; + rv = PR_Delete(filename); + if (rv != PR_SUCCESS) goto finished; + } + } + +close: + (void)PR_Close(file); +purge: + (void)PR_Delete(filename); +finished: + PR_Lock(cd->ml); + cd->action = sg_done; + PR_NotifyCondVar(cd->cv); + PR_Unlock(cd->ml); + + if (debug_mode) printf("Ending work on %s\n", filename); + + return; +} /* Thread */ + +static Hammer_t hammer[100]; +static PRCondVar *cv; +/*********************************************************************** +** PRIVATE FUNCTION: main +** DESCRIPTION: +** Hammer on the file I/O system +** INPUTS: The usual argc and argv +** argv[0] - program name (not used) +** argv[1] - the number of times to execute the major loop +** argv[2] - the number of threads to toss into the batch +** argv[3] - the clipping number applied to randoms +** default values: loops = 2, threads = 10, limit = 57 +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** Creates, accesses and deletes lots of files +** RESTRICTIONS: +** (Currently) must have file create permission in "/usr/tmp". +** MEMORY: NA +** ALGORITHM: +** 1) Fork a "Thread()" +** 2) Wait for 'interleave' seconds +** 3) For [0..'threads') repeat [1..2] +** 4) Mark all objects to stop +** 5) Collect the threads, accumulating the results +** 6) For [0..'loops') repeat [1..5] +** 7) Print accumulated results and exit +** +** Characteristic output (from IRIX) +** Random File: Using loops = 2, threads = 10, limit = 57 +** Random File: [min [avg] max] writes/sec average +***********************************************************************/ +int main (int argc, char *argv[]) +{ + PRLock *ml; + PRUint32 id = 0; + int active, poll; + PRIntervalTime interleave; + PRIntervalTime duration = 0; + int limit = 0, loops = 0, threads = 0, times; + PRUint32 writes, writesMin = 0x7fffffff, writesTot = 0, durationTot = 0, writesMax = 0; + + const char *where[] = {"okay", "open", "close", "delete", "write", "seek"}; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:t:i:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'G': /* global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'l': /* limiting number */ + limit = atoi(opt->value); + break; + case 't': /* number of threads */ + threads = atoi(opt->value); + break; + case 'i': /* iteration counter */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + interleave = PR_SecondsToInterval(10); + +#ifdef XP_MAC + SetupMacPrintfLog("ranfile.log"); + debug_mode = 1; +#endif + + ml = PR_NewLock(); + cv = PR_NewCondVar(ml); + + if (loops == 0) loops = DEFAULT_LOOPS; + if (limit == 0) limit = DEFAULT_LIMIT; + if (threads == 0) threads = DEFAULT_THREADS; + + if (debug_mode) printf( + "%s: Using loops = %d, threads = %d, limit = %d and %s threads\n", + programName, loops, threads, limit, + (thread_scope == PR_LOCAL_THREAD) ? "LOCAL" : "GLOBAL"); + + for (times = 0; times < loops; ++times) + { + if (debug_mode) printf("%s: Setting concurrency level to %d\n", programName, times + 1); + PR_SetConcurrency(times + 1); + for (active = 0; active < threads; active++) + { + hammer[active].ml = ml; + hammer[active].cv = cv; + hammer[active].id = id++; + hammer[active].writes = 0; + hammer[active].action = sg_go; + hammer[active].problem = sg_okay; + hammer[active].limit = (Random() % limit) + 1; + hammer[active].timein = PR_IntervalNow(); + hammer[active].thread = PR_CreateThread( + PR_USER_THREAD, Thread, &hammer[active], + PR_GetThreadPriority(PR_GetCurrentThread()), + thread_scope, PR_JOINABLE_THREAD, 0); + + PR_Lock(ml); + PR_WaitCondVar(cv, interleave); /* start new ones slowly */ + PR_Unlock(ml); + } + + /* + * The last thread started has had the opportunity to run for + * 'interleave' seconds. Now gather them all back in. + */ + PR_Lock(ml); + for (poll = 0; poll < threads; poll++) + { + if (hammer[poll].action == sg_go) /* don't overwrite done */ + hammer[poll].action = sg_stop; /* ask him to stop */ + } + PR_Unlock(ml); + + while (active > 0) + { + for (poll = 0; poll < threads; poll++) + { + PR_Lock(ml); + while (hammer[poll].action < sg_done) + PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(ml); + + active -= 1; /* this is another one down */ + (void)PR_JoinThread(hammer[poll].thread); + hammer[poll].thread = NULL; + if (hammer[poll].problem == sg_okay) + { + duration = PR_IntervalToMilliseconds( + PR_IntervalNow() - hammer[poll].timein); + writes = hammer[poll].writes * 1000 / duration; + if (writes < writesMin) + writesMin = writes; + if (writes > writesMax) + writesMax = writes; + writesTot += hammer[poll].writes; + durationTot += duration; + } + else + if (debug_mode) printf( + "%s: test failed %s after %ld seconds\n", + programName, where[hammer[poll].problem], duration); + else failed_already=1; + } + } + } + if (debug_mode) printf( + "%s: [%ld [%ld] %ld] writes/sec average\n", + programName, writesMin, writesTot * 1000 / durationTot, writesMax); + + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + + if (failed_already) + { + printf("FAIL\n"); + return 1; + } + else + { + printf("PASS\n"); + return 0; + } +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/rmdir.c b/src/libs/xpcom18a4/nsprpub/pr/tests/rmdir.c new file mode 100644 index 00000000..81689e8d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/rmdir.c @@ -0,0 +1,127 @@ +/* -*- 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 ***** */ + +/* +** File: rmdir.c +** Description: Demonstrate bugzilla 80884. +** +** after fix to unix_errors.c, message should report correct +** failure of PR_Rmdir(). +** +** +** +*/ + +#include +#include +#include +#include +#include "plgetopt.h" + +#define DIRNAME "xxxBug80884/" +#define FILENAME "file80883" + +PRBool failed_already = PR_FALSE; +PRBool debug_mode = PR_FALSE; + +PRLogModuleInfo *lm; + +/* +** Help() -- print Usage information +*/ +static void Help( void ) { + fprintf(stderr, "template usage:\n" + "\t-d debug mode\n" + ); +} /* --- end Help() */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRFileDesc* fd; + PRErrorCode err; + + /* parse command line options */ + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + lm = PR_NewLogModule( "testcase" ); + + (void) PR_MkDir( DIRNAME, 0777); + fd = PR_Open( DIRNAME FILENAME, PR_CREATE_FILE|PR_RDWR, 0666); + if (fd == 0) { + PRErrorCode err = PR_GetError(); + fprintf(stderr, "create file fails: %d: %s\n", err, + PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); + failed_already = PR_TRUE; + goto Finished; + } + + PR_Close(fd); + + if (PR_RmDir( DIRNAME ) == PR_SUCCESS) { + fprintf(stderr, "remove directory succeeds\n"); + failed_already = PR_TRUE; + goto Finished; + } + + err = PR_GetError(); + fprintf(stderr, "remove directory fails with: %d: %s\n", err, + PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); + + (void) PR_Delete( DIRNAME FILENAME); + (void) PR_RmDir( DIRNAME ); + + return 0; + +Finished: + if ( debug_mode ) printf("%s\n", ( failed_already ) ? "FAILED" : "PASS" ); + return( (failed_already)? 1 : 0 ); +} /* --- end main() */ +/* --- end template.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.ksh b/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.ksh new file mode 100755 index 00000000..3af86d39 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.ksh @@ -0,0 +1,292 @@ +#!/bin/ksh +# +# ***** 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 ***** + +# +# tests.ksh +# korn shell script for nspr tests +# + +SYSTEM_INFO=`uname -a` +OS_ARCH=`uname -s` +if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "OS/2" ] +then + NULL_DEVICE=nul +else + NULL_DEVICE=/dev/null +fi + +# +# Irrevelant tests +# +#bug1test - used to demonstrate a bug on NT +#bigfile2 - requires 4Gig file creation. See BugZilla #5451 +#bigfile3 - requires 4Gig file creation. See BugZilla #5451 +#dbmalloc - obsolete; originally for testing debug version of nspr's malloc +#dbmalloc1 - obsolete; originally for testing debug version of nspr's malloc +#depend - obsolete; used to test a initial spec for library dependencies +#dceemu - used to tests special functions in NSPR for DCE emulation +#ipv6 - IPV6 not in use by NSPR clients +#mbcs - tests use of multi-byte charset for filenames. See BugZilla #25140 +#sproc_ch - obsolete; sproc-based tests for Irix +#sproc_p - obsolete; sproc-based tests for Irix +#io_timeoutk - obsolete; subsumed in io_timeout +#io_timeoutu - obsolete; subsumed in io_timeout +#prftest1 - obsolete; subsumed by prftest +#prftest2 - obsolete; subsumed by prftest +#prselect - obsolete; PR_Select is obsolete +#select2 - obsolete; PR_Select is obsolete +#sem - obsolete; PRSemaphore is obsolete +#stat - for OS2? +#suspend - private interfaces PR_SuspendAll, PR_ResumeAll, etc.. +#thruput - needs to be run manually as client/server +#time - used to measure time with native calls and nspr calls +#tmoacc - should be run with tmocon +#tmocon - should be run with tmoacc +#op_noacc - limited use +#yield - limited use for PR_Yield + +# +# Tests not run (but should) +# + +#forktest (failed on IRIX) +#nbconn - fails on some platforms +#poll_er - fails on some platforms? limited use? +#prpoll - the bad-FD test needs to be moved to a different test +#sleep - specific to OS/2 + +LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE} + +# +# Tests run on all platforms +# + +TESTS=" +accept +acceptread +acceptreademu +affinity +alarm +anonfm +atomic +attach +bigfile +cleanup +cltsrv +concur +cvar +cvar2 +dlltest +dtoa +errcodes +exit +fdcach +fileio +foreign +formattm +fsync +gethost +getproto +i2l +initclk +inrval +instrumt +intrio +intrupt +io_timeout +ioconthr +join +joinkk +joinku +joinuk +joinuu +layer +lazyinit +libfilename +lltest +lock +lockfile +logger +many_cv +multiwait +nameshm1 +nblayer +nonblock +ntioto +ntoh +op_2long +op_excl +op_filnf +op_filok +op_nofil +parent +peek +perf +pipeping +pipeping2 +pipeself +poll_nm +poll_to +pollable +prftest +primblok +provider +prpollml +ranfile +randseed +rwlocktest +sel_spd +selct_er +selct_nm +selct_to +selintr +sema +semaerr +semaping +sendzlf +server_test +servr_kk +servr_uk +servr_ku +servr_uu +short_thread +sigpipe +socket +sockopt +sockping +sprintf +stack +stdio +str2addr +strod +switch +system +testbit +testfile +threads +timemac +timetest +tpd +udpsrv +vercheck +version +writev +xnotify +zerolen" + +rval=0 + + +# +# When set, value of the environment variable TEST_TIMEOUT is the maximum +# time (secs) allowed for a test program beyond which it is terminated. +# If TEST_TIMEOUT is not set or if it's value is 0, then test programs +# don't timeout. +# +# Running runtests.ksh under MKS toolkit on NT, 95, 98 does not cause +# timeout detection correctly. For these platforms, do not attempt timeout +# test. (lth). +# +# + +OS_PLATFORM=`uname` +OBJDIR=`basename $PWD` +echo "\nNSPR Test Results - $OBJDIR\n" +echo "BEGIN\t\t\t`date`" +echo "NSPR_TEST_LOGFILE\t${LOGFILE}\n" +echo "Test\t\t\tResult\n" +if [ $OS_PLATFORM = "Windows_95" ] || [ $OS_PLATFORM = "Windows_98" ] || [ $OS_PLATFORM = "Windows_NT" ] || [ $OS_PLATFORM = "OS/2" ] ; then + for prog in $TESTS + do + echo "$prog\c" + echo "\nBEGIN TEST: $prog\n" >> ${LOGFILE} 2>&1 + ./$prog >> ${LOGFILE} 2>&1 + if [ 0 = $? ] ; then + echo "\t\t\tPassed"; + else + echo "\t\t\tFAILED"; + rval=1 + fi; + echo "\nEND TEST: $prog\n" >> ${LOGFILE} 2>&1 + done +else + for prog in $TESTS + do + echo "$prog\c" + echo "\nBEGIN TEST: $prog\n" >> ${LOGFILE} 2>&1 + export test_rval + ./$prog >> ${LOGFILE} 2>&1 & + test_pid=$! + sleep_pid=0 + if [ "$TEST_TIMEOUT" -gt 0 ] + then + (sleep $TEST_TIMEOUT; kill $test_pid >/dev/null 2>&1 ) & + sleep_pid=$! + fi + wait $test_pid + test_rval=$? + [ $sleep_pid -eq 0 ] || kill $sleep_pid >/dev/null 2>&1 + if [ 0 = $test_rval ] ; then + echo "\t\t\tPassed"; + else + echo "\t\t\tFAILED"; + rval=1 + fi; + echo "\nEND TEST: $prog\n" >> ${LOGFILE} 2>&1 + done +fi; + +echo "END\t\t\t`date`" +exit $rval + + + + + + + + + + + + + + + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.sh b/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.sh new file mode 100755 index 00000000..bb4a65eb --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/runtests.sh @@ -0,0 +1,292 @@ +#!/bin/sh +# +# ***** 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 ***** + +# +# tests.ksh +# korn shell script for nspr tests +# + +SYSTEM_INFO=`uname -a` +OS_ARCH=`uname -s` +if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "OS/2" ] +then + NULL_DEVICE=nul +else + NULL_DEVICE=/dev/null +fi + +# +# Irrevelant tests +# +#bug1test - used to demonstrate a bug on NT +#bigfile2 - requires 4Gig file creation. See BugZilla #5451 +#bigfile3 - requires 4Gig file creation. See BugZilla #5451 +#dbmalloc - obsolete; originally for testing debug version of nspr's malloc +#dbmalloc1 - obsolete; originally for testing debug version of nspr's malloc +#depend - obsolete; used to test a initial spec for library dependencies +#dceemu - used to tests special functions in NSPR for DCE emulation +#ipv6 - IPV6 not in use by NSPR clients +#mbcs - tests use of multi-byte charset for filenames. See BugZilla #25140 +#sproc_ch - obsolete; sproc-based tests for Irix +#sproc_p - obsolete; sproc-based tests for Irix +#io_timeoutk - obsolete; subsumed in io_timeout +#io_timeoutu - obsolete; subsumed in io_timeout +#prftest1 - obsolete; subsumed by prftest +#prftest2 - obsolete; subsumed by prftest +#prselect - obsolete; PR_Select is obsolete +#select2 - obsolete; PR_Select is obsolete +#sem - obsolete; PRSemaphore is obsolete +#stat - for OS2? +#suspend - private interfaces PR_SuspendAll, PR_ResumeAll, etc.. +#thruput - needs to be run manually as client/server +#time - used to measure time with native calls and nspr calls +#tmoacc - should be run with tmocon +#tmocon - should be run with tmoacc +#op_noacc - limited use +#yield - limited use for PR_Yield + +# +# Tests not run (but should) +# + +#forktest (failed on IRIX) +#nbconn - fails on some platforms +#poll_er - fails on some platforms? limited use? +#prpoll - the bad-FD test needs to be moved to a different test +#sleep - specific to OS/2 + +LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE} + +# +# Tests run on all platforms +# + +TESTS=" +accept +acceptread +acceptreademu +affinity +alarm +anonfm +atomic +attach +bigfile +cleanup +cltsrv +concur +cvar +cvar2 +dlltest +dtoa +errcodes +exit +fdcach +fileio +foreign +formattm +fsync +gethost +getproto +i2l +initclk +inrval +instrumt +intrio +intrupt +io_timeout +ioconthr +join +joinkk +joinku +joinuk +joinuu +layer +lazyinit +libfilename +lltest +lock +lockfile +logger +many_cv +multiwait +nameshm1 +nblayer +nonblock +ntioto +ntoh +op_2long +op_excl +op_filnf +op_filok +op_nofil +parent +peek +perf +pipeping +pipeping2 +pipeself +poll_nm +poll_to +pollable +prftest +primblok +provider +prpollml +ranfile +randseed +rwlocktest +sel_spd +selct_er +selct_nm +selct_to +selintr +sema +semaerr +semaping +sendzlf +server_test +servr_kk +servr_uk +servr_ku +servr_uu +short_thread +sigpipe +socket +sockopt +sockping +sprintf +stack +stdio +str2addr +strod +switch +system +testbit +testfile +threads +timemac +timetest +tpd +udpsrv +vercheck +version +writev +xnotify +zerolen" + +rval=0 + + +# +# When set, value of the environment variable TEST_TIMEOUT is the maximum +# time (secs) allowed for a test program beyond which it is terminated. +# If TEST_TIMEOUT is not set or if it's value is 0, then test programs +# don't timeout. +# +# Running runtests.ksh under MKS toolkit on NT, 95, 98 does not cause +# timeout detection correctly. For these platforms, do not attempt timeout +# test. (lth). +# +# + +OS_PLATFORM=`uname` +OBJDIR=`basename $PWD` +printf "\nNSPR Test Results - $OBJDIR\n\n" +printf "BEGIN\t\t\t`date`\n" +printf "NSPR_TEST_LOGFILE\t${LOGFILE}\n\n" +printf "Test\t\t\tResult\n\n" +if [ $OS_PLATFORM = "Windows_95" ] || [ $OS_PLATFORM = "Windows_98" ] || [ $OS_PLATFORM = "Windows_NT" ] || [ $OS_PLATFORM = "OS/2" ] ; then + for prog in $TESTS + do + printf "$prog" + printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + ./$prog >> ${LOGFILE} 2>&1 + if [ 0 = $? ] ; then + printf "\t\t\tPassed\n"; + else + printf "\t\t\tFAILED\n"; + rval=1 + fi; + printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + done +else + for prog in $TESTS + do + printf "$prog" + printf "\nBEGIN TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + export test_rval + ./$prog >> ${LOGFILE} 2>&1 & + test_pid=$! + sleep_pid=0 + if test -n "$TEST_TIMEOUT" && test "$TEST_TIMEOUT" -gt 0 + then + (sleep $TEST_TIMEOUT; kill $test_pid >/dev/null 2>&1 ) & + sleep_pid=$! + fi + wait $test_pid + test_rval=$? + [ $sleep_pid -eq 0 ] || kill $sleep_pid >/dev/null 2>&1 + if [ 0 = $test_rval ] ; then + printf "\t\t\tPassed\n"; + else + printf "\t\t\tFAILED\n"; + rval=1 + fi; + printf "\nEND TEST: $prog\n\n" >> ${LOGFILE} 2>&1 + done +fi; + +printf "END\t\t\t`date`\n" +exit $rval + + + + + + + + + + + + + + + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/runy2ktests.ksh b/src/libs/xpcom18a4/nsprpub/pr/tests/runy2ktests.ksh new file mode 100755 index 00000000..e7a32501 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/runy2ktests.ksh @@ -0,0 +1,269 @@ +#!/bin/ksh +# +# ***** 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 ***** + +# +# runy2ktests.ksh +# Set system clock to Y2K dates of interest and run the Y2K tests. +# Needs root/administrator privilege +# +# WARNING: Because this script needs to be run with root/administrator +# privilege, thorough understanding of the script and extreme +# caution are urged. +# + +# +# SECTION I +# Define variables +# + +SYSTEM_INFO=`uname -a` +OS_ARCH=`uname -s` +if [ $OS_ARCH = "Windows_NT" ] || [ $OS_ARCH = "Windows_95" ] +then + NULL_DEVICE=nul +else + NULL_DEVICE=/dev/null +fi + +# +# Test dates for NSPR Y2K tests +# +Y2KDATES=" 123123591998.55 + 090923591999.55 + 123123591999.55 + 022823592000.55 + 022923592000.55 + 123123592000.55" + +Y2KDATES_AIX=" 12312359.5598 + 09092359.5599 + 12312359.5599 + 02282359.5500 + 02292359.5500 + 12312359.5500" + +Y2KDATES_HPUX=" 123123591998 + 090923591999 + 123123591999 + 022823592000 + 022923592000 + 123123592000" + +Y2KDATES_MKS=" 1231235998.55 + 0909235999.55 + 1231235999.55 + 0228235900.55 + 0229235900.55 + 1231235900.55" + +# +# NSPR Y2K tests +# +Y2KTESTS=" +y2k \n +y2ktmo \n +y2k \n +../runtests.ksh" + +Y2KTESTS_HPUX=" +y2k \n +y2ktmo -l 60\n +y2k \n +../runtests.ksh" + +# +# SECTION II +# Define functions +# + +save_date() +{ + case $OS_ARCH in + AIX) + SAVED_DATE=`date "+%m%d%H%M.%S%y"` + ;; + HP-UX) + SAVED_DATE=`date "+%m%d%H%M%Y"` + ;; + Windows_NT) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + Windows_95) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + *) + SAVED_DATE=`date "+%m%d%H%M%Y.%S"` + ;; + esac +} + +set_date() +{ + case $OS_ARCH in + Windows_NT) +# +# The date command in MKS Toolkit releases 5.1 and 5.2 +# uses the current DST status for the date we want to +# set the system clock to. However, the DST status for +# that date may be different from the current DST status. +# We can work around this problem by invoking the date +# command with the same date twice. +# + date "$1" > $NULL_DEVICE + date "$1" > $NULL_DEVICE + ;; + *) + date "$1" > $NULL_DEVICE + ;; + esac +} + +restore_date() +{ + set_date "$SAVED_DATE" +} + +savedate() +{ + case $OS_ARCH in + AIX) + SAVED_DATE=`date "+%m%d%H%M.%S%y"` + ;; + HP-UX) + SAVED_DATE=`date "+%m%d%H%M%Y"` + ;; + Windows_NT) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + Windows_95) + SAVED_DATE=`date "+%m%d%H%M%y.%S"` + ;; + *) + SAVED_DATE=`date "+%m%d%H%M%Y.%S"` + ;; + esac +} + +set_y2k_test_parameters() +{ +# +# set dates +# + case $OS_ARCH in + AIX) + DATES=$Y2KDATES_AIX + ;; + HP-UX) + DATES=$Y2KDATES_HPUX + ;; + Windows_NT) + DATES=$Y2KDATES_MKS + ;; + Windows_95) + DATES=$Y2KDATES_MKS + ;; + *) + DATES=$Y2KDATES + ;; + esac + +# +# set tests +# + case $OS_ARCH in + HP-UX) + TESTS=$Y2KTESTS_HPUX + ;; + *) + TESTS=$Y2KTESTS + ;; + esac +} + +# +# runtests: +# - runs each test in $TESTS after setting the +# system clock to each date in $DATES +# + +runtests() +{ +for newdate in ${DATES} +do + set_date $newdate + echo $newdate + echo "BEGIN\t\t\t`date`" + echo "Date\t\t\t\t\tTest\t\t\tResult" + echo $TESTS | while read prog + do + echo "`date`\t\t\c" + echo "$prog\c" + ./$prog >> ${LOGFILE} 2>&1 + if [ 0 = $? ] ; then + echo "\t\t\tPassed"; + else + echo "\t\t\tFAILED"; + fi; + done + echo "END\t\t\t`date`\n" +done + +} + +# +# SECTION III +# Run tests +# + +LOGFILE=${NSPR_TEST_LOGFILE:-$NULL_DEVICE} +OBJDIR=`basename $PWD` +echo "\nNSPR Year 2000 Test Results - $OBJDIR\n" +echo "SYSTEM:\t\t\t${SYSTEM_INFO}" +echo "NSPR_TEST_LOGFILE:\t${LOGFILE}\n" + + +save_date + +# +# Run NSPR Y2k and standard tests +# + +set_y2k_test_parameters +runtests + +restore_date diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/rwlocktest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/rwlocktest.c new file mode 100644 index 00000000..b7c4f1e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/rwlocktest.c @@ -0,0 +1,241 @@ +/* ***** 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 ***** */ + + +/* + * + * RWLock tests + * + * Several threads are created to access and modify data arrays using + * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are + * initialized with random data and a third array, array_C, is initialized + * with the sum of the first 2 arrays. + * + * Each one of the threads acquires a read lock to verify that the sum of + * the arrays A and B is equal to array C, and acquires a write lock to + * consistently update arrays A and B so that their is equal to array C. + * + */ + +#include "nspr.h" +#include "plgetopt.h" +#include "prrwlock.h" + +static int _debug_on; +static void rwtest(void *args); +static PRInt32 *array_A,*array_B,*array_C; +static void update_array(void); +static void check_array(void); + +typedef struct thread_args { + PRRWLock *rwlock; + PRInt32 loop_cnt; +} thread_args; + +PRFileDesc *output; +PRFileDesc *errhandle; + +#define DEFAULT_THREAD_CNT 4 +#define DEFAULT_LOOP_CNT 100 +#define TEST_ARRAY_SIZE 100 + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 cnt; + PRStatus rc; + PRInt32 i; + + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; + PRInt32 loop_cnt = DEFAULT_LOOP_CNT; + PRThread **threads; + thread_args *params; + PRRWLock *rwlock1; + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 't': /* thread count */ + thread_cnt = atoi(opt->value); + break; + case 'c': /* loop count */ + loop_cnt = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(4); + + output = PR_GetSpecialFD(PR_StandardOutput); + errhandle = PR_GetSpecialFD(PR_StandardError); + + rwlock1 = PR_NewRWLock(0,"Lock 1"); + if (rwlock1 == NULL) { + PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", + PR_GetError()); + return 1; + } + + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); + params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt); + + /* + * allocate and initialize data arrays + */ + array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); + cnt = 0; + for (i=0; i < TEST_ARRAY_SIZE;i++) { + array_A[i] = cnt++; + array_B[i] = cnt++; + array_C[i] = array_A[i] + array_B[i]; + } + + if (_debug_on) + PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0], + thread_cnt, loop_cnt); + for(cnt = 0; cnt < thread_cnt; cnt++) { + PRThreadScope scope; + + params[cnt].rwlock = rwlock1; + params[cnt].loop_cnt = loop_cnt; + + /* + * create LOCAL and GLOBAL threads alternately + */ + if (cnt & 1) + scope = PR_LOCAL_THREAD; + else + scope = PR_GLOBAL_THREAD; + + threads[cnt] = PR_CreateThread(PR_USER_THREAD, + rwtest, ¶ms[cnt], + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + if (threads[cnt] == NULL) { + PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", + PR_GetError()); + PR_ProcessExit(2); + } + if (_debug_on) + PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0], + threads[cnt]); + } + + for(cnt = 0; cnt < thread_cnt; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + + } + + PR_DELETE(threads); + PR_DELETE(params); + + PR_DELETE(array_A); + PR_DELETE(array_B); + PR_DELETE(array_C); + + PR_DestroyRWLock(rwlock1); + + + printf("PASS\n"); + return 0; +} + +static void rwtest(void *args) +{ + PRInt32 index; + thread_args *arg = (thread_args *) args; + + + for (index = 0; index < arg->loop_cnt; index++) { + + /* + * verify sum, update arrays and verify sum again + */ + + PR_RWLock_Rlock(arg->rwlock); + check_array(); + PR_RWLock_Unlock(arg->rwlock); + + PR_RWLock_Wlock(arg->rwlock); + update_array(); + PR_RWLock_Unlock(arg->rwlock); + + PR_RWLock_Rlock(arg->rwlock); + check_array(); + PR_RWLock_Unlock(arg->rwlock); + } + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] lock = 0x%x exiting\n", + PR_GetCurrentThread(), arg->rwlock); + +} + +static void check_array(void) +{ +PRInt32 i; + + for (i=0; i < TEST_ARRAY_SIZE;i++) + if (array_C[i] != (array_A[i] + array_B[i])) { + PR_fprintf(output, "Error - data check failed\n"); + PR_ProcessExit(1); + } +} + +static void update_array(void) +{ +PRInt32 i; + + for (i=0; i < TEST_ARRAY_SIZE;i++) { + array_A[i] += i; + array_B[i] -= i; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sel_spd.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sel_spd.c new file mode 100644 index 00000000..6760e640 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sel_spd.c @@ -0,0 +1,567 @@ +/* -*- 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 ***** */ + +/* + * Test the speed of select within NSPR + * + */ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ +PR_LogPrint(fmt); +return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define PORT_BASE 19000 + +typedef struct timer_slot_t { + unsigned long d_connect; + unsigned long d_cl_data; + unsigned long d_sv_data; + unsigned long d_close; + unsigned long d_total; + unsigned long requests; +} timer_slot_t; + +static long _iterations = 5; +static long _client_data = 8192; + +#if defined(XP_MAC) +/* + * Mac does not scale well specially the requirement for thread stack + * space and buffer allocation space. It is easy to get into a fragmented + * memory and not be able to allocate thread stack or client/server data + * buffer. +*/ +static long _server_data = (8*1024); +static long _threads_max = 10, _threads = 10; +#else +static long _server_data = (128*1024); +static long _threads_max = 10, _threads = 10; +#endif + +static int verbose=0; +static PRMonitor *exit_cv; +static long _thread_exit_count; +static timer_slot_t *timer_data; +static PRThreadScope scope1, scope2; + +void tally_results(int); + +/* return the diff in microseconds */ +unsigned long _delta(PRIntervalTime *start, PRIntervalTime *stop) +{ + /* + * Will C do the right thing with unsigned arithemtic? + */ + return PR_IntervalToMicroseconds(*stop - *start); +} + +int _readn(PRFileDesc *sock, char *buf, int len) +{ + int rem; + int bytes; + + for (rem=len; rem; rem -= bytes) { + bytes = PR_Recv(sock, buf+len-rem, rem, 0, PR_INTERVAL_NO_TIMEOUT); + if (bytes <= 0) + return -1; + } + return len; +} + +void +_thread_exit(int id) +{ + PR_EnterMonitor(exit_cv); +#ifdef DEBUG + fprintf(stdout, "Thread %d EXIT\n", id); +#endif + + _thread_exit_count--; + if (_thread_exit_count == 0) { +#ifdef DEBUG + fprintf(stdout, "Thread %d EXIT triggered notify\n", id); +#endif + PR_Notify(exit_cv); + } + PR_ExitMonitor(exit_cv); +} + +void +_server_thread(void *arg_id) +{ + void _client_thread(void *); + PRThread *thread; + int *id = (int *)arg_id; + PRFileDesc *sock; + PRSocketOptionData sockopt; + PRNetAddr sa; + PRFileDesc * newsock; + char *data_buffer = NULL; + int data_buffer_size; + int index; + PRIntervalTime start, + connect_done, + read_done, + write_done, + close_done; + + +#ifdef DEBUG + fprintf(stdout, "server thread %d alive\n", *id); +#endif + + data_buffer_size = (_client_data>_server_data?_client_data:_server_data); + + if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL ) { + fprintf(stderr, "Error creating buffer in server thread %d\n", *id); + goto done; + } + + + if ( (sock = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Error creating socket in server thread %d\n", *id); + goto done; + } + + sockopt.option = PR_SockOpt_Reuseaddr; + sockopt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(sock, &sockopt) == PR_FAILURE) { + fprintf(stderr, "Error setting socket option in server thread %d\n", *id); + goto done; + } + + memset(&sa, 0 , sizeof(sa)); + sa.inet.family = PR_AF_INET; + sa.inet.port = PR_htons(PORT_BASE + *id); + sa.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(sock, &sa) < 0) { + fprintf(stderr, "Error binding socket in server thread %d errno = %d\n", *id, errno); + goto done; + } + + if ( PR_Listen(sock, 32) < 0 ) { + fprintf(stderr, "Error listening to socket in server thread %d\n", *id); + goto done; + } + + /* Tell the client to start */ + if ( (thread = PR_CreateThread(PR_USER_THREAD, + _client_thread, + id, + PR_PRIORITY_NORMAL, + scope2, + PR_UNJOINABLE_THREAD, + 0)) == NULL) + fprintf(stderr, "Error creating client thread %d\n", *id); + + for (index = 0; index< _iterations; index++) { + +#ifdef DEBUG + fprintf(stdout, "server thread %d loop %d\n", *id, index); +#endif + + start = PR_IntervalNow(); + + if ( (newsock = PR_Accept(sock, &sa, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr, "Error accepting connection %d in server thread %d\n", + index, *id); + goto done; + } +#ifdef DEBUG + fprintf(stdout, "server thread %d got connection %d\n", *id, newsock); +#endif + + + connect_done = PR_IntervalNow(); + + if ( _readn(newsock, data_buffer, _client_data) < _client_data) { + fprintf(stderr, "Error reading client data for iteration %d in server thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "server thread %d read %d bytes\n", *id, _client_data); +#endif + read_done = PR_IntervalNow(); + + if ( PR_Send(newsock, data_buffer, _server_data, 0, + PR_INTERVAL_NO_TIMEOUT) < _server_data) { + fprintf(stderr, "Error sending client data for iteration %d in server thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "server thread %d write %d bytes\n", *id, _server_data); +#endif + + write_done = PR_IntervalNow(); + + PR_Close(newsock); + + close_done = PR_IntervalNow(); + + timer_data[2*(*id)].d_connect += _delta(&start, &connect_done); + timer_data[2*(*id)].d_cl_data += _delta(&connect_done, &read_done); + timer_data[2*(*id)].d_sv_data += _delta(&read_done, &write_done); + timer_data[2*(*id)].d_close += _delta(&write_done, &close_done); + timer_data[2*(*id)].d_total += _delta(&start, &close_done); + timer_data[2*(*id)].requests++; + + +#ifdef DEBUG + fprintf(stdout, "server: %d %d %d %d %d\n", + _delta(&start, &connect_done), _delta(&connect_done, &read_done), + _delta(&read_done, &write_done), _delta(&write_done, &close_done), + _delta(&start, &close_done)); +#endif + } + +done: + if (data_buffer != NULL) PR_Free (data_buffer); + if (sock) PR_Close(sock); + _thread_exit(*id); + return; +} + +void +_client_thread(void *arg_id) +{ + int *id = (int *)arg_id; + int index; + PRNetAddr sa; + PRFileDesc *sock_h; + char *data_buffer = NULL; + int data_buffer_size; + int bytes; + PRIntervalTime start, + connect_done, + read_done, + write_done, + close_done; + PRStatus rv; + +#ifdef DEBUG + fprintf(stdout, "client thread %d alive\n", *id); +#endif + + data_buffer_size = (_client_data>_server_data?_client_data:_server_data); + + if ( (data_buffer = (char *)PR_Malloc(data_buffer_size * sizeof(char))) == NULL) { + fprintf(stderr, "Error creating buffer in server thread %d\n", *id); + goto done; + } + + memset(&sa, 0 , sizeof(sa)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, PORT_BASE + *id, &sa); + PR_ASSERT(PR_SUCCESS == rv); + + for (index = 0; index< _iterations; index++) { + +#ifdef DEBUG + fprintf(stdout, "client thread %d loop %d\n", *id, index); +#endif + + start = PR_IntervalNow(); + if ( (sock_h = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Error creating socket %d in client thread %d\n", + index, *id); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket created %d\n", *id, sock_h); +#endif + + if ( PR_Connect(sock_h, &sa, + PR_INTERVAL_NO_TIMEOUT) < 0) { + fprintf(stderr, "Error accepting connection %d in client thread %d\n", + index, *id); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket connected %d\n", *id, sock_h); +#endif + + connect_done = PR_IntervalNow(); + if ( PR_Send(sock_h, data_buffer, _client_data, 0, + PR_INTERVAL_NO_TIMEOUT) < _client_data) { + fprintf(stderr, "Error sending client data for iteration %d in client thread %d\n", index, *id ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket wrote %d\n", *id, _client_data); +#endif + + write_done = PR_IntervalNow(); + if ( (bytes = _readn(sock_h, data_buffer, _server_data)) < _server_data) { + fprintf(stderr, "Error reading server data for iteration %d in client thread %d (read %d bytes)\n", index, *id, bytes ); + goto done; + } + +#ifdef DEBUG + fprintf(stdout, "client thread %d socket read %d\n", *id, _server_data); +#endif + + read_done = PR_IntervalNow(); + PR_Close(sock_h); + close_done = PR_IntervalNow(); + + timer_data[2*(*id)+1].d_connect += _delta(&start, &connect_done); + timer_data[2*(*id)+1].d_cl_data += _delta(&connect_done, &write_done); + timer_data[2*(*id)+1].d_sv_data += _delta(&write_done, &read_done); + timer_data[2*(*id)+1].d_close += _delta(&read_done, &close_done); + timer_data[2*(*id)+1].d_total += _delta(&start, &close_done); + timer_data[2*(*id)+1].requests++; + } +done: + if (data_buffer != NULL) PR_Free (data_buffer); + _thread_exit(*id); + + return; +} + +static +void do_work(void) +{ + int index; + + _thread_exit_count = _threads * 2; + for (index=0; index<_threads; index++) { + PRThread *thread; + int *id = (int *)PR_Malloc(sizeof(int)); + + *id = index; + + if ( (thread = PR_CreateThread(PR_USER_THREAD, + _server_thread, + id, + PR_PRIORITY_NORMAL, + scope1, + PR_UNJOINABLE_THREAD, + 0)) == NULL) + fprintf(stderr, "Error creating server thread %d\n", index); + } + + PR_EnterMonitor(exit_cv); + while (_thread_exit_count > 0) + PR_Wait(exit_cv, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(exit_cv); + + fprintf(stdout, "TEST COMPLETE!\n"); + + tally_results(verbose); + +} + +static void do_workUU(void) +{ + scope1 = PR_LOCAL_THREAD; + scope2 = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + scope1 = PR_LOCAL_THREAD; + scope2 = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + scope1 = PR_GLOBAL_THREAD; + scope2 = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + scope1 = PR_GLOBAL_THREAD; + scope2 = PR_GLOBAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + printf("%40s: %6.2f usec\n", msg, d / _iterations); +} + + +int main(int argc, char **argv) +{ +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + int opt; + extern char *optarg; +#endif + +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + while ( (opt = getopt(argc, argv, "c:s:i:t:v")) != EOF) { + switch(opt) { + case 'i': + _iterations = atoi(optarg); + break; + case 't': + _threads_max = _threads = atoi(optarg); + break; + case 'c': + _client_data = atoi(optarg); + break; + case 's': + _server_data = atoi(optarg); + break; + case 'v': + verbose = 1; + break; + default: + break; + } + } +#endif + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("sel_spd.log"); +#endif + + fprintf(stdout, "Running test for %d iterations with %d simultaneous threads.\n", + _iterations, _threads); + fprintf(stdout, "\tWill send %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + + if ( (exit_cv = PR_NewMonitor()) == NULL) + fprintf(stderr, "Error creating monitor for exit cv\n"); + if ( (timer_data = (timer_slot_t *)PR_Malloc(2*_threads * sizeof(timer_slot_t))) == NULL) + fprintf(stderr, "error allocating thread time results array\n"); + memset(timer_data, 0 , 2*_threads*sizeof(timer_slot_t)); + + Measure(do_workUU, "select loop user/user"); + Measure(do_workUK, "select loop user/kernel"); + Measure(do_workKU, "select loop kernel/user"); + Measure(do_workKK, "select loop kernel/kernel"); + + + return 0; +} + +void +tally_results(int verbose) +{ + int index; + unsigned long tot_connect = 0; + unsigned long tot_cl_data = 0; + unsigned long tot_sv_data = 0; + unsigned long tot_close = 0; + unsigned long tot_all = 0; + unsigned long tot_requests = 0; + + fprintf(stdout, "Server results:\n\n"); + for (index=0; index<_threads_max*2; index+=2) { + + if (verbose) + fprintf(stdout, "server thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n", + index, timer_data[index].requests, timer_data[index].d_connect, + timer_data[index].d_cl_data, timer_data[index].d_sv_data, + timer_data[index].d_close, timer_data[index].d_total); + + tot_connect += timer_data[index].d_connect / _threads; + tot_cl_data += timer_data[index].d_cl_data / _threads; + tot_sv_data += timer_data[index].d_sv_data / _threads; + tot_close += timer_data[index].d_close / _threads; + tot_all += timer_data[index].d_total / _threads; + tot_requests += timer_data[index].requests / _threads; + } + fprintf(stdout, "----------\n"); + fprintf(stdout, "server per thread totals %u\t%u\t%u\t%u\t%u\n", + tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close); + fprintf(stdout, "server per thread elapsed time %u\n", tot_all); + fprintf(stdout, "----------\n"); + + tot_connect = tot_cl_data = tot_sv_data = tot_close = tot_all = tot_requests = 0; + fprintf(stdout, "Client results:\n\n"); + for (index=1; index<_threads_max*2; index+=2) { + + if (verbose) + fprintf(stdout, "client thread %u\t%u\t%u\t%u\t%u\t%u\t%u\n", + index, timer_data[index].requests, timer_data[index].d_connect, + timer_data[index].d_cl_data, timer_data[index].d_sv_data, + timer_data[index].d_close, timer_data[index].d_total); + + tot_connect += timer_data[index].d_connect / _threads; + tot_cl_data += timer_data[index].d_cl_data / _threads; + tot_sv_data += timer_data[index].d_sv_data / _threads; + tot_close += timer_data[index].d_close / _threads; + tot_all += timer_data[index].d_total / _threads; + tot_requests += timer_data[index].requests / _threads; + } + fprintf(stdout, "----------\n"); + fprintf(stdout, "client per thread totals %u\t%u\t%u\t%u\t%u\n", + tot_requests, tot_connect, tot_cl_data, tot_sv_data, tot_close); + fprintf(stdout, "client per thread elapsed time %u\n", tot_all); +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/selct_er.c b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_er.c new file mode 100644 index 00000000..e658813f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_er.c @@ -0,0 +1,234 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_err.c +** +** Description: tests PR_Select with sockets Error condition functions. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "primpl.h" +#include "pprio.h" +#include "prnetdb.h" + +#include +#include +#include + + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *badFD; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRInt32 retVal; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Error\n"); + printf("reporting operations are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = AF_INET; + addr.inet.ip = PR_htonl(INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + + /* Testing bad fd */ + if (debug_mode) printf("PR_Select should detect a bad file descriptor\n"); + if ((badFD = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a TCP socket\n"); + failed_already=1; + goto exit_now; + } + + PR_FD_SET(badFD, &readFdSet); + /* + * Make the fd invalid + */ +#if defined(XP_UNIX) + close(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_OS2) + soclose(PR_FileDesc2NativeHandle(badFD)); +#elif defined(WIN32) || defined(WIN16) + closesocket(PR_FileDesc2NativeHandle(badFD)); +#elif defined(XP_MAC) + _PR_MD_CLOSE_SOCKET(PR_FileDesc2NativeHandle(badFD)); +#else +#error "Unknown architecture" +#endif + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + if (retVal != -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR) { + fprintf(stderr, "Failed to detect the bad fd: " + "PR_Select returns %d\n", retVal); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + } + goto exit_now; + } + if (debug_mode) printf("PR_Select detected a bad fd. Test passed.\n\n"); + PR_FD_CLR(badFD, &readFdSet); + + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; + +} + +#endif /* XP_BEOS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/selct_nm.c b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_nm.c new file mode 100644 index 00000000..56a80a76 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_nm.c @@ -0,0 +1,320 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_norm.c +** +** Description: tests PR_Select with sockets - Normal operations. +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prerror.h" +#include "prnetdb.h" + +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void +clientThreadFunc(void *arg) +{ + PRUintn port = (PRUintn) arg; + PRFileDesc *sock; + PRNetAddr addr; + char buf[128]; + int i; + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((PRUint16)port); + addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + PR_snprintf(buf, sizeof(buf), "%hu", addr.inet.port); + + for (i = 0; i < 5; i++) { + sock = PR_NewTCPSocket(); + PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT); + PR_Write(sock, buf, sizeof(buf)); + PR_Close(sock); + } +} + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRFileDesc *fds0[10], *fds1[10], **fds, **other_fds; + PRIntn nfds; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRThread *clientThread; + PRInt32 retVal; + PRIntn i, j; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. \n"); + printf(" Normal operation are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); +failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort1, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + clientThreadFunc, (void *) listenPort2, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (clientThread == NULL) { + fprintf(stderr, "can't create thread\n"); + failed_already=1; + goto exit_now; + } + + if (debug_mode) { + printf("Two client threads are created. Each of them will\n"); + printf("send data to one of the two ports the server is listening on.\n"); + printf("The data they send is the port number. Each of them send\n"); + printf("the data five times, so you should see ten lines below,\n"); + printf("interleaved in an arbitrary order.\n"); + } + /* set up the fd array */ + fds = fds0; + other_fds = fds1; + fds[0] = listenSock1; + fds[1] = listenSock2; + nfds = 2; + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* 20 events total */ + i = 0; + while (i < 20) { + PRFileDesc **tmp; + int nextIndex; + int nEvents = 0; + + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(retVal != 0); /* no timeout */ + if (retVal == -1) { + fprintf(stderr, "PR_Select failed (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + goto exit_now; + } + + nextIndex = 2; + /* the two listening sockets */ + for (j = 0; j < 2; j++) { + other_fds[j] = fds[j]; + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRFileDesc *sock; + + nEvents++; + sock = PR_Accept(fds[j], NULL, PR_INTERVAL_NO_TIMEOUT); + if (sock == NULL) { + fprintf(stderr, "PR_Accept() failed\n"); + failed_already=1; + goto exit_now; + } + other_fds[nextIndex] = sock; + PR_FD_SET(sock, &readFdSet); + nextIndex++; + } + PR_FD_SET(fds[j], &readFdSet); + } + + for (j = 2; j < nfds; j++) { + if (PR_FD_ISSET(fds[j], &readFdSet)) { + PRInt32 nBytes; + + PR_FD_CLR(fds[j], &readFdSet); + nEvents++; + nBytes = PR_Read(fds[j], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read() failed\n"); + failed_already=1; + goto exit_now; + } + /* Just to be safe */ + buf[127] = '\0'; + PR_Close(fds[j]); + if (debug_mode) printf("The server received \"%s\" from a client\n", buf); + } else { + PR_FD_SET(fds[j], &readFdSet); + other_fds[nextIndex] = fds[j]; + nextIndex++; + } + } + + PR_ASSERT(retVal == nEvents); + /* swap */ + tmp = fds; + fds = other_fds; + other_fds = tmp; + nfds = nextIndex; + i += nEvents; + } + + if (debug_mode) printf("Test passed\n"); + + PR_Cleanup(); + goto exit_now; +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/selct_to.c b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_to.c new file mode 100644 index 00000000..b5600fa9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/selct_to.c @@ -0,0 +1,208 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** 1997 - Netscape Communications Corporation +** +** Name: prselect_to.c +** +** Description: tests PR_Select with sockets. Time out functions +** +** Modification History: +** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prio.h" +#include "prlog.h" +#include "prprf.h" +#include "prnetdb.h" + +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include "prerror.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +int main(int argc, char **argv) +{ + PRFileDesc *listenSock1, *listenSock2; + PRUint16 listenPort1, listenPort2; + PRNetAddr addr; + PR_fd_set readFdSet; + char buf[128]; + PRInt32 retVal; + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (debug_mode) { + printf("This program tests PR_Select with sockets. Timeout \n"); + printf("operations are tested.\n\n"); + } + + /* Create two listening sockets */ + if ((listenSock1 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort1 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock1, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + + if ((listenSock2 = PR_NewTCPSocket()) == NULL) { + fprintf(stderr, "Can't create a new TCP socket\n"); + failed_already=1; + goto exit_now; + } + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + addr.inet.port = PR_htons(0); + if (PR_Bind(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "Can't bind socket\n"); + failed_already=1; + goto exit_now; + } + if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + failed_already=1; + goto exit_now; + } + listenPort2 = PR_ntohs(addr.inet.port); + if (PR_Listen(listenSock2, 5) == PR_FAILURE) { + fprintf(stderr, "Can't listen on a socket\n"); + failed_already=1; + goto exit_now; + } + PR_snprintf(buf, sizeof(buf), + "The server thread is listening on ports %hu and %hu\n\n", + listenPort1, listenPort2); + if (debug_mode) printf("%s", buf); + + /* Set up the fd set */ + PR_FD_ZERO(&readFdSet); + PR_FD_SET(listenSock1, &readFdSet); + PR_FD_SET(listenSock2, &readFdSet); + + /* Testing timeout */ + if (debug_mode) printf("PR_Select should time out in 5 seconds\n"); + retVal = PR_Select(0 /* unused */, &readFdSet, NULL, NULL, + PR_SecondsToInterval(5)); + if (retVal != 0) { + PR_snprintf(buf, sizeof(buf), + "PR_Select should time out and return 0, but it returns %ld\n", + retVal); + fprintf(stderr, "%s", buf); + if (retVal == -1) { + fprintf(stderr, "Error %d, oserror %d\n", PR_GetError(), + PR_GetOSError()); + failed_already=1; + } + goto exit_now; + } + if (debug_mode) printf("PR_Select timed out. Test passed.\n\n"); + + PR_Cleanup(); + +exit_now: + if(failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/select2.c b/src/libs/xpcom18a4/nsprpub/pr/tests/select2.c new file mode 100644 index 00000000..0651c450 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/select2.c @@ -0,0 +1,354 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: select2.c +** +** Description: Measure PR_Select and Empty_Select performance. +** +** Modification History: +** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" +#include "prttools.h" +#include "primpl.h" + +#include +#include +#include +#if defined(OS2) +#include +#endif + +#define PORT 8000 +#define DEFAULT_COUNT 10 +PRInt32 count; + + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + switch (result) + { + case PASS: + printf ("PASS\n"); + break; + case FAIL: + printf ("FAIL\n"); + break; + default: + printf ("NOSTATUS\n"); + break; + } +} + +static void EmptyPRSelect(void) +{ + PRInt32 index = count; + PRInt32 rv; + + for (; index--;) + rv = PR_Select(0, NULL, NULL, NULL, PR_INTERVAL_NO_WAIT); +} + +static void EmptyNativeSelect(void) +{ + PRInt32 rv; + PRInt32 index = count; + struct timeval timeout; + + timeout.tv_sec = timeout.tv_usec = 0; + for (; index--;) + rv = select(0, NULL, NULL, NULL, &timeout); +} + +static void PRSelectTest(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + return; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address\n"); + PR_Close(listenSocket); + return; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + PR_Close(listenSocket); + return; + } + if (debug_mode) printf("Listening on port %d\n", PORT); + + { + PRFileDesc *newSock; + PRNetAddr rAddr; + PRInt32 loops = 0; + PR_fd_set rdset; + PRInt32 rv; + PRInt32 bytesRead; + char buf[11]; + + loops++; + + if (debug_mode) printf("Going into accept\n"); + + newSock = PR_Accept(listenSocket, + &rAddr, + PR_INTERVAL_NO_TIMEOUT); + + if (newSock) { + if (debug_mode) printf("Got connection!\n"); + } else { + if (debug_mode) printf("PR_Accept failed: error code %d\n", PR_GetError()); + else Test_Result (FAIL); + } + + PR_FD_ZERO(&rdset); + PR_FD_SET(newSock, &rdset); + + if (debug_mode) printf("Going into select \n"); + + rv = PR_Select(0, &rdset, 0, 0, PR_INTERVAL_NO_TIMEOUT); + + if (debug_mode) printf("return from select is %d\n", rv); + + if (PR_FD_ISSET(newSock, &rdset)) { + if (debug_mode) printf("I can't believe it- the socket is ready okay!\n"); + } else { + if (debug_mode) printf("Damn; the select test failed...\n"); + else Test_Result (FAIL); + } + + strcpy(buf, "XXXXXXXXXX"); + bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT); + buf[10] = '\0'; + + if (debug_mode) printf("Recv completed with %d bytes, %s\n", bytesRead, buf); + + PR_Close(newSock); + } + +} + +#if defined(XP_UNIX) + +static void NativeSelectTest(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + return; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address\n"); + PR_Close(listenSocket); + return; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + PR_Close(listenSocket); + return; + } + if (debug_mode) printf("Listening on port %d\n", PORT); + + { + PRIntn osfd; + char buf[11]; + fd_set rdset; + PRNetAddr rAddr; + PRFileDesc *newSock; + struct timeval timeout; + PRInt32 bytesRead, rv, loops = 0; + + loops++; + + if (debug_mode) printf("Going into accept\n"); + + newSock = PR_Accept(listenSocket, &rAddr, PR_INTERVAL_NO_TIMEOUT); + + if (newSock) { + if (debug_mode) printf("Got connection!\n"); + } else { + if (debug_mode) printf("PR_Accept failed: error code %d\n", PR_GetError()); + else Test_Result (FAIL); + } + + osfd = PR_FileDesc2NativeHandle(newSock); + FD_ZERO(&rdset); + FD_SET(osfd, &rdset); + + if (debug_mode) printf("Going into select \n"); + + + timeout.tv_sec = 2; timeout.tv_usec = 0; + rv = select(osfd + 1, &rdset, NULL, NULL, &timeout); + + if (debug_mode) printf("return from select is %d\n", rv); + + if (FD_ISSET(osfd, &rdset)) { + if (debug_mode) + printf("I can't believe it- the socket is ready okay!\n"); + } else { + if (debug_mode) printf("Damn; the select test failed...\n"); + else Test_Result (FAIL); + } + + strcpy(buf, "XXXXXXXXXX"); + bytesRead = PR_Recv(newSock, buf, 10, 0, PR_INTERVAL_NO_TIMEOUT); + buf[10] = '\0'; + + if (debug_mode) printf("Recv completed with %d bytes, %s\n", bytesRead, buf); + + PR_Close(newSock); + } + +} /* NativeSelectTest */ + +#endif /* defined(XP_UNIX) */ + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + if (debug_mode) printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 2) { + count = atoi(argv[2]); + } else { + count = DEFAULT_COUNT; + } + +#if defined(XP_UNIX) + Measure(NativeSelectTest, "time to call 1 element select()"); +#endif + Measure(EmptyPRSelect, "time to call Empty PR_select()"); + Measure(EmptyNativeSelect, "time to call Empty select()"); + Measure(PRSelectTest, "time to call 1 element PR_select()"); + + if (!debug_mode) Test_Result (NOSTATUS); + PR_Cleanup(); + + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/selintr.c b/src/libs/xpcom18a4/nsprpub/pr/tests/selintr.c new file mode 100644 index 00000000..f47efca4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/selintr.c @@ -0,0 +1,81 @@ +/* -*- 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) 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 ***** */ + +/* + * Test whether classic NSPR's select() wrapper properly blocks + * the periodic SIGALRM clocks. On some platforms (such as + * HP-UX and SINIX) an interrupted select() system call is + * restarted with the originally specified timeout, ignoring + * the time that has elapsed. If a select() call is interrupted + * repeatedly, it will never time out. (See Bugzilla bug #39674.) + */ + +#if !defined(XP_UNIX) + +/* + * This test is applicable to Unix only. + */ + +int main() +{ + return 0; +} + +#else /* XP_UNIX */ + +#include "nspr.h" + +#include +#include + +int main() +{ + struct timeval timeout; + int rv; + + PR_SetError(0, 0); /* force NSPR to initialize */ + PR_EnableClockInterrupts(); + + /* 2 seconds timeout */ + timeout.tv_sec = 2; + timeout.tv_usec = 0; + rv = select(1, NULL, NULL, NULL, &timeout); + printf("select returned %d\n", rv); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sem.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sem.c new file mode 100644 index 00000000..09c9f3cd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sem.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 ***** */ + +/*********************************************************************** +** +** Name: sem.c +** +** Description: Tests Semaphonre functions. +** +** Modification History: +** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include + +PRIntn failed_already=0; +PRIntn debug_mode; + +/* + Since we don't have stdin, stdout everywhere, we will fake + it with our in-memory buffers called stdin and stdout. +*/ + +#define SBSIZE 1024 + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +static char stdinBuf[SBSIZE]; +static char stdoutBuf[SBSIZE]; + +static PRUintn stdinBufIdx = 0; +static PRUintn stdoutBufIdx = 0; +static PRStatus finalResult = PR_SUCCESS; + + +static size_t dread (PRUintn device, char *buf, size_t bufSize) +{ + PRUintn i; + + /* during first read call, initialize the stdinBuf buffer*/ + if (stdinBufIdx == 0) { + for (i=0; i 0); +} + +static void writer(void) +{ + PRUintn i = 0; + size_t nbytes; + + do { + (void) PR_WaitSem(fullBufs); + nbytes = buf[i].nbytes; + if (nbytes > 0) { + nbytes = dwrite(1, buf[i].data, nbytes); + PR_PostSem(emptyBufs); + i = (i + 1) % 2; + } + } while (nbytes > 0); +} + +int main(int argc, char **argv) +{ + PRThread *r; + + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + { + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + /* main test */ + +#ifdef XP_MAC + SetupMacPrintfLog("sem.log"); + debug_mode = 1; +#endif + + emptyBufs = PR_NewSem(2); /* two empty buffers */ + + fullBufs = PR_NewSem(0); /* zero full buffers */ + + /* create the reader thread */ + + r = PR_CreateThread(PR_USER_THREAD, + reader, 0, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + + /* Do the writer operation in this thread */ + writer(); + + PR_DestroySem(emptyBufs); + PR_DestroySem(fullBufs); + + if (finalResult == PR_SUCCESS) { + if (debug_mode) printf("sem Test Passed.\n"); + } + else{ + if (debug_mode) printf("sem Test Failed.\n"); + failed_already=1; + } + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sema.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sema.c new file mode 100644 index 00000000..3dff8a00 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sema.c @@ -0,0 +1,180 @@ +/* -*- 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 ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRIntn counter; +static PRSem *sem1, *sem2; + +/* + * Thread 2 waits on semaphore 2 and posts to semaphore 1. + */ +void ThreadFunc(void *arg) +{ + PRIntn i; + + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (counter == 2*i+1) { + if (debug_mode) printf("thread 2: counter = %d\n", counter); + } else { + fprintf(stderr, "thread 2: counter should be %d but is %d\n", + 2*i+1, counter); + exit(1); + } + counter++; + if (PR_PostSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } +} + +static void Help(void) +{ + fprintf(stderr, "sema test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRThread *thred; + PRIntn i; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME2); + } + + sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed\n"); + exit(1); + } + thred = PR_CreateThread(PR_USER_THREAD, ThreadFunc, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == thred) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + + /* + * Thread 1 waits on semaphore 1 and posts to semaphore 2. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (counter == 2*i) { + if (debug_mode) printf("thread 1: counter = %d\n", counter); + } else { + fprintf(stderr, "thread 1: counter should be %d but is %d\n", + 2*i, counter); + exit(1); + } + counter++; + if (PR_PostSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + + if (PR_JoinThread(thred) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr.c b/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr.c new file mode 100644 index 00000000..8feb8d81 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr.c @@ -0,0 +1,142 @@ +/* -*- 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 ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define NO_SUCH_SEM_NAME "/tmp/nosuchsem.sem" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_MODE 0666 + +static PRBool debug_mode = PR_FALSE; + +static void Help(void) +{ + fprintf(stderr, "semaerr test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRSem *sem; + char *child_argv[32]; + char **child_arg; + PRProcess *proc; + PRInt32 exit_code; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + /* + * Open a nonexistent semaphore without the PR_SEM_CREATE + * flag should fail with PR_FILE_NOT_FOUND_ERROR. + */ + (void) PR_DeleteSemaphore(NO_SUCH_SEM_NAME); + sem = PR_OpenSemaphore(NO_SUCH_SEM_NAME, 0, 0, 0); + if (NULL != sem) { + fprintf(stderr, "Opening nonexistent semaphore %s " + "without the PR_SEM_CREATE flag should fail " + "but succeeded\n", NO_SUCH_SEM_NAME); + exit(1); + } + if (PR_GetError() != PR_FILE_NOT_FOUND_ERROR) { + fprintf(stderr, "Expected error is %d but got (%d, %d)\n", + PR_FILE_NOT_FOUND_ERROR, PR_GetError(), PR_GetOSError()); + exit(1); + } + + /* + * Create a semaphore and let the another process + * try PR_SEM_CREATE and PR_SEM_CREATE|PR_SEM_EXCL. + */ + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: deleted semaphore %s from previous " + "run of the test\n", SEM_NAME1); + } + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + child_arg = child_argv; + *child_arg++ = "semaerr1"; + if (debug_mode) { + *child_arg++ = "-d"; + } + *child_arg = NULL; + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + if (proc == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exit_code != 0) { + fprintf(stderr, "process semaerr1 failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr1.c b/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr1.c new file mode 100644 index 00000000..eeccdc43 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/semaerr1.c @@ -0,0 +1,137 @@ +/* -*- 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 ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 + +static PRBool debug_mode = PR_FALSE; + +static void Help(void) +{ + fprintf(stderr, "semaerr1 test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh"); + PRSem *sem; + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + /* + * PR_SEM_CREATE|PR_SEM_EXCL should be able to + * create a nonexistent semaphore. + */ + (void) PR_DeleteSemaphore(SEM_NAME2); + sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + exit(1); + } + + /* + * Opening an existing semaphore with PR_SEM_CREATE|PR_SEM_EXCL. + * should fail with PR_FILE_EXISTS_ERROR. + */ + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem != NULL) { + fprintf(stderr, "PR_OpenSemaphore should fail but succeeded\n"); + exit(1); + } + if (PR_GetError() != PR_FILE_EXISTS_ERROR) { + fprintf(stderr, "Expect %d but got %d\n", PR_FILE_EXISTS_ERROR, + PR_GetError()); + exit(1); + } + + /* + * Try again, with just PR_SEM_CREATE. This should succeed. + */ + sem = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + + sem = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE|PR_SEM_EXCL, SEM_MODE, 0); + if (sem == NULL) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + if (PR_CloseSemaphore(sem) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + exit(1); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/semaping.c b/src/libs/xpcom18a4/nsprpub/pr/tests/semaping.c new file mode 100644 index 00000000..7b145fc5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/semaping.c @@ -0,0 +1,203 @@ +/* -*- 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 ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SHM_NAME "/tmp/counter" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define SEM_MODE 0666 +#define SHM_MODE 0666 +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRSem *sem1, *sem2; + +static void Help(void) +{ + fprintf(stderr, "semaping test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRProcess *proc; + PRIntn i; + char *child_argv[32]; + char **child_arg; + char iterations_buf[32]; + PRSharedMemory *shm; + PRIntn *counter_addr; + PRInt32 exit_code; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (PR_DeleteSharedMemory(SHM_NAME) == PR_SUCCESS) { + fprintf(stderr, "warning: removed shared memory %s left over " + "from previous run\n", SHM_NAME); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME1); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_SUCCESS) { + fprintf(stderr, "warning: removed semaphore %s left over " + "from previous run\n", SEM_NAME2); + } + + shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), PR_SHM_CREATE, SHM_MODE); + if (NULL == shm) { + fprintf(stderr, "PR_OpenSharedMemory failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + counter_addr = PR_AttachSharedMemory(shm, 0); + if (NULL == counter_addr) { + fprintf(stderr, "PR_AttachSharedMemory failed\n"); + exit(1); + } + *counter_addr = 0; + sem1 = PR_OpenSemaphore(SEM_NAME1, PR_SEM_CREATE, SEM_MODE, 1); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, PR_SEM_CREATE, SEM_MODE, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + child_arg = &child_argv[0]; + *child_arg++ = "semapong"; + if (debug_mode != PR_FALSE) { + *child_arg++ = "-d"; + } + if (iterations != ITERATIONS) { + *child_arg++ = "-c"; + PR_snprintf(iterations_buf, sizeof(iterations_buf), "%d", iterations); + *child_arg++ = iterations_buf; + } + *child_arg = NULL; + proc = PR_CreateProcess(child_argv[0], child_argv, NULL, NULL); + if (NULL == proc) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + + /* + * Process 1 waits on semaphore 1 and posts to semaphore 2. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (*counter_addr == 2*i) { + if (debug_mode) printf("process 1: counter = %d\n", *counter_addr); + } else { + fprintf(stderr, "process 1: counter should be %d but is %d\n", + 2*i, *counter_addr); + exit(1); + } + (*counter_addr)++; + if (PR_PostSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) { + fprintf(stderr, "PR_DetachSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSharedMemory(shm) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + + if (PR_WaitProcess(proc, &exit_code) == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exit_code != 0) { + fprintf(stderr, "process 2 failed with exit code %d\n", exit_code); + exit(1); + } + + if (PR_DeleteSharedMemory(SHM_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSharedMemory failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME1) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + if (PR_DeleteSemaphore(SEM_NAME2) == PR_FAILURE) { + fprintf(stderr, "PR_DeleteSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/semapong.c b/src/libs/xpcom18a4/nsprpub/pr/tests/semapong.c new file mode 100644 index 00000000..d3733290 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/semapong.c @@ -0,0 +1,147 @@ +/* -*- 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 ***** */ + +#include "nspr.h" +#include "plgetopt.h" + +#include + +#define SHM_NAME "/tmp/counter" +#define SEM_NAME1 "/tmp/foo.sem" +#define SEM_NAME2 "/tmp/bar.sem" +#define ITERATIONS 1000 + +static PRBool debug_mode = PR_FALSE; +static PRIntn iterations = ITERATIONS; +static PRSem *sem1, *sem2; + +static void Help(void) +{ + fprintf(stderr, "semapong test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-c loop count (%d)\n", ITERATIONS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRIntn i; + PRSharedMemory *shm; + PRIntn *counter_addr; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dc:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop count */ + iterations = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + shm = PR_OpenSharedMemory(SHM_NAME, sizeof(*counter_addr), 0, 0666); + if (NULL == shm) { + fprintf(stderr, "PR_OpenSharedMemory failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem1 = PR_OpenSemaphore(SEM_NAME1, 0, 0, 0); + if (NULL == sem1) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + sem2 = PR_OpenSemaphore(SEM_NAME2, 0, 0, 0); + if (NULL == sem2) { + fprintf(stderr, "PR_OpenSemaphore failed (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + counter_addr = PR_AttachSharedMemory(shm, 0); + if (NULL == counter_addr) { + fprintf(stderr, "PR_AttachSharedMemory failed\n"); + exit(1); + } + + /* + * Process 2 waits on semaphore 2 and posts to semaphore 1. + */ + for (i = 0; i < iterations; i++) { + if (PR_WaitSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_WaitSemaphore failed\n"); + exit(1); + } + if (*counter_addr == 2*i+1) { + if (debug_mode) printf("process 2: counter = %d\n", *counter_addr); + } else { + fprintf(stderr, "process 2: counter should be %d but is %d\n", + 2*i+1, *counter_addr); + exit(1); + } + (*counter_addr)++; + if (PR_PostSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_PostSemaphore failed\n"); + exit(1); + } + } + if (PR_DetachSharedMemory(shm, counter_addr) == PR_FAILURE) { + fprintf(stderr, "PR_DetachSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSharedMemory(shm) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSharedMemory failed\n"); + exit(1); + } + if (PR_CloseSemaphore(sem1) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + if (PR_CloseSemaphore(sem2) == PR_FAILURE) { + fprintf(stderr, "PR_CloseSemaphore failed\n"); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sendzlf.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sendzlf.c new file mode 100644 index 00000000..5416475b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sendzlf.c @@ -0,0 +1,246 @@ +/* -*- 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 ***** */ + +/* + * Test: sendzlf.c + * + * Description: send a zero-length file with PR_SendFile and + * PR_TransmitFile. + */ + +#define ZERO_LEN_FILE_NAME "zerolen.tmp" +#define HEADER_STR "Header" +#define HEADER_LEN 6 /* length of HEADER_STR, not counting the null byte */ +#define TRAILER_STR "Trailer" +#define TRAILER_LEN 7 /* length of TRAILER_STR, not counting the null byte */ + +#include "nspr.h" + +#include +#include +#include + +static void ClientThread(void *arg) +{ + PRFileDesc *sock; + PRNetAddr addr; + PRUint16 port = (PRUint16) arg; + char buf[1024]; + char *bufPtr; + PRInt32 nbytes; + PRInt32 ntotal; + PRInt32 nexpected; + + sock = PR_NewTCPSocket(); + if (NULL == sock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + ntotal = 0; + bufPtr = buf; + while ((nbytes = PR_Read(sock, bufPtr, sizeof(buf)-ntotal)) > 0) { + ntotal += nbytes; + bufPtr += nbytes; + } + if (-1 == nbytes) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + nexpected = HEADER_LEN+TRAILER_LEN+TRAILER_LEN+HEADER_LEN+HEADER_LEN; + if (ntotal != nexpected) { + fprintf(stderr, "total bytes read should be %d but is %d\n", + nexpected, ntotal); + exit(1); + } + if (memcmp(buf, HEADER_STR TRAILER_STR TRAILER_STR HEADER_STR HEADER_STR, + nexpected) != 0) { + fprintf(stderr, "wrong data is received\n"); + exit(1); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +static void ServerThread(void *arg) +{ + PRFileDesc *listenSock = (PRFileDesc *) arg; + PRFileDesc *acceptSock; + PRFileDesc *file; + PRSendFileData sfd; + char header[1024], trailer[1024]; + PRInt32 nbytes; + + /* Create a zero-length file */ + file = PR_Open(ZERO_LEN_FILE_NAME, + PR_CREATE_FILE|PR_TRUNCATE|PR_RDWR, 0666); + if (NULL == file) { + fprintf(stderr, "PR_Open failed\n"); + exit(1); + } + sfd.fd = file; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + memcpy(header, HEADER_STR, HEADER_LEN); + memcpy(trailer, TRAILER_STR, TRAILER_LEN); + sfd.header = header; + sfd.hlen = HEADER_LEN; + sfd.trailer = trailer; + sfd.tlen = TRAILER_LEN; + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + /* Send both header and trailer */ + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN+TRAILER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + HEADER_LEN+TRAILER_LEN, nbytes); + exit(1); + } + /* Trailer only, no header */ + sfd.hlen = 0; + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (TRAILER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + TRAILER_LEN, nbytes); + exit(1); + } + /* Header only, no trailer */ + sfd.hlen = HEADER_LEN; + sfd.tlen = 0; + nbytes = PR_SendFile(acceptSock, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN != nbytes) { + fprintf(stderr, "PR_SendFile should return %d but returned %d\n", + HEADER_LEN, nbytes); + exit(1); + } + /* Try PR_TransmitFile */ + nbytes = PR_TransmitFile(acceptSock, file, header, HEADER_LEN, + PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); + if (HEADER_LEN != nbytes) { + fprintf(stderr, "PR_TransmitFile should return %d but returned %d\n", + HEADER_LEN, nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Close(file) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_Delete(ZERO_LEN_FILE_NAME) == PR_FAILURE) { + fprintf(stderr, "PR_Delete failed\n"); + exit(1); + } +} + +int main() +{ + PRFileDesc *listenSock; + PRThread *clientThread; + PRThread *serverThread; + PRNetAddr addr; + PRThreadScope scope = PR_GLOBAL_THREAD; + + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + /* Find out what port number we are bound to. */ + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + serverThread = PR_CreateThread(PR_USER_THREAD, + ServerThread, listenSock, + PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); + if (NULL == serverThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_JoinThread(serverThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c b/src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c new file mode 100644 index 00000000..ffe37a5e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/server_test.c @@ -0,0 +1,634 @@ +/* -*- 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 server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +#define PASS 0 +#define FAIL 1 +static int debug_mode = 0; + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#undef DEBUGPRINTS +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + + +/*********************************************************************** +** PRIVATE FUNCTION: Test_Result +** DESCRIPTION: Used in conjunction with the regress tool, prints out the +** status of the test case. +** INPUTS: PASS/FAIL +** OUTPUTS: None +** RETURN: None +** SIDE EFFECTS: +** +** RESTRICTIONS: +** None +** MEMORY: NA +** ALGORITHM: Determine what the status is and print accordingly. +** +***********************************************************************/ + + +static void Test_Result (int result) +{ + switch (result) + { + case PASS: + printf ("PASS\n"); + break; + case FAIL: + printf ("FAIL\n"); + break; + default: + break; + } +} + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + else + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else Test_Result(FAIL); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else Test_Result(FAIL); + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else Test_Result(FAIL); + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 10; + _clients = 1; + _client_data = 10; + _server_data = 10; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUU, "server loop user/user"); + #if 0 + Measure(do_workUK, "server loop user/kernel"); + Measure(do_workKU, "server loop kernel/user"); + Measure(do_workKK, "server loop kernel/kernel"); + #endif + + PR_Cleanup(); + + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/servr_kk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_kk.c new file mode 100644 index 00000000..a8fdf1df --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_kk.c @@ -0,0 +1,613 @@ +/* -*- 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 server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + else + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + +static void do_workKK(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +int main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + + Measure(do_workKK, "server loop kernel/kernel"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/servr_ku.c b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_ku.c new file mode 100644 index 00000000..fa0a168e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_ku.c @@ -0,0 +1,593 @@ +/* -*- 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 server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + else + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + + +static void do_workKU(void) +{ + ServerScope = PR_GLOBAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workKU, "server loop kernel/user"); + + PR_Cleanup(); + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uk.c b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uk.c new file mode 100644 index 00000000..139081af --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uk.c @@ -0,0 +1,595 @@ +/* -*- 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 server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + + + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + else + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + + +static void do_workUK(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_GLOBAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUK, "server loop user/kernel"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uu.c b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uu.c new file mode 100644 index 00000000..3bd1d574 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/servr_uu.c @@ -0,0 +1,593 @@ +/* -*- 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 server simulates a server running in loopback mode. +** +** The idea is that a single server is created. The server initially creates +** a number of worker threads. Then, with the server running, a number of +** clients are created which start requesting service from the server. +** +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprthred.h" + +#include + +#define PORT 15004 +#define THREAD_STACKSIZE 0 + +static int _iterations = 1000; +static int _clients = 1; +static int _client_data = 250; +static int _server_data = (8*1024); + +static PRThreadScope ServerScope, ClientScope; + +#define SERVER "Server" +#define MAIN "Main" + +#define SERVER_STATE_STARTUP 0 +#define SERVER_STATE_READY 1 +#define SERVER_STATE_DYING 2 +#define SERVER_STATE_DEAD 4 +int ServerState; +PRLock *ServerStateCVLock; +PRCondVar *ServerStateCV; + +#ifdef DEBUGPRINTS +#define DPRINTF printf +#else +#define DPRINTF +#endif + +PRIntn failed_already=0; +PRIntn debug_mode; + +static void do_work(void); + +/* --- Server state functions --------------------------------------------- */ +void +SetServerState(char *waiter, PRInt32 state) +{ + PR_Lock(ServerStateCVLock); + ServerState = state; + PR_NotifyCondVar(ServerStateCV); + + if (debug_mode) DPRINTF("\t%s changed state to %d\n", waiter, state); + + PR_Unlock(ServerStateCVLock); +} + +int +WaitServerState(char *waiter, PRInt32 state) +{ + PRInt32 rv; + + PR_Lock(ServerStateCVLock); + + if (debug_mode) DPRINTF("\t%s waiting for state %d\n", waiter, state); + + while(!(ServerState & state)) + PR_WaitCondVar(ServerStateCV, PR_INTERVAL_NO_TIMEOUT); + rv = ServerState; + + if (debug_mode) DPRINTF("\t%s resuming from wait for state %d; state now %d\n", + waiter, state, ServerState); + PR_Unlock(ServerStateCVLock); + + return rv; +} + +/* --- Server Functions ------------------------------------------- */ + +PRLock *workerThreadsLock; +PRInt32 workerThreads; +PRInt32 workerThreadsBusy; + +void +WorkerThreadFunc(void *_listenSock) +{ + PRFileDesc *listenSock = (PRFileDesc *)_listenSock; + PRInt32 bytesRead; + PRInt32 bytesWritten; + char *dataBuf; + char *sendBuf; + + if (debug_mode) DPRINTF("\tServer buffer is %d bytes; %d data, %d netaddrs\n", + _client_data+(2*sizeof(PRNetAddr))+32, _client_data, (2*sizeof(PRNetAddr))+32); + dataBuf = (char *)PR_MALLOC(_client_data + 2*sizeof(PRNetAddr) + 32); + if (!dataBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + sendBuf = (char *)PR_MALLOC(_server_data *sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tServer could not malloc space!?\n"); + + if (debug_mode) DPRINTF("\tServer worker thread running\n"); + + while(1) { + PRInt32 bytesToRead = _client_data; + PRInt32 bytesToWrite = _server_data; + PRFileDesc *newSock; + PRNetAddr *rAddr; + PRInt32 loops = 0; + + loops++; + + if (debug_mode) DPRINTF("\tServer thread going into accept\n"); + + bytesRead = PR_AcceptRead(listenSock, + &newSock, + &rAddr, + dataBuf, + bytesToRead, + PR_INTERVAL_NO_TIMEOUT); + + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error in accept (%d)\n", bytesRead); + continue; + } + + if (debug_mode) DPRINTF("\tServer accepted connection (%d bytes)\n", bytesRead); + + PR_AtomicIncrement(&workerThreadsBusy); + if (workerThreadsBusy == workerThreads) { + + PR_Lock(workerThreadsLock); + if (workerThreadsBusy == workerThreads) { + PRThread *WorkerThread; + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSock, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) + if (debug_mode) printf("Error creating client thread %d\n", workerThreads); + else { + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer creates worker (%d)\n", workerThreads); + } + } + PR_Unlock(workerThreadsLock); + } + + bytesToRead -= bytesRead; + while (bytesToRead) { + bytesRead = PR_Recv(newSock, + dataBuf, + bytesToRead, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesRead < 0) { + if (debug_mode) printf("\tServer error receiving data (%d)\n", bytesRead); + continue; + } + if (debug_mode) DPRINTF("\tServer received %d bytes\n", bytesRead); + } + + bytesWritten = PR_Send(newSock, + sendBuf, + bytesToWrite, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (bytesWritten != _server_data) + if (debug_mode) printf("\tError sending data to client (%d, %d)\n", + bytesWritten, PR_GetOSError()); + else + if (debug_mode) DPRINTF("\tServer sent %d bytes\n", bytesWritten); + + PR_Close(newSock); + PR_AtomicDecrement(&workerThreadsBusy); + } +} + +PRFileDesc * +ServerSetup(void) +{ + PRFileDesc *listenSocket; + PRSocketOptionData sockOpt; + PRNetAddr serverAddr; + PRThread *WorkerThread; + + if ( (listenSocket = PR_NewTCPSocket()) == NULL) { + if (debug_mode) printf("\tServer error creating listen socket\n"); + else failed_already=1; + return NULL; + } + + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + if ( PR_SetSocketOption(listenSocket, &sockOpt) == PR_FAILURE) { + if (debug_mode) printf("\tServer error setting socket option: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_ANY); + + if ( PR_Bind(listenSocket, &serverAddr) == PR_FAILURE) { + if (debug_mode) printf("\tServer error binding to server address: OS error %d\n", + PR_GetOSError()); + else failed_already=1; + PR_Close(listenSocket); + return NULL; + } + + if ( PR_Listen(listenSocket, 128) == PR_FAILURE) { + if (debug_mode) printf("\tServer error listening to server socket\n"); + else failed_already=1; + PR_Close(listenSocket); + + return NULL; + } + + /* Create Clients */ + workerThreads = 0; + workerThreadsBusy = 0; + + workerThreadsLock = PR_NewLock(); + + WorkerThread = PR_CreateThread( + PR_SYSTEM_THREAD, + WorkerThreadFunc, + listenSocket, + PR_PRIORITY_NORMAL, + ServerScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!WorkerThread) { + if (debug_mode) printf("error creating working thread\n"); + PR_Close(listenSocket); + return NULL; + } + PR_AtomicIncrement(&workerThreads); + if (debug_mode) DPRINTF("\tServer created primordial worker thread\n"); + + return listenSocket; +} + +/* The main server loop */ +void +ServerThreadFunc(void *unused) +{ + PRFileDesc *listenSocket; + + /* Do setup */ + listenSocket = ServerSetup(); + + if (!listenSocket) { + SetServerState(SERVER, SERVER_STATE_DEAD); + } else { + + if (debug_mode) DPRINTF("\tServer up\n"); + + /* Tell clients they can start now. */ + SetServerState(SERVER, SERVER_STATE_READY); + + /* Now wait for server death signal */ + WaitServerState(SERVER, SERVER_STATE_DYING); + + /* Cleanup */ + SetServerState(SERVER, SERVER_STATE_DEAD); + } +} + +/* --- Client Functions ------------------------------------------- */ + +PRInt32 numRequests; +PRInt32 numClients; +PRMonitor *clientMonitor; + +void +ClientThreadFunc(void *unused) +{ + PRNetAddr serverAddr; + PRFileDesc *clientSocket; + char *sendBuf; + char *recvBuf; + PRInt32 rv; + PRInt32 bytesNeeded; + + sendBuf = (char *)PR_MALLOC(_client_data * sizeof(char)); + if (!sendBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + recvBuf = (char *)PR_MALLOC(_server_data * sizeof(char)); + if (!recvBuf) + if (debug_mode) printf("\tClient could not malloc space!?\n"); + + memset(&serverAddr, 0, sizeof(PRNetAddr)); + serverAddr.inet.family = PR_AF_INET; + serverAddr.inet.port = PR_htons(PORT); + serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + + while(numRequests > 0) { + + if ( (numRequests % 10) == 0 ) + if (debug_mode) printf("."); + if (debug_mode) DPRINTF("\tClient starting request %d\n", numRequests); + + clientSocket = PR_NewTCPSocket(); + if (!clientSocket) { + if (debug_mode) printf("Client error creating socket: OS error %d\n", + PR_GetOSError()); + continue; + } + + if (debug_mode) DPRINTF("\tClient connecting\n"); + + rv = PR_Connect(clientSocket, + &serverAddr, + PR_INTERVAL_NO_TIMEOUT); + if (!clientSocket) { + if (debug_mode) printf("\tClient error connecting\n"); + continue; + } + + if (debug_mode) DPRINTF("\tClient connected\n"); + + rv = PR_Send(clientSocket, + sendBuf, + _client_data, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv != _client_data) { + if (debug_mode) printf("Client error sending data (%d)\n", rv); + PR_Close(clientSocket); + continue; + } + + if (debug_mode) DPRINTF("\tClient sent %d bytes\n", rv); + + bytesNeeded = _server_data; + while(bytesNeeded) { + rv = PR_Recv(clientSocket, + recvBuf, + bytesNeeded, + 0, + PR_INTERVAL_NO_TIMEOUT); + if (rv <= 0) { + if (debug_mode) printf("Client error receiving data (%d) (%d/%d)\n", + rv, (_server_data - bytesNeeded), _server_data); + break; + } + if (debug_mode) DPRINTF("\tClient received %d bytes; need %d more\n", rv, bytesNeeded - rv); + bytesNeeded -= rv; + } + + PR_Close(clientSocket); + + PR_AtomicDecrement(&numRequests); + } + + PR_EnterMonitor(clientMonitor); + --numClients; + PR_Notify(clientMonitor); + PR_ExitMonitor(clientMonitor); + + PR_DELETE(sendBuf); + PR_DELETE(recvBuf); +} + +void +RunClients(void) +{ + PRInt32 index; + + numRequests = _iterations; + numClients = _clients; + clientMonitor = PR_NewMonitor(); + + for (index=0; index<_clients; index++) { + PRThread *clientThread; + + + clientThread = PR_CreateThread( + PR_USER_THREAD, + ClientThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ClientScope, + PR_UNJOINABLE_THREAD, + THREAD_STACKSIZE); + + if (!clientThread) { + if (debug_mode) printf("\terror creating client thread %d\n", index); + } else + if (debug_mode) DPRINTF("\tMain created client %d/%d\n", index+1, _clients); + + } + + PR_EnterMonitor(clientMonitor); + while(numClients) + PR_Wait(clientMonitor, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(clientMonitor); +} + +/* --- Main Function ---------------------------------------------- */ + +static +void do_work() +{ + PRThread *ServerThread; + PRInt32 state; + + SetServerState(MAIN, SERVER_STATE_STARTUP); + ServerThread = PR_CreateThread( + PR_USER_THREAD, + ServerThreadFunc, + NULL, + PR_PRIORITY_NORMAL, + ServerScope, + PR_JOINABLE_THREAD, + THREAD_STACKSIZE); + if (!ServerThread) { + if (debug_mode) printf("error creating main server thread\n"); + return; + } + + /* Wait for server to be ready */ + state = WaitServerState(MAIN, SERVER_STATE_READY|SERVER_STATE_DEAD); + + if (!(state & SERVER_STATE_DEAD)) { + /* Run Test Clients */ + RunClients(); + + /* Send death signal to server */ + SetServerState(MAIN, SERVER_STATE_DYING); + } + + PR_JoinThread(ServerThread); +} + +static void do_workUU(void) +{ + ServerScope = PR_LOCAL_THREAD; + ClientScope = PR_LOCAL_THREAD; + do_work(); +} + + + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + + if (debug_mode) printf("\n%40s: %6.2f usec\n", msg, d / _iterations); +} + + +main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + if (debug_mode) { + printf("Enter number of iterations: \n"); + scanf("%d", &_iterations); + printf("Enter number of clients : \n"); + scanf("%d", &_clients); + printf("Enter size of client data : \n"); + scanf("%d", &_client_data); + printf("Enter size of server data : \n"); + scanf("%d", &_server_data); + } + else { + _iterations = 7; + _clients = 7; + _client_data = 100; + _server_data = 100; + } + + if (debug_mode) { + printf("\n\n%d iterations with %d client threads.\n", + _iterations, _clients); + printf("Sending %d bytes of client data and %d bytes of server data\n", + _client_data, _server_data); + } + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + PR_SetThreadRecycleMode(64); + + ServerStateCVLock = PR_NewLock(); + ServerStateCV = PR_NewCondVar(ServerStateCVLock); + + Measure(do_workUU, "server loop user/user"); + + PR_Cleanup(); + + if(failed_already) + return 1; + else + return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/short_thread.c b/src/libs/xpcom18a4/nsprpub/pr/tests/short_thread.c new file mode 100644 index 00000000..42a52d7c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/short_thread.c @@ -0,0 +1,90 @@ +/* -*- 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 +#include "nspr.h" +#include "plgetopt.h" + +/* + * Create a thread that exits right away; useful for testing race conditions in thread + * creation + */ + +int _debug_on = 0; +#define DPRINTF(arg) if (_debug_on) printf arg + +static void housecleaning(void *cur_time); + +int main (int argc, char **argv) +{ + static PRIntervalTime thread_start_time; + static PRThread *housekeeping_tid = NULL; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (( housekeeping_tid = + PR_CreateThread (PR_USER_THREAD, housecleaning, (void*)&thread_start_time, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0)) + == NULL ) { + fprintf(stderr, + "simple_test: Error - PR_CreateThread failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + exit( 1 ); + } + PR_Cleanup(); + return(0); +} + +static void +housecleaning (void *cur_time) +{ + DPRINTF(("Child Thread exiting\n")); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sigpipe.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sigpipe.c new file mode 100644 index 00000000..ecb9689c --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sigpipe.c @@ -0,0 +1,131 @@ +/* -*- 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 ***** */ + +/* + ************************************************************************* + * + * Test: sigpipe.c + * + * Test the SIGPIPE handler in NSPR. This test applies to Unix only. + * + ************************************************************************* + */ + +#if !defined(XP_UNIX) && !defined(XP_OS2) + +int main(void) +{ + /* This test applies to Unix and OS/2 (emx build). */ + return 0; +} + +#else /* XP_UNIX && OS/2 */ + +#include "nspr.h" + +#ifdef XP_OS2 +#define INCL_DOSQUEUES +#define INCL_DOSERRORS +#include +#endif + +#include +#ifdef XP_OS2_VACPP +#define EPIPE EBADF /* IBM's write() doesn't return EPIPE */ +#include +#else +#include +#endif +#include + +static void Test(void *arg) +{ +#ifdef XP_OS2 + HFILE pipefd[2]; +#else + int pipefd[2]; +#endif + int rv; + char c = '\0'; + +#ifdef XP_OS2 + if (DosCreatePipe(&pipefd[0], &pipefd[1], 4096) != 0) { +#else + if (pipe(pipefd) == -1) { +#endif + fprintf(stderr, "cannot create pipe: %d\n", errno); + exit(1); + } + close(pipefd[0]); + + rv = write(pipefd[1], &c, 1); + if (rv != -1) { + fprintf(stderr, "write to broken pipe should have failed with EPIPE but returned %d\n", rv); + exit(1); + } + if (errno != EPIPE) { + fprintf(stderr, "write to broken pipe failed but with wrong errno: %d\n", errno); + exit(1); + } + close(pipefd[1]); + printf("write to broken pipe failed with EPIPE, as expected\n"); +} + +int main(void) +{ + PRThread *thread; + + /* This initializes NSPR. */ + PR_SetError(0, 0); + + thread = PR_CreateThread(PR_USER_THREAD, Test, NULL, PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (thread == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + if (PR_JoinThread(thread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + Test(NULL); + + printf("PASSED\n"); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sleep.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sleep.c new file mode 100644 index 00000000..51847367 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sleep.c @@ -0,0 +1,134 @@ +/* -*- 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 "nspr.h" + +#if defined(XP_UNIX) || defined(XP_OS2) + +#include + +#ifndef XP_OS2 +#include +#endif +#include + +#if defined(HAVE_SVID_GETTOD) +#define GTOD(_a) gettimeofday(_a) +#else +#define GTOD(_a) gettimeofday((_a), NULL) +#endif + +#if defined (XP_OS2_VACPP) +#define INCL_DOSPROCESS +#include +#endif + +static PRIntn rv = 0; + +static void Other(void *unused) +{ + PRIntn didit = 0; + while (PR_SUCCESS == PR_Sleep(PR_MillisecondsToInterval(250))) + { + fprintf(stderr, "."); + didit += 1; + } + if (didit < 5) rv = 1; +} + +PRIntn main () +{ + PRUint32 elapsed; + PRThread *thread; + struct timeval timein, timeout; + PRInt32 onePercent = 3000000UL / 100UL; + + fprintf (stderr, "First sleep will sleep 3 seconds.\n"); + fprintf (stderr, " sleep 1 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 1 end\n"); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + + PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 100); + PR_STDIO_INIT(); + + fprintf (stderr, "Second sleep should do the same (does it?).\n"); + fprintf (stderr, " sleep 2 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 2 end\n"); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + + fprintf (stderr, "What happens to other threads?\n"); + fprintf (stderr, "You should see dots every quarter second.\n"); + fprintf (stderr, "If you don't, you're probably running on classic NSPR.\n"); + thread = PR_CreateThread( + PR_USER_THREAD, Other, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + fprintf (stderr, " sleep 2 begin\n"); + (void)GTOD(&timein); + sleep (3); + (void)GTOD(&timeout); + fprintf (stderr, " sleep 2 end\n"); + PR_Interrupt(thread); + PR_JoinThread(thread); + elapsed = 1000000UL * (timeout.tv_sec - timein.tv_sec); + elapsed += (timeout.tv_usec - timein.tv_usec); + fprintf(stderr, "elapsed %u usecs\n", elapsed); + if (labs(elapsed - 3000000UL) > onePercent) rv = 1; + fprintf(stderr, "%s\n", (0 == rv) ? "PASSED" : "FAILED"); + return rv; +} + +#else /* defined(XP_UNIX) */ + +PRIntn main() +{ + return 2; +} + +#endif /* defined(XP_UNIX) */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/socket.c b/src/libs/xpcom18a4/nsprpub/pr/tests/socket.c new file mode 100644 index 00000000..8e4a899b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/socket.c @@ -0,0 +1,2354 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: socket.c +** +** Description: Test socket functionality. +** +** Modification History: +*/ +#include "primpl.h" + +#include "plgetopt.h" + +#include +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static int test_cancelio = 0; + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +#ifdef XP_PC +char *TEST_DIR = "prdir"; +char *SMALL_FILE_NAME = "prsmallf"; +char *LARGE_FILE_NAME = "prlargef"; +#else +char *TEST_DIR = "/tmp/prsocket_test_dir"; +char *SMALL_FILE_NAME = "/tmp/prsocket_test_dir/small_file"; +char *LARGE_FILE_NAME = "/tmp/prsocket_test_dir/large_file"; +#endif +#define SMALL_FILE_SIZE (3 * 1024) /* 3 KB */ +#define SMALL_FILE_OFFSET_1 (512) +#define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB */ +#define SMALL_FILE_OFFSET_2 (75) +#define SMALL_FILE_LEN_2 (758) +#define SMALL_FILE_OFFSET_3 (1024) +#define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3) +#define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */ +#define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes */ + +#define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */ +#define LARGE_FILE_OFFSET_1 (0) +#define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB */ +#define LARGE_FILE_OFFSET_2 (64) +#define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75) +#define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128) +#define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3) +#define LARGE_FILE_OFFSET_4 PR_GetPageSize() +#define LARGE_FILE_LEN_4 769 +#define LARGE_FILE_HEADER_SIZE (512) +#define LARGE_FILE_TRAILER_SIZE (64) + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +/* + * set UDP datagram size small enough that datagrams sent to a port on the + * local host will not be lost + */ +#define UDP_DGRAM_SIZE 128 +#define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */ +#define NUM_UDP_CLIENTS 10 + +#ifndef XP_MAC +#define NUM_TRANSMITFILE_CLIENTS 4 +#else +/* Mac can't handle more than 2* (3Mb) allocations for large file size buffers */ +#define NUM_TRANSMITFILE_CLIENTS 2 +#endif + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 5 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define NUM_UDP_DATAGRAMS_PER_CLIENT 5 +#define TCP_SERVER_PORT 10000 +#define UDP_SERVER_PORT TCP_SERVER_PORT +#define SERVER_MAX_BIND_COUNT 100 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_udp_clients = NUM_UDP_CLIENTS; +static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; +static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT; +static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE; + +static PRInt32 thread_count; +PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET; + +/* an I/O layer that uses the emulated senfile method */ +static PRDescIdentity emuSendFileIdentity; +static PRIOMethods emuSendFileMethods; + +int failed_already=0; +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +PRNetAddr tcp_server_addr, udp_server_addr; + +typedef struct Serve_Client_Param { + PRFileDesc *sockfd; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ +} Serve_Client_Param; + +typedef struct Server_Param { + PRSemaphore *addr_sem; /* sem to post on, after setting up the address */ + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ +} Server_Param; + + +typedef struct Client_Param { + PRNetAddr server_addr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; + PRInt32 udp_connect; /* if set clients connect udp sockets */ +} Client_Param; + +/* the sendfile method in emuSendFileMethods */ +static PRInt32 PR_CALLBACK +emu_SendFile(PRFileDesc *sd, PRSendFileData *sfd, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + return PR_EmulateSendFile(sd, sfd, flags, timeout); +} + +/* the transmitfile method in emuSendFileMethods */ +static PRInt32 PR_CALLBACK +emu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers, + PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + return emu_SendFile(sd, &sfd, flags, timeout); +} + +/* + * readn + * read data from sockfd into buf + */ +static PRInt32 +readn(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + int err; + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + if (test_cancelio) + timeout = PR_SecondsToInterval(2); + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), rem)); +retry: + bytes = PR_Recv(sockfd, buf + offset, rem, 0, + timeout); + DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes < 0) { +#ifdef WINNT + printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()), + PR_GetOSError()); + if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) { + if (PR_NT_CancelIo(sockfd) != PR_SUCCESS) + printf("PR_NT_CancelIO: error = %d\n",PR_GetError()); + timeout = PR_INTERVAL_NO_TIMEOUT; + goto retry; + } +#endif + return -1; + } + } + return len; +} + +/* + * writen + * write data from buf to sockfd + */ +static PRInt32 +writen(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Send(sockfd, buf + offset, rem, 0, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes <= 0) + return -1; + } + return len; +} + +/* + * Serve_Client + * Thread, started by the server, for serving a client connection. + * Reads data from socket and writes it back, unmodified, and + * closes the socket + */ +static void PR_CALLBACK +Serve_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf; + PRInt32 bytes, j; + + sockfd = scp->sockfd; + bytes = scp->datalen; + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + goto exit; + } + + + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * Read data from client and send it back to the client unmodified + */ + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n"); + failed_already=1; + goto exit; + } + /* + * shutdown reads, after the last read + */ + if (j == num_tcp_mesgs_per_connection - 1) + if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + } + DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(), + (*((int *) in_buf->data)))); + if (writen(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n"); + failed_already=1; + goto exit; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + failed_already=1; + } + +exit: + PR_Close(sockfd); + if (in_buf) { + PR_DELETE(in_buf); + } +} + +PRThread* create_new_thread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRInt32 index) +{ +PRInt32 native_thread = 0; + + PR_ASSERT(state == PR_UNJOINABLE_THREAD); +#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) + switch(index % 4) { + case 0: + scope = (PR_LOCAL_THREAD); + break; + case 1: + scope = (PR_GLOBAL_THREAD); + break; + case 2: + scope = (PR_GLOBAL_BOUND_THREAD); + break; + case 3: + native_thread = 1; + break; + default: + PR_ASSERT(!"Invalid scope"); + break; + } + if (native_thread) { +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + pthread_t tid; + if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg)) + return((PRThread *) tid); + else + return (NULL); +#else + HANDLE thandle; + unsigned tid; + + thandle = (HANDLE) _beginthreadex( + NULL, + stackSize, + (unsigned (__stdcall *)(void *))start, + arg, + 0, + &tid); + return((PRThread *) thandle); +#endif + } else { + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); + } +#else + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); +#endif +} + +/* + * TCP Server + * Server Thread + * Bind an address to a socket and listen for incoming connections + * Start a Serve_Client thread for each incoming connection. + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + PRThread *t; + Server_Param *sp = (Server_Param *) arg; + Serve_Client_Param *scp; + PRFileDesc *sockfd, *newsockfd; + PRNetAddr netaddr; + PRInt32 i; + /* + * Create a tcp socket + */ + if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n"); + goto exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + + if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + goto exit; + } + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + failed_already=1; + goto exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n"); + failed_already=1; + goto exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + goto exit; + } + + DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain, + PR_ntohs(PR_NetAddrInetPort(&netaddr)), + &tcp_server_addr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + goto exit; + } + if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET)) + PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK), + &tcp_server_addr.ipv6.ip); + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'tcp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) { + /* test both null and non-null 'addr' argument to PR_Accept */ + PRNetAddr *addrp = (i%2 ? &netaddr: NULL); + + DPRINTF(("TCP_Server: Accepting connection\n")); + if ((newsockfd = PR_Accept(sockfd, addrp, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n"); + goto exit; + } + DPRINTF(("TCP_Server: Accepted connection\n")); + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + goto exit; + } + + /* + * Start a Serve_Client thread for each incoming connection + */ + scp->sockfd = newsockfd; + scp->datalen = sp->datalen; + + t = create_new_thread(PR_USER_THREAD, + Serve_Client, (void *)scp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + goto exit; + } + DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t)); + } + +exit: + if (sockfd) { + PR_Close(sockfd); + } + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * UDP Server + * Server Thread + * Bind an address to a socket, read data from clients and send data + * back to clients + */ +static void PR_CALLBACK +UDP_Server(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf; + PRNetAddr netaddr; + PRInt32 bytes, i, rv = 0; + + + bytes = sp->datalen; + /* + * Create a udp socket + */ + if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n"); + failed_already=1; + return; + } + memset(&netaddr, 0 , sizeof(netaddr)); + if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + failed_already=1; + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + return; + } + + DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + /* + * We can't use the IP address returned by PR_GetSockName in + * netaddr.inet.ip because netaddr.inet.ip is returned + * as 0 (= PR_INADDR_ANY). + */ + + if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain, + PR_ntohs(PR_NetAddrInetPort(&netaddr)), + &udp_server_addr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET)) + PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK), + &udp_server_addr.ipv6.ip); + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'udp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + bytes = sp->datalen; + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + /* + * Receive datagrams from clients and send them back, unmodified, to the + * clients + */ + memset(&netaddr, 0 , sizeof(netaddr)); + for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) { + DPRINTF(("UDP_Server: calling PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n", + netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data, + in_buf->data[0])); + + rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("UDP_Server: PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n", + netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data, + in_buf->data[0])); + if (rv != bytes) { + return; + } + rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + } + + PR_DELETE(in_buf); + PR_Close(sockfd); + + /* + * Decrement exit_counter and notify parent thread + */ + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * TCP_Client + * Client Thread + * Connect to the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket for server connection + */ +static void PR_CALLBACK +TCP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, j; + + + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + netaddr = cp->server_addr; + + for (i = 0; i < num_tcp_connections_per_client; i++) { + if ((sockfd = PR_OpenTCPSocket(client_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n"); + failed_already=1; + return; + } + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + return; + } + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * fill in random data + */ + memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes); + /* + * write to server + */ +#ifdef WINNT + if (test_cancelio && (j == 0)) + PR_Sleep(PR_SecondsToInterval(12)); +#endif + if (writen(sockfd, out_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n"); + failed_already=1; + return; + } + DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n"); + failed_already=1; + return; + } + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"prsocket_test: ERROR - data corruption\n"); + failed_already=1; + return; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n"); + failed_already=1; + } + PR_Close(sockfd); + } + + PR_DELETE(out_buf); + PR_DELETE(in_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * UDP_Client + * Client Thread + * Create a socket and bind an address + * Communicate with the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket + */ +static void PR_CALLBACK +UDP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, rv; + + + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n"); + failed_already=1; + return; + } + if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n"); + failed_already=1; + return; + } + + /* + * bind an address for the client, let the system chose the port + * number + */ + memset(&netaddr, 0 , sizeof(netaddr)); + if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0, + &netaddr) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n"); + failed_already=1; + return; + } + if (PR_Bind(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n"); + perror("PR_Bind"); + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + return; + } + + DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + + netaddr = cp->server_addr; + + if (cp->udp_connect) { + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr,"prsocket_test: PR_Connect failed\n"); + failed_already=1; + return; + } + } + + for (i = 0; i < num_udp_datagrams_per_client; i++) { + /* + * fill in random data + */ + DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n", + PR_GetCurrentThread(), out_buf->data, bytes)); + memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes); + /* + * write to server + */ + if (cp->udp_connect) + rv = PR_Send(sockfd, out_buf->data, bytes, 0, + PR_INTERVAL_NO_TIMEOUT); + else + rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + if (cp->udp_connect) + rv = PR_Recv(sockfd, in_buf->data, bytes, 0, + PR_INTERVAL_NO_TIMEOUT); + else + rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr, + PR_INTERVAL_NO_TIMEOUT); + if (rv != bytes) { + return; + } + DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data)))); + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n"); + failed_already=1; + return; + } + } + PR_Close(sockfd); + + PR_DELETE(in_buf); + PR_DELETE(out_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + PR_DELETE(cp); + DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread())); +} + +/* + * TCP_Socket_Client_Server_Test - concurrent server test + * + * One server and several clients are started + * Each client connects to the server and sends a chunk of data + * For each connection, server starts another thread to read the data + * from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +TCP_Socket_Client_Server_Test(void) +{ + int i; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + + + datalen = tcp_mesg_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + return -1; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + t = PR_CreateThread(PR_USER_THREAD, + TCP_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + DPRINTF(("Created TCP server = 0x%lx\n", t)); + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + cparamp->server_addr = tcp_server_addr; + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + for (i = 0; i < num_tcp_clients; i++) { + t = create_new_thread(PR_USER_THREAD, + TCP_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + DPRINTF(("Created TCP client = 0x%lx\n", t)); + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("TCP Server - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + return 0; +} + +/* + * UDP_Socket_Client_Server_Test - iterative server test + * + * One server and several clients are started + * Each client connects to the server and sends a chunk of data + * For each connection, server starts another thread to read the data + * from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +UDP_Socket_Client_Server_Test(void) +{ + int i; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + PRInt32 udp_connect = 1; + + + datalen = udp_datagram_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + return -1; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + DPRINTF(("Creating UDP server")); + t = PR_CreateThread(PR_USER_THREAD, + UDP_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + for (i = 0; i < num_udp_clients; i++) { + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + return -1; + } + cparamp->server_addr = udp_server_addr; + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + /* + * Cause every other client thread to connect udp sockets + */ +#ifndef XP_MAC + cparamp->udp_connect = udp_connect; +#else + /* No support for UDP connects on Mac */ + cparamp->udp_connect = 0; +#endif + if (udp_connect) + udp_connect = 0; + else + udp_connect = 1; + DPRINTF(("Creating UDP client %d\n", i)); + t = PR_CreateThread(PR_USER_THREAD, + UDP_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + return -1; + } + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("UDP Server - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); + printf("%30s","UDP_Socket_Client_Server_Test: "); + printf("%2ld Server %2ld Clients\n",1l, num_udp_clients); + printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":", + num_udp_datagrams_per_client, udp_datagram_size); + + return 0; +} + +static PRFileDesc *small_file_fd, *large_file_fd; +static void *small_file_addr, *small_file_header, *large_file_addr; +static void *small_file_trailer, *large_file_header, *large_file_trailer; +/* + * TransmitFile_Client + * Client Thread + */ +static void +TransmitFile_Client(void *arg) +{ + PRFileDesc *sockfd; + union PRNetAddr netaddr; + char *small_buf, *large_buf; + Client_Param *cp = (Client_Param *) arg; + PRInt32 rlen; + + small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE); + if (small_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer\n"); + failed_already=1; + return; + } + large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE); + if (large_buf == NULL) { + fprintf(stderr,"prsocket_test: failed to alloc buffer\n"); + failed_already=1; + return; + } + netaddr.inet.family = cp->server_addr.inet.family; + netaddr.inet.port = cp->server_addr.inet.port; + netaddr.inet.ip = cp->server_addr.inet.ip; + + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n"); + failed_already=1; + return; + } + + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr,"prsocket_test: PR_Connect failed\n"); + failed_already=1; + return; + } + /* + * read the small file and verify the data + */ + if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE) + != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE, + SMALL_FILE_SIZE) != 0) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * read the large file and verify the data + */ + if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) { + fprintf(stderr, + "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n"); + failed_already=1; + } +#endif + + + /* + * receive data from PR_SendFile + */ + /* + * case 1: small file with header and trailer + */ + rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 1. ERROR - small file header corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE, + SMALL_FILE_SIZE) != 0) { + fprintf(stderr, + "SendFile 1. ERROR - small file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_trailer, + small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE, + SMALL_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 1. ERROR - small file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 2: partial large file at zero offset, file with header and trailer + */ + rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 2. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_1) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_trailer, + large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1, + LARGE_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 3: partial small file at non-zero offset, with header + */ + rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 3. ERROR - small file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_1, + small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) { + fprintf(stderr, + "SendFile 3. ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 4: partial small file at non-zero offset, with trailer + */ + rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_2, small_buf, + SMALL_FILE_LEN_2) != 0) { + fprintf(stderr, + "SendFile 4. ERROR - small file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2, + SMALL_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 4. ERROR - small file trailer corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 5: partial large file at non-zero offset, file with header + */ + rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 5. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_2, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_2) != 0) { + fprintf(stderr, + "SendFile 5. ERROR - large file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 6: partial small file at non-zero offset, with header + */ + rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE; + if (readn(sockfd, small_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 6. ERROR - small file header corruption\n"); + return; + } + if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_3, + small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) { +#if 0 + char *i, *j; + int k; + + i = (char *) small_file_addr + SMALL_FILE_OFFSET_3; + j = small_buf + SMALL_FILE_HEADER_SIZE; + k = SMALL_FILE_LEN_3; + while (k-- > 0) { + if (*i++ != *j++) + printf("i = %d j = %d\n", + (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)), + (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE))); + } +#endif + fprintf(stderr, + "SendFile 6. ERROR - small file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 7: partial large file at non-zero offset, with header + */ + rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 7. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_3, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_3) != 0) { + fprintf(stderr, + "SendFile 7. ERROR - large file data corruption\n"); + failed_already=1; + return; + } +#endif + /* + * case 8: partial large file at non-zero, page-aligned offset, with + * header and trailer + */ + rlen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (readn(sockfd, large_buf, rlen) != rlen) { + fprintf(stderr, + "prsocket_test: SendFile_Client failed to receive file\n"); + failed_already=1; + return; + } +#ifdef XP_UNIX + if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0){ + fprintf(stderr, + "SendFile 2. ERROR - large file header corruption\n"); + failed_already=1; + return; + } + if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_4, + large_buf + LARGE_FILE_HEADER_SIZE, + LARGE_FILE_LEN_4) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file data corruption\n"); + failed_already=1; + return; + } + if (memcmp(large_file_trailer, + large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_4, + LARGE_FILE_TRAILER_SIZE) != 0) { + fprintf(stderr, + "SendFile 2. ERROR - large file trailer corruption\n"); + failed_already=1; + return; + } +#endif + PR_DELETE(small_buf); + PR_DELETE(large_buf); + PR_Close(sockfd); + + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * Serve_TransmitFile_Client + * Thread, started by the server, for serving a client connection. + * Trasmits a small file, with a header, and a large file, without + * a header + */ +static void +Serve_TransmitFile_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + PRFileDesc *sockfd; + PRInt32 bytes; + PRFileDesc *local_small_file_fd=NULL; + PRFileDesc *local_large_file_fd=NULL; + PRSendFileData sfd; + PRInt32 slen; + + sockfd = scp->sockfd; + local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0); + + if (local_small_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n", + SMALL_FILE_NAME); + failed_already=1; + goto done; + } + local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0); + + if (local_large_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n", + LARGE_FILE_NAME); + failed_already=1; + goto done; + } + bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header, + SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) { + fprintf(stderr, + "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0, + PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT); + if (bytes != LARGE_FILE_SIZE) { + fprintf(stderr, + "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + /* + * PR_SendFile test cases + */ + + /* + * case 1: small file with header and trailer + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = small_file_trailer; + sfd.tlen = SMALL_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE + + SMALL_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 1. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + /* + * case 2: partial large file at zero offset, file with header and trailer + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = 0; + sfd.file_nbytes = LARGE_FILE_LEN_1; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = large_file_trailer; + sfd.tlen = LARGE_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 3: partial small file at non-zero offset, with header + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_1; + sfd.file_nbytes = SMALL_FILE_LEN_1; + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 4: partial small file at non-zero offset, with trailer + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_2; + sfd.file_nbytes = SMALL_FILE_LEN_2; + sfd.header = NULL; + sfd.hlen = 0; + sfd.trailer = small_file_trailer; + sfd.tlen = SMALL_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 5: partial large file at non-zero offset, file with header + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_2; + sfd.file_nbytes = LARGE_FILE_LEN_2; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 6: partial small file from non-zero offset till end of file, with header + */ + sfd.fd = local_small_file_fd; + sfd.file_offset = SMALL_FILE_OFFSET_3; + sfd.file_nbytes = 0; /* data from offset to end-of-file */ + sfd.header = small_file_header; + sfd.hlen = SMALL_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 7: partial large file at non-zero offset till end-of-file, with header + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_3; + sfd.file_nbytes = 0; /* data until end-of-file */ + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = NULL; + sfd.tlen = 0; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } + /* + * case 8: partial large file at non-zero page-aligned offset, + * with header and trailer + */ + sfd.fd = local_large_file_fd; + sfd.file_offset = LARGE_FILE_OFFSET_4; + sfd.file_nbytes = LARGE_FILE_LEN_4; + sfd.header = large_file_header; + sfd.hlen = LARGE_FILE_HEADER_SIZE; + sfd.trailer = large_file_trailer; + sfd.tlen = LARGE_FILE_TRAILER_SIZE; + bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET, + PR_INTERVAL_NO_TIMEOUT); + slen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE + + LARGE_FILE_TRAILER_SIZE; + if (bytes != slen) { + fprintf(stderr, + "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n", + slen, bytes); + fprintf(stderr, + "prsocket_test: PR_SendFile failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + } +done: + if (local_small_file_fd != NULL) + PR_Close(local_small_file_fd); + if (local_large_file_fd != NULL) + PR_Close(local_large_file_fd); +} + +/* + * TransmitFile Server + * Server Thread + * Bind an address to a socket and listen for incoming connections + * Create worker threads to service clients + */ +static void +TransmitFile_Server(void *arg) +{ + PRThread **t = NULL; /* an array of PRThread pointers */ + Server_Param *sp = (Server_Param *) arg; + Serve_Client_Param *scp; + PRFileDesc *sockfd = NULL, *newsockfd; + PRNetAddr netaddr; + PRInt32 i; + + t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *)); + if (t == NULL) { + fprintf(stderr, "prsocket_test: run out of memory\n"); + failed_already=1; + goto exit; + } + /* + * Create a tcp socket + */ + if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) { + fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n"); + failed_already=1; + goto exit; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n"); + failed_already=1; + perror("PR_Bind"); + goto exit; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n"); + failed_already=1; + goto exit; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr, + "prsocket_test: ERROR - PR_GetSockName failed\n"); + failed_already=1; + goto exit; + } + + DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + tcp_server_addr.inet.family = netaddr.inet.family; + tcp_server_addr.inet.port = netaddr.inet.port; + tcp_server_addr.inet.ip = netaddr.inet.ip; + + /* + * Wake up parent thread because server address is bound and made + * available in the global variable 'tcp_server_addr' + */ + PR_PostSem(sp->addr_sem); + + for (i = 0; i < num_transmitfile_clients ; i++) { + /* test both null and non-null 'addr' argument to PR_Accept */ + PRNetAddr *addrp = (i%2 ? &netaddr: NULL); + + if ((newsockfd = PR_Accept(sockfd, addrp, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr, + "prsocket_test: ERROR - PR_Accept failed\n"); + failed_already=1; + goto exit; + } + /* test both regular and emulated PR_SendFile */ + if (i%2) { + PRFileDesc *layer = PR_CreateIOLayerStub( + emuSendFileIdentity, &emuSendFileMethods); + if (layer == NULL) { + fprintf(stderr, + "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n"); + failed_already=1; + goto exit; + } + if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer) + == PR_FAILURE) { + fprintf(stderr, + "prsocket_test: ERROR - PR_PushIOLayer failed\n"); + failed_already=1; + goto exit; + } + } + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + goto exit; + } + + /* + * Start a Serve_Client thread for each incoming connection + */ + scp->sockfd = newsockfd; + scp->datalen = sp->datalen; + + t[i] = PR_CreateThread(PR_USER_THREAD, + Serve_TransmitFile_Client, (void *)scp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0); + if (t[i] == NULL) { + fprintf(stderr, + "prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + goto exit; + } + DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t)); + } + + /* + * Wait for all the worker threads to end, so that we know + * they are no longer using the small and large file fd's. + */ + + for (i = 0; i < num_transmitfile_clients; i++) { + PR_JoinThread(t[i]); + } + +exit: + if (t) { + PR_DELETE(t); + } + if (sockfd) { + PR_Close(sockfd); + } + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(sp->exit_mon); + --(*sp->exit_counter); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread())); +} + +/* + * Socket_Misc_Test - test miscellaneous functions + * + */ +static PRInt32 +Socket_Misc_Test(void) +{ + PRIntn i, rv = 0, bytes, count, len; + PRThread *t; + PRSemaphore *server_sem; + Server_Param *sparamp; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + + /* + * We deliberately pick a buffer size that is not a nice multiple + * of 1024. + */ +#define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11) + + typedef struct { + char data[TRANSMITFILE_BUF_SIZE]; + } file_buf; + file_buf *buf = NULL; + + /* + * create file(s) to be transmitted + */ + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf("prsocket_test failed to create dir %s\n",TEST_DIR); + failed_already=1; + return -1; + } + + small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); + + if (small_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to create/open file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + buf = PR_NEW(file_buf); + if (buf == NULL) { + fprintf(stderr,"prsocket_test failed to allocate buffer\n"); + failed_already=1; + rv = -1; + goto done; + } + /* + * fill in random data + */ + for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { + buf->data[i] = i; + } + count = 0; + do { + len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? + TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count); + bytes = PR_Write(small_file_fd, buf->data, len); + if (bytes <= 0) { + fprintf(stderr, + "prsocket_test failed to write to file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + count += bytes; + } while (count < SMALL_FILE_SIZE); +#ifdef XP_UNIX + /* + * map the small file; used in checking for data corruption + */ + small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ, + MAP_SHARED, small_file_fd->secret->md.osfd, 0); + if (small_file_addr == (void *) -1) { + fprintf(stderr,"prsocket_test failed to mmap file %s\n", + SMALL_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } +#endif + /* + * header for small file + */ + small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE); + if (small_file_header == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header file\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(small_file_header, (int) PR_IntervalNow(), + SMALL_FILE_HEADER_SIZE); + /* + * trailer for small file + */ + small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE); + if (small_file_trailer == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header trailer\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(small_file_trailer, (int) PR_IntervalNow(), + SMALL_FILE_TRAILER_SIZE); + /* + * setup large file + */ + large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777); + + if (large_file_fd == NULL) { + fprintf(stderr,"prsocket_test failed to create/open file %s\n", + LARGE_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } + /* + * fill in random data + */ + for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) { + buf->data[i] = i; + } + count = 0; + do { + len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ? + TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count); + bytes = PR_Write(large_file_fd, buf->data, len); + if (bytes <= 0) { + fprintf(stderr, + "prsocket_test failed to write to file %s: (%ld, %ld)\n", + LARGE_FILE_NAME, + PR_GetError(), PR_GetOSError()); + failed_already=1; + rv = -1; + goto done; + } + count += bytes; + } while (count < LARGE_FILE_SIZE); +#ifdef XP_UNIX + /* + * map the large file; used in checking for data corruption + */ + large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ, + MAP_SHARED, large_file_fd->secret->md.osfd, 0); + if (large_file_addr == (void *) -1) { + fprintf(stderr,"prsocket_test failed to mmap file %s\n", + LARGE_FILE_NAME); + failed_already=1; + rv = -1; + goto done; + } +#endif + /* + * header for large file + */ + large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE); + if (large_file_header == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header file\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(large_file_header, (int) PR_IntervalNow(), + LARGE_FILE_HEADER_SIZE); + /* + * trailer for large file + */ + large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE); + if (large_file_trailer == NULL) { + fprintf(stderr,"prsocket_test failed to malloc header trailer\n"); + failed_already=1; + rv = -1; + goto done; + } + memset(large_file_trailer, (int) PR_IntervalNow(), + LARGE_FILE_TRAILER_SIZE); + + datalen = tcp_mesg_size; + thread_count = 0; + /* + * start the server thread + */ + sparamp = PR_NEW(Server_Param); + if (sparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + rv = -1; + goto done; + } + server_sem = PR_NewSem(0); + if (server_sem == NULL) { + fprintf(stderr,"prsocket_test: PR_NewSem failed\n"); + failed_already=1; + rv = -1; + goto done; + } + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n"); + failed_already=1; + rv = -1; + goto done; + } + PR_EnterMonitor(mon2); + + sparamp->addr_sem = server_sem; + sparamp->exit_mon = mon2; + sparamp->exit_counter = &thread_count; + sparamp->datalen = datalen; + t = PR_CreateThread(PR_USER_THREAD, + TransmitFile_Server, (void *)sparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + failed_already=1; + rv = -1; + goto done; + } + DPRINTF(("Created TCP server = 0x%x\n", t)); + thread_count++; + + /* + * wait till the server address is setup + */ + PR_WaitSem(server_sem); + + /* + * Now start a bunch of client threads + */ + + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"prsocket_test: PR_NEW failed\n"); + failed_already=1; + rv = -1; + goto done; + } + cparamp->server_addr = tcp_server_addr; + cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + cparamp->exit_mon = mon2; + cparamp->exit_counter = &thread_count; + cparamp->datalen = datalen; + for (i = 0; i < num_transmitfile_clients; i++) { + t = create_new_thread(PR_USER_THREAD, + TransmitFile_Client, (void *) cparamp, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (t == NULL) { + fprintf(stderr,"prsocket_test: PR_CreateThread failed\n"); + rv = -1; + failed_already=1; + goto done; + } + DPRINTF(("Created TransmitFile client = 0x%lx\n", t)); + thread_count++; + } + /* Wait for server and client threads to exit */ + while (thread_count) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("Socket_Misc_Test - thread_count = %d\n", thread_count)); + } + PR_ExitMonitor(mon2); +done: + if (buf) { + PR_DELETE(buf); + } +#ifdef XP_UNIX + munmap((char*)small_file_addr, SMALL_FILE_SIZE); + munmap((char*)large_file_addr, LARGE_FILE_SIZE); +#endif + PR_Close(small_file_fd); + PR_Close(large_file_fd); + if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: failed to unlink file %s\n", + SMALL_FILE_NAME); + failed_already=1; + } + if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test: failed to unlink file %s\n", + LARGE_FILE_NAME); + failed_already=1; + } + if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) { + fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + failed_already=1; + } + + printf("%-29s%s","Socket_Misc_Test",":"); + printf("%2d Server %2d Clients\n",1, num_transmitfile_clients); + printf("%30s Sizes of Transmitted Files - %4d KB, %2d MB \n",":", + SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024)); + + + return rv; +} +/************************************************************************/ + +/* + * Test Socket NSPR APIs + */ + +int +main(int argc, char **argv) +{ + /* + * -d debug mode + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile"); + emuSendFileMethods = *PR_GetDefaultIOMethods(); + emuSendFileMethods.transmitfile = emu_TransmitFile; + emuSendFileMethods.sendfile = emu_SendFile; + + /* + * run client-server test with TCP, Ipv4-Ipv4 + */ + printf("TCP Client/Server Test - IPv4/Ipv4\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv6-Ipv4 + */ + client_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv6/Ipv4\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv4-Ipv6 + */ + client_domain = PR_AF_INET; + server_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv4/Ipv6\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + /* + * client-server test, Ipv6-Ipv6 + */ + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET6; + printf("TCP Client/Server Test - IPv6/Ipv6\n"); + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); + test_cancelio = 0; + /* + * run client-server test with UDP, IPv4/IPv4 + */ + printf("UDP Client/Server Test - IPv4/Ipv4\n"); + client_domain = PR_AF_INET; + server_domain = PR_AF_INET; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP, IPv6/IPv4 + */ + printf("UDP Client/Server Test - IPv6/Ipv4\n"); + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP,IPv4-IPv6 + */ + printf("UDP Client/Server Test - IPv4/Ipv6\n"); + client_domain = PR_AF_INET; + server_domain = PR_AF_INET6; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * run client-server test with UDP,IPv6-IPv6 + */ + printf("UDP Client/Server Test - IPv6/Ipv6\n"); + client_domain = PR_AF_INET6; + server_domain = PR_AF_INET6; + if (UDP_Socket_Client_Server_Test() < 0) { + printf("UDP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("UDP_Socket_Client_Server_Test Passed\n"); + /* + * Misc socket tests - including transmitfile, etc. + */ + +#if !defined(WIN16) + /* +** The 'transmit file' test does not run because +** transmit file is not implemented in NSPR yet. +** +*/ + if (Socket_Misc_Test() < 0) { + printf("Socket_Misc_Test failed\n"); + failed_already=1; + goto done; + } else + printf("Socket_Misc_Test passed\n"); + + /* + * run client-server test with TCP again to test + * recycling used sockets from PR_TransmitFile(). + */ + if (TCP_Socket_Client_Server_Test() < 0) { + printf("TCP_Socket_Client_Server_Test failed\n"); + goto done; + } else + printf("TCP_Socket_Client_Server_Test Passed\n"); +#endif + +done: + PR_Cleanup(); + if (failed_already) return 1; + else return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sockopt.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sockopt.c new file mode 100644 index 00000000..905e2387 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sockopt.c @@ -0,0 +1,213 @@ +/* -*- 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 "nspr.h" +#include "prio.h" +#include "prinit.h" +#include "prprf.h" +#ifdef XP_MAC +#include "probslet.h" +#else +#include "obsolete/probslet.h" +#endif + +#include "plerror.h" + +static PRFileDesc *err = NULL; +static PRBool failed = PR_FALSE; + +#ifndef XP_MAC +static void Failed(const char *msg1, const char *msg2) +{ + if (NULL != msg1) PR_fprintf(err, "%s ", msg1); + PL_FPrintError(err, msg2); + failed = PR_TRUE; +} /* Failed */ + +#else +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +static void Failed(const char *msg1, const char *msg2) +{ + if (NULL != msg1) printf("%s ", msg1); + printf (msg2); + failed |= PR_TRUE; +} /* Failed */ + +#endif + +static PRSockOption Incr(PRSockOption *option) +{ + PRIntn val = ((PRIntn)*option) + 1; + *option = (PRSockOption)val; + return (PRSockOption)val; +} /* Incr */ + +PRIntn main(PRIntn argc, char *argv) +{ + PRStatus rv; + PRFileDesc *udp = PR_NewUDPSocket(); + PRFileDesc *tcp = PR_NewTCPSocket(); + const char *tag[] = + { + "PR_SockOpt_Nonblocking", /* nonblocking io */ + "PR_SockOpt_Linger", /* linger on close if data present */ + "PR_SockOpt_Reuseaddr", /* allow local address reuse */ + "PR_SockOpt_Keepalive", /* keep connections alive */ + "PR_SockOpt_RecvBufferSize", /* send buffer size */ + "PR_SockOpt_SendBufferSize", /* receive buffer size */ + + "PR_SockOpt_IpTimeToLive", /* time to live */ + "PR_SockOpt_IpTypeOfService", /* type of service and precedence */ + + "PR_SockOpt_AddMember", /* add an IP group membership */ + "PR_SockOpt_DropMember", /* drop an IP group membership */ + "PR_SockOpt_McastInterface", /* multicast interface address */ + "PR_SockOpt_McastTimeToLive", /* multicast timetolive */ + "PR_SockOpt_McastLoopback", /* multicast loopback */ + + "PR_SockOpt_NoDelay", /* don't delay send to coalesce packets */ + "PR_SockOpt_MaxSegment", /* maximum segment size */ + "PR_SockOpt_Broadcast", /* Enable broadcast */ + "PR_SockOpt_Last" + }; + + err = PR_GetSpecialFD(PR_StandardError); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("sockopt.log"); +#endif + + if (NULL == udp) Failed("PR_NewUDPSocket()", NULL); + else if (NULL == tcp) Failed("PR_NewTCPSocket()", NULL); + else + { + PRSockOption option; + PRUint32 segment = 1024; + PRNetAddr addr; + + rv = PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr); + if (PR_FAILURE == rv) Failed("PR_InitializeNetAddr()", NULL); + rv = PR_Bind(udp, &addr); + if (PR_FAILURE == rv) Failed("PR_Bind()", NULL); + for(option = PR_SockOpt_Linger; option < PR_SockOpt_Last; Incr(&option)) + { + PRSocketOptionData data; + PRFileDesc *fd = tcp; + data.option = option; + switch (option) + { + case PR_SockOpt_Nonblocking: + data.value.non_blocking = PR_TRUE; + break; + case PR_SockOpt_Linger: + data.value.linger.polarity = PR_TRUE; + data.value.linger.linger = PR_SecondsToInterval(2); + break; + case PR_SockOpt_Reuseaddr: + data.value.reuse_addr = PR_TRUE; + break; + case PR_SockOpt_Keepalive: + data.value.keep_alive = PR_TRUE; + break; + case PR_SockOpt_RecvBufferSize: + data.value.recv_buffer_size = segment; + break; + case PR_SockOpt_SendBufferSize: + data.value.send_buffer_size = segment; + break; + case PR_SockOpt_IpTimeToLive: + data.value.ip_ttl = 64; + break; + case PR_SockOpt_IpTypeOfService: + data.value.tos = 0; + break; + case PR_SockOpt_McastTimeToLive: + fd = udp; + data.value.mcast_ttl = 4; + break; + case PR_SockOpt_McastLoopback: + fd = udp; + data.value.mcast_loopback = PR_TRUE; + break; + case PR_SockOpt_NoDelay: + data.value.no_delay = PR_TRUE; + break; +#ifndef WIN32 + case PR_SockOpt_MaxSegment: + data.value.max_segment = segment; + break; +#endif + case PR_SockOpt_Broadcast: + fd = udp; + data.value.broadcast = PR_TRUE; + break; + default: continue; + } + + /* + * TCP_MAXSEG can only be read, not set + */ + if (option != PR_SockOpt_MaxSegment) { +#ifdef WIN32 + if (option != PR_SockOpt_McastLoopback) +#endif + { + rv = PR_SetSocketOption(fd, &data); + if (PR_FAILURE == rv) + Failed("PR_SetSocketOption()", tag[option]); + } + } + + rv = PR_GetSocketOption(fd, &data); + if (PR_FAILURE == rv) Failed("PR_GetSocketOption()", tag[option]); + } + PR_Close(udp); + PR_Close(tcp); + } +#ifndef XP_MAC + PR_fprintf(err, "%s\n", (failed) ? "FAILED" : "PASSED"); +#else + printf("%s\n", (failed) ? "FAILED" : "PASSED"); +#endif + return (failed) ? 1 : 0; +} /* main */ + +/* sockopt.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sockping.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sockping.c new file mode 100644 index 00000000..09365138 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sockping.c @@ -0,0 +1,164 @@ +/* -*- 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 ***** */ + +/* + * File: sockping.c + * + * Description: + * This test runs in conjunction with the sockpong test. + * This test creates a socket pair and passes one socket + * to the sockpong test. Then this test writes "ping" to + * to the sockpong test and the sockpong test writes "pong" + * back. To run this pair of tests, just invoke sockping. + * + * Tested areas: process creation, socket pairs, file + * descriptor inheritance. + */ + +#include "prerror.h" +#include "prio.h" +#include "prproces.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +static char *child_argv[] = { "sockpong", NULL }; + +int main() +{ + PRFileDesc *sock[2]; + PRStatus status; + PRProcess *process; + PRProcessAttr *attr; + char buf[1024]; + PRInt32 nBytes; + PRInt32 exitCode; + int idx; + + status = PR_NewTCPSocketPair(sock); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_NewTCPSocketPair failed\n"); + exit(1); + } + + status = PR_SetFDInheritable(sock[0], PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + status = PR_SetFDInheritable(sock[1], PR_TRUE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + + attr = PR_NewProcessAttr(); + if (attr == NULL) { + fprintf(stderr, "PR_NewProcessAttr failed\n"); + exit(1); + } + + status = PR_ProcessAttrSetInheritableFD(attr, sock[1], "SOCKET"); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_ProcessAttrSetInheritableFD failed\n"); + exit(1); + } + + process = PR_CreateProcess(child_argv[0], child_argv, NULL, attr); + if (process == NULL) { + fprintf(stderr, "PR_CreateProcess failed\n"); + exit(1); + } + PR_DestroyProcessAttr(attr); + status = PR_Close(sock[1]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + strcpy(buf, "ping"); + printf("ping process: sending \"%s\"\n", buf); + nBytes = PR_Write(sock[0], buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(sock[0], buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("ping process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "ping process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "pong") != 0) { + fprintf(stderr, "ping process: expected \"pong\" but got \"%s\"\n", + buf); + exit(1); + } + } + + status = PR_Close(sock[0]); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + status = PR_WaitProcess(process, &exitCode); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_WaitProcess failed\n"); + exit(1); + } + if (exitCode == 0) { + printf("PASS\n"); + return 0; + } else { + printf("FAIL\n"); + return 1; + } +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sockpong.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sockpong.c new file mode 100644 index 00000000..e54e3423 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sockpong.c @@ -0,0 +1,115 @@ +/* -*- 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 ***** */ + +/* + * File: sockpong.c + * + * Description: + * This test runs in conjunction with the sockping test. + * The sockping test creates a socket pair and passes one + * socket to this test. Then the sockping test writes + * "ping" to this test and this test writes "pong" back. + * To run this pair of tests, just invoke sockping. + * + * Tested areas: process creation, socket pairs, file + * descriptor inheritance. + */ + +#include "prerror.h" +#include "prio.h" + +#include +#include +#include + +#define NUM_ITERATIONS 10 + +int main() +{ + PRFileDesc *sock; + PRStatus status; + char buf[1024]; + PRInt32 nBytes; + int idx; + + sock = PR_GetInheritedFD("SOCKET"); + if (sock == NULL) { + fprintf(stderr, "PR_GetInheritedFD failed\n"); + exit(1); + } + status = PR_SetFDInheritable(sock, PR_FALSE); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_SetFDInheritable failed\n"); + exit(1); + } + + for (idx = 0; idx < NUM_ITERATIONS; idx++) { + memset(buf, 0, sizeof(buf)); + nBytes = PR_Read(sock, buf, sizeof(buf)); + if (nBytes == -1) { + fprintf(stderr, "PR_Read failed: (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + exit(1); + } + printf("pong process: received \"%s\"\n", buf); + if (nBytes != 5) { + fprintf(stderr, "pong process: expected 5 bytes but got %d bytes\n", + nBytes); + exit(1); + } + if (strcmp(buf, "ping") != 0) { + fprintf(stderr, "pong process: expected \"ping\" but got \"%s\"\n", + buf); + exit(1); + } + + strcpy(buf, "pong"); + printf("pong process: sending \"%s\"\n", buf); + nBytes = PR_Write(sock, buf, 5); + if (nBytes == -1) { + fprintf(stderr, "PR_Write failed\n"); + exit(1); + } + } + + status = PR_Close(sock); + if (status == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sprintf.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sprintf.c new file mode 100644 index 00000000..7fe2ac19 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sprintf.c @@ -0,0 +1,454 @@ +/* -*- 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 ***** */ + +/* + * File: sprintf.c + * Description: + * This is a test program for the PR_snprintf() functions defined + * in prprf.c. This test program is based on ns/nspr/tests/sprintf.c, + * revision 1.10. + * Modification History: + * 20-May-1997 AGarcia replaced printf statment to return PASS\n. This is to be used by the + * regress tool parsing routine. + ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to + * recognize the return code from tha main program. + */ + +#include "prinit.h" +#include "prprf.h" +#include "prlog.h" +#include "prlong.h" +#include +#include +#include + +#define countof(a) (sizeof(a)/sizeof(a[0])) + +static char sbuf[20000]; + + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_i(char *pattern, int i) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, i); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, i); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, pattern, i); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' i=%d\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, i, s, buf, sbuf); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestI(void) +{ + static int nums[] = { + 0, 1, -1, 10, -10, + 32767, -32768, + }; + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { + "d", "o", "x", "u", + "hd", "ho", "hx", "hu" + }; + int f, s, n, p; + char fmt[20]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + if (formats[f]) strcat(fmt, formats[f]); + for (n = 0; n < countof(nums); n++) { + test_i(fmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_l(char *pattern, char *spattern, PRInt32 l) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, l); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, l); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, spattern, l); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' l=%ld\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, l, s, buf, sbuf); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestL(void) +{ + static PRInt32 nums[] = { + 0, + 1, + -1, + 10, + -10, + 32767, + -32768, + PR_INT32(0x7fffffff), /* 2147483647L */ + -1 - PR_INT32(0x7fffffff) /* -2147483648L */ + }; + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "ld", "lo", "lx", "lu" }; + +#if PR_BYTES_PER_INT == 4 + static char *sformats[] = { "d", "o", "x", "u" }; +#elif PR_BYTES_PER_LONG == 4 + static char *sformats[] = { "ld", "lo", "lx", "lu" }; +#else +#error Neither int nor long is 4 bytes on this platform +#endif + + int f, s, n, p; + char fmt[40], sfmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + strcpy(sfmt, fmt); + if (formats[f]) strcat(fmt, formats[f]); + if (sformats[f]) strcat(sfmt, sformats[f]); + for (n = 0; n < countof(nums); n++) { + test_l(fmt, sfmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_ll(char *pattern, char *spattern, PRInt64 l) +{ + char *s; + char buf[200]; + int n; + + /* try all three routines */ + s = PR_smprintf(pattern, l); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, l); + PR_ASSERT(n <= sizeof(buf)); +#if defined(HAVE_LONG_LONG) + sprintf(sbuf, spattern, l); + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { +#if PR_BYTES_PER_LONG == 8 +#define FORMAT_SPEC "%ld" +#elif defined(WIN16) +#define FORMAT_SPEC "%Ld" +#elif defined(WIN32) +#define FORMAT_SPEC "%I64d" +#else +#define FORMAT_SPEC "%lld" +#endif + fprintf(stderr, + "pattern='%s' ll=" FORMAT_SPEC "\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, l, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +#else + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0)) { + fprintf(stderr, + "pattern='%s'\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +#endif +} + +static void TestLL(void) +{ + static PRInt64 nums[] = { + LL_INIT(0, 0), + LL_INIT(0, 1), + LL_INIT(0xffffffff, 0xffffffff), /* -1 */ + LL_INIT(0, 10), + LL_INIT(0xffffffff, 0xfffffff6), /* -10 */ + LL_INIT(0, 32767), + LL_INIT(0xffffffff, 0xffff8000), /* -32768 */ + LL_INIT(0, 0x7fffffff), /* 2147483647 */ + LL_INIT(0xffffffff, 0x80000000), /* -2147483648 */ + LL_INIT(0x7fffffff, 0xffffffff), /* 9223372036854775807 */ + LL_INIT(0x80000000, 0) /* -9223372036854775808 */ + }; + + static char *signs[] = { + "", + "0", "-", "+", " ", + "0-", "0+", "0 ", "-0", "-+", "- ", + "+0", "+-", "+ ", " 0", " -", " +", + "0-+", "0- ", "0+-", "0+ ", "0 -", "0 +", + "-0+", "-0 ", "-+0", "-+ ", "- 0", "- +", + "+0-", "+0 ", "+-0", "+- ", "+ 0", "+ -", + " 0-", " 0+", " -0", " -+", " +0", " +-", + "0-+ ", "0- +", "0+- ", "0+ -", "0 -+", "0 +-", + "-0+ ", "-0 +", "-+0 ", "-+ 0", "- 0+", "- +0", + "+0- ", "+0 -", "+-0 ", "+- 0", "+ 0-", "+ -0", + " 0-+", " 0+-", " -0+", " -+0", " +0-", " +-0", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "lld", "llo", "llx", "llu" }; + +#if PR_BYTES_PER_LONG == 8 + static char *sformats[] = { "ld", "lo", "lx", "lu" }; +#elif defined(WIN16) + /* Watcom uses the format string "%Ld" instead of "%lld". */ + static char *sformats[] = { "Ld", "Lo", "Lx", "Lu" }; +#elif defined(WIN32) + static char *sformats[] = { "I64d", "I64o", "I64x", "I64u" }; +#else + static char *sformats[] = { "lld", "llo", "llx", "llu" }; +#endif + + int f, s, n, p; + char fmt[40], sfmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt, signs[s]); + if (precs[p]) strcat(fmt, precs[p]); + strcpy(sfmt, fmt); + if (formats[f]) strcat(fmt, formats[f]); + if (sformats[f]) strcat(sfmt, sformats[f]); + for (n = 0; n < countof(nums); n++) { + test_ll(fmt, sfmt, nums[n]); + } + } + } + } +} + +/************************************************************************/ + +/* +** Perform a three way test against PR_smprintf, PR_snprintf, and sprintf. +** Make sure the results are identical +*/ +static void test_s(char *pattern, char *ss) +{ + char *s; + unsigned char before[8]; + char buf[200]; + unsigned char after[8]; + int n; + + memset(before, 0xBB, 8); + memset(after, 0xAA, 8); + + /* try all three routines */ + s = PR_smprintf(pattern, ss); + PR_ASSERT(s != 0); + n = PR_snprintf(buf, sizeof(buf), pattern, ss); + PR_ASSERT(n <= sizeof(buf)); + sprintf(sbuf, pattern, ss); + + for (n = 0; n < 8; n++) { + PR_ASSERT(before[n] == 0xBB); + PR_ASSERT(after[n] == 0xAA); + } + + /* compare results */ + if ((strncmp(s, buf, sizeof(buf)) != 0) || + (strncmp(s, sbuf, sizeof(sbuf)) != 0)) { + fprintf(stderr, + "pattern='%s' ss=%.20s\nPR_smprintf='%s'\nPR_snprintf='%s'\n sprintf='%s'\n", + pattern, ss, s, buf, sbuf); + printf("FAIL\n"); + PR_smprintf_free(s); + exit(-1); + } + PR_smprintf_free(s); +} + +static void TestS(void) +{ + static char *strs[] = { + "", + "a", + "abc", + "abcde", + "abcdefABCDEF", + "abcdefghijklmnopqrstuvwxyz0123456789!@#$" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$" + "abcdefghijklmnopqrstuvwxyz0123456789!@#$", + }; + /* '0' is not relevant to printing strings */ + static char *signs[] = { + "", + "-", "+", " ", + "-+", "- ", "+-", "+ ", " -", " +", + "-+ ", "- +", "+- ", "+ -", " -+", " +-", + }; + static char *precs[] = { + "", "3", "5", "43", + ".3", ".43", + "7.3", "7.5", "7.11", "7.43", + }; + static char *formats[] = { "s" }; + int f, s, n, p; + char fmt[40]; + + for (f = 0; f < countof(formats); f++) { + for (s = 0; s < countof(signs); s++) { + for (p = 0; p < countof(precs); p++) { + fmt[0] = '%'; + fmt[1] = 0; + if (signs[s]) strcat(fmt+strlen(fmt), signs[s]); + if (precs[p]) strcat(fmt+strlen(fmt), precs[p]); + if (formats[f]) strcat(fmt+strlen(fmt), formats[f]); + for (n = 0; n < countof(strs); n++) { + test_s(fmt, strs[n]); + } + } + } + } +} + +/************************************************************************/ + +int main(int argc, char **argv) +{ + PR_STDIO_INIT(); + TestI(); + TestL(); + TestLL(); + TestS(); + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_ch.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_ch.c new file mode 100644 index 00000000..98dee083 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_ch.c @@ -0,0 +1,119 @@ +/* -*- 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 ***** */ + +/* + * Test sproc_ch.c + * + * The purpose of this test and the sproc_p.c test is to test the shutdown + * of all the IRIX sprocs in a program when one of them dies due to an error. + * + * There are three sprocs in this test: the parent, the child, and the + * grandchild. The parent and child sprocs never stop on their own. + * The grandchild sproc gets a segmentation fault and dies. You should + * You should use "ps" to see if the parent and child sprocs are killed + * after the grandchild dies. + */ + +#include "prinit.h" +#include + +#if !defined(IRIX) + +int main() +{ + printf("This test applies to IRIX only.\n"); + return 0; +} + +#else /* IRIX */ + +#include "prthread.h" +#include +#include + +void SegFault(void *unused) +{ + int *p = 0; + + printf("The grandchild sproc has pid %d.\n", getpid()); + printf("The grandchild sproc will get a segmentation fault and die.\n"); + printf("The parent and child sprocs should be killed after the " + "grandchild sproc dies.\n"); + printf("Use 'ps' to make sure this is so.\n"); + fflush(stdout); + /* Force a segmentation fault */ + *p = 0; +} + +void NeverStops(void *unused) +{ + int i = 0; + + printf("The child sproc has pid %d.\n", getpid()); + printf("The child sproc won't stop on its own.\n"); + fflush(stdout); + + /* create the grandchild sproc */ + PR_CreateThread(PR_USER_THREAD, SegFault, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + while (1) { + i++; + } +} + +int main() +{ + int i= 0; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + printf("The parent sproc has pid %d.\n", getpid()); + printf("The parent sproc won't stop on its own.\n"); + fflush(stdout); + + /* create the child sproc */ + PR_CreateThread(PR_USER_THREAD, NeverStops, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + while (1) { + i++; + } + return 0; +} + +#endif /* IRIX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_p.c b/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_p.c new file mode 100644 index 00000000..e8ded66b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/sproc_p.c @@ -0,0 +1,101 @@ +/* -*- 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 ***** */ + +/* + * Test sproc_p.c + * + * The purpose of this test and the sproc_ch.c test is to test the shutdown + * of all the IRIX sprocs in a program when one of them dies due to an error. + * + * In this test, the parent sproc gets a segmentation fault and dies. + * The child sproc never stops on its own. You should use "ps" to see if + * the child sproc is killed after the parent dies. + */ + +#include "prinit.h" +#include + +#if !defined(IRIX) + +int main() +{ + printf("This test applies to IRIX only.\n"); + return 0; +} + +#else /* IRIX */ + +#include "prthread.h" +#include +#include + +void NeverStops(void *unused) +{ + int i = 0; + + printf("The child sproc has pid %d.\n", getpid()); + printf("The child sproc won't stop on its own.\n"); + fflush(stdout); + + /* I never stop */ + while (1) { + i++; + } +} + +int main() +{ + int *p = 0; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + printf("The parent sproc has pid %d.\n", getpid()); + printf("The parent sproc will first create a child sproc.\n"); + printf("Then the parent sproc will get a segmentation fault and die.\n"); + printf("The child sproc should be killed after the parent sproc dies.\n"); + printf("Use 'ps' to make sure this is so.\n"); + fflush(stdout); + + PR_CreateThread(PR_USER_THREAD, NeverStops, NULL, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + + /* Force a segmentation fault */ + *p = 0; + return 0; +} + +#endif /* IRIX */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/stack.c b/src/libs/xpcom18a4/nsprpub/pr/tests/stack.c new file mode 100644 index 00000000..c47cb71f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/stack.c @@ -0,0 +1,310 @@ +/* -*- 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 ***** */ + + +/* + * + * Test atomic stack operations + * + * Two stacks are created and threads add data items (each containing + * one of the first n integers) to the first stack, remove data items + * from the first stack and add them to the second stack. The primordial + * thread compares the sum of the first n integers to the sum of the + * integers in the data items in the second stack. The test succeeds if + * they are equal. + */ + +#include "nspr.h" +#include "plgetopt.h" + +typedef struct _DataRecord { + PRInt32 data; + PRStackElem link; +} DataRecord; + +#define RECORD_LINK_PTR(lp) ((DataRecord*) ((char*) (lp) - offsetof(DataRecord,link))) + +#define MAX_THREAD_CNT 100 +#define DEFAULT_THREAD_CNT 4 +#define DEFAULT_DATA_CNT 100 +#define DEFAULT_LOOP_CNT 10000 + +/* + * sum of the first n numbers using the formula n*(n+1)/2 + */ +#define SUM_OF_NUMBERS(n) ((n & 1) ? (((n + 1)/2) * n) : ((n/2) * (n+1))) + +typedef struct stack_data { + PRStack *list1; + PRStack *list2; + PRInt32 initial_data_value; + PRInt32 data_cnt; + PRInt32 loops; +} stack_data; + +static void stackop(void *arg); + +static int _debug_on; + +PRFileDesc *output; +PRFileDesc *errhandle; + +PRIntn main(PRIntn argc, char **argv) +{ + PRInt32 rv, cnt, sum; + DataRecord *Item; + PRStack *list1, *list2; + PRStackElem *node; + PRStatus rc; + + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; + PRInt32 data_cnt = DEFAULT_DATA_CNT; + PRInt32 loops = DEFAULT_LOOP_CNT; + PRThread **threads; + stack_data *thread_args; + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:l:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 't': /* thread count */ + thread_cnt = atoi(opt->value); + break; + case 'c': /* data count */ + data_cnt = atoi(opt->value); + break; + case 'l': /* loop count */ + loops = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_SetConcurrency(4); + + output = PR_GetSpecialFD(PR_StandardOutput); + errhandle = PR_GetSpecialFD(PR_StandardError); + list1 = PR_CreateStack("Stack_1"); + if (list1 == NULL) { + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", + PR_GetError()); + return 1; + } + + list2 = PR_CreateStack("Stack_2"); + if (list2 == NULL) { + PR_fprintf(errhandle, "PR_CreateStack failed - error %d\n", + PR_GetError()); + return 1; + } + + + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); + thread_args = (stack_data *) PR_CALLOC(sizeof(stack_data) * thread_cnt); + + if (_debug_on) + PR_fprintf(output,"%s: thread_cnt = %d data_cnt = %d\n", argv[0], + thread_cnt, data_cnt); + for(cnt = 0; cnt < thread_cnt; cnt++) { + PRThreadScope scope; + + thread_args[cnt].list1 = list1; + thread_args[cnt].list2 = list2; + thread_args[cnt].loops = loops; + thread_args[cnt].data_cnt = data_cnt; + thread_args[cnt].initial_data_value = 1 + cnt * data_cnt; + + if (cnt & 1) + scope = PR_GLOBAL_THREAD; + else + scope = PR_LOCAL_THREAD; + + + threads[cnt] = PR_CreateThread(PR_USER_THREAD, + stackop, &thread_args[cnt], + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + if (threads[cnt] == NULL) { + PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", + PR_GetError()); + PR_ProcessExit(2); + } + if (_debug_on) + PR_fprintf(output,"%s: created thread = 0x%x\n", argv[0], + threads[cnt]); + } + + for(cnt = 0; cnt < thread_cnt; cnt++) { + rc = PR_JoinThread(threads[cnt]); + PR_ASSERT(rc == PR_SUCCESS); + } + + node = PR_StackPop(list1); + /* + * list1 should be empty + */ + if (node != NULL) { + PR_fprintf(errhandle, "Error - Stack 1 not empty\n"); + PR_ASSERT(node == NULL); + PR_ProcessExit(4); + } + + cnt = data_cnt * thread_cnt; + sum = 0; + while (cnt-- > 0) { + node = PR_StackPop(list2); + /* + * There should be at least 'cnt' number of records + */ + if (node == NULL) { + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); + PR_ProcessExit(3); + } + Item = RECORD_LINK_PTR(node); + sum += Item->data; + } + node = PR_StackPop(list2); + /* + * there should be exactly 'cnt' number of records + */ + if (node != NULL) { + PR_fprintf(errhandle, "Error - Stack 2 not empty\n"); + PR_ASSERT(node == NULL); + PR_ProcessExit(4); + } + PR_DELETE(threads); + PR_DELETE(thread_args); + + PR_DestroyStack(list1); + PR_DestroyStack(list2); + + if (sum == SUM_OF_NUMBERS(data_cnt * thread_cnt)) { + PR_fprintf(output, "%s successful\n", argv[0]); + PR_fprintf(output, "\t\tsum = 0x%x, expected = 0x%x\n", sum, + SUM_OF_NUMBERS(thread_cnt * data_cnt)); + return 0; + } else { + PR_fprintf(output, "%s failed: sum = 0x%x, expected = 0x%x\n", + argv[0], sum, + SUM_OF_NUMBERS(data_cnt * thread_cnt)); + return 2; + } +} + +static void stackop(void *thread_arg) +{ + PRInt32 val, cnt, index, loops; + DataRecord *Items, *Item; + PRStack *list1, *list2; + PRStackElem *node; + stack_data *arg = (stack_data *) thread_arg; + + val = arg->initial_data_value; + cnt = arg->data_cnt; + loops = arg->loops; + list1 = arg->list1; + list2 = arg->list2; + + /* + * allocate memory for the data records + */ + Items = (DataRecord *) PR_CALLOC(sizeof(DataRecord) * cnt); + PR_ASSERT(Items != NULL); + index = 0; + + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] init_val = %d cnt = %d data1 = 0x%x datan = 0x%x\n", + PR_GetCurrentThread(), val, cnt, &Items[0], &Items[cnt-1]); + + + /* + * add the data records to list1 + */ + while (cnt-- > 0) { + Items[index].data = val++; + PR_StackPush(list1, &Items[index].link); + index++; + } + + /* + * pop data records from list1 and add them back to list1 + * generates contention for the stack accesses + */ + while (loops-- > 0) { + cnt = arg->data_cnt; + while (cnt-- > 0) { + node = PR_StackPop(list1); + if (node == NULL) { + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); + PR_ASSERT(node != NULL); + PR_ProcessExit(3); + } + PR_StackPush(list1, node); + } + } + /* + * remove the data records from list1 and add them to list2 + */ + cnt = arg->data_cnt; + while (cnt-- > 0) { + node = PR_StackPop(list1); + if (node == NULL) { + PR_fprintf(errhandle, "Error - PR_StackPop returned NULL\n"); + PR_ASSERT(node != NULL); + PR_ProcessExit(3); + } + PR_StackPush(list2, node); + } + if (_debug_on) + PR_fprintf(output, + "Thread[0x%x] init_val = %d cnt = %d exiting\n", + PR_GetCurrentThread(), val, cnt); + +} + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/stat.c b/src/libs/xpcom18a4/nsprpub/pr/tests/stat.c new file mode 100644 index 00000000..73803d05 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/stat.c @@ -0,0 +1,119 @@ +/* -*- 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 ***** */ + +/* + * Program to test different ways to get file info; right now it + * only works for solaris and OS/2. + * + */ +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#include +#include +#include + +#ifdef XP_OS2 +#include +#include +#include +#endif + +#define DEFAULT_COUNT 100000 +PRInt32 count; + +#ifndef XP_PC +char *filename = "/etc/passwd"; +#else +char *filename = "..\\stat.c"; +#endif + +static void statPRStat(void) +{ + PRFileInfo finfo; + PRInt32 index = count; + + for (;index--;) { + PR_GetFileInfo(filename, &finfo); + } +} + +static void statStat(void) +{ + struct stat finfo; + PRInt32 index = count; + + for (;index--;) { + stat(filename, &finfo); + } +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 1) { + count = atoi(argv[1]); + } else { + count = DEFAULT_COUNT; + } + + Measure(statPRStat, "time to call PR_GetFileInfo()"); + Measure(statStat, "time to call stat()"); + + PR_Cleanup(); +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/stdio.c b/src/libs/xpcom18a4/nsprpub/pr/tests/stdio.c new file mode 100644 index 00000000..d0d84e4e --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/stdio.c @@ -0,0 +1,83 @@ +/* -*- 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 ***** */ + +/* + * File: stdio.c + * Description: testing the "special" fds + * Modification History: + * 20-May-1997 AGarcia - Replace Test succeeded status with PASS. This is used by the + * regress tool parsing code. + ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to +** recognize the return code from tha main program. + */ + + +#include "prlog.h" +#include "prinit.h" +#include "prio.h" + +#include +#include + +static PRIntn PR_CALLBACK stdio(PRIntn argc, char **argv) +{ + PRInt32 rv; + + PRFileDesc *out = PR_GetSpecialFD(PR_StandardOutput); + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + + rv = PR_Write( + out, "This to standard out\n", + strlen("This to standard out\n")); + PR_ASSERT((PRInt32)strlen("This to standard out\n") == rv); + rv = PR_Write( + err, "This to standard err\n", + strlen("This to standard err\n")); + PR_ASSERT((PRInt32)strlen("This to standard err\n") == rv); + + return 0; + +} /* stdio */ + +int main(int argc, char **argv) +{ + PR_STDIO_INIT(); + return PR_Initialize(stdio, argc, argv, 0); +} /* main */ + + +/* stdio.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/str2addr.c b/src/libs/xpcom18a4/nsprpub/pr/tests/str2addr.c new file mode 100644 index 00000000..b1d4cf4a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/str2addr.c @@ -0,0 +1,82 @@ +/* -*- 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 ***** */ + +/* + * File: str2addr.c + * Description: a test for PR_StringToNetAddr + */ + +#include "nspr.h" + +#include +#include + +/* Address string to convert */ +#define DEFAULT_IPV4_ADDR_STR "207.200.73.41" + +/* Expected conversion result, in network byte order */ +static unsigned char default_ipv4_addr[] = {207, 200, 73, 41}; + +int main(int argc, char **argv) +{ + PRNetAddr addr; + const char *addrStr; + unsigned char *bytes; + int idx; + + addrStr = DEFAULT_IPV4_ADDR_STR; + if (PR_StringToNetAddr(addrStr, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_StringToNetAddr failed\n"); + exit(1); + } + if (addr.inet.family != PR_AF_INET) { + fprintf(stderr, "addr.inet.family should be %d but is %d\n", + PR_AF_INET, addr.inet.family); + exit(1); + } + bytes = (unsigned char *) &addr.inet.ip; + for (idx = 0; idx < 4; idx++) { + if (bytes[idx] != default_ipv4_addr[idx]) { + fprintf(stderr, "byte %d of IPv4 addr should be %d but is %d\n", + idx, default_ipv4_addr[idx], bytes[idx]); + exit(1); + } + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/strod.c b/src/libs/xpcom18a4/nsprpub/pr/tests/strod.c new file mode 100644 index 00000000..242617a7 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/strod.c @@ -0,0 +1,106 @@ +/* -*- 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 "prinit.h" +#include "prio.h" +#include "prprf.h" +#include "prdtoa.h" +#include "plgetopt.h" + +#include + +static void Help(void) +{ + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PR_fprintf(err, "Usage: /.strod [-n n] [-l n] [-h]\n"); + PR_fprintf(err, "\t-n n Number to translate (default: 1234567890123456789)\n"); + PR_fprintf(err, "\t-l n Times to loop the test (default: 1)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +static PRIntn PR_CALLBACK RealMain(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRIntn loops = 1; + PRFloat64 answer; + const char *number = "1234567890123456789"; + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + PLOptState *opt = PL_CreateOptState(argc, argv, "hc:l:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'n': /* number to translate */ + number = opt->value; + break; + case 'l': /* number of times to run the tests */ + loops = atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_fprintf(err, "Settings\n"); + PR_fprintf(err, "\tNumber to translate %s\n", number); + PR_fprintf(err, "\tLoops to run test: %d\n", loops); + + while (loops--) + { + answer = PR_strtod(number, NULL); + PR_fprintf(err, "Translation = %20.0f\n", answer); + } + return 0; +} + + + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/suspend.c b/src/libs/xpcom18a4/nsprpub/pr/tests/suspend.c new file mode 100644 index 00000000..44ba6f87 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/suspend.c @@ -0,0 +1,231 @@ +/* -*- 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 ***** */ + +#ifdef XP_BEOS +#include +int main() +{ + printf( "This test is not ported to the BeOS\n" ); + return 0; +} +#else + +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#if defined(XP_MAC) +#include "gcint.h" +#endif + +#include +#include +#include + +#ifdef XP_MAC +#include "gcint.h" +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +PRInt32 count; +PRInt32 alive; + +#define SLEEP_TIME 4 /* secs */ + +void PR_CALLBACK +Level_2_Thread(void *arg) +{ + PR_Sleep(PR_MillisecondsToInterval(4 * 1000)); + printf("Level_2_Thread[0x%lx] exiting\n",PR_GetCurrentThread()); + return; +} + +void PR_CALLBACK +Level_1_Thread(void *arg) +{ + PRUint32 tmp = (PRUint32)arg; + PRThreadScope scope = (PRThreadScope) tmp; + PRThread *thr; + + thr = PR_CreateThreadGCAble(PR_USER_THREAD, + Level_2_Thread, + NULL, + PR_PRIORITY_HIGH, + scope, + PR_JOINABLE_THREAD, + 0); + + if (!thr) { + printf("Could not create thread!\n"); + } else { + printf("Level_1_Thread[0x%lx] created %15s thread 0x%lx\n", + PR_GetCurrentThread(), + (scope == PR_GLOBAL_THREAD) ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD", + thr); + PR_JoinThread(thr); + } + PR_EnterMonitor(mon); + alive--; + PR_Notify(mon); + PR_ExitMonitor(mon); + printf("Thread[0x%lx] exiting\n",PR_GetCurrentThread()); +} + +static PRStatus PR_CALLBACK print_thread(PRThread *thread, int i, void *arg) +{ + PRInt32 words; + PRWord *registers; + + printf( + "\nprint_thread[0x%lx]: %-20s - i = %ld\n",thread, + (PR_GLOBAL_THREAD == PR_GetThreadScope(thread)) ? + "PR_GLOBAL_THREAD" : "PR_LOCAL_THREAD", i); + registers = PR_GetGCRegisters(thread, 0, (int *)&words); + printf("Regsters R0 = 0x%x R1 = 0x%x R2 = 0x%x R3 = 0x%x\n", + registers[0],registers[1],registers[2],registers[3]); + printf("Stack Pointer = 0x%lx\n", PR_GetSP(thread)); + return PR_SUCCESS; +} + +static void Level_0_Thread(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *thr; + PRThread *me = PR_GetCurrentThread(); + int n; + PRInt32 words; + PRWord *registers; + + alive = 0; + mon = PR_NewMonitor(); + + alive = count; + for (n=0; n 1) { + count = atoi(argv[1]); + } else { + count = 5; + } + + printf("\n\n%20s%30s\n\n"," ","Suspend_Resume Test"); + CreateThreadsUU(); + CreateThreadsUK(); + CreateThreadsKU(); + CreateThreadsKK(); + PR_SetConcurrency(2); + + printf("\n%20s%30s\n\n"," ","Added 2nd CPU\n"); + + CreateThreadsUK(); + CreateThreadsKK(); + CreateThreadsUU(); + CreateThreadsKU(); + PR_Cleanup(); +} + +#endif /* XP_BEOS */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/switch.c b/src/libs/xpcom18a4/nsprpub/pr/tests/switch.c new file mode 100644 index 00000000..2e42b793 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/switch.c @@ -0,0 +1,274 @@ +/* -*- 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 ***** */ + +/* +** File: switch.c +** Description: trying to time context switches +*/ + +#include "prinit.h" +#include "prcvar.h" +#include "prmem.h" +#include "prinrval.h" +#include "prlock.h" +#include "prlog.h" +#include "prthread.h" +#include "prprf.h" + +#include "plerror.h" +#include "plgetopt.h" + +#if defined(XP_MAC) +#include "pprio.h" +#define printf PR_LogPrint +#else +#include "private/pprio.h" +#endif + +#include + +#define INNER_LOOPS 100 +#define DEFAULT_LOOPS 100 +#define DEFAULT_THREADS 10 + +static PRFileDesc *debug_out = NULL; +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE; + +typedef struct Shared +{ + PRLock *ml; + PRCondVar *cv; + PRBool twiddle; + PRThread *thread; + struct Shared *next; +} Shared; + +static void Help(void) +{ + debug_out = PR_STDOUT; + + PR_fprintf( + debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n"); + PR_fprintf( + debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS); + PR_fprintf( + debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS); + PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n"); + PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n"); + PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n"); + PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n"); +} /* Help */ + +static void PR_CALLBACK Notified(void *arg) +{ + Shared *shared = (Shared*)arg; + PRStatus status = PR_SUCCESS; + while (PR_SUCCESS == status) + { + PR_Lock(shared->ml); + while (shared->twiddle && (PR_SUCCESS == status)) + status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); + if (verbosity) PR_fprintf(debug_out, "+"); + shared->twiddle = PR_TRUE; + shared->next->twiddle = PR_FALSE; + PR_NotifyCondVar(shared->next->cv); + PR_Unlock(shared->ml); + } +} /* Notified */ + +static Shared home; +PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv) +{ + PLOptStatus os; + PRStatus status; + PRBool help = PR_FALSE; + PRUintn concurrency = 1; + Shared *shared, *link; + PRIntervalTime timein, timeout; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRUintn thread_count, inner_count, loop_count, average; + PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'v': /* verbose mode */ + verbosity = PR_TRUE; + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + loop_limit = atoi(opt->value); + break; + case 't': /* thread limit */ + thread_limit = atoi(opt->value); + break; + case 'C': /* Concurrency limit */ + concurrency = atoi(opt->value); + break; + case 'G': /* global threads only */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'h': /* help message */ + Help(); + help = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (help) return -1; + + if (PR_TRUE == debug_mode) + { + debug_out = PR_STDOUT; + PR_fprintf(debug_out, "Test parameters\n"); + PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit); + PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit); + PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency); + PR_fprintf( + debug_out, "\tThread type: %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + } + + PR_SetConcurrency(concurrency); + + link = &home; + home.ml = PR_NewLock(); + home.cv = PR_NewCondVar(home.ml); + home.twiddle = PR_FALSE; + home.next = NULL; + + timeout = 0; + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + shared = PR_NEWZAP(Shared); + + shared->ml = home.ml; + shared->cv = PR_NewCondVar(home.ml); + shared->twiddle = PR_TRUE; + shared->next = link; + link = shared; + + shared->thread = PR_CreateThread( + PR_USER_THREAD, Notified, shared, + PR_PRIORITY_HIGH, thread_scope, + PR_JOINABLE_THREAD, 0); + PR_ASSERT(shared->thread != NULL); + if (NULL == shared->thread) + failed = PR_TRUE; + } + + for (loop_count = 1; loop_count <= loop_limit; ++loop_count) + { + timein = PR_IntervalNow(); + for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count) + { + PR_Lock(home.ml); + home.twiddle = PR_TRUE; + shared->twiddle = PR_FALSE; + PR_NotifyCondVar(shared->cv); + while (home.twiddle) + { + status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT); + if (PR_FAILURE == status) + failed = PR_TRUE; + } + PR_Unlock(home.ml); + } + timeout += (PR_IntervalNow() - timein); + } + + if (debug_mode) + { + average = PR_IntervalToMicroseconds(timeout) + / (INNER_LOOPS * loop_limit * thread_count); + PR_fprintf( + debug_out, "Average switch times %d usecs for %d threads\n", + average, thread_limit); + } + + link = shared; + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + if (&home == link) break; + status = PR_Interrupt(link->thread); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to interrupt"); + } + link = link->next; + } + + for (thread_count = 1; thread_count <= thread_limit; ++thread_count) + { + link = shared->next; + status = PR_JoinThread(shared->thread); + if (PR_SUCCESS != status) + { + failed = PR_TRUE; + if (debug_mode) + PL_FPrintError(debug_out, "Failed to join"); + } + PR_DestroyCondVar(shared->cv); + PR_DELETE(shared); + if (&home == link) break; + shared = link; + } + PR_DestroyCondVar(home.cv); + PR_DestroyLock(home.ml); + + PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n")); + return ((failed) ? 1 : 0); +} /* Switch */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn result; + PR_STDIO_INIT(); + result = PR_Initialize(Switch, argc, argv, 0); + return result; +} /* main */ + +/* switch.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/system.c b/src/libs/xpcom18a4/nsprpub/pr/tests/system.c new file mode 100644 index 00000000..b4a89a0a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/system.c @@ -0,0 +1,82 @@ +/* -*- 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 "prio.h" +#include "prmem.h" +#include "prprf.h" +#include "prsystem.h" + +#include "plerror.h" + +static char *tag[] = +{ + "PR_SI_HOSTNAME", + "PR_SI_SYSNAME", + "PR_SI_RELEASE", + "PR_SI_ARCHITECTURE" +}; + +static PRSysInfo Incr(PRSysInfo *cmd) +{ + PRIntn tmp = (PRIntn)*cmd + 1; + *cmd = (PRSysInfo)tmp; + return (PRSysInfo)tmp; +} /* Incr */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRStatus rv; + PRSysInfo cmd; + PRFileDesc *output = PR_GetSpecialFD(PR_StandardOutput); + + char *info = (char*)PR_Calloc(SYS_INFO_BUFFER_LENGTH, 1); + for (cmd = PR_SI_HOSTNAME; cmd <= PR_SI_ARCHITECTURE; Incr(&cmd)) + { + rv = PR_GetSystemInfo(cmd, info, SYS_INFO_BUFFER_LENGTH); + if (PR_SUCCESS == rv) PR_fprintf(output, "%s: %s\n", tag[cmd], info); + else PL_FPrintError(output, tag[cmd]); + } + PR_DELETE(info); + + PR_fprintf(output, "Host page size is %d\n", PR_GetPageSize()); + PR_fprintf(output, "Page shift is %d\n", PR_GetPageShift()); + PR_fprintf(output, "Number of processors is: %d\n", PR_GetNumberOfProcessors()); + + return 0; +} /* main */ + +/* system.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/testbit.c b/src/libs/xpcom18a4/nsprpub/pr/tests/testbit.c new file mode 100644 index 00000000..1ad0b8f4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/testbit.c @@ -0,0 +1,129 @@ +/* -*- 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 ***** */ + +/* +** File: lazyinit.c +** Description: Test the functions and macros declared in prbit.h +** +*/ + +#include "nspr.h" + +#define ErrorReport(x) { printf((x)); failed = 1; } + +prbitmap_t myMap[512/32] = { 0 }; + +PRInt32 rc; +PRInt32 i; +PRIntn failed = 0; + +PRIntn main(PRIntn argc, char **argv ) +{ + /* + ** Test bitmap things. + */ + if ( PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 0.0: Failed\n"); + + if ( PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 0.1: Failed\n"); + + if ( PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 0.2: Failed\n"); + + if ( PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 0.3: Failed\n"); + + + PR_SET_BIT( myMap, 0 ); + if ( !PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 1.0: Failed\n"); + + PR_CLEAR_BIT( myMap, 0 ); + if ( PR_TEST_BIT( myMap, 0 )) + ErrorReport("Test 1.0.1: Failed\n"); + + PR_SET_BIT( myMap, 31 ); + if ( !PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 1.1: Failed\n"); + + PR_CLEAR_BIT( myMap, 31 ); + if ( PR_TEST_BIT( myMap, 31 )) + ErrorReport("Test 1.1.1: Failed\n"); + + PR_SET_BIT( myMap, 128 ); + if ( !PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 1.2: Failed\n"); + + PR_CLEAR_BIT( myMap, 128 ); + if ( PR_TEST_BIT( myMap, 128 )) + ErrorReport("Test 1.2.1: Failed\n"); + + PR_SET_BIT( myMap, 129 ); + if ( !PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 1.3: Failed\n"); + + PR_CLEAR_BIT( myMap, 129 ); + if ( PR_TEST_BIT( myMap, 129 )) + ErrorReport("Test 1.3.1: Failed\n"); + + + /* + ** Test Ceiling and Floor functions and macros + */ + if ((rc = PR_CeilingLog2(32)) != 5 ) + ErrorReport("Test 10.0: Failed\n"); + + if ((rc = PR_FloorLog2(32)) != 5 ) + ErrorReport("Test 10.1: Failed\n"); + + + /* + ** Evaluate results and exit + */ + if (failed) + { + printf("FAILED\n"); + return(1); + } + else + { + printf("PASSED\n"); + return(0); + } +} /* end main() */ +/* end testbit.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/testfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/testfile.c new file mode 100644 index 00000000..4d2228e8 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/testfile.c @@ -0,0 +1,1008 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nspr.h" +#include "prpriv.h" + +#include +#include +#include +#ifdef WIN32 +#include +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#if defined(XP_OS2) +#define INCL_DOSFILEMGR +#include +#ifdef XP_OS2_EMX +#include +#include +#endif /* XP_OS2_EMX */ +#endif /* XP_OS2 */ + +static int _debug_on = 0; + +#ifdef XP_MAC +#include "prlog.h" +#include "primpl.h" +#define printf PR_LogPrint +#define setbuf(x,y) +extern void SetupMacPrintfLog(char *logFile); +#endif + +#ifdef XP_WIN +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +PRLock *lock; +PRMonitor *mon; +PRInt32 count; +int thread_count; + +#ifdef WIN16 +#define BUF_DATA_SIZE 256 * 120 +#else +#define BUF_DATA_SIZE 256 * 1024 +#endif + +#define NUM_RDWR_THREADS 10 +#define NUM_DIRTEST_THREADS 4 +#define CHUNK_SIZE 512 + +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +typedef struct File_Rdwr_Param { + char *pathname; + char *buf; + int offset; + int len; +} File_Rdwr_Param; + +#ifdef XP_PC +#ifdef XP_OS2 +char *TEST_DIR = "prdir"; +#else +char *TEST_DIR = "C:\\temp\\prdir"; +#endif +char *FILE_NAME = "pr_testfile"; +char *HIDDEN_FILE_NAME = "hidden_pr_testfile"; +#else +char *TEST_DIR = "/tmp/testfile_dir"; +char *FILE_NAME = "pr_testfile"; +char *HIDDEN_FILE_NAME = ".hidden_pr_testfile"; +#endif +buffer *in_buf, *out_buf; +char pathname[256], renamename[256]; +#define TMPDIR_LEN 64 +char testdir[TMPDIR_LEN]; +static PRInt32 PR_CALLBACK DirTest(void *argunused); +PRInt32 dirtest_failed = 0; + +PRThread* create_new_thread(PRThreadType type, + void (*start)(void *arg), + void *arg, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state, + PRUint32 stackSize, PRInt32 index) +{ +PRInt32 native_thread = 0; + + PR_ASSERT(state == PR_UNJOINABLE_THREAD); + +#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) || defined(XP_OS2) + + switch(index % 4) { + case 0: + scope = (PR_LOCAL_THREAD); + break; + case 1: + scope = (PR_GLOBAL_THREAD); + break; + case 2: + scope = (PR_GLOBAL_BOUND_THREAD); + break; + case 3: + native_thread = 1; + break; + default: + PR_ASSERT(!"Invalid scope"); + break; + } + if (native_thread) { +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) + pthread_t tid; + if (!pthread_create(&tid, NULL, start, arg)) + return((PRThread *) tid); + else + return (NULL); +#elif defined(XP_OS2) + TID tid; + + tid = (TID)_beginthread((void(* _Optlink)(void*))start, + NULL, 32768, arg); + if (tid == -1) { + printf("_beginthread failed. errno %d\n", errno); + return (NULL); + } + else + return((PRThread *) tid); +#else + HANDLE thandle; + unsigned tid; + + thandle = (HANDLE) _beginthreadex( + NULL, + stackSize, + (unsigned (__stdcall *)(void *))start, + arg, + 0, + &tid); + return((PRThread *) thandle); +#endif + } else { + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); + } +#else + return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize)); +#endif +} + +static void PR_CALLBACK File_Write(void *arg) +{ +PRFileDesc *fd_file; +File_Rdwr_Param *fp = (File_Rdwr_Param *) arg; +char *name, *buf; +int offset, len; + + setbuf(stdout, NULL); + name = fp->pathname; + buf = fp->buf; + offset = fp->offset; + len = fp->len; + + fd_file = PR_Open(name, PR_RDWR | PR_CREATE_FILE, 0777); + if (fd_file == NULL) { + printf("testfile failed to create/open file %s\n",name); + return; + } + if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) { + printf("testfile failed to seek in file %s\n",name); + return; + } + if ((PR_Write(fd_file, buf, len)) < 0) { + printf("testfile failed to write to file %s\n",name); + return; + } + DPRINTF(("Write out_buf[0] = 0x%x\n",(*((int *) buf)))); + PR_Close(fd_file); + PR_DELETE(fp); + + PR_EnterMonitor(mon); + --thread_count; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void PR_CALLBACK File_Read(void *arg) +{ +PRFileDesc *fd_file; +File_Rdwr_Param *fp = (File_Rdwr_Param *) arg; +char *name, *buf; +int offset, len; + + setbuf(stdout, NULL); + name = fp->pathname; + buf = fp->buf; + offset = fp->offset; + len = fp->len; + + fd_file = PR_Open(name, PR_RDONLY, 0); + if (fd_file == NULL) { + printf("testfile failed to open file %s\n",name); + return; + } + if (PR_Seek(fd_file, offset, PR_SEEK_SET) < 0) { + printf("testfile failed to seek in file %s\n",name); + return; + } + if ((PR_Read(fd_file, buf, len)) < 0) { + printf("testfile failed to read to file %s\n",name); + return; + } + DPRINTF(("Read in_buf[0] = 0x%x\n",(*((int *) buf)))); + PR_Close(fd_file); + PR_DELETE(fp); + + PR_EnterMonitor(mon); + --thread_count; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + + +static PRInt32 Misc_File_Tests(char *pathname) +{ +PRFileDesc *fd_file; +int len, rv = 0; +PRFileInfo file_info, file_info1; +char tmpname[1024]; + + setbuf(stdout, NULL); + /* + * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access + */ + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf("testfile failed to create/open file %s\n",pathname); + return -1; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_EXISTS) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_WRITE_OK) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_Access(pathname, PR_ACCESS_READ_OK) != 0) { + printf("testfile PR_Access failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + + + if (PR_GetFileInfo(pathname, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (file_info.type != PR_FILE_FILE) { + printf( + "testfile: Error - PR_GetFileInfo returned incorrect type for file %s\n", + pathname); + rv = -1; + goto cleanup; + } + if (file_info.size != 0) { + printf( + "testfile PR_GetFileInfo returned incorrect size (%d should be 0) for file %s\n", + file_info.size, pathname); + rv = -1; + goto cleanup; + } + file_info1 = file_info; + + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != 0) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + 0, len); + rv = -1; + goto cleanup; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + goto cleanup; + } + if (LL_NE(file_info.creationTime , file_info1.creationTime)) { + printf( + "testfile PR_GetFileInfo returned incorrect status-change time: %s\n", + pathname); + printf("ft = %lld, ft1 = %lld\n",file_info.creationTime, + file_info1.creationTime); + rv = -1; + goto cleanup; + } + len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE); + if (len < 0) { + printf("testfile failed to write to file %s\n",pathname); + rv = -1; + goto cleanup; + } + if (PR_GetOpenFileInfo(fd_file, &file_info) < 0) { + printf("testfile PR_GetFileInfo failed on file %s\n",pathname); + goto cleanup; + } + if (file_info.size != CHUNK_SIZE) { + printf( + "testfile PR_GetFileInfo returned incorrect size (%d should be %d) for file %s\n", + file_info.size, CHUNK_SIZE, pathname); + rv = -1; + goto cleanup; + } + if (LL_CMP(file_info.modifyTime, < , file_info1.modifyTime)) { + printf( + "testfile PR_GetFileInfo returned incorrect modify time: %s\n", + pathname); + printf("ft = %lld, ft1 = %lld\n",file_info.modifyTime, + file_info1.modifyTime); + rv = -1; + goto cleanup; + } + + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != 0) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + 0, len); + rv = -1; + goto cleanup; + } + + PR_Seek(fd_file, 0, PR_SEEK_SET); + len = PR_Available(fd_file); + if (len < 0) { + printf("testfile PR_Available failed on file %s\n",pathname); + rv = -1; + goto cleanup; + } else if (len != CHUNK_SIZE) { + printf( + "testfile PR_Available failed: expected/returned = %d/%d bytes\n", + CHUNK_SIZE, len); + rv = -1; + goto cleanup; + } + PR_Close(fd_file); + + strcpy(tmpname,pathname); + strcat(tmpname,".RENAMED"); + if (PR_FAILURE == PR_Rename(pathname, tmpname)) { + printf("testfile failed to rename file %s\n",pathname); + rv = -1; + goto cleanup; + } + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + len = PR_Write(fd_file, out_buf->data, CHUNK_SIZE); + PR_Close(fd_file); + if (PR_SUCCESS == PR_Rename(pathname, tmpname)) { + printf("testfile renamed to existing file %s\n",pathname); + } + + if ((PR_Delete(tmpname)) < 0) { + printf("testfile failed to unlink file %s\n",tmpname); + rv = -1; + } + +cleanup: + if ((PR_Delete(pathname)) < 0) { + printf("testfile failed to unlink file %s\n",pathname); + rv = -1; + } + return rv; +} + + +static PRInt32 PR_CALLBACK FileTest(void) +{ +PRDir *fd_dir; +int i, offset, len, rv = 0; +PRThread *t; +PRThreadScope scope; +File_Rdwr_Param *fparamp; + + /* + * Create Test dir + */ + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf("testfile failed to create dir %s\n",TEST_DIR); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf("testfile failed to open dir %s\n",TEST_DIR); + rv = -1; + goto cleanup; + } + + PR_CloseDir(fd_dir); + + strcat(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + printf( + "testfile failed to alloc buffer struct\n"); + rv = -1; + goto cleanup; + } + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + printf( + "testfile failed to alloc buffer struct\n"); + rv = -1; + goto cleanup; + } + + /* + * Start a bunch of writer threads + */ + offset = 0; + len = CHUNK_SIZE; + PR_EnterMonitor(mon); + for (i = 0; i < NUM_RDWR_THREADS; i++) { + fparamp = PR_NEW(File_Rdwr_Param); + if (fparamp == NULL) { + printf( + "testfile failed to alloc File_Rdwr_Param struct\n"); + rv = -1; + goto cleanup; + } + fparamp->pathname = pathname; + fparamp->buf = out_buf->data + offset; + fparamp->offset = offset; + fparamp->len = len; + memset(fparamp->buf, i, len); + + t = create_new_thread(PR_USER_THREAD, + File_Write, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0, i); + offset += len; + } + thread_count = i; + /* Wait for writer threads to exit */ + while (thread_count) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + + /* + * Start a bunch of reader threads + */ + offset = 0; + len = CHUNK_SIZE; + PR_EnterMonitor(mon); + for (i = 0; i < NUM_RDWR_THREADS; i++) { + fparamp = PR_NEW(File_Rdwr_Param); + if (fparamp == NULL) { + printf( + "testfile failed to alloc File_Rdwr_Param struct\n"); + rv = -1; + goto cleanup; + } + fparamp->pathname = pathname; + fparamp->buf = in_buf->data + offset; + fparamp->offset = offset; + fparamp->len = len; + + t = create_new_thread(PR_USER_THREAD, + File_Read, (void *)fparamp, + PR_PRIORITY_NORMAL, + scope, + PR_UNJOINABLE_THREAD, + 0, i); + offset += len; + if ((offset + len) > BUF_DATA_SIZE) + break; + } + thread_count = i; + + /* Wait for reader threads to exit */ + while (thread_count) { + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + } + PR_ExitMonitor(mon); + + if (memcmp(in_buf->data, out_buf->data, offset) != 0) { + printf("File Test failed: file data corrupted\n"); + rv = -1; + goto cleanup; + } + + if ((PR_Delete(pathname)) < 0) { + printf("testfile failed to unlink file %s\n",pathname); + rv = -1; + goto cleanup; + } + + /* + * Test PR_Available, PR_Seek, PR_GetFileInfo, PR_Rename, PR_Access + */ + if (Misc_File_Tests(pathname) < 0) { + rv = -1; + } + +cleanup: + if ((PR_RmDir(TEST_DIR)) < 0) { + printf("testfile failed to rmdir %s\n", TEST_DIR); + rv = -1; + } + return rv; +} + +struct dirtest_arg { + PRMonitor *mon; + PRInt32 done; +}; + +static PRInt32 RunDirTest(void) +{ +int i; +PRThread *t; +PRMonitor *mon; +struct dirtest_arg thrarg; + + mon = PR_NewMonitor(); + if (!mon) { + printf("RunDirTest: Error - failed to create monitor\n"); + dirtest_failed = 1; + return -1; + } + thrarg.mon = mon; + + for (i = 0; i < NUM_DIRTEST_THREADS; i++) { + + thrarg.done= 0; + t = create_new_thread(PR_USER_THREAD, + DirTest, &thrarg, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_UNJOINABLE_THREAD, + 0, i); + if (!t) { + printf("RunDirTest: Error - failed to create thread\n"); + dirtest_failed = 1; + return -1; + } + PR_EnterMonitor(mon); + while (!thrarg.done) + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + PR_ExitMonitor(mon); + + } + PR_DestroyMonitor(mon); + return 0; +} + +static PRInt32 PR_CALLBACK DirTest(void *arg) +{ +struct dirtest_arg *tinfo = (struct dirtest_arg *) arg; +PRFileDesc *fd_file; +PRDir *fd_dir; +int i; +int path_len; +PRDirEntry *dirEntry; +PRFileInfo info; +PRInt32 num_files = 0; +#if defined(XP_PC) && defined(WIN32) +HANDLE hfile; +#endif + +#define FILES_IN_DIR 20 + + /* + * Create Test dir + */ + DPRINTF(("Creating test dir %s\n",TEST_DIR)); + if ((PR_MkDir(TEST_DIR, 0777)) < 0) { + printf( + "testfile failed to create dir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to open dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + path_len = strlen(pathname); + + for (i = 0; i < FILES_IN_DIR; i++) { + + sprintf(pathname + path_len,"%d%s",i,""); + + DPRINTF(("Creating test file %s\n",pathname)); + + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf( + "testfile failed to create/open file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_Close(fd_file); + } +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + /* + * Create a hidden file - a platform-dependent operation + */ + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, HIDDEN_FILE_NAME); +#if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_BEOS) + DPRINTF(("Creating hidden test file %s\n",pathname)); + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, 0777); + + if (fd_file == NULL) { + printf( + "testfile failed to create/open hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + +#if defined(XP_MAC) + { +#include + + OSErr err; + FCBPBRec fcbpb; + CInfoPBRec pb; + Str255 pascalMacPath; + + fcbpb.ioNamePtr = pascalMacPath; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd_file->secret->md.osfd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + pb.hFileInfo.ioFlFndrInfo.fdFlags |= fInvisible; + + err = PBSetCatInfoSync(&pb); + if (err != noErr) { + PR_Close(fd_file); + return -1; + } + + } +#endif + + PR_Close(fd_file); + + +#elif defined(XP_PC) && defined(WIN32) + DPRINTF(("Creating hidden test file %s\n",pathname)); + hfile = CreateFile(pathname, GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL, + CREATE_NEW, + FILE_ATTRIBUTE_HIDDEN, + NULL); + if (hfile == INVALID_HANDLE_VALUE) { + printf("testfile failed to create/open hidden file %s [0, %d]\n", + pathname, GetLastError()); + return -1; + } + CloseHandle(hfile); + +#elif defined(OS2) + DPRINTF(("Creating hidden test file %s\n",pathname)); + fd_file = PR_Open(pathname, PR_RDWR | PR_CREATE_FILE, (int)FILE_HIDDEN); + + if (fd_file == NULL) { + printf("testfile failed to create/open hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_Close(fd_file); +#endif /* XP _UNIX || XP_MAC*/ + +#endif /* XP_UNIX || XP_MAC ||(XP_PC && WIN32) */ + + + if (PR_FAILURE == PR_CloseDir(fd_dir)) + { + printf( + "testfile failed to close dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + /* + * List all files, including hidden files + */ + DPRINTF(("Listing all files in directory %s\n",TEST_DIR)); +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + num_files = FILES_IN_DIR + 1; +#else + num_files = FILES_IN_DIR; +#endif + while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_BOTH)) != NULL) { + num_files--; + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, dirEntry->name); + DPRINTF(("\t%s\n",dirEntry->name)); + + if ((PR_GetFileInfo(pathname, &info)) < 0) { + printf( + "testfile failed to GetFileInfo file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (info.type != PR_FILE_FILE) { + printf( + "testfile incorrect fileinfo for file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + } + if (num_files != 0) + { + printf( + "testfile failed to find all files in directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + PR_CloseDir(fd_dir); + +#if defined(XP_UNIX) || defined(XP_MAC) || (defined(XP_PC) && defined(WIN32)) || defined(XP_OS2) || defined(XP_BEOS) + + /* + * List all files, except hidden files + */ + + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen dirctory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + DPRINTF(("Listing non-hidden files in directory %s\n",TEST_DIR)); + while ((dirEntry = PR_ReadDir(fd_dir, PR_SKIP_HIDDEN)) != NULL) { + DPRINTF(("\t%s\n",dirEntry->name)); + if (!strcmp(HIDDEN_FILE_NAME, dirEntry->name)) { + printf("testfile found hidden file %s\n", pathname); + return -1; + } + + } + /* + * Delete hidden file + */ + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, HIDDEN_FILE_NAME); + if (PR_FAILURE == PR_Delete(pathname)) { + printf( + "testfile failed to delete hidden file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + + PR_CloseDir(fd_dir); +#endif /* XP_UNIX || XP_MAC || (XP_PC && WIN32) */ + + strcpy(renamename, TEST_DIR); + strcat(renamename, ".RENAMED"); + if (PR_FAILURE == PR_Rename(TEST_DIR, renamename)) { + printf( + "testfile failed to rename directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (PR_FAILURE == PR_MkDir(TEST_DIR, 0777)) { + printf( + "testfile failed to recreate dir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + if (PR_SUCCESS == PR_Rename(renamename, TEST_DIR)) { + printf( + "testfile renamed directory to existing name %s\n", + renamename); + return -1; + } + + if (PR_FAILURE == PR_RmDir(TEST_DIR)) { + printf( + "testfile failed to rmdir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + if (PR_FAILURE == PR_Rename(renamename, TEST_DIR)) { + printf( + "testfile failed to rename directory %s [%d, %d]\n", + renamename, PR_GetError(), PR_GetOSError()); + return -1; + } + fd_dir = PR_OpenDir(TEST_DIR); + if (fd_dir == NULL) { + printf( + "testfile failed to reopen directory %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + + strcpy(pathname, TEST_DIR); + strcat(pathname, "/"); + strcat(pathname, FILE_NAME); + path_len = strlen(pathname); + + for (i = 0; i < FILES_IN_DIR; i++) { + + sprintf(pathname + path_len,"%d%s",i,""); + + if (PR_FAILURE == PR_Delete(pathname)) { + printf( + "testfile failed to delete file %s [%d, %d]\n", + pathname, PR_GetError(), PR_GetOSError()); + return -1; + } + } + + PR_CloseDir(fd_dir); + + if (PR_FAILURE == PR_RmDir(TEST_DIR)) { + printf( + "testfile failed to rmdir %s [%d, %d]\n", + TEST_DIR, PR_GetError(), PR_GetOSError()); + return -1; + } + PR_EnterMonitor(tinfo->mon); + tinfo->done = 1; + PR_Notify(tinfo->mon); + PR_ExitMonitor(tinfo->mon); + + return 0; +} +/************************************************************************/ + +/* + * Test file and directory NSPR APIs + */ + +int main(int argc, char **argv) +{ +#ifdef WIN32 + PRUint32 len; +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + int opt; + extern char *optarg; + extern int optind; +#endif +#if defined(XP_UNIX) || defined(XP_OS2_EMX) + while ((opt = getopt(argc, argv, "d")) != EOF) { + switch(opt) { + case 'd': + _debug_on = 1; + break; + default: + break; + } + } +#endif + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("testfile.log"); +#endif + + mon = PR_NewMonitor(); + if (mon == NULL) { + printf("testfile: PR_NewMonitor failed\n"); + exit(2); + } +#ifdef WIN32 + len = GetTempPath(TMPDIR_LEN, testdir); + if ((len > 0) && (len < (TMPDIR_LEN - 6))) { + /* + * enough space for prdir + */ + strcpy((testdir + len),"prdir"); + TEST_DIR = testdir; + printf("TEST_DIR = %s\n",TEST_DIR); + } + +#endif + + if (FileTest() < 0) { + printf("File Test failed\n"); + exit(2); + } + printf("File Test passed\n"); + if ((RunDirTest() < 0) || dirtest_failed) { + printf("Dir Test failed\n"); + exit(2); + } + printf("Dir Test passed\n"); + + PR_DestroyMonitor(mon); + PR_Cleanup(); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/threads.c b/src/libs/xpcom18a4/nsprpub/pr/tests/threads.c new file mode 100644 index 00000000..e1d188d4 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/threads.c @@ -0,0 +1,249 @@ +/* -*- 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 "nspr.h" +#include "prinrval.h" +#include "plgetopt.h" +#include "pprthred.h" +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + +PRMonitor *mon; +PRInt32 count, iterations, alive; + +PRBool debug_mode = PR_FALSE, passed = PR_TRUE; + +void +PR_CALLBACK +ReallyDumbThread(void *arg) +{ + return; +} + +void +PR_CALLBACK +DumbThread(void *arg) +{ + PRInt32 tmp = (PRInt32)arg; + PRThreadScope scope = (PRThreadScope)tmp; + PRThread *thr; + + thr = PR_CreateThread(PR_USER_THREAD, + ReallyDumbThread, + NULL, + PR_PRIORITY_NORMAL, + scope, + PR_JOINABLE_THREAD, + 0); + + if (!thr) { + if (debug_mode) { + printf("Could not create really dumb thread (%d, %d)!\n", + PR_GetError(), PR_GetOSError()); + } + passed = PR_FALSE; + } else { + PR_JoinThread(thr); + } + PR_EnterMonitor(mon); + alive--; + PR_Notify(mon); + PR_ExitMonitor(mon); +} + +static void CreateThreads(PRThreadScope scope1, PRThreadScope scope2) +{ + PRThread *thr; + int n; + + alive = 0; + mon = PR_NewMonitor(); + + alive = count; + for (n=0; noption) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'c': /* loop counter */ + count = atoi(opt->value); + break; + case 'i': /* loop counter */ + iterations = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + +#ifdef XP_MAC + SetupMacPrintfLog("threads.log"); + count = 10; + iterations = 10; + debug_mode = PR_TRUE; +#else + if (0 == count) count = 50; + if (0 == iterations) iterations = 10; + +#endif + + if (debug_mode) + { + printf("\ +** Tests lots of thread creations. \n\ +** Create %ld native threads %ld times. \n\ +** Create %ld user threads %ld times \n", iterations,count,iterations,count); + } + + for (index=0; index +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static int server_port = -1; +static char *program_name = NULL; + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */ + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 10 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define TCP_SERVER_PORT 10000 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; + +int failed_already=0; + +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + +PRNetAddr tcp_server_addr, udp_server_addr; + +typedef struct Client_Param { + PRNetAddr server_addr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *exit_counter; /* counter to decrement, before exit */ + PRInt32 datalen; +} Client_Param; + +/* + * readn + * read data from sockfd into buf + */ +static PRInt32 +readn(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Recv(sockfd, buf + offset, rem, 0, + timeout); + DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes < 0) { + return -1; + } + } + return len; +} + +/* + * writen + * write data from buf to sockfd + */ +static PRInt32 +writen(PRFileDesc *sockfd, char *buf, int len) +{ + int rem; + int bytes; + int offset = 0; + + for (rem=len; rem; offset += bytes, rem -= bytes) { + DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n", + PR_GetCurrentThread(), rem)); + bytes = PR_Send(sockfd, buf + offset, rem, 0, + PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n", + PR_GetCurrentThread(), bytes)); + if (bytes <= 0) + return -1; + } + return len; +} + +/* + * TCP_Client + * Client job + * Connect to the server at the address specified in the argument. + * Fill in a buffer, write data to server, read it back and check + * for data corruption. + * Close the socket for server connection + */ +static void PR_CALLBACK +TCP_Client(void *arg) +{ + Client_Param *cp = (Client_Param *) arg; + PRFileDesc *sockfd; + buffer *in_buf, *out_buf; + union PRNetAddr netaddr; + PRInt32 bytes, i, j; + + + DPRINTF(("TCP client started\n")); + bytes = cp->datalen; + out_buf = PR_NEW(buffer); + if (out_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name); + failed_already=1; + return; + } + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n", program_name); + failed_already=1; + return; + } + netaddr.inet.family = cp->server_addr.inet.family; + netaddr.inet.port = cp->server_addr.inet.port; + netaddr.inet.ip = cp->server_addr.inet.ip; + + for (i = 0; i < num_tcp_connections_per_client; i++) { + if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) { + fprintf(stderr,"%s: PR_OpenTCPSocket failed\n", program_name); + failed_already=1; + return; + } + + DPRINTF(("TCP client connecting to server:%d\n", server_port)); + if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0){ + fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n", + PR_GetError(), PR_GetOSError()); + failed_already=1; + return; + } + for (j = 0; j < num_tcp_mesgs_per_connection; j++) { + /* + * fill in random data + */ + memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes); + /* + * write to server + */ + if (writen(sockfd, out_buf->data, bytes) < bytes) { + fprintf(stderr,"%s: ERROR - TCP_Client:writen\n", program_name); + failed_already=1; + return; + } + /* + DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n", + PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data)))); + */ + if (readn(sockfd, in_buf->data, bytes) < bytes) { + fprintf(stderr,"%s: ERROR - TCP_Client:readn\n", program_name); + failed_already=1; + return; + } + /* + * verify the data read + */ + if (memcmp(in_buf->data, out_buf->data, bytes) != 0) { + fprintf(stderr,"%s: ERROR - data corruption\n", program_name); + failed_already=1; + return; + } + } + /* + * shutdown reads and writes + */ + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name); + failed_already=1; + } + PR_Close(sockfd); + } + + PR_DELETE(out_buf); + PR_DELETE(in_buf); + + /* + * Decrement exit_counter and notify parent thread + */ + + PR_EnterMonitor(cp->exit_mon); + --(*cp->exit_counter); + PR_Notify(cp->exit_mon); + PR_ExitMonitor(cp->exit_mon); + DPRINTF(("TCP_Client exiting\n")); +} + +/* + * TCP_Socket_Client_Server_Test - concurrent server test + * + * Each client connects to the server and sends a chunk of data + * For each connection, server reads the data + * from the client and sends it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * + */ + +static PRInt32 +TCP_Socket_Client_Server_Test(void) +{ + int i; + Client_Param *cparamp; + PRMonitor *mon2; + PRInt32 datalen; + PRInt32 connections = 0; + PRThread *thr; + + datalen = tcp_mesg_size; + connections = 0; + + mon2 = PR_NewMonitor(); + if (mon2 == NULL) { + fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name); + failed_already=1; + return -1; + } + + /* + * Start client jobs + */ + cparamp = PR_NEW(Client_Param); + if (cparamp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + return -1; + } + cparamp->server_addr.inet.family = PR_AF_INET; + cparamp->server_addr.inet.port = PR_htons(server_port); + cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); + cparamp->exit_mon = mon2; + cparamp->exit_counter = &connections; + cparamp->datalen = datalen; + for (i = 0; i < num_tcp_clients; i++) { + thr = PR_CreateThread(PR_USER_THREAD, TCP_Client, (void *)cparamp, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); + if (NULL == thr) { + fprintf(stderr,"%s: PR_CreateThread failed\n", program_name); + failed_already=1; + return -1; + } + PR_EnterMonitor(mon2); + connections++; + PR_ExitMonitor(mon2); + DPRINTF(("Created TCP client = 0x%lx\n", thr)); + } + /* Wait for client jobs to exit */ + PR_EnterMonitor(mon2); + while (0 != connections) { + PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("Client job count = %d\n", connections)); + } + PR_ExitMonitor(mon2); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + PR_DELETE(cparamp); + return 0; +} + +/************************************************************************/ + +int +main(int argc, char **argv) +{ + /* + * -d debug mode + */ + PLOptStatus os; + PLOptState *opt; + program_name = argv[0]; + + opt = PL_CreateOptState(argc, argv, "dp:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + case 'p': + server_port = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + TCP_Socket_Client_Server_Test(); + + PR_Cleanup(); + if (failed_already) + return 1; + else + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/thrpool_server.c b/src/libs/xpcom18a4/nsprpub/pr/tests/thrpool_server.c new file mode 100644 index 00000000..cafa67ad --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/thrpool_server.c @@ -0,0 +1,607 @@ +/* -*- 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 ***** */ + +/*********************************************************************** +** +** Name: thrpool.c +** +** Description: Test threadpool functionality. +** +** Modification History: +*/ +#include "primpl.h" + +#include "plgetopt.h" + +#include +#include +#include +#ifdef XP_UNIX +#include +#endif +#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) +#include +#endif + +/* for getcwd */ +#if defined(XP_UNIX) || defined (XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(XP_PC) +#include +#endif + +#ifdef WIN32 +#include +#endif + +static int _debug_on = 0; +static char *program_name = NULL; +static void serve_client_write(void *arg); + +#ifdef XP_MAC +#include "prlog.h" +#include "prsem.h" +int fprintf(FILE *stream, const char *fmt, ...) +{ + PR_LogPrint(fmt); + return 0; +} +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#else +#include "obsolete/prsem.h" +#endif + +#ifdef XP_PC +#define mode_t int +#endif + +#define DPRINTF(arg) if (_debug_on) printf arg + + +#define BUF_DATA_SIZE (2 * 1024) +#define TCP_MESG_SIZE 1024 +#define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */ + + +#define NUM_TCP_CONNECTIONS_PER_CLIENT 10 +#define NUM_TCP_MESGS_PER_CONNECTION 10 +#define TCP_SERVER_PORT 10000 +#define SERVER_MAX_BIND_COUNT 100 + +static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS; +static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT; +static PRInt32 tcp_mesg_size = TCP_MESG_SIZE; +static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION; +static void TCP_Server_Accept(void *arg); + + +int failed_already=0; +typedef struct buffer { + char data[BUF_DATA_SIZE]; +} buffer; + + +typedef struct Server_Param { + PRJobIoDesc iod; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ + PRNetAddr netaddr; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRInt32 conn_counter; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Server_Param; + +typedef struct Serve_Client_Param { + PRJobIoDesc iod; /* socket to read from/write to */ + PRInt32 datalen; /* bytes of data transfered in each read/write */ + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Serve_Client_Param; + +typedef struct Session { + PRJobIoDesc iod; /* socket to read from/write to */ + buffer *in_buf; + PRInt32 bytes; + PRInt32 msg_num; + PRInt32 bytes_read; + PRMonitor *exit_mon; /* monitor to signal on exit */ + PRInt32 *job_counterp; /* counter to decrement, before exit */ + PRThreadPool *tp; +} Session; + +static void +serve_client_read(void *arg) +{ + Session *sp = (Session *) arg; + int rem; + int bytes; + int offset; + PRFileDesc *sockfd; + char *buf; + PRJob *jobp; + + PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; + + sockfd = sp->iod.socket; + buf = sp->in_buf->data; + + PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); + PR_ASSERT(sp->bytes_read < sp->bytes); + + offset = sp->bytes_read; + rem = sp->bytes - offset; + bytes = PR_Recv(sockfd, buf + offset, rem, 0, timeout); + if (bytes < 0) { + return; + } + sp->bytes_read += bytes; + sp->iod.timeout = PR_SecondsToInterval(60); + if (sp->bytes_read < sp->bytes) { + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + PR_ASSERT(sp->bytes_read == sp->bytes); + DPRINTF(("serve_client: read complete, msg(%d) \n", sp->msg_num)); + + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Write(sp->tp, &sp->iod, serve_client_write, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + + return; +} + +static void +serve_client_write(void *arg) +{ + Session *sp = (Session *) arg; + int bytes; + PRFileDesc *sockfd; + char *buf; + PRJob *jobp; + + sockfd = sp->iod.socket; + buf = sp->in_buf->data; + + PR_ASSERT(sp->msg_num < num_tcp_mesgs_per_connection); + + bytes = PR_Send(sockfd, buf, sp->bytes, 0, PR_INTERVAL_NO_TIMEOUT); + PR_ASSERT(bytes == sp->bytes); + + if (bytes < 0) { + return; + } + DPRINTF(("serve_client: write complete, msg(%d) \n", sp->msg_num)); + sp->msg_num++; + if (sp->msg_num < num_tcp_mesgs_per_connection) { + sp->bytes_read = 0; + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + + DPRINTF(("serve_client: read/write complete, msg(%d) \n", sp->msg_num)); + if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) { + fprintf(stderr,"%s: ERROR - PR_Shutdown\n", program_name); + } + + PR_Close(sockfd); + PR_EnterMonitor(sp->exit_mon); + --(*sp->job_counterp); + PR_Notify(sp->exit_mon); + PR_ExitMonitor(sp->exit_mon); + + PR_DELETE(sp->in_buf); + PR_DELETE(sp); + + return; +} + +/* + * Serve_Client + * Thread, started by the server, for serving a client connection. + * Reads data from socket and writes it back, unmodified, and + * closes the socket + */ +static void PR_CALLBACK +Serve_Client(void *arg) +{ + Serve_Client_Param *scp = (Serve_Client_Param *) arg; + buffer *in_buf; + Session *sp; + PRJob *jobp; + + sp = PR_NEW(Session); + sp->iod = scp->iod; + + in_buf = PR_NEW(buffer); + if (in_buf == NULL) { + fprintf(stderr,"%s: failed to alloc buffer struct\n",program_name); + failed_already=1; + return; + } + + sp->in_buf = in_buf; + sp->bytes = scp->datalen; + sp->msg_num = 0; + sp->bytes_read = 0; + sp->tp = scp->tp; + sp->exit_mon = scp->exit_mon; + sp->job_counterp = scp->job_counterp; + + sp->iod.timeout = PR_SecondsToInterval(60); + jobp = PR_QueueJob_Read(sp->tp, &sp->iod, serve_client_read, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + PR_DELETE(scp); +} + +static void +print_stats(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRThreadPool *tp = sp->tp; + PRInt32 counter; + PRJob *jobp; + + PR_EnterMonitor(sp->exit_mon); + counter = (*sp->job_counterp); + PR_ExitMonitor(sp->exit_mon); + + printf("PRINT_STATS: #client connections = %d\n",counter); + + + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), + print_stats, sp, PR_FALSE); + + PR_ASSERT(NULL != jobp); +} + +static int job_counter = 0; +/* + * TCP Server + * Server binds an address to a socket, starts a client process and + * listens for incoming connections. + * Each client connects to the server and sends a chunk of data + * Starts a Serve_Client job for each incoming connection, to read + * the data from the client and send it back to the client, unmodified. + * Each client checks that data received from server is same as the + * data it sent to the server. + * Finally, the threadpool is shutdown + */ +static void PR_CALLBACK +TCP_Server(void *arg) +{ + PRThreadPool *tp = (PRThreadPool *) arg; + Server_Param *sp; + PRFileDesc *sockfd; + PRNetAddr netaddr; + PRMonitor *sc_mon; + PRJob *jobp; + int i; + PRStatus rval; + + /* + * Create a tcp socket + */ + if ((sockfd = PR_NewTCPSocket()) == NULL) { + fprintf(stderr,"%s: PR_NewTCPSocket failed\n", program_name); + return; + } + memset(&netaddr, 0 , sizeof(netaddr)); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons(TCP_SERVER_PORT); + netaddr.inet.ip = PR_htonl(PR_INADDR_ANY); + /* + * try a few times to bind server's address, if addresses are in + * use + */ + i = 0; + while (PR_Bind(sockfd, &netaddr) < 0) { + if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { + netaddr.inet.port += 2; + if (i++ < SERVER_MAX_BIND_COUNT) + continue; + } + fprintf(stderr,"%s: ERROR - PR_Bind failed\n", program_name); + perror("PR_Bind"); + failed_already=1; + return; + } + + if (PR_Listen(sockfd, 32) < 0) { + fprintf(stderr,"%s: ERROR - PR_Listen failed\n", program_name); + failed_already=1; + return; + } + + if (PR_GetSockName(sockfd, &netaddr) < 0) { + fprintf(stderr,"%s: ERROR - PR_GetSockName failed\n", program_name); + failed_already=1; + return; + } + + DPRINTF(( + "TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n", + netaddr.inet.ip, netaddr.inet.port)); + + sp = PR_NEW(Server_Param); + if (sp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + return; + } + sp->iod.socket = sockfd; + sp->iod.timeout = PR_SecondsToInterval(60); + sp->datalen = tcp_mesg_size; + sp->exit_mon = sc_mon; + sp->job_counterp = &job_counter; + sp->conn_counter = 0; + sp->tp = tp; + sp->netaddr = netaddr; + + /* create and cancel an io job */ + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + rval = PR_CancelJob(jobp); + PR_ASSERT(PR_SUCCESS == rval); + + /* + * create the client process + */ + { +#define MAX_ARGS 4 + char *argv[MAX_ARGS + 1]; + int index = 0; + char port[32]; + char path[1024 + sizeof("/thrpool_client")]; + (void)getcwd(path, sizeof(path)); + (void)strcat(path, "/thrpool_client"); +#ifdef XP_PC + (void)strcat(path, ".exe"); +#endif + argv[index++] = path; + sprintf(port,"%d",PR_ntohs(netaddr.inet.port)); + if (_debug_on) + { + argv[index++] = "-d"; + argv[index++] = "-p"; + argv[index++] = port; + argv[index++] = NULL; + } else { + argv[index++] = "-p"; + argv[index++] = port; + argv[index++] = NULL; + } + PR_ASSERT(MAX_ARGS >= (index - 1)); + + DPRINTF(("creating client process %s ...\n", path)); + if (PR_FAILURE == PR_CreateProcessDetached(path, argv, NULL, NULL)) { + fprintf(stderr, + "thrpool_server: ERROR - PR_CreateProcessDetached failed\n"); + failed_already=1; + return; + } + } + + sc_mon = PR_NewMonitor(); + if (sc_mon == NULL) { + fprintf(stderr,"%s: PR_NewMonitor failed\n", program_name); + failed_already=1; + return; + } + + sp->iod.socket = sockfd; + sp->iod.timeout = PR_SecondsToInterval(60); + sp->datalen = tcp_mesg_size; + sp->exit_mon = sc_mon; + sp->job_counterp = &job_counter; + sp->conn_counter = 0; + sp->tp = tp; + sp->netaddr = netaddr; + + /* create and cancel a timer job */ + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(5000), + print_stats, sp, PR_FALSE); + PR_ASSERT(NULL != jobp); + rval = PR_CancelJob(jobp); + PR_ASSERT(PR_SUCCESS == rval); + + DPRINTF(("TCP_Server: Accepting connections \n")); + + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; +} + +static void +TCP_Server_Accept(void *arg) +{ + Server_Param *sp = (Server_Param *) arg; + PRThreadPool *tp = sp->tp; + Serve_Client_Param *scp; + PRFileDesc *newsockfd; + PRJob *jobp; + + if ((newsockfd = PR_Accept(sp->iod.socket, &sp->netaddr, + PR_INTERVAL_NO_TIMEOUT)) == NULL) { + fprintf(stderr,"%s: ERROR - PR_Accept failed\n", program_name); + failed_already=1; + goto exit; + } + scp = PR_NEW(Serve_Client_Param); + if (scp == NULL) { + fprintf(stderr,"%s: PR_NEW failed\n", program_name); + failed_already=1; + goto exit; + } + + /* + * Start a Serve_Client job for each incoming connection + */ + scp->iod.socket = newsockfd; + scp->iod.timeout = PR_SecondsToInterval(60); + scp->datalen = tcp_mesg_size; + scp->exit_mon = sp->exit_mon; + scp->job_counterp = sp->job_counterp; + scp->tp = sp->tp; + + PR_EnterMonitor(sp->exit_mon); + (*sp->job_counterp)++; + PR_ExitMonitor(sp->exit_mon); + jobp = PR_QueueJob(tp, Serve_Client, scp, + PR_FALSE); + + PR_ASSERT(NULL != jobp); + DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", jobp)); + + /* + * single-threaded update; no lock needed + */ + sp->conn_counter++; + if (sp->conn_counter < + (num_tcp_clients * num_tcp_connections_per_client)) { + jobp = PR_QueueJob_Accept(tp, &sp->iod, TCP_Server_Accept, sp, + PR_FALSE); + PR_ASSERT(NULL != jobp); + return; + } + jobp = PR_QueueJob_Timer(tp, PR_MillisecondsToInterval(500), + print_stats, sp, PR_FALSE); + + PR_ASSERT(NULL != jobp); + DPRINTF(("TCP_Server: Created print_stats timer job = 0x%lx\n", jobp)); + +exit: + PR_EnterMonitor(sp->exit_mon); + /* Wait for server jobs to finish */ + while (0 != *sp->job_counterp) { + PR_Wait(sp->exit_mon, PR_INTERVAL_NO_TIMEOUT); + DPRINTF(("TCP_Server: conn_counter = %d\n", + *sp->job_counterp)); + } + + PR_ExitMonitor(sp->exit_mon); + if (sp->iod.socket) { + PR_Close(sp->iod.socket); + } + PR_DestroyMonitor(sp->exit_mon); + printf("%30s","TCP_Socket_Client_Server_Test:"); + printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l, + num_tcp_clients, num_tcp_connections_per_client); + printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":", + num_tcp_mesgs_per_connection, tcp_mesg_size); + + DPRINTF(("%s: calling PR_ShutdownThreadPool\n", program_name)); + PR_ShutdownThreadPool(sp->tp); + PR_DELETE(sp); +} + +/************************************************************************/ + +#define DEFAULT_INITIAL_THREADS 4 +#define DEFAULT_MAX_THREADS 100 +#define DEFAULT_STACKSIZE (512 * 1024) + +int +main(int argc, char **argv) +{ + PRInt32 initial_threads = DEFAULT_INITIAL_THREADS; + PRInt32 max_threads = DEFAULT_MAX_THREADS; + PRInt32 stacksize = DEFAULT_STACKSIZE; + PRThreadPool *tp = NULL; + PRStatus rv; + PRJob *jobp; + + /* + * -d debug mode + */ + PLOptStatus os; + PLOptState *opt; + + program_name = argv[0]; + opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + +#ifdef XP_MAC + SetupMacPrintfLog("socket.log"); +#endif + PR_SetConcurrency(4); + + tp = PR_CreateThreadPool(initial_threads, max_threads, stacksize); + if (NULL == tp) { + printf("PR_CreateThreadPool failed\n"); + failed_already=1; + goto done; + } + jobp = PR_QueueJob(tp, TCP_Server, tp, PR_TRUE); + rv = PR_JoinJob(jobp); + PR_ASSERT(PR_SUCCESS == rv); + + DPRINTF(("%s: calling PR_JoinThreadPool\n", program_name)); + rv = PR_JoinThreadPool(tp); + PR_ASSERT(PR_SUCCESS == rv); + DPRINTF(("%s: returning from PR_JoinThreadPool\n", program_name)); + +done: + PR_Cleanup(); + if (failed_already) return 1; + else return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/thruput.c b/src/libs/xpcom18a4/nsprpub/pr/tests/thruput.c new file mode 100644 index 00000000..e6319dbe --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/thruput.c @@ -0,0 +1,412 @@ +/* -*- 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 ***** */ + +/* +** File: thruput.c +** Description: Test server's throughput capability comparing various +** implmentation strategies. +** +** Note: Requires a server machine and an aribitrary number of +** clients to bang on it. Trust the numbers on the server +** more than those being displayed by the various clients. +*/ + +#include "prerror.h" +#include "prinrval.h" +#include "prinit.h" +#include "prio.h" +#include "prlock.h" +#include "prmem.h" +#include "prnetdb.h" +#include "prprf.h" +#include "prthread.h" + +#include "pprio.h" + +#include "plerror.h" +#include "plgetopt.h" + +#define ADDR_BUFFER 100 +#define PORT_NUMBER 51877 +#define SAMPLING_INTERVAL 10 +#define BUFFER_SIZE (32 * 1024) + +static PRInt32 domain = PR_AF_INET; +static PRInt32 protocol = 6; /* TCP */ +static PRFileDesc *err = NULL; +static PRIntn concurrency = 1; +static PRInt32 xport_buffer = -1; +static PRUint32 initial_streams = 1; +static PRInt32 buffer_size = BUFFER_SIZE; +static PRThreadScope thread_scope = PR_LOCAL_THREAD; + +typedef struct Shared +{ + PRLock *ml; + PRUint32 sampled; + PRUint32 threads; + PRIntervalTime timein; + PRNetAddr server_address; +} Shared; + +static Shared *shared = NULL; + +static PRStatus PrintAddress(const PRNetAddr* address) +{ + char buffer[ADDR_BUFFER]; + PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); + if (PR_SUCCESS == rv) + PR_fprintf(err, "%s:%u\n", buffer, PR_ntohs(address->inet.port)); + else PL_FPrintError(err, "PR_NetAddrToString"); + return rv; +} /* PrintAddress */ + + +static void PR_CALLBACK Clientel(void *arg) +{ + PRStatus rv; + PRFileDesc *xport; + PRInt32 bytes, sampled; + PRIntervalTime now, interval; + PRBool do_display = PR_FALSE; + Shared *shared = (Shared*)arg; + char *buffer = (char*)PR_Malloc(buffer_size); + PRNetAddr *server_address = &shared->server_address; + PRIntervalTime connect_timeout = PR_SecondsToInterval(5); + PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL); + + PR_fprintf(err, "Client connecting to "); + (void)PrintAddress(server_address); + + do + { + xport = PR_Socket(domain, PR_SOCK_STREAM, protocol); + if (NULL == xport) + { + PL_FPrintError(err, "PR_Socket"); + return; + } + + if (xport_buffer != -1) + { + PRSocketOptionData data; + data.option = PR_SockOpt_RecvBufferSize; + data.value.recv_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(xport, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + data.option = PR_SockOpt_SendBufferSize; + data.value.send_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(xport, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + } + + rv = PR_Connect(xport, server_address, connect_timeout); + if (PR_FAILURE == rv) + { + PL_FPrintError(err, "PR_Connect"); + if (PR_IO_TIMEOUT_ERROR != PR_GetError()) + PR_Sleep(connect_timeout); + PR_Close(xport); /* delete it and start over */ + } + } while (PR_FAILURE == rv); + + do + { + bytes = PR_Recv( + xport, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT); + PR_Lock(shared->ml); + now = PR_IntervalNow(); + shared->sampled += bytes; + interval = now - shared->timein; + if (interval > sampling_interval) + { + sampled = shared->sampled; + shared->timein = now; + shared->sampled = 0; + do_display = PR_TRUE; + } + PR_Unlock(shared->ml); + + if (do_display) + { + PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval); + PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate); + do_display = PR_FALSE; + } + + } while (bytes > 0); +} /* Clientel */ + +static void Client(const char *server_name) +{ + PRStatus rv; + PRHostEnt host; + char buffer[PR_NETDB_BUF_SIZE]; + PRIntervalTime dally = PR_SecondsToInterval(60); + PR_fprintf(err, "Translating the name %s\n", server_name); + rv = PR_GetHostByName(server_name, buffer, sizeof(buffer), &host); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_GetHostByName"); + else + { + if (PR_EnumerateHostEnt( + 0, &host, PORT_NUMBER, &shared->server_address) < 0) + PL_FPrintError(err, "PR_EnumerateHostEnt"); + else + { + do + { + shared->threads += 1; + (void)PR_CreateThread( + PR_USER_THREAD, Clientel, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_UNJOINABLE_THREAD, 8 * 1024); + if (shared->threads == initial_streams) + { + PR_Sleep(dally); + initial_streams += 1; + } + } while (PR_TRUE); + } + } +} + +static void PR_CALLBACK Servette(void *arg) +{ + PRInt32 bytes, sampled; + PRIntervalTime now, interval; + PRBool do_display = PR_FALSE; + PRFileDesc *client = (PRFileDesc*)arg; + char *buffer = (char*)PR_Malloc(buffer_size); + PRIntervalTime sampling_interval = PR_SecondsToInterval(SAMPLING_INTERVAL); + + if (xport_buffer != -1) + { + PRStatus rv; + PRSocketOptionData data; + data.option = PR_SockOpt_RecvBufferSize; + data.value.recv_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(client, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + data.option = PR_SockOpt_SendBufferSize; + data.value.send_buffer_size = (PRSize)xport_buffer; + rv = PR_SetSocketOption(client, &data); + if (PR_FAILURE == rv) + PL_FPrintError(err, "PR_SetSocketOption - ignored"); + } + + do + { + bytes = PR_Send( + client, buffer, buffer_size, 0, PR_INTERVAL_NO_TIMEOUT); + + PR_Lock(shared->ml); + now = PR_IntervalNow(); + shared->sampled += bytes; + interval = now - shared->timein; + if (interval > sampling_interval) + { + sampled = shared->sampled; + shared->timein = now; + shared->sampled = 0; + do_display = PR_TRUE; + } + PR_Unlock(shared->ml); + + if (do_display) + { + PRUint32 rate = sampled / PR_IntervalToMilliseconds(interval); + PR_fprintf(err, "%u streams @ %u Kbytes/sec\n", shared->threads, rate); + do_display = PR_FALSE; + } + } while (bytes > 0); +} /* Servette */ + +static void Server(void) +{ + PRStatus rv; + PRNetAddr server_address, client_address; + PRFileDesc *xport = PR_Socket(domain, PR_SOCK_STREAM, protocol); + + if (NULL == xport) + { + PL_FPrintError(err, "PR_Socket"); + return; + } + + rv = PR_InitializeNetAddr(PR_IpAddrAny, PORT_NUMBER, &server_address); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_InitializeNetAddr"); + else + { + rv = PR_Bind(xport, &server_address); + if (PR_FAILURE == rv) PL_FPrintError(err, "PR_Bind"); + else + { + PRFileDesc *client; + rv = PR_Listen(xport, 10); + PR_fprintf(err, "Server listening on "); + (void)PrintAddress(&server_address); + do + { + client = PR_Accept( + xport, &client_address, PR_INTERVAL_NO_TIMEOUT); + if (NULL == client) PL_FPrintError(err, "PR_Accept"); + else + { + PR_fprintf(err, "Server accepting from "); + (void)PrintAddress(&client_address); + shared->threads += 1; + (void)PR_CreateThread( + PR_USER_THREAD, Servette, client, + PR_PRIORITY_NORMAL, thread_scope, + PR_UNJOINABLE_THREAD, 8 * 1024); + } + } while (PR_TRUE); + + } + } +} /* Server */ + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-h] []\n"); + PR_fprintf(err, "\t-s Initial # of connections (default: 1)\n"); + PR_fprintf(err, "\t-C Set 'concurrency' (default: 1)\n"); + PR_fprintf(err, "\t-b Client buffer size (default: 32k)\n"); + PR_fprintf(err, "\t-B Transport recv/send buffer size (default: sys)\n"); + PR_fprintf(err, "\t-G Use GLOBAL threads (default: LOCAL)\n"); + PR_fprintf(err, "\t-X Use XTP transport (default: TCP)\n"); + PR_fprintf(err, "\t-6 Use IPv6 (default: IPv4)\n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); + PR_fprintf(err, "\t DNS name of server\n"); + PR_fprintf(err, "\t\tIf is not specified, this host will be\n"); + PR_fprintf(err, "\t\tthe server and not act as a client.\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PLOptStatus os; + const char *server_name = NULL; + PLOptState *opt = PL_CreateOptState(argc, argv, "hGX6C:b:s:B:"); + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* Name of server */ + server_name = opt->value; + break; + case 'G': /* Globular threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'X': /* Use XTP as the transport */ + protocol = 36; + break; + case '6': /* Use IPv6 */ + domain = PR_AF_INET6; + break; + case 's': /* initial_streams */ + initial_streams = atoi(opt->value); + break; + case 'C': /* concurrency */ + concurrency = atoi(opt->value); + break; + case 'b': /* buffer size */ + buffer_size = 1024 * atoi(opt->value); + break; + case 'B': /* buffer size */ + xport_buffer = 1024 * atoi(opt->value); + break; + case 'h': /* user wants some guidance */ + default: + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + shared = PR_NEWZAP(Shared); + shared->ml = PR_NewLock(); + + PR_fprintf(err, + "This machine is %s\n", + (NULL == server_name) ? "the SERVER" : "a CLIENT"); + + PR_fprintf(err, + "Transport being used is %s\n", + (6 == protocol) ? "TCP" : "XTP"); + + if (PR_GLOBAL_THREAD == thread_scope) + { + if (1 != concurrency) + { + PR_fprintf(err, " **Concurrency > 1 and GLOBAL threads!?!?\n"); + PR_fprintf(err, " **Ignoring concurrency\n"); + concurrency = 1; + } + } + + if (1 != concurrency) + { + PR_SetConcurrency(concurrency); + PR_fprintf(err, "Concurrency set to %u\n", concurrency); + } + + PR_fprintf(err, + "All threads will be %s\n", + (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL"); + + PR_fprintf(err, "Client buffer size will be %u\n", buffer_size); + + if (-1 != xport_buffer) + PR_fprintf( + err, "Transport send & receive buffer size will be %u\n", xport_buffer); + + + if (NULL == server_name) Server(); + else Client(server_name); + +} /* main */ + +/* thruput.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/time.c b/src/libs/xpcom18a4/nsprpub/pr/tests/time.c new file mode 100644 index 00000000..b8e7d61a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/time.c @@ -0,0 +1,201 @@ +/* -*- 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 ***** */ + +/* + * Program to test different ways to get the time; right now it is tuned + * only for solaris. + * solaris results (100000 iterations): + * time to get time with time(): 4.63 usec avg, 463 msec total + * time to get time with gethrtime(): 2.17 usec avg, 217 msec total + * time to get time with gettimeofday(): 1.25 usec avg, 125 msec total + * + * + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "prpriv.h" +#include "prinrval.h" + +#include +#include +#include +#include + +#define DEFAULT_COUNT 100000 +PRInt32 count; + +time_t itime; +hrtime_t ihrtime; + +void +ftime_init() +{ + itime = time(NULL); + ihrtime = gethrtime(); +} + +time_t +ftime() +{ + hrtime_t now = gethrtime(); + + return itime + ((now - ihrtime) / 1000000000ll); +} + +static void timeTime(void) +{ + PRInt32 index = count; + time_t rv; + + for (;index--;) + rv = time(NULL); +} + +static void timeGethrtime(void) +{ + PRInt32 index = count; + time_t rv; + + for (;index--;) + rv = ftime(); +} + +static void timeGettimeofday(void) +{ + PRInt32 index = count; + time_t rv; + struct timeval tp; + + for (;index--;) + rv = gettimeofday(&tp, NULL); +} + +static void timePRTime32(void) +{ + PRInt32 index = count; + PRInt32 rv32; + PRTime q; + PRTime rv; + + LL_I2L(q, 1000000); + + for (;index--;) { + rv = PR_Now(); + LL_DIV(rv, rv, q); + LL_L2I(rv32, rv); + } +} + +static void timePRTime64(void) +{ + PRInt32 index = count; + PRTime rv; + + for (;index--;) + rv = PR_Now(); +} + +/************************************************************************/ + +static void Measure(void (*func)(void), const char *msg) +{ + PRIntervalTime start, stop; + double d; + PRInt32 tot; + + start = PR_IntervalNow(); + (*func)(); + stop = PR_IntervalNow(); + + d = (double)PR_IntervalToMicroseconds(stop - start); + tot = PR_IntervalToMilliseconds(stop-start); + + if (debug_mode) printf("%40s: %6.2f usec avg, %d msec total\n", msg, d / count, tot); +} + +void main(int argc, char **argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "d:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + + if (argc > 1) { + count = atoi(argv[1]); + } else { + count = DEFAULT_COUNT; + } + + ftime_init(); + + Measure(timeTime, "time to get time with time()"); + Measure(timeGethrtime, "time to get time with gethrtime()"); + Measure(timeGettimeofday, "time to get time with gettimeofday()"); + Measure(timePRTime32, "time to get time with PR_Time() (32bit)"); + Measure(timePRTime64, "time to get time with PR_Time() (64bit)"); + + PR_Cleanup(); + return 0; +} + + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/timemac.c b/src/libs/xpcom18a4/nsprpub/pr/tests/timemac.c new file mode 100644 index 00000000..c58c24bd --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/timemac.c @@ -0,0 +1,153 @@ +/* -*- 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 ***** */ + +/* + * file: timemac.c + * description: test time and date routines on the Mac + */ +#include +#include "prinit.h" +#include "prtime.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +extern void SetupMacPrintfLog(char *logFile); +#endif + + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +static void printExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + printf( "%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + printf("UTC "); + } else { + sign = ""; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } + + /* Print year */ + printf("%d", et->tm_year); +} + +int main(int argc, char** argv) +{ + PR_STDIO_INIT(); + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + +#ifdef XP_MAC + SetupMacPrintfLog("timemac.log"); +#endif + + /* + ************************************************************* + ** + ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime + ** on the current time + ** + ************************************************************* + */ + + { + PRTime t1, t2; + PRExplodedTime et; + + printf("*********************************************\n"); + printf("** **\n"); + printf("** Testing PR_Now(), PR_ExplodeTime, and **\n"); + printf("** PR_ImplodeTime on the current time **\n"); + printf("** **\n"); + printf("*********************************************\n\n"); + t1 = PR_Now(); + + /* First try converting to UTC */ + + PR_ExplodeTime(t1, PR_GMTParameters, &et); + if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) { + printf("ERROR: UTC has nonzero gmt or dst offset.\n"); + return 1; + } + printf("Current UTC is "); + printExplodedTime(&et); + printf("\n"); + + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + + /* Next, try converting to local (US Pacific) time */ + + PR_ExplodeTime(t1, PR_LocalTimeParameters, &et); + printf("Current local time is "); + printExplodedTime(&et); + printf("\n"); + printf("GMT offset is %ld, DST offset is %ld\n", + et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset); + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + } + + printf("Please examine the results\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/timetest.c b/src/libs/xpcom18a4/nsprpub/pr/tests/timetest.c new file mode 100644 index 00000000..8560b719 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/timetest.c @@ -0,0 +1,782 @@ +/* -*- 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 ***** */ + +/* + * file: timetest.c + * description: test time and date routines + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prtime.h" +#include "prprf.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#include "macstdlibextras.h" +extern void SetupMacPrintfLog(char *logFile); +#endif + +int failed_already=0; +PRBool debug_mode = PR_FALSE; + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +static void PrintExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + if (debug_mode) printf("UTC "); + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + if (debug_mode) + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } + + /* Print year */ + if (debug_mode) printf("%hd", et->tm_year); +} + +static int ExplodedTimeIsEqual(const PRExplodedTime *et1, + const PRExplodedTime *et2) +{ + if (et1->tm_usec == et2->tm_usec && + et1->tm_sec == et2->tm_sec && + et1->tm_min == et2->tm_min && + et1->tm_hour == et2->tm_hour && + et1->tm_mday == et2->tm_mday && + et1->tm_month == et2->tm_month && + et1->tm_year == et2->tm_year && + et1->tm_wday == et2->tm_wday && + et1->tm_yday == et2->tm_yday && + et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset && + et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) { + return 1; + } else { + return 0; + } +} + +static void +testParseTimeString(PRTime t) +{ + PRExplodedTime et; + PRTime t2; + char timeString[128]; + char buf[128]; + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + PRInt64 usec_per_sec; + + /* Truncate the microsecond part of PRTime */ + LL_I2L(usec_per_sec, PR_USEC_PER_SEC); + LL_DIV(t, t, usec_per_sec); + LL_MUL(t, t, usec_per_sec); + + PR_ExplodeTime(t, PR_LocalTimeParameters, &et); + + /* Print day of the week, month, day, hour, minute, and second */ + PR_snprintf(timeString, 128, "%s %s %ld %02ld:%02ld:%02ld ", + dayOfWeek[et.tm_wday], month[et.tm_month], et.tm_mday, + et.tm_hour, et.tm_min, et.tm_sec); + /* Print time zone */ + totalOffset = et.tm_params.tp_gmt_offset + et.tm_params.tp_dst_offset; + if (totalOffset == 0) { + strcat(timeString, "GMT "); /* I wanted to use "UTC" here, but + * PR_ParseTimeString doesn't + * understand "UTC". */ + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + PR_snprintf(buf, 128, "%s%02ld%02ld ", sign, hourOffset, minOffset); + strcat(timeString, buf); + } + /* Print year */ + PR_snprintf(buf, 128, "%hd", et.tm_year); + strcat(timeString, buf); + + if (PR_ParseTimeString(timeString, PR_FALSE, &t2) == PR_FAILURE) { + fprintf(stderr, "PR_ParseTimeString() failed\n"); + exit(1); + } + if (LL_NE(t, t2)) { + fprintf(stderr, "PR_ParseTimeString() incorrect\n"); + PR_snprintf(buf, 128, "t is %lld, t2 is %lld, time string is %s\n", + t, t2, timeString); + fprintf(stderr, "%s\n", buf); + exit(1); + } +} + +int main(int argc, char** argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + +#ifdef XP_MAC + /* Set up the console */ + InitializeSIOUX(true); + debug_mode = PR_TRUE; +#endif + /* Testing zero PRTime (the epoch) */ + { + PRTime t; + PRExplodedTime et; + + LL_I2L(t, 0); + if (debug_mode) printf("The NSPR epoch is:\n"); + PR_ExplodeTime(t, PR_LocalTimeParameters, &et); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + PR_ExplodeTime(t, PR_GMTParameters, &et); + PrintExplodedTime(&et); + if (debug_mode) printf("\n\n"); + testParseTimeString(t); + } + + /* + ************************************************************* + ** + ** Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime + ** on the current time + ** + ************************************************************* + */ + + { + PRTime t1, t2; + PRExplodedTime et; + + if (debug_mode) { + printf("*********************************************\n"); + printf("** **\n"); + printf("** Testing PR_Now(), PR_ExplodeTime, and **\n"); + printf("** PR_ImplodeTime on the current time **\n"); + printf("** **\n"); + printf("*********************************************\n\n"); + } + t1 = PR_Now(); + + /* First try converting to UTC */ + + PR_ExplodeTime(t1, PR_GMTParameters, &et); + if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) { + if (debug_mode) printf("ERROR: UTC has nonzero gmt or dst offset.\n"); + else failed_already=1; + return 1; + } + if (debug_mode) printf("Current UTC is "); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n"); + else printf("FAIL\n"); + return 1; + } + + /* Next, try converting to local (US Pacific) time */ + + PR_ExplodeTime(t1, PR_LocalTimeParameters, &et); + if (debug_mode) printf("Current local time is "); + PrintExplodedTime(&et); + if (debug_mode) printf("\n"); + if (debug_mode) printf("GMT offset is %ld, DST offset is %ld\n", + et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset); + t2 = PR_ImplodeTime(&et); + if (LL_NE(t1, t2)) { + if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n"); + return 1; + } + + if (debug_mode) printf("Please examine the results\n"); + testParseTimeString(t1); + } + + + /* + ******************************************* + ** + ** Testing PR_NormalizeTime() + ** + ******************************************* + */ + + /* July 4, 2001 is Wednesday */ + { + PRExplodedTime et; + + if (debug_mode) { + printf("\n"); + printf("**********************************\n"); + printf("** **\n"); + printf("** Testing PR_NormalizeTime() **\n"); + printf("** **\n"); + printf("**********************************\n\n"); + } + et.tm_year = 2001; + et.tm_month = 7 - 1; + et.tm_mday = 4; + et.tm_hour = 0; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params = PR_GMTParameters(&et); + + PR_NormalizeTime(&et, PR_GMTParameters); + + if (debug_mode) printf("July 4, 2001 is %s.\n", dayOfWeek[et.tm_wday]); + if (et.tm_wday == 3) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Wednesday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* June 12, 1997 23:00 PST == June 13, 1997 00:00 PDT */ + et.tm_year = 1997; + et.tm_month = 6 - 1; + et.tm_mday = 12; + et.tm_hour = 23; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + + PR_NormalizeTime(&et, PR_USPacificTimeParameters); + + if (debug_mode) { + printf("Thu Jun 12, 1997 23:00:00 PST is "); + } + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + if (et.tm_wday == 5) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Friday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* Feb 14, 1997 00:00:00 PDT == Feb 13, 1997 23:00:00 PST */ + et.tm_year = 1997; + et.tm_month = 2 - 1; + et.tm_mday = 14; + et.tm_hour = 0; + et.tm_min = 0; + et.tm_sec = 0; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 3600; + + PR_NormalizeTime(&et, PR_USPacificTimeParameters); + + if (debug_mode) { + printf("Fri Feb 14, 1997 00:00:00 PDT is "); + } + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + if (et.tm_wday == 4) { + if (debug_mode) printf("PASS\n"); + } else { + if (debug_mode) printf("ERROR: It should be Thursday\n"); + else failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et)); + + /* What time is Nov. 7, 1996, 18:29:23 PDT? */ + et.tm_year = 1996; + et.tm_month = 11 - 1; + et.tm_mday = 7; + et.tm_hour = 18; + et.tm_min = 29; + et.tm_sec = 23; + et.tm_usec = 0; + et.tm_params.tp_gmt_offset = -8 * 3600; /* PDT */ + et.tm_params.tp_dst_offset = 3600; + + PR_NormalizeTime(&et, PR_LocalTimeParameters); + if (debug_mode) printf("Nov 7 18:29:23 PDT 1996 is "); + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + testParseTimeString(PR_ImplodeTime(&et)); + + /* What time is Oct. 7, 1995, 18:29:23 PST? */ + et.tm_year = 1995; + et.tm_month = 10 - 1; + et.tm_mday = 7; + et.tm_hour = 18; + et.tm_min = 29; + et.tm_sec = 23; + et.tm_params.tp_gmt_offset = -8 * 3600; /* PST */ + et.tm_params.tp_dst_offset = 0; + + PR_NormalizeTime(&et, PR_LocalTimeParameters); + if (debug_mode) printf("Oct 7 18:29:23 PST 1995 is "); + PrintExplodedTime(&et); + if (debug_mode) printf(".\n"); + testParseTimeString(PR_ImplodeTime(&et)); + + if (debug_mode) printf("Please examine the results\n"); + } + + /* + ************************************************************** + ** + ** Testing range of years + ** + ************************************************************** + */ + + { + PRExplodedTime et1, et2; + PRTime ttt; + PRTime secs; + + if (debug_mode) { + printf("\n"); + printf("***************************************\n"); + printf("** **\n"); + printf("** Testing range of years **\n"); + printf("** **\n"); + printf("***************************************\n\n"); + } + /* April 4, 1917 GMT */ + et1.tm_usec = 0; + et1.tm_sec = 0; + et1.tm_min = 0; + et1.tm_hour = 0; + et1.tm_mday = 4; + et1.tm_month = 4 - 1; + et1.tm_year = 1917; + et1.tm_params = PR_GMTParameters(&et1); + PR_NormalizeTime(&et1, PR_LocalTimeParameters); + secs = PR_ImplodeTime(&et1); + if (LL_GE_ZERO(secs)) { + if (debug_mode) + printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n"); + failed_already = 1; + return 1; + } + PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2); + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) + printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for April 4, 1917 GMT\n"); + failed_already=1; + return 1; + } + ttt = PR_ImplodeTime(&et1); + testParseTimeString( ttt ); + + if (debug_mode) printf("Test passed for April 4, 1917\n"); + + /* July 4, 2050 */ + et1.tm_usec = 0; + et1.tm_sec = 0; + et1.tm_min = 0; + et1.tm_hour = 0; + et1.tm_mday = 4; + et1.tm_month = 7 - 1; + et1.tm_year = 2050; + et1.tm_params = PR_GMTParameters(&et1); + PR_NormalizeTime(&et1, PR_LocalTimeParameters); + secs = PR_ImplodeTime(&et1); + if (!LL_GE_ZERO(secs)) { + if (debug_mode) + printf("ERROR: July 4, 2050 GMT returns a negative second count\n"); + failed_already = 1; + return 1; + } + PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2); + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) + printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July 4, 2050 GMT\n"); + failed_already=1; + return 1; + } + testParseTimeString(PR_ImplodeTime(&et1)); + + if (debug_mode) printf("Test passed for July 4, 2050\n"); + + } + + /* + ************************************************************** + ** + ** Stress test + * + ** Go through four years, starting from + ** 00:00:00 PST Jan. 1, 1993, incrementing + ** every 10 minutes. + ** + ************************************************************** + */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test **\n"); + printf("** Starting from midnight Jan. 1, 1993 PST, **\n"); + printf("** going through four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 1993 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 1993; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_ADD(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1); + + et2 = et; + et2.tm_usec += 600000000L; + PR_NormalizeTime(&et2, PR_USPacificTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + PrintExplodedTime(&et2); + if (debug_mode) printf("\n"); + failed_already=1; + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + if (debug_mode) + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } + + et = et1; + } + } + } + if (debug_mode) printf("Test passed\n"); + } + + + /* Same stress test, but with PR_LocalTimeParameters */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test **\n"); + printf("** Starting from midnight Jan. 1, 1993 PST, **\n"); + printf("** going through four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 1993 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 1993; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_ADD(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1); + + et2 = et; + et2.tm_usec += 600000000L; + PR_NormalizeTime(&et2, PR_LocalTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + PrintExplodedTime(&et2); + if (debug_mode) printf("\n"); + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } + + et = et1; + } + } + } + if (debug_mode) printf("Test passed\n"); + } + + /* Same stress test, but with PR_LocalTimeParameters and going backward */ + + { + PRExplodedTime et, et1, et2; + PRInt64 usecPer10Min; + int day, hour, min; + PRTime usecs; + int dstInEffect = 0; + + if (debug_mode) { + printf("\n"); + printf("*******************************************************\n"); + printf("** **\n"); + printf("** Stress test **\n"); + printf("** Starting from midnight Jan. 1, 1997 PST, **\n"); + printf("** going back four years in 10-minute increment **\n"); + printf("** **\n"); + printf("*******************************************************\n\n"); + } + + LL_I2L(usecPer10Min, 600000000L); + + /* 00:00:00 PST Jan. 1, 1997 */ + et.tm_usec = 0; + et.tm_sec = 0; + et.tm_min = 0; + et.tm_hour = 0; + et.tm_mday = 1; + et.tm_month = 0; + et.tm_year = 1997; + et.tm_params.tp_gmt_offset = -8 * 3600; + et.tm_params.tp_dst_offset = 0; + usecs = PR_ImplodeTime(&et); + + for (day = 0; day < 4 * 365 + 1; day++) { + for (hour = 0; hour < 24; hour++) { + for (min = 0; min < 60; min += 10) { + LL_SUB(usecs, usecs, usecPer10Min); + PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1); + + et2 = et; + et2.tm_usec -= 600000000L; + PR_NormalizeTime(&et2, PR_LocalTimeParameters); + + if (!ExplodedTimeIsEqual(&et1, &et2)) { + if (debug_mode) printf("ERROR: componentwise comparison failed\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + PrintExplodedTime(&et2); + if (debug_mode) printf("\n"); + return 1; + } + + if (LL_NE(usecs, PR_ImplodeTime(&et1))) { + if (debug_mode) + printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n"); + PrintExplodedTime(&et1); + if (debug_mode) printf("\n"); + failed_already=1; + return 1; + } + testParseTimeString(usecs); + + if (!dstInEffect && et1.tm_params.tp_dst_offset) { + dstInEffect = 1; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } else if (dstInEffect && !et1.tm_params.tp_dst_offset) { + dstInEffect = 0; + if (debug_mode) printf("DST changeover from "); + PrintExplodedTime(&et); + if (debug_mode) printf(" to "); + PrintExplodedTime(&et1); + if (debug_mode) printf(".\n"); + } + + et = et1; + } + } + } + } + +#ifdef XP_MAC + if (1) + { + char dummyChar; + + printf("Press return to exit\n\n"); + scanf("%c", &dummyChar); + } +#endif + + if (failed_already) return 1; + else return 0; + +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/tmoacc.c b/src/libs/xpcom18a4/nsprpub/pr/tests/tmoacc.c new file mode 100644 index 00000000..fa974a13 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/tmoacc.c @@ -0,0 +1,333 @@ +/* -*- 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 "nspr.h" + +#include +#include + +#include "plerror.h" +#include "plgetopt.h" + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + +#define BASE_PORT 9867 +#define DEFAULT_THREADS 1 +#define DEFAULT_BACKLOG 10 +#define DEFAULT_TIMEOUT 10 +#define RANDOM_RANGE 100 /* should be significantly smaller than RAND_MAX */ + +typedef enum {running, stopped} Status; + +typedef struct Shared +{ + PRLock *ml; + PRCondVar *cv; + PRBool passed; + PRBool random; + PRFileDesc *debug; + PRIntervalTime timeout; + PRFileDesc *listenSock; + Status status; +} Shared; + +static PRIntervalTime Timeout(const Shared *shared) +{ + PRIntervalTime timeout = shared->timeout; + if (shared->random) + { + PRIntervalTime half = timeout >> 1; /* one half of the interval */ + PRIntervalTime quarter = half >> 1; /* one quarter of the interval */ + /* something in [0..timeout / 2) */ + PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE; + timeout = (3 * quarter) + random; /* [75..125)% */ + } + return timeout; +} /* Timeout */ + +static void Accept(void *arg) +{ + PRStatus rv; + char *buffer = NULL; + PRNetAddr clientAddr; + Shared *shared = (Shared*)arg; + PRInt32 recv_length = 0, flags = 0; + PRFileDesc *clientSock; + PRIntn toread, byte, bytes, loop = 0; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + + do + { + PRUint32 checksum = 0; + if (NULL != shared->debug) + PR_fprintf(shared->debug, "[%d]accepting ... ", loop++); + clientSock = PR_Accept( + shared->listenSock, &clientAddr, Timeout(shared)); + if (clientSock != NULL) + { + if (NULL != shared->debug) + PR_fprintf(shared->debug, "reading length ... "); + bytes = PR_Recv( + clientSock, &descriptor, sizeof(descriptor), + flags, Timeout(shared)); + if (sizeof(descriptor) == bytes) + { + /* and, before doing something stupid ... */ + descriptor.length = PR_ntohl(descriptor.length); + descriptor.checksum = PR_ntohl(descriptor.checksum); + if (NULL != shared->debug) + PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length); + toread = descriptor.length; + if (recv_length < descriptor.length) + { + if (NULL != buffer) PR_DELETE(buffer); + buffer = (char*)PR_MALLOC(descriptor.length); + recv_length = descriptor.length; + } + for (toread = descriptor.length; toread > 0; toread -= bytes) + { + bytes = PR_Recv( + clientSock, &buffer[descriptor.length - toread], + toread, flags, Timeout(shared)); + if (-1 == bytes) + { + if (NULL != shared->debug) + PR_fprintf(shared->debug, "read data failed..."); + bytes = 0; + } + } + } + else if (NULL != shared->debug) + { + PR_fprintf(shared->debug, "read desciptor failed..."); + descriptor.length = -1; + } + if (NULL != shared->debug) + PR_fprintf(shared->debug, "closing"); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + if ((PR_FAILURE == rv) && (NULL != shared->debug)) + { + PR_fprintf(shared->debug, " failed"); + shared->passed = PR_FALSE; + } + rv = PR_Close(clientSock); + if (PR_FAILURE == rv) if (NULL != shared->debug) + { + PR_fprintf(shared->debug, " failed"); + shared->passed = PR_FALSE; + } + if (descriptor.length > 0) + { + for (byte = 0; byte < descriptor.length; ++byte) + { + PRUint32 overflow = checksum & 0x80000000; + checksum = (checksum << 1); + if (0x00000000 != overflow) checksum += 1; + checksum += buffer[byte]; + } + if ((descriptor.checksum != checksum) && (NULL != shared->debug)) + { + PR_fprintf(shared->debug, " ... data mismatch"); + shared->passed = PR_FALSE; + } + } + else if (0 == descriptor.length) + { + PR_Lock(shared->ml); + shared->status = stopped; + PR_NotifyCondVar(shared->cv); + PR_Unlock(shared->ml); + } + if (NULL != shared->debug) + PR_fprintf(shared->debug, "\n"); + } + else + { + if (PR_PENDING_INTERRUPT_ERROR != PR_GetError()) + { + if (NULL != shared->debug) PL_PrintError("Accept"); + shared->passed = PR_FALSE; + } + } + } while (running == shared->status); + if (NULL != buffer) PR_DELETE(buffer); +} /* Accept */ + +PRIntn Tmoacc(PRIntn argc, char **argv) +{ + PRStatus rv; + PRIntn exitStatus; + PRIntn index; + Shared *shared; + PLOptStatus os; + PRThread **thread; + PRNetAddr listenAddr; + PRSocketOptionData sockOpt; + PRIntn timeout = DEFAULT_TIMEOUT; + PRIntn threads = DEFAULT_THREADS; + PRIntn backlog = DEFAULT_BACKLOG; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + + PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R"); + + shared = PR_NEWZAP(Shared); + + shared->debug = NULL; + shared->passed = PR_TRUE; + shared->random = PR_TRUE; + shared->status = running; + shared->ml = PR_NewLock(); + shared->cv = PR_NewCondVar(shared->ml); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + shared->debug = PR_GetSpecialFD(PR_StandardError); + break; + case 'G': /* use global threads */ + thread_scope = PR_GLOBAL_THREAD; + break; + case 'b': /* size of listen backlog */ + backlog = atoi(opt->value); + break; + case 't': /* number of threads doing accept */ + threads = atoi(opt->value); + break; + case 'T': /* timeout used for network operations */ + timeout = atoi(opt->value); + break; + case 'R': /* randomize the timeout values */ + shared->random = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + if (0 == threads) threads = DEFAULT_THREADS; + if (0 == backlog) backlog = DEFAULT_BACKLOG; + if (0 == timeout) timeout = DEFAULT_TIMEOUT; + + PR_STDIO_INIT(); + memset(&listenAddr, 0, sizeof(listenAddr)); + rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr); + PR_ASSERT(PR_SUCCESS == rv); + + shared->timeout = PR_SecondsToInterval(timeout); + + /* First bind to the socket */ + shared->listenSock = PR_NewTCPSocket(); + if (shared->listenSock) + { + sockOpt.option = PR_SockOpt_Reuseaddr; + sockOpt.value.reuse_addr = PR_TRUE; + rv = PR_SetSocketOption(shared->listenSock, &sockOpt); + PR_ASSERT(PR_SUCCESS == rv); + rv = PR_Bind(shared->listenSock, &listenAddr); + if (rv != PR_FAILURE) + { + rv = PR_Listen(shared->listenSock, threads + backlog); + if (PR_SUCCESS == rv) + { + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); + for (index = 0; index < threads; ++index) + { + thread[index] = PR_CreateThread( + PR_USER_THREAD, Accept, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + PR_ASSERT(NULL != thread[index]); + } + + PR_Lock(shared->ml); + while (shared->status == running) + PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); + PR_Unlock(shared->ml); + for (index = 0; index < threads; ++index) + { + rv = PR_Interrupt(thread[index]); + PR_ASSERT(PR_SUCCESS== rv); + rv = PR_JoinThread(thread[index]); + PR_ASSERT(PR_SUCCESS== rv); + } + PR_DELETE(thread); + } + else + { + if (shared->debug) PL_PrintError("Listen"); + shared->passed = PR_FALSE; + } + } + else + { + if (shared->debug) PL_PrintError("Bind"); + shared->passed = PR_FALSE; + } + + PR_Close(shared->listenSock); + } + else + { + if (shared->debug) PL_PrintError("Create"); + shared->passed = PR_FALSE; + } + + PR_DestroyCondVar(shared->cv); + PR_DestroyLock(shared->ml); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), "%s\n", + ((shared->passed) ? "PASSED" : "FAILED")); + + exitStatus = (shared->passed) ? 0 : 1; + PR_DELETE(shared); + return exitStatus; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Tmoacc, argc, argv, 4) : -1; +} /* main */ + +/* tmoacc */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/tmocon.c b/src/libs/xpcom18a4/nsprpub/pr/tests/tmocon.c new file mode 100644 index 00000000..269e3003 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/tmocon.c @@ -0,0 +1,401 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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 Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/*********************************************************************** +** +** Name: tmocon.c +** +** Description: test client socket connection. +** +** Modification History: +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. +** The debug mode will print all of the printfs associated with this test. +** The regress mode will be the default mode. Since the regress tool limits +** the output to a one line status:PASS or FAIL,all of the printf statements +** have been handled with an if (debug_mode) statement. +***********************************************************************/ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "nspr.h" +#include "pprio.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include +#include +#include + +/* for getcwd */ +#if defined(XP_UNIX) || defined (XP_OS2_EMX) || defined(XP_BEOS) +#include +#elif defined(XP_PC) +#include +#endif + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + + +#define BASE_PORT 9867 + +#define DEFAULT_DALLY 1 +#define DEFAULT_THREADS 1 +#define DEFAULT_TIMEOUT 10 +#define DEFAULT_MESSAGES 100 +#define DEFAULT_MESSAGESIZE 100 + +static PRFileDesc *debug_out = NULL; + +typedef struct Shared +{ + PRBool random; + PRBool failed; + PRBool intermittant; + PRIntn debug; + PRInt32 messages; + PRIntervalTime dally; + PRIntervalTime timeout; + PRInt32 message_length; + PRNetAddr serverAddress; +} Shared; + +static PRIntervalTime Timeout(const Shared *shared) +{ + PRIntervalTime timeout = shared->timeout; + if (shared->random) + { + PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */ + PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */ + timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */ + } + return timeout; +} /* Timeout */ + +static void CauseTimeout(const Shared *shared) +{ + if (shared->intermittant) PR_Sleep(Timeout(shared)); +} /* CauseTimeout */ + +static PRStatus MakeReceiver(Shared *shared) +{ + PRStatus rv = PR_FAILURE; + if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback)) + { + char *argv[3]; + char path[1024 + sizeof("/tmoacc")]; + (void)getcwd(path, sizeof(path)); + (void)strcat(path, "/tmoacc"); +#ifdef XP_PC + (void)strcat(path, ".exe"); +#endif + argv[0] = path; + if (shared->debug > 0) + { + argv[1] = "-d"; + argv[2] = NULL; + } + else argv[1] = NULL; + if (shared->debug > 1) + PR_fprintf(debug_out, " creating accept process %s ...", path); + fflush(stdout); + rv = PR_CreateProcessDetached(path, argv, NULL, NULL); + if (PR_SUCCESS == rv) + { + if (shared->debug > 1) + PR_fprintf(debug_out, " wait 5 seconds"); + if (shared->debug > 1) + PR_fprintf(debug_out, " before connecting to accept process ..."); + fflush(stdout); + PR_Sleep(PR_SecondsToInterval(5)); + return rv; + } + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_CreateProcessDetached failed"); + } + return rv; +} /* MakeReceiver */ + +static void Connect(void *arg) +{ + PRStatus rv; + char *buffer = NULL; + PRFileDesc *clientSock; + Shared *shared = (Shared*)arg; + PRInt32 loop, bytes, flags = 0; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError); + + buffer = (char*)PR_MALLOC(shared->message_length); + + for (bytes = 0; bytes < shared->message_length; ++bytes) + buffer[bytes] = (char)bytes; + + descriptor.checksum = 0; + for (bytes = 0; bytes < shared->message_length; ++bytes) + { + PRUint32 overflow = descriptor.checksum & 0x80000000; + descriptor.checksum = (descriptor.checksum << 1); + if (0x00000000 != overflow) descriptor.checksum += 1; + descriptor.checksum += buffer[bytes]; + } + descriptor.checksum = PR_htonl(descriptor.checksum); + + for (loop = 0; loop < shared->messages; ++loop) + { + if (shared->debug > 1) + PR_fprintf(debug_out, "[%d]socket ... ", loop); + clientSock = PR_NewTCPSocket(); + if (clientSock) + { + /* + * We need to slow down the rate of generating connect requests, + * otherwise the listen backlog queue on the accept side may + * become full and we will get connection refused or timeout + * error. + */ + + PR_Sleep(shared->dally); + if (shared->debug > 1) + { + char buf[128]; + PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf)); + PR_fprintf(debug_out, "connecting to %s ... ", buf); + } + rv = PR_Connect( + clientSock, &shared->serverAddress, Timeout(shared)); + if (PR_SUCCESS == rv) + { + PRInt32 descriptor_length = (loop < (shared->messages - 1)) ? + shared->message_length : 0; + descriptor.length = PR_htonl(descriptor_length); + if (shared->debug > 1) + PR_fprintf( + debug_out, "sending %d bytes ... ", descriptor_length); + CauseTimeout(shared); /* might cause server to timeout */ + bytes = PR_Send( + clientSock, &descriptor, sizeof(descriptor), + flags, Timeout(shared)); + if (bytes != sizeof(descriptor)) + { + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_Send failed"); + } + if (0 != descriptor_length) + { + CauseTimeout(shared); + bytes = PR_Send( + clientSock, buffer, descriptor_length, + flags, Timeout(shared)); + if (bytes != descriptor_length) + { + shared->failed = PR_TRUE; + if (shared->debug > 0) + PL_FPrintError(debug_out, "PR_Send failed"); + } + } + if (shared->debug > 1) PR_fprintf(debug_out, "closing ... "); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + rv = PR_Close(clientSock); + if (shared->debug > 1) + { + if (PR_SUCCESS == rv) PR_fprintf(debug_out, "\n"); + else PL_FPrintError(debug_out, "shutdown failed"); + } + } + else + { + if (shared->debug > 1) PL_FPrintError(debug_out, "connect failed"); + PR_Close(clientSock); + if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR)) + { + if (MakeReceiver(shared) == PR_FAILURE) break; + } + else + { + if (shared->debug > 1) PR_fprintf(debug_out, " exiting\n"); + break; + } + } + } + else + { + shared->failed = PR_TRUE; + if (shared->debug > 0) PL_FPrintError(debug_out, "create socket"); + break; + } + } + + PR_DELETE(buffer); +} /* Connect */ + +int Tmocon(int argc, char **argv) +{ + /* + * USAGE + * -d turn on debugging output (default = off) + * -v turn on verbose output (default = off) + * -h dns name of host serving the connection (default = self) + * -i dally intermittantly to cause timeouts (default = off) + * -m number of messages to send (default = 100) + * -s size of each message (default = 100) + * -t number of threads sending (default = 1) + * -G use global threads (default = local) + * -T timeout on I/O operations (seconds) (default = 10) + * -D dally between connect requests (seconds)(default = 0) + * -R randomize the dally types around 'T' (default = no) + */ + + PRStatus rv; + int exitStatus; + PLOptStatus os; + Shared *shared = NULL; + PRThread **thread = NULL; + PRIntn index, threads = DEFAULT_THREADS; + PRThreadScope thread_scope = PR_LOCAL_THREAD; + PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT; + PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:"); + + shared = PR_NEWZAP(Shared); + + shared->debug = 0; + shared->failed = PR_FALSE; + shared->random = PR_FALSE; + shared->messages = DEFAULT_MESSAGES; + shared->message_length = DEFAULT_MESSAGESIZE; + + PR_STDIO_INIT(); + memset(&shared->serverAddress, 0, sizeof(shared->serverAddress)); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress); + PR_ASSERT(PR_SUCCESS == rv); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': + if (0 == shared->debug) shared->debug = 1; + break; + case 'v': + if (0 == shared->debug) shared->debug = 2; + break; + case 'i': + shared->intermittant = PR_TRUE; + break; + case 'R': + shared->random = PR_TRUE; + break; + case 'G': + thread_scope = PR_GLOBAL_THREAD; + break; + case 'h': /* the value for backlock */ + { + PRIntn es = 0; + PRHostEnt host; + char buffer[1024]; + (void)PR_GetHostByName( + opt->value, buffer, sizeof(buffer), &host); + es = PR_EnumerateHostEnt( + es, &host, BASE_PORT, &shared->serverAddress); + PR_ASSERT(es > 0); + } + break; + case 'm': /* number of messages to send */ + shared->messages = atoi(opt->value); + break; + case 't': /* number of threads sending */ + threads = atoi(opt->value); + break; + case 'D': /* dally time between transmissions */ + dally = atoi(opt->value); + break; + case 'T': /* timeout on I/O operations */ + timeout = atoi(opt->value); + break; + case 's': /* total size of each message */ + shared->message_length = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == timeout) timeout = DEFAULT_TIMEOUT; + if (0 == threads) threads = DEFAULT_THREADS; + if (0 == shared->messages) shared->messages = DEFAULT_MESSAGES; + if (0 == shared->message_length) shared->message_length = DEFAULT_MESSAGESIZE; + + shared->dally = PR_SecondsToInterval(dally); + shared->timeout = PR_SecondsToInterval(timeout); + + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); + + for (index = 0; index < threads; ++index) + thread[index] = PR_CreateThread( + PR_USER_THREAD, Connect, shared, + PR_PRIORITY_NORMAL, thread_scope, + PR_JOINABLE_THREAD, 0); + for (index = 0; index < threads; ++index) + rv = PR_JoinThread(thread[index]); + + PR_DELETE(thread); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), "%s\n", + ((shared->failed) ? "FAILED" : "PASSED")); + exitStatus = (shared->failed) ? 1 : 0; + PR_DELETE(shared); + return exitStatus; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Tmocon, argc, argv, 4) : -1; +} /* main */ + +/* tmocon.c */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/tpd.c b/src/libs/xpcom18a4/nsprpub/pr/tests/tpd.c new file mode 100644 index 00000000..c9bc5c78 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/tpd.c @@ -0,0 +1,334 @@ +/* -*- 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 ***** */ + +/* +** File: tpd.c +** Description: Exercising the thread private data bailywick. +*/ + +#include "prmem.h" +#include "prinit.h" +#include "prlog.h" +#include "prprf.h" +#include "prthread.h" +#include "prtypes.h" + +#if defined(XP_MAC) +#include "pprio.h" +#else +#include "private/pprio.h" +#endif + +#include "plgetopt.h" + +static PRUintn key[128]; +static PRIntn debug = 0; +static PRBool failed = PR_FALSE; +static PRBool should = PR_TRUE; +static PRBool did = PR_TRUE; +static PRFileDesc *fout = NULL; + +static void PrintProgress(PRIntn line) +{ + failed = failed || (should && !did); + failed = failed || (!should && did); + if (debug > 0) + { +#if defined(WIN16) + printf( + "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); +#else + PR_fprintf( + fout, "@ line %d destructor should%s have been called and was%s\n", + line, ((should) ? "" : " NOT"), ((did) ? "" : " NOT")); +#endif + } +} /* PrintProgress */ + +static void MyAssert(const char *expr, const char *file, PRIntn line) +{ + if (debug > 0) + (void)PR_fprintf(fout, "'%s' in file: %s: %d\n", expr, file, line); +} /* MyAssert */ + +#define MY_ASSERT(_expr) \ + ((_expr)?((void)0):MyAssert(# _expr,__FILE__,__LINE__)) + + +static void PR_CALLBACK Destructor(void *data) +{ + MY_ASSERT(NULL != data); + if (should) did = PR_TRUE; + else failed = PR_TRUE; + /* + * We don't actually free the storage since it's actually allocated + * on the stack. Normally, this would not be the case and this is + * the opportunity to free whatever. + PR_Free(data); + */ +} /* Destructor */ + +static void PR_CALLBACK Thread(void *null) +{ + void *pd; + PRStatus rv; + PRUintn keys; + char *key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = PR_GetThreadPrivate(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + + /* put in keys and leave them there for thread exit */ + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + did = PR_FALSE; should = PR_TRUE; + +} /* Thread */ + +static PRIntn PR_CALLBACK Tpd(PRIntn argc, char **argv) +{ + void *pd; + PRStatus rv; + PRUintn keys; + PRThread *thread; + char *key_string[] = { + "Key #0", "Key #1", "Key #2", "Key #3", + "Bogus #5", "Bogus #6", "Bogus #7", "Bogus #8"}; + + fout = PR_STDOUT; + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 8; ++keys) + { + pd = PR_GetThreadPrivate(key[keys]); + MY_ASSERT(NULL == pd); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + for (keys = 4; keys < 8; ++keys) + key[keys] = 4096; /* set to invalid value */ + did = should = PR_FALSE; + for (keys = 4; keys < 8; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_FAILURE == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], key_string[keys]); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 0; keys < 4; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_NewThreadPrivateIndex(&key[keys], Destructor); + MY_ASSERT(PR_SUCCESS == rv); + rv = PR_SetThreadPrivate(key[keys], "EXTENSION"); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = PR_FALSE; should = PR_TRUE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + PrintProgress(__LINE__); + + did = should = PR_FALSE; + for (keys = 8; keys < 127; ++keys) + { + rv = PR_SetThreadPrivate(key[keys], NULL); + MY_ASSERT(PR_SUCCESS == rv); + } + + thread = PR_CreateThread( + PR_USER_THREAD, Thread, NULL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + (void)PR_JoinThread(thread); + + PrintProgress(__LINE__); + +#if defined(WIN16) + printf( + "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); +#else + (void)PR_fprintf( + fout, "%s\n",((PR_TRUE == failed) ? "FAILED" : "PASSED")); +#endif + + return 0; + +} /* Tpd */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl:r:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + PR_STDIO_INIT(); + return PR_Initialize(Tpd, argc, argv, 0); +} /* main */ + +/* tpd.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/udpsrv.c b/src/libs/xpcom18a4/nsprpub/pr/tests/udpsrv.c new file mode 100644 index 00000000..b9b615a2 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/udpsrv.c @@ -0,0 +1,566 @@ +/* -*- 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 ***** */ + +/******************************************************************* +** udpsrc.c -- Test basic function of UDP server +** +** udpsrv operates on the same machine with program udpclt. +** udpsrv is the server side of a udp sockets application. +** udpclt is the client side of a udp sockets application. +** +** The test is designed to assist developers in porting/debugging +** the UDP socket functions of NSPR. +** +** This test is not a stress test. +** +** main() starts two threads: UDP_Server() and UDP_Client(); +** main() uses PR_JoinThread() to wait for the threads to complete. +** +** UDP_Server() does repeated recvfrom()s from a socket. +** He detects an EOF condition set by UDP_Client(). For each +** packet received by UDP_Server(), he checks its content for +** expected content, then sends the packet back to UDP_Client(). +** +** UDP_Client() sends packets to UDP_Server() using sendto() +** he recieves packets back from the server via recvfrom(). +** After he sends enough packets containing UDP_AMOUNT_TO_WRITE +** bytes of data, he sends an EOF message. +** +** The test issues a pass/fail message at end. +** +** Notes: +** The variable "_debug_on" can be set to 1 to cause diagnostic +** messages related to client/server synchronization. Useful when +** the test hangs. +** +** Error messages are written to stdout. +** +******************************************************************** +*/ +/* --- include files --- */ +#include "nspr.h" +#include "prpriv.h" + +#include "plgetopt.h" +#include "prttools.h" + +#include +#include +#include +#include + +#ifdef XP_PC +#define mode_t int +#endif + +#define UDP_BUF_SIZE 4096 +#define UDP_DGRAM_SIZE 128 +#define UDP_AMOUNT_TO_WRITE (PRInt32)((UDP_DGRAM_SIZE * 1000l) +1) +#define NUM_UDP_CLIENTS 1 +#define NUM_UDP_DATAGRAMS_PER_CLIENT 5 +#define UDP_SERVER_PORT 9050 +#define UDP_CLIENT_PORT 9053 +#define MY_INADDR PR_INADDR_ANY +#define PEER_INADDR PR_INADDR_LOOPBACK + +#define UDP_TIMEOUT 400000 +/* #define UDP_TIMEOUT PR_INTERVAL_NO_TIMEOUT */ + +/* --- static data --- */ +static PRIntn _debug_on = 0; +static PRBool passed = PR_TRUE; +static PRUint32 cltBytesRead = 0; +static PRUint32 srvBytesRead = 0; +static PRFileDesc *output = NULL; + +/* --- static function declarations --- */ +#define DPRINTF(arg) if (_debug_on) PR_fprintf(output, arg) + + + +/******************************************************************* +** ListNetAddr() -- Display the Net Address on stdout +** +** Description: displays the component parts of a PRNetAddr struct +** +** Arguments: address of PRNetAddr structure to display +** +** Returns: void +** +** Notes: +** +******************************************************************** +*/ +void ListNetAddr( char *msg, PRNetAddr *na ) +{ + char mbuf[256]; + + sprintf( mbuf, "ListNetAddr: %s family: %d, port: %d, ip: %8.8X\n", + msg, na->inet.family, PR_ntohs( na->inet.port), PR_ntohl(na->inet.ip) ); +#if 0 + DPRINTF( mbuf ); +#endif +} /* --- end ListNetAddr() --- */ + +/******************************************************************** +** UDP_Server() -- Test a UDP server application +** +** Description: The Server side of a UDP Client/Server application. +** +** Arguments: none +** +** Returns: void +** +** Notes: +** +** +******************************************************************** +*/ +static void PR_CALLBACK UDP_Server( void *arg ) +{ + static char svrBuf[UDP_BUF_SIZE]; + PRFileDesc *svrSock; + PRInt32 rv; + PRNetAddr netaddr; + PRBool bound = PR_FALSE; + PRBool endOfInput = PR_FALSE; + PRInt32 numBytes = UDP_DGRAM_SIZE; + + DPRINTF("udpsrv: UDP_Server(): starting\n" ); + + /* --- Create the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Creating UDP Socket\n" ); + svrSock = PR_NewUDPSocket(); + if ( svrSock == NULL ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_NewUDPSocket() returned NULL\n" ); + return; + } + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); + netaddr.inet.ip = PR_htonl( MY_INADDR ); + + /* --- Bind the socket --- */ + while ( !bound ) + { + DPRINTF("udpsrv: UDP_Server(): Binding socket\n" ); + rv = PR_Bind( svrSock, &netaddr ); + if ( rv < 0 ) + { + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ + PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); + PR_Sleep( PR_MillisecondsToInterval( 2000 )); + continue; + } + else + { + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, "udpsrv: UDP_Server(): \ + PR_Bind(): failed: %ld with error: %ld\n", + rv, PR_GetError() ); + PR_Close( svrSock ); + return; + } + } + else + bound = PR_TRUE; + } + ListNetAddr( "UDP_Server: after bind", &netaddr ); + + /* --- Recv the socket --- */ + while( !endOfInput ) + { + DPRINTF("udpsrv: UDP_Server(): RecvFrom() socket\n" ); + rv = PR_RecvFrom( svrSock, svrBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( svrSock ); + return; + } + ListNetAddr( "UDP_Server after RecvFrom", &netaddr ); + + srvBytesRead += rv; + + if ( svrBuf[0] == 'E' ) + { + DPRINTF("udpsrv: UDP_Server(): EOF on input detected\n" ); + endOfInput = PR_TRUE; + } + + /* --- Send the socket --- */ + DPRINTF("udpsrv: UDP_Server(): SendTo(): socket\n" ); + rv = PR_SendTo( svrSock, svrBuf, rv, 0, &netaddr, PR_INTERVAL_NO_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( svrSock ); + return; + } + ListNetAddr( "UDP_Server after SendTo", &netaddr ); + } + + /* --- Close the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); + rv = PR_Close( svrSock ); + if ( rv != PR_SUCCESS ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Server(): PR_Close(): failed to close socket\n" ); + return; + } + + DPRINTF("udpsrv: UDP_Server(): Normal end\n" ); +} /* --- end UDP_Server() --- */ + + +static char cltBuf[UDP_BUF_SIZE]; +static char cltBufin[UDP_BUF_SIZE]; +/******************************************************************** +** UDP_Client() -- Test a UDP client application +** +** Description: +** +** Arguments: +** +** +** Returns: +** 0 -- Successful execution +** 1 -- Test failed. +** +** Notes: +** +** +******************************************************************** +*/ +static void PR_CALLBACK UDP_Client( void *arg ) +{ + PRFileDesc *cltSock; + PRInt32 rv; + PRBool bound = PR_FALSE; + PRNetAddr netaddr; + PRNetAddr netaddrx; + PRBool endOfInput = PR_FALSE; + PRInt32 numBytes = UDP_DGRAM_SIZE; + PRInt32 writeThisMany = UDP_AMOUNT_TO_WRITE; + int i; + + + DPRINTF("udpsrv: UDP_Client(): starting\n" ); + + /* --- Create the socket --- */ + cltSock = PR_NewUDPSocket(); + if ( cltSock == NULL ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_NewUDPSocket() returned NULL\n" ); + return; + } + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.ip = PR_htonl( MY_INADDR ); + netaddr.inet.port = PR_htons( UDP_CLIENT_PORT ); + + /* --- Initialize the write buffer --- */ + for ( i = 0; i < UDP_BUF_SIZE ; i++ ) + cltBuf[i] = i; + + /* --- Bind the socket --- */ + while ( !bound ) + { + DPRINTF("udpsrv: UDP_Client(): Binding socket\n" ); + rv = PR_Bind( cltSock, &netaddr ); + if ( rv < 0 ) + { + if ( PR_GetError() == PR_ADDRESS_IN_USE_ERROR ) + { + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): reports: PR_ADDRESS_IN_USE_ERROR\n"); + PR_Sleep( PR_MillisecondsToInterval( 2000 )); + continue; + } + else + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Bind(): failed: %ld with error: %ld\n", + rv, PR_GetError() ); + PR_Close( cltSock ); + return; + } + } + else + bound = PR_TRUE; + } + ListNetAddr( "UDP_Client after Bind", &netaddr ); + + /* --- Initialize the sockaddr_in structure --- */ + memset( &netaddr, 0, sizeof( netaddr )); + netaddr.inet.family = PR_AF_INET; + netaddr.inet.ip = PR_htonl( PEER_INADDR ); + netaddr.inet.port = PR_htons( UDP_SERVER_PORT ); + + /* --- send and receive packets until no more data left */ + while( !endOfInput ) + { + /* + ** Signal EOF in the data stream on the last packet + */ + if ( writeThisMany <= UDP_DGRAM_SIZE ) + { + DPRINTF("udpsrv: UDP_Client(): Send EOF packet\n" ); + cltBuf[0] = 'E'; + endOfInput = PR_TRUE; + } + + /* --- SendTo the socket --- */ + if ( writeThisMany > UDP_DGRAM_SIZE ) + numBytes = UDP_DGRAM_SIZE; + else + numBytes = writeThisMany; + writeThisMany -= numBytes; + { + char mbuf[256]; + sprintf( mbuf, "udpsrv: UDP_Client(): write_this_many: %d, numbytes: %d\n", + writeThisMany, numBytes ); + DPRINTF( mbuf ); + } + + DPRINTF("udpsrv: UDP_Client(): SendTo(): socket\n" ); + rv = PR_SendTo( cltSock, cltBuf, numBytes, 0, &netaddr, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) + PR_fprintf(output, + "udpsrv: UDP_Client(): PR_SendTo(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( cltSock ); + return; + } + ListNetAddr( "UDP_Client after SendTo", &netaddr ); + + /* --- RecvFrom the socket --- */ + memset( cltBufin, 0, UDP_BUF_SIZE ); + DPRINTF("udpsrv: UDP_Client(): RecvFrom(): socket\n" ); + rv = PR_RecvFrom( cltSock, cltBufin, numBytes, 0, &netaddrx, UDP_TIMEOUT ); + if ( rv == -1 ) + { + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_RecvFrom(): failed with error: %ld\n", + PR_GetError() ); + PR_Close( cltSock ); + return; + } + ListNetAddr( "UDP_Client after RecvFrom()", &netaddr ); + cltBytesRead += rv; + + /* --- verify buffer --- */ + for ( i = 0; i < rv ; i++ ) + { + if ( cltBufin[i] != i ) + { + /* --- special case, end of input --- */ + if ( endOfInput && i == 0 && cltBufin[0] == 'E' ) + continue; + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): return data mismatch\n" ); + PR_Close( cltSock ); + return; + } + } + if (debug_mode) PR_fprintf(output, "."); + } + + /* --- Close the socket --- */ + DPRINTF("udpsrv: UDP_Server(): Closing socket\n" ); + rv = PR_Close( cltSock ); + if ( rv != PR_SUCCESS ) + { + passed = PR_FALSE; + if (debug_mode) PR_fprintf(output, + "udpsrv: UDP_Client(): PR_Close(): failed to close socket\n" ); + return; + } + DPRINTF("udpsrv: UDP_Client(): ending\n" ); +} /* --- end UDP_Client() --- */ + +/******************************************************************** +** main() -- udpsrv +** +** arguments: +** +** Returns: +** 0 -- Successful execution +** 1 -- Test failed. +** +** Description: +** +** Standard test case setup. +** +** Calls the function UDP_Server() +** +******************************************************************** +*/ + +int main(int argc, char **argv) +{ + PRThread *srv, *clt; +/* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d -v + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dv"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = 1; + break; + case 'v': /* verbose mode */ + _debug_on = 1; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + PR_STDIO_INIT(); + output = PR_STDERR; + +#ifdef XP_MAC + SetupMacPrintfLog("udpsrv.log"); +#endif + + PR_SetConcurrency(4); + + /* + ** Create the Server thread + */ + DPRINTF( "udpsrv: Creating Server Thread\n" ); + srv = PR_CreateThread( PR_USER_THREAD, + UDP_Server, + (void *) 0, + PR_PRIORITY_LOW, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + if ( srv == NULL ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); + passed = PR_FALSE; + } + + /* + ** Give the Server time to Start + */ + DPRINTF( "udpsrv: Pausing to allow Server to start\n" ); + PR_Sleep( PR_MillisecondsToInterval(200) ); + + /* + ** Create the Client thread + */ + DPRINTF( "udpsrv: Creating Client Thread\n" ); + clt = PR_CreateThread( PR_USER_THREAD, + UDP_Client, + (void *) 0, + PR_PRIORITY_LOW, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + if ( clt == NULL ) + { + if (debug_mode) PR_fprintf(output, "udpsrv: Cannot create server thread\n" ); + passed = PR_FALSE; + } + + /* + ** + */ + DPRINTF("udpsrv: Waiting to join Server & Client Threads\n" ); + PR_JoinThread( srv ); + PR_JoinThread( clt ); + + /* + ** Evaluate test results + */ + if (debug_mode) PR_fprintf(output, "\n\nudpsrv: main(): cltBytesRead(%ld), \ + srvBytesRead(%ld), expected(%ld)\n", + cltBytesRead, srvBytesRead, UDP_AMOUNT_TO_WRITE ); + if ( cltBytesRead != srvBytesRead || cltBytesRead != UDP_AMOUNT_TO_WRITE ) + { + passed = PR_FALSE; + } + PR_Cleanup(); + if ( passed ) + return 0; + else + return 1; +} /* --- end main() --- */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/ut_ttools.h b/src/libs/xpcom18a4/nsprpub/pr/tests/ut_ttools.h new file mode 100644 index 00000000..dc38f316 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/ut_ttools.h @@ -0,0 +1,43 @@ +/* -*- 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 ***** */ + +/* Used in Regress Tool */ +#define NOSTATUS 2 +#define PASS 1 +#define FAIL 0 + +PRIntn debug_mode=0; diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/vercheck.c b/src/libs/xpcom18a4/nsprpub/pr/tests/vercheck.c new file mode 100644 index 00000000..eed5006a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/vercheck.c @@ -0,0 +1,108 @@ +/* -*- 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 ***** */ + +/* + * File: vercheck.c + * + * Description: + * This test tests the PR_VersionCheck() function. The + * compatible_version and incompatible_version arrays + * need to be updated for each patch or release. + * + * Tested areas: library version compatibility check. + */ + +#include "prinit.h" + +#include +#include + +/* + * This release (4.5) is backward compatible with the + * 4.0.x, 4.1.x, 4.2.x, 4.3.x, and 4.4.x releases. It, of course, + * is compatible with itself. + */ +static char *compatible_version[] = { + "4.0", "4.0.1", "4.1", "4.1.1", "4.1.2", "4.1.3", + "4.2", "4.2.1", "4.2.2", "4.3", "4.4", "4.4.1", PR_VERSION +}; + +/* + * This release is not backward compatible with the old + * NSPR 2.1 and 3.x releases. + * + * Any release is incompatible with future releases and + * patches. + */ +static char *incompatible_version[] = { + "2.1 19980529", + "3.0", "3.0.1", + "3.1", "3.1.1", "3.1.2", "3.1.3", + "3.5", "3.5.1", + "4.5.3", + "4.6", "4.6.1", + "10.0", "11.1", "12.14.20" +}; + +int main() +{ + int idx; + int num_compatible = sizeof(compatible_version) / sizeof(char *); + int num_incompatible = sizeof(incompatible_version) / sizeof(char *); + + printf("NSPR release %s:\n", PR_VERSION); + for (idx = 0; idx < num_compatible; idx++) { + if (PR_VersionCheck(compatible_version[idx]) == PR_FALSE) { + fprintf(stderr, "Should be compatible with version %s\n", + compatible_version[idx]); + exit(1); + } + printf("Compatible with version %s\n", compatible_version[idx]); + } + + for (idx = 0; idx < num_incompatible; idx++) { + if (PR_VersionCheck(incompatible_version[idx]) == PR_TRUE) { + fprintf(stderr, "Should be incompatible with version %s\n", + incompatible_version[idx]); + exit(1); + } + printf("Incompatible with version %s\n", incompatible_version[idx]); + } + + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/version.c b/src/libs/xpcom18a4/nsprpub/pr/tests/version.c new file mode 100644 index 00000000..597f5571 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/version.c @@ -0,0 +1,123 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "prlink.h" +#include "prvrsion.h" + +#include "plerror.h" +#include "plgetopt.h" + +PR_IMPORT(const PRVersionDescription *) libVersionPoint(void); + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv = 1; + PLOptStatus os; + PRIntn verbosity = 0; + PRLibrary *runtime = NULL; + const char *library_name = NULL; + const PRVersionDescription *version_info; + char buffer[100]; + PRExplodedTime exploded; + PLOptState *opt = PL_CreateOptState(argc, argv, "d"); + + PRFileDesc *err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* fully qualified library name */ + library_name = opt->value; + break; + case 'd': /* verbodity */ + verbosity += 1; + break; + default: + PR_fprintf(err, "Usage: version [-d] {fully qualified library name}\n"); + return 2; /* but not a lot else */ + } + } + PL_DestroyOptState(opt); + + if (NULL != library_name) + { + runtime = PR_LoadLibrary(library_name); + if (NULL == runtime) { + PL_FPrintError(err, "PR_LoadLibrary"); + return 3; + } else { + versionEntryPointType versionPoint = (versionEntryPointType) + PR_FindSymbol(runtime, "libVersionPoint"); + if (NULL == versionPoint) { + PL_FPrintError(err, "PR_FindSymbol"); + return 4; + } + version_info = versionPoint(); + } + } else + version_info = libVersionPoint(); /* NSPR's version info */ + + (void)PR_fprintf(err, "Runtime library version information\n"); + PR_ExplodeTime( + version_info->buildTime, PR_GMTParameters, &exploded); + (void)PR_FormatTime( + buffer, sizeof(buffer), "%d %b %Y %H:%M:%S", &exploded); + (void)PR_fprintf(err, " Build time: %s GMT\n", buffer); + (void)PR_fprintf( + err, " Build time: %s\n", version_info->buildTimeString); + (void)PR_fprintf( + err, " %s V%u.%u.%u (%s%s%s)\n", + version_info->description, + version_info->vMajor, + version_info->vMinor, + version_info->vPatch, + (version_info->beta ? " beta " : ""), + (version_info->debug ? " debug " : ""), + (version_info->special ? " special" : "")); + (void)PR_fprintf(err, " filename: %s\n", version_info->filename); + (void)PR_fprintf(err, " security: %s\n", version_info->security); + (void)PR_fprintf(err, " copyright: %s\n", version_info->copyright); + (void)PR_fprintf(err, " comment: %s\n", version_info->comment); + rv = 0; + return rv; +} + +/* version.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/.cvsignore b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/Makefile.in b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/Makefile.in new file mode 100644 index 00000000..ead153ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/Makefile.in @@ -0,0 +1,99 @@ +# +# ***** 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 ***** + +#! gmake + + + +MOD_DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +W16STDIO = $(MOD_DEPTH)/pr/src/md/windows/$(OBJDIR)/w16stdio.$(OBJ_SUFFIX) + +CSRCS = poppad.c \ + popfile.c \ + popfont.c \ + popfind.c \ + popprnt0.c + + +INCLUDES = -I$(dist_includedir) +LIBPR = $(dist_libdir)/nspr$(MOD_MAJOR_VERSION).lib +LIBPLDS = $(dist_libdir)/plds$(MOD_MAJOR_VERSION).lib +TARGETS = $(OBJDIR)/poppad.exe +OS_CFLAGS = $(OS_EXE_CFLAGS) + +include $(topsrcdir)/config/rules.mk + + +ifeq ($(OS_TARGET),WIN16) +$(OBJDIR)/poppad.exe: $(OBJS) + @$(MAKE_OBJDIR) + echo system windows >w16link + echo name $@ >>w16link + echo option map >>w16link + echo option stack=16K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo file >>w16link + echo $(OBJDIR)\\poppad.$(OBJ_SUFFIX), >>w16link + echo $(OBJDIR)\\popfile.$(OBJ_SUFFIX), >>w16link + echo $(OBJDIR)\\popfont.$(OBJ_SUFFIX), >>w16link + echo $(OBJDIR)\\popfind.$(OBJ_SUFFIX), >>w16link + echo $(OBJDIR)\\popprnt0.$(OBJ_SUFFIX), >>w16link + echo $(W16STDIO) >>w16link + echo library $(LIBPR) >>w16link + echo library $(LIBPLDS) >>w16link + echo library clibl, commdlg >>w16link + echo library winsock.lib >>w16link + wlink @w16link. + wrc -bt=windows poppad.rc $(OBJDIR)\\poppad.exe +else +$(OBJDIR)/poppad.exe: $(OBJS) + link $(LDOPTS) $< $(LIBPLC) $(LIBPR) wsock32.lib -out:$@ +endif + +export:: $(TARGETS) + + +clean:: + rm -rf $(TARGETS) diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfile.c b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfile.c new file mode 100644 index 00000000..9aa7187d --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfile.c @@ -0,0 +1,167 @@ +/* -*- 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 ***** */ + +/*------------------------------------------ + POPFILE.C -- Popup Editor File Functions + (c) Charles Petzold, 1992 + ------------------------------------------*/ + +#include +#include +#include + +static OPENFILENAME ofn ; + +void PopFileInitialize (HWND hwnd) + { + static char *szFilter[] = { "Text Files (*.TXT)", "*.txt", + "ASCII Files (*.ASC)", "*.asc", + "All Files (*.*)", "*.*", + "" } ; + + ofn.lStructSize = sizeof (OPENFILENAME) ; + ofn.hwndOwner = hwnd ; + ofn.hInstance = NULL ; + ofn.lpstrFilter = szFilter [0] ; + ofn.lpstrCustomFilter = NULL ; + ofn.nMaxCustFilter = 0 ; + ofn.nFilterIndex = 0 ; + ofn.lpstrFile = NULL ; // Set in Open and Close functions + ofn.nMaxFile = _MAX_PATH ; + ofn.lpstrFileTitle = NULL ; // Set in Open and Close functions + ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT ; + ofn.lpstrInitialDir = NULL ; + ofn.lpstrTitle = NULL ; + ofn.Flags = 0 ; // Set in Open and Close functions + ofn.nFileOffset = 0 ; + ofn.nFileExtension = 0 ; + ofn.lpstrDefExt = "txt" ; + ofn.lCustData = 0L ; + ofn.lpfnHook = NULL ; + ofn.lpTemplateName = NULL ; + } + +BOOL PopFileOpenDlg (HWND hwnd, LPSTR lpstrFileName, LPSTR lpstrTitleName) + { + ofn.hwndOwner = hwnd ; + ofn.lpstrFile = lpstrFileName ; + ofn.lpstrFileTitle = lpstrTitleName ; + ofn.Flags = OFN_CREATEPROMPT ; + + return GetOpenFileName (&ofn) ; + } + +BOOL PopFileSaveDlg (HWND hwnd, LPSTR lpstrFileName, LPSTR lpstrTitleName) + { + ofn.hwndOwner = hwnd ; + ofn.lpstrFile = lpstrFileName ; + ofn.lpstrFileTitle = lpstrTitleName ; + ofn.Flags = OFN_OVERWRITEPROMPT ; + + return GetSaveFileName (&ofn) ; + } + +static long PopFileLength (int hFile) + { + long lCurrentPos = _llseek (hFile, 0L, 1) ; + long lFileLength = _llseek (hFile, 0L, 2) ; + + _llseek (hFile, lCurrentPos, 0) ; + + return lFileLength ; + } + +BOOL PopFileRead (HWND hwndEdit, LPSTR lpstrFileName) + { + long lLength ; + HANDLE hBuffer ; + int hFile ; + LPSTR lpstrBuffer ; + + if (-1 == (hFile = _lopen (lpstrFileName, OF_READ | OF_SHARE_DENY_WRITE))) + return FALSE ; + + if ((lLength = PopFileLength (hFile)) >= 32000) + { + _lclose (hFile) ; + return FALSE ; + } + + if (NULL == (hBuffer = GlobalAlloc (GHND, lLength + 1))) + { + _lclose (hFile) ; + return FALSE ; + } + + lpstrBuffer = GlobalLock (hBuffer) ; + _lread (hFile, lpstrBuffer, (WORD) lLength) ; + _lclose (hFile) ; + lpstrBuffer [(WORD) lLength] = '\0' ; + + SetWindowText (hwndEdit, lpstrBuffer) ; + GlobalUnlock (hBuffer) ; + GlobalFree (hBuffer) ; + + return TRUE ; + } + +BOOL PopFileWrite (HWND hwndEdit, LPSTR lpstrFileName) + { + HANDLE hBuffer ; + int hFile ; + LPSTR lpstrBuffer ; + WORD wLength ; + + if (-1 == (hFile = _lopen (lpstrFileName, OF_WRITE | OF_SHARE_EXCLUSIVE))) + if (-1 == (hFile = _lcreat (lpstrFileName, 0))) + return FALSE ; + + wLength = GetWindowTextLength (hwndEdit) ; + hBuffer = (HANDLE) SendMessage (hwndEdit, EM_GETHANDLE, 0, 0L) ; + lpstrBuffer = (LPSTR) LocalLock (hBuffer) ; + + if (wLength != _lwrite (hFile, lpstrBuffer, wLength)) + { + _lclose (hFile) ; + return FALSE ; + } + + _lclose (hFile) ; + LocalUnlock (hBuffer) ; + + return TRUE ; + } diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfind.c b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfind.c new file mode 100644 index 00000000..023095ea --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfind.c @@ -0,0 +1,149 @@ +/* -*- 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 ***** */ + +/*-------------------------------------------------------- + POPFIND.C -- Popup Editor Search and Replace Functions + (c) Charles Petzold, 1992 + --------------------------------------------------------*/ + +#include +#include +#include +#define MAX_STRING_LEN 256 + +static char szFindText [MAX_STRING_LEN] ; +static char szReplText [MAX_STRING_LEN] ; + +HWND PopFindFindDlg (HWND hwnd) + { + static FINDREPLACE fr ; // must be static for modeless dialog!!! + + fr.lStructSize = sizeof (FINDREPLACE) ; + fr.hwndOwner = hwnd ; + fr.hInstance = NULL ; + fr.Flags = FR_HIDEUPDOWN | FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD ; + fr.lpstrFindWhat = szFindText ; + fr.lpstrReplaceWith = NULL ; + fr.wFindWhatLen = sizeof (szFindText) ; + fr.wReplaceWithLen = 0 ; + fr.lCustData = 0 ; + fr.lpfnHook = NULL ; + fr.lpTemplateName = NULL ; + + return FindText (&fr) ; + } + +HWND PopFindReplaceDlg (HWND hwnd) + { + static FINDREPLACE fr ; // must be static for modeless dialog!!! + + fr.lStructSize = sizeof (FINDREPLACE) ; + fr.hwndOwner = hwnd ; + fr.hInstance = NULL ; + fr.Flags = FR_HIDEUPDOWN | FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD ; + fr.lpstrFindWhat = szFindText ; + fr.lpstrReplaceWith = szReplText ; + fr.wFindWhatLen = sizeof (szFindText) ; + fr.wReplaceWithLen = sizeof (szReplText) ; + fr.lCustData = 0 ; + fr.lpfnHook = NULL ; + fr.lpTemplateName = NULL ; + + return ReplaceText (&fr) ; + } + +BOOL PopFindFindText (HWND hwndEdit, int *piSearchOffset, LPFINDREPLACE lpfr) + { + int iPos ; + LOCALHANDLE hLocal ; + LPSTR lpstrDoc, lpstrPos ; + + // Get a pointer to the edit document + + hLocal = (HWND) SendMessage (hwndEdit, EM_GETHANDLE, 0, 0L) ; + lpstrDoc = (LPSTR) LocalLock (hLocal) ; + + // Search the document for the find string + + lpstrPos = _fstrstr (lpstrDoc + *piSearchOffset, lpfr->lpstrFindWhat) ; + LocalUnlock (hLocal) ; + + // Return an error code if the string cannot be found + + if (lpstrPos == NULL) + return FALSE ; + + // Find the position in the document and the new start offset + + iPos = lpstrPos - lpstrDoc ; + *piSearchOffset = iPos + _fstrlen (lpfr->lpstrFindWhat) ; + + // Select the found text + + SendMessage (hwndEdit, EM_SETSEL, 0, + MAKELONG (iPos, *piSearchOffset)) ; + + return TRUE ; + } + +BOOL PopFindNextText (HWND hwndEdit, int *piSearchOffset) + { + FINDREPLACE fr ; + + fr.lpstrFindWhat = szFindText ; + + return PopFindFindText (hwndEdit, piSearchOffset, &fr) ; + } + +BOOL PopFindReplaceText (HWND hwndEdit, int *piSearchOffset, LPFINDREPLACE lpfr) + { + // Find the text + + if (!PopFindFindText (hwndEdit, piSearchOffset, lpfr)) + return FALSE ; + + // Replace it + + SendMessage (hwndEdit, EM_REPLACESEL, 0, (long) lpfr->lpstrReplaceWith) ; + + return TRUE ; + } + +BOOL PopFindValidFind (void) + { + return *szFindText != '\0' ; + } diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfont.c b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfont.c new file mode 100644 index 00000000..5f28af70 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popfont.c @@ -0,0 +1,94 @@ +/* -*- 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 ***** */ + +/*------------------------------------------ + POPFONT.C -- Popup Editor Font Functions + (c) Charles Petzold, 1992 + ------------------------------------------*/ + +#include +#include + +static LOGFONT logfont ; +static HFONT hFont ; + +BOOL PopFontChooseFont (HWND hwnd) + { + CHOOSEFONT cf ; + + cf.lStructSize = sizeof (CHOOSEFONT) ; + cf.hwndOwner = hwnd ; + cf.hDC = NULL ; + cf.lpLogFont = &logfont ; + cf.iPointSize = 0 ; + cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS + | CF_EFFECTS ; + cf.rgbColors = 0L ; + cf.lCustData = 0L ; + cf.lpfnHook = NULL ; + cf.lpTemplateName = NULL ; + cf.hInstance = NULL ; + cf.lpszStyle = NULL ; + cf.nFontType = 0 ; // Returned from ChooseFont + cf.nSizeMin = 0 ; + cf.nSizeMax = 0 ; + + return ChooseFont (&cf) ; + } + +void PopFontInitialize (HWND hwndEdit) + { + GetObject (GetStockObject (SYSTEM_FONT), sizeof (LOGFONT), + (LPSTR) &logfont) ; + hFont = CreateFontIndirect (&logfont) ; + SendMessage (hwndEdit, WM_SETFONT, hFont, 0L) ; + } + +void PopFontSetFont (HWND hwndEdit) + { + HFONT hFontNew ; + + hFontNew = CreateFontIndirect (&logfont) ; + SendMessage (hwndEdit, WM_SETFONT, hFontNew, 0L) ; + DeleteObject (hFont) ; + hFont = hFontNew ; + } + +void PopFontDeinitialize (void) + { + DeleteObject (hFont) ; + } diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.c b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.c new file mode 100644 index 00000000..c62ef23b --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.c @@ -0,0 +1,672 @@ +/* -*- 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 ***** */ + +/*--------------------------------------- + POPPAD.C -- Popup Editor + (c) Charles Petzold, 1992 + ---------------------------------------*/ + +#include "nspr.h" +#include "plevent.h" +#include +#include +#include +#include "poppad.h" +#include + +#define EDITID 1 +#define UNTITLED "(untitled)" + +long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG) ; +BOOL FAR PASCAL _export AboutDlgProc (HWND, UINT, UINT, LONG) ; + +/* Declarations for NSPR customization +** +*/ +typedef struct PadEvent +{ + PLEvent plEvent; + int unused; +} PadEvent; + +static void PR_CALLBACK TimerThread( void *arg); +static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ); +static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ); +static PRThread *tThread; +static PLEventQueue *padQueue; +static int quitSwitch = 0; +static long ThreadSleepTime = 1000; +static long timerCount = 0; +static char *startMessage = "Poppad: NSPR GUI and event test program.\n" + "You should see lines of 50 characters\n" + "with a new character appearing at 1 second intervals.\n" + "Every 10 seconds gets a '+'; every 5 seconds gets a '_';\n" + "every 1 second gets a '.'.\n\n" + "You should be able to type in the window.\n\n\n"; + + + // Functions in POPFILE.C + +void PopFileInitialize (HWND) ; +BOOL PopFileOpenDlg (HWND, LPSTR, LPSTR) ; +BOOL PopFileSaveDlg (HWND, LPSTR, LPSTR) ; +BOOL PopFileRead (HWND, LPSTR) ; +BOOL PopFileWrite (HWND, LPSTR) ; + + // Functions in POPFIND.C + +HWND PopFindFindDlg (HWND) ; +HWND PopFindReplaceDlg (HWND) ; +BOOL PopFindFindText (HWND, int *, LPFINDREPLACE) ; +BOOL PopFindReplaceText (HWND, int *, LPFINDREPLACE) ; +BOOL PopFindNextText (HWND, int *) ; +BOOL PopFindValidFind (void) ; + + // Functions in POPFONT.C + +void PopFontInitialize (HWND) ; +BOOL PopFontChooseFont (HWND) ; +void PopFontSetFont (HWND) ; +void PopFontDeinitialize (void) ; + + // Functions in POPPRNT.C + +BOOL PopPrntPrintFile (HANDLE, HWND, HWND, LPSTR) ; + + // Global variables + +static char szAppName [] = "PopPad" ; +static HWND hDlgModeless ; +static HWND hwndEdit ; + +int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) + { + MSG msg; + HWND hwnd ; + HANDLE hAccel ; + WNDCLASS wndclass ; + + PR_STDIO_INIT(); + PR_Init(0, 0, 0); + + if (!hPrevInstance) + { + wndclass.style = CS_HREDRAW | CS_VREDRAW ; + wndclass.lpfnWndProc = WndProc ; + wndclass.cbClsExtra = 0 ; + wndclass.cbWndExtra = 0 ; + wndclass.hInstance = hInstance ; + wndclass.hIcon = LoadIcon (hInstance, szAppName) ; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; + wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; + wndclass.lpszMenuName = szAppName ; + wndclass.lpszClassName = szAppName ; + + RegisterClass (&wndclass) ; + } + + hwnd = CreateWindow (szAppName, NULL, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, lpszCmdLine) ; + + ShowWindow (hwnd, nCmdShow) ; + UpdateWindow (hwnd); + + hAccel = LoadAccelerators (hInstance, szAppName) ; + + for(;;) + { + if ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE )) + { + if (GetMessage(&msg, NULL, 0, 0)) + { + if (hDlgModeless == NULL || !IsDialogMessage (hDlgModeless, &msg)) + { + if (!TranslateAccelerator (hwnd, hAccel, &msg)) + { + TranslateMessage (&msg) ; + DispatchMessage (&msg) ; + } /* end if !TranslateAccelerator */ + } + } + else + { + break; + } /* end if GetMessage() */ + } + else /* !PeekMessage */ + { + PR_Sleep(50); + }/* end if PeekMessage() */ + } /* end for() */ + + PR_JoinThread( tThread ); + PL_DestroyEventQueue( padQueue ); + PR_Cleanup(); + return msg.wParam ; + } + +void DoCaption (HWND hwnd, char *szTitleName) + { + char szCaption [64 + _MAX_FNAME + _MAX_EXT] ; + + wsprintf (szCaption, "%s - %s", (LPSTR) szAppName, + (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; + + SetWindowText (hwnd, szCaption) ; + } + +void OkMessage (HWND hwnd, char *szMessage, char *szTitleName) + { + char szBuffer [64 + _MAX_FNAME + _MAX_EXT] ; + + wsprintf (szBuffer, szMessage, + (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; + + MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ; + } + +short AskAboutSave (HWND hwnd, char *szTitleName) + { + char szBuffer [64 + _MAX_FNAME + _MAX_EXT] ; + short nReturn ; + + wsprintf (szBuffer, "Save current changes in %s?", + (LPSTR) (szTitleName [0] ? szTitleName : UNTITLED)) ; + + nReturn = MessageBox (hwnd, szBuffer, szAppName, + MB_YESNOCANCEL | MB_ICONQUESTION) ; + + if (nReturn == IDYES) + if (!SendMessage (hwnd, WM_COMMAND, IDM_SAVE, 0L)) + nReturn = IDCANCEL ; + + return nReturn ; + } + +long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam, + LONG lParam) + { + static BOOL bNeedSave = FALSE ; + static char szFileName [_MAX_PATH] ; + static char szTitleName [_MAX_FNAME + _MAX_EXT] ; + static FARPROC lpfnAboutDlgProc ; + static HANDLE hInst ; + static int iOffset ; + static UINT messageFindReplace ; + LONG lSelect ; + LPFINDREPLACE lpfr ; + WORD wEnable ; + + switch (message) + { + case WM_CREATE: + // Get About dialog instance address + + hInst = ((LPCREATESTRUCT) lParam)->hInstance ; + lpfnAboutDlgProc = MakeProcInstance ((FARPROC) AboutDlgProc, + hInst) ; + + // Create the edit control child window + + hwndEdit = CreateWindow ("edit", NULL, + WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | + WS_BORDER | ES_LEFT | ES_MULTILINE | + ES_NOHIDESEL | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, + hwnd, EDITID, hInst, NULL) ; + + SendMessage (hwndEdit, EM_LIMITTEXT, 32000, 0L) ; + + // Initialize common dialog box stuff + + PopFileInitialize (hwnd) ; + PopFontInitialize (hwndEdit) ; + + messageFindReplace = RegisterWindowMessage (FINDMSGSTRING) ; + + // Process command line + + lstrcpy (szFileName, (LPSTR) + (((LPCREATESTRUCT) lParam)->lpCreateParams)) ; + + if (lstrlen (szFileName) > 0) + { + GetFileTitle (szFileName, szTitleName, + sizeof (szTitleName)) ; + + if (!PopFileRead (hwndEdit, szFileName)) + OkMessage (hwnd, "File %s cannot be read!", + szTitleName) ; + } + + DoCaption (hwnd, szTitleName) ; + + /* Initialize Event Processing for NSPR + ** Retrieve the event queue just created + ** Create the TimerThread + */ + PL_InitializeEventsLib("someName"); + padQueue = PL_GetMainEventQueue(); + tThread = PR_CreateThread(PR_USER_THREAD, + TimerThread, + NULL, + PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + return 0 ; + + case WM_SETFOCUS: + SetFocus (hwndEdit) ; + return 0 ; + + case WM_SIZE: + MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), + HIWORD (lParam), TRUE) ; + return 0 ; + + case WM_INITMENUPOPUP: + switch (lParam) + { + case 1: // Edit menu + + // Enable Undo if edit control can do it + + EnableMenuItem (wParam, IDM_UNDO, + SendMessage (hwndEdit, EM_CANUNDO, 0, 0L) ? + MF_ENABLED : MF_GRAYED) ; + + // Enable Paste if text is in the clipboard + + EnableMenuItem (wParam, IDM_PASTE, + IsClipboardFormatAvailable (CF_TEXT) ? + MF_ENABLED : MF_GRAYED) ; + + // Enable Cut, Copy, and Del if text is selected + + lSelect = SendMessage (hwndEdit, EM_GETSEL, 0, 0L) ; + wEnable = HIWORD (lSelect) != LOWORD (lSelect) ? + MF_ENABLED : MF_GRAYED ; + + EnableMenuItem (wParam, IDM_CUT, wEnable) ; + EnableMenuItem (wParam, IDM_COPY, wEnable) ; + EnableMenuItem (wParam, IDM_DEL, wEnable) ; + break ; + + case 2: // Search menu + + // Enable Find, Next, and Replace if modeless + // dialogs are not already active + + wEnable = hDlgModeless == NULL ? + MF_ENABLED : MF_GRAYED ; + + EnableMenuItem (wParam, IDM_FIND, wEnable) ; + EnableMenuItem (wParam, IDM_NEXT, wEnable) ; + EnableMenuItem (wParam, IDM_REPLACE, wEnable) ; + break ; + } + return 0 ; + + case WM_COMMAND : + // Messages from edit control + + if (LOWORD (lParam) && wParam == EDITID) + { + switch (HIWORD (lParam)) + { + case EN_UPDATE: + bNeedSave = TRUE ; + return 0 ; + + case EN_ERRSPACE: + case EN_MAXTEXT: + MessageBox (hwnd, "Edit control out of space.", + szAppName, MB_OK | MB_ICONSTOP) ; + return 0 ; + } + break ; + } + + switch (wParam) + { + // Messages from File menu + + case IDM_NEW: + if (bNeedSave && IDCANCEL == + AskAboutSave (hwnd, szTitleName)) + return 0 ; + + SetWindowText (hwndEdit, "\0") ; + szFileName [0] = '\0' ; + szTitleName [0] = '\0' ; + DoCaption (hwnd, szTitleName) ; + bNeedSave = FALSE ; + return 0 ; + + case IDM_OPEN: + if (bNeedSave && IDCANCEL == + AskAboutSave (hwnd, szTitleName)) + return 0 ; + + if (PopFileOpenDlg (hwnd, szFileName, szTitleName)) + { + if (!PopFileRead (hwndEdit, szFileName)) + { + OkMessage (hwnd, "Could not read file %s!", + szTitleName) ; + szFileName [0] = '\0' ; + szTitleName [0] = '\0' ; + } + } + + DoCaption (hwnd, szTitleName) ; + bNeedSave = FALSE ; + return 0 ; + + case IDM_SAVE: + if (szFileName [0]) + { + if (PopFileWrite (hwndEdit, szFileName)) + { + bNeedSave = FALSE ; + return 1 ; + } + else + OkMessage (hwnd, "Could not write file %s", + szTitleName) ; + return 0 ; + } + // fall through + case IDM_SAVEAS: + if (PopFileSaveDlg (hwnd, szFileName, szTitleName)) + { + DoCaption (hwnd, szTitleName) ; + + if (PopFileWrite (hwndEdit, szFileName)) + { + bNeedSave = FALSE ; + return 1 ; + } + else + OkMessage (hwnd, "Could not write file %s", + szTitleName) ; + } + return 0 ; + + case IDM_PRINT: + if (!PopPrntPrintFile (hInst, hwnd, hwndEdit, + szTitleName)) + OkMessage (hwnd, "Could not print file %s", + szTitleName) ; + return 0 ; + + case IDM_EXIT: + SendMessage (hwnd, WM_CLOSE, 0, 0L) ; + return 0 ; + + // Messages from Edit menu + + case IDM_UNDO: + SendMessage (hwndEdit, WM_UNDO, 0, 0L) ; + return 0 ; + + case IDM_CUT: + SendMessage (hwndEdit, WM_CUT, 0, 0L) ; + return 0 ; + + case IDM_COPY: + SendMessage (hwndEdit, WM_COPY, 0, 0L) ; + return 0 ; + + case IDM_PASTE: + SendMessage (hwndEdit, WM_PASTE, 0, 0L) ; + return 0 ; + + case IDM_DEL: + SendMessage (hwndEdit, WM_CLEAR, 0, 0L) ; + return 0 ; + + case IDM_SELALL: + SendMessage (hwndEdit, EM_SETSEL, 0, + MAKELONG (0, 32767)) ; + return 0 ; + + // Messages from Search menu + + case IDM_FIND: + iOffset = HIWORD ( + SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; + hDlgModeless = PopFindFindDlg (hwnd) ; + return 0 ; + + case IDM_NEXT: + iOffset = HIWORD ( + SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; + + if (PopFindValidFind ()) + PopFindNextText (hwndEdit, &iOffset) ; + else + hDlgModeless = PopFindFindDlg (hwnd) ; + + return 0 ; + + case IDM_REPLACE: + iOffset = HIWORD ( + SendMessage (hwndEdit, EM_GETSEL, 0, 0L)) ; + + hDlgModeless = PopFindReplaceDlg (hwnd) ; + return 0 ; + + case IDM_FONT: + if (PopFontChooseFont (hwnd)) + PopFontSetFont (hwndEdit) ; + + return 0 ; + + // Messages from Help menu + + case IDM_HELP: + OkMessage (hwnd, "Help not yet implemented!", NULL) ; + return 0 ; + + case IDM_ABOUT: + DialogBox (hInst, "AboutBox", hwnd, lpfnAboutDlgProc); + return 0 ; + } + break ; + + case WM_CLOSE: + if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) + DestroyWindow (hwnd) ; + + return 0 ; + + case WM_QUERYENDSESSION: + if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) + return 1L ; + + return 0 ; + + case WM_DESTROY: + PopFontDeinitialize () ; + PostQuitMessage (0) ; + quitSwitch = 1; + return 0 ; + + default: + // Process "Find-Replace" messages + + if (message == messageFindReplace) + { + lpfr = (LPFINDREPLACE) lParam ; + + if (lpfr->Flags & FR_DIALOGTERM) + hDlgModeless = NULL ; + + if (lpfr->Flags & FR_FINDNEXT) + if (!PopFindFindText (hwndEdit, &iOffset, lpfr)) + OkMessage (hwnd, "Text not found!", NULL) ; + + if (lpfr->Flags & FR_REPLACE || + lpfr->Flags & FR_REPLACEALL) + if (!PopFindReplaceText (hwndEdit, &iOffset, lpfr)) + OkMessage (hwnd, "Text not found!", NULL) ; + + if (lpfr->Flags & FR_REPLACEALL) + while (PopFindReplaceText (hwndEdit, &iOffset, lpfr)); + + return 0 ; + } + break ; + } + return DefWindowProc (hwnd, message, wParam, lParam) ; + } + +BOOL FAR PASCAL _export AboutDlgProc (HWND hDlg, UINT message, UINT wParam, + LONG lParam) + { + switch (message) + { + case WM_INITDIALOG: + return TRUE ; + + case WM_COMMAND: + switch (wParam) + { + case IDOK: + EndDialog (hDlg, 0) ; + return TRUE ; + } + break ; + } + return FALSE ; + } +/* +** TimerThread() -- The Main function of the timer pop thread +** +*/ +static void PR_CALLBACK TimerThread( void *arg) +{ + do { + PadEvent *ev; + + /* + ** Should we quit now? + */ + if ( quitSwitch ) + break; + /* + ** Create and Post the event the event + */ + PL_ENTER_EVENT_QUEUE_MONITOR( padQueue ); + ev = (PadEvent *) PR_NEW( PadEvent ); + PL_InitEvent( &ev->plEvent, NULL, + (PLHandleEventProc)HandlePadEvent, + (PLDestroyEventProc)DestroyPadEvent ); + PL_PostEvent( padQueue, &ev->plEvent ); + PL_EXIT_EVENT_QUEUE_MONITOR( padQueue ); + + PR_Sleep( ThreadSleepTime ); + } while(1); + return; +} + +/* +** HandlePadEvent() -- gets called because of PostEvent +*/ +static void PR_CALLBACK HandlePadEvent( PadEvent *padEvent ) +{ + if ( timerCount++ == 0 ) + { + char *cp; + + for ( cp = startMessage; *cp != 0 ; cp++ ) + { + SendMessage( hwndEdit, WM_CHAR, *cp, MAKELONG( *cp, 1 )); + } + } + /* + ** Send a WM_CHAR event the edit Window + */ + if ((timerCount % 10) == 0) + { + SendMessage( hwndEdit, WM_CHAR, '+', MAKELONG( '+', 1 )); + } + else if ((timerCount % 5) == 0) + { + SendMessage( hwndEdit, WM_CHAR, '_', MAKELONG( '_', 1 )); + } + else + { + SendMessage( hwndEdit, WM_CHAR, '.', MAKELONG( '.', 1 )); + } + + if ( (timerCount % 50) == 0) + { + SendMessage( hwndEdit, WM_CHAR, '\n', MAKELONG( '\n', 1 )); + } + + /* + ** PL_RevokeEvents() is broken. Test to fix it. + */ + { + static long revokeCounter = 0; + + if (revokeCounter++ > 10 ) + { + PR_Sleep( ThreadSleepTime * 10 ); + SendMessage( hwndEdit, WM_CHAR, '*', MAKELONG( '\n', 1 )); + PL_RevokeEvents( padQueue, NULL ); + revokeCounter = 0; + } + } + return; +} + +/* +** DestroyPadEvent() -- Called after HandlePadEvent() +*/ +static void PR_CALLBACK DestroyPadEvent( PadEvent *padevent ) +{ + PR_Free( padevent ); + return; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.h b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.h new file mode 100644 index 00000000..202095e5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.h @@ -0,0 +1,66 @@ +/* -*- 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 ***** */ + +/*---------------------- + POPPAD.H header file + (c) Charles Petzold, 1992 + ----------------------*/ + +#define IDM_NEW 10 +#define IDM_OPEN 11 +#define IDM_SAVE 12 +#define IDM_SAVEAS 13 +#define IDM_PRINT 14 +#define IDM_EXIT 15 + +#define IDM_UNDO 20 +#define IDM_CUT 21 +#define IDM_COPY 22 +#define IDM_PASTE 23 +#define IDM_DEL 24 +#define IDM_SELALL 25 + +#define IDM_FIND 30 +#define IDM_NEXT 31 +#define IDM_REPLACE 32 + +#define IDM_FONT 40 + +#define IDM_HELP 50 +#define IDM_ABOUT 51 + +#define IDD_FNAME 10 diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.ico b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.ico new file mode 100644 index 00000000..fe7097c5 Binary files /dev/null and b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.ico differ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.rc b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.rc new file mode 100644 index 00000000..227f5e4a --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/poppad.rc @@ -0,0 +1,121 @@ +/* -*- 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 ***** */ + +/*--------------------------- + POPPAD.RC resource script + ---------------------------*/ + +#include +#include "poppad.h" + +PopPad ICON "poppad.ico" + +PopPad MENU + { + POPUP "&File" + { + MENUITEM "&New", IDM_NEW + MENUITEM "&Open...", IDM_OPEN + MENUITEM "&Save", IDM_SAVE + MENUITEM "Save &As...", IDM_SAVEAS + MENUITEM SEPARATOR + MENUITEM "&Print...", IDM_PRINT + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_EXIT + } + POPUP "&Edit" + { + MENUITEM "&Undo\tCtrl+Z", IDM_UNDO + MENUITEM SEPARATOR + MENUITEM "Cu&t\tCtrl+X", IDM_CUT + MENUITEM "&Copy\tCtrl+C", IDM_COPY + MENUITEM "&Paste\tCtrl+V", IDM_PASTE + MENUITEM "De&lete\tDel", IDM_DEL + MENUITEM SEPARATOR + MENUITEM "&Select All", IDM_SELALL + } + POPUP "&Search" + { + MENUITEM "&Find...", IDM_FIND + MENUITEM "Find &Next\tF3", IDM_NEXT + MENUITEM "&Replace...", IDM_REPLACE + } + POPUP "&Character" + { + MENUITEM "&Font...", IDM_FONT + } + POPUP "&Help" + { + MENUITEM "&Help", IDM_HELP + MENUITEM "&About PopPad...", IDM_ABOUT + } + } + +PopPad ACCELERATORS + { + "^Z", IDM_UNDO + VK_BACK, IDM_UNDO, VIRTKEY, ALT + "^X", IDM_CUT + VK_DELETE, IDM_CUT, VIRTKEY, SHIFT + "^C", IDM_COPY + VK_INSERT, IDM_COPY, VIRTKEY, CONTROL + "^V", IDM_PASTE + VK_INSERT, IDM_PASTE, VIRTKEY, SHIFT + VK_DELETE, IDM_DEL, VIRTKEY + VK_F3, IDM_NEXT, VIRTKEY + VK_F1, IDM_HELP, VIRTKEY + } + +AboutBox DIALOG 20, 20, 160, 80 + STYLE WS_POPUP | WS_DLGFRAME + { + CTEXT "PopPad" -1, 0, 12, 160, 8 + ICON "PopPad" -1, 8, 8, 0, 0 + CTEXT "Popup Editor for Microsoft Windows" -1, 0, 36, 160, 8 + CTEXT "Copyright (c) Charles Petzold, 1992" -1, 0, 48, 160, 8 + DEFPUSHBUTTON "OK" IDOK, 64, 60, 32, 14, WS_GROUP + } + +PrintDlgBox DIALOG 20, 20, 100, 76 + STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE + CAPTION "PopPad" + { + CTEXT "Sending", -1, 0, 10, 100, 8 + CTEXT "", IDD_FNAME, 0, 20, 100, 8 + CTEXT "to print spooler.", -1, 0, 30, 100, 8 + DEFPUSHBUTTON "Cancel", IDCANCEL, 34, 50, 32, 14, WS_GROUP + } diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popprnt0.c b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popprnt0.c new file mode 100644 index 00000000..4e76377f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/popprnt0.c @@ -0,0 +1,49 @@ +/* -*- 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 ***** */ + +/*--------------------------------------------------------------- + POPPRNT0.C -- Popup Editor Printing Functions (dummy version) + (c) Charles Petzold, 1992 + ---------------------------------------------------------------*/ + +#include + +BOOL PopPrntPrintFile (HANDLE hInst, HWND hwnd, HWND hwndEdit, + LPSTR lpstrTitleName) + { + return FALSE ; + } diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/readme.1st b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/readme.1st new file mode 100644 index 00000000..afdf847f --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/w16gui/readme.1st @@ -0,0 +1,37 @@ +readme.1st. + +The files in the pr/tests/w16gui directory are taken +from "Programming Windows 3.1" by Charles Petzold, +specifically, the programs in chapter 14 related +to the "poppad4" sample application. + +These programs are compiled with nspr20 to test nspr 2.0 +and to demostrate the use of nspr in a gui application. + +Library (DLL) PLDSxx.lib PLDSxx.dll is required to be +linked with this test case. Functions in this dll are +in the source ns/nspr20/lib/ds/plevent.* files. + +Permission to use. + +The source for poppad.c are used under license from +Petzold. The license to use is stated in the book. +The following paragraph of the license grants that +use. + + 5. SAMPLE CODE. If the SOFTWARE includes Sample Code, then + Microsoft grants you a royalty-free right to reproduce and + distribute the sample code of the SOFTWARE provided that you: + (a) distribute the sample code only in conjunction with and + as part of your software product; (b) do not use Microsoft's + or its authors' names, logos, or trademarks to market your + software product; (c) include the copyright notice that appears + on the SOFTWARE on your product label and as a part of the + sign-on message for your software product; and (d) agree to + idemnify, hold harmless, and defend Microsoft and its authors + from and against any claims or lawsuits, including attorneys' + fees, that arise or result from the use or distribution of + your software product. + +lth. 9/24/97. + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/writev.c b/src/libs/xpcom18a4/nsprpub/pr/tests/writev.c new file mode 100644 index 00000000..603526c9 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/writev.c @@ -0,0 +1,234 @@ +/* -*- 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 "nspr.h" + +#include "plgetopt.h" + +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#define printf PR_LogPrint +#endif + + +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + +#define BASE_PORT 9867 + +int PR_CALLBACK Writev(int argc, char **argv) +{ + + PRStatus rv; + PRNetAddr serverAddr; + PRFileDesc *clientSock, *debug = NULL; + + char *buffer = NULL; + PRIOVec *iov = NULL; + PRBool passed = PR_TRUE; + PRIntervalTime timein, elapsed, timeout; + PRIntervalTime tmo_min = 0x7fffffff, tmo_max = 0, tmo_elapsed = 0; + PRInt32 tmo_counted = 0, iov_index, loop, bytes, number_fragments; + PRInt32 message_length = 100, fragment_length = 100, messages = 100; + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; + + /* + * USAGE + * -h dns name of host serving the connection (default = self) + * -m number of messages to send (default = 100) + * -s size of each message (default = 100) + * -f size of each message fragment (default = 100) + */ + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dh:m:s:f:"); + + PR_STDIO_INIT(); + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &serverAddr); + PR_ASSERT(PR_SUCCESS == rv); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'h': /* the remote host */ + { + PRIntn es = 0; + PRHostEnt host; + char buffer[1024]; + (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host); + es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &serverAddr); + PR_ASSERT(es > 0); + } + break; + case 'd': /* debug mode */ + debug = PR_GetSpecialFD(PR_StandardError); + break; + case 'm': /* number of messages to send */ + messages = atoi(opt->value); + break; + case 's': /* total size of each message */ + message_length = atoi(opt->value); + break; + case 'f': /* size of each message fragment */ + fragment_length = atoi(opt->value); + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + buffer = (char*)malloc(message_length); + + number_fragments = (message_length + fragment_length - 1) / fragment_length + 1; + while (IOV_MAX < number_fragments) + { + fragment_length = message_length / (IOV_MAX - 2); + number_fragments = (message_length + fragment_length - 1) / + fragment_length + 1; + if (NULL != debug) PR_fprintf(debug, + "Too many fragments - reset fragment length to %ld\n", fragment_length); + } + iov = (PRIOVec*)malloc(number_fragments * sizeof(PRIOVec)); + + iov[0].iov_base = (char*)&descriptor; + iov[0].iov_len = sizeof(descriptor); + for (iov_index = 1; iov_index < number_fragments; ++iov_index) + { + iov[iov_index].iov_base = buffer + (iov_index - 1) * fragment_length; + iov[iov_index].iov_len = fragment_length; + } + + for (bytes = 0; bytes < message_length; ++bytes) + buffer[bytes] = (char)bytes; + + timeout = PR_SecondsToInterval(1); + + for (loop = 0; loop < messages; ++loop) + { + if (NULL != debug) + PR_fprintf(debug, "[%d]socket ... ", loop); + clientSock = PR_NewTCPSocket(); + if (clientSock) + { + timein = PR_IntervalNow(); + if (NULL != debug) + PR_fprintf(debug, "connecting ... "); + rv = PR_Connect(clientSock, &serverAddr, timeout); + if (PR_SUCCESS == rv) + { + descriptor.checksum = 0; + descriptor.length = (loop < (messages - 1)) ? message_length : 0; + if (0 == descriptor.length) number_fragments = 1; + else + for (iov_index = 0; iov_index < descriptor.length; ++iov_index) + { + PRUint32 overflow = descriptor.checksum & 0x80000000; + descriptor.checksum = (descriptor.checksum << 1); + if (0x00000000 != overflow) descriptor.checksum += 1; + descriptor.checksum += buffer[iov_index]; + } + if (NULL != debug) PR_fprintf( + debug, "sending %d bytes ... ", descriptor.length); + + /* then, at the last moment ... */ + descriptor.length = PR_ntohl(descriptor.length); + descriptor.checksum = PR_ntohl(descriptor.checksum); + + bytes = PR_Writev(clientSock, iov, number_fragments, timeout); + if (NULL != debug) + PR_fprintf(debug, "closing ... "); + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); + rv = PR_Close(clientSock); + if (NULL != debug) PR_fprintf( + debug, "%s\n", ((PR_SUCCESS == rv) ? "good" : "bad")); + elapsed = PR_IntervalNow() - timein; + if (elapsed < tmo_min) tmo_min = elapsed; + else if (elapsed > tmo_max) tmo_max = elapsed; + tmo_elapsed += elapsed; + tmo_counted += 1; + } + else + { + if (NULL != debug) PR_fprintf( + debug, "failed - retrying (%d, %d)\n", + PR_GetError(), PR_GetOSError()); + PR_Close(clientSock); + } + } + else if (NULL != debug) + { + PR_fprintf(debug, "unable to create client socket\n"); + passed = PR_FALSE; + } + } + if (NULL != debug) { + if (0 == tmo_counted) { + PR_fprintf(debug, "No connection made\n"); + } else { + PR_fprintf( + debug, "\nTimings: %d [%d] %d (microseconds)\n", + PR_IntervalToMicroseconds(tmo_min), + PR_IntervalToMicroseconds(tmo_elapsed / tmo_counted), + PR_IntervalToMicroseconds(tmo_max)); + } + } + + PR_DELETE(buffer); + PR_DELETE(iov); + + PR_fprintf( + PR_GetSpecialFD(PR_StandardError), + "%s\n", (passed) ? "PASSED" : "FAILED"); + return (passed) ? 0 : 1; +} + +int main(int argc, char **argv) +{ + return (PR_VersionCheck(PR_VERSION)) ? + PR_Initialize(Writev, argc, argv, 4) : -1; +} /* main */ + +/* writev.c */ + + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/xnotify.c b/src/libs/xpcom18a4/nsprpub/pr/tests/xnotify.c new file mode 100644 index 00000000..97f64917 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/xnotify.c @@ -0,0 +1,389 @@ +/* -*- 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 "plerror.h" +#include "plgetopt.h" + +#include "prinit.h" +#include "prprf.h" +#include "prio.h" +#include "prcvar.h" +#include "prmon.h" +#include "prcmon.h" +#include "prlock.h" +#include "prerror.h" +#include "prinit.h" +#include "prinrval.h" +#include "prthread.h" + +static PRLock *ml = NULL; +static PRIntervalTime base; +static PRFileDesc *err = NULL; + +typedef struct CMonShared +{ + PRInt32 o1, o2; +} CMonShared; + +typedef struct MonShared +{ + PRMonitor *o1, *o2; +} MonShared; + +typedef struct LockShared +{ + PRLock *o1, *o2; + PRCondVar *cv1, *cv2; +} LockShared; + +static void LogNow(const char *msg, PRStatus rv) +{ + PRIntervalTime now = PR_IntervalNow(); + PR_Lock(ml); + PR_fprintf(err, "%6ld: %s", (now - base), msg); + if (PR_FAILURE == rv) PL_FPrintError(err, " "); + else PR_fprintf(err, "\n"); + PR_Unlock(ml); +} /* LogNow */ + +static void Help(void) +{ + PR_fprintf(err, "Usage: [-[d][l][m][c]] [-h]\n"); + PR_fprintf(err, "\t-d debug mode (default: FALSE)\n"); + PR_fprintf(err, "\t-l test with locks (default: FALSE)\n"); + PR_fprintf(err, "\t-m tests with monitors (default: FALSE)\n"); + PR_fprintf(err, "\t-c tests with cmonitors (default: FALSE)\n"); + PR_fprintf(err, "\t-h help\n"); +} /* Help */ + +static void PR_CALLBACK T2CMon(void *arg) +{ + PRStatus rv; + CMonShared *shared = (CMonShared*)arg; + + PR_CEnterMonitor(&shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_CWait(&shared->o1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_CNotify(&shared->o1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_CExitMonitor(&shared->o1); +} /* T2CMon */ + +static void PR_CALLBACK T3CMon(void *arg) +{ + PRStatus rv; + CMonShared *shared = (CMonShared*)arg; + + PR_CEnterMonitor(&shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_CWait(&shared->o2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_CNotify(&shared->o2); + LogNow("T3 notify on o2", rv); + PR_CExitMonitor(&shared->o2); + +} /* T3CMon */ + +static CMonShared sharedCM; + +static void T1CMon(void) +{ + PRStatus rv; + PRThread *t2, *t3; + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " CACHED MONITORS\n"); + PR_fprintf(err, "**********************************\n"); + + base = PR_IntervalNow(); + + PR_CEnterMonitor(&sharedCM.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_CWait(&sharedCM.o1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_CExitMonitor(&sharedCM.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2CMon, &sharedCM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3CMon, &sharedCM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_CEnterMonitor(&sharedCM.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_CWait(&sharedCM.o2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_CExitMonitor(&sharedCM.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + +} /* T1CMon */ + +static void PR_CALLBACK T2Mon(void *arg) +{ + PRStatus rv; + MonShared *shared = (MonShared*)arg; + + PR_EnterMonitor(shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_Wait(shared->o1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_Notify(shared->o1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_ExitMonitor(shared->o1); +} /* T2Mon */ + +static void PR_CALLBACK T3Mon(void *arg) +{ + PRStatus rv; + MonShared *shared = (MonShared*)arg; + + PR_EnterMonitor(shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_Wait(shared->o2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_Notify(shared->o2); + LogNow("T3 notify on o2", rv); + PR_ExitMonitor(shared->o2); + +} /* T3Mon */ + +static MonShared sharedM; +static void T1Mon(void) +{ + PRStatus rv; + PRThread *t2, *t3; + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " MONITORS\n"); + PR_fprintf(err, "**********************************\n"); + + sharedM.o1 = PR_NewMonitor(); + sharedM.o2 = PR_NewMonitor(); + + base = PR_IntervalNow(); + + PR_EnterMonitor(sharedM.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_Wait(sharedM.o1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_ExitMonitor(sharedM.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2Mon, &sharedM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3Mon, &sharedM, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_EnterMonitor(sharedM.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_Wait(sharedM.o2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_ExitMonitor(sharedM.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + + PR_DestroyMonitor(sharedM.o1); + PR_DestroyMonitor(sharedM.o2); + +} /* T1Mon */ + +static void PR_CALLBACK T2Lock(void *arg) +{ + PRStatus rv; + LockShared *shared = (LockShared*)arg; + + PR_Lock(shared->o1); + LogNow("T2 waiting 5 seconds on o1", PR_SUCCESS); + rv = PR_WaitCondVar(shared->cv1, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T2 resuming on o1", rv); + else LogNow("T2 wait failed on o1", rv); + + rv = PR_NotifyCondVar(shared->cv1); + if (PR_SUCCESS == rv) LogNow("T2 notified o1", rv); + else LogNow("T2 notify on o1 failed", rv); + + PR_Unlock(shared->o1); +} /* T2Lock */ + +static void PR_CALLBACK T3Lock(void *arg) +{ + PRStatus rv; + LockShared *shared = (LockShared*)arg; + + PR_Lock(shared->o2); + LogNow("T3 waiting 5 seconds on o2", PR_SUCCESS); + rv = PR_WaitCondVar(shared->cv2, PR_SecondsToInterval(5)); + if (PR_SUCCESS == rv) LogNow("T3 resuming on o2", rv); + else LogNow("T3 wait failed on o2", rv); + rv = PR_NotifyCondVar(shared->cv2); + LogNow("T3 notify on o2", rv); + PR_Unlock(shared->o2); + +} /* T3Lock */ + +/* +** Make shared' a static variable for Win16 +*/ +static LockShared sharedL; + +static void T1Lock(void) +{ + PRStatus rv; + PRThread *t2, *t3; + sharedL.o1 = PR_NewLock(); + sharedL.o2 = PR_NewLock(); + sharedL.cv1 = PR_NewCondVar(sharedL.o1); + sharedL.cv2 = PR_NewCondVar(sharedL.o2); + + PR_fprintf(err, "\n**********************************\n"); + PR_fprintf(err, " LOCKS\n"); + PR_fprintf(err, "**********************************\n"); + + base = PR_IntervalNow(); + + PR_Lock(sharedL.o1); + LogNow("T1 waiting 3 seconds on o1", PR_SUCCESS); + rv = PR_WaitCondVar(sharedL.cv1, PR_SecondsToInterval(3)); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o1", rv); + else LogNow("T1 wait on o1 failed", rv); + PR_Unlock(sharedL.o1); + + LogNow("T1 creating T2", PR_SUCCESS); + t2 = PR_CreateThread( + PR_USER_THREAD, T2Lock, &sharedL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + LogNow("T1 creating T3", PR_SUCCESS); + t3 = PR_CreateThread( + PR_USER_THREAD, T3Lock, &sharedL, PR_PRIORITY_NORMAL, + PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); + + PR_Lock(sharedL.o2); + LogNow("T1 waiting forever on o2", PR_SUCCESS); + rv = PR_WaitCondVar(sharedL.cv2, PR_INTERVAL_NO_TIMEOUT); + if (PR_SUCCESS == rv) LogNow("T1 resuming on o2", rv); + else LogNow("T1 wait on o2 failed", rv); + PR_Unlock(sharedL.o2); + + (void)PR_JoinThread(t2); + (void)PR_JoinThread(t3); + + PR_DestroyLock(sharedL.o1); + PR_DestroyLock(sharedL.o2); + PR_DestroyCondVar(sharedL.cv1); + PR_DestroyCondVar(sharedL.cv2); +} /* T1Lock */ + +static PRIntn PR_CALLBACK RealMain( PRIntn argc, char **argv ) +{ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dhlmc"); + PRBool locks = PR_FALSE, monitors = PR_FALSE, cmonitors = PR_FALSE; + + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode (noop) */ + break; + case 'l': /* locks */ + locks = PR_TRUE; + break; + case 'm': /* monitors */ + monitors = PR_TRUE; + break; + case 'c': /* cached monitors */ + cmonitors = PR_TRUE; + break; + case 'h': /* needs guidance */ + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + ml = PR_NewLock(); + if (locks) T1Lock(); + if (monitors) T1Mon(); + if (cmonitors) T1CMon(); + + PR_DestroyLock(ml); + + PR_fprintf(err, "Done!\n"); + return 0; +} /* main */ + + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv; + + PR_STDIO_INIT(); + rv = PR_Initialize(RealMain, argc, argv, 0); + return rv; +} /* main */ +/* xnotify.c */ diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/y2k.c b/src/libs/xpcom18a4/nsprpub/pr/tests/y2k.c new file mode 100644 index 00000000..80fc10a5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/y2k.c @@ -0,0 +1,840 @@ +/* -*- 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 ***** */ + +/* + * file: y2k.c + * description: Test for y2k compliance for NSPR. + * + * Sep 1999. lth. Added "Sun" specified dates to the test data. + */ +/*********************************************************************** +** Includes +***********************************************************************/ +/* Used to get the command line option */ +#include "plgetopt.h" + +#include "prinit.h" +#include "prtime.h" +#include "prprf.h" +#include "prlog.h" + +#include +#include +#include + +#ifdef XP_MAC +#include "prlog.h" +#include "macstdlibextras.h" +extern void SetupMacPrintfLog(char *logFile); +#endif + +#define PRINT_DETAILS + +int failed_already=0; +PRBool debug_mode = PR_FALSE; + +static char *dayOfWeek[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" }; +static char *month[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; + +PRLogModuleInfo *lm; + +static void PrintExplodedTime(const PRExplodedTime *et) { + PRInt32 totalOffset; + PRInt32 hourOffset, minOffset; + const char *sign; + + /* Print day of the week, month, day, hour, minute, and second */ + printf("%s %s %2ld %02ld:%02ld:%02ld ", + dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday, + et->tm_hour, et->tm_min, et->tm_sec); + + /* Print year */ + printf("%hd ", et->tm_year); + + /* Print time zone */ + totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset; + if (totalOffset == 0) { + printf("UTC "); + } else { + sign = "+"; + if (totalOffset < 0) { + totalOffset = -totalOffset; + sign = "-"; + } + hourOffset = totalOffset / 3600; + minOffset = (totalOffset % 3600) / 60; + printf("%s%02ld%02ld ", sign, hourOffset, minOffset); + } +#ifdef PRINT_DETAILS + printf("{%d, %d, %d, %d, %d, %d, %d, %d, %d, { %d, %d}}\n",et->tm_usec, + et->tm_sec, + et->tm_min, + et->tm_hour, + et->tm_mday, + et->tm_month, + et->tm_year, + et->tm_wday, + et->tm_yday, + et->tm_params.tp_gmt_offset, + et->tm_params.tp_dst_offset); +#endif +} + +static int ExplodedTimeIsEqual(const PRExplodedTime *et1, + const PRExplodedTime *et2) +{ + if (et1->tm_usec == et2->tm_usec && + et1->tm_sec == et2->tm_sec && + et1->tm_min == et2->tm_min && + et1->tm_hour == et2->tm_hour && + et1->tm_mday == et2->tm_mday && + et1->tm_month == et2->tm_month && + et1->tm_year == et2->tm_year && + et1->tm_wday == et2->tm_wday && + et1->tm_yday == et2->tm_yday && + et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset && + et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) { + return 1; + } else { + return 0; + } +} + +/* + * TEST 1: TestExplodeImplodeTime + * Description: + * For each given timestamp T (a PRTime value), call PR_ExplodeTime + * with GMT, US Pacific, and local time parameters. Compare the + * resulting calendar (exploded) time values with the expected + * values. + * + * Note: the expected local time values depend on the local time + * zone. The local time values stored in this test are for the US + * Pacific Time Zone. If you are running this test in a different + * time zone, you need to modify the values in the localt array. + * An example is provided below. + * + * Call PR_ImplodeTime for each of the exploded values and compare + * the resulting PRTime values with the original input. + * + * This test is run for the values of time T corresponding to the + * following dates: + * - 12/31/99 - before 2000 + * - 01/01/00 - after 2000 + * - Leap year - Feb 29, 2000 + * - March 1st, 2001 (after 1 year) + * - March 1st, 2005 (after second leap year) + * - 09/09/99 (used by some programs as an end of file marker) + * + * Call PR_Now, convert to calendar time using PR_ExplodeTime and + * manually check the result for correctness. The time should match + * the system clock. + * + * Tested functions: PR_Now, PR_ExplodeTime, PR_ImplodeTime, + * PR_LocalTimeParameters, PR_GMTParameters. + */ + +static PRTime prt[] = { + LL_INIT(220405, 2133125120), /* 946634400000000 */ + LL_INIT(220425, 2633779200), /* 946720800000000 */ + LL_INIT(221612, 2107598848), /* 951818400000000 */ + LL_INIT(228975, 663398400), /* 983440800000000 */ + LL_INIT(258365, 1974568960), /* 1109671200000000 */ + LL_INIT(218132, 1393788928), /* 936871200000000 */ + /* Sun's dates follow */ + LL_INIT( 213062, 4077979648 ), /* Dec 31 1998 10:00:00 */ + LL_INIT( 218152, 1894443008 ), /* Sep 10 1999 10:00:00 */ + LL_INIT( 221592, 1606944768 ), /* Feb 28 2000 10:00:00 */ + LL_INIT( 227768, 688924672 ), /* Dec 31 2000 10:00:00 */ + LL_INIT( 227788, 1189578752 ), /* Jan 1 2001 10:00:00 */ +}; + +static PRExplodedTime gmt[] = { + { 0, 0, 0, 10, 31, 11, 1999, 5, 364, {0, 0}}, /* 1999/12/31 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 0, 2000, 6, 0, {0, 0}}, /* 2000/01/01 10:00:00 GMT */ + { 0, 0, 0, 10, 29, 1, 2000, 2, 59, {0, 0}}, /* 2000/02/29 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 2, 2001, 4, 59, {0, 0}}, /* 2001/3/1 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 2, 2005, 2, 59, {0, 0}}, /* 2005/3/1 10:00:00 GMT */ + { 0, 0, 0, 10, 9, 8, 1999, 4, 251, {0, 0}}, /* 1999/9/9 10:00:00 GMT */ + /* Sun's dates follow */ + { 0, 0, 0, 10, 31, 11, 1998, 4, 364, {0, 0}}, /* 12/31/1998 10:00:00 GMT */ + { 0, 0, 0, 10, 10, 8, 1999, 5, 252, {0, 0}}, /* 9/10/1999 10:00:00 GMT */ + { 0, 0, 0, 10, 28, 1, 2000, 1, 58, {0, 0}}, /* 2/28/2000 10:00:00 GMT */ + { 0, 0, 0, 10, 31, 11, 2000, 0, 365, {0, 0}}, /* 12/31/2000 10:00:00 GMT */ + { 0, 0, 0, 10, 1, 0, 2001, 1, 0, {0, 0}} /* 1/1/2001 10:00:00 GMT */ +}; + +static PRExplodedTime uspt[] = { +{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */ +{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */ +{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */ + /* Sun's dates follow */ + { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */ +}; + +/* + * This test assumes that we are in US Pacific Time Zone. + * If you are running this test in a different time zone, + * you need to modify the localt array and fill in the + * expected results. The localt array for US Eastern Time + * Zone is provided as an example. + */ +static PRExplodedTime localt[] = { +{ 0, 0, 0, 2, 31, 11, 1999, 5, 364, {-28800, 0}}, /* 1999/12/31 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 0, 2000, 6, 0, {-28800, 0}}, /* 2000/01/01 2:00:00 PST */ +{ 0, 0, 0, 2, 29, 1, 2000, 2, 59, {-28800, 0}}, /* 2000/02/29 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2001, 4, 59, {-28800, 0}}, /* 2001/3/1 2:00:00 PST */ +{ 0, 0, 0, 2, 1, 2, 2005, 2, 59, {-28800, 0}}, /* 2005/3/1 2:00:00 PST */ +{ 0, 0, 0, 3, 9, 8, 1999, 4, 251, {-28800, 3600}}, /* 1999/9/9 3:00:00 PDT */ + /* Sun's dates follow */ + { 0, 0, 0, 2, 31, 11, 1998, 4, 364, {-28800, 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 3, 10, 8, 1999, 5, 252, {-28800, 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 2, 28, 1, 2000, 1, 58, {-28800, 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 31, 11, 2000, 0, 365, {-28800, 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 2, 1, 0, 2001, 1, 0, {-28800, 0}} /* 1/1/2001 00:00:00 GMT */ +}; + +#ifdef US_EASTERN_TIME +static PRExplodedTime localt[] = { +{ 0, 0, 0, 5, 31, 11, 1999, 5, 364, {-18000, 0}}, /* 1999/12/31 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 0, 2000, 6, 0, {-18000, 0}}, /* 2000/01/01 2:00:00 EST */ +{ 0, 0, 0, 5, 29, 1, 2000, 2, 59, {-18000, 0}}, /* 2000/02/29 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 2, 2001, 4, 59, {-18000, 0}}, /* 2001/3/1 2:00:00 EST */ +{ 0, 0, 0, 5, 1, 2, 2005, 2, 59, {-18000, 0}}, /* 2005/3/1 2:00:00 EST */ +{ 0, 0, 0, 6, 9, 8, 1999, 4, 251, {-18000, 3600}}, /* 1999/9/9 3:00:00 EDT */ + /* Sun's dates follow */ + { 0, 0, 0, 5, 31, 11, 1998, 4, 364, {-18000 0}}, /* 12/31/1998 00:00:00 GMT */ + { 0, 0, 0, 6, 10, 8, 1999, 5, 252, {-18000 3600}}, /* 9/10/1999 00:00:00 GMT */ + { 0, 0, 0, 5, 28, 1, 2000, 1, 58, {-18000 0}}, /* 2/28/2000 00:00:00 GMT */ + { 0, 0, 0, 5, 31, 11, 2000, 0, 365, {-18000 0}}, /* 12/31/2000 00:00:00 GMT */ + { 0, 0, 0, 5, 1, 0, 2001, 1, 0, {-18000 0}} /* 1/1/2001 00:00:00 GMT */ +}; +#endif + +static PRStatus TestExplodeImplodeTime(void) +{ + PRTime prt_tmp; + PRTime now; + int idx; + int array_size = sizeof(prt) / sizeof(PRTime); + PRExplodedTime et_tmp; + char buf[1024]; + + for (idx = 0; idx < array_size; idx++) { + PR_snprintf(buf, sizeof(buf), "%lld", prt[idx]); + if (debug_mode) printf("Time stamp %s\n", buf); + PR_ExplodeTime(prt[idx], PR_GMTParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &gmt[idx])) { + fprintf(stderr, "GMT not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&gmt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "PRTime not equal\n"); + exit(1); + } + if (debug_mode) { + printf("GMT: "); + PrintExplodedTime(&et_tmp); + printf("\n"); + } + + PR_ExplodeTime(prt[idx], PR_USPacificTimeParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &uspt[idx])) { + fprintf(stderr, "US Pacific Time not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&uspt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "PRTime not equal\n"); + exit(1); + } + if (debug_mode) { + printf("US Pacific Time: "); + PrintExplodedTime(&et_tmp); + printf("\n"); + } + + PR_ExplodeTime(prt[idx], PR_LocalTimeParameters, &et_tmp); + if (!ExplodedTimeIsEqual(&et_tmp, &localt[idx])) { + fprintf(stderr, "not equal\n"); + PrintExplodedTime(&et_tmp); + PrintExplodedTime(&localt[idx]); + exit(1); + } + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, prt[idx])) { + fprintf(stderr, "not equal\n"); + exit(1); + } + if (debug_mode) { + printf("Local time:"); + PrintExplodedTime(&et_tmp); + printf("\n\n"); + } + } + + now = PR_Now(); + PR_ExplodeTime(now, PR_GMTParameters, &et_tmp); + printf("Current GMT is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + PR_ExplodeTime(now, PR_USPacificTimeParameters, &et_tmp); + printf("Current US Pacific Time is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + PR_ExplodeTime(now, PR_LocalTimeParameters, &et_tmp); + printf("Current local time is "); + PrintExplodedTime(&et_tmp); + printf("\n"); + prt_tmp = PR_ImplodeTime(&et_tmp); + if (LL_NE(prt_tmp, now)) { + fprintf(stderr, "not equal\n"); + exit(1); + } + printf("Please verify the results\n\n"); + + if (debug_mode) printf("Test 1 passed\n"); + return PR_SUCCESS; +} +/* End of Test 1: TestExplodeImplodeTime */ + +/* + * Test 2: Normalize Time + */ + +/* + * time increment for addition to PRExplodeTime + */ +typedef struct time_increment { + PRInt32 ti_usec; + PRInt32 ti_sec; + PRInt32 ti_min; + PRInt32 ti_hour; +} time_increment_t; + +/* + * Data for testing PR_Normalize + * Add the increment to base_time, normalize it to GMT and US Pacific + * Time zone. + */ +typedef struct normalize_test_data { + PRExplodedTime base_time; + time_increment_t increment; + PRExplodedTime expected_gmt_time; + PRExplodedTime expected_uspt_time; +} normalize_test_data_t; + + +/* + * Test data - the base time values cover dates of interest including y2k - 1, + * y2k + 1, y2k leap year, y2k leap date + 1year, + * y2k leap date + 4 years + */ +normalize_test_data_t normalize_test_array[] = { + /*usec sec min hour mday mo year wday yday {gmtoff, dstoff }*/ + + /* Fri 12/31/1999 19:32:48 PST */ + {{0, 48, 32, 19, 31, 11, 1999, 5, 364, { -28800, 0}}, + {0, 0, 30, 20}, + {0, 48, 2, 0, 2, 0, 2000, 0, 1, { 0, 0}}, /*Sun Jan 2 00:02:48 UTC 2000*/ + {0, 48, 2, 16, 1, 0, 2000, 6, 0, { -28800, 0}},/* Sat Jan 1 16:02:48 + PST 2000*/ + }, + /* Fri 99-12-31 23:59:02 GMT */ + {{0, 2, 59, 23, 31, 11, 1999, 5, 364, { 0, 0}}, + {0, 0, 45, 0}, + {0, 2, 44, 0, 1, 0, 2000, 6, 0, { 0, 0}},/* Sat Jan 1 00:44:02 UTC 2000*/ + {0, 2, 44, 16, 31, 11, 1999, 5, 364, { -28800, 0}}/*Fri Dec 31 16:44:02 + PST 1999*/ + }, + /* 99-12-25 12:00:00 GMT */ + {{0, 0, 0, 12, 25, 11, 1999, 6, 358, { 0, 0}}, + {0, 0, 0, 364 * 24}, + {0, 0, 0, 12, 23, 11, 2000, 6, 357, { 0, 0}},/*Sat Dec 23 12:00:00 + 2000 UTC*/ + {0, 0, 0, 4, 23, 11, 2000, 6, 357, { -28800, 0}}/*Sat Dec 23 04:00:00 + 2000 -0800*/ + }, + /* 00-01-1 00:00:00 PST */ + {{0, 0, 0, 0, 1, 0, 2000, 6, 0, { -28800, 0}}, + {0, 0, 0, 48}, + {0, 0, 0, 8, 3, 0, 2000, 1, 2, { 0, 0}},/*Mon Jan 3 08:00:00 2000 UTC*/ + {0, 0, 0, 0, 3, 0, 2000, 1, 2, { -28800, 0}}/*Mon Jan 3 00:00:00 2000 + -0800*/ + }, + /* 00-01-10 12:00:00 PST */ + {{0, 0, 0, 12, 10, 0, 2000, 1, 9, { -28800, 0}}, + {0, 0, 0, 364 * 5 * 24}, + {0, 0, 0, 20, 3, 0, 2005, 1, 2, { 0, 0}},/*Mon Jan 3 20:00:00 2005 UTC */ + {0, 0, 0, 12, 3, 0, 2005, 1, 2, { -28800, 0}}/*Mon Jan 3 12:00:00 + 2005 -0800*/ + }, + /* 00-02-28 15:39 GMT */ + {{0, 0, 39, 15, 28, 1, 2000, 1, 58, { 0, 0}}, + {0, 0, 0, 24}, + {0, 0, 39, 15, 29, 1, 2000, 2, 59, { 0, 0}}, /*Tue Feb 29 15:39:00 2000 + UTC*/ + {0, 0, 39, 7, 29, 1, 2000, 2, 59, { -28800, 0}}/*Tue Feb 29 07:39:00 + 2000 -0800*/ + }, + /* 01-03-01 12:00 PST */ + {{0, 0, 0, 12, 3, 0, 2001, 3, 2, { -28800, 0}},/*Wed Jan 3 12:00:00 + -0800 2001*/ + {0, 30, 30,45}, + {0, 30, 30, 17, 5, 0, 2001, 5, 4, { 0, 0}}, /*Fri Jan 5 17:30:30 2001 + UTC*/ + {0, 30, 30, 9, 5, 0, 2001, 5, 4, { -28800, 0}} /*Fri Jan 5 09:30:30 + 2001 -0800*/ + }, + /* 2004-04-26 12:00 GMT */ + {{0, 0, 0, 20, 3, 0, 2001, 3, 2, { 0, 0}}, + {0, 0, 30,0}, + {0, 0, 30, 20, 3, 0, 2001, 3, 2, { 0, 0}},/*Wed Jan 3 20:30:00 2001 UTC*/ + {0, 0, 30, 12, 3, 0, 2001, 3, 2, { -28800, 0}}/*Wed Jan 3 12:30:00 + 2001 -0800*/ + }, + /* 99-09-09 00:00 GMT */ + {{0, 0, 0, 0, 9, 8, 1999, 4, 251, { 0, 0}}, + {0, 0, 0, 12}, + {0, 0, 0, 12, 9, 8, 1999, 4, 251, { 0, 0}},/*Thu Sep 9 12:00:00 1999 UTC*/ + {0, 0, 0, 5, 9, 8, 1999, 4, 251, { -28800, 3600}}/*Thu Sep 9 05:00:00 + 1999 -0700*/ + } +}; + +void add_time_increment(PRExplodedTime *et1, time_increment_t *it) +{ + et1->tm_usec += it->ti_usec; + et1->tm_sec += it->ti_sec; + et1->tm_min += it->ti_min; + et1->tm_hour += it->ti_hour; +} + +/* +** TestNormalizeTime() -- Test PR_NormalizeTime() +** For each data item, add the time increment to the base_time and then +** normalize it for GMT and local time zones. This test assumes that +** the local time zone is the Pacific Time Zone. The normalized values +** should match the expected values in the data item. +** +*/ +PRStatus TestNormalizeTime(void) +{ +int idx, count; +normalize_test_data_t *itemp; +time_increment_t *itp; + + count = sizeof(normalize_test_array)/sizeof(normalize_test_array[0]); + for (idx = 0; idx < count; idx++) { + itemp = &normalize_test_array[idx]; + if (debug_mode) { + printf("%2d. %15s",idx +1,"Base time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + itp = &itemp->increment; + if (debug_mode) { + printf("%20s %2d hrs %2d min %3d sec\n","Add",itp->ti_hour, + itp->ti_min, itp->ti_sec); + } + add_time_increment(&itemp->base_time, &itemp->increment); + PR_NormalizeTime(&itemp->base_time, PR_LocalTimeParameters); + if (debug_mode) { + printf("%19s","PST time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + if (!ExplodedTimeIsEqual(&itemp->base_time, + &itemp->expected_uspt_time)) { + printf("PR_NormalizeTime failed\n"); + if (debug_mode) + PrintExplodedTime(&itemp->expected_uspt_time); + return PR_FAILURE; + } + PR_NormalizeTime(&itemp->base_time, PR_GMTParameters); + if (debug_mode) { + printf("%19s","GMT time: "); + PrintExplodedTime(&itemp->base_time); + printf("\n"); + } + + if (!ExplodedTimeIsEqual(&itemp->base_time, + &itemp->expected_gmt_time)) { + printf("PR_NormalizeTime failed\n"); + return PR_FAILURE; + } + } + return PR_SUCCESS; +} + + +/* +** ParseTest. Structure defining a string time and a matching exploded time +** +*/ +typedef struct ParseTest +{ + char *sDate; /* string to be converted using PR_ParseTimeString() */ + PRExplodedTime et; /* expected result of the conversion */ +} ParseTest; + +static ParseTest parseArray[] = +{ + /* |<----- expected result ------------------------------------------->| */ + /* "string to test" usec sec min hour day mo year wday julian {gmtoff, dstoff }*/ + { "Thursday 1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1 Jan 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01-Jan-1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 1, 1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 1, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01, 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01 1970 00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "January 01 1970 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01-01-1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/1970", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/70", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "01/01/70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/1/1 00:00:", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "00:00 Thursday, January 1, 1970",{ 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "1-Jan-70 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + { "70/01/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 1970, 4, 0, {-28800, 0 }}}, + + /* 31-Dec-1969 */ + { "Wed 31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "31 Dec 1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "12/31/69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "12/31/1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "12-31-69 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "12-31-1969 00:00:00", { 000000, 00, 00, 00, 31, 11, 1969, 3, 364, {-28800, 0 }}}, + { "69-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + { "69/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2069, 2, 364, {-28800, 0 }}}, + + /* "Sun". 31-Dec-1998 (?) */ + { "Thu 31 Dec 1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12/31/98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12/31/1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12-31-98 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "12-31-1998 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "98-12-31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + { "98/12/31 00:00:00", { 00000, 00, 00, 00, 31, 11, 1998, 4, 364, {-28800, 0 }}}, + + /* 09-Sep-1999. Interesting because of its use as an eof marker? */ + { "09 Sep 1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9/9/99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9/9/1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9-9-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "9-9-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "09-09-99 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "09-09-1999 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + { "99-09-09 00:00:00", { 000000, 00, 00, 00, 9, 8, 1999, 4, 251, {-28800, 3600 }}}, + + /* "Sun". 10-Sep-1999. Because Sun said so. */ + { "10 Sep 1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9/10/99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9/10/1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "9-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "09-10-99 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "09-10-1999 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + { "99-09-10 00:00:00", { 000000, 00, 00, 00, 10, 8, 1999, 5, 252, {-28800, 3600 }}}, + + /* 31-Dec-1999 */ + { "31 Dec 1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12/31/99 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12/31/1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12-31-99 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "12-31-1999 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "99-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + { "99/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 1999, 5, 364, {-28800, 0 }}}, + + /* 01-Jan-2000 */ + { "01 Jan 2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1/1/00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1-1-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "1-1-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "01-01-00 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + { "Saturday 01-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 0, 2000, 6, 0, {-28800, 0 }}}, + + /* "Sun". 28-Feb-2000 */ + { "28 Feb 2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2/28/00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2/28/2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "2-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "02-28-00 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + { "02-28-2000 00:00:00", { 000000, 00, 00, 00, 28, 1, 2000, 1, 58, {-28800, 0 }}}, + + /* 29-Feb-2000 */ + { "29 Feb 2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2/29/00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2/29/2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2-29-00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "2-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "02-29-00 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + { "02-29-2000 00:00:00", { 000000, 00, 00, 00, 29, 1, 2000, 2, 59, {-28800, 0 }}}, + + /* 01-Mar-2000 */ + { "01 Mar 2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3/1/00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3/1/2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "3-1-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "03-01-00 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + { "03-01-2000 00:00:00", { 000000, 00, 00, 00, 1, 2, 2000, 3, 60, {-28800, 0 }}}, + + /* "Sun". 31-Dec-2000 */ + { "31 Dec 2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12/31/00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12/31/2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12-31-00 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "12-31-2000 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "00-12-31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + { "00/12/31 00:00:00", { 000000, 00, 00, 00, 31, 11, 2000, 0, 365, {-28800, 0 }}}, + + /* "Sun". 01-Jan-2001 */ + { "01 Jan 2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1/1/01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1/1/2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1-1-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "1-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "01-01-01 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + { "Saturday 01-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 0, 2001, 1, 0, {-28800, 0 }}}, + + /* 01-Mar-2001 */ + { "01 Mar 2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3/1/01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3/1/2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3-1-01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "3-1-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "03-01-01 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + { "03-01-2001 00:00:00", { 000000, 00, 00, 00, 1, 2, 2001, 4, 59, {-28800, 0 }}}, + + /* 29-Feb-2004 */ + { "29 Feb 2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2/29/04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2/29/2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2-29-04 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + { "2-29-2004 00:00:00", { 000000, 00, 00, 00, 29, 1, 2004, 0, 59, {-28800, 0 }}}, + + /* 01-Mar-2004 */ + { "01 Mar 2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3/1/04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3/1/2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3-1-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "3-1-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "03-01-04 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + { "03-01-2004 00:00:00", { 000000, 00, 00, 00, 1, 2, 2004, 1, 60, {-28800, 0 }}}, + + /* 01-Mar-2005 */ + { "01 Mar 2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3/1/05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3/1/2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3-1-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "3-1-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "03-01-05 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + { "03-01-2005 00:00:00", { 000000, 00, 00, 00, 1, 2, 2005, 2, 59, {-28800, 0 }}}, + + /* last element. string must be null */ + { NULL } +}; /* end array of ParseTest */ + +/* +** TestParseTime() -- Test PR_ParseTimeString() for y2k compliance +** +** TestParseTime() loops thru the array parseArray. For each element in +** the array, he calls PR_ParseTimeString() with sDate as the conversion +** argument. The result (ct) is then converted to a PRExplodedTime structure +** and compared with the exploded time value (parseArray[n].et) in the +** array element; if equal, the element passes the test. +** +** The array parseArray[] contains entries that are interesting to the +** y2k problem. +** +** +*/ +static PRStatus TestParseTime( void ) +{ + ParseTest *ptp = parseArray; + PRTime ct; + PRExplodedTime cet; + char *sp = ptp->sDate; + PRStatus rc; + PRStatus rv = PR_SUCCESS; + + while ( sp != NULL) + { + rc = PR_ParseTimeString( sp, PR_FALSE, &ct ); + if ( PR_FAILURE == rc ) + { + printf("TestParseTime(): PR_ParseTimeString() failed to convert: %s\n", sp ); + rv = PR_FAILURE; + failed_already = 1; + } + else + { + PR_ExplodeTime( ct, PR_LocalTimeParameters , &cet ); + + if ( !ExplodedTimeIsEqual( &cet, &ptp->et )) + { + printf("TestParseTime(): Exploded time compare failed: %s\n", sp ); + if ( debug_mode ) + { + PrintExplodedTime( &cet ); + printf("\n"); + PrintExplodedTime( &ptp->et ); + printf("\n"); + } + + rv = PR_FAILURE; + failed_already = 1; + } + } + + /* point to next element in array, keep going */ + ptp++; + sp = ptp->sDate; + } /* end while() */ + + return( rv ); +} /* end TestParseTime() */ + +int main(int argc, char** argv) +{ + /* The command line argument: -d is used to determine if the test is being run + in debug mode. The regress tool requires only one line output:PASS or FAIL. + All of the printfs associated with this test has been handled with a if (debug_mode) + test. + Usage: test_name -d + */ + PLOptStatus os; + PLOptState *opt; + + PR_STDIO_INIT(); + opt = PL_CreateOptState(argc, argv, "d"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + /* main test */ + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + lm = PR_NewLogModule("test"); + +#ifdef XP_MAC + /* Set up the console */ + InitializeSIOUX(true); + debug_mode = PR_TRUE; +#endif + + if ( PR_FAILURE == TestExplodeImplodeTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestExplodeImplodeTime() failed")); + } + else + printf("Test 1: Calendar Time Test passed\n"); + + if ( PR_FAILURE == TestNormalizeTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestNormalizeTime() failed")); + } + else + printf("Test 2: Normalize Time Test passed\n"); + + if ( PR_FAILURE == TestParseTime()) + { + PR_LOG( lm, PR_LOG_ERROR, + ("TestParseTime() failed")); + } + else + printf("Test 3: Parse Time Test passed\n"); + +#ifdef XP_MAC + if (1) + { + char dummyChar; + + printf("Press return to exit\n\n"); + scanf("%c", &dummyChar); + } +#endif + + if (failed_already) + return 1; + else + return 0; +} /* end main() y2k.c */ + diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/y2ktmo.c b/src/libs/xpcom18a4/nsprpub/pr/tests/y2ktmo.c new file mode 100644 index 00000000..a37ae072 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/y2ktmo.c @@ -0,0 +1,546 @@ +/* -*- 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 ***** */ + +/* + * Test: y2ktmo + * + * Description: + * This test tests the interval time facilities in NSPR for Y2K + * compliance. All the functions that take a timeout argument + * are tested: PR_Sleep, socket I/O (PR_Accept is taken as a + * representative), PR_Poll, PR_WaitCondVar, PR_Wait, and + * PR_CWait. A thread of each thread scope (local, global, and + * global bound) is created to call each of these functions. + * The test should be started at the specified number of seconds + * (called the lead time) before a Y2K rollover test date. The + * timeout values for these threads will span over the rollover + * date by at least the specified number of seconds. For + * example, if the lead time is 5 seconds, the test should + * be started at time (D - 5), where D is a rollover date, and + * the threads will time out at or after time (D + 5). The + * timeout values for the threads are spaced one second apart. + * + * When a thread times out, it calls PR_IntervalNow() to verify + * that it did wait for the specified time. In addition, it + * calls a platform-native function to verify the actual elapsed + * time again, to rule out the possibility that PR_IntervalNow() + * is broken. We allow the actual elapsed time to deviate from + * the specified timeout by a certain tolerance (in milliseconds). + */ + +#include "nspr.h" +#include "plgetopt.h" + +#include +#include +#include +#if defined(XP_UNIX) +#include /* for gettimeofday */ +#endif +#if defined(WIN32) +#include +#include /* for _ftime */ +#endif + +#define DEFAULT_LEAD_TIME_SECS 5 +#define DEFAULT_TOLERANCE_MSECS 500 + +static PRBool debug_mode = PR_FALSE; +static PRInt32 lead_time_secs = DEFAULT_LEAD_TIME_SECS; +static PRInt32 tolerance_msecs = DEFAULT_TOLERANCE_MSECS; +static PRIntervalTime start_time; +static PRIntervalTime tolerance; + +#if defined(XP_UNIX) +static struct timeval start_time_tv; +#endif +#if defined(WIN32) +static struct _timeb start_time_tb; +#endif + +static void SleepThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + + if (PR_Sleep(timeout) == PR_FAILURE) { + fprintf(stderr, "PR_Sleep failed\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (debug_mode) { + fprintf(stderr, "Sleep thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void AcceptThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRFileDesc *sock; + PRNetAddr addr; + PRFileDesc *accepted; + + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + accepted = PR_Accept(sock, NULL, timeout); + if (accepted != NULL || PR_GetError() != PR_IO_TIMEOUT_ERROR) { + fprintf(stderr, "PR_Accept did not time out\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (debug_mode) { + fprintf(stderr, "Accept thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void PollThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRFileDesc *sock; + PRNetAddr addr; + PRPollDesc pd; + PRIntn rv; + + sock = PR_NewTCPSocket(); + if (sock == NULL) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + memset(&addr, 0, sizeof(addr)); + addr.inet.family = PR_AF_INET; + addr.inet.port = 0; + addr.inet.ip = PR_htonl(PR_INADDR_ANY); + if (PR_Bind(sock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + if (PR_Listen(sock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + pd.fd = sock; + pd.in_flags = PR_POLL_READ; + rv = PR_Poll(&pd, 1, timeout); + if (rv != 0) { + fprintf(stderr, "PR_Poll did not time out\n"); + exit(1); + } + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (debug_mode) { + fprintf(stderr, "Poll thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitCondVarThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRLock *ml; + PRCondVar *cv; + + ml = PR_NewLock(); + if (ml == NULL) { + fprintf(stderr, "PR_NewLock failed\n"); + exit(1); + } + cv = PR_NewCondVar(ml); + if (cv == NULL) { + fprintf(stderr, "PR_NewCondVar failed\n"); + exit(1); + } + PR_Lock(ml); + PR_WaitCondVar(cv, timeout); + PR_Unlock(ml); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + PR_DestroyCondVar(cv); + PR_DestroyLock(ml); + if (debug_mode) { + fprintf(stderr, "wait cond var thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitMonitorThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + PRMonitor *mon; + + mon = PR_NewMonitor(); + if (mon == NULL) { + fprintf(stderr, "PR_NewMonitor failed\n"); + exit(1); + } + PR_EnterMonitor(mon); + PR_Wait(mon, timeout); + PR_ExitMonitor(mon); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + PR_DestroyMonitor(mon); + if (debug_mode) { + fprintf(stderr, "wait monitor thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +static void WaitCMonitorThread(void *arg) +{ + PRIntervalTime timeout = (PRIntervalTime) arg; + PRIntervalTime elapsed; +#if defined(XP_UNIX) || defined(WIN32) + PRInt32 timeout_msecs = PR_IntervalToMilliseconds(timeout); + PRInt32 elapsed_msecs; +#endif +#if defined(XP_UNIX) + struct timeval end_time_tv; +#endif +#if defined(WIN32) + struct _timeb end_time_tb; +#endif + int dummy; + + PR_CEnterMonitor(&dummy); + PR_CWait(&dummy, timeout); + PR_CExitMonitor(&dummy); + elapsed = (PRIntervalTime)(PR_IntervalNow() - start_time); + if (elapsed + tolerance < timeout || elapsed > timeout + tolerance) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#if defined(XP_UNIX) + gettimeofday(&end_time_tv, NULL); + elapsed_msecs = 1000*(end_time_tv.tv_sec - start_time_tv.tv_sec) + + (end_time_tv.tv_usec - start_time_tv.tv_usec)/1000; +#endif +#if defined(WIN32) + _ftime(&end_time_tb); + elapsed_msecs = 1000*(end_time_tb.time - start_time_tb.time) + + (end_time_tb.millitm - start_time_tb.millitm); +#endif +#if defined(XP_UNIX) || defined(WIN32) + if (elapsed_msecs + tolerance_msecs < timeout_msecs + || elapsed_msecs > timeout_msecs + tolerance_msecs) { + fprintf(stderr, "timeout wrong\n"); + exit(1); + } +#endif + if (debug_mode) { + fprintf(stderr, "wait cached monitor thread (scope %d) done\n", + PR_GetThreadScope(PR_GetCurrentThread())); + } +} + +typedef void (*NSPRThreadFunc)(void*); + +static NSPRThreadFunc threadFuncs[] = { + SleepThread, AcceptThread, PollThread, + WaitCondVarThread, WaitMonitorThread, WaitCMonitorThread}; + +static PRThreadScope threadScopes[] = { + PR_LOCAL_THREAD, PR_GLOBAL_THREAD, PR_GLOBAL_BOUND_THREAD}; + +static void Help(void) +{ + fprintf(stderr, "y2ktmo test program usage:\n"); + fprintf(stderr, "\t-d debug mode (FALSE)\n"); + fprintf(stderr, "\t-l lead time (%d)\n", + DEFAULT_LEAD_TIME_SECS); + fprintf(stderr, "\t-t tolerance (%d)\n", + DEFAULT_TOLERANCE_MSECS); + fprintf(stderr, "\t-h this message\n"); +} /* Help */ + +int main(int argc, char **argv) +{ + PRThread **threads; + int num_thread_funcs = sizeof(threadFuncs)/sizeof(NSPRThreadFunc); + int num_thread_scopes = sizeof(threadScopes)/sizeof(PRThreadScope); + int i, j; + int idx; + PRInt32 secs; + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "dl:t:h"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { + if (PL_OPT_BAD == os) continue; + switch (opt->option) { + case 'd': /* debug mode */ + debug_mode = PR_TRUE; + break; + case 'l': /* lead time */ + lead_time_secs = atoi(opt->value); + break; + case 't': /* tolerance */ + tolerance_msecs = atoi(opt->value); + break; + case 'h': + default: + Help(); + return 2; + } + } + PL_DestroyOptState(opt); + + if (debug_mode) { + fprintf(stderr, "lead time: %d secs\n", lead_time_secs); + fprintf(stderr, "tolerance: %d msecs\n", tolerance_msecs); + } + + start_time = PR_IntervalNow(); +#if defined(XP_UNIX) + gettimeofday(&start_time_tv, NULL); +#endif +#if defined(WIN32) + _ftime(&start_time_tb); +#endif + tolerance = PR_MillisecondsToInterval(tolerance_msecs); + + threads = PR_Malloc( + num_thread_scopes * num_thread_funcs * sizeof(PRThread*)); + if (threads == NULL) { + fprintf(stderr, "PR_Malloc failed\n"); + exit(1); + } + + /* start to time out 5 seconds after a rollover date */ + secs = lead_time_secs + 5; + idx = 0; + for (i = 0; i < num_thread_scopes; i++) { + for (j = 0; j < num_thread_funcs; j++) { + threads[idx] = PR_CreateThread(PR_USER_THREAD, threadFuncs[j], + (void*)PR_SecondsToInterval(secs), PR_PRIORITY_NORMAL, + threadScopes[i], PR_JOINABLE_THREAD, 0); + if (threads[idx] == NULL) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + secs++; + idx++; + } + } + for (idx = 0; idx < num_thread_scopes*num_thread_funcs; idx++) { + if (PR_JoinThread(threads[idx]) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + } + PR_Free(threads); + printf("PASS\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/nsprpub/pr/tests/yield.c b/src/libs/xpcom18a4/nsprpub/pr/tests/yield.c new file mode 100644 index 00000000..5f441a19 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/tests/yield.c @@ -0,0 +1,88 @@ +/* -*- 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 +#include "prthread.h" +#include "prinit.h" +#ifndef XP_OS2 +#include "private/pprmisc.h" +#include +#else +#include "primpl.h" +#include +#endif + +#define THREADS 10 + + +void +threadmain(void *_id) +{ + int id = (int)_id; + int index; + + printf("thread %d alive\n", id); + for (index=0; index<10; index++) { + printf("thread %d yielding\n", id); + PR_Sleep(0); + printf("thread %d awake\n", id); + } + printf("thread %d dead\n", id); + +} + +main() +{ + int index; + PRThread *a[THREADS]; + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 5); + PR_STDIO_INIT(); + + for (index=0; index + +int main() +{ + printf("PASS\n"); + return 0; +} + +#else /* XP_UNIX */ + +#include "nspr.h" +#include "private/pprio.h" + +#include +#include +#include +#include +#include + +static void ClientThread(void *arg) +{ + PRFileDesc *sock; + PRNetAddr addr; + PRUint16 port = (PRUint16) arg; + char buf[1024]; + PRInt32 nbytes; + + sock = PR_NewTCPSocket(); + if (NULL == sock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrLoopback, port, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "PR_Connect failed\n"); + exit(1); + } + /* + * Sleep 5 seconds to force the server thread to get EAGAIN. + */ + if (PR_Sleep(PR_SecondsToInterval(5)) == PR_FAILURE) { + fprintf(stderr, "PR_Sleep failed\n"); + exit(1); + } + /* + * Then start reading. + */ + while ((nbytes = PR_Read(sock, buf, sizeof(buf))) > 0) { + /* empty loop body */ + } + if (-1 == nbytes) { + fprintf(stderr, "PR_Read failed\n"); + exit(1); + } + if (PR_Close(sock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } +} + +int main() +{ + PRFileDesc *listenSock; + PRFileDesc *acceptSock; + int osfd; + PRThread *clientThread; + PRNetAddr addr; + char buf[1024]; + PRInt32 nbytes; + PRIOVec iov; + + memset(buf, 0, sizeof(buf)); /* Initialize the buffer. */ + listenSock = PR_NewTCPSocket(); + if (NULL == listenSock) { + fprintf(stderr, "PR_NewTCPSocket failed\n"); + exit(1); + } + if (PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_InitializeNetAddr failed\n"); + exit(1); + } + if (PR_Bind(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_Bind failed\n"); + exit(1); + } + /* Find out what port number we are bound to. */ + if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { + fprintf(stderr, "PR_GetSockName failed\n"); + exit(1); + } + if (PR_Listen(listenSock, 5) == PR_FAILURE) { + fprintf(stderr, "PR_Listen failed\n"); + exit(1); + } + + /* + * First test PR_Writev. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + iov.iov_base = buf; + iov.iov_len = 0; + printf("calling PR_Writev with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Writev(acceptSock, &iov, 1, PR_INTERVAL_NO_TIMEOUT); + if (nbytes != 0) { + fprintf(stderr, "PR_Writev should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + /* + * Then test PR_Write. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + printf("calling PR_Write with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Write(acceptSock, buf, 0); + if (nbytes != 0) { + fprintf(stderr, "PR_Write should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + /* + * Finally test PR_Send. + */ + clientThread = PR_CreateThread(PR_USER_THREAD, + ClientThread, (void *) PR_ntohs(PR_NetAddrInetPort(&addr)), + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); + if (NULL == clientThread) { + fprintf(stderr, "PR_CreateThread failed\n"); + exit(1); + } + acceptSock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); + if (NULL == acceptSock) { + fprintf(stderr, "PR_Accept failed\n"); + exit(1); + } + osfd = PR_FileDesc2NativeHandle(acceptSock); + while ((nbytes = write(osfd, buf, sizeof(buf))) != -1) { + /* empty loop body */ + } + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + fprintf(stderr, "write failed\n"); + exit(1); + } + printf("calling PR_Send with a zero-length buffer\n"); + fflush(stdout); + nbytes = PR_Send(acceptSock, buf, 0, 0, PR_INTERVAL_NO_TIMEOUT); + if (nbytes != 0) { + fprintf(stderr, "PR_Send should return 0 but returns %d\n", nbytes); + exit(1); + } + if (PR_Close(acceptSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + if (PR_JoinThread(clientThread) == PR_FAILURE) { + fprintf(stderr, "PR_JoinThread failed\n"); + exit(1); + } + + if (PR_Close(listenSock) == PR_FAILURE) { + fprintf(stderr, "PR_Close failed\n"); + exit(1); + } + printf("PASS\n"); + return 0; +} + +#endif /* XP_UNIX */ diff --git a/src/libs/xpcom18a4/nsprpub/tools/.cvsignore b/src/libs/xpcom18a4/nsprpub/tools/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/tools/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/nsprpub/tools/Makefile.in b/src/libs/xpcom18a4/nsprpub/tools/Makefile.in new file mode 100644 index 00000000..eb18de01 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/tools/Makefile.in @@ -0,0 +1,249 @@ +# +# ***** 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 ***** + +#! gmake + +MOD_DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(MOD_DEPTH)/config/autoconf.mk + +include $(topsrcdir)/config/config.mk + +ifeq ($(OS_TARGET), WIN16) +OS_CFLAGS = $(OS_EXE_CFLAGS) +endif + + +DIRS = + +CSRCS = \ + httpget.c \ + tail.c \ + $(NULL) + +ifeq (,$(filter-out WINNT OS2,$(OS_ARCH))) +PROG_SUFFIX = .exe +else +PROG_SUFFIX = +endif + +PROGS = $(addprefix $(OBJDIR)/, $(CSRCS:.c=$(PROG_SUFFIX))) + +TARGETS = $(PROGS) + +INCLUDES = -I$(dist_includedir) + +NSPR_VERSION = 3 + +# Setting the variables LDOPTS and LIBPR. We first initialize +# them to the default values, then adjust them for some platforms. +LDOPTS = -L$(dist_libdir) +LIBPR = -lnspr$(NSPR_VERSION) +LIBPLC = -lplc$(NSPR_VERSION) + +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET), WIN16) + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(NSPR_VERSION).lib +else +LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).$(LIB_SUFFIX) +LIBPLC= $(dist_libdir)/libplc$(NSPR_VERSION).$(LIB_SUFFIX) +endif +endif + +ifeq ($(OS_ARCH),OS2) + ifeq ($(MOZ_OS2_TOOLS),VACPP) + LDOPTS = -NOE -DEBUG -nologo -PMTYPE:VIO + LIBPR = $(dist_libdir)/nspr$(NSPR_VERSION).lib + LIBPLC= $(dist_libdir)/plc$(NSPR_VERSION).lib + else + LDOPTS += -Zomf -Zlinker /PM:VIO + endif +endif + +ifneq ($(OS_ARCH), WINNT) +PWD = $(shell pwd) +endif + +ifeq ($(OS_ARCH), IRIX) +LDOPTS += -rpath $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), OSF1) +LDOPTS += -rpath $(PWD)/$(dist_libdir) -lpthread +endif + +ifeq ($(OS_ARCH), HP-UX) +LDOPTS += -Wl,+s,+b,$(PWD)/$(dist_libdir) +endif + +# AIX +ifeq ($(OS_ARCH),AIX) +LDOPTS += -blibpath:$(PWD)/$(dist_libdir):/usr/lib:/lib +LIBPR = -lnspr$(NSPR_VERSION)_shr +LIBPLC = -lplc$(NSPR_VERSION)_shr +endif + +# Solaris +ifeq ($(OS_ARCH), SunOS) +ifneq ($(OS_RELEASE), 4.1.3_U1) +ifdef NS_USE_GCC +LDOPTS += -Xlinker -R -Xlinker $(PWD)/$(dist_libdir) +else +LDOPTS += -R $(PWD)/$(dist_libdir) +endif +endif + +# SunOS 5.4 and 5.5 need to link with -lthread or -lpthread, +# even though we already linked with these system libraries +# when we built libnspr.so. +ifeq ($(OS_RELEASE), 5.4) +EXTRA_LIBS = -lthread +endif + +ifeq ($(OS_RELEASE), 5.5) +ifdef USE_PTHREADS +EXTRA_LIBS = -lpthread +else +EXTRA_LIBS = -lthread +endif +endif +endif # SunOS + +ifeq ($(OS_ARCH), NCR) +# XXX: We see some strange problems when we link with libnspr.so. +# So for now we use static libraries on NCR. The shared library +# stuff below is commented out. +LIBPR = $(dist_libdir)/libnspr$(NSPR_VERSION).a +LIBPLC = $(dist_libdir)/libplc$(NSPR_VERSION).a +EXTRA_LIBS = -lsocket -lnsl -ldl + +# NCR needs to link against -lsocket -lnsl (and -lc, which is linked +# implicitly by $(CC)) again even though we already linked with these +# system libraries when we built libnspr.so. +#EXTRA_LIBS = -lsocket -lnsl +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +#export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +ifeq ($(OS_ARCH), SCOOS) +# SCO Unix needs to link against -lsocket again even though we +# already linked with these system libraries when we built libnspr.so. +EXTRA_LIBS = -lsocket +# This hardcodes in the executable programs the directory to find +# libnspr.so etc. at program startup. Equivalent to the -R or -rpath +# option for ld on other platforms. +export LD_RUN_PATH = $(PWD)/$(dist_libdir) +endif + +##################################################### +# +# The rules +# +##################################################### + +include $(topsrcdir)/config/rules.mk + +AIX_PRE_4_2 = 0 +ifeq ($(OS_ARCH),AIX) +ifneq ($(OS_RELEASE),4.2) +ifneq ($(USE_PTHREADS), 1) +#AIX_PRE_4_2 = 1 +endif +endif +endif + +ifeq ($(AIX_PRE_4_2),1) + +# AIX releases prior to 4.2 need a special two-step linking hack +# in order to both override the system select() and be able to +# get at the original system select(). +# +# We use a pattern rule in ns/nspr20/config/rules.mk to generate +# the .$(OBJ_SUFFIX) file from the .c source file, then do the +# two-step linking hack below. + +$(OBJDIR)/%: $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) + rm -f $@ $(AIX_TMP) + $(CC) $(AIX_LINK_OPTS) -o $(AIX_TMP) $< $(dist_libdir)/libnspr$(NSPR_VERSION).a + $(CC) -o $@ $(AIX_TMP) $(AIX_WRAP) + rm -f $(AIX_TMP) + +else + +# All platforms that are not AIX pre-4.2. + +$(OBJDIR)/%$(PROG_SUFFIX): $(OBJDIR)/%.$(OBJ_SUFFIX) + @$(MAKE_OBJDIR) +ifeq ($(OS_ARCH), WINNT) +ifeq ($(OS_TARGET),WIN16) + echo system windows >w16link + echo option map >>w16link + echo option stack=10K >>w16link + echo option heapsize=32K >>w16link + echo debug $(DEBUGTYPE) all >>w16link + echo name $@ >>w16link + echo file >>w16link + echo $< >>w16link + echo library >>w16link + echo $(LIBPR), >>w16link + echo $(LIBPLC), >>w16link + echo winsock.lib >>w16link + wlink @w16link. +else + link $(LDOPTS) $< $(LIBPR) $(LIBPLC) wsock32.lib -out:$@ +endif +else +ifeq ($(OS_ARCH),OS2) + $(LINK) $(LDOPTS) $< $(LIBPR) $(LIBPLC) $(OS_LIBS) $(EXTRA_LIBS) -o $@ +else + $(CC) $(XCFLAGS) $< $(LDOPTS) $(LIBPR) $(LIBPLC) $(EXTRA_LIBS) -o $@ +endif +endif +endif + +export:: $(TARGETS) +clean:: + rm -f $(TARGETS) + diff --git a/src/libs/xpcom18a4/nsprpub/tools/httpget.c b/src/libs/xpcom18a4/nsprpub/tools/httpget.c new file mode 100644 index 00000000..6eea9351 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/tools/httpget.c @@ -0,0 +1,466 @@ +/* -*- 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 ***** */ + + +/* + * Author: Wan-Teh Chang + * + * Given an HTTP URL, httpget uses the GET method to fetch the file. + * The fetched file is written to stdout by default, or can be + * saved in an output file. + * + * This is a single-threaded program. + */ + +#include "prio.h" +#include "prnetdb.h" +#include "prlog.h" +#include "prerror.h" +#include "prprf.h" +#include "prinit.h" + +#include +#include +#include /* for atoi */ + +#define FCOPY_BUFFER_SIZE (16 * 1024) +#define INPUT_BUFFER_SIZE 1024 +#define LINE_SIZE 512 +#define HOST_SIZE 256 +#define PORT_SIZE 32 +#define PATH_SIZE 512 + +/* + * A buffer for storing the excess input data for ReadLine. + * The data in the buffer starts from (including) the element pointed to + * by inputHead, and ends just before (not including) the element pointed + * to by inputTail. The buffer is empty if inputHead == inputTail. + */ + +static char inputBuf[INPUT_BUFFER_SIZE]; +/* + * inputBufEnd points just past the end of inputBuf + */ +static char *inputBufEnd = inputBuf + sizeof(inputBuf); +static char *inputHead = inputBuf; +static char *inputTail = inputBuf; + +static PRBool endOfStream = PR_FALSE; + +/* + * ReadLine -- + * + * Read in a line of text, terminated by CRLF or LF, from fd into buf. + * The terminating CRLF or LF is included (always as '\n'). The text + * in buf is terminated by a null byte. The excess bytes are stored in + * inputBuf for use in the next ReadLine call or FetchFile call. + * Returns the number of bytes in buf. 0 means end of stream. Returns + * -1 if read fails. + */ + +PRInt32 ReadLine(PRFileDesc *fd, char *buf, PRUint32 bufSize) +{ + char *dst = buf; + char *bufEnd = buf + bufSize; /* just past the end of buf */ + PRBool lineFound = PR_FALSE; + char *crPtr = NULL; /* points to the CR ('\r') character */ + PRInt32 nRead; + +loop: + PR_ASSERT(inputBuf <= inputHead && inputHead <= inputTail + && inputTail <= inputBufEnd); + while (lineFound == PR_FALSE && inputHead != inputTail + && dst < bufEnd - 1) { + if (*inputHead == '\r') { + crPtr = dst; + } else if (*inputHead == '\n') { + lineFound = PR_TRUE; + if (crPtr == dst - 1) { + dst--; + } + } + *(dst++) = *(inputHead++); + } + if (lineFound == PR_TRUE || dst == bufEnd - 1 || endOfStream == PR_TRUE) { + *dst = '\0'; + return dst - buf; + } + + /* + * The input buffer should be empty now + */ + PR_ASSERT(inputHead == inputTail); + + nRead = PR_Read(fd, inputBuf, sizeof(inputBuf)); + if (nRead == -1) { + *dst = '\0'; + return -1; + } else if (nRead == 0) { + endOfStream = PR_TRUE; + *dst = '\0'; + return dst - buf; + } + inputHead = inputBuf; + inputTail = inputBuf + nRead; + goto loop; +} + +PRInt32 DrainInputBuffer(char *buf, PRUint32 bufSize) +{ + PRInt32 nBytes = inputTail - inputHead; + + if (nBytes == 0) { + if (endOfStream) { + return -1; + } else { + return 0; + } + } + if ((PRInt32) bufSize < nBytes) { + nBytes = bufSize; + } + memcpy(buf, inputHead, nBytes); + inputHead += nBytes; + return nBytes; +} + +PRStatus FetchFile(PRFileDesc *in, PRFileDesc *out) +{ + char buf[FCOPY_BUFFER_SIZE]; + PRInt32 nBytes; + + while ((nBytes = DrainInputBuffer(buf, sizeof(buf))) > 0) { + if (PR_Write(out, buf, nBytes) != nBytes) { + fprintf(stderr, "httpget: cannot write to file\n"); + return PR_FAILURE; + } + } + if (nBytes < 0) { + /* Input buffer is empty and end of stream */ + return PR_SUCCESS; + } + while ((nBytes = PR_Read(in, buf, sizeof(buf))) > 0) { + if (PR_Write(out, buf, nBytes) != nBytes) { + fprintf(stderr, "httpget: cannot write to file\n"); + return PR_FAILURE; + } + } + if (nBytes < 0) { + fprintf(stderr, "httpget: cannot read from socket\n"); + return PR_FAILURE; + } + return PR_SUCCESS; +} + +PRStatus FastFetchFile(PRFileDesc *in, PRFileDesc *out, PRUint32 size) +{ + PRInt32 nBytes; + PRFileMap *outfMap; + void *addr; + char *start; + PRUint32 rem; + PRUint32 bytesToRead; + PRStatus rv; + PRInt64 sz64; + + LL_UI2L(sz64, size); + outfMap = PR_CreateFileMap(out, sz64, PR_PROT_READWRITE); + PR_ASSERT(outfMap); + addr = PR_MemMap(outfMap, LL_ZERO, size); + if (addr == (void *) -1) { + fprintf(stderr, "cannot memory-map file: (%d, %d)\n", PR_GetError(), + PR_GetOSError()); + + PR_CloseFileMap(outfMap); + return PR_FAILURE; + } + PR_ASSERT(addr != (void *) -1); + start = (char *) addr; + rem = size; + while ((nBytes = DrainInputBuffer(start, rem)) > 0) { + start += nBytes; + rem -= nBytes; + } + if (nBytes < 0) { + /* Input buffer is empty and end of stream */ + return PR_SUCCESS; + } + bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; + while (rem > 0 && (nBytes = PR_Read(in, start, bytesToRead)) > 0) { + start += nBytes; + rem -= nBytes; + bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; + } + if (nBytes < 0) { + fprintf(stderr, "httpget: cannot read from socket\n"); + return PR_FAILURE; + } + rv = PR_MemUnmap(addr, size); + PR_ASSERT(rv == PR_SUCCESS); + rv = PR_CloseFileMap(outfMap); + PR_ASSERT(rv == PR_SUCCESS); + return PR_SUCCESS; +} + +PRStatus ParseURL(char *url, char *host, PRUint32 hostSize, + char *port, PRUint32 portSize, char *path, PRUint32 pathSize) +{ + char *start, *end; + char *dst; + char *hostEnd; + char *portEnd; + char *pathEnd; + + if (strncmp(url, "http", 4)) { + fprintf(stderr, "httpget: the protocol must be http\n"); + return PR_FAILURE; + } + if (strncmp(url + 4, "://", 3) || url[7] == '\0') { + fprintf(stderr, "httpget: malformed URL: %s\n", url); + return PR_FAILURE; + } + + start = end = url + 7; + dst = host; + hostEnd = host + hostSize; + while (*end && *end != ':' && *end != '/') { + if (dst == hostEnd - 1) { + fprintf(stderr, "httpget: host name too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + + if (*end == '\0') { + PR_snprintf(port, portSize, "%d", 80); + PR_snprintf(path, pathSize, "%s", "/"); + return PR_SUCCESS; + } + + if (*end == ':') { + end++; + dst = port; + portEnd = port + portSize; + while (*end && *end != '/') { + if (dst == portEnd - 1) { + fprintf(stderr, "httpget: port number too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + if (*end == '\0') { + PR_snprintf(path, pathSize, "%s", "/"); + return PR_SUCCESS; + } + } else { + PR_snprintf(port, portSize, "%d", 80); + } + + dst = path; + pathEnd = path + pathSize; + while (*end) { + if (dst == pathEnd - 1) { + fprintf(stderr, "httpget: file pathname too long\n"); + return PR_FAILURE; + } + *(dst++) = *(end++); + } + *dst = '\0'; + return PR_SUCCESS; +} + +void PrintUsage(void) { + fprintf(stderr, "usage: httpget url\n" + " httpget -o outputfile url\n" + " httpget url -o outputfile\n"); +} + +int main(int argc, char **argv) +{ + PRHostEnt hostentry; + char buf[PR_NETDB_BUF_SIZE]; + PRNetAddr addr; + PRFileDesc *socket = NULL, *file = NULL; + PRIntn cmdSize; + char host[HOST_SIZE]; + char port[PORT_SIZE]; + char path[PATH_SIZE]; + char line[LINE_SIZE]; + int exitStatus = 0; + PRBool endOfHeader = PR_FALSE; + char *url; + char *fileName = NULL; + PRUint32 fileSize; + + if (argc != 2 && argc != 4) { + PrintUsage(); + exit(1); + } + + if (argc == 2) { + /* + * case 1: httpget url + */ + url = argv[1]; + } else { + if (strcmp(argv[1], "-o") == 0) { + /* + * case 2: httpget -o outputfile url + */ + fileName = argv[2]; + url = argv[3]; + } else { + /* + * case 3: httpget url -o outputfile + */ + url = argv[1]; + if (strcmp(argv[2], "-o") != 0) { + PrintUsage(); + exit(1); + } + fileName = argv[3]; + } + } + + if (ParseURL(url, host, sizeof(host), port, sizeof(port), + path, sizeof(path)) == PR_FAILURE) { + exit(1); + } + + if (PR_GetHostByName(host, buf, sizeof(buf), &hostentry) + == PR_FAILURE) { + fprintf(stderr, "httpget: unknown host name: %s\n", host); + exit(1); + } + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons((short) atoi(port)); + addr.inet.ip = *((PRUint32 *) hostentry.h_addr_list[0]); + + socket = PR_NewTCPSocket(); + if (socket == NULL) { + fprintf(stderr, "httpget: cannot create new tcp socket\n"); + exit(1); + } + + if (PR_Connect(socket, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { + fprintf(stderr, "httpget: cannot connect to http server\n"); + exitStatus = 1; + goto done; + } + + if (fileName == NULL) { + file = PR_STDOUT; + } else { + file = PR_Open(fileName, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, + 00777); + if (file == NULL) { + fprintf(stderr, "httpget: cannot open file %s: (%d, %d)\n", + fileName, PR_GetError(), PR_GetOSError()); + exitStatus = 1; + goto done; + } + } + + cmdSize = PR_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", path); + PR_ASSERT(cmdSize == (PRIntn) strlen("GET HTTP/1.0\r\n\r\n") + + (PRIntn) strlen(path)); + if (PR_Write(socket, buf, cmdSize) != cmdSize) { + fprintf(stderr, "httpget: cannot write to http server\n"); + exitStatus = 1; + goto done; + } + + if (ReadLine(socket, line, sizeof(line)) <= 0) { + fprintf(stderr, "httpget: cannot read line from http server\n"); + exitStatus = 1; + goto done; + } + + /* HTTP response: 200 == OK */ + if (strstr(line, "200") == NULL) { + fprintf(stderr, "httpget: %s\n", line); + exitStatus = 1; + goto done; + } + + while (ReadLine(socket, line, sizeof(line)) > 0) { + if (line[0] == '\n') { + endOfHeader = PR_TRUE; + break; + } + if (strncmp(line, "Content-Length", 14) == 0 + || strncmp(line, "Content-length", 14) == 0) { + char *p = line + 14; + + while (*p == ' ' || *p == '\t') { + p++; + } + if (*p != ':') { + continue; + } + p++; + while (*p == ' ' || *p == '\t') { + p++; + } + fileSize = 0; + while ('0' <= *p && *p <= '9') { + fileSize = 10 * fileSize + (*p - '0'); + p++; + } + } + } + if (endOfHeader == PR_FALSE) { + fprintf(stderr, "httpget: cannot read line from http server\n"); + exitStatus = 1; + goto done; + } + + if (fileName == NULL || fileSize == 0) { + FetchFile(socket, file); + } else { + FastFetchFile(socket, file, fileSize); + } + +done: + if (socket) PR_Close(socket); + if (file) PR_Close(file); + PR_Cleanup(); + return exitStatus; +} diff --git a/src/libs/xpcom18a4/nsprpub/tools/tail.c b/src/libs/xpcom18a4/nsprpub/tools/tail.c new file mode 100644 index 00000000..dc729c15 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/tools/tail.c @@ -0,0 +1,166 @@ +/* -*- 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 "prio.h" +#include "prprf.h" +#include "prinit.h" +#include "prthread.h" +#include "prinrval.h" + +#include "plerror.h" +#include "plgetopt.h" + +#include + +#define BUFFER_SIZE 500 + +static PRFileDesc *out = NULL, *err = NULL; + +static void Help(void) +{ + PR_fprintf(err, "Usage: tail [-n ] [-f] [-h] \n"); + PR_fprintf(err, "\t-t Dally time in milliseconds\n"); + PR_fprintf(err, "\t-n Number of bytes before \n"); + PR_fprintf(err, "\t-f Follow the \n"); + PR_fprintf(err, "\t-h This message and nothing else\n"); +} /* Help */ + +PRIntn main(PRIntn argc, char **argv) +{ + PRIntn rv = 0; + PLOptStatus os; + PRStatus status; + PRFileDesc *file; + PRFileInfo fileInfo; + PRIntervalTime dally; + char buffer[BUFFER_SIZE]; + PRBool follow = PR_FALSE; + const char *filename = NULL; + PRUint32 position = 0, seek = 0, time = 0; + PLOptState *opt = PL_CreateOptState(argc, argv, "hfn:"); + + out = PR_GetSpecialFD(PR_StandardOutput); + err = PR_GetSpecialFD(PR_StandardError); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 0: /* it's the filename */ + filename = opt->value; + break; + case 'n': /* bytes before end of file */ + seek = atoi(opt->value); + break; + case 't': /* dally time */ + time = atoi(opt->value); + break; + case 'f': /* follow the end of file */ + follow = PR_TRUE; + break; + case 'h': /* user wants some guidance */ + Help(); /* so give him an earful */ + return 2; /* but not a lot else */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + + if (0 == time) time = 1000; + dally = PR_MillisecondsToInterval(time); + + if (NULL == filename) + { + (void)PR_fprintf(out, "Input file not specified\n"); + rv = 1; goto done; + } + file = PR_Open(filename, PR_RDONLY, 0); + if (NULL == file) + { + PL_FPrintError(err, "File cannot be opened for reading"); + return 1; + } + + status = PR_GetOpenFileInfo(file, &fileInfo); + if (PR_FAILURE == status) + { + PL_FPrintError(err, "Cannot acquire status of file"); + rv = 1; goto done; + } + if (seek > 0) + { + if (seek > fileInfo.size) seek = 0; + position = PR_Seek(file, (fileInfo.size - seek), PR_SEEK_SET); + if (-1 == (PRInt32)position) + PL_FPrintError(err, "Cannot seek to starting position"); + } + + do + { + while (position < fileInfo.size) + { + PRInt32 read, bytes = fileInfo.size - position; + if (bytes > sizeof(buffer)) bytes = sizeof(buffer); + read = PR_Read(file, buffer, bytes); + if (read != bytes) + PL_FPrintError(err, "Cannot read to eof"); + position += read; + PR_Write(out, buffer, read); + } + + if (follow) + { + PR_Sleep(dally); + status = PR_GetOpenFileInfo(file, &fileInfo); + if (PR_FAILURE == status) + { + PL_FPrintError(err, "Cannot acquire status of file"); + rv = 1; goto done; + } + } + } while (follow); + +done: + PR_Close(file); + + return rv; +} /* main */ + +/* tail.c */ diff --git a/src/libs/xpcom18a4/python/.cvsignore b/src/libs/xpcom18a4/python/.cvsignore new file mode 100644 index 00000000..9d5da30c --- /dev/null +++ b/src/libs/xpcom18a4/python/.cvsignore @@ -0,0 +1,4 @@ +*.pyc +*.pyo +*.idb +*.pdb \ No newline at end of file diff --git a/src/libs/xpcom18a4/python/Makefile.kmk b/src/libs/xpcom18a4/python/Makefile.kmk new file mode 100644 index 00000000..b8dcd44a --- /dev/null +++ b/src/libs/xpcom18a4/python/Makefile.kmk @@ -0,0 +1,789 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for Python bindings +# + +# +# Copyright (C) 2009-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + +# +# List of supported Python versions, defining a number of +# VBOX_PYTHON[26|27|31|32|32M|33|33M|34|34M|35|35M|36|36M|37|37M|38|38M|39|39M|310|310M|DEF]_[INC|LIB] variables +# which get picked up below. +# +ifeq ($(KBUILD_TARGET),darwin) # Relatively predictable, don't script. + ifn1of ($(VBOX_DEF_MACOSX_VERSION_MIN), 10.10 10.9 10.8 10.7 10.6 10.5 10.4) ## @todo @bugref{9790}: if $(VBOX_DEF_MACOSX_VERSION_MIN) vge 10.11 + VBOX_PYTHON_SUFFTBD := .tbd + else + VBOX_PYTHON_SUFFTBD := + endif + ifndef VBOX_WITHOUT_VBOXPYTHON_FOR_OSX_10_6 + if1of ($(VBOX_DEF_MACOSX_VERSION_MIN), 10.5 10.4) + VBOX_PYTHON26_INC = $(VBOX_PATH_MACOSX_SDK_10_6)/usr/include/python2.6 + VBOX_PYTHON26_LIB = $(VBOX_PATH_MACOSX_SDK_10_6)/usr/lib/libpython2.6.dylib + else if "$(VBOX_DEF_MACOSX_VERSION_MIN)" == "10.9" && "$(VBOX_XCODE_VERSION)" == "6.2" # 'effing 10.9 SDK in Xcode 6.2 is missing python. Stupid, stupid Apple!! + VBOX_PYTHON26_INC = $(VBOX_PATH_MACOSX_SDK)/../MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.6/Headers + VBOX_PYTHON26_LIB = $(VBOX_PATH_MACOSX_SDK)/../MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.6/Python + else if "$(VBOX_DEF_MACOSX_VERSION_MIN)" vlt "10.13" + VBOX_PYTHON26_INC = $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/Python.framework/Versions/2.6/Headers + VBOX_PYTHON26_LIB = $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/Python.framework/Versions/2.6/Python$(VBOX_PYTHON_SUFFTBD) + endif + if !defined(VBOX_OSE) || "$(wildcard $(VBOX_PYTHON26_LIB))" != "" + VBOX_PYTHON26_LIB_X86 = $(VBOX_PYTHON26_LIB) + else + VBOX_PYTHON26_INC = + VBOX_PYTHON26_LIB = + endif + endif + ifndef VBOX_WITHOUT_VBOXPYTHON_FOR_OSX_10_7 + if1of ($(VBOX_DEF_MACOSX_VERSION_MIN), 10.6 10.5 10.4) + VBOX_PYTHON27_INC = $(VBOX_PATH_MACOSX_SDK_10_7)/usr/include/python2.7 + VBOX_PYTHON27_LIB = $(VBOX_PATH_MACOSX_SDK_10_7)/usr/lib/libpython2.7.dylib + else if "$(VBOX_DEF_MACOSX_VERSION_MIN)" == "10.9" && "$(VBOX_XCODE_VERSION)" == "6.2" # 'effing 10.9 SDK in Xcode 6.2 is missing python. Stupid, stupid Apple!! + VBOX_PYTHON27_INC = $(VBOX_PATH_MACOSX_SDK)/../MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.7/Headers + VBOX_PYTHON27_LIB = $(VBOX_PATH_MACOSX_SDK)/../MacOSX10.10.sdk/System/Library/Frameworks/Python.framework/Versions/2.7/Python + else + VBOX_PYTHON27_INC = $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/Python.framework/Versions/2.7/Headers + VBOX_PYTHON27_LIB = $(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/Python.framework/Versions/2.7/Python$(VBOX_PYTHON_SUFFTBD) + endif + if !defined(VBOX_OSE) || "$(wildcard $(VBOX_PYTHON27_LIB))" != "" + VBOX_PYTHON27_LIB_X86 = $(VBOX_PYTHON27_LIB) + else + VBOX_PYTHON27_INC = + VBOX_PYTHON27_LIB = + endif + endif + # No Python 3.x yet as part of OSX versions including El Capitan, 10.11. + +else + # Use the script. + $(eval $(subst |,$(NL),$(shell $(VBOX_BLD_PYTHON) \ + $(PATH_SUB_CURRENT)/gen_python_deps.py \ + $(KBUILD_TARGET) \ + $(KBUILD_TARGET_ARCH) \ + $(if-expr defined(VBOX_WITH_MULTIVERSION_PYTHON),1,0)))) +endif + +ifndef VBOX_ONLY_SDK + +# +# Base Python Client Module - the C++/XPCOM bits (not actually built). +# +VBoxPythonBase_TEMPLATE = XPCOM +VBoxPythonBase_CXXFLAGS = -Wno-write-strings +VBoxPythonBase_CXXFLAGS.solaris = $(VBOX_GCC_Wno-unknown-pragmas) # /usr/include/python[23].[75]*/ceval.h:67: warning: ignoring #pragma no_inline(PyEval_EvalFrameEx) +VBoxPythonBase_DLLSUFF.darwin = .so +VBoxPythonBase_DEFS = \ + _IMPL_NS_COM \ + _IMPL_NS_BASE \ + EXPORT_XPTI_API \ + EXPORT_XPT_API \ + VBOX_PYXPCOM \ + VBOX_WITH_XPCOM \ + VBOX_PYXPCOM_VERSIONED +#VBoxPythonBase_DEFS.debug = \ +# VBOX_DEBUG_LIFETIMES +VBoxPythonBase_INCS = \ + src +VBoxPythonBase_SOURCES = \ + src/module/_xpcom.cpp \ + src/dllmain.cpp \ + src/ErrorUtils.cpp \ + src/PyGBase.cpp \ + src/PyGInputStream.cpp \ + src/PyGModule.cpp \ + src/PyGStub.cpp \ + src/PyGWeakReference.cpp \ + src/PyIClassInfo.cpp \ + src/PyIComponentManager.cpp \ + src/PyIComponentManagerObsolete.cpp \ + src/PyIEnumerator.cpp \ + src/PyIID.cpp \ + src/PyIInputStream.cpp \ + src/PyIInterfaceInfo.cpp \ + src/PyIInterfaceInfoManager.cpp \ + src/PyISimpleEnumerator.cpp \ + src/PyISupports.cpp \ + src/PyIVariant.cpp \ + src/Pyxpt_info.cpp \ + src/TypeObject.cpp \ + src/VariantUtils.cpp +VBoxPythonBase_LIBS = \ + $(PATH_STAGE_LIB)/VBoxCOM$(VBOX_SUFF_LIB) \ + $(PATH_STAGE_BIN)/VBoxXPCOM$(VBOX_SUFF_DLL) + +# pymalloc abi variant. +VBoxPythonBase_m_EXTENDS = VBoxPythonBase +VBoxPythonBase_m_DEFS = MODULE_NAME_SUFFIX=m $(VBoxPythonBase_DEFS) + +# 32-bit base. +VBoxPythonBase_x86_TEMPLATE = XPCOM-x86 +VBoxPythonBase_x86_EXTENDS = VBoxPythonBase +VBoxPythonBase_x86_DEFS = MODULE_NAME_SUFFIX=_x86 $(VBoxPythonBase_DEFS) +VBoxPythonBase_x86_LIBS = \ + $(PATH_STAGE_LIB)/VBoxCOM-x86$(VBOX_SUFF_LIB) \ + $(PATH_STAGE_BIN)/VBoxXPCOM-x86$(VBOX_SUFF_DLL) + +# 32-bit pymalloc abi variant. +VBoxPythonBase_x86_m_EXTENDS = VBoxPythonBase_x86 +VBoxPythonBase_x86_m_DEFS = MODULE_NAME_SUFFIX=_x86m $(VBoxPythonBase_DEFS) + + +ifdef VBOX_PYTHON26_INC +# +# Python 2.6 version +# +DLLS += VBoxPython2_6 +VBoxPython2_6_EXTENDS = VBoxPythonBase +VBoxPython2_6_EXTENDS_BY = appending + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_6_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.6",OSX106,) + else +VBoxPython2_6_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.6",OSX106,) + endif +VBoxPython2_6_INCS = $(VBOX_PYTHON26_INC) +VBoxPython2_6_LIBS = $(VBOX_PYTHON26_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON26_LIB_X86 +DLLS += VBoxPython2_6_x86 +VBoxPython2_6_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython2_6_x86_EXTENDS_BY = appending + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_6_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.6",OSX106,-x86) + else +VBoxPython2_6_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.6",OSX106,-x86) + endif +VBoxPython2_6_x86_INCS = $(VBOX_PYTHON26_INC) +VBoxPython2_6_x86_LIBS = $(VBOX_PYTHON26_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON27_INC +# +# Python 2.7 version +# +DLLS += VBoxPython2_7 +VBoxPython2_7_EXTENDS = VBoxPythonBase +VBoxPython2_7_EXTENDS_BY = appending + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_7_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.7",OSX107,) + else +VBoxPython2_7_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.7" && "$(length-var VBOX_DEF_MACOSX_VERSION_MIN)" == "4",OSX107,) + endif +VBoxPython2_7_INCS = $(VBOX_PYTHON27_INC) +VBoxPython2_7_LIBS = $(VBOX_PYTHON27_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON27_LIB_X86 +DLLS += VBoxPython2_7_x86 +VBoxPython2_7_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython2_7_x86_EXTENDS_BY = appending + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_7_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.7",OSX107,-x86) + else +VBoxPython2_7_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.7" && "$(length-var VBOX_DEF_MACOSX_VERSION_MIN)" == "4",OSX107,-x86) + endif +VBoxPython2_7_x86_INCS = $(VBOX_PYTHON27_INC) +VBoxPython2_7_x86_LIBS = $(VBOX_PYTHON27_LIB_X86) + endif + endif +endif + +# +# Unversioned Python 2.x. +# + if defined(VBOX_PYTHON27_INC) || defined(VBOX_PYTHON26_INC) +DLLS += VBoxPython2 +VBoxPython2_EXTENDS = VBoxPythonBase +VBoxPython2_EXTENDS_BY = appending +VBoxPython2_DEFS = VBOX_PYXPCOM_MAJOR_VERSIONED + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.7",OSX107,) + else +VBoxPython2_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.7" && "$(length-var VBOX_DEF_MACOSX_VERSION_MIN)" == "4",OSX107,) + endif + if defined(VBOX_PYTHON26_INC) +VBoxPython2_INCS = $(VBOX_PYTHON26_INC) + ifn1of ($(KBUILD_TARGET), linux) +VBoxPython2_LIBS = $(VBOX_PYTHON26_LIB) + endif + else +VBoxPython2_INCS = $(VBOX_PYTHON27_INC) + ifn1of ($(KBUILD_TARGET), linux) +VBoxPython2_LIBS = $(VBOX_PYTHON27_LIB) + endif + endif + endif + + if defined(VBOX_WITH_32_ON_64_MAIN_API) && (defined(VBOX_PYTHON27_LIB_X86) || defined(VBOX_PYTHON26_INC_X86)) +DLLS += VBoxPython2_x86 +VBoxPython2_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython2_x86_EXTENDS_BY = appending +VBoxPython2_x86_DEFS = VBOX_PYXPCOM_MAJOR_VERSIONED $(VBoxPythonBase_x86_DEFS) + ifdef KMK_WITH_VERSION_COMPARE +VBoxPython2_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" vle "10.7",OSX107,-x86) + else +VBoxPython2_x86_TEMPLATE = XPCOM$(if-expr "$(KBUILD_TARGET)" == "darwin" && "$(VBOX_DEF_MACOSX_VERSION_MIN)" <= "10.7" && "$(length-var VBOX_DEF_MACOSX_VERSION_MIN)" == "4",OSX107,-x86) + endif + if defined(VBOX_PYTHON26LIB_X86) +VBoxPython2_x86_INCS = $(VBOX_PYTHON26_INC) + ifn1of ($(KBUILD_TARGET), linux) +VBoxPython2_x86_LIBS = $(VBOX_PYTHON26_LIB_X86) + endif + else +VBoxPython2_x86_INCS = $(VBOX_PYTHON27_INC) + ifn1of ($(KBUILD_TARGET), linux) +VBoxPython2_x86_LIBS = $(VBOX_PYTHON27_LIB_X86) + endif + endif + endif + + +ifdef VBOX_PYTHON31_INC +# +# Python 3.1 version +# +DLLS += VBoxPython3_1 +VBoxPython3_1_EXTENDS = VBoxPythonBase +VBoxPython3_1_EXTENDS_BY = appending +VBoxPython3_1_TEMPLATE = XPCOM +VBoxPython3_1_INCS = $(VBOX_PYTHON31_INC) +VBoxPython3_1_LIBS = $(VBOX_PYTHON31_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON31_LIB_X86 +DLLS += VBoxPython3_1_x86 +VBoxPython3_1_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_1_x86_EXTENDS_BY = appending +VBoxPython3_1_x86_TEMPLATE = XPCOM +VBoxPython3_1_x86_INCS = $(VBOX_PYTHON31_INC) +VBoxPython3_1_x86_LIBS = $(VBOX_PYTHON31_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON32_INC +# +# Python 3.2 version +# +DLLS += VBoxPython3_2 +VBoxPython3_2_EXTENDS = VBoxPythonBase +VBoxPython3_2_EXTENDS_BY = appending +VBoxPython3_2_TEMPLATE = XPCOM +VBoxPython3_2_INCS = $(VBOX_PYTHON32_INC) +VBoxPython3_2_LIBS = $(VBOX_PYTHON32_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON32_LIB_X86 +DLLS += VBoxPython3_2_x86 +VBoxPython3_2_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_2_x86_EXTENDS_BY = appending +VBoxPython3_2_x86_TEMPLATE = XPCOM +VBoxPython3_2_x86_INCS = $(VBOX_PYTHON32_INC) +VBoxPython3_2_x86_LIBS = $(VBOX_PYTHON32_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON32M_INC +# +# Python 3.2 version with pymalloc +# +DLLS += VBoxPython3_2m +VBoxPython3_2m_EXTENDS = VBoxPythonBase_m +VBoxPython3_2m_EXTENDS_BY = appending +VBoxPython3_2m_TEMPLATE = XPCOM +VBoxPython3_2m_INCS = $(VBOX_PYTHON32M_INC) +VBoxPython3_2m_LIBS = $(VBOX_PYTHON32M_LIB) +VBoxPython3_2m_DEFS = MODULE_NAME_SUFFIX + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON32M_LIB_X86 +DLLS += VBoxPython3_2m_x86 +VBoxPython3_2m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_2m_x86_EXTENDS_BY = appending +VBoxPython3_2m_x86_TEMPLATE = XPCOM +VBoxPython3_2m_x86_INCS = $(VBOX_PYTHON32M_INC) +VBoxPython3_2m_x86_LIBS = $(VBOX_PYTHON32M_LIB_X86) + endif + endif +endif + + ifndef VBOX_WITH_ONLY_PYTHON_LIMITED_API + +ifdef VBOX_PYTHON33_INC +# +# Python 3.3 version +# +DLLS += VBoxPython3_3 +VBoxPython3_3_EXTENDS = VBoxPythonBase +VBoxPython3_3_EXTENDS_BY = appending +VBoxPython3_3_TEMPLATE = XPCOM +VBoxPython3_3_INCS = $(VBOX_PYTHON33_INC) +VBoxPython3_3_LIBS = $(VBOX_PYTHON33_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON33_LIB_X86 +DLLS += VBoxPython3_3_x86 +VBoxPython3_3_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_3_x86_EXTENDS_BY = appending +VBoxPython3_3_x86_TEMPLATE = XPCOM +VBoxPython3_3_x86_INCS = $(VBOX_PYTHON33_INC) +VBoxPython3_3_x86_LIBS = $(VBOX_PYTHON33_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON33M_INC +# +# Python 3.3 version with pymalloc +# +DLLS += VBoxPython3_3m +VBoxPython3_3m_EXTENDS = VBoxPythonBase_m +VBoxPython3_3m_EXTENDS_BY = appending +VBoxPython3_3m_TEMPLATE = XPCOM +VBoxPython3_3m_INCS = $(VBOX_PYTHON33M_INC) +VBoxPython3_3m_LIBS = $(VBOX_PYTHON33M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON33M_LIB_X86 +DLLS += VBoxPython3_3m_x86 +VBoxPython3_3m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_3m_x86_EXTENDS_BY = appending +VBoxPython3_3m_x86_TEMPLATE = XPCOM +VBoxPython3_3m_x86_INCS = $(VBOX_PYTHON33M_INC) +VBoxPython3_3m_x86_LIBS = $(VBOX_PYTHON33M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON34_INC +# +# Python 3.4 version +# +DLLS += VBoxPython3_4 +VBoxPython3_4_EXTENDS = VBoxPythonBase +VBoxPython3_4_EXTENDS_BY = appending +VBoxPython3_4_TEMPLATE = XPCOM +VBoxPython3_4_INCS = $(VBOX_PYTHON34_INC) +VBoxPython3_4_LIBS = $(VBOX_PYTHON34_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON34_LIB_X86 +DLLS += VBoxPython3_4_x86 +VBoxPython3_4_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_4_x86_EXTENDS_BY = appending +VBoxPython3_4_x86_TEMPLATE = XPCOM +VBoxPython3_4_x86_INCS = $(VBOX_PYTHON34_INC) +VBoxPython3_4_x86_LIBS = $(VBOX_PYTHON34_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON34M_INC +# +# Python 3.4 version with pymalloc +# +DLLS += VBoxPython3_4m +VBoxPython3_4m_EXTENDS = VBoxPythonBase_m +VBoxPython3_4m_EXTENDS_BY = appending +VBoxPython3_4m_TEMPLATE = XPCOM +VBoxPython3_4m_INCS = $(VBOX_PYTHON34M_INC) +VBoxPython3_4m_LIBS = $(VBOX_PYTHON34M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON34M_LIB_X86 +DLLS += VBoxPython3_4m_x86 +VBoxPython3_4m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_4m_x86_EXTENDS_BY = appending +VBoxPython3_4m_x86_TEMPLATE = XPCOM +VBoxPython3_4m_x86_INCS = $(VBOX_PYTHON34M_INC) +VBoxPython3_4m_x86_LIBS = $(VBOX_PYTHON34M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON35_INC +# +# Python 3.5 version +# +DLLS += VBoxPython3_5 +VBoxPython3_5_EXTENDS = VBoxPythonBase +VBoxPython3_5_EXTENDS_BY = appending +VBoxPython3_5_TEMPLATE = XPCOM +VBoxPython3_5_INCS = $(VBOX_PYTHON35_INC) +VBoxPython3_5_LIBS = $(VBOX_PYTHON35_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON35_LIB_X86 +DLLS += VBoxPython3_5_x86 +VBoxPython3_5_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_5_x86_EXTENDS_BY = appending +VBoxPython3_5_x86_TEMPLATE = XPCOM +VBoxPython3_5_x86_INCS = $(VBOX_PYTHON35_INC) +VBoxPython3_5_x86_LIBS = $(VBOX_PYTHON35_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON35M_INC +# +# Python 3.5 version with pymalloc +# +DLLS += VBoxPython3_5m +VBoxPython3_5m_EXTENDS = VBoxPythonBase_m +VBoxPython3_5m_EXTENDS_BY = appending +VBoxPython3_5m_TEMPLATE = XPCOM +VBoxPython3_5m_INCS = $(VBOX_PYTHON35M_INC) +VBoxPython3_5m_LIBS = $(VBOX_PYTHON35M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON35M_LIB_X86 +DLLS += VBoxPython3_5m_x86 +VBoxPython3_5m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_5m_x86_EXTENDS_BY = appending +VBoxPython3_5m_x86_TEMPLATE = XPCOM +VBoxPython3_5m_x86_INCS = $(VBOX_PYTHON35M_INC) +VBoxPython3_5m_x86_LIBS = $(VBOX_PYTHON35M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON36_INC +# +# Python 3.6 version +# +DLLS += VBoxPython3_6 +VBoxPython3_6_EXTENDS = VBoxPythonBase +VBoxPython3_6_EXTENDS_BY = appending +VBoxPython3_6_TEMPLATE = XPCOM +VBoxPython3_6_INCS = $(VBOX_PYTHON36_INC) +VBoxPython3_6_LIBS = $(VBOX_PYTHON36_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON36_LIB_X86 +DLLS += VBoxPython3_6_x86 +VBoxPython3_6_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_6_x86_EXTENDS_BY = appending +VBoxPython3_6_x86_TEMPLATE = XPCOM +VBoxPython3_6_x86_INCS = $(VBOX_PYTHON36_INC) +VBoxPython3_6_x86_LIBS = $(VBOX_PYTHON36_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON36M_INC +# +# Python 3.6 version with pymalloc +# +DLLS += VBoxPython3_6m +VBoxPython3_6m_EXTENDS = VBoxPythonBase_m +VBoxPython3_6m_EXTENDS_BY = appending +VBoxPython3_6m_TEMPLATE = XPCOM +VBoxPython3_6m_INCS = $(VBOX_PYTHON36M_INC) +VBoxPython3_6m_LIBS = $(VBOX_PYTHON36M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON36M_LIB_X86 +DLLS += VBoxPython3_6m_x86 +VBoxPython3_6m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_6m_x86_EXTENDS_BY = appending +VBoxPython3_6m_x86_TEMPLATE = XPCOM +VBoxPython3_6m_x86_INCS = $(VBOX_PYTHON36M_INC) +VBoxPython3_6m_x86_LIBS = $(VBOX_PYTHON36M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON37_INC +# +# Python 3.7 version +# +DLLS += VBoxPython3_7 +VBoxPython3_7_EXTENDS = VBoxPythonBase +VBoxPython3_7_EXTENDS_BY = appending +VBoxPython3_7_TEMPLATE = XPCOM +VBoxPython3_7_INCS = $(VBOX_PYTHON37_INC) +VBoxPython3_7_LIBS = $(VBOX_PYTHON37_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON37_LIB_X86 +DLLS += VBoxPython3_7_x86 +VBoxPython3_7_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_7_x86_EXTENDS_BY = appending +VBoxPython3_7_x86_TEMPLATE = XPCOM +VBoxPython3_7_x86_INCS = $(VBOX_PYTHON37_INC) +VBoxPython3_7_x86_LIBS = $(VBOX_PYTHON37_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON37M_INC +# +# Python 3.7 version with pymalloc +# +DLLS += VBoxPython3_7m +VBoxPython3_7m_EXTENDS = VBoxPythonBase_m +VBoxPython3_7m_EXTENDS_BY = appending +VBoxPython3_7m_TEMPLATE = XPCOM +VBoxPython3_7m_INCS = $(VBOX_PYTHON37M_INC) +VBoxPython3_7m_LIBS = $(VBOX_PYTHON37M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON37M_LIB_X86 +DLLS += VBoxPython3_7m_x86 +VBoxPython3_7m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_7m_x86_EXTENDS_BY = appending +VBoxPython3_7m_x86_TEMPLATE_ = XPCOM +VBoxPython3_7m_x86_INCS = $(VBOX_PYTHON37M_INC) +VBoxPython3_7m_x86_LIBS = $(VBOX_PYTHON37M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON38_INC +# +# Python 3.8 version +# +DLLS += VBoxPython3_8 +VBoxPython3_8_EXTENDS = VBoxPythonBase +VBoxPython3_8_EXTENDS_BY = appending +VBoxPython3_8_TEMPLATE = XPCOM +VBoxPython3_8_INCS = $(VBOX_PYTHON38_INC) +VBoxPython3_8_LIBS = $(VBOX_PYTHON38_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON38_LIB_X86 +DLLS += VBoxPython3_8_x86 +VBoxPython3_8_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_8_x86_EXTENDS_BY = appending +VBoxPython3_8_x86_TEMPLATE = XPCOM +VBoxPython3_8_x86_INCS = $(VBOX_PYTHON38_INC) +VBoxPython3_8_x86_LIBS = $(VBOX_PYTHON38_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON38M_INC +# +# Python 3.8 version with pymalloc +# +DLLS += VBoxPython3_8m +VBoxPython3_8m_EXTENDS = VBoxPythonBase_m +VBoxPython3_8m_EXTENDS_BY = appending +VBoxPython3_8m_TEMPLATE = XPCOM +VBoxPython3_8m_INCS = $(VBOX_PYTHON38M_INC) +VBoxPython3_8m_LIBS = $(VBOX_PYTHON38M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON38M_LIB_X86 +DLLS += VBoxPython3_8m_x86 +VBoxPython3_8m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_8m_x86_EXTENDS_BY = appending +VBoxPython3_8m_x86_TEMPLATE_ = XPCOM +VBoxPython3_8m_x86_INCS = $(VBOX_PYTHON38M_INC) +VBoxPython3_8m_x86_LIBS = $(VBOX_PYTHON38M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON39_INC +# +# Python 3.9 version +# +DLLS += VBoxPython3_9 +VBoxPython3_9_EXTENDS = VBoxPythonBase +VBoxPython3_9_EXTENDS_BY = appending +VBoxPython3_9_TEMPLATE = XPCOM +VBoxPython3_9_INCS = $(VBOX_PYTHON39_INC) +VBoxPython3_9_LIBS = $(VBOX_PYTHON39_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON39_LIB_X86 +DLLS += VBoxPython3_9_x86 +VBoxPython3_9_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_9_x86_EXTENDS_BY = appending +VBoxPython3_9_x86_TEMPLATE = XPCOM +VBoxPython3_9_x86_INCS = $(VBOX_PYTHON39_INC) +VBoxPython3_9_x86_LIBS = $(VBOX_PYTHON39_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON39M_INC +# +# Python 3.9 version with pymalloc +# +DLLS += VBoxPython3_9m +VBoxPython3_9m_EXTENDS = VBoxPythonBase_m +VBoxPython3_9m_EXTENDS_BY = appending +VBoxPython3_9m_TEMPLATE = XPCOM +VBoxPython3_9m_INCS = $(VBOX_PYTHON39M_INC) +VBoxPython3_9m_LIBS = $(VBOX_PYTHON39M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON39M_LIB_X86 +DLLS += VBoxPython3_9m_x86 +VBoxPython3_9m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_9m_x86_EXTENDS_BY = appending +VBoxPython3_9m_x86_TEMPLATE_ = XPCOM +VBoxPython3_9m_x86_INCS = $(VBOX_PYTHON39M_INC) +VBoxPython3_9m_x86_LIBS = $(VBOX_PYTHON39M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON310_INC +# +# Python 3.10 version +# +DLLS += VBoxPython3_10 +VBoxPython3_10_EXTENDS = VBoxPythonBase +VBoxPython3_10_EXTENDS_BY = appending +VBoxPython3_10_TEMPLATE = XPCOM +VBoxPython3_10_INCS = $(VBOX_PYTHON310_INC) +VBoxPython3_10_LIBS = $(VBOX_PYTHON310_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON310_LIB_X86 +DLLS += VBoxPython3_10_x86 +VBoxPython3_10_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython3_10_x86_EXTENDS_BY = appending +VBoxPython3_10_x86_TEMPLATE = XPCOM +VBoxPython3_10_x86_INCS = $(VBOX_PYTHON310_INC) +VBoxPython3_10_x86_LIBS = $(VBOX_PYTHON310_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHON310M_INC +# +# Python 3.10 version with pymalloc +# +DLLS += VBoxPython3_10m +VBoxPython3_10m_EXTENDS = VBoxPythonBase_m +VBoxPython3_10m_EXTENDS_BY = appending +VBoxPython3_10m_TEMPLATE = XPCOM +VBoxPython3_10m_INCS = $(VBOX_PYTHON310M_INC) +VBoxPython3_10m_LIBS = $(VBOX_PYTHON310M_LIB) + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHON310M_LIB_X86 +DLLS += VBoxPython3_10m_x86 +VBoxPython3_10m_x86_EXTENDS = VBoxPythonBase_x86_m +VBoxPython3_10m_x86_EXTENDS_BY = appending +VBoxPython3_10m_x86_TEMPLATE_ = XPCOM +VBoxPython3_10m_x86_INCS = $(VBOX_PYTHON310M_INC) +VBoxPython3_10m_x86_LIBS = $(VBOX_PYTHON310M_LIB_X86) + endif + endif +endif + +ifdef VBOX_PYTHONDEF_INC +# +# Python without versioning +# +DLLS += VBoxPython +VBoxPython_EXTENDS = VBoxPythonBase +VBoxPython_DEFS = $(filter-out VBOX_PYXPCOM_VERSIONED,$(VBoxPythonBase_DEFS)) +VBoxPython_INCS = $(VBoxPythonBase_INCS) $(VBOX_PYTHONDEF_INC) +if "$(KBUILD_TARGET)" == "linux" + VBoxPython_LIBS = $(VBoxPythonBase_LIBS) +else + VBoxPython_LIBS = $(VBoxPythonBase_LIBS) $(VBOX_PYTHONDEF_LIB) +endif + + ifdef VBOX_WITH_32_ON_64_MAIN_API + ifdef VBOX_PYTHONDEF_LIB_X86 +VBoxPython_x86_EXTENDS = VBoxPythonBase_x86 +VBoxPython_x86_DEFS = $(filter-out VBOX_PYXPCOM_VERSIONED,$(VBoxPythonBase_x86_DEFS)) +VBoxPython_x86_INCS = $(VBoxPythonBase_x86_INCS) $(VBOX_PYTHONDEF_INC) +if "$(KBUILD_TARGET)" == "linux" + VBoxPython_x86_LIBS = $(VBoxPythonBase_x86_LIBS) +else + VBoxPython_x86_LIBS = $(VBoxPythonBase_x86_LIBS) $(VBOX_PYTHONDEF_LIB_X86) +endif + endif + endif +endif + + endif # !VBOX_WITH_ONLY_PYTHON_LIMITED_API + + ifndef VBOX_WITHOUT_PYTHON_LIMITED_API +# +# If there is python 3.3 or later present, we can build a generic +# 3.x extension. Since 3.3 and 3.4 are rather old, we will pick +# those headers last. +# +# Note! No library dependencies are needed here (at least that's +# how the xxlimited.so demo extension is done on linux and darwin). +# Note! The 'm' ABI suffix was discontinued in 3.8. +# TODO: ASSUMING that we don't need a different headers for pymalloc +# ('m' builds < 3.8) and CRT malloc. +# +VBOX_PYTHON_LIMITED_API_VER := $(firstword $(foreach ver, 35 36 38 39 310 34 33 \ +,$(if-expr defined(VBOX_PYTHON$(ver)_INC),$(ver),)$(if-expr defined(VBOX_PYTHON$(ver)M_INC),$(ver)M,))) + ifneq ($(VBOX_PYTHON_LIMITED_API_VER),) +DLLS += VBoxPython3 +VBoxPython3_EXTENDS = VBoxPythonBase +VBoxPython3_DEFS = $(filter-out VBOX_PYXPCOM_VERSIONED,$(VBoxPythonBase_DEFS)) Py_LIMITED_API=0x03030000 +VBoxPython3_INCS = $(VBoxPythonBase_INCS) $(VBOX_PYTHON$(VBOX_PYTHON_LIMITED_API_VER)_INC) + +DLLS += VBoxPython3m +VBoxPython3m_EXTENDS = VBoxPythonBase_m +VBoxPython3m_DEFS = $(filter-out VBOX_PYXPCOM_VERSIONED,$(VBoxPythonBase_m_DEFS)) Py_LIMITED_API=0x03030000 +VBoxPython3m_INCS = $(VBoxPythonBase_m_INCS) $(VBOX_PYTHON$(VBOX_PYTHON_LIMITED_API_VER)_INC) + endif + endif # VBOX_WITH_PYTHON_LIMITED_API + +endif # VBOX_ONLY_SDK + +# +# Install the python modules. +# +INSTALLS += VBoxPython-inst-py-xpcom +VBoxPython-inst-py-xpcom_INST = $(INST_SDK)bindings/xpcom/python/xpcom/ +VBoxPython-inst-py-xpcom_MODE = a+r,u+w +VBoxPython-inst-py-xpcom_SOURCES = \ + vboxxpcom.py \ + components.py \ + file.py \ + __init__.py \ + nsError.py \ + primitives.py \ + xpcom_consts.py \ + xpt.py \ + client/__init__.py=>client/__init__.py \ + server/__init__.py=>server/__init__.py \ + server/enumerator.py=>server/enumerator.py \ + server/factory.py=>server/factory.py \ + server/loader.py=>server/loader.py \ + server/module.py=>server/module.py \ + server/policy.py=>server/policy.py + + +include $(FILE_KBUILD_SUB_FOOTER) diff --git a/src/libs/xpcom18a4/python/README.vbox b/src/libs/xpcom18a4/python/README.vbox new file mode 100644 index 00000000..b85f854c --- /dev/null +++ b/src/libs/xpcom18a4/python/README.vbox @@ -0,0 +1,5 @@ + PyXPCOM sources (see http://developer.mozilla.org/en/docs/PyXPCOM) +were taken from :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot, +directory extensions/python/xpcom, branch DOM_AGNOSTIC2_BRANCH, Aug 14 2008. + + Imported to VirtualBox codebase in revision 34814. diff --git a/src/libs/xpcom18a4/python/__init__.py b/src/libs/xpcom18a4/python/__init__.py new file mode 100755 index 00000000..3a5943b6 --- /dev/null +++ b/src/libs/xpcom18a4/python/__init__.py @@ -0,0 +1,173 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# Activestate Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond +# +# 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 ***** +# + +# The XPCOM (Cross Platform COM) package. +from __future__ import print_function +import sys +if sys.version_info[0] <= 2: + import exceptions + XPCOMBaseException = exceptions.Exception +else: + XPCOMBaseException = Exception + +# A global "verbose" flag - currently used by the +# server package to print trace messages +verbose = 0 +# Map of nsresult -> constant_name. +hr_map = {} + +# The standard XPCOM exception object. +# Instances of this class are raised by the XPCOM extension module. +class Exception(XPCOMBaseException): + def __init__(self, errno, message = None): + assert int(errno) == errno, "The errno param must be an integer" + self.errno = errno + self.msg = message + XPCOMBaseException.__init__(self, errno) + def __str__(self): + if not hr_map: + from . import nsError + for name, val in list(nsError.__dict__.items()): + if type(val)==type(0): + hr_map[val] = name + message = self.msg + if message is None: + message = hr_map.get(self.errno) + if message is None: + message = "" + return "0x%x (%s)" % (self.errno & 0xFFFFFFFF, message) + +# An alias for Exception - allows code to say "from xpcom import COMException" +# rather than "Exception", preventing clashes with the builtin Exception +COMException = Exception + +# Exceptions thrown by servers. It can be good for diagnostics to +# differentiate between a ServerException (which was presumably explicitly thrown) +# and a normal exception which may simply be propagating down. +# (When ServerException objects are thrown across the XPConnect +# gateway they will be converted back to normal client exceptions if +# subsequently re-caught by Python) +class ServerException(Exception): + def __init__(self, errno=None, *args, **kw): + if errno is None: + from . import nsError + errno = nsError.NS_ERROR_FAILURE + Exception.__init__(self, errno, *args, **kw) + +# Logging support - setup the 'xpcom' logger to write to the Mozilla +# console service, and also to sys.stderr, or optionally a file. +# Environment variables supports: +# PYXPCOM_LOG_FILE=filename - if set, used instead of sys.stderr. +# PYXPCOM_LOG_LEVEL=level - level may be a number or a logging level +# constant (eg, 'debug', 'error') +# Later it may make sense to allow a different log level to be set for +# the file than for the console service. +import logging +class ConsoleServiceStream: + # enough of a stream to keep logging happy + def flush(self): + pass + def write(self, msg): + import xpcom._xpcom as _xpcom + _xpcom.LogConsoleMessage(msg) + def close(self): + pass + +def setupLogging(): + import os + if sys.version_info[0] <= 2: + import threading, thread + hdlr = logging.StreamHandler(ConsoleServiceStream()) + fmt = logging.Formatter(logging.BASIC_FORMAT) + hdlr.setFormatter(fmt) + # There is a bug in 2.3 and 2.4.x logging module in that it doesn't + # use an RLock, leading to deadlocks in some cases (specifically, + # logger.warning("ob is %r", ob), and where repr(ob) itself tries to log) + # Later versions of logging use an RLock, so we detect an "old" style + # handler and update its lock + if sys.version_info[0] <= 2: + if type(hdlr.lock) == thread.LockType: + hdlr.lock = threading.RLock() + + logger.addHandler(hdlr) + # The console handler in mozilla does not go to the console!? + # Add a handler to print to stderr, or optionally a file + # PYXPCOM_LOG_FILE can specify a filename + filename = os.environ.get("PYXPCOM_LOG_FILE") + stream = sys.stderr # this is what logging uses as default + if filename: + try: + # open without buffering so never pending output + stream = open(filename, "wU", 0) + except IOError as why: + print("pyxpcom failed to open log file '%s': %s" % (filename, why), file=sys.stderr) + # stream remains default + + hdlr = logging.StreamHandler(stream) + # see above - fix a deadlock problem on this handler too. + if sys.version_info[0] <= 2: + if type(hdlr.lock) == thread.LockType: + hdlr.lock = threading.RLock() + + fmt = logging.Formatter(logging.BASIC_FORMAT) + hdlr.setFormatter(fmt) + logger.addHandler(hdlr) + # Allow PYXPCOM_LOG_LEVEL to set the level + level = os.environ.get("PYXPCOM_LOG_LEVEL") + if level: + try: + level = int(level) + except ValueError: + try: + # might be a symbolic name - all are upper-case + level = int(getattr(logging, level.upper())) + except (AttributeError, ValueError): + logger.warning("The PYXPCOM_LOG_LEVEL variable specifies an " + "invalid level") + level = None + if level: + logger.setLevel(level) + +logger = logging.getLogger('xpcom') +# If someone else has already setup this logger, leave things alone. +if len(logger.handlers) == 0: + setupLogging() + +# Cleanup namespace - but leave 'logger' there for people to use, so they +# don't need to know the exact name of the logger. +del ConsoleServiceStream, logging, setupLogging diff --git a/src/libs/xpcom18a4/python/client/.cvsignore b/src/libs/xpcom18a4/python/client/.cvsignore new file mode 100644 index 00000000..52e4e611 --- /dev/null +++ b/src/libs/xpcom18a4/python/client/.cvsignore @@ -0,0 +1,2 @@ +*.pyc +*.pyo diff --git a/src/libs/xpcom18a4/python/client/__init__.py b/src/libs/xpcom18a4/python/client/__init__.py new file mode 100755 index 00000000..48adc7f5 --- /dev/null +++ b/src/libs/xpcom18a4/python/client/__init__.py @@ -0,0 +1,539 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +import os +from types import MethodType +import logging +from xpcom import xpt, COMException, nsError, logger + +# Suck in stuff from _xpcom we use regularly to prevent a module lookup +from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, \ + IID_nsISupportsCString, IID_nsISupportsString, \ + IID_nsISupportsWeakReference, IID_nsIWeakReference, \ + XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex + +# Python 3 hacks: +import sys +if sys.version_info[0] >= 3: + long = int # pylint: disable=W0622,C0103 + +# Attribute names we may be __getattr__'d for, but know we don't want to delegate +# Could maybe just look for startswith("__") but this may screw things for some objects. +_special_getattr_names = ["__del__", "__len__", "__nonzero__", "__eq__", "__neq__"] + +_just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"] +_just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"] +_just_float_interfaces = ["nsISupportsDouble", "nsISupportsFloat"] +# When doing a specific conversion, the order we try the interfaces in. +_int_interfaces = _just_int_interfaces + _just_float_interfaces +_long_interfaces = _just_long_interfaces + _just_int_interfaces + _just_float_interfaces +_float_interfaces = _just_float_interfaces + _just_long_interfaces + _just_int_interfaces + +method_template = """ +def %s(self, %s): + return XPTC_InvokeByIndex(self._comobj_, %d, (%s, (%s))) +""" +def _MakeMethodCode(method): + # Build a declaration + param_no = 0 + param_decls = [] + param_flags = [] + param_names = [] + used_default = 0 + for param in method.params: + param_no = param_no + 1 + param_name = "Param%d" % (param_no,) + param_default = "" + if not param.hidden_indicator and param.IsIn() and not param.IsDipper(): + if param.IsOut() or used_default: # If the param is "inout", provide a useful default for the "in" direction. + param_default = " = None" + used_default = 1 # Once we have used one once, we must for the rest! + param_decls.append(param_name + param_default) + param_names.append(param_name) + + type_repr = xpt.MakeReprForInvoke(param) + param_flags.append( (param.param_flags,) + type_repr ) + sep = ", " + param_decls = sep.join(param_decls) + if len(param_names)==1: # Damn tuple reprs. + param_names = param_names[0] + "," + else: + param_names = sep.join(param_names) + # A couple of extra newlines make them easier to read for debugging :-) + return method_template % (method.name, param_decls, method.method_index, tuple(param_flags), param_names) + +# Keyed by IID, each item is a tuple of (methods, getters, setters) +interface_cache = {} +# Keyed by [iid][name], each item is an unbound method. +interface_method_cache = {} + +# Keyed by clsid from nsIClassInfo - everything ever queried for the CID. +contractid_info_cache = {} +have_shutdown = 0 + +def _shutdown(): + interface_cache.clear() + interface_method_cache.clear() + contractid_info_cache.clear() + global have_shutdown + have_shutdown = 1 + +# Fully process the named method, generating method code etc. +def BuildMethod(method_info, iid): + name = method_info.name + try: + return interface_method_cache[iid][name] + except KeyError: + pass + # Generate it. + assert not (method_info.IsSetter() or method_info.IsGetter()), "getters and setters should have been weeded out by now" + method_code = _MakeMethodCode(method_info) + # Build the method - We only build a function object here + # - they are bound to each instance as needed. + +## print "Method Code for %s (%s):" % (name, iid) +## print method_code + codeObject = compile(method_code, "" % (name,), "exec") + # Exec the code object + tempNameSpace = {} + exec(codeObject, globals(), tempNameSpace) + ret = tempNameSpace[name] + if iid not in interface_method_cache: + interface_method_cache[iid] = {} + interface_method_cache[iid][name] = ret + return ret + +from xpcom.xpcom_consts import XPT_MD_GETTER, XPT_MD_SETTER, XPT_MD_NOTXPCOM, XPT_MD_CTOR, XPT_MD_HIDDEN +FLAGS_TO_IGNORE = XPT_MD_NOTXPCOM | XPT_MD_CTOR | XPT_MD_HIDDEN + +# Pre-process the interface - generate a list of methods, constants etc, +# but don't actually generate the method code. +def BuildInterfaceInfo(iid): + assert not have_shutdown, "Can't build interface info after a shutdown" + ret = interface_cache.get(iid, None) + if ret is None: + # Build the data for the cache. + method_code_blocks = [] + getters = {} + setters = {} + method_infos = {} + + interface = xpt.Interface(iid) + for m in interface.methods: + flags = m.flags + if flags & FLAGS_TO_IGNORE == 0: + if flags & XPT_MD_SETTER: + param_flags = list([(x.param_flags,) + xpt.MakeReprForInvoke(x) for x in m.params]) + setters[m.name] = m.method_index, param_flags + elif flags & XPT_MD_GETTER: + param_flags = list([(x.param_flags,) + xpt.MakeReprForInvoke(x) for x in m.params]) + getters[m.name] = m.method_index, param_flags + else: + method_infos[m.name] = m + + # Build the constants. + constants = {} + for c in interface.constants: + constants[c.name] = c.value + ret = method_infos, getters, setters, constants + interface_cache[iid] = ret + return ret + +class _XPCOMBase: + def __cmp__(self, other): + try: + other = other._comobj_ + except AttributeError: + pass + return cmp(self._comobj_, other) + + def __hash__(self): + return hash(self._comobj_) + + # The basic rich compare ops for equality + def __eq__(self, other): + try: + other = other._comobj_ + except AttributeError: + pass + return self._comobj_ == other + + def __neq__(self, other): + try: + other = other._comobj_ + except AttributeError: + pass + return self._comobj_ != other + + # See if the object support strings. + def __str__(self): + try: + self._comobj_.QueryInterface(IID_nsISupportsCString, 0) + return str(self._comobj_) + except COMException: + return self.__repr__() + + def __unicode__(self): + try: + prin = self._comobj_.QueryInterface(IID_nsISupportsString) + except COMException: + return unicode(str(self)) + return prin.data + + # Try the numeric support. + def _do_conversion(self, interface_names, cvt): + iim = XPTI_GetInterfaceInfoManager() + for interface_name in interface_names: + iid = iim.GetInfoForName(interface_name).GetIID() + try: + prim = self._comobj_.QueryInterface(iid) + return cvt(prim.data) + except COMException: + pass + raise ValueError("This object does not support automatic numeric conversion to this type") + + def __int__(self): + if sys.version_info[0] >= 3: + return self._do_conversion(_int_interfaces + _long_interfaces, int) + return self._do_conversion(_int_interfaces, int) + + def __long__(self): + return self._do_conversion(_long_interfaces, long) + + def __float__(self): + return self._do_conversion(_float_interfaces, float) + +class Component(_XPCOMBase): + def __init__(self, ob, iid = IID_nsISupports): + assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one" + ob_name = None + if not hasattr(ob, "IID"): + ob_name = ob + cm = GetComponentManager() + ob = cm.createInstanceByContractID(ob) + assert not hasattr(ob, "_comobj_"), "The created object should be a raw nsIWhatever, not a wrapped one" + # Keep a reference to the object in the component too + self.__dict__['_comobj_'] = ob + # hit __dict__ directly to avoid __setattr__() + self.__dict__['_interfaces_'] = {} # keyed by IID + self.__dict__['_interface_names_'] = {} # keyed by IID name + self.__dict__['_interface_infos_'] = {} # keyed by IID + self.__dict__['_name_to_interface_iid_'] = {} + self.__dict__['_tried_classinfo_'] = 0 + + if ob_name is None: + ob_name = "" + self.__dict__['_object_name_'] = ob_name + self.QueryInterface(iid) + + def _build_all_supported_interfaces_(self): + # Use nsIClassInfo, but don't do it at object construction to keep perf up. + # Only pay the penalty when we really need it. + assert not self._tried_classinfo_, "already tried to get the class info." + self.__dict__['_tried_classinfo_'] = 1 + # See if nsIClassInfo is supported. + try: + classinfo = self._comobj_.QueryInterface(IID_nsIClassInfo, 0) + except COMException: + classinfo = None + if classinfo is not None: + try: + real_cid = classinfo.contractID + except COMException: + real_cid = None + if real_cid: + self.__dict__['_object_name_'] = real_cid + contractid_info = contractid_info_cache.get(real_cid) + else: + contractid_info = None + if contractid_info is None: + try: + interface_infos = classinfo.getInterfaces() + except COMException: + interface_infos = [] + for nominated_iid in interface_infos: + # Interface may appear twice in the class info list, so check this here. + if nominated_iid not in self.__dict__['_interface_infos_']: + # Just invoke our QI on the object + self.queryInterface(nominated_iid) + if real_cid is not None: + contractid_info = {} + contractid_info['_name_to_interface_iid_'] = self.__dict__['_name_to_interface_iid_'] + contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_'] + contractid_info_cache[real_cid] = contractid_info + else: + for key, val in list(contractid_info.items()): + self.__dict__[key].update(val) + + self.__dict__['_com_classinfo_'] = classinfo + + def _remember_interface_info(self, iid): + # XXX - there is no good reason to cache this only in each instance + # It should be cached at the module level, so we don't need to + # rebuild the world for each new object. + iis = self.__dict__['_interface_infos_'] + assert iid not in iis, "Already remembered this interface!" + try: + method_infos, getters, setters, constants = BuildInterfaceInfo(iid) + except COMException as why: + # Failing to build an interface info generally isn't a real + # problem - its probably just that the interface is non-scriptable. + logger.info("Failed to build interface info for %s: %s", iid, why) + # Remember the fact we failed. + iis[iid] = None + return + + # Remember all the names so we can delegate + iis[iid] = method_infos, getters, setters, constants + names = self.__dict__['_name_to_interface_iid_'] + for name in list(method_infos.keys()): names[name] = iid + for name in list(getters.keys()): names[name] = iid + for name in list(setters.keys()): names[name] = iid + for name in list(constants.keys()): names[name] = iid + + def QueryInterface(self, iid): + if iid in self._interfaces_: + assert iid.name in self._interface_names_, "_interfaces_ has the key, but _interface_names_ does not!" + return self + # Haven't seen this before - do a real QI. + if iid not in self._interface_infos_: + self._remember_interface_info(iid) + iface_info = self._interface_infos_[iid] + if iface_info is None: + # We have tried, but failed, to get this interface info. Its + # unlikely to work later either - its probably non-scriptable. + # That means our component wrappers are useless - so just return a + # raw nsISupports object with no wrapper. + return self._comobj_.QueryInterface(iid, 0) + + raw_iface = self._comobj_.QueryInterface(iid, 0) + + method_infos, getters, setters, constants = iface_info + new_interface = _Interface(raw_iface, iid, method_infos, + getters, setters, constants) + self._interfaces_[iid] = new_interface + self._interface_names_[iid.name] = new_interface + # As we 'flatten' objects when possible, a QI on an object just + # returns ourself - all the methods etc on this interface are + # available. + return self + + queryInterface = QueryInterface # Alternate name. + + def __getattr__(self, attr): + if attr in _special_getattr_names: + raise AttributeError(attr) + # First allow the interface name to return the "raw" interface + interface = self.__dict__['_interface_names_'].get(attr, None) + if interface is not None: + return interface + # See if we know the IID of an interface providing this attribute + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) + # This may be first time trying this interface - get the nsIClassInfo + if iid is None and not self._tried_classinfo_: + self._build_all_supported_interfaces_() + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) + # If the request is for an interface name, it may now be + # available. + interface = self.__dict__['_interface_names_'].get(attr, None) + if interface is not None: + return interface + + if iid is not None: + interface = self.__dict__['_interfaces_'].get(iid, None) + if interface is None: + self.QueryInterface(iid) + interface = self.__dict__['_interfaces_'][iid] + return getattr(interface, attr) + # Some interfaces may provide this name via "native" support. + # Loop over all interfaces, and if found, cache it for next time. + for interface in list(self.__dict__['_interfaces_'].values()): + try: + ret = getattr(interface, attr) + self.__dict__['_name_to_interface_iid_'][attr] = interface._iid_ + return ret + except AttributeError: + pass + raise AttributeError("XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)) + + def __setattr__(self, attr, val): + iid = self._name_to_interface_iid_.get(attr, None) + # This may be first time trying this interface - get the nsIClassInfo + if iid is None and not self._tried_classinfo_: + self._build_all_supported_interfaces_() + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) + if iid is not None: + interface = self._interfaces_.get(iid, None) + if interface is None: + self.QueryInterface(iid) + interface = self.__dict__['_interfaces_'][iid] + setattr(interface, attr, val) + return + raise AttributeError("XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)) + + def _get_classinfo_repr_(self): + try: + if not self._tried_classinfo_: + self._build_all_supported_interfaces_() + assert self._tried_classinfo_, "Should have tried the class info by now!" + except COMException: + # Error building the info - ignore the error, but ensure that + # we are flagged as *not* having built, so the error is seen + # by the first caller who actually *needs* this to work. + self.__dict__['_tried_classinfo_'] = 0 + + iface_names = list(self.__dict__['_interface_names_'].keys()) + try: + iface_names.remove("nsISupports") + except ValueError: + pass + iface_names.sort() + + iface_desc = "implementing %s" % (",".join(iface_names),) + return iface_desc + + def __repr__(self): + # We can advantage from nsIClassInfo - use it. + iface_desc = self._get_classinfo_repr_() + return "" % (self._object_name_,iface_desc) + +class _Interface(_XPCOMBase): + def __init__(self, comobj, iid, method_infos, getters, setters, constants): + self.__dict__['_comobj_'] = comobj + self.__dict__['_iid_'] = iid + self.__dict__['_property_getters_'] = getters + self.__dict__['_property_setters_'] = setters + self.__dict__['_method_infos_'] = method_infos # method infos waiting to be turned into real methods. + self.__dict__['_methods_'] = {} # unbound methods + self.__dict__['_object_name_'] = iid.name + self.__dict__.update(constants) + # We remember the constant names to prevent the user trying to assign to them! + self.__dict__['_constant_names_'] = list(constants.keys()) + + def __getattr__(self, attr): + # Allow the underlying interface to provide a better implementation if desired. + if attr in _special_getattr_names: + raise AttributeError(attr) + + ret = getattr(self.__dict__['_comobj_'], attr, None) + if ret is not None: + return ret + # Do the function thing first. + unbound_method = self.__dict__['_methods_'].get(attr, None) + if unbound_method is not None: + return MethodType(unbound_method, self) + + getters = self.__dict__['_property_getters_'] + info = getters.get(attr) + if info is not None: + method_index, param_infos = info + if len(param_infos)!=1: # Only expecting a retval + raise RuntimeError("Can't get properties with this many args!") + args = ( param_infos, () ) + return XPTC_InvokeByIndex(self._comobj_, method_index, args) + + # See if we have a method info waiting to be turned into a method. + # Do this last as it is a one-off hit. + method_info = self.__dict__['_method_infos_'].get(attr, None) + if method_info is not None: + unbound_method = BuildMethod(method_info, self._iid_) + # Cache it locally + self.__dict__['_methods_'][attr] = unbound_method + return MethodType(unbound_method, self) + + raise AttributeError("XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr)) + + def __setattr__(self, attr, val): + # If we already have a __dict__ item of that name, and its not one of + # our constants, we just directly set it, and leave. + if attr in self.__dict__ and attr not in self.__dict__['_constant_names_']: + self.__dict__[attr] = val + return + # Start sniffing for what sort of attribute this might be? + setters = self.__dict__['_property_setters_'] + info = setters.get(attr) + if info is None: + raise AttributeError("XPCOM component '%s' can not set attribute '%s'" % (self._object_name_, attr)) + method_index, param_infos = info + if len(param_infos)!=1: # Only expecting a single input val + raise RuntimeError("Can't set properties with this many args!") + real_param_infos = ( param_infos, (val,) ) + return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos) + + def __repr__(self): + return "" % (self._object_name_,) + + +# Called by the _xpcom C++ framework to wrap interfaces up just +# before they are returned. +def MakeInterfaceResult(ob, iid): + return Component(ob, iid) + +class WeakReference: + """A weak-reference object. You construct a weak reference by passing + any COM object you like. If the object does not support weak + refs, you will get a standard NS_NOINTERFACE exception. + + Once you have a weak-reference, you can "call" the object to get + back a strong reference. Eg: + + >>> some_ob = components.classes['...'] + >>> weak_ref = WeakReference(some_ob) + >>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point + >>> # EXCEPT: new_ob may be None if some_ob has already died - a + >>> # weak reference does not keep the object alive (that is the point) + + You should never hold onto this resulting strong object for a long time, + or else you defeat the purpose of the weak-reference. + """ + def __init__(self, ob, iid = None): + swr = Component(ob._comobj_, IID_nsISupportsWeakReference) + self._comobj_ = Component(swr.GetWeakReference()._comobj_, IID_nsIWeakReference) + if iid is None: + try: + iid = ob.IID + except AttributeError: + iid = IID_nsISupports + self._iid_ = iid + def __call__(self, iid = None): + if iid is None: iid = self._iid_ + try: + return Component(self._comobj_.QueryReferent(iid)._comobj_, iid) + except COMException as details: + if details.errno != nsError.NS_ERROR_NULL_POINTER: + raise + return None diff --git a/src/libs/xpcom18a4/python/components.py b/src/libs/xpcom18a4/python/components.py new file mode 100755 index 00000000..b0910f87 --- /dev/null +++ b/src/libs/xpcom18a4/python/components.py @@ -0,0 +1,248 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 module provides the JavaScript "components" interface +from . import xpt +import xpcom +import xpcom._xpcom as _xpcom +import xpcom.client +import xpcom.server + +StringTypes = [bytes, str] + +def _get_good_iid(iid): + if iid is None: + iid = _xpcom.IID_nsISupports + elif type(iid) in StringTypes and len(iid)>0 and iid[0] != "{": + iid = getattr(interfaces, iid) + return iid + +# The "manager" object. +manager = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentManager) + +# The component registrar +registrar = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentRegistrar) + +# The "interfaceInfoManager" object - JS doesnt have this. +interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager() + +# The serviceManager - JS doesnt have this either! +serviceManager = _xpcom.GetServiceManager() + +# The "Exception" object +Exception = xpcom.COMException + +# Base class for our collections. +# It appears that all objects supports "." and "[]" notation. +# eg, "interface.nsISupports" or interfaces["nsISupports"] +class _ComponentCollection: + # Bases are to over-ride 2 methods. + # _get_one(self, name) - to return one object by name + # _build_dict - to return a dictionary which provide access into + def __init__(self): + self._dict_data = None + def keys(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.keys()) + def items(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.items()) + def values(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return list(self._dict_data.values()) +# def has_key(self, key): +# if self._dict_data is None: +# self._dict_data = self._build_dict() +# return self._dict_data.has_key(key) + + def __len__(self): + if self._dict_data is None: + self._dict_data = self._build_dict() + return len(self._dict_data) + + def __getattr__(self, attr): + if self._dict_data is not None and attr in self._dict_data: + return self._dict_data[attr] + return self._get_one(attr) + def __getitem__(self, item): + if self._dict_data is not None and item in self._dict_data: + return self._dict_data[item] + return self._get_one(item) + +_constants_by_iid_map = {} + +class _Interface: + # An interface object. + def __init__(self, name, iid): + # Bypass self.__setattr__ when initializing attributes. + d = self.__dict__ + d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID. + d['name'] = name + def __cmp__(self, other): + this_iid = self._iidobj_ + other_iid = getattr(other, "_iidobj_", other) + return cmp(this_iid, other_iid) + def __eq__(self, other): + this_iid = self._iidobj_ + other_iid = getattr(other, "_iidobj_", other) + return this_iid == other_iid + def __hash__(self): + return hash(self._iidobj_) + def __str__(self): + return str(self._iidobj_) + def __getitem__(self, item): + raise TypeError("components.interface objects are not subscriptable") + def __setitem__(self, item, value): + raise TypeError("components.interface objects are not subscriptable") + def __setattr__(self, attr, value): + raise AttributeError("Can not set attributes on components.Interface objects") + def __getattr__(self, attr): + # Support constants as attributes. + c = _constants_by_iid_map.get(self._iidobj_) + if c is None: + c = {} + i = xpt.Interface(self._iidobj_) + for c_ob in i.constants: + c[c_ob.name] = c_ob.value + _constants_by_iid_map[self._iidobj_] = c + if attr in c: + return c[attr] + raise AttributeError("'%s' interfaces do not define a constant '%s'" % (self.name, attr)) + + +class _Interfaces(_ComponentCollection): + def _get_one(self, name): + try: + item = interfaceInfoManager.GetInfoForName(name) + except xpcom.COMException as why: + # Present a better exception message, and give a more useful error code. + from . import nsError + raise xpcom.COMException(nsError.NS_ERROR_NO_INTERFACE, "The interface '%s' does not exist" % (name,)) + return _Interface(item.GetName(), item.GetIID()) + + def _build_dict(self): + ret = {} + enum = interfaceInfoManager.EnumerateInterfaces() + while not enum.IsDone(): + # Call the Python-specific FetchBlock, to keep the loop in C. + items = enum.FetchBlock(500, _xpcom.IID_nsIInterfaceInfo) + # This shouldnt be necessary, but appears to be so! + for item in items: + ret[item.GetName()] = _Interface(item.GetName(), item.GetIID()) + return ret + +# And the actual object people use. +interfaces = _Interfaces() + +del _Interfaces # Keep our namespace clean. + +################################################# +class _Class: + def __init__(self, contractid): + self.contractid = contractid + def __getattr__(self, attr): + if attr == "clsid": + rc = registrar.contractIDToCID(self.contractid) + # stash it away - it can never change! + self.clsid = rc + return rc + raise AttributeError("%s class has no attribute '%s'" % (self.contractid, attr)) + def createInstance(self, iid = None): + import xpcom.client + try: + return xpcom.client.Component(self.contractid, _get_good_iid(iid)) + except xpcom.COMException as details: + from . import nsError + # Handle "no such component" in a cleaner way for the user. + if details.errno == nsError.NS_ERROR_FACTORY_NOT_REGISTERED: + raise xpcom.COMException(details.errno, "No such component '%s'" % (self.contractid,)) + raise # Any other exception reraise. + def getService(self, iid = None): + return serviceManager.getServiceByContractID(self.contractid, _get_good_iid(iid)) + +class _Classes(_ComponentCollection): + def __init__(self): + _ComponentCollection.__init__(self) + def _get_one(self, name): + # XXX - Need to check the contractid is valid! + return _Class(name) + + def _build_dict(self): + ret = {} + enum = registrar.enumerateContractIDs() + while enum.hasMoreElements(): + # Call the Python-specific FetchBlock, to keep the loop in C. + items = enum.fetchBlock(2000, _xpcom.IID_nsISupportsCString) + for item in items: + name = str(item.data) + ret[name] = _Class(name) + return ret + +classes = _Classes() + +del _Classes + +del _ComponentCollection + +# The ID function +ID = _xpcom.ID + +# A helper to cleanup our namespace as xpcom shuts down. +class _ShutdownObserver: + _com_interfaces_ = interfaces.nsIObserver + def observe(self, service, topic, extra): + global manager, registrar, classes, interfaces, interfaceInfoManager, _shutdownObserver, serviceManager, _constants_by_iid_map + manager = registrar = classes = interfaces = interfaceInfoManager = _shutdownObserver = serviceManager = _constants_by_iid_map = None + xpcom.client._shutdown() + xpcom.server._shutdown() + def _query_interface_(self, iid): # VBox: Needed so that the interface check in the DefaultPolicy initialization will pass; @bugref{10079}. + if iid == interfaces.nsIObserver: + return 1 + return None + +svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/observer-service;1", interfaces.nsIObserverService) +# Observers will be QI'd for a weak-reference, so we must keep the +# observer alive ourself, and must keep the COM object alive, +# _not_ just the Python instance!!! +_shutdownObserver = xpcom.server.WrapObject(_ShutdownObserver(), interfaces.nsIObserver) +# Say we want a weak ref due to an assertion failing. If this is fixed, we can pass 0, +# and remove the lifetime hacks above! See http://bugzilla.mozilla.org/show_bug.cgi?id=99163 +svc.addObserver(_shutdownObserver, "xpcom-shutdown", 1) +del svc, _ShutdownObserver diff --git a/src/libs/xpcom18a4/python/doc/advanced.html b/src/libs/xpcom18a4/python/doc/advanced.html new file mode 100644 index 00000000..ab6994fc --- /dev/null +++ b/src/libs/xpcom18a4/python/doc/advanced.html @@ -0,0 +1,176 @@ + + + + + + + +Python XPCOM Advanced Topics + + + + +

Python XPCOM Advanced Topics

+ +

This document contains a series of tidbits that don't fit +anywhere else. As the Python XPCOM Package documentation matures, most of +these topics will have another home.

+ +

XPCOM Services

+

An XPCOM service is simply a singleton registered by name.  Python has +full support for both using and implementing XPCOM services.  To use a +service, use xpcom.components.services just like the JavaScript +counterpart.  There is nothing special about implementing a service in +Python; see the standard XPCOM documentation on services for more information.

+ +

nsIVariant

+ +

There is (almost) full support for nsIVariant.  Any nsIVariant +parameters will automatically be translated to and from regular Python objects +giving, in effect, a multi-type parameter.  This should be automatic, so +there is not much else to say!  Note that if you really want, you can +create and pass your own nsIVariant object instead of a regular Python +object, thereby allowing explicit control over the type of variant created.

+ +

nsISupports Primitives.

+ +

There is a set of interfaces described in nsISupportsPrimitives.idl, which I +term collectively the nsISupports Primitives Interfaces.  These +are a set of interfaces a component can support to allow automatic conversion to +and from many basic types.  For example, an interface can define that it +supports the nsISupportsCString interface, and this could be used by any +program that wishes to get a string representation of the object.  If an +interface wishes to expose itself as a "boolean value", it may choose +to support the nsISupportsPRBool interface.

+

When you call an XPCOM object (i.e., you have an XPCOM interface you are +calling), you can use +the builtin functions str(), int(), long() etc., on the +object.  In the +case of str(), if the object does not support the nsISupportsCString +or nsISupportsString interfaces, the default string str() for the +object will be returned (i.e., what is normally returned for most XPCOM objects - +support for these interface is not very common!).  In the case of the numeric functions, a ValueError +exception will be raised if the objects do not support any interface that can be +used for the conversion. ValueError is used instead of TypeError, +as the type itself (i.e., an XPCOM object) can sometimes be used in this context - +hence it is the specific value of the object that is the problem.

+

The use of repr() on an XPCOM interface object prevents support +attempts for these interfaces, and allows you to see the +"real" object, rather than what the object wants you to see!

+

When you implement an XPCOM object, you have two choices for implementation +of these interfaces:

+
    +
  • You can explicitly handle these interfaces like any other interface.  + In this case, you have full control.  However, if you + implement only one of these standard interfaces, then you are only + overriding the default behavior for that specific interface - all other + interfaces not explicitly listed in your class will still get the behavior + described below.
    +
  • +
  • If your class does not define support for these interfaces, the framework + will use standard Python class semantics to implement them - i.e., if your + class provides a __str__ method, it will be used to implement nsISupportsCString + and nsISupportsString, if you provide __int__, __long__, + __float__ etc., methods, they will be used to implement the numeric + interfaces.  If your class defines no such special methods, then the + QueryInterface() for those interfaces fails (rather than the QI succeeding + and the operation to fetch the data failing).
  • +
+
+

This allows for an interesting feature that would not normally be +possible.  Consider Python code that does a str() on an  XPCOM +interface, and where the XPCOM interface itself is implemented in Python and +provides a __str__ method.  The str() on the original +interface queries for the nsISupportsCString interface.  The +Python implemented object responds to this interface and delegates to the __str__ +method. At the end of all this, str() returns the same result +as if the objects were native Python objects with no XPCOM layer in between.

+ +
+ +

Enumerators

+ +

The primary enumerator used by XPCOM is nsISimpleEnumerator. +Although the Python XPCOM package has full support for nsIEnumerator, +since this interface is not "scriptable", you should avoided using it in interfaces +you design.

+ +

When you use nsISimpleEnumerator from Python, the following enhancements +are available:

+
    +
  • The GetNext() method takes an optional IID as a parameter. If + this is specified, the returned object will be of this interface.  This + prevents the manual QueryInterface() generally required from other + languages.
  • +
  • There is a FetchBlock(num, [iid]) method, which fetches the + specified number of elements in one operation and returns a Python + list. This can be useful for large enumerator sets, so the loop + iterating the elements runs at full C++ speed.
  • +
+

nsIEnumerator has similar enhancements.

+

When implementing a Python XPCOM object, the Python class xpcom.server.enumerator.SimpleEnumerator() +can be used.  You can pass a standard Python sequence (list, etc), and it +will be correctly wrapped in an nsISimpleEnumerator interface.

+

Files

+

The Python XPCOM package provides an xpcom.file module.  This implements +a Python-like file object on top of the XPCOM/Mozilla stream interfaces.  +When run from within the Mozilla environment, this allows you to open almost any +URL supported by Mozilla (including "chrome://" etc.,).

+

See this module for more information, including test code.

+

XPCOM Object Identity

+

XPCOM has defined rules for object identity and for how objects must behave +in their QueryInterface() implementations.  The Python XPCOM framework +manages this for you; your code can return new Python instances etc., when +responding to new interfaces, and the framework itself will ensure the XPCOM +semantics are followed.  Critically, the framework provides no mechanism +for breaking these rules.

+

Policies

+

The Python XPCOM framework has the concept of "policies" that +define how XPCOM semantics are mapped to Python objects.  It is the policy +that implements delegation of QueryInterface(), translates property +references into direct property references, and failing that, "get_name" +and "set_name" calls, decides how to handle exceptions in the +component, and so on.

+

The default policy is very flexible and suitable for most purposes. +Indeed, the Komodo project has never had to implement a custom policy. +However, you should be aware the feature exists should you wish to do some +bizarre things, such as using Python as a bridge between XPCOM and some other +component technology.

+ + + + diff --git a/src/libs/xpcom18a4/python/doc/architecture.html b/src/libs/xpcom18a4/python/doc/architecture.html new file mode 100644 index 00000000..d12a2a76 --- /dev/null +++ b/src/libs/xpcom18a4/python/doc/architecture.html @@ -0,0 +1,116 @@ + + + + + + + +Architecture + + + + +

Python XPCOM Package Architecture

+

Architecture

+

Much of the design for the Python XPCOM Package has been borrowed from the Python MS-COM +extensions in win32com. Most of the major limitations and drawbacks in the win32com +design have been addressed, mainly "auto-wrapping" of +interface objects, which is not supported by win32com.

+

Like win32com, this architecture includes the concept of client COM and server +COM.

+

Client COM:

+
    +
  • calls other interfaces
  • +
  • is supported by PyInterfaces implemented in C++, which assists +in making the COM calls
  • +
  • is supported by PyGateways, which assists in receiving +external COM calls and dispatching them to the correct Python object
  • +
  • is supported in the xpcom/client package
  • +
+

Server COM:

+
    +
  • implements interfaces for use by other XPCOM applications or components
  • +
  • is +supported in the xpcom/server package
  • +
+

The XPConnect framework is very powerful, and far exceeds what COM's +IDispatch can offer.  Thus, we are able to get by with far fewer interfaces +supported in the C++ level, and defer most things to the Python code that uses +XPConnect.  As a result, the requirement for a huge number of interfaces to +exist in the .pyd does not exist.  There are, however, a number of +interfaces that do require native C++ support: these are interfaces +required to "boot" the XPConnect support (i.e., the interfaces that are +used to get information about interfaces), and also two gateways that need to +work without interface information available. This last requirement is +due to the XPCOM shutdown-ordering - it may be a bug, but is not an unreasonable +amount of code anyway.

+

Auto-wrapping of COM objects is supported by both client COM and +server COM. For client COM, auto-wrapping means that the +Python programmer always sees Python "component" objects, rather than +raw C++ interface objects; to the user, it all appears to "just +work".  This is a major source of frustration in the win32com +framework.

+

For server COM, auto-wrapping means that you can +pass Python instances wherever a COM object is expected. If the Python +instance supports COM interfaces, by virtue of having a _com_interfaces_ +attribute that lists the interface requested, it will be automatically wrapped +in the correct COM object. 

+

Error Handling: The C++ framework has good error handling support, +and uses the XPCOM console service to log debug messages, Python exceptions and +tracebacks.  win32com does not have good exception/traceback support +at the C++ level, mainly because COM does not define a service like +the console where debug messages can go.  This does mean that in Mozilla +release builds, these debug messages are likely to be lost, but the --console +command line option to a release Mozilla will get them back.  Therefore, +the other error-support utilities, such as the error callbacks made on the +policy object, may be used.

+

Component Loader, Modules and Factories:  XPCOM has the concept +of a component loader - a module used to load all components of a +particular type.  For example, the moz.jsloader.1 component loads all +the JavaScript components. Similarly, the moz.pyloader.1 +component loads all Python components.  However, unlike +JavaScript, the Python component loader is actually implemented in Python +itself! Since the Python component loader can not be used to load +itself, this component has some special code, pyloader.dll, to boot-strap itself.

+

This means is that all XPCOM components, including the Python loader itself and all +XPCOM module and factory interfaces, are implemented in +Python. There are no components or interfaces implemented purely in C++ +in this entire package!

+ + + + diff --git a/src/libs/xpcom18a4/python/doc/configure.html b/src/libs/xpcom18a4/python/doc/configure.html new file mode 100644 index 00000000..e2b5d416 --- /dev/null +++ b/src/libs/xpcom18a4/python/doc/configure.html @@ -0,0 +1,196 @@ + + + + + + + +Configuring your Environment + + + + +

Building, Configuring and Testing Python XPCOM Package

+

This document attempts to explain how to build, configure and test the +Python XPCOM Package. This document assumes you have already successfully +built +Mozilla from source and your environment is currently set up for such a build - +see the Mozilla build documentation +for more information.

+

PyXPCOM can be built on Windows using either the nmake makefile.win +process, or the configure; gmake process used by Linux.

+

configure; gmake Instructions

+

Preparing for the build

+
    +
  • Apply the patch in bugzilla + bug 129216. (If this bug is marked as "FIXED", it probably + means there is no need to apply the patch and that these docs are out of + date)
  • +
  • On Linux, you must have Python built for dynamic linking.  ActivePython + 2.1 is one such build.
  • +
  • On Windows, you must have a Python source tree installed and built.  + Patches gratefully accepted that allow an installed Python to be used (it + should not be hard!)
  • +
  • Ensure the Python interpreter you wish to use is on your path, such that + "python" will execute it correctly.  The configure process + uses this to locate the Python support files.
  • +
+

Building

+
    +
  • From the top-level Mozilla directory, execute ./configure + --enable-extensions=python/xpcom. As per the Mozilla build + instructions, you may add this option to your .mozconfig file.  + If you wish to enable debugging, just enable it as you would normally for + Mozilla; PyXPCOM will pick up the same settings.
    + (On Windows you will need to execute sh ./configure ... if running + from a Command Prompt.  See the Mozilla + win32 specific gmake build instructions for more details.
  • +
  • Build the Mozilla tree as normal; PyXPCOM will automatically be + built.  Alternatively, change to the top-level PyXPCOM directory and + execute gmake in that directory.
  • +
+

PyXPCOM outside Mozilla

+

When you are using PyXPCOM from inside mozilla, no additional configuration +options should be necessary.  However, if you wish to use PyXPCOM from +stand-alone Python (ie, so you can write simple Python scripts that can be +executed normally and use XPCOM), then additional environment variables must be +setup.

+
    +
  • PYTHONPATH - PYTHONPATH needs to + be set appropriately. You must manually ensure that the mozilla/dist/bin/python + directory (which is where PyXPCOM was installed during the build process) is + listed.  Note that when PyXPCOM is used from within Mozilla (or any + other xpcom process), this path will automatically be added to sys.path.  + It is only when Python directly uses xpcom that this step is necessary.
    + If anything is wrong here you should get a normal ImportError.
  • +
+
+

Note that on Windows, the PYTHONPATH is generally maintained in the + Registry; however, you can set this variable at a DOS prompt, and it will still be +added to the core PYTHONPATH. +

+
    +
  • PATH, LD_LIBRARY_PATH, etc - On Windows, you + must ensure that the Mozilla bin directory is listed on your PATH, or that + you execute your scripts with the Mozilla bin directory as the current + directory.
    + On Linux, you must set your PATH and LD_LIBRARY_PATH variables + appropriately.  However, you may find it simpler and easier to use the run-mozilla.sh + script in the Mozilla bin directory.  For example, changing to the + Mozilla bin directory and executing:
    + ./run-mozilla.sh python ~/src/mozilla/extensions/python/xpcom/test/regrtest.py
    + should setup a correct environment and execute the PyXPCOM test suite.
  • +
+

Testing your Setup

+

The Python XPCOM Package has a complete test suite.

+

In the rest of this section, we walk through some simpler tests a step at a time, +to help diagnose any problems.

+

Note: We recommend you do all your testing outside of mozilla.exe; it is far simpler to test all of +this using the PyXPCOM package stand-alone.

+

Note: On Windows, if you use a debug build of Mozilla (i.e., in dist\WIN32_D.OBJ\bin), + you must use python_d.exe; if you use a release build (i.e., in + a dist\WIN32_O.OBJ\bin directory), you must use python.exe.  +makefile.stupid.win handles this automatically.

+

To test your setup:

+
    +
  1. Start Python, and check
    + >>> import xpcom
    + works. If not, check your PYTHONPATH - the + main PyXPCOM package can not be located.  Also check your PATH, + and if you are on Linux, remember that executing ./run-mozilla.sh python is + the easiest way.
  2. +
  3. Check
    + >>> import xpcom._xpcom

    + +works. If not, then most likely your Mozilla + directory is not on your path, or something is wrong with _xpcom(_d).pyd/_xpcommodule.so.
  4. + +
  5. Next run a simple test: test/test_misc.py. With a Windows debug build, the command may look like:
    + C:\Anywhere> python_d \src\python\xpcom\test\test_misc.py
    +
    or on Linux
    + /home/user/src/mozilla/dist/bin$ python /home/user/src/python/xpcom/test/test_misc.py
  6. +
+

If you can't get this going, you won't get much further! (You may see a few +errors - that is OK, as long as it appears something worked!).  If +everything looks OK, the +next step is to register our test component and run our full test suite.

+

Registering the Loader and Test Component

+

First register the generic Python loader. For instructions, see the architecture +document. Do this only once, regardless of how many +Python components you have.  Then install the test component itself, and +finally you can test it!

+

Registering the Python Loader and Component

+

To register the Python Loader and Component:

+
    +
  1. Ensure the build process has put pyloader.dll (or modpyloader.so + for Unix), and the files py_test_component.py and py_test_component.idl into + the Mozilla bin/components directory.  If not, copy the files + there manually.
  2. +
  3. Run regxpcom (or ./run-mozilla.sh ./regxpcom if appropriate). regxpcom is a standard Mozilla + executable, found in the bin directory, that detects the new DLL and + .py + files and registers them accordingly.  You should + see a few messages that include the following:
  4. +
+
+
Registering: PythonComponentLoader
+Registered 1 Python components in pyloader.dll
+nsNativeComponentLoader: autoregistering succeeded
+Auto-registering all Python components in F:\src\mozilla\dist\WIN32_D.OBJ\bin\components
+Registering: PythonTestComponent
+Registered 1 Python components in py_test_component.py
+
+

If so (or you see no message at all), you are ready to run the test suite.

+

Note: If you execute this same step a second time, you will not +see any of the above mentioned messages. XPCOM knows that nothing has +changed since you last ran regxpcom, so nothing is registered.  If +you do not see these messages the first time you run it, there is the +possibility that some other process, possibly the build process, has already +executed this step.

+

Running the Test Suite

+

Before running the test suite, you should change to the mozilla/xpcom/sample +directory and build it.  This will build and install a sample component +which is used by the test suite.  If you do not have this component +available, some of the Python tests will fail.

+ +

To run the test suite, run xpcom/test/regrtest.py.  This runs the +tests and ensures that the test output is as expected.  If all tests +pass, you have a fully functioning Python XPCOM package.  Enjoy!

+ + + + diff --git a/src/libs/xpcom18a4/python/doc/credits.html b/src/libs/xpcom18a4/python/doc/credits.html new file mode 100644 index 00000000..2be7809f --- /dev/null +++ b/src/libs/xpcom18a4/python/doc/credits.html @@ -0,0 +1,86 @@ + + + + + + + + +Credits and Acknowledgements + + + + +

Credits and Acknowledgements

+

ActiveState Tool Corporation

+

The Python XPCOM Package was developed primarily by Mark +Hammond of ActiveState Tool Corporation.

+

The developers on the Komodo +project deserve high praise for putting up with early versions when almost +nothing worked, and for believing in Python as a viable XPCOM language.  +Their feedback and patience has allowed the first public release to be amazingly +functional and bug-free.

+

Komodo Development Team (at December 2000)

+

David Ascher, Aaron Bingham, +Bin Du, Mark +Hammond, Trent Mick (build god),  +Paul PrescodEric Promislow, +Ken Simpson, Neil Watkiss, +Audrey Schumacher.

+

Mozilla/Netscape

+

The following people at Netscape and Mozilla +(or not there but still heavily involved in the project) have provided enormous +help in getting things integrated with their build system, answering us on the +newsgroup, teaching us the finer points of XPCOM, gently slapping us for accidentally +referring to jscript, etc., and otherwise lending us a clue in the +Mozilla/Netscape/XPCOM world.

+

John Bandhauer, Brendan +Eich, Mike Shaver, Eric Vaughan, +David Hyatt

+

External Contributors

+

The following people have made contributions to the project, simply because +they find it useful and enjoy supporting Open Source projects.

+

Christof Meerwald

+

Documentation Credits

+

The following people have contributed to the Python XPCOM Package +documentation 

+

Mark +Hammond, Audrey Schumacher

+ + + + diff --git a/src/libs/xpcom18a4/python/doc/tutorial.html b/src/libs/xpcom18a4/python/doc/tutorial.html new file mode 100644 index 00000000..808d4c06 --- /dev/null +++ b/src/libs/xpcom18a4/python/doc/tutorial.html @@ -0,0 +1,286 @@ + + + + + + + +Python XPCOM Package Tutorial + + + + +

Python XPCOM Package Tutorial

+

This is a quick introduction to the Python XPCOM Package. We assume that you have a good understanding of Python and XPCOM, +and have experience both using and implementing XPCOM objects in some other +language (e.g., C++ or JavaScript). We do not attempt to +provide a tutorial to XPCOM or Python itself, only to using Python and + XPCOM.

+

This tutorial contains the following sections:

+ +

For anything not covered here, try the advanced +documentation, and if that fails, use the source, Luke!

+

Using XPCOM object and interfaces.

+

The techniques for using XPCOM in Python have been borrowed from JavaScript - +thus, the model described here should be quite familiar to existing JavaScript +XPCOM programmers.

+

xpcom.components module

+

When using an XPCOM object, the primary module used is the xpcom.components + module.  Using this module, you can get a Python object that supports any +scriptable XPCOM interface. Once you have this Python object, you can +simply call XPCOM methods on the object, as normal.

+

The xpcom.components module defines the following public +members:

+ + + + + + + + + + + + + +
NameDescription
classesA mapping (dictionary-like object) used to get XPCOM + "classes".  These are indexed by XPCOM contract ID, just + like the JavaScript object of the same name.   +

Example:

+
cls = components.classes["@mozilla.org/sample;1"]
+ob = cls.createInstance() # Now have an nsISupports
+
interfacesAn object that exposes all XPCOM interface IDs (IIDs).  + Like the JavaScript object of the same name, this object uses + "dot" notation, as demonstrated below. +

Example:

+
ob = cls.createInstance(components.interfaces.nsISample) 
+# Now have an nsISample
+
+

For many people, this is all you need to know. Consider the Mozilla Sample Component.  The Mozilla Sample +Component has a contract ID of @mozilla.org/sample;1, +and implements the nsISample interface.

+

Thus, a complete Python program that uses this component is shown below.

+
from xpcom import components
+cls = components.classes["@mozilla.org/sample;1"]
+ob = cls.createInstance() # no need to specify an IID for most components
+# nsISample defines a "value" property - let's use it!
+ob.value = "new value"
+if ob.value != "new value":
+    print "Eeek - what happened?"
+

And that is it - a complete Python program that uses XPCOM.

+

Implementing XPCOM Objects and Interfaces.

+

Implementing XPCOM objects is almost as simple as using them. The +basic strategy is this:

+
    +
  1. Create a standard Python source file, with a standard Python class.
  2. +
  3. Add some special attributes to your class for use by the Python XPCOM + framework. This controls the XPCOM behavior of your object.
  4. +
  5. Implement the XPCOM properties and methods of your classes as normal.
  6. +
  7. Put the Python source file in the Mozilla components directory.
  8. +
  9. Run regxpcom.
  10. +
+

Your component is now ready to be used.

+

Attributes

+

There are two classes of attributes: those used at runtime to define the object +behavior and those used at registration time to control object +registration.  Not all objects require registration, thus not all +Python XPCOM objects will have registration-related attributes.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescription
_com_interfaces_The interface IDs (IIDs) supported by the component.  + For simplicity, this may be either a single IID, or a list of IIDs.  + There is no need to specify base interfaces, as all parent interfaces are + automatically supported. Thus, it is never necessary to nominate + nsISupports in the list of interfaces. +

This attribute is required. Objects without such an attribute are + deemed unsuitable for use as a XPCOM object.

_reg_contractid_The contract ID of the component.  Required if the + component requires registration (i.e., exists in the components directory).
_reg_clsid_The Class ID (CLSID) of the component, as a string in the + standard "{XXX-XXX-XXX-XXX}" format. Required if the + component requires registration (i.e., exists in the components directory).
_reg_registrar_Nominates a function that is called at registration + time. The default is for no extra function to be called. This can + be useful if a component has special registration requirements and needs + to hook into the registration process.
_reg_desc_The description of the XPCOM object. This may be used by + browsers or other such objects.  If not specified, the contract ID + is used.
+

Properties

+

A Python class can support XPCOM properties in one of two ways.  Either +a standard Python property of the same name can exist - our sample +component demonstrates this with the boolean_value property.  +Alternatively, the class can provide the get_propertyName(self) and set_propertyName(self, +value) functions (with propertyName changed to the appropriate value for the +property), and these functions will be called instead.

+

Example:  The Python XPCOM Test Component

+

As an example, examine the Python XPCOM Test Component.  This +code can be found in py_test_component.py.

+
from xpcom import components
+
+class PythonTestComponent:
+    _com_interfaces_ = components.interfaces.nsIPythonTestInterface
+    _reg_clsid_ = "{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}"
+    _reg_contractid_ = "Python.TestComponent"
+    def __init__(self):
+        self.boolean_value = 1
+        ...
+    def do_boolean(self, p1, p2):
+        ret = p1 ^ p2
+        return ret, not ret, ret
+...
+

Note: This component only specifies the mandatory attributes - _com_interfaces, +_reg_clsid_ and _reg_contractid_.

+

This sample code demonstrates supporting the boolean_value attribute, +supported implicitly, as it is defined in the IDL and exists as a real Python +attribute of that name, and a method called do_boolean.

+

Tip: The xpcom/xpt.py Script

+

The xpcom/xpt.py script is a useful script that can generate the skeleton of a class for +any XPCOM interface.  Just specify the interface name on the command-line, +and paste the output into your source file.

+

This is the output of running this program over the nsISample +interface (i.e., assuming we wanted to implement a component that supported this +interface):

+
class nsISample:
+    _com_interfaces_ = xpcom.components.interfaces.nsISample
+    # If this object needs to be registered, the following 2 are also needed.
+    # _reg_clsid_ = {a new clsid generated for this object}
+    # _reg_contractid_ = "The.Object.Name"
+
+    def get_value( self ):
+        # Result: string
+        pass
+    def set_value( self, param0 ):
+        # Result: void - None
+        # In: param0: string
+        pass
+    def writeValue( self, param0 ):
+        # Result: void - None
+        # In: param0: string
+        pass
+    def poke( self, param0 ):
+        # Result: void - None
+        # In: param0: string
+        pass
+

Note: The types of the parameters and the function itself are included in +the comments. You need to implement the functions +themselves.  Another advantage of this script is that the hidden +parameters are handled for you; the comments indicate when parameters +have been hidden.

+

Parameters and Types

+

This section briefly describes the XPCOM type support in +Python.

+

All XPCOM interfaces define parameters of a specific type.  There is +currently no concept of a variant, or union of all types. Thus, the +conversion rules are very straightforward, and generally surprise free: for +any given XPCOM method, there is only one possible type for a given parameter.

+

Type Conversion Rules:

+ + +

Interface Flattening

+

Most people can ignore this information - Python XPCOM objects just +work.  However, if you are familiar with xpcom from C++ and the concept of QueryInterface, +you may like to read this.

+

Most components support the concept of "interface +flattening".  Such objects can report the interfaces they support, +allowing languages such as Python and Javascript avoid using QueryInterface.  +When you are using an XPCOM object from Python, you can just call methods and +reference properties without regard for the interface that implements it.

+

When multiple interfaces share the same method or property name, you can use +the name of the interface as a differentiator.  Thus, ob.nsIFoo.close() +will call close on ob's nsIFoo interface, while ob.nsIBar.close() +will use the nsIBar interface.  ob.close() is not defined.

+ + + + + + diff --git a/src/libs/xpcom18a4/python/file.py b/src/libs/xpcom18a4/python/file.py new file mode 100755 index 00000000..59b0da58 --- /dev/null +++ b/src/libs/xpcom18a4/python/file.py @@ -0,0 +1,318 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +"""Implementation of Python file objects for Mozilla/xpcom. + +Introduction: + This module defines various class that are implemented using + Mozilla streams. This allows you to open Mozilla URI's, and + treat them as Python file object. + +Example: +>>> file = URIFile("chrome://whatever") +>>> data = file.read(5) # Pass no arg to read everything. + +Known Limitations: + * Not all URL schemes will work from "python.exe" - most notably + "chrome://" and "http://" URLs - this is because a simple initialization of + xpcom by Python does not load up the full set of Mozilla URL handlers. + If you can work out how to correctly initialize the chrome registry and + setup a message queue. + +Known Bugs: + * Only read ("r") mode is supported. Although write ("w") mode doesnt make + sense for HTTP type URLs, it potentially does for file:// etc type ones. + * No concept of text mode vs binary mode. It appears Mozilla takes care of + this internally (ie, all "text/???" mime types are text, rest are binary) + +""" + +from xpcom import components, Exception, _xpcom +import os +import threading # for locks. + +NS_RDONLY = 0x01 +NS_WRONLY = 0x02 +NS_RDWR = 0x04 +NS_CREATE_FILE = 0x08 +NS_APPEND = 0x10 +NS_TRUNCATE = 0x20 +NS_SYNC = 0x40 +NS_EXCL = 0x80 + +# A helper function that may come in useful +def LocalFileToURL(localFileName): + "Convert a filename to an XPCOM nsIFileURL object." + # Create an nsILocalFile + localFile = components.classes["@mozilla.org/file/local;1"] \ + .createInstance(components.interfaces.nsILocalFile) + localFile.initWithPath(localFileName) + + # Use the IO Service to create the interface, then QI for a FileURL + io_service = components.classes["@mozilla.org/network/io-service;1"] \ + .getService(components.interfaces.nsIIOService) + url = io_service.newFileURI(localFile).queryInterface(components.interfaces.nsIFileURL) + # Setting the "file" attribute causes initialization... + url.file = localFile + return url + +# A base class for file objects. +class _File: + def __init__(self, name_thingy = None, mode="r"): + self.lockob = threading.Lock() + self.inputStream = self.outputStream = None + if name_thingy is not None: + self.init(name_thingy, mode) + + def __del__(self): + self.close() + + # The Moz file streams are not thread safe. + def _lock(self): + self.lockob.acquire() + def _release(self): + self.lockob.release() + def read(self, n = -1): + assert self.inputStream is not None, "Not setup for read!" + self._lock() + try: + return str(self.inputStream.read(n)) + finally: + self._release() + + def readlines(self): + # Not part of the xpcom interface, but handy for direct Python users. + # Not 100% faithful, but near enough for now! + lines = self.read().split("\n") + if len(lines) and len(lines[-1]) == 0: + lines = lines[:-1] + return [s+"\n" for s in lines ] + + def write(self, data): + assert self.outputStream is not None, "Not setup for write!" + self._lock() + try: + self.outputStream.write(data, len(data)) + finally: + self._release() + + def close(self): + self._lock() + try: + if self.inputStream is not None: + self.inputStream.close() + self.inputStream = None + if self.outputStream is not None: + self.outputStream.close() + self.outputStream = None + self.channel = None + finally: + self._release() + + def flush(self): + self._lock() + try: + if self.outputStream is not None: self.outputStream.flush() + finally: + self._release() + +# A synchronous "file object" used to open a URI. +class URIFile(_File): + def init(self, url, mode="r"): + self.close() + if mode != "r": + raise ValueError("only 'r' mode supported") + io_service = components.classes["@mozilla.org/network/io-service;1"] \ + .getService(components.interfaces.nsIIOService) + if hasattr(url, "queryInterface"): + url_ob = url + else: + url_ob = io_service.newURI(url, None, None) + # Mozilla asserts and starts saying "NULL POINTER" if this is wrong! + if not url_ob.scheme: + raise ValueError("The URI '%s' is invalid (no scheme)" + % (url_ob.spec,)) + self.channel = io_service.newChannelFromURI(url_ob) + self.inputStream = self.channel.open() + +# A "file object" implemented using Netscape's native file support. +# Based on io.js - http://lxr.mozilla.org/seamonkey/source/xpcom/tests/utils/io.js +# You open this file using a local file name (as a string) so it really is pointless - +# you may as well be using a standard Python file object! +class LocalFile(_File): + def __init__(self, *args): + self.fileIO = None + _File.__init__(self, *args) + + def init(self, name, mode = "r"): + name = os.path.abspath(name) # Moz libraries under Linux fail with relative paths. + self.close() + file = components.classes['@mozilla.org/file/local;1'].createInstance("nsILocalFile") + file.initWithPath(name) + if mode in ["w","a"]: + self.fileIO = components.classes["@mozilla.org/network/file-output-stream;1"].createInstance("nsIFileOutputStream") + if mode== "w": + if file.exists(): + file.remove(0) + moz_mode = NS_CREATE_FILE | NS_WRONLY + elif mode=="a": + moz_mode = NS_APPEND + else: + assert 0, "Can't happen!" + self.fileIO.init(file, moz_mode, -1,0) + self.outputStream = self.fileIO + elif mode == "r": + self.fileIO = components.classes["@mozilla.org/network/file-input-stream;1"].createInstance("nsIFileInputStream") + self.fileIO.init(file, NS_RDONLY, -1,0) + self.inputStream = components.classes["@mozilla.org/scriptableinputstream;1"].createInstance("nsIScriptableInputStream") + self.inputStream.init(self.fileIO) + else: + raise ValueError("Unknown mode") + + def close(self): + if self.fileIO is not None: + self.fileIO.close() + self.fileIO = None + _File.close(self) + + def read(self, n = -1): + return _File.read(self, n) + + +########################################################## +## +## Test Code +## +########################################################## +def _DoTestRead(file, expected): + # read in a couple of chunks, just to test that our various arg combinations work. + got = file.read(3) + got = got + file.read(300) + got = got + file.read(0) + got = got + file.read() + if got != expected: + raise RuntimeError("Reading '%s' failed - got %d bytes, but expected %d bytes" % (file, len(got), len(expected))) + +def _DoTestBufferRead(file, expected): + # read in a couple of chunks, just to test that our various arg combinations work. + buffer = _xpcom.AllocateBuffer(50) + got = '' + while 1: + # Note - we need to reach into the file object so we + # can get at the native buffer supported function. + num = file.inputStream.read(buffer) + if num == 0: + break + got = got + str(buffer[:num]) + if got != expected: + raise RuntimeError("Reading '%s' failed - got %d bytes, but expected %d bytes" % (file, len(got), len(expected))) + +def _TestLocalFile(): + import tempfile, os + fname = tempfile.mktemp() + data = "Hello from Python" + test_file = LocalFile(fname, "w") + try: + test_file.write(data) + test_file.close() + # Make sure Python can read it OK. + f = open(fname, "r") + assert f.read() == data, "Eeek - Python could not read the data back correctly!" + f.close() + # For the sake of the test, try a re-init. + test_file.init(fname, "r") + got = str(test_file.read()) + assert got == data, got + test_file.close() + # Try reading in chunks. + test_file = LocalFile(fname, "r") + got = test_file.read(10) + test_file.read() + assert got == data, got + test_file.close() + # Open the same file again for writing - this should delete the old one. + if not os.path.isfile(fname): + raise RuntimeError("The file '%s' does not exist, but we are explicitly testing create semantics when it does" % (fname,)) + test_file = LocalFile(fname, "w") + test_file.write(data) + test_file.close() + # Make sure Python can read it OK. + f = open(fname, "r") + assert f.read() == data, "Eeek - Python could not read the data back correctly after recreating an existing file!" + f.close() + + # XXX - todo - test "a" mode! + finally: + os.unlink(fname) + +def _TestAll(): + # A mini test suite. + # Get a test file, and convert it to a file:// URI. + # check what we read is the same as when + # we read this file "normally" + fname = components.__file__ + if fname[-1] in "cCoO": # fix .pyc/.pyo + fname = fname[:-1] + expected = open(fname, "rb").read() + # convert the fname to a URI. + url = LocalFileToURL(fname) + # First try passing a URL as a string. + _DoTestRead( URIFile( url.spec), expected) + # Now with a URL object. + _DoTestRead( URIFile( url ), expected) + + _DoTestBufferRead( URIFile( url ), expected) + + # For the sake of testing, do our pointless, demo object! + _DoTestRead( LocalFile(fname), expected ) + + # Now do the full test of our pointless, demo object! + _TestLocalFile() + +def _TestURI(url): + test_file = URIFile(url) + print("Opened file is", test_file) + got = test_file.read() + print("Read %d bytes of data from %r" % (len(got), url)) + test_file.close() + +if __name__=='__main__': + import sys + if len(sys.argv) < 2: + print("No URL specified on command line - performing self-test") + _TestAll() + else: + _TestURI(sys.argv[1]) diff --git a/src/libs/xpcom18a4/python/gen_python_deps.py b/src/libs/xpcom18a4/python/gen_python_deps.py new file mode 100755 index 00000000..12fbb7ac --- /dev/null +++ b/src/libs/xpcom18a4/python/gen_python_deps.py @@ -0,0 +1,147 @@ +#!/usr/bin/python + +""" +Copyright (C) 2009-2022 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation, in version 3 of the +License. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . + +SPDX-License-Identifier: GPL-3.0-only +""" + +from __future__ import print_function +import os,sys +from distutils.version import StrictVersion + +versions = ["2.6", "2.7", "3.1", "3.2", "3.2m", "3.3", "3.3m", "3.4", "3.4m", "3.5", "3.5m", "3.6", "3.6m", "3.7", "3.7m", "3.8", "3.8m", "3.9", "3.9m", "3.10", "3.10m", "3.11", "3.11m" ] +prefixes = ["/usr", "/usr/local", "/opt", "/opt/local"] +known = {} + +def checkPair(p, v, dllpre, dllsuff, bitness_magic): + incdir = os.path.join(p, "include", "python"+v) + incfile = os.path.join(incdir, "Python.h") + if not os.path.isfile(incfile): + return None + + lib = os.path.join(p, "lib/i386-linux-gnu", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib): + lib = os.path.join(p, "lib", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib): + lib = None + + if bitness_magic == 1: + lib64 = os.path.join(p, "lib", "64", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib64): + lib64 = None + elif bitness_magic == 2: + lib64 = os.path.join(p, "lib/x86_64-linux-gnu", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib64): + lib64 = os.path.join(p, "lib64", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib64): + lib64 = os.path.join(p, "lib", dllpre+"python"+v+dllsuff) + if not os.path.isfile(lib64): + lib64 = None + else: + lib64 = None + + if lib is None and lib64 is None: + return None + else: + return [incdir, lib, lib64] + +def print_vars(vers, known, sep, bitness_magic): + print("VBOX_PYTHON%s_INC=%s%s" %(vers, known[0], sep)) + if bitness_magic > 0: + if known[2]: + print("VBOX_PYTHON%s_LIB=%s%s" %(vers, known[2], sep)) + if known[1]: + print("VBOX_PYTHON%s_LIB_X86=%s%s" %(vers, known[1], sep)) + else: + print("VBOX_PYTHON%s_LIB=%s%s" %(vers, known[1], sep)) + + +def main(argv): + global prefixes + global versions + + dllpre = "lib" + dllsuff = ".so" + bitness_magic = 0 + + if len(argv) > 1: + target = argv[1] + else: + target = sys.platform + + if len(argv) > 2: + arch = argv[2] + else: + arch = "unknown" + + if len(argv) > 3: + multi = int(argv[3]) + else: + multi = 1 + + if multi == 0: + prefixes = ["/usr"] + versions = [str(sys.version_info[0])+'.'+str(sys.version_info[1]), + str(sys.version_info[0])+'.'+str(sys.version_info[1])+'m'] + + if target == 'darwin': + ## @todo Pick up the locations from VBOX_PATH_MACOSX_SDK_10_*. + prefixes = ['/Developer/SDKs/MacOSX10.4u.sdk/usr', + '/Developer/SDKs/MacOSX10.5.sdk/usr', + '/Developer/SDKs/MacOSX10.6.sdk/usr', + '/Developer/SDKs/MacOSX10.7.sdk/usr'] + dllsuff = '.dylib' + + if target == 'solaris' and arch == 'amd64': + bitness_magic = 1 + + if target == 'linux' and arch == 'amd64': + bitness_magic = 2 + + for v in versions: + if v.endswith("m"): + realversion = v[:-1] + else: + realversion = v + if StrictVersion(realversion) < StrictVersion('2.6'): + continue + for p in prefixes: + c = checkPair(p, v, dllpre, dllsuff, bitness_magic) + if c is not None: + known[v] = c + break + keys = list(known.keys()) + # we want default to be the lowest versioned Python + keys.sort() + d = None + # We need separator other than newline, to sneak through $(shell) + sep = "|" + for k in keys: + if d is None: + d = k + vers = k.replace('.', '').upper() + print_vars(vers, known[k], sep, bitness_magic) + if d is not None: + print_vars("DEF", known[d], sep, bitness_magic) + else: + print(argv[0] + ": No Python development package found!", file=sys.stderr) + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/libs/xpcom18a4/python/nsError.py b/src/libs/xpcom18a4/python/nsError.py new file mode 100755 index 00000000..af9cdbfd --- /dev/null +++ b/src/libs/xpcom18a4/python/nsError.py @@ -0,0 +1,166 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is ActiveState Tool Corp. +# Portions created by ActiveState Tool Corp. are Copyright (C) 2000, 2001 +# ActiveState Tool Corp. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# Generated by h2py from nsError.h +# CMD line: h2py.py -i (nsresult) nsError.h + +# XXX - NOTE - some manual code at the end, and all literals moved back to ints +NS_ERROR_MODULE_XPCOM = 1 +NS_ERROR_MODULE_BASE = 2 +NS_ERROR_MODULE_GFX = 3 +NS_ERROR_MODULE_WIDGET = 4 +NS_ERROR_MODULE_CALENDAR = 5 +NS_ERROR_MODULE_NETWORK = 6 +NS_ERROR_MODULE_PLUGINS = 7 +NS_ERROR_MODULE_LAYOUT = 8 +NS_ERROR_MODULE_HTMLPARSER = 9 +NS_ERROR_MODULE_RDF = 10 +NS_ERROR_MODULE_UCONV = 11 +NS_ERROR_MODULE_REG = 12 +NS_ERROR_MODULE_FILES = 13 +NS_ERROR_MODULE_DOM = 14 +NS_ERROR_MODULE_IMGLIB = 15 +NS_ERROR_MODULE_MAILNEWS = 16 +NS_ERROR_MODULE_EDITOR = 17 +NS_ERROR_MODULE_XPCONNECT = 18 +NS_ERROR_MODULE_PROFILE = 19 +NS_ERROR_MODULE_LDAP = 20 +NS_ERROR_MODULE_SECURITY = 21 +NS_ERROR_MODULE_DOM_XPATH = 22 +NS_ERROR_MODULE_DOM_RANGE = 23 +NS_ERROR_MODULE_URILOADER = 24 +NS_ERROR_MODULE_CONTENT = 25 +NS_ERROR_MODULE_PYXPCOM = 26 +NS_ERROR_MODULE_XSLT = 27 +NS_ERROR_MODULE_IPC = 28 +NS_ERROR_MODULE_SVG = 29 +NS_ERROR_MODULE_GENERAL = 51 + +def NS_FAILED(_nsresult): return ((_nsresult) & -2147483648) + +NS_ERROR_SEVERITY_SUCCESS = 0 +NS_ERROR_SEVERITY_ERROR = 1 +NS_ERROR_MODULE_BASE_OFFSET = 69 +def NS_ERROR_GET_CODE(err): return ((err) & 65535) + +def NS_ERROR_GET_MODULE(err): return (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 8191)) + +def NS_ERROR_GET_SEVERITY(err): return (((err) >> 31) & 1) + +NS_OK = 0 +NS_COMFALSE = 1 +NS_ERROR_BASE = ( -1041039360) +NS_ERROR_NOT_INITIALIZED = (NS_ERROR_BASE + 1) +NS_ERROR_ALREADY_INITIALIZED = (NS_ERROR_BASE + 2) +NS_ERROR_NOT_IMPLEMENTED = ( -2147467263) +NS_NOINTERFACE = ( -2147467262) +NS_ERROR_NO_INTERFACE = NS_NOINTERFACE +NS_ERROR_INVALID_POINTER = ( -2147467261) +NS_ERROR_NULL_POINTER = NS_ERROR_INVALID_POINTER +NS_ERROR_ABORT = ( -2147467260) +NS_ERROR_FAILURE = ( -2147467259) +NS_ERROR_UNEXPECTED = ( -2147418113) +NS_ERROR_OUT_OF_MEMORY = ( -2147024882) +NS_ERROR_ILLEGAL_VALUE = ( -2147024809) +NS_ERROR_INVALID_ARG = NS_ERROR_ILLEGAL_VALUE +NS_ERROR_NO_AGGREGATION = ( -2147221232) +NS_ERROR_NOT_AVAILABLE = ( -2147221231) +NS_ERROR_FACTORY_NOT_REGISTERED = ( -2147221164) +NS_ERROR_FACTORY_REGISTER_AGAIN = ( -2147221163) +NS_ERROR_FACTORY_NOT_LOADED = ( -2147221000) +NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT = \ + (NS_ERROR_BASE + 257) +NS_ERROR_FACTORY_EXISTS = (NS_ERROR_BASE + 256) +NS_ERROR_PROXY_INVALID_IN_PARAMETER = ( -2147418096) +NS_ERROR_PROXY_INVALID_OUT_PARAMETER = ( -2147418095) + +##### END OF GENERATED CODE +##### +def NS_ERROR_GENERATE_FAILURE(module,code): + # slightly optimized, and avoids 2.3->2.4 long/int changes + # return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + return -2147483648 | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + +def NS_ERROR_GENERATE_SUCCESS(module,code): + #return (NS_ERROR_SEVERITY_SUCCESS<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + return ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + +NS_BASE_STREAM_CLOSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) +NS_BASE_STREAM_OSERROR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3) +NS_BASE_STREAM_ILLEGAL_ARGS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 4) +NS_BASE_STREAM_NO_CONVERTER = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5) +NS_BASE_STREAM_BAD_CONVERSION = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6) +NS_BASE_STREAM_WOULD_BLOCK = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 7) +NS_ERROR_FILE_UNRECOGNIZED_PATH = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 1) +NS_ERROR_FILE_UNRESOLVABLE_SYMLINK = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 2) +NS_ERROR_FILE_EXECUTION_FAILED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 3) +NS_ERROR_FILE_UNKNOWN_TYPE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 4) +NS_ERROR_FILE_DESTINATION_NOT_DIR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 5) +NS_ERROR_FILE_TARGET_DOES_NOT_EXIST = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 6) +NS_ERROR_FILE_COPY_OR_MOVE_FAILED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 7) +NS_ERROR_FILE_ALREADY_EXISTS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 8) +NS_ERROR_FILE_INVALID_PATH = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 9) +NS_ERROR_FILE_DISK_FULL = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 10) +NS_ERROR_FILE_CORRUPTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 11) +NS_ERROR_FILE_NOT_DIRECTORY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 12) +NS_ERROR_FILE_IS_DIRECTORY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 13) +NS_ERROR_FILE_IS_LOCKED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 14) +NS_ERROR_FILE_TOO_BIG = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 15) +NS_ERROR_FILE_NO_DEVICE_SPACE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 16) +NS_ERROR_FILE_NAME_TOO_LONG = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 17) +NS_ERROR_FILE_NOT_FOUND = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 18) +NS_ERROR_FILE_READ_ONLY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 19) +NS_ERROR_FILE_DIR_NOT_EMPTY = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 20) +NS_ERROR_FILE_ACCESS_DENIED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 21) + +## from netCore.h +NS_ERROR_ALREADY_CONNECTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 11) + +NS_ERROR_NOT_CONNECTED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 12) +NS_ERROR_IN_PROGRESS = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 15) +NS_ERROR_OFFLINE = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 16) + +## from nsISocketTransportService.idl +NS_ERROR_CONNECTION_REFUSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 13) + +NS_ERROR_NET_TIMEOUT = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 14) + +# Status nsresult codes: used with nsIProgressEventSink::OnStatus +NS_NET_STATUS_RESOLVING_HOST = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 3) +NS_NET_STATUS_CONNECTED_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 4) +NS_NET_STATUS_SENDING_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 5) +NS_NET_STATUS_RECEIVING_FROM = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 6) +NS_NET_STATUS_CONNECTING_TO = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 7) diff --git a/src/libs/xpcom18a4/python/primitives.py b/src/libs/xpcom18a4/python/primitives.py new file mode 100755 index 00000000..464f12e4 --- /dev/null +++ b/src/libs/xpcom18a4/python/primitives.py @@ -0,0 +1,39 @@ +# Various utilities for working with nsISupportsPrimitive +from xpcom import components + +_primitives_map = {} + +def _build_map(): + ifaces = components.interfaces + iface = ifaces.nsISupportsPrimitive + m = _primitives_map + + m[iface.TYPE_ID] = ifaces.nsISupportsID + m[iface.TYPE_CSTRING] = ifaces.nsISupportsCString + m[iface.TYPE_STRING] = ifaces.nsISupportsString + m[iface.TYPE_PRBOOL] = ifaces.nsISupportsPRBool + m[iface.TYPE_PRUINT8] = ifaces.nsISupportsPRUint8 + m[iface.TYPE_PRUINT16] = ifaces.nsISupportsPRUint16 + m[iface.TYPE_PRUINT32] = ifaces.nsISupportsPRUint32 + m[iface.TYPE_PRUINT64] = ifaces.nsISupportsPRUint64 + m[iface.TYPE_PRINT16] = ifaces.nsISupportsPRInt16 + m[iface.TYPE_PRINT32] = ifaces.nsISupportsPRInt32 + m[iface.TYPE_PRINT64] = ifaces.nsISupportsPRInt64 + m[iface.TYPE_PRTIME] = ifaces.nsISupportsPRTime + m[iface.TYPE_CHAR] = ifaces.nsISupportsChar + m[iface.TYPE_FLOAT] = ifaces.nsISupportsFloat + m[iface.TYPE_DOUBLE] = ifaces.nsISupportsDouble + # Do interface pointer specially - it provides the IID. + #m[iface.TYPE_INTERFACE_POINTER] = ifaces.nsISupportsDouble + +def GetPrimitive(ob): + if len(_primitives_map)==0: + _build_map() + + prin = ob.QueryInterface(components.interfaces.nsISupportsPrimitive) + try: + better = _primitives_map[prin.type] + except KeyError: + raise ValueError("This primitive type (%d) is not supported" % (prin.type,)) + prin = prin.QueryInterface(better) + return prin.data diff --git a/src/libs/xpcom18a4/python/readme.html b/src/libs/xpcom18a4/python/readme.html new file mode 100644 index 00000000..112f43e0 --- /dev/null +++ b/src/libs/xpcom18a4/python/readme.html @@ -0,0 +1,121 @@ + + + + + + + +Python XPCOM module + + + + +

Python XPCOM Package

+ +

Mozilla CVS Version - Last updated May 2002

+

This is the readme for the Python interface to XPCOM.

+

XPCOM is an acronym for "Cross Platform COM".  It has +come out of the Mozilla project, which +maintains the main XPCOM +project pages.  The Python XPCOM package is a set of Python bindings to +XPCOM, allowing a Python programmer to both use and implement XPCOM +interfaces.  If you don't know what Python +is, then none of this probably interests you at all!

+

This readme has links to the following information:

+ +

Note: This package requires Python 1.6 or later; we recommend using +the latest +official Python version.  This package works +very well with the latest ActivePython, +and does not require any external modules or packages beyond what is provided in +the core Python release for each platform.

+

About the Python XPCOM Package

+

The Python XPCOM Package was developed by ActiveState +Tool Corporation, and came out of their Komodo +project.  The Python XPCOM package is released under the Mozilla +Public License (MPL)

+

Please see the credits file for a list of +contributors.

+

Known Bugs/Issues

+
    +
  • No attempt is made to recurse sub-directories of the main +"components" directory.  This is because we may decide on some +smart scheme for recursion (similar to Python packages), and don't want people +to rely on simple recursive searches.
  • +
  • No unregistration support at all. The main Python Component Loader supports + unregistration, but the actual Python objects themselves do not support unregistration. It is unclear if the Component Loader + unregistration process needs to manually remove each component it is responsible +for.
  • +
  • All Python-implemented components unconditionally support +weak-references.  There is no way to disable this feature for any or all +components.  It is unclear if there is a need to prevent this, but it is +documented here just in case!
  • +
+

Release History

+

Version 0.90 - January 2001

+
    +
  • First public release.
  • +
+

Version 0.91 - January 2001

+
    +
  • Fix a seg fault on Linux when PYTHONPATH is not set.
  • +
  • Changes to allow building with stand-alone XPCOM.
  • +
+ +

Version 0.92 - May 2001

+

Implement interface flattening.  You should (almost) never need to use QueryInterface()!  +We are still 100% backwards compatible, so usage of QI still works - just is +generally not necessary.

+ +

Version 0.93 - May 2002

+ +

Implement nsIVariant and all new string types.  Complete move to +autoconf build system.

+ + + + diff --git a/src/libs/xpcom18a4/python/server/.cvsignore b/src/libs/xpcom18a4/python/server/.cvsignore new file mode 100644 index 00000000..52e4e611 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/.cvsignore @@ -0,0 +1,2 @@ +*.pyc +*.pyo diff --git a/src/libs/xpcom18a4/python/server/__init__.py b/src/libs/xpcom18a4/python/server/__init__.py new file mode 100755 index 00000000..48b15106 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/__init__.py @@ -0,0 +1,88 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# Activestate Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond +# +# 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 ***** + +# The xpcom.server package. + +from xpcom.server.policy import DefaultPolicy +from xpcom import _xpcom + +# We define the concept of a single "tracer" object - similar to the single +# Python "trace hook" for debugging. Someone can set +# xpcom.server.tracer to some class/function, and it will be used in place +# of the real xpcom object. Presumably this "trace" object will delegate +# to the real object, but presumably also taking some other action, such +# as calling a profiler or debugger. +# tracer_unwrap is a function used to "unwrap" the tracer object. +# If is expected that tracer_unwrap will be called with an object +# previously returned by "tracer()". +tracer = tracer_unwrap = None + +# Wrap an instance in an interface (via a policy) +def WrapObject(ob, iid, policy = None, bWrapClient = 1): + """Called by the framework to attempt to wrap + an object in a policy. + If iid is None, it will use the first interface the object indicates it supports. + """ + if policy is None: + policy = DefaultPolicy + if tracer is not None: + ob = tracer(ob) + return _xpcom.WrapObject(policy( ob, iid ), iid, bWrapClient) + +# Unwrap a Python object back into the Python object +def UnwrapObject(ob): + if ob is None: + return None + ret = _xpcom.UnwrapObject(ob)._obj_ + if tracer_unwrap is not None: + ret = tracer_unwrap(ret) + return ret + +# Create the main module for the Python loader. +# This is a once only init process, and the returned object +# if used to load all other Python components. + +# This means that we keep all factories, modules etc implemented in +# Python! +def NS_GetModule( serviceManager, nsIFile ): + from . import loader + iid = _xpcom.IID_nsIModule + return WrapObject(loader.MakePythonComponentLoaderModule(serviceManager, nsIFile), iid, bWrapClient = 0) + +def _shutdown(): + from xpcom.server.policy import _shutdown + _shutdown() diff --git a/src/libs/xpcom18a4/python/server/enumerator.py b/src/libs/xpcom18a4/python/server/enumerator.py new file mode 100755 index 00000000..d3fb89a9 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/enumerator.py @@ -0,0 +1,58 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +from xpcom import components + +# This class is created by Python components when it +# needs to return an enumerator. +# For example, a component may implement a function: +# nsISimpleEnumerator enumSomething(); +# This could could simply say: +# return SimpleEnumerator([something1, something2, something3]) +class SimpleEnumerator: + _com_interfaces_ = [components.interfaces.nsISimpleEnumerator] + + def __init__(self, data): + self._data = data + self._index = 0 + + def hasMoreElements(self): + return self._index < len(self._data) + + def getNext(self): + self._index = self._index + 1 + return self._data[self._index-1] diff --git a/src/libs/xpcom18a4/python/server/factory.py b/src/libs/xpcom18a4/python/server/factory.py new file mode 100755 index 00000000..b65483dd --- /dev/null +++ b/src/libs/xpcom18a4/python/server/factory.py @@ -0,0 +1,68 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# Class factory +# +# Hardly worth its own source file! +import xpcom +from xpcom import components, nsError, _xpcom, logger + +class Factory: + _com_interfaces_ = components.interfaces.nsIFactory + # This will only ever be constructed via other Python code, + # so we can have ctor args. + def __init__(self, klass): + self.klass = klass + + def createInstance(self, outer, iid): + if outer is not None: + raise xpcom.ServerException(nsError.NS_ERROR_NO_AGGREGATION) + + logger.debug("Python Factory creating %s", self.klass.__name__) + try: + return self.klass() + except: + # An exception here may not be obvious to the user - none + # of their code has been called yet. It can be handy on + # failure to tell the user what class failed! + logger.error("Creation of class '%r' failed!\nException details follow\n", + self.klass) + # The framework itself will also report the error. + raise + + def lockServer(self, lock): + logger.debug("Python Factory LockServer called '%s'", lock) diff --git a/src/libs/xpcom18a4/python/server/loader.py b/src/libs/xpcom18a4/python/server/loader.py new file mode 100755 index 00000000..ebd42b61 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/loader.py @@ -0,0 +1,227 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# Activestate Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond +# +# 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 ***** + +import xpcom +from xpcom import components, logger +from . import module +import glob +import os +from xpcom.client import Component + +# Until we get interface constants. +When_Startup = 0 +When_Component = 1 +When_Timer = 2 + +def _has_good_attr(object, attr): + # Actually allows "None" to be specified to disable inherited attributes. + return getattr(object, attr, None) is not None + +def FindCOMComponents(py_module): + # For now, just run over all classes looking for likely candidates. + comps = [] + for name, object in list(py_module.__dict__.items()): + try: + if (type(object) == type or issubclass(object, object)) and \ + _has_good_attr(object, "_com_interfaces_") and \ + _has_good_attr(object, "_reg_clsid_") and \ + _has_good_attr(object, "_reg_contractid_"): + comps.append(object) + except TypeError: + # The issubclass call raises TypeError when the obj is not a class. + pass; + return comps + +def register_self(klass, compMgr, location, registryLocation, componentType): + pcl = PythonComponentLoader + from xpcom import _xpcom + svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/categorymanager;1", components.interfaces.nsICategoryManager) + svc.addCategoryEntry("component-loader", pcl._reg_component_type_, pcl._reg_contractid_, 1, 1) + +class PythonComponentLoader: + _com_interfaces_ = components.interfaces.nsIComponentLoader + _reg_clsid_ = "{63B68B1E-3E62-45f0-98E3-5E0B5797970C}" # Never copy these! + _reg_contractid_ = "moz.pyloader.1" + _reg_desc_ = "Python component loader" + # Optional function which performs additional special registration + # Appears that no special unregistration is needed for ComponentLoaders, hence no unregister function. + _reg_registrar_ = (register_self,None) + # Custom attributes for ComponentLoader registration. + _reg_component_type_ = "script/python" + + def __init__(self): + self.com_modules = {} # Keyed by module's FQN as obtained from nsIFile.path + self.moduleFactory = module.Module + self.num_modules_this_register = 0 + + def _getCOMModuleForLocation(self, componentFile): + fqn = componentFile.path + mod = self.com_modules.get(fqn) + if mod is not None: + return mod + import ihooks, sys + base_name = os.path.splitext(os.path.basename(fqn))[0] + loader = ihooks.ModuleLoader() + + module_name_in_sys = "component:%s" % (base_name,) + stuff = loader.find_module(base_name, [componentFile.parent.path]) + assert stuff is not None, "Couldnt find the module '%s'" % (base_name,) + py_mod = loader.load_module( module_name_in_sys, stuff ) + + # Make and remember the COM module. + comps = FindCOMComponents(py_mod) + mod = self.moduleFactory(comps) + + self.com_modules[fqn] = mod + return mod + + def getFactory(self, clsid, location, type): + # return the factory + assert type == self._reg_component_type_, "Being asked to create an object not of my type:%s" % (type,) + # FIXME: how to do this without obsolete component manager? + cmo = components.manager.queryInterface(components.interfaces.nsIComponentManagerObsolete) + file_interface = cmo.specForRegistryLocation(location) + # delegate to the module. + m = self._getCOMModuleForLocation(file_interface) + return m.getClassObject(components.manager, clsid, components.interfaces.nsIFactory) + + def init(self, comp_mgr, registry): + # void + self.comp_mgr = comp_mgr + logger.debug("Python component loader init() called") + + # Called when a component of the appropriate type is registered, + # to give the component loader an opportunity to do things like + # annotate the registry and such. + def onRegister (self, clsid, type, className, proId, location, replace, persist): + logger.debug("Python component loader - onRegister() called") + + def autoRegisterComponents (self, when, directory): + directory_path = directory.path + self.num_modules_this_register = 0 + logger.debug("Auto-registering all Python components in '%s'", directory_path) + + # ToDo - work out the right thing here + # eg - do we recurse? + # - do we support packages? + entries = directory.directoryEntries + while entries.HasMoreElements(): + entry = entries.GetNext(components.interfaces.nsIFile) + if os.path.splitext(entry.path)[1]==".py": + try: + self.autoRegisterComponent(when, entry) + # Handle some common user errors + except xpcom.COMException as details: + from xpcom import nsError + # If the interface name does not exist, suppress the traceback + if details.errno==nsError.NS_ERROR_NO_INTERFACE: + logger.error("Registration of '%s' failed\n %s", + entry.leafName, details.message) + else: + logger.exception("Registration of '%s' failed!", entry.leafName) + except SyntaxError as details: + # Syntax error in source file - no useful traceback here either. + logger.error("Registration of '%s' failed\n %s", + entry.leafName, details) + except: + # All other exceptions get the full traceback. + logger.exception("Registration of '%s' failed.", entry.leafName) + + def autoRegisterComponent (self, when, componentFile): + # bool return + + # Check if we actually need to do anything + modtime = componentFile.lastModifiedTime + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + if not loader_mgr.hasFileChanged(componentFile, None, modtime): + return 1 + + if self.num_modules_this_register == 0: + # New components may have just installed new Python + # modules into the main python directory (including new .pth files) + # So we ask Python to re-process our site directory. + # Note that the pyloader does the equivalent when loading. + try: + from xpcom import _xpcom + import site + NS_XPCOM_CURRENT_PROCESS_DIR="XCurProcD" + dirname = _xpcom.GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR) + dirname.append("python") + site.addsitedir(dirname.path) + except: + logger.exception("PyXPCOM loader failed to process site directory before component registration") + + self.num_modules_this_register += 1 + + # auto-register via the module. + m = self._getCOMModuleForLocation(componentFile) + m.registerSelf(components.manager, componentFile, None, self._reg_component_type_) + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + loader_mgr.saveFileInfo(componentFile, None, modtime) + return 1 + + def autoUnregisterComponent (self, when, componentFile): + # bool return + # auto-unregister via the module. + m = self._getCOMModuleForLocation(componentFile) + loader_mgr = components.manager.queryInterface(components.interfaces.nsIComponentLoaderManager) + try: + m.unregisterSelf(components.manager, componentFile) + finally: + loader_mgr.removeFileInfo(componentFile, None) + return 1 + + def registerDeferredComponents (self, when): + # bool return + logger.debug("Python component loader - registerDeferred() called") + return 0 # no more to register + + def unloadAll (self, when): + # This is called at shutdown time - don't get too upset if an error + # results from logging due to the logfile being closed + try: + logger.debug("Python component loader being asked to unload all components!") + except: + # Evil blank except, but restricting to just catching IOError + # failure means custom logs could still screw us + pass + self.comp_mgr = None + self.com_modules = {} + +def MakePythonComponentLoaderModule(serviceManager, nsIFile): + from . import module + return module.Module( [PythonComponentLoader] ) diff --git a/src/libs/xpcom18a4/python/server/module.py b/src/libs/xpcom18a4/python/server/module.py new file mode 100755 index 00000000..73024e95 --- /dev/null +++ b/src/libs/xpcom18a4/python/server/module.py @@ -0,0 +1,108 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is ActiveState Tool Corp. +# Portions created by ActiveState Tool Corp. are Copyright (C) 2000, 2001 +# ActiveState Tool Corp. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +from xpcom import components +from xpcom import ServerException, Exception +from xpcom import nsError + +from . import factory + +import types +import os + +class Module: + _com_interfaces_ = components.interfaces.nsIModule + def __init__(self, comps): + # Build a map of classes we can provide factories for. + c = self.components = {} + for klass in comps: + c[components.ID(klass._reg_clsid_)] = klass + self.klassFactory = factory.Factory + + def getClassObject(self, compMgr, clsid, iid): + # Single retval result. + try: + klass = self.components[clsid] + except KeyError: + raise ServerException(nsError.NS_ERROR_FACTORY_NOT_REGISTERED) + + # We can ignore the IID - the auto-wrap process will automatically QI us. + return self.klassFactory(klass) + + def registerSelf(self, compMgr, location, loaderStr, componentType): + # void function. + fname = os.path.basename(location.path) + for klass in list(self.components.values()): + reg_contractid = klass._reg_contractid_ + print("Registering '%s' (%s)" % (reg_contractid, fname)) + reg_desc = getattr(klass, "_reg_desc_", reg_contractid) + compMgr = compMgr.queryInterface(components.interfaces.nsIComponentRegistrar) + compMgr.registerFactoryLocation(klass._reg_clsid_, + reg_desc, + reg_contractid, + location, + loaderStr, + componentType) + + # See if this class nominates custom register_self + extra_func = getattr(klass, "_reg_registrar_", (None,None))[0] + if extra_func is not None: + extra_func(klass, compMgr, location, loaderStr, componentType) + + def unregisterSelf(self, compMgr, location, loaderStr): + # void function. + for klass in list(self.components.values()): + ok = 1 + try: + compMgr.unregisterComponentSpec(klass._reg_clsid_, location) + except Exception: + ok = 0 + # Give the class a bash even if we failed! + extra_func = getattr(klass, "_reg_registrar_", (None,None))[1] + if extra_func is not None: + try: + extra_func(klass, compMgr, location, loaderStr) + except Exception: + ok = 0 + if ok: + print("Successfully unregistered", klass.__name__) + else: + print("Unregistration of", klass.__name__, "failed. (probably just not already registered)") + + def canUnload(self, compMgr): + # single bool result + return 0 # we can never unload! + diff --git a/src/libs/xpcom18a4/python/server/policy.py b/src/libs/xpcom18a4/python/server/policy.py new file mode 100755 index 00000000..7f84167c --- /dev/null +++ b/src/libs/xpcom18a4/python/server/policy.py @@ -0,0 +1,398 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +from xpcom import xpcom_consts, _xpcom, client, nsError, logger +from xpcom import ServerException, COMException +import xpcom +import xpcom.server +import operator +import types +import logging +import sys + +# Python 3 hacks: +if sys.version_info[0] >= 3: + long = int # pylint: disable=W0622,C0103 + + +IID_nsISupports = _xpcom.IID_nsISupports +IID_nsIVariant = _xpcom.IID_nsIVariant +XPT_MD_IS_GETTER = xpcom_consts.XPT_MD_IS_GETTER +XPT_MD_IS_SETTER = xpcom_consts.XPT_MD_IS_SETTER + +VARIANT_INT_TYPES = xpcom_consts.VTYPE_INT8, xpcom_consts.VTYPE_INT16, xpcom_consts.VTYPE_INT32, \ + xpcom_consts.VTYPE_UINT8, xpcom_consts.VTYPE_UINT16, xpcom_consts.VTYPE_INT32 +VARIANT_LONG_TYPES = xpcom_consts.VTYPE_INT64, xpcom_consts.VTYPE_UINT64 +VARIANT_FLOAT_TYPES = xpcom_consts.VTYPE_FLOAT, xpcom_consts.VTYPE_DOUBLE +VARIANT_STRING_TYPES = xpcom_consts.VTYPE_CHAR, xpcom_consts.VTYPE_CHAR_STR, xpcom_consts.VTYPE_STRING_SIZE_IS, \ + xpcom_consts.VTYPE_CSTRING +VARIANT_UNICODE_TYPES = xpcom_consts.VTYPE_WCHAR, xpcom_consts.VTYPE_DOMSTRING, xpcom_consts.VTYPE_WSTRING_SIZE_IS, \ + xpcom_consts.VTYPE_ASTRING + +_supports_primitives_map_ = {} # Filled on first use. + +_interface_sequence_types_ = tuple, list +if sys.version_info[0] <= 2: + _string_types_ = str, unicode +else: + _string_types_ = bytes, str +XPTI_GetInterfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager + +def _GetNominatedInterfaces(obj): + ret = getattr(obj, "_com_interfaces_", None) + if ret is None: return None + # See if the user only gave one. + if type(ret) not in _interface_sequence_types_: + ret = [ret] + real_ret = [] + # For each interface, walk to the root of the interface tree. + iim = XPTI_GetInterfaceInfoManager() + for interface in ret: + # Allow interface name or IID. + interface_info = None + if type(interface) in _string_types_: + try: + interface_info = iim.GetInfoForName(interface) + except COMException: + pass + if interface_info is None: + # Allow a real IID + interface_info = iim.GetInfoForIID(interface) + real_ret.append(interface_info.GetIID()) + parent = interface_info.GetParent() + while parent is not None: + parent_iid = parent.GetIID() + if parent_iid == IID_nsISupports: + break + real_ret.append(parent_iid) + parent = parent.GetParent() + return real_ret + +## +## ClassInfo support +## +## We cache class infos by class +class_info_cache = {} + +def GetClassInfoForObject(ob): + if xpcom.server.tracer_unwrap is not None: + ob = xpcom.server.tracer_unwrap(ob) + klass = ob.__class__ + ci = class_info_cache.get(klass) + if ci is None: + ci = DefaultClassInfo(klass) + ci = xpcom.server.WrapObject(ci, _xpcom.IID_nsIClassInfo, bWrapClient = 0) + class_info_cache[klass] = ci + return ci + +class DefaultClassInfo: + _com_interfaces_ = _xpcom.IID_nsIClassInfo + def __init__(self, klass): + self.klass = klass + self.contractID = getattr(klass, "_reg_contractid_", None) + self.classDescription = getattr(klass, "_reg_desc_", None) + self.classID = getattr(klass, "_reg_clsid_", None) + self.implementationLanguage = 3 # Python - avoid lookups just for this + self.flags = 0 # what to do here?? + self.interfaces = None + + def get_classID(self): + if self.classID is None: + raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED, "Class '%r' has no class ID" % (self.klass,)) + return self.classID + + def getInterfaces(self): + if self.interfaces is None: + self.interfaces = _GetNominatedInterfaces(self.klass) + return self.interfaces + + def getHelperForLanguage(self, language): + return None # Not sure what to do here. + +class DefaultPolicy: + def __init__(self, instance, iid): + self._obj_ = instance + self._nominated_interfaces_ = ni = _GetNominatedInterfaces(instance) + self._iid_ = iid + if ni is None: + raise ValueError("The object '%r' can not be used as a COM object" % (instance,)) + # This is really only a check for the user + if __debug__: + if iid != IID_nsISupports and iid not in ni: + # The object may delegate QI. + delegate_qi = getattr(instance, "_query_interface_", None) + # Perform the actual QI and throw away the result - the _real_ + # QI performed by the framework will set things right! + if delegate_qi is None or not delegate_qi(iid): + raise ServerException(nsError.NS_ERROR_NO_INTERFACE) + # Stuff for the magic interface conversion. + self._interface_info_ = None + self._interface_iid_map_ = {} # Cache - Indexed by (method_index, param_index) + + def _QueryInterface_(self, com_object, iid): + # Framework allows us to return a single boolean integer, + # or a COM object. + if iid in self._nominated_interfaces_: + # We return the underlying object re-wrapped + # in a new gateway - which is desirable, as one gateway should only support + # one interface (this wont affect the users of this policy - we can have as many + # gateways as we like pointing to the same Python objects - the users never + # see what object the call came in from. + # NOTE: We could have simply returned the instance and let the framework + # do the auto-wrap for us - but this way we prevent a round-trip back into Python + # code just for the autowrap. + return xpcom.server.WrapObject(self._obj_, iid, bWrapClient = 0) + + # Always support nsIClassInfo + if iid == _xpcom.IID_nsIClassInfo: + return GetClassInfoForObject(self._obj_) + + # See if the instance has a QI + # use lower-case "_query_interface_" as win32com does, and it doesnt really matter. + delegate = getattr(self._obj_, "_query_interface_", None) + if delegate is not None: + # The COM object itself doesnt get passed to the child + # (again, as win32com doesnt). It is rarely needed + # (in win32com, we dont even pass it to the policy, although we have identified + # one place where we should - for marshalling - so I figured I may as well pass it + # to the policy layer here, but no all the way down to the object. + return delegate(iid) + # Finally see if we are being queried for one of the "nsISupports primitives" + if not _supports_primitives_map_: + iim = _xpcom.XPTI_GetInterfaceInfoManager() + for (iid_name, attr, cvt) in _supports_primitives_data_: + special_iid = iim.GetInfoForName(iid_name).GetIID() + _supports_primitives_map_[special_iid] = (attr, cvt) + attr, cvt = _supports_primitives_map_.get(iid, (None,None)) + if attr is not None and hasattr(self._obj_, attr): + return xpcom.server.WrapObject(SupportsPrimitive(iid, self._obj_, attr, cvt), iid, bWrapClient = 0) + # Out of clever things to try! + return None # We dont support this IID. + + def _MakeInterfaceParam_(self, interface, iid, method_index, mi, param_index): + # Wrap a "raw" interface object in a nice object. The result of this + # function will be passed to one of the gateway methods. + if iid is None: + # look up the interface info - this will be true for all xpcom called interfaces. + if self._interface_info_ is None: + import xpcom.xpt + self._interface_info_ = xpcom.xpt.Interface( self._iid_ ) + iid = self._interface_iid_map_.get( (method_index, param_index)) + if iid is None: + iid = self._interface_info_.GetIIDForParam(method_index, param_index) + self._interface_iid_map_[(method_index, param_index)] = iid + # handle nsIVariant + if iid == IID_nsIVariant: + interface = interface.QueryInterface(iid) + dt = interface.dataType + if dt in VARIANT_INT_TYPES: + return interface.getAsInt32() + if dt in VARIANT_LONG_TYPES: + return interface.getAsInt64() + if dt in VARIANT_FLOAT_TYPES: + return interface.getAsFloat() + if dt in VARIANT_STRING_TYPES: + return interface.getAsStringWithSize() + if dt in VARIANT_UNICODE_TYPES: + return interface.getAsWStringWithSize() + if dt == xpcom_consts.VTYPE_BOOL: + return interface.getAsBool() + if dt == xpcom_consts.VTYPE_INTERFACE: + return interface.getAsISupports() + if dt == xpcom_consts.VTYPE_INTERFACE_IS: + return interface.getAsInterface() + if dt == xpcom_consts.VTYPE_EMPTY or dt == xpcom_consts.VTYPE_VOID: + return None + if dt == xpcom_consts.VTYPE_ARRAY: + return interface.getAsArray() + if dt == xpcom_consts.VTYPE_EMPTY_ARRAY: + return [] + if dt == xpcom_consts.VTYPE_ID: + return interface.getAsID() + # all else fails... + logger.warning("Warning: nsIVariant type %d not supported - returning a string", dt) + try: + return interface.getAsString() + except COMException: + logger.exception("Error: failed to get Variant as a string - returning variant object") + return interface + + return client.Component(interface, iid) + + def _CallMethod_(self, com_object, index, info, params): + #print "_CallMethod_", index, info, params + flags, name, param_descs, ret = info + assert ret[1][0] == xpcom_consts.TD_UINT32, "Expected an nsresult (%s)" % (ret,) + if XPT_MD_IS_GETTER(flags): + # Look for a function of that name + func = getattr(self._obj_, "get_" + name, None) + if func is None: + assert len(param_descs)==1 and len(params)==0, "Can only handle a single [out] arg for a default getter" + ret = getattr(self._obj_, name) # Let attribute error go here! + else: + ret = func(*params) + return 0, ret + elif XPT_MD_IS_SETTER(flags): + # Look for a function of that name + func = getattr(self._obj_, "set_" + name, None) + if func is None: + assert len(param_descs)==1 and len(params)==1, "Can only handle a single [in] arg for a default setter" + setattr(self._obj_, name, params[0]) # Let attribute error go here! + else: + func(*params) + return 0 + else: + # A regular method. + func = getattr(self._obj_, name) + return 0, func(*params) + + def _doHandleException(self, func_name, exc_info): + exc_val = exc_info[1] + is_server_exception = isinstance(exc_val, ServerException) + if is_server_exception: + # When a component raised an explicit COM exception, it is + # considered 'normal' - however, we still write a debug log + # record to help track these otherwise silent exceptions. + + # Note that Python 2.3 does not allow an explicit exc_info tuple + # and passing 'True' will not work as there is no exception pending. + # Trick things! + if logger.isEnabledFor(logging.DEBUG): + try: + if sys.version_info[0] <= 2: + exec('raise exc_info[0], exc_info[1], exc_info[2]') + else: + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) + except: + logger.debug("'%s' raised COM Exception %s", + func_name, exc_val, exc_info = 1) + return exc_val.errno + # Unhandled exception - always print a warning and the traceback. + # As above, trick the logging module to handle Python 2.3 + try: + if sys.version_info[0] <= 2: + exec('raise exc_info[0], exc_info[1], exc_info[2]') + else: + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2]) + except: + logger.exception("Unhandled exception calling '%s'", func_name) + return nsError.NS_ERROR_FAILURE + + # Called whenever an unhandled Python exception is detected as a result + # of _CallMethod_ - this exception may have been raised during the _CallMethod_ + # invocation, or after its return, but when unpacking the results + # eg, type errors, such as a Python integer being used as a string "out" param. + def _CallMethodException_(self, com_object, index, info, params, exc_info): + # Later we may want to have some smart "am I debugging" flags? + # Or maybe just delegate to the actual object - it's probably got the best + # idea what to do with them! + flags, name, param_descs, ret = info + exc_typ, exc_val, exc_tb = exc_info + # use the xpt module to get a better repr for the method. + # But if we fail, ignore it! + try: + import xpcom.xpt + m = xpcom.xpt.Method(info, index, None) + func_repr = m.Describe().lstrip() + except COMException: + func_repr = "%s(%r)" % (name, param_descs) + except: + # any other errors are evil!? Log it + self._doHandleException("", sys.exc_info()) + # And fall through to logging the original error. + return self._doHandleException(func_repr, exc_info) + + # Called whenever a gateway fails due to anything other than _CallMethod_. + # Really only used for the component loader etc objects, so most + # users should never see exceptions triggered here. + def _GatewayException_(self, name, exc_info): + return self._doHandleException(name, exc_info) + +if sys.version_info[0] <= 2: + _supports_primitives_data_ = [ + ("nsISupportsCString", "__str__", str), + ("nsISupportsString", "__unicode__", unicode), + ("nsISupportsPRUint64", "__long__", long), + ("nsISupportsPRInt64", "__long__", long), + ("nsISupportsPRUint32", "__int__", int), + ("nsISupportsPRInt32", "__int__", int), + ("nsISupportsPRUint16", "__int__", int), + ("nsISupportsPRInt16", "__int__", int), + ("nsISupportsPRUint8", "__int__", int), + ("nsISupportsPRBool", "__nonzero__", operator.truth), + ("nsISupportsDouble", "__float__", float), + ("nsISupportsFloat", "__float__", float), + ] +else: + _supports_primitives_data_ = [ + ("nsISupportsCString", "__str__", str), + ("nsISupportsString", "__unicode__", str), + ("nsISupportsPRUint64", "__long__", int), + ("nsISupportsPRInt64", "__long__", int), + ("nsISupportsPRUint32", "__int__", int), + ("nsISupportsPRInt32", "__int__", int), + ("nsISupportsPRUint16", "__int__", int), + ("nsISupportsPRInt16", "__int__", int), + ("nsISupportsPRUint8", "__int__", int), + ("nsISupportsPRBool", "__nonzero__", operator.truth), + ("nsISupportsDouble", "__float__", float), + ("nsISupportsFloat", "__float__", float), + ] + +# Support for the nsISupports primitives: +class SupportsPrimitive: + _com_interfaces_ = ["nsISupports"] + def __init__(self, iid, base_ob, attr_name, converter): + self.iid = iid + self.base_ob = base_ob + self.attr_name = attr_name + self.converter = converter + def _query_interface_(self, iid): + if iid == self.iid: + return 1 + return None + def get_data(self): + method = getattr(self.base_ob, self.attr_name) + val = method() + return self.converter(val) + def set_data(self, val): + raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED) + def toString(self): + return str(self.get_data()) + +def _shutdown(): + class_info_cache.clear() diff --git a/src/libs/xpcom18a4/python/src/ErrorUtils.cpp b/src/libs/xpcom18a4/python/src/ErrorUtils.cpp new file mode 100644 index 00000000..9400799b --- /dev/null +++ b/src/libs/xpcom18a4/python/src/ErrorUtils.cpp @@ -0,0 +1,483 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsReadableUtils.h" +#include +#ifdef VBOX +# include +# include +# include +#endif +#include "nspr.h" // PR_fprintf + +static char *PyTraceback_AsString(PyObject *exc_tb); + +// The internal helper that actually moves the +// formatted string to the target! + +// Only used in really bad situations! +static void _PanicErrorWrite(const char *msg) +{ + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + PR_fprintf(PR_STDERR,"%s\n", msg); +} + +// Called when our "normal" error logger fails. +static void HandleLogError(const char *pszMessageText) +{ + nsCAutoString streamout; + + _PanicErrorWrite("Failed to log an error record"); + if (PyXPCOM_FormatCurrentException(streamout)) + _PanicErrorWrite(streamout.get()); + _PanicErrorWrite("Original error follows:"); + _PanicErrorWrite(pszMessageText); +} + +static const char *LOGGER_WARNING = "warning"; +static const char *LOGGER_ERROR = "error"; +static const char *LOGGER_DEBUG = "debug"; + +// Our "normal" error logger - calls back to the logging module. +void DoLogMessage(const char *methodName, const char *pszMessageText) +{ + // We use the logging module now. Originally this code called + // the logging module directly by way of the C API's + // PyImport_ImportModule/PyObject_CallMethod etc. However, this + // causes problems when there is no Python caller on the stack - + // the logging module's findCaller method fails with a None frame. + // We now work around this by calling PyRun_SimpleString - this + // causes a new frame to be created for executing the compiled + // string, and the logging module no longer fails. + // XXX - this implementation is less than ideal - findCaller now + // returns ("", 2). Ideally we would compile with a + // filename something similar to "". + + // But this also means we need a clear error state... + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); +// We will execute: +// import logging +// logging.getLogger('xpcom').{warning/error/etc}("%s", {msg_text}) + nsCAutoString c("import logging\nlogging.getLogger('xpcom')."); + c += methodName; + c += "('%s', "; + // Pull a trick to ensure a valid string - use Python repr! +#if PY_MAJOR_VERSION <= 2 + PyObject *obMessage = PyString_FromString(pszMessageText); +#else + PyObject *obMessage = PyUnicode_FromString(pszMessageText); +#endif + if (obMessage) { + PyObject *repr = PyObject_Repr(obMessage); + if (repr) { +#if PY_MAJOR_VERSION <= 2 + c += PyString_AsString(repr); +#else + c += PyUnicode_AsUTF8(repr); +#endif + Py_DECREF(repr); + } + Py_DECREF(obMessage); + } + c += ")\n"; + if (PyRun_SimpleString(c.get()) != 0) { + HandleLogError(pszMessageText); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + +void LogMessage(const char *methodName, const char *pszMessageText) +{ + // Be careful to save and restore the Python exception state + // before calling back to Python, or we lose the original error. + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + DoLogMessage(methodName, pszMessageText); + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + + +void LogMessage(const char *methodName, nsACString &text) +{ + char *c = ToNewCString(text); + LogMessage(methodName, c); + nsCRT::free(c); +} + +// A helper for the various logging routines. +static void VLogF(const char *methodName, const char *fmt, va_list argptr) +{ + char buff[512]; +#ifdef VBOX /* Enable the use of VBox formatting types. */ + RTStrPrintfV(buff, sizeof(buff), fmt, argptr); +#else + // Use safer NS_ functions. + PR_vsnprintf(buff, sizeof(buff), fmt, argptr); +#endif + + LogMessage(methodName, buff); +} + +PRBool PyXPCOM_FormatCurrentException(nsCString &streamout) +{ + PRBool ok = PR_FALSE; + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); + if (exc_typ) { + ok = PyXPCOM_FormatGivenException(streamout, exc_typ, exc_val, + exc_tb); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); + return ok; +} + +PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb) +{ + if (!exc_typ) + return PR_FALSE; + streamout += "\n"; + + if (exc_tb) { + const char *szTraceback = PyTraceback_AsString(exc_tb); + if (szTraceback == NULL) + streamout += "Can't get the traceback info!"; + else { + streamout += "Traceback (most recent call last):\n"; + streamout += szTraceback; + PyMem_Free((void *)szTraceback); + } + } + PyObject *temp = PyObject_Str(exc_typ); + if (temp) { +#if PY_MAJOR_VERSION <= 2 + streamout += PyString_AsString(temp); +#else + streamout += PyUnicode_AsUTF8(temp); +#endif + Py_DECREF(temp); + } else + streamout += "Can't convert exception to a string!"; + streamout += ": "; + if (exc_val != NULL) { + temp = PyObject_Str(exc_val); + if (temp) { +#if PY_MAJOR_VERSION <= 2 + streamout += PyString_AsString(temp); +#else + streamout += PyUnicode_AsUTF8(temp); +#endif + Py_DECREF(temp); + } else + streamout += "Can't convert exception value to a string!"; + } + return PR_TRUE; +} + +void PyXPCOM_LogError(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + // NOTE: It is tricky to use logger.exception here - the exception + // state when called back from the C code is clear. Only Python 2.4 + // and later allows an explicit exc_info tuple(). + + // Don't use VLogF here, instead arrange for exception info and + // traceback to be in the same buffer. + char buff[512]; + PR_vsnprintf(buff, sizeof(buff), fmt, marker); + // If we have a Python exception, also log that: + nsCAutoString streamout(buff); + if (PyXPCOM_FormatCurrentException(streamout)) { + LogMessage(LOGGER_ERROR, streamout); + } + va_end(marker); +} + +void PyXPCOM_LogWarning(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF(LOGGER_WARNING, fmt, marker); + va_end(marker); +} + +void PyXPCOM_Log(const char *level, const nsCString &msg) +{ + DoLogMessage(level, msg.get()); +} + +#ifdef DEBUG +void PyXPCOM_LogDebug(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF(LOGGER_DEBUG, fmt, marker); + va_end(marker); +} +#endif + +#ifdef VBOX +PyObject *PyXPCOM_BuildErrorMessage(nsresult r) +{ + char msg[512]; + bool gotMsg = false; + + if (!gotMsg) + { + nsresult rc; + nsCOMPtr es; + es = do_GetService (NS_EXCEPTIONSERVICE_CONTRACTID, &rc); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr em; + rc = es->GetCurrentExceptionManager (getter_AddRefs (em)); + if (NS_SUCCEEDED (rc)) + { + nsCOMPtr ex; + rc = em->GetExceptionFromProvider(r, NULL, getter_AddRefs (ex)); + if (NS_SUCCEEDED (rc) && ex) + { + nsXPIDLCString emsg; + ex->GetMessage(getter_Copies(emsg)); + PR_snprintf(msg, sizeof(msg), "%s", + emsg.get()); + gotMsg = true; + } + } + } + } + + if (!gotMsg) + { + const RTCOMERRMSG* pMsg = RTErrCOMGet(r); + if (strncmp(pMsg->pszMsgFull, "Unknown", 7) != 0) + { + PR_snprintf(msg, sizeof(msg), "%s (%s)", + pMsg->pszMsgFull, pMsg->pszDefine); + gotMsg = true; + } + } + + if (!gotMsg) + { + PR_snprintf(msg, sizeof(msg), "Error 0x%x in module 0x%x", + NS_ERROR_GET_CODE(r), NS_ERROR_GET_MODULE(r)); + } + PyObject *evalue = Py_BuildValue("is", r, msg); + return evalue; +} +#endif + +PyObject *PyXPCOM_BuildPyException(nsresult r) +{ +#ifndef VBOX + // Need the message etc. + PyObject *evalue = Py_BuildValue("i", r); +#else + PyObject *evalue = PyXPCOM_BuildErrorMessage(r); +#endif + PyErr_SetObject(PyXPCOM_Error, evalue); + Py_XDECREF(evalue); + return NULL; +} + +nsresult PyXPCOM_SetCOMErrorFromPyException() +{ + if (!PyErr_Occurred()) + // No error occurred + return NS_OK; + nsresult rv = NS_ERROR_FAILURE; + if (PyErr_ExceptionMatches(PyExc_MemoryError)) + rv = NS_ERROR_OUT_OF_MEMORY; + // todo: + // * Set an exception using the exception service. + + // Once we have returned to the xpcom caller, we don't want to leave a + // Python exception pending - it may get noticed when the next call + // is made on the same thread. + PyErr_Clear(); + return rv; +} + +/* Obtains a string from a Python traceback. + This is the exact same string as "traceback.print_exc" would return. + + Pass in a Python traceback object (probably obtained from PyErr_Fetch()) + Result is a string which must be free'd using PyMem_Free() +*/ +#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;} + +char *PyTraceback_AsString(PyObject *exc_tb) +{ + const char *errMsg = NULL; /* holds a local error message */ + char *result = NULL; /* a valid, allocated result. */ + PyObject *modStringIO = NULL; + PyObject *modTB = NULL; + PyObject *obFuncStringIO = NULL; + PyObject *obStringIO = NULL; + PyObject *obFuncTB = NULL; + PyObject *argsTB = NULL; + PyObject *obResult = NULL; + +#if PY_MAJOR_VERSION <= 2 + /* Import the modules we need - cStringIO and traceback */ + modStringIO = PyImport_ImportModule("cStringIO"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import cStringIO\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a cStringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n"); +#else + /* Import the modules we need - io and traceback */ + modStringIO = PyImport_ImportModule("io"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import io\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a StringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find io.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("io.StringIO() failed\n"); +#endif + /* Get the traceback.print_exception function, and call it. */ + obFuncTB = PyObject_GetAttrString(modTB, "print_tb"); + if (obFuncTB==NULL) + TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n"); + + argsTB = Py_BuildValue("OOO", + exc_tb ? exc_tb : Py_None, + Py_None, + obStringIO); + if (argsTB==NULL) + TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n"); + + obResult = PyObject_CallObject(obFuncTB, argsTB); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n"); + /* Now call the getvalue() method in the StringIO instance */ + Py_DECREF(obFuncStringIO); + obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find getvalue function\n"); + Py_DECREF(obResult); + obResult = PyObject_CallObject(obFuncStringIO, NULL); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("getvalue() failed.\n"); + + /* And it should be a string all ready to go - duplicate it. */ +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(obResult)) +#else + if (!PyUnicode_Check(obResult)) +#endif + TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n"); + + { // a temp scope so I can use temp locals. +#if PY_MAJOR_VERSION <= 2 + char *tempResult = PyString_AsString(obResult); +#else + /* PyUnicode_AsUTF8() is const char * as of Python 3.7, char * earlier. */ + const char *tempResult = (const char *)PyUnicode_AsUTF8(obResult); +#endif + result = (char *)PyMem_Malloc(strlen(tempResult)+1); + if (result==NULL) + TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string\n"); + + strcpy(result, tempResult); + } // end of temp scope. +done: + /* All finished - first see if we encountered an error */ + if (result==NULL && errMsg != NULL) { + result = (char *)PyMem_Malloc(strlen(errMsg)+1); + if (result != NULL) + /* if it does, not much we can do! */ + strcpy(result, errMsg); + } + Py_XDECREF(modStringIO); + Py_XDECREF(modTB); + Py_XDECREF(obFuncStringIO); + Py_XDECREF(obStringIO); + Py_XDECREF(obFuncTB); + Py_XDECREF(argsTB); + Py_XDECREF(obResult); + return result; +} + +// See comments in PyXPCOM.h for why we need this! +void PyXPCOM_MakePendingCalls() +{ + while (1) { + int rc = Py_MakePendingCalls(); + if (rc == 0) + break; + // An exception - just report it as normal. + // Note that a traceback is very unlikely! + PyXPCOM_LogError("Unhandled exception detected before entering Python.\n"); + PyErr_Clear(); + // And loop around again until we are told everything is done! + } +} diff --git a/src/libs/xpcom18a4/python/src/PyGBase.cpp b/src/libs/xpcom18a4/python/src/PyGBase.cpp new file mode 100644 index 00000000..e73b2a6d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGBase.cpp @@ -0,0 +1,852 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// PyGBase.cpp - implementation of the PyG_Base class +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include + +static PRInt32 cGateways = 0; +PRInt32 _PyXPCOM_GetGatewayCount(void) +{ + return cGateways; +} + +extern PyG_Base *MakePyG_nsIModule(PyObject *); +extern PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance); +extern PyG_Base *MakePyG_nsIInputStream(PyObject *instance); + +static char *PyXPCOM_szDefaultGatewayAttributeName = (char*)"_com_instance_default_gateway_"; +PyG_Base *GetDefaultGateway(PyObject *instance); +void AddDefaultGateway(PyObject *instance, nsISupports *gateway); +PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway); + +/*static*/ nsresult +PyG_Base::CreateNew(PyObject *pPyInstance, const nsIID &iid, void **ppResult) +{ + NS_PRECONDITION(ppResult && *ppResult==NULL, "NULL or uninitialized pointer"); + if (ppResult==nsnull) + return NS_ERROR_NULL_POINTER; + + PyG_Base *ret; + // Hack for few extra gateways we support. + if (iid.Equals(NS_GET_IID(nsIModule))) + ret = MakePyG_nsIModule(pPyInstance); + else if (iid.Equals(NS_GET_IID(nsIComponentLoader))) + ret = MakePyG_nsIComponentLoader(pPyInstance); + else if (iid.Equals(NS_GET_IID(nsIInputStream))) + ret = MakePyG_nsIInputStream(pPyInstance); + else + ret = new PyXPCOM_XPTStub(pPyInstance, iid); + if (ret==nsnull) + return NS_ERROR_OUT_OF_MEMORY; + ret->AddRef(); // The first reference for the caller. + *ppResult = ret->ThisAsIID(iid); + NS_ABORT_IF_FALSE(*ppResult != NULL, "ThisAsIID() gave NULL, but we know it supports it!"); + return *ppResult ? NS_OK : NS_ERROR_FAILURE; +} + +PyG_Base::PyG_Base(PyObject *instance, const nsIID &iid) +{ + // Note that "instance" is the _policy_ instance!! + PR_AtomicIncrement(&cGateways); + m_pBaseObject = GetDefaultGateway(instance); + // m_pWeakRef is an nsCOMPtr and needs no init. + + NS_ABORT_IF_FALSE(!(iid.Equals(NS_GET_IID(nsISupportsWeakReference)) || iid.Equals(NS_GET_IID(nsIWeakReference))),"Should not be creating gateways with weak-ref interfaces"); + m_iid = iid; + m_pPyObject = instance; + NS_PRECONDITION(instance, "NULL PyObject for PyXPCOM_XPTStub!"); + +#ifdef NS_BUILD_REFCNT_LOGGING + // If XPCOM reference count logging is enabled, then allow us to give the Python class. + PyObject *realInstance = PyObject_GetAttrString(instance, "_obj_"); + PyObject *r = PyObject_Repr(realInstance); + const char *szRepr; + if (r==NULL) { + PyXPCOM_LogError("Getting the __repr__ of the object failed"); + PyErr_Clear(); + szRepr = "(repr failed!)"; + } + else +#if PY_MAJOR_VERSION <= 2 + szRepr = PyString_AsString(r); +#else + szRepr = PyUnicode_AsUTF8(r); +#endif + if (szRepr==NULL) szRepr = ""; + int reprOffset = *szRepr=='<' ? 1 : 0; + static const char *reprPrefix = "component:"; + if (strncmp(reprPrefix, szRepr+reprOffset, strlen(reprPrefix)) == 0) + reprOffset += strlen(reprPrefix); + strncpy(refcntLogRepr, szRepr + reprOffset, sizeof(refcntLogRepr)-1); + refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0'; + // See if we should get rid of the " at 0x12345" portion. + char *lastPos = strstr(refcntLogRepr, " at "); + if (lastPos) *lastPos = '\0'; + Py_XDECREF(realInstance); + Py_XDECREF(r); +#endif // NS_BUILD_REFCNT_LOGGING + +#ifdef DEBUG_LIFETIMES + { + char *iid_repr; + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + if (iim!=nsnull) + iim->GetNameForIID(&iid, &iid_repr); + PyObject *real_instance = PyObject_GetAttrString(instance, "_obj_"); + PyObject *real_repr = PyObject_Repr(real_instance); + + PYXPCOM_LOG_DEBUG("PyG_Base created at %p\n instance_repr=%s\n IID=%s\n", this, PyString_AsString(real_repr), iid_repr); + nsMemory::Free(iid_repr); + Py_XDECREF(real_instance); + Py_XDECREF(real_repr); + } +#endif // DEBUG_LIFETIMES + Py_XINCREF(instance); // instance should never be NULL - but whats an X between friends! + + PyXPCOM_DLLAddRef(); + +#ifdef DEBUG_FULL + LogF("PyGatewayBase: created %s", m_pPyObject ? PyXPCOM_ObTypeName(m_pPyObject) : ""); +#endif +} + +PyG_Base::~PyG_Base() +{ + PR_AtomicDecrement(&cGateways); +#ifdef DEBUG_LIFETIMES + PYXPCOM_LOG_DEBUG("PyG_Base: deleted %p", this); +#endif + if ( m_pPyObject ) { + CEnterLeavePython celp; + Py_DECREF(m_pPyObject); + } + if (m_pBaseObject) + m_pBaseObject->Release(); + if (m_pWeakRef) { + // Need to ensure some other thread isnt doing a QueryReferent on + // our weak reference at the same time + CEnterLeaveXPCOMFramework _celf; + PyXPCOM_GatewayWeakReference *p = (PyXPCOM_GatewayWeakReference *)(nsISupports *)m_pWeakRef; + p->m_pBase = nsnull; + m_pWeakRef = nsnull; + } + PyXPCOM_DLLRelease(); +} + +// Get the correct interface pointer for this object given the IID. +void *PyG_Base::ThisAsIID( const nsIID &iid ) +{ + if (this==NULL) return NULL; + if (iid.Equals(NS_GET_IID(nsISupports))) + return (nsISupports *)(nsIInternalPython *)this; + if (iid.Equals(NS_GET_IID(nsISupportsWeakReference))) + return (nsISupportsWeakReference *)this; + if (iid.Equals(NS_GET_IID(nsIInternalPython))) + return (nsISupports *)(nsIInternalPython *)this; + return NULL; +} + +// Call back into Python, passing a Python instance, and get back +// an interface object that wraps the instance. +/*static*/ PRBool +PyG_Base::AutoWrapPythonInstance(PyObject *ob, const nsIID &iid, nsISupports **ppret) +{ + NS_PRECONDITION(ppret!=NULL, "null pointer when wrapping a Python instance!"); + NS_PRECONDITION(ob && PyObject_HasAttrString(ob, "__class__"), + "AutoWrapPythonInstance is expecting an non-NULL instance!"); + PRBool ok = PR_FALSE; + // XXX - todo - this static object leaks! (but Python on Windows leaks 2000+ objects as it is ;-) + static PyObject *func = NULL; // fetch this once and remember! + PyObject *obIID = NULL; + PyObject *wrap_ret = NULL; + PyObject *args = NULL; + if (func==NULL) { // not thread-safe, but nothing bad can happen, except an extra reference leak + PyObject *mod = PyImport_ImportModule("xpcom.server"); + if (mod) + func = PyObject_GetAttrString(mod, "WrapObject"); + Py_XDECREF(mod); + if (func==NULL) goto done; + } + // See if the instance has previously been wrapped. + if (CheckDefaultGateway(ob, iid, ppret)) { + ok = PR_TRUE; // life is good! + } else { + PyErr_Clear(); + + obIID = Py_nsIID::PyObjectFromIID(iid); + if (obIID==NULL) goto done; + args = Py_BuildValue("OOzi", ob, obIID, NULL, 0); + if (args==NULL) goto done; + wrap_ret = PyEval_CallObject(func, args); + if (wrap_ret==NULL) goto done; + ok = Py_nsISupports::InterfaceFromPyObject(wrap_ret, iid, ppret, PR_FALSE, PR_FALSE); +#ifdef DEBUG + if (ok) + // Check we _now_ have a default gateway + { + nsISupports *temp = NULL; + NS_ABORT_IF_FALSE(CheckDefaultGateway(ob, iid, &temp), "Auto-wrapped object didnt get a default gateway!"); + if (temp) temp->Release(); + } +#endif + } +done: +// Py_XDECREF(func); -- func is static for performance reasons. + Py_XDECREF(obIID); + Py_XDECREF(wrap_ret); + Py_XDECREF(args); + return ok; +} + +// Call back into Python, passing a raw nsIInterface object, getting back +// the object to actually use as the gateway parameter for this interface. +// For example, it is expected that the policy will wrap the interface +// object in one of the xpcom.client.Interface objects, allowing +// natural usage of the interface from Python clients. +// Note that piid will usually be NULL - this is because the runtime +// reflection interfaces dont provide this information to me. +// In this case, the Python code may choose to lookup the complete +// interface info to obtain the IID. +// It is expected (but should not be assumed) that the method info +// or the IID will be NULL. +// Worst case, the code should provide a wrapper for the nsiSupports interface, +// so at least the user can simply QI the object. +PyObject * +PyG_Base::MakeInterfaceParam(nsISupports *pis, + const nsIID *piid, + int methodIndex /* = -1 */, + const XPTParamDescriptor *d /* = NULL */, + int paramIndex /* = -1 */) +{ + if (pis==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + // This condition is true today, but not necessarily so. + // But if it ever triggers, the poor Python code has no real hope + // of returning something useful, so we should at least do our + // best to provide the useful data. + NS_WARN_IF_FALSE( ((piid != NULL) ^ (d != NULL)) == 1, "No information on the interface available - Python's gunna have a hard time doing much with it!"); + PyObject *obIID = NULL; + PyObject *obISupports = NULL; + PyObject *obParamDesc = NULL; + PyObject *result = NULL; + + // get the basic interface first, as if we fail, we can try and use this. + // If we don't know the IID, we must explicitly query for nsISupports. + nsCOMPtr piswrap; + nsIID iid_check; + if (piid) { + iid_check = *piid; + piswrap = pis; + } else { + /* HACK ALERT! Dropping the python interpreter lock here while + doing QueryInterface because it may involve IPC to a python + object in the same interpreter and deadlock. Not at all + sure if this is a good idea or not for the internal PyXPCOM + state, but it might fix the deadloock... Hoping for the best. */ + Py_BEGIN_ALLOW_THREADS; + iid_check = NS_GET_IID(nsISupports); + pis->QueryInterface(iid_check, getter_AddRefs(piswrap)); + Py_END_ALLOW_THREADS; + } + + obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE); + if (!obISupports) + goto done; + if (piid==NULL) { + obIID = Py_None; + Py_INCREF(Py_None); + } else + obIID = Py_nsIID::PyObjectFromIID(*piid); + if (obIID==NULL) + goto done; + obParamDesc = PyObject_FromXPTParamDescriptor(d); + if (obParamDesc==NULL) + goto done; + + result = PyObject_CallMethod(m_pPyObject, + (char*)"_MakeInterfaceParam_", + (char*)"OOiOi", + obISupports, + obIID, + methodIndex, + obParamDesc, + paramIndex); +done: + if (PyErr_Occurred()) { + NS_WARN_IF_FALSE(result==NULL, "Have an error, but also a result!"); + PyXPCOM_LogError("Wrapping an interface object for the gateway failed\n"); + } + Py_XDECREF(obIID); + Py_XDECREF(obParamDesc); + if (result==NULL) { // we had an error. + PyErr_Clear(); // but are not reporting it back to Python itself! + // return our obISupports. If NULL, we are really hosed and nothing we can do. + return obISupports; + } + // Dont need to return this - we have a better result. + Py_XDECREF(obISupports); + return result; +} + +NS_IMETHODIMP +PyG_Base::QueryInterface(REFNSIID iid, void** ppv) +{ +#ifdef PYXPCOM_DEBUG_FULL + { + char *sziid = iid.ToString(); + LogF("PyGatewayBase::QueryInterface: %s", sziid); + Allocator::Free(sziid); + } +#endif + NS_PRECONDITION(ppv, "NULL pointer"); + if (ppv==nsnull) + return NS_ERROR_NULL_POINTER; + *ppv = nsnull; + // If one of our native interfaces (but NOT nsISupports if we have a base) + // return this. + // It is important is that nsISupports come from the base object + // to ensure that we live by XPCOM identity rules (other interfaces need + // not abide by this rule - only nsISupports.) + if ( (m_pBaseObject==NULL || !iid.Equals(NS_GET_IID(nsISupports))) + && (*ppv=ThisAsIID(iid)) != NULL ) { + AddRef(); + return NS_OK; + } + // If we have a "base object", then we need to delegate _every_ remaining + // QI to it. + if (m_pBaseObject != NULL) + return m_pBaseObject->QueryInterface(iid, ppv); + + // Call the Python policy to see if it (says it) supports the interface + PRBool supports = PR_FALSE; + { // temp scope for Python lock + CEnterLeavePython celp; + + PyObject * ob = Py_nsIID::PyObjectFromIID(iid); + // must say this is an 'internal' call, else we recurse QI into + // oblivion. + PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface( + (nsXPTCStubBase *)this, + iid, PR_FALSE, PR_TRUE); + if ( !ob || !this_interface_ob) { + Py_XDECREF(ob); + Py_XDECREF(this_interface_ob); + return NS_ERROR_OUT_OF_MEMORY; + } + + PyObject *result = PyObject_CallMethod(m_pPyObject, (char*)"_QueryInterface_", + (char*)"OO", + this_interface_ob, ob); + Py_DECREF(ob); + Py_DECREF(this_interface_ob); + + if ( result ) { + if (Py_nsISupports::InterfaceFromPyObject(result, iid, (nsISupports **)ppv, PR_TRUE)) { + // If OK, but NULL, _QI_ returned None, which simply means + // "no such interface" + supports = (*ppv!=NULL); + // result has been QI'd and AddRef'd all ready for return. + } else { + // Dump this message and any Python exception before + // reporting the fact that QI failed - this error + // may provide clues! + PyXPCOM_LogError("The _QueryInterface_ method returned an object of type '%s', but an interface was expected\n", PyXPCOM_ObTypeName(result)); + // supports remains false + } + Py_DECREF(result); + } else { + NS_ABORT_IF_FALSE(PyErr_Occurred(), "Got NULL result, but no Python error flagged!"); + NS_WARN_IF_FALSE(!supports, "Have failure with success flag set!"); + PyXPCOM_LogError("The _QueryInterface_ processing failed.\n"); + // supports remains false. + // We have reported the error, and are returning to COM, + // so we should clear it. + PyErr_Clear(); + } + } // end of temp scope for Python lock - lock released here! + if ( !supports ) + return NS_ERROR_NO_INTERFACE; + return NS_OK; +} + +nsrefcnt +PyG_Base::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + // If we have no pBaseObject, then we need to ignore them + if (m_pBaseObject == NULL) + NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this)); +#endif + return cnt; +} + +nsrefcnt +PyG_Base::Release(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + if (m_pBaseObject == NULL) + NS_LOG_RELEASE(this, cnt, refcntLogRepr); +#endif + if ( cnt == 0 ) + delete this; + return cnt; +} + +NS_IMETHODIMP +PyG_Base::GetWeakReference(nsIWeakReference **ret) +{ + // always delegate back to the "base" gateway for the object, as this tear-off + // interface may not live as long as the base. So we recurse back to the base. + if (m_pBaseObject) { + NS_PRECONDITION(m_pWeakRef == nsnull, "Not a base object, but do have a weak-ref!"); + return m_pBaseObject->GetWeakReference(ret); + } + NS_PRECONDITION(ret, "null pointer"); + if (ret==nsnull) return NS_ERROR_INVALID_POINTER; + if (!m_pWeakRef) { + // First query for a weak reference - create it. + // XXX - this looks like it needs thread safety!? + m_pWeakRef = new PyXPCOM_GatewayWeakReference(this); + NS_ABORT_IF_FALSE(m_pWeakRef, "Shouldn't be able to fail creating a weak reference!"); + if (!m_pWeakRef) + return NS_ERROR_UNEXPECTED; + } + *ret = m_pWeakRef; + (*ret)->AddRef(); + return NS_OK; +} + +nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName) +{ + nsresult rc = NS_OK; + if (PyErr_Occurred()) { + // The error handling - fairly involved, but worth it as + // good error reporting is critical for users to know WTF + // is going on - especially with TypeErrors etc in their + // return values (ie, after the Python code has successfully + // exited, but we encountered errors unpacking their + // result values for the COM caller - there is literally no + // way to catch these exceptions from Python code, as their + // is no Python function directly on the call-stack) + + // First line of attack in an error is to call-back on the policy. + // If the callback of the error handler succeeds and returns an + // integer (for the nsresult), we take no further action. + + // If this callback fails, we log _2_ exceptions - the error + // handler error, and the original error. + + PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing! + PyObject *exc_typ, *exc_val, *exc_tb; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); + + PyObject *err_result = PyObject_CallMethod(m_pPyObject, + (char*)"_GatewayException_", + (char*)"z(OOO)", + szMethodName, + exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming... + exc_val ? exc_val : Py_None, // may well be NULL. + exc_tb ? exc_tb : Py_None); // may well be NULL. + if (err_result == NULL) { + PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n"); + } else if (err_result == Py_None) { + // The exception handler has chosen not to do anything with + // this error, so we still need to print it! + ; + } else if (PyInt_Check(err_result)) { + // The exception handler has given us the nresult. + rc = PyInt_AsLong(err_result); + bProcessMainError = PR_FALSE; + } else { + // The exception handler succeeded, but returned other than + // int or None. + PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", PyXPCOM_ObTypeName(err_result)); + } + Py_XDECREF(err_result); + PyErr_Restore(exc_typ, exc_val, exc_tb); + if (bProcessMainError) { + PyXPCOM_LogError("The function '%s' failed\n", szMethodName); + rc = PyXPCOM_SetCOMErrorFromPyException(); + } + PyErr_Clear(); + } + return rc; +} + +static nsresult do_dispatch( + PyObject *pPyObject, + PyObject **ppResult, + const char *szMethodName, + const char *szFormat, + va_list va + ) +{ + NS_PRECONDITION(ppResult, "Must provide a result buffer"); + *ppResult = nsnull; + // Build the Invoke arguments... + PyObject *args = NULL; + PyObject *method = NULL; + PyObject *real_ob = NULL; + nsresult ret = NS_ERROR_FAILURE; + if ( szFormat ) + args = Py_VaBuildValue((char *)szFormat, va); + else + args = PyTuple_New(0); + if ( !args ) + goto done; + + // make sure a tuple. + if ( !PyTuple_Check(args) ) { + PyObject *a = PyTuple_New(1); + if ( a == NULL ) + { + Py_DECREF(args); + goto done; + } + PyTuple_SET_ITEM(a, 0, args); + args = a; + } + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + goto done; + } + method = PyObject_GetAttrString(real_ob, (char *)szMethodName); + if ( !method ) { + PyErr_Clear(); + ret = NS_PYXPCOM_NO_SUCH_METHOD; + goto done; + } + // Make the call + *ppResult = PyEval_CallObject(method, args); + ret = *ppResult ? NS_OK : NS_ERROR_FAILURE; +done: + Py_XDECREF(method); + Py_XDECREF(real_ob); + Py_XDECREF(args); + return ret; +} + + +nsresult PyG_Base::InvokeNativeViaPolicyInternal( + const char *szMethodName, + PyObject **ppResult, + const char *szFormat, + va_list va + ) +{ + if ( m_pPyObject == NULL || szMethodName == NULL ) + return NS_ERROR_NULL_POINTER; + + PyObject *temp = nsnull; + if (ppResult == nsnull) + ppResult = &temp; + nsresult nr = do_dispatch(m_pPyObject, ppResult, szMethodName, szFormat, va); + + // If temp is NULL, they provided a buffer, and we dont touch it. + // If not NULL, *ppResult = temp, and _we_ do own it. + Py_XDECREF(temp); + return nr; +} + +nsresult PyG_Base::InvokeNativeViaPolicy( + const char *szMethodName, + PyObject **ppResult /* = NULL */, + const char *szFormat /* = NULL */, + ... + ) +{ + va_list va; + va_start(va, szFormat); + nsresult nr = InvokeNativeViaPolicyInternal(szMethodName, ppResult, szFormat, va); + va_end(va); + + if (nr == NS_PYXPCOM_NO_SUCH_METHOD) { + // Only problem was missing method. + PyErr_Format(PyExc_AttributeError, "The object does not have a '%s' function.", szMethodName); + } + return nr == NS_OK ? NS_OK : HandleNativeGatewayError(szMethodName); +} + +nsresult PyG_Base::InvokeNativeGetViaPolicy( + const char *szPropertyName, + PyObject **ppResult /* = NULL */ + ) +{ + PyObject *ob_ret = NULL; + nsresult ret = NS_OK; + PyObject *real_ob = NULL; + if ( m_pPyObject == NULL || szPropertyName == NULL ) + return NS_ERROR_NULL_POINTER; + // First see if we have a method of that name. + char buf[256]; + strcpy(buf, "get_"); + strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1); + buf[sizeof(buf)/sizeof(buf[0])-1] = '\0'; + ret = InvokeNativeViaPolicyInternal(buf, ppResult, nsnull, nsnull); + if (ret == NS_PYXPCOM_NO_SUCH_METHOD) { + // No method of that name - just try a property. + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + ret = HandleNativeGatewayError(szPropertyName); + goto done; + } + ob_ret = PyObject_GetAttrString(real_ob, (char *)szPropertyName); + if (ob_ret==NULL) { + PyErr_Format(PyExc_AttributeError, + "The object does not have a 'get_%s' function, or a '%s attribute.", + szPropertyName, szPropertyName); + } else { + ret = NS_OK; + if (ppResult) + *ppResult = ob_ret; + else + Py_XDECREF(ob_ret); + } + } + if (ret != NS_OK) + ret = HandleNativeGatewayError(szPropertyName); + +done: + Py_XDECREF(real_ob); + return ret; +} + +nsresult PyG_Base::InvokeNativeSetViaPolicy( + const char *szPropertyName, + ... + ) +{ + if ( m_pPyObject == NULL || szPropertyName == NULL ) + return NS_ERROR_NULL_POINTER; + nsresult ret = NS_OK; + PyObject *real_ob = NULL; + char buf[256]; + strcpy(buf, "set_"); + strncat(buf, szPropertyName, sizeof(buf)*sizeof(buf[0])-strlen(buf)-1); + buf[sizeof(buf)/sizeof(buf[0])-1] = '\0'; + va_list va; + va_start(va, szPropertyName); + ret = InvokeNativeViaPolicyInternal(buf, NULL, "O", va); + va_end(va); + if (ret == NS_PYXPCOM_NO_SUCH_METHOD) { + // No method of that name - just try a property. + // Bit to a hack here to maintain the use of a policy. + // We actually get the policies underlying object + // to make the call on. + real_ob = PyObject_GetAttrString(m_pPyObject, "_obj_"); + if (real_ob == NULL) { + PyErr_Format(PyExc_AttributeError, "The policy object does not have an '_obj_' attribute."); + ret = HandleNativeGatewayError(szPropertyName); + goto done; + } + va_list va2; + va_start(va2, szPropertyName); + PyObject *arg = va_arg( va2, PyObject *); + va_end(va2); + if (PyObject_SetAttrString(real_ob, (char *)szPropertyName, arg) == 0) + ret = NS_OK; + else { + PyErr_Format(PyExc_AttributeError, + "The object does not have a 'set_%s' function, or a '%s attribute.", + szPropertyName, szPropertyName); + } + } + if (ret != NS_OK) + ret = HandleNativeGatewayError(szPropertyName); +done: + Py_XDECREF(real_ob); + return ret; +} + +// Get at the underlying Python object. +PyObject *PyG_Base::UnwrapPythonObject(void) +{ + Py_INCREF(m_pPyObject); + return m_pPyObject; +} +/****************************************************** + + Some special support to help with object identity. + + In the simplest case, assume a Python XPCOM object is + supporting a function "nsIWhatever GetWhatever()", + so implements it as: + return self + it is almost certain they intend returning + the same COM OBJECT to the caller! Thus, if a user of this COM + object does: + + p1 = foo.GetWhatever(); + p2 = foo.GetWhatever(); + + We almost certainly expect p1==p2==foo. + + We previously _did_ have special support for the "self" + example above, but this implements a generic scheme that + works for _all_ objects. + + Whenever we are asked to "AutoWrap" a Python object, the + first thing we do is see if it has been auto-wrapped before. + + If not, we create a new wrapper, then make a COM weak reference + to that wrapper, and store it directly back into the instance + we are auto-wrapping! The use of a weak-reference prevents + cycles. + + The existance of this attribute in an instance indicates if it + has been previously auto-wrapped. + + If it _has_ previously been auto-wrapped, we de-reference the + weak reference, and use that gateway. + +*********************************************************************/ + +PyG_Base *GetDefaultGateway(PyObject *policy) +{ + // NOTE: Instance is the policy, not the real instance + PyObject *instance = PyObject_GetAttrString(policy, "_obj_"); + if (instance == nsnull) + return nsnull; + PyObject *ob_existing_weak = PyObject_GetAttrString(instance, PyXPCOM_szDefaultGatewayAttributeName); + Py_DECREF(instance); + if (ob_existing_weak != NULL) { + PRBool ok = PR_TRUE; + nsCOMPtr pWeakRef; + ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak, + NS_GET_IID(nsIWeakReference), + getter_AddRefs(pWeakRef), + PR_FALSE)); + Py_DECREF(ob_existing_weak); + nsISupports *pip; + if (ok) { + nsresult nr = pWeakRef->QueryReferent( NS_GET_IID(nsIInternalPython), (void **)&pip); + if (NS_FAILED(nr)) + return nsnull; + return (PyG_Base *)(nsIInternalPython *)pip; + } + } else + PyErr_Clear(); + return nsnull; +} + +PRBool CheckDefaultGateway(PyObject *real_inst, REFNSIID iid, nsISupports **ret_gateway) +{ + NS_ABORT_IF_FALSE(real_inst, "Did not have an _obj_ attribute"); + if (real_inst==NULL) { + PyErr_Clear(); + return PR_FALSE; + } + PyObject *ob_existing_weak = PyObject_GetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName); + if (ob_existing_weak != NULL) { + // We have an existing default, but as it is a weak reference, it + // may no longer be valid. Check it. + PRBool ok = PR_TRUE; + nsCOMPtr pWeakRef; + ok = NS_SUCCEEDED(Py_nsISupports::InterfaceFromPyObject(ob_existing_weak, + NS_GET_IID(nsIWeakReference), + getter_AddRefs(pWeakRef), + PR_FALSE)); + Py_DECREF(ob_existing_weak); + if (ok) { + Py_BEGIN_ALLOW_THREADS; + ok = NS_SUCCEEDED(pWeakRef->QueryReferent( iid, (void **)(ret_gateway))); + Py_END_ALLOW_THREADS; + } + if (!ok) { + // We have the attribute, but not valid - wipe it + // before restoring it. + if (0 != PyObject_DelAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) + PyErr_Clear(); + } + return ok; + } + PyErr_Clear(); + return PR_FALSE; +} + +void AddDefaultGateway(PyObject *instance, nsISupports *gateway) +{ + // NOTE: Instance is the _policy_! + PyObject *real_inst = PyObject_GetAttrString(instance, "_obj_"); + NS_ABORT_IF_FALSE(real_inst, "Could not get the '_obj_' element"); + if (!real_inst) return; + if (!PyObject_HasAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName)) { + nsCOMPtr swr( do_QueryInterface((nsISupportsWeakReference *)(gateway)) ); + NS_ABORT_IF_FALSE(swr, "Our gateway failed with a weak reference query"); + // Create the new default gateway - get a weak reference for our gateway. + if (swr) { + nsCOMPtr pWeakReference; + swr->GetWeakReference( getter_AddRefs(pWeakReference) ); + if (pWeakReference) { + PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference, + NS_GET_IID(nsIWeakReference), + PR_FALSE ); /* bMakeNicePyObject */ + // pWeakReference reference consumed. + if (ob_new_weak) { + PyObject_SetAttrString(real_inst, PyXPCOM_szDefaultGatewayAttributeName, ob_new_weak); + Py_DECREF(ob_new_weak); + } + } + } + } + Py_DECREF(real_inst); +} diff --git a/src/libs/xpcom18a4/python/src/PyGInputStream.cpp b/src/libs/xpcom18a4/python/src/PyGInputStream.cpp new file mode 100644 index 00000000..d7c27043 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGInputStream.cpp @@ -0,0 +1,173 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// PyGInputStream.cpp +// +// This code is part of the XPCOM extensions for Python. +// +// Written October 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +class PyG_nsIInputStream : public PyG_Base, public nsIInputStream +{ +public: + PyG_nsIInputStream(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIInputStream)) {;} + PYGATEWAY_BASE_SUPPORT(nsIInputStream, PyG_Base); + + NS_IMETHOD Close(void); + NS_IMETHOD Available(PRUint32 *_retval); + NS_IMETHOD Read(char * buf, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD IsNonBlocking(PRBool *aNonBlocking); +}; + + +PyG_Base *MakePyG_nsIInputStream(PyObject *instance) +{ + return new PyG_nsIInputStream(instance); +} + +NS_IMETHODIMP +PyG_nsIInputStream::Close() +{ + CEnterLeavePython _celp; + const char *methodName = "close"; + return InvokeNativeViaPolicy(methodName, NULL); +} + +NS_IMETHODIMP +PyG_nsIInputStream::Available(PRUint32 *_retval) +{ + NS_PRECONDITION(_retval, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "available"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + Py_XDECREF(ret); + } + return nr; +} + +NS_IMETHODIMP +PyG_nsIInputStream::Read(char * buf, PRUint32 count, PRUint32 *_retval) +{ + NS_PRECONDITION(_retval, "null pointer"); + NS_PRECONDITION(buf, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "read"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", count); + if (NS_SUCCEEDED(nr)) { +#if 0 /* VBox: new buffer protocol (though I could use it for Py_LIMITED_API and ditch the warning, but cpython specific) */ + Py_buffer py_view; + if (PyObject_GetBuffer(ret, &py_view, PyBUF_SIMPLE) == 0) { + if (py_view.len <= count) { + count = py_view.len; + } else { + PyXPCOM_LogWarning("nsIInputStream::read() was asked for %d bytes, but the string returned is %d bytes - truncating!\n", count, py_size); + } + memcpy(buf, py_view.py_buf, count); + PyBuffer_Release(&py_view); + *_retval = count; + } else { + PyErr_Format(PyExc_TypeError, "nsIInputStream::read() method must return a buffer object - not a '%s' object", PyXPCOM_ObTypeName(ret)); + nr = HandleNativeGatewayError(methodName); + } +#else /* Old protocol: */ +# ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 py_size; + const void *py_buf; + if (PyObject_AsReadBuffer(ret, &py_buf, (Py_ssize_t*)&py_size)!=0) { +# else /* VBOX */ + const void *py_buf; +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t py_size; +# else + int py_size; +# endif + if (PyObject_AsReadBuffer(ret, &py_buf, &py_size)!=0) { +# endif /* VBOX */ + PyErr_Format(PyExc_TypeError, "nsIInputStream::read() method must return a buffer object - not a '%s' object", PyXPCOM_ObTypeName(ret)); + nr = HandleNativeGatewayError(methodName); + } else { + if (py_size > count) { + PyXPCOM_LogWarning("nsIInputStream::read() was asked for %d bytes, but the string returned is %d bytes - truncating!\n", count, py_size); + py_size = count; + } + memcpy(buf, py_buf, py_size); + *_retval = py_size; + } +#endif + } + return nr; +} + + +NS_IMETHODIMP +PyG_nsIInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_WARNING("ReadSegments() not implemented!!!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +PyG_nsIInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + NS_PRECONDITION(aNonBlocking, "null pointer"); + CEnterLeavePython _celp; + PyObject *ret; + const char *methodName = "isNonBlocking"; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret); + if (NS_SUCCEEDED(nr)) { + *aNonBlocking = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + Py_XDECREF(ret); + } + return nr; +} diff --git a/src/libs/xpcom18a4/python/src/PyGModule.cpp b/src/libs/xpcom18a4/python/src/PyGModule.cpp new file mode 100644 index 00000000..599e0f87 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGModule.cpp @@ -0,0 +1,297 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +// Unfortunately, we can not use an XPConnect object for +// the nsiModule and nsiComponentLoader interfaces. +// As XPCOM shuts down, it shuts down the interface manager before +// it releases all the modules. This is a bit of a problem for +// us, as it means we can't get runtime info on the interface at shutdown time. + +#include "PyXPCOM_std.h" +#include +#include + +class PyG_nsIModule : public PyG_Base, public nsIModule +{ +public: + PyG_nsIModule(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIModule)) {;} + PYGATEWAY_BASE_SUPPORT(nsIModule, PyG_Base); + + NS_DECL_NSIMODULE +}; + +PyG_Base *MakePyG_nsIModule(PyObject *instance) +{ + return new PyG_nsIModule(instance); +} + + +// Create a factory object for creating instances of aClass. +NS_IMETHODIMP +PyG_nsIModule::GetClassObject(nsIComponentManager *aCompMgr, + const nsCID& aClass, + const nsIID& aIID, + void** r_classObj) +{ + NS_PRECONDITION(r_classObj, "null pointer"); + *r_classObj = nsnull; + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *iid = Py_nsIID::PyObjectFromIID(aIID); + PyObject *clsid = Py_nsIID::PyObjectFromIID(aClass); + const char *methodName = "getClassObject"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "OOO", cm, clsid, iid); + Py_XDECREF(cm); + Py_XDECREF(iid); + Py_XDECREF(clsid); + if (NS_SUCCEEDED(nr)) { + nr = Py_nsISupports::InterfaceFromPyObject(ret, aIID, (nsISupports **)r_classObj, PR_FALSE); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + if (NS_FAILED(nr)) { + NS_ABORT_IF_FALSE(*r_classObj==NULL, "returning error result with an interface - probable leak!"); + } + Py_XDECREF(ret); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::RegisterSelf(nsIComponentManager *aCompMgr, + nsIFile* aPath, + const char* registryLocation, + const char* componentType) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(aPath, "null pointer"); + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); + const char *methodName = "registerSelf"; + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOzz", cm, path, registryLocation, componentType); + Py_XDECREF(cm); + Py_XDECREF(path); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::UnregisterSelf(nsIComponentManager* aCompMgr, + nsIFile* aPath, + const char* registryLocation) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(aPath, "null pointer"); + CEnterLeavePython _celp; + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); + const char *methodName = "unregisterSelf"; + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOz", cm, path, registryLocation); + Py_XDECREF(cm); + Py_XDECREF(path); + return nr; +} + +NS_IMETHODIMP +PyG_nsIModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) +{ + NS_PRECONDITION(aCompMgr, "null pointer"); + NS_PRECONDITION(okToUnload, "null pointer"); + CEnterLeavePython _celp; + // we are shutting down - don't ask for a nice wrapped object. + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_FALSE); + const char *methodName = "canUnload"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "O", cm); + Py_XDECREF(cm); + if (NS_SUCCEEDED(nr)) { + *okToUnload = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/////////////////////////////////////////////////////////////////////////////////// + +class PyG_nsIComponentLoader : public PyG_Base, public nsIComponentLoader +{ +public: + PyG_nsIComponentLoader(PyObject *instance) : PyG_Base(instance, NS_GET_IID(nsIComponentLoader)) {;} + PYGATEWAY_BASE_SUPPORT(nsIComponentLoader, PyG_Base); + + NS_DECL_NSICOMPONENTLOADER +}; + +PyG_Base *MakePyG_nsIComponentLoader(PyObject *instance) +{ + return new PyG_nsIComponentLoader(instance); +} + +/* nsIFactory getFactory (in nsIIDRef aCID, in string aLocation, in string aType); */ +NS_IMETHODIMP PyG_nsIComponentLoader::GetFactory(const nsIID & aCID, const char *aLocation, const char *aType, nsIFactory **_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "getFactory"; + PyObject *iid = Py_nsIID::PyObjectFromIID(aCID); + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "Ozz", + iid, + aLocation, + aType); + Py_XDECREF(iid); + if (NS_SUCCEEDED(nr)) { + Py_nsISupports::InterfaceFromPyObject(ret, NS_GET_IID(nsIFactory), (nsISupports **)_retval, PR_FALSE); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* void init (in nsIComponentManager aCompMgr, in nsISupports aRegistry); */ +NS_IMETHODIMP PyG_nsIComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aRegistry) +{ + CEnterLeavePython _celp; + const char *methodName = "init"; + PyObject *c = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *r = PyObject_FromNSInterface(aRegistry, NS_GET_IID(nsISupports)); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OO", c, r); + Py_XDECREF(c); + Py_XDECREF(r); + return nr; +} + +/* void onRegister (in nsIIDRef aCID, in string aType, in string aClassName, in string aContractID, in string aLocation, in boolean aReplace, in boolean aPersist); */ +NS_IMETHODIMP PyG_nsIComponentLoader::OnRegister(const nsIID & aCID, const char *aType, const char *aClassName, const char *aContractID, const char *aLocation, PRBool aReplace, PRBool aPersist) +{ + CEnterLeavePython _celp; + const char *methodName = "onRegister"; + PyObject *iid = Py_nsIID::PyObjectFromIID(aCID); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "Ossssii", + iid, + aType, + aClassName, + aContractID, + aLocation, + aReplace, + aPersist); + Py_XDECREF(iid); + return nr; +} + +/* void autoRegisterComponents (in long aWhen, in nsIFile aDirectory); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponents(PRInt32 aWhen, nsIFile *aDirectory) +{ + CEnterLeavePython _celp; + const char *methodName = "autoRegisterComponents"; + PyObject *c = PyObject_FromNSInterface(aDirectory, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "iO", aWhen, c); + Py_XDECREF(c); + return nr; +} + +/* boolean autoRegisterComponent (in long aWhen, in nsIFile aComponent); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoRegisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "autoRegisterComponent"; + PyObject *ret = NULL; + PyObject *c = PyObject_FromNSInterface(aComponent, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c); + Py_XDECREF(c); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* boolean autoUnregisterComponent (in long aWhen, in nsIFile aComponent); */ +NS_IMETHODIMP PyG_nsIComponentLoader::AutoUnregisterComponent(PRInt32 aWhen, nsIFile *aComponent, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "autoUnregisterComponent"; + PyObject *ret = NULL; + PyObject *c = PyObject_FromNSInterface(aComponent, NS_GET_IID(nsIFile)); + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "iO", aWhen, c); + Py_XDECREF(c); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* boolean registerDeferredComponents (in long aWhen); */ +NS_IMETHODIMP PyG_nsIComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, PRBool *_retval) +{ + CEnterLeavePython _celp; + const char *methodName = "registerDeferredComponents"; + PyObject *ret = NULL; + nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "i", aWhen); + if (NS_SUCCEEDED(nr)) { + *_retval = PyInt_AsLong(ret); + if (PyErr_Occurred()) + nr = HandleNativeGatewayError(methodName); + } + Py_XDECREF(ret); + return nr; +} + +/* void unloadAll (in long aWhen); */ +NS_IMETHODIMP PyG_nsIComponentLoader::UnloadAll(PRInt32 aWhen) +{ + CEnterLeavePython _celp; + const char *methodName = "unloadAll"; + return InvokeNativeViaPolicy(methodName, NULL, "i", aWhen); +} diff --git a/src/libs/xpcom18a4/python/src/PyGStub.cpp b/src/libs/xpcom18a4/python/src/PyGStub.cpp new file mode 100644 index 00000000..6f219333 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGStub.cpp @@ -0,0 +1,180 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// PyXPTStub - the stub for implementing interfaces. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +void *PyXPCOM_XPTStub::ThisAsIID(const nsIID &iid) +{ + if (iid.Equals(NS_GET_IID(nsISupports))) + return (nsISupports *)(nsXPTCStubBase *)this; + else if (iid.Equals(m_iid)) + return (nsISupports *)(nsXPTCStubBase *)this; + else + return PyG_Base::ThisAsIID(iid); +} + + +NS_IMETHODIMP +PyXPCOM_XPTStub::GetInterfaceInfo(nsIInterfaceInfo** info) +{ + NS_PRECONDITION(info, "NULL pointer"); + if (info==nsnull) + return NS_ERROR_NULL_POINTER; + // Simply get the XPCOM runtime to provide this + // (but there must be some reason why they dont get it themselves!? + // Maybe because they dont know the IID? + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!"); + if (iim==nsnull) + return NS_ERROR_FAILURE; + + return iim->GetInfoForIID( &m_iid, info); +} + +// call this method and return result +NS_IMETHODIMP +PyXPCOM_XPTStub::CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) +{ + nsresult rc = NS_ERROR_FAILURE; + NS_PRECONDITION(info, "NULL methodinfo pointer"); + NS_PRECONDITION(params, "NULL variant pointer"); + CEnterLeavePython _celp; + PyObject *obParams = NULL; + PyObject *result = NULL; + PyObject *obThisObject = NULL; + PyObject *obMI = PyObject_FromXPTMethodDescriptor(info); + PyXPCOM_GatewayVariantHelper arg_helper(this, methodIndex, info, params); + if (obMI==NULL) + goto done; + // base object is passed raw. + obThisObject = PyObject_FromNSInterface((nsXPTCStubBase *)this, + m_iid, PR_FALSE); + obParams = arg_helper.MakePyArgs(); + if (obParams==NULL) + goto done; + result = PyObject_CallMethod(m_pPyObject, + (char*)"_CallMethod_", + (char*)"OiOO", + obThisObject, + (int)methodIndex, + obMI, + obParams); + if (result!=NULL) { + rc = arg_helper.ProcessPythonResult(result); + // Use an xor to check failure && pyerr, or !failure && !pyerr. + NS_ABORT_IF_FALSE( ((NS_FAILED(rc)!=0)^(PyErr_Occurred()!=0)) == 0, "We must have failure with a Python error, or success without a Python error."); + } +done: + if (PyErr_Occurred()) { + // The error handling - fairly involved, but worth it as + // good error reporting is critical for users to know WTF + // is going on - especially with TypeErrors etc in their + // return values (ie, after the Python code has successfully + // exited, but we encountered errors unpacking the + // result values for the COM caller - there is literally no + // way to catch these exceptions from Python code, as their + // is no Python function on the call-stack) + + // First line of attack in an error is to call-back on the policy. + // If the callback of the error handler succeeds and returns an + // integer (for the nsresult), we take no further action. + + // If this callback fails, we log _2_ exceptions - the error handler + // error, and the original error. + + PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing! + PyObject *exc_typ, *exc_val, *exc_tb; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); + PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); + + PyObject *err_result = PyObject_CallMethod(m_pPyObject, + (char*)"_CallMethodException_", + (char*)"OiOO(OOO)", + obThisObject, + (int)methodIndex, + obMI, + obParams, + exc_typ ? exc_typ : Py_None, // should never be NULL, but defensive programming... + exc_val ? exc_val : Py_None, // may well be NULL. + exc_tb ? exc_tb : Py_None); // may well be NULL. + if (err_result == NULL) { + PyXPCOM_LogError("The exception handler _CallMethodException_ failed!\n"); + } else if (err_result == Py_None) { + // The exception handler has chosen not to do anything with + // this error, so we still need to print it! + ; + } else if (PyInt_Check(err_result)) { + // The exception handler has given us the nresult. + rc = PyInt_AsLong(err_result); + bProcessMainError = PR_FALSE; + } else { + // The exception handler succeeded, but returned other than + // int or None. + PyXPCOM_LogError("The _CallMethodException_ handler returned object of type '%s' - None or an integer expected\n", PyXPCOM_ObTypeName(err_result)); + } + Py_XDECREF(err_result); + PyErr_Restore(exc_typ, exc_val, exc_tb); + if (bProcessMainError) { + PyXPCOM_LogError("The function '%s' failed\n", info->GetName()); + rc = PyXPCOM_SetCOMErrorFromPyException(); + } + // else everything is already setup, + // just clear the Python error state. + PyErr_Clear(); + } + + Py_XDECREF(obMI); + Py_XDECREF(obParams); + Py_XDECREF(obThisObject); + Py_XDECREF(result); + return rc; +} diff --git a/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp b/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp new file mode 100644 index 00000000..e5254acc --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyGWeakReference.cpp @@ -0,0 +1,112 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// PyGWeakReference - implements weak references for gateways. +// +// This code is part of the XPCOM extensions for Python. +// +// Written November 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +PyXPCOM_GatewayWeakReference::PyXPCOM_GatewayWeakReference( PyG_Base *base ) +{ + m_pBase = base; + +#ifdef NS_BUILD_REFCNT_LOGGING + // bloat view uses 40 chars - stick "(WR)" at the end of this position. + strncpy(refcntLogRepr, m_pBase->refcntLogRepr, sizeof(refcntLogRepr)); + refcntLogRepr[sizeof(refcntLogRepr)-1] = '\0'; + char *dest = refcntLogRepr + ((strlen(refcntLogRepr) > 36) ? 36 : strlen(refcntLogRepr)); + strcpy(dest, "(WR)"); +#endif // NS_BUILD_REFCNT_LOGGING +} + +PyXPCOM_GatewayWeakReference::~PyXPCOM_GatewayWeakReference() +{ + // Simply zap my reference to the gateway! + // No need to zap my gateway's reference to me, as + // it already holds a reference, so if we are destructing, + // then it can't possibly hold one. + m_pBase = NULL; +} + +nsrefcnt +PyXPCOM_GatewayWeakReference::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + NS_LOG_ADDREF(this, cnt, refcntLogRepr, sizeof(*this)); +#endif + return cnt; +} + +nsrefcnt +PyXPCOM_GatewayWeakReference::Release(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); +#ifdef NS_BUILD_REFCNT_LOGGING + NS_LOG_RELEASE(this, cnt, refcntLogRepr); +#endif + if ( cnt == 0 ) + delete this; + return cnt; +} + +NS_IMPL_THREADSAFE_QUERY_INTERFACE1(PyXPCOM_GatewayWeakReference, nsIWeakReference) + +NS_IMETHODIMP +PyXPCOM_GatewayWeakReference::QueryReferent(REFNSIID iid, void * *ret) +{ + { + // Temp scope for lock. We can't hold the lock during + // a QI, as this may itself need the lock. + // Make sure our object isn't dieing right now on another thread. + CEnterLeaveXPCOMFramework _celf; + if (m_pBase == NULL) + return NS_ERROR_NULL_POINTER; + m_pBase->AddRef(); // Can't die while we have a ref. + } // end of lock scope - lock unlocked. + nsresult nr = m_pBase->QueryInterface(iid, ret); + m_pBase->Release(); + return nr; +} diff --git a/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp b/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp new file mode 100644 index 00000000..6d0f499d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIClassInfo.cpp @@ -0,0 +1,181 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. Portions created by ActiveState Tool Corp. are Copyright (C) 2001 ActiveState Tool Corp. All Rights Reserved. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2001 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2001, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsIClassInfo.h" + +static nsIClassInfo *_GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIClassInfo); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIClassInfo *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIClassInfo *pI = _GetI(self); + if (pI==NULL) + return NULL; + + nsIID** iidArray = nsnull; + PRUint32 iidCount = 0; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInterfaces(&iidCount, &iidArray); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + PyObject *ret = PyTuple_New(iidCount); + if (ret==NULL) + return NULL; + for (PRUint32 i=0;i pi; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetHelperForLanguage(language, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports)); +} + +static PyObject *MakeStringOrNone(char *v) +{ + if (v) +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(v); +#else + return PyUnicode_FromString(v); +#endif + Py_INCREF(Py_None); + return Py_None; +} + +#define GETATTR_CHECK_RESULT(nr) if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr) + +PyObject * +Py_nsIClassInfo::getattr(const char *name) +{ + nsIClassInfo *pI = _GetI(this); + if (pI==NULL) + return NULL; + + nsresult nr; + PyObject *ret = NULL; + if (strcmp(name, "contractID")==0) { + char *str_ret = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetContractID(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsMemory::Free(str_ret); + } else if (strcmp(name, "classDescription")==0) { + char *str_ret = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassDescription(&str_ret); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = MakeStringOrNone(str_ret); + nsMemory::Free(str_ret); + } else if (strcmp(name, "classID")==0) { + nsIID *iid = NULL; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetClassID(&iid); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = Py_nsIID::PyObjectFromIID(*iid); + nsMemory::Free(iid); + } else if (strcmp(name, "implementationLanguage")==0) { + PRUint32 i; + Py_BEGIN_ALLOW_THREADS; + nr = pI->GetImplementationLanguage(&i); + Py_END_ALLOW_THREADS; + GETATTR_CHECK_RESULT(nr); + ret = PyInt_FromLong(i); + } else { + ret = Py_nsISupports::getattr(name); + } + return ret; +} + +int +Py_nsIClassInfo::setattr(const char *name, PyObject *v) +{ + return Py_nsISupports::setattr(name, v); + +} + +struct PyMethodDef +PyMethods_IClassInfo[] = +{ + { "getInterfaces", PyGetInterfaces, 1}, + { "GetInterfaces", PyGetInterfaces, 1}, + { "getHelperForLanguage", PyGetHelperForLanguage, 1}, + { "GetHelperForLanguage", PyGetHelperForLanguage, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp b/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp new file mode 100644 index 00000000..c3b89112 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIComponentManager.cpp @@ -0,0 +1,138 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +static nsIComponentManager *GetI(PyObject *self) { + static const nsIID iid = NS_GET_IID(nsIComponentManager); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return NS_STATIC_CAST(nsIComponentManager*, Py_nsISupports::GetI(self)); +} + +static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) +{ + // second arg to CreateInstanceByContractID is a "delegate" - we + // aren't sure of the semantics of this yet and it seems rarely used, + // so we just punt for now. + char *pid, *notyet = NULL; + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "s|zO", &pid, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstanceByContractID(pid, NULL, iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); +} + +static PyObject *PyCreateInstance(PyObject *self, PyObject *args) +{ + char *notyet = NULL; + PyObject *obClassID = NULL, *obIID = NULL; + if (!PyArg_ParseTuple(args, "O|zO", &obClassID, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID classID; + if (!Py_nsIID::IIDFromPyObject(obClassID, &classID)) + return NULL; + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstance(classID, NULL, iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); +} + +struct PyMethodDef +PyMethods_IComponentManager[] = +{ + { "createInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "createInstance", PyCreateInstance, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp b/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp new file mode 100644 index 00000000..7d07d421 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIComponentManagerObsolete.cpp @@ -0,0 +1,203 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + +static nsIComponentManagerObsolete *GetI(PyObject *self) { + static const nsIID iid = NS_GET_IID(nsIComponentManagerObsolete); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIComponentManagerObsolete *)Py_nsISupports::GetI(self); +} + +static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) +{ + char *pid, *notyet = NULL; + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "s|zO", &pid, ¬yet, &obIID)) + return NULL; + if (notyet != NULL) { + PyErr_SetString(PyExc_ValueError, "2nd arg must be none"); + return NULL; + } + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (obIID==NULL) + iid = NS_GET_IID(nsISupports); + else + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsISupports *pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CreateInstanceByContractID(pid, NULL, iid, (void **)&pis); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE); +} + +static PyObject *PyContractIDToClassID(PyObject *self, PyObject *args) +{ + char *pid; + if (!PyArg_ParseTuple(args, "s", &pid)) + return NULL; + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->ContractIDToClassID(pid, &iid); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsIID::PyObjectFromIID(iid); +} + +static PyObject *PyCLSIDToContractID(PyObject *self, PyObject *args) +{ + PyObject *obIID; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + char *ret_pid = nsnull; + char *ret_class = nsnull; + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CLSIDToContractID(iid, &ret_class, &ret_pid); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + +#if PY_MAJOR_VERSION <= 2 + PyObject *ob_pid = PyString_FromString(ret_pid); + PyObject *ob_class = PyString_FromString(ret_class); +#else + PyObject *ob_pid = PyUnicode_FromString(ret_pid); + PyObject *ob_class = PyUnicode_FromString(ret_class); +#endif + PyObject *ret = Py_BuildValue("OO", ob_pid, ob_class); + nsMemory::Free(ret_pid); + nsMemory::Free(ret_class); + Py_XDECREF(ob_pid); + Py_XDECREF(ob_class); + return ret; +} + +static PyObject *PyEnumerateCLSIDs(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIEnumerator *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateCLSIDs(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE); +} + +static PyObject *PyEnumerateContractIDs(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIComponentManagerObsolete *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIEnumerator *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateContractIDs(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE); +} + +struct PyMethodDef +PyMethods_IComponentManagerObsolete[] = +{ + { "CreateInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "createInstanceByContractID", PyCreateInstanceByContractID, 1}, + { "EnumerateCLSIDs", PyEnumerateCLSIDs, 1}, + { "enumerateCLSIDs", PyEnumerateCLSIDs, 1}, + { "EnumerateContractIDs", PyEnumerateContractIDs, 1}, + { "enumerateContractIDs", PyEnumerateContractIDs, 1}, + { "ContractIDToClassID", PyContractIDToClassID, 1}, + { "contractIDToClassID", PyContractIDToClassID, 1}, + { "CLSIDToContractID", PyCLSIDToContractID, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp b/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp new file mode 100644 index 00000000..b196d956 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIEnumerator.cpp @@ -0,0 +1,235 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsIEnumerator *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIEnumerator); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIEnumerator *)Py_nsISupports::GetI(self); +} + +static PyObject *PyFirst(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":First")) + return NULL; + + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->First(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(r); +} + +static PyObject *PyNext(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":Next")) + return NULL; + + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Next(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(r); +} + +static PyObject *PyCurrentItem(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "|O:CurrentItem", &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsISupports *pRet = nsnull; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->CurrentItem(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + if (obIID) { + nsISupports *temp; + Py_BEGIN_ALLOW_THREADS; + r = pRet->QueryInterface(iid, (void **)&temp); + pRet->Release(); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) { + return PyXPCOM_BuildPyException(r); + } + pRet = temp; + } + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; +} + +// A method added for Python performance if you really need +// it. Allows you to fetch a block of objects in one +// hit, allowing the loop to remain implemented in C. +static PyObject *PyFetchBlock(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + int n_wanted; + int n_fetched = 0; + if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsIEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + // We want to fetch with the thread-lock released, + // but this means we can not append to the PyList + nsISupports **fetched = new nsISupports*[n_wanted]; + if (fetched==nsnull) { + PyErr_NoMemory(); + return NULL; + } + memset(fetched, 0, sizeof(nsISupports *) * n_wanted); + nsresult r = NS_OK; + Py_BEGIN_ALLOW_THREADS; + for (;n_fetchedCurrentItem(&pNew); + if (NS_FAILED(r)) { + r = 0; // Normal enum end + break; + } + if (obIID) { + nsISupports *temp; + r = pNew->QueryInterface(iid, (void **)&temp); + pNew->Release(); + if ( NS_FAILED(r) ) { + break; + } + pNew = temp; + } + fetched[n_fetched] = pNew; + n_fetched++; // must increment before breaking out. + if (NS_FAILED(pI->Next())) + break; // not an error condition. + } + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_SUCCEEDED(r)) { + ret = PyList_New(n_fetched); + if (ret) + for (int i=0;iRelease(); + + } + delete [] fetched; + return ret; +} + +static PyObject *PyIsDone(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":IsDone")) + return NULL; + + nsIEnumerator *pI = GetI(self); + nsresult r; + if (pI==NULL) + return NULL; + + Py_BEGIN_ALLOW_THREADS; + r = pI->IsDone(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(r)) + return PyXPCOM_BuildPyException(r); + PyObject *ret = r==NS_OK ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +struct PyMethodDef +PyMethods_IEnumerator[] = +{ + { "First", PyFirst, 1}, + { "first", PyFirst, 1}, + { "Next", PyNext, 1}, + { "next", PyNext, 1}, + { "CurrentItem", PyCurrentItem, 1}, + { "currentItem", PyCurrentItem, 1}, + { "IsDone", PyIsDone, 1}, + { "isDone", PyIsDone, 1}, + { "FetchBlock", PyFetchBlock, 1}, + { "fetchBlock", PyFetchBlock, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIID.cpp b/src/libs/xpcom18a4/python/src/PyIID.cpp new file mode 100644 index 00000000..f24ae20e --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIID.cpp @@ -0,0 +1,410 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// Py_nsIID.cpp -- IID type for Python/XPCOM +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. +// +// @doc + +#include "PyXPCOM_std.h" +#include + +nsIID Py_nsIID_NULL = {0,0,0,{0,0,0,0,0,0,0,0}}; + +// @pymethod |xpcom|IID|Creates a new IID object +PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args) +{ + PyObject *obIID; + PyObject *obBuf; + if ( PyArg_ParseTuple(args, "O", &obBuf)) { +#if PY_MAJOR_VERSION <= 2 + if (PyBuffer_Check(obBuf)) { + PyBufferProcs *pb = NULL; + pb = obBuf->ob_type->tp_as_buffer; + void *buf = NULL; + int size = (*pb->bf_getreadbuffer)(obBuf, 0, &buf); +#else + if (PyObject_CheckBuffer(obBuf)) { +# ifndef Py_LIMITED_API + Py_buffer view; + if (PyObject_GetBuffer(obBuf, &view, PyBUF_CONTIG_RO) != 0) { + PyErr_Format(PyExc_ValueError, "Could not get contiguous buffer from object"); + return NULL; + } + Py_ssize_t size = view.len; + const void *buf = view.buf; +# else /* Py_LIMITED_API - the buffer API is non-existant, from what I can tell */ + const void *buf = NULL; + Py_ssize_t size = 0; + if (PyObject_AsReadBuffer(obBuf, &buf, &size) != 0) { + PyErr_Format(PyExc_ValueError, "Could not get read-only buffer from object"); + return NULL; + } +# endif /* Py_LIMITED_API */ +#endif + if (size != sizeof(nsIID) || buf==NULL) { +#if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API) + PyBuffer_Release(&view); +#endif +#ifdef VBOX + PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", (int)sizeof(nsIID)); +#else + PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", sizeof(nsIID)); +#endif + return NULL; + } + nsIID iid; + unsigned char const *ptr = (unsigned char const *)buf; + iid.m0 = XPT_SWAB32(*((PRUint32 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m1); + iid.m1 = XPT_SWAB16(*((PRUint16 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m2); + iid.m2 = XPT_SWAB16(*((PRUint16 *)ptr)); + ptr = ((unsigned char const *)buf) + offsetof(nsIID, m3); + for (int i=0;i<8;i++) { + iid.m3[i] = *((PRUint8 const *)ptr); + ptr += sizeof(PRUint8); + } +#if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API) + PyBuffer_Release(&view); +#endif + return new Py_nsIID(iid); + } + } + PyErr_Clear(); + // @pyparm string/Unicode|iidString||A string representation of an IID, or a ContractID. + if ( !PyArg_ParseTuple(args, "O", &obIID) ) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + return new Py_nsIID(iid); +} + +/*static*/ PRBool +Py_nsIID::IIDFromPyObject(PyObject *ob, nsIID *pRet) { + PRBool ok = PR_TRUE; + nsIID iid; + if (ob==NULL) { + PyErr_SetString(PyExc_RuntimeError, "The IID object is invalid!"); + return PR_FALSE; + } +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(ob)) { + ok = iid.Parse(PyString_AsString(ob)); +#else + if (PyUnicode_Check(ob)) { + ok = iid.Parse(PyUnicode_AsUTF8(ob)); +#endif + if (!ok) { + PyXPCOM_BuildPyException(NS_ERROR_ILLEGAL_VALUE); + return PR_FALSE; + } +#ifndef Py_LIMITED_API + } else if (ob->ob_type == &type) { +#else + } else if (ob->ob_type == Py_nsIID::GetTypeObject()) { +#endif + iid = ((Py_nsIID *)ob)->m_iid; + } else if (PyObject_HasAttrString(ob, "__class__")) { + // Get the _iidobj_ attribute + PyObject *use_ob = PyObject_GetAttrString(ob, "_iidobj_"); + if (use_ob==NULL) { + PyErr_SetString(PyExc_TypeError, "Only instances with _iidobj_ attributes can be used as IID objects"); + return PR_FALSE; + } +#ifndef Py_LIMITED_API + if (use_ob->ob_type != &type) { +#else + if (use_ob->ob_type != Py_nsIID::GetTypeObject()) { +#endif + Py_DECREF(use_ob); + PyErr_SetString(PyExc_TypeError, "instance _iidobj_ attributes must be raw IID object"); + return PR_FALSE; + } + iid = ((Py_nsIID *)use_ob)->m_iid; + Py_DECREF(use_ob); + } else { + PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an IID", PyXPCOM_ObTypeName(ob)); + ok = PR_FALSE; + } + if (ok) *pRet = iid; + return ok; +} + + +// @object Py_nsIID|A Python object, representing an IID/CLSID. +// All pythoncom functions that return a CLSID/IID will return one of these +// objects. However, in almost all cases, functions that expect a CLSID/IID +// as a param will accept either a string object, or a native Py_nsIID object. +#ifndef Py_LIMITED_API +PyTypeObject Py_nsIID::type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "IID", + sizeof(Py_nsIID), + 0, + PyTypeMethod_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + PyTypeMethod_getattr, /* tp_getattr */ + 0, /* tp_setattr */ +#if PY_MAJOR_VERSION <= 2 + PyTypeMethod_compare, /* tp_compare */ +#else + 0, /* reserved */ +#endif + PyTypeMethod_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + PyTypeMethod_hash, /* tp_hash */ + 0, /* tp_call */ + PyTypeMethod_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + PyTypeMethod_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ +}; +#else /* Py_LIMITED_API */ +NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) Py_nsIID::s_pType = NULL; + +PyTypeObject *Py_nsIID::GetTypeObject(void) +{ + PyTypeObject *pTypeObj = Py_nsIID::s_pType; + if (pTypeObj) + return pTypeObj; + + PyType_Slot aTypeSlots[] = { + { Py_tp_base, &PyType_Type }, + { Py_tp_dealloc, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_dealloc }, + { Py_tp_getattr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_getattr }, + { Py_tp_repr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_repr }, + { Py_tp_hash, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_hash }, + { Py_tp_str, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_str }, + { Py_tp_richcompare, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_richcompare }, + { 0, NULL } /* terminator */ + }; + PyType_Spec TypeSpec = { + /* .name: */ "IID", + /* .basicsize: */ sizeof(Py_nsIID), + /* .itemsize: */ 0, + /* .flags: */ 0, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + Py_nsIID::s_pType = pTypeObj; + return pTypeObj; +} +#endif /* Py_LIMITED_API */ + +Py_nsIID::Py_nsIID(const nsIID &riid) +{ +#ifndef Py_LIMITED_API + ob_type = &type; +#else + ob_type = GetTypeObject(); +#endif +#if 1 /* VBox: Must use for 3.9+, includes _Py_NewReferences. Works for all older versions too. @bugref{10079} */ + PyObject_Init(this, ob_type); +#else + _Py_NewReference(this); +#endif + + m_iid = riid; +} + +/*static*/PyObject * +Py_nsIID::PyTypeMethod_getattr(PyObject *self, char *name) +{ + Py_nsIID *me = (Py_nsIID *)self; + if (strcmp(name, "name")==0) { + char *iid_repr = nsnull; + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim!=nsnull) + iim->GetNameForIID(&me->m_iid, &iid_repr); + if (iid_repr==nsnull) + iid_repr = me->m_iid.ToString(); + PyObject *ret; + if (iid_repr != nsnull) { +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(iid_repr); +#else + ret = PyUnicode_FromString(iid_repr); +#endif + nsMemory::Free(iid_repr); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(""); +#else + ret = PyUnicode_FromString(""); +#endif + return ret; + } + return PyErr_Format(PyExc_AttributeError, "IID objects have no attribute '%s'", name); +} + +#if PY_MAJOR_VERSION <= 2 +/* static */ int +Py_nsIID::PyTypeMethod_compare(PyObject *self, PyObject *other) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + Py_nsIID *o_iid = (Py_nsIID *)other; + int rc = memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid)); + return rc == 0 ? 0 : (rc < 0 ? -1 : 1); +} +#endif + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_richcompare(PyObject *self, PyObject *other, int op) +{ + PyObject *result = NULL; + Py_nsIID *s_iid = (Py_nsIID *)self; + Py_nsIID *o_iid = (Py_nsIID *)other; + int rc = memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid)); + switch (op) + { + case Py_LT: + result = rc < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = rc <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = rc == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = rc != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = rc > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = rc >= 0 ? Py_True : Py_False; + break; + } + Py_XINCREF(result); + return result; +} + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_repr(PyObject *self) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + char buf[256]; + char *sziid = s_iid->m_iid.ToString(); +#ifdef VBOX + snprintf(buf, sizeof(buf), "_xpcom.ID('%s')", sziid); +#else + sprintf(buf, "_xpcom.IID('%s')", sziid); +#endif + nsMemory::Free(sziid); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(buf); +#else + return PyUnicode_FromString(buf); +#endif +} + +/* static */ PyObject * +Py_nsIID::PyTypeMethod_str(PyObject *self) +{ + Py_nsIID *s_iid = (Py_nsIID *)self; + char *sziid = s_iid->m_iid.ToString(); +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(sziid); +#else + PyObject *ret = PyUnicode_FromString(sziid); +#endif + nsMemory::Free(sziid); + return ret; +} + +#if PY_VERSION_HEX >= 0x03020000 +/* static */Py_hash_t +Py_nsIID::PyTypeMethod_hash(PyObject *self) +#else +/* static */long +Py_nsIID::PyTypeMethod_hash(PyObject *self) +#endif +{ + const nsIID &iid = ((Py_nsIID *)self)->m_iid; + +#if PY_VERSION_HEX >= 0x03020000 + Py_hash_t ret = iid.m0 + iid.m1 + iid.m2; +#else + long ret = iid.m0 + iid.m1 + iid.m2; +#endif + for (int i=0;i<7;i++) + ret += iid.m3[i]; + if ( ret == -1 ) + return -2; + return ret; +} + +/*static*/ void +Py_nsIID::PyTypeMethod_dealloc(PyObject *ob) +{ + delete (Py_nsIID *)ob; +} diff --git a/src/libs/xpcom18a4/python/src/PyIInputStream.cpp b/src/libs/xpcom18a4/python/src/PyIInputStream.cpp new file mode 100644 index 00000000..b290a3e4 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInputStream.cpp @@ -0,0 +1,190 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written September 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsIInputStream.h" + +// Prevents us needing to use an nsIScriptableInputStream +// (and even that can't read binary data!!!) + +static nsIInputStream *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInputStream); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInputStream *)Py_nsISupports::GetI(self); +} + +static PyObject *DoPyRead_Buffer(nsIInputStream *pI, PyObject *obBuffer, PRUint32 n) +{ + PRUint32 nread; + void *buf; +#ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 buf_len; + if (PyObject_AsWriteBuffer(obBuffer, &buf, (Py_ssize_t *)&buf_len) != 0) { +#else /* VBOX */ +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t buf_len; +# else + int buf_len; +# endif /* VBOX */ + if (PyObject_AsWriteBuffer(obBuffer, &buf, &buf_len) != 0) { +#endif + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "The buffer object does not have a write buffer!"); + return NULL; + } + if (n==(PRUint32)-1) { + n = buf_len; + } else { + if (n > buf_len) { + NS_WARNING("Warning: PyIInputStream::read() was passed an integer size greater than the size of the passed buffer! Buffer size used.\n"); + n = buf_len; + } + } + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Read((char *)buf, n, &nread); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(nread); +} + +static PyObject *DoPyRead_Size(nsIInputStream *pI, PRUint32 n) +{ + if (n==(PRUint32)-1) { + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->Available(&n); + Py_END_ALLOW_THREADS; + if (NS_FAILED(r)) + return PyXPCOM_BuildPyException(r); + } + if (n==0) { // mozilla will assert if we alloc zero bytes. +#if PY_MAJOR_VERSION <= 2 + return PyBuffer_New(0); +#else + return PyBytes_FromString(""); +#endif + } + char *buf = (char *)nsMemory::Alloc(n); + if (buf==NULL) { + PyErr_NoMemory(); + return NULL; + } + nsresult r; + PRUint32 nread; + Py_BEGIN_ALLOW_THREADS; + r = pI->Read(buf, n, &nread); + Py_END_ALLOW_THREADS; + PyObject *rc = NULL; + if ( NS_SUCCEEDED(r) ) { +#if PY_MAJOR_VERSION <= 2 + rc = PyBuffer_New(nread); + if (rc != NULL) { + void *ob_buf; +#ifndef VBOX /* unsafe cast on 64-bit hosts. */ + PRUint32 buf_len; + if (PyObject_AsWriteBuffer(rc, &ob_buf, (Py_ssize_t *)&buf_len) != 0) { +#else /* VBOX */ +# if PY_VERSION_HEX >= 0x02050000 || defined(PY_SSIZE_T_MIN) + Py_ssize_t buf_len; +# else + int buf_len; +# endif /* VBOX */ + if (PyObject_AsWriteBuffer(rc, &ob_buf, &buf_len) != 0) { +#endif + // should never fail - we just created it! + return NULL; + } + if (buf_len != nread) { + PyErr_SetString(PyExc_RuntimeError, "New buffer isnt the size we create it!"); + return NULL; + } + memcpy(ob_buf, buf, nread); + } +#else + rc = PyBytes_FromStringAndSize(buf, nread); +#endif + } else + PyXPCOM_BuildPyException(r); + nsMemory::Free(buf); + return rc; +} + +static PyObject *PyRead(PyObject *self, PyObject *args) +{ + PyObject *obBuffer = NULL; + PRUint32 n = (PRUint32)-1; + + nsIInputStream *pI = GetI(self); + if (pI==NULL) + return NULL; + if (PyArg_ParseTuple(args, "|i", (int *)&n)) + // This worked - no args, or just an int. + return DoPyRead_Size(pI, n); + // try our other supported arg format. + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "O|i", &obBuffer, (int *)&n)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, "'read()' must be called as (buffer_ob, int_size=-1) or (int_size=-1)"); + return NULL; + } + return DoPyRead_Buffer(pI, obBuffer, n); +} + + +struct PyMethodDef +PyMethods_IInputStream[] = +{ + { "read", PyRead, 1}, + // The rest are handled as normal + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp b/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp new file mode 100644 index 00000000..7e1a9466 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInterfaceInfo.cpp @@ -0,0 +1,431 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" + + +static nsIInterfaceInfo *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInterfaceInfo); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInterfaceInfo *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetName(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetName")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + char *name; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetName(&name); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(name); +#else + PyObject *ret = PyUnicode_FromString(name); +#endif + nsMemory::Free(name); + return ret; +} + +static PyObject *PyGetIID(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetIID")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID *iid_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInterfaceIID(&iid_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret); + nsMemory::Free(iid_ret); + return ret; +} + +static PyObject *PyIsScriptable(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":IsScriptable")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRBool b_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->IsScriptable(&b_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(b_ret); +} + +static PyObject *PyGetParent(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetParent")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetParent(getter_AddRefs(pRet)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); +} + +static PyObject *PyGetMethodCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetMethodCount")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodCount(&ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(ret); +} + + +static PyObject *PyGetConstantCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":GetConstantCount")) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetConstantCount(&ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetMethodInfo(PyObject *self, PyObject *args) +{ + PRUint16 index; + if (!PyArg_ParseTuple(args, "h:GetMethodInfo", &index)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + PRUint16 nmethods; + pI->GetMethodCount(&nmethods); + if (index>=nmethods) { + PyErr_SetString(PyExc_ValueError, "The method index is out of range"); + return NULL; + } + + const nsXPTMethodInfo *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodInfo(index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyObject_FromXPTMethodDescriptor(pRet); +} + +static PyObject *PyGetMethodInfoForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:GetMethodInfoForName", &name)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + const nsXPTMethodInfo *pRet; + PRUint16 index; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetMethodInfoForName(name, &index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + PyObject *ret_i = PyObject_FromXPTMethodDescriptor(pRet); + if (ret_i==NULL) + return NULL; + PyObject *real_ret = Py_BuildValue("iO", (int)index, ret_i); + Py_DECREF(ret_i); + return real_ret; +} + + +static PyObject *PyGetConstant(PyObject *self, PyObject *args) +{ + PRUint16 index; + if (!PyArg_ParseTuple(args, "h:GetConstant", &index)) + return NULL; + + nsIInterfaceInfo *pI = GetI(self); + if (pI==NULL) + return NULL; + + const nsXPTConstant *pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetConstant(index, &pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyObject_FromXPTConstant(pRet); +} + +static PRBool __GetMethodInfoHelper(nsIInterfaceInfo *pii, int mi, int pi, const nsXPTMethodInfo **ppmi) +{ + PRUint16 nmethods=0; + pii->GetMethodCount(&nmethods); + if (mi<0 || mi>=nmethods) { + PyErr_SetString(PyExc_ValueError, "The method index is out of range"); + return PR_FALSE; + } + const nsXPTMethodInfo *pmi; + nsresult r = pii->GetMethodInfo(mi, &pmi); + if ( NS_FAILED(r) ) { + PyXPCOM_BuildPyException(r); + return PR_FALSE; + } + + int nparams=0; + nparams = pmi->GetParamCount(); + if (pi<0 || pi>=nparams) { + PyErr_SetString(PyExc_ValueError, "The param index is out of range"); + return PR_FALSE; + } + *ppmi = pmi; + return PR_TRUE; +} + +static PyObject *PyGetInfoForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hh:GetInfoForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsCOMPtr pnewii; + nsresult n = pii->GetInfoForParam(mi, ¶m_info, getter_AddRefs(pnewii)); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo)); +} + +static PyObject *PyGetIIDForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hh:GetIIDForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsIID *piid; + nsresult n = pii->GetIIDForParam(mi, ¶m_info, &piid); + if (NS_FAILED(n) || piid==nsnull) + return PyXPCOM_BuildPyException(n); + PyObject *rc = Py_nsIID::PyObjectFromIID(*piid); + nsMemory::Free((void*)piid); + return rc; +} + +static PyObject *PyGetTypeForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetTypeForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + nsXPTType datumType; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetTypeForParam(mi, ¶m_info, dim, &datumType); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyObject_FromXPTType(&datumType); +} + +static PyObject *PyGetSizeIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetSizeIsArgNumberForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetSizeIsArgNumberForParam(mi, ¶m_info, dim, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetLengthIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi, dim; + if (!PyArg_ParseTuple(args, "hhh:GetLengthIsArgNumberForParam", &mi, &pi, &dim)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetLengthIsArgNumberForParam(mi, ¶m_info, dim, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +static PyObject *PyGetInterfaceIsArgNumberForParam(PyObject *self, PyObject *args) +{ + nsIInterfaceInfo *pii = GetI(self); + if (pii==NULL) + return NULL; + PRUint16 mi, pi; + if (!PyArg_ParseTuple(args, "hhh:GetInterfaceIsArgNumberForParam", &mi, &pi)) + return NULL; + const nsXPTMethodInfo *pmi; + if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) + return NULL; + PRUint8 ret; + const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); + nsresult n = pii->GetInterfaceIsArgNumberForParam(mi, ¶m_info, &ret); + if (NS_FAILED(n)) + return PyXPCOM_BuildPyException(n); + return PyInt_FromLong(ret); +} + +struct PyMethodDef +PyMethods_IInterfaceInfo[] = +{ + { "GetName", PyGetName, 1}, + { "GetIID", PyGetIID, 1}, + { "IsScriptable", PyIsScriptable, 1}, + { "GetParent", PyGetParent, 1}, + { "GetMethodCount", PyGetMethodCount, 1}, + { "GetConstantCount", PyGetConstantCount, 1}, + { "GetMethodInfo", PyGetMethodInfo, 1}, + { "GetMethodInfoForName", PyGetMethodInfoForName, 1}, + { "GetConstant", PyGetConstant, 1}, + { "GetInfoForParam", PyGetInfoForParam, 1}, + { "GetIIDForParam", PyGetIIDForParam, 1}, + { "GetTypeForParam", PyGetTypeForParam, 1}, + { "GetSizeIsArgNumberForParam", PyGetSizeIsArgNumberForParam, 1}, + { "GetLengthIsArgNumberForParam", PyGetLengthIsArgNumberForParam, 1}, + { "GetInterfaceIsArgNumberForParam", PyGetInterfaceIsArgNumberForParam, 1}, + {NULL} +}; + +/* + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) = 0; + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) = 0; + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) = 0; + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) = 0; + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) = 0; + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) = 0; + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0; + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) = 0; + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) = 0; + +*/ diff --git a/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp b/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp new file mode 100644 index 00000000..7c629413 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIInterfaceInfoManager.cpp @@ -0,0 +1,206 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsIInterfaceInfoManager *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIInterfaceInfoManager); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIInterfaceInfoManager *)Py_nsISupports::GetI(self); +} + +static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr pi; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInfoForIID(&iid, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + nsIID new_iid = NS_GET_IID(nsIInterfaceInfo); + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE); +} + +static PyObject *PyGetInfoForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pi; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetInfoForName(name, getter_AddRefs(pi)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); +} + +static PyObject *PyGetNameForIID(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "O", &obIID)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + char *ret_name = NULL; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetNameForIID(&iid, &ret_name); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + +#if PY_MAJOR_VERSION <= 2 + PyObject *ret = PyString_FromString(ret_name); +#else + PyObject *ret = PyUnicode_FromString(ret_name); +#endif + nsMemory::Free(ret_name); + return ret; +} + +static PyObject *PyGetIIDForName(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s", &name)) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsIID *iid_ret; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetIIDForName(name, &iid_ret); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + PyObject *ret = Py_nsIID::PyObjectFromIID(*iid_ret); + nsMemory::Free(iid_ret); + return ret; +} + +static PyObject *PyEnumerateInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + nsIInterfaceInfoManager *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsCOMPtr pRet; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->EnumerateInterfaces(getter_AddRefs(pRet)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator)); +} + +// TODO: +// void autoRegisterInterfaces(); + +PyMethodDef +PyMethods_IInterfaceInfoManager[] = +{ + { "GetInfoForIID", PyGetInfoForIID, 1}, + { "getInfoForIID", PyGetInfoForIID, 1}, + { "GetInfoForName", PyGetInfoForName, 1}, + { "getInfoForName", PyGetInfoForName, 1}, + { "GetIIDForName", PyGetIIDForName, 1}, + { "getIIDForName", PyGetIIDForName, 1}, + { "GetNameForIID", PyGetNameForIID, 1}, + { "getNameForIID", PyGetNameForIID, 1}, + { "EnumerateInterfaces", PyEnumerateInterfaces, 1}, + { "enumerateInterfaces", PyEnumerateInterfaces, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp b/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp new file mode 100644 index 00000000..b94d8eb2 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyISimpleEnumerator.cpp @@ -0,0 +1,202 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include + +static nsISimpleEnumerator *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsISimpleEnumerator); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsISimpleEnumerator *)Py_nsISupports::GetI(self); +} + + +static PyObject *PyHasMoreElements(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":HasMoreElements")) + return NULL; + + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsresult r; + PRBool more; + Py_BEGIN_ALLOW_THREADS; + r = pI->HasMoreElements(&more); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + return PyInt_FromLong(more); +} + +static PyObject *PyGetNext(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + if (!PyArg_ParseTuple(args, "|O:GetNext", &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + nsISupports *pRet = nsnull; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pI->GetNext(&pRet); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + if (obIID) { + nsISupports *temp; + Py_BEGIN_ALLOW_THREADS; + r = pRet->QueryInterface(iid, (void **)&temp); + pRet->Release(); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) { + return PyXPCOM_BuildPyException(r); + } + pRet = temp; + } + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; +} + +// A method added for Python performance if you really need +// it. Allows you to fetch a block of objects in one +// hit, allowing the loop to remain implemented in C. +static PyObject *PyFetchBlock(PyObject *self, PyObject *args) +{ + PyObject *obIID = NULL; + int n_wanted; + int n_fetched = 0; + if (!PyArg_ParseTuple(args, "i|O:FetchBlock", &n_wanted, &obIID)) + return NULL; + + nsIID iid(NS_GET_IID(nsISupports)); + if (obIID != NULL && !Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsISimpleEnumerator *pI = GetI(self); + if (pI==NULL) + return NULL; + + // We want to fetch with the thread-lock released, + // but this means we can not append to the PyList + nsISupports **fetched = new nsISupports*[n_wanted]; + if (fetched==nsnull) { + PyErr_NoMemory(); + return NULL; + } + memset(fetched, 0, sizeof(nsISupports *) * n_wanted); + nsresult r = NS_OK; + PRBool more; + Py_BEGIN_ALLOW_THREADS; + for (;n_fetchedHasMoreElements(&more); + if (NS_FAILED(r)) + break; // this _is_ an error! + if (!more) + break; // Normal enum end. + nsISupports *pNew; + r = pI->GetNext(&pNew); + if (NS_FAILED(r)) // IS an error + break; + if (obIID) { + nsISupports *temp; + r = pNew->QueryInterface(iid, (void **)&temp); + pNew->Release(); + if ( NS_FAILED(r) ) { + break; + } + pNew = temp; + } + fetched[n_fetched] = pNew; + n_fetched++; + } + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_SUCCEEDED(r)) { + ret = PyList_New(n_fetched); + if (ret) + for (int i=0;iRelease(); + + } + delete [] fetched; + return ret; +} + + +struct PyMethodDef +PyMethods_ISimpleEnumerator[] = +{ + { "HasMoreElements", PyHasMoreElements, 1}, + { "hasMoreElements", PyHasMoreElements, 1}, + { "GetNext", PyGetNext, 1}, + { "getNext", PyGetNext, 1}, + { "FetchBlock", PyFetchBlock, 1}, + { "fetchBlock", PyFetchBlock, 1}, + {NULL} +}; diff --git a/src/libs/xpcom18a4/python/src/PyISupports.cpp b/src/libs/xpcom18a4/python/src/PyISupports.cpp new file mode 100644 index 00000000..84504038 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyISupports.cpp @@ -0,0 +1,621 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include "nsISupportsPrimitives.h" + +static PRInt32 cInterfaces=0; +static PyObject *g_obFuncMakeInterfaceCount = NULL; // XXX - never released!!! + +#ifdef VBOX_DEBUG_LIFETIMES +# include +# include + +/*static*/ RTLISTNODE Py_nsISupports::g_List; +/*static*/ RTONCE Py_nsISupports::g_Once = RTONCE_INITIALIZER; +/*static*/ RTCRITSECT Py_nsISupports::g_CritSect; + +/*static*/ DECLCALLBACK(int32_t) +Py_nsISupports::initOnceCallback(void *pvUser1) +{ + NOREF(pvUser1); + RTListInit(&g_List); + return RTCritSectInit(&g_CritSect); +} + +/*static*/ void +Py_nsISupports::dumpList(void) +{ + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + + uint32_t i = 0; + Py_nsISupports *pCur; + RTListForEach(&g_List, pCur, Py_nsISupports, m_ListEntry) + { + nsISupports *pISup = pCur->m_obj; + PyXPCOM_LogWarning("#%u: %p iid=%RTuuid obj=%p", i, pCur, &pCur->m_iid, pISup); + i++; + } + + RTCritSectLeave(&g_CritSect); +} + +/*static*/ void +Py_nsISupports::dumpListToStdOut() +{ + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + + uint32_t i = 0; + Py_nsISupports *pCur; + RTListForEach(&g_List, pCur, Py_nsISupports, m_ListEntry) + { + nsISupports *pISup = pCur->m_obj; + RTPrintf("#%u: %p iid=%RTuuid obj=%p\n", i, pCur, &pCur->m_iid, pISup); + i++; + } + + RTCritSectLeave(&g_CritSect); +} + +PRInt32 +_PyXPCOM_DumpInterfaces(void) +{ + Py_nsISupports::dumpListToStdOut(); + return NS_OK; +} + +#endif /* _DEBUG_LIFETIMES */ + + + +PyObject *PyObject_FromNSInterface( nsISupports *aInterface, + const nsIID &iid, + PRBool bMakeNicePyObject /*= PR_TRUE */) +{ + return Py_nsISupports::PyObjectFromInterface(aInterface, iid, + bMakeNicePyObject); +} + +PRInt32 +_PyXPCOM_GetInterfaceCount(void) +{ + return cInterfaces; +} + +#ifndef Py_LIMITED_API +Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyTypeObject *this_type) +#else +Py_nsISupports::Py_nsISupports(nsISupports *punk, const nsIID &iid, PyXPCOM_TypeObject *this_type) +#endif +{ +#ifndef Py_LIMITED_API + ob_type = this_type; +#else + ob_type = this_type->m_pTypeObj; + m_pMyTypeObj = this_type; +#endif + m_obj = punk; + m_iid = iid; + // refcnt of object managed by caller. + PR_AtomicIncrement(&cInterfaces); + PyXPCOM_DLLAddRef(); +#if 1 /* VBox: Must use for 3.9+, includes _Py_NewReferences. Works for all older versions too. @bugref{10079} */ + PyObject_Init(this, ob_type); +#else + _Py_NewReference(this); +#endif + +#ifdef VBOX_DEBUG_LIFETIMES + RTOnce(&g_Once, initOnceCallback, NULL); + RTCritSectEnter(&g_CritSect); + RTListAppend(&g_List, &m_ListEntry); + RTCritSectLeave(&g_CritSect); + PyXPCOM_LogWarning("Creating %p: iid=%RTuuid obj=%p", this, &m_iid, punk); +#endif +} + +Py_nsISupports::~Py_nsISupports() +{ +#ifdef VBOX_DEBUG_LIFETIMES + RTCritSectEnter(&g_CritSect); + nsISupports *punk = m_obj; + RTListNodeRemove(&m_ListEntry); + RTCritSectLeave(&g_CritSect); + PyXPCOM_LogWarning("Destroying %p: iid=%RTuuid obj=%p", this, &m_iid, punk); +#endif + + SafeRelease(this); + PR_AtomicDecrement(&cInterfaces); + PyXPCOM_DLLRelease(); +} + +/*static*/ nsISupports * +Py_nsISupports::GetI(PyObject *self, nsIID *ret_iid) +{ + if (self==NULL) { + PyErr_SetString(PyExc_ValueError, "The Python object is invalid"); + return NULL; + } + Py_nsISupports *pis = (Py_nsISupports *)self; + if (pis->m_obj==NULL) { + // This should never be able to happen. + PyErr_SetString(PyExc_ValueError, "Internal Error - The XPCOM object has been released."); + return NULL; + } + if (ret_iid) + *ret_iid = pis->m_iid; + return pis->m_obj; +} + +/*static*/ void +Py_nsISupports::SafeRelease(Py_nsISupports *ob) +{ + if (!ob) + return; + if (ob->m_obj) + { + Py_BEGIN_ALLOW_THREADS; + ob->m_obj = nsnull; + Py_END_ALLOW_THREADS; + } +} + +/* virtual */ PyObject * +Py_nsISupports::getattr(const char *name) +{ + if (strcmp(name, "IID")==0) + return Py_nsIID::PyObjectFromIID( m_iid ); + + // Support for __unicode__ until we get a tp_unicode slot. + if (strcmp(name, "__unicode__")==0) { + nsresult rv; + PRUnichar *val = NULL; + Py_BEGIN_ALLOW_THREADS; + { // scope to kill pointer while thread-lock released. + nsCOMPtr ss( do_QueryInterface(m_obj, &rv )); + if (NS_SUCCEEDED(rv)) + rv = ss->ToString(&val); + } // end-scope + Py_END_ALLOW_THREADS; + PyObject *ret = NS_FAILED(rv) ? + PyXPCOM_BuildPyException(rv) : + PyObject_FromNSString(val); + if (val) nsMemory::Free(val); + return ret; + } +#ifndef Py_LIMITED_API + PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type; +#else + PyXPCOM_TypeObject *this_type = m_pMyTypeObj; +#endif +#if PY_MAJOR_VERSION <= 2 + return Py_FindMethodInChain(&this_type->chain, this, (char *)name); +#else + PyMethodChain *chain = &this_type->chain; + if (name[0] == '_' && name[1] == '_') { +# ifndef Py_LIMITED_API /** @todo ? */ + if (!strcmp(name, "__doc__")) { + const char *doc = ob_type->tp_doc; + if (doc) + return PyUnicode_FromString(doc); + } +# endif + } + while (chain) { + PyMethodDef *ml = chain->methods; + for (; ml->ml_name; ml++) { + if (!strcmp(name, ml->ml_name)) + return PyCFunction_New(ml, this); + } + chain = chain->link; + } + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +#endif +} + +/* virtual */ int +Py_nsISupports::setattr(const char *name, PyObject *v) +{ + char buf[128]; +#ifdef VBOX + snprintf(buf, sizeof(buf), "%s has read-only attributes", PyXPCOM_ObTypeName(this) ); +#else + sprintf(buf, "%s has read-only attributes", PyXPCOM_ObTypeName(this) ); +#endif + PyErr_SetString(PyExc_TypeError, buf); + return -1; +} + +/*static*/ Py_nsISupports * +Py_nsISupports::Constructor(nsISupports *pInitObj, const nsIID &iid) +{ + return new Py_nsISupports(pInitObj, + iid, + type); +} + +PRBool +Py_nsISupports::InterfaceFromPyISupports(PyObject *ob, + const nsIID &iid, + nsISupports **ppv) +{ + nsISupports *pis; + PRBool rc = PR_FALSE; + if ( !Check(ob) ) + { + PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be used as COM objects", PyXPCOM_ObTypeName(ob)); + goto done; + } + nsIID already_iid; + pis = GetI(ob, &already_iid); + if ( !pis ) + goto done; /* exception was set by GetI() */ + /* note: we don't (yet) explicitly hold a reference to pis */ + if (iid.Equals(Py_nsIID_NULL)) { + // a bit of a hack - we are asking for the arbitary interface + // wrapped by this object, not some other specific interface - + // so no QI, just an AddRef(); + Py_BEGIN_ALLOW_THREADS + pis->AddRef(); + Py_END_ALLOW_THREADS + *ppv = pis; + } else { + // specific interface requested - if it is not already the + // specific interface, QI for it and discard pis. + if (iid.Equals(already_iid)) { + *ppv = pis; + pis->AddRef(); + } else { + nsresult r; + Py_BEGIN_ALLOW_THREADS + r = pis->QueryInterface(iid, (void **)ppv); + Py_END_ALLOW_THREADS + if ( NS_FAILED(r) ) + { + PyXPCOM_BuildPyException(r); + goto done; + } + /* note: the QI added a ref for the return value */ + } + } + rc = PR_TRUE; +done: + return rc; +} + +PRBool +Py_nsISupports::InterfaceFromPyObject(PyObject *ob, + const nsIID &iid, + nsISupports **ppv, + PRBool bNoneOK, + PRBool bTryAutoWrap /* = PR_TRUE */) +{ + if ( ob == NULL ) + { + // don't overwrite an error message + if ( !PyErr_Occurred() ) + PyErr_SetString(PyExc_TypeError, "The Python object is invalid"); + return PR_FALSE; + } + if ( ob == Py_None ) + { + if ( bNoneOK ) + { + *ppv = NULL; + return PR_TRUE; + } + else + { + PyErr_SetString(PyExc_TypeError, "None is not a invalid interface object in this context"); + return PR_FALSE; + } + } + + // support nsIVariant + if (iid.Equals(NS_GET_IID(nsIVariant)) || iid.Equals(NS_GET_IID(nsIWritableVariant))) { + // Check it is not already nsIVariant + if (PyObject_HasAttrString(ob, "__class__")) { + PyObject *sub_ob = PyObject_GetAttrString(ob, "_comobj_"); + if (sub_ob==NULL) { + PyErr_Clear(); + } else { + if (InterfaceFromPyISupports(sub_ob, iid, ppv)) { + Py_DECREF(sub_ob); + return PR_TRUE; + } + PyErr_Clear(); + Py_DECREF(sub_ob); + } + } + nsresult nr = PyObject_AsVariant(ob, (nsIVariant **)ppv); + if (NS_FAILED(nr)) { + PyXPCOM_BuildPyException(nr); + return PR_FALSE; + } + NS_ASSERTION(ppv != nsnull, "PyObject_AsVariant worked but gave null!"); + return PR_TRUE; + } + // end of variant support. + + if (PyObject_HasAttrString(ob, "__class__")) { + // Get the _comobj_ attribute + PyObject *use_ob = PyObject_GetAttrString(ob, "_comobj_"); + if (use_ob==NULL) { + PyErr_Clear(); + if (bTryAutoWrap) + // Try and auto-wrap it - errors will leave Py exception set, + return PyXPCOM_XPTStub::AutoWrapPythonInstance(ob, iid, ppv); + PyErr_SetString(PyExc_TypeError, "The Python instance can not be converted to an XPCOM object"); + return PR_FALSE; + } else + ob = use_ob; + + } else { + Py_INCREF(ob); + } + PRBool rc = InterfaceFromPyISupports(ob, iid, ppv); + Py_DECREF(ob); + return rc; +} + + +// Interface conversions +/*static*/void +#ifndef Py_LIMITED_API +Py_nsISupports::RegisterInterface( const nsIID &iid, PyTypeObject *t) +#else +Py_nsISupports::RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t) +#endif +{ + if (mapIIDToType==NULL) + mapIIDToType = PyDict_New(); + + if (mapIIDToType) { + PyObject *key = Py_nsIID::PyObjectFromIID(iid); + if (key) + PyDict_SetItem(mapIIDToType, key, (PyObject *)t); + Py_XDECREF(key); + } +} + +/*static */PyObject * +Py_nsISupports::PyObjectFromInterface(nsISupports *pis, + const nsIID &riid, + PRBool bMakeNicePyObject, /* = PR_TRUE */ + PRBool bIsInternalCall /* = PR_FALSE */) +{ + // Quick exit. + if (pis==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + if (!bIsInternalCall) { +#ifdef NS_DEBUG + nsISupports *queryResult = nsnull; + Py_BEGIN_ALLOW_THREADS; + pis->QueryInterface(riid, (void **)&queryResult); + Py_END_ALLOW_THREADS; + NS_ASSERTION(queryResult == pis, "QueryInterface needed"); + NS_IF_RELEASE(queryResult); +#endif + } + +#ifndef Py_LIMITED_API + PyTypeObject *createType = NULL; +#else + PyXPCOM_TypeObject *createType = NULL; +#endif + // If the IID is for nsISupports, dont bother with + // a map lookup as we know the type! + if (!riid.Equals(NS_GET_IID(nsISupports))) { + // Look up the map + PyObject *obiid = Py_nsIID::PyObjectFromIID(riid); + if (!obiid) return NULL; + + if (mapIIDToType != NULL) +#ifndef Py_LIMITED_API + createType = (PyTypeObject *)PyDict_GetItem(mapIIDToType, obiid); +#else + createType = (PyXPCOM_TypeObject *)PyDict_GetItem(mapIIDToType, obiid); +#endif + Py_DECREF(obiid); + } + if (createType==NULL) + createType = Py_nsISupports::type; +#ifndef Py_LIMITED_API + // Check it is indeed one of our types. + if (!PyXPCOM_TypeObject::IsType(createType)) { + PyErr_SetString(PyExc_RuntimeError, "The type map is invalid"); + return NULL; + } + // we can now safely cast the thing to a PyComTypeObject and use it + PyXPCOM_TypeObject *myCreateType = (PyXPCOM_TypeObject *)createType; +#else /* Since the mapIIDToType is only updated by us, there should be no need for the above. */ + PyXPCOM_TypeObject * const myCreateType = createType; +#endif + if (myCreateType->ctor==NULL) { + PyErr_SetString(PyExc_TypeError, "The type does not declare a PyCom constructor"); + return NULL; + } + + Py_nsISupports *ret = (*myCreateType->ctor)(pis, riid); +#ifdef _DEBUG_LIFETIMES + PyXPCOM_LogF("XPCOM Object created at 0x%0xld, nsISupports at 0x%0xld", + ret, ret->m_obj); +#endif + if (ret && bMakeNicePyObject) + return MakeDefaultWrapper(ret, riid); + return ret; +} + +// Call back into Python, passing a raw nsIInterface object, getting back +// the object to actually pass to Python. +PyObject * +Py_nsISupports::MakeDefaultWrapper(PyObject *pyis, + const nsIID &iid) +{ + NS_PRECONDITION(pyis, "NULL pyobject!"); + PyObject *obIID = NULL; + PyObject *args = NULL; + PyObject *mod = NULL; + PyObject *ret = NULL; + + obIID = Py_nsIID::PyObjectFromIID(iid); + if (obIID==NULL) + goto done; + + if (g_obFuncMakeInterfaceCount==NULL) { + PyObject *mod = PyImport_ImportModule("xpcom.client"); + if (mod) + g_obFuncMakeInterfaceCount = PyObject_GetAttrString(mod, "MakeInterfaceResult"); + Py_XDECREF(mod); + } + if (g_obFuncMakeInterfaceCount==NULL) goto done; + + args = Py_BuildValue("OO", pyis, obIID); + if (args==NULL) goto done; + ret = PyEval_CallObject(g_obFuncMakeInterfaceCount, args); +done: + if (PyErr_Occurred()) { + NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!"); + PyXPCOM_LogError("Creating an interface object to be used as a result failed\n"); + PyErr_Clear(); + } + Py_XDECREF(mod); + Py_XDECREF(args); + Py_XDECREF(obIID); + if (ret==NULL) // eek - error - return the original with no refcount mod. + ret = pyis; + else + // no error - decref the old object + Py_DECREF(pyis); + // return our obISupports. If NULL, we are really hosed and nothing we can do. + return ret; +} + +// @pymethod |Py_nsISupports|QueryInterface|Queries an object for a specific interface. +PyObject * +Py_nsISupports::QueryInterface(PyObject *self, PyObject *args) +{ + PyObject *obiid; + int bWrap = 1; + // @pyparm IID|iid||The IID requested. + // @rdesc The result is always a object. + // Any error (including E_NOINTERFACE) will generate a exception. + if (!PyArg_ParseTuple(args, "O|i:QueryInterface", &obiid, &bWrap)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obiid, &iid)) + return NULL; + + nsISupports *pMyIS = GetI(self); + if (pMyIS==NULL) return NULL; + + // Optimization, If we already wrap the IID, just return + // ourself. + if (!bWrap && iid.Equals(((Py_nsISupports *)self)->m_iid)) { + Py_INCREF(self); + return self; + } + + nsCOMPtr pis; + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = pMyIS->QueryInterface(iid, getter_AddRefs(pis)); + Py_END_ALLOW_THREADS; + + /* Note that this failure may include E_NOINTERFACE */ + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + /* Return a type based on the IID (with no extra ref) */ + return ((Py_nsISupports *)self)->MakeInterfaceResult(pis, iid, (PRBool)bWrap); +} + + +#ifdef VBOX +static PyObject * +QueryErrorObject(PyObject *self, PyObject *args) +{ + nsresult rc = 0; + + if (!PyArg_ParseTuple(args, "i", &rc)) + return NULL; + + return PyXPCOM_BuildErrorMessage(rc); +} +#endif + +// @object Py_nsISupports|The base object for all PythonCOM objects. Wraps a COM nsISupports interface. +/*static*/ struct PyMethodDef +Py_nsISupports::methods[] = +{ + { "queryInterface", Py_nsISupports::QueryInterface, 1, "Queries the object for an interface."}, + { "QueryInterface", Py_nsISupports::QueryInterface, 1, "An alias for queryInterface."}, +#ifdef VBOX + { "QueryErrorObject", QueryErrorObject, 1, "Query an error object for given status code."}, +#endif + {NULL} +}; + +/*static*/void Py_nsISupports::InitType(void) +{ + type = new PyXPCOM_TypeObject( + "nsISupports", + NULL, + sizeof(Py_nsISupports), + methods, + Constructor); +} + +PyXPCOM_TypeObject *Py_nsISupports::type = NULL; +PyObject *Py_nsISupports::mapIIDToType = NULL; diff --git a/src/libs/xpcom18a4/python/src/PyIVariant.cpp b/src/libs/xpcom18a4/python/src/PyIVariant.cpp new file mode 100644 index 00000000..cd9f79c4 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyIVariant.cpp @@ -0,0 +1,231 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * Mark Hammond. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written April 2002 + +#include "PyXPCOM_std.h" +#include "nsIVariant.h" + +// Prevents us needing to use an nsIScriptableInputStream +// (and even that can't read binary data!!!) + +static nsIVariant *GetI(PyObject *self) { + nsIID iid = NS_GET_IID(nsIVariant); + + if (!Py_nsISupports::Check(self, iid)) { + PyErr_SetString(PyExc_TypeError, "This object is not the correct interface"); + return NULL; + } + return (nsIVariant *)Py_nsISupports::GetI(self); +} + +static PyObject *MyBool( PRBool v) { + PyObject *ret = v ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} +static PyObject *MyChar( char c) { +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize(&c, 1); +#else + return PyUnicode_FromStringAndSize(&c, 1); +#endif +} +static PyObject *MyUChar( PRUnichar c) { + return PyObject_FromNSString( &c, 1); +} +static PyObject *MyUnicode( PRUnichar *p) { + return PyObject_FromNSString(p); +} + +#define GET_SIMPLE(Type, FuncGet, FuncConvert) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; \ + nsresult nr = pI->FuncGet(&t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + return FuncConvert(t); \ +} + +#define GET_ALLOCATED(Type, FuncGet, FuncConvert, FuncFree) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; \ + nsresult nr = pI->FuncGet(&t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + PyObject *ret = FuncConvert(t); \ + FuncFree(t); \ + return ret; \ +} + +#define GET_ALLOCATED_SIZE(Type, FuncGet, FuncConvert, FuncFree) \ +static PyObject *FuncGet(PyObject *self, PyObject *args) { \ + nsIVariant *pI = GetI(self); \ + if (pI==NULL) return NULL; \ + if (!PyArg_ParseTuple(args, ":" #FuncGet)) return NULL; \ + Type t; PRUint32 size; \ + nsresult nr = pI->FuncGet(&size, &t); \ + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); \ + PyObject *ret = FuncConvert(t, size); \ + FuncFree(t); \ + return ret; \ +} + +GET_SIMPLE(PRUint8, GetAsInt8, PyInt_FromLong) +GET_SIMPLE(PRUint8, GetAsUint8, PyInt_FromLong) +GET_SIMPLE(PRInt16, GetAsInt16, PyInt_FromLong) +GET_SIMPLE(PRUint16, GetAsUint16, PyInt_FromLong) +GET_SIMPLE(PRInt32, GetAsInt32, PyInt_FromLong) +GET_SIMPLE(PRUint32, GetAsUint32, PyInt_FromLong) +GET_SIMPLE(PRInt64, GetAsInt64, PyLong_FromLongLong) +GET_SIMPLE(PRUint64, GetAsUint64, PyLong_FromUnsignedLongLong) +GET_SIMPLE(float, GetAsFloat, PyFloat_FromDouble) +GET_SIMPLE(double, GetAsDouble, PyFloat_FromDouble) +GET_SIMPLE(PRBool, GetAsBool, MyBool) +GET_SIMPLE(char, GetAsChar, MyChar) +GET_SIMPLE(PRUnichar, GetAsWChar, MyUChar) +GET_SIMPLE(nsIID, GetAsID, Py_nsIID::PyObjectFromIID) + +#if PY_MAJOR_VERSION <= 2 +GET_ALLOCATED(char *, GetAsString, PyString_FromString, nsMemory::Free) +#else +GET_ALLOCATED(char *, GetAsString, PyUnicode_FromString, nsMemory::Free) +#endif +GET_ALLOCATED(PRUnichar *, GetAsWString, MyUnicode, nsMemory::Free) +#if PY_MAJOR_VERSION <= 2 +GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyString_FromStringAndSize, nsMemory::Free) +#else +GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyUnicode_FromStringAndSize, nsMemory::Free) +#endif +GET_ALLOCATED_SIZE(PRUnichar *, GetAsWStringWithSize, PyObject_FromNSString, nsMemory::Free) + +static PyObject *GetAsInterface(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; + nsCOMPtr p; + nsIID *iid; + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + return Py_nsISupports::PyObjectFromInterface(p, *iid); +} + +static PyObject *GetAsISupports(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; + nsCOMPtr p; + nsIID *iid; + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + return Py_nsISupports::PyObjectFromInterface(p, *iid); +} + +extern PyObject *PyObject_FromVariantArray( Py_nsISupports*, nsIVariant *v); + +static PyObject *GetAsArray(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsArray")) return NULL; + return PyObject_FromVariantArray((Py_nsISupports *)self, pI); +} + +static PyObject *Get(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":Get")) return NULL; + return PyObject_FromVariant((Py_nsISupports *)self, pI); +} + +struct PyMethodDef +PyMethods_IVariant[] = +{ + { "getAsInt8", GetAsInt8, 1}, + { "getAsUint8", GetAsUint8, 1}, + { "getAsInt16", GetAsInt16, 1}, + { "getAsUint16", GetAsUint16, 1}, + { "getAsInt32", GetAsInt32, 1}, + { "getAsUint32", GetAsUint32, 1}, + { "getAsInt64", GetAsInt64, 1}, + { "getAsUint64", GetAsUint64, 1}, + { "getAsFloat", GetAsFloat, 1}, + { "getAsDouble", GetAsDouble, 1}, + { "getAsBool", GetAsBool, 1}, + { "getAsChar", GetAsChar, 1}, + { "getAsWChar", GetAsWChar, 1}, + { "getAsString", GetAsString, 1}, + { "getAsWString", GetAsWString, 1}, + { "getAsStringWithSize", GetAsStringWithSize, 1}, + { "getAsWStringWithSize", GetAsWStringWithSize, 1}, + { "getAsISupports", GetAsISupports, 1}, + { "getAsInterface", GetAsInterface, 1}, + { "getAsArray", GetAsArray, 1}, + { "getAsID", GetAsID, 1}, + { "get", Get, 1}, + {NULL} +}; + +PyObject * +Py_nsIVariant::getattr(const char *name) +{ + + PyObject *ret = NULL; + if (strcmp(name, "dataType")==0) { + nsIVariant *pI = ::GetI(this); + if (pI) { + PRUint16 dt; + nsresult nr = pI->GetDataType(&dt); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + ret = PyInt_FromLong(dt); + } + } else { + ret = Py_nsISupports::getattr(name); + } + return ret; +} + +int +Py_nsIVariant::setattr(const char *name, PyObject *v) +{ + return Py_nsISupports::setattr(name, v); +} diff --git a/src/libs/xpcom18a4/python/src/PyXPCOM.h b/src/libs/xpcom18a4/python/src/PyXPCOM.h new file mode 100644 index 00000000..91bc8d12 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyXPCOM.h @@ -0,0 +1,1036 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// PyXPCOM.h - the main header file for the Python XPCOM support. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#ifndef __PYXPCOM_H__ +#define __PYXPCOM_H__ + +#include "nsIAllocator.h" +#include "nsIWeakReference.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIClassInfo.h" +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsIInputStream.h" +#include "nsIVariant.h" +#include "nsIModule.h" + +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "xptcall.h" +#include "xpt_xdr.h" + +#ifdef VBOX_DEBUG_LIFETIMES +# include +# include +# include +#endif + +#ifdef HAVE_LONG_LONG + // Mozilla also defines this - we undefine it to + // prevent a compiler warning. +# undef HAVE_LONG_LONG +#endif // HAVE_LONG_LONG + +#ifdef _POSIX_C_SOURCE // Ditto here +# undef _POSIX_C_SOURCE +#endif // _POSIX_C_SOURCE + +#ifdef VBOX_PYXPCOM +// unfortunatelly, if SOLARIS is defined Python porting layer +// defines gethostname() in invalid fashion what kills compilation +# ifdef SOLARIS +# undef SOLARIS +# define SOLARIS_WAS_DEFINED +# endif + +// Python.h/pyconfig.h redefines _XOPEN_SOURCE on some hosts +# ifdef _XOPEN_SOURCE +# define VBOX_XOPEN_SOURCE_DEFINED _XOPEN_SOURCE +# undef _XOPEN_SOURCE +# endif + +#endif /* VBOX_PYXPCOM */ + +#include + +#ifdef VBOX_PYXPCOM + +# ifdef SOLARIS_WAS_DEFINED +# define SOLARIS +# undef SOLARIS_WAS_DEFINED +# endif + +// restore the old value of _XOPEN_SOURCE if not defined by Python.h/pyconfig.h +# if !defined(_XOPEN_SOURCE) && defined(VBOX_XOPEN_SOURCE_DEFINED) +# define _XOPEN_SOURCE VBOX_XOPEN_SOURCE_DEFINED +# endif +# undef VBOX_XOPEN_SOURCE_DEFINED + +# if (PY_VERSION_HEX <= 0x02040000) +// although in more recent versions of Python this type is ssize_t, earlier +// it was used as int +typedef int Py_ssize_t; +# endif + +# if (PY_VERSION_HEX <= 0x02030000) +// this one not defined before +inline PyObject *PyBool_FromLong(long ok) +{ + PyObject *result; + if (ok) + result = Py_True; + else + result = Py_False; + Py_INCREF(result); + return result; +} +# endif + +# if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong(l) PyLong_FromLong(l) +# define PyInt_Check(o) PyLong_Check(o) +# define PyInt_AsLong(o) PyLong_AsLong(o) +# define PyNumber_Int(o) PyNumber_Long(o) +# if !defined(Py_LIMITED_API) && PY_VERSION_HEX <= 0x03030000 /* 3.3 added PyUnicode_AsUTF8AndSize */ +# ifndef PyUnicode_AsUTF8 +# define PyUnicode_AsUTF8(o) _PyUnicode_AsString(o) +# endif +# ifndef PyUnicode_AsUTF8AndSize +# define PyUnicode_AsUTF8AndSize(o,s) _PyUnicode_AsStringAndSize(o,s) +# endif +# endif +typedef struct PyMethodChain +{ + PyMethodDef *methods; + struct PyMethodChain *link; +} PyMethodChain; +# endif + +#endif /* VBOX_PYXPCOM */ + +#ifdef BUILD_PYXPCOM + /* We are building the main dll */ +# define PYXPCOM_EXPORT NS_EXPORT +#else + /* This module uses the dll */ +# define PYXPCOM_EXPORT NS_IMPORT +#endif // BUILD_PYXPCOM + +// An IID we treat as NULL when passing as a reference. +extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL; + +class Py_nsISupports; + + +/** @name VBox limited API hacks: + * @{ */ +#ifndef Py_LIMITED_API + +# define PyXPCOM_ObTypeName(obj) (Py_TYPE(obj)->tp_name) + +#else /* Py_LIMITED_API */ + +# if PY_VERSION_HEX <= 0x03030000 +# error "Py_LIMITED_API mode only works for Python 3.3 and higher." +# endif + +const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj); +# define PyXPCOM_ObTypeName(obj) PyXPCOMGetObTypeName(Py_TYPE(obj)) + +# if Py_LIMITED_API < 0x030A0000 +/* Note! While we should not technically be using PyUnicode_AsUTF8AndSize, it was + made part of the limited API in 3.10 (see https://bugs.python.org/issue41784 and + https://github.com/python/cpython/commit/a05195ac61f1908ac5990cccb5aa82442bdaf15d). */ +extern "C" PyAPI_FUNC(const char *) PyUnicode_AsUTF8AndSize(PyObject *, Py_ssize_t *); +# endif + +/* PyUnicode_AsUTF8 is just PyUnicode_AsUTF8AndSize without returning a size. */ +# define PyUnicode_AsUTF8(o) PyUnicode_AsUTF8AndSize(o, NULL) + +DECLINLINE(int) PyRun_SimpleString(const char *pszCode) +{ + /* Get the main mode dictionary: */ + PyObject *pMainMod = PyImport_AddModule("__main__"); + if (pMainMod) { + PyObject *pMainModDict = PyModule_GetDict(pMainMod); + + /* Compile and run the code. */ + PyObject *pCodeObject = Py_CompileString(pszCode, "PyXPCOM", Py_file_input); + if (pCodeObject) { + PyObject *pResult = PyEval_EvalCode(pCodeObject, pMainModDict, pMainModDict); + Py_DECREF(pCodeObject); + if (pResult) { + Py_DECREF(pResult); + return 0; + } + PyErr_Print(); + } + } + return -1; +} + +DECLINLINE(PyObject *) PyTuple_GET_ITEM(PyObject *pTuple, Py_ssize_t idx) +{ + return PyTuple_GetItem(pTuple, idx); +} + +DECLINLINE(int) PyTuple_SET_ITEM(PyObject *pTuple, Py_ssize_t idx, PyObject *pItem) +{ + int rc = PyTuple_SetItem(pTuple, idx, pItem); /* Steals pItem ref, just like PyTuple_SET_ITEM. */ + Assert(rc == 0); + return rc; +} + +DECLINLINE(int) PyList_SET_ITEM(PyObject *pList, Py_ssize_t idx, PyObject *pItem) +{ + int rc = PyList_SetItem(pList, idx, pItem); /* Steals pItem ref, just like PyList_SET_ITEM. */ + Assert(rc == 0); + return rc; +} + +DECLINLINE(Py_ssize_t) PyBytes_GET_SIZE(PyObject *pBytes) +{ + return PyBytes_Size(pBytes); +} + +DECLINLINE(const char *) PyBytes_AS_STRING(PyObject *pBytes) +{ + return PyBytes_AsString(pBytes); +} + +DECLINLINE(Py_ssize_t) PyUnicode_GET_SIZE(PyObject *pUnicode) +{ + /* Note! Currently only used for testing for zero or 1 codepoints, so we don't + really need to deal with the different way these two treats surrogate pairs. */ +# if Py_LIMITED_API >= 0x03030000 + return PyUnicode_GetLength(pUnicode); +# else + return PyUnicode_GetSize(pUnicode); +# endif +} + +# define PyObject_CheckBuffer(pAllegedBuffer) PyObject_CheckReadBuffer(pAllegedBuffer) + +# include +DECLINLINE(Py_hash_t) _Py_HashPointer(void *p) +{ + Py_hash_t uHash = (Py_hash_t)RT_CONCAT(ASMRotateRightU,ARCH_BITS)((uintptr_t)p, 4); + return uHash != -1 ? uHash : -2; +} + +#endif /* Py_LIMITED_API */ +/** @} */ + + +/************************************************************************* +************************************************************************** + + Error and exception related function. + +************************************************************************** +*************************************************************************/ + +#define NS_PYXPCOM_NO_SUCH_METHOD \ + NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_PYXPCOM, 0) + +// The exception object (loaded from the xpcom .py code) +extern PYXPCOM_EXPORT PyObject *PyXPCOM_Error; + +// Client related functions - generally called by interfaces before +// they return NULL back to Python to indicate the error. +// All these functions return NULL so interfaces can generally +// just "return PyXPCOM_BuildPyException(hr, punk, IID_IWhatever)" +PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res); + +#ifdef VBOX +// Build human readable error message out of XPCOM error +PYXPCOM_EXPORT PyObject *PyXPCOM_BuildErrorMessage(nsresult r); +#endif + +// Used in gateways to handle the current Python exception +// NOTE: this function assumes it is operating within the Python context +PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException(); + +// Write current exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatCurrentException(nsCString &streamout); +// Write specified exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb); + +// A couple of logging/error functions. These probably end up +// being written to the console service. + +// Log a warning for the user - something at runtime +// they may care about, but nothing that prevents us actually +// working. +// As it's designed for user error/warning, it exists in non-debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...); + +// Log an error for the user - something that _has_ prevented +// us working. This is probably accompanied by a traceback. +// As it's designed for user error/warning, it exists in non-debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...); + +// The raw one +PYXPCOM_EXPORT void PyXPCOM_Log(const char *level, const nsCString &msg); + +#ifdef DEBUG +// Mainly designed for developers of the XPCOM package. +// Only enabled in debug builds. +PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...); +#define PYXPCOM_LOG_DEBUG PyXPCOM_LogDebug +#else +#define PYXPCOM_LOG_DEBUG() +#endif // DEBUG + +// Some utility converters +// moz strings to PyObject. +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsACString &s, + PRBool bAssumeUTF8 = PR_FALSE ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsAString &s ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len = (PRUint32)-1); + +// PyObjects to moz strings. As per the moz string guide, we pass a reference +// to an abstract string +PYXPCOM_EXPORT PRBool PyObject_AsNSString( PyObject *ob, nsAString &aStr); + +// Variants. +PYXPCOM_EXPORT nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet); +PYXPCOM_EXPORT PyObject *PyObject_FromVariant( Py_nsISupports *parent, + nsIVariant *v); + +// Interfaces - these are the "official" functions +PYXPCOM_EXPORT PyObject *PyObject_FromNSInterface( nsISupports *aInterface, + const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE); + +/************************************************************************* +************************************************************************** + + Support for CALLING (ie, using) interfaces. + +************************************************************************** +*************************************************************************/ + +typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &); + +////////////////////////////////////////////////////////////////////////// +// class PyXPCOM_TypeObject +// Base class for (most of) the type objects. + +#ifndef Py_LIMITED_API +class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyTypeObject { +#else +class PYXPCOM_EXPORT PyXPCOM_TypeObject : public PyObject { +#endif +public: + PyXPCOM_TypeObject( + const char *name, + PyXPCOM_TypeObject *pBaseType, + int typeSize, + struct PyMethodDef* methodList, + PyXPCOM_I_CTOR ctor); + ~PyXPCOM_TypeObject(); + + PyMethodChain chain; + PyXPCOM_TypeObject *baseType; + PyXPCOM_I_CTOR ctor; + + static PRBool IsType(PyTypeObject *t); + // Static methods for the Python type. + static void Py_dealloc(PyObject *ob); + static PyObject *Py_repr(PyObject *ob); + static PyObject *Py_str(PyObject *ob); + static PyObject *Py_getattr(PyObject *self, char *name); + static int Py_setattr(PyObject *op, char *name, PyObject *v); + static int Py_cmp(PyObject *ob1, PyObject *ob2); + static PyObject *Py_richcmp(PyObject *ob1, PyObject *ob2, int op); +#if PY_VERSION_HEX >= 0x03020000 + static Py_hash_t Py_hash(PyObject *self); +#else + static long Py_hash(PyObject *self); +#endif +#ifdef Py_LIMITED_API + PyTypeObject *m_pTypeObj; /**< The python type object we wrap. */ +#endif +}; + +////////////////////////////////////////////////////////////////////////// +// class Py_nsISupports +// This class serves 2 purposes: +// * It is a base class for other interfaces we support "natively" +// * It is instantiated for _all_ other interfaces. +// +// This is different than win32com, where a PyIUnknown only +// ever holds an IUnknown - but here, we could be holding +// _any_ interface. +class PYXPCOM_EXPORT Py_nsISupports : public PyObject +{ +public: + // Check if a Python object can safely be cast to an Py_nsISupports, + // and optionally check that the object is wrapping the specified + // interface. + static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) { + Py_nsISupports *self = static_cast(ob); + if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type )) + return PR_FALSE; + if (!checkIID.Equals(Py_nsIID_NULL)) + return self->m_iid.Equals(checkIID) != 0; + return PR_TRUE; + } + // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED + static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL); + nsCOMPtr m_obj; + nsIID m_iid; +#ifdef Py_LIMITED_API + /** Because PyXPCOM_TypeObject cannot inherit from PyTypeObject in + * Py_LIMITED_API mode, we cannot use ob_type to get to the method list. + * Instead of we store it here. */ + PyXPCOM_TypeObject *m_pMyTypeObj; +#endif + + // Given an nsISupports and an Interface ID, create and return an object + // Does not QI the object - the caller must ensure the nsISupports object + // is really a pointer to an object identified by the IID (although + // debug builds should check this) + // PRBool bMakeNicePyObject indicates if we should call back into + // Python to wrap the object. This allows Python code to + // see the correct xpcom.client.Interface object even when calling + // xpcom functions directly from C++. + // NOTE: There used to be a bAddRef param to this as an internal + // optimization, but since removed. This function *always* takes a + // reference to the nsISupports. + static PyObject *PyObjectFromInterface(nsISupports *ps, + const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE, + PRBool bIsInternalCall = PR_FALSE); + + // Given a Python object that is a registered COM type, return a given + // interface pointer on its underlying object, with a NEW REFERENCE ADDED. + // bTryAutoWrap indicates if a Python instance object should attempt to + // be automatically wrapped in an XPCOM object. This is really only + // provided to stop accidental recursion should the object returned by + // the wrap process itself be in instance (where it should already be + // a COM object. + // If |iid|==nsIVariant, then arbitary Python objects will be wrapped + // in an nsIVariant. + static PRBool InterfaceFromPyObject( + PyObject *ob, + const nsIID &iid, + nsISupports **ppret, + PRBool bNoneOK, + PRBool bTryAutoWrap = PR_TRUE); + + // Given a Py_nsISupports, return an interface. + // Object *must* be Py_nsISupports - there is no + // "autowrap", no "None" support, etc + static PRBool InterfaceFromPyISupports(PyObject *ob, + const nsIID &iid, + nsISupports **ppv); + + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid); + // The Python methods + static PyObject *QueryInterface(PyObject *self, PyObject *args); + + // Internal (sort-of) objects. + static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type; + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; + static PyObject *mapIIDToType; + static void SafeRelease(Py_nsISupports *ob); +#ifndef Py_LIMITED_API + static void RegisterInterface( const nsIID &iid, PyTypeObject *t); +#else + static void RegisterInterface( const nsIID &iid, PyXPCOM_TypeObject *t); +#endif + static void InitType(); +#ifdef VBOX_DEBUG_LIFETIMES + static void dumpList(void); + static void dumpListToStdOut(void); +#endif + + virtual ~Py_nsISupports(); + virtual PyObject *getattr(const char *name); + virtual int setattr(const char *name, PyObject *val); + // A virtual function to sub-classes can customize the way + // nsISupports objects are returned from their methods. + // ps is a new object just obtained from some operation performed on us + virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE) { + return PyObjectFromInterface(ps, iid, bMakeNicePyObject); + } + +protected: + // ctor is protected - must create objects via + // PyObjectFromInterface() + Py_nsISupports(nsISupports *p, + const nsIID &iid, +#ifndef Py_LIMITED_API + PyTypeObject *type); +#else + PyXPCOM_TypeObject *type); +#endif + + // Make a default wrapper for an ISupports (which is an + // xpcom.client.Component instance) + static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid); + +#ifdef VBOX_DEBUG_LIFETIMES + static DECLCALLBACK(int32_t) initOnceCallback(void *pvUser1); + + RTLISTNODE m_ListEntry; /**< List entry. */ + + static RTONCE g_Once; /**< Init list and critsect once. */ + static RTCRITSECT g_CritSect; /**< Critsect protecting the list. */ + static RTLISTANCHOR g_List; /**< List of live interfaces.*/ +#endif +}; + +// Python/XPCOM IID support +class PYXPCOM_EXPORT Py_nsIID : public PyObject +{ +public: + Py_nsIID(const nsIID &riid); + nsIID m_iid; + + PRBool + IsEqual(const nsIID &riid) { + return m_iid.Equals(riid); + } + + PRBool + IsEqual(PyObject *ob) { + return ob && +#ifndef Py_LIMITED_API + ob->ob_type== &type && +#else + ob->ob_type == s_pType && +#endif + m_iid.Equals(((Py_nsIID *)ob)->m_iid); + } + + PRBool + IsEqual(Py_nsIID &iid) { + return m_iid.Equals(iid.m_iid); + } + + static PyObject * + PyObjectFromIID(const nsIID &iid) { + return new Py_nsIID(iid); + } + + static PRBool IIDFromPyObject(PyObject *ob, nsIID *pRet); + /* Python support */ + static PyObject *PyTypeMethod_getattr(PyObject *self, char *name); +#if PY_MAJOR_VERSION <= 2 + static int PyTypeMethod_compare(PyObject *self, PyObject *ob); +#endif + static PyObject *PyTypeMethod_richcompare(PyObject *self, PyObject *ob, int op); + static PyObject *PyTypeMethod_repr(PyObject *self); +#if PY_VERSION_HEX >= 0x03020000 + static Py_hash_t PyTypeMethod_hash(PyObject *self); +#else + static long PyTypeMethod_hash(PyObject *self); +#endif + static PyObject *PyTypeMethod_str(PyObject *self); + static void PyTypeMethod_dealloc(PyObject *self); +#ifndef Py_LIMITED_API + static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type; +#else + static NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) s_pType; + static PyTypeObject *GetTypeObject(void); +#endif + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; +}; + +/////////////////////////////////////////////////////// +// +// Helper classes for managing arrays of variants. +class PythonTypeDescriptor; // Forward declare. + +class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper { +public: + PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent, int methodindex); + ~PyXPCOM_InterfaceVariantHelper(); + PRBool Init(PyObject *obParams); + PRBool FillArray(); + + PyObject *MakePythonResult(); + + nsXPTCVariant *m_var_array; + int m_num_array; + int m_methodindex; +protected: + PyObject *MakeSinglePythonResult(int index); + PRBool FillInVariant(const PythonTypeDescriptor &, int, int); + PRBool PrepareOutVariant(const PythonTypeDescriptor &td, int value_index); + PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size); + PRUint32 GetSizeIs( int var_index, PRBool is_arg1); + + PyObject *m_pyparams; // sequence of actual params passed (ie, not including hidden) + PyObject *m_typedescs; // desc of _all_ params, including hidden. + PythonTypeDescriptor *m_python_type_desc_array; + void **m_buffer_array; + Py_nsISupports *m_parent; + +}; + +/************************************************************************* +************************************************************************** + + Support for IMPLEMENTING interfaces. + +************************************************************************** +*************************************************************************/ +#define NS_IINTERNALPYTHON_IID_STR "AC7459FC-E8AB-4f2e-9C4F-ADDC53393A20" +#define NS_IINTERNALPYTHON_IID \ + { 0xac7459fc, 0xe8ab, 0x4f2e, { 0x9c, 0x4f, 0xad, 0xdc, 0x53, 0x39, 0x3a, 0x20 } } + +class PyXPCOM_GatewayWeakReference; + +// This interface is needed primarily to give us a known vtable base. +// If we QI a Python object for this interface, we can safely cast the result +// to a PyG_Base. Any other interface, we do now know which vtable we will get. +// We also allow the underlying PyObject to be extracted +class nsIInternalPython : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IINTERNALPYTHON_IID) + // Get the underlying Python object with new reference added + virtual PyObject *UnwrapPythonObject(void) = 0; +}; + +// This is roughly equivalent to PyGatewayBase in win32com +// +class PYXPCOM_EXPORT PyG_Base : public nsIInternalPython, public nsISupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSWEAKREFERENCE + PyObject *UnwrapPythonObject(void); + + // A static "constructor" - the real ctor is protected. + static nsresult CreateNew(PyObject *pPyInstance, + const nsIID &iid, + void **ppResult); + + // A utility to auto-wrap an arbitary Python instance + // in a COM gateway. + static PRBool AutoWrapPythonInstance(PyObject *ob, + const nsIID &iid, + nsISupports **ppret); + + + // A helper that creates objects to be passed for nsISupports + // objects. See extensive comments in PyG_Base.cpp. + PyObject *MakeInterfaceParam(nsISupports *pis, + const nsIID *piid, + int methodIndex = -1, + const XPTParamDescriptor *d = NULL, + int paramIndex = -1); + + // A helper that ensures all casting and vtable offsetting etc + // done against this object happens in the one spot! + virtual void *ThisAsIID( const nsIID &iid ) = 0; + + // Helpers for "native" interfaces. + // Not used by the generic stub interface. + nsresult HandleNativeGatewayError(const char *szMethodName); + + // These data members used by the converter helper functions - hence public + nsIID m_iid; + PyObject * m_pPyObject; + // We keep a reference count on this object, and the object + // itself uses normal refcount rules - thus, it will only + // die when we die, and all external references are removed. + // This means that once we have created it (and while we + // are alive) it will never die. + nsCOMPtr m_pWeakRef; +#ifdef NS_BUILD_REFCNT_LOGGING + char refcntLogRepr[64]; // sigh - I wish I knew how to use the Moz string classes :( OK for debug only tho. +#endif +protected: + PyG_Base(PyObject *instance, const nsIID &iid); + virtual ~PyG_Base(); + PyG_Base *m_pBaseObject; // A chain to implement identity rules. + nsresult InvokeNativeViaPolicy( const char *szMethodName, + PyObject **ppResult = NULL, + const char *szFormat = NULL, + ... + ); + nsresult InvokeNativeViaPolicyInternal( const char *szMethodName, + PyObject **ppResult, + const char *szFormat, + va_list va); + nsresult InvokeNativeGetViaPolicy(const char *szPropertyName, + PyObject **ppResult = NULL + ); + nsresult InvokeNativeSetViaPolicy(const char *szPropertyName, + ...); +}; + +class PYXPCOM_EXPORT PyXPCOM_XPTStub : public PyG_Base, public nsXPTCStubBase +{ +friend class PyG_Base; +public: + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \ + {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \ + NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \ + NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \ + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info); + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params); + + virtual void *ThisAsIID(const nsIID &iid); +protected: + PyXPCOM_XPTStub(PyObject *instance, const nsIID &iid) : PyG_Base(instance, iid) {;} +private: +}; + +// For the Gateways we manually implement. +#define PYGATEWAY_BASE_SUPPORT(INTERFACE, GATEWAY_BASE) \ + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) \ + {return PyG_Base::QueryInterface(aIID, aInstancePtr);} \ + NS_IMETHOD_(nsrefcnt) AddRef(void) {return PyG_Base::AddRef();} \ + NS_IMETHOD_(nsrefcnt) Release(void) {return PyG_Base::Release();} \ + virtual void *ThisAsIID(const nsIID &iid) { \ + if (iid.Equals(NS_GET_IID(INTERFACE))) return (INTERFACE *)this; \ + return GATEWAY_BASE::ThisAsIID(iid); \ + } \ + +extern PYXPCOM_EXPORT void AddDefaultGateway(PyObject *instance, nsISupports *gateway); + +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetGatewayCount(void); +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetInterfaceCount(void); +#ifdef VBOX_DEBUG_LIFETIMES +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_DumpInterfaces(void); +#endif + + +// Weak Reference class. This is a true COM object, representing +// a weak reference to a Python object. For each Python XPCOM object, +// there is exactly zero or one corresponding weak reference instance. +// When both are alive, each holds a pointer to the other. When the main +// object dies due to XPCOM reference counting, it zaps the pointer +// in its corresponding weak reference object. Thus, the weak-reference +// can live beyond the object (possibly with a NULL pointer back to the +// "real" object, but as implemented, the weak reference will never be +// destroyed before the object +class PYXPCOM_EXPORT PyXPCOM_GatewayWeakReference : public nsIWeakReference { +public: + PyXPCOM_GatewayWeakReference(PyG_Base *base); + virtual ~PyXPCOM_GatewayWeakReference(); + NS_DECL_ISUPPORTS + NS_DECL_NSIWEAKREFERENCE + PyG_Base *m_pBase; // NO REF COUNT!!! +#ifdef NS_BUILD_REFCNT_LOGGING + char refcntLogRepr[41]; +#endif +}; + + +// Helpers classes for our gateways. +class PYXPCOM_EXPORT PyXPCOM_GatewayVariantHelper +{ +public: + PyXPCOM_GatewayVariantHelper( PyG_Base *gateway, + int methodIndex, + const nsXPTMethodInfo *info, + nsXPTCMiniVariant* params ); + ~PyXPCOM_GatewayVariantHelper(); + PyObject *MakePyArgs(); + nsresult ProcessPythonResult(PyObject *ob); + PyG_Base *m_gateway; +private: + nsresult BackFillVariant( PyObject *ob, int index); + PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td); + PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret); + nsresult GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **ppiid); + PRUint32 GetSizeIs( int var_index, PRBool is_arg1); + PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size); + PRBool CanSetSizeIs( int var_index, PRBool is_arg1 ); + nsIInterfaceInfo *GetInterfaceInfo(); // NOTE: no ref count on result. + + + nsXPTCMiniVariant* m_params; + const nsXPTMethodInfo *m_info; + int m_method_index; + PythonTypeDescriptor *m_python_type_desc_array; + int m_num_type_descs; + nsCOMPtr m_interface_info; +}; + +// Misc converters. +PyObject *PyObject_FromXPTType( const nsXPTType *d); +// XPTTypeDescriptor derived from XPTType - latter is automatically processed via PyObject_FromXPTTypeDescriptor XPTTypeDescriptor +PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d); + +PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d); +PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d); +PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d); + +// DLL reference counting functions. +// Although we maintain the count, we never actually +// finalize Python when it hits zero! +void PyXPCOM_DLLAddRef(); +void PyXPCOM_DLLRelease(); + +/************************************************************************* +************************************************************************** + + LOCKING AND THREADING + +************************************************************************** +*************************************************************************/ + +// +// We have 2 discrete locks in use (when no free-threaded is used, anyway). +// The first type of lock is the global Python lock. This is the standard lock +// in use by Python, and must be used as documented by Python. Specifically, no +// 2 threads may _ever_ call _any_ Python code (including INCREF/DECREF) without +// first having this thread lock. +// +// The second type of lock is a "global framework lock", and used whenever 2 threads +// of C code need access to global data. This is different than the Python +// lock - this lock is used when no Python code can ever be called by the +// threads, but the C code still needs thread-safety. + +// We also supply helper classes which make the usage of these locks a one-liner. + +// The "framework" lock, implemented as a PRLock +PYXPCOM_EXPORT void PyXPCOM_AcquireGlobalLock(void); +PYXPCOM_EXPORT void PyXPCOM_ReleaseGlobalLock(void); + +// Helper class for the DLL global lock. +// +// This class magically waits for PyXPCOM framework global lock, and releases it +// when finished. +// NEVER new one of these objects - only use on the stack! +class CEnterLeaveXPCOMFramework { +public: + CEnterLeaveXPCOMFramework() {PyXPCOM_AcquireGlobalLock();} + ~CEnterLeaveXPCOMFramework() {PyXPCOM_ReleaseGlobalLock();} +}; + +// Python thread-lock stuff. Free-threading patches use different semantics, but +// these are abstracted away here... +//#include + +// Helper class for Enter/Leave Python +// +// This class magically waits for the Python global lock, and releases it +// when finished. + +// Nested invocations will deadlock, so be careful. + +// NEVER new one of these objects - only use on the stack! + +PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls(); +PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure(); + +// For 2.3, use the PyGILState_ calls +#if (PY_VERSION_HEX >= 0x02030000) +#define PYXPCOM_USE_PYGILSTATE +#endif + +#ifdef PYXPCOM_USE_PYGILSTATE +class CEnterLeavePython { +public: + CEnterLeavePython() { + state = PyGILState_Ensure(); + // See "pending calls" comment below. We reach into the Python + // implementation to see if we are the first call on the stack. +# ifndef Py_LIMITED_API + if (PyThreadState_Get()->gilstate_counter==1) { +# else + if (state == PyGILState_UNLOCKED) { +# endif + PyXPCOM_MakePendingCalls(); + } + } + ~CEnterLeavePython() { + PyGILState_Release(state); + } + PyGILState_STATE state; +}; +#else + +extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState; +PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release(); + +// Pre 2.3 thread-state dances. +class CEnterLeavePython { +public: + CEnterLeavePython() { + created = PyXPCOM_ThreadState_Ensure(); + PyXPCOM_InterpreterLock_Acquire(); + if (created) { + // If pending python calls are waiting as we enter Python, + // it will generally mean an asynch signal handler, etc. + // We can either call it here, or wait for Python to call it + // as part of its "even 'n' opcodes" check. If we wait for + // Python to check it and the pending call raises an exception, + // then it is _our_ code that will fail - this is unfair, + // as the signal was raised before we were entered - indeed, + // we may be directly responding to the signal! + // Thus, we flush all the pending calls here, and report any + // exceptions via our normal exception reporting mechanism. + // We can then execute our code in the knowledge that only + // signals raised _while_ we are executing will cause exceptions. + PyXPCOM_MakePendingCalls(); + } + } + ~CEnterLeavePython() { + // The interpreter state must be cleared + // _before_ we release the lock, as some of + // the sys. attributes cleared (eg, the current exception) + // may need the lock to invoke their destructors - + // specifically, when exc_value is a class instance, and + // the exception holds the last reference! + if ( created ) + PyXPCOM_ThreadState_Clear(); + PyXPCOM_InterpreterLock_Release(); + if ( created ) + PyXPCOM_ThreadState_Free(); + } +private: + PRBool created; +}; +#endif // PYXPCOM_USE_PYGILSTATE + +// Our classes. +// Hrm - So we can't have templates, eh?? +// preprocessor to the rescue, I guess. +#define PyXPCOM_INTERFACE_DECLARE(ClassName, InterfaceName, Methods ) \ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType() { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ + } \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_INTERFACE_DECLARE macro + +#define PyXPCOM_ATTR_INTERFACE_DECLARE(ClassName, InterfaceName, Methods )\ + \ +extern struct PyMethodDef Methods[]; \ + \ +class ClassName : public Py_nsISupports \ +{ \ +public: \ + static PyXPCOM_TypeObject *type; \ + static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ + return new ClassName(pInitObj, iid); \ + } \ + static void InitType() { \ + type = new PyXPCOM_TypeObject( \ + #InterfaceName, \ + Py_nsISupports::type, \ + sizeof(ClassName), \ + Methods, \ + Constructor); \ + const nsIID &iid = NS_GET_IID(InterfaceName); \ + RegisterInterface(iid, type); \ +} \ + virtual PyObject *getattr(const char *name); \ + virtual int setattr(const char *name, PyObject *val); \ +protected: \ + ClassName(nsISupports *p, const nsIID &iid) : \ + Py_nsISupports(p, iid, type) { \ + /* The IID _must_ be the IID of the interface we are wrapping! */ \ + NS_ABORT_IF_FALSE(iid.Equals(NS_GET_IID(InterfaceName)), "Bad IID"); \ + } \ +}; \ + \ +// End of PyXPCOM_ATTR_INTERFACE_DECLARE macro + +#define PyXPCOM_INTERFACE_DEFINE(ClassName, InterfaceName, Methods ) \ +PyXPCOM_TypeObject *ClassName::type = NULL; + + +// And the classes +PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DECLARE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DECLARE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) +PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) +// deprecated, but retained for backward compatibility: +PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete) +#endif // __PYXPCOM_H__ diff --git a/src/libs/xpcom18a4/python/src/PyXPCOM_std.h b/src/libs/xpcom18a4/python/src/PyXPCOM_std.h new file mode 100644 index 00000000..b7b7ff8c --- /dev/null +++ b/src/libs/xpcom18a4/python/src/PyXPCOM_std.h @@ -0,0 +1,56 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// standard include - sets up all the defines used by +// the mozilla make process - too lazy to work out how to integrate +// with their make, so this will do! + +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +// This header is considered internal - hence +// we can use it to trigger "exports" +#define BUILD_PYXPCOM + +#include "PyXPCOM.h" diff --git a/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp b/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp new file mode 100644 index 00000000..d1df54fe --- /dev/null +++ b/src/libs/xpcom18a4/python/src/Pyxpt_info.cpp @@ -0,0 +1,197 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// Pyxpt_info.cpp - wrappers for the xpt_info objects. +// +// This code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. +#include "PyXPCOM_std.h" + +PyObject *PyObject_FromXPTType( const nsXPTType *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + // build an object using the same format as a TypeDescriptor. + return Py_BuildValue("bzzz", + d->flags, + NULL, NULL, NULL); +} + +PyObject *PyObject_FromXPTTypeDescriptor( const XPTTypeDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + return Py_BuildValue("bbbh", + d->prefix.flags, + d->argnum, + d->argnum2, + d->type.iface // this is actually a union! + ); +} + +PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob = PyObject_FromXPTTypeDescriptor(&d->type); + PyObject *ret = Py_BuildValue("bO", d->flags, ob); + Py_DECREF(ob); + return ret; +} + +PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d) +{ + if (d==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob_params = PyTuple_New(d->num_args); + if (ob_params==NULL) + return NULL; + for (int i=0;inum_args;i++) + PyTuple_SET_ITEM(ob_params, i, PyObject_FromXPTParamDescriptor(d->params+i)); + PyObject *ob_ret = PyObject_FromXPTParamDescriptor(d->result); + PyObject *ret = Py_BuildValue("bsOO", d->flags, d->name, ob_params, ob_ret); + Py_XDECREF(ob_ret); + Py_XDECREF(ob_params); + return ret; +} + +PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c) +{ + if (c==nsnull) { + Py_INCREF(Py_None); + return Py_None; + } + PyObject *ob_type = PyObject_FromXPTTypeDescriptor(&c->type); + if (ob_type==NULL) + return NULL; + PyObject *v = NULL; + switch (c->type.prefix.flags) { + case TD_INT8: + v = PyInt_FromLong( c->value.i8 ); + break; + case TD_INT16: + v = PyInt_FromLong( c->value.i16 ); + break; + case TD_INT32: + v = PyInt_FromLong( c->value.i32 ); + break; + case TD_INT64: + v = PyLong_FromLongLong(c->value.i64); + break; + case TD_UINT8: + v = PyInt_FromLong( c->value.ui8 ); + break; + case TD_UINT16: + v = PyInt_FromLong( c->value.ui16 ); + break; + case TD_UINT32: + v = PyInt_FromLong( c->value.ui32 ); + break; + case TD_UINT64: + v = PyLong_FromUnsignedLongLong(c->value.ui64); + break; + case TD_FLOAT: + v = PyFloat_FromDouble(c->value.flt); + break; + case TD_DOUBLE: + v = PyFloat_FromDouble(c->value.dbl); + break; + case TD_BOOL: + v = c->value.bul ? Py_True : Py_False; + Py_INCREF(v); + break; + case TD_CHAR: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromStringAndSize(&c->value.ch, 1); +#else + v = PyUnicode_FromStringAndSize(&c->value.ch, 1); +#endif + break; + case TD_WCHAR: + v = PyObject_FromNSString((PRUnichar *)&c->value.wch, 1); + break; + // TD_VOID = 13, + case TD_PNSIID: + v = Py_nsIID::PyObjectFromIID(*c->value.iid); + break; + // TD_DOMSTRING = 15, + case TD_PSTRING: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromString(c->value.str); +#else + v = PyUnicode_FromString(c->value.str); +#endif + break; + case TD_PWSTRING: + v = PyObject_FromNSString((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr)); + break; + // TD_INTERFACE_TYPE = 18, + // TD_INTERFACE_IS_TYPE = 19, + // TD_ARRAY = 20, + // TD_PSTRING_SIZE_IS = 21, + // TD_PWSTRING_SIZE_IS = 22 + // TD_UTF8STRING = 23, + // TD_CSTRING = 24, + // TD_ASTRING = 25 + default: +#if PY_MAJOR_VERSION <= 2 + v = PyString_FromString("Unknown type code!!"); +#else + v = PyUnicode_FromString("Unknown type code!!"); +#endif + break; + + } + PyObject *ret = Py_BuildValue("sbO", c->name, ob_type, v); + Py_DECREF(ob_type); + Py_DECREF(v); + return ret; +} diff --git a/src/libs/xpcom18a4/python/src/TypeObject.cpp b/src/libs/xpcom18a4/python/src/TypeObject.cpp new file mode 100644 index 00000000..37cc13d7 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/TypeObject.cpp @@ -0,0 +1,457 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include + +#if defined(Py_LIMITED_API) && defined(RT_OS_LINUX) +# include +# ifdef __GLIBC_PREREQ +# if __GLIBC_PREREQ(2,9) +# define PYXPCOM_HAVE_PIPE2 +# include +# endif +# endif +#endif + + +#ifndef Py_LIMITED_API +static PyTypeObject PyInterfaceType_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "interface-type", /* Name of this type */ + sizeof(PyTypeObject), /* Basic object size */ + 0, /* Item size for varobject */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + PyType_Type.tp_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + PyType_Type.tp_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /* tp_getattro */ + 0, /*tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + "Define the behavior of a PythonCOM Interface type.", +}; + +#else /* Py_LIMITED_API */ + +/** The offset of PyTypeObject::ob_name. */ +static size_t g_offObTypeNameMember = sizeof(PyVarObject); + +/** + * Base type object for XPCOM interfaces. Created dynamicially. + */ +static PyTypeObject *g_pPyInterfaceTypeObj = NULL; + +/** + * Gets the base XPCOM interface type object, creating it if needed. + */ +static PyTypeObject *PyXPCOM_CreateInterfaceType(void) +{ + static char g_szTypeDoc[] = "Define the behavior of a PythonCOM Interface type."; /* need non-const */ + PyType_Slot aTypeSlots[] = { + { Py_tp_doc, g_szTypeDoc }, + { 0, NULL } /* terminator */ + }; + static const char g_szClassNm[] = "interface-type"; + PyType_Spec TypeSpec = { + /* .name: */ g_szClassNm, + /* .basicsize: */ 0, + /* .itemsize: */ 0, + /* .flags: */ Py_TPFLAGS_BASETYPE, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + PyTypeObject *pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + g_pPyInterfaceTypeObj = pTypeObj; + + /* + * Verify/correct g_offObTypeNameMember. + * + * Using pipe+write to probe the memory content, banking on the kernel + * to return EFAULT when we pass it an invalid address. + */ + for (size_t off = sizeof(PyVarObject); off < sizeof(PyVarObject) + 64; off += sizeof(char *)) { + const char * const pszProbe = *(const char **)((uintptr_t)(pTypeObj) + off); + if (RT_VALID_PTR(pszProbe)) { + int fds[2] = { -1, -1 }; +# ifdef PYXPCOM_HAVE_PIPE2 + int rc = pipe2(fds, O_CLOEXEC); +# else + int rc = pipe(fds); +# endif + if (rc) + break; + + ssize_t cbWritten = write(fds[1], pszProbe, sizeof(g_szClassNm)); + if (cbWritten == (ssize_t)sizeof(g_szClassNm)) { + char szReadBack[sizeof(g_szClassNm)]; + ssize_t offRead = 0; + while (offRead < cbWritten) { + ssize_t cbRead = read(fds[0], &szReadBack[offRead], cbWritten - offRead); + if (cbRead >= 0) { + offRead += cbRead; + } else if (errno != EINTR) + break; + } + if ( cbWritten == offRead + && memcmp(szReadBack, g_szClassNm, sizeof(szReadBack)) == 0) { + g_offObTypeNameMember = off; + close(fds[0]); + close(fds[1]); + return pTypeObj; + } + } + close(fds[0]); + close(fds[1]); + } + } + assert(0); + + return pTypeObj; +} + +/** + * Gets the base XPCOM interface type object, creating it if needed. + */ +static PyTypeObject *PyXPCOM_GetInterfaceType(void) +{ + PyTypeObject *pTypeObj = g_pPyInterfaceTypeObj; + if (pTypeObj) + return pTypeObj; + return PyXPCOM_CreateInterfaceType(); +} + +/** + * Get the PyTypeObject::ob_name value. + * + * @todo This is _horrible_, but there appears to be no simple tp_name getter + * till https://bugs.python.org/issue31497 (2017 / 3.7.0). But even then + * it is not part of the limited API. + */ +const char *PyXPCOMGetObTypeName(PyTypeObject *pTypeObj) +{ + return *(const char **)((uintptr_t)(pTypeObj) + g_offObTypeNameMember); +} + +#endif /* Py_LIMITED_API */ + +/*static*/ PRBool +PyXPCOM_TypeObject::IsType(PyTypeObject *t) +{ +#if PY_MAJOR_VERSION <= 2 + return t->ob_type == &PyInterfaceType_Type; +#elif !defined(Py_LIMITED_API) + return Py_TYPE(t) == &PyInterfaceType_Type; +#else + return Py_TYPE(t) == g_pPyInterfaceTypeObj /* Typically not the case as t->ob_type is &PyType_Type */ + || PyType_IsSubtype(t, g_pPyInterfaceTypeObj); /* rather than g_pPyInterfaceTypeObj because of PyType_FromSpec(). */ +#endif +} + +//////////////////////////////////////////////////////////////////// +// +// The type methods +// +/*static*/PyObject * +PyXPCOM_TypeObject::Py_getattr(PyObject *self, char *name) +{ + return ((Py_nsISupports *)self)->getattr(name); +} + +/*static*/int +PyXPCOM_TypeObject::Py_setattr(PyObject *op, char *name, PyObject *v) +{ + return ((Py_nsISupports *)op)->setattr(name, v); +} + +// @pymethod int|Py_nsISupports|__cmp__|Implements XPCOM rules for object identity. +/*static*/int +PyXPCOM_TypeObject::Py_cmp(PyObject *self, PyObject *other) +{ + // @comm NOTE: Copied from COM - have not confirmed these rules are true for XPCOM + // @comm As per the XPCOM rules for object identity, both objects are queried for nsISupports, and these values compared. + // The only meaningful test is for equality - the result of other comparisons is undefined + // (ie, determined by the object's relative addresses in memory. + nsISupports *pUnkOther; + nsISupports *pUnkThis; + if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE)) + return -1; + if (!Py_nsISupports::InterfaceFromPyObject(other, NS_GET_IID(nsISupports), &pUnkOther, PR_FALSE)) { + pUnkThis->Release(); + return -1; + } + int rc = pUnkThis==pUnkOther ? 0 : + (pUnkThis < pUnkOther ? -1 : 1); + pUnkThis->Release(); + pUnkOther->Release(); + return rc; +} + +/*static*/PyObject * +PyXPCOM_TypeObject::Py_richcmp(PyObject *self, PyObject *other, int op) +{ + PyObject *result = NULL; + int rc = Py_cmp(self, other); + switch (op) + { + case Py_LT: + result = rc < 0 ? Py_True : Py_False; + break; + case Py_LE: + result = rc <= 0 ? Py_True : Py_False; + break; + case Py_EQ: + result = rc == 0 ? Py_True : Py_False; + break; + case Py_NE: + result = rc != 0 ? Py_True : Py_False; + break; + case Py_GT: + result = rc > 0 ? Py_True : Py_False; + break; + case Py_GE: + result = rc >= 0 ? Py_True : Py_False; + break; + } + Py_XINCREF(result); + return result; +} + +// @pymethod int|Py_nsISupports|__hash__|Implement a hash-code for the XPCOM object using XPCOM identity rules. +#if PY_VERSION_HEX >= 0x03020000 +/*static*/Py_hash_t PyXPCOM_TypeObject::Py_hash(PyObject *self) +#else +/*static*/long PyXPCOM_TypeObject::Py_hash(PyObject *self) +#endif +{ + // We always return the value of the nsISupports *. + nsISupports *pUnkThis; + if (!Py_nsISupports::InterfaceFromPyObject(self, NS_GET_IID(nsISupports), &pUnkThis, PR_FALSE)) + return -1; +#if PY_VERSION_HEX >= 0x03020000 + Py_hash_t ret = _Py_HashPointer(pUnkThis); +#else + long ret = _Py_HashPointer(pUnkThis); +#endif + pUnkThis->Release(); + return ret; +} + +// @method string|Py_nsISupports|__repr__|Called to create a representation of a Py_nsISupports object +/*static */PyObject * +PyXPCOM_TypeObject::Py_repr(PyObject *self) +{ + // @comm The repr of this object displays both the object's address, and its attached nsISupports's address + Py_nsISupports *pis = (Py_nsISupports *)self; + // Try and get the IID name. + char *iid_repr = nsnull; + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim!=nsnull) + iim->GetNameForIID(&pis->m_iid, &iid_repr); + if (iid_repr==nsnull) + // no IIM available, or it doesnt know the name. + iid_repr = pis->m_iid.ToString(); + // XXX - need some sort of buffer overflow. + char buf[512]; +#ifdef VBOX + snprintf(buf, sizeof(buf), "", + iid_repr, (void *)self, (void *)pis->m_obj.get()); +#else + sprintf(buf, "", + iid_repr, (void *)self, (void *)pis->m_obj.get()); +#endif + nsMemory::Free(iid_repr); +#if PY_MAJOR_VERSION <= 2 + return PyString_FromString(buf); +#else + return PyUnicode_FromString(buf); +#endif +} + +/*static */PyObject * +PyXPCOM_TypeObject::Py_str(PyObject *self) +{ + Py_nsISupports *pis = (Py_nsISupports *)self; + nsresult rv; + char *val = NULL; + Py_BEGIN_ALLOW_THREADS; + { // scope to kill pointer while thread-lock released. + nsCOMPtr ss( do_QueryInterface(pis->m_obj, &rv )); + if (NS_SUCCEEDED(rv)) + rv = ss->ToString(&val); + } // end-scope + Py_END_ALLOW_THREADS; + PyObject *ret; + if (NS_FAILED(rv)) + ret = Py_repr(self); + else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(val); +#else + ret = PyUnicode_FromString(val); +#endif + if (val) nsMemory::Free(val); + return ret; +} + +/* static */void +PyXPCOM_TypeObject::Py_dealloc(PyObject *self) +{ + delete (Py_nsISupports *)self; +} + +PyXPCOM_TypeObject::PyXPCOM_TypeObject( const char *name, PyXPCOM_TypeObject *pBase, int typeSize, struct PyMethodDef* methodList, PyXPCOM_I_CTOR thector) +{ +#ifndef Py_LIMITED_API + static const PyTypeObject type_template = { + PyVarObject_HEAD_INIT(&PyInterfaceType_Type, 0) + "XPCOMTypeTemplate", /*tp_name*/ + sizeof(Py_nsISupports), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + Py_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + Py_getattr, /* tp_getattr */ + Py_setattr, /* tp_setattr */ +#if PY_MAJOR_VERSION <= 2 + Py_cmp, /* tp_compare */ +#else + 0, /* reserved */ +#endif + Py_repr, /* tp_repr */ + 0, /* tp_as_number*/ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + Py_hash, /* tp_hash */ + 0, /* tp_call */ + Py_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + Py_richcmp, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + }; + + *((PyTypeObject *)this) = type_template; +#else /* Py_LIMITED_API */ + /* Create the type specs: */ + PyType_Slot aTypeSlots[] = { + { Py_tp_base, PyXPCOM_GetInterfaceType() }, + { Py_tp_dealloc, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_dealloc }, + { Py_tp_getattr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_getattr }, + { Py_tp_setattr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_setattr }, + { Py_tp_repr, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_repr }, + { Py_tp_hash, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_hash }, + { Py_tp_str, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_str }, + { Py_tp_richcompare, (void *)(uintptr_t)&PyXPCOM_TypeObject::Py_richcmp }, + { 0, NULL } /* terminator */ + }; + PyType_Spec TypeSpec = { + /* .name: */ name, + /* .basicsize: */ typeSize, + /* .itemsize: */ 0, + /* .flags: */ Py_TPFLAGS_BASETYPE /*?*/, + /* .slots: */ aTypeSlots, + }; + + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */ + + m_pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec); + assert(m_pTypeObj); + + PyErr_Restore(exc_typ, exc_val, exc_tb); + + /* Initialize the PyObject part - needed so we can keep instance in a PyDict: */ + ob_type = PyXPCOM_GetInterfaceType(); + PyObject_Init(this, ob_type); /* VBox: Needed for 3.9 and up (also works on Python 2.7), includes _Py_NewReferences. @bugref{10079} */ + +#endif /* Py_LIMITED_API */ + + chain.methods = methodList; + chain.link = pBase ? &pBase->chain : NULL; + + baseType = pBase; + ctor = thector; + +#ifndef Py_LIMITED_API + // cast away const, as Python doesnt use it. + tp_name = (char *)name; + tp_basicsize = typeSize; +#endif +} + +PyXPCOM_TypeObject::~PyXPCOM_TypeObject() +{ +} + diff --git a/src/libs/xpcom18a4/python/src/VariantUtils.cpp b/src/libs/xpcom18a4/python/src/VariantUtils.cpp new file mode 100644 index 00000000..ac14a2cf --- /dev/null +++ b/src/libs/xpcom18a4/python/src/VariantUtils.cpp @@ -0,0 +1,3112 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * Unicode corrections by Shane Hathaway (http://hathawaymix.org), + * inspired by Mikhail Sobolev + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include +#include +#include + +// ------------------------------------------------------------------------ +// nsString utilities +// ------------------------------------------------------------------------ +// one day we may know what they look like. +inline +PRBool +IsNullDOMString( const nsAString& aString ) +{ + return PR_FALSE; +} + +inline +PRBool +IsNullDOMString( const nsACString& aString ) +{ + return PR_FALSE; +} + +#define PyUnicode_FromPRUnichar(src, size) \ + PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL) + +// Create a zero-terminated PRUnichar buffer from a Python unicode. +// On success, returns 0. On failure, returns -1 and sets an exception. +// dest_out must not be null. size_out may be null. +static int +PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out) +{ + PRUint32 size; + PyObject *s; + const void *src; + PRUnichar *dest; + + s = PyUnicode_AsUTF16String(obj); + if (!s) + return -1; + // Drop the UTF-16 byte order mark at the beginning of + // the string. (See the docs on PyUnicode_AsUTF16String.) + // Some Mozilla libraries don't like the mark. +#if PY_MAJOR_VERSION <= 2 + size = (PyString_GET_SIZE(s) - 2) / sizeof(PRUnichar); + src = PyString_AS_STRING(s) + 2; +#else + if (!PyBytes_Check(s)) { + PyErr_SetString(PyExc_TypeError, "internal error in PyXPCOM, parameter must be a bytes object"); + return -1; + } + size = (PyBytes_GET_SIZE(s) - 2) / sizeof(PRUnichar); + src = PyBytes_AS_STRING(s) + 2; +#endif + dest = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (size + 1)); + if (!dest) { + PyErr_NoMemory(); + Py_DECREF(s); + return -1; + } + memcpy(dest, src, sizeof(PRUnichar) * size); + Py_DECREF(s); + dest[size] = 0; + *dest_out = dest; + if (size_out) + *size_out = size; + return 0; +} + +PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 /*= PR_FALSE */) +{ + PyObject *ret; + if (IsNullDOMString(s)) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + if (bAssumeUTF8) { + const nsPromiseFlatCString& temp = PromiseFlatCString(s); + ret = PyUnicode_DecodeUTF8(temp.get(), temp.Length(), NULL); + } else { +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(NULL, s.Length()); +#else + ret = PyUnicode_FromStringAndSize(NULL, s.Length()); +#endif + if (!ret) + return NULL; + // Need "CopyAsciiTo"!? + nsACString::const_iterator fromBegin, fromEnd; +#if PY_MAJOR_VERSION <= 2 + char* dest = (char *)PyString_AS_STRING(ret); +#else + char* dest = (char *)PyUnicode_AsUTF8(ret); +#endif + copy_string(s.BeginReading(fromBegin), s.EndReading(fromEnd), dest); + } + } + return ret; +} + +PyObject *PyObject_FromNSString( const nsAString &s ) +{ + PyObject *ret; + if (IsNullDOMString(s)) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + const nsPromiseFlatString& temp = PromiseFlatString(s); + ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length()); + } + return ret; +} + +PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len /* = (PRUint32)-1*/) +{ + return PyUnicode_FromPRUnichar(s, + len==((PRUint32)-1)? nsCRT::strlen(s) : len); +} + +PRBool PyObject_AsNSString( PyObject *val, nsAString &aStr) +{ + if (val == Py_None) { + aStr.Truncate(); + return NS_OK; + } + PyObject *val_use = NULL; + PRBool ok = PR_TRUE; +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + ok = PR_FALSE; + } + if (ok && (val_use = PyUnicode_FromObject(val))==NULL) + ok = PR_FALSE; +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + ok = PR_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (ok) { + if (PyUnicode_GET_SIZE(val_use) == 0) { + aStr.Truncate(); + } + else { + PRUint32 nch; + PRUnichar *tempo; + // can we do this without the copy? + if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0) + return PR_FALSE; + aStr.Assign(tempo, nch); + nsMemory::Free(tempo); + } + } + Py_XDECREF(val_use); + return ok; +} + +// Array utilities +static PRUint32 GetArrayElementSize( PRUint8 t) +{ + PRUint32 ret; + switch (t & XPT_TDP_TAGMASK) { + case nsXPTType::T_U8: + case nsXPTType::T_I8: + ret = sizeof(PRInt8); + break; + case nsXPTType::T_I16: + case nsXPTType::T_U16: + ret = sizeof(PRInt16); + break; + case nsXPTType::T_I32: + case nsXPTType::T_U32: + ret = sizeof(PRInt32); + break; + case nsXPTType::T_I64: + case nsXPTType::T_U64: + ret = sizeof(PRInt64); + break; + case nsXPTType::T_FLOAT: + ret = sizeof(float); + break; + case nsXPTType::T_DOUBLE: + ret = sizeof(double); + break; + case nsXPTType::T_BOOL: + ret = sizeof(PRBool); + break; + case nsXPTType::T_CHAR: + ret = sizeof(char); + break; + case nsXPTType::T_WCHAR: + ret = sizeof(PRUnichar); + break; + case nsXPTType::T_IID: + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + case nsXPTType::T_INTERFACE: + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_INTERFACE_IS: + case nsXPTType::T_PSTRING_SIZE_IS: + case nsXPTType::T_CSTRING: + case nsXPTType::T_ASTRING: + case nsXPTType::T_UTF8STRING: + + ret = sizeof( void * ); + break; + default: + NS_ABORT_IF_FALSE(0, "Unknown array type code!"); + ret = 0; + break; + } + return ret; +} + +static nsresult +GetArrayElementIID(Py_nsISupports* self, + nsXPTCVariant* dispatchParams, + PRUint16 methodIndex, + PRUint8 paramIndex, + nsIID *result) +{ + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr ii; + nsresult rc; + + rc = iim->GetInfoForIID(&self->m_iid, getter_AddRefs(ii)); + if (NS_FAILED(rc)) + return rc; + + + const nsXPTMethodInfo *mi; + rc = ii->GetMethodInfo(methodIndex, &mi); + if (NS_FAILED(rc)) + return rc; + + const nsXPTParamInfo& paramInfo = mi->GetParam(paramIndex); + + if (!paramInfo.GetType().IsArray()) { + PyXPCOM_LogWarning("Passing non-array to GetArrayElementIID\n"); + return NS_ERROR_INVALID_ARG; + } + + nsXPTType elemType; + rc = ii->GetTypeForParam(methodIndex, ¶mInfo, 1, &elemType); + if (NS_FAILED(rc)) + return rc; + + PRUint8 tag = elemType.TagPart(); + if (tag == nsXPTType::T_INTERFACE) + { + rc = ii->GetIIDForParamNoAlloc(methodIndex, ¶mInfo, result); + } + else if (tag == nsXPTType::T_INTERFACE_IS) + { + PyXPCOM_LogWarning("Unable to handle T_INTERFACE_IS yet\n"); + return NS_ERROR_NOT_IMPLEMENTED; + } + else + { + // this may be valid case, for arrays of other types + // we don't need IID for + rc = NS_ERROR_INVALID_ARG; + } + + return rc; +} + + +void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type) +{ + // Free each array element - NOT the array itself + // Thus, we only need to free arrays or pointers. + void **p = (void **)array_ptr; + PRUint32 i; + switch(array_type & XPT_TDP_TAGMASK) { + case nsXPTType::T_IID: + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + for (i=0; iRelease(); + Py_END_ALLOW_THREADS; + } + break; + + // Ones we know need no deallocation + case nsXPTType::T_U8: + case nsXPTType::T_I8: + case nsXPTType::T_I16: + case nsXPTType::T_U16: + case nsXPTType::T_I32: + case nsXPTType::T_U32: + case nsXPTType::T_I64: + case nsXPTType::T_U64: + case nsXPTType::T_FLOAT: + case nsXPTType::T_DOUBLE: + case nsXPTType::T_BOOL: + case nsXPTType::T_CHAR: + case nsXPTType::T_WCHAR: + break; + + // And a warning should new type codes appear, as they may need deallocation. + default: + PyXPCOM_LogWarning("Deallocating unknown type %d (0x%x) - possible memory leak\n"); + break; + } +} + +#define FILL_SIMPLE_POINTER( type, val ) *((type *)pthis) = (type)(val) +#define BREAK_FALSE {rc=PR_FALSE;break;} + + +PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, + PRUint32 array_element_size, PRUint8 array_type, nsIID *pIID) +{ + PRUint8 *pthis = (PRUint8 *)array_ptr; + NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!"); + PRBool rc = PR_TRUE; + // We handle T_U8 specially as a string/Unicode. + // If it is NOT a string, we just fall through and allow the standard + // sequence unpack code process it (just slower!) +#if PY_MAJOR_VERSION <= 2 + if ( array_type == nsXPTType::T_U8 && + (PyString_Check(sequence_ob) || PyUnicode_Check(sequence_ob))) { +#else + if ( array_type == nsXPTType::T_U8 && PyUnicode_Check(sequence_ob)) { +#endif + + PRBool release_seq; + if (PyUnicode_Check(sequence_ob)) { + release_seq = PR_TRUE; +#if PY_MAJOR_VERSION <= 2 + sequence_ob = PyObject_Str(sequence_ob); +#else + sequence_ob = PyUnicode_AsUTF8String(sequence_ob); +#endif + } else + release_seq = PR_FALSE; + if (!sequence_ob) // presumably a memory error, or Unicode encoding error. + return PR_FALSE; +#if PY_MAJOR_VERSION <= 2 + memcpy(pthis, PyString_AS_STRING(sequence_ob), sequence_size); +#else + memcpy(pthis, PyUnicode_AsUTF8(sequence_ob), sequence_size); +#endif + if (release_seq) + { + Py_DECREF(sequence_ob); + } + return PR_TRUE; + } + + for (PRUint32 i=0; rc && iRelease(); + Py_END_ALLOW_THREADS; + } + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + default: + // try and limp along in this case. + // leave rc TRUE + PyXPCOM_LogWarning("Converting Python object for an array element - The object type (0x%x) is unknown - leaving param alone!\n", array_type); + break; + } + Py_XDECREF(val_use); + Py_DECREF(val); + } + return rc; +} + +static PyObject *UnpackSingleArray(Py_nsISupports *parent, void *array_ptr, + PRUint32 sequence_size, PRUint8 array_type, nsIID *iid) +{ + if (array_ptr==NULL) { + Py_INCREF(Py_None); + return Py_None; + } + if (array_type == nsXPTType::T_U8) +#if PY_MAJOR_VERSION <= 2 + return PyString_FromStringAndSize( (char *)array_ptr, sequence_size ); +#else + return PyBytes_FromStringAndSize( (char *)array_ptr, sequence_size ); +#endif + + PRUint32 array_element_size = GetArrayElementSize(array_type); + PyObject *list_ret = PyList_New(sequence_size); + PRUint8 *pthis = (PRUint8 *)array_ptr; + for (PRUint32 i=0; iEquals(NS_GET_IID(nsIVariant))) + val = PyObject_FromVariant(parent, (nsIVariant *)*pp); + else if (parent) + val = parent->MakeInterfaceResult(*pp, iid ? *iid : NS_GET_IID(nsISupports)); + else + val = Py_nsISupports::PyObjectFromInterface( + *pp, + iid ? *iid : NS_GET_IID(nsISupports), + PR_TRUE); + break; + } + default: { + char buf[128]; + sprintf(buf, "Unknown XPCOM array type flags (0x%x)", array_type); + PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf); +#if PY_MAJOR_VERSION <= 2 + val = PyString_FromString(buf); +#else + val = PyUnicode_FromString(buf); +#endif + break; + } + } + if (val==NULL) { + NS_ABORT_IF_FALSE(PyErr_Occurred(), "NULL result in array conversion, but no error set!"); + return NULL; + } + PyList_SET_ITEM(list_ret, i, val); // ref-count consumed. + } + return list_ret; +} + + +// ------------------------------------------------------------------------ +// nsIVariant utilities +// ------------------------------------------------------------------------ +struct BVFTResult { + BVFTResult() {pis = NULL;iid=Py_nsIID_NULL;} + nsISupports *pis; + nsIID iid; +}; + +static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NULL) +{ + nsISupports *ps = NULL; + nsIID iid; + // start with some fast concrete checks. + if (ob==Py_None) + return nsIDataType::VTYPE_EMPTY; + if (ob==Py_True || ob == Py_False) + return nsIDataType::VTYPE_BOOL; + if (PyInt_Check(ob)) + return nsIDataType::VTYPE_INT32; + if (PyLong_Check(ob)) + return nsIDataType::VTYPE_INT64; + if (PyFloat_Check(ob)) + return nsIDataType::VTYPE_DOUBLE; +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(ob)) + return nsIDataType::VTYPE_STRING_SIZE_IS; +#endif + if (PyUnicode_Check(ob)) + return nsIDataType::VTYPE_WSTRING_SIZE_IS; + if (PyTuple_Check(ob) || PyList_Check(ob)) { + if (PySequence_Length(ob)) + return nsIDataType::VTYPE_ARRAY; + return nsIDataType::VTYPE_EMPTY_ARRAY; + } + // Now do expensive or abstract checks. + if (Py_nsISupports::InterfaceFromPyObject(ob, NS_GET_IID(nsISupports), &ps, PR_TRUE)) { + if (pdata) { + pdata->pis = ps; + pdata->iid = NS_GET_IID(nsISupports); + } else + ps->Release(); + return nsIDataType::VTYPE_INTERFACE_IS; + } else + PyErr_Clear(); + if (Py_nsIID::IIDFromPyObject(ob, &iid)) { + if (pdata) + pdata->iid = iid; + return nsIDataType::VTYPE_ID; + } else + PyErr_Clear(); + if (PySequence_Check(ob)) { + if (PySequence_Length(ob)) + return nsIDataType::VTYPE_ARRAY; + return nsIDataType::VTYPE_EMPTY_ARRAY; + } + return (PRUint16)-1; +} + +nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet) +{ + nsresult nr = NS_OK; + nsCOMPtr v = do_CreateInstance("@mozilla.org/variant;1", &nr); + NS_ENSURE_SUCCESS(nr, nr); + // *sigh* - I tried the abstract API (PyNumber_Check, etc) + // but our COM instances too often qualify. + BVFTResult cvt_result; + PRUint16 dt = BestVariantTypeForPyObject(ob, &cvt_result); + switch (dt) { + case nsIDataType::VTYPE_BOOL: + nr = v->SetAsBool(ob==Py_True); + break; + case nsIDataType::VTYPE_INT32: + nr = v->SetAsInt32(PyInt_AsLong(ob)); + break; + case nsIDataType::VTYPE_INT64: + nr = v->SetAsInt64(PyLong_AsLongLong(ob)); + break; + case nsIDataType::VTYPE_DOUBLE: + nr = v->SetAsDouble(PyFloat_AsDouble(ob)); + break; + case nsIDataType::VTYPE_STRING_SIZE_IS: + { +#if PY_MAJOR_VERSION <= 2 + nr = v->SetAsStringWithSize(PyString_Size(ob), PyString_AsString(ob)); +#else + Py_ssize_t cb = 0; + const char *psz = PyUnicode_AsUTF8AndSize(ob, &cb); + nr = v->SetAsStringWithSize(cb, psz); +#endif + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: +#if PY_VERSION_HEX >= 0x03030000 + if (PyUnicode_GetLength(ob) == 0) { +#else + if (PyUnicode_GetSize(ob) == 0) { +#endif + nr = v->SetAsWStringWithSize(0, (PRUnichar*)NULL); + } + else { + PRUint32 nch; + PRUnichar *p; + if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) { + PyXPCOM_LogWarning("Failed to convert object to unicode", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + break; + } + nr = v->SetAsWStringWithSize(nch, p); + nsMemory::Free(p); + } + break; + case nsIDataType::VTYPE_INTERFACE_IS: + { + nsISupports *ps = cvt_result.pis; + nr = v->SetAsInterface(cvt_result.iid, ps); + if (ps) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + ps->Release(); + Py_END_ALLOW_THREADS; + } + break; + } + case nsIDataType::VTYPE_ID: + nr = v->SetAsID(cvt_result.iid); + break; + case nsIDataType::VTYPE_ARRAY: + { + int seq_length = PySequence_Length(ob); + NS_ABORT_IF_FALSE(seq_length!=0, "VTYPE_ARRAY assumes at least one element!"); + PyObject *first = PySequence_GetItem(ob, 0); + if (!first) break; + int array_type = BestVariantTypeForPyObject(first); + Py_DECREF(first); + // Arrays can't handle all types. This means we lost embedded NULLs. + // This should really be fixed in XPCOM. + if (array_type == nsIDataType::VTYPE_STRING_SIZE_IS) array_type = nsIDataType::VTYPE_CHAR_STR; + if (array_type == nsIDataType::VTYPE_WSTRING_SIZE_IS) array_type = nsIDataType::VTYPE_WCHAR_STR; + PRUint32 element_size = GetArrayElementSize(array_type); + int cb_buffer_pointer = seq_length * element_size; + void *buffer_pointer; + if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) { + nr = NS_ERROR_OUT_OF_MEMORY; + break; + } + memset(buffer_pointer, 0, cb_buffer_pointer); + if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type, nsnull)) { + nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer); + FreeSingleArray(buffer_pointer, seq_length, array_type); + } else + nr = NS_ERROR_UNEXPECTED; + nsMemory::Free(buffer_pointer); + break; + } + case nsIDataType::VTYPE_EMPTY: + nr = v->SetAsEmpty(); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + nr = v->SetAsEmptyArray(); + break; + case (PRUint16)-1: + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + default: + NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!"); + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", PyXPCOM_ObTypeName(ob)); + nr = NS_ERROR_UNEXPECTED; + } + if (NS_FAILED(nr)) + return nr; + return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet); +} + +static PyObject *MyBool_FromBool(PRBool v) +{ + PyObject *ret = v ? Py_True : Py_False; + Py_INCREF(ret); + return ret; +} + +#define GET_FROM_V(Type, FuncGet, FuncConvert) { \ + Type t; \ + if (NS_FAILED(nr = FuncGet( &t ))) goto done;\ + ret = FuncConvert(t);\ + break; \ +} + +PyObject *PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v) +{ + nsresult nr; + NS_PRECONDITION(v, "NULL variant!"); + if (!v) + return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER); +#ifdef NS_DEBUG + PRUint16 dt; + nr = v->GetDataType(&dt); + NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant"); +#endif + nsIID iid; + void *p; + PRUint16 type; + PRUint32 count; + nr = v->GetAsArray(&type, &iid, &count, &p); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid); + FreeSingleArray(p, count, (PRUint8)type); + nsMemory::Free(p); + return ret; +} + +PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v) +{ + if (!v) { + Py_INCREF(Py_None); + return Py_None; + } + PRUint16 dt; + nsresult nr; + PyObject *ret = NULL; + nr = v->GetDataType(&dt); + if (NS_FAILED(nr)) goto done; + switch (dt) { + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + ret = Py_None; + Py_INCREF(Py_None); + break; + case nsIDataType::VTYPE_ARRAY: + ret = PyObject_FromVariantArray(parent, v); + break; + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong); + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong); + case nsIDataType::VTYPE_INT64: + GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong); + case nsIDataType::VTYPE_UINT64: + GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong); + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble); + case nsIDataType::VTYPE_BOOL: + GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool); + default: + PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt); + // Fall through to the string case + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_CSTRING: { + nsCAutoString s; + if (NS_FAILED(nr=v->GetAsACString(s))) goto done; + ret = PyObject_FromNSString(s); + break; + } + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_ASTRING: { + nsAutoString s; + if (NS_FAILED(nr=v->GetAsAString(s))) goto done; + ret = PyObject_FromNSString(s); + break; + } + case nsIDataType::VTYPE_ID: + GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID); + case nsIDataType::VTYPE_INTERFACE: { + nsCOMPtr p; + if (NS_FAILED(nr=v->GetAsISupports(getter_AddRefs(p)))) goto done; + if (parent) + ret = parent->MakeInterfaceResult(p, NS_GET_IID(nsISupports)); + else + ret = Py_nsISupports::PyObjectFromInterface( + p, NS_GET_IID(nsISupports), PR_TRUE); + break; + } + case nsIDataType::VTYPE_INTERFACE_IS: { + nsCOMPtr p; + nsIID *iid; + if (NS_FAILED(nr=v->GetAsInterface(&iid, getter_AddRefs(p)))) goto done; + // If the variant itself holds a variant, we should + // probably unpack that too? + ret = parent->MakeInterfaceResult(p, *iid); + break; + // case nsIDataType::VTYPE_WCHAR_STR + // case nsIDataType::VTYPE_UTF8STRING + } + } +done: + if (NS_FAILED(nr)) { + NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!"); + PyXPCOM_BuildPyException(nr); + } + return ret; +} + +// ------------------------------------------------------------------------ +// TypeDescriptor helper class +// ------------------------------------------------------------------------ +class PythonTypeDescriptor { +public: + PythonTypeDescriptor() { + param_flags = type_flags = argnum = argnum2 = 0; + extra = NULL; + is_auto_out = PR_FALSE; + is_auto_in = PR_FALSE; + have_set_auto = PR_FALSE; + } + ~PythonTypeDescriptor() { + Py_XDECREF(extra); + } + PRUint8 param_flags; + PRUint8 type_flags; + PRUint8 argnum; /* used for iid_is and size_is */ + PRUint8 argnum2; /* used for length_is */ + PyObject *extra; // The IID object, or the type of the array. + // Extra items to help our processing. + // Is this auto-filled by some other "in" param? + PRBool is_auto_in; + // Is this auto-filled by some other "out" param? + PRBool is_auto_out; + // If is_auto_out, have I already filled it? Used when multiple + // params share a size_is fields - first time sets it, subsequent + // time check it. + PRBool have_set_auto; +}; + +static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num) +{ + // Loop over the array, checking all the params marked as having an arg. + // If these args nominate another arg as the size_is param, then + // we reset the size_is param to _not_ requiring an arg. + int i; + for (i=0;iRelease(); + Py_END_ALLOW_THREADS; + } + } + if (ns_v.IsValDOMString() && ns_v.val.p) { + delete (const nsAString *)ns_v.val.p; + } + if (ns_v.IsValCString() && ns_v.val.p) { + delete (const nsACString *)ns_v.val.p; + } + if (ns_v.IsValUTF8String() && ns_v.val.p) { + delete (const nsACString *)ns_v.val.p; + } + if (ns_v.IsValArray()) { + nsXPTCVariant &ns_v = m_var_array[i]; + if (ns_v.val.p) { + PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra); + PRUint32 seq_size = GetSizeIs(i, PR_FALSE); + FreeSingleArray(ns_v.val.p, seq_size, array_type); + } + } + // IsOwned must be the last check of the loop, as + // this frees the underlying data used above (eg, by the array free process) + if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) { + NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free"); + nsMemory::Free(ns_v.val.p); + } + } + if (m_buffer_array && m_buffer_array[i]) + nsMemory::Free(m_buffer_array[i]); + } + delete [] m_python_type_desc_array; + delete [] m_buffer_array; + delete [] m_var_array; +} + +PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams) +{ + PRBool ok = PR_FALSE; + int i; + int total_params_needed = 0; + if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) { + PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2"); + return PR_FALSE; + } + PyObject *typedescs = PySequence_GetItem(obParams, 0); + if (typedescs==NULL) + return PR_FALSE; + // NOTE: The length of the typedescs may be different than the + // args actually passed. The typedescs always include all + // hidden params (such as "size_is"), while the actual + // args never include this. + m_num_array = PySequence_Length(typedescs); + if (PyErr_Occurred()) goto done; + + m_pyparams = PySequence_GetItem(obParams, 1); + if (m_pyparams==NULL) goto done; + + m_python_type_desc_array = new PythonTypeDescriptor[m_num_array]; + if (!m_python_type_desc_array) goto done; + + // Pull apart the type descs and stash them. + for (i=0;iMakeInterfaceResult(iret, iid); + break; + } + case nsXPTType::T_INTERFACE_IS: { + nsIID iid; + nsXPTCVariant &ns_viid = m_var_array[td.argnum]; + NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!"); + if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) { + nsIID *piid = (nsIID *)ns_viid.val.p; + if (piid==NULL) + // Also serious, but like below, not our fault! + iid = NS_GET_IID(nsISupports); + else + iid = *piid; + } else { + // This is a pretty serious problem, but not Python's fault! + // Just return an nsISupports and hope the caller does whatever + // QI they need before using it. + NS_ERROR("Failed to get the IID for T_INTERFACE_IS!"); + iid = NS_GET_IID(nsISupports); + } + nsISupports *iret = *((nsISupports **)ns_v.ptr); + if (iid.Equals(NS_GET_IID(nsIVariant))) + ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret); + else + ret = m_parent->MakeInterfaceResult(iret, iid); + break; + } + case nsXPTType::T_ARRAY: { + if ( (* ((void **)ns_v.ptr)) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } + if (!PyInt_Check(td.extra)) { + PyErr_SetString(PyExc_TypeError, "The array info is not valid"); + break; + } + PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra); + PRUint32 seq_size = GetSizeIs(index, PR_FALSE); + nsXPTCVariant &ns_viid = m_var_array[td.argnum]; + nsIID iid; + nsresult res = GetArrayElementIID(m_parent, + m_var_array, + m_methodindex, + index, + &iid); + ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr), + seq_size, array_type&XPT_TDP_TAGMASK, + NS_SUCCEEDED(res) ? &iid : NULL); + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: + if (*((char **)ns_v.ptr) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + PRUint32 string_size = GetSizeIs(index, PR_TRUE); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size ); +#else + ret = PyUnicode_FromStringAndSize( *((char **)ns_v.ptr), string_size ); +#endif + } + break; + + case nsXPTType::T_PWSTRING_SIZE_IS: + if (*((PRUnichar **)ns_v.ptr) == NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + ret = PyUnicode_FromPRUnichar( *((PRUnichar **)ns_v.ptr), string_size ); + } + break; + default: + PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type)); + /* ret remains nsnull */ + break; + } + return ret; +} + + +PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult() +{ + // First we count the results. + int i = 0; + int n_results = 0; + PyObject *ret = NULL; + PRBool have_retval = PR_FALSE; + for (i=0;i 1) { + ret = PyTuple_New(n_results); + if (ret==NULL) + return NULL; + } + int ret_index = 0; + int max_index = m_num_array; + // Stick the retval at the front if we have have + if (have_retval && n_results > 1) { + PyObject *val = MakeSinglePythonResult(m_num_array-1); + if (val==NULL) { + Py_DECREF(ret); + return NULL; + } + PyTuple_SET_ITEM(ret, 0, val); + max_index--; + ret_index++; + + } + for (i=0;ret_index < n_results && i < max_index;i++) { + if (!m_python_type_desc_array[i].is_auto_out) { + if (XPT_PD_IS_OUT(m_python_type_desc_array[i].param_flags) || XPT_PD_IS_DIPPER(m_python_type_desc_array[i].param_flags)) { + PyObject *val = MakeSinglePythonResult(i); + if (val==NULL) { + Py_XDECREF(ret); + return NULL; + } + if (n_results > 1) { + PyTuple_SET_ITEM(ret, ret_index, val); + ret_index++; + } else { + NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!"); + ret = val; + } + } + } + } + + } + return ret; +} + +/************************************************************************* +************************************************************************** + + Helpers when IMPLEMENTING interfaces. + +************************************************************************** +*************************************************************************/ + +PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params ) +{ + m_params = params; + m_info = info; + // no references added - this class is only alive for + // a single gateway invocation + m_gateway = gw; + m_method_index = method_index; + m_python_type_desc_array = NULL; + m_num_type_descs = 0; +} + +PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper() +{ + delete [] m_python_type_desc_array; +} + +PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs() +{ + NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct"); + // Setup our array of Python typedescs, and determine the number of objects we + // pass to Python. + m_num_type_descs = m_info->num_args; + m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs]; + if (m_python_type_desc_array==nsnull) + return PyErr_NoMemory(); + + // First loop to count the number of objects + // we pass to Python + int i; + for (i=0;inum_args;i++) { + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i; + PythonTypeDescriptor &td = m_python_type_desc_array[i]; + td.param_flags = pi->flags; + td.type_flags = pi->type.prefix.flags; + td.argnum = pi->type.argnum; + td.argnum2 = pi->type.argnum2; + } + int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs); + PyObject *ret = PyTuple_New(num_args); + if (ret==NULL) + return NULL; + int this_arg = 0; + for (i=0;i=0 && this_arg= m_num_type_descs) { + PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param"); + return PR_FALSE; + } + PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags); + nsXPTCMiniVariant &ns_v = m_params[argnum]; + NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32"); + return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32; +} + +#undef DEREF_IN_OR_OUT +#define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element)) + +PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td) +{ + NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!"); + nsXPTCMiniVariant &ns_v = m_params[index]; + PyObject *ret = NULL; + PRBool is_out = XPT_PD_IS_OUT(td.param_flags); + + switch (td.type_flags & XPT_TDP_TAGMASK) { + case nsXPTType::T_I8: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) ); + break; + case nsXPTType::T_I16: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) ); + break; + case nsXPTType::T_I32: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) ); + break; + case nsXPTType::T_I64: + ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) ); + break; + case nsXPTType::T_U8: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) ); + break; + case nsXPTType::T_U16: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) ); + break; + case nsXPTType::T_U32: + ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) ); + break; + case nsXPTType::T_U64: + ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) ); + break; + case nsXPTType::T_FLOAT: + ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.f, float) ); + break; + case nsXPTType::T_DOUBLE: + ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.d, double) ); + break; + case nsXPTType::T_BOOL: { + PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool); + ret = temp ? Py_True : Py_False; + Py_INCREF(ret); + break; + } + case nsXPTType::T_CHAR: { + char temp = DEREF_IN_OR_OUT(ns_v.val.c, char); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(&temp, 1); +#else + ret = PyUnicode_FromStringAndSize(&temp, 1); +#endif + break; + } + case nsXPTType::T_WCHAR: { + PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar); + ret = PyUnicode_FromPRUnichar(&temp, 1); + break; + } +// case nsXPTType::T_VOID: + case nsXPTType::T_IID: { + ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) ); + break; + } + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: { + NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout"); + const nsAString *rs = (const nsAString *)ns_v.val.p; + ret = PyObject_FromNSString(*rs); + break; + } + case nsXPTType::T_CSTRING: + case nsXPTType::T_UTF8STRING: { + NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout"); + const nsCString *rs = (const nsCString *)ns_v.val.p; + ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING); + break; + } + case nsXPTType::T_CHAR_STR: { + char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(t); +#else + ret = PyUnicode_FromString(t); +#endif + break; + } + + case nsXPTType::T_WCHAR_STR: { + PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *); + if (us==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us)); + } + break; + } + case nsXPTType::T_INTERFACE_IS: // our Python code does it :-) + case nsXPTType::T_INTERFACE: { + nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *); + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index); + break; + } +/*** + nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *); + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + nsXPTCMiniVariant &ns_viid = m_params[td.argnum]; + NS_ABORT_IF_FALSE((m_python_type_desc_array[td.argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!"); + const nsIID * iid = NULL; + if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags)) + // may still be inout! + iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *); + + ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index); + break; + } +****/ + case nsXPTType::T_ARRAY: { + void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *); + if (t==NULL) { + // JS may send us a NULL here occasionally - as the + // type is array, we silently convert this to a zero + // length list, a-la JS. + ret = PyList_New(0); + } else { + PRUint8 array_type; + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); + if (NS_FAILED(ns)) { + PyXPCOM_BuildPyException(ns); + break; + } + PRUint32 seq_size = GetSizeIs(index, PR_FALSE); + ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid); + } + break; + } + case nsXPTType::T_PSTRING_SIZE_IS: { + char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *); + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromStringAndSize(t, string_size); +#else + ret = PyUnicode_FromStringAndSize(t, string_size); +#endif + break; + } + case nsXPTType::T_PWSTRING_SIZE_IS: { + PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *); + PRUint32 string_size = GetSizeIs(index, PR_TRUE); + if (t==NULL) { + ret = Py_None; + Py_INCREF(Py_None); + } else { + ret = PyUnicode_FromPRUnichar(t, string_size); + } + break; + } + default: + // As this is called by external components, + // we return _something_ rather than failing before any user code has run! + { + char buf[128]; + sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags); + PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf); +#if PY_MAJOR_VERSION <= 2 + ret = PyString_FromString(buf); +#else + ret = PyUnicode_FromString(buf); +#endif + break; + } + } + return ret; +} + +nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid) +{ + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!"); + if (iim==nsnull) + return NS_ERROR_FAILURE; + + nsCOMPtr ii; + nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii)); + if (NS_FAILED(rc)) + return rc; + nsXPTType datumType; + const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index); + rc = ii->GetTypeForParam(m_method_index, ¶m_info, 1, &datumType); + if (NS_FAILED(rc)) + return rc; + if (iid) { + *iid = (nsIID *)&NS_GET_IID(nsISupports); + if (XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE || + XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE_IS || + XPT_TDP_TAG(datumType)==nsXPTType::T_ARRAY) + ii->GetIIDForParam(m_method_index, ¶m_info, iid); + } + *ret = datumType.flags; + return NS_OK; +} + +PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret) +{ + // Not sure if the IID pointed at by by this is allows to be + // in or out, so we will allow it. + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + nsXPTType typ = pi->GetType(); + NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!"); + NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value."); + if (XPT_TDP_TAG(typ) != nsXPTType::T_IID) + *ppret = &NS_GET_IID(nsISupports); + else { + nsXPTCMiniVariant &ns_v = m_params[index]; + if (pi->IsOut()) { + nsIID **pp = (nsIID **)ns_v.val.p; + if (pp && *pp) + *ppret = *pp; + else + *ppret = &NS_GET_IID(nsISupports); + } else if (pi->IsIn()) { + nsIID *p = (nsIID *)ns_v.val.p; + if (p) + *ppret = p; + else + *ppret = &NS_GET_IID(nsISupports); + } else { + NS_ERROR("Param is not in or out!"); + *ppret = &NS_GET_IID(nsISupports); + } + } + return PR_TRUE; +} + +nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo() +{ + if (!m_interface_info) { + nsCOMPtr iim(do_GetService( + NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + if (iim) + iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info)); + } + return m_interface_info; +} + +#undef FILL_SIMPLE_POINTER +#define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob) + +nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index) +{ + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index; + NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!"); + NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param"); + nsXPTCMiniVariant &ns_v = m_params[index]; + + nsXPTType typ = pi->GetType(); + PyObject* val_use = NULL; + + NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!"); + if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER; + + PRBool rc = PR_TRUE; + switch (XPT_TDP_TAG(typ)) { + case nsXPTType::T_I8: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I16: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I32: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_I64: + if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) ); + break; + case nsXPTType::T_U8: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U16: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U32: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_U64: + if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE; + FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) ); + break; + case nsXPTType::T_FLOAT: + if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) ); + break; + case nsXPTType::T_DOUBLE: + if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) ); + break; + case nsXPTType::T_BOOL: + if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE + FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) ); + break; + case nsXPTType::T_CHAR: +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) ); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } +# ifndef Py_LIMITED_API + FILL_SIMPLE_POINTER( char, *PyUnicode_AS_UNICODE(val) ); +# else + FILL_SIMPLE_POINTER( char, PyUnicode_ReadChar(val, 0) ); +# endif +#endif + break; + + case nsXPTType::T_WCHAR: +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a Unicode object"); + BREAK_FALSE; + } +#endif + if ((val_use = PyUnicode_FromObject(val))==NULL) + BREAK_FALSE; + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); + // Lossy! +#ifndef Py_LIMITED_API + FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) ); +#else + FILL_SIMPLE_POINTER( PRUnichar, PyUnicode_ReadChar(val_use, 0) ); +#endif + break; + +// case nsXPTType::T_VOID: + case nsXPTType::T_IID: { + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(val, &iid)) + BREAK_FALSE; + nsIID **pp = (nsIID **)ns_v.val.p; + // If there is an existing [in] IID, free it. + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID)); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + memcpy(*pp, &iid, sizeof(iid)); + break; + } + + case nsXPTType::T_ASTRING: + case nsXPTType::T_DOMSTRING: { + nsAString *ws = (nsAString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (!PyObject_AsNSString(val, *ws)) + BREAK_FALSE; + break; + } + case nsXPTType::T_CSTRING: { + nsCString *ws = (nsCString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (val == Py_None) { + NS_ABORT_IF_FALSE(0, "dont handle None here yet"); + } else { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyObject_Str(val); + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + const char *sz = PyString_AS_STRING(val_use); + ws->Assign(sz, PyString_GET_SIZE(val_use)); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_AsUTF8String(val); + const char *sz = PyBytes_AS_STRING(val_use); + ws->Assign(sz, PyBytes_GET_SIZE(val_use)); +#endif + } + break; + } + case nsXPTType::T_UTF8STRING: { + nsCString *ws = (nsCString *)ns_v.val.p; + NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); + if (val == Py_None) { + NS_ABORT_IF_FALSE(0, "dont handle None here yet"); + } else { +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(val)) { + val_use = val; + Py_INCREF(val); + } + else +#endif + if (PyUnicode_Check(val)) { + val_use = PyUnicode_AsUTF8String(val); + } else { +#if PY_MAJOR_VERSION <= 2 + PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects"); +#else + PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be unicode objects"); +#endif + BREAK_FALSE; + } +#if PY_MAJOR_VERSION <= 2 + NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!"); + const char *sz = PyString_AS_STRING(val_use); + ws->Assign(sz, PyString_GET_SIZE(val_use)); +#else + NS_ABORT_IF_FALSE(PyBytes_Check(val_use), "must have a bytes object!"); + const char *sz = PyBytes_AS_STRING(val_use); + ws->Assign(sz, PyBytes_GET_SIZE(val_use)); +#endif + } + break; + } + + case nsXPTType::T_CHAR_STR: { + // If it is an existing string, free it. + char **pp = (char **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + + if (val == Py_None) + break; // Remains NULL. +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + + const char *sz = PyString_AS_STRING(val_use); + int nch = PyString_GET_SIZE(val_use); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + if ((val_use = PyUnicode_AsUTF8String(val))==NULL) + BREAK_FALSE; + + const char *sz = PyBytes_AS_STRING(val_use); + int nch = PyBytes_GET_SIZE(val_use); +#endif + + *pp = (char *)nsMemory::Alloc(nch+1); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + strncpy(*pp, sz, nch+1); + break; + } + case nsXPTType::T_WCHAR_STR: { + // If it is an existing string, free it. + PRUnichar **pp = (PRUnichar **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + if (val == Py_None) + break; // Remains NULL. +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_FromObject(val); + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0) + BREAK_FALSE; + break; + } + case nsXPTType::T_INTERFACE: { + nsISupports *pnew = nsnull; + // Find out what IID we are declared to use. + nsIID *iid = NULL; + nsIInterfaceInfo *ii = GetInterfaceInfo(); + if (ii) + ii->GetIIDForParam(m_method_index, pi, &iid); + + // Get it the "standard" way. + // We do allow NULL here, even tho doing so will no-doubt crash some objects. + // (but there will certainly be objects out there that will allow NULL :-( + nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports); + if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE)) + BREAK_FALSE; + nsISupports **pp = (nsISupports **)ns_v.val.p; + if (*pp && pi->IsIn()) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + (*pp)->Release(); + Py_END_ALLOW_THREADS; + } + + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + case nsXPTType::T_INTERFACE_IS: { + const nsIID *piid; + if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid)) + BREAK_FALSE; + + nsISupports *pnew = nsnull; + // Get it the "standard" way. + // We do allow NULL here, even tho doing so will no-doubt crash some objects. + // (but there will certainly be objects out there that will allow NULL :-( + if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE)) + BREAK_FALSE; + nsISupports **pp = (nsISupports **)ns_v.val.p; + if (*pp && pi->IsIn()) { + Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires. + (*pp)->Release(); + Py_END_ALLOW_THREADS; + } + + *pp = pnew; // ref-count added by InterfaceFromPyObject + break; + } + + case nsXPTType::T_PSTRING_SIZE_IS: { + const char *sz = nsnull; + PRUint32 nch = 0; + if (val != Py_None) { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + if ((val_use = PyObject_Str(val))==NULL) + BREAK_FALSE; + // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode! + NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!"); + + sz = PyString_AS_STRING(val_use); + nch = PyString_GET_SIZE(val_use); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + if ((val_use = PyUnicode_AsUTF8String(val))==NULL) + BREAK_FALSE; + + sz = PyBytes_AS_STRING(val_use); + nch = PyBytes_GET_SIZE(val_use); +#endif + } + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + PRUint32 existing_size = GetSizeIs(index, PR_TRUE); + if (nch != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) { + memcpy(*(char **)ns_v.val.p, sz, nch); + } else { + // If we have an existing string, free it! + char **pp = (char **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = nsnull; + if (sz==nsnull) // None specified. + break; // Remains NULL. + *pp = (char *)nsMemory::Alloc(nch); + if (*pp==NULL) { + PyErr_NoMemory(); + BREAK_FALSE; + } + memcpy(*pp, sz, nch); + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_TRUE, nch); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size"); + } + } + break; + } + + case nsXPTType::T_PWSTRING_SIZE_IS: { + PRUnichar *sz = nsnull; + PRUint32 nch = 0; + PRUint32 nbytes = 0; + + if (val != Py_None) { +#if PY_MAJOR_VERSION <= 2 + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + BREAK_FALSE; + } + val_use = PyUnicode_FromObject(val); + NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!"); +#else + if (!PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object"); + BREAK_FALSE; + } + val_use = val; + Py_INCREF(val_use); +#endif + if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0) + BREAK_FALSE; + nbytes = sizeof(PRUnichar) * nch; + } + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + // It is a buffer the caller prolly wants us to fill in-place! + PRUint32 existing_size = GetSizeIs(index, PR_TRUE); + if (nch != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) { + memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes); + } else { + // If it is an existing string, free it. + PRUnichar **pp = (PRUnichar **)ns_v.val.p; + if (*pp && pi->IsIn()) + nsMemory::Free(*pp); + *pp = sz; + sz = nsnull; + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_TRUE, nch); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size"); + } + } + if (sz) + nsMemory::Free(sz); + break; + } + case nsXPTType::T_ARRAY: { + // If it is an existing array of the correct size, keep it. + PRUint32 sequence_size = 0; + PRUint8 array_type; + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); + if (NS_FAILED(ns)) + return ns; + PRUint32 element_size = GetArrayElementSize(array_type); + if (val != Py_None) { + if (!PySequence_Check(val)) { + PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", PyXPCOM_ObTypeName(val)); + BREAK_FALSE; + } + sequence_size = PySequence_Length(val); + } + PRUint32 existing_size = GetSizeIs(index, PR_FALSE); + PRBool bBackFill = PR_FALSE; + PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE); + // If we can not change the size, check our sequence is correct. + if (!bCanSetSizeIs) { + // It is a buffer the caller prolly wants us to fill in-place! + if (sequence_size != existing_size) { + PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size); + BREAK_FALSE; + } + // It we have an "inout" param, but an "in" count, then + // it is probably a buffer the caller expects us to + // fill in-place! + bBackFill = pi->IsIn(); + } + if (bBackFill) + rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); + else { + // If it is an existing array, free it. + void **pp = (void **)ns_v.val.p; + if (*pp && pi->IsIn()) { + FreeSingleArray(*pp, existing_size, array_type); + nsMemory::Free(*pp); + } + *pp = nsnull; + if (val == Py_None) + break; // Remains NULL. + size_t nbytes = sequence_size * element_size; + if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes + *pp = (void *)nsMemory::Alloc(nbytes); + memset(*pp, 0, nbytes); + rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); + if (!rc) break; + if (bCanSetSizeIs) + rc = SetSizeIs(index, PR_FALSE, sequence_size); + else { + NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size"); + } + } + break; + } + default: + // try and limp along in this case. + // leave rc TRUE + PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ)); + break; + } + Py_XDECREF(val_use); + if (!rc) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob) +{ + // NOTE - although we return an nresult, if we leave a Python + // exception set, then our caller may take additional action + // (ie, translating our nsresult to a more appropriate nsresult + // for the Python exception.) + NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result"); + + nsresult rc = NS_OK; + // If we dont get a tuple back, then the result is only + // an int nresult for the underlying function. + // (ie, the policy is expected to return (NS_OK, user_retval), + // but can also return (say), NS_ERROR_FAILURE + if (PyInt_Check(ret_ob)) + return PyInt_AsLong(ret_ob); + // Now it must be the tuple. + if (!PyTuple_Check(ret_ob) || + PyTuple_Size(ret_ob)!=2 || + !PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) { + PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int."); + return NS_ERROR_FAILURE; + } + PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1); + // Count up how many results our function needs. + int i; + int num_results = 0; + int last_result = -1; // optimization if we only have one - this is it! + int index_retval = -1; + for (i=0;iparams+i; + if (!m_python_type_desc_array[i].is_auto_out) { + if (pi->IsOut() || pi->IsDipper()) { + num_results++; + last_result = i; + } + if (pi->IsRetval()) + index_retval = i; + } + } + + if (num_results==0) { + ; // do nothing + } else if (num_results==1) { + // May or may not be the nominated retval - who cares! + NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!"); + rc = BackFillVariant( user_result, last_result ); + } else { + // Loop over each one, filling as we go. + // We allow arbitary sequences here, but _not_ strings + // or Unicode! + // NOTE - We ALWAYS do the nominated retval first. + // The Python pattern is always: + // return retval [, byref1 [, byref2 ...] ] + // But the retval is often the last param described in the info. + if (!PySequence_Check(user_result) || +#if PY_MAJOR_VERSION <= 2 + PyString_Check(user_result) || +#else + PyBytes_Check(user_result) || +#endif + PyUnicode_Check(user_result)) { + PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them"); + return NS_ERROR_FAILURE; + } + int num_user_results = PySequence_Length(user_result); + // If they havent given enough, we dont really care. + // although a warning is probably appropriate. + if (num_user_results != num_results) { + const char *method_name = m_info->GetName(); + PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n", + method_name, + num_results, + num_user_results); + } + int this_py_index = 0; + if (index_retval != -1) { + // We always return the nominated result first! + PyObject *sub = PySequence_GetItem(user_result, 0); + if (sub==NULL) + return NS_ERROR_FAILURE; + rc = BackFillVariant(sub, index_retval); + Py_DECREF(sub); + this_py_index = 1; + } + for (i=0;NS_SUCCEEDED(rc) && iGetParamCount();i++) { + // If weve already done it, or dont need to do it! + if (i==index_retval || m_python_type_desc_array[i].is_auto_out) + continue; + nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i; + if (pi->IsOut()) { + PyObject *sub = PySequence_GetItem(user_result, this_py_index); + if (sub==NULL) + return NS_ERROR_FAILURE; + rc = BackFillVariant(sub, i); + Py_DECREF(sub); + this_py_index++; + } + } + } + return rc; +} diff --git a/src/libs/xpcom18a4/python/src/dllmain.cpp b/src/libs/xpcom18a4/python/src/dllmain.cpp new file mode 100644 index 00000000..4cc08578 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/dllmain.cpp @@ -0,0 +1,352 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM_std.h" +#include +#include "nsIThread.h" +#include "nsILocalFile.h" + +#ifdef XP_WIN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" +#endif + +static PRInt32 g_cLockCount = 0; +static PRLock *g_lockMain = nsnull; + +PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; + +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) +// deprecated, but retained for backward compatibility: +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete) + +#ifndef PYXPCOM_USE_PYGILSTATE + +//////////////////////////////////////////////////////////// +// Thread-state helpers/global functions. +// Only used if there is no Python PyGILState_* API +// +static PyThreadState *ptsGlobal = nsnull; +PyInterpreterState *PyXPCOM_InterpreterState = nsnull; +PRUintn tlsIndex = 0; + + +// This function must be called at some time when the interpreter lock and state is valid. +// Called by init{module} functions and also COM factory entry point. +void PyXPCOM_InterpreterState_Ensure() +{ + if (PyXPCOM_InterpreterState==NULL) { + PyThreadState *threadStateSave = PyThreadState_Swap(NULL); + if (threadStateSave==NULL) + Py_FatalError("Can not setup interpreter state, as current state is invalid"); + + PyXPCOM_InterpreterState = threadStateSave->interp; + PyThreadState_Swap(threadStateSave); + } +} + +void PyXPCOM_InterpreterState_Free() +{ + PyXPCOM_ThreadState_Free(); + PyXPCOM_InterpreterState = NULL; // Eek - should I be freeing something? +} + +// This structure is stored in the TLS slot. At this stage only a Python thread state +// is kept, but this may change in the future... +struct ThreadData{ + PyThreadState *ts; +}; + +// Ensure that we have a Python thread state available to use. +// If this is called for the first time on a thread, it will allocate +// the thread state. This does NOT change the state of the Python lock. +// Returns TRUE if a new thread state was created, or FALSE if a +// thread state already existed. +PRBool PyXPCOM_ThreadState_Ensure() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + if (pData==NULL) { /* First request on this thread */ + /* Check we have an interpreter state */ + if (PyXPCOM_InterpreterState==NULL) { + Py_FatalError("Can not setup thread state, as have no interpreter state"); + } + pData = (ThreadData *)nsMemory::Alloc(sizeof(ThreadData)); + if (!pData) + Py_FatalError("Out of memory allocating thread state."); + memset(pData, 0, sizeof(*pData)); + if (NS_FAILED( PR_SetThreadPrivate( tlsIndex, pData ) ) ) { + NS_ABORT_IF_FALSE(0, "Could not create thread data for this thread!"); + Py_FatalError("Could not thread private thread data!"); + } + pData->ts = PyThreadState_New(PyXPCOM_InterpreterState); + return PR_TRUE; // Did create a thread state state + } + return PR_FALSE; // Thread state was previously created +} + +// Asuming we have a valid thread state, acquire the Python lock. +void PyXPCOM_InterpreterLock_Acquire() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); + PyThreadState *thisThreadState = pData->ts; + PyEval_AcquireThread(thisThreadState); +} + +// Asuming we have a valid thread state, release the Python lock. +void PyXPCOM_InterpreterLock_Release() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + NS_ABORT_IF_FALSE(pData, "Have no thread data for this thread!"); + PyThreadState *thisThreadState = pData->ts; + PyEval_ReleaseThread(thisThreadState); +} + +// Free the thread state for the current thread +// (Presumably previously create with a call to +// PyXPCOM_ThreadState_Ensure) +void PyXPCOM_ThreadState_Free() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + if (!pData) return; + PyThreadState *thisThreadState = pData->ts; + PyThreadState_Delete(thisThreadState); + PR_SetThreadPrivate(tlsIndex, NULL); + nsMemory::Free(pData); +} + +void PyXPCOM_ThreadState_Clear() +{ + ThreadData *pData = (ThreadData *)PR_GetThreadPrivate(tlsIndex); + PyThreadState *thisThreadState = pData->ts; + PyThreadState_Clear(thisThreadState); +} +#endif // PYXPCOM_USE_PYGILSTATE + +//////////////////////////////////////////////////////////// +// Lock/exclusion global functions. +// +void PyXPCOM_AcquireGlobalLock(void) +{ + NS_PRECONDITION(g_lockMain != nsnull, "Cant acquire a NULL lock!"); + PR_Lock(g_lockMain); +} +void PyXPCOM_ReleaseGlobalLock(void) +{ + NS_PRECONDITION(g_lockMain != nsnull, "Cant release a NULL lock!"); + PR_Unlock(g_lockMain); +} + +void PyXPCOM_DLLAddRef(void) +{ + // Must be thread-safe, although cant have the Python lock! + CEnterLeaveXPCOMFramework _celf; + PRInt32 cnt = PR_AtomicIncrement(&g_cLockCount); + if (cnt==1) { // First call + if (!Py_IsInitialized()) { + Py_Initialize(); + // Make sure our Windows framework is all setup. + PyXPCOM_Globals_Ensure(); + // Make sure we have _something_ as sys.argv. + if (PySys_GetObject((char*)"argv")==NULL) { + PyObject *path = PyList_New(0); +#if PY_MAJOR_VERSION <= 2 + PyObject *str = PyString_FromString(""); +#else + PyObject *str = PyUnicode_FromString(""); +#endif + PyList_Append(path, str); + PySys_SetObject((char*)"argv", path); + Py_XDECREF(path); + Py_XDECREF(str); + } + + // Must force Python to start using thread locks, as + // we are free-threaded (maybe, I think, sometimes :-) + PyEval_InitThreads(); +#ifndef PYXPCOM_USE_PYGILSTATE + // Release Python lock, as first thing we do is re-get it. + ptsGlobal = PyEval_SaveThread(); +#endif + // NOTE: We never finalize Python!! + } + } +} +void PyXPCOM_DLLRelease(void) +{ + PR_AtomicDecrement(&g_cLockCount); +} + +void pyxpcom_construct(void) +{ + g_lockMain = PR_NewLock(); +#ifndef PYXPCOM_USE_PYGILSTATE + PRStatus status; + status = PR_NewThreadPrivateIndex( &tlsIndex, NULL ); + NS_WARN_IF_FALSE(status==0, "Could not allocate TLS storage"); + if (NS_FAILED(status)) { + PR_DestroyLock(g_lockMain); + return; // PR_FALSE; + } +#endif // PYXPCOM_USE_PYGILSTATE + return; // PR_TRUE; +} + +void pyxpcom_destruct(void) +{ + PR_DestroyLock(g_lockMain); +#ifndef PYXPCOM_USE_PYGILSTATE + // I can't locate a way to kill this - + // should I pass a dtor to PR_NewThreadPrivateIndex?? + // TlsFree(tlsIndex); +#endif // PYXPCOM_USE_PYGILSTATE +} + +// Yet another attempt at cross-platform library initialization and finalization. +struct DllInitializer { + DllInitializer() { + pyxpcom_construct(); + } + ~DllInitializer() { + pyxpcom_destruct(); + } +} dll_initializer; + +//////////////////////////////////////////////////////////// +// Other helpers/global functions. +// +PRBool PyXPCOM_Globals_Ensure() +{ + PRBool rc = PR_TRUE; + +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + + // The exception object - we load it from .py code! + if (PyXPCOM_Error == NULL) { + rc = PR_FALSE; + PyObject *mod = NULL; + + mod = PyImport_ImportModule("xpcom"); + if (mod!=NULL) { + PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception"); + Py_DECREF(mod); + } + rc = (PyXPCOM_Error != NULL); + } + if (!rc) + return rc; + + static PRBool bHaveInitXPCOM = PR_FALSE; + if (!bHaveInitXPCOM) { + nsCOMPtr thread_check; + // xpcom appears to assert if already initialized + // Is there an official way to determine this? + if (NS_FAILED(nsIThread::GetMainThread(getter_AddRefs(thread_check)))) { + // not already initialized. +#ifdef XP_WIN + // On Windows, we need to locate the Mozilla bin + // directory. This by using locating a Moz DLL we depend + // on, and assume it lives in that bin dir. Different + // moz build types (eg, xulrunner, suite) package + // XPCOM itself differently - but all appear to require + // nspr4.dll - so this is what we use. + char landmark[MAX_PATH+1]; + HMODULE hmod = GetModuleHandle("nspr4.dll"); + if (hmod==NULL) { + PyErr_SetString(PyExc_RuntimeError, "We dont appear to be linked against nspr4.dll."); + return PR_FALSE; + } + GetModuleFileName(hmod, landmark, sizeof(landmark)/sizeof(landmark[0])); + char *end = landmark + (strlen(landmark)-1); + while (end > landmark && *end != '\\') + end--; + if (end > landmark) *end = '\0'; + + nsCOMPtr ns_bin_dir; + NS_ConvertASCIItoUCS2 strLandmark(landmark); + NS_NewLocalFile(strLandmark, PR_FALSE, getter_AddRefs(ns_bin_dir)); + nsresult rv = NS_InitXPCOM2(nsnull, ns_bin_dir, nsnull); +#else + // Elsewhere, Mozilla can find it itself (we hope!) + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif // XP_WIN + if (NS_FAILED(rv)) { + PyErr_SetString(PyExc_RuntimeError, "The XPCOM subsystem could not be initialized"); + return PR_FALSE; + } + } + // Even if xpcom was already init, we want to flag it as init! + bHaveInitXPCOM = PR_TRUE; + // Register our custom interfaces. + + Py_nsISupports::InitType(); + Py_nsIComponentManager::InitType(); + Py_nsIInterfaceInfoManager::InitType(); + Py_nsIEnumerator::InitType(); + Py_nsISimpleEnumerator::InitType(); + Py_nsIInterfaceInfo::InitType(); + Py_nsIInputStream::InitType(); + Py_nsIClassInfo::InitType(); + Py_nsIVariant::InitType(); + // for backward compatibility: + Py_nsIComponentManagerObsolete::InitType(); + + } + return rc; +} + diff --git a/src/libs/xpcom18a4/python/src/loader/pyloader.cpp b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp new file mode 100644 index 00000000..dc116f1d --- /dev/null +++ b/src/libs/xpcom18a4/python/src/loader/pyloader.cpp @@ -0,0 +1,435 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// pyloader +// +// Not part of the main Python _xpcom package, but a separate, thin DLL. +// +// The main loader and registrar for Python. A thin DLL that is designed to live in +// the xpcom "components" directory. Simply locates and loads the standard +// pyxpcom core library and transfers control to that. + +#include + +#include "nsDirectoryServiceDefs.h" +#include "nsILocalFile.h" + +#include "nspr.h" // PR_fprintf + +#if (PY_VERSION_HEX >= 0x02030000) +#define PYXPCOM_USE_PYGILSTATE +#endif + +static char *PyTraceback_AsString(PyObject *exc_tb); + +#ifdef XP_WIN +#include "windows.h" +#endif + +#ifdef XP_UNIX +#include +#include + +#endif + +#include "nsITimelineService.h" + +typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result); + + +static void LogError(const char *fmt, ...); +static void LogDebug(const char *fmt, ...); + +// Ensure that any paths guaranteed by this package exist on sys.path +// Only called once as we are first loaded into the process. +void AddStandardPaths() +{ + // Put {bin}\Python on the path if it exists. + nsresult rv; + nsCOMPtr aFile; + rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, getter_AddRefs(aFile)); + if (NS_FAILED(rv)) { + LogError("The Python XPCOM loader could not locate the 'bin' directory\n"); + return; + } + aFile->Append(NS_LITERAL_STRING("python")); + nsAutoString pathBuf; + aFile->GetPath(pathBuf); + PyObject *obPath = PySys_GetObject("path"); + if (!obPath) { + LogError("The Python XPCOM loader could not get the Python sys.path variable\n"); + return; + } + NS_LossyConvertUCS2toASCII pathCBuf(pathBuf); + LogDebug("The Python XPCOM loader is adding '%s' to sys.path\n", pathCBuf.get()); + PyObject *newStr = PyString_FromString(pathCBuf.get()); + PyList_Insert(obPath, 0, newStr); + Py_XDECREF(newStr); + // And now try and get Python to process this directory as a "site dir" + // - ie, look for .pth files, etc + nsCAutoString cmdBuf(NS_LITERAL_CSTRING("import site;site.addsitedir(r'") + pathCBuf + NS_LITERAL_CSTRING("')\n")); + if (0 != PyRun_SimpleString((char *)cmdBuf.get())) { + LogError("The directory '%s' could not be added as a site directory", pathCBuf.get()); + PyErr_Clear(); + } + // and somewhat like Python itself (site, citecustomize), we attempt + // to import "sitepyxpcom" ignoring ImportError + if (NULL==PyImport_ImportModule("sitepyxpcom")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + LogError("Failed to import 'sitepyxpcom'"); + PyErr_Clear(); + } +} + +//////////////////////////////////////////////////////////// +// This is the main entry point that delegates into Python +nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result) +{ + NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!"); +#ifndef LOADER_LINKS_WITH_PYTHON + if (!Py_IsInitialized()) { + Py_Initialize(); + if (!Py_IsInitialized()) { + PyXPCOM_LogError("Python initialization failed!\n"); + return NS_ERROR_FAILURE; + } + PyEval_InitThreads(); +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + PyEval_SaveThread(); + } +#endif // LOADER_LINKS_WITH_PYTHON + CEnterLeavePython _celp; + PyObject *func = NULL; + PyObject *obServMgr = NULL; + PyObject *obLocation = NULL; + PyObject *wrap_ret = NULL; + PyObject *args = NULL; + PyObject *mod = PyImport_ImportModule("xpcom.server"); + if (!mod) goto done; + func = PyObject_GetAttrString(mod, "NS_GetModule"); + if (func==NULL) goto done; + obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager)); + if (obServMgr==NULL) goto done; + obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile)); + if (obLocation==NULL) goto done; + args = Py_BuildValue("OO", obServMgr, obLocation); + if (args==NULL) goto done; + wrap_ret = PyEval_CallObject(func, args); + if (wrap_ret==NULL) goto done; + Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE); +done: + nsresult nr = NS_OK; + if (PyErr_Occurred()) { + PyXPCOM_LogError("Obtaining the module object from Python failed.\n"); + nr = PyXPCOM_SetCOMErrorFromPyException(); + } + Py_XDECREF(func); + Py_XDECREF(obServMgr); + Py_XDECREF(obLocation); + Py_XDECREF(wrap_ret); + Py_XDECREF(mod); + Py_XDECREF(args); + return nr; +} + +extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result) +{ +#ifdef XP_UNIX + // *sob* - seems necessary to open the .so as RTLD_GLOBAL + dlopen(PYTHON_SO,RTLD_NOW | RTLD_GLOBAL); +#endif + PRBool bDidInitPython = !Py_IsInitialized(); // well, I will next line, anyway :-) + if (bDidInitPython) { + NS_TIMELINE_START_TIMER("PyXPCOM: Python initializing"); + Py_Initialize(); + if (!Py_IsInitialized()) { + LogError("Python initialization failed!\n"); + return NS_ERROR_FAILURE; + } +#ifndef NS_DEBUG + Py_OptimizeFlag = 1; +#endif // NS_DEBUG + PyEval_InitThreads(); + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing"); + } + // Get the Python interpreter state + NS_TIMELINE_START_TIMER("PyXPCOM: Python threadstate setup"); +#ifndef PYXPCOM_USE_PYGILSTATE + PyThreadState *threadStateCreated = NULL; + PyThreadState *threadState = PyThreadState_Swap(NULL); + if (threadState==NULL) { + // no thread-state - set one up. + // *sigh* - what I consider a bug is that Python + // will deadlock unless we own the lock before creating + // a new interpreter (it appear Py_NewInterpreter has + // really only been tested/used with no thread lock + PyEval_AcquireLock(); + threadState = threadStateCreated = Py_NewInterpreter(); + PyThreadState_Swap(NULL); + } + PyEval_ReleaseLock(); + PyEval_AcquireThread(threadState); +#else + PyGILState_STATE state = PyGILState_Ensure(); +#endif // PYXPCOM_USE_PYGILSTATE +#ifdef MOZ_TIMELINE + // If the timeline service is installed, see if we can install our hooks. + if (NULL==PyImport_ImportModule("timeline_hook")) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + LogError("Failed to import 'timeline_hook'"); + PyErr_Clear(); // but don't care if we can't. + } +#endif + // Add the standard paths always - we may not have been the first to + // init Python. + AddStandardPaths(); + +#ifndef PYXPCOM_USE_PYGILSTATE + // Abandon the thread-lock, as the first thing Python does + // is re-establish the lock (the Python thread-state story SUCKS!!!) + if (threadStateCreated) { + Py_EndInterpreter(threadStateCreated); + PyEval_ReleaseLock(); // see Py_NewInterpreter call above + } else { + PyEval_ReleaseThread(threadState); + PyThreadState *threadStateSave = PyThreadState_Swap(NULL); + if (threadStateSave) + PyThreadState_Delete(threadStateSave); + } +#else + // If we initialized Python, then we will also have acquired the thread + // lock. In that case, we want to leave it unlocked, so other threads + // are free to run, even if they aren't running Python code. + PyGILState_Release(bDidInitPython ? PyGILState_UNLOCKED : state); +#endif + + NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup"); + NS_TIMELINE_START_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + nsresult rc = PyXPCOM_NSGetModule(servMgr, location, result); + NS_TIMELINE_STOP_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + NS_TIMELINE_MARK_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); + return rc; +} + +// The internal helper that actually moves the +// formatted string to the target! + +void LogMessage(const char *prefix, const char *pszMessageText) +{ + PR_fprintf(PR_STDERR, "%s", pszMessageText); +} + +void LogMessage(const char *prefix, nsACString &text) +{ + LogMessage(prefix, nsPromiseFlatCString(text).get()); +} + +// A helper for the various logging routines. +static void VLogF(const char *prefix, const char *fmt, va_list argptr) +{ + char buff[512]; + + vsprintf(buff, fmt, argptr); + + LogMessage(prefix, buff); +} + +static void LogError(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Error: ", fmt, marker); + // If we have a Python exception, also log that: + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + if (exc_typ) { + nsCAutoString streamout; + + if (exc_tb) { + const char *szTraceback = PyTraceback_AsString(exc_tb); + if (szTraceback == NULL) + streamout += "Can't get the traceback info!"; + else { + streamout += "Traceback (most recent call last):\n"; + streamout += szTraceback; + PyMem_Free((void *)szTraceback); + } + } + PyObject *temp = PyObject_Str(exc_typ); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can convert exception to a string!"; + streamout += ": "; + if (exc_val != NULL) { + temp = PyObject_Str(exc_val); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can convert exception value to a string!"; + } + streamout += "\n"; + LogMessage("PyXPCOM Exception:", streamout); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); + va_end(marker); +} +/*** - not currently used - silence compiler warning. +static void LogWarning(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Warning: ", fmt, marker); +} +***/ +#ifdef DEBUG +static void LogDebug(const char *fmt, ...) +{ + va_list marker; + va_start(marker, fmt); + VLogF("PyXPCOM Loader Debug: ", fmt, marker); + va_end(marker); +} +#else +static void LogDebug(const char *fmt, ...) +{ +} +#endif + +/* Obtains a string from a Python traceback. + This is the exact same string as "traceback.print_exc" would return. + + Pass in a Python traceback object (probably obtained from PyErr_Fetch()) + Result is a string which must be free'd using PyMem_Free() +*/ +#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;} + +char *PyTraceback_AsString(PyObject *exc_tb) +{ + char *errMsg = NULL; /* a static that hold a local error message */ + char *result = NULL; /* a valid, allocated result. */ + PyObject *modStringIO = NULL; + PyObject *modTB = NULL; + PyObject *obFuncStringIO = NULL; + PyObject *obStringIO = NULL; + PyObject *obFuncTB = NULL; + PyObject *argsTB = NULL; + PyObject *obResult = NULL; + + /* Import the modules we need - cStringIO and traceback */ + modStringIO = PyImport_ImportModule("cStringIO"); + if (modStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant import cStringIO\n"); + + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) + TRACEBACK_FETCH_ERROR("cant import traceback\n"); + /* Construct a cStringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find cStringIO.StringIO\n"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) + TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed\n"); + /* Get the traceback.print_exception function, and call it. */ + obFuncTB = PyObject_GetAttrString(modTB, "print_tb"); + if (obFuncTB==NULL) + TRACEBACK_FETCH_ERROR("cant find traceback.print_tb\n"); + + argsTB = Py_BuildValue("OOO", + exc_tb ? exc_tb : Py_None, + Py_None, + obStringIO); + if (argsTB==NULL) + TRACEBACK_FETCH_ERROR("cant make print_tb arguments\n"); + + obResult = PyObject_CallObject(obFuncTB, argsTB); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("traceback.print_tb() failed\n"); + /* Now call the getvalue() method in the StringIO instance */ + Py_DECREF(obFuncStringIO); + obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); + if (obFuncStringIO==NULL) + TRACEBACK_FETCH_ERROR("cant find getvalue function\n"); + Py_DECREF(obResult); + obResult = PyObject_CallObject(obFuncStringIO, NULL); + if (obResult==NULL) + TRACEBACK_FETCH_ERROR("getvalue() failed.\n"); + + /* And it should be a string all ready to go - duplicate it. */ + if (!PyString_Check(obResult)) + TRACEBACK_FETCH_ERROR("getvalue() did not return a string\n"); + + { // a temp scope so I can use temp locals. + char *tempResult = PyString_AsString(obResult); + result = (char *)PyMem_Malloc(strlen(tempResult)+1); + if (result==NULL) + TRACEBACK_FETCH_ERROR("memory error duplicating the traceback string"); + + strcpy(result, tempResult); + } // end of temp scope. +done: + /* All finished - first see if we encountered an error */ + if (result==NULL && errMsg != NULL) { + result = (char *)PyMem_Malloc(strlen(errMsg)+1); + if (result != NULL) + /* if it does, not much we can do! */ + strcpy(result, errMsg); + } + Py_XDECREF(modStringIO); + Py_XDECREF(modTB); + Py_XDECREF(obFuncStringIO); + Py_XDECREF(obStringIO); + Py_XDECREF(obFuncTB); + Py_XDECREF(argsTB); + Py_XDECREF(obResult); + return result; +} diff --git a/src/libs/xpcom18a4/python/src/module/_xpcom.cpp b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp new file mode 100644 index 00000000..d40d2b52 --- /dev/null +++ b/src/libs/xpcom18a4/python/src/module/_xpcom.cpp @@ -0,0 +1,950 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 code is part of the XPCOM extensions for Python. +// +// Written May 2000 by Mark Hammond. +// +// Based heavily on the Python COM support, which is +// (c) Mark Hammond and Greg Stein. +// +// (c) 2000, ActiveState corp. + +#include "PyXPCOM.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsIFile.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIConsoleService.h" +#include "nspr.h" // PR_fprintf +#ifdef VBOX +# include "nsEventQueueUtils.h" +#endif + +#ifdef XP_WIN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "windows.h" +#endif + +#include "nsIEventQueue.h" +#include "nsIProxyObjectManager.h" + +#define LOADER_LINKS_WITH_PYTHON + +#ifndef PYXPCOM_USE_PYGILSTATE +extern PYXPCOM_EXPORT void PyXPCOM_InterpreterState_Ensure(); +#endif + +#ifdef VBOX_PYXPCOM +# include +# include +# ifndef MODULE_NAME_SUFFIX +# define MANGLE_MODULE_NAME(a_szName) a_szName +# define MANGLE_MODULE_INIT(a_Name) a_Name +# else +# define MANGLE_MODULE_NAME(a_szName) a_szName RT_XSTR(MODULE_NAME_SUFFIX) +# define MANGLE_MODULE_INIT(a_Name) RT_CONCAT(a_Name, MODULE_NAME_SUFFIX) +# endif +# if defined(VBOX_PYXPCOM_VERSIONED) && !defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# if PY_VERSION_HEX >= 0x030a0000 && PY_VERSION_HEX < 0x030b0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_10") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_10) + +# elif PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_9") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_9) + +# elif PY_VERSION_HEX >= 0x03080000 && PY_VERSION_HEX < 0x03090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_8") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_8) + +# elif PY_VERSION_HEX >= 0x03070000 && PY_VERSION_HEX < 0x03080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_7") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_7) + +# elif PY_VERSION_HEX >= 0x03060000 && PY_VERSION_HEX < 0x03070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_6") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_6) + +# elif PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03060000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_5") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_5) + +# elif PY_VERSION_HEX >= 0x03040000 && PY_VERSION_HEX < 0x03050000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_4") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_4) + +# elif PY_VERSION_HEX >= 0x03030000 && PY_VERSION_HEX < 0x03040000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_3) + +# elif PY_VERSION_HEX >= 0x03020000 && PY_VERSION_HEX < 0x03030000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_2") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_2) + +# elif PY_VERSION_HEX >= 0x03010000 && PY_VERSION_HEX < 0x03020000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3_1") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3_1) + +# elif PY_VERSION_HEX >= 0x02080000 && PY_VERSION_HEX < 0x02090000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_8") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_8) + +# elif PY_VERSION_HEX >= 0x02070000 && PY_VERSION_HEX < 0x02080000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_7") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_7) + +# elif PY_VERSION_HEX >= 0x02060000 && PY_VERSION_HEX < 0x02070000 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2_6") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2_6) +# else +# error "Fix module versioning. This Python version is not recognized." +# endif +# else +# if PY_MAJOR_VERSION <= 2 && defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython2") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython2) +# elif PY_MAJOR_VERSION <= 2 +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(initVBoxPython) +# elif defined(Py_LIMITED_API) || defined(VBOX_PYXPCOM_MAJOR_VERSIONED) +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython3") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython3) +# else +# define MODULE_NAME MANGLE_MODULE_NAME("VBoxPython") +# define initVBoxPython MANGLE_MODULE_INIT(PyInit_VBoxPython) +# endif +# endif +#else +#define MODULE_NAME "_xpcom" +#endif + +// "boot-strap" methods - interfaces we need to get the base +// interface support! + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_NS_GetGlobalComponentManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetComponentManager instead") < 0) + return NULL; + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + nsCOMPtr ocm(do_QueryInterface(cm, &rv)); + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(ocm, NS_GET_IID(nsIComponentManagerObsolete), PR_FALSE); +} +#endif + +static PyObject * +PyXPCOMMethod_GetComponentManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentManager(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_FALSE); +} + +// No xpcom callable way to get at the registrar, even though the interface +// is scriptable. +static PyObject * +PyXPCOMMethod_GetComponentRegistrar(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentRegistrar(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsISupports), PR_FALSE); +} + +static PyObject * +PyXPCOMMethod_GetServiceManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr sm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetServiceManager(getter_AddRefs(sm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + // Return a type based on the IID. + return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager)); +} + +#ifndef VBOX +/* deprecated, included for backward compatibility */ +static PyObject * +PyXPCOMMethod_GetGlobalServiceManager(PyObject *self, PyObject *args) +{ + if (PyErr_Warn(PyExc_DeprecationWarning, "Use GetServiceManager instead") < 0) + return NULL; + + return PyXPCOMMethod_GetComponentManager(self, args); +} +#endif + +static PyObject * +PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsIInterfaceInfoManager* im; + Py_BEGIN_ALLOW_THREADS; + im = XPTI_GetInterfaceInfoManager(); + Py_END_ALLOW_THREADS; + if ( im == nsnull ) + return PyXPCOM_BuildPyException(NS_ERROR_FAILURE); + + /* Return a type based on the IID (with no extra ref) */ + // Can not auto-wrap the interface info manager as it is critical to + // building the support we need for autowrap. + PyObject *ret = Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE); + NS_IF_RELEASE(im); + return ret; +} + +static PyObject * +PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args) +{ + PyObject *obIS, *obParams; + nsCOMPtr pis; + int index; + + // We no longer rely on PyErr_Occurred() for our error state, + // but keeping this assertion can't hurt - it should still always be true! + NS_WARN_IF_FALSE(!PyErr_Occurred(), "Should be no pending Python error!"); + + if (!PyArg_ParseTuple(args, "OiO", &obIS, &index, &obParams)) + return NULL; + + if (!Py_nsISupports::Check(obIS)) { + return PyErr_Format(PyExc_TypeError, + "First param must be a native nsISupports wrapper (got %s)", + PyXPCOM_ObTypeName(obIS)); + } + // Ack! We must ask for the "native" interface supported by + // the object, not specifically nsISupports, else we may not + // back the same pointer (eg, Python, following identity rules, + // will return the "original" gateway when QI'd for nsISupports) + if (!Py_nsISupports::InterfaceFromPyObject( + obIS, + Py_nsIID_NULL, + getter_AddRefs(pis), + PR_FALSE)) + return NULL; + + PyXPCOM_InterfaceVariantHelper arg_helper((Py_nsISupports *)obIS, index); + if (!arg_helper.Init(obParams)) + return NULL; + + if (!arg_helper.FillArray()) + return NULL; + + nsresult r; + Py_BEGIN_ALLOW_THREADS; + r = XPTC_InvokeByIndex(pis, index, arg_helper.m_num_array, arg_helper.m_var_array); +/** @todo bird: Maybe we could processing pending XPCOM events here to make + * life a bit simpler inside python? */ + Py_END_ALLOW_THREADS; + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + return arg_helper.MakePythonResult(); +} + +static PyObject * +PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob, *obIID; + int bWrapClient = 1; + if (!PyArg_ParseTuple(args, "OO|i", &ob, &obIID, &bWrapClient)) + return NULL; + + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + + nsCOMPtr ret; + nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, getter_AddRefs(ret)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + + // _ALL_ wrapped objects are associated with a weak-ref + // to their "main" instance. + AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance. + + // Now wrap it in an interface. + return Py_nsISupports::PyObjectFromInterface(ret, iid, bWrapClient); +} + +static PyObject * +PyXPCOMMethod_UnwrapObject(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O", &ob)) + return NULL; + + nsISupports *uob = NULL; + nsIInternalPython *iob = NULL; + PyObject *ret = NULL; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + &uob, + PR_FALSE)) + goto done; + if (NS_FAILED(uob->QueryInterface(NS_GET_IID(nsIInternalPython), reinterpret_cast(&iob)))) { + PyErr_SetString(PyExc_ValueError, "This XPCOM object is not implemented by Python"); + goto done; + } + ret = iob->UnwrapPythonObject(); +done: + Py_BEGIN_ALLOW_THREADS; + NS_IF_RELEASE(uob); + NS_IF_RELEASE(iob); + Py_END_ALLOW_THREADS; + return ret; +} + +// @pymethod int|pythoncom|_GetInterfaceCount|Retrieves the number of interface objects currently in existance +static PyObject * +PyXPCOMMethod_GetInterfaceCount(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_GetInterfaceCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetInterfaceCount()); + // @comm If is occasionally a good idea to call this function before your Python program + // terminates. If this function returns non-zero, then you still have PythonCOM objects + // alive in your program (possibly in global variables). +} + +#ifdef VBOX_DEBUG_LIFETIMES +// @pymethod int|pythoncom|_DumpInterfaces|Dumps the interfaces still in existance to standard output +static PyObject * +PyXPCOMMethod_DumpInterfaces(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":_DumpInterfaces")) + return NULL; + return PyInt_FromLong(_PyXPCOM_DumpInterfaces()); +} +#endif + +// @pymethod int|pythoncom|_GetGatewayCount|Retrieves the number of gateway objects currently in existance +static PyObject * +PyXPCOMMethod_GetGatewayCount(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":_GetGatewayCount")) + return NULL; + return PyInt_FromLong(_PyXPCOM_GetGatewayCount()); +} + +static PyObject * +PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args) +{ + // @comm This is the number of Python object that implement COM servers which + // are still alive (ie, serving a client). The only way to reduce this count + // is to have the process which uses these PythonCOM servers release its references. + if (!PyArg_ParseTuple(args, ":NS_ShutdownXPCOM")) + return NULL; + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = NS_ShutdownXPCOM(nsnull); + Py_END_ALLOW_THREADS; + +#ifdef VBOX_DEBUG_LIFETIME + Py_nsISupports::dumpList(); +#endif + + // Dont raise an exception - as we are probably shutting down + // and dont really case - just return the status + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + +// A hack to work around their magic constants! +static PyObject * +PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) +{ + PyObject *obQueue, *obIID, *obOb; + int flags; + if (!PyArg_ParseTuple(args, "OOOi", &obQueue, &obIID, &obOb, &flags)) + return NULL; + nsIID iid; + if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) + return NULL; + nsCOMPtr pob; + if (!Py_nsISupports::InterfaceFromPyObject(obOb, iid, getter_AddRefs(pob), PR_FALSE)) + return NULL; + nsIEventQueue *pQueue = NULL; + nsIEventQueue *pQueueRelease = NULL; + + if (PyInt_Check(obQueue)) { + pQueue = (nsIEventQueue *)PyInt_AsLong(obQueue); + } else { + if (!Py_nsISupports::InterfaceFromPyObject(obQueue, NS_GET_IID(nsIEventQueue), (nsISupports **)&pQueue, PR_TRUE)) + return NULL; + pQueueRelease = pQueue; + } + + nsresult rv_proxy; + nsCOMPtr presult; + Py_BEGIN_ALLOW_THREADS; + nsCOMPtr proxyMgr = + do_GetService(kProxyObjectManagerCID, &rv_proxy); + + if ( NS_SUCCEEDED(rv_proxy) ) { + rv_proxy = proxyMgr->GetProxyForObject(pQueue, + iid, + pob, + flags, + getter_AddRefs(presult)); + } + if (pQueueRelease) + pQueueRelease->Release(); + Py_END_ALLOW_THREADS; + + PyObject *result; + if (NS_SUCCEEDED(rv_proxy) ) { + result = Py_nsISupports::PyObjectFromInterface(presult, iid); + } else { + result = PyXPCOM_BuildPyException(rv_proxy); + } + return result; +} + +static PyObject * +PyXPCOMMethod_MakeVariant(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O:MakeVariant", &ob)) + return NULL; + nsCOMPtr pVar; + nsresult nr = PyObject_AsVariant(ob, getter_AddRefs(pVar)); + if (NS_FAILED(nr)) + return PyXPCOM_BuildPyException(nr); + if (pVar == nsnull) { + NS_ERROR("PyObject_AsVariant worked but returned a NULL ptr!"); + return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + } + return Py_nsISupports::PyObjectFromInterface(pVar, NS_GET_IID(nsIVariant)); +} + +static PyObject * +PyXPCOMMethod_GetVariantValue(PyObject *self, PyObject *args) +{ + PyObject *ob, *obParent = NULL; + if (!PyArg_ParseTuple(args, "O|O:GetVariantValue", &ob, &obParent)) + return NULL; + + nsCOMPtr var; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + getter_AddRefs(var), + PR_FALSE)) + return PyErr_Format(PyExc_ValueError, + "Object is not an nsIVariant (got %s)", + PyXPCOM_ObTypeName(ob)); + + Py_nsISupports *parent = nsnull; + if (obParent && obParent != Py_None) { + if (!Py_nsISupports::Check(obParent)) { + PyErr_SetString(PyExc_ValueError, + "Object not an nsISupports wrapper"); + return NULL; + } + parent = (Py_nsISupports *)obParent; + } + return PyObject_FromVariant(parent, var); +} + +PyObject *PyGetSpecialDirectory(PyObject *self, PyObject *args) +{ + char *dirname; + if (!PyArg_ParseTuple(args, "s:GetSpecialDirectory", &dirname)) + return NULL; + nsCOMPtr file; + nsresult r = NS_GetSpecialDirectory(dirname, getter_AddRefs(file)); + if ( NS_FAILED(r) ) + return PyXPCOM_BuildPyException(r); + // returned object swallows our reference. + return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile)); +} + +PyObject *AllocateBuffer(PyObject *self, PyObject *args) +{ + int bufSize; + if (!PyArg_ParseTuple(args, "i", &bufSize)) + return NULL; +#if PY_MAJOR_VERSION <= 2 + return PyBuffer_New(bufSize); +#else + return PyBytes_FromStringAndSize(NULL, bufSize); +#endif +} + +// Writes a message to the console service. This could be done via pure +// Python code, but is useful when the logging code is actually the +// xpcom .py framework itself (ie, we don't want our logging framework to +// call back into the very code generating the log messages! +PyObject *LogConsoleMessage(PyObject *self, PyObject *args) +{ + char *msg; + if (!PyArg_ParseTuple(args, "s", &msg)) + return NULL; + + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + else { + // This either means no such service, or in shutdown - hardly worth + // the warning, and not worth reporting an error to Python about - its + // log handler would just need to catch and ignore it. + // And as this is only called by this logging setup, any messages should + // still go to stderr or a logfile. + NS_WARNING("pyxpcom can't log console message."); + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef VBOX + +# include +# include + +static PyObject * +PyXPCOMMethod_WaitForEvents(PyObject *self, PyObject *args) +{ + long lTimeout; + if (!PyArg_ParseTuple(args, "l", &lTimeout)) + return NULL; + + int rc; + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + { + PyErr_SetString(PyExc_TypeError, "the main event queue is NULL"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + + RTMSINTERVAL cMsTimeout = (RTMSINTERVAL)lTimeout; + if (lTimeout < 0 || (long)cMsTimeout != lTimeout) + cMsTimeout = RT_INDEFINITE_WAIT; + rc = aEventQ->processEventQueue(cMsTimeout); + + Py_END_ALLOW_THREADS + if (RT_SUCCESS(rc)) + return PyInt_FromLong(0); + + if ( rc == VERR_TIMEOUT + || rc == VERR_INTERRUPTED) + return PyInt_FromLong(1); + + if (rc == VERR_INVALID_CONTEXT) + { + PyErr_SetString(PyExc_Exception, "wrong thread, use the main thread"); + return NULL; + } + + return PyInt_FromLong(2); +} + +static PyObject* +PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args) +{ + com::NativeEventQueue* aEventQ = com::NativeEventQueue::getMainEventQueue(); + NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue"); + if (!aEventQ) + return NULL; + + int rc = aEventQ->interruptEventQueueProcessing(); + return PyBool_FromLong(RT_SUCCESS(rc)); +} + +static nsresult deinitVBoxPython(); + +static PyObject* +PyXPCOMMethod_DeinitCOM(PyObject *self, PyObject *args) +{ + nsresult nr; + Py_BEGIN_ALLOW_THREADS; + nr = deinitVBoxPython(); + Py_END_ALLOW_THREADS; + return PyInt_FromLong(nr); +} + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static PyObject* +PyXPCOMMethod_AttachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr eqs; + + // Create the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->CreateThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +static PyObject* +PyXPCOMMethod_DetachThread(PyObject *self, PyObject *args) +{ + nsresult rv; + PRInt32 result = 0; + nsCOMPtr eqs; + + // Destroy the Event Queue for this thread... + Py_BEGIN_ALLOW_THREADS; + eqs = + do_GetService(kEventQueueServiceCID, &rv); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 1; + goto done; + } + + Py_BEGIN_ALLOW_THREADS; + rv = eqs->DestroyThreadEventQueue(); + Py_END_ALLOW_THREADS; + if (NS_FAILED(rv)) + { + result = 2; + goto done; + } + + done: + /** @todo: better throw an exception on error */ + return PyInt_FromLong(result); +} + +#endif /* VBOX */ + +extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args); + +static struct PyMethodDef xpcom_methods[]= +{ + {"GetComponentManager", PyXPCOMMethod_GetComponentManager, 1}, + {"GetComponentRegistrar", PyXPCOMMethod_GetComponentRegistrar, 1}, +#ifndef VBOX + {"NS_GetGlobalComponentManager", PyXPCOMMethod_NS_GetGlobalComponentManager, 1}, // deprecated +#endif + {"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1}, + {"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1}, + {"GetServiceManager", PyXPCOMMethod_GetServiceManager, 1}, +#ifndef VBOX + {"GetGlobalServiceManager", PyXPCOMMethod_GetGlobalServiceManager, 1}, // deprecated + {"IID", PyXPCOMMethod_IID, 1}, // IID is wrong - deprecated - not just IID, but CID, etc. +#endif + {"ID", PyXPCOMMethod_IID, 1}, // This is the official name. + {"NS_ShutdownXPCOM", PyXPCOMMethod_NS_ShutdownXPCOM, 1}, + {"WrapObject", PyXPCOMMethod_WrapObject, 1}, + {"UnwrapObject", PyXPCOMMethod_UnwrapObject, 1}, + {"_GetInterfaceCount", PyXPCOMMethod_GetInterfaceCount, 1}, + {"_GetGatewayCount", PyXPCOMMethod_GetGatewayCount, 1}, + {"getProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, + {"GetSpecialDirectory", PyGetSpecialDirectory, 1}, + {"AllocateBuffer", AllocateBuffer, 1}, + {"LogConsoleMessage", LogConsoleMessage, 1, "Write a message to the xpcom console service"}, + {"MakeVariant", PyXPCOMMethod_MakeVariant, 1}, + {"GetVariantValue", PyXPCOMMethod_GetVariantValue, 1}, +#ifdef VBOX + {"WaitForEvents", PyXPCOMMethod_WaitForEvents, 1}, + {"InterruptWait", PyXPCOMMethod_InterruptWait, 1}, + {"DeinitCOM", PyXPCOMMethod_DeinitCOM, 1}, + {"AttachThread", PyXPCOMMethod_AttachThread, 1}, + {"DetachThread", PyXPCOMMethod_DetachThread, 1}, +#endif +#ifdef VBOX_DEBUG_LIFETIMES + {"_DumpInterfaces", PyXPCOMMethod_DumpInterfaces, 1}, +#endif + // These should no longer be used - just use the logging.getLogger('pyxpcom')... + /* bird: The above comment refers to LogWarning and LogError. Both now removed. */ + { NULL } +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef xpcom_module = +{ + PyModuleDef_HEAD_INIT, + MODULE_NAME, /* name of module */ + NULL, /* module documentation */ + -1, /* size of per-interpreter state or -1 if using globals */ + xpcom_methods +}; +#endif + + +#define REGISTER_IID(t) { \ + PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \ + PyDict_SetItemString(dict, "IID_"#t, iid_ob); \ + Py_DECREF(iid_ob); \ + } + +#define REGISTER_INT(val) { \ + PyObject *ob = PyInt_FromLong(val); \ + PyDict_SetItemString(dict, #val, ob); \ + Py_DECREF(ob); \ + } + + +//////////////////////////////////////////////////////////// +// The module init code. +// +#if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +#else +PyObject * +#endif +init_xpcom() { + PyObject *oModule; + + // ensure the framework has valid state to work with. + if (!PyXPCOM_Globals_Ensure()) +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + + // Must force Python to start using thread locks + PyEval_InitThreads(); + + // Create the module and add the functions +#if PY_MAJOR_VERSION <= 2 + oModule = Py_InitModule(MODULE_NAME, xpcom_methods); +#else + oModule = PyModule_Create(&xpcom_module); +#endif + + PyObject *dict = PyModule_GetDict(oModule); + PyObject *pycom_Error = PyXPCOM_Error; + if (pycom_Error == NULL || PyDict_SetItemString(dict, "error", pycom_Error) != 0) + { + PyErr_SetString(PyExc_MemoryError, "can't define error"); +#if PY_MAJOR_VERSION <= 2 + return; +#else + return NULL; +#endif + } +#ifndef Py_LIMITED_API + PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type); +#else + PyDict_SetItemString(dict, "IIDType", (PyObject *)Py_nsIID::GetTypeObject()); +#endif + + REGISTER_IID(nsISupports); + REGISTER_IID(nsISupportsCString); + REGISTER_IID(nsISupportsString); + REGISTER_IID(nsIModule); + REGISTER_IID(nsIFactory); + REGISTER_IID(nsIWeakReference); + REGISTER_IID(nsISupportsWeakReference); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIServiceManager); + REGISTER_IID(nsIComponentRegistrar); + + // Register our custom interfaces. + REGISTER_IID(nsIComponentManager); + REGISTER_IID(nsIInterfaceInfoManager); + REGISTER_IID(nsIEnumerator); + REGISTER_IID(nsISimpleEnumerator); + REGISTER_IID(nsIInterfaceInfo); + REGISTER_IID(nsIInputStream); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIVariant); + // for backward compatibility: + REGISTER_IID(nsIComponentManagerObsolete); + + // No good reason not to expose this impl detail, and tests can use it + REGISTER_IID(nsIInternalPython); + // We have special support for proxies - may as well add their constants! + REGISTER_INT(PROXY_SYNC); + REGISTER_INT(PROXY_ASYNC); + REGISTER_INT(PROXY_ALWAYS); + // Build flags that may be useful. + PyObject *ob = PyBool_FromLong( +#ifdef NS_DEBUG + 1 +#else + 0 +#endif + ); + PyDict_SetItemString(dict, "NS_DEBUG", ob); + Py_DECREF(ob); +#if PY_MAJOR_VERSION >= 3 + return oModule; +#endif +} + +#ifdef VBOX_PYXPCOM +# include +using namespace com; + +# include +# include +# include +# include + +/** Set if NS_ShutdownXPCOM has been called successfully already and we don't + * need to do it again during module termination. This avoids assertion in the + * VBoxCOM glue code. */ +static bool g_fComShutdownAlready = true; + +# if PY_MAJOR_VERSION <= 2 +extern "C" NS_EXPORT +void +# else +/** @todo r=klaus this is hacky, but as Python3 doesn't deal with ELF + * visibility, assuming that all globals are visible (which is ugly and not + * true in our case). */ +# undef PyMODINIT_FUNC +# define PyMODINIT_FUNC extern "C" NS_EXPORT PyObject* +PyMODINIT_FUNC +# endif +initVBoxPython() { /* NOTE! This name is redefined at the top of the file! */ + static bool s_vboxInited = false; + if (!s_vboxInited) { + int rc = 0; /* Error handling in this code is NON-EXISTING. Sigh. */ + +# if defined(VBOX_PATH_APP_PRIVATE_ARCH) && defined(VBOX_PATH_SHARED_LIBS) + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); +# else + const char *home = getenv("VBOX_PROGRAM_PATH"); + if (home) { + size_t len = strlen(home); + char *exepath = (char *)alloca(len + 32); + memcpy(exepath, home, len); + memcpy(exepath + len, "/pythonfake", sizeof("/pythonfake")); + rc = RTR3InitEx(RTR3INIT_VER_CUR, RTR3INIT_FLAGS_DLL | RTR3INIT_FLAGS_UNOBTRUSIVE, 0, NULL, exepath); + } else { + rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE); + } +# endif + + rc = com::Initialize(); + g_fComShutdownAlready = false; + +# if PY_MAJOR_VERSION <= 2 + init_xpcom(); +# else + return init_xpcom(); +# endif + } +# if PY_MAJOR_VERSION >= 3 + return NULL; +# endif +} + +static +nsresult deinitVBoxPython() +{ + nsresult nr; + if (!g_fComShutdownAlready) + { + nr = com::Shutdown(); + if (!NS_FAILED(nr)) + g_fComShutdownAlready = true; + } + else + nr = NS_ERROR_NOT_INITIALIZED; + return nr; +} + +#endif /* VBOX_PYXPCOM */ diff --git a/src/libs/xpcom18a4/python/src/readme.html b/src/libs/xpcom18a4/python/src/readme.html new file mode 100644 index 00000000..b049dbad --- /dev/null +++ b/src/libs/xpcom18a4/python/src/readme.html @@ -0,0 +1,99 @@ + + + + + + + + +Building the Python XPCOM package + + + + +

Building the Python XPCOM package.

+ +

This file describes how to build the Python XPCOM C++ sources.

+

There are the following steps

+ +

Testing etc is described in the main readme.

+

Configuring environment variables

+

MOZ_SRC 

+

Windows: Run the standard MOZENV.BAT used to build Mozilla.  This +sets MOZ_SRC

+

Unix: Set MOZ_SRC to point to the base source directory - assumes +"mozilla" sub-directory with mozilla directory tree under that. eg: assuming +/home/user/src/mozilla/dist/..."

+
export MOZ_SRC=/home/user/src
+

PYTHON_SRC

+

Windows: Set PYTHON_SRC to point to the base Python source directory.  +eg: assuming c:\src\python\PCBuild\...

set PYTHON_SRC=c:\src\python
+

Unix: Set PYTHON_SRC to point to the base of an "installed" Python +tree. eg:

export PYTHON_SRC=/usr/local/ActivePython-1.6
+

Building the sources

+

You must ensure some environment variables are setup.  The section on configuring +environment variables explains how.

+

There are 2 build processes to run All C++ sources are in the xpcom\src + directory.:

+

Windows

+
    +
  • Execute "compile.py" in this directory. This will take Setup.in, create an MSDev project, and build + ..\_xpcom.pyd and ..\_xpcom_d.pyd"
  • +
  • Change to the loader directory.
  • +
  • Run nmake -f makefile.win. This will create pyloader.dll, and + automatically copy it to the Mozilla build directory.
  • + +
+

Finally, run the tests, + where we also test everything imports correctly.

+

Linux

+

NOTE: Do not attempt to use "Setup.in" to create a Makefile 

+
    +
  • Run "make" in this directory.  This will create ../_xpcommodule.so
  • +
  • Run "make" in the loader directory. This will create libpyloader.so, + and copy it to the Mozilla directory.
  • + +
+

Finally, running the tests, + where we also test everything imports correctly.

+ + + + diff --git a/src/libs/xpcom18a4/python/test/.cvsignore b/src/libs/xpcom18a4/python/test/.cvsignore new file mode 100644 index 00000000..52e4e611 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/.cvsignore @@ -0,0 +1,2 @@ +*.pyc +*.pyo diff --git a/src/libs/xpcom18a4/python/test/output/test_com_exceptions b/src/libs/xpcom18a4/python/test/output/test_com_exceptions new file mode 100644 index 00000000..16e4bda1 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_com_exceptions @@ -0,0 +1,8 @@ +test_com_exceptions +** Unhandled exception calling 'int8 do_short(in int16, inout int16, out int16, out retval int16);' +** Returning nsresult of NS_ERROR_FAILURE +** Unhandled exception calling 'int8 do_unsigned_short(in uint16, inout uint16, out uint16, out retval uint16);' +** Returning nsresult of NS_ERROR_FAILURE +** Unhandled exception calling 'int8 do_unsigned_long_long(in uint64, inout uint64, out uint64, out retval uint64);' +** Returning nsresult of NS_ERROR_FAILURE +The xpcom exception tests passed diff --git a/src/libs/xpcom18a4/python/test/output/test_comfile b/src/libs/xpcom18a4/python/test/output/test_comfile new file mode 100644 index 00000000..8de43add --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_comfile @@ -0,0 +1,7 @@ +test_comfile +Open as string test worked. +Open as URL test worked. +File test using buffers worked. +Local file read test worked. +Read the correct data. +Chunks read the correct data. diff --git a/src/libs/xpcom18a4/python/test/output/test_components b/src/libs/xpcom18a4/python/test/output/test_components new file mode 100644 index 00000000..4a6386e7 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_components @@ -0,0 +1,4 @@ +test_components +The interfaces object appeared to work! +The classes object appeared to work! +The ID function appeared to work! diff --git a/src/libs/xpcom18a4/python/test/output/test_isupports_primitives b/src/libs/xpcom18a4/python/test/output/test_isupports_primitives new file mode 100644 index 00000000..7765ac21 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_isupports_primitives @@ -0,0 +1,2 @@ +test_isupports_primitives +The nsISupports primitive interface tests appeared to work diff --git a/src/libs/xpcom18a4/python/test/output/test_streams b/src/libs/xpcom18a4/python/test/output/test_streams new file mode 100644 index 00000000..e81ef151 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_streams @@ -0,0 +1 @@ +test_streams diff --git a/src/libs/xpcom18a4/python/test/output/test_test_component b/src/libs/xpcom18a4/python/test/output/test_test_component new file mode 100644 index 00000000..c57c1325 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_test_component @@ -0,0 +1,4 @@ +test_test_component +Testing the Python.TestComponent component +The Python test component worked! +Javascript could successfully use the Python test component. diff --git a/src/libs/xpcom18a4/python/test/output/test_weakreferences b/src/libs/xpcom18a4/python/test/output/test_weakreferences new file mode 100644 index 00000000..b337d26a --- /dev/null +++ b/src/libs/xpcom18a4/python/test/output/test_weakreferences @@ -0,0 +1,2 @@ +test_weakreferences +Weak-reference tests appear to have worked! diff --git a/src/libs/xpcom18a4/python/test/pyxpcom_test_tools.py b/src/libs/xpcom18a4/python/test/pyxpcom_test_tools.py new file mode 100755 index 00000000..447c5446 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/pyxpcom_test_tools.py @@ -0,0 +1,126 @@ +# test tools for the pyxpcom bindings +from xpcom import _xpcom +import unittest + +# export a "getmemusage()" function that returns a useful "bytes used" count +# for the current process. Growth in this when doing the same thing over and +# over implies a leak. + +try: + import win32api + import win32pdh + import win32pdhutil + have_pdh = 1 +except ImportError: + have_pdh = 0 + +# XXX - win32pdh is slow, particularly finding our current process. +# A better way would be good. + +# Our win32pdh specific functions - they can be at the top-level on all +# platforms, but will only actually be called if the modules are available. +def FindMyCounter(): + pid_me = win32api.GetCurrentProcessId() + + object = "Process" + items, instances = win32pdh.EnumObjectItems(None,None,object, -1) + for instance in instances: + # We use 2 counters - "ID Process" and "Working Set" + counter = "ID Process" + format = win32pdh.PDH_FMT_LONG + + hq = win32pdh.OpenQuery() + path = win32pdh.MakeCounterPath( (None,object,instance, None, -1,"ID Process") ) + hc1 = win32pdh.AddCounter(hq, path) + path = win32pdh.MakeCounterPath( (None,object,instance, None, -1,"Working Set") ) + hc2 = win32pdh.AddCounter(hq, path) + win32pdh.CollectQueryData(hq) + type, pid = win32pdh.GetFormattedCounterValue(hc1, format) + if pid==pid_me: + win32pdh.RemoveCounter(hc1) # not needed any more + return hq, hc2 + # Not mine - close the query and try again + win32pdh.RemoveCounter(hc1) + win32pdh.RemoveCounter(hc2) + win32pdh.CloseQuery(hq) + else: + raise RuntimeError, "Can't find myself!?" + +def CloseCounter(hq, hc): + win32pdh.RemoveCounter(hc) + win32pdh.CloseQuery(hq) + +def GetCounterValue(hq, hc): + win32pdh.CollectQueryData(hq) + format = win32pdh.PDH_FMT_LONG + type, val = win32pdh.GetFormattedCounterValue(hc, format) + return val + +g_pdh_data = None +# The pdh function that does the work +def pdh_getmemusage(): + global g_pdh_data + if g_pdh_data is None: + hq, hc = FindMyCounter() + g_pdh_data = hq, hc + hq, hc = g_pdh_data + return GetCounterValue(hq, hc) + +# The public bit +if have_pdh: + getmemusage = pdh_getmemusage +else: + def getmemusage(): + return 0 + +# Test runner utilities, including some support for builtin leak tests. +class TestLoader(unittest.TestLoader): + def loadTestsFromTestCase(self, testCaseClass): + """Return a suite of all tests cases contained in testCaseClass""" + leak_tests = [] + for name in self.getTestCaseNames(testCaseClass): + real_test = testCaseClass(name) + leak_test = self._getTestWrapper(real_test) + leak_tests.append(leak_test) + return self.suiteClass(leak_tests) + def _getTestWrapper(self, test): + # later! see pywin32's win32/test/util.py + return test + def loadTestsFromModule(self, mod): + if hasattr(mod, "suite"): + ret = mod.suite() + else: + ret = unittest.TestLoader.loadTestsFromModule(self, mod) + assert ret.countTestCases() > 0, "No tests in %r" % (mod,) + return ret + def loadTestsFromName(self, name, module=None): + test = unittest.TestLoader.loadTestsFromName(self, name, module) + if isinstance(test, unittest.TestSuite): + pass # hmmm? print "Don't wrap suites yet!", test._tests + elif isinstance(test, unittest.TestCase): + test = self._getTestWrapper(test) + else: + print "XXX - what is", test + return test + +# A base class our tests should derive from (well, one day it will be) +TestCase = unittest.TestCase + +def suite_from_functions(*funcs): + suite = unittest.TestSuite() + for func in funcs: + suite.addTest(unittest.FunctionTestCase(func)) + return suite + +def testmain(*args, **kw): + new_kw = kw.copy() + if not new_kw.has_key('testLoader'): + new_kw['testLoader'] = TestLoader() + try: + unittest.main(*args, **new_kw) + finally: + _xpcom.NS_ShutdownXPCOM() + ni = _xpcom._GetInterfaceCount() + ng = _xpcom._GetGatewayCount() + if ni or ng: + print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) diff --git a/src/libs/xpcom18a4/python/test/regrtest.py b/src/libs/xpcom18a4/python/test/regrtest.py new file mode 100644 index 00000000..90d07948 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/regrtest.py @@ -0,0 +1,91 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# regrtest.py +# +# The Regression Tests for the xpcom package. +import os +import sys + +import unittest + +# A little magic to create a single "test suite" from all test_ files +# in this dir. A single suite makes for prettier output test :) +def suite(): + # Loop over all test_*.py files here + try: + me = __file__ + except NameError: + me = sys.argv[0] + me = os.path.abspath(me) + files = os.listdir(os.path.dirname(me)) + suite = unittest.TestSuite() + # XXX - add the others here! + #suite.addTest(unittest.FunctionTestCase(import_all)) + for file in files: + base, ext = os.path.splitext(file) + if ext=='.py' and os.path.basename(base).startswith("test_"): + mod = __import__(base) + if hasattr(mod, "suite"): + test = mod.suite() + else: + test = unittest.defaultTestLoader.loadTestsFromModule(mod) + suite.addTest(test) + return suite + +class CustomLoader(unittest.TestLoader): + def loadTestsFromModule(self, module): + return suite() + +try: + unittest.TestProgram(testLoader=CustomLoader())(argv=sys.argv) +finally: + from xpcom import _xpcom + _xpcom.NS_ShutdownXPCOM() # To get leak stats and otherwise ensure life is good. + ni = _xpcom._GetInterfaceCount() + ng = _xpcom._GetGatewayCount() + if ni or ng: + # The old 'regrtest' that was not based purely on unittest did not + # do this check at the end - it relied on each module doing it itself. + # Thus, these leaks are not new, just newly noticed :) Likely to be + # something silly like module globals. + if ni == 6 and ng == 1: + print "Sadly, there are 6/1 leaks, but these appear normal and benign" + else: + print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) + else: + print "yay! Our leaks have all vanished!" diff --git a/src/libs/xpcom18a4/python/test/test_com_exceptions.py b/src/libs/xpcom18a4/python/test/test_com_exceptions.py new file mode 100755 index 00000000..7813bf98 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_com_exceptions.py @@ -0,0 +1,124 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is ActiveState Tool Corp. +# Portions created by ActiveState Tool Corp. are Copyright (C) 2000, 2001 +# ActiveState Tool Corp. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# Test pyxpcom exception. + +from xpcom import components, nsError, ServerException, COMException, logger +from xpcom.server import WrapObject +from pyxpcom_test_tools import testmain + +import unittest +import logging + +class PythonFailingComponent: + # Re-use the test interface for this test. + _com_interfaces_ = components.interfaces.nsIPythonTestInterfaceExtra + + def do_boolean(self, p1, p2): + # This should cause the caller to see a "silent" NS_ERROR_FAILURE exception. + raise ServerException() + + def do_octet(self, p1, p2): + # This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception. + raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED) + + def do_short(self, p1, p2): + # This should cause the caller to see a "debug" NS_ERROR_FAILURE exception. + raise COMException(nsError.NS_ERROR_NOT_IMPLEMENTED) + + def do_unsigned_short(self, p1, p2): + # This should cause the caller to see a "debug" NS_ERROR_FAILURE exception. + raise "Foo" + + def do_long(self, p1, p2): + # This should cause the caller to see a "silent" NS_ERROR_FAILURE exception. + raise ServerException + + def do_unsigned_long(self, p1, p2): + # This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception. + raise ServerException, nsError.NS_ERROR_NOT_IMPLEMENTED + + def do_long_long(self, p1, p2): + # This should cause the caller to see a "silent" NS_ERROR_NOT_IMPLEMENTED exception. + raise ServerException, (nsError.NS_ERROR_NOT_IMPLEMENTED, "testing") + + def do_unsigned_long_long(self, p1, p2): + # Report of a crash in this case - test it! + raise ServerException, "A bad exception param" + +class TestHandler(logging.Handler): + def __init__(self, level=logging.ERROR): # only counting error records + logging.Handler.__init__(self, level) + self.records = [] + + def reset(self): + self.records = [] + + def handle(self, record): + self.records.append(record) + +class ExceptionTests(unittest.TestCase): + + def _testit(self, expected_errno, num_tracebacks, func, *args): + + # Screw with the logger + old_handlers = logger.handlers + test_handler = TestHandler() + logger.handlers = [test_handler] + + try: + try: + apply(func, args) + except COMException, what: + if what.errno != expected_errno: + raise + finally: + logger.handlers = old_handlers + self.failUnlessEqual(num_tracebacks, len(test_handler.records)) + + def testEmAll(self): + ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra) + self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_boolean, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_octet, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_short, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_short, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_long, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_unsigned_long, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_long_long, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_long_long, 0, 0) + +if __name__=='__main__': + testmain() diff --git a/src/libs/xpcom18a4/python/test/test_comfile.py b/src/libs/xpcom18a4/python/test/test_comfile.py new file mode 100755 index 00000000..9ffebe37 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_comfile.py @@ -0,0 +1,49 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (markh@activestate.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 ***** + +"""Test the xpcom.file module.""" +from pyxpcom_test_tools import suite_from_functions, testmain + +import xpcom.file + +# Make this test run under our std test suite +def suite(): + return suite_from_functions(xpcom.file._TestAll) + +if __name__=='__main__': + testmain() + diff --git a/src/libs/xpcom18a4/python/test/test_component/_xpidlgen/.done b/src/libs/xpcom18a4/python/test/test_component/_xpidlgen/.done new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/python/test/test_component/_xpidlgen/py_test_component.h b/src/libs/xpcom18a4/python/test/test_component/_xpidlgen/py_test_component.h new file mode 100644 index 00000000..7d0cd8c9 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_component/_xpidlgen/py_test_component.h @@ -0,0 +1,1411 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM py_test_component.idl + */ + +#ifndef __gen_py_test_component_h__ +#define __gen_py_test_component_h__ + + +#ifndef __gen_nsISupports_h__ +#include "nsISupports.h" +#endif + +#ifndef __gen_nsIVariant_h__ +#include "nsIVariant.h" +#endif + +/* For IDL files that don't want to include root IDL files. */ +#ifndef NS_NO_VTABLE +#define NS_NO_VTABLE +#endif + +/* starting interface: nsIPythonTestInterface */ +#define NS_IPYTHONTESTINTERFACE_IID_STR "1ecaed4f-e4d5-4ee7-abf0-7d72ae1441d7" + +#define NS_IPYTHONTESTINTERFACE_IID \ + {0x1ecaed4f, 0xe4d5, 0x4ee7, \ + { 0xab, 0xf0, 0x7d, 0x72, 0xae, 0x14, 0x41, 0xd7 }} + +class NS_NO_VTABLE nsIPythonTestInterface : public nsISupports { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPYTHONTESTINTERFACE_IID) + + enum { One = 1 }; + + enum { Two = 2 }; + + enum { MinusOne = -1 }; + + enum { BigLong = 2147483647 }; + + enum { BiggerLong = 4294967295 }; + + enum { BigULong = 4294967295U }; + + /* attribute boolean boolean_value; */ + NS_IMETHOD GetBoolean_value(PRBool *aBoolean_value) = 0; + NS_IMETHOD SetBoolean_value(PRBool aBoolean_value) = 0; + + /* attribute octet octet_value; */ + NS_IMETHOD GetOctet_value(PRUint8 *aOctet_value) = 0; + NS_IMETHOD SetOctet_value(PRUint8 aOctet_value) = 0; + + /* attribute short short_value; */ + NS_IMETHOD GetShort_value(PRInt16 *aShort_value) = 0; + NS_IMETHOD SetShort_value(PRInt16 aShort_value) = 0; + + /* attribute unsigned short ushort_value; */ + NS_IMETHOD GetUshort_value(PRUint16 *aUshort_value) = 0; + NS_IMETHOD SetUshort_value(PRUint16 aUshort_value) = 0; + + /* attribute long long_value; */ + NS_IMETHOD GetLong_value(PRInt32 *aLong_value) = 0; + NS_IMETHOD SetLong_value(PRInt32 aLong_value) = 0; + + /* attribute unsigned long ulong_value; */ + NS_IMETHOD GetUlong_value(PRUint32 *aUlong_value) = 0; + NS_IMETHOD SetUlong_value(PRUint32 aUlong_value) = 0; + + /* attribute long long long_long_value; */ + NS_IMETHOD GetLong_long_value(PRInt64 *aLong_long_value) = 0; + NS_IMETHOD SetLong_long_value(PRInt64 aLong_long_value) = 0; + + /* attribute unsigned long long ulong_long_value; */ + NS_IMETHOD GetUlong_long_value(PRUint64 *aUlong_long_value) = 0; + NS_IMETHOD SetUlong_long_value(PRUint64 aUlong_long_value) = 0; + + /* attribute float float_value; */ + NS_IMETHOD GetFloat_value(float *aFloat_value) = 0; + NS_IMETHOD SetFloat_value(float aFloat_value) = 0; + + /* attribute double double_value; */ + NS_IMETHOD GetDouble_value(double *aDouble_value) = 0; + NS_IMETHOD SetDouble_value(double aDouble_value) = 0; + + /* attribute char char_value; */ + NS_IMETHOD GetChar_value(char *aChar_value) = 0; + NS_IMETHOD SetChar_value(char aChar_value) = 0; + + /* attribute wchar wchar_value; */ + NS_IMETHOD GetWchar_value(PRUnichar *aWchar_value) = 0; + NS_IMETHOD SetWchar_value(PRUnichar aWchar_value) = 0; + + /* attribute string string_value; */ + NS_IMETHOD GetString_value(char * *aString_value) = 0; + NS_IMETHOD SetString_value(const char * aString_value) = 0; + + /* attribute wstring wstring_value; */ + NS_IMETHOD GetWstring_value(PRUnichar * *aWstring_value) = 0; + NS_IMETHOD SetWstring_value(const PRUnichar * aWstring_value) = 0; + + /* attribute AString astring_value; */ + NS_IMETHOD GetAstring_value(nsAString & aAstring_value) = 0; + NS_IMETHOD SetAstring_value(const nsAString & aAstring_value) = 0; + + /* attribute ACString acstring_value; */ + NS_IMETHOD GetAcstring_value(nsACString & aAcstring_value) = 0; + NS_IMETHOD SetAcstring_value(const nsACString & aAcstring_value) = 0; + + /* attribute AUTF8String utf8string_value; */ + NS_IMETHOD GetUtf8string_value(nsACString & aUtf8string_value) = 0; + NS_IMETHOD SetUtf8string_value(const nsACString & aUtf8string_value) = 0; + + /* attribute nsIIDRef iid_value; */ + NS_IMETHOD GetIid_value(nsIID & *aIid_value) = 0; + NS_IMETHOD SetIid_value(const nsIID & aIid_value) = 0; + + /* attribute nsIPythonTestInterface interface_value; */ + NS_IMETHOD GetInterface_value(nsIPythonTestInterface * *aInterface_value) = 0; + NS_IMETHOD SetInterface_value(nsIPythonTestInterface * aInterface_value) = 0; + + /* attribute nsISupports isupports_value; */ + NS_IMETHOD GetIsupports_value(nsISupports * *aIsupports_value) = 0; + NS_IMETHOD SetIsupports_value(nsISupports * aIsupports_value) = 0; + + /* boolean do_boolean (in boolean p1, inout boolean p2, out boolean p3); */ + NS_IMETHOD Do_boolean(PRBool p1, PRBool *p2, PRBool *p3, PRBool *_retval) = 0; + + /* octet do_octet (in octet p1, inout octet p2, out octet p3); */ + NS_IMETHOD Do_octet(PRUint8 p1, PRUint8 *p2, PRUint8 *p3, PRUint8 *_retval) = 0; + + /* short do_short (in short p1, inout short p2, out short p3); */ + NS_IMETHOD Do_short(PRInt16 p1, PRInt16 *p2, PRInt16 *p3, PRInt16 *_retval) = 0; + + /* unsigned short do_unsigned_short (in unsigned short p1, inout unsigned short p2, out unsigned short p3); */ + NS_IMETHOD Do_unsigned_short(PRUint16 p1, PRUint16 *p2, PRUint16 *p3, PRUint16 *_retval) = 0; + + /* long do_long (in long p1, inout long p2, out long p3); */ + NS_IMETHOD Do_long(PRInt32 p1, PRInt32 *p2, PRInt32 *p3, PRInt32 *_retval) = 0; + + /* unsigned long do_unsigned_long (in unsigned long p1, inout unsigned long p2, out unsigned long p3); */ + NS_IMETHOD Do_unsigned_long(PRUint32 p1, PRUint32 *p2, PRUint32 *p3, PRUint32 *_retval) = 0; + + /* long long do_long_long (in long long p1, inout long long p2, out long long p3); */ + NS_IMETHOD Do_long_long(PRInt64 p1, PRInt64 *p2, PRInt64 *p3, PRInt64 *_retval) = 0; + + /* unsigned long long do_unsigned_long_long (in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3); */ + NS_IMETHOD Do_unsigned_long_long(PRUint64 p1, PRUint64 *p2, PRUint64 *p3, PRUint64 *_retval) = 0; + + /* float do_float (in float p1, inout float p2, out float p3); */ + NS_IMETHOD Do_float(float p1, float *p2, float *p3, float *_retval) = 0; + + /* double do_double (in double p1, inout double p2, out double p3); */ + NS_IMETHOD Do_double(double p1, double *p2, double *p3, double *_retval) = 0; + + /* char do_char (in char p1, inout char p2, out char p3); */ + NS_IMETHOD Do_char(char p1, char *p2, char *p3, char *_retval) = 0; + + /* wchar do_wchar (in wchar p1, inout wchar p2, out wchar p3); */ + NS_IMETHOD Do_wchar(PRUnichar p1, PRUnichar *p2, PRUnichar *p3, PRUnichar *_retval) = 0; + + /* string do_string (in string p1, inout string p2, out string p3); */ + NS_IMETHOD Do_string(const char *p1, char **p2, char **p3, char **_retval) = 0; + + /* wstring do_wstring (in wstring p1, inout wstring p2, out wstring p3); */ + NS_IMETHOD Do_wstring(const PRUnichar *p1, PRUnichar **p2, PRUnichar **p3, PRUnichar **_retval) = 0; + + /* nsIIDRef do_nsIIDRef (in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3); */ + NS_IMETHOD Do_nsIIDRef(const nsIID & p1, nsIID & *p2, nsIID & *p3, nsIID & *_retval) = 0; + + /* nsIPythonTestInterface do_nsIPythonTestInterface (in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3); */ + NS_IMETHOD Do_nsIPythonTestInterface(nsIPythonTestInterface *p1, nsIPythonTestInterface **p2, nsIPythonTestInterface **p3, nsIPythonTestInterface **_retval) = 0; + + /* nsISupports do_nsISupports (in nsISupports p1, inout nsISupports p2, out nsISupports p3); */ + NS_IMETHOD Do_nsISupports(nsISupports *p1, nsISupports **p2, nsISupports **p3, nsISupports **_retval) = 0; + + /* void do_nsISupportsIs (in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */ + NS_IMETHOD Do_nsISupportsIs(const nsIID & iid, void * *result) = 0; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIPYTHONTESTINTERFACE \ + NS_IMETHOD GetBoolean_value(PRBool *aBoolean_value); \ + NS_IMETHOD SetBoolean_value(PRBool aBoolean_value); \ + NS_IMETHOD GetOctet_value(PRUint8 *aOctet_value); \ + NS_IMETHOD SetOctet_value(PRUint8 aOctet_value); \ + NS_IMETHOD GetShort_value(PRInt16 *aShort_value); \ + NS_IMETHOD SetShort_value(PRInt16 aShort_value); \ + NS_IMETHOD GetUshort_value(PRUint16 *aUshort_value); \ + NS_IMETHOD SetUshort_value(PRUint16 aUshort_value); \ + NS_IMETHOD GetLong_value(PRInt32 *aLong_value); \ + NS_IMETHOD SetLong_value(PRInt32 aLong_value); \ + NS_IMETHOD GetUlong_value(PRUint32 *aUlong_value); \ + NS_IMETHOD SetUlong_value(PRUint32 aUlong_value); \ + NS_IMETHOD GetLong_long_value(PRInt64 *aLong_long_value); \ + NS_IMETHOD SetLong_long_value(PRInt64 aLong_long_value); \ + NS_IMETHOD GetUlong_long_value(PRUint64 *aUlong_long_value); \ + NS_IMETHOD SetUlong_long_value(PRUint64 aUlong_long_value); \ + NS_IMETHOD GetFloat_value(float *aFloat_value); \ + NS_IMETHOD SetFloat_value(float aFloat_value); \ + NS_IMETHOD GetDouble_value(double *aDouble_value); \ + NS_IMETHOD SetDouble_value(double aDouble_value); \ + NS_IMETHOD GetChar_value(char *aChar_value); \ + NS_IMETHOD SetChar_value(char aChar_value); \ + NS_IMETHOD GetWchar_value(PRUnichar *aWchar_value); \ + NS_IMETHOD SetWchar_value(PRUnichar aWchar_value); \ + NS_IMETHOD GetString_value(char * *aString_value); \ + NS_IMETHOD SetString_value(const char * aString_value); \ + NS_IMETHOD GetWstring_value(PRUnichar * *aWstring_value); \ + NS_IMETHOD SetWstring_value(const PRUnichar * aWstring_value); \ + NS_IMETHOD GetAstring_value(nsAString & aAstring_value); \ + NS_IMETHOD SetAstring_value(const nsAString & aAstring_value); \ + NS_IMETHOD GetAcstring_value(nsACString & aAcstring_value); \ + NS_IMETHOD SetAcstring_value(const nsACString & aAcstring_value); \ + NS_IMETHOD GetUtf8string_value(nsACString & aUtf8string_value); \ + NS_IMETHOD SetUtf8string_value(const nsACString & aUtf8string_value); \ + NS_IMETHOD GetIid_value(nsIID & *aIid_value); \ + NS_IMETHOD SetIid_value(const nsIID & aIid_value); \ + NS_IMETHOD GetInterface_value(nsIPythonTestInterface * *aInterface_value); \ + NS_IMETHOD SetInterface_value(nsIPythonTestInterface * aInterface_value); \ + NS_IMETHOD GetIsupports_value(nsISupports * *aIsupports_value); \ + NS_IMETHOD SetIsupports_value(nsISupports * aIsupports_value); \ + NS_IMETHOD Do_boolean(PRBool p1, PRBool *p2, PRBool *p3, PRBool *_retval); \ + NS_IMETHOD Do_octet(PRUint8 p1, PRUint8 *p2, PRUint8 *p3, PRUint8 *_retval); \ + NS_IMETHOD Do_short(PRInt16 p1, PRInt16 *p2, PRInt16 *p3, PRInt16 *_retval); \ + NS_IMETHOD Do_unsigned_short(PRUint16 p1, PRUint16 *p2, PRUint16 *p3, PRUint16 *_retval); \ + NS_IMETHOD Do_long(PRInt32 p1, PRInt32 *p2, PRInt32 *p3, PRInt32 *_retval); \ + NS_IMETHOD Do_unsigned_long(PRUint32 p1, PRUint32 *p2, PRUint32 *p3, PRUint32 *_retval); \ + NS_IMETHOD Do_long_long(PRInt64 p1, PRInt64 *p2, PRInt64 *p3, PRInt64 *_retval); \ + NS_IMETHOD Do_unsigned_long_long(PRUint64 p1, PRUint64 *p2, PRUint64 *p3, PRUint64 *_retval); \ + NS_IMETHOD Do_float(float p1, float *p2, float *p3, float *_retval); \ + NS_IMETHOD Do_double(double p1, double *p2, double *p3, double *_retval); \ + NS_IMETHOD Do_char(char p1, char *p2, char *p3, char *_retval); \ + NS_IMETHOD Do_wchar(PRUnichar p1, PRUnichar *p2, PRUnichar *p3, PRUnichar *_retval); \ + NS_IMETHOD Do_string(const char *p1, char **p2, char **p3, char **_retval); \ + NS_IMETHOD Do_wstring(const PRUnichar *p1, PRUnichar **p2, PRUnichar **p3, PRUnichar **_retval); \ + NS_IMETHOD Do_nsIIDRef(const nsIID & p1, nsIID & *p2, nsIID & *p3, nsIID & *_retval); \ + NS_IMETHOD Do_nsIPythonTestInterface(nsIPythonTestInterface *p1, nsIPythonTestInterface **p2, nsIPythonTestInterface **p3, nsIPythonTestInterface **_retval); \ + NS_IMETHOD Do_nsISupports(nsISupports *p1, nsISupports **p2, nsISupports **p3, nsISupports **_retval); \ + NS_IMETHOD Do_nsISupportsIs(const nsIID & iid, void * *result); + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIPYTHONTESTINTERFACE(_to) \ + NS_IMETHOD GetBoolean_value(PRBool *aBoolean_value) { return _to GetBoolean_value(aBoolean_value); } \ + NS_IMETHOD SetBoolean_value(PRBool aBoolean_value) { return _to SetBoolean_value(aBoolean_value); } \ + NS_IMETHOD GetOctet_value(PRUint8 *aOctet_value) { return _to GetOctet_value(aOctet_value); } \ + NS_IMETHOD SetOctet_value(PRUint8 aOctet_value) { return _to SetOctet_value(aOctet_value); } \ + NS_IMETHOD GetShort_value(PRInt16 *aShort_value) { return _to GetShort_value(aShort_value); } \ + NS_IMETHOD SetShort_value(PRInt16 aShort_value) { return _to SetShort_value(aShort_value); } \ + NS_IMETHOD GetUshort_value(PRUint16 *aUshort_value) { return _to GetUshort_value(aUshort_value); } \ + NS_IMETHOD SetUshort_value(PRUint16 aUshort_value) { return _to SetUshort_value(aUshort_value); } \ + NS_IMETHOD GetLong_value(PRInt32 *aLong_value) { return _to GetLong_value(aLong_value); } \ + NS_IMETHOD SetLong_value(PRInt32 aLong_value) { return _to SetLong_value(aLong_value); } \ + NS_IMETHOD GetUlong_value(PRUint32 *aUlong_value) { return _to GetUlong_value(aUlong_value); } \ + NS_IMETHOD SetUlong_value(PRUint32 aUlong_value) { return _to SetUlong_value(aUlong_value); } \ + NS_IMETHOD GetLong_long_value(PRInt64 *aLong_long_value) { return _to GetLong_long_value(aLong_long_value); } \ + NS_IMETHOD SetLong_long_value(PRInt64 aLong_long_value) { return _to SetLong_long_value(aLong_long_value); } \ + NS_IMETHOD GetUlong_long_value(PRUint64 *aUlong_long_value) { return _to GetUlong_long_value(aUlong_long_value); } \ + NS_IMETHOD SetUlong_long_value(PRUint64 aUlong_long_value) { return _to SetUlong_long_value(aUlong_long_value); } \ + NS_IMETHOD GetFloat_value(float *aFloat_value) { return _to GetFloat_value(aFloat_value); } \ + NS_IMETHOD SetFloat_value(float aFloat_value) { return _to SetFloat_value(aFloat_value); } \ + NS_IMETHOD GetDouble_value(double *aDouble_value) { return _to GetDouble_value(aDouble_value); } \ + NS_IMETHOD SetDouble_value(double aDouble_value) { return _to SetDouble_value(aDouble_value); } \ + NS_IMETHOD GetChar_value(char *aChar_value) { return _to GetChar_value(aChar_value); } \ + NS_IMETHOD SetChar_value(char aChar_value) { return _to SetChar_value(aChar_value); } \ + NS_IMETHOD GetWchar_value(PRUnichar *aWchar_value) { return _to GetWchar_value(aWchar_value); } \ + NS_IMETHOD SetWchar_value(PRUnichar aWchar_value) { return _to SetWchar_value(aWchar_value); } \ + NS_IMETHOD GetString_value(char * *aString_value) { return _to GetString_value(aString_value); } \ + NS_IMETHOD SetString_value(const char * aString_value) { return _to SetString_value(aString_value); } \ + NS_IMETHOD GetWstring_value(PRUnichar * *aWstring_value) { return _to GetWstring_value(aWstring_value); } \ + NS_IMETHOD SetWstring_value(const PRUnichar * aWstring_value) { return _to SetWstring_value(aWstring_value); } \ + NS_IMETHOD GetAstring_value(nsAString & aAstring_value) { return _to GetAstring_value(aAstring_value); } \ + NS_IMETHOD SetAstring_value(const nsAString & aAstring_value) { return _to SetAstring_value(aAstring_value); } \ + NS_IMETHOD GetAcstring_value(nsACString & aAcstring_value) { return _to GetAcstring_value(aAcstring_value); } \ + NS_IMETHOD SetAcstring_value(const nsACString & aAcstring_value) { return _to SetAcstring_value(aAcstring_value); } \ + NS_IMETHOD GetUtf8string_value(nsACString & aUtf8string_value) { return _to GetUtf8string_value(aUtf8string_value); } \ + NS_IMETHOD SetUtf8string_value(const nsACString & aUtf8string_value) { return _to SetUtf8string_value(aUtf8string_value); } \ + NS_IMETHOD GetIid_value(nsIID & *aIid_value) { return _to GetIid_value(aIid_value); } \ + NS_IMETHOD SetIid_value(const nsIID & aIid_value) { return _to SetIid_value(aIid_value); } \ + NS_IMETHOD GetInterface_value(nsIPythonTestInterface * *aInterface_value) { return _to GetInterface_value(aInterface_value); } \ + NS_IMETHOD SetInterface_value(nsIPythonTestInterface * aInterface_value) { return _to SetInterface_value(aInterface_value); } \ + NS_IMETHOD GetIsupports_value(nsISupports * *aIsupports_value) { return _to GetIsupports_value(aIsupports_value); } \ + NS_IMETHOD SetIsupports_value(nsISupports * aIsupports_value) { return _to SetIsupports_value(aIsupports_value); } \ + NS_IMETHOD Do_boolean(PRBool p1, PRBool *p2, PRBool *p3, PRBool *_retval) { return _to Do_boolean(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_octet(PRUint8 p1, PRUint8 *p2, PRUint8 *p3, PRUint8 *_retval) { return _to Do_octet(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_short(PRInt16 p1, PRInt16 *p2, PRInt16 *p3, PRInt16 *_retval) { return _to Do_short(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_short(PRUint16 p1, PRUint16 *p2, PRUint16 *p3, PRUint16 *_retval) { return _to Do_unsigned_short(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_long(PRInt32 p1, PRInt32 *p2, PRInt32 *p3, PRInt32 *_retval) { return _to Do_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_long(PRUint32 p1, PRUint32 *p2, PRUint32 *p3, PRUint32 *_retval) { return _to Do_unsigned_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_long_long(PRInt64 p1, PRInt64 *p2, PRInt64 *p3, PRInt64 *_retval) { return _to Do_long_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_long_long(PRUint64 p1, PRUint64 *p2, PRUint64 *p3, PRUint64 *_retval) { return _to Do_unsigned_long_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_float(float p1, float *p2, float *p3, float *_retval) { return _to Do_float(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_double(double p1, double *p2, double *p3, double *_retval) { return _to Do_double(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_char(char p1, char *p2, char *p3, char *_retval) { return _to Do_char(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_wchar(PRUnichar p1, PRUnichar *p2, PRUnichar *p3, PRUnichar *_retval) { return _to Do_wchar(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_string(const char *p1, char **p2, char **p3, char **_retval) { return _to Do_string(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_wstring(const PRUnichar *p1, PRUnichar **p2, PRUnichar **p3, PRUnichar **_retval) { return _to Do_wstring(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsIIDRef(const nsIID & p1, nsIID & *p2, nsIID & *p3, nsIID & *_retval) { return _to Do_nsIIDRef(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsIPythonTestInterface(nsIPythonTestInterface *p1, nsIPythonTestInterface **p2, nsIPythonTestInterface **p3, nsIPythonTestInterface **_retval) { return _to Do_nsIPythonTestInterface(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsISupports(nsISupports *p1, nsISupports **p2, nsISupports **p3, nsISupports **_retval) { return _to Do_nsISupports(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsISupportsIs(const nsIID & iid, void * *result) { return _to Do_nsISupportsIs(iid, result); } + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIPYTHONTESTINTERFACE(_to) \ + NS_IMETHOD GetBoolean_value(PRBool *aBoolean_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetBoolean_value(aBoolean_value); } \ + NS_IMETHOD SetBoolean_value(PRBool aBoolean_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetBoolean_value(aBoolean_value); } \ + NS_IMETHOD GetOctet_value(PRUint8 *aOctet_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetOctet_value(aOctet_value); } \ + NS_IMETHOD SetOctet_value(PRUint8 aOctet_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetOctet_value(aOctet_value); } \ + NS_IMETHOD GetShort_value(PRInt16 *aShort_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetShort_value(aShort_value); } \ + NS_IMETHOD SetShort_value(PRInt16 aShort_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetShort_value(aShort_value); } \ + NS_IMETHOD GetUshort_value(PRUint16 *aUshort_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUshort_value(aUshort_value); } \ + NS_IMETHOD SetUshort_value(PRUint16 aUshort_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetUshort_value(aUshort_value); } \ + NS_IMETHOD GetLong_value(PRInt32 *aLong_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetLong_value(aLong_value); } \ + NS_IMETHOD SetLong_value(PRInt32 aLong_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetLong_value(aLong_value); } \ + NS_IMETHOD GetUlong_value(PRUint32 *aUlong_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUlong_value(aUlong_value); } \ + NS_IMETHOD SetUlong_value(PRUint32 aUlong_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetUlong_value(aUlong_value); } \ + NS_IMETHOD GetLong_long_value(PRInt64 *aLong_long_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetLong_long_value(aLong_long_value); } \ + NS_IMETHOD SetLong_long_value(PRInt64 aLong_long_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetLong_long_value(aLong_long_value); } \ + NS_IMETHOD GetUlong_long_value(PRUint64 *aUlong_long_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUlong_long_value(aUlong_long_value); } \ + NS_IMETHOD SetUlong_long_value(PRUint64 aUlong_long_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetUlong_long_value(aUlong_long_value); } \ + NS_IMETHOD GetFloat_value(float *aFloat_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetFloat_value(aFloat_value); } \ + NS_IMETHOD SetFloat_value(float aFloat_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetFloat_value(aFloat_value); } \ + NS_IMETHOD GetDouble_value(double *aDouble_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDouble_value(aDouble_value); } \ + NS_IMETHOD SetDouble_value(double aDouble_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetDouble_value(aDouble_value); } \ + NS_IMETHOD GetChar_value(char *aChar_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetChar_value(aChar_value); } \ + NS_IMETHOD SetChar_value(char aChar_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetChar_value(aChar_value); } \ + NS_IMETHOD GetWchar_value(PRUnichar *aWchar_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetWchar_value(aWchar_value); } \ + NS_IMETHOD SetWchar_value(PRUnichar aWchar_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetWchar_value(aWchar_value); } \ + NS_IMETHOD GetString_value(char * *aString_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetString_value(aString_value); } \ + NS_IMETHOD SetString_value(const char * aString_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetString_value(aString_value); } \ + NS_IMETHOD GetWstring_value(PRUnichar * *aWstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetWstring_value(aWstring_value); } \ + NS_IMETHOD SetWstring_value(const PRUnichar * aWstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetWstring_value(aWstring_value); } \ + NS_IMETHOD GetAstring_value(nsAString & aAstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetAstring_value(aAstring_value); } \ + NS_IMETHOD SetAstring_value(const nsAString & aAstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetAstring_value(aAstring_value); } \ + NS_IMETHOD GetAcstring_value(nsACString & aAcstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetAcstring_value(aAcstring_value); } \ + NS_IMETHOD SetAcstring_value(const nsACString & aAcstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetAcstring_value(aAcstring_value); } \ + NS_IMETHOD GetUtf8string_value(nsACString & aUtf8string_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUtf8string_value(aUtf8string_value); } \ + NS_IMETHOD SetUtf8string_value(const nsACString & aUtf8string_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetUtf8string_value(aUtf8string_value); } \ + NS_IMETHOD GetIid_value(nsIID & *aIid_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetIid_value(aIid_value); } \ + NS_IMETHOD SetIid_value(const nsIID & aIid_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetIid_value(aIid_value); } \ + NS_IMETHOD GetInterface_value(nsIPythonTestInterface * *aInterface_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetInterface_value(aInterface_value); } \ + NS_IMETHOD SetInterface_value(nsIPythonTestInterface * aInterface_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetInterface_value(aInterface_value); } \ + NS_IMETHOD GetIsupports_value(nsISupports * *aIsupports_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetIsupports_value(aIsupports_value); } \ + NS_IMETHOD SetIsupports_value(nsISupports * aIsupports_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetIsupports_value(aIsupports_value); } \ + NS_IMETHOD Do_boolean(PRBool p1, PRBool *p2, PRBool *p3, PRBool *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_boolean(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_octet(PRUint8 p1, PRUint8 *p2, PRUint8 *p3, PRUint8 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_octet(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_short(PRInt16 p1, PRInt16 *p2, PRInt16 *p3, PRInt16 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_short(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_short(PRUint16 p1, PRUint16 *p2, PRUint16 *p3, PRUint16 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_unsigned_short(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_long(PRInt32 p1, PRInt32 *p2, PRInt32 *p3, PRInt32 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_long(PRUint32 p1, PRUint32 *p2, PRUint32 *p3, PRUint32 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_unsigned_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_long_long(PRInt64 p1, PRInt64 *p2, PRInt64 *p3, PRInt64 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_long_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_unsigned_long_long(PRUint64 p1, PRUint64 *p2, PRUint64 *p3, PRUint64 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_unsigned_long_long(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_float(float p1, float *p2, float *p3, float *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_float(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_double(double p1, double *p2, double *p3, double *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_double(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_char(char p1, char *p2, char *p3, char *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_char(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_wchar(PRUnichar p1, PRUnichar *p2, PRUnichar *p3, PRUnichar *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_wchar(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_string(const char *p1, char **p2, char **p3, char **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_string(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_wstring(const PRUnichar *p1, PRUnichar **p2, PRUnichar **p3, PRUnichar **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_wstring(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsIIDRef(const nsIID & p1, nsIID & *p2, nsIID & *p3, nsIID & *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_nsIIDRef(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsIPythonTestInterface(nsIPythonTestInterface *p1, nsIPythonTestInterface **p2, nsIPythonTestInterface **p3, nsIPythonTestInterface **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_nsIPythonTestInterface(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsISupports(nsISupports *p1, nsISupports **p2, nsISupports **p3, nsISupports **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_nsISupports(p1, p2, p3, _retval); } \ + NS_IMETHOD Do_nsISupportsIs(const nsIID & iid, void * *result) { return !_to ? NS_ERROR_NULL_POINTER : _to->Do_nsISupportsIs(iid, result); } + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsPythonTestInterface : public nsIPythonTestInterface +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPYTHONTESTINTERFACE + + nsPythonTestInterface(); + +private: + ~nsPythonTestInterface(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsPythonTestInterface, nsIPythonTestInterface) + +nsPythonTestInterface::nsPythonTestInterface() +{ + /* member initializers and constructor code */ +} + +nsPythonTestInterface::~nsPythonTestInterface() +{ + /* destructor code */ +} + +/* attribute boolean boolean_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetBoolean_value(PRBool *aBoolean_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetBoolean_value(PRBool aBoolean_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute octet octet_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetOctet_value(PRUint8 *aOctet_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetOctet_value(PRUint8 aOctet_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute short short_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetShort_value(PRInt16 *aShort_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetShort_value(PRInt16 aShort_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute unsigned short ushort_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetUshort_value(PRUint16 *aUshort_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetUshort_value(PRUint16 aUshort_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute long long_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetLong_value(PRInt32 *aLong_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetLong_value(PRInt32 aLong_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute unsigned long ulong_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetUlong_value(PRUint32 *aUlong_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetUlong_value(PRUint32 aUlong_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute long long long_long_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetLong_long_value(PRInt64 *aLong_long_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetLong_long_value(PRInt64 aLong_long_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute unsigned long long ulong_long_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetUlong_long_value(PRUint64 *aUlong_long_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetUlong_long_value(PRUint64 aUlong_long_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute float float_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetFloat_value(float *aFloat_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetFloat_value(float aFloat_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute double double_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetDouble_value(double *aDouble_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetDouble_value(double aDouble_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute char char_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetChar_value(char *aChar_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetChar_value(char aChar_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute wchar wchar_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetWchar_value(PRUnichar *aWchar_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetWchar_value(PRUnichar aWchar_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute string string_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetString_value(char * *aString_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetString_value(const char * aString_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute wstring wstring_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetWstring_value(PRUnichar * *aWstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetWstring_value(const PRUnichar * aWstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute AString astring_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetAstring_value(nsAString & aAstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetAstring_value(const nsAString & aAstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute ACString acstring_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetAcstring_value(nsACString & aAcstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetAcstring_value(const nsACString & aAcstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute AUTF8String utf8string_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetUtf8string_value(nsACString & aUtf8string_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetUtf8string_value(const nsACString & aUtf8string_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute nsIIDRef iid_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetIid_value(nsIID & *aIid_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetIid_value(const nsIID & aIid_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute nsIPythonTestInterface interface_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetInterface_value(nsIPythonTestInterface * *aInterface_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetInterface_value(nsIPythonTestInterface * aInterface_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute nsISupports isupports_value; */ +NS_IMETHODIMP nsPythonTestInterface::GetIsupports_value(nsISupports * *aIsupports_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterface::SetIsupports_value(nsISupports * aIsupports_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* boolean do_boolean (in boolean p1, inout boolean p2, out boolean p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_boolean(PRBool p1, PRBool *p2, PRBool *p3, PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* octet do_octet (in octet p1, inout octet p2, out octet p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_octet(PRUint8 p1, PRUint8 *p2, PRUint8 *p3, PRUint8 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* short do_short (in short p1, inout short p2, out short p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_short(PRInt16 p1, PRInt16 *p2, PRInt16 *p3, PRInt16 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* unsigned short do_unsigned_short (in unsigned short p1, inout unsigned short p2, out unsigned short p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_unsigned_short(PRUint16 p1, PRUint16 *p2, PRUint16 *p3, PRUint16 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* long do_long (in long p1, inout long p2, out long p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_long(PRInt32 p1, PRInt32 *p2, PRInt32 *p3, PRInt32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* unsigned long do_unsigned_long (in unsigned long p1, inout unsigned long p2, out unsigned long p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_unsigned_long(PRUint32 p1, PRUint32 *p2, PRUint32 *p3, PRUint32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* long long do_long_long (in long long p1, inout long long p2, out long long p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_long_long(PRInt64 p1, PRInt64 *p2, PRInt64 *p3, PRInt64 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* unsigned long long do_unsigned_long_long (in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_unsigned_long_long(PRUint64 p1, PRUint64 *p2, PRUint64 *p3, PRUint64 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* float do_float (in float p1, inout float p2, out float p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_float(float p1, float *p2, float *p3, float *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* double do_double (in double p1, inout double p2, out double p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_double(double p1, double *p2, double *p3, double *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* char do_char (in char p1, inout char p2, out char p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_char(char p1, char *p2, char *p3, char *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* wchar do_wchar (in wchar p1, inout wchar p2, out wchar p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_wchar(PRUnichar p1, PRUnichar *p2, PRUnichar *p3, PRUnichar *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* string do_string (in string p1, inout string p2, out string p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_string(const char *p1, char **p2, char **p3, char **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* wstring do_wstring (in wstring p1, inout wstring p2, out wstring p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_wstring(const PRUnichar *p1, PRUnichar **p2, PRUnichar **p3, PRUnichar **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIIDRef do_nsIIDRef (in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_nsIIDRef(const nsIID & p1, nsIID & *p2, nsIID & *p3, nsIID & *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIPythonTestInterface do_nsIPythonTestInterface (in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_nsIPythonTestInterface(nsIPythonTestInterface *p1, nsIPythonTestInterface **p2, nsIPythonTestInterface **p3, nsIPythonTestInterface **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsISupports do_nsISupports (in nsISupports p1, inout nsISupports p2, out nsISupports p3); */ +NS_IMETHODIMP nsPythonTestInterface::Do_nsISupports(nsISupports *p1, nsISupports **p2, nsISupports **p3, nsISupports **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void do_nsISupportsIs (in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */ +NS_IMETHODIMP nsPythonTestInterface::Do_nsISupportsIs(const nsIID & iid, void * *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +/* starting interface: nsIPythonTestInterfaceExtra */ +#define NS_IPYTHONTESTINTERFACEEXTRA_IID_STR "b38d1538-fe92-42c3-831f-285242edeea4" + +#define NS_IPYTHONTESTINTERFACEEXTRA_IID \ + {0xb38d1538, 0xfe92, 0x42c3, \ + { 0x83, 0x1f, 0x28, 0x52, 0x42, 0xed, 0xee, 0xa4 }} + +class NS_NO_VTABLE nsIPythonTestInterfaceExtra : public nsIPythonTestInterface { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPYTHONTESTINTERFACEEXTRA_IID) + + /* void MultiplyEachItemInIntegerArray (in PRInt32 val, in PRUint32 count, [array, size_is (count)] inout PRInt32 valueArray); */ + NS_IMETHOD MultiplyEachItemInIntegerArray(PRInt32 val, PRUint32 count, PRInt32 **valueArray) = 0; + + /* void MultiplyEachItemInIntegerArrayAndAppend (in PRInt32 val, inout PRUint32 count, [array, size_is (count)] inout PRInt32 valueArray); */ + NS_IMETHOD MultiplyEachItemInIntegerArrayAndAppend(PRInt32 val, PRUint32 *count, PRInt32 **valueArray) = 0; + + /* void CompareStringArrays ([array, size_is (count)] in string arr1, [array, size_is (count)] in string arr2, in unsigned long count, [retval] out short result); */ + NS_IMETHOD CompareStringArrays(const char **arr1, const char **arr2, PRUint32 count, PRInt16 *result) = 0; + + /* void DoubleStringArray (inout PRUint32 count, [array, size_is (count)] inout string valueArray); */ + NS_IMETHOD DoubleStringArray(PRUint32 *count, char ***valueArray) = 0; + + /* void ReverseStringArray (in PRUint32 count, [array, size_is (count)] inout string valueArray); */ + NS_IMETHOD ReverseStringArray(PRUint32 count, char ***valueArray) = 0; + + /* void DoubleString (inout PRUint32 count, [size_is (count)] inout string str); */ + NS_IMETHOD DoubleString(PRUint32 *count, char **str) = 0; + + /* void DoubleString2 (in PRUint32 in_count, [size_is (in_count)] in string in_str, out PRUint32 out_count, [size_is (out_count)] out string out_str); */ + NS_IMETHOD DoubleString2(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) = 0; + + /* void DoubleString3 (in PRUint32 in_count, [size_is (in_count)] in string in_str, out PRUint32 out_count, [size_is (out_count), retval] out string out_str); */ + NS_IMETHOD DoubleString3(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) = 0; + + /* void DoubleString4 ([size_is (count)] in string in_str, inout PRUint32 count, [size_is (count)] out string out_str); */ + NS_IMETHOD DoubleString4(const char *in_str, PRUint32 *count, char **out_str) = 0; + + /* void UpString (in PRUint32 count, [size_is (count)] inout string str); */ + NS_IMETHOD UpString(PRUint32 count, char **str) = 0; + + /* void UpString2 (in PRUint32 count, [size_is (count)] in string in_str, [size_is (count)] out string out_str); */ + NS_IMETHOD UpString2(PRUint32 count, const char *in_str, char **out_str) = 0; + + /* void CopyUTF8String (in AUTF8String in_str, out AUTF8String out_str); */ + NS_IMETHOD CopyUTF8String(const nsACString & in_str, nsACString & out_str) = 0; + + /* void CopyUTF8String2 (in AUTF8String in_str, out AUTF8String out_str); */ + NS_IMETHOD CopyUTF8String2(const nsACString & in_str, nsACString & out_str) = 0; + + /* void GetFixedString (in PRUint32 count, [size_is (count)] out string out_str); */ + NS_IMETHOD GetFixedString(PRUint32 count, char **out_str) = 0; + + /* void DoubleWideString (inout PRUint32 count, [size_is (count)] inout wstring str); */ + NS_IMETHOD DoubleWideString(PRUint32 *count, PRUnichar **str) = 0; + + /* void DoubleWideString2 (in PRUint32 in_count, [size_is (in_count)] in wstring in_str, out PRUint32 out_count, [size_is (out_count)] out wstring out_str); */ + NS_IMETHOD DoubleWideString2(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) = 0; + + /* void DoubleWideString3 (in PRUint32 in_count, [size_is (in_count)] in wstring in_str, out PRUint32 out_count, [size_is (out_count), retval] out wstring out_str); */ + NS_IMETHOD DoubleWideString3(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) = 0; + + /* void DoubleWideString4 ([size_is (count)] in wstring in_str, inout PRUint32 count, [size_is (count)] out wstring out_str); */ + NS_IMETHOD DoubleWideString4(const PRUnichar *in_str, PRUint32 *count, PRUnichar **out_str) = 0; + + /* void UpWideString (in PRUint32 count, [size_is (count)] inout wstring str); */ + NS_IMETHOD UpWideString(PRUint32 count, PRUnichar **str) = 0; + + /* void UpWideString2 (in PRUint32 count, [size_is (count)] in wstring in_str, [size_is (count)] out wstring out_str); */ + NS_IMETHOD UpWideString2(PRUint32 count, const PRUnichar *in_str, PRUnichar **out_str) = 0; + + /* void GetFixedWideString (in PRUint32 count, [size_is (count)] out string out_str); */ + NS_IMETHOD GetFixedWideString(PRUint32 count, char **out_str) = 0; + + /* void GetStrings (out PRUint32 count, [array, size_is (count), retval] out string str); */ + NS_IMETHOD GetStrings(PRUint32 *count, char ***str) = 0; + + /* void UpOctetArray (inout PRUint32 count, [array, size_is (count)] inout PRUint8 data); */ + NS_IMETHOD UpOctetArray(PRUint32 *count, PRUint8 **data) = 0; + + /* void UpOctetArray2 (inout PRUint32 count, [array, size_is (count)] inout PRUint8 data); */ + NS_IMETHOD UpOctetArray2(PRUint32 *count, PRUint8 **data) = 0; + + /* void CheckInterfaceArray (in PRUint32 count, [array, size_is (count)] in nsISupports data, [retval] out PRBool all_non_null); */ + NS_IMETHOD CheckInterfaceArray(PRUint32 count, nsISupports **data, PRBool *all_non_null) = 0; + + /* void CopyInterfaceArray (in PRUint32 count, [array, size_is (count)] in nsISupports data, [array, size_is (out_count)] out nsISupports out_data, out PRUint32 out_count); */ + NS_IMETHOD CopyInterfaceArray(PRUint32 count, nsISupports **data, nsISupports ***out_data, PRUint32 *out_count) = 0; + + /* void GetInterfaceArray (out PRUint32 count, [array, size_is (count)] out nsISupports data); */ + NS_IMETHOD GetInterfaceArray(PRUint32 *count, nsISupports ***data) = 0; + + /* void ExtendInterfaceArray (inout PRUint32 count, [array, size_is (count)] inout nsISupports data); */ + NS_IMETHOD ExtendInterfaceArray(PRUint32 *count, nsISupports ***data) = 0; + + /* void CheckIIDArray (in PRUint32 count, [array, size_is (count)] in nsIIDRef data, [retval] out PRBool all_mine); */ + NS_IMETHOD CheckIIDArray(PRUint32 count, const nsIID & *data, PRBool *all_mine) = 0; + + /* void GetIIDArray (out PRUint32 count, [array, size_is (count)] out nsIIDRef data); */ + NS_IMETHOD GetIIDArray(PRUint32 *count, nsIID & **data) = 0; + + /* void ExtendIIDArray (inout PRUint32 count, [array, size_is (count)] inout nsIIDRef data); */ + NS_IMETHOD ExtendIIDArray(PRUint32 *count, nsIID & **data) = 0; + + /* void SumArrays (in PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] in PRInt32 array2, [retval] out PRInt32 result); */ + NS_IMETHOD SumArrays(PRUint32 count, PRInt32 *array1, PRInt32 *array2, PRInt32 *result) = 0; + + /* void GetArrays (out PRUint32 count, [array, size_is (count)] out PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ + NS_IMETHOD GetArrays(PRUint32 *count, PRInt32 **array1, PRInt32 **array2) = 0; + + /* void GetFixedArray (in PRUint32 count, [array, size_is (count)] out PRInt32 array1); */ + NS_IMETHOD GetFixedArray(PRUint32 count, PRInt32 **array1) = 0; + + /* void CopyArray (in PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ + NS_IMETHOD CopyArray(PRUint32 count, PRInt32 *array1, PRInt32 **array2) = 0; + + /* void CopyAndDoubleArray (inout PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ + NS_IMETHOD CopyAndDoubleArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) = 0; + + /* void AppendArray (inout PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] inout PRInt32 array2); */ + NS_IMETHOD AppendArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) = 0; + + /* void AppendVariant (in nsIVariant variant, inout nsIVariant result); */ + NS_IMETHOD AppendVariant(nsIVariant *variant, nsIVariant **result) = 0; + + /* nsIVariant CopyVariant (in nsIVariant variant); */ + NS_IMETHOD CopyVariant(nsIVariant *variant, nsIVariant **_retval) = 0; + + /* nsIVariant SumVariants (in PRUint32 incount, [array, size_is (incount)] in nsIVariant variants); */ + NS_IMETHOD SumVariants(PRUint32 incount, nsIVariant **variants, nsIVariant **_retval) = 0; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIPYTHONTESTINTERFACEEXTRA \ + NS_IMETHOD MultiplyEachItemInIntegerArray(PRInt32 val, PRUint32 count, PRInt32 **valueArray); \ + NS_IMETHOD MultiplyEachItemInIntegerArrayAndAppend(PRInt32 val, PRUint32 *count, PRInt32 **valueArray); \ + NS_IMETHOD CompareStringArrays(const char **arr1, const char **arr2, PRUint32 count, PRInt16 *result); \ + NS_IMETHOD DoubleStringArray(PRUint32 *count, char ***valueArray); \ + NS_IMETHOD ReverseStringArray(PRUint32 count, char ***valueArray); \ + NS_IMETHOD DoubleString(PRUint32 *count, char **str); \ + NS_IMETHOD DoubleString2(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str); \ + NS_IMETHOD DoubleString3(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str); \ + NS_IMETHOD DoubleString4(const char *in_str, PRUint32 *count, char **out_str); \ + NS_IMETHOD UpString(PRUint32 count, char **str); \ + NS_IMETHOD UpString2(PRUint32 count, const char *in_str, char **out_str); \ + NS_IMETHOD CopyUTF8String(const nsACString & in_str, nsACString & out_str); \ + NS_IMETHOD CopyUTF8String2(const nsACString & in_str, nsACString & out_str); \ + NS_IMETHOD GetFixedString(PRUint32 count, char **out_str); \ + NS_IMETHOD DoubleWideString(PRUint32 *count, PRUnichar **str); \ + NS_IMETHOD DoubleWideString2(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str); \ + NS_IMETHOD DoubleWideString3(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str); \ + NS_IMETHOD DoubleWideString4(const PRUnichar *in_str, PRUint32 *count, PRUnichar **out_str); \ + NS_IMETHOD UpWideString(PRUint32 count, PRUnichar **str); \ + NS_IMETHOD UpWideString2(PRUint32 count, const PRUnichar *in_str, PRUnichar **out_str); \ + NS_IMETHOD GetFixedWideString(PRUint32 count, char **out_str); \ + NS_IMETHOD GetStrings(PRUint32 *count, char ***str); \ + NS_IMETHOD UpOctetArray(PRUint32 *count, PRUint8 **data); \ + NS_IMETHOD UpOctetArray2(PRUint32 *count, PRUint8 **data); \ + NS_IMETHOD CheckInterfaceArray(PRUint32 count, nsISupports **data, PRBool *all_non_null); \ + NS_IMETHOD CopyInterfaceArray(PRUint32 count, nsISupports **data, nsISupports ***out_data, PRUint32 *out_count); \ + NS_IMETHOD GetInterfaceArray(PRUint32 *count, nsISupports ***data); \ + NS_IMETHOD ExtendInterfaceArray(PRUint32 *count, nsISupports ***data); \ + NS_IMETHOD CheckIIDArray(PRUint32 count, const nsIID & *data, PRBool *all_mine); \ + NS_IMETHOD GetIIDArray(PRUint32 *count, nsIID & **data); \ + NS_IMETHOD ExtendIIDArray(PRUint32 *count, nsIID & **data); \ + NS_IMETHOD SumArrays(PRUint32 count, PRInt32 *array1, PRInt32 *array2, PRInt32 *result); \ + NS_IMETHOD GetArrays(PRUint32 *count, PRInt32 **array1, PRInt32 **array2); \ + NS_IMETHOD GetFixedArray(PRUint32 count, PRInt32 **array1); \ + NS_IMETHOD CopyArray(PRUint32 count, PRInt32 *array1, PRInt32 **array2); \ + NS_IMETHOD CopyAndDoubleArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2); \ + NS_IMETHOD AppendArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2); \ + NS_IMETHOD AppendVariant(nsIVariant *variant, nsIVariant **result); \ + NS_IMETHOD CopyVariant(nsIVariant *variant, nsIVariant **_retval); \ + NS_IMETHOD SumVariants(PRUint32 incount, nsIVariant **variants, nsIVariant **_retval); + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIPYTHONTESTINTERFACEEXTRA(_to) \ + NS_IMETHOD MultiplyEachItemInIntegerArray(PRInt32 val, PRUint32 count, PRInt32 **valueArray) { return _to MultiplyEachItemInIntegerArray(val, count, valueArray); } \ + NS_IMETHOD MultiplyEachItemInIntegerArrayAndAppend(PRInt32 val, PRUint32 *count, PRInt32 **valueArray) { return _to MultiplyEachItemInIntegerArrayAndAppend(val, count, valueArray); } \ + NS_IMETHOD CompareStringArrays(const char **arr1, const char **arr2, PRUint32 count, PRInt16 *result) { return _to CompareStringArrays(arr1, arr2, count, result); } \ + NS_IMETHOD DoubleStringArray(PRUint32 *count, char ***valueArray) { return _to DoubleStringArray(count, valueArray); } \ + NS_IMETHOD ReverseStringArray(PRUint32 count, char ***valueArray) { return _to ReverseStringArray(count, valueArray); } \ + NS_IMETHOD DoubleString(PRUint32 *count, char **str) { return _to DoubleString(count, str); } \ + NS_IMETHOD DoubleString2(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) { return _to DoubleString2(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleString3(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) { return _to DoubleString3(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleString4(const char *in_str, PRUint32 *count, char **out_str) { return _to DoubleString4(in_str, count, out_str); } \ + NS_IMETHOD UpString(PRUint32 count, char **str) { return _to UpString(count, str); } \ + NS_IMETHOD UpString2(PRUint32 count, const char *in_str, char **out_str) { return _to UpString2(count, in_str, out_str); } \ + NS_IMETHOD CopyUTF8String(const nsACString & in_str, nsACString & out_str) { return _to CopyUTF8String(in_str, out_str); } \ + NS_IMETHOD CopyUTF8String2(const nsACString & in_str, nsACString & out_str) { return _to CopyUTF8String2(in_str, out_str); } \ + NS_IMETHOD GetFixedString(PRUint32 count, char **out_str) { return _to GetFixedString(count, out_str); } \ + NS_IMETHOD DoubleWideString(PRUint32 *count, PRUnichar **str) { return _to DoubleWideString(count, str); } \ + NS_IMETHOD DoubleWideString2(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) { return _to DoubleWideString2(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleWideString3(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) { return _to DoubleWideString3(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleWideString4(const PRUnichar *in_str, PRUint32 *count, PRUnichar **out_str) { return _to DoubleWideString4(in_str, count, out_str); } \ + NS_IMETHOD UpWideString(PRUint32 count, PRUnichar **str) { return _to UpWideString(count, str); } \ + NS_IMETHOD UpWideString2(PRUint32 count, const PRUnichar *in_str, PRUnichar **out_str) { return _to UpWideString2(count, in_str, out_str); } \ + NS_IMETHOD GetFixedWideString(PRUint32 count, char **out_str) { return _to GetFixedWideString(count, out_str); } \ + NS_IMETHOD GetStrings(PRUint32 *count, char ***str) { return _to GetStrings(count, str); } \ + NS_IMETHOD UpOctetArray(PRUint32 *count, PRUint8 **data) { return _to UpOctetArray(count, data); } \ + NS_IMETHOD UpOctetArray2(PRUint32 *count, PRUint8 **data) { return _to UpOctetArray2(count, data); } \ + NS_IMETHOD CheckInterfaceArray(PRUint32 count, nsISupports **data, PRBool *all_non_null) { return _to CheckInterfaceArray(count, data, all_non_null); } \ + NS_IMETHOD CopyInterfaceArray(PRUint32 count, nsISupports **data, nsISupports ***out_data, PRUint32 *out_count) { return _to CopyInterfaceArray(count, data, out_data, out_count); } \ + NS_IMETHOD GetInterfaceArray(PRUint32 *count, nsISupports ***data) { return _to GetInterfaceArray(count, data); } \ + NS_IMETHOD ExtendInterfaceArray(PRUint32 *count, nsISupports ***data) { return _to ExtendInterfaceArray(count, data); } \ + NS_IMETHOD CheckIIDArray(PRUint32 count, const nsIID & *data, PRBool *all_mine) { return _to CheckIIDArray(count, data, all_mine); } \ + NS_IMETHOD GetIIDArray(PRUint32 *count, nsIID & **data) { return _to GetIIDArray(count, data); } \ + NS_IMETHOD ExtendIIDArray(PRUint32 *count, nsIID & **data) { return _to ExtendIIDArray(count, data); } \ + NS_IMETHOD SumArrays(PRUint32 count, PRInt32 *array1, PRInt32 *array2, PRInt32 *result) { return _to SumArrays(count, array1, array2, result); } \ + NS_IMETHOD GetArrays(PRUint32 *count, PRInt32 **array1, PRInt32 **array2) { return _to GetArrays(count, array1, array2); } \ + NS_IMETHOD GetFixedArray(PRUint32 count, PRInt32 **array1) { return _to GetFixedArray(count, array1); } \ + NS_IMETHOD CopyArray(PRUint32 count, PRInt32 *array1, PRInt32 **array2) { return _to CopyArray(count, array1, array2); } \ + NS_IMETHOD CopyAndDoubleArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) { return _to CopyAndDoubleArray(count, array1, array2); } \ + NS_IMETHOD AppendArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) { return _to AppendArray(count, array1, array2); } \ + NS_IMETHOD AppendVariant(nsIVariant *variant, nsIVariant **result) { return _to AppendVariant(variant, result); } \ + NS_IMETHOD CopyVariant(nsIVariant *variant, nsIVariant **_retval) { return _to CopyVariant(variant, _retval); } \ + NS_IMETHOD SumVariants(PRUint32 incount, nsIVariant **variants, nsIVariant **_retval) { return _to SumVariants(incount, variants, _retval); } + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIPYTHONTESTINTERFACEEXTRA(_to) \ + NS_IMETHOD MultiplyEachItemInIntegerArray(PRInt32 val, PRUint32 count, PRInt32 **valueArray) { return !_to ? NS_ERROR_NULL_POINTER : _to->MultiplyEachItemInIntegerArray(val, count, valueArray); } \ + NS_IMETHOD MultiplyEachItemInIntegerArrayAndAppend(PRInt32 val, PRUint32 *count, PRInt32 **valueArray) { return !_to ? NS_ERROR_NULL_POINTER : _to->MultiplyEachItemInIntegerArrayAndAppend(val, count, valueArray); } \ + NS_IMETHOD CompareStringArrays(const char **arr1, const char **arr2, PRUint32 count, PRInt16 *result) { return !_to ? NS_ERROR_NULL_POINTER : _to->CompareStringArrays(arr1, arr2, count, result); } \ + NS_IMETHOD DoubleStringArray(PRUint32 *count, char ***valueArray) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleStringArray(count, valueArray); } \ + NS_IMETHOD ReverseStringArray(PRUint32 count, char ***valueArray) { return !_to ? NS_ERROR_NULL_POINTER : _to->ReverseStringArray(count, valueArray); } \ + NS_IMETHOD DoubleString(PRUint32 *count, char **str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleString(count, str); } \ + NS_IMETHOD DoubleString2(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleString2(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleString3(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleString3(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleString4(const char *in_str, PRUint32 *count, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleString4(in_str, count, out_str); } \ + NS_IMETHOD UpString(PRUint32 count, char **str) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpString(count, str); } \ + NS_IMETHOD UpString2(PRUint32 count, const char *in_str, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpString2(count, in_str, out_str); } \ + NS_IMETHOD CopyUTF8String(const nsACString & in_str, nsACString & out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyUTF8String(in_str, out_str); } \ + NS_IMETHOD CopyUTF8String2(const nsACString & in_str, nsACString & out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyUTF8String2(in_str, out_str); } \ + NS_IMETHOD GetFixedString(PRUint32 count, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetFixedString(count, out_str); } \ + NS_IMETHOD DoubleWideString(PRUint32 *count, PRUnichar **str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleWideString(count, str); } \ + NS_IMETHOD DoubleWideString2(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleWideString2(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleWideString3(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleWideString3(in_count, in_str, out_count, out_str); } \ + NS_IMETHOD DoubleWideString4(const PRUnichar *in_str, PRUint32 *count, PRUnichar **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->DoubleWideString4(in_str, count, out_str); } \ + NS_IMETHOD UpWideString(PRUint32 count, PRUnichar **str) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpWideString(count, str); } \ + NS_IMETHOD UpWideString2(PRUint32 count, const PRUnichar *in_str, PRUnichar **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpWideString2(count, in_str, out_str); } \ + NS_IMETHOD GetFixedWideString(PRUint32 count, char **out_str) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetFixedWideString(count, out_str); } \ + NS_IMETHOD GetStrings(PRUint32 *count, char ***str) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetStrings(count, str); } \ + NS_IMETHOD UpOctetArray(PRUint32 *count, PRUint8 **data) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpOctetArray(count, data); } \ + NS_IMETHOD UpOctetArray2(PRUint32 *count, PRUint8 **data) { return !_to ? NS_ERROR_NULL_POINTER : _to->UpOctetArray2(count, data); } \ + NS_IMETHOD CheckInterfaceArray(PRUint32 count, nsISupports **data, PRBool *all_non_null) { return !_to ? NS_ERROR_NULL_POINTER : _to->CheckInterfaceArray(count, data, all_non_null); } \ + NS_IMETHOD CopyInterfaceArray(PRUint32 count, nsISupports **data, nsISupports ***out_data, PRUint32 *out_count) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyInterfaceArray(count, data, out_data, out_count); } \ + NS_IMETHOD GetInterfaceArray(PRUint32 *count, nsISupports ***data) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetInterfaceArray(count, data); } \ + NS_IMETHOD ExtendInterfaceArray(PRUint32 *count, nsISupports ***data) { return !_to ? NS_ERROR_NULL_POINTER : _to->ExtendInterfaceArray(count, data); } \ + NS_IMETHOD CheckIIDArray(PRUint32 count, const nsIID & *data, PRBool *all_mine) { return !_to ? NS_ERROR_NULL_POINTER : _to->CheckIIDArray(count, data, all_mine); } \ + NS_IMETHOD GetIIDArray(PRUint32 *count, nsIID & **data) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetIIDArray(count, data); } \ + NS_IMETHOD ExtendIIDArray(PRUint32 *count, nsIID & **data) { return !_to ? NS_ERROR_NULL_POINTER : _to->ExtendIIDArray(count, data); } \ + NS_IMETHOD SumArrays(PRUint32 count, PRInt32 *array1, PRInt32 *array2, PRInt32 *result) { return !_to ? NS_ERROR_NULL_POINTER : _to->SumArrays(count, array1, array2, result); } \ + NS_IMETHOD GetArrays(PRUint32 *count, PRInt32 **array1, PRInt32 **array2) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetArrays(count, array1, array2); } \ + NS_IMETHOD GetFixedArray(PRUint32 count, PRInt32 **array1) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetFixedArray(count, array1); } \ + NS_IMETHOD CopyArray(PRUint32 count, PRInt32 *array1, PRInt32 **array2) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyArray(count, array1, array2); } \ + NS_IMETHOD CopyAndDoubleArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyAndDoubleArray(count, array1, array2); } \ + NS_IMETHOD AppendArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) { return !_to ? NS_ERROR_NULL_POINTER : _to->AppendArray(count, array1, array2); } \ + NS_IMETHOD AppendVariant(nsIVariant *variant, nsIVariant **result) { return !_to ? NS_ERROR_NULL_POINTER : _to->AppendVariant(variant, result); } \ + NS_IMETHOD CopyVariant(nsIVariant *variant, nsIVariant **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->CopyVariant(variant, _retval); } \ + NS_IMETHOD SumVariants(PRUint32 incount, nsIVariant **variants, nsIVariant **_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->SumVariants(incount, variants, _retval); } + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsPythonTestInterfaceExtra : public nsIPythonTestInterfaceExtra +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPYTHONTESTINTERFACEEXTRA + + nsPythonTestInterfaceExtra(); + +private: + ~nsPythonTestInterfaceExtra(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsPythonTestInterfaceExtra, nsIPythonTestInterfaceExtra) + +nsPythonTestInterfaceExtra::nsPythonTestInterfaceExtra() +{ + /* member initializers and constructor code */ +} + +nsPythonTestInterfaceExtra::~nsPythonTestInterfaceExtra() +{ + /* destructor code */ +} + +/* void MultiplyEachItemInIntegerArray (in PRInt32 val, in PRUint32 count, [array, size_is (count)] inout PRInt32 valueArray); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::MultiplyEachItemInIntegerArray(PRInt32 val, PRUint32 count, PRInt32 **valueArray) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void MultiplyEachItemInIntegerArrayAndAppend (in PRInt32 val, inout PRUint32 count, [array, size_is (count)] inout PRInt32 valueArray); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::MultiplyEachItemInIntegerArrayAndAppend(PRInt32 val, PRUint32 *count, PRInt32 **valueArray) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CompareStringArrays ([array, size_is (count)] in string arr1, [array, size_is (count)] in string arr2, in unsigned long count, [retval] out short result); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CompareStringArrays(const char **arr1, const char **arr2, PRUint32 count, PRInt16 *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleStringArray (inout PRUint32 count, [array, size_is (count)] inout string valueArray); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleStringArray(PRUint32 *count, char ***valueArray) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void ReverseStringArray (in PRUint32 count, [array, size_is (count)] inout string valueArray); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::ReverseStringArray(PRUint32 count, char ***valueArray) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleString (inout PRUint32 count, [size_is (count)] inout string str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleString(PRUint32 *count, char **str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleString2 (in PRUint32 in_count, [size_is (in_count)] in string in_str, out PRUint32 out_count, [size_is (out_count)] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleString2(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleString3 (in PRUint32 in_count, [size_is (in_count)] in string in_str, out PRUint32 out_count, [size_is (out_count), retval] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleString3(PRUint32 in_count, const char *in_str, PRUint32 *out_count, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleString4 ([size_is (count)] in string in_str, inout PRUint32 count, [size_is (count)] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleString4(const char *in_str, PRUint32 *count, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpString (in PRUint32 count, [size_is (count)] inout string str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpString(PRUint32 count, char **str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpString2 (in PRUint32 count, [size_is (count)] in string in_str, [size_is (count)] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpString2(PRUint32 count, const char *in_str, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CopyUTF8String (in AUTF8String in_str, out AUTF8String out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyUTF8String(const nsACString & in_str, nsACString & out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CopyUTF8String2 (in AUTF8String in_str, out AUTF8String out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyUTF8String2(const nsACString & in_str, nsACString & out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetFixedString (in PRUint32 count, [size_is (count)] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetFixedString(PRUint32 count, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleWideString (inout PRUint32 count, [size_is (count)] inout wstring str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleWideString(PRUint32 *count, PRUnichar **str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleWideString2 (in PRUint32 in_count, [size_is (in_count)] in wstring in_str, out PRUint32 out_count, [size_is (out_count)] out wstring out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleWideString2(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleWideString3 (in PRUint32 in_count, [size_is (in_count)] in wstring in_str, out PRUint32 out_count, [size_is (out_count), retval] out wstring out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleWideString3(PRUint32 in_count, const PRUnichar *in_str, PRUint32 *out_count, PRUnichar **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void DoubleWideString4 ([size_is (count)] in wstring in_str, inout PRUint32 count, [size_is (count)] out wstring out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::DoubleWideString4(const PRUnichar *in_str, PRUint32 *count, PRUnichar **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpWideString (in PRUint32 count, [size_is (count)] inout wstring str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpWideString(PRUint32 count, PRUnichar **str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpWideString2 (in PRUint32 count, [size_is (count)] in wstring in_str, [size_is (count)] out wstring out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpWideString2(PRUint32 count, const PRUnichar *in_str, PRUnichar **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetFixedWideString (in PRUint32 count, [size_is (count)] out string out_str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetFixedWideString(PRUint32 count, char **out_str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetStrings (out PRUint32 count, [array, size_is (count), retval] out string str); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetStrings(PRUint32 *count, char ***str) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpOctetArray (inout PRUint32 count, [array, size_is (count)] inout PRUint8 data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpOctetArray(PRUint32 *count, PRUint8 **data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void UpOctetArray2 (inout PRUint32 count, [array, size_is (count)] inout PRUint8 data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::UpOctetArray2(PRUint32 *count, PRUint8 **data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CheckInterfaceArray (in PRUint32 count, [array, size_is (count)] in nsISupports data, [retval] out PRBool all_non_null); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CheckInterfaceArray(PRUint32 count, nsISupports **data, PRBool *all_non_null) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CopyInterfaceArray (in PRUint32 count, [array, size_is (count)] in nsISupports data, [array, size_is (out_count)] out nsISupports out_data, out PRUint32 out_count); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyInterfaceArray(PRUint32 count, nsISupports **data, nsISupports ***out_data, PRUint32 *out_count) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetInterfaceArray (out PRUint32 count, [array, size_is (count)] out nsISupports data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetInterfaceArray(PRUint32 *count, nsISupports ***data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void ExtendInterfaceArray (inout PRUint32 count, [array, size_is (count)] inout nsISupports data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::ExtendInterfaceArray(PRUint32 *count, nsISupports ***data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CheckIIDArray (in PRUint32 count, [array, size_is (count)] in nsIIDRef data, [retval] out PRBool all_mine); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CheckIIDArray(PRUint32 count, const nsIID & *data, PRBool *all_mine) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetIIDArray (out PRUint32 count, [array, size_is (count)] out nsIIDRef data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetIIDArray(PRUint32 *count, nsIID & **data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void ExtendIIDArray (inout PRUint32 count, [array, size_is (count)] inout nsIIDRef data); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::ExtendIIDArray(PRUint32 *count, nsIID & **data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void SumArrays (in PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] in PRInt32 array2, [retval] out PRInt32 result); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::SumArrays(PRUint32 count, PRInt32 *array1, PRInt32 *array2, PRInt32 *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetArrays (out PRUint32 count, [array, size_is (count)] out PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetArrays(PRUint32 *count, PRInt32 **array1, PRInt32 **array2) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetFixedArray (in PRUint32 count, [array, size_is (count)] out PRInt32 array1); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::GetFixedArray(PRUint32 count, PRInt32 **array1) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CopyArray (in PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyArray(PRUint32 count, PRInt32 *array1, PRInt32 **array2) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void CopyAndDoubleArray (inout PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] out PRInt32 array2); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyAndDoubleArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void AppendArray (inout PRUint32 count, [array, size_is (count)] in PRInt32 array1, [array, size_is (count)] inout PRInt32 array2); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::AppendArray(PRUint32 *count, PRInt32 *array1, PRInt32 **array2) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void AppendVariant (in nsIVariant variant, inout nsIVariant result); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::AppendVariant(nsIVariant *variant, nsIVariant **result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIVariant CopyVariant (in nsIVariant variant); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::CopyVariant(nsIVariant *variant, nsIVariant **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIVariant SumVariants (in PRUint32 incount, [array, size_is (incount)] in nsIVariant variants); */ +NS_IMETHODIMP nsPythonTestInterfaceExtra::SumVariants(PRUint32 incount, nsIVariant **variants, nsIVariant **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +/* starting interface: nsIPythonTestInterfaceDOMStrings */ +#define NS_IPYTHONTESTINTERFACEDOMSTRINGS_IID_STR "657ae651-a973-4818-8c06-f4b948b3d758" + +#define NS_IPYTHONTESTINTERFACEDOMSTRINGS_IID \ + {0x657ae651, 0xa973, 0x4818, \ + { 0x8c, 0x06, 0xf4, 0xb9, 0x48, 0xb3, 0xd7, 0x58 }} + +class NS_NO_VTABLE nsIPythonTestInterfaceDOMStrings : public nsIPythonTestInterfaceExtra { + public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPYTHONTESTINTERFACEDOMSTRINGS_IID) + + /* DOMString GetDOMStringResult (in PRInt32 length); */ + NS_IMETHOD GetDOMStringResult(PRInt32 length, nsAString & _retval) = 0; + + /* void GetDOMStringOut (in PRInt32 length, [retval] out DOMString s); */ + NS_IMETHOD GetDOMStringOut(PRInt32 length, nsAString & s) = 0; + + /* PRUint32 GetDOMStringLength (in DOMString s); */ + NS_IMETHOD GetDOMStringLength(const nsAString & s, PRUint32 *_retval) = 0; + + /* PRUint32 GetDOMStringRefLength (in DOMStringRef s); */ + NS_IMETHOD GetDOMStringRefLength(const nsAString & s, PRUint32 *_retval) = 0; + + /* PRUint32 GetDOMStringPtrLength (in DOMStringPtr s); */ + NS_IMETHOD GetDOMStringPtrLength(const nsAString * s, PRUint32 *_retval) = 0; + + /* void ConcatDOMStrings (in DOMString s1, in DOMString s2, out DOMString ret); */ + NS_IMETHOD ConcatDOMStrings(const nsAString & s1, const nsAString & s2, nsAString & ret) = 0; + + /* attribute DOMString domstring_value; */ + NS_IMETHOD GetDomstring_value(nsAString & aDomstring_value) = 0; + NS_IMETHOD SetDomstring_value(const nsAString & aDomstring_value) = 0; + + /* readonly attribute DOMString domstring_value_ro; */ + NS_IMETHOD GetDomstring_value_ro(nsAString & aDomstring_value_ro) = 0; + +}; + +/* Use this macro when declaring classes that implement this interface. */ +#define NS_DECL_NSIPYTHONTESTINTERFACEDOMSTRINGS \ + NS_IMETHOD GetDOMStringResult(PRInt32 length, nsAString & _retval); \ + NS_IMETHOD GetDOMStringOut(PRInt32 length, nsAString & s); \ + NS_IMETHOD GetDOMStringLength(const nsAString & s, PRUint32 *_retval); \ + NS_IMETHOD GetDOMStringRefLength(const nsAString & s, PRUint32 *_retval); \ + NS_IMETHOD GetDOMStringPtrLength(const nsAString * s, PRUint32 *_retval); \ + NS_IMETHOD ConcatDOMStrings(const nsAString & s1, const nsAString & s2, nsAString & ret); \ + NS_IMETHOD GetDomstring_value(nsAString & aDomstring_value); \ + NS_IMETHOD SetDomstring_value(const nsAString & aDomstring_value); \ + NS_IMETHOD GetDomstring_value_ro(nsAString & aDomstring_value_ro); + +/* Use this macro to declare functions that forward the behavior of this interface to another object. */ +#define NS_FORWARD_NSIPYTHONTESTINTERFACEDOMSTRINGS(_to) \ + NS_IMETHOD GetDOMStringResult(PRInt32 length, nsAString & _retval) { return _to GetDOMStringResult(length, _retval); } \ + NS_IMETHOD GetDOMStringOut(PRInt32 length, nsAString & s) { return _to GetDOMStringOut(length, s); } \ + NS_IMETHOD GetDOMStringLength(const nsAString & s, PRUint32 *_retval) { return _to GetDOMStringLength(s, _retval); } \ + NS_IMETHOD GetDOMStringRefLength(const nsAString & s, PRUint32 *_retval) { return _to GetDOMStringRefLength(s, _retval); } \ + NS_IMETHOD GetDOMStringPtrLength(const nsAString * s, PRUint32 *_retval) { return _to GetDOMStringPtrLength(s, _retval); } \ + NS_IMETHOD ConcatDOMStrings(const nsAString & s1, const nsAString & s2, nsAString & ret) { return _to ConcatDOMStrings(s1, s2, ret); } \ + NS_IMETHOD GetDomstring_value(nsAString & aDomstring_value) { return _to GetDomstring_value(aDomstring_value); } \ + NS_IMETHOD SetDomstring_value(const nsAString & aDomstring_value) { return _to SetDomstring_value(aDomstring_value); } \ + NS_IMETHOD GetDomstring_value_ro(nsAString & aDomstring_value_ro) { return _to GetDomstring_value_ro(aDomstring_value_ro); } + +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ +#define NS_FORWARD_SAFE_NSIPYTHONTESTINTERFACEDOMSTRINGS(_to) \ + NS_IMETHOD GetDOMStringResult(PRInt32 length, nsAString & _retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDOMStringResult(length, _retval); } \ + NS_IMETHOD GetDOMStringOut(PRInt32 length, nsAString & s) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDOMStringOut(length, s); } \ + NS_IMETHOD GetDOMStringLength(const nsAString & s, PRUint32 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDOMStringLength(s, _retval); } \ + NS_IMETHOD GetDOMStringRefLength(const nsAString & s, PRUint32 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDOMStringRefLength(s, _retval); } \ + NS_IMETHOD GetDOMStringPtrLength(const nsAString * s, PRUint32 *_retval) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDOMStringPtrLength(s, _retval); } \ + NS_IMETHOD ConcatDOMStrings(const nsAString & s1, const nsAString & s2, nsAString & ret) { return !_to ? NS_ERROR_NULL_POINTER : _to->ConcatDOMStrings(s1, s2, ret); } \ + NS_IMETHOD GetDomstring_value(nsAString & aDomstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDomstring_value(aDomstring_value); } \ + NS_IMETHOD SetDomstring_value(const nsAString & aDomstring_value) { return !_to ? NS_ERROR_NULL_POINTER : _to->SetDomstring_value(aDomstring_value); } \ + NS_IMETHOD GetDomstring_value_ro(nsAString & aDomstring_value_ro) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetDomstring_value_ro(aDomstring_value_ro); } + +#if 0 +/* Use the code below as a template for the implementation class for this interface. */ + +/* Header file */ +class nsPythonTestInterfaceDOMStrings : public nsIPythonTestInterfaceDOMStrings +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPYTHONTESTINTERFACEDOMSTRINGS + + nsPythonTestInterfaceDOMStrings(); + +private: + ~nsPythonTestInterfaceDOMStrings(); + +protected: + /* additional members */ +}; + +/* Implementation file */ +NS_IMPL_ISUPPORTS1(nsPythonTestInterfaceDOMStrings, nsIPythonTestInterfaceDOMStrings) + +nsPythonTestInterfaceDOMStrings::nsPythonTestInterfaceDOMStrings() +{ + /* member initializers and constructor code */ +} + +nsPythonTestInterfaceDOMStrings::~nsPythonTestInterfaceDOMStrings() +{ + /* destructor code */ +} + +/* DOMString GetDOMStringResult (in PRInt32 length); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDOMStringResult(PRInt32 length, nsAString & _retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void GetDOMStringOut (in PRInt32 length, [retval] out DOMString s); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDOMStringOut(PRInt32 length, nsAString & s) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* PRUint32 GetDOMStringLength (in DOMString s); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDOMStringLength(const nsAString & s, PRUint32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* PRUint32 GetDOMStringRefLength (in DOMStringRef s); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDOMStringRefLength(const nsAString & s, PRUint32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* PRUint32 GetDOMStringPtrLength (in DOMStringPtr s); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDOMStringPtrLength(const nsAString * s, PRUint32 *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void ConcatDOMStrings (in DOMString s1, in DOMString s2, out DOMString ret); */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::ConcatDOMStrings(const nsAString & s1, const nsAString & s2, nsAString & ret) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute DOMString domstring_value; */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDomstring_value(nsAString & aDomstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::SetDomstring_value(const nsAString & aDomstring_value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* readonly attribute DOMString domstring_value_ro; */ +NS_IMETHODIMP nsPythonTestInterfaceDOMStrings::GetDomstring_value_ro(nsAString & aDomstring_value_ro) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* End of implementation class template. */ +#endif + + +#endif /* __gen_py_test_component_h__ */ diff --git a/src/libs/xpcom18a4/python/test/test_component/py_test_component.html b/src/libs/xpcom18a4/python/test/test_component/py_test_component.html new file mode 100644 index 00000000..1e17d24c --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_component/py_test_component.html @@ -0,0 +1,182 @@ + + +
Python Component Sample + +

+
+Last modified + +

+ +

XPConnect allows JavaScript +to transparantly access and manipulate XPCOM objects; + +

Big Deal, I hear you say! But it also works for Python!!! + +

+This sample demonstrates accessing a XPCOM object through XPConnect. +The JavaScript executed when this page loads creates an instance +of the Python object by +using the Components object, then accesses it through +the nsISample interface by calling QueryInterface: +
+

+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["component://mozilla/sample/sample-world"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsISample);
+
+ +

+The buttons on the form are connected to JavaScript event handlers which +call the methods defined in Python + + +

Compiling the idl + +

The XPIDL compiler (xpidl on Unix, xpidl.exe on Windows, and a CodeWarrior plugin on Mac) +is compiled at build time (except on Mac) thus +you will have to build mozilla in order to test this out. If you +have already built mozilla then the compiler will be located at mozilla\dist\WIN32_D.OBJ\bin\xpidl.exe. + +

Once you have the XPIDL compiler enter the following command at your +prompt: +
D:\whereever\xpcom\test\test_component>d:\mozilla\dist\WIN32_D.OBJ\bin\xpidl -I +d:\mozilla\dist\idl -m typelib py_test_component.idl. You must then copy the generated .xpt file +to the mozilla component directory. + +

The -I d:\mozilla\dist\idl points the compiler to the folder +containing the other idl files, needed because nsISample.idl inherits from +nsISupports.idl. The -m typelib instruction tells the compiler +to build the .XPT typelib file.. + +

+For more information on compilation see the xpidl +compiler page. + +

Running the sample +

NOTE: This doesnt work for me - I get an access denied error using XPConnect! +

Using Mozilla, load this file. Pay attention +to the console when clicking "write". + + + + +

+

+ + + + + + + +
+ +

+JavaScript and form source: + + +

+<script>
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["component://Python.TestComponent"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsIPythonTestInterface);
+dump("sample = " + sample + "\n");
+
+function get()
+{
+  var field = document.getElementById('Value');
+  field.value = sample.str_value;
+}
+
+function set()
+{
+  var field = document.getElementById('Value');
+  sample.str_value = field.value;
+}
+
+function poke()
+{
+  var field = document.getElementById('Value');
+  sample.poke(field.value);
+}
+
+function write()
+{
+  sample.writeValue("here is what I'm writing: ");
+}
+</script>
+
+<form name="form">
+<input type="button" value="Get" onclick="get();">
+<input type="button" value="Set" onclick="set();">
+<input type="button" value="Poke" onclick="poke();">
+<input type="text" id="Value">
+<input type="button" value="Write" onclick="write();">
+<form>
+
+
diff --git a/src/libs/xpcom18a4/python/test/test_component/py_test_component.idl b/src/libs/xpcom18a4/python/test/test_component/py_test_component.idl new file mode 100644 index 00000000..cd3e1c45 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_component/py_test_component.idl @@ -0,0 +1,231 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +// NOTE: This is a TEST interface, not a DEMO interface :-) +// We try to get as many data-types etc exposed, meaning this +// doesnt really make a good demo of a "simple component" +#include "nsISupports.idl" +#include "nsIVariant.idl" + +[scriptable, uuid(1ECAED4F-E4D5-4ee7-ABF0-7D72AE1441D7)] +interface nsIPythonTestInterface : nsISupports +{ + // Some constants for us to test - one for every type supported by xpidl + const short One = 1; + const long Two = 2; + const long MinusOne = -1; + const long BigLong = 0x7FFFFFFF; + const long BiggerLong = 0xFFFFFFFF; + const unsigned long BigULong = 0xFFFFFFFF; + + // Declare every type supported as an attribute. + attribute boolean boolean_value; // PRBool + attribute octet octet_value; // PRUint8 + attribute short short_value; // PRInt16 + attribute unsigned short ushort_value; // PRUint16 + attribute long long_value; // PRInt32 + attribute unsigned long ulong_value; // PRUint32 + attribute long long long_long_value; // PRInt64 + attribute unsigned long long ulong_long_value; // PRUint64 + attribute float float_value; // float + attribute double double_value; // double + attribute char char_value; // char + attribute wchar wchar_value; // PRUnichar + attribute string string_value; // char * + attribute wstring wstring_value; // PRUnichar* + attribute AString astring_value; // nsAString & + attribute ACString acstring_value; // nsACString & + attribute AUTF8String utf8string_value; // nsAUTF8String & + attribute nsIIDRef iid_value; // an IID + attribute nsIPythonTestInterface interface_value; // A specific interface + attribute nsISupports isupports_value; // A generic interface + + // Declare every type supported as a method with an "in", "in/out" and "out" params + boolean do_boolean(in boolean p1, inout boolean p2, out boolean p3); + octet do_octet(in octet p1, inout octet p2, out octet p3); + short do_short(in short p1, inout short p2, out short p3); + unsigned short do_unsigned_short(in unsigned short p1, inout unsigned short p2, out unsigned short p3); + long do_long(in long p1, inout long p2, out long p3); + unsigned long do_unsigned_long(in unsigned long p1, inout unsigned long p2, out unsigned long p3); + long long do_long_long(in long long p1, inout long long p2, out long long p3); + unsigned long long do_unsigned_long_long(in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3); + float do_float(in float p1, inout float p2, out float p3); + double do_double(in double p1, inout double p2, out double p3); + char do_char(in char p1, inout char p2, out char p3); + wchar do_wchar(in wchar p1, inout wchar p2, out wchar p3); + string do_string(in string p1, inout string p2, out string p3); + wstring do_wstring(in wstring p1, inout wstring p2, out wstring p3); + nsIIDRef do_nsIIDRef(in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3); + nsIPythonTestInterface do_nsIPythonTestInterface(in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3); + nsISupports do_nsISupports(in nsISupports p1, inout nsISupports p2, out nsISupports p3); + void do_nsISupportsIs(in nsIIDRef iid, [iid_is(iid),retval] out nsQIResult result); +// Do I really need these?? +// void do_nsISupportsIs2(inout nsIIDRef iid, [iid_is(iid)] inout nsQIResult result); +// void do_nsISupportsIs3(out nsIIDRef iid, [iid_is(iid)] inout nsQIResult result); +// void do_nsISupportsIs4(out nsIIDRef iid, [iid_is(iid)] out nsQIResult result); +}; + +// Another interface - we use another interface purely for testing purposes - +// We ensure that the entire interface hierarcy is available correctly. +[scriptable, uuid(B38D1538-FE92-42c3-831F-285242EDEEA4)] +interface nsIPythonTestInterfaceExtra : nsIPythonTestInterface +{ + // These were copied from the XPCOM test 'xpctest.idl' + // (and a few extras added) + void MultiplyEachItemInIntegerArray( + in PRInt32 val, + in PRUint32 count, + [array, size_is(count)] inout PRInt32 valueArray); + void MultiplyEachItemInIntegerArrayAndAppend( + in PRInt32 val, + inout PRUint32 count, + [array, size_is(count)] inout PRInt32 valueArray); + + // Note that this method shares a single "size_is" between 2 params! + void CompareStringArrays([array, size_is(count)] in string arr1, + [array, size_is(count)] in string arr2, + in unsigned long count, + [retval] out short result); + + void DoubleStringArray(inout PRUint32 count, + [array, size_is(count)] inout string valueArray); + void ReverseStringArray(in PRUint32 count, + [array, size_is(count)] inout string valueArray); + + // One count, one inout array. + void DoubleString(inout PRUint32 count, + [size_is(count)] inout string str); + // One in count and in array, plus out count and out array + void DoubleString2(in PRUint32 in_count, [size_is(in_count)] in string in_str, + out PRUint32 out_count, [size_is(out_count)] out string out_str); + // As per DoubleString2, but out string also marked retval + void DoubleString3(in PRUint32 in_count, [size_is(in_count)] in string in_str, + out PRUint32 out_count, [size_is(out_count), retval] out string out_str); + // One in array, one out array, one share inout count. + void DoubleString4([size_is(count)] in string in_str, inout PRUint32 count, [size_is(count)] out string out_str); + // UpString defines the count as only "in" - meaning the result must be the same size + void UpString(in PRUint32 count, + [size_is(count)] inout string str); + // UpString2 defines count as only "in", and a string as only "out" + void UpString2(in PRUint32 count, + [size_is(count)] in string in_str, + [size_is(count)]out string out_str); + void CopyUTF8String(in AUTF8String in_str, out AUTF8String out_str); + void CopyUTF8String2(in AUTF8String in_str, out AUTF8String out_str); + // Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!) + void GetFixedString(in PRUint32 count, [size_is(count)]out string out_str); + + void DoubleWideString(inout PRUint32 count, + [size_is(count)] inout wstring str); + void DoubleWideString2(in PRUint32 in_count, [size_is(in_count)] in wstring in_str, + out PRUint32 out_count, [size_is(out_count)] out wstring out_str); + void DoubleWideString3(in PRUint32 in_count, [size_is(in_count)] in wstring in_str, + out PRUint32 out_count, [size_is(out_count), retval] out wstring out_str); + void DoubleWideString4([size_is(count)] in wstring in_str, inout PRUint32 count, [size_is(count)] out wstring out_str); + // UpWideString defines the count as only "in" - meaning the result must be the same size + void UpWideString(in PRUint32 count, + [size_is(count)] inout wstring str); + // UpWideString2 defines count as only "in", and a string as only "out" + void UpWideString2(in PRUint32 count, + [size_is(count)] in wstring in_str, + [size_is(count)]out wstring out_str); + // Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!) + void GetFixedWideString(in PRUint32 count, [size_is(count)]out string out_str); + + void GetStrings(out PRUint32 count, + [retval, array, size_is(count)] out string str); + + void UpOctetArray(inout PRUint32 count, + [array, size_is(count)] inout PRUint8 data); + + void UpOctetArray2(inout PRUint32 count, + [array, size_is(count)] inout PRUint8 data); + + // Arrays of interfaces + void CheckInterfaceArray(in PRUint32 count, + [array, size_is(count)] in nsISupports data, + [retval] out PRBool all_non_null); + void CopyInterfaceArray(in PRUint32 count, + [array, size_is(count)] in nsISupports data, + [array, size_is(out_count)] out nsISupports out_data, + out PRUint32 out_count); + void GetInterfaceArray(out PRUint32 count, + [array, size_is(count)] out nsISupports data); + void ExtendInterfaceArray(inout PRUint32 count, + [array, size_is(count)] inout nsISupports data); + + // Arrays of IIDs + void CheckIIDArray(in PRUint32 count, + [array, size_is(count)] in nsIIDRef data, + [retval] out PRBool all_mine); + void GetIIDArray(out PRUint32 count, + [array, size_is(count)] out nsIIDRef data); + void ExtendIIDArray(inout PRUint32 count, + [array, size_is(count)] inout nsIIDRef data); + + // More specific tests. + // Test our count param can be shared as an "in" param. + void SumArrays(in PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]in PRInt32 array2, [retval]out PRInt32 result); + // Test our count param can be shared as an "out" param. + void GetArrays(out PRUint32 count, [array, size_is(count)]out PRInt32 array1, [array, size_is(count)]out PRInt32 array2); + // Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!) + void GetFixedArray(in PRUint32 count, [array, size_is(count)]out PRInt32 array1); + // Test our "in" count param can be shared as one "in", plus one "out" param. + void CopyArray(in PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]out PRInt32 array2); + // Test our "in-out" count param can be shared as one "in", plus one "out" param. + void CopyAndDoubleArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]out PRInt32 array2); + // Test our "in-out" count param can be shared as one "in", plus one "in-out" param. + void AppendArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]inout PRInt32 array2); + void AppendVariant(in nsIVariant variant, inout nsIVariant result); + nsIVariant CopyVariant(in nsIVariant variant); + nsIVariant SumVariants(in PRUint32 incount, [array, size_is(incount)]in nsIVariant variants); +}; + +// DOM String support is a "recent" (01/2001) addition to XPCOM. These test +// have their own interface for no real good reason ;-) +[scriptable, uuid(657ae651-a973-4818-8c06-f4b948b3d758)] +interface nsIPythonTestInterfaceDOMStrings : nsIPythonTestInterfaceExtra +{ + DOMString GetDOMStringResult(in PRInt32 length); + void GetDOMStringOut(in PRInt32 length, [retval] out DOMString s); + PRUint32 GetDOMStringLength(in DOMString s); + PRUint32 GetDOMStringRefLength(in DOMStringRef s); + PRUint32 GetDOMStringPtrLength(in DOMStringPtr s); + void ConcatDOMStrings(in DOMString s1, in DOMString s2, out DOMString ret); + attribute DOMString domstring_value; + readonly attribute DOMString domstring_value_ro; +}; diff --git a/src/libs/xpcom18a4/python/test/test_component/py_test_component.py b/src/libs/xpcom18a4/python/test/test_component/py_test_component.py new file mode 100755 index 00000000..c0373de9 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_component/py_test_component.py @@ -0,0 +1,421 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# NOTE: This is a TEST interface, not a DEMO interface :-) +# We try to get as many data-types etc exposed, meaning this +# doesnt really make a good demo of a "simple component" + + +from xpcom import components, verbose + +class PythonTestComponent: + # Note we only list the "child" interface, not our intermediate interfaces + # (which we must, by definition, also support) + _com_interfaces_ = components.interfaces.nsIPythonTestInterfaceDOMStrings + _reg_clsid_ = "{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}" + _reg_contractid_ = "Python.TestComponent" + def __init__(self): + self.boolean_value = 1 + self.octet_value = 2 + self.short_value = 3 + self.ushort_value = 4 + self.long_value = 5 + self.ulong_value = 6 + self.long_long_value = 7 + self.ulong_long_value = 8 + self.float_value = 9.0 + self.double_value = 10.0 + self.char_value = "a" + self.wchar_value = "b" + self.string_value = "cee" + self.wstring_value = "dee" + self.astring_value = "astring" + self.acstring_value = "acstring" + self.utf8string_value = "utf8string" + self.iid_value = self._reg_clsid_ + self.interface_value = None + self.isupports_value = None + self.domstring_value = "dom" + + def __del__(self): + if verbose: + print "Python.TestComponent: __del__ method called - object is destructing" + + def do_boolean(self, p1, p2): + # boolean do_boolean(in boolean p1, inout boolean p2, out boolean p3); + ret = p1 ^ p2 + return ret, not ret, ret + + def do_octet(self, p1, p2): + # octet do_octet(in octet p1, inout octet p2, out octet p3); + return p1+p2, p1-p2, p1*p2 + + def do_short(self, p1, p2): + # short do_short(in short p1, inout short p2, out short p3); + return p1+p2, p1-p2, p1*p2 + + def do_unsigned_short(self, p1, p2): + # unsigned short do_unsigned_short(in unsigned short p1, inout unsigned short p2, out unsigned short p3); + return p1+p2, p1-p2, p1*p2 + def do_long(self, p1, p2): + # long do_long(in long p1, inout long p2, out long p3); + return p1+p2, p1-p2, p1*p2 + + def do_unsigned_long(self, p1, p2): + # unsigned long do_unsigned_long(in unsigned long p1, inout unsigned long p2, out unsigned long p3); + return p1+p2, p1-p2, p1*p2 + def do_long_long(self, p1, p2): + # long long do_long_long(in long long p1, inout long long p2, out long long p3); + return p1+p2, p1-p2, p1*p2 + def do_unsigned_long_long(self, p1, p2): + # unsigned long long do_unsigned_long_long(in unsigned long long p1, inout unsigned long long p2, out unsigned long long p3); + return p1+p2, p1-p2, p1*p2 + def do_float(self, p1, p2): + # float do_float(in float p1, inout float p2, out float p3); + return p1+p2, p1-p2, p1*p2 + def do_double(self, p1, p2): + # double do_double(in double p1, inout double p2, out double p3); + return p1+p2, p1-p2, p1*p2 + def do_char(self, p1, p2): + # char do_char(in char p1, inout char p2, out char p3); + return chr(ord(p1)+ord(p2)), p2, p1 + def do_wchar(self, p1, p2): + # wchar do_wchar(in wchar p1, inout wchar p2, out wchar p3); + return chr(ord(p1)+ord(p2)), p2, p1 + def do_string(self, p1, p2): + # string do_string(in string p1, inout string p2, out string p3); + ret = "" + if p1 is not None: ret = ret + p1 + if p2 is not None: ret = ret + p2 + return ret, p1, p2 + def do_wstring(self, p1, p2): + # wstring do_wstring(in wstring p1, inout wstring p2, out wstring p3); + ret = u"" + if p1 is not None: ret = ret + p1 + if p2 is not None: ret = ret + p2 + return ret, p1, p2 + def do_nsIIDRef(self, p1, p2): + # nsIIDRef do_nsIIDRef(in nsIIDRef p1, inout nsIIDRef p2, out nsIIDRef p3); + return p1, self._reg_clsid_, p2 + def do_nsIPythonTestInterface(self, p1, p2): + # nsIPythonTestInterface do_nsIPythonTestInterface(in nsIPythonTestInterface p1, inout nsIPythonTestInterface p2, out nsIPythonTestInterface p3); + return p2, p1, self + def do_nsISupports(self, p1, p2): + # nsISupports do_nsISupports(in nsISupports p1, inout nsISupports p2, out nsISupports p3); + return self, p1, p2 + def do_nsISupportsIs(self, iid): + # void do_nsISupportsIs(in nsIIDRef iid, [iid_is(iid),retval] out nsQIResult result) + # Note the framework does the QI etc on us, so there is no real point me doing it. + # (However, user code _should_ do the QI - otherwise any errors are deemed "internal" (as they + # are raised by the C++ framework), and therefore logged to the console, etc. + # A user QI allows the user to fail gracefully, whatever gracefully means for them! + return self +# Do I really need these?? +## def do_nsISupportsIs2(self, iid, interface): +## # void do_nsISupportsIs2(inout nsIIDRef iid, [iid_is(iid),retval] inout nsQIResult result); +## return iid, interface +## def do_nsISupportsIs3(self, interface): +## # void do_nsISupportsIs3(out nsIIDRef iid, [iid_is(iid)] inout nsQIResult result); +## return self._com_interfaces_, interface +## def do_nsISupportsIs4(self): +## # void do_nsISupportsIs4(out nsIIDRef iid, [iid_is(iid)] out nsQIResult result); +## return self._com_interfaces_, self + + # Methods from the nsIPythonTestInterfaceExtra interface + # + def MultiplyEachItemInIntegerArray(self, val, valueArray): + # void MultiplyEachItemInIntegerArray( + # in PRInt32 val, + # in PRUint32 count, + # [array, size_is(count)] inout PRInt32 valueArray); + # NOTE - the "sizeis" params are never passed to or returned from Python! + results = [] + for item in valueArray: + results.append(item * val) + return results + def MultiplyEachItemInIntegerArrayAndAppend(self, val, valueArray): + #void MultiplyEachItemInIntegerArrayAndAppend( + # in PRInt32 val, + # inout PRUint32 count, + # [array, size_is(count)] inout PRInt32 valueArray); + results = valueArray[:] + for item in valueArray: + results.append(item * val) + return results + def DoubleStringArray(self, valueArray): + # void DoubleStringArray(inout PRUint32 count, + # [array, size_is(count)] inout string valueArray); + results = [] + for item in valueArray: + results.append(item * 2) + return results + + def ReverseStringArray(self, valueArray): + # void ReverseStringArray(in PRUint32 count, + # [array, size_is(count)] inout string valueArray); + valueArray.reverse() + return valueArray + + # Note that this method shares a single "size_is" between 2 params! + def CompareStringArrays(self, ar1, ar2): + # void CompareStringArrays([array, size_is(count)] in string arr1, + # [array, size_is(count)] in string arr2, + # in unsigned long count, + # [retval] out short result); + return cmp(ar1, ar2) + + def DoubleString(self, val): + # void DoubleString(inout PRUint32 count, + # [size_is(count)] inout string str); + return val * 2 + def DoubleString2(self, val): + # void DoubleString2(in PRUint32 in_count, [size_is(in_count)] in string in_str, + # out PRUint32 out_count, [size_is(out_count)] out string out_str); + return val * 2 + def DoubleString3(self, val): + # void DoubleString3(in PRUint32 in_count, [size_is(in_count)] in string in_str, + # out PRUint32 out_count, [size_is(out_count), retval] string out_str); + return val * 2 + def DoubleString4(self, val): + # void DoubleString4([size_is(count)] in string in_str, inout PRUint32 count, [size_is(count)] out string out_str); + return val * 2 + def UpString(self, val): + # // UpString defines the count as only "in" - meaning the result must be the same size + # void UpString(in PRUint32 count, + # [size_is(count)] inout string str); + return val.upper() + UpString2 = UpString + # // UpString2 defines count as only "in", and a string as only "out" + # void UpString2(in PRUint32 count, + # [size_is(count)] inout string in_str, + # [size_is(count)]out string out_str); + + def GetFixedString(self, count): + # void GetFixedString(in PRUint32 count, [size_is(count)out string out_str); + return "A" * count + + # DoubleWideString functions are identical to DoubleString, except use wide chars! + def DoubleWideString(self, val): + return val * 2 + def DoubleWideString2(self, val): + return val * 2 + def DoubleWideString3(self, val): + return val * 2 + def DoubleWideString4(self, val): + return val * 2 + def UpWideString(self, val): + return val.upper() + UpWideString2 = UpWideString + def CopyUTF8String(self, v): + return v + def CopyUTF8String2(self, v): + return v.encode("utf8") + # Test we can get an "out" array with an "in" size (and the size is not used anywhere as a size for an in!) + def GetFixedWideString(self, count): + # void GetFixedWideString(in PRUint32 count, [size_is(count)out string out_str); + return u"A" * count + + def GetStrings(self): + # void GetStrings(out PRUint32 count, + # [retval, array, size_is(count)] out string str); + return "Hello from the Python test component".split() + # Some tests for our special "PRUint8" support. + def UpOctetArray( self, data ): + # void UpOctetArray(inout PRUint32 count, + # [array, size_is(count)] inout PRUint8 data); + return data.upper() + + def UpOctetArray2( self, data ): + # void UpOctetArray2(inout PRUint32 count, + # [array, size_is(count)] inout PRUint8 data); + data = data.upper() + # This time we return a list of integers. + return map( ord, data ) + + # Arrays of interfaces + def CheckInterfaceArray(self, interfaces): + # void CheckInterfaceArray(in PRUint32 count, + # [array, size_is(count)] in nsISupports data, + # [retval] out PRBool all_non_null); + ret = 1 + for i in interfaces: + if i is None: + ret = 0 + break + return ret + def CopyInterfaceArray(self, a): + return a + def GetInterfaceArray(self): + # void GetInterfaceArray(out PRUint32 count, + # [array, size_is(count)] out nsISupports data); + return self, self, self, None + def ExtendInterfaceArray(self, data): + # void ExtendInterfaceArray(inout PRUint32 count, + # [array, size_is(count)] inout nsISupports data); + return data * 2 + + # Arrays of IIDs + def CheckIIDArray(self, data): + # void CheckIIDArray(in PRUint32 count, + # [array, size_is(count)] in nsIIDRef data, + # [retval] out PRBool all_mine); + ret = 1 + for i in data: + if i!= self._com_interfaces_ and i != self._reg_clsid_: + ret = 0 + break + return ret + def GetIIDArray(self): + # void GetIIDArray(out PRUint32 count, + # [array, size_is(count)] out nsIIDRef data); + return self._com_interfaces_, self._reg_clsid_ + def ExtendIIDArray(self, data): + # void ExtendIIDArray(inout PRUint32 count, + # [array, size_is(count)] inout nsIIDRef data); + return data * 2 + + # Test our count param can be shared as an "in" param. + def SumArrays(self, array1, array2): + # void SumArrays(in PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]in array2, [retval]result); + if len(array1)!=len(array2): + print "SumArrays - not expecting different lengths!" + result = 0 + for i in array1: + result = result + i + for i in array2: + result = result+i + return result + + # Test our count param can be shared as an "out" param. + def GetArrays(self): + # void GetArrays(out PRUint32 count, [array, size_is(count)]out array1, [array, size_is(count)]out array2); + return (1,2,3), (4,5,6) + # Test we can get an "out" array with an "in" size + def GetFixedArray(self, size): + # void GetFixedArray(in PRUint32 count, [array, size_is(count)]out PRInt32 array1]); + return 0 * size + + # Test our "in" count param can be shared as one "in", plus one "out" param. + def CopyArray(self, array1): + # void CopyArray(in PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]out array2); + return array1 + # Test our "in-out" count param can be shared as one "in", plus one "out" param. + def CopyAndDoubleArray(self, array): + # void CopyAndDoubleArray(inout PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]out array2); + return array + array + # Test our "in-out" count param can be shared as one "in", plus one "in-out" param. + def AppendArray(self, array1, array2): + # void AppendArray(inout PRUint32 count, [array, size_is(count)]in array1, [array, size_is(count)]inout array2); + rc = array1 + if array2 is not None: + rc.extend(array2) + return rc + # Test nsIVariant support + def AppendVariant(self, invar, inresult): + if type(invar)==type([]): + invar_use = invar[0] + for v in invar[1:]: + invar_use += v + else: + invar_use = invar + if type(inresult)==type([]): + inresult_use = inresult[0] + for v in inresult[1:]: + inresult_use += v + else: + inresult_use = inresult + if inresult_use is None and invar_use is None: + return None + return inresult_use + invar_use + + def CopyVariant(self, invar): + return invar + + def SumVariants(self, variants): + if len(variants) == 0: + return None + result = variants[0] + for v in variants[1:]: + result += v + return result + + # Some tests for the "new" (Feb-2001) DOMString type. + def GetDOMStringResult( self, length ): + # Result: DOMString & + if length == -1: + return None + return "P" * length + def GetDOMStringOut( self, length ): + # Result: DOMString & + if length == -1: + return None + return "y" * length + def GetDOMStringLength( self, param0 ): + # Result: uint32 + # In: param0: DOMString & + if param0 is None: return -1 + return len(param0) + + def GetDOMStringRefLength( self, param0 ): + # Result: uint32 + # In: param0: DOMString & + if param0 is None: return -1 + return len(param0) + + def GetDOMStringPtrLength( self, param0 ): + # Result: uint32 + # In: param0: DOMString * + if param0 is None: return -1 + return len(param0) + + def ConcatDOMStrings( self, param0, param1 ): + # Result: void - None + # In: param0: DOMString & + # In: param1: DOMString & + # Out: DOMString & + return param0 + param1 + def get_domstring_value( self ): + # Result: DOMString & + return self.domstring_value + def set_domstring_value( self, param0 ): + # Result: void - None + # In: param0: DOMString & + self.domstring_value = param0 + + def get_domstring_value_ro( self ): + # Result: DOMString & + return self.domstring_value diff --git a/src/libs/xpcom18a4/python/test/test_components.py b/src/libs/xpcom18a4/python/test/test_components.py new file mode 100755 index 00000000..80007722 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_components.py @@ -0,0 +1,109 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +"""Tests the "xpcom.components" object. +""" + +import xpcom.components +from pyxpcom_test_tools import suite_from_functions, testmain + +if not __debug__: + raise RuntimeError, "This test uses assert, so must be run in debug mode" + +def test_interfaces(): + "Test the xpcom.components.interfaces object" + + iid = xpcom.components.interfaces.nsISupports + assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!" + iid = xpcom.components.interfaces['nsISupports'] + assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!" + + # Test dictionary semantics + num_fetched = num_nsisupports = 0 + for name, iid in xpcom.components.interfaces.items(): + num_fetched = num_fetched + 1 + if name == "nsISupports": + num_nsisupports = num_nsisupports + 1 + assert iid == xpcom._xpcom.IID_nsISupports, "Got the wrong IID!" + assert xpcom.components.interfaces[name] == iid + # Check all the lengths match. + assert len(xpcom.components.interfaces.keys()) == len(xpcom.components.interfaces.values()) == \ + len(xpcom.components.interfaces.items()) == len(xpcom.components.interfaces) == \ + num_fetched, "The collection lengths were wrong" + assert num_nsisupports == 1, "Didnt find exactly 1 nsiSupports!" + +def test_classes(): + # Need a well-known contractID here? + prog_id = "@mozilla.org/supports-array;1" + clsid = xpcom.components.ID("{bda17d50-0d6b-11d3-9331-00104ba0fd40}") + + # Check we can create the instance (dont check we can do anything with it tho!) + klass = xpcom.components.classes[prog_id] + instance = klass.createInstance() + + # Test dictionary semantics + num_fetched = num_mine = 0 + for name, klass in xpcom.components.classes.items(): + num_fetched = num_fetched + 1 + if name == prog_id: + assert klass.clsid == clsid, "Eeek - didn't get the correct IID - got %s" %klass.clsid + num_mine = num_mine + 1 + +# xpcom appears to add charset info to the contractid!? +# assert xpcom.components.classes[name].contractid == prog_id, "Expected '%s', got '%s'" % (prog_id, xpcom.components.classes[name].contractid) + # Check all the lengths match. + if len(xpcom.components.classes.keys()) == len(xpcom.components.classes.values()) == \ + len(xpcom.components.classes.items()) == len(xpcom.components.classes) == \ + num_fetched: + pass + else: + raise RuntimeError, "The collection lengths were wrong" + if num_fetched <= 0: + raise RuntimeError, "Didnt get any classes!!!" + if num_mine != 1: + raise RuntimeError, "Didnt find exactly 1 of my contractid! (%d)" % (num_mine,) + +def test_id(): + id = xpcom.components.ID(str(xpcom._xpcom.IID_nsISupports)) + assert id == xpcom._xpcom.IID_nsISupports + +# Make this test run under our std test suite +def suite(): + return suite_from_functions(test_interfaces, test_classes, test_id) + +if __name__=='__main__': + testmain() diff --git a/src/libs/xpcom18a4/python/test/test_isupports_primitives.py b/src/libs/xpcom18a4/python/test/test_isupports_primitives.py new file mode 100755 index 00000000..3d0e7023 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_isupports_primitives.py @@ -0,0 +1,207 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# Test our support for the interfaces defined in nsISupportsPrimitives.idl +# +# The framework supports nsISupportsCString and nsISupportsString, but +# only if our class doesnt provide explicit support. + +from xpcom import components +from xpcom import primitives +import xpcom.server, xpcom.client +from pyxpcom_test_tools import testmain +import unittest + +class NoSupportsString: + _com_interfaces_ = [components.interfaces.nsISupports] + +class ImplicitSupportsString: + _com_interfaces_ = [components.interfaces.nsISupports] + def __str__(self): + return "" + +class ExplicitSupportsString: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsCString] + type = components.interfaces.nsISupportsPrimitive.TYPE_CSTRING + test_data = "" + # __str__ will be ignored by XPCOM, as we have _explicit_ support. + def __str__(self): + return "" + # These are the ones that will be used. + def get_data(self): + return self.test_data + def toString(self): + return self.test_data + +class ImplicitSupportsUnicode: + _com_interfaces_ = [components.interfaces.nsISupports] + test_data = u"Copyright \xa9 the initial developer" + def __unicode__(self): + # An extended character in unicode tests can't hurt! + return self.test_data + +class ExplicitSupportsUnicode: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsString] + type = components.interfaces.nsISupportsPrimitive.TYPE_STRING + # __unicode__ will be ignored by XPCOM, as we have _explicit_ support. + test_data = u"Copyright \xa9 the initial developer" + def __unicode__(self): + return self.test_data + def get_data(self): + return self.test_data + +class ImplicitSupportsInt: + _com_interfaces_ = [components.interfaces.nsISupports] + def __int__(self): + return 99 + +class ExplicitSupportsInt: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsPRInt32] + type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT32 + def get_data(self): + return 99 + +class ImplicitSupportsLong: + _com_interfaces_ = [components.interfaces.nsISupports] + def __long__(self): + return 99L + +class ExplicitSupportsLong: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsPRInt64] + type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT64 + def get_data(self): + return 99 + +class ExplicitSupportsFloat: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsDouble] + type = components.interfaces.nsISupportsPrimitive.TYPE_DOUBLE + def get_data(self): + return 99.99 + +class ImplicitSupportsFloat: + _com_interfaces_ = [components.interfaces.nsISupports] + def __float__(self): + return 99.99 + +class PrimitivesTestCase(unittest.TestCase): + def testNoSupports(self): + ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports) + if not str(ob).startswith("") + + def testExplicitString(self): + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessEqual(str(ob), "") + + def testImplicitUnicode(self): + ob = xpcom.server.WrapObject( ImplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(unicode(ob), ImplicitSupportsUnicode.test_data) + + def testExplicitUnicode(self): + ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(unicode(ob), ExplicitSupportsUnicode.test_data) + + def testConvertInt(self): + # Try our conversions. + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessRaises( ValueError, int, ob) + + def testExplicitInt(self): + ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessAlmostEqual(float(ob), 99.0) + self.failUnlessEqual(int(ob), 99) + + def testImplicitInt(self): + ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessAlmostEqual(float(ob), 99.0) + self.failUnlessEqual(int(ob), 99) + + def testExplicitLong(self): + ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports) + if long(ob) != 99 or not repr(long(ob)).endswith("L"): + raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) + self.failUnlessAlmostEqual(float(ob), 99.0) + + def testImplicitLong(self): + ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports) + if long(ob) != 99 or not repr(long(ob)).endswith("L"): + raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) + self.failUnlessAlmostEqual(float(ob), 99.0) + + def testExplicitFloat(self): + ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(float(ob), 99.99) + self.failUnlessEqual(int(ob), 99) + + def testImplicitFloat(self): + ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(float(ob), 99.99) + self.failUnlessEqual(int(ob), 99) + +class PrimitivesModuleTestCase(unittest.TestCase): + def testExplicitString(self): + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), "") + + def testExplicitUnicode(self): + ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), ExplicitSupportsUnicode.test_data) + self.failUnlessEqual(type(primitives.GetPrimitive(ob)), unicode) + + def testExplicitInt(self): + ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99) + + def testExplicitLong(self): + ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99) + + def testExplicitFloat(self): + ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99.99) + +if __name__=='__main__': + testmain() diff --git a/src/libs/xpcom18a4/python/test/test_misc.py b/src/libs/xpcom18a4/python/test/test_misc.py new file mode 100755 index 00000000..6cf1b74e --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_misc.py @@ -0,0 +1,236 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# Activestate Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond +# +# 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 ***** + +import xpcom +import xpcom.client +import xpcom.server +import xpcom._xpcom +import xpcom.components +import string +from pyxpcom_test_tools import testmain + +import unittest + +import traceback, getopt, sys + +verbose_level = 0 + +reportedSampleMissing = 0 + +def get_sample_component_cpp(): + global reportedSampleMissing + contractid = "@mozilla.org/sample;1" # The C++ version. + try: + return xpcom.components.classes[contractid].createInstance() + except xpcom.COMException: + if not reportedSampleMissing: + print "***" + print "*** This test requires an XPCOM sample component," + print "*** which does not exist. To build this test, you" + print "*** should change to the 'mozilla/xpcom/sample' directory," + print "*** and run 'make', then run this test again." + print "***" + reportedSampleMissing = 1 + else: + print "(skipping - no C++ sample...) ", + return None + +def get_sample_component_js(): + # This should *always* exist - no special make process. + contractid = "@mozilla.org/jssample;1" # the JS version + return xpcom.components.classes[contractid].createInstance() + +class TestDumpInterfaces(unittest.TestCase): + def testAllInterfaces(self): + "Dump every interface under the sun!" + import xpcom, xpcom.xpt, xpcom._xpcom + iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager() + + if verbose_level: + print "Dumping every interface I can find" + enum = iim.EnumerateInterfaces() + rc = enum.First() + num = 0 + while rc==0: + item = enum.CurrentItem(xpcom._xpcom.IID_nsIInterfaceInfo) + try: + iid = item.GetIID() + except xpcom.COMException: + if verbose_level: + print "Can't dump", item + continue # Dont bother dumping this. + interface = xpcom.xpt.Interface(iid) + num = num + 1 + text = interface.Describe() + if verbose_level: + print text + + rc = enum.Next() + if num < 200: + print "Only found", num, "interfaces - this seems unusually low!" + +class TestEnumContractIDs(unittest.TestCase): + def testContractIDs(self): + """Enumerate all the ContractIDs registered""" + enum = xpcom.components.registrar.enumerateContractIDs() + n = 0 + while enum.hasMoreElements(): + item = enum.getNext(xpcom.components.interfaces.nsISupportsCString) + n = n + 1 + if verbose_level: + print "ContractID:", item.data + if n < 200: + print "Only found", n, "ContractIDs - this seems unusually low!" + +class TestSampleComponent(unittest.TestCase): + def _doTestSampleComponent(self, test_flat = 0): + """Test the standard Netscape 'sample' sample""" + c = get_sample_component_cpp() + if c is None: + return + if not test_flat: + c = c.queryInterface(xpcom.components.interfaces.nsISample) + self.failUnlessEqual(c.value, "initial value") + c.value = "new value" + self.failUnlessEqual(c.value, "new value") + c.poke("poked value") + self.failUnlessEqual(c.value, "poked value") + c.writeValue("Python just poked:") + + def testSampleComponentFlat(self): + """Test the standard Netscape 'sample' sample using interface flattening""" + self._doTestSampleComponent(1) + + def testSampleComponentOld(self): + """Test the standard Netscape 'sample' sample using explicit QI""" + self._doTestSampleComponent(0) + + def _doTestHash(self, c): + "Test that hashing COM objects works" + d = {} + d[c] = None + if not d.has_key(c): + raise RuntimeError, "Can't get the exact same object back!" + if not d.has_key(c.queryInterface(xpcom.components.interfaces.nsISupports)): + raise RuntimeError, "Can't get back as nsISupports" + + # And the same in reverse - stick an nsISupports in, and make sure an explicit interface comes back. + d = {} +# contractid = "@mozilla.org/sample;1" # The C++ version. +# c = xpcom.components.classes[contractid].createInstance() \ +# .queryInterface(xpcom.components.interfaces.nsISupports) + d[c] = None + if not d.has_key(c): + raise RuntimeError, "Can't get the exact same object back!" + if not d.has_key(c.queryInterface(xpcom.components.interfaces.nsISample)): + raise RuntimeError, "Can't get back as nsISupports" + + def testHashJS(self): + c = get_sample_component_js() + self._doTestHash(c) + + def testHashCPP(self): + c = get_sample_component_cpp() + if c is not None: + self._doTestHash(c) + + +class TestIIDs(unittest.TestCase): + def TestIIDs(self): + "Do some basic IID semantic tests." + iid_str = "{7ee4bdc6-cb53-42c1-a9e4-616b8e012aba}" + IID = xpcom._xpcom.IID + self.failUnlessEqual(IID(iid_str), IID(iid_str)) + self.failUnlessEqual(hash(IID(iid_str)), hash(IID(iid_str))) + self.failUnlessEqual(IID(iid_str), IID(iid_str.upper())) + self.failUnlessEqual(hash(IID(iid_str)), hash(IID(iid_str.upper()))) + # If the above work, this shoud too, but WTF + dict = {} + dict[IID(iid_str)] = None + self.failUnless(dict.has_key(IID(iid_str)), "hashes failed in dictionary") + self.failUnless(dict.has_key(IID(iid_str.upper())), "uppercase hash failed in dictionary") + +class TestRepr(unittest.TestCase): + def _doTestRepr(self, progid, interfaces): + if isinstance(progid, str): + ob = xpcom.components.classes[progid].createInstance() + else: + ob = progid + self.failUnless(repr(ob).find(str(progid)) >= 0, repr(ob)) + for interface_name in interfaces.split(): + self.failUnless(repr(ob).find(interface_name) >= 0, repr(ob)) + + def testReprPython(self): + "Test repr() of Python objects" + self._doTestRepr("Python.TestComponent", "nsIPythonTestInterfaceDOMStrings nsIPythonTestInterfaceExtra nsIPythonTestInterface") + + # JS does not provide class-info :( + #def testReprJS(self): + # self._doTestRepr("@mozilla.org/jssample;1", "nsISample") + + def testReprSample(self): + "Test repr() of non-Python objects" + ob = get_sample_component_cpp() + if ob is None: + return + self._doTestRepr(ob, "nsISample") + +class TestUnwrap(unittest.TestCase): + "Test the unwrap facilities" + def testUnwrap(self): + # First test that a Python object can be unwrapped. + ob = xpcom.components.classes["Python.TestComponent"].createInstance() + pyob = xpcom.server.UnwrapObject(ob) + # This depends on our __repr__ implementation, but that's OK - it + # can be updated should our __repr__ change :) + self.failUnless(str(pyob).startswith(" (original author) +# +# 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 ***** + +import xpcom +from xpcom import _xpcom, components, COMException, ServerException, nsError +from StringIO import StringIO +import unittest +from pyxpcom_test_tools import testmain + +test_data = "abcdefeghijklmnopqrstuvwxyz" + +class koTestSimpleStream: + _com_interfaces_ = [components.interfaces.nsIInputStream] + # We avoid registering this object - see comments in get_test_inout_? below. + + def __init__(self): + self.data=StringIO(test_data) + self._non_blocking = False + + def close( self ): + pass + + def available( self ): + return self.data.len-self.data.pos + + def readStr( self, amount): + return self.data.read(amount) + + read=readStr + + def get_observer( self ): + raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED) + + def set_observer( self, param0 ): + raise ServerException(nsError.NS_ERROR_NOT_IMPLEMENTED) + + def isNonBlocking(self): + return self._non_blocking + +def get_test_input(): + # We use a couple of internal hacks here that mean we can avoid having the object + # registered. This code means that we are still working over the xpcom boundaries, tho + # (and the point of this test is not the registration, etc). + import xpcom.server, xpcom.client + ob = xpcom.server.WrapObject( koTestSimpleStream(), _xpcom.IID_nsISupports) + ob = xpcom.client.Component(ob._comobj_, components.interfaces.nsIInputStream) + return ob + +class StreamTests(unittest.TestCase): + def testInput(self): + self.do_test_input( get_test_input() ) + + def do_test_input(self, myStream): + self.failUnlessEqual(str(myStream.read(5)), test_data[:5]) + self.failUnlessEqual(str(myStream.read(0)), '') + self.failUnlessEqual(str(myStream.read(5)), test_data[5:10]) + self.failUnlessEqual(str(myStream.read(-1)), test_data[10:]) + self.failIf(myStream.isNonBlocking(), "Expected default to be blocking") + # stream observer mechanism has changed - we should test that. + +if __name__=='__main__': + testmain() diff --git a/src/libs/xpcom18a4/python/test/test_test_component.js b/src/libs/xpcom18a4/python/test/test_test_component.js new file mode 100644 index 00000000..54e39382 --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_test_component.js @@ -0,0 +1,138 @@ +/* ***** 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 Python XPCOM language bindings. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond (original author) + * + * 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 ***** */ + +/* Javascript code calling the Python test interface. */ + +var extended_unicode_string = "The Euro Symbol is '\u20ac'"; + +function MakeTestInterface() +{ + var clazz = Components.classes["Python.TestComponent"]; + var iface = Components.interfaces.nsIPythonTestInterfaceDOMStrings; + return new clazz(iface); +} + +var c = new MakeTestInterface(); + +if (c.boolean_value != 1) + throw("boolean_value has wrong initial value"); +c.boolean_value = false; +if (c.boolean_value != false) + throw("boolean_value has wrong new value"); + +// Python's own test does thorough testing of all numeric types +// Wont bother from here! + +if (c.char_value != 'a') + throw("char_value has wrong initial value"); +c.char_value = 'b'; +if (c.char_value != 'b') + throw("char_value has wrong new value"); + +if (c.wchar_value != 'b') + throw("wchar_value has wrong initial value"); +c.wchar_value = 'c'; +if (c.wchar_value != 'c') + throw("wchar_value has wrong new value"); + +if (c.string_value != 'cee') + throw("string_value has wrong initial value"); +c.string_value = 'dee'; +if (c.string_value != 'dee') + throw("string_value has wrong new value"); + +if (c.wstring_value != 'dee') + throw("wstring_value has wrong initial value"); +c.wstring_value = 'eee'; +if (c.wstring_value != 'eee') + throw("wstring_value has wrong new value"); +c.wstring_value = extended_unicode_string; +if (c.wstring_value != extended_unicode_string) + throw("wstring_value has wrong new value"); + +if (c.domstring_value != 'dom') + throw("domstring_value has wrong initial value"); +c.domstring_value = 'New value'; +if (c.domstring_value != 'New value') + throw("domstring_value has wrong new value"); +c.domstring_value = extended_unicode_string; +if (c.domstring_value != extended_unicode_string) + throw("domstring_value has wrong new value"); + +if (c.utf8string_value != 'utf8string') + throw("utf8string_value has wrong initial value"); +c.utf8string_value = 'New value'; +if (c.utf8string_value != 'New value') + throw("utf8string_value has wrong new value"); +c.utf8string_value = extended_unicode_string; +if (c.utf8string_value != extended_unicode_string) + throw("utf8string_value has wrong new value"); + +var v = new Object(); +v.value = "Hello" +var l = new Object(); +l.value = v.value.length; +c.DoubleString(l, v); +if ( v.value != "HelloHello") + throw("Could not double the string!"); + +var v = new Object(); +v.value = "Hello" +var l = new Object(); +l.value = v.value.length; +c.DoubleWideString(l, v); +if ( v.value != "HelloHello") + throw("Could not double the wide string!"); + +// Some basic array tests +var v = new Array() +v[0] = 1; +v[2] = 2; +v[3] = 3; +var v2 = new Array() +v2[0] = 4; +v2[2] = 5; +v2[3] = 6; +if (c.SumArrays(v.length, v, v2) != 21) + throw("Could not sum an array of integers!"); + +var count = new Object(); +count.value = 0; +var out = []; +c.DoubleStringArray(count, out); + +print("javascript successfully tested the Python test component."); diff --git a/src/libs/xpcom18a4/python/test/test_test_component.py b/src/libs/xpcom18a4/python/test/test_test_component.py new file mode 100755 index 00000000..dd78133a --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_test_component.py @@ -0,0 +1,575 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +import sys, os, time +import xpcom.components +import xpcom._xpcom +import xpcom.nsError + +MakeVariant = xpcom._xpcom.MakeVariant + +try: + import gc +except ImportError: + gc = None + +num_errors = 0 + +component_iid = xpcom.components.ID("{7EE4BDC6-CB53-42c1-A9E4-616B8E012ABA}") +new_iid = xpcom.components.ID("{2AF747D3-ECBC-457b-9AF9-5C5D80EDC360}") + +contractid = "Python.TestComponent" + +really_big_string = "This is really repetitive!" * 10000 +really_big_wstring = u"This is really repetitive!" * 10000 +extended_unicode_string = u"The Euro Symbol is '\u20ac'" + +# Exception raised when a -ve integer is converted to an unsigned C integer +# (via an extension module). This changed in Python 2.2 +if sys.hexversion > 0x02010000: + UnsignedMismatchException = TypeError +else: + UnsignedMismatchException = OverflowError + +def print_error(error): + print error + global num_errors + num_errors = num_errors + 1 + +def _test_value(what, got, expecting): + ok = got == expecting + if type(got)==type(expecting)==type(0.0): + ok = abs(got-expecting) < 0.001 + if not ok: + print_error("*** Error %s - got '%r', but expecting '%r'" % (what, got, expecting)) + +def test_attribute(ob, attr_name, expected_init, new_value, new_value_really = None): + if xpcom.verbose: + print "Testing attribute %s" % (attr_name,) + if new_value_really is None: + new_value_really = new_value # Handy for eg bools - set a BOOL to 2, you still get back 1! + + _test_value( "getting initial attribute value (%s)" % (attr_name,), getattr(ob, attr_name), expected_init) + setattr(ob, attr_name, new_value) + _test_value( "getting new attribute value (%s)" % (attr_name,), getattr(ob, attr_name), new_value_really) + # And set it back to the expected init. + setattr(ob, attr_name, expected_init) + _test_value( "getting back initial attribute value after change (%s)" % (attr_name,), getattr(ob, attr_name), expected_init) + +def test_string_attribute(ob, attr_name, expected_init, is_dumb_sz = False, ascii_only = False): + test_attribute(ob, attr_name, expected_init, "normal value") + val = "a null >\0<" + if is_dumb_sz: + expected = "a null >" # dumb strings are \0 terminated. + else: + expected = val + test_attribute(ob, attr_name, expected_init, val, expected) + test_attribute(ob, attr_name, expected_init, "") + test_attribute(ob, attr_name, expected_init, really_big_string) + test_attribute(ob, attr_name, expected_init, u"normal unicode value") + val = u"a null >\0<" + if is_dumb_sz: + expected = "a null >" # dumb strings are \0 terminated. + else: + expected = val + test_attribute(ob, attr_name, expected_init, val, expected) + test_attribute(ob, attr_name, expected_init, u"") + test_attribute(ob, attr_name, expected_init, really_big_wstring) + if not ascii_only: + test_attribute(ob, attr_name, expected_init, extended_unicode_string) + +def test_attribute_failure(ob, attr_name, new_value, expected_exception): + try: + setattr(ob, attr_name, new_value) + print_error("*** Setting attribute '%s' to '%r' didnt yield an exception!" % (attr_name, new_value) ) + except: + exc_typ = sys.exc_info()[0] + exc_val = sys.exc_info()[1] + ok = issubclass(exc_typ, expected_exception) + if not ok: + print_error("*** Wrong exception setting '%s' to '%r'- got '%s: %s', expected '%s'" % (attr_name, new_value, exc_typ, exc_val, expected_exception)) + + +def test_method(method, args, expected_results): + if xpcom.verbose: + print "Testing %s%s" % (method.__name__, `args`) + ret = method(*args) + if ret != expected_results: + print_error("calling method %s - expected %r, but got %r" % (method.__name__, expected_results, ret)) + +def test_int_method(meth): + test_method(meth, (0,0), (0,0,0)) + test_method(meth, (1,1), (2,0,1)) + test_method(meth, (5,2), (7,3,10)) +# test_method(meth, (2,5), (7,-3,10)) + +def test_constant(ob, cname, val): + v = getattr(ob, cname) + if v != val: + print_error("Bad value for constant '%s' - got '%r'" % (cname, v)) + try: + setattr(ob, cname, 0) + print_error("The object allowed us to set the constant '%s'" % (cname,)) + except AttributeError: + pass + +def test_base_interface(c): + test_attribute(c, "boolean_value", 1, 0) + test_attribute(c, "boolean_value", 1, -1, 1) # Set a bool to anything, you should always get back 0 or 1 + test_attribute(c, "boolean_value", 1, 4, 1) # Set a bool to anything, you should always get back 0 or 1 + test_attribute(c, "boolean_value", 1, "1", 1) # This works by virtual of PyNumber_Int - not sure I agree, but... + test_attribute_failure(c, "boolean_value", "boo", ValueError) + test_attribute_failure(c, "boolean_value", test_base_interface, TypeError) + + test_attribute(c, "octet_value", 2, 5) + test_attribute(c, "octet_value", 2, 0) + test_attribute(c, "octet_value", 2, 128) # octet is unsigned 8 bit + test_attribute(c, "octet_value", 2, 255) # octet is unsigned 8 bit + test_attribute(c, "octet_value", 2, -1, 255) # octet is unsigned 8 bit + test_attribute_failure(c, "octet_value", "boo", ValueError) + + test_attribute(c, "short_value", 3, 10) + test_attribute(c, "short_value", 3, -1) # 16 bit signed + test_attribute(c, "short_value", 3, 0xFFFF, -1) # 16 bit signed + test_attribute(c, "short_value", 3, 0L) + test_attribute(c, "short_value", 3, 1L) + test_attribute(c, "short_value", 3, -1L) + test_attribute(c, "short_value", 3, 0xFFFFL, -1) + test_attribute_failure(c, "short_value", "boo", ValueError) + + test_attribute(c, "ushort_value", 4, 5) + test_attribute(c, "ushort_value", 4, 0) + test_attribute(c, "ushort_value", 4, -1, 0xFFFF) # 16 bit signed + test_attribute(c, "ushort_value", 4, 0xFFFF) # 16 bit signed + test_attribute(c, "ushort_value", 4, 0L) + test_attribute(c, "ushort_value", 4, 1L) + test_attribute(c, "ushort_value", 4, -1L, 0xFFFF) + test_attribute_failure(c, "ushort_value", "boo", ValueError) + + test_attribute(c, "long_value", 5, 7) + test_attribute(c, "long_value", 5, 0) + test_attribute(c, "long_value", 5, -1, -1) # 32 bit signed. + test_attribute(c, "long_value", 5, -1) # 32 bit signed. + test_attribute(c, "long_value", 5, 0L) + test_attribute(c, "long_value", 5, 1L) + test_attribute(c, "long_value", 5, -1L) + test_attribute_failure(c, "long_value", 0xFFFFL * 0xFFFF, OverflowError) # long int too long to convert + test_attribute_failure(c, "long_value", "boo", ValueError) + + test_attribute(c, "ulong_value", 6, 7) + test_attribute(c, "ulong_value", 6, 0) + test_attribute(c, "ulong_value", 6, -1) # 32 bit signed. + test_attribute_failure(c, "ulong_value", "boo", ValueError) + + test_attribute(c, "long_long_value", 7, 8) + test_attribute(c, "long_long_value", 7, 0) + test_attribute(c, "long_long_value", 7, -1) + test_attribute(c, "long_long_value", 7, 0xFFFF) + test_attribute(c, "long_long_value", 7, 0xFFFFL * 2) + test_attribute_failure(c, "long_long_value", 0xFFFFL * 0xFFFF * 0xFFFF * 0xFFFF, OverflowError) # long int too long to convert + test_attribute_failure(c, "long_long_value", "boo", ValueError) + + test_attribute(c, "ulong_long_value", 8, 9) + test_attribute(c, "ulong_long_value", 8, 0) + test_attribute_failure(c, "ulong_long_value", "boo", ValueError) + test_attribute_failure(c, "ulong_long_value", -1, UnsignedMismatchException) # can't convert negative value to unsigned long) + + test_attribute(c, "float_value", 9.0, 10.2) + test_attribute(c, "float_value", 9.0, 0) + test_attribute(c, "float_value", 9.0, -1) + test_attribute(c, "float_value", 9.0, 1L) + test_attribute_failure(c, "float_value", "boo", ValueError) + + test_attribute(c, "double_value", 10.0, 9.0) + test_attribute(c, "double_value", 10.0, 0) + test_attribute(c, "double_value", 10.0, -1) + test_attribute(c, "double_value", 10.0, 1L) + test_attribute_failure(c, "double_value", "boo", ValueError) + + test_attribute(c, "char_value", "a", "b") + test_attribute(c, "char_value", "a", "\0") + test_attribute_failure(c, "char_value", "xy", ValueError) + test_attribute(c, "char_value", "a", u"c") + test_attribute(c, "char_value", "a", u"\0") + test_attribute_failure(c, "char_value", u"xy", ValueError) + + test_attribute(c, "wchar_value", "b", "a") + test_attribute(c, "wchar_value", "b", "\0") + test_attribute_failure(c, "wchar_value", "hi", ValueError) + test_attribute(c, "wchar_value", "b", u"a") + test_attribute(c, "wchar_value", "b", u"\0") + test_attribute_failure(c, "wchar_value", u"hi", ValueError) + + test_string_attribute(c, "string_value", "cee", is_dumb_sz = True, ascii_only = True) + test_string_attribute(c, "wstring_value", "dee", is_dumb_sz = True) + test_string_attribute(c, "astring_value", "astring") + test_string_attribute(c, "acstring_value", "acstring", ascii_only = True) + + test_string_attribute(c, "utf8string_value", "utf8string") + # Test a string already encoded gets through correctly. + test_attribute(c, "utf8string_value", "utf8string", extended_unicode_string.encode("utf8"), extended_unicode_string) + + # This will fail internal string representation :( Test we don't crash + try: + c.wstring_value = "a big char >" + chr(129) + "<" + print_error("strings with chars > 128 appear to have stopped failing?") + except UnicodeError: + pass + + test_attribute(c, "iid_value", component_iid, new_iid) + test_attribute(c, "iid_value", component_iid, str(new_iid), new_iid) + test_attribute(c, "iid_value", component_iid, xpcom._xpcom.ID(new_iid)) + + test_attribute_failure(c, "no_attribute", "boo", AttributeError) + + test_attribute(c, "interface_value", None, c) + test_attribute_failure(c, "interface_value", 2, TypeError) + + test_attribute(c, "isupports_value", None, c) + + # The methods + test_method(c.do_boolean, (0,1), (1,0,1)) + test_method(c.do_boolean, (1,0), (1,0,1)) + test_method(c.do_boolean, (1,1), (0,1,0)) + + test_int_method(c.do_octet) + test_int_method(c.do_short) + + test_int_method(c.do_unsigned_short) + test_int_method(c.do_long) + test_int_method(c.do_unsigned_long) + test_int_method(c.do_long_long) + test_int_method(c.do_unsigned_long) + test_int_method(c.do_float) + test_int_method(c.do_double) + + test_method(c.do_char, ("A", " "), (chr(ord("A")+ord(" ")), " ","A") ) + test_method(c.do_char, ("A", "\0"), ("A", "\0","A") ) + test_method(c.do_wchar, ("A", " "), (chr(ord("A")+ord(" ")), " ","A") ) + test_method(c.do_wchar, ("A", "\0"), ("A", "\0","A") ) + + test_method(c.do_string, ("Hello from ", "Python"), ("Hello from Python", "Hello from ", "Python") ) + test_method(c.do_string, (u"Hello from ", u"Python"), ("Hello from Python", "Hello from ", "Python") ) + test_method(c.do_string, (None, u"Python"), ("Python", None, "Python") ) + test_method(c.do_string, (None, really_big_string), (really_big_string, None, really_big_string) ) + test_method(c.do_string, (None, really_big_wstring), (really_big_string, None, really_big_string) ) + test_method(c.do_wstring, ("Hello from ", "Python"), ("Hello from Python", "Hello from ", "Python") ) + test_method(c.do_wstring, (u"Hello from ", u"Python"), ("Hello from Python", "Hello from ", "Python") ) + test_method(c.do_string, (None, really_big_wstring), (really_big_wstring, None, really_big_wstring) ) + test_method(c.do_string, (None, really_big_string), (really_big_wstring, None, really_big_wstring) ) + test_method(c.do_nsIIDRef, (component_iid, new_iid), (component_iid, component_iid, new_iid)) + test_method(c.do_nsIIDRef, (new_iid, component_iid), (new_iid, component_iid, component_iid)) + test_method(c.do_nsIPythonTestInterface, (None, None), (None, None, c)) + test_method(c.do_nsIPythonTestInterface, (c, c), (c, c, c)) + test_method(c.do_nsISupports, (None, None), (c, None, None)) + test_method(c.do_nsISupports, (c,c), (c, c, c)) + test_method(c.do_nsISupportsIs, (xpcom._xpcom.IID_nsISupports,), c) + test_method(c.do_nsISupportsIs, (xpcom.components.interfaces.nsIPythonTestInterface,), c) +## test_method(c.do_nsISupportsIs2, (xpcom.components.interfaces.nsIPythonTestInterface,c), (xpcom.components.interfaces.nsIPythonTestInterface,c)) +## test_method(c.do_nsISupportsIs3, (c,), (xpcom.components.interfaces.nsIPythonTestInterface,c)) +## test_method(c.do_nsISupportsIs4, (), (xpcom.components.interfaces.nsIPythonTestInterface,c)) + # Test the constants. + test_constant(c, "One", 1) + test_constant(c, "Two", 2) + test_constant(c, "MinusOne", -1) + test_constant(c, "BigLong", 0x7FFFFFFF) + test_constant(c, "BiggerLong", -1) + test_constant(c, "BigULong", -1) + # Test the components.Interfaces semantics + i = xpcom.components.interfaces.nsIPythonTestInterface + test_constant(i, "One", 1) + test_constant(i, "Two", 2) + test_constant(i, "MinusOne", -1) + test_constant(i, "BigLong", 0x7FFFFFFF) + test_constant(i, "BigULong", -1) + +def test_derived_interface(c, test_flat = 0): + val = "Hello\0there" + expected = val * 2 + + test_method(c.DoubleString, (val,), expected) + test_method(c.DoubleString2, (val,), expected) + test_method(c.DoubleString3, (val,), expected) + test_method(c.DoubleString4, (val,), expected) + test_method(c.UpString, (val,), val.upper()) + test_method(c.UpString2, (val,), val.upper()) + test_method(c.GetFixedString, (20,), "A"*20) + val = u"Hello\0there" + expected = val * 2 + test_method(c.DoubleWideString, (val,), expected) + test_method(c.DoubleWideString2, (val,), expected) + test_method(c.DoubleWideString3, (val,), expected) + test_method(c.DoubleWideString4, (val,), expected) + test_method(c.UpWideString, (val,), val.upper()) + test_method(c.UpWideString2, (val,), val.upper()) + test_method(c.GetFixedWideString, (20,), u"A"*20) + val = extended_unicode_string + test_method(c.CopyUTF8String, ("foo",), "foo") + test_method(c.CopyUTF8String, (u"foo",), "foo") + test_method(c.CopyUTF8String, (val,), val) + test_method(c.CopyUTF8String, (val.encode("utf8"),), val) + test_method(c.CopyUTF8String2, ("foo",), "foo") + test_method(c.CopyUTF8String2, (u"foo",), "foo") + test_method(c.CopyUTF8String2, (val,), val) + test_method(c.CopyUTF8String2, (val.encode("utf8"),), val) + items = [1,2,3,4,5] + test_method(c.MultiplyEachItemInIntegerArray, (3, items,), map(lambda i:i*3, items)) + + test_method(c.MultiplyEachItemInIntegerArrayAndAppend, (3, items), items + map(lambda i:i*3, items)) + items = "Hello from Python".split() + expected = map( lambda x: x*2, items) + test_method(c.DoubleStringArray, (items,), expected) + + test_method(c.CompareStringArrays, (items, items), cmp(items, items)) + # Can we pass lists and tuples correctly? + test_method(c.CompareStringArrays, (items, tuple(items)), cmp(items, items)) + items2 = ["Not", "the", "same"] + test_method(c.CompareStringArrays, (items, items2), cmp(items, items2)) + + expected = items[:] + expected.reverse() + test_method(c.ReverseStringArray, (items,), expected) + + expected = "Hello from the Python test component".split() + test_method(c.GetStrings, (), expected) + + val = "Hello\0there" + test_method(c.UpOctetArray, (val,), val.upper()) + test_method(c.UpOctetArray, (unicode(val),), val.upper()) + # Passing Unicode objects here used to cause us grief. + test_method(c.UpOctetArray2, (val,), val.upper()) + + test_method(c.CheckInterfaceArray, ((c, c),), 1) + test_method(c.CheckInterfaceArray, ((c, None),), 0) + test_method(c.CheckInterfaceArray, ((),), 1) + test_method(c.CopyInterfaceArray, ((c, c),), [c,c]) + + test_method(c.GetInterfaceArray, (), [c,c,c, None]) + test_method(c.ExtendInterfaceArray, ((c,c,c, None),), [c,c,c,None,c,c,c,None] ) + + expected = [xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings, xpcom.components.classes[contractid].clsid] + test_method(c.GetIIDArray, (), expected) + + val = [xpcom.components.interfaces.nsIPythonTestInterfaceExtra, xpcom.components.classes[contractid].clsid] + expected = val * 2 + test_method(c.ExtendIIDArray, (val,), expected) + + test_method(c.GetArrays, (), ( [1,2,3], [4,5,6] ) ) + test_method(c.CopyArray, ([1,2,3],), [1,2,3] ) + test_method(c.CopyAndDoubleArray, ([1,2,3],), [1,2,3,1,2,3] ) + test_method(c.AppendArray, ([1,2,3],), [1,2,3]) + test_method(c.AppendArray, ([1,2,3],[4,5,6]), [1,2,3,4,5,6]) + + test_method(c.CopyVariant, (None,), None) + test_method(c.CopyVariant, (1,), 1) + test_method(c.CopyVariant, (1.0,), 1.0) + test_method(c.CopyVariant, (-1,), -1) + test_method(c.CopyVariant, (sys.maxint+1,), sys.maxint+1) + test_method(c.CopyVariant, ("foo",), "foo") + test_method(c.CopyVariant, (u"foo",), u"foo") + test_method(c.CopyVariant, (c,), c) + test_method(c.CopyVariant, (component_iid,), component_iid) + test_method(c.CopyVariant, ((1,2),), [1,2]) + test_method(c.CopyVariant, ((1.2,2.1),), [1.2,2.1]) + test_method(c.CopyVariant, (("foo","bar"),), ["foo", "bar"]) + test_method(c.CopyVariant, ((component_iid,component_iid),), [component_iid,component_iid]) + test_method(c.CopyVariant, ((c,c),), [c,c]) + sup = c.queryInterface(xpcom.components.interfaces.nsISupports)._comobj_ + test_method(c.CopyVariant, ((sup, sup),), [sup,sup]) + test_method(c.AppendVariant, (1,2), 3) + test_method(c.AppendVariant, ((1,2),(3,4)), 10) + test_method(c.AppendVariant, ("bar", "foo"), "foobar") + test_method(c.AppendVariant, (None, None), None) + + test_method(c.SumVariants, ([],), None) + # Array's dont expose their interface, so we are unable to auto-wrap + # variant arrays, as they aren't aware if the IID of the array + test_method(c.SumVariants, ([MakeVariant(1),MakeVariant(2),MakeVariant(3)],), 6) + test_method(c.SumVariants, ([MakeVariant('foo'), MakeVariant('bar')],), 'foobar') + + if not test_flat: + c = c.queryInterface(xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings) +# NULL DOM strings don't work yet. +# test_method(c.GetDOMStringResult, (-1,), None) + test_method(c.GetDOMStringResult, (3,), "PPP") +# test_method(c.GetDOMStringOut, (-1,), None) + test_method(c.GetDOMStringOut, (4,), "yyyy") + val = "Hello there" + test_method(c.GetDOMStringLength, (val,), len(val)) + test_method(c.GetDOMStringRefLength, (val,), len(val)) + test_method(c.GetDOMStringPtrLength, (val,), len(val)) + test_method(c.ConcatDOMStrings, (val,val), val+val) + test_attribute(c, "domstring_value", "dom", "new dom") + if c.domstring_value_ro != "dom": + print "Read-only DOMString not correct - got", c.domstring_ro + try: + c.dom_string_ro = "new dom" + print "Managed to set a readonly attribute - eek!" + except AttributeError: + pass + except: + print "Unexpected exception when setting readonly attribute: %s: %s" % (sys.exc_info()[0], sys.exc_info()[1]) + if c.domstring_value_ro != "dom": + print "Read-only DOMString not correct after failed set attempt - got", c.domstring_ro + +def do_test_failures(): + c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterfaceExtra) + try: + ret = c.do_nsISupportsIs( xpcom._xpcom.IID_nsIInterfaceInfoManager ) + print "*** got", ret, "***" + raise RuntimeError, "We worked when using an IID we dont support!?!" + except xpcom.Exception, details: + if details.errno != xpcom.nsError.NS_ERROR_NO_INTERFACE: + raise RuntimeError, "Wrong COM exception type: %r" % (details,) + +def test_failures(): + # This extra stack-frame ensures Python cleans up sys.last_traceback etc + do_test_failures() + +def test_all(): + c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterface) + test_base_interface(c) + # Now create an instance using the derived IID, and test that. + c = xpcom.client.Component(contractid, xpcom.components.interfaces.nsIPythonTestInterfaceExtra) + test_base_interface(c) + test_derived_interface(c) + # Now create an instance and test interface flattening. + c = xpcom.components.classes[contractid].createInstance() + test_base_interface(c) + test_derived_interface(c, test_flat=1) + + # We had a bug where a "set" of an attribute before a "get" failed. + # Don't let it happen again :) + c = xpcom.components.classes[contractid].createInstance() + c.boolean_value = 0 + + # This name is used in exceptions etc - make sure we got it from nsIClassInfo OK. + assert c._object_name_ == "Python.TestComponent" + + test_failures() + +try: + from sys import gettotalrefcount +except ImportError: + # Not a Debug build - assume no references (can't be leaks then :-) + def gettotalrefcount(): + return 0 + +from pyxpcom_test_tools import getmemusage + +def test_from_js(): + # Ensure we can find the js test script - same dir as this! + # Assume the path of sys.argv[0] is where we can find the js test code. + # (Running under the regression test is a little painful) + script_dir = os.path.split(sys.argv[0])[0] + fname = os.path.join( script_dir, "test_test_component.js") + if not os.path.isfile(fname): + raise RuntimeError, "Can not find '%s'" % (fname,) + # Note we _dont_ pump the test output out, as debug "xpcshell" spews + # extra debug info that will cause our output comparison to fail. + data = os.popen('xpcshell "' + fname + '"').readlines() + good = 0 + for line in data: + if line.strip() == "javascript successfully tested the Python test component.": + good = 1 + if not good: + print "** The javascript test appeared to fail! Test output follows **" + print "".join(data) + print "** End of javascript test output **" + raise RuntimeError, "test failed" + +def doit(num_loops = -1): + if "-v" in sys.argv: # Hack the verbose flag for the server + xpcom.verbose = 1 + # Do the test lots of times - can help shake-out ref-count bugs. + if num_loops == -1: num_loops = 5 + for i in xrange(num_loops): + test_all() + + if i==0: + # First loop is likely to "leak" as we cache things. + # Leaking after that is a problem. + if gc is not None: + gc.collect() + num_refs = gettotalrefcount() + mem_usage = getmemusage() + + if num_errors: + break + + if gc is not None: + gc.collect() + + lost = gettotalrefcount() - num_refs + # Sometimes we get spurious counts off by 1 or 2. + # This can't indicate a real leak, as we have looped + # more than twice! + if abs(lost)>3: # 2 or 3 :) + print "*** Lost %d references" % (lost,) + + # sleep to allow the OS to recover + time.sleep(1) + mem_lost = getmemusage() - mem_usage + # working set size is fickle, and when we were leaking strings, this test + # would report a leak of 100MB. So we allow a 3MB buffer - but even this + # may still occasionally report spurious warnings. If you are really + # worried, bump the counter to a huge value, and if there is a leak it will + # show. + if mem_lost > 3000000: + print "*** Lost %.6f MB of memory" % (mem_lost/1000000.0,) + + assert num_errors==0, "There were %d errors testing the Python component" % (num_errors,) + +def suite(): + from pyxpcom_test_tools import suite_from_functions + return suite_from_functions(doit, test_from_js) + +if __name__=='__main__': + num_iters = 10 # times times is *lots* - we do a fair bit of work! + if __name__=='__main__' and len(sys.argv) > 1: + num_iters = int(sys.argv[1]) + + print "Testing the Python.TestComponent component" + doit(num_iters) + print "The Python test component worked." + test_from_js() + print "JS successfully used our Python test component." + xpcom._xpcom.NS_ShutdownXPCOM() + ni = xpcom._xpcom._GetInterfaceCount() + ng = xpcom._xpcom._GetGatewayCount() + if ni or ng: + print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) diff --git a/src/libs/xpcom18a4/python/test/test_weakreferences.py b/src/libs/xpcom18a4/python/test/test_weakreferences.py new file mode 100755 index 00000000..9bfb3fbc --- /dev/null +++ b/src/libs/xpcom18a4/python/test/test_weakreferences.py @@ -0,0 +1,114 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# test_weakreferences.py - Test our weak reference implementation. +from xpcom import components, _xpcom +import xpcom.server, xpcom.client +from pyxpcom_test_tools import suite_from_functions, testmain + +try: + from sys import gettotalrefcount +except ImportError: + # Not a Debug build - assume no references (can't be leaks then :-) + gettotalrefcount = lambda: 0 + +num_alive = 0 + +class koTestSimple: + _com_interfaces_ = [components.interfaces.nsIInputStream] + def __init__(self): + global num_alive + num_alive += 1 + def __del__(self): + global num_alive + num_alive -= 1 + def close( self ): + pass + +def test(): + ob = xpcom.server.WrapObject( koTestSimple(), components.interfaces.nsIInputStream) + + if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + + # Check we can create a weak reference to our object. + wr = xpcom.client.WeakReference(ob) + if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + + # Check we can call methods via the weak reference. + if wr() is None: raise RuntimeError, "Our weak-reference is returning None before it should!" + wr().close() + + ob = None # This should kill the object. + if num_alive != 0: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + if wr() is not None: raise RuntimeError, "Our weak-reference is not returning None when it should!" + + # Now a test that we can get a _new_ interface from the weak reference - ie, + # an IID the real object has never previously been queried for + # (this behaviour previously caused a bug - never again ;-) + ob = xpcom.server.WrapObject( koTestSimple(), components.interfaces.nsISupports) + if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + wr = xpcom.client.WeakReference(ob, components.interfaces.nsIInputStream) + if num_alive != 1: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + wr() # This would die once upon a time ;-) + ob = None # This should kill the object. + if num_alive != 0: raise RuntimeError, "Eeek - there are %d objects alive" % (num_alive,) + if wr() is not None: raise RuntimeError, "Our weak-reference is not returning None when it should!" + +def test_refcount(num_loops=-1): + # Do the test lots of times - can help shake-out ref-count bugs. + if num_loops == -1: num_loops = 10 + for i in xrange(num_loops): + test() + + if i==0: + # First loop is likely to "leak" as we cache things. + # Leaking after that is a problem. + num_refs = gettotalrefcount() + + lost = gettotalrefcount() - num_refs + # Sometimes we get spurious counts off by 1 or 2. + # This can't indicate a real leak, as we have looped + # more than twice! + if abs(lost)>2: + print "*** Lost %d references" % (lost,) + +# Make this test run under our std test suite +def suite(): + return suite_from_functions(test_refcount) + +if __name__=='__main__': + testmain() diff --git a/src/libs/xpcom18a4/python/tools/regxpcom.py b/src/libs/xpcom18a4/python/tools/regxpcom.py new file mode 100755 index 00000000..2b7ea6a4 --- /dev/null +++ b/src/libs/xpcom18a4/python/tools/regxpcom.py @@ -0,0 +1,68 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# regxpcom.py - basically the standard regxpcom.cpp ported to Python. +# In general, you should use regxpcom.exe instead of this. + +from xpcom import components, _xpcom +from xpcom.client import Component +import sys +import os + +registrar = Component(_xpcom.GetComponentRegistrar(), + components.interfaces.nsIComponentRegistrar) + +def ProcessArgs(args): + + unregister = 0 + for arg in args: + spec = components.classes['@mozilla.org/file/local;1'].createInstance() + spec = spec.QueryInterface(components.interfaces.nsILocalFile) + spec.initWithPath(os.path.abspath(arg)) + if arg == "-u": + registrar.autoUnregister(spec) + print "Successfully unregistered", spec.path + else: + registrar.autoRegister(spec) + print "Successfully registered", spec.path + +if len(sys.argv) < 2: + registrar.autoRegister( None) +else: + ProcessArgs(sys.argv[1:]) + +#_xpcom.NS_ShutdownXPCOM() diff --git a/src/libs/xpcom18a4/python/tools/tracer_demo.py b/src/libs/xpcom18a4/python/tools/tracer_demo.py new file mode 100755 index 00000000..045c3db8 --- /dev/null +++ b/src/libs/xpcom18a4/python/tools/tracer_demo.py @@ -0,0 +1,113 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 is a demo is how to use the xpcom.server "tracer" facility. +# +# This demo installs a tracer that uses the Python profiler. It then +# creates the Python test component, and references some methods +# and properties. It then dumps the profile statistics. + +# This same technique could also be used for debugging, for example. + +import profile + +p = profile.Profile() +getters = {} +setters = {} + +# A wrapper around a function - looks like a function, +# but actually profiles the delegate. +class TracerDelegate: + def __init__(self, callme): + self.callme = callme + def __call__(self, *args): + return p.runcall(self.callme, *args) + +# A wrapper around each of our XPCOM objects. All PyXPCOM calls +# in are made on this object, which creates a TracerDelagate around +# every function. As the function is called, it collects profile info. +class Tracer: + def __init__(self, ob): + self.__dict__['_ob'] = ob + def __repr__(self): + return "" % (self._ob,) + def __str__(self): + return "" % (self._ob,) + def __getattr__(self, attr): + ret = getattr(self._ob, attr) # Attribute error just goes up + if callable(ret): + return TracerDelegate(ret) + else: + if not attr.startswith("_com_") and not attr.startswith("_reg_"): + getters[attr] = getters.setdefault(attr,0) + 1 + return ret + def __setattr__(self, attr, val): + if self.__dict__.has_key(attr): + self.__dict__[attr] = val + return + setters[attr] = setters.setdefault(attr,0) + 1 + setattr(self._ob, attr, val) + +# Installed as a global XPCOM function that if exists, will be called +# to wrap each XPCOM object created. +def MakeTracer(ob): + # In some cases we may be asked to wrap ourself, so handle that. + if isinstance(ob, Tracer): + return ob + return Tracer(ob) + +def test(): + import xpcom.server, xpcom.components + xpcom.server.tracer = MakeTracer + contractid = "Python.TestComponent" + for i in range(100): + c = xpcom.components.classes[contractid].createInstance().queryInterface(xpcom.components.interfaces.nsIPythonTestInterface) + c.boolean_value = 0 + a = c.boolean_value + c.do_boolean(0,1) + print "Finshed" + p.print_stats() + print "%-30s%s" % ("Attribute Gets", "Number") + print "-" * 36 + for name, num in getters.items(): + print "%-30s%d" % (name, num) + print "%-30s%s" % ("Attribute Sets", "Number") + print "-" * 36 + for name, num in setters.items(): + print "%-30s%d" % (name, num) + +test() diff --git a/src/libs/xpcom18a4/python/vboxxpcom.py b/src/libs/xpcom18a4/python/vboxxpcom.py new file mode 100755 index 00000000..6fd54d53 --- /dev/null +++ b/src/libs/xpcom18a4/python/vboxxpcom.py @@ -0,0 +1,83 @@ +""" +Copyright (C) 2008-2022 Oracle and/or its affiliates. + +This file is part of VirtualBox base platform packages, as +available from https://www.virtualbox.org. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation, in version 3 of the +License. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, see . + +SPDX-License-Identifier: GPL-3.0-only +""" + +import xpcom +import sys +import platform + +# +# This code overcomes somewhat unlucky feature of Python, where it searches +# for binaries in the same place as platfom independent modules, while +# rest of Python bindings expect _xpcom to be inside xpcom module +# + +_asVBoxPythons = [ + 'VBoxPython' + str(sys.version_info[0]) + '_' + str(sys.version_info[1]), + 'VBoxPython' + str(sys.version_info[0]), + 'VBoxPython' +] + +# For Python 3.2 and later use the right ABI flag suffix for the module. +if sys.hexversion >= 0x030200f0 and sys.abiflags: + _asNew = [] + for sCandidate in _asVBoxPythons: + if sCandidate[-1:].isdigit(): + _asNew.append(sCandidate + sys.abiflags) + else: + _asNew.append(sCandidate) + _asVBoxPythons = _asNew + del _asNew + +# On platforms where we ship both 32-bit and 64-bit API bindings, we have to +# look for the right set if we're a 32-bit process. +if platform.system() in [ 'SunOS', ] and sys.maxsize <= 2**32: + _asNew = [ sCandidate + '_x86' for sCandidate in _asVBoxPythons ] + _asNew.extend(_asVBoxPythons) + _asVBoxPythons = _asNew + del _asNew + +# On Darwin (aka Mac OS X) we know exactly where things are in a normal +# VirtualBox installation. +## @todo Edit this at build time to the actual VBox location set in the make files. +## @todo We know the location for most hardened builds, not just darwin! +if platform.system() == 'Darwin': + sys.path.append('/Applications/VirtualBox.app/Contents/MacOS') + +_oVBoxPythonMod = None +for m in _asVBoxPythons: + try: + _oVBoxPythonMod = __import__(m) + break + except: + pass + #except Exception as x: + # print('m=%s x=%s' % (m, x)) + +if platform.system() == 'Darwin': + sys.path.remove('/Applications/VirtualBox.app/Contents/MacOS') + +if _oVBoxPythonMod == None: + raise Exception('Cannot find VBoxPython module (tried: %s)' % (', '.join(_asVBoxPythons),)) + +sys.modules['xpcom._xpcom'] = _oVBoxPythonMod +xpcom._xpcom = _oVBoxPythonMod + diff --git a/src/libs/xpcom18a4/python/xpcom_consts.py b/src/libs/xpcom18a4/python/xpcom_consts.py new file mode 100644 index 00000000..933f93ef --- /dev/null +++ b/src/libs/xpcom18a4/python/xpcom_consts.py @@ -0,0 +1,272 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# 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 ***** + +# Could maybe later have a process that extracted these enums should they change. +# from nsFileLocations.h +App_DirectoryBase = 0x00010000 +App_PrefsDirectory30 = App_DirectoryBase + 1 +App_PrefsDirectory40 = App_DirectoryBase + 2 +App_PrefsDirectory50 = App_DirectoryBase + 3 +App_ResDirectory = App_DirectoryBase + 5 +App_UserProfileDirectory30 = App_DirectoryBase + 10 +App_UserProfileDirectory40 = App_DirectoryBase + 11 +App_UserProfileDirectory50 = App_DirectoryBase + 12 +App_DefaultUserProfileRoot30 = App_DirectoryBase + 13 +App_DefaultUserProfileRoot40 = App_DirectoryBase + 14 +App_DefaultUserProfileRoot50 = App_DirectoryBase + 15 +App_ProfileDefaultsFolder30 = App_DirectoryBase + 16 +App_ProfileDefaultsFolder40 = App_DirectoryBase + 17 +App_ProfileDefaultsFolder50 = App_DirectoryBase + 18 +App_PrefDefaultsFolder50 = App_DirectoryBase + 19 +App_DefaultsFolder50 = App_DirectoryBase + 25 +App_ComponentsDirectory = App_DirectoryBase + 30 +App_ChromeDirectory = App_DirectoryBase + 31 +App_PluginsDirectory = App_DirectoryBase + 32 +App_UserChromeDirectory = App_DirectoryBase + 40 +App_FileBase = App_DirectoryBase + 1000 +App_PreferencesFile30 = App_FileBase + 1 +App_PreferencesFile40 = App_FileBase + 2 +App_PreferencesFile50 = App_FileBase + 3 +App_BookmarksFile30 = App_FileBase + 10 +App_BookmarksFile40 = App_FileBase + 11 +App_BookmarksFile50 = App_FileBase + 12 +App_Registry40 = App_FileBase + 20 +App_Registry50 = App_FileBase + 21 +App_LocalStore50 = App_FileBase + 30 +App_History50 = App_FileBase + 40 +App_MailDirectory50 = App_FileBase + 50 +App_ImapMailDirectory50 = App_FileBase + 60 +App_NewsDirectory50 = App_FileBase + 70 +App_MessengerFolderCache50 = App_FileBase + 80 +App_UsersPanels50 = App_FileBase + 90 +App_SearchFile50 = App_FileBase + 100 +App_SearchDirectory50 = App_FileBase + 101 + +# From nsSpecialSystemDirectory.h +OS_DriveDirectory = 1 +OS_TemporaryDirectory = 2 +OS_CurrentProcessDirectory= 3 +OS_CurrentWorkingDirectory= 4 + +XPCOM_CurrentProcessComponentDirectory= 5 +XPCOM_CurrentProcessComponentRegistry= 6 + +Moz_BinDirectory = 10 + +Mac_SystemDirectory = 101 +Mac_DesktopDirectory = 102 +Mac_TrashDirectory = 103 +Mac_StartupDirectory = 104 +Mac_ShutdownDirectory = 105 +Mac_AppleMenuDirectory = 106 +Mac_ControlPanelDirectory = 107 +Mac_ExtensionDirectory = 108 +Mac_FontsDirectory = 109 +Mac_PreferencesDirectory = 110 +Mac_DocumentsDirectory = 111 +Mac_InternetSearchDirectory = 112 + +Win_SystemDirectory = 201 +Win_WindowsDirectory = 202 + +Win_HomeDirectory = 203 +Win_Desktop = 204 +Win_Programs = 205 +Win_Controls = 206 +Win_Printers = 207 +Win_Personal = 208 +Win_Favorites = 209 +Win_Startup = 210 +Win_Recent = 211 +Win_Sendto = 212 +Win_Bitbucket = 213 +Win_Startmenu = 214 +Win_Desktopdirectory = 215 +Win_Drives = 216 +Win_Network = 217 +Win_Nethood = 218 +Win_Fonts = 219 +Win_Templates = 220 +Win_Common_Startmenu = 221 +Win_Common_Programs = 222 +Win_Common_Startup = 223 +Win_Common_Desktopdirectory = 224 +Win_Appdata = 225 +Win_Printhood = 226 + +Unix_LocalDirectory = 301 +Unix_LibDirectory = 302 +Unix_HomeDirectory = 303 + +BeOS_SettingsDirectory = 401 +BeOS_HomeDirectory = 402 +BeOS_DesktopDirectory = 403 +BeOS_SystemDirectory = 404 + +OS2_SystemDirectory = 501 + +# Type/Variant related constants. +TD_INT8 = 0 +TD_INT16 = 1 +TD_INT32 = 2 +TD_INT64 = 3 +TD_UINT8 = 4 +TD_UINT16 = 5 +TD_UINT32 = 6 +TD_UINT64 = 7 +TD_FLOAT = 8 +TD_DOUBLE = 9 +TD_BOOL = 10 +TD_CHAR = 11 +TD_WCHAR = 12 +TD_VOID = 13 +TD_PNSIID = 14 +TD_DOMSTRING = 15 +TD_PSTRING = 16 +TD_PWSTRING = 17 +TD_INTERFACE_TYPE = 18 +TD_INTERFACE_IS_TYPE = 19 +TD_ARRAY = 20 +TD_PSTRING_SIZE_IS = 21 +TD_PWSTRING_SIZE_IS = 22 +TD_UTF8STRING = 23 +TD_CSTRING = 24 +TD_ASTRING = 25 + +# From xpt_struct.h +XPT_TDP_POINTER = 0x80 +XPT_TDP_UNIQUE_POINTER = 0x40 +XPT_TDP_REFERENCE = 0x20 +XPT_TDP_FLAGMASK = 0xe0 +XPT_TDP_TAGMASK = (~XPT_TDP_FLAGMASK) +def XPT_TDP_TAG(tdp): return (tdp & XPT_TDP_TAGMASK) + +def XPT_TDP_IS_POINTER(flags): return (flags & XPT_TDP_POINTER) +def XPT_TDP_IS_UNIQUE_POINTER(flags): return (flags & XPT_TDP_UNIQUE_POINTER) +def XPT_TDP_IS_REFERENCE(flags): return (flags & XPT_TDP_REFERENCE) + +XPT_ID_SCRIPTABLE = 0x80 +XPT_ID_FLAGMASK = 0x80 +XPT_ID_TAGMASK = ~XPT_ID_FLAGMASK +def XPT_ID_TAG(id): return id & XPT_ID_TAGMASK + +def XPT_ID_IS_SCRIPTABLE(flags): return flags & XPT_ID_SCRIPTABLE + +XPT_PD_IN = 0x80 +XPT_PD_OUT = 0x40 +XPT_PD_RETVAL = 0x20 +XPT_PD_SHARED = 0x10 +XPT_PD_DIPPER = 0x08 +XPT_PD_FLAGMASK = 0xf0 + +def XPT_PD_IS_IN(flags): return (flags & XPT_PD_IN) +def XPT_PD_IS_OUT(flags): return (flags & XPT_PD_OUT) +def XPT_PD_IS_RETVAL(flags): return (flags & XPT_PD_RETVAL) +def XPT_PD_IS_SHARED(flags): return (flags & XPT_PD_SHARED) +def XPT_PD_IS_DIPPER(flags): return (flags & XPT_PD_DIPPER) + +XPT_MD_GETTER = 0x80 +XPT_MD_SETTER = 0x40 +XPT_MD_NOTXPCOM = 0x20 +XPT_MD_CTOR = 0x10 +XPT_MD_HIDDEN = 0x08 +XPT_MD_FLAGMASK = 0xf8 + +def XPT_MD_IS_GETTER(flags): return (flags & XPT_MD_GETTER) +def XPT_MD_IS_SETTER(flags): return (flags & XPT_MD_SETTER) +def XPT_MD_IS_NOTXPCOM(flags): return (flags & XPT_MD_NOTXPCOM) +def XPT_MD_IS_CTOR(flags): return (flags & XPT_MD_CTOR) +def XPT_MD_IS_HIDDEN(flags): return (flags & XPT_MD_HIDDEN) + +# From xptinfo.h + +T_I8 = TD_INT8 +T_I16 = TD_INT16 +T_I32 = TD_INT32 +T_I64 = TD_INT64 +T_U8 = TD_UINT8 +T_U16 = TD_UINT16 +T_U32 = TD_UINT32 +T_U64 = TD_UINT64 +T_FLOAT = TD_FLOAT +T_DOUBLE = TD_DOUBLE +T_BOOL = TD_BOOL +T_CHAR = TD_CHAR +T_WCHAR = TD_WCHAR +T_VOID = TD_VOID +T_IID = TD_PNSIID +T_DOMSTRING = TD_DOMSTRING +T_CHAR_STR = TD_PSTRING +T_WCHAR_STR = TD_PWSTRING +T_INTERFACE = TD_INTERFACE_TYPE +T_INTERFACE_IS = TD_INTERFACE_IS_TYPE +T_ARRAY = TD_ARRAY +T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS +T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS +T_UTF8STRING = TD_UTF8STRING +T_CSTRING = TD_CSTRING +T_ASTRING = TD_ASTRING + +# from nsIVariant +VTYPE_INT8 = 0 +VTYPE_INT16 = 1 +VTYPE_INT32 = 2 +VTYPE_INT64 = 3 +VTYPE_UINT8 = 4 +VTYPE_UINT16 = 5 +VTYPE_UINT32 = 6 +VTYPE_UINT64 = 7 +VTYPE_FLOAT = 8 +VTYPE_DOUBLE = 9 +VTYPE_BOOL = 10 +VTYPE_CHAR = 11 +VTYPE_WCHAR = 12 +VTYPE_VOID = 13 +VTYPE_ID = 14 +VTYPE_DOMSTRING = 15 +VTYPE_CHAR_STR = 16 +VTYPE_WCHAR_STR = 17 +VTYPE_INTERFACE = 18 +VTYPE_INTERFACE_IS = 19 +VTYPE_ARRAY = 20 +VTYPE_STRING_SIZE_IS = 21 +VTYPE_WSTRING_SIZE_IS = 22 +VTYPE_UTF8STRING = 23 +VTYPE_CSTRING = 24 +VTYPE_ASTRING = 25 +VTYPE_EMPTY_ARRAY = 254 +VTYPE_EMPTY = 255 diff --git a/src/libs/xpcom18a4/python/xpt.py b/src/libs/xpcom18a4/python/xpt.py new file mode 100755 index 00000000..67021572 --- /dev/null +++ b/src/libs/xpcom18a4/python/xpt.py @@ -0,0 +1,471 @@ +# ***** 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 Python XPCOM language bindings. +# +# The Initial Developer of the Original Code is +# ActiveState Tool Corp. +# Portions created by the Initial Developer are Copyright (C) 2000, 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# David Ascher (original author) +# Mark Hammond +# +# 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 ***** + +""" +Program: xpt.py + +Task: describe interfaces etc using XPCOM reflection. + +Subtasks: + output (nearly) exactly the same stuff as xpt_dump, for verification + output Python source code that can be used as a template for an interface + +Status: Works pretty well if you ask me :-) + +Author: + David Ascher did an original version that parsed XPT files + directly. Mark Hammond changed it to use the reflection interfaces, + but kept most of the printing logic. + + +Revision: + + 0.1: March 6, 2000 + 0.2: April 2000 - Mark removed lots of Davids lovely parsing code in favour + of the new xpcom interfaces that provide this info. + + May 2000 - Moved into Perforce - track the log there! + Early 2001 - Moved into the Mozilla CVS tree - track the log there! + +Todo: + Fill out this todo list. + +""" + +import string, sys +import xpcom +import xpcom._xpcom + +from .xpcom_consts import * + +class Interface: + def __init__(self, iid): + iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager() + if hasattr(iid, "upper"): # Is it a stringy thing. + item = iim.GetInfoForName(iid) + else: + item = iim.GetInfoForIID(iid) + self.interface_info = item + self.namespace = "" # where does this come from? + self.methods = Methods(item) + self.constants = Constants(item) + + # delegate attributes to the real interface + def __getattr__(self, attr): + return getattr(self.interface_info, attr) + + def GetParent(self): + try: + raw_parent = self.interface_info.GetParent() + if raw_parent is None: + return None + return Interface(raw_parent.GetIID()) + except xpcom.Exception: + # Parent interface is probably not scriptable - assume nsISupports. + if xpcom.verbose: + # The user may be confused as to why this is happening! + print("The parent interface of IID '%s' can not be located - assuming nsISupports") + return Interface(xpcom._xpcom.IID_nsISupports) + + def Describe_Python(self): + method_reprs = [] + methods = [m for m in self.methods if not m.IsNotXPCOM()] + for m in methods: + method_reprs.append(m.Describe_Python()) + method_joiner = "\n" + methods_repr = method_joiner.join(method_reprs) + return \ +"""class %s: + _com_interfaces_ = xpcom.components.interfaces.%s + # If this object needs to be registered, the following 2 are also needed. + # _reg_clsid_ = "{a new clsid generated for this object}" + # _reg_contractid_ = "The.Object.Name"\n%s""" % (self.GetName(), self.GetIID().name, methods_repr) + + def Describe(self): + # Make the IID look like xtp_dump - "(" instead of "{" + iid_use = "(" + str(self.GetIID())[1:-1] + ")" + s = ' - '+self.namespace+'::'+ self.GetName() + ' ' + iid_use + ':\n' + + parent = self.GetParent() + if parent is not None: + s = s + ' Parent: ' + parent.namespace + '::' + parent.GetName() + '\n' + s = s + ' Flags:\n' + if self.IsScriptable(): word = 'TRUE' + else: word = 'FALSE' + s = s + ' Scriptable: ' + word + '\n' + s = s + ' Methods:\n' + methods = [m for m in self.methods if not m.IsNotXPCOM()] + if len(methods): + for m in methods: + s = s + ' ' + m.Describe() + '\n' + else: + s = s + ' No Methods\n' + s = s + ' Constants:\n' + if self.constants: + for c in self.constants: + s = s + ' ' + c.Describe() + '\n' + else: + s = s + ' No Constants\n' + + return s + +# A class that allows caching and iterating of methods. +class Methods: + def __init__(self, interface_info): + self.interface_info = interface_info + try: + self.items = [None] * interface_info.GetMethodCount() + except xpcom.Exception: + if xpcom.verbose: + print("** GetMethodCount failed?? - assuming no methods") + self.items = [] + def __len__(self): + return len(self.items) + def __getitem__(self, index): + ret = self.items[index] + if ret is None: + mi = self.interface_info.GetMethodInfo(index) + ret = self.items[index] = Method(mi, index, self.interface_info) + return ret + +class Method: + + def __init__(self, method_info, method_index, interface_info = None): + self.interface_info = interface_info + self.method_index = method_index + self.flags, self.name, param_descs, self.result_desc = method_info + # Build the params. + self.params = [] + pi=0 + for pd in param_descs: + self.params.append( Parameter(pd, pi, method_index, interface_info) ) + pi = pi + 1 + # Run over the params setting the "sizeof" params to hidden. + for p in self.params: + td = p.type_desc + tag = XPT_TDP_TAG(td[0]) + if tag==T_ARRAY and p.IsIn(): + self.params[td[1]].hidden_indicator = 2 + elif tag in [T_PSTRING_SIZE_IS, T_PWSTRING_SIZE_IS] and p.IsIn(): + self.params[td[1]].hidden_indicator = 1 + + def IsGetter(self): + return (self.flags & XPT_MD_GETTER) + def IsSetter(self): + return (self.flags & XPT_MD_SETTER) + def IsNotXPCOM(self): + return (self.flags & XPT_MD_NOTXPCOM) + def IsConstructor(self): + return (self.flags & XPT_MD_CTOR) + def IsHidden(self): + return (self.flags & XPT_MD_HIDDEN) + + def Describe_Python(self): + if self.method_index < 3: # Ignore QI etc + return "" + base_name = self.name + if self.IsGetter(): + name = "get_%s" % (base_name,) + elif self.IsSetter(): + name = "set_%s" % (base_name,) + else: + name = base_name + param_decls = ["self"] + in_comments = [] + out_descs = [] + result_comment = "Result: void - None" + for p in self.params: + in_desc, in_desc_comments, out_desc, this_result_comment = p.Describe_Python() + if in_desc is not None: + param_decls.append(in_desc) + if in_desc_comments is not None: + in_comments.append(in_desc_comments) + if out_desc is not None: + out_descs.append(out_desc) + if this_result_comment is not None: + result_comment = this_result_comment + joiner = "\n # " + in_comment = out_desc = "" + if in_comments: in_comment = joiner + joiner.join(in_comments) + if out_descs: out_desc = joiner + joiner.join(out_descs) + + return """ def %s( %s ): + # %s%s%s + pass""" % (name, ", ".join(param_decls), result_comment, in_comment, out_desc) + + def Describe(self): + s = '' + if self.IsGetter(): + G = 'G' + else: + G = ' ' + if self.IsSetter(): + S = 'S' + else: S = ' ' + if self.IsHidden(): + H = 'H' + else: + H = ' ' + if self.IsNotXPCOM(): + N = 'N' + else: + N = ' ' + if self.IsConstructor(): + C = 'C' + else: + C = ' ' + + def desc(a): return a.Describe() + method_desc = string.join(list(map(desc, self.params)), ', ') + result_type = TypeDescriber(self.result_desc[0], None) + return_desc = result_type.Describe() + i = string.find(return_desc, 'retval ') + if i != -1: + return_desc = return_desc[:i] + return_desc[i+len('retval '):] + return G+S+H+N+C+' '+return_desc+' '+self.name + '('+ method_desc + ');' + +class Parameter: + def __init__(self, param_desc, param_index, method_index, interface_info = None): + self.param_flags, self.type_desc = param_desc + self.hidden_indicator = 0 # Is this a special "size" type param that will be hidden from Python? + self.param_index = param_index + self.method_index= method_index + self.interface_info = interface_info + def __repr__(self): + return "" % self.__dict__ + def IsIn(self): + return XPT_PD_IS_IN(self.param_flags) + def IsOut(self): + return XPT_PD_IS_OUT(self.param_flags) + def IsInOut(self): + return self.IsIn() and self.IsOut() + def IsRetval(self): + return XPT_PD_IS_RETVAL(self.param_flags) + def IsShared(self): + return XPT_PD_IS_SHARED(self.param_flags) + def IsDipper(self): + return XPT_PD_IS_DIPPER(self.param_flags) + + def Describe_Python(self): + name = "param%d" % (self.param_index,) + if self.hidden_indicator: + # Could remove the comment - Im trying to tell the user where that param has + # gone from the signature! + return None, "%s is a hidden parameter" % (name,), None, None + t = TypeDescriber(self.type_desc[0], self) + decl = in_comment = out_comment = result_comment = None + type_desc = t.Describe() + if self.IsIn() and not self.IsDipper(): + decl = name + extra="" + if self.IsOut(): + extra = "Out" + in_comment = "In%s: %s: %s" % (extra, name, type_desc) + elif self.IsOut() or self.IsDipper(): + if self.IsRetval(): + result_comment = "Result: %s" % (type_desc,) + else: + out_comment = "Out: %s" % (type_desc,) + return decl, in_comment, out_comment, result_comment + + def Describe(self): + parts = [] + if self.IsInOut(): + parts.append('inout') + elif self.IsIn(): + parts.append('in') + elif self.IsOut(): + parts.append('out') + + if self.IsDipper(): parts.append("dipper") + if self.IsRetval(): parts.append('retval') + if self.IsShared(): parts.append('shared') + t = TypeDescriber(self.type_desc[0], self) + type_str = t.Describe() + parts.append(type_str) + return string.join(parts) + +# A class that allows caching and iterating of constants. +class Constants: + def __init__(self, interface_info): + self.interface_info = interface_info + try: + self.items = [None] * interface_info.GetConstantCount() + except xpcom.Exception: + if xpcom.verbose: + print("** GetConstantCount failed?? - assuming no constants") + self.items = [] + def __len__(self): + return len(self.items) + def __getitem__(self, index): + ret = self.items[index] + if ret is None: + ci = self.interface_info.GetConstant(index) + ret = self.items[index] = Constant(ci) + return ret + +class Constant: + def __init__(self, ci): + self.name, self.type, self.value = ci + + def Describe(self): + return TypeDescriber(self.type, None).Describe() + ' ' +self.name+' = '+str(self.value)+';' + + __str__ = Describe + +def MakeReprForInvoke(param): + tag = param.type_desc[0] & XPT_TDP_TAGMASK + if tag == T_INTERFACE: + i_info = param.interface_info + try: + iid = i_info.GetIIDForParam(param.method_index, param.param_index) + except xpcom.Exception: + # IID not available (probably not scriptable) - just use nsISupports. + iid = xpcom._xpcom.IID_nsISupports + return param.type_desc[0], 0, 0, str(iid) + elif tag == T_ARRAY: + i_info = param.interface_info + array_desc = i_info.GetTypeForParam(param.method_index, param.param_index, 1) + return param.type_desc[:-1] + array_desc[:1] + return param.type_desc + + +class TypeDescriber: + def __init__(self, type_flags, param): + self.type_flags = type_flags + self.tag = XPT_TDP_TAG(self.type_flags) + self.param = param + def IsPointer(self): + return XPT_TDP_IS_POINTER(self.type_flags) + def IsUniquePointer(self): + return XPT_TDP_IS_UNIQUE_POINTER(self.type_flags) + def IsReference(self): + return XPT_TDP_IS_REFERENCE(self.type_flags) + def repr_for_invoke(self): + return (self.type_flags,) + def GetName(self): + is_ptr = self.IsPointer() + data = type_info_map.get(self.tag) + if data is None: + data = ("unknown",) + if self.IsReference(): + if len(data) > 2: + return data[2] + return data[0] + " &" + if self.IsPointer(): + if len(data)>1: + return data[1] + return data[0] + " *" + return data[0] + + def Describe(self): + if self.tag == T_ARRAY: + # NOTE - Adding a type specifier to the array is different from xpt_dump.exe + if self.param is None or self.param.interface_info is None: + type_desc = "" # Dont have explicit info about the array type :-( + else: + i_info = self.param.interface_info + type_code = i_info.GetTypeForParam(self.param.method_index, self.param.param_index, 1) + type_desc = TypeDescriber( type_code[0], None).Describe() + return self.GetName() + "[" + type_desc + "]" + elif self.tag == T_INTERFACE: + if self.param is None or self.param.interface_info is None: + return "nsISomething" # Dont have explicit info about the IID :-( + i_info = self.param.interface_info + m_index = self.param.method_index + p_index = self.param.param_index + try: + iid = i_info.GetIIDForParam(m_index, p_index) + return iid.name + except xpcom.Exception: + return "nsISomething" + return self.GetName() + +# These are just for output purposes, so should be +# the same as xpt_dump uses +type_info_map = { + T_I8 : ("int8",), + T_I16 : ("int16",), + T_I32 : ("int32",), + T_I64 : ("int64",), + T_U8 : ("uint8",), + T_U16 : ("uint16",), + T_U32 : ("uint32",), + T_U64 : ("uint64",), + T_FLOAT : ("float",), + T_DOUBLE : ("double",), + T_BOOL : ("boolean",), + T_CHAR : ("char",), + T_WCHAR : ("wchar_t", "wstring"), + T_VOID : ("void",), + T_IID : ("reserved", "nsIID *", "nsIID &"), + T_DOMSTRING : ("DOMString",), + T_CHAR_STR : ("reserved", "string"), + T_WCHAR_STR : ("reserved", "wstring"), + T_INTERFACE : ("reserved", "Interface"), + T_INTERFACE_IS : ("reserved", "InterfaceIs *"), + T_ARRAY : ("reserved", "Array"), + T_PSTRING_SIZE_IS : ("reserved", "string_s"), + T_PWSTRING_SIZE_IS : ("reserved", "wstring_s"), +} + +def dump_interface(iid, mode): + interface = Interface(iid) + describer_name = "Describe" + if mode == "xptinfo": mode = None + if mode is not None: + describer_name = describer_name + "_" + mode.capitalize() + describer = getattr(interface, describer_name) + print(describer()) + +if __name__=='__main__': + if len(sys.argv) == 1: + print("Usage: xpt.py [-xptinfo] interface_name, ...") + print(" -info: Dump in a style similar to the xptdump tool") + print("Dumping nsISupports and nsIInterfaceInfo") + sys.argv.append('nsIInterfaceInfo') + sys.argv.append('-xptinfo') + sys.argv.append('nsISupports') + sys.argv.append('nsIInterfaceInfo') + + mode = "Python" + for i in sys.argv[1:]: + if i[0] == "-": + mode = i[1:] + else: + dump_interface(i, mode) diff --git a/src/libs/xpcom18a4/vboxdeps.cpp b/src/libs/xpcom18a4/vboxdeps.cpp new file mode 100644 index 00000000..37f70bba --- /dev/null +++ b/src/libs/xpcom18a4/vboxdeps.cpp @@ -0,0 +1,75 @@ +/* The usual story: drag stuff from the libraries into the link. */ + + +#include +#include +#include +#include +#include +#include +#include +#include "xpcom/proxy/src/nsProxyEventPrivate.h" +#include "nsTraceRefcnt.h" +#include "nsDebug.h" + +uintptr_t deps[] = +{ + (uintptr_t)PL_strncpy, + (uintptr_t)PL_strchr, + (uintptr_t)PL_strncpyz, + (uintptr_t)PL_HashString, + (uintptr_t)PR_DestroyPollableEvent, + (uintptr_t)NS_NewPipe2, + (uintptr_t)NS_ProxyRelease, + (uintptr_t)nsTraceRefcnt::LogRelease, + (uintptr_t)nsDebug::Assertion, + 0 +}; + +class foobardep : public nsXPTCStubBase +{ +public: + NS_IMETHOD_(nsrefcnt) AddRef(void) + { + return 1; + } + + NS_IMETHOD_(nsrefcnt) Release(void) + { + return 0; + } + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) + { + (void)info; + return 0; + } + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, const nsXPTMethodInfo* info, nsXPTCMiniVariant* params) + { + (void)methodIndex; + (void)info; + (void)params; + return 0; + } + +}; + + + +void foodep(void) +{ + nsVoidHashSetSuper *a = new nsVoidHashSetSuper(); + a->Init(123); + nsDeque *b = new nsDeque((nsDequeFunctor*)0); + + //nsXPTCStubBase + nsProxyEventObject *c = new nsProxyEventObject(); + c->Release(); + + foobardep *d = new foobardep(); + nsXPTCStubBase *e = d; + e->Release(); +} + diff --git a/src/libs/xpcom18a4/xpcom-config.h b/src/libs/xpcom18a4/xpcom-config.h new file mode 100644 index 00000000..ee34a6d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom-config.h @@ -0,0 +1,69 @@ +/* xpcom/xpcom-config.h. Generated automatically by configure. */ +/* Global defines needed by xpcom clients */ + +#ifndef _XPCOM_CONFIG_H_ +#define _XPCOM_CONFIG_H_ + +/* Define this to throw() if the compiler complains about + * constructors returning NULL + */ +#define CPP_THROW_NEW throw() + +/* Define if the c++ compiler supports a 2-byte wchar_t */ +#define HAVE_CPP_2BYTE_WCHAR_T 1 + +/* Define if the c++ compiler supports changing access with |using| */ +#define HAVE_CPP_ACCESS_CHANGING_USING 1 + +/* Define if the c++ compiler can resolve ambiguity with |using| */ +#define HAVE_CPP_AMBIGUITY_RESOLVING_USING 1 + +/* Define if the c++ compiler has builtin Bool type */ +/* #undef HAVE_CPP_BOOL */ + +/* Define if a dyanmic_cast to void* gives the most derived object */ +#define HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR 1 + +/* Define if the c++ compiler supports the |explicit| keyword */ +#define HAVE_CPP_EXPLICIT 1 + +/* Define if the c++ compiler supports the modern template + * specialization syntax + */ +#define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX 1 + +/* Define if the c++ compiler supports the |std| namespace */ +#define HAVE_CPP_NAMESPACE_STD 1 + +/* Define if the c++ compiler supports reinterpret_cast */ +#define HAVE_CPP_NEW_CASTS 1 + +/* Define if the c++ compiler supports partial template specialization */ +#define HAVE_CPP_PARTIAL_SPECIALIZATION 1 + +/* Define if the c++ compiler has trouble comparing a constant + * reference to a templatized class to zero + */ +/* #undef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO */ + +/* Define if the c++ compiler supports the |typename| keyword */ +#define HAVE_CPP_TYPENAME 1 + +/* Define if the stanard template operator!=() is ambiguous */ +#define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL 1 + +/* Define if statvfs() is available */ +#define HAVE_STATVFS 1 + +/* Define if the c++ compiler requires implementations of + * unused virtual methods + */ +#define NEED_CPP_UNUSED_IMPLEMENTATIONS 1 + +/* Define to either or */ +#define NEW_H + +/* Define if binary compatibility with Mozilla 1.x string code is desired */ +#define MOZ_V1_STRING_ABI 1 + +#endif /* _XPCOM_CONFIG_H_ */ diff --git a/src/libs/xpcom18a4/xpcom-namespace-cleanup.map b/src/libs/xpcom18a4/xpcom-namespace-cleanup.map new file mode 100644 index 00000000..9a6c9d4c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom-namespace-cleanup.map @@ -0,0 +1,34 @@ +# GNU ld version script, for linux +# Gets rid of all non-prefixed non-C++ global symbols. They cause problem if +# VirtualBox drags in the system-provided nspr library or some other code from +# the Mozilla project. VirtualBox shouldn't pollute the namespace. + +# +# Copyright (C) 2008-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# SPDX-License-Identifier: GPL-3.0-only +# + +{ + global: + _Z*; VBoxNs*; + __bss_start; _edata; _end; _fini; _init; + local: + *; +}; diff --git a/src/libs/xpcom18a4/xpcom-private.h b/src/libs/xpcom18a4/xpcom-private.h new file mode 100644 index 00000000..e0721fae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom-private.h @@ -0,0 +1,32 @@ +/* xpcom/xpcom-private.h. Generated automatically by configure. */ +/* The following defines are only used by the xpcom implementation */ + +#ifndef _XPCOM_PRIVATE_H_ +#define _XPCOM_PRIVATE_H_ + +/* Define to build the static component loader */ +#define ENABLE_STATIC_COMPONENT_LOADER 1 + +/* Define if getpagesize() is available */ +#define HAVE_GETPAGESIZE 1 + +/* Define if iconv() is available */ +#define HAVE_ICONV 1 + +/* Define if iconv() supports const input */ +/* #undef HAVE_ICONV_WITH_CONST_INPUT */ + +/* Define if mbrtowc() is available */ +#define HAVE_MBRTOWC 1 + +/* Define if is present */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define if is present */ +#define HAVE_SYS_VFS_H 1 + +/* Define if wcrtomb() is available */ +#define HAVE_WCRTOMB 1 + +#endif /* _XPCOM_PRIVATE_H_ */ + diff --git a/src/libs/xpcom18a4/xpcom/.cvsignore b/src/libs/xpcom18a4/xpcom/.cvsignore new file mode 100644 index 00000000..34b091a9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/.cvsignore @@ -0,0 +1,3 @@ +Makefile +xpcom-config.h +xpcom-private.h diff --git a/src/libs/xpcom18a4/xpcom/Makefile.in b/src/libs/xpcom18a4/xpcom/Makefile.in new file mode 100644 index 00000000..8bfe9abe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/Makefile.in @@ -0,0 +1,84 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = .. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +GRE_MODULE = 1 + +DIRS = \ + MoreFiles \ + typelib \ + string \ + glue \ + base \ + ds \ + io \ + components \ + threads \ + reflect \ + proxy \ + build \ + tools \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef MOZ_DEBUG +DIRS += windbgdlg +endif +endif + +ifdef ENABLE_TESTS +DIRS += \ + tests \ + sample \ + typelib/xpt/tests \ + reflect/xptinfo/tests \ + reflect/xptcall/tests \ + proxy/tests +endif + +# xpcom-config.h is generated by configure +SDK_HEADERS = xpcom-config.h + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/Makefile.kup b/src/libs/xpcom18a4/xpcom/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore b/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in b/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in new file mode 100644 index 00000000..56d89456 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/Makefile.in @@ -0,0 +1,70 @@ +# +# ***** 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 Mozilla. +# +# The Initial Developer of the Original Code is +# Netscape Communications. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = macmorefiles +REQUIRES = + +# ifeq for standalone builds +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) + +LIBRARY_NAME = macmorefiles_s + +CSRCS = \ + MoreFilesX.c \ + FSCopyObject.c \ + $(NULL) + +EXPORTS += \ + MoreFilesX.h \ + FSCopyObject.h \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a +# static lib. +FORCE_STATIC_LIB=1 +FORCE_USE_PIC=1 + +endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c new file mode 100644 index 00000000..d1b7af9e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c @@ -0,0 +1,2765 @@ +/* + File: MoreFilesX.c + + Contains: A collection of useful high-level File Manager routines + which use the HFS Plus APIs wherever possible. + + Version: MoreFilesX 1.0.1 + + +*/ + +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// Modified 2006-01-23 - added this comment. + +#if defined(__MACH__) + #include + #include +#else + #include + #include +#endif + +#include "MoreFilesX.h" + +/* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */ +#ifndef BuildingMoreFilesXForMacOS9 + #define BuildingMoreFilesXForMacOS9 0 +#endif + +/*****************************************************************************/ + +#pragma mark ----- Local type definitions ----- + +struct FSIterateContainerGlobals +{ + IterateContainerFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */ + FSCatalogInfoBitmap whichInfo; /* fields of the CatalogInfo to get */ + FSCatalogInfo catalogInfo; /* FSCatalogInfo */ + FSRef ref; /* FSRef */ + FSSpec spec; /* FSSpec */ + FSSpec *specPtr; /* pointer to spec field, or NULL */ + HFSUniStr255 name; /* HFSUniStr255 */ + HFSUniStr255 *namePtr; /* pointer to name field, or NULL */ + void *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */ + ItemCount maxLevels; /* maximum levels to iterate through */ + ItemCount currentLevel; /* the current level FSIterateContainerLevel is on */ + Boolean quitFlag; /* set to true if filter wants to kill interation */ + Boolean containerChanged; /* temporary - set to true if the current container changed during iteration */ + OSErr result; /* result */ + ItemCount actualObjects; /* number of objects returned */ +}; +typedef struct FSIterateContainerGlobals FSIterateContainerGlobals; + +struct FSDeleteContainerGlobals +{ + OSErr result; /* result */ + ItemCount actualObjects; /* number of objects returned */ + FSCatalogInfo catalogInfo; /* FSCatalogInfo */ +}; +typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals; + +/*****************************************************************************/ + +#pragma mark ----- Local prototypes ----- + +static +void +FSDeleteContainerLevel( + const FSRef *container, + FSDeleteContainerGlobals *theGlobals); + +static +void +FSIterateContainerLevel( + FSIterateContainerGlobals *theGlobals); + +static +OSErr +GenerateUniqueHFSUniStr( + long *startSeed, + const FSRef *dir1, + const FSRef *dir2, + HFSUniStr255 *uniqueName); + +/*****************************************************************************/ + +#pragma mark ----- File Access Routines ----- + +/*****************************************************************************/ + +OSErr +FSCopyFork( + SInt16 srcRefNum, + SInt16 dstRefNum, + void *copyBufferPtr, + ByteCount copyBufferSize) +{ + OSErr srcResult; + OSErr dstResult; + OSErr result; + SInt64 forkSize; + ByteCount readActualCount; + + /* check input parameters */ + require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr); + + /* get source fork size */ + result = FSGetForkSize(srcRefNum, &forkSize); + require_noerr(result, SourceFSGetForkSizeFailed); + + /* allocate disk space for destination fork */ + result = FSSetForkSize(dstRefNum, fsFromStart, forkSize); + require_noerr(result, DestinationFSSetForkSizeFailed); + + /* reset source fork's position to 0 */ + result = FSSetForkPosition(srcRefNum, fsFromStart, 0); + require_noerr(result, SourceFSSetForkPositionFailed); + + /* reset destination fork's position to 0 */ + result = FSSetForkPosition(dstRefNum, fsFromStart, 0); + require_noerr(result, DestinationFSSetForkPositionFailed); + + /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */ + /* This will make writes on local volumes faster */ + if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) ) + { + copyBufferSize &= ~(0x00001000 - 1); + } + + /* copy source to destination */ + srcResult = dstResult = noErr; + while ( (noErr == srcResult) && (noErr == dstResult) ) + { + srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount); + dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL); + } + + /* make sure there were no errors at the destination */ + require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult); + + /* make sure the error at the source was eofErr */ + require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult); + + /* everything went as expected */ + result = noErr; + +SourceResultNotEofErr: +DestinationFSWriteForkFailed: +DestinationFSSetForkPositionFailed: +SourceFSSetForkPositionFailed: +DestinationFSSetForkSizeFailed: +SourceFSGetForkSizeFailed: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Volume Access Routines ----- + +/*****************************************************************************/ + +OSErr +FSGetVolParms( + FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer *volParmsInfo, + UInt32 *actualInfoSize) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action((NULL != volParmsInfo) && (NULL != actualInfoSize), + BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)volParmsInfo; + pb.ioParam.ioReqCount = (SInt32)bufferSize; + result = PBHGetVolParmsSync(&pb); + require_noerr(result, PBHGetVolParmsSync); + + /* return number of bytes the file system returned in volParmsInfo buffer */ + *actualInfoSize = (UInt32)pb.ioParam.ioActCount; + +PBHGetVolParmsSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVRefNum( + const FSRef *ref, + FSVolumeRefNum *vRefNum) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != vRefNum, BadParameter, result = paramErr); + + /* get the volume refNum from the FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* return volume refNum from catalogInfo */ + *vRefNum = catalogInfo.volume; + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVInfo( + FSVolumeRefNum volume, + HFSUniStr255 *volumeName, /* can be NULL */ + UInt64 *freeBytes, /* can be NULL */ + UInt64 *totalBytes) /* can be NULL */ +{ + OSErr result; + FSVolumeInfo info; + + /* ask for the volume's sizes only if needed */ + result = FSGetVolumeInfo(volume, 0, NULL, + (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone), + &info, volumeName, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( NULL != freeBytes ) + { + *freeBytes = info.freeBytes; + } + if ( NULL != totalBytes ) + { + *totalBytes = info.totalBytes; + } + +FSGetVolumeInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolFileSystemID( + FSVolumeRefNum volume, + UInt16 *fileSystemID, /* can be NULL */ + UInt16 *signature) /* can be NULL */ +{ + OSErr result; + FSVolumeInfo info; + + result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( NULL != fileSystemID ) + { + *fileSystemID = info.filesystemID; + } + if ( NULL != signature ) + { + *signature = info.signature; + } + +FSGetVolumeInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetMountedVolumes( + FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ + ItemCount *numVolumes) +{ + OSErr result; + OSErr memResult; + ItemCount volumeIndex; + FSRef ref; + + /* check parameters */ + require_action((NULL != volumeRefsHandle) && (NULL != numVolumes), + BadParameter, result = paramErr); + + /* No volumes yet */ + *numVolumes = 0; + + /* Allocate a handle for the results */ + *volumeRefsHandle = (FSRef **)NewHandle(0); + require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr); + + /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */ + volumeIndex = 1; + do + { + result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref); + if ( noErr == result ) + { + /* concatenate the FSRef to the end of the handle */ + PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef)); + memResult = MemError(); + require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); + + ++(*numVolumes); /* increment the volume count */ + ++volumeIndex; /* and the volumeIndex to get the next volume*/ + } + } while ( noErr == result ); + + /* nsvErr is OK -- it just means there are no more volumes */ + require(nsvErr == result, FSGetVolumeInfo); + + return ( noErr ); + + /**********************/ + +MemoryAllocationFailed: +FSGetVolumeInfo: + + /* dispose of handle if already allocated and clear the outputs */ + if ( NULL != *volumeRefsHandle ) + { + DisposeHandle((Handle)*volumeRefsHandle); + *volumeRefsHandle = NULL; + } + *numVolumes = 0; + +NewHandle: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- + +/*****************************************************************************/ + +OSErr +FSRefMakeFSSpec( + const FSRef *ref, + FSSpec *spec) +{ + OSErr result; + + /* check parameters */ + require_action(NULL != spec, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMakeFSRef( + FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref) +{ + OSErr result; + FSRefParam pb; + + /* check parameters */ + require_action(NULL != ref, BadParameter, result = paramErr); + + pb.ioVRefNum = volRefNum; + pb.ioDirID = dirID; + pb.ioNamePtr = (StringPtr)name; + pb.newRef = ref; + result = PBMakeFSRefSync(&pb); + require_noerr(result, PBMakeFSRefSync); + +PBMakeFSRefSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSStatus +FSMakePath( + SInt16 volRefNum, + SInt32 dirID, + ConstStr255Param name, + UInt8 *path, + UInt32 maxPathSize) +{ + OSStatus result; + FSRef ref; + + /* check parameters */ + require_action(NULL != path, BadParameter, result = paramErr); + + /* convert the inputs to an FSRef */ + result = FSMakeFSRef(volRefNum, dirID, name, &ref); + require_noerr(result, FSMakeFSRef); + + /* and then convert the FSRef to a path */ + result = FSRefMakePath(&ref, path, maxPathSize); + require_noerr(result, FSRefMakePath); + +FSRefMakePath: +FSMakeFSRef: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSStatus +FSPathMakeFSSpec( + const UInt8 *path, + FSSpec *spec, + Boolean *isDirectory) /* can be NULL */ +{ + OSStatus result; + FSRef ref; + + /* check parameters */ + require_action(NULL != spec, BadParameter, result = paramErr); + + /* convert the POSIX path to an FSRef */ + result = FSPathMakeRef(path, &ref, isDirectory); + require_noerr(result, FSPathMakeRef); + + /* and then convert the FSRef to an FSSpec */ + result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +FSPathMakeRef: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +UnicodeNameGetHFSName( + UniCharCount nameLength, + const UniChar *name, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str31 hfsName) +{ + OSStatus result; + ByteCount unicodeByteLength; + ByteCount unicodeBytesConverted; + ByteCount actualPascalBytes; + UnicodeMapping uMapping; + UnicodeToTextInfo utInfo; + + /* check parameters */ + require_action(NULL != hfsName, BadParameter, result = paramErr); + + /* make sure output is valid in case we get errors or there's nothing to convert */ + hfsName[0] = 0; + + unicodeByteLength = nameLength * sizeof(UniChar); + if ( 0 == unicodeByteLength ) + { + /* do nothing */ + result = noErr; + } + else + { + /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ + if ( kTextEncodingUnknown == textEncodingHint ) + { + ScriptCode script; + RegionCode region; + + script = (ScriptCode)GetScriptManagerVariable(smSysScript); + region = (RegionCode)GetScriptManagerVariable(smRegionCode); + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, + NULL, &textEncodingHint ); + if ( paramErr == result ) + { + /* ok, ignore the region and try again */ + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &textEncodingHint ); + } + if ( noErr != result ) + { + /* ok... try something */ + textEncodingHint = kTextEncodingMacRoman; + } + } + + uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, + kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); + uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); + uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; + + result = CreateUnicodeToTextInfo(&uMapping, &utInfo); + require_noerr(result, CreateUnicodeToTextInfo); + + result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask, + 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ + isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars, + &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]); + require_noerr(result, ConvertFromUnicodeToText); + + hfsName[0] = (unsigned char)actualPascalBytes; /* fill in length byte */ + +ConvertFromUnicodeToText: + + /* verify the result in debug builds -- there's really not anything you can do if it fails */ + verify_noerr(DisposeUnicodeToTextInfo(&utInfo)); + } + +CreateUnicodeToTextInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +HFSNameGetUnicodeName( + ConstStr31Param hfsName, + TextEncoding textEncodingHint, + HFSUniStr255 *unicodeName) +{ + ByteCount unicodeByteLength; + OSStatus result; + UnicodeMapping uMapping; + TextToUnicodeInfo tuInfo; + ByteCount pascalCharsRead; + + /* check parameters */ + require_action(NULL != unicodeName, BadParameter, result = paramErr); + + /* make sure output is valid in case we get errors or there's nothing to convert */ + unicodeName->length = 0; + + if ( 0 == StrLength(hfsName) ) + { + result = noErr; + } + else + { + /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ + if ( kTextEncodingUnknown == textEncodingHint ) + { + ScriptCode script; + RegionCode region; + + script = GetScriptManagerVariable(smSysScript); + region = GetScriptManagerVariable(smRegionCode); + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, + NULL, &textEncodingHint); + if ( paramErr == result ) + { + /* ok, ignore the region and try again */ + result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &textEncodingHint); + } + if ( noErr != result ) + { + /* ok... try something */ + textEncodingHint = kTextEncodingMacRoman; + } + } + + uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, + kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); + uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); + uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; + + result = CreateTextToUnicodeInfo(&uMapping, &tuInfo); + require_noerr(result, CreateTextToUnicodeInfo); + + result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1], + 0, /* no control flag bits */ + 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ + sizeof(unicodeName->unicode), /* output buffer size in bytes */ + &pascalCharsRead, &unicodeByteLength, unicodeName->unicode); + require_noerr(result, ConvertFromTextToUnicode); + + /* convert from byte count to char count */ + unicodeName->length = unicodeByteLength / sizeof(UniChar); + +ConvertFromTextToUnicode: + + /* verify the result in debug builds -- there's really not anything you can do if it fails */ + verify_noerr(DisposeTextToUnicodeInfo(&tuInfo)); + } + +CreateTextToUnicodeInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- File/Directory Manipulation Routines ----- + +/*****************************************************************************/ + +Boolean FSRefValid(const FSRef *ref) +{ + return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) ); +} + +/*****************************************************************************/ + +OSErr +FSGetParentRef( + const FSRef *ref, + FSRef *parentRef) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != parentRef, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* + * Note: FSRefs always point to real file system objects. So, there cannot + * be a FSRef to the parent of volume root directories. Early versions of + * Mac OS X do not handle this case correctly and incorrectly return a + * FSRef for the parent of volume root directories instead of returning an + * invalid FSRef (a cleared FSRef is invalid). The next three lines of code + * ensure that you won't run into this bug. WW9D! + */ + if ( fsRtDirID == catalogInfo.nodeID ) + { + /* clear parentRef and return noErr which is the proper behavior */ + memset(parentRef, 0, sizeof(FSRef)); + } + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetFileDirName( + const FSRef *ref, + HFSUniStr255 *outName) +{ + OSErr result; + + /* check parameters */ + require_action(NULL != outName, BadParameter, result = paramErr); + + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetNodeID( + const FSRef *ref, + long *nodeID, /* can be NULL */ + Boolean *isDirectory) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information to get */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != nodeID ) + { + whichInfo |= kFSCatInfoNodeID; + } + if ( NULL != isDirectory ) + { + whichInfo |= kFSCatInfoNodeFlags; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + if ( NULL != nodeID ) + { + *nodeID = catalogInfo.nodeID; + } + if ( NULL != isDirectory ) + { + *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetUserPrivilegesPermissions( + const FSRef *ref, + UInt8 *userPrivileges, /* can be NULL */ + UInt32 permissions[4]) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information to get */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != userPrivileges ) + { + whichInfo |= kFSCatInfoUserPrivs; + } + if ( NULL != permissions ) + { + whichInfo |= kFSCatInfoPermissions; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + if ( NULL != userPrivileges ) + { + *userPrivileges = catalogInfo.userPrivileges; + } + if ( NULL != permissions ) + { + BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCheckLock( + const FSRef *ref) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSVolumeInfo volumeInfo; + + /* get nodeFlags and vRefNum for container */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* is file locked? */ + if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) + { + result = fLckdErr; /* file is locked */ + } + else + { + /* file isn't locked, but is volume locked? */ + + /* get volume flags */ + result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL); + require_noerr(result, FSGetVolumeInfo); + + if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) ) + { + result = wPrErr; /* volume locked by hardware */ + } + else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) ) + { + result = vLckdErr; /* volume locked by software */ + } + } + +FSGetVolumeInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetForkSizes( + const FSRef *ref, + UInt64 *dataLogicalSize, /* can be NULL */ + UInt64 *rsrcLogicalSize) /* can be NULL */ +{ + OSErr result; + FSCatalogInfoBitmap whichInfo; + FSCatalogInfo catalogInfo; + + whichInfo = kFSCatInfoNodeFlags; + if ( NULL != dataLogicalSize ) + { + /* get data fork size */ + whichInfo |= kFSCatInfoDataSizes; + } + if ( NULL != rsrcLogicalSize ) + { + /* get resource fork size */ + whichInfo |= kFSCatInfoRsrcSizes; + } + + /* get nodeFlags and catalog info */ + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* make sure FSRef was to a file */ + require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); + + if ( NULL != dataLogicalSize ) + { + /* return data fork size */ + *dataLogicalSize = catalogInfo.dataLogicalSize; + } + if ( NULL != rsrcLogicalSize ) + { + /* return resource fork size */ + *rsrcLogicalSize = catalogInfo.rsrcLogicalSize; + } + +FSRefNotFile: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetTotalForkSizes( + const FSRef *ref, + UInt64 *totalLogicalSize, /* can be NULL */ + UInt64 *totalPhysicalSize, /* can be NULL */ + ItemCount *forkCount) /* can be NULL */ +{ + OSErr result; + CatPositionRec forkIterator; + SInt64 forkSize; + SInt64 *forkSizePtr; + UInt64 forkPhysicalSize; + UInt64 *forkPhysicalSizePtr; + + /* Determine if forkSize needed */ + if ( NULL != totalLogicalSize) + { + *totalLogicalSize = 0; + forkSizePtr = &forkSize; + } + else + { + forkSizePtr = NULL; + } + + /* Determine if forkPhysicalSize is needed */ + if ( NULL != totalPhysicalSize ) + { + *totalPhysicalSize = 0; + forkPhysicalSizePtr = &forkPhysicalSize; + } + else + { + forkPhysicalSizePtr = NULL; + } + + /* zero fork count if returning it */ + if ( NULL != forkCount ) + { + *forkCount = 0; + } + + /* Iterate through the forks to get the sizes */ + forkIterator.initialize = 0; + do + { + result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr); + if ( noErr == result ) + { + if ( NULL != totalLogicalSize ) + { + *totalLogicalSize += forkSize; + } + + if ( NULL != totalPhysicalSize ) + { + *totalPhysicalSize += forkPhysicalSize; + } + + if ( NULL != forkCount ) + { + ++*forkCount; + } + } + } while ( noErr == result ); + + /* any error result other than errFSNoMoreItems is serious */ + require(errFSNoMoreItems == result, FSIterateForks); + + /* Normal exit */ + result = noErr; + +FSIterateForks: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSBumpDate( + const FSRef *ref) +{ + OSStatus result; + FSCatalogInfo catalogInfo; + UTCDateTime oldDateTime; +#if !BuildingMoreFilesXForMacOS9 + FSRef parentRef; + Boolean notifyParent; +#endif + +#if !BuildingMoreFilesXForMacOS9 + /* Get the node flags, the content modification date and time, and the parent ref */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* Notify the parent if this is a file */ + notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); +#else + /* Get the content modification date and time */ + result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); +#endif + + oldDateTime = catalogInfo.contentModDate; + + /* Get the current date and time */ + result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions); + require_noerr(result, GetUTCDateTime); + + /* if the old date and time is the the same as the current, bump the seconds by one */ + if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) && + (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) && + (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) ) + { + ++catalogInfo.contentModDate.lowSeconds; + if ( 0 == catalogInfo.contentModDate.lowSeconds ) + { + ++catalogInfo.contentModDate.highSeconds; + } + } + + /* Bump the content modification date and time */ + result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + +#if !BuildingMoreFilesXForMacOS9 + /* + * The problem with FNNotify is that it is not available under Mac OS 9 + * and there's no way to test for that except for looking for the symbol + * or something. So, I'll just conditionalize this for those who care + * to send a notification. + */ + + /* Send a notification for the parent of the file, or for the directory */ + result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions); + require_noerr(result, FNNotify); +#endif + + /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */ +FNNotify: +FSSetCatalogInfo: + + return ( noErr ); + + /**********************/ + +GetUTCDateTime: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetFinderInfo( + const FSRef *ref, + FinderInfo *info, /* can be NULL */ + ExtendedFinderInfo *extendedInfo, /* can be NULL */ + Boolean *isDirectory) /* can be NULL */ +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information is really needed */ + whichInfo = kFSCatInfoNone; + + if ( NULL != info ) + { + /* get FinderInfo */ + whichInfo |= kFSCatInfoFinderInfo; + } + + if ( NULL != extendedInfo ) + { + /* get ExtendedFinderInfo */ + whichInfo |= kFSCatInfoFinderXInfo; + } + + if ( NULL != isDirectory ) + { + whichInfo |= kFSCatInfoNodeFlags; + } + + result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* return FinderInfo if requested */ + if ( NULL != info ) + { + BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo)); + } + + /* return ExtendedFinderInfo if requested */ + if ( NULL != extendedInfo) + { + BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo)); + } + + /* set isDirectory Boolean if requested */ + if ( NULL != isDirectory) + { + *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); + } + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetFinderInfo( + const FSRef *ref, + const FinderInfo *info, + const ExtendedFinderInfo *extendedInfo) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSCatalogInfoBitmap whichInfo; + + /* determine what catalog information will be set */ + whichInfo = kFSCatInfoNone; /* start with none */ + if ( NULL != info ) + { + /* set FinderInfo */ + whichInfo |= kFSCatInfoFinderInfo; + BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo)); + } + if ( NULL != extendedInfo ) + { + /* set ExtendedFinderInfo */ + whichInfo |= kFSCatInfoFinderXInfo; + BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo)); + } + + result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo); + require_noerr(result, FSGetCatalogInfo); + +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSChangeCreatorType( + const FSRef *ref, + OSType fileCreator, + OSType fileType) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSRef parentRef; + + /* get nodeFlags, finder info, and parent FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* make sure FSRef was to a file */ + require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); + + /* If fileType not 0x00000000, change fileType */ + if ( fileType != (OSType)0x00000000 ) + { + ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType; + } + + /* If creator not 0x00000000, change creator */ + if ( fileCreator != (OSType)0x00000000 ) + { + ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator; + } + + /* now, save the new information back to disk */ + result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + + /* and attempt to bump the parent directory's mod date to wake up */ + /* the Finder to the change we just made (ignore errors from this) */ + verify_noerr(FSBumpDate(&parentRef)); + +FSSetCatalogInfo: +FSRefNotFile: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSChangeFinderFlags( + const FSRef *ref, + Boolean setBits, + UInt16 flagBits) +{ + OSErr result; + FSCatalogInfo catalogInfo; + FSRef parentRef; + + /* get the current finderInfo */ + result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef); + require_noerr(result, FSGetCatalogInfo); + + /* set or clear the appropriate bits in the finderInfo.finderFlags */ + if ( setBits ) + { + /* OR in the bits */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits; + } + else + { + /* AND out the bits */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits; + } + + /* save the modified finderInfo */ + result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + + /* and attempt to bump the parent directory's mod date to wake up the Finder */ + /* to the change we just made (ignore errors from this) */ + verify_noerr(FSBumpDate(&parentRef)); + +FSSetCatalogInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetInvisible( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kIsInvisible) ); +} + +OSErr +FSClearInvisible( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kIsInvisible) ); +} + +/*****************************************************************************/ + +OSErr +FSSetNameLocked( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kNameLocked) ); +} + +OSErr +FSClearNameLocked( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kNameLocked) ); +} + +/*****************************************************************************/ + +OSErr +FSSetIsStationery( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kIsStationery) ); +} + +OSErr +FSClearIsStationery( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kIsStationery) ); +} + +/*****************************************************************************/ + +OSErr +FSSetHasCustomIcon( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) ); +} + +OSErr +FSClearHasCustomIcon( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) ); +} + +/*****************************************************************************/ + +OSErr +FSClearHasBeenInited( + const FSRef *ref) +{ + return ( FSChangeFinderFlags(ref, false, kHasBeenInited) ); +} + +/*****************************************************************************/ + +OSErr +FSCopyFileMgrAttributes( + const FSRef *sourceRef, + const FSRef *destinationRef, + Boolean copyLockBit) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* get the source information */ + result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* don't copy the hasBeenInited bit; clear it */ + ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited; + + /* should the locked bit be copied? */ + if ( !copyLockBit ) + { + /* no, make sure the locked bit is clear */ + catalogInfo.nodeFlags &= ~kFSNodeLockedMask; + } + + /* set the destination information */ + result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo); + require_noerr(result, FSSetCatalogInfo); + +FSSetCatalogInfo: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMoveRenameObjectUnicode( + const FSRef *ref, + const FSRef *destDirectory, + UniCharCount nameLength, + const UniChar *name, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* if function fails along the way, newRef is final location of file */ +{ + OSErr result; + FSVolumeRefNum vRefNum; + FSCatalogInfo catalogInfo; + FSRef originalDirectory; + TextEncoding originalTextEncodingHint; + HFSUniStr255 originalName; + HFSUniStr255 uniqueName; /* unique name given to object while moving it to destination */ + long theSeed; /* the seed for generating unique names */ + + /* check parameters */ + require_action(NULL != newRef, BadParameter, result = paramErr); + + /* newRef = input to start with */ + BlockMoveData(ref, newRef, sizeof(FSRef)); + + /* get destDirectory's vRefNum */ + result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); + require_noerr(result, DestinationBad); + + /* save vRefNum */ + vRefNum = catalogInfo.volume; + + /* get ref's vRefNum, TextEncoding, name and parent directory*/ + result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory); + require_noerr(result, SourceBad); + + /* save TextEncoding */ + originalTextEncodingHint = catalogInfo.textEncodingHint; + + /* make sure ref and destDirectory are on same volume */ + require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* Skip a few steps if we're not renaming */ + if ( NULL != name ) + { + /* generate a name that is unique in both directories */ + theSeed = 0x4a696d4c; /* a fine unlikely filename */ + + result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName); + require_noerr(result, GenerateUniqueHFSUniStrFailed); + + /* Rename the object to uniqueName */ + result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef); + require_noerr(result, FSRenameUnicodeBeforeMoveFailed); + + if ( FSCompareFSRefs(destDirectory, &originalDirectory) != noErr ) + { + /* Move object to its new home */ + result = FSMoveObject(newRef, destDirectory, newRef); + require_noerr(result, FSMoveObjectAfterRenameFailed); + } + + /* Rename the object to new name */ + result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef); + require_noerr(result, FSRenameUnicodeAfterMoveFailed); + } + else + { + /* Move object to its new home */ + result = FSMoveObject(newRef, destDirectory, newRef); + require_noerr(result, FSMoveObjectNoRenameFailed); + } + + return ( result ); + + /*************/ + +/* + * failure handling code when renaming + */ + +FSRenameUnicodeAfterMoveFailed: + + /* Error handling: move object back to original location - ignore errors */ + verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef)); + +FSMoveObjectAfterRenameFailed: + + /* Error handling: rename object back to original name - ignore errors */ + verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef)); + +FSRenameUnicodeBeforeMoveFailed: +GenerateUniqueHFSUniStrFailed: + +/* + * failure handling code for renaming or not + */ +FSMoveObjectNoRenameFailed: +NotSameVolume: +SourceBad: +DestinationBad: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The FSDeleteContainerLevel function deletes the contents of a container + directory. All files and subdirectories in the specified container are + deleted. If a locked file or directory is encountered, it is unlocked + and then deleted. If any unexpected errors are encountered, + FSDeleteContainerLevel quits and returns to the caller. + + container --> FSRef to a directory. + theGlobals --> A pointer to a FSDeleteContainerGlobals struct + which contains the variables that do not need to + be allocated each time FSDeleteContainerLevel + recurses. That lets FSDeleteContainerLevel use + less stack space per recursion level. +*/ + +static +void +FSDeleteContainerLevel( + const FSRef *container, + FSDeleteContainerGlobals *theGlobals) +{ + /* level locals */ + FSIterator iterator; + FSRef itemToDelete; + UInt16 nodeFlags; + + /* Open FSIterator for flat access and give delete optimization hint */ + theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator); + require_noerr(theGlobals->result, FSOpenIterator); + + /* delete the contents of the directory */ + do + { + /* get 1 item to delete */ + theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, + NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo, + &itemToDelete, NULL, NULL); + if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) ) + { + /* save node flags in local in case we have to recurse */ + nodeFlags = theGlobals->catalogInfo.nodeFlags; + + /* is it a file or directory? */ + if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) ) + { + /* it's a directory -- delete its contents before attempting to delete it */ + FSDeleteContainerLevel(&itemToDelete, theGlobals); + } + /* are we still OK to delete? */ + if ( noErr == theGlobals->result ) + { + /* is item locked? */ + if ( 0 != (nodeFlags & kFSNodeLockedMask) ) + { + /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ + theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo); + } + /* delete the item */ + theGlobals->result = FSDeleteObject(&itemToDelete); + } + } + } while ( noErr == theGlobals->result ); + + /* we found the end of the items normally, so return noErr */ + if ( errFSNoMoreItems == theGlobals->result ) + { + theGlobals->result = noErr; + } + + /* close the FSIterator (closing an open iterator should never fail) */ + verify_noerr(FSCloseIterator(iterator)); + +FSOpenIterator: + + return; +} + +/*****************************************************************************/ + +OSErr +FSDeleteContainerContents( + const FSRef *container) +{ + FSDeleteContainerGlobals theGlobals; + + /* delete container's contents */ + FSDeleteContainerLevel(container, &theGlobals); + + return ( theGlobals.result ); +} + +/*****************************************************************************/ + +OSErr +FSDeleteContainer( + const FSRef *container) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* get nodeFlags for container */ + result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL); + require_noerr(result, FSGetCatalogInfo); + + /* make sure container is a directory */ + require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr); + + /* delete container's contents */ + result = FSDeleteContainerContents(container); + require_noerr(result, FSDeleteContainerContents); + + /* is container locked? */ + if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) + { + /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ + catalogInfo.nodeFlags &= ~kFSNodeLockedMask; + (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo); + } + + /* delete the container */ + result = FSDeleteObject(container); + +FSDeleteContainerContents: +ContainerNotDirectory: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The FSIterateContainerLevel function iterates the contents of a container + directory and calls a IterateContainerFilterProc function once for each + file and directory found. + + theGlobals --> A pointer to a FSIterateContainerGlobals struct + which contains the variables needed globally by + all recusion levels of FSIterateContainerLevel. + That makes FSIterateContainer thread safe since + each call to it uses its own global world. + It also contains the variables that do not need + to be allocated each time FSIterateContainerLevel + recurses. That lets FSIterateContainerLevel use + less stack space per recursion level. +*/ + +static +void +FSIterateContainerLevel( + FSIterateContainerGlobals *theGlobals) +{ + FSIterator iterator; + + /* If maxLevels is zero, we aren't checking levels */ + /* If currentLevel < maxLevels, look at this level */ + if ( (theGlobals->maxLevels == 0) || + (theGlobals->currentLevel < theGlobals->maxLevels) ) + { + /* Open FSIterator for flat access to theGlobals->ref */ + theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator); + require_noerr(theGlobals->result, FSOpenIterator); + + ++theGlobals->currentLevel; /* Go to next level */ + + /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ + do + { + theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, + &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo, + &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr); + if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) && + (0 != theGlobals->actualObjects) ) + { + /* Call the IterateFilterProc */ + theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter, + theGlobals->containerChanged, theGlobals->currentLevel, + &theGlobals->catalogInfo, &theGlobals->ref, + theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr); + /* Is it a directory? */ + if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) ) + { + /* Keep going? */ + if ( !theGlobals->quitFlag ) + { + /* Dive again if the IterateFilterProc didn't say "quit" */ + FSIterateContainerLevel(theGlobals); + } + } + } + /* time to fall back a level? */ + } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) ); + + /* errFSNoMoreItems is OK - it only means we hit the end of this level */ + /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ + if ( (errFSNoMoreItems == theGlobals->result) || + (afpAccessDenied == theGlobals->result) ) + { + theGlobals->result = noErr; + } + + --theGlobals->currentLevel; /* Return to previous level as we leave */ + + /* Close the FSIterator (closing an open iterator should never fail) */ + verify_noerr(FSCloseIterator(iterator)); + } + +FSOpenIterator: + + return; +} + +/*****************************************************************************/ + +OSErr +FSIterateContainer( + const FSRef *container, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + Boolean wantFSSpec, + Boolean wantName, + IterateContainerFilterProcPtr iterateFilter, + void *yourDataPtr) +{ + OSErr result; + FSIterateContainerGlobals theGlobals; + + /* make sure there is an iterateFilter */ + require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr); + + /* + * set up the globals we need to access from the recursive routine + */ + theGlobals.iterateFilter = iterateFilter; + /* we need the node flags no matter what was requested so we can detect files vs. directories */ + theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags; + /* start with input container -- the first OpenIterator will ensure it is a directory */ + theGlobals.ref = *container; + if ( wantFSSpec ) + { + theGlobals.specPtr = &theGlobals.spec; + } + else + { + theGlobals.specPtr = NULL; + } + if ( wantName ) + { + theGlobals.namePtr = &theGlobals.name; + } + else + { + theGlobals.namePtr = NULL; + } + theGlobals.yourDataPtr = yourDataPtr; + theGlobals.maxLevels = maxLevels; + theGlobals.currentLevel = 0; + theGlobals.quitFlag = false; + theGlobals.containerChanged = false; + theGlobals.result = noErr; + theGlobals.actualObjects = 0; + + /* here we go into recursion land... */ + FSIterateContainerLevel(&theGlobals); + result = theGlobals.result; + require_noerr(result, FSIterateContainerLevel); + +FSIterateContainerLevel: +NoIterateFilter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetDirectoryItems( + const FSRef *container, + FSRef ***refsHandle, /* pointer to handle of FSRefs */ + ItemCount *numRefs, + Boolean *containerChanged) +{ + /* Grab items 10 at a time. */ + enum { kMaxItemsPerBulkCall = 10 }; + + OSErr result; + OSErr memResult; + FSIterator iterator; + FSRef refs[kMaxItemsPerBulkCall]; + ItemCount actualObjects; + Boolean changed; + + /* check parameters */ + require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged), + BadParameter, result = paramErr); + + *numRefs = 0; + *containerChanged = false; + *refsHandle = (FSRef **)NewHandle(0); + require_action(NULL != *refsHandle, NewHandle, result = memFullErr); + + /* open an FSIterator */ + result = FSOpenIterator(container, kFSIterateFlat, &iterator); + require_noerr(result, FSOpenIterator); + + /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ + do + { + result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects, + &changed, kFSCatInfoNone, NULL, refs, NULL, NULL); + + /* if the container changed, set containerChanged for output, but keep going */ + if ( changed ) + { + *containerChanged = changed; + } + + /* any result other than noErr and errFSNoMoreItems is serious */ + require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk); + + /* add objects to output array and count */ + if ( 0 != actualObjects ) + { + /* concatenate the FSRefs to the end of the handle */ + PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef)); + memResult = MemError(); + require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); + + *numRefs += actualObjects; + } + } while ( noErr == result ); + + verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */ + + return ( noErr ); + + /**********************/ + +MemoryAllocationFailed: +FSGetCatalogInfoBulk: + + /* close the iterator */ + verify_noerr(FSCloseIterator(iterator)); + +FSOpenIterator: + /* dispose of handle if already allocated and clear the outputs */ + if ( NULL != *refsHandle ) + { + DisposeHandle((Handle)*refsHandle); + *refsHandle = NULL; + } + *numRefs = 0; + +NewHandle: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +/* + The GenerateUniqueName function generates a HFSUniStr255 name that is + unique in both dir1 and dir2. + + startSeed --> A pointer to a long which is used to generate the + unique name. + <-- It is modified on output to a value which should + be used to generate the next unique name. + dir1 --> The first directory. + dir2 --> The second directory. + uniqueName <-- A pointer to a HFSUniStr255 where the unique name + is to be returned. +*/ + +static +OSErr +GenerateUniqueHFSUniStr( + long *startSeed, + const FSRef *dir1, + const FSRef *dir2, + HFSUniStr255 *uniqueName) +{ + OSErr result; + long i; + FSRefParam pb; + FSRef newRef; + unsigned char hexStr[17] = "0123456789ABCDEF"; + + /* set up the parameter block */ + pb.name = uniqueName->unicode; + pb.nameLength = 8; /* always 8 characters */ + pb.textEncodingHint = kTextEncodingUnknown; + pb.newRef = &newRef; + + /* loop until we get fnfErr with a filename in both directories */ + result = noErr; + while ( fnfErr != result ) + { + /* convert startSeed to 8 character Unicode string */ + uniqueName->length = 8; + for ( i = 0; i < 8; ++i ) + { + uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)]; + } + + /* try in dir1 */ + pb.ref = dir1; + result = PBMakeFSRefUnicodeSync(&pb); + if ( fnfErr == result ) + { + /* try in dir2 */ + pb.ref = dir2; + result = PBMakeFSRefUnicodeSync(&pb); + if ( fnfErr != result ) + { + /* exit if anything other than noErr or fnfErr */ + require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed); + } + } + else + { + /* exit if anything other than noErr or fnfErr */ + require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed); + } + + /* increment seed for next pass through loop, */ + /* or for next call to GenerateUniqueHFSUniStr */ + ++(*startSeed); + } + + /* we have a unique file name which doesn't exist in dir1 or dir2 */ + result = noErr; + +Dir2PBMakeFSRefUnicodeSyncFailed: +Dir1PBMakeFSRefUnicodeSyncFailed: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSExchangeObjectsCompat( + const FSRef *sourceRef, + const FSRef *destRef, + FSRef *newSourceRef, + FSRef *newDestRef) +{ + enum + { + /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */ + kGetCatInformationMask = (kFSCatInfoSettableInfo | + kFSCatInfoVolume | + kFSCatInfoParentDirID) & + ~(kFSCatInfoContentMod | kFSCatInfoAttrMod), + /* set everything possible except for mod dates */ + kSetCatinformationMask = kFSCatInfoSettableInfo & + ~(kFSCatInfoContentMod | kFSCatInfoAttrMod) + }; + + OSErr result; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */ + FSCatalogInfo destCatalogInfo; /* destination file's catalog information */ + HFSUniStr255 sourceName; /* source file's Unicode name */ + HFSUniStr255 destName; /* destination file's Unicode name */ + FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */ + FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */ + FSRef sourceParentRef; /* FSRef to parent directory of source file */ + FSRef destParentRef; /* FSRef to parent directory of destination file */ + HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */ + HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */ + long theSeed; /* the seed for generating unique names */ + Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */ + + /* check parameters */ + require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr); + + /* output refs and current refs = input refs to start with */ + BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef)); + BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef)); + + BlockMoveData(destRef, newDestRef, sizeof(FSRef)); + BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef)); + + /* get source volume's vRefNum */ + result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL); + require_noerr(result, DetermineSourceVRefNumFailed); + + /* see if that volume supports FSExchangeObjects */ + result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) ) + { + /* yes - use FSExchangeObjects */ + result = FSExchangeObjects(sourceRef, destRef); + } + else + { + /* no - emulate FSExchangeObjects */ + + /* Note: The compatibility case won't work for files with *Btree control blocks. */ + /* Right now the only *Btree files are created by the system. */ + + /* get all catalog information and Unicode names for each file */ + result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef); + require_noerr(result, SourceFSGetCatalogInfoFailed); + + result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef); + require_noerr(result, DestFSGetCatalogInfoFailed); + + /* make sure source and destination are on same volume */ + require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* make sure both files are *really* files */ + require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) && + (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr); + + /* generate 2 names that are unique in both directories */ + theSeed = 0x4a696d4c; /* a fine unlikely filename */ + + result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName); + require_noerr(result, GenerateUniqueHFSUniStr1Failed); + + result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName); + require_noerr(result, GenerateUniqueHFSUniStr2Failed); + + /* rename sourceCurrentRef to sourceUniqueName */ + result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef); + require_noerr(result, FSRenameUnicode1Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* rename destCurrentRef to destUniqueName */ + result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef); + require_noerr(result, FSRenameUnicode2Failed); + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + + /* are the source and destination parent directories the same? */ + sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID ); + if ( !sameParentDirs ) + { + /* move source file to dest parent directory */ + result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef); + require_noerr(result, FSMoveObject1Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* move dest file to source parent directory */ + result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef); + require_noerr(result, FSMoveObject2Failed); + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + } + + /* At this point, the files are in their new locations (if they were moved). */ + /* The source file is named sourceUniqueName and is in the directory referred to */ + /* by destParentRef. The destination file is named destUniqueName and is in the */ + /* directory referred to by sourceParentRef. */ + + /* give source file the dest file's catalog information except for mod dates */ + result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo); + require_noerr(result, FSSetCatalogInfo1Failed); + + /* give dest file the source file's catalog information except for mod dates */ + result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo); + require_noerr(result, FSSetCatalogInfo2Failed); + + /* rename source file with dest file's name */ + result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef); + require_noerr(result, FSRenameUnicode3Failed); + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + + /* rename dest file with source file's name */ + result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef); + require_noerr(result, FSRenameUnicode4Failed); + + /* we're done with no errors, so swap newSourceRef and newDestRef */ + BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef)); + BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef)); + } + + return ( result ); + + /**********************/ + +/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */ +/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */ +/* state and location they ended up in so that both files can be found by the calling code. */ + +FSRenameUnicode4Failed: + + /* attempt to rename source file to sourceUniqueName */ + if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) ) + { + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + } + +FSRenameUnicode3Failed: + + /* attempt to restore dest file's catalog information */ + verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo)); + +FSSetCatalogInfo2Failed: + + /* attempt to restore source file's catalog information */ + verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo)); + +FSSetCatalogInfo1Failed: + + if ( !sameParentDirs ) + { + /* attempt to move dest file back to dest directory */ + if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) ) + { + BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); + } + } + +FSMoveObject2Failed: + + if ( !sameParentDirs ) + { + /* attempt to move source file back to source directory */ + if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) ) + { + BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); + } + } + +FSMoveObject1Failed: + + /* attempt to rename dest file to original name */ + verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef)); + +FSRenameUnicode2Failed: + + /* attempt to rename source file to original name */ + verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef)); + +FSRenameUnicode1Failed: +GenerateUniqueHFSUniStr2Failed: +GenerateUniqueHFSUniStr1Failed: +NotAFile: +NotSameVolume: +DestFSGetCatalogInfoFailed: +SourceFSGetCatalogInfoFailed: +DetermineSourceVRefNumFailed: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Shared Environment Routines ----- + +/*****************************************************************************/ + +/* Renamed from FSLockRange to MFX_FSLockRange to avoid a conflict with + * the FSLockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSLockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart) +{ + OSErr result; + ParamBlockRec pb; + + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioReqCount = rangeLength; + pb.ioParam.ioPosMode = fsFromStart; + pb.ioParam.ioPosOffset = rangeStart; + result = PBLockRangeSync(&pb); + require_noerr(result, PBLockRangeSync); + +PBLockRangeSync: + + return ( result ); +} + +/*****************************************************************************/ + +/* Renamed from FSUnlockRange to MFX_FSUnlockRange to avoid a conflict with + * the FSUnlockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSUnlockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart) +{ + OSErr result; + ParamBlockRec pb; + + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioReqCount = rangeLength; + pb.ioParam.ioPosMode = fsFromStart; + pb.ioParam.ioPosOffset = rangeStart; + result = PBUnlockRangeSync(&pb); + require_noerr(result, PBUnlockRangeSync); + +PBUnlockRangeSync: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetDirAccess( + const FSRef *ref, + SInt32 *ownerID, /* can be NULL */ + SInt32 *groupID, /* can be NULL */ + SInt32 *accessRights) /* can be NULL */ +{ + OSErr result; + FSSpec spec; + HParamBlockRec pb; + + /* get FSSpec from FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* get directory access info for FSSpec */ + pb.accessParam.ioNamePtr = (StringPtr)spec.name; + pb.accessParam.ioVRefNum = spec.vRefNum; + pb.fileParam.ioDirID = spec.parID; + result = PBHGetDirAccessSync(&pb); + require_noerr(result, PBHGetDirAccessSync); + + /* return the IDs and access rights */ + if ( NULL != ownerID ) + { + *ownerID = pb.accessParam.ioACOwnerID; + } + if ( NULL != groupID ) + { + *groupID = pb.accessParam.ioACGroupID; + } + if ( NULL != accessRights ) + { + *accessRights = pb.accessParam.ioACAccess; + } + +PBHGetDirAccessSync: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSSetDirAccess( + const FSRef *ref, + SInt32 ownerID, + SInt32 groupID, + SInt32 accessRights) +{ + OSErr result; + FSSpec spec; + HParamBlockRec pb; + + enum + { + /* Just the bits that can be set */ + kSetDirAccessSettableMask = (kioACAccessBlankAccessMask + + kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask + + kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask + + kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask) + }; + + /* get FSSpec from FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* set directory access info for FSSpec */ + pb.accessParam.ioNamePtr = (StringPtr)spec.name; + pb.accessParam.ioVRefNum = spec.vRefNum; + pb.fileParam.ioDirID = spec.parID; + pb.accessParam.ioACOwnerID = ownerID; + pb.accessParam.ioACGroupID = groupID; + pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask; + result = PBHSetDirAccessSync(&pb); + require_noerr(result, PBHSetDirAccessSync); + +PBHSetDirAccessSync: +FSGetCatalogInfo: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolMountInfoSize( + FSVolumeRefNum volRefNum, + SInt16 *size) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != size, BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)size; + result = PBGetVolMountInfoSize(&pb); + require_noerr(result, PBGetVolMountInfoSize); + +PBGetVolMountInfoSize: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSGetVolMountInfo( + FSVolumeRefNum volRefNum, + void *volMountInfo) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != volMountInfo, BadParameter, result = paramErr); + + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr)volMountInfo; + result = PBGetVolMountInfo(&pb); + require_noerr(result, PBGetVolMountInfo); + +PBGetVolMountInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +// This function exists in Mac OS X 10.5, we cannot re-define it here. +// We don't use this function, so just don't compile it. +#if 0 +OSErr +FSVolumeMount( + const void *volMountInfo, + FSVolumeRefNum *volRefNum) +{ + OSErr result; + ParamBlockRec pb; + + /* check parameters */ + require_action(NULL != volRefNum, BadParameter, result = paramErr); + + pb.ioParam.ioBuffer = (Ptr)volMountInfo; + result = PBVolumeMount(&pb); + require_noerr(result, PBVolumeMount); + + /* return the volume reference number */ + *volRefNum = pb.ioParam.ioVRefNum; + +PBVolumeMount: +BadParameter: + + return ( result ); +} +#endif + +/*****************************************************************************/ + +OSErr +FSMapID( + FSVolumeRefNum volRefNum, + SInt32 ugID, + SInt16 objType, + Str31 name) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action(NULL != name, BadParameter, result = paramErr); + + pb.objParam.ioNamePtr = NULL; + pb.objParam.ioVRefNum = volRefNum; + pb.objParam.ioObjType = objType; + pb.objParam.ioObjNamePtr = name; + pb.objParam.ioObjID = ugID; + result = PBHMapIDSync(&pb); + require_noerr(result, PBHMapIDSync); + +PBHMapIDSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMapName( + FSVolumeRefNum volRefNum, + ConstStr255Param name, + SInt16 objType, + SInt32 *ugID) +{ + OSErr result; + HParamBlockRec pb; + + /* check parameters */ + require_action(NULL != ugID, BadParameter, result = paramErr); + + pb.objParam.ioNamePtr = NULL; + pb.objParam.ioVRefNum = volRefNum; + pb.objParam.ioObjType = objType; + pb.objParam.ioObjNamePtr = (StringPtr)name; + result = PBHMapNameSync(&pb); + require_noerr(result, PBHMapNameSync); + + /* return the user or group ID */ + *ugID = pb.objParam.ioObjID; + +PBHMapNameSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCopyFile( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *copyName, /* can be NULL (no rename during copy) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* can be NULL */ +{ + OSErr result; + FSSpec srcFileSpec; + FSCatalogInfo catalogInfo; + HParamBlockRec pb; + Str31 hfsName; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + + /* get source FSSpec from source FSRef */ + result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); + require_noerr(result, FSGetCatalogInfo_srcFileRef); + + /* Make sure the volume supports CopyFile */ + result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + require_action((noErr == result) && VolHasCopyFile(&volParmsInfo), + NoCopyFileSupport, result = paramErr); + + /* get destination volume reference number and destination directory ID from destination FSRef */ + result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); + + /* tell the server to copy the object */ + pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; + pb.copyParam.ioDirID = srcFileSpec.parID; + pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; + pb.copyParam.ioDstVRefNum = catalogInfo.volume; + pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; + pb.copyParam.ioNewName = NULL; + if ( NULL != copyName ) + { + result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName); + require_noerr(result, UnicodeNameGetHFSName); + + pb.copyParam.ioCopyName = hfsName; + } + else + { + pb.copyParam.ioCopyName = NULL; + } + result = PBHCopyFileSync(&pb); + require_noerr(result, PBHCopyFileSync); + + if ( NULL != newRef ) + { + verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, + pb.copyParam.ioCopyName, newRef)); + } + +PBHCopyFileSync: +UnicodeNameGetHFSName: +FSGetCatalogInfo_dstDirectoryRef: +NoCopyFileSupport: +FSGetCatalogInfo_srcFileRef: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSMoveRename( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *moveName, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef) /* can be NULL */ +{ + OSErr result; + FSSpec srcFileSpec; + FSCatalogInfo catalogInfo; + HParamBlockRec pb; + Str31 hfsName; + GetVolParmsInfoBuffer volParmsInfo; + UInt32 infoSize; + + /* get source FSSpec from source FSRef */ + result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); + require_noerr(result, FSGetCatalogInfo_srcFileRef); + + /* Make sure the volume supports MoveRename */ + result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), + &volParmsInfo, &infoSize); + require_action((noErr == result) && VolHasMoveRename(&volParmsInfo), + NoMoveRenameSupport, result = paramErr); + + /* get destination volume reference number and destination directory ID from destination FSRef */ + result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); + + /* make sure the source and destination are on the same volume */ + require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); + + /* tell the server to move and rename the object */ + pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; + pb.copyParam.ioDirID = srcFileSpec.parID; + pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; + pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; + pb.copyParam.ioNewName = NULL; + if ( NULL != moveName ) + { + result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName); + require_noerr(result, UnicodeNameGetHFSName); + + pb.copyParam.ioCopyName = hfsName; + } + else + { + pb.copyParam.ioCopyName = NULL; + } + result = PBHMoveRenameSync(&pb); + require_noerr(result, PBHMoveRenameSync); + + if ( NULL != newRef ) + { + verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID, + pb.copyParam.ioCopyName, newRef)); + } + +PBHMoveRenameSync: +UnicodeNameGetHFSName: +NotSameVolume: +FSGetCatalogInfo_dstDirectoryRef: +NoMoveRenameSupport: +FSGetCatalogInfo_srcFileRef: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- File ID Routines ----- + +/*****************************************************************************/ + +OSErr +FSResolveFileIDRef( + FSVolumeRefNum volRefNum, + SInt32 fileID, + FSRef *ref) +{ + OSErr result; + FIDParam pb; + Str255 tempStr; + + /* check parameters */ + require_action(NULL != ref, BadParameter, result = paramErr); + + /* resolve the file ID reference */ + tempStr[0] = 0; + pb.ioNamePtr = tempStr; + pb.ioVRefNum = volRefNum; + pb.ioFileID = fileID; + result = PBResolveFileIDRefSync((HParmBlkPtr)&pb); + require_noerr(result, PBResolveFileIDRefSync); + + /* and then make an FSRef to the file */ + result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref); + require_noerr(result, FSMakeFSRef); + +FSMakeFSRef: +PBResolveFileIDRefSync: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSCreateFileIDRef( + const FSRef *ref, + SInt32 *fileID) +{ + OSErr result; + FSSpec spec; + FIDParam pb; + + /* check parameters */ + require_action(NULL != fileID, BadParameter, result = paramErr); + + /* Get an FSSpec from the FSRef */ + result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Create (or get) the file ID reference using the FSSpec */ + pb.ioNamePtr = (StringPtr)spec.name; + pb.ioVRefNum = spec.vRefNum; + pb.ioSrcDirID = spec.parID; + result = PBCreateFileIDRefSync((HParmBlkPtr)&pb); + require((noErr == result) || (fidExists == result) || (afpIDExists == result), + PBCreateFileIDRefSync); + + /* return the file ID reference */ + *fileID = pb.ioFileID; + +PBCreateFileIDRefSync: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +#pragma mark ----- Utility Routines ----- + +/*****************************************************************************/ + +Ptr +GetTempBuffer( + ByteCount buffReqSize, + ByteCount *buffActSize) +{ + enum + { + kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */ + }; + + Ptr tempPtr; + + /* check parameters */ + require_action(NULL != buffActSize, BadParameter, tempPtr = NULL); + + /* Make request a multiple of 4K bytes */ + buffReqSize = buffReqSize & 0xfffff000; + + if ( buffReqSize < 0x00001000 ) + { + /* Request was smaller than 4K bytes - make it 4K */ + buffReqSize = 0x00001000; + } + + /* Attempt to allocate the memory */ + tempPtr = NewPtr(buffReqSize); + + /* If request failed, go to backup plan */ + if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) ) + { + /* + ** Try to get largest 4K byte block available + ** leaving some slop for the toolbox if possible + */ + long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000; + + buffReqSize = MaxBlock() & 0xfffff000; + + if ( buffReqSize > freeMemory ) + { + buffReqSize = freeMemory; + } + + if ( buffReqSize == 0 ) + { + buffReqSize = 0x00001000; + } + + tempPtr = NewPtr(buffReqSize); + } + + /* Return bytes allocated */ + if ( tempPtr != NULL ) + { + *buffActSize = buffReqSize; + } + else + { + *buffActSize = 0; + } + +BadParameter: + + return ( tempPtr ); +} + +/*****************************************************************************/ + +OSErr +FileRefNumGetFSRef( + short refNum, + FSRef *ref) +{ + return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) ); +} + +/*****************************************************************************/ + +OSErr +FSSetDefault( + const FSRef *newDefault, + FSRef *oldDefault) +{ + OSErr result; + FSVolumeRefNum vRefNum; + long dirID; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr); + + /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */ + result = FSGetCatalogInfo(newDefault, + kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Make sure newDefault is a directory */ + require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory, + result = dirNFErr); + + /* Get the current working directory. */ + result = HGetVol(NULL, &vRefNum, &dirID); + require_noerr(result, HGetVol); + + /* Return the oldDefault FSRef */ + result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault); + require_noerr(result, FSMakeFSRef); + + /* Set the new current working directory */ + result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); + require_noerr(result, HSetVol); + +HSetVol: +FSMakeFSRef: +HGetVol: +NewDefaultNotDirectory: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ + +OSErr +FSRestoreDefault( + const FSRef *oldDefault) +{ + OSErr result; + FSCatalogInfo catalogInfo; + + /* check parameters */ + require_action(NULL != oldDefault, BadParameter, result = paramErr); + + /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */ + result = FSGetCatalogInfo(oldDefault, + kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, + &catalogInfo, NULL, NULL, NULL); + require_noerr(result, FSGetCatalogInfo); + + /* Make sure oldDefault is a directory */ + require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory, + result = dirNFErr); + + /* Set the current working directory to oldDefault */ + result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); + require_noerr(result, HSetVol); + +HSetVol: +OldDefaultNotDirectory: +FSGetCatalogInfo: +BadParameter: + + return ( result ); +} + +/*****************************************************************************/ diff --git a/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h new file mode 100644 index 00000000..378e4552 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.h @@ -0,0 +1,1800 @@ +/* + File: MoreFilesX.h + + Contains: A collection of useful high-level File Manager routines + which use the HFS Plus APIs wherever possible. + + Version: MoreFilesX 1.0.1 + + +*/ + +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// Modified 2006-01-23 - added this comment. + +#ifndef __MOREFILESX__ +#define __MOREFILESX__ + +#ifndef __CARBON__ + #if defined(__MACH__) + #include + #else + #include + #endif +#endif + +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if PRAGMA_IMPORT +#pragma import on +#endif + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=mac68k +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(push, 2) +#elif PRAGMA_STRUCT_PACK + #pragma pack(2) +#endif + +/*****************************************************************************/ + +#pragma mark ----- FinderInfo and ExtendedFinderInfo ----- + +/* + * FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information. + */ + +union FinderInfo +{ + FileInfo file; + FolderInfo folder; +}; +typedef union FinderInfo FinderInfo; + +union ExtendedFinderInfo +{ + ExtendedFileInfo file; + ExtendedFolderInfo folder; +}; +typedef union ExtendedFinderInfo ExtendedFinderInfo; + +/*****************************************************************************/ + +#pragma mark ----- GetVolParmsInfoBuffer Macros ----- + +/* + * Macros to get information out of GetVolParmsInfoBuffer. + */ + +/* version 1 field getters */ +#define GetVolParmsInfoVersion(volParms) \ + ((volParms)->vMVersion) +#define GetVolParmsInfoAttrib(volParms) \ + ((volParms)->vMAttrib) +#define GetVolParmsInfoLocalHand(volParms) \ + ((volParms)->vMLocalHand) +#define GetVolParmsInfoServerAdr(volParms) \ + ((volParms)->vMServerAdr) + +/* version 2 field getters (assume zero result if version < 2) */ +#define GetVolParmsInfoVolumeGrade(volParms) \ + (((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0) +#define GetVolParmsInfoForeignPrivID(volParms) \ + (((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0) + +/* version 3 field getters (assume zero result if version < 3) */ +#define GetVolParmsInfoExtendedAttributes(volParms) \ + (((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0) + +/* attribute bits supported by all versions of GetVolParmsInfoBuffer */ +#define VolIsNetworkVolume(volParms) \ + ((volParms)->vMServerAdr != 0) +#define VolHasLimitFCBs(volParms) \ + (((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0) +#define VolHasLocalWList(volParms) \ + (((volParms)->vMAttrib & (1L << bLocalWList)) != 0) +#define VolHasNoMiniFndr(volParms) \ + (((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0) +#define VolHasNoVNEdit(volParms) \ + (((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0) +#define VolHasNoLclSync(volParms) \ + (((volParms)->vMAttrib & (1L << bNoLclSync)) != 0) +#define VolHasTrshOffLine(volParms) \ + (((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0) +#define VolHasNoSwitchTo(volParms) \ + (((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0) +#define VolHasNoDeskItems(volParms) \ + (((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0) +#define VolHasNoBootBlks(volParms) \ + (((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0) +#define VolHasAccessCntl(volParms) \ + (((volParms)->vMAttrib & (1L << bAccessCntl)) != 0) +#define VolHasNoSysDir(volParms) \ + (((volParms)->vMAttrib & (1L << bNoSysDir)) != 0) +#define VolHasExtFSVol(volParms) \ + (((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0) +#define VolHasOpenDeny(volParms) \ + (((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0) +#define VolHasCopyFile(volParms) \ + (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0) +#define VolHasMoveRename(volParms) \ + (((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0) +#define VolHasDesktopMgr(volParms) \ + (((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0) +#define VolHasShortName(volParms) \ + (((volParms)->vMAttrib & (1L << bHasShortName)) != 0) +#define VolHasFolderLock(volParms) \ + (((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0) +#define VolHasPersonalAccessPrivileges(volParms) \ + (((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0) +#define VolHasUserGroupList(volParms) \ + (((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0) +#define VolHasCatSearch(volParms) \ + (((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0) +#define VolHasFileIDs(volParms) \ + (((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0) +#define VolHasBTreeMgr(volParms) \ + (((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0) +#define VolHasBlankAccessPrivileges(volParms) \ + (((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0) +#define VolSupportsAsyncRequests(volParms) \ + (((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0) +#define VolSupportsTrashVolumeCache(volParms) \ + (((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0) + +/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ +#define VolIsEjectable(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0) +#define VolSupportsHFSPlusAPIs(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0) +#define VolSupportsFSCatalogSearch(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0) +#define VolSupportsFSExchangeObjects(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0) +#define VolSupports2TBFiles(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0) +#define VolSupportsLongNames(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0) +#define VolSupportsMultiScriptNames(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0) +#define VolSupportsNamedForks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0) +#define VolSupportsSubtreeIterators(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0) +#define VolL2PCanMapFileBlocks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0) +#define VolParentModDateChanges(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0) +#define VolAncestorModDateChanges(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0) +#define VolSupportsSymbolicLinks(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0) +#define VolIsAutoMounted(volParms) \ + ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0) + +/*****************************************************************************/ + +#pragma mark ----- userPrivileges Bit Masks and Macros ----- + +/* + * Bit masks and macros to get common information out of userPrivileges byte + * returned by FSGetCatalogInfo. + * + * Note: The userPrivileges byte is the same as the ioACUser byte returned + * by PBGetCatInfo, and is the 1's complement of the user's privileges + * byte returned in ioACAccess by PBHGetDirAccess. That's where the + * ioACUser names came from. + * + * The userPrivileges are user's effective privileges based on the + * user ID and the groups that user belongs to, and the owner, group, + * and everyone privileges for the given directory. + */ + +enum +{ + /* mask for just the access restriction bits */ + kioACUserAccessMask = (kioACUserNoSeeFolderMask + + kioACUserNoSeeFilesMask + + kioACUserNoMakeChangesMask), + /* common access privilege settings */ + kioACUserFull = 0x00, /* no access restiction bits on */ + kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */ + kioACUserDropBox = (kioACUserNoSeeFolderMask + + kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */ + kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */ +}; + + +/* Macros for testing ioACUser bits. */ + +#define UserIsOwner(userPrivileges) \ + (((userPrivileges) & kioACUserNotOwnerMask) == 0) +#define UserHasFullAccess(userPrivileges) \ + (((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull) +#define UserHasDropBoxAccess(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox) +#define UserHasBulletinBoard(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard) +#define UserHasNoAccess(userPrivileges) \ + (((userPrivileges) & kioACUserAccessMask) == kioACUserNone) + +/*****************************************************************************/ + +#pragma mark ----- File Access Routines ----- + +/*****************************************************************************/ + +#pragma mark FSCopyFork + +OSErr +FSCopyFork( + SInt16 srcRefNum, + SInt16 dstRefNum, + void *copyBufferPtr, + ByteCount copyBufferSize); + +/* + The FSCopyFork function copies all data from the source fork to the + destination fork of open file forks and makes sure the destination EOF + is equal to the source EOF. + + srcRefNum --> The source file reference number. + dstRefNum --> The destination file reference number. + copyBufferPtr --> Pointer to buffer to use during copy. The + buffer should be at least 4K-bytes minimum. + The larger the buffer, the faster the copy + (up to a point). + copyBufferSize --> The size of the copy buffer. +*/ + +/*****************************************************************************/ + +#pragma mark ----- Volume Access Routines ----- + +/*****************************************************************************/ + +#pragma mark FSGetVolParms + +OSErr +FSGetVolParms( + FSVolumeRefNum volRefNum, + UInt32 bufferSize, + GetVolParmsInfoBuffer *volParmsInfo, + UInt32 *actualInfoSize); + +/* + The FSGetVolParms function returns information about the characteristics + of a volume. A result of paramErr usually just means the volume doesn't + support GetVolParms and the feature you were going to check + for isn't available. + + volRefNum --> Volume specification. + bufferSize --> Size of buffer pointed to by volParmsInfo. + volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume + attributes information is returned. + actualInfoSize <-- The number of bytes actually returned + in volParmsInfo. + + __________ + + Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits + in this file +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVRefNum + +OSErr +FSGetVRefNum( + const FSRef *ref, + FSVolumeRefNum *vRefNum); + +/* + The FSGetVRefNum function determines the volume reference + number of a volume from a FSRef. + + ref --> The FSRef. + vRefNum <-- The volume reference number. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVInfo + +OSErr +FSGetVInfo( + FSVolumeRefNum volume, + HFSUniStr255 *volumeName, /* can be NULL */ + UInt64 *freeBytes, /* can be NULL */ + UInt64 *totalBytes); /* can be NULL */ + +/* + The FSGetVInfo function returns the name, available space (in bytes), + and total space (in bytes) for the specified volume. + + volume --> The volume reference number. + volumeName <** An optional pointer to a HFSUniStr255. + If not NULL, the volume name will be returned in + the HFSUniStr255. + freeBytes <** An optional pointer to a UInt64. + If not NULL, the number of free bytes on the + volume will be returned in the UInt64. + totalBytes <** An optional pointer to a UInt64. + If not NULL, the total number of bytes on the + volume will be returned in the UInt64. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolFileSystemID + +OSErr +FSGetVolFileSystemID( + FSVolumeRefNum volume, + UInt16 *fileSystemID, /* can be NULL */ + UInt16 *signature); /* can be NULL */ + +/* + The FSGetVolFileSystemID function returns the file system ID and signature + of a mounted volume. The file system ID identifies the file system + that handles requests to a particular volume. The signature identifies the + volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS + or MFS, where a signature of 0x4244 identifies the volume as HFS). + Here's a partial list of file system ID numbers (only Apple's file systems + are listed): + FSID File System + ----- ----------------------------------------------------- + $0000 Macintosh HFS Plus, HFS or MFS + $0100 ProDOS File System + $0101 PowerTalk Mail Enclosures + $4147 ISO 9660 File Access (through Foreign File Access) + $4242 High Sierra File Access (through Foreign File Access) + $464D QuickTake File System (through Foreign File Access) + $4953 Macintosh PC Exchange (MS-DOS) + $4A48 Audio CD Access (through Foreign File Access) + $4D4B Apple Photo Access (through Foreign File Access) + $6173 AppleShare (later versions of AppleShare only) + + See the Technical Note "FL 35 - Determining Which File System + Is Active" and the "Guide to the File System Manager" for more + information. + + volume --> The volume reference number. + fileSystemID <** An optional pointer to a UInt16. + If not NULL, the volume's file system ID will + be returned in the UInt16. + signature <** An optional pointer to a UInt16. + If not NULL, the volume's signature will + be returned in the UInt16. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetMountedVolumes + +OSErr +FSGetMountedVolumes( + FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ + ItemCount *numVolumes); + +/* + The FSGetMountedVolumes function returns the list of volumes currently + mounted in an array of FSRef records. The array of FSRef records is + returned in a Handle, volumeRefsHandle, which is allocated by + FSGetMountedVolumes. The caller is responsible for disposing of + volumeRefsHandle if the FSGetMountedVolumes returns noErr. + + volumeRefsHandle <-- Pointer to an FSRef Handle where the array of + FSRefs is to be returned. + numVolumes <-- The number of volumes returned in the array. +*/ + +/*****************************************************************************/ + +#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- + +/*****************************************************************************/ + +#pragma mark FSRefMakeFSSpec + +OSErr +FSRefMakeFSSpec( + const FSRef *ref, + FSSpec *spec); + +/* + The FSRefMakeFSSpec function returns an FSSpec for the file or + directory specified by the ref parameter. + + ref --> An FSRef specifying the file or directory. + spec <-- The FSSpec. +*/ + +/*****************************************************************************/ + +#pragma mark FSMakeFSRef + +OSErr +FSMakeFSRef( + FSVolumeRefNum volRefNum, + SInt32 dirID, + ConstStr255Param name, + FSRef *ref); + +/* + The FSMakeFSRef function creates an FSRef from the traditional + volume reference number, directory ID and pathname inputs. It is + functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef. + + volRefNum --> Volume specification. + dirID --> Directory specification. + name --> The file or directory name, or NULL. + ref <-- The FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSMakePath + +OSStatus +FSMakePath( + SInt16 vRefNum, + SInt32 dirID, + ConstStr255Param name, + UInt8 *path, + UInt32 maxPathSize); + +/* + The FSMakePath function creates a pathname from the traditional volume reference + number, directory ID, and pathname inputs. It is functionally equivalent to + FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath. + + volRefNum --> Volume specification. + dirID --> Directory specification. + name --> The file or directory name, or NULL. + path <-- A pointer to a buffer which FSMakePath will + fill with a C string representing the pathname + to the file or directory specified. The format of + the pathname returned can be determined with the + Gestalt selector gestaltFSAttr's + gestaltFSUsesPOSIXPathsForConversion bit. + If the gestaltFSUsesPOSIXPathsForConversion bit is + clear, the pathname is a Mac OS File Manager full + pathname in a C string, and file or directory names + in the pathname may be mangled as returned by + the File Manager. If the + gestaltFSUsesPOSIXPathsForConversion bit is set, + the pathname is a UTF8 encoded POSIX absolute + pathname in a C string. In either case, the + pathname returned can be passed back to + FSPathMakeRef to create an FSRef to the file or + directory, or FSPathMakeFSSpec to craete an FSSpec + to the file or directory. + maxPathSize --> The size of the path buffer in bytes. If the path + buffer is too small for the pathname string, + FSMakePath returns pathTooLongErr or + buffersTooSmall. +*/ + +/*****************************************************************************/ + +#pragma mark FSPathMakeFSSpec + +OSStatus +FSPathMakeFSSpec( + const UInt8 *path, + FSSpec *spec, + Boolean *isDirectory); /* can be NULL */ + +/* + The FSPathMakeFSSpec function converts a pathname to an FSSpec. + + path --> A pointer to a C String that is the pathname. The + format of the pathname you must supply can be + determined with the Gestalt selector gestaltFSAttr's + gestaltFSUsesPOSIXPathsForConversion bit. + If the gestaltFSUsesPOSIXPathsForConversion bit is + clear, the pathname must be a Mac OS File Manager + full pathname in a C string. If the + gestaltFSUsesPOSIXPathsForConversion bit is set, + the pathname must be a UTF8 encoded POSIX absolute + pathname in a C string. + spec <-- The FSSpec. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the specified path is a directory, or false will + be returned in the Boolean if the specified path is + a file. +*/ + +/*****************************************************************************/ + +#pragma mark UnicodeNameGetHFSName + +OSErr +UnicodeNameGetHFSName( + UniCharCount nameLength, + const UniChar *name, + TextEncoding textEncodingHint, + Boolean isVolumeName, + Str31 hfsName); + +/* + The UnicodeNameGetHFSName function converts a Unicode string + to a Pascal Str31 (or Str27) string using an algorithm similar to that used + by the File Manager. Note that if the name is too long or cannot be converted + using the given text encoding hint, you will get an error instead of the + mangled name that the File Manager would return. + + nameLength --> Number of UniChar in name parameter. + name --> The Unicode string to convert. + textEncodingHint --> The text encoding hint used for the conversion. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + isVolumeName --> If true, the output name will be limited to + 27 characters (kHFSMaxVolumeNameChars). If false, + the output name will be limited to 31 characters + (kHFSMaxFileNameChars). + hfsName <-- The hfsName as a Pascal string. + + __________ + + Also see: HFSNameGetUnicodeName +*/ + +/*****************************************************************************/ + +#pragma mark HFSNameGetUnicodeName + +OSErr +HFSNameGetUnicodeName( + ConstStr31Param hfsName, + TextEncoding textEncodingHint, + HFSUniStr255 *unicodeName); + +/* + The HFSNameGetUnicodeName function converts a Pascal Str31 string to an + Unicode HFSUniStr255 string using the same routines as the File Manager. + + hfsName --> The Pascal string to convert. + textEncodingHint --> The text encoding hint used for the conversion. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + unicodeName <-- The Unicode string. + + __________ + + Also see: UnicodeNameGetHFSName +*/ + +/*****************************************************************************/ + +#pragma mark ----- File/Directory Manipulation Routines ----- + +/*****************************************************************************/ + +#pragma mark FSRefValid + +Boolean FSRefValid(const FSRef *ref); + +/* + The FSRefValid function determines if an FSRef is valid. If the result is + true, then the FSRef refers to an existing file or directory. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetParentRef + +OSErr +FSGetParentRef( + const FSRef *ref, + FSRef *parentRef); + +/* + The FSGetParentRef function gets the parent directory FSRef of the + specified object. + + Note: FSRefs always point to real file system objects. So, there cannot + be a FSRef to the parent of volume root directories. If you call + FSGetParentRef with a ref to the root directory of a volume, the + function result will be noErr and the parentRef will be invalid (using it + for other file system requests will fail). + + ref --> FSRef to a file or directory. + parentRef <-- The parent directory's FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetFileDirName + +OSErr +FSGetFileDirName( + const FSRef *ref, + HFSUniStr255 *outName); + +/* + The FSGetFileDirName function gets the name of the file or directory + specified. + + ref --> FSRef to a file or directory. + outName <-- The file or directory name. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetNodeID + +OSErr +FSGetNodeID( + const FSRef *ref, + long *nodeID, /* can be NULL */ + Boolean *isDirectory); /* can be NULL */ + +/* + The GetNodeIDFromFSRef function gets the node ID number of the + file or directory specified (note: the node ID is the directory ID + for directories). + + ref --> FSRef to a file or directory. + nodeID <** An optional pointer to a long. + If not NULL, the node ID will be returned in + the long. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the object is a directory, or false will be + returned in the Boolean if object is a file. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetUserPrivilegesPermissions + +OSErr +FSGetUserPrivilegesPermissions( + const FSRef *ref, + UInt8 *userPrivileges, /* can be NULL */ + UInt32 permissions[4]); /* can be NULL */ + +/* + The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or + permissions of the file or directory specified. + + ref --> FSRef to a file or directory. + userPrivileges <** An optional pointer to a UInt8. + If not NULL, the userPrivileges will be returned + in the UInt8. + permissions <** An optional pointer to an UInt32[4] array. + If not NULL, the permissions will be returned + in the UInt32[4] array. +*/ + +/*****************************************************************************/ + +#pragma mark FSCheckLock + +OSErr +FSCheckLock( + const FSRef *ref); + +/* + The FSCheckLock function determines if a file or directory is locked. + If FSCheckLock returns noErr, then the file or directory is not locked + and the volume it is on is not locked either. If FSCheckLock returns + fLckdErr, then the file or directory is locked. If FSCheckLock returns + wPrErr, then the volume is locked by hardware (i.e., locked tab on + removable media). If FSCheckLock returns vLckdErr, then the volume is + locked by software. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetForkSizes + +OSErr +FSGetForkSizes( + const FSRef *ref, + UInt64 *dataLogicalSize, /* can be NULL */ + UInt64 *rsrcLogicalSize); /* can be NULL */ + +/* + The FSGetForkSizes returns the size of the data and/or resource fork for + the specified file. + + ref --> FSRef to a file or directory. + dataLogicalSize <** An optional pointer to a UInt64. + If not NULL, the data fork's size will be + returned in the UInt64. + rsrcLogicalSize <** An optional pointer to a UInt64. + If not NULL, the resource fork's size will be + returned in the UInt64. + + __________ + + Also see: FSGetTotalForkSizes +*/ + +/*****************************************************************************/ + +#pragma mark FSGetTotalForkSizes + +OSErr +FSGetTotalForkSizes( + const FSRef *ref, + UInt64 *totalLogicalSize, /* can be NULL */ + UInt64 *totalPhysicalSize, /* can be NULL */ + ItemCount *forkCount); /* can be NULL */ + +/* + The FSGetTotalForkSizes returns the total logical size and/or the total + physical size of the specified file (i.e., it adds the sizes of all file + forks). It optionally returns the number of file forks. + + ref --> FSRef to a file or directory. + totalLogicalSize <** An optional pointer to a UInt64. + If not NULL, the sum of all fork logical sizes + will be returned in the UInt64. + totalPhysicalSize <** An optional pointer to a UInt64. + If not NULL, the sum of all fork physical sizes + will be returned in the UInt64. + forkCount <** An optional pointer to a ItemCount. + If not NULL, the number of file forks + will be returned in the ItemCount. + + __________ + + Also see: FSGetForkSizes +*/ + +/*****************************************************************************/ + +#pragma mark FSBumpDate + +OSErr +FSBumpDate( + const FSRef *ref); + +/* + The FSBumpDate function changes the content modification date of a file + or directory to the current date/time. If the content modification date + is already equal to the current date/time, then add one second to the + content modification date. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetFinderInfo + +OSErr +FSGetFinderInfo( + const FSRef *ref, + FinderInfo *info, /* can be NULL */ + ExtendedFinderInfo *extendedInfo, /* can be NULL */ + Boolean *isDirectory); /* can be NULL */ + +/* + The FSGetFinderInfo function gets the finder information for a file or + directory. + + ref --> FSRef to a file or directory. + info <** An optional pointer to a FinderInfo. + If not NULL, the FileInfo (if ref is a file) or + the FolderInfo (if ref is a folder) will be + returned in the FinderInfo. + extendedInfo <** An optional pointer to a ExtendedFinderInfo. + If not NULL, the ExtendedFileInfo (if ref is a file) + or the ExtendedFolderInfo (if ref is a folder) will + be returned in the ExtendedFinderInfo. + isDirectory <** An optional pointer to a Boolean. + If not NULL, true will be returned in the Boolean + if the object is a directory, or false will be + returned in the Boolean if object is a file. + + __________ + + Also see: FSSetFinderInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSSetFinderInfo + +OSErr +FSSetFinderInfo( + const FSRef *ref, + const FinderInfo *info, /* can be NULL */ + const ExtendedFinderInfo *extendedInfo); /* can be NULL */ + +/* + The FSSetFinderInfo function sets the finder information for a file or + directory. + + ref --> FSRef to a file or directory. + info **> A pointer to a FinderInfo record with the new + FileInfo (if ref is a file) or new FolderInfo + (if ref is a folder), or NULL if the FinderInfo + is not to be changed. + extendedInfo **> A pointer to a FinderInfo record with the new + ExtendedFileInfo (if ref is a file) or new + ExtendedFolderInfo (if ref is a folder), or NULL + if the ExtendedFinderInfo is not to be changed. + + __________ + + Also see: FSGetFinderInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSChangeCreatorType + +OSErr +FSChangeCreatorType( + const FSRef *ref, + OSType fileCreator, + OSType fileType); + +/* + The FSChangeCreatorType function changes the creator and/or file type of a file. + + ref --> FSRef to a file. + creator --> The new creator type or 0x00000000 to leave + the creator type alone. + fileType --> The new file type or 0x00000000 to leave the + file type alone. +*/ + +/*****************************************************************************/ + +#pragma mark FSChangeFinderFlags + +OSErr +FSChangeFinderFlags( + const FSRef *ref, + Boolean setBits, + UInt16 flagBits); + +/* + The FSChangeFinderFlags function sets or clears flag bits in + the finderFlags field of a file's FileInfo record or a + directory's FolderInfo record. + + ref --> FSRef to a file or directory. + setBits --> If true, then set the bits specified in flagBits. + If false, then clear the bits specified in flagBits. + flagBits --> The flagBits parameter specifies which Finder Flag + bits to set or clear. If a bit in flagBits is set, + then the same bit in fdFlags is either set or + cleared depending on the state of the setBits + parameter. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetInvisible + +OSErr +FSSetInvisible( + const FSRef *ref); + +#pragma mark FSClearInvisible + +OSErr +FSClearInvisible( + const FSRef *ref); + +/* + The FSSetInvisible and FSClearInvisible functions set or clear the + kIsInvisible bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetNameLocked + +OSErr +FSSetNameLocked( + const FSRef *ref); + +#pragma mark FSClearNameLocked + +OSErr +FSClearNameLocked( + const FSRef *ref); + +/* + The FSSetNameLocked and FSClearNameLocked functions set or clear the + kNameLocked bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetIsStationery + +OSErr +FSSetIsStationery( + const FSRef *ref); + +#pragma mark FSClearIsStationery + +OSErr +FSClearIsStationery( + const FSRef *ref); + +/* + The FSSetIsStationery and FSClearIsStationery functions set or clear the + kIsStationery bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetHasCustomIcon + +OSErr +FSSetHasCustomIcon( + const FSRef *ref); + +#pragma mark FSClearHasCustomIcon + +OSErr +FSClearHasCustomIcon( + const FSRef *ref); + +/* + The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the + kHasCustomIcon bit bit in the finderFlags field of the specified file or + directory's finder information. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSClearHasBeenInited + +OSErr +FSClearHasBeenInited( + const FSRef *ref); + +/* + The FSClearHasBeenInited function clears the kHasBeenInited bit in the + finderFlags field of the specified file or directory's finder information. + + Note: There is no FSSetHasBeenInited function because ONLY the Finder + should set the kHasBeenInited bit. + + ref --> FSRef to a file or directory. +*/ + +/*****************************************************************************/ + +#pragma mark FSCopyFileMgrAttributes + +OSErr +FSCopyFileMgrAttributes( + const FSRef *sourceRef, + const FSRef *destinationRef, + Boolean copyLockBit); + +/* + The CopyFileMgrAttributes function copies all File Manager attributes + from the source file or directory to the destination file or directory. + If copyLockBit is true, then set the locked state of the destination + to match the source. + + sourceRef --> FSRef to a file or directory. + destinationRef --> FSRef to a file or directory. + copyLockBit --> If true, set the locked state of the destination + to match the source. +*/ + +/*****************************************************************************/ + +#pragma mark FSMoveRenameObjectUnicode + +OSErr +FSMoveRenameObjectUnicode( + const FSRef *ref, + const FSRef *destDirectory, + UniCharCount nameLength, + const UniChar *name, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* if function fails along the way, newRef is final location of file */ + +/* + The FSMoveRenameObjectUnicode function moves a file or directory and + optionally renames it. The source and destination locations must be on + the same volume. + + Note: If the input ref parameter is invalid, this call will fail and + newRef, like ref, will be invalid. + + ref --> FSRef to a file or directory. + destDirectory --> FSRef to the destination directory. + nameLength --> Number of UniChar in name parameter. + name --> An Unicode string with the new name for the + moved object, or NULL if no rename is wanted. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <-- The new FSRef of the object moved. Note that if + this function fails at any step along the way, + newRef is still then final location of the object. +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteContainerContents + +OSErr +FSDeleteContainerContents( + const FSRef *container); + +/* + The FSDeleteContainerContents function deletes the contents of a container + directory. All files and subdirectories in the specified container are + deleted. If a locked file or directory is encountered, it is unlocked and + then deleted. If any unexpected errors are encountered, + FSDeleteContainerContents quits and returns to the caller. + + container --> FSRef to a directory. + + __________ + + Also see: FSDeleteContainer +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteContainer + +OSErr +FSDeleteContainer( + const FSRef *container); + +/* + The FSDeleteContainer function deletes a container directory and its contents. + All files and subdirectories in the specified container are deleted. + If a locked file or directory is encountered, it is unlocked and then + deleted. After deleting the container's contents, the container is + deleted. If any unexpected errors are encountered, FSDeleteContainer + quits and returns to the caller. + + container --> FSRef to a directory. + + __________ + + Also see: FSDeleteContainerContents +*/ + +/*****************************************************************************/ + +#pragma mark IterateContainerFilterProcPtr + +typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) ( + Boolean containerChanged, + ItemCount currentLevel, + const FSCatalogInfo *catalogInfo, + const FSRef *ref, + const FSSpec *spec, + const HFSUniStr255 *name, + void *yourDataPtr); + +/* + This is the prototype for the IterateContainerFilterProc function which + is called once for each file and directory found by FSIterateContainer. + The IterateContainerFilterProc can use the read-only data it receives for + whatever it wants. + + The result of the IterateContainerFilterProc function indicates if + iteration should be stopped. To stop iteration, return true; to continue + iteration, return false. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within the IterateContainerFilterProc. + + containerChanged --> Set to true if the container's contents changed + during iteration. + currentLevel --> The current recursion level into the container. + 1 = the container, 2 = the container's immediate + subdirectories, etc. + catalogInfo --> The catalog information for the current object. + Only the fields requested by the whichInfo + parameter passed to FSIterateContainer are valid. + ref --> The FSRef to the current object. + spec --> The FSSpec to the current object if the wantFSSpec + parameter passed to FSIterateContainer is true. + name --> The name of the current object if the wantName + parameter passed to FSIterateContainer is true. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + IterateFilterProc. + result <-- To stop iteration, return true; to continue + iteration, return false. + + __________ + + Also see: FSIterateContainer +*/ + +/*****************************************************************************/ + +#pragma mark CallIterateContainerFilterProc + +#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \ + (*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr)) + +/*****************************************************************************/ + +#pragma mark FSIterateContainer + +OSErr +FSIterateContainer( + const FSRef *container, + ItemCount maxLevels, + FSCatalogInfoBitmap whichInfo, + Boolean wantFSSpec, + Boolean wantName, + IterateContainerFilterProcPtr iterateFilter, + void *yourDataPtr); + +/* + The FSIterateContainer function performs a recursive iteration (scan) of the + specified container directory and calls your IterateContainerFilterProc + function once for each file and directory found. + + The maxLevels parameter lets you control how deep the recursion goes. + If maxLevels is 1, FSIterateContainer only scans the specified directory; + if maxLevels is 2, FSIterateContainer scans the specified directory and + one subdirectory below the specified directory; etc. Set maxLevels to + zero to scan all levels. + + The yourDataPtr parameter can point to whatever data structure you might + want to access from within your IterateContainerFilterProc. + + container --> The FSRef to the container directory to iterate. + maxLevels --> Maximum number of directory levels to scan or + zero to scan all directory levels. + whichInfo --> The fields of the FSCatalogInfo you wish to get. + wantFSSpec --> Set to true if you want the FSSpec to each + object passed to your IterateContainerFilterProc. + wantName --> Set to true if you want the name of each + object passed to your IterateContainerFilterProc. + iterateFilter --> A pointer to the IterateContainerFilterProc you + want called once for each file and directory found + by FSIterateContainer. + yourDataPtr --> An optional pointer to whatever data structure you + might want to access from within the + IterateFilterProc. +*/ + +/*****************************************************************************/ + +#pragma mark FSGetDirectoryItems + +OSErr +FSGetDirectoryItems( + const FSRef *container, + FSRef ***refsHandle, /* pointer to handle of FSRefs */ + ItemCount *numRefs, + Boolean *containerChanged); + +/* + The FSGetDirectoryItems function returns the list of items in the specified + container. The array of FSRef records is returned in a Handle, refsHandle, + which is allocated by FSGetDirectoryItems. The caller is responsible for + disposing of refsHandle if the FSGetDirectoryItems returns noErr. + + container --> FSRef to a directory. + refsHandle <-- Pointer to an FSRef Handle where the array of + FSRefs is to be returned. + numRefs <-- The number of FSRefs returned in the array. + containerChanged <-- Set to true if the container changes while the + list of items is being obtained. +*/ + +/*****************************************************************************/ + +#pragma mark FSExchangeObjectsCompat + +OSErr +FSExchangeObjectsCompat( + const FSRef *sourceRef, + const FSRef *destRef, + FSRef *newSourceRef, + FSRef *newDestRef); + +/* + The FSExchangeObjectsCompat function exchanges the data between two files. + + The FSExchangeObjectsCompat function is an enhanced version of + FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat + provides are: + + 1, FSExchangeObjectsCompat will work on volumes which do not support + FSExchangeObjects. FSExchangeObjectsCompat does this by emulating + FSExchangeObjects through a series of File Manager operations. If + there is a failure at any step along the way, FSExchangeObjectsCompat + attempts to undo any steps already taken to leave the files in their + original state in their original locations. + + 2. FSExchangeObjectsCompat returns new FSRefs to the source and + destination files. Note that if this function fails at any step along + the way, newSourceRef and newDestRef still give you access to the final + locations of the files being exchanged -- even if they are renamed or + not in their original locations. + + sourceRef --> FSRef to the source file. + destRef --> FSRef to the destination file. + newSourceRef <-- The new FSRef to the source file. + newDestRef <-- The new FSRef to the destination file. +*/ + +/*****************************************************************************/ + +#pragma mark ----- Shared Environment Routines ----- + +/*****************************************************************************/ + +#pragma mark MFX_FSLockRange +/* Renamed from FSLockRange to MFX_FSLockRange to avoid a conflict with + * the FSLockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSLockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart); + +/* + The LockRange function locks (denies access to) a portion of a file + that was opened with shared read/write permission. + + refNum --> The file reference number of an open file. + rangeLength --> The number of bytes in the range. + rangeStart --> The starting byte in the range to lock. + + __________ + + Also see: UnlockRange +*/ + +/*****************************************************************************/ + +#pragma mark MFX_FSUnlockRange +/* Renamed from FSUnlockRange to MFX_FSUnlockRange to avoid a conflict with + * the FSUnlockRange function present in the system library since Mac OS X + * 10.4. */ + +OSErr +MFX_FSUnlockRange( + SInt16 refNum, + SInt32 rangeLength, + SInt32 rangeStart); + +/* + The UnlockRange function unlocks (allows access to) a previously locked + portion of a file that was opened with shared read/write permission. + + refNum --> The file reference number of an open file. + rangeLength --> The number of bytes in the range. + rangeStart --> The starting byte in the range to unlock. + + __________ + + Also see: LockRange +*/ + +/*****************************************************************************/ + +#pragma mark FSGetDirAccess + +OSErr +FSGetDirAccess( + const FSRef *ref, + SInt32 *ownerID, /* can be NULL */ + SInt32 *groupID, /* can be NULL */ + SInt32 *accessRights); /* can be NULL */ + +/* + The FSGetDirAccess function retrieves the directory access control + information for a directory on a shared volume. + + ref --> An FSRef specifying the directory. + ownerID <** An optional pointer to a SInt32. + If not NULL, the directory's owner ID + will be returned in the SInt32. + groupID <** An optional pointer to a SInt32. + If not NULL, the directory's group ID, or 0 + if no group affiliation, will be returned in + the SInt32. + accessRights <** An optional pointer to a SInt32. + If not NULL, the directory's access rights + will be returned in the SInt32. + + __________ + + Also see: FSSetDirAccess, FSMapID, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSSetDirAccess + +OSErr +FSSetDirAccess( + const FSRef *ref, + SInt32 ownerID, + SInt32 groupID, + SInt32 accessRights); + +/* + The FSpSetDirAccess function changes the directory access control + information for a directory on a shared volume. You must be the owner of + a directory to change its access control information. + + ref --> An FSRef specifying the directory. + ownerID --> The directory's owner ID. + groupID --> The directory's group ID or 0 if no group affiliation. + accessRights --> The directory's access rights. + + __________ + + Also see: FSGetDirAccess, FSMapID, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolMountInfoSize + +OSErr +FSGetVolMountInfoSize( + FSVolumeRefNum volRefNum, + SInt16 *size); + +/* + The FSGetVolMountInfoSize function determines the how much space the + program needs to allocate for a volume mounting information record. + + volRefNum --> Volume specification. + size <-- The space needed (in bytes) of the volume + mounting information record. + + __________ + + Also see: FSGetVolMountInfo, VolumeMount +*/ + +/*****************************************************************************/ + +#pragma mark FSGetVolMountInfo + +OSErr +FSGetVolMountInfo( + FSVolumeRefNum volRefNum, + void *volMountInfo); + +/* + The FSGetVolMountInfo function retrieves a volume mounting information + record containing all the information needed to mount the volume, + except for passwords. + + volRefNum --> Volume specification. + volMountInfo <-- The volume mounting information. + + __________ + + Also see: FSGetVolMountInfoSize, VolumeMount +*/ + +/*****************************************************************************/ + +#pragma mark FSVolumeMount + +// This function exists in Mac OS X 10.5, we cannot re-define it here. +// We don't use this function, so just don't compile it. +#if 0 +OSErr +FSVolumeMount( + const void *volMountInfo, + FSVolumeRefNum *volRefNum); +#endif + +/* + The VolumeMount function mounts a volume using a volume mounting + information record. + + volMountInfo --> A volume mounting information record. + volRefNum <-- The volume reference number. + + __________ + + Also see: FSGetVolMountInfoSize, FSGetVolMountInfo +*/ + +/*****************************************************************************/ + +#pragma mark FSMapID + +OSErr +FSMapID( + FSVolumeRefNum volRefNum, + SInt32 ugID, + SInt16 objType, + Str31 name); + +/* + The FSMapID function determines the name of a user or group if you know + the user or group ID. + + volRefNum --> Volume specification. + objType --> The mapping function code: + kOwnerID2Name to map a user ID to a user name + kGroupID2Name to map a group ID to a group name + name <** An optional pointer to a buffer (minimum Str31). + If not NULL, the user or group name + will be returned in the buffer. + + __________ + + Also see: FSGetDirAccess, FSSetDirAccess, FSMapName +*/ + +/*****************************************************************************/ + +#pragma mark FSMapName + +OSErr +FSMapName( + FSVolumeRefNum volRefNum, + ConstStr255Param name, + SInt16 objType, + SInt32 *ugID); + +/* + The FSMapName function determines the user or group ID if you know the + user or group name. + + volRefNum --> Volume specification. + name --> The user or group name. + objType --> The mapping function code: + kOwnerName2ID to map a user name to a user ID + kGroupName2ID to map a user name to a group ID + ugID <-- The user or group ID. + + __________ + + Also see: FSGetDirAccess, FSSetDirAccess, FSMapID +*/ + +/*****************************************************************************/ + +#pragma mark FSCopyFile + +OSErr +FSCopyFile( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *copyName, /* can be NULL (no rename during copy) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* can be NULL */ + +/* + The FSCopyFile function duplicates a file and optionally renames it. + The source and destination volumes must be on the same file server. + This function instructs the server to copy the file. + + srcFileRef --> An FSRef specifying the source file. + dstDirectoryRef --> An FSRef specifying the destination directory. + nameLength --> Number of UniChar in copyName parameter (ignored + if copyName is NULL). + copyName --> Points to the new file name if the file is to be + renamed, or NULL if the file isn't to be renamed. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <** An optional pointer to a FSRef. + If not NULL, the FSRef of the duplicated file + will be returned in the FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark FSMoveRename + +OSErr +FSMoveRename( + const FSRef *srcFileRef, + const FSRef *dstDirectoryRef, + UniCharCount nameLength, + const UniChar *moveName, /* can be NULL (no rename during move) */ + TextEncoding textEncodingHint, + FSRef *newRef); /* can be NULL */ + +/* + The FSMoveRename function moves a file or directory (object), and + optionally renames it. The source and destination locations must be on + the same shared volume. + + srcFileRef --> An FSRef specifying the source file. + dstDirectoryRef --> An FSRef specifying the destination directory. + nameLength --> Number of UniChar in moveName parameter (ignored + if copyName is NULL) + moveName --> Points to the new object name if the object is to be + renamed, or NULL if the object isn't to be renamed. + textEncodingHint --> The text encoding hint used for the rename. + You can pass kTextEncodingUnknown to use the + "default" textEncodingHint. + newRef <** An optional pointer to a FSRef. + If not NULL, the FSRef of the moved object + will be returned in the FSRef. +*/ + +/*****************************************************************************/ + +#pragma mark ----- File ID Routines ----- + +/*****************************************************************************/ + +#pragma mark FSResolveFileIDRef + +OSErr +FSResolveFileIDRef( + FSVolumeRefNum volRefNum, + SInt32 fileID, + FSRef *ref); + +/* + The FSResolveFileIDRef function returns an FSRef for the file with the + specified file ID reference. + + volRefNum --> Volume specification. + fileID --> The file ID reference. + ref <-- The FSRef for the file ID reference. + + __________ + + Also see: FSCreateFileIDRef, FSDeleteFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark FSCreateFileIDRef + +OSErr +FSCreateFileIDRef( + const FSRef *ref, + SInt32 *fileID); + +/* + The FSCreateFileIDRef function creates a file ID reference for the + specified file, or if a file ID reference already exists, supplies + the file ID reference and returns the result code fidExists or afpIDExists. + + ref --> The FSRef for the file. + fileID <-- The file ID reference (if result is noErr, + fidExists, or afpIDExists). + + __________ + + Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark FSDeleteFileIDRef + +/* + Why is there no FSDeleteFileIDRef routine? There are two reasons: + + 1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references. + On HFS volumes, deleting a file ID reference breaks aliases (which + use file ID references to track files as they are moved around on a + volume) and file ID references are automatically deleted when the file + they refer to is deleted. On HFS Plus volumes, file ID references are + always created when a file is created, deleted when the file is deleted, + and cannot be deleted at any other time. + + 2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0 + through 10.1.x. While this will be fixed in a future release, the + implementation, like the Mac OS 8/9 implementation, does not delete + file ID references. + + __________ + + Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef +*/ + +/*****************************************************************************/ + +#pragma mark ----- Utility Routines ----- + +/*****************************************************************************/ + +#pragma mark GetTempBuffer + +Ptr +GetTempBuffer( + ByteCount buffReqSize, + ByteCount *buffActSize); + +/* + The GetTempBuffer function allocates a temporary buffer for file system + operations which is at least 4K bytes and a multiple of 4K bytes. + + buffReqSize --> Size you'd like the buffer to be. + buffActSize <-- The size of the buffer allocated. + function result <-- Pointer to memory allocated, or NULL if no memory + was available. The caller is responsible for + disposing of this buffer with DisposePtr. +*/ + +/*****************************************************************************/ + +#pragma mark FileRefNumGetFSRef + +OSErr +FileRefNumGetFSRef( + short refNum, + FSRef *ref); + +/* + The FileRefNumGetFSRef function gets the FSRef of an open file. + + refNum --> The file reference number of an open file. + ref <-- The FSRef to the open file. +*/ + +/*****************************************************************************/ + +#pragma mark FSSetDefault + +OSErr +FSSetDefault( + const FSRef *newDefault, + FSRef *oldDefault); + +/* + The FSSetDefault function sets the current working directory to the + directory specified by newDefault. The previous current working directory + is returned in oldDefault and must be used to restore the current working + directory to its previous state with the FSRestoreDefault function. + These two functions are designed to be used as a wrapper around + Standard I/O routines where the location of the file is implied to be the + current working directory. This is how you should use these functions: + + result = FSSetDefault(&newDefault, &oldDefault); + if ( noErr == result ) + { + // call the Stdio functions like remove, rename, + // fopen, freopen, etc here! + + result = FSRestoreDefault(&oldDefault); + } + + newDefault --> An FSRef that specifies the new current working + directory. + oldDefault <-- The previous current working directory's FSRef. + + __________ + + Also see: FSRestoreDefault +*/ + +/*****************************************************************************/ + +#pragma mark FSRestoreDefault + +OSErr +FSRestoreDefault( + const FSRef *oldDefault); + +/* + The FSRestoreDefault function restores the current working directory + to the directory specified by oldDefault. The oldDefault parameter was + previously obtained from the FSSetDefault function. + These two functions are designed to be used as a wrapper around + Standard I/O routines where the location of the file is implied to be the + current working directory. This is how you should use these functions: + + result = FSSetDefault(&newDefault, &oldDefault); + if ( noErr == result ) + { + // call the Stdio functions like remove, rename, + // fopen, freopen, etc here! + + result = FSRestoreDefault(&oldDefault); + } + + oldDefault --> The FSRef of the location to restore. + + __________ + + Also see: FSSetDefault +*/ + +/*****************************************************************************/ + +#if PRAGMA_STRUCT_ALIGN + #pragma options align=reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack(pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack() +#endif + +#ifdef PRAGMA_IMPORT_OFF +#pragma import off +#elif PRAGMA_IMPORT +#pragma import reset +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MOREFILESX__ */ + diff --git a/src/libs/xpcom18a4/xpcom/base/.cvsignore b/src/libs/xpcom18a4/xpcom/base/.cvsignore new file mode 100644 index 00000000..235f7398 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/.cvsignore @@ -0,0 +1,2 @@ +Makefile +bloatblame diff --git a/src/libs/xpcom18a4/xpcom/base/Makefile.in b/src/libs/xpcom18a4/xpcom/base/Makefile.in new file mode 100644 index 00000000..a897bca8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/Makefile.in @@ -0,0 +1,133 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_base +LIBRARY_NAME = xpcombase_s +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +CPPSRCS = \ + nsAllocator.cpp \ + nsConsoleMessage.cpp \ + nsConsoleService.cpp \ + nsDebugImpl.cpp \ + nsErrorService.cpp \ + nsExceptionService.cpp \ + nsID.cpp \ + nsMemoryImpl.cpp \ + nsTraceRefcntImpl.cpp \ + $(NULL) + +ifdef GC_LEAK_DETECTOR +CSRCS += nsGarbageCollector.c +CPPSRCS += nsLeakDetector.cpp +REQUIRES += boehm +endif + +EXPORTS = \ + nsAgg.h \ + nsAutoPtr.h \ + nsCom.h \ + nsDebugImpl.h \ + nsIAllocator.h \ + nsIID.h \ + nsISupportsObsolete.h \ + nsTraceRefcntImpl.h \ + nsWeakPtr.h \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef MOZ_DEBUG +CSRCS += pure_api.c +EXPORTS += pure.h +endif +CPPSRCS += nsStackFrameWin.cpp +endif + +ifneq ($(OS_ARCH),WINNT) +CPPSRCS += nsStackFrameUnix.cpp +endif + +SDK_XPIDLSRCS = \ + nsIDebug.idl \ + nsIInterfaceRequestor.idl \ + nsIMemory.idl \ + nsIProgrammingLanguage.idl \ + nsISupports.idl \ + nsITraceRefcnt.idl \ + nsIWeakReference.idl \ + nsrootidl.idl \ + +SDK_HEADERS = \ + nsError.h \ + nsID.h \ + nsISupportsBase.h \ + nscore.h \ + +XPIDLSRCS = \ + nsIConsoleListener.idl \ + nsIConsoleMessage.idl \ + nsIConsoleService.idl \ + nsIErrorService.idl \ + nsIException.idl \ + nsIExceptionService.idl \ + $(NULL) + +ifdef GC_LEAK_DETECTOR +XPIDLSRCS += nsILeakDetector.idl +endif + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + diff --git a/src/libs/xpcom18a4/xpcom/base/nsAgg.h b/src/libs/xpcom18a4/xpcom/base/nsAgg.h new file mode 100644 index 00000000..c818639e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAgg.h @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsAgg_h___ +#define nsAgg_h___ + +#include "nsISupports.h" + + +//////////////////////////////////////////////////////////////////////////////// + +// Put this in your class's declaration: +#define NS_DECL_AGGREGATED \ + NS_DECL_ISUPPORTS \ + \ +public: \ + \ + /* You must implement this operation instead of the nsISupports */ \ + /* methods if you inherit from nsAggregated. */ \ + NS_IMETHOD \ + AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr); \ + \ +protected: \ + \ + class Internal : public nsISupports { \ + public: \ + \ + Internal() {} \ + \ + NS_IMETHOD QueryInterface(const nsIID& aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ + \ + }; \ + \ + friend class Internal; \ + \ + nsISupports* fOuter; \ + Internal fAggregated; \ + \ + nsISupports* GetInner(void) { return &fAggregated; } \ + \ +public: \ + + +// Put this in your class's constructor: +#define NS_INIT_AGGREGATED(outer) \ + PR_BEGIN_MACRO \ + fOuter = outer ? outer : &fAggregated; \ + PR_END_MACRO + + +// Put this in your class's implementation file: +#define NS_IMPL_AGGREGATED(_class) \ +NS_IMETHODIMP \ +_class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ +{ \ + return fOuter->QueryInterface(aIID, aInstancePtr); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::AddRef(void) \ +{ \ + return fOuter->AddRef(); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Release(void) \ +{ \ + return fOuter->Release(); \ +} \ + \ +NS_IMETHODIMP \ +_class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + return agg->AggregatedQueryInterface(aIID, aInstancePtr); \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Internal::AddRef(void) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + NS_PRECONDITION(PRInt32(agg->mRefCnt) >= 0, "illegal refcnt"); \ + ++agg->mRefCnt; \ + NS_LOG_ADDREF(this, agg->mRefCnt, #_class, sizeof(*this)); \ + return agg->mRefCnt; \ +} \ + \ +NS_IMETHODIMP_(nsrefcnt) \ +_class::Internal::Release(void) \ +{ \ + _class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \ + NS_PRECONDITION(0 != agg->mRefCnt, "dup release"); \ + --agg->mRefCnt; \ + NS_LOG_RELEASE(this, agg->mRefCnt, #_class); \ + if (agg->mRefCnt == 0) { \ + agg->mRefCnt = 1; /* stabilize */ \ + NS_DELETEXPCOM(agg); \ + return 0; \ + } \ + return agg->mRefCnt; \ +} \ + +// for use with QI macros in nsISupportsUtils.h: + +#define NS_INTERFACE_MAP_BEGIN_AGGREGATED(_class) \ + NS_IMPL_AGGREGATED_QUERY_HEAD(_class) + +#define NS_IMPL_AGGREGATED_QUERY_HEAD(_class) \ +NS_IMETHODIMP \ +_class::AggregatedQueryInterface(REFNSIID aIID, void** aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, \ + "AggregatedQueryInterface requires a non-NULL result ptr!"); \ + if ( !aInstancePtr ) \ + return NS_ERROR_NULL_POINTER; \ + nsISupports* foundInterface; + +#endif /* nsAgg_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp b/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp new file mode 100644 index 00000000..d565329d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAllocator.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// obsolete +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/base/nsAllocator.h b/src/libs/xpcom18a4/xpcom/base/nsAllocator.h new file mode 100644 index 00000000..5320469c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAllocator.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// obsolete +//////////////////////////////////////////////////////////////////////////////// + +#ifndef nsAllocator_h__ +#define nsAllocator_h__ + +#include "nsIAllocator.h" +#include "prmem.h" +#include "nsAgg.h" +#include "nsIFactory.h" + +#endif // nsAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h b/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h new file mode 100644 index 00000000..874b1e31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsAutoPtr.h @@ -0,0 +1,1353 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author of nsCOMPtr) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsAutoPtr_h___ +#define nsAutoPtr_h___ + + // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") +#ifndef nsCOMPtr_h___ + // For |already_AddRefed|, |nsDerivedSafe|, |NSCAP_Zero|, + // |NSCAP_DONT_PROVIDE_NONCONST_OPEQ|, + // |NSCAP_FEATURE_INLINE_STARTASSIGNMENT| +#include "nsCOMPtr.h" +#endif + +/*****************************************************************************/ + +// template class nsAutoPtrGetterTransfers; + +template +class nsAutoPtr + { + private: + void** + begin_assignment() + { + assign(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + delete oldPtr; + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsAutoPtr() + { + delete mRawPtr; + } + + // Constructors + + nsAutoPtr() + : mRawPtr(0) + // default constructor + { + } + + nsAutoPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + } + + nsAutoPtr( nsAutoPtr& aSmartPtr ) + : mRawPtr( aSmartPtr.forget() ) + // Construct by transferring ownership from another smart pointer. + { + } + + + // Assignment operators + + nsAutoPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign(rhs); + return *this; + } + + nsAutoPtr& operator=( nsAutoPtr& rhs ) + // assign by transferring ownership from another smart pointer. + { + assign(rhs.forget()); + return *this; + } + + // Other pointer operators + + T* + get() const + /* + Prefer the implicit conversion provided automatically by + |operator T*() const|. Use |get()| _only_ to resolve + ambiguity. + */ + { + return mRawPtr; + } + + operator T*() const + /* + ...makes an |nsAutoPtr| act like its underlying raw pointer + type whenever it is used in a context where a raw pointer + is expected. It is this operator that makes an |nsAutoPtr| + substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, + except where necessary to resolve ambiguity. + */ + { + return get(); + } + + T* + forget() + { + T* temp = mRawPtr; + mRawPtr = 0; + return temp; + } + + T* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsAutoPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsAutoPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsAutoPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsAutoPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + T& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsAutoPtr* +address_of( const nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsAutoPtr* +address_of( nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsAutoPtr* +address_of( const nsAutoPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsAutoPtrGetterTransfers + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsAutoPtr fooP; + ...->GetTransferedPointer(getter_Transfers(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. + + When initialized with a |nsAutoPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetTransferedPointer| in this case) can fill in. + + This type should be a nested class inside |nsAutoPtr|. + */ + { + public: + explicit + nsAutoPtrGetterTransfers( nsAutoPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsAutoPtr& mTargetSmartPtr; + }; + +template +inline +nsAutoPtrGetterTransfers +getter_Transfers( nsAutoPtr& aSmartPtr ) + /* + Used around a |nsAutoPtr| when + ...makes the class |nsAutoPtrGetterTransfers| invisible. + */ + { + return nsAutoPtrGetterTransfers(aSmartPtr); + } + + + + // Comparing two |nsAutoPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsAutoPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsAutoPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsAutoPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsAutoPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsAutoPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsAutoPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsAutoPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + +/*****************************************************************************/ + +// template class nsAutoArrayPtrGetterTransfers; + +template +class nsAutoArrayPtr + { + private: + void** + begin_assignment() + { + assign(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + delete [] oldPtr; + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsAutoArrayPtr() + { + delete [] mRawPtr; + } + + // Constructors + + nsAutoArrayPtr() + : mRawPtr(0) + // default constructor + { + } + + nsAutoArrayPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + } + + nsAutoArrayPtr( nsAutoArrayPtr& aSmartPtr ) + : mRawPtr( aSmartPtr.forget() ) + // Construct by transferring ownership from another smart pointer. + { + } + + + // Assignment operators + + nsAutoArrayPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign(rhs); + return *this; + } + + nsAutoArrayPtr& operator=( nsAutoArrayPtr& rhs ) + // assign by transferring ownership from another smart pointer. + { + assign(rhs.forget()); + return *this; + } + + // Other pointer operators + + T* + get() const + /* + Prefer the implicit conversion provided automatically by + |operator T*() const|. Use |get()| _only_ to resolve + ambiguity. + */ + { + return mRawPtr; + } + + operator T*() const + /* + ...makes an |nsAutoArrayPtr| act like its underlying raw pointer + type whenever it is used in a context where a raw pointer + is expected. It is this operator that makes an |nsAutoArrayPtr| + substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, + except where necessary to resolve ambiguity. + */ + { + return get(); + } + + T* + forget() + { + T* temp = mRawPtr; + mRawPtr = 0; + return temp; + } + + T* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsAutoArrayPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsAutoArrayPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsAutoArrayPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsAutoArrayPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + T& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsAutoArrayPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsAutoArrayPtr* +address_of( const nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsAutoArrayPtr* +address_of( nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsAutoArrayPtr* +address_of( const nsAutoArrayPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsAutoArrayPtrGetterTransfers + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsAutoArrayPtr fooP; + ...->GetTransferedPointer(getter_Transfers(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_Transfers()| instead. + + When initialized with a |nsAutoArrayPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetTransferedPointer| in this case) can fill in. + + This type should be a nested class inside |nsAutoArrayPtr|. + */ + { + public: + explicit + nsAutoArrayPtrGetterTransfers( nsAutoArrayPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsAutoArrayPtr& mTargetSmartPtr; + }; + +template +inline +nsAutoArrayPtrGetterTransfers +getter_Transfers( nsAutoArrayPtr& aSmartPtr ) + /* + Used around a |nsAutoArrayPtr| when + ...makes the class |nsAutoArrayPtrGetterTransfers| invisible. + */ + { + return nsAutoArrayPtrGetterTransfers(aSmartPtr); + } + + + + // Comparing two |nsAutoArrayPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsAutoArrayPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsAutoArrayPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsAutoArrayPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsAutoArrayPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsAutoArrayPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsAutoArrayPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + + +/*****************************************************************************/ + +// template class nsRefPtrGetterAddRefs; + +template +class nsRefPtr + { + private: + + void + assign_with_AddRef( T* rawPtr ) + { + if ( rawPtr ) + rawPtr->AddRef(); + assign_assuming_AddRef(rawPtr); + } + + void** + begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } + + void + assign_assuming_AddRef( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + if ( oldPtr ) + oldPtr->Release(); + } + + private: + T* mRawPtr; + + public: + typedef T element_type; + + ~nsRefPtr() + { + if ( mRawPtr ) + mRawPtr->Release(); + } + + // Constructors + + nsRefPtr() + : mRawPtr(0) + // default constructor + { + } + + nsRefPtr( const nsRefPtr& aSmartPtr ) + : mRawPtr(aSmartPtr.mRawPtr) + // copy-constructor + { + if ( mRawPtr ) + mRawPtr->AddRef(); + } + + nsRefPtr( T* aRawPtr ) + : mRawPtr(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + mRawPtr->AddRef(); + } + + nsRefPtr( const already_AddRefed& aSmartPtr ) + : mRawPtr(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + } + + // Assignment operators + + nsRefPtr& + operator=( const nsRefPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsRefPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + return *this; + } + + nsRefPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + return *this; + } + + // Other pointer operators + + void + swap( nsRefPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + T* temp = rhs.mRawPtr; + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + } + + void + swap( T*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + T* temp = rhs; + rhs = mRawPtr; + mRawPtr = temp; + } + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_CONST_CAST(nsDerivedSafe*, + NS_REINTERPRET_CAST(const nsDerivedSafe*, mRawPtr)); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsRefPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsRefPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsRefPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsRefPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsRefPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsRefPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsRefPtr with operator*()."); + return *get(); + } + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsRefPtr* +address_of( const nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsRefPtr* +address_of( nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsRefPtr* +address_of( const nsRefPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsRefPtrGetterAddRefs + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsRefPtr fooP; + ...->GetAddRefedPointer(getter_AddRefs(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. + + When initialized with a |nsRefPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the + outer call (|GetAddRefedPointer| in this case) can fill in. + + This type should be a nested class inside |nsRefPtr|. + */ + { + public: + explicit + nsRefPtrGetterAddRefs( nsRefPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsRefPtr& mTargetSmartPtr; + }; + +template +inline +nsRefPtrGetterAddRefs +getter_AddRefs( nsRefPtr& aSmartPtr ) + /* + Used around a |nsRefPtr| when + ...makes the class |nsRefPtrGetterAddRefs| invisible. + */ + { + return nsRefPtrGetterAddRefs(aSmartPtr); + } + + + + // Comparing two |nsRefPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsRefPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsRefPtr& rhs ) + { + return NS_STATIC_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsRefPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsRefPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsRefPtr| to |0| + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsRefPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsRefPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsRefPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsRefPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsRefPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + +/*****************************************************************************/ + +#endif // !defined(nsAutoPtr_h___) diff --git a/src/libs/xpcom18a4/xpcom/base/nsCom.h b/src/libs/xpcom18a4/xpcom/base/nsCom.h new file mode 100644 index 00000000..54b0b8bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsCom.h @@ -0,0 +1,43 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsCom_h__ +#define nsCom_h__ +#include "nscore.h" +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp new file mode 100644 index 00000000..02dc589b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Base implementation for console messages. + */ + +#include "nsConsoleMessage.h" +#include "nsReadableUtils.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsConsoleMessage, nsIConsoleMessage) + +nsConsoleMessage::nsConsoleMessage() +{ +} + +nsConsoleMessage::nsConsoleMessage(const PRUnichar *message) +{ + mMessage.Assign(message); +} + +NS_IMETHODIMP +nsConsoleMessage::GetMessage(PRUnichar **result) { + *result = ToNewUnicode(mMessage); + + return NS_OK; +} + +// NS_IMETHODIMP +// nsConsoleMessage::Init(const PRUnichar *message) { +// nsAutoString newMessage(message); +// mMessage = ToNewUnicode(newMessage); +// return NS_OK; +// } + diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h new file mode 100644 index 00000000..3d4a7e6c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleMessage.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsconsolemessage_h__ +#define __nsconsolemessage_h__ + +#include "nsIConsoleMessage.h" +#include "nsString.h" + +class nsConsoleMessage : public nsIConsoleMessage { +public: + nsConsoleMessage(); + nsConsoleMessage(const PRUnichar *message); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONSOLEMESSAGE + +private: + ~nsConsoleMessage() {} + + nsString mMessage; +}; + +#endif /* __nsconsolemessage_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp new file mode 100644 index 00000000..1b369071 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.cpp @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Maintains a circular buffer of recent messages, and notifies + * listeners when new messages are logged. + */ + +/* Threadsafe. */ + +#include "nsMemory.h" +#include "nsIServiceManager.h" +#include "nsIProxyObjectManager.h" +#include "nsSupportsArray.h" + +#include "nsConsoleService.h" +#include "nsConsoleMessage.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsConsoleService, nsIConsoleService) + +nsConsoleService::nsConsoleService() + : mCurrent(0), mFull(PR_FALSE), mListening(PR_FALSE), mLock(nsnull) +{ + // XXX grab this from a pref! + // hm, but worry about circularity, bc we want to be able to report + // prefs errs... + mBufferSize = 250; + + // XXX deal with these two allocations by detecting null mLock in factory? + mMessages = (nsIConsoleMessage **) + nsMemory::Alloc(mBufferSize * sizeof(nsIConsoleMessage *)); + + mLock = PR_NewLock(); + + // Array elements should be 0 initially for circular buffer algorithm. + for (PRUint32 i = 0; i < mBufferSize; i++) { + mMessages[i] = nsnull; + } + +} + +nsConsoleService::~nsConsoleService() +{ + PRUint32 i = 0; + while (i < mBufferSize && mMessages[i] != nsnull) { + NS_RELEASE(mMessages[i]); + i++; + } + +#ifdef DEBUG_mccabe + if (mListeners.Count() != 0) { + fprintf(stderr, + "WARNING - %d console error listeners still registered!\n" + "More calls to nsIConsoleService::UnregisterListener needed.\n", + mListeners.Count()); + } + +#endif + + nsMemory::Free(mMessages); + if (mLock) + PR_DestroyLock(mLock); +} + +static PRBool PR_CALLBACK snapshot_enum_func(nsHashKey *key, void *data, void* closure) +{ + nsISupportsArray *array = (nsISupportsArray *)closure; + + // Copy each element into the temporary nsSupportsArray... + array->AppendElement((nsISupports*)data); + return PR_TRUE; +} + +// nsIConsoleService methods +NS_IMETHODIMP +nsConsoleService::LogMessage(nsIConsoleMessage *message) +{ + if (message == nsnull) + return NS_ERROR_INVALID_ARG; + + nsSupportsArray listenersSnapshot; + nsIConsoleMessage *retiredMessage; + + NS_ADDREF(message); // early, in case it's same as replaced below. + + /* + * Lock while updating buffer, and while taking snapshot of + * listeners array. + */ + { + nsAutoLock lock(mLock); + + /* + * If there's already a message in the slot we're about to replace, + * we've wrapped around, and we need to release the old message. We + * save a pointer to it, so we can release below outside the lock. + */ + retiredMessage = mMessages[mCurrent]; + + mMessages[mCurrent++] = message; + if (mCurrent == mBufferSize) { + mCurrent = 0; // wrap around. + mFull = PR_TRUE; + } + + /* + * Copy the listeners into the snapshot array - in case a listener + * is removed during an Observe(...) notification... + */ + mListeners.Enumerate(snapshot_enum_func, &listenersSnapshot); + } + if (retiredMessage != nsnull) + NS_RELEASE(retiredMessage); + + /* + * Iterate through any registered listeners and tell them about + * the message. We use the mListening flag to guard against + * recursive message logs. This could sometimes result in + * listeners being skipped because of activity on other threads, + * when we only care about the recursive case. + */ + nsCOMPtr listener; + nsresult rv; + nsresult returned_rv; + PRUint32 snapshotCount; + rv = listenersSnapshot.Count(&snapshotCount); + if (NS_FAILED(rv)) + return rv; + + { + nsAutoLock lock(mLock); + if (mListening) + return NS_OK; + mListening = PR_TRUE; + } + + returned_rv = NS_OK; + for (PRUint32 i = 0; i < snapshotCount; i++) { + rv = listenersSnapshot.GetElementAt(i, getter_AddRefs(listener)); + if (NS_FAILED(rv)) { + returned_rv = rv; + break; // fall thru to mListening restore code below. + } + listener->Observe(message); + } + + { + nsAutoLock lock(mLock); + mListening = PR_FALSE; + } + + return returned_rv; +} + +NS_IMETHODIMP +nsConsoleService::LogStringMessage(const PRUnichar *message) +{ + nsConsoleMessage *msg = new nsConsoleMessage(message); + return this->LogMessage(msg); +} + +NS_IMETHODIMP +nsConsoleService::GetMessageArray(nsIConsoleMessage ***messages, PRUint32 *count) +{ + nsIConsoleMessage **messageArray; + + /* + * Lock the whole method, as we don't want anyone mucking with mCurrent or + * mFull while we're copying out the buffer. + */ + nsAutoLock lock(mLock); + + if (mCurrent == 0 && !mFull) { + /* + * Make a 1-length output array so that nobody gets confused, + * and return a count of 0. This should result in a 0-length + * array object when called from script. + */ + messageArray = (nsIConsoleMessage **) + nsMemory::Alloc(sizeof (nsIConsoleMessage *)); + *messageArray = nsnull; + *messages = messageArray; + *count = 0; + + return NS_OK; + } + + PRUint32 resultSize = mFull ? mBufferSize : mCurrent; + messageArray = + (nsIConsoleMessage **)nsMemory::Alloc((sizeof (nsIConsoleMessage *)) + * resultSize); + + if (messageArray == nsnull) { + *messages = nsnull; + *count = 0; + return NS_ERROR_FAILURE; + } + + PRUint32 i; + if (mFull) { + for (i = 0; i < mBufferSize; i++) { + // if full, fill the buffer starting from mCurrent (which'll be + // oldest) wrapping around the buffer to the most recent. + messageArray[i] = mMessages[(mCurrent + i) % mBufferSize]; + NS_ADDREF(messageArray[i]); + } + } else { + for (i = 0; i < mCurrent; i++) { + messageArray[i] = mMessages[i]; + NS_ADDREF(messageArray[i]); + } + } + *count = resultSize; + *messages = messageArray; + + return NS_OK; +} + +NS_IMETHODIMP +nsConsoleService::RegisterListener(nsIConsoleListener *listener) { + nsresult rv; + + /* + * Store a threadsafe proxy to the listener rather than the + * listener itself; we want the console service to be callable + * from any thread, but listeners can be implemented in + * thread-specific ways, and we always want to call them on their + * originating thread. JavaScript is the motivating example. + */ + nsCOMPtr proxiedListener; + + rv = GetProxyForListener(listener, getter_AddRefs(proxiedListener)); + if (NS_FAILED(rv)) + return rv; + + { + nsAutoLock lock(mLock); + nsISupportsKey key(listener); + + /* + * Put the proxy event listener into a hashtable using the *real* + * listener as the key. + * + * This is necessary because proxy objects do *not* maintain + * nsISupports identity. Therefore, since GetProxyForListener(...) + * can return different proxies for the same object (see bug #85831) + * we need to use the real object as the unique key... + */ + mListeners.Put(&key, proxiedListener); + } + return NS_OK; +} + +NS_IMETHODIMP +nsConsoleService::UnregisterListener(nsIConsoleListener *listener) { + nsAutoLock lock(mLock); + + nsISupportsKey key(listener); + mListeners.Remove(&key); + return NS_OK; +} + +nsresult +nsConsoleService::GetProxyForListener(nsIConsoleListener* aListener, + nsIConsoleListener** aProxy) +{ + nsresult rv; + *aProxy = nsnull; + + nsCOMPtr proxyManager = + (do_GetService(NS_XPCOMPROXY_CONTRACTID)); + + if (proxyManager == nsnull) + return NS_ERROR_NOT_AVAILABLE; + + /* + * NOTE this will fail if the calling thread doesn't have an eventQ. + * + * Would it be better to catch that case and leave the listener unproxied? + */ + rv = proxyManager->GetProxyForObject(NS_CURRENT_EVENTQ, + NS_GET_IID(nsIConsoleListener), + aListener, + PROXY_ASYNC | PROXY_ALWAYS, + (void**) aProxy); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h new file mode 100644 index 00000000..59758f84 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsConsoleService.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * nsConsoleService class declaration. + */ + +#ifndef __nsconsoleservice_h__ +#define __nsconsoleservice_h__ + +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsAutoLock.h" + +#include "nsIConsoleService.h" + +class nsConsoleService : public nsIConsoleService +{ +public: + nsConsoleService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONSOLESERVICE + +private: + ~nsConsoleService(); + + // build (or find) a proxy for the listener + nsresult GetProxyForListener(nsIConsoleListener* aListener, + nsIConsoleListener** aProxy); + + // Circular buffer of saved messages + nsIConsoleMessage **mMessages; + + // How big? + PRUint32 mBufferSize; + + // Index of slot in mMessages that'll be filled by *next* log message + PRUint32 mCurrent; + + // Is the buffer full? (Has mCurrent wrapped around at least once?) + PRBool mFull; + + // Listeners to notify whenever a new message is logged. + nsSupportsHashtable mListeners; + + // Current listener being notified of a logged error - to prevent + // stack overflows. + PRBool mListening; + + // To serialize interesting methods. + PRLock *mLock; +}; + +#endif /* __nsconsoleservice_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp new file mode 100644 index 00000000..f8806092 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.cpp @@ -0,0 +1,477 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOMPrivate.h" +#include "nsDebugImpl.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prlog.h" +#include "prinit.h" +#include "plstr.h" +#include "nsError.h" +#include "prerror.h" +#include "prerr.h" + +#if defined(XP_BEOS) +/* For DEBUGGER macros */ +#include +#endif + +#if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS) +/* for abort() and getenv() */ +#include +#endif + +#if defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) +#include +/* for nsTraceRefcnt::WalkTheStack() */ +#include "nsISupportsUtils.h" +#include "nsTraceRefcntImpl.h" + +#if defined(__GNUC__) && defined(__i386) +# define DebugBreak() { asm("int $3"); } +#elif defined(__APPLE__) && defined(TARGET_CARBON) +# include "MacTypes.h" +# define DebugBreak() { Debugger(); } +#else +# define DebugBreak() +#endif +#endif + +#if defined(XP_OS2) + /* Added definitions for DebugBreak() for 2 different OS/2 compilers. Doing + * the int3 on purpose so that a developer can step over the + * instruction if so desired. Not always possible if trapping due to exception + * handling IBM-AKR + */ + #define INCL_WINDIALOGS // need for WinMessageBox + #include + #include + + #if defined(DEBUG) + #define DebugBreak() { asm("int $3"); } + #else + #define DebugBreak() + #endif /* DEBUG */ +#endif /* XP_OS2 */ + +#if defined(_WIN32) +#include +#include +#elif defined(XP_MAC) + #define TEMP_MAC_HACK + + //------------------------ + #ifdef TEMP_MAC_HACK + #include + #include + #include + + // TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON + // LOGGING ON MACINTOSH + // At this moment, NSPR's logging is a no-op on Macintosh. + + #include + #include + + #undef PR_LOG + #undef PR_LogFlush + #define PR_LOG(module,level,args) dprintf args + #define PR_LogFlush() + static void dprintf(const char *format, ...) + { + va_list ap; + Str255 buffer; + + va_start(ap, format); + buffer[0] = std::vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap); + va_end(ap); + if (PL_strcasestr((char *)&buffer[1], "warning")) + printf("¥¥¥%s\n", (char*)buffer + 1); + else + DebugStr(buffer); + } + #endif // TEMP_MAC_HACK + //------------------------ +#elif defined(XP_UNIX) +#include +#endif + +/* + * Determine if debugger is present in windows. + */ +#if defined (_WIN32) + +typedef WINBASEAPI BOOL (WINAPI* LPFNISDEBUGGERPRESENT)(); +PRBool InDebugger() +{ + PRBool fReturn = PR_FALSE; + LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent = NULL; + HINSTANCE hKernel = LoadLibrary("Kernel32.dll"); + + if(hKernel) + { + lpfnIsDebuggerPresent = + (LPFNISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent"); + if(lpfnIsDebuggerPresent) + { + fReturn = (*lpfnIsDebuggerPresent)(); + } + FreeLibrary(hKernel); + } + + return fReturn; +} + +#endif /* WIN32*/ + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDebugImpl, nsIDebug) + +nsDebugImpl::nsDebugImpl() +{ +} + +/** + * Implementation of the nsDebug methods. Note that this code is + * always compiled in, in case some other module that uses it is + * compiled with debugging even if this library is not. + */ +static PRLogModuleInfo* gDebugLog; + +static void InitLog(void) +{ + if (0 == gDebugLog) { + gDebugLog = PR_NewLogModule("nsDebug"); + gDebugLog->level = PR_LOG_DEBUG; + } +} + + + +NS_IMETHODIMP +nsDebugImpl::Assertion(const char *aStr, const char *aExpr, const char *aFile, PRInt32 aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "###!!! ASSERTION: %s: '%s', file %s, line %d", + aStr, aExpr, aFile, aLine); + + // Write out the assertion message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + PR_LogFlush(); + + // And write it out to the stderr + fprintf(stderr, "%s\n", buf); + fflush(stderr); + +#if defined(_WIN32) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + if(!InDebugger()) + { + DWORD code = IDRETRY; + + /* Create the debug dialog out of process to avoid the crashes caused by + * Windows events leaking into our event loop from an in process dialog. + * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg). + * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792 + */ + PROCESS_INFORMATION pi; + STARTUPINFO si; + char executable[MAX_PATH]; + char* pName; + + memset(&pi, 0, sizeof(pi)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.wShowWindow = SW_SHOW; + + if(GetModuleFileName(GetModuleHandle(XPCOM_DLL), executable, MAX_PATH) && + NULL != (pName = strrchr(executable, '\\')) && + NULL != strcpy(pName+1, "windbgdlg.exe") && +#ifdef DEBUG_jband + (printf("Launching %s\n", executable), PR_TRUE) && +#endif + CreateProcess(executable, buf, NULL, NULL, PR_FALSE, + DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, + NULL, NULL, &si, &pi) && + WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, INFINITE) && + GetExitCodeProcess(pi.hProcess, &code)) + { + CloseHandle(pi.hProcess); + } + + switch(code) + { + case IDABORT: + //This should exit us + raise(SIGABRT); + //If we are ignored exit this way.. + _exit(3); + break; + + case IDIGNORE: + return NS_OK; + // Fall Through + } + } +#endif + +#if defined(XP_OS2) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + char msg[1200]; + PR_snprintf(msg, sizeof(msg), + "%s\n\nClick Cancel to Debug Application.\n" + "Click Enter to continue running the Application.", buf); + ULONG code = MBID_ERROR; + code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg, + "nsDebug::Assertion", 0, + MB_ERROR | MB_ENTERCANCEL); + + /* It is possible that we are executing on a thread that doesn't have a + * message queue. In that case, the message won't appear, and code will + * be 0xFFFF. We'll give the user a chance to debug it by calling + * Break() + * Actually, that's a really bad idea since this happens a lot with threadsafe + * assertions and since it means that you can't actually run the debug build + * outside a debugger without it crashing constantly. + */ + if(( code == MBID_ENTER ) || (code == MBID_ERROR)) + { + return NS_OK; + // If Retry, Fall Through + } +#endif + + Break(aFile, aLine); + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Break(const char *aFile, PRInt32 aLine) +{ +#ifndef TEMP_MAC_HACK + // Write out the assertion message to the debug log + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Break: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + + fprintf(stderr, "Break: at file %s, line %d\n",aFile, aLine); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + ::DebugBreak(); +#endif +#elif defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) + fprintf(stderr, "\07"); + + char *assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + + if (!assertBehavior) { + + // the default; nothing else to do + ; + + } else if ( strcmp(assertBehavior, "suspend")== 0 ) { + + // the suspend case is first because we wanna send the signal before + // other threads have had a chance to get too far from the state that + // caused this assertion (in case they happen to have been involved). + // + fprintf(stderr, "Suspending process; attach with the debugger.\n"); + kill(0, SIGSTOP); + + } else if ( strcmp(assertBehavior, "warn")==0 ) { + + // same as default; nothing else to do (see "suspend" case comment for + // why this compare isn't done as part of the default case) + // + ; + + } + else if ( strcmp(assertBehavior,"stack")==0 ) { + + // walk the stack + // + nsTraceRefcntImpl::WalkTheStack(stderr); + } + else if ( strcmp(assertBehavior,"abort")==0 ) { + + // same as UNIX_CRASH_ON_ASSERT + // + Abort(aFile, aLine); + + } else if ( strcmp(assertBehavior,"trap")==0 ) { + + DebugBreak(); + + } else { + + fprintf(stderr, "unrecognized value of XPCOM_DEBUG_BREAK env var!\n"); + + } + fflush(stderr); // this shouldn't really be necessary, i don't think, + // but maybe there's some lame stdio that buffers stderr + +#elif defined(XP_BEOS) + { +#ifdef UNIX_CRASH_ON_ASSERT + char buf[2000]; + sprintf(buf, "Break: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#else + Abort(aFile, aLine); +#endif +#endif // TEMP_MAC_HACK + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Abort(const char *aFile, PRInt32 aLine) +{ + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Abort: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + fprintf(stderr, "\07 Abort\n"); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + long* __p = (long*) 0x7; + *__p = 0x7; +#else /* _M_ALPHA */ + PR_Abort(); +#endif +#elif defined(XP_MAC) + ExitToShell(); +#elif defined(XP_UNIX) + PR_Abort(); +#elif defined(XP_OS2) + DebugBreak(); + return NS_OK; +#elif defined(XP_BEOS) + { +#ifndef DEBUG_cls + char buf[2000]; + sprintf(buf, "Abort: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Warning(const char* aMessage, + const char* aFile, PRIntn aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "WARNING: %s, file %s, line %d", + aMessage, aFile, aLine); + + // Write out the warning message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + + // And write it out to the stdout + fprintf(stderr, "%s\n", buf); + fflush(stderr); + return NS_OK; +} + +NS_METHOD +nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + *aInstancePtr = nsnull; + nsIDebug* debug = new nsDebugImpl(); + if (!debug) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = debug->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) { + delete debug; + } + + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_ErrorAccordingToNSPR() +{ + PRErrorCode err = PR_GetError(); + switch (err) { + case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY; + case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK; + case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND; + case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY; + case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY; + case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY; + case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; + case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS; + case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED; + case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG; + case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE; + case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG; + case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY; + case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED; + default: return NS_ERROR_FAILURE; + } +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h new file mode 100644 index 00000000..b6ca9770 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsDebugImpl.h @@ -0,0 +1,61 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 "nsIDebug.h" + +class nsDebugImpl : public nsIDebug +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDEBUG + + nsDebugImpl(); + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsDebugImpl() {} +}; + + +#define NS_DEBUG_CONTRACTID "@mozilla.org/xpcom/debug;1" +#define NS_DEBUG_CLASSNAME "nsDebug Interface" +#define NS_DEBUG_CID \ +{ /* a80b1fb3-aaf6-4852-b678-c27eb7a518af */ \ + 0xa80b1fb3, \ + 0xaaf6, \ + 0x4852, \ + {0xb6, 0x78, 0xc2, 0x7e, 0xb7, 0xa5, 0x18, 0xaf} \ +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsError.h b/src/libs/xpcom18a4/xpcom/base/nsError.h new file mode 100644 index 00000000..e0f3fe54 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsError.h @@ -0,0 +1,317 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsError_h__ +#define nsError_h__ + +#ifndef nscore_h___ +#include "nscore.h" /* needed for nsresult */ +#endif + +/* + * To add error code to your module, you need to do the following: + * + * 1) Add a module offset code. Add yours to the bottom of the list + * right below this comment, adding 1. + * + * 2) In your module, define a header file which uses one of the + * NE_ERROR_GENERATExxxxxx macros. Some examples below: + * + * #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1) + * #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2) + * #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3) + * + */ + + +/** + * @name Standard Module Offset Code. Each Module should identify a unique number + * and then all errors associated with that module become offsets from the + * base associated with that module id. There are 16 bits of code bits for + * each module. + */ + +#define NS_ERROR_MODULE_XPCOM 1 +#define NS_ERROR_MODULE_BASE 2 +#define NS_ERROR_MODULE_GFX 3 +#define NS_ERROR_MODULE_WIDGET 4 +#define NS_ERROR_MODULE_CALENDAR 5 +#define NS_ERROR_MODULE_NETWORK 6 +#define NS_ERROR_MODULE_PLUGINS 7 +#define NS_ERROR_MODULE_LAYOUT 8 +#define NS_ERROR_MODULE_HTMLPARSER 9 +#define NS_ERROR_MODULE_RDF 10 +#define NS_ERROR_MODULE_UCONV 11 +#define NS_ERROR_MODULE_REG 12 +#define NS_ERROR_MODULE_FILES 13 +#define NS_ERROR_MODULE_DOM 14 +#define NS_ERROR_MODULE_IMGLIB 15 +#define NS_ERROR_MODULE_MAILNEWS 16 +#define NS_ERROR_MODULE_EDITOR 17 +#define NS_ERROR_MODULE_XPCONNECT 18 +#define NS_ERROR_MODULE_PROFILE 19 +#define NS_ERROR_MODULE_LDAP 20 +#define NS_ERROR_MODULE_SECURITY 21 +#define NS_ERROR_MODULE_DOM_XPATH 22 +#define NS_ERROR_MODULE_DOM_RANGE 23 +#define NS_ERROR_MODULE_URILOADER 24 +#define NS_ERROR_MODULE_CONTENT 25 +#define NS_ERROR_MODULE_PYXPCOM 26 +#define NS_ERROR_MODULE_XSLT 27 +#define NS_ERROR_MODULE_IPC 28 +#define NS_ERROR_MODULE_SVG 29 + +/* NS_ERROR_MODULE_GENERAL should be used by modules that do not + * care if return code values overlap. Callers of methods that + * return such codes should be aware that they are not + * globally unique. Implementors should be careful about blindly + * returning codes from other modules that might also use + * the generic base. + */ +#define NS_ERROR_MODULE_GENERAL 51 + +/** + * @name Standard Error Handling Macros + */ + +#define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +#define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +/** + * @name Severity Code. This flag identifies the level of warning + */ + +#define NS_ERROR_SEVERITY_SUCCESS 0 +#define NS_ERROR_SEVERITY_ERROR 1 + +/** + * @name Mozilla Code. This flag separates consumers of mozilla code + * from the native platform + */ + +#define NS_ERROR_MODULE_BASE_OFFSET 0x45 + +/** + * @name Standard Error Generating Macros + */ + +#define NS_ERROR_GENERATE(sev,module,code) \ + ((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +#define NS_ERROR_GENERATE_SUCCESS(module,code) \ + ((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +#define NS_ERROR_GENERATE_FAILURE(module,code) \ + ((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) ) + +/** + * @name Standard Macros for retrieving error bits + */ + +#define NS_ERROR_GET_CODE(err) ((err) & 0xffff) +#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff)) +#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1) + +/** + * @name Standard return values + */ + +/*@{*/ + +/* Standard "it worked" return value */ +#define NS_OK 0 + +#define NS_ERROR_BASE ((nsresult) 0xC1F30000) + +/* Returned when an instance is not initialized */ +#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1) + +/* Returned when an instance is already initialized */ +#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2) + +/* Returned by a not implemented function */ +#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L) + +/* Returned when a given interface is not supported. */ +#define NS_NOINTERFACE ((nsresult) 0x80004002L) +#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE + +#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L) +#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER + +/* Returned when a function aborts */ +#define NS_ERROR_ABORT ((nsresult) 0x80004004L) + +/* Returned when a function fails */ +#define NS_ERROR_FAILURE ((nsresult) 0x80004005L) + +/* Returned when an IPC fails */ +#define NS_ERROR_CALL_FAILED ((nsresult) 0x800706beL) + +/* Returned when an unexpected error occurs */ +#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL) + +/* Returned when a memory allocation fails */ +#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL) + +/* Returned when an illegal value is passed */ +#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L) +#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE + +/* Returned when a class doesn't allow aggregation */ +#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L) + +/* Returned when an operation can't complete due to an unavailable resource */ +#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L) + +/* Returned when a class is not registered */ +#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L) + +/* Returned when a class cannot be registered, but may be tried again later */ +#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L) + +/* Returned when a dynamically loaded factory couldn't be found */ +#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L) + +/* Returned when a factory doesn't support signatures */ +#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \ + (NS_ERROR_BASE + 0x101) + +/* Returned when a factory already is registered */ +#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100) + +/* Socket failures */ +#define NS_ERROR_SOCKET_FAIL (NS_ERROR_BASE + 0x200) + + +/* For COM compatibility reasons, we want to use exact error code numbers + for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER. + The first matches: + + #define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) + + Errors returning this mean that the xpcom proxy code could not create a proxy for + one of the in paramaters. + + Because of this, we are ignoring the convention if using a base and offset for + error numbers. + +*/ + +/* Returned when a proxy could not be create a proxy for one of the IN parameters + This is returned only when the "real" meathod has NOT been invoked. +*/ + +#define NS_ERROR_PROXY_INVALID_IN_PARAMETER ((nsresult) 0x80010010L) + +/* Returned when a proxy could not be create a proxy for one of the OUT parameters + This is returned only when the "real" meathod has ALREADY been invoked. +*/ + +#define NS_ERROR_PROXY_INVALID_OUT_PARAMETER ((nsresult) 0x80010011L) + + +/*@}*/ + + /* I/O Errors */ + + /* Stream closed */ +#define NS_BASE_STREAM_CLOSED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) + /* Error from the operating system */ +#define NS_BASE_STREAM_OSERROR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3) + /* Illegal arguments */ +#define NS_BASE_STREAM_ILLEGAL_ARGS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 4) + /* For unichar streams */ +#define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5) + /* For unichar streams */ +#define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6) + +#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 7) + + +#define NS_ERROR_FILE_UNRECOGNIZED_PATH NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 1) +#define NS_ERROR_FILE_UNRESOLVABLE_SYMLINK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 2) +#define NS_ERROR_FILE_EXECUTION_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 3) +#define NS_ERROR_FILE_UNKNOWN_TYPE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 4) +#define NS_ERROR_FILE_DESTINATION_NOT_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 5) +#define NS_ERROR_FILE_TARGET_DOES_NOT_EXIST NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 6) +#define NS_ERROR_FILE_COPY_OR_MOVE_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 7) +#define NS_ERROR_FILE_ALREADY_EXISTS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 8) +#define NS_ERROR_FILE_INVALID_PATH NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 9) +#define NS_ERROR_FILE_DISK_FULL NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 10) +#define NS_ERROR_FILE_CORRUPTED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 11) +#define NS_ERROR_FILE_NOT_DIRECTORY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 12) +#define NS_ERROR_FILE_IS_DIRECTORY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 13) +#define NS_ERROR_FILE_IS_LOCKED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 14) +#define NS_ERROR_FILE_TOO_BIG NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 15) +#define NS_ERROR_FILE_NO_DEVICE_SPACE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 16) +#define NS_ERROR_FILE_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 17) +#define NS_ERROR_FILE_NOT_FOUND NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 18) +#define NS_ERROR_FILE_READ_ONLY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 19) +#define NS_ERROR_FILE_DIR_NOT_EMPTY NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 20) +#define NS_ERROR_FILE_ACCESS_DENIED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 21) + +#define NS_SUCCESS_FILE_DIRECTORY_EMPTY NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_FILES, 1) + + /* Result codes used by nsIVariant */ + +#define NS_ERROR_CANNOT_CONVERT_DATA NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 1) +#define NS_ERROR_OBJECT_IS_IMMUTABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 2) +#define NS_ERROR_LOSS_OF_SIGNIFICANT_DATA NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 3) + +#define NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 1) + + + /* + * This will return the nsresult corresponding to the most recent NSPR failure + * returned by PR_GetError. + * + *********************************************************************** + * Do not depend on this function. It will be going away! + *********************************************************************** + */ +extern NS_COM nsresult +NS_ErrorAccordingToNSPR(); + + +#ifdef _MSC_VER +#pragma warning(disable: 4251) /* 'nsCOMPtr' needs to have dll-interface to be used by clients of class 'nsInputStream' */ +#pragma warning(disable: 4275) /* non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode' */ +#endif + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp b/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp new file mode 100644 index 00000000..f38495ed --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsErrorService.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsErrorService.h" +#include "nsCRT.h" + +static void* PR_CALLBACK +CloneCString(nsHashKey *aKey, void *aData, void* closure) +{ + return nsCRT::strdup((const char*)aData); +} + +static PRBool PR_CALLBACK +DeleteCString(nsHashKey *aKey, void *aData, void* closure) +{ + nsCRT::free((char*)aData); + return PR_TRUE; +} + +nsInt2StrHashtable::nsInt2StrHashtable() + : mHashtable(CloneCString, nsnull, DeleteCString, nsnull, 16) +{ +} + +nsresult +nsInt2StrHashtable::Put(PRUint32 key, const char* aData) +{ + char* value = nsCRT::strdup(aData); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + nsPRUint32Key k(key); + char* oldValue = (char*)mHashtable.Put(&k, value); + if (oldValue) + nsCRT::free(oldValue); + return NS_OK; +} + +char* +nsInt2StrHashtable::Get(PRUint32 key) +{ + nsPRUint32Key k(key); + const char* value = (const char*)mHashtable.Get(&k); + if (value == nsnull) + return nsnull; + return nsCRT::strdup(value); +} + +nsresult +nsInt2StrHashtable::Remove(PRUint32 key) +{ + nsPRUint32Key k(key); + char* oldValue = (char*)mHashtable.Remove(&k); + if (oldValue) + nsCRT::free(oldValue); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMPL_ISUPPORTS1(nsErrorService, nsIErrorService) + +NS_METHOD +nsErrorService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_NO_AGGREGATION(outer); + nsErrorService* serv = new nsErrorService(); + if (serv == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(serv); + nsresult rv = serv->QueryInterface(aIID, aInstancePtr); + NS_RELEASE(serv); + return rv; +} + +NS_IMETHODIMP +nsErrorService::RegisterErrorStringBundle(PRInt16 errorModule, const char *stringBundleURL) +{ + return mErrorStringBundleURLMap.Put(errorModule, stringBundleURL); +} + +NS_IMETHODIMP +nsErrorService::UnregisterErrorStringBundle(PRInt16 errorModule) +{ + return mErrorStringBundleURLMap.Remove(errorModule); +} + +NS_IMETHODIMP +nsErrorService::GetErrorStringBundle(PRInt16 errorModule, char **result) +{ + char* value = mErrorStringBundleURLMap.Get(errorModule); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = value; + return NS_OK; +} + +NS_IMETHODIMP +nsErrorService::RegisterErrorStringBundleKey(nsresult error, const char *stringBundleKey) +{ + return mErrorStringBundleKeyMap.Put(error, stringBundleKey); +} + +NS_IMETHODIMP +nsErrorService::UnregisterErrorStringBundleKey(nsresult error) +{ + return mErrorStringBundleKeyMap.Remove(error); +} + +NS_IMETHODIMP +nsErrorService::GetErrorStringBundleKey(nsresult error, char **result) +{ + char* value = mErrorStringBundleKeyMap.Get(error); + if (value == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = value; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/base/nsErrorService.h b/src/libs/xpcom18a4/xpcom/base/nsErrorService.h new file mode 100644 index 00000000..70a30c0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsErrorService.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsErrorService_h__ +#define nsErrorService_h__ + +#include "nsIErrorService.h" +#include "nsHashtable.h" + +class nsInt2StrHashtable +{ +public: + nsInt2StrHashtable(); + + nsresult Put(PRUint32 key, const char* aData); + char* Get(PRUint32 key); + nsresult Remove(PRUint32 key); + +protected: + nsObjectHashtable mHashtable; +}; + +class nsErrorService : public nsIErrorService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIERRORSERVICE + + nsErrorService() {} + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsErrorService() {} + +protected: + nsInt2StrHashtable mErrorStringBundleURLMap; + nsInt2StrHashtable mErrorStringBundleKeyMap; +}; + +#endif // nsErrorService_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp new file mode 100644 index 00000000..f68f2d5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp @@ -0,0 +1,383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsExceptionService.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "prthread.h" +#include "prlock.h" +static const PRUintn BAD_TLS_INDEX = (PRUintn) -1; + +#define CHECK_SERVICE_USE_OK() if (tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED +#define CHECK_MANAGER_USE_OK() if (!mService || nsExceptionService::tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED + +// A key for our registered module providers hashtable +class nsProviderKey : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsProviderKey(PRUint32 key) : mKey(key) {} + PRUint32 HashCode(void) const { + return mKey; + } + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsProviderKey *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsProviderKey(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + +/** Exception Manager definition **/ +class nsExceptionManager : public nsIExceptionManager +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEXCEPTIONMANAGER + + nsExceptionManager(nsExceptionService *svc); + /* additional members */ + nsCOMPtr mCurrentException; + nsExceptionManager *mNextThread; // not ref-counted. + nsExceptionService *mService; // not ref-counted +#ifdef NS_DEBUG + static PRInt32 totalInstances; +#endif + +#ifdef NS_DEBUG + inline nsrefcnt ReleaseQuiet() { + // shut up NS_ASSERT_OWNINGTHREAD (see explanation below) + nsAutoOwningThread old = _mOwningThread; + _mOwningThread = nsAutoOwningThread(); + nsrefcnt ref = Release(); + NS_ASSERTION(ref == 0, "the object is still referenced by other threads while it shouldn't"); + if (ref != 0) + _mOwningThread = old; + return ref; + } +#else + inline nsrefcnt ReleaseQuiet(void) { return Release(); } +#endif + +private: + ~nsExceptionManager(); +}; + + +#ifdef NS_DEBUG +PRInt32 nsExceptionManager::totalInstances = 0; +#endif + +// Note: the nsExceptionManager object is single threaded - the exception +// service itself ensures one per thread. However, there are two methods that +// may be called on foreign threads: DropAllThreads (called on the thread +// shutting down xpcom) and ThreadDestruct (called after xpcom destroyed the +// internal thread struct, so that PR_GetCurrentThread() will create a new one +// from scratch which will obviously not match the old one stored in the +// instance on creation). In both cases, there should be no other threads +// holding objects (i.e. it's thread-safe to call them), but +// NS_CheckThreadSafe() assertions will still happen and yell in the debug +// build. Since it is quite annoying, we use a special ReleaseQuiet() method +// in DoDropThread() to shut them up. +NS_IMPL_THREADSAFE_ISUPPORTS1(nsExceptionManager, nsIExceptionManager) + +nsExceptionManager::nsExceptionManager(nsExceptionService *svc) : + mNextThread(nsnull), + mService(svc) +{ + /* member initializers and constructor code */ +#ifdef NS_DEBUG + PR_AtomicIncrement(&totalInstances); +#endif +} + +nsExceptionManager::~nsExceptionManager() +{ + /* destructor code */ +#ifdef NS_DEBUG + PR_AtomicDecrement(&totalInstances); +#endif // NS_DEBUG +} + +/* void setCurrentException (in nsIException error); */ +NS_IMETHODIMP nsExceptionManager::SetCurrentException(nsIException *error) +{ + CHECK_MANAGER_USE_OK(); + mCurrentException = error; + return NS_OK; +} + +/* nsIException getCurrentException (); */ +NS_IMETHODIMP nsExceptionManager::GetCurrentException(nsIException **_retval) +{ + CHECK_MANAGER_USE_OK(); + *_retval = mCurrentException; + NS_IF_ADDREF(*_retval); + return NS_OK; +} + +/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */ +NS_IMETHODIMP nsExceptionManager::GetExceptionFromProvider(nsresult rc, nsIException * defaultException, nsIException **_retval) +{ + CHECK_MANAGER_USE_OK(); + // Just delegate back to the service with the provider map. + return mService->GetExceptionFromProvider(rc, defaultException, _retval); +} + +/* The Exception Service */ + +PRUintn nsExceptionService::tlsIndex = BAD_TLS_INDEX; +PRLock *nsExceptionService::lock = nsnull; +nsExceptionManager *nsExceptionService::firstThread = nsnull; + +#ifdef NS_DEBUG +PRInt32 nsExceptionService::totalInstances = 0; +#endif + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsExceptionService, nsIExceptionService, nsIObserver) + +nsExceptionService::nsExceptionService() + : mProviders(4, PR_TRUE) /* small, thread-safe hashtable */ +{ +#ifdef NS_DEBUG + if (PR_AtomicIncrement(&totalInstances)!=1) { + NS_ERROR("The nsExceptionService is a singleton!"); + } +#endif + /* member initializers and constructor code */ + if (tlsIndex == BAD_TLS_INDEX) { + PRStatus status; + status = PR_NewThreadPrivateIndex( &tlsIndex, ThreadDestruct ); + NS_WARN_IF_FALSE(status==0, "ScriptErrorService could not allocate TLS storage."); + } + lock = PR_NewLock(); + NS_WARN_IF_FALSE(lock, "Error allocating ExceptionService lock"); + + // observe XPCOM shutdown. + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + NS_WARN_IF_FALSE(observerService, "Could not get observer service!"); + if (observerService) + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); +} + +nsExceptionService::~nsExceptionService() +{ + Shutdown(); + if (lock) { + PRLock *tmp = lock; + lock = nsnull; + PR_DestroyLock(tmp); + } + /* destructor code */ +#ifdef NS_DEBUG + PR_AtomicDecrement(&totalInstances); +#endif +} + +/*static*/ +void nsExceptionService::ThreadDestruct( void *data ) +{ + if (!lock) { + NS_WARNING("nsExceptionService ignoring thread destruction after shutdown"); + return; + } + DropThread( (nsExceptionManager *)data ); +} + + +void nsExceptionService::Shutdown() +{ + PRUintn tmp = tlsIndex; + tlsIndex = BAD_TLS_INDEX; + PR_SetThreadPrivate(tmp, nsnull); + mProviders.Reset(); + if (lock) { + DropAllThreads(); + } +} + +/* void setCurrentException (in nsIException error); */ +NS_IMETHODIMP nsExceptionService::SetCurrentException(nsIException *error) +{ + CHECK_SERVICE_USE_OK(); + nsCOMPtr sm; + nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm)); + if (NS_FAILED(nr)) + return nr; + return sm->SetCurrentException(error); +} + +/* nsIException getCurrentException (); */ +NS_IMETHODIMP nsExceptionService::GetCurrentException(nsIException **_retval) +{ + CHECK_SERVICE_USE_OK(); + nsCOMPtr sm; + nsresult nr = GetCurrentExceptionManager(getter_AddRefs(sm)); + if (NS_FAILED(nr)) + return nr; + return sm->GetCurrentException(_retval); +} + +/* nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); */ +NS_IMETHODIMP nsExceptionService::GetExceptionFromProvider(nsresult rc, + nsIException * defaultException, nsIException **_retval) +{ + CHECK_SERVICE_USE_OK(); + return DoGetExceptionFromProvider(rc, defaultException, _retval); +} + +/* readonly attribute nsIExceptionManager currentExceptionManager; */ +NS_IMETHODIMP nsExceptionService::GetCurrentExceptionManager(nsIExceptionManager * *aCurrentScriptManager) +{ + CHECK_SERVICE_USE_OK(); + nsExceptionManager *mgr = (nsExceptionManager *)PR_GetThreadPrivate(tlsIndex); + if (mgr == nsnull) { + // Stick the new exception object in with no reference count. + mgr = new nsExceptionManager(this); + if (mgr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + PR_SetThreadPrivate(tlsIndex, mgr); + // The reference count is held in the thread-list + AddThread(mgr); + } + *aCurrentScriptManager = mgr; + NS_ADDREF(*aCurrentScriptManager); + return NS_OK; +} + +/* void registerErrorProvider (in nsIExceptionProvider provider, in PRUint32 moduleCode); */ +NS_IMETHODIMP nsExceptionService::RegisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule) +{ + CHECK_SERVICE_USE_OK(); + + nsProviderKey key(errorModule); + if (mProviders.Put(&key, provider)) { + NS_WARNING("Registration of exception provider overwrote another provider with the same module code!"); + } + return NS_OK; +} + +/* void unregisterErrorProvider (in nsIExceptionProvider provider, in PRUint32 errorModule); */ +NS_IMETHODIMP nsExceptionService::UnregisterExceptionProvider(nsIExceptionProvider *provider, PRUint32 errorModule) +{ + CHECK_SERVICE_USE_OK(); + nsProviderKey key(errorModule); + if (!mProviders.Remove(&key)) { + NS_WARNING("Attempt to unregister an unregistered exception provider!"); + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +// nsIObserver +NS_IMETHODIMP nsExceptionService::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) +{ + Shutdown(); + return NS_OK; +} + +nsresult +nsExceptionService::DoGetExceptionFromProvider(nsresult errCode, + nsIException * defaultException, + nsIException **_exc) +{ + // Check for an existing exception + nsresult nr = GetCurrentException(_exc); + if (NS_SUCCEEDED(nr) && *_exc) { + (*_exc)->GetResult(&nr); + // If it matches our result then use it + if (nr == errCode) + return NS_OK; + NS_RELEASE(*_exc); + } + nsProviderKey key(NS_ERROR_GET_MODULE(errCode)); + nsCOMPtr provider = + dont_AddRef((nsIExceptionProvider *)mProviders.Get(&key)); + + // No provider so we'll return the default exception + if (!provider) { + *_exc = defaultException; + NS_IF_ADDREF(*_exc); + return NS_OK; + } + + return provider->GetException(errCode, defaultException, _exc); +} + +// thread management +/*static*/ void nsExceptionService::AddThread(nsExceptionManager *thread) +{ + PR_Lock(lock); + thread->mNextThread = firstThread; + firstThread = thread; + NS_ADDREF(thread); + PR_Unlock(lock); +} + +/*static*/ void nsExceptionService::DoDropThread(nsExceptionManager *thread) +{ + nsExceptionManager **emp = &firstThread; + while (*emp != thread) { + if (!*emp) + { + NS_WARNING("Could not find the thread to drop!"); + return; + } + emp = &(*emp)->mNextThread; + } + *emp = thread->mNextThread; + thread->ReleaseQuiet(); + thread = nsnull; +} + +/*static*/ void nsExceptionService::DropThread(nsExceptionManager *thread) +{ + PR_Lock(lock); + DoDropThread(thread); + PR_Unlock(lock); +} + +/*static*/ void nsExceptionService::DropAllThreads() +{ + PR_Lock(lock); + while (firstThread) + DoDropThread(firstThread); + PR_Unlock(lock); +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h new file mode 100644 index 00000000..441a4c5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsExceptionService_h__ +#define nsExceptionService_h__ + +#include "nsVoidArray.h" +#include "nsIException.h" +#include "nsIExceptionService.h" +#include "nsIObserverService.h" +#include "nsHashtable.h" +#include "nsIObserver.h" + +class nsExceptionManager; + +/** Exception Service definition **/ +class nsExceptionService : public nsIExceptionService, public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIEXCEPTIONSERVICE + NS_DECL_NSIEXCEPTIONMANAGER + NS_DECL_NSIOBSERVER + + nsExceptionService(); + + /* additional members */ + nsresult DoGetExceptionFromProvider(nsresult errCode, + nsIException *defaultException, + nsIException **_richError); + void Shutdown(); + + + /* thread management and cleanup */ + static void AddThread(nsExceptionManager *); + static void DropThread(nsExceptionManager *); + static void DoDropThread(nsExceptionManager *thread); + + static void DropAllThreads(); + static nsExceptionManager *firstThread; + + nsSupportsHashtable mProviders; + + /* single lock protects both providers hashtable + and thread list */ + static PRLock* lock; + + static PRUintn tlsIndex; + static void PR_CALLBACK ThreadDestruct( void *data ); +#ifdef NS_DEBUG + static PRInt32 totalInstances; +#endif + +private: + ~nsExceptionService(); +}; + + +#endif // nsExceptionService_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c b/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c new file mode 100644 index 00000000..b0447598 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsGarbageCollector.c @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + nsGarbageCollector.c + */ + +#ifdef GC_LEAK_DETECTOR + +/* for FILE */ +#include + +/* NSPR stuff */ +#include "generic_threads.h" +#include "prthread.h" +#include "prlock.h" + +/* Linux/Win32 export private NSPR files to include/private */ +#ifdef XP_MAC +#include "pprthred.h" +#else +#include "private/pprthred.h" +#endif + +#include "nsLeakDetector.h" + +extern FILE *GC_stdout, *GC_stderr; + +extern void GC_gcollect(void); +extern void GC_clear_roots(void); + +static PRStatus PR_CALLBACK scanner(PRThread* t, void** baseAddr, PRUword count, void* closure) +{ + char* begin = (char*)baseAddr; + char* end = (char*)(baseAddr + count); + GC_mark_range_proc marker = (GC_mark_range_proc) closure; + marker(begin, end); + return PR_SUCCESS; +} + +static void mark_all_stacks(GC_mark_range_proc marker) +{ + /* PR_ThreadScanStackPointers(PR_GetCurrentThread(), &scanner, marker); */ + PR_ScanStackPointers(&scanner, (void *)marker); +} + +static void locker(void* mutex) +{ + PR_Lock(mutex); +} + +static void unlocker(void* mutex) +{ + PR_Unlock(mutex); +} + +static void stopper(void* unused) +{ + PR_SuspendAll(); +} + +static void starter(void* unused) +{ + PR_ResumeAll(); +} + +nsresult NS_InitGarbageCollector() +{ + PRLock* mutex; + + /* redirect GC's stderr to catch startup leaks. */ + GC_stderr = fopen("StartupLeaks", "w"); + + mutex = PR_NewLock(); + if (mutex == NULL) + return NS_ERROR_FAILURE; + + GC_generic_init_threads(&mark_all_stacks, mutex, + &locker, &unlocker, + &stopper, &starter); + + return NS_OK; +} + +nsresult NS_ShutdownGarbageCollector() +{ + /* do anything you need to shut down the collector. */ + return NS_OK; +} + +#endif /* GC_LEAK_DETECTOR */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h b/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h new file mode 100644 index 00000000..2195f42d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIAllocator.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 This file is obsolete. Use nsIMemory.idl or nsMemory.h instead. + */ + +#ifndef nsIAllocator_h___ +#define nsIAllocator_h___ + +#include "nsMemory.h" + +#define nsIAllocator nsIMemory +#define nsAllocator nsMemory +#define GetGlobalAllocator GetGlobalMemoryService + +#define NS_IALLOCATOR_IID NS_GET_IID(nsIMemory) +#define NS_ALLOCATOR_CONTRACTID NS_MEMORY_CONTRACTID +#define NS_ALLOCATOR_CLASSNAME NS_MEMORY_CLASSNAME +#define NS_ALLOCATOR_CID NS_MEMORY_CID + +#endif /* nsIAllocator_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl new file mode 100644 index 00000000..f983132d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleListener.idl @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Used by the console service to notify listeners of new console messages. + */ + +#include "nsISupports.idl" +#include "nsIConsoleMessage.idl" + +[scriptable, uuid(eaaf61d6-1dd1-11b2-bc6e-8fc96480f20d)] +interface nsIConsoleListener : nsISupports +{ + void observe(in nsIConsoleMessage aMessage); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl new file mode 100644 index 00000000..0662a2d2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleMessage.idl @@ -0,0 +1,56 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * This is intended as a base interface; implementations may want to + * provide an object that can be qi'ed to provide more specific + * message information. + */ +[scriptable, uuid(41bd8784-1dd2-11b2-9553-8606958fffe1)] +interface nsIConsoleMessage : nsISupports +{ + readonly attribute wstring message; +}; + +%{ C++ +#define NS_CONSOLEMESSAGE_CID \ +{ 0x56c9d666, 0x1dd2, 0x11b2, { 0xb4, 0x3c, 0xa8, 0x4b, 0xf3, 0xb3, 0xec, 0xbb }} + +#define NS_CONSOLEMESSAGE_CONTRACTID "@mozilla.org/consolemessage;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl b/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl new file mode 100644 index 00000000..283c7acc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIConsoleService.idl @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIConsoleListener.idl" +#include "nsIConsoleMessage.idl" + +[scriptable, uuid(a647f184-1dd1-11b2-a9d1-8537b201161b)] +interface nsIConsoleService : nsISupports +{ + void logMessage(in nsIConsoleMessage message); + + /** + * Convenience method for logging simple messages. + */ + void logStringMessage(in wstring message); + + /** + * Get an array of all the messages logged so far. If no messages + * are logged, this function will return a count of 0, but still + * will allocate one word for messages, so as to show up as a + * 0-length array when called from script. + */ + void getMessageArray([array, size_is(count)] out nsIConsoleMessage messages, + out PRUint32 count); + + /** + * To guard against stack overflows from listeners that could log + * messages (it's easy to do this inadvertently from listeners + * implemented in JavaScript), we don't call any listeners when + * another error is already being logged. + */ + void registerListener(in nsIConsoleListener listener); + + /** + * Each registered listener should also be unregistered. + */ + void unregisterListener(in nsIConsoleListener listener); + +}; + + +%{ C++ +#define NS_CONSOLESERVICE_CLASSNAME "Console Service" + +#define NS_CONSOLESERVICE_CID \ +{ 0x7e3ff85c, 0x1dd2, 0x11b2, { 0x8d, 0x4b, 0xeb, 0x45, 0x2c, 0xb0, 0xff, 0x40 }} + +#define NS_CONSOLESERVICE_CONTRACTID "@mozilla.org/consoleservice;1" +%} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsID.cpp b/src/libs/xpcom18a4/xpcom/base/nsID.cpp new file mode 100644 index 00000000..adb0d41c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsID.cpp @@ -0,0 +1,152 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Bratell + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsID.h" +#include "prprf.h" +#include "prmem.h" + +static const char gIDFormat[] = + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"; + +static const char gIDFormat2[] = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + + +/** + * Multiplies the_int_var with 16 (0x10) and adds the value of the + * hexadecimal digit the_char. If it fails it returns PR_FALSE from + * the function it's used in. + */ + +#define ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(the_char, the_int_var) \ + the_int_var = (the_int_var << 4) + the_char; \ + if(the_char >= '0' && the_char <= '9') the_int_var -= '0'; \ + else if(the_char >= 'a' && the_char <= 'f') the_int_var -= 'a'-10; \ + else if(the_char >= 'A' && the_char <= 'F') the_int_var -= 'A'-10; \ + else return PR_FALSE + + +/** + * Parses number_of_chars characters from the char_pointer pointer and + * puts the number in the dest_variable. The pointer is moved to point + * at the first character after the parsed ones. If it fails it returns + * PR_FALSE from the function the macro is used in. + */ + +#define PARSE_CHARS_TO_NUM(char_pointer, dest_variable, number_of_chars) \ + do { PRInt32 _i=number_of_chars; \ + dest_variable = 0; \ + while(_i) { \ + ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(*char_pointer, dest_variable); \ + char_pointer++; \ + _i--; \ + } } while(0) + + +/** + * Parses a hyphen from the char_pointer string. If there is no hyphen there + * the function returns PR_FALSE from the function it's used in. The + * char_pointer is advanced one step. + */ + + #define PARSE_HYPHEN(char_pointer) if(*(char_pointer++) != '-') return PR_FALSE + +/* + * Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} string into + * an nsID. It can also handle the old format without the { and }. + */ + +NS_COM PRBool nsID::Parse(const char *aIDStr) +{ + /* Optimized for speed */ + if(!aIDStr) { + return PR_FALSE; + } + + PRBool expectFormat1 = (aIDStr[0] == '{'); + if(expectFormat1) aIDStr++; + + PARSE_CHARS_TO_NUM(aIDStr, m0, 8); + PARSE_HYPHEN(aIDStr); + PARSE_CHARS_TO_NUM(aIDStr, m1, 4); + PARSE_HYPHEN(aIDStr); + PARSE_CHARS_TO_NUM(aIDStr, m2, 4); + PARSE_HYPHEN(aIDStr); + int i; + for(i=0; i<2; i++) + PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2); + PARSE_HYPHEN(aIDStr); + while(i < 8) { + PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2); + i++; + } + + return expectFormat1 ? *aIDStr == '}' : PR_TRUE; +} + +/* + * Returns an allocated string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + * format. The string is allocated with PR_Malloc and should be freed by + * the caller. + */ + +NS_COM char *nsID::ToString() const +{ + char *res = (char*)PR_Malloc(39); // use PR_Malloc if this is to be freed with nsCRT::free + + if (res != NULL) { + PR_snprintf(res, 39, gIDFormat, + m0, (PRUint32) m1, (PRUint32) m2, + (PRUint32) m3[0], (PRUint32) m3[1], (PRUint32) m3[2], + (PRUint32) m3[3], (PRUint32) m3[4], (PRUint32) m3[5], + (PRUint32) m3[6], (PRUint32) m3[7]); + } + return res; +} + +#ifdef VBOX +void nsID::ToProvidedString(char (&dest)[NSID_LENGTH]) const +{ + PR_snprintf(dest, NSID_LENGTH, gIDFormat, + m0, (PRUint32) m1, (PRUint32) m2, + (PRUint32) m3[0], (PRUint32) m3[1], (PRUint32) m3[2], + (PRUint32) m3[3], (PRUint32) m3[4], (PRUint32) m3[5], + (PRUint32) m3[6], (PRUint32) m3[7]); +} +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsID.h b/src/libs/xpcom18a4/xpcom/base/nsID.h new file mode 100644 index 00000000..257ba927 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsID.h @@ -0,0 +1,166 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsID_h__ +#define nsID_h__ + +#include + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifdef VBOX +#define NSID_LENGTH 39 +#endif + +/** + * A "unique identifier". This is modeled after OSF DCE UUIDs. + * @status FROZEN + */ + +struct nsID { + /** + * @name Indentifier values + */ + + //@{ + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; + //@} + + /** + * @name Methods + */ + + //@{ + /** + * Equivalency method. Compares this nsID with another. + * @return PR_TRUE if they are the same, PR_FALSE if not. + */ + + inline PRBool Equals(const nsID& other) const { + // One would think that this could be done faster with a really + // efficient implementation of memcmp(), but evidently no + // memcmp()'s out there are better than this code. + // + // See bug http://bugzilla.mozilla.org/show_bug.cgi?id=164580 for + // details. + + return (PRBool) + ((((PRUint32*) &m0)[0] == ((PRUint32*) &other.m0)[0]) && + (((PRUint32*) &m0)[1] == ((PRUint32*) &other.m0)[1]) && + (((PRUint32*) &m0)[2] == ((PRUint32*) &other.m0)[2]) && + (((PRUint32*) &m0)[3] == ((PRUint32*) &other.m0)[3])); + } + + /** + * nsID Parsing method. Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + * string into an nsID + */ + NS_COM PRBool Parse(const char *aIDStr); + + /** + * nsID string encoder. Returns an allocated string in + * {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format. Caller should free string. + */ + NS_COM char* ToString() const; + +#ifdef VBOX + /** + * nsID string encoder. Builds a string in + * {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format, into a char[NSID_LENGTH] + * buffer provided by the caller (for instance, on the stack). + */ + NS_COM void ToProvidedString(char (&dest)[NSID_LENGTH]) const; +#endif + + //@} +}; + +/* + * Class IDs + */ + +typedef nsID nsCID; + +// Define an CID +#define NS_DEFINE_CID(_name, _cidspec) \ + const nsCID _name = _cidspec + +#define REFNSCID const nsCID& + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + */ + +typedef nsID nsIID; + +/** + * A macro shorthand for const nsIID& + */ + +#define REFNSIID const nsIID& + +/** + * Define an IID + * obsolete - do not use this macro + */ + +#define NS_DEFINE_IID(_name, _iidspec) \ + const nsIID _name = _iidspec + +/** + * A macro to build the static const IID accessor method + */ + +#define NS_DEFINE_STATIC_IID_ACCESSOR(the_iid) \ + static const nsIID& GetIID() {static const nsIID iid = the_iid; return iid;} + +/** + * A macro to build the static const CID accessor method + */ + +#define NS_DEFINE_STATIC_CID_ACCESSOR(the_cid) \ + static const nsID& GetCID() {static const nsID cid = the_cid; return cid;} + +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl b/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl new file mode 100644 index 00000000..73b3912a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIDebug.idl @@ -0,0 +1,67 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 "nsISupports.idl" + +/** + * nsIDebug is an interface between XPCOM Glue and XPCOM. Users should access + * the nsIDebug interface through the static class nsDebug. + * @see nsDebug.h + * + * @status UNDER_REVIEW + * + */ + +[scriptable, uuid(3bf0c3d7-3bd9-4cf2-a971-33572c503e1e)] +interface nsIDebug : nsISupports +{ + void assertion(in string aStr, + in string aExpr, + in string aFile, + in long aLine); + + void warning(in string aStr, + in string aFile, + in long aLine); + + void break(in string aFile, + in long aLine); + + void abort(in string aFile, + in long aLine); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl b/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl new file mode 100644 index 00000000..c4ed3964 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIErrorService.idl @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * nsIErrorService: This is an interim service that allows nsresult codes to be mapped to + * string bundles that can be used to look up error messages. String bundle keys can also + * be mapped. + * + * This service will eventually get replaced by extending xpidl to allow errors to be defined. + * (http://bugzilla.mozilla.org/show_bug.cgi?id=13423). + */ +[scriptable, uuid(e72f94b2-5f85-11d4-9877-00c04fa0cf4a)] +interface nsIErrorService : nsISupports +{ + /** + * Registers a string bundle URL for an error module. Error modules are obtained from + * nsresult code with NS_ERROR_GET_MODULE. + */ + void registerErrorStringBundle(in short errorModule, in string stringBundleURL); + + /** + * Registers a string bundle URL for an error module. + */ + void unregisterErrorStringBundle(in short errorModule); + + /** + * Retrieves a string bundle URL for an error module. + */ + string getErrorStringBundle(in short errorModule); + + /** + * Registers a key in a string bundle for an nsresult error code. Only the code portion + * of the nsresult is used (obtained with NS_ERROR_GET_CODE) in this registration. The + * string bundle key is used to look up internationalized messages in the string bundle. + */ + void registerErrorStringBundleKey(in nsresult error, in string stringBundleKey); + + /** + * Unregisters a key in a string bundle for an nsresult error code. + */ + void unregisterErrorStringBundleKey(in nsresult error); + + /** + * Retrieves a key in a string bundle for an nsresult error code. If no key is registered + * for the specified nsresult's code (obtained with NS_ERROR_GET_CODE), then the stringified + * version of the nsresult code is returned. + */ + string getErrorStringBundleKey(in nsresult error); +}; + +%{C++ + +// The global nsIErrorService: +#define NS_ERRORSERVICE_NAME "Error Service" +#define NS_ERRORSERVICE_CONTRACTID "@mozilla.org/xpcom/error-service;1" +#define NS_ERRORSERVICE_CID \ +{ /* 744afd5e-5f8c-11d4-9877-00c04fa0cf4a */ \ + 0x744afd5e, \ + 0x5f8c, \ + 0x11d4, \ + {0x98, 0x77, 0x00, 0xc0, 0x4f, 0xa0, 0xcf, 0x4a} \ +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIException.idl b/src/libs/xpcom18a4/xpcom/base/nsIException.idl new file mode 100644 index 00000000..affbb36e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIException.idl @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Interfaces for representing cross-language exceptions and stack traces. + */ + + +#include "nsISupports.idl" +#include "nsIProgrammingLanguage.idl" + +// XXX - most "string"s in this file should probably move to Unicode +// so may as well use AStrings... + + +[scriptable, uuid(91d82105-7c62-4f8b-9779-154277c0ee90)] +interface nsIStackFrame : nsISupports +{ + // see nsIProgrammingLanguage for list of language consts + readonly attribute PRUint32 language; + readonly attribute string languageName; + readonly attribute string filename; + readonly attribute string name; + // Valid line numbers begin at '1'. '0' indicates unknown. + readonly attribute PRInt32 lineNumber; + readonly attribute string sourceLine; + readonly attribute nsIStackFrame caller; + + string toString(); +}; + +[scriptable, uuid(F3A8D3B4-C424-4edc-8BF6-8974C983BA78)] +interface nsIException : nsISupports +{ + // A custom message set by the thrower. + readonly attribute string message; + // The nsresult associated with this exception. + readonly attribute nsresult result; + // The name of the error code (ie, a string repr of |result|) + readonly attribute string name; + + // Filename location. This is the location that caused the + // error, which may or may not be a source file location. + // For example, standard language errors would generally have + // the same location as their top stack entry. File + // parsers may put the location of the file they were parsing, + // etc. + + // null indicates "no data" + readonly attribute string filename; + // Valid line numbers begin at '1'. '0' indicates unknown. + readonly attribute PRUint32 lineNumber; + // Valid column numbers begin at 0. + // We don't have an unambiguous indicator for unknown. + readonly attribute PRUint32 columnNumber; + + // A stack trace, if available. + readonly attribute nsIStackFrame location; + // An inner exception that triggered this, if available. + readonly attribute nsIException inner; + + // Arbitary data for the implementation. + readonly attribute nsISupports data; + + // A generic formatter - make it suitable to print, etc. + string toString(); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl b/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl new file mode 100644 index 00000000..22ebe751 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIExceptionService.idl @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * ActiveState Tool Corp.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Hammond + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIException.idl" + +// An exception provider. These can turn special nsresult codes +// into nsIExceptions + +[scriptable, uuid(0577744c-c1d2-47f2-8bcc-ce7a9e5a88fc)] +interface nsIExceptionProvider : nsISupports +{ + /** Gets an nsIException or returns NULL if not possible. **/ + nsIException getException(in nsresult result, in nsIException defaultException); +}; + +// A ScriptErrorManager for a single thread. These objects +// are _not_ thread-safe. Use the ScriptErrorService +// to get a script error manager for your current thread. +[scriptable, uuid(efc9d00b-231c-4feb-852c-ac017266a415)] +interface nsIExceptionManager : nsISupports +{ + /** Sets (or clears with nsnull) the current error on the this thread. */ + void setCurrentException( in nsIException error); + + /** Gets the current error for the current thread, or NULL if no error */ + nsIException getCurrentException(); + + /** Gets an exception from a registered exception provider.. + This has no effect on the "current exception" */ + nsIException getExceptionFromProvider( in nsresult rc, in nsIException defaultException); +}; + + +// The Exception Service. Allows you to get an set exceptions in a thread +// safe manner, or to get an ExceptionManager for your specific thread. +[scriptable, uuid(35A88F54-F267-4414-92A7-191F6454AB52)] +interface nsIExceptionService : nsIExceptionManager +{ + /** Obtains an exception manager for the current thread. */ + readonly attribute nsIExceptionManager currentExceptionManager; + + /** Installs an "exception provider" which is capable of + translating an nsresult into an exception. This enables + error providers to return simple nsresults and only provide + rich errors when specifically requested. It also has the + advantage of allowing code like the DOM to handle all errors + in a single function rather than at each XPCOM entry point. + NOTE: This interface must be thread-safe - it will be called + on whatever thread needs the error translation performed.*/ + void registerExceptionProvider( in nsIExceptionProvider provider, in PRUint32 moduleCode ); + void unregisterExceptionProvider( in nsIExceptionProvider provider, in PRUint32 moduleCode ); +}; + + +%{ C++ +#define NS_EXCEPTIONSERVICE_CLASSNAME "Exception Service" +// {35A88F54-F267-4414-92A7-191F6454AB52} +#define NS_EXCEPTIONSERVICE_CID \ +{ 0x35a88f54, 0xf267, 0x4414, { 0x92, 0xa7, 0x19, 0x1f, 0x64, 0x54, 0xab, 0x52 } } +#define NS_EXCEPTIONSERVICE_CONTRACTID "@mozilla.org/exceptionservice;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsIID.h b/src/libs/xpcom18a4/xpcom/base/nsIID.h new file mode 100644 index 00000000..f00d6b23 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIID.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsIID_h +#define __nsIID_h +#include "nsID.h" +#endif /* __nsIID_h */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl b/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl new file mode 100644 index 00000000..31388643 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIInterfaceRequestor.idl @@ -0,0 +1,72 @@ +/* -*- Mode: IDL; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Travis Bogard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * The nsIInterfaceRequestor interface defines a generic interface for + * requesting interfaces that a given object might provide access to. + * This is very similar to QueryInterface found in nsISupports. + * The main difference is that interfaces returned from GetInterface() + * are not required to provide a way back to the object implementing this + * interface. The semantics of QI() dictate that given an interface A that + * you QI() on to get to interface B, you must be able to QI on B to get back + * to A. This interface however allows you to obtain an interface C from A + * that may or most likely will not have the ability to get back to A. + * + * @status FROZEN + */ + +[scriptable, uuid(033A1470-8B2A-11d3-AF88-00A024FFC08C)] +interface nsIInterfaceRequestor : nsISupports +{ + /** + * Retrieves the specified interface pointer. + * + * @param uuid The IID of the interface being requested. + * @param result [out] The interface pointer to be filled in if + * the interface is accessible. + * @return NS_OK - interface was successfully returned. + * NS_NOINTERFACE - interface not accessible. + * NS_ERROR* - method failure. + */ + void getInterface(in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl b/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl new file mode 100644 index 00000000..6d27fa70 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsILeakDetector.idl @@ -0,0 +1,54 @@ +/* -*- Mode: IDL; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsICollection; + +/** + * Controls the leak detector. + */ +[scriptable, uuid(a2ec052c-1dd1-11b2-9c92-84be252fe47e)] +interface nsILeakDetector : nsISupports { + void dumpLeaks(); + void traceObject(in nsISupports object, in PRBool verbose); + void traceCollection(in nsICollection objects, in PRBool verbose); + void markObject(in nsISupports object, in PRBool marked); + readonly attribute nsISupports services; +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl b/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl new file mode 100644 index 00000000..071aed06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIMemory.idl @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * + * nsIMemory: interface to allocate and deallocate memory. Also provides + * for notifications in low-memory situations. + * + * A client that wishes to be notified of low memory situations (for + * example, because the client maintains a large memory cache that + * could be released when memory is tight) should register with the + * observer service (see nsIObserverService) using the topic + * "memory-pressure". There are three specific types of notications + * that can occur. These types will be passed as the |aData| + * parameter of the of the "memory-pressure" notification: + * + * "low-memory" + * This will be passed as the extra data when the pressure + * observer is being asked to flush for low-memory conditions. + * + * "heap-minimize" + * This will be passed as the extra data when the pressure + * observer is being asked to flush because of a heap minimize + * call. + * + * "alloc-failure" + * This will be passed as the extra data when the pressure + * observer has been asked to flush because a malloc() or + * realloc() has failed. + * + * @status FROZEN + */ + +[scriptable, uuid(59e7e77a-38e4-11d4-8cf5-0060b0fc14a3)] +interface nsIMemory : nsISupports +{ + /** + * Allocates a block of memory of a particular size. If the memory + * cannot be allocated (because of an out-of-memory condition), null + * is returned. + * + * @param size - the size of the block to allocate + * @result the block of memory + */ + [noscript, notxpcom] voidPtr alloc(in size_t size); + + /** + * Reallocates a block of memory to a new size. + * + * @param ptr - the block of memory to reallocate + * @param size - the new size + * @result the reallocated block of memory + * + * If ptr is null, this function behaves like malloc. + * If s is the size of the block to which ptr points, the first + * min(s, size) bytes of ptr's block are copied to the new block. + * If the allocation succeeds, ptr is freed and a pointer to the + * new block returned. If the allocation fails, ptr is not freed + * and null is returned. The returned value may be the same as ptr. + */ + [noscript, notxpcom] voidPtr realloc(in voidPtr ptr, + in size_t newSize); + + /** + * Frees a block of memory. Null is a permissible value, in which case + * nothing happens. + * + * @param ptr - the block of memory to free + */ + [noscript, notxpcom] void free(in voidPtr ptr); + + /** + * Attempts to shrink the heap. + * @param immediate - if true, heap minimization will occur + * immediately if the call was made on the main thread. If + * false, the flush will be scheduled to happen when the app is + * idle. + * @return NS_ERROR_FAILURE if 'immediate' is set an the call + * was not on the application's main thread. + */ + void heapMinimize(in boolean immediate); + + /** + * This predicate can be used to determine if we're in a low-memory + * situation (what constitutes low-memory is platform dependent). This + * can be used to trigger the memory pressure observers. + */ + boolean isLowMemory(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl b/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl new file mode 100644 index 00000000..2fe6fb58 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIProgrammingLanguage.idl @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#ifdef XP_OS2 // OS2 has UNKNOWN problems :) +#undef UNKNOWN +#endif +%} + +/** + * Enumeration of Programming Languages + * @status FROZEN + */ + +[scriptable, uuid(ea604e90-40ba-11d5-90bb-0010a4e73d9a)] +interface nsIProgrammingLanguage : nsISupports +{ + /** + * Identifiers for programming languages. + */ + const PRUint32 UNKNOWN = 0; + const PRUint32 CPLUSPLUS = 1; + const PRUint32 JAVASCRIPT = 2; + const PRUint32 PYTHON = 3; + const PRUint32 PERL = 4; + const PRUint32 JAVA = 5; + const PRUint32 ZX81_BASIC = 6; // it could happen :) + const PRUint32 JAVASCRIPT2 = 7; + // This list can grow indefinitely. Just don't ever change an existing item. + +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupports.idl b/src/libs/xpcom18a4/xpcom/base/nsISupports.idl new file mode 100644 index 00000000..6bf08ac4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupports.idl @@ -0,0 +1,80 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * The mother of all xpcom interfaces. + * @status FROZEN + */ + +/* In order to get both the right typelib and the right header we force +* the 'real' output from xpidl to be commented out in the generated header +* and includes a copy of the original nsISupports.h. This is all just to deal +* with the Mac specific ": public __comobject" thing. +*/ + +#include "nsrootidl.idl" + +%{C++ +/* + * Start commenting out the C++ versions of the below in the output header + */ +#if 0 +%} + +[scriptable, uuid(00000000-0000-0000-c000-000000000046)] +interface nsISupports { + void QueryInterface(in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); + [noscript, notxpcom] nsrefcnt AddRef(); + [noscript, notxpcom] nsrefcnt Release(); +}; + +%{C++ +/* + * End commenting out the C++ versions of the above in the output header + */ +#endif +%} + + +%{C++ +#include "nsISupportsBase.h" + +#ifndef MOZILLA_STRICT_API +#include "nsISupportsUtils.h" +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h b/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h new file mode 100644 index 00000000..bea876f5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupportsBase.h @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 nsISupportsBase_h__ +#define nsISupportsBase_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsID_h__ +#include "nsID.h" +#endif + + +/*@{*/ +/** + * IID for the nsISupports interface + * {00000000-0000-0000-c000-000000000046} + * + * To maintain binary compatibility with COM's IUnknown, we define the IID + * of nsISupports to be the same as that of COM's IUnknown. + */ +#define NS_ISUPPORTS_IID \ + { 0x00000000, 0x0000, 0x0000, \ + {0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} } + +/** + * Reference count values + * + * This is the return type for AddRef() and Release() in nsISupports. + * IUnknown of COM returns an unsigned long from equivalent functions. + * The following ifdef exists to maintain binary compatibility with + * IUnknown. + */ +#if defined(XP_WIN) && PR_BYTES_PER_LONG == 4 +typedef unsigned long nsrefcnt; +#else +typedef PRUint32 nsrefcnt; +#endif + +/** + * Basic component object model interface. Objects which implement + * this interface support runtime interface discovery (QueryInterface) + * and a reference counted memory model (AddRef/Release). This is + * modelled after the win32 IUnknown API. + */ +class NS_NO_VTABLE nsISupports { +public: + + /** + * @name Methods + */ + + //@{ + /** + * A run time mechanism for interface discovery. + * @param aIID [in] A requested interface IID + * @param aInstancePtr [out] A pointer to an interface pointer to + * receive the result. + * @return NS_OK if the interface is supported by the associated + * instance, NS_NOINTERFACE if it is not. + * NS_ERROR_INVALID_POINTER if aInstancePtr is NULL. + */ + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0; + /** + * Increases the reference count for this interface. + * The associated instance will not be deleted unless + * the reference count is returned to zero. + * + * @return The resulting reference count. + */ + NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; + + /** + * Decreases the reference count for this interface. + * Generally, if the reference count returns to zero, + * the associated instance is deleted. + * + * @return The resulting reference count. + */ + NS_IMETHOD_(nsrefcnt) Release(void) = 0; + + //@} +}; +/*@}*/ +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h b/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h new file mode 100644 index 00000000..874d859f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISupportsObsolete.h @@ -0,0 +1,243 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 nsISupportsObsolete_h__ +#define nsISupportsObsolete_h__ + +#include "prcmon.h" + +/////////////////////////////////////////////////////////////////////////////// + + +#define NS_INIT_REFCNT() NS_INIT_ISUPPORTS() + +/** + * Macro to free an array of pointers to nsISupports (or classes + * derived from it). A convenience wrapper around + * NS_FREE_XPCOM_POINTER_ARRAY. + * + * Note that if you know that none of your nsISupports pointers are + * going to be 0, you can gain a bit of speed by calling + * NS_FREE_XPCOM_POINTER_ARRAY directly and using NS_RELEASE as your + * free function. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_IF_RELEASE) + + +/////////////////////////////////////////////////////////////////////////////// + +/* use these functions to associate get/set methods with a + C++ member variable +*/ + +#define NS_METHOD_GETTER(_method, _type, _member) \ +_method(_type* aResult) \ +{\ + if (!aResult) return NS_ERROR_NULL_POINTER; \ + *aResult = _member; \ + return NS_OK; \ +} + +#define NS_METHOD_SETTER(_method, _type, _member) \ +_method(_type aResult) \ +{ \ + _member = aResult; \ + return NS_OK; \ +} + +/* + * special for strings to get/set char* strings + * using PL_strdup and PR_FREEIF + */ +#define NS_METHOD_GETTER_STR(_method,_member) \ +_method(char* *aString) \ +{ \ + if (!aString) return NS_ERROR_NULL_POINTER; \ + if (!(*aString = PL_strdup(_member))) \ + return NS_ERROR_OUT_OF_MEMORY; \ + return NS_OK; \ +} + +#define NS_METHOD_SETTER_STR(_method, _member) \ +_method(const char *aString) \ +{ \ + if (_member) PR_Free(_member); \ + if (!aString) \ + _member = nsnull; \ + else if (!(_member = PL_strdup(aString))) \ + return NS_ERROR_OUT_OF_MEMORY; \ + return NS_OK; \ +} + +/* Getter/Setter macros. + Usage: + NS_IMPL_[CLASS_]GETTER[_](method, [type,] member); + NS_IMPL_[CLASS_]SETTER[_](method, [type,] member); + NS_IMPL_[CLASS_]GETSET[_]([class, ]postfix, [type,] member); + + where: + CLASS_ - implementation is inside a class definition + (otherwise the class name is needed) + Do NOT use in publicly exported header files, because + the implementation may be included many times over. + Instead, use the non-CLASS_ version. + _ - For more complex (STR, IFACE) data types + (otherwise the simple data type is needed) + method - name of the method, such as GetWidth or SetColor + type - simple data type if required + member - class member variable such as m_width or mColor + class - the class name, such as Window or MyObject + postfix - Method part after Get/Set such as "Width" for "GetWidth" + + Example: + class Window { + public: + NS_IMPL_CLASS_GETSET(Width, int, m_width); + NS_IMPL_CLASS_GETTER_STR(GetColor, m_color); + NS_IMETHOD SetColor(char *color); + + private: + int m_width; // read/write + char *m_color; // readonly + }; + + // defined outside of class + NS_IMPL_SETTER_STR(Window::GetColor, m_color); + + Questions/Comments to alecf@netscape.com +*/ + + +/* + * Getter/Setter implementation within a class definition + */ + +/* simple data types */ +#define NS_IMPL_CLASS_GETTER(_method, _type, _member) \ +NS_IMETHOD NS_METHOD_GETTER(_method, _type, _member) + +#define NS_IMPL_CLASS_SETTER(_method, _type, _member) \ +NS_IMETHOD NS_METHOD_SETTER(_method, _type, _member) + +#define NS_IMPL_CLASS_GETSET(_postfix, _type, _member) \ +NS_IMPL_CLASS_GETTER(Get##_postfix, _type, _member) \ +NS_IMPL_CLASS_SETTER(Set##_postfix, _type, _member) + +/* strings */ +#define NS_IMPL_CLASS_GETTER_STR(_method, _member) \ +NS_IMETHOD NS_METHOD_GETTER_STR(_method, _member) + +#define NS_IMPL_CLASS_SETTER_STR(_method, _member) \ +NS_IMETHOD NS_METHOD_SETTER_STR(_method, _member) + +#define NS_IMPL_CLASS_GETSET_STR(_postfix, _member) \ +NS_IMPL_CLASS_GETTER_STR(Get##_postfix, _member) \ +NS_IMPL_CLASS_SETTER_STR(Set##_postfix, _member) + +/* Getter/Setter implementation outside of a class definition */ + +/* simple data types */ +#define NS_IMPL_GETTER(_method, _type, _member) \ +NS_IMETHODIMP NS_METHOD_GETTER(_method, _type, _member) + +#define NS_IMPL_SETTER(_method, _type, _member) \ +NS_IMETHODIMP NS_METHOD_SETTER(_method, _type, _member) + +#define NS_IMPL_GETSET(_class, _postfix, _type, _member) \ +NS_IMPL_GETTER(_class::Get##_postfix, _type, _member) \ +NS_IMPL_SETTER(_class::Set##_postfix, _type, _member) + +/* strings */ +#define NS_IMPL_GETTER_STR(_method, _member) \ +NS_IMETHODIMP NS_METHOD_GETTER_STR(_method, _member) + +#define NS_IMPL_SETTER_STR(_method, _member) \ +NS_IMETHODIMP NS_METHOD_SETTER_STR(_method, _member) + +#define NS_IMPL_GETSET_STR(_class, _postfix, _member) \ +NS_IMPL_GETTER_STR(_class::Get##_postfix, _member) \ +NS_IMPL_SETTER_STR(_class::Set##_postfix, _member) + +/** + * IID for the nsIsThreadsafe interface + * {88210890-47a6-11d2-bec3-00805f8a66dc} + * + * This interface is *only* used for debugging purposes to determine if + * a given component is threadsafe. + */ +#define NS_ISTHREADSAFE_IID \ + { 0x88210890, 0x47a6, 0x11d2, \ + {0xbe, 0xc3, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc} } + +#define NS_LOCK_INSTANCE() \ + PR_CEnterMonitor((void*)this) +#define NS_UNLOCK_INSTANCE() \ + PR_CExitMonitor((void*)this) + +/** + * This implements query interface with two assumptions: First, the + * class in question implements nsISupports and its own interface and + * nothing else. Second, the implementation of the class's primary + * inheritance chain leads to its own interface. + * + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ +#if defined(NS_DEBUG) +#define NS_VERIFY_THREADSAFE_INTERFACE(_iface) \ + if (NULL != (_iface)) { \ + nsISupports* tmp; \ + static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID); \ + NS_PRECONDITION((NS_OK == _iface->QueryInterface(kIsThreadsafeIID, \ + (void**)&tmp)), \ + "Interface is not threadsafe"); \ + } +#else +#define NS_VERIFY_THREADSAFE_INTERFACE(_iface) +#endif + +//////////////////////////////////////////////////////////////////////////////// + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl b/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl new file mode 100644 index 00000000..0351196a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsISystemInfo.idl @@ -0,0 +1,62 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * System information service. + * + * At present, a thin wrapper around PR_GetSystemInfo. + */ + +[scriptable,uuid(4189b420-1dd2-11b2-bff7-daaf5c1f7b10)] +interface nsISystemInfo : nsISupports +{ + /** The system hostname. */ + readonly attribute string hostname; + + /** The operating system name. */ + readonly attribute string OSName; + + /** The operating system version. */ + readonly attribute string OSVersion; + + /** The processor architecture of the machine. */ + readonly attribute string architecture; +}; + diff --git a/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl b/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl new file mode 100644 index 00000000..536861a0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsITraceRefcnt.idl @@ -0,0 +1,72 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 "nsISupports.idl" + +/** + * nsITraceRefcnt is an interface between XPCOM Glue and XPCOM. Users should + * access the nsITraceRefcnt interface through the static class nsTraceRefcnt. + * @see nsTraceRefcnt.h + * + * @status UNDER_REVIEW + */ + +[uuid(273dc92f-0fe6-4545-96a9-21be77828039)] +interface nsITraceRefcnt : nsISupports +{ + void logAddRef(in voidPtr aPtr, + in nsrefcnt aNewRefcnt, + in string aTypeName, + in unsigned long aInstanceSize); + + void logRelease(in voidPtr aPtr, + in nsrefcnt aNewRefcnt, + in string aTypeName); + + void logCtor(in voidPtr aPtr, + in string aTypeName, + in unsigned long aInstanceSize); + + void logDtor(in voidPtr aPtr, + in string aTypeName, + in unsigned long aInstanceSize); + + + void logAddCOMPtr(in voidPtr aPtr, in nsISupports aObject); + + void logReleaseCOMPtr(in voidPtr aPtr, in nsISupports aObject); +}; diff --git a/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl b/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl new file mode 100644 index 00000000..2806fc8a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsIWeakReference.idl @@ -0,0 +1,102 @@ +/* -*- Mode: IDL; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + + +/** + * An instance of |nsIWeakReference| is a proxy object that cooperates with + * its referent to give clients a non-owning, non-dangling reference. Clients + * own the proxy, and should generally manage it with an |nsCOMPtr| (see the + * type |nsWeakPtr| for a |typedef| name that stands out) as they would any + * other XPCOM object. The |QueryReferent| member function provides a + * (hopefully short-lived) owning reference on demand, through which clients + * can get useful access to the referent, while it still exists. + * + * @status FROZEN + * @version 1.0 + * @see nsISupportsWeakReference + * @see nsWeakReference + * @see nsWeakPtr + */ +[scriptable, uuid(9188bc85-f92e-11d2-81ef-0060083a0bcf)] +interface nsIWeakReference : nsISupports + { + /** + * |QueryReferent| queries the referent, if it exists, and like |QueryInterface|, produces + * an owning reference to the desired interface. It is designed to look and act exactly + * like (a proxied) |QueryInterface|. Don't hold on to the produced interface permanently; + * that would defeat the purpose of using a non-owning |nsIWeakReference| in the first place. + */ + void QueryReferent( in nsIIDRef uuid, [iid_is(uuid), retval] out nsQIResult result ); + }; + + +/** + * |nsISupportsWeakReference| is a factory interface which produces appropriate + * instances of |nsIWeakReference|. Weak references in this scheme can only be + * produced for objects that implement this interface. + * + * @status FROZEN + * @version 1.0 + * @see nsIWeakReference + * @see nsSupportsWeakReference + */ +[scriptable, uuid(9188bc86-f92e-11d2-81ef-0060083a0bcf)] +interface nsISupportsWeakReference : nsISupports + { + /** + * |GetWeakReference| produces an appropriate instance of |nsIWeakReference|. + * As with all good XPCOM `getters', you own the resulting interface and should + * manage it with an |nsCOMPtr|. + * + * @see nsIWeakReference + * @see nsWeakPtr + * @see nsCOMPtr + */ + nsIWeakReference GetWeakReference(); + }; + + +%{C++ +#ifndef MOZILLA_STRICT_API +#include "nsIWeakReferenceUtils.h" +#endif +%} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp new file mode 100644 index 00000000..a42f77bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.cpp @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * ***** 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#if defined(GC_LEAK_DETECTOR) + +#include "nsLeakDetector.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsIGenericFactory.h" +#include "nsILeakDetector.h" +#include "nsICollection.h" + +#include +#include + +#include "gc.h" + +extern "C" { +extern FILE *GC_stdout, *GC_stderr; +extern void GC_trace_object(GC_PTR object, int verbose); +extern void GC_mark_object(GC_PTR object, GC_word mark); +} + +static nsresult nextLeakFile() +{ + if (GC_stderr != NULL) + fclose(GC_stderr); + + // generate a time stamped report name. + time_t timer; + time(&timer); + tm* now = localtime(&timer); + + char reportName[256]; + sprintf(reportName, "Leaks%02d%02d%02d", + now->tm_hour, now->tm_min, now->tm_sec); + GC_stderr = fopen(reportName, "w"); + + return NS_OK; +} + +static FILE* openTraceFile() +{ + // generate a time stamped report name. + time_t timer; + time(&timer); + tm* now = localtime(&timer); + + char reportName[256]; + sprintf(reportName, "Trace%02d%02d%02d", + now->tm_hour, now->tm_min, now->tm_sec); + return fopen(reportName, "w"); +} + +class nsLeakDetector : public nsILeakDetector { +public: + nsLeakDetector(); + + NS_DECL_ISUPPORTS + NS_DECL_NSILEAKDETECTOR +private: + ~nsLeakDetector() {} +}; + +NS_IMPL_ISUPPORTS1(nsLeakDetector, nsILeakDetector) + +nsLeakDetector::nsLeakDetector() { + } + +NS_METHOD nsLeakDetector::DumpLeaks() +{ + GC_gcollect(); + + return nextLeakFile(); +} + +NS_METHOD nsLeakDetector::TraceObject(nsISupports* object, PRBool verbose) +{ + FILE* trace = openTraceFile(); + if (trace != NULL) { + FILE* old_stderr = GC_stderr; + GC_stderr = trace; + GC_trace_object(object, (verbose ? 1 : 0)); + GC_stderr = old_stderr; + fclose(trace); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_METHOD nsLeakDetector::TraceCollection(nsICollection* objects, PRBool verbose) +{ + PRUint32 count; + if (NS_FAILED(objects->Count(&count))) + return NS_ERROR_FAILURE; + + nsCOMPtr* elements = new nsCOMPtr[count]; + if (elements == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (PRUint32 i = 0; i < count; ++i) + objects->GetElementAt(i, getter_AddRefs(elements[i])); + + nsresult rv = NS_ERROR_FAILURE; + FILE* trace = openTraceFile(); + if (trace != NULL) { + FILE* old_stderr = GC_stderr; + GC_stderr = trace; + GC_trace_object(elements, (verbose ? 1 : 0)); + GC_stderr = old_stderr; + fclose(trace); + rv = NS_OK; + } + + delete[] elements; + + return rv; +} + +NS_METHOD nsLeakDetector::MarkObject(nsISupports* object, PRBool marked) +{ + GC_mark_object(object, (marked ? 1 : 0)); + return NS_OK; +} + +NS_METHOD nsLeakDetector::GetServices(nsISupports* *result) +{ + return NS_GetServiceManager((nsIServiceManager**)result); +} + +#define NS_CLEAKDETECTOR_CID_STR "bb1ba360-1dd1-11b2-b30e-aa2314429f54" +#define NS_CLEAKDETECTOR_CID {0xbb1ba360, 0x1dd1, 0x11b2, {0xb3, 0x0e, 0xaa, 0x23, 0x14, 0x42, 0x9f, 0x54}} +#define NS_CLEAKDETECTOR_CONTRACTID "@mozilla.org/xpcom/leakdetector;1" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsLeakDetector) + +static NS_DEFINE_CID(kCLeakDetectorCID, NS_CLEAKDETECTOR_CID); + +nsresult NS_InitLeakDetector() +{ + nsresult rv; + + // open the first leak file. + rv = nextLeakFile(); + if (NS_FAILED(rv)) + return rv; + + static const nsModuleComponentInfo info = { + "Leak Detector", kCLeakDetectorCID, NS_CLEAKDETECTOR_CONTRACTID, nsLeakDetectorConstructor + }; + + // create a generic factory for the leak detector. + nsCOMPtr factory; + rv = NS_NewGenericFactory(getter_AddRefs(factory), &info); + if (NS_FAILED(rv)) + return rv; + + // register this factory with the component manager. + return nsComponentManager::RegisterFactory(info.mCID, info.mDescription, info.mContractID, factory, PR_TRUE); +} + +#ifdef XP_MAC +#define SHUTDOWN_LEAKS_EARLY +#undef SHUTDOWN_LEAKS_MEDIUM +#undef SHUTDOWN_LEAKS_LATE +#else +#undef SHUTDOWN_LEAKS_EARLY +#undef SHUTDOWN_LEAKS_MEDIUM +#define SHUTDOWN_LEAKS_LATE +#endif + +class LeakDetectorFinalizer +{ +public: + ~LeakDetectorFinalizer(); +}; + +#ifdef SHUTDOWN_LEAKS_LATE +// do shutdown leaks when XPCOM library is unloaded +LeakDetectorFinalizer gLeakDetectorFinalizer; +#endif + +LeakDetectorFinalizer::~LeakDetectorFinalizer() +{ + GC_gcollect(); + +#if 0 + nextLeakFile(); + if (GC_stdout != NULL) { + fprintf(GC_stdout, "ShutDown Leaks\n"); + GC_clear_roots(); + GC_gcollect(); + } +#endif +} + +nsresult NS_ShutdownLeakDetector() +{ +#if defined(SHUTDOWN_LEAKS_MEDIUM) + // Make this the first atexit() called so it's before the atexit() crashes + // see http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=23552 + static LeakDetectorFinalizer trick; +#elif defined(SHUTDOWN_LEAKS_EARLY) + // do shutdown leaks now + LeakDetectorFinalizer trick; +#endif + return NS_OK; +} + +#endif /* defined(GC_LEAK_DETECTOR) */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h new file mode 100644 index 00000000..5c560401 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsLeakDetector.h @@ -0,0 +1,60 @@ +/* -*- Mode: IDL; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Patrick C. Beard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsLeakDetector_h +#define nsLeakDetector_h + +#ifndef nsError_h +#include "nsError.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +nsresult NS_InitGarbageCollector(void); +nsresult NS_InitLeakDetector(void); +nsresult NS_ShutdownLeakDetector(void); +nsresult NS_ShutdownGarbageCollector(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* nsLeakDetector_h */ diff --git a/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp new file mode 100644 index 00000000..8aa16e58 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.cpp @@ -0,0 +1,548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsMemoryImpl.h" +#include "prmem.h" +#include "nsAlgorithm.h" +#include "nsIServiceManager.h" +#include "nsIObserverService.h" +#include "nsAutoLock.h" +#include "nsIThread.h" +#include "nsIEventQueueService.h" +#include "nsString.h" + +#if defined(XP_WIN) +#include +#define NS_MEMORY_FLUSHER_THREAD +#elif defined(XP_MAC) +#include +#define NS_MEMORY_FLUSHER_THREAD +#else +// Need to implement the nsIMemory::IsLowMemory() predicate +#undef NS_MEMORY_FLUSHER_THREAD +#endif + +//---------------------------------------------------------------------- + +#if defined(XDEBUG_waterson) +#define NS_TEST_MEMORY_FLUSHER +#endif + +/** + * A runnable that is used to periodically check the status + * of the system, determine if too much memory is in use, + * and if so, trigger a "memory flush". + */ +class MemoryFlusher : public nsIRunnable +{ +protected: + nsMemoryImpl* mMemoryImpl; // WEAK, it owns us. + PRBool mRunning; + PRIntervalTime mTimeout; + PRLock* mLock; + PRCondVar* mCVar; + + MemoryFlusher(nsMemoryImpl* aMemoryImpl); + + enum { + kInitialTimeout = 60 /*seconds*/ + }; + +private: + ~MemoryFlusher(); + +public: + /** + * Create a memory flusher. + * @param aResult the memory flusher + * @param aMemoryImpl the owning nsMemoryImpl object + * @return NS_OK if the memory flusher was created successfully + */ + static nsresult + Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl); + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + /** + * Stop the memory flusher. + */ + nsresult Stop(); +}; + + +MemoryFlusher::MemoryFlusher(nsMemoryImpl* aMemoryImpl) + : mMemoryImpl(aMemoryImpl), + mRunning(PR_FALSE), + mTimeout(PR_SecondsToInterval(kInitialTimeout)), + mLock(nsnull), + mCVar(nsnull) +{ +} + +MemoryFlusher::~MemoryFlusher() +{ + if (mLock) + PR_DestroyLock(mLock); + + if (mCVar) + PR_DestroyCondVar(mCVar); +} + + +nsresult +MemoryFlusher::Create(MemoryFlusher** aResult, nsMemoryImpl* aMemoryImpl) +{ + MemoryFlusher* result = new MemoryFlusher(aMemoryImpl); + if (! result) + return NS_ERROR_OUT_OF_MEMORY; + + do { + if ((result->mLock = PR_NewLock()) == nsnull) + break; + + if ((result->mCVar = PR_NewCondVar(result->mLock)) == nsnull) + break; + + NS_ADDREF(*aResult = result); + return NS_OK; + } while (0); + + // Something bad happened if we get here... + delete result; + return NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(MemoryFlusher, nsIRunnable) + +NS_IMETHODIMP +MemoryFlusher::Run() +{ + nsresult rv; + + mRunning = PR_TRUE; + + while (1) { + PRStatus status; + + { + nsAutoLock l(mLock); + if (! mRunning) { + rv = NS_OK; + break; + } + + status = PR_WaitCondVar(mCVar, mTimeout); + } + + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + break; + } + + if (! mRunning) { + rv = NS_OK; + break; + } + + PRBool isLowMemory; + rv = mMemoryImpl->IsLowMemory(&isLowMemory); + if (NS_FAILED(rv)) + break; + +#ifdef NS_TEST_MEMORY_FLUSHER + // Fire the flusher *every* time + isLowMemory = PR_TRUE; +#endif + + if (isLowMemory) { + mMemoryImpl->FlushMemory(NS_LITERAL_STRING("low-memory").get(), PR_FALSE); + } + } + + mRunning = PR_FALSE; + + return rv; +} + + +nsresult +MemoryFlusher::Stop() +{ + if (mRunning) { + nsAutoLock l(mLock); + mRunning = PR_FALSE; + PR_NotifyCondVar(mCVar); + } + + return NS_OK; +} + +//---------------------------------------------------------------------- + +nsMemoryImpl* gMemory = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsMemoryImpl, nsIMemory) + +NS_METHOD +nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_PROPER_AGGREGATION(outer, aIID); + if (gMemory && NS_SUCCEEDED(gMemory->QueryInterface(aIID, aInstancePtr))) + return NS_OK; + + nsMemoryImpl* mm = new nsMemoryImpl(); + if (mm == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv; + + do { + rv = mm->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + break; + + rv = NS_ERROR_OUT_OF_MEMORY; + + mm->mFlushLock = PR_NewLock(); + if (! mm->mFlushLock) + break; + + rv = NS_OK; + } while (0); + + if (NS_FAILED(rv)) + delete mm; + + return rv; +} + + +nsMemoryImpl::nsMemoryImpl() + : mFlusher(nsnull), + mFlushLock(nsnull), + mIsFlushing(PR_FALSE) +{ +} + +nsMemoryImpl::~nsMemoryImpl() +{ + if (mFlushLock) + PR_DestroyLock(mFlushLock); +} + +//////////////////////////////////////////////////////////////////////////////// +// Define NS_OUT_OF_MEMORY_TESTER if you want to force memory failures + +#ifdef DEBUG_xwarren +#define NS_OUT_OF_MEMORY_TESTER +#endif + +#ifdef NS_OUT_OF_MEMORY_TESTER + +// flush memory one in this number of times: +#define NS_FLUSH_FREQUENCY 100000 + +// fail allocation one in this number of flushes: +#define NS_FAIL_FREQUENCY 10 + +PRUint32 gFlushFreq = 0; +PRUint32 gFailFreq = 0; + +static void* +mallocator(PRSize size, PRUint32& counter, PRUint32 max) +{ + if (counter++ >= max) { + counter = 0; + NS_ASSERTION(0, "about to fail allocation... watch out"); + return nsnull; + } + return PR_Malloc(size); +} + +static void* +reallocator(void* ptr, PRSize size, PRUint32& counter, PRUint32 max) +{ + if (counter++ >= max) { + counter = 0; + NS_ASSERTION(0, "about to fail reallocation... watch out"); + return nsnull; + } + return PR_Realloc(ptr, size); +} + +#define MALLOC1(s) mallocator(s, gFlushFreq, NS_FLUSH_FREQUENCY) +#define REALLOC1(p, s) reallocator(p, s, gFlushFreq, NS_FLUSH_FREQUENCY) + +#else + +#define MALLOC1(s) PR_Malloc(s) +#define REALLOC1(p, s) PR_Realloc(p, s) + +#endif // NS_OUT_OF_MEMORY_TESTER + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP_(void *) +nsMemoryImpl::Alloc(PRSize size) +{ + NS_ASSERTION(size, "nsMemoryImpl::Alloc of 0"); + void* result = MALLOC1(size); + if (! result) { + // Request an asynchronous flush + FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; +} + +NS_IMETHODIMP_(void *) +nsMemoryImpl::Realloc(void * ptr, PRSize size) +{ + void* result = REALLOC1(ptr, size); + if (! result) { + // Request an asynchronous flush + FlushMemory(NS_LITERAL_STRING("alloc-failure").get(), PR_FALSE); + } + return result; +} + +NS_IMETHODIMP_(void) +nsMemoryImpl::Free(void * ptr) +{ + PR_Free(ptr); +} + +NS_IMETHODIMP +nsMemoryImpl::HeapMinimize(PRBool aImmediate) +{ + return FlushMemory(NS_LITERAL_STRING("heap-minimize").get(), aImmediate); +} + +NS_IMETHODIMP +nsMemoryImpl::IsLowMemory(PRBool *result) +{ +#if defined(XP_WIN) + MEMORYSTATUS stat; + GlobalMemoryStatus(&stat); + *result = ((float)stat.dwAvailPageFile / stat.dwTotalPageFile) < 0.1; +#elif defined(XP_MAC) + + const long kReserveHeapFreeSpace = (256 * 1024); + const long kReserveHeapContigSpace = (128 * 1024); + + long totalSpace, contiguousSpace; + // this call measures how much memory would be available if the OS + // purged. Despite the name, it does not purge (that happens + // automatically when heap space is low). + ::PurgeSpace(&totalSpace, &contiguousSpace); + if (totalSpace < kReserveHeapFreeSpace || contiguousSpace < kReserveHeapContigSpace) + { + NS_WARNING("Found that heap mem is low"); + *result = PR_TRUE; + return NS_OK; + } + + // see how much temp mem is available (since our allocators allocate 1Mb chunks + // in temp mem. We don't use TempMaxMem() (to get contig space) here, because it + // compacts the application heap, so can be slow. + const long kReserveTempFreeSpace = (2 * 1024 * 1024); // 2Mb + long totalTempSpace = ::TempFreeMem(); + if (totalTempSpace < kReserveTempFreeSpace) + { + NS_WARNING("Found that temp mem is low"); + *result = PR_TRUE; + return NS_OK; + } + + *result = PR_FALSE; + +#else + *result = PR_FALSE; +#endif + return NS_OK; +} + +nsresult +nsMemoryImpl::FlushMemory(const PRUnichar* aReason, PRBool aImmediate) +{ + nsresult rv; + + if (aImmediate) { + // They've asked us to run the flusher *immediately*. We've + // got to be on the UI main thread for us to be able to do + // that...are we? + PRBool isOnUIThread = PR_FALSE; + + nsCOMPtr main; + rv = nsIThread::GetMainThread(getter_AddRefs(main)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr current; + rv = nsIThread::GetCurrent(getter_AddRefs(current)); + if (NS_SUCCEEDED(rv)) { + if (current == main) + isOnUIThread = PR_TRUE; + } + } + + if (! isOnUIThread) { + NS_ERROR("can't synchronously flush memory: not on UI thread"); + return NS_ERROR_FAILURE; + } + } + + { + // Are we already flushing? + nsAutoLock l(mFlushLock); + if (mIsFlushing) + return NS_OK; + + // Well, we are now! + mIsFlushing = PR_TRUE; + } + + // Run the flushers immediately if we can; otherwise, proxy to the + // UI thread an run 'em asynchronously. + if (aImmediate) { + rv = RunFlushers(this, aReason); + } + else { + nsCOMPtr eqs = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + if (eqs) { + nsCOMPtr eq; + rv = eqs->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eq)); + if (NS_SUCCEEDED(rv)) { + PL_InitEvent(&mFlushEvent.mEvent, this, HandleFlushEvent, DestroyFlushEvent); + mFlushEvent.mReason = aReason; + + rv = eq->PostEvent(NS_REINTERPRET_CAST(PLEvent*, &mFlushEvent)); + } + } + } + + return rv; +} + +nsresult +nsMemoryImpl::RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason) +{ + nsCOMPtr os = do_GetService("@mozilla.org/observer-service;1"); + if (os) { + os->NotifyObservers(aSelf, "memory-pressure", aReason); + } + + { + // Done flushing + nsAutoLock l(aSelf->mFlushLock); + aSelf->mIsFlushing = PR_FALSE; + } + + return NS_OK; +} + +void* +nsMemoryImpl::HandleFlushEvent(PLEvent* aEvent) +{ + nsMemoryImpl* self = NS_STATIC_CAST(nsMemoryImpl*, PL_GetEventOwner(aEvent)); + FlushEvent* event = NS_REINTERPRET_CAST(FlushEvent*, aEvent); + + RunFlushers(self, event->mReason); + return 0; +} + +void +nsMemoryImpl::DestroyFlushEvent(PLEvent* aEvent) +{ + // no-op, since mEvent is a member of nsMemoryImpl +} + +static void +EnsureGlobalMemoryService() +{ + if (gMemory) return; + nsresult rv = nsMemoryImpl::Create(nsnull, NS_GET_IID(nsIMemory), (void**)&gMemory); + NS_ASSERTION(NS_SUCCEEDED(rv), "nsMemoryImpl::Create failed"); + NS_ASSERTION(gMemory, "improper xpcom initialization"); +} + +nsresult +nsMemoryImpl::Startup() +{ + EnsureGlobalMemoryService(); + if (! gMemory) + return NS_ERROR_FAILURE; + +#ifdef NS_MEMORY_FLUSHER_THREAD + nsresult rv; + + // Create and start a memory flusher thread + rv = MemoryFlusher::Create(&gMemory->mFlusher, gMemory); + if (NS_FAILED(rv)) return rv; + + rv = NS_NewThread(getter_AddRefs(gMemory->mFlusherThread), + gMemory->mFlusher, + 0, /* XXX use default stack size? */ + PR_JOINABLE_THREAD); + + if (NS_FAILED(rv)) return rv; +#endif + + return NS_OK; +} + +nsresult +nsMemoryImpl::Shutdown() +{ + if (gMemory) { +#ifdef NS_MEMORY_FLUSHER_THREAD + if (gMemory->mFlusher) { + // Stop the runnable... + gMemory->mFlusher->Stop(); + NS_RELEASE(gMemory->mFlusher); + + // ...and wait for the thread to exit + if (gMemory->mFlusherThread) + gMemory->mFlusherThread->Join(); + } +#endif + + NS_RELEASE(gMemory); + gMemory = nsnull; + } + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h new file mode 100644 index 00000000..c9086d11 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsMemoryImpl.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsMemoryImpl_h__ +#define nsMemoryImpl_h__ + +#include "nsMemory.h" +#include "nsISupportsArray.h" +#include "nsIRunnable.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" +#include "plevent.h" + +struct PRLock; +class MemoryFlusher; + +class nsMemoryImpl : public nsIMemory +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORY + + nsMemoryImpl(); + + nsresult FlushMemory(const PRUnichar* aReason, PRBool aImmediate); + + // called from xpcom initialization/finalization: + static nsresult Startup(); + static nsresult Shutdown(); + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsMemoryImpl(); + +protected: + MemoryFlusher* mFlusher; + nsCOMPtr mFlusherThread; + + PRLock* mFlushLock; + PRBool mIsFlushing; + + struct FlushEvent { + PLEvent mEvent; + const PRUnichar* mReason; + }; + + FlushEvent mFlushEvent; + + static nsresult RunFlushers(nsMemoryImpl* aSelf, const PRUnichar* aReason); + + static void* PR_CALLBACK HandleFlushEvent(PLEvent* aEvent); + static void PR_CALLBACK DestroyFlushEvent(PLEvent* aEvent); +}; + +#endif // nsMemoryImpl_h__ diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp new file mode 100644 index 00000000..11fe0fca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.cpp @@ -0,0 +1,375 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsStackFrameUnix.h" +#include +#include +#include +#include "nscore.h" + +// On glibc 2.1, the Dl_info api defined in is only exposed +// if __USE_GNU is defined. I suppose its some kind of standards +// adherence thing. +// +#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU) +#define __USE_GNU +#endif + +#ifdef HAVE_LIBDL +#include +#endif + + + +// This thing is exported by libstdc++ +// Yes, this is a gcc only hack +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include +#include // for free() +#endif // MOZ_DEMANGLE_SYMBOLS + +void DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen) +{ + aBuffer[0] = '\0'; + +#if defined(MOZ_DEMANGLE_SYMBOLS) + /* See demangle.h in the gcc source for the voodoo */ + char * demangled = abi::__cxa_demangle(aSymbol,0,0,0); + + if (demangled) + { + strncpy(aBuffer,demangled,aBufLen); + free(demangled); + } +#endif // MOZ_DEMANGLE_SYMBOLS +} + + +#if defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) // i386 or PPC Linux stackwalking code + +#include +// + +void DumpStackToFile(FILE* aStream) +{ + jmp_buf jb; + setjmp(jb); + + // Stack walking code courtesy Kipp's "leaky". + + // Get the frame pointer out of the jmp_buf + void **bp = (void**) +#if defined(__i386) + (jb[0].__jmpbuf[JB_BP]); +#elif defined(PPC) + (jb[0].__jmpbuf[JB_GPR1]); +#endif + + int skip = 2; + for ( ; (void**)*bp > bp; bp = (void**)*bp) { + void *pc = *(bp+1); + if (--skip <= 0) { + Dl_info info; + int ok = dladdr(pc, &info); + if (!ok) { + fprintf(aStream, "UNKNOWN %p\n", pc); + continue; + } + + PRUint32 foff = (char*)pc - (char*)info.dli_fbase; + + const char * symbol = info.dli_sname; + int len; + if (!symbol || !(len = strlen(symbol))) { + fprintf(aStream, "UNKNOWN [%s +0x%08X]\n", + info.dli_fname, foff); + continue; + } + + char demangled[4096] = "\0"; + + DemangleSymbol(symbol, demangled, sizeof(demangled)); + + if (strlen(demangled)) { + symbol = demangled; + len = strlen(symbol); + } + + PRUint32 off = (char*)pc - (char*)info.dli_saddr; + fprintf(aStream, "%s+0x%08X [%s +0x%08X]\n", + symbol, off, info.dli_fname, foff); + } + } +} + +#elif defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386)) + +/* + * Stack walking code for Solaris courtesy of Bart Smaalder's "memtrak". + */ + +#include +#include +#include +#include +#include + +static int load_address ( void * pc, void * arg, FILE * aStream ); +static int write_address_file ( void * pc ); +static struct bucket * newbucket ( void * pc ); +static struct frame * cs_getmyframeptr ( void ); +static void cs_walk_stack ( void * (*read_func)(char * address), + struct frame * fp, + int (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); +static void cs_operate ( void (*operate_func)(void *, void *), + void * usrarg, FILE * aStream ); + +#ifndef STACK_BIAS +#define STACK_BIAS 0 +#endif /*STACK_BIAS*/ + +#define LOGSIZE 4096 + +/* type of demangling function */ +typedef int demf_t(const char *, char *, size_t); + +static demf_t *demf; + +static int initialized = 0; + +#if defined(sparc) || defined(__sparc) +#define FRAME_PTR_REGISTER REG_SP +#endif + +#if defined(i386) || defined(__i386) +#define FRAME_PTR_REGISTER EBP +#endif + +struct bucket { + void * pc; + int index; + struct bucket * next; +}; + +struct mybuf { + char * buffer; + int chars_left; +}; + + +static void myinit(); + +#pragma init (myinit) + +static void +myinit() +{ + + if (! initialized) { +#ifndef __GNUC__ + void *handle; + const char *libdem = "libdemangle.so.1"; + + /* load libdemangle if we can and need to (only try this once) */ + if ((handle = dlopen(libdem, RTLD_LAZY)) != NULL) { + demf = (demf_t *)dlsym(handle, + "cplus_demangle"); /*lint !e611 */ + /* + * lint override above is to prevent lint from + * complaining about "suspicious cast". + */ + } +#endif /*__GNUC__*/ + } + initialized = 1; +} + + +static int +write_address_file(void * pc, FILE* aStream) +{ + static struct bucket table[2048]; + static mutex_t lock; + struct bucket * ptr; + + unsigned int val = NS_PTR_TO_INT32(pc); + + ptr = table + ((val >> 2)&2047); + + mutex_lock(&lock); + while (ptr->next) { + if (ptr->next->pc == pc) + break; + ptr = ptr->next; + } + + if (ptr->next) { + mutex_unlock(&lock); + return (ptr->next->index); + } else { + char buffer[4096], dembuff[4096]; + Dl_info info; + const char *func = "??", *lib = "??"; + + ptr->next = newbucket(pc); + mutex_unlock(&lock); + + if (dladdr(pc, & info)) { + if (info.dli_fname) + lib = info.dli_fname; + if (info.dli_sname) + func = info.dli_sname; + } + +#ifdef __GNUC__ + DemangleSymbol(func, dembuff, sizeof(dembuff)); +#else + if (!demf || demf(func, dembuff, sizeof (dembuff))) + dembuff[0] = 0; +#endif /*__GNUC__*/ + if (strlen(dembuff)) { + func = dembuff; + } + fprintf(aStream, "%u %s:%s+0x%x\n", + ptr->next->index, + lib, + func, + (char *)pc - (char*)info.dli_saddr); + + return (ptr->next->index); + } +} + + +static int +load_address(void * pc, void * arg, FILE * aStream) +{ + struct mybuf * buf = (struct mybuf *) arg; + + char name[80]; + int len; + + sprintf(name, " %u", write_address_file(pc, aStream)); + + len = strlen(name); + + if (len >= buf->chars_left) + return (1); + + strcat(buf->buffer, name); + + buf->chars_left -= len; + + return (0); +} + + +static struct bucket * +newbucket(void * pc) +{ + struct bucket * ptr = (struct bucket *) malloc(sizeof (*ptr)); + static int index; /* protected by lock in caller */ + + ptr->index = index++; + ptr->next = NULL; + ptr->pc = pc; + return (ptr); +} + + +static struct frame * +csgetframeptr() +{ + ucontext_t u; + struct frame *fp; + + (void) getcontext(&u); + + fp = (struct frame *) + ((char *)u.uc_mcontext.gregs[FRAME_PTR_REGISTER] + + STACK_BIAS); + + /* make sure to return parents frame pointer.... */ + + return ((struct frame *)((ulong_t)fp->fr_savfp + STACK_BIAS)); +} + + +static void +cswalkstack(struct frame *fp, int (*operate_func)(void *, void *, FILE *), + void *usrarg, FILE * aStream) +{ + + while (fp != 0 && fp->fr_savpc != 0) { + + if (operate_func((void *)fp->fr_savpc, usrarg, aStream) != 0) + break; + /* + * watch out - libthread stacks look funny at the top + * so they may not have their STACK_BIAS set + */ + + fp = (struct frame *)((ulong_t)fp->fr_savfp + + (fp->fr_savfp?(ulong_t)STACK_BIAS:0)); + } +} + + +static void +cs_operate(int (*operate_func)(void *, void *, FILE *), void * usrarg, FILE *aStream) +{ + cswalkstack(csgetframeptr(), operate_func, usrarg, aStream); +} + +void DumpStackToFile(FILE* aStream) +{ + char buffer[LOGSIZE]; + struct mybuf mybuf; + + if (!initialized) + myinit(); + + mybuf.chars_left = LOGSIZE - strlen(buffer)-1; + mybuf.buffer = buffer; + cs_operate(load_address, &mybuf, aStream); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h new file mode 100644 index 00000000..1673ae76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameUnix.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStackFrameUnix_h___ +#define nsStackFrameUnix_h___ + +#include "stdio.h" + +void DumpStackToFile(FILE* out); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp new file mode 100644 index 00000000..7228356b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.cpp @@ -0,0 +1,351 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2003. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Judge, 20-December-2000 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" +#include "windows.h" +#include "imagehlp.h" +#include "stdio.h" +#include "nsStackFrameWin.h" + +// Define these as static pointers so that we can load the DLL on the +// fly (and not introduce a link-time dependency on it). Tip o' the +// hat to Matt Pietrick for this idea. See: +// +// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm +// + + +PR_BEGIN_EXTERN_C + +SYMSETOPTIONSPROC _SymSetOptions; + +SYMINITIALIZEPROC _SymInitialize; + +SYMCLEANUPPROC _SymCleanup; + +STACKWALKPROC _StackWalk; + +SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; + +SYMGETMODULEBASEPROC _SymGetModuleBase; + +SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; + +SYMLOADMODULE _SymLoadModule; + +SYMUNDNAME _SymUnDName; + +SYMGETMODULEINFO _SymGetModuleInfo; + +ENUMLOADEDMODULES _EnumerateLoadedModules; + +SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; + +PR_END_EXTERN_C + + + + +PRBool +EnsureImageHlpInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + HMODULE module = ::LoadLibrary("IMAGEHLP.DLL"); + if (!module) return PR_FALSE; + + _SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions"); + if (!_SymSetOptions) return PR_FALSE; + + _SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize"); + if (!_SymInitialize) return PR_FALSE; + + _SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup"); + if (!_SymCleanup) return PR_FALSE; + + _StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk"); + if (!_StackWalk) return PR_FALSE; + + _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess"); + if (!_SymFunctionTableAccess) return PR_FALSE; + + _SymGetModuleBase = (SYMGETMODULEBASEPROC)GetProcAddress(module, "SymGetModuleBase"); + if (!_SymGetModuleBase) return PR_FALSE; + + _SymGetSymFromAddr = (SYMGETSYMFROMADDRPROC)GetProcAddress(module, "SymGetSymFromAddr"); + if (!_SymGetSymFromAddr) return PR_FALSE; + + _SymLoadModule = (SYMLOADMODULE)GetProcAddress(module, "SymLoadModule"); + if (!_SymLoadModule) return PR_FALSE; + + _SymUnDName = (SYMUNDNAME)GetProcAddress(module, "SymUnDName"); + if (!_SymUnDName) return PR_FALSE; + + _SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo"); + if (!_SymGetModuleInfo) return PR_FALSE; + + _EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules"); + if (!_EnumerateLoadedModules) return PR_FALSE; + + _SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr"); + if (!_SymGetLineFromAddr) return PR_FALSE; + + gInitialized = PR_TRUE; + } + + return gInitialized; +} + +/* + * Callback used by SymGetModuleInfoEspecial + */ +static BOOL CALLBACK callbackEspecial(LPSTR aModuleName, ULONG aModuleBase, ULONG aModuleSize, PVOID aUserContext) +{ + BOOL retval = TRUE; + DWORD addr = (DWORD)aUserContext; + + /* + * You'll want to control this if we are running on an + * architecture where the addresses go the other direction. + * Not sure this is even a realistic consideration. + */ + const BOOL addressIncreases = TRUE; + + /* + * If it falls in side the known range, load the symbols. + */ + if(addressIncreases + ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize)) + : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize)) + ) + { + BOOL loadRes = FALSE; + HANDLE process = GetCurrentProcess(); + + loadRes = _SymLoadModule(process, NULL, aModuleName, NULL, aModuleBase, aModuleSize); + PR_ASSERT(FALSE != loadRes); + } + + return retval; +} + +/* + * SymGetModuleInfoEspecial + * + * Attempt to determine the module information. + * Bug 112196 says this DLL may not have been loaded at the time + * SymInitialize was called, and thus the module information + * and symbol information is not available. + * This code rectifies that problem. + */ +BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo) +{ + BOOL retval = FALSE; + + /* + * Init the vars if we have em. + */ + aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE); + if (nsnull != aLineInfo) { + aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE); + } + + /* + * Give it a go. + * It may already be loaded. + */ + retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo); + + if (FALSE == retval) { + BOOL enumRes = FALSE; + + /* + * Not loaded, here's the magic. + * Go through all the modules. + */ + enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)aAddr); + if(FALSE != enumRes) + { + /* + * One final go. + * If it fails, then well, we have other problems. + */ + retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo); + } + } + + /* + * If we got module info, we may attempt line info as well. + * We will not report failure if this does not work. + */ + if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr) { + DWORD displacement = 0; + BOOL lineRes = FALSE; + + lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo); + } + + return retval; +} + +PRBool +EnsureSymInitialized() +{ + static PRBool gInitialized = PR_FALSE; + + if (! gInitialized) { + if (! EnsureImageHlpInitialized()) + return PR_FALSE; + _SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + gInitialized = _SymInitialize(GetCurrentProcess(), 0, TRUE); + } + return gInitialized; +} + + +/** + * Walk the stack, translating PC's found into strings and recording the + * chain in aBuffer. For this to work properly, the dll's must be rebased + * so that the address in the file agrees with the address in memory. + * Otherwise StackWalk will return FALSE when it hits a frame in a dll's + * whose in memory address doesn't match it's in-file address. + * + * Fortunately, there is a handy dandy routine in IMAGEHLP.DLL that does + * the rebasing and accordingly I've made a tool to use it to rebase the + * DLL's in one fell swoop (see xpcom/tools/windows/rebasedlls.cpp). + */ + + +void +DumpStackToFile(FILE* aStream) +{ + HANDLE myProcess = ::GetCurrentProcess(); + HANDLE myThread = ::GetCurrentThread(); + BOOL ok; + + ok = EnsureSymInitialized(); + if (! ok) + return; + + // Get the context information for this thread. That way we will + // know where our sp, fp, pc, etc. are and can fill in the + // STACKFRAME with the initial values. + CONTEXT context; + context.ContextFlags = CONTEXT_FULL; + ok = GetThreadContext(myThread, &context); + if (! ok) + return; + + // Setup initial stack frame to walk from + STACKFRAME frame; + memset(&frame, 0, sizeof(frame)); + frame.AddrPC.Offset = context.Eip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Esp; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Ebp; + frame.AddrFrame.Mode = AddrModeFlat; + + // Now walk the stack and map the pc's to symbol names + int skip = 2; + while (1) { + ok = _StackWalk(IMAGE_FILE_MACHINE_I386, + myProcess, + myThread, + &frame, + &context, + 0, // read process memory routine + _SymFunctionTableAccess, // function table access routine + _SymGetModuleBase, // module base routine + 0); // translate address routine + + if (!ok) { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(aStream, "### ERROR: WalkStack: %s", lpMsgBuf); + fflush(aStream); + LocalFree( lpMsgBuf ); + } + if (!ok || frame.AddrPC.Offset == 0) + break; + + if (skip-- > 0) + continue; + + // + // Attempt to load module info before we attempt to reolve the symbol. + // This just makes sure we get good info if available. + // + IMAGEHLP_MODULE modInfo; + modInfo.SizeOfStruct = sizeof(modInfo); + BOOL modInfoRes = TRUE; + modInfoRes = SymGetModuleInfoEspecial(myProcess, frame.AddrPC.Offset, &modInfo, nsnull); + + char buf[sizeof(IMAGEHLP_SYMBOL) + 512]; + PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL) buf; + symbol->SizeOfStruct = sizeof(buf); + symbol->MaxNameLength = 512; + + DWORD displacement; + ok = _SymGetSymFromAddr(myProcess, + frame.AddrPC.Offset, + &displacement, + symbol); + + if (ok) { + fprintf(aStream, "%s+0x%08X\n", symbol->Name, displacement); + } + else { + fprintf(aStream, "0x%08X\n", frame.AddrPC.Offset); + } + } +} + diff --git a/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h new file mode 100644 index 00000000..d9b6585c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsStackFrameWin.h @@ -0,0 +1,126 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsStackFrameWin.h code, released + * December 20, 2000. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Judge, 20-December-2000 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStackFrameWin_h___ +#define nsStackFrameWin_h___ + + +#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include "nspr.h" +#include +#include + +// Define these as static pointers so that we can load the DLL on the +// fly (and not introduce a link-time dependency on it). Tip o' the +// hat to Matt Pietrick for this idea. See: +// +// http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm +// +PR_BEGIN_EXTERN_C + +typedef DWORD (__stdcall *SYMSETOPTIONSPROC)(DWORD); +extern SYMSETOPTIONSPROC _SymSetOptions; + +typedef BOOL (__stdcall *SYMINITIALIZEPROC)(HANDLE, LPSTR, BOOL); +extern SYMINITIALIZEPROC _SymInitialize; + +typedef BOOL (__stdcall *SYMCLEANUPPROC)(HANDLE); +extern SYMCLEANUPPROC _SymCleanup; + +typedef BOOL (__stdcall *STACKWALKPROC)(DWORD, + HANDLE, + HANDLE, + LPSTACKFRAME, + LPVOID, + PREAD_PROCESS_MEMORY_ROUTINE, + PFUNCTION_TABLE_ACCESS_ROUTINE, + PGET_MODULE_BASE_ROUTINE, + PTRANSLATE_ADDRESS_ROUTINE); +extern STACKWALKPROC _StackWalk; + +typedef LPVOID (__stdcall *SYMFUNCTIONTABLEACCESSPROC)(HANDLE, DWORD); +extern SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess; + +typedef DWORD (__stdcall *SYMGETMODULEBASEPROC)(HANDLE, DWORD); +extern SYMGETMODULEBASEPROC _SymGetModuleBase; + +typedef BOOL (__stdcall *SYMGETSYMFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_SYMBOL); +extern SYMGETSYMFROMADDRPROC _SymGetSymFromAddr; + +typedef DWORD ( __stdcall *SYMLOADMODULE)(HANDLE, HANDLE, PSTR, PSTR, DWORD, DWORD); +extern SYMLOADMODULE _SymLoadModule; + +typedef DWORD ( __stdcall *SYMUNDNAME)(PIMAGEHLP_SYMBOL, PSTR, DWORD); +extern SYMUNDNAME _SymUnDName; + +typedef DWORD ( __stdcall *SYMGETMODULEINFO)( HANDLE, DWORD, PIMAGEHLP_MODULE); +extern SYMGETMODULEINFO _SymGetModuleInfo; + +typedef BOOL ( __stdcall *ENUMLOADEDMODULES)( HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID); +extern ENUMLOADEDMODULES _EnumerateLoadedModules; + +typedef BOOL (__stdcall *SYMGETLINEFROMADDRPROC)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE); +extern SYMGETLINEFROMADDRPROC _SymGetLineFromAddr; + +PRBool EnsureSymInitialized(); + +PRBool EnsureImageHlpInitialized(); + +/* + * SymGetModuleInfoEspecial + * + * Attempt to determine the module information. + * Bug 112196 says this DLL may not have been loaded at the time + * SymInitialize was called, and thus the module information + * and symbol information is not available. + * This code rectifies that problem. + * Line information is optional. + */ +BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo); + + +void DumpStackToFile(FILE* out); + +PR_END_EXTERN_C + +#endif //WIN32 + +#endif //nsStackFrameWin_h___ + + diff --git a/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp new file mode 100644 index 00000000..f74e84df --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.cpp @@ -0,0 +1,1444 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTraceRefcntImpl.h" +#include "nscore.h" +#include "nsISupports.h" +#include "nsVoidArray.h" +#include "prprf.h" +#include "prlog.h" +#include "plstr.h" +#include +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include + +#if defined(_WIN32) +#include +#elif defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC)) +#include + +// +// On glibc 2.1, the Dl_info api defined in is only exposed +// if __USE_GNU is defined. I suppose its some kind of standards +// adherence thing. +// +#if (__GLIBC_MINOR__ >= 1) && !defined(__USE_GNU) +#define __USE_GNU +#endif + +#include +#endif + +#ifdef HAVE_LIBDL +#include +#endif + +#if defined(XP_MAC) && !TARGET_CARBON +#include "macstdlibextras.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM void +NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult) +{ + double mean = 0.0, var = 0.0, stdDev = 0.0; + if (n > 0.0 && sumOfValues >= 0) { + mean = sumOfValues / n; + double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues); + if (temp < 0.0 || n <= 1) + var = 0.0; + else + var = temp / (n * (n - 1)); + // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this: + stdDev = var != 0.0 ? sqrt(var) : 0.0; + } + *meanResult = mean; + *stdDevResult = stdDev; +} + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef NS_BUILD_REFCNT_LOGGING +#include "plhash.h" +#include "prmem.h" + +#include "prlock.h" + +static PRLock* gTraceLock; + +#define LOCK_TRACELOG() PR_Lock(gTraceLock) +#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock) + +static PLHashTable* gBloatView; +static PLHashTable* gTypesToLog; +static PLHashTable* gObjectsToLog; +static PLHashTable* gSerialNumbers; +static PRInt32 gNextSerialNumber; + +static PRBool gLogging; +static PRBool gLogToLeaky; +static PRBool gLogLeaksOnly; + +static void (*leakyLogAddRef)(void* p, int oldrc, int newrc); +static void (*leakyLogRelease)(void* p, int oldrc, int newrc); + +static PRBool gInitialized = PR_FALSE; +static FILE *gBloatLog = nsnull; +static FILE *gRefcntsLog = nsnull; +static FILE *gAllocLog = nsnull; +static FILE *gLeakyLog = nsnull; +static FILE *gCOMPtrLog = nsnull; +static PRBool gActivityIsLegal = PR_FALSE; + +struct serialNumberRecord { + PRInt32 serialNumber; + PRInt32 refCount; + PRInt32 COMPtrCount; +}; + +struct nsTraceRefcntStats { + nsrefcnt mAddRefs; + nsrefcnt mReleases; + nsrefcnt mCreates; + nsrefcnt mDestroys; + double mRefsOutstandingTotal; + double mRefsOutstandingSquared; + double mObjsOutstandingTotal; + double mObjsOutstandingSquared; +}; + +#ifdef DEBUG_dbaron_off + // I hope to turn this on for everybody once we hit it a little less. +#define ASSERT_ACTIVITY_IS_LEGAL \ + NS_WARN_IF_FALSE(gActivityIsLegal, \ + "XPCOM objects created/destroyed from static ctor/dtor") +#else +#define ASSERT_ACTIVITY_IS_LEGAL +#endif + + +// These functions are copied from nsprpub/lib/ds/plhash.c, with changes +// to the functions not called Default* to free the serialNumberRecord or +// the BloatEntry. + +static void * PR_CALLBACK +DefaultAllocTable(void *pool, PRSize size) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + return PR_MALLOC(size); +} + +static void PR_CALLBACK +DefaultFreeTable(void *pool, void *item) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + PR_Free(item); +} + +static PLHashEntry * PR_CALLBACK +DefaultAllocEntry(void *pool, const void *key) +{ +#if defined(XP_MAC) +#pragma unused (pool,key) +#endif + + return PR_NEW(PLHashEntry); +} + +static void PR_CALLBACK +SerialNumberFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + PR_Free(NS_REINTERPRET_CAST(serialNumberRecord*,he->value)); + PR_Free(he); + } +} + +static void PR_CALLBACK +TypesToLogFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + nsCRT::free(NS_CONST_CAST(char*, + NS_REINTERPRET_CAST(const char*, he->key))); + PR_Free(he); + } +} + +static const PLHashAllocOps serialNumberHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, SerialNumberFreeEntry +}; + +static const PLHashAllocOps typesToLogHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, TypesToLogFreeEntry +}; + +//////////////////////////////////////////////////////////////////////////////// + +class BloatEntry { +public: + BloatEntry(const char* className, PRUint32 classSize) + : mClassSize(classSize) { + mClassName = PL_strdup(className); + Clear(&mNewStats); + Clear(&mAllStats); + mTotalLeaked = 0; + } + + ~BloatEntry() { + PL_strfree(mClassName); + } + + PRUint32 GetClassSize() { return (PRUint32)mClassSize; } + const char* GetClassName() { return mClassName; } + + static void Clear(nsTraceRefcntStats* stats) { + stats->mAddRefs = 0; + stats->mReleases = 0; + stats->mCreates = 0; + stats->mDestroys = 0; + stats->mRefsOutstandingTotal = 0; + stats->mRefsOutstandingSquared = 0; + stats->mObjsOutstandingTotal = 0; + stats->mObjsOutstandingSquared = 0; + } + + void Accumulate() { + mAllStats.mAddRefs += mNewStats.mAddRefs; + mAllStats.mReleases += mNewStats.mReleases; + mAllStats.mCreates += mNewStats.mCreates; + mAllStats.mDestroys += mNewStats.mDestroys; + mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal; + mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared; + mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal; + mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared; + Clear(&mNewStats); + } + + void AddRef(nsrefcnt refcnt) { + mNewStats.mAddRefs++; + if (refcnt == 1) { + Ctor(); + } + AccountRefs(); + } + + void Release(nsrefcnt refcnt) { + mNewStats.mReleases++; + if (refcnt == 0) { + Dtor(); + } + AccountRefs(); + } + + void Ctor() { + mNewStats.mCreates++; + AccountObjs(); + } + + void Dtor() { + mNewStats.mDestroys++; + AccountObjs(); + } + + void AccountRefs() { + PRInt32 cnt = (mNewStats.mAddRefs - mNewStats.mReleases); + mNewStats.mRefsOutstandingTotal += cnt; + mNewStats.mRefsOutstandingSquared += cnt * cnt; + } + + void AccountObjs() { + PRInt32 cnt = (mNewStats.mCreates - mNewStats.mDestroys); + mNewStats.mObjsOutstandingTotal += cnt; + mNewStats.mObjsOutstandingSquared += cnt * cnt; + } + + static PRIntn PR_CALLBACK DumpEntry(PLHashEntry *he, PRIntn i, void *arg) { + BloatEntry* entry = (BloatEntry*)he->value; + if (entry) { + entry->Accumulate(); + NS_STATIC_CAST(nsVoidArray*, arg)->AppendElement(entry); + } + return HT_ENUMERATE_NEXT; + } + + static PRIntn PR_CALLBACK TotalEntries(PLHashEntry *he, PRIntn i, void *arg) { + BloatEntry* entry = (BloatEntry*)he->value; + if (entry && nsCRT::strcmp(entry->mClassName, "TOTAL") != 0) { + entry->Total((BloatEntry*)arg); + } + return HT_ENUMERATE_NEXT; + } + + void Total(BloatEntry* total) { + total->mAllStats.mAddRefs += mNewStats.mAddRefs + mAllStats.mAddRefs; + total->mAllStats.mReleases += mNewStats.mReleases + mAllStats.mReleases; + total->mAllStats.mCreates += mNewStats.mCreates + mAllStats.mCreates; + total->mAllStats.mDestroys += mNewStats.mDestroys + mAllStats.mDestroys; + total->mAllStats.mRefsOutstandingTotal += mNewStats.mRefsOutstandingTotal + mAllStats.mRefsOutstandingTotal; + total->mAllStats.mRefsOutstandingSquared += mNewStats.mRefsOutstandingSquared + mAllStats.mRefsOutstandingSquared; + total->mAllStats.mObjsOutstandingTotal += mNewStats.mObjsOutstandingTotal + mAllStats.mObjsOutstandingTotal; + total->mAllStats.mObjsOutstandingSquared += mNewStats.mObjsOutstandingSquared + mAllStats.mObjsOutstandingSquared; + PRInt32 count = (mNewStats.mCreates + mAllStats.mCreates); + total->mClassSize += mClassSize * count; // adjust for average in DumpTotal + total->mTotalLeaked += (PRInt32)(mClassSize * + ((mNewStats.mCreates + mAllStats.mCreates) + -(mNewStats.mDestroys + mAllStats.mDestroys))); + } + + nsresult DumpTotal(PRUint32 nClasses, FILE* out) { + mClassSize /= mAllStats.mCreates; + return Dump(-1, out, nsTraceRefcntImpl::ALL_STATS); + } + + static PRBool HaveLeaks(nsTraceRefcntStats* stats) { + return ((stats->mAddRefs != stats->mReleases) || + (stats->mCreates != stats->mDestroys)); + } + + static nsresult PrintDumpHeader(FILE* out, const char* msg) { + fprintf(out, "\n== BloatView: %s\n\n", msg); + fprintf(out, + " |<----------------Class--------------->|<-----Bytes------>|<----------------Objects---------------->|<--------------References-------------->|\n"); + fprintf(out, + " Per-Inst Leaked Total Rem Mean StdDev Total Rem Mean StdDev\n"); + return NS_OK; + } + + nsresult Dump(PRIntn i, FILE* out, nsTraceRefcntImpl::StatisticsType type) { + nsTraceRefcntStats* stats = (type == nsTraceRefcntImpl::NEW_STATS) ? &mNewStats : &mAllStats; + if (gLogLeaksOnly && !HaveLeaks(stats)) { + return NS_OK; + } + + double meanRefs, stddevRefs; + NS_MeanAndStdDev(stats->mAddRefs + stats->mReleases, + stats->mRefsOutstandingTotal, + stats->mRefsOutstandingSquared, + &meanRefs, &stddevRefs); + + double meanObjs, stddevObjs; + NS_MeanAndStdDev(stats->mCreates + stats->mDestroys, + stats->mObjsOutstandingTotal, + stats->mObjsOutstandingSquared, + &meanObjs, &stddevObjs); + + if ((stats->mAddRefs - stats->mReleases) != 0 || + stats->mAddRefs != 0 || + meanRefs != 0 || + stddevRefs != 0 || + (stats->mCreates - stats->mDestroys) != 0 || + stats->mCreates != 0 || + meanObjs != 0 || + stddevObjs != 0) { + fprintf(out, "%4d %-40.40s %8d %8d %8d %8d (%8.2f +/- %8.2f) %8d %8d (%8.2f +/- %8.2f)\n", + i+1, mClassName, + (PRInt32)mClassSize, + (nsCRT::strcmp(mClassName, "TOTAL")) + ?(PRInt32)((stats->mCreates - stats->mDestroys) * mClassSize) + :mTotalLeaked, + stats->mCreates, + (stats->mCreates - stats->mDestroys), + meanObjs, + stddevObjs, + stats->mAddRefs, + (stats->mAddRefs - stats->mReleases), + meanRefs, + stddevRefs); + } + return NS_OK; + } + +protected: + char* mClassName; + double mClassSize; // this is stored as a double because of the way we compute the avg class size for total bloat + PRInt32 mTotalLeaked; // used only for TOTAL entry + nsTraceRefcntStats mNewStats; + nsTraceRefcntStats mAllStats; +}; + +static void PR_CALLBACK +BloatViewFreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ +#if defined(XP_MAC) +#pragma unused (pool) +#endif + + if (flag == HT_FREE_ENTRY) { + BloatEntry* entry = NS_REINTERPRET_CAST(BloatEntry*,he->value); + delete entry; + PR_Free(he); + } +} + +const static PLHashAllocOps bloatViewHashAllocOps = { + DefaultAllocTable, DefaultFreeTable, + DefaultAllocEntry, BloatViewFreeEntry +}; + +static void +RecreateBloatView() +{ + gBloatView = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + &bloatViewHashAllocOps, NULL); +} + +static BloatEntry* +GetBloatEntry(const char* aTypeName, PRUint32 aInstanceSize) +{ + if (!gBloatView) { + RecreateBloatView(); + } + BloatEntry* entry = NULL; + if (gBloatView) { + entry = (BloatEntry*)PL_HashTableLookup(gBloatView, aTypeName); + if (entry == NULL && aInstanceSize > 0) { + + entry = new BloatEntry(aTypeName, aInstanceSize); + PLHashEntry* e = PL_HashTableAdd(gBloatView, aTypeName, entry); + if (e == NULL) { + delete entry; + entry = NULL; + } + } else { + NS_ASSERTION(aInstanceSize == 0 || + entry->GetClassSize() == aInstanceSize, + "bad size recorded"); + } + } + return entry; +} + +static PRIntn PR_CALLBACK DumpSerialNumbers(PLHashEntry* aHashEntry, PRIntn aIndex, void* aClosure) +{ + serialNumberRecord* record = NS_REINTERPRET_CAST(serialNumberRecord *,aHashEntry->value); +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + fprintf((FILE*) aClosure, "%d (%d references; %d from COMPtrs)\n", + record->serialNumber, + record->refCount, + record->COMPtrCount); +#else + fprintf((FILE*) aClosure, "%d (%d references)\n", + record->serialNumber, + record->refCount); +#endif + return HT_ENUMERATE_NEXT; +} + + +#endif /* NS_BUILD_REFCNT_LOGGING */ + +nsresult +nsTraceRefcntImpl::DumpStatistics(StatisticsType type, FILE* out) +{ + nsresult rv = NS_OK; +#ifdef NS_BUILD_REFCNT_LOGGING + if (gBloatLog == nsnull || gBloatView == nsnull) { + return NS_ERROR_FAILURE; + } + if (out == nsnull) { + out = gBloatLog; + } + + LOCK_TRACELOG(); + + PRBool wasLogging = gLogging; + gLogging = PR_FALSE; // turn off logging for this method + + const char* msg; + if (type == NEW_STATS) { + if (gLogLeaksOnly) + msg = "NEW (incremental) LEAK STATISTICS"; + else + msg = "NEW (incremental) LEAK AND BLOAT STATISTICS"; + } + else { + if (gLogLeaksOnly) + msg = "ALL (cumulative) LEAK STATISTICS"; + else + msg = "ALL (cumulative) LEAK AND BLOAT STATISTICS"; + } + rv = BloatEntry::PrintDumpHeader(out, msg); + if (NS_FAILED(rv)) goto done; + + { + BloatEntry total("TOTAL", 0); + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::TotalEntries, &total); + total.DumpTotal(gBloatView->nentries, out); + + nsVoidArray entries; + PL_HashTableEnumerateEntries(gBloatView, BloatEntry::DumpEntry, &entries); + + fprintf(stdout, "nsTraceRefcntImpl::DumpStatistics: %d entries\n", + entries.Count()); + + // Sort the entries alphabetically by classname. + PRInt32 i, j; + for (i = entries.Count() - 1; i >= 1; --i) { + for (j = i - 1; j >= 0; --j) { + BloatEntry* left = NS_STATIC_CAST(BloatEntry*, entries[i]); + BloatEntry* right = NS_STATIC_CAST(BloatEntry*, entries[j]); + + if (PL_strcmp(left->GetClassName(), right->GetClassName()) < 0) { + entries.ReplaceElementAt(right, i); + entries.ReplaceElementAt(left, j); + } + } + } + + // Enumerate from back-to-front, so things come out in alpha order + for (i = 0; i < entries.Count(); ++i) { + BloatEntry* entry = NS_STATIC_CAST(BloatEntry*, entries[i]); + entry->Dump(i, out, type); + } + } + + if (gSerialNumbers) { + fprintf(out, "\n\nSerial Numbers of Leaked Objects:\n"); + PL_HashTableEnumerateEntries(gSerialNumbers, DumpSerialNumbers, out); + } + +done: + gLogging = wasLogging; + UNLOCK_TRACELOG(); +#endif + return rv; +} + +void +nsTraceRefcntImpl::ResetStatistics() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + LOCK_TRACELOG(); + if (gBloatView) { + PL_HashTableDestroy(gBloatView); + gBloatView = nsnull; + } + UNLOCK_TRACELOG(); +#endif +} + +#ifdef NS_BUILD_REFCNT_LOGGING +static PRBool LogThisType(const char* aTypeName) +{ + void* he = PL_HashTableLookup(gTypesToLog, aTypeName); + return nsnull != he; +} + +static PRInt32 GetSerialNumber(void* aPtr, PRBool aCreate) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return PRInt32((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->serialNumber); + } + else if (aCreate) { + serialNumberRecord *record = PR_NEW(serialNumberRecord); + record->serialNumber = ++gNextSerialNumber; + record->refCount = 0; + record->COMPtrCount = 0; + PL_HashTableRawAdd(gSerialNumbers, hep, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr, NS_REINTERPRET_CAST(void*,record)); + return gNextSerialNumber; + } + else { + return 0; + } +} + +static PRInt32* GetRefCount(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->refCount); + } else { + return nsnull; + } +} + +static PRInt32* GetCOMPtrCount(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PLHashEntry** hep = PL_HashTableRawLookup(gSerialNumbers, PLHashNumber(NS_PTR_TO_INT32(aPtr)), aPtr); + if (hep && *hep) { + return &((NS_REINTERPRET_CAST(serialNumberRecord*,(*hep)->value))->COMPtrCount); + } else { + return nsnull; + } +} + +static void RecycleSerialNumberPtr(void* aPtr) +{ +#ifdef GC_LEAK_DETECTOR + // need to disguise this pointer, so the table won't keep the object alive. + aPtr = (void*) ~PLHashNumber(aPtr); +#endif + PL_HashTableRemove(gSerialNumbers, aPtr); +} + +static PRBool LogThisObj(PRInt32 aSerialNumber) +{ + return nsnull != PL_HashTableLookup(gObjectsToLog, (const void*)(uintptr_t)(aSerialNumber)); +} + +static PRBool InitLog(const char* envVar, const char* msg, FILE* *result) +{ + const char* value = getenv(envVar); + if (value) { + if (nsCRT::strcmp(value, "1") == 0) { + *result = stdout; + fprintf(stdout, "### %s defined -- logging %s to stdout\n", + envVar, msg); + return PR_TRUE; + } + else if (nsCRT::strcmp(value, "2") == 0) { + *result = stderr; + fprintf(stdout, "### %s defined -- logging %s to stderr\n", + envVar, msg); + return PR_TRUE; + } + else { + FILE *stream = ::fopen(value, "w"); + if (stream != NULL) { + *result = stream; + fprintf(stdout, "### %s defined -- logging %s to %s\n", + envVar, msg, value); + return PR_TRUE; + } + else { + fprintf(stdout, "### %s defined -- unable to log %s to %s\n", + envVar, msg, value); + return PR_FALSE; + } + } + } + return PR_FALSE; +} + + +static PLHashNumber PR_CALLBACK HashNumber(const void* aKey) +{ + return PLHashNumber(NS_PTR_TO_INT32(aKey)); +} + +static void InitTraceLog(void) +{ + if (gInitialized) return; + gInitialized = PR_TRUE; + +#if defined(XP_MAC) && !TARGET_CARBON + // this can get called before Toolbox has been initialized. + InitializeMacToolbox(); +#endif + + PRBool defined; + defined = InitLog("XPCOM_MEM_BLOAT_LOG", "bloat/leaks", &gBloatLog); + if (!defined) + gLogLeaksOnly = InitLog("XPCOM_MEM_LEAK_LOG", "leaks", &gBloatLog); + if (defined || gLogLeaksOnly) { + RecreateBloatView(); + if (!gBloatView) { + NS_WARNING("out of memory"); + gBloatLog = nsnull; + gLogLeaksOnly = PR_FALSE; + } + } + + (void)InitLog("XPCOM_MEM_REFCNT_LOG", "refcounts", &gRefcntsLog); + + (void)InitLog("XPCOM_MEM_ALLOC_LOG", "new/delete", &gAllocLog); + + defined = InitLog("XPCOM_MEM_LEAKY_LOG", "for leaky", &gLeakyLog); + if (defined) { + gLogToLeaky = PR_TRUE; + void* p = nsnull; + void* q = nsnull; +#ifdef HAVE_LIBDL + p = dlsym(0, "__log_addref"); + q = dlsym(0, "__log_release"); +#endif + if (p && q) { + leakyLogAddRef = (void (*)(void*,int,int)) p; + leakyLogRelease = (void (*)(void*,int,int)) q; + } + else { + gLogToLeaky = PR_FALSE; + fprintf(stdout, "### ERROR: XPCOM_MEM_LEAKY_LOG defined, but can't locate __log_addref and __log_release symbols\n"); + fflush(stdout); + } + } + + const char* classes = getenv("XPCOM_MEM_LOG_CLASSES"); + +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + if (classes) { + (void)InitLog("XPCOM_MEM_COMPTR_LOG", "nsCOMPtr", &gCOMPtrLog); + } else { + if (getenv("XPCOM_MEM_COMPTR_LOG")) { + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but XPCOM_MEM_LOG_CLASSES is not defined\n"); + } + } +#else + const char* comptr_log = getenv("XPCOM_MEM_COMPTR_LOG"); + if (comptr_log) { + fprintf(stdout, "### XPCOM_MEM_COMPTR_LOG defined -- but it will not work without dynamic_cast\n"); + } +#endif + + if (classes) { + // if XPCOM_MEM_LOG_CLASSES was set to some value, the value is interpreted + // as a list of class names to track + gTypesToLog = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + &typesToLogHashAllocOps, NULL); + if (!gTypesToLog) { + NS_WARNING("out of memory"); + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- unable to log specific classes\n"); + } + else { + fprintf(stdout, "### XPCOM_MEM_LOG_CLASSES defined -- only logging these classes: "); + const char* cp = classes; + for (;;) { + char* cm = (char*) strchr(cp, ','); + if (cm) { + *cm = '\0'; + } + PL_HashTableAdd(gTypesToLog, nsCRT::strdup(cp), (void*)1); + fprintf(stdout, "%s ", cp); + if (!cm) break; + *cm = ','; + cp = cm + 1; + } + fprintf(stdout, "\n"); + } + + gSerialNumbers = PL_NewHashTable(256, + HashNumber, + PL_CompareValues, + PL_CompareValues, + &serialNumberHashAllocOps, NULL); + + + } + + const char* objects = getenv("XPCOM_MEM_LOG_OBJECTS"); + if (objects) { + gObjectsToLog = PL_NewHashTable(256, + HashNumber, + PL_CompareValues, + PL_CompareValues, + NULL, NULL); + + if (!gObjectsToLog) { + NS_WARNING("out of memory"); + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- unable to log specific objects\n"); + } + else if (! (gRefcntsLog || gAllocLog || gCOMPtrLog)) { + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- but none of XPCOM_MEM_(REFCNT|ALLOC|COMPTR)_LOG is defined\n"); + } + else { + fprintf(stdout, "### XPCOM_MEM_LOG_OBJECTS defined -- only logging these objects: "); + const char* cp = objects; + for (;;) { + char* cm = (char*) strchr(cp, ','); + if (cm) { + *cm = '\0'; + } + PRInt32 top = 0; + PRInt32 bottom = 0; + while (*cp) { + if (*cp == '-') { + bottom = top; + top = 0; + ++cp; + } + top *= 10; + top += *cp - '0'; + ++cp; + } + if (!bottom) { + bottom = top; + } + for(PRInt32 serialno = bottom; serialno <= top; serialno++) { + PL_HashTableAdd(gObjectsToLog, (const void*)serialno, (void*)1); + fprintf(stdout, "%d ", serialno); + } + if (!cm) break; + *cm = ','; + cp = cm + 1; + } + fprintf(stdout, "\n"); + } + } + + + if (gBloatLog || gRefcntsLog || gAllocLog || gLeakyLog || gCOMPtrLog) { + gLogging = PR_TRUE; + } + + gTraceLock = PR_NewLock(); +} + +#endif + +#if defined(_WIN32) && defined(_M_IX86) // WIN32 x86 stack walking code +#include "nsStackFrameWin.h" +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + DumpStackToFile(aStream); +} + +// WIN32 x86 stack walking code +// i386 or PPC Linux stackwalking code or Solaris +#elif (defined(linux) && !defined(VBOX) && defined(__GLIBC__) && (defined(__i386) || defined(PPC))) || (defined(__sun) && (defined(__sparc) || defined(sparc) || defined(__i386) || defined(i386))) +#include "nsStackFrameUnix.h" +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + DumpStackToFile(aStream); +} + +#elif defined(XP_MAC) + +/** + * Stack walking code for the Mac OS. + */ + +#include "gc_fragments.h" + +#include + +extern "C" { +void MWUnmangle(const char *mangled_name, char *unmangled_name, size_t buffersize); +} + +struct traceback_table { + long zero; + long magic; + long reserved; + long codeSize; + short nameLength; + char name[2]; +}; + +static char* pc2name(long* pc, char name[], long size) +{ + name[0] = '\0'; + + // make sure pc is instruction aligned (at least). + if (UInt32(pc) == (UInt32(pc) & 0xFFFFFFFC)) { + long instructionsToLook = 4096; + long* instruction = (long*)pc; + + // look for the traceback table. + while (instructionsToLook--) { + if (instruction[0] == 0x4E800020 && instruction[1] == 0x00000000) { + traceback_table* tb = (traceback_table*)&instruction[1]; + memcpy(name, tb->name + 1, --nameLength); + name[nameLength] = '\0'; + break; + } + ++instruction; + } + } + + return name; +} + +struct stack_frame { + stack_frame* next; // savedSP + void* savedCR; + void* savedLR; + void* reserved0; + void* reserved1; + void* savedTOC; +}; + +static asm stack_frame* getStackFrame() +{ + mr r3, sp + blr +} + +NS_COM void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + stack_frame* currentFrame = getStackFrame(); // WalkTheStack's frame. + currentFrame = currentFrame->next; // WalkTheStack's caller's frame. + currentFrame = currentFrame->next; // WalkTheStack's caller's caller's frame. + + while (true) { + // LR saved at 8(SP) in each frame. subtract 4 to get address of calling instruction. + void* pc = currentFrame->savedLR; + + // convert PC to name, unmangle it, and generate source location, if possible. + static char symbol_name[1024], unmangled_name[1024], file_name[256]; UInt32 file_offset; + + if (GC_address_to_source((char*)pc, symbol_name, file_name, &file_offset)) { + MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name)); + fprintf(aStream, "%s[%s,%ld]\n", unmangled_name, file_name, file_offset); + } else { + pc2name((long*)pc, symbol_name, sizeof(symbol_name)); + MWUnmangle(symbol_name, unmangled_name, sizeof(unmangled_name)); + fprintf(aStream, "%s(0x%08X)\n", unmangled_name, pc); + } + + currentFrame = currentFrame->next; + // the bottom-most frame is marked as pointing to NULL, or is ODD if a 68K transition frame. + if (currentFrame == NULL || UInt32(currentFrame) & 0x1) + break; + } +} + +#else // unsupported platform. + +void +nsTraceRefcntImpl::WalkTheStack(FILE* aStream) +{ + fprintf(aStream, "write me, dammit!\n"); +} + +#endif + +//---------------------------------------------------------------------- + +// This thing is exported by libstdc++ +// Yes, this is a gcc only hack +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include +#include // for free() +#endif // MOZ_DEMANGLE_SYMBOLS + +NS_COM void +nsTraceRefcntImpl::DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen) +{ + NS_ASSERTION(nsnull != aSymbol,"null symbol"); + NS_ASSERTION(nsnull != aBuffer,"null buffer"); + NS_ASSERTION(aBufLen >= 32 ,"pulled 32 out of you know where"); + + aBuffer[0] = '\0'; + +#if defined(MOZ_DEMANGLE_SYMBOLS) + /* See demangle.h in the gcc source for the voodoo */ + char * demangled = abi::__cxa_demangle(aSymbol,0,0,0); + + if (demangled) + { + strncpy(aBuffer,demangled,aBufLen); + free(demangled); + } +#endif // MOZ_DEMANGLE_SYMBOLS +} + + +//---------------------------------------------------------------------- + +NS_COM void +nsTraceRefcntImpl::LoadLibrarySymbols(const char* aLibraryName, + void* aLibrayHandle) +{ +#ifdef NS_BUILD_REFCNT_LOGGING +#if defined(_WIN32) && defined(_M_IX86) /* Win32 x86 only */ + if (!gInitialized) + InitTraceLog(); + + if (gAllocLog || gRefcntsLog) { + fprintf(stdout, "### Loading symbols for %s\n", aLibraryName); + fflush(stdout); + + HANDLE myProcess = ::GetCurrentProcess(); + BOOL ok = EnsureSymInitialized(); + if (ok) { + const char* baseName = aLibraryName; + // just get the base name of the library if a full path was given: + PRInt32 len = strlen(aLibraryName); + for (PRInt32 i = len - 1; i >= 0; i--) { + if (aLibraryName[i] == '\\') { + baseName = &aLibraryName[i + 1]; + break; + } + } + DWORD baseAddr = _SymLoadModule(myProcess, + NULL, + (char*)baseName, + (char*)baseName, + 0, + 0); + ok = (baseAddr != nsnull); + } + if (!ok) { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(stdout, "### ERROR: LoadLibrarySymbols for %s: %s\n", + aLibraryName, lpMsgBuf); + fflush(stdout); + LocalFree( lpMsgBuf ); + } + } +#endif +#endif +} + +//---------------------------------------------------------------------- + + + + + + +// don't use the logging ones. :-) +NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::AddRef(void) +{ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + ++mRefCnt; + return mRefCnt; +} + +NS_IMETHODIMP_(nsrefcnt) nsTraceRefcntImpl::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + --mRefCnt; + if (mRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + return mRefCnt; +} + +NS_IMPL_QUERY_INTERFACE1(nsTraceRefcntImpl, nsITraceRefcnt) + +nsTraceRefcntImpl::nsTraceRefcntImpl() +{ + /* member initializers and constructor code */ +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogAddRef(void* aPtr, + nsrefcnt aRefcnt, + const char* aClazz, + PRUint32 classSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aClazz, classSize); + if (entry) { + entry->AddRef(aRefcnt); + } + } + + // Here's the case where neither NS_NEWXPCOM nor MOZ_COUNT_CTOR were used, + // yet we still want to see creation information: + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, aRefcnt == 1); + PRInt32* count = GetRefCount(aPtr); + if(count) + (*count)++; + + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (aRefcnt == 1 && gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Create\n", + aClazz, NS_PTR_TO_INT32(aPtr), serialno); + WalkTheStack(gAllocLog); + } + + if (gRefcntsLog && loggingThisType && loggingThisObject) { + if (gLogToLeaky) { + (*leakyLogAddRef)(aPtr, aRefcnt - 1, aRefcnt); + } + else { + // Can't use PR_LOG(), b/c it truncates the line + fprintf(gRefcntsLog, + "\n<%s> 0x%08X %d AddRef %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + WalkTheStack(gRefcntsLog); + fflush(gRefcntsLog); + } + } + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogRelease(void* aPtr, + nsrefcnt aRefcnt, + const char* aClazz) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aClazz, 0); + if (entry) { + entry->Release(aRefcnt); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aClazz)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_FALSE); + PRInt32* count = GetRefCount(aPtr); + if(count) + (*count)--; + + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (gRefcntsLog && loggingThisType && loggingThisObject) { + if (gLogToLeaky) { + (*leakyLogRelease)(aPtr, aRefcnt + 1, aRefcnt); + } + else { + // Can't use PR_LOG(), b/c it truncates the line + fprintf(gRefcntsLog, + "\n<%s> 0x%08X %d Release %d\n", aClazz, NS_PTR_TO_INT32(aPtr), serialno, aRefcnt); + WalkTheStack(gRefcntsLog); + fflush(gRefcntsLog); + } + } + + // Here's the case where neither NS_DELETEXPCOM nor MOZ_COUNT_DTOR were used, + // yet we still want to see deletion information: + + if (aRefcnt == 0 && gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, + "\n<%s> 0x%08X %d Destroy\n", + aClazz, NS_PTR_TO_INT32(aPtr), serialno); + WalkTheStack(gAllocLog); + } + + if (aRefcnt == 0 && gSerialNumbers && loggingThisType) { + RecycleSerialNumberPtr(aPtr); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsTraceRefcntImpl::LogCtor(void* aPtr, + const char* aType, + PRUint32 aInstanceSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); + if (entry) { + entry->Ctor(); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aType)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_TRUE); + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + if (gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Ctor (%d)\n", + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); + WalkTheStack(gAllocLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogDtor(void* aPtr, + const char* aType, + PRUint32 aInstanceSize) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + ASSERT_ACTIVITY_IS_LEGAL; + if (!gInitialized) + InitTraceLog(); + + if (gLogging) { + LOCK_TRACELOG(); + + if (gBloatLog) { + BloatEntry* entry = GetBloatEntry(aType, aInstanceSize); + if (entry) { + entry->Dtor(); + } + } + + PRBool loggingThisType = (!gTypesToLog || LogThisType(aType)); + PRInt32 serialno = 0; + if (gSerialNumbers && loggingThisType) { + serialno = GetSerialNumber(aPtr, PR_FALSE); + RecycleSerialNumberPtr(aPtr); + } + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + // (If we're on a losing architecture, don't do this because we'll be + // using LogDeleteXPCOM instead to get file and line numbers.) + if (gAllocLog && loggingThisType && loggingThisObject) { + fprintf(gAllocLog, "\n<%s> 0x%08X %d Dtor (%d)\n", + aType, NS_PTR_TO_INT32(aPtr), serialno, aInstanceSize); + WalkTheStack(gAllocLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogAddCOMPtr(void* aCOMPtr, + nsISupports* aObject) +{ +#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) + // Get the most-derived object. + void *object = dynamic_cast(aObject); + + // This is a very indirect way of finding out what the class is + // of the object being logged. If we're logging a specific type, + // then + if (!gTypesToLog || !gSerialNumbers) { + return NS_OK; + } + PRInt32 serialno = GetSerialNumber(object, PR_FALSE); + if (serialno == 0) { + return NS_OK; + } + + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + PRInt32* count = GetCOMPtrCount(object); + if(count) + (*count)++; + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + if (gCOMPtrLog && loggingThisObject) { + fprintf(gCOMPtrLog, "\n 0x%08X %d nsCOMPtrAddRef %d 0x%08X\n", + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); + WalkTheStack(gCOMPtrLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + + +NS_IMETHODIMP +nsTraceRefcntImpl::LogReleaseCOMPtr(void* aCOMPtr, + nsISupports* aObject) +{ +#if defined(NS_BUILD_REFCNT_LOGGING) && defined(HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR) + // Get the most-derived object. + void *object = dynamic_cast(aObject); + + // This is a very indirect way of finding out what the class is + // of the object being logged. If we're logging a specific type, + // then + if (!gTypesToLog || !gSerialNumbers) { + return NS_OK; + } + PRInt32 serialno = GetSerialNumber(object, PR_FALSE); + if (serialno == 0) { + return NS_OK; + } + + if (!gInitialized) + InitTraceLog(); + if (gLogging) { + LOCK_TRACELOG(); + + PRInt32* count = GetCOMPtrCount(object); + if(count) + (*count)--; + + PRBool loggingThisObject = (!gObjectsToLog || LogThisObj(serialno)); + + if (gCOMPtrLog && loggingThisObject) { + fprintf(gCOMPtrLog, "\n 0x%08X %d nsCOMPtrRelease %d 0x%08X\n", + NS_PTR_TO_INT32(object), serialno, count?(*count):-1, NS_PTR_TO_INT32(aCOMPtr)); + WalkTheStack(gCOMPtrLog); + } + + UNLOCK_TRACELOG(); + } +#endif + return NS_OK; +} + +NS_COM void +nsTraceRefcntImpl::Startup() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + SetActivityIsLegal(PR_TRUE); +#endif +} + +NS_COM void +nsTraceRefcntImpl::Shutdown() +{ +#ifdef NS_BUILD_REFCNT_LOGGING + + if (gBloatView) { + PL_HashTableDestroy(gBloatView); + gBloatView = nsnull; + } + if (gTypesToLog) { + PL_HashTableDestroy(gTypesToLog); + gTypesToLog = nsnull; + } + if (gObjectsToLog) { + PL_HashTableDestroy(gObjectsToLog); + gObjectsToLog = nsnull; + } + if (gSerialNumbers) { + PL_HashTableDestroy(gSerialNumbers); + gSerialNumbers = nsnull; + } + + SetActivityIsLegal(PR_FALSE); + +#endif +} + +NS_COM void +nsTraceRefcntImpl::SetActivityIsLegal(PRBool aLegal) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + gActivityIsLegal = aLegal; +#endif +} + + +NS_METHOD +nsTraceRefcntImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + *aInstancePtr = nsnull; + nsITraceRefcnt* tracer = new nsTraceRefcntImpl(); + if (!tracer) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = tracer->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) { + delete tracer; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h new file mode 100644 index 00000000..528b285d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsTraceRefcntImpl.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsTraceRefcntImpl_h___ +#define nsTraceRefcntImpl_h___ + +#include // for FILE +#include "nsITraceRefcnt.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_MeanAndStdDev VBoxNsxpNS_MeanAndStdDev +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class nsTraceRefcntImpl : public nsITraceRefcnt +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITRACEREFCNT + + nsTraceRefcntImpl(); + + static NS_COM void Startup(); + static NS_COM void Shutdown(); + + enum StatisticsType { + ALL_STATS, + NEW_STATS + }; + + static NS_COM nsresult DumpStatistics(StatisticsType type = ALL_STATS, + FILE* out = 0); + + static NS_COM void ResetStatistics(void); + + static NS_COM void LoadLibrarySymbols(const char* aLibraryName, + void* aLibrayHandle); + + + static NS_COM void DemangleSymbol(const char * aSymbol, + char * aBuffer, + int aBufLen); + + static NS_COM void WalkTheStack(FILE* aStream); + /** + * Tell nsTraceRefcnt whether refcounting, allocation, and destruction + * activity is legal. This is used to trigger assertions for any such + * activity that occurs because of static constructors or destructors. + */ + static NS_COM void SetActivityIsLegal(PRBool aLegal); + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsTraceRefcntImpl() {} +}; + +#define NS_TRACE_REFCNT_CONTRACTID "@mozilla.org/xpcom/trace-refcnt;1" +#define NS_TRACE_REFCNT_CLASSNAME "nsTraceRefcnt Interface" +#define NS_TRACE_REFCNT_CID \ +{ /* e3e7511e-a395-4924-94b1-d527861cded4 */ \ + 0xe3e7511e, \ + 0xa395, \ + 0x4924, \ + {0x94, 0xb1, 0xd5, 0x27, 0x86, 0x1c, 0xde, 0xd4} \ +} \ + +//////////////////////////////////////////////////////////////////////////////// +// And now for that utility that you've all been asking for... + +extern "C" NS_COM void +NS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult); + +//////////////////////////////////////////////////////////////////////////////// +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h b/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h new file mode 100644 index 00000000..c15e31f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsWeakPtr.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsWeakPtr_h__ +#define nsWeakPtr_h__ + +#include "nsIWeakReference.h" +#include "nsCOMPtr.h" + +// typedef nsCOMPtr nsWeakPtr; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/nscore.h b/src/libs/xpcom18a4/xpcom/base/nscore.h new file mode 100644 index 00000000..b7bfa11f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nscore.h @@ -0,0 +1,468 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nscore_h___ +#define nscore_h___ + +/** + * Make sure that we have the proper platform specific + * c++ definitions needed by nscore.h + */ +#ifndef _XPCOM_CONFIG_H_ +#include "xpcom-config.h" +#endif + +/** + * Incorporate the core NSPR data types which XPCOM uses. + */ +#include "prtypes.h" + +/* Core XPCOM declarations. */ + +/** + * Macros defining the target platform... + */ +#ifdef _WIN32 +#define NS_WIN32 1 + +#elif defined(__unix) +#define NS_UNIX 1 + +#elif defined(XP_OS2) +#define NS_OS2 1 +#endif +/*----------------------------------------------------------------------*/ +/* Import/export defines */ + +/** + * Using the visibility("hidden") attribute allows the compiler to use + * PC-relative addressing to call this function. If a function does not + * access any global data, and does not call any methods which are not either + * file-local or hidden, then on ELF systems we avoid loading the address of + * the PLT into a register at the start of the function, which reduces code + * size and frees up a register for general use. + * + * As a general rule, this should be used for any non-exported symbol + * (including virtual method implementations). NS_IMETHOD uses this by + * default; if you need to have your NS_IMETHOD functions exported, you can + * wrap your class as follows: + * + * #undef IMETHOD_VISIBILITY + * #define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + * + * class Foo { + * ... + * }; + * + * #undef IMETHOD_VISIBILITY + * #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + * + * Don't forget to change the visibility back to hidden before the end + * of a header! + * + * Other examples: + * + * NS_HIDDEN_(int) someMethod(); + * SomeCtor() NS_HIDDEN; + */ + +#ifdef HAVE_VISIBILITY_ATTRIBUTE +#define NS_VISIBILITY_HIDDEN __attribute__ ((visibility ("hidden"))) +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define NS_VISIBILITY_DEFAULT __attribute__ ((visibility ("default"))) +# else +# define NS_VISIBILITY_DEFAULT +# endif + +#define NS_HIDDEN_(type) NS_VISIBILITY_HIDDEN type +#else +#define NS_VISIBILITY_HIDDEN +#define NS_VISIBILITY_DEFAULT + +#define NS_HIDDEN_(type) type +#endif + +#define NS_HIDDEN NS_VISIBILITY_HIDDEN + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +/** + * Mark a function as using a potentially non-standard function calling + * convention. This can be used on functions that are called very + * frequently, to reduce the overhead of the function call. It is still worth + * using the macro for C++ functions which take no parameters since it allows + * passing |this| in a register. + * + * - Do not use this on any scriptable interface method since xptcall won't be + * aware of the different calling convention. + * - This must appear on the declaration, not the definition. + * - Adding this to a public function _will_ break binary compatibility. + * - This may be used on virtual functions but you must ensure it is applied + * to all implementations - the compiler will _not_ warn but it will crash. + * - This has no effect for inline functions or functions which take a + * variable number of arguments. + * + * Examples: int NS_FASTCALL func1(char *foo); + * NS_HIDDEN_(int) NS_FASTCALL func2(char *foo); + */ + +#if defined(__i386__) && defined(__GNUC__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define NS_FASTCALL __attribute__ ((regparm (3), stdcall)) +#else +#define NS_FASTCALL +#endif + +/* XXX: nike, maybe fix */ +#define NS_EXPORT_STATIC_MEMBER_(type) type +#define NS_IMPORT_STATIC_MEMBER_(type) type + +#ifdef NS_WIN32 + +#define NS_IMPORT __declspec(dllimport) +#define NS_IMPORT_(type) type __declspec(dllimport) __stdcall +#define NS_EXPORT __declspec(dllexport) +#define NS_EXPORT_(type) type __declspec(dllexport) __stdcall +#define NS_IMETHOD_(type) virtual type __stdcall +#define NS_IMETHODIMP_(type) type __stdcall +#define NS_METHOD_(type) type __stdcall +#define NS_CALLBACK_(_type, _name) _type (__stdcall * _name) +#define NS_STDCALL __stdcall + +#elif defined(XP_MAC) + +#define NS_IMPORT +#define NS_IMPORT_(type) type +#define NS_EXPORT __declspec(export) +#define NS_EXPORT_(type) __declspec(export) type +#define NS_IMETHOD_(type) virtual type +#define NS_IMETHODIMP_(type) type +#define NS_METHOD_(type) type +#define NS_CALLBACK_(_type, _name) _type (* _name) +#define NS_STDCALL + +#elif defined(XP_OS2) && defined(__declspec) + +#define NS_IMPORT __declspec(dllimport) +#define NS_IMPORT_(type) type __declspec(dllimport) __stdcall +#define NS_EXPORT __declspec(dllexport) +#define NS_EXPORT_(type) type __declspec(dllexport) __stdcall +#define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +#define NS_IMETHODIMP_(type) type +#define NS_METHOD_(type) type +#define NS_CALLBACK_(_type, _name) _type (* _name) +#define NS_STDCALL + +#else + +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define NS_IMPORT +# define NS_IMPORT_(type) type +# define NS_EXPORT __attribute__((visibility("default"))) +# define NS_EXPORT_(type) __attribute__((visibility("default"))) type +# define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +# define NS_IMETHODIMP_(type) type +# define NS_METHOD_(type) type +# define NS_CALLBACK_(_type, _name) _type (* _name) +# define NS_STDCALL +# else +# define NS_IMPORT +# define NS_IMPORT_(type) type +# define NS_EXPORT +# define NS_EXPORT_(type) type +# define NS_IMETHOD_(type) virtual IMETHOD_VISIBILITY type +# define NS_IMETHODIMP_(type) type +# define NS_METHOD_(type) type +# define NS_CALLBACK_(_type, _name) _type (* _name) +# define NS_STDCALL +# endif +#endif + +/** + * Macro for creating typedefs for pointer-to-member types which are + * declared with stdcall. It is important to use this for any type which is + * declared as stdcall (i.e. NS_IMETHOD). For example, instead of writing: + * + * typedef nsresult (nsIFoo::*someType)(nsISupports* arg); + * + * you should write: + * + * typedef + * NS_STDCALL_FUNCPROTO(nsresult, someType, nsIFoo, typeFunc, (nsISupports*)); + * + * where nsIFoo::typeFunc is any method declared as + * NS_IMETHOD typeFunc(nsISupports*); + * + * XXX this can be simplified to always use the non-typeof implementation + * when http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11893 is fixed. + */ + +#ifdef __GNUC__ +#define NS_STDCALL_FUNCPROTO(ret, name, class, func, args) \ + typeof(&class::func) name +#else +#define NS_STDCALL_FUNCPROTO(ret, name, class, func, args) \ + ret (NS_STDCALL class::*name) args +#endif + +/** + * Generic API modifiers which return the standard XPCOM nsresult type + */ +#define NS_IMETHOD NS_IMETHOD_(nsresult) +#define NS_IMETHODIMP NS_IMETHODIMP_(nsresult) +#define NS_METHOD NS_METHOD_(nsresult) +#define NS_CALLBACK(_name) NS_CALLBACK_(nsresult, _name) + +/** + * Import/Export macros for XPCOM APIs + */ + +#ifdef _IMPL_NS_COM +#define NS_COM NS_EXPORT +#elif _IMPL_NS_COM_OFF +#define NS_COM +#elif XPCOM_GLUE +#define NS_COM +#else +#define NS_COM NS_IMPORT +#endif + + +/** + * NS_NO_VTABLE is emitted by xpidl in interface declarations whenever + * xpidl can determine that the interface can't contain a constructor. + * This results in some space savings and possible runtime savings - + * see bug 49416. We undefine it first, as xpidl-generated headers + * define it for IDL uses that don't include this file. + */ +#ifdef NS_NO_VTABLE +#undef NS_NO_VTABLE +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1100 +#define NS_NO_VTABLE __declspec(novtable) +#else +#define NS_NO_VTABLE +#endif + + +/** + * Generic XPCOM result data type + */ +typedef PRUint32 nsresult; + +/** + * The preferred symbol for null. + */ +#define nsnull 0 + +#include "nsError.h" + +/* ------------------------------------------------------------------------ */ +/* Casting macros for hiding C++ features from older compilers */ + + /* + All our compiler support template specialization, but not all support the + |template <>| notation. The compiler that don't understand this notation + just omit it for specialization. + + Need to add an autoconf test for this. + */ + + /* under Metrowerks (Mac), we don't have autoconf yet */ +#ifdef __MWERKS__ + #define HAVE_CPP_PARTIAL_SPECIALIZATION + #define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + + #define HAVE_CPP_ACCESS_CHANGING_USING + #define HAVE_CPP_AMBIGUITY_RESOLVING_USING + #define HAVE_CPP_EXPLICIT + #define HAVE_CPP_TYPENAME + #define HAVE_CPP_BOOL + #define HAVE_CPP_NAMESPACE_STD + #define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + #define HAVE_CPP_2BYTE_WCHAR_T +#endif + + /* under VC++ (Windows), we don't have autoconf yet */ +#if defined(_MSC_VER) && (_MSC_VER>=1100) + /* VC++ 5.0 and greater implement template specialization, 4.2 is unknown */ + #define HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + + #define HAVE_CPP_EXPLICIT + #define HAVE_CPP_TYPENAME + #define HAVE_CPP_ACCESS_CHANGING_USING + + #if (_MSC_VER==1100) + /* VC++5.0 has an internal compiler error (sometimes) without this */ + #undef HAVE_CPP_ACCESS_CHANGING_USING + #endif + + #define HAVE_CPP_NAMESPACE_STD + #define HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + #define HAVE_CPP_2BYTE_WCHAR_T +#endif + +#ifndef __PRUNICHAR__ +#define __PRUNICHAR__ + /* For now, don't use wchar_t on Unix because it breaks the Netscape + * commercial build. When this is fixed there will be no need for the + * |NS_REINTERPRET_CAST| in nsLiteralString.h either. + */ + #if defined(HAVE_CPP_2BYTE_WCHAR_T) && (defined(NS_WIN32) || defined(XP_MAC)) + typedef wchar_t PRUnichar; + #else + typedef PRUint16 PRUnichar; + #endif +#endif + + /* + If the compiler doesn't support |explicit|, we'll just make it go away, trusting + that the builds under compilers that do have it will keep us on the straight and narrow. + */ +#ifndef HAVE_CPP_EXPLICIT + #define explicit +#endif + +#ifndef HAVE_CPP_TYPENAME + #define typename +#endif + +#ifdef HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + #define NS_SPECIALIZE_TEMPLATE template <> +#else + #define NS_SPECIALIZE_TEMPLATE +#endif + +/* unix and beos now determine this automatically */ +#if ! defined XP_UNIX && ! defined XP_BEOS && !defined(XP_OS2) +#ifndef HAVE_CPP_NEW_CASTS +#define HAVE_CPP_NEW_CASTS 1 /* we'll be optimistic. */ +#endif +#endif + +#if defined(HAVE_CPP_NEW_CASTS) +#define NS_STATIC_CAST(__type, __ptr) static_cast< __type >(__ptr) +#define NS_CONST_CAST(__type, __ptr) const_cast< __type >(__ptr) + +#define NS_REINTERPRET_POINTER_CAST(__type, __ptr) reinterpret_cast< __type >(__ptr) +#define NS_REINTERPRET_NONPOINTER_CAST(__type, __obj) reinterpret_cast< __type >(__obj) +#define NS_REINTERPRET_CAST(__type, __expr) reinterpret_cast< __type >(__expr) + +#else +#define NS_STATIC_CAST(__type, __ptr) ((__type)(__ptr)) +#define NS_CONST_CAST(__type, __ptr) ((__type)(__ptr)) + +#define NS_REINTERPRET_POINTER_CAST(__type, __ptr) ((__type)((void*)(__ptr))) +#define NS_REINTERPRET_NONPOINTER_CAST(__type, __obj) ((__type)(__obj)) + + /* Note: the following is only appropriate for pointers. */ +#define NS_REINTERPRET_CAST(__type, __expr) NS_REINTERPRET_POINTER_CAST(__type, __expr) + /* + Why cast to a |void*| first? Well, when old-style casting from + a pointer to a base to a pointer to a derived class, the cast will be + ambiguous if the source pointer type appears multiple times in the + destination, e.g., + + class Base {}; + class Derived : public Base, public Base {}; + + void foo( Base* b ) + { + ((Derived*)b)->some_derived_member ... // Error: Ambiguous, expand from which |Base|? + } + + an old-style cast (like |static_cast|) will change the pointer, but + here, doesn't know how. The cast to |void*| prevents it from thinking + it needs to expand the original pointer. + + The cost is, |NS_REINTERPRET_CAST| is no longer appropriate for non-pointer + conversions. Also, mis-applying |NS_REINTERPRET_CAST| to cast |this| to something + will still expand the pointer to the outer object in standards complying compilers. + */ + + /* + No sense in making an NS_DYNAMIC_CAST() macro: you can't duplicate + the semantics. So if you want to dynamic_cast, then just use it + "straight", no macro. + */ +#endif + +#if __cplusplus+0 > 201100L +#define NS_DEFAULT = default +#define NS_DELETE = delete +#else +#define NS_DEFAULT +#define NS_DELETE +#endif + + +#ifndef VBOX +/* + * Use these macros to do 64bit safe pointer conversions. + */ + +#define NS_PTR_TO_INT32(x) ((char *)(x) - (char *)0) +#define NS_INT32_TO_PTR(x) ((void *)((char *)0 + (x))) +#else /* VBOX */ +// This stuff is (contrary to the comment) totally 64bit unsafe, so strip +// it down to only do one direction, which is used by the hashing code. +#define NS_PTR_TO_INT32(x) ((PRInt32)((char *)(x) - (char *)0)) +#endif /* VBOX */ + +/* + * These macros allow you to give a hint to the compiler about branch + * probability so that it can better optimize. Use them like this: + * + * if (NS_LIKELY(v == 1)) { + * ... expected code path ... + * } + * + * if (NS_UNLIKELY(v == 0)) { + * ... non-expected code path ... + * } + * + */ + +#if defined(__GNUC__) && (__GNUC__ > 2) && !defined(FORTIFY_RUNNING) +#define NS_LIKELY(x) (__builtin_expect(!!(x), 1)) +#define NS_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#else +#define NS_LIKELY(x) (x) +#define NS_UNLIKELY(x) (x) +#endif + +#endif /* nscore_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl b/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl new file mode 100644 index 00000000..0538e4bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/nsrootidl.idl @@ -0,0 +1,128 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Root idl declarations to be used by all. + * @status FROZEN + */ + +%{C++ + +#include "nscore.h" +#include "prtime.h" + +/* + * Forward declarations for new string types + */ +class nsAString; +class nsACString; + +/* + * Start commenting out the C++ versions of the below in the output header + */ +#if 0 +%} + +typedef boolean PRBool ; +typedef octet PRUint8 ; +typedef unsigned short PRUint16 ; +typedef unsigned short PRUnichar; +typedef unsigned long PRUint32 ; +typedef unsigned long long PRUint64 ; +typedef unsigned long long PRTime ; +typedef short PRInt16 ; +typedef long PRInt32 ; +typedef long long PRInt64 ; + +typedef unsigned long nsrefcnt ; +typedef unsigned long nsresult ; + +// XXX need this built into xpidl compiler so that it's really size_t or PRSize +// and it's scriptable: +typedef unsigned long size_t; + +[ptr] native voidPtr(void); +[ptr] native charPtr(char); +[ptr] native unicharPtr(PRUnichar); + +[ref, nsid] native nsIDRef(nsID); +[ref, nsid] native nsIIDRef(nsIID); +[ref, nsid] native nsCIDRef(nsCID); + +[ptr, nsid] native nsIDPtr(nsID); +[ptr, nsid] native nsIIDPtr(nsIID); +[ptr, nsid] native nsCIDPtr(nsCID); + +// NOTE: Be careful in using the following 3 types. The *Ref and *Ptr variants +// are more commonly used (and better supported). Those variants require +// nsMemory alloc'd copies when used as 'out' params while these types do not. +// However, currently these types can not be used for 'in' params. And, methods +// that use them as 'out' params *must* be declared [notxpcom] (with an explicit +// return type of nsresult). This makes such methods implicitly not scriptable. +// Use of these types in methods without a [notxpcom] declaration will cause +// the xpidl compiler to raise an error. +// See: http://bugzilla.mozilla.org/show_bug.cgi?id=93792 + +[nsid] native nsIID(nsIID); +[nsid] native nsID(nsID); +[nsid] native nsCID(nsCID); + +[ptr] native nsQIResult(void); + +[ref, domstring] native DOMString(ignored); +[ref, domstring] native DOMStringRef(ignored); +[ptr, domstring] native DOMStringPtr(ignored); + +[ref, utf8string] native AUTF8String(ignored); +[ref, utf8string] native AUTF8StringRef(ignored); +[ptr, utf8string] native AUTF8StringPtr(ignored); + +[ref, cstring] native ACString(ignored); +[ref, cstring] native ACStringRef(ignored); +[ptr, cstring] native ACStringPtr(ignored); + +[ref, astring] native AString(ignored); +[ref, astring] native AStringRef(ignored); +[ptr, astring] native AStringPtr(ignored); + +%{C++ +/* + * End commenting out the C++ versions of the above in the output header + */ +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/base/pure.h b/src/libs/xpcom18a4/xpcom/base/pure.h new file mode 100644 index 00000000..ea11b99d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/pure.h @@ -0,0 +1,135 @@ +/* + * Header file of Pure API function declarations. + * + * Explicitly no copyright. + * You may recompile and redistribute these definitions as required. + * + * Version 1.0 + */ + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif + +#define PURE_H_VERSION 1 + +////////////////////////////// +// API's Specific to Purify // +////////////////////////////// + +// TRUE when Purify is running. +int __cdecl PurifyIsRunning(void) ; +// +// Print a string to the viewer. +// +int __cdecl PurePrintf(const char *fmt, ...) ; +int __cdecl PurifyPrintf(const char *fmt, ...) ; +// +// Purify functions for leak and memory-in-use functionalty. +// +int __cdecl PurifyNewInuse(void) ; +int __cdecl PurifyAllInuse(void) ; +int __cdecl PurifyClearInuse(void) ; +int __cdecl PurifyNewLeaks(void) ; +int __cdecl PurifyAllLeaks(void) ; +int __cdecl PurifyClearLeaks(void) ; +// +// Purify functions for handle leakage. +// +int __cdecl PurifyAllHandlesInuse(void) ; +int __cdecl PurifyNewHandlesInuse(void) ; +// +// Functions that tell you about the state of memory. +// +int __cdecl PurifyDescribe(void *addr) ; +int __cdecl PurifyWhatColors(void *addr, int size) ; +// +// Functions to test the state of memory. If the memory is not +// accessable, an error is signaled just as if there were a memory +// reference and the function returns false. +// +int __cdecl PurifyAssertIsReadable(const void *addr, int size) ; +int __cdecl PurifyAssertIsWritable(const void *addr, int size) ; +// +// Functions to test the state of memory. If the memory is not +// accessable, these functions return false. No error is signaled. +// +int __cdecl PurifyIsReadable(const void *addr, int size) ; +int __cdecl PurifyIsWritable(const void *addr, int size) ; +int __cdecl PurifyIsInitialized(const void *addr, int size) ; +// +// Functions to set the state of memory. +// +void __cdecl PurifyMarkAsInitialized(void *addr, int size) ; +void __cdecl PurifyMarkAsUninitialized(void *addr, int size) ; +// +// Functions to do late detection of ABWs, FMWs, IPWs. +// +#define PURIFY_HEAP_CRT 0xfffffffe +#define PURIFY_HEAP_ALL 0xfffffffd +#define PURIFY_HEAP_BLOCKS_LIVE 0x80000000 +#define PURIFY_HEAP_BLOCKS_DEFERRED_FREE 0x40000000 +#define PURIFY_HEAP_BLOCKS_ALL (PURIFY_HEAP_BLOCKS_LIVE|PURIFY_HEAP_BLOCKS_DEFERRED_FREE) +int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) ; +int __cdecl PurifySetLateDetectScanCounter(int counter); +int __cdecl PurifySetLateDetectScanInterval(int seconds); + + +//////////////////////////////// +// API's Specific to Quantify // +//////////////////////////////// + +// TRUE when Quantify is running. +int __cdecl QuantifyIsRunning(void) ; + +// +// Functions for controlling collection +// +int __cdecl QuantifyDisableRecordingData(void) ; +int __cdecl QuantifyStartRecordingData(void) ; +int __cdecl QuantifyStopRecordingData(void) ; +int __cdecl QuantifyClearData(void) ; +int __cdecl QuantifyIsRecordingData(void) ; + +// Add a comment to the dataset +int __cdecl QuantifyAddAnnotation(char *) ; + +// Save the current data, creating a "checkpoint" dataset +int __cdecl QuantifySaveData(void) ; + +//////////////////////////////// +// API's Specific to Coverage // +//////////////////////////////// + +// TRUE when Coverage is running. +int __cdecl CoverageIsRunning(void) ; +// +// Functions for controlling collection +// +int __cdecl CoverageDisableRecordingData(void) ; +int __cdecl CoverageStartRecordingData(void) ; +int __cdecl CoverageStopRecordingData(void) ; +int __cdecl CoverageClearData(void) ; +int __cdecl CoverageIsRecordingData(void) ; +// Add a comment to the dataset +int __cdecl CoverageAddAnnotation(char *) ; + +// Save the current data, creating a "checkpoint" dataset +int __cdecl CoverageSaveData(void) ; + + + + +//////////////////////////////// +// API's Specific to Purelock // +//////////////////////////////// + +// TRUE when Purelock is running. +int __cdecl PurelockIsRunning(void) ; + + + + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/base/pure_api.c b/src/libs/xpcom18a4/xpcom/base/pure_api.c new file mode 100644 index 00000000..716460ed --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/base/pure_api.c @@ -0,0 +1,126 @@ +/* + * Header file of Pure API function declarations. + * + * Explicitly no copyright. + * You may recompile and redistribute these definitions as required. + * + * NOTE1: In some situations when compiling with MFC, you should + * enable the setting 'Not using precompiled headers' in Visual C++ + * to avoid a compiler diagnostic. + * + * NOTE2: This file works through the use of deep magic. Calls to functions + * in this file are replaced with calls into the OCI runtime system + * when an instrumented version of this program is run. + * + * NOTE3: The static vars avoidGy_n (where n is a unique number) are used + * to prevent optimizing the functions away when compiler option + * /Gy is set. This is needed so that NOTE2 works properly. + */ +static int avoidGy_1; +static int avoidGy_2; +static int avoidGy_3; +static int avoidGy_4; +static int avoidGy_5; +static int avoidGy_6; +static int avoidGy_7; +static int avoidGy_8; +static int avoidGy_9; +static int avoidGy_10; +static int avoidGy_11; +static int avoidGy_12; +static int avoidGy_13; +static int avoidGy_14; +static int avoidGy_15; +static int avoidGy_16; +static int avoidGy_17; +static int avoidGy_18; +static int avoidGy_19; +static int avoidGy_20; +static int avoidGy_21; +static int avoidGy_22; +static int avoidGy_23; +static int avoidGy_24; +static int avoidGy_25; +static int avoidGy_26; +static int avoidGy_27; +static int avoidGy_28; +static int avoidGy_29; +static int avoidGy_30; +static int avoidGy_31; +static int avoidGy_32; +static int avoidGy_33; +static int avoidGy_34; +static int avoidGy_35; +static int avoidGy_36; +static int avoidGy_37; +static int avoidGy_38; +static int avoidGy_39; +static int avoidGy_40; +static int avoidGy_41; +static int avoidGy_42; +static int avoidGy_43; +static int avoidGy_44; +static int avoidGy_45; +static int avoidGy_46; +static int avoidGy_47; +static int avoidGy_48; +static int avoidGy_49; +static int avoidGy_50; +static int avoidGy_51; +static int avoidGy_52; +static int avoidGy_53; +static int avoidGy_54; +static int avoidGy_55; +static int avoidGy_56; +static int avoidGy_57; +static int avoidGy_58; +static int avoidGy_59; +static int avoidGy_60; +static int avoidGy_PL_01; +__declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { avoidGy_1++; fmt; return 0; } +__declspec(dllexport) int __cdecl PurifyIsRunning(void) { avoidGy_2++; return 0; } +__declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { avoidGy_3++; fmt; return 0; } +__declspec(dllexport) int __cdecl PurifyNewInuse(void) { avoidGy_4++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllInuse(void) { avoidGy_5++; return 0; } +__declspec(dllexport) int __cdecl PurifyClearInuse(void) { avoidGy_6++; return 0; } +__declspec(dllexport) int __cdecl PurifyNewLeaks(void) { avoidGy_7++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllLeaks(void) { avoidGy_8++; return 0; } +__declspec(dllexport) int __cdecl PurifyClearLeaks(void) { avoidGy_9++; return 0; } +__declspec(dllexport) int __cdecl PurifyAllHandlesInuse(void) { avoidGy_10++; return 0; } +__declspec(dllexport) int __cdecl PurifyNewHandlesInuse(void) { avoidGy_11++; return 0; } +__declspec(dllexport) int __cdecl PurifyDescribe(void *addr) { avoidGy_12++; addr; return 0; } +__declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, int size) { avoidGy_13++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, int size) { avoidGy_14++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, int size) { avoidGy_15++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, int size) { avoidGy_16++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, int size) { avoidGy_17++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, int size) { avoidGy_18++; addr; size; return 1; } +__declspec(dllexport) int __cdecl PurifyRed(void *addr, int size) { avoidGy_19++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyGreen(void *addr, int size) { avoidGy_20++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyYellow(void *addr, int size) { avoidGy_21++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyBlue(void *addr, int size) { avoidGy_22++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, int size) { avoidGy_23++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, int size) { avoidGy_24++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, int size) { avoidGy_25++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, int size) { avoidGy_26++; addr; size; return 0; } +__declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) + { avoidGy_27++; hHeap; dwFlags; addr; return 1; } +__declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { avoidGy_28++; counter; return 0; }; +__declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { avoidGy_29++; seconds; return 0; }; +__declspec(dllexport) int __cdecl CoverageIsRunning(void) { avoidGy_30++; return 0; } +__declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { avoidGy_31++; return 0; } +__declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { avoidGy_32++; return 0; } +__declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { avoidGy_33++; return 0; } +__declspec(dllexport) int __cdecl CoverageClearData(void) { avoidGy_34++; return 0; } +__declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { avoidGy_35++; return 0; } +__declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { avoidGy_36++; str; return 0; } +__declspec(dllexport) int __cdecl CoverageSaveData(void) { avoidGy_37++; return 0; } +__declspec(dllexport) int __cdecl QuantifyIsRunning(void) { avoidGy_42++; return 0; } +__declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { avoidGy_43++; return 0; } +__declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { avoidGy_44++; return 0; } +__declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { avoidGy_45++; return 0; } +__declspec(dllexport) int __cdecl QuantifyClearData(void) { avoidGy_46++; return 0; } +__declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { avoidGy_47++; return 0; } +__declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { avoidGy_48++; str; return 0; } +__declspec(dllexport) int __cdecl QuantifySaveData(void) { avoidGy_49++; return 0; } +__declspec(dllexport) int __cdecl PurelockIsRunning(void) { avoidGy_PL_01++; return 0; } diff --git a/src/libs/xpcom18a4/xpcom/build/.cvsignore b/src/libs/xpcom18a4/xpcom/build/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/build/Makefile.in b/src/libs/xpcom18a4/xpcom/build/Makefile.in new file mode 100644 index 00000000..5c2386ce --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/Makefile.in @@ -0,0 +1,165 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpcom + +PACKAGE_FILE = xpcom.pkg +PACKAGE_VARS += USE_SHORT_LIBNAME + +ifdef ENABLE_TESTS +PACKAGE_FILE += xpcom-tests.pkg +endif + +# Do not set EXPORT_LIBRARY as we do not want xpcom in the static libs list +#EXPORT_LIBRARY = 1 +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = nsXPComInit.cpp \ + nsStringAPI.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +CPPSRCS += dlldeps.cpp +endif + +ifdef XPCOM_USE_LEA +CSRCS += malloc.c +endif + +ifeq ($(OS_TARGET),OS2) +CPPSRCS += nsOS2VACLegacy.cpp +endif + +ifdef GC_LEAK_DETECTOR +EXTRA_DSO_LIBS = boehm +endif + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomio_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomcomponents_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomthreads_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomproxy_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcombase_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptcall.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptinfo.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xptcmd.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)string_s.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \ + $(NULL) + +LOCAL_INCLUDES = \ + -I.. \ + -I$(srcdir)/../glue \ + -I$(srcdir)/../base \ + -I$(srcdir)/../ds \ + -I$(srcdir)/../io \ + -I$(srcdir)/../components \ + -I$(srcdir)/../threads \ + -I$(srcdir)/../threads/_xpidlgen \ + -I$(srcdir)/../proxy/src \ + $(NULL) + +SDK_HEADERS = \ + nsXPCOM.h \ + nsXPCOMCID.h \ + $(NULL) + +SDK_LIBRARY = $(IMPORT_LIBRARY) +SDK_BINARY = $(SHARED_LIBRARY) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXTRA_DSO_LIBS = macmorefiles_s +EXTRA_DSO_LDOPTS += $(EXTRA_DSO_LIBS) +EXTRA_DEPS += $(DIST)/lib/$(LIB_PREFIX)macmorefiles_s.$(LIB_SUFFIX) +endif + +# Force use of PIC +FORCE_USE_PIC = 1 + +FORCE_SHARED_LIB = 1 + +# UNIX98 iconv support +OS_LIBS += $(LIBICONV) + +include $(topsrcdir)/config/rules.mk + +DEFINES += \ + -D_IMPL_NS_COM \ + -DEXPORT_XPT_API \ + -DEXPORT_XPTC_API \ + -DEXPORT_XPTI_API + +EXTRA_DSO_LDOPTS += $(NSPR_LIBS) + +ifdef GC_LEAK_DETECTOR +DEFINES += -DGC_LEAK_DETECTOR +endif + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CXXFLAGS += $(TK_CFLAGS) +EXTRA_DSO_LDOPTS += $(TK_LIBS) +endif + +ifeq ($(OS_ARCH),BeOS) +EXTRA_DSO_LDOPTS += -lbe +endif + +ifeq ($(OS_ARCH),WINNT) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,shell32 ole32 uuid) +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME,imagehlp) +endif +endif # WINNT diff --git a/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp b/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp new file mode 100644 index 00000000..5fc31189 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/dlldeps.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Force references to all of the symbols that we want exported from +// the dll that are located in the .lib files we link with + +#include "nsVoidArray.h" +#include "nsValueArray.h" +#include "nsIAtom.h" +//#include "nsIBuffer.h" +#include "nsIByteArrayInputStream.h" +#include "nsFixedSizeAllocator.h" +#include "nsRecyclingAllocator.h" +#include "nsIThread.h" +#include "nsDeque.h" +#include "nsTraceRefcnt.h" +#include "nsTraceRefcntImpl.h" +#include "nsXPIDLString.h" +#include "nsIEnumerator.h" +#include "nsEnumeratorUtils.h" +#include "nsQuickSort.h" +#include "nsString.h" +#include "nsPrintfCString.h" +#include "nsSupportsArray.h" +#include "nsArray.h" +#include "nsArrayEnumerator.h" +#include "nsProxyEventPrivate.h" +#include "nsProxyRelease.h" +#include "xpt_xdr.h" +#include "xptcall.h" +#include "nsILocalFile.h" +#include "nsIGenericFactory.h" +#include "nsIPipe.h" +#include "nsStreamUtils.h" +#include "nsWeakReference.h" +#include "nsTextFormatter.h" +#include "nsIStorageStream.h" +#include "nsLinebreakConverter.h" +#include "nsIBinaryInputStream.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsReadableUtils.h" +#include "nsStaticNameTable.h" +#include "nsProcess.h" +#include "nsStringEnumerator.h" +#include "nsIInputStreamTee.h" +#include "nsCheapSets.h" +#ifdef DEBUG +#include "pure.h" +#endif +#include "nsHashKeys.h" +#include "nsTHashtable.h" +#include "pldhash.h" +#include "nsVariant.h" +#include "nsEscape.h" +#include "nsStreamUtils.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" + +void XXXNeverCalled() +{ + nsTextFormatter::snprintf(nsnull,0,nsnull); + nsTextFormatter::smprintf(nsnull, nsnull); + nsTextFormatter::smprintf_free(nsnull); + nsVoidArray(); + nsSmallVoidArray(); + nsStringHashSet(); + nsCStringHashSet(); + nsInt32HashSet(); + nsVoidHashSet(); + nsCheapStringSet(); + nsCheapInt32Set(); + nsValueArray(0); + nsSupportsArray(); + NS_GetNumberOfAtoms(); + NS_NewPipe2(nsnull, nsnull, PR_FALSE, PR_FALSE, 0, 0, nsnull); + NS_NewInputStreamReadyEvent(nsnull, nsnull, nsnull); + NS_NewOutputStreamReadyEvent(nsnull, nsnull, nsnull); + NS_AsyncCopy(nsnull, nsnull, nsnull, NS_ASYNCCOPY_VIA_READSEGMENTS, 0, nsnull, nsnull); + PL_DHashStubEnumRemove(nsnull, nsnull, nsnull, nsnull); + nsIDHashKey::HashKey(nsnull); + nsFixedSizeAllocator a; + nsRecyclingAllocator recyclingAllocator(2); + a.Init(0, 0, 0, 0, 0); + a.Alloc(0); + a.Free(0, 0); + nsIThread::GetCurrent(nsnull); + nsDeque(nsnull); + nsTraceRefcnt::LogAddCOMPtr(nsnull, nsnull); + nsTraceRefcntImpl::DumpStatistics(); + NS_NewEmptyEnumerator(nsnull); + new nsArrayEnumerator(nsnull); + NS_QuickSort(nsnull, 0, 0, nsnull, nsnull); + nsString(); + nsProxyObject(nsnull, 0, nsnull); + NS_ProxyRelease(nsnull, nsnull, PR_FALSE); + XPT_DoString(nsnull, nsnull, nsnull); + XPT_DoHeader(nsnull, nsnull, nsnull); +#ifdef DEBUG + PurePrintf(0); +#endif + XPTC_InvokeByIndex(nsnull, 0, 0, nsnull); + xptc_dummy(); + xptc_dummy2(); + XPTI_GetInterfaceInfoManager(); + NS_NewGenericFactory(nsnull, nsnull); + NS_NewGenericModule2(nsnull, nsnull); + NS_GetWeakReference(nsnull); + nsCOMPtr dummyFoo(do_GetInterface(nsnull)); + NS_NewByteArrayInputStream(nsnull, nsnull, 0); + NS_NewStorageStream(0,0, nsnull); + nsString foo; + nsPrintfCString bar(""); + nsLinebreakConverter::ConvertStringLineBreaks(foo, + nsLinebreakConverter::eLinebreakAny, nsLinebreakConverter::eLinebreakContent); + NS_NewLocalFile(nsString(), PR_FALSE, nsnull); + NS_NewNativeLocalFile(nsCString(), PR_FALSE, nsnull); + new nsProcess(); + nsStaticCaseInsensitiveNameTable(); + nsAutoString str1; + str1.AssignWithConversion(nsnull, 0); + nsCAutoString str2; + ToNewUnicode(str1); + ToNewUnicode(str2); + ToNewCString(str1); + ToNewCString(str2); + PL_DHashTableFinish(nsnull); + NS_NewInputStreamTee(nsnull, nsnull, nsnull); + NS_NewArray(nsnull); + nsCOMArray dummyArray; + NS_NewArray(nsnull, dummyArray); + NS_NewArrayEnumerator(nsnull, dummyArray); + new nsVariant(); + nsUnescape(nsnull); + nsEscape(nsnull, url_XAlphas); + nsStringArray array; + NS_NewStringEnumerator(nsnull, &array); + NS_NewAdoptingStringEnumerator(nsnull, &array); + nsCStringArray carray; + NS_NewUTF8StringEnumerator(nsnull, &carray); + NS_NewAdoptingUTF8StringEnumerator(nsnull, &carray); + nsVoidableString str3; + nsCStringContainer sc1; + NS_CStringContainerInit(sc1); + NS_CStringContainerFinish(sc1); + NS_CStringGetData(str2, nsnull, nsnull); + NS_CStringSetData(str2, nsnull, 0); + NS_CStringSetDataRange(str2, 0, 0, nsnull, 0); + NS_CStringCopy(str2, str2); + nsStringContainer sc2; + NS_StringContainerInit(sc2); + NS_StringContainerFinish(sc2); + NS_StringGetData(str1, nsnull, nsnull); + NS_StringSetData(str1, nsnull, 0); + NS_StringSetDataRange(str1, 0, 0, nsnull, 0); + NS_StringCopy(str1, str1); + { + nsAdoptingCString foo, bar; + foo = bar; + } + { + nsAdoptingString foo, bar; + foo = bar; + } + NS_UTF16ToCString(str1, NS_CSTRING_ENCODING_ASCII, str2); + NS_CStringToUTF16(str2, NS_CSTRING_ENCODING_ASCII, str1); +} diff --git a/src/libs/xpcom18a4/xpcom/build/malloc.c b/src/libs/xpcom18a4/xpcom/build/malloc.c new file mode 100644 index 00000000..96691829 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/malloc.c @@ -0,0 +1,5126 @@ +#define USE_MALLOC_LOCK +#define DEFAULT_TRIM_THRESHOLD (256 * 1024) + +/* ---------- To make a malloc.h, start cutting here ------------ */ + +/* + **************************************************************** + * THIS IS A PRERELEASE. It has not yet been tested adequately. * + * If you use it, please send back comments, suggestions, * + * performance reports, etc. * + **************************************************************** +*/ + +/* + A version (aka dlmalloc) of malloc/free/realloc written by Doug + Lea and released to the public domain. Use this code without + permission or acknowledgement in any way you wish. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* VERSION 2.7.0pre7 Wed Jan 10 13:33:01 2001 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O), and link it into another program. All + of the compile-time options default to reasonable values for use on + most unix platforms. Compile -DWIN32 for reasonable defaults on windows. + You might later want to step through various compile options. + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator for malloc-intensive programs. + + The main properties of the algorithms are: + * For large (>= 512 bytes) requests, it is a pure best-fit allocator, + with ties normally decided via FIFO (i.e. least recently used). + * For small (<= 64 bytes by default) requests, it is a caching + allocator, that maintains pools of quickly recycled chunks. + * In between, and for combinations of large and small requests, it does + the best it can trying to meet both goals at once. + + Compared to 2.6.X versions, this version is generally faster, + especially for programs that allocate and free many small chunks. + + For a longer but slightly out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + + You may already by default be using a c library containing a malloc + that is somehow based on some version of this malloc (for example in + linux). You might still want to use the one in this file in order to + customize settings or to avoid overheads associated with library + versions. + +* Synopsis of public routines + + (Much fuller descriptions are contained in the program documentation below.) + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(Void_t* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(Void_t* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system (or as near to this as can be figured out from + all the includes/defines below.) + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(Void_t* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(Void_t* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics on stderr. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. + +* Vital statistics: + + Assumed pointer representation: 4 or 8 bytes + (Thanks to Wolfram Gloger for contributing most of the + changes supporting dual 4/8.) + + Assumed size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + You can adjust this by defining INTERNAL_SIZE_T + + Alignment: 2 * sizeof(size_t) + (i.e., 8 byte alignment with 4byte size_t). This suffices for + nearly all current machines and C compilers. However, you can + define MALLOC_ALIGNMENT to be wider than this if necessary. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden word of overhead holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field and 8 (16) bytes for + free list pointers. Thus, the minimum allocatable size is + 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is 2 * + sizeof(size_t) bytes plus the remainder from a system page (the + minimal mmap unit); typically 4096 bytes. + + Maximum allocated size: 4-byte size_t: 2^31 minus about two pages + 8-byte size_t: 2^63 minus about two pages + + It is assumed that (possibly signed) size_t values suffice + to represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. The ISO C standard says that it must be + unsigned, but a few systems are known not to adhere to this. + Additionally, even when size_t is unsigned, sbrk (which is by + default used to obtain memory from system) accepts signed + arguments, and may not be able to handle size_t-wide arguments + with negative sign bit. To be conservative, values that would + appear as negative after accounting for overhead and alignment + are rejected. + + Requests for sizes outside this range will perform an optional + failure action and then return null. (Requests may also + also fail because a system is out of memory.) + + Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined + + When USE_MALLOC_LOCK is defined, wrappers are created to + surround every public call with either a pthread mutex or + a win32 critical section (depending on WIN32). This is not + especially fast, and can be a major bottleneck in programs with + many threads. It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + you would be far better off obtaining ptmalloc, which is + derived from a version of this malloc, and is well-tuned for + concurrent programs. (See http://www.malloc.de) + + Compliance: I believe it is compliant with the 1997 Single Unix Specification + + (See http://www.opennc.org). Probably other standards as well. + +* Limitations + + Here are some features that are NOT currently supported + + * No automated mechanism for fully checking that all accesses + to malloced memory stay within their bounds. However, there + are several add-ons and adaptations of this or other mallocs + available that do this. + * No support for compaction. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People also report using it in stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. It is not + at all modular. (Sorry!) It uses a lot of macros. To be at all + usable, this code should be compiled using an optimizing compiler + (for example gcc -O3) that can simplify expressions and control + paths. (FAQ: some macros import variables as arguments rather than + declare locals because people reported that some debuggers + otherwise get confused.) + + OPTION DEFAULT VALUE + + Compilation Environment options: + + __STD_C derived from C compiler defines + WIN32 NOT defined + HAVE_MEMCPY defined + USE_MEMCPY 1 if HAVE_MEMCPY is defined + HAVE_MMAP defined as 1 + MMAP_AS_MORECORE_SIZE (1024 * 1024) + HAVE_MREMAP defined as 0 unless linux defined + malloc_getpagesize derived from system #includes, or 4096 if not + HAVE_USR_INCLUDE_MALLOC_H NOT defined + LACKS_UNISTD_H NOT defined unless WIN32 + LACKS_SYS_PARAM_H NOT defined unless WIN32 + LACKS_SYS_MMAN_H NOT defined unless WIN32 + + Changing default word sizes: + + INTERNAL_SIZE_T size_t + MALLOC_ALIGNMENT 2 * sizeof(INTERNAL_SIZE_T) + + Configuration and functionality options: + + USE_DL_PREFIX NOT defined + USE_PUBLIC_MALLOC_WRAPPERS NOT defined + USE_MALLOC_LOCK NOT defined + DEBUG NOT defined + REALLOC_ZERO_BYTES_FREES NOT defined + MALLOC_FAILURE_ACTION errno = ENOMEM, if __STD_C defined, else no-op + TRIM_FASTBINS 0 + + Options for customizing MORECORE: + + MORECORE sbrk + MORECORE_CONTIGUOUS 1 + + Tuning options that are also dynamically changeable via mallopt: + + DEFAULT_MXFAST 64 + DEFAULT_TRIM_THRESHOLD 128 * 1024 + DEFAULT_TOP_PAD 0 + DEFAULT_MMAP_THRESHOLD 128 * 1024 + DEFAULT_MMAP_MAX 256 + + There are several other #defined constants and macros that you + probably don't want to touch unless you are extending or adapting malloc. + +*/ +#include "xpcom-private.h" + + + +/* + WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. +*/ + +/* #define WIN32 */ + +#ifdef WIN32 + +#include + +/* Win32 doesn't supply or need the following headers */ +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H + +/* Use the supplied emulation of sbrk */ +#define MORECORE sbrk +#define MORECORE_CONTIGUOUS 1 +#define MORECORE_FAILURE ((void*)(-1)) + +/* Use the supplied emulation mmap, munmap */ +#define HAVE_MMAP 1 +#define MUNMAP_FAILURE (-1) +/* These values don't really matter in windows mmap emulation */ +#define MAP_PRIVATE 1 +#define MAP_ANONYMOUS 2 +#define PROT_READ 1 +#define PROT_WRITE 2 + +/* Emulation functions defined at the end of this file */ + +/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */ +#ifdef USE_MALLOC_LOCK +static int slwait(int *sl); +static int slrelease(int *sl); +#endif + +static long getpagesize(void); +static long getregionsize(void); +static void *sbrk(long size); +static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg); +static long munmap(void *ptr, long size); + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed); +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user); + +#endif + + + +/* + __STD_C should be nonzero if using ANSI-standard C compiler, a C++ + compiler, or a C compiler sufficiently close to ANSI to get away + with it. +*/ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C 1 +#else +#if __cplusplus +#define __STD_C 1 +#else +#define __STD_C 0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + + +/* + Void_t* is the pointer type that malloc should say it returns +*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include /* for size_t */ +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* define LACKS_UNISTD_H if your system does not have a . */ + +/* #define LACKS_UNISTD_H */ + +#ifndef LACKS_UNISTD_H +#include +#endif + +/* define LACKS_SYS_PARAM_H if your system does not have a . */ + +/* #define LACKS_SYS_PARAM_H */ + + +#include /* needed for malloc_stats */ +#include /* needed for optional MALLOC_FAILURE_ACTION */ + + +/* + Debugging: + + Because freed chunks may be overwritten with bookkeeping fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + +*/ + +#if DEBUG +#include +#else +#define assert(x) ((void)0) +#endif + + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. + + The default version is the same as size_t. + + While not strictly necessary, it is best to define this as an + unsigned type, even if size_t is a signed type. This may avoid some + artificial size limitations on some systems. + + On a 64-bit machine, you may be able to reduce malloc overhead by + defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the + expense of not being able to handle more than 2^32 of malloced + space. If this limitation is acceptable, you are encouraged to set + this unless you are on a platform requiring 16byte alignments. In + this case the alignment requirements turn out to negate any + potential advantages of decreasing size_t word size. + + Note to implementors: To deal with all this, comparisons and + difference computations among INTERNAL_SIZE_Ts should normally cast + INTERNAL_SIZE_T's to long or unsigned long, as appropriate, being + aware of the fact that casting an unsigned int to a wider long does not + sign-extend. (This also makes checking for negative numbers awkward.) + +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* The corresponding word size */ +#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) + + +/* + MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks. + It must be a power of two at least 2 * SIZE_SZ, even on machines + for which smaller alignments would suffice. It may be defined as + larger than this though. (Note however that code and data structures + are optimized for the case of 8-byte alignment.) + +*/ + + /* #define MALLOC_ALIGNMENT 16 */ + +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT (2 * SIZE_SZ) +#endif + +/* The corresponding bit mask value */ +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) + + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + +/* #define REALLOC_ZERO_BYTES_FREES */ + + +/* + USE_DL_PREFIX will prefix all public routines with the string 'dl'. + This is necessary when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. +*/ + +/* #define USE_DL_PREFIX */ + + +/* + USE_MALLOC_LOCK causes wrapper functions to surround each + callable routine with pthread mutex lock/unlock. + + USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined +*/ + +/* #define USE_MALLOC_LOCK */ + + +/* + If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is + actually a wrapper function that first calls MALLOC_PREACTION, then + calls the internal routine, and follows it with + MALLOC_POSTACTION. This is needed for locking, but you can also use + this, without USE_MALLOC_LOCK, for purposes of interception, + instrumentation, etc. It is a sad fact that using wrappers often + noticeably degrades performance of malloc-intensive programs. +*/ + +#ifdef USE_MALLOC_LOCK +#define USE_PUBLIC_MALLOC_WRAPPERS +#else +/* #define USE_PUBLIC_MALLOC_WRAPPERS */ +#endif + + + + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined below. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are faster than libc versions on some systems. + + Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks + (of <= 36 bytes) are manually unrolled in realloc and calloc. +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#ifdef WIN32 + /* + On Win32 platforms, 'memset()' and 'memcpy()' are already declared in + 'windows.h' + */ +#else +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +void* memmove(void*, const void*, size_t); +#else +Void_t* memset(); +Void_t* memcpy(); +Void_t* memmove(); +#endif +#endif +#endif + + +/* + MALLOC_FAILURE_ACTION is the action to take before "return 0" when + malloc fails to be able to return memory, either because memory is + exhausted or because of illegal arguments. + + By default, sets errno if running on STD_C platform, else does nothing. +*/ + +#ifndef MALLOC_FAILURE_ACTION +#if __STD_C +#define MALLOC_FAILURE_ACTION \ + errno = ENOMEM; + +#else + +#define MALLOC_FAILURE_ACTION +#endif +#endif + +/* + Define HAVE_MMAP as true to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). Also, if mmap + is available, it is used as a backup strategy in cases where + MORECORE fails to provide space from system. + + This malloc is best tuned to work with mmap for large requests. + If you do not have mmap, allocation of very large chunks (1MB + or so) may be slower than you'd like. +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif + +/* + MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if + sbrk fails, and mmap is used as a backup (which is done only if + HAVE_MMAP). The value must be a multiple of page size. This + backup strategy generally applies only when systems have "holes" in + address space, so sbrk cannot perform contiguous expansion, but + there is still space available on system. On systems for which + this is known to be useful (i.e. most linux kernels), this occurs + only when programs allocate huge amounts of memory. Between this, + and the fact that mmap regions tend to be limited, the size should + be large, to avoid too many mmap calls and thus avoid running out + of kernel resources. +*/ + +#ifndef MMAP_AS_MORECORE_SIZE +#define MMAP_AS_MORECORE_SIZE (1024 * 1024) +#endif + + + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif + +#endif /* HAVE_MMAP */ + + +/* + + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any SVID/XPG compliant system that has + a /usr/include/malloc.h defining struct mallinfo. (If you'd like to + install such a thing yourself, cut out the preliminary declarations + as described above and below and save them in a malloc.h file. But + there's no compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of field that are not even meaningful in this version of + malloc. These fields are are instead filled by mallinfo() with + other numbers that might be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* non-mmapped space allocated from system */ + int ordblks; /* number of free chunks */ + int smblks; /* number of fastbin blocks */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* space in mmapped regions */ + int usmblks; /* maximum total allocated space */ + int fsmblks; /* space available in freed fastbin blocks */ + int uordblks; /* total allocated space */ + int fordblks; /* total free space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST 1 /* Set maximum fastbin size */ +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#define M_GRAIN 3 /* UNUSED in this malloc */ +#define M_KEEP 4 /* UNUSED in this malloc */ + + +#endif + + +/* Additional mallopt options supported in this malloc */ + +#ifndef M_TRIM_THRESHOLD +#define M_TRIM_THRESHOLD -1 +#endif + +#ifndef M_TOP_PAD +#define M_TOP_PAD -2 +#endif + +#ifndef M_MMAP_THRESHOLD +#define M_MMAP_THRESHOLD -3 +#endif + +#ifndef M_MMAP_MAX +#define M_MMAP_MAX -4 +#endif + + +/* + MXFAST is the maximum request size used for "fastbins", special bins + that hold returned chunks without consolidating their spaces. This + enables future requests for chunks of the same size to be handled + very quickly, but can increase fragmentation, and thus increase the + overall memory footprint of a program. + + This malloc manages fastbins very conservatively yet still + efficiently, so fragmentation is rarely a problem for values less + than or equal to the default. The maximum supported value of MXFAST + is 80. You wouldn't want it any higher than this anyway. Fastbins + are designed especially for use with many small structs, objects or + strings -- the default handles structs/objects/arrays with sizes up + to 8 4byte fields, or small strings representing words, tokens, + etc. Using fastbins for larger objects normally worsens + fragmentation without improving speed. + + MXFAST is set in REQUEST size units. It is internally used in + chunksize units, which adds padding and alignment. You can reduce + MXFAST to 0 to disable all use of fastbins. This causes the malloc + algorithm to be a close approximation of fifo-best-fit in all cases, + not just for larger requests, but will generally cause it to be + slower. + +*/ + +#ifndef DEFAULT_MXFAST +#define DEFAULT_MXFAST 64 +#endif + + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The default trim value is high enough to cause trimming only in + fairly extreme (by current memory consumption standards) cases. + It must be greater than page size to have any useful effect. To + disable trimming completely, you can set to (unsigned long)(-1); + + Trim settings interact with fastbin (MXFAST) settings: Unless + TRIM_FASTBINS is defined, automatic trimming never takes place upon + freeing a chunk with size less than or equal to MXFAST. Trimming is + instead delayed until subsequent freeing of larger chunks. However, + you can still force an attempted trim by calling malloc_trim. + + Also, trimming is not generally possible in cases where + the main arena is obtained via mmap. + +*/ + + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + + + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. + +*/ + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefit that mmapped space + can ALWAYS be individually released back to the system, which + helps keep the system level memory demands of a long-lived + program low. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + means that even trimming via malloc_trim would not release them. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + All together, these considerations should lead you to use mmap + only for relatively large requests. + +*/ + + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because: + + 1. Some systems have a limited number of internal tables for + use by mmap. + 2. In most systems, overreliance on mmap can degrade overall + performance. + 3. If a program allocates many large regions, it is probably + better off using normal sbrk-based allocation routines that + can reclaim and reallocate normal heap memory. + + Setting to 0 disables use of mmap for servicing large requests. If + HAVE_MMAP is not set, the default value is 0, and attempts to set it + to non-zero values in mallopt will fail. +*/ + + + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX (256) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + + +/* + TRIM_FASTBINS controls whether free() of a very small chunk can + immediately lead to trimming. Setting to true (1) can reduce memory + footprint, but will almost always slow down (by a few percent) + programs that use a lot of small chunks. + + Define this only if you are willing to give up some speed to more + aggressively reduce system-level memory footprint when releasing + memory in programs that use many small chunks. You can get + essentially the same effect by setting MXFAST to 0, but this can + lead to even greater slowdowns in programs using many small chunks. + TRIM_FASTBINS is an in-between compile-time option, that disables + only those chunks bordering topmost memory from being placed in + fastbins. + +*/ + + +#ifndef TRIM_FASTBINS +#define TRIM_FASTBINS 0 +#endif + + +/* + MORECORE-related declarations. By default, rely on sbrk +*/ + + +#ifdef LACKS_UNISTD_H +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#if __STD_C +extern Void_t* sbrk(ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif +#endif +#endif + +/* + MORECORE is the name of the routine to call to obtain more memory + from the system. See below for general guidance on writing + alternative MORECORE functions, as well as a version for WIN32 and a + sample version for pre-OSX macos. +*/ + +#ifndef MORECORE +#define MORECORE sbrk +#endif + + +/* + MORECORE_FAILURE is the value returned upon failure of MORECORE + as well as mmap. Since it cannot be an otherwise valid memory address, + and must reflect values of standard sys calls, you probably ought not + try to redefine it. +*/ + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE (-1) +#endif + +/* + If MORECORE_CONTIGUOUS is true, take advantage of fact that + consecutive calls to MORECORE with positive arguments always return + contiguous increasing addresses. This is true of unix sbrk. Even + if not defined, when regions happen to be contiguous, malloc will + permit allocations spanning regions obtained from different + calls. But defining this when applicable enables some stronger + consistency checks and space efficiencies. +*/ + + +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif + + +/* + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. Note that this value is + cached during initialization into a field of malloc_state. So even + if malloc_getpagesize is a function, it is only called once. + + The following mechanics for getpagesize were adapted from bsd/gnu + getpagesize.h. If none of the system-probes here apply, a value of + 4096 is used, which should be OK: If they don't apply, then using + the actual value probably doesn't impact performance. +*/ + +#ifndef malloc_getpagesize + +#ifndef LACKS_UNISTD_H +# include +#endif + +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif + +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize (4096) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + + +/* Two-phase Name mangling */ + +#ifndef USE_PUBLIC_MALLOC_WRAPPERS +#define cALLOc public_cALLOc +#define fREe public_fREe +#define cFREe public_cFREe +#define mALLOc public_mALLOc +#define mEMALIGn public_mEMALIGn +#define rEALLOc public_rEALLOc +#define vALLOc public_vALLOc +#define pVALLOc public_pVALLOc +#define mALLINFo public_mALLINFo +#define mALLOPt public_mALLOPt +#define mTRIm public_mTRIm +#define mSTATs public_mSTATs +#define mUSABLe public_mUSABLe +#endif + +#ifdef USE_DL_PREFIX +#define public_cALLOc dlcalloc +#define public_fREe dlfree +#define public_cFREe dlcfree +#define public_mALLOc dlmalloc +#define public_mEMALIGn dlmemalign +#define public_rEALLOc dlrealloc +#define public_vALLOc dlvalloc +#define public_pVALLOc dlpvalloc +#define public_mALLINFo dlmallinfo +#define public_mALLOPt dlmallopt +#define public_mTRIm dlmalloc_trim +#define public_mSTATs dlmalloc_stats +#define public_mUSABLe dlmalloc_usable_size +#else /* USE_DL_PREFIX */ +#define public_cALLOc calloc +#define public_fREe free +#define public_cFREe cfree +#define public_mALLOc malloc +#define public_mEMALIGn memalign +#define public_rEALLOc realloc +#define public_vALLOc valloc +#define public_pVALLOc pvalloc +#define public_mALLINFo mallinfo +#define public_mALLOPt mallopt +#define public_mTRIm malloc_trim +#define public_mSTATs malloc_stats +#define public_mUSABLe malloc_usable_size +#endif /* USE_DL_PREFIX */ + +#if __STD_C + +Void_t* public_mALLOc(size_t); +void public_fREe(Void_t*); +Void_t* public_rEALLOc(Void_t*, size_t); +Void_t* public_mEMALIGn(size_t, size_t); +Void_t* public_vALLOc(size_t); +Void_t* public_pVALLOc(size_t); +Void_t* public_cALLOc(size_t, size_t); +void public_cFREe(Void_t*); +int public_mTRIm(size_t); +size_t public_mUSABLe(Void_t*); +void public_mSTATs(); +int public_mALLOPt(int, int); +struct mallinfo public_mALLINFo(void); +#else +Void_t* public_mALLOc(); +void public_fREe(); +Void_t* public_rEALLOc(); +Void_t* public_mEMALIGn(); +Void_t* public_vALLOc(); +Void_t* public_pVALLOc(); +Void_t* public_cALLOc(); +void public_cFREe(); +int public_mTRIm(); +size_t public_mUSABLe(); +void public_mSTATs(); +int public_mALLOPt(); +struct mallinfo public_mALLINFo(); +#endif + + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + + + +/* ---------- To make a malloc.h, end cutting here ------------ */ + + +/* Declarations of internal utilities defined below */ + + + + +#ifdef USE_PUBLIC_MALLOC_WRAPPERS +#if __STD_C + +static Void_t* mALLOc(size_t); +static void fREe(Void_t*); +static Void_t* rEALLOc(Void_t*, size_t); +static Void_t* mEMALIGn(size_t, size_t); +static Void_t* vALLOc(size_t); +static Void_t* pVALLOc(size_t); +static Void_t* cALLOc(size_t, size_t); +static void cFREe(Void_t*); +static int mTRIm(size_t); +static size_t mUSABLe(Void_t*); +static void mSTATs(); +static int mALLOPt(int, int); +static struct mallinfo mALLINFo(void); +#else +static Void_t* mALLOc(); +static void fREe(); +static Void_t* rEALLOc(); +static Void_t* mEMALIGn(); +static Void_t* vALLOc(); +static Void_t* pVALLOc(); +static Void_t* cALLOc(); +static void cFREe(); +static int mTRIm(); +static size_t mUSABLe(); +static void mSTATs(); +static int mALLOPt(); +static struct mallinfo mALLINFo(); +#endif +#endif + + + +/* ---------- public wrappers --------------- */ + +#ifdef USE_PUBLIC_MALLOC_WRAPPERS + +/* + MALLOC_PREACTION and MALLOC_POSTACTION should be + defined to return 0 on success, and nonzero on failure. + The return value of MALLOC_POSTACTION is currently ignored + in wrapper functions since there is no reasonable default + action to take on failure. +*/ + + +#ifdef USE_MALLOC_LOCK + +#ifdef WIN32 + +static int mALLOC_MUTEx; + +#define MALLOC_PREACTION slwait(&mALLOC_MUTEx) +#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx) + +#else + +#include + +static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER; + +#define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx) +#define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx) + +#endif /* USE_MALLOC_LOCK */ + +#else + +/* Substitute anything you like for these */ + +#define MALLOC_PREACTION (0) +#define MALLOC_POSTACTION (0) + +#endif + +Void_t* public_mALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_fREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + fREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +Void_t* public_rEALLOc(Void_t* m, size_t bytes) { + if (MALLOC_PREACTION != 0) { + return 0; + } + m = rEALLOc(m, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_mEMALIGn(size_t alignment, size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mEMALIGn(alignment, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_vALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = vALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_pVALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = pVALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_cALLOc(size_t n, size_t elem_size) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = cALLOc(n, elem_size); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_cFREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + cFREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +int public_mTRIm(size_t s) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mTRIm(s); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + + +size_t public_mUSABLe(Void_t* m) { + size_t result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mUSABLe(m); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + + +void public_mSTATs() { + if (MALLOC_PREACTION != 0) { + return; + } + mSTATs(); + if (MALLOC_POSTACTION != 0) { + } +} + +struct mallinfo public_mALLINFo() { + struct mallinfo m; + if (MALLOC_PREACTION != 0) { + return m; + } + m = mALLINFo(); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +int public_mALLOPt(int p, int v) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mALLOPt(p, v); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + +#endif + + + +/* ------------- Optional versions of memcopy ---------------- */ + + +#if USE_MEMCPY + +#define MALLOC_COPY(dest, src, nbytes, overlap) \ + ((overlap) ? memmove(dest, src, nbytes) : memcpy(dest, src, nbytes)) +#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +/* For overlapping case, dest is always _below_ src. */ + +#define MALLOC_COPY(dest,src,nbytes,overlap) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + +/* ------------------ MMAP support ------------------ */ + + +#if HAVE_MMAP + +#include +#ifndef LACKS_SYS_MMAN_H +#include +#endif + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + + +/* + Nearly all versions of mmap support MAP_ANONYMOUS, + so the following is unlikely to be needed, but is + supplied just in case. +*/ + +#ifndef MAP_ANONYMOUS + +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ + +#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) + +#else + +#define MMAP(addr, size, prot, flags) \ + (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0)) + +#endif + +#endif /* HAVE_MMAP */ + + +/* ---------- Alternative MORECORE functions ------------ */ + + +/* + General Requirements for MORECORE. + + The MORECORE function must have the following properties: + + If MORECORE_CONTIGUOUS is false: + + * MORECORE must allocate in multiples of pagesize. It will + only be called with arguments that are multiples of pagesize. + + * MORECORE must page-align. That is, MORECORE(0) must + return an address at a page boundary. + + else (i.e. If MORECORE_CONTIGUOUS is true): + + * Consecutive calls to MORECORE with positive arguments + return increasing addresses, indicating that space has been + contiguously extended. + + * MORECORE need not allocate in multiples of pagesize. + Calls to MORECORE need not have args of multiples of pagesize. + + * MORECORE need not page-align. + + In either case: + + * MORECORE may allocate more memory than requested. (Or even less, + but this will generally result in a malloc failure.) + + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. This malloc does NOT call MORECORE(0) + until at least one call with positive arguments is made, so + the initial value returned is not important. + + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + + * MORECORE need not handle negative arguments -- it may instead + just return MORECORE_FAILURE when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. + + There is some variation across systems about the type of the + argument to sbrk/MORECORE. If size_t is unsigned, then it cannot + actually be size_t, because sbrk supports negative args, so it is + normally the signed type of the same width as size_t (sometimes + declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much + matter though. Internally, we use "long" as arguments, which should + work across all reasonable possibilities. + + Additionally, if MORECORE ever returns failure for a positive + request, and HAVE_MMAP is true, then mmap is used as a noncontiguous + system allocator. This is a useful backup strategy for systems with + holes in address spaces -- in this case sbrk cannot contiguously + expand the heap, but mmap may be able to map noncontiguous space. + If you'd like mmap to ALWAYS be used, you can define MORECORE to be + a function that always returns MORECORE_FAILURE. + + If you are using this malloc with something other than unix sbrk to + supply memory regions, you probably want to set MORECORE_CONTIGUOUS + as false. As an example, here is a custom allocator kindly + contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + #define MORECORE_CONTIGUOUS 0 + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MORECORE_FAILURE; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MORECORE_FAILURE; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + + + + +/* + ----------------------- Chunk representations ----------------------- +*/ + + +/* + This struct declaration is misleading (but accurate and necessary). + It declares a "view" into memory allowing access to necessary + fields at known offsets from a given base. See explanation below. +*/ + +struct malloc_chunk { + + INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + + +typedef struct malloc_chunk* mchunkptr; + +/* + + malloc_chunk details: + + (The following includes lightly edited explanations by Colin Plumb.) + + Chunks of memory are maintained using a `boundary tag' method as + described in e.g., Knuth or Standish. (See the paper by Paul + Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a + survey of such techniques.) Sizes of free chunks are stored both + in the front of each chunk and at the end. This makes + consolidating fragmented chunks into bigger chunks very fast. The + size fields also hold bits representing whether chunks are free or + in use. + + An allocated chunk looks like this: + + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk, if allocated | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | User data starts here... . + . . + . (malloc_usable_space() bytes) . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Where "chunk" is the front of the chunk for the purpose of most of + the malloc code, but "mem" is the pointer that is returned to the + user. "Nextchunk" is the beginning of the next contiguous chunk. + + Chunks always begin on even word boundries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus double-word aligned. + + Free chunks are stored in circular doubly-linked lists, and look like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The P (PREV_INUSE) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, + preventing access to non-existent (or non-owned) memory. If + prev_inuse is set for any given chunk, then you CANNOT determine + the size of the previous chunk, and might even get a memory + addressing fault when trying to do so. + + Note that the `foot' of the current chunk is actually represented + as the prev_size of the NEXT chunk. (This makes it easier to + deal with alignments etc). + + The two exceptions to all this are + + 1. The special chunk `top' doesn't bother using the + trailing size field since there is no next contiguous chunk + that would have to index off it. After initialization, `top' + is forced to always exist. If it would become less than + MINSIZE bytes long, it is replenished. + + 2. Chunks allocated via mmap, which have the second-lowest-order + bit (IS_MMAPPED) set in their size fields. Because they are + allocated one-by-one, each must contain its own trailing size field. + +*/ + + + +/* + Size and alignment checks and conversions +*/ + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* The smallest possible chunk */ +#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk)) + +/* The smallest size we can malloc is an aligned minimal chunk */ + +#define MINSIZE ((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + +/* + Check for negative/huge sizes. + This cannot just test for < 0 because argument might + be an unsigned type of uncertain width. +*/ + +#define IS_NEGATIVE(x) \ + ((unsigned long)x >= \ + (unsigned long)((((INTERNAL_SIZE_T)(1)) << ((SIZE_SZ)*8 - 1)))) + + +/* pad request bytes into a usable size -- internal version */ + +#define request2size(req) \ + (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ + MINSIZE : \ + ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + + +/* + Same, except check for negative/huge arguments. + This lets through args that are positive but wrap into + negatives when padded. However, these are trapped + elsewhere. +*/ + +#define checked_request2size(req, sz) \ + if (IS_NEGATIVE(req)) { \ + MALLOC_FAILURE_ACTION; \ + return 0; \ + } \ + (sz) = request2size(req); + + + + +/* + Physical chunk operations +*/ + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ + +#define PREV_INUSE 0x1 + + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ + +#define IS_MMAPPED 0x2 + + +/* Bits to mask off when extracting size */ + +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + + +/* Ptr to next physical malloc_chunk. */ + +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + + +/* Ptr to previous physical malloc_chunk */ + +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + + +/* Treat space at ptr + offset as a chunk */ + +#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) + + + + +/* + Dealing with use bits + + Note: IS_MMAPPED is intentionally not masked off from size field in + macros for which mmapped chunks should never be seen. This should + cause helpful core dumps to occur if it is tried by accident by + people extending or adapting this malloc. + +*/ + + +/* extract p's inuse bit */ + +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + + +/* extract inuse bit of previous chunk */ + +#define prev_inuse(p) ((p)->size & PREV_INUSE) + + +/* check for mmap()'ed chunk */ + +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + + +/* set/clear chunk as being inuse without otherwise disturbing */ + +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + + +/* check/set/clear inuse bits in known places */ + +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + + + + +/* + Dealing with size fields +*/ + +/* Get size, ignoring use bits */ + +#define chunksize(p) ((p)->size & ~(SIZE_BITS)) + +/* Set size at head, without disturbing its use bit */ + +#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use field */ + +#define set_head(p, s) ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ + +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + + + + + +/* + ------------------ Internal data structures -------------------- + + All internal state is held in an instance of malloc_state defined + below. There are no other static variables, except in two optional + cases: + * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared + above. + * If HAVE_MMAP is true, but mmap doesn't support + MAP_ANONYMOUS, a dummy file descriptor for mmap. + + Beware of lots of tricks that minimize the total space + requirements. The result is a little over 1K bytes (for 4byte + pointers and size_t.) + +*/ + +/* + + Bins + + An array of bin headers for free chunks. Each bin is doubly + linked. The bins are approximately proportionally (log) spaced. + There are a lot of these bins (128). This may look excessive, but + works very well in practice. Most bins hold sizes that are + unusual as malloc request sizes, but are more usual for fragments + and consolidated sets of chunks, which is what these bins hold, so + they can be found quickly. All procedures maintain the invariant + that no consolidated chunk physically borders another one, so each + chunk in a list is known to be preceeded and followed by either + inuse chunks or the ends of memory. + + Chunks in bins are kept in size order, with ties going to the + approximately least recently used chunk. Ordering is irrelevant + for the small bins, which all contain the same-sized chunks, but + facilitates best-fit allocation for larger chunks. (These lists + are just sequential. Keeping them in order almost never requires + enough traversal to warrant using fancier ordered data + structures.) Chunks of the same size are linked with the most + recently freed at the front, and allocations are taken from the + back. This results in LRU (FIFO) allocation order, which tends + to give each chunk an equal opportunity to be consolidated with + adjacent freed chunks, resulting in larger free chunks and less + fragmentation. + + To simplify use in double-linked lists, each bin header acts + as a malloc_chunk. This avoids special-casing for headers. + But to conserve space and (mainly) improve locality, we allocate + only the fd/bk pointers of bins, and then use repositioning tricks + to treat these as the fields of a malloc_chunk*. +*/ + +typedef struct malloc_chunk* mbinptr; + +#define NBINS 128 + + +/* addressing -- note that bin_at(0) does not exist */ + +#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1))) + + +/* analog of ++bin */ + +#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1))) + + +/* Reminders about list directionality within bins */ + +#define first(b) ((b)->fd) +#define last(b) ((b)->bk) + +/* + Take a chunk off a bin list +*/ + +#define unlink(P, BK, FD) { \ + FD = P->fd; \ + BK = P->bk; \ + FD->bk = BK; \ + BK->fd = FD; \ +} + +/* + Indexing bins + + Bins for sizes < 512 bytes contain chunks of all the same size, spaced + 8 bytes apart. Larger bins are approximately logarithmically spaced: + + 64 bins of size 8 + 32 bins of size 64 + 16 bins of size 512 + 8 bins of size 4096 + 4 bins of size 32768 + 2 bins of size 262144 + 1 bin of size what's left + + There is actually a little bit of slop in the numbers in bin_index + for the sake of speed. This makes no difference elsewhere. + + The bins top out at around 1mb because we expect to service large + chunks via mmap. + +*/ + +/* The first NSMALLBIN bins (and fastbins) hold only one size */ +#define NSMALLBINS 64 +#define SMALLBIN_WIDTH 8 +#define MIN_LARGE_SIZE 512 + +#define in_smallbin_range(sz) ((sz) < MIN_LARGE_SIZE) + +#define smallbin_index(sz) (((unsigned)(sz)) >> 3) + +#define largebin_index(sz) \ +(((((unsigned long)(sz)) >> 6) <= 32)? 56 + (((unsigned long)(sz)) >> 6): \ + ((((unsigned long)(sz)) >> 9) <= 20)? 91 + (((unsigned long)(sz)) >> 9): \ + ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 15) <= 4)? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 18) <= 2)? 124 + (((unsigned long)(sz)) >> 18): \ + 126) + +#define bin_index(sz) \ + ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz)) + + +/* + Unsorted chunks + + All remainders from chunk splits, as well as all returned chunks, + are first placed in the "unsorted" bin. They are then placed + in regular bins after malloc gives them ONE chance to be used before + binning. So, basically, the unsorted_chunks list acts as a queue, + with chunks being placed on it in free (and malloc_consolidate), + and taken off (to be either used or placed in bins) in malloc. + +*/ + + +/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ + +#define unsorted_chunks(M) (bin_at(M, 1)) + + +/* + Top + + The top-most available chunk (i.e., the one bordering the end of + available memory) is treated specially. It is never included in + any bin, is used only if no other chunk is available, and is + released back to the system if it is very large (see + M_TRIM_THRESHOLD). `top' is never properly linked to its bin + since it is always handled specially. Because top initially + points to its own bin with initial zero size, thus forcing + extension on the first malloc request, we avoid having any special + code in malloc to check whether it even exists yet. But we still + need to do so when getting memory from system, so we make + initial_top treat the bin as a legal but unusable chunk during the + interval between initialization and the first call to + sYSMALLOc. (This is somewhat delicate, since it relies on + the 2 preceding words to be zero during this interval as well.) +*/ + + +/* Conveniently, the unsorted bin can be used as dummy top on first call */ +#define initial_top(M) (unsorted_chunks(M)) + +/* + Binmap + + To help compensate for the large number of bins, a one-level index + structure is used for bin-by-bin searching. `binmap' is a + bitvector recording whether bins are definitely empty so they can + be skipped over during during traversals. The bits are NOT always + cleared as soon as bins are empty, but instead only + when they are noticed to be empty during traversal in malloc. + +*/ + +/* Conservatively use 32 bits per map word, even if on 64bit system */ +#define BINMAPSHIFT 5 +#define BITSPERMAP (1U << BINMAPSHIFT) +#define BINMAPSIZE (NBINS / BITSPERMAP) + +#define idx2block(i) ((i) >> BINMAPSHIFT) +#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1)))) + +#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i)) +#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i))) +#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i)) + + +/* + Fastbins + + An array of lists holding recently freed small chunks. Fastbins + are not doubly linked. It is faster to single-link them, and + since chunks are never removed from the middles of these lists, + double linking is not necessary. + + Chunks in fastbins keep their inuse bit set, so they cannot + be consolidated with other free chunks. malloc_consolidate + releases all chunks in fastbins and consolidates them with + other free chunks. +*/ + +typedef struct malloc_chunk* mfastbinptr; + +/* offset 2 to use otherwise unindexable first 2 bins */ +#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2) + +/* The maximum fastbin request size we support */ +#define MAX_FAST_SIZE 80 + +#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1) + + + +/* + Flag bit held in max_fast indicating that there probably are some + fastbin chunks . It is set true on entering a chunk into any fastbin, + and cleared only in malloc_consolidate. + + The truth value is inverted so that have_fastchunks will be true + upon startup (since statics are zero-filled). +*/ + + +#define have_fastchunks(M) (((M)->max_fast & 1U) == 0) +#define clear_fastchunks(M) ((M)->max_fast |= 1U) +#define set_fastchunks(M) ((M)->max_fast &= ~1U) + +/* + Initialization value of max_fast. + Use impossibly small value if 0. + Value also has flag bit clear. +*/ +#define req2max_fast(s) (((((s) == 0)? SMALLBIN_WIDTH: request2size(s))) | 1U) + + +/* + NONCONTIGUOUS_REGIONS is a special value for sbrk_base indicating that + MORECORE does not return contiguous regions. In this case, we do not check + or assume that the address of each chunk is at least sbrk_base. Otherwise, + contiguity is exploited in merging together, when possible, results + from consecutive MORECORE calls. + + The possible values for sbrk_base are: + MORECORE_FAILURE: + MORECORE has not yet been called, but we expect contiguous space + NONCONTIGUOUS_REGIONS: + we don't expect or rely on contiguous space + any other legal address: + the first address returned by MORECORE when contiguous +*/ + +#define NONCONTIGUOUS_REGIONS ((char*)(-3)) + + +/* + ----------- Internal state representation and initialization ----------- +*/ + + +struct malloc_state { + + /* The maximum chunk size to be eligible for fastbin */ + INTERNAL_SIZE_T max_fast; /* low bit used as fastbin flag */ + + /* Base of the topmost chunk -- not otherwise kept in a bin */ + mchunkptr top; + + /* The remainder from the most recent split of a small request */ + mchunkptr last_remainder; + + /* Fastbins */ + mfastbinptr fastbins[NFASTBINS]; + + /* Normal bins packed as described above */ + mchunkptr bins[NBINS * 2]; + + /* Bitmap of bins */ + unsigned int binmap[BINMAPSIZE]; + + /* Tunable parameters */ + unsigned long trim_threshold; + INTERNAL_SIZE_T top_pad; + INTERNAL_SIZE_T mmap_threshold; + + /* Memory map support */ + int n_mmaps; + int n_mmaps_max; + int max_n_mmaps; + + /* Bookkeeping for sbrk */ + unsigned int pagesize; /* Cache malloc_getpagesize */ + char* sbrk_base; /* first address returned by sbrk, + or NONCONTIGUOUS_REGIONS */ + /* Statistics */ + + INTERNAL_SIZE_T mmapped_mem; + INTERNAL_SIZE_T sbrked_mem; + + INTERNAL_SIZE_T max_sbrked_mem; + INTERNAL_SIZE_T max_mmapped_mem; + INTERNAL_SIZE_T max_total_mem; +}; + +typedef struct malloc_state *mstate; + +/* + There is exactly one instance of this struct in this malloc. + + If you are adapting this malloc in a way that does NOT use a static + malloc_state, you MUST explicitly zero-fill it before using. This + malloc relies on the property that malloc_state is initialized to + all zeroes (as is true of C statics). + +*/ + +static struct malloc_state av_; /* never directly referenced */ + +/* + All uses of av_ are via get_malloc_state(). + This simplifies construction of multithreaded, etc extensions. + + At most one call to get_malloc_state is made per invocation of + the public versions of malloc, free, and all other routines + except realloc, valloc, and vpalloc. Also, it is called + in check* routines if DEBUG is set. +*/ + +#define get_malloc_state() (&(av_)) + +/* + Initialize a malloc_state struct. + + This is called only from within malloc_consolidate, which needs + be called in the same contexts anyway. It is never called directly + outside of malloc_consolidate because some optimizing compilers try + to inline it at all call points, which turns out not to be an + optimization at all. (Inlining it only in malloc_consolidate is fine though.) +*/ + +#if __STD_C +static void malloc_init_state(mstate av) +#else +static void malloc_init_state(av) mstate av; +#endif +{ + int i; + mbinptr bin; + + + /* Uncomment this if you are not using a static av */ + /* MALLOC_ZERO(av, sizeof(struct malloc_state); */ + + /* Establish circular links for normal bins */ + for (i = 1; i < NBINS; ++i) { + bin = bin_at(av,i); + bin->fd = bin->bk = bin; + } + + av->max_fast = req2max_fast(DEFAULT_MXFAST); + + av->top_pad = DEFAULT_TOP_PAD; + av->n_mmaps_max = DEFAULT_MMAP_MAX; + av->mmap_threshold = DEFAULT_MMAP_THRESHOLD; + +#if MORECORE_CONTIGUOUS + av->trim_threshold = DEFAULT_TRIM_THRESHOLD; + av->sbrk_base = (char*)MORECORE_FAILURE; +#else + av->trim_threshold = (unsigned long)(-1); + av->sbrk_base = NONCONTIGUOUS_REGIONS; +#endif + + av->top = initial_top(av); + av->pagesize = malloc_getpagesize; +} + +/* + Other internal utilities operating on mstates +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate); +static int sYSTRIm(size_t, mstate); +static void malloc_consolidate(mstate); +#else +static Void_t* sYSMALLOc(); +static int sYSTRIm(); +static void malloc_consolidate(); +#endif + + +/* + Debugging support + + These routines make a number of assertions about the states + of data structures that should be true at all times. If any + are not true, it's very likely that a user program has somehow + trashed memory. (It's also possible that there is a coding error + in malloc. In which case, please report it!) + +*/ + +#if ! DEBUG + +#define check_chunk(P) +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) +#define check_malloc_state() + +#else +#define check_chunk(P) do_check_chunk(P) +#define check_free_chunk(P) do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#define check_malloc_state() do_check_malloc_state() + + +/* + Properties of all chunks +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ + + mstate av = get_malloc_state(); + unsigned long sz = chunksize(p); + + if (!chunk_is_mmapped(p)) { + + /* Has legal address ... */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p) >= ((char*)(av->sbrk_base))); + } + + if (p != av->top) { + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p + sz) <= ((char*)(av->top))); + } + } + else { + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(((char*)p + sz) <= ((char*)(av->sbrk_base) + av->sbrked_mem)); + } + /* top size is always at least MINSIZE */ + assert((long)(sz) >= (long)(MINSIZE)); + /* top predecessor always marked inuse */ + assert(prev_inuse(p)); + } + + } + else { +#if HAVE_MMAP + /* address is outside main heap */ + /* unless mmap has been used as sbrk backup */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + assert(! (((char*)p) >= ((char*)av->sbrk_base) && + ((char*)p) < ((char*)(av->sbrk_base) + av->sbrked_mem))); + } + /* chunk is page-aligned */ + assert(((p->prev_size + sz) & (av->pagesize-1)) == 0); + /* mem is aligned */ + assert(aligned_OK(chunk2mem(p))); +#else + /* force an appropriate assert violation if debug set */ + assert(!chunk_is_mmapped(p)); +#endif + } + +} + +/* + Properties of free chunks +*/ + + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + mchunkptr next = chunk_at_offset(p, sz); + + do_check_chunk(p); + + /* Chunk must claim to be free ... */ + assert(!inuse(p)); + assert (!chunk_is_mmapped(p)); + + /* Unless a special marker, must have OK fields */ + if ((unsigned long)sz >= (unsigned long)MINSIZE) + { + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(aligned_OK(chunk2mem(p))); + /* ... matching footer field */ + assert(next->prev_size == sz); + /* ... and is fully consolidated */ + assert(prev_inuse(p)); + assert (next == av->top || inuse(next)); + + /* ... and has minimally sane links */ + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_SZ */ + assert(sz == SIZE_SZ); +} + +/* + Properties of inuse chunks +*/ + + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + mchunkptr next; + do_check_chunk(p); + + if (chunk_is_mmapped(p)) + return; /* mmapped chunks have no next/prev */ + + /* Check whether it claims to be in use ... */ + assert(inuse(p)); + + next = next_chunk(p); + + /* ... and is surrounded by OK chunks. + Since more things can be checked with free chunks than inuse ones, + if an inuse chunk borders them and debug is on, it's worth doing them. + */ + if (!prev_inuse(p)) { + /* Note that we cannot even look at prev unless it is not inuse */ + mchunkptr prv = prev_chunk(p); + assert(next_chunk(prv) == p); + do_check_free_chunk(prv); + } + + if (next == av->top) { + assert(prev_inuse(next)); + assert(chunksize(next) >= MINSIZE); + } + else if (!inuse(next)) + do_check_free_chunk(next); + +} + +/* + Properties of chunks recycled from fastbins +*/ + +#if __STD_C +static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + + do_check_inuse_chunk(p); + + /* Legal size ... */ + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert((long)sz - (long)MINSIZE >= 0); + assert((long)sz - (long)s >= 0); + assert((long)sz - (long)(s + MINSIZE) < 0); + + /* ... and alignment */ + assert(aligned_OK(chunk2mem(p))); + +} + +/* + Properties of nonrecycled chunks at the point they are malloced +*/ + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + /* same as recycled case ... */ + do_check_remalloced_chunk(p, s); + + /* + ... plus, must obey implementation invariant that prev_inuse is + always true of any allocated chunk; i.e., that each allocated + chunk borders either a previously allocated and still in-use + chunk, or the base of its memory arena. This is ensured + by making all allocations from the the `lowest' part of any found + chunk. This does not necessarily hold however for chunks + recycled via fastbins. + */ + + assert(prev_inuse(p)); +} + + +/* + Properties of malloc_state. + + This may be useful for debugging malloc, as well as detecting user + programmer errors that somehow write into malloc_state. +*/ + +static void do_check_malloc_state() +{ + mstate av = get_malloc_state(); + int i; + mchunkptr p; + mchunkptr q; + mbinptr b; + unsigned int biton; + int empty; + unsigned int idx; + INTERNAL_SIZE_T size; + unsigned long total = 0; + int max_fast_bin; + + + /* internal size_t must be no wider than pointer type */ + assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*)); + + /* alignment is a power of 2 */ + assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0); + + /* cannot run remaining checks until fully initialized */ + if (av->top == 0 || av->top == initial_top(av)) + return; + + /* pagesize is a power of 2 */ + assert((av->pagesize & (av->pagesize-1)) == 0); + + /* properties of fastbins */ + + /* max_fast is in allowed range */ + + assert((av->max_fast & ~1) <= request2size(MAX_FAST_SIZE)); + + max_fast_bin = fastbin_index(av->max_fast); + + for (i = 0; i < NFASTBINS; ++i) { + p = av->fastbins[i]; + + /* all bins past max_fast are empty */ + if (i > max_fast_bin) + assert(p == 0); + + while (p != 0) { + /* each chunk claims to be inuse */ + do_check_inuse_chunk(p); + total += chunksize(p); + /* chunk belongs in this bin */ + assert(fastbin_index(chunksize(p)) == i); + p = p->fd; + } + } + + if (total != 0) + assert(have_fastchunks(av)); + + /* check normal bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av,i); + + /* binmap is accurate (except for bin 1 == unsorted_chunks) */ + if (i >= 2) { + biton = get_binmap(av,i); + empty = last(b) == b; + if (!biton) + assert(empty); + else if (!empty) + assert(biton); + } + + for (p = last(b); p != b; p = p->bk) { + /* each chunk claims to be free */ + do_check_free_chunk(p); + size = chunksize(p); + total += size; + if (i >= 2) { + /* chunk belongs in bin */ + idx = bin_index(size); + assert(idx == i); + /* lists are sorted */ + assert(p->bk == b || chunksize(p->bk) >= chunksize(p)); + } + /* chunk is followed by a legal chain of inuse chunks */ + for (q = next_chunk(p); + q != av->top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; + q = next_chunk(q)) + do_check_inuse_chunk(q); + + } + } + + /* top chunk is OK */ + check_chunk(av->top); + + /* sanity checks for statistics */ + + assert(total <= (unsigned long)(av->max_total_mem)); + assert(av->n_mmaps >= 0); + assert(av->n_mmaps <= av->n_mmaps_max); + assert(av->n_mmaps <= av->max_n_mmaps); + assert(av->max_n_mmaps <= av->n_mmaps_max); + + assert((unsigned long)(av->sbrked_mem) <= + (unsigned long)(av->max_sbrked_mem)); + + assert((unsigned long)(av->mmapped_mem) <= + (unsigned long)(av->max_mmapped_mem)); + + assert((unsigned long)(av->max_total_mem) >= + (unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem)); + +} + + +#endif + + + + + +/* ----------- Routines dealing with system allocation -------------- */ + +/* + Handle malloc cases requiring more memory from system. + malloc relays to sYSMALLOc if it cannot allocate out of + existing memory. + + On entry, it is assumed that av->top does not have enough + space to service request for nb bytes, thus requiring more meory + from system. +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av) +#else +static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av; +#endif +{ + mchunkptr old_top; /* incoming value of av->top */ + INTERNAL_SIZE_T old_size; /* its size */ + char* old_end; /* its end address */ + + long size; /* arg to first MORECORE or mmap call */ + char* brk; /* return value from MORECORE */ + char* mm; /* return value from mmap call*/ + + long correction; /* arg to 2nd MORECORE call */ + char* snd_brk; /* 2nd return val */ + + INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ + INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */ + char* aligned_brk; /* aligned offset into brk */ + + mchunkptr p; /* the allocated/returned chunk */ + mchunkptr remainder; /* remainder from allocation */ + long remainder_size; /* its size */ + + unsigned long sum; /* for updating stats */ + + size_t pagemask = av->pagesize - 1; + + /* + If have mmap, and the request size meets the mmap threshold, and + the system supports mmap, and there are few enough currently + allocated mmapped regions, and a call to mmap succeeds, try to + directly map this request rather than expanding top. + */ + +#if HAVE_MMAP + if ((unsigned long)nb >= (unsigned long)(av->mmap_threshold) && + (av->n_mmaps < av->n_mmaps_max)) { + + /* + Round up size to nearest page. For mmapped chunks, the overhead + is one SIZE_SZ unit larger than for normal chunks, because there + is no following chunk whose prev_size field could be used. + */ + size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; + + mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (mm != (char*)(MORECORE_FAILURE)) { + + /* + The offset to the start of the mmapped region is stored + in the prev_size field of the chunk. This allows us to adjust + returned start address to meet alignment requirements here + and in memalign(), and still be able to compute proper + address argument for later munmap in free() and realloc(). + */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + correction = MALLOC_ALIGNMENT - front_misalign; + p = (mchunkptr)(mm + correction); + p->prev_size = correction; + set_head(p, (size - correction) |IS_MMAPPED); + } + else { + p = (mchunkptr)mm; + set_head(p, size|IS_MMAPPED); + } + + check_chunk(p); + + /* update statistics */ + + if (++av->n_mmaps > av->max_n_mmaps) + av->max_n_mmaps = av->n_mmaps; + + sum = av->mmapped_mem += size; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + return chunk2mem(p); + } + } +#endif + + /* record incoming configuration of top */ + + old_top = av->top; + old_size = chunksize(old_top); + old_end = (char*)(chunk_at_offset(old_top, old_size)); + + brk = snd_brk = (char*)(MORECORE_FAILURE); + + /* + If not the first time through, we require old_size to be + at least MINSIZE and to have prev_inuse set. + */ + + assert(old_top == initial_top(av) || + ((unsigned long) (old_size) >= (unsigned long)(MINSIZE) && + prev_inuse(old_top))); + + + /* Request enough space for nb + pad + overhead */ + + size = nb + av->top_pad + MINSIZE; + + /* + If contiguous, we can subtract out existing space that we hope to + combine with new space. We add it back later only if + we don't actually get contiguous space. + */ + + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) + size -= old_size; + + /* + Round to a multiple of page size. + If MORECORE is not contiguous, this ensures that we only call it + with whole-page arguments. And if MORECORE is contiguous and + this is not first time through, this preserves page-alignment of + previous calls. Otherwise, we re-correct anyway to page-align below. + */ + + size = (size + pagemask) & ~pagemask; + + /* + Don't try to call MORECORE if argument is so big as to appear + negative. Note that since mmap takes size_t arg, it may succeed + below even if we cannot call MORECORE. + */ + + if (size > 0) + brk = (char*)(MORECORE(size)); + + /* + If have mmap, try using it as a backup when MORECORE fails. This + is worth doing on systems that have "holes" in address space, so + sbrk cannot extend to give contiguous space, but space is available + elsewhere. Note that we ignore mmap max count and threshold limits, + since there is no reason to artificially limit use here. + */ + +#if HAVE_MMAP + if (brk == (char*)(MORECORE_FAILURE)) { + + /* Cannot merge with old top, so add its size back in */ + + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) + size = (size + old_size + pagemask) & ~pagemask; + + /* If we are relying on mmap as backup, then use larger units */ + + if ((unsigned long)size < (unsigned long)MMAP_AS_MORECORE_SIZE) + size = MMAP_AS_MORECORE_SIZE; + + brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (brk != (char*)(MORECORE_FAILURE)) { + + /* We do not need, and cannot use, another sbrk call to find end */ + snd_brk = brk + size; + + /* + Record that we no longer have a contiguous sbrk region. + After the first time mmap is used as backup, we cannot + ever rely on contiguous space. + */ + av->sbrk_base = NONCONTIGUOUS_REGIONS; + } + } +#endif + + if (brk != (char*)(MORECORE_FAILURE)) { + + av->sbrked_mem += size; + + /* + If MORECORE extends previous space, we can likewise extend top size. + */ + + if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { + set_head(old_top, (size + old_size) | PREV_INUSE); + } + + /* + Otherwise, make adjustments guided by the special values of + av->sbrk_base (MORECORE_FAILURE or NONCONTIGUOUS_REGIONS): + + * If the first time through or noncontiguous, we need to call sbrk + just to find out where the end of memory lies. + + * We need to ensure that all returned chunks from malloc will meet + MALLOC_ALIGNMENT + + * If there was an intervening foreign sbrk, we need to adjust sbrk + request size to account for fact that we will not be able to + combine new space with existing space in old_top. + + * Almost all systems internally allocate whole pages at a time, in + which case we might as well use the whole last page of request. + So we allocate enough more memory to hit a page boundary now, + which in turn causes future contiguous calls to page-align. + + */ + + else { + front_misalign = 0; + end_misalign = 0; + correction = 0; + aligned_brk = brk; + + /* handle contiguous cases */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + + /* Guarantee alignment of first new chunk made from this space */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + + /* + Skip over some bytes to arrive at an aligned position. + We don't need to specially mark these wasted front bytes. + They will never be accessed anyway because + prev_inuse of av->top (and any chunk created from its start) + is always true after initialization. + */ + + correction = MALLOC_ALIGNMENT - front_misalign; + aligned_brk += correction; + } + + /* + If this isn't adjacent to a previous sbrk, then we will not + be able to merge with old_top space, so must add to 2nd request. + */ + + correction += old_size; + + /* Pad out to hit a page boundary */ + + end_misalign = (INTERNAL_SIZE_T)(brk + size + correction); + correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; + + assert(correction >= 0); + + snd_brk = (char*)(MORECORE(correction)); + + /* + If can't allocate correction, try to at least find out current + brk. It might be enough to proceed without failing. + + Note that if second sbrk did NOT fail, we assume that space + is contiguous with first sbrk. This is a safe assumption unless + program is multithreaded but doesn't use locks and a foreign sbrk + occurred between our first and second calls. + */ + + if (snd_brk == (char*)(MORECORE_FAILURE)) { + correction = 0; + snd_brk = (char*)(MORECORE(0)); + } + } + + /* handle non-contiguous cases */ + else { + + /* MORECORE/mmap must correctly align etc */ + assert(((unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK) == 0); + + /* Find out current end of memory */ + if (snd_brk == (char*)(MORECORE_FAILURE)) { + snd_brk = (char*)(MORECORE(0)); + } + + /* This must lie on a page boundary */ + if (snd_brk != (char*)(MORECORE_FAILURE)) { + assert(((INTERNAL_SIZE_T)(snd_brk) & pagemask) == 0); + } + } + + /* Adjust top based on results of second sbrk */ + if (snd_brk != (char*)(MORECORE_FAILURE)) { + + av->top = (mchunkptr)aligned_brk; + set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); + + av->sbrked_mem += correction; + + /* If first time through and contiguous, record base */ + if (old_top == initial_top(av)) { + if (av->sbrk_base == (char*)(MORECORE_FAILURE)) + av->sbrk_base = brk; + } + + /* + Otherwise, we either have a gap due to foreign sbrk or a + non-contiguous region. Insert a double fencepost at old_top + to prevent consolidation with space we don't own. These + fenceposts are artificial chunks that are marked as inuse + and are in any case too small to use. We need two to make + sizes and alignments work out. + */ + + else { + + /* + Shrink old_top to insert fenceposts, keeping size a + multiple of MALLOC_ALIGNMENT. + */ + old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head(old_top, old_size | PREV_INUSE); + + /* + Note that the following assignments overwrite old_top when + old_size was previously MINSIZE. This is intentional. We + need the fencepost, even if old_top otherwise gets lost. + */ + chunk_at_offset(old_top, old_size )->size = + SIZE_SZ|PREV_INUSE; + + chunk_at_offset(old_top, old_size + SIZE_SZ)->size = + SIZE_SZ|PREV_INUSE; + + /* If possible, release the rest. */ + if (old_size >= MINSIZE) + fREe(chunk2mem(old_top)); + + } + } + } + + /* Update statistics */ + + sum = av->sbrked_mem; + if (sum > (unsigned long)(av->max_sbrked_mem)) + av->max_sbrked_mem = sum; + + sum += av->mmapped_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + check_malloc_state(); + + /* finally, do the allocation */ + + p = av->top; + size = chunksize(p); + remainder_size = (long)size - (long)nb; + + /* check that one of the above allocation paths succeeded */ + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(p, nb); + av->top = remainder; + set_head(p, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk(p, nb); + return chunk2mem(p); + } + } + + /* catch all failure paths */ + MALLOC_FAILURE_ACTION; + return 0; +} + + +/* + sYSTRIm is an inverse of sorts to sYSMALLOc. + It gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. It is called automatically by free() + when top space exceeds the trim threshold. + returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +static int sYSTRIm(size_t pad, mstate av) +#else +static int sYSTRIm(pad, av) size_t pad; mstate av; +#endif +{ + long top_size; /* Amount of top-most memory */ + long extra; /* Amount to release */ + long released; /* Amount actually released */ + char* current_brk; /* address returned by pre-check sbrk call */ + char* new_brk; /* address returned by post-check sbrk call */ + size_t pagesz; + + /* Don't bother trying if sbrk doesn't provide contiguous regions */ + if (av->sbrk_base != NONCONTIGUOUS_REGIONS) { + + pagesz = av->pagesize; + top_size = chunksize(av->top); + + /* Release in pagesize units, keeping at least one page */ + extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + + if (extra > 0) { + + /* + Only proceed if end of memory is where we last set it. + This avoids problems if there were foreign sbrk calls. + */ + current_brk = (char*)(MORECORE(0)); + if (current_brk == (char*)(av->top) + top_size) { + + /* + Attempt to release memory. We ignore return value, + and instead call again to find out where new end of memory is. + This avoids problems if first call releases less than we asked, + of if failure somehow altered brk value. (We could still + encounter problems if it altered brk in some very bad way, + but the only thing we can do is adjust anyway, which will cause + some downstream failure.) + */ + + MORECORE(-extra); + new_brk = (char*)(MORECORE(0)); + + if (new_brk != (char*)MORECORE_FAILURE) { + released = (long)(current_brk - new_brk); + + if (released != 0) { + /* Success. Adjust top. */ + av->sbrked_mem -= released; + set_head(av->top, (top_size - released) | PREV_INUSE); + check_malloc_state(); + return 1; + } + } + } + } + } + + return 0; +} + +/* ----------------------- Main public routines ----------------------- */ + + +/* + Malloc routine. See running comments for algorithm description. +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else + Void_t* mALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* normalized request size */ + unsigned int idx; /* associated bin index */ + mbinptr bin; /* associated bin */ + mfastbinptr* fb; /* associated fastbin */ + + mchunkptr victim; /* inspected/selected chunk */ + INTERNAL_SIZE_T size; /* its size */ + int victim_index; /* its bin index */ + + mchunkptr remainder; /* remainder from a split */ + long remainder_size; /* its size */ + + unsigned int block; /* bit map traverser */ + unsigned int bit; /* bit map traverser */ + unsigned int map; /* current word of binmap */ + + mchunkptr fwd; /* misc temp for linking */ + mchunkptr bck; /* misc temp for linking */ + + + /* + Check request for legality and convert to internal form, nb. + This rejects negative arguments when size_t is treated as + signed. It also rejects arguments that are so large that the size + appears negative when aligned and padded. The converted form + adds SIZE_T bytes overhead plus possibly more to obtain necessary + alignment and/or to obtain a size of at least MINSIZE, the + smallest allocatable size. + */ + + checked_request2size(bytes, nb); + + /* + If the size qualifies as a fastbin, first check corresponding bin. + This code is safe to execute even if av not yet initialized, so we + can try it first, which saves some time on this fast path. + */ + + if (nb <= av->max_fast) { + fb = &(av->fastbins[(fastbin_index(nb))]); + if ( (victim = *fb) != 0) { + *fb = victim->fd; + check_remalloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + + /* + If a small request, check regular bin. Since these "smallbins" + hold one size each, no searching within bins is necessary. + + (If a large request, we need to wait until unsorted chunks are + processed to find best fit. But for small ones, fits are exact + anyway, so we can check now, which is faster.) + */ + + if (in_smallbin_range(nb)) { + idx = smallbin_index(nb); + bin = bin_at(av,idx); + + if ( (victim = last(bin)) != bin) { + if (victim == 0) /* initialization check */ + malloc_consolidate(av); + else { + bck = victim->bk; + set_inuse_bit_at_offset(victim, nb); + bin->bk = bck; + bck->fd = bin; + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + If a large request, consolidate fastbins before continuing. + While it might look excessive to kill all fastbins before + even seeing if there is space available, this avoids + fragmentation problems normally associated with fastbins. + Also, in practice, programs tend to have runs of either small or + large requests, but less often mixtures, so consolidation is not + usually invoked all that often. + */ + + else { + idx = largebin_index(nb); + if (have_fastchunks(av)) /* consolidation/initialization check */ + malloc_consolidate(av); + } + + + /* + Process recently freed or remaindered chunks, taking one only if + it is exact fit, or, if a small request, it is the remainder from + the most recent non-exact fit. Place other traversed chunks in + bins. Note that this step is the only place in any routine where + chunks are placed in bins. + + The outer loop here is needed because we might not realize until + near the end of malloc that we should have consolidated, so must + do so and retry. This happens at most once, and only when we would + otherwise need to expand memory to service a "small" request. + */ + + + for(;;) { + + while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { + bck = victim->bk; + size = chunksize(victim); + + /* + If a small request, try to use last remainder if it is the + only chunk in unsorted bin. This helps promote locality for + runs of consecutive small requests. This is the only + exception to best-fit. + */ + + if (in_smallbin_range(nb) && + victim == av->last_remainder && + bck == unsorted_chunks(av) && + (remainder_size = (long)size - (long)nb) >= (long)MINSIZE) { + + /* split and reattach remainder */ + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + av->last_remainder = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* remove from unsorted list */ + unsorted_chunks(av)->bk = bck; + bck->fd = unsorted_chunks(av); + + /* Take now instead of binning if exact fit */ + + if (size == nb) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* place chunk in bin */ + + if (in_smallbin_range(size)) { + victim_index = smallbin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + } + else { + victim_index = largebin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + + /* maintain large bins in sorted order */ + if (fwd != bck) { + /* if smaller than smallest, bypass loop below */ + if ((unsigned long)size <= + (unsigned long)(chunksize(bck->bk))) { + fwd = bck; + bck = bck->bk; + } + else { + while (fwd != bck && + (unsigned long)size < (unsigned long)(chunksize(fwd))) { + fwd = fwd->fd; + } + bck = fwd->bk; + } + } + } + + mark_bin(av, victim_index); + victim->bk = bck; + victim->fd = fwd; + fwd->bk = victim; + bck->fd = victim; + } + + /* + If a large request, scan through the chunks of current bin in + sorted order to find smallest that fits. This is the only step + where an unbounded number of chunks might be scanned without doing + anything useful with them. However the lists tend to be very + short. + */ + + if (!in_smallbin_range(nb)) { + bin = bin_at(av, idx); + + /* skip scan if largest chunk is too small */ + if ((victim = last(bin)) != bin && + (long)(chunksize(first(bin))) - (long)(nb) >= 0) { + do { + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + if (remainder_size >= 0) { + unlink(victim, bck, fwd); + + /* Exhaust */ + if (remainder_size < (long)MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } while ( (victim = victim->bk) != bin); + } + } + + /* + Search for a chunk by scanning bins, starting with next largest + bin. This search is strictly by best-fit; i.e., the smallest + (with ties going to approximately the least recently used) chunk + that fits is selected. + + The bitmap avoids needing to check that most blocks are nonempty. + The particular case of skipping all bins during warm-up phases + when no chunks have been returned yet is faster than it might look. + */ + + ++idx; + bin = bin_at(av,idx); + block = idx2block(idx); + map = av->binmap[block]; + bit = idx2bit(idx); + + for (;;) { + /* + Skip rest of block if there are no more set bits in this block. + */ + + if (bit > map || bit == 0) { + for (;;) { + if (++block >= BINMAPSIZE) /* out of bins */ + break; + + else if ( (map = av->binmap[block]) != 0) { + bin = bin_at(av, (block << BINMAPSHIFT)); + bit = 1; + break; + } + } + /* Optimizers seem to like this double-break better than goto */ + if (block >= BINMAPSIZE) + break; + } + + /* Advance to bin with set bit. There must be one. */ + while ((bit & map) == 0) { + bin = next_bin(bin); + bit <<= 1; + } + + victim = last(bin); + + /* False alarm -- the bin is empty. Clear the bit. */ + if (victim == bin) { + av->binmap[block] = map &= ~bit; /* Write through */ + bin = next_bin(bin); + bit <<= 1; + } + + /* We know the first chunk in this bin is big enough to use. */ + else { + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + assert(remainder_size >= 0); + + /* unlink */ + bck = victim->bk; + bin->bk = bck; + bck->fd = bin; + + + /* Exhaust */ + if (remainder_size < (long)MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + /* advertise as last remainder */ + if (in_smallbin_range(nb)) + av->last_remainder = remainder; + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + If large enough, split off the chunk bordering the end of memory + ("top"). Note that this use of top is in accord with the best-fit search + rule. In effect, top is treated as larger (and thus less well + fitting) than any other available chunk since it can be extended + to be as large as necessary (up to system limitations). + + We require that "top" always exists (i.e., has size >= MINSIZE) + after initialization, so if it would otherwise be exhuasted by + current request, it is replenished. (Among the reasons for + ensuring it exists is that we may need MINSIZE space to put in + fenceposts in sysmalloc.) + */ + + victim = av->top; + size = chunksize(victim); + remainder_size = (long)size - (long)nb; + + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(victim, nb); + av->top = remainder; + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* + If there is space available in fastbins, consolidate and retry, + to possibly avoid expanding memory. This can occur only if nb is + in smallbin range so we didn't consolidate upon entry. + */ + + else if (have_fastchunks(av)) { + assert(in_smallbin_range(nb)); + idx = smallbin_index(nb); /* restore original bin index */ + malloc_consolidate(av); + } + + /* + Otherwise, relay to handle system-dependent cases + */ + else + return sYSMALLOc(nb, av); + } +} + + + +/* + Free routine. See running comments for algorithm description. +*/ + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ + mstate av = get_malloc_state(); + + mchunkptr p; /* chunk corresponding to mem */ + INTERNAL_SIZE_T size; /* its size */ + mfastbinptr* fb; /* associated fastbin */ + mchunkptr nextchunk; /* next contiguous chunk */ + INTERNAL_SIZE_T nextsize; /* its size */ + int nextinuse; /* true if nextchunk is used */ + INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */ + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + + /* free(0) has no effect */ + if (mem != 0) { + + p = mem2chunk(mem); + check_inuse_chunk(p); + + size = chunksize(p); + + /* + If eligible, place chunk on a fastbin so it can be found + and used quickly in malloc. + */ + + if ((unsigned long)size <= (unsigned long)av->max_fast + +#if TRIM_FASTBINS + /* + If TRIM_FASTBINS set, don't place chunks + bordering top into fastbins + */ + && (chunk_at_offset(p, size) != av->top) +#endif + ) { + + set_fastchunks(av); + fb = &(av->fastbins[fastbin_index(size)]); + p->fd = *fb; + *fb = p; + } + + /* + Consolidate non-mmapped chunks as they arrive. + */ + + else if (!chunk_is_mmapped(p)) { + + nextchunk = chunk_at_offset(p, size); + + /* consolidate backward */ + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + nextsize = chunksize(nextchunk); + + if (nextchunk != av->top) { + + /* get and clear inuse bit */ + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + /* consolidate forward */ + if (!nextinuse) { + unlink(nextchunk, bck, fwd); + size += nextsize; + } + + /* + Place chunk in unsorted chunk list. Chunks are + not placed into regular bins until after they have + been given one chance to be used in malloc. + */ + + bck = unsorted_chunks(av); + fwd = bck->fd; + p->bk = bck; + p->fd = fwd; + bck->fd = p; + fwd->bk = p; + + set_head(p, size | PREV_INUSE); + set_foot(p, size); + } + + /* + If the chunk borders the current high end of memory, + consolidate into top + */ + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + + /* + If the total unused topmost memory exceeds trim + threshold, ask malloc_trim to reduce top. + + Unless max_fast is 0, we don't know if there are fastbins + bordering top, so we cannot tell for sure whether threshold has + been reached unless fastbins are consolidated. But we don't + want to consolidate on each free. As a compromise, + consolidation is performed if half the threshold is + reached. + + */ + + if ((unsigned long)(size) > (unsigned long)(av->trim_threshold / 2)) { + if (have_fastchunks(av)) { + malloc_consolidate(av); + size = chunksize(av->top); + } + + if ((unsigned long)(size) > (unsigned long)(av->trim_threshold)) + sYSTRIm(av->top_pad, av); + } + } + } + + /* + If the chunk was allocated via mmap, release via munmap() + Note that if HAVE_MMAP is false but chunk_is_mmapped is + true, then user must have overwritten memory. There's nothing + we can do to catch this error unless DEBUG is set, in which case + check_inuse_chunk (above) will have triggered error. + */ + + else { +#if HAVE_MMAP + int ret; + INTERNAL_SIZE_T offset = p->prev_size; + av->n_mmaps--; + av->mmapped_mem -= (size + offset); + ret = munmap((char*)p - offset, size + offset); + /* munmap returns non-zero on failure */ + assert(ret == 0); +#endif + } + } +} + + + +/* + malloc_consolidate is a specialized version of free() that tears + down chunks held in fastbins. Free itself cannot be used for this + purpose since, among other things, it might place chunks back onto + fastbins. So, instead, we need to use a minor variant of the same + code. + + Also, because this routine needs to be called the first time through + malloc anyway, it turns out to be the perfect place to bury + initialization code. +*/ + +#if __STD_C +static void malloc_consolidate(mstate av) +#else +static void malloc_consolidate(av) mstate av; +#endif +{ + mfastbinptr* fb; + mfastbinptr* maxfb; + mchunkptr p; + mchunkptr nextp; + mchunkptr unsorted_bin; + mchunkptr first_unsorted; + + /* These have same use as in free() */ + mchunkptr nextchunk; + INTERNAL_SIZE_T size; + INTERNAL_SIZE_T nextsize; + INTERNAL_SIZE_T prevsize; + int nextinuse; + mchunkptr bck; + mchunkptr fwd; + + /* + If max_fast is 0, we know that malloc hasn't + yet been initialized, in which case do so. + */ + + if (av->max_fast == 0) { + malloc_init_state(av); + check_malloc_state(); + } + else if (have_fastchunks(av)) { + clear_fastchunks(av); + + unsorted_bin = unsorted_chunks(av); + + /* + Remove each chunk from fast bin and consolidate it, placing it + then in unsorted bin. Among other reasons for doing this, + placing in unsorted bin avoids needing to calculate actual bins + until malloc is sure that chunks aren't immediately going to be + reused anyway. + */ + + maxfb = &(av->fastbins[fastbin_index(av->max_fast)]); + fb = &(av->fastbins[0]); + do { + if ( (p = *fb) != 0) { + *fb = 0; + + do { + check_inuse_chunk(p); + nextp = p->fd; + + /* Slightly streamlined version of consolidation code in free() */ + size = p->size & ~PREV_INUSE; + nextchunk = chunk_at_offset(p, size); + + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + nextsize = chunksize(nextchunk); + + if (nextchunk != av->top) { + + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + if (!nextinuse) { + size += nextsize; + unlink(nextchunk, bck, fwd); + } + + first_unsorted = unsorted_bin->fd; + unsorted_bin->fd = p; + first_unsorted->bk = p; + + set_head(p, size | PREV_INUSE); + p->bk = unsorted_bin; + p->fd = first_unsorted; + set_foot(p, size); + } + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + } + + } while ( (p = nextp) != 0); + + } + } while (fb++ != maxfb); + } +} + + + + +/* + Realloc algorithm cases: + + * Chunks that were obtained via mmap cannot be extended or shrunk + unless HAVE_MREMAP is defined, in which case mremap is used. + Otherwise, if the reallocation is for additional space, they are + copied. If for less, they are just left alone. + + * Otherwise, if the reallocation is for additional space, and the + chunk can be extended, it is, else a malloc-copy-free sequence is + taken. There are several different ways that a chunk could be + extended. All are tried: + + * Extending forward into following adjacent free chunk. + * Shifting backwards, joining preceding adjacent space + * Both shifting backwards and extending forward. + * Extending into newly sbrked space + + * If there is not enough memory available to realloc, realloc + returns null, but does NOT free the existing space. + + * If the reallocation is for less space, the newly unused space is + lopped off and freed. Unless the #define REALLOC_ZERO_BYTES_FREES + is set, realloc with a size argument of zero (re)allocates a + minimum-sized chunk. + + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is no longer supported. + I don't know of any programs still relying on this feature, + and allowing it would also allow too many other incorrect + usages of realloc to be sensible. +*/ + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* padded request size */ + + mchunkptr oldp; /* chunk corresponding to oldmem */ + INTERNAL_SIZE_T oldsize; /* its size */ + + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + Void_t* newmem; /* corresponding user mem */ + + mchunkptr next; /* next contiguous chunk after oldp */ + mchunkptr prev; /* previous contiguous chunk before oldp */ + + mchunkptr remainder; /* extra space at end of newp */ + long remainder_size; /* its size */ + + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + INTERNAL_SIZE_T copysize; /* bytes to copy */ + int ncopies; /* INTERNAL_SIZE_T words to copy */ + INTERNAL_SIZE_T* s; /* copy source */ + INTERNAL_SIZE_T* d; /* copy destination */ + + +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + fREe(oldmem); + return 0; + } +#endif + + /* realloc of null is supposed to be same as malloc */ + if (oldmem == 0) return mALLOc(bytes); + + checked_request2size(bytes, nb); + + oldp = mem2chunk(oldmem); + oldsize = chunksize(oldp); + + check_inuse_chunk(oldp); + + if (!chunk_is_mmapped(oldp)) { + + if ((unsigned long)(oldsize) >= (unsigned long)(nb)) { + /* already big enough; split below */ + newp = oldp; + newsize = oldsize; + } + + else { + newp = 0; + newsize = 0; + + next = chunk_at_offset(oldp, oldsize); + + if (next == av->top) { /* Expand forward into top */ + newsize = oldsize + chunksize(next); + + if ((unsigned long)(newsize) >= (unsigned long)(nb + MINSIZE)) { + set_head_size(oldp, nb); + av->top = chunk_at_offset(oldp, nb); + set_head(av->top, (newsize - nb) | PREV_INUSE); + return chunk2mem(oldp); + } + + else if (!prev_inuse(oldp)) { /* Shift backwards + top */ + prev = prev_chunk(oldp); + newsize += chunksize(prev); + + if ((unsigned long)(newsize) >= (unsigned long)(nb + MINSIZE)) { + newp = prev; + unlink(prev, bck, fwd); + av->top = chunk_at_offset(newp, nb); + set_head(av->top, (newsize - nb) | PREV_INUSE); + newsize = nb; + } + } + } + + else if (!inuse(next)) { /* Forward into next chunk */ + newsize = oldsize + chunksize(next); + + if (((unsigned long)(newsize) >= (unsigned long)(nb))) { + newp = oldp; + unlink(next, bck, fwd); + } + + else if (!prev_inuse(oldp)) { /* Forward + backward */ + prev = prev_chunk(oldp); + newsize += chunksize(prev); + + if (((unsigned long)(newsize) >= (unsigned long)(nb))) { + newp = prev; + unlink(prev, bck, fwd); + unlink(next, bck, fwd); + } + } + } + + else if (!prev_inuse(oldp)) { /* Backward only */ + prev = prev_chunk(oldp); + newsize = oldsize + chunksize(prev); + + if ((unsigned long)(newsize) >= (unsigned long)(nb)) { + newp = prev; + unlink(prev, bck, fwd); + } + } + + if (newp != 0) { + if (newp != oldp) { + /* Backward copies are not worth unrolling */ + MALLOC_COPY(chunk2mem(newp), oldmem, oldsize - SIZE_SZ, 1); + } + } + + /* Must allocate */ + else { + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem == 0) + return 0; /* propagate failure */ + + newp = mem2chunk(newmem); + newsize = chunksize(newp); + + /* + Avoid copy if newp is next chunk after oldp. + */ + if (newp == next) { + newsize += oldsize; + newp = oldp; + } + else { + + /* + Unroll copy of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + copysize = oldsize - SIZE_SZ; + s = (INTERNAL_SIZE_T*)oldmem; + d = (INTERNAL_SIZE_T*)(chunk2mem(newp)); + ncopies = copysize / sizeof(INTERNAL_SIZE_T); + assert(ncopies >= 3); + + if (ncopies > 9) + MALLOC_COPY(d, s, copysize, 0); + + else { + *(d+0) = *(s+0); + *(d+1) = *(s+1); + *(d+2) = *(s+2); + if (ncopies > 4) { + *(d+3) = *(s+3); + *(d+4) = *(s+4); + if (ncopies > 6) { + *(d+5) = *(s+5); + *(d+6) = *(s+6); + if (ncopies > 8) { + *(d+7) = *(s+7); + *(d+8) = *(s+8); + } + } + } + } + + fREe(oldmem); + check_inuse_chunk(newp); + return chunk2mem(newp); + } + } + } + + + /* If possible, free extra space in old or extended chunk */ + + remainder_size = (long)newsize - (long)nb; + assert(remainder_size >= 0); + + if (remainder_size >= (long)MINSIZE) { /* split remainder */ + remainder = chunk_at_offset(newp, nb); + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + /* Mark remainder as inuse so free() won't complain */ + set_inuse_bit_at_offset(remainder, remainder_size); + fREe(chunk2mem(remainder)); + } + + else { /* not enough extra to split off */ + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } + + check_inuse_chunk(newp); + return chunk2mem(newp); + } + + /* + Handle mmap cases + */ + + else { +#if HAVE_MMAP + +#if HAVE_MREMAP + INTERNAL_SIZE_T offset = oldp->prev_size; + size_t pagemask = av->pagesize - 1; + char *cp; + unsigned long sum; + + /* Note the extra SIZE_SZ overhead */ + newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask; + + /* don't need to remap if still within same page */ + if (oldsize == newsize - offset) + return oldmem; + + cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1); + + if (cp != (char*)MORECORE_FAILURE) { + + newp = (mchunkptr)(cp + offset); + set_head(newp, (newsize - offset)|IS_MMAPPED); + + assert(aligned_OK(chunk2mem(newp))); + assert((newp->prev_size == offset)); + + /* update statistics */ + sum = av->mmapped_mem += newsize - oldsize; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + return chunk2mem(newp); + } + +#endif + + /* Note the extra SIZE_SZ overhead. */ + if ((long)oldsize - (long)SIZE_SZ >= (long)nb) + newmem = oldmem; /* do nothing */ + else { + /* Must alloc, copy, free. */ + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem != 0) { + MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ, 0); + fREe(oldmem); + } + } + return newmem; + +#else + /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */ + check_malloc_state(); + MALLOC_FAILURE_ACTION; + return 0; +#endif + } + +} + + + +/* + memalign requests more than enough space from malloc, finds a spot + within that chunk that meets the alignment request, and then + possibly frees the leading and trailing space. + + Alignments must be powers of two. If the argument is not a + power of two, the nearest greater power is used. + + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ + + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + char* m; /* memory returned by malloc call */ + mchunkptr p; /* corresponding chunk */ + char* brk; /* alignment point within p */ + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ + mchunkptr remainder; /* spare room at end to split off */ + long remainder_size; /* its size */ + + + /* If need less alignment than we give anyway, just relay to malloc */ + + if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + + /* Otherwise, ensure that it is at least a minimum chunk size */ + + if (alignment < MINSIZE) alignment = MINSIZE; + + /* Make sure alignment is power of 2 (in case MINSIZE is not). */ + if ((alignment & (alignment - 1)) != 0) { + size_t a = MALLOC_ALIGNMENT * 2; + while ((unsigned long)a < (unsigned long)alignment) a <<= 1; + alignment = a; + } + + checked_request2size(bytes, nb); + + /* Call malloc with worst case padding to hit alignment. */ + + m = (char*)(mALLOc(nb + alignment + MINSIZE)); + + if (m == 0) return 0; /* propagate failure */ + + p = mem2chunk(m); + + if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */ + + /* + Find an aligned spot inside chunk. Since we need to give back + leading space in a chunk of at least MINSIZE, if the first + calculation places us at a spot with less than MINSIZE leader, + we can move to the next aligned spot -- we've allocated enough + total room so that this is always possible. + */ + + brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & + -((signed long) alignment)); + if ((long)(brk - (char*)(p)) < (long)MINSIZE) + brk = brk + alignment; + + newp = (mchunkptr)brk; + leadsize = brk - (char*)(p); + newsize = chunksize(p) - leadsize; + + /* For mmapped chunks, just adjust offset */ + if (chunk_is_mmapped(p)) { + newp->prev_size = p->prev_size + leadsize; + set_head(newp, newsize|IS_MMAPPED); + return chunk2mem(newp); + } + + /* Otherwise, give back leader, use the rest */ + + set_head(newp, newsize | PREV_INUSE); + set_inuse_bit_at_offset(newp, newsize); + set_head_size(p, leadsize); + fREe(chunk2mem(p)); + p = newp; + + assert (newsize >= nb && + (((unsigned long)(chunk2mem(p))) % alignment) == 0); + } + + /* Also give back spare room at the end */ + if (!chunk_is_mmapped(p)) { + + remainder_size = (long)(chunksize(p)) - (long)nb; + + if (remainder_size >= (long)MINSIZE) { + remainder = chunk_at_offset(p, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_head_size(p, nb); + fREe(chunk2mem(remainder)); + } + } + + check_inuse_chunk(p); + return chunk2mem(p); + +} + + + + +/* + calloc calls malloc, then zeroes out the allocated chunk. +*/ + +#if __STD_C +Void_t* cALLOc(size_t n_elements, size_t elem_size) +#else +Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size; +#endif +{ + mchunkptr p; + INTERNAL_SIZE_T clearsize; + int nclears; + INTERNAL_SIZE_T* d; + + Void_t* mem = mALLOc(n_elements * elem_size); + + if (mem != 0) { + p = mem2chunk(mem); + if (!chunk_is_mmapped(p)) { /* don't need to clear mmapped space */ + + /* + Unroll clear of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + d = (INTERNAL_SIZE_T*)mem; + clearsize = chunksize(p) - SIZE_SZ; + nclears = clearsize / sizeof(INTERNAL_SIZE_T); + assert(nclears >= 3); + + if (nclears > 9) + MALLOC_ZERO(d, clearsize); + + else { + *(d+0) = 0; + *(d+1) = 0; + *(d+2) = 0; + if (nclears > 4) { + *(d+3) = 0; + *(d+4) = 0; + if (nclears > 6) { + *(d+5) = 0; + *(d+6) = 0; + if (nclears > 8) { + *(d+7) = 0; + *(d+8) = 0; + } + } + } + } + } + } + return mem; +} + + +/* + cfree just calls free. It is needed/defined on some systems + that pair it with calloc, presumably for odd historical reasons + (such as: cfree is used in example code in first edition of K&R). +*/ + +#if __STD_C +void cFREe(Void_t *mem) +#else +void cFREe(mem) Void_t *mem; +#endif +{ + fREe(mem); +} + + + + + +/* + valloc just invokes memalign with alignment argument equal + to the page size of the system (or as near to this as can + be figured out from all the includes/defines above.) +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ + /* Ensure initialization/consolidation */ + mstate av = get_malloc_state(); + malloc_consolidate(av); + return mEMALIGn(av->pagesize, bytes); +} + +/* + pvalloc just invokes valloc for the nearest pagesize + that will accommodate request +*/ + + +#if __STD_C +Void_t* pVALLOc(size_t bytes) +#else +Void_t* pVALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + size_t pagesz; + + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + pagesz = av->pagesize; + return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1)); +} + + +/* + Malloc_Trim gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. You can call this after freeing large blocks of + memory to potentially reduce the system-level memory requirements + of a program. However, it cannot guarantee to reduce memory. Under + some allocation patterns, some large free blocks of memory will be + locked between two used chunks, so they cannot be given back to + the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, + only the minimum amount of memory to maintain internal data + structures will be left (one page or less). Non-zero arguments + can be supplied to maintain enough trailing space to service + future expected allocations without having to re-obtain memory + from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +int mTRIm(size_t pad) +#else +int mTRIm(pad) size_t pad; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + return sYSTRIm(pad, av); +} + +/* + malloc_usable_size tells you how many bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not). You can use this many bytes without worrying about + overwriting other allocated objects. Not a particularly great + programming practice, but still sometimes useful. +*/ + +#if __STD_C +size_t mUSABLe(Void_t* mem) +#else +size_t mUSABLe(mem) Void_t* mem; +#endif +{ + mchunkptr p; + if (mem != 0) { + p = mem2chunk(mem); + if (chunk_is_mmapped(p)) + return chunksize(p) - 2*SIZE_SZ; + else if (inuse(p)) + return chunksize(p) - SIZE_SZ; + } + return 0; +} + + + + +/* + mallinfo returns a copy of updated current mallinfo. +*/ + +struct mallinfo mALLINFo() +{ + mstate av = get_malloc_state(); + struct mallinfo mi; + int i; + mbinptr b; + mchunkptr p; + INTERNAL_SIZE_T avail; + int navail; + int nfastblocks; + int fastbytes; + + /* Ensure initialization */ + if (av->top == 0) malloc_consolidate(av); + + check_malloc_state(); + + /* Account for top */ + avail = chunksize(av->top); + navail = 1; /* top always exists */ + + /* traverse fastbins */ + nfastblocks = 0; + fastbytes = 0; + + for (i = 0; i < NFASTBINS; ++i) { + for (p = av->fastbins[i]; p != 0; p = p->fd) { + ++nfastblocks; + fastbytes += chunksize(p); + } + } + + avail += fastbytes; + + /* traverse regular bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av, i); + for (p = last(b); p != b; p = p->bk) { + avail += chunksize(p); + navail++; + } + } + + mi.smblks = nfastblocks; + mi.ordblks = navail; + mi.fordblks = avail; + mi.uordblks = av->sbrked_mem - avail; + mi.arena = av->sbrked_mem; + mi.hblks = av->n_mmaps; + mi.hblkhd = av->mmapped_mem; + mi.fsmblks = fastbytes; + mi.keepcost = chunksize(av->top); + mi.usmblks = av->max_total_mem; + return mi; +} + + + +/* + malloc_stats prints on stderr the amount of space obtained from the + system (both via sbrk and mmap), the maximum amount (which may be + more than current if malloc_trim and/or munmap got called), and the + current number of bytes allocated via malloc (or realloc, etc) but + not yet freed. Note that this is the number of bytes allocated, not + the number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than zero + even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ + +void mSTATs() +{ + struct mallinfo mi = mALLINFo(); + +#ifdef WIN32 + { + unsigned long free, reserved, committed; + vminfo (&free, &reserved, &committed); + fprintf(stderr, "free bytes = %10lu\n", + free); + fprintf(stderr, "reserved bytes = %10lu\n", + reserved); + fprintf(stderr, "committed bytes = %10lu\n", + committed); + } +#endif + + + fprintf(stderr, "max system bytes = %10lu\n", + (unsigned long)(mi.usmblks)); + fprintf(stderr, "system bytes = %10lu\n", + (unsigned long)(mi.arena + mi.hblkhd)); + fprintf(stderr, "in use bytes = %10lu\n", + (unsigned long)(mi.uordblks + mi.hblkhd)); + +#ifdef WIN32 + { + unsigned long kernel, user; + if (cpuinfo (TRUE, &kernel, &user)) { + fprintf(stderr, "kernel ms = %10lu\n", + kernel); + fprintf(stderr, "user ms = %10lu\n", + user); + } + } +#endif +} + + + +/* + mallopt is the general SVID/XPG interface to tunable parameters. + The format is to provide a (parameter-number, parameter-value) + pair. mallopt then sets the corresponding parameter to the + argument value if it can (i.e., so long as the value is + meaningful), and returns 1 if successful else 0. See descriptions + of tunable parameters above for meanings. +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + switch(param_number) { + case M_MXFAST: + if (value >= 0 && value <= MAX_FAST_SIZE) { + av->max_fast = req2max_fast(value); + return 1; + } + else + return 0; + + case M_TRIM_THRESHOLD: + av->trim_threshold = value; + return 1; + + case M_TOP_PAD: + av->top_pad = value; + return 1; + + case M_MMAP_THRESHOLD: + av->mmap_threshold = value; + return 1; + + case M_MMAP_MAX: +#if HAVE_MMAP + av->n_mmaps_max = value; + return 1; +#else + if (value != 0) + return 0; + else { + av->n_mmaps_max = value; + return 1; + } +#endif + + default: + return 0; + } +} + + +/* -------------------------------------------------------------- */ + +/* + Emulation of sbrk for win32. + Donated by J. Walter . + For additional information about this code, and malloc on Win32, see + http://www.genesys-e.de/jwalter/ + +*/ + + +#ifdef WIN32 + +#ifdef _DEBUG +/* #define TRACE */ +#endif + +/* Support for USE_MALLOC_LOCK */ +#ifdef USE_MALLOC_LOCK + +/* Wait for spin lock */ +static int slwait (int *sl) { + while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0) + Sleep (0); + return 0; +} + +/* Release spin lock */ +static int slrelease (int *sl) { + InterlockedExchange (sl, 0); + return 0; +} + +#ifdef NEEDED +/* Spin lock for emulation code */ +static int g_sl; +#endif + +#endif /* USE_MALLOC_LOCK */ + +/* getpagesize for windows */ +static long getpagesize (void) { + static long g_pagesize = 0; + if (! g_pagesize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_pagesize = system_info.dwPageSize; + } + return g_pagesize; +} +static long getregionsize (void) { + static long g_regionsize = 0; + if (! g_regionsize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_regionsize = system_info.dwAllocationGranularity; + } + return g_regionsize; +} + +/* A region list entry */ +typedef struct _region_list_entry { + void *top_allocated; + void *top_committed; + void *top_reserved; + long reserve_size; + struct _region_list_entry *previous; +} region_list_entry; + +/* Allocate and link a region entry in the region list */ +static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) { + region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry)); + if (! next) + return FALSE; + next->top_allocated = (char *) base_reserved; + next->top_committed = (char *) base_reserved; + next->top_reserved = (char *) base_reserved + reserve_size; + next->reserve_size = reserve_size; + next->previous = *last; + *last = next; + return TRUE; +} +/* Free and unlink the last region entry from the region list */ +static int region_list_remove (region_list_entry **last) { + region_list_entry *previous = (*last)->previous; + if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last)) + return FALSE; + *last = previous; + return TRUE; +} + +#define CEIL(size,to) (((size)+(to)-1)&~((to)-1)) +#define FLOOR(size,to) ((size)&~((to)-1)) + +#define SBRK_SCALE 0 +/* #define SBRK_SCALE 1 */ +/* #define SBRK_SCALE 2 */ +/* #define SBRK_SCALE 4 */ + +/* sbrk for windows */ +static void *sbrk (long size) { + static long g_pagesize, g_my_pagesize; + static long g_regionsize, g_my_regionsize; + static region_list_entry *g_last; + void *result = (void *) MORECORE_FAILURE; +#ifdef TRACE + printf ("sbrk %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) { + g_pagesize = getpagesize (); + g_my_pagesize = g_pagesize << SBRK_SCALE; + } + if (! g_regionsize) { + g_regionsize = getregionsize (); + g_my_regionsize = g_regionsize << SBRK_SCALE; + } + if (! g_last) { + if (! region_list_append (&g_last, 0, 0)) + goto sbrk_exit; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + /* Allocation requested? */ + if (size >= 0) { + /* Allocation size is the requested size */ + long allocate_size = size; + /* Compute the size to commit */ + long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Do we reach the commit limit? */ + if (to_commit > 0) { + /* Round size to commit */ + long commit_size = CEIL (to_commit, g_my_pagesize); + /* Compute the size to reserve */ + long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved; + /* Do we reach the reserve limit? */ + if (to_reserve > 0) { + /* Compute the remaining size to commit in the current region */ + long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed; + if (remaining_commit_size > 0) { + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, remaining_commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + remaining_commit_size; + } + } { + /* Now we are going to search and reserve. */ + int contiguous = -1; + int found = FALSE; + MEMORY_BASIC_INFORMATION memory_info; + void *base_reserved; + long reserve_size; + do { + /* Assume contiguous memory */ + contiguous = TRUE; + /* Round size to reserve */ + reserve_size = CEIL (to_reserve, g_my_regionsize); + /* Start with the current region's top */ + memory_info.BaseAddress = g_last->top_reserved; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + /* Assert postconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); +#ifdef TRACE + printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize, + memory_info.State == MEM_FREE ? "FREE": + (memory_info.State == MEM_RESERVE ? "RESERVED": + (memory_info.State == MEM_COMMIT ? "COMMITTED": "?"))); +#endif + /* Region is free, well aligned and big enough: we are done */ + if (memory_info.State == MEM_FREE && + (unsigned) memory_info.BaseAddress % g_regionsize == 0 && + memory_info.RegionSize >= (unsigned) reserve_size) { + found = TRUE; + break; + } + /* From now on we can't get contiguous memory! */ + contiguous = FALSE; + /* Recompute size to reserve */ + reserve_size = CEIL (allocate_size, g_my_regionsize); + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + } + /* Search failed? */ + if (! found) + goto sbrk_exit; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + /* Try to reserve this */ + base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size, + MEM_RESERVE, PAGE_NOACCESS); + if (! base_reserved) { + int rc = GetLastError (); + if (rc != ERROR_INVALID_ADDRESS) + goto sbrk_exit; + } + /* A null pointer signals (hopefully) a race condition with another thread. */ + /* In this case, we try again. */ + } while (! base_reserved); + /* Check returned pointer for consistency */ + if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); +#ifdef TRACE + printf ("Reserve %p %d\n", base_reserved, reserve_size); +#endif + /* Did we get contiguous memory? */ + if (contiguous) { + long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated; + /* Adjust allocation size */ + allocate_size -= start_size; + /* Adjust the regions allocation top */ + g_last->top_allocated = g_last->top_committed; + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + /* Append the new region to the list */ + if (! region_list_append (&g_last, base_reserved, reserve_size)) + goto sbrk_exit; + /* Didn't we get contiguous memory? */ + if (! contiguous) { + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + } + } + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < commit_size && commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + commit_size; + } + } + /* Adjust the regions allocation top */ + g_last->top_allocated = (char *) g_last->top_allocated + allocate_size; + result = (char *) g_last->top_allocated - size; + /* Deallocation requested? */ + } else if (size < 0) { + long deallocate_size = - size; + /* As long as we have a region to release */ + while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) { + /* Get the size to release */ + long release_size = g_last->reserve_size; + /* Get the base address */ + void *base_reserved = (char *) g_last->top_reserved - release_size; + /* Assert preconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); + assert (0 < release_size && release_size % g_regionsize == 0); { + /* Release this */ + int rc = VirtualFree (base_reserved, 0, + MEM_RELEASE); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Release %p %d\n", base_reserved, release_size); +#endif + } + /* Adjust deallocation size */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved; + /* Remove the old region from the list */ + if (! region_list_remove (&g_last)) + goto sbrk_exit; + } { + /* Compute the size to decommit */ + long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size); + if (to_decommit >= g_my_pagesize) { + /* Compute the size to decommit */ + long decommit_size = FLOOR (to_decommit, g_my_pagesize); + /* Compute the base address */ + void *base_committed = (char *) g_last->top_committed - decommit_size; + /* Assert preconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); + assert (0 < decommit_size && decommit_size % g_pagesize == 0); { + /* Decommit this */ + int rc = VirtualFree ((char *) base_committed, decommit_size, + MEM_DECOMMIT); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Decommit %p %d\n", base_committed, decommit_size); +#endif + } + /* Adjust deallocation size and regions commit and allocate top */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed; + g_last->top_committed = base_committed; + g_last->top_allocated = base_committed; + } + } + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size; + /* Check for underflow */ + if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated || + g_last->top_allocated > g_last->top_committed) { + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size; + goto sbrk_exit; + } + result = g_last->top_allocated; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + +sbrk_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return result; +} + +/* mmap for windows */ +static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { + static long g_pagesize; + static long g_regionsize; +#ifdef TRACE + printf ("mmap %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Allocate this */ + ptr = VirtualAlloc (ptr, size, + MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); + if (! ptr) { + ptr = (void *) MORECORE_FAILURE; + goto mmap_exit; + } + /* Assert postconditions */ + assert ((unsigned) ptr % g_regionsize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", ptr, size); +#endif +mmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return ptr; +} + +/* munmap for windows */ +static long munmap (void *ptr, long size) { + static long g_pagesize; + static long g_regionsize; + int rc = MUNMAP_FAILURE; +#ifdef TRACE + printf ("munmap %p %d\n", ptr, size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Free this */ + if (! VirtualFree (ptr, 0, + MEM_RELEASE)) + goto munmap_exit; + rc = 0; +#ifdef TRACE + printf ("Release %p %d\n", ptr, size); +#endif +munmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return rc; +} + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed) { + MEMORY_BASIC_INFORMATION memory_info; + memory_info.BaseAddress = 0; + *free = *reserved = *committed = 0; + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + switch (memory_info.State) { + case MEM_FREE: + *free += memory_info.RegionSize; + break; + case MEM_RESERVE: + *reserved += memory_info.RegionSize; + break; + case MEM_COMMIT: + *committed += memory_info.RegionSize; + break; + } + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + } +} + +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user) { + if (whole) { + __int64 creation64, exit64, kernel64, user64; + int rc = GetProcessTimes (GetCurrentProcess (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } else { + __int64 creation64, exit64, kernel64, user64; + int rc = GetThreadTimes (GetCurrentThread (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } +} + +#endif /* WIN32 */ + +/* + +History: + + V2.7.0 + * new WIN32 sbrk, mmap, munmap, lock code from . + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: use memmove when regions may overlap. + * Collect all cases in malloc requiring system memory into sYSMALLOc + * Use mmap as backup to sbrk, if available; fold these mmap-related + operations into others. + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Adjust request2size to fit with MALLOC_FAILURE_ACTION. + * Include errno.h to support default failure action. + * Further improve WIN32 'sbrk()' emulation's 'findRegion()' routine + to avoid infinite loop when allocating initial memory larger + than RESERVED_SIZE and/or subsequent memory larger than + NEXT_SIZE. Thanks to Andreas Mueller + for finding this one. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp b/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp new file mode 100644 index 00000000..c9c04b30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsOS2VACLegacy.cpp @@ -0,0 +1,753 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla.org code. + * + * The Initial Developer of the Original Code is + * innotek GmbH. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * innotek GmbH / Knut St. Osmundsen + * + * 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 module contains wrappers for a handful of XPCOM methods which someone + * have been so kind as to link their plugins against. This module will only + * provide the minimum of what necessary to make legacy plugins work with + * the GCC based mozilla. Luckily this only means the IBM oji JAVA plugins. + * + * Actually, I haven't seen npoji6 calling any of these yet. + */ + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** @group Visual Age for C++ v3.6.5 target (OS/2). */ +/* @{ */ +/** Indicate Visual Age for C++ v3.6.5 target */ +#define VFT_VAC365 1 +/** VFTable/Interface Calling Convention for Win32. */ +#define VFTCALL _Optlink +/** First Entry which VAC uses. */ +#define VFTFIRST_DECL unsigned uFirst[2] +#define VFTFIRST_VAL() {0, 0}, +/** This deltas which VAC uses. */ +#define VFTDELTA_DECL(n) unsigned uDelta##n +#define VFTDELTA_VAL() 0, +/** @} */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "nscore.h" +#include "nsIServiceManagerUtils.h" + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +#ifndef __cplusplus +typedef struct nsID +{ + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +} nsID, nsCID, nsIID; +#define REFNSIID const nsIID * + +typedef PRUint32 nsrefcnt; +#endif + + +/** + * nsISupports vftable. + */ +typedef struct vftable_nsISupports +{ + VFTFIRST_DECL; + nsresult (*VFTCALL QueryInterface)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(QueryInterface); + nsrefcnt (*VFTCALL AddRef)(void *pvThis); + VFTDELTA_DECL(AddRef); + nsrefcnt (*VFTCALL Release)(void *pvThis); + VFTDELTA_DECL(Release); +} VFTnsISupports; + +/** + * nsGetServiceByCID::nsCOMPtr_helper vftable. + */ +typedef struct vftable_nsGetServiceByCID_nsCOMPtr_helper +{ + VFTFIRST_DECL; + /* virtual nsresult operator()( const nsIID&, void** ) const; */ + nsresult (*VFTCALL __operator_paratheses)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(__operator_paratheses); + void * (*VFTCALL __destructor)(void *pvThis, unsigned __dtorFlags, unsigned __vtt); + VFTDELTA_DECL(__destructor); +} VFTnsGetServiceByCID_nsCOMPtr_helper; + +/** + * nsQueryInterface::nsCOMPtr_helper vftable. + */ +typedef struct vftable_nsQueryInterface_nsCOMPtr_helper +{ + VFTFIRST_DECL; + nsresult (*VFTCALL __operator_paratheses)(void *pvThis, REFNSIID aIID, void** aInstancePtr); + VFTDELTA_DECL(__operator_paratheses); +} VFTnsQueryInterface_nsCOMPtr_helper; + + + + +/** + * nsISupport object. + */ +typedef struct obj_nsISupports +{ + VFTnsISupports *pVFT; +} obj_nsISupports; + +/** + * nsCOMPtr_base object. + */ +typedef struct obj_nsCOMPtr_base +{ + obj_nsISupports *mRawPtr; +} obj_nsCOMPtr_base; + +/** + * nsGetServiceByCID_nsCOMPtr_helper object. + */ +typedef struct obj_nsGetServiceByCID_nsCOMPtr_helper +{ + VFTnsGetServiceByCID_nsCOMPtr_helper *pVFT; /* ?? */ + nsID *mCID; /* const nsCID& */ + void *mServiceManager;/* nsCOMPtr */ + nsresult *mErrorPtr; +} obj_nsGetServiceByCID_nsCOMPtr_helper; + +/** + * nsQueryInterface_nsCOMPtr_helper object. + */ +typedef struct obj_nsQueryInterface_nsCOMPtr_helper +{ + VFTnsQueryInterface_nsCOMPtr_helper *pVFT; /* ?? */ + obj_nsISupports *mRawPtr; /* const nsCID& */ + nsresult *mErrorPtr; +} obj_nsQueryInterface_nsCOMPtr_helper; + + + + +/** + * nsCOMPtr_base::~nsCOMPtr_base() + * + * @remark This guys doing the oji plugin have been very unfortunate to link in this + * without any similar new operator. The object is thus created in the plugin + * but freed by xpcom.dll. As the plugin and mozilla have different CRTs this + * is a good way of asking for trouble. But, they guys've been lucky, the VAC + * CRT might just handle this ok. + * However, we cannot perform this delete as we have no VAC CRT around, and + * hence we will leak this object. + * ---- + * assembly: + public __dt__13nsCOMPtr_baseFv +__dt__13nsCOMPtr_baseFv proc + push ebp + mov ebp,esp + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; __dtorFlags + +; 63 if ( mRawPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax],0h + je @BLBL4 + +; 64 NSCAP_RELEASE(this, mRawPtr); + mov ecx,[ebp+08h]; this + mov ecx,[ecx] + mov ecx,[ecx] + mov eax,[ebp+08h]; this + mov eax,[eax] + add eax,[ecx+01ch] + mov ecx,[ebp+08h]; this + mov ecx,[ecx] + mov ecx,[ecx] + call dword ptr [ecx+018h] +@BLBL4: + +; 65 } + test byte ptr [ebp+0ch],01h; __dtorFlags + je @BLBL6 + mov eax,[ebp+08h]; this + call __dl__FPv +@BLBL6: + mov eax,[ebp+08h]; this + add esp,08h + pop ebp + ret +__dt__13nsCOMPtr_baseFv endp +*/ +extern "C" void * VFTCALL __dt__13nsCOMPtr_baseFv(void *pvThis, unsigned __dtorFlags) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base*)pvThis; +//asm("int $3"); + if (pThis->mRawPtr) + { + /* NSCAP_RELEASE(this, mRawPtr); */ + pThis->mRawPtr->pVFT->Release((char*)pThis->mRawPtr + pThis->mRawPtr->pVFT->uDeltaRelease); + } + + /* + * Delete the object... + * (As memtioned before we'll rather leak this.) + */ + #if 0 + if (!(__dtorFlags & 1)) + __dl__FPv(this) + #endif + + return pvThis; +} + +/** workaround for _Optlink bug.. */ +extern "C" void * VFTCALL _dt__13nsCOMPtr_baseFv(void *pvThis, unsigned __dtorFlags) +{ + return __dt__13nsCOMPtr_baseFv(pvThis, __dtorFlags); +} + + + +/** + * + * ----- + * assembly: +; 92 nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const + align 010h + + public __cl__17nsGetServiceByCIDCFRC4nsIDPPv +__cl__17nsGetServiceByCIDCFRC4nsIDPPv proc + push ebp + mov ebp,esp + sub esp,014h + push ebx + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; aIID + mov [ebp+010h],ecx; aInstancePtr + +; 94 nsresult status = NS_ERROR_FAILURE; + mov dword ptr [ebp-04h],080004005h; status + +; 95 if ( mServiceManager ) { + mov eax,[ebp+08h]; this + add eax,08h + call __opP13nsDerivedSafeXT17nsIServiceManager___8nsCOMPtrXT17nsIServiceManager_CFv + test eax,eax + je @BLBL13 + +; 96 status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + mov eax,[ebp+08h]; this + add eax,08h + call __rf__8nsCOMPtrXT17nsIServiceManager_CFv + mov [ebp-08h],eax; __212 + mov eax,[ebp+010h]; aInstancePtr + push eax + mov ecx,[ebp+0ch]; aIID + mov edx,[ebp+08h]; this + mov edx,[edx+04h] + mov ebx,[ebp-08h]; __212 + mov ebx,[ebx] + mov eax,[ebp-08h]; __212 + add eax,[ebx+024h] + sub esp,0ch + mov ebx,[ebp-08h]; __212 + mov ebx,[ebx] + call dword ptr [ebx+020h] + add esp,010h + mov [ebp-04h],eax; status + +; 97 } else { + jmp @BLBL14 + align 010h +@BLBL13: + +; 95 if ( mServiceManager ) { + +; 98 nsCOMPtr mgr; + lea eax,[ebp-0ch]; mgr + call __ct__8nsCOMPtrXT17nsIServiceManager_Fv + +; 99 NS_GetServiceManager(getter_AddRefs(mgr)); + lea edx,[ebp-0ch]; mgr + lea eax,[ebp-010h]; __216 + call getter_AddRefs__FR8nsCOMPtrXT17nsIServiceManager_ + sub esp,04h + lea eax,[ebp-010h]; __216 + sub esp,04h + call __opPP17nsIServiceManager__15nsGetterAddRefsXT17nsIServiceManager_Fv + add esp,08h + call NS_GetServiceManager + mov edx,02h + lea eax,[ebp-010h]; __216 + call __dt__15nsGetterAddRefsXT17nsIServiceManager_Fv + +; 100 if (mgr) + lea eax,[ebp-0ch]; mgr + call __opP13nsDerivedSafeXT17nsIServiceManager___8nsCOMPtrXT17nsIServiceManager_CFv + test eax,eax + je @BLBL15 + +; 101 status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + lea eax,[ebp-0ch]; mgr + call __rf__8nsCOMPtrXT17nsIServiceManager_CFv + mov [ebp-014h],eax; __217 + mov eax,[ebp+010h]; aInstancePtr + push eax + mov ecx,[ebp+0ch]; aIID + mov edx,[ebp+08h]; this + mov edx,[edx+04h] + mov ebx,[ebp-014h]; __217 + mov ebx,[ebx] + mov eax,[ebp-014h]; __217 + add eax,[ebx+024h] + sub esp,0ch + mov ebx,[ebp-014h]; __217 + mov ebx,[ebx] + call dword ptr [ebx+020h] + add esp,010h + mov [ebp-04h],eax; status +@BLBL15: + +; 102 } + mov edx,02h + lea eax,[ebp-0ch]; mgr + call __dt__8nsCOMPtrXT17nsIServiceManager_Fv +@BLBL14: + +; 103 if ( NS_FAILED(status) ) + test byte ptr [ebp-01h],080h; status + je @BLBL16 + +; 104 *aInstancePtr = 0; + mov eax,[ebp+010h]; aInstancePtr + mov dword ptr [eax],0h +@BLBL16: + +; 106 if ( mErrorPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+0ch],0h + je @BLBL17 + +; 107 *mErrorPtr = status; + mov eax,[ebp+08h]; this + mov eax,[eax+0ch] + mov ebx,[ebp-04h]; status + mov [eax],ebx +@BLBL17: + +; 108 return status; + mov eax,[ebp-04h]; status + add esp,08h + pop ebx + mov esp,ebp + pop ebp + ret +__cl__17nsGetServiceByCIDCFRC4nsIDPPv endp + + * ----- + * C++ Code: +nsresult +nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + } + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + */ +extern "C" nsresult VFTCALL GSBC_COM__operator_paratheses(void *pvThis, REFNSIID aIID, void** aInstancePtr) +{ + obj_nsGetServiceByCID_nsCOMPtr_helper *pThis = (obj_nsGetServiceByCID_nsCOMPtr_helper *)pvThis; + nsresult status = NS_ERROR_FAILURE; +//asm("int $3"); + + /* For convenience we don't use mServiceManager here because it's a wrapped object. + * We ASSUME that there is only one service manager floating around.... + */ + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(*pThis->mCID, aIID, (void**)aInstancePtr); + + if (NS_FAILED(status)) + *aInstancePtr = 0; + + if (pThis->mErrorPtr) + *pThis->mErrorPtr = status; + return status; +} + +/** + * Just a destructor. + * ----- + * assembly: +; 59 virtual ~nsGetServiceByCID() {}; + align 010h + +__dt__17nsGetServiceByCIDFv proc + push ebp + mov ebp,esp + sub esp,08h + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; __dtorFlags + mov [ebp+010h],ecx; __vtt + mov eax,[ebp+08h]; this + mov dword ptr [eax],offset FLAT:__vft17nsGetServiceByCID15nsCOMPtr_helper + mov edx,02h + mov eax,[ebp+08h]; this + add eax,08h + call __dt__8nsCOMPtrXT17nsIServiceManager_Fv + test byte ptr [ebp+0ch],01h; __dtorFlags + je @BLBL24 + mov eax,[ebp+08h]; this + call __dl__FPv +@BLBL24: + mov eax,[ebp+08h]; this + add esp,08h + pop ebp + ret +__dt__17nsGetServiceByCIDFv endp + */ +extern "C" void * VFTCALL GSBC_COM__destructor(void *pvThis, unsigned __dtorFlags, unsigned __vtt) +{ + obj_nsGetServiceByCID_nsCOMPtr_helper *pThis = (obj_nsGetServiceByCID_nsCOMPtr_helper *)pvThis; +//asm("int $3"); + + /* + * Because previously mentioned issues with VAC heaps, we'll + * not do anything in here. + * (We will then skip destruction of all parents and such, but + * I don't think that will hurt anyone.) + */ + __dtorFlags = __dtorFlags; + __vtt = __vtt; + return pThis; +} + + +/** + * VFT for nsGetServiceByCID::nsCOMPtr_helper or something like that. + * It's just implementing an operator() and the destructor. + * + * @remark We need to skip an underscore to get the name right. + * ---- + * assembly: +__vft17nsGetServiceByCID15nsCOMPtr_helper dd 0 + db 0h,0h,0h,0h + dd offset FLAT:__cl__17nsGetServiceByCIDCFRC4nsIDPPv + db 0h,0h,0h,0h + dd offset FLAT:__dt__17nsGetServiceByCIDFv + db 0h,0h,0h,0h + */ +extern const VFTnsGetServiceByCID_nsCOMPtr_helper _vft17nsGetServiceByCID15nsCOMPtr_helper = +{ + VFTFIRST_VAL() + GSBC_COM__operator_paratheses, VFTDELTA_VAL() + GSBC_COM__destructor, VFTDELTA_VAL() +}; + + + +/** + * + * ----- + * assembly +; 42 nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + align 010h + + public __cl__16nsQueryInterfaceCFRC4nsIDPPv +__cl__16nsQueryInterfaceCFRC4nsIDPPv proc + push ebp + mov ebp,esp + sub esp,08h + push ebx + sub esp,0ch + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; aIID + mov [ebp+010h],ecx; answer + +; 45 if ( mRawPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+04h],0h + je @BLBL1 + +; 46 { +; 47 status = mRawPtr->QueryInterface(aIID, answer); + mov ecx,[ebp+010h]; answer + mov edx,[ebp+0ch]; aIID + mov ebx,[ebp+08h]; this + mov ebx,[ebx+04h] + mov ebx,[ebx] + mov eax,[ebp+08h]; this + mov eax,[eax+04h] + add eax,[ebx+0ch] + mov ebx,[ebp+08h]; this + mov ebx,[ebx+04h] + mov ebx,[ebx] + call dword ptr [ebx+08h] + mov [ebp-04h],eax; status + +; 48 #ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS +; 49 NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +; 50 #endif +; 51 } + jmp @BLBL2 + align 010h +@BLBL1: + +; 45 if ( mRawPtr ) + +; 53 status = NS_ERROR_NULL_POINTER; + mov dword ptr [ebp-04h],080004003h; status +@BLBL2: + +; 55 if ( mErrorPtr ) + mov eax,[ebp+08h]; this + cmp dword ptr [eax+08h],0h + je @BLBL3 + +; 56 *mErrorPtr = status; + mov eax,[ebp+08h]; this + mov eax,[eax+08h] + mov ebx,[ebp-04h]; status + mov [eax],ebx +@BLBL3: + +; 57 return status; + mov eax,[ebp-04h]; status + add esp,0ch + pop ebx + mov esp,ebp + pop ebp + ret +__cl__16nsQueryInterfaceCFRC4nsIDPPv endp + + * ----- + * C++ Code: +nsresult +nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + */ +extern "C" nsresult VFTCALL QI_COM__operator_paratheses(void *pvThis, REFNSIID aIID, void** aInstancePtr) +{ + obj_nsQueryInterface_nsCOMPtr_helper *pThis = (obj_nsQueryInterface_nsCOMPtr_helper *)pvThis; + nsresult status = NS_ERROR_NULL_POINTER; +//asm("int $3"); + + if (pThis->mRawPtr) + { + status = pThis->mRawPtr->pVFT->QueryInterface(pThis->mRawPtr, aIID, aInstancePtr); + /* don't care about warnings, do we? */ + } + + if (pThis->mErrorPtr) + *pThis->mErrorPtr = status; + return status; +} + + + +/** + * VFT for nsQueryInterface::nsCOMPtr_helper or something like that. + * No destructor, only an operator(). + * + * @remark We need to skip an underscore to get the name right. + * ----- + * assembly: +__vft16nsQueryInterface15nsCOMPtr_helper dd 0 + db 0h,0h,0h,0h + dd offset FLAT:__cl__16nsQueryInterfaceCFRC4nsIDPPv + db 0h,0h,0h,0h + */ +extern const VFTnsQueryInterface_nsCOMPtr_helper _vft16nsQueryInterface15nsCOMPtr_helper = +{ + VFTFIRST_VAL() + QI_COM__operator_paratheses, VFTDELTA_VAL() +}; + +/** + * + * ----- + * C++ Code: +void +assign_assuming_AddRef( nsISupports* newPtr ) +{ + / * + |AddRef()|ing the new value (before entering this function) before + |Release()|ing the old lets us safely ignore the self-assignment case. + We must, however, be careful only to |Release()| _after_ doing the + assignment, in case the |Release()| leads to our _own_ destruction, + which would, in turn, cause an incorrect second |Release()| of our old + pointer. Thank for discovering this. + * / + nsISupports* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); +} + */ +extern "C" void VFTCALL assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports(void *pvThis, obj_nsISupports *newPtr) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base *)pvThis; + obj_nsISupports *oldPtr; + + oldPtr = pThis->mRawPtr; + pThis->mRawPtr = newPtr; + if (oldPtr) + { + /* NSCAP_RELEASE(this, oldPtr); */ + pThis->mRawPtr->pVFT->Release(oldPtr + oldPtr->pVFT->uDeltaRelease); + } +} + + + + +/** + * + * ----- + * Assembly: +; 77 nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + align 010h + + public assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID +assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID proc + push ebp + mov ebp,esp + sub esp,08h + push ebx + sub esp,0ch + mov [ebp+08h],eax; this + mov [ebp+0ch],edx; helper + mov [ebp+010h],ecx; iid + +; 80 if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + lea ecx,[ebp-04h]; newRawPtr + mov edx,[ebp+010h]; iid + mov ebx,[ebp+0ch]; helper + mov ebx,[ebx] + mov eax,[ebp+0ch]; helper + add eax,[ebx+0ch] + mov ebx,[ebp+0ch]; helper + mov ebx,[ebx] + call dword ptr [ebx+08h] + test eax,080000000h + je @BLBL8 + +; 81 newRawPtr = 0; + mov dword ptr [ebp-04h],0h; newRawPtr +@BLBL8: + +; 82 assign_assuming_AddRef(newRawPtr); + mov edx,[ebp-04h]; newRawPtr + mov eax,[ebp+08h]; this + call assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports + add esp,0ch + pop ebx + mov esp,ebp + pop ebp + ret +assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID endp + + * ----- + * C Code: +void +nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + */ +extern "C" void VFTCALL assign_from_helper__13nsCOMPtr_baseFRC15nsCOMPtr_helperRC4nsID( + void *pvThis, void * helper, REFNSIID iid) +{ + obj_nsCOMPtr_base *pThis = (obj_nsCOMPtr_base *)pvThis; + obj_nsISupports* newRawPtr = NULL; + nsresult status = NS_ERROR_FAILURE; +//asm("int $3"); + + /* this may or may not be correct but the layout is the same. */ + obj_nsQueryInterface_nsCOMPtr_helper * pHelper = (obj_nsQueryInterface_nsCOMPtr_helper*)helper; + + /* if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) */ + status = pHelper->pVFT->__operator_paratheses((char*)pHelper + pHelper->pVFT->uDelta__operator_paratheses, + iid, (void**)&newRawPtr); + if (NS_FAILED(status)) + newRawPtr = 0; + + /* assign_assuming_AddRef(newRawPtr); */ + assign_assuming_AddRef__13nsCOMPtr_baseFP11nsISupports(pThis, newRawPtr); +} + + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp b/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp new file mode 100644 index 00000000..ca9a76e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsStringAPI.cpp @@ -0,0 +1,261 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsString.h" +#include "nsCharTraits.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" +#include "nsNativeCharsetUtils.h" + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsStringContainer) >= sizeof(nsString), + "nsStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsString object + new (&aContainer) nsString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer) +{ + // call the nsString dtor + NS_REINTERPRET_CAST(nsString *, &aContainer)->~nsString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_StringGetData(const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsAString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData(const nsAString &aStr) +{ + return ToNewUnicode(aStr); +} + +NS_STRINGAPI(nsresult) +NS_StringSetData(nsAString &aStr, const PRUnichar *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringSetDataRange(nsAString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsCStringContainer) >= sizeof(nsCString), + "nsCStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsCString object + new (&aContainer) nsCString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer) +{ + // call the nsCString dtor + NS_REINTERPRET_CAST(nsCString *, &aContainer)->~nsCString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_CStringGetData(const nsACString &aStr, const char **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsACString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(char *) +NS_CStringCloneData(const nsACString &aStr) +{ + return ToNewCString(aStr); +} + +NS_STRINGAPI(nsresult) +NS_CStringSetData(nsACString &aStr, const char *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange(nsACString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSrc, + nsCStringEncoding aSrcEncoding, + nsAString &aDest) +{ + switch (aSrcEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + CopyASCIItoUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF8toUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyNativeToUnicode(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSrc, + nsCStringEncoding aDestEncoding, + nsACString &aDest) +{ + switch (aDestEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + LossyCopyUTF16toASCII(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF16toUTF8(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyUnicodeToNative(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h new file mode 100644 index 00000000..4e60c74e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOM.h @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsXPCOM_h__ +#define nsXPCOM_h__ + +#include "nscore.h" +#include "nsXPCOMCID.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_InitXPCOM2 VBoxNsxpNS_InitXPCOM2 +#define NS_ShutdownXPCOM VBoxNsxpNS_ShutdownXPCOM +#define NS_NewNativeLocalFile VBoxNsxpNS_NewNativeLocalFile +#define NS_GetServiceManager VBoxNsxpNS_GetServiceManager +#define NS_GetComponentManager VBoxNsxpNS_GetComponentManager +#define NS_GetComponentRegistrar VBoxNsxpNS_GetComponentRegistrar +#define NS_GetDebug VBoxNsxpNS_GetDebug +#define NS_GetMemoryManager VBoxNsxpNS_GetMemoryManager +#define NS_GetTraceRefcnt VBoxNsxpNS_GetTraceRefcnt +#define NS_NewLocalFile VBoxNsxpNS_NewLocalFile +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class nsAString; +class nsACString; + +class nsIComponentManager; +class nsIComponentRegistrar; +class nsIServiceManager; +class nsIFile; +class nsILocalFile; +class nsIDirectoryServiceProvider; +class nsIMemory; +class nsIDebug; +class nsITraceRefcnt; + +/** + * Initialises XPCOM. You must call this method before proceeding + * to use xpcom. The one exception is that you may call + * NS_NewLocalFile to create a nsIFile. + * + * @status FROZEN + * + * @note Use NS_NewLocalFile or NS_NewNativeLocalFile + * to create the file object you supply as the bin directory path in this + * call. The function may be safely called before the rest of XPCOM or + * embedding has been initialised. + * + * @param result The service manager. You may pass null. + * + * @param binDirectory The directory containing the component + * registry and runtime libraries; + * or use nsnull to use the working + * directory. + * + * @param appFileLocationProvider The object to be used by Gecko that specifies + * to Gecko where to find profiles, the component + * registry preferences and so on; or use + * nsnull for the default behaviour. + * + * @see NS_NewLocalFile + * @see nsILocalFile + * @see nsIDirectoryServiceProvider + * + * @return NS_OK for success; + * NS_ERROR_NOT_INITIALIZED if static globals were not initialied, which + * can happen if XPCOM is reloaded, but did not completly shutdown. + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider); +/** + * Shutdown XPCOM. You must call this method after you are finished + * using xpcom. + * + * @status FROZEN + * + * @param servMgr The service manager which was returned by NS_InitXPCOM2. + * This will release servMgr. You may pass null. + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_ShutdownXPCOM(nsIServiceManager* servMgr); + + +/** + * Public Method to access to the service manager. + * + * @status FROZEN + * @param result Interface pointer to the service manager + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result); + +/** + * Public Method to access to the component manager. + * + * @status FROZEN + * @param result Interface pointer to the service + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result); + +/** + * Public Method to access to the component registration manager. + * + * @status FROZEN + * @param result Interface pointer to the service + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result); + +/** + * Public Method to access to the memory manager. See nsIMemory + * + * @status FROZEN + * @param result Interface pointer to the memory manager + * + * @return NS_OK for success; + * other error codes indicate a failure during initialisation. + * + */ +extern "C" NS_COM nsresult +NS_GetMemoryManager(nsIMemory* *result); + +/** + * Public Method to create an instance of a nsILocalFile. This function + * may be called prior to NS_InitXPCOM2. + * + * @status FROZEN + * + * @param path + * A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). + * |NS_NewNativeLocalFile|'s path must be in the + * filesystem charset. + * @param followLinks + * This attribute will determine if the nsLocalFile will auto + * resolve symbolic links. By default, this value will be false + * on all non unix systems. On unix, this attribute is effectively + * a noop. + * @param result Interface pointer to a new instance of an nsILocalFile + * + * @return NS_OK for success; + * other error codes indicate a failure. + */ + +extern "C" NS_COM nsresult +NS_NewLocalFile(const nsAString &path, + PRBool followLinks, + nsILocalFile* *result); + +extern "C" NS_COM nsresult +NS_NewNativeLocalFile(const nsACString &path, + PRBool followLinks, + nsILocalFile* *result); + + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result); + +extern "C" NS_COM nsresult +NS_GetTraceRefcnt(nsITraceRefcnt* *result); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h new file mode 100644 index 00000000..d5bd039c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOMCID.h @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsXPCOMCID_h__ +#define nsXPCOMCID_h__ + +/** + * XPCOM Directory Service Contract ID + * The directory service provides ways to obtain file system locations. The + * directory service is a singleton. + * + * This contract supports the nsIDirectoryService and the nsIProperties + * interfaces. + * + */ +#define NS_DIRECTORY_SERVICE_CONTRACTID "@mozilla.org/file/directory_service;1" + +/** + * XPCOM File + * The file abstraction provides ways to obtain and access files and + * directories located on the local system. + * + * This contract supports the nsIFile interface and the nsILocalFile interface. + * This contract may also support platform specific interfaces such as + * nsILocalFileMac on platforms where additional interfaces are required. + * + */ +#define NS_LOCAL_FILE_CONTRACTID "@mozilla.org/file/local;1" + +/** + * XPCOM Category Manager Contract ID + * The contract supports the nsICategoryManager interface. The + * category manager is a singleton. + */ +#define NS_CATEGORYMANAGER_CONTRACTID "@mozilla.org/categorymanager;1" + +/** + * XPCOM Properties Object Contract ID + * Simple mapping object which supports the nsIProperties interface. + */ +#define NS_PROPERTIES_CONTRACTID "@mozilla.org/properties;1" + +/** + * XPCOM Array Object ContractID + * Simple array implementation which supports the nsIArray and + * nsIMutableArray interfaces. + */ +#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1" + +/** + * The following are the CIDs and Contract IDs of the nsISupports wrappers for + * primative types. + */ +#define NS_SUPPORTS_ID_CID \ +{ 0xacf8dc40, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_ID_CONTRACTID "@mozilla.org/supports-id;1" + +#define NS_SUPPORTS_CSTRING_CID \ +{ 0xacf8dc41, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_CSTRING_CONTRACTID "@mozilla.org/supports-cstring;1" + +#define NS_SUPPORTS_STRING_CID \ +{ 0xacf8dc42, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_STRING_CONTRACTID "@mozilla.org/supports-string;1" + +#define NS_SUPPORTS_PRBOOL_CID \ +{ 0xacf8dc43, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRBOOL_CONTRACTID "@mozilla.org/supports-PRBool;1" + +#define NS_SUPPORTS_PRUINT8_CID \ +{ 0xacf8dc44, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT8_CONTRACTID "@mozilla.org/supports-PRUint8;1" + +#define NS_SUPPORTS_PRUINT16_CID \ +{ 0xacf8dc46, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT16_CONTRACTID "@mozilla.org/supports-PRUint16;1" + +#define NS_SUPPORTS_PRUINT32_CID \ +{ 0xacf8dc47, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT32_CONTRACTID "@mozilla.org/supports-PRUint32;1" + +#define NS_SUPPORTS_PRUINT64_CID \ +{ 0xacf8dc48, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRUINT64_CONTRACTID "@mozilla.org/supports-PRUint64;1" + +#define NS_SUPPORTS_PRTIME_CID \ +{ 0xacf8dc49, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRTIME_CONTRACTID "@mozilla.org/supports-PRTime;1" + +#define NS_SUPPORTS_CHAR_CID \ +{ 0xacf8dc4a, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_CHAR_CONTRACTID "@mozilla.org/supports-char;1" + +#define NS_SUPPORTS_PRINT16_CID \ +{ 0xacf8dc4b, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT16_CONTRACTID "@mozilla.org/supports-PRInt16;1" + +#define NS_SUPPORTS_PRINT32_CID \ +{ 0xacf8dc4c, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT32_CONTRACTID "@mozilla.org/supports-PRInt32;1" + +#define NS_SUPPORTS_PRINT64_CID \ +{ 0xacf8dc4d, 0x4a25, 0x11d3, \ +{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } +#define NS_SUPPORTS_PRINT64_CONTRACTID "@mozilla.org/supports-PRInt64;1" + +#define NS_SUPPORTS_FLOAT_CID \ +{ 0xcbf86870, 0x4ac0, 0x11d3, \ +{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_FLOAT_CONTRACTID "@mozilla.org/supports-float;1" + +#define NS_SUPPORTS_DOUBLE_CID \ +{ 0xcbf86871, 0x4ac0, 0x11d3, \ +{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_DOUBLE_CONTRACTID "@mozilla.org/supports-double;1" + +#define NS_SUPPORTS_VOID_CID \ +{ 0xaf10f3e0, 0x568d, 0x11d3, \ +{ 0xba, 0xf8, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } } +#define NS_SUPPORTS_VOID_CONTRACTID "@mozilla.org/supports-void;1" + +#define NS_SUPPORTS_INTERFACE_POINTER_CID \ +{ 0xA99FEBBA, 0x1DD1, 0x11B2, \ +{ 0xA9, 0x43, 0xB0, 0x23, 0x34, 0xA6, 0xD0, 0x83 } } +#define NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID "@mozilla.org/supports-interface-pointer;1" + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h b/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h new file mode 100644 index 00000000..cd526ba3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPCOMPrivate.h @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 et cindent: */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsXPComPrivate_h__ +#define nsXPComPrivate_h__ + +#include "nscore.h" +#include "nsXPCOM.h" + +class nsStringContainer; +class nsCStringContainer; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_GetFrozenFunctions VBoxNsxpNS_GetFrozenFunctions +#define NS_RegisterXPCOMExitRoutine VBoxNsxpNS_RegisterXPCOMExitRoutine +#define NS_UnregisterXPCOMExitRoutine VBoxNsxpNS_UnregisterXPCOMExitRoutine +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * Private Method to register an exit routine. This method + * allows you to setup a callback that will be called from + * the NS_ShutdownXPCOM function after all services and + * components have gone away. + * + * This API is for the exclusive use of the xpcom glue library. + * + * Note that these APIs are NOT threadsafe and must be called on the + * main thread. + * + * @status FROZEN + * @param exitRoutine pointer to user defined callback function + * of type XPCOMExitRoutine. + * @param priority higher priorities are called before lower + * priorities. + * + * @return NS_OK for success; + * other error codes indicate a failure. + * + */ +typedef NS_CALLBACK(XPCOMExitRoutine)(void); + +extern "C" NS_COM nsresult +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority); + +extern "C" NS_COM nsresult +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine); + + +// PUBLIC +typedef nsresult (* InitFunc)(nsIServiceManager* *result, nsIFile* binDirectory, nsIDirectoryServiceProvider* appFileLocationProvider); +typedef nsresult (* ShutdownFunc)(nsIServiceManager* servMgr); +typedef nsresult (* GetServiceManagerFunc)(nsIServiceManager* *result); +typedef nsresult (* GetComponentManagerFunc)(nsIComponentManager* *result); +typedef nsresult (* GetComponentRegistrarFunc)(nsIComponentRegistrar* *result); +typedef nsresult (* GetMemoryManagerFunc)(nsIMemory* *result); +typedef nsresult (* NewLocalFileFunc)(const nsAString &path, PRBool followLinks, nsILocalFile* *result); +typedef nsresult (* NewNativeLocalFileFunc)(const nsACString &path, PRBool followLinks, nsILocalFile* *result); + +typedef nsresult (* GetDebugFunc)(nsIDebug* *result); +typedef nsresult (* GetTraceRefcntFunc)(nsITraceRefcnt* *result); + +typedef nsresult (* StringContainerInitFunc)(nsStringContainer&); +typedef void (* StringContainerFinishFunc)(nsStringContainer&); +typedef PRUint32 (* StringGetDataFunc)(const nsAString&, const PRUnichar**, PRBool*); +typedef PRUnichar* (* StringCloneDataFunc)(const nsAString&); +typedef nsresult (* StringSetDataFunc)(nsAString&, const PRUnichar*, PRUint32); +typedef nsresult (* StringSetDataRangeFunc)(nsAString&, PRUint32, PRUint32, const PRUnichar*, PRUint32); +typedef nsresult (* StringCopyFunc)(nsAString &, const nsAString &); + +typedef nsresult (* CStringContainerInitFunc)(nsCStringContainer&); +typedef void (* CStringContainerFinishFunc)(nsCStringContainer&); +typedef PRUint32 (* CStringGetDataFunc)(const nsACString&, const char**, PRBool*); +typedef char* (* CStringCloneDataFunc)(const nsACString&); +typedef nsresult (* CStringSetDataFunc)(nsACString&, const char*, PRUint32); +typedef nsresult (* CStringSetDataRangeFunc)(nsACString&, PRUint32, PRUint32, const char*, PRUint32); +typedef nsresult (* CStringCopyFunc)(nsACString &, const nsACString &); + +typedef nsresult (* CStringToUTF16)(const nsACString &, PRUint32, const nsAString &); +typedef nsresult (* UTF16ToCString)(const nsAString &, PRUint32, const nsACString &); + +// PRIVATE +typedef nsresult (* RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine, PRUint32 priority); +typedef nsresult (* UnregisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine); + +typedef struct XPCOMFunctions{ + PRUint32 version; + PRUint32 size; + + InitFunc init; + ShutdownFunc shutdown; + GetServiceManagerFunc getServiceManager; + GetComponentManagerFunc getComponentManager; + GetComponentRegistrarFunc getComponentRegistrar; + GetMemoryManagerFunc getMemoryManager; + NewLocalFileFunc newLocalFile; + NewNativeLocalFileFunc newNativeLocalFile; + + RegisterXPCOMExitRoutineFunc registerExitRoutine; + UnregisterXPCOMExitRoutineFunc unregisterExitRoutine; + + // Added for Mozilla 1.5 + GetDebugFunc getDebug; + GetTraceRefcntFunc getTraceRefcnt; + + // Added for Mozilla 1.7 + StringContainerInitFunc stringContainerInit; + StringContainerFinishFunc stringContainerFinish; + StringGetDataFunc stringGetData; + StringSetDataFunc stringSetData; + StringSetDataRangeFunc stringSetDataRange; + StringCopyFunc stringCopy; + CStringContainerInitFunc cstringContainerInit; + CStringContainerFinishFunc cstringContainerFinish; + CStringGetDataFunc cstringGetData; + CStringSetDataFunc cstringSetData; + CStringSetDataRangeFunc cstringSetDataRange; + CStringCopyFunc cstringCopy; + CStringToUTF16 cstringToUTF16; + UTF16ToCString utf16ToCString; + StringCloneDataFunc stringCloneData; + CStringCloneDataFunc cstringCloneData; + +} XPCOMFunctions; + +typedef nsresult (PR_CALLBACK *GetFrozenFunctionsFunc)(XPCOMFunctions *entryPoints, const char* libraryPath); +extern "C" NS_COM nsresult +NS_GetFrozenFunctions(XPCOMFunctions *entryPoints, const char* libraryPath); + +// think hard before changing this +#define XPCOM_GLUE_VERSION 1 + + +/* XPCOM Specific Defines + * + * XPCOM_DLL - name of the loadable xpcom library on disk. + * XPCOM_SEARCH_KEY - name of the environment variable that can be + * modified to include additional search paths. + * GRE_CONF_NAME - Name of the GRE Configuration file + */ + +#ifdef XPCOM_DLL_BASE +#define XPCOM_DLL XPCOM_DLL_BASE MOZ_DLL_SUFFIX +#endif + +#if defined(XP_WIN32) || defined(XP_OS2) + +#define XPCOM_SEARCH_KEY "PATH" +#define GRE_CONF_NAME "gre.config" +#define GRE_WIN_REG_LOC "Software\\mozilla.org\\GRE\\" +#ifndef XPCOM_DLL +#define XPCOM_DLL "xpcom"MOZ_DLL_SUFFIX +#endif + +#elif defined(XP_BEOS) + +#define XPCOM_SEARCH_KEY "ADDON_PATH" +#define GRE_CONF_NAME ".gre.config" +#define GRE_CONF_PATH "/boot/home/config/settings/GRE/gre.conf" +#ifndef XPCOM_DLL +#define XPCOM_DLL "libxpcom"MOZ_DLL_SUFFIX +#endif + +#else // Unix + +#ifndef XPCOM_DLL +#define XPCOM_DLL "libxpcom"MOZ_DLL_SUFFIX +#endif + +// you have to love apple.. +#ifdef XP_MACOSX +#define XPCOM_SEARCH_KEY "DYLD_LIBRARY_PATH" +#else +#define XPCOM_SEARCH_KEY "LD_LIBRARY_PATH" +#endif + +#define GRE_CONF_NAME ".gre.config" +#define GRE_CONF_PATH "/etc/gre.conf" +#define GRE_CONF_DIR "/etc/gre.d/" +#endif + +#if defined(XP_WIN) || defined(XP_OS2) + #define XPCOM_FILE_PATH_SEPARATOR "\\" + #define XPCOM_ENV_PATH_SEPARATOR ";" +#elif defined(XP_UNIX) || defined(XP_BEOS) + #define XPCOM_FILE_PATH_SEPARATOR "/" + #define XPCOM_ENV_PATH_SEPARATOR ":" +#else + #error need_to_define_your_file_path_separator_and_illegal_characters +#endif + +#endif + + diff --git a/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp b/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp new file mode 100644 index 00000000..65d84b6b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp @@ -0,0 +1,1079 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nscore.h" +#include "prlink.h" +#include "nsCOMPtr.h" +#include "nsObserverList.h" +#include "nsObserverService.h" +#include "nsProperties.h" +#include "nsIProperties.h" +#include "nsPersistentProperties.h" +#include "nsScriptableInputStream.h" +#include "nsBinaryStream.h" +#include "nsStorageStream.h" + +#include "nsMemoryImpl.h" +#include "nsDebugImpl.h" +#include "nsTraceRefcntImpl.h" +#include "nsErrorService.h" +#include "nsByteBuffer.h" + +#include "nsSupportsArray.h" +#include "nsArray.h" +#include "nsSupportsPrimitives.h" +#include "nsConsoleService.h" +#include "nsExceptionService.h" + +#include "nsComponentManager.h" +#include "nsCategoryManagerUtils.h" +#include "nsIServiceManager.h" +#include "nsGenericFactory.h" + +#include "nsEventQueueService.h" +#include "nsEventQueue.h" +#ifdef VBOX +# include "nsEventQueueUtils.h" +# include "nsProxyRelease.h" +#endif /* VBOX */ + +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" // access to the impl of nsProxyObjectManager for the generic factory registration. + +#include "xptinfo.h" +#include "nsIInterfaceInfoManager.h" + +#include "nsTimerImpl.h" +#include "TimerThread.h" + +#include "nsThread.h" +#include "nsProcess.h" +#include "nsEnvironment.h" + +#include "nsEmptyEnumerator.h" + +#include "nsILocalFile.h" +#include "nsLocalFile.h" +#if defined(XP_UNIX) || defined(XP_OS2) +#include "nsNativeCharsetUtils.h" +#endif +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCategoryManager.h" +#include "nsICategoryManager.h" +#include "nsStringStream.h" +#include "nsMultiplexInputStream.h" + +#include "nsFastLoadService.h" + +#include "nsAtomService.h" +#include "nsAtomTable.h" +#include "nsTraceRefcnt.h" +#include "nsTimelineService.h" + +#include "nsVariant.h" + +#ifdef GC_LEAK_DETECTOR +#include "nsLeakDetector.h" +#endif +#include "nsRecyclingAllocator.h" + +#include "SpecialSystemDirectory.h" + +#include "ipcdclient.h" +#include "ipcService.h" +#include "ipcConfig.h" +#include "ipcCID.h" +#include "ipcLockService.h" +#include "ipcLockCID.h" +#include "tmTransactionService.h" +#include "ipcDConnectService.h" + +#include + +// Registry Factory creation function defined in nsRegistry.cpp +// We hook into this function locally to create and register the registry +// Since noone outside xpcom needs to know about this and nsRegistry.cpp +// does not have a local include file, we are putting this definition +// here rather than in nsIRegistry.h +extern nsresult NS_RegistryGetFactory(nsIFactory** aFactory); +extern nsresult NS_CategoryManagerGetFactory( nsIFactory** ); + +#ifdef DEBUG +extern void _FreeAutoLockStatics(); +#endif + +static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); +static NS_DEFINE_CID(kMemoryCID, NS_MEMORY_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsProcess) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEventQueueServiceImpl, Init) + +#define NS_ENVIRONMENT_CLASSNAME "Environment Service" + +#include "nsXPCOM.h" +// ds/nsISupportsPrimitives +#define NS_SUPPORTS_ID_CLASSNAME "Supports ID" +#define NS_SUPPORTS_CSTRING_CLASSNAME "Supports String" +#define NS_SUPPORTS_STRING_CLASSNAME "Supports WString" +#define NS_SUPPORTS_PRBOOL_CLASSNAME "Supports PRBool" +#define NS_SUPPORTS_PRUINT8_CLASSNAME "Supports PRUint8" +#define NS_SUPPORTS_PRUINT16_CLASSNAME "Supports PRUint16" +#define NS_SUPPORTS_PRUINT32_CLASSNAME "Supports PRUint32" +#define NS_SUPPORTS_PRUINT64_CLASSNAME "Supports PRUint64" +#define NS_SUPPORTS_PRTIME_CLASSNAME "Supports PRTime" +#define NS_SUPPORTS_CHAR_CLASSNAME "Supports Char" +#define NS_SUPPORTS_PRINT16_CLASSNAME "Supports PRInt16" +#define NS_SUPPORTS_PRINT32_CLASSNAME "Supports PRInt32" +#define NS_SUPPORTS_PRINT64_CLASSNAME "Supports PRInt64" +#define NS_SUPPORTS_FLOAT_CLASSNAME "Supports float" +#define NS_SUPPORTS_DOUBLE_CLASSNAME "Supports double" +#define NS_SUPPORTS_VOID_CLASSNAME "Supports void" +#define NS_SUPPORTS_INTERFACE_POINTER_CLASSNAME "Supports interface pointer" + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsIDImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsStringImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCStringImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRBoolImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint8Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint16Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint32Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRUint64Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRTimeImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsCharImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt16Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt32Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsPRInt64Impl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsFloatImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsDoubleImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsVoidImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSupportsInterfacePointerImpl) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsArray) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsConsoleService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAtomService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsExceptionService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimerImpl) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimerManager) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsBinaryOutputStream) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsBinaryInputStream) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsStorageStream) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsVariant) + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsRecyclingAllocatorImpl) + +#ifdef MOZ_TIMELINE +NS_GENERIC_FACTORY_CONSTRUCTOR(nsTimelineService) +#endif + +static NS_METHOD +nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, + const nsIID& aIID, + void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); + + nsCOMPtr iim(dont_AddRef(XPTI_GetInterfaceInfoManager())); + if (!iim) { + return NS_ERROR_FAILURE; + } + + return iim->QueryInterface(aIID, aInstancePtr); +} + + +PR_STATIC_CALLBACK(nsresult) +RegisterGenericFactory(nsIComponentRegistrar* registrar, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsIGenericFactory* fact; + rv = NS_NewGenericFactory(&fact, info); + if (NS_FAILED(rv)) return rv; + + rv = registrar->RegisterFactory(info->mCID, + info->mDescription, + info->mContractID, + fact); + NS_RELEASE(fact); + return rv; +} + +// In order to support the installer, we need +// to be told out of band if we should cause +// an autoregister. If the file ".autoreg" exists in the binary +// directory, we check its timestamp against the timestamp of the +// compreg.dat file. If the .autoreg file is newer, we autoregister. +static PRBool CheckUpdateFile() +{ + nsresult rv; + nsCOMPtr directoryService; + nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(directoryService)); + + if (!directoryService) + return PR_FALSE; + + nsCOMPtr file; + rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(file)); + + if (NS_FAILED(rv)) { + NS_WARNING("Getting NS_XPCOM_CURRENT_PROCESS_DIR failed"); + return PR_FALSE; + } + + file->AppendNative(nsDependentCString(".autoreg")); + + PRBool exists; + file->Exists(&exists); + if (!exists) + return PR_FALSE; + + nsCOMPtr compregFile; + rv = directoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); + + + if (NS_FAILED(rv)) { + NS_WARNING("Getting NS_XPCOM_COMPONENT_REGISTRY_FILE failed"); + return PR_FALSE; + } + + // Don't need to check whether compreg exists; if it doesn't + // we won't even be here. + + PRInt64 compregModTime, autoregModTime; + compregFile->GetLastModifiedTime(&compregModTime); + file->GetLastModifiedTime(&autoregModTime); + + return LL_CMP(autoregModTime, >, compregModTime); +} + +#if 0 /// @todo later +NS_GENERIC_FACTORY_CONSTRUCTOR(ipcService) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcLockService, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR(tmTransactionService) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ipcDConnectService, Init) + +// enable this code to make the IPC DCONNECT service auto-start. +NS_METHOD +ipcDConnectServiceRegisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // + // add ipcService to the XPCOM startup category + // + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) { + nsXPIDLCString prevEntry; + catman->AddCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, "ipcDConnectService", + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE, PR_TRUE, + getter_Copies(prevEntry)); + } + return NS_OK; +} + +NS_METHOD +ipcDConnectServiceUnregisterProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + nsCOMPtr catman(do_GetService(NS_CATEGORYMANAGER_CONTRACTID)); + if (catman) + catman->DeleteCategoryEntry(NS_XPCOM_STARTUP_OBSERVER_ID, + IPC_DCONNECTSERVICE_CONTRACTID, PR_TRUE); + return NS_OK; +} +#endif + +nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL; +nsIProperties *gDirectoryService = NULL; +PRBool gXPCOMShuttingDown = PR_FALSE; + +// For each class that wishes to support nsIClassInfo, add a line like this +// NS_DECL_CLASSINFO(nsMyClass) + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + +#define COMPONENT_CI(NAME, Ctor, Class) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor, \ + NULL, NULL, NULL, NS_CI_INTERFACE_GETTER_NAME(Class), NULL, \ + &NS_CLASSINFO_NAME(Class) } + +static const nsModuleComponentInfo components[] = { + COMPONENT(MEMORY, nsMemoryImpl::Create), + COMPONENT(DEBUG, nsDebugImpl::Create), +#define NS_ERRORSERVICE_CLASSNAME NS_ERRORSERVICE_NAME + COMPONENT(ERRORSERVICE, nsErrorService::Create), + + COMPONENT(BYTEBUFFER, ByteBufferImpl::Create), + COMPONENT(SCRIPTABLEINPUTSTREAM, nsScriptableInputStream::Create), + COMPONENT(BINARYINPUTSTREAM, nsBinaryInputStreamConstructor), + COMPONENT(BINARYOUTPUTSTREAM, nsBinaryOutputStreamConstructor), + COMPONENT(STORAGESTREAM, nsStorageStreamConstructor), + +#define NS_PROPERTIES_CLASSNAME "Properties" + COMPONENT(PROPERTIES, nsProperties::Create), + +#define NS_PERSISTENTPROPERTIES_CID NS_IPERSISTENTPROPERTIES_CID /* sigh */ + COMPONENT(PERSISTENTPROPERTIES, nsPersistentProperties::Create), + + COMPONENT(SUPPORTSARRAY, nsSupportsArray::Create), + COMPONENT(ARRAY, nsArrayConstructor), + COMPONENT(CONSOLESERVICE, nsConsoleServiceConstructor), + COMPONENT(EXCEPTIONSERVICE, nsExceptionServiceConstructor), + COMPONENT(ATOMSERVICE, nsAtomServiceConstructor), +#ifdef MOZ_TIMELINE + COMPONENT(TIMELINESERVICE, nsTimelineServiceConstructor), +#endif + COMPONENT(OBSERVERSERVICE, nsObserverService::Create), + COMPONENT(GENERICFACTORY, nsGenericFactory::Create), + COMPONENT(EVENTQUEUESERVICE, nsEventQueueServiceImplConstructor), + COMPONENT(EVENTQUEUE, nsEventQueueImpl::Create), + COMPONENT(THREAD, nsThread::Create), + +#define NS_XPCOMPROXY_CID NS_PROXYEVENT_MANAGER_CID + COMPONENT(XPCOMPROXY, nsProxyObjectManager::Create), + + COMPONENT(TIMER, nsTimerImplConstructor), + COMPONENT(TIMERMANAGER, nsTimerManagerConstructor), + +#define COMPONENT_SUPPORTS(TYPE, Type) \ + COMPONENT(SUPPORTS_##TYPE, nsSupports##Type##ImplConstructor) + + COMPONENT_SUPPORTS(ID, ID), + COMPONENT_SUPPORTS(STRING, String), + COMPONENT_SUPPORTS(CSTRING, CString), + COMPONENT_SUPPORTS(PRBOOL, PRBool), + COMPONENT_SUPPORTS(PRUINT8, PRUint8), + COMPONENT_SUPPORTS(PRUINT16, PRUint16), + COMPONENT_SUPPORTS(PRUINT32, PRUint32), + COMPONENT_SUPPORTS(PRUINT64, PRUint64), + COMPONENT_SUPPORTS(PRTIME, PRTime), + COMPONENT_SUPPORTS(CHAR, Char), + COMPONENT_SUPPORTS(PRINT16, PRInt16), + COMPONENT_SUPPORTS(PRINT32, PRInt32), + COMPONENT_SUPPORTS(PRINT64, PRInt64), + COMPONENT_SUPPORTS(FLOAT, Float), + COMPONENT_SUPPORTS(DOUBLE, Double), + COMPONENT_SUPPORTS(VOID, Void), + COMPONENT_SUPPORTS(INTERFACE_POINTER, InterfacePointer), + +#undef COMPONENT_SUPPORTS +#define NS_LOCAL_FILE_CLASSNAME "Local File Specification" + COMPONENT(LOCAL_FILE, nsLocalFile::nsLocalFileConstructor), +#define NS_DIRECTORY_SERVICE_CLASSNAME "nsIFile Directory Service" + COMPONENT(DIRECTORY_SERVICE, nsDirectoryService::Create), + COMPONENT(PROCESS, nsProcessConstructor), + COMPONENT(ENVIRONMENT, nsEnvironment::Create), + + COMPONENT(STRINGINPUTSTREAM, nsStringInputStreamConstructor), + COMPONENT(MULTIPLEXINPUTSTREAM, nsMultiplexInputStreamConstructor), + + COMPONENT(FASTLOADSERVICE, nsFastLoadService::Create), + COMPONENT(VARIANT, nsVariantConstructor), + COMPONENT(INTERFACEINFOMANAGER_SERVICE, nsXPTIInterfaceInfoManagerGetSingleton), + + COMPONENT(RECYCLINGALLOCATOR, nsRecyclingAllocatorImplConstructor), + +#if 0 /// @todo later + { IPC_SERVICE_CLASSNAME, + IPC_SERVICE_CID, + IPC_SERVICE_CONTRACTID, + ipcServiceConstructor }, + /* + ipcServiceRegisterProc, + ipcServiceUnregisterProc }, + */ + // + // extensions go here: + // + { IPC_LOCKSERVICE_CLASSNAME, + IPC_LOCKSERVICE_CID, + IPC_LOCKSERVICE_CONTRACTID, + ipcLockServiceConstructor }, + { IPC_TRANSACTIONSERVICE_CLASSNAME, + IPC_TRANSACTIONSERVICE_CID, + IPC_TRANSACTIONSERVICE_CONTRACTID, + tmTransactionServiceConstructor }, + +#ifdef BUILD_DCONNECT + { IPC_DCONNECTSERVICE_CLASSNAME, + IPC_DCONNECTSERVICE_CID, + IPC_DCONNECTSERVICE_CONTRACTID, + ipcDConnectServiceConstructor, + ipcDConnectServiceRegisterProc, + ipcDConnectServiceUnregisterProc }, +#endif +#endif +}; + +#undef COMPONENT + +const int components_length = sizeof(components) / sizeof(components[0]); + +// gMemory will be freed during shutdown. +static nsIMemory* gMemory = nsnull; +nsresult NS_COM NS_GetMemoryManager(nsIMemory* *result) +{ + nsresult rv = NS_OK; + if (!gMemory) + { + rv = nsMemoryImpl::Create(nsnull, + NS_GET_IID(nsIMemory), + (void**)&gMemory); + } + NS_IF_ADDREF(*result = gMemory); + return rv; +} + +// gDebug will be freed during shutdown. +static nsIDebug* gDebug = nsnull; +nsresult NS_COM NS_GetDebug(nsIDebug** result) +{ + nsresult rv = NS_OK; + if (!gDebug) + { + rv = nsDebugImpl::Create(nsnull, + NS_GET_IID(nsIDebug), + (void**)&gDebug); + } + NS_IF_ADDREF(*result = gDebug); + return rv; +} + +#ifdef NS_BUILD_REFCNT_LOGGING +// gTraceRefcnt will be freed during shutdown. +static nsITraceRefcnt* gTraceRefcnt = nsnull; +#endif + +nsresult NS_COM NS_GetTraceRefcnt(nsITraceRefcnt** result) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + nsresult rv = NS_OK; + if (!gTraceRefcnt) + { + rv = nsTraceRefcntImpl::Create(nsnull, + NS_GET_IID(nsITraceRefcnt), + (void**)&gTraceRefcnt); + } + NS_IF_ADDREF(*result = gTraceRefcnt); + return rv; +#else + return NS_ERROR_NOT_INITIALIZED; +#endif +} + +nsresult NS_COM NS_InitXPCOM(nsIServiceManager* *result, + nsIFile* binDirectory) +{ + return NS_InitXPCOM2(result, binDirectory, nsnull); +} + +nsresult NS_COM NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider) +{ + nsresult rv = NS_OK; + + // We are not shutting down + gXPCOMShuttingDown = PR_FALSE; + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::Startup(); +#endif + + // Establish the main thread here. + rv = nsIThread::SetMainThread(); + if (NS_FAILED(rv)) return rv; + + // Set up the timer globals/timer thread + rv = nsTimerImpl::Startup(); + NS_ENSURE_SUCCESS(rv, rv); + + // Startup the memory manager + rv = nsMemoryImpl::Startup(); + if (NS_FAILED(rv)) return rv; + + // If the locale hasn't already been setup by our embedder, + // get us out of the "C" locale and into the system + if (strcmp(setlocale(LC_ALL, NULL), "C") == 0) + setlocale(LC_ALL, ""); + +#if defined(XP_UNIX) || defined(XP_OS2) + NS_StartupNativeCharsetUtils(); +#endif + NS_StartupLocalFile(); + + StartupSpecialSystemDirectory(); + + // Start the directory service so that the component manager init can use it. + rv = nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + (void**)&gDirectoryService); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr dirService = do_QueryInterface(gDirectoryService, &rv); + if (NS_FAILED(rv)) + return rv; + rv = dirService->Init(); + if (NS_FAILED(rv)) + return rv; + + // Create the Component/Service Manager + nsComponentManagerImpl *compMgr = NULL; + + if (nsComponentManagerImpl::gComponentManager == NULL) + { + compMgr = new nsComponentManagerImpl(); + if (compMgr == NULL) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(compMgr); + + nsCOMPtr xpcomLib; + + PRBool value; + if (binDirectory) + { + rv = binDirectory->IsDirectory(&value); + + if (NS_SUCCEEDED(rv) && value) { + gDirectoryService->Set(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, binDirectory); + binDirectory->Clone(getter_AddRefs(xpcomLib)); + } + } + else { + gDirectoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(xpcomLib)); + } + + if (xpcomLib) { + xpcomLib->AppendNative(nsDependentCString(XPCOM_DLL)); + gDirectoryService->Set(NS_XPCOM_LIBRARY_FILE, xpcomLib); + } + + if (appFileLocationProvider) { + rv = dirService->RegisterProvider(appFileLocationProvider); + if (NS_FAILED(rv)) return rv; + } + + rv = compMgr->Init(); + if (NS_FAILED(rv)) + { + NS_RELEASE(compMgr); + return rv; + } + + nsComponentManagerImpl::gComponentManager = compMgr; + + if (result) { + nsIServiceManager *serviceManager = + NS_STATIC_CAST(nsIServiceManager*, compMgr); + + NS_ADDREF(*result = serviceManager); + } + } + + nsCOMPtr memory; + NS_GetMemoryManager(getter_AddRefs(memory)); + // dougt - these calls will be moved into a new interface when nsIComponentManager is frozen. + rv = compMgr->RegisterService(kMemoryCID, memory); + if (NS_FAILED(rv)) return rv; + + rv = compMgr->RegisterService(kComponentManagerCID, NS_STATIC_CAST(nsIComponentManager*, compMgr)); + if (NS_FAILED(rv)) return rv; + +#ifdef GC_LEAK_DETECTOR + rv = NS_InitLeakDetector(); + if (NS_FAILED(rv)) return rv; +#endif + + // 2. Register the global services with the component manager so that + // clients can create new objects. + + // Category Manager + { + nsCOMPtr categoryManagerFactory; + if ( NS_FAILED(rv = NS_CategoryManagerGetFactory(getter_AddRefs(categoryManagerFactory))) ) + return rv; + + NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); + + rv = compMgr->RegisterFactory(kCategoryManagerCID, + NS_CATEGORYMANAGER_CLASSNAME, + NS_CATEGORYMANAGER_CONTRACTID, + categoryManagerFactory, + PR_TRUE); + if ( NS_FAILED(rv) ) return rv; + } + + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr registrar = do_QueryInterface( + NS_STATIC_CAST(nsIComponentManager*,compMgr), &rv); + if (registrar) { + for (int i = 0; i < components_length; i++) + RegisterGenericFactory(registrar, &components[i]); + } + rv = nsComponentManagerImpl::gComponentManager->ReadPersistentRegistry(); +#ifdef DEBUG + if (NS_FAILED(rv)) { + printf("No Persistent Registry Found.\n"); + } +#endif + +#if 0 /// @todo later + rv = IPC_Init(); + if (NS_FAILED(rv)) + return rv; +#endif + + if ( NS_FAILED(rv) || CheckUpdateFile()) { + // if we find no persistent registry, we will try to autoregister + // the default components directory. + nsComponentManagerImpl::gComponentManager->AutoRegister(nsnull); + + // If the application is using a GRE, then, + // auto register components in the GRE directory as well. + // + // The application indicates that it's using an GRE by + // returning a valid nsIFile when queried (via appFileLocProvider) + // for the NS_GRE_DIR atom as shown below + // + + if ( appFileLocationProvider ) { + nsCOMPtr greDir; + PRBool persistent = PR_TRUE; + + appFileLocationProvider->GetFile(NS_GRE_DIR, &persistent, getter_AddRefs(greDir)); + + if (greDir) { +#ifdef DEBUG_dougt + printf("start - Registering GRE components\n"); +#endif + rv = gDirectoryService->Get(NS_GRE_COMPONENT_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(greDir)); + if (NS_FAILED(rv)) { + NS_ERROR("Could not get GRE components directory!"); + return rv; + } + + // If the GRE contains any loaders, we want to know about it so that we can cause another + // autoregistration of the applications component directory. + int loaderCount = nsComponentManagerImpl::gComponentManager->GetLoaderCount(); + rv = nsComponentManagerImpl::gComponentManager->AutoRegister(greDir); + + if (loaderCount != nsComponentManagerImpl::gComponentManager->GetLoaderCount()) + nsComponentManagerImpl::gComponentManager->AutoRegisterNonNativeComponents(nsnull); + +#ifdef DEBUG_dougt + printf("end - Registering GRE components\n"); +#endif + if (NS_FAILED(rv)) { + NS_ERROR("Could not AutoRegister GRE components"); + return rv; + } + } + } + + // + // If additional component directories have been specified, then + // register them as well. + // + + nsCOMPtr dirList; + gDirectoryService->Get(NS_XPCOM_COMPONENT_DIR_LIST, + NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(dirList)); + if (dirList) { + PRBool hasMore; + while (NS_SUCCEEDED(dirList->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr elem; + dirList->GetNext(getter_AddRefs(elem)); + if (elem) { + nsCOMPtr dir = do_QueryInterface(elem); + if (dir) + nsComponentManagerImpl::gComponentManager->AutoRegister(dir); + + // XXX should we worry about new component loaders being + // XXX defined by this process? + } + } + } + + + // Make sure the compreg file's mod time is current. + nsCOMPtr compregFile; + rv = gDirectoryService->Get(NS_XPCOM_COMPONENT_REGISTRY_FILE, + NS_GET_IID(nsIFile), + getter_AddRefs(compregFile)); + compregFile->SetLastModifiedTime(PR_Now() / 1000); + } + + // Pay the cost at startup time of starting this singleton. + nsIInterfaceInfoManager* iim = XPTI_GetInterfaceInfoManager(); + NS_IF_RELEASE(iim); +#ifdef VBOX + // Must initialize the EventQueueService singleton before anyone is + // using it. The notification below creates a thread which races creating + // the EventQueueService creation otherwise, no matter what. + nsCOMPtr eventQ; + rv = NS_GetMainEventQ(getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) { + NS_ERROR("Could not create event queue for main thread"); + /* this is just a build-time hack, to reference NS_ProxyRelease */ + if (rv == 666) + NS_ProxyRelease(nsnull, nsnull); + return rv; + } +#endif /* VBOX */ + + // Notify observers of xpcom autoregistration start + NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_OBSERVER_ID, + nsnull, + NS_XPCOM_STARTUP_OBSERVER_ID); + + return NS_OK; +} + + +static nsVoidArray* gExitRoutines; + +static void CallExitRoutines() +{ + if (!gExitRoutines) + return; + + PRInt32 count = gExitRoutines->Count(); + for (PRInt32 i = 0; i < count; i++) { + XPCOMExitRoutine func = (XPCOMExitRoutine) gExitRoutines->ElementAt(i); + func(); + } + gExitRoutines->Clear(); + delete gExitRoutines; + gExitRoutines = nsnull; +} + +nsresult NS_COM +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority) +{ + // priority are not used right now. It will need to be implemented as more + // classes are moved into the glue library --dougt + if (!gExitRoutines) { + gExitRoutines = new nsVoidArray(); + if (!gExitRoutines) { + NS_WARNING("Failed to allocate gExitRoutines"); + return NS_ERROR_FAILURE; + } + } + + PRBool okay = gExitRoutines->AppendElement((void*)exitRoutine); + return okay ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult NS_COM +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) +{ + if (!gExitRoutines) + return NS_ERROR_FAILURE; + + PRBool okay = gExitRoutines->RemoveElement((void*)exitRoutine); + return okay ? NS_OK : NS_ERROR_FAILURE; +} + + +// +// NS_ShutdownXPCOM() +// +// The shutdown sequence for xpcom would be +// +// - Release the Global Service Manager +// - Release all service instances held by the global service manager +// - Release the Global Service Manager itself +// - Release the Component Manager +// - Release all factories cached by the Component Manager +// - Unload Libraries +// - Release Contractid Cache held by Component Manager +// - Release dll abstraction held by Component Manager +// - Release the Registry held by Component Manager +// - Finally, release the component manager itself +// +nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) +{ + + // Notify observers of xpcom shutting down + nsresult rv = NS_OK; + { + // Block it so that the COMPtr will get deleted before we hit + // servicemanager shutdown + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + (void) observerService->NotifyObservers(mgr, + NS_XPCOM_SHUTDOWN_OBSERVER_ID, + nsnull); + } + } + } + + // grab the event queue so that we can process events one last time before exiting + nsCOMPtr currentQ; + { + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + + if (eventQService) { + eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(currentQ)); + } + } + // XPCOM is officially in shutdown mode NOW + // Set this only after the observers have been notified as this + // will cause servicemanager to become inaccessible. + gXPCOMShuttingDown = PR_TRUE; + +#ifdef DEBUG_dougt + fprintf(stderr, "* * * * XPCOM shutdown. Access will be denied * * * * \n"); +#endif + +#if 0 /// @todo later + IPC_Shutdown(); +#endif + + // We may have AddRef'd for the caller of NS_InitXPCOM, so release it + // here again: + NS_IF_RELEASE(servMgr); + + // Shutdown global servicemanager + if (nsComponentManagerImpl::gComponentManager) { + nsComponentManagerImpl::gComponentManager->FreeServices(); + } + nsServiceManager::ShutdownGlobalServiceManager(nsnull); + + if (currentQ) { + currentQ->ProcessPendingEvents(); + currentQ = 0; + } + + nsProxyObjectManager::Shutdown(); + + // Release the directory service + NS_IF_RELEASE(gDirectoryService); + + // Shutdown nsLocalFile string conversion + NS_ShutdownLocalFile(); +#ifdef XP_UNIX + NS_ShutdownNativeCharsetUtils(); +#endif + + // Shutdown the timer thread and all timers that might still be alive before + // shutting down the component manager + nsTimerImpl::Shutdown(); + + CallExitRoutines(); + + // Shutdown xpcom. This will release all loaders and cause others holding + // a refcount to the component manager to release it. + if (nsComponentManagerImpl::gComponentManager) { + rv = (nsComponentManagerImpl::gComponentManager)->Shutdown(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Component Manager shutdown failed."); + } else + NS_WARNING("Component Manager was never created ..."); + + // Release our own singletons + // Do this _after_ shutting down the component manager, because the + // JS component loader will use XPConnect to call nsIModule::canUnload, + // and that will spin up the InterfaceInfoManager again -- bad mojo + XPTI_FreeInterfaceInfoManager(); + + // Finally, release the component manager last because it unloads the + // libraries: + if (nsComponentManagerImpl::gComponentManager) { + nsrefcnt cnt; + NS_RELEASE2(nsComponentManagerImpl::gComponentManager, cnt); + NS_WARN_IF_FALSE(cnt == 0, "Component Manager being held past XPCOM shutdown."); + } + nsComponentManagerImpl::gComponentManager = nsnull; + +#ifdef DEBUG + _FreeAutoLockStatics(); +#endif + + ShutdownSpecialSystemDirectory(); + + EmptyEnumeratorImpl::Shutdown(); + nsMemoryImpl::Shutdown(); + NS_IF_RELEASE(gMemory); + + nsThread::Shutdown(); + NS_PurgeAtomTable(); + + NS_IF_RELEASE(gDebug); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::DumpStatistics(); + nsTraceRefcntImpl::ResetStatistics(); + nsTraceRefcntImpl::Shutdown(); +#endif + +#ifdef GC_LEAK_DETECTOR + // Shutdown the Leak detector. + NS_ShutdownLeakDetector(); +#endif + + return NS_OK; +} + +#define GET_FUNC(_tag, _decl, _name) \ + functions->_tag = (_decl) PR_FindSymbol(xpcomLib, _name); \ + if (!functions->_tag) goto end + +nsresult NS_COM PR_CALLBACK +NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* libraryPath) +{ + if (!functions) + return NS_ERROR_OUT_OF_MEMORY; + + if (functions->version != XPCOM_GLUE_VERSION) + return NS_ERROR_FAILURE; + + PRLibrary *xpcomLib = PR_LoadLibrary(libraryPath); + if (!xpcomLib) + return NS_ERROR_FAILURE; + + nsresult rv = NS_ERROR_FAILURE; + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(init, InitFunc, "VBoxNsxpNS_InitXPCOM2"); + GET_FUNC(shutdown, ShutdownFunc, "VBoxNsxpNS_ShutdownXPCOM"); + GET_FUNC(getServiceManager, GetServiceManagerFunc, "VBoxNsxpNS_GetServiceManager"); + GET_FUNC(getComponentManager, GetComponentManagerFunc, "VBoxNsxpNS_GetComponentManager"); + GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "VBoxNsxpNS_GetComponentRegistrar"); + GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "VBoxNsxpNS_GetMemoryManager"); + GET_FUNC(newLocalFile, NewLocalFileFunc, "VBoxNsxpNS_NewLocalFile"); + GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "VBoxNsxpNS_NewNativeLocalFile"); + GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "VBoxNsxpNS_RegisterXPCOMExitRoutine"); + GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "VBoxNsxpNS_UnregisterXPCOMExitRoutine"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(init, InitFunc, "NS_InitXPCOM2"); + GET_FUNC(shutdown, ShutdownFunc, "NS_ShutdownXPCOM"); + GET_FUNC(getServiceManager, GetServiceManagerFunc, "NS_GetServiceManager"); + GET_FUNC(getComponentManager, GetComponentManagerFunc, "NS_GetComponentManager"); + GET_FUNC(getComponentRegistrar, GetComponentRegistrarFunc, "NS_GetComponentRegistrar"); + GET_FUNC(getMemoryManager, GetMemoryManagerFunc, "NS_GetMemoryManager"); + GET_FUNC(newLocalFile, NewLocalFileFunc, "NS_NewLocalFile"); + GET_FUNC(newNativeLocalFile, NewNativeLocalFileFunc, "NS_NewNativeLocalFile"); + GET_FUNC(registerExitRoutine, RegisterXPCOMExitRoutineFunc, "NS_RegisterXPCOMExitRoutine"); + GET_FUNC(unregisterExitRoutine, UnregisterXPCOMExitRoutineFunc, "NS_UnregisterXPCOMExitRoutine"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + + // these functions were added post 1.4 (need to check size of |functions|) + if (functions->size > offsetof(XPCOMFunctions, getTraceRefcnt)) { +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(getDebug, GetDebugFunc, "VBoxNsxpNS_GetDebug"); + GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "VBoxNsxpNS_GetTraceRefcnt"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(getDebug, GetDebugFunc, "NS_GetDebug"); + GET_FUNC(getTraceRefcnt, GetTraceRefcntFunc, "NS_GetTraceRefcnt"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + } + + // these functions were added post 1.6 (need to check size of |functions|) + if (functions->size > offsetof(XPCOMFunctions, cstringCloneData)) { +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + GET_FUNC(stringContainerInit, StringContainerInitFunc, "VBoxNsxpNS_StringContainerInit"); + GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "VBoxNsxpNS_StringContainerFinish"); + GET_FUNC(stringGetData, StringGetDataFunc, "VBoxNsxpNS_StringGetData"); + GET_FUNC(stringSetData, StringSetDataFunc, "VBoxNsxpNS_StringSetData"); + GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "VBoxNsxpNS_StringSetDataRange"); + GET_FUNC(stringCopy, StringCopyFunc, "VBoxNsxpNS_StringCopy"); + GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "VBoxNsxpNS_CStringContainerInit"); + GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "VBoxNsxpNS_CStringContainerFinish"); + GET_FUNC(cstringGetData, CStringGetDataFunc, "VBoxNsxpNS_CStringGetData"); + GET_FUNC(cstringSetData, CStringSetDataFunc, "VBoxNsxpNS_CStringSetData"); + GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "VBoxNsxpNS_CStringSetDataRange"); + GET_FUNC(cstringCopy, CStringCopyFunc, "VBoxNsxpNS_CStringCopy"); + GET_FUNC(cstringToUTF16, CStringToUTF16, "VBoxNsxpNS_CStringToUTF16"); + GET_FUNC(utf16ToCString, UTF16ToCString, "VBoxNsxpNS_UTF16ToCString"); + GET_FUNC(stringCloneData, StringCloneDataFunc, "VBoxNsxpNS_StringCloneData"); + GET_FUNC(cstringCloneData, CStringCloneDataFunc, "VBoxNsxpNS_CStringCloneData"); +#else /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + GET_FUNC(stringContainerInit, StringContainerInitFunc, "NS_StringContainerInit"); + GET_FUNC(stringContainerFinish, StringContainerFinishFunc, "NS_StringContainerFinish"); + GET_FUNC(stringGetData, StringGetDataFunc, "NS_StringGetData"); + GET_FUNC(stringSetData, StringSetDataFunc, "NS_StringSetData"); + GET_FUNC(stringSetDataRange, StringSetDataRangeFunc, "NS_StringSetDataRange"); + GET_FUNC(stringCopy, StringCopyFunc, "NS_StringCopy"); + GET_FUNC(cstringContainerInit, CStringContainerInitFunc, "NS_CStringContainerInit"); + GET_FUNC(cstringContainerFinish, CStringContainerFinishFunc, "NS_CStringContainerFinish"); + GET_FUNC(cstringGetData, CStringGetDataFunc, "NS_CStringGetData"); + GET_FUNC(cstringSetData, CStringSetDataFunc, "NS_CStringSetData"); + GET_FUNC(cstringSetDataRange, CStringSetDataRangeFunc, "NS_CStringSetDataRange"); + GET_FUNC(cstringCopy, CStringCopyFunc, "NS_CStringCopy"); + GET_FUNC(cstringToUTF16, CStringToUTF16, "NS_CStringToUTF16"); + GET_FUNC(utf16ToCString, UTF16ToCString, "NS_UTF16ToCString"); + GET_FUNC(stringCloneData, StringCloneDataFunc, "NS_StringCloneData"); + GET_FUNC(cstringCloneData, CStringCloneDataFunc, "NS_CStringCloneData"); +#endif /* !VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + } + + rv = NS_OK; +end: + PR_UnloadLibrary(xpcomLib); // the library is refcnt'ed above by the caller. + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/build/win32.order b/src/libs/xpcom18a4/xpcom/build/win32.order new file mode 100644 index 00000000..ce6856ba --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/win32.order @@ -0,0 +1,1514 @@ +??1nsCOMPtr_base@@QAE@XZ ; 33017395 +?ElementAt@nsVoidArray@@QBEPAXH@Z ; 14120786 +?AddRef@nsEventQueueServiceImpl@@UAGKXZ ; 13612685 +?Release@AtomImpl@@UAGKXZ ; 13067618 +?Initialize@nsStr@@SAXAAU1@W4eCharSize@@@Z ; 9860800 +?Reference@nsCWeakProxy@@QAEPAXXZ ; 9283082 +?Free@nsStr@@CAHAAU1@@Z ; 8492496 +?Destroy@nsStr@@SAXAAU1@@Z ; 8159980 +??1nsString@@UAE@XZ ; 7681847 +??0nsString@@QAE@XZ ; 7538998 +?GetWritableFragment@nsString@@MAEPAGAAU?$nsWritableFragment@G@@W4nsFragmentRequest@@I@Z ; 7387979 +?Initialize@nsStr@@SAXAAU1@PADIIW4eCharSize@@H@Z ; 7301440 +??1nsAutoString@@UAE@XZ ; 6828894 +??0nsAutoString@@QAE@XZ ; 6681318 +?normalize_forward@?$nsReadingIterator@G@@QAEXXZ ; 6469200 +?normalize_forward@?$nsWritingIterator@D@@QAEXXZ ; 4717355 +?StrTruncate@nsStr@@SAXAAU1@I@Z ; 4534497 +?assign_from_helper@nsCOMPtr_base@@QAEXABVnsCOMPtr_helper@@ABUnsID@@@Z ; 4516612 +??0nsHashKey@@IAE@XZ ; 4270805 +??1nsHashKey@@UAE@XZ ; 4268636 +??RnsQueryInterface@@UBEIABUnsID@@PAPAX@Z ; 4148520 +?SetLength@nsCString@@UAEXI@Z ; 4098410 +?Get@nsHashtable@@QAEPAXPAVnsHashKey@@@Z ; 3790063 +?GetFlatBufferHandle@nsLocalString@@UBEPBV?$nsBufferHandle@G@@XZ ; 3747888 +?BeginReading@nsACString@@QBEAAV?$nsReadingIterator@D@@AAV2@@Z ; 3649883 +?FindChar1@@YAHPBDIHGHH@Z ; 2533672 +?BeginWriting@nsACString@@QAEAAV?$nsWritingIterator@D@@AAV2@@Z ; 2226534 +?advance@?$nsWritingIterator@G@@QAEAAV1@H@Z ; 2049632 +?advance@?$nsReadingIterator@G@@QAEAAV1@H@Z ; 1995545 +?GetReadableFragment@nsAFlatCString@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 1948988 +?Count@nsSupportsArray@@UAGIPAI@Z ; 1839978 +?readable_distance@?$nsCharSourceTraits@V?$nsReadingIterator@G@@@@SAIABV?$nsReadingIterator@G@@0@Z ; 1802375 +?GetReadableFragment@nsCString@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 1763345 +??0nsQueryInterface@@QAE@PAVnsISupports@@PAI@Z ; 1655422 +?copy_string@@YAAAV?$nsWritingIterator@G@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 1487171 +?GetWritableFragment@nsAFlatString@@MAEPAGAAU?$nsWritableFragment@G@@W4nsFragmentRequest@@I@Z ; 1391163 +?advance@?$nsWritingIterator@D@@QAEAAV1@H@Z ; 1335661 +?Equals@nsAString@@QBEHABV1@@Z ; 1318787 +?move@?$nsCharTraits@G@@SAPAGPAGPBGI@Z ; 1315826 +?assign_with_AddRef@nsCOMPtr_base@@QAEXPAVnsISupports@@@Z ; 1259090 +?write@?$nsWritingIterator@G@@QAEIPBGI@Z ; 1243674 +?Get@nsSupportsHashtable@@QAEPAVnsISupports@@PAVnsHashKey@@@Z ; 1199544 +?GetUnicode@nsString@@QBEPBGXZ ; 1141413 +?StrAppend@nsStr@@SAXAAU1@ABU1@IH@Z ; 1102413 +?FindChar@nsString@@QBEHGHHH@Z ; 1090463 +?FindChar@nsStr@@SAHABU1@GHHH@Z ; 1090463 +?FindChar2@@YAHPBDIHGHH@Z ; 1056090 +?ElementAt@nsSupportsArray@@UAGPAVnsISupports@@I@Z ; 1055798 +?InsertElementAt@nsVoidArray@@QAEHPAXH@Z ; 926721 +?Compare2To2@@YAHPBD0IH@Z ; 920121 +?EnumerateForwards@nsSupportsArray@@UAGHP6AHPAVnsISupports@@PAX@Z1@Z ; 908730 +?strncasecmp@nsCRT@@SAHPBG0I@Z ; 896894 +?StrCompare@nsStr@@SAHABU1@0HH@Z ; 886450 +?Free@nsMemoryImpl@@UAGXPAX@Z ; 842646 +?Free@nsMemory@@SAXPAX@Z ; 832569 +?Distance@@YAIABV?$nsReadingIterator@G@@0@Z ; 801833 +?copy_string@@YAAAV?$CalculateLength@G@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 801833 +?Compare2To1@@YAHPBD0IH@Z ; 797802 +?Alloc@nsMemoryImpl@@UAGPAXI@Z ; 795063 +?Length@nsAFlatString@@UBEIXZ ; 789895 +?advance@?$nsReadingIterator@D@@QAEAAV1@H@Z ; 778072 +?copy_string@@YAAAV?$nsWritingIterator@D@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 738318 +?Alloc@nsMemory@@SAPAXI@Z ; 731916 +?write@?$nsWritingIterator@D@@QAEIPBDI@Z ; 724438 +?EqualsWithConversion@nsString@@QBEHABV1@HH@Z ; 680848 +?EqualsIgnoreCase@nsString@@QBEHABV1@@Z ; 680848 +?Length@nsAFlatCString@@UBEIXZ ; 674814 +?GetReadableFragment@nsSlidingSubstring@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 671287 +?do_AppendFromReadable@nsAString@@MAEXABV1@@Z ; 657779 +?Compare@@YAHABVnsAString@@0@Z ; 630913 +?do_AssignFromReadable@nsAString@@MAEXABV1@@Z ; 630139 +?CopyChars2To2@@YAXPADHPBDII@Z ; 615216 +?do_AppendFromReadable@nsACString@@MAEXABV1@@Z ; 584996 +?ObjectAt@nsDeque@@QBEPAXH@Z ; 568869 +?InsertElementAt@nsSupportsArray@@UAGHPAVnsISupports@@I@Z ; 548718 +?AssignFromReadable@nsACString@@IAEXABV1@@Z ; 534684 +??0nsLocalCString@@QAE@PBD@Z ; 525422 +?strlen@nsCRT@@SAIPBG@Z ; 517372 +?get@nsString@@UBEPBGXZ ; 500471 +?GrowCapacity@nsStr@@SAHAAU1@I@Z ; 493115 +?Realloc@nsStr@@CAHAAU1@I@Z ; 493115 +?Alloc@nsStr@@CAHAAU1@I@Z ; 493115 +?EnsureCapacity@nsStr@@SAHAAU1@I@Z ; 493115 +??0nsVoidArray@@QAE@XZ ; 490358 +?strncmp@nsCRT@@SAHPBGPBDI@Z ; 489334 +??1nsVoidArray@@UAE@XZ ; 481308 +??1nsCString@@UAE@XZ ; 478019 +?RemoveElementAt@nsVoidArray@@QAEHH@Z ; 473592 +?AppendElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 464186 +?AppendWithConversion@nsCString@@QAEXG@Z ; 452063 +??0nsCString@@QAE@XZ ; 449721 +?do_AppendFromElementPtr@nsACString@@MAEXPBD@Z ; 427640 +?SetArraySize@nsVoidArray@@IAEXH@Z ; 425906 +?get@nsPromiseFlatCString@@UBEPBDXZ ; 413903 +?Alloc@nsFixedSizeAllocator@@QAEPAXI@Z ; 411293 +??0nsPromiseFlatString@@IAE@ABVnsAString@@@Z ; 410015 +?Free@nsFixedSizeAllocator@@SAXPAXI@Z ; 401028 +?strcmp@nsCRT@@SAHPBG0@Z ; 400500 +??1nsPromiseFlatString@@UAE@XZ ; 398346 +??1nsCAutoString@@UAE@XZ ; 391273 +?GetFlatBufferHandle@nsCString@@MBEPBV?$nsBufferHandle@D@@XZ ; 385981 +?Push@nsDeque@@QAEAAV1@PAX@Z ; 367628 +?Equals@nsIDKey@@UBEHPBVnsHashKey@@@Z ; 358933 +?Clear@nsSupportsArray@@UAGIXZ ; 352217 +?AppendFromReadable@nsAString@@IAEXABV1@@Z ; 352181 +?strncasecmp@nsCRT@@SAHPBGPBDI@Z ; 330906 +?IsAsciiAlpha@nsCRT@@SAHG@Z ; 327047 +??0nsCAutoString@@QAE@XZ ; 311314 +?Clear@nsVoidArray@@QAEXXZ ; 287750 +?Compare1To1@@YAHPBD0IH@Z ; 276525 +?Length@nsSlidingSubstring@@UBEIXZ ; 264724 +?PopFront@nsDeque@@QAEPAXXZ ; 260861 +?AcquireNonOwningReference@Buffer@nsSharedBufferList@@QBEXXZ ; 256259 +?Distance@Position@nsSharedBufferList@@SAHABU12@0@Z ; 254042 +?DiscardUnreferencedPrefix@nsSlidingSharedBufferList@@QAEXPAVBuffer@nsSharedBufferList@@@Z ; 254040 +?ReleaseNonOwningReference@Buffer@nsSharedBufferList@@QBEXXZ ; 254040 +??1nsCStringKey@@UAE@XZ ; 253255 +?HashCode@nsCRT@@SAIPBDPAI@Z ; 251093 +?HashCode@nsCStringKey@@UBEIXZ ; 250679 +?NS_GetGlobalComponentManager@@YAIPAPAVnsIComponentManager@@@Z ; 250625 +??1nsAFlatString@@UAE@XZ ; 249908 +??0nsAFlatString@@QAE@XZ ; 243174 +?Equals@nsCStringKey@@UBEHPBVnsHashKey@@@Z ; 238528 +?IsAsciiSpace@nsCRT@@SAHG@Z ; 238314 +?CopyChars1To2@@YAXPADHPBDII@Z ; 237716 +??0nsLocalString@@QAE@PBGI@Z ; 236845 +?NS_NewAtom@@YAPAVnsIAtom@@ABVnsAString@@@Z ; 235384 +?Release@nsSupportsArray@@UAGKXZ ; 229149 +?GetParameterCount@nsProxyObjectCallInfo@@QBEIXZ ; 228843 +??0nsAutoVoidArray@@QAE@XZ ; 223605 +?do_AppendFromElementPtrLength@nsAString@@MAEXPBGI@Z ; 221664 +?AppendWithConversion@nsString@@QAEXPBDH@Z ; 216212 +?ChangeCase@nsStr@@SAXAAU1@H@Z ; 211594 +?length@?$nsCharTraits@G@@SAIPBG@Z ; 206064 +??0nsLocalString@@QAE@PBG@Z ; 205367 +?SetArrayOwner@nsVoidArray@@IAEXH@Z ; 202301 +?GetFactoryEntry@nsComponentManagerImpl@@IAEPAVnsFactoryEntry@@ABUnsID@@H@Z ; 198436 +?FindFactory@nsComponentManagerImpl@@UAGIABUnsID@@PAPAVnsIFactory@@@Z ; 198385 +?GetFactory@nsFactoryEntry@@QAEIPAPAVnsIFactory@@PAVnsComponentManagerImpl@@@Z ; 198384 +?CreateInstance@nsComponentManagerImpl@@UAGIABUnsID@@PAVnsISupports@@0PAPAX@Z ; 198351 +?ToLowerCase@nsString@@QAEXXZ ; 198180 +?Remove@nsHashtable@@QAEPAXPAVnsHashKey@@@Z ; 191685 +?ToString@AtomImpl@@UAGIAAVnsAString@@@Z ; 189337 +?First@nsAString@@QBEGXZ ; 189245 +?release_ownership_of_buffer_list@nsSlidingSubstring@@AAEXXZ ; 188763 +?IndexOf@nsVoidArray@@QBEHPAX@Z ; 175677 +?StartAssignmentByValue@nsXPIDLString@@AAEPAPAGXZ ; 173850 +?SetCapacity@nsString@@UAEXI@Z ; 170493 +?CopyChars2To1@@YAXPADHPBDII@Z ; 168065 +?Put@nsHashtable@@QAEPAXPAVnsHashKey@@PAX@Z ; 160536 +?DiscardPrefix@nsSlidingString@@QAEXABV?$nsReadingIterator@G@@@Z ; 159450 +?StrAssign@nsStr@@SAXAAU1@ABU1@IH@Z ; 154324 +?Trim@nsStr@@SAXAAU1@PBDHH@Z ; 154152 +?SetCapacity@nsCString@@UAEXI@Z ; 151535 +?GetGlobalServiceManager@nsServiceManager@@SAIPAPAVnsIServiceManager@@@Z ; 148522 +?GetService@nsServiceManagerImpl@@UAGIABUnsID@@0PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 146024 +?AddListener@nsServiceEntry@@QAEIPAVnsIShutdownListener@@@Z ; 146022 +?GetUnicode@AtomImpl@@UAGIPAPBG@Z ; 143965 +?Pop@nsDeque@@QAEPAXXZ ; 143309 +??RnsQueryReferent@@UBEIABUnsID@@PAPAX@Z ; 142474 +?normalize_backward@?$nsReadingIterator@G@@QAEXXZ ; 142302 +?QueryReferent@nsWeakReference@@UAGIABUnsID@@PAPAX@Z ; 142237 +?AddRef@nsStorageStream@@UAGKXZ ; 141846 +?Assign@nsACString@@QAEXPBD@Z ; 141606 +?FindCharInSet@nsStr@@SAHABU1@0HH@Z ; 138161 +?FindCharInSet@nsCString@@QBEHPBDH@Z ; 138161 +?CreateInstance@nsComponentManager@@SAIABUnsID@@PAVnsISupports@@0PAPAX@Z ; 137059 +??0nsCStringKey@@QAE@PBDHW4Ownership@0@@Z ; 136293 +??1nsXPIDLCString@@UAE@XZ ; 134911 +??0nsString@@QAE@ABV0@@Z ; 134194 +?do_AssignFromReadable@nsACString@@MAEXABV1@@Z ; 128929 +?ConvertCase1@@YAHPADIH@Z ; 128876 +?AssignWithConversion@nsCString@@QAEXPBGH@Z ; 122216 +?do_AppendFromElement@nsACString@@MAEXD@Z ; 120364 +?Write@FileImpl@@UAGIPBDIPAI@Z ; 120089 +?AssignWithConversion@nsCString@@QAEXABVnsString@@@Z ; 119962 +?AddRef@nsSupportsStringImpl@@UAGKXZ ; 118646 +??0nsCStringKey@@QAE@ABVnsCString@@@Z ; 117124 +?GetResolveState@xptiInterfaceInfo@@QBEEXZ ; 117066 +?AppendUnicodeTo@@YAXABV?$nsReadingIterator@G@@0AAVnsAString@@@Z ; 115792 +?AssignWithConversion@nsString@@QAEXPBD@Z ; 115695 +?Last@nsAString@@QBEGXZ ; 115018 +?ContractIDToClassID@nsComponentManagerImpl@@UAGIPBDPAUnsID@@@Z ; 112973 +?ToNewCString@nsCString@@QBEPADXZ ; 110413 +?LookupLowercasedKeyword@@YAHABVnsCString@@PAVnsHashtable@@@Z ; 110405 +?IsAsciiDigit@nsCRT@@SAHG@Z ; 107530 +?Remove@nsSupportsHashtable@@QAEHPAVnsHashKey@@PAPAVnsISupports@@@Z ; 106325 +??0nsAutoString@@QAE@ABVnsString@@@Z ; 103799 +?CompareWithConversion@nsString@@QBEHPBDHH@Z ; 102438 +?EqualsWithConversion@nsString@@QBEHPBDHH@Z ; 101441 +?Lookup@nsStaticCaseInsensitiveNameTable@@QAEHABVnsString@@@Z ; 101178 +?Trim@nsString@@QAEXPBDHHH@Z ; 100923 +?Release@nsWeakReference@@UAGKXZ ; 100809 +?GetReadableFragment@nsPromiseSubstring@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 98711 +?GetService@nsServiceManager@@SAIABUnsID@@0PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 97630 +?write@nsOutputStream@@QAEHPBXH@Z ; 96747 +?Init@nsXPTCVariant@@QAEXABUnsXPTCMiniVariant@@ABVnsXPTType@@E@Z ; 95698 +?acquire_ownership_of_buffer_list@nsSlidingString@@ABEXXZ ; 94592 +?ReleaseReference@nsSlidingSharedBufferList@@QAEXXZ ; 94590 +??1nsSlidingSubstring@@UAE@XZ ; 94580 +??0nsSlidingSubstring@@QAE@XZ ; 94173 +?RemoveElement@nsVoidArray@@QAEHPAX@Z ; 91746 +??RnsGetServiceByCID@@UBEIABUnsID@@PAPAX@Z ; 91521 +??0nsGetServiceByCID@@QAE@ABUnsID@@PAVnsISupports@@PAI@Z ; 91521 +?Release@nsEventQueueImpl@@UAGKXZ ; 87880 +?EqualsIgnoreCase@nsString@@QBEHPBDH@Z ; 86030 +?Init@NS_ConvertUTF8toUCS2@@IAEXPBDI@Z ; 85607 +?Rebind@nsSlidingSubstring@@QAEXABVnsSlidingString@@ABV?$nsReadingIterator@G@@1@Z ; 83943 +?do_AppendFromElementPtr@nsAString@@MAEXPBG@Z ; 83867 +??0nsSupportsArray@@QAE@XZ ; 83106 +?ConvertCase2@@YAHPADIH@Z ; 82718 +?DeleteArray@nsSupportsArray@@IAEXXZ ; 82548 +??1nsSupportsArray@@UAE@XZ ; 82548 +?QueryInterface@nsSupportsArray@@UAGIABUnsID@@PAPAX@Z ; 81918 +?Create@nsSupportsArray@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 81725 +?NS_NewISupportsArray@@YAIPAPAVnsISupportsArray@@@Z ; 81666 +?CopyChars1To1@@YAXPADHPBDII@Z ; 81524 +??_EnsSupportsArray@@UAEPAXI@Z ; 81168 +?GetMethodInfo@xptiInterfaceInfo@@UAGIGPAPBVnsXPTMethodInfo@@@Z ; 78229 +?Release@xptiInterfaceInfo@@UAGKXZ ; 76117 +?do_AssignFromElementPtr@nsAString@@MAEXPBG@Z ; 73811 +?copy_string@@YAAAPAGAAV?$nsReadingIterator@G@@ABV1@AAPAG@Z ; 71847 +?GetReadableFragment@nsPromiseCSubstring@@MBEPBDAAU?$nsReadableFragment@D@@W4nsFragmentRequest@@I@Z ; 71331 +?GetBuffer@ByteBufferImpl@@UBGPADXZ ; 71201 +?Read@ConverterInputStream@@UAGIPAGIIPAI@Z ; 70839 +?Read@nsPersistentProperties@@QAEHXZ ; 70367 +?do_AssignFromElementPtr@nsACString@@MAEXPBD@Z ; 62916 +?Length@nsPromiseCSubstring@@UBEIXZ ; 62793 +?CompareWithConversion@nsCString@@QBEHPBDHH@Z ; 62172 +??0NS_ConvertASCIItoUCS2@@QAE@PBD@Z ; 61750 +?CreateInstanceByContractID@nsComponentManagerImpl@@UAGIPBDPAVnsISupports@@ABUnsID@@PAPAX@Z ; 61075 +?CreateInstance@nsComponentManager@@SAIPBDPAVnsISupports@@ABUnsID@@PAPAX@Z ; 61075 +?Exit@nsAutoMonitor@@QAEXXZ ; 59293 +?Enter@nsAutoMonitor@@QAEXXZ ; 59293 +PL_GetEventOwner ; 55295 +?RefCountInInterfacePointers@nsProxyObjectCallInfo@@AAEXH@Z ; 55218 +?Clone@nsMemory@@SAPAXPBXI@Z ; 53069 +?Promises@nsAString@@UBEHABV1@@Z ; 52421 +?Promises@nsPromiseSubstring@@UBEHABVnsAString@@@Z ; 52287 +?ContractIDToClassID@nsComponentManager@@SAIPBDPAUnsID@@@Z ; 51898 +?GetStringValue@nsStaticCaseInsensitiveNameTable@@QAEABVnsCString@@H@Z ; 51863 +?CopyUnicodeTo@@YAXABV?$nsReadingIterator@G@@0AAVnsAString@@@Z ; 51424 +??RnsGetInterface@@UBEIABUnsID@@PAPAX@Z ; 51014 +?GetService@nsServiceManager@@SAIPBDABUnsID@@PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 50614 +?GetService@nsServiceManagerImpl@@UAGIPBDABUnsID@@PAPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 50608 +?GetElementAt@nsSupportsArray@@UAGIIPAPAVnsISupports@@@Z ; 50421 +??0nsCAutoString@@QAE@PBD@Z ; 50288 +?Release@nsGenericFactory@@UAGKXZ ; 48967 +?Release@nsLocalFile@@UAGKXZ ; 48924 +?CreateInstance@nsGenericFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 47807 +?ToNewUnicode@@YAPAGABVnsAString@@@Z ; 47476 +?Equals@nsSupportsArray@@UAGHPBVnsISupportsArray@@@Z ; 47394 +?QueryInterface@nsWeakReference@@UAGIABUnsID@@PAPAX@Z ; 47232 +?ToInteger@nsString@@QBEHPAHI@Z ; 46397 +??0nsGetServiceByContractID@@QAE@PBDPAVnsISupports@@PAI@Z ; 45960 +??RnsGetServiceByContractID@@UBEIABUnsID@@PAPAX@Z ; 45960 +?Reset@nsHashtable@@QAEXP6AHPAVnsHashKey@@PAX1@Z1@Z ; 45160 +?Reset@nsHashtable@@QAEXXZ ; 44779 +?strdup@nsCRT@@SAPAGPBG@Z ; 44542 +?strndup@nsCRT@@SAPAGPBGI@Z ; 44542 +PL_InitEvent ; 42216 +PL_DestroyEvent ; 42216 +?Release@nsProxyObject@@UAGKXZ ; 42053 +?HashCode@nsCRT@@SAIPBGPAI@Z ; 41515 +?MakeDirty@nsLocalFile@@AAEXXZ ; 40921 +?CompressSet@nsStr@@SAXAAU1@PBDHH@Z ; 40756 +?FindSubstr@nsStr@@SAHABU1@0HHH@Z ; 40557 +XPTC_InvokeByIndex ; 40446 +?QueryInterface@nsEventQueueImpl@@UAGIABUnsID@@PAPAX@Z ; 40010 +?Peek@nsDeque@@QAEPAXXZ ; 39695 +?ToUpper@nsCRT@@SAGG@Z ; 39657 +?CopyStrings@nsProxyObjectCallInfo@@AAEXH@Z ; 39492 +PL_DHashTableOperate ; 39446 +??0nsDeque@@QAE@PAVnsDequeFunctor@@@Z ; 38500 +?Empty@nsDeque@@QAEAAV1@XZ ; 38489 +??1nsDeque@@QAE@XZ ; 38489 +?Erase@nsDeque@@QAEAAV1@XZ ; 38489 +?GetSegmentCount@nsSegmentedBuffer@@QAEIXZ ; 38168 +?Release@nsProxyEventObject@@UAGKXZ ; 37461 +?ReplaceElementAt@nsVoidArray@@QAEHPAXH@Z ; 37379 +??0nsAutoString@@QAE@PBG@Z ; 35740 +PL_GetEvent ; 34422 +PL_HandleEvent ; 34415 +PL_PostEvent ; 34415 +?PostEvent@nsEventQueueImpl@@UAG?AW4PRStatus@@PAUPLEvent@@@Z ; 34353 +?strncmp@nsCRT@@SAHPBG0I@Z ; 34311 +?Cut@nsAString@@UAEXII@Z ; 33933 +?Release@nsThread@@UAGKXZ ; 32675 +?GetInstance@nsProxyObjectManager@@SAPAV1@XZ ; 31747 +?EqualsWithConversion@nsCString@@QBEHPBGHH@Z ; 31327 +?CompareWithConversion@nsCString@@QBEHPBGHH@Z ; 31327 +?GetRealObject@nsProxyObject@@QBEPAVnsISupports@@XZ ; 30180 +PL_DHashStringKey ; 29743 +?QueryInterface@nsEventQueueServiceImpl@@UAGIABUnsID@@PAPAX@Z ; 29645 +?GetReadSegment@nsPipe@@QAEIIPAPBDPAI@Z ; 29618 +??1nsXPIDLString@@UAE@XZ ; 29310 +?Release@nsProxyEventClass@@UAGKXZ ; 29259 +??0nsPromiseSubstring@@QAE@ABVnsAString@@II@Z ; 29232 +?Compact@nsSupportsArray@@UAGIXZ ; 28635 +?Mid@nsAString@@QBEIAAV1@II@Z ; 28616 +?AssignFromPromise@nsAString@@IAEXABV1@@Z ; 28510 +?get@nsAFlatString@@UBEPBGXZ ; 28400 +?Equals@nsACString@@QBEHABV1@@Z ; 28339 +?convertMiniVariantToVariant@nsProxyObject@@AAEIPAVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@PAPAUnsXPTCVariant@@PAE@Z ; 27609 +??_EnsProxyObjectCallInfo@@UAEPAXI@Z ; 27609 +?Post@nsProxyObject@@QAEIIPAVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@PAVnsIInterfaceInfo@@@Z ; 27609 +??1nsProxyObjectCallInfo@@UAE@XZ ; 27609 +?CallMethod@nsProxyEventObject@@UAGIGPBVnsXPTMethodInfo@@PAUnsXPTCMiniVariant@@@Z ; 27609 +??0nsProxyObjectCallInfo@@QAE@PAVnsProxyObject@@PAVnsXPTMethodInfo@@IPAUnsXPTCVariant@@IPAUPLEvent@@@Z ; 27609 +?Append@NS_ConvertUCS2toUTF8@@IAEXPBGI@Z ; 27265 +?ReplaceChar@nsString@@QAEXPBDG@Z ; 26980 +?CompressSet@nsString@@QAEXPBDGHH@Z ; 26980 +?CompressChars2@@YAHPADIPBD@Z ; 26980 +?CompressWhitespace@nsString@@QAEXHH@Z ; 26980 +?assign_assuming_AddRef@nsCOMPtr_base@@IAEXPAVnsISupports@@@Z ; 26695 +?do_AssignFromElement@nsAString@@MAEXG@Z ; 25781 +??0nsCAutoString@@QAE@ABVCBufDescriptor@@@Z ; 25669 +??0CBufDescriptor@@QAE@PADHIH@Z ; 25623 +?RemoveElementAt@nsSupportsArray@@UAGHI@Z ; 25489 +PL_IsQueueOnCurrentThread ; 25382 +?GetInterfaceInfo@nsProxyEventObject@@UAGIPAPAVnsIInterfaceInfo@@@Z ; 25038 +?Equals@nsACString@@QBEHPBD@Z ; 24972 +?ReadSegments@nsPipeInputStream@nsPipe@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 24934 +?Cut@nsACString@@UAEXII@Z ; 24343 +?RemoveElement@nsSupportsArray@@UAGHPBVnsISupports@@I@Z ; 24174 +?RemoveElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 24174 +??0nsPromiseCSubstring@@QAE@ABVnsACString@@II@Z ; 23764 +?Mid@nsACString@@QBEIAAV1@II@Z ; 23764 +?AssignFromPromise@nsACString@@IAEXABV1@@Z ; 23764 +?ToNewUnicode@nsString@@QBEPAGXZ ; 23688 +?Last@nsACString@@QBEDXZ ; 22996 +?AssignWithConversion@nsCString@@QAEXABVnsAString@@@Z ; 22923 +?IsQueueOnCurrentThread@nsEventQueueImpl@@UAGIPAH@Z ; 22307 +?AppendWithConversion@nsString@@QAEXD@Z ; 22276 +?Compare1To2@@YAHPBD0IH@Z ; 22272 +?GetIID@xptiInterfaceInfo@@UAGIPAPAUnsID@@@Z ; 21683 +?Find@nsString@@QBEHPBDHHH@Z ; 21620 +?AppendFromReadable@nsACString@@IAEXABV1@@Z ; 21546 +??0nsLocalCString@@QAE@PBDI@Z ; 21266 +??0nsAString@@QAE@XZ ; 20650 +?HashCode@nsProxyEventKey@@UBEIXZ ; 20409 +?QueryInterface@nsLocalFile@@UAGIABUnsID@@PAPAX@Z ; 19832 +?QueryElementAt@nsSupportsArray@@UAGIIABUnsID@@PAPAX@Z ; 19439 +?HashCode@nsStringKey@@UBEIXZ ; 19128 +??1nsStringKey@@UAE@XZ ; 18271 +??RnsCreateInstanceByContractID@@UBEIABUnsID@@PAPAX@Z ; 17842 +?GetTypelibGuts@xptiWorkingSet@@QAEPAVxptiTypelibGuts@@ABVxptiTypelib@@@Z ; 17499 +?GetInfoAtNoAddRef@xptiTypelibGuts@@QAEPAVxptiInterfaceInfo@@G@Z ; 17499 +?GetInfoForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAPAVnsIInterfaceInfo@@@Z ; 17441 +?GetIIDForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAPAUnsID@@@Z ; 17381 +?Find@nsString@@QBEHABV1@HHH@Z ; 17158 +?NS_NewAtom@@YAPAVnsIAtom@@PBG@Z ; 17124 +?Delete@nsStr@@SAXAAU1@II@Z ; 17080 +?QueryInterface@nsProxyEventObject@@UAGIABUnsID@@PAPAX@Z ; 17047 +?StripChars@nsStr@@SAXAAU1@PBD@Z ; 16392 +?StripChars@nsCString@@QAEXPBD@Z ; 16392 +?Equals@nsVoidKey@@UBEHPBVnsHashKey@@@Z ; 15797 +?StripChar@nsString@@QAEXGH@Z ; 15611 +?do_AppendFromElementPtrLength@nsACString@@MAEXPBDI@Z ; 15433 +?NS_NewAtom@@YAPAVnsIAtom@@PBD@Z ; 14915 +?strcasecmp@nsCRT@@SAHPBG0@Z ; 14605 +?GetNewOrUsedClass@nsProxyEventClass@@SAPAV1@ABUnsID@@@Z ; 14587 +?do_GetService@@YA?BVnsGetServiceByCID@@ABUnsID@@PAI@Z ; 14568 +??0nsProxyEventObject@@QAE@PAVnsIEventQueue@@HPAVnsISupports@@PAVnsProxyEventClass@@PAV0@@Z ; 14476 +??0nsProxyObject@@QAE@PAVnsIEventQueue@@HPAVnsISupports@@@Z ; 14476 +??1nsProxyEventObject@@UAE@XZ ; 14444 +??_EnsProxyObject@@UAEPAXI@Z ; 14444 +??_EnsProxyEventObject@@UAEPAXI@Z ; 14444 +??1nsProxyObject@@UAE@XZ ; 14444 +?ReleaseData@nsSimpleCharString@@IAEXXZ ; 14127 +??1?$nsSharedBufferHandle@G@@QAE@XZ ; 13784 +?CompressChars1@@YAHPADIPBD@Z ; 13776 +?CompressSet@nsCString@@QAEXPBDGHH@Z ; 13776 +?ReplaceChar@nsCString@@QAEXPBDG@Z ; 13776 +??0NS_ConvertUCS2toUTF8@@QAE@ABVnsAString@@@Z ; 13501 +??0nsCString@@QAE@ABVnsACString@@@Z ; 13490 +?Compact@nsVoidArray@@QAEXXZ ; 13069 +?ResolveAndStat@nsLocalFile@@AAEIH@Z ; 13042 +?Trim@nsCString@@QAEXPBDHHH@Z ; 12473 +?ToCString@nsString@@QBEPADPADII@Z ; 12467 +?Copy@nsXPIDLCString@@SAPADPBD@Z ; 12345 +?StripChars1@@YAHPADIPBD@Z ; 12243 +PL_ProcessPendingEvents ; 11979 +?copy_string@@YAAAV?$LossyConvertEncoding@GD@@AAV?$nsReadingIterator@G@@ABV2@AAV1@@Z ; 11800 +?ToNewCString@@YAPADABVnsAString@@@Z ; 11800 +?ToNewUTF8String@@YAPADABVnsAString@@@Z ; 11776 +?Release@nsProxyObjectManager@@UAGKXZ ; 11736 +??1nsCommonString@@UAE@XZ ; 11669 +?UnlinkBuffer@nsSharedBufferList@@QAEPAVBuffer@1@PAV21@@Z ; 11567 +?FindItem@nsAVLTree@@QBEPAXPAX@Z ; 11472 +?ReallocData@nsSimpleCharString@@IAEXI@Z ; 11366 +?ShiftCharsLeft@@YAXPADIII@Z ; 11222 +?GetYoungest@nsEventQueueImpl@@UAGIPAPAVnsIEventQueue@@@Z ; 10964 +?SetFollowLinks@nsLocalFile@@UAGIH@Z ; 10936 +?GetYoungestEventQueue@nsEventQueueServiceImpl@@AAEIPAVnsIEventQueue@@PAPAV2@@Z ; 10928 +?GetThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAUPRThread@@PAPAVnsIEventQueue@@@Z ; 10925 +??0nsSharedBufferList@@QAE@PAVBuffer@0@@Z ; 10649 +?init_range_from_buffer_list@nsSlidingSubstring@@AAEXXZ ; 10649 +?DestroyBuffers@nsSharedBufferList@@IAEXXZ ; 10647 +??_EnsSlidingSharedBufferList@@UAEPAXI@Z ; 10647 +??1nsSharedBufferList@@UAE@XZ ; 10647 +??RnsCreateInstanceByCID@@UBEIABUnsID@@PAPAX@Z ; 10636 +?Put@nsSupportsHashtable@@QAEHPAVnsHashKey@@PAVnsISupports@@PAPAV3@@Z ; 10605 +?ToLowerCase@nsString@@QBEXAAV1@@Z ; 10514 +?GetPath@nsLocalFile@@UAGIPAPAD@Z ; 10449 +??0nsStringKey@@QAE@PBGHW4Ownership@0@@Z ; 10430 +?AddRef@nsPipeInputStream@nsPipe@@UAGKXZ ; 10377 +?Release@nsPipeInputStream@nsPipe@@UAGKXZ ; 10375 +?Rebind@nsSlidingSubstring@@QAEXABVnsAString@@@Z ; 10240 +?PeekFront@nsDeque@@QAEPAXXZ ; 10192 +??2AtomImpl@@SAPAXIABVnsAString@@@Z ; 10144 +??0AtomImpl@@QAE@XZ ; 10144 +?ResolveEventQueue@nsEventQueueServiceImpl@@UAGIPAVnsIEventQueue@@PAPAV2@@Z ; 10065 +?ToNewUTF8String@nsString@@QBEPADXZ ; 10047 +PL_DHashTableEnumerate ; 9813 +?AddBucket@nsFixedSizeAllocator@@IAEII@Z ; 9776 +?AppendWithConversion@nsCString@@QAEXABVnsString@@H@Z ; 9758 +?Right@nsACString@@QBEIAAV1@I@Z ; 9591 +?Lookup@nsStaticCaseInsensitiveNameTable@@QAEHABVnsCString@@@Z ; 9227 +?Enumerate@nsHashtable@@QAEXP6AHPAVnsHashKey@@PAX1@Z1@Z ; 9133 +?GetParent@xptiInterfaceInfo@@UAGIPAPAVnsIInterfaceInfo@@@Z ; 9105 +_md_EventReceiverProc@16 ; 9061 +?InitWithPath@nsLocalFile@@UAGIPBD@Z ; 8986 +??0nsLocalFile@@QAE@XZ ; 8981 +??_EnsLocalFile@@UAEPAXI@Z ; 8977 +??1nsLocalFile@@UAE@XZ ; 8977 +NS_NewLocalFile ; 8952 +?GetWriteSegment@nsPipe@@QAEIPAPADPAI@Z ; 8809 +?GetProxyForObject@nsProxyObjectManager@@UAGIPAVnsIEventQueue@@ABUnsID@@PAVnsISupports@@HPAPAX@Z ; 8762 +?GetNewOrUsedProxy@nsProxyEventObject@@SAPAV1@PAVnsIEventQueue@@HPAVnsISupports@@ABUnsID@@@Z ; 8762 +?Equals@nsProxyEventKey@@UBEHPBVnsHashKey@@@Z ; 8745 +?AddRef@nsPipeOutputStream@nsPipe@@UAGKXZ ; 8650 +?Release@nsPipeOutputStream@nsPipe@@UAGKXZ ; 8649 +?Read@nsPipeInputStream@nsPipe@@UAGIPADIPAI@Z ; 8617 +??4nsXPIDLCString@@QAEAAV0@PBD@Z ; 8570 +??1nsSimpleCharString@@QAE@XZ ; 8555 +?Equals@nsStringKey@@UBEHPBVnsHashKey@@@Z ; 8497 +?AddRefData@nsSimpleCharString@@IAEXXZ ; 8367 +?Init@nsFixedSizeAllocator@@QAEIPBDPBIHHH@Z ; 7954 +??0nsStringKey@@QAE@ABVnsAString@@@Z ; 7944 +?Release@nsArrayEnumerator@@UAGKXZ ; 7923 +?PostCompleted@nsProxyObjectCallInfo@@QAEXXZ ; 7863 +?SetCompleted@nsProxyObjectCallInfo@@QAEXXZ ; 7863 +??0nsCString@@QAE@ABV0@@Z ; 7622 +?AppendNewSegment@nsSegmentedBuffer@@QAEPADXZ ; 7622 +??_GAtomImpl@@UAEPAXI@Z ; 7566 +??1AtomImpl@@UAE@XZ ; 7566 +??0nsCString@@QAE@PBD@Z ; 7541 +??0nsAutoString@@QAE@ABVCBufDescriptor@@@Z ; 7529 +??0NS_ConvertASCIItoUCS2@@QAE@PBDI@Z ; 7452 +??0nsString@@QAE@ABVnsAString@@@Z ; 7419 +??0CBufDescriptor@@QAE@PAGHIH@Z ; 7406 +??0nsCreateInstanceByContractID@@QAE@PBDPAVnsISupports@@PAI@Z ; 7402 +?EnumerateForwards@nsVoidArray@@QAEHP6AHPAX0@Z0@Z ; 7195 +?AppendInt@nsCString@@QAEXHH@Z ; 7047 +??RnsGetWeakReference@@UBEIABUnsID@@PAPAX@Z ; 7028 +?NS_GetWeakReference@@YAPAVnsIWeakReference@@PAVnsISupports@@PAI@Z ; 7022 +?Clone@nsLocalFile@@UAGIPAPAVnsIFile@@@Z ; 6960 +?AppendRelativePath@nsLocalFile@@UAGIPBD@Z ; 6927 +?Empty@nsSegmentedBuffer@@QAEXXZ ; 6878 +??_EnsIDKey@@UAEPAXI@Z ; 6876 +?Append@nsLocalFile@@UAGIPBD@Z ; 6818 +?RFindChar@nsStr@@SAHABU1@GHHH@Z ; 6753 +?RFindChar@nsString@@QBEHGHHH@Z ; 6753 +?GetWeakReference@nsSupportsWeakReference@@UAGIPAPAVnsIWeakReference@@@Z ; 6751 +?Release@nsMemoryImpl@@UAGKXZ ; 6468 +??1nsSupportsWeakReference@@UAE@XZ ; 6428 +?SetNonBlocking@nsPipeInputStream@nsPipe@@UAGIH@Z ; 6306 +PL_DHashTableRawRemove ; 6270 +?GetNext@nsArrayEnumerator@@UAGIPAPAVnsISupports@@@Z ; 6180 +?ReleaseService@nsServiceManagerImpl@@UAGIABUnsID@@PAVnsISupports@@PAVnsIShutdownListener@@@Z ; 6156 +?RFindSubstr@nsStr@@SAHABU1@0HHH@Z ; 6056 +?RFind@nsCString@@QBEHPBDHHH@Z ; 6052 +?HasMoreElements@nsDirEnumerator@@UAGIPAH@Z ; 5962 +?QueryInterface@nsProxyObjectManager@@UAGIABUnsID@@PAPAX@Z ; 5920 +?GetReadableFragment@nsSlidingString@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 5909 +?ShiftDoubleCharsLeft@@YAXPADIII@Z ; 5858 +?Clone@nsProxyEventKey@@UBEPAVnsHashKey@@XZ ; 5832 +?IsManagerShutdown@nsProxyObjectManager@@SAHXZ ; 5823 +?ReleaseService@nsServiceManager@@SAIABUnsID@@PAVnsISupports@@PAVnsIShutdownListener@@@Z ; 5681 +??4nsSimpleCharString@@QAEXABV0@@Z ; 5572 +?Copy@nsXPIDLString@@SAPAGPBG@Z ; 5526 +??0nsString@@QAE@PBG@Z ; 5504 +?Find@nsProxyEventObject@@QAEPAV1@ABUnsID@@@Z ; 5501 +?WriteSegments@nsPipeOutputStream@nsPipe@@UAGIP6GIPAVnsIOutputStream@@PAXPADIIPAI@Z1I3@Z ; 5497 +?Read@StringUnicharInputStream@@UAGIPAGIIPAI@Z ; 5482 +?WriteFrom@nsPipeOutputStream@nsPipe@@UAGIPAVnsIInputStream@@IPAI@Z ; 5388 +?ToNewCString@nsString@@QBEPADXZ ; 5351 +?Release@nsInputStreamTee@@UAGKXZ ; 5341 +?IndexOf@nsSupportsArray@@UAGHPBVnsISupports@@@Z ; 5281 +?IndexOfStartingAt@nsSupportsArray@@UAGHPBVnsISupports@@I@Z ; 5281 +??6nsOutputStream@@QAEAAV0@PBD@Z ; 5112 +?ToInteger@nsCString@@QBEHPAHI@Z ; 5109 +?do_AssignFromElementPtrLength@nsACString@@MAEXPBDI@Z ; 5103 +?Exists@nsLocalFile@@UAGIPAH@Z ; 5085 +?PL_HashTableInit@@YA?AW4PRStatus@@PAUPLHashTable@@IP6AIPBX@ZP6AH11@Z3PBUPLHashAllocOps@@PAX@Z ; 4964 +??0nsHashtable@@QAE@IH@Z ; 4964 +?Get@nsInt2StrHashtable@@QAEPADI@Z ; 4864 +??BnsSimpleCharString@@QAEPADXZ ; 4785 +?GetConstant@xptiInterfaceInfo@@UAGIGPAPBVnsXPTConstant@@@Z ; 4716 +?PL_HashTableFinalize@@YAXPAUPLHashTable@@@Z ; 4596 +??1nsHashtable@@UAE@XZ ; 4596 +?do_AssignFromElementPtrLength@nsAString@@MAEXPBGI@Z ; 4541 +?Error@nsFileSpec@@QBEIXZ ; 4535 +?GetSpecialEventQueue@nsEventQueueServiceImpl@@UAGIHPAPAVnsIEventQueue@@@Z ; 4454 +?GetStringProperty@nsPersistentProperties@@UAGIABVnsString@@AAV2@@Z ; 4441 +?DumpStatistics@nsTraceRefcnt@@SAIW4StatisticsType@1@PAU_iobuf@@@Z ; 4434 +?GetBufferHandle@nsPrivateSharableString@@UBEPBV?$nsBufferHandle@G@@XZ ; 4434 +?Release@xptiInterfaceInfoManager@@UAGKXZ ; 4417 +?Clone@nsCStringKey@@UBEPAVnsHashKey@@XZ ; 4332 +?normalize_backward@?$nsWritingIterator@D@@QAEXXZ ; 4288 +??1nsFileSpec@@UAE@XZ ; 4256 +?AddRef@BasicStringImpl@@UAGKXZ ; 4185 +??_EnsCStringKey@@UAEPAXI@Z ; 4173 +?ToCString@nsCString@@QBEPADPADII@Z ; 4056 +?First@nsDequeIterator@@QAEAAV1@XZ ; 4049 +??_EnsSubsumeStr@@UAEPAXI@Z ; 4048 +?InsertStringAt@nsStringArray@@QAEHABVnsAString@@H@Z ; 4026 +?Release@BasicStringImpl@@UAGKXZ ; 3967 +?ReleaseValues@nsProperties@@SAHPAVnsHashKey@@PAX1@Z ; 3966 +?StripChars2@@YAHPADIPBD@Z ; 3927 +?ToFloat@nsString@@QBEMPAH@Z ; 3910 +?Release@nsThreadPool@@UAGKXZ ; 3896 +??0nsPromiseFlatCString@@IAE@ABVnsACString@@@Z ; 3888 +??1nsPromiseFlatCString@@UAE@XZ ; 3878 +?Clone@nsStringKey@@UBEPAVnsHashKey@@XZ ; 3824 +?RFindChar2@@YAHPBDIHGHH@Z ; 3738 +??_EnsStringKey@@UAEPAXI@Z ; 3721 +?Alloc@ArenaImpl@@UAGPAXI@Z ; 3688 +?DeleteFirstSegment@nsSegmentedBuffer@@QAEHXZ ; 3646 +?OpenANSIFileDesc@nsLocalFile@@UAGIPBDPAPAU_iobuf@@@Z ; 3547 +?EqualsWithConversion@nsCString@@QBEHPBDHH@Z ; 3544 +?EqualsIgnoreCase@nsCString@@QBEHPBDH@Z ; 3544 +?ResolvePath@nsLocalFile@@AAEIPBDHPAPAD@Z ; 3539 +?CopyFrom@nsSimpleCharString@@QAEXPBDI@Z ; 3498 +?FindCharInReadable@@YAHGAAV?$nsReadingIterator@G@@ABV1@@Z ; 3480 +??0nsPromiseSubstring@@QAE@ABV?$nsReadingIterator@G@@0@Z ; 3431 +?GetStringUTF8@nsRegistry@@UAGIIPBDPAPAD@Z ; 3345 +??0nsSegmentedBuffer@@QAE@XZ ; 3334 +??1nsSegmentedBuffer@@QAE@XZ ; 3333 +?GetInfoForName@xptiInterfaceInfoManager@@UAGIPBDPAPAVnsIInterfaceInfo@@@Z ; 3332 +?Init@nsSegmentedBuffer@@QAEIIIPAVnsIMemory@@@Z ; 3307 +?HasInterfaceRecord@xptiInterfaceInfo@@QBEHXZ ; 3300 +?Compare@@YAHABVnsACString@@0@Z ; 3236 +?vsmprintf@nsTextFormatter@@SAPAGPBGPAD@Z ; 3228 +?smprintf@nsTextFormatter@@SAPAGPBGZZ ; 3228 +?QueryInterface@nsMemoryImpl@@UAGIABUnsID@@PAPAX@Z ; 3156 +??0nsPipe@@QAE@XZ ; 3153 +?Close@nsPipeOutputStream@nsPipe@@UAGIXZ ; 3153 +?SetObserver@nsPipeInputStream@nsPipe@@UAGIPAVnsIInputStreamObserver@@@Z ; 3153 +?Initialize@nsPipe@@UAGIIIHHPAVnsIMemory@@@Z ; 3153 +?NS_NewPipe@@YAIPAPAVnsIInputStream@@PAPAVnsIOutputStream@@IIHHPAVnsIMemory@@@Z ; 3153 +?Close@nsPipeInputStream@nsPipe@@UAGIXZ ; 3152 +??1nsPipe@@UAE@XZ ; 3152 +??_GnsPipe@@UAEPAXI@Z ; 3152 +?GetLeafName@nsLocalFile@@UAGIPAPAD@Z ; 3138 +?Parse@nsID@@QAEHPBD@Z ; 3088 +?GetLeaf@nsSimpleCharString@@QBEPADD@Z ; 3070 +?GetLeafName@nsFileSpec@@QBEPADXZ ; 3070 +?Flush@nsPipeOutputStream@nsPipe@@UAGIXZ ; 3043 +?CheckForDeactivation@nsEventQueueImpl@@AAEXXZ ; 3018 +?RFindChar1@@YAHPBDIHGHH@Z ; 3015 +??0nsCAutoString@@QAE@ABVnsACString@@@Z ; 3014 +?GetNext@nsDirEnumerator@@UAGIPAPAVnsISupports@@@Z ; 2976 +?ProcessPendingEvents@nsEventQueueImpl@@UAGIXZ ; 2951 +?GetInterfaceInfoManagerNoAddRef@xptiInterfaceInfoManager@@SAPAV1@XZ ; 2948 +?CountChar@nsAString@@QBEIG@Z ; 2937 +?AppendInt@nsString@@QAEXHH@Z ; 2922 +?ToUpperCase@nsString@@QAEXXZ ; 2900 +nsUnescapeCount ; 2828 +nsUnescape ; 2828 +??0nsSimpleCharString@@QAE@ABV0@@Z ; 2795 +??4nsFileSpec@@QAEXABV0@@Z ; 2739 +??0nsFileSpec@@QAE@ABV0@@Z ; 2731 +?StripWhitespace@nsString@@QAEXXZ ; 2714 +XPTI_GetInterfaceInfoManager ; 2696 +?StringAt@nsStringArray@@QBEPAVnsString@@H@Z ; 2681 +??0nsArrayEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 2637 +??1nsArrayEnumerator@@UAE@XZ ; 2637 +?GetPRThread@nsThread@@UAGIPAPAUPRThread@@@Z ; 2623 +?GetMainThread@nsIThread@@SAIPAPAV1@@Z ; 2622 +NS_NewArrayEnumerator ; 2582 +??_EnsArrayEnumerator@@UAEPAXI@Z ; 2582 +?CallQueryInterfaceOnProxy@nsProxyEventClass@@AAEIPAVnsProxyEventObject@@ABUnsID@@PAPAV2@@Z ; 2571 +?GetQueue@nsProxyEventObject@@QBEPAVnsIEventQueue@@XZ ; 2571 +?DelegatedQueryInterface@nsProxyEventClass@@UAGIPAVnsProxyEventObject@@ABUnsID@@PAPAX@Z ; 2571 +?GetRealObject@nsProxyEventObject@@QBEPAVnsISupports@@XZ ; 2571 +??_EnsWeakReference@@EAEPAXI@Z ; 2556 +?ReadSegments@ConstCharImpl@@MAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 2520 +?IsDone@nsRegSubtreeEnumerator@@UAGIXZ ; 2490 +?Next@nsRegSubtreeEnumerator@@UAGIXZ ; 2490 +?advance@nsRegSubtreeEnumerator@@MAGIXZ ; 2451 +?GetErrorStringBundleKey@nsErrorService@@UAGIIPAPAD@Z ; 2432 +?GetErrorStringBundle@nsErrorService@@UAGIFPAPAD@Z ; 2432 +?GetIndexOf@nsSupportsArray@@UAGIPAVnsISupports@@PAH@Z ; 2409 +?ToNewUnicode@nsCString@@QBEPAGXZ ; 2376 +?ToNewCString@@YAPADABVnsACString@@@Z ; 2364 +?copy_string@@YAAAPADAAV?$nsReadingIterator@D@@ABV1@AAPAD@Z ; 2364 +?WriteSegmentFun@nsInputStreamTee@@CGIPAVnsIInputStream@@PAXPBDIIPAI@Z ; 2346 +?CurrentItemInPlaceUTF8@nsRegSubtreeEnumerator@@UAGIPAIPAPBD@Z ; 2320 +PL_DHashAllocTable ; 2253 +?Release@nsFileSpecImpl@@UAGKXZ ; 2241 +?GetSharedBufferHandle@nsCommonCString@@MBEPBV?$nsSharedBufferHandle@D@@XZ ; 2217 +?assign@nsCommonString@@IAEXABVnsAString@@@Z ; 2217 +?ReleaseReference@?$nsSharedBufferHandle@G@@QBEXXZ ; 2217 +?NS_AllocateContiguousHandleWithData@@YAPAV?$nsSharedBufferHandle@G@@PBV1@ABVnsAString@@I@Z ; 2217 +?QueryInterface@nsFileSpecImpl@@UAGIABUnsID@@PAPAX@Z ; 2172 +?GetRequest@nsThreadPool@@QAEPAVnsIRunnable@@PAVnsIThread@@@Z ; 2147 +PL_DHashFreeTable ; 2125 +?Clear@nsCStringArray@@QAEXXZ ; 2122 +?ReadSegments@nsInputStreamTee@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 2115 +?TeeSegment@nsInputStreamTee@@AAEIPBDI@Z ; 2045 +?DispatchRequest@nsThreadPool@@UAGIPAVnsIRunnable@@@Z ; 2038 +??1nsThreadPoolBusyBody@@QAE@XZ ; 2038 +??0nsThreadPoolBusyBody@@QAE@PAVnsThreadPool@@@Z ; 2038 +??0nsCreateInstanceByCID@@QAE@ABUnsID@@PAVnsISupports@@PAI@Z ; 2029 +?ReplaceChar@nsCString@@QAEXGG@Z ; 2022 +?CloseStream@nsFileSpecImpl@@UAGIXZ ; 1968 +?do_InsertFromReadable@nsACString@@MAEXABV1@I@Z ; 1965 +?do_InsertFromElement@nsACString@@MAEXDI@Z ; 1965 +??_EnsFileSpecImpl@@UAEPAXI@Z ; 1955 +??1nsFileSpecImpl@@UAE@XZ ; 1955 +??0nsSimpleCharString@@QAE@PBD@Z ; 1936 +?RFindCharInSet@nsCString@@QBEHPBDH@Z ; 1913 +?RFindCharInSet@nsStr@@SAHABU1@0HH@Z ; 1913 +?Release@ByteBufferImpl@@UAGKXZ ; 1905 +?SkipWhiteSpace@nsPersistentProperties@@QAEHH@Z ; 1898 +?First@nsACString@@QBEDXZ ; 1881 +??0nsVoidArray@@QAE@H@Z ; 1876 +?copy_string_backward@@YAAAV?$nsWritingIterator@D@@ABV?$nsReadingIterator@D@@AAV2@AAV1@@Z ; 1834 +?QueryInterface@nsPipeInputStream@nsPipe@@UAGIABUnsID@@PAPAX@Z ; 1782 +?QueryInterface@nsPipe@@UAGIABUnsID@@PAPAX@Z ; 1782 +?CountCharInReadable@@YAIABVnsAString@@G@Z ; 1767 +?IsDirectory@nsLocalFile@@UAGIPAH@Z ; 1765 +?GetFileSpec@nsFileSpecImpl@@UAGIPAVnsFileSpec@@@Z ; 1765 +?CopyUnicodeTo@@YAPAGABVnsAString@@IPAGI@Z ; 1749 +NS_QuickSort ; 1729 +??1nsStringArray@@UAE@XZ ; 1709 +??0nsStringArray@@QAE@XZ ; 1709 +?IsScriptable@xptiInterfaceInfo@@UAGIPAH@Z ; 1690 +?Find@nsCString@@QBEHPBGHHH@Z ; 1674 +?SetLeafName@nsFileSpec@@QAEXPBD@Z ; 1670 +?LeafReplace@nsSimpleCharString@@QAEXDPBD@Z ; 1670 +?NextLine@ManifestLineReader@@QAEHXZ ; 1658 +??0nsFileSpec@@QAE@XZ ; 1656 +PL_DHashTableInit ; 1622 +??4nsSimpleCharString@@QAEXPBD@Z ; 1598 +?GetInterfaceIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@PAE@Z ; 1555 +?Init@nsInputStreamTee@@UAGIPAVnsIInputStream@@PAVnsIOutputStream@@@Z ; 1550 +?QueryInterface@nsInputStreamTee@@UAGIABUnsID@@PAPAX@Z ; 1550 +?Right@nsAString@@QBEIAAV1@I@Z ; 1518 +PL_DHashTableFinish ; 1494 +??0nsFileSpecImpl@@QAE@ABVnsFileSpec@@@Z ; 1446 +?MakeInterface@nsFileSpecImpl@@SAIABVnsFileSpec@@PAPAVnsIFileSpec@@@Z ; 1446 +?NS_NewFileSpecWithSpec@@YAIABVnsFileSpec@@PAPAVnsIFileSpec@@@Z ; 1437 +??0xptiInterfaceInfo@@QAE@PBDABUnsID@@ABVxptiTypelib@@PAVxptiWorkingSet@@@Z ; 1434 +?CopyName@xptiInterfaceInfo@@AAEXPBDPAVxptiWorkingSet@@@Z ; 1434 +?SetScriptableFlag@xptiInterfaceInfo@@QAEXH@Z ; 1434 +??1xptiInterfaceInfo@@UAE@XZ ; 1427 +??_GxptiInterfaceInfo@@UAEPAXI@Z ; 1427 +??1nsSupportsHashtable@@UAE@XZ ; 1406 +??0nsACString@@QAE@XZ ; 1361 +?Exists@nsHashtable@@QAEHPAVnsHashKey@@@Z ; 1348 +?SetData@nsSupportsVoidImpl@@UAGIPAX@Z ; 1337 +??0BasicStringImpl@@QAE@XZ ; 1319 +?QueryInterface@BasicStringImpl@@UAGIABUnsID@@PAPAX@Z ; 1319 +??0ConstCharImpl@@QAE@PBDH@Z ; 1319 +?NewMonitor@nsAutoMonitor@@SAPAUPRMonitor@@PBD@Z ; 1312 +??1BasicStringImpl@@UAE@XZ ; 1309 +?DestroyMonitor@nsAutoMonitor@@SAXPAUPRMonitor@@@Z ; 1309 +??_EBasicStringImpl@@UAEPAXI@Z ; 1309 +?Enter@nsAutoCMonitor@@QAEXXZ ; 1307 +?Exit@nsAutoCMonitor@@QAEXXZ ; 1307 +?StringAllocator_wchar_t@@YAAAV?$nsStringAllocator@G@@XZ ; 1306 +?get_allocator@?$nsSharedBufferHandle@G@@IBEAAV?$nsStringAllocator@G@@XZ ; 1306 +?Deallocate@?$XPCOM_StringAllocator@G@@UBEXPAG@Z ; 1306 +NS_NewCharInputStream ; 1303 +?Release@nsRegSubtreeEnumerator@@UAGKXZ ; 1289 +??0nsDequeIterator@@QAE@ABVnsDeque@@H@Z ; 1284 +??FnsDequeIterator@@QAEPAXXZ ; 1284 +?End@nsDeque@@QBE?AVnsDequeIterator@@XZ ; 1284 +?OpenNSPRFileDesc@nsLocalFile@@UAGIHHPAPAUPRFileDesc@@@Z ; 1275 +?StrInsert@nsStr@@SAXAAU1@IABU1@IH@Z ; 1266 +?InsertWithConversion@nsString@@QAEXPBDIH@Z ; 1266 +?ShiftDoubleCharsRight@@YAXPADIII@Z ; 1266 +??0nsSupportsVoidImpl@@QAE@XZ ; 1260 +??_GnsSupportsVoidImpl@@UAEPAXI@Z ; 1260 +??1nsSupportsVoidImpl@@UAE@XZ ; 1260 +?QueryInterface@nsSupportsVoidImpl@@UAGIABUnsID@@PAPAX@Z ; 1260 +?QueryInterface@ConverterInputStream@@UAGIABUnsID@@PAPAX@Z ; 1258 +?get_at_eof@nsRandomAccessInputStream@@MBEHXZ ; 1241 +?GetAtEOF@FileImpl@@UAGIPAH@Z ; 1241 +?get_at_eof@nsRandomAccessStoreClient@@MBEHXZ ; 1241 +?GetTargetArraySize@nsObserverListEnumerator@@ABEIXZ ; 1208 +??YnsSimpleCharString@@QAEXPBD@Z ; 1187 +??_EStringUnicharInputStream@@UAEPAXI@Z ; 1178 +??1StringUnicharInputStream@@UAE@XZ ; 1178 +??0StringUnicharInputStream@@QAE@PAVnsString@@@Z ; 1178 +?NS_NewStringUnicharInputStream@@YAIPAPAVnsIUnicharInputStream@@PAVnsString@@@Z ; 1178 +??0nsInputStreamTee@@QAE@XZ ; 1164 +??_GnsInputStreamTee@@UAEPAXI@Z ; 1164 +??1nsInputStreamTee@@UAE@XZ ; 1164 +?NS_NewInputStreamTee@@YAIPAPAVnsIInputStream@@PAV1@PAVnsIOutputStream@@@Z ; 1164 +?GetTypelibRecord@xptiInterfaceInfo@@QBEABVxptiTypelib@@XZ ; 1156 +?Write@nsStorageStream@@UAGIPBDIPAI@Z ; 1138 +?GetObserverList@nsObserverService@@EAGIPBGPAPAVnsIObserverList@@@Z ; 1119 +?HasMoreElements@nsArrayEnumerator@@UAGIPAH@Z ; 1100 +?GetCString@nsFileSpec@@QBEPBDXZ ; 1098 +PL_DHashVoidPtrKeyStub ; 1098 +?strtok@nsCRT@@SAPADPADPBDPAPAD@Z ; 1084 +?GetInfoForIID@xptiInterfaceInfoManager@@UAGIPBUnsID@@PAPAVnsIInterfaceInfo@@@Z ; 1081 +??_EnsSupportsArrayEnumerator@@UAEPAXI@Z ; 1065 +??0nsSupportsArrayEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 1065 +??1nsSupportsArrayEnumerator@@UAE@XZ ; 1065 +?Enumerate@nsSupportsArray@@UAGIPAPAVnsIEnumerator@@@Z ; 1065 +?First@nsSupportsArrayEnumerator@@UAGIXZ ; 1065 +?WriteFully@nsBinaryOutputStream@@QAEIPBDI@Z ; 1055 +?CurrentItem@nsSupportsArrayEnumerator@@UAGIPAPAVnsISupports@@@Z ; 1053 +?GetConstantCount@xptiInterfaceInfo@@UAGIPAG@Z ; 1040 +?Clone@nsIDKey@@UBEPAVnsHashKey@@XZ ; 1035 +?SetStringProperty@nsPersistentProperties@@UAGIABVnsString@@AAV2@1@Z ; 1006 +?Next@nsSupportsArrayEnumerator@@UAGIXZ ; 993 +?Release@nsStorageInputStream@@UAGKXZ ; 981 +?GetMethodCount@xptiInterfaceInfo@@UAGIPAG@Z ; 970 +?QueryInterface@nsObserverService@@UAGIABUnsID@@PAPAX@Z ; 948 +?FindChar@nsAString@@QBEHGI@Z ; 941 +?LinkBuffer@nsSharedBufferList@@QAEXPAVBuffer@1@00@Z ; 920 +?IsIID@xptiInterfaceInfo@@UAGIPBUnsID@@PAH@Z ; 918 +?AppendBuffer@nsSlidingString@@QAEXPAG00@Z ; 900 +??1nsFilePath@@UAE@XZ ; 886 +?NativeToUnix@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@@Z ; 886 +?SetDeallocator@nsDeque@@QAEXPAVnsDequeFunctor@@@Z ; 885 +?IsASCII@@YAHABVnsAString@@@Z ; 875 +?SkipLine@nsPersistentProperties@@QAEHH@Z ; 862 +?EnumerateObserverList@nsObserverService@@UAGIPBGPAPAVnsIEnumerator@@@Z ; 855 +?EnumerateObserverList@nsObserverList@@UAGIPAPAVnsIEnumerator@@@Z ; 855 +??4nsPersistentFileDescriptor@@QAEXABVnsFileSpec@@@Z ; 849 +??1nsPersistentFileDescriptor@@UAE@XZ ; 849 +??0nsPersistentFileDescriptor@@QAE@ABVnsFileSpec@@@Z ; 849 +?GetData@nsPersistentFileDescriptor@@QBEXAAVnsSimpleCharString@@@Z ; 849 +?GetPersistentDescriptorString@nsFileSpecImpl@@UAGIPAPAD@Z ; 849 +?FindInReadable@@YAHABVnsAString@@AAV?$nsReadingIterator@G@@1@Z ; 819 +?nsCID_Destroy@@YAHPAVnsHashKey@@PAX1@Z ; 773 +?Read@nsInputStreamTee@@UAGIPADIPAI@Z ; 769 +??1nsFactoryEntry@@QAE@XZ ; 737 +?nsFactoryEntry_Destroy@@YAHPAVnsHashKey@@PAX1@Z ; 733 +??0nsFileSpecImpl@@QAE@XZ ; 726 +?NS_NewFileSpec@@YAIPAPAVnsIFileSpec@@@Z ; 726 +?Create@nsFileSpecImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 726 +?UnixToNative@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@@Z ; 719 +?Invalidate@xptiInterfaceInfo@@QAEXXZ ; 717 +?AppendWithConversion@nsCString@@QAEXPBGH@Z ; 697 +??0nsFactoryEntry@@QAE@ABUnsID@@PBD1PAVnsIComponentLoader@@@Z ; 695 +?SetInfoAt@xptiTypelibGuts@@QAEIGPAVxptiInterfaceInfo@@@Z ; 683 +PL_DHashGetKeyStub ; 678 +PL_DHashMoveEntryStub ; 678 +?GrowCapacity@nsDeque@@AAEAAV1@XZ ; 673 +?AssignWithConversion@nsString@@QAEXPBDH@Z ; 665 +??4nsFilePath@@QAEXABVnsFileSpec@@@Z ; 659 +??0nsFilePath@@QAE@ABVnsFileSpec@@@Z ; 659 +?Canonify@nsFileSpecHelpers@@YAXAAVnsSimpleCharString@@H@Z ; 653 +?FromFileSpec@nsFileSpecImpl@@UAGIPBVnsIFileSpec@@@Z ; 652 +?GetValueType@nsRegistry@@UAGIIPBDPAI@Z ; 652 +?GetBytesUTF8@nsRegistry@@UAGIIPBDPAIPAPAE@Z ; 651 +?Write32@nsBinaryOutputStream@@UAGII@Z ; 649 +?EnumerateBackwards@nsSupportsArray@@UAGHP6AHPAVnsISupports@@PAX@Z1@Z ; 648 +?SetFromFileSpec@nsFileSpecImpl@@UAGIABVnsFileSpec@@@Z ; 634 +?smprintf_free@nsTextFormatter@@SAXPAG@Z ; 623 +?nsEndl@@YAAAVnsOutputStream@@AAV1@@Z ; 615 +?QueryInterface@nsGenericFactory@@UAGIABUnsID@@PAPAX@Z ; 606 +?Equals@nsAString@@QBEHPBG@Z ; 599 +?strcasecmp@nsCRT@@SAHPBGPBD@Z ; 585 +?put@nsOutputStream@@QAEXD@Z ; 572 +?IsFile@nsLocalFile@@UAGIPAH@Z ; 570 +?ForEach@nsDeque@@QBEXAAVnsDequeFunctor@@@Z ; 558 +?Release@EmptyEnumeratorImpl@@UAGKXZ ; 553 +NS_NewEmptyEnumerator ; 553 +?HasMoreElements@EmptyEnumeratorImpl@@UAGIPAH@Z ; 552 +?AddRef@FileImpl@@UAGKXZ ; 549 +?Release@FileImpl@@UAGKXZ ; 542 +?snprintf@nsTextFormatter@@SAIPAGIPBGZZ ; 534 +?vsnprintf@nsTextFormatter@@SAIPAGIPBGPAD@Z ; 534 +?Available@nsPipeInputStream@nsPipe@@UAGIPAI@Z ; 533 +?PushFront@nsDeque@@QAEAAV1@PAX@Z ; 522 +?AddItem@nsAVLTree@@QAE?AW4eAVLStatus@@PAX@Z ; 518 +??0nsAutoString@@QAE@PBGH@Z ; 509 +?IsDone@nsObserverListEnumerator@@UAGIXZ ; 479 +?MoveToIndex@nsObserverListEnumerator@@AAEII@Z ; 479 +?ReleaseService@nsServiceManager@@SAIPBDPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 477 +?ReleaseService@nsServiceManagerImpl@@UAGIPBDPAVnsISupports@@PAVnsIShutdownListener@@@Z ; 477 +?AppendWithConversion@nsCString@@QAEXABVnsAString@@@Z ; 467 +?CreateDll@nsNativeComponentLoader@@AAEIPAVnsIFile@@PBDPA_J2PAPAVnsDll@@@Z ; 466 +?Flush@FileImpl@@UAGIXZ ; 455 +??1nsNSPRPath@@UAE@XZ ; 444 +??BnsNSPRPath@@QBEPBDXZ ; 444 +??0nsByteArrayInputStream@@QAE@PADI@Z ; 443 +??_EnsByteArrayInputStream@@UAEPAXI@Z ; 443 +??1nsByteArrayInputStream@@UAE@XZ ; 443 +?QueryInterface@nsByteArrayInputStream@@UAGIABUnsID@@PAPAX@Z ; 443 +?NS_NewByteArrayInputStream@@YAIPAPAVnsIByteArrayInputStream@@PADK@Z ; 443 +PL_DHashMatchEntryStub ; 442 +?ScriptableFlagIsValid@xptiInterfaceInfo@@ABEHXZ ; 439 +?PartiallyResolveLocked@xptiInterfaceInfo@@QAEHPAUXPTInterfaceDescriptor@@PAVxptiWorkingSet@@@Z ; 439 +??1xptiInterfaceGuts@@QAE@XZ ; 439 +?QueryInterface@FileImpl@@UAGIABUnsID@@PAPAX@Z ; 433 +??1xptiFile@@QAE@XZ ; 424 +?QueryInterface@nsSupportsStringImpl@@UAGIABUnsID@@PAPAX@Z ; 422 +?ReplaceChar@nsString@@QAEXGG@Z ; 421 +?Notify@nsObserverService@@UAGIPAVnsISupports@@PBG1@Z ; 416 +??0nsSlidingString@@QAE@PAG00@Z ; 408 +?NewWrappingBuffer@nsSharedBufferList@@SAPAVBuffer@1@PAG00@Z ; 408 +??0nsSlidingSubstring@@IAE@PAVnsSlidingSharedBufferList@@@Z ; 408 +??0nsCStringArray@@QAE@XZ ; 394 +??1nsCStringArray@@UAE@XZ ; 393 +??EnsDirectoryIterator@@QAEAAV0@XZ ; 377 +?Reset@nsSupportsHashtable@@QAEXXZ ; 370 +?ReadSegments@nsByteArrayInputStream@@UAGIP6GIPAVnsIInputStream@@PAXPBDIIPAI@Z1I3@Z ; 356 +?GetFileSize@nsLocalFile@@UAGIPA_J@Z ; 354 +?SetDataWithLength@nsSupportsStringImpl@@UAGIIPBD@Z ; 344 +??0nsSupportsStringImpl@@QAE@XZ ; 344 +??1nsSupportsStringImpl@@UAE@XZ ; 337 +??_EnsSupportsStringImpl@@UAEPAXI@Z ; 337 +?GetModule@nsDll@@QAEIPAVnsISupports@@PAPAVnsIModule@@@Z ; 331 +?Release@nsStorageStream@@UAGKXZ ; 328 +?Release@nsSupportsIDImpl@@UAGKXZ ; 327 +?CopyASCIItoUCS2@@YAXABVnsACString@@AAVnsAString@@@Z ; 327 +?copy_string@@YAAAV?$LossyConvertEncoding@DG@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 327 +??_EnsCString@@UAEPAXI@Z ; 324 +?StringAt@nsStringArray@@QBEXHAAVnsAString@@@Z ; 321 +?ToString@nsID@@QBEPADXZ ; 319 +?GetLength@UnicharBufferImpl@@UBGHXZ ; 316 +?Fill@ByteBufferImpl@@UAGHPAIPAVnsIInputStream@@I@Z ; 316 +?Fill@ConverterInputStream@@IAEHPAI@Z ; 316 +?copy_string_backward@@YAAAV?$nsWritingIterator@G@@ABV?$nsReadingIterator@G@@AAV2@AAV1@@Z ; 310 +?do_InsertFromReadable@nsAString@@MAEXABV1@I@Z ; 310 +??0nsFileSpec@@QAE@PBDH@Z ; 307 +?SetData@nsSupportsStringImpl@@UAGIPBD@Z ; 295 +?InsertCStringAt@nsCStringArray@@QAEHABVnsCString@@H@Z ; 288 +??YnsFileSpec@@QAEXPBD@Z ; 281 +?CompressWhitespace@nsCString@@QAEXHH@Z ; 278 +?GetFactory@nsNativeComponentLoader@@UAGIABUnsID@@PBD1PAPAVnsIFactory@@@Z ; 273 +?GetFactoryFromModule@nsNativeComponentLoader@@AAEIPAVnsDll@@ABUnsID@@PAPAVnsIFactory@@@Z ; 273 +?GetReadableFragment@nsPromiseConcatenation@@MBEPBGAAU?$nsReadableFragment@G@@W4nsFragmentRequest@@I@Z ; 268 +?Load@nsDll@@QAEHXZ ; 254 +?HasMoreElements@nsAdapterEnumerator@@UAGIPAH@Z ; 251 +?Next@nsObserverListEnumerator@@UAGIXZ ; 250 +??0nsSubsumeStr@@QAE@XZ ; 250 +?Subsume@nsSubsumeStr@@QAEHPAGHH@Z ; 250 +?CurrentItem@nsObserverListEnumerator@@UAGIPAPAVnsISupports@@@Z ; 250 +?Release@nsRegistryNode@@UAGKXZ ; 245 +?PrepareEncoder@nsFSStringConversion@@CAIXZ ; 241 +?UCSToNewFS@nsFSStringConversion@@SAIPBGPAPAD@Z ; 241 +?Write@nsBinaryOutputStream@@UAGIPBDIPAI@Z ; 238 +?IsDirectory@nsFileSpec@@QBEHXZ ; 236 +?QueryInterface@nsConjoiningEnumerator@@UAGIABUnsID@@PAPAX@Z ; 236 +_DllMain@12 ; 235 +??_GnsObserverListEnumerator@@UAEPAXI@Z ; 229 +?First@nsObserverListEnumerator@@UAGIXZ ; 229 +??0nsObserverListEnumerator@@QAE@PAVnsISupportsArray@@@Z ; 229 +?SetComponentInfo@nsGenericFactory@@UAGIPAUnsModuleComponentInfo@@@Z ; 228 +?NS_NewGenericFactory@@YAIPAPAVnsIGenericFactory@@PAUnsModuleComponentInfo@@@Z ; 228 +?Create@nsGenericFactory@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 228 +??0nsGenericFactory@@QAE@PAUnsModuleComponentInfo@@@Z ; 228 +?do_InsertFromElementPtrLength@nsAString@@MAEXPBGII@Z ; 227 +??1nsGenericFactory@@UAE@XZ ; 226 +?GetBufferSize@ByteBufferImpl@@UBGIXZ ; 226 +??_EnsGenericFactory@@UAEPAXI@Z ; 226 +??4nsFileSpec@@QAEXABVnsFilePath@@@Z ; 219 +?GetLastModifiedTime@nsLocalFile@@UAGIPA_J@Z ; 217 +?RFindInReadable@@YAHABVnsAString@@AAV?$nsReadingIterator@G@@1@Z ; 217 +?GetTarget@nsLocalFile@@UAGIPAPAD@Z ; 216 +?CopyFields@xptiFile@@AAEXABV1@@Z ; 212 +??0xptiFile@@QAE@XZ ; 212 +?ConvertStringLineBreaks@nsLinebreakConverter@@SAIAAVnsString@@W4ELinebreakType@1@1@Z ; 212 +??0xptiFile@@QAE@ABVnsInt64@@0PBDPAVxptiWorkingSet@@PAUXPTHeader@@@Z ; 212 +?QueryInterface@nsDirectoryService@@UAGIABUnsID@@PAPAX@Z ; 211 +?ReplaceSubstring@nsString@@QAEXABV1@0@Z ; 210 +?GetLongLong@nsRegistry@@UAGIIPBDPA_J@Z ; 210 +??0nsSimpleCharString@@QAE@ABVnsString@@@Z ; 209 +PL_DHashClearEntryStub ; 209 +??4nsSimpleCharString@@QAEXABVnsString@@@Z ; 209 +?Release@nsDirectoryService@@UAGKXZ ; 208 +?GetType@xptiFileType@@SA?AW4Type@1@PBD@Z ; 208 +?AutoRegisterComponent@nsNativeComponentLoader@@UAGIHPAVnsIFile@@PAH@Z ; 208 +?SetLeafName@nsFileSpecImpl@@UAGIPBD@Z ; 207 +?SetLeafName@nsFileSpec@@QAEXABVnsString@@@Z ; 203 +??0nsFilePath@@QAE@ABVnsString@@H@Z ; 203 +nsEscapeHTML ; 200 +?SetActivityIsLegal@nsTraceRefcnt@@SAXH@Z ; 198 +?GetProxy@nsCWeakReferent@@QAEPAVnsCWeakProxy@@XZ ; 196 +??0nsCWeakProxy@@QAE@PAXPAVnsCWeakReferent@@@Z ; 196 +??0nsCWeakReferent@@QAE@PAX@Z ; 196 +?ReleaseReference@nsCWeakProxy@@QAEXXZ ; 195 +??_EnsCWeakProxy@@UAEPAXI@Z ; 195 +??1nsCWeakProxy@@UAE@XZ ; 195 +??1nsCWeakReferent@@UAE@XZ ; 195 +nsEscape ; 178 +nsEscapeCount ; 178 +?GetIsOpen@FileImpl@@UAGIPAH@Z ; 177 +?Exists@nsFileSpec@@QBEHXZ ; 173 +?read@nsInputStream@@QAEHPAXH@Z ; 171 +?Read@FileImpl@@UAGIPADIPAI@Z ; 171 +??0nsAutoString@@QAE@G@Z ; 170 +?GetClassObject@nsGenericModule@@UAGIPAVnsIComponentManager@@ABUnsID@@1PAPAX@Z ; 169 +?Get@nsDirectoryService@@UAGIPBDABUnsID@@PAPAX@Z ; 165 +?Seek@nsStorageStream@@AAGIH@Z ; 164 +?SetLength@nsStorageStream@@UAGII@Z ; 164 +?Close@FileImpl@@UAGIXZ ; 163 +?WriteStringZ@nsBinaryOutputStream@@UAGIPBD@Z ; 163 +?AppendElements@nsSupportsArray@@UAGHPAVnsISupportsArray@@@Z ; 162 +?Write8@nsBinaryOutputStream@@UAGIE@Z ; 162 +?AddObserver@nsObserverService@@UAGIPAVnsIObserver@@PBG@Z ; 158 +?AddObserver@nsObserverList@@UAGIPAVnsIObserver@@@Z ; 158 +?read@ConstCharImpl@@MAEHPADI@Z ; 156 +?Read@BasicStringImpl@@UAGIPADIPAI@Z ; 156 +?GetGlobalMemoryService@nsMemory@@SAPAVnsIMemory@@XZ ; 155 +?GetData@nsSupportsStringImpl@@UAGIPAPAD@Z ; 153 +??0nsCAutoString@@QAE@PBDH@Z ; 152 +??0nsObjectHashtable@@QAE@P6APAXPAVnsHashKey@@PAX1@Z1P6AH011@Z1IH@Z ; 140 +??0ArenaImpl@@QAE@XZ ; 139 +?Init@ArenaImpl@@UAGII@Z ; 139 +?Create@ArenaImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 139 +?NS_NewHeapArena@@YAIPAPAVnsIArena@@I@Z ; 139 +?QueryInterface@ArenaImpl@@UAGIABUnsID@@PAPAX@Z ; 139 +??1nsObjectHashtable@@UAE@XZ ; 138 +?Reset@nsObjectHashtable@@QAEXXZ ; 138 +?ResolveLocked@xptiInterfaceInfo@@AAEHPAVxptiWorkingSet@@@Z ; 129 +?GetNext@nsAdapterEnumerator@@UAGIPAPAVnsISupports@@@Z ; 129 +?GetCompleted@nsProxyObjectCallInfo@@QAEHXZ ; 124 +??0CBufDescriptor@@QAE@PBGHIH@Z ; 123 +??0nsServiceEntry@@QAE@ABUnsID@@PAVnsISupports@@@Z ; 122 +?NotifyListeners@nsServiceEntry@@QAEIXZ ; 122 +??1nsServiceEntry@@QAE@XZ ; 122 +?Resolve@xptiInterfaceInfo@@AAEHPAVxptiWorkingSet@@@Z ; 122 +??4nsFileSpec@@QAEXPBD@Z ; 121 +?QueryInterface@nsRegistryNode@@UAGIABUnsID@@PAPAX@Z ; 114 +?RegisterThreadSelf@nsThread@@QAEIXZ ; 114 +?FindSymbol@nsDll@@QAEPAXPBD@Z ; 114 +??_GnsRegistryNode@@UAEPAXI@Z ; 114 +??0nsThread@@QAE@XZ ; 114 +??0nsRegistryNode@@QAE@PAXPADJ@Z ; 114 +?CurrentItem@nsRegSubtreeEnumerator@@UAGIPAPAVnsISupports@@@Z ; 114 +??1nsRegistryNode@@UAE@XZ ; 114 +?Init@nsThread@@UAGIPAVnsIRunnable@@IW4PRThreadPriority@@W4PRThreadScope@@W4PRThreadState@@@Z ; 113 +?NS_NewThread@@YAIPAPAVnsIThread@@PAVnsIRunnable@@IW4PRThreadState@@W4PRThreadPriority@@W4PRThreadScope@@@Z ; 113 +?WaitUntilReadyToStartMain@nsThread@@QAEXXZ ; 113 +?Main@nsThread@@SAXPAX@Z ; 113 +??1ArenaImpl@@UAE@XZ ; 112 +??_GArenaImpl@@UAEPAXI@Z ; 112 +?GetKey@nsRegistryNode@@UAGIPAI@Z ; 112 +?Exit@nsThread@@SAXPAX@Z ; 111 +??1nsThread@@UAE@XZ ; 110 +?GetCurrent@nsIThread@@SAIPAPAV1@@Z ; 110 +??_GnsThread@@UAEPAXI@Z ; 110 +?WriteToLog@xptiInterfaceInfoManager@@SAXPBDZZ ; 110 +?GetIThread@nsIThread@@SAIPAUPRThread@@PAPAV1@@Z ; 110 +?Write@nsPipeOutputStream@nsPipe@@UAGIPBDIPAI@Z ; 109 +?AddThread@nsThreadPool@@IAEIXZ ; 109 +?Run@nsThreadPoolRunnable@@UAGIXZ ; 109 +??0nsThreadPoolRunnable@@QAE@PAVnsThreadPool@@@Z ; 109 +?DeleteLastElement@nsSupportsArray@@UAGIPAVnsISupports@@@Z ; 108 +??_GnsThreadPoolRunnable@@UAEPAXI@Z ; 108 +?RemoveLastElement@nsSupportsArray@@UAGHPBVnsISupports@@@Z ; 108 +?RemoveThread@nsThreadPool@@IAEIPAVnsIThread@@@Z ; 108 +??1nsThreadPoolRunnable@@UAE@XZ ; 108 +?GetNameUTF8@nsRegistryNode@@UAGIPAPAD@Z ; 108 +?RemoveObserver@nsObserverService@@UAGIPAVnsIObserver@@PBG@Z ; 106 +?RemoveObserver@nsObserverList@@UAGIPAVnsIObserver@@@Z ; 106 +?Contains@nsLocalFile@@UAGIPAVnsIFile@@HPAH@Z ; 104 +?RegistryLocationForSpec@nsComponentManagerImpl@@UAGIPAVnsIFile@@PAPAD@Z ; 104 +?Close@ConverterInputStream@@UAGIXZ ; 103 +??1nsDll@@QAE@XZ ; 103 +?Init@nsDll@@AAEXPAVnsIFile@@@Z ; 100 +??0nsDll@@QAE@PAVnsIFile@@PBDPA_J2@Z ; 100 +?SpecForRegistryLocation@nsComponentManagerImpl@@UAGIPBDPAPAVnsIFile@@@Z ; 100 +?UnescapeKey@nsRegistry@@UAGIPAEIPAIPAPAE@Z ; 99 +?GetRegistryDllInfo@nsNativeComponentLoader@@AAEIIPA_J0@Z ; 99 +NS_NewIOFileStream ; 98 +?Open@FileImpl@@UAGIABVnsFileSpec@@HH@Z ; 98 +??1FileImpl@@UAE@XZ ; 98 +??_GFileImpl@@UAEPAXI@Z ; 98 +??0FileImpl@@QAE@ABVnsFileSpec@@HH@Z ; 98 +?HasChanged@nsDll@@QAEHXZ ; 94 +?Read@nsByteArrayInputStream@@UAGIPADIPAI@Z ; 87 +PL_DHashGetStubOps ; 86 +??0nsStorageStream@@QAE@XZ ; 83 +?NS_NewStorageStream@@YAIIIPAPAVnsIStorageStream@@@Z ; 83 +??1nsStorageStream@@UAE@XZ ; 83 +?Init@nsStorageStream@@QAGIIIPAVnsIMemory@@@Z ; 83 +??_EnsStorageStream@@UAEPAXI@Z ; 83 +?GetOutputStream@nsStorageStream@@UAGIHPAPAVnsIOutputStream@@@Z ; 82 +?WriteBytes@nsBinaryOutputStream@@UAGIPBDI@Z ; 82 +??0nsBinaryOutputStream@@QAE@PAVnsIOutputStream@@@Z ; 81 +?Write16@nsBinaryOutputStream@@UAGIG@Z ; 81 +??1nsStorageInputStream@@UAE@XZ ; 81 +?Available@nsStorageInputStream@@UAGIPAI@Z ; 81 +?NewInputStream@nsStorageStream@@UAGIHPAPAVnsIInputStream@@@Z ; 81 +??_EnsStorageInputStream@@UAEPAXI@Z ; 81 +?WriteFloat@nsBinaryOutputStream@@UAGIM@Z ; 81 +?NS_NewBinaryOutputStream@@YAIPAPAVnsIBinaryOutputStream@@PAVnsIOutputStream@@@Z ; 81 +?Release@nsBinaryOutputStream@@UAGKXZ ; 81 +??_EnsBinaryOutputStream@@UAEPAXI@Z ; 81 +?Read@nsStorageInputStream@@UAGIPADIPAI@Z ; 81 +??0nsStorageInputStream@@QAE@PAVnsStorageStream@@I@Z ; 81 +??_EConverterInputStream@@UAEPAXI@Z ; 80 +??0ByteBufferImpl@@QAE@XZ ; 80 +?QueryInterface@nsSupportsPRInt32Impl@@UAGIABUnsID@@PAPAX@Z ; 80 +?NS_NewUnicharBuffer@@YAIPAPAVnsIUnicharBuffer@@PAVnsISupports@@I@Z ; 80 +?NS_NewB2UConverter@@YAIPAPAVnsIUnicodeDecoder@@PAVnsISupports@@PAVnsString@@@Z ; 80 +?QueryInterface@UnicharBufferImpl@@UAGIABUnsID@@PAPAX@Z ; 80 +??1ByteBufferImpl@@UAE@XZ ; 80 +?Init@UnicharBufferImpl@@UAGII@Z ; 80 +??0UnicharBufferImpl@@QAE@XZ ; 80 +?Create@UnicharBufferImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 80 +?NS_NewByteBuffer@@YAIPAPAVnsIByteBuffer@@PAVnsISupports@@I@Z ; 80 +?Init@ByteBufferImpl@@UAGII@Z ; 80 +?QueryInterface@ByteBufferImpl@@UAGIABUnsID@@PAPAX@Z ; 80 +??0ConverterInputStream@@QAE@PAVnsIInputStream@@PAVnsIUnicodeDecoder@@I@Z ; 80 +??1UnicharBufferImpl@@UAE@XZ ; 80 +??_EUnicharBufferImpl@@UAEPAXI@Z ; 80 +?NS_NewConverterStream@@YAIPAPAVnsIUnicharInputStream@@PAVnsISupports@@PAVnsIInputStream@@HPAVnsString@@@Z ; 80 +??_EByteBufferImpl@@UAEPAXI@Z ; 80 +??1ConverterInputStream@@UAE@XZ ; 80 +?Create@ByteBufferImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 80 +?is_open@nsFileClient@@QBEHXZ ; 79 +?GetData@nsSupportsPRBoolImpl@@UAGIPAH@Z ; 78 +??0nsSupportsPRInt32Impl@@QAE@XZ ; 77 +?SetNativePath@nsFileSpecImpl@@UAGIPBD@Z ; 74 +?InsertFromReadable@nsAString@@IAEXABV1@I@Z ; 74 +?ToString@nsSupportsStringImpl@@UAGIPAPAD@Z ; 74 +?IsDone@nsSupportsArrayEnumerator@@UAGIXZ ; 73 +?AllocateBuffers@FileImpl@@IAEIII@Z ; 71 +??1nsOutputStream@@UAE@XZ ; 71 +??_EnsSupportsPRInt32Impl@@UAEPAXI@Z ; 70 +??1nsOutputFileStream@@UAE@XZ ; 70 +?AssignFrom@nsOutputFileStream@@IAEXPAVnsISupports@@@Z ; 70 +??0nsRandomAccessOutputStream@@IAE@XZ ; 70 +??0nsOutputStream@@QAE@PAVnsIOutputStream@@@Z ; 70 +??1nsRandomAccessOutputStream@@UAE@XZ ; 70 +??1nsSupportsPRInt32Impl@@UAE@XZ ; 70 +??0nsDirectoryIterator@@QAE@ABVnsFileSpec@@H@Z ; 68 +??1nsDirectoryIterator@@UAE@XZ ; 68 +?Promises@nsPromiseCConcatenation@@UBEHABVnsACString@@@Z ; 67 +?Length@nsPromiseConcatenation@@UBEIXZ ; 67 +?AppendFromPromise@nsAString@@IAEXABV1@@Z ; 67 +?IndexOf@nsStringArray@@QBEHABVnsAString@@@Z ; 67 +??0nsOutputFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 67 +?Available@nsInputStreamTee@@UAGIPAI@Z ; 66 +?HashContractID@nsComponentManagerImpl@@IAEIPBDABUnsID@@@Z ; 65 +??0nsSubsumeCStr@@QAE@PADHH@Z ; 65 +?close@nsInputStream@@QAEIXZ ; 65 +?HandleEvent@nsEventQueueImpl@@UAGIPAUPLEvent@@@Z ; 62 +?PostAndWait@nsProxyObject@@QAEIPAVnsProxyObjectCallInfo@@@Z ; 62 +?WaitForEvent@nsEventQueueImpl@@UAGIPAPAUPLEvent@@@Z ; 62 +?SetCallersQueue@nsProxyObjectCallInfo@@QAEXPAVnsIEventQueue@@@Z ; 62 +PL_PostSynchronousEvent ; 62 +?PostSynchronousEvent@nsEventQueueImpl@@UAGIPAUPLEvent@@PAPAX@Z ; 62 +PL_WaitForEvent ; 62 +?strcmp@nsCRT@@SAHPBGPBD@Z ; 60 +?ns_file_convert_result@@YAIH@Z ; 60 +?Load@nsLocalFile@@UAGIPAPAUPRLibrary@@@Z ; 54 +?hash_enumerator@@YAHPAVnsHashKey@@PAX1@Z ; 53 +?Shutdown@nsDll@@QAEIXZ ; 53 +??1nsAdapterEnumerator@@UAE@XZ ; 51 +?IsDone@nsHashtableEnumerator@@UAGIXZ ; 51 +?CurrentItem@nsHashtableEnumerator@@UAGIPAPAVnsISupports@@@Z ; 51 +?Next@nsHashtableEnumerator@@UAGIXZ ; 51 +??0nsAdapterEnumerator@@QAE@PAVnsIEnumerator@@@Z ; 51 +??HnsFileSpec@@QBE?AV0@PBD@Z ; 50 +?Read32@nsBinaryInputStream@@UAGIPAI@Z ; 50 +?Available@nsByteArrayInputStream@@UAGIPAI@Z ; 50 +?flush@nsOutputFileStream@@UAEIXZ ; 49 +?RegisterComponentCommon@nsComponentManagerImpl@@IAEIABUnsID@@PBD11HH1@Z ; 48 +??0nsString@@QAE@AAVnsSubsumeStr@@@Z ; 47 +??0nsSubsumeStr@@QAE@PAGHH@Z ; 47 +??0CBufDescriptor@@QAE@PBDHIH@Z ; 46 +?Initialize@nsGenericModule@@IAEIXZ ; 45 +??0nsGenericModule@@QAE@PBDIPAUnsModuleComponentInfo@@P6AXPAVnsIModule@@@Z@Z ; 45 +?CanUnload@nsGenericModule@@UAGIPAVnsIComponentManager@@PAH@Z ; 45 +?Shutdown@nsGenericModule@@IAEXXZ ; 45 +?NS_NewGenericModule@@YAIPBDIPAUnsModuleComponentInfo@@P6AXPAVnsIModule@@@ZPAPAV2@@Z ; 45 +?GetLoaderForType@nsComponentManagerImpl@@IAEIPBDPAPAVnsIComponentLoader@@@Z ; 45 +?QueryInterface@nsGenericModule@@UAGIABUnsID@@PAPAX@Z ; 45 +??_EnsGenericModule@@UAEPAXI@Z ; 45 +??1nsGenericModule@@UAE@XZ ; 45 +?OnRegister@nsNativeComponentLoader@@UAGIABUnsID@@PBD111HH@Z ; 44 +?GetLeafName@nsFileSpecImpl@@UAGIPAPAD@Z ; 44 +?QueryInterface@AtomImpl@@UAGIABUnsID@@PAPAX@Z ; 44 +?find_category@nsCategoryManager@@AAEPAVCategoryNode@@PBD@Z ; 44 +?RegistryNameForLib@nsComponentManagerImpl@@IAEIPBDPAPAD@Z ; 44 +?RegisterComponentLib@nsComponentManager@@SAIABUnsID@@PBD11HH@Z ; 44 +?RegisterComponentLib@nsComponentManagerImpl@@UAGIABUnsID@@PBD11HH@Z ; 44 +?RegisterFactory@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFactory@@H@Z ; 42 +??0nsFactoryEntry@@QAE@ABUnsID@@PAVnsIFactory@@@Z ; 42 +?copy_string@@YAAAV?$ConvertToUpperCase@G@@AAV?$nsWritingIterator@G@@ABV2@AAV1@@Z ; 40 +?ResolveSymlink@nsFileSpec@@QAEIAAH@Z ; 40 +?ToUpperCase@@YAXAAVnsAString@@@Z ; 40 +?advance@nsRegValueEnumerator@@UAGIXZ ; 39 +?Release@nsPersistentProperties@@UAGKXZ ; 39 +?ToNewString@nsString@@QBEPAV1@XZ ; 38 +?IsValid@xptiWorkingSet@@QBEHXZ ; 38 +?GetComponentsDir@xptiInterfaceInfoManager@@QAEHPAPAVnsILocalFile@@@Z ; 37 +??1xptiTypelibGuts@@QAE@XZ ; 36 +??0xptiTypelibGuts@@QAE@PAUXPTHeader@@@Z ; 36 +?LoadFile@xptiInterfaceInfoManager@@QAEHABVxptiTypelib@@PAVxptiWorkingSet@@@Z ; 36 +?SetHeader@xptiFile@@QAEHPAUXPTHeader@@@Z ; 36 +?ReadXPTFile@xptiInterfaceInfoManager@@AAEPAUXPTHeader@@PAVnsILocalFile@@PAVxptiWorkingSet@@@Z ; 36 +?ConvertBreaks@@YAPAGPBGAAHPBD2@Z ; 35 +?ConvertUnicharLineBreaksInSitu@nsLinebreakConverter@@SAIPAPAGW4ELinebreakType@1@1HPAH@Z ; 35 +?CountLinebreaks@@YAHPBGHPBD@Z ; 35 +?FindFactory@nsComponentManager@@SAIABUnsID@@PAPAVnsIFactory@@@Z ; 34 +??1nsRegistryValue@@UAE@XZ ; 32 +??_GnsRegistryValue@@UAEPAXI@Z ; 32 +?getInfo@nsRegistryValue@@IAEIXZ ; 32 +?find_leaf@CategoryNode@@QAEPAVnsCString@@PBD@Z ; 32 +??0nsRegistryValue@@QAE@PAXJK@Z ; 32 +?QueryInterface@nsRegistryValue@@UAGIABUnsID@@PAPAX@Z ; 32 +?GetNameUTF8@nsRegistryValue@@UAGIPAPAD@Z ; 32 +?AddCategoryEntry@nsCategoryManager@@UAGIPBD00HHPAPAD@Z ; 32 +?CurrentItem@nsRegValueEnumerator@@UAGIPAPAVnsISupports@@@Z ; 32 +??1nsInputFileStream@@UAE@XZ ; 29 +??YnsFileSpec@@QAEXABVnsString@@@Z ; 29 +?Release@nsAppFileLocationProvider@@UAGKXZ ; 29 +??0nsInputStream@@QAE@PAVnsIInputStream@@@Z ; 29 +??1nsRandomAccessInputStream@@UAE@XZ ; 29 +??1nsInputStream@@UAE@XZ ; 29 +?IsLowMemory@nsMemoryImpl@@UAGIPAH@Z ; 29 +??8nsFileSpec@@QBEHABV0@@Z ; 28 +?QueryInterface@nsAppFileLocationProvider@@UAGIABUnsID@@PAPAX@Z ; 27 +?copy_string@@YAAAV?$CalculateLength@D@@AAV?$nsReadingIterator@D@@ABV2@AAV1@@Z ; 26 +?Distance@@YAIABV?$nsReadingIterator@D@@0@Z ; 26 +?GetFile@nsAppFileLocationProvider@@UAGIPBDPAHPAPAVnsIFile@@@Z ; 26 +?nsLocalFileConstructor@nsLocalFile@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 26 +?GetFactoryFromNSGetFactory@nsNativeComponentLoader@@AAEIPAVnsDll@@ABUnsID@@PAVnsIServiceManager@@PAPAVnsIFactory@@@Z ; 25 +?Release@nsRegistry@@UAGKXZ ; 25 +?First@nsRegSubtreeEnumerator@@UAGIXZ ; 24 +??1nsRegSubtreeEnumerator@@UAE@XZ ; 24 +??0nsRegSubtreeEnumerator@@QAE@PAXJH@Z ; 24 +?Set@nsDirectoryService@@UAGIPBDPAVnsISupports@@@Z ; 24 +??_GnsRegSubtreeEnumerator@@UAEPAXI@Z ; 24 +??0nsPersistentProperties@@QAE@XZ ; 23 +?Load@nsPersistentProperties@@UAGIPAVnsIInputStream@@@Z ; 23 +?Create@nsPersistentProperties@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 23 +?QueryInterface@nsPersistentProperties@@UAGIABUnsID@@PAPAX@Z ; 23 +??1nsFileURL@@UAE@XZ ; 20 +?SetPersistentDescriptor@nsLocalFile@@UAGIPBD@Z ; 20 +?Close@BasicStringImpl@@UAGIXZ ; 20 +??4nsFileURL@@QAEXABVnsFilePath@@@Z ; 20 +?ReplaceElementAt@nsSupportsArray@@UAGHPAVnsISupports@@I@Z ; 20 +?NS_AllocateContiguousHandleWithData@@YAPAVBuffer@nsSharedBufferList@@PBV12@ABVnsLocalString@@I@Z ; 20 +?QueryInterface@nsRegistry@@UAGIABUnsID@@PAPAX@Z ; 19 +?SetCharAt@nsCString@@QAEHGI@Z ; 19 +??0nsSpecialSystemDirectory@@QAE@W4SystemDirectories@0@@Z ; 18 +?GetFileSize@nsFileSpec@@QBEIXZ ; 18 +?Exists@nsFileSpecImpl@@UAGIPAH@Z ; 18 +?GetSubtree@nsRegistry@@UAGIIPBDPAI@Z ; 18 +??4nsSpecialSystemDirectory@@QAEXW4SystemDirectories@0@@Z ; 18 +??1nsSpecialSystemDirectory@@UAE@XZ ; 18 +??0nsRandomAccessInputStream@@IAE@XZ ; 17 +??0nsObserverList@@QAE@XZ ; 17 +??1nsObserverList@@UAE@XZ ; 17 +?EnumerateSubtrees@nsRegistry@@UAGIIPAPAVnsIEnumerator@@@Z ; 17 +?NS_NewObserverList@@YAIPAPAVnsIObserverList@@@Z ; 17 +?AssignFrom@nsInputFileStream@@IAEXPAVnsISupports@@@Z ; 17 +??0nsInputFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 17 +?QueryInterface@nsObserverList@@UAGIABUnsID@@PAPAX@Z ; 17 +??_GnsObserverList@@UAEPAXI@Z ; 17 +?Unescape@nsSimpleCharString@@QAEXXZ ; 16 +?SetCharAt@nsString@@QAEHGI@Z ; 16 +??1nsOpaqueKey@@UAE@XZ ; 16 +??1nsPersistentProperties@@UAE@XZ ; 16 +??_EnsPersistentProperties@@UAEPAXI@Z ; 16 +??0nsFilePath@@QAE@PBDH@Z ; 16 +??0nsOpaqueKey@@QAE@PBDIW4Ownership@0@@Z ; 16 +?AppendRelativeUnixPath@nsFileSpecImpl@@UAGIPBD@Z ; 15 +??0nsCString@@QAE@PBDH@Z ; 15 +?GetString@nsRegistry@@UAGIIPBGPAPAG@Z ; 15 +?SetStringUTF8@nsRegistry@@UAGIIPBD0@Z ; 15 +?SetString@nsRegistry@@UAGIIPBG0@Z ; 15 +?ReleaseElements@nsHashtableEnumerator@@EAGIXZ ; 14 +PL_GetEventQueueMonitor ; 14 +?ReadStringZ@nsBinaryInputStream@@UAGIPAPAD@Z ; 14 +?EscapeKey@nsRegistry@@UAGIPAEIPAIPAPAE@Z ; 14 +?AppendFromPromise@nsACString@@IAEXABV1@@Z ; 13 +?FindCharInReadable@@YAHDAAV?$nsReadingIterator@D@@ABV1@@Z ; 13 +??0nsPromiseCSubstring@@QAE@ABV?$nsReadingIterator@D@@0@Z ; 13 +?GetName@xptiInterfaceInfo@@UAGIPAPAD@Z ; 12 +?StartAssignmentByReference@nsXPIDLCString@@AAEPAPBDXZ ; 12 +??0nsFileURL@@QAE@ABVnsFileSpec@@@Z ; 12 +?ConvertFromFileSystemCharset@nsFileSpec@@IAEPAGPBD@Z ; 12 +?Read8@nsBinaryInputStream@@UAGIPAE@Z ; 12 +?IsHidden@nsLocalFile@@UAGIPAH@Z ; 12 +?BufferHashCode@nsCRT@@SAIPBDI@Z ; 12 +?GetFileSystemCharset@nsFileSpec@@KAXAAVnsString@@@Z ; 12 +??0nsRandomAccessStoreClient@@QAE@ABV?$nsCOMPtr@VnsIRandomAccessStore@@@@@Z ; 12 +??0nsFileClient@@QAE@ABV?$nsCOMPtr@VnsIOpenFile@@@@@Z ; 12 +?SetLongLong@nsRegistry@@UAGIIPBDPA_J@Z ; 12 +??0nsInputFileStream@@QAE@PAVnsIInputStream@@@Z ; 12 +?HashCode@nsOpaqueKey@@UBEIXZ ; 12 +??0nsRandomAccessInputStream@@QAE@PAVnsIInputStream@@@Z ; 12 +??4nsFileURL@@QAEXABVnsFileSpec@@@Z ; 12 +?AddRef@nsCategoryManager@@UAGKXZ ; 11 +?Release@nsCategoryManager@@UAGKXZ ; 11 +?GetFile@nsDirectoryService@@UAGIPBDPAHPAPAVnsIFile@@@Z ; 11 +??0nsProxyEventClass@@IAE@ABUnsID@@PAVnsIInterfaceInfo@@@Z ; 11 +?Read@nsFileSpecImpl@@UAGIPAPADHPAH@Z ; 11 +?InsertReadable@nsSlidingString@@IAEXABVnsAString@@ABV?$nsReadingIterator@G@@@Z ; 10 +NS_NewTypicalInputFileStream ; 10 +??1nsCommonCString@@UAE@XZ ; 10 +?SplitBuffer@nsSharedBufferList@@QAEXABUPosition@1@W4SplitDisposition@1@@Z ; 10 +?OpenStreamForReading@nsFileSpecImpl@@UAGIXZ ; 10 +PL_IsQueueNative ; 10 +?Release@nsRegistryFactory@@UAGKXZ ; 10 +??0ConstStringImpl@@QAE@ABVnsCString@@@Z ; 10 +?ResolveSymlink@nsFileSpecImpl@@UAGIXZ ; 10 +?IsQueueNative@nsEventQueueImpl@@UAGIPAH@Z ; 10 +??1nsACString@@UAE@XZ ; 10 +?Clone@nsVoidKey@@UBEPAVnsHashKey@@XZ ; 10 +NS_NewCStringInputStream ; 10 +?QueryInterface@nsRegSubtreeEnumerator@@UAGIABUnsID@@PAPAX@Z ; 9 +?GetFileSize@nsFileSpecImpl@@UAGIPAI@Z ; 9 +?GetTypeForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAVnsXPTType@@@Z ; 9 +?Exists@nsDirectoryIteratorImpl@@UAGIPAH@Z ; 9 +?do_InsertFromElement@nsAString@@MAEXGI@Z ; 9 +?Create@nsDirectoryService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 9 +?QueryInterface@nsCategoryManager@@UAGIABUnsID@@PAPAX@Z ; 9 +?GetFileContents@nsFileSpecImpl@@UAGIPAPAD@Z ; 9 +?GetTypeInArray@xptiInterfaceInfo@@EAGIPBVnsXPTParamInfo@@GPAPBUXPTTypeDescriptor@@@Z ; 9 +?IsOpen@nsRegistry@@UAGIPAH@Z ; 9 +?set_at_eof@nsRandomAccessStoreClient@@MAEXH@Z ; 8 +??0nsFilePath@@QAE@ABVnsFileURL@@@Z ; 8 +?GetLengthIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAE@Z ; 8 +?SetAtEOF@FileImpl@@UAGIH@Z ; 8 +?GetSubtreeRaw@nsRegistry@@UAGIIPBDPAI@Z ; 8 +?Delete@nsFileSpec@@QBEXH@Z ; 8 +??_EnsDirEnumerator@@UAEPAXI@Z ; 8 +??_EnsHashtable@@UAEPAXI@Z ; 8 +?ReadBytes@nsBinaryInputStream@@UAGIPAPADI@Z ; 8 +?Next@nsDirectoryIteratorImpl@@UAGIXZ ; 8 +?GetDirectoryEntries@nsLocalFile@@UAGIPAPAVnsISimpleEnumerator@@@Z ; 8 +??0nsFileURL@@QAE@PBDH@Z ; 8 +?EnumerateCategory@nsCategoryManager@@UAGIPBDPAPAVnsISimpleEnumerator@@@Z ; 8 +??0nsDirEnumerator@@QAE@XZ ; 8 +?Put@nsInt2StrHashtable@@QAEIIPBD@Z ; 8 +??0nsFileSpec@@QAE@ABVnsFileURL@@@Z ; 8 +?GetCurrentSpec@nsDirectoryIteratorImpl@@UAGIPAPAVnsIFileSpec@@@Z ; 8 +?Init@nsDirEnumerator@@QAEIPAVnsILocalFile@@@Z ; 8 +??1nsDirEnumerator@@UAE@XZ ; 8 +?MakeAllDirectories@nsFileSpecHelpers@@YAXPBDH@Z ; 8 +?NotifyObservers@nsEventQueueImpl@@AAEXPBD@Z ; 8 +?Reset@nsHashtableEnumerator@@EAGIPAVnsHashtable@@P6GIPAVnsHashKey@@PAX2PAPAVnsISupports@@@Z2@Z ; 7 +NS_NewHashtableEnumerator ; 7 +?GetLeafName@nsFileSpec@@QAEXAAVnsString@@@Z ; 7 +??1nsHashtableEnumerator@@UAE@XZ ; 7 +??0CategoryNode@@QAE@XZ ; 7 +?IsASCII@nsString@@QAEHPBG@Z ; 7 +NS_NewAdapterEnumerator ; 7 +??0nsRegValueEnumerator@@QAE@PAXJ@Z ; 7 +??1nsProxyEventClass@@MAE@XZ ; 7 +?Realloc@nsMemoryImpl@@UAGPAXPAXI@Z ; 7 +?EnterMonitor@nsEventQueueImpl@@UAGIXZ ; 7 +??_EnsHashtableEnumerator@@UAEPAXI@Z ; 7 +?First@nsHashtableEnumerator@@UAGIXZ ; 7 +?RegisterErrorStringBundleKey@nsErrorService@@UAGIIPBD@Z ; 7 +?EnumerateValues@nsRegistry@@UAGIIPAPAVnsIEnumerator@@@Z ; 7 +?GetSizeIsArgNumberForParam@xptiInterfaceInfo@@UAGIGPBVnsXPTParamInfo@@GPAE@Z ; 7 +??0nsHashtableEnumerator@@QAE@PAVnsHashtable@@P6GIPAVnsHashKey@@PAX2PAPAVnsISupports@@@Z2@Z ; 7 +??_EnsAdapterEnumerator@@UAEPAXI@Z ; 7 +?Release@nsComponentManagerImpl@@UAGKXZ ; 7 +??_GCategoryNode@@UAEPAXI@Z ; 7 +?Delete@nsLocalFile@@UAGIH@Z ; 7 +??_GnsProxyEventClass@@MAEPAXI@Z ; 7 +?ExitMonitor@nsEventQueueImpl@@UAGIXZ ; 7 +??0nsBinaryInputStream@@QAE@PAVnsIInputStream@@@Z ; 6 +?OpenWellKnownRegistry@nsRegistry@@UAGIH@Z ; 6 +??0nsStaticCaseInsensitiveNameTable@@QAE@XZ ; 6 +??0nsXPIDLString@@QAE@XZ ; 6 +?NS_NewBinaryInputStream@@YAIPAPAVnsIBinaryInputStream@@PAVnsIInputStream@@@Z ; 6 +?SetYounger@nsEventQueueImpl@@UAGIPAVnsPIEventQueueChain@@@Z ; 6 +?MakeUnique@nsFileSpec@@QAEXXZ ; 6 +?Release@nsBinaryInputStream@@UAGKXZ ; 6 +??_GnsBinaryInputStream@@UAEPAXI@Z ; 6 +?ConvertUnknownBreaks@@YAPADPBDAAH0@Z ; 6 +?Read16@nsBinaryInputStream@@UAGIPAG@Z ; 6 +?AddSubtreeRaw@nsRegistry@@UAGIIPBDPAI@Z ; 6 +?Init@nsStaticCaseInsensitiveNameTable@@QAEHQAPBDH@Z ; 6 +?IsFile@nsFileSpec@@QBEHXZ ; 6 +??0nsFileSpec@@QAE@ABVnsString@@H@Z ; 6 +?ConvertLineBreaks@nsLinebreakConverter@@SAPADPBDW4ELinebreakType@1@1HPAH@Z ; 6 +NS_NewByteInputStream ; 6 +?ReadFloat@nsBinaryInputStream@@UAGIPAM@Z ; 6 +?Realloc@nsMemory@@SAPAXPAXI@Z ; 6 +??1nsStaticCaseInsensitiveNameTable@@QAE@XZ ; 6 +?GetLength@nsStorageStream@@UAGIPAI@Z ; 6 +??_GnsRegistry@@UAEPAXI@Z ; 5 +??_EnsObjectHashtable@@UAEPAXI@Z ; 5 +?CloneMozBinDirectory@nsAppFileLocationProvider@@IAGIPAPAVnsILocalFile@@@Z ; 5 +?StripWhitespace@nsCString@@QAEXXZ ; 5 +??0nsRegistry@@QAE@XZ ; 5 +?MakeNewQueue@nsEventQueueServiceImpl@@EAGIPAUPRThread@@HPAPAVnsIEventQueue@@@Z ; 5 +?StopAcceptingEvents@nsEventQueueImpl@@UAGIXZ ; 5 +??1nsRegistry@@UAE@XZ ; 5 +?Create@nsEventQueueImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 5 +?Close@nsRegistry@@MAGIXZ ; 5 +?CreateInstance@nsRegistryFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 5 +?InitFromPRThread@nsEventQueueImpl@@UAGIPAUPRThread@@H@Z ; 5 +??4nsFileSpec@@QAEXABVnsString@@@Z ; 5 +?NS_FileSpecToIFile@@YAIPAVnsFileSpec@@PAPAVnsILocalFile@@@Z ; 5 +?QueryInterface@nsComponentManagerImpl@@UAGIABUnsID@@PAPAX@Z ; 5 +?GetNativePathString@nsFileSpec@@QAEXAAVnsString@@@Z ; 5 +??0nsEventQueueImpl@@QAE@XZ ; 5 +?do_GetService@@YA?BVnsGetServiceByContractID@@PBDPAI@Z ; 5 +PL_EventAvailable ; 4 +?RFind@nsString@@QBEHABV1@HHH@Z ; 4 +?RegisterComponentSpec@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFile@@HH@Z ; 4 +?FSToNewUCS@nsFSStringConversion@@SAIPBDPAPAG@Z ; 4 +?GetCategoryEntry@nsCategoryManager@@UAGIPBD0PAPAD@Z ; 4 +?RegisterComponentWithType@nsComponentManagerImpl@@UAGIABUnsID@@PBD1PAVnsIFile@@1HH1@Z ; 4 +PL_CreateNativeEventQueue ; 4 +?RemoveStringAt@nsStringArray@@QAEHH@Z ; 4 +?PrepareDecoder@nsFSStringConversion@@CAIXZ ; 4 +?GetName@nsRegistryNode@@UAGIPAPAG@Z ; 4 +?Clone@nsOpaqueKey@@UBEPAVnsHashKey@@XZ ; 4 +?SetBufferSize@nsRegistry@@QAEHH@Z ; 4 +?GetCategoryEntryRaw@nsCategoryManager@@UAGIPBD0PAPAD@Z ; 4 +?AddSubtree@nsRegistry@@UAGIIPBDPAI@Z ; 4 +??_EnsOpaqueKey@@UAEPAXI@Z ; 4 +?GetOutputStream@nsFileSpecImpl@@UAGIPAPAVnsIOutputStream@@@Z ; 3 +NS_NewTypicalOutputFileStream ; 3 +?PushThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAPAVnsIEventQueue@@@Z ; 3 +?QueryInterface@nsConsoleService@@UAGIABUnsID@@PAPAX@Z ; 3 +?PopThreadEventQueue@nsEventQueueServiceImpl@@UAGIPAVnsIEventQueue@@@Z ; 3 +PL_MapEvents ; 3 +?Unlink@nsEventQueueImpl@@UAGIXZ ; 3 +?SetElder@nsEventQueueImpl@@UAGIPAVnsPIEventQueueChain@@@Z ; 3 +?AppendQueue@nsEventQueueImpl@@UAGIPAVnsIEventQueue@@@Z ; 3 +??1nsEventQueueImpl@@UAE@XZ ; 3 +?OpenStreamForWriting@nsFileSpecImpl@@UAGIXZ ; 3 +??0nsOutputFileStream@@QAE@PAVnsIFileSpec@@@Z ; 3 +?LogMessage@nsConsoleService@@UAGIPAVnsIConsoleMessage@@@Z ; 3 +PL_DestroyEventQueue ; 3 +?IsRegistered@nsComponentManagerImpl@@UAGIABUnsID@@PAH@Z ; 3 +?GetCurrentProcessDirectory@nsDirectoryService@@AAEIPAPAVnsILocalFile@@@Z ; 3 +??_EnsEventQueueImpl@@UAEPAXI@Z ; 3 +?CreateDirectory@nsFileSpec@@QAEXH@Z ; 3 +??0nsDll@@QAE@PBDH@Z ; 3 +??1nsAVLTree@@QAE@XZ ; 2 +?NewFileArray@xptiWorkingSet@@QAEHI@Z ; 2 +?ToUpper@nsCRT@@SADD@Z ; 2 +??1nsInt2StrHashtable@@UAE@XZ ; 2 +?GetUnicodeLeafName@nsLocalFile@@UAGIPAPAG@Z ; 2 +?CompareWithConversion@nsString@@QBEHABV1@HH@Z ; 2 +?Read@xptiManifest@@SAHPAVxptiInterfaceInfoManager@@PAVxptiWorkingSet@@@Z ; 2 +??0nsMemoryImpl@@QAE@XZ ; 2 +??1xptiWorkingSet@@QAE@XZ ; 2 +?Create@nsMemoryImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 2 +??0nsRegistryFactory@@QAE@XZ ; 2 +?NS_ErrorAccordingToNSPR@@YAIXZ ; 2 +?ClearHashTables@xptiWorkingSet@@QAEXXZ ; 2 +??_ExptiFile@@QAEPAXI@Z ; 2 +?AppendUnicode@nsLocalFile@@UAGIPBG@Z ; 2 +?Release@MemoryFlusher@@UAGKXZ ; 2 +??_EnsSupportsHashtable@@UAEPAXI@Z ; 2 +?CreateEventQueue@nsEventQueueServiceImpl@@EAGIPAUPRThread@@H@Z ; 2 +??1xptiAutoLog@@QAE@XZ ; 2 +NS_RegistryGetFactory ; 2 +?ClearFiles@xptiWorkingSet@@QAEXXZ ; 2 +??0xptiWorkingSet@@QAE@XZ ; 2 +?Tell@FileImpl@@UAGIPAH@Z ; 2 +?RegisterProvider@nsDirectoryService@@UAGIPAVnsIDirectoryServiceProvider@@@Z ; 2 +?GetKey@nsRegistry@@UAGIIPBGPAI@Z ; 2 +?ClearZipItems@xptiWorkingSet@@QAEXXZ ; 2 +?readline@nsRandomAccessInputStream@@QAEHPADH@Z ; 2 +??0nsAVLTree@@QAE@AAVnsAVLNodeComparitor@@PAVnsAVLNodeFunctor@@@Z ; 2 +?GetManifestDir@xptiInterfaceInfoManager@@QAEHPAPAVnsILocalFile@@@Z ; 2 +??0xptiAutoLog@@QAE@PAVxptiInterfaceInfoManager@@PAVnsILocalFile@@H@Z ; 2 +?tell@nsRandomAccessStoreClient@@QAEHXZ ; 2 +NS_NewUnicodeLocalFile ; 2 +??0nsInt2StrHashtable@@QAE@XZ ; 2 +?seek@nsRandomAccessStoreClient@@QAEXW4PRSeekWhence@@H@Z ; 2 +?Open@nsRegistry@@UAGIPBD@Z ; 2 +?QueryInterface@nsErrorService@@UAGIABUnsID@@PAPAX@Z ; 2 +?RegisterService@nsServiceManagerImpl@@UAGIABUnsID@@PAVnsISupports@@@Z ; 2 +?Seek@FileImpl@@UAGIW4PRSeekWhence@@H@Z ; 2 +?GetUnicodePath@nsLocalFile@@UAGIPAPAG@Z ; 2 +?AddRef@MemoryFlusher@@UAGKXZ ; 2 +?PrepareFSCharset@nsFSStringConversion@@CAIXZ ; 2 +??_EnsDirectoryService@@UAEPAXI@Z ; 1 +?NS_ShutdownXPCOM@@YAIPAVnsIServiceManager@@@Z ; 1 +?AutoRegister@nsComponentManagerImpl@@UAGIHPAVnsIFile@@@Z ; 1 +?OnShutdown@HandleCaseConversionShutdown3@@UAGIABUnsID@@PAVnsISupports@@@Z ; 1 +?GetParent@nsFileSpec@@QBEXAAV1@@Z ; 1 +??1nsConsoleService@@UAE@XZ ; 1 +??0nsComponentManagerImpl@@QAE@XZ ; 1 +?PlatformVersionCheck@nsComponentManagerImpl@@IAEIPAI@Z ; 1 +?PlatformInit@nsComponentManagerImpl@@IAEIXZ ; 1 +??_EnsAppFileLocationProvider@@MAEPAXI@Z ; 1 +??_EnsVoidArray@@UAEPAXI@Z ; 1 +??RnsGetServiceFromCategory@@UBEIABUnsID@@PAPAX@Z ; 1 +??0nsIOFileStream@@QAE@ABVnsFileSpec@@HH@Z ; 1 +?NS_PurgeAtomTable@@YAXXZ ; 1 +??0nsProxyObjectManager@@QAE@XZ ; 1 +?NS_NewThreadPool@@YAIPAPAVnsIThreadPool@@IIIW4PRThreadPriority@@W4PRThreadScope@@@Z ; 1 +?GetNext@EmptyEnumeratorImpl@@UAGIPAPAVnsISupports@@@Z ; 1 +??_GxptiInterfaceInfoManager@@UAEPAXI@Z ; 1 +?ReallocLastSegment@nsSegmentedBuffer@@QAEHI@Z ; 1 +??0nsNativeComponentLoader@@QAE@XZ ; 1 +?Init@nsComponentManagerImpl@@QAEIXZ ; 1 +?CreateMonitoredThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +?UnloadLibraries@nsComponentManagerImpl@@IAEIPAVnsIServiceManager@@H@Z ; 1 +?Run@MemoryFlusher@@UAGIXZ ; 1 +??1nsDirectoryService@@UAE@XZ ; 1 +?SetRegistryDllInfo@nsNativeComponentLoader@@AAEIPBDPA_J1@Z ; 1 +??1nsDirectoryIteratorImpl@@UAE@XZ ; 1 +?DestroyThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +?GetInt@nsRegistry@@UAGIIPBDPAH@Z ; 1 +??0MemoryFlusher@@IAE@PAVnsMemoryImpl@@@Z ; 1 +?EnumerateBackwards@nsCStringArray@@QAEHP6AHAAVnsCString@@PAX@Z1@Z ; 1 +?GetParent@nsFileSpecImpl@@UAGIPAPAVnsIFileSpec@@@Z ; 1 +?BuildFileList@xptiInterfaceInfoManager@@AAEHPAPAVnsISupportsArray@@@Z ; 1 +??1nsServiceManagerImpl@@MAE@XZ ; 1 +??1nsObserverService@@UAE@XZ ; 1 +?GetRegistryDllInfo@nsNativeComponentLoader@@AAEIPBDPA_J1@Z ; 1 +?Shutdown@nsMemoryImpl@@SAIXZ ; 1 +NS_CategoryManagerGetFactory ; 1 +?Create@nsProxyObjectManager@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??_EnsDirectoryIteratorImpl@@UAEPAXI@Z ; 1 +??1nsAppFileLocationProvider@@MAE@XZ ; 1 +?GetProductDirectory@nsAppFileLocationProvider@@IAGIPAPAVnsILocalFile@@@Z ; 1 +??0?$nsCOMPtr@VnsIServiceManager@@@@QAE@ABVnsCOMPtr_helper@@@Z ; 1 +??_EnsNativeComponentLoader@@UAEPAXI@Z ; 1 +?Create@nsObserverService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??0nsCategoryManager@@AAE@XZ ; 1 +??1nsIOFileStream@@UAE@XZ ; 1 +??1nsCategoryManager@@UAE@XZ ; 1 +?InvalidateInterfaceInfos@xptiWorkingSet@@QAEXXZ ; 1 +?PlatformPrePopulateRegistry@nsComponentManagerImpl@@QAEIXZ ; 1 +?NS_InitXPCOM2@@YAIPAPAVnsIServiceManager@@PAVnsIFile@@PAVnsIDirectoryServiceProvider@@@Z ; 1 +??_EnsDirectoryIterator@@UAEPAXI@Z ; 1 +?IsValid@xptiInterfaceInfoManager@@AAEHXZ ; 1 +?Shutdown@xptiZipLoader@@SAXXZ ; 1 +?Init@nsDirectoryService@@UAGIXZ ; 1 +?Create@nsErrorService@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +?RegisterDeferredComponents@nsNativeComponentLoader@@UAGIHPAH@Z ; 1 +?Shutdown@nsComponentManagerImpl@@QAEIXZ ; 1 +?Shutdown@nsThread@@SAXXZ ; 1 +?Sync@nsDll@@QAEIXZ ; 1 +?Startup@nsMemoryImpl@@SAIXZ ; 1 +?Define@nsDirectoryService@@UAGIPBDPAVnsISupports@@@Z ; 1 +?SetMainThread@nsIThread@@SAIXZ ; 1 +?ShutdownSpecialSystemDirectory@@YAXXZ ; 1 +?Init@nsNativeComponentLoader@@UAGIPAVnsIComponentManager@@PAVnsISupports@@@Z ; 1 +??0nsCategoryManagerFactory@@QAE@XZ ; 1 +?RegisterErrorStringBundle@nsErrorService@@UAGIFPBD@Z ; 1 +??0nsDirectoryService@@QAE@XZ ; 1 +?RegisterFactory@nsComponentManager@@SAIABUnsID@@PBD1PAVnsIFactory@@H@Z ; 1 +?AutoRegisterImpl@nsComponentManagerImpl@@AAEIHPAVnsIFile@@@Z ; 1 +?DetermineAutoRegStrategy@xptiInterfaceInfoManager@@AAE?AW4AutoRegMode@1@PAVnsISupportsArray@@PAVxptiWorkingSet@@@Z ; 1 +??0nsAppFileLocationProvider@@QAE@XZ ; 1 +??1MemoryFlusher@@MAE@XZ ; 1 +?Create@nsLocalFile@@UAGIII@Z ; 1 +?Join@nsThread@@UAGIXZ ; 1 +??_GnsProxyObjectManager@@UAEPAXI@Z ; 1 +?LogStats@xptiInterfaceInfoManager@@AAEXXZ ; 1 +?Valid@nsFileSpec@@QBEHXZ ; 1 +?NS_InitXPCOM@@YAIPAPAVnsIServiceManager@@PAVnsIFile@@@Z ; 1 +?ShutdownGlobalServiceManager@nsServiceManager@@SAIPAPAVnsIServiceManager@@@Z ; 1 +??1xptiInterfaceInfoManager@@UAE@XZ ; 1 +??_GnsComponentManagerImpl@@UAEPAXI@Z ; 1 +?FreeInterfaceInfoManager@xptiInterfaceInfoManager@@SAXXZ ; 1 +?Create@MemoryFlusher@@SAIPAPAV1@PAVnsMemoryImpl@@@Z ; 1 +??_EnsErrorService@@UAEPAXI@Z ; 1 +??1nsProxyObjectManager@@UAE@XZ ; 1 +??0nsConsoleService@@QAE@XZ ; 1 +?AutoRegisterComponents@nsNativeComponentLoader@@UAGIHPAVnsIFile@@@Z ; 1 +?AutoRegister@nsComponentManager@@SAIHPAVnsIFile@@@Z ; 1 +?QueryInterface@nsDirectoryIteratorImpl@@UAGIABUnsID@@PAPAX@Z ; 1 +??_EMemoryFlusher@@MAEPAXI@Z ; 1 +?initialize@nsCategoryManager@@AAEIXZ ; 1 +?AutoRegisterInterfaces@xptiInterfaceInfoManager@@UAGIXZ ; 1 +PL_CreateMonitoredEventQueue ; 1 +??_GnsCategoryManager@@UAEPAXI@Z ; 1 +?Close@nsStorageStream@@UAGIXZ ; 1 +?Init@nsThreadPool@@UAGIIIIW4PRThreadPriority@@W4PRThreadScope@@@Z ; 1 +??0nsObserverService@@QAE@XZ ; 1 +?Create@nsEventQueueServiceImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??0xptiInterfaceInfoManager@@AAE@XZ ; 1 +?GetDllSpec@nsDll@@QAEIPAPAVnsIFile@@@Z ; 1 +??_EnsServiceManagerImpl@@MAEPAXI@Z ; 1 +?SelfRegisterDll@nsNativeComponentLoader@@AAEIPAVnsDll@@PBDH@Z ; 1 +?UnloadAll@nsNativeComponentLoader@@UAGIH@Z ; 1 +??0?$nsCOMPtr@VnsIOutputStream@@@@QAE@ABVnsCOMPtr_helper@@@Z ; 1 +?Undefine@nsDirectoryService@@UAGIPBD@Z ; 1 +??0nsDirectoryIteratorImpl@@QAE@XZ ; 1 +??0CCaseConversionServiceInitializer@@QAE@XZ ; 1 +??1nsComponentManagerImpl@@UAE@XZ ; 1 +?RegisterComponentsInDir@nsNativeComponentLoader@@MAGIHPAVnsIFile@@@Z ; 1 +??0nsEventQueueServiceImpl@@QAE@XZ ; 1 +?CreateInstance@nsCategoryManagerFactory@@UAGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 +??_GnsObserverService@@UAEPAXI@Z ; 1 +XPTI_FreeInterfaceInfoManager ; 1 +?Stop@MemoryFlusher@@QAEIXZ ; 1 +?CreateThreadEventQueue@nsEventQueueServiceImpl@@UAGIXZ ; 1 +??0nsServiceManagerImpl@@QAE@XZ ; 1 +??1nsNativeComponentLoader@@UAE@XZ ; 1 +??0nsThreadPool@@QAE@XZ ; 1 +?NS_ShutdownLocalFile@@YAXXZ ; 1 +??_GHandleCaseConversionShutdown3@@UAEPAXI@Z ; 1 +?Init@nsDirectoryIteratorImpl@@UAGIPAVnsIFileSpec@@H@Z ; 1 +??0nsErrorService@@QAE@XZ ; 1 +??_EnsConsoleService@@UAEPAXI@Z ; 1 +??0nsSlidingSubstring@@QAE@ABVnsAString@@@Z ; 1 +?CleanUp@nsFSStringConversion@@SAXXZ ; 1 +?Create@nsDirectoryIteratorImpl@@SGIPAVnsISupports@@ABUnsID@@PAPAX@Z ; 1 diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg b/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg new file mode 100644 index 00000000..8a32b21f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom-tests.pkg @@ -0,0 +1,47 @@ +[xpcom-tests] +#if USE_SHORT_LIBNAME +dist/bin/components/@DLLP@tdynamic@DLLS@ +dist/bin/components/@DLLP@MyServce@DLLS@ +dist/bin/components/@DLLP@xpcomsmp@DLLS@ +#else +dist/bin/components/@DLLP@testdynamic@DLLS@ +dist/bin/components/@DLLP@MyService@DLLS@ +dist/bin/components/@DLLP@xpcomsample@DLLS@ +#endif +dist/bin/components/nsSample.js +!xpt dist/bin/components/xpcomsample.xpt +dist/bin/nsTestSample@BINS@ +dist/bin/res/test.properties +dist/bin/res/samples/xpconnect-sample.html +!xpt dist/bin/components/proxytest.xpt +dist/bin/proxytests@BINS@ + +dist/bin/PrimitiveTest@BINS@ +dist/bin/SimpleTypeLib@BINS@ +dist/bin/TestInterfaceInfo@BINS@ +dist/bin/TestXPTCInvoke@BINS@ + +dist/bin/nsIFileEnumerator@BINS@ +dist/bin/nsIFileTest@BINS@ +dist/bin/TestArray@BINS@ +dist/bin/TestAtoms@BINS@ +dist/bin/TestAutoLock@BINS@ +dist/bin/TestCallTemplates@BINS@ +dist/bin/TestCOMPtr@BINS@ +dist/bin/TestCOMPtrEq@BINS@ +dist/bin/TestCRT@BINS@ +dist/bin/TestFactory@BINS@ +dist/bin/TestHashtables@BINS@ +dist/bin/TestID@BINS@ +dist/bin/TestObserverService@BINS@ +dist/bin/TestPermanentAtoms@BINS@ +dist/bin/TestPipes@BINS@ +dist/bin/TestServMgr@BINS@ +dist/bin/TestThreads@BINS@ +dist/bin/TestXPIDLString@BINS@ +dist/bin/TestDeque@BINS@ +dist/bin/TestAutoPtr@BINS@ + +#if OS_ARCH==WINNT +dist/bin/TestCOM.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom.pkg b/src/libs/xpcom18a4/xpcom/build/xpcom.pkg new file mode 100644 index 00000000..eab0e19d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom.pkg @@ -0,0 +1,106 @@ +[xpcom] +dist/bin/@DLLP@xpcom@DLLS@ +!xpt dist/bin/components/xpcom_base.xpt +!xpt dist/bin/components/xpcom_components.xpt +!xpt dist/bin/components/xpcom_ds.xpt +!xpt dist/bin/components/xpcom_io.xpt +!xpt dist/bin/components/xpcom_xpti.xpt + +#if OS_ARCH==WINNT +!xpt dist/bin/components/xpcom_thread.xpt +!xpt dist/bin/components/proxyObject.xpt +#else +!xpt dist/bin/components/xpcom_threads.xpt +!xpt dist/bin/components/proxyObjInst.xpt +#endif + +[gecko-support] +dist/bin/regxpcom@BINS@ +dist/bin/xpt_dump@BINS@ +dist/bin/xpt_link@BINS@ +#if MOZ_DEBUG +#if OS_ARCH==WINNT +dist/bin/windbgdlg.exe +#endif +#endif + +# xpidl.exe is not licensed MPL, so we don't include it with applications. +# It is only included in the developer (SDK) packages. +[gecko-devel] +dist/bin/xpidl@BINS@ + +# put NSPR here, because hacking the NSPR build system is too painful +# xxxbsmedberg: this doesn't obey --with-system-nspr +[nspr] +dist/bin/@DLLP@nspr4@DLLS@ +dist/bin/@DLLP@plc4@DLLS@ +dist/bin/@DLLP@plds4@DLLS@ + +[nspr-devel] +dist/lib/@LIBP@nspr4@LIBS@ +dist/lib/@LIBP@plc4@LIBS@ +dist/lib/@LIBP@plds4@LIBS@ +dist/include/nspr/private/pprio.h +dist/include/nspr/private/pprthred.h +dist/include/nspr/private/prpriv.h +dist/include/nspr/prcpucfg.h +dist/include/nspr/obsolete/pralarm.h +dist/include/nspr/obsolete/probslet.h +dist/include/nspr/obsolete/protypes.h +dist/include/nspr/obsolete/prsem.h +dist/include/nspr/nspr.h +dist/include/nspr/pratom.h +dist/include/nspr/prbit.h +dist/include/nspr/prclist.h +dist/include/nspr/prcmon.h +dist/include/nspr/prcountr.h +dist/include/nspr/prcvar.h +dist/include/nspr/prdtoa.h +dist/include/nspr/prenv.h +dist/include/nspr/prerr.h +dist/include/nspr/prerror.h +dist/include/nspr/prinet.h +dist/include/nspr/prinit.h +dist/include/nspr/prinrval.h +dist/include/nspr/prio.h +dist/include/nspr/pripcsem.h +dist/include/nspr/prlink.h +dist/include/nspr/prlock.h +dist/include/nspr/prlog.h +dist/include/nspr/prlong.h +dist/include/nspr/prmem.h +dist/include/nspr/prmon.h +dist/include/nspr/prmwait.h +dist/include/nspr/prnetdb.h +dist/include/nspr/prolock.h +dist/include/nspr/prpdce.h +dist/include/nspr/prprf.h +dist/include/nspr/prproces.h +dist/include/nspr/prrng.h +dist/include/nspr/prrwlock.h +dist/include/nspr/prshma.h +dist/include/nspr/prshm.h +dist/include/nspr/prsystem.h +dist/include/nspr/prthread.h +dist/include/nspr/prtime.h +dist/include/nspr/prtpool.h +dist/include/nspr/prtrace.h +dist/include/nspr/prtypes.h +dist/include/nspr/prvrsion.h +dist/include/nspr/prwin16.h +dist/include/nspr/plarenas.h +dist/include/nspr/plarena.h +dist/include/nspr/plhash.h +dist/include/nspr/plbase64.h +dist/include/nspr/plerror.h +dist/include/nspr/plgetopt.h +dist/include/nspr/plresolv.h +dist/include/nspr/plstr.h + +[unpackaged-files] +!optional dist/bin/.autoreg +!optional dist/bin/components/xpti.dat +!optional dist/bin/components/compreg.dat +#if OS_ARCH==WINNT +dist/bin/rebasedlls.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def b/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def new file mode 100644 index 00000000..966f2ea4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/build/xpcom_alpha.def @@ -0,0 +1,252 @@ +LIBRARY xpcom +DESCRIPTION "xpcom library" + +EXPORTS + ?Stub3@nsXPTCStubBase@@UAAIXZ + ?Stub4@nsXPTCStubBase@@UAAIXZ + ?Stub5@nsXPTCStubBase@@UAAIXZ + ?Stub6@nsXPTCStubBase@@UAAIXZ + ?Stub7@nsXPTCStubBase@@UAAIXZ + ?Stub8@nsXPTCStubBase@@UAAIXZ + ?Stub9@nsXPTCStubBase@@UAAIXZ + ?Stub10@nsXPTCStubBase@@UAAIXZ + ?Stub11@nsXPTCStubBase@@UAAIXZ + ?Stub12@nsXPTCStubBase@@UAAIXZ + ?Stub13@nsXPTCStubBase@@UAAIXZ + ?Stub14@nsXPTCStubBase@@UAAIXZ + ?Stub15@nsXPTCStubBase@@UAAIXZ + ?Stub16@nsXPTCStubBase@@UAAIXZ + ?Stub17@nsXPTCStubBase@@UAAIXZ + ?Stub18@nsXPTCStubBase@@UAAIXZ + ?Stub19@nsXPTCStubBase@@UAAIXZ + ?Stub20@nsXPTCStubBase@@UAAIXZ + ?Stub21@nsXPTCStubBase@@UAAIXZ + ?Stub22@nsXPTCStubBase@@UAAIXZ + ?Stub23@nsXPTCStubBase@@UAAIXZ + ?Stub24@nsXPTCStubBase@@UAAIXZ + ?Stub25@nsXPTCStubBase@@UAAIXZ + ?Stub26@nsXPTCStubBase@@UAAIXZ + ?Stub27@nsXPTCStubBase@@UAAIXZ + ?Stub28@nsXPTCStubBase@@UAAIXZ + ?Stub29@nsXPTCStubBase@@UAAIXZ + ?Stub30@nsXPTCStubBase@@UAAIXZ + ?Stub31@nsXPTCStubBase@@UAAIXZ + ?Stub32@nsXPTCStubBase@@UAAIXZ + ?Stub33@nsXPTCStubBase@@UAAIXZ + ?Stub34@nsXPTCStubBase@@UAAIXZ + ?Stub35@nsXPTCStubBase@@UAAIXZ + ?Stub36@nsXPTCStubBase@@UAAIXZ + ?Stub37@nsXPTCStubBase@@UAAIXZ + ?Stub38@nsXPTCStubBase@@UAAIXZ + ?Stub39@nsXPTCStubBase@@UAAIXZ + ?Stub40@nsXPTCStubBase@@UAAIXZ + ?Stub41@nsXPTCStubBase@@UAAIXZ + ?Stub42@nsXPTCStubBase@@UAAIXZ + ?Stub43@nsXPTCStubBase@@UAAIXZ + ?Stub44@nsXPTCStubBase@@UAAIXZ + ?Stub45@nsXPTCStubBase@@UAAIXZ + ?Stub46@nsXPTCStubBase@@UAAIXZ + ?Stub47@nsXPTCStubBase@@UAAIXZ + ?Stub48@nsXPTCStubBase@@UAAIXZ + ?Stub49@nsXPTCStubBase@@UAAIXZ + ?Stub50@nsXPTCStubBase@@UAAIXZ + ?Stub51@nsXPTCStubBase@@UAAIXZ + ?Stub52@nsXPTCStubBase@@UAAIXZ + ?Stub53@nsXPTCStubBase@@UAAIXZ + ?Stub54@nsXPTCStubBase@@UAAIXZ + ?Stub55@nsXPTCStubBase@@UAAIXZ + ?Stub56@nsXPTCStubBase@@UAAIXZ + ?Stub57@nsXPTCStubBase@@UAAIXZ + ?Stub58@nsXPTCStubBase@@UAAIXZ + ?Stub59@nsXPTCStubBase@@UAAIXZ + ?Stub60@nsXPTCStubBase@@UAAIXZ + ?Stub61@nsXPTCStubBase@@UAAIXZ + ?Stub62@nsXPTCStubBase@@UAAIXZ + ?Stub63@nsXPTCStubBase@@UAAIXZ + ?Stub64@nsXPTCStubBase@@UAAIXZ + ?Stub65@nsXPTCStubBase@@UAAIXZ + ?Stub66@nsXPTCStubBase@@UAAIXZ + ?Stub67@nsXPTCStubBase@@UAAIXZ + ?Stub68@nsXPTCStubBase@@UAAIXZ + ?Stub69@nsXPTCStubBase@@UAAIXZ + ?Stub70@nsXPTCStubBase@@UAAIXZ + ?Stub71@nsXPTCStubBase@@UAAIXZ + ?Stub72@nsXPTCStubBase@@UAAIXZ + ?Stub73@nsXPTCStubBase@@UAAIXZ + ?Stub74@nsXPTCStubBase@@UAAIXZ + ?Stub75@nsXPTCStubBase@@UAAIXZ + ?Stub76@nsXPTCStubBase@@UAAIXZ + ?Stub77@nsXPTCStubBase@@UAAIXZ + ?Stub78@nsXPTCStubBase@@UAAIXZ + ?Stub79@nsXPTCStubBase@@UAAIXZ + ?Stub80@nsXPTCStubBase@@UAAIXZ + ?Stub81@nsXPTCStubBase@@UAAIXZ + ?Stub82@nsXPTCStubBase@@UAAIXZ + ?Stub83@nsXPTCStubBase@@UAAIXZ + ?Stub84@nsXPTCStubBase@@UAAIXZ + ?Stub85@nsXPTCStubBase@@UAAIXZ + ?Stub86@nsXPTCStubBase@@UAAIXZ + ?Stub87@nsXPTCStubBase@@UAAIXZ + ?Stub88@nsXPTCStubBase@@UAAIXZ + ?Stub89@nsXPTCStubBase@@UAAIXZ + ?Stub90@nsXPTCStubBase@@UAAIXZ + ?Stub91@nsXPTCStubBase@@UAAIXZ + ?Stub92@nsXPTCStubBase@@UAAIXZ + ?Stub93@nsXPTCStubBase@@UAAIXZ + ?Stub94@nsXPTCStubBase@@UAAIXZ + ?Stub95@nsXPTCStubBase@@UAAIXZ + ?Stub96@nsXPTCStubBase@@UAAIXZ + ?Stub97@nsXPTCStubBase@@UAAIXZ + ?Stub98@nsXPTCStubBase@@UAAIXZ + ?Stub99@nsXPTCStubBase@@UAAIXZ + ?Stub100@nsXPTCStubBase@@UAAIXZ + ?Stub101@nsXPTCStubBase@@UAAIXZ + ?Stub102@nsXPTCStubBase@@UAAIXZ + ?Stub103@nsXPTCStubBase@@UAAIXZ + ?Stub104@nsXPTCStubBase@@UAAIXZ + ?Stub105@nsXPTCStubBase@@UAAIXZ + ?Stub106@nsXPTCStubBase@@UAAIXZ + ?Stub107@nsXPTCStubBase@@UAAIXZ + ?Stub108@nsXPTCStubBase@@UAAIXZ + ?Stub109@nsXPTCStubBase@@UAAIXZ + ?Stub110@nsXPTCStubBase@@UAAIXZ + ?Stub111@nsXPTCStubBase@@UAAIXZ + ?Stub112@nsXPTCStubBase@@UAAIXZ + ?Stub113@nsXPTCStubBase@@UAAIXZ + ?Stub114@nsXPTCStubBase@@UAAIXZ + ?Stub115@nsXPTCStubBase@@UAAIXZ + ?Stub116@nsXPTCStubBase@@UAAIXZ + ?Stub117@nsXPTCStubBase@@UAAIXZ + ?Stub118@nsXPTCStubBase@@UAAIXZ + ?Stub119@nsXPTCStubBase@@UAAIXZ + ?Stub120@nsXPTCStubBase@@UAAIXZ + ?Stub121@nsXPTCStubBase@@UAAIXZ + ?Stub122@nsXPTCStubBase@@UAAIXZ + ?Stub123@nsXPTCStubBase@@UAAIXZ + ?Stub124@nsXPTCStubBase@@UAAIXZ + ?Stub125@nsXPTCStubBase@@UAAIXZ + ?Stub126@nsXPTCStubBase@@UAAIXZ + ?Stub127@nsXPTCStubBase@@UAAIXZ + ?Stub128@nsXPTCStubBase@@UAAIXZ + ?Stub129@nsXPTCStubBase@@UAAIXZ + ?Stub130@nsXPTCStubBase@@UAAIXZ + ?Stub131@nsXPTCStubBase@@UAAIXZ + ?Stub132@nsXPTCStubBase@@UAAIXZ + ?Stub133@nsXPTCStubBase@@UAAIXZ + ?Stub134@nsXPTCStubBase@@UAAIXZ + ?Stub135@nsXPTCStubBase@@UAAIXZ + ?Stub136@nsXPTCStubBase@@UAAIXZ + ?Stub137@nsXPTCStubBase@@UAAIXZ + ?Stub138@nsXPTCStubBase@@UAAIXZ + ?Stub139@nsXPTCStubBase@@UAAIXZ + ?Stub140@nsXPTCStubBase@@UAAIXZ + ?Stub141@nsXPTCStubBase@@UAAIXZ + ?Stub142@nsXPTCStubBase@@UAAIXZ + ?Stub143@nsXPTCStubBase@@UAAIXZ + ?Stub144@nsXPTCStubBase@@UAAIXZ + ?Stub145@nsXPTCStubBase@@UAAIXZ + ?Stub146@nsXPTCStubBase@@UAAIXZ + ?Stub147@nsXPTCStubBase@@UAAIXZ + ?Stub148@nsXPTCStubBase@@UAAIXZ + ?Stub149@nsXPTCStubBase@@UAAIXZ + ?Stub150@nsXPTCStubBase@@UAAIXZ + ?Stub151@nsXPTCStubBase@@UAAIXZ + ?Stub152@nsXPTCStubBase@@UAAIXZ + ?Stub153@nsXPTCStubBase@@UAAIXZ + ?Stub154@nsXPTCStubBase@@UAAIXZ + ?Stub155@nsXPTCStubBase@@UAAIXZ + ?Stub156@nsXPTCStubBase@@UAAIXZ + ?Stub157@nsXPTCStubBase@@UAAIXZ + ?Stub158@nsXPTCStubBase@@UAAIXZ + ?Stub159@nsXPTCStubBase@@UAAIXZ + ?Stub160@nsXPTCStubBase@@UAAIXZ + ?Stub161@nsXPTCStubBase@@UAAIXZ + ?Stub162@nsXPTCStubBase@@UAAIXZ + ?Stub163@nsXPTCStubBase@@UAAIXZ + ?Stub164@nsXPTCStubBase@@UAAIXZ + ?Stub165@nsXPTCStubBase@@UAAIXZ + ?Stub166@nsXPTCStubBase@@UAAIXZ + ?Stub167@nsXPTCStubBase@@UAAIXZ + ?Stub168@nsXPTCStubBase@@UAAIXZ + ?Stub169@nsXPTCStubBase@@UAAIXZ + ?Stub170@nsXPTCStubBase@@UAAIXZ + ?Stub171@nsXPTCStubBase@@UAAIXZ + ?Stub172@nsXPTCStubBase@@UAAIXZ + ?Stub173@nsXPTCStubBase@@UAAIXZ + ?Stub174@nsXPTCStubBase@@UAAIXZ + ?Stub175@nsXPTCStubBase@@UAAIXZ + ?Stub176@nsXPTCStubBase@@UAAIXZ + ?Stub177@nsXPTCStubBase@@UAAIXZ + ?Stub178@nsXPTCStubBase@@UAAIXZ + ?Stub179@nsXPTCStubBase@@UAAIXZ + ?Stub180@nsXPTCStubBase@@UAAIXZ + ?Stub181@nsXPTCStubBase@@UAAIXZ + ?Stub182@nsXPTCStubBase@@UAAIXZ + ?Stub183@nsXPTCStubBase@@UAAIXZ + ?Stub184@nsXPTCStubBase@@UAAIXZ + ?Stub185@nsXPTCStubBase@@UAAIXZ + ?Stub186@nsXPTCStubBase@@UAAIXZ + ?Stub187@nsXPTCStubBase@@UAAIXZ + ?Stub188@nsXPTCStubBase@@UAAIXZ + ?Stub189@nsXPTCStubBase@@UAAIXZ + ?Stub190@nsXPTCStubBase@@UAAIXZ + ?Stub191@nsXPTCStubBase@@UAAIXZ + ?Stub192@nsXPTCStubBase@@UAAIXZ + ?Stub193@nsXPTCStubBase@@UAAIXZ + ?Stub194@nsXPTCStubBase@@UAAIXZ + ?Stub195@nsXPTCStubBase@@UAAIXZ + ?Stub196@nsXPTCStubBase@@UAAIXZ + ?Stub197@nsXPTCStubBase@@UAAIXZ + ?Stub198@nsXPTCStubBase@@UAAIXZ + ?Stub199@nsXPTCStubBase@@UAAIXZ + ?Stub200@nsXPTCStubBase@@UAAIXZ + ?Stub201@nsXPTCStubBase@@UAAIXZ + ?Stub202@nsXPTCStubBase@@UAAIXZ + ?Stub203@nsXPTCStubBase@@UAAIXZ + ?Stub204@nsXPTCStubBase@@UAAIXZ + ?Stub205@nsXPTCStubBase@@UAAIXZ + ?Stub206@nsXPTCStubBase@@UAAIXZ + ?Stub207@nsXPTCStubBase@@UAAIXZ + ?Stub208@nsXPTCStubBase@@UAAIXZ + ?Stub209@nsXPTCStubBase@@UAAIXZ + ?Stub210@nsXPTCStubBase@@UAAIXZ + ?Stub211@nsXPTCStubBase@@UAAIXZ + ?Stub212@nsXPTCStubBase@@UAAIXZ + ?Stub213@nsXPTCStubBase@@UAAIXZ + ?Stub214@nsXPTCStubBase@@UAAIXZ + ?Stub215@nsXPTCStubBase@@UAAIXZ + ?Stub216@nsXPTCStubBase@@UAAIXZ + ?Stub217@nsXPTCStubBase@@UAAIXZ + ?Stub218@nsXPTCStubBase@@UAAIXZ + ?Stub219@nsXPTCStubBase@@UAAIXZ + ?Stub220@nsXPTCStubBase@@UAAIXZ + ?Stub221@nsXPTCStubBase@@UAAIXZ + ?Stub222@nsXPTCStubBase@@UAAIXZ + ?Stub223@nsXPTCStubBase@@UAAIXZ + ?Stub224@nsXPTCStubBase@@UAAIXZ + ?Stub225@nsXPTCStubBase@@UAAIXZ + ?Stub226@nsXPTCStubBase@@UAAIXZ + ?Stub227@nsXPTCStubBase@@UAAIXZ + ?Stub228@nsXPTCStubBase@@UAAIXZ + ?Stub229@nsXPTCStubBase@@UAAIXZ + ?Stub230@nsXPTCStubBase@@UAAIXZ + ?Stub231@nsXPTCStubBase@@UAAIXZ + ?Stub232@nsXPTCStubBase@@UAAIXZ + ?Stub233@nsXPTCStubBase@@UAAIXZ + ?Stub234@nsXPTCStubBase@@UAAIXZ + ?Stub235@nsXPTCStubBase@@UAAIXZ + ?Stub236@nsXPTCStubBase@@UAAIXZ + ?Stub237@nsXPTCStubBase@@UAAIXZ + ?Stub238@nsXPTCStubBase@@UAAIXZ + ?Stub239@nsXPTCStubBase@@UAAIXZ + ?Stub240@nsXPTCStubBase@@UAAIXZ + ?Stub241@nsXPTCStubBase@@UAAIXZ + ?Stub242@nsXPTCStubBase@@UAAIXZ + ?Stub243@nsXPTCStubBase@@UAAIXZ + ?Stub244@nsXPTCStubBase@@UAAIXZ + ?Stub245@nsXPTCStubBase@@UAAIXZ + ?Stub246@nsXPTCStubBase@@UAAIXZ + ?Stub247@nsXPTCStubBase@@UAAIXZ + ?Stub248@nsXPTCStubBase@@UAAIXZ + ?Stub249@nsXPTCStubBase@@UAAIXZ + diff --git a/src/libs/xpcom18a4/xpcom/components/.cvsignore b/src/libs/xpcom18a4/xpcom/components/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/components/Makefile.in b/src/libs/xpcom18a4/xpcom/components/Makefile.in new file mode 100644 index 00000000..68614854 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/Makefile.in @@ -0,0 +1,107 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_components +LIBRARY_NAME = xpcomcomponents_s +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +CPPSRCS = \ + nsCategoryManager.cpp \ + nsComponentManager.cpp \ + nsComponentManagerObsolete.cpp \ + nsNativeComponentLoader.cpp \ + nsServiceManagerObsolete.cpp \ + xcDll.cpp \ + $(NULL) + +ifdef MOZ_STATIC_COMPONENT_LOADER +CPPSRCS += nsStaticComponentLoader.cpp +endif + +EXPORTS = \ + nsCategoryManagerUtils.h \ + nsComponentManagerUtils.h \ + nsComponentManagerObsolete.h \ + nsIServiceManagerUtils.h \ + nsIServiceManagerObsolete.h \ + nsModule.h \ + nsNativeComponentLoader.h \ + nsStaticComponent.h \ + nsObsoleteModuleLoading.h \ + xcDll.h \ + $(NULL) + +XPIDLSRCS = \ + nsIComponentLoader.idl \ + nsIComponentLoaderManager.idl \ + nsIComponentManagerObsolete.idl \ + nsINativeComponentLoader.idl \ + $(NULL) + +SDK_XPIDLSRCS = \ + nsIClassInfo.idl \ + nsIComponentRegistrar.idl \ + nsIFactory.idl \ + nsIModule.idl \ + nsIServiceManager.idl \ + nsIComponentManager.idl \ + nsICategoryManager.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +LOCAL_INCLUDES = -I$(srcdir)/../base -I$(srcdir)/../thread -I$(srcdir)/../ds -I.. + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp new file mode 100644 index 00000000..d7202bdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp @@ -0,0 +1,799 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#define PL_ARENA_CONST_ALIGN_MASK 7 + +#include "nsICategoryManager.h" +#include "nsCategoryManager.h" + +#include "plarena.h" +#include "prio.h" +#include "prprf.h" +#include "prlock.h" +#include "nsCOMPtr.h" +#include "nsTHashtable.h" +#include "nsClassHashtable.h" +#include "nsIFactory.h" +#include "nsIStringEnumerator.h" +#include "nsSupportsPrimitives.h" +#include "nsIServiceManagerUtils.h" +#include "nsIObserver.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsEnumeratorUtils.h" + +class nsIComponentLoaderManager; + +/* + CategoryDatabase + contains 0 or more 1-1 mappings of string to Category + each Category contains 0 or more 1-1 mappings of string keys to string values + + In other words, the CategoryDatabase is a tree, whose root is a hashtable. + Internal nodes (or Categories) are hashtables. Leaf nodes are strings. + + The leaf strings are allocated in an arena, because we assume they're not + going to change much ;) +*/ + +#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8) + +// pulled in from nsComponentManager.cpp +char* ArenaStrdup(const char* s, PLArenaPool* aArena); + +// +// BaseStringEnumerator is subclassed by EntryEnumerator and +// CategoryEnumerator +// +class BaseStringEnumerator + : public nsISimpleEnumerator, + nsIUTF8StringEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + NS_DECL_NSIUTF8STRINGENUMERATOR + +protected: + BaseStringEnumerator() + : mArray(nsnull), + mCount(0), + mSimpleCurItem(0), + mStringCurItem(0) { } + + // A virtual destructor is needed here because subclasses of + // BaseStringEnumerator do not implement their own Release() method. + + virtual ~BaseStringEnumerator() + { + if (mArray) + delete[] mArray; + } + + const char** mArray; + PRUint32 mCount; + PRUint32 mSimpleCurItem; + PRUint32 mStringCurItem; +}; + +NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator) + +NS_IMETHODIMP +BaseStringEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = (mSimpleCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsISupports **_retval) +{ + if (mSimpleCurItem >= mCount) + return NS_ERROR_FAILURE; + + nsSupportsDependentCString* str = + new nsSupportsDependentCString(mArray[mSimpleCurItem++]); + if (!str) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = str; + NS_ADDREF(*_retval); + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::HasMore(PRBool *_retval) +{ + *_retval = (mStringCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsACString& _retval) +{ + if (mStringCurItem >= mCount) + return NS_ERROR_FAILURE; + + _retval = nsDependentCString(mArray[mStringCurItem++]); + return NS_OK; +} + + +// +// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory +// +class EntryEnumerator + : public BaseStringEnumerator +{ +public: + static EntryEnumerator* Create(nsTHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg); +}; + + +PLDHashOperator PR_CALLBACK +EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg) +{ + EntryEnumerator* mythis = NS_STATIC_CAST(EntryEnumerator*, userArg); + mythis->mArray[mythis->mCount++] = aLeaf->GetKey(); + + return PL_DHASH_NEXT; +} + +EntryEnumerator* +EntryEnumerator::Create(nsTHashtable& aTable) +{ + EntryEnumerator* enumObj = new EntryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new char const* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateEntries(enumfunc_createenumerator, enumObj); + + return enumObj; +} + + +// +// CategoryNode implementations +// + +CategoryNode* +CategoryNode::Create(PLArenaPool* aArena) +{ + CategoryNode* node = new(aArena) CategoryNode(); + if (!node) + return nsnull; + + if (!node->mTable.Init()) { + delete node; + return nsnull; + } + + node->mLock = PR_NewLock(); + if (!node->mLock) { + delete node; + return nsnull; + } + + return node; +} + +CategoryNode::~CategoryNode() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +void* +CategoryNode::operator new(size_t aSize, PLArenaPool* aArena) +{ + void* p; + PL_ARENA_ALLOCATE(p, aArena, aSize); + return p; +} + +NS_METHOD +CategoryNode::GetLeaf(const char* aEntryName, + char** _retval) +{ + PR_Lock(mLock); + nsresult rv = NS_ERROR_NOT_AVAILABLE; + CategoryLeaf* ent = + mTable.GetEntry(aEntryName); + + // we only want the non-persistent value + if (ent && ent->nonpValue) { + *_retval = nsCRT::strdup(ent->nonpValue); + if (*_retval) + rv = NS_OK; + } + PR_Unlock(mLock); + + return rv; +} + +NS_METHOD +CategoryNode::AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena) +{ + PR_Lock(mLock); + CategoryLeaf* leaf = + mTable.GetEntry(aEntryName); + + nsresult rv = NS_OK; + if (leaf) { + //if the entry was found, aReplace must be specified + if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue ))) + rv = NS_ERROR_INVALID_ARG; + } else { + const char* arenaEntryName = ArenaStrdup(aEntryName, aArena); + if (!arenaEntryName) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf = mTable.PutEntry(arenaEntryName); + if (!leaf) + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + if (NS_SUCCEEDED(rv)) { + const char* arenaValue = ArenaStrdup(aValue, aArena); + if (!arenaValue) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf->nonpValue = arenaValue; + if (aPersist) + leaf->pValue = arenaValue; + } + } + + PR_Unlock(mLock); + return rv; +} + +NS_METHOD +CategoryNode::DeleteLeaf(const char* aEntryName, + PRBool aDontPersist) +{ + // we don't throw any errors, because it normally doesn't matter + // and it makes JS a lot cleaner + PR_Lock(mLock); + + if (aDontPersist) { + // we can just remove the entire hash entry without introspection + mTable.RemoveEntry(aEntryName); + } else { + // if we are keeping the persistent value, we need to look at + // the contents of the current entry + CategoryLeaf* leaf = mTable.GetEntry(aEntryName); + if (leaf) { + if (leaf->pValue) { + leaf->nonpValue = nsnull; + } else { + // if there is no persistent value, just remove the entry + mTable.RawRemoveEntry(leaf); + } + } + } + PR_Unlock(mLock); + + return NS_OK; +} + +NS_METHOD +CategoryNode::Enumerate(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + EntryEnumerator* enumObj = EntryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct persistent_userstruct { + PRFileDesc* fd; + const char* categoryName; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg) +{ + persistent_userstruct* args = + NS_STATIC_CAST(persistent_userstruct*, userArg); + + PLDHashOperator status = PL_DHASH_NEXT; + + if (aLeaf->pValue) { + if (PR_fprintf(args->fd, + "%s,%s,%s\n", + args->categoryName, + aLeaf->GetKey(), + aLeaf->pValue) == (PRUint32) -1) { + args->success = PR_FALSE; + status = PL_DHASH_STOP; + } + } + + return status; +} + +PRBool +CategoryNode::WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName) +{ + persistent_userstruct args = { + fd, + aCategoryName, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateEntries(enumfunc_pentries, &args); + PR_Unlock(mLock); + + return args.success; +} + + +// +// CategoryEnumerator class +// + +class CategoryEnumerator + : public BaseStringEnumerator +{ +public: + static CategoryEnumerator* Create(nsClassHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(const char* aStr, + CategoryNode* aNode, + void* userArg); +}; + +CategoryEnumerator* +CategoryEnumerator::Create(nsClassHashtable& aTable) +{ + CategoryEnumerator* enumObj = new CategoryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new const char* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateRead(enumfunc_createenumerator, enumObj); + + return enumObj; +} + +PLDHashOperator PR_CALLBACK +CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg) +{ + CategoryEnumerator* mythis = NS_STATIC_CAST(CategoryEnumerator*, userArg); + + // if a category has no entries, we pretend it doesn't exist + if (aNode->Count()) + mythis->mArray[mythis->mCount++] = aStr; + + return PL_DHASH_NEXT; +} + + +// +// nsCategoryManager implementations +// + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCategoryManager, nsICategoryManager) + +nsCategoryManager* +nsCategoryManager::Create() +{ + nsCategoryManager* manager = new nsCategoryManager(); + + if (!manager) + return nsnull; + + PL_INIT_ARENA_POOL(&(manager->mArena), "CategoryManagerArena", + NS_CATEGORYMANAGER_ARENA_SIZE); // this never fails + + if (!manager->mTable.Init()) { + delete manager; + return nsnull; + } + + manager->mLock = PR_NewLock(); + + if (!manager->mLock) { + delete manager; + return nsnull; + } + + return manager; +} + +nsCategoryManager::~nsCategoryManager() +{ + if (mLock) + PR_DestroyLock(mLock); + + // the hashtable contains entries that must be deleted before the arena is + // destroyed, or else you will have PRLocks undestroyed and other Really + // Bad Stuff (TM) + mTable.Clear(); + + PL_FinishArenaPool(&mArena); +} + +inline CategoryNode* +nsCategoryManager::get_category(const char* aName) { + CategoryNode* node; + if (!mTable.Get(aName, &node)) { + return nsnull; + } + return node; +} + +NS_IMETHODIMP +nsCategoryManager::GetCategoryEntry( const char *aCategoryName, + const char *aEntryName, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(_retval); + + nsresult status = NS_ERROR_NOT_AVAILABLE; + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) { + status = category->GetLeaf(aEntryName, _retval); + } + + return status; +} + +NS_IMETHODIMP +nsCategoryManager::AddCategoryEntry( const char *aCategoryName, + const char *aEntryName, + const char *aValue, + PRBool aPersist, + PRBool aReplace, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(aValue); + + // Before we can insert a new entry, we'll need to + // find the |CategoryNode| to put it in... + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + + if (!category) { + // That category doesn't exist yet; let's make it. + category = CategoryNode::Create(&mArena); + + char* categoryName = ArenaStrdup(aCategoryName, &mArena); + mTable.Put(categoryName, category); + } + PR_Unlock(mLock); + + if (!category) + return NS_ERROR_OUT_OF_MEMORY; + + return category->AddLeaf(aEntryName, + aValue, + aPersist, + aReplace, + _retval, + &mArena); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, + const char *aEntryName, + PRBool aDontPersist) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + + /* + Note: no errors are reported since failure to delete + probably won't hurt you, and returning errors seriously + inconveniences JS clients + */ + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) + return NS_OK; + + return category->DeleteLeaf(aEntryName, + aDontPersist); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategory( const char *aCategoryName ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + + // the categories are arena-allocated, so we don't + // actually delete them. We just remove all of the + // leaf nodes. + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) + category->Clear(); + + return NS_OK; +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategory( const char *aCategoryName, + nsISimpleEnumerator **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) { + return NS_NewEmptyEnumerator(_retval); + } + + return category->Enumerate(_retval); +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct writecat_struct { + PRFileDesc* fd; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg) +{ + writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg); + + PLDHashOperator result = PL_DHASH_NEXT; + + if (!aCategory->WritePersistentEntries(args->fd, aKey)) { + args->success = PR_FALSE; + result = PL_DHASH_STOP; + } + + return result; +} + +NS_METHOD +nsCategoryManager::WriteCategoryManagerToRegistry(PRFileDesc* fd) +{ + writecat_struct args = { + fd, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateRead(enumfunc_categories, &args); + PR_Unlock(mLock); + + if (!args.success) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +class nsCategoryManagerFactory : public nsIFactory + { + public: + nsCategoryManagerFactory() { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + }; + +NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory) + +NS_IMETHODIMP +nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult ) + { + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = 0; + + nsresult status = NS_OK; + if ( aOuter ) + status = NS_ERROR_NO_AGGREGATION; + else + { + nsCategoryManager* raw_category_manager = nsCategoryManager::Create(); + nsCOMPtr new_category_manager = raw_category_manager; + if ( new_category_manager ) + status = new_category_manager->QueryInterface(aIID, aResult); + else + status = NS_ERROR_OUT_OF_MEMORY; + } + + return status; + } + +NS_IMETHODIMP +nsCategoryManagerFactory::LockFactory( PRBool ) + { + // Not implemented... + return NS_OK; + } + +nsresult +NS_CategoryManagerGetFactory( nsIFactory** aFactory ) + { + // assert(aFactory); + + nsresult status; + + *aFactory = 0; + nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory); + if (new_factory) + { + *aFactory = new_factory; + NS_ADDREF(*aFactory); + status = NS_OK; + } + else + status = NS_ERROR_OUT_OF_MEMORY; + + return status; + } + + + +/* + * CreateServicesFromCategory() + * + * Given a category, this convenience functions enumerates the category and + * creates a service of every CID or ContractID registered under the category. + * If observerTopic is non null and the service implements nsIObserver, + * this will attempt to notify the observer with the origin, observerTopic string + * as parameter. + */ +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic) +{ + nsresult rv = NS_OK; + + int nFailed = 0; + nsCOMPtr categoryManager = + do_GetService("@mozilla.org/categorymanager;1", &rv); + if (!categoryManager) return rv; + + nsCOMPtr enumerator; + rv = categoryManager->EnumerateCategory(category, + getter_AddRefs(enumerator)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr entry; + while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) { + // From here on just skip any error we get. + nsCOMPtr catEntry = do_QueryInterface(entry, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsCAutoString entryString; + rv = catEntry->GetData(entryString); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsXPIDLCString contractID; + rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID)); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + nsCOMPtr instance = do_GetService(contractID, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + if (observerTopic) { + // try an observer, if it implements it. + nsCOMPtr observer = do_QueryInterface(instance, &rv); + if (NS_SUCCEEDED(rv) && observer) + observer->Observe(origin, observerTopic, EmptyString().get()); + } + } + return (nFailed ? NS_ERROR_FAILURE : NS_OK); +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h new file mode 100644 index 00000000..a5cdb59a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 NSCATEGORYMANAGER_H +#define NSCATEGORYMANAGER_H + +#include "prio.h" +#include "prlock.h" +#include "plarena.h" +#include "nsClassHashtable.h" +#include "nsICategoryManager.h" + +#define NS_CATEGORYMANAGER_CLASSNAME "Category Manager" + +/* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */ +#define NS_CATEGORYMANAGER_CID \ +{ 0x16d222a6, 0x1dd2, 0x11b2, \ + {0xb6, 0x93, 0xf3, 0x8b, 0x02, 0xc0, 0x21, 0xb2} } + +/** + * a "leaf-node", managed by the nsCategoryNode hashtable. + * + * we need to keep a "persistent value" (which will be written to the registry) + * and a non-persistent value (for the current runtime): these are usually + * the same, except when aPersist==PR_FALSE. The strings are permanently arena- + * allocated, and will never go away. + */ +class CategoryLeaf : public nsDepCharHashKey +{ +public: + CategoryLeaf(const char* aKey) + : nsDepCharHashKey(aKey), + pValue(nsnull), + nonpValue(nsnull) { } + const char* pValue; + const char* nonpValue; +}; + + +/** + * CategoryNode keeps a hashtable of it's entries. + * the CategoryNode itself is permanently allocated in + * the arena. + */ +class CategoryNode +{ +public: + NS_METHOD GetLeaf(const char* aEntryName, + char** _retval); + + NS_METHOD AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena); + + NS_METHOD DeleteLeaf(const char* aEntryName, + PRBool aDontPersist); + + void Clear() { + PR_Lock(mLock); + mTable.Clear(); + PR_Unlock(mLock); + } + + PRUint32 Count() { + PR_Lock(mLock); + PRUint32 tCount = mTable.Count(); + PR_Unlock(mLock); + return tCount; + } + + NS_METHOD Enumerate(nsISimpleEnumerator** _retval); + + PRBool WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName); + + // CategoryNode is arena-allocated, with the strings + static CategoryNode* Create(PLArenaPool* aArena); + ~CategoryNode(); + void operator delete(void*) { } + +private: + CategoryNode() : mLock(nsnull) { } + void* operator new(size_t aSize, PLArenaPool* aArena); + + nsTHashtable mTable; + PRLock* mLock; +}; + + +/** + * The main implementation of nsICategoryManager. + * + * This implementation is thread-safe. + */ +class nsCategoryManager + : public nsICategoryManager +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICATEGORYMANAGER + + /** + * Write the categories to the XPCOM persistent registry. + * This is to be used by nsComponentManagerImpl (and NO ONE ELSE). + */ + NS_METHOD WriteCategoryManagerToRegistry(PRFileDesc* fd); + + nsCategoryManager() : mLock(nsnull) { } +private: + friend class nsCategoryManagerFactory; + static nsCategoryManager* Create(); + + ~nsCategoryManager(); + + CategoryNode* get_category(const char* aName); + + PLArenaPool mArena; + nsClassHashtable mTable; + PRLock* mLock; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h new file mode 100644 index 00000000..54a9fcec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsCategoryManagerUtils_h__ +#define nsCategoryManagerUtils_h__ + +#include "nsICategoryManager.h" +#include "nsCOMPtr.h" + +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic); + +class NS_COM nsCreateInstanceFromCategory : public nsCOMPtr_helper +{ +public: + nsCreateInstanceFromCategory(const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mErrorPtr(aErrorPtr) + { + // nothing else to do; + } + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** aInstancePtr) const; + +private: + const char *mCategory; // Do not free. This char * is not owned. + const char *mEntry; // Do not free. This char * is not owned. + + nsISupports *mOuter; + nsresult *mErrorPtr; + +}; + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, 0, aErrorPtr); +} + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, aOuter, aErrorPtr); +} + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp new file mode 100644 index 00000000..980b0565 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp @@ -0,0 +1,3794 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ +#include +#include "nscore.h" +#include "nsISupports.h" +#include "nspr.h" +#include "nsCRT.h" // for atoll +// Arena used by component manager for storing contractid string, dll +// location strings and small objects +// CAUTION: Arena align mask needs to be defined before including plarena.h +// currently from nsComponentManager.h +#define PL_ARENA_CONST_ALIGN_MASK 7 +#define NS_CM_BLOCK_SIZE (1024 * 8) + +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCategoryManager.h" +#include "nsCategoryManagerUtils.h" +#include "nsIComponentLoader.h" +#include "nsIEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIModule.h" +#include "nsIObserverService.h" +#include "nsISimpleEnumerator.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsLocalFile.h" +#include "nsNativeComponentLoader.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "prcmon.h" +#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself... + +#include "nsInt64.h" +#include "nsManifestLineReader.h" + +#include NEW_H // for placement new + + +#ifdef XP_BEOS +#include +#include +#endif + +#include "prlog.h" + +PRLogModuleInfo* nsComponentManagerLog = nsnull; + +#if 0 || defined (DEBUG_timeless) + #define SHOW_DENIED_ON_SHUTDOWN + #define SHOW_CI_ON_EXISTING_SERVICE + #define XPCOM_CHECK_PENDING_CIDS +#endif + +// Loader Types +#define NS_LOADER_DATA_ALLOC_STEP 6 + +// Bloated registry buffer size to improve startup performance -- needs to +// be big enough to fit the entire file into memory or it'll thrash. +// 512K is big enough to allow for some future growth in the registry. +#define BIG_REGISTRY_BUFLEN (512*1024) + +// Common Key Names +const char classIDKeyName[]="classID"; +const char classesKeyName[]="contractID"; +const char componentLoadersKeyName[]="componentLoaders"; +const char componentsKeyName[]="components"; +const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components"; +const char xpcomKeyName[]="software/mozilla/XPCOM"; + +// Common Value Names +const char classIDValueName[]="ClassID"; +const char classNameValueName[]="ClassName"; +const char componentCountValueName[]="ComponentsCount"; +const char componentTypeValueName[]="ComponentType"; +const char contractIDValueName[]="ContractID"; +const char fileSizeValueName[]="FileSize"; +const char inprocServerValueName[]="InprocServer"; +const char lastModValueName[]="LastModTimeStamp"; +const char nativeComponentType[]="application/x-mozilla-native"; +const char staticComponentType[]="application/x-mozilla-static"; +const char versionValueName[]="VersionString"; + +const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:"; +const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:"; +const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:"; + +static const char gIDFormat[] = + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"; + + +#define NS_EMPTY_IID \ +{ \ + 0x00000000, \ + 0x0000, \ + 0x0000, \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \ +} + +NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID); +NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); + +#define UID_STRING_LENGTH 39 + +// Set to true from NS_ShutdownXPCOM. +extern PRBool gXPCOMShuttingDown; + +static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH]) +{ + PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat, + aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2, + (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1], + (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3], + (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5], + (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]); +} + +nsresult +nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + /* + * If I were a real man, I would consolidate this with + * nsGetServiceFromContractID::operator(). + */ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr compMgr; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + + if (NS_FAILED(rv)) goto error; + + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + NS_GetComponentManager(getter_AddRefs(compMgr)); + if (!compMgr) + return NS_ERROR_FAILURE; + compMgr->CreateInstanceByContractID(value, + mOuter, + aIID, + aInstancePtr); + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + + *mErrorPtr = rv; + return rv; +} + + +nsresult +nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + if (NS_FAILED(rv)) goto error; + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + if (mServiceManager) { + rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + rv = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + *mErrorPtr = rv; + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// +// Arena helper functions +//////////////////////////////////////////////////////////////////////////////// +char * +ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena) +{ + void *mem; + // Include trailing null in the len + PL_ARENA_ALLOCATE(mem, arena, len+1); + if (mem) + memcpy(mem, s, len+1); + return NS_STATIC_CAST(char *, mem); +} + +char* +ArenaStrdup(const char *s, PLArenaPool *arena) +{ + return ArenaStrndup(s, strlen(s), arena); +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Callbacks +//////////////////////////////////////////////////////////////////////////////// + +PRBool PR_CALLBACK +nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure); + +PR_STATIC_CALLBACK(const void *) +factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + return &entry->mFactoryEntry->mCid; +} + +PR_STATIC_CALLBACK(PLDHashNumber) +factory_HashKey(PLDHashTable *aTable, const void *aKey) +{ + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return cidp->m0; +} + +PR_STATIC_CALLBACK(PRBool) +factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr, + const void *aKey) +{ + const nsFactoryTableEntry* entry = + NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr); + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return (entry->mFactoryEntry->mCid).Equals(*cidp); +} + +PR_STATIC_CALLBACK(void) +factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps factory_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + factory_GetKey, + factory_HashKey, + factory_MatchEntry, + PL_DHashMoveEntryStub, + factory_ClearEntry, + PL_DHashFinalizeStub, +}; + +PR_STATIC_CALLBACK(void) +contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY && + entry->mFactoryEntry->mCid.Equals(kEmptyCID)) { + // this object is owned by the hash. + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + } + + // contractIDs are arena allocated. No need to free them. + + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps contractID_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + contractID_ClearEntry, + PL_DHashFinalizeStub, +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsFactoryEntry +//////////////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(nsFactoryEntry) +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + const char *aLocation, + PRUint32 locationlen, + int aType, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(aType), mParent(parent) +{ + // Arena allocate the location string + mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena); +} + +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + nsIFactory *aFactory, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY), mParent(parent) +{ + mFactory = aFactory; + mLocation = nsnull; +} + +// nsFactoryEntry is usually arena allocated including the strings it +// holds. So we call destructor by hand. +nsFactoryEntry::~nsFactoryEntry(void) +{ + // Release the reference to the factory + mFactory = nsnull; + + // Release any service reference + mServiceObject = nsnull; + + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + if (mParent) + mParent->~nsFactoryEntry(); +} + +nsresult +nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType) +{ + NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG); + // cid has to match + // SERVICE_ONLY entries can be promoted to an entry of another type + NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)), + NS_ERROR_INVALID_ARG); + + // Arena allocate the location string + mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena); + + mTypeIndex = aType; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Enumeration +//////////////////////////////////////////////////////////////////////////////// +typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, + nsISupports **retval); + +class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator, + public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIENUMERATOR + NS_DECL_NSIBIDIRECTIONALENUMERATOR + NS_DECL_NSISIMPLEENUMERATOR + + PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData); + PRInt32 Count() { return mCount; } +private: + PLDHashTableEnumeratorImpl(); /* no implementation */ + + ~PLDHashTableEnumeratorImpl(); + NS_IMETHODIMP ReleaseElements(); + + nsVoidArray mElements; + PRInt32 mCount, mCurrent; + PRMonitor* mMonitor; + + struct Closure { + PRBool succeeded; + EnumeratorConverter converter; + void *data; + PLDHashTableEnumeratorImpl *impl; + }; + + static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data); +}; + +// static +PLDHashOperator PR_CALLBACK +PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data) +{ + Closure *c = NS_REINTERPRET_CAST(Closure *, data); + nsISupports *converted; + if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) || + !c->impl->mElements.AppendElement(converted)) { + c->succeeded = PR_FALSE; + return PL_DHASH_STOP; + } + + c->succeeded = PR_TRUE; + return PL_DHASH_NEXT; +} + +PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData) +: mCurrent(0) +{ + mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl"); + NS_ASSERTION(mMonitor, "NULL Monitor"); + + nsAutoMonitor mon(mMonitor); + + Closure c = { PR_FALSE, converter, converterData, this }; + mCount = PL_DHashTableEnumerate(table, Enumerator, &c); + if (!c.succeeded) { + ReleaseElements(); + mCount = 0; + } +} + +NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl, + nsIBidirectionalEnumerator, + nsIEnumerator, + nsISimpleEnumerator) + +PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl() +{ + (void) ReleaseElements(); + + // Destroy the Lock + if (mMonitor) + nsAutoMonitor::DestroyMonitor(mMonitor); +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::ReleaseElements() +{ + for (PRInt32 i = 0; i < mCount; i++) { + nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *, + mElements[i]); + NS_IF_RELEASE(supports); + } + return NS_OK; +} + +NS_IMETHODIMP +PL_NewDHashTableEnumerator(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData, + PLDHashTableEnumeratorImpl **retval) +{ + PLDHashTableEnumeratorImpl *impl = + new PLDHashTableEnumeratorImpl(table, converter, converterData); + + if (!impl) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(impl); + + if (impl->Count() == -1) { + // conversion failed + NS_RELEASE(impl); + return NS_ERROR_FAILURE; + } + + *retval = impl; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::First() +{ + if (!mCount) + return NS_ERROR_FAILURE; + + mCurrent = 0; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Last() +{ + if (!mCount) + return NS_ERROR_FAILURE; + mCurrent = mCount - 1; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Prev() +{ + if (!mCurrent) + return NS_ERROR_FAILURE; + + mCurrent--; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Next() +{ + // If empty or we're past the end, or we are at the end return error + if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval) +{ + if (!mCount || mCurrent == mCount) + return NS_ERROR_FAILURE; + + *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]); + if (*retval) + NS_ADDREF(*retval); + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::IsDone() +{ + if (!mCount || (mCurrent == mCount)) + return NS_OK; + + return NS_ENUMERATOR_FALSE; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval) +{ + if (!mCount || (mCurrent == mCount)) + *_retval = PR_FALSE; + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval) +{ + nsresult rv = Next(); + if (NS_FAILED(rv)) return rv; + + return CurrentItem(_retval); +} + +static NS_IMETHODIMP +ConvertFactoryEntryToCID(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsFactoryTableEntry *entry = + NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr); + if (entry) { + nsFactoryEntry *fe = entry->mFactoryEntry; + + wrapper->SetData(&fe->mCid); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; + } + *retval = nsnull; + + return rv; +} + +static NS_IMETHODIMP +ConvertContractIDKeyToString(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsContractIDTableEntry *entry = + NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr); + + wrapper->SetData(nsDependentCString(entry->mContractID, + entry->mContractIDLen)); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; +} + +// this is safe to call during InitXPCOM +static nsresult GetLocationFromDirectoryService(const char* prop, + nsIFile** aDirectory) +{ + nsCOMPtr directoryService; + nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(directoryService)); + + if (!directoryService) + return NS_ERROR_FAILURE; + + return directoryService->Get(prop, + NS_GET_IID(nsIFile), + (void**)aDirectory); +} + + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl +//////////////////////////////////////////////////////////////////////////////// + + +nsComponentManagerImpl::nsComponentManagerImpl() + : + mMon(NULL), + mNativeComponentLoader(0), +#ifdef ENABLE_STATIC_COMPONENT_LOADER + mStaticComponentLoader(0), +#endif + mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED), + mLoaderData(nsnull), + mRegistryDirty(PR_FALSE) +{ + mFactories.ops = nsnull; + mContractIDs.ops = nsnull; +} + +nsresult nsComponentManagerImpl::Init(void) +{ + PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS); + if (mShuttingDown == NS_SHUTDOWN_INPROGRESS) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED; + + if (nsComponentManagerLog == nsnull) + { + nsComponentManagerLog = PR_NewLogModule("nsComponentManager"); + } + + // Initialize our arena + PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE); + + if (!mFactories.ops) { + if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps, + 0, sizeof(nsFactoryTableEntry), + 1024)) { + mFactories.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=2 because nsFactoryTableEntry saves two + // words compared to what a chained hash table requires. + PL_DHashTableSetAlphaBounds(&mFactories, + 0.875, + PL_DHASH_MIN_ALPHA(&mFactories, 2)); + } + + if (!mContractIDs.ops) { + if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps, + 0, sizeof(nsContractIDTableEntry), + 1024)) { + mContractIDs.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=1 because nsContractIDTableEntry saves one + // word compared to what a chained hash table requires. +#if 0 + PL_DHashTableSetAlphaBounds(&mContractIDs, + 0.875, + PL_DHASH_MIN_ALPHA(&mContractIDs, 1)); +#endif + } + if (mMon == nsnull) { + mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl"); + if (mMon == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + if (mNativeComponentLoader == nsnull) { + /* Create the NativeComponentLoader */ + mNativeComponentLoader = new nsNativeComponentLoader(); + if (!mNativeComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mNativeComponentLoader); + + nsresult rv = mNativeComponentLoader->Init(this, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + // Add predefined loaders + mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP); + if (!mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP; + + mNLoaderData = NS_COMPONENT_TYPE_NATIVE; + mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType); + mLoaderData[mNLoaderData].loader = mNativeComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + if (mStaticComponentLoader == nsnull) { + extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **); + NS_NewStaticComponentLoader(&mStaticComponentLoader); + if (!mStaticComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + } + + mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType); + mLoaderData[mNLoaderData].loader = mStaticComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + + if (mStaticComponentLoader) { + /* Init the static loader */ + mStaticComponentLoader->Init(this, nsnull); + } +#endif + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir)); + if (!mComponentsDir) + return NS_ERROR_OUT_OF_MEMORY; + + nsCAutoString componentDescriptor; + nsresult rv = mComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) + return rv; + + mComponentsOffset = componentDescriptor.Length(); + + GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir)); + if (mGREComponentsDir) { + nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) { + NS_WARNING("No GRE component manager"); + return rv; + } + mGREComponentsOffset = componentDescriptor.Length(); + } + + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE, + getter_AddRefs(mRegistryFile)); + + if(!mRegistryFile) { + NS_WARNING("No Component Registry file was found in the directory service"); + return NS_ERROR_FAILURE; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsComponentManager: Initialized.")); + + return NS_OK; +} + +PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure) +{ + delete (AutoRegEntry*)aData; + return kHashEnumerateNext; +} + +nsresult nsComponentManagerImpl::Shutdown(void) +{ + PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED); + if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_INPROGRESS; + + // Shutdown the component manager + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); + + PRInt32 i; + + // Write out our component data file. + if (mRegistryDirty) { + nsresult rv = WritePersistentRegistry(); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out perisistant registry.")); +#ifdef DEBUG + printf("Could not write out perisistant registry!\n"); +#endif + } + } + + mAutoRegEntries.Reset(AutoRegEntryDestroy); + + // Release all cached factories + if (mContractIDs.ops) { + PL_DHashTableFinish(&mContractIDs); + mContractIDs.ops = nsnull; + } + if (mFactories.ops) { + PL_DHashTableFinish(&mFactories); + mFactories.ops = nsnull; + } + // Unload libraries + UnloadLibraries(nsnull, NS_Shutdown); + + // delete arena for strings and small objects + PL_FinishArenaPool(&mArena); + + mComponentsDir = 0; + + mCategoryManager = 0; + + // Release all the component data - loaders and type strings + for (i=0; i < mNLoaderData; i++) { + NS_IF_RELEASE(mLoaderData[i].loader); + PL_strfree((char *)mLoaderData[i].type); + } + PR_Free(mLoaderData); + mLoaderData = nsnull; + + // we have an extra reference on this one, which is probably a good thing + NS_IF_RELEASE(mNativeComponentLoader); +#ifdef ENABLE_STATIC_COMPONENT_LOADER + NS_IF_RELEASE(mStaticComponentLoader); +#endif + + mShuttingDown = NS_SHUTDOWN_COMPLETE; + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete.")); + + return NS_OK; +} + +nsComponentManagerImpl::~nsComponentManagerImpl() +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction.")); + + if (mShuttingDown != NS_SHUTDOWN_COMPLETE) + Shutdown(); + + if (mMon) { + nsAutoMonitor::DestroyMonitor(mMon); + } + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed.")); +} + +NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl, + nsIComponentManager, + nsIServiceManager, + nsISupportsWeakReference, + nsIInterfaceRequestor, + nsIComponentRegistrar, + nsIServiceManagerObsolete, + nsIComponentManagerObsolete, + nsIComponentLoaderManager) + + +nsresult +nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result) +{ + if (uuid.Equals(NS_GET_IID(nsINativeComponentLoader))) + { + if (!mNativeComponentLoader) + return NS_ERROR_NOT_INITIALIZED; + + return mNativeComponentLoader->QueryInterface(uuid, result); + } + + NS_WARNING("This isn't supported"); + // fall through to QI as anything QIable is a superset of what can be + // got via the GetInterface() + return QueryInterface(uuid, result); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl: Platform methods +//////////////////////////////////////////////////////////////////////////////// + +#define PERSISTENT_REGISTRY_VERSION_MINOR 5 +#define PERSISTENT_REGISTRY_VERSION_MAJOR 0 + + +AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) : + mName(ToNewCString(name)), + mNameLen(name.Length()), + mData(nsnull), + mModDate(*modDate) +{ +} + +AutoRegEntry::~AutoRegEntry() +{ + if (mName) PL_strfree(mName); + if (mData) PL_strfree(mData); +} + +PRBool +AutoRegEntry::Modified(PRInt64 *date) +{ + return !LL_EQ(*date, mModDate); +} + +void +AutoRegEntry::SetOptionalData(const char* data) +{ + if (mData) + PL_strfree(mData); + + if (!data) { + mData = nsnull; + return; + } + + mData = PL_strdup(data); +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token) +{ + while (1) + { + if (*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if (*p != ']') + break; + *p = 0; + + char* values[1]; + int lengths[1]; + if (2 != reader.ParseLine(values, lengths, 1)) + break; + + // ignore the leading '[' + if (0 != PL_strcmp(values[0]+1, token)) + break; + + return PR_TRUE; + } + + if (!reader.NextLine()) + break; + } + return PR_FALSE; +} + +nsresult +nsComponentManagerImpl::ReadPersistentRegistry() +{ + + // populate Category Manager. need to get this early so that we don't get + // skipped by 'goto out' + nsresult rv = GetService(kCategoryManagerCID, + NS_GET_IID(nsICategoryManager), + getter_AddRefs(mCategoryManager)); + if (NS_FAILED(rv)) + return rv; + + nsAutoMonitor mon(mMon); + nsManifestLineReader reader; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; // this should have been set by Init(). + + PRFileDesc* fd = nsnull; + + // Set From Init + if (!mRegistryFile) { + return NS_ERROR_FILE_NOT_FOUND; + } + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fileSize; + rv = localFile->GetFileSize(&fileSize); + if (NS_FAILED(rv)) + { + PR_Close(fd); + return rv; + } + + PRInt32 flen = nsInt64(fileSize); + if (flen == 0) + { + PR_Close(fd); + NS_WARNING("Persistent Registry Empty!"); + return NS_OK; // ERROR CONDITION + } + + char* registry = new char[flen+1]; + if (!registry) + goto out; + + if (flen > PR_Read(fd, registry, flen)) + { + rv = NS_ERROR_FAILURE; + goto out; + } + registry[flen] = '\0'; + + reader.Init(registry, flen); + + if (ReadSectionHeader(reader, "HEADER")) + goto out; + + if (!reader.NextLine()) + goto out; + + char* values[6]; + int lengths[6]; + + // VersionLiteral,major,minor + if (3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // VersionLiteral + if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version")) + goto out; + + // major + if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1])) + goto out; + + // minor + if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2])) + goto out; + + if (ReadSectionHeader(reader, "COMPONENTS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //name,last_modification_date[,optionaldata] + int parts = reader.ParseLine(values, lengths, 3); + if (2 > parts) + break; + + PRInt64 a = nsCRT::atoll(values[1]); + AutoRegEntry *entry = + new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (parts == 3) + entry->SetOptionalData(values[2]); + + nsCStringKey key((const char*)values[0]); + mAutoRegEntries.Put(&key, entry); + } + + if (ReadSectionHeader(reader, "CLASSIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + // cid,contract_id,type,class_name,inproc_server + if (5 != reader.ParseLine(values, lengths, 5)) + break; + + nsCID aClass; + if (!aClass.Parse(values[0])) + continue; + + int loadertype = GetLoaderType(values[2]); + if (loadertype < 0) { + rv = AddLoaderType(values[2], &loadertype); + if (NS_FAILED(rv)) + continue; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + } + + if (ReadSectionHeader(reader, "CONTRACTIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //contractID,cid + if (2 != reader.ParseLine(values, lengths, 2)) + break; + + nsCID aClass; + if (!aClass.Parse(values[1])) + continue; + + + //need to find the location for this cid. + nsFactoryEntry *cidEntry = GetFactoryEntry(aClass); + if (!cidEntry || cidEntry->mTypeIndex < 0) + continue; //what should we really do? + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, + values[0], + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + continue; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(values[0], lengths[0], &mArena); + contractIDTableEntry->mContractIDLen = lengths[0]; + } + + contractIDTableEntry->mFactoryEntry = cidEntry; + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + { +/* + * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to + * track down their cause, then you should add the contracts listed by the + * assertion to abusedContracts. The next time you run your xpcom app, xpcom + * will assert the first time the object associated with the contract is + * instantiated (which in many cases is the source of the problem). + * + * If you're doing this then you might want to NOP and soft breakpoint the + * lines labeled: NOP_AND_BREAK. + * + * Otherwise XPCOM will refuse to create the object for the caller, which + * while reasonable at some level, will almost certainly cause the app to + * stop functioning normally. + */ + static char abusedContracts[][128] = { + /*// Example contracts: + "@mozilla.org/rdf/container;1", + "@mozilla.org/intl/charsetalias;1", + "@mozilla.org/locale/win32-locale;1", + "@mozilla.org/widget/lookandfeel/win;1", + // */ + { 0 } + }; + for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) { + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, abusedContracts[i], + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + AddPendingCID(entry->mCid); + } + } + } +#endif + + if (ReadSectionHeader(reader, "CATEGORIES")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //type,name,value + if (3 != reader.ParseLine(values, lengths, 3)) + break; + + mCategoryManager->AddCategoryEntry(values[0], + values[1], + values[2], + PR_TRUE, + PR_TRUE, + 0); + } + + mRegistryDirty = PR_FALSE; +out: + if (fd) + PR_Close(fd); + + if (registry) + delete [] registry; + + return rv; +} + +struct PersistentWriterArgs +{ + PRFileDesc *mFD; + nsLoaderdata *mLoaderData; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +ContractIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID; + nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) + return PL_DHASH_NEXT; + + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails? + return PL_DHASH_NEXT; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +ClassIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry; + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) { + return PL_DHASH_NEXT; + } + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + + char *contractID = nsnull, *className = nsnull; + + nsCOMPtr classInfo = do_QueryInterface(factoryEntry->mFactory); + if (classInfo) + { + classInfo->GetContractID(&contractID); + classInfo->GetClassDescription(&className); + } + + const char * loaderName = nsnull; + if (factoryEntry->mTypeIndex) + loaderName = loaderData[factoryEntry->mTypeIndex].type; + + char* location = factoryEntry->mLocation; + + // cid,contract_id,type,class_name,inproc_server + PR_fprintf(fd, + "%s,%s,%s,%s,%s\n", + cidString, + (contractID ? contractID : ""), + (loaderName ? loaderName : ""), + (className ? className : ""), + (location ? location : "")); + + if (contractID) + PR_Free(contractID); + if (className) + PR_Free(className); + + return PL_DHASH_NEXT; +} + +PRIntn PR_CALLBACK +AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure) +{ + PRFileDesc* fd = (PRFileDesc*) aClosure; + AutoRegEntry* entry = (AutoRegEntry*) aData; + + const char* extraData = entry->GetOptionalData(); + const char *fmt; + if (extraData) + fmt = "%s,%lld,%s\n"; + else + fmt = "%s,%lld\n"; + PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData); + + return PR_TRUE; +} + +nsresult +nsComponentManagerImpl::WritePersistentRegistry() +{ + if (!mRegistryFile) + return NS_ERROR_FAILURE; // this should have been set by Init(). + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + nsCAutoString originalLeafName; + localFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + localFile->SetNativeLeafName(leafName); + + PRFileDesc* fd = nsnull; + nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); + if (NS_FAILED(rv)) + return rv; + + if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n", + PERSISTENT_REGISTRY_VERSION_MAJOR, + PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd); + + PersistentWriterArgs args; + args.mFD = fd; + args.mLoaderData = mLoaderData; + + if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + if (!mCategoryManager) { + NS_WARNING("Could not access category manager. Will not be able to save categories!"); + rv = NS_ERROR_UNEXPECTED; + } else { + rv = mCategoryManager->WriteCategoryManagerToRegistry(fd); + } + +out: + if (fd) + PR_Close(fd); + + // don't create the file is there was a problem???? + NS_ENSURE_SUCCESS(rv, rv); + + if (!mRegistryFile) + return NS_ERROR_NOT_INITIALIZED; + + PRBool exists; + if(NS_FAILED(mRegistryFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mRegistryFile->GetParent(getter_AddRefs(parent)); + + rv = localFile->MoveToNative(parent, originalLeafName); + mRegistryDirty = PR_FALSE; + + return rv; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Hash Functions +//////////////////////////////////////////////////////////////////////////////// +nsresult +nsComponentManagerImpl::HashContractID(const char *aContractID, + PRUint32 aContractIDLen, + nsFactoryEntry *fe) +{ + if(!aContractID || !aContractIDLen) + return NS_ERROR_NULL_POINTER; + + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict"); + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(aContractID, aContractIDLen, &mArena); + contractIDTableEntry->mContractIDLen = aContractIDLen; + } + + contractIDTableEntry->mFactoryEntry = fe; + + return NS_OK; +} + +/** + * LoadFactory() + * + * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory + * symbol, calls the routine to create a new factory and returns it to the + * caller. + * + * No attempt is made to store the factory in any form anywhere. + */ +nsresult +nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry, + nsIFactory **aFactory) +{ + + if (!aFactory) + return NS_ERROR_NULL_POINTER; + *aFactory = nsnull; + + nsresult rv; + rv = aEntry->GetFactory(aFactory, this); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsComponentManager: FAILED to load factory from %s (%s)\n", + (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type)); + return rv; + } + + return NS_OK; +} + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen) +{ + nsFactoryEntry *fe = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + fe = contractIDTableEntry->mFactoryEntry; + } + } //exit monitor + + return fe; +} + + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass) +{ + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + } // exit monitor + + return entry; +} + + +/** + * FindFactory() + * + * Given a classID, this finds the factory for this CID by first searching the + * local CID<->factory mapping. Next it searches for a Dll that implements + * this classID and calls LoadFactory() to create the factory. + * + * Again, no attempt is made at storing the factory. + */ +nsresult +nsComponentManagerImpl::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + + +nsresult +nsComponentManagerImpl::FindFactory(const char *contractID, + PRUint32 aContractIDLen, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + +/** + * GetClassObject() + * + * Given a classID, this finds the singleton ClassObject that implements the CID. + * Returns an interface of type aIID off the singleton classobject. + */ +nsresult +nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + char *buf = aClass.ToString(); + PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf); + if (buf) + PR_Free(buf); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(aClass, getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + + +nsresult +nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, + const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +/** + * ContractIDToClassID() + * + * Mapping function from a ContractID to a classID. Directly talks to the registry. + * + */ +nsresult +nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass) +{ + NS_PRECONDITION(aContractID != nsnull, "null ptr"); + if (!aContractID) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(aClass != nsnull, "null ptr"); + if (!aClass) + return NS_ERROR_NULL_POINTER; + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + + nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID)); + if (fe) { + *aClass = fe->mCid; + rv = NS_OK; + } +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) { + char *buf = 0; + if (NS_SUCCEEDED(rv)) + buf = aClass->ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID, + NS_SUCCEEDED(rv) ? buf : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +/** + * CLSIDToContractID() + * + * Translates a classID to a {ContractID, Class Name}. Does direct registry + * access to do the translation. + * + * NOTE: Since this isn't heavily used, we arent caching this. + */ +nsresult +nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass, + char* *aClassName, + char* *aContractID) +{ + NS_WARNING("Need to implement CLSIDToContractID"); + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CLSIDToContractID(%s)->%s", buf, + NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +#ifdef XPCOM_CHECK_PENDING_CIDS + +// This method must be called from within the mMon monitor +nsresult +nsComponentManagerImpl::AddPendingCID(const nsCID &aClass) +{ + int max = mPendingCIDs.Count(); + for (int index = 0; index < max; index++) + { + nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index); + NS_ASSERTION(cidp, "Bad CID in pending list"); + if (cidp->Equals(aClass)) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("Creation of \"") + + cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)"); + // Note that you may see this assertion by near-simultaneous + // calls to GetService on multiple threads. + NS_WARNING(message.get()); + return NS_ERROR_NOT_AVAILABLE; + } + } + mPendingCIDs.AppendElement((void*)&aClass); + return NS_OK; +} + +// This method must be called from within the mMon monitor +void +nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass) +{ + mPendingCIDs.RemoveElement((void*)&aClass); +} +#endif +/** + * CreateInstance() + * + * Create an instance of an object that implements an interface and belongs + * to the implementation aClass using the factory. The factory is immediately + * released and not held onto for any longer. + */ +nsresult +nsComponentManagerImpl::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!"); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstance(%s) %s", buf, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + if (buf) + PR_Free(buf); + } +#endif + + return rv; +} + +/** + * CreateInstanceByContractID() + * + * A variant of CreateInstance() that creates an instance of the object that + * implements the interface aIID and whose implementation has a contractID aContractID. + * + * This is only a convenience routine that turns around can calls the + * CreateInstance() with classid and iid. + */ +nsresult +nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID)); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsCAutoString message; + message = + NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + nsDependentCString(aContractID) + + NS_LITERAL_CSTRING("\" when a service for this CID already exists! " + "Add it to abusedContracts to track down the service consumer."); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + if (rv != NS_ERROR_SOCKET_FAIL) + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +// Service Manager Impl +static +PLDHashOperator PR_CALLBACK +FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +static +PLDHashOperator PR_CALLBACK +FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +nsresult +nsComponentManagerImpl::FreeServices() +{ + NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services"); + + if (!gXPCOMShuttingDown) + return NS_ERROR_FAILURE; + + if (mContractIDs.ops) { + PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull); + } + + + if (mFactories.ops) { + PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsIDKey key(aClass); + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(aClass); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + RemovePendingCID(aClass); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result))); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(aClass, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const nsCID& aClass) +{ + nsresult rv = NS_OK; + + nsFactoryEntry* entry = nsnull; + + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService) +{ + + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + PRUint32 contractIDLen = strlen(aContractID); + nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + delete entry; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = + ArenaStrndup(aContractID, contractIDLen, &mArena); + + contractIDTableEntry->mContractIDLen = contractIDLen; + } + + contractIDTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; + +} + +NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + } // exit monitor + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const char* aContractID) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetServiceByContractID(const char* aContractID, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (entry) { + if (entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(entry->mCid); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + } + + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + if (entry) + RemovePendingCID(entry->mCid); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetService(aClass, aIID, (void**)result); +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetServiceByContractID(aContractID, aIID, (void**)result); +} + + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +/* + * I want an efficient way to allocate a buffer to the right size + * and stick the prefix and dllName in, then be able to hand that buffer + * off to the FactoryEntry. Is that so wrong? + * + * *regName is allocated on success. + * + * This should live in nsNativeComponentLoader.cpp, I think. + */ +static nsresult +MakeRegistryName(const char *aDllName, const char *prefix, char **regName) +{ + char *registryName; + + PRUint32 len = strlen(prefix); + + PRUint32 registryNameLen = strlen(aDllName) + len; + registryName = (char *)nsMemory::Alloc(registryNameLen + 1); + + // from here on it, we want len sans terminating NUL + + if (!registryName) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(registryName, prefix, len); + strcpy(registryName + len, aDllName); + registryName[registryNameLen] = '\0'; + *regName = registryName; + +#ifdef DEBUG_shaver_off + fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n", + aDllName, prefix, *regName); +#endif + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec, + char **aRegistryName) +{ + nsresult rv; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + if (!aSpec) { + *aRegistryName = PL_strdup(""); + return NS_OK; + } + + + // First check to see if this component is in the application + // components directory + PRBool containedIn; + mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + nsCAutoString nativePathString; + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName); + } + + // Next check to see if this component is in the GRE + // components directory + + mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName); + } + + /* absolute names include volume info on Mac, so persistent descriptor */ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName); +} + +nsresult +nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation, + nsIFile **aSpec) +{ + // i18n: assuming aLocation is encoded for the current locale + + nsresult rv; + if (!aLocation || !aSpec) + return NS_ERROR_NULL_POINTER; + + /* abs:/full/path/to/libcomponent.so */ + if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) { + + nsLocalFile* file = new nsLocalFile; + if (!file) return NS_ERROR_FAILURE; + + rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4)); + file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec); + return rv; + } + + if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) { + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) { + + if (!mGREComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mGREComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + *aSpec = nsnull; + return NS_ERROR_INVALID_ARG; +} + +/** + * RegisterFactory() + * + * Register a factory to be responsible for creation of implementation of + * classID aClass. Plus creates as association of aClassName and aContractID + * to the classID. If replace is PR_TRUE, we replace any existing registrations + * with this one. + * + * Once registration is complete, we add the class to the factories cache + * that we maintain. The factories cache is the ONLY place where these + * registrations are ever kept. + * + * The other RegisterFunctions create a loader mapping and persistent + * location, but we just slam it into the cache here. And we don't call the + * loader's OnRegister function, either. + */ +nsresult +nsComponentManagerImpl::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsAutoMonitor mon(mMon); +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterFactory(%s, %s)", buf, + (aContractID ? aContractID : "(null)"))); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && !aReplace) + { + // Already registered + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + entry = new (mem) nsFactoryEntry(aClass, aFactory, entry); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + // Update the ContractID->CLSID Map + if (aContractID) { + nsresult rv = HashContractID(aContractID, strlen(aContractID), entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded. " + "Hashing contractid (%s) FAILED.", aContractID)); + return rv; + } + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded contractid=%s.", + aContractID ? aContractID : "")); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aPersistentDescriptor, + aPersistentDescriptor ? + strlen(aPersistentDescriptor) : 0, + aReplace, aPersist, + nativeComponentType); +} + +nsresult +nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aSpec, + const char *aLocation, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aLocation, + aLocation ? strlen(aLocation) : 0, + aReplace, aPersist, + aType); +} + +/* + * Register a component, using whatever they stuck in the nsIFile. + */ +nsresult +nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrarySpec, + PRBool aReplace, + PRBool aPersist) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + rv = RegisterComponentWithType(aClass, aClassName, + aContractID, + aLibrarySpec, + registryName, + aReplace, aPersist, + nativeComponentType); + return rv; +} + +nsresult +nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aDllName, + PRBool aReplace, + PRBool aPersist) +{ + // deprecated and obsolete. + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* + * Add a component to the known universe of components. + + * Once we enter this function, we own aRegistryName, and must free it + * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us + * sane. + */ + +nsresult +nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + nsIDKey key(aClass); + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + // Normalize proid and classname + const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull; + const char *className = (aClassName && *aClassName) ? aClassName : nsnull; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)", + buf, + contractID ? contractID : "(null)", + aRegistryName, aType)); + if (buf) + PR_Free(buf); + } +#endif + if (entry && !aReplace) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + int typeIndex = GetLoaderType(aType); + + nsCOMPtr loader; + nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader)); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tgetting loader for %s FAILED\n", aType)); + return rv; + } + + if (entry) { + entry->ReInit(aClass, aRegistryName, typeIndex); + } + else { + + // Arena allocate the nsFactoryEntry + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + mRegistryDirty = PR_TRUE; + entry = new (mem) nsFactoryEntry(aClass, + aRegistryName, aRegistryNameLen, + typeIndex); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + + // Update the ContractID->CLSID Map + if (contractID) { + rv = HashContractID(contractID, aContractIDLen, entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tHashContractID(%s) FAILED\n", contractID)); + return rv; + } + } + return rv; +} + + +nsresult +nsComponentManagerImpl::GetLoaderForType(int aType, + nsIComponentLoader **aLoader) +{ + nsresult rv; + + // Make sure we have a valid type + if (aType < 0 || aType >= mNLoaderData) + return NS_ERROR_INVALID_ARG; + + *aLoader = mLoaderData[aType].loader; + if (*aLoader) { + NS_ADDREF(*aLoader); + return NS_OK; + } + + nsCOMPtr loader; + loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = loader->Init(this, nsnull); + + if (NS_SUCCEEDED(rv)) { + mLoaderData[aType].loader = loader; + NS_ADDREF(mLoaderData[aType].loader); + *aLoader = loader; + NS_ADDREF(*aLoader); + } + return rv; +} + + + +// Convert a loader type string into an index into the component data +// array. Empty loader types are converted to NATIVE. Returns -1 if +// loader type cannot be determined. +int +nsComponentManagerImpl::GetLoaderType(const char *typeStr) +{ + if (!typeStr || !*typeStr) { + // Empty type strings are NATIVE + return NS_COMPONENT_TYPE_NATIVE; + } + + for (int i=NS_COMPONENT_TYPE_NATIVE; i= 0) { + *aTypeIndex = typeIndex; + return NS_OK; + } + + // Add the loader type + if (mNLoaderData >= mMaxNLoaderData) { + NS_ASSERTION(mNLoaderData == mMaxNLoaderData, + "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun."); + // Need to increase our loader array + nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata)); + if (!new_mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mLoaderData = new_mLoaderData; + mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP; + } + + typeIndex = mNLoaderData; + mLoaderData[typeIndex].type = PL_strdup(typeStr); + if (!mLoaderData[typeIndex].type) { + // mmh! no memory. return failure. + return NS_ERROR_OUT_OF_MEMORY; + } + mLoaderData[typeIndex].loader = nsnull; + mNLoaderData++; + + *aTypeIndex = typeIndex; + return NS_OK; +} + +typedef struct +{ + const nsCID* cid; + const char* regName; + nsIFactory* factory; +} UnregisterConditions; + +static PLDHashOperator PR_CALLBACK +DeleteFoundCIDs(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + UnregisterConditions* data = (UnregisterConditions*)aData; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + if (data->cid->Equals(factoryEntry->mCid) && + ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) || + (data->factory && data->factory == factoryEntry->mFactory.get()))) + return PL_DHASH_REMOVE; + + return PL_DHASH_NEXT; +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = registryName; + aData.factory = nsnull; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); + +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = nsnull; + aData.factory = factory; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); +} + +nsresult +nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterFactory(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, aFactory); + + // next check to see if there is a CID registered + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + old = GetFactoryEntry(aClass); + + if (old && (old->mFactory.get() == aFactory)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + rv = NS_OK; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tUnregisterFactory() %s", + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + return rv; +} + +nsresult +nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass, + const char *registryName) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterComponent(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + + NS_ENSURE_ARG_POINTER(registryName); + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, registryName); + + // next check to see if there is a CID registered + old = GetFactoryEntry(aClass); + if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Factory unregister(%s) succeeded.", registryName)); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) return rv; + return UnregisterComponent(aClass, registryName); +} + +// XXX Need to pass in aWhen and servicemanager +nsresult +nsComponentManagerImpl::FreeLibraries(void) +{ + return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when +} + +// Private implementation of unloading libraries +nsresult +nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Unloading Libraries.")); + + // UnloadAll the loaders + /* iterate over all known loaders and ask them to autoregister. */ + // Skip mNativeComponentLoader + for (int i=NS_COMPONENT_TYPE_NATIVE + 1; iUnloadAll(aWhen); + if (NS_FAILED(rv)) + break; + } + } + + // UnloadAll the native loader + rv = mNativeComponentLoader->UnloadAll(aWhen); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +/** + * AutoRegister(RegistrationInstant, const char *directory) + * + * Given a directory in the following format, this will ensure proper registration + * of all components. No default directory is looked at. + * + * Directory and fullname are what NSPR will accept. For eg. + * WIN y:/home/dp/mozilla/dist/bin + * UNIX /home/dp/mozilla/dist/bin + * MAC /Hard drive/mozilla/dist/apprunner + * + * This will take care not loading already registered dlls, finding and + * registering new dlls, re-registration of modified dlls + * + */ + +nsresult +nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec) +{ + return AutoRegisterImpl(when, inDirSpec); +} + +nsresult +nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when, + nsIFile *inDirSpec, + PRBool fileIsCompDir) +{ + nsCOMPtr dir; + nsresult rv; + +#ifdef DEBUG + // testing release behaviour + if (getenv("XPCOM_NO_AUTOREG")) + return NS_OK; +#endif + if (inDirSpec) + { + // Use supplied components' directory + dir = inDirSpec; + } + else + { + mComponentsDir->Clone(getter_AddRefs(dir)); + if (!dir) + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtr iim = + dont_AddRef(XPTI_GetInterfaceInfoManager()); + + if (!iim) + return NS_ERROR_UNEXPECTED; + + // Notify observers of xpcom autoregistration start + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "start"); + + /* do the native loader first, so we can find other loaders */ + rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir); + if (NS_FAILED(rv)) return rv; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec); + if (NS_FAILED(rv)) return rv; +#endif + + /* do InterfaceInfoManager after native loader so it can use components. */ + rv = iim->AutoRegisterInterfaces(); + if (NS_FAILED(rv)) return rv; + + if (!mCategoryManager) { + NS_WARNING("mCategoryManager is null"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr loaderEnum; + rv = mCategoryManager->EnumerateCategory("component-loader", + getter_AddRefs(loaderEnum)); + if (NS_FAILED(rv)) return rv; + + PRBool hasMore; + while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr supports; + if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports)))) + continue; + + nsCOMPtr supStr = do_QueryInterface(supports); + if (!supStr) + continue; + + nsCAutoString loaderType; + if (NS_FAILED(supStr->GetData(loaderType))) + continue; + + // We depend on the loader being created. Add the loader type and + // create the loader object too. + nsCOMPtr loader; + int typeIndex; + rv = AddLoaderType(loaderType.get(), &typeIndex); + if (NS_FAILED(rv)) + return rv; + GetLoaderForType(typeIndex, getter_AddRefs(loader)); + } + + rv = AutoRegisterNonNativeComponents(dir.get()); + + // Notify observers of xpcom autoregistration completion + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "end"); + + if (mRegistryDirty) + FlushPersistentStore(PR_TRUE); + return rv; +} + +nsresult +nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec) +{ + nsresult rv = NS_OK; + nsCOMPtr directory = spec; + + if (!directory) { + mComponentsDir->Clone(getter_AddRefs(directory)); + if (!directory) + return NS_ERROR_NOT_INITIALIZED; + } + + for (int i = 1; i < mNLoaderData; i++) { + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory); + if (NS_FAILED(rv)) + break; + } + + if (NS_SUCCEEDED(rv)) + { + PRBool registered; + do { + registered = PR_FALSE; + for (int i = 0; i < mNLoaderData; i++) { + PRBool b = PR_FALSE; + if (mLoaderData[i].loader) { + rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b); + if (NS_FAILED(rv)) + continue; + registered |= b; + } + } + } while (NS_SUCCEEDED(rv) && registered); + } + return rv; +} +nsresult +nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED; + /* + * Do we have to give the native loader first crack at it? + * I vote ``no''. + */ + for (int i = 0; i < mNLoaderData; i++) { + PRBool didRegister; + if (!mLoaderData[i].loader) { + nsCOMPtr loader; + rv = GetLoaderForType(i, getter_AddRefs(loader)); + if (NS_FAILED(rv)) + continue; + // |GetLoaderForType| has filled in |mLoaderData[i].loader|: + NS_ASSERTION(loader == mLoaderData[i].loader, "oops"); + } + rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister); + if (NS_FAILED(rv)) { + res = rv; + } else if (didRegister) { + return rv; + } + } + return res; +} + +nsresult +nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK; + for (int i = 0; i < mNLoaderData; i++) { + PRBool didUnRegister; + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister); + if (NS_SUCCEEDED(rv) && didUnRegister) { + // we need to remove this file from our list of known libraries. + RemoveFileInfo(component, nsnull); + mRegistryDirty = PR_TRUE; + break; + } + } + return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK; +} + +nsresult +nsComponentManagerImpl::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + if (!aRegistered) + { + NS_ASSERTION(0, "null ptr"); + return NS_ERROR_NULL_POINTER; + } + *aRegistered = (nsnull != GetFactoryEntry(aClass)); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + *aEnumerator = nsnull; + + nsresult rv; + + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +// nsIComponentRegistrar + +NS_IMETHODIMP +nsComponentManagerImpl::AutoRegister(nsIFile *aSpec) +{ + if (aSpec == nsnull) + return AutoRegisterImpl(0, aSpec); + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return AutoRegisterImpl(0, aSpec, PR_FALSE); + + return AutoRegisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec) +{ + // unregistering a complete directory is not implmeneted yet...FIX + if (aSpec == nsnull) + return NS_ERROR_NOT_IMPLEMENTED; + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return NS_ERROR_NOT_IMPLEMENTED; + + return AutoUnregisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactory(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory) +{ + return RegisterFactory(aClass, + aClassName, + aContractID, + aFactory, + PR_TRUE); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aFile, + const char *loaderStr, + const char *aType) +{ + nsXPIDLCString registryName; + + if (!loaderStr) + { + nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + } + + nsresult rv; + rv = RegisterComponentWithType(aClass, + aClassName, + aContractID, + aFile, + (loaderStr ? loaderStr : registryName.get()), + PR_TRUE, + PR_TRUE, + (aType ? aType : nativeComponentType)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass, + nsIFile *aFile) +{ + return UnregisterComponentSpec(aClass, aFile); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass, + PRBool *_retval) +{ + return IsRegistered(aClass, _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, + PRBool *_retval) +{ + nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); + + if (entry) + *_retval = PR_TRUE; + else + *_retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::CIDToContractID(const nsCID & aClass, + char **_retval) +{ + return CLSIDToContractID(aClass, + nsnull, + _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::ContractIDToCID(const char *aContractID, + nsCID * *_retval) +{ + *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = ContractIDToClassID(aContractID, *_retval); + if (NS_FAILED(rv)) { + nsMemory::Free(*_retval); + *_retval = nsnull; + } + return rv; +} + +// end nsIComponentRegistrar + + + + +NS_IMETHODIMP +nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval) +{ + *_retval = PR_TRUE; + + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (entry) + *_retval = entry->Modified(&modDate); + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + // check to see if exists in the array before adding it so that we don't have dups. + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (entry) + { + entry->SetDate(&modDate); + return NS_OK; + } + + entry = new AutoRegEntry(registryName, &modDate); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key); + if (entry) + delete entry; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetOptionalData(nsIFile *file, + const char *loaderString, + char **_retval) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (!entry) { + return NS_ERROR_NOT_INITIALIZED; + } + const char* opData = entry->GetOptionalData(); + + if (opData) + *_retval = ToNewCString(nsDependentCString(opData)); + else + *_retval = nsnull; + return NS_OK; + } + +NS_IMETHODIMP +nsComponentManagerImpl::SetOptionalData(nsIFile *file, + const char *loaderString, + const char *data) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (!entry) { + PRInt64 zero = LL_Zero(); + entry = new AutoRegEntry(registryName, &zero); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + } + + entry->SetOptionalData(data); + + return NS_OK; + } + + +NS_IMETHODIMP +nsComponentManagerImpl::FlushPersistentStore(PRBool now) +{ + mRegistryDirty = PR_TRUE; + if (now) + return WritePersistentRegistry(); + + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Static Access Functions +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result) +{ +#ifdef DEBUG_dougt + // NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager"); +#endif + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_SUCCEEDED(rv)) + { + // NO ADDREF since this is never intended to be released. + // See nsComponentManagerObsolete.h for the reason for such + // casting uglyness + *result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager; + } + + return rv; +} + +NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result) +{ + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + *result = NS_STATIC_CAST(nsIComponentManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + +NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { +#ifdef VBOX + // While XPCOM might need initialization, we're not in a position + // to pass the right values to this call. This is actually triggered + // on object destruction, so there is no point in re-initializing, + // and actually the attempt would lead to nested calls to + // xptiInterfaceInfoManager::BuildFileSearchPath, which it detects + // as unsafe in debug builds. Just fail, no real problem. +#ifdef DEBUG + printf("NS_GetServiceManager: no current instance, suppressed XPCOM initialization!\n"); +#endif + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; +#else /* !VBOX */ + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif /* !VBOX */ + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIServiceManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentRegistrar*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +// nsIComponentLoaderManager is not frozen, but is defined here +// so that I can use it internally in xpcom. +nsresult +NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == NULL) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentLoaderManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h new file mode 100644 index 00000000..df128125 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsComponentManager_h__ +#define nsComponentManager_h__ + +#include "nsXPCOM.h" + +#include "nsIComponentLoader.h" +#include "xpcom-private.h" +#include "nsNativeComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIComponentLoaderManager.h" +#include "nsCategoryManager.h" +#include "nsIServiceManager.h" +#include "nsIFactory.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "pldhash.h" +#include "prtime.h" +#include "prmon.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsXPIDLString.h" +#include "nsIFile.h" +#include "plarena.h" + +class nsFactoryEntry; +class nsDll; +class nsIServiceManager; + + +// Predefined loader types. Do not change the numbers. +// NATIVE should be 0 as it is being used as the first array index. +#define NS_COMPONENT_TYPE_NATIVE 0 +#define NS_COMPONENT_TYPE_FACTORY_ONLY -1 +// this define means that the factory entry only has a ContractID +// to service mapping and has no cid mapping. +#define NS_COMPONENT_TYPE_SERVICE_ONLY -2 + + +#ifdef DEBUG +#define XPCOM_CHECK_PENDING_CIDS +#endif +//////////////////////////////////////////////////////////////////////////////// + +// Array of Loaders and their type strings +struct nsLoaderdata { + nsIComponentLoader *loader; + const char *type; +}; + +class nsComponentManagerImpl + : public nsIComponentManager, + public nsIServiceManager, + public nsIComponentRegistrar, + public nsSupportsWeakReference, + public nsIInterfaceRequestor, + public nsIComponentLoaderManager, + public nsIServiceManagerObsolete, + public nsIComponentManagerObsolete +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEREQUESTOR + // Since the nsIComponentManagerObsolete and nsIComponentManager share some of the + // same interface function names, we have to manually define the functions here. + // The only function that is in nsIComponentManagerObsolete and is in nsIComponentManager + // is GetClassObjectContractID. + // + // nsIComponentManager function not in nsIComponentManagerObsolete: + NS_IMETHOD GetClassObjectByContractID(const char *aContractID, + const nsIID &aIID, + void **_retval); + + + NS_DECL_NSICOMPONENTMANAGEROBSOLETE + + // Since the nsIComponentManagerObsolete and nsIComponentRegistrar share some of the + // same interface function names, we have to manually define the functions here. + // the only function that is shared is UnregisterFactory + NS_IMETHOD AutoRegister(nsIFile *aSpec); + NS_IMETHOD AutoUnregister(nsIFile *aSpec); + NS_IMETHOD RegisterFactory(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFactory *aFactory); + // NS_IMETHOD UnregisterFactory(const nsCID & aClass, nsIFactory *aFactory); + NS_IMETHOD RegisterFactoryLocation(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFile *aFile, const char *loaderStr, const char *aType); + NS_IMETHOD UnregisterFactoryLocation(const nsCID & aClass, nsIFile *aFile); + NS_IMETHOD IsCIDRegistered(const nsCID & aClass, PRBool *_retval); + NS_IMETHOD IsContractIDRegistered(const char *aClass, PRBool *_retval); + NS_IMETHOD EnumerateCIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD EnumerateContractIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD CIDToContractID(const nsCID & aClass, char **_retval); + NS_IMETHOD ContractIDToCID(const char *aContractID, nsCID * *_retval); + + NS_DECL_NSISERVICEMANAGER + NS_DECL_NSISERVICEMANAGEROBSOLETE + NS_DECL_NSICOMPONENTLOADERMANAGER + + // nsComponentManagerImpl methods: + nsComponentManagerImpl(); + + static nsComponentManagerImpl* gComponentManager; + nsresult Init(void); + + nsresult WritePersistentRegistry(); + nsresult ReadPersistentRegistry(); + + nsresult Shutdown(void); + + nsresult FreeServices(); + + nsresult + NS_GetService(const char *aContractID, const nsIID& aIID, PRBool aDontCreate, nsISupports** result); + + nsresult RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, PRBool aPersist, + const char *aType); + nsresult GetLoaderForType(int aType, + nsIComponentLoader **aLoader); + nsresult FindFactory(const char *contractID, PRUint32 aContractIDLen, nsIFactory **aFactory) ; + nsresult LoadFactory(nsFactoryEntry *aEntry, nsIFactory **aFactory); + + nsFactoryEntry *GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen); + nsFactoryEntry *GetFactoryEntry(const nsCID &aClass); + + nsresult SyncComponentsInDir(PRInt32 when, nsIFile *dirSpec); + nsresult SelfRegisterDll(nsDll *dll); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult HashContractID(const char *acontractID, PRUint32 aContractIDLen, + nsFactoryEntry *fe_ptr); + + void DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName); + void DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory); + + nsresult UnloadLibraries(nsIServiceManager *servmgr, PRInt32 when); + + // Convert a loader type string into an index into the loader data + // array. Empty loader types are converted to NATIVE. Returns -1 if + // loader type cannot be determined. + int GetLoaderType(const char *typeStr); + + // Add a loader type if not already known. Out the typeIndex + // if the loader type is either added or already there; + // returns NS_OK or an error on failure. + nsresult AddLoaderType(const char *typeStr, int *typeIndex); + + int GetLoaderCount() { return mNLoaderData + 1; } + + // registers only the files in spec's location by loaders other than the + // native loader. This is an optimization method only. + nsresult AutoRegisterNonNativeComponents(nsIFile* spec); + + nsresult AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec, PRBool fileIsCompDir=PR_TRUE); + nsresult RemoveEntries(nsIFile* file); + + PLDHashTable mFactories; + PLDHashTable mContractIDs; + PRMonitor* mMon; + + nsNativeComponentLoader *mNativeComponentLoader; +#ifdef ENABLE_STATIC_COMPONENT_LOADER + nsIComponentLoader *mStaticComponentLoader; +#endif + nsCOMPtr mComponentsDir; + PRInt32 mComponentsOffset; + + nsCOMPtr mGREComponentsDir; + PRInt32 mGREComponentsOffset; + + nsCOMPtr mRegistryFile; + + // Shutdown + #define NS_SHUTDOWN_NEVERHAPPENED 0 + #define NS_SHUTDOWN_INPROGRESS 1 + #define NS_SHUTDOWN_COMPLETE 2 + PRUint32 mShuttingDown; + + nsLoaderdata *mLoaderData; + int mNLoaderData; + int mMaxNLoaderData; + + PRBool mRegistryDirty; + nsHashtable mAutoRegEntries; + nsCOMPtr mCategoryManager; + + PLArenaPool mArena; + +#ifdef XPCOM_CHECK_PENDING_CIDS + nsresult AddPendingCID(const nsCID &aClass); + void RemovePendingCID(const nsCID &aClass); + + nsVoidArray mPendingCIDs; +#endif + +private: + ~nsComponentManagerImpl(); +}; + + +#define NS_MAX_FILENAME_LEN 1024 + +#define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24) + +//////////////////////////////////////////////////////////////////////////////// +/** + * Class: nsFactoryEntry() + * + * There are two types of FactoryEntries. + * + * 1. {CID, dll} mapping. + * Factory is a consequence of the dll. These can be either session + * specific or persistent based on whether we write this + * to the registry or not. + * + * 2. {CID, factory} mapping + * These are strictly session specific and in memory only. + */ + +class nsFactoryEntry { +public: + nsFactoryEntry(const nsCID &aClass, + const char *location, PRUint32 locationlen, int aType, class nsFactoryEntry* parent = nsnull); + nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory, class nsFactoryEntry* parent = nsnull); + ~nsFactoryEntry(); + + nsresult ReInit(const nsCID &aClass, const char *location, int aType); + + nsresult GetFactory(nsIFactory **aFactory, + nsComponentManagerImpl * mgr) { + if (mFactory) { + *aFactory = mFactory.get(); + NS_ADDREF(*aFactory); + return NS_OK; + } + + if (mTypeIndex < 0) + return NS_ERROR_FAILURE; + + nsresult rv; + nsCOMPtr loader; + rv = mgr->GetLoaderForType(mTypeIndex, getter_AddRefs(loader)); + if(NS_FAILED(rv)) + return rv; + + rv = loader->GetFactory(mCid, mLocation, mgr->mLoaderData[mTypeIndex].type, aFactory); + if (NS_SUCCEEDED(rv)) + mFactory = do_QueryInterface(*aFactory); + return rv; + } + + nsCID mCid; + nsCOMPtr mFactory; + // This is an index into the mLoaderData array that holds the type string and the loader + int mTypeIndex; + nsCOMPtr mServiceObject; + char* mLocation; + class nsFactoryEntry* mParent; +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct nsFactoryTableEntry : public PLDHashEntryHdr { + nsFactoryEntry *mFactoryEntry; +}; + +struct nsContractIDTableEntry : public PLDHashEntryHdr { + char *mContractID; + PRUint32 mContractIDLen; + nsFactoryEntry *mFactoryEntry; +}; + + +class AutoRegEntry +{ +public: + AutoRegEntry(const nsACString& name, PRInt64* modDate); + ~AutoRegEntry(); + + const nsDependentCString GetName() + { return nsDependentCString(mName, mNameLen); } + PRInt64 GetDate() {return mModDate;} + void SetDate(PRInt64 *date) { mModDate = *date;} + PRBool Modified(PRInt64 *date); + + // this is the optional field line in the compreg.dat. + // it must not contain any comma's and it must be null terminated. + char* GetOptionalData() {return mData;}; + void SetOptionalData(const char* data); + +private: + char* mName; + PRUint32 mNameLen; + char* mData; + PRInt64 mModDate; +}; +#endif // nsComponentManager_h__ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp new file mode 100644 index 00000000..fca77cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp @@ -0,0 +1,271 @@ + +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// Global Static Component Manager Methods +// (for when you need to link with xpcom) + +#include "nsIComponentManagerObsolete.h" +#include "nsComponentManagerObsolete.h" + + +nsresult +nsComponentManager::Initialize(void) +{ + return NS_OK; +} + +nsresult +nsComponentManager::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FindFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->GetClassObject(aClass, aIID, aResult); +} + +nsresult +nsComponentManager::ContractIDToClassID(const char *aContractID, + nsCID *aClass) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->ContractIDToClassID(aContractID, aClass); +} + +nsresult +nsComponentManager::CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CLSIDToContractID(*aClass, aClassName, aContractID); +} + +nsresult +nsComponentManager::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstance(aClass, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstanceByContractID(aContractID, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterFactory(aClass, aClassName, aContractID, + aFactory, aReplace); +} + +nsresult +nsComponentManager::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponent(aClass, aClassName, aContractID, + aLibraryPersistentDescriptor, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentSpec(aClass, aClassName, aContractID, + aLibrary, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentLib(aClass, aClassName, aContractID, + adllName, aReplace, aPersist); +} + +nsresult +nsComponentManager::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::UnregisterComponent(const nsCID &aClass, + const char *aLibrary) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponent(aClass, aLibrary); +} + +nsresult +nsComponentManager::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponentSpec(aClass, aLibrarySpec); +} + +nsresult +nsComponentManager::FreeLibraries(void) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FreeLibraries(); +} + +nsresult +nsComponentManager::AutoRegister(PRInt32 when, nsIFile *directory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegister(when, directory); +} + +nsresult +nsComponentManager::AutoRegisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegisterComponent(when, fullname); +} + +nsresult +nsComponentManager::AutoUnregisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoUnregisterComponent(when, fullname); +} + +nsresult +nsComponentManager::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->IsRegistered(aClass, aRegistered); +} + +nsresult +nsComponentManager::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateCLSIDs(aEnumerator); +} + +nsresult +nsComponentManager::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateContractIDs(aEnumerator); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h new file mode 100644 index 00000000..dfcde87a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsComponentManagerObsolete_h___ +#define nsComponentManagerObsolete_h___ + +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" + +class nsIEnumerator; +class nsIFactory; +class nsIFile; +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIComponentManager.idl for the supported interface +// to the component manager. +// +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// God save me from this evilness. Below is a very bad +// function. Its out var is really a nsIComponentManagerObsolete +// but it has been cast to a nsIComponentManager. +// The reason for such uglyness is that this function is require for +// backward compatiblity of some plugins. This funciton will +// be removed at some point. +//////////////////////////////////////////////////////////////////// + +extern NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result); + + + + +class NS_COM nsComponentManager { +public: + static nsresult Initialize(void); + + // Finds a factory for a specific class ID + static nsresult FindFactory(const nsCID &aClass, + nsIFactory **aFactory); + + // Get the singleton class object that implements the CID aClass + static nsresult GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult); + + // Finds a class ID for a specific Program ID + static nsresult ContractIDToClassID(const char *aContractID, + nsCID *aClass); + + // Finds a Program ID for a specific class ID + // caller frees the result with delete[] + static nsresult CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID); + + // Creates a class instance for a specific class ID + static nsresult CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Convenience routine, creates a class instance for a specific ContractID + static nsresult CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Manually registry a factory for a class + static nsresult RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace); + + // Manually register a dynamically loaded component. + // The libraryPersistentDescriptor is what gets passed to the library + // self register function from ComponentManager. The format of this string + // is the same as nsIFile::GetPath() + // + // This function will go away in favour of RegisterComponentSpec. In fact, + // it internally turns around and calls RegisterComponentSpec. + static nsresult RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its FileSpec as its identification + // This is the more prevalent use. + static nsresult RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its dllName. This could be a dll name with + // no path so that LD_LIBRARY_PATH on unix or PATH on win can load it. Or + // this could be a code fragment name on the Mac. + static nsresult RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist); + + + // Manually unregister a factory for a class + static nsresult UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponent(const nsCID &aClass, + const char *aLibrary); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec); + + // Unload dynamically loaded factories that are not in use + static nsresult FreeLibraries(void); + ////////////////////////////////////////////////////////////////////////////// + // DLL registration support + + // If directory is NULL, then AutoRegister will try registering components + // in the default components directory. + static nsresult AutoRegister(PRInt32 when, nsIFile* directory); + static nsresult AutoRegisterComponent(PRInt32 when, nsIFile *component); + static nsresult AutoUnregisterComponent(PRInt32 when, nsIFile *component); + + // Is the given CID currently registered? + static nsresult IsRegistered(const nsCID &aClass, + PRBool *aRegistered); + + // Get an enumeration of all the CIDs + static nsresult EnumerateCLSIDs(nsIEnumerator** aEmumerator); + + // Get an enumeration of all the ContractIDs + static nsresult EnumerateContractIDs(nsIEnumerator** aEmumerator); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h new file mode 100644 index 00000000..cda56416 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsComponentManagerUtils_h__ +#define nsComponentManagerUtils_h__ + +/* + * Do not include this file directly. Instead, + * |#include "nsIComponentManager.h"|. + */ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +#ifndef nsComponentManagerObsolete_h___ +#include "nsComponentManagerObsolete.h" +#endif + +#define NS_COMPONENTMANAGER_CID \ +{ /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \ + 0x91775d60, \ + 0xd5dc, \ + 0x11d2, \ + {0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \ +} + +class NS_COM nsCreateInstanceByCID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByCID( const nsCID& aCID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mCID(aCID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const nsCID& mCID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +class NS_COM nsCreateInstanceByContractID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByContractID( const char* aContractID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mContractID(aContractID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const char* mContractID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, 0, error); +} + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, aOuter, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, 0, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, aOuter, error); +} + +// type-safe shortcuts for calling |CreateInstance| +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, + aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +/* keys for registry use */ +extern const char xpcomKeyName[]; +extern const char xpcomComponentsKeyName[]; +extern const char lastModValueName[]; +extern const char fileSizeValueName[]; +extern const char nativeComponentType[]; +extern const char staticComponentType[]; + +#endif /* nsComponentManagerUtils_h__ */ + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl new file mode 100644 index 00000000..509f7870 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsISimpleEnumerator.idl" + +/* + * nsICategoryManager + * @status FROZEN + */ + +[scriptable, uuid(3275b2cd-af6d-429a-80d7-f0c5120342ac)] +interface nsICategoryManager : nsISupports +{ + /** + * Get the value for the given category's entry. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry you're looking for ("http") + * @return The value. + */ + string getCategoryEntry(in string aCategory, in string aEntry); + + /** + * Add an entry to a category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aValue The value for the entry ("moz.httprulez.1") + * @param aPersist Should this data persist between invocations? + * @param aReplace Should we replace an existing entry? + * @return Previous entry, if any + */ + string addCategoryEntry(in string aCategory, in string aEntry, + in string aValue, in boolean aPersist, + in boolean aReplace); + + /** + * Delete an entry from the category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aPersist Delete persistent data from registry, if present? + */ + void deleteCategoryEntry(in string aCategory, in string aEntry, + in boolean aPersist); + + /** + * Delete a category and all entries. + * @param aCategory The category to be deleted. + */ + void deleteCategory(in string aCategory); + + /** + * Enumerate the entries in a category. + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategory(in string aCategory); + + /** + * Enumerate all existing categories + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategories(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl new file mode 100644 index 00000000..e934057c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIProgrammingLanguage.idl" + +/** + * Provides information about a specific implementation class + * @status FROZEN + */ + +[scriptable, uuid(986c11d0-f340-11d4-9075-0010a4e73d9a)] +interface nsIClassInfo : nsISupports +{ + /** + * Get an ordered list of the interface ids that instances of the class + * promise to implement. Note that nsISupports is an implicit member + * of any such list and need not be included. + * + * Should set *count = 0 and *array = null and return NS_OK if getting the + * list is not supported. + */ + void getInterfaces(out PRUint32 count, + [array, size_is(count), retval] out nsIIDPtr array); + + /** + * Get a language mapping specific helper object that may assist in using + * objects of this class in a specific lanaguage. For instance, if asked + * for the helper for nsIProgrammingLanguage::JAVASCRIPT this might return + * an object that can be QI'd into the nsIXPCScriptable interface to assist + * XPConnect in supplying JavaScript specific behavior to callers of the + * instance object. + * + * see: nsIProgrammingLanguage.idl + * + * Should return null if no helper available for given language. + */ + nsISupports getHelperForLanguage(in PRUint32 language); + + /** + * A contract ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute string contractID; + + /** + * A human readable string naming the class, or null. + */ + readonly attribute string classDescription; + + /** + * A class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute nsCIDPtr classID; + + /** + * Return language type from list in nsIProgrammingLanguage + */ + + readonly attribute PRUint32 implementationLanguage; + + /** + * Bitflags for 'flags' attribute. + */ + const PRUint32 SINGLETON = 1 << 0; + const PRUint32 THREADSAFE = 1 << 1; + const PRUint32 MAIN_THREAD_ONLY = 1 << 2; + const PRUint32 DOM_OBJECT = 1 << 3; + const PRUint32 PLUGIN_OBJECT = 1 << 4; + const PRUint32 EAGER_CLASSINFO = 1 << 5; + /** + * 'flags' attribute bitflag: whether objects of this type implement + * nsIContent. + */ + const PRUint32 CONTENT_NODE = 1 << 6; + + // The high order bit is RESERVED for consumers of these flags. + // No implementor of this interface should ever return flags + // with this bit set. + const PRUint32 RESERVED = 1 << 31; + + + readonly attribute PRUint32 flags; + + /** + * Also a class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|). If the class does + * not have a CID, it should return NS_ERROR_NOT_AVAILABLE. This attribute + * exists so C++ callers can avoid allocating and freeing a CID, as would + * happen if they used classID. + */ + [notxpcom] readonly attribute nsCID classIDNoAlloc; + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl new file mode 100644 index 00000000..d1b4be6e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFactory.idl" +#include "nsIFile.idl" +#include "nsIComponentManager.idl" + +[object, uuid(c073cfc0-567c-11d3-aec1-0000f8e25c06)] +interface nsIComponentLoader : nsISupports { + + /** + * Get the factory for a given component. + */ + nsIFactory getFactory(in nsIIDRef aCID, in string aLocation, + in string aType); + + /** + * Initialize the loader. + * + * We use nsISupports here because nsIRegistry isn't IDLized yet. + */ + void init(in nsIComponentManager aCompMgr, in nsISupports aRegistry); + + /** + * Called when a component of the appropriate type is registered, + * to give the component loader an opportunity to do things like + * annotate the registry and such. + */ + void onRegister(in nsIIDRef aCID, in string aType, + in string aClassName, in string aContractID, + in string aLocation, in boolean aReplace, + in boolean aPersist); + + /** + * When is AutoRegistration occuring? + */ + const long Startup = 0; + const long Component = 1; + const long Timer = 2; + + /** + * AutoRegister components in the given directory. + */ + void autoRegisterComponents(in long aWhen, in nsIFile aDirectory); + + /** + * AutoRegister the given component. + * + * Returns true if the component was registered, false if it couldn't + * attempt to register the component (wrong type) and ``throws'' an + * NS_FAILED code if there was an error during registration. + */ + boolean autoRegisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * AutoUnregister the given component. + * Returns true if the component was unregistered, false if it coudln't + * attempt to unregister the component (not found, wrong type). + */ + boolean autoUnregisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * Register any deferred (NS_ERROR_FACTORY_REGISTER_AGAIN) components. + * Return registered-any-components? + */ + boolean registerDeferredComponents(in long aWhen); + + /** + * Unload all components that are willing. + */ + void unloadAll(in long aWhen); + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl new file mode 100644 index 00000000..9f1784d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl @@ -0,0 +1,72 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status EXPERIMENTAL + * + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + */ + +#include "nsISupports.idl" + +interface nsIFile; + +[uuid(fce83d37-a3c0-4e09-ad9f-6842a984dbdf)] +interface nsIComponentLoaderManager : nsISupports +{ + boolean hasFileChanged(in nsIFile file, in string loaderString, in PRInt64 modDate); + void saveFileInfo(in nsIFile file, in string loaderString, in PRInt64 modDate); + void removeFileInfo(in nsIFile file, in string loaderString); + void flushPersistentStore(in boolean now); + + string getOptionalData(in nsIFile file, in string loaderString); + void setOptionalData(in nsIFile file, in string loaderString, in string value); +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl new file mode 100644 index 00000000..20661803 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl @@ -0,0 +1,111 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * The nsIComponentManager interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFactory; + +[scriptable, uuid(a88e5a60-205a-4bb1-94e1-2628daf51eae)] +interface nsIComponentManager : nsISupports +{ + /** + * getClassObject + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObject(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * getClassObjectByContractID + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObjectByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); +}; + + +%{ C++ +#ifndef MOZILLA_STRICT_API +#include "nsComponentManagerUtils.h" +#include "nsComponentManagerObsolete.h" +#endif +%} C++ diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl new file mode 100644 index 00000000..ac5f7975 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFactory.idl" + +interface nsIFile; +interface nsIEnumerator; + +[scriptable, uuid(8458a740-d5dc-11d2-92fb-00e09805570f)] +interface nsIComponentManagerObsolete : nsISupports +{ + /** + * findFactory + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + nsIFactory findFactory(in nsCIDRef aClass); + + /** + * getClassObject + * + * @param aClass : CID of the class whose class object is requested + * @param aIID : IID of an interface that the class object is known to + * to implement. nsISupports and nsIFactory are known to + * be implemented by the class object. + */ + [noscript] voidPtr getClassObject(in nsCIDRef aClass, in nsIIDRef aIID); + + /** + * contractIDToClassID + * + * Get the ClassID for a given ContractID. Many ClassIDs may implement a + * ContractID. In such a situation, this returns the preferred ClassID, which + * happens to be the last registered ClassID. + * + * @param aContractID : Contractid for which ClassID is requested + * @return aClass : ClassID return + */ + [notxpcom] nsresult contractIDToClassID(in string aContractID, out nsCID aClass); + + /** + * classIDToContractid + * + * Get the ContractID for a given ClassID. A ClassIDs may implement multiple + * ContractIDs. This function return the last registered ContractID. + * + * @param aClass : ClassID for which ContractID is requested. + * @return aClassName : returns class name asssociated with aClass + * @return : ContractID last registered for aClass + */ + string CLSIDToContractID(in nsCIDRef aClass, out string aClassName); + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. This is a convenience function that effectively does + * ContractIDToClassID() followed by CreateInstance(). + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef IID); + /** + * registryLocationForSpec + * + * Given a file specification, return the registry representation of + * the filename. Files that are found relative to the components + * directory will have a registry representation + * "rel:" while filenames that are not, will have + * "abs:". + */ + string registryLocationForSpec(in nsIFile aSpec); + + /** + * specForRegistyLocation + * + * Create a file specification for the registry representation (rel:/abs:) + * got via registryLocationForSpec. + */ + nsIFile specForRegistryLocation(in string aLocation); + + /** + * registerFactory + * + * Register a factory and ContractID associated with CID aClass + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * @param aReplace : Boolean that indicates whether to replace a previous + * registration for the CID aClass. + */ + void registerFactory(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFactory aFactory, + in boolean aReplace); + + /** + * registerComponent + * + * Register a native dll module via its registry representation as returned + * by registryLocationForSpec() as the container of CID implemenation + * aClass and associate aContractID and aClassName to the CID aClass. Native + * dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLocation : Location of module (dll). Format of this is the + * registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponent(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aLocation, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentWithType + * + * Register a module's location via its registry representation + * as returned by registryLocationForSpec() as the container of CID implemenation + * aClass of type aType and associate aContractID and aClassName to the CID aClass. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aSpec : Filename spec for module's location. + * @param aLocation : Location of module of type aType. Format of this string + * is the registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * loader registration for aClass. + * @param aPersist : Remember this registration across sessions. + * @param aType : Component Type of CID aClass. + */ + void registerComponentWithType(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aSpec, + in string aLocation, in boolean aReplace, + in boolean aPersist, in string aType); + + /** + * registerComponentSpec + * + * Register a native dll module via its file specification as the container + * of CID implemenation aClass and associate aContractID and aClassName to the + * CID aClass. Native dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLibrary : File specification Location of module (dll). + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentSpec(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aLibrary, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentLib + * + * Register a native dll module via its dll name (not full path) as the + * container of CID implemenation aClass and associate aContractID and aClassName + * to the CID aClass. Native dll component type is assumed and the system + * services will be used to load this dll. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aDllNameLocation : Dll name of module. + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentLib(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aDllName, + in boolean aReplace, in boolean aPersist); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : ClassID being unregistered + * @param aFactory : Factory previously registered to create instances of + * ClassID aClass. + */ + void unregisterFactory(in nsCIDRef aClass, in nsIFactory aFactory); + + /** + * unregisterComponent + * + * Disassociate module aLocation represented as registry location as returned + * by registryLocationForSpec() as containing ClassID aClass. + * + * @param aClass : ClassID being unregistered + * @param aLocation : Location of module. Format of this is the registry + * representation as returned by registryLocationForSpec(). + * Components of any type will be unregistered. + */ + void unregisterComponent(in nsCIDRef aClass, in string aLocation); + + /** + * unregisterComponentSpec + * + * Disassociate module references by file specification aLibrarySpec as + * containing ClassID aClass. + */ + void unregisterComponentSpec(in nsCIDRef aClass, in nsIFile aLibrarySpec); + + /** + * freeLibraries + * + * Enumerates all loaded modules and unloads unused modules. + */ + void freeLibraries(); + + /** + * ID values for 'when' + */ + const long NS_Startup = 0; + const long NS_Script = 1; + const long NS_Timer = 2; + const long NS_Shutdown = 3; + + /** + * autoRegister + * + * Enumerates directory looking for modules of all types and registers + * modules who have changed (modtime or size) since the last time + * autoRegister() was invoked. + * + * @param when : ID values of when the call is being made. + * @param directory : Directory the will be enumerated. + */ + void autoRegister(in long when, in nsIFile directory); + + /** + * autoRegisterComponent + * + * Loads module using appropriate loader and gives it an opportunity to + * register its CIDs if module's modtime or size changed since the last + * time this was called. + * + * @param when : ID values of when the call is being made. + * @param aFileLocation : File specification of module. + */ + void autoRegisterComponent(in long when, in nsIFile aFileLocation); + + /** + * autoUnregisterComponent + * + * Loads module using approriate loader and gives it an opportunity to + * unregister its CIDs + */ + void autoUnregisterComponent(in long when, in nsIFile aFileLocation); + + /** + * isRegistered + * + * Returns true if a factory or module is registered for CID aClass. + * + * @param aClass : ClassID queried for registeration + * @return : true if a factory or module is registered for CID aClass. + * false otherwise. + */ + boolean isRegistered(in nsCIDRef aClass); + + /** + * enumerateCLSIDs + * + * Enumerate the list of all registered ClassIDs. + * + * @return : enumerator for ClassIDs. + */ + nsIEnumerator enumerateCLSIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. + */ + nsIEnumerator enumerateContractIDs(); +}; + +%{ C++ +/* include after the class def'n, because it needs to see it. */ +#include "nsComponentManagerUtils.h" +%} C++ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h new file mode 100644 index 00000000..a21ee7e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIComponentManagerUtils_h__ +#define nsIComponentManagerUtils_h__ + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl new file mode 100644 index 00000000..2a4a55db --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl @@ -0,0 +1,243 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFile; +interface nsIFactory; +interface nsISimpleEnumerator; + +[scriptable, uuid(2417cbfe-65ad-48a6-b4b6-eb84db174392)] +interface nsIComponentRegistrar : nsISupports +{ + /** + * autoRegister + * + * Register a component file or all component files in a directory. + * + * Component files must have an associated loader and export the required + * symbols which this loader defines. For example, if the given file is a + * native library (which is built into XPCOM), it must export the symbol + * "NSGetModule". Other loaders may have different semantics. + * + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, then every component file in the + * directory will be registered. + * If the aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered (see nsIDirectoryService.idl) + * + * @return NS_OK : Registration was successful. + * NS_ERROR: Method failure. + */ + void autoRegister(in nsIFile aSpec); + + /** + * autoUnregister + * + * Unregister a component file or all component files in a directory. + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, the every component file in the directory + * will be registered. + * If aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered. (see nsIDirectoryService.idl) + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void autoUnregister(in nsIFile aSpec); + + + /** + * registerFactory + * + * Register a factory with a given ContractID, CID and Class Name. + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * + * @return NS_OK Registration was successful. + * NS_ERROR* method failure. + */ + void registerFactory(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFactory aFactory); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFactory : Factory previously registered to create instances of + * CID aClass. + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactory(in nsCIDRef aClass, + in nsIFactory aFactory); + + /** + * registerFactoryLocation + * + * Register a factory with a given ContractID, CID and Class Name + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader specifies. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aType : Component Type of CID aClass. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + */ + void registerFactoryLocation(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFile aFile, + in string aLoaderStr, + in string aType); + + /** + * unregisterFactoryLocation + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFile : Component File previously registered + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactoryLocation(in nsCIDRef aClass, + in nsIFile aFile); + + /** + * isCIDRegistered + * + * Returns true if a factory is registered for the CID. + * + * @param aClass : CID queried for registeration + * @return : true if a factory is registered for CID + * false otherwise. + */ + boolean isCIDRegistered(in nsCIDRef aClass); + + /** + * isContractIDRegistered + * + * Returns true if a factory is registered for the contract id. + * + * @param aClass : contract id queried for registeration + * @return : true if a factory is registered for contract id + * false otherwise. + */ + boolean isContractIDRegistered(in string aContractID); + + /** + * enumerateCIDs + * + * Enumerate the list of all registered CIDs. + * + * @return : enumerator for CIDs. Elements of the enumeration can be QI'ed + * for the nsISupportsID interface. From the nsISupportsID, you + * can obtain the actual CID. + */ + nsISimpleEnumerator enumerateCIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. Elements of the enumeration can be + * QI'ed for the nsISupportsCString interface. From the + * nsISupportsCString interface, you can obtain the actual + * Contract ID string. + */ + nsISimpleEnumerator enumerateContractIDs(); + + /** + * CIDToContractID + * + * Returns the Contract ID for a given CID, if one exists and is registered. + * + * @return : Contract ID. + */ + string CIDToContractID(in nsCIDRef aClass); + + /** + * contractIDToCID + * + * Returns the CID for a given Contract ID, if one exists and is registered. + * + * @return : Contract ID. + */ + nsCIDPtr contractIDToCID(in string aContractID); + +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl new file mode 100644 index 00000000..bda0b43a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * A class factory allows the creation of nsISupports derived + * components without specifying a concrete base class. + * + * @status FROZEN + */ + +[scriptable, object, uuid(00000001-0000-0000-c000-000000000046)] +interface nsIFactory : nsISupports { + /** + * Creates an instance of a component. + * + * @param aOuter Pointer to a component that wishes to be aggregated + * in the resulting instance. This will be nsnull if no + * aggregation is requested. + * @param iid The IID of the interface being requested in + * the component which is being currently created. + * @param result [out] Pointer to the newly created instance, if successful. + * @return NS_OK - Component successfully created and the interface + * being requested was successfully returned in result. + * NS_NOINTERFACE - Interface not accessible. + * NS_ERROR_NO_AGGREGATION - if an 'outer' object is supplied, but the + * component is not aggregatable. + * NS_ERROR* - Method failure. + */ + void createInstance(in nsISupports aOuter, in nsIIDRef iid, + [retval, iid_is(iid)] out nsQIResult result); + + /** + * LockFactory provides the client a way to keep the component + * in memory until it is finished with it. The client can call + * LockFactory(PR_TRUE) to lock the factory and LockFactory(PR_FALSE) + * to release the factory. + * + * @param lock - Must be PR_TRUE or PR_FALSE + * @return NS_OK - If the lock operation was successful. + * NS_ERROR* - Method failure. + */ + void lockFactory(in PRBool lock); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIModule.idl b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl new file mode 100644 index 00000000..a71b9b13 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; +interface nsIComponentManager; + +/** + * The nsIModule interface. + * @status FROZEN + */ + +[scriptable, uuid(7392D032-5371-11d3-994E-00805FD26FEE)] +interface nsIModule : nsISupports +{ + /** + * Object Instance Creation + * + * Obtains a Class Object from a nsIModule for a given CID and IID pair. + * This class object can either be query to a nsIFactory or a may be + * query to a nsIClassInfo. + * + * @param aCompMgr : The global component manager + * @param aClass : ClassID of object instance requested + * @param aIID : IID of interface requested + * + */ + void getClassObject(in nsIComponentManager aCompMgr, + in nsCIDRef aClass, + in nsIIDRef aIID, + [retval, iid_is(aIID)] out nsQIResult aResult); + + + /** + * One time registration callback + * + * When the nsIModule is discovered, this method will be + * called so that any setup registration can be preformed. + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr: Opaque loader specific string + * @param aType : Loader Type being used to load this module + */ + void registerSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr, + in string aType); + /** + * One time unregistration callback + * + * When the nsIModule is being unregistered, this method will be + * called so that any unregistration can be preformed + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr : Opaque loader specific string + * + */ + void unregisterSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr); + + /** + * Module load management + * + * @param aCompMgr : The global component manager + * + * @return indicates to the caller if the module can be unloaded. + * Returning PR_TRUE isn't a guarantee that the module will be + * unloaded. It constitues only willingness of the module to be + * unloaded. It is very important to ensure that no outstanding + * references to the module's code/data exist before returning + * PR_TRUE. + * Returning PR_FALSE guaratees that the module wont be unloaded. + */ + boolean canUnload(in nsIComponentManager aCompMgr); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl new file mode 100644 index 00000000..c5d18111 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; + +[uuid(10d1a2a2-d816-458d-a4c3-0805ff0f7b31)] +interface nsINativeComponentLoader : nsISupports +{ + + /** + * addDependentLibrary + * + * This method informs the native component loader that the + * given component library referenced by |aFile| requires + * symbols that can be found in the library named |aLibName|. + * + * The native component loader is expected to resolve these + * external symobls prior to loading the component library. + * + * @param aFile + * The native component file location that is declaring a + * a dependency. This file is expected to be a DSO/DLL. + * + * @param aLibName + * This is a name of a library that the component requires. + * This file name is found in either the GRE bin directory + * or the application's bin directory. Full file path are + * also accepted. Passing nsnull for the |aLibName| will + * clear all dependencies. Note that non null aLibName + * values are expected to be in the native charset. + */ + + void addDependentLibrary(in nsIFile aFile, in string aLibName); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl new file mode 100644 index 00000000..200c2a69 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 "nsISupports.idl" + +/** + * The nsIServiceManager manager interface provides a means to obtain + * global services in an application. The service manager depends on the + * repository to find and instantiate factories to obtain services. + * + * Users of the service manager must first obtain a pointer to the global + * service manager by calling NS_GetServiceManager. After that, + * they can request specific services by calling GetService. When they are + * finished they can NS_RELEASE() the service as usual. + * + * A user of a service may keep references to particular services indefinitely + * and only must call Release when it shuts down. + * + * @status FROZEN + */ + +[scriptable, uuid(8bb35ed9-e332-462d-9155-4a002ab5c958)] +interface nsIServiceManager : nsISupports +{ + /** + * getServiceByContractID + * + * Returns the instance that implements aClass or aContractID and the + * interface aIID. This may result in the instance being created. + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param result : resulting service + */ + void getService(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + void getServiceByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * isServiceInstantiated + * + * isServiceInstantiated will return a true if the service has already + * been created, otherwise false + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param aIID : IID of interface requested + */ + boolean isServiceInstantiated(in nsCIDRef aClass, in nsIIDRef aIID); + boolean isServiceInstantiatedByContractID(in string aContractID, in nsIIDRef aIID); +}; + + +%{C++ +#define NS_ERROR_SERVICE_NOT_AVAILABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_NOT_FOUND NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_IN_USE NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 23) + +// Observing xpcom startup. If you component has not been created, it will be. +#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup" + +// Observing xpcom shutdown +#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown" + +// Observing xpcom autoregistration. Topics will be 'start' and 'stop'. +#define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration" + +#ifndef MOZILLA_STRICT_API +#include "nsXPCOM.h" +#include "nsIServiceManagerUtils.h" +#include "nsIServiceManagerObsolete.h" +#endif +%} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h new file mode 100644 index 00000000..dc229c76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIServiceManagerObsolete_h___ +#define nsIServiceManagerObsolete_h___ + +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIServiceManager.idl for the supported interface +// to the service manager. +// +//////////////////////////////////////////////////////////////////// + +#include "nsIComponentManager.h" +#include "nsID.h" + +#ifndef nsCOMPtr_h___ +#include "nsCOMPtr.h" +#endif + +class nsIServiceManager; +class nsIShutdownListener; +class nsIDirectoryServiceProvider; + +class nsServiceManagerObsolete; + +#define NS_ISERVICEMANAGER_OBSOLETE_IID \ +{ /* cf0df3b0-3401-11d2-8163-006008119d7a */ \ + 0xcf0df3b0, \ + 0x3401, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +/** + * The nsIServiceManagerObsolete manager is obsolete. Please refer + * to nsIServiceManager. + */ +class nsIServiceManagerObsolete : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISERVICEMANAGER_OBSOLETE_IID); + + /** + * RegisterService may be called explicitly to register a service + * with the service manager. If a service is not registered explicitly, + * the component manager will be used to create an instance according + * to the class ID specified. + */ + NS_IMETHOD + RegisterService(const nsCID& aClass, nsISupports* aService) = 0; + + /** + * Requests a service to be shut down, possibly unloading its DLL. + * + * @returns NS_OK - if shutdown was successful and service was unloaded, + * @returns NS_ERROR_SERVICE_NOT_FOUND - if shutdown failed because + * the service was not currently loaded + * @returns NS_ERROR_SERVICE_IN_USE - if shutdown failed because some + * user of the service wouldn't voluntarily release it by using + * a shutdown listener. + */ + NS_IMETHOD + UnregisterService(const nsCID& aClass) = 0; + + NS_IMETHOD + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + NS_IMETHOD + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + NS_IMETHOD + RegisterService(const char* aContractID, nsISupports* aService) = 0; + + NS_IMETHOD + UnregisterService(const char* aContractID) = 0; + + NS_IMETHOD + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE */ + NS_IMETHOD + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + +}; + +// Interface to Global Services +class NS_COM nsServiceManager { +public: + + static nsresult + RegisterService(const nsCID& aClass, nsISupports* aService); + + static nsresult + UnregisterService(const nsCID& aClass); + + static nsresult + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + static nsresult + RegisterService(const char* aContractID, nsISupports* aService); + + static nsresult + UnregisterService(const char* aContractID); + + static nsresult + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + + //////////////////////////////////////////////////////////////////////////// + // These methods return really nsIServiceManagerObsolete, but they are + // statically cast to nsIServiceManager to preserve backwards compatiblity. + static nsresult GetGlobalServiceManager(nsIServiceManager* *result); + static nsresult ShutdownGlobalServiceManager(nsIServiceManager* *result); +}; + + +#define NS_DECL_NSISERVICEMANAGEROBSOLETE \ + NS_IMETHOD RegisterService(const nsCID& aClass, nsISupports* aService); \ + NS_IMETHOD UnregisterService(const nsCID& aClass);\ + NS_IMETHOD GetService(const nsCID& aClass, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const nsCID& aClass, nsISupports* service, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD RegisterService(const char* aContractID, nsISupports* aService);\ + NS_IMETHOD UnregisterService(const char* aContractID);\ + NS_IMETHOD GetService(const char* aContractID, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const char* aContractID, nsISupports* service, nsIShutdownListener* shutdownListener); + +//////////////////////////////////////////////////////////////////////////////// + +#define NS_ISHUTDOWNLISTENER_IID \ +{ /* 56decae0-3406-11d2-8163-006008119d7a */ \ + 0x56decae0, \ + 0x3406, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +class nsIShutdownListener; + + +template +inline +nsresult +CallGetService( const nsCID &aClass, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +//////////////////////////////////////////////////////////////////////////////// + + +#endif /* nsIServiceManagerObsolete_h___ */ + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h new file mode 100644 index 00000000..b7b432af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIServiceManagerUtils_h__ +#define nsIServiceManagerUtils_h__ + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsCOMPtr.h" + +//////////////////////////////////////////////////////////////////////////// +// Using servicemanager with COMPtrs +class NS_COM nsGetServiceByCID : public nsCOMPtr_helper +{ + public: + nsGetServiceByCID( const nsCID& aCID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mCID(aCID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const nsCID& mCID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, 0, error); +} + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, aServiceManager, error); +} + +class NS_COM nsGetServiceByContractID : public nsCOMPtr_helper +{ + public: + nsGetServiceByContractID( const char* aContractID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mContractID(aContractID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + // Implement a dummy destructor to workaround linking issue on Solaris gcc 4.8.2 (see @bugref{5838}) + ~nsGetServiceByContractID() {} + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const char* mContractID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, 0, error); +} + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, aServiceManager, error); +} + +class nsGetServiceFromCategory : public nsCOMPtr_helper +{ + public: + nsGetServiceFromCategory(const char* aCategory, const char* aEntry, + nsISupports* aServiceManager, + nsresult* aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + protected: + const char* mCategory; + const char* mEntry; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceFromCategory +do_GetServiceFromCategory( const char* category, const char* entry, + nsresult* error = 0) +{ + return nsGetServiceFromCategory(category, entry, 0, error); +} + +// type-safe shortcuts for calling |GetService| +template +inline +nsresult +CallGetService( const nsCID &aClass, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetServiceByContractID(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsModule.h b/src/libs/xpcom18a4/xpcom/components/nsModule.h new file mode 100644 index 00000000..56a06354 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsModule.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Marco Pesenti Gritti + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsModule_h__ +#define nsModule_h__ + +#include "nsIModule.h" +#include "nsIFile.h" +#include "nsIComponentManager.h" + +// Exported Function from module dll to Create the nsIModule +#define NS_GET_MODULE_SYMBOL "NSGetModule" + +extern "C" NS_EXPORT nsresult PR_CALLBACK +NSGetModule(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + +typedef nsresult (PR_CALLBACK *nsGetModuleProc)(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + + +#endif /* nsModule_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp new file mode 100644 index 00000000..a3fd5df8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp @@ -0,0 +1,1150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include "prmem.h" +#include "prerror.h" +#include "prsystem.h" // PR_GetDirectorySeparator +#include "nsNativeComponentLoader.h" +#include "nsComponentManager.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsIModule.h" +#include "xcDll.h" +#include "nsHashtable.h" +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "nsIObserverService.h" + +#if defined(XP_MAC) // sdagley dougt fix +#include +#include +#include "nsILocalFileMac.h" +#endif + +#include "prlog.h" +extern PRLogModuleInfo *nsComponentManagerLog; + +static PRBool PR_CALLBACK +DLLStore_Destroy(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll* entry = NS_STATIC_CAST(nsDll*, aData); + delete entry; + return PR_TRUE; +} + +nsNativeComponentLoader::nsNativeComponentLoader() : + mCompMgr(nsnull), + mLoadedDependentLibs(16, PR_TRUE), + mDllStore(nsnull, nsnull, DLLStore_Destroy, + nsnull, 256, PR_TRUE) +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNativeComponentLoader, + nsIComponentLoader, + nsINativeComponentLoader) + +NS_IMETHODIMP +nsNativeComponentLoader::GetFactory(const nsIID & aCID, + const char *aLocation, + const char *aType, + nsIFactory **_retval) +{ + nsresult rv; + + if (!_retval) + return NS_ERROR_NULL_POINTER; + + /* use a hashtable of WeakRefs to store the factory object? */ + + /* Should this all live in xcDll? */ + nsDll *dll; + rv = CreateDll(nsnull, aLocation, &dll); + if (NS_FAILED(rv)) + return rv; + + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + + if (!dll->IsLoaded()) { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: loading \"%s\"", + displayPath.get())); +#endif + if (!dll->Load()) { + + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: load FAILED")); + + char errorMsg[1024] = ""; + + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "GetFactory", errorMsg); + + return NS_ERROR_FAILURE; + } + } + + /* Get service manager for factory */ + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(rv)) + return rv; // XXX translate error code? + + rv = GetFactoryFromModule(dll, aCID, _retval); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: Factory creation %s for %s", + (NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"), + aLocation)); + + // If the dll failed to get us a factory. But the dll registered that + // it would be able to create a factory for this CID. mmh! + // We cannot just delete the dll as the dll could be hosting + // other CID for which factory creation can pass. + // We will just let it be. The effect will be next time we try + // creating the object, we will query the dll again. Since the + // dll is loaded, this aint a big hit. So for optimized builds + // this is ok to limp along. + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed"); + + return rv; +} + +NS_IMETHODIMP +nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg) +{ + mCompMgr = aCompMgr; + if (!mCompMgr) + return NS_ERROR_INVALID_ARG; + + return NS_OK; +} + +NS_IMETHODIMP +nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen, + nsIFile *aDirectory) +{ +#ifdef DEBUG + /* do we _really_ want to print this every time? */ + fprintf(stderr, "nsNativeComponentLoader: autoregistering begins.\n"); +#endif + + nsresult rv = RegisterComponentsInDir(aWhen, aDirectory); + +#ifdef DEBUG + fprintf(stderr, "nsNativeComponentLoader: autoregistering %s\n", + NS_FAILED(rv) ? "FAILED" : "succeeded"); +#endif + + return rv; +} + +nsresult +nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when, + nsIFile *dir) +{ + nsresult rv = NS_ERROR_FAILURE; + PRBool isDir = PR_FALSE; + +#if 0 + // Going to many of these checks is a performance hit on the mac. + // Since these routines are called relatively infrequently and + // we will fail anyway down the line if a directory aint there, + // we are commenting this check out. + + // Make sure we are dealing with a directory + rv = dir->IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + + if (!isDir) + return NS_ERROR_INVALID_ARG; +#endif /* 0 */ + + // Create a directory iterator + nsCOMPtr dirIterator; + rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator)); + + if (NS_FAILED(rv)) return rv; + + // whip through the directory to register every file + nsCOMPtr dirEntry; + PRBool more = PR_FALSE; + + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + while (more == PR_TRUE) + { + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); + if (NS_SUCCEEDED(rv)) + { + rv = dirEntry->IsDirectory(&isDir); + if (NS_SUCCEEDED(rv)) + { + if (isDir == PR_TRUE) + { + // This is a directory. Grovel for components into the directory. +#ifdef RT_OS_DARWIN // But not if it's a debug bundle. + nsCAutoString leafName; + rv = dirEntry->GetNativeLeafName(leafName); + if ( NS_FAILED(rv) + || leafName.Length() < sizeof(".dSYM") + || PL_strcasecmp(leafName.get() + (leafName.Length() - sizeof(".dSYM") + 1), ".dSYM")) +#endif + rv = RegisterComponentsInDir(when, dirEntry); + } + else + { + PRBool registered; + // This is a file. Try to register it. + rv = AutoRegisterComponent(when, dirEntry, ®istered); + } + } + } + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + } + + return rv; +} + +static nsresult PR_CALLBACK +nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (!dll || dll->IsLoaded() == PR_FALSE) + { + return NS_ERROR_INVALID_ARG; + } + + // Get if the dll was marked for unload in an earlier round + PRBool dllMarkedForUnload = dll->IsMarkedForUnload(); + + // Reset dll marking for unload just in case we return with + // an error. + dll->MarkForUnload(PR_FALSE); + + PRBool canUnload = PR_FALSE; + + // Get the module object + nsCOMPtr mobj; + /* XXXshaver cheat and use the global component manager */ + rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager), + getter_AddRefs(mobj)); + if (NS_SUCCEEDED(rv)) + { + rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload); + } + + mobj = nsnull; // Release our reference to the module object + // When shutting down, whether we can unload the dll or not, + // we will shutdown the dll to release any memory it has got + if (when == nsIComponentManagerObsolete::NS_Shutdown) + { + dll->Shutdown(); + } + + // Check error status on CanUnload() call + if (NS_FAILED(rv)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.", + displayPath.get())); +#endif + return rv; + } + + if (canUnload) + { + if (dllMarkedForUnload) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get())); +#endif + +#ifdef DEBUG_dougt + // XXX dlls aren't counting their outstanding instances correctly + // XXX hence, dont unload until this gets enforced. + rv = dll->Unload(); +#endif /* 0 */ + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get())); +#endif + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get())); +#endif + rv = NS_ERROR_FAILURE; + } + return rv; +} + +struct freeLibrariesClosure +{ + nsIServiceManager *serviceMgr; + PRInt32 when; +}; + +static PRBool PR_CALLBACK +nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll *dll = (nsDll *) aData; + struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure; + nsFreeLibrary(dll, + (callData ? callData->serviceMgr : NULL), + (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer)); + return PR_TRUE; +} + +/* + * SelfRegisterDll + * + * Given a dll abstraction, this will load, selfregister the dll and + * unload the dll. + * + */ +nsresult +nsNativeComponentLoader::SelfRegisterDll(nsDll *dll, + const char *registryLocation, + PRBool deferred) +{ + // Precondition: dll is not loaded already, unless we're deferred + PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE); + + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + char errorMsg[1024] = "Cannot get error from nspr. Not enough memory."; + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "SelfRegisterDll", errorMsg); + + return NS_ERROR_FAILURE; + } + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get())); +#endif + + // Tell the module to self register + nsCOMPtr fs; + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { + /************************************************************* + * WARNING: Why are use introducing 'res2' here and then * + * later assigning it to 'res' rather than just using 'res'? * + * This is because this code turns up a code-generation bug * + * in VC6 on NT. Assigning to 'res' on the next line causes * + * the value of 'dll' to get nulled out! The two seem to be * + * getting aliased together during compilation. * + *************************************************************/ + nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above + if (NS_SUCCEEDED(res2)) { + // in the case of re-registering a component, we want to remove + // any optional data that this file may have had. + AddDependentLibrary(fs, nsnull); + + res = mobj->RegisterSelf(mCompMgr, fs, registryLocation, + nativeComponentType); + } + else + { + res = res2; // don't take this out -- see warning, above + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.", + displayPath.get())); +#endif + } + mobj = NULL; // Force a release of the Module object before unload() + } + + // Update the timestamp and size of the dll in registry + // Don't enter deferred modules in the registry, because it might only be + // able to register on some later autoreg, after another component has been + // installed. + if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) { + PRInt64 modTime; + if (!fs) + return res; + + fs->GetLastModifiedTime(&modTime); + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + return NS_ERROR_FAILURE; + + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + + manager->SaveFileInfo(fs, registryLocation, modTime); + } + + return res; +} + +// +// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing. +// + +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol() +#endif + +nsresult +nsNativeComponentLoader::DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg) +{ + PR_ASSERT(aCallerName != NULL); + + if (nsnull == dll || nsnull == aNsprErrorMsg) + return NS_OK; + + nsCAutoString errorMsg(aNsprErrorMsg); + +#if defined(MOZ_DEMANGLE_SYMBOLS) + // Demangle undefined symbols + nsCAutoString undefinedMagicString("undefined symbol:"); + + PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE); + + if (offset != kNotFound) + { + nsCAutoString symbol(errorMsg); + nsCAutoString demangledSymbol; + + symbol.Cut(0,offset); + + symbol.Cut(0,undefinedMagicString.Length()); + + symbol.StripWhitespace(); + + char demangled[4096] = "\0"; + + nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled)); + + if (demangled && *demangled != '\0') + demangledSymbol = demangled; + + if (!demangledSymbol.IsEmpty()) + { + nsCAutoString tmp(errorMsg); + + + tmp.Cut(offset + undefinedMagicString.Length(), + tmp.Length() - offset - undefinedMagicString.Length()); + + tmp += " \n"; + + tmp += demangledSymbol; + + errorMsg = tmp; + } + } +#endif // MOZ_DEMANGLE_SYMBOLS + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + +#ifdef DEBUG + fprintf(stderr, + "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n", + aCallerName, + displayPath.get(), + errorMsg.get()); +#endif + + // Do NSPR log +#ifdef PR_LOGGING + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s", + aCallerName, + displayPath.get(), + errorMsg.get())); +#endif + return NS_OK; +} + +nsresult +nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll) +{ + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + return(NS_ERROR_FAILURE); + } + + // Tell the module to self register + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get())); +#endif + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + // Get registry location for spec + nsXPIDLCString registryName; + + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &res); + if (obsoleteManager) + res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName)); + + if (NS_FAILED(res)) return res; + mobj->UnregisterSelf(mCompMgr, fs, registryName); + } + return res; +} + +nsresult +nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *unregistered) +{ + + nsresult rv = NS_ERROR_FAILURE; + + *unregistered = PR_FALSE; + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) return rv; + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + (void) observerService->NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + NS_LITERAL_STRING("Unregistering native component").get()); + } + } + + nsDll *dll = NULL; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv) || dll == NULL) return rv; + + rv = SelfUnregisterDll(dll); + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: AutoUnregistration for %s %s.", + (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get())); +#endif + + if (NS_FAILED(rv)) + return rv; + + // Remove any autoreg info about this dll + nsCStringKey key(persistentDescriptor); + mDllStore.RemoveAndDelete(&key); + + nsCOMPtr manager = do_QueryInterface(mCompMgr); + NS_ASSERTION(manager, "Something is terribly wrong"); + + manager->RemoveFileInfo(component, nsnull); + + *unregistered = PR_TRUE; + return rv; +} + +nsresult +nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when, + nsIFile *component, + PRBool *registered) +{ + nsresult rv; + if (!registered) + return NS_ERROR_NULL_POINTER; + + *registered = PR_FALSE; + +#ifndef VBOX + /* this should be a pref or registry entry, or something */ + static const char *ValidDllExtensions[] = { + ".dll", /* Windows */ + ".so", /* Unix */ + ".shlb", /* Mac ? */ + ".dso", /* Unix ? */ + ".dylib", /* Unix: Mach */ + ".so.1.0", /* Unix: BSD */ + ".sl", /* Unix: HP-UX */ +#if defined(VMS) + ".exe", /* Open VMS */ +#endif + ".dlm", /* new for all platforms */ + NULL + }; + + *registered = PR_FALSE; + +#if 0 + // This is a performance hit on mac. Since we have already checked + // this; plus is we dont, load will fail anyway later on, this + // is being commented out. + + // Ensure we are dealing with a file as opposed to a dir + PRBool b = PR_FALSE; + + rv = component->IsFile(&b); + if (NS_FAILED(rv) || !b) + return rv; +#endif /* 0 */ + + // deal only with files that have a valid extension + PRBool validExtension = PR_FALSE; + +#if defined(XP_MAC) // sdagley dougt fix + // rjc - on Mac, check the file's type code (skip checking the creator code) + + nsCOMPtr localFileMac = do_QueryInterface(component); + if (localFileMac) + { + OSType type; + rv = localFileMac->GetFileType(&type); + if (NS_SUCCEEDED(rv)) + { + // on Mac, Mozilla shared libraries are of type 'shlb' + // Note: we don't check the creator (which for Mozilla is 'MOZZ') + // so that 3rd party shared libraries will be noticed! + validExtension = ((type == 'shlb') || (type == 'NSPL')); + } + } + +#else + nsCAutoString leafName; + rv = component->GetNativeLeafName(leafName); + if (NS_FAILED(rv)) return rv; + int flen = leafName.Length(); + for (int i=0; ValidDllExtensions[i] != NULL; i++) + { + int extlen = PL_strlen(ValidDllExtensions[i]); + + // Does fullname end with this extension + if (flen >= extlen && + !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i]) + ) + { + validExtension = PR_TRUE; + break; + } + } +#endif + + if (validExtension == PR_FALSE) + // Skip invalid extensions + return NS_OK; + +#else /* VBOX */ + /* VBox: Only one valid suffix exist, so dispense with the the list. */ +# ifdef RT_OS_DARWIN +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dylib"; +# else + static const char s_szSuff[] = ".dylib"; + static const char s_szSuffInvalid[] = "-x86.dylib"; +# endif +# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dll"; +#else + static const char s_szSuff[] = ".dll"; + static const char s_szSuffInvalid[] = "-x86.dll"; +# endif +# else +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.so"; +#else + static const char s_szSuff[] = ".so"; + static const char s_szSuffInvalid[] = "-x86.so"; +# endif +# endif + + nsCAutoString strLeafName; + rv = component->GetNativeLeafName(strLeafName); + if (NS_FAILED(rv)) + return rv; + size_t cchLeafName = strLeafName.Length(); + if ( cchLeafName <= sizeof(s_szSuff) + || PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuff) + 1, s_szSuff)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s'...", strLeafName.get())); + return NS_OK; /* skip */ + } +# ifndef VBOX_IN_32_ON_64_MAIN_API + if ( cchLeafName >= sizeof(s_szSuffInvalid) + && !PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuffInvalid) + 1, s_szSuffInvalid)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s' (#2)...", strLeafName.get())); + return NS_OK; /* skip */ + } +# endif + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("... '%s'", strLeafName.get())); +#endif /* VBOX */ + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(persistentDescriptor); + + // Get the registry representation of the dll, if any + nsDll *dll; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv)) + return rv; + + if (dll != NULL) + { + // We already have seen this dll. Check if this dll changed + if (!dll->HasChanged()) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + // Dll hasn't changed. Skip. + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...", + displayPath.get())); +#endif + *registered = PR_TRUE; + return NS_OK; + } + + // Aagh! the dll has changed since the last time we saw it. + // re-register dll + + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + // this string can't come from a string bundle, because we + // don't have string bundles yet. + NS_ConvertASCIItoUCS2 fileName("(no name)"); + + // get the file name + nsCOMPtr dllSpec; + if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec) + { + dllSpec->GetLeafName(fileName); + } + + // this string can't come from a string bundle, because we + // don't have string bundles yet. + (void) observerService-> + NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + PromiseFlatString(NS_LITERAL_STRING("Registering native component ") + + fileName).get()); + } + } + + if (dll->IsLoaded()) + { + // We loaded the old version of the dll and now we find that the + // on-disk copy if newer. Try to unload the dll. + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + + rv = nsFreeLibrary(dll, serviceMgr, when); + if (NS_FAILED(rv)) + { + // THIS IS THE WORST SITUATION TO BE IN. + // Dll doesn't want to be unloaded. Cannot re-register + // this dll. +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: *** Dll already loaded. " + "Cannot unload either. Hence cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return rv; + } + else { + // dll doesn't have a CanUnload proc. Guess it is + // ok to unload it. + dll->Unload(); +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).", + displayPath.get())); +#endif + } + + } // dll isloaded + + // Sanity. + if (dll->IsLoaded()) + { + // We went through all the above to make sure the dll + // is unloaded. And here we are with the dll still + // loaded. Whoever taught dp programming... +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Dll still loaded. Cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FAILURE; + } + } // dll != NULL + else + { + // Create and add the dll to the mDllStore + // It is ok to do this even if the creation of nsDll + // didnt succeed. That way we wont do this again + // when we encounter the same dll. + dll = new nsDll(component, this); + if (dll == NULL) + return NS_ERROR_OUT_OF_MEMORY; + mDllStore.Put(&key, (void *) dll); + } // dll == NULL + + // Either we are seeing the dll for the first time or the dll has + // changed since we last saw it and it is unloaded successfully. + // + // Now we can try register the dll for sure. + nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE); + if (NS_FAILED(res)) + { + if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) { + /* defer for later loading */ + mDeferredComponents.AppendElement(dll); + *registered = PR_TRUE; + return NS_OK; + } else { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: Autoregistration FAILED for " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Autoregistration Passed for " + "\"%s\".", displayPath.get())); +#endif + // Marking dll along with modified time and size in the + // registry happens at PlatformRegister(). No need to do it + // here again. + *registered = PR_TRUE; + } + return NS_OK; +} + +nsresult +nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, + PRBool *aRegistered) +{ +#ifdef DEBUG + fprintf(stderr, "nNCL: registering deferred (%d)\n", + mDeferredComponents.Count()); +#endif + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]); + nsresult rv = SelfRegisterDll(dll, + nsnull, + PR_TRUE); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } +#ifdef DEBUG + if (*aRegistered) + fprintf(stderr, "nNCL: registered deferred, %d left\n", + mDeferredComponents.Count()); + else + fprintf(stderr, "nNCL: didn't register any components, %d left\n", + mDeferredComponents.Count()); +#endif + /* are there any fatal errors? */ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, + PRBool aPersist) +{ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::UnloadAll(PRInt32 aWhen) +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading....")); + + struct freeLibrariesClosure callData; + callData.serviceMgr = NULL; // XXX need to get this as a parameter + callData.when = aWhen; + + // Cycle through the dlls checking to see if they want to be unloaded + mDllStore.Enumerate(nsFreeLibraryEnum, &callData); + return NS_OK; +} + +// +// CreateDll +// The only way to create a dll or get it from the dll cache. This will +// be called in multiple situations: +// +// 1. Autoregister will create one for each dll it is trying to register. This +// call will be passing a spec in. +// {spec, NULL, 0, 0} +// +// 2. GetFactory() This will call CreateDll() with a null spec but will give +// the registry represented name of the dll. If modtime and size are zero, +// we will go the registry to find the right modtime and size. +// {NULL, rel:libpref.so, 0, 0} +// +// 3. Prepopulation of dllCache A dll object created off a registry entry. +// Specifically dll name is stored in rel: or abs: or lib: formats in the +// registry along with its lastModTime and fileSize. +// {NULL, rel:libpref.so, 8985659, 20987} +nsresult +nsNativeComponentLoader::CreateDll(nsIFile *aSpec, + const char *aLocation, + nsDll **aDll) +{ + nsDll *dll; + nsCOMPtr dllSpec; + nsCOMPtr spec; + nsresult rv; + + nsCStringKey key(aLocation); + dll = (nsDll *)mDllStore.Get(&key); + if (dll) + { + *aDll = dll; + return NS_OK; + } + + if (!aSpec) + { + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->SpecForRegistryLocation(aLocation, + getter_AddRefs(spec)); + if (NS_FAILED(rv)) + return rv; + } + else + { + spec = aSpec; + } + + if (!dll) + { + dll = new nsDll(spec, this); + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + } + + *aDll = dll; + mDllStore.Put(&key, dll); + return NS_OK; +} + +nsresult +nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory) +{ + nsresult rv; + + nsCOMPtr module; + rv = aDll->GetModule(mCompMgr, getter_AddRefs(module)); + + if (NS_FAILED(rv)) + return rv; + + return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory), + (void **)aFactory); +} + + +NS_IMETHODIMP +nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName) +{ + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + { + NS_WARNING("Something is terribly wrong"); + return NS_ERROR_FAILURE; + } + + // the native component loader uses the optional data + // to store a space delimited list of dependent library + // names + + if (!libName) + { + manager->SetOptionalData(aFile, nsnull, nsnull); + return NS_OK; + } + + nsXPIDLCString data; + manager->GetOptionalData(aFile, nsnull, getter_Copies(data)); + + if (!data.IsEmpty()) + data.AppendLiteral(" "); + + data.Append(nsDependentCString(libName)); + + manager->SetOptionalData(aFile, nsnull, data); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h new file mode 100644 index 00000000..818596ec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsIComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsDirectoryService.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" +#include "xcDll.h" +#include "nsINativeComponentLoader.h" + +#ifndef nsNativeComponentLoader_h__ +#define nsNativeComponentLoader_h__ + +class nsNativeComponentLoader : public nsIComponentLoader, public nsINativeComponentLoader { + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + NS_DECL_NSINATIVECOMPONENTLOADER + + nsNativeComponentLoader(); + + nsIComponentManager* mCompMgr; // weak reference -- backpointer + nsHashtable mLoadedDependentLibs; + + private: + nsObjectHashtable mDllStore; + nsVoidArray mDeferredComponents; + + ~nsNativeComponentLoader() {} + + NS_IMETHOD RegisterComponentsInDir(PRInt32 when, nsIFile *dir); + + nsresult CreateDll(nsIFile *aSpec, const char *aLocation, nsDll **aDll); + nsresult SelfRegisterDll(nsDll *dll, const char *registryLocation, + PRBool deferred); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory); + + nsresult DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg); +}; + +#endif /* nsNativeComponentLoader_h__ */ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h new file mode 100644 index 00000000..da3e7a43 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h @@ -0,0 +1,27 @@ + +#ifndef OBSOLETE_MODULE_LOADING +/* + * Prototypes for dynamic library export functions. Your DLL/DSO needs to export + * these methods to play in the component world. + * + * THIS IS OBSOLETE. Look at nsIModule.idl + */ + +extern "C" NS_EXPORT nsresult NSGetFactory(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +extern "C" NS_EXPORT PRBool NSCanUnload(nsISupports* aServMgr); +extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char *fullpath); +extern "C" NS_EXPORT nsresult NSUnregisterSelf(nsISupports* aServMgr, const char *fullpath); + +typedef nsresult (*nsFactoryProc)(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +typedef PRBool (*nsCanUnloadProc)(nsISupports* aServMgr); +typedef nsresult (*nsRegisterProc)(nsISupports* aServMgr, const char *path); +typedef nsresult (*nsUnregisterProc)(nsISupports* aServMgr, const char *path); +#endif /* OBSOLETE_MODULE_LOADING */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp new file mode 100644 index 00000000..dd6856d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp @@ -0,0 +1,155 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsComponentManager.h" + +extern PRBool gXPCOMShuttingDown; + +// Global service manager interface (see nsIServiceManagerObsolete.h) + +nsresult +nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result) +{ + if (gXPCOMShuttingDown) + return NS_ERROR_UNEXPECTED; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + // this method does not addref for historical reasons. + // we return the nsIServiceManagerObsolete interface via a cast. + *result = (nsIServiceManager*) NS_STATIC_CAST(nsIServiceManagerObsolete*, + nsComponentManagerImpl::gComponentManager); + return NS_OK; +} + +nsresult +nsServiceManager::ShutdownGlobalServiceManager(nsIServiceManager* *result) +{ + return NS_OK; +} + +nsresult +nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetService(aClass, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aClass, aService); +} + +nsresult +nsServiceManager::UnregisterService(const nsCID& aClass) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aClass); +} + +//////////////////////////////////////////////////////////////////////////////// +// let's do it again, this time with ContractIDs... + +nsresult +nsServiceManager::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetServiceByContractID(aContractID, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const char* aContractID, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aContractID, aService); +} + +nsresult +nsServiceManager::UnregisterService(const char* aContractID) +{ + // Don't create the global service manager here because we might + // be shutting down, and releasing all the services in its + // destructor + if (gXPCOMShuttingDown) + return NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aContractID); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h new file mode 100644 index 00000000..c770afdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIModule.h" +#include "nsModule.h" + +struct nsStaticModuleInfo { + const char *name; + nsGetModuleProc getModule; +}; + +// Must be implemented by some part of the app, if we're building the +// static component loader. +extern "C" { +typedef nsresult (PR_CALLBACK *NSGetStaticModuleInfoFunc)(nsStaticModuleInfo **info, PRUint32 *count); +extern NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp new file mode 100644 index 00000000..b17b74bb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsStaticComponent.h" +#include "nsIComponentLoader.h" +#include "nsVoidArray.h" +#include "pldhash.h" +#include NEW_H +#include + +struct StaticModuleInfo : public PLDHashEntryHdr { + nsStaticModuleInfo info; + nsCOMPtr module; +}; + +class nsStaticComponentLoader : public nsIComponentLoader +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + + nsStaticComponentLoader() : + mAutoRegistered(PR_FALSE), mLoadedInfo(PR_FALSE) { + } + + static NS_HIDDEN_(PLDHashOperator) PR_CALLBACK + info_RegisterSelf(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +private: + ~nsStaticComponentLoader() { + if (mInfoHash.ops) + PL_DHashTableFinish(&mInfoHash); + } + +protected: + nsresult GetModuleInfo(); + nsresult GetInfoFor(const char *aLocation, StaticModuleInfo **retval); + + PRBool mAutoRegistered; + PRBool mLoadedInfo; + nsCOMPtr mComponentMgr; + PLDHashTable mInfoHash; + static PLDHashTableOps sInfoHashOps; + nsVoidArray mDeferredComponents; +}; + +PR_STATIC_CALLBACK(void) +info_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, entry); + info->module = 0; + info->~StaticModuleInfo(); +} + +PR_STATIC_CALLBACK(PRBool) +info_InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) +{ + // Construct so that our nsCOMPtr is zeroed, etc. + new (NS_STATIC_CAST(void *, entry)) StaticModuleInfo(); + return PR_TRUE; +} + +/* static */ PLDHashTableOps nsStaticComponentLoader::sInfoHashOps = { + PL_DHashAllocTable, PL_DHashFreeTable, + PL_DHashGetKeyStub, PL_DHashStringKey, PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, info_ClearEntry, + PL_DHashFinalizeStub, info_InitEntry +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsStaticComponentLoader, nsIComponentLoader) + +NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; + +nsresult +nsStaticComponentLoader::GetModuleInfo() +{ + if (mLoadedInfo) + return NS_OK; + + if (!mInfoHash.ops) { // creation failed in init, why are we here? + NS_WARNING("operating on uninitialized static component loader"); + return NS_ERROR_NOT_INITIALIZED; + } + + if (! NSGetStaticModuleInfo) { + // We're a static build with no static modules to + // register. This can happen in shared uses (such as the GRE) + return NS_OK; + } + + nsStaticModuleInfo *infoList; + PRUint32 count; + nsresult rv; + if (NS_FAILED(rv = (*NSGetStaticModuleInfo)(&infoList, &count))) + return rv; + for (PRUint32 i = 0; i < count; i++) { + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, infoList[i].name, + PL_DHASH_ADD)); + if (!info) + return NS_ERROR_OUT_OF_MEMORY; + info->info = infoList[i]; + } + + mLoadedInfo = PR_TRUE; + return NS_OK; +} + +nsresult +nsStaticComponentLoader::GetInfoFor(const char *aLocation, + StaticModuleInfo **retval) +{ + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, aLocation, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(info)) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + if (!info->module) { + rv = info->info.getModule(mComponentMgr, nsnull, + getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: GetInfoFor(\"%s\"): %x\n", aLocation, rv); +#endif + if (NS_FAILED(rv)) + return rv; + } + + *retval = info; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::Init(nsIComponentManager *mgr, nsISupports *aReg) +{ + mComponentMgr = mgr; + if (!PL_DHashTableInit(&mInfoHash, &sInfoHashOps, nsnull, + sizeof(StaticModuleInfo), 1024)) { + mInfoHash.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsStaticComponentLoader::info_RegisterSelf(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + nsStaticComponentLoader *loader = NS_STATIC_CAST(nsStaticComponentLoader *, + arg); + nsIComponentManager *mgr = loader->mComponentMgr; + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, hdr); + + nsresult rv; + if (!info->module) { + rv = info->info.getModule(mgr, nsnull, getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: getModule(\"%s\"): %x\n", info->info.name, rv); +#endif + if (NS_FAILED(rv)) + return PL_DHASH_NEXT; // oh well. + } + + rv = info->module->RegisterSelf(mgr, nsnull, info->info.name, + staticComponentType); +#ifdef DEBUG + fprintf(stderr, "nSCL: autoreg of \"%s\": %x\n", info->info.name, rv); +#endif + + if (rv == NS_ERROR_FACTORY_REGISTER_AGAIN) + loader->mDeferredComponents.AppendElement(info); + + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponents(PRInt32 when, nsIFile *dir) +{ + if (mAutoRegistered) + return NS_OK; + + // if a directory has been explicitly specified, then return early. we + // don't load static components from disk ;) + if (dir) + return NS_OK; + + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + PL_DHashTableEnumerate(&mInfoHash, info_RegisterSelf, this); + + mAutoRegistered = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponent(PRInt32 when, nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::RegisterDeferredComponents(PRInt32 when, + PRBool *aRegistered) +{ + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, + mDeferredComponents[i]); + nsresult rv = info->module->RegisterSelf(mComponentMgr, nsnull, + info->info.name, + staticComponentType); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::OnRegister(const nsCID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, PRBool aPersist) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::UnloadAll(PRInt32 aWhen) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::GetFactory(const nsCID &aCID, const char *aLocation, + const char *aType, nsIFactory **_retval) +{ + StaticModuleInfo *info; + nsresult rv; + + if (NS_FAILED(rv = GetInfoFor(aLocation, &info))) + return rv; + + return info->module->GetClassObject(mComponentMgr, aCID, + NS_GET_IID(nsIFactory), + (void **)_retval); +} + +nsresult +NS_NewStaticComponentLoader(nsIComponentLoader **retval) +{ + NS_IF_ADDREF(*retval = NS_STATIC_CAST(nsIComponentLoader *, + new nsStaticComponentLoader)); + return *retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.cpp b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp new file mode 100644 index 00000000..494cf174 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsDll + * + * Abstraction of a Dll. Stores modifiedTime and size for easy detection of + * change in dll. + * + * dp Suresh + */ + +#include "xcDll.h" +#include "nsDebug.h" +#include "nsIComponentManager.h" +#include "nsIComponentLoaderManager.h" +#include "nsIModule.h" +#include "nsILocalFile.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsITimelineService.h" +#include "nsModule.h" +#ifdef DEBUG +#if defined(VMS) +#include +#include +#elif defined(XP_MACOSX) +#include +#endif +#endif /* defined(DEBUG) */ + +#include "nsTraceRefcntImpl.h" + +#define UNLOAD_DEPENDENT_LIBS +#ifdef HPUX +#undef UNLOAD_DEPENDENT_LIBS +#endif + +#include "nsNativeComponentLoader.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include "nsMemory.h" +#endif + +nsDll::nsDll(nsIFile *dllSpec, nsNativeComponentLoader *loader) + : m_dllSpec(do_QueryInterface(dllSpec)), + m_instance(NULL), + m_moduleObject(NULL), + m_loader(loader), + m_markForUnload(PR_FALSE) +{ + NS_ASSERTION(loader, "Null loader when creating a nsDLL"); +} + +nsDll::~nsDll(void) +{ + //#if DEBUG_dougt + // The dll gets deleted when the dllStore is destroyed. This happens on + // app shutdown. At that point, unloading dlls can cause crashes if we have + // - dll dependencies + // - callbacks + // - static dtors + // Hence turn it back on after all the above have been removed. + //Unload(); + //#endif +} + +void +nsDll::GetDisplayPath(nsACString& aLeafName) +{ + m_dllSpec->GetNativeLeafName(aLeafName); + + if (aLeafName.IsEmpty()) + aLeafName.AssignLiteral("unknown!"); +} + +PRBool +nsDll::HasChanged() +{ + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + // If mod date has changed, then dll has changed + PRInt64 currentDate; + nsresult rv = m_dllSpec->GetLastModifiedTime(¤tDate); + if (NS_FAILED(rv)) + return PR_TRUE; + PRBool changed = PR_TRUE; + manager->HasFileChanged(m_dllSpec, nsnull, currentDate, &changed); + return changed; +} + +PRBool nsDll::Load(void) +{ + if (m_instance != NULL) + { + // Already loaded + return (PR_TRUE); + } + + if (m_dllSpec) + { +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + + // Load any library dependencies + // The Component Loader Manager may hold onto some extra data + // set by either the native component loader or the native + // component. We assume that this data is a space delimited + // listing of dependent libraries which are required to be + // loaded prior to us loading the given component. Once, the + // component is loaded into memory, we can release our hold + // on the dependent libraries with the assumption that the + // component library holds a reference via the OS so loader. + +#if defined(XP_UNIX) + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + nsXPIDLCString extraData; + manager->GetOptionalData(m_dllSpec, nsnull, getter_Copies(extraData)); + +#ifdef UNLOAD_DEPENDENT_LIBS + nsVoidArray dependentLibArray; +#endif + + // if there was any extra data, treat it as a listing of dependent libs + if (extraData != nsnull) + { + // all dependent libraries are suppose to be in the "gre" directory. + // note that the gre directory is the same as the "bin" directory, + // when there isn't a real "gre" found. + + nsXPIDLCString path; + nsCOMPtr file; + NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); + + if (!file) + return NS_ERROR_FAILURE; + + // we are talking about a file in the GRE dir. Lets append something + // stupid right now, so that later we can just set the leaf name. + file->AppendNative(NS_LITERAL_CSTRING("dummy")); + +# ifdef VBOX_USE_IPRT_IN_XPCOM + char *buffer = (char *)nsMemory::Clone(extraData, strlen(extraData) + 1); +# else + char *buffer = strdup(extraData); +# endif + if (!buffer) + return NS_ERROR_OUT_OF_MEMORY; + + char* newStr; + char *token = nsCRT::strtok(buffer, " ", &newStr); + while (token!=nsnull) + { + nsCStringKey key(token); + if (m_loader->mLoadedDependentLibs.Get(&key)) { + token = nsCRT::strtok(newStr, " ", &newStr); + continue; + } + + m_loader->mLoadedDependentLibs.Put(&key, (void*)1); + + nsXPIDLCString libpath; + file->SetNativeLeafName(nsDependentCString(token)); + file->GetNativePath(path); + if (!path) + return NS_ERROR_FAILURE; + + // Load this dependent library with the global flag and stash + // the result for later so that we can unload it. + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_Pathname; + + // if the depend library path starts with a / we are + // going to assume that it is a full path and should + // be loaded without prepending the gre diretory + // location. We could have short circuited the + // SetNativeLeafName above, but this is clearer and + // the common case is a relative path. + + if (token[0] == '/') + libSpec.value.pathname = token; + else + libSpec.value.pathname = path; + + PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); + // if we couldn't load the dependent library. We did the best we + // can. Now just let us fail later if this really was a required + // dependency. +#ifdef UNLOAD_DEPENDENT_LIBS + if (lib) + dependentLibArray.AppendElement((void*)lib); +#endif + + token = nsCRT::strtok(newStr, " ", &newStr); + } +# ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(buffer); +# else + free(buffer); +# endif + } +#endif + + // load the component + nsCOMPtr lf(do_QueryInterface(m_dllSpec)); + NS_ASSERTION(lf, "nsIFile here must implement a nsILocalFile"); + lf->Load(&m_instance); + +#if defined(XP_UNIX) + // Unload any of library dependencies we loaded earlier. The assumption + // here is that the component will have a "internal" reference count to + // the dependency library we just loaded. + // XXX should we unload later - or even at all? + +#ifdef UNLOAD_DEPENDENT_LIBS + if (extraData != nsnull) + { + PRInt32 arrayCount = dependentLibArray.Count(); + for (PRInt32 index = 0; index < arrayCount; index++) + PR_UnloadLibrary((PRLibrary*)dependentLibArray.ElementAt(index)); + } +#endif +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); + if (m_instance) { + // Inform refcnt tracer of new library so that calls through the + // new library can be traced. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + nsTraceRefcntImpl::LoadLibrarySymbols(displayPath.get(), m_instance); + } +#endif + } + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + // Debugging help for components. Component dlls need to have their + // symbols loaded before we can put a breakpoint in the debugger. + // This will help figureing out the point when the dll was loaded. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + BreakAfterLoad(displayPath.get()); +#endif + + return ((m_instance == NULL) ? PR_FALSE : PR_TRUE); +} + +PRBool nsDll::Unload(void) +{ + if (m_instance == NULL) + return (PR_FALSE); + + // Shutdown the dll + Shutdown(); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + PRStatus ret = PR_UnloadLibrary(m_instance); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + + if (ret == PR_SUCCESS) + { + m_instance = NULL; + return (PR_TRUE); + } + else + return (PR_FALSE); +} + +void * nsDll::FindSymbol(const char *symbol) +{ + if (symbol == NULL) + return (NULL); + + // If not already loaded, load it now. + if (Load() != PR_TRUE) + return (NULL); + + return(PR_FindSymbol(m_instance, symbol)); +} + + +// Component dll specific functions +nsresult nsDll::GetDllSpec(nsIFile **fsobj) +{ + NS_ASSERTION(m_dllSpec, "m_dllSpec NULL"); + NS_ASSERTION(fsobj, "xcDll::GetModule : Null argument" ); + + *fsobj = m_dllSpec; + NS_ADDREF(*fsobj); + return NS_OK; +} + +nsresult nsDll::GetModule(nsISupports *servMgr, nsIModule **cobj) +{ + // using the backpointer of the loader. + nsIComponentManager* compMgr = m_loader->mCompMgr; + NS_ASSERTION(compMgr, "Global Component Manager is null" ); + if (!compMgr) return NS_ERROR_UNEXPECTED; + + NS_ASSERTION(cobj, "xcDll::GetModule : Null argument" ); + + if (m_moduleObject) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + return NS_OK; + } + + // If not already loaded, load it now. + if (Load() != PR_TRUE) return NS_ERROR_FAILURE; + + // We need a nsIFile for location + if (!m_dllSpec) + { + return NS_ERROR_FAILURE; + } + + nsGetModuleProc proc = + (nsGetModuleProc) FindSymbol(NS_GET_MODULE_SYMBOL); + + if (proc == NULL) + return NS_ERROR_FACTORY_NOT_LOADED; + + nsresult rv = (*proc) (compMgr, m_dllSpec, &m_moduleObject); + if (NS_SUCCEEDED(rv)) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + } + return rv; +} + + +// These are used by BreakAfterLoad, below. +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +static nsCString *sBreakList[16]; +static int sBreakListCount = 0; +#endif + +nsresult nsDll::Shutdown(void) +{ + // Release the module object if we got one + nsrefcnt refcnt; + if (m_moduleObject) + { + NS_RELEASE2(m_moduleObject, refcnt); + NS_ASSERTION(refcnt == 0, "Dll moduleObject refcount non zero"); + } +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + for (int i = 0; i < sBreakListCount; i++) + { + delete sBreakList[i]; + sBreakList[i] = nsnull; + } + sBreakListCount = 0; +#endif + return NS_OK; + +} +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +void nsDll::BreakAfterLoad(const char *nsprPath) +{ + static PRBool firstTime = PR_TRUE; + + // return if invalid input + if (!nsprPath || !*nsprPath) return; + + // return if nothing to break on + if (!firstTime && sBreakListCount == 0) return; + + if (firstTime) + { + firstTime = PR_FALSE; + // Form the list of dlls to break on load + nsCAutoString envList(getenv("XPCOM_BREAK_ON_LOAD")); + if (envList.IsEmpty()) return; + PRInt32 ofset = 0; + PRInt32 start = 0; + do + { + ofset = envList.FindChar(':', start); + sBreakList[sBreakListCount] = new nsCString(); + envList.Mid(*(sBreakList[sBreakListCount]), start, ofset); + sBreakListCount++; + start = ofset + 1; + } + while (ofset != -1 && 16 > sBreakListCount); // avoiding vc6.0 compiler issue. count < thinks it is starting a template + } + + // Find the dllname part of the string + nsCString currentPath(nsprPath); + PRInt32 lastSep = currentPath.RFindCharInSet(":\\/"); + + for (int i=0; i 0) + { + // Loading a dll that we want to break on + // Put your breakpoint here + fprintf(stderr, "...Loading module %s\n", nsprPath); + // Break in the debugger here. +#if defined(__i386) && defined(__GNUC__) + asm("int $3"); +#elif defined(VMS) + lib$signal(SS$_DEBUG); +#elif defined(XP_MACOSX) + raise(SIGTRAP); +#endif + } + return; +} +#endif /* SHOULD_IMPLEMENT_BREAKAFTERLOAD */ diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.h b/src/libs/xpcom18a4/xpcom/components/xcDll.h new file mode 100644 index 00000000..5de5b0eb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.h @@ -0,0 +1,121 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Dll + * + * Programmatic representation of a dll. Stores modifiedTime and size for + * easy detection of change in dll. + * + * dp Suresh + */ + +#ifndef xcDll_h__ +#define xcDll_h__ + +#include "prio.h" +#include "prlink.h" +#include "nsISupports.h" +#include "nsILocalFile.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +class nsNativeComponentLoader; + +#if defined(DEBUG) && !defined(XP_BEOS) +#define SHOULD_IMPLEMENT_BREAKAFTERLOAD +#endif + +class nsIModule; +class nsIServiceManager; + +typedef enum nsDllStatus +{ + DLL_OK = 0, + DLL_NO_MEM = 1, + DLL_STAT_ERROR = 2, + DLL_NOT_FILE = 3, + DLL_INVALID_PARAM = 4 +} nsDllStatus; + +class nsDll +{ +private: + nsCOMPtr m_dllSpec; + PRLibrary *m_instance; + nsIModule *m_moduleObject; + nsNativeComponentLoader *m_loader; + PRBool m_markForUnload; + + void Init(nsIFile *dllSpec); + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + void BreakAfterLoad(const char *nsprPath); +#endif + +public: + + nsDll(nsIFile *dllSpec, nsNativeComponentLoader* loader); + ~nsDll(void); + + // Dll Loading + PRBool Load(void); + PRBool Unload(void); + PRBool IsLoaded(void) + { + return ((m_instance != 0) ? PR_TRUE : PR_FALSE); + } + void MarkForUnload(PRBool mark) { m_markForUnload = mark; } + PRBool IsMarkedForUnload(void) { return m_markForUnload; } + + // Shutdown the dll. This will call any on unload hook for the dll. + // This wont unload the dll. Unload() implicitly calls Shutdown(). + nsresult Shutdown(void); + + void *FindSymbol(const char *symbol); + + PRBool HasChanged(void); + + void GetDisplayPath(nsACString& string); + + PRLibrary *GetInstance(void) { return (m_instance); } + + // NS_RELEASE() is required to be done on objects returned + nsresult GetDllSpec(nsIFile **dllSpec); + nsresult GetModule(nsISupports *servMgr, nsIModule **mobj); +}; + +#endif /* xcDll_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/doc/README b/src/libs/xpcom18a4/xpcom/doc/README new file mode 100644 index 00000000..edef8772 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/doc/README @@ -0,0 +1,8 @@ + + + READ ME + + + +

+XPCOM documentation can be found at + * + * 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 "nsArray.h" +#include "nsArrayEnumerator.h" +#include "nsWeakReference.h" + +// used by IndexOf() +struct findIndexOfClosure +{ + nsISupports *targetElement; + PRUint32 startIndex; + PRUint32 resultIndex; +}; + +PR_STATIC_CALLBACK(PRBool) FindElementCallback(void* aElement, void* aClosure); + + +NS_IMPL_ISUPPORTS2(nsArray, nsIArray, nsIMutableArray) + +nsArray::~nsArray() +{ + Clear(); +} + +NS_IMETHODIMP +nsArray::GetLength(PRUint32* aLength) +{ + *aLength = mArray.Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsArray::QueryElementAt(PRUint32 aIndex, + const nsIID& aIID, + void ** aResult) +{ + nsISupports * obj = mArray.ObjectAt(aIndex); + if (!obj) return NS_ERROR_UNEXPECTED; + + // no need to worry about a leak here, because ObjectAt() doesn't + // addref its result + return obj->QueryInterface(aIID, aResult); +} + +NS_IMETHODIMP +nsArray::IndexOf(PRUint32 aStartIndex, nsISupports* aElement, + PRUint32* aResult) +{ + // optimize for the common case by forwarding to mArray + if (aStartIndex == 0) { + *aResult = mArray.IndexOf(aElement); + if (*aResult == -1) + return NS_ERROR_FAILURE; + return NS_OK; + } + + findIndexOfClosure closure = { aElement, aStartIndex, 0 }; + PRBool notFound = mArray.EnumerateForwards(FindElementCallback, &closure); + if (notFound) + return NS_ERROR_FAILURE; + + *aResult = closure.resultIndex; + return NS_OK; +} + +NS_IMETHODIMP +nsArray::Enumerate(nsISimpleEnumerator **aResult) +{ + return NS_NewArrayEnumerator(aResult, NS_STATIC_CAST(nsIArray*, this)); +} + +// nsIMutableArray implementation + +NS_IMETHODIMP +nsArray::AppendElement(nsISupports* aElement, PRBool aWeak) +{ + PRBool result; + if (aWeak) { + nsCOMPtr elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "AppendElement: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + result = mArray.AppendObject(elementRef); + } + + else { + // add the object directly + result = mArray.AppendObject(aElement); + } + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::RemoveElementAt(PRUint32 aIndex) +{ + PRBool result = mArray.RemoveObjectAt(aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex, PRBool aWeak) +{ + nsCOMPtr elementRef; + if (aWeak) { + elementRef = + getter_AddRefs(NS_STATIC_CAST(nsISupports*, + NS_GetWeakReference(aElement))); + NS_ASSERTION(elementRef, "InsertElementAt: Trying to use weak references on an object that doesn't support it"); + if (!elementRef) + return NS_ERROR_FAILURE; + } else { + elementRef = aElement; + } + PRBool result = mArray.InsertObjectAt(elementRef, aIndex); + return result ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsArray::Clear() +{ + mArray.Clear(); + return NS_OK; +} + +// +// static helper routines +// +PRBool +FindElementCallback(void *aElement, void* aClosure) +{ + findIndexOfClosure* closure = + NS_STATIC_CAST(findIndexOfClosure*, aClosure); + + nsISupports* element = + NS_STATIC_CAST(nsISupports*, aElement); + + // don't start searching until we're past the startIndex + if (closure->resultIndex >= closure->startIndex && + element == closure->targetElement) { + return PR_FALSE; // stop! We found it + } + closure->resultIndex++; + + return PR_TRUE; +} + +// +// do_QueryElementAt helper stuff +// +nsresult +nsQueryArrayElementAt::operator()(const nsIID& aIID, void** aResult) const + { + nsresult status = mArray + ? mArray->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if (mErrorPtr) + *mErrorPtr = status; + + return status; + } + +// +// exported constructor routines +// +nsresult +NS_NewArray(nsIMutableArray** aResult) +{ + nsArray* arr = new nsArray; + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*,arr); + NS_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& aBaseArray) +{ + nsArray* arr = new nsArray(aBaseArray); + if (!arr) return NS_ERROR_OUT_OF_MEMORY; + + *aResult = NS_STATIC_CAST(nsIMutableArray*, arr); + NS_ADDREF(*aResult); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsArray.h new file mode 100644 index 00000000..4a4f6cf2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArray.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 nsArray_h__ +#define nsArray_h__ + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsCOMPtr.h" + +#define NS_ARRAY_CLASSNAME \ + "nsIArray implementation" + +// {35C66FD1-95E9-4e0a-80C5-C3BD2B375481} +#define NS_ARRAY_CID \ +{ 0x35c66fd1, 0x95e9, 0x4e0a, \ + { 0x80, 0xc5, 0xc3, 0xbd, 0x2b, 0x37, 0x54, 0x81 } } + + +// create a new, empty array +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult); + +// The resulting array will hold an owning reference to every element +// in the original nsCOMArray. This also means that any further +// changes to the original nsCOMArray will not affect the new +// array, and that the original array can go away and the new array +// will still hold valid elements. +nsresult NS_COM +NS_NewArray(nsIMutableArray** aResult, const nsCOMArray_base& base); + +// adapter class to map nsIArray->nsCOMArray +// do NOT declare this as a stack or member variable, use +// nsCOMArray instead! +// if you need to convert a nsCOMArray->nsIArray, see NS_NewArray above +class nsArray : public nsIMutableArray +{ +public: + nsArray() { } + nsArray(const nsCOMArray_base& aBaseArray) : mArray(aBaseArray) + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIARRAY + NS_DECL_NSIMUTABLEARRAY + +private: + ~nsArray(); + + nsCOMArray_base mArray; +}; + + +// helper class for do_QueryElementAt +class NS_COM nsQueryArrayElementAt : public nsCOMPtr_helper + { + public: + nsQueryArrayElementAt(nsIArray* aArray, PRUint32 aIndex, + nsresult* aErrorPtr) + : mArray(aArray), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const; + + private: + nsIArray* mArray; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryArrayElementAt +do_QueryElementAt(nsIArray* aArray, PRUint32 aIndex, nsresult* aErrorPtr = 0) + { + return nsQueryArrayElementAt(aArray, aIndex, aErrorPtr); + } + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp new file mode 100644 index 00000000..c105622a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.cpp @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsArrayEnumerator.h" + +NS_IMPL_ISUPPORTS1(nsSimpleArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSimpleArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsSimpleArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->GetLength(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= cnt) + return NS_ERROR_UNEXPECTED; + + return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports), (void**)aResult); +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array) +{ + nsSimpleArrayEnumerator* enumer = new nsSimpleArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*result = enumer); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +// enumerator implementation for nsCOMArray +// creates a snapshot of the array in question +// you MUST use NS_NewArrayEnumerator to create this, so that +// allocation is done correctly +class nsCOMArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsCOMArrayEnumerator() : mIndex(0) { + } + + // specialized operator to make sure we make room for mValues + void* operator new (size_t size, const nsCOMArray_base& aArray) CPP_THROW_NEW; + void operator delete(void* ptr) { + ::operator delete(ptr); + } + +private: + ~nsCOMArrayEnumerator(void); + +protected: + PRUint32 mIndex; // current position + PRUint32 mArraySize; // size of the array + + // this is actually bigger + nsISupports* mValueArray[1]; +}; + +NS_IMPL_ISUPPORTS1(nsCOMArrayEnumerator, nsISimpleEnumerator) + +nsCOMArrayEnumerator::~nsCOMArrayEnumerator() +{ + // only release the entries that we haven't visited yet + for (; mIndex < mArraySize; ++mIndex) { + NS_IF_RELEASE(mValueArray[mIndex]); + } +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = (mIndex < mArraySize); + return NS_OK; +} + +NS_IMETHODIMP +nsCOMArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mIndex >= mArraySize) + return NS_ERROR_UNEXPECTED; + + // pass the ownership of the reference to the caller. Since + // we AddRef'ed during creation of |this|, there is no need + // to AddRef here + *aResult = mValueArray[mIndex++]; + + // this really isn't necessary. just pretend this happens, since + // we'll never visit this value again! + // mValueArray[(mIndex-1)] = nsnull; + + return NS_OK; +} + +void* +nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) + CPP_THROW_NEW +{ + // create enough space such that mValueArray points to a large + // enough value. Note that the initial value of size gives us + // space for mValueArray[0], so we must subtract + size += (aArray.Count() - 1) * sizeof(aArray[0]); + + // do the actual allocation + nsCOMArrayEnumerator * result = + NS_STATIC_CAST(nsCOMArrayEnumerator*, ::operator new(size)); + + // now need to copy over the values, and addref each one + // now this might seem like alot of work, but we're actually just + // doing all our AddRef's ahead of time since GetNext() doesn't + // need to AddRef() on the way out + PRUint32 i; + PRUint32 max = result->mArraySize = aArray.Count(); + for (i = 0; imValueArray[i] = aArray[i]; + NS_IF_ADDREF(result->mValueArray[i]); + } + + return result; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray) +{ + nsCOMArrayEnumerator *enumerator = new (aArray) nsCOMArrayEnumerator(); + if (!enumerator) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*aResult = enumerator); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h new file mode 100644 index 00000000..e22302b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsArrayEnumerator.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array implementation. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 nsArrayEnumerator_h__ +#define nsArrayEnumerator_h__ + +// enumerator implementation for nsIArray + +#include "nsIArray.h" +#include "nsCOMArray.h" +#include "nsISimpleEnumerator.h" +#include "nsCOMPtr.h" + +class nsSimpleArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + // nsSimpleArrayEnumerator methods + nsSimpleArrayEnumerator(nsIArray* aValueArray) : + mValueArray(aValueArray), mIndex(0) { + } + +private: + ~nsSimpleArrayEnumerator() {} + +protected: + nsCOMPtr mValueArray; + PRUint32 mIndex; +}; + + +// Create an enumerator for an existing nsIArray implementation +// The enumerator holds an owning reference to the array. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsIArray* array); + + +// create an enumerator for an existing nsCOMArray implementation +// The enumerator will hold an owning reference to each ELEMENT in +// the array. This means that the nsCOMArray can safely go away +// without its objects going away. +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *aResult, + const nsCOMArray_base& aArray); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp new file mode 100644 index 00000000..f0366043 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAtomService.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsAtomService, nsIAtomService) + +nsAtomService::nsAtomService() +{ +} + +nsresult +nsAtomService::GetAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +nsresult +nsAtomService::GetPermanentAtom(const PRUnichar *aString, nsIAtom ** aResult) +{ + *aResult = NS_NewPermanentAtom(aString); + + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h new file mode 100644 index 00000000..ae036b80 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomService.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsAtomService_h +#define __nsAtomService_h + +#include "nsIAtomService.h" + +class nsAtomService : public nsIAtomService +{ + public: + nsAtomService(); + NS_DECL_ISUPPORTS + + NS_DECL_NSIATOMSERVICE + + private: + ~nsAtomService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp new file mode 100644 index 00000000..fc92dec8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.cpp @@ -0,0 +1,616 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// vim:cindent:ts=2:et:sw=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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAtomTable.h" +#include "nsStaticAtom.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "pldhash.h" +#include "prenv.h" +#include "nsVoidArray.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "plarena.h" + +class nsStaticAtomWrapper; + +/** + * The shared hash table for atom lookups. + * + * XXX This should be manipulated in a threadsafe way or we should make + * sure it's only manipulated from the main thread. Probably the latter + * is better, since the former would hurt performance. + * + * If |gAtomTable.ops| is 0, then the table is uninitialized. + */ +static PLDHashTable gAtomTable; + +// this is where we keep the nsStaticAtomWrapper objects + +static PLArenaPool* gStaticAtomArena = 0; + +class nsStaticAtomWrapper : public nsIAtom +{ +public: + nsStaticAtomWrapper(const nsStaticAtom* aAtom) : + mStaticAtom(aAtom) + { + MOZ_COUNT_CTOR(nsStaticAtomWrapper); + } + ~nsStaticAtomWrapper() { // no subclasses -> not virtual + // this is arena allocated and won't be called except in debug + // builds. If this function ever does anything non-debug, be sure + // to get rid of the ifdefs in AtomTableClearEntry! + MOZ_COUNT_DTOR(nsStaticAtomWrapper); + } + + NS_IMETHOD QueryInterface(REFNSIID aIID, + void** aInstancePtr); + NS_IMETHOD_(nsrefcnt) AddRef(void); + NS_IMETHOD_(nsrefcnt) Release(void); + + NS_DECL_NSIATOM + + const nsStaticAtom* GetStaticAtom() { + return mStaticAtom; + } +private: + const nsStaticAtom* mStaticAtom; +}; + +// the atomtableentry can contain either an AtomImpl or a +// nsStaticAtomWrapper, indicated by the first bit of PtrBits +typedef unsigned long PtrBits; + +struct AtomTableEntry : public PLDHashEntryHdr { + // mAtom & 0x1 means (mAtom & ~0x1) points to an nsStaticAtomWrapper + // else it points to an nsAtomImpl + PtrBits mAtom; + + inline PRBool IsStaticAtom() const { + return (mAtom & 0x1) != 0; + } + + inline void SetAtomImpl(AtomImpl* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + mAtom = PtrBits(aAtom); + } + + inline void SetStaticAtomWrapper(nsStaticAtomWrapper* aAtom) { + NS_ASSERTION(aAtom, "Setting null atom"); + NS_ASSERTION((PtrBits(aAtom) & ~0x1) == PtrBits(aAtom), + "Pointers must align or this is broken"); + + mAtom = PtrBits(aAtom) | 0x1; + } + + inline void ClearAtom() { + mAtom = nsnull; + } + + inline PRBool HasValue() const { + return (mAtom & ~0x1) != 0; + } + + // these accessors assume that you already know the type + inline AtomImpl *GetAtomImpl() const { + NS_ASSERTION(!IsStaticAtom(), "This is a static atom, not an AtomImpl"); + return (AtomImpl*) (mAtom & ~0x1); + } + + inline nsStaticAtomWrapper *GetStaticAtomWrapper() const { + NS_ASSERTION(IsStaticAtom(), "This is an AtomImpl, not a static atom"); + return (nsStaticAtomWrapper*) (mAtom & ~0x1); + } + + inline const nsStaticAtom* GetStaticAtom() const { + return GetStaticAtomWrapper()->GetStaticAtom(); + } + + // type-agnostic accessors + + // get the string buffer + inline const char* get() const { + return IsStaticAtom() ? GetStaticAtom()->mString : GetAtomImpl()->mString; + } + + // get an addreffed nsIAtom - not using already_AddRef'ed atom + // because the callers are not (and should not be) using nsCOMPtr + inline nsIAtom* GetAtom() const { + nsIAtom* result; + + if (IsStaticAtom()) + result = GetStaticAtomWrapper(); + else { + result = GetAtomImpl(); + NS_ADDREF(result); + } + + return result; + } +}; + +PR_STATIC_CALLBACK(const void *) +AtomTableGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + NS_ASSERTION(he->HasValue(), "Empty atom. how did that happen?"); + return he->get(); +} + +PR_STATIC_CALLBACK(PRBool) +AtomTableMatchKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const AtomTableEntry *he = NS_STATIC_CAST(const AtomTableEntry*, entry); + const char* keyStr = NS_STATIC_CAST(const char*, key); + return nsCRT::strcmp(keyStr, he->get()) == 0; +} + +PR_STATIC_CALLBACK(void) +AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + AtomTableEntry *he = NS_STATIC_CAST(AtomTableEntry*, entry); + + he->keyHash = 0; + + if (!he->IsStaticAtom()) { + AtomImpl *atom = he->GetAtomImpl(); + // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and + // they then remove themselves from the table. In other words, they + // are owned by the callers who own references to them. + // |PermanentAtomImpl| permanent atoms ignore their refcount and are + // deleted when they are removed from the table at table destruction. + // In other words, they are owned by the atom table. + if (atom->IsPermanent()) + delete NS_STATIC_CAST(PermanentAtomImpl*, atom); + } + else { + he->GetStaticAtomWrapper()->~nsStaticAtomWrapper(); + } + + he->ClearAtom(); +} + +static const PLDHashTableOps AtomTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + AtomTableGetKey, + PL_DHashStringKey, + AtomTableMatchKey, + PL_DHashMoveEntryStub, + AtomTableClearEntry, + PL_DHashFinalizeStub, + NULL +}; + + +#ifdef DEBUG + +PR_STATIC_CALLBACK(PLDHashOperator) +DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he, + PRUint32 index, void *arg) +{ + AtomTableEntry *entry = NS_STATIC_CAST(AtomTableEntry*, he); + + if (entry->IsStaticAtom()) + return PL_DHASH_NEXT; + + AtomImpl* atom = entry->GetAtomImpl(); + if (!atom->IsPermanent()) { + ++*NS_STATIC_CAST(PRUint32*, arg); + const char *str; + atom->GetUTF8String(&str); + fputs(str, stdout); + fputs("\n", stdout); + } + return PL_DHASH_NEXT; +} + +#endif + +static inline +void PromoteToPermanent(AtomImpl* aAtom) +{ +#ifdef NS_BUILD_REFCNT_LOGGING + { + nsrefcnt refcount = aAtom->GetRefCount(); + do { + NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl"); + } while (refcount); + } +#endif + aAtom = new (aAtom) PermanentAtomImpl(); +} + +void NS_PurgeAtomTable() +{ + if (gAtomTable.ops) { +#ifdef DEBUG + if (PR_GetEnv("MOZ_DUMP_ATOM_LEAKS")) { + PRUint32 leaked = 0; + printf("*** %d atoms still exist (including permanent):\n", + gAtomTable.entryCount); + PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked); + printf("*** %u non-permanent atoms leaked\n", leaked); + } +#endif + PL_DHashTableFinish(&gAtomTable); + gAtomTable.entryCount = 0; + gAtomTable.ops = nsnull; + + if (gStaticAtomArena) { + PL_FinishArenaPool(gStaticAtomArena); + delete gStaticAtomArena; + gStaticAtomArena = nsnull; + } + } +} + +AtomImpl::AtomImpl() +{ +} + +AtomImpl::~AtomImpl() +{ + NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable"); + // Permanent atoms are removed from the hashtable at shutdown, and we + // don't want to remove them twice. See comment above in + // |AtomTableClearEntry|. + if (!IsPermanent()) { + PL_DHashTableOperate(&gAtomTable, mString, PL_DHASH_REMOVE); + if (gAtomTable.entryCount == 0) { + PL_DHashTableFinish(&gAtomTable); + NS_ASSERTION(gAtomTable.entryCount == 0, + "PL_DHashTableFinish changed the entry count"); + } + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(AtomImpl, nsIAtom) + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release() +{ + return 1; +} + +/* virtual */ PRBool +AtomImpl::IsPermanent() +{ + return PR_FALSE; +} + +/* virtual */ PRBool +PermanentAtomImpl::IsPermanent() +{ + return PR_TRUE; +} + +void* AtomImpl::operator new ( size_t size, const nsACString& aString ) CPP_THROW_NEW +{ + /* + Note: since the |size| will initially also include the |PRUnichar| member + |mString|, our size calculation will give us one character too many. + We use that extra character for a zero-terminator. + + Note: this construction is not guaranteed to be possible by the C++ + compiler. A more reliable scheme is used by |nsShared[C]String|s, see + http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsSharedString.h#174 + */ + size += aString.Length() * sizeof(char); + AtomImpl* ii = NS_STATIC_CAST(AtomImpl*, ::operator new(size)); + + char* toBegin = &ii->mString[0]; + nsACString::const_iterator fromBegin, fromEnd; + *copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin) = '\0'; + return ii; +} + +void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW { + NS_ASSERTION(!aAtom->IsPermanent(), + "converting atom that's already permanent"); + + // Just let the constructor overwrite the vtable pointer. + return aAtom; +} + +NS_IMETHODIMP +AtomImpl::ToString(nsAString& aBuf) +{ + CopyUTF8toUTF16(nsDependentCString(mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::GetUTF8String(const char **aResult) +{ + NS_PRECONDITION(aResult, "null out param"); + *aResult = mString; + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mString); + return NS_OK; +} + +NS_IMETHODIMP +AtomImpl::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUTF16toUTF8(aString).Equals(mString); + return NS_OK; +} + +//---------------------------------------------------------------------- + +// wrapper class for the nsStaticAtom struct + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::AddRef() +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) +nsStaticAtomWrapper::Release() +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(nsStaticAtomWrapper, nsIAtom) + +NS_IMETHODIMP +nsStaticAtomWrapper::GetUTF8String(const char** aResult) +{ + *aResult = mStaticAtom->mString; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToString(nsAString& aBuf) +{ + // static should always be always ASCII, to allow tools like gperf + // to generate the tables, and to avoid unnecessary conversion + NS_ASSERTION(nsCRT::IsAscii(mStaticAtom->mString), + "Data loss - atom should be ASCII"); + CopyASCIItoUCS2(nsDependentCString(mStaticAtom->mString), aBuf); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::ToUTF8String(nsACString& aBuf) +{ + aBuf.Assign(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::EqualsUTF8(const nsACString& aString, PRBool* aResult) +{ + *aResult = aString.Equals(mStaticAtom->mString); + return NS_OK; +} + +NS_IMETHODIMP +nsStaticAtomWrapper::Equals(const nsAString& aString, PRBool* aResult) +{ + *aResult = NS_ConvertUCS2toUTF8(aString).Equals(mStaticAtom->mString); + return NS_OK; +} +//---------------------------------------------------------------------- + +NS_COM nsIAtom* NS_NewAtom(const char* isolatin1) +{ + return NS_NewAtom(nsDependentCString(isolatin1)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom(const char* isolatin1) +{ + return NS_NewPermanentAtom(NS_ConvertASCIItoUCS2(isolatin1)); +} + +static nsStaticAtomWrapper* +WrapStaticAtom(const nsStaticAtom* aAtom) +{ + if (!gStaticAtomArena) { + gStaticAtomArena = new PLArenaPool; + if (!gStaticAtomArena) + return nsnull; + + PL_INIT_ARENA_POOL(gStaticAtomArena, "nsStaticAtomArena", 4096); + } + + void* mem; + PL_ARENA_ALLOCATE(mem, gStaticAtomArena, sizeof(nsStaticAtom)); + + nsStaticAtomWrapper* wrapper = + new (mem) nsStaticAtomWrapper(aAtom); + + return wrapper; +} + +static AtomTableEntry* GetAtomHashEntry(const char* aString) +{ + if (!gAtomTable.ops && + !PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0, + sizeof(AtomTableEntry), 2048)) { + gAtomTable.ops = nsnull; + return nsnull; + } + return NS_STATIC_CAST(AtomTableEntry*, + PL_DHashTableOperate(&gAtomTable, + aString, + PL_DHASH_ADD)); +} + +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, PRUint32 aAtomCount) +{ + // this does two things: + // 1) wraps each static atom in a wrapper, if necessary + // 2) initializes the address pointed to by each mAtom slot + + for (PRUint32 i=0; iHasValue() && aAtoms[i].mAtom) { + // there already is an atom with this name in the table.. but we + // still have to update mAtom + if (!he->IsStaticAtom() && !he->GetAtomImpl()->IsPermanent()) { + // since we wanted to create a static atom but there is + // already one there, we convert it to a non-refcounting + // permanent atom + PromoteToPermanent(he->GetAtomImpl()); + } + + // and now, if the consumer wants to remember this value in a + // slot, we do so + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = he->GetAtom(); + } + + else { + nsStaticAtomWrapper* atom = WrapStaticAtom(&aAtoms[i]); + NS_ASSERTION(atom, "Failed to wrap static atom"); + + // but even if atom is null, no real difference in code.. + he->SetStaticAtomWrapper(atom); + if (aAtoms[i].mAtom) + *aAtoms[i].mAtom = atom; + } + } + return NS_OK; +} + +NS_COM nsIAtom* NS_NewAtom( const nsAString& aString ) +{ + NS_ConvertUCS2toUTF8 utf8String(aString); + + return NS_NewAtom(utf8String); +} + +NS_COM +nsIAtom* +NS_NewAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue()) + return he->GetAtom(); + + AtomImpl* atom = new (aString) AtomImpl(); + he->SetAtomImpl(atom); + if (!atom) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const nsAString& aString ) +{ + return NS_NewPermanentAtom(NS_ConvertUCS2toUTF8(aString)); +} + +NS_COM +nsIAtom* NS_NewPermanentAtom( const nsACString& aString ) +{ + AtomTableEntry *he = GetAtomHashEntry(PromiseFlatCString(aString).get()); + + if (he->HasValue() && he->IsStaticAtom()) + return he->GetStaticAtomWrapper(); + + // either there is no atom and we'll create an AtomImpl, + // or there is an existing AtomImpl + AtomImpl* atom = he->GetAtomImpl(); + + if (atom) { + // ensure that it's permanent + if (!atom->IsPermanent()) { + PromoteToPermanent(atom); + } + } else { + // otherwise, make a new atom + atom = new (aString) PermanentAtomImpl(); + he->SetAtomImpl(atom); + if ( !atom ) { + PL_DHashTableRawRemove(&gAtomTable, he); + return nsnull; + } + } + + NS_ADDREF(atom); + return atom; +} + +NS_COM nsIAtom* NS_NewAtom( const PRUnichar* str ) +{ + return NS_NewAtom(NS_ConvertUCS2toUTF8(str)); +} + +NS_COM nsIAtom* NS_NewPermanentAtom( const PRUnichar* str ) +{ + return NS_NewPermanentAtom(nsDependentString(str)); +} + +NS_COM nsrefcnt NS_GetNumberOfAtoms(void) +{ + return gAtomTable.entryCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h new file mode 100644 index 00000000..d8971cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAtomTable.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsAtomTable_h__ +#define nsAtomTable_h__ + +#include "nsIAtom.h" + +/** + * A threadsafely-refcounted implementation of nsIAtom. Note that + * AtomImpl objects are sometimes converted into PermanentAtomImpl + * objects using placement new and just overwriting the vtable pointer. + */ + +class AtomImpl : public nsIAtom { +public: + AtomImpl(); + +protected: + // We don't need a virtual destructor here because PermanentAtomImpl + // deletions aren't handled through Release(). + ~AtomImpl(); + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIATOM + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW; + + void operator delete(void* ptr) { + ::operator delete(ptr); + } + + // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count + nsrefcnt GetRefCount() { return mRefCnt; } + + // Actually more; 0 terminated. This slot is reserved for the + // terminating zero. + char mString[1]; +}; + +/** + * A non-refcounted implementation of nsIAtom. + */ + +class PermanentAtomImpl : public AtomImpl { +public: +#ifdef AIX + PermanentAtomImpl() : AtomImpl() {} +#endif + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + + virtual PRBool IsPermanent(); + + void* operator new(size_t size, const nsACString& aString) CPP_THROW_NEW { + return AtomImpl::operator new(size, aString); + } + void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW; + +}; + +void NS_PurgeAtomTable(); + +#endif // nsAtomTable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h new file mode 100644 index 00000000..84011369 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsAutoBuffer.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; 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 auto buffer template. + * + * The Initial Developer of the Original Code is + * Conrad Carlen . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jungshik Shin + * + * 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 nsAutoBuffer_h__ +#define nsAutoBuffer_h__ + +#ifndef nsMemory_h__ +#include "nsMemory.h" +#endif + +/** + * A buffer which will use stack space if the requested size will + * fit in the stack buffer and allocate from the heap if not. + * + * Below is a usage example : + * + * typedef nsAutoBuffer nsAutoUnicharBuffer; + * + * nsAutoUnicharBuffer buffer; + * + * if (!buffer.EnsureElemCapacity(initialLength)) + * return NS_ERROR_OUT_OF_MEMORY; + * + * PRUnichar *unicharPtr = buffer.get(); + * + * // add PRUnichar's to the buffer pointed to by |unicharPtr| as long as + * // the number of PRUnichar's is less than |intialLength| + * + * // increase the capacity + * if (!buffer.AddElemCapacity(extraLength)) + * return NS_ERROR_OUT_OF_MEMORY + * + * unicharPtr = buffer.get() + initialLength; + * + * //continue to add PRUnichar's.... + */ + +template +class nsAutoBuffer +{ +public: + nsAutoBuffer() : + mBufferPtr(mStackBuffer), + mCurElemCapacity(sz) + { + } + + ~nsAutoBuffer() + { + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + } + + PRBool EnsureElemCapacity(PRInt32 inElemCapacity) + { + if (inElemCapacity <= mCurElemCapacity) + return PR_TRUE; + + T* newBuffer; + + if (mBufferPtr != mStackBuffer) + newBuffer = (T*)nsMemory::Realloc((void *)mBufferPtr, inElemCapacity * sizeof(T)); + else + newBuffer = (T*)nsMemory::Alloc(inElemCapacity * sizeof(T)); + + if (!newBuffer) + return PR_FALSE; + + if (mBufferPtr != mStackBuffer) + nsMemory::Free(mBufferPtr); + + mBufferPtr = newBuffer; + mCurElemCapacity = inElemCapacity; + return PR_TRUE; + } + + PRBool AddElemCapacity(PRInt32 inElemCapacity) + { + return EnsureElemCapacity(mCurElemCapacity + inElemCapacity); + } + + T* get() const { return mBufferPtr; } + PRInt32 GetElemCapacity() const { return mCurElemCapacity; } + +protected: + + T *mBufferPtr; + T mStackBuffer[sz]; + PRInt32 mCurElemCapacity; +}; + +#endif // nsAutoBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h new file mode 100644 index 00000000..92300c2f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsBaseHashtable.h @@ -0,0 +1,458 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsBaseHashtable_h__ +#define nsBaseHashtable_h__ + +#include "nsTHashtable.h" +#include "prlock.h" +#include "nsDebug.h" + +template +class nsBaseHashtable; // forward declaration + +/** + * the private nsTHashtable::EntryType class used by nsBaseHashtable + * @see nsTHashtable for the specification of this class + * @see nsBaseHashtable for template parameters + */ +template +class nsBaseHashtableET : public KeyClass +{ +public: + DataType mData; + friend class nsTHashtable< nsBaseHashtableET >; + +private: + typedef typename KeyClass::KeyType KeyType; + typedef typename KeyClass::KeyTypePointer KeyTypePointer; + + nsBaseHashtableET(KeyTypePointer aKey); + nsBaseHashtableET(nsBaseHashtableET& toCopy); + ~nsBaseHashtableET(); +}; + +/** + * templated hashtable for simple data types + * This class manages simple data types that do not need construction or + * destruction. Thread-safety is optional, via a flag in Init() + * + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the datatype stored in the hashtable, + * for example, PRUint32 or nsCOMPtr. If UserDataType is not the same, + * DataType must implicitly cast to UserDataType + * @param UserDataType the user sees, for example PRUint32 or nsISupports* + */ +template +class nsBaseHashtable : + protected nsTHashtable< nsBaseHashtableET > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef nsBaseHashtableET EntryType; + + // default constructor+destructor are fine + + /** + * Initialize the object. + * @param initSize the initial number of buckets in the hashtable, + * default 16 + * @param threadSafe whether to provide read/write + * locking on all class methods + * @return PR_TRUE if the object was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE) + { return nsTHashtable::Init(initSize); } + + /** + * Check whether the table has been initialized. + * This function is especially useful for static hashtables. + * @return PR_TRUE if the table has been initialized. + */ + PRBool IsInitialized() const { return this->mTable.entrySize; } + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const + { return nsTHashtable::Count(); } + + /** + * retrieve the value for a key. + * @param aKey the key to retreive + * @param pData data associated with this key will be placed at this + * pointer. If you only need to check if the key exists, pData + * may be null. + * @return PR_TRUE if the key exists. If key does not exist, pData is not + * modified. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const + { + EntryType* ent = this->GetEntry(aKey); + + if (!ent) + return PR_FALSE; + + if (pData) + *pData = ent->mData; + + return PR_TRUE; + } + + /** + * put a new value for the associated key + * @param aKey the key to put + * @param aData the new data + * @return always PR_TRUE, unless memory allocation failed + */ + PRBool Put(KeyType aKey, UserDataType aData) + { + EntryType* ent = this->PutEntry(aKey); + + if (!ent) + return PR_FALSE; + + ent->mData = aData; + + return PR_TRUE; + } + + /** + * remove the data for the associated key + * @param aKey the key to remove from the hashtable + */ + void Remove(KeyType aKey) { this->RemoveEntry(aKey); } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData data being enumerated + * @parm userArg passed unchanged from Enumerate + * @return either + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumReadFunction)(KeyType aKey, + UserDataType aData, + void* userArg); + + /** + * enumerate entries in the hashtable, without allowing changes + * this function read-locks the hashtable, so other threads may read keys + * at the same time in multi-thread environments. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumReadFunction + */ + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumReadArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(NS_CONST_CAST(PLDHashTable*, &this->mTable), + s_EnumReadStub, + &enumData); + } + + /** + * function type provided by the application for enumeration. + * @param aKey the key being enumerated + * @param aData Reference to data being enumerated, may be altered. e.g. for + * nsInterfaceHashtable this is an nsCOMPtr reference... + * @parm userArg passed unchanged from Enumerate + * @return bitflag combination of + * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink + */ + typedef PLDHashOperator + (*PR_CALLBACK EnumFunction)(KeyType aKey, + DataType& aData, + void* userArg); + + /** + * enumerate entries in the hashtable, allowing changes. This + * functions write-locks the hashtable. + * @param enumFunc enumeration callback + * @param userArg passed unchanged to the EnumFunction + */ + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg) + { + NS_ASSERTION(this->mTable.entrySize, + "nsBaseHashtable was not initialized properly."); + + s_EnumArgs enumData = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&this->mTable, + s_EnumStub, + &enumData); + } + + /** + * reset the hashtable, removing all entries + */ + void Clear() { nsTHashtable::Clear(); } + +protected: + /** + * used internally during EnumerateRead. Allocated on the stack. + * @param func the enumerator passed to EnumerateRead + * @param userArg the userArg passed to EnumerateRead + */ + struct s_EnumReadArgs + { + EnumReadFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumReadStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); + + struct s_EnumArgs + { + EnumFunction func; + void* userArg; + }; + + static PLDHashOperator s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg); +}; + +/** + * This class is a thread-safe version of nsBaseHashtable. + */ +template +class nsBaseHashtableMT : + protected nsBaseHashtable +{ +public: + typedef typename + nsBaseHashtable::EntryType EntryType; + typedef typename + nsBaseHashtable::KeyType KeyType; + typedef typename + nsBaseHashtable::EnumFunction EnumFunction; + typedef typename + nsBaseHashtable::EnumReadFunction EnumReadFunction; + + nsBaseHashtableMT() : mLock(nsnull) { } + ~nsBaseHashtableMT(); + + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + PRBool IsInitialized() const { return (PRBool) mLock; } + PRUint32 Count() const; + PRBool Get(KeyType aKey, UserDataType* pData) const; + PRBool Put(KeyType aKey, UserDataType aData); + void Remove(KeyType aKey); + + PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const; + PRUint32 Enumerate(EnumFunction enumFunc, void* userArg); + void Clear(); + +protected: + PRLock* mLock; +}; + + +// +// nsBaseHashtableET definitions +// + +template +nsBaseHashtableET::nsBaseHashtableET(KeyTypePointer aKey) : + KeyClass(aKey) +{ } + +template +nsBaseHashtableET::nsBaseHashtableET + (nsBaseHashtableET& toCopy) : + KeyClass(toCopy), + mData(toCopy.mData) +{ } + +template +nsBaseHashtableET::~nsBaseHashtableET() +{ } + + +// +// nsBaseHashtable definitions +// + +template +PLDHashOperator +nsBaseHashtable::s_EnumReadStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; + + PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); + + NS_ASSERTION( !(res & PL_DHASH_REMOVE ), + "PL_DHASH_REMOVE return during const enumeration; ignoring."); + + if (res & PL_DHASH_STOP) + return PL_DHASH_STOP; + + return PL_DHASH_NEXT; +} + +template +PLDHashOperator +nsBaseHashtable::s_EnumStub + (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg) +{ + EntryType* ent = NS_STATIC_CAST(EntryType*, hdr); + s_EnumArgs* eargs = (s_EnumArgs*) arg; + + return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); +} + + +// +// nsBaseHashtableMT definitions +// + +template +nsBaseHashtableMT::~nsBaseHashtableMT() +{ + if (this->mLock) + PR_DestroyLock(this->mLock); +} + +template +PRBool +nsBaseHashtableMT::Init(PRUint32 initSize) +{ + if (!nsTHashtable::IsInitialized() && !nsTHashtable::Init(initSize)) + return PR_FALSE; + + this->mLock = PR_NewLock(); + NS_WARN_IF_FALSE(this->mLock, "Error creating lock during nsBaseHashtableL::Init()"); + + return (this->mLock != nsnull); +} + +template +PRUint32 +nsBaseHashtableMT::Count() const +{ + PR_Lock(this->mLock); + PRUint32 count = nsTHashtable::Count(); + PR_Unlock(this->mLock); + + return count; +} + +template +PRBool +nsBaseHashtableMT::Get(KeyType aKey, + UserDataType* pData) const +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable::Get(aKey, pData); + PR_Unlock(this->mLock); + + return res; +} + +template +PRBool +nsBaseHashtableMT::Put(KeyType aKey, + UserDataType aData) +{ + PR_Lock(this->mLock); + PRBool res = + nsBaseHashtable::Put(aKey, aData); + PR_Unlock(this->mLock); + + return res; +} + +template +void +nsBaseHashtableMT::Remove(KeyType aKey) +{ + PR_Lock(this->mLock); + nsBaseHashtable::Remove(aKey); + PR_Unlock(this->mLock); +} + +template +PRUint32 +nsBaseHashtableMT::EnumerateRead + (EnumReadFunction fEnumCall, void* userArg) const +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable::EnumerateRead(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template +PRUint32 +nsBaseHashtableMT::Enumerate + (EnumFunction fEnumCall, void* userArg) +{ + PR_Lock(this->mLock); + PRUint32 count = + nsBaseHashtable::Enumerate(fEnumCall, userArg); + PR_Unlock(this->mLock); + + return count; +} + +template +void +nsBaseHashtableMT::Clear() +{ + PR_Lock(this->mLock); + nsBaseHashtable::Clear(); + PR_Unlock(this->mLock); +} + +#endif // nsBaseHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp new file mode 100644 index 00000000..a51ff9d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsByteBuffer.h" +#include "nsIInputStream.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +ByteBufferImpl::ByteBufferImpl(void) + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_IMETHODIMP +ByteBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new char[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(ByteBufferImpl,nsIByteBuffer) + +ByteBufferImpl::~ByteBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_METHOD +ByteBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + ByteBufferImpl* it = new ByteBufferImpl(); + if (nsnull == it) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, (void**)aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetLength(void) const +{ + return mLength; +} + +NS_IMETHODIMP_(PRUint32) +ByteBufferImpl::GetBufferSize(void) const +{ + return mSpace; +} + +NS_IMETHODIMP_(char*) +ByteBufferImpl::GetBuffer(void) const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +ByteBufferImpl::Grow(PRUint32 aNewSize) +{ + if (aNewSize < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + char* newbuf = new char[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRInt32) +ByteBufferImpl::Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) +{ + NS_PRECONDITION(nsnull != aStream, "null stream"); + NS_PRECONDITION(aKeep <= mLength, "illegal keep count"); + if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) { + // whoops + *aErrorCode = NS_BASE_STREAM_ILLEGAL_ARGS; + return -1; + } + + if (0 != aKeep) { + // Slide over kept data + memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep); + } + + // Read in some new data + mLength = aKeep; + PRUint32 nb; + *aErrorCode = aStream->Read(mBuffer + aKeep, mSpace - aKeep, &nb); + if (NS_SUCCEEDED(*aErrorCode)) { + mLength += nb; + } + else + nb = 0; + return nb; +} + +NS_COM nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIByteBuffer* buf; + rv = ByteBufferImpl::Create(aOuter, NS_GET_IID(nsIByteBuffer), (void**)&buf); + if (NS_FAILED(rv)) return rv; + + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h new file mode 100644 index 00000000..0a474570 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsByteBuffer.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsByteBuffer_h__ +#define nsByteBuffer_h__ + +#include "nsIByteBuffer.h" + +class ByteBufferImpl : public nsIByteBuffer { +public: + ByteBufferImpl(void); + + NS_DECL_ISUPPORTS + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRUint32) GetLength(void) const; + NS_IMETHOD_(PRUint32) GetBufferSize(void) const; + NS_IMETHOD_(char*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize); + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep); + + char* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; +private: + ~ByteBufferImpl(); +}; + +#endif // nsByteBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp new file mode 100644 index 00000000..9a270223 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a COM aware array class. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsCOMArray.h" +#include "nsCOMPtr.h" + +PR_STATIC_CALLBACK(PRBool) ReleaseObjects(void* aElement, void*); + +// implementations of non-trivial methods in nsCOMArray_base + +// copy constructor - we can't just memcpy here, because +// we have to make sure we own our own array buffer, and that each +// object gets another AddRef() +nsCOMArray_base::nsCOMArray_base(const nsCOMArray_base& aOther) +{ + // make sure we do only one allocation + mArray.SizeTo(aOther.Count()); + AppendObjects(aOther); +} + +nsCOMArray_base::~nsCOMArray_base() +{ + PRInt32 count = Count(), i; + for (i = 0; i < count; ++i) { + nsISupports* obj = ObjectAt(i); + NS_IF_RELEASE(obj); + } +} + +PRInt32 +nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { + NS_ENSURE_TRUE(aObject, -1); + nsCOMPtr supports = do_QueryInterface(aObject); + NS_ENSURE_TRUE(supports, -1); + + PRInt32 i, count; + PRInt32 retval = -1; + count = mArray.Count(); + for (i = 0; i < count; ++i) { + nsCOMPtr arrayItem = + do_QueryInterface(NS_REINTERPRET_CAST(nsISupports*,mArray.ElementAt(i))); + if (arrayItem == supports) { + retval = i; + break; + } + } + return retval; +} + +PRBool +nsCOMArray_base::InsertObjectAt(nsISupports* aObject, PRInt32 aIndex) { + PRBool result = mArray.InsertElementAt(aObject, aIndex); + if (result) + NS_IF_ADDREF(aObject); + return result; +} + +PRBool +nsCOMArray_base::InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex) { + PRBool result = mArray.InsertElementsAt(aObjects.mArray, aIndex); + if (result) { + // need to addref all these + PRInt32 count = aObjects.Count(); + for (PRInt32 i = 0; i < count; ++i) { + NS_IF_ADDREF(aObjects.ObjectAt(i)); + } + } + return result; +} + +PRBool +nsCOMArray_base::ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex) +{ + // its ok if oldObject is null here + nsISupports *oldObject = + NS_REINTERPRET_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + + PRBool result = mArray.ReplaceElementAt(aObject, aIndex); + + // ReplaceElementAt could fail, such as if the array grows + // so only release the existing object if the replacement succeeded + if (result) { + // Make sure to addref first, in case aObject == oldObject + NS_IF_ADDREF(aObject); + NS_IF_RELEASE(oldObject); + } + return result; +} + +PRBool +nsCOMArray_base::RemoveObject(nsISupports *aObject) +{ + PRBool result = mArray.RemoveElement(aObject); + if (result) + NS_IF_RELEASE(aObject); + return result; +} + +PRBool +nsCOMArray_base::RemoveObjectAt(PRInt32 aIndex) +{ + nsISupports* element = ObjectAt(aIndex); + if (element) { + PRBool result = mArray.RemoveElementAt(aIndex); + if (result) + NS_IF_RELEASE(element); + return result; + } + return PR_FALSE; +} + +// useful for destructors +PRBool +ReleaseObjects(void* aElement, void*) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aElement); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +void +nsCOMArray_base::Clear() +{ + mArray.EnumerateForwards(ReleaseObjects, nsnull); + mArray.Clear(); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h new file mode 100644 index 00000000..cbb728c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCOMArray.h @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a COM aware array class. + * + * The Initial Developer of the Original Code + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 nsCOMArray_h__ +#define nsCOMArray_h__ + +#include "nsVoidArray.h" +#include "nsISupports.h" + +// See below for the definition of nsCOMArray + +// a class that's nsISupports-specific, so that we can contain the +// work of this class in the XPCOM dll +class NS_COM nsCOMArray_base +{ + friend class nsArray; +protected: + nsCOMArray_base() {} + nsCOMArray_base(PRInt32 aCount) : mArray(aCount) {} + nsCOMArray_base(const nsCOMArray_base& other); + ~nsCOMArray_base(); + + PRInt32 IndexOf(nsISupports* aObject) const { + return mArray.IndexOf(aObject); + } + + PRInt32 IndexOfObject(nsISupports* aObject) const; + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateForwards(aFunc, aData); + } + + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) { + return mArray.EnumerateBackwards(aFunc, aData); + } + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData) { + mArray.Sort(aFunc, aData); + } + + // any method which is not a direct forward to mArray should + // avoid inline bodies, so that the compiler doesn't inline them + // all over the place + void Clear(); + PRBool InsertObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool InsertObjectsAt(const nsCOMArray_base& aObjects, PRInt32 aIndex); + PRBool ReplaceObjectAt(nsISupports* aObject, PRInt32 aIndex); + PRBool AppendObject(nsISupports *aObject) { + return InsertObjectAt(aObject, Count()); + } + PRBool AppendObjects(const nsCOMArray_base& aObjects) { + return InsertObjectsAt(aObjects, Count()); + } + PRBool RemoveObject(nsISupports *aObject); + PRBool RemoveObjectAt(PRInt32 aIndex); + +public: + // override nsVoidArray stuff so that they can be accessed by + // consumers of nsCOMArray + PRInt32 Count() const { + return mArray.Count(); + } + + nsISupports* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.FastElementAt(aIndex)); + } + + nsISupports* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(nsISupports*, mArray.SafeElementAt(aIndex)); + } + + nsISupports* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + +private: + + // the actual storage + nsVoidArray mArray; + + // don't implement these, defaults will muck with refcounts! + nsCOMArray_base& operator=(const nsCOMArray_base& other); +}; + +// a non-XPCOM, refcounting array of XPCOM objects +// used as a member variable or stack variable - this object is NOT +// refcounted, but the objects that it holds are +// +// most of the read-only accessors like ObjectAt()/etc do NOT refcount +// on the way out. This means that you can do one of two things: +// +// * does an addref, but holds onto a reference +// nsCOMPtr foo = array[i]; +// +// * avoids the refcount, but foo might go stale if array[i] is ever +// * modified/removed. Be careful not to NS_RELEASE(foo)! +// T* foo = array[i]; +// +// This array will accept null as an argument for any object, and will +// store null in the array, just like nsVoidArray. But that also means +// that methods like ObjectAt() may return null when referring to an +// existing, but null entry in the array. +template +class nsCOMArray : public nsCOMArray_base +{ + public: + nsCOMArray() {} + nsCOMArray(PRInt32 aCount) : nsCOMArray_base(aCount) {} + + // only to be used by trusted classes who are going to pass us the + // right type! + nsCOMArray(const nsCOMArray& aOther) : nsCOMArray_base(aOther) { } + + ~nsCOMArray() {} + + // these do NOT refcount on the way out, for speed + T* ObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::ObjectAt(aIndex)); + } + + // these do NOT refcount on the way out, for speed + T* SafeObjectAt(PRInt32 aIndex) const { + return NS_STATIC_CAST(T*,nsCOMArray_base::SafeObjectAt(aIndex)); + } + + // indexing operator for syntactic sugar + T* operator[](PRInt32 aIndex) const { + return ObjectAt(aIndex); + } + + // index of the element in question.. does NOT refcount + // note: this does not check COM object identity. Use + // IndexOfObject() for that purpose + PRInt32 IndexOf(T* aObject) const { + return nsCOMArray_base::IndexOf(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // index of the element in question.. be careful! + // this is much slower than IndexOf() because it uses + // QueryInterface to determine actual COM identity of the object + // if you need to do this frequently then consider enforcing + // COM object identity before adding/comparing elements + PRInt32 IndexOfObject(T* aObject) const { + return nsCOMArray_base::IndexOfObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // inserts aObject at aIndex, shifting the objects at aIndex and + // later to make space + PRBool InsertObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // inserts the objects from aObject at aIndex, shifting the + // objects at aIndex and later to make space + PRBool InsertObjectsAt(const nsCOMArray& aObjects, PRInt32 aIndex) { + return nsCOMArray_base::InsertObjectsAt(aObjects, aIndex); + } + + // replaces an existing element. Warning: if the array grows, + // the newly created entries will all be null + PRBool ReplaceObjectAt(T* aObject, PRInt32 aIndex) { + return nsCOMArray_base::ReplaceObjectAt(NS_STATIC_CAST(nsISupports*, aObject), aIndex); + } + + // override nsVoidArray stuff so that they can be accessed by + // other methods + + // elements in the array (including null elements!) + PRInt32 Count() const { + return nsCOMArray_base::Count(); + } + + // remove all elements in the array, and call NS_RELEASE on each one + void Clear() { + nsCOMArray_base::Clear(); + } + + // Enumerator callback function. Return PR_FALSE to stop + // Here's a more readable form: + // PRBool PR_CALLBACK enumerate(T* aElement, void* aData) + typedef PRBool (* PR_CALLBACK nsCOMArrayEnumFunc) + (T* aElement, void *aData); + + // enumerate through the array with a callback. + PRBool EnumerateForwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateForwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + PRBool EnumerateBackwards(nsCOMArrayEnumFunc aFunc, void* aData) { + return nsCOMArray_base::EnumerateBackwards(nsVoidArrayEnumFunc(aFunc), + aData); + } + + typedef int (* PR_CALLBACK nsCOMArrayComparatorFunc) + (T* aElement1, T* aElement2, void* aData); + + void Sort(nsCOMArrayComparatorFunc aFunc, void* aData) { + nsCOMArray_base::Sort(nsVoidArrayComparatorFunc(aFunc), aData); + } + + // append an object, growing the array as necessary + PRBool AppendObject(T *aObject) { + return nsCOMArray_base::AppendObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // append objects, growing the array as necessary + PRBool AppendObjects(const nsCOMArray& aObjects) { + return nsCOMArray_base::AppendObjects(aObjects); + } + + // remove the first instance of the given object and shrink the + // array as necessary + // Warning: if you pass null here, it will remove the first null element + PRBool RemoveObject(T *aObject) { + return nsCOMArray_base::RemoveObject(NS_STATIC_CAST(nsISupports*, aObject)); + } + + // remove an element at a specific position, shrinking the array + // as necessary + PRBool RemoveObjectAt(PRInt32 aIndex) { + return nsCOMArray_base::RemoveObjectAt(aIndex); + } + +private: + + // don't implement these! + nsCOMArray& operator=(const nsCOMArray& other); +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp new file mode 100644 index 00000000..23392f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.cpp @@ -0,0 +1,534 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * MODULE NOTES: + * @update gess7/30/98 + * + * Much as I hate to do it, we were using string compares wrong. + * Often, programmers call functions like strcmp(s1,s2), and pass + * one or more null strings. Rather than blow up on these, I've + * added quick checks to ensure that cases like this don't cause + * us to fail. + * + * In general, if you pass a null into any of these string compare + * routines, we simply return 0. + */ + + +#include "nsCRT.h" +#include "nsIServiceManager.h" + +// XXX Bug: These tables don't lowercase the upper 128 characters properly + +// This table maps uppercase characters to lower case characters; +// characters that are neither upper nor lower case are unaffected. +static const unsigned char kUpper2Lower[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, + + // upper band mapped to lower [A-Z] => [a-z] + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122, + + 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +static const unsigned char kLower2Upper[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, + + // lower band mapped to upper [a-z] => [A-Z] + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + + 123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 +}; + +//---------------------------------------------------------------------- + +char nsCRT::ToUpper(char aChar) +{ + return (char)kLower2Upper[(unsigned char)aChar]; +} + +char nsCRT::ToLower(char aChar) +{ + return (char)kUpper2Lower[(unsigned char)aChar]; +} + +PRBool nsCRT::IsUpper(char aChar) +{ + return aChar != nsCRT::ToLower(aChar); +} + +PRBool nsCRT::IsLower(char aChar) +{ + return aChar != nsCRT::ToUpper(aChar); +} + +//////////////////////////////////////////////////////////////////////////////// +// My lovely strtok routine + +#define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7))) +#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7))) +#define DELIM_TABLE_SIZE 32 + +char* nsCRT::strtok(char* string, const char* delims, char* *newStr) +{ + NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null."); + + char delimTable[DELIM_TABLE_SIZE]; + PRUint32 i; + char* result; + char* str = string; + + for (i = 0; i < DELIM_TABLE_SIZE; i++) + delimTable[i] = '\0'; + + for (i = 0; delims[i]; i++) { + SET_DELIM(delimTable, NS_STATIC_CAST(PRUint8, delims[i])); + } + NS_ASSERTION(delims[i] == '\0', "too many delimiters"); + + // skip to beginning + while (*str && IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + str++; + } + result = str; + + // fix up the end of the token + while (*str) { + if (IS_DELIM(delimTable, NS_STATIC_CAST(PRUint8, *str))) { + *str++ = '\0'; + break; + } + str++; + } + *newStr = str; + + return str == result ? NULL : result; +} + +//////////////////////////////////////////////////////////////////////////////// + +PRUint32 nsCRT::strlen(const PRUnichar* s) +{ + PRUint32 len = 0; + if(s) { + while (*s++ != 0) { + len++; + } + } + return len; +} + + +/** + * Compare unichar string ptrs, stopping at the 1st null + * NOTE: If both are null, we return 0. + * NOTE: We terminate the search upon encountering a NULL + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1s2 + */ +PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2) { + if(s1 && s2) { + for (;;) { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + if ((0==c1) || (0==c2)) break; + } + } + else { + if (s1) // s2 must have been null + return -1; + if (s2) // s1 must have been null + return 1; + } + return 0; +} + +/** + * Compare unichar string ptrs, stopping at the 1st null or nth char. + * NOTE: If either is null, we return 0. + * NOTE: We DO NOT terminate the search upon encountering NULL's before N + * + * @update gess 11/10/99 + * @param s1 and s2 both point to unichar strings + * @return 0 if they match, -1 if s1s2 + */ +PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n) { + if(s1 && s2) { + if(n != 0) { + do { + PRUnichar c1 = *s1++; + PRUnichar c2 = *s2++; + if (c1 != c2) { + if (c1 < c2) return -1; + return 1; + } + } while (--n != 0); + } + } + return 0; +} + +PRUnichar* nsCRT::strdup(const PRUnichar* str) +{ + PRUint32 len = nsCRT::strlen(str); + return strndup(str, len); +} + +PRUnichar* nsCRT::strndup(const PRUnichar* str, PRUint32 len) +{ + nsCppSharedAllocator shared_allocator; + PRUnichar* rslt = shared_allocator.allocate(len + 1); // add one for the null + // PRUnichar* rslt = new PRUnichar[len + 1]; + + if (rslt == NULL) return NULL; + memcpy(rslt, str, len * sizeof(PRUnichar)); + rslt[len] = 0; + return rslt; +} + + /** + * |nsCRT::HashCode| is identical to |PL_HashString|, which tests + * (http://bugzilla.mozilla.org/showattachment.cgi?attach_id=26596) + * show to be the best hash among several other choices. + * + * We re-implement it here rather than calling it for two reasons: + * (1) in this interface, we also calculate the length of the + * string being hashed; and (2) the narrow and wide and `buffer' versions here + * will hash equivalent strings to the same value, e.g., "Hello" and L"Hello". + */ +PRUint32 nsCRT::HashCode(const char* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const char* s = str; + + if (!str) return h; + + unsigned char c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCode(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + if (!str) return h; + + PRUnichar c; + while ( (c = *s++) ) + h = (h>>28) ^ (h<<4) ^ c; + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::HashCodeAsUTF8(const PRUnichar* str, PRUint32* resultingStrLen) +{ + PRUint32 h = 0; + const PRUnichar* s = str; + + { + PRUint16 W1 = 0; // the first UTF-16 word in a two word tuple + PRUint32 U = 0; // the current char as UCS-4 + int code_length = 0; // the number of bytes in the UTF-8 sequence for the current char + + PRUint16 W; + while ( (W = *s++) ) + { + /* + * On the fly, decoding from UTF-16 (and/or UCS-2) into UTF-8 as per + * http://www.ietf.org/rfc/rfc2781.txt + * http://www.ietf.org/rfc/rfc2279.txt + */ + + if ( !W1 ) + { + if ( W < 0xD800 || 0xDFFF < W ) + { + U = W; + if ( W <= 0x007F ) + code_length = 1; + else if ( W <= 0x07FF ) + code_length = 2; + else + code_length = 3; + } + else if ( /* 0xD800 <= W1 && */ W <= 0xDBFF ) + W1 = W; + } + else + { + // as required by the standard, this code is careful to + // throw out illegal sequences + + if ( 0xDC00 <= W && W <= 0xDFFF ) + { + U = PRUint32( (W1&0x03FF)<<10 | (W&0x3FFF) ); + if ( U <= 0x001FFFFF ) + code_length = 4; + else if ( U <= 0x3FFFFFF ) + code_length = 5; + else + code_length = 6; + } + W1 = 0; + } + + + if ( code_length > 0 ) + { + static const PRUint16 sBytePrefix[7] = { 0x0000, 0x0000, 0x00C0, 0x00E0, 0x00F0, 0x00F8, 0x00FC }; + static const PRUint16 sShift[7] = { 0, 0, 6, 12, 18, 24, 30 }; + + /* + * Unlike the algorithm in http://www.ietf.org/rfc/rfc2279.txt + * we must calculate the bytes in left to right order so that + * our hash result matches what the narrow version would calculate + * on an already UTF-8 string. + */ + + // hash the first (and often, only, byte) + h = (h>>28) ^ (h<<4) ^ (sBytePrefix[code_length] | (U>>sShift[code_length])); + + // an unrolled loop for hashing any remaining bytes in this sequence + switch ( code_length ) + { // falling through in each case + case 6: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>24) & 0x003F)); + case 5: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>18) & 0x003F)); + case 4: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>12) & 0x003F)); + case 3: h = (h>>28) ^ (h<<4) ^ (0x80 | ((U>>6 ) & 0x003F)); + case 2: h = (h>>28) ^ (h<<4) ^ (0x80 | ( U & 0x003F)); + default: code_length = 0; + break; + } + } + } + } + + if ( resultingStrLen ) + *resultingStrLen = (s-str)-1; + return h; +} + +PRUint32 nsCRT::BufferHashCode(const char* s, PRUint32 len) +{ + PRUint32 h = 0; + const char* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint8(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +PRUint32 nsCRT::BufferHashCode(const PRUnichar* s, PRUint32 len) +{ + PRUint32 h = 0; + const PRUnichar* done = s + len; + + while ( s < done ) + h = (h>>28) ^ (h<<4) ^ PRUint16(*s++); // cast to unsigned to prevent possible sign extension + + return h; +} + +// This should use NSPR but NSPR isn't exporting its PR_strtoll function +// Until then... +PRInt64 nsCRT::atoll(const char *str) +{ + if (!str) + return LL_Zero(); + + PRInt64 ll = LL_Zero(), digitll = LL_Zero(); + + while (*str && *str >= '0' && *str <= '9') { + LL_MUL(ll, ll, 10); + LL_UI2L(digitll, (*str - '0')); + LL_ADD(ll, ll, digitll); + str++; + } + + return ll; +} + +/** + * Determine if given char in valid ascii range + * + * @update ftang 04.27.2000 + * @param aChar is character to be tested + * @return TRUE if in ASCII range + */ +PRBool nsCRT::IsAscii(PRUnichar aChar) { + return (0x0080 > aChar); +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const PRUnichar *aString) { + while(*aString) { + if( 0x0080 <= *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine if given char in valid ascii range + * + * @update ftang 10.02.2001 + * @param aString is null terminated to be tested + * @return TRUE if all characters aare in ASCII range + */ +PRBool nsCRT::IsAscii(const char *aString) { + while(*aString) { + if( 0x80 & *aString) + return PR_FALSE; + aString++; + } + return PR_TRUE; +} +/** + * Determine whether the given string consists of valid ascii chars + * + * @param aString is null terminated + * @param aLength is the number of chars to test. This must be at most + * the number of chars in aString before the null terminator + * @return PR_TRUE if all chars are valid ASCII chars, PR_FALSE otherwise + */ +PRBool nsCRT::IsAscii(const char* aString, PRUint32 aLength) +{ + const char* end = aString + aLength; + while (aString < end) { + NS_ASSERTION(*aString, "Null byte before end of data!"); + if (0x80 & *aString) + return PR_FALSE; + ++aString; + } + return PR_TRUE; +} + +/** + * Determine if given char in valid alpha range + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if in alpha range + */ +PRBool nsCRT::IsAsciiAlpha(PRUnichar aChar) { + // XXX i18n + if (((aChar >= 'A') && (aChar <= 'Z')) || ((aChar >= 'a') && (aChar <= 'z'))) { + return PR_TRUE; + } + return PR_FALSE; +} + +/** + * Determine if given char is a valid space character + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if is valid space char + */ +PRBool nsCRT::IsAsciiSpace(PRUnichar aChar) { + // XXX i18n + if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) { + return PR_TRUE; + } + return PR_FALSE; +} + + + +/** + * Determine if given char is valid digit + * + * @update rickg 03.10.2000 + * @param aChar is character to be tested + * @return TRUE if char is a valid digit + */ +PRBool nsCRT::IsAsciiDigit(PRUnichar aChar) { + // XXX i18n + return PRBool((aChar >= '0') && (aChar <= '9')); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCRT.h b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h new file mode 100644 index 00000000..c168a0a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCRT.h @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsCRT_h___ +#define nsCRT_h___ + +#include +#include +#include +#include "plstr.h" +#include "nscore.h" +#include "prtypes.h" +#include "nsCppSharedAllocator.h" + +#ifdef XP_MAC +# define NS_LINEBREAK "\015" +# define NS_LINEBREAK_LEN 1 +#else +# if defined(XP_WIN) || defined(XP_OS2) +# define NS_LINEBREAK "\015\012" +# define NS_LINEBREAK_LEN 2 +# else +# if defined(XP_UNIX) || defined(XP_BEOS) +# define NS_LINEBREAK "\012" +# define NS_LINEBREAK_LEN 1 +# endif /* XP_UNIX */ +# endif /* XP_WIN || XP_OS2 */ +#endif /* XP_MAC */ + +extern const PRUnichar kIsoLatin1ToUCS2[256]; + +// This macro can be used in a class declaration for classes that want +// to ensure that their instance memory is zeroed. +#define NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// This macro works with the next macro to declare a non-inlined +// version of the above. +#define NS_DECL_ZEROING_OPERATOR_NEW \ + void* operator new(size_t sz) CPP_THROW_NEW; \ + void operator delete(void* ptr); + +#define NS_IMPL_ZEROING_OPERATOR_NEW(_class) \ + void* _class::operator new(size_t sz) CPP_THROW_NEW { \ + void* rv = ::operator new(sz); \ + if (rv) { \ + memset(rv, 0, sz); \ + } \ + return rv; \ + } \ + void _class::operator delete(void* ptr) { \ + ::operator delete(ptr); \ + } + +// Freeing helper +#define CRTFREEIF(x) if (x) { nsCRT::free(x); x = 0; } + +/// This is a wrapper class around all the C runtime functions. + +class NS_COM nsCRT { +public: + enum { + TAB='\t' /* Horizontal Tab */, + LF='\n' /* Line Feed */, + VTAB='\v' /* Vertical Tab */, + FF='\f' /* Form Feed */, + CR='\r' /* Carriage Return */ + }; + + /*** + *** The following nsCRT::mem* functions are no longer + *** supported, please use the corresponding lib C + *** functions instead. + *** + *** nsCRT::memcpy() + *** nsCRT::memcmp() + *** nsCRT::memmove() + *** nsCRT::memset() + *** nsCRT::zero() + *** + *** Additionally, the following char* string utilities + *** are no longer supported, please use the + *** corresponding lib C functions instead. + *** + *** nsCRT::strlen() + *** + ***/ + + /** Compute the string length of s + @param s the string in question + @return the length of s + */ + static PRUint32 strlen(const char* s) { + return PRUint32(::strlen(s)); + } + + /// Compare s1 and s2. + static PRInt32 strcmp(const char* s1, const char* s2) { + return PRInt32(PL_strcmp(s1, s2)); + } + + static PRInt32 strncmp(const char* s1, const char* s2, + PRUint32 aMaxLen) { + return PRInt32(PL_strncmp(s1, s2, aMaxLen)); + } + + /// Case-insensitive string comparison. + static PRInt32 strcasecmp(const char* s1, const char* s2) { + return PRInt32(PL_strcasecmp(s1, s2)); + } + + /// Case-insensitive string comparison with length + static PRInt32 strncasecmp(const char* s1, const char* s2, PRUint32 aMaxLen) { + PRInt32 result=PRInt32(PL_strncasecmp(s1, s2, aMaxLen)); + //Egads. PL_strncasecmp is returning *very* negative numbers. + //Some folks expect -1,0,1, so let's temper its enthusiasm. + if (result<0) + result=-1; + return result; + } + + static PRInt32 strncmp(const char* s1, const char* s2, PRInt32 aMaxLen) { + // inline the first test (assumes strings are not null): + PRInt32 diff = ((const unsigned char*)s1)[0] - ((const unsigned char*)s2)[0]; + if (diff != 0) return diff; + return PRInt32(PL_strncmp(s1,s2,unsigned(aMaxLen))); + } + + static char* strdup(const char* str) { + return PL_strdup(str); + } + + static char* strndup(const char* str, PRUint32 len) { + return PL_strndup(str, len); + } + + static void free(char* str) { + PL_strfree(str); + } + + /** + + How to use this fancy (thread-safe) version of strtok: + + void main(void) { + printf("%s\n\nTokens:\n", string); + // Establish string and get the first token: + char* newStr; + token = nsCRT::strtok(string, seps, &newStr); + while (token != NULL) { + // While there are tokens in "string" + printf(" %s\n", token); + // Get next token: + token = nsCRT::strtok(newStr, seps, &newStr); + } + } + * WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED * + * MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() * + */ + static char* strtok(char* str, const char* delims, char* *newStr); + + /// Like strlen except for ucs2 strings + static PRUint32 strlen(const PRUnichar* s); + + /// Like strcmp except for ucs2 strings + static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2); + /// Like strcmp except for ucs2 strings + static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2, + PRUint32 aMaxLen); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by nsCRT::strdup(PRUnichar*). + static PRUnichar* strdup(const PRUnichar* str); + + // You must use nsCRT::free(PRUnichar*) to free memory allocated + // by strndup(PRUnichar*, PRUint32). + static PRUnichar* strndup(const PRUnichar* str, PRUint32 len); + + static void free(PRUnichar* str) { + nsCppSharedAllocator shared_allocator; + shared_allocator.deallocate(str, 0 /*we never new or kept the size*/); + } + + // Computes the hashcode for a c-string, returns the string length as + // an added bonus. + static PRUint32 HashCode(const char* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a ucs2 string, returns the string length + // as an added bonus. + static PRUint32 HashCode(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes a hashcode for a ucs2 string that returns the same thing + // as the HashCode method taking a |char*| would if the string were + // converted to UTF8. Returns the string length as an added bonus. + static PRUint32 HashCodeAsUTF8(const PRUnichar* str, + PRUint32* resultingStrLen = nsnull); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const char* str, PRUint32 strLen); + + // Computes the hashcode for a buffer with a specified length. + static PRUint32 BufferHashCode(const PRUnichar* str, PRUint32 strLen); + + // String to longlong + static PRInt64 atoll(const char *str); + + static char ToUpper(char aChar); + + static char ToLower(char aChar); + + static PRBool IsUpper(char aChar); + + static PRBool IsLower(char aChar); + + static PRBool IsAscii(PRUnichar aChar); + static PRBool IsAscii(const PRUnichar* aString); + static PRBool IsAsciiAlpha(PRUnichar aChar); + static PRBool IsAsciiDigit(PRUnichar aChar); + static PRBool IsAsciiSpace(PRUnichar aChar); + static PRBool IsAscii(const char* aString); + static PRBool IsAscii(const char* aString, PRUint32 aLength); +}; + +#define FF '\014' +#define TAB '\011' + +#define CRSTR "\015" +#define LFSTR "\012" +#define CRLF "\015\012" /* A CR LF equivalent string */ + + +#if defined(XP_MAC) + #define FILE_PATH_SEPARATOR ":" + #define FILE_ILLEGAL_CHARACTERS "" +#elif defined(XP_WIN) || defined(XP_OS2) + #define FILE_PATH_SEPARATOR "\\" + #define FILE_ILLEGAL_CHARACTERS "/:*?\"<>|" +#elif defined(XP_UNIX) || defined(XP_BEOS) + #define FILE_PATH_SEPARATOR "/" + #define FILE_ILLEGAL_CHARACTERS "" +#else + #error need_to_define_your_file_path_separator_and_illegal_characters +#endif + +#define NS_IS_SPACE(VAL) \ + (((((intn)(VAL)) & 0x7f) == ((intn)(VAL))) && isspace((intn)(VAL)) ) + +#define NS_IS_CNTRL(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : iscntrl(i)) +#define NS_IS_DIGIT(i) ((((unsigned int) (i)) > 0x7f) ? (int) 0 : isdigit(i)) +#if defined(XP_WIN) || defined(XP_OS2) +#define NS_IS_ALPHA(VAL) (isascii((int)(VAL)) && isalpha((int)(VAL))) +#else +#define NS_IS_ALPHA(VAL) ((((unsigned int) (VAL)) > 0x7f) ? (int) 0 : isalpha((int)(VAL))) +#endif + + +#endif /* nsCRT_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp new file mode 100644 index 00000000..954de2d1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCheapSets.h" + +nsCheapStringSet::~nsCheapStringSet() +{ + nsStringHashSet* set = GetHash(); + if (set) { + delete set; + } else { + delete GetStr(); + } +} + +/** + * Put a string into the table + */ +nsresult +nsCheapStringSet::Put(const nsAString& aVal) +{ + // Add the value to the hash if it is there + nsStringHashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // If a string is already there, create a hashtable and both of these to it + if (GetStr()) { + nsAString* oldStr = GetStr(); + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(*oldStr); + delete oldStr; + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Nothing exists in the hash right now, so just set the single string + return SetStr(aVal); +} + +void +nsCheapStringSet::Remove(const nsAString& aVal) +{ + // Remove from the hash if the hash is there + nsStringHashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + return; + } + + // Remove the string if there is just a string + nsAString* str = GetStr(); + if (str && str->Equals(aVal)) { + delete str; + mValOrHash = nsnull; + } +} + +nsresult +nsCheapStringSet::InitHash(nsStringHashSet** aSet) +{ + nsStringHashSet* newSet = new nsStringHashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} + + +nsCheapInt32Set::~nsCheapInt32Set() +{ + delete GetHash(); +} + +nsresult +nsCheapInt32Set::Put(PRInt32 aVal) +{ + // Add the value to the hash or set the pointer as an int + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Put(aVal); + } + + // Create the hash and add the value to it if there is an int already + if (IsInt()) { + PRInt32 oldInt = GetInt(); + + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + rv = set->Put(oldInt); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Create the hash anyway if the int is negative (negative numbers cannot + // fit into our PtrBits abstraction) + if (aVal < 0) { + nsresult rv = InitHash(&set); + NS_ENSURE_SUCCESS(rv, rv); + + return set->Put(aVal); + } + + // Finally, just set the int if we can't do anything with hashes + SetInt(aVal); + return NS_OK; +} + +void +nsCheapInt32Set::Remove(PRInt32 aVal) +{ + nsInt32HashSet* set = GetHash(); + if (set) { + set->Remove(aVal); + } else if (IsInt() && GetInt() == aVal) { + mValOrHash = nsnull; + } +} + +nsresult +nsCheapInt32Set::InitHash(nsInt32HashSet** aSet) +{ + nsInt32HashSet* newSet = new nsInt32HashSet(); + if (!newSet) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = newSet->Init(10); + NS_ENSURE_SUCCESS(rv, rv); + + mValOrHash = newSet; + *aSet = newSet; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h new file mode 100644 index 00000000..7e1c917d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCheapSets.h @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsCheapSets_h__ +#define __nsCheapSets_h__ + +#include "nsHashSets.h" + +/** + * A string set that takes up minimal size when there are 0 or 1 strings in the + * set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapStringSet { +public: + nsCheapStringSet() : mValOrHash(nsnull) + { + } + ~nsCheapStringSet(); + + /** + * Put a string into the set + * @param aVal the value to put in + */ + nsresult Put(const nsAString& aVal); + + /** + * Remove a string from the set + * @param aVal the string to remove + */ + void Remove(const nsAString& aVal); + + /** + * Check if the set contains a particular string + * @param aVal the string to check for + * @return whether the string is in the set + */ + PRBool Contains(const nsAString& aVal) + { + nsStringHashSet* set = GetHash(); + // Check the value from the hash if the hash is there + if (set) { + return set->Contains(aVal); + } + + // Check whether the value is equal to the string if the string is there + nsAString* str = GetStr(); + return str && str->Equals(aVal); + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsStringHashSet* GetHash() + { + return (PtrBits(mValOrHash) & 0x1) ? nsnull : (nsStringHashSet*)mValOrHash; + } + /** Find out whether it is a string */ + nsAString* GetStr() + { + return (PtrBits(mValOrHash) & 0x1) + ? (nsAString*)(PtrBits(mValOrHash) & ~0x1) + : nsnull; + } + /** Set the single string */ + nsresult SetStr(const nsAString& aVal) + { + nsString* str = new nsString(aVal); + if (!str) { + return NS_ERROR_OUT_OF_MEMORY; + } + mValOrHash = (nsAString*)(PtrBits(str) | 0x1); + return NS_OK; + } + /** Initialize the hash */ + nsresult InitHash(nsStringHashSet** aSet); + +private: + /** A hash or string ptr, depending on the lower bit (0=hash, 1=string) */ + void* mValOrHash; +}; + + +/** + * An integer set that takes up only 4 bytes when there are 0 or 1 integers + * in the set. Use for cases where sizes of 0 and 1 are even slightly common. + */ +class NS_COM nsCheapInt32Set { +public: + nsCheapInt32Set() : mValOrHash(nsnull) + { + } + ~nsCheapInt32Set(); + + /** + * Put an int into the set + */ + nsresult Put(PRInt32 aVal); + + /** + * Remove a int from the set + * @param aVal the int to remove + */ + void Remove(PRInt32 aVal); + + /** + * Check if the set contains a particular int + * @param aVal the int to check for + * @return whether the int is in the set + */ + PRBool Contains(PRInt32 aVal) + { + nsInt32HashSet* set = GetHash(); + if (set) { + return set->Contains(aVal); + } + if (IsInt()) { + return GetInt() == aVal; + } + return PR_FALSE; + } + +private: + typedef PRUint64 PtrBits; + + /** Get the hash pointer (or null if we're not a hash) */ + nsInt32HashSet* GetHash() + { + return PtrBits(mValOrHash) & 0x1 ? nsnull : (nsInt32HashSet*)mValOrHash; + } + /** Find out whether it is an integer */ + PRBool IsInt() + { + return !!(PtrBits(mValOrHash) & 0x1); + } + /** Get the single integer */ + PRInt32 GetInt() + { + return PtrBits(mValOrHash) >> 1; + } + /** Set the single integer */ + void SetInt(PRInt32 aInt) + { + mValOrHash = (void*)(uintptr_t)((aInt << 1) | 0x1); + } + /** Create the hash and initialize */ + nsresult InitHash(nsInt32HashSet** aSet); + +private: + /** A hash or int, depending on the lower bit (0=hash, 1=int) */ + void* mValOrHash; +}; + + +/** + * XXX We may want an nsCheapVoidSet and nsCheapCStringSet at some point + */ + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h new file mode 100644 index 00000000..1fd73489 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsClassHashtable.h @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsClassHashtable_h__ +#define nsClassHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to C++ object pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsClassHashtable : + public nsBaseHashtable< KeyClass, nsAutoPtr, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +/** + * Thread-safe version of nsClassHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Class the class-type being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsClassHashtableMT : + public nsBaseHashtableMT< KeyClass, nsAutoPtr, T* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef T* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData if the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; +}; + + +// +// nsClassHashtable definitions +// + +template +PRBool +nsClassHashtable::Get(KeyType aKey, T** retVal) const +{ + typename nsBaseHashtable,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + return PR_FALSE; +} + + +// +// nsClassHashtableMT definitions +// + +template +PRBool +nsClassHashtableMT::Get(KeyType aKey, T** retVal) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT,T*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (retVal) + *retVal = ent->mData; + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + if (retVal) + *retVal = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsClassHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h new file mode 100644 index 00000000..55f3e19d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsCppSharedAllocator.h @@ -0,0 +1,127 @@ +#ifndef nsCppSharedAllocator_h__ +#define nsCppSharedAllocator_h__ + +#include "nsMemory.h" // for |nsMemory| +#include "nscore.h" // for |NS_XXX_CAST| +#include NEW_H // to allow placement |new| + + + // under Metrowerks (Mac), we don't have autoconf yet +#ifdef __MWERKS__ + #define HAVE_CPP_MEMBER_TEMPLATES + #define HAVE_CPP_NUMERIC_LIMITS +#endif + + // under MSVC shut off copious warnings about unused in-lines +#ifdef _MSC_VER + #pragma warning( disable: 4514 ) +#endif + +#ifdef HAVE_CPP_NUMERIC_LIMITS +#include +#else +#include +#endif + + +template +class nsCppSharedAllocator + /* + ...allows Standard Library containers, et al, to use our global shared + (XP)COM-aware allocator. + */ + { + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; + + + + nsCppSharedAllocator() { } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template + nsCppSharedAllocator( const nsCppSharedAllocator& ) { } +#endif + + ~nsCppSharedAllocator() { } + + + pointer + address( reference r ) const + { + return &r; + } + + const_pointer + address( const_reference r ) const + { + return &r; + } + + pointer + allocate( size_type n, const void* /*hint*/=0 ) + { + return NS_REINTERPRET_CAST(pointer, nsMemory::Alloc(NS_STATIC_CAST(PRUint32, n*sizeof(T)))); + } + + void + deallocate( pointer p, size_type /*n*/ ) + { + nsMemory::Free(p); + } + + void + construct( pointer p, const T& val ) + { + new (p) T(val); + } + + void + destroy( pointer p ) + { + p->~T(); + } + + size_type + max_size() const + { +#ifdef HAVE_CPP_NUMERIC_LIMITS + return numeric_limits::max() / sizeof(T); +#else + return ULONG_MAX / sizeof(T); +#endif + } + +#ifdef HAVE_CPP_MEMBER_TEMPLATES + template + struct rebind + { + typedef nsCppSharedAllocator other; + }; +#endif + }; + + +template +PRBool +operator==( const nsCppSharedAllocator&, const nsCppSharedAllocator& ) + { + return PR_TRUE; + } + +template +PRBool +operator!=( const nsCppSharedAllocator&, const nsCppSharedAllocator& ) + { + return PR_FALSE; + } + +#endif /* !defined(nsCppSharedAllocator_h__) */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h new file mode 100644 index 00000000..7a14f826 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDataHashtable.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsDataHashtable_h__ +#define nsDataHashtable_h__ + +#include "nsHashKeys.h" +#include "nsBaseHashtable.h" + +/** + * templated hashtable class maps keys to simple datatypes. + * See nsBaseHashtable for complete declaration + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param DataType the simple datatype being wrapped + * @see nsInterfaceHashtable, nsClassHashtable + */ +template +class nsDataHashtable : + public nsBaseHashtable +{ }; + +template +class nsDataHashtableMT : + public nsBaseHashtableMT +{ }; + +#endif // nsDataHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp new file mode 100644 index 00000000..d94568bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.cpp @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsDeque.h" +#include "nsCRT.h" +#ifdef DEBUG_rickg +#include +#endif + +/** + * 07/02/2001 09:17p 509,104 clangref.pdf from openwatcom's site + * Watcom C Language Reference Edition 11.0c + * page 118 of 297 + * + * The % symbol yields the remainder from the division of the first operand + * by the second operand. The operands of % must have integral type. + * + * When both operands of % are positive, the result is a positive value + * smaller than the second operand. When one or both operands is negative, + * whether the result is positive or negative is implementation-defined. + * + */ +/* Ok, so first of all, C is underspecified. joy. + * The following functions do not provide a correct implementation of modulus + * They provide functionality for x>-y. + * There are risks of 2*y being greater than max int, which is part of the + * reason no multiplication is used and other operations are avoided. + * + * modasgn + * @param x variable + * @param y expression + * approximately equivalent to x %= y + * + * modulus + * @param x expression + * @param y expression + * approximately equivalent to x % y + */ +#define modasgn(x,y) if (x<0) x+=y; x%=y +#define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y)) + +MOZ_DECL_CTOR_COUNTER(nsDeque) + +/** + * Standard constructor + * @param deallocator, called by Erase and ~nsDeque + */ +nsDeque::nsDeque(nsDequeFunctor* aDeallocator) { + MOZ_COUNT_CTOR(nsDeque); + mDeallocator=aDeallocator; + mOrigin=mSize=0; + mData=mBuffer; // don't allocate space until you must + mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]); + memset(mData, 0, mCapacity*sizeof(mBuffer[0])); +} + +/** + * Destructor + */ +nsDeque::~nsDeque() { + MOZ_COUNT_DTOR(nsDeque); + +#ifdef DEBUG_rickg + char buffer[30]; + printf("Capacity: %i\n", mCapacity); + + static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + switch(mCapacity) { + case 4: mCaps[0]++; break; + case 8: mCaps[1]++; break; + case 16: mCaps[2]++; break; + case 32: mCaps[3]++; break; + case 64: mCaps[4]++; break; + case 128: mCaps[5]++; break; + case 256: mCaps[6]++; break; + case 512: mCaps[7]++; break; + case 1024: mCaps[8]++; break; + case 2048: mCaps[9]++; break; + case 4096: mCaps[10]++; break; + default: + break; + } +#endif + + Erase(); + if (mData && (mData!=mBuffer)) { + delete [] mData; + } + mData=0; + SetDeallocator(0); +} + +/** + * Set the functor to be called by Erase() + * The deque owns the functor. + * + * @param aDeallocator functor object for use by Erase() + */ +void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ + if (mDeallocator) { + delete mDeallocator; + } + mDeallocator=aDeallocator; +} + +/** + * Remove all items from container without destroying them. + * + * @return *this + */ +nsDeque& nsDeque::Empty() { + if (mSize && mData) { + memset(mData, 0, mCapacity*sizeof(*mData)); + } + mSize=0; + mOrigin=0; + return *this; +} + +/** + * Remove and delete all items from container + * + * @return *this + */ +nsDeque& nsDeque::Erase() { + if (mDeallocator && mSize) { + ForEach(*mDeallocator); + } + return Empty(); +} + +/** + * This method quadruples the size of the deque + * Elements in the deque are resequenced so that elements + * in the deque are stored sequentially + * + * If the deque actually overflows, there's very little we can do. + * Perhaps this function should return PRBool/nsresult indicating success/failure. + * + * @return capacity of the deque + * If the deque did not grow, + * and you knew its capacity beforehand, + * then this would be a way to indicate the failure. + */ +PRInt32 nsDeque::GrowCapacity() { + PRInt32 theNewSize=mCapacity<<2; + NS_ASSERTION(theNewSize>mCapacity, "Overflow"); + if (theNewSize<=mCapacity) + return mCapacity; + void** temp=new void*[theNewSize]; + + //Here's the interesting part: You can't just move the elements + //directly (in situ) from the old buffer to the new one. + //Since capacity has changed, the old origin doesn't make + //sense anymore. It's better to resequence the elements now. + + if (temp) { + PRInt32 tempi=0; + PRInt32 i=0; + PRInt32 j=0; + for (i=mOrigin; i0) { + --mSize; + PRInt32 offset=modulus(mSize + mOrigin, mCapacity); + result=mData[offset]; + mData[offset]=0; + if (!mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to remove and return + * the first member in the container. + * + * @return last item in container + */ +void* nsDeque::PopFront() { + void* result=0; + if (mSize>0) { + NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin"); + result=mData[mOrigin]; + mData[mOrigin++]=0; //zero it out for debugging purposes. + mSize--; + // Cycle around if we pop off the end + // and reset origin if when we pop the last element + if (mCapacity==mOrigin || !mSize) { + mOrigin=0; + } + } + return result; +} + +/** + * This method gets called you want to peek at the bottom + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::Peek() { + void* result=0; + if (mSize>0) { + result = mData[modulus(mSize - 1 + mOrigin, mCapacity)]; + } + return result; +} + +/** + * This method gets called you want to peek at the topmost + * member without removing it. + * + * @return last item in container + */ +void* nsDeque::PeekFront() { + void* result=0; + if (mSize>0) { + result=mData[mOrigin]; + } + return result; +} + +/** + * Call this to retrieve the ith element from this container. + * Keep in mind that accessing the underlying elements is + * done in a relative fashion. Object 0 is not necessarily + * the first element (the first element is at mOrigin). + * + * @param aIndex : 0 relative offset of item you want + * @return void* or null + */ +void* nsDeque::ObjectAt(PRInt32 aIndex) const { + void* result=0; + if ((aIndex>=0) && (aIndexoperator==(aIter)); +} + +/** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over the same deque. + */ +PRBool nsDequeIterator::operator<(nsDequeIterator& aIter) { + return PRBool(((mIndex=(nsDequeIterator& aIter) { + return PRBool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque))); +} + +/** + * Pre-increment operator + * + * @return object at post-incremented index + */ +void* nsDequeIterator::operator++() { + NS_ASSERTION(mIndex=mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(++mIndex); +} + +/** + * Post-increment operator + * + * @param param is ignored + * @return object at pre-incremented index + */ +void* nsDequeIterator::operator++(int) { + NS_ASSERTION(mIndex<=mDeque.mSize, + "You have already reached the end of the Internet."\ + "You have seen everything there is to see. Please go back. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>mDeque.mSize) return 0; +#endif + return mDeque.ObjectAt(mIndex++); +} + +/** + * Pre-decrement operator + * + * @return object at pre-decremented index + */ +void* nsDequeIterator::operator--() { + NS_ASSERTION(mIndex>=0, + "You have reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(--mIndex); +} + +/** + * Post-decrement operator + * + * @param param is ignored + * @return object at post-decremented index + */ +void* nsDequeIterator::operator--(int) { + NS_ASSERTION(mIndex>=0, + "You have already reached the beginning of the Internet."\ + "You have seen everything there is to see. Please go forward. Now." + ); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex--); +} + +/** + * Dereference operator + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 spaces. + * + * Picture: [1 2I 3 4] + * PopFront() + * Picture: [2 3I 4] + * Note that I still happily points to object at the second index + * + * @return object at ith index + */ +void* nsDequeIterator::GetCurrent() { + NS_ASSERTION(mIndex=0,"Current is out of bounds"); +#ifndef TIMELESS_LIGHTWEIGHT + if (mIndex>=mDeque.mSize||mIndex<0) return 0; +#endif + return mDeque.ObjectAt(mIndex); +} + +/** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ +void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{ + mDeque.ForEach(aFunctor); +} + +/** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ +const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{ + return mDeque.FirstThat(aFunctor); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDeque.h b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h new file mode 100644 index 00000000..7fdf7465 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDeque.h @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * MODULE NOTES: + * + * The Deque is a very small, very efficient container object + * than can hold elements of type void*, offering the following features: + * Its interface supports pushing and popping of elements. + * It can iterate (via an interator class) its elements. + * When full, it can efficiently resize dynamically. + * + * + * NOTE: The only bit of trickery here is that this deque is + * built upon a ring-buffer. Like all ring buffers, the first + * element may not be at index[0]. The mOrigin member determines + * where the first child is. This point is quietly hidden from + * customers of this class. + * + */ + +#ifndef _NSDEQUE +#define _NSDEQUE + +#include "nscore.h" + +/** + * The nsDequeFunctor class is used when you want to create + * callbacks between the deque and your generic code. + * Use these objects in a call to ForEach(); + * + */ + +class nsDequeFunctor{ +public: + virtual void* operator()(void* anObject)=0; +}; + +/****************************************************** + * Here comes the nsDeque class itself... + ******************************************************/ + +/** + * The deque (double-ended queue) class is a common container type, + * whose behavior mimics a line in your favorite checkout stand. + * Classic CS describes the common behavior of a queue as FIFO. + * A deque allows insertion and removal at both ends of + * the container. + * + * The deque stores pointers to items. + */ + +class nsDequeIterator; + +class NS_COM nsDeque { + friend class nsDequeIterator; + public: + nsDeque(nsDequeFunctor* aDeallocator); + ~nsDeque(); + + /** + * Returns the number of elements currently stored in + * this deque. + * + * @return number of elements currently in the deque + */ + inline PRInt32 GetSize() const {return mSize;} + + /** + * Appends new member at the end of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& Push(void* aItem); + + /** + * Inserts new member at the front of the deque. + * + * @param item to store in deque + * @return *this + */ + nsDeque& PushFront(void* aItem); + + /** + * Remove and return the last item in the container. + * + * @return the item that was the last item in container + */ + void* Pop(); + + /** + * Remove and return the first item in the container. + * + * @return the item that was first item in container + */ + void* PopFront(); + + /** + * Retrieve the bottom item without removing it. + * + * @return the first item in container + */ + + void* Peek(); + /** + * Return topmost item without removing it. + * + * @return the first item in container + */ + void* PeekFront(); + + /** + * Retrieve the i'th member from the deque without removing it. + * + * @param index of desired item + * @return i'th element in list + */ + void* ObjectAt(int aIndex) const; + + /** + * Remove all items from container without destroying them. + * + * @return *this + */ + nsDeque& Empty(); + + /** + * Remove and delete all items from container. + * Deletes are handled by the deallocator nsDequeFunctor + * which is specified at deque construction. + * + * @return *this + */ + nsDeque& Erase(); + + /** + * Creates a new iterator, pointing to the first + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator Begin() const; + + /** + * Creates a new iterator, pointing to the last + * item in the deque. + * + * @return new dequeIterator + */ + nsDequeIterator End() const; + + void* Last() const; + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + void SetDeallocator(nsDequeFunctor* aDeallocator); + +protected: + PRInt32 mSize; + PRInt32 mCapacity; + PRInt32 mOrigin; + nsDequeFunctor* mDeallocator; + void* mBuffer[8]; + void** mData; + +private: + + /** + * Simple default constructor (PRIVATE) + */ + nsDeque(); + + /** + * Copy constructor (PRIVATE) + * + * @param another deque + */ + nsDeque(const nsDeque& other); + + /** + * Deque assignment operator (PRIVATE) + * + * @param another deque + * @return *this + */ + nsDeque& operator=(const nsDeque& anOther); + + PRInt32 GrowCapacity(); +}; + +/****************************************************** + * Here comes the nsDequeIterator class... + ******************************************************/ + +class nsDequeIterator { +public: + /** + * DequeIterator is an object that knows how to iterate + * (forward and backward) through a Deque. Normally, + * you don't need to do this, but there are some special + * cases where it is pretty handy. + * + * One warning: the iterator is not bound to an item, + * it is bound to an index, so if you insert or remove + * from the beginning while using an iterator + * (which is not recommended) then the iterator will + * point to a different item. @see GetCurrent() + * + * Here you go. + * + * @param aQueue is the deque object to be iterated + * @param aIndex is the starting position for your iteration + */ + nsDequeIterator(const nsDeque& aQueue, int aIndex=0); + + /** + * Create a copy of a DequeIterator + * + * @param aCopy is another iterator to copy from + */ + nsDequeIterator(const nsDequeIterator& aCopy); + + /** + * Moves iterator to first element in the deque + * @return *this + */ + nsDequeIterator& First(); + + /** + * Standard assignment operator for dequeiterator + * @param aCopy is another iterator to copy from + * @return *this + */ + nsDequeIterator& operator=(const nsDequeIterator& aCopy); + + /** + * preform ! operation against two iterators to test for equivalence + * (or lack thereof)! + * + * @param aIter is the object to be compared to + * @return TRUE if NOT equal. + */ + PRBool operator!=(nsDequeIterator& aIter); + + /** + * Compare two iterators for increasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to an element before + * the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator<(nsDequeIterator& aIter); + + /** + * Compare two iterators for equivalence. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if EQUAL + */ + PRBool operator==(nsDequeIterator& aIter); + + /** + * Compare two iterators for non strict decreasing order. + * + * @param aIter is the other iterator to be compared to + * @return TRUE if this object points to the same element, or + * an element after the element pointed to by aIter. + * FALSE if this and aIter are not iterating over + * the same deque. + */ + PRBool operator>=(nsDequeIterator& aIter); + + /** + * Pre-increment operator + * Iterator will advance one index towards the end. + * + * @return object_at(++index) + */ + void* operator++(); + + /** + * Post-increment operator + * Iterator will advance one index towards the end. + * + * @param param is ignored + * @return object_at(mIndex++) + */ + void* operator++(int); + + /** + * Pre-decrement operator + * Iterator will advance one index towards the beginning. + * + * @return object_at(--index) + */ + void* operator--(); + + /** + * Post-decrement operator + * Iterator will advance one index towards the beginning. + * + * @param param is ignored + * @return object_at(index--) + */ + void* operator--(int); + + /** + * Retrieve the the iterator's notion of current node. + * + * Note that the iterator floats, so you don't need to do: + * ++iter; aDeque.PopFront(); + * Unless you actually want your iterator to jump 2 positions + * relative to its origin. + * + * Picture: [1 2i 3 4] + * PopFront() + * Picture: [2 3i 4] + * Note that I still happily points to object at the second index. + * + * @return object at i'th index + */ + void* GetCurrent(); + + /** + * Call this method when you want to iterate all the + * members of the container, passing a functor along + * to call your code. + * + * @param aFunctor object to call for each member + * @return *this + */ + void ForEach(nsDequeFunctor& aFunctor) const; + + /** + * Call this method when you want to iterate all the + * members of the container, calling the functor you + * passed with each member. This process will interrupt + * if your function returns non 0 to this method. + * + * @param aFunctor object to call for each member + * @return first nonzero result of aFunctor or 0. + */ + const void* FirstThat(nsDequeFunctor& aFunctor) const; + + protected: + + PRInt32 mIndex; + const nsDeque& mDeque; +}; +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h new file mode 100644 index 00000000..27bf4ce5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsDoubleHashtable.h @@ -0,0 +1,505 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * nsDoubleHashtable.h is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef __nsDoubleHashtable_h__ +#define __nsDoubleHashtable_h__ + +#include "pldhash.h" +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* + * This file provides several major things to make PLDHashTable easier to use: + * - hash class macros for you to define a hashtable + * - default key classes to use as superclasses for your entries + * - empty maps for string, cstring, int and void + */ + +/* + * USAGE + * + * To use nsDoubleHashtable macros + * (1) Define an entry class + * (2) Create the hash class + * (3) Use the hash class + * + * EXAMPLE + * + * As an example, let's create a dictionary, a mapping from a string (the word) + * to the pronunciation and definition of those words. + * + * (1) Define an entry class + * + * What we want here is an entry class that contains the word, the + * pronunciation string, and the definition string. Since we have a string key + * we can use the standard PLDHashStringEntry class as our base, it will handle + * the key stuff for us automatically. + * + * #include "nsDoubleHashtable.h" + * + * // Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * // This is because of the 4-byte pointer C++ magically prepends onto your + * // entry class. It interacts very unhappily with PLDHashTable. + * class DictionaryEntry : public PLDHashStringEntry { + * public: + * DictionaryEntry(const void* aKey) : PLDHashStringEntry(aKey) { } + * ~DictionaryEntry() { } + * nsString mPronunciation; + * nsString mDefinition; + * } + * + * (2) Create the hash class + * + * The final hash class you will use in step 3 is defined by 2 macros. + * + * DECL_DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * DHASH_WRAPPER(Dictionary, DictionaryEntry, const nsAString&) + * + * (3) Use the hash class + * + * Here is a simple main() that might look up a string: + * + * int main(void) { + * Dictionary d; + * nsresult rv = d.Init(10); + * if (NS_FAILED(rv)) return 1; + * + * // Put an entry + * DictionaryEntry* a = d.AddEntry(NS_LITERAL_STRING("doomed")); + * if (!a) return 1; + * a->mDefinition.AssignLiteral("The state you get in when a Mozilla release is pending"); + * a->mPronunciation.AssignLiteral("doom-d"); + * + * // Get the entry + * DictionaryEntry* b = d.GetEntry(NS_LITERAL_STRING("doomed")); + * printf("doomed: %s\n", NS_ConvertUCS2toUTF8(b->mDefinition).get()); + * + * // Entries will be automagically cleaned up when the Dictionary object goes away + * return 0; + * } + * + * + * BONUS POINTS + * + * You may wish to extend this class and add helper functions like + * nsDependentString* GetDefinition(nsAString& aWord). For example: + * + * class MyDictionary : public Dictionary { + * public: + * MyDictionary() { } + * // Make SURE you have a virtual destructor + * virtual ~myDictionary() { } + * nsDependentString* GetDefinition(const nsAString& aWord) { + * DictionaryEntry* e = GetEntry(aWord); + * if (e) { + * // We're returning an nsDependentString here, callers need to delete it + * // and it doesn't last long, but at least it doesn't create a copy + * return new nsDependentString(e->mDefinition.get()); + * } else { + * return nsnull; + * } + * } + * nsresult PutDefinition(const nsAString& aWord, + * const nsAString& aDefinition, + * const nsAString& aPronunciation) { + * DictionaryEntry* e = AddEntry(aWord); + * if (!e) { + * return NS_ERROR_OUT_OF_MEMORY; + * } + * e->mDefinition = aDefinition; + * e->mPronunciation = aPronunciation; + * return NS_OK; + * } + * } + */ + +/* + * ENTRY CLASS DEFINITION + * + * The simplifications of PLDHashTable all hinge upon the idea of an entry + * class, which is a class you define, where you store the key and values that + * you will place in each hash entry. You must define six methods for an entry + * (the standard key classes, which you can extend from, define all of these + * for you except the constructor and destructor): + * + * CONSTRUCTOR(const void* aKey) + * When your entry is constructed it will only be given a pointer to the key. + * + * DESTRUCTOR + * Called when the entry is destroyed (of course). + * + * const void* GetKey() + * Must return a pointer to the key + * + * PRBool MatchEntry(const void* aKey) - return true or false depending on + * whether the key pointed to by aKey matches this entry + * + * static PLDHashNumber HashKey(const void* aKey) - get a hashcode based on the + * key (must be the same every time for the same key, but does not have + * to be unique) + * + * For a small hash that just does key->value, you will often just extend a + * standard key class and put a value member into it, and have a destructor and + * constructor--nothing else necessary. + * + * See the default key entry classes as example entry classes. + * + * NOTES: + * - Do NOT ADD VIRTUAL METHODS INTO YOUR ENTRY. Everything will break. + * This is because of the 4-byte pointer C++ magically prepends onto your + * entry class. It interacts very unhappily with PLDHashTable. + */ + +/* + * PRIVATE HASHTABLE MACROS + * + * These internal macros can be used to declare the callbacks for an entry + * class, but the wrapper class macros call these for you so don't call them. + */ + +// +// DHASH_CALLBACKS +// +// Define the hashtable callback functions. Do this in one place only, as you +// will have redundant symbols otherwise. +// +// ENTRY_CLASS: the classname of the entry +// +#define DHASH_CALLBACKS(ENTRY_CLASS) \ +PR_STATIC_CALLBACK(const void *) \ +ENTRY_CLASS##GetKey(PLDHashTable* table, PLDHashEntryHdr* entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, entry); \ + return e->GetKey(); \ +} \ +PR_STATIC_CALLBACK(PLDHashNumber) \ +ENTRY_CLASS##HashKey(PLDHashTable* table, const void* key) \ +{ \ + return ENTRY_CLASS::HashKey(key); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + const ENTRY_CLASS* e = NS_STATIC_CAST(const ENTRY_CLASS*, entry); \ + return e->MatchEntry(key); \ +} \ +PR_STATIC_CALLBACK(void) \ +ENTRY_CLASS##ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) \ +{ \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS *, entry); \ + e->~ENTRY_CLASS(); \ +} \ +PR_STATIC_CALLBACK(PRBool) \ +ENTRY_CLASS##InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, \ + const void *key) \ +{ \ + new (entry) ENTRY_CLASS(key); \ + return PR_TRUE; \ +} + +// +// DHASH_INIT +// +// Initialize hashtable to a certain class. +// +// HASHTABLE: the name of the PLDHashTable variable +// ENTRY_CLASS: the classname of the entry +// NUM_INITIAL_ENTRIES: the number of entry slots the hashtable should start +// with +// RV: an nsresult variable to hold the outcome of the initialization. +// Will be NS_ERROR_OUT_OF_MEMORY if failed, NS_OK otherwise. +// +#define DHASH_INIT(HASHTABLE,ENTRY_CLASS,NUM_INITIAL_ENTRIES,RV) \ +PR_BEGIN_MACRO \ + static PLDHashTableOps hash_table_ops = \ + { \ + PL_DHashAllocTable, \ + PL_DHashFreeTable, \ + ENTRY_CLASS##GetKey, \ + ENTRY_CLASS##HashKey, \ + ENTRY_CLASS##MatchEntry, \ + PL_DHashMoveEntryStub, \ + ENTRY_CLASS##ClearEntry, \ + PL_DHashFinalizeStub, \ + ENTRY_CLASS##InitEntry \ + }; \ + PRBool isLive = PL_DHashTableInit(&(HASHTABLE), \ + &hash_table_ops, nsnull, \ + sizeof(ENTRY_CLASS), \ + (NUM_INITIAL_ENTRIES)); \ + if (!isLive) { \ + (HASHTABLE).ops = nsnull; \ + RV = NS_ERROR_OUT_OF_MEMORY; \ + } else { \ + RV = NS_OK; \ + } \ +PR_END_MACRO + + +/* + * WRAPPER CLASS + * + * This class handles initialization and destruction of the hashtable + * (you must call Init() yourself). It defines these functions: + * + * Init(aNumInitialEntries) + * Initialize the hashtable. This must be called once, it is only separate + * from the constructor so that you can get the return value. You should pass + * in the number of entries you think the hashtable will typically hold (this + * will be the amount of space allocated initially so that it will not have to + * grow). + * + * ENTRY_CLASS* GetEntry(aKey): + * Get the entry referenced by aKey and return a pointer to it. THIS IS A + * TEMPORARY POINTER and is only guaranteed to exist until the next time you do + * an operation on the hashtable. But you can safely use it until then. + * + * Returns nsnull if the entry is not found. + * + * ENTRY_CLASS* AddEntry(aKey): + * Create a new, empty entry and return a pointer to it for you to fill values + * into. THIS IS A TEMPORARY POINTER and is only guaranteed to exist until the + * next time you do an operation on the hashtable. But you can safely fill it + * in. + * + * Returns nsnull if the entry cannot be created (usually a low memory + * constraint). + * + * void Remove(aKey) + * Remove the entry referenced by aKey. If the entry does not exist, nothing + * will happen. + * + * + * DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Declare the hash class but do not define the functions. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) + * + * Define the functions for the hash class. + * + * CLASSNAME: the name of the class to declare. + * ENTRY_CLASS: the class of the entry struct. + * KEY_TYPE: the name of the key type for GetEntry and AddEntry. + * + * + * CAVEATS: + * - You may have only *one* wrapper class per entry class. + */ + +#define DECL_DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME { \ +public: \ + CLASSNAME(); \ + ~CLASSNAME(); \ + nsresult Init(PRUint32 aNumInitialEntries); \ + ENTRY_CLASS* GetEntry(const KEY_TYPE aKey); \ + ENTRY_CLASS* AddEntry(const KEY_TYPE aKey); \ + void Remove(const KEY_TYPE aKey); \ + PLDHashTable mHashTable; \ +}; + +#define DHASH_WRAPPER(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_CALLBACKS(ENTRY_CLASS) \ +CLASSNAME::CLASSNAME() { \ + mHashTable.ops = nsnull; \ +} \ +CLASSNAME::~CLASSNAME() { \ + if (mHashTable.ops) { \ + PL_DHashTableFinish(&mHashTable); \ + } \ +} \ +nsresult CLASSNAME::Init(PRUint32 aNumInitialEntries) { \ + if (!mHashTable.ops) { \ + nsresult rv; \ + DHASH_INIT(mHashTable,ENTRY_CLASS,aNumInitialEntries,rv); \ + return rv; \ + } \ + return NS_OK; \ +} \ +ENTRY_CLASS* CLASSNAME::GetEntry(const KEY_TYPE aKey) { \ + ENTRY_CLASS* e = NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_LOOKUP)); \ + return PL_DHASH_ENTRY_IS_BUSY(e) ? e : nsnull; \ +} \ +ENTRY_CLASS* CLASSNAME::AddEntry(const KEY_TYPE aKey) { \ + return NS_STATIC_CAST(ENTRY_CLASS*, \ + PL_DHashTableOperate(&mHashTable, &aKey, \ + PL_DHASH_ADD)); \ +} \ +void CLASSNAME::Remove(const KEY_TYPE aKey) { \ + PL_DHashTableOperate(&mHashTable, &aKey, PL_DHASH_REMOVE); \ +} + +/* + * STANDARD KEY ENTRY CLASSES + * + * We have declared some standard key classes for you to make life a little + * easier. These include string, int and void* keys. You can extend these + * and add value data members to make a working hash entry class with your + * values. + * + * PLDHashStringEntry: nsAString + * PLDHashCStringEntry: nsACString + * PLDHashInt32Entry: PRInt32 + * PLDHashVoidEntry: void* + * + * As a short example, if you want to make a class that maps int to string, + * you could do: + * + * class MyIntStringEntry : public PLDHashInt32Entry + * { + * public: + * MyIntStringEntry(const void* aKey) : PLDHashInt32Entry(aKey) { } + * ~MyIntStringEntry() { }; + * nsString mMyStr; + * }; + * + * XXX It could be advisable (unless COW strings ever happens) to have a + * PLDHashDependentStringEntry + */ + +// +// String-key entry +// +class NS_COM PLDHashStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsAString*, aKey)) { } + ~PLDHashStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsAString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsAString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsAString*, key)->Equals(mKey); + } + + const nsString mKey; +}; + +// +// CString-key entry +// +class NS_COM PLDHashCStringEntry : public PLDHashEntryHdr +{ +public: + PLDHashCStringEntry(const void* aKey) : + mKey(*NS_STATIC_CAST(const nsACString*, aKey)) { } + ~PLDHashCStringEntry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const nsACString*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return HashString(*NS_STATIC_CAST(const nsACString*, key)); + } + PRBool MatchEntry(const void* key) const { + return NS_STATIC_CAST(const nsACString*, key)->Equals(mKey); + } + + const nsCString mKey; +}; + +// +// Int-key entry +// +class NS_COM PLDHashInt32Entry : public PLDHashEntryHdr +{ +public: + PLDHashInt32Entry(const void* aKey) : + mKey(*(NS_STATIC_CAST(const PRInt32*, aKey))) { } + ~PLDHashInt32Entry() { } + + const void* GetKey() const { + return NS_STATIC_CAST(const PRInt32*, &mKey); + } + static PLDHashNumber HashKey(const void* key) { + return *NS_STATIC_CAST(const PRInt32*, key); + } + PRBool MatchEntry(const void* key) const { + return *(NS_STATIC_CAST(const PRInt32*, key)) == mKey; + } + + const PRInt32 mKey; +}; + + +// +// Void-key entry +// +class NS_COM PLDHashVoidEntry : public PLDHashEntryHdr +{ +public: + PLDHashVoidEntry(const void* aKey) : + mKey(*(const void**)aKey) { } + ~PLDHashVoidEntry() { } + + const void* GetKey() const { + return (const void**)&mKey; + } + static PLDHashNumber HashKey(const void* key) { + return PLDHashNumber(NS_PTR_TO_INT32(*(const void**)key)) >> 2; + } + PRBool MatchEntry(const void* key) const { + return *(const void**)key == mKey; + } + + const void* mKey; +}; + + +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp new file mode 100644 index 00000000..c00d118c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.cpp @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsEmptyEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(EmptyEnumeratorImpl) + +EmptyEnumeratorImpl::EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_CTOR(EmptyEnumeratorImpl); +} + +EmptyEnumeratorImpl::~EmptyEnumeratorImpl(void) +{ + MOZ_COUNT_DTOR(EmptyEnumeratorImpl); +} + +// nsISupports interface +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::AddRef(void) +{ + return 2; +} + +NS_IMETHODIMP_(nsrefcnt) EmptyEnumeratorImpl::Release(void) +{ + return 1; +} + +NS_IMPL_QUERY_INTERFACE1(EmptyEnumeratorImpl, nsISimpleEnumerator) + + +// nsISimpleEnumerator interface +NS_IMETHODIMP EmptyEnumeratorImpl::HasMoreElements(PRBool* aResult) +{ + *aResult = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP EmptyEnumeratorImpl::GetNext(nsISupports** aResult) +{ + return NS_ERROR_UNEXPECTED; +} + +static EmptyEnumeratorImpl* gEmptyEnumerator = nsnull; + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult) +{ + nsresult rv = NS_OK; + if (!gEmptyEnumerator) { + gEmptyEnumerator = new EmptyEnumeratorImpl(); + if (!gEmptyEnumerator) + rv = NS_ERROR_OUT_OF_MEMORY; + } + *aResult = gEmptyEnumerator; + return rv; +} + +/* static */ void +EmptyEnumeratorImpl::Shutdown() +{ + delete gEmptyEnumerator; + gEmptyEnumerator = nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h new file mode 100644 index 00000000..4b2feabe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEmptyEnumerator.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + An empty enumerator. + + */ + +#include "nsIEnumerator.h" + +//////////////////////////////////////////////////////////////////////// + +class EmptyEnumeratorImpl : public nsISimpleEnumerator +{ +public: + EmptyEnumeratorImpl(void); + + // nsISupports interface + NS_DECL_ISUPPORTS_INHERITED // not really inherited, but no mRefCnt + + // nsISimpleEnumerator + NS_DECL_NSISIMPLEENUMERATOR + + static void Shutdown(); + +private: + ~EmptyEnumeratorImpl(void); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp new file mode 100644 index 00000000..e91f68e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsEnumeratorUtils.h" + + +nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), + mIndex(0) +{ + NS_IF_ADDREF(mValueArray); +} + +nsArrayEnumerator::~nsArrayEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsArrayEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + *aResult = (mIndex < (PRInt32) cnt); + return NS_OK; +} + +NS_IMETHODIMP +nsArrayEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + PRUint32 cnt; + nsresult rv = mValueArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mIndex >= (PRInt32) cnt) + return NS_ERROR_UNEXPECTED; + + *aResult = mValueArray->ElementAt(mIndex++); + return NS_OK; +} + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array) +{ + nsArrayEnumerator* enumer = new nsArrayEnumerator(array); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue) + : mValue(aValue) +{ + NS_IF_ADDREF(mValue); + mConsumed = (mValue ? PR_FALSE : PR_TRUE); +} + +nsSingletonEnumerator::~nsSingletonEnumerator() +{ + NS_IF_RELEASE(mValue); +} + +NS_IMPL_ISUPPORTS1(nsSingletonEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsSingletonEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = !mConsumed; + return NS_OK; +} + + +NS_IMETHODIMP +nsSingletonEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + mConsumed = PR_TRUE; + + *aResult = mValue; + NS_ADDREF(*aResult); + return NS_OK; +} + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton) +{ + nsSingletonEnumerator* enumer = new nsSingletonEnumerator(singleton); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + NS_ADDREF(*result); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) + : mFirstEnumerator(firstEnumerator), + mSecondEnumerator(secondEnumerator), + mConsumed(PR_FALSE), mAtSecond(PR_FALSE) +{ +} + +nsUnionEnumerator::~nsUnionEnumerator() +{ +} + +NS_IMPL_ISUPPORTS1(nsUnionEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +nsUnionEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + + if (mConsumed) { + *aResult = PR_FALSE; + return NS_OK; + } + + if (! mAtSecond) { + rv = mFirstEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + mAtSecond = PR_TRUE; + } + + rv = mSecondEnumerator->HasMoreElements(aResult); + if (NS_FAILED(rv)) return rv; + + if (*aResult) + return NS_OK; + + *aResult = PR_FALSE; + mConsumed = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsUnionEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (mConsumed) + return NS_ERROR_UNEXPECTED; + + if (! mAtSecond) + return mFirstEnumerator->GetNext(aResult); + + return mSecondEnumerator->GetNext(aResult); +} + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator) +{ + *result = nsnull; + if (! firstEnumerator) { + *result = secondEnumerator; + } else if (! secondEnumerator) { + *result = firstEnumerator; + } else { + nsUnionEnumerator* enumer = new nsUnionEnumerator(firstEnumerator, secondEnumerator); + if (enumer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + *result = enumer; + } + NS_ADDREF(*result); + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h new file mode 100644 index 00000000..2d8182b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsEnumeratorUtils.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsEnumeratorUtils_h__ +#define nsEnumeratorUtils_h__ + +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewSingletonEnumerator VBoxNsxpNS_NewSingletonEnumerator +#define NS_NewUnionEnumerator VBoxNsxpNS_NewUnionEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +class NS_COM nsArrayEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + // nsArrayEnumerator methods + nsArrayEnumerator(nsISupportsArray* aValueArray); + +private: + ~nsArrayEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +extern NS_COM nsresult +NS_NewArrayEnumerator(nsISimpleEnumerator* *result, + nsISupportsArray* array); + +//////////////////////////////////////////////////////////////////////////////// + +class NS_COM nsSingletonEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsSingletonEnumerator(nsISupports* aValue); + +private: + ~nsSingletonEnumerator(); + +protected: + nsISupports* mValue; + PRBool mConsumed; +}; + +extern "C" NS_COM nsresult +NS_NewSingletonEnumerator(nsISimpleEnumerator* *result, + nsISupports* singleton); + +//////////////////////////////////////////////////////////////////////// + +class NS_COM nsUnionEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator methods + NS_IMETHOD HasMoreElements(PRBool* aResult); + NS_IMETHOD GetNext(nsISupports** aResult); + + nsUnionEnumerator(nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +private: + ~nsUnionEnumerator(); + +protected: + nsCOMPtr mFirstEnumerator, mSecondEnumerator; + PRBool mConsumed; + PRBool mAtSecond; +}; + +extern "C" NS_COM nsresult +NS_NewUnionEnumerator(nsISimpleEnumerator* *result, + nsISimpleEnumerator* firstEnumerator, + nsISimpleEnumerator* secondEnumerator); + +//////////////////////////////////////////////////////////////////////// + +#endif /* nsEnumeratorUtils_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp new file mode 100644 index 00000000..1b6232f9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson mSize = aSize; + bucket->mFirst = nsnull; + bucket->mNext = mBuckets; + + mBuckets = bucket; + return bucket; +} + +nsresult +nsFixedSizeAllocator::Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign) +{ + NS_PRECONDITION(aNumBuckets > 0, "no buckets"); + if (aNumBuckets <= 0) + return NS_ERROR_INVALID_ARG; + + // Blow away the old pool if we're being re-initialized. + if (mBuckets) + PL_FinishArenaPool(&mPool); + + PRInt32 bucketspace = aNumBuckets * sizeof(Bucket); + PL_InitArenaPool(&mPool, aName, bucketspace + aInitialSize, aAlign); + + mBuckets = nsnull; + for (PRInt32 i = 0; i < aNumBuckets; ++i) + AddBucket(aBucketSizes[i]); + + return NS_OK; +} + +nsFixedSizeAllocator::Bucket * +nsFixedSizeAllocator::FindBucket(size_t aSize) +{ + Bucket** link = &mBuckets; + Bucket* bucket; + + while ((bucket = *link) != nsnull) { + if (aSize == bucket->mSize) { + // Promote to the head of the list, under the assumption + // that we'll allocate same-sized object contemporaneously. + *link = bucket->mNext; + bucket->mNext = mBuckets; + mBuckets = bucket; + return bucket; + } + + link = &bucket->mNext; + } + return nsnull; +} + +void* +nsFixedSizeAllocator::Alloc(size_t aSize) +{ + Bucket* bucket = FindBucket(aSize); + if (! bucket) { + // Oops, we don't carry that size. Let's fix that. + bucket = AddBucket(aSize); + if (! bucket) + return nsnull; + } + + void* next; + if (bucket->mFirst) { + next = bucket->mFirst; + bucket->mFirst = bucket->mFirst->mNext; + } + else { + PL_ARENA_ALLOCATE(next, &mPool, aSize); + if (!next) + return nsnull; + } + +#ifdef DEBUG + memset(next, 0xc8, aSize); +#endif + + return next; +} + +void +nsFixedSizeAllocator::Free(void* aPtr, size_t aSize) +{ + FreeEntry* entry = NS_REINTERPRET_CAST(FreeEntry*, aPtr); + Bucket* bucket = FindBucket(aSize); + +#ifdef DEBUG + NS_ASSERTION(bucket && bucket->mSize == aSize, "ack! corruption! bucket->mSize != aSize!"); + memset(aPtr, 0xd8, bucket->mSize); +#endif + + entry->mNext = bucket->mFirst; + bucket->mFirst = entry; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h new file mode 100644 index 00000000..16708cdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsFixedSizeAllocator.h @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson ~Foo(); + aAllocator.Free(aFoo, sizeof(Foo)); + } + + // ctor & dtor + Foo() {} + ~Foo() {} + }; + + + int main(int argc, char* argv[]) + { + // Somewhere in your code, you'll need to create an + // nsFixedSizeAllocator object and initialize it: + nsFixedSizeAllocator pool; + + // The fixed size allocator will support multiple fixed sizes. + // This array lists an initial set of sizes that the allocator + // should be prepared to support. In our case, there's just one, + // which is Foo. + static const size_t kBucketSizes[] + = { sizeof(Foo) } + + // This is the number of different "buckets" you'll need for + // fixed size objects. In our example, this will be "1". + static const PRInt32 kNumBuckets + = sizeof(kBucketSizes) / sizeof(size_t); + + // This is the intial size of the allocator, in bytes. We'll + // assume that we want to start with space for 1024 Foo objects. + static const PRInt32 kInitialPoolSize = + NS_SIZE_IN_HEAP(sizeof(Foo)) * 1024; + + // Initialize (or re-initialize) the pool + pool.Init("TheFooPool", kBucketSizes, kNumBuckets, kInitialPoolSize); + + // Now we can use the pool. + + // Create a new Foo object using the pool: + Foo* foo = Foo::Create(pool); + if (! foo) { + // uh oh, out of memory! + } + + // Delete the object. The memory used by `foo' is recycled in + // the pool, and placed in a freelist + Foo::Destroy(foo); + + // Create another foo: this one will be allocated from the + // free-list + foo = Foo::Create(pool); + + // When pool is destroyed, all of its memory is automatically + // freed. N.B. it will *not* call your objects' destructors! In + // this case, foo's ~Foo() method would never be called. + } + +*/ + +#ifndef nsFixedSizeAllocator_h__ +#define nsFixedSizeAllocator_h__ + +#include "nscore.h" +#include "nsError.h" +#include "plarena.h" + +#define NS_SIZE_IN_HEAP(_size) (_size) + +class NS_COM nsFixedSizeAllocator +{ +protected: + PLArenaPool mPool; + + struct Bucket; + struct FreeEntry; + + friend struct Bucket; + friend struct FreeEntry; + + struct FreeEntry { + FreeEntry* mNext; + }; + + struct Bucket { + size_t mSize; + FreeEntry* mFirst; + Bucket* mNext; + }; + + Bucket* mBuckets; + + Bucket * + AddBucket(size_t aSize); + + Bucket * + FindBucket(size_t aSize); + +public: + nsFixedSizeAllocator() : mBuckets(nsnull) {} + + ~nsFixedSizeAllocator() { + if (mBuckets) + PL_FinishArenaPool(&mPool); + } + + /** + * Initialize the fixed size allocator. 'aName' is used to tag + * the underlying PLArena object for debugging and measurement + * purposes. 'aNumBuckets' specifies the number of elements in + * 'aBucketSizes', which is an array of integral block sizes + * that this allocator should be prepared to handle. + */ + nsresult + Init(const char* aName, + const size_t* aBucketSizes, + PRInt32 aNumBuckets, + PRInt32 aInitialSize, + PRInt32 aAlign = 0); + + /** + * Allocate a block of memory 'aSize' bytes big. + */ + void* Alloc(size_t aSize); + + /** + * Free a pointer allocated using a fixed-size allocator + */ + void Free(void* aPtr, size_t aSize); +}; + + + +#endif // nsFixedSizeAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h new file mode 100644 index 00000000..8a6d272e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashKeys.h @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsTHashKeys_h__ +#define nsTHashKeys_h__ + +#include "nsAString.h" +#include "nsString.h" +#include "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsISupports.h" +#include "nsCOMPtr.h" +#include "pldhash.h" +#include NEW_H + +/** @file nsHashKeys.h + * standard HashKey classes for nsBaseHashtable and relatives. Each of these + * classes follows the nsTHashtable::EntryType specification + * + * Lightweight keytypes provided here: + * nsStringHashKey + * nsCStringHashKey + * nsUint32HashKey + * nsISupportsHashKey + * nsIDHashKey + * nsDepCharHashKey + */ + +/** + * hashkey wrapper using nsAString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsAString& KeyType; + typedef const nsAString* KeyTypePointer; + + nsStringHashKey(KeyTypePointer aStr) : mStr(*aStr) { } + nsStringHashKey(const nsStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + PRBool KeyEquals(const KeyTypePointer aKey) const + { + return mStr.Equals(*aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(const KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsString mStr; +}; + +/** + * hashkey wrapper using nsACString KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsCStringHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsACString& KeyType; + typedef const nsACString* KeyTypePointer; + + nsCStringHashKey(const nsACString* aStr) : mStr(*aStr) { } + nsCStringHashKey(const nsCStringHashKey& toCopy) : mStr(toCopy.mStr) { } + ~nsCStringHashKey() { } + + KeyType GetKey() const { return mStr; } + KeyTypePointer GetKeyPointer() const { return &mStr; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return mStr.Equals(*aKey); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return HashString(*aKey); + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsCString mStr; +}; + +/** + * hashkey wrapper using PRUint32 KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsUint32HashKey : public PLDHashEntryHdr +{ +public: + typedef const PRUint32& KeyType; + typedef const PRUint32* KeyTypePointer; + + nsUint32HashKey(KeyTypePointer aKey) : mValue(*aKey) { } + nsUint32HashKey(const nsUint32HashKey& toCopy) : mValue(toCopy.mValue) { } + ~nsUint32HashKey() { } + + KeyType GetKey() const { return mValue; } + KeyTypePointer GetKeyPointer() const { return &mValue; } + PRBool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return *aKey; } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const PRUint32 mValue; +}; + +/** + * hashkey wrapper using nsISupports* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsISupportsHashKey : public PLDHashEntryHdr +{ +public: + typedef nsISupports* KeyType; + typedef const nsISupports* KeyTypePointer; + + nsISupportsHashKey(const nsISupports* key) : + mSupports(NS_CONST_CAST(nsISupports*,key)) { } + nsISupportsHashKey(const nsISupportsHashKey& toCopy) : + mSupports(toCopy.mSupports) { } + ~nsISupportsHashKey() { } + + KeyType GetKey() const { return mSupports; } + KeyTypePointer GetKeyPointer() const { return mSupports; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mSupports; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + nsCOMPtr mSupports; +}; + +/** + * hashkey wrapper using void* KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsVoidPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const void* KeyType; + typedef const void* KeyTypePointer; + + nsVoidPtrHashKey(const void* key) : + mKey(key) { } + nsVoidPtrHashKey(const nsVoidPtrHashKey& toCopy) : + mKey(toCopy.mKey) { } + ~nsVoidPtrHashKey() { } + + KeyType GetKey() const { return mKey; } + KeyTypePointer GetKeyPointer() const { return mKey; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) + { + return NS_PTR_TO_INT32(aKey) >>2; + } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const void* mKey; +}; + +/** + * hashkey wrapper using nsID KeyType + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsIDHashKey : public PLDHashEntryHdr +{ +public: + typedef const nsID& KeyType; + typedef const nsID* KeyTypePointer; + + nsIDHashKey(const nsID* id) : mID(*id) { } + nsIDHashKey(const nsIDHashKey& toCopy) : mID(toCopy.mID) { } + ~nsIDHashKey() { } + + KeyType GetKey() const { return mID; } + KeyTypePointer GetKeyPointer() const { return &mID; } + + PRBool KeyEquals(KeyTypePointer aKey) const { return aKey->Equals(mID); } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey); + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const nsID mID; +}; + +/** + * hashkey wrapper for "dependent" const char*; this class does not "own" + * its string pointer. + * + * This class must only be used if the strings have a lifetime longer than + * the hashtable they occupy. This normally occurs only for static + * strings or strings that have been arena-allocated. + * + * @see nsTHashtable::EntryType for specification + */ +class NS_COM nsDepCharHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsDepCharHashKey(const char* aKey) { mKey = aKey; } + nsDepCharHashKey(const nsDepCharHashKey& toCopy) { mKey = toCopy.mKey; } + ~nsDepCharHashKey() { } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(const char* aKey) const + { + return !strcmp(mKey, aKey); + } + + static const char* KeyToPointer(const char* aKey) { return aKey; } + static PLDHashNumber HashKey(const char* aKey) { return nsCRT::HashCode(aKey); } + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +/** + * hashkey wrapper for const char*; at construction, this class duplicates + * a string pointed to by the pointer so that it doesn't matter whether or not + * the string lives longer than the hash table. + */ +class NS_COM nsCharPtrHashKey : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + nsCharPtrHashKey(const char* aKey) : mKey(strdup(aKey)) { } + nsCharPtrHashKey(const nsCharPtrHashKey& toCopy) : mKey(strdup(toCopy.mKey)) { } + ~nsCharPtrHashKey() { if (mKey) free(NS_CONST_CAST(char *, mKey)); } + + const char* GetKey() const { return mKey; } + const char* GetKeyPointer() const { return mKey; } + PRBool KeyEquals(KeyTypePointer aKey) const + { + return !strcmp(mKey, aKey); + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { return nsCRT::HashCode(aKey); } + + enum { ALLOW_MEMMOVE = PR_TRUE }; + +private: + const char* mKey; +}; + +#endif // nsTHashKeys_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp new file mode 100644 index 00000000..3f11ba55 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" +#include NEW_H + +#include "nsHashSets.h" + +DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h new file mode 100644 index 00000000..627a6a06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashSets.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsHashSets_h__ +#define __nsHashSets_h__ + +#include "nsDoubleHashtable.h" + +/* + * HASH SETS + * + * These hash classes describe hashtables that contain keys without values. + * This is useful when you want to store things and then just test for their + * existence later. We have defined standard ones for string, int and void. + * + * nsStringHashSet: nsAString& + * nsCStringHashSet: nsACString& + * nsInt32HashSet: PRInt32 + * nsVoidHashSet: void* + * + * USAGE: + * Put(): put a thing of the given type into the set + * Contains(): whether it contains a thing of the given type + * To use, you just do: (for example) + * + * #include "nsDoubleHashtable.h" + * nsInt32HashSet mySet; + * mySet.Init(1); + * mySet.Put(5); + * if (mySet.Contains(5)) { + * printf("yay\n"); + * } + * + * There is a nice convenient macro for declaring empty map classes: + * DECL_DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) + * - CLASSNAME: the name of the class + * - ENTRY_CLASS: the name of the entry class with the key in it + * - KEY_TYPE: the type of key for Put() and Contains() + * + * DHASH_SET(CLASSNAME, ENTRY_CLASS, KEY_TYPE) is the companion macro + * you must put in the .cpp (implementation) code. + */ + +#define DECL_DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DECL_DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) \ +class DHASH_EXPORT CLASSNAME : public CLASSNAME##Super { \ +public: \ + CLASSNAME() : CLASSNAME##Super() { } \ + ~CLASSNAME() { } \ + nsresult Put(const KEY_TYPE aKey) { \ + return AddEntry(aKey) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; \ + } \ + PRBool Contains(const KEY_TYPE aKey) { \ + return GetEntry(aKey) ? PR_TRUE : PR_FALSE; \ + } \ +}; + +#define DHASH_SET(CLASSNAME,ENTRY_CLASS,KEY_TYPE) \ +DHASH_WRAPPER(CLASSNAME##Super,ENTRY_CLASS,KEY_TYPE) + +#undef DHASH_EXPORT +#define DHASH_EXPORT NS_COM + +DECL_DHASH_SET(nsStringHashSet, PLDHashStringEntry, nsAString&) +DECL_DHASH_SET(nsCStringHashSet,PLDHashCStringEntry,nsACString&) +DECL_DHASH_SET(nsInt32HashSet, PLDHashInt32Entry, PRInt32) +DECL_DHASH_SET(nsVoidHashSet, PLDHashVoidEntry, void*) + +#undef DHASH_EXPORT +#define DHASH_EXPORT + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp new file mode 100644 index 00000000..ce74fb28 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.cpp @@ -0,0 +1,896 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include +#include "prmem.h" +#include "prlog.h" +#include "nsHashtable.h" +#include "nsReadableUtils.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsCRT.h" + +struct HTEntry : PLDHashEntryHdr +{ + nsHashKey* key; + void* value; +}; + +// +// Key operations +// + +PR_STATIC_CALLBACK(PRBool) +matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry, + const void* key) +{ + const HTEntry* hashEntry = + NS_STATIC_CAST(const HTEntry*, entry); + + if (hashEntry->key == key) + return PR_TRUE; + + const nsHashKey* otherKey = NS_REINTERPRET_CAST(const nsHashKey*, key); + return otherKey->Equals(hashEntry->key); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +hashKey(PLDHashTable* table, const void* key) +{ + const nsHashKey* hashKey = NS_STATIC_CAST(const nsHashKey*, key); + + return hashKey->HashCode(); +} + +PR_STATIC_CALLBACK(void) +clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry) +{ + HTEntry* hashEntry = NS_STATIC_CAST(HTEntry*, entry); + + // leave it up to the nsHashKey destructor to free the "value" + delete hashEntry->key; + hashEntry->key = nsnull; + hashEntry->value = nsnull; // probably not necessary, but for + // sanity's sake +} + + +static const PLDHashTableOps hashtableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + hashKey, + matchKeyEntry, + PL_DHashMoveEntryStub, + clearHashEntry, + PL_DHashFinalizeStub, + nsnull, +}; + + +// +// Enumerator callback +// + +struct _HashEnumerateArgs { + nsHashtableEnumFunc fn; + void* arg; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + switch (thunk->fn(entry->key, entry->value, thunk->arg)) { + case kHashEnumerateNext: + return PL_DHASH_NEXT; + case kHashEnumerateRemove: + return PL_DHASH_REMOVE; + } + return PL_DHASH_STOP; +} + +// +// HashKey +// + +nsHashKey::~nsHashKey(void) +{ + MOZ_COUNT_DTOR(nsHashKey); +} + +nsresult +nsHashKey::Write(nsIObjectOutputStream* aStream) const +{ + NS_NOTREACHED("oops"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +MOZ_DECL_CTOR_COUNTER(nsHashtable) + +nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe) + : mLock(NULL), mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nsnull, + sizeof(HTEntry), aInitSize); + + NS_ASSERTION(result, "Hashtable failed to initialize"); + + // make sure we detect this later + if (!result) + mHashtable.ops = nsnull; + + if (threadSafe) { + mLock = PR_NewLock(); + if (mLock == NULL) { + // Cannot create a lock. If running on a multiprocessing system + // we are sure to die. + PR_ASSERT(mLock != NULL); + } + } +} + + +nsHashtable::~nsHashtable() { + MOZ_COUNT_DTOR(nsHashtable); + if (mHashtable.ops) + PL_DHashTableFinish(&mHashtable); + if (mLock) PR_DestroyLock(mLock); +} + +PRBool nsHashtable::Exists(nsHashKey *aKey) +{ + if (mLock) PR_Lock(mLock); + + if (!mHashtable.ops) + return PR_FALSE; + + PLDHashEntryHdr *entry = + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP); + + PRBool exists = PL_DHASH_ENTRY_IS_BUSY(entry); + + if (mLock) PR_Unlock(mLock); + + return exists; +} + +void *nsHashtable::Put(nsHashKey *aKey, void *aData) +{ + void *res = NULL; + + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD)); + + if (entry) { // don't return early, or you'll be locked! + if (entry->key) { + // existing entry, need to boot the old value + res = entry->value; + entry->value = aData; + } else { + // new entry (leave res == null) + entry->key = aKey->Clone(); + entry->value = aData; + } + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +void *nsHashtable::Get(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nsnull; + + if (mLock) PR_Unlock(mLock); + + return ret; +} + +void *nsHashtable::Remove(nsHashKey *aKey) +{ + if (!mHashtable.ops) return nsnull; + + if (mLock) PR_Lock(mLock); + + // shouldn't be adding an item during enumeration + PR_ASSERT(!mEnumerating); + + + // need to see if the entry is actually there, in order to get the + // old value for the result + HTEntry* entry = + NS_STATIC_CAST(HTEntry*, + PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP)); + void *res; + + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + // value wasn't in the table anyway + res = nsnull; + } else { + res = entry->value; + PL_DHashTableRawRemove(&mHashtable, entry); + } + + if (mLock) PR_Unlock(mLock); + + return res; +} + +// XXX This method was called _hashEnumerateCopy, but it didn't copy the element! +// I don't know how this was supposed to work since the elements are neither copied +// nor refcounted. +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry * entry = NS_STATIC_CAST(HTEntry*, hdr); + + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable * nsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable); + return newHashTable; +} + +void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + PRBool wasEnumerating = mEnumerating; + mEnumerating = PR_TRUE; + _HashEnumerateArgs thunk; + thunk.fn = aEnumFunc; + thunk.arg = aClosure; + PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk); + mEnumerating = wasEnumerating; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, PRUint32 i, void *arg) +{ + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg; + if (thunk) { + return thunk->fn(entry->key, entry->value, thunk->arg) + ? PL_DHASH_REMOVE + : PL_DHASH_STOP; + } + return PL_DHASH_REMOVE; +} + +void nsHashtable::Reset() { + Reset(NULL); +} + +void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure) +{ + if (!mHashtable.ops) return; + + _HashEnumerateArgs thunk, *thunkp; + if (!destroyFunc) { + thunkp = nsnull; + } else { + thunkp = &thunk; + thunk.fn = destroyFunc; + thunk.arg = aClosure; + } + PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp); +} + +// nsISerializable helpers + +nsHashtable::nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal) + : mLock(nsnull), + mEnumerating(PR_FALSE) +{ + MOZ_COUNT_CTOR(nsHashtable); + + PRBool threadSafe; + nsresult rv = aStream->ReadBoolean(&threadSafe); + if (NS_SUCCEEDED(rv)) { + if (threadSafe) { + mLock = PR_NewLock(); + if (!mLock) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_SUCCEEDED(rv)) { + PRUint32 count; + rv = aStream->Read32(&count); + + if (NS_SUCCEEDED(rv)) { + PRBool status = + PL_DHashTableInit(&mHashtable, &hashtableOps, + nsnull, sizeof(HTEntry), count); + if (!status) { + mHashtable.ops = nsnull; + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + for (PRUint32 i = 0; i < count; i++) { + nsHashKey* key; + void *data; + + rv = aReadEntryFunc(aStream, &key, &data); + if (NS_SUCCEEDED(rv)) { + if (!Put(key, data)) { + rv = NS_ERROR_OUT_OF_MEMORY; + aFreeEntryFunc(aStream, key, data); + } else { + // XXXbe must we clone key? can't we hand off + aFreeEntryFunc(aStream, key, nsnull); + } + if (NS_FAILED(rv)) + break; + } + } + } + } + } + } + *aRetVal = rv; +} + +struct WriteEntryArgs { + nsIObjectOutputStream* mStream; + nsHashtableWriteDataFunc mWriteDataFunc; + nsresult mRetVal; +}; + +PR_STATIC_CALLBACK(PRBool) +WriteEntry(nsHashKey *aKey, void *aData, void* aClosure) +{ + WriteEntryArgs* args = (WriteEntryArgs*) aClosure; + nsIObjectOutputStream* stream = args->mStream; + + nsresult rv = aKey->Write(stream); + if (NS_SUCCEEDED(rv)) + rv = args->mWriteDataFunc(stream, aData); + + args->mRetVal = rv; + return PR_TRUE; +} + +nsresult +nsHashtable::Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const +{ + if (!mHashtable.ops) + return NS_ERROR_OUT_OF_MEMORY; + PRBool threadSafe = (mLock != nsnull); + nsresult rv = aStream->WriteBoolean(threadSafe); + if (NS_FAILED(rv)) return rv; + + // Write the entry count first, so we know how many key/value pairs to read. + PRUint32 count = mHashtable.entryCount; + rv = aStream->Write32(count); + if (NS_FAILED(rv)) return rv; + + // Write all key/value pairs in the table. + WriteEntryArgs args = {aStream, aWriteDataFunc}; + NS_CONST_CAST(nsHashtable*, this)->Enumerate(WriteEntry, (void*) &args); + return args.mRetVal; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mKey(nsnull) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->ReadObject(PR_TRUE, &mKey); + *aResult = rv; +} + +nsresult +nsISupportsKey::Write(nsIObjectOutputStream* aStream) const +{ + PRBool nonnull = (mKey != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteObject(mKey, PR_TRUE); + return rv; +} + +nsIDKey::nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult) +{ + *aResult = aStream->ReadID(&mID); +} + +nsresult nsIDKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteID(mID); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsCStringKey::nsCStringKey(const nsCStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(char); + char* str = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(len + sizeof(char))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = '\0'; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsAFlatCString& str) + : mStr(NS_CONST_CAST(char*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const nsACString& str) + : mStr(ToNewCString(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::nsCStringKey(const char* str, PRInt32 strLen, Ownership own) + : mStr((char*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = strlen(str); +#ifdef DEBUG + mKeyType = CStringKey; +#endif + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsCStringKey::~nsCStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsCStringKey); +} + +PRUint32 +nsCStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsCStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types"); + nsCStringKey* other = (nsCStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0; +} + +nsHashKey* +nsCStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsCStringKey(mStr, mStrLen, NEVER_OWN); + + // Since this might hold binary data OR a string, we ensure that the + // clone string is zero terminated, but don't assume that the source + // string was so terminated. + + PRUint32 len = mStrLen * sizeof(char); + char* str = (char*)nsMemory::Alloc(len + sizeof(char)); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + str[len] = 0; + return new nsCStringKey(str, mStrLen, OWN); +} + +nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsCAutoString str; + nsresult rv = aStream->ReadCString(str); + mStr = ToNewCString(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsCStringKey); +} + +nsresult +nsCStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// + +// Copy Constructor +// We need to free mStr if the object is passed with mOwnership as OWN. As the +// destructor here is freeing mStr in that case, mStr is NOT getting leaked here. + +nsStringKey::nsStringKey(const nsStringKey& aKey) + : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership) +{ + if (mOwnership != NEVER_OWN) { + PRUint32 len = mStrLen * sizeof(PRUnichar); + PRUnichar* str = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(len + sizeof(PRUnichar))); + if (!str) { + // Pray we don't dangle! + mOwnership = NEVER_OWN; + } else { + // Use memcpy in case there are embedded NULs. + memcpy(str, mStr, len); + str[mStrLen] = 0; + mStr = str; + mOwnership = OWN; + } + } +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAFlatString& str) + : mStr(NS_CONST_CAST(PRUnichar*, str.get())), + mStrLen(str.Length()), + mOwnership(OWN_CLONE) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const nsAString& str) + : mStr(ToNewUnicode(str)), + mStrLen(str.Length()), + mOwnership(OWN) +{ + NS_ASSERTION(mStr, "null string key"); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::nsStringKey(const PRUnichar* str, PRInt32 strLen, Ownership own) + : mStr((PRUnichar*)str), mStrLen(strLen), mOwnership(own) +{ + NS_ASSERTION(mStr, "null string key"); + if (mStrLen == PRUint32(-1)) + mStrLen = nsCRT::strlen(str); +#ifdef DEBUG + mKeyType = StringKey; +#endif + MOZ_COUNT_CTOR(nsStringKey); +} + +nsStringKey::~nsStringKey(void) +{ + if (mOwnership == OWN) + nsMemory::Free(mStr); + MOZ_COUNT_DTOR(nsStringKey); +} + +PRUint32 +nsStringKey::HashCode(void) const +{ + return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen); +} + +PRBool +nsStringKey::Equals(const nsHashKey* aKey) const +{ + NS_ASSERTION(aKey->GetKeyType() == StringKey, "mismatched key types"); + nsStringKey* other = (nsStringKey*)aKey; + NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode"); + NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode"); + if (mStrLen != other->mStrLen) + return PR_FALSE; + return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0; +} + +nsHashKey* +nsStringKey::Clone() const +{ + if (mOwnership == NEVER_OWN) + return new nsStringKey(mStr, mStrLen, NEVER_OWN); + + PRUint32 len = (mStrLen+1) * sizeof(PRUnichar); + PRUnichar* str = (PRUnichar*)nsMemory::Alloc(len); + if (str == NULL) + return NULL; + memcpy(str, mStr, len); + return new nsStringKey(str, mStrLen, OWN); +} + +nsStringKey::nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult) + : mStr(nsnull), mStrLen(0), mOwnership(OWN) +{ + nsAutoString str; + nsresult rv = aStream->ReadString(str); + mStr = ToNewUnicode(str); + if (NS_SUCCEEDED(rv)) + mStrLen = str.Length(); + *aResult = rv; + MOZ_COUNT_CTOR(nsStringKey); +} + +nsresult +nsStringKey::Write(nsIObjectOutputStream* aStream) const +{ + return aStream->WriteWStringZ(mStr); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize, PRBool threadSafe) + : nsHashtable(aSize, threadSafe), + mCloneElementFun(cloneElementFun), + mCloneElementClosure(cloneElementClosure), + mDestroyElementFun(destroyElementFun), + mDestroyElementClosure(destroyElementClosure) +{ +} + +nsObjectHashtable::~nsObjectHashtable() +{ + Reset(); +} + + +PLDHashOperator PR_CALLBACK +nsObjectHashtable::CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg; + HTEntry *entry = NS_STATIC_CAST(HTEntry*, hdr); + + void* newElement = + newHashtable->mCloneElementFun(entry->key, entry->value, + newHashtable->mCloneElementClosure); + if (newElement == nsnull) + return PL_DHASH_STOP; + newHashtable->Put(entry->key, newElement); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsObjectHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = PR_FALSE; + if (mLock) + threadSafe = PR_TRUE; + nsObjectHashtable* newHashTable = + new nsObjectHashtable(mCloneElementFun, mCloneElementClosure, + mDestroyElementFun, mDestroyElementClosure, + mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable); + return newHashTable; +} + +void +nsObjectHashtable::Reset() +{ + nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure); +} + +PRBool +nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey) +{ + void *value = Remove(aKey); + if (value && mDestroyElementFun) + return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure); + return PR_FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +PRBool PR_CALLBACK +nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure) +{ + nsISupports* element = NS_STATIC_CAST(nsISupports*, aData); + NS_IF_RELEASE(element); + return PR_TRUE; +} + +nsSupportsHashtable::~nsSupportsHashtable() +{ + Enumerate(ReleaseElement, nsnull); +} + +// Return true if we overwrote something + +PRBool +nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value) +{ + NS_IF_ADDREF(aData); + void *prev = nsHashtable::Put(aKey, aData); + nsISupports *old = NS_REINTERPRET_CAST(nsISupports *, prev); + if (value) // pass own the ownership to the caller + *value = old; + else // the caller doesn't care, we do + NS_IF_RELEASE(old); + return prev != nsnull; +} + +nsISupports * +nsSupportsHashtable::Get(nsHashKey *aKey) +{ + void* data = nsHashtable::Get(aKey); + if (!data) + return nsnull; + nsISupports* element = NS_REINTERPRET_CAST(nsISupports*, data); + NS_IF_ADDREF(element); + return element; +} + +// Return true if we found something (useful for checks) + +PRBool +nsSupportsHashtable::Remove(nsHashKey *aKey, nsISupports **value) +{ + void* data = nsHashtable::Remove(aKey); + nsISupports* element = NS_STATIC_CAST(nsISupports*, data); + if (value) // caller wants it + *value = element; + else // caller doesn't care, we do + NS_IF_RELEASE(element); + return data != nsnull; +} + +PLDHashOperator PR_CALLBACK +nsSupportsHashtable::EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg) +{ + nsHashtable *newHashtable = (nsHashtable *)arg; + HTEntry* entry = NS_STATIC_CAST(HTEntry*, hdr); + + nsISupports* element = NS_STATIC_CAST(nsISupports*, entry->value); + NS_IF_ADDREF(element); + newHashtable->Put(entry->key, entry->value); + return PL_DHASH_NEXT; +} + +nsHashtable* +nsSupportsHashtable::Clone() +{ + if (!mHashtable.ops) return nsnull; + + PRBool threadSafe = (mLock != nsnull); + nsSupportsHashtable* newHashTable = + new nsSupportsHashtable(mHashtable.entryCount, threadSafe); + + PL_DHashTableEnumerate(&mHashtable, EnumerateCopy, newHashTable); + return newHashTable; +} + +void +nsSupportsHashtable::Reset() +{ + Enumerate(ReleaseElement, nsnull); + nsHashtable::Reset(); +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h new file mode 100644 index 00000000..21ce9028 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsHashtable.h @@ -0,0 +1,454 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +/** + * nsHashtable is OBSOLETE. Use nsTHashtable or a derivative instead. + */ + +#ifndef nsHashtable_h__ +#define nsHashtable_h__ + +#include "pldhash.h" +#include "prlock.h" +#include "nscore.h" +#include "nsString.h" +#include "nsISupportsBase.h" +#include "nsTraceRefcnt.h" + +class nsIObjectInputStream; +class nsIObjectOutputStream; + +class nsHashtable; +class nsStringKey; + +class NS_COM nsHashKey { + protected: + nsHashKey(void) { +#ifdef DEBUG + mKeyType = UnknownKey; +#endif + MOZ_COUNT_CTOR(nsHashKey); + } + + + public: + // Virtual destructor because all hash keys are |delete|d via a + // nsHashKey pointer. + + virtual ~nsHashKey(void); + virtual PRUint32 HashCode(void) const = 0; + virtual PRBool Equals(const nsHashKey *aKey) const = 0; + virtual nsHashKey *Clone() const = 0; + virtual nsresult Write(nsIObjectOutputStream* aStream) const; + +#ifdef DEBUG + public: + // used for verification that we're casting to the correct key type + enum nsHashKeyType { + UnknownKey, + SupportsKey, + PRUint32Key, + VoidKey, + IDKey, + CStringKey, + StringKey + }; + nsHashKeyType GetKeyType() const { return mKeyType; } + protected: + nsHashKeyType mKeyType; +#endif +}; + +// Enumerator and Read/Write callback functions. + +// Return values for nsHashtableEnumFunc +enum { + kHashEnumerateStop = PR_FALSE, + kHashEnumerateNext = PR_TRUE, + kHashEnumerateRemove = 2 +}; + +typedef PRIntn +(*PR_CALLBACK nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +typedef nsresult +(*PR_CALLBACK nsHashtableReadEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey **aKey, + void **aData); + +// NB: may be called with null aKey or aData, to free just one of the two. +typedef void +(*PR_CALLBACK nsHashtableFreeEntryFunc)(nsIObjectInputStream *aStream, + nsHashKey *aKey, + void *aData); + +typedef nsresult +(*PR_CALLBACK nsHashtableWriteDataFunc)(nsIObjectOutputStream *aStream, + void *aData); + +class NS_COM nsHashtable { + protected: + // members + PRLock* mLock; + PLDHashTable mHashtable; + PRBool mEnumerating; + + public: + nsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + virtual ~nsHashtable(); + + PRInt32 Count(void) { return mHashtable.entryCount; } + PRBool Exists(nsHashKey *aKey); + void *Put(nsHashKey *aKey, void *aData); + void *Get(nsHashKey *aKey); + void *Remove(nsHashKey *aKey); + nsHashtable *Clone(); + void Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure = NULL); + void Reset(); + void Reset(nsHashtableEnumFunc destroyFunc, void* aClosure = NULL); + + nsHashtable(nsIObjectInputStream* aStream, + nsHashtableReadEntryFunc aReadEntryFunc, + nsHashtableFreeEntryFunc aFreeEntryFunc, + nsresult *aRetVal); + nsresult Write(nsIObjectOutputStream* aStream, + nsHashtableWriteDataFunc aWriteDataFunc) const; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be +// deleted + +typedef void* (*PR_CALLBACK nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* aClosure); + +class NS_COM nsObjectHashtable : public nsHashtable { + public: + nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun, + void* cloneElementClosure, + nsHashtableEnumFunc destroyElementFun, + void* destroyElementClosure, + PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE); + ~nsObjectHashtable(); + + nsHashtable *Clone(); + void Reset(); + PRBool RemoveAndDelete(nsHashKey *aKey); + + protected: + static PLDHashOperator PR_CALLBACK CopyElement(PLDHashTable* table, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); + + nsHashtableCloneElementFunc mCloneElementFun; + void* mCloneElementClosure; + nsHashtableEnumFunc mDestroyElementFun; + void* mDestroyElementClosure; +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsSupportsHashtable: an nsHashtable where the elements are nsISupports* + +class nsISupports; + +class NS_COM nsSupportsHashtable + : private nsHashtable +{ + public: + typedef PRBool (* PR_CALLBACK EnumFunc) (nsHashKey *aKey, void *aData, void* aClosure); + + nsSupportsHashtable(PRUint32 aSize = 16, PRBool threadSafe = PR_FALSE) + : nsHashtable(aSize, threadSafe) {} + ~nsSupportsHashtable(); + + PRInt32 Count(void) { + return nsHashtable::Count(); + } + PRBool Exists(nsHashKey *aKey) { + return nsHashtable::Exists (aKey); + } + PRBool Put(nsHashKey *aKey, + nsISupports *aData, + nsISupports **value = nsnull); + nsISupports* Get(nsHashKey *aKey); + PRBool Remove(nsHashKey *aKey, nsISupports **value = nsnull); + nsHashtable *Clone(); + void Enumerate(EnumFunc aEnumFunc, void* aClosure = NULL) { + nsHashtable::Enumerate(aEnumFunc, aClosure); + } + void Reset(); + + private: + static PRBool PR_CALLBACK ReleaseElement(nsHashKey *, void *, void *); + static PLDHashOperator PR_CALLBACK EnumerateCopy(PLDHashTable*, + PLDHashEntryHdr* hdr, + PRUint32 i, void *arg); +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsISupportsKey: Where keys are nsISupports objects that get refcounted. + +#include "nsISupports.h" + +class NS_COM nsISupportsKey : public nsHashKey { + protected: + nsISupports* mKey; + + public: + nsISupportsKey(const nsISupportsKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + NS_IF_ADDREF(mKey); + } + + nsISupportsKey(nsISupports* key) { +#ifdef DEBUG + mKeyType = SupportsKey; +#endif + mKey = key; + NS_IF_ADDREF(mKey); + } + + ~nsISupportsKey(void) { + NS_IF_RELEASE(mKey); + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == SupportsKey, "mismatched key types"); + return (mKey == ((nsISupportsKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsISupportsKey(mKey); + } + + nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + + +class nsPRUint32Key : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsPRUint32Key(PRUint32 key) { +#ifdef DEBUG + mKeyType = PRUint32Key; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return mKey; + } + + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsPRUint32Key *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsPRUint32Key(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsVoidKey: Where keys are void* objects that don't get refcounted. + +class nsVoidKey : public nsHashKey { + protected: + void* mKey; + + public: + nsVoidKey(const nsVoidKey& aKey) : mKey(aKey.mKey) { +#ifdef DEBUG + mKeyType = aKey.mKeyType; +#endif + } + + nsVoidKey(void* key) { +#ifdef DEBUG + mKeyType = VoidKey; +#endif + mKey = key; + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mKey); + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == VoidKey, "mismatched key types"); + return (mKey == ((const nsVoidKey *) aKey)->mKey); + } + + nsHashKey *Clone() const { + return new nsVoidKey(mKey); + } + + void* GetValue() { return mKey; } +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID). + +#include "nsID.h" + +class NS_COM nsIDKey : public nsHashKey { + protected: + nsID mID; + + public: + nsIDKey(const nsIDKey& aKey) : mID(aKey.mID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + } + + nsIDKey(const nsID &aID) { +#ifdef DEBUG + mKeyType = IDKey; +#endif + mID = aID; + } + + PRUint32 HashCode(void) const { + return mID.m0; + } + + PRBool Equals(const nsHashKey *aKey) const { + NS_ASSERTION(aKey->GetKeyType() == IDKey, "mismatched key types"); + return (mID.Equals(((const nsIDKey *) aKey)->mID)); + } + + nsHashKey *Clone() const { + return new nsIDKey(mID); + } + + nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsString.h" + +// for null-terminated c-strings +class NS_COM nsCStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsCStringKey(const nsCStringKey& aStrKey); + nsCStringKey(const char* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsCStringKey(const nsAFlatCString& str); + nsCStringKey(const nsACString& str); + ~nsCStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const char* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + char* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +// for null-terminated unicode strings +class NS_COM nsStringKey : public nsHashKey { + public: + + // NB: when serializing, NEVER_OWN keys are deserialized as OWN. + enum Ownership { + NEVER_OWN, // very long lived, even clones don't need to copy it. + OWN_CLONE, // as long lived as this key. But clones make a copy. + OWN // to be free'd in key dtor. Clones make their own copy. + }; + + nsStringKey(const nsStringKey& aKey); + nsStringKey(const PRUnichar* str, PRInt32 strLen = -1, Ownership own = OWN_CLONE); + nsStringKey(const nsAFlatString& str); + nsStringKey(const nsAString& str); + ~nsStringKey(void); + + PRUint32 HashCode(void) const; + PRBool Equals(const nsHashKey* aKey) const; + nsHashKey* Clone() const; + nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult); + nsresult Write(nsIObjectOutputStream* aStream) const; + + // For when the owner of the hashtable wants to peek at the actual + // string in the key. No copy is made, so be careful. + const PRUnichar* GetString() const { return mStr; } + PRUint32 GetStringLength() const { return mStrLen; } + + protected: + PRUnichar* mStr; + PRUint32 mStrLen; + Ownership mOwnership; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl new file mode 100644 index 00000000..c937ec4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIArray.idl @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM Array interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsISupports.idl" + +interface nsISimpleEnumerator; + +/** + * nsIArray + * + * An indexed collection of elements. Provides basic functionality for + * retrieving elements at a specific position, searching for + * elements. Indexes are zero-based, such that the last element in the + * array is stored at the index length-1. + * + * For an array which can be modified, see nsIMutableArray below. + * + * Neither interface makes any attempt to protect the individual + * elements from modification. The convention is that the elements of + * the array should not be modified. Documentation within a specific + * interface should describe variations from this convention. + * + * It is also convention that if an interface provides access to an + * nsIArray, that the array should not be QueryInterfaced to an + * nsIMutableArray for modification. If the interface in question had + * intended the array to be modified, it would have returned an + * nsIMutableArray! + * + * null is a valid entry in the array, and as such any nsISupports + * parameters may be null, except where noted. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(114744d9-c369-456e-b55a-52fe52880d2d)] +interface nsIArray : nsISupports +{ + /** + * length + * + * number of elements in the array. + */ + readonly attribute unsigned long length; + + /** + * queryElementAt() + * + * Retrieve a specific element of the array, and QueryInterface it + * to the specified interface. null is a valid result for + * this method, but exceptions are thrown in other circumstances + * + * @param index position of element + * @param uuid the IID of the requested interface + * @param result the object, QI'd to the requested interface + * + * @throws NS_ERROR_NO_INTERFACE when an entry exists at the + * specified index, but the requested interface is not + * available. + * @throws NS_ERROR_ILLEGAL_VALUE when index > length-1 + * + */ + void queryElementAt(in unsigned long index, + in nsIIDRef uuid, + [iid_is(uuid), retval] out nsQIResult result); + + /** + * indexOf() + * + * Get the position of a specific element. Note that since null is + * a valid input, exceptions are used to indicate that an element + * is not found. + * + * @param startIndex The initial element to search in the array + * To start at the beginning, use 0 as the + * startIndex + * @param element The element you are looking for + * @returns a number >= startIndex which is the position of the + * element in the array. + * @throws NS_ERROR_NOT_FOUND if the element was not in the array. + */ + unsigned long indexOf(in unsigned long startIndex, + in nsISupports element); + + /** + * enumerate the array + * + * @returns a new enumerator positioned at the start of the array + * @throws NS_ERROR_FAILURE if the array is empty (to make it easy + * to detect errors) + */ + nsISimpleEnumerator enumerate(); + +}; + +/** + * nsIMutableArray + * A separate set of methods that will act on the array. Consumers of + * nsIArray should not QueryInterface to nsIMutableArray unless they + * own the array. + * + * As above, it is legal to add null elements to the array. Note also + * that null elements can be created as a side effect of + * insertElementAt(). Conversely, if insertElementAt() is never used, + * and null elements are never explicitly added to the array, then it + * is guaranteed that queryElementAt() will never return a null value. + * + * Any of these methods may throw NS_ERROR_OUT_OF_MEMORY when the + * array must grow to complete the call, but the allocation fails. + * + * @status UNDER_REVIEW + */ + +[scriptable, uuid(2cd0b2f8-d4dd-48b8-87ba-b0200501f079)] +interface nsIMutableArray : nsIArray +{ + /** + * appendElement() + * + * Append an element at the end of the array. + * + * @param element The element to append. + * @param element Whether or not to store the element using a weak + * reference. + * @throws NS_ERROR_UNEXPECTED when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void appendElement(in nsISupports element, in boolean weak); + + /** + * removeElementAt() + * + * Remove an element at a specific position. + * To remove a specific element, use indexOf() to find the index + * first, then call removeElementAt(). + * + * @param index the position of the item + * + */ + void removeElementAt(in unsigned long index); + + /** + * insertElementAt() + * + * Insert an element at the given position, and move all elements + * stored at a higher position up one. + * + * @param element The element to insert + * @param index The position in the array. If the position is + * greater than or equal to the length of the array + * (@see nsIArray) then the array will grow to + * exactly accomadate the index, and the new length + * will be index+1. The newly created entries will + * be null. + * + * @throws NS_ERROR_FAILURE when a weak reference is requested, + * but the element does not support + * nsIWeakReference. + */ + void insertElementAt(in nsISupports element, in unsigned long index, in boolean weak); + + /** + * clear() + * + * clear the entire array, releasing all stored objects + */ + void clear(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl new file mode 100644 index 00000000..45eecb4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtom.idl @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#include "nsAString.h" +#include "nsCOMPtr.h" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(3d1b15b0-93b4-11d1-895b-006008911b81)] +interface nsIAtom : nsISupports +{ + /** + * Get the Unicode or UTF8 value for the string + */ + AString toString(); + AUTF8String toUTF8String(); + + /** + * Return a pointer to a zero terminated UTF8 string. + */ + [noscript] void getUTF8String([shared, retval] out string aResult); + + /** + * Compare the atom to a specific string value + * Note that this will NEVER return/throw an error condition. + */ + boolean equals(in AString aString); + + boolean equalsUTF8(in AUTF8String aString); + +%{C++ + // note this is NOT virtual so this won't muck with the vtable! + inline PRBool Equals(const nsAString& s) { + PRBool result; + Equals(s, &result); + return result; + } + + inline PRBool EqualsUTF8(const nsACString& s) { + PRBool result; + EqualsUTF8(s, &result); + return result; + } +%} + +}; + + +%{C++ +/* + * The three forms of NS_NewAtom and do_GetAtom (for use with + * |nsCOMPtr|) return the atom for the string given. At any + * given time there will always be one atom representing a given string. + * Atoms are intended to make string comparison cheaper by simplifying + * it to pointer equality. A pointer to the atom that does not own a + * reference is not guaranteed to be valid. + * + * The three forms of NS_NewPermanentAtom and do_GetPermanentAtom return + * the atom for the given string and ensure that the atom is permanent. + * An atom that is permanent will exist (occupy space at a specific + * location in memory) until XPCOM is shut down. The advantage of + * permanent atoms is that they do not need to maintain a reference + * count, which requires locking and hurts performance. + */ + + +/** + * Find an atom that matches the given UTF-8 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const char* aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const char* aUTF8String); + +inline already_AddRefed do_GetAtom(const char* aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed do_GetPermanentAtom(const char* aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-8 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsACString& aUTF8String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsACString& aUTF8String); + +inline already_AddRefed do_GetAtom(const nsACString& aUTF8String) + { return NS_NewAtom(aUTF8String); } +inline already_AddRefed do_GetPermanentAtom(const nsACString& aUTF8String) + { return NS_NewPermanentAtom(aUTF8String); } + +/** + * Find an atom that matches the given UTF-16 string. + * The string is assumed to be zero terminated. + */ +extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const PRUnichar* aUTF16String); + +inline already_AddRefed do_GetAtom(const PRUnichar* aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed do_GetPermanentAtom(const PRUnichar* aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Find an atom that matches the given UTF-16 string. + */ +extern NS_COM nsIAtom* NS_NewAtom(const nsAString& aUTF16String); +extern NS_COM nsIAtom* NS_NewPermanentAtom(const nsAString& aUTF16String); + +inline already_AddRefed do_GetAtom(const nsAString& aUTF16String) + { return NS_NewAtom(aUTF16String); } +inline already_AddRefed do_GetPermanentAtom(const nsAString& aUTF16String) + { return NS_NewPermanentAtom(aUTF16String); } + +/** + * Return a count of the total number of atoms currently + * alive in the system. + */ +extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void); + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl new file mode 100644 index 00000000..b3a30358 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIAtomService.idl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAtom.idl" + +%{C++ +#define NS_ATOMSERVICE_CID \ +{ /* ed3db3fc-0168-4cab-8818-98f5475a490c */ \ + 0xed3db3fc, \ + 0x0168, \ + 0x4cab, \ + {0x88, 0x18, 0x98, 0xf5, 0x47, 0x5a, 0x49, 0x0c} } + +#define NS_ATOMSERVICE_CONTRACTID "@mozilla.org/atom-service;1" +#define NS_ATOMSERVICE_CLASSNAME "Atom Service" +%} + +/* + * Should this really be scriptable? Using atoms from script or proxies + * could be dangerous since double-wrapping could lead to loss of + * pointer identity. + */ + +[scriptable, uuid(e5d0d92b-ea45-4622-ab48-302baf2094ee)] +interface nsIAtomService : nsISupports { + + /** + * Version of NS_NewAtom that doesn't require linking against the + * XPCOM library. See nsIAtom.idl. + */ + nsIAtom getAtom(in wstring value); + + /** + * Version of NS_NewPermanentAtom that doesn't require linking against + * the XPCOM library. See nsIAtom.idl. + */ + nsIAtom getPermanentAtom(in wstring value); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h new file mode 100644 index 00000000..5d02c9cb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIByteBuffer.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIByteBuffer_h___ +#define nsIByteBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +class nsIInputStream; + +#define NS_IBYTE_BUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_IBYTEBUFFER_IID \ +{ 0xe4a6e4b0, 0x93b4, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } +#define NS_BYTEBUFFER_CONTRACTID "@mozilla.org/byte-buffer;1" +#define NS_BYTEBUFFER_CLASSNAME "Byte Buffer" + +/** Interface to a buffer that holds bytes */ +class nsIByteBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFER_IID) + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + + /** @return length of buffer, i.e. how many bytes are currently in it. */ + NS_IMETHOD_(PRUint32) GetLength(void) const = 0; + + /** @return number of bytes allocated in the buffer */ + NS_IMETHOD_(PRUint32) GetBufferSize(void) const = 0; + + /** @return the buffer */ + NS_IMETHOD_(char*) GetBuffer(void) const = 0; + + /** Grow buffer to aNewSize bytes. */ + NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize) = 0; + + /** Fill the buffer with data from aStream. Don't grow the buffer, only + * read until length of buffer equals buffer size. */ + NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream, + PRUint32 aKeep) = 0; +}; + +#define NS_BYTEBUFFER_CID \ +{ /* a49d5280-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xa49d5280, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +/** Create a new byte buffer using the given buffer size. */ +extern NS_COM nsresult +NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#endif /* nsIByteBuffer_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl new file mode 100644 index 00000000..f97bf970 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsICollection.idl @@ -0,0 +1,92 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins : |do_QueryElementAt| + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISerializable.idl" +#include "nsIEnumerator.idl" + +[scriptable, uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsICollection : nsISerializable +{ + + PRUint32 Count(); + nsISupports GetElementAt(in PRUint32 index); + void QueryElementAt(in PRUint32 index, in nsIIDRef uuid, + [iid_is(uuid),retval] out nsQIResult result); + void SetElementAt(in PRUint32 index, in nsISupports item); + void AppendElement(in nsISupports item); + void RemoveElement(in nsISupports item); + + nsIEnumerator Enumerate(); + + void Clear(); + +}; + +%{C++ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +class NS_COM nsQueryElementAt : public nsCOMPtr_helper + { + public: + nsQueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr ) + : mCollection(aCollection), + mIndex(aIndex), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsICollection* mCollection; + PRUint32 mIndex; + nsresult* mErrorPtr; + }; + +inline +const nsQueryElementAt +do_QueryElementAt( nsICollection* aCollection, PRUint32 aIndex, nsresult* aErrorPtr = 0 ) + { + return nsQueryElementAt(aCollection, aIndex, aErrorPtr); + } + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl new file mode 100644 index 00000000..7f8824b2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIEnumerator.idl @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISimpleEnumerator.idl" + +%{C++ +#define NS_ENUMERATOR_FALSE 1 + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewEmptyEnumerator VBoxNsxpNS_NewEmptyEnumerator +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +extern "C" NS_COM nsresult +NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult); +%} +/* + * DO NOT USE THIS INTERFACE. IT IS HORRIBLY BROKEN, USES NS_COMFALSE + * AND IS BASICALLY IMPOSSIBLE TO USE CORRECTLY THROUGH PROXIES OR + * XPCONNECT. IF YOU SEE NEW USES OF THIS INTERFACE IN CODE YOU ARE + * REVIEWING, YOU SHOULD INSIST ON nsISimpleEnumerator. + * + * DON'T MAKE ME COME OVER THERE. + */ +[scriptable, uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)] +interface nsIEnumerator : nsISupports { + /** First will reset the list. will return NS_FAILED if no items + */ + void first(); + + /** Next will advance the list. will return failed if already at end + */ + void next(); + + /** CurrentItem will return the CurrentItem item it will fail if the + * list is empty + */ + nsISupports currentItem(); + + /** return if the collection is at the end. that is the beginning following + * a call to Prev and it is the end of the list following a call to next + */ + void isDone(); +}; + +[uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)] +interface nsIBidirectionalEnumerator : nsIEnumerator { + + /** Last will reset the list to the end. will return NS_FAILED if no items + */ + void last(); + + /** Prev will decrement the list. will return failed if already at beginning + */ + void prev(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl new file mode 100644 index 00000000..ca3c6598 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIHashable.idl @@ -0,0 +1,58 @@ +/* ***** 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 Mozilla XPCOM. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg . + * + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Mozilla Foundation . 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 "nsISupports.idl" + +/** + * Represents an object that can be stored in a hashtable. + */ + +[scriptable, uuid(17e595fa-b57a-4933-bd0f-b1812e8ab188)] +interface nsIHashable : nsISupports +{ + /** + * Is this object the equivalent of the other object? + */ + boolean equals(in nsIHashable aOther); + + /** + * A generated hashcode for this object. Objects that are equivalent + * must have the same hash code. Getting this property should never + * throw an exception! + */ + readonly attribute unsigned long hashCode; +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl new file mode 100644 index 00000000..d2240f2e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserver.idl @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * This interface is implemented by an object that wants + * to observe an event corresponding to a topic. + * + * @status FROZEN + */ + +[scriptable, uuid(DB242E01-E4D9-11d2-9DDE-000064657374)] +interface nsIObserver : nsISupports { + + /** + * Observe will be called when there is a notification for the + * topic |aTopic|. This assumes that the object implementing + * this interface has been registered with an observer service + * such as the nsIObserverService. + * + * If you expect multiple topics/subjects, the impl is + * responsible for filtering. + * + * You should not modify, add, remove, or enumerate + * notifications in the implemention of observe. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param aData : Notification specific wide string. + * subject event. + */ + void observe( in nsISupports aSubject, + in string aTopic, + in wstring aData ); + +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl new file mode 100644 index 00000000..059a903a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIObserverService.idl @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObserver; +interface nsISimpleEnumerator; + +/** + * nsIObserverService + * + * Service allows a client listener (nsIObserver) to register and unregister for + * notifications of specific string referenced topic. Service also provides a + * way to notify registered listeners and a way to enumerate registered client + * listeners. + * + * @status FROZEN + */ + +[scriptable, uuid(D07F5192-E3D1-11d2-8ACD-00105A1B8860)] +interface nsIObserverService : nsISupports +{ + + /** + * AddObserver + * + * Registers a given listener for a notifications regarding the specified + * topic. + * + * @param anObserve : The interface pointer which will receive notifications. + * @param aTopic : The notification topic or subject. + * @param ownsWeak : If set to false, the nsIObserverService will hold a + * strong reference to |anObserver|. If set to true and + * |anObserver| supports the nsIWeakReference interface, + * a weak reference will be held. Otherwise an error will be + * returned. + */ + void addObserver( in nsIObserver anObserver, in string aTopic, in boolean ownsWeak); + + /** + * removeObserver + * + * Unregisters a given listener from notifications regarding the specified + * topic. + * + * @param anObserver : The interface pointer which will stop recieving + * notifications. + * @param aTopic : The notification topic or subject. + */ + void removeObserver( in nsIObserver anObserver, in string aTopic ); + + /** + * notifyObservers + * + * Notifies all registered listeners of the given topic. + * + * @param aSubject : Notification specific interface pointer. + * @param aTopic : The notification topic or subject. + * @param someData : Notification specific wide string. + */ + void notifyObservers( in nsISupports aSubject, + in string aTopic, + in wstring someData ); + + /** + * enumerateObservers + * + * Returns an enumeration of all registered listeners. + * + * @param aTopic : The notification topic or subject. + */ + nsISimpleEnumerator enumerateObservers( in string aTopic ); + + +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h new file mode 100644 index 00000000..773a52ad --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties.h @@ -0,0 +1,8 @@ + +#ifndef __gen_nsIPersistentProperties_h__ +#define __gen_nsIPersistentProperties_h__ + +// "soft" switch over to an IDL generated header file +#include "nsIPersistentProperties2.h" + +#endif /* __gen_nsIPersistentProperties_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl new file mode 100644 index 00000000..3d935621 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPersistentProperties2.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIProperties.idl" +#include "nsISimpleEnumerator.idl" + +interface nsIInputStream; +interface nsIOutputStream; + +[scriptable, uuid(283EE646-1AEF-11D4-98B3-00C04fA0CE9A)] +interface nsIPropertyElement : nsISupports { + attribute AUTF8String key; + attribute AString value; +}; + +[scriptable, uuid(1A180F60-93B2-11d2-9B8B-00805F8A16D9)] +interface nsIPersistentProperties : nsIProperties +{ + /** + * load a set of name/value pairs from the input stream + * names and values should be in UTF8 + */ + void load(in nsIInputStream input); + + /** + * output the values to the stream - results will be in UTF8 + */ + void save(in nsIOutputStream output, in AUTF8String header); + + /** + * call subclass() to make future calls to load() set the properties + * in this "superclass" instead + */ + void subclass(in nsIPersistentProperties superclass); + + /** + * get an enumeration of nsIPropertyElement objects, + * which are read-only (i.e. setting properties on the element will + * not make changes back into the source nsIPersistentProperties + */ + nsISimpleEnumerator enumerate(); + + /** + * shortcut to nsIProperty's get() which retrieves a string value + * directly (and thus faster) + */ + AString getStringProperty(in AUTF8String key); + + /** + * shortcut to nsIProperty's set() which sets a string value + * directly (and thus faster) + */ + AString setStringProperty(in AUTF8String key, in AString value); +}; + + +%{C++ + +//{283EE645-1AEF-11D4-98B3-00C04fA0CE9A} +#define NS_IPROPERTYELEMENT_CID \ +{ 0x283ee645, 0x1aef, 0x11d4, \ + { 0x98, 0xb3, 0x0, 0xc0, 0x4f, 0xa0, 0xce, 0x9a } } + +#define NS_IPERSISTENTPROPERTIES_CID \ +{ 0x2245e573, 0x9464, 0x11d2, \ + { 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } } + +#define NS_PERSISTENTPROPERTIES_CONTRACTID "@mozilla.org/persistent-properties;1" +#define NS_PERSISTENTPROPERTIES_CLASSNAME "Persistent Properties" + +%} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl new file mode 100644 index 00000000..32a2a057 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIProperties.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/* + * Simple mapping service interface. + * @status FROZEN + */ + +[scriptable, uuid(78650582-4e93-4b60-8e85-26ebd3eb14ca)] +interface nsIProperties : nsISupports +{ + /** + * Gets a property with a given name. + * + * @return NS_ERROR_FAILURE if a property with that name doesn't exist. + * @return NS_ERROR_NO_INTERFACE if the found property fails to QI to the + * given iid. + */ + void get(in string prop, in nsIIDRef iid, + [iid_is(iid),retval] out nsQIResult result); + + /** + * Sets a property with a given name to a given value. + */ + void set(in string prop, in nsISupports value); + + /** + * Returns true if the property with the given name exists. + */ + boolean has(in string prop); + + /** + * Undefines a property. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * already exist. + */ + void undefine(in string prop); + + /** + * Returns an array of the keys. + */ + void getKeys(out PRUint32 count, [array, size_is(count), retval] out string keys); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl new file mode 100644 index 00000000..b54577ff --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIPropertyBag.idl @@ -0,0 +1,77 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsIVariant based Property Bag support. */ + +#include "nsISupports.idl" +#include "nsIVariant.idl" +#include "nsISimpleEnumerator.idl" + +[scriptable, uuid(6dcf9030-a49f-11d5-910d-0010a4e73d9a)] +interface nsIProperty : nsISupports +{ + /** + * Get the name of the property. + */ + readonly attribute AString name; + + /** + * Get the value of the property. + */ + readonly attribute nsIVariant value; +}; + +[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)] +interface nsIPropertyBag : nsISupports +{ + /** + * Get a nsISimpleEnumerator whose elements are nsIProperty objects. + */ + readonly attribute nsISimpleEnumerator enumerator; + + /** + * Get a property value for the given name. + * @return NS_ERROR_FAILURE if a property with that name doesn't + * exist. + */ + nsIVariant getProperty(in AString name); +}; + +// We can add nsIWritableProperty and nsIWritablePropertyBag when we need them. + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl new file mode 100644 index 00000000..5402890e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIRecyclingAllocator.idl @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIMemory.idl" + +/** + * + * nsIRecyclingAllocator: A wrapper for the nsRecyclingAllocator + * + * Holds allocations and reuses them for subsequent allocs. + * Thread safe and uses a timer to release freelist. + * + * @status UNDER-DEVELOPMENT + */ + +[scriptable, uuid(d064a04c-9cee-4319-be31-64d565bccba9)] +interface nsIRecyclingAllocator : nsIMemory +{ + void init(in size_t nblocks, in size_t recycleAfter, in string id); +}; + +%{C++ +#define NS_RECYCLINGALLOCATOR_CID \ +{ /* ac07ed4c-bf17-4976-a15c-d2194db3b1bf */ \ + 0xac07ed4c, \ + 0xbf17, \ + 0x4976, \ + {0xa1, 0x5c, 0xd2, 0x19, 0x4d, 0xb3, 0xb1, 0xbf} } + +#define NS_RECYCLINGALLOCATOR_CLASSNAME "Recycling Allocator" + +#define NS_RECYCLINGALLOCATOR_CONTRACTID "@mozilla.org/recycling-allocator;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl new file mode 100644 index 00000000..907c4824 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISerializable.idl @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObjectInputStream; +interface nsIObjectOutputStream; + +[scriptable, uuid(91cca981-c26d-44a8-bebe-d9ed4891503a)] +interface nsISerializable : nsISupports +{ + /** + * Initialize the object implementing nsISerializable, which must have + * been freshly constructed via CreateInstance. All data members that + * can't be set to default values must have been serialized by write, + * and should be read from aInputStream in the same order by this method. + */ + void read(in nsIObjectInputStream aInputStream); + + /** + * Serialize the object implementing nsISerializable to aOutputStream, by + * writing each data member that must be recovered later to reconstitute + * a working replica of this object, in a canonical member and byte order, + * to aOutputStream. + * + * NB: a class that implements nsISerializable *must* also implement + * nsIClassInfo, in particular nsIClassInfo::GetClassID. + */ + void write(in nsIObjectOutputStream aOutputStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl new file mode 100644 index 00000000..3f0efbf5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISimpleEnumerator.idl @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +/** + * Used to enumerate over elements defined by its implementor. + * Although hasMoreElements() can be called independently of getNext(), + * getNext() must be pre-ceeded by a call to hasMoreElements(). There is + * no way to "reset" an enumerator, once you obtain one. + * + * @status FROZEN + * @version 1.0 + */ + +[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)] +interface nsISimpleEnumerator : nsISupports { + /** + * Called to determine whether or not the enumerator has + * any elements that can be returned via getNext(). This method + * is generally used to determine whether or not to initiate or + * continue iteration over the enumerator, though it can be + * called without subsequent getNext() calls. Does not affect + * internal state of enumerator. + * + * @see getNext() + * @return PR_TRUE if there are remaining elements in the enumerator. + * PR_FALSE if there are no more elements in the enumerator. + */ + boolean hasMoreElements(); + + /** + * Called to retrieve the next element in the enumerator. The "next" + * element is the first element upon the first call. Must be + * pre-ceeded by a call to hasMoreElements() which returns PR_TRUE. + * This method is generally called within a loop to iterate over + * the elements in the enumerator. + * + * @see hasMoreElements() + * @return NS_OK if the call succeeded in returning a non-null + * value through the out parameter. + * NS_ERROR_FAILURE if there are no more elements + * to enumerate. + * @return the next element in the enumeration. + */ + nsISupports getNext(); +}; diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl new file mode 100644 index 00000000..a7ac9131 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIStringEnumerator.idl @@ -0,0 +1,58 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsISupports.idl" + +/** + * Used to enumerate over an ordered list of strings. + */ + +[scriptable, uuid(50d3ef6c-9380-4f06-9fb2-95488f7d141c)] +interface nsIStringEnumerator : nsISupports +{ + boolean hasMore(); + AString getNext(); +}; + +[scriptable, uuid(9bdf1010-3695-4907-95ed-83d0410ec307)] +interface nsIUTF8StringEnumerator : nsISupports +{ + boolean hasMore(); + AUTF8String getNext(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl new file mode 100644 index 00000000..bce9f4bf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsArray.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsICollection.idl" + +/* + * This entire interface is deprecated and should not be used. + * See nsIArray and nsIMutableArray for the new implementations. + * + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=3D779491.3050506%40netscape.com&rnum=2 + * http://groups.google.com/groups?q=nsisupportsarray+group:netscape.public.mozilla.xpcom&hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=al8412%245ab2%40ripley.netscape.com&rnum=8 + */ + +native nsISupportsArrayEnumFunc(nsISupportsArrayEnumFunc); + +%{C++ + +class nsIBidirectionalEnumerator; + +#define NS_SUPPORTSARRAY_CID \ +{ /* bda17d50-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xbda17d50, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} +#define NS_SUPPORTSARRAY_CONTRACTID "@mozilla.org/supports-array;1" +#define NS_SUPPORTSARRAY_CLASSNAME "Supports Array" + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (*nsISupportsArrayEnumFunc)(nsISupports* aElement, void *aData); + +%} + +[scriptable, uuid(791eafa0-b9e6-11d1-8031-006008159b5a)] +interface nsISupportsArray : nsICollection { + + [notxpcom] boolean Equals([const] in nsISupportsArray other); + + [notxpcom] nsISupports ElementAt(in unsigned long aIndex); + + [notxpcom] long IndexOf([const] in nsISupports aPossibleElement); + [notxpcom] long IndexOfStartingAt([const] in nsISupports aPossibleElement, + in unsigned long aStartIndex); + [notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement); + + // xpcom-compatible versions + long GetIndexOf(in nsISupports aPossibleElement); + long GetIndexOfStartingAt(in nsISupports aPossibleElement, + in unsigned long aStartIndex); + long GetLastIndexOf(in nsISupports aPossibleElement); + + [notxpcom] boolean InsertElementAt(in nsISupports aElement, + in unsigned long aIndex); + [notxpcom] boolean ReplaceElementAt(in nsISupports aElement, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementAt(in unsigned long aIndex); + [notxpcom] boolean RemoveLastElement([const] in nsISupports aElement); + + // xpcom-compatible versions + void DeleteLastElement(in nsISupports aElement); + void DeleteElementAt(in unsigned long aIndex); + + [notxpcom] boolean AppendElements(in nsISupportsArray aElements); + + void Compact(); + + [notxpcom, noscript] + boolean EnumerateForwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + [notxpcom, noscript] + boolean EnumerateBackwards(in nsISupportsArrayEnumFunc aFunc, + in voidPtr aData); + + nsISupportsArray clone(); + + [notxpcom] boolean MoveElement(in long aFrom, + in long aTo); + + [notxpcom] boolean InsertElementsAt(in nsISupportsArray aOther, + in unsigned long aIndex); + + [notxpcom] boolean RemoveElementsAt(in unsigned long aIndex, + in unsigned long aCount); + + [notxpcom] boolean SizeTo(in long aSize); + +}; + +%{C++ + +// Construct and return a default implementation of nsISupportsArray: +extern NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult); + +// Construct and return a default implementation of an enumerator for nsISupportsArrays: +extern NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult); + + +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl new file mode 100644 index 00000000..f1d8bce1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsIterators.idl @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsISupportsIterators.idl --- IDL defining general purpose iterators */ + + +#include "nsISupports.idl" + + + /* + ... + */ + + + /** + * ... + */ +[scriptable, uuid(7330650e-1dd2-11b2-a0c2-9ff86ee97bed)] +interface nsIOutputIterator : nsISupports + { + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + }; + + /** + * ... + */ +[scriptable, uuid(85585e12-1dd2-11b2-a930-f6929058269a)] +interface nsIInputIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(8da01646-1dd2-11b2-98a7-c7009045be7e)] +interface nsIForwardIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(948defaa-1dd1-11b2-89f6-8ce81f5ebda9)] +interface nsIBidirectionalIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + + /** + * ... + */ +[scriptable, uuid(9bd6fdb0-1dd1-11b2-9101-d15375968230)] +interface nsIRandomAccessIterator : nsISupports + { + /** + * Retrieve (and |AddRef()|) the element this iterator currently points to. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @result a new reference to the element this iterator currently points to (if any) + */ + nsISupports getElement(); + + /** + * Retrieve (and |AddRef()|) an element at some offset from where this iterator currently points. + * The offset may be negative. |getElementAt(0)| is equivalent to |getElement()|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @result a new reference to the indicated element (if any) + */ + nsISupports getElementAt( in PRInt32 anOffset ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElement( in nsISupports anElementToPut ); + + /** + * Put |anElementToPut| into the underlying container or sequence at the position |anOffset| away from that currently pointed to by this iterator. + * The iterator and the underlying container or sequence cooperate to |Release()| + * the replaced element, if any and if necessary, and to |AddRef()| the new element. + * |putElementAt(0, obj)| is equivalent to |putElement(obj)|. + * + * The result is undefined if this iterator currently points outside the + * useful range of the underlying container or sequence. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + * @param anElementToPut the element to place into the underlying container or sequence + */ + void putElementAt( in PRInt32 anOffset, in nsISupports anElementToPut ); + + /** + * Advance this iterator to the next position in the underlying container or sequence. + */ + void stepForward(); + + /** + * Move this iterator by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepForwardBy(1)| is equivalent to |stepForward()|. + * |stepForwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepForwardBy( in PRInt32 anOffset ); + + /** + * Move this iterator to the previous position in the underlying container or sequence. + */ + void stepBackward(); + + /** + * Move this iterator backwards by |anOffset| positions in the underlying container or sequence. + * |anOffset| may be negative. |stepBackwardBy(1)| is equivalent to |stepBackward()|. + * |stepBackwardBy(n)| is equivalent to |stepForwardBy(-n)|. |stepBackwardBy(0)| is a no-op. + * + * @param anOffset a |0|-based offset from the position to which this iterator currently points + */ + void stepBackwardBy( in PRInt32 anOffset ); + + /** + * Test if |anotherIterator| points to the same position in the underlying container or sequence. + * + * The result is undefined if |anotherIterator| was not created by or for the same underlying container or sequence. + * + * @param anotherIterator another iterator to compare against, created by or for the same underlying container or sequence + * @result true if |anotherIterator| points to the same position in the underlying container or sequence + */ + boolean isEqualTo( in nsISupports anotherIterator ); + + /** + * Create a new iterator pointing to the same position in the underlying container or sequence to which this iterator currently points. + * The returned iterator is suitable for use in a subsequent call to |isEqualTo()| against this iterator. + * + * @result a new iterator pointing at the same position in the same underlying container or sequence as this iterator + */ + nsISupports clone(); + }; + +%{C++ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl new file mode 100644 index 00000000..680e5599 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsISupportsPrimitives.idl @@ -0,0 +1,304 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsISupports wrappers for single primitive pieces of data. */ + +#include "nsISupports.idl" + +/** + * Primitive base interface. + * + * These first three are pointer types and do data copying + * using the nsIMemory. Be careful! + * + * @status FROZEN + */ + +[scriptable, uuid(d0d4b136-1dd1-11b2-9371-f0727ef827c0)] +interface nsISupportsPrimitive : nsISupports +{ + const unsigned short TYPE_ID = 1; + const unsigned short TYPE_CSTRING = 2; + const unsigned short TYPE_STRING = 3; + const unsigned short TYPE_PRBOOL = 4; + const unsigned short TYPE_PRUINT8 = 5; + const unsigned short TYPE_PRUINT16 = 6; + const unsigned short TYPE_PRUINT32 = 7; + const unsigned short TYPE_PRUINT64 = 8; + const unsigned short TYPE_PRTIME = 9; + const unsigned short TYPE_CHAR = 10; + const unsigned short TYPE_PRINT16 = 11; + const unsigned short TYPE_PRINT32 = 12; + const unsigned short TYPE_PRINT64 = 13; + const unsigned short TYPE_FLOAT = 14; + const unsigned short TYPE_DOUBLE = 15; + const unsigned short TYPE_VOID = 16; + const unsigned short TYPE_INTERFACE_POINTER = 17; + + readonly attribute unsigned short type; +}; + +/** + * Scriptable storage for nsID structures + * + * @status FROZEN + */ + +[scriptable, uuid(d18290a0-4a1c-11d3-9890-006008962422)] +interface nsISupportsID : nsISupportsPrimitive +{ + attribute nsIDPtr data; + string toString(); +}; + +/** + * Scriptable storage for ASCII strings + * + * @status FROZEN + */ + +[scriptable, uuid(d65ff270-4a1c-11d3-9890-006008962422)] +interface nsISupportsCString : nsISupportsPrimitive +{ + attribute ACString data; + string toString(); +}; + +/** + * Scriptable storage for Unicode strings + * + * @status FROZEN + */ + +[scriptable, uuid(d79dc970-4a1c-11d3-9890-006008962422)] +interface nsISupportsString : nsISupportsPrimitive +{ + attribute AString data; + wstring toString(); +}; + +/** + * The rest are truly primitive and are passed by value + */ + +/** + * Scriptable storage for booleans + * + * @status FROZEN + */ + +[scriptable, uuid(ddc3b490-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRBool : nsISupportsPrimitive +{ + attribute PRBool data; + string toString(); +}; + +/** + * Scriptable storage for 8-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dec2e4e0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint8 : nsISupportsPrimitive +{ + attribute PRUint8 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(dfacb090-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint16 : nsISupportsPrimitive +{ + attribute PRUint16 data; + string toString(); +}; + +/** + * Scriptable storage for unsigned 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e01dc470-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint32 : nsISupportsPrimitive +{ + attribute PRUint32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e13567c0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRUint64 : nsISupportsPrimitive +{ + attribute PRUint64 data; + string toString(); +}; + +/** + * Scriptable storage for NSPR date/time values + * + * @status FROZEN + */ + +[scriptable, uuid(e2563630-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRTime : nsISupportsPrimitive +{ + attribute PRTime data; + string toString(); +}; + +/** + * Scriptable storage for single character values + * (often used to store an ASCII character) + * + * @status FROZEN + */ + +[scriptable, uuid(e2b05e40-4a1c-11d3-9890-006008962422)] +interface nsISupportsChar : nsISupportsPrimitive +{ + attribute char data; + string toString(); +}; + +/** + * Scriptable storage for 16-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e30d94b0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt16 : nsISupportsPrimitive +{ + attribute PRInt16 data; + string toString(); +}; + +/** + * Scriptable storage for 32-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e36c5250-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt32 : nsISupportsPrimitive +{ + attribute PRInt32 data; + string toString(); +}; + +/** + * Scriptable storage for 64-bit integers + * + * @status FROZEN + */ + +[scriptable, uuid(e3cb0ff0-4a1c-11d3-9890-006008962422)] +interface nsISupportsPRInt64 : nsISupportsPrimitive +{ + attribute PRInt64 data; + string toString(); +}; + +/** + * Scriptable storage for floating point numbers + * + * @status FROZEN + */ + +[scriptable, uuid(abeaa390-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsFloat : nsISupportsPrimitive +{ + attribute float data; + string toString(); +}; + +/** + * Scriptable storage for doubles + * + * @status FROZEN + */ + +[scriptable, uuid(b32523a0-4ac0-11d3-baea-00805f8a5dd7)] +interface nsISupportsDouble : nsISupportsPrimitive +{ + attribute double data; + string toString(); +}; + +/** + * Scriptable storage for generic pointers + * + * @status FROZEN + */ + +[scriptable, uuid(464484f0-568d-11d3-baf8-00805f8a5dd7)] +interface nsISupportsVoid : nsISupportsPrimitive +{ + [noscript] attribute voidPtr data; + string toString(); +}; + +/** + * Scriptable storage for other XPCOM objects + * + * @status FROZEN + */ + +[scriptable, uuid(995ea724-1dd1-11b2-9211-c21bdd3e7ed0)] +interface nsISupportsInterfacePointer : nsISupportsPrimitive +{ + attribute nsISupports data; + attribute nsIDPtr dataIID; + + string toString(); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl new file mode 100644 index 00000000..f0495a35 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsITimelineService.idl @@ -0,0 +1,242 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#ifdef MOZ_TIMELINE +%} + +/** + * nsITimelineService is used to constuct a timeline of program + * execution. The timeline is output to a file, either stderr or the + * value of the environment variable NS_TIMELINE_LOG_FILE. On the + * Mac, the timeline is output to the file named "timeline.txt". The + * reason it's different on the Mac is that the Mac environment + * initialization code happens after timeline initialization code. + * + * If NS_TIMELINE_INIT_TIME is set in the environment, that will be + * used as the time of startup; otherwise the current time when mark() + * is first called will be used. + * + * mark() is used to put marks on the timeline. + * + * indent() and outdent() are used to format the timeline a bit to + * show nesting. This doesn't produce perfect results in the face of + * asychrony and multiple threads. + * + * enter() and leave() are convenience functions that add marks to the + * timeline and do indentation. + * + * startTimer() and stopTimer() control named stop watches. If + * startTimer() is called more than once, an equal number of + * stopTimer() calls are needed to actually stop the timer. This + * makes these timers slightly useful in a threaded environment. + * + * markTimer() puts a mark on the timeline containing the total for + * the named timer. + * + * Don't use nsITimelineService in C++ code; use the NS_TIMELINE + * macros instead. nsITimelineService exists so that JavaScript code + * can mark the timeline. + */ +[scriptable, uuid(93276790-3daf-11d5-b67d-000064657374)] +interface nsITimelineService : nsISupports +{ + /** + * mark() + * Print ": \n" in the timeline log file. + */ + void mark(in string text); + + /** + * causes subsequent marks to be indented for a more readable + * report. + */ + void indent(); + + /** + * Causes subsequent marks to be outdented. + */ + void outdent(); + + /** + * enter/leave bracket code with "..." and "..." as + * well as indentation. + */ + void enter(in string text); + void leave(in string text); + + void startTimer(in string timerName); + + void stopTimer(in string timerName); + + void markTimer(in string timerName); + + void resetTimer(in string timerName); + + // Mark a timer, plus an additional comment + void markTimerWithComment(in string timerName, in string comment); +}; + +%{C++ +#endif /* MOZ_TIMELINE */ +%} + + +%{C++ + +#ifdef MOZ_TIMELINE + +/* + * These are equivalent to the corresponding nsITimelineService + * methods, and can be called before XPCOM is initialized. + */ +extern "C" NS_COM nsresult NS_TimelineMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineForceMark(const char *text, ...); +extern "C" NS_COM nsresult NS_TimelineStartTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineStopTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineResetTimer(const char *timerName); +extern "C" NS_COM nsresult NS_TimelineMarkTimer(const char *timerName, const char *str=nsnull); +extern "C" NS_COM nsresult NS_TimelineIndent(); +extern "C" NS_COM nsresult NS_TimelineOutdent(); +extern "C" NS_COM nsresult NS_TimelineEnter(const char *text); +extern "C" NS_COM nsresult NS_TimelineLeave(const char *text); + +/* + * Use these macros for the above calls so we can easily compile them + * out. + */ +#define NS_TIMELINE_MARK(text) NS_TimelineMark(text) +#define NS_TIMELINE_MARKV(args) NS_TimelineMark args +#define NS_TIMELINE_INDENT() NS_TimelineIndent() +#define NS_TIMELINE_OUTDENT() NS_TimelineOutdent() +#define NS_TIMELINE_ENTER(text) NS_TimelineEnter(text) +#define NS_TIMELINE_LEAVE(text) NS_TimelineLeave(text) +#define NS_TIMELINE_START_TIMER(timerName) NS_TimelineStartTimer(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) NS_TimelineStopTimer(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) NS_TimelineMarkTimer(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) NS_TimelineResetTimer(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) NS_TimelineMarkTimer(timerName, str) + +/* + * Helper class to time functions. Use only static strings. + */ +class nsFunctionTimer { +public: + const char *mTimer; + PRBool mMark; + const char *mMarkStr; + nsFunctionTimer(const char *timer, PRBool mark = PR_TRUE, const char *markStr = nsnull) + : mTimer(timer), mMark(mark), mMarkStr(markStr) + { + NS_TIMELINE_START_TIMER(mTimer); + } + + ~nsFunctionTimer() + { + NS_TIMELINE_STOP_TIMER(mTimer); + if (mMark) + if (mMarkStr) + NS_TIMELINE_MARK_TIMER1(mTimer, mMarkStr); + else + NS_TIMELINE_MARK_TIMER(mTimer); + } +}; + +/* + * NS_TIMELINE_MARK_ macros for various data types. Each of these + * macros replaces "%s" in its "text" argument with a string + * representation of its last argument. + * + * Please feel free to add more NS_TIMELINE_MARK_ macros for + * various data types so that code using NS_TIMELINE is uncluttered. + * Don't forget the empty versions in the #else section below for + * non-timeline builds. + */ +#define NS_TIMELINE_MARK_URI(text, uri) \ + { \ + nsCAutoString spec; \ + if (uri) { \ + uri->GetSpec(spec); \ + } \ + if (!spec.IsEmpty()) { \ + NS_TimelineMark(text, spec.get()); \ + } else { \ + NS_TimelineMark(text, "??"); \ + } \ + } + +#define NS_TIMELINE_MARK_CHANNEL(text, channel) \ + { \ + nsCOMPtr uri; \ + if (channel) { \ + channel->GetURI(getter_AddRefs(uri)); \ + } \ + NS_TIMELINE_MARK_URI(text, uri); \ + } + +#define NS_TIMELINE_MARK_LOADER(text, loader) \ + { \ + nsCOMPtr request; \ + loader->GetRequest(getter_AddRefs(request)); \ + nsCOMPtr channel(do_QueryInterface(request)); \ + NS_TIMELINE_MARK_CHANNEL(text, channel); \ + } +#define NS_TIMELINE_MARK_FUNCTION(timer) nsFunctionTimer functionTimer(timer) +#define NS_TIMELINE_MARK_FUNCTION1(timer, str) nsFunctionTimer functionTimer(timer, PR_TRUE, str) +#define NS_TIMELINE_TIME_FUNCTION(timer) nsFunctionTimer functionTimer(timer, PR_FALSE) /* no mark, only time */ + +#else /* !defined(MOZ_TIMELINE) */ +#define NS_TIMELINE_MARK(text) +#define NS_TIMELINE_MARKV(args) +#define NS_TIMELINE_INDENT() +#define NS_TIMELINE_OUTDENT() +#define NS_TIMELINE_START_TIMER(timerName) +#define NS_TIMELINE_STOP_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER(timerName) +#define NS_TIMELINE_RESET_TIMER(timerName) +#define NS_TIMELINE_MARK_TIMER1(timerName, str) +#define NS_TIMELINE_ENTER(text) +#define NS_TIMELINE_LEAVE(text) +#define NS_TIMELINE_MARK_URI(text, uri) +#define NS_TIMELINE_MARK_FUNCTION(timer) +#define NS_TIMELINE_TIME_FUNCTION(timer) +#define NS_TIMELINE_MARK_CHANNEL(text, channel) +#define NS_TIMELINE_MARK_LOADER(text, loader); +#endif /* defined(MOZ_TIMELINE) */ +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h new file mode 100644 index 00000000..dae89021 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIUnicharBuffer.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIUnicharBuffer_h___ +#define nsIUnicharBuffer_h___ + +#include "nscore.h" +#include "nsISupports.h" + +#define NS_IUNICHARBUFFER_IID \ +{ 0x14cf6970, 0x93b5, 0x11d1, \ + {0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} } + +/// Interface to a buffer that holds unicode characters +class nsIUnicharBuffer : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHARBUFFER_IID); + + NS_IMETHOD Init(PRUint32 aBufferSize) = 0; + NS_IMETHOD_(PRInt32) GetLength() const = 0; + NS_IMETHOD_(PRInt32) GetBufferSize() const = 0; + NS_IMETHOD_(PRUnichar*) GetBuffer() const = 0; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize) = 0; +}; + +/// Factory method for nsIUnicharBuffer. +extern NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize = 0); + +#define NS_UNICHARBUFFER_CID \ +{ /* c81fd8f0-0d6b-11d3-9331-00104ba0fd40 */ \ + 0xc81fd8f0, \ + 0x0d6b, \ + 0x11d3, \ + {0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +#endif /* nsIUnicharBuffer_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl new file mode 100644 index 00000000..2c9d9e96 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsIVariant.idl @@ -0,0 +1,188 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsISupports.idl" + +[scriptable,uuid(4d12e540-83d7-11d5-90ed-0010a4e73d9a)] +interface nsIDataType : nsISupports +{ + // These MUST match the declarations in xpt_struct.h. + // Otherwise the world is likely to explode. + // From xpt_struct.h ... + const PRUint16 VTYPE_INT8 = 0; // TD_INT8 = 0, + const PRUint16 VTYPE_INT16 = 1; // TD_INT16 = 1, + const PRUint16 VTYPE_INT32 = 2; // TD_INT32 = 2, + const PRUint16 VTYPE_INT64 = 3; // TD_INT64 = 3, + const PRUint16 VTYPE_UINT8 = 4; // TD_UINT8 = 4, + const PRUint16 VTYPE_UINT16 = 5; // TD_UINT16 = 5, + const PRUint16 VTYPE_UINT32 = 6; // TD_UINT32 = 6, + const PRUint16 VTYPE_UINT64 = 7; // TD_UINT64 = 7, + const PRUint16 VTYPE_FLOAT = 8; // TD_FLOAT = 8, + const PRUint16 VTYPE_DOUBLE = 9; // TD_DOUBLE = 9, + const PRUint16 VTYPE_BOOL = 10; // TD_BOOL = 10, + const PRUint16 VTYPE_CHAR = 11; // TD_CHAR = 11, + const PRUint16 VTYPE_WCHAR = 12; // TD_WCHAR = 12, + const PRUint16 VTYPE_VOID = 13; // TD_VOID = 13, + const PRUint16 VTYPE_ID = 14; // TD_PNSIID = 14, + const PRUint16 VTYPE_DOMSTRING = 15; // TD_DOMSTRING = 15, + const PRUint16 VTYPE_CHAR_STR = 16; // TD_PSTRING = 16, + const PRUint16 VTYPE_WCHAR_STR = 17; // TD_PWSTRING = 17, + const PRUint16 VTYPE_INTERFACE = 18; // TD_INTERFACE_TYPE = 18, + const PRUint16 VTYPE_INTERFACE_IS = 19; // TD_INTERFACE_IS_TYPE = 19, + const PRUint16 VTYPE_ARRAY = 20; // TD_ARRAY = 20, + const PRUint16 VTYPE_STRING_SIZE_IS = 21; // TD_PSTRING_SIZE_IS = 21, + const PRUint16 VTYPE_WSTRING_SIZE_IS = 22; // TD_PWSTRING_SIZE_IS = 22, + const PRUint16 VTYPE_UTF8STRING = 23; // TD_UTF8STRING = 23, + const PRUint16 VTYPE_CSTRING = 24; // TD_CSTRING = 24, + const PRUint16 VTYPE_ASTRING = 25; // TD_ASTRING = 25, + const PRUint16 VTYPE_EMPTY_ARRAY = 254; + const PRUint16 VTYPE_EMPTY = 255; +}; + + +/** + * XPConnect has magic to transparently convert between nsIVariant and JS types. + * We mark the interface [scriptable] so that JS can use methods + * that refer to this interface. But we mark all the methods and attributes + * [noscript] since any nsIVariant object will be automatically converted to a + * JS type anyway. + */ + +[scriptable, uuid(6c9eb060-8c6a-11d5-90f3-0010a4e73d9a)] +interface nsIVariant : nsISupports +{ + [noscript] readonly attribute PRUint16 dataType; + + [noscript] PRUint8 getAsInt8(); + [noscript] PRInt16 getAsInt16(); + [noscript] PRInt32 getAsInt32(); + [noscript] PRInt64 getAsInt64(); + [noscript] PRUint8 getAsUint8(); + [noscript] PRUint16 getAsUint16(); + [noscript] PRUint32 getAsUint32(); + [noscript] PRUint64 getAsUint64(); + [noscript] float getAsFloat(); + [noscript] double getAsDouble(); + [noscript] PRBool getAsBool(); + [noscript] char getAsChar(); + [noscript] wchar getAsWChar(); + [notxpcom] nsresult getAsID(out nsID retval); + [noscript] AString getAsAString(); + [noscript] DOMString getAsDOMString(); + [noscript] ACString getAsACString(); + [noscript] AUTF8String getAsAUTF8String(); + [noscript] string getAsString(); + [noscript] wstring getAsWString(); + [noscript] nsISupports getAsISupports(); + + [noscript] void getAsInterface(out nsIIDPtr iid, + [iid_is(iid), retval] out nsQIResult iface); + + [notxpcom] nsresult getAsArray(out PRUint16 type, out nsIID iid, + out PRUint32 count, out voidPtr ptr); + + [noscript] void getAsStringWithSize(out PRUint32 size, + [size_is(size), retval] out string str); + + [noscript] void getAsWStringWithSize(out PRUint32 size, + [size_is(size), retval] out wstring str); +}; + +/** + * An object that implements nsIVariant may or may NOT also implement this + * nsIWritableVariant. + * + * If the 'writable' attribute is false then attempts to call any of the 'set' + * methods can be expected to fail. Setting the 'writable' attribute may or + * may not succeed. + * + */ + +[scriptable, uuid(5586a590-8c82-11d5-90f3-0010a4e73d9a)] +interface nsIWritableVariant : nsIVariant +{ + attribute PRBool writable; + + void setAsInt8(in PRUint8 aValue); + void setAsInt16(in PRInt16 aValue); + void setAsInt32(in PRInt32 aValue); + void setAsInt64(in PRInt64 aValue); + void setAsUint8(in PRUint8 aValue); + void setAsUint16(in PRUint16 aValue); + void setAsUint32(in PRUint32 aValue); + void setAsUint64(in PRUint64 aValue); + void setAsFloat(in float aValue); + void setAsDouble(in double aValue); + void setAsBool(in PRBool aValue); + void setAsChar(in char aValue); + void setAsWChar(in wchar aValue); + void setAsID(in nsIDRef aValue); + void setAsAString(in AString aValue); + void setAsDOMString(in DOMString aValue); + void setAsACString(in ACString aValue); + void setAsAUTF8String(in AUTF8String aValue); + void setAsString(in string aValue); + void setAsWString(in wstring aValue); + void setAsISupports(in nsISupports aValue); + + void setAsInterface(in nsIIDRef iid, + [iid_is(iid)] in nsQIResult iface); + + [noscript] void setAsArray(in PRUint16 type, in nsIIDPtr iid, + in PRUint32 count, in voidPtr ptr); + + void setAsStringWithSize(in PRUint32 size, + [size_is(size)] in string str); + + void setAsWStringWithSize(in PRUint32 size, + [size_is(size)] in wstring str); + + void setAsVoid(); + void setAsEmpty(); + void setAsEmptyArray(); + + void setFromVariant(in nsIVariant aValue); +}; + +%{C++ +// The contractID for the generic implementation built in to xpcom. +#define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" +%} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInt64.h b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h new file mode 100644 index 00000000..c7421548 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInt64.h @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsInt64_h__ +#define nsInt64_h__ + +#include "prlong.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit integer functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsInt64". + +template +class nsTInt64 +{ +public: //XXX should be private + T mValue; + +public: + /** + * Construct a new 64-bit integer. + */ + nsTInt64(void) : mValue(LL_ZERO) { + } + + /** + * Construct a new 64-bit integer from a 32-bit signed integer + */ + nsTInt64(const PRInt32 aInt32) { + LL_I2L(mValue, aInt32); + } + + /** + * Construct a new 64-bit integer from a 32-bit unsigned integer + */ + nsTInt64(const PRUint32 aUint32) { + LL_UI2L(mValue, aUint32); + } + + /** + * Construct a new 64-bit integer from a floating point value. + */ + nsTInt64(const PRFloat64 aFloat64) { + LL_D2L(mValue, aFloat64); + } + + /** + * Construct a new 64-bit integer from a native 64-bit integer + */ + nsTInt64(const T aInt64) : mValue(aInt64) { + } + + /** + * Construct a new 64-bit integer from another 64-bit integer + */ + nsTInt64(const nsTInt64& aObject) : mValue(aObject.mValue) { + } + + // ~nsTInt64(void) -- XXX destructor unnecessary + + /** + * Assign a 64-bit integer to another 64-bit integer + */ + const nsTInt64& operator =(const nsTInt64& aObject) { + mValue = aObject.mValue; + return *this; + } + + /** + * Convert a 64-bit integer to a signed 32-bit value + */ + operator PRInt32(void) const { + PRInt32 result; + LL_L2I(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to an unsigned 32-bit value + */ + operator PRUint32(void) const { + PRUint32 result; + LL_L2UI(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a floating point value + */ + operator PRFloat64(void) const { + PRFloat64 result; + LL_L2D(result, mValue); + return result; + } + + /** + * Convert a 64-bit integer to a native 64-bit integer. + */ + operator T() const { + return mValue; + } + + /** + * Perform unary negation on a 64-bit integer. + */ + const nsTInt64 operator -(void) { + nsTInt64 result; + LL_NEG(result.mValue, mValue); + return result; + } + + // Arithmetic operators + + /** + * Increment a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator +=(const nsTInt64& aObject) { + LL_ADD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Decrement a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator -=(const nsTInt64& aObject) { + LL_SUB(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Multiply a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator *=(const nsTInt64& aObject) { + LL_MUL(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Divide a 64-bit integer by a 64-bit integer amount. + */ + nsTInt64& operator /=(const nsTInt64& aObject) { + LL_DIV(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the modulus of a 64-bit integer to a 64-bit value. + */ + nsTInt64& operator %=(const nsTInt64& aObject) { + LL_MOD(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Shift a 64-bit integer left. + */ + nsTInt64& operator <<=(int aCount) { + LL_SHL(mValue, mValue, aCount); + return *this; + } + + /** + * Shift a 64-bit signed integer right. + */ + nsTInt64& operator >>=(int aCount) { + LL_SHR(mValue, mValue, aCount); + return *this; + } + + // Comparison operators + /** + * Add two 64-bit integers. + */ + inline const nsTInt64 + operator +(const nsTInt64& aObject2) const { + return nsTInt64(*this) += aObject2; + } + + /** + * Subtract one 64-bit integer from another. + */ + inline const nsTInt64 + operator -(const nsTInt64& aObject2) const { + return nsTInt64(*this) -= aObject2; + } + + /** + * Multiply two 64-bit integers + */ + inline const nsTInt64 + operator *(const nsTInt64& aObject2) const { + return nsTInt64(*this) *= aObject2; + } + + /** + * Divide one 64-bit integer by another + */ + inline const nsTInt64 + operator /(const nsTInt64& aObject2) const { + return nsTInt64(*this) /= aObject2; + } + + /** + * Compute the modulus of two 64-bit integers + */ + inline const nsTInt64 + operator %(const nsTInt64& aObject2) const { + return nsTInt64(*this) %= aObject2; + } + + /** + * Shift left a 64-bit integer + */ + inline const nsTInt64 + operator <<(int aCount) const { + return nsTInt64(*this) <<= aCount; + } + + /** + * Shift right a signed 64-bit integer + */ + inline const nsTInt64 + operator >>(int aCount) const { + return nsTInt64(*this) >>= aCount; + } + + /** + * Determine if two 64-bit integers are equal + */ + inline PRBool + operator ==(const nsTInt64& aObject2) const { + return LL_EQ(mValue, aObject2.mValue); + } + + /** + * Determine if two 64-bit integers are not equal + */ + inline PRBool + operator !=(const nsTInt64& aObject2) const { + return LL_NE(mValue, aObject2.mValue); + } + + + /** + * Perform a bitwise AND of two 64-bit integers + */ + inline const nsTInt64 + operator &(const nsTInt64& aObject2) const { + return nsTInt64(*this) &= aObject2; + } + + /** + * Perform a bitwise OR of two 64-bit integers + */ + inline const nsTInt64 + operator |(const nsTInt64& aObject2) const { + return nsTInt64(*this) |= aObject2; + } + + /** + * Perform a bitwise XOR of two 64-bit integers + */ + inline const nsTInt64 + operator ^(const nsTInt64& aObject2) const { + return nsTInt64(*this) ^= aObject2; + } + + // Bitwise operators + + /** + * Compute the bitwise NOT of a 64-bit integer + */ + const nsTInt64 operator ~(void) const { + nsTInt64 result; + LL_NOT(result.mValue, mValue); + return result; + } + + /** + * Compute the bitwise AND with another 64-bit integer + */ + nsTInt64& operator &=(const nsTInt64& aObject) { + LL_AND(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise OR with another 64-bit integer + */ + nsTInt64& operator |=(const nsTInt64& aObject) { + LL_OR(mValue, mValue, aObject.mValue); + return *this; + } + + /** + * Compute the bitwise XOR with another 64-bit integer + */ + nsTInt64& operator ^=(const nsTInt64& aObject) { + LL_XOR(mValue, mValue, aObject.mValue); + return *this; + } +}; + +typedef nsTInt64 nsInt64; +typedef nsTInt64 nsUint64; + +/** + * Determine if one 64-bit integer is strictly greater than another, using signed values + */ +inline PRBool +operator >(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator >(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is greater than or equal to another, using signed values + */ +inline PRBool +operator >=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator >=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integer is strictly less than another, using signed values + */ +inline PRBool +operator <(const nsInt64& aObject1, const nsInt64& aObject2) { + return LL_CMP(aObject1.mValue, <, aObject2.mValue); +} + +inline PRBool +operator <(const nsUint64& aObject1, const nsUint64& aObject2) { + return LL_UCMP(aObject1.mValue, <, aObject2.mValue); +} + +/** + * Determine if one 64-bit integers is less than or equal to another, using signed values + */ +inline PRBool +operator <=(const nsInt64& aObject1, const nsInt64& aObject2) { + return ! LL_CMP(aObject1.mValue, >, aObject2.mValue); +} + +inline PRBool +operator <=(const nsUint64& aObject1, const nsUint64& aObject2) { + return ! LL_UCMP(aObject1.mValue, >, aObject2.mValue); +} + +#endif // nsInt64_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h new file mode 100644 index 00000000..68b06d66 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsInterfaceHashtable.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsInterfaceHashtable_h__ +#define nsInterfaceHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsCOMPtr.h" + +/** + * templated hashtable class maps keys to interface pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template +class nsInterfaceHashtable : + public nsBaseHashtable< KeyClass, nsCOMPtr , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + Interface* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsInterfaceHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param Interface the interface-type being wrapped + */ +template +class nsInterfaceHashtableMT : + public nsBaseHashtableMT< KeyClass, nsCOMPtr , Interface* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef Interface* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsInterfaceHashtable definitions +// + +template +PRBool +nsInterfaceHashtable::Get + (KeyType aKey, UserDataType* pInterface) const +{ + typename nsBaseHashtable, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + return PR_FALSE; +} + +template +Interface* +nsInterfaceHashtable::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsInterfaceHashtableMT definitions +// + +template +PRBool +nsInterfaceHashtableMT::Get + (KeyType aKey, UserDataType* pInterface) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT, Interface*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pInterface) + { + *pInterface = ent->mData; + + NS_IF_ADDREF(*pInterface); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pInterface to null + // so that it is a valid XPCOM getter + if (pInterface) + *pInterface = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsInterfaceHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h new file mode 100644 index 00000000..761c28c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsManifestLineReader.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsManifestLineReader_h__ +#define nsManifestLineReader_h__ + +#include "nspr.h" +#include "nsDebug.h" + +class nsManifestLineReader +{ +public: + nsManifestLineReader() : mBase(nsnull) {} + ~nsManifestLineReader() {} + + void Init(char* base, PRUint32 flen) + { + mBase = mCur = mNext = base; + mLength = 0; + mLimit = base + flen; + } + + PRBool NextLine() + { + if(mNext >= mLimit) + return PR_FALSE; + + mCur = mNext; + mLength = 0; + + while(mNext < mLimit) + { + if(IsEOL(*mNext)) + { + *mNext = '\0'; + for(++mNext; mNext < mLimit; ++mNext) + if(!IsEOL(*mNext)) + break; + return PR_TRUE; + } + ++mNext; + ++mLength; + } + return PR_FALSE; + } + + int ParseLine(char** chunks, int* lengths, int maxChunks) + { + NS_ASSERTION(mCur && maxChunks && chunks, "bad call to ParseLine"); + int found = 0; + chunks[found++] = mCur; + + if(found < maxChunks) + { + char *lastchunk = mCur; + int *lastlength = lengths; + for(char* cur = mCur; *cur; cur++) + { + if(*cur == ',') + { + *cur = 0; + // always fill in the previous chunk's length + *lastlength++ = cur - lastchunk; + chunks[found++] = lastchunk = cur+1; + if(found == maxChunks) + break; + } + } + // crazy pointer math - calculate the length of the final chunk + *lastlength = (mCur + mLength) - lastchunk; + } + return found; + } + + char* LinePtr() {return mCur;} + PRUint32 LineLength() {return mLength;} + + PRBool IsEOL(char c) {return c == '\n' || c == '\r';} +private: + char* mCur; + PRUint32 mLength; + char* mNext; + char* mBase; + char* mLimit; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp new file mode 100644 index 00000000..51fb04b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.cpp @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#define NS_WEAK_OBSERVERS + +#include "pratom.h" +#include "nsString.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsIWeakReference.h" +#include "nsEnumeratorUtils.h" +#include "nsObserverList.h" + +nsObserverList::nsObserverList() +{ + MOZ_COUNT_CTOR(nsObserverList); + mLock = PR_NewLock(); +} + +nsObserverList::~nsObserverList(void) +{ + MOZ_COUNT_DTOR(nsObserverList); + PR_DestroyLock(mLock); +} + +nsresult +nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak) +{ + nsresult rv; + PRBool inserted; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) { + rv = NS_NewISupportsArray(getter_AddRefs(mObserverList)); + if (NS_FAILED(rv)) return rv; + } + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr observerRef; + if (ownsWeak) { + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(weakRefFactory, "AddObserver: trying weak object that doesnt support nsIWeakReference"); + if ( weakRefFactory ) + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + } else { +#if DEBUG_dougt_xxx + // if you are hitting this assertion, contact dougt@netscape.com. There may be a ownership problem caused by his checkin to freeze nsIObserver + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + NS_ASSERTION(!weakRefFactory, "Your object supports weak references, but is being added with a strong reference"); +#endif + observerRef = anObserver; + } + if (!observerRef) + return NS_ERROR_FAILURE; + + inserted = mObserverList->AppendElement(observerRef); +#else + if (*anObserver) + inserted = mObserverList->AppendElement(*anObserver); +#endif + return inserted ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::RemoveObserver(nsIObserver* anObserver) +{ + PRBool removed = PR_FALSE; + + NS_ENSURE_ARG(anObserver); + + nsAutoLock lock(mLock); + + if (!mObserverList) + return NS_ERROR_FAILURE; + +#ifdef NS_WEAK_OBSERVERS + nsCOMPtr weakRefFactory = do_QueryInterface(anObserver); + nsCOMPtr observerRef; + if (weakRefFactory) { + observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + if (observerRef) + removed = mObserverList->RemoveElement(observerRef); + if (!removed) + observerRef = anObserver; + } else + observerRef = anObserver; + + if (!removed && observerRef) + removed = mObserverList->RemoveElement(observerRef); +#else + if (*anObserver) + removed = mObserverList->RemoveElement(*anObserver); +#endif + return removed ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult +nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator) +{ + nsAutoLock lock(mLock); + + ObserverListEnumerator * enumerator= new ObserverListEnumerator(mObserverList); + *anEnumerator = enumerator; + if (!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(enumerator); + return NS_OK; +} + + +ObserverListEnumerator::ObserverListEnumerator(nsISupportsArray* aValueArray) + : mValueArray(aValueArray), mIndex(0) +{ + if (mValueArray) { + NS_ADDREF(mValueArray); + PRUint32 total; + mValueArray->Count(&total); + mIndex = PRInt32(total); + } +} + +ObserverListEnumerator::~ObserverListEnumerator(void) +{ + NS_IF_RELEASE(mValueArray); +} + +NS_IMPL_ISUPPORTS1(ObserverListEnumerator, nsISimpleEnumerator) + +NS_IMETHODIMP +ObserverListEnumerator::HasMoreElements(PRBool* aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = PR_FALSE; + return NS_OK; + } + + *aResult = (mIndex > 0); + return NS_OK; +} + +NS_IMETHODIMP +ObserverListEnumerator::GetNext(nsISupports** aResult) +{ + NS_PRECONDITION(aResult != 0, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (!mValueArray) { + *aResult = nsnull; + return NS_OK; + } + + if (mIndex <= 0 ) + return NS_ERROR_UNEXPECTED; + + mValueArray->GetElementAt(--mIndex, aResult); + if (*aResult) { + nsCOMPtr weakRefFactory = do_QueryInterface(*aResult); + if ( weakRefFactory ) { + nsCOMPtr weakref = do_QueryReferent(weakRefFactory); + NS_RELEASE(*aResult); + NS_IF_ADDREF(*aResult = weakref); + + return NS_OK; + } + } + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h new file mode 100644 index 00000000..521ce1c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverList.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsObserverList_h___ +#define nsObserverList_h___ + +#include "nsIObserver.h" +#include "nsIEnumerator.h" +#include "nsISupportsArray.h" +#include "nsISimpleEnumerator.h" + +class ObserverListEnumerator : public nsISimpleEnumerator +{ +public: + // nsISupports interface + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + ObserverListEnumerator(nsISupportsArray* aValueArray); + +private: + ~ObserverListEnumerator(void); + +protected: + nsISupportsArray* mValueArray; + PRInt32 mIndex; +}; + +class nsObserverList +{ +public: + nsObserverList(); + ~nsObserverList(); + + nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak); + nsresult RemoveObserver(nsIObserver* anObserver); + nsresult GetObserverList(nsISimpleEnumerator** anEnumerator); + +protected: + PRLock* mLock; + nsCOMPtr mObserverList; +}; + + +#endif /* nsObserverList_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp new file mode 100644 index 00000000..f4c66bcc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prlog.h" +#include "prlock.h" +#include "nsIFactory.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsIObserverService.h" +#include "nsObserverService.h" +#include "nsObserverList.h" +#include "nsHashtable.h" +#include "nsIWeakReference.h" + +#define NS_WEAK_OBSERVERS + + + +#if defined(PR_LOGGING) +// Log module for nsObserverService logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=ObserverService:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +PRLogModuleInfo* observerServiceLog = nsnull; +#endif /* PR_LOGGING */ + +//////////////////////////////////////////////////////////////////////////////// +// nsObserverService Implementation + + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService) + +nsObserverService::nsObserverService() + : mObserverTopicTable(nsnull) +{ +} + +nsObserverService::~nsObserverService(void) +{ + if(mObserverTopicTable) + delete mObserverTopicTable; +} + +NS_METHOD +nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ +#if defined(PR_LOGGING) + if (!observerServiceLog) + observerServiceLog = PR_NewLogModule("ObserverService"); +#endif + + nsresult rv; + nsObserverService* os = new nsObserverService(); + if (os == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(os); + rv = os->QueryInterface(aIID, aInstancePtr); + NS_RELEASE(os); + return rv; +} + +static PRBool PR_CALLBACK +ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure) +{ + nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData); + delete(observerList); + return PR_TRUE; +} + +nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList) +{ + if (anObserverList == nsnull) + return NS_ERROR_NULL_POINTER; + + if(mObserverTopicTable == nsnull) + { + mObserverTopicTable = new nsObjectHashtable(nsnull, + nsnull, // should never be cloned + ReleaseObserverList, + nsnull, + 256, + PR_TRUE); + if (mObserverTopicTable == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + + nsCStringKey key(aTopic); + + nsObserverList *topicObservers; + topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key); + + if (topicObservers) + { + *anObserverList = topicObservers; + return NS_OK; + } + + topicObservers = new nsObserverList(); + if (!topicObservers) + return NS_ERROR_OUT_OF_MEMORY; + + *anObserverList = topicObservers; + mObserverTopicTable->Put(&key, topicObservers); + + return NS_OK; +} + +NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->AddObserver(anObserver, ownsWeak); +} + +NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anObserver == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->RemoveObserver(anObserver); +} + +NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) +{ + nsObserverList* anObserverList; + nsresult rv; + + if (anEnumerator == nsnull || aTopic == nsnull) + return NS_ERROR_NULL_POINTER; + + rv = GetObserverList(aTopic, &anObserverList); + if (NS_FAILED(rv)) return rv; + + return anObserverList->GetObserverList(anEnumerator); +} + +// Enumerate observers of aTopic and call Observe on each. +NS_IMETHODIMP nsObserverService::NotifyObservers( nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData ) { + nsresult rv = NS_OK; + nsCOMPtr observers; + nsCOMPtr observerRef; + + rv = EnumerateObservers( aTopic, getter_AddRefs(observers) ); + if ( NS_FAILED( rv ) ) + return rv; + PRBool loop = PR_TRUE; + while( NS_SUCCEEDED(observers->HasMoreElements(&loop)) && loop) + { + observers->GetNext(getter_AddRefs(observerRef)); + nsCOMPtr observer = do_QueryInterface(observerRef); + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); +#ifdef NS_WEAK_OBSERVERS + else + { // check for weak reference. + nsCOMPtr weakRef = do_QueryInterface(observerRef); + if ( weakRef ) + weakRef->QueryReferent(NS_GET_IID(nsIObserver), getter_AddRefs(observer)); + + if ( observer ) + observer->Observe( aSubject, aTopic, someData ); + + PR_LOG(observerServiceLog, PR_LOG_DEBUG, ("Notification - %s\n", aTopic ? aTopic : "undefined")); + + } +#endif + } + return NS_OK; +} +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h new file mode 100644 index 00000000..0a08f2ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsObserverService.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsObserverService_h___ +#define nsObserverService_h___ + +#include "nsIObserverService.h" + +#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1" +#define NS_OBSERVERSERVICE_CLASSNAME "Observer Service" + +class nsObserverList; +class nsObjectHashtable; + +// {D07F5195-E3D1-11d2-8ACD-00105A1B8860} +#define NS_OBSERVERSERVICE_CID \ + { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } } + +class nsObserverService : public nsIObserverService { +public: + NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID ) + + nsObserverService(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVERSERVICE + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsObserverService(void); + + nsObjectHashtable* mObserverTopicTable; + + nsresult GetObserverList(const char* aTopic, nsObserverList** anObserverList); + + +}; + +#endif /* nsObserverService_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp new file mode 100644 index 00000000..0bdef252 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.cpp @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsID.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" +#include "nsIInputStream.h" +#include "nsIUnicharInputStream.h" +#include "pratom.h" +#include "nsEnumeratorUtils.h" +#include "nsReadableUtils.h" +#include "nsPrintfCString.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsPersistentProperties.h" +#include "nsIProperties.h" +#include "nsProperties.h" + +struct PropertyTableEntry : public PLDHashEntryHdr +{ + // both of these are arena-allocated + const char *mKey; + const PRUnichar *mValue; +}; + +static PRUnichar* +ArenaStrdup(const nsAFlatString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(PRUnichar); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) { + memcpy(mem, aString.get(), len); + } + return NS_STATIC_CAST(PRUnichar*, mem); +} + +static char* +ArenaStrdup(const nsAFlatCString& aString, PLArenaPool* aArena) +{ + void *mem; + // add one to include the null terminator + PRInt32 len = (aString.Length()+1) * sizeof(char); + PL_ARENA_ALLOCATE(mem, aArena, len); + NS_ASSERTION(mem, "Couldn't allocate space!\n"); + if (mem) + memcpy(mem, aString.get(), len); + return NS_STATIC_CAST(char*, mem); +} + +static const struct PLDHashTableOps property_HashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsPersistentProperties::nsPersistentProperties() +: mIn(nsnull) +{ + mSubclass = NS_STATIC_CAST(nsIPersistentProperties*, this); + mTable.ops = nsnull; + PL_INIT_ARENA_POOL(&mArena, "PersistentPropertyArena", 2048); +} + +nsPersistentProperties::~nsPersistentProperties() +{ + PL_FinishArenaPool(&mArena); + if (mTable.ops) + PL_DHashTableFinish(&mTable); +} + +nsresult +nsPersistentProperties::Init() +{ + if (!PL_DHashTableInit(&mTable, &property_HashTableOps, nsnull, + sizeof(PropertyTableEntry), 20)) { + mTable.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +NS_METHOD +nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPersistentProperties* props = new nsPersistentProperties(); + if (props == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(props); + nsresult rv = props->Init(); + if (NS_SUCCEEDED(rv)) + rv = props->QueryInterface(aIID, aResult); + + NS_RELEASE(props); + return rv; +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties) + +NS_IMETHODIMP +nsPersistentProperties::Load(nsIInputStream *aIn) +{ + PRInt32 c; + nsresult ret = NS_NewUTF8ConverterStream(&mIn, aIn, 0); + + if (ret != NS_OK) { + NS_WARNING("NS_NewUTF8ConverterStream failed"); + return NS_ERROR_FAILURE; + } + c = Read(); + while (1) { + c = SkipWhiteSpace(c); + if (c < 0) { + break; + } + else if ((c == '#') || (c == '!')) { + c = SkipLine(c); + continue; + } + else { + nsAutoString key; + while ((c >= 0) && (c != '=') && (c != ':')) { + key.Append(PRUnichar(c)); + c = Read(); + } + if (c < 0) { + break; + } + static const char trimThese[] = " \t"; + key.Trim(trimThese, PR_FALSE, PR_TRUE); + c = Read(); + nsAutoString value; + PRUint32 state = 0; + PRUnichar uchar = 0; + while ((c >= 0) && (c != '\r') && (c != '\n')) { + switch(state) { + case 0: + if (c == '\\') { + c = Read(); + switch(c) { + case '\r': + case '\n': + // Only skip first EOL characters and then next line's + // whitespace characters. Skipping all EOL characters + // and all upcoming whitespace is too agressive. + if (c == '\r') + c = Read(); + if (c == '\n') + c = Read(); + while (c == ' ' || c == '\t') + c = Read(); + continue; + case 'u': + case 'U': + state = 1; + uchar=0; + break; + case 't': + value.Append(PRUnichar('\t')); + break; + case 'n': + value.Append(PRUnichar('\n')); + break; + case 'r': + value.Append(PRUnichar('\r')); + break; + default: + value.Append((PRUnichar) c); + } // switch(c) + } else { + value.Append((PRUnichar) c); + } + c = Read(); + break; + case 1: + case 2: + case 3: + case 4: + if (('0' <= c) && (c <= '9')) { + uchar = (uchar << 4) | (c - '0'); + state++; + c = Read(); + } else if (('a' <= c) && (c <= 'f')) { + uchar = (uchar << 4) | (c - 'a' + 0x0a); + state++; + c = Read(); + } else if (('A' <= c) && (c <= 'F')) { + uchar = (uchar << 4) | (c - 'A' + 0x0a); + state++; + c = Read(); + } else { + value.Append((PRUnichar) uchar); + state = 0; + } + break; + case 5: + value.Append((PRUnichar) uchar); + state = 0; + } + } + if (state != 0) { + value.Append((PRUnichar) uchar); + state = 0; + } + + value.Trim(trimThese, PR_TRUE, PR_TRUE); + nsAutoString oldValue; + mSubclass->SetStringProperty(NS_ConvertUCS2toUTF8(key), value, oldValue); + } + } + mIn->Close(); + NS_RELEASE(mIn); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::SetStringProperty(const nsACString& aKey, + const nsAString& aNewValue, + nsAString& aOldValue) +{ +#if 0 + cout << "will add " << aKey.get() << "=" << + NS_LossyConvertUCS2ToASCII(aNewValue).get() << endl; +#endif + + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_ADD)); + + if (entry->mKey) { + aOldValue = entry->mValue; + NS_WARNING(nsPrintfCString(aKey.Length() + 30, + "the property %s already exists\n", + flatKey.get()).get()); + } + + entry->mKey = ArenaStrdup(flatKey, &mArena); + entry->mValue = ArenaStrdup(PromiseFlatString(aNewValue), &mArena); + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::Save(nsIOutputStream* aOut, const nsACString& aHeader) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass) +{ + if (aSubclass) { + mSubclass = aSubclass; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsPersistentProperties::GetStringProperty(const nsACString& aKey, + nsAString& aValue) +{ + const nsAFlatCString& flatKey = PromiseFlatCString(aKey); + + PropertyTableEntry *entry = + NS_STATIC_CAST(PropertyTableEntry*, + PL_DHashTableOperate(&mTable, flatKey.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return NS_ERROR_FAILURE; + + aValue = entry->mValue; + return NS_OK; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +AddElemToArray(PLDHashTable* table, PLDHashEntryHdr *hdr, + PRUint32 i, void *arg) +{ + nsISupportsArray *propArray = (nsISupportsArray *) arg; + PropertyTableEntry* entry = + NS_STATIC_CAST(PropertyTableEntry*, hdr); + + nsPropertyElement *element = + new nsPropertyElement(nsDependentCString(entry->mKey), + nsDependentString(entry->mValue)); + if (!element) + return PL_DHASH_STOP; + + NS_ADDREF(element); + propArray->InsertElementAt(element, i); + + return PL_DHASH_NEXT; +} + + +NS_IMETHODIMP +nsPersistentProperties::Enumerate(nsISimpleEnumerator** aResult) +{ + nsCOMPtr iterator; + + nsISupportsArray* propArray; + nsresult rv = NS_NewISupportsArray(&propArray); + if (rv != NS_OK) + return rv; + + // Step through hash entries populating a transient array + PRUint32 n = + PL_DHashTableEnumerate(&mTable, AddElemToArray, (void *)propArray); + if (n < mTable.entryCount) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_NewArrayEnumerator(aResult, propArray); +} + + +PRInt32 +nsPersistentProperties::Read() +{ + PRUnichar c; + PRUint32 nRead; + nsresult ret; + + ret = mIn->Read(&c, 1, &nRead); + if (ret == NS_OK && nRead == 1) { + return c; + } + + return -1; +} + +#define IS_WHITE_SPACE(c) \ + (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n')) + +PRInt32 +nsPersistentProperties::SkipWhiteSpace(PRInt32 c) +{ + while (IS_WHITE_SPACE(c)) { + c = Read(); + } + + return c; +} + +PRInt32 +nsPersistentProperties::SkipLine(PRInt32 c) +{ + while ((c >= 0) && (c != '\r') && (c != '\n')) { + c = Read(); + } + if (c == '\r') { + c = Read(); + } + if (c == '\n') { + c = Read(); + } + + return c; +} + +//////////////////////////////////////////////////////////////////////////////// +// XXX Some day we'll unify the nsIPersistentProperties interface with +// nsIProperties, but until now... + +NS_IMETHODIMP +nsPersistentProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Set(const char* prop, nsISupports* value) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP +nsPersistentProperties::Undefine(const char* prop) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::Has(const char* prop, PRBool *result) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPersistentProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// +// PropertyElement +//////////////////////////////////////////////////////////////////////////////// + + +NS_METHOD +nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + nsPropertyElement* propElem = new nsPropertyElement(); + if (propElem == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(propElem); + nsresult rv = propElem->QueryInterface(aIID, aResult); + NS_RELEASE(propElem); + return rv; +} + +NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement) + +NS_IMETHODIMP +nsPropertyElement::GetKey(nsACString& aReturnKey) +{ + aReturnKey = mKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::GetValue(nsAString& aReturnValue) +{ + aReturnValue = mValue; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetKey(const nsACString& aKey) +{ + mKey = aKey; + return NS_OK; +} + +NS_IMETHODIMP +nsPropertyElement::SetValue(const nsAString& aValue) +{ + mValue = aValue; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h new file mode 100644 index 00000000..020ff82d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsPersistentProperties.h @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsPersistentProperties_h___ +#define nsPersistentProperties_h___ + +#include "nsIPersistentProperties2.h" +#include "pldhash.h" +#include "plarena.h" +#include "nsString.h" + +class nsIUnicharInputStream; + + +class nsPersistentProperties : public nsIPersistentProperties +{ +public: + nsPersistentProperties(); + nsresult Init(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTIES + NS_DECL_NSIPERSISTENTPROPERTIES + + + // nsPersistentProperties methods: + PRInt32 Read(); + PRInt32 SkipLine(PRInt32 c); + PRInt32 SkipWhiteSpace(PRInt32 c); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPersistentProperties(); + +protected: + nsIUnicharInputStream* mIn; + PRUint32 mBufferPos; + PRUint32 mBufferLength; + nsIPersistentProperties* mSubclass; + struct PLDHashTable mTable; + PLArenaPool mArena; +}; + +class nsPropertyElement : public nsIPropertyElement +{ +public: + nsPropertyElement() + { + } + + nsPropertyElement(const nsACString& aKey, const nsAString& aValue) + : mKey(aKey), mValue(aValue) + { + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROPERTYELEMENT + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsPropertyElement() {} + +protected: + nsCString mKey; + nsString mValue; +}; + +#endif /* nsPersistentProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp new file mode 100644 index 00000000..8276e4a5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProperties.h" + +//#include + +//////////////////////////////////////////////////////////////////////////////// + +nsProperties::nsProperties(nsISupports* outer) +{ + NS_INIT_AGGREGATED(outer); +} + +NS_METHOD +nsProperties::Create(nsISupports *outer, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_PROPER_AGGREGATION(outer, aIID); + + nsProperties* props = new nsProperties(outer); + if (props == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = props->AggregatedQueryInterface(aIID, aResult); + if (NS_FAILED(rv)) + delete props; + return rv; +} + +PRBool PR_CALLBACK +nsProperties::ReleaseValues(nsHashKey* key, void* data, void* closure) +{ + nsISupports* value = (nsISupports*)data; + NS_IF_RELEASE(value); + return PR_TRUE; +} + +nsProperties::~nsProperties() +{ + Enumerate(ReleaseValues); +} + +NS_IMPL_AGGREGATED(nsProperties) + +NS_METHOD +nsProperties::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + + if (aIID.Equals(NS_GET_IID(nsISupports))) + *aInstancePtr = GetInner(); + else if (aIID.Equals(NS_GET_IID(nsIProperties))) + *aInstancePtr = NS_STATIC_CAST(nsIProperties*, this); + else { + *aInstancePtr = nsnull; + return NS_NOINTERFACE; + } + + NS_ADDREF((nsISupports*)*aInstancePtr); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) +{ + nsresult rv; + nsCStringKey key(prop); + nsISupports* value = (nsISupports*)nsHashtable::Get(&key); + if (value) { + rv = value->QueryInterface(uuid, result); + } + else { + rv = NS_ERROR_FAILURE; + } + return rv; +} + +NS_IMETHODIMP +nsProperties::Set(const char* prop, nsISupports* value) +{ + nsCStringKey key(prop); + + nsISupports* prevValue = (nsISupports*)Put(&key, value); + NS_IF_RELEASE(prevValue); + NS_IF_ADDREF(value); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Undefine(const char* prop) +{ + nsCStringKey key(prop); + if (!Exists(&key)) + return NS_ERROR_FAILURE; + + nsISupports* prevValue = (nsISupports*)Remove(&key); + NS_IF_RELEASE(prevValue); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::Has(const char* prop, PRBool *result) +{ + nsCStringKey key(prop); + *result = nsHashtable::Exists(&key); + return NS_OK; +} + +NS_IMETHODIMP +nsProperties::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/ds/nsProperties.h b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h new file mode 100644 index 00000000..ee225547 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsProperties.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsProperties_h___ +#define nsProperties_h___ + +#include "nsIProperties.h" +#include "nsHashtable.h" +#include "nsAgg.h" + +#define NS_PROPERTIES_CID \ +{ /* 4de2bc90-b1bf-11d3-93b6-00104ba0fd40 */ \ + 0x4de2bc90, \ + 0xb1bf, \ + 0x11d3, \ + {0x93, 0xb6, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +class nsIUnicharInputStream; + +class nsProperties : public nsIProperties, public nsHashtable { +public: + + NS_DECL_AGGREGATED + NS_DECL_NSIPROPERTIES + + nsProperties(nsISupports* outer); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); + +private: + ~nsProperties(); +}; + +#endif /* nsProperties_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp new file mode 100644 index 00000000..0a71d25d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#include +#include "prtypes.h" +#include "nsQuickSort.h" + +PR_BEGIN_EXTERN_C + +#if !defined(DEBUG) && (defined(__cplusplus) || defined(__gcc)) +# ifndef INLINE +# define INLINE inline +# endif +#else +# define INLINE +#endif + +typedef int cmp_t(const void *, const void *, void *); +static INLINE char *med3(char *, char *, char *, cmp_t *, void *); +static INLINE void swapfunc(char *, char *, int, int); + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static INLINE void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc((char *)a, (char*)b, (int)es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc((char *)a, (char *)b, (int)n, swaptype) + +static INLINE char * +med3(char *a, char *b, char *c, cmp_t* cmp, void *data) +{ + return cmp(a, b, data) < 0 ? + (cmp(b, c, data) < 0 ? b : (cmp(a, c, data) < 0 ? c : a )) + :(cmp(b, c, data) > 0 ? b : (cmp(a, c, data) < 0 ? a : c )); +} + +void NS_QuickSort ( + void *a, + unsigned int n, + unsigned int es, + cmp_t *cmp, + void *data + ) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, data); + pm = med3(pm - d, pm, pm + d, cmp, data); + pn = med3(pn - 2 * d, pn - d, pn, cmp, data); + } + pm = med3(pl, pm, pn, cmp, data); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a, data)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a, data)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = PR_MIN(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = PR_MIN(pd - pc, (int)(pn - pd - es)); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > (int)es) + NS_QuickSort(a, r / es, es, cmp, data); + if ((r = pd - pc) > (int)es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* NS_QuickSort(pn - r, r / es, es, cmp, data);*/ +} + +PR_END_EXTERN_C diff --git a/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h new file mode 100644 index 00000000..0dd16385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsQuickSort.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* We need this because Solaris' version of qsort is broken and + * causes array bounds reads. + */ + +#ifndef nsQuickSort_h___ +#define nsQuickSort_h___ + +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_QuickSort VBoxNsxpNS_QuickSort +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/** + * Parameters: + * 1. the array to sort + * 2. the number of elements in the array + * 3. the size of each array element + * 4. comparison function taking two elements and parameter #5 and + * returning an integer: + * + less than zero if the first element should be before the second + * + 0 if the order of the elements does not matter + * + greater than zero if the second element should be before the first + * 5. extra data to pass to comparison function + */ +PR_EXTERN(void) NS_QuickSort(void *, unsigned int, unsigned int, + int (*)(const void *, const void *, void *), + void *); + +PR_END_EXTERN_C + +#endif /* nsQuickSort_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp new file mode 100644 index 00000000..241f795c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.cpp @@ -0,0 +1,443 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * 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 ***** */ + +/* + * nsRecyclingAllocator + */ + +#include +#include +#include +#include "nsRecyclingAllocator.h" +#include "nsIMemory.h" +#include "nsAutoLock.h" +#include "prprf.h" +#include "nsITimer.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +#define NS_SEC_TO_MS(s) ((s) * 1000) + +void +nsRecyclingAllocator::nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure) +{ + nsRecyclingAllocator *obj = (nsRecyclingAllocator *) aClosure; + if (!obj->mTouched) + { + if (obj->mFreeList) + obj->FreeUnusedBuckets(); + + // If we are holding no more memory, there is no need for the timer. + // We will revive the timer on the next allocation. + // XXX Unfortunately there is no way to Cancel and restart the same timer. + // XXX So we pretty much kill it and create a new one later. + if (!obj->mFreeList && obj->mRecycleTimer) + { + obj->mRecycleTimer->Cancel(); + NS_RELEASE(obj->mRecycleTimer); + } + } + else + { + // Clear touched so the next time the timer fires we can test whether + // the allocator was used or not. + obj->Untouch(); + } +} + + +nsRecyclingAllocator::nsRecyclingAllocator(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) : + mMaxBlocks(nbucket), mBlocks(nsnull), mFreeList(nsnull), mNotUsedList(nsnull), + mRecycleTimer(nsnull), mRecycleAfter(recycleAfter), mTouched(0), mId(id) +#ifdef DEBUG + ,mNAllocated(0) +#endif +{ + NS_ASSERTION(mMaxBlocks <= NS_MAX_BLOCKS, "Too many blocks. This will affect the allocator's performance."); + + mLock = PR_NewLock(); + NS_ASSERTION(mLock, "Recycling allocator cannot get lock"); + + Init(nbucket, recycleAfter, id); +} + +nsresult +nsRecyclingAllocator::Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id) +{ + nsAutoLock lock(mLock); + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + // Reinitialize everything + mMaxBlocks = nbucket; + if (nbucket) + { + // Create memory for our bookkeeping + mBlocks = new BlockStoreNode[mMaxBlocks]; + if (!mBlocks) + return NS_ERROR_OUT_OF_MEMORY; + // Link them together + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + } + + mRecycleAfter = recycleAfter; + mId = id; + + return NS_OK; +} + +nsRecyclingAllocator::~nsRecyclingAllocator() +{ + // Cancel and destroy recycle timer + if (mRecycleTimer) + { + mRecycleTimer->Cancel(); + NS_RELEASE(mRecycleTimer); + } + + // Free all memory held, if any + while(mFreeList) + { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(mFreeList->block); +#else + free(mFreeList->block); +#endif + mFreeList = mFreeList->next; + } + mFreeList = nsnull; + + if (mBlocks) + delete [] mBlocks; + + if (mLock) + { + PR_DestroyLock(mLock); + mLock = nsnull; + } +} + +// Allocation and free routines +void* +nsRecyclingAllocator::Malloc(PRSize bytes, PRBool zeroit) +{ + // Mark that we are using. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* freeBlock = FindFreeBlock(bytes); + if (freeBlock) + { + void *data = DATA(freeBlock); + + if (zeroit) + memset(data, 0, bytes); + return data; + } + + // We need to do an allocation + // Add 4 bytes to what we allocate to hold the bucket index + PRSize allocBytes = bytes + NS_ALLOCATOR_OVERHEAD_BYTES; + + // We dont have that memory already. Allocate. +#ifdef VBOX_USE_IPRT_IN_XPCOM + Block *ptr = (Block *) (zeroit ? RTMemAllocZ(allocBytes) : RTMemAlloc(allocBytes)); +#else + Block *ptr = (Block *) (zeroit ? calloc(1, allocBytes) : malloc(allocBytes)); +#endif + + // Deal with no memory situation + if (!ptr) + return ptr; + + // This is the first allocation we are holding. + // Setup timer for releasing memory + // If this fails, then we wont have a timer to release unused + // memory. We can live with that. Also, the next allocation + // will try again to set the timer. + if (mRecycleAfter && !mRecycleTimer) + { + // known only to stuff in xpcom. + extern nsresult NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure, + PRUint32 aDelay, PRUint32 aType); + + (void) NS_NewTimer(&mRecycleTimer, nsRecycleTimerCallback, this, + NS_SEC_TO_MS(mRecycleAfter), + nsITimer::TYPE_REPEATING_SLACK); + NS_ASSERTION(mRecycleTimer, "nsRecyclingAllocator: Creating timer failed.\n"); + } + +#ifdef DEBUG + mNAllocated++; +#endif + + // Store size and return data portion + ptr->bytes = bytes; + return DATA(ptr); +} + +void +nsRecyclingAllocator::Free(void *ptr) +{ + // Mark that we are using the allocator. This will prevent any + // timer based release of unused memory. + Touch(); + + Block* block = DATA_TO_BLOCK(ptr); + + if (!AddToFreeList(block)) + { + // We are holding more than max. Failover to free +#ifdef DEBUG_dp + char buf[1024]; + // Warn if we are failing over to malloc/free and not storing it + // This says we have a misdesigned memory pool. The intent was + // once the pool was full, we would never fail over to calloc. + PR_snprintf(buf, sizeof(buf), "nsRecyclingAllocator(%s) FAILOVER 0x%p (%d) - %d allocations, %d max\n", + mId, (char *)ptr, block->bytes, mNAllocated, mMaxBlocks); + NS_WARNING(buf); + mNAllocated--; +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(block); +#else + free(block); +#endif + } +} + +/* FreeUnusedBuckets + * + * Frees any bucket memory that isn't in use + */ + +void +nsRecyclingAllocator::FreeUnusedBuckets() +{ +#ifdef DEBUG_dp + printf("DEBUG: nsRecyclingAllocator(%s) FreeUnusedBuckets: ", mId); +#endif + nsAutoLock lock(mLock); + + // We will run through the freelist and free all blocks + BlockStoreNode* node = mFreeList; + while (node) + { + // Free the allocated block +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(node->block); +#else + free(node->block); +#endif + +#ifdef DEBUG_dp + printf("%d ", node->bytes); +#endif + // Clear Node + node->block = nsnull; + node->bytes = 0; + node = node->next; + } + + // remake the lists + mNotUsedList = mBlocks; + for (PRUint32 i=0; i < mMaxBlocks-1; i++) + mBlocks[i].next = &(mBlocks[i+1]); + mBlocks[mMaxBlocks-1].next = nsnull; + mFreeList = nsnull; + +#ifdef DEBUG + mNAllocated = 0; +#endif +#ifdef DEBUG_dp + printf("\n"); +#endif +} + +nsRecyclingAllocator::Block* +nsRecyclingAllocator::FindFreeBlock(PRSize bytes) +{ + // We dont enter lock for this check. This is intentional. + // Here is my logic: we are checking if (!mFreeList). Doing this check + // without locking can lead to unpredictable results. YES. But the effect + // of the unpredictedness are ok. here is why: + // + // a) if the check returned NULL when there is stuff in freelist + // We would just end up reallocating. + // + // b) if the check returned nonNULL when our freelist is empty + // This is the more likely and dangerous case. The code for + // FindFreeBlock() will enter lock, while (null) and return null. + // + // The reason why I chose to not enter lock for this check was that when + // the allocator is full, we dont want to impose any more overhead than + // we already are for failing over to malloc/free. + + if (!mFreeList) + return NULL; + + Block *block = nsnull; + + nsAutoLock lock(mLock); + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + + while (freeNode) + { + if (freeNode->bytes >= bytes) + { + // Found the best fit free block + block = freeNode->block; + + // Clear the free node + freeNode->block = nsnull; + freeNode->bytes = 0; + + // Remove free node from free list + *prevp = freeNode->next; + + // Add removed BlockStoreNode to not used list + freeNode->next = mNotUsedList; + mNotUsedList = freeNode; + + break; + } + + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + return block; +} + +PRInt32 +nsRecyclingAllocator::AddToFreeList(Block* block) +{ + nsAutoLock lock(mLock); + + if (!mNotUsedList) + return PR_FALSE; + + // Pick a node from the not used list + BlockStoreNode *node = mNotUsedList; + mNotUsedList = mNotUsedList->next; + + // Initialize the node + node->bytes = block->bytes; + node->block = block; + + // Find the right spot in the sorted list. + BlockStoreNode* freeNode = mFreeList; + BlockStoreNode** prevp = &mFreeList; + while (freeNode) + { + if (freeNode->bytes >= block->bytes) + break; + prevp = &(freeNode->next); + freeNode = freeNode->next; + } + + // Needs to be inserted between *prevp and freeNode + *prevp = node; + node->next = freeNode; + + return PR_TRUE; +} + + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// nsIMemory methods +NS_IMPL_THREADSAFE_ISUPPORTS2(nsRecyclingAllocatorImpl, nsIMemory, nsIRecyclingAllocator) + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Alloc(PRSize size) +{ + return nsRecyclingAllocatorImpl::Malloc(size, PR_FALSE); +} + +NS_IMETHODIMP_(void *) +nsRecyclingAllocatorImpl::Realloc(void *ptr, PRSize size) +{ + // XXX Not yet implemented + return NULL; +} + +NS_IMETHODIMP_(void) +nsRecyclingAllocatorImpl::Free(void *ptr) +{ + nsRecyclingAllocator::Free(ptr); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::Init(size_t nbuckets, size_t recycleAfter, const char *id) +{ + return nsRecyclingAllocator::Init((PRUint32) nbuckets, (PRUint32) recycleAfter, id); +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::HeapMinimize(PRBool immediate) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsRecyclingAllocatorImpl::IsLowMemory(PRBool *lowmemoryb_ptr) +{ + // XXX Not yet implemented + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h new file mode 100644 index 00000000..4266b1b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRecyclingAllocator.h @@ -0,0 +1,208 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * 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 ***** */ + +/* + * nsRecyclingAllocator + * + * This allocator is useful when we cycle through a small set of allocations + * repeatedly with minimal overlap. For eg. something we do for every gif + * file read (or) buffers required for decompression of every file from jar. + * + * What this does is keeps around the first set of memory allocated and + * reuses it subsequently. If all buckets are full, this falls back to + * malloc/free + * + * Uses a timer to release all memory allocated if not used for more than + * 10 secs automatically. + * + * Also there is a 4 byte maintenance overhead on every allocation. + * + * This allocator is thread safe. + * + * CAVEATS: As the number of buckets increases, this allocators performance + * will drop. As a general guideline, dont use this for more + * than NS_MAX_BLOCKS + */ + +#ifndef nsRecyclingAllocator_h__ +#define nsRecyclingAllocator_h__ + +#include "nscore.h" +#include "pratom.h" +#include "prlock.h" +#include "nsIRecyclingAllocator.h" +#include "nsIGenericFactory.h" + +#define NS_DEFAULT_RECYCLE_TIMEOUT 10 // secs +#define NS_MAX_BLOCKS 24 +#define NS_ALLOCATOR_OVERHEAD_BYTES (sizeof(Block)) // bytes + +class nsITimer; +class nsIMemory; + +class NS_COM nsRecyclingAllocator { + protected: + struct Block { + PRSize bytes; + }; + + // Make |BlockStoreNode| a |friend| so it can access |Block|. + struct BlockStoreNode; + friend struct BlockStoreNode; + + struct BlockStoreNode { + BlockStoreNode() : bytes(0), block(nsnull), next(nsnull) {}; + PRSize bytes; + Block *block; + BlockStoreNode *next; + }; + +#define DATA(block) ((void *)(((char *)block) + NS_ALLOCATOR_OVERHEAD_BYTES)) +#define DATA_TO_BLOCK(data) ((Block *)((char *)(data) - NS_ALLOCATOR_OVERHEAD_BYTES)) + + // mMaxBlocks: Maximum number of blocks that can be allocated + PRUint32 mMaxBlocks; + + // mBlocks: + // All blocks used or not. + BlockStoreNode *mBlocks; + + // mFreeList + // A linked list of free blocks sorted by increasing order of size + BlockStoreNode* mFreeList; + + // mNotUsedList + // A linked list of BlockStoreNodes that are not used to store + // any block information. When we add blocks into mFreeList, we + // take BlockStoreNode from here. + BlockStoreNode* mNotUsedList; + + // mLock: Thread safety of mFreeList and mNotUsedList + PRLock *mLock; + + // Timer for freeing unused memory + nsITimer *mRecycleTimer; + + // mRecycleAfter: + // Allocator should be untouched for this many seconds for freeing + // unused Blocks. + PRUint32 mRecycleAfter; + + // mTouched: + // says if the allocator touched any bucket. If allocator didn't touch + // any bucket over a time time interval, timer will call FreeUnusedBuckets() + PRInt32 mTouched; + + // mId: + // a string for identifying the user of nsRecyclingAllocator + // User mainly for debug prints + const char *mId; + +#ifdef DEBUG + // mNAllocated: Number of blocks allocated + PRInt32 mNAllocated; +#endif + + public: + + // nbucket : number of buckets to hold. Capped at NS_MAX_BUCKET + // recycleAfter : Try recycling allocated buckets after this many seconds + // id : a string used to identify debug prints. Will not be released. + nsRecyclingAllocator(PRUint32 nbucket = 0, PRUint32 recycleAfter = NS_DEFAULT_RECYCLE_TIMEOUT, + const char *id = NULL); + ~nsRecyclingAllocator(); + + nsresult Init(PRUint32 nbucket, PRUint32 recycleAfter, const char *id); + + // Allocation and free routines + void* Malloc(PRSize size, PRBool zeroit = PR_FALSE); + void Free(void *ptr); + + void* Calloc(PRUint32 items, PRSize size) + { + return Malloc(items * size, PR_TRUE); + } + + // FreeUnusedBuckets - Frees any bucket memory that isn't in use + void FreeUnusedBuckets(); + + protected: + + // Timer callback to trigger unused memory + static void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); + + // Freelist management + // FindFreeBlock: return a free block that can hold bytes (best fit) + Block* FindFreeBlock(PRSize bytes); + // AddToFreeList: adds block into our freelist for future retrieval. + // Returns PR_TRUE is addition was successful. PR_FALSE otherewise. + PRBool AddToFreeList(Block* block); + + // Touch will mark that someone used this allocator + // Timer based release will free unused memory only if allocator + // was not touched for mRecycleAfter seconds. + void Touch() { + if (!mTouched) + PR_AtomicSet(&mTouched, 1); + } + void Untouch() { + PR_AtomicSet(&mTouched, 0); + } + + friend void nsRecycleTimerCallback(nsITimer *aTimer, void *aClosure); +}; + +// ---------------------------------------------------------------------- +// Wrapping the recyling allocator with nsIMemory +// ---------------------------------------------------------------------- + +// Wrapping the nsRecyclingAllocator with nsIMemory +class nsRecyclingAllocatorImpl : public nsRecyclingAllocator, public nsIRecyclingAllocator { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMEMORY + NS_DECL_NSIRECYCLINGALLOCATOR + + nsRecyclingAllocatorImpl() + { + } + +private: + ~nsRecyclingAllocatorImpl() {} +}; +#endif // nsRecyclingAllocator_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h new file mode 100644 index 00000000..69cdbe88 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsRefPtrHashtable.h @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Neil Rashbrook + * + * 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 nsRefPtrHashtable_h__ +#define nsRefPtrHashtable_h__ + +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsAutoPtr.h" + +/** + * templated hashtable class maps keys to reference pointers. + * See nsBaseHashtable for complete declaration. + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + * @see nsDataHashtable, nsClassHashtable + */ +template +class nsRefPtrHashtable : + public nsBaseHashtable< KeyClass, nsRefPtr , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + /** + * Gets a weak reference to the hashtable entry. + * @param aFound If not nsnull, will be set to PR_TRUE if the entry is found, + * to PR_FALSE otherwise. + * @return The entry, or nsnull if not found. Do not release this pointer! + */ + RefPtr* GetWeak(KeyType aKey, PRBool* aFound = nsnull) const; +}; + +/** + * Thread-safe version of nsRefPtrHashtable + * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h + * for a complete specification. + * @param RefPtr the reference-type being wrapped + */ +template +class nsRefPtrHashtableMT : + public nsBaseHashtableMT< KeyClass, nsRefPtr , RefPtr* > +{ +public: + typedef typename KeyClass::KeyType KeyType; + typedef RefPtr* UserDataType; + + /** + * @copydoc nsBaseHashtable::Get + * @param pData This is an XPCOM getter, so pData is already_addrefed. + * If the key doesn't exist, pData will be set to nsnull. + */ + PRBool Get(KeyType aKey, UserDataType* pData) const; + + // GetWeak does not make sense on a multi-threaded hashtable, where another + // thread may remove the entry (and hence release it) as soon as GetWeak + // returns +}; + + +// +// nsRefPtrHashtable definitions +// + +template +PRBool +nsRefPtrHashtable::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + typename nsBaseHashtable, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + return PR_FALSE; +} + +template +RefPtr* +nsRefPtrHashtable::GetWeak + (KeyType aKey, PRBool* aFound) const +{ + typename nsBaseHashtable, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (aFound) + *aFound = PR_TRUE; + + return ent->mData; + } + + // Key does not exist, return nsnull and set aFound to PR_FALSE + if (aFound) + *aFound = PR_FALSE; + return nsnull; +} + +// +// nsRefPtrHashtableMT definitions +// + +template +PRBool +nsRefPtrHashtableMT::Get + (KeyType aKey, UserDataType* pRefPtr) const +{ + PR_Lock(this->mLock); + + typename nsBaseHashtableMT, RefPtr*>::EntryType* ent = + this->GetEntry(aKey); + + if (ent) + { + if (pRefPtr) + { + *pRefPtr = ent->mData; + + NS_IF_ADDREF(*pRefPtr); + } + + PR_Unlock(this->mLock); + + return PR_TRUE; + } + + // if the key doesn't exist, set *pRefPtr to null + // so that it is a valid XPCOM getter + if (pRefPtr) + *pRefPtr = nsnull; + + PR_Unlock(this->mLock); + + return PR_FALSE; +} + +#endif // nsRefPtrHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h new file mode 100644 index 00000000..6c76d016 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticAtom.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Static Atom classes. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 nsStaticAtom_h__ +#define nsStaticAtom_h__ + +#include "nsIAtom.h" + +// see http://www.mozilla.org/projects/xpcom/atoms.html to use this stuff + +// class for declaring a static list of atoms, for use with gperf +// Keep this VERY simple +// mString: the value of the atom - the policy is that this is only +// ASCII, in order to avoid unnecessary conversions if +// someone asks for this in unicode +// mAtom: a convienience pointer - if you want to store the value of +// the atom created by this structure somewhere, put its +// address here +struct nsStaticAtom { + const char* mString; + nsIAtom ** mAtom; +}; + + +// register your lookup function with the atom table. Your function +// will be called when at atom is not found in the main atom table. +NS_COM nsresult +NS_RegisterStaticAtoms(const nsStaticAtom*, PRUint32 aAtomCount); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp new file mode 100644 index 00000000..35489c6a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Class to manage lookup of static names in a table. */ + +#include "nsCRT.h" + +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +#define PL_ARENA_CONST_ALIGN_MASK 3 +#include "nsStaticNameTable.h" + +struct NameTableEntry : public PLDHashEntryHdr +{ + // no ownership here! + const char *mKey; + PRInt32 mIndex; +}; + +PR_STATIC_CALLBACK(PRBool) +matchNameKeysCaseInsensitive(PLDHashTable*, const PLDHashEntryHdr* aHdr, + const void* key) +{ + const NameTableEntry* entry = + NS_STATIC_CAST(const NameTableEntry *, aHdr); + const char *keyValue = NS_STATIC_CAST(const char*, key); + + return (nsCRT::strcasecmp(entry->mKey, keyValue)==0); +} + +/* + * caseInsensitiveHashKey is just like PL_DHashStringKey except it + * uses (*s & ~0x20) instead of simply *s. This means that "aFOO" and + * "afoo" and "aFoo" will all hash to the same thing. It also means + * that some strings that aren't case-insensensitively equal will hash + * to the same value, but it's just a hash function so it doesn't + * matter. + */ +PR_STATIC_CALLBACK(PLDHashNumber) +caseInsensitiveStringHashKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h = 0; + for (const unsigned char* s = + NS_STATIC_CAST(const unsigned char*, key); + *s != '\0'; + s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ (*s & ~0x20); + return h; +} + +static const struct PLDHashTableOps nametable_CaseInsensitiveHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + caseInsensitiveStringHashKey, + matchNameKeysCaseInsensitive, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + nsnull, +}; + +nsStaticCaseInsensitiveNameTable::nsStaticCaseInsensitiveNameTable() + : mNameArray(nsnull), mNullStr("") +{ + MOZ_COUNT_CTOR(nsStaticCaseInsensitiveNameTable); + mNameTable.ops = nsnull; +} + +nsStaticCaseInsensitiveNameTable::~nsStaticCaseInsensitiveNameTable() +{ + if (mNameArray) { + // manually call the destructor on placement-new'ed objects + for (PRUint32 index = 0; index < mNameTable.entryCount; index++) { + mNameArray[index].~nsDependentCString(); + } + nsMemory::Free((void*)mNameArray); + } + if (mNameTable.ops) + PL_DHashTableFinish(&mNameTable); + MOZ_COUNT_DTOR(nsStaticCaseInsensitiveNameTable); +} + +PRBool +nsStaticCaseInsensitiveNameTable::Init(const char* const aNames[], PRInt32 Count) +{ + NS_ASSERTION(!mNameArray, "double Init"); + NS_ASSERTION(!mNameTable.ops, "double Init"); + NS_ASSERTION(aNames, "null name table"); + NS_ASSERTION(Count, "0 count"); + + mNameArray = (nsDependentCString*) + nsMemory::Alloc(Count * sizeof(nsDependentCString)); + if (!mNameArray) + return PR_FALSE; + + if (!PL_DHashTableInit(&mNameTable, + &nametable_CaseInsensitiveHashTableOps, + nsnull, sizeof(NameTableEntry), Count)) { + mNameTable.ops = nsnull; + return PR_FALSE; + } + + for (PRInt32 index = 0; index < Count; ++index) { + const char* raw = aNames[index]; +#ifdef DEBUG + { + // verify invariants of contents + nsCAutoString temp1(raw); + nsDependentCString temp2(raw); + ToLowerCase(temp1); + NS_ASSERTION(temp1.Equals(temp2), "upper case char in table"); + NS_ASSERTION(nsCRT::IsAscii(raw), + "non-ascii string in table -- " + "case-insensitive matching won't work right"); + } +#endif + // use placement-new to initialize the string object + new (&mNameArray[index]) nsDependentCString(raw); + + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&mNameTable, raw, PL_DHASH_ADD)); + + if (!entry) continue; + + NS_ASSERTION(entry->mKey == 0, "Entry already exists!"); + + entry->mKey = raw; // not owned! + entry->mIndex = index; + } + return PR_TRUE; +} + +inline PRInt32 +LookupFlatKeyword(const nsAFlatCString& aKeyword, + PLDHashTable& aTable) +{ + NameTableEntry *entry = + NS_STATIC_CAST(NameTableEntry*, + PL_DHashTableOperate(&aTable, aKeyword.get(), PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return nsStaticCaseInsensitiveNameTable::NOT_FOUND; + + return entry->mIndex; +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsACString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + return LookupFlatKeyword(PromiseFlatCString(aName), mNameTable); +} + +PRInt32 +nsStaticCaseInsensitiveNameTable::Lookup(const nsAString& aName) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + nsCAutoString cstring; + cstring.AssignWithConversion(aName); + return LookupFlatKeyword(cstring, mNameTable); +} + +const nsAFlatCString& +nsStaticCaseInsensitiveNameTable::GetStringValue(PRInt32 index) +{ + NS_ASSERTION(mNameArray, "not inited"); + NS_ASSERTION(mNameTable.ops, "not inited"); + + if ((NOT_FOUND < index) && ((PRUint32)index < mNameTable.entryCount)) { + return mNameArray[index]; + } + return mNullStr; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h new file mode 100644 index 00000000..154a1c9d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStaticNameTable.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Classes to manage lookup of static names in a table. */ + +#ifndef nsStaticNameTable_h___ +#define nsStaticNameTable_h___ + +#include "pldhash.h" +/* This class supports case insensitive lookup. + * + * It differs from atom tables: + * - It supports case insensitive lookup. + * - It has minimal footprint by not copying the string table. + * - It does no locking. + * - It returns zero based indexes and const nsCString& as required by its + * callers in the parser. + * - It is not an xpcom interface - meant for fast lookup in static tables. + * + * ***REQUIREMENTS*** + * - It *requires* that all entries in the table be lowercase only. + * - It *requires* that the table of strings be in memory that lives at least + * as long as this table object - typically a static string array. + */ + +class NS_COM nsStaticCaseInsensitiveNameTable +{ +public: + enum { NOT_FOUND = -1 }; + + PRBool Init(const char* const aNames[], PRInt32 Count); + PRInt32 Lookup(const nsACString& aName); + PRInt32 Lookup(const nsAString& aName); + const nsAFlatCString& GetStringValue(PRInt32 index); + + nsStaticCaseInsensitiveNameTable(); + ~nsStaticCaseInsensitiveNameTable(); + +private: + nsDependentCString* mNameArray; + PLDHashTable mNameTable; + nsDependentCString mNullStr; +}; + +#endif /* nsStaticNameTable_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp new file mode 100644 index 00000000..8a10b18c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.cpp @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsStringEnumerator.h" +#include "prtypes.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsISimpleEnumerator.h" +#include "nsSupportsPrimitives.h" + +// +// nsStringEnumerator +// + +class nsStringEnumerator : public nsIStringEnumerator, + public nsIUTF8StringEnumerator, + public nsISimpleEnumerator +{ +public: + nsStringEnumerator(const nsStringArray* aArray, PRBool aOwnsArray) : + mArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, PRBool aOwnsArray) : + mCArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(PR_FALSE) + {} + + nsStringEnumerator(const nsStringArray* aArray, nsISupports* aOwner) : + mArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_TRUE) + {} + + nsStringEnumerator(const nsCStringArray* aArray, nsISupports* aOwner) : + mCArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(PR_FALSE), mIsUnicode(PR_FALSE) + {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIUTF8STRINGENUMERATOR + + // have to declare nsIStringEnumerator manually, because of + // overlapping method names + NS_IMETHOD GetNext(nsAString& aResult); + NS_DECL_NSISIMPLEENUMERATOR + +private: + ~nsStringEnumerator() { + if (mOwnsArray) { + // const-casting is safe here, because the NS_New* + // constructors make sure mOwnsArray is consistent with + // the constness of the objects + if (mIsUnicode) + delete NS_CONST_CAST(nsStringArray*,mArray); + else + delete NS_CONST_CAST(nsCStringArray*,mCArray); + } + } + + union { + const nsStringArray* mArray; + const nsCStringArray* mCArray; + }; + + inline PRUint32 Count() { + return mIsUnicode ? mArray->Count() : mCArray->Count(); + } + + PRUint32 mIndex; + + // the owner allows us to hold a strong reference to the object + // that owns the array. Having a non-null value in mOwner implies + // that mOwnsArray is PR_FALSE, because we rely on the real owner + // to release the array + nsCOMPtr mOwner; + PRPackedBool mOwnsArray; + PRPackedBool mIsUnicode; +}; + +NS_IMPL_ISUPPORTS3(nsStringEnumerator, + nsIStringEnumerator, + nsIUTF8StringEnumerator, + nsISimpleEnumerator) + +NS_IMETHODIMP +nsStringEnumerator::HasMore(PRBool* aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = mIndex < Count(); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::HasMoreElements(PRBool* aResult) +{ + return HasMore(aResult); +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsISupports** aResult) +{ + if (mIsUnicode) { + nsSupportsStringImpl* stringImpl = new nsSupportsStringImpl(); + if (!stringImpl) return NS_ERROR_OUT_OF_MEMORY; + + stringImpl->SetData(*mArray->StringAt(mIndex++)); + *aResult = stringImpl; + } + else { + nsSupportsCStringImpl* cstringImpl = new nsSupportsCStringImpl(); + if (!cstringImpl) return NS_ERROR_OUT_OF_MEMORY; + + cstringImpl->SetData(*mCArray->CStringAt(mIndex++)); + *aResult = cstringImpl; + } + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsAString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + aResult = *mArray->StringAt(mIndex++); + else + CopyUTF8toUTF16(*mCArray->CStringAt(mIndex++), aResult); + + return NS_OK; +} + +NS_IMETHODIMP +nsStringEnumerator::GetNext(nsACString& aResult) +{ + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + + if (mIsUnicode) + CopyUTF16toUTF8(*mArray->StringAt(mIndex++), aResult); + else + aResult = *mCArray->CStringAt(mIndex++); + + return NS_OK; +} + +template +static inline nsresult +StringEnumeratorTail(T** aResult) +{ + if (!*aResult) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*aResult); + return NS_OK; +} + +// +// constructors +// + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, nsISupports* aOwner) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, aOwner); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_TRUE); + return StringEnumeratorTail(aResult); +} + +// const ones internally just forward to the non-const equivalents +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray) +{ + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); + + *aResult = new nsStringEnumerator(aArray, PR_FALSE); + return StringEnumeratorTail(aResult); +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h new file mode 100644 index 00000000..d0080005 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsStringEnumerator.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 String Enumerator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alec Flett + * + * 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 "nsIStringEnumerator.h" +#include "nsVoidArray.h" + +// nsIStringEnumerator/nsIUTF8StringEnumerator implementations +// +// Currently all implementations support both interfaces. The +// constructors below provide the most common interface for the given +// type (i.e. nsIStringEnumerator for PRUnichar* strings, and so +// forth) but any resulting enumerators can be queried to the other +// type. Internally, the enumerators will hold onto the type that was +// passed in and do conversion if GetNext() for the other type of +// string is called. + +// There are a few different types of enumerators: + +// +// These enumerators hold a pointer to the array. Be careful +// because modifying the array may confuse the iterator, especially if +// you insert or remove elements in the middle of the array. +// + +// The non-adopting enumerator requires that the array sticks around +// at least as long as the enumerator does. These are for constant +// string arrays that the enumerator does not own, this could be used +// in VERY specialized cases such as when the provider KNOWS that the +// string enumerator will be consumed immediately, or will at least +// outlast the array. +// For example: +// +// nsCStringArray array; +// array.AppendCString("abc"); +// array.AppendCString("def"); +// NS_NewStringEnumerator(&enumerator, &array, PR_TRUE); +// +// // call some internal method which iterates the enumerator +// InternalMethod(enumerator); +// NS_RELEASE(enumerator); +// +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray); + +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray); + +// Adopting string enumerators assume ownership of the array and will +// call |operator delete| on the array when the enumerator is destroyed +// this is useful when the provider creates an array soley for the +// purpose of creating the enumerator. +// For example: +// +// nsCStringArray* array = new nsCStringArray; +// array->AppendString("abcd"); +// NS_NewAdoptingStringEnumerator(&result, array); +NS_COM nsresult +NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, + nsStringArray* aArray); + +NS_COM nsresult +NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + nsCStringArray* aArray); + + +// these versions take a refcounted "owner" which will be addreffed +// when the enumerator is created, and destroyed when the enumerator +// is released. This allows providers to give non-owning pointers to +// ns*StringArray member variables without worrying about lifetime +// issues +// For example: +// +// nsresult MyClass::Enumerate(nsIUTF8StringEnumerator** aResult) { +// mCategoryList->AppendString("abcd"); +// return NS_NewStringEnumerator(aResult, mCategoryList, this); +// } +// +NS_COM nsresult +NS_NewStringEnumerator(nsIStringEnumerator** aResult, + const nsStringArray* aArray, + nsISupports* aOwner); +NS_COM nsresult +NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, + const nsCStringArray* aArray, + nsISupports* aOwner); diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp new file mode 100644 index 00000000..e0774083 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.cpp @@ -0,0 +1,684 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins : |do_QueryElementAt| + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "prbit.h" +#include "nsSupportsArray.h" +#include "nsSupportsArrayEnumerator.h" +#include "nsAString.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" + +#if DEBUG_SUPPORTSARRAY +#define MAXSUPPORTS 20 + +class SupportsStats { +public: + SupportsStats(); + ~SupportsStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXSUPPORTS]; // sizes of the allocations. sorted +static int NumberOfSize[MAXSUPPORTS]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXSUPPORTS]; // number of this allocation size (each size for array used) +static int GrowInPlace[MAXSUPPORTS]; + +// these are per-allocation +static int MaxElements[3000]; + +// very evil +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXSUPPORTS) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0); + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0); + + +SupportsStats::SupportsStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +SupportsStats::~SupportsStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of SupportsArrays this size (max): %d\n",NumberOfSize[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of SupportsArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor get called +SupportsStats gSupportsStats; +#endif + +nsresult +nsQueryElementAt::operator()( const nsIID& aIID, void** aResult ) const + { + nsresult status = mCollection + ? mCollection->QueryElementAt(mIndex, aIID, aResult) + : NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + + return status; + } + +static const PRInt32 kGrowArrayBy = 8; +static const PRInt32 kLinearThreshold = 16 * sizeof(nsISupports *); + +nsSupportsArray::nsSupportsArray() +{ + mArray = mAutoArray; + mArraySize = kAutoArraySize; + mCount = 0; +#if DEBUG_SUPPORTSARRAY + mMaxCount = 0; + mMaxSize = 0; + ADD_TO_STATS(NumberOfSize,kAutoArraySize*sizeof(mArray[0])); + MaxElements[0]++; +#endif +} + +nsSupportsArray::~nsSupportsArray() +{ + DeleteArray(); +} + +PRBool nsSupportsArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // We have to grow the array. Grow by kGrowArrayBy slots if we're smaller + // than kLinearThreshold bytes, or a power of two if we're larger. + // This is much more efficient with most memory allocators, especially + // if it's very large, or of the allocator is binned. + if (aGrowBy < kGrowArrayBy) + aGrowBy = kGrowArrayBy; + + PRUint32 newCount = mArraySize + aGrowBy; // Minimum increase + PRUint32 newSize = sizeof(mArray[0]) * newCount; + + if (newSize >= (PRUint32) kLinearThreshold) + { + // newCount includes enough space for at least kGrowArrayBy new slots. + // Select the next power-of-two size in bytes above that if newSize is + // not a power of two. + if (newSize & (newSize - 1)) + newSize = PR_BIT(PR_CeilingLog2(newSize)); + + newCount = newSize / sizeof(mArray[0]); + } + // XXX This would be far more efficient in many allocators if we used + // XXX PR_Realloc(), etc + nsISupports** oldArray = mArray; + + mArray = new nsISupports*[newCount]; + if (!mArray) { // ran out of memory + mArray = oldArray; + return PR_FALSE; + } + mArraySize = newCount; + +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,mCount); + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); + if (mArraySize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,mArraySize*sizeof(mArray[0])); + if (oldArray != &(mAutoArray[0])) + SUB_FROM_STATS(NumberOfSize,mCount*sizeof(mArray[0])); + mMaxSize = mArraySize; + } +#endif + if (oldArray) { // need to move old data + if (0 < mCount) { + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + } + if (oldArray != &(mAutoArray[0])) { + delete[] oldArray; + } + } + + return PR_TRUE; +} + +NS_METHOD +nsSupportsArray::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsCOMPtr it = new nsSupportsArray(); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + return it->QueryInterface(aIID, aResult); +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsSupportsArray, nsISupportsArray, nsICollection, nsISerializable) + +NS_IMETHODIMP +nsSupportsArray::Read(nsIObjectInputStream *aStream) +{ + nsresult rv; + + PRUint32 newArraySize; + rv = aStream->Read32(&newArraySize); + + if (newArraySize <= kAutoArraySize) { + if (mArray != mAutoArray) { + delete[] mArray; + mArray = mAutoArray; + } + newArraySize = kAutoArraySize; + } + else { + if (newArraySize <= mArraySize) { + // Keep non-default-size mArray, it's more than big enough. + newArraySize = mArraySize; + } + else { + nsISupports** array = new nsISupports*[newArraySize]; + if (!array) + return NS_ERROR_OUT_OF_MEMORY; + if (mArray != mAutoArray) + delete[] mArray; + mArray = array; + } + } + mArraySize = newArraySize; + + rv = aStream->Read32(&mCount); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(mCount <= mArraySize, "overlarge mCount!"); + if (mCount > mArraySize) + mCount = mArraySize; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->ReadObject(PR_TRUE, &mArray[i]); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Write(nsIObjectOutputStream *aStream) +{ + nsresult rv; + + rv = aStream->Write32(mArraySize); + if (NS_FAILED(rv)) return rv; + + rv = aStream->Write32(mCount); + if (NS_FAILED(rv)) return rv; + + for (PRUint32 i = 0; i < mCount; i++) { + rv = aStream->WriteObject(mArray[i], PR_TRUE); + if (NS_FAILED(rv)) return rv; + } + + return NS_OK; +} + +void nsSupportsArray::DeleteArray(void) +{ + Clear(); + if (mArray != &(mAutoArray[0])) { + delete[] mArray; + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } +} + + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::Equals(const nsISupportsArray* aOther) +{ + if (aOther) { + PRUint32 countOther; + nsISupportsArray* other = NS_CONST_CAST(nsISupportsArray*, aOther); + nsresult rv = other->Count(&countOther); + if (NS_FAILED( rv )) + return PR_FALSE; + + if (mCount == countOther) { + PRUint32 index = mCount; + nsCOMPtr otherElem; + while (index--) { + if (NS_FAILED(other->GetElementAt(index, getter_AddRefs(otherElem)))) + return PR_FALSE; + if (mArray[index] != otherElem) + return PR_FALSE; + } + return PR_TRUE; + } + } + return PR_FALSE; +} + +NS_IMETHODIMP_(nsISupports*) +nsSupportsArray::ElementAt(PRUint32 aIndex) +{ + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + NS_IF_ADDREF(element); + return element; + } + return 0; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOf(const nsISupports* aPossibleElement) +{ + return IndexOfStartingAt(aPossibleElement, 0); +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex) +{ + if (aStartIndex < mCount) { + const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior + const nsISupports** ep = (start + aStartIndex); + const nsISupports** end = (start + mCount); + while (ep < end) { + if (aPossibleElement == *ep) { + return (ep - start); + } + ep++; + } + } + return -1; +} + +NS_IMETHODIMP_(PRInt32) +nsSupportsArray::LastIndexOf(const nsISupports* aPossibleElement) +{ + if (0 < mCount) { + const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior + const nsISupports** ep = (start + mCount); + while (start <= --ep) { + if (aPossibleElement == *ep) { + return (ep - start); + } + } + } + return -1; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 aIndex) +{ + if (aIndex <= mCount) { + if (mArraySize < (mCount + 1)) { + // need to grow the array + if (!GrowArrayBy(1)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*)); + } + + mArray[aIndex] = aElement; + NS_IF_ADDREF(aElement); + mCount++; + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::InsertElementsAt(nsISupportsArray* aElements, PRUint32 aIndex) +{ + if (!aElements) { + return PR_FALSE; + } + PRUint32 countElements; + if (NS_FAILED( aElements->Count( &countElements ) )) + return PR_FALSE; + + if (aIndex <= mCount) { + if (mArraySize < (mCount + countElements)) { + // need to grow the array + if (!GrowArrayBy(countElements)) + return PR_FALSE; + } + + // Could be slightly more efficient if GrowArrayBy knew about the + // split, but the difference is trivial. + PRUint32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex + countElements, mArray + aIndex, + slide * sizeof(nsISupports*)); + } + + for (PRUint32 i = 0; i < countElements; ++i, ++mCount) { + // use GetElementAt to copy and do AddRef for us + if (NS_FAILED( aElements->GetElementAt( i, mArray + aIndex + i) )) + return PR_FALSE; + } + +#if DEBUG_SUPPORTSARRAY + if (mCount > mMaxCount && + mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mCount; + } +#endif + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex) +{ + if (aIndex < mCount) { + NS_IF_ADDREF(aElement); // addref first in case it's the same object! + NS_IF_RELEASE(mArray[aIndex]); + mArray[aIndex] = aElement; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount) +{ + if (aIndex + aCount <= mCount) { + for (PRUint32 i = 0; i < aCount; i++) + NS_IF_RELEASE(mArray[aIndex+i]); + mCount -= aCount; + PRInt32 slide = (mCount - aIndex); + if (0 < slide) { + ::memmove(mArray + aIndex, mArray + aIndex + aCount, + slide * sizeof(nsISupports*)); + } + return PR_TRUE; + } + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex) +{ + PRInt32 theIndex = IndexOfStartingAt(aElement,aStartIndex); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::RemoveLastElement(const nsISupports* aElement) +{ + PRInt32 theIndex = LastIndexOf(aElement); + if (theIndex >= 0) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + nsISupports *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + if (aTo < 0 || aFrom < 0 || + (PRUint32) aTo >= mCount || (PRUint32) aFrom >= mCount) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + ::memmove(mArray + aTo + 1, mArray + aTo, + (aFrom-aTo) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + ::memmove(mArray + aFrom, mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mArray[0])); + mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +NS_IMETHODIMP +nsSupportsArray::Clear(void) +{ + if (0 < mCount) { + do { + --mCount; + NS_IF_RELEASE(mArray[mCount]); + } while (0 != mCount); + } + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArray::Compact(void) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) { + nsISupports** oldArray = mArray; + if (mCount <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[mCount]; + if (!mArray) { + mArray = oldArray; + return NS_OK; + } + mArraySize = mCount; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + delete[] oldArray; + } + return NS_OK; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::SizeTo(PRInt32 aSize) +{ +#if DEBUG_SUPPORTSARRAY + PRUint32 oldArraySize = mArraySize; +#endif + NS_ASSERTION(aSize >= 0, "negative aSize!"); + + // XXX for aSize < mCount we could resize to mCount + if (mArraySize == (PRUint32) aSize || (PRUint32) aSize < mCount) + return PR_TRUE; // nothing to do + + // switch back to autoarray if possible + nsISupports** oldArray = mArray; + if ((PRUint32) aSize <= kAutoArraySize) { + mArray = mAutoArray; + mArraySize = kAutoArraySize; + } + else { + mArray = new nsISupports*[aSize]; + if (!mArray) { + mArray = oldArray; + return PR_FALSE; + } + mArraySize = aSize; + } +#if DEBUG_SUPPORTSARRAY + if (oldArray == mArray && + oldArray != &(mAutoArray[0])) // can't happen without use of realloc + ADD_TO_STATS(GrowInPlace,oldArraySize); + if (oldArray != &(mAutoArray[0])) + ADD_TO_STATS(AllocedOfSize,mArraySize*sizeof(mArray[0])); +#endif + ::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*)); + if (oldArray != mAutoArray) + delete[] oldArray; + + return PR_TRUE; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRInt32 aIndex = -1; + PRBool running = PR_TRUE; + + while (running && (++aIndex < (PRInt32)mCount)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP_(PRBool) +nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) +{ + PRUint32 aIndex = mCount; + PRBool running = PR_TRUE; + + while (running && (0 < aIndex--)) { + running = (*aFunc)(mArray[aIndex], aData); + } + return running; +} + +NS_IMETHODIMP +nsSupportsArray::Enumerate(nsIEnumerator* *result) +{ + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this); + if (!e) + return NS_ERROR_OUT_OF_MEMORY; + *result = e; + NS_ADDREF(e); + return NS_OK; +} + +static PRBool +CopyElement(nsISupports* aElement, void *aData) +{ + nsresult rv; + nsISupportsArray* newArray = (nsISupportsArray*)aData; + rv = newArray->AppendElement(aElement); + return NS_SUCCEEDED(rv); +} + +NS_IMETHODIMP +nsSupportsArray::Clone(nsISupportsArray* *result) +{ + nsresult rv; + nsISupportsArray* newArray; + rv = NS_NewISupportsArray(&newArray); + PRBool ok = EnumerateForwards(CopyElement, newArray); + if (!ok) return NS_ERROR_OUT_OF_MEMORY; + *result = newArray; + return NS_OK; +} + +NS_COM nsresult +NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult) +{ + nsresult rv; + rv = nsSupportsArray::Create(NULL, NS_GET_IID(nsISupportsArray), + (void**)aInstancePtrResult); + return rv; +} + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h new file mode 100644 index 00000000..0f9c9601 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArray.h @@ -0,0 +1,172 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsSupportsArray_h__ +#define nsSupportsArray_h__ + +//#define DEBUG_SUPPORTSARRAY 1 + +#include "nsISupportsArray.h" + +static const PRUint32 kAutoArraySize = 8; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class NS_COM nsSupportsArray : public nsISupportsArray { +public: + nsSupportsArray(void); + ~nsSupportsArray(void); // nonvirtual since we're not subclassed + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + + NS_DECL_NSISERIALIZABLE + + // nsICollection methods: + NS_IMETHOD Count(PRUint32 *result) { *result = mCount; return NS_OK; } + NS_IMETHOD GetElementAt(PRUint32 aIndex, nsISupports* *result) { + *result = ElementAt(aIndex); + return NS_OK; + } + NS_IMETHOD QueryElementAt(PRUint32 aIndex, const nsIID & aIID, void * *aResult) { + if (aIndex < mCount) { + nsISupports* element = mArray[aIndex]; + if (nsnull != element) + return element->QueryInterface(aIID, aResult); + } + return NS_ERROR_FAILURE; + } + NS_IMETHOD SetElementAt(PRUint32 aIndex, nsISupports* value) { + return ReplaceElementAt(value, aIndex) ? NS_OK : NS_ERROR_FAILURE; + } + NS_IMETHOD AppendElement(nsISupports *aElement) { + return InsertElementAt(aElement, mCount)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + // XXX this is badly named - should be RemoveFirstElement + NS_IMETHOD RemoveElement(nsISupports *aElement) { + return RemoveElement(aElement, 0)/* ? NS_OK : NS_ERROR_FAILURE*/; + } + NS_IMETHOD_(PRBool) MoveElement(PRInt32 aFrom, PRInt32 aTo); + NS_IMETHOD Enumerate(nsIEnumerator* *result); + NS_IMETHOD Clear(void); + + // nsISupportsArray methods: + NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* aOther); + + NS_IMETHOD_(nsISupports*) ElementAt(PRUint32 aIndex); + + NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement); + NS_IMETHOD_(PRInt32) IndexOfStartingAt(const nsISupports* aPossibleElement, + PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement); + + NS_IMETHOD GetIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = IndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD GetIndexOfStartingAt(nsISupports *aPossibleElement, + PRUint32 aStartIndex, PRInt32 *_retval) { + *_retval = IndexOfStartingAt(aPossibleElement, aStartIndex); + return NS_OK; + } + + NS_IMETHOD GetLastIndexOf(nsISupports *aPossibleElement, PRInt32 *_retval) { + *_retval = LastIndexOf(aPossibleElement); + return NS_OK; + } + + NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex) { + return RemoveElementsAt(aIndex,1); + } + NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex = 0); + NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement); + + NS_IMETHOD DeleteLastElement(nsISupports *aElement) { + return (RemoveLastElement(aElement) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD DeleteElementAt(PRUint32 aIndex) { + return (RemoveElementAt(aIndex) ? NS_OK : NS_ERROR_FAILURE); + } + + NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) { + return InsertElementsAt(aElements,mCount); + } + + NS_IMETHOD Compact(void); + + NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData); + NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData); + + NS_IMETHOD Clone(nsISupportsArray **_retval); + + NS_IMETHOD_(PRBool) InsertElementsAt(nsISupportsArray *aOther, PRUint32 aIndex); + + NS_IMETHOD_(PRBool) RemoveElementsAt(PRUint32 aIndex, PRUint32 aCount); + + NS_IMETHOD_(PRBool) SizeTo(PRInt32 aSize); +protected: + void DeleteArray(void); + + NS_IMETHOD_(PRBool) GrowArrayBy(PRInt32 aGrowBy); + + nsISupports** mArray; + PRUint32 mArraySize; + PRUint32 mCount; + nsISupports* mAutoArray[kAutoArraySize]; +#if DEBUG_SUPPORTSARRAY + PRUint32 mMaxCount; + PRUint32 mMaxSize; +#endif + +private: + // Copy constructors are not allowed + nsSupportsArray(const nsISupportsArray& other); +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +#endif // nsSupportsArray_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp new file mode 100644 index 00000000..38d7d728 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.cpp @@ -0,0 +1,148 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSupportsArrayEnumerator.h" +#include "nsISupportsArray.h" + +nsSupportsArrayEnumerator::nsSupportsArrayEnumerator(nsISupportsArray* array) + : mArray(array), mCursor(0) +{ + NS_ASSERTION(array, "null array"); + NS_ADDREF(mArray); +} + +nsSupportsArrayEnumerator::~nsSupportsArrayEnumerator() +{ + NS_RELEASE(mArray); +} + +NS_IMPL_ISUPPORTS2(nsSupportsArrayEnumerator, nsIBidirectionalEnumerator, nsIEnumerator) + +NS_IMETHODIMP +nsSupportsArrayEnumerator::First() +{ + mCursor = 0; + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Next() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + PRInt32 end = (PRInt32)cnt; + if (mCursor < end) // don't count upward forever + mCursor++; + if (mCursor < end) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::CurrentItem(nsISupports **aItem) +{ + NS_ASSERTION(aItem, "null out parameter"); + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + if (mCursor >= 0 && mCursor < (PRInt32)cnt) { + *aItem = mArray->ElementAt(mCursor); + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::IsDone() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + return (mCursor >= 0 && mCursor < (PRInt32)cnt) + ? NS_ENUMERATOR_FALSE : NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Last() +{ + PRUint32 cnt; + nsresult rv = mArray->Count(&cnt); + if (NS_FAILED(rv)) return rv; + mCursor = cnt - 1; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsArrayEnumerator::Prev() +{ + if (mCursor >= 0) + --mCursor; + if (mCursor >= 0) + return NS_OK; + else + return NS_ERROR_FAILURE; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_NewISupportsArrayEnumerator(nsISupportsArray* array, + nsIBidirectionalEnumerator* *aInstancePtrResult) +{ + if (aInstancePtrResult == 0) + return NS_ERROR_NULL_POINTER; + nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(array); + if (e == 0) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(e); + *aInstancePtrResult = e; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h new file mode 100644 index 00000000..e987709f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsArrayEnumerator.h @@ -0,0 +1,67 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsSupportsArrayEnumerator_h___ +#define nsSupportsArrayEnumerator_h___ + +#include "nsIEnumerator.h" + +class nsISupportsArray; + +class nsSupportsArrayEnumerator : public nsIBidirectionalEnumerator { +public: + NS_DECL_ISUPPORTS + + nsSupportsArrayEnumerator(nsISupportsArray* array); + + // nsIEnumerator methods: + NS_DECL_NSIENUMERATOR + + // nsIBidirectionalEnumerator methods: + NS_DECL_NSIBIDIRECTIONALENUMERATOR + +private: + ~nsSupportsArrayEnumerator(); + +protected: + nsISupportsArray* mArray; + PRInt32 mCursor; + +}; + +#endif // __nsSupportsArrayEnumerator_h + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp new file mode 100644 index 00000000..7fe5502a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.cpp @@ -0,0 +1,880 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSupportsPrimitives.h" +#include "nsCRT.h" +#include "nsMemory.h" +#include "prprf.h" +#include "nsIInterfaceInfoManager.h" +#include "nsDependentString.h" +#include "nsReadableUtils.h" +#include "nsPromiseFlatString.h" + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsIDImpl, nsISupportsID, nsISupportsPrimitive) + +nsSupportsIDImpl::nsSupportsIDImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsIDImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_ID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::GetData(nsID **aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + if(mData) + { + *aData = (nsID*) nsMemory::Clone(mData, sizeof(nsID)); + return *aData ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::SetData(const nsID *aData) +{ + if(mData) + nsMemory::Free(mData); + if(aData) + mData = (nsID*) nsMemory::Clone(aData, sizeof(nsID)); + else + mData = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsIDImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + if(mData) + { + result = mData->ToString(); + } + else + { + static const char nullStr[] = "null"; + result = (char*) nsMemory::Clone(nullStr, sizeof(nullStr)); + } + + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************** + * nsSupportsCStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCStringImpl, nsISupportsCString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsCStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::ToString(char **_retval) +{ + *_retval = ToNewCString(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCStringImpl::SetData(const nsACString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************** + * nsSupportsStringImpl + *****************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsStringImpl, nsISupportsString, + nsISupportsPrimitive) + +NS_IMETHODIMP nsSupportsStringImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + + *aType = TYPE_STRING; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::GetData(nsAString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::ToString(PRUnichar **_retval) +{ + *_retval = ToNewUnicode(mData); + + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsStringImpl::SetData(const nsAString& aData) +{ + mData = aData; + return NS_OK; +} + +/***************************************************************************/ + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsPRBoolImpl, nsISupportsPRBool, + nsISupportsPrimitive) + +nsSupportsPRBoolImpl::nsSupportsPRBoolImpl() + : mData(PR_FALSE) +{ +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRBOOL; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::GetData(PRBool *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::SetData(PRBool aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRBoolImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + const char * str = mData ? "true" : "false"; + char* result = (char*) nsMemory::Clone(str, + (strlen(str)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint8Impl, nsISupportsPRUint8, + nsISupportsPrimitive) + +nsSupportsPRUint8Impl::nsSupportsPRUint8Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT8; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::GetData(PRUint8 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::SetData(PRUint8 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint8Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (PRUint16) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint16Impl, nsISupportsPRUint16, + nsISupportsPrimitive) + +nsSupportsPRUint16Impl::nsSupportsPRUint16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::GetData(PRUint16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::SetData(PRUint16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%u", (int) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint32Impl, nsISupportsPRUint32, + nsISupportsPrimitive) + +nsSupportsPRUint32Impl::nsSupportsPRUint32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::GetData(PRUint32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::SetData(PRUint32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%lu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRUint64Impl, nsISupportsPRUint64, + nsISupportsPrimitive) + +nsSupportsPRUint64Impl::nsSupportsPRUint64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRUINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::GetData(PRUint64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::SetData(PRUint64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRUint64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRTimeImpl, nsISupportsPRTime, + nsISupportsPrimitive) + +nsSupportsPRTimeImpl::nsSupportsPRTimeImpl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRTIME; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::GetData(PRTime *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::SetData(PRTime aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRTimeImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%llu", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsCharImpl, nsISupportsChar, + nsISupportsPrimitive) + +nsSupportsCharImpl::nsSupportsCharImpl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsCharImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_CHAR; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::GetData(char *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::SetData(char aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsCharImpl::ToString(char **_retval) +{ + char* result; + NS_ASSERTION(_retval, "Bad pointer"); + + if(nsnull != (result = (char*) nsMemory::Alloc(2*sizeof(char)))) + { + result[0] = mData; + result[1] = '\0'; + } + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt16Impl, nsISupportsPRInt16, + nsISupportsPrimitive) + +nsSupportsPRInt16Impl::nsSupportsPRInt16Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT16; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::GetData(PRInt16 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::SetData(PRInt16 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt16Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 8; + char buf[size]; + + PR_snprintf(buf, size, "%d", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt32Impl, nsISupportsPRInt32, + nsISupportsPrimitive) + +nsSupportsPRInt32Impl::nsSupportsPRInt32Impl() + : mData(0) +{ +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT32; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::GetData(PRInt32 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::SetData(PRInt32 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt32Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 16; + char buf[size]; + + PR_snprintf(buf, size, "%ld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsPRInt64Impl, nsISupportsPRInt64, + nsISupportsPrimitive) + +nsSupportsPRInt64Impl::nsSupportsPRInt64Impl() + : mData(LL_ZERO) +{ +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_PRINT64; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::GetData(PRInt64 *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::SetData(PRInt64 aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsPRInt64Impl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%lld", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsFloatImpl, nsISupportsFloat, + nsISupportsPrimitive) + +nsSupportsFloatImpl::nsSupportsFloatImpl() + : mData(float(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_FLOAT; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::GetData(float *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::SetData(float aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsFloatImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", (double) mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDoubleImpl, nsISupportsDouble, + nsISupportsPrimitive) + +nsSupportsDoubleImpl::nsSupportsDoubleImpl() + : mData(double(0.0)) +{ +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_DOUBLE; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::GetData(double *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::SetData(double aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsDoubleImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + static const int size = 32; + char buf[size]; + + PR_snprintf(buf, size, "%f", mData); + + char* result = (char*) nsMemory::Clone(buf, + (strlen(buf)+1)*sizeof(char)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsVoidImpl, nsISupportsVoid, + nsISupportsPrimitive) + +nsSupportsVoidImpl::nsSupportsVoidImpl() + : mData(nsnull) +{ +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_VOID; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::GetData(void * *aData) +{ + NS_ASSERTION(aData, "Bad pointer"); + *aData = mData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::SetData(void * aData) +{ + mData = aData; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsVoidImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[raw data]"; + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsSupportsInterfacePointerImpl, + nsISupportsInterfacePointer, + nsISupportsPrimitive) + +nsSupportsInterfacePointerImpl::nsSupportsInterfacePointerImpl() + : mIID(nsnull) +{ +} + +nsSupportsInterfacePointerImpl::~nsSupportsInterfacePointerImpl() +{ + if (mIID) { + nsMemory::Free(mIID); + } +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetType(PRUint16 *aType) +{ + NS_ASSERTION(aType, "Bad pointer"); + *aType = TYPE_INTERFACE_POINTER; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetData(nsISupports **aData) +{ + NS_ASSERTION(aData,"Bad pointer"); + + *aData = mData; + NS_IF_ADDREF(*aData); + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetData(nsISupports * aData) +{ + mData = aData; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::GetDataIID(nsID **aIID) +{ + NS_ASSERTION(aIID,"Bad pointer"); + + if(mIID) + { + *aIID = (nsID*) nsMemory::Clone(mIID, sizeof(nsID)); + return *aIID ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + *aIID = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::SetDataIID(const nsID *aIID) +{ + if(mIID) + nsMemory::Free(mIID); + if(aIID) + mIID = (nsID*) nsMemory::Clone(aIID, sizeof(nsID)); + else + mIID = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP nsSupportsInterfacePointerImpl::ToString(char **_retval) +{ + NS_ASSERTION(_retval, "Bad pointer"); + + static const char str[] = "[interface pointer]"; + + // jband sez: think about asking nsIInterfaceInfoManager whether + // the interface has a known human-readable name + char* result = (char*) nsMemory::Clone(str, sizeof(str)); + *_retval = result; + return result ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/***************************************************************************/ + +NS_IMPL_ISUPPORTS2(nsSupportsDependentCString,nsISupportsCString,nsISupportsPrimitive) + +nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr) + : mData(aStr) +{ } + +NS_IMETHODIMP +nsSupportsDependentCString::GetType(PRUint16 *aType) +{ + NS_ENSURE_ARG_POINTER(aType); + + *aType = TYPE_CSTRING; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::GetData(nsACString& aData) +{ + aData = mData; + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::ToString(char **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = ToNewCString(mData); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +NS_IMETHODIMP +nsSupportsDependentCString::SetData(const nsACString& aData) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h new file mode 100644 index 00000000..81e83fa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsSupportsPrimitives.h @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Rosen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsSupportsPrimitives_h__ +#define nsSupportsPrimitives_h__ + +#include "nsISupportsPrimitives.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsDependentString.h" + +class nsSupportsIDImpl : public nsISupportsID +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSID + + nsSupportsIDImpl(); + +private: + ~nsSupportsIDImpl() { } + + nsID *mData; +}; + +/***************************************************************************/ + +class nsSupportsCStringImpl : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsCStringImpl() {} + +private: + ~nsSupportsCStringImpl() {} + + nsCString mData; +}; + +/***************************************************************************/ + +class nsSupportsStringImpl : public nsISupportsString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSSTRING + + nsSupportsStringImpl() {} + +private: + ~nsSupportsStringImpl() {} + + nsString mData; +}; + +/***************************************************************************/ + +class nsSupportsPRBoolImpl : public nsISupportsPRBool +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRBOOL + + nsSupportsPRBoolImpl(); + +private: + ~nsSupportsPRBoolImpl() {} + + PRBool mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint8Impl : public nsISupportsPRUint8 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT8 + + nsSupportsPRUint8Impl(); + +private: + ~nsSupportsPRUint8Impl() {} + + PRUint8 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint16Impl : public nsISupportsPRUint16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT16 + + nsSupportsPRUint16Impl(); + +private: + ~nsSupportsPRUint16Impl() {} + + PRUint16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint32Impl : public nsISupportsPRUint32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT32 + + nsSupportsPRUint32Impl(); + +private: + ~nsSupportsPRUint32Impl() {} + + PRUint32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRUint64Impl : public nsISupportsPRUint64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRUINT64 + + nsSupportsPRUint64Impl(); + +private: + ~nsSupportsPRUint64Impl() {} + + PRUint64 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRTimeImpl : public nsISupportsPRTime +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRTIME + + nsSupportsPRTimeImpl(); + +private: + ~nsSupportsPRTimeImpl() {} + + PRTime mData; +}; + +/***************************************************************************/ + +class nsSupportsCharImpl : public nsISupportsChar +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCHAR + + nsSupportsCharImpl(); + +private: + ~nsSupportsCharImpl() {} + + char mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt16Impl : public nsISupportsPRInt16 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT16 + + nsSupportsPRInt16Impl(); + +private: + ~nsSupportsPRInt16Impl() {} + + PRInt16 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt32Impl : public nsISupportsPRInt32 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT32 + + nsSupportsPRInt32Impl(); + +private: + ~nsSupportsPRInt32Impl() {} + + PRInt32 mData; +}; + +/***************************************************************************/ + +class nsSupportsPRInt64Impl : public nsISupportsPRInt64 +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSPRINT64 + + nsSupportsPRInt64Impl(); + +private: + ~nsSupportsPRInt64Impl() {} + + PRInt64 mData; +}; + +/***************************************************************************/ + +class nsSupportsFloatImpl : public nsISupportsFloat +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSFLOAT + + nsSupportsFloatImpl(); + +private: + ~nsSupportsFloatImpl() {} + + float mData; +}; + +/***************************************************************************/ + +class nsSupportsDoubleImpl : public nsISupportsDouble +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSDOUBLE + + nsSupportsDoubleImpl(); + +private: + ~nsSupportsDoubleImpl() {} + + double mData; +}; + +/***************************************************************************/ + +class nsSupportsVoidImpl : public nsISupportsVoid +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSVOID + + nsSupportsVoidImpl(); + +private: + ~nsSupportsVoidImpl() {} + + void* mData; +}; + +/***************************************************************************/ + +class nsSupportsInterfacePointerImpl : public nsISupportsInterfacePointer +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSINTERFACEPOINTER + + nsSupportsInterfacePointerImpl(); + +private: + ~nsSupportsInterfacePointerImpl(); + + nsCOMPtr mData; + nsID *mIID; +}; + +/***************************************************************************/ + +/** + * Wraps a static const char* buffer for use with nsISupportsCString + * + * Only use this class with static buffers, or arena-allocated buffers of + * permanent lifetime! + */ +class nsSupportsDependentCString : public nsISupportsCString +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISUPPORTSPRIMITIVE + NS_DECL_NSISUPPORTSCSTRING + + nsSupportsDependentCString(const char* aStr); + +private: + ~nsSupportsDependentCString() {} + + nsDependentCString mData; +}; + +#endif /* nsSupportsPrimitives_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp new file mode 100644 index 00000000..37fa998f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 "nsTHashtable.h" +#include "nsHashKeys.h" + +PR_IMPLEMENT(PLDHashOperator) +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userarg) +{ + return PL_DHASH_REMOVE; +} + +PRUint32 nsIDHashKey::HashKey(const nsID* id) +{ + PRUint32 h = id->m0; + PRUint32 i; + + h = (h>>28) ^ (h<<4) ^ id->m1; + h = (h>>28) ^ (h<<4) ^ id->m2; + + for (i = 0; i < 8; i++) + h = (h>>28) ^ (h<<4) ^ id->m3[i]; + + return h; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h new file mode 100644 index 00000000..1e55ada6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTHashtable.h @@ -0,0 +1,429 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 nsTHashtable_h__ +#define nsTHashtable_h__ + +#include "nscore.h" +#include "pldhash.h" +#include "nsDebug.h" +#include NEW_H + +// helper function for nsTHashtable::Clear() +PR_EXTERN(PLDHashOperator) PR_CALLBACK +PL_DHashStubEnumRemove(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 ordinal, + void *userArg); + + +/** + * a base class for templated hashtables. + * + * Clients will rarely need to use this class directly. Check the derived + * classes first, to see if they will meet your needs. + * + * @param EntryType the templated entry-type class that is managed by the + * hashtable. EntryType must extend the following declaration, + * and must not declare any virtual functions or derive from classes + * with virtual functions. Any vtable pointer would break the + * PLDHashTable code. + *

   class EntryType : public PLDHashEntryHdr
+ *   {
+ *   public: or friend nsTHashtable;
+ *     // KeyType is what we use when Get()ing or Put()ing this entry
+ *     // this should either be a simple datatype (PRUint32, nsISupports*) or
+ *     // a const reference (const nsAString&)
+ *     typedef something KeyType;
+ *     // KeyTypePointer is the pointer-version of KeyType, because pldhash.h
+ *     // requires keys to cast to const void*
+ *     typedef const something* KeyTypePointer;
+ *
+ *     EntryType(KeyTypePointer aKey);
+ *
+ *     // the copy constructor must be defined, even if AllowMemMove() == true
+ *     // or you will cause link errors!
+ *     EntryType(const EntryType& aEnt);
+ *
+ *     // the destructor must be defined... or you will cause link errors!
+ *     ~EntryType();
+ *
+ *     // return the key of this entry
+ *     const KeyTypePointer GetKeyPointer() const;
+ *
+ *     // KeyEquals(): does this entry match this key?
+ *     PRBool KeyEquals(KeyTypePointer aKey) const;
+ *
+ *     // KeyToPointer(): Convert KeyType to KeyTypePointer
+ *     static KeyTypePointer KeyToPointer(KeyType aKey);
+ *
+ *     // HashKey(): calculate the hash number
+ *     static PLDHashNumber HashKey(KeyTypePointer aKey);
+ *
+ *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
+ *     // to use the copy constructor?
+ *     enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) };
+ *   }
+ * + * @see nsInterfaceHashtable + * @see nsDataHashtable + * @see nsClassHashtable + * @author "Benjamin Smedberg " + */ + +template +class nsTHashtable +{ +public: + /** + * A dummy constructor; you must call Init() before using this class. + */ + nsTHashtable(); + + /** + * destructor, cleans up and deallocates + */ + ~nsTHashtable(); + + /** + * Initialize the table. This function must be called before any other + * class operations. This can fail due to OOM conditions. + * @param initSize the initial number of buckets in the hashtable, default 16 + * @return PR_TRUE if the class was initialized properly. + */ + PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); + + /** + * Check whether the table has been initialized. This can be useful for static hashtables. + * @return the initialization state of the class. + */ + PRBool IsInitialized() const { return mTable.entrySize; } + + /** + * KeyType is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyType KeyType; + + /** + * KeyTypePointer is typedef'ed for ease of use. + */ + typedef typename EntryType::KeyTypePointer KeyTypePointer; + + /** + * Return the number of entries in the table. + * @return number of entries + */ + PRUint32 Count() const { return mTable.entryCount; } + + /** + * Get the entry associated with a key. + * @param aKey the key to retrieve + * @return pointer to the entry class, if the key exists; nsnull if the + * key doesn't exist + */ + EntryType* GetEntry(KeyType aKey) const + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + EntryType* entry = + NS_REINTERPRET_CAST(EntryType*, + PL_DHashTableOperate( + NS_CONST_CAST(PLDHashTable*,&mTable), + EntryType::KeyToPointer(aKey), + PL_DHASH_LOOKUP)); + return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nsnull; + } + + /** + * Get the entry associated with a key, or create a new entry, + * @param aKey the key to retrieve + * @return pointer to the entry class retreived; nsnull only if memory + can't be allocated + */ + EntryType* PutEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + return NS_STATIC_CAST(EntryType*, + PL_DHashTableOperate( + &mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_ADD)); + } + + /** + * Remove the entry associated with a key. + * @param aKey of the entry to remove + */ + void RemoveEntry(KeyType aKey) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableOperate(&mTable, + EntryType::KeyToPointer(aKey), + PL_DHASH_REMOVE); + } + + /** + * Remove the entry associated with a key, but don't resize the hashtable. + * This is a low-level method, and is not recommended unless you know what + * you're doing and you need the extra performance. This method can be used + * during enumeration, while RemoveEntry() cannot. + * @param aEntry the entry-pointer to remove (obtained from GetEntry or + * the enumerator + */ + void RawRemoveEntry(EntryType* aEntry) + { + PL_DHashTableRawRemove(&mTable, aEntry); + } + + /** + * client must provide an Enumerator function for + * EnumerateEntries + * @param aEntry the entry being enumerated + * @param userArg passed unchanged from EnumerateEntries + * @return combination of flags + * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink , + * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink , + * @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink + */ + typedef PLDHashOperator (*PR_CALLBACK Enumerator)(EntryType* aEntry, void* userArg); + + /** + * Enumerate all the entries of the function. + * @param enumFunc the Enumerator function to call + * @param userArg a pointer to pass to the + * Enumerator function + * @return the number of entries actually enumerated + */ + PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg) + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + s_EnumArgs args = { enumFunc, userArg }; + return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args); + } + + /** + * remove all entries, return hashtable to "pristine" state ;) + */ + void Clear() + { + NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); + + PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull); + } + +protected: + PLDHashTable mTable; + + static const void* PR_CALLBACK s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PLDHashNumber PR_CALLBACK s_HashKey(PLDHashTable *table, + const void *key); + + static PRBool PR_CALLBACK s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + + static void PR_CALLBACK s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + + static void PR_CALLBACK s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry); + + static PRBool PR_CALLBACK s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + + /** + * passed internally during enumeration. Allocated on the stack. + * + * @param userFunc the Enumerator function passed to + * EnumerateEntries by the client + * @param userArg the userArg passed unaltered + */ + struct s_EnumArgs + { + Enumerator userFunc; + void* userArg; + }; + + static PLDHashOperator PR_CALLBACK s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg); +private: + // copy constructor, not implemented + nsTHashtable(nsTHashtable& toCopy); + + // assignment operator, not implemented + nsTHashtable& operator= (nsTHashtable& toEqual); +}; + +// +// template definitions +// + +template +nsTHashtable::nsTHashtable() +{ + // entrySize is our "I'm initialized" indicator + mTable.entrySize = 0; +} + +template +nsTHashtable::~nsTHashtable() +{ + if (mTable.entrySize) + PL_DHashTableFinish(&mTable); +} + +template +PRBool +nsTHashtable::Init(PRUint32 initSize) +{ + if (mTable.entrySize) + { + NS_ERROR("nsTHashtable::Init() should not be called twice."); + return PR_TRUE; + } + + static PLDHashTableOps sOps = + { + ::PL_DHashAllocTable, + ::PL_DHashFreeTable, + s_GetKey, + s_HashKey, + s_MatchEntry, + ::PL_DHashMoveEntryStub, + s_ClearEntry, + ::PL_DHashFinalizeStub, + s_InitEntry + }; + + if (!EntryType::ALLOW_MEMMOVE) + { + sOps.moveEntry = s_CopyEntry; + } + + if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize)) + { + // if failed, reset "flag" + mTable.entrySize = 0; + return PR_FALSE; + } + + return PR_TRUE; +} + +// static definitions + +template +const void* +nsTHashtable::s_GetKey(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + return ((EntryType*) entry)->GetKeyPointer(); +} + +template +PLDHashNumber +nsTHashtable::s_HashKey(PLDHashTable *table, + const void *key) +{ + return EntryType::HashKey(NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template +PRBool +nsTHashtable::s_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + return ((const EntryType*) entry)->KeyEquals( + NS_REINTERPRET_CAST(const KeyTypePointer, key)); +} + +template +void +nsTHashtable::s_CopyEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + EntryType* fromEntry = + NS_CONST_CAST(EntryType*, NS_REINTERPRET_CAST(const EntryType*, from)); + + new(to) EntryType(*fromEntry); + + fromEntry->~EntryType(); +} + +template +void +nsTHashtable::s_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + NS_REINTERPRET_CAST(EntryType*,entry)->~EntryType(); +} + +template +PRBool +nsTHashtable::s_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key) +{ + new(entry) EntryType(NS_REINTERPRET_CAST(KeyTypePointer,key)); + return PR_TRUE; +} + +template +PLDHashOperator +nsTHashtable::s_EnumStub(PLDHashTable *table, + PLDHashEntryHdr *entry, + PRUint32 number, + void *arg) +{ + // dereferences the function-pointer to the user's enumeration function + return (* NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userFunc)( + NS_REINTERPRET_CAST(EntryType*,entry), + NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userArg); +} + +#endif // nsTHashtable_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp new file mode 100644 index 00000000..a5f2dde0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTextFormatter.cpp @@ -0,0 +1,1557 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Portable safe sprintf code. + * + * Code based on mozilla/nsprpub/src/io/prprf.c rev 3.7 + * + * Contributor(s): + * Kipp E.B. Hickman (original author) + * Frank Yung-Fong Tang + * Daniele Nicolodi + */ + +#include +#include +#include +#include +#include "prdtoa.h" +#include "prlong.h" +#include "prlog.h" +#include "prmem.h" +#include "prprf.h" +#include "nsCRT.h" +#include "nsTextFormatter.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/* +** Note: on some platforms va_list is defined as an array, +** and requires array notation. +*/ + +#ifdef HAVE_VA_COPY +#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) +#elif defined(HAVE_VA_LIST_AS_ARRAY) +#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] +#else +#define VARARGS_ASSIGN(foo, bar) (foo) = (bar) +#endif + +typedef struct SprintfStateStr SprintfState; + +struct SprintfStateStr { + int (*stuff)(SprintfState *ss, const PRUnichar *sp, PRUint32 len); + + PRUnichar *base; + PRUnichar *cur; + PRUint32 maxlen; + + void *stuffclosure; +}; + +/* +** Numbered Arguement State +*/ +struct NumArgState{ + int type; /* type of the current ap */ + va_list ap; /* point to the corresponding position on ap */ +}; + +#define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */ + +#define TYPE_INT16 0 +#define TYPE_UINT16 1 +#define TYPE_INTN 2 +#define TYPE_UINTN 3 +#define TYPE_INT32 4 +#define TYPE_UINT32 5 +#define TYPE_INT64 6 +#define TYPE_UINT64 7 +#define TYPE_STRING 8 +#define TYPE_DOUBLE 9 +#define TYPE_INTSTR 10 +#define TYPE_UNISTRING 11 +#define TYPE_UNKNOWN 20 + +#define _LEFT 0x1 +#define _SIGNED 0x2 +#define _SPACED 0x4 +#define _ZEROS 0x8 +#define _NEG 0x10 + +#define ELEMENTS_OF(array_) (sizeof(array_) / sizeof(array_[0])) + +// Warning: if aDest isn't big enough this function returns the converted +// string in allocated memory which must be freed using PR_FREE(). +// May return nsnull if memory couldn't be allocated. +static PRUnichar* UTF8ToUCS2(const char *aSrc, PRUint32 aSrcLen, + PRUnichar* aDest, PRUint32 aDestLen) +{ + const char *in, *inend; + inend = aSrc + aSrcLen; + PRUnichar *out; + PRUint32 state; + PRUint32 ucs4; + // decide the length of the UCS2 first. + PRUint32 needLen = 0; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + needLen++; + } else if (0xC0 == (0xE0 & (*in))) { + needLen++; + state = 1; + } else if (0xE0 == (0xF0 & (*in))) { + needLen++; + state = 2; + } else if (0xF0 == (0xF8 & (*in))) { + needLen+=2; + state = 3; + } else if (0xF8 == (0xFC & (*in))) { + needLen+=2; + state = 4; + } else if (0xFC == (0xFE & (*in))) { + needLen+=2; + state = 5; + } else { + needLen++; + state = 0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if(0x80 == (0xC0 & (*in))) { + state--; + } else { + state = 0; + } + } + } + needLen++; // add null termination. + + // allocates sufficient memory if aDest is not big enough. + if (needLen > aDestLen) { + aDest = (PRUnichar*)PR_MALLOC(sizeof(PRUnichar) * needLen); + } + if (nsnull == aDest) { + return nsnull; + } + out = aDest; + + for (in = aSrc, state = 0, ucs4 = 0; in < inend; in++) { + if (0 == state) { + if (0 == (0x80 & (*in))) { + // ASCII + *out++ = (PRUnichar)*in; + } else if (0xC0 == (0xE0 & (*in))) { + // 2 bytes UTF8 + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 6) & 0x000007C0L; + state=1; + } else if (0xE0 == (0xF0 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 12) & 0x0000F000L; + state=2; + } else if (0xF0 == (0xF8 & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 18) & 0x001F0000L; + state=3; + } else if (0xF8 == (0xFC & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 24) & 0x03000000L; + state=4; + } else if (0xFC == (0xFE & (*in))) { + ucs4 = (PRUint32)(*in); + ucs4 = (ucs4 << 30) & 0x40000000L; + state=5; + } else { + NS_ASSERTION(0, "The input string is not in utf8"); + state=0; + ucs4=0; + } + } else { + NS_ASSERTION((0x80 == (0xC0 & (*in))), "The input string is not in utf8"); + if (0x80 == (0xC0 & (*in))) { + PRUint32 tmp = (*in); + int shift = --state * 6; + tmp = (tmp << shift) & (0x0000003FL << shift); + ucs4 |= tmp; + if (0 == state) { + if (ucs4 >= 0x00010000) { + if (ucs4 >= 0x00110000) { + *out++ = 0xFFFD; + } else { + ucs4 -= 0x00010000; + *out++ = 0xD800 | (0x000003FF & (ucs4 >> 10)); + *out++ = 0xDC00 | (0x000003FF & ucs4); + } + } else { + *out++ = ucs4; + } + ucs4 = 0; + } + } else { + state = 0; + ucs4 = 0; + } + } + } + *out = 0x0000; + return aDest; +} + +/* +** Fill into the buffer using the data in src +*/ +static int fill2(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int flags) +{ + PRUnichar space = ' '; + int rv; + + width -= srclen; + /* Right adjusting */ + if ((width > 0) && ((flags & _LEFT) == 0)) { + if (flags & _ZEROS) { + space = '0'; + } + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Copy out the source data */ + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + + /* Left adjusting */ + if ((width > 0) && ((flags & _LEFT) != 0)) { + while (--width >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + return 0; +} + +/* +** Fill a number. The order is: optional-sign zero-filling conversion-digits +*/ +static int fill_n(SprintfState *ss, const PRUnichar *src, int srclen, + int width, int prec, int type, int flags) +{ + int zerowidth = 0; + int precwidth = 0; + int signwidth = 0; + int leftspaces = 0; + int rightspaces = 0; + int cvtwidth; + int rv; + PRUnichar sign; + PRUnichar space = ' '; + PRUnichar zero = '0'; + + if ((type & 1) == 0) { + if (flags & _NEG) { + sign = '-'; + signwidth = 1; + } else if (flags & _SIGNED) { + sign = '+'; + signwidth = 1; + } else if (flags & _SPACED) { + sign = ' '; + signwidth = 1; + } + } + cvtwidth = signwidth + srclen; + + if (prec > 0) { + if (prec > srclen) { + /* Need zero filling */ + precwidth = prec - srclen; + cvtwidth += precwidth; + } + } + + if ((flags & _ZEROS) && (prec < 0)) { + if (width > cvtwidth) { + /* Zero filling */ + zerowidth = width - cvtwidth; + cvtwidth += zerowidth; + } + } + + if (flags & _LEFT) { + if (width > cvtwidth) { + /* Space filling on the right (i.e. left adjusting) */ + rightspaces = width - cvtwidth; + } + } else { + if (width > cvtwidth) { + /* Space filling on the left (i.e. right adjusting) */ + leftspaces = width - cvtwidth; + } + } + while (--leftspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + if (signwidth) { + rv = (*ss->stuff)(ss, &sign, 1); + if (rv < 0) { + return rv; + } + } + while (--precwidth >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + while (--zerowidth >= 0) { + rv = (*ss->stuff)(ss, &zero, 1); + if (rv < 0) { + return rv; + } + } + rv = (*ss->stuff)(ss, src, srclen); + if (rv < 0) { + return rv; + } + while (--rightspaces >= 0) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + return 0; +} + +/* +** Convert a long into its printable form +*/ +static int cvt_l(SprintfState *ss, long num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (num == 0)) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (num) { + int digit = (((unsigned long)num) % radix) & 0xF; + *--cvt = hexp[digit]; + digits++; + num = (long)(((unsigned long)num) / radix); + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a 64-bit integer into its printable form +*/ +static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, + int radix, int type, int flags, const PRUnichar *hexp) +{ + PRUnichar cvtbuf[100]; + PRUnichar *cvt; + int digits; + PRInt64 rad; + + /* according to the man page this needs to happen */ + if ((prec == 0) && (LL_IS_ZERO(num))) { + return 0; + } + + /* + ** Converting decimal is a little tricky. In the unsigned case we + ** need to stop when we hit 10 digits. In the signed case, we can + ** stop when the number is zero. + */ + LL_I2L(rad, radix); + cvt = &cvtbuf[0] + ELEMENTS_OF(cvtbuf); + digits = 0; + while (!LL_IS_ZERO(num)) { + PRInt32 digit; + PRInt64 quot, rem; + LL_UDIVMOD(", &rem, num, rad); + LL_L2I(digit, rem); + *--cvt = hexp[digit & 0xf]; + digits++; + num = quot; + } + if (digits == 0) { + *--cvt = '0'; + digits++; + } + + /* + ** Now that we have the number converted without its sign, deal with + ** the sign and zero padding. + */ + return fill_n(ss, cvt, digits, width, prec, type, flags); +} + +/* +** Convert a double precision floating point number into its printable +** form. +*/ +static int cvt_f(SprintfState *ss, double d, int width, int prec, + const PRUnichar type, int flags) +{ + int mode = 2; + int decpt; + int sign; + char buf[256]; + char * bufp = buf; + int bufsz = 256; + char num[256]; + char * nump; + char * endnum; + int numdigits = 0; + char exp = 'e'; + + if (prec == -1) { + prec = 6; + } else if (prec > 50) { + // limit precision to avoid PR_dtoa bug 108335 + // and to prevent buffers overflows + prec = 50; + } + + switch (type) { + case 'f': + numdigits = prec; + mode = 3; + break; + case 'E': + exp = 'E'; + // no break + case 'e': + numdigits = prec + 1; + mode = 2; + break; + case 'G': + exp = 'E'; + // no break + case 'g': + if (prec == 0) { + prec = 1; + } + numdigits = prec; + mode = 2; + break; + default: + NS_ERROR("invalid type passed to cvt_f"); + } + + if (PR_dtoa(d, mode, numdigits, &decpt, &sign, &endnum, num, bufsz) == PR_FAILURE) { + buf[0] = '\0'; + return -1; + } + numdigits = endnum - num; + nump = num; + + if (sign) { + *bufp++ = '-'; + } else if (flags & _SIGNED) { + *bufp++ = '+'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++)) { } + } else { + + switch (type) { + + case 'E': + case 'e': + + *bufp++ = *nump++; + if (prec > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + prec--; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + break; + + case 'f': + + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++ && prec-- > 0) { + *bufp++ = '0'; + } + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (prec > 0) { + *bufp++ = '.'; + while (*nump && prec-- > 0) { + *bufp++ = *nump++; + } + while (prec-- > 0) { + *bufp++ = '0'; + } + } + } + *bufp = '\0'; + break; + + case 'G': + case 'g': + + if ((decpt < -3) || ((decpt - 1) >= prec)) { + *bufp++ = *nump++; + numdigits--; + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + *bufp++ = exp; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+03d", decpt-1); + } else { + if (decpt < 1) { + *bufp++ = '0'; + if (prec > 0) { + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + while (*nump) { + *bufp++ = *nump++; + } + } + } else { + while (*nump && decpt-- > 0) { + *bufp++ = *nump++; + numdigits--; + } + while (decpt-- > 0) { + *bufp++ = '0'; + } + if (numdigits > 0) { + *bufp++ = '.'; + while (*nump) { + *bufp++ = *nump++; + } + } + } + *bufp = '\0'; + } + } + } + + PRUnichar rbuf[256]; + PRUnichar *rbufp = rbuf; + bufp = buf; + // cast to PRUnichar + while ((*rbufp++ = *bufp++)) { } + *rbufp = '\0'; + + return fill2(ss, rbuf, nsCRT::strlen(rbuf), width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_S(SprintfState *ss, const PRUnichar *s, int width, + int prec, int flags) +{ + int slen; + + if (prec == 0) { + return 0; + } + + /* Limit string length by precision value */ + slen = s ? nsCRT::strlen(s) : 6; + if (prec > 0) { + if (prec < slen) { + slen = prec; + } + } + + /* and away we go */ + NS_NAMED_LITERAL_STRING(nullstr, "(null)"); + + return fill2(ss, s ? s : nullstr.get(), slen, width, flags); +} + +/* +** Convert a string into its printable form. "width" is the output +** width. "prec" is the maximum number of characters of "s" to output, +** where -1 means until NUL. +*/ +static int cvt_s(SprintfState *ss, const char *s, int width, + int prec, int flags) +{ + // convert s from UTF8 to PRUnichar* + // Fix me !!! + PRUnichar buf[256]; + PRUnichar *retbuf = nsnull; + + if (s) { + retbuf = UTF8ToUCS2(s, strlen(s), buf, 256); + if(nsnull == retbuf) { + return -1; + } + } + int ret = cvt_S(ss, retbuf, width, prec, flags); + + if (retbuf != buf) { + PR_DELETE(retbuf); + } + return ret; +} + +/* +** BiuldArgArray stands for Numbered Argument list Sprintf +** for example, +** fmp = "%4$i, %2$d, %3s, %1d"; +** the number must start from 1, and no gap among them +*/ + +static struct NumArgState* BuildArgArray(const PRUnichar *fmt, + va_list ap, int * rv, + struct NumArgState * nasArray) +{ + int number = 0, cn = 0, i; + const PRUnichar* p; + PRUnichar c; + struct NumArgState* nas; + + /* + ** first pass: + ** detemine how many legal % I have got, then allocate space + */ + p = fmt; + *rv = 0; + i = 0; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + /* skip %% case */ + if ((c = *p++) == '%') { + continue; + } + + while( c != 0 ){ + if (c > '9' || c < '0') { + /* numbered argument csae */ + if (c == '$') { + if (i > 0) { + *rv = -1; + return NULL; + } + number++; + break; + + } else { + /* non-numbered argument case */ + if (number > 0) { + *rv = -1; + return NULL; + } + i = 1; + break; + } + } + c = *p++; + } + } + + if (number == 0) { + return NULL; + } + + if (number > NAS_DEFAULT_NUM) { + nas = (struct NumArgState*)PR_MALLOC(number * sizeof(struct NumArgState)); + if (!nas) { + *rv = -1; + return NULL; + } + } else { + nas = nasArray; + } + + for (i = 0; i < number; i++) { + nas[i].type = TYPE_UNKNOWN; + } + + /* + ** second pass: + ** set nas[].type + */ + p = fmt; + while ((c = *p++) != 0) { + if (c != '%') { + continue; + } + c = *p++; + if (c == '%') { + continue; + } + cn = 0; + /* should imporve error check later */ + while (c && c != '$') { + cn = cn*10 + c - '0'; + c = *p++; + } + + if (!c || cn < 1 || cn > number) { + *rv = -1; + break; + } + + /* nas[cn] starts from 0, and make sure + nas[cn].type is not assigned */ + cn--; + if (nas[cn].type != TYPE_UNKNOWN) { + continue; + } + + c = *p++; + + /* width */ + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + + /* precision */ + if (c == '.') { + c = *p++; + if (c == '*') { + /* not supported feature, for the argument is not numbered */ + *rv = -1; + break; + } else { + while ((c >= '0') && (c <= '9')) { + c = *p++; + } + } + } + + /* size */ + nas[cn].type = TYPE_INTN; + if (c == 'h') { + nas[cn].type = TYPE_INT16; + c = *p++; + } else if (c == 'L') { + /* XXX not quite sure here */ + nas[cn].type = TYPE_INT64; + c = *p++; + } else if (c == 'l') { + nas[cn].type = TYPE_INT32; + c = *p++; + if (c == 'l') { + nas[cn].type = TYPE_INT64; + c = *p++; + } + } + + /* format */ + switch (c) { + case 'd': + case 'c': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + break; + + case 'e': + case 'f': + case 'g': + nas[cn].type = TYPE_DOUBLE; + break; + + case 'p': + /* XXX should use cpp */ + if (sizeof(void *) == sizeof(PRInt32)) { + nas[cn].type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + nas[cn].type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(PRIntn)) { + nas[cn].type = TYPE_UINTN; + } else { + nas[cn].type = TYPE_UNKNOWN; + } + break; + + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + + case 'S': + nas[cn].type = TYPE_UNISTRING; + break; + + case 's': + nas[cn].type = TYPE_STRING; + break; + + case 'n': + nas[cn].type = TYPE_INTSTR; + break; + + default: + PR_ASSERT(0); + nas[cn].type = TYPE_UNKNOWN; + break; + } + + /* get a legal para. */ + if (nas[cn].type == TYPE_UNKNOWN) { + *rv = -1; + break; + } + } + + + /* + ** third pass + ** fill the nas[cn].ap + */ + if (*rv < 0) { + if( nas != nasArray ) { + PR_DELETE(nas); + } + return NULL; + } + + cn = 0; + while (cn < number) { + if (nas[cn].type == TYPE_UNKNOWN) { + cn++; + continue; + } + + VARARGS_ASSIGN(nas[cn].ap, ap); + + switch (nas[cn].type) { + case TYPE_INT16: + case TYPE_UINT16: + case TYPE_INTN: + case TYPE_UINTN: (void)va_arg(ap, PRIntn); break; + + case TYPE_INT32: (void)va_arg(ap, PRInt32); break; + + case TYPE_UINT32: (void)va_arg(ap, PRUint32); break; + + case TYPE_INT64: (void)va_arg(ap, PRInt64); break; + + case TYPE_UINT64: (void)va_arg(ap, PRUint64); break; + + case TYPE_STRING: (void)va_arg(ap, char*); break; + + case TYPE_INTSTR: (void)va_arg(ap, PRIntn*); break; + + case TYPE_DOUBLE: (void)va_arg(ap, double); break; + + case TYPE_UNISTRING: (void)va_arg(ap, PRUnichar*); break; + + default: + if( nas != nasArray ) { + PR_DELETE( nas ); + } + *rv = -1; + return NULL; + } + cn++; + } + return nas; +} + +/* +** The workhorse sprintf code. +*/ +static int dosprintf(SprintfState *ss, const PRUnichar *fmt, va_list ap) +{ + PRUnichar c; + int flags, width, prec, radix, type; + union { + PRUnichar ch; + int i; + long l; + PRInt64 ll; + double d; + const char *s; + const PRUnichar *S; + int *ip; + } u; + PRUnichar space = ' '; + const PRUnichar *fmt0; + + nsAutoString hex; + hex.AssignLiteral("0123456789abcdef"); + + nsAutoString HEX; + HEX.AssignLiteral("0123456789ABCDEF"); + + const PRUnichar *hexp; + int rv, i; + struct NumArgState* nas = NULL; + struct NumArgState nasArray[NAS_DEFAULT_NUM]; + /* in "%4$.2f" dolPt will point to . */ + const PRUnichar* dolPt = NULL; + + + /* + ** build an argument array, IF the fmt is numbered argument + ** list style, to contain the Numbered Argument list pointers + */ + nas = BuildArgArray (fmt, ap, &rv, nasArray); + if (rv < 0) { + /* the fmt contains error Numbered Argument format, jliu@netscape.com */ + PR_ASSERT(0); + return rv; + } + + while ((c = *fmt++) != 0) { + if (c != '%') { + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + fmt0 = fmt - 1; + + /* + ** Gobble up the % format string. Hopefully we have handled all + ** of the strange cases! + */ + flags = 0; + c = *fmt++; + if (c == '%') { + /* quoting a % with %% */ + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + continue; + } + + if (nas != NULL) { + /* the fmt contains the Numbered Arguments feature */ + i = 0; + /* should imporve error check later */ + while (c && c != '$') { + i = (i * 10) + (c - '0'); + c = *fmt++; + } + + if (nas[i-1].type == TYPE_UNKNOWN) { + if (nas && (nas != nasArray)) { + PR_DELETE(nas); + } + return -1; + } + + ap = nas[i-1].ap; + dolPt = fmt; + c = *fmt++; + } + + /* + * Examine optional flags. Note that we do not implement the + * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is + * somewhat ambiguous and not ideal, which is perhaps why + * the various sprintf() implementations are inconsistent + * on this feature. + */ + while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) { + if (c == '-') flags |= _LEFT; + if (c == '+') flags |= _SIGNED; + if (c == ' ') flags |= _SPACED; + if (c == '0') flags |= _ZEROS; + c = *fmt++; + } + if (flags & _SIGNED) flags &= ~_SPACED; + if (flags & _LEFT) flags &= ~_ZEROS; + + /* width */ + if (c == '*') { + c = *fmt++; + width = va_arg(ap, int); + } else { + width = 0; + while ((c >= '0') && (c <= '9')) { + width = (width * 10) + (c - '0'); + c = *fmt++; + } + } + + /* precision */ + prec = -1; + if (c == '.') { + c = *fmt++; + if (c == '*') { + c = *fmt++; + prec = va_arg(ap, int); + } else { + prec = 0; + while ((c >= '0') && (c <= '9')) { + prec = (prec * 10) + (c - '0'); + c = *fmt++; + } + } + } + + /* size */ + type = TYPE_INTN; + if (c == 'h') { + type = TYPE_INT16; + c = *fmt++; + } else if (c == 'L') { + /* XXX not quite sure here */ + type = TYPE_INT64; + c = *fmt++; + } else if (c == 'l') { + type = TYPE_INT32; + c = *fmt++; + if (c == 'l') { + type = TYPE_INT64; + c = *fmt++; + } + } + + /* format */ + hexp = hex.get(); + switch (c) { + case 'd': + case 'i': /* decimal/integer */ + radix = 10; + goto fetch_and_convert; + + case 'o': /* octal */ + radix = 8; + type |= 1; + goto fetch_and_convert; + + case 'u': /* unsigned decimal */ + radix = 10; + type |= 1; + goto fetch_and_convert; + + case 'x': /* unsigned hex */ + radix = 16; + type |= 1; + goto fetch_and_convert; + + case 'X': /* unsigned HEX */ + radix = 16; + hexp = HEX.get(); + type |= 1; + goto fetch_and_convert; + + fetch_and_convert: + switch (type) { + case TYPE_INT16: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT16: + u.l = va_arg(ap, int) & 0xffff; + goto do_long; + case TYPE_INTN: + u.l = va_arg(ap, int); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINTN: + u.l = (long)va_arg(ap, unsigned int); + goto do_long; + + case TYPE_INT32: + u.l = va_arg(ap, PRInt32); + if (u.l < 0) { + u.l = -u.l; + flags |= _NEG; + } + goto do_long; + case TYPE_UINT32: + u.l = (long)va_arg(ap, PRUint32); + do_long: + rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + + case TYPE_INT64: + u.ll = va_arg(ap, PRInt64); + if (!LL_GE_ZERO(u.ll)) { + LL_NEG(u.ll, u.ll); + flags |= _NEG; + } + goto do_longlong; + case TYPE_UINT64: + u.ll = va_arg(ap, PRUint64); + do_longlong: + rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp); + if (rv < 0) { + return rv; + } + break; + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + u.d = va_arg(ap, double); + rv = cvt_f(ss, u.d, width, prec, c, flags); + if (rv < 0) { + return rv; + } + break; + + case 'c': + u.ch = va_arg(ap, int); + if ((flags & _LEFT) == 0) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + rv = (*ss->stuff)(ss, &u.ch, 1); + if (rv < 0) { + return rv; + } + if (flags & _LEFT) { + while (width-- > 1) { + rv = (*ss->stuff)(ss, &space, 1); + if (rv < 0) { + return rv; + } + } + } + break; + + case 'p': + if (sizeof(void *) == sizeof(PRInt32)) { + type = TYPE_UINT32; + } else if (sizeof(void *) == sizeof(PRInt64)) { + type = TYPE_UINT64; + } else if (sizeof(void *) == sizeof(int)) { + type = TYPE_UINTN; + } else { + PR_ASSERT(0); + break; + } + radix = 16; + goto fetch_and_convert; + +#if 0 + case 'C': + /* XXX not supported I suppose */ + PR_ASSERT(0); + break; +#endif + + case 'S': + u.S = va_arg(ap, const PRUnichar*); + rv = cvt_S(ss, u.S, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 's': + u.s = va_arg(ap, const char*); + rv = cvt_s(ss, u.s, width, prec, flags); + if (rv < 0) { + return rv; + } + break; + + case 'n': + u.ip = va_arg(ap, int*); + if (u.ip) { + *u.ip = ss->cur - ss->base; + } + break; + + default: + /* Not a % token after all... skip it */ +#if 0 + PR_ASSERT(0); +#endif + PRUnichar perct = '%'; + rv = (*ss->stuff)(ss, &perct, 1); + if (rv < 0) { + return rv; + } + rv = (*ss->stuff)(ss, fmt - 1, 1); + if (rv < 0) { + return rv; + } + } + } + + /* Stuff trailing NUL */ + PRUnichar null = '\0'; + + rv = (*ss->stuff)(ss, &null, 1); + + if( nas && ( nas != nasArray ) ){ + PR_DELETE( nas ); + } + + return rv; +} + +/************************************************************************/ + +static int +StringStuff(SprintfState* ss, const PRUnichar* sp, PRUint32 len) +{ + ptrdiff_t off = ss->cur - ss->base; + + nsAString* str = NS_STATIC_CAST(nsAString*,ss->stuffclosure); + str->Append(sp, len); + + // we can assume contiguous storage + nsAString::iterator begin; + str->BeginWriting(begin); + ss->base = begin.get(); + ss->cur = ss->base + off; + + return 0; +} + +/* +** Stuff routine that automatically grows the malloc'd output buffer +** before it overflows. +*/ +static int GrowStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + ptrdiff_t off; + PRUnichar *newbase; + PRUint32 newlen; + + off = ss->cur - ss->base; + if (off + len >= ss->maxlen) { + /* Grow the buffer */ + newlen = ss->maxlen + ((len > 32) ? len : 32); + if (ss->base) { + newbase = (PRUnichar*) PR_REALLOC(ss->base, newlen*sizeof(PRUnichar)); + } else { + newbase = (PRUnichar*) PR_MALLOC(newlen*sizeof(PRUnichar)); + } + if (!newbase) { + /* Ran out of memory */ + return -1; + } + ss->base = newbase; + ss->maxlen = newlen; + ss->cur = ss->base + off; + } + + /* Copy data */ + while (len) { + --len; + *ss->cur++ = *sp++; + } + PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen); + return 0; +} + +/* +** sprintf into a malloc'd buffer +*/ +PRUnichar * nsTextFormatter::smprintf(const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsmprintf(fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::ssprintf(nsAString& out, const PRUnichar* fmt, ...) +{ + va_list ap; + PRUint32 rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vssprintf(out, fmt, ap); + va_end(ap); + return rv; +} + +/* +** Free memory allocated, for the caller, by smprintf +*/ +void nsTextFormatter::smprintf_free(PRUnichar *mem) +{ + PR_DELETE(mem); +} + +PRUint32 nsTextFormatter::vssprintf(nsAString& out, const PRUnichar* fmt, va_list ap) +{ + SprintfState ss; + ss.stuff = StringStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + ss.stuffclosure = &out; + + out.Truncate(); + int n = dosprintf(&ss, fmt, ap); + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::vsmprintf(const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} + +/* +** Stuff routine that discards overflow data +*/ +static int LimitStuff(SprintfState *ss, const PRUnichar *sp, PRUint32 len) +{ + PRUint32 limit = ss->maxlen - (ss->cur - ss->base); + + if (len > limit) { + len = limit; + } + while (len) { + --len; + *ss->cur++ = *sp++; + } + return 0; +} + +/* +** sprintf into a fixed size buffer. Make sure there is a NUL at the end +** when finished. +*/ +PRUint32 nsTextFormatter::snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUint32 rv; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + va_start(ap, fmt); + rv = nsTextFormatter::vsnprintf(out, outlen, fmt, ap); + va_end(ap); + return rv; +} + +PRUint32 nsTextFormatter::vsnprintf(PRUnichar *out, PRUint32 outlen,const PRUnichar *fmt, + va_list ap) +{ + SprintfState ss; + PRUint32 n; + + PR_ASSERT((PRInt32)outlen > 0); + if ((PRInt32)outlen <= 0) { + return 0; + } + + ss.stuff = LimitStuff; + ss.base = out; + ss.cur = out; + ss.maxlen = outlen; + (void) dosprintf(&ss, fmt, ap); + + /* If we added chars, and we didn't append a null, do it now. */ + if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) + *(--ss.cur) = '\0'; + + n = ss.cur - ss.base; + return n ? n - 1 : n; +} + +PRUnichar * nsTextFormatter::sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...) +{ + va_list ap; + PRUnichar *rv; + + va_start(ap, fmt); + rv = nsTextFormatter::vsprintf_append(last, fmt, ap); + va_end(ap); + return rv; +} + +PRUnichar * nsTextFormatter::vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap) +{ + SprintfState ss; + int rv; + + ss.stuff = GrowStuff; + if (last) { + int lastlen = nsCRT::strlen(last); + ss.base = last; + ss.cur = last + lastlen; + ss.maxlen = lastlen; + } else { + ss.base = 0; + ss.cur = 0; + ss.maxlen = 0; + } + rv = dosprintf(&ss, fmt, ap); + if (rv < 0) { + if (ss.base) { + PR_DELETE(ss.base); + } + return 0; + } + return ss.base; +} +#ifdef DEBUG +PRBool nsTextFormatter::SelfTest() +{ + PRBool passed = PR_TRUE ; + nsAutoString fmt(NS_LITERAL_STRING("%3$s %4$S %1$d %2$d")); + + char utf8[] = "Hello"; + PRUnichar ucs2[]={'W', 'o', 'r', 'l', 'd', 0x4e00, 0xAc00, 0xFF45, 0x0103}; + int d=3; + + + PRUnichar buf[256]; + int ret; + ret = nsTextFormatter::snprintf(buf, 256, fmt.get(), d, 333, utf8, ucs2); + printf("ret = %d\n", ret); + nsAutoString out(buf); + printf("%s \n", NS_LossyConvertUCS2toASCII(out).get()); + const PRUnichar *uout = out.get(); + for(PRUint32 i=0;i +#include +#include "nscore.h" +#include "nsAString.h" + + +class NS_COM nsTextFormatter { + +public: + +/* +** sprintf into a fixed size buffer. Guarantees that a NUL is at the end +** of the buffer. Returns the length of the written output, NOT including +** the NUL, or (PRUint32)-1 if an error occurs. +*/ +static PRUint32 snprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, ...); + +/* +** sprintf into a PR_MALLOC'd buffer. Return a pointer to the malloc'd +** buffer on success, NULL on failure. Call "smprintf_free" to release +** the memory returned. +*/ +static PRUnichar* smprintf(const PRUnichar *fmt, ...); + + +static PRUint32 ssprintf(nsAString& out, const PRUnichar* fmt, ...); +/* +** Free the memory allocated, for the caller, by smprintf +*/ +static void smprintf_free(PRUnichar *mem); + +/* +** "append" sprintf into a PR_MALLOC'd buffer. "last" is the last value of +** the PR_MALLOC'd buffer. sprintf will append data to the end of last, +** growing it as necessary using realloc. If last is NULL, PR_sprintf_append +** will allocate the initial string. The return value is the new value of +** last for subsequent calls, or NULL if there is a malloc failure. +*/ +static PRUnichar* sprintf_append(PRUnichar *last, const PRUnichar *fmt, ...); + +/* +** va_list forms of the above. +*/ +static PRUint32 vsnprintf(PRUnichar *out, PRUint32 outlen, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsmprintf(const PRUnichar *fmt, va_list ap); +static PRUint32 vssprintf(nsAString& out, const PRUnichar *fmt, va_list ap); +static PRUnichar* vsprintf_append(PRUnichar *last, const PRUnichar *fmt, va_list ap); + +#ifdef DEBUG +static PRBool SelfTest(); +#endif + + +}; + +#endif /* nsTextFormatter_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTime.h b/src/libs/xpcom18a4/xpcom/ds/nsTime.h new file mode 100644 index 00000000..f5c3a0ab --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTime.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsTime_h__ +#define nsTime_h__ + +#include "prtime.h" +#include "nsInt64.h" +#include "nscore.h" + +/** + * This class encapsulates full 64-bit time functionality and + * provides simple arithmetic and conversion operations. + */ + +// If you ever decide that you need to add a non-inline method to this +// class, be sure to change the class declaration to "class NS_BASE +// nsTime". + +class nsTime : public nsInt64 +{ +public: + /** + * Construct the current time. + */ + nsTime(void) : nsInt64(PR_Now()) { + } + + /** + * Construct the time from a string. + */ + nsTime(const char* dateStr, PRBool defaultToGMT) { + PRInt64 theTime; + PRStatus status = PR_ParseTimeString(dateStr, defaultToGMT, &theTime); + if (status == PR_SUCCESS) + mValue = theTime; + else + mValue = LL_ZERO; + } + + /** + * Construct a time from a PRTime. + */ + nsTime(const PRTime aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from a 64-bit value. + */ + nsTime(const nsInt64& aTime) : nsInt64(aTime) { + } + + /** + * Construct a time from another time. + */ + nsTime(const nsTime& aTime) : nsInt64(aTime.mValue) { + } + + // ~nsTime(void) -- XXX destructor unnecessary + + /** + * Assign one time to another. + */ + const nsTime& operator =(const nsTime& aTime) { + mValue = aTime.mValue; + return *this; + } + + /** + * Convert a nsTime object to a PRTime + */ + operator PRTime(void) const { + return mValue; + } +}; + +/** + * Determine if one time is strictly less than another + */ +inline const PRBool +operator <(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue < aTime2.mValue; +} + +/** + * Determine if one time is less than or equal to another + */ +inline const PRBool +operator <=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue <= aTime2.mValue; +} + +/** + * Determine if one time is strictly greater than another + */ +inline const PRBool +operator >(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue > aTime2.mValue; +} + +/** + * Determine if one time is greater than or equal to another + */ +inline const PRBool +operator >=(const nsTime& aTime1, const nsTime& aTime2) { + return aTime1.mValue >= aTime2.mValue; +} + +#endif // nsTime_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp new file mode 100644 index 00000000..4974f562 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.cpp @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimelineService.h" +#include "prlong.h" +#include "prprf.h" +#include "prenv.h" +#include "plhash.h" +#include "prlock.h" +#include "prinit.h" +#include "prinrval.h" +#include "prthread.h" + +#ifdef MOZ_TIMELINE + +#define MAXINDENT 20 + +#ifdef XP_MAC +static PRIntervalTime initInterval = 0; +#endif + +static PRFileDesc *timelineFD = PR_STDERR; +static PRBool gTimelineDisabled = PR_TRUE; + +// Notes about threading: +// We avoid locks as we always use thread-local-storage. +// This means every other thread has its own private copy of +// data, and this thread can't re-enter (as our implemenation +// doesn't call back out anywhere). Thus, we can avoid locks! +// TLS index +static const PRUintn BAD_TLS_INDEX = (PRUintn) -1; +static PRUintn gTLSIndex = BAD_TLS_INDEX; + +class TimelineThreadData { +public: + TimelineThreadData() : initTime(0), indent(0), + disabled(PR_TRUE), timers(nsnull) {} + ~TimelineThreadData() {if (timers) PL_HashTableDestroy(timers);} + PRTime initTime; + PRHashTable *timers; + int indent; + PRBool disabled; +}; + +/* Implementation file */ +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimelineService, nsITimelineService) + +static PRTime Now(void); + +/* + * Timer structure stored in a hash table to keep track of named + * timers. + */ +class nsTimelineServiceTimer { + public: + nsTimelineServiceTimer(); + ~nsTimelineServiceTimer(); + void start(); + + /* + * Caller passes in "now" rather than having us calculate it so + * that we can avoid including timer overhead in the time being + * measured. + */ + void stop(PRTime now); + void reset(); + PRTime getAccum(); + PRTime getAccum(PRTime now); + + private: + PRTime mAccum; + PRTime mStart; + PRInt32 mRunning; + PRThread *mOwnerThread; // only used for asserts - could be #if MOZ_DEBUG +}; + +#define TIMER_CHECK_OWNER() \ + NS_ABORT_IF_FALSE(PR_GetCurrentThread() == mOwnerThread, \ + "Timer used by non-owning thread") + + +nsTimelineServiceTimer::nsTimelineServiceTimer() +: mAccum(LL_ZERO), mStart(LL_ZERO), mRunning(0), + mOwnerThread(PR_GetCurrentThread()) +{ +} + +nsTimelineServiceTimer::~nsTimelineServiceTimer() +{ +} + +void nsTimelineServiceTimer::start() +{ + TIMER_CHECK_OWNER(); + if (!mRunning) { + mStart = Now(); + } + mRunning++; +} + +void nsTimelineServiceTimer::stop(PRTime now) +{ + TIMER_CHECK_OWNER(); + mRunning--; + if (mRunning == 0) { + PRTime delta, accum; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + mAccum = accum; + } +} + +void nsTimelineServiceTimer::reset() +{ + TIMER_CHECK_OWNER(); + mStart = 0; + mAccum = 0; +} + +PRTime nsTimelineServiceTimer::getAccum() +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, Now(), mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +PRTime nsTimelineServiceTimer::getAccum(PRTime now) +{ + TIMER_CHECK_OWNER(); + PRTime accum; + + if (!mRunning) { + accum = mAccum; + } else { + PRTime delta; + LL_SUB(delta, now, mStart); + LL_ADD(accum, mAccum, delta); + } + return accum; +} + +#ifdef XP_MAC +/* + * PR_Now() on the Mac only gives us a resolution of seconds. Using + * PR_IntervalNow() gives us better resolution. with the drawback that + * the timeline is only good for about six hours. + * + * PR_IntervalNow() occasionally exhibits discontinuities on Windows, + * so we only use it on the Mac. Bleah! + */ +static PRTime Now(void) +{ + PRIntervalTime numTicks = PR_IntervalNow() - initInterval; + PRTime now; + LL_ADD(now, initTime, PR_IntervalToMilliseconds(numTicks) * 1000); + return now; +} +#else +static PRTime Now(void) +{ + return PR_Now(); +} +#endif + +static TimelineThreadData *GetThisThreadData() +{ + NS_ABORT_IF_FALSE(gTLSIndex!=BAD_TLS_INDEX, "Our TLS not initialized"); + TimelineThreadData *new_data = nsnull; + TimelineThreadData *data = (TimelineThreadData *)PR_GetThreadPrivate(gTLSIndex); + if (data == nsnull) { + // First request for this thread - allocate it. + new_data = new TimelineThreadData(); + if (!new_data) + goto done; + + // Fill it + new_data->timers = PL_NewHashTable(100, PL_HashString, PL_CompareStrings, + PL_CompareValues, NULL, NULL); + if (new_data->timers==NULL) + goto done; + new_data->initTime = PR_Now(); + NS_WARN_IF_FALSE(!gTimelineDisabled, + "Why are we creating new state when disabled?"); + new_data->disabled = PR_FALSE; + data = new_data; + new_data = nsnull; + PR_SetThreadPrivate(gTLSIndex, data); + } +done: + if (new_data) // eeek - error during creation! + delete new_data; + NS_WARN_IF_FALSE(data, "TimelineService could not get thread-local data"); + return data; +} + +extern "C" { + static void ThreadDestruct (void *data); + static PRStatus TimelineInit(void); +}; + +void ThreadDestruct( void *data ) +{ + if (data) + delete (TimelineThreadData *)data; +} + +/* +* PRCallOnceFN that initializes stuff for the timing service. +*/ +static PRCallOnceType initonce; + +PRStatus TimelineInit(void) +{ + char *timeStr; + char *fileName; + PRInt32 secs, msecs; + PRFileDesc *fd; + PRInt64 tmp1, tmp2; + + PRStatus status = PR_NewThreadPrivateIndex( &gTLSIndex, ThreadDestruct ); + NS_WARN_IF_FALSE(status==0, "TimelineService could not allocate TLS storage."); + + timeStr = PR_GetEnv("NS_TIMELINE_INIT_TIME"); +#ifdef XP_MAC + initInterval = PR_IntervalNow(); +#endif + // NS_TIMELINE_INIT_TIME only makes sense for the main thread, so if it + // exists, set it there. If not, let normal thread management code take + // care of setting the init time. + if (timeStr != NULL && 2 == PR_sscanf(timeStr, "%d.%d", &secs, &msecs)) { + PRTime &initTime = GetThisThreadData()->initTime; + LL_MUL(tmp1, (PRInt64)secs, 1000000); + LL_MUL(tmp2, (PRInt64)msecs, 1000); + LL_ADD(initTime, tmp1, tmp2); +#ifdef XP_MAC + initInterval -= PR_MicrosecondsToInterval( + (PRUint32)(PR_Now() - initTime)); +#endif + } + // Get the log file. +#ifdef XP_MAC + fileName = "timeline.txt"; +#else + fileName = PR_GetEnv("NS_TIMELINE_LOG_FILE"); +#endif + if (fileName != NULL + && (fd = PR_Open(fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666)) != NULL) { + timelineFD = fd; + PR_fprintf(fd, + "NOTE: due to asynchrony, the indentation that you see does" + " not necessarily correspond to nesting in the code.\n\n"); + } + + // Runtime disable of timeline + if (PR_GetEnv("NS_TIMELINE_ENABLE")) + gTimelineDisabled = PR_FALSE; + return PR_SUCCESS; +} + +static void ParseTime(PRTime tm, PRInt32& secs, PRInt32& msecs) +{ + PRTime llsecs, llmsecs, tmp; + + LL_DIV(llsecs, tm, 1000000); + LL_MOD(tmp, tm, 1000000); + LL_DIV(llmsecs, tmp, 1000); + + LL_L2I(secs, llsecs); + LL_L2I(msecs, llmsecs); +} + +static char *Indent(char *buf) +{ + int &indent = GetThisThreadData()->indent; + int amount = indent; + if (amount > MAXINDENT) { + amount = MAXINDENT; + } + if (amount < 0) { + amount = 0; + indent = 0; + PR_Write(timelineFD, "indent underflow!\n", 18); + } + while (amount--) { + *buf++ = ' '; + } + return buf; +} + +static void PrintTime(PRTime tm, const char *text, va_list args) +{ + PRInt32 secs, msecs; + char pbuf[550], *pc, tbuf[550]; + + ParseTime(tm, secs, msecs); + + // snprintf/write rather than fprintf because we don't want + // messages from multiple threads to garble one another. + pc = Indent(pbuf); + PR_vsnprintf(pc, sizeof pbuf - (pc - pbuf), text, args); + PR_snprintf(tbuf, sizeof tbuf, "%05d.%03d (%08p): %s\n", + secs, msecs, PR_GetCurrentThread(), pbuf); + PR_Write(timelineFD, tbuf, strlen(tbuf)); +} + +/* + * Make this public if we need it. + */ +static nsresult NS_TimelineMarkV(const char *text, va_list args) +{ + PRTime elapsed,tmp; + + PR_CallOnce(&initonce, TimelineInit); + + TimelineThreadData *thread = GetThisThreadData(); + + tmp = Now(); + LL_SUB(elapsed, tmp, thread->initTime); + + PrintTime(elapsed, text, args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineForceMark(const char *text, ...) +{ + va_list args; + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMark(const char *text, ...) +{ + va_list args; + + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + va_start(args, text); + NS_TimelineMarkV(text, args); + va_end(args); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStartTimer(const char *timerName) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + timer = new nsTimelineServiceTimer; + if (!timer) + return NS_ERROR_OUT_OF_MEMORY; + + PL_HashTableAdd(thread->timers, timerName, timer); + } + timer->start(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineStopTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + /* + * Strange-looking now/timer->stop() interaction is to avoid + * including time spent in TLS and PL_HashTableLookup in the + * timer. + */ + PRTime now = Now(); + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->stop(now); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineMarkTimer(const char *timerName, const char *str) +{ + PR_CallOnce(&initonce, TimelineInit); + + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + PRTime accum = timer->getAccum(); + + char buf[500]; + PRInt32 sec, msec; + ParseTime(accum, sec, msec); + if (!str) + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d", + timerName, sec, msec); + else + PR_snprintf(buf, sizeof buf, "%s total: %d.%03d (%s)", + timerName, sec, msec, str); + NS_TimelineMark(buf); + + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineResetTimer(const char *timerName) +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->timers == NULL) + return NS_ERROR_FAILURE; + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + nsTimelineServiceTimer *timer + = (nsTimelineServiceTimer *)PL_HashTableLookup(thread->timers, timerName); + if (timer == NULL) { + return NS_ERROR_FAILURE; + } + + timer->reset(); + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineIndent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent++; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineOutdent() +{ + if (gTimelineDisabled) + return NS_ERROR_NOT_AVAILABLE; + + TimelineThreadData *thread = GetThisThreadData(); + if (thread->disabled) + return NS_ERROR_NOT_AVAILABLE; + thread->indent--; + return NS_OK; +} + +PR_IMPLEMENT(nsresult) NS_TimelineEnter(const char *text) +{ + nsresult rv = NS_TimelineMark("%s...", text); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineIndent(); +} + +PR_IMPLEMENT(nsresult) NS_TimelineLeave(const char *text) +{ + nsresult rv = NS_TimelineOutdent(); + if (NS_FAILED(rv)) { + return rv; + } + return NS_TimelineMark("...%s", text); +} + +nsTimelineService::nsTimelineService() +{ + /* member initializers and constructor code */ +} + +/* void mark (in string text); */ +NS_IMETHODIMP nsTimelineService::Mark(const char *text) +{ + return NS_TimelineMark(text); +} + +/* void startTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StartTimer(const char *timerName) +{ + return NS_TimelineStartTimer(timerName); +} + +/* void stopTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::StopTimer(const char *timerName) +{ + return NS_TimelineStopTimer(timerName); +} + +/* void markTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::MarkTimer(const char *timerName) +{ + return NS_TimelineMarkTimer(timerName); +} + +/* void markTimerWithComment(in string timerName, in string comment); */ +NS_IMETHODIMP nsTimelineService::MarkTimerWithComment(const char *timerName, const char *comment) +{ + return NS_TimelineMarkTimer(timerName, comment); +} + +/* void resetTimer (in string timerName); */ +NS_IMETHODIMP nsTimelineService::ResetTimer(const char *timerName) +{ + return NS_TimelineResetTimer(timerName); +} + +/* void indent (); */ +NS_IMETHODIMP nsTimelineService::Indent() +{ + return NS_TimelineIndent(); +} + +/* void outdent (); */ +NS_IMETHODIMP nsTimelineService::Outdent() +{ + return NS_TimelineOutdent(); +} + +/* void enter (in string text); */ +NS_IMETHODIMP nsTimelineService::Enter(const char *text) +{ + return NS_TimelineEnter(text); +} + +/* void leave (in string text); */ +NS_IMETHODIMP nsTimelineService::Leave(const char *text) +{ + return NS_TimelineLeave(text); +} + +#endif /* MOZ_TIMELINE */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h new file mode 100644 index 00000000..bb579755 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsTimelineService.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsITimelineService.h" + +#ifdef MOZ_TIMELINE + +#define NS_TIMELINESERVICE_CID \ +{ /* a335edf0-3daf-11d5-b67d-000064657374 */ \ + 0xa335edf0, \ + 0x3daf, \ + 0x11d5, \ + {0xb6, 0x7d, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +#define NS_TIMELINESERVICE_CONTRACTID "@mozilla.org;timeline-service;1" +#define NS_TIMELINESERVICE_CLASSNAME "Timeline Service" + +class nsTimelineService : public nsITimelineService +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITIMELINESERVICE + + nsTimelineService(); + +private: + ~nsTimelineService() {} +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp new file mode 100644 index 00000000..12033da0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.cpp @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsUnicharBuffer.h" +#include "nsCRT.h" + +#define MIN_BUFFER_SIZE 32 + +UnicharBufferImpl::UnicharBufferImpl() + : mBuffer(NULL), mSpace(0), mLength(0) +{ +} + +NS_METHOD +UnicharBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + UnicharBufferImpl* it = new UnicharBufferImpl(); + if (it == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(it); + nsresult rv = it->QueryInterface(aIID, aResult); + NS_RELEASE(it); + return rv; +} + +NS_IMETHODIMP +UnicharBufferImpl::Init(PRUint32 aBufferSize) +{ + if (aBufferSize < MIN_BUFFER_SIZE) { + aBufferSize = MIN_BUFFER_SIZE; + } + mSpace = aBufferSize; + mLength = 0; + mBuffer = new PRUnichar[aBufferSize]; + return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMPL_ISUPPORTS1(UnicharBufferImpl, nsIUnicharBuffer) + +UnicharBufferImpl::~UnicharBufferImpl() +{ + if (nsnull != mBuffer) { + delete[] mBuffer; + mBuffer = nsnull; + } + mLength = 0; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetLength() const +{ + return mLength; +} + +NS_IMETHODIMP_(PRInt32) +UnicharBufferImpl::GetBufferSize() const +{ + return mSpace; +} + +NS_IMETHODIMP_(PRUnichar*) +UnicharBufferImpl::GetBuffer() const +{ + return mBuffer; +} + +NS_IMETHODIMP_(PRBool) +UnicharBufferImpl::Grow(PRInt32 aNewSize) +{ + if (PRUint32(aNewSize) < MIN_BUFFER_SIZE) { + aNewSize = MIN_BUFFER_SIZE; + } + PRUnichar* newbuf = new PRUnichar[aNewSize]; + if (nsnull != newbuf) { + if (0 != mLength) { + memcpy(newbuf, mBuffer, mLength * sizeof(PRUnichar)); + } + delete[] mBuffer; + mBuffer = newbuf; + return PR_TRUE; + } + return PR_FALSE; +} + +NS_COM nsresult +NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult, + nsISupports* aOuter, + PRUint32 aBufferSize) +{ + nsresult rv; + nsIUnicharBuffer* buf; + rv = UnicharBufferImpl::Create(aOuter, NS_GET_IID(nsIUnicharBuffer), + (void**)&buf); + if (NS_FAILED(rv)) return rv; + rv = buf->Init(aBufferSize); + if (NS_FAILED(rv)) { + NS_RELEASE(buf); + return rv; + } + *aInstancePtrResult = buf; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h new file mode 100644 index 00000000..d57a48ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnicharBuffer.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsUnicharBuffer_h__ +#define nsUnicharBuffer_h__ + +#include "nsIUnicharBuffer.h" + +class UnicharBufferImpl : public nsIUnicharBuffer { +public: + UnicharBufferImpl(); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_DECL_ISUPPORTS + NS_IMETHOD Init(PRUint32 aBufferSize); + NS_IMETHOD_(PRInt32) GetLength() const; + NS_IMETHOD_(PRInt32) GetBufferSize() const; + NS_IMETHOD_(PRUnichar*) GetBuffer() const; + NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize); + + PRUnichar* mBuffer; + PRUint32 mSpace; + PRUint32 mLength; + +private: + ~UnicharBufferImpl(); +}; + +#endif // nsUnicharBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h new file mode 100644 index 00000000..07825385 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsUnitConversion.h @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsUnitConversion_h__ +#define nsUnitConversion_h__ + +#include "nscore.h" +#include "nsCoord.h" +#include +#include + +#ifndef FLT_EPSILON +// Not an ANSI compiler... oh, well. Use an IEEE value. +#define FLT_EPSILON 1.19209290e-7f +#endif +/// handy constants +#define TWIPS_PER_POINT_INT 20 +#define TWIPS_PER_POINT_FLOAT 20.0f +#define CEIL_CONST_FLOAT (1.0f - 0.5f*FLT_EPSILON) +#define ROUND_EXCLUSIVE_CONST_FLOAT (0.5f*CEIL_CONST_FLOAT) +#define ROUND_CONST_FLOAT 0.5f + + +/* + * Coord Rounding Functions + */ +inline nscoord NSToCoordFloor(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue) : nscoord(aValue - CEIL_CONST_FLOAT)); +} + +inline nscoord NSToCoordCeil(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + CEIL_CONST_FLOAT) : nscoord(aValue)); +} + +inline nscoord NSToCoordRound(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_CONST_FLOAT) : nscoord(aValue - ROUND_CONST_FLOAT)); +} + +inline nscoord NSToCoordRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? nscoord(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + nscoord(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Int Rounding Functions + */ +inline PRInt32 NSToIntFloor(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue) : PRInt32(aValue - CEIL_CONST_FLOAT)); +} + +inline PRInt32 NSToIntCeil(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + CEIL_CONST_FLOAT) : PRInt32(aValue)); +} + +inline PRInt32 NSToIntRound(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_CONST_FLOAT) : PRInt32(aValue - ROUND_CONST_FLOAT)); +} + +inline PRInt32 NSToIntRoundExclusive(float aValue) +{ + return ((0.0f <= aValue) ? PRInt32(aValue + ROUND_EXCLUSIVE_CONST_FLOAT) : + PRInt32(aValue - ROUND_EXCLUSIVE_CONST_FLOAT)); +} + + +/* + * Twips/Points conversions + */ +inline nscoord NSFloatPointsToTwips(float aPoints) +{ + return NSToCoordRound(aPoints * TWIPS_PER_POINT_FLOAT); +} + +inline nscoord NSIntPointsToTwips(PRInt32 aPoints) +{ + return nscoord(aPoints * TWIPS_PER_POINT_INT); +} + +inline PRInt32 NSTwipsToIntPoints(nscoord aTwips) +{ + return NSToIntRound(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToFloorIntPoints(nscoord aTwips) +{ + return NSToIntFloor(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline PRInt32 NSTwipsToCeilIntPoints(nscoord aTwips) +{ + return NSToIntCeil(aTwips / TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToFloatPoints(nscoord aTwips) +{ + return (float(aTwips) / TWIPS_PER_POINT_FLOAT); +} + +/* + * Twips/Pixel conversions + */ +inline nscoord NSFloatPixelsToTwips(float aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(aPixels * aTwipsPerPixel); +} + +inline nscoord NSIntPixelsToTwips(PRInt32 aPixels, float aTwipsPerPixel) +{ + return NSToCoordRound(float(aPixels) * aTwipsPerPixel); +} + +inline float NSTwipsToFloatPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return (float(aTwips) * aPixelsPerTwip); +} + +inline PRInt32 NSTwipsToIntPixels(nscoord aTwips, float aPixelsPerTwip) +{ + return NSToIntRound(float(aTwips) * aPixelsPerTwip); +} + +/* + * Twips/unit conversions + */ +inline nscoord NSUnitsToTwips(float aValue, float aPointsPerUnit) +{ + return NSToCoordRound(aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT); +} + +inline float NSTwipsToUnits(nscoord aTwips, float aUnitsPerPoint) +{ + return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT)); +} + + +/// Unit conversion macros +//@{ +#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), 72.0f) // 72 points per inch +#define NS_FEET_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f)) // 12 inches per foot +#define NS_MILES_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 12.0f * 5280.0f)) // 5280 feet per mile + +#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.03937f)) +#define NS_CENTIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 0.3937f)) +#define NS_METERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39.37f)) +#define NS_KILOMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (72.0f * 39370.0f)) + +#define NS_PICAS_TO_TWIPS(x) NSUnitsToTwips((x), 12.0f) // 12 points per pica +#define NS_DIDOTS_TO_TWIPS(x) NSUnitsToTwips((x), (16.0f / 15.0f)) // 15 didots per 16 points +#define NS_CICEROS_TO_TWIPS(x) NSUnitsToTwips((x), (12.0f * (16.0f / 15.0f))) // 12 didots per cicero + + +#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / 72.0f) +#define NS_TWIPS_TO_FEET(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f)) +#define NS_TWIPS_TO_MILES(x) NSTwipsToUnits((x), 1.0f / (72.0f * 12.0f * 5280.0f)) + +#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.03937f)) +#define NS_TWIPS_TO_CENTIMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 0.3937f)) +#define NS_TWIPS_TO_METERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39.37f)) +#define NS_TWIPS_TO_KILOMETERS(x) NSTwipsToUnits((x), 1.0f / (72.0f * 39370.0f)) + +#define NS_TWIPS_TO_PICAS(x) NSTwipsToUnits((x), 1.0f / 12.0f) +#define NS_TWIPS_TO_DIDOTS(x) NSTwipsToUnits((x), 1.0f / (16.0f / 15.0f)) +#define NS_TWIPS_TO_CICEROS(x) NSTwipsToUnits((x), 1.0f / (12.0f * (16.0f / 15.0f))) +//@} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp new file mode 100644 index 00000000..4660ccec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.cpp @@ -0,0 +1,304 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// +// nsValueArray.cpp +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nsValueArray.h" +#include "nsCRT.h" +#include "prmem.h" +#include "prbit.h" + +#define NSVALUEARRAY_LINEAR_GROWBY 8 +#define NSVALUEARRAY_LINEAR_THRESHOLD 128 + +nsValueArray::nsValueArray(nsValueArrayValue aMaxValue, nsValueArrayCount aInitialCapacity) { + mCount = 0; + mCapacity = 0; + mValueArray = nsnull; + + PRUint8 test8 = (PRUint8)aMaxValue; + PRUint16 test16 = (PRUint16)aMaxValue; + PRUint32 test32 = (PRUint32)aMaxValue; + if ((nsValueArrayValue)test8 == aMaxValue) { + mBytesPerValue = sizeof(test8); + } + else if ((nsValueArrayValue)test16 == aMaxValue) { + mBytesPerValue = sizeof(test16); + } + else if ((nsValueArrayValue)test32 == aMaxValue) { + mBytesPerValue = sizeof(test32); + } + else { + NS_ASSERTION(0, "not supported yet, add it yourself..."); + mBytesPerValue = 0; + } + + if (aInitialCapacity) { + mValueArray = (PRUint8*)PR_Malloc(aInitialCapacity * mBytesPerValue); + if (nsnull != mValueArray) { + mCapacity = aInitialCapacity; + } + } +} + +nsValueArray::~nsValueArray() { + if (nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + } +} + +// +// Copy it. +// +nsValueArray& nsValueArray::operator=(const nsValueArray& aOther) { + // + // Free off what you know if not enough space, or units differ. + // + if ((mBytesPerValue != aOther.mBytesPerValue || mCapacity < aOther.mCount) && nsnull != mValueArray) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCount = mCapacity = 0; + } + + // + // Copy some attribs. + // + mBytesPerValue = aOther.mBytesPerValue; + mCount = aOther.mCount; + + // + // Anything to do? + // + if (0 != mCount) { + // + // May need to allocate our buffer. + // + if (0 == mCapacity) { + mValueArray = (PRUint8*)PR_Malloc(mCount * mBytesPerValue); + mCapacity = mCount; + } + + NS_ASSERTION(nsnull != mValueArray, "loss of value array assignment and original data."); + if (nsnull != mValueArray) { + memcpy(mValueArray, aOther.mValueArray, mCount * mBytesPerValue); + } + else { + mCount = mCapacity = 0; + } + } + + return *this; +} + +// +// Insert a value into the array. +// No validity checking other than index is done. +// +PRBool nsValueArray::InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex <= count) { + // + // If we're at capacity, then we'll need to grow a little. + // + if (Capacity() == count) { + PRUint8* reallocRes = nsnull; + nsValueArrayCount growBy = NSVALUEARRAY_LINEAR_GROWBY; + + // + // Up to a particular limit we grow in small increments. + // Otherwise, grow exponentially. + // + if (count >= NSVALUEARRAY_LINEAR_THRESHOLD) { + growBy = PR_BIT(PR_CeilingLog2(count + 1)) - count; + } + + if (nsnull == mValueArray) { + reallocRes = (PRUint8*)PR_Malloc((count + growBy) * mBytesPerValue); + } + else { + reallocRes = (PRUint8*)PR_Realloc(mValueArray, (count + growBy) * mBytesPerValue); + } + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity += growBy; + } + } + + // + // Only if we are below capacity do we continue. + // + if (Capacity() > count) { + // + // All those at and beyond the insertion point need to move. + // + if (aIndex < count) { + memmove(&mValueArray[(aIndex + 1) * mBytesPerValue], &mValueArray[aIndex * mBytesPerValue], (count - aIndex) * mBytesPerValue); + } + + // + // Do the assignment. + // + switch (mBytesPerValue) { + case sizeof(PRUint8): + *((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint8)aValue; + NS_ASSERTION(*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint16): + *((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint16)aValue; + NS_ASSERTION(*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + case sizeof(PRUint32): + *((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) = (PRUint32)aValue; + NS_ASSERTION(*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]) == aValue, "Lossy value array detected. Report a higher maximum upon construction!"); + break; + default: + NS_ASSERTION(0, "surely you've been warned prior to this!"); + break; + } + + // + // Up the count by 1. + // + mCount++; + } + } + + return retval; +} + +// +// Remove the index from the value array. +// The array does not shrink until Compact() is invoked. +// +PRBool nsValueArray::RemoveValueAt(nsValueArrayIndex aIndex) { + PRBool retval = PR_FALSE; + + nsValueArrayCount count = Count(); + if (aIndex < count) { + // + // Move memory around if appropriate. + // + if (aIndex != (count - 1)) { + memmove(&mValueArray[aIndex * mBytesPerValue], &mValueArray[(aIndex + 1) * mBytesPerValue], (count - aIndex - 1) * mBytesPerValue); + } + + // + // Update our count. + // + mCount--; + } + + return retval; +} + +// +// Shrink as much as possible. +// +void nsValueArray::Compact() { + nsValueArrayCount count = Count(); + if (Capacity() != count) + { + if (0 == count) { + PR_Free(mValueArray); + mValueArray = nsnull; + mCapacity = 0; + } + else { + PRUint8* reallocRes = (PRUint8*)PR_Realloc(mValueArray, count * mBytesPerValue); + if (nsnull != reallocRes) { + mValueArray = reallocRes; + mCapacity = count; + } + } + } +} + +// +// Return the value at the index. +// +nsValueArrayValue nsValueArray::ValueAt(nsValueArrayIndex aIndex) const { + nsValueArrayValue retval = NSVALUEARRAY_INVALID; + + if (aIndex < Count()) { + switch (mBytesPerValue) { + case sizeof(PRUint8): + retval = (nsValueArrayIndex)*((PRUint8*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint16): + retval = (nsValueArrayIndex)*((PRUint16*)&mValueArray[aIndex * mBytesPerValue]); + break; + case sizeof(PRUint32): + retval = (nsValueArrayIndex)*((PRUint32*)&mValueArray[aIndex * mBytesPerValue]); + break; + default: + NS_ASSERTION(0, "unexpected for sure."); + break; + } + } + + return retval; +} + +// +// Return the first encountered index of the value. +// +nsValueArrayIndex nsValueArray::IndexOf(nsValueArrayValue aPossibleValue) const { + nsValueArrayIndex retval = NSVALUEARRAY_INVALID; + nsValueArrayIndex traverse; + + for (traverse = 0; traverse < Count(); traverse++) { + if (aPossibleValue == ValueAt(traverse)) { + retval = traverse; + break; + } + } + + return retval; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h new file mode 100644 index 00000000..6437ca60 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsValueArray.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 nsValueArray.h/nsValueArray.cpp code, released + * Dec 28, 2001. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Garrett Arch Blythe, 20-December-2001 + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsValueArray_h___ +#define nsValueArray_h___ + +// +// nsValueArray.h +// +// Implement an array class to store unsigned integer values. +// The maximum value must be known up front. Once known, the +// smallest memory representation will be attempted; i.e. if the +// maximum value was 1275, then 2 bytes (uint16) would represent each value +// in the array instead of 4 bytes (uint32). +// +#include "nscore.h" + +typedef PRUint32 nsValueArrayCount; +typedef PRUint32 nsValueArrayIndex; +typedef PRUint32 nsValueArrayValue; +#define NSVALUEARRAY_INVALID ((nsValueArrayValue)-1) + +class NS_COM nsValueArray { + public: + nsValueArray(nsValueArrayValue aMaxValue, + nsValueArrayCount aInitialCapacity = 0); + ~nsValueArray(); + + // + // Assignment. + // + public: + nsValueArray& operator=(const nsValueArray& other); + + // + // Array size information. + // Ability to add more values without growing is Capacity - Count. + // + public: + inline nsValueArrayCount Count() const { + return mCount; + } + + inline nsValueArrayCount Capacity() const { + return mCapacity; + } + + void Compact(); + + // Removes all elements from this array + inline void Clear() { + mCount = 0; + } + + // + // Array access. + // + public: + nsValueArrayValue ValueAt(nsValueArrayIndex aIndex) const; + + inline nsValueArrayValue operator[](nsValueArrayIndex aIndex) const { + return ValueAt(aIndex); + } + + nsValueArrayIndex IndexOf(nsValueArrayValue aPossibleValue) const; + + inline PRBool AppendValue(nsValueArrayValue aValue) { + return InsertValueAt(aValue, Count()); + } + + inline PRBool RemoveValue(nsValueArrayValue aValue) { + return RemoveValueAt(IndexOf(aValue)); + } + + PRBool InsertValueAt(nsValueArrayValue aValue, nsValueArrayIndex aIndex); + + PRBool RemoveValueAt(nsValueArrayIndex aIndex); + + // + // Data members. + // + private: + nsValueArrayCount mCount; + nsValueArrayCount mCapacity; + PRUint8* mValueArray; + PRUint8 mBytesPerValue; +}; + +#endif /* nsValueArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp new file mode 100644 index 00000000..09a4cda5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.cpp @@ -0,0 +1,2092 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsVariant.h" +#include "nsString.h" +#include "prprf.h" +#include "prdtoa.h" +#include +#include "nsCRT.h" + +/***************************************************************************/ +// Helpers for static convert functions... + +static nsresult String2Double(const char* aString, double* retval) +{ + char* next; + double value = PR_strtod(aString, &next); + if(next == aString) + return NS_ERROR_CANNOT_CONVERT_DATA; + *retval = value; + return NS_OK; +} + +static nsresult AString2Double(const nsAString& aString, double* retval) +{ + char* pChars = ToNewCString(aString); + if(!pChars) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = String2Double(pChars, retval); + nsMemory::Free(pChars); + return rv; +} + +static nsresult AUTF8String2Double(const nsAUTF8String& aString, double* retval) +{ + return String2Double(PromiseFlatUTF8String(aString).get(), retval); +} + +static nsresult ACString2Double(const nsACString& aString, double* retval) +{ + return String2Double(PromiseFlatCString(aString).get(), retval); +} + +// Fills outVariant with double, PRUint32, or PRInt32. +// Returns NS_OK, an error code, or a non-NS_OK success code +static nsresult ToManageableNumber(const nsDiscriminatedUnion& inData, + nsDiscriminatedUnion* outData) +{ + nsresult rv; + + switch(inData.mType) + { + // This group results in a PRInt32... + +#define CASE__NUMBER_INT32(type_, member_) \ + case nsIDataType :: type_ : \ + outData->u.mInt32Value = inData.u. member_ ; \ + outData->mType = nsIDataType::VTYPE_INT32; \ + return NS_OK; + + CASE__NUMBER_INT32(VTYPE_INT8, mInt8Value) + CASE__NUMBER_INT32(VTYPE_INT16, mInt16Value) + CASE__NUMBER_INT32(VTYPE_INT32, mInt32Value) + CASE__NUMBER_INT32(VTYPE_UINT8, mUint8Value) + CASE__NUMBER_INT32(VTYPE_UINT16, mUint16Value) + CASE__NUMBER_INT32(VTYPE_BOOL, mBoolValue) + CASE__NUMBER_INT32(VTYPE_CHAR, mCharValue) + CASE__NUMBER_INT32(VTYPE_WCHAR, mWCharValue) + +#undef CASE__NUMBER_INT32 + + // This group results in a PRUint32... + + case nsIDataType::VTYPE_UINT32: + outData->u.mInt32Value = inData.u.mUint32Value; + outData->mType = nsIDataType::VTYPE_INT32; + return NS_OK; + + // This group results in a double... + + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT64: + // XXX Need boundary checking here. + // We may need to return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA + LL_L2D(outData->u.mDoubleValue, inData.u.mInt64Value); + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_FLOAT: + outData->u.mDoubleValue = inData.u.mFloatValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOUBLE: + outData->u.mDoubleValue = inData.u.mDoubleValue; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + rv = String2Double(inData.u.str.mStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_ASTRING: + rv = AString2Double(*inData.u.mAStringValue, &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + rv = AUTF8String2Double(*inData.u.mUTF8StringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + rv = ACString2Double(*inData.u.mCStringValue, + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + rv = AString2Double(nsDependentString(inData.u.wstr.mWStringValue), + &outData->u.mDoubleValue); + if(NS_FAILED(rv)) + return rv; + outData->mType = nsIDataType::VTYPE_DOUBLE; + return NS_OK; + + // This group fails... + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ +// Array helpers... + +static void FreeArray(nsDiscriminatedUnion* data) +{ + NS_ASSERTION(data->mType == nsIDataType::VTYPE_ARRAY, "bad FreeArray call"); + NS_ASSERTION(data->u.array.mArrayValue, "bad array"); + NS_ASSERTION(data->u.array.mArrayCount, "bad array count"); + +#define CASE__FREE_ARRAY_PTR(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + nsMemory::Free((char*)*p); \ + break; \ + } + +#define CASE__FREE_ARRAY_IFACE(type_, ctype_) \ + case nsIDataType:: type_ : \ + { \ + ctype_ ** p = (ctype_ **) data->u.array.mArrayValue; \ + for(PRUint32 i = data->u.array.mArrayCount; i > 0; p++, i--) \ + if(*p) \ + (*p)->Release(); \ + break; \ + } + + switch(data->u.array.mArrayType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + CASE__FREE_ARRAY_PTR(VTYPE_ID, nsID) + CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char) + CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, PRUnichar) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports) + CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports) + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + break; + } + + // Free the array memory. + nsMemory::Free((char*)data->u.array.mArrayValue); + +#undef CASE__FREE_ARRAY_PTR +#undef CASE__FREE_ARRAY_IFACE +} + +static nsresult CloneArray(PRUint16 inType, const nsIID* inIID, + PRUint32 inCount, void* inValue, + PRUint16* outType, nsIID* outIID, + PRUint32* outCount, void** outValue) +{ + NS_ASSERTION(inCount, "bad param"); + NS_ASSERTION(inValue, "bad param"); + NS_ASSERTION(outType, "bad param"); + NS_ASSERTION(outCount, "bad param"); + NS_ASSERTION(outValue, "bad param"); + + PRUint32 allocatedValueCount = 0; + nsresult rv = NS_OK; + PRUint32 i; + + // First we figure out the size of the elements for the new u.array. + + size_t elementSize; + size_t allocSize; + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + elementSize = sizeof(PRInt8); + break; + case nsIDataType::VTYPE_INT16: + elementSize = sizeof(PRInt16); + break; + case nsIDataType::VTYPE_INT32: + elementSize = sizeof(PRInt32); + break; + case nsIDataType::VTYPE_INT64: + elementSize = sizeof(PRInt64); + break; + case nsIDataType::VTYPE_UINT8: + elementSize = sizeof(PRUint8); + break; + case nsIDataType::VTYPE_UINT16: + elementSize = sizeof(PRUint16); + break; + case nsIDataType::VTYPE_UINT32: + elementSize = sizeof(PRUint32); + break; + case nsIDataType::VTYPE_UINT64: + elementSize = sizeof(PRUint64); + break; + case nsIDataType::VTYPE_FLOAT: + elementSize = sizeof(float); + break; + case nsIDataType::VTYPE_DOUBLE: + elementSize = sizeof(double); + break; + case nsIDataType::VTYPE_BOOL: + elementSize = sizeof(PRBool); + break; + case nsIDataType::VTYPE_CHAR: + elementSize = sizeof(char); + break; + case nsIDataType::VTYPE_WCHAR: + elementSize = sizeof(PRUnichar); + break; + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + elementSize = sizeof(void*); + break; + + // The rest are illegal. + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + + // Alloc the u.array. + + allocSize = inCount * elementSize; + *outValue = nsMemory::Alloc(allocSize); + if(!*outValue) + return NS_ERROR_OUT_OF_MEMORY; + + // Clone the elements. + + switch(inType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + memcpy(*outValue, inValue, allocSize); + break; + + case nsIDataType::VTYPE_INTERFACE_IS: + if(outIID) + *outIID = *inIID; + // fall through... + case nsIDataType::VTYPE_INTERFACE: + { + memcpy(*outValue, inValue, allocSize); + + nsISupports** p = (nsISupports**) *outValue; + for(i = inCount; i > 0; p++, i--) + if(*p) + (*p)->AddRef(); + break; + } + + // XXX We ASSUME that "array of nsID" means "array of pointers to nsID". + case nsIDataType::VTYPE_ID: + { + nsID** inp = (nsID**) inValue; + nsID** outp = (nsID**) *outValue; + for(i = inCount; i > 0; i--) + { + nsID* idp = *(inp++); + if(idp) + { + if(nsnull == (*(outp++) = (nsID*) + nsMemory::Clone((char*)idp, sizeof(nsID)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_CHAR_STR: + { + char** inp = (char**) inValue; + char** outp = (char**) *outValue; + for(i = inCount; i > 0; i--) + { + char* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (char*) + nsMemory::Clone(str, (strlen(str)+1)*sizeof(char)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + case nsIDataType::VTYPE_WCHAR_STR: + { + PRUnichar** inp = (PRUnichar**) inValue; + PRUnichar** outp = (PRUnichar**) *outValue; + for(i = inCount; i > 0; i--) + { + PRUnichar* str = *(inp++); + if(str) + { + if(nsnull == (*(outp++) = (PRUnichar*) + nsMemory::Clone(str, + (nsCRT::strlen(str)+1)*sizeof(PRUnichar)))) + goto bad; + } + else + *(outp++) = nsnull; + allocatedValueCount++; + } + break; + } + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + default: + NS_ERROR("bad type in array!"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *outType = inType; + *outCount = inCount; + return NS_OK; + +bad: + if(*outValue) + { + char** p = (char**) *outValue; + for(i = allocatedValueCount; i > 0; p++, i--) + if(*p) + nsMemory::Free(*p); + nsMemory::Free((char*)*outValue); + *outValue = nsnull; + } + return rv; +} + +/***************************************************************************/ + +#define TRIVIAL_DATA_CONVERTER(type_, data_, member_, retval_) \ + if(data_.mType == nsIDataType :: type_) { \ + *retval_ = data_.u.member_; \ + return NS_OK; \ + } + +#define NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ +/* static */ nsresult \ +nsVariant::ConvertTo##name_ (const nsDiscriminatedUnion& data, \ + Ctype_ *_retval) \ +{ \ + TRIVIAL_DATA_CONVERTER(type_, data, m##name_##Value, _retval) \ + nsDiscriminatedUnion tempData; \ + nsVariant::Initialize(&tempData); \ + nsresult rv = ToManageableNumber(data, &tempData); \ + /* */ \ + /* NOTE: rv may indicate a success code that we want to preserve */ \ + /* For the final return. So all the return cases below should return */ \ + /* this rv when indicating success. */ \ + /* */ \ + if(NS_FAILED(rv)) \ + return rv; \ + switch(tempData.mType) \ + { + +#define CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_INT32: \ + *_retval = ( Ctype_ ) tempData.u.mInt32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_INT32: \ + { \ + PRInt32 value = tempData.u.mInt32Value; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_UINT32: \ + *_retval = ( Ctype_ ) tempData.u.mUint32Value; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + case nsIDataType::VTYPE_UINT32: \ + { \ + PRUint32 value = tempData.u.mUint32Value; \ + if(value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(Ctype_) \ + case nsIDataType::VTYPE_DOUBLE: \ + *_retval = ( Ctype_ ) tempData.u.mDoubleValue; \ + return rv; + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return rv; \ + } + +#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) \ + case nsIDataType::VTYPE_DOUBLE: \ + { \ + double value = tempData.u.mDoubleValue; \ + if(value < min_ || value > max_) \ + return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \ + *_retval = ( Ctype_ ) value; \ + return (0.0 == fmod(value,1.0)) ? \ + rv : NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; \ + } + +#define CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \ + CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \ + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) + +#define NUMERIC_CONVERSION_METHOD_END \ + default: \ + NS_ERROR("bad type returned from ToManageableNumber"); \ + return NS_ERROR_CANNOT_CONVERT_DATA; \ + } \ +} + +#define NUMERIC_CONVERSION_METHOD_NORMAL(type_, Ctype_, name_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \ + CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \ + NUMERIC_CONVERSION_METHOD_END + +/***************************************************************************/ +// These expand into full public methods... + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT8, PRUint8, Int8, (-127-1), 127) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT16, PRInt16, Int16, (-32767-1), 32767) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_INT32, PRInt32, Int32) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRInt32) + CASE__NUMERIC_CONVERSION_UINT32_MAX(PRInt32, 2147483647) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRInt32, (-2147483647-1), 2147483647) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT8, PRUint8, Uint8, 0, 255) +NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT16, PRUint16, Uint16, 0, 65535) + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_UINT32, PRUint32, Uint32) + CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(PRUint32, 0, 2147483647) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUint32) + CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(PRUint32, 0, 4294967295U) +NUMERIC_CONVERSION_METHOD_END + +// XXX toFloat convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_FLOAT, float, Float) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(float) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(float) +NUMERIC_CONVERSION_METHOD_END + +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_DOUBLE, double, Double) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(double) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(double) +NUMERIC_CONVERSION_METHOD_END + +// XXX toChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_CHAR, char, Char) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char) +NUMERIC_CONVERSION_METHOD_END + +// XXX toWChar convertions need to be fixed! +NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_WCHAR, PRUnichar, WChar) + CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(PRUnichar) + CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(PRUnichar) +NUMERIC_CONVERSION_METHOD_END + +#undef NUMERIC_CONVERSION_METHOD_BEGIN +#undef CASE__NUMERIC_CONVERSION_INT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_INT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_UINT32_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX +#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT +#undef CASES__NUMERIC_CONVERSION_NORMAL +#undef NUMERIC_CONVERSION_METHOD_END +#undef NUMERIC_CONVERSION_METHOD_NORMAL + +/***************************************************************************/ + +// Just leverage a numeric converter for bool (but restrict the values). +// XXX Is this really what we want to do? + +/* static */ nsresult +nsVariant::ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_BOOL, data, mBoolValue, _retval) + + double val; + nsresult rv = nsVariant::ConvertToDouble(data, &val); + if(NS_FAILED(rv)) + return rv; + *_retval = 0.0 != val; + return rv; +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval) +{ + TRIVIAL_DATA_CONVERTER(VTYPE_INT64, data, mInt64Value, _retval) + TRIVIAL_DATA_CONVERTER(VTYPE_UINT64, data, mUint64Value, _retval) + + nsDiscriminatedUnion tempData; + nsVariant::Initialize(&tempData); + nsresult rv = ToManageableNumber(data, &tempData); + if(NS_FAILED(rv)) + return rv; + switch(tempData.mType) + { + case nsIDataType::VTYPE_INT32: + LL_I2L(*_retval, tempData.u.mInt32Value); + return rv; + case nsIDataType::VTYPE_UINT32: + LL_UI2L(*_retval, tempData.u.mUint32Value); + return rv; + case nsIDataType::VTYPE_DOUBLE: + // XXX should check for data loss here! + LL_D2L(*_retval, tempData.u.mDoubleValue); + return rv; + default: + NS_ERROR("bad type returned from ToManageableNumber"); + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval) +{ + return nsVariant::ConvertToInt64(data, (PRInt64 *)_retval); +} + +/***************************************************************************/ + +static PRBool String2ID(const nsDiscriminatedUnion& data, nsID* pid) +{ + nsAutoString tempString; + nsAString* pString; + + switch(data.mType) + { + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + return pid->Parse(data.u.str.mStringValue); + case nsIDataType::VTYPE_CSTRING: + return pid->Parse(PromiseFlatCString(*data.u.mCStringValue).get()); + case nsIDataType::VTYPE_UTF8STRING: + return pid->Parse(PromiseFlatUTF8String(*data.u.mUTF8StringValue).get()); + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + pString = data.u.mAStringValue; + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + tempString.Assign(data.u.wstr.mWStringValue); + pString = &tempString; + break; + default: + NS_ERROR("bad type in call to String2ID"); + return PR_FALSE; + } + + char* pChars = ToNewCString(*pString); + if(!pChars) + return PR_FALSE; + PRBool result = pid->Parse(pChars); + nsMemory::Free(pChars); + return result; +} + +/* static */ nsresult +nsVariant::ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval) +{ + nsID id; + + switch(data.mType) + { + case nsIDataType::VTYPE_ID: + *_retval = data.u.mIDValue; + return NS_OK; + case nsIDataType::VTYPE_INTERFACE: + *_retval = NS_GET_IID(nsISupports); + return NS_OK; + case nsIDataType::VTYPE_INTERFACE_IS: + *_retval = data.u.iface.mInterfaceID; + return NS_OK; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + if(!String2ID(data, &id)) + return NS_ERROR_CANNOT_CONVERT_DATA; + *_retval = id; + return NS_OK; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/***************************************************************************/ + +static nsresult ToString(const nsDiscriminatedUnion& data, + nsACString & outString) +{ + char* ptr; + + switch(data.mType) + { + // all the stuff we don't handle... + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_WCHAR: + NS_ERROR("ToString being called for a string type - screwy logic!"); + // fall through... + + // XXX We might want stringified versions of these... ??? + + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + + // nsID has its own text formater. + + case nsIDataType::VTYPE_ID: + ptr = data.u.mIDValue.ToString(); + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + nsMemory::Free(ptr); + return NS_OK; + + // the rest can be PR_smprintf'd and use common code. + +#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_) \ + case nsIDataType :: type_ : \ + ptr = PR_smprintf( format_ , (cast_) data.u. member_ ); \ + break; + + CASE__SMPRINTF_NUMBER(VTYPE_INT8, "%d", int, mInt8Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT16, "%d", int, mInt16Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT32, "%d", int, mInt32Value) + CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%lld", PRInt64, mInt64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_UINT8, "%u", unsigned, mUint8Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u", unsigned, mUint16Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u", unsigned, mUint32Value) + CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%llu", PRInt64, mUint64Value) + + CASE__SMPRINTF_NUMBER(VTYPE_FLOAT, "%f", float, mFloatValue) + CASE__SMPRINTF_NUMBER(VTYPE_DOUBLE, "%f", double, mDoubleValue) + + // XXX Would we rather print "true" / "false" ? + CASE__SMPRINTF_NUMBER(VTYPE_BOOL, "%d", int, mBoolValue) + + CASE__SMPRINTF_NUMBER(VTYPE_CHAR, "%c", char, mCharValue) + +#undef CASE__SMPRINTF_NUMBER + } + + if(!ptr) + return NS_ERROR_OUT_OF_MEMORY; + outString.Assign(ptr); + PR_smprintf_free(ptr); + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToAString(const nsDiscriminatedUnion& data, + nsAString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + _retval.Assign(*data.u.mAStringValue); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + CopyASCIItoUCS2(*data.u.mCStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + CopyUTF8toUTF16(*data.u.mUTF8StringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + CopyASCIItoUTF16(data.u.str.mStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + _retval.Assign(data.u.wstr.mWStringValue); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + CopyASCIItoUCS2(nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + _retval.Assign(data.u.wstr.mWStringValue, data.u.wstr.mWStringLength); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + _retval.Assign(data.u.mWCharValue); + return NS_OK; + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + CopyASCIItoUTF16(tempCString, _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToACString(const nsDiscriminatedUnion& data, + nsACString & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUCS2toASCII(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + _retval.Assign(*data.u.mCStringValue); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + // XXX This is an extra copy that should be avoided + // once Jag lands support for UTF8String and associated + // conversion methods. + CopyUCS2toASCII(NS_ConvertUTF8toUCS2(*data.u.mUTF8StringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + _retval.Assign(*data.u.str.mStringValue); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + _retval.Assign(data.u.str.mStringValue, data.u.str.mStringLength); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUCS2toASCII(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUCS2toASCII(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + return ToString(data, _retval); + } +} + +/* static */ nsresult +nsVariant::ConvertToAUTF8String(const nsDiscriminatedUnion& data, + nsAUTF8String & _retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + CopyUTF16toUTF8(*data.u.mAStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_CSTRING: + // XXX Extra copy, can be removed if we're sure CSTRING can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*data.u.mCStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_UTF8STRING: + _retval.Assign(*data.u.mUTF8StringValue); + return NS_OK; + case nsIDataType::VTYPE_CHAR_STR: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(data.u.str.mStringValue), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR_STR: + CopyUTF16toUTF8(data.u.wstr.mWStringValue, _retval); + return NS_OK; + case nsIDataType::VTYPE_STRING_SIZE_IS: + // XXX Extra copy, can be removed if we're sure CHAR_STR can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16( + nsDependentCString(data.u.str.mStringValue, + data.u.str.mStringLength)), _retval); + return NS_OK; + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CopyUTF16toUTF8(nsDependentString(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength), + _retval); + return NS_OK; + case nsIDataType::VTYPE_WCHAR: + { + const PRUnichar* str = &data.u.mWCharValue; + CopyUTF16toUTF8(Substring(str, str + 1), _retval); + return NS_OK; + } + default: + { + nsCAutoString tempCString; + nsresult rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + // XXX Extra copy, can be removed if we're sure tempCString can + // only contain ASCII. + CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(tempCString), _retval); + return NS_OK; + } + } +} + +/* static */ nsresult +nsVariant::ConvertToString(const nsDiscriminatedUnion& data, char **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval) +{ + PRUint32 ignored; + return nsVariant::ConvertToWStringWithSize(data, &ignored, _retval); +} + +/* static */ nsresult +nsVariant::ConvertToStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, char **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewCString(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewCString(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + // XXX This is doing 1 extra copy. Need to fix this + // when Jag lands UTF8String + // we want: + // *size = *data.mUTF8StringValue->Length(); + // *str = ToNewCString(*data.mUTF8StringValue); + // But this will have to do for now. + NS_ConvertUTF8toUCS2 tempString(*data.u.mUTF8StringValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewCString(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewCString(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewCString(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewCString(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} +/* static */ nsresult +nsVariant::ConvertToWStringWithSize(const nsDiscriminatedUnion& data, + PRUint32 *size, PRUnichar **str) +{ + nsAutoString tempString; + nsCAutoString tempCString; + nsresult rv; + + switch(data.mType) + { + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + *size = data.u.mAStringValue->Length(); + *str = ToNewUnicode(*data.u.mAStringValue); + break; + case nsIDataType::VTYPE_CSTRING: + *size = data.u.mCStringValue->Length(); + *str = ToNewUnicode(*data.u.mCStringValue); + break; + case nsIDataType::VTYPE_UTF8STRING: + { + *str = UTF8ToNewUnicode(*data.u.mUTF8StringValue, size); + break; + } + case nsIDataType::VTYPE_CHAR_STR: + { + nsDependentCString cString(data.u.str.mStringValue); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WCHAR_STR: + { + nsDependentString string(data.u.wstr.mWStringValue); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: + { + nsDependentCString cString(data.u.str.mStringValue, + data.u.str.mStringLength); + *size = cString.Length(); + *str = ToNewUnicode(cString); + break; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + { + nsDependentString string(data.u.wstr.mWStringValue, + data.u.wstr.mWStringLength); + *size = string.Length(); + *str = ToNewUnicode(string); + break; + } + case nsIDataType::VTYPE_WCHAR: + tempString.Assign(data.u.mWCharValue); + *size = tempString.Length(); + *str = ToNewUnicode(tempString); + break; + default: + rv = ToString(data, tempCString); + if(NS_FAILED(rv)) + return rv; + *size = tempCString.Length(); + *str = ToNewUnicode(tempCString); + break; + } + + return *str ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +/* static */ nsresult +nsVariant::ConvertToISupports(const nsDiscriminatedUnion& data, + nsISupports **_retval) +{ + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue-> + QueryInterface(NS_GET_IID(nsISupports), (void**)_retval); + } else { + *_retval = nsnull; + return NS_OK; + } + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } +} + +/* static */ nsresult +nsVariant::ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, + void * *iface) +{ + const nsIID* piid; + + switch(data.mType) + { + case nsIDataType::VTYPE_INTERFACE: + piid = &NS_GET_IID(nsISupports); + break; + case nsIDataType::VTYPE_INTERFACE_IS: + piid = &data.u.iface.mInterfaceID; + break; + default: + return NS_ERROR_CANNOT_CONVERT_DATA; + } + + *iid = (nsIID*) nsMemory::Clone(piid, sizeof(nsIID)); + if(!*iid) + return NS_ERROR_OUT_OF_MEMORY; + + if (data.u.iface.mInterfaceValue) { + return data.u.iface.mInterfaceValue->QueryInterface(*piid, iface); + } + + *iface = nsnull; + return NS_OK; +} + +/* static */ nsresult +nsVariant::ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, + nsIID* iid, PRUint32 *count, void * *ptr) +{ + // XXX perhaps we'd like to add support for converting each of the various + // types into an array containing one element of that type. We can leverage + // CloneArray to do this if we want to support this. + + if(data.mType == nsIDataType::VTYPE_ARRAY) + return CloneArray(data.u.array.mArrayType, &data.u.array.mArrayInterfaceID, + data.u.array.mArrayCount, data.u.array.mArrayValue, + type, iid, count, ptr); + return NS_ERROR_CANNOT_CONVERT_DATA; +} + +/***************************************************************************/ +// static setter functions... + +#define DATA_SETTER_PROLOGUE(data_) \ + nsVariant::Cleanup(data_); + +#define DATA_SETTER_EPILOGUE(data_, type_) \ + data_->mType = nsIDataType :: type_; \ + return NS_OK; + +#define DATA_SETTER(data_, type_, member_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + +#define DATA_SETTER_WITH_CAST(data_, type_, member_, cast_, value_) \ + DATA_SETTER_PROLOGUE(data_) \ + data_->u.member_ = cast_ value_; \ + DATA_SETTER_EPILOGUE(data_, type_) + + +/********************************************/ + +#define CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + { \ + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + rv = aValue->GetAs##name_ (&(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + rv = aValue->GetAs##name_ ( cast_ &(data->u. member_ )); + +#define CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) \ + if(NS_SUCCEEDED(rv)) \ + { \ + data->mType = nsIDataType :: type_ ; \ + } \ + break; \ + } + +#define CASE__SET_FROM_VARIANT_TYPE(type_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + +#define CASE__SET_FROM_VARIANT_VTYPE_CAST(type_, cast_, member_, name_) \ + case nsIDataType :: type_ : \ + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \ + CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \ + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) + + +/* static */ nsresult +nsVariant::SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue) +{ + PRUint16 type; + nsresult rv; + + nsVariant::Cleanup(data); + + rv = aValue->GetDataType(&type); + if(NS_FAILED(rv)) + return rv; + + switch(type) + { + CASE__SET_FROM_VARIANT_VTYPE_CAST(VTYPE_INT8, (PRUint8*), mInt8Value, + Int8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT16, mInt16Value, Int16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT32, mInt32Value, Int32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT8, mUint8Value, Uint8) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT16, mUint16Value, Uint16) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT32, mUint32Value, Uint32) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT, mFloatValue, Float) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL , mBoolValue, Bool) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR, mCharValue, Char) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR, mWCharValue, WChar) + CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID, mIDValue, ID) + + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING); + data->u.mAStringValue = new nsString(); + if(!data->u.mAStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAString(*data->u.mAStringValue); + if(NS_FAILED(rv)) + delete data->u.mAStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ASTRING) + + case nsIDataType::VTYPE_CSTRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_CSTRING); + data->u.mCStringValue = new nsCString(); + if(!data->u.mCStringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsACString(*data->u.mCStringValue); + if(NS_FAILED(rv)) + delete data->u.mCStringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_CSTRING) + + case nsIDataType::VTYPE_UTF8STRING: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_UTF8STRING); + data->u.mUTF8StringValue = new nsUTF8String(); + if(!data->u.mUTF8StringValue) + return NS_ERROR_OUT_OF_MEMORY; + rv = aValue->GetAsAUTF8String(*data->u.mUTF8StringValue); + if(NS_FAILED(rv)) + delete data->u.mUTF8StringValue; + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_UTF8STRING) + + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_STRING_SIZE_IS); + rv = aValue->GetAsStringWithSize(&data->u.str.mStringLength, + &data->u.str.mStringValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_STRING_SIZE_IS) + + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_INTERFACE_IS); + // XXX This iid handling is ugly! + nsIID* iid; + rv = aValue->GetAsInterface(&iid, (void**)&data->u.iface.mInterfaceValue); + if(NS_SUCCEEDED(rv)) + { + data->u.iface.mInterfaceID = *iid; + nsMemory::Free((char*)iid); + } + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_INTERFACE_IS) + + case nsIDataType::VTYPE_ARRAY: + CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ARRAY); + rv = aValue->GetAsArray(&data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY) + + case nsIDataType::VTYPE_VOID: + rv = nsVariant::SetToVoid(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + rv = nsVariant::SetToEmptyArray(data); + break; + case nsIDataType::VTYPE_EMPTY: + rv = nsVariant::SetToEmpty(data); + break; + default: + NS_ERROR("bad type in variant!"); + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +/* static */ nsresult +nsVariant::SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER_WITH_CAST(data, VTYPE_INT8, mInt8Value, (PRUint8), aValue) +} +/* static */ nsresult +nsVariant::SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue) +{ + DATA_SETTER(data, VTYPE_INT16, mInt16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue) +{ + DATA_SETTER(data, VTYPE_INT32, mInt32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue) +{ + DATA_SETTER(data, VTYPE_INT64, mInt64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue) +{ + DATA_SETTER(data, VTYPE_UINT8, mUint8Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue) +{ + DATA_SETTER(data, VTYPE_UINT16, mUint16Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue) +{ + DATA_SETTER(data, VTYPE_UINT32, mUint32Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue) +{ + DATA_SETTER(data, VTYPE_UINT64, mUint64Value, aValue) +} +/* static */ nsresult +nsVariant::SetFromFloat(nsDiscriminatedUnion* data, float aValue) +{ + DATA_SETTER(data, VTYPE_FLOAT, mFloatValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromDouble(nsDiscriminatedUnion* data, double aValue) +{ + DATA_SETTER(data, VTYPE_DOUBLE, mDoubleValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromBool(nsDiscriminatedUnion* data, PRBool aValue) +{ + DATA_SETTER(data, VTYPE_BOOL, mBoolValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromChar(nsDiscriminatedUnion* data, char aValue) +{ + DATA_SETTER(data, VTYPE_CHAR, mCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue) +{ + DATA_SETTER(data, VTYPE_WCHAR, mWCharValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromID(nsDiscriminatedUnion* data, const nsID & aValue) +{ + DATA_SETTER(data, VTYPE_ID, mIDValue, aValue) +} +/* static */ nsresult +nsVariant::SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mAStringValue = new nsString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_ASTRING); +} + +/* static */ nsresult +nsVariant::SetFromACString(nsDiscriminatedUnion* data, + const nsACString & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mCStringValue = new nsCString(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_CSTRING); +} + +/* static */ nsresult +nsVariant::SetFromAUTF8String(nsDiscriminatedUnion* data, + const nsAUTF8String & aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!(data->u.mUTF8StringValue = new nsUTF8String(aValue))) + return NS_ERROR_OUT_OF_MEMORY; + DATA_SETTER_EPILOGUE(data, VTYPE_UTF8STRING); +} + +/* static */ nsresult +nsVariant::SetFromString(nsDiscriminatedUnion* data, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromStringWithSize(data, strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + return SetFromWStringWithSize(data, nsCRT::strlen(aValue), aValue); +} +/* static */ nsresult +nsVariant::SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue) +{ + return SetFromInterface(data, NS_GET_IID(nsISupports), aValue); +} +/* static */ nsresult +nsVariant::SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, + nsISupports *aValue) +{ + DATA_SETTER_PROLOGUE(data); + NS_IF_ADDREF(aValue); + data->u.iface.mInterfaceValue = aValue; + data->u.iface.mInterfaceID = iid; + DATA_SETTER_EPILOGUE(data, VTYPE_INTERFACE_IS); +} +/* static */ nsresult +nsVariant::SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, + const nsIID* iid, PRUint32 count, void * aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue || !count) + return NS_ERROR_NULL_POINTER; + + nsresult rv = CloneArray(type, iid, count, aValue, + &data->u.array.mArrayType, + &data->u.array.mArrayInterfaceID, + &data->u.array.mArrayCount, + &data->u.array.mArrayValue); + if(NS_FAILED(rv)) + return rv; + DATA_SETTER_EPILOGUE(data, VTYPE_ARRAY); +} +/* static */ nsresult +nsVariant::SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.str.mStringValue = + (char*) nsMemory::Clone(aValue, (size+1)*sizeof(char)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.str.mStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_STRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue) +{ + DATA_SETTER_PROLOGUE(data); + if(!aValue) + return NS_ERROR_NULL_POINTER; + if(!(data->u.wstr.mWStringValue = + (PRUnichar*) nsMemory::Clone(aValue, (size+1)*sizeof(PRUnichar)))) + return NS_ERROR_OUT_OF_MEMORY; + data->u.wstr.mWStringLength = size; + DATA_SETTER_EPILOGUE(data, VTYPE_WSTRING_SIZE_IS); +} +/* static */ nsresult +nsVariant::SetToVoid(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_VOID); +} +/* static */ nsresult +nsVariant::SetToEmpty(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY); +} +/* static */ nsresult +nsVariant::SetToEmptyArray(nsDiscriminatedUnion* data) +{ + DATA_SETTER_PROLOGUE(data); + DATA_SETTER_EPILOGUE(data, VTYPE_EMPTY_ARRAY); +} + +/***************************************************************************/ + +/* static */ nsresult +nsVariant::Initialize(nsDiscriminatedUnion* data) +{ + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/* static */ nsresult +nsVariant::Cleanup(nsDiscriminatedUnion* data) +{ + switch(data->mType) + { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: + case nsIDataType::VTYPE_BOOL: + case nsIDataType::VTYPE_CHAR: + case nsIDataType::VTYPE_WCHAR: + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ID: + break; + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_DOMSTRING: + delete data->u.mAStringValue; + break; + case nsIDataType::VTYPE_CSTRING: + delete data->u.mCStringValue; + break; + case nsIDataType::VTYPE_UTF8STRING: + delete data->u.mUTF8StringValue; + break; + case nsIDataType::VTYPE_CHAR_STR: + case nsIDataType::VTYPE_STRING_SIZE_IS: + nsMemory::Free((char*)data->u.str.mStringValue); + break; + case nsIDataType::VTYPE_WCHAR_STR: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + nsMemory::Free((char*)data->u.wstr.mWStringValue); + break; + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: + NS_IF_RELEASE(data->u.iface.mInterfaceValue); + break; + case nsIDataType::VTYPE_ARRAY: + FreeArray(data); + break; + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + break; + default: + NS_ERROR("bad type in variant!"); + break; + } + + data->mType = nsIDataType::VTYPE_EMPTY; + return NS_OK; +} + +/***************************************************************************/ +/***************************************************************************/ +// members... + +NS_IMPL_ISUPPORTS2(nsVariant, nsIVariant, nsIWritableVariant) + +nsVariant::nsVariant() + : mWritable(PR_TRUE) +{ + nsVariant::Initialize(&mData); + +#ifdef DEBUG + { + // Assert that the nsIDataType consts match the values #defined in + // xpt_struct.h. Bad things happen somewhere if they don't. + struct THE_TYPES {PRUint16 a; PRUint16 b;}; + static const THE_TYPES array[] = { + {nsIDataType::VTYPE_INT8 , TD_INT8 }, + {nsIDataType::VTYPE_INT16 , TD_INT16 }, + {nsIDataType::VTYPE_INT32 , TD_INT32 }, + {nsIDataType::VTYPE_INT64 , TD_INT64 }, + {nsIDataType::VTYPE_UINT8 , TD_UINT8 }, + {nsIDataType::VTYPE_UINT16 , TD_UINT16 }, + {nsIDataType::VTYPE_UINT32 , TD_UINT32 }, + {nsIDataType::VTYPE_UINT64 , TD_UINT64 }, + {nsIDataType::VTYPE_FLOAT , TD_FLOAT }, + {nsIDataType::VTYPE_DOUBLE , TD_DOUBLE }, + {nsIDataType::VTYPE_BOOL , TD_BOOL }, + {nsIDataType::VTYPE_CHAR , TD_CHAR }, + {nsIDataType::VTYPE_WCHAR , TD_WCHAR }, + {nsIDataType::VTYPE_VOID , TD_VOID }, + {nsIDataType::VTYPE_ID , TD_PNSIID }, + {nsIDataType::VTYPE_DOMSTRING , TD_DOMSTRING }, + {nsIDataType::VTYPE_CHAR_STR , TD_PSTRING }, + {nsIDataType::VTYPE_WCHAR_STR , TD_PWSTRING }, + {nsIDataType::VTYPE_INTERFACE , TD_INTERFACE_TYPE }, + {nsIDataType::VTYPE_INTERFACE_IS , TD_INTERFACE_IS_TYPE}, + {nsIDataType::VTYPE_ARRAY , TD_ARRAY }, + {nsIDataType::VTYPE_STRING_SIZE_IS , TD_PSTRING_SIZE_IS }, + {nsIDataType::VTYPE_WSTRING_SIZE_IS , TD_PWSTRING_SIZE_IS }, + {nsIDataType::VTYPE_UTF8STRING , TD_UTF8STRING }, + {nsIDataType::VTYPE_CSTRING , TD_CSTRING }, + {nsIDataType::VTYPE_ASTRING , TD_ASTRING } + }; + static const int length = sizeof(array)/sizeof(array[0]); + static PRBool inited = PR_FALSE; + if(!inited) + { + for(int i = 0; i < length; i++) + NS_ASSERTION(array[i].a == array[i].b, "bad const declaration"); + inited = PR_TRUE; + } + } +#endif +} + +nsVariant::~nsVariant() +{ + nsVariant::Cleanup(&mData); +} + +// For all the data getters we just forward to the static (and sharable) +// 'ConvertTo' functions. + +/* readonly attribute PRUint16 dataType; */ +NS_IMETHODIMP nsVariant::GetDataType(PRUint16 *aDataType) +{ + *aDataType = mData.mType; + return NS_OK; +} + +/* PRUint8 getAsInt8 (); */ +NS_IMETHODIMP nsVariant::GetAsInt8(PRUint8 *_retval) +{ + return nsVariant::ConvertToInt8(mData, _retval); +} + +/* PRInt16 getAsInt16 (); */ +NS_IMETHODIMP nsVariant::GetAsInt16(PRInt16 *_retval) +{ + return nsVariant::ConvertToInt16(mData, _retval); +} + +/* PRInt32 getAsInt32 (); */ +NS_IMETHODIMP nsVariant::GetAsInt32(PRInt32 *_retval) +{ + return nsVariant::ConvertToInt32(mData, _retval); +} + +/* PRInt64 getAsInt64 (); */ +NS_IMETHODIMP nsVariant::GetAsInt64(PRInt64 *_retval) +{ + return nsVariant::ConvertToInt64(mData, _retval); +} + +/* PRUint8 getAsUint8 (); */ +NS_IMETHODIMP nsVariant::GetAsUint8(PRUint8 *_retval) +{ + return nsVariant::ConvertToUint8(mData, _retval); +} + +/* PRUint16 getAsUint16 (); */ +NS_IMETHODIMP nsVariant::GetAsUint16(PRUint16 *_retval) +{ + return nsVariant::ConvertToUint16(mData, _retval); +} + +/* PRUint32 getAsUint32 (); */ +NS_IMETHODIMP nsVariant::GetAsUint32(PRUint32 *_retval) +{ + return nsVariant::ConvertToUint32(mData, _retval); +} + +/* PRUint64 getAsUint64 (); */ +NS_IMETHODIMP nsVariant::GetAsUint64(PRUint64 *_retval) +{ + return nsVariant::ConvertToUint64(mData, _retval); +} + +/* float getAsFloat (); */ +NS_IMETHODIMP nsVariant::GetAsFloat(float *_retval) +{ + return nsVariant::ConvertToFloat(mData, _retval); +} + +/* double getAsDouble (); */ +NS_IMETHODIMP nsVariant::GetAsDouble(double *_retval) +{ + return nsVariant::ConvertToDouble(mData, _retval); +} + +/* PRBool getAsBool (); */ +NS_IMETHODIMP nsVariant::GetAsBool(PRBool *_retval) +{ + return nsVariant::ConvertToBool(mData, _retval); +} + +/* char getAsChar (); */ +NS_IMETHODIMP nsVariant::GetAsChar(char *_retval) +{ + return nsVariant::ConvertToChar(mData, _retval); +} + +/* wchar getAsWChar (); */ +NS_IMETHODIMP nsVariant::GetAsWChar(PRUnichar *_retval) +{ + return nsVariant::ConvertToWChar(mData, _retval); +} + +/* [notxpcom] nsresult getAsID (out nsID retval); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsID(nsID *retval) +{ + return nsVariant::ConvertToID(mData, retval); +} + +/* AString getAsAString (); */ +NS_IMETHODIMP nsVariant::GetAsAString(nsAString & _retval) +{ + return nsVariant::ConvertToAString(mData, _retval); +} + +/* DOMString getAsDOMString (); */ +NS_IMETHODIMP nsVariant::GetAsDOMString(nsAString & _retval) +{ + // A DOMString maps to an AString internally, so we can re-use + // ConvertToAString here. + return nsVariant::ConvertToAString(mData, _retval); +} + +/* ACString getAsACString (); */ +NS_IMETHODIMP nsVariant::GetAsACString(nsACString & _retval) +{ + return nsVariant::ConvertToACString(mData, _retval); +} + +/* AUTF8String getAsAUTF8String (); */ +NS_IMETHODIMP nsVariant::GetAsAUTF8String(nsAUTF8String & _retval) +{ + return nsVariant::ConvertToAUTF8String(mData, _retval); +} + +/* string getAsString (); */ +NS_IMETHODIMP nsVariant::GetAsString(char **_retval) +{ + return nsVariant::ConvertToString(mData, _retval); +} + +/* wstring getAsWString (); */ +NS_IMETHODIMP nsVariant::GetAsWString(PRUnichar **_retval) +{ + return nsVariant::ConvertToWString(mData, _retval); +} + +/* nsISupports getAsISupports (); */ +NS_IMETHODIMP nsVariant::GetAsISupports(nsISupports **_retval) +{ + return nsVariant::ConvertToISupports(mData, _retval); +} + +/* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */ +NS_IMETHODIMP nsVariant::GetAsInterface(nsIID * *iid, void * *iface) +{ + return nsVariant::ConvertToInterface(mData, iid, iface); +} + +/* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */ +NS_IMETHODIMP_(nsresult) nsVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr) +{ + return nsVariant::ConvertToArray(mData, type, iid, count, ptr); +} + +/* void getAsStringWithSize (out PRUint32 size, [size_is (size), retval] out string str); */ +NS_IMETHODIMP nsVariant::GetAsStringWithSize(PRUint32 *size, char **str) +{ + return nsVariant::ConvertToStringWithSize(mData, size, str); +} + +/* void getAsWStringWithSize (out PRUint32 size, [size_is (size), retval] out wstring str); */ +NS_IMETHODIMP nsVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str) +{ + return nsVariant::ConvertToWStringWithSize(mData, size, str); +} + +/***************************************************************************/ + +/* attribute PRBool writable; */ +NS_IMETHODIMP nsVariant::GetWritable(PRBool *aWritable) +{ + *aWritable = mWritable; + return NS_OK; +} +NS_IMETHODIMP nsVariant::SetWritable(PRBool aWritable) +{ + if(!mWritable && aWritable) + return NS_ERROR_FAILURE; + mWritable = aWritable; + return NS_OK; +} + +/***************************************************************************/ + +// For all the data setters we just forward to the static (and sharable) +// 'SetFrom' functions. + +/* void setAsInt8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt8(&mData, aValue); +} + +/* void setAsInt16 (in PRInt16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt16(PRInt16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt16(&mData, aValue); +} + +/* void setAsInt32 (in PRInt32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt32(PRInt32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt32(&mData, aValue); +} + +/* void setAsInt64 (in PRInt64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsInt64(PRInt64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInt64(&mData, aValue); +} + +/* void setAsUint8 (in PRUint8 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint8(PRUint8 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint8(&mData, aValue); +} + +/* void setAsUint16 (in PRUint16 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint16(PRUint16 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint16(&mData, aValue); +} + +/* void setAsUint32 (in PRUint32 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint32(PRUint32 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint32(&mData, aValue); +} + +/* void setAsUint64 (in PRUint64 aValue); */ +NS_IMETHODIMP nsVariant::SetAsUint64(PRUint64 aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromUint64(&mData, aValue); +} + +/* void setAsFloat (in float aValue); */ +NS_IMETHODIMP nsVariant::SetAsFloat(float aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromFloat(&mData, aValue); +} + +/* void setAsDouble (in double aValue); */ +NS_IMETHODIMP nsVariant::SetAsDouble(double aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromDouble(&mData, aValue); +} + +/* void setAsBool (in PRBool aValue); */ +NS_IMETHODIMP nsVariant::SetAsBool(PRBool aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromBool(&mData, aValue); +} + +/* void setAsChar (in char aValue); */ +NS_IMETHODIMP nsVariant::SetAsChar(char aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromChar(&mData, aValue); +} + +/* void setAsWChar (in wchar aValue); */ +NS_IMETHODIMP nsVariant::SetAsWChar(PRUnichar aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWChar(&mData, aValue); +} + +/* void setAsID (in nsIDRef aValue); */ +NS_IMETHODIMP nsVariant::SetAsID(const nsID & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromID(&mData, aValue); +} + +/* void setAsAString (in AString aValue); */ +NS_IMETHODIMP nsVariant::SetAsAString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsDOMString (in DOMString aValue); */ +NS_IMETHODIMP nsVariant::SetAsDOMString(const nsAString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + + // A DOMString maps to an AString internally, so we can re-use + // SetFromAString here. + return nsVariant::SetFromAString(&mData, aValue); +} + +/* void setAsACString (in ACString aValue); */ +NS_IMETHODIMP nsVariant::SetAsACString(const nsACString & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromACString(&mData, aValue); +} + +/* void setAsAUTF8String (in AUTF8String aValue); */ +NS_IMETHODIMP nsVariant::SetAsAUTF8String(const nsAUTF8String & aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromAUTF8String(&mData, aValue); +} + +/* void setAsString (in string aValue); */ +NS_IMETHODIMP nsVariant::SetAsString(const char *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromString(&mData, aValue); +} + +/* void setAsWString (in wstring aValue); */ +NS_IMETHODIMP nsVariant::SetAsWString(const PRUnichar *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWString(&mData, aValue); +} + +/* void setAsISupports (in nsISupports aValue); */ +NS_IMETHODIMP nsVariant::SetAsISupports(nsISupports *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromISupports(&mData, aValue); +} + +/* void setAsInterface (in nsIIDRef iid, [iid_is (iid)] in nsQIResult iface); */ +NS_IMETHODIMP nsVariant::SetAsInterface(const nsIID & iid, void * iface) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromInterface(&mData, iid, (nsISupports*)iface); +} + +/* [noscript] void setAsArray (in PRUint16 type, in nsIIDPtr iid, in PRUint32 count, in voidPtr ptr); */ +NS_IMETHODIMP nsVariant::SetAsArray(PRUint16 type, const nsIID * iid, PRUint32 count, void * ptr) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromArray(&mData, type, iid, count, ptr); +} + +/* void setAsStringWithSize (in PRUint32 size, [size_is (size)] in string str); */ +NS_IMETHODIMP nsVariant::SetAsStringWithSize(PRUint32 size, const char *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromStringWithSize(&mData, size, str); +} + +/* void setAsWStringWithSize (in PRUint32 size, [size_is (size)] in wstring str); */ +NS_IMETHODIMP nsVariant::SetAsWStringWithSize(PRUint32 size, const PRUnichar *str) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromWStringWithSize(&mData, size, str); +} + +/* void setAsVoid (); */ +NS_IMETHODIMP nsVariant::SetAsVoid() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToVoid(&mData); +} + +/* void setAsEmpty (); */ +NS_IMETHODIMP nsVariant::SetAsEmpty() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmpty(&mData); +} + +/* void setAsEmptyArray (); */ +NS_IMETHODIMP nsVariant::SetAsEmptyArray() +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetToEmptyArray(&mData); +} + +/* void setFromVariant (in nsIVariant aValue); */ +NS_IMETHODIMP nsVariant::SetFromVariant(nsIVariant *aValue) +{ + if(!mWritable) return NS_ERROR_OBJECT_IS_IMMUTABLE; + return nsVariant::SetFromVariant(&mData, aValue); +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVariant.h b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h new file mode 100644 index 00000000..393e745f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVariant.h @@ -0,0 +1,203 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The long avoided variant support for xpcom. */ + +#include "nsIVariant.h" +#include "nsStringFwd.h" +#include "xpt_struct.h" + +/** + * Map the nsAUTF8String, nsUTF8String classes to the nsACString and + * nsCString classes respectively for now. These defines need to be removed + * once Jag lands his nsUTF8String implementation. + */ +#define nsAUTF8String nsACString +#define nsUTF8String nsCString +#define PromiseFlatUTF8String PromiseFlatCString + +/** + * nsDiscriminatedUnion is a type that nsIVariant implementors *may* use + * to hold underlying data. It has no methods. So, its use requires no linkage + * to the xpcom module. + */ + +struct nsDiscriminatedUnion +{ + union { + PRInt8 mInt8Value; + PRInt16 mInt16Value; + PRInt32 mInt32Value; + PRInt64 mInt64Value; + PRUint8 mUint8Value; + PRUint16 mUint16Value; + PRUint32 mUint32Value; + PRUint64 mUint64Value; + float mFloatValue; + double mDoubleValue; + PRBool mBoolValue; + char mCharValue; + PRUnichar mWCharValue; + nsIID mIDValue; + nsAString* mAStringValue; + nsAUTF8String* mUTF8StringValue; + nsACString* mCStringValue; + struct { + nsISupports* mInterfaceValue; + nsIID mInterfaceID; + } iface; + struct { + nsIID mArrayInterfaceID; + void* mArrayValue; + PRUint32 mArrayCount; + PRUint16 mArrayType; + } array; + struct { + char* mStringValue; + PRUint32 mStringLength; + } str; + struct { + PRUnichar* mWStringValue; + PRUint32 mWStringLength; + } wstr; + } u; + PRUint16 mType; +}; + +/** + * nsVariant implements the generic variant support. The xpcom module registers + * a factory (see NS_VARIANT_CONTRACTID in nsIVariant.idl) that will create + * these objects. They are created 'empty' and 'writable'. + * + * nsIVariant users won't usually need to see this class. + * + * This class also has static helper methods that nsIVariant *implementors* can + * use to help them do all the 'standard' nsIVariant data conversions. + */ + +class NS_COM nsVariant : public nsIWritableVariant +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIVARIANT + NS_DECL_NSIWRITABLEVARIANT + + nsVariant(); + + static nsresult Initialize(nsDiscriminatedUnion* data); + static nsresult Cleanup(nsDiscriminatedUnion* data); + + static nsresult ConvertToInt8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToInt16(const nsDiscriminatedUnion& data, PRInt16 *_retval); + static nsresult ConvertToInt32(const nsDiscriminatedUnion& data, PRInt32 *_retval); + static nsresult ConvertToInt64(const nsDiscriminatedUnion& data, PRInt64 *_retval); + static nsresult ConvertToUint8(const nsDiscriminatedUnion& data, PRUint8 *_retval); + static nsresult ConvertToUint16(const nsDiscriminatedUnion& data, PRUint16 *_retval); + static nsresult ConvertToUint32(const nsDiscriminatedUnion& data, PRUint32 *_retval); + static nsresult ConvertToUint64(const nsDiscriminatedUnion& data, PRUint64 *_retval); + static nsresult ConvertToFloat(const nsDiscriminatedUnion& data, float *_retval); + static nsresult ConvertToDouble(const nsDiscriminatedUnion& data, double *_retval); + static nsresult ConvertToBool(const nsDiscriminatedUnion& data, PRBool *_retval); + static nsresult ConvertToChar(const nsDiscriminatedUnion& data, char *_retval); + static nsresult ConvertToWChar(const nsDiscriminatedUnion& data, PRUnichar *_retval); + static nsresult ConvertToID(const nsDiscriminatedUnion& data, nsID * _retval); + static nsresult ConvertToAString(const nsDiscriminatedUnion& data, nsAString & _retval); + static nsresult ConvertToAUTF8String(const nsDiscriminatedUnion& data, nsAUTF8String & _retval); + static nsresult ConvertToACString(const nsDiscriminatedUnion& data, nsACString & _retval); + static nsresult ConvertToString(const nsDiscriminatedUnion& data, char **_retval); + static nsresult ConvertToWString(const nsDiscriminatedUnion& data, PRUnichar **_retval); + static nsresult ConvertToISupports(const nsDiscriminatedUnion& data, nsISupports **_retval); + static nsresult ConvertToInterface(const nsDiscriminatedUnion& data, nsIID * *iid, void * *iface); + static nsresult ConvertToArray(const nsDiscriminatedUnion& data, PRUint16 *type, nsIID* iid, PRUint32 *count, void * *ptr); + static nsresult ConvertToStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, char **str); + static nsresult ConvertToWStringWithSize(const nsDiscriminatedUnion& data, PRUint32 *size, PRUnichar **str); + + static nsresult SetFromVariant(nsDiscriminatedUnion* data, nsIVariant* aValue); + + static nsresult SetFromInt8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromInt16(nsDiscriminatedUnion* data, PRInt16 aValue); + static nsresult SetFromInt32(nsDiscriminatedUnion* data, PRInt32 aValue); + static nsresult SetFromInt64(nsDiscriminatedUnion* data, PRInt64 aValue); + static nsresult SetFromUint8(nsDiscriminatedUnion* data, PRUint8 aValue); + static nsresult SetFromUint16(nsDiscriminatedUnion* data, PRUint16 aValue); + static nsresult SetFromUint32(nsDiscriminatedUnion* data, PRUint32 aValue); + static nsresult SetFromUint64(nsDiscriminatedUnion* data, PRUint64 aValue); + static nsresult SetFromFloat(nsDiscriminatedUnion* data, float aValue); + static nsresult SetFromDouble(nsDiscriminatedUnion* data, double aValue); + static nsresult SetFromBool(nsDiscriminatedUnion* data, PRBool aValue); + static nsresult SetFromChar(nsDiscriminatedUnion* data, char aValue); + static nsresult SetFromWChar(nsDiscriminatedUnion* data, PRUnichar aValue); + static nsresult SetFromID(nsDiscriminatedUnion* data, const nsID & aValue); + static nsresult SetFromAString(nsDiscriminatedUnion* data, const nsAString & aValue); + static nsresult SetFromAUTF8String(nsDiscriminatedUnion* data, const nsAUTF8String & aValue); + static nsresult SetFromACString(nsDiscriminatedUnion* data, const nsACString & aValue); + static nsresult SetFromString(nsDiscriminatedUnion* data, const char *aValue); + static nsresult SetFromWString(nsDiscriminatedUnion* data, const PRUnichar *aValue); + static nsresult SetFromISupports(nsDiscriminatedUnion* data, nsISupports *aValue); + static nsresult SetFromInterface(nsDiscriminatedUnion* data, const nsIID& iid, nsISupports *aValue); + static nsresult SetFromArray(nsDiscriminatedUnion* data, PRUint16 type, const nsIID* iid, PRUint32 count, void * aValue); + static nsresult SetFromStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const char *aValue); + static nsresult SetFromWStringWithSize(nsDiscriminatedUnion* data, PRUint32 size, const PRUnichar *aValue); + + static nsresult SetToVoid(nsDiscriminatedUnion* data); + static nsresult SetToEmpty(nsDiscriminatedUnion* data); + static nsresult SetToEmptyArray(nsDiscriminatedUnion* data); + +private: + ~nsVariant(); + +protected: + nsDiscriminatedUnion mData; + PRBool mWritable; +}; + +/** + * Users of nsIVariant should be using the contractID and not this CID. + * - see NS_VARIANT_CONTRACTID in nsIVariant.idl. + */ + +#define NS_VARIANT_CID \ +{ /* 0D6EA1D0-879C-11d5-90EF-0010A4E73D9A */ \ + 0xd6ea1d0, \ + 0x879c, \ + 0x11d5, \ + {0x90, 0xef, 0x0, 0x10, 0xa4, 0xe7, 0x3d, 0x9a}} + +#define NS_VARIANT_CLASSNAME "Variant" + diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp new file mode 100644 index 00000000..259d0bd3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.cpp @@ -0,0 +1,1560 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsVoidArray.h" +#include "nsQuickSort.h" +#include "prmem.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prbit.h" + +/** + * Grow the array by at least this many elements at a time. + */ +static const PRInt32 kMinGrowArrayBy = 8; +static const PRInt32 kMaxGrowArrayBy = 1024; + +/** + * This is the threshold (in bytes) of the mImpl struct, past which + * we'll force the array to grow geometrically + */ +static const PRInt32 kLinearThreshold = 24 * sizeof(void *); + +/** + * Compute the number of bytes requires for the mImpl struct that will + * hold |n| elements. + */ +#define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1)) + + +/** + * Compute the number of elements that an mImpl struct of |n| bytes + * will hold. + */ +#define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1) + +#if DEBUG_VOIDARRAY +#define MAXVOID 10 + +class VoidStats { +public: + VoidStats(); + ~VoidStats(); + +}; + +static int sizesUsed; // number of the elements of the arrays used +static int sizesAlloced[MAXVOID]; // sizes of the allocations. sorted +static int NumberOfSize[MAXVOID]; // number of this allocation size (1 per array) +static int AllocedOfSize[MAXVOID]; // number of this allocation size (each size for array used) +static int MaxAuto[MAXVOID]; // AutoArrays that maxed out at this size +static int GrowInPlace[MAXVOID]; // arrays this size that grew in-place via realloc + +// these are per-allocation +static int MaxElements[2000]; // # of arrays that maxed out at each size. + +// statistics macros +#define ADD_TO_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])++; break; } \ + } \ + if (i >= sizesUsed && sizesUsed < MAXVOID) \ + { sizesAlloced[sizesUsed] = (size); \ + ((x)[sizesUsed++])++; break; \ + } \ + } while (0) + +#define SUB_FROM_STATS(x,size) do {int i; for (i = 0; i < sizesUsed; i++) \ + { \ + if (sizesAlloced[i] == (int)(size)) \ + { ((x)[i])--; break; } \ + } \ + } while (0) + + +VoidStats::VoidStats() +{ + sizesUsed = 1; + sizesAlloced[0] = 0; +} + +VoidStats::~VoidStats() +{ + int i; + for (i = 0; i < sizesUsed; i++) + { + printf("Size %d:\n",sizesAlloced[i]); + printf("\tNumber of VoidArrays this size (max): %d\n",NumberOfSize[i]-MaxAuto[i]); + printf("\tNumber of AutoVoidArrays this size (max): %d\n",MaxAuto[i]); + printf("\tNumber of allocations this size (total): %d\n",AllocedOfSize[i]); + printf("\tNumber of GrowsInPlace this size (total): %d\n",GrowInPlace[i]); + } + printf("Max Size of VoidArray:\n"); + for (i = 0; i < (int)(sizeof(MaxElements)/sizeof(MaxElements[0])); i++) + { + if (MaxElements[i]) + printf("\t%d: %d\n",i,MaxElements[i]); + } +} + +// Just so constructor/destructor's get called +VoidStats gVoidStats; +#endif + +inline void +nsVoidArray::SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner) +{ + // old mImpl has been realloced and so we don't free/delete it + NS_PRECONDITION(newImpl, "can't set size"); + mImpl = newImpl; + mImpl->mCount = aCount; + mImpl->mBits = PRUint32(aSize & kArraySizeMask) | + (owner ? kArrayOwnerMask : 0); +} + +// This does all allocation/reallocation of the array. +// It also will compact down to N - good for things that might grow a lot +// at times, but usually are smaller, like JS deferred GC releases. +PRBool nsVoidArray::SizeTo(PRInt32 aSize) +{ + PRUint32 oldsize = GetArraySize(); + + if (aSize == (PRInt32) oldsize) + return PR_TRUE; // no change + + if (aSize <= 0) + { + // free the array if allocated + if (mImpl) + { + if (IsArrayOwner()) + { + PR_Free(NS_REINTERPRET_CAST(char *, mImpl)); + mImpl = nsnull; + } + else + { + mImpl->mCount = 0; // nsAutoVoidArray + } + } + return PR_TRUE; + } + + if (mImpl && IsArrayOwner()) + { + // We currently own an array impl. Resize it appropriately. + if (aSize < mImpl->mCount) + { + // XXX Note: we could also just resize to mCount + return PR_TRUE; // can't make it that small, ignore request + } + + char* bytes = (char *) PR_Realloc(mImpl,SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + if (mImpl == newImpl) + ADD_TO_STATS(GrowInPlace,oldsize); + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + if (mIsAuto) + { + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,oldsize); + } + } +#endif + SetArray(newImpl,aSize,newImpl->mCount,PR_TRUE); + return PR_TRUE; + } + + // just allocate an array + // allocate the exact size requested + char* bytes = (char *) PR_Malloc(SIZEOF_IMPL(aSize)); + Impl* newImpl = NS_REINTERPRET_CAST(Impl*, bytes); + if (!newImpl) + return PR_FALSE; + +#if DEBUG_VOIDARRAY + ADD_TO_STATS(AllocedOfSize,SIZEOF_IMPL(aSize)); + if (aSize > mMaxSize) + { + ADD_TO_STATS(NumberOfSize,SIZEOF_IMPL(aSize)); + if (oldsize && !mImpl) + SUB_FROM_STATS(NumberOfSize,oldsize); + mMaxSize = aSize; + } +#endif + if (mImpl) + { +#if DEBUG_VOIDARRAY + ADD_TO_STATS(MaxAuto,SIZEOF_IMPL(aSize)); + SUB_FROM_STATS(MaxAuto,0); + SUB_FROM_STATS(NumberOfSize,0); + mIsAuto = PR_TRUE; +#endif + // We must be growing an nsAutoVoidArray - copy since we didn't + // realloc. + memcpy(newImpl->mArray, mImpl->mArray, + mImpl->mCount * sizeof(mImpl->mArray[0])); + } + + SetArray(newImpl,aSize,mImpl ? mImpl->mCount : 0,PR_TRUE); + // no memset; handled later in ReplaceElementAt if needed + return PR_TRUE; +} + +PRBool nsVoidArray::GrowArrayBy(PRInt32 aGrowBy) +{ + // We have to grow the array. Grow by kMinGrowArrayBy slots if we're + // smaller than kLinearThreshold bytes, or a power of two if we're + // larger. This is much more efficient with most memory allocators, + // especially if it's very large, or of the allocator is binned. + if (aGrowBy < kMinGrowArrayBy) + aGrowBy = kMinGrowArrayBy; + + PRUint32 newCapacity = GetArraySize() + aGrowBy; // Minimum increase + PRUint32 newSize = SIZEOF_IMPL(newCapacity); + + if (newSize >= (PRUint32) kLinearThreshold) + { + // newCount includes enough space for at least kMinGrowArrayBy new + // slots. Select the next power-of-two size in bytes above or + // equal to that. + // Also, limit the increase in size to about a VM page or two. + if (GetArraySize() >= kMaxGrowArrayBy) + { + newCapacity = GetArraySize() + PR_MAX(kMaxGrowArrayBy,aGrowBy); + newSize = SIZEOF_IMPL(newCapacity); + } + else + { + newSize = PR_BIT(PR_CeilingLog2(newSize)); + newCapacity = CAPACITYOF_IMPL(newSize); + } + } + // frees old mImpl IF this succeeds + if (!SizeTo(newCapacity)) + return PR_FALSE; + + return PR_TRUE; +} + +nsVoidArray::nsVoidArray() + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + ADD_TO_STATS(NumberOfSize,0); + MaxElements[0]++; +#endif +} + +nsVoidArray::nsVoidArray(PRInt32 aCount) + : mImpl(nsnull) +{ + MOZ_COUNT_CTOR(nsVoidArray); +#if DEBUG_VOIDARRAY + mMaxCount = 0; + mMaxSize = 0; + mIsAuto = PR_FALSE; + MaxElements[0]++; +#endif + SizeTo(aCount); +} + +nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) +{ + PRInt32 otherCount = other.Count(); + PRInt32 maxCount = GetArraySize(); + if (otherCount) + { + if (otherCount > maxCount) + { + // frees old mImpl IF this succeeds + if (!GrowArrayBy(otherCount-maxCount)) + return *this; // XXX The allocation failed - don't do anything + + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + } + else + { + // the old array can hold the new array + memcpy(mImpl->mArray, other.mImpl->mArray, otherCount * sizeof(mImpl->mArray[0])); + mImpl->mCount = otherCount; + // if it shrank a lot, compact it anyways + if ((otherCount*2) < maxCount && maxCount > 100) + { + Compact(); // shrank by at least 50 entries + } + } +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + else + { + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); + + mImpl = nsnull; + } + + return *this; +} + +nsVoidArray::~nsVoidArray() +{ + MOZ_COUNT_DTOR(nsVoidArray); + if (mImpl && IsArrayOwner()) + PR_Free(NS_REINTERPRET_CAST(char*, mImpl)); +} + +PRInt32 nsVoidArray::IndexOf(void* aPossibleElement) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + if (*ap == aPossibleElement) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool nsVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"InsertElementAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that add more than one entry to the + // array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount >= GetArraySize()) + { + if (!GrowArrayBy(1)) + return PR_FALSE; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + 1, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + mImpl->mArray[aIndex] = aElement; + mImpl->mCount++; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::InsertElementsAt(const nsVoidArray& other, PRInt32 aIndex) +{ + PRInt32 oldCount = Count(); + PRInt32 otherCount = other.Count(); + + NS_ASSERTION(aIndex >= 0,"InsertElementsAt(negative index)"); + if (PRUint32(aIndex) > PRUint32(oldCount)) + { + // An invalid index causes the insertion to fail + // Invalid indexes are ones that are more than one entry past the end of + // the array (i.e., they can append). + return PR_FALSE; + } + + if (oldCount + otherCount > GetArraySize()) + { + if (!GrowArrayBy(otherCount)) + return PR_FALSE;; + } + // else the array is already large enough + + PRInt32 slide = oldCount - aIndex; + if (0 != slide) + { + // Slide data over to make room for the insertion + memmove(mImpl->mArray + aIndex + otherCount, mImpl->mArray + aIndex, + slide * sizeof(mImpl->mArray[0])); + } + + for (PRInt32 i = 0; i < otherCount; i++) + { + // copy all the elements (destroys aIndex) + mImpl->mArray[aIndex++] = other.mImpl->mArray[i]; + mImpl->mCount++; + } + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + + return PR_TRUE; +} + +PRBool nsVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(aIndex >= 0,"ReplaceElementAt(negative index)"); + if (aIndex < 0) + return PR_FALSE; + + // Unlike InsertElementAt, ReplaceElementAt can implicitly add more + // than just the one element to the array. + if (PRUint32(aIndex) >= PRUint32(GetArraySize())) + { + PRInt32 oldCount = Count(); + PRInt32 requestedCount = aIndex + 1; + PRInt32 growDelta = requestedCount - oldCount; + + // frees old mImpl IF this succeeds + if (!GrowArrayBy(growDelta)) + return PR_FALSE; + } + + mImpl->mArray[aIndex] = aElement; + if (aIndex >= mImpl->mCount) + { + // Make sure that any entries implicitly added to the array by this + // ReplaceElementAt are cleared to 0. Some users of this assume that. + // This code means we don't have to memset when we allocate an array. + if (aIndex > mImpl->mCount) // note: not >= + { + // For example, if mCount is 2, and we do a ReplaceElementAt for + // element[5], then we need to set three entries ([2], [3], and [4]) + // to 0. + memset(&mImpl->mArray[mImpl->mCount], 0, + (aIndex - mImpl->mCount) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount = aIndex + 1; + +#if DEBUG_VOIDARRAY + if (mImpl->mCount > mMaxCount && + mImpl->mCount < (PRInt32)(sizeof(MaxElements)/sizeof(MaxElements[0]))) + { + MaxElements[mImpl->mCount]++; + MaxElements[mMaxCount]--; + mMaxCount = mImpl->mCount; + } +#endif + } + + return PR_TRUE; +} + +// useful for doing LRU arrays +PRBool nsVoidArray::MoveElement(PRInt32 aFrom, PRInt32 aTo) +{ + void *tempElement; + + if (aTo == aFrom) + return PR_TRUE; + + NS_ASSERTION(aTo >= 0 && aFrom >= 0,"MoveElement(negative index)"); + if (aTo >= Count() || aFrom >= Count()) + { + // can't extend the array when moving an element. Also catches mImpl = null + return PR_FALSE; + } + tempElement = mImpl->mArray[aFrom]; + + if (aTo < aFrom) + { + // Moving one element closer to the head; the elements inbetween move down + memmove(mImpl->mArray + aTo + 1, mImpl->mArray + aTo, + (aFrom-aTo) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + else // already handled aFrom == aTo + { + // Moving one element closer to the tail; the elements inbetween move up + memmove(mImpl->mArray + aFrom, mImpl->mArray + aFrom + 1, + (aTo-aFrom) * sizeof(mImpl->mArray[0])); + mImpl->mArray[aTo] = tempElement; + } + + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + PRInt32 oldCount = Count(); + NS_ASSERTION(aIndex >= 0,"RemoveElementsAt(negative index)"); + if (PRUint32(aIndex) >= PRUint32(oldCount)) + { + // An invalid index causes the replace to fail + return PR_FALSE; + } + // Limit to available entries starting at aIndex + if (aCount + aIndex > oldCount) + aCount = oldCount - aIndex; + + // We don't need to move any elements if we're removing the + // last element in the array + if (aIndex < (oldCount - aCount)) + { + memmove(mImpl->mArray + aIndex, mImpl->mArray + aIndex + aCount, + (oldCount - (aIndex + aCount)) * sizeof(mImpl->mArray[0])); + } + + mImpl->mCount -= aCount; + return PR_TRUE; +} + +PRBool nsVoidArray::RemoveElement(void* aElement) +{ + PRInt32 theIndex = IndexOf(aElement); + if (theIndex != -1) + return RemoveElementAt(theIndex); + + return PR_FALSE; +} + +void nsVoidArray::Clear() +{ + if (mImpl) + { + mImpl->mCount = 0; + } +} + +void nsVoidArray::Compact() +{ + if (mImpl) + { + // XXX NOTE: this is quite inefficient in many cases if we're only + // compacting by a little, but some callers care more about memory use. + if (GetArraySize() > Count()) + { + SizeTo(Count()); + } + } +} + +// Needed because we want to pass the pointer to the item in the array +// to the comparator function, not a pointer to the pointer in the array. +struct VoidArrayComparatorContext { + nsVoidArrayComparatorFunc mComparatorFunc; + void* mData; +}; + +PR_STATIC_CALLBACK(int) +VoidArrayComparator(const void* aElement1, const void* aElement2, void* aData) +{ + VoidArrayComparatorContext* ctx = NS_STATIC_CAST(VoidArrayComparatorContext*, aData); + return (*ctx->mComparatorFunc)(*NS_STATIC_CAST(void* const*, aElement1), + *NS_STATIC_CAST(void* const*, aElement2), + ctx->mData); +} + +void nsVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (mImpl && mImpl->mCount > 1) + { + VoidArrayComparatorContext ctx = {aFunc, aData}; + NS_QuickSort(mImpl->mArray, mImpl->mCount, sizeof(mImpl->mArray[0]), + VoidArrayComparator, &ctx); + } +} + +PRBool nsVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +PRBool nsVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(mImpl->mArray[index], aData); + } + } + return running; +} + +//---------------------------------------------------------------- +// nsAutoVoidArray + +nsAutoVoidArray::nsAutoVoidArray() + : nsVoidArray() +{ + // Don't need to clear it. Some users just call ReplaceElementAt(), + // but we'll clear it at that time if needed to save CPU cycles. +#if DEBUG_VOIDARRAY + mIsAuto = PR_TRUE; + ADD_TO_STATS(MaxAuto,0); +#endif + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); +} + +void nsAutoVoidArray::Clear() +{ + // We don't have to free on Clear, but since we have a built-in buffer, + // it's worth considering. + nsVoidArray::Clear(); + if (IsArrayOwner() && GetArraySize() > 4*kAutoBufSize) + SizeTo(0); // we override CompactTo - delete and repoint at auto array +} + +PRBool nsAutoVoidArray::SizeTo(PRInt32 aSize) +{ + if (!nsVoidArray::SizeTo(aSize)) + return PR_FALSE; + + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } + return PR_TRUE; +} + +void nsAutoVoidArray::Compact() +{ + nsVoidArray::Compact(); + if (!mImpl) + { + // reset the array to point to our autobuf + SetArray(NS_REINTERPRET_CAST(Impl*, mAutoBuf),kAutoBufSize,0,PR_FALSE); + } +} + +//---------------------------------------------------------------- +// nsStringArray + +nsStringArray::nsStringArray(void) + : nsVoidArray() +{ +} + +nsStringArray::nsStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsStringArray::~nsStringArray(void) +{ + Clear(); +} + +nsStringArray& +nsStringArray::operator=(const nsStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsString* oldString = NS_STATIC_CAST(nsString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsString(*oldString); + } + + return *this; +} + +void +nsStringArray::StringAt(PRInt32 aIndex, nsAString& aString) const +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aString.Assign(*string); + } + else + { + aString.Truncate(); + } +} + +nsString* +nsStringArray::StringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsStringArray::IndexOf(const nsAString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsString* string = NS_STATIC_CAST(nsString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsStringArray::InsertStringAt(const nsAString& aString, PRInt32 aIndex) +{ + nsString* string = new nsString(aString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsStringArray::ReplaceStringAt(const nsAString& aString, + PRInt32 aIndex) +{ + nsString* string = NS_STATIC_CAST(nsString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsStringArray::RemoveString(const nsAString& aString) +{ + PRInt32 index = IndexOf(aString); + if (-1 < index) + { + return RemoveStringAt(index); + } + return PR_FALSE; +} + +PRBool nsStringArray::RemoveStringAt(PRInt32 aIndex) +{ + nsString* string = StringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsString* string = NS_STATIC_CAST(nsString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareString(const nsString* aString1, const nsString* aString2, void*) +{ + return Compare(*aString1, *aString2); +} + +void nsStringArray::Sort(void) +{ + Sort(CompareString, nsnull); +} + +void nsStringArray::Sort(nsStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsStringArray::EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = -1; + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsStringArray::EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData) +{ + PRInt32 index = Count(); + PRBool running = PR_TRUE; + + if (mImpl) + { + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + + +//---------------------------------------------------------------- +// nsCStringArray + +nsCStringArray::nsCStringArray(void) + : nsVoidArray() +{ +} + +// Parses a given string using the delimiter passed in and appends items +// parsed to the array. +void +nsCStringArray::ParseString(const char* string, const char* delimiter) +{ + if (string && *string && delimiter && *delimiter) { + char *newStr; + char *rest = nsCRT::strdup(string); + char *token = nsCRT::strtok(rest, delimiter, &newStr); + + while (token) { + if (*token) { + /* calling AppendElement(void*) to avoid extra nsCString copy */ + AppendElement(new nsCString(token)); + } + token = nsCRT::strtok(newStr, delimiter, &newStr); + } + PR_FREEIF(rest); + } +} + +nsCStringArray::nsCStringArray(PRInt32 aCount) + : nsVoidArray(aCount) +{ +} + +nsCStringArray::~nsCStringArray(void) +{ + Clear(); +} + +nsCStringArray& +nsCStringArray::operator=(const nsCStringArray& other) +{ + // Copy the pointers + nsVoidArray::operator=(other); + + // Now copy the strings + for (PRInt32 i = Count() - 1; i >= 0; --i) + { + nsCString* oldString = NS_STATIC_CAST(nsCString*, other.ElementAt(i)); + mImpl->mArray[i] = new nsCString(*oldString); + } + + return *this; +} + +void +nsCStringArray::CStringAt(PRInt32 aIndex, nsACString& aCString) const +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + aCString = *string; + } + else + { + aCString.Truncate(); + } +} + +nsCString* +nsCStringArray::CStringAt(PRInt32 aIndex) const +{ + return NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); +} + +PRInt32 +nsCStringArray::IndexOf(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString)) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRInt32 +nsCStringArray::IndexOfIgnoreCase(const nsACString& aPossibleString) const +{ + if (mImpl) + { + void** ap = mImpl->mArray; + void** end = ap + mImpl->mCount; + while (ap < end) + { + nsCString* string = NS_STATIC_CAST(nsCString*, *ap); + if (string->Equals(aPossibleString, nsCaseInsensitiveCStringComparator())) + { + return ap - mImpl->mArray; + } + ap++; + } + } + return -1; +} + +PRBool +nsCStringArray::InsertCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = new nsCString(aCString); + if (nsVoidArray::InsertElementAt(string, aIndex)) + { + return PR_TRUE; + } + delete string; + return PR_FALSE; +} + +PRBool +nsCStringArray::ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex) +{ + nsCString* string = NS_STATIC_CAST(nsCString*, nsVoidArray::ElementAt(aIndex)); + if (nsnull != string) + { + *string = aCString; + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCString(const nsACString& aCString) +{ + PRInt32 index = IndexOf(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool +nsCStringArray::RemoveCStringIgnoreCase(const nsACString& aCString) +{ + PRInt32 index = IndexOfIgnoreCase(aCString); + if (-1 < index) + { + return RemoveCStringAt(index); + } + return PR_FALSE; +} + +PRBool nsCStringArray::RemoveCStringAt(PRInt32 aIndex) +{ + nsCString* string = CStringAt(aIndex); + if (nsnull != string) + { + nsVoidArray::RemoveElementAt(aIndex); + delete string; + return PR_TRUE; + } + return PR_FALSE; +} + +void +nsCStringArray::Clear(void) +{ + PRInt32 index = Count(); + while (0 <= --index) + { + nsCString* string = NS_STATIC_CAST(nsCString*, mImpl->mArray[index]); + delete string; + } + nsVoidArray::Clear(); +} + +PR_STATIC_CALLBACK(int) +CompareCString(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2); +} + +PR_STATIC_CALLBACK(int) +CompareCStringIgnoreCase(const nsCString* aCString1, const nsCString* aCString2, void*) +{ + return Compare(*aCString1, *aCString2, nsCaseInsensitiveCStringComparator()); +} + +void nsCStringArray::Sort(void) +{ + Sort(CompareCString, nsnull); +} + +void nsCStringArray::SortIgnoreCase(void) +{ + Sort(CompareCStringIgnoreCase, nsnull); +} + +void nsCStringArray::Sort(nsCStringArrayComparatorFunc aFunc, void* aData) +{ + nsVoidArray::Sort(NS_REINTERPRET_CAST(nsVoidArrayComparatorFunc, aFunc), aData); +} + +PRBool +nsCStringArray::EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = -1; + while (running && (++index < mImpl->mCount)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + +PRBool +nsCStringArray::EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData) +{ + PRBool running = PR_TRUE; + + if (mImpl) + { + PRInt32 index = Count(); + while (running && (0 <= --index)) + { + running = (*aFunc)(*NS_STATIC_CAST(nsCString*, mImpl->mArray[index]), aData); + } + } + return running; +} + + +//---------------------------------------------------------------------- +// NOTE: nsSmallVoidArray elements MUST all have the low bit as 0. +// This means that normally it's only used for pointers, and in particular +// structures or objects. +nsSmallVoidArray::nsSmallVoidArray() +{ + mChildren = nsnull; +} + +nsSmallVoidArray::~nsSmallVoidArray() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + delete vector; + } +} + +nsSmallVoidArray& +nsSmallVoidArray::operator=(nsSmallVoidArray& other) +{ + nsVoidArray* ourArray = GetChildVector(); + nsVoidArray* otherArray = other.GetChildVector(); + + if (HasVector()) + { + if (other.HasVector()) + { + // if both are real arrays, just use array= */ + *ourArray = *otherArray; + } + else + { + // we have an array, but the other doesn't. + otherArray = other.SwitchToVector(); + if (otherArray) + *ourArray = *otherArray; + } + } + else + { + if (other.HasVector()) + { + // we have no array, but other does + ourArray = SwitchToVector(); + if (ourArray) + *ourArray = *otherArray; + } + else + { + // neither has an array (either may have 0 or 1 items) + SetSingleChild(other.GetSingleChild()); + } + } + return *this; +} + +PRInt32 +nsSmallVoidArray::GetArraySize() const +{ + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->GetArraySize(); + + return 1; +} + +PRInt32 +nsSmallVoidArray::Count() const +{ + if (HasSingleChild()) + { + return 1; + } + else { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->Count(); + } + + return 0; +} + +void* +nsSmallVoidArray::ElementAt(PRInt32 aIndex) const +{ + if (HasSingleChild()) + { + if (0 == aIndex) + return (void*)GetSingleChild(); + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ElementAt(aIndex); + } + + return nsnull; +} + +PRInt32 +nsSmallVoidArray::IndexOf(void* aPossibleElement) const +{ + if (HasSingleChild()) + { + if (aPossibleElement == (void*)GetSingleChild()) + return 0; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->IndexOf(aPossibleElement); + } + + return -1; +} + +PRBool +nsSmallVoidArray::InsertElementAt(void* aElement, PRInt32 aIndex) +{ + nsVoidArray* vector; + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + if (0 == aIndex) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + } + + return vector->InsertElementAt(aElement, aIndex); +} + +PRBool nsSmallVoidArray::InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex) +{ + nsVoidArray* vector; + PRInt32 count = other.Count(); + if (count == 0) + return PR_TRUE; + +#ifdef DEBUG + for (int i = 0; i < count; i++) + { + NS_ASSERTION(!(PtrBits(other.ElementAt(i)) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(other.ElementAt(i) != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + } +#endif + + if (!HasVector()) + { + if (HasSingleChild() || count > 1 || aIndex > 0) + { + vector = SwitchToVector(); + } + else + { + // count == 1, aIndex == 0, no elements already + SetSingleChild(other[0]); + return PR_TRUE; + } + } + else + { + vector = GetChildVector(); + } + + if (vector) + { + return vector->InsertElementsAt(other,aIndex); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::ReplaceElementAt(void* aElement, PRInt32 aIndex) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + if (HasSingleChild()) + { + if (aIndex == 0) + { + SetSingleChild(aElement); + return PR_TRUE; + } + return PR_FALSE; + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->ReplaceElementAt(aElement, aIndex); + + return PR_FALSE; + } +} + +PRBool +nsSmallVoidArray::AppendElement(void* aElement) +{ + NS_ASSERTION(!(PtrBits(aElement) & 0x1),"Attempt to add element with 0x1 bit set to nsSmallVoidArray"); + NS_ASSERTION(aElement != nsnull,"Attempt to add a NULL element to an nsSmallVoidArray"); + + nsVoidArray* vector; + if (HasSingleChild()) + { + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (!vector) + { + SetSingleChild(aElement); + return PR_TRUE; + } + } + + return vector->AppendElement(aElement); +} + +PRBool +nsSmallVoidArray::RemoveElement(void* aElement) +{ + if (HasSingleChild()) + { + if (aElement == GetSingleChild()) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + return vector->RemoveElement(aElement); + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementAt(PRInt32 aIndex) +{ + if (HasSingleChild()) + { + if (0 == aIndex) + { + SetSingleChild(nsnull); + return PR_TRUE; + } + } + else + { + nsVoidArray* vector = GetChildVector(); + if (vector) + { + return vector->RemoveElementAt(aIndex); + } + } + + return PR_FALSE; +} + +PRBool +nsSmallVoidArray::RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount) +{ + nsVoidArray* vector = GetChildVector(); + + if (aCount == 0) + return PR_TRUE; + + if (HasSingleChild()) + { + if (aIndex == 0) + SetSingleChild(nsnull); + return PR_TRUE; + } + + if (!vector) + return PR_TRUE; + + // complex case; remove entries from an array + return vector->RemoveElementsAt(aIndex,aCount); +} + +void +nsSmallVoidArray::Clear() +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Clear(); + } + else + { + SetSingleChild(nsnull); + } +} + +PRBool +nsSmallVoidArray::SizeTo(PRInt32 aMin) +{ + nsVoidArray* vector; + if (!HasVector()) + { + if (aMin <= 1) + return PR_TRUE; + vector = SwitchToVector(); + } + else + { + vector = GetChildVector(); + if (aMin <= 1) + { + void *prev = nsnull; + if (vector->Count() == 1) + { + prev = vector->ElementAt(0); + } + delete vector; + SetSingleChild(prev); + return PR_TRUE; + } + } + return vector->SizeTo(aMin); +} + +void +nsSmallVoidArray::Compact() +{ + if (!HasSingleChild()) + { + nsVoidArray* vector = GetChildVector(); + if (vector) + vector->Compact(); + } +} + +void +nsSmallVoidArray::Sort(nsVoidArrayComparatorFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + vector->Sort(aFunc,aData); + } +} + +PRBool +nsSmallVoidArray::EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateForwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +PRBool +nsSmallVoidArray::EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData) +{ + if (HasVector()) + { + nsVoidArray* vector = GetChildVector(); + return vector->EnumerateBackwards(aFunc,aData); + } + if (HasSingleChild()) + { + return (*aFunc)(GetSingleChild(), aData); + } + return PR_TRUE; +} + +void +nsSmallVoidArray::SetSingleChild(void* aChild) +{ + if (aChild) + mChildren = (void*)(PtrBits(aChild) | 0x1); + else + mChildren = nsnull; +} + +nsVoidArray* +nsSmallVoidArray::SwitchToVector() +{ + void* child = GetSingleChild(); + + mChildren = (void*)new nsAutoVoidArray(); + nsVoidArray* vector = GetChildVector(); + if (vector && child) + vector->AppendElement(child); + + return vector; +} diff --git a/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h new file mode 100644 index 00000000..28d950e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/nsVoidArray.h @@ -0,0 +1,410 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsVoidArray_h___ +#define nsVoidArray_h___ + +//#define DEBUG_VOIDARRAY 1 + +#include "nscore.h" +#include "nsAString.h" + +// Comparator callback function for sorting array values. +typedef int (* PR_CALLBACK nsVoidArrayComparatorFunc) + (const void* aElement1, const void* aElement2, void* aData); + +// Enumerator callback function. Return PR_FALSE to stop +typedef PRBool (* PR_CALLBACK nsVoidArrayEnumFunc)(void* aElement, void *aData); + +/// A basic zero-based array of void*'s that manages its own memory +class NS_COM nsVoidArray { +public: + nsVoidArray(); + nsVoidArray(PRInt32 aCount); // initial count of aCount elements set to nsnull + virtual ~nsVoidArray(); + + nsVoidArray& operator=(const nsVoidArray& other); + + inline PRInt32 Count() const { + return mImpl ? mImpl->mCount : 0; + } + // returns the max number that can be held without allocating + inline PRInt32 GetArraySize() const { + return mImpl ? (PRInt32(mImpl->mBits) & kArraySizeMask) : 0; + } + + void* FastElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return mImpl->mArray[aIndex]; + } + + // This both asserts and bounds-checks, because (1) we don't want + // people to write bad code, but (2) we don't want to change it to + // crashing for backwards compatibility. See bug 96108. + void* ElementAt(PRInt32 aIndex) const + { + NS_ASSERTION(0 <= aIndex && aIndex < Count(), "index out of range"); + return SafeElementAt(aIndex); + } + + // bounds-checked version + void* SafeElementAt(PRInt32 aIndex) const + { + if (PRUint32(aIndex) >= PRUint32(Count())) // handles aIndex < 0 too + { + return nsnull; + } + // The bounds check ensures mImpl is non-null. + return mImpl->mArray[aIndex]; + } + + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 IndexOf(void* aPossibleElement) const; + + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + + // useful for doing LRU arrays, sorting, etc + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + + PRBool AppendElement(void* aElement) { + return InsertElementAt(aElement, Count()); + } + + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex) { return RemoveElementsAt(aIndex,1); } + + virtual void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + // Subtly different - Compact() tries to be smart about whether we + // should reallocate the array; SizeTo() just does it. + virtual void Compact(); + + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +protected: + virtual PRBool GrowArrayBy(PRInt32 aGrowBy); + + struct Impl { + /** + * Packed bits. The low 31 bits are the array's size. + * The highest bit is a flag that indicates + * whether or not we "own" mArray, and must free() it when + * destroyed. + */ + PRUint32 mBits; + + /** + * The number of elements in the array + */ + PRInt32 mCount; + + /** + * Array data, padded out to the actual size of the array. + */ + void* mArray[1]; + }; + + Impl* mImpl; +#if DEBUG_VOIDARRAY + PRInt32 mMaxCount; + PRInt32 mMaxSize; + PRBool mIsAuto; +#endif + + enum { + kArrayOwnerMask = 1 << 31, + kArraySizeMask = ~kArrayOwnerMask + }; + + + // bit twiddlers + void SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, PRBool owner); + inline PRBool IsArrayOwner() const { + return mImpl ? (PRBool(mImpl->mBits) & kArrayOwnerMask) : PR_FALSE; + } + +private: + /// Copy constructors are not allowed + nsVoidArray(const nsVoidArray& other); +}; + + +// A zero-based array with a bit of automatic internal storage +class NS_COM nsAutoVoidArray : public nsVoidArray { +public: + nsAutoVoidArray(); + void Clear(); + + virtual PRBool SizeTo(PRInt32 aMin); + virtual void Compact(); + +protected: + // The internal storage + enum { kAutoBufSize = 8 }; + char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)]; +}; + + +class nsString; + +typedef int (* PR_CALLBACK nsStringArrayComparatorFunc) + (const nsString* aElement1, const nsString* aElement2, void* aData); + +typedef PRBool (*nsStringArrayEnumFunc)(nsString& aElement, void *aData); + +class NS_COM nsStringArray: protected nsVoidArray +{ +public: + nsStringArray(void); + nsStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsStringArray(void); + + nsStringArray& operator=(const nsStringArray& other); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void StringAt(PRInt32 aIndex, nsAString& aString) const; + nsString* StringAt(PRInt32 aIndex) const; + nsString* operator[](PRInt32 aIndex) const { return StringAt(aIndex); } + + PRInt32 IndexOf(const nsAString& aPossibleString) const; + + PRBool InsertStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool ReplaceStringAt(const nsAString& aString, PRInt32 aIndex); + + PRBool AppendString(const nsAString& aString) { + return InsertStringAt(aString, Count()); + } + + PRBool RemoveString(const nsAString& aString); + PRBool RemoveStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void Sort(nsStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsStringArray(const nsStringArray& other); +}; + + +class nsCString; + +typedef int (* PR_CALLBACK nsCStringArrayComparatorFunc) + (const nsCString* aElement1, const nsCString* aElement2, void* aData); + +typedef PRBool (*nsCStringArrayEnumFunc)(nsCString& aElement, void *aData); + +class NS_COM nsCStringArray: protected nsVoidArray +{ +public: + nsCStringArray(void); + nsCStringArray(PRInt32 aCount); // Storage for aCount elements will be pre-allocated + virtual ~nsCStringArray(void); + + nsCStringArray& operator=(const nsCStringArray& other); + + // Parses a given string using the delimiter passed in. If the array + // already has some elements, items parsed from string will be appended + // to array. For example, array.ParseString("a,b,c", ","); will add strings + // "a", "b" and "c" to the array. Parsing process has the same tokenizing + // behavior as strtok(). + void ParseString(const char* string, const char* delimiter); + + PRInt32 Count(void) const { + return nsVoidArray::Count(); + } + + void CStringAt(PRInt32 aIndex, nsACString& aCString) const; + nsCString* CStringAt(PRInt32 aIndex) const; + nsCString* operator[](PRInt32 aIndex) const { return CStringAt(aIndex); } + + PRInt32 IndexOf(const nsACString& aPossibleString) const; + PRInt32 IndexOfIgnoreCase(const nsACString& aPossibleString) const; + + PRBool InsertCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool ReplaceCStringAt(const nsACString& aCString, PRInt32 aIndex); + + PRBool AppendCString(const nsACString& aCString) { + return InsertCStringAt(aCString, Count()); + } + + PRBool RemoveCString(const nsACString& aCString); + PRBool RemoveCStringIgnoreCase(const nsACString& aCString); + PRBool RemoveCStringAt(PRInt32 aIndex); + void Clear(void); + + void Compact(void) { + nsVoidArray::Compact(); + } + + void Sort(void); + void SortIgnoreCase(void); + void Sort(nsCStringArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsCStringArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsCStringArrayEnumFunc aFunc, void* aData); + +private: + /// Copy constructors are not allowed + nsCStringArray(const nsCStringArray& other); +}; + + +//=================================================================== +// nsSmallVoidArray is not a general-purpose replacement for +// ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays +// larger than 1 element, though not a lot. It is appropriate for +// space-sensitive uses where sizes of 0 or 1 are moderately common or +// more, and where we're NOT storing arbitrary integers or arbitrary +// pointers. + +// NOTE: nsSmallVoidArray can ONLY be used for holding items that always +// have the low bit as a 0 - i.e. element & 1 == 0. This happens to be +// true for allocated and object pointers for all the architectures we run +// on, but conceivably there might be some architectures/compilers for +// which it is NOT true. We know this works for all existing architectures +// because if it didn't then nsCheapVoidArray would have failed. Also note +// that we will ASSERT if this assumption is violated in DEBUG builds. + +// XXX we're really re-implementing the whole nsVoidArray interface here - +// some form of abstract class would be useful + +// I disagree on the abstraction here. If the point of this class is to be +// as small as possible, and no one will ever derive from it, as I found +// today, there should not be any virtualness to it to avoid the vtable +// ptr overhead. + +class NS_COM nsSmallVoidArray +{ +public: + nsSmallVoidArray(); + ~nsSmallVoidArray(); + + nsSmallVoidArray& operator=(nsSmallVoidArray& other); + void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); } + + PRInt32 GetArraySize() const; + + PRInt32 Count() const; + void* ElementAt(PRInt32 aIndex) const; + void* SafeElementAt(PRInt32 aIndex) const { + // let compiler inline; it may be able to remove these checks + if (aIndex < 0 || aIndex >= Count()) + return nsnull; + return ElementAt(aIndex); + } + PRInt32 IndexOf(void* aPossibleElement) const; + PRBool InsertElementAt(void* aElement, PRInt32 aIndex); + PRBool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex); + PRBool ReplaceElementAt(void* aElement, PRInt32 aIndex); + PRBool MoveElement(PRInt32 aFrom, PRInt32 aTo); + PRBool AppendElement(void* aElement); + PRBool AppendElements(nsVoidArray& aElements) { + return InsertElementsAt(aElements, Count()); + } + PRBool RemoveElement(void* aElement); + PRBool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount); + PRBool RemoveElementAt(PRInt32 aIndex); + + void Clear(); + PRBool SizeTo(PRInt32 aMin); + void Compact(); + void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); + + PRBool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); + PRBool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); + +private: +#ifdef RT_OS_OS2 /* shut up a million warnings */ + typedef PRUint32 PtrBits; +#else + typedef PRUint64 PtrBits; +#endif + + PRBool HasSingleChild() const + { + return (mChildren && (PtrBits(mChildren) & 0x1)); + } + PRBool HasVector() const + { + return (mChildren && !(PtrBits(mChildren) & 0x1)); + } + void* GetSingleChild() const + { + return (mChildren ? ((void*)(PtrBits(mChildren) & ~0x1)) : nsnull); + } + void SetSingleChild(void *aChild); + nsVoidArray* GetChildVector() const + { + return (nsVoidArray*)mChildren; + } + nsVoidArray* SwitchToVector(); + + // A tagged pointer that's either a pointer to a single child + // or a pointer to a vector of multiple children. This is a space + // optimization since a large number of containers have only a + // single child. + void *mChildren; +}; + +#endif /* nsVoidArray_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.c b/src/libs/xpcom18a4/xpcom/ds/pldhash.c new file mode 100644 index 00000000..74f8cd0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.c @@ -0,0 +1,826 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Double hashing implementation. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include +#include +#include +#include "prbit.h" +#include "pldhash.h" +#include "prlog.h" /* for PR_ASSERT */ + +#ifdef PL_DHASHMETER +# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan +# include "nsTraceMalloc.h" +# endif +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +PR_IMPLEMENT(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + return RTMemAlloc(nbytes); +#else + return malloc(nbytes); +#endif +} + +PR_IMPLEMENT(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(ptr); +#else + free(ptr); +#endif +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key) +{ + PLDHashNumber h; + const unsigned char *s; + + h = 0; + for (s = key; *s != '\0'; s++) + h = (h >> (PL_DHASH_BITS - 4)) ^ (h << 4) ^ *s; + return h; +} + +PR_IMPLEMENT(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashEntryStub *stub = (PLDHashEntryStub *)entry; + + return stub->key; +} + +PR_IMPLEMENT(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber)(uintptr_t)key >> 2; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + return stub->key == key; +} + +PR_IMPLEMENT(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + + /* XXX tolerate null keys on account of sloppy Mozilla callers. */ + return stub->key == key || + (stub->key && key && strcmp(stub->key, key) == 0); +} + +PR_IMPLEMENT(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + memcpy(to, from, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + const PLDHashEntryStub *stub = (const PLDHashEntryStub *)entry; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree((void *) stub->key); +#else + free((void *) stub->key); +#endif + memset(entry, 0, table->entrySize); +} + +PR_IMPLEMENT(void) +PL_DHashFinalizeStub(PLDHashTable *table) +{ +} + +static const PLDHashTableOps stub_ops = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + +PR_IMPLEMENT(const PLDHashTableOps *) +PL_DHashGetStubOps(void) +{ + return &stub_ops; +} + +PR_IMPLEMENT(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity) +{ + PLDHashTable *table; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + table = (PLDHashTable *) RTMemAlloc(sizeof *table); +#else + table = (PLDHashTable *) malloc(sizeof *table); +#endif + if (!table) + return NULL; + if (!PL_DHashTableInit(table, ops, data, entrySize, capacity)) { +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif + return NULL; + } + return table; +} + +PR_IMPLEMENT(void) +PL_DHashTableDestroy(PLDHashTable *table) +{ + PL_DHashTableFinish(table); +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(table); +#else + free(table); +#endif +} + +PR_IMPLEMENT(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity) +{ + int log2; + PRUint32 nbytes; + +#ifdef DEBUG + if (entrySize > 10 * sizeof(void *)) { + fprintf(stderr, + "pldhash: for the table at address %p, the given entrySize" + " of %lu %s favors chaining over double hashing.\n", + (void *)table, + (unsigned long) entrySize, + (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably"); + } +#endif + + table->ops = ops; + table->data = data; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + log2 = PR_CeilingLog2(capacity); + capacity = PR_BIT(log2); + if (capacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + table->hashShift = PL_DHASH_BITS - log2; + table->maxAlphaFrac = 0xC0; /* .75 */ + table->minAlphaFrac = 0x40; /* .25 */ + table->entrySize = entrySize; + table->entryCount = table->removedCount = 0; + table->generation = 0; + nbytes = capacity * entrySize; + + table->entryStore = ops->allocTable(table, nbytes); + if (!table->entryStore) + return PR_FALSE; + memset(table->entryStore, 0, nbytes); + METER(memset(&table->stats, 0, sizeof table->stats)); + return PR_TRUE; +} + +/* + * Compute max and min load numbers (entry counts) from table params. + */ +#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8) +#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8) + +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha) +{ + PRUint32 size; + + /* + * Reject obviously insane bounds, rather than trying to guess what the + * buggy caller intended. + */ + PR_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha); + if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0) + return; + + /* + * Ensure that at least one entry will always be free. If maxAlpha at + * minimum size leaves no entries free, reduce maxAlpha based on minimum + * size and the precision limit of maxAlphaFrac's fixed point format. + */ + PR_ASSERT(PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) >= 1); + if (PL_DHASH_MIN_SIZE - (maxAlpha * PL_DHASH_MIN_SIZE) < 1) { + maxAlpha = (float) + (PL_DHASH_MIN_SIZE - PR_MAX(PL_DHASH_MIN_SIZE / 256, 1)) + / PL_DHASH_MIN_SIZE; + } + + /* + * Ensure that minAlpha is strictly less than half maxAlpha. Take care + * not to truncate an entry's worth of alpha when storing in minAlphaFrac + * (8-bit fixed point format). + */ + PR_ASSERT(minAlpha < maxAlpha / 2); + if (minAlpha >= maxAlpha / 2) { + size = PL_DHASH_TABLE_SIZE(table); + minAlpha = (size * maxAlpha - PR_MAX(size / 256, 1)) / (2 * size); + } + + table->maxAlphaFrac = (uint8)(maxAlpha * 256); + table->minAlphaFrac = (uint8)(minAlpha * 256); +} + +/* + * Double hashing needs the second hash code to be relatively prime to table + * size, so we simply make hash2 odd. + */ +#define HASH1(hash0, shift) ((hash0) >> (shift)) +#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1) + +/* + * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note + * that a removed-entry sentinel need be stored only if the removed entry had + * a colliding entry added after it. Therefore we can use 1 as the collision + * flag in addition to the removed-entry sentinel value. Multiplicative hash + * uses the high order bits of keyHash, so this least-significant reservation + * should not hurt the hash function's effectiveness much. + * + * If you change any of these magic numbers, also update PL_DHASH_ENTRY_IS_LIVE + * in pldhash.h. It used to be private to pldhash.c, but then became public to + * assist iterator writers who inspect table->entryStore directly. + */ +#define COLLISION_FLAG ((PLDHashNumber) 1) +#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0) +#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1) +#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1) +#define ENTRY_IS_LIVE(entry) PL_DHASH_ENTRY_IS_LIVE(entry) +#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0 + +/* Match an entry's keyHash against an unstored one computed from a key. */ +#define MATCH_ENTRY_KEYHASH(entry,hash0) \ + (((entry)->keyHash & ~COLLISION_FLAG) == (hash0)) + +/* Compute the address of the indexed entry in table. */ +#define ADDRESS_ENTRY(table, index) \ + ((PLDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize)) + +PR_IMPLEMENT(void) +PL_DHashTableFinish(PLDHashTable *table) +{ + char *entryAddr, *entryLimit; + PRUint32 entrySize; + PLDHashEntryHdr *entry; + +#ifdef DEBUG_XXXbrendan + static FILE *dumpfp = NULL; + if (!dumpfp) dumpfp = fopen("/tmp/pldhash.bigdump", "w"); + if (dumpfp) { +#ifdef MOZILLA_CLIENT + NS_TraceStack(1, dumpfp); +#endif + PL_DHashTableDumpMeter(table, NULL, dumpfp); + fputc('\n', dumpfp); + } +#endif + + /* Call finalize before clearing entries, so it can enumerate them. */ + table->ops->finalize(table); + + /* Clear any remaining live entries. */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + entryLimit = entryAddr + PL_DHASH_TABLE_SIZE(table) * entrySize; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + METER(table->stats.removeEnums++); + table->ops->clearEntry(table, entry); + } + entryAddr += entrySize; + } + + /* Free entry storage last. */ + table->ops->freeTable(table, table->entryStore); +} + +static PLDHashEntryHdr * PL_DHASH_FASTCALL +SearchTable(PLDHashTable *table, const void *key, PLDHashNumber keyHash, + PLDHashOperator op) +{ + PLDHashNumber hash1, hash2; + int hashShift, sizeLog2; + PLDHashEntryHdr *entry, *firstRemoved; + PLDHashMatchEntry matchEntry; + PRUint32 sizeMask; + + METER(table->stats.searches++); + PR_ASSERT(!(keyHash & COLLISION_FLAG)); + + /* Compute the primary hash address. */ + hashShift = table->hashShift; + hash1 = HASH1(keyHash, hashShift); + entry = ADDRESS_ENTRY(table, hash1); + + /* Miss: return space for a new entry. */ + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return entry; + } + + /* Hit: return entry. */ + matchEntry = table->ops->matchEntry; + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + /* Collision: double hash. */ + sizeLog2 = PL_DHASH_BITS - table->hashShift; + hash2 = HASH2(keyHash, sizeLog2, hashShift); + sizeMask = PR_BITMASK(sizeLog2); + + /* Save the first removed entry pointer so PL_DHASH_ADD can recycle it. */ + if (ENTRY_IS_REMOVED(entry)) { + firstRemoved = entry; + } else { + firstRemoved = NULL; + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + + for (;;) { + METER(table->stats.steps++); + hash1 -= hash2; + hash1 &= sizeMask; + + entry = ADDRESS_ENTRY(table, hash1); + if (PL_DHASH_ENTRY_IS_FREE(entry)) { + METER(table->stats.misses++); + return (firstRemoved && op == PL_DHASH_ADD) ? firstRemoved : entry; + } + + if (MATCH_ENTRY_KEYHASH(entry, keyHash) && + matchEntry(table, entry, key)) { + METER(table->stats.hits++); + return entry; + } + + if (ENTRY_IS_REMOVED(entry)) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (op == PL_DHASH_ADD) + entry->keyHash |= COLLISION_FLAG; + } + } + + /* NOTREACHED */ + return NULL; +} + +static PRBool +ChangeTable(PLDHashTable *table, int deltaLog2) +{ + int oldLog2, newLog2; + PRUint32 oldCapacity, newCapacity; + char *newEntryStore, *oldEntryStore, *oldEntryAddr; + PRUint32 entrySize, i, nbytes; + PLDHashEntryHdr *oldEntry, *newEntry; + PLDHashGetKey getKey; + PLDHashMoveEntry moveEntry; + +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation != PR_UINT32_MAX); + if (table->generation == PR_UINT32_MAX) + return PR_FALSE; +#endif + + /* Look, but don't touch, until we succeed in getting new entry store. */ + oldLog2 = PL_DHASH_BITS - table->hashShift; + newLog2 = oldLog2 + deltaLog2; + oldCapacity = PR_BIT(oldLog2); + newCapacity = PR_BIT(newLog2); + if (newCapacity >= PL_DHASH_SIZE_LIMIT) + return PR_FALSE; + entrySize = table->entrySize; + nbytes = newCapacity * entrySize; + + newEntryStore = table->ops->allocTable(table, nbytes); + if (!newEntryStore) + return PR_FALSE; + + /* We can't fail from here on, so update table parameters. */ + table->hashShift = PL_DHASH_BITS - newLog2; + table->removedCount = 0; + table->generation++; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + if (table->generation == PR_UINT32_MAX) + table->generation++; +#endif + + /* Assign the new entry store to table. */ + memset(newEntryStore, 0, nbytes); + oldEntryAddr = oldEntryStore = table->entryStore; + table->entryStore = newEntryStore; + getKey = table->ops->getKey; + moveEntry = table->ops->moveEntry; + + /* Copy only live entries, leaving removed ones behind. */ + for (i = 0; i < oldCapacity; i++) { + oldEntry = (PLDHashEntryHdr *)oldEntryAddr; + if (ENTRY_IS_LIVE(oldEntry)) { + oldEntry->keyHash &= ~COLLISION_FLAG; + newEntry = SearchTable(table, getKey(table, oldEntry), + oldEntry->keyHash, PL_DHASH_ADD); + PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(newEntry)); + moveEntry(table, oldEntry, newEntry); + newEntry->keyHash = oldEntry->keyHash; + } + oldEntryAddr += entrySize; + } + + table->ops->freeTable(table, oldEntryStore); + return PR_TRUE; +} + +PR_IMPLEMENT(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op) +{ + PLDHashNumber keyHash; + PLDHashEntryHdr *entry; + PRUint32 size; + int deltaLog2; + + keyHash = table->ops->hashKey(table, key); + keyHash *= PL_DHASH_GOLDEN_RATIO; + + /* Avoid 0 and 1 hash codes, they indicate free and removed entries. */ + ENSURE_LIVE_KEYHASH(keyHash); + keyHash &= ~COLLISION_FLAG; + + switch (op) { + case PL_DHASH_LOOKUP: + METER(table->stats.lookups++); + entry = SearchTable(table, key, keyHash, op); + break; + + case PL_DHASH_ADD: + /* + * If alpha is >= .75, grow or compress the table. If key is already + * in the table, we may grow once more than necessary, but only if we + * are on the edge of being overloaded. + */ + size = PL_DHASH_TABLE_SIZE(table); + if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) { + /* Compress if a quarter or more of all entries are removed. */ + if (table->removedCount >= size >> 2) { + METER(table->stats.compresses++); + deltaLog2 = 0; + } else { + METER(table->stats.grows++); + deltaLog2 = 1; + } + + /* + * Grow or compress table, returning null if ChangeTable fails and + * falling through might claim the last free entry. + */ + if (!ChangeTable(table, deltaLog2) && + table->entryCount + table->removedCount == size - 1) { + METER(table->stats.addFailures++); + return NULL; + } + } + + /* + * Look for entry after possibly growing, so we don't have to add it, + * then skip it while growing the table and re-add it after. + */ + entry = SearchTable(table, key, keyHash, op); + if (!ENTRY_IS_LIVE(entry)) { + /* Initialize the entry, indicating that it's no longer free. */ + METER(table->stats.addMisses++); + if (ENTRY_IS_REMOVED(entry)) { + METER(table->stats.addOverRemoved++); + table->removedCount--; + keyHash |= COLLISION_FLAG; + } + if (table->ops->initEntry && + !table->ops->initEntry(table, entry, key)) { + /* We haven't claimed entry yet; fail with null return. */ + memset(entry + 1, 0, table->entrySize - sizeof *entry); + return NULL; + } + entry->keyHash = keyHash; + table->entryCount++; + } + METER(else table->stats.addHits++); + break; + + case PL_DHASH_REMOVE: + entry = SearchTable(table, key, keyHash, op); + if (ENTRY_IS_LIVE(entry)) { + /* Clear this entry and mark it as "removed". */ + METER(table->stats.removeHits++); + PL_DHashTableRawRemove(table, entry); + + /* Shrink if alpha is <= .25 and table isn't too small already. */ + size = PL_DHASH_TABLE_SIZE(table); + if (size > PL_DHASH_MIN_SIZE && +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + /** @todo This is where IPC screws up, avoid the assertion in ChangeTable until it's fixed. */ + table->generation != PR_UINT32_MAX && +#endif + table->entryCount <= MIN_LOAD(table, size)) { + METER(table->stats.shrinks++); + (void) ChangeTable(table, -1); + } + } + METER(else table->stats.removeMisses++); + entry = NULL; + break; + + default: + PR_ASSERT(0); + entry = NULL; + } + + return entry; +} + +PR_IMPLEMENT(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + PLDHashNumber keyHash; /* load first in case clearEntry goofs it */ + + PR_ASSERT(PL_DHASH_ENTRY_IS_LIVE(entry)); + keyHash = entry->keyHash; + table->ops->clearEntry(table, entry); + if (keyHash & COLLISION_FLAG) { + MARK_ENTRY_REMOVED(entry); + table->removedCount++; + } else { + METER(table->stats.removeFrees++); + MARK_ENTRY_FREE(entry); + } + table->entryCount--; +} + +PR_IMPLEMENT(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg) +{ + char *entryAddr, *entryLimit; + PRUint32 i, capacity, entrySize; + PRBool didRemove; + PLDHashEntryHdr *entry; + PLDHashOperator op; +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PRUint32 generation; + + /* + * The hack! Set generation to PR_UINT32_MAX during the enumeration so + * we can prevent ChangeTable from being called. + * + * This happens during ipcDConnectService::OnClientStateChange() + * / ipcDConnectService::DeleteInstance() now when running + * java clienttest list hostinfo and vboxwebsrv crashes. It's quite + * likely that the IPC code isn't following the rules here, but it + * looks more difficult to fix that just hacking this hash code. + */ + generation = table->generation; + table->generation = PR_UINT32_MAX; +#endif /* VBOX */ + entryAddr = table->entryStore; + entrySize = table->entrySize; + capacity = PL_DHASH_TABLE_SIZE(table); + entryLimit = entryAddr + capacity * entrySize; + i = 0; + didRemove = PR_FALSE; + while (entryAddr < entryLimit) { + entry = (PLDHashEntryHdr *)entryAddr; + if (ENTRY_IS_LIVE(entry)) { + op = etor(table, entry, i++, arg); +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + PR_ASSERT(table->generation == PR_UINT32_MAX); +#endif + if (op & PL_DHASH_REMOVE) { + METER(table->stats.removeEnums++); + PL_DHashTableRawRemove(table, entry); + didRemove = PR_TRUE; + } + if (op & PL_DHASH_STOP) + break; + } + entryAddr += entrySize; + } +#ifdef VBOX /* HACK ALERT! generation == PR_UINT32_MAX during enumeration. */ + table->generation = generation; +#endif + + /* + * Shrink or compress if a quarter or more of all entries are removed, or + * if the table is underloaded according to the configured minimum alpha, + * and is not minimal-size already. Do this only if we removed above, so + * non-removing enumerations can count on stable table->entryStore until + * the next non-lookup-Operate or removing-Enumerate. + */ + if (didRemove && + (table->removedCount >= capacity >> 2 || + (capacity > PL_DHASH_MIN_SIZE && + table->entryCount <= MIN_LOAD(table, capacity)))) { + METER(table->stats.enumShrinks++); + capacity = table->entryCount; + capacity += capacity >> 1; + if (capacity < PL_DHASH_MIN_SIZE) + capacity = PL_DHASH_MIN_SIZE; + (void) ChangeTable(table, + PR_CeilingLog2(capacity) + - (PL_DHASH_BITS - table->hashShift)); + } + return i; +} + +#ifdef PL_DHASHMETER +#include + +PR_IMPLEMENT(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp) +{ + char *entryAddr; + PRUint32 entrySize, entryCount; + int hashShift, sizeLog2; + PRUint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount; + PLDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2; + double sqsum, mean, variance, sigma; + PLDHashEntryHdr *entry, *probe; + + entryAddr = table->entryStore; + entrySize = table->entrySize; + hashShift = table->hashShift; + sizeLog2 = PL_DHASH_BITS - hashShift; + tableSize = PL_DHASH_TABLE_SIZE(table); + sizeMask = PR_BITMASK(sizeLog2); + chainCount = maxChainLen = 0; + hash2 = 0; + sqsum = 0; + + for (i = 0; i < tableSize; i++) { + entry = (PLDHashEntryHdr *)entryAddr; + entryAddr += entrySize; + if (!ENTRY_IS_LIVE(entry)) + continue; + hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift); + saveHash1 = hash1; + probe = ADDRESS_ENTRY(table, hash1); + chainLen = 1; + if (probe == entry) { + /* Start of a (possibly unit-length) chain. */ + chainCount++; + } else { + hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2, + hashShift); + do { + chainLen++; + hash1 -= hash2; + hash1 &= sizeMask; + probe = ADDRESS_ENTRY(table, hash1); + } while (probe != entry); + } + sqsum += chainLen * chainLen; + if (chainLen > maxChainLen) { + maxChainLen = chainLen; + maxChainHash1 = saveHash1; + maxChainHash2 = hash2; + } + } + + entryCount = table->entryCount; + if (entryCount && chainCount) { + mean = (double)entryCount / chainCount; + variance = chainCount * sqsum - entryCount * entryCount; + if (variance < 0 || chainCount == 1) + variance = 0; + else + variance /= chainCount * (chainCount - 1); + sigma = sqrt(variance); + } else { + mean = sigma = 0; + } + + fprintf(fp, "Double hashing statistics:\n"); + fprintf(fp, " table size (in entries): %u\n", tableSize); + fprintf(fp, " number of entries: %u\n", table->entryCount); + fprintf(fp, " number of removed entries: %u\n", table->removedCount); + fprintf(fp, " number of searches: %u\n", table->stats.searches); + fprintf(fp, " number of hits: %u\n", table->stats.hits); + fprintf(fp, " number of misses: %u\n", table->stats.misses); + fprintf(fp, " mean steps per search: %g\n", table->stats.searches ? + (double)table->stats.steps + / table->stats.searches : + 0.); + fprintf(fp, " mean hash chain length: %g\n", mean); + fprintf(fp, " standard deviation: %g\n", sigma); + fprintf(fp, " maximum hash chain length: %u\n", maxChainLen); + fprintf(fp, " number of lookups: %u\n", table->stats.lookups); + fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses); + fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved); + fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits); + fprintf(fp, " add failures: %u\n", table->stats.addFailures); + fprintf(fp, " useful removes: %u\n", table->stats.removeHits); + fprintf(fp, " useless removes: %u\n", table->stats.removeMisses); + fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees); + fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums); + fprintf(fp, " number of grows: %u\n", table->stats.grows); + fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks); + fprintf(fp, " number of compresses: %u\n", table->stats.compresses); + fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks); + + if (dump && maxChainLen && hash2) { + fputs("Maximum hash chain:\n", fp); + hash1 = maxChainHash1; + hash2 = maxChainHash2; + entry = ADDRESS_ENTRY(table, hash1); + i = 0; + do { + if (dump(table, entry, i++, fp) != PL_DHASH_NEXT) + break; + hash1 -= hash2; + hash1 &= sizeMask; + entry = ADDRESS_ENTRY(table, hash1); + } while (PL_DHASH_ENTRY_IS_BUSY(entry)); + } +} +#endif /* PL_DHASHMETER */ diff --git a/src/libs/xpcom18a4/xpcom/ds/pldhash.h b/src/libs/xpcom18a4/xpcom/ds/pldhash.h new file mode 100644 index 00000000..8c4347c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/ds/pldhash.h @@ -0,0 +1,603 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla JavaScript code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 pldhash_h___ +#define pldhash_h___ +/* + * Double hashing, a la Knuth 6. + * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + */ +#include "prtypes.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_DHashTableInit VBoxNsplPL_DHashTableInit +#define PL_DHashTableFinish VBoxNsplPL_DHashTableFinish +#define PL_DHashTableOperate VBoxNsplPL_DHashTableOperate +#define PL_DHashTableEnumerate VBoxNsplPL_DHashTableEnumerate +#define PL_DHashAllocTable VBoxNsplPL_DHashAllocTable +#define PL_DHashFreeTable VBoxNsplPL_DHashFreeTable +#define PL_DHashMoveEntryStub VBoxNsplPL_DHashMoveEntryStub +#define PL_DHashFinalizeStub VBoxNsplPL_DHashFinalizeStub +#define PL_DHashClearEntryStub VBoxNsplPL_DHashClearEntryStub +#define PL_DHashFreeStringKey VBoxNsplPL_DHashFreeStringKey +#define PL_DHashGetKeyStub VBoxNsplPL_DHashGetKeyStub +#define PL_DHashGetStubOps VBoxNsplPL_DHashGetStubOps +#define PL_DHashMatchEntryStub VBoxNsplPL_DHashMatchEntryStub +#define PL_DHashMatchStringKey VBoxNsplPL_DHashMatchStringKey +#define PL_DHashStringKey VBoxNsplPL_DHashStringKey +#define PL_DHashTableDestroy VBoxNsplPL_DHashTableDestroy +#define PL_DHashTableRawRemove VBoxNsplPL_DHashTableRawRemove +#define PL_DHashTableSetAlphaBounds VBoxNsplPL_DHashTableSetAlphaBounds +#define PL_DHashVoidPtrKeyStub VBoxNsplPL_DHashVoidPtrKeyStub +#define PL_NewDHashTable VBoxNsplPL_NewDHashTable +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +#ifdef DEBUG_XXXbrendan +#define PL_DHASHMETER 1 +#endif + +#if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2) +#define PL_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) +#else +#define PL_DHASH_FASTCALL +#endif + +/* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */ +#undef PL_DHASH_SIZE_LIMIT +#define PL_DHASH_SIZE_LIMIT PR_BIT(24) + +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ +#ifndef PL_DHASH_MIN_SIZE +#define PL_DHASH_MIN_SIZE 16 +#elif (PL_DHASH_MIN_SIZE & (PL_DHASH_MIN_SIZE - 1)) != 0 +#error "PL_DHASH_MIN_SIZE must be a power of two!" +#endif + +/* + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, + * expressed as a fixed-point 32-bit fraction. + */ +#define PL_DHASH_BITS 32 +#define PL_DHASH_GOLDEN_RATIO 0x9E3779B9U + +/* Primitive and forward-struct typedefs. */ +typedef PRUint32 PLDHashNumber; +typedef struct PLDHashEntryHdr PLDHashEntryHdr; +typedef struct PLDHashEntryStub PLDHashEntryStub; +typedef struct PLDHashTable PLDHashTable; +typedef struct PLDHashTableOps PLDHashTableOps; + +/* + * Table entry header structure. + * + * In order to allow in-line allocation of key and value, we do not declare + * either here. Instead, the API uses const void *key as a formal parameter, + * and asks each entry for its key when necessary via a getKey callback, used + * when growing or shrinking the table. Other callback types are defined + * below and grouped into the PLDHashTableOps structure, for single static + * initialization per hash table sub-type. + * + * Each hash table sub-type should nest the PLDHashEntryHdr structure at the + * front of its particular entry type. The keyHash member contains the result + * of multiplying the hash code returned from the hashKey callback (see below) + * by PL_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 + * and 1 values. The stored keyHash value is table size invariant, and it is + * maintained automatically by PL_DHashTableOperate -- users should never set + * it, and its only uses should be via the entry macros below. + * + * The PL_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor + * removed. An entry may be either busy or free; if busy, it may be live or + * removed. Consumers of this API should not access members of entries that + * are not live. + * + * However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries + * returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a + * non-live, busy (i.e., removed) entry pointer to its caller. See below for + * more details on PL_DHashTableOperate's calling rules. + */ +struct PLDHashEntryHdr { + PLDHashNumber keyHash; /* every entry must begin like this */ +}; + +#define PL_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0) +#define PL_DHASH_ENTRY_IS_BUSY(entry) (!PL_DHASH_ENTRY_IS_FREE(entry)) +#define PL_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2) + +/* + * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead) + * on most architectures, and may be allocated on the stack or within another + * structure or class (see below for the Init and Finish functions to use). + * + * To decide whether to use double hashing vs. chaining, we need to develop a + * trade-off relation, as follows: + * + * Let alpha be the load factor, esize the entry size in words, count the + * entry count, and pow2 the power-of-two table size in entries. + * + * (PLDHashTable overhead) > (PLHashTable overhead) + * (unused table entry space) > (malloc and .next overhead per entry) + + * (buckets overhead) + * (1 - alpha) * esize * pow2 > 2 * count + pow2 + * + * Notice that alpha is by definition (count / pow2): + * + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 + * (1 - alpha) * esize > 2 * alpha + 1 + * + * esize > (1 + 2 * alpha) / (1 - alpha) + * + * This assumes both tables must keep keyHash, key, and value for each entry, + * where key and value point to separately allocated strings or structures. + * If key and value can be combined into one pointer, then the trade-off is: + * + * esize > (1 + 3 * alpha) / (1 - alpha) + * + * If the entry value can be a subtype of PLDHashEntryHdr, rather than a type + * that must be allocated separately and referenced by an entry.value pointer + * member, and provided key's allocation can be fused with its entry's, then + * k (the words wasted per entry with chaining) is 4. + * + * To see these curves, feed gnuplot input like so: + * + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) + * + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 + * words for chaining to be more space-efficient than double hashing. + * + * Solving for alpha helps us decide when to shrink an underloaded table: + * + * esize > (1 + k * alpha) / (1 - alpha) + * esize - alpha * esize > 1 + k * alpha + * esize - 1 > (k + esize) * alpha + * (esize - 1) / (k + esize) > alpha + * + * alpha < (esize - 1) / (esize + k) + * + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), + * assuming esize is not too large (in which case, chaining should probably be + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 + * would still obtain. See the PL_DHASH_MIN_ALPHA macro further below. + * + * The current implementation uses a configurable lower bound on alpha, which + * defaults to .25, when deciding to shrink the table (while still respecting + * PL_DHASH_MIN_SIZE). + * + * Note a qualitative difference between chaining and double hashing: under + * chaining, entry addresses are stable across table shrinks and grows. With + * double hashing, you can't safely hold an entry pointer and use it after an + * ADD or REMOVE operation, unless you sample table->generation before adding + * or removing, and compare the sample after, dereferencing the entry pointer + * only if table->generation has not changed. + * + * The moral of this story: there is no one-size-fits-all hash table scheme, + * but for small table entry size, and assuming entry address stability is not + * required, double hashing wins. + */ +struct PLDHashTable { + const PLDHashTableOps *ops; /* virtual operations, see below */ + void *data; /* ops- and instance-specific data */ + PRInt16 hashShift; /* multiplicative hash shift */ + uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */ + uint8 minAlphaFrac; /* 8-bit fixed point min alpha */ + PRUint32 entrySize; /* number of bytes in an entry */ + PRUint32 entryCount; /* number of entries in table */ + PRUint32 removedCount; /* removed entry sentinels in table */ + PRUint32 generation; /* entry storage generation number */ + char *entryStore; /* entry storage */ +#ifdef PL_DHASHMETER + struct PLDHashStats { + PRUint32 searches; /* total number of table searches */ + PRUint32 steps; /* hash chain links traversed */ + PRUint32 hits; /* searches that found key */ + PRUint32 misses; /* searches that didn't find key */ + PRUint32 lookups; /* number of PL_DHASH_LOOKUPs */ + PRUint32 addMisses; /* adds that miss, and do work */ + PRUint32 addOverRemoved; /* adds that recycled a removed entry */ + PRUint32 addHits; /* adds that hit an existing entry */ + PRUint32 addFailures; /* out-of-memory during add growth */ + PRUint32 removeHits; /* removes that hit, and do work */ + PRUint32 removeMisses; /* useless removes that miss */ + PRUint32 removeFrees; /* removes that freed entry directly */ + PRUint32 removeEnums; /* removes done by Enumerate */ + PRUint32 grows; /* table expansions */ + PRUint32 shrinks; /* table contractions */ + PRUint32 compresses; /* table compressions */ + PRUint32 enumShrinks; /* contractions after Enumerate */ + } stats; +#endif +}; + +/* + * Size in entries (gross, not net of free and removed sentinels) for table. + * We store hashShift rather than sizeLog2 to optimize the collision-free case + * in SearchTable. + */ +#define PL_DHASH_TABLE_SIZE(table) PR_BIT(PL_DHASH_BITS - (table)->hashShift) + +/* + * Table space at entryStore is allocated and freed using these callbacks. + * The allocator should return null on error only (not if called with nbytes + * equal to 0; but note that pldhash.c code will never call with 0 nbytes). + */ +typedef void * +(* PR_CALLBACK PLDHashAllocTable)(PLDHashTable *table, PRUint32 nbytes); + +typedef void +(* PR_CALLBACK PLDHashFreeTable) (PLDHashTable *table, void *ptr); + +/* + * When a table grows or shrinks, each entry is queried for its key using this + * callback. NB: in that event, entry is not in table any longer; it's in the + * old entryStore vector, which is due to be freed once all entries have been + * moved via moveEntry callbacks. + */ +typedef const void * +(* PR_CALLBACK PLDHashGetKey) (PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Compute the hash code for a given key to be looked up, added, or removed + * from table. A hash code may have any PLDHashNumber value. + */ +typedef PLDHashNumber +(* PR_CALLBACK PLDHashHashKey) (PLDHashTable *table, const void *key); + +/* + * Compare the key identifying entry in table with the provided key parameter. + * Return PR_TRUE if keys match, PR_FALSE otherwise. + */ +typedef PRBool +(* PR_CALLBACK PLDHashMatchEntry)(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +/* + * Copy the data starting at from to the new entry storage at to. Do not add + * reference counts for any strong references in the entry, however, as this + * is a "move" operation: the old entry storage at from will be freed without + * any reference-decrementing callback shortly. + */ +typedef void +(* PR_CALLBACK PLDHashMoveEntry)(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +/* + * Clear the entry and drop any strong references it holds. This callback is + * invoked during a PL_DHASH_REMOVE operation (see below for operation codes), + * but only if the given key is found in the table. + */ +typedef void +(* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry); + +/* + * Called when a table (whether allocated dynamically by itself, or nested in + * a larger structure, or allocated on the stack) is finished. This callback + * allows table->ops-specific code to finalize table->data. + */ +typedef void +(* PR_CALLBACK PLDHashFinalize) (PLDHashTable *table); + +/* + * Initialize a new entry, apart from keyHash. This function is called when + * PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the + * given key, and must add a new one. At that point, entry->keyHash is not + * set yet, to avoid claiming the last free entry in a severely overloaded + * table. + */ +typedef PRBool +(* PR_CALLBACK PLDHashInitEntry)(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key); + +/* + * Finally, the "vtable" structure for PLDHashTable. The first eight hooks + * must be provided by implementations; they're called unconditionally by the + * generic pldhash.c code. Hooks after these may be null. + * + * Summary of allocation-related hook usage with C++ placement new emphasis: + * allocTable Allocate raw bytes with malloc, no ctors run. + * freeTable Free raw bytes with free, no dtors run. + * initEntry Call placement new using default key-based ctor. + * Return PR_TRUE on success, PR_FALSE on error. + * moveEntry Call placement new using copy ctor, run dtor on old + * entry storage. + * clearEntry Run dtor on entry. + * finalize Stub unless table->data was initialized and needs to + * be finalized. + * + * Note the reason why initEntry is optional: the default hooks (stubs) clear + * entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD), + * the returned entry pointer addresses an entry struct whose keyHash member + * has been set non-zero, but all other entry members are still clear (null). + * PL_DHASH_ADD callers can test such members to see whether the entry was + * newly created by the PL_DHASH_ADD call that just succeeded. If placement + * new or similar initialization is required, define an initEntry hook. Of + * course, the clearEntry hook must zero or null appropriately. + * + * XXX assumes 0 is null for pointer types. + */ +struct PLDHashTableOps { + /* Mandatory hooks. All implementations must provide these. */ + PLDHashAllocTable allocTable; + PLDHashFreeTable freeTable; + PLDHashGetKey getKey; + PLDHashHashKey hashKey; + PLDHashMatchEntry matchEntry; + PLDHashMoveEntry moveEntry; + PLDHashClearEntry clearEntry; + PLDHashFinalize finalize; + + /* Optional hooks start here. If null, these are not called. */ + PLDHashInitEntry initEntry; +}; + +/* + * Default implementations for the above ops. + */ +PR_EXTERN(void *) +PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes); + +PR_EXTERN(void) +PL_DHashFreeTable(PLDHashTable *table, void *ptr); + +PR_EXTERN(PLDHashNumber) +PL_DHashStringKey(PLDHashTable *table, const void *key); + +/* A minimal entry contains a keyHash header and a void key pointer. */ +struct PLDHashEntryStub { + PLDHashEntryHdr hdr; + const void *key; +}; + +PR_EXTERN(const void *) +PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(PLDHashNumber) +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(PRBool) +PL_DHashMatchStringKey(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key); + +PR_EXTERN(void) +PL_DHashMoveEntryStub(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to); + +PR_EXTERN(void) +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry); + +PR_EXTERN(void) +PL_DHashFinalizeStub(PLDHashTable *table); + +/* + * If you use PLDHashEntryStub or a subclass of it as your entry struct, and + * if your entries move via memcpy and clear via memset(0), you can use these + * stub operations. + */ +PR_EXTERN(const PLDHashTableOps *) +PL_DHashGetStubOps(void); + +/* + * Dynamically allocate a new PLDHashTable using malloc, initialize it using + * PL_DHashTableInit, and return its address. Return null on malloc failure. + * Note that the entry storage at table->entryStore will be allocated using + * the ops->allocTable callback. + */ +PR_EXTERN(PLDHashTable *) +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize, + PRUint32 capacity); + +/* + * Finalize table's data, free its entry storage (via table->ops->freeTable), + * and return the memory starting at table to the malloc heap. + */ +PR_EXTERN(void) +PL_DHashTableDestroy(PLDHashTable *table); + +/* + * Initialize table with ops, data, entrySize, and capacity. Capacity is a + * guess for the smallest table size at which the table will usually be less + * than 75% loaded (the table will grow or shrink as needed; capacity serves + * only to avoid inevitable early growth from PL_DHASH_MIN_SIZE). + */ +PR_EXTERN(PRBool) +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, + PRUint32 entrySize, PRUint32 capacity); + +/* + * Set maximum and minimum alpha for table. The defaults are 0.75 and .25. + * maxAlpha must be in [0.5, 0.9375] for the default PL_DHASH_MIN_SIZE; or if + * MinSize=PL_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or + * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that + * we don't shrink on the very next remove after growing a table upon adding + * an entry that brings entryCount past maxAlpha * tableSize. + */ +PR_IMPLEMENT(void) +PL_DHashTableSetAlphaBounds(PLDHashTable *table, + float maxAlpha, + float minAlpha); + +/* + * Call this macro with k, the number of pointer-sized words wasted per entry + * under chaining, to compute the minimum alpha at which double hashing still + * beats chaining. + */ +#define PL_DHASH_MIN_ALPHA(table, k) \ + ((float)((table)->entrySize / sizeof(void *) - 1) \ + / ((table)->entrySize / sizeof(void *) + (k))) + +/* + * Finalize table's data, free its entry storage using table->ops->freeTable, + * and leave its members unchanged from their last live values (which leaves + * pointers dangling). If you want to burn cycles clearing table, it's up to + * your code to call memset. + */ +PR_EXTERN(void) +PL_DHashTableFinish(PLDHashTable *table); + +/* + * To consolidate keyHash computation and table grow/shrink code, we use a + * single entry point for lookup, add, and remove operations. The operation + * codes are declared here, along with codes returned by PLDHashEnumerator + * functions, which control PL_DHashTableEnumerate's behavior. + */ +typedef enum PLDHashOperator { + PL_DHASH_LOOKUP = 0, /* lookup entry */ + PL_DHASH_ADD = 1, /* add entry */ + PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ + PL_DHASH_NEXT = 0, /* enumerator says continue */ + PL_DHASH_STOP = 1 /* enumerator says stop */ +} PLDHashOperator; + +/* + * To lookup a key in table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_LOOKUP); + * + * If PL_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies + * entry. If PL_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. + * + * To add an entry identified by key to table, call: + * + * entry = PL_DHashTableOperate(table, key, PL_DHASH_ADD); + * + * If entry is null upon return, then either the table is severely overloaded, + * and memory can't be allocated for entry storage via table->ops->allocTable; + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may + * have returned false. + * + * Otherwise, entry->keyHash has been set so that PL_DHASH_ENTRY_IS_BUSY(entry) + * is true, and it is up to the caller to initialize the key and value parts + * of the entry sub-type, if they have not been set already (i.e. if entry was + * not already in the table, and if the optional initEntry hook was not used). + * + * To remove an entry identified by key from table, call: + * + * (void) PL_DHashTableOperate(table, key, PL_DHASH_REMOVE); + * + * If key's entry is found, it is cleared (via table->ops->clearEntry) and + * the entry is marked so that PL_DHASH_ENTRY_IS_FREE(entry). This operation + * returns null unconditionally; you should ignore its return value. + */ +PR_EXTERN(PLDHashEntryHdr *) PL_DHASH_FASTCALL +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op); + +/* + * Remove an entry already accessed via LOOKUP or ADD. + * + * NB: this is a "raw" or low-level routine, intended to be used only where + * the inefficiency of a full PL_DHashTableOperate (which rehashes in order + * to find the entry given its key) is not tolerable. This function does not + * shrink the table if it is underloaded. It does not update stats #ifdef + * PL_DHASHMETER, either. + */ +PR_EXTERN(void) +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry); + +/* + * Enumerate entries in table using etor: + * + * count = PL_DHashTableEnumerate(table, etor, arg); + * + * PL_DHashTableEnumerate calls etor like so: + * + * op = etor(table, entry, number, arg); + * + * where number is a zero-based ordinal assigned to live entries according to + * their order in table->entryStore. + * + * The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT, + * then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via + * table->ops->clearEntry) and free entry. Then we check whether op contains + * PL_DHASH_STOP; if so, stop enumerating and return the number of live entries + * that were enumerated so far. Return the total number of live entries when + * enumeration completes normally. + * + * If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it + * must return PL_DHASH_STOP; otherwise undefined behavior results. + * + * If any enumerator returns PL_DHASH_REMOVE, table->entryStore may be shrunk + * or compressed after enumeration, but before PL_DHashTableEnumerate returns. + * Such an enumerator therefore can't safely set aside entry pointers, but an + * enumerator that never returns PL_DHASH_REMOVE can set pointers to entries + * aside, e.g., to avoid copying live entries into an array of the entry type. + * Copying entry pointers is cheaper, and safe so long as the caller of such a + * "stable" Enumerate doesn't use the set-aside pointers after any call either + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might + * grow or shrink entryStore. + * + * If your enumerator wants to remove certain entries, but set aside pointers + * to other entries that it retains, it can use PL_DHashTableRawRemove on the + * entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if + * you want to remove entries, but for some reason you do not want entryStore + * to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on + * the entry being enumerated, rather than returning PL_DHASH_REMOVE. + */ +typedef PLDHashOperator +(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +PR_EXTERN(PRUint32) +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg); + +#ifdef PL_DHASHMETER +#include + +PR_EXTERN(void) +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp); +#endif + +PR_END_EXTERN_C + +#endif /* pldhash_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/.cvsignore b/src/libs/xpcom18a4/xpcom/glue/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/glue/Makefile.in b/src/libs/xpcom18a4/xpcom/glue/Makefile.in new file mode 100644 index 00000000..a3b1f24d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/Makefile.in @@ -0,0 +1,86 @@ +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(srcdir)/objs.mk + +DIRS = standalone + +MODULE = xpcom +LIBRARY_NAME = xpcomglue_s + +REQUIRES = $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../build \ + $(NULL) + +CPPSRCS = \ + $(XPCOM_GLUE_SRC_LCSRCS) \ + $(NULL) + +SDK_HEADERS = \ + nsIGenericFactory.h \ + nsIInterfaceRequestorUtils.h \ + nsISupportsImpl.h \ + nsISupportsUtils.h \ + nsIWeakReferenceUtils.h \ + $(XPCOM_GLUE_SRC_LEXPORTS) \ + $(NULL) + +SDK_LIBRARY = \ + $(LIB_PREFIX)xpcomglue_s.$(LIB_SUFFIX) \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +# hack to work around objdir bustage +export:: + rm -f $(XPCOM_GLUE_SRC_CSRCS:.cpp=.$(OBJ_SUFFIX)) + +DEFINES += \ + -D_IMPL_NS_COM diff --git a/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp new file mode 100644 index 00000000..cac3c6d4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" + +nsresult +nsQueryInterface::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + return status; + } + +nsresult +nsQueryInterfaceWithError::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mRawPtr ) + { + status = mRawPtr->QueryInterface(aIID, answer); +#ifdef NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS + NS_WARN_IF_FALSE(NS_SUCCEEDED(status), "interface not found---were you expecting that?"); +#endif + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + +nsCOMPtr_base::~nsCOMPtr_base() + { + NSCAP_LOG_RELEASE(this, mRawPtr); + if ( mRawPtr ) + NSCAP_RELEASE(this, mRawPtr); + } + +void +nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr ) + { + if ( rawPtr ) + NSCAP_ADDREF(this, rawPtr); + assign_assuming_AddRef(rawPtr); + } + +void +nsCOMPtr_base::assign_from_qi( const nsQueryInterface qi, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( qi(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void +nsCOMPtr_base::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( qi(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void +nsCOMPtr_base::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( helper(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +void** +nsCOMPtr_base::begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } diff --git a/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h new file mode 100644 index 00000000..b5a0fd78 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsCOMPtr.h @@ -0,0 +1,1405 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsCOMPtr_h___ +#define nsCOMPtr_h___ + +/* + Having problems? + + See the User Manual at: + http://www.mozilla.org/projects/xpcom/nsCOMPtr.html + + + nsCOMPtr + better than a raw pointer + for owning objects + -- scc +*/ + + + // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") +#ifndef nsDebug_h___ +#include "nsDebug.h" + // for |NS_PRECONDITION| +#endif + +#ifndef nsISupportsUtils_h__ +#include "nsISupportsUtils.h" + // for |nsresult|, |NS_ADDREF|, |NS_GET_IID| et al +#endif + +#ifndef nscore_h___ +#include "nscore.h" + // for |NS_..._CAST|, |NS_COM| +#endif + + +/* + WARNING: + This file defines several macros for internal use only. These macros begin with the + prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use + only for cross-platform compatibility, and are subject to change without notice. +*/ + + +#ifdef _MSC_VER + #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT + // under VC++, we win by inlining StartAssignment + + // Also under VC++, at the highest warning level, we are overwhelmed with warnings + // about (unused) inline functions being removed. This is to be expected with + // templates, so we disable the warning. + #pragma warning( disable: 4514 ) +#endif + +#define NSCAP_FEATURE_USE_BASE + +#ifdef NS_DEBUG + #define NSCAP_FEATURE_TEST_DONTQUERY_CASES + #undef NSCAP_FEATURE_USE_BASE +//#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS +#endif + + /* + |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is + problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing + a mechanism by which these features can be explicitly disabled from the command-line. + */ + +#ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES + #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES +#endif + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) + // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing + // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher + // don't reorder instructions based on aliasing assumptions for + // this variable. Fortunately, gcc versions < 3.3 do not do any + // optimizations that break nsCOMPtr. + + #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__)) +#else + #define NS_MAY_ALIAS_PTR(t) t* +#endif + +#if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) + #define NSCAP_FEATURE_USE_BASE +#endif + + +#ifdef HAVE_CPP_BOOL + typedef bool NSCAP_BOOL; +#else + typedef PRBool NSCAP_BOOL; +#endif + + + + + /* + The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|) + allow external clients the ability to add logging or other interesting debug facilities. + In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you + provide (e.g., in "nsTraceRefcnt.h") suitable definitions + + #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr) + #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr) + */ + +#ifndef NSCAP_ADDREF + #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef() +#endif + +#ifndef NSCAP_RELEASE + #define NSCAP_RELEASE(this, ptr) (ptr)->Release() +#endif + + // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging. +#ifdef NSCAP_LOG_ASSIGNMENT + // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know + // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into + // the |nsCOMPtr|. + #define NSCAP_LOG_EXTERNAL_ASSIGNMENT +#else + // ...otherwise, just strip it out of the code + #define NSCAP_LOG_ASSIGNMENT(this, ptr) +#endif + +#ifndef NSCAP_LOG_RELEASE + #define NSCAP_LOG_RELEASE(this, ptr) +#endif + + + + + /* + WARNING: + VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined + in an order that satisfies: + + nsDerivedSafe < nsCOMPtr + already_AddRefed < nsCOMPtr + nsCOMPtr < nsGetterAddRefs + + The other compilers probably won't complain, so please don't reorder these + classes, on pain of breaking 4.2 compatibility. + */ + + +template +class nsDerivedSafe : public T + /* + No client should ever see or have to type the name of this class. It is the + artifact that makes it a compile-time error to call |AddRef| and |Release| + on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. + + See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al. + + This type should be a nested class inside |nsCOMPtr|. + */ + { + private: +#ifdef HAVE_CPP_ACCESS_CHANGING_USING + using T::AddRef; + using T::Release; +#else + nsrefcnt AddRef(void); + nsrefcnt Release(void); +#endif + +#if !defined(AIX) && !defined(IRIX) + void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED + // declaring |operator delete| private makes calling delete on an interface pointer a compile error +#endif + + nsDerivedSafe& operator=( const T& ); // NOT TO BE IMPLEMENTED + // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one + + /* + Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=(). + If you see that, that means somebody checked in a [XP]COM interface class that declares an + |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly + to stop people from doing it. + */ + + protected: + nsDerivedSafe(); // NOT TO BE IMPLEMENTED + /* + This ctor exists to avoid compile errors and warnings about nsDeriviedSafe using the + default ctor but inheriting classes without an empty ctor. See bug 209667. + */ + }; + +#if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS) +template +nsrefcnt +nsDerivedSafe::AddRef() + { + return 0; + } + +template +nsrefcnt +nsDerivedSafe::Release() + { + return 0; + } + +#endif + + + +template +struct already_AddRefed + /* + ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ + |AddRef|ing it. You might want to use this as a return type from a function + that produces an already |AddRef|ed pointer as a result. + + See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. + + This type should be a nested class inside |nsCOMPtr|. + + Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to + avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest + case, and perhaps worth the savings in time and space that its specific + implementation affords over the more general solution offered by + |nsCOMPtr_helper|. + */ + { + already_AddRefed( T* aRawPtr ) + : mRawPtr(aRawPtr) + { + // nothing else to do here + } + + T* get() const { return mRawPtr; } + + T* mRawPtr; + }; + +template +inline +const already_AddRefed +getter_AddRefs( T* aRawPtr ) + /* + ...makes typing easier, because it deduces the template type, e.g., + you write |dont_AddRef(fooP)| instead of |already_AddRefed(fooP)|. + */ + { + return already_AddRefed(aRawPtr); + } + +template +inline +const already_AddRefed +getter_AddRefs( const already_AddRefed aAlreadyAddRefedPtr ) + { + return aAlreadyAddRefedPtr; + } + +template +inline +const already_AddRefed +dont_AddRef( T* aRawPtr ) + { + return already_AddRefed(aRawPtr); + } + +template +inline +const already_AddRefed +dont_AddRef( const already_AddRefed aAlreadyAddRefedPtr ) + { + return aAlreadyAddRefedPtr; + } + + + +class nsCOMPtr_helper + /* + An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms + that are more convenient to call, and more efficient to use with |nsCOMPtr|s. + Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. + + Here are the rules for a helper: + - it implements |operator()| to produce an interface pointer + - (except for its name) |operator()| is a valid [XP]COM `getter' + - the interface pointer that it returns is already |AddRef()|ed (as from any good getter) + - it matches the type requested with the supplied |nsIID| argument + - its constructor provides an optional |nsresult*| that |operator()| can fill + in with an error when it is executed + + See |class nsGetInterface| for an example. + */ + { + public: + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const = 0; + }; + +/* + |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to + avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface| + is called often enough that the codesize savings are big enough to + warrant the specialcasing. +*/ + +class NS_COM nsQueryInterface + { + public: + nsQueryInterface( nsISupports* aRawPtr ) + : mRawPtr(aRawPtr) + { + // nothing else to do here + } + + nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsISupports* mRawPtr; + }; + +class NS_COM nsQueryInterfaceWithError + { + public: + nsQueryInterfaceWithError( nsISupports* aRawPtr, nsresult* error ) + : mRawPtr(aRawPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsISupports* mRawPtr; + nsresult* mErrorPtr; + }; + +inline +nsQueryInterface +do_QueryInterface( nsISupports* aRawPtr ) + { + return nsQueryInterface(aRawPtr); + } + +inline +nsQueryInterfaceWithError +do_QueryInterface( nsISupports* aRawPtr, nsresult* error ) + { + return nsQueryInterfaceWithError(aRawPtr, error); + } + +template +inline +void +do_QueryInterface( already_AddRefed& ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + +template +inline +void +do_QueryInterface( already_AddRefed&, nsresult* ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + + + +class nsCOMPtr_base + /* + ...factors implementation for all template versions of |nsCOMPtr|. + + This should really be an |nsCOMPtr|, but this wouldn't work + because unlike the + + Here's the way people normally do things like this + + template class Foo { ... }; + template <> class Foo { ... }; + template class Foo : private Foo { ... }; + */ + { + public: + + nsCOMPtr_base( nsISupports* rawPtr = 0 ) + : mRawPtr(rawPtr) + { + // nothing else to do here + } + + NS_COM NS_FASTCALL ~nsCOMPtr_base(); + + NS_COM void NS_FASTCALL assign_with_AddRef( nsISupports* ); + NS_COM void NS_FASTCALL assign_from_qi( const nsQueryInterface, const nsIID& ); + NS_COM void NS_FASTCALL assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); + NS_COM void NS_FASTCALL assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); + NS_COM void** NS_FASTCALL begin_assignment(); + + protected: + NS_MAY_ALIAS_PTR(nsISupports) mRawPtr; + + void + assign_assuming_AddRef( nsISupports* newPtr ) + { + /* + |AddRef()|ing the new value (before entering this function) before + |Release()|ing the old lets us safely ignore the self-assignment case. + We must, however, be careful only to |Release()| _after_ doing the + assignment, in case the |Release()| leads to our _own_ destruction, + which would, in turn, cause an incorrect second |Release()| of our old + pointer. Thank for discovering this. + */ + nsISupports* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); + } + }; + +// template class nsGetterAddRefs; + +template +class nsCOMPtr +#ifdef NSCAP_FEATURE_USE_BASE + : private nsCOMPtr_base +#endif + { + +#ifdef NSCAP_FEATURE_USE_BASE + #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x) +#else + #define NSCAP_CTOR_BASE(x) mRawPtr(x) + + private: + void assign_with_AddRef( nsISupports* ); + void assign_from_qi( const nsQueryInterface, const nsIID& ); + void assign_from_qi_with_error( const nsQueryInterfaceWithError&, const nsIID& ); + void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); + void** begin_assignment(); + + void + assign_assuming_AddRef( T* newPtr ) + { + T* oldPtr = mRawPtr; + mRawPtr = newPtr; + NSCAP_LOG_ASSIGNMENT(this, newPtr); + NSCAP_LOG_RELEASE(this, oldPtr); + if ( oldPtr ) + NSCAP_RELEASE(this, oldPtr); + } + + private: + T* mRawPtr; +#endif + + public: + typedef T element_type; + +#ifndef NSCAP_FEATURE_USE_BASE + ~nsCOMPtr() + { + NSCAP_LOG_RELEASE(this, mRawPtr); + if ( mRawPtr ) + NSCAP_RELEASE(this, mRawPtr); + } +#endif + +#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES + void + Assert_NoQueryNeeded() + { + if ( mRawPtr ) + { + nsCOMPtr query_result( do_QueryInterface(mRawPtr) ); + NS_ASSERTION(query_result.get() == mRawPtr, "QueryInterface needed"); + } + } + + #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded(); +#else + #define NSCAP_ASSERT_NO_QUERY_NEEDED() +#endif + + + // Constructors + + nsCOMPtr() + : NSCAP_CTOR_BASE(0) + // default constructor + { + NSCAP_LOG_ASSIGNMENT(this, 0); + } + + nsCOMPtr( const nsCOMPtr& aSmartPtr ) + : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) + // copy-constructor + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( T* aRawPtr ) + : NSCAP_CTOR_BASE(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + nsCOMPtr( const already_AddRefed& aSmartPtr ) + : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + nsCOMPtr( const nsQueryInterface qi ) + : NSCAP_CTOR_BASE(0) + // construct from |do_QueryInterface(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi(qi, NS_GET_IID(T)); + } + + nsCOMPtr( const nsQueryInterfaceWithError& qi ) + : NSCAP_CTOR_BASE(0) + // construct from |do_QueryInterface(expr, &rv)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi_with_error(qi, NS_GET_IID(T)); + } + + nsCOMPtr( const nsCOMPtr_helper& helper ) + : NSCAP_CTOR_BASE(0) + // ...and finally, anything else we might need to construct from + // can exploit the |nsCOMPtr_helper| facility + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_helper(helper, NS_GET_IID(T)); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + + // Assignment operators + + nsCOMPtr& + operator=( const nsCOMPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( T* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + nsCOMPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterface rhs ) + // assign from |do_QueryInterface(expr)| + { + assign_from_qi(rhs, NS_GET_IID(T)); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterfaceWithError& rhs ) + // assign from |do_QueryInterface(expr, &rv)| + { + assign_from_qi_with_error(rhs, NS_GET_IID(T)); + return *this; + } + + nsCOMPtr& + operator=( const nsCOMPtr_helper& rhs ) + // ...and finally, anything else we might need to assign from + // can exploit the |nsCOMPtr_helper| facility. + { + assign_from_helper(rhs, NS_GET_IID(T)); + NSCAP_ASSERT_NO_QUERY_NEEDED(); + return *this; + } + + void + swap( nsCOMPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { +#ifdef NSCAP_FEATURE_USE_BASE + nsISupports* temp = rhs.mRawPtr; +#else + T* temp = rhs.mRawPtr; +#endif + NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + NSCAP_LOG_RELEASE(&rhs, temp); + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED| + } + + void + swap( T*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { +#ifdef NSCAP_FEATURE_USE_BASE + nsISupports* temp = rhs; +#else + T* temp = rhs; +#endif + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + rhs = NS_REINTERPRET_CAST(T*, mRawPtr); + mRawPtr = temp; + NSCAP_ASSERT_NO_QUERY_NEEDED(); + } + + + // Other pointer operators + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsCOMPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsCOMPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsCOMPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); + return *get(); + } + +#if 0 + private: + friend class nsGetterAddRefs; +#endif + + T** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(T**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(T**, &mRawPtr); +#endif + } + }; + + + + /* + Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr| the + same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing + to any valid [XP]COM interface. Otherwise, an |nsCOMPtr| would only be able + to point to the single [XP]COM-correct |nsISupports| instance within an object; extra + querying ensues. Clients need to be able to pass around arbitrary interface pointers, + without hassles, through intermediary code that doesn't know the exact type. + */ + +NS_SPECIALIZE_TEMPLATE +class nsCOMPtr + : private nsCOMPtr_base + { + public: + typedef nsISupports element_type; + + // Constructors + + nsCOMPtr() + : nsCOMPtr_base(0) + // default constructor + { + NSCAP_LOG_ASSIGNMENT(this, 0); + } + + nsCOMPtr( const nsCOMPtr& aSmartPtr ) + : nsCOMPtr_base(aSmartPtr.mRawPtr) + // copy constructor + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( nsISupports* aRawPtr ) + : nsCOMPtr_base(aRawPtr) + // construct from a raw pointer (of the right type) + { + if ( mRawPtr ) + NSCAP_ADDREF(this, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, aRawPtr); + } + + nsCOMPtr( const already_AddRefed& aSmartPtr ) + : nsCOMPtr_base(aSmartPtr.mRawPtr) + // construct from |dont_AddRef(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr); + } + + nsCOMPtr( const nsQueryInterface qi ) + : nsCOMPtr_base(0) + // assign from |do_QueryInterface(expr)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi(qi, NS_GET_IID(nsISupports)); + } + + nsCOMPtr( const nsQueryInterfaceWithError& qi ) + : nsCOMPtr_base(0) + // assign from |do_QueryInterface(expr, &rv)| + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_qi_with_error(qi, NS_GET_IID(nsISupports)); + } + + nsCOMPtr( const nsCOMPtr_helper& helper ) + : nsCOMPtr_base(0) + // ...and finally, anything else we might need to construct from + // can exploit the |nsCOMPtr_helper| facility + { + NSCAP_LOG_ASSIGNMENT(this, 0); + assign_from_helper(helper, NS_GET_IID(nsISupports)); + } + + + // Assignment operators + + nsCOMPtr& + operator=( const nsCOMPtr& rhs ) + // copy assignment operator + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( nsISupports* rhs ) + // assign from a raw pointer (of the right type) + { + assign_with_AddRef(rhs); + return *this; + } + + nsCOMPtr& + operator=( const already_AddRefed& rhs ) + // assign from |dont_AddRef(expr)| + { + assign_assuming_AddRef(rhs.mRawPtr); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterface rhs ) + // assign from |do_QueryInterface(expr)| + { + assign_from_qi(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + nsCOMPtr& + operator=( const nsQueryInterfaceWithError& rhs ) + // assign from |do_QueryInterface(expr, &rv)| + { + assign_from_qi_with_error(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + nsCOMPtr& + operator=( const nsCOMPtr_helper& rhs ) + // ...and finally, anything else we might need to assign from + // can exploit the |nsCOMPtr_helper| facility. + { + assign_from_helper(rhs, NS_GET_IID(nsISupports)); + return *this; + } + + void + swap( nsCOMPtr& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + nsISupports* temp = rhs.mRawPtr; + NSCAP_LOG_ASSIGNMENT(&rhs, mRawPtr); + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + NSCAP_LOG_RELEASE(&rhs, temp); + rhs.mRawPtr = mRawPtr; + mRawPtr = temp; + } + + void + swap( nsISupports*& rhs ) + // ...exchange ownership with |rhs|; can save a pair of refcount operations + { + nsISupports* temp = rhs; + NSCAP_LOG_ASSIGNMENT(this, temp); + NSCAP_LOG_RELEASE(this, mRawPtr); + rhs = mRawPtr; + mRawPtr = temp; + } + + + // Other pointer operators + + nsDerivedSafe* + get() const + /* + Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*() const|. + Use |get()| _only_ to resolve ambiguity. + + Returns a |nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. + */ + { + return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); + } + + operator nsDerivedSafe*() const + /* + ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, + and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator + that makes an |nsCOMPtr| substitutable for a raw pointer. + + Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. + */ + { + return get(); + } + + nsDerivedSafe* + operator->() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); + return get(); + } + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + // broken version for IRIX + + nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return NS_CONST_CAST(nsCOMPtr*, this); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + nsCOMPtr* + get_address() + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + + const nsCOMPtr* + get_address() const + // This is not intended to be used by clients. See |address_of| + // below. + { + return this; + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + + public: + + nsDerivedSafe& + operator*() const + { + NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); + return *get(); + } + +#if 0 + private: + friend class nsGetterAddRefs; +#endif + + nsISupports** + StartAssignment() + { +#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT + return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); +#else + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); +#endif + } + }; + +#ifndef NSCAP_FEATURE_USE_BASE +template +void +nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) + { + if ( rawPtr ) + NSCAP_ADDREF(this, rawPtr); + assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr)); + } + +template +void +nsCOMPtr::assign_from_qi( const nsQueryInterface qi, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( qi(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void +nsCOMPtr::assign_from_qi_with_error( const nsQueryInterfaceWithError& qi, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( qi(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void +nsCOMPtr::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID ) + { + T* newRawPtr; + if ( NS_FAILED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } + +template +void** +nsCOMPtr::begin_assignment() + { + assign_assuming_AddRef(0); + return NS_REINTERPRET_CAST(void**, &mRawPtr); + } +#endif + +#ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY + +// This is the broken version for IRIX, which can't handle the version below. + +template +inline +nsCOMPtr* +address_of( const nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +#else // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +inline +nsCOMPtr* +address_of( nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +template +inline +const nsCOMPtr* +address_of( const nsCOMPtr& aPtr ) + { + return aPtr.get_address(); + } + +#endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY + +template +class nsGetterAddRefs + /* + ... + + This class is designed to be used for anonymous temporary objects in the + argument list of calls that return COM interface pointers, e.g., + + nsCOMPtr fooP; + ...->QueryInterface(iid, getter_AddRefs(fooP)) + + DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. + + When initialized with a |nsCOMPtr|, as in the example above, it returns + a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this + case) can fill in. + + This type should be a nested class inside |nsCOMPtr|. + */ + { + public: + explicit + nsGetterAddRefs( nsCOMPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + +#if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT) + ~nsGetterAddRefs() + { +#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT + NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); +#endif + +#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES + mTargetSmartPtr.Assert_NoQueryNeeded(); +#endif + } +#endif + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator nsISupports**() + { + return NS_REINTERPRET_CAST(nsISupports**, mTargetSmartPtr.StartAssignment()); + } + + operator T**() + { + return mTargetSmartPtr.StartAssignment(); + } + + T*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsCOMPtr& mTargetSmartPtr; + }; + + +NS_SPECIALIZE_TEMPLATE +class nsGetterAddRefs + { + public: + explicit + nsGetterAddRefs( nsCOMPtr& aSmartPtr ) + : mTargetSmartPtr(aSmartPtr) + { + // nothing else to do + } + +#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT + ~nsGetterAddRefs() + { + NSCAP_LOG_ASSIGNMENT(NS_REINTERPRET_CAST(void *, address_of(mTargetSmartPtr)), mTargetSmartPtr.get()); + } +#endif + + operator void**() + { + return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); + } + + operator nsISupports**() + { + return mTargetSmartPtr.StartAssignment(); + } + + nsISupports*& + operator*() + { + return *(mTargetSmartPtr.StartAssignment()); + } + + private: + nsCOMPtr& mTargetSmartPtr; + }; + + +template +inline +nsGetterAddRefs +getter_AddRefs( nsCOMPtr& aSmartPtr ) + /* + Used around a |nsCOMPtr| when + ...makes the class |nsGetterAddRefs| invisible. + */ + { + return nsGetterAddRefs(aSmartPtr); + } + + + + // Comparing two |nsCOMPtr|s + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_STATIC_CAST(const U*, rhs.get()); + } + + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_STATIC_CAST(const U*, rhs.get()); + } + + + // Comparing an |nsCOMPtr| to a raw pointer + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == rhs; + } + +template +inline +NSCAP_BOOL +operator==( const U* lhs, const nsCOMPtr& rhs ) + { + return lhs == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, const U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != rhs; + } + +template +inline +NSCAP_BOOL +operator!=( const U* lhs, const nsCOMPtr& rhs ) + { + return lhs != NS_STATIC_CAST(const T*, rhs.get()); + } + + // To avoid ambiguities caused by the presence of builtin |operator==|s + // creating a situation where one of the |operator==| defined above + // has a better conversion for one argument and the builtin has a + // better conversion for the other argument, define additional + // |operator==| without the |const| on the raw pointer. + // See bug 65664 for details. + +// This is defined by an autoconf test, but VC++ also has a bug that +// prevents us from using these. (It also, fortunately, has the bug +// that we don't need them either.) +#if defined(_MSC_VER) && (_MSC_VER < 1310) +#define NSCAP_DONT_PROVIDE_NONCONST_OPEQ +#endif + +#ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) == NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( U* lhs, const nsCOMPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) == NS_STATIC_CAST(const T*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, U* rhs ) + { + return NS_STATIC_CAST(const T*, lhs.get()) != NS_CONST_CAST(const U*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( U* lhs, const nsCOMPtr& rhs ) + { + return NS_CONST_CAST(const U*, lhs) != NS_STATIC_CAST(const T*, rhs.get()); + } +#endif + + + + // Comparing an |nsCOMPtr| to |0| + +class NSCAP_Zero; + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +template +inline +NSCAP_BOOL +operator!=( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) + // specifically to allow |smartPtr != 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator!=( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 != smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); + } + + +#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + + // We need to explicitly define comparison operators for `int' + // because the compiler is lame. + +template +inline +NSCAP_BOOL +operator==( const nsCOMPtr& lhs, int rhs ) + // specifically to allow |smartPtr == 0| + { + return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); + } + +template +inline +NSCAP_BOOL +operator==( int lhs, const nsCOMPtr& rhs ) + // specifically to allow |0 == smartPtr| + { + return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); + } + +#endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO) + + // Comparing any two [XP]COM objects for identity + +inline +NSCAP_BOOL +SameCOMIdentity( nsISupports* lhs, nsISupports* rhs ) + { + return nsCOMPtr( do_QueryInterface(lhs) ) == nsCOMPtr( do_QueryInterface(rhs) ); + } + + + +template +inline +nsresult +CallQueryInterface( nsCOMPtr& aSourcePtr, DestinationType** aDestPtr ) + { + return CallQueryInterface(aSourcePtr.get(), aDestPtr); + } + +#endif // !defined(nsCOMPtr_h___) diff --git a/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp b/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp new file mode 100644 index 00000000..5733fc36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsComponentManagerUtils.cpp @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsXPCOM_h__ +#include "nsXPCOM.h" +#endif + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +#include "nsComponentManagerUtils.h" +#include "nsIServiceManagerUtils.h" + +nsresult +nsCreateInstanceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsCOMPtr compMgr; + nsresult status = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (compMgr) + status = compMgr->CreateInstance(mCID, mOuter, aIID, aInstancePtr); + else if (NS_SUCCEEDED(status)) + status = NS_ERROR_UNEXPECTED; + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + +nsresult +nsCreateInstanceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status; + if ( mContractID ) { + nsCOMPtr compMgr; + status = NS_GetComponentManager(getter_AddRefs(compMgr)); + if (compMgr) + status = compMgr->CreateInstanceByContractID(mContractID, mOuter, + aIID, aInstancePtr); + else if (NS_SUCCEEDED(status)) + status = NS_ERROR_UNEXPECTED; + } + else + status = NS_ERROR_NULL_POINTER; + + if (NS_FAILED(status)) + *aInstancePtr = 0; + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + + +nsresult +nsGetServiceByCID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetService(mCID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); + } + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + +nsresult +nsGetServiceByContractID::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status = NS_ERROR_FAILURE; + if ( mServiceManager ) { + status = mServiceManager->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + status = mgr->GetServiceByContractID(mContractID, aIID, (void**)aInstancePtr); + } + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp b/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp new file mode 100644 index 00000000..9e947f30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsDebug.cpp @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsDebug.h" +#include "nsDebugImpl.h" + +static nsIDebug* gDebugObject = nsnull; + +// Note: Although the machinery here is similar to nsMemory.cpp, we cannot use +// NS_ASSERTION macros below because they end up in nsDebug::Assertion and +// therefore may produce endless recursion. + +static NS_METHOD FreeDebugObject(void) +{ + NS_IF_RELEASE(gDebugObject); + return NS_OK; +} + +#define ENSURE_DEBUGOBJECT \ + (gDebugObject ? PR_TRUE : (PRBool)(SetupDebugObject() != nsnull)) + +static nsIDebug* SetupDebugObject() +{ + if (!gDebugObject) + { + NS_GetDebug(&gDebugObject); + if (gDebugObject) + NS_RegisterXPCOMExitRoutine(FreeDebugObject, 0); + } + return gDebugObject; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupDebug() +{ + if (!gDebugObject) + { + NS_GetDebug(&gDebugObject); + if (!gDebugObject) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +void GlueShutdownDebug() +{ + NS_IF_RELEASE(gDebugObject); +} +#endif + +NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Abort(aFile, aLine); +} + +NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Break(aFile, aLine); +} + +NS_COM void nsDebug::Warning(const char* aStr, + const char* aFile, + PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Warning(aStr, aFile, aLine); +} + +NS_COM void nsDebug::Assertion(const char* aStr, const char* aExpr, + const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Assertion(aStr, aExpr, aFile, aLine); +} diff --git a/src/libs/xpcom18a4/xpcom/glue/nsDebug.h b/src/libs/xpcom18a4/xpcom/glue/nsDebug.h new file mode 100644 index 00000000..f2ed4c56 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsDebug.h @@ -0,0 +1,276 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsDebug_h___ +#define nsDebug_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsError_h__ +#include "nsError.h" +#endif + +#ifdef DEBUG +#define NS_DEBUG +#endif + +/** + * Namespace for debugging methods. Note that your code must use the + * macros defined later in this file so that the debug code can be + * conditionally compiled out. + */ + +/* in case this is included by a C file */ +#ifdef __cplusplus + +class nsDebug { +public: + + /** + * Log a warning message to the debug log. + */ + static NS_COM void Warning(const char* aMessage, + const char* aFile, PRIntn aLine); + + /** + * Abort the executing program. This works on all architectures. + */ + static NS_COM void Abort(const char* aFile, PRIntn aLine); + + /** + * Break the executing program into the debugger. + */ + static NS_COM void Break(const char* aFile, PRIntn aLine); + + /** + * Log an assertion message to the debug log + */ + static NS_COM void Assertion(const char* aStr, const char* aExpr, + const char* aFile, PRIntn aLine); +}; + +#ifdef DEBUG + +/** + * Abort the execution of the program if the expression evaluates to + * false. + * + * There is no status value returned from the macro. + * + * Note that the non-debug version of this macro does not + * evaluate the expression argument. Hence side effect statements + * as arguments to the macro will yield improper execution in a + * non-debug build. For example: + * + * NS_ABORT_IF_FALSE(0 == foo++, "yikes foo should be zero"); + * + * Note also that the non-debug version of this macro does not + * evaluate the message argument. + */ +#define NS_ABORT_IF_FALSE(_expr, _msg) \ + PR_BEGIN_MACRO \ + if (!(_expr)) { \ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Warn if a given condition is false. + * + * Program execution continues past the usage of this macro. + * + * Note also that the non-debug version of this macro does not + * evaluate the message argument. + */ +#define NS_WARN_IF_FALSE(_expr,_msg) \ + PR_BEGIN_MACRO \ + if (!(_expr)) { \ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test a precondition for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_PRECONDITION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test an assertion for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_ASSERTION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * Test a post-condition for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_POSTCONDITION(expr, str) \ + PR_BEGIN_MACRO \ + if (!(expr)) { \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ + } \ + PR_END_MACRO + +/** + * This macros triggers a program failure if executed. It indicates that + * an attempt was made to execute some unimplimented functionality. + */ +#define NS_NOTYETIMPLEMENTED(str) \ + nsDebug::Assertion(str, "NotYetImplemented", __FILE__, __LINE__) + +/** + * This macros triggers a program failure if executed. It indicates that + * an attempt was made to execute some unimplimented functionality. + */ +#define NS_NOTREACHED(str) \ + nsDebug::Assertion(str, "Not Reached", __FILE__, __LINE__) + +/** + * Log an error message. + */ +#define NS_ERROR(str) \ + nsDebug::Assertion(str, "Error", __FILE__, __LINE__) + +/** + * Log a warning message. + */ +#define NS_WARNING(str) \ + nsDebug::Warning(str, __FILE__, __LINE__) + +/** + * Trigger an abort + */ +#define NS_ABORT() \ + nsDebug::Abort(__FILE__, __LINE__) + +/** + * Cause a break + */ +#define NS_BREAK() \ + nsDebug::Break(__FILE__, __LINE__) + +#else /* NS_DEBUG */ + +/** + * The non-debug version of these macros do not evaluate the + * expression or the message arguments to the macro. + */ +#define NS_ABORT_IF_FALSE(_expr, _msg) /* nothing */ +#define NS_WARN_IF_FALSE(_expr, _msg) /* nothing */ +#define NS_PRECONDITION(expr, str) /* nothing */ +#define NS_ASSERTION(expr, str) /* nothing */ +#define NS_POSTCONDITION(expr, str) /* nothing */ +#define NS_NOTYETIMPLEMENTED(str) /* nothing */ +#define NS_NOTREACHED(str) /* nothing */ +#define NS_ERROR(str) /* nothing */ +#define NS_WARNING(str) /* nothing */ +#define NS_ABORT() /* nothing */ +#define NS_BREAK() /* nothing */ + +#endif /* ! NS_DEBUG */ +#endif /* __cplusplus */ + +// Macros for checking the trueness of an expression passed in within an +// interface implementation. These need to be compiled regardless of the +// NS_DEBUG flag +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_TRUE(x, ret) \ + PR_BEGIN_MACRO \ + if (NS_UNLIKELY(!(x))) { \ + NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ + return ret; \ + } \ + PR_END_MACRO + +#define NS_ENSURE_FALSE(x, ret) \ + NS_ENSURE_TRUE(!(x), ret) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for checking results +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_SUCCESS(res, ret) \ + NS_ENSURE_TRUE(NS_SUCCEEDED(res), ret) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for checking state and arguments upon entering interface boundaries +/////////////////////////////////////////////////////////////////////////////// + +#define NS_ENSURE_ARG(arg) \ + NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_POINTER(arg) \ + NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_POINTER) + +#define NS_ENSURE_ARG_MIN(arg, min) \ + NS_ENSURE_TRUE((arg) >= min, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_MAX(arg, max) \ + NS_ENSURE_TRUE((arg) <= max, NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_ARG_RANGE(arg, min, max) \ + NS_ENSURE_TRUE(((arg) >= min) && ((arg) <= max), NS_ERROR_INVALID_ARG) + +#define NS_ENSURE_STATE(state) \ + NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED) + +#define NS_ENSURE_NO_AGGREGATION(outer) \ + NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) + +#define NS_ENSURE_PROPER_AGGREGATION(outer, iid) \ + NS_ENSURE_FALSE(outer && !iid.Equals(NS_GET_IID(nsISupports)), NS_ERROR_INVALID_ARG) + +/////////////////////////////////////////////////////////////////////////////// + +#define NS_CheckThreadSafe(owningThread, msg) \ + NS_ASSERTION(owningThread == PR_GetCurrentThread(), msg) + +#endif /* nsDebug_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp new file mode 100644 index 00000000..2d791943 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +// DO NOT COPY THIS CODE INTO YOUR SOURCE! USE NS_IMPL_NSGETMODULE() + +#include "nsGenericFactory.h" +#include "nsMemory.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#include "nsXPCOMPrivate.h" +#else +#include "nsIInterfaceRequestorUtils.h" +#include "nsINativeComponentLoader.h" +#endif + +nsGenericFactory::nsGenericFactory(const nsModuleComponentInfo *info) + : mInfo(info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); +} + +nsGenericFactory::~nsGenericFactory() +{ + if (mInfo) { + if (mInfo->mFactoryDestructor) + mInfo->mFactoryDestructor(); + if (mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsGenericFactory, + nsIGenericFactory, + nsIFactory, + nsIClassInfo) + +NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter, + REFNSIID aIID, void **aResult) +{ + if (mInfo->mConstructor) { + return mInfo->mConstructor(aOuter, aIID, aResult); + } + + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock) +{ + // XXX do we care if (mInfo->mFlags & THREADSAFE)? + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetInterfaces(PRUint32 *countp, + nsIID* **array) +{ + if (!mInfo->mGetInterfacesProc) { + *countp = 0; + *array = nsnull; + return NS_OK; + } + return mInfo->mGetInterfacesProc(countp, array); +} + +NS_IMETHODIMP nsGenericFactory::GetHelperForLanguage(PRUint32 language, + nsISupports **helper) +{ + if (mInfo->mGetLanguageHelperProc) + return mInfo->mGetLanguageHelperProc(language, helper); + *helper = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetContractID(char **aContractID) +{ + if (mInfo->mContractID) { + *aContractID = (char *)nsMemory::Alloc(strlen(mInfo->mContractID) + 1); + if (!*aContractID) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aContractID, mInfo->mContractID); + } else { + *aContractID = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassDescription(char * *aClassDescription) +{ + if (mInfo->mDescription) { + *aClassDescription = (char *) + nsMemory::Alloc(strlen(mInfo->mDescription) + 1); + if (!*aClassDescription) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aClassDescription, mInfo->mDescription); + } else { + *aClassDescription = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassID(nsCID * *aClassID) +{ + *aClassID = + NS_REINTERPRET_CAST(nsCID*, + nsMemory::Clone(&mInfo->mCID, sizeof mInfo->mCID)); + if (! *aClassID) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassIDNoAlloc(nsCID *aClassID) +{ + *aClassID = mInfo->mCID; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetImplementationLanguage(PRUint32 *langp) +{ + *langp = nsIProgrammingLanguage::CPLUSPLUS; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetFlags(PRUint32 *flagsp) +{ + *flagsp = mInfo->mFlags; + return NS_OK; +} + +// nsIGenericFactory: component-info accessors +NS_IMETHODIMP nsGenericFactory::SetComponentInfo(const nsModuleComponentInfo *info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + mInfo = info; + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetComponentInfo(const nsModuleComponentInfo **infop) +{ + *infop = mInfo; + return NS_OK; +} + +NS_METHOD nsGenericFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + // sorry, aggregation not spoken here. + nsresult res = NS_ERROR_NO_AGGREGATION; + if (outer == NULL) { + nsGenericFactory* factory = new nsGenericFactory; + if (factory != NULL) { + res = factory->QueryInterface(aIID, aInstancePtr); + if (res != NS_OK) + delete factory; + } else { + res = NS_ERROR_OUT_OF_MEMORY; + } + } + return res; +} + +NS_COM nsresult +NS_NewGenericFactory(nsIGenericFactory* *result, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsIGenericFactory* fact; + rv = nsGenericFactory::Create(NULL, NS_GET_IID(nsIGenericFactory), (void**)&fact); + if (NS_FAILED(rv)) return rv; + rv = fact->SetComponentInfo(info); + if (NS_FAILED(rv)) goto error; + *result = fact; + return rv; + + error: + NS_RELEASE(fact); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsGenericModule::nsGenericModule(const char* moduleName, PRUint32 componentCount, + const nsModuleComponentInfo* components, + nsModuleConstructorProc ctor, + nsModuleDestructorProc dtor, + const char** aLibDepends) + : mInitialized(PR_FALSE), + mModuleName(moduleName), + mComponentCount(componentCount), + mComponents(components), + mFactoriesNotToBeRegistered(nsnull), + mCtor(ctor), + mDtor(dtor), + mLibraryDependencies(aLibDepends) +{ +} + +nsGenericModule::~nsGenericModule() +{ + Shutdown(); + +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsGenericModule, nsIModule) + +nsresult +nsGenericModule::AddFactoryNode(nsIGenericFactory* fact) +{ + if (!fact) + return NS_ERROR_FAILURE; + + FactoryNode *node = new FactoryNode(fact, mFactoriesNotToBeRegistered); + if (!node) + return NS_ERROR_OUT_OF_MEMORY; + + mFactoriesNotToBeRegistered = node; + return NS_OK; +} + + +// Perform our one-time intialization for this module +nsresult +nsGenericModule::Initialize(nsIComponentManager *compMgr) +{ + nsresult rv; + + if (mInitialized) { + return NS_OK; + } + + if (mCtor) { + rv = mCtor(this); + if (NS_FAILED(rv)) + return rv; + } + + +#ifdef XPCOM_GLUE + rv = XPCOMGlueStartup("."); + if (NS_FAILED(rv)) + return rv; +#endif + + nsCOMPtr registrar = do_QueryInterface(compMgr, &rv); + if (NS_FAILED(rv)) + return rv; + + // Eagerly populate factory/class object hash for entries + // without constructors. If we didn't, the class object would + // never get created. Also create the factory, which doubles + // as the class object, if the EAGER_CLASSINFO flag was given. + // This allows objects to be created (within their modules) + // via operator new rather than CreateInstance, yet still be + // QI'able to nsIClassInfo. + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (!desc->mConstructor || + (desc->mFlags & nsIClassInfo::EAGER_CLASSINFO)) { + nsCOMPtr fact; + nsresult rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + + // if we don't have a mConstructor, then we should not populate + // the component manager. + if (!desc->mConstructor) { + rv = AddFactoryNode(fact); + } else { + rv = registrar->RegisterFactory(desc->mCID, + desc->mDescription, + desc->mContractID, + fact); + } + if (NS_FAILED(rv)) return rv; + } + desc++; + } + + mInitialized = PR_TRUE; + return NS_OK; +} + +// Shutdown this module, releasing all of the module resources +void +nsGenericModule::Shutdown() +{ + // Free cached factories that were not registered. + FactoryNode* node; + while (mFactoriesNotToBeRegistered) + { + node = mFactoriesNotToBeRegistered->mNext; + delete mFactoriesNotToBeRegistered; + mFactoriesNotToBeRegistered = node; + } + + if (mInitialized) { + mInitialized = PR_FALSE; + + if (mDtor) + mDtor(this); + } +} + +// Create a factory object for creating instances of aClass. +NS_IMETHODIMP +nsGenericModule::GetClassObject(nsIComponentManager *aCompMgr, + const nsCID& aClass, + const nsIID& aIID, + void** r_classObj) +{ + nsresult rv; + + // Defensive programming: Initialize *r_classObj in case of error below + if (!r_classObj) { + return NS_ERROR_INVALID_POINTER; + } + *r_classObj = NULL; + + // Do one-time-only initialization if necessary + if (!mInitialized) { + rv = Initialize(aCompMgr); + if (NS_FAILED(rv)) { + // Initialization failed! yikes! + return rv; + } + } + + // Choose the appropriate factory, based on the desired instance + // class type (aClass). + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (desc->mCID.Equals(aClass)) { + nsCOMPtr fact; + rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + return fact->QueryInterface(aIID, r_classObj); + } + desc++; + } + // not found in descriptions +#ifndef XPCOM_GLUE +#ifdef DEBUG + char* cs = aClass.ToString(); + fprintf(stderr, "+++ nsGenericModule %s: unable to create factory for %s\n", mModuleName, cs); + // leak until we resolve the nsID Allocator. + // nsCRT::free(cs); +#endif // XXX put in stop-gap so that we don't search for this one again +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP +nsGenericModule::RegisterSelf(nsIComponentManager *aCompMgr, + nsIFile* aPath, + const char* registryLocation, + const char* componentType) +{ + nsresult rv = NS_OK; + +#ifdef DEBUG + fprintf(stderr, "*** Registering %s components (all right -- a generic module!)\n", mModuleName); +#endif + + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Register the component only if it has a constructor + if (cp->mConstructor) { + nsCOMPtr registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->RegisterFactoryLocation(cp->mCID, + cp->mDescription, + cp->mContractID, + aPath, + registryLocation, + componentType); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to register %s component => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + // Call the registration hook of the component, if any + if (cp->mRegisterSelfProc) + { + rv = cp->mRegisterSelfProc(aCompMgr, aPath, registryLocation, + componentType, cp); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: Register hook for %s component returned error => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + cp++; + } + +#ifndef XPCOM_GLUE + // We want to tell the component loader of any dependencies + // we have so that the loader can resolve them for us. + + nsCOMPtr loader = do_GetInterface(aCompMgr); + if (loader && mLibraryDependencies) + { + for(int i=0; mLibraryDependencies[i] != nsnull && + mLibraryDependencies[i][0] != '\0'; i++) + { + loader->AddDependentLibrary(aPath, + mLibraryDependencies[i]); + } + loader = nsnull; + } +#endif + + + + return rv; +} + +NS_IMETHODIMP +nsGenericModule::UnregisterSelf(nsIComponentManager* aCompMgr, + nsIFile* aPath, + const char* registryLocation) +{ +#ifdef DEBUG + fprintf(stderr, "*** Unregistering %s components (all right -- a generic module!)\n", mModuleName); +#endif + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Call the unregistration hook of the component, if any + if (cp->mUnregisterSelfProc) + { + cp->mUnregisterSelfProc(aCompMgr, aPath, registryLocation, cp); + } + + // Unregister the component + nsresult rv; + nsCOMPtr registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->UnregisterFactoryLocation(cp->mCID, aPath); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to unregister %s component => %x\n", + mModuleName, cp->mDescription, rv); +#endif + } + cp++; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsGenericModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) +{ + if (!okToUnload) { + return NS_ERROR_INVALID_POINTER; + } + *okToUnload = PR_FALSE; + return NS_ERROR_FAILURE; +} + +NS_COM nsresult +NS_NewGenericModule2(nsModuleInfo* info, nsIModule* *result) +{ + nsresult rv = NS_OK; + + // Create and initialize the module instance + nsGenericModule *m = + new nsGenericModule(info->mModuleName, info->mCount, info->mComponents, + info->mCtor, info->mDtor, info->mLibraryDependencies); + + if (!m) + return NS_ERROR_OUT_OF_MEMORY; + + // Increase refcnt and store away nsIModule interface to m in result + NS_ADDREF(*result = m); + return rv; +} + +NS_COM nsresult +NS_NewGenericModule(const char* moduleName, + PRUint32 componentCount, + nsModuleComponentInfo* components, + nsModuleDestructorProc dtor, + nsIModule* *result) +{ + nsModuleInfo info; + memset(&info, 0, sizeof(info)); + + info.mVersion = NS_MODULEINFO_VERSION; + info.mModuleName = moduleName; + info.mComponents = components; + info.mCount = componentCount; + info.mDtor = dtor; + info.mLibraryDependencies = nsnull; + + return NS_NewGenericModule2(&info, result); +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h new file mode 100644 index 00000000..64afd0de --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsGenericFactory_h___ +#define nsGenericFactory_h___ + +#include "nsCOMPtr.h" +#include "nsIGenericFactory.h" +#include "nsIClassInfo.h" + +/** + * Most factories follow this simple pattern, so why not just use a function + * pointer for most creation operations? + */ +class nsGenericFactory : public nsIGenericFactory, public nsIClassInfo { +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_GENERICFACTORY_CID); + + nsGenericFactory(const nsModuleComponentInfo *info = NULL); + + NS_DECL_ISUPPORTS + NS_DECL_NSICLASSINFO + + /* nsIGenericFactory methods */ + NS_IMETHOD SetComponentInfo(const nsModuleComponentInfo *info); + NS_IMETHOD GetComponentInfo(const nsModuleComponentInfo **infop); + + NS_IMETHOD CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock); + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); +private: + ~nsGenericFactory(); + + const nsModuleComponentInfo *mInfo; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#include "nsIModule.h" +#include "plhash.h" + +class nsGenericModule : public nsIModule +{ +public: + nsGenericModule(const char* moduleName, + PRUint32 componentCount, + const nsModuleComponentInfo* components, + nsModuleConstructorProc ctor, + nsModuleDestructorProc dtor, + const char** alibDepends); + +private: + ~nsGenericModule(); + +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIMODULE + + struct FactoryNode + { + FactoryNode(nsIGenericFactory* fact, FactoryNode* next) + { + mFactory = fact; + mNext = next; + } + ~FactoryNode(){} + + nsCOMPtr mFactory; + FactoryNode* mNext; + }; + + + + +protected: + nsresult Initialize(nsIComponentManager* compMgr); + + void Shutdown(); + nsresult AddFactoryNode(nsIGenericFactory* fact); + + PRBool mInitialized; + const char* mModuleName; + PRUint32 mComponentCount; + const nsModuleComponentInfo* mComponents; + FactoryNode* mFactoriesNotToBeRegistered; + nsModuleConstructorProc mCtor; + nsModuleDestructorProc mDtor; + const char** mLibraryDependencies; +}; + +#endif /* nsGenericFactory_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h b/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h new file mode 100644 index 00000000..82506e8e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIGenericFactory.h @@ -0,0 +1,480 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIGenericFactory_h___ +#define nsIGenericFactory_h___ + +#include "nsIFactory.h" +#include "nsIModule.h" +#include "nsIClassInfo.h" +#ifdef HAVE_DEPENDENT_LIBS +#include "dependentLibs.h" +#endif + +// {3bc97f01-ccdf-11d2-bab8-b548654461fc} +#define NS_GENERICFACTORY_CID \ + { 0x3bc97f01, 0xccdf, 0x11d2, \ + { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } } + +// {3bc97f00-ccdf-11d2-bab8-b548654461fc} +#define NS_IGENERICFACTORY_IID \ + { 0x3bc97f00, 0xccdf, 0x11d2, \ + { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } } + +#define NS_GENERICFACTORY_CONTRACTID "@mozilla.org/generic-factory;1" +#define NS_GENERICFACTORY_CLASSNAME "Generic Factory" + +struct nsModuleComponentInfo; // forward declaration + +/** + * Provides a Generic nsIFactory implementation that can be used by + * DLLs with very simple factory needs. + */ +class nsIGenericFactory : public nsIFactory { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IGENERICFACTORY_IID) + + NS_IMETHOD SetComponentInfo(const nsModuleComponentInfo *info) = 0; + NS_IMETHOD GetComponentInfo(const nsModuleComponentInfo **infop) = 0; +}; + +NS_COM nsresult +NS_NewGenericFactory(nsIGenericFactory **result, + const nsModuleComponentInfo *info); + + +/** Component Callbacks **/ + + /** + * NSConstructorProcPtr + * + * This function will be used by the generic factory to create an + * instance of the given CID. + * + * @param aOuter : Pointer to a component that wishes to be aggregated + * in the resulting instance. This will be nsnull if no + * aggregation is requested. + * @param iid : The IID of the interface being requested in + * the component which is being currently created. + * @param result : [out] Pointer to the newly created instance, if successful. + * + * @return NS_OK Component successfully created and the interface + * being requested was successfully returned in result. + * NS_NOINTERFACE Interface not accessible. + * NS_ERROR_NO_AGGREGATION if an 'outer' object is supplied, but the + * component is not aggregatable. + * NS_ERROR* Method failure. + **/ +typedef NS_CALLBACK(NSConstructorProcPtr)(nsISupports *aOuter, + REFNSIID aIID, + void **aResult); + +/** + * NSRegisterSelfProcPtr + * + * One time registration call back. Allows you to perform registration + * specific activity like adding yourself to a category. + * + * @param aCompMgr : The global component manager + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader defines. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aType : Component Type of CID aClass. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aInfo : Pointer to array of nsModuleComponentInfo + * + * @param aInfo + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + **/ +typedef NS_CALLBACK(NSRegisterSelfProcPtr)(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *aLoaderStr, + const char *aType, + const nsModuleComponentInfo *aInfo); + +/** + * NSUnregisterSelfProcPtr + * + * One time unregistration call back. Allows you to perform unregistration + * specific activity like removing yourself from a category. + * + * @param aCompMgr : The global component manager + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader defines. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location + * @param aInfo : Pointer to array of nsModuleComponentInfo + * + * @param aInfo + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + + **/ +typedef NS_CALLBACK(NSUnregisterSelfProcPtr)(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *aLoaderStr, + const nsModuleComponentInfo *aInfo); + +/** + * NSFactoryDestructorProcPtr + * + * This function will be called when the factory is being destroyed. + * + **/ +typedef NS_CALLBACK(NSFactoryDestructorProcPtr)(void); + + +/** + * NSGetInterfacesProcPtr + * + * This function is used to implement class info. + * + * Get an ordered list of the interface ids that instances of the class + * promise to implement. Note that nsISupports is an implicit member + * of any such list and need not be included. + * + * Should set *count = 0 and *array = null and return NS_OK if getting the + * list is not supported. + * + * @see nsIClassInfo.idl + **/ +typedef NS_CALLBACK(NSGetInterfacesProcPtr)(PRUint32 *countp, + nsIID* **array); + +/** + * NSGetLanguageHelperProcPtr + * + * This function is used to implement class info. + * + * Get a language mapping specific helper object that may assist in using + * objects of this class in a specific lanaguage. For instance, if asked + * for the helper for nsIProgrammingLanguage::JAVASCRIPT this might return + * an object that can be QI'd into the nsIXPCScriptable interface to assist + * XPConnect in supplying JavaScript specific behavior to callers of the + * instance object. + * + * @see: nsIClassInfo.idl, nsIProgrammingLanguage.idl + * + * Should return null if no helper available for given language. + **/ +typedef NS_CALLBACK(NSGetLanguageHelperProcPtr)(PRUint32 language, + nsISupports **helper); + +/** + * nsModuleComponentInfo + * + * Use this type to define a list of module component info to pass to + * NS_NewGenericModule. + * + * @param mDescription : Class Name of given object + * @param mCID : CID of given object + * @param mContractID : Contract ID of given object + * @param mConstructor : Constructor of given object + * @param mRegisterSelfProc : (optional) Registration Callback + * @param mUnregisterSelfProc : (optional) Unregistration Callback + * @param mFactoryDestructor : (optional) Destruction Callback + * @param mGetInterfacesProc : (optional) Interfaces Callback + * @param mGetLanguageHelperProc : (optional) Language Helper Callback + * @param mClassInfoGlobal : (optional) Global Class Info of given object + * @param mFlags : (optional) Class Info Flags @see nsIClassInfo + * + * E.g.: + * static nsModuleComponentInfo components[] = { ... }; + * + * See xpcom/sample/nsSampleModule.cpp for more info. + */ +struct nsModuleComponentInfo { + const char* mDescription; + nsCID mCID; + const char* mContractID; + NSConstructorProcPtr mConstructor; + NSRegisterSelfProcPtr mRegisterSelfProc; + NSUnregisterSelfProcPtr mUnregisterSelfProc; + NSFactoryDestructorProcPtr mFactoryDestructor; + NSGetInterfacesProcPtr mGetInterfacesProc; + NSGetLanguageHelperProcPtr mGetLanguageHelperProc; + nsIClassInfo ** mClassInfoGlobal; + PRUint32 mFlags; +}; + + +/** Module Callbacks **/ + + +/** + * nsModuleConstructorProc + * + * This function is called when the module is first being constructed. + * @param self module which is being constructed. + * + * @return NS_OK Construction successful. + * NS_ERROR* Method failure which will result in module not being + * loaded. + **/ +typedef nsresult (PR_CALLBACK *nsModuleConstructorProc) (nsIModule *self); + + +/** + * nsModuleDestructorProc + * + * This function is called when the module is being destroyed. + * @param self module which is being destroyed. + * + **/ +typedef void (PR_CALLBACK *nsModuleDestructorProc) (nsIModule *self); + +/** + * nsModuleInfo + * + * Use this structure to define meta-information about the module + * itself, including the name, its components, and an optional + * module-level initialization or shutdown routine. + * + * @param mVersion : Module Info Version + * @param mModuleName : Module Name + * @param mComponents : Array of Components + * @param mCount : Count of mComponents + * @param mCtor : Module user defined constructor + * @param mDtor : Module user defined destructor + * @param mLibraryDependencies : array of library which this module is + * dependent on. + * + **/ + +struct nsModuleInfo { + PRUint32 mVersion; + const char* mModuleName; + const nsModuleComponentInfo* mComponents; + PRUint32 mCount; + nsModuleConstructorProc mCtor; + nsModuleDestructorProc mDtor; + const char** mLibraryDependencies; +}; + +/** + * Rev this if you change the nsModuleInfo, and are worried about + * binary compatibility. (Ostensibly fix NS_NewGenericModule2() to deal + * with older rev's at the same time.) + */ +#define NS_MODULEINFO_VERSION 0x00015000UL // 1.5 + +/** + * Create a new generic module. Use the NS_IMPL_NSGETMODULE macro, or + * one of its relatives, rather than using this directly. + */ +NS_COM nsresult +NS_NewGenericModule2(nsModuleInfo *info, nsIModule* *result); + +/** + * Obsolete. Use NS_NewGenericModule2() instead. + */ +NS_COM nsresult +NS_NewGenericModule(const char* moduleName, + PRUint32 componentCount, + nsModuleComponentInfo* components, + nsModuleDestructorProc dtor, + nsIModule* *result); + +#if defined(XPCOM_TRANSLATE_NSGM_ENTRY_POINT) +# define NS_MODULEINFO nsModuleInfo +# define NSMODULEINFO(_name) _name##_gModuleInfo +# define NSGETMODULE_ENTRY_POINT(_info) +# define NSDEPENDENT_LIBS(_name) const char* _name##_gDependlibs[]={DEPENDENT_LIBS "\0"}; +# define NSDEPENDENT_LIBS_NAME(_name) _name##_gDependlibs +#else +# define NS_MODULEINFO static nsModuleInfo +# define NSMODULEINFO(_name) gModuleInfo +# define NSDEPENDENT_LIBS(_name) static const char* gDependlibs[]={DEPENDENT_LIBS "\0"}; +# define NSDEPENDENT_LIBS_NAME(_name) gDependlibs +# define NSGETMODULE_ENTRY_POINT(_info) \ +extern "C" NS_EXPORT nsresult \ +NSGetModule(nsIComponentManager *servMgr, \ + nsIFile* location, \ + nsIModule** result) \ +{ \ + (void)servMgr; \ + (void)location; \ + return NS_NewGenericModule2(&(_info), result); \ +} +#endif + +/** + * Ease of use Macros which define NSGetModule for your component. + * See xpcom/sample/nsSampleModule.cpp for more info. + * + **/ + +#define NS_IMPL_NSGETMODULE(_name, _components) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, nsnull, nsnull) + +#define NS_IMPL_NSGETMODULE_WITH_CTOR(_name, _components, _ctor) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, nsnull) + +#define NS_IMPL_NSGETMODULE_WITH_DTOR(_name, _components, _dtor) \ + NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, nsnull, _dtor) + +#ifndef DEPENDENT_LIBS + +#define NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, _dtor) \ +NS_MODULEINFO NSMODULEINFO(_name) = { \ + NS_MODULEINFO_VERSION, \ + (#_name), \ + (_components), \ + (sizeof(_components) / sizeof(_components[0])), \ + (_ctor), \ + (_dtor), \ + (nsnull) \ +}; \ +NSGETMODULE_ENTRY_POINT(NSMODULEINFO(_name)) + +#else // DEPENDENT_LIBS + +#define NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(_name, _components, _ctor, _dtor) \ +NSDEPENDENT_LIBS(_name) \ +NS_MODULEINFO NSMODULEINFO(_name) = { \ + NS_MODULEINFO_VERSION, \ + (#_name), \ + (_components), \ + (sizeof(_components) / sizeof(_components[0])), \ + (_ctor), \ + (_dtor), \ + (NSDEPENDENT_LIBS_NAME(_name)) \ +}; \ +NSGETMODULE_ENTRY_POINT(NSMODULEINFO(_name)) + +#endif + +//////////////////////////////////////////////////////////////////////////////// + +#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + NS_NEWXPCOM(inst, _InstanceClass); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + NS_ADDREF(inst); \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + + +#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + NS_NEWXPCOM(inst, _InstanceClass); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + NS_ADDREF(inst); \ + rv = inst->_InitMethod(); \ + if(NS_SUCCEEDED(rv)) { \ + rv = inst->QueryInterface(aIID, aResult); \ + } \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + +// 'Constructor' that uses an existing getter function that gets a singleton. +// NOTE: assumes that getter does an AddRef - so additional AddRef is not done. +#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(_InstanceClass, _GetterProc) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + inst = _GetterProc(); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + /* NS_ADDREF(inst); */ \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} \ + +#endif /* nsIGenericFactory_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp new file mode 100644 index 00000000..b440c342 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" + +nsresult +nsGetInterface::operator()( const nsIID& aIID, void** aInstancePtr ) const +{ + nsresult status; + + if ( mSource ) + { + nsCOMPtr factoryPtr = do_QueryInterface(mSource, &status); + NS_ASSERTION(factoryPtr, "Did you know you were calling |do_GetInterface()| on an object that doesn't support the |nsIInterfaceRequestor| interface?"); + + if ( factoryPtr ) + status = factoryPtr->GetInterface(aIID, aInstancePtr); + + if ( NS_FAILED(status) ) + *aInstancePtr = 0; + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h new file mode 100644 index 00000000..e971dd4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIInterfaceRequestorUtils.h @@ -0,0 +1,83 @@ +/* -*- Mode: IDL; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsInterfaceRequestorUtils_h +#define __nsInterfaceRequestorUtils_h + +#include "nsCOMPtr.h" + +// a type-safe shortcut for calling the |GetInterface()| member function +// T must inherit from nsIInterfaceRequestor, but the cast may be ambiguous. +template +inline +nsresult +CallGetInterface( T* aSource, DestinationType** aDestination ) + { + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->GetInterface(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); + } + +class NS_COM nsGetInterface : public nsCOMPtr_helper + { + public: + nsGetInterface( nsISupports* aSource, nsresult* error ) + : mSource(aSource), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + nsCOMPtr mSource; + nsresult* mErrorPtr; + }; + +inline +const nsGetInterface +do_GetInterface( nsISupports* aSource, nsresult* error = 0 ) + { + return nsGetInterface(aSource, error); + } + +#endif // __nsInterfaceRequestorUtils_h + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h b/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h new file mode 100644 index 00000000..588a2c73 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsISupportsImpl.h @@ -0,0 +1,1246 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2001 + * 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 nsISupportsImpl_h__ +#define nsISupportsImpl_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsISupportsBase_h__ +#include "nsISupportsBase.h" +#endif + +#include "prthread.h" /* needed for thread-safety checks */ +#include "pratom.h" /* needed for PR_AtomicIncrement and PR_AtomicDecrement */ + +#include "nsDebug.h" +#include "nsTraceRefcnt.h" +#ifdef VBOX +# include "iprt/asm.h" +# include "iprt/assert.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Macros to help detect thread-safety: + +#if defined(NS_DEBUG) + +class nsAutoOwningThread { +public: + nsAutoOwningThread() { mThread = PR_GetCurrentThread(); } + void *GetThread() const { return mThread; } + +private: + void *mThread; +}; + +#define NS_DECL_OWNINGTHREAD nsAutoOwningThread _mOwningThread; +#define NS_ASSERT_OWNINGTHREAD(_class) \ + NS_CheckThreadSafe(_mOwningThread.GetThread(), #_class " not thread-safe") + +#else // !(defined(NS_DEBUG)) + +#define NS_DECL_OWNINGTHREAD /* nothing */ +#define NS_ASSERT_OWNINGTHREAD(_class) ((void)0) + +#endif // !(defined(NS_DEBUG)) + +class nsAutoRefCnt { + + public: + nsAutoRefCnt() : mValue(0) +#ifdef VBOX + , mState(0) +#endif + {} + nsAutoRefCnt(nsrefcnt aValue) : mValue(aValue) {} + + // only support prefix increment/decrement + nsrefcnt operator++() { return ++mValue; } + nsrefcnt operator--() { return --mValue; } + + nsrefcnt operator=(nsrefcnt aValue) { return (mValue = aValue); } + operator nsrefcnt() const { return mValue; } + nsrefcnt get() const { return mValue; } +#ifdef VBOX + nsrefcnt *ref() { return &mValue; } + PRUint32 getState() const { return mState; } + PRUint32 *refState() { return &mState; } +#endif + private: + // do not define these to enforce the faster prefix notation + nsrefcnt operator++(int); + nsrefcnt operator--(int); + nsrefcnt mValue; +#ifdef VBOX + PRUint32 mState; +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Declare the reference count variable and the implementations of the + * AddRef and QueryInterface methods. + */ + +#define NS_DECL_ISUPPORTS \ +public: \ + NS_IMETHOD QueryInterface(REFNSIID aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ +protected: \ + nsAutoRefCnt mRefCnt; \ + NS_DECL_OWNINGTHREAD \ +public: + + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Previously used to initialize the reference count, but no longer needed. + * + * DEPRECATED. + */ +#define NS_INIT_ISUPPORTS() ((void)0) + +/** + * Use this macro to implement the AddRef method for a given _class + * @param _class The name of the class implementing the method + */ +#define NS_IMPL_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + ++mRefCnt; \ + NS_LOG_ADDREF(this, mRefCnt, #_class, sizeof(*this)); \ + return mRefCnt; \ +} + +/** + * Use this macro to implement the AddRef method for a given _class + * implemented as a wholly owned aggregated object intended to implement + * interface(s) for its owner + * @param _class The name of the class implementing the method + * @param _aggregator the owning/containing object + */ +#define NS_IMPL_ADDREF_USING_AGGREGATOR(_class, _aggregator) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(_aggregator, "null aggregator"); \ + return (_aggregator)->AddRef(); \ +} + +/** + * Use this macro to implement the Release method for a given + * _class. + * @param _class The name of the class implementing the method + * @param _destroy A statement that is executed when the object's + * refcount drops to zero. + * + * For example, + * + * NS_IMPL_RELEASE_WITH_DESTROY(Foo, Destroy(this)) + * + * will cause + * + * Destroy(this); + * + * to be invoked when the object's refcount drops to zero. This + * allows for arbitrary teardown activity to occur (e.g., deallocation + * of object allocated with placement new). + */ +#define NS_IMPL_RELEASE_WITH_DESTROY(_class, _destroy) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + NS_ASSERT_OWNINGTHREAD(_class); \ + --mRefCnt; \ + NS_LOG_RELEASE(this, mRefCnt, #_class); \ + if (mRefCnt == 0) { \ + mRefCnt = 1; /* stabilize */ \ + _destroy; \ + return 0; \ + } \ + return mRefCnt; \ +} + +/** + * Use this macro to implement the Release method for a given _class + * @param _class The name of the class implementing the method + * + * A note on the 'stabilization' of the refcnt to one. At that point, + * the object's refcount will have gone to zero. The object's + * destructor may trigger code that attempts to QueryInterface() and + * Release() 'this' again. Doing so will temporarily increment and + * decrement the refcount. (Only a logic error would make one try to + * keep a permanent hold on 'this'.) To prevent re-entering the + * destructor, we make sure that no balanced refcounting can return + * the refcount to |0|. + */ +#define NS_IMPL_RELEASE(_class) \ + NS_IMPL_RELEASE_WITH_DESTROY(_class, NS_DELETEXPCOM(this)) + +/** + * Use this macro to implement the Release method for a given _class + * implemented as a wholly owned aggregated object intended to implement + * interface(s) for its owner + * @param _class The name of the class implementing the method + * @param _aggregator the owning/containing object + */ +#define NS_IMPL_RELEASE_USING_AGGREGATOR(_class, _aggregator) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(_aggregator, "null aggregator"); \ + return (_aggregator)->Release(); \ +} + + + +/////////////////////////////////////////////////////////////////////////////// + +/* + * Some convenience macros for implementing QueryInterface + */ + +/** + * This implements query interface with two assumptions: First, the + * class in question implements nsISupports and its own interface and + * nothing else. Second, the implementation of the class's primary + * inheritance chain leads to its own interface. + * + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ + +#define NS_IMPL_QUERY_HEAD(_class) \ +NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, \ + "QueryInterface requires a non-NULL destination!"); \ + nsISupports* foundInterface; + +#define NS_IMPL_QUERY_BODY(_interface) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, this); \ + else + +#define NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) \ + if ( (condition) && aIID.Equals(NS_GET_IID(_interface))) \ + foundInterface = NS_STATIC_CAST(_interface*, this); \ + else + +#define NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, \ + NS_STATIC_CAST(_implClass*, this)); \ + else + +#define NS_IMPL_QUERY_BODY_AGGREGATED(_interface, _aggregate) \ + if ( aIID.Equals(NS_GET_IID(_interface)) ) \ + foundInterface = NS_STATIC_CAST(_interface*, _aggregate); \ + else + +#define NS_IMPL_QUERY_TAIL_GUTS \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) \ + status = NS_NOINTERFACE; \ + else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL_INHERITING(_baseclass) \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) \ + status = _baseclass::QueryInterface(aIID, (void**)&foundInterface); \ + else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) \ + foundInterface = 0; \ + nsresult status; \ + if ( !foundInterface ) { \ + NS_ASSERTION(_aggregator, "null aggregator"); \ + status = _aggregator->QueryInterface(aIID, (void**)&foundInterface); \ + } else \ + { \ + NS_ADDREF(foundInterface); \ + status = NS_OK; \ + } \ + *aInstancePtr = foundInterface; \ + return status; \ +} + +#define NS_IMPL_QUERY_TAIL(_supports_interface) \ + NS_IMPL_QUERY_BODY_AMBIGUOUS(nsISupports, _supports_interface) \ + NS_IMPL_QUERY_TAIL_GUTS + + + /* + This is the new scheme. Using this notation now will allow us to switch to + a table driven mechanism when it's ready. Note the difference between this + and the (currently) underlying NS_IMPL_QUERY_INTERFACE mechanism. You must + explicitly mention |nsISupports| when using the interface maps. + */ +#define NS_INTERFACE_MAP_BEGIN(_implClass) NS_IMPL_QUERY_HEAD(_implClass) +#define NS_INTERFACE_MAP_ENTRY(_interface) NS_IMPL_QUERY_BODY(_interface) +#define NS_INTERFACE_MAP_ENTRY_CONDITIONAL(_interface, condition) \ + NS_IMPL_QUERY_BODY_CONDITIONAL(_interface, condition) +#define NS_INTERFACE_MAP_ENTRY_AGGREGATED(_interface,_aggregate) \ + NS_IMPL_QUERY_BODY_AGGREGATED(_interface,_aggregate) + +#define NS_INTERFACE_MAP_END NS_IMPL_QUERY_TAIL_GUTS +#define NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(_interface, _implClass) \ + NS_IMPL_QUERY_BODY_AMBIGUOUS(_interface, _implClass) +#define NS_INTERFACE_MAP_END_INHERITING(_baseClass) \ + NS_IMPL_QUERY_TAIL_INHERITING(_baseClass) +#define NS_INTERFACE_MAP_END_AGGREGATED(_aggregator) \ + NS_IMPL_QUERY_TAIL_USING_AGGREGATOR(_aggregator) + +#define NS_IMPL_QUERY_INTERFACE0(_class) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(nsISupports) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE1(_class, _i1) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE2(_class, _i1, _i2) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE3(_class, _i1, _i2, _i3) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY(_i11) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_INTERFACE_MAP_END + + +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE0 NS_IMPL_QUERY_INTERFACE0 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE1 NS_IMPL_QUERY_INTERFACE1 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE2 NS_IMPL_QUERY_INTERFACE2 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE3 NS_IMPL_QUERY_INTERFACE3 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE4 NS_IMPL_QUERY_INTERFACE4 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE5 NS_IMPL_QUERY_INTERFACE5 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE6 NS_IMPL_QUERY_INTERFACE6 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE7 NS_IMPL_QUERY_INTERFACE7 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE8 NS_IMPL_QUERY_INTERFACE8 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE9 NS_IMPL_QUERY_INTERFACE9 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE10 NS_IMPL_QUERY_INTERFACE10 +#define NS_IMPL_THREADSAFE_QUERY_INTERFACE11 NS_IMPL_QUERY_INTERFACE11 + +/** + * Declare that you're going to inherit from something that already + * implements nsISupports, but also implements an additional interface, thus + * causing an ambiguity. In this case you don't need another mRefCnt, you + * just need to forward the definitions to the appropriate superclass. E.g. + * + * class Bar : public Foo, public nsIBar { // both provide nsISupports + * public: + * NS_DECL_ISUPPORTS_INHERITED + * ...other nsIBar and Bar methods... + * }; + */ +#define NS_DECL_ISUPPORTS_INHERITED \ +public: \ + NS_IMETHOD QueryInterface(REFNSIID aIID, \ + void** aInstancePtr); \ + NS_IMETHOD_(nsrefcnt) AddRef(void); \ + NS_IMETHOD_(nsrefcnt) Release(void); \ + +/** + * These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED + * to implement the nsISupports methods, forwarding the invocations to a + * superclass that already implements nsISupports. + * + * Note that I didn't make these inlined because they're virtual methods. + */ + +#define NS_IMPL_ADDREF_INHERITED(Class, Super) \ +NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \ +{ \ + return Super::AddRef(); \ +} \ + +#define NS_IMPL_RELEASE_INHERITED(Class, Super) \ +NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \ +{ \ + return Super::Release(); \ +} \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED1(Class, Super, i1) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED5(Class,Super,i1,i2,i3,i4,i5) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +#define NS_IMPL_QUERY_INTERFACE_INHERITED6(Class,Super,i1,i2,i3,i4,i5,i6) \ + NS_IMPL_QUERY_HEAD(Class) \ + NS_IMPL_QUERY_BODY(i1) \ + NS_IMPL_QUERY_BODY(i2) \ + NS_IMPL_QUERY_BODY(i3) \ + NS_IMPL_QUERY_BODY(i4) \ + NS_IMPL_QUERY_BODY(i5) \ + NS_IMPL_QUERY_BODY(i6) \ + NS_IMPL_QUERY_TAIL_INHERITING(Super) \ + +/** + * Convenience macros for implementing all nsISupports methods for + * a simple class. + * @param _class The name of the class implementing the method + * @param _classiiddef The name of the #define symbol that defines the IID + * for the class (e.g. NS_ISUPPORTS_IID) + */ + +#define NS_IMPL_ISUPPORTS0(_class) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE0(_class) + +#define NS_IMPL_ISUPPORTS1(_class, _interface) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE1(_class, _interface) + +#define NS_IMPL_ISUPPORTS2(_class, _i1, _i2) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE2(_class, _i1, _i2) + +#define NS_IMPL_ISUPPORTS3(_class, _i1, _i2, _i3) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE3(_class, _i1, _i2, _i3) + +#define NS_IMPL_ISUPPORTS4(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_ISUPPORTS5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_ISUPPORTS6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_ISUPPORTS7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) + +#define NS_IMPL_ISUPPORTS8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) + +#define NS_IMPL_ISUPPORTS9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9) + +#define NS_IMPL_ISUPPORTS10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10) + +#define NS_IMPL_ISUPPORTS11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, \ + _i9, _i10, _i11) + +#define NS_IMPL_ISUPPORTS_INHERITED0(Class, Super) \ + NS_IMPL_QUERY_INTERFACE_INHERITED0(Class, Super) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED1(Class, Super, i1) \ + NS_IMPL_QUERY_INTERFACE_INHERITED1(Class, Super, i1) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_QUERY_INTERFACE_INHERITED2(Class, Super, i1, i2) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_QUERY_INTERFACE_INHERITED3(Class, Super, i1, i2, i3) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_QUERY_INTERFACE_INHERITED4(Class, Super, i1, i2, i3, i4) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED5(Class, Super, i1, i2, i3, i4, i5) \ + NS_IMPL_QUERY_INTERFACE_INHERITED5(Class, Super, i1, i2, i3, i4, i5) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +#define NS_IMPL_ISUPPORTS_INHERITED6(Class, Super, i1, i2, i3, i4, i5, i6) \ + NS_IMPL_QUERY_INTERFACE_INHERITED6(Class, Super, i1, i2, i3, i4, i5, i6) \ + NS_IMPL_ADDREF_INHERITED(Class, Super) \ + NS_IMPL_RELEASE_INHERITED(Class, Super) \ + +/////////////////////////////////////////////////////////////////////////////// +/** + * + * Threadsafe implementations of the ISupports convenience macros + * + */ + +/** + * Use this macro to implement the AddRef method for a given _class + * @param _class The name of the class implementing the method + */ + +#ifdef VBOX +#define NS_IMPL_THREADSAFE_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + nsrefcnt count = mRefCnt.get(); \ + PRUint32 state = mRefCnt.getState(); \ + AssertReleaseMsg( state <= 1 \ + && ( (state == 0 && count == 0) \ + || (state == 1 && count < PR_UINT32_MAX/2)), \ + ("AddRef: illegal refcnt=%u state=%d\n", count, state)); \ + switch (state) \ + { \ + case 0: \ + if (!ASMAtomicCmpXchgU32(mRefCnt.refState(), 1, 0)) \ + AssertReleaseMsgFailed(("AddRef: racing for first increment\n")); \ + count = ASMAtomicIncU32(mRefCnt.ref()); \ + AssertReleaseMsg(count == 1, \ + ("AddRef: unexpected refcnt=%u\n", count)); \ + break; \ + case 1: \ + count = ASMAtomicIncU32(mRefCnt.ref()); \ + AssertReleaseMsg(count <= PR_UINT32_MAX/2, \ + ("AddRef: unexpected refcnt=%u\n", count)); \ + break; \ + case 2: \ + AssertReleaseMsgFailed(("AddRef: freed object\n")); \ + break; \ + default: \ + AssertReleaseMsgFailed(("AddRef: garbage object\n")); \ + } \ + NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ + return count; \ +} +#else +#define NS_IMPL_THREADSAFE_ADDREF(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \ +{ \ + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \ + nsrefcnt count; \ + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); \ + NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \ + return count; \ +} +#endif + +/** + * Use this macro to implement the Release method for a given _class + * @param _class The name of the class implementing the method + */ + +#ifdef VBOX +#define NS_IMPL_THREADSAFE_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + nsrefcnt count = mRefCnt.get(); \ + PRUint32 state = mRefCnt.getState(); \ + AssertReleaseMsg(state == 1 && count <= PR_UINT32_MAX/2, \ + ("Release: illegal refcnt=%u state=%d\n", count, state)); \ + switch (state) \ + { \ + case 0: \ + AssertReleaseMsgFailed(("Release: new object\n")); \ + break; \ + case 1: \ + count = ASMAtomicDecU32(mRefCnt.ref()); \ + AssertReleaseMsg(count < PR_UINT32_MAX/2, \ + ("Release: unexpected refcnt=%u\n", count)); \ + if (count == 0) \ + { \ + if (!ASMAtomicCmpXchgU32(mRefCnt.refState(), 2, 1)) \ + AssertReleaseMsgFailed(("Release: racing for state free\n")); \ + /* Use better stabilization: reserve everything with top bit set. */ \ + if (!ASMAtomicCmpXchgU32(mRefCnt.ref(), PR_UINT32_MAX/4*3, 0)) \ + AssertReleaseMsgFailed(("Release: racing for refcnt stabilize\n")); \ + NS_DELETEXPCOM(this); \ + } \ + break; \ + case 2: \ + AssertReleaseMsgFailed(("Release: freed object\n")); \ + break; \ + default: \ + AssertReleaseMsgFailed(("Release: garbage object\n")); \ + } \ + NS_LOG_RELEASE(this, count, #_class); \ + return count; \ +} +#else +#define NS_IMPL_THREADSAFE_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + nsrefcnt count; \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \ + NS_LOG_RELEASE(this, count, #_class); \ + if (0 == count) { \ + mRefCnt = 1; /* stabilize */ \ + /* enable this to find non-threadsafe destructors: */ \ + /* NS_ASSERT_OWNINGTHREAD(_class); */ \ + NS_DELETEXPCOM(this); \ + return 0; \ + } \ + return count; \ +} +#endif + +#define NS_IMPL_THREADSAFE_ISUPPORTS0(_class) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE0(_class) + +#define NS_IMPL_THREADSAFE_ISUPPORTS1(_class, _interface) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE1(_class, _interface) + +#define NS_IMPL_THREADSAFE_ISUPPORTS2(_class, _i1, _i2) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE2(_class, _i1, _i2) + +#define NS_IMPL_THREADSAFE_ISUPPORTS3(_class, _i1, _i2, _i3) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE3(_class, _i1, _i2, _i3) + +#define NS_IMPL_THREADSAFE_ISUPPORTS4(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_THREADSAFE_ISUPPORTS5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_THREADSAFE_ISUPPORTS6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_THREADSAFE_ISUPPORTS7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) + +#define NS_IMPL_THREADSAFE_ISUPPORTS8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) + +#define NS_IMPL_THREADSAFE_ISUPPORTS9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) + +#define NS_IMPL_THREADSAFE_ISUPPORTS10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) + +#define NS_IMPL_THREADSAFE_ISUPPORTS11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_IMPL_THREADSAFE_ADDREF(_class) \ + NS_IMPL_THREADSAFE_RELEASE(_class) \ + NS_IMPL_THREADSAFE_QUERY_INTERFACE11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) + +/////////////////////////////////////////////////////////////////////////////// +// Macros for implementing nsIClassInfo-related stuff. +/////////////////////////////////////////////////////////////////////////////// + +// include here instead of at the top because it requires the nsISupport decl +#include "nsIClassInfo.h" + +#define NS_CLASSINFO_NAME(_class) _class##_classInfoGlobal +#define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper + +#define NS_DECL_CI_INTERFACE_GETTER(_class) \ + extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)(PRUint32 *, \ + nsIID ***); + +#define NS_DECL_CLASSINFO(_class) \ + NS_DECL_CI_INTERFACE_GETTER(_class) \ + nsIClassInfo *NS_CLASSINFO_NAME(_class); + +#define NS_IMPL_QUERY_CLASSINFO(_class) \ + if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) { \ + extern nsIClassInfo *NS_CLASSINFO_NAME(_class); \ + foundInterface = NS_STATIC_CAST(nsIClassInfo*, NS_CLASSINFO_NAME(_class));\ + } else + +#define NS_CLASSINFO_HELPER_BEGIN(_class, _c) \ +NS_IMETHODIMP \ +NS_CI_INTERFACE_GETTER_NAME(_class)(PRUint32 *count, nsIID ***array) \ +{ \ + *count = _c; \ + *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c); + +#define NS_CLASSINFO_HELPER_ENTRY(_i, _interface) \ + (*array)[_i] = (nsIID *)nsMemory::Clone(&NS_GET_IID(_interface), \ + sizeof(nsIID)); + +#define NS_CLASSINFO_HELPER_END \ + return NS_OK; \ +} + +#define NS_IMPL_CI_INTERFACE_GETTER1(_class, _interface) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 1) \ + NS_CLASSINFO_HELPER_ENTRY(0, _interface) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE1_CI(_class, _i1) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS1_CI(_class, _interface) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE1_CI(_class, _interface) \ + NS_IMPL_CI_INTERFACE_GETTER1(_class, _interface) + +#define NS_IMPL_CI_INTERFACE_GETTER2(_class, _i1, _i2) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 2) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE2_CI(_class, _i1, _i2) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS2_CI(_class, _i1, _i2) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE2_CI(_class, _i1, _i2) \ + NS_IMPL_CI_INTERFACE_GETTER2(_class, _i1, _i2) + +#define NS_IMPL_CI_INTERFACE_GETTER3(_class, _i1, _i2, _i3) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 3) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE3_CI(_class, _i1, _i2, _i3) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS3_CI(_class, _i1, _i2, _i3) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE3_CI(_class, _i1, _i2, _i3) \ + NS_IMPL_CI_INTERFACE_GETTER3(_class, _i1, _i2, _i3) + +#define NS_IMPL_CI_INTERFACE_GETTER4(_class, _i1, _i2, _i3, _i4) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 4) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE4_CI(_class, _i1, _i2, _i3, _i4) \ + NS_IMPL_CI_INTERFACE_GETTER4(_class, _i1, _i2, _i3, _i4) + +#define NS_IMPL_CI_INTERFACE_GETTER5(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 5) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE5_CI(_class, _i1, _i2, _i3, _i4, _i5) \ + NS_IMPL_CI_INTERFACE_GETTER5(_class, _i1, _i2, _i3, _i4, _i5) + +#define NS_IMPL_CI_INTERFACE_GETTER6(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 6) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE6_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6) \ + NS_IMPL_CI_INTERFACE_GETTER6(_class, _i1, _i2, _i3, _i4, _i5, _i6) + +#define NS_IMPL_CI_INTERFACE_GETTER7(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 7) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE7_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) \ + NS_IMPL_CI_INTERFACE_GETTER7(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7) + +#define NS_IMPL_CI_INTERFACE_GETTER8(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 8) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE8_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) \ + NS_IMPL_CI_INTERFACE_GETTER8(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8) + +#define NS_IMPL_CI_INTERFACE_GETTER9(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 9) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE9_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) \ + NS_IMPL_CI_INTERFACE_GETTER9(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9) + +#define NS_IMPL_CI_INTERFACE_GETTER10(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 10) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_ENTRY(9, _i10) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_CI_INTERFACE_GETTER11(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_CLASSINFO_HELPER_BEGIN(_class, 10) \ + NS_CLASSINFO_HELPER_ENTRY(0, _i1) \ + NS_CLASSINFO_HELPER_ENTRY(1, _i2) \ + NS_CLASSINFO_HELPER_ENTRY(2, _i3) \ + NS_CLASSINFO_HELPER_ENTRY(3, _i4) \ + NS_CLASSINFO_HELPER_ENTRY(4, _i5) \ + NS_CLASSINFO_HELPER_ENTRY(5, _i6) \ + NS_CLASSINFO_HELPER_ENTRY(6, _i7) \ + NS_CLASSINFO_HELPER_ENTRY(7, _i8) \ + NS_CLASSINFO_HELPER_ENTRY(8, _i9) \ + NS_CLASSINFO_HELPER_ENTRY(9, _i10) \ + NS_CLASSINFO_HELPER_ENTRY(10, _i11) \ + NS_CLASSINFO_HELPER_END + +#define NS_IMPL_QUERY_INTERFACE10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_QUERY_INTERFACE11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, \ + _i7, _i8, _i9, _i10, _i11) \ + NS_INTERFACE_MAP_BEGIN(_class) \ + NS_INTERFACE_MAP_ENTRY(_i1) \ + NS_INTERFACE_MAP_ENTRY(_i2) \ + NS_INTERFACE_MAP_ENTRY(_i3) \ + NS_INTERFACE_MAP_ENTRY(_i4) \ + NS_INTERFACE_MAP_ENTRY(_i5) \ + NS_INTERFACE_MAP_ENTRY(_i6) \ + NS_INTERFACE_MAP_ENTRY(_i7) \ + NS_INTERFACE_MAP_ENTRY(_i8) \ + NS_INTERFACE_MAP_ENTRY(_i9) \ + NS_INTERFACE_MAP_ENTRY(_i10) \ + NS_INTERFACE_MAP_ENTRY(_i11) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, _i1) \ + NS_IMPL_QUERY_CLASSINFO(_class) \ + NS_INTERFACE_MAP_END + +#define NS_IMPL_ISUPPORTS10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE10_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) \ + NS_IMPL_CI_INTERFACE_GETTER10(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10) + +#define NS_IMPL_ISUPPORTS11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) \ + NS_IMPL_ADDREF(_class) \ + NS_IMPL_RELEASE(_class) \ + NS_IMPL_QUERY_INTERFACE11_CI(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) \ + NS_IMPL_CI_INTERFACE_GETTER11(_class, _i1, _i2, _i3, _i4, _i5, _i6, _i7, \ + _i8, _i9, _i10, _i11) + +#define NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_QUERY_TAIL_GUTS + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h new file mode 100644 index 00000000..d8d002b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsISupportsUtils.h @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Scott Collins + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsISupportsUtils_h__ +#define nsISupportsUtils_h__ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsISupportsBase_h__ +#include "nsISupportsBase.h" +#endif + +#ifndef nsError_h__ +#include "nsError.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + +#ifndef nsISupportsImpl_h__ +#include "nsISupportsImpl.h" +#endif + +/** + * Macro for instantiating a new object that implements nsISupports. + * Note that you can only use this if you adhere to the no arguments + * constructor com policy (which you really should!). + * @param _result Where the new instance pointer is stored + * @param _type The type of object to call "new" with. + */ +#define NS_NEWXPCOM(_result,_type) \ + PR_BEGIN_MACRO \ + _result = new _type(); \ + PR_END_MACRO + +/** + * Macro for deleting an object that implements nsISupports. + * @param _ptr The object to delete. + */ +#define NS_DELETEXPCOM(_ptr) \ + PR_BEGIN_MACRO \ + delete (_ptr); \ + PR_END_MACRO + +/** + * Macro for adding a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_ADDREF(_ptr) \ + (_ptr)->AddRef() + +/** + * Macro for adding a reference to this. This macro should be used + * because NS_ADDREF (when tracing) may require an ambiguous cast + * from the pointers primary type to nsISupports. This macro sidesteps + * that entire problem. + */ +#define NS_ADDREF_THIS() \ + AddRef() + + +extern "C++" { +// ...because some one is accidentally including this file inside +// an |extern "C"| + + +// Making this a |inline| |template| allows |expr| to be evaluated only once, +// yet still denies you the ability to |AddRef()| an |nsCOMPtr|. +template +inline +nsrefcnt +ns_if_addref( T expr ) +{ + return expr ? expr->AddRef() : 0; +} + +} /* extern "C++" */ + +/** + * Macro for adding a reference to an interface that checks for NULL. + * @param _expr The interface pointer. + */ +#define NS_IF_ADDREF(_expr) ns_if_addref(_expr) + +/* + * Given these declarations, it explicitly OK and efficient to end a `getter' with: + * + * NS_IF_ADDREF(*result = mThing); + * + * even if |mThing| is an |nsCOMPtr|. If |mThing| is an |nsCOMPtr|, however, it is still + * _illegal_ to say |NS_IF_ADDREF(mThing)|. + */ + +/** + * Macro for releasing a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_RELEASE(_ptr) \ + PR_BEGIN_MACRO \ + (_ptr)->Release(); \ + (_ptr) = 0; \ + PR_END_MACRO + +/** + * Macro for releasing a reference to an interface. + * @param _ptr The interface pointer. + */ +#define NS_RELEASE_THIS() \ + Release() + +/** + * Macro for releasing a reference to an interface, except that this + * macro preserves the return value from the underlying Release call. + * The interface pointer argument will only be NULLed if the reference count + * goes to zero. + * + * @param _ptr The interface pointer. + */ +#define NS_RELEASE2(_ptr,_rv) \ + PR_BEGIN_MACRO \ + _rv = (_ptr)->Release(); \ + if (0 == (_rv)) (_ptr) = 0; \ + PR_END_MACRO + +/** + * Macro for releasing a reference to an interface that checks for NULL; + * @param _ptr The interface pointer. + */ +#define NS_IF_RELEASE(_ptr) \ + PR_BEGIN_MACRO \ + if (_ptr) { \ + (_ptr)->Release(); \ + (_ptr) = 0; \ + } \ + PR_END_MACRO + +/* + * Often you have to cast an implementation pointer, e.g., |this|, to an + * |nsISupports*|, but because you have multiple inheritance, a simple cast + * is ambiguous. One could simply say, e.g., (given a base |nsIBase|), + * |NS_STATIC_CAST(nsIBase*, this)|; but that disguises the fact that what + * you are really doing is disambiguating the |nsISupports|. You could make + * that more obvious with a double cast, e.g., |NS_STATIC_CAST(nsISupports*, + * NS_STATIC_CAST(nsIBase*, this))|, but that is bulky and harder to read... + * + * The following macro is clean, short, and obvious. In the example above, + * you would use it like this: |NS_ISUPPORTS_CAST(nsIBase*, this)|. + */ + +#define NS_ISUPPORTS_CAST(__unambiguousBase, __expr) \ + NS_STATIC_CAST(nsISupports*, NS_STATIC_CAST(__unambiguousBase, __expr)) + +extern "C++" { +// ...because some one is accidentally including this file inside +// an |extern "C"| + +class nsISupports; + +template +struct nsCOMTypeInfo +{ + static const nsIID& GetIID() { return T::GetIID(); } +}; + +NS_SPECIALIZE_TEMPLATE +struct nsCOMTypeInfo +{ + static const nsIID& GetIID() { + static const nsIID iid_NS_ISUPPORTS_IID = NS_ISUPPORTS_IID; return iid_NS_ISUPPORTS_IID; + } +}; + +#define NS_GET_IID(T) nsCOMTypeInfo::GetIID() + +// a type-safe shortcut for calling the |QueryInterface()| member function +template +inline +nsresult +CallQueryInterface( T* aSource, DestinationType** aDestination ) +{ + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->QueryInterface(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +} // extern "C++" + +#endif /* __nsISupportsUtils_h */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h new file mode 100644 index 00000000..17d1bd79 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsIWeakReferenceUtils.h @@ -0,0 +1,162 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIWeakReferenceUtils_h__ +#define nsIWeakReferenceUtils_h__ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +typedef nsCOMPtr nsWeakPtr; + +/** + * + */ + +// a type-safe shortcut for calling the |QueryReferent()| member function +// T must inherit from nsIWeakReference, but the cast may be ambiguous. +template +inline +nsresult +CallQueryReferent( T* aSource, DestinationType** aDestination ) + { + NS_PRECONDITION(aSource, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return aSource->QueryReferent(NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); + } + + +class NS_COM nsQueryReferent : public nsCOMPtr_helper + { + public: + nsQueryReferent( nsIWeakReference* aWeakPtr, nsresult* error ) + : mWeakPtr(aWeakPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** ) const; + + private: + nsIWeakReference* mWeakPtr; + nsresult* mErrorPtr; + }; + +inline +const nsQueryReferent +do_QueryReferent( nsIWeakReference* aRawPtr, nsresult* error = 0 ) + { + return nsQueryReferent(aRawPtr, error); + } + + + +class NS_COM nsGetWeakReference : public nsCOMPtr_helper + { + public: + nsGetWeakReference( nsISupports* aRawPtr, nsresult* error ) + : mRawPtr(aRawPtr), + mErrorPtr(error) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + nsISupports* mRawPtr; + nsresult* mErrorPtr; + }; + + /** + * |do_GetWeakReference| is a convenience function that bundles up all the work needed + * to get a weak reference to an arbitrary object, i.e., the |QueryInterface|, test, and + * call through to |GetWeakReference|, and put it into your |nsCOMPtr|. + * It is specifically designed to cooperate with |nsCOMPtr| (or |nsWeakPtr|) like so: + * |nsWeakPtr myWeakPtr = do_GetWeakReference(aPtr);|. + */ +inline +const nsGetWeakReference +do_GetWeakReference( nsISupports* aRawPtr, nsresult* error = 0 ) + { + return nsGetWeakReference(aRawPtr, error); + } + +inline +void +do_GetWeakReference( nsIWeakReference* aRawPtr, nsresult* error = 0 ) + { + // This signature exists soley to _stop_ you from doing a bad thing. + // Saying |do_GetWeakReference()| on a weak reference itself, + // is very likely to be a programmer error. + } + +template +inline +void +do_GetWeakReference( already_AddRefed& ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_GetWeakReference()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + +template +inline +void +do_GetWeakReference( already_AddRefed&, nsresult* ) + { + // This signature exists soley to _stop_ you from doing the bad thing. + // Saying |do_GetWeakReference()| on a pointer that is not otherwise owned by + // someone else is an automatic leak. See . + } + + + + /** + * Deprecated, use |do_GetWeakReference| instead. + */ +extern NS_COM +nsIWeakReference* +NS_GetWeakReference( nsISupports* , nsresult* aResult=0 ); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp b/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp new file mode 100644 index 00000000..2449c58e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsMemory.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsMemory.h" +#include "nsXPCOMPrivate.h" + +static nsIMemory* gMemory = nsnull; + +static NS_METHOD FreeGlobalMemory(void) +{ + NS_ASSERTION(gMemory, "must be not null after SetupGlobalMemory"); + NS_IF_RELEASE(gMemory); + return NS_OK; +} + +#define ENSURE_ALLOCATOR \ + (gMemory ? PR_TRUE : (PRBool)(SetupGlobalMemory() != nsnull)) + +static nsIMemory* +SetupGlobalMemory() +{ + NS_ASSERTION(!gMemory, "must be called once"); + if (!gMemory) + { + NS_GetMemoryManager(&gMemory); + NS_ASSERTION(gMemory, "can't get memory manager!"); + if (gMemory) + NS_RegisterXPCOMExitRoutine(FreeGlobalMemory, 0); + } + return gMemory; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupMemory() +{ + NS_ASSERTION(!gMemory, "must be called once"); + if (!gMemory) + { + NS_GetMemoryManager(&gMemory); + NS_ASSERTION(gMemory, "can't get memory manager!"); + if (!gMemory) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +void GlueShutdownMemory() +{ + NS_IF_RELEASE(gMemory); +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// nsMemory static helper routines + +NS_COM void* +nsMemory::Alloc(PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + return gMemory->Alloc(size); +} + +NS_COM void* +nsMemory::Realloc(void* ptr, PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + return gMemory->Realloc(ptr, size); +} + +NS_COM void +nsMemory::Free(void* ptr) +{ + if (!ENSURE_ALLOCATOR) + return; + + gMemory->Free(ptr); +} + +NS_COM nsresult +nsMemory::HeapMinimize(PRBool aImmediate) +{ + if (!ENSURE_ALLOCATOR) + return NS_ERROR_FAILURE; + + return gMemory->HeapMinimize(aImmediate); +} + +NS_COM void* +nsMemory::Clone(const void* ptr, PRSize size) +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + void* newPtr = gMemory->Alloc(size); + if (newPtr) + memcpy(newPtr, ptr, size); + return newPtr; +} + +NS_COM nsIMemory* +nsMemory::GetGlobalMemoryService() +{ + if (!ENSURE_ALLOCATOR) + return nsnull; + + nsIMemory* result = gMemory; + NS_IF_ADDREF(result); + return result; +} + +//---------------------------------------------------------------------- + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsMemory.h b/src/libs/xpcom18a4/xpcom/glue/nsMemory.h new file mode 100644 index 00000000..4ee48bf0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsMemory.h @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsMemory_h__ +#define nsMemory_h__ + +#include "nsIMemory.h" + +#define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" +#define NS_MEMORY_CLASSNAME "Global Memory Service" +#define NS_MEMORY_CID \ +{ /* 30a04e40-38e7-11d4-8cf5-0060b0fc14a3 */ \ + 0x30a04e40, \ + 0x38e7, \ + 0x11d4, \ + {0x8c, 0xf5, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \ +} + + +/** + * Static helper routines to manage memory. These routines allow easy access + * to xpcom's built-in (global) nsIMemory implementation, without needing + * to go through the service manager to get it. However this requires clients + * to link with the xpcom DLL. + * + * This class is not threadsafe and is intented for use only on the main + * thread. + */ +class nsMemory +{ +public: + static NS_COM void* Alloc(size_t size); + static NS_COM void* Realloc(void* ptr, size_t size); + static NS_COM void Free(void* ptr); + static NS_COM nsresult HeapMinimize(PRBool aImmediate); + static NS_COM void* Clone(const void* ptr, size_t size); + static NS_COM nsIMemory* GetGlobalMemoryService(); // AddRefs +}; + +/** + * Macro to free all elements of an XPCOM array of a given size using + * freeFunc, then frees the array itself using nsMemory::Free(). + * + * Note that this macro (and its wrappers) can be used to deallocate a + * partially- or completely-built array while unwinding an error + * condition inside the XPCOM routine that was going to return the + * array. For this to work on a partially-built array, your code + * needs to be building the array from index 0 upwards, and simply + * pass the number of elements that have already been built (and thus + * need to be freed) as |size|. + * + * Thanks to for suggesting this form, which + * allows the macro to be used with NS_RELEASE / NS_RELEASE_IF in + * addition to nsMemory::Free. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + * @param freeFunc The function or macro to be used to free it. + * For arrays of nsISupports (or any class derived + * from it), NS_IF_RELEASE (or NS_RELEASE) should be + * passed as freeFunc. For most (all?) other pointer + * types (including XPCOM strings and wstrings), + * nsMemory::Free should be used, since the + * shared-allocator (nsMemory) is what will have been + * used to allocate the memory. + */ +#define NS_FREE_XPCOM_POINTER_ARRAY(size, array, freeFunc) \ + PR_BEGIN_MACRO \ + PRInt32 iter_ = PRInt32(size); \ + while (--iter_ >= 0) \ + freeFunc((array)[iter_]); \ + nsMemory::Free((array)); \ + PR_END_MACRO + +// convenience macros for commonly used calls. mmmmm. syntactic sugar. + +/** + * Macro to free arrays of non-refcounted objects allocated by the + * shared allocator (nsMemory) such as strings and wstrings. A + * convenience wrapper around NS_FREE_XPCOM_POINTER_ARRAY. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), nsMemory::Free) + +/** + * Macro to free an array of pointers to nsISupports (or classes + * derived from it). A convenience wrapper around + * NS_FREE_XPCOM_POINTER_ARRAY. + * + * Note that if you know that none of your nsISupports pointers are + * going to be 0, you can gain a bit of speed by calling + * NS_FREE_XPCOM_POINTER_ARRAY directly and using NS_RELEASE as your + * free function. + * + * @param size Number of elements in the array. If not a constant, this + * should be a PRInt32. Note that this means this macro + * will not work if size >= 2^31. + * @param array The array to be freed. + */ +#define NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(size, array) \ + NS_FREE_XPCOM_POINTER_ARRAY((size), (array), NS_IF_RELEASE) + +/** + * Helpful array length function for calculating the length of a + * statically declared array. + */ + +#define NS_ARRAY_LENGTH(array_) \ + (sizeof(array_)/sizeof(array_[0])) + + +#endif // nsMemory_h__ + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h b/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h new file mode 100644 index 00000000..b225b6a2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsServiceManagerUtils.h @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIServiceManagerUtils_h__ +#define nsIServiceManagerUtils_h__ + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsCOMPtr.h" + +//////////////////////////////////////////////////////////////////////////// +// Using servicemanager with COMPtrs +class NS_COM nsGetServiceByCID : public nsCOMPtr_helper +{ + public: + nsGetServiceByCID( const nsCID& aCID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mCID(aCID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const nsCID& mCID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, 0, error); +} + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, aServiceManager, error); +} + +class NS_COM nsGetServiceByContractID : public nsCOMPtr_helper +{ + public: + nsGetServiceByContractID( const char* aContractID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mContractID(aContractID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const char* mContractID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, 0, error); +} + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, aServiceManager, error); +} + +class nsGetServiceFromCategory : public nsCOMPtr_helper +{ + public: + nsGetServiceFromCategory(const char* aCategory, const char* aEntry, + nsISupports* aServiceManager, + nsresult* aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + protected: + const char* mCategory; + const char* mEntry; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceFromCategory +do_GetServiceFromCategory( const char* category, const char* entry, + nsresult* error = 0) +{ + return nsGetServiceFromCategory(category, entry, 0, error); +} + +// type-safe shortcuts for calling |GetService| +template +inline +nsresult +CallGetService( const nsCID &aClass, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetServiceByContractID(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp new file mode 100644 index 00000000..14e9469b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.cpp @@ -0,0 +1,125 @@ +/* ***** 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsTraceRefcnt.h" +#include "nsTraceRefcntImpl.h" + +static nsITraceRefcnt* gTraceRefcntObject = nsnull; + +static NS_METHOD FreeTraceRefcntObject(void) +{ + NS_IF_RELEASE(gTraceRefcntObject); + return NS_OK; +} + +#define ENSURE_TRACEOBJECT \ + (gTraceRefcntObject || SetupTraceRefcntObject() != nsnull) + +static nsITraceRefcnt* SetupTraceRefcntObject() +{ + NS_GetTraceRefcnt(&gTraceRefcntObject); + if (gTraceRefcntObject) + NS_RegisterXPCOMExitRoutine(FreeTraceRefcntObject, 0); + return gTraceRefcntObject; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupTraceRefcnt() +{ + NS_GetTraceRefcnt(&gTraceRefcntObject); + if (!gTraceRefcntObject) + return NS_ERROR_FAILURE; + return NS_OK; +} + +void GlueShutdownTraceRefcnt() +{ + NS_IF_RELEASE(gTraceRefcntObject); +} +#endif + +NS_COM void +nsTraceRefcnt::LogAddRef(void * aPtr, nsrefcnt aNewRefcnt, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogAddRef(aPtr, aNewRefcnt, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogRelease(void * aPtr, nsrefcnt aNewRefcnt, const char *aTypeName) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogRelease(aPtr, aNewRefcnt, aTypeName); +} + +NS_COM void +nsTraceRefcnt::LogCtor(void * aPtr, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogCtor(aPtr, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogDtor(void * aPtr, const char *aTypeName, PRUint32 aInstanceSize) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogDtor(aPtr, aTypeName, aInstanceSize); +} + +NS_COM void +nsTraceRefcnt::LogAddCOMPtr(void * aPtr, nsISupports *aObject) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogAddCOMPtr(aPtr, aObject); +} + +NS_COM void +nsTraceRefcnt::LogReleaseCOMPtr(void * aPtr, nsISupports *aObject) +{ + if (!ENSURE_TRACEOBJECT) + return; + gTraceRefcntObject->LogReleaseCOMPtr(aPtr, aObject); +} + diff --git a/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h new file mode 100644 index 00000000..afafda4b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsTraceRefcnt.h @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsTraceRefcnt_h___ +#define nsTraceRefcnt_h___ + +#include "nscore.h" + +class nsISupports; + +// By default refcnt logging is not part of the build. +#undef NS_BUILD_REFCNT_LOGGING + +#if (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING)) +// Make refcnt logging part of the build. This doesn't mean that +// actual logging will occur (that requires a separate enable; see +// nsTraceRefcnt.h for more information). +#define NS_BUILD_REFCNT_LOGGING 1 +#endif + +// If NO_BUILD_REFCNT_LOGGING is defined then disable refcnt logging +// in the build. This overrides FORCE_BUILD_REFCNT_LOGGING. +#if defined(NO_BUILD_REFCNT_LOGGING) +#undef NS_BUILD_REFCNT_LOGGING +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + +#define NS_LOG_ADDREF(_p, _rc, _type, _size) \ + nsTraceRefcnt::LogAddRef((_p), (_rc), (_type), (PRUint32) (_size)) + +#define NS_LOG_RELEASE(_p, _rc, _type) \ + nsTraceRefcnt::LogRelease((_p), (_rc), (_type)) + +#define MOZ_DECL_CTOR_COUNTER(_type) + +#define MOZ_COUNT_CTOR(_type) \ +PR_BEGIN_MACRO \ + nsTraceRefcnt::LogCtor((void*)this, #_type, sizeof(*this)); \ +PR_END_MACRO + +#define MOZ_COUNT_DTOR(_type) \ +PR_BEGIN_MACRO \ + nsTraceRefcnt::LogDtor((void*)this, #_type, sizeof(*this)); \ +PR_END_MACRO + +#ifdef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR // from autoconf (XXX needs to be + // set for non-autoconf platforms) + +// nsCOMPtr.h allows these macros to be defined by clients +// These logging functions require dynamic_cast, so we don't +// define these macros if we don't have dynamic_cast. +#define NSCAP_LOG_ASSIGNMENT(_c, _p) \ + if (_p) \ + nsTraceRefcnt::LogAddCOMPtr((_c),NS_STATIC_CAST(nsISupports*,_p)) + +#define NSCAP_LOG_RELEASE(_c, _p) \ + if (_p) \ + nsTraceRefcnt::LogReleaseCOMPtr((_c), NS_STATIC_CAST(nsISupports*,_p)) + +#endif /* HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR */ + +#else /* !NS_BUILD_REFCNT_LOGGING */ + +#define NS_LOG_ADDREF(_p, _rc, _type, _size) +#define NS_LOG_RELEASE(_p, _rc, _type) +#define MOZ_DECL_CTOR_COUNTER(_type) +#define MOZ_COUNT_CTOR(_type) +#define MOZ_COUNT_DTOR(_type) + +#endif /* NS_BUILD_REFCNT_LOGGING */ + +//---------------------------------------------------------------------- + +/** + * Note: The implementations for these methods are no-ops in a build + * where NS_BUILD_REFCNT_LOGGING is disabled. + */ +class nsTraceRefcnt { +public: + static NS_COM void LogAddRef(void* aPtr, + nsrefcnt aNewRefCnt, + const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogRelease(void* aPtr, + nsrefcnt aNewRefCnt, + const char* aTypeName); + + static NS_COM void LogCtor(void* aPtr, const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogDtor(void* aPtr, const char* aTypeName, + PRUint32 aInstanceSize); + + static NS_COM void LogAddCOMPtr(void *aCOMPtr, nsISupports *aObject); + + static NS_COM void LogReleaseCOMPtr(void *aCOMPtr, nsISupports *aObject); + +}; +#endif /* nsTraceRefcnt_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp new file mode 100644 index 00000000..76d9f593 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.cpp @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// nsWeakReference.cpp + +#include "nsWeakReference.h" +#include "nsCOMPtr.h" + +nsresult +nsQueryReferent::operator()( const nsIID& aIID, void** answer ) const + { + nsresult status; + if ( mWeakPtr ) + { + if ( NS_FAILED(status = mWeakPtr->QueryReferent(aIID, answer)) ) + *answer = 0; + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + +nsresult +nsGetWeakReference::operator()( const nsIID&, void** aResult ) const + { + nsresult status; + // nsIWeakReference** result = &NS_STATIC_CAST(nsIWeakReference*, *aResult); + *aResult = 0; + + if ( mRawPtr ) + { + nsCOMPtr factoryPtr = do_QueryInterface(mRawPtr, &status); + NS_ASSERTION(factoryPtr, "Oops! You're asking for a weak reference to an object that doesn't support that."); + if ( factoryPtr ) + { + nsIWeakReference* temp; + status = factoryPtr->GetWeakReference(&temp); + *aResult = temp; + } + // else, |status| has already been set by |do_QueryInterface| + } + else + status = NS_ERROR_NULL_POINTER; + + if ( mErrorPtr ) + *mErrorPtr = status; + return status; + } + + +NS_COM nsIWeakReference* // or else |already_AddRefed| +NS_GetWeakReference( nsISupports* aInstancePtr, nsresult* aErrorPtr ) + { + void* result = 0; + nsGetWeakReference(aInstancePtr, aErrorPtr)(NS_GET_IID(nsIWeakReference), &result); + return NS_STATIC_CAST(nsIWeakReference*, result); + } + +NS_COM nsresult +nsSupportsWeakReference::GetWeakReference( nsIWeakReference** aInstancePtr ) + { + if ( !aInstancePtr ) + return NS_ERROR_NULL_POINTER; + + if ( !mProxy ) + mProxy = new nsWeakReference(this); + *aInstancePtr = mProxy; + + nsresult status; + if ( !*aInstancePtr ) + status = NS_ERROR_OUT_OF_MEMORY; + else + { + NS_ADDREF(*aInstancePtr); + status = NS_OK; + } + + return status; + } + +NS_IMETHODIMP_(nsrefcnt) +nsWeakReference::AddRef() + { + return ++mRefCount; + } + +NS_IMETHODIMP_(nsrefcnt) +nsWeakReference::Release() + { + nsrefcnt temp = --mRefCount; + if ( !mRefCount ) + delete this; + return temp; + } + +NS_IMETHODIMP +nsWeakReference::QueryInterface( const nsIID& aIID, void** aInstancePtr ) + { + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); + + if ( !aInstancePtr ) + return NS_ERROR_NULL_POINTER; + + nsISupports* foundInterface; + if ( aIID.Equals(NS_GET_IID(nsIWeakReference)) ) + foundInterface = NS_STATIC_CAST(nsIWeakReference*, this); + else if ( aIID.Equals(NS_GET_IID(nsISupports)) ) + foundInterface = NS_STATIC_CAST(nsISupports*, this); + else + foundInterface = 0; + + nsresult status; + if ( !foundInterface ) + status = NS_NOINTERFACE; + else + { + NS_ADDREF(foundInterface); + status = NS_OK; + } + + *aInstancePtr = foundInterface; + return status; + } + +NS_IMETHODIMP +nsWeakReference::QueryReferent( const nsIID& aIID, void** aInstancePtr ) + { + return mReferent ? mReferent->QueryInterface(aIID, aInstancePtr) : NS_ERROR_NULL_POINTER; + } diff --git a/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h new file mode 100644 index 00000000..96e63f22 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsWeakReference.h @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsWeakReference_h__ +#define nsWeakReference_h__ + +// nsWeakReference.h + +#include "nsIWeakReference.h" + +class nsWeakReference; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class NS_COM nsSupportsWeakReference : public nsISupportsWeakReference + { + public: + nsSupportsWeakReference() + : mProxy(0) + { + // nothing else to do here + } + + NS_DECL_NSISUPPORTSWEAKREFERENCE + + protected: + inline ~nsSupportsWeakReference(); + + private: + friend class nsWeakReference; + + void + NoticeProxyDestruction() + // ...called (only) by an |nsWeakReference| from _its_ dtor. + { + mProxy = 0; + } + + nsWeakReference* mProxy; + + protected: + + inline void ClearWeakReferences(); + PRBool HasWeakReferences() const {return mProxy != 0;} + }; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +class NS_COM nsWeakReference : public nsIWeakReference + { + public: + // nsISupports... + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + // nsIWeakReference... + NS_DECL_NSIWEAKREFERENCE + + private: + friend class nsSupportsWeakReference; + + nsWeakReference( nsSupportsWeakReference* referent ) + : mRefCount(0), + mReferent(referent) + // ...I can only be constructed by an |nsSupportsWeakReference| + { + // nothing else to do here + } + + ~nsWeakReference() + // ...I will only be destroyed by calling |delete| myself. + { + if ( mReferent ) + mReferent->NoticeProxyDestruction(); + } + + void + NoticeReferentDestruction() + // ...called (only) by an |nsSupportsWeakReference| from _its_ dtor. + { + mReferent = 0; + } + + nsrefcnt mRefCount; + nsSupportsWeakReference* mReferent; + }; + +inline +void +nsSupportsWeakReference::ClearWeakReferences() + /* + Usually being called from |nsSupportsWeakReference::~nsSupportsWeakReference| + will be good enough, but you may have a case where you need to call disconnect + your weak references in an outer destructor (to prevent some client holding a + weak reference from re-entering your destructor). + */ + { + if ( mProxy ) + { + mProxy->NoticeReferentDestruction(); + mProxy = 0; + } + } + +inline +nsSupportsWeakReference::~nsSupportsWeakReference() + { + ClearWeakReferences(); + } + +#endif diff --git a/src/libs/xpcom18a4/xpcom/glue/objs.mk b/src/libs/xpcom18a4/xpcom/glue/objs.mk new file mode 100644 index 00000000..d6d04a5a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/objs.mk @@ -0,0 +1,60 @@ +# ***** 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 mozilla.org. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# 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 ***** + +XPCOM_GLUE_SRC_LCSRCS = \ + nsCOMPtr.cpp \ + nsComponentManagerUtils.cpp \ + nsDebug.cpp \ + nsGenericFactory.cpp \ + nsIInterfaceRequestorUtils.cpp \ + nsMemory.cpp \ + nsTraceRefcnt.cpp \ + nsWeakReference.cpp \ + $(NULL) \ + +XPCOM_GLUE_SRC_LEXPORTS = \ + nsCOMPtr.h \ + nsDebug.h \ + nsGenericFactory.h \ + nsIGenericFactory.h \ + nsMemory.h \ + nsTraceRefcnt.h \ + nsWeakReference.h \ + $(NULL) + + + +XPCOM_GLUE_SRC_CSRCS := $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCSRCS)) diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore b/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore new file mode 100644 index 00000000..a0182c1f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/.cvsignore @@ -0,0 +1,8 @@ +Makefile +nsCOMPtr.cpp +nsDebug.cpp +nsGenericFactory.cpp +nsIInterfaceRequestorUtils.cpp +nsMemory.cpp +nsWeakReference.cpp +nsComponentManagerUtils.cpp diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in b/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in new file mode 100644 index 00000000..ae23d8e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/Makefile.in @@ -0,0 +1,88 @@ +# ***** 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 mozilla.org. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2002 +# 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk +include $(srcdir)/../objs.mk + +MODULE = xpcom +LIBRARY_NAME = xpcomglue + +REQUIRES = string \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../build \ + $(NULL) + +CPPSRCS = \ + $(XPCOM_GLUE_SRC_LCSRCS) \ + nsXPCOMGlue.cpp \ + nsGREDirServiceProvider.cpp \ + $(NULL) + +SDK_HEADERS = \ + nsXPCOMGlue.h \ + $(NULL) + +SDK_LIBRARY = \ + $(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +GARBAGE += $(XPCOM_GLUE_SRC_LCSRCS) $(wildcard *.$(OBJ_SUFFIX)) + +ifeq ($(OS_ARCH),WINNT) +GARBAGE += $(addprefix $(srcdir)/,$(XPCOM_GLUE_SRC_LCSRCS)) +endif + +SRCS_IN_OBJDIR = 1 + +include $(topsrcdir)/config/rules.mk + +export:: $(XPCOM_GLUE_SRC_CSRCS) + $(INSTALL) $^ . + +DEFINES += -DXPCOM_GLUE diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp new file mode 100644 index 00000000..4a1247eb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.cpp @@ -0,0 +1,596 @@ +/* -*- 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 Mozilla Communicator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sean Su + * + * 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 "nsBuildID.h" + +#include "nsEmbedString.h" +#include "nsXPCOMPrivate.h" +#include "nsXPCOMGlue.h" +#include "nsILocalFile.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCOMPtr.h" + +#include "nspr.h" +#include "plstr.h" + +#ifdef XP_WIN32 +#include +#include +#elif defined(XP_OS2) +#define INCL_DOS +#include +#include +#include +#include "prenv.h" +#elif defined(XP_MACOSX) +#include +#include +#elif defined(XP_UNIX) +#include +#include +#include +#include +#include "prenv.h" +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#include + +#include "nsGREDirServiceProvider.h" + +PRBool GRE_GetCurrentProcessDirectory(char* buffer); +PRBool GRE_GetPathFromConfigDir(const char* dirname, char* buffer); +PRBool GRE_GetPathFromConfigFile(const char* dirname, char* buffer); + +//***************************************************************************** +// nsGREDirServiceProvider::nsISupports +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(nsGREDirServiceProvider, nsIDirectoryServiceProvider) + +//***************************************************************************** +// nsGREDirServiceProvider::nsIDirectoryServiceProvider +//***************************************************************************** + +NS_IMETHODIMP +nsGREDirServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + *_retval = nsnull; + *persistant = PR_TRUE; + + //--------------------------------------------------------------- + // Note that by returning a valid localFile's for NS_GRE_DIR, + // your app is indicating to XPCOM that it found a GRE version + // with which it's compatible with and intends to be "run against" + // that GRE. + // + // Please see http://www.mozilla.org/projects/embedding/GRE.html + // for more info on GRE. + //--------------------------------------------------------------- + if(strcmp(prop, NS_GRE_DIR) == 0) + { + nsILocalFile* lfile = nsnull; + nsresult rv = GRE_GetGREDirectory(&lfile); + *_retval = lfile; + return rv; + } + + return NS_ERROR_FAILURE; +} + +//***************************************************************************** +// Implementations from nsXPCOMGlue.h and helper functions. +//***************************************************************************** + +PRBool +GRE_GetCurrentProcessDirectory(char* buffer) +{ + *buffer = '\0'; + +#ifdef XP_WIN + if ( ::GetModuleFileName(0, buffer, MAXPATHLEN) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buffer, '\\'); + if (lastSlash) { + *(lastSlash) = '\0'; + return PR_TRUE; + } + } + +#elif defined(XP_MACOSX) + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (appBundle != nsnull) + { + CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle); + if (bundleURL != nsnull) + { + CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL); + if (parentURL) + { + CFStringRef path = CFURLCopyFileSystemPath(parentURL, kCFURLPOSIXPathStyle); + if (path) + { + CFStringGetCString(path, buffer, MAXPATHLEN, kCFStringEncodingUTF8); + CFRelease(path); + } + CFRelease(parentURL); + } + CFRelease(bundleURL); + } +#if 0 /* bird: Causes crashes in objc_msgSend() later if released. I dunno why really. + Something could be seriously screwed up somewhere else, but this'll have + to do for now. (appBundle isn't released in the other place it's used.) */ + CFRelease(appBundle); +#endif + } + if (*buffer) return PR_TRUE; + +#elif defined(XP_UNIX) + +#if 0 /* we need .so location. */ + // Actually we have a way on linux. + static volatile bool fPathSet = false; + static char szPath[MAXPATHLEN]; + if (!fPathSet) + { + char buf2[MAXPATHLEN + 3]; + buf2[0] = '\0'; + + /* + * Env.var. VBOX_XPCOM_HOME first. + */ + char *psz = PR_GetEnv("VBOX_XPCOM_HOME"); + if (psz) + { + if (strlen(psz) < MAXPATHLEN) + { + if (!realpath(psz, buf2)) + strcpy(buf2, psz); + strcat(buf2, "/x"); /* for the filename stripping */ + } + } + + /* + * The dynamic loader. + */ + if (!buf2[0]) + { + Dl_info DlInfo = {0}; + if ( !dladdr((const void *)GRE_GetCurrentProcessDirectory, &DlInfo) + && DlInfo.dli_fname) + { + if (!realpath(DlInfo.dli_fname, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Executable location. + */ + if (!buf2[0]) + { + char buf[MAXPATHLEN]; + int cchLink = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (cchLink > 0 || cchLink != sizeof(buf) - 1) + { + buf[cchLink] = '\0'; + if (!realpath(buf, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Copy to static buffer on success. + */ + if (buf2[0]) + { + char *p = strrchr(buf2, '/'); + if (p) + { + p[p == buf2] = '\0'; + #ifdef DEBUG + printf("debug: (1) VBOX_XPCOM_HOME=%s\n", buf2); + #endif + strcpy(szPath, buf2); + fPathSet = true; + } + } + } + if (fPathSet) + { + strcpy(buffer, szPath); + return PR_TRUE; + } +#endif + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + + // The MOZ_DEFAULT_VBOX_XPCOM_HOME variable can be set at configure time with + // a --with-default-mozilla-five-home=foo autoconf flag. + // + // The idea here is to allow for builds that have a default VBOX_XPCOM_HOME + // regardless of the environment. This makes it easier to write apps that + // embed mozilla without having to worry about setting up the environment + // + // We do this py putenv()ing the default value into the environment. Note that + // we only do this if it is not already set. +#ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + if (PR_GetEnv("VBOX_XPCOM_HOME") == nsnull) + { + putenv("VBOX_XPCOM_HOME=" MOZ_DEFAULT_VBOX_XPCOM_HOME); + } +#endif + + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + + if (moz5 && *moz5) + { + if (!realpath(moz5, buffer)) + strcpy(buffer, moz5); + + return PR_TRUE; + } + else + { +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buffer, MAXPATHLEN)) + { + return PR_TRUE; + } + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char* p; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, buffer); + p = strrchr( buffer, '\\'); // XXX DBCS misery + if (p) { + *p = '\0'; + return PR_TRUE; + } + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + strcpy(buffer, moz5); + return PR_TRUE; + } + else + { + int32 cookie = 0; + image_info info; + char *p; + *buffer = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buffer, info.name); + if((p = strrchr(buffer, '/')) != 0) + { + *p = 0; + + return PR_TRUE; + } + } + } + +#endif + + return PR_FALSE; +} + +/** + * the GRE location is stored in a static buffer so that we don't have + * to compute it multiple times. + */ + +static char sGRELocation[MAXPATHLEN] = ""; + +extern "C" char const * +GRE_GetGREPath() +{ + // we've already done this... + if (*sGRELocation) + return sGRELocation; + + char buffer[MAXPATHLEN]; + + // If the xpcom library exists in the current process directory, + // then we will not use any GRE. The assumption here is that the + // GRE is in the same directory as the executable. + if (GRE_GetCurrentProcessDirectory(buffer)) { + PRUint32 pathlen = strlen(buffer); + strcpy(buffer + pathlen, XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL); + + struct stat libStat; + int statResult = stat(buffer, &libStat); + + if (statResult != -1) { + //found our xpcom lib in the current process directory + buffer[pathlen] = '\0'; + strcpy(sGRELocation, buffer); + return sGRELocation; + } + } + + // if GRE_HOME is in the environment, use that GRE + const char* env = PR_GetEnv("GRE_HOME"); + if (env && *env) { +#if XP_UNIX + if (!realpath(env, sGRELocation)) + strcpy(sGRELocation, env); +#elif XP_WIN32 + if (!_fullpath(sGRELocation, env, MAXPATHLEN)) + strcpy(sGRELocation, env); +#endif + // xxxbsmedberg: it would help that other platforms had a "make absolute" function + return sGRELocation; + } + + // the Gecko bits that sit next to the application or in the LD_LIBRARY_PATH + env = PR_GetEnv("USE_LOCAL_GRE"); + if (env && *env) + return nsnull; + +#if XP_UNIX + // check in the HOME directory + env = PR_GetEnv("HOME"); + if (env && *env) { +# ifdef VBOX + snprintf(buffer, sizeof(buffer), "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env); +# else + sprintf(buffer, "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env); +# endif + + if (GRE_GetPathFromConfigFile(buffer, sGRELocation)) { + return sGRELocation; + } + } +#endif + + env = PR_GetEnv("MOZ_GRE_CONF"); + if (env) { + if (GRE_GetPathFromConfigFile(env, sGRELocation)) { + return sGRELocation; + } + } + +#if XP_UNIX + // Look for a group of config files in /etc/gre.d/ + if (GRE_GetPathFromConfigDir(GRE_CONF_DIR, sGRELocation)) { + return sGRELocation; + } + + // Look for a global /etc/gre.conf file + if (GRE_GetPathFromConfigFile(GRE_CONF_PATH, sGRELocation)) { + return sGRELocation; + } +#endif + +#if XP_WIN32 + char szKey[256]; + HKEY hRegKey = NULL; + DWORD dwLength = MAXPATHLEN; + + // A couple of key points here: + // 1. Note the usage of the "Software\\Mozilla\\GRE" subkey - this allows + // us to have multiple versions of GREs on the same machine by having + // subkeys such as 1.0, 1.1, 2.0 etc. under it. + // 2. In this sample below we're looking for the location of GRE version 1.2 + // i.e. we're compatible with GRE 1.2 and we're trying to find it's install + // location. + // + // Please see http://www.mozilla.org/projects/embedding/GRE.html for + // more info. + // + strcpy(szKey, GRE_WIN_REG_LOC GRE_BUILD_ID); + + if (::RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) { + if (::RegQueryValueEx(hRegKey, "GreHome", NULL, NULL, (BYTE *)sGRELocation, &dwLength) != ERROR_SUCCESS) { + *sGRELocation = '\0'; + } + ::RegCloseKey(hRegKey); + + if (*sGRELocation) + return sGRELocation; + } + + if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) { + if (::RegQueryValueEx(hRegKey, "GreHome", NULL, NULL, (BYTE *)sGRELocation, &dwLength) != ERROR_SUCCESS) { + *sGRELocation = '\0'; + } + ::RegCloseKey(hRegKey); + + if (*sGRELocation) + return sGRELocation; + } +#endif + + return nsnull; +} + +PRBool +GRE_GetPathFromConfigDir(const char* dirname, char* buffer) +{ + // Open the directory provided and try to read any files in that + // directory that end with .conf. We look for an entry that might + // point to the GRE that we're interested in. + PRDir *dir = PR_OpenDir(dirname); + if (!dir) + return nsnull; + + PRBool found = PR_FALSE; + PRDirEntry *entry; + + while (!found && (entry = PR_ReadDir(dir, PR_SKIP_BOTH))) { + + // Only look for files that end in .conf + char *offset = PL_strrstr(entry->name, ".conf"); + if (!offset) + continue; + + if (offset != entry->name + strlen(entry->name) - 5) + continue; + + nsEmbedCString fullPath; + NS_CStringAppendData(fullPath, dirname); + NS_CStringAppendData(fullPath, XPCOM_FILE_PATH_SEPARATOR); + NS_CStringAppendData(fullPath, entry->name); + + found = GRE_GetPathFromConfigFile(fullPath.get(), buffer); + } + + PR_CloseDir(dir); + + return found; +} + +PRBool +GRE_GetPathFromConfigFile(const char* filename, char* pathBuffer) +{ + *pathBuffer = '\0'; + char buffer[1024]; + FILE *cfg; + PRBool foundHeader = PR_FALSE; + PRInt32 versionLen = sizeof(GRE_BUILD_ID)-1; + + if((cfg=fopen(filename,"r"))==nsnull) { + return nsnull; + } + + while (fgets(buffer, 1024, cfg) != nsnull) { + // skip over comment lines and blank lines + if (buffer[0] == '#' || buffer[0] == '\n') { + continue; + } + + // we found a section heading, check to see if it is the one we are intersted in. + if (buffer[0] == '[') { + if (!strncmp (buffer+1, GRE_BUILD_ID, versionLen)) { + foundHeader = PR_TRUE; + } + continue; + } + + if (foundHeader && !strncmp (buffer, "GRE_PATH=", 9)) { + strcpy(pathBuffer, buffer + 9); + // kill the line feed if any + PRInt32 len = strlen(pathBuffer); + len--; + + if (pathBuffer[len] == '\n') + pathBuffer[len] = '\0'; + break; + } + } + fclose(cfg); + return (*pathBuffer != '\0'); +} + +extern "C" nsresult +GRE_GetGREDirectory(nsILocalFile* *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + nsresult rv = NS_ERROR_FAILURE; + + // Get the path of the GRE which is compatible with our embedding application + // from the registry + + const char *pGREDir = GRE_GetGREPath(); + if(pGREDir) { + nsCOMPtr tempLocal; + nsEmbedCString leaf; + NS_CStringSetData(leaf, pGREDir); + rv = NS_NewNativeLocalFile(leaf, PR_TRUE, getter_AddRefs(tempLocal)); + + if (NS_SUCCEEDED(rv)) { + *_retval = tempLocal; + NS_ADDREF(*_retval); + } + } + return rv; +} + +static char sXPCOMPath[MAXPATHLEN]; + +extern "C" const char* +GRE_GetXPCOMPath() +{ + const char* grePath = GRE_GetGREPath(); + + if (!grePath) { + grePath = PR_GetEnv("VBOX_XPCOM_HOME"); + if (!grePath || !*grePath) { + return nsnull; + } + } + +#ifdef VBOX + snprintf(sXPCOMPath, sizeof(sXPCOMPath), "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, grePath); +#else + sprintf(sXPCOMPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, grePath); +#endif + + return sXPCOMPath; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h new file mode 100644 index 00000000..0638a127 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsGREDirServiceProvider.h @@ -0,0 +1,68 @@ +/* ***** 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 Mozilla Communicator. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Sean Su + * + * 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 nsGREDirServiceProvider_h_ +#define nsGREDirServiceProvider_h_ + +#include "nsIDirectoryService.h" + +#ifndef MAXPATHLEN +#ifdef _MAX_PATH +#define MAXPATHLEN _MAX_PATH +#elif defined(CCHMAXPATH) +#define MAXPATHLEN CCHMAXPATH +#else +#define MAXPATHLEN 1024 +#endif +#endif + +/** + * the directoryserviceprovider used by GRE_Startup when calling NS_InitXPCOM2 + */ +class nsGREDirServiceProvider : public nsIDirectoryServiceProvider +{ +public: + nsGREDirServiceProvider() { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + +private: + ~nsGREDirServiceProvider() { } +}; + +#endif // nsGREDirServiceProvider.h diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp new file mode 100644 index 00000000..091538fa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:set ts=4 sw=4 et cindent: */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOMGlue.h" + +#include "nspr.h" +#include "nsMemory.h" +#include "nsGREDirServiceProvider.h" +#include "nsXPCOMPrivate.h" +#include +#ifdef VBOX +# include +#endif + +#if XP_WIN32 +#include +#endif + +void GRE_AddGREToEnvironment(); + +// functions provided by nsMemory.cpp and nsDebug.cpp +nsresult GlueStartupMemory(); +void GlueShutdownMemory(); +nsresult GlueStartupDebug(); +void GlueShutdownDebug(); + +static PRLibrary *xpcomLib; +static XPCOMFunctions xpcomFunctions; + +extern "C" +nsresult XPCOMGlueStartup(const char* xpcomFile) +{ +#ifdef XPCOM_GLUE_NO_DYNAMIC_LOADING + return NS_OK; +#else + nsresult rv = NS_OK; + GetFrozenFunctionsFunc function = nsnull; + + xpcomFunctions.version = XPCOM_GLUE_VERSION; + xpcomFunctions.size = sizeof(XPCOMFunctions); + + // + // if xpcomFile == ".", then we assume xpcom is already loaded, and we'll + // use NSPR to find NS_GetFrozenFunctions from the list of already loaded + // libraries. + // + // otherwise, we try to load xpcom and then look for NS_GetFrozenFunctions. + // if xpcomFile == NULL, then we try to load xpcom by name w/o a fully + // qualified path. + // + + if (xpcomFile && (xpcomFile[0] == '.' && xpcomFile[1] == '\0')) { + function = (GetFrozenFunctionsFunc) + PR_FindSymbolAndLibrary("NS_GetFrozenFunctions", &xpcomLib); + if (!function) { + // The symbol was not found, so failover to loading XPCOM_DLL, + // and look for the symbol there. See bug 240986 for details. + xpcomFile = nsnull; + } + else { + char *libPath = PR_GetLibraryFilePathname(XPCOM_DLL, (PRFuncPtr) function); + if (!libPath) + rv = NS_ERROR_FAILURE; + else { + rv = (*function)(&xpcomFunctions, libPath); + PR_Free(libPath); + } + } + } + + if (!function) { + PRLibSpec libSpec; + + libSpec.type = PR_LibSpec_Pathname; + if (!xpcomFile) + libSpec.value.pathname = XPCOM_DLL; + else + libSpec.value.pathname = xpcomFile; + + xpcomLib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); +#ifdef RT_OS_DARWIN /* vbox */ + /* works around bundle problem. */ + if (!xpcomLib) { + const char *home = PR_GetEnv("VBOX_XPCOM_HOME"); + if (home) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/%s", home, libSpec.value.pathname); + libSpec.value.pathname = path; + xpcomLib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); + } + } +#endif + if (!xpcomLib) + return NS_ERROR_FAILURE; + + function = (GetFrozenFunctionsFunc) PR_FindSymbol(xpcomLib, "NS_GetFrozenFunctions"); + + if (!function) + rv = NS_ERROR_FAILURE; + else + rv = (*function)(&xpcomFunctions, libSpec.value.pathname); + } + + if (NS_FAILED(rv)) + goto bail; + + rv = GlueStartupDebug(); + if (NS_FAILED(rv)) + goto bail; + + // startup the nsMemory + rv = GlueStartupMemory(); + if (NS_FAILED(rv)) { + GlueShutdownDebug(); + goto bail; + } + + GRE_AddGREToEnvironment(); + return NS_OK; + +bail: + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + memset(&xpcomFunctions, 0, sizeof(xpcomFunctions)); + return NS_ERROR_FAILURE; +#endif +} + +extern "C" +nsresult XPCOMGlueShutdown() +{ +#ifdef XPCOM_GLUE_NO_DYNAMIC_LOADING + return NS_OK; +#else + + GlueShutdownMemory(); + + GlueShutdownDebug(); + + if (xpcomLib) { + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + } + + memset(&xpcomFunctions, 0, sizeof(xpcomFunctions)); + return NS_OK; +#endif +} + +#ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING +extern "C" NS_COM nsresult +NS_InitXPCOM2(nsIServiceManager* *result, + nsIFile* binDirectory, + nsIDirectoryServiceProvider* appFileLocationProvider) +{ + if (!xpcomFunctions.init) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.init(result, binDirectory, appFileLocationProvider); +} + +extern "C" NS_COM nsresult +NS_ShutdownXPCOM(nsIServiceManager* servMgr) +{ + if (!xpcomFunctions.shutdown) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.shutdown(servMgr); +} + +extern "C" NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result) +{ + if (!xpcomFunctions.getServiceManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getServiceManager(result); +} + +extern "C" NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result) +{ + if (!xpcomFunctions.getComponentManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getComponentManager(result); +} + +extern "C" NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result) +{ + if (!xpcomFunctions.getComponentRegistrar) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getComponentRegistrar(result); +} + +extern "C" NS_COM nsresult +NS_GetMemoryManager(nsIMemory* *result) +{ + if (!xpcomFunctions.getMemoryManager) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getMemoryManager(result); +} + +extern "C" NS_COM nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + if (!xpcomFunctions.newLocalFile) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.newLocalFile(path, followLinks, result); +} + +extern "C" NS_COM nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + if (!xpcomFunctions.newNativeLocalFile) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.newNativeLocalFile(path, followLinks, result); +} + +extern "C" NS_COM nsresult +NS_RegisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine, PRUint32 priority) +{ + if (!xpcomFunctions.registerExitRoutine) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.registerExitRoutine(exitRoutine, priority); +} + +extern "C" NS_COM nsresult +NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) +{ + if (!xpcomFunctions.unregisterExitRoutine) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.unregisterExitRoutine(exitRoutine); +} + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result) +{ + if (!xpcomFunctions.getDebug) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getDebug(result); +} + + +extern "C" NS_COM nsresult +NS_GetTraceRefcnt(nsITraceRefcnt* *result) +{ + if (!xpcomFunctions.getTraceRefcnt) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.getTraceRefcnt(result); +} + + +extern "C" NS_COM nsresult +NS_StringContainerInit(nsStringContainer &aStr) +{ + if (!xpcomFunctions.stringContainerInit) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringContainerInit(aStr); +} + +extern "C" NS_COM void +NS_StringContainerFinish(nsStringContainer &aStr) +{ + if (xpcomFunctions.stringContainerFinish) + xpcomFunctions.stringContainerFinish(aStr); +} + +extern "C" NS_COM PRUint32 +NS_StringGetData(const nsAString &aStr, const PRUnichar **aBuf, PRBool *aTerm) +{ + if (!xpcomFunctions.stringGetData) { + *aBuf = nsnull; + return 0; + } + return xpcomFunctions.stringGetData(aStr, aBuf, aTerm); +} + +extern "C" NS_COM PRUnichar * +NS_StringCloneData(const nsAString &aStr) +{ + if (!xpcomFunctions.stringCloneData) + return nsnull; + return xpcomFunctions.stringCloneData(aStr); +} + +extern "C" NS_COM nsresult +NS_StringSetData(nsAString &aStr, const PRUnichar *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.stringSetData) + return NS_ERROR_NOT_INITIALIZED; + + return xpcomFunctions.stringSetData(aStr, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_StringSetDataRange(nsAString &aStr, PRUint32 aCutStart, PRUint32 aCutLength, + const PRUnichar *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.stringSetDataRange) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + if (!xpcomFunctions.stringCopy) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.stringCopy(aDest, aSrc); +} + + +extern "C" NS_COM nsresult +NS_CStringContainerInit(nsCStringContainer &aStr) +{ + if (!xpcomFunctions.cstringContainerInit) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringContainerInit(aStr); +} + +extern "C" NS_COM void +NS_CStringContainerFinish(nsCStringContainer &aStr) +{ + if (xpcomFunctions.cstringContainerFinish) + xpcomFunctions.cstringContainerFinish(aStr); +} + +extern "C" NS_COM PRUint32 +NS_CStringGetData(const nsACString &aStr, const char **aBuf, PRBool *aTerm) +{ + if (!xpcomFunctions.cstringGetData) { + *aBuf = nsnull; + return 0; + } + return xpcomFunctions.cstringGetData(aStr, aBuf, aTerm); +} + +extern "C" NS_COM char * +NS_CStringCloneData(const nsACString &aStr) +{ + if (!xpcomFunctions.cstringCloneData) + return nsnull; + return xpcomFunctions.cstringCloneData(aStr); +} + +extern "C" NS_COM nsresult +NS_CStringSetData(nsACString &aStr, const char *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.cstringSetData) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringSetData(aStr, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_CStringSetDataRange(nsACString &aStr, PRUint32 aCutStart, PRUint32 aCutLength, + const char *aBuf, PRUint32 aCount) +{ + if (!xpcomFunctions.cstringSetDataRange) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringSetDataRange(aStr, aCutStart, aCutLength, aBuf, aCount); +} + +extern "C" NS_COM nsresult +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + if (!xpcomFunctions.cstringCopy) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringCopy(aDest, aSrc); +} + +extern "C" NS_COM nsresult +NS_CStringToUTF16(const nsACString &aSrc, PRUint32 aSrcEncoding, nsAString &aDest) +{ + if (!xpcomFunctions.cstringToUTF16) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.cstringToUTF16(aSrc, aSrcEncoding, aDest); +} + +extern "C" NS_COM nsresult +NS_UTF16ToCString(const nsAString &aSrc, PRUint32 aDestEncoding, nsACString &aDest) +{ + if (!xpcomFunctions.utf16ToCString) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions.utf16ToCString(aSrc, aDestEncoding, aDest); +} + +#endif // #ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING + + +static char sEnvString[MAXPATHLEN*10]; +static char* spEnvString = 0; + +void +GRE_AddGREToEnvironment() +{ + const char* grePath = GRE_GetGREPath(); + char szPath[MAXPATHLEN]; + if (!grePath) + return; + + const char* path = PR_GetEnv(XPCOM_SEARCH_KEY); + if (!path) + path = ""; +#ifdef VBOX + else + { + /* sEnvString is part of the environment because of putenv(). + * path is only temporarily used and not argument of putenv() itself */ + snprintf(szPath, sizeof(szPath), "%s", path); + path = szPath; + } +#endif + + if (spEnvString) PR_smprintf_free(spEnvString); + + /** + * if the PATH string is longer than our static buffer, allocate a + * buffer for the environment string. This buffer will be leaked at shutdown! + */ + if (strlen(grePath) + strlen(path) + + sizeof(XPCOM_SEARCH_KEY) + sizeof(XPCOM_ENV_PATH_SEPARATOR) > MAXPATHLEN*10) { + if (PR_smprintf(XPCOM_SEARCH_KEY "=%s" XPCOM_ENV_PATH_SEPARATOR "%s", + grePath, + path)) { + PR_SetEnv(spEnvString); + } + } else { + if (sprintf(sEnvString, + XPCOM_SEARCH_KEY "=%s" XPCOM_ENV_PATH_SEPARATOR "%s", + grePath, + path) > 0) { + PR_SetEnv(sEnvString); + } + } + +#if XP_WIN32 + // On windows, the current directory is searched before the + // PATH environment variable. This is a very bad thing + // since libraries in the cwd will be picked up before + // any that are in either the application or GRE directory. + + if (grePath) { + SetCurrentDirectory(grePath); + } +#endif +} + + +// Default GRE startup/shutdown code + +extern "C" +nsresult GRE_Startup() +{ + const char* xpcomLocation = GRE_GetXPCOMPath(); + + // Startup the XPCOM Glue that links us up with XPCOM. + nsresult rv = XPCOMGlueStartup(xpcomLocation); + + if (NS_FAILED(rv)) { + NS_WARNING("gre: XPCOMGlueStartup failed"); + return rv; + } + + nsGREDirServiceProvider *provider = new nsGREDirServiceProvider(); + if ( !provider ) { + NS_WARNING("GRE_Startup failed"); + XPCOMGlueShutdown(); + return NS_ERROR_OUT_OF_MEMORY; + } + + nsCOMPtr servMan; + NS_ADDREF( provider ); + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, provider); + NS_RELEASE(provider); + + if ( NS_FAILED(rv) || !servMan) { + NS_WARNING("gre: NS_InitXPCOM failed"); + XPCOMGlueShutdown(); + return rv; + } + + return NS_OK; +} + +extern "C" +nsresult GRE_Shutdown() +{ + NS_ShutdownXPCOM(nsnull); + XPCOMGlueShutdown(); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h new file mode 100644 index 00000000..6044e084 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/standalone/nsXPCOMGlue.h @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nscore.h" + +class nsILocalFile; + +/** + * Initialize the XPCOM glue by dynamically linking against the XPCOM + * shared library indicated by xpcomFile. + */ + +extern "C" +nsresult XPCOMGlueStartup(const char* xpcomFile); + + +/** + * Finish the XPCOM glue after it is no longer needed. + */ + +extern "C" +nsresult XPCOMGlueShutdown(); + + +/** + * Locate the path of a compatible GRE. + * + * @return string buffer pointing to the GRE path (without a trailing + * directory separator). Callers do no need to free this buffer. + */ + +extern "C" +char const * GRE_GetGREPath(); + + +/** + * Locate the path of a compatible GRE. This is returned as an + * nsILocalFile instead of a char*. + * + * @param _retval Ordinary XPCOM getter, returns an addrefed interface. + */ + +extern "C" +nsresult GRE_GetGREDirectory(nsILocalFile* *_retval); + + +/** + * Locate the path of the XPCOM binary of a compatible GRE. + * The result of this function is normally passed directly to + * XPCOMGlueStartup. + * + * @return string buffer pointing to the XPCOM DLL path. Callers do + * not need to free this buffer. + */ + +extern "C" +char const * GRE_GetXPCOMPath(); + + +/** + * Embedding applications which don't need a custom + * directoryserviceprovider may use GRE_Startup to start the XPCOM + * glue and initialize the GRE in one step. + */ + +extern "C" +nsresult GRE_Startup(); + + +/** + * Shut down XPCOM and the XPCOM glue in one step. + */ + +extern "C" +nsresult GRE_Shutdown(); diff --git a/src/libs/xpcom18a4/xpcom/io/.cvsignore b/src/libs/xpcom18a4/xpcom/io/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/io/Makefile.in b/src/libs/xpcom18a4/xpcom/io/Makefile.in new file mode 100644 index 00000000..ed2f3f6d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/Makefile.in @@ -0,0 +1,175 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_io +LIBRARY_NAME = xpcomio_s +GRE_MODULE = 1 +REQUIRES = string \ + $(NULL) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = \ + nsAppFileLocationProvider.cpp \ + nsBinaryStream.cpp \ + nsByteArrayInputStream.cpp \ + nsDirectoryService.cpp \ + nsEscape.cpp \ + nsFastLoadFile.cpp \ + nsFastLoadService.cpp \ + nsInputStreamTee.cpp \ + nsLinebreakConverter.cpp \ + nsLocalFileCommon.cpp \ + nsMultiplexInputStream.cpp \ + nsPipe3.cpp \ + nsStreamUtils.cpp \ + nsScriptableInputStream.cpp \ + nsSegmentedBuffer.cpp \ + SpecialSystemDirectory.cpp \ + nsStorageStream.cpp \ + nsStringStream.cpp \ + nsUnicharInputStream.cpp \ + nsNativeCharsetUtils.cpp \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +CPPSRCS += nsLocalFileOS2.cpp +else +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CPPSRCS += nsLocalFileOSX.cpp +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += nsLocalFileWin.cpp +else +CPPSRCS += nsLocalFileUnix.cpp +endif # windows +endif # mac +endif # OS2 + +EXPORTS = \ + nsAppDirectoryServiceDefs.h \ + nsDirectoryService.h \ + nsDirectoryServiceUtils.h \ + nsEscape.h \ + nsFastLoadPtr.h \ + nsFastLoadService.h \ + nsIUnicharInputStream.h \ + nsLinebreakConverter.h \ + nsLocalFile.h \ + nsMultiplexInputStream.h \ + nsScriptableInputStream.h \ + nsStorageStream.h \ + nsStringIO.h \ + nsStringStream.h \ + nsStreamUtils.h \ + nsNativeCharsetUtils.h \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +EXPORTS += nsLocalFileOS2.h +else +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXPORTS += nsLocalFileOSX.h +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +EXPORTS += nsLocalFileWin.h +else +EXPORTS += nsLocalFileUnix.h +endif # windows +endif # mac +endif # os2 + +XPIDLSRCS = \ + nsIBinaryInputStream.idl \ + nsIBinaryOutputStream.idl \ + nsIByteArrayInputStream.idl \ + nsIFastLoadFileControl.idl \ + nsIFastLoadService.idl \ + nsIInputStreamTee.idl \ + nsILineInputStream.idl \ + nsIMultiplexInputStream.idl \ + nsIObjectInputStream.idl \ + nsIObjectOutputStream.idl \ + nsIPipe.idl \ + nsISeekableStream.idl \ + nsIStorageStream.idl \ + nsIStringStream.idl \ + nsIStreamBufferAccess.idl \ + nsIAsyncInputStream.idl \ + nsIAsyncOutputStream.idl \ + $(NULL) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +XPIDLSRCS += nsILocalFileMac.idl +endif + +SDK_XPIDLSRCS = \ + nsIDirectoryService.idl \ + nsIFile.idl \ + nsILocalFile.idl \ + nsIInputStream.idl \ + nsIOutputStream.idl \ + nsIScriptableInputStream.idl \ + $(NULL) + +SDK_HEADERS = \ + nsDirectoryServiceDefs.h \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + +LOCAL_INCLUDES = -I.. diff --git a/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp new file mode 100644 index 00000000..5d1bc4fd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.cpp @@ -0,0 +1,770 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "SpecialSystemDirectory.h" +#include "nsString.h" +#include "nsDependentString.h" + + +#ifdef XP_MAC + +#include +#include +#include +#include +#include +#include "nsIInternetConfigService.h" + + +#if UNIVERSAL_INTERFACES_VERSION < 0x0340 + enum { + kSystemDomain = -32766, /* Read-only system hierarchy.*/ + kLocalDomain = -32765, /* All users of a single machine have access to these resources.*/ + kNetworkDomain = -32764, /* All users configured to use a common network server has access to these resources.*/ + kUserDomain = -32763, /* Read/write. Resources that are private to the user.*/ + kClassicDomain = -32762, /* Domain referring to the currently configured Classic System Folder*/ + + kDomainLibraryFolderType = FOUR_CHAR_CODE('dlib') + }; +#endif + +#elif defined(XP_WIN) + +#include +#include +#include +#include +#include + +#elif defined(XP_OS2) + +#define MAX_PATH _MAX_PATH +#define INCL_WINWORKPLACE +#define INCL_DOSMISC +#define INCL_DOSMODULEMGR +#define INCL_DOSPROCESS +#define INCL_WINSHELLDATA +#include +#include +#include +#include "prenv.h" + +#elif defined(XP_UNIX) + +#include +#include +#include +#include "prenv.h" +# if defined(XP_MACOSX) && defined(VBOX_WITH_NEWER_OSX_SDK) +# include +# endif + +#elif defined(XP_BEOS) + +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" + +#endif + +#if defined(VMS) +#include +#endif + + + +#if defined (XP_WIN) +typedef BOOL (WINAPI * GetSpecialPathProc) (HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); +GetSpecialPathProc gGetSpecialPathProc = NULL; +static HINSTANCE gShell32DLLInst = NULL; +#endif +NS_COM void StartupSpecialSystemDirectory() +{ +#if defined (XP_WIN) + /* On windows, the old method to get file locations is incredibly slow. + As of this writing, 3 calls to GetWindowsFolder accounts for 3% of mozilla + startup. Replacing these older calls with a single call to SHGetSpecialFolderPath + effectively removes these calls from the performace radar. We need to + support the older way of file location lookup on systems that do not have + IE4. (Note: gets the ansi version: SHGetSpecialFolderPathA). + */ + gShell32DLLInst = LoadLibrary("Shell32.dll"); + if(gShell32DLLInst) + { + gGetSpecialPathProc = (GetSpecialPathProc) GetProcAddress(gShell32DLLInst, + "SHGetSpecialFolderPathA"); + } +#endif +} + +NS_COM void ShutdownSpecialSystemDirectory() +{ +#if defined (XP_WIN) + if (gShell32DLLInst) + { + FreeLibrary(gShell32DLLInst); + gShell32DLLInst = NULL; + gGetSpecialPathProc = NULL; + } +#endif +} + +#if defined (XP_WIN) + +//---------------------------------------------------------------------------------------- +static nsresult GetWindowsFolder(int folder, nsILocalFile** aFile) +//---------------------------------------------------------------------------------------- +{ + if (gGetSpecialPathProc) { + TCHAR path[MAX_PATH]; + HRESULT result = gGetSpecialPathProc(NULL, path, folder, true); + + if (!SUCCEEDED(result)) + return NS_ERROR_FAILURE; + + // Append the trailing slash + int len = strlen(path); + if (len>1 && path[len-1] != '\\') + { + path[len] = '\\'; + path[len + 1] = '\0'; + } + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + nsresult rv = NS_ERROR_FAILURE; + LPMALLOC pMalloc = NULL; + LPSTR pBuffer = NULL; + LPITEMIDLIST pItemIDList = NULL; + int len; + + // Get the shell's allocator. + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + return NS_ERROR_FAILURE; + + // Allocate a buffer + if ((pBuffer = (LPSTR) pMalloc->Alloc(MAX_PATH + 2)) == NULL) + return NS_ERROR_FAILURE; + + // Get the PIDL for the folder. + if (!SUCCEEDED(SHGetSpecialFolderLocation( + NULL, folder, &pItemIDList))) + goto Clean; + + if (!SUCCEEDED(SHGetPathFromIDList(pItemIDList, pBuffer))) + goto Clean; + + // Append the trailing slash + len = strlen(pBuffer); + pBuffer[len] = '\\'; + pBuffer[len + 1] = '\0'; + + // Assign the directory + rv = NS_NewNativeLocalFile(nsDependentCString(pBuffer), + PR_TRUE, + aFile); + +Clean: + // Clean up. + if (pItemIDList) + pMalloc->Free(pItemIDList); + if (pBuffer) + pMalloc->Free(pBuffer); + + pMalloc->Release(); + + return rv; +} + +#endif // XP_WIN + + + + +nsresult +GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, + nsILocalFile** aFile) +{ +#ifdef XP_MAC + OSErr err; + short vRefNum; + long dirID; +#endif + + switch (aSystemSystemDirectory) + { + case OS_DriveDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + if (len) + { + if ( path[1] == ':' && path[2] == '\\' ) + path[3] = 0; + } + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#elif defined(XP_OS2) + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } +#elif defined(XP_MAC) + { + return nsIFileFromOSType(kVolumeRootFolderType, aFile); + } +#else + return NS_NewNativeLocalFile(nsDependentCString("/"), + PR_TRUE, + aFile); + +#endif + + case OS_TemporaryDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + DWORD len = GetTempPath(_MAX_PATH, path); + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#elif defined(XP_OS2) + { + char buffer[CCHMAXPATH] = ""; + char *c = getenv( "TMP"); + if( c) strcpy( buffer, c); + else + { + c = getenv( "TEMP"); + if( c) strcpy( buffer, c); + } + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } +#elif defined(XP_MAC) + return nsIFileFromOSType(kTemporaryFolderType, aFile); + +#elif defined(XP_MACOSX) + { + return GetOSXFolderType(kUserDomain, kTemporaryFolderType, aFile); + } + +#elif defined(XP_UNIX) || defined(XP_BEOS) + { + static const char *tPath = nsnull; + if (!tPath) { + tPath = PR_GetEnv("TMPDIR"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TMP"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TEMP"); + if (!tPath || !*tPath) { + tPath = "/tmp/"; + } + } + } + } + return NS_NewNativeLocalFile(nsDependentCString(tPath), + PR_TRUE, + aFile); + } +#else + break; +#endif + +#if defined(XP_MAC) + case Mac_SystemDirectory: + return nsIFileFromOSType(kSystemFolderType, aFile); + + case Mac_DesktopDirectory: + return nsIFileFromOSType(kDesktopFolderType, aFile); + + case Mac_TrashDirectory: + return nsIFileFromOSType(kTrashFolderType, aFile); + + case Mac_StartupDirectory: + return nsIFileFromOSType(kStartupFolderType, aFile); + + case Mac_ShutdownDirectory: + return nsIFileFromOSType(kShutdownFolderType, aFile); + + case Mac_AppleMenuDirectory: + return nsIFileFromOSType(kAppleMenuFolderType, aFile); + + case Mac_ControlPanelDirectory: + return nsIFileFromOSType(kControlPanelFolderType, aFile); + + case Mac_ExtensionDirectory: + return nsIFileFromOSType(kExtensionFolderType, aFile); + + case Mac_FontsDirectory: + return nsIFileFromOSType(kFontsFolderType, aFile); + + case Mac_ClassicPreferencesDirectory: + { + // whether Mac OS X or pre-Mac OS X, return Classic's Prefs folder + short domain; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + domain = (!err && response >= 0x00001000) ? kClassicDomain : kOnSystemDisk; + err = ::FindFolder(domain, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + return NS_FILE_RESULT(err); + } + + case Mac_PreferencesDirectory: + { + // if Mac OS X, return Mac OS X's Prefs folder + // if pre-Mac OS X, return Mac OS's Prefs folder + err = ::FindFolder(kOnSystemDisk, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + return NS_FILE_RESULT(err); + } + + case Mac_DocumentsDirectory: + return nsIFileFromOSType(kDocumentsFolderType, aFile); + + case Mac_InternetSearchDirectory: + return nsIFileFromOSType(kInternetSearchSitesFolderType, aFile); + + case Mac_DefaultDownloadDirectory: + return nsIFileFromOSType(kDefaultDownloadFolderType, aFile); + + case Mac_UserLibDirectory: + { + FSSpec spec; + err = ::FindFolder(kUserDomain, kDomainLibraryFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &spec); + } + + return NS_NewLocalFileWithFSSpec(&spec, PR_FALUE, aFile); + } +#endif + +#if defined (XP_WIN) + case Win_SystemDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetSystemDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case Win_WindowsDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case Win_HomeDirectory: + { + char path[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOME"), path, _MAX_PATH) > 0) + { + PRInt32 len = strlen(path); + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + if (GetEnvironmentVariable(TEXT("HOMEDRIVE"), path, _MAX_PATH) > 0) + { + char temp[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOMEPATH"), temp, _MAX_PATH) > 0) + strncat(path, temp, _MAX_PATH); + + PRInt32 len = strlen(path); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + } + case Win_Desktop: + { + return GetWindowsFolder(CSIDL_DESKTOP, aFile); + } + case Win_Programs: + { + return GetWindowsFolder(CSIDL_PROGRAMS, aFile); + } + case Win_Controls: + { + return GetWindowsFolder(CSIDL_CONTROLS, aFile); + } + case Win_Printers: + { + return GetWindowsFolder(CSIDL_PRINTERS, aFile); + } + case Win_Personal: + { + return GetWindowsFolder(CSIDL_PERSONAL, aFile); + } + case Win_Favorites: + { + return GetWindowsFolder(CSIDL_FAVORITES, aFile); + } + case Win_Startup: + { + return GetWindowsFolder(CSIDL_STARTUP, aFile); + } + case Win_Recent: + { + return GetWindowsFolder(CSIDL_RECENT, aFile); + } + case Win_Sendto: + { + return GetWindowsFolder(CSIDL_SENDTO, aFile); + } + case Win_Bitbucket: + { + return GetWindowsFolder(CSIDL_BITBUCKET, aFile); + } + case Win_Startmenu: + { + return GetWindowsFolder(CSIDL_STARTMENU, aFile); + } + case Win_Desktopdirectory: + { + return GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, aFile); + } + case Win_Drives: + { + return GetWindowsFolder(CSIDL_DRIVES, aFile); + } + case Win_Network: + { + return GetWindowsFolder(CSIDL_NETWORK, aFile); + } + case Win_Nethood: + { + return GetWindowsFolder(CSIDL_NETHOOD, aFile); + } + case Win_Fonts: + { + return GetWindowsFolder(CSIDL_FONTS, aFile); + } + case Win_Templates: + { + return GetWindowsFolder(CSIDL_TEMPLATES, aFile); + } + case Win_Common_Startmenu: + { + return GetWindowsFolder(CSIDL_COMMON_STARTMENU, aFile); + } + case Win_Common_Programs: + { + return GetWindowsFolder(CSIDL_COMMON_PROGRAMS, aFile); + } + case Win_Common_Startup: + { + return GetWindowsFolder(CSIDL_COMMON_STARTUP, aFile); + } + case Win_Common_Desktopdirectory: + { + return GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, aFile); + } + case Win_Appdata: + { + return GetWindowsFolder(CSIDL_APPDATA, aFile); + } + case Win_Printhood: + { + return GetWindowsFolder(CSIDL_PRINTHOOD, aFile); + } + case Win_Cookies: + { + return GetWindowsFolder(CSIDL_COOKIES, aFile); + } +#endif // XP_WIN + +#if defined(XP_UNIX) + case Unix_LocalDirectory: + return NS_NewNativeLocalFile(nsDependentCString("/usr/local/netscape/"), + PR_TRUE, + aFile); + case Unix_LibDirectory: + return NS_NewNativeLocalFile(nsDependentCString("/usr/local/lib/netscape/"), + PR_TRUE, + aFile); + + case Unix_HomeDirectory: +#ifdef VMS + { + char *pHome; + pHome = getenv("HOME"); + if (*pHome == '/') { + return NS_NewNativeLocalFile(nsDependentCString(pHome), + PR_TRUE, + aFile); + + } + else + { + return NS_NewNativeLocalFile(nsDependentCString(decc$translate_vms(pHome)), + PR_TRUE, + aFile); + } + } +#else + return NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), + PR_TRUE, + aFile); + +#endif + +#endif + +#ifdef XP_BEOS + case BeOS_SettingsDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_HomeDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_DesktopDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_DESKTOP_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } + + case BeOS_SystemDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_BEOS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(path), + PR_TRUE, + aFile); + } +#endif +#ifdef XP_OS2 + case OS2_SystemDirectory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\System\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } + + case OS2_OS2Directory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + + return NS_NewNativeLocalFile(nsDependentCString(buffer), + PR_TRUE, + aFile); + } + + case OS2_HomeDirectory: + { + nsresult rv; + char *tPath = PR_GetEnv("MOZILLA_HOME"); + char buffer[CCHMAXPATH]; + /* If MOZILLA_HOME is not set, use GetCurrentProcessDirectory */ + /* To ensure we get a long filename system */ + if (!tPath || !*tPath) { + PPIB ppib; + PTIB ptib; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + tPath = buffer; + } + rv = NS_NewNativeLocalFile(nsDependentCString(tPath), + PR_TRUE, + aFile); + + PrfWriteProfileString(HINI_USERPROFILE, "Mozilla", "Home", tPath); + return rv; + } + + case OS2_DesktopDirectory: + { + char szPath[CCHMAXPATH + 1]; + BOOL fSuccess; + fSuccess = WinQueryActiveDesktopPathname (szPath, sizeof(szPath)); + int len = strlen (szPath); + if (len > CCHMAXPATH -1) + break; + szPath[len] = '\\'; + szPath[len + 1] = '\0'; + + return NS_NewNativeLocalFile(nsDependentCString(szPath), + PR_TRUE, + aFile); + } +#endif + default: + break; + } + return NS_ERROR_NOT_AVAILABLE; +} + +#if defined (XP_MACOSX) +nsresult +GetOSXFolderType(short aDomain, OSType aFolderType, nsILocalFile **localFile) +{ + OSErr err; + FSRef fsRef; + nsresult rv = NS_ERROR_FAILURE; + + err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef); + if (err == noErr) + { + NS_NewLocalFile(EmptyString(), PR_TRUE, localFile); + nsCOMPtr localMacFile(do_QueryInterface(*localFile)); + if (localMacFile) + rv = localMacFile->InitWithFSRef(&fsRef); + } + return rv; +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.h new file mode 100644 index 00000000..b4aaf30e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/SpecialSystemDirectory.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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _SPECIALSYSTEMDIRECTORY_H_ +#define _SPECIALSYSTEMDIRECTORY_H_ + +#include "nscore.h" +#include "nsILocalFile.h" + +#if defined(XP_MAC) || defined(XP_MACOSX) +# ifndef VBOX_WITH_NEWER_OSX_SDK +# include +# endif +#include "nsILocalFileMac.h" +#include "prenv.h" +#endif + + +extern NS_COM void StartupSpecialSystemDirectory(); +extern NS_COM void ShutdownSpecialSystemDirectory(); + + +enum SystemDirectories { + OS_DriveDirectory = 1, + OS_TemporaryDirectory = 2, + OS_CurrentProcessDirectory= 3, + OS_CurrentWorkingDirectory= 4, + XPCOM_CurrentProcessComponentDirectory= 5, + XPCOM_CurrentProcessComponentRegistry= 6, + + Moz_BinDirectory = 100 , + Mac_SystemDirectory = 101, + Mac_DesktopDirectory = 102, + Mac_TrashDirectory = 103, + Mac_StartupDirectory = 104, + Mac_ShutdownDirectory = 105, + Mac_AppleMenuDirectory = 106, + Mac_ControlPanelDirectory = 107, + Mac_ExtensionDirectory = 108, + Mac_FontsDirectory = 109, + Mac_ClassicPreferencesDirectory = 110, + Mac_DocumentsDirectory = 111, + Mac_InternetSearchDirectory = 112, + Mac_DefaultDownloadDirectory = 113, + Mac_UserLibDirectory = 114, + Mac_PreferencesDirectory = 115, + + Win_SystemDirectory = 201, + Win_WindowsDirectory = 202, + Win_HomeDirectory = 203, + Win_Desktop = 204, + Win_Programs = 205, + Win_Controls = 206, + Win_Printers = 207, + Win_Personal = 208, + Win_Favorites = 209, + Win_Startup = 210, + Win_Recent = 211, + Win_Sendto = 212, + Win_Bitbucket = 213, + Win_Startmenu = 214, + Win_Desktopdirectory = 215, + Win_Drives = 216, + Win_Network = 217, + Win_Nethood = 218, + Win_Fonts = 219, + Win_Templates = 220, + Win_Common_Startmenu = 221, + Win_Common_Programs = 222, + Win_Common_Startup = 223, + Win_Common_Desktopdirectory = 224, + Win_Appdata = 225, + Win_Printhood = 226, + Win_Cookies = 227, + + Unix_LocalDirectory = 301, + Unix_LibDirectory = 302, + Unix_HomeDirectory = 303, + + BeOS_SettingsDirectory = 401, + BeOS_HomeDirectory = 402, + BeOS_DesktopDirectory = 403, + BeOS_SystemDirectory = 404, + + OS2_SystemDirectory = 501, + OS2_OS2Directory = 502, + OS2_DesktopDirectory = 503, + OS2_HomeDirectory = 504 +}; + +nsresult +GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, + nsILocalFile** aFile); +#if defined(XP_MACOSX) +nsresult +GetOSXFolderType(short aDomain, OSType aFolderType, nsILocalFile **localFile); +#endif + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c new file mode 100644 index 00000000..838dffa2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.c @@ -0,0 +1,784 @@ +/* +** Apple Macintosh Developer Technical Support +** +** DirectoryCopy: A robust, general purpose directory copy routine. +** +** by Jim Luther, Apple Developer Technical Support Emeritus +** +** File: DirectoryCopy.c +** +** Copyright © 1992-1998 Apple Computer, Inc. +** All rights reserved. +** +** You may incorporate this sample code into your applications without +** restriction, though the sample code has been provided "AS IS" and the +** responsibility for its operation is 100% yours. However, what you are +** not permitted to do is to redistribute the source as "DSC Sample Code" +** after having made changes. If you're going to re-distribute the source, +** we require that you make it clear in the source that the code was +** descended from Apple Sample Code, but that you've made changes. +*/ + +// Modified to allow renaming the destination folder + +#include +#include +#include +#include +#include + +#define __COMPILINGMOREFILES + +#include "MoreFiles.h" +#include "MoreFilesExtras.h" +#include "MoreDesktopMgr.h" +#include "FileCopy.h" +#include "MacDirectoryCopy.h" +#include + + +/*****************************************************************************/ + +enum +{ + getNextItemOp = 1, /* couldn't access items in this directory - no access privileges */ + copyDirCommentOp = 2, /* couldn't copy directory's Finder comment */ + copyDirAccessPrivsOp = 3, /* couldn't copy directory's AFP access privileges */ + copyDirFMAttributesOp = 4, /* couldn't copy directory's File Manager attributes */ + dirCreateOp = 5, /* couldn't create destination directory */ + fileCopyOp = 6 /* couldn't copy file */ +}; + +/*****************************************************************************/ + + + +#define CallCopyErrProc(userRoutine, error, failedOperation, srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName) \ + (*(userRoutine))((error), (failedOperation), (srcVRefNum), (srcDirID), (srcName), (dstVRefNum), (dstDirID), (dstName)) + +/*****************************************************************************/ + +typedef pascal Boolean (*CopyFilterProcPtr) (const CInfoPBRec * const cpbPtr); + +/* ¦ Prototype for the CopyFilterProc function. + This is the prototype for the CopyFilterProc function called by + FilteredDirectoryCopy and GetLevelSize. If true is returned, + the file/folder is included in the copy, otherwise it is excluded. + + pb input: Points to the CInfoPBRec for the item under consideration. + + __________ + + Also see: FilteredDirectoryCopy, FSpFilteredDirectoryCopy +*/ + +#define CallCopyFilterProc(userRoutine, cpbPtr) (*(userRoutine))((cpbPtr)) + + + +/*****************************************************************************/ + +/* local constants */ + +enum +{ + dirCopyBigCopyBuffSize = 0x00004000, + dirCopyMinCopyBuffSize = 0x00000200 +}; + + +/*****************************************************************************/ + +/* local data structures */ + +/* The EnumerateGlobals structure is used to minimize the amount of +** stack space used when recursively calling CopyLevel and to hold +** global information that might be needed at any time. */ + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#endif +struct EnumerateGlobals +{ + Ptr copyBuffer; /* pointer to buffer used for file copy operations */ + long bufferSize; /* the size of the copy buffer */ + CopyErrProcPtr errorHandler; /* pointer to error handling function */ + CopyFilterProcPtr copyFilterProc; /* pointer to filter function */ + OSErr error; /* temporary holder of results - saves 2 bytes of stack each level */ + Boolean bailout; /* set to true to by error handling function if fatal error */ + short destinationVRefNum; /* the destination vRefNum */ + Str63 itemName; /* the name of the current item */ + CInfoPBRec myCPB; /* the parameter block used for PBGetCatInfo calls */ +}; +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#endif + +typedef struct EnumerateGlobals EnumerateGlobals; +typedef EnumerateGlobals *EnumerateGlobalsPtr; + + +/* The PreflightGlobals structure is used to minimize the amount of +** stack space used when recursively calling GetLevelSize and to hold +** global information that might be needed at any time. */ + +#if PRAGMA_STRUCT_ALIGN +#pragma options align=mac68k +#endif +struct PreflightGlobals +{ + OSErr result; /* temporary holder of results - saves 2 bytes of stack each level */ + Str63 itemName; /* the name of the current item */ + CInfoPBRec myCPB; /* the parameter block used for PBGetCatInfo calls */ + + unsigned long dstBlksPerAllocBlk; /* the number of 512 byte blocks per allocation block on destination */ + + unsigned long allocBlksNeeded; /* the total number of allocation blocks needed */ + + unsigned long tempBlocks; /* temporary storage for calculations (save some stack space) */ + CopyFilterProcPtr copyFilterProc; /* pointer to filter function */ +}; +#if PRAGMA_STRUCT_ALIGN +#pragma options align=reset +#endif + +typedef struct PreflightGlobals PreflightGlobals; +typedef PreflightGlobals *PreflightGlobalsPtr; + +/*****************************************************************************/ + +/* static prototypes */ + +static void GetLevelSize(long currentDirID, + PreflightGlobals *theGlobals); + +static OSErr PreflightDirectoryCopySpace(short srcVRefNum, + long srcDirID, + short dstVRefNum, + CopyFilterProcPtr copyFilterProc, + Boolean *spaceOK); + +static void CopyLevel(long sourceDirID, + long dstDirID, + EnumerateGlobals *theGlobals); + +/*****************************************************************************/ + +static void GetLevelSize(long currentDirID, + PreflightGlobals *theGlobals) +{ + short index = 1; + + do + { + theGlobals->myCPB.dirInfo.ioFDirIndex = index; + theGlobals->myCPB.dirInfo.ioDrDirID = currentDirID; /* we need to do this every time */ + /* through, since GetCatInfo */ + /* returns ioFlNum in this field */ + theGlobals->result = PBGetCatInfoSync(&theGlobals->myCPB); + if ( theGlobals->result == noErr ) + { + if ( (theGlobals->copyFilterProc == NULL) || + CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ + { + /* Either there's no filter proc OR the filter proc says to use this item */ + if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & ioDirMask) != 0 ) + { + /* we have a directory */ + + GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */ + theGlobals->result = noErr; /* clear error return on way back */ + } + else + { + /* We have a file - add its allocation blocks to allocBlksNeeded. */ + /* Since space on Mac OS disks is always allocated in allocation blocks, */ + /* this takes into account rounding up to the end of an allocation block. */ + + /* get number of 512-byte blocks needed for data fork */ + if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen & 0x000001ff) != 0 ) + { + theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1; + } + else + { + theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9; + } + /* now, calculate number of new allocation blocks needed for the data fork and add it to the total */ + if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk ) + { + theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; + } + else + { + theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; + } + + /* get number of 512-byte blocks needed for resource fork */ + if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen & 0x000001ff) != 0 ) + { + theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1; + } + else + { + theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9; + } + /* now, calculate number of new allocation blocks needed for the resource fork and add it to the total */ + if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk ) + { + theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1; + } + else + { + theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk; + } + } + } + } + ++index; + } while ( theGlobals->result == noErr ); +} + +/*****************************************************************************/ + +static OSErr PreflightDirectoryCopySpace(short srcVRefNum, + long srcDirID, + short dstVRefNum, + CopyFilterProcPtr copyFilterProc, + Boolean *spaceOK) +{ + XVolumeParam pb; + OSErr error; + unsigned long dstFreeBlocks; + PreflightGlobals theGlobals; + + error = XGetVolumeInfoNoName(NULL, dstVRefNum, &pb); + if ( error == noErr ) + { + /* Convert freeBytes to free disk blocks (512-byte blocks) */ +#if (UNIVERSAL_INTERFACES_VERSION >= 0x0330) + dstFreeBlocks = (pb.ioVFreeBytes >> 9); +#else + dstFreeBlocks = (pb.ioVFreeBytes.hi << 23) + (pb.ioVFreeBytes.lo >> 9); +#endif + /* get allocation block size (always multiple of 512) and divide by 512 + to get number of 512-byte blocks per allocation block */ + theGlobals.dstBlksPerAllocBlk = ((unsigned long)pb.ioVAlBlkSiz >> 9); + + theGlobals.allocBlksNeeded = 0; + + theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName; + theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum; + + theGlobals.copyFilterProc = copyFilterProc; + + GetLevelSize(srcDirID, &theGlobals); + + /* Is there enough room on the destination volume for the source file? */ + /* Note: This will work because the largest number of disk blocks supported */ + /* on a 2TB volume is 0xffffffff and (allocBlksNeeded * dstBlksPerAllocBlk) */ + /* will always be less than 0xffffffff. */ + *spaceOK = ((theGlobals.allocBlksNeeded * theGlobals.dstBlksPerAllocBlk) <= dstFreeBlocks); + } + + return ( error ); +} + +/*****************************************************************************/ + +static void CopyLevel(long sourceDirID, + long dstDirID, + EnumerateGlobals *theGlobals) +{ + long currentSrcDirID; + long newDirID; + short index = 1; + + do + { + /* Get next source item at the current directory level */ + + theGlobals->myCPB.dirInfo.ioFDirIndex = index; + theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID; + theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB); + + if ( theGlobals->error == noErr ) + { + if ( (theGlobals->copyFilterProc == NULL) || + CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */ + { + /* Either there's no filter proc OR the filter proc says to use this item */ + + /* We have an item. Is it a file or directory? */ + if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) + { + /* We have a directory */ + + /* Create a new directory at the destination. No errors allowed! */ + theGlobals->error = DirCreate(theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName, &newDirID); + if ( theGlobals->error == noErr ) + { + /* Save the current source directory ID where we can get it when we come back + ** from recursion land. */ + currentSrcDirID = theGlobals->myCPB.dirInfo.ioDrDirID; + + /* Dive again (copy the directory level we just found below this one) */ + CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals); + + if ( !theGlobals->bailout ) + { + /* Copy comment from old to new directory. */ + /* Ignore the result because we really don't care if it worked or not. */ + (void) DTCopyComment(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL); + + /* Copy directory attributes (dates, etc.) to newDirID. */ + /* No errors allowed */ + theGlobals->error = CopyFileMgrAttributes(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL, true); + + /* handle any errors from CopyFileMgrAttributes */ + if ( theGlobals->error != noErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp, + theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, + theGlobals->destinationVRefNum, newDirID, NULL); + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + } + else /* error handling for DirCreate */ + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp, + theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, + theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName); + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + + if ( !theGlobals->bailout ) + { + /* clear error return on way back if we aren't bailing out */ + theGlobals->error = noErr; + } + } + else + { + /* We have a file, so copy it */ + + theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum, + theGlobals->myCPB.hFileInfo.ioFlParID, + theGlobals->itemName, + theGlobals->destinationVRefNum, + dstDirID, + NULL, + NULL, + theGlobals->copyBuffer, + theGlobals->bufferSize, + false); + + /* handle any errors from FileCopy */ + if ( theGlobals->error != noErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, fileCopyOp, + theGlobals->myCPB.hFileInfo.ioVRefNum, theGlobals->myCPB.hFileInfo.ioFlParID, theGlobals->itemName, + theGlobals->destinationVRefNum, dstDirID, NULL); + if ( !theGlobals->bailout ) + { + /* If the CopyErrProc handled the problem, clear the error here */ + theGlobals->error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + } + } + else + { /* error handling for PBGetCatInfo */ + /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */ + if ( theGlobals->error != fnfErr ) + { + if ( theGlobals->errorHandler != NULL ) + { + theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp, + theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL); + if ( !theGlobals->bailout ) + { + /* If the CopyErrProc handled the problem, clear the error here */ + theGlobals->error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + theGlobals->bailout = true; + } + } + } + ++index; /* prepare to get next item */ + } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */ +} + +/*****************************************************************************/ + +pascal OSErr FilteredDirectoryCopy(short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler, + CopyFilterProcPtr copyFilterProc, ConstStr255Param newName ); +/* ¦ Make a copy of a directory structure in a new location with item filtering. + The FilteredDirectoryCopy function makes a copy of a directory + structure in a new location. If copyBufferPtr <> NIL, it points to + a buffer of copyBufferSize that is used to copy files data. The + larger the supplied buffer, the faster the copy. If + copyBufferPtr = NIL, then this routine allocates a buffer in the + application heap. If you pass a copy buffer to this routine, make + its size a multiple of 512 ($200) bytes for optimum performance. + + The optional copyFilterProc parameter lets a routine you define + decide what files or directories are copied to the destination. + + FilteredDirectoryCopy normally creates a new directory *in* the + specified destination directory and copies the source directory's + content into the new directory. However, if root parent directory + (fsRtParID) is passed as the dstDirID parameter and NULL is + passed as the dstName parameter, DirectoryCopy renames the + destination volume to the source directory's name (truncating + if the name is longer than 27 characters) and copies the source + directory's content into the destination volume's root directory. + This special case is supported by FilteredDirectoryCopy, but + not by FSpFilteredDirectoryCopy since with FSpFilteredDirectoryCopy, + the dstName parameter can not be NULL. + + srcVRefNum input: Source volume specification. + srcDirID input: Source directory ID. + srcName input: Source directory name, or nil if + srcDirID specifies the directory. + dstVRefNum input: Destination volume specification. + dstDirID input: Destination directory ID. + dstName input: Destination directory name, or nil if + dstDirID specifies the directory. + copyBufferPtr input: Points to a buffer of copyBufferSize that + is used the i/o buffer for the copy or + nil if you want DirectoryCopy to allocate its + own buffer in the application heap. + copyBufferSize input: The size of the buffer pointed to + by copyBufferPtr. + preflight input: If true, DirectoryCopy makes sure there are + enough allocation blocks on the destination + volume to hold the directory's files before + starting the copy. + copyErrHandler input: A pointer to the routine you want called if an + error condition is detected during the copy, or + nil if you don't want to handle error conditions. + If you don't handle error conditions, the first + error will cause the copy to quit and + DirectoryCopy will return the error. + Error handling is recommended... + copyFilterProc input: A pointer to the filter routine you want called + for each item in the source directory, or NULL + if you don't want to filter. + + Result Codes + noErr 0 No error + readErr Ð19 Driver does not respond to read requests + writErr Ð20 Driver does not respond to write requests + badUnitErr Ð21 Driver reference number does not + match unit table + unitEmptyErr Ð22 Driver reference number specifies a + nil handle in unit table + abortErr Ð27 Request aborted by KillIO + notOpenErr Ð28 Driver not open + dskFulErr -34 Destination volume is full + nsvErr -35 No such volume + ioErr -36 I/O error + bdNamErr -37 Bad filename + tmfoErr -42 Too many files open + fnfErr -43 Source file not found, or destination + directory does not exist + wPrErr -44 Volume locked by hardware + fLckdErr -45 File is locked + vLckdErr -46 Destination volume is read-only + fBsyErr -47 The source or destination file could + not be opened with the correct access + modes + dupFNErr -48 Destination file already exists + opWrErr -49 File already open for writing + paramErr -50 No default volume or function not + supported by volume + permErr -54 File is already open and cannot be opened using specified deny modes + memFullErr -108 Copy buffer could not be allocated + dirNFErr -120 Directory not found or incomplete pathname + wrgVolTypErr -123 Function not supported by volume + afpAccessDenied -5000 User does not have the correct access + afpDenyConflict -5006 The source or destination file could + not be opened with the correct access + modes + afpObjectTypeErr -5025 Source is a directory, directory not found + or incomplete pathname + + __________ + + Also see: CopyErrProcPtr, CopyFilterProcPtr, FSpFilteredDirectoryCopy, + DirectoryCopy, FSpDirectoryCopy, FileCopy, FSpFileCopy +*/ + +/*****************************************************************************/ + +pascal OSErr FilteredDirectoryCopy(short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler, + CopyFilterProcPtr copyFilterProc, ConstStr255Param newName) +{ + EnumerateGlobals theGlobals; + Boolean isDirectory; + OSErr error; + Boolean ourCopyBuffer = false; + Str63 srcDirName, oldDiskName; + Boolean spaceOK; + + /* Make sure a copy buffer is allocated. */ + if ( copyBufferPtr == NULL ) + { + /* The caller didn't supply a copy buffer so grab one from the application heap. + ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer. + ** If 512 bytes aren't available, we're in trouble. */ + copyBufferSize = dirCopyBigCopyBuffSize; + copyBufferPtr = NewPtr(copyBufferSize); + if ( copyBufferPtr == NULL ) + { + copyBufferSize = dirCopyMinCopyBuffSize; + copyBufferPtr = NewPtr(copyBufferSize); + if ( copyBufferPtr == NULL ) + { + return ( memFullErr ); + } + } + ourCopyBuffer = true; + } + + /* Get the real dirID where we're copying from and make sure it is a directory. */ + error = GetDirectoryID(srcVRefNum, srcDirID, srcName, &srcDirID, &isDirectory); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !isDirectory ) + { + error = dirNFErr; + goto ErrorExit; + } + + /* Special case destination if it is the root parent directory. */ + /* Since you can't create the root directory, this is needed if */ + /* you want to copy a directory's content to a disk's root directory. */ + if ( (dstDirID == fsRtParID) && (dstName == NULL) ) + { + dstDirID = fsRtParID; + isDirectory = true; + error = noErr; + } + else + { + /* Get the real dirID where we're going to put the copy and make sure it is a directory. */ + error = GetDirectoryID(dstVRefNum, dstDirID, dstName, &dstDirID, &isDirectory); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !isDirectory ) + { + error = dirNFErr; + goto ErrorExit; + } + } + + /* Get the real vRefNum of both the source and destination */ + error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum); + if ( error != noErr ) + { + goto ErrorExit; + } + error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum); + if ( error != noErr ) + { + goto ErrorExit; + } + + if ( preflight ) + { + error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK); + if ( error != noErr ) + { + goto ErrorExit; + } + if ( !spaceOK ) + { + error = dskFulErr; /* not enough room on destination */ + goto ErrorExit; + } + } + + /* Create the new directory in the destination directory with the */ + /* same name as the source directory. */ + /* + if newName is not empty use it rather than the original dir name. + */ + if ( newName[0] == 0 ) + { + error = GetDirName(srcVRefNum, srcDirID, srcDirName); + if ( error != noErr ) + { + goto ErrorExit; + } + } + else + { + memcpy(srcDirName, newName, 32 ); + + } + /* Again, special case destination if the destination is the */ + /* root parent directory. This time, we'll rename the disk to */ + /* the source directory name. */ + if ( dstDirID == fsRtParID ) + { + /* Get the current name of the destination disk */ + error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName); + if ( error == noErr ) + { + /* Shorten the name if it's too long to be the volume name */ + TruncPString(srcDirName, srcDirName, 27); + + /* Rename the disk */ + error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName); + /* and copy to the root directory */ + dstDirID = fsRtDirID; + } + } + else + { + error = DirCreate(dstVRefNum, dstDirID, srcDirName, &dstDirID); + } + if ( error != noErr ) + { + /* handle any errors from DirCreate */ + if ( copyErrHandler != NULL ) + { + if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp, + srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, srcDirName) ) + { + goto ErrorExit; + } + else + { + /* If the CopyErrProc handled the problem, clear the error here */ + /* and continue */ + error = noErr; + } + } + else + { + /* If you don't handle the errors with an error handler, */ + /* then the copy stops here. */ + goto ErrorExit; + } + } + + /* dstDirID is now the newly created directory! */ + + /* Set up the globals we need to access from the recursive routine. */ + theGlobals.copyBuffer = (Ptr)copyBufferPtr; + theGlobals.bufferSize = copyBufferSize; + theGlobals.destinationVRefNum = dstVRefNum; /* so we can get to it always */ + theGlobals.myCPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName; + theGlobals.myCPB.hFileInfo.ioVRefNum = srcVRefNum; + theGlobals.errorHandler = copyErrHandler; + theGlobals.bailout = false; + theGlobals.copyFilterProc = copyFilterProc; + + /* Here we go into recursion land... */ + CopyLevel(srcDirID, dstDirID, &theGlobals); + error = theGlobals.error; /* get the result */ + + if ( !theGlobals.bailout ) + { + /* Copy comment from source to destination directory. */ + /* Ignore the result because we really don't care if it worked or not. */ + (void) DTCopyComment(srcVRefNum, srcDirID, NULL, dstVRefNum, dstDirID, NULL); + + /* Copy the File Manager attributes */ + error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, NULL, true); + + /* handle any errors from CopyFileMgrAttributes */ + if ( (error != noErr) && (copyErrHandler != NULL) ) + { + theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp, + srcVRefNum, srcDirID, NULL, + dstVRefNum, dstDirID, NULL); + } + } + +ErrorExit: + /* Get rid of the copy buffer if we allocated it. */ + if ( ourCopyBuffer ) + { + DisposePtr((Ptr)copyBufferPtr); + } + + return ( error ); +} + + +/*****************************************************************************/ + + +pascal OSErr MacFSpDirectoryCopyRename(const FSSpec *srcSpec, + const FSSpec *dstSpec, + ConstStr255Param newName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler) +{ + return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, + dstSpec->vRefNum, dstSpec->parID, dstSpec->name, + copyBufferPtr, copyBufferSize, preflight, + copyErrHandler, NULL, newName) ); +} diff --git a/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h new file mode 100644 index 00000000..361c820e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/macDirectoryCopy.h @@ -0,0 +1,158 @@ +/* +** Apple Macintosh Developer Technical Support +** +** DirectoryCopy: A robust, general purpose directory copy routine. +** +** by Jim Luther, Apple Developer Technical Support Emeritus +** +** File: DirectoryCopy.h +** +** Copyright © 1992-1998 Apple Computer, Inc. +** All rights reserved. +** +** You may incorporate this sample code into your applications without +** restriction, though the sample code has been provided "AS IS" and the +** responsibility for its operation is 100% yours. However, what you are +** not permitted to do is to redistribute the source as "DSC Sample Code" +** after having made changes. If you're going to re-distribute the source, +** we require that you make it clear in the source that the code was +** descended from Apple Sample Code, but that you've made changes. +*/ + +// Modified to allow renaming the destination folder + +#ifndef __MACDIRECTORYCOPY__ +#define __MACDIRECTORYCOPY__ + +#include +#include + +#include "Optimization.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef pascal Boolean (*CopyErrProcPtr) (OSErr error, + short failedOperation, + short srcVRefNum, + long srcDirID, + ConstStr255Param srcName, + short dstVRefNum, + long dstDirID, + ConstStr255Param dstName); +/* ¦ Prototype for the CopyErrProc function DirectoryCopy calls. + This is the prototype for the CopyErrProc function DirectoryCopy + calls if an error condition is detected sometime during the copy. If + CopyErrProc returns false, then DirectoryCopy attempts to continue with + the directory copy operation. If CopyErrProc returns true, then + DirectoryCopy stops the directory copy operation. + + error input: The error result code that caused CopyErrProc to + be called. + failedOperation input: The operation that returned an error to + DirectoryCopy. + srcVRefNum input: Source volume specification. + srcDirID input: Source directory ID. + srcName input: Source file or directory name, or nil if + srcDirID specifies the directory. + dstVRefNum input: Destination volume specification. + dstDirID input: Destination directory ID. + dstName input: Destination file or directory name, or nil if + dstDirID specifies the directory. + + __________ + + Also see: FilteredDirectoryCopy, FSpFilteredDirectoryCopy, DirectoryCopy, FSpDirectoryCopy +*/ + +pascal OSErr MacFSpDirectoryCopyRename(const FSSpec *srcSpec, + const FSSpec *dstSpec, + ConstStr255Param newName, + void *copyBufferPtr, + long copyBufferSize, + Boolean preflight, + CopyErrProcPtr copyErrHandler); +/* ¦ Make a copy of a directory structure in a new location. + The FSpDirectoryCopy function makes a copy of a directory structure in a + new location. If copyBufferPtr <> NIL, it points to a buffer of + copyBufferSize that is used to copy files data. The larger the + supplied buffer, the faster the copy. If copyBufferPtr = NIL, then this + routine allocates a buffer in the application heap. If you pass a + copy buffer to this routine, make its size a multiple of 512 + ($200) bytes for optimum performance. + + srcSpec input: An FSSpec record specifying the directory to copy. + dstSpec input: An FSSpec record specifying destination directory + of the copy. + copyBufferPtr input: Points to a buffer of copyBufferSize that + is used the i/o buffer for the copy or + nil if you want DirectoryCopy to allocate its + own buffer in the application heap. + copyBufferSize input: The size of the buffer pointed to + by copyBufferPtr. + preflight input: If true, FSpDirectoryCopy makes sure there are + enough allocation blocks on the destination + volume to hold the directory's files before + starting the copy. + copyErrHandler input: A pointer to the routine you want called if an + error condition is detected during the copy, or + nil if you don't want to handle error conditions. + If you don't handle error conditions, the first + error will cause the copy to quit and + DirectoryCopy will return the error. + Error handling is recommended... + + Result Codes + noErr 0 No error + readErr Ð19 Driver does not respond to read requests + writErr Ð20 Driver does not respond to write requests + badUnitErr Ð21 Driver reference number does not + match unit table + unitEmptyErr Ð22 Driver reference number specifies a + nil handle in unit table + abortErr Ð27 Request aborted by KillIO + notOpenErr Ð28 Driver not open + dskFulErr -34 Destination volume is full + nsvErr -35 No such volume + ioErr -36 I/O error + bdNamErr -37 Bad filename + tmfoErr -42 Too many files open + fnfErr -43 Source file not found, or destination + directory does not exist + wPrErr -44 Volume locked by hardware + fLckdErr -45 File is locked + vLckdErr -46 Destination volume is read-only + fBsyErr -47 The source or destination file could + not be opened with the correct access + modes + dupFNErr -48 Destination file already exists + opWrErr -49 File already open for writing + paramErr -50 No default volume or function not + supported by volume + permErr -54 File is already open and cannot be opened using specified deny modes + memFullErr -108 Copy buffer could not be allocated + dirNFErr -120 Directory not found or incomplete pathname + wrgVolTypErr -123 Function not supported by volume + afpAccessDenied -5000 User does not have the correct access + afpDenyConflict -5006 The source or destination file could + not be opened with the correct access + modes + afpObjectTypeErr -5025 Source is a directory, directory not found + or incomplete pathname + + __________ + + Also see: CopyErrProcPtr, DirectoryCopy, FilteredDirectoryCopy, + FSpFilteredDirectoryCopy, FileCopy, FSpFileCopy +*/ + +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#include "OptimizationEnd.h" + +#endif /* __DIRECTORYCOPY__ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h b/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h new file mode 100644 index 00000000..768cb38f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppDirectoryServiceDefs.h @@ -0,0 +1,120 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen conrad@ingress.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsAppDirectoryServiceDefs_h___ +#define nsAppDirectoryServiceDefs_h___ + +//======================================================================================== +// +// Defines property names for directories available from standard nsIDirectoryServiceProviders. +// These keys are not guaranteed to exist because the nsIDirectoryServiceProviders which +// provide them are optional. +// +// Keys whose definition ends in "DIR" or "FILE" return a single nsIFile (or subclass). +// Keys whose definition ends in "LIST" return an nsISimpleEnumerator which enumerates a +// list of file objects. +// +// System and XPCOM level properties are defined in nsDirectoryServiceDefs.h. +// +//======================================================================================== + + +// -------------------------------------------------------------------------------------- +// Files and directories which exist on a per-product basis +// -------------------------------------------------------------------------------------- + +#define NS_APP_APPLICATION_REGISTRY_FILE "AppRegF" +#define NS_APP_APPLICATION_REGISTRY_DIR "AppRegD" + +#define NS_APP_DEFAULTS_50_DIR "DefRt" // The root dir of all defaults dirs +#define NS_APP_PREF_DEFAULTS_50_DIR "PrfDef" +#define NS_APP_PROFILE_DEFAULTS_50_DIR "profDef" // The profile defaults of the "current" + // locale. Should be first choice. +#define NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR "ProfDefNoLoc" // The profile defaults of the "default" + // installed locale. Second choice + // when above is not available. + +#define NS_APP_USER_PROFILES_ROOT_DIR "DefProfRt" // The dir where user profile dirs get created. + +#define NS_APP_RES_DIR "ARes" +#define NS_APP_CHROME_DIR "AChrom" +#define NS_APP_PLUGINS_DIR "APlugns" // Deprecated - use NS_APP_PLUGINS_DIR_LIST +#define NS_APP_SEARCH_DIR "SrchPlugns" + +#define NS_APP_CHROME_DIR_LIST "AChromDL" +#define NS_APP_PLUGINS_DIR_LIST "APluginsDL" + +// -------------------------------------------------------------------------------------- +// Files and directories which exist on a per-profile basis +// These locations are typically provided by the profile mgr +// -------------------------------------------------------------------------------------- + +// In a shared profile environment, prefixing a profile-relative +// key with NS_SHARED returns a location that is shared by +// other users of the profile. Without this prefix, the consumer +// has exclusive access to this location. + +#define NS_SHARED "SHARED" + +#define NS_APP_PREFS_50_DIR "PrefD" // Directory which contains user prefs +#define NS_APP_PREFS_50_FILE "PrefF" +#define NS_APP_PREFS_DEFAULTS_DIR_LIST "PrefDL" + +#define NS_APP_USER_PROFILE_50_DIR "ProfD" + +#define NS_APP_USER_CHROME_DIR "UChrm" + +#define NS_APP_LOCALSTORE_50_FILE "LclSt" +#define NS_APP_HISTORY_50_FILE "UHist" +#define NS_APP_USER_PANELS_50_FILE "UPnls" +#define NS_APP_USER_MIMETYPES_50_FILE "UMimTyp" +#define NS_APP_CACHE_PARENT_DIR "cachePDir" + +#define NS_APP_BOOKMARKS_50_FILE "BMarks" + +#define NS_APP_DOWNLOADS_50_FILE "DLoads" + +#define NS_APP_SEARCH_50_FILE "SrchF" + +#define NS_APP_MAIL_50_DIR "MailD" +#define NS_APP_IMAP_MAIL_50_DIR "IMapMD" +#define NS_APP_NEWS_50_DIR "NewsD" +#define NS_APP_MESSENGER_FOLDER_CACHE_50_DIR "MFCaD" + +#define NS_APP_INSTALL_CLEANUP_DIR "XPIClnupD" //location of xpicleanup.dat xpicleanup.exe +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp new file mode 100644 index 00000000..9d4f785d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.cpp @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAppFileLocationProvider.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIAtom.h" +#include "nsILocalFile.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" +#include "prenv.h" +#include "nsCRT.h" + +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +#include +#include +#include +#include +#include "nsILocalFileMac.h" +#elif defined(XP_OS2) +#define INCL_DOSPROCESS +#define INCL_DOSMODULEMGR +#include +#elif defined(XP_WIN) +#include +#include +#elif defined(XP_UNIX) +#include +#include +#include +#elif defined(XP_BEOS) +#include +#include +#include +#endif + + +// WARNING: These hard coded names need to go away. They need to +// come from localizable resources + +#if defined(XP_MAC) || defined(XP_MACOSX) +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("Application Registry") +#define ESSENTIAL_FILES NS_LITERAL_CSTRING("Essential Files") +#elif defined(XP_WIN) || defined(XP_OS2) +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("registry.dat") +#else +#define APP_REGISTRY_NAME NS_LITERAL_CSTRING("appreg") +#endif + +// define default product directory +#ifdef XP_MAC +#define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING("Mozilla") +#else +#define DEFAULT_PRODUCT_DIR NS_LITERAL_CSTRING(MOZ_USER_DIR) +#endif + +// Locally defined keys used by nsAppDirectoryEnumerator +#define NS_ENV_PLUGINS_DIR "EnvPlugins" // env var MOZ_PLUGIN_PATH +#define NS_USER_PLUGINS_DIR "UserPlugins" + +#if defined(XP_MAC) || defined(XP_MACOSX) +#define NS_MACOSX_USER_PLUGIN_DIR "OSXUserPlugins" +#define NS_MACOSX_LOCAL_PLUGIN_DIR "OSXLocalPlugins" +#define NS_MAC_CLASSIC_PLUGIN_DIR "MacSysPlugins" +#endif + +#if defined(XP_MAC) +#define DEFAULTS_DIR_NAME NS_LITERAL_CSTRING("Defaults") +#define DEFAULTS_PREF_DIR_NAME NS_LITERAL_CSTRING("Pref") +#define DEFAULTS_PROFILE_DIR_NAME NS_LITERAL_CSTRING("Profile") +#define RES_DIR_NAME NS_LITERAL_CSTRING("Res") +#define CHROME_DIR_NAME NS_LITERAL_CSTRING("Chrome") +#define PLUGINS_DIR_NAME NS_LITERAL_CSTRING("Plug-ins") +#define SEARCH_DIR_NAME NS_LITERAL_CSTRING("Search Plugins") +#else +#define DEFAULTS_DIR_NAME NS_LITERAL_CSTRING("defaults") +#define DEFAULTS_PREF_DIR_NAME NS_LITERAL_CSTRING("pref") +#define DEFAULTS_PROFILE_DIR_NAME NS_LITERAL_CSTRING("profile") +#define RES_DIR_NAME NS_LITERAL_CSTRING("res") +#define CHROME_DIR_NAME NS_LITERAL_CSTRING("chrome") +#define PLUGINS_DIR_NAME NS_LITERAL_CSTRING("plugins") +#define SEARCH_DIR_NAME NS_LITERAL_CSTRING("searchplugins") +#endif + +//***************************************************************************** +// nsAppFileLocationProvider::Constructor/Destructor +//***************************************************************************** + +nsAppFileLocationProvider::nsAppFileLocationProvider() +{ +} + +//***************************************************************************** +// nsAppFileLocationProvider::nsISupports +//***************************************************************************** + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsAppFileLocationProvider, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2) + +//***************************************************************************** +// nsAppFileLocationProvider::nsIDirectoryServiceProvider +//***************************************************************************** + +NS_IMETHODIMP +nsAppFileLocationProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + NS_ENSURE_ARG(prop); + *_retval = nsnull; + *persistant = PR_TRUE; + +#if (defined (XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + short foundVRefNum; + SInt32 foundDirID; + FSSpec fileSpec; + nsCOMPtr macFile; +#endif + + if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_DIR) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_APP_APPLICATION_REGISTRY_FILE) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendNative(APP_REGISTRY_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_DEFAULTS_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_PREF_DEFAULTS_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_PREF_DIR_NAME); + } + } + else if (nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_50_DIR) == 0 || + nsCRT::strcmp(prop, NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + rv = localFile->AppendRelativeNativePath(DEFAULTS_DIR_NAME); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(DEFAULTS_PROFILE_DIR_NAME); + } + } + else if (nsCRT::strcmp(prop, NS_APP_USER_PROFILES_ROOT_DIR) == 0) + { + rv = GetDefaultUserProfileRoot(getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_APP_RES_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(RES_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_CHROME_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(CHROME_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME); + } +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + else if (nsCRT::strcmp(prop, NS_MACOSX_USER_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kUserDomain, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } + else if (nsCRT::strcmp(prop, NS_MACOSX_LOCAL_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kLocalDomain, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } + else if (nsCRT::strcmp(prop, NS_MAC_CLASSIC_PLUGIN_DIR) == 0) + { + if (!(::FindFolder(kOnAppropriateDisk, + kInternetPlugInFolderType, + kDontCreateFolder, &foundVRefNum, &foundDirID)) && + !(::FSMakeFSSpec(foundVRefNum, foundDirID, "\p", &fileSpec))) { + rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(rv)) + localFile = macFile; + } + } +#else + else if (nsCRT::strcmp(prop, NS_ENV_PLUGINS_DIR) == 0) + { + NS_ERROR("Don't use nsAppFileLocationProvider::GetFile(NS_ENV_PLUGINS_DIR, ...). " + "Use nsAppFileLocationProvider::GetFiles(...)."); + const char *pathVar = PR_GetEnv("VBOX_XPCOM_PLUGIN_PATH"); + if (pathVar) + rv = NS_NewNativeLocalFile(nsDependentCString(pathVar), PR_TRUE, getter_AddRefs(localFile)); + } + else if (nsCRT::strcmp(prop, NS_USER_PLUGINS_DIR) == 0) + { + rv = GetProductDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(PLUGINS_DIR_NAME); + } +#endif + else if (nsCRT::strcmp(prop, NS_APP_SEARCH_DIR) == 0) + { + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendRelativeNativePath(SEARCH_DIR_NAME); + } + else if (nsCRT::strcmp(prop, NS_APP_INSTALL_CLEANUP_DIR) == 0) + { + // This is cloned so that embeddors will have a hook to override + // with their own cleanup dir. See bugzilla bug #105087 + rv = CloneMozBinDirectory(getter_AddRefs(localFile)); +#ifdef XP_MAC + if (NS_SUCCEEDED(rv)) + rv = localFile->AppendNative(ESSENTIAL_FILES); +#endif + + } + + if (localFile && NS_SUCCEEDED(rv)) + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); + + return rv; +} + + +NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + nsresult rv; + + if (!mMozBinDirectory) + { + // Get the mozilla bin directory + // 1. Check the directory service first for NS_XPCOM_CURRENT_PROCESS_DIR + // This will be set if a directory was passed to NS_InitXPCOM + // 2. If that doesn't work, set it to be the current process directory + nsCOMPtr + directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return rv; + + rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory)); + if (NS_FAILED(rv)) { + rv = directoryService->Get(NS_OS_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mMozBinDirectory)); + if (NS_FAILED(rv)) + return rv; + } + } + + nsCOMPtr aFile; + rv = mMozBinDirectory->Clone(getter_AddRefs(aFile)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr lfile = do_QueryInterface (aFile); + if (!lfile) + return NS_ERROR_FAILURE; + + NS_IF_ADDREF(*aLocalFile = lfile); + return NS_OK; +} + + +//---------------------------------------------------------------------------------------- +// GetProductDirectory - Gets the directory which contains the application data folder +// +// UNIX : ~/.mozilla/ +// WIN : \Mozilla +// Mac : :Documents:Mozilla: +//---------------------------------------------------------------------------------------- +NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + + nsresult rv; + PRBool exists; + nsCOMPtr localDir; + +#if defined(XP_MAC) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + OSErr err; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + const char *prop = (!err && response >= 0x00001000) ? NS_MAC_USER_LIB_DIR : NS_MAC_DOCUMENTS_DIR; + rv = directoryService->Get(prop, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_MACOSX) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + FSRef fsRef; + OSErr err = ::FSFindFolder(kUserDomain, kDomainLibraryFolderType, kCreateFolder, &fsRef); + if (err) return NS_ERROR_FAILURE; + NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(localDir)); + if (!localDir) return NS_ERROR_FAILURE; + nsCOMPtr localDirMac(do_QueryInterface(localDir)); + rv = localDirMac->InitWithFSRef(&fsRef); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_OS2) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = directoryService->Get(NS_OS2_HOME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_WIN) + nsCOMPtr directoryService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = directoryService->Get(NS_WIN_APPDATA_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + if (NS_SUCCEEDED(rv)) + rv = localDir->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + // On some Win95 machines, NS_WIN_APPDATA_DIR does not exist - revert to NS_WIN_WINDOWS_DIR + localDir = nsnull; + rv = directoryService->Get(NS_WIN_WINDOWS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(localDir)); + } + if (NS_FAILED(rv)) return rv; +#elif defined(XP_UNIX) + rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), PR_TRUE, getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#elif defined(XP_BEOS) + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + return NS_ERROR_FAILURE; + path[len] = '/'; + path[len+1] = '\0'; + rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_TRUE, getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; +#else +#error dont_know_how_to_get_product_dir_on_your_platform +#endif + + rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR); + if (NS_FAILED(rv)) return rv; + rv = localDir->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (NS_FAILED(rv)) return rv; + + *aLocalFile = localDir; + NS_ADDREF(*aLocalFile); + + return rv; +} + + +//---------------------------------------------------------------------------------------- +// GetDefaultUserProfileRoot - Gets the directory which contains each user profile dir +// +// UNIX : ~/.mozilla/ +// WIN : \Mozilla\Profiles +// Mac : :Documents:Mozilla:Profiles: +//---------------------------------------------------------------------------------------- +NS_METHOD nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsILocalFile **aLocalFile) +{ + NS_ENSURE_ARG_POINTER(aLocalFile); + + nsresult rv; + nsCOMPtr localDir; + + rv = GetProductDirectory(getter_AddRefs(localDir)); + if (NS_FAILED(rv)) return rv; + +#if defined(XP_MAC) || defined(XP_MACOSX) || defined(XP_OS2) || defined(XP_WIN) + // These 3 platforms share this part of the path - do them as one + rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles")); + if (NS_FAILED(rv)) return rv; + + PRBool exists; + rv = localDir->Exists(&exists); + if (NS_SUCCEEDED(rv) && !exists) + rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775); + if (NS_FAILED(rv)) return rv; +#endif + + *aLocalFile = localDir; + NS_ADDREF(*aLocalFile); + + return rv; +} + +//***************************************************************************** +// nsAppFileLocationProvider::nsIDirectoryServiceProvider2 +//***************************************************************************** + +class nsAppDirectoryEnumerator : public nsISimpleEnumerator +{ + public: + NS_DECL_ISUPPORTS + + /** + * aKeyList is a null-terminated list of properties which are provided by aProvider + * They do not need to be publicly defined keys. + */ + nsAppDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider, + const char* aKeyList[]) : + mProvider(aProvider), + mCurrentKey(aKeyList) + { + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + while (!mNext && *mCurrentKey) + { + PRBool dontCare; + nsCOMPtr testFile; + (void)mProvider->GetFile(*mCurrentKey++, &dontCare, getter_AddRefs(testFile)); + // Don't return a file which does not exist. + PRBool exists; + if (testFile && NS_SUCCEEDED(testFile->Exists(&exists)) && exists) + mNext = testFile; + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + PRBool hasMore; + HasMoreElements(&hasMore); + if (!hasMore) + return NS_ERROR_FAILURE; + + *result = mNext; + NS_IF_ADDREF(*result); + mNext = nsnull; + + return *result ? NS_OK : NS_ERROR_FAILURE; + } + + // Virtual destructor since subclass nsPathsDirectoryEnumerator + // does not re-implement Release() + + virtual ~nsAppDirectoryEnumerator() + { + } + + protected: + nsIDirectoryServiceProvider *mProvider; + const char** mCurrentKey; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsAppDirectoryEnumerator, nsISimpleEnumerator) + +/* nsPathsDirectoryEnumerator and PATH_SEPARATOR + * are not used on MacOS/X. */ + +#if defined(XP_WIN) || defined(XP_OS2)/* Win32, Win16, and OS/2 */ +#define PATH_SEPARATOR ';' +#else /*if defined(XP_UNIX) || defined(XP_BEOS)*/ +#define PATH_SEPARATOR ':' +#endif + +class nsPathsDirectoryEnumerator : public nsAppDirectoryEnumerator +{ + public: + /** + * aKeyList is a null-terminated list. + * The first element is a path list. + * The remainder are properties provided by aProvider. + * They do not need to be publicly defined keys. + */ + nsPathsDirectoryEnumerator(nsIDirectoryServiceProvider *aProvider, + const char* aKeyList[]) : + nsAppDirectoryEnumerator(aProvider, aKeyList+1), + mEndPath(aKeyList[0]) + { + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + if (mEndPath) + while (!mNext && *mEndPath) + { + const char *pathVar = mEndPath; + do { ++mEndPath; } while (*mEndPath && *mEndPath != PATH_SEPARATOR); + + nsCOMPtr localFile; + NS_NewNativeLocalFile(Substring(pathVar, mEndPath), + PR_TRUE, + getter_AddRefs(localFile)); + if (*mEndPath == PATH_SEPARATOR) + ++mEndPath; + // Don't return a "file" (directory) which does not exist. + PRBool exists; + if (localFile && + NS_SUCCEEDED(localFile->Exists(&exists)) && + exists) + mNext = localFile; + } + if (mNext) + *result = PR_TRUE; + else + nsAppDirectoryEnumerator::HasMoreElements(result); + + return NS_OK; + } + + protected: + const char *mEndPath; +}; + +NS_IMETHODIMP +nsAppFileLocationProvider::GetFiles(const char *prop, nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + nsresult rv = NS_ERROR_FAILURE; + + if (!nsCRT::strcmp(prop, NS_APP_PLUGINS_DIR_LIST)) + { +#if (defined(XP_MAC) || defined(XP_MACOSX)) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) + static const char* osXKeys[] = { NS_APP_PLUGINS_DIR, NS_MACOSX_USER_PLUGIN_DIR, NS_MACOSX_LOCAL_PLUGIN_DIR, nsnull }; + static const char* os9Keys[] = { NS_APP_PLUGINS_DIR, NS_MAC_CLASSIC_PLUGIN_DIR, nsnull }; + static const char** keys; + + if (!keys) { + OSErr err; + SInt32 response; + err = ::Gestalt(gestaltSystemVersion, &response); + keys = (!err && response >= 0x00001000) ? osXKeys : os9Keys; + } + + *_retval = new nsAppDirectoryEnumerator(this, keys); +#else + static const char* keys[] = { nsnull, NS_APP_PLUGINS_DIR, nsnull }; + if (!keys[0] && !(keys[0] = PR_GetEnv("VBOX_XPCOM_PLUGIN_PATH"))) { + static const char nullstr = 0; + keys[0] = &nullstr; + } + *_retval = new nsPathsDirectoryEnumerator(this, keys); +#endif + NS_IF_ADDREF(*_retval); + rv = *_retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h new file mode 100644 index 00000000..677ae00e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsAppFileLocationProvider.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIDirectoryService.h" +#include "nsILocalFile.h" + +class nsIFile; + +//***************************************************************************** +// class nsAppFileLocationProvider +//***************************************************************************** + +class nsAppFileLocationProvider : public nsIDirectoryServiceProvider2 +{ +public: + nsAppFileLocationProvider(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + +private: + ~nsAppFileLocationProvider() {} + +protected: + NS_METHOD CloneMozBinDirectory(nsILocalFile **aLocalFile); + NS_METHOD GetProductDirectory(nsILocalFile **aLocalFile); + NS_METHOD GetDefaultUserProfileRoot(nsILocalFile **aLocalFile); + + nsCOMPtr mMozBinDirectory; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp new file mode 100644 index 00000000..bc60eea3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.cpp @@ -0,0 +1,663 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 file contains implementations of the nsIBinaryInputStream and + * nsIBinaryOutputStream interfaces. Together, these interfaces allows reading + * and writing of primitive data types (integers, floating-point values, + * booleans, etc.) to a stream in a binary, untagged, fixed-endianness format. + * This might be used, for example, to implement network protocols or to + * produce architecture-neutral binary disk files, i.e. ones that can be read + * and written by both big-endian and little-endian platforms. Output is + * written in big-endian order (high-order byte first), as this is traditional + * network order. + * + * @See nsIBinaryInputStream + * @See nsIBinaryOutputStream + */ +#include +#include "nsBinaryStream.h" +#include "nsCRT.h" +#include "nsIStreamBufferAccess.h" +#include "nsMemory.h" +#include "prlong.h" +#include "nsGenericFactory.h" + +NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream) + +NS_IMETHODIMP +nsBinaryOutputStream::Flush() { return mOutputStream->Flush(); } + +NS_IMETHODIMP +nsBinaryOutputStream::Close() { return mOutputStream->Close(); } + +NS_IMETHODIMP +nsBinaryOutputStream::Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) +{ + return mOutputStream->Write(aBuf, aCount, aActualBytes); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + return mOutputStream->IsNonBlocking(aNonBlocking); +} + +nsresult +nsBinaryOutputStream::WriteFully(const char *aBuf, PRUint32 aCount) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = mOutputStream->Write(aBuf, aCount, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != aCount) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream) +{ + NS_ENSURE_ARG_POINTER(aOutputStream); + mOutputStream = aOutputStream; + mBufferAccess = do_QueryInterface(aOutputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteBoolean(PRBool aBoolean) +{ + return Write8(aBoolean); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write8(PRUint8 aByte) +{ + return WriteFully((const char*)&aByte, sizeof aByte); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write16(PRUint16 a16) +{ + a16 = NS_SWAP16(a16); + return WriteFully((const char*)&a16, sizeof a16); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write32(PRUint32 a32) +{ + a32 = NS_SWAP32(a32); + return WriteFully((const char*)&a32, sizeof a32); +} + +NS_IMETHODIMP +nsBinaryOutputStream::Write64(PRUint64 a64) +{ + nsresult rv; + PRUint32 bytesWritten; + + a64 = NS_SWAP64(a64); + rv = Write(NS_REINTERPRET_CAST(char*, &a64), sizeof a64, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != sizeof a64) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteFloat(float aFloat) +{ + NS_ASSERTION(sizeof(float) == sizeof (PRUint32), + "False assumption about sizeof(float)"); + return Write32(*NS_REINTERPRET_CAST(PRUint32*, &aFloat)); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteDouble(double aDouble) +{ + NS_ASSERTION(sizeof(double) == sizeof(PRUint64), + "False assumption about sizeof(double)"); + return Write64(*NS_REINTERPRET_CAST(PRUint64*, &aDouble)); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteStringZ(const char *aString) +{ + PRUint32 length; + nsresult rv; + + length = strlen(aString); + rv = Write32(length); + if (NS_FAILED(rv)) return rv; + return WriteFully(aString, length); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteWStringZ(const PRUnichar* aString) +{ + PRUint32 length, byteCount; + nsresult rv; + + length = nsCRT::strlen(aString); + rv = Write32(length); + if (NS_FAILED(rv)) return rv; + + if (length == 0) + return NS_OK; + byteCount = length * sizeof(PRUnichar); + +#ifdef IS_BIG_ENDIAN + rv = WriteBytes(NS_REINTERPRET_CAST(const char*, aString), byteCount); +#else + // XXX use WriteSegments here to avoid copy! + PRUnichar *copy, temp[64]; + if (length <= 64) { + copy = temp; + } else { + copy = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc(byteCount)); + if (!copy) + return NS_ERROR_OUT_OF_MEMORY; + } + NS_ASSERTION((PRUptrdiff(aString) & 0x1) == 0, "aString not properly aligned"); + for (PRUint32 i = 0; i < length; i++) + copy[i] = NS_SWAP16(aString[i]); + rv = WriteBytes(NS_REINTERPRET_CAST(const char*, copy), byteCount); + if (copy != temp) + nsMemory::Free(copy); +#endif + + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteUtf8Z(const PRUnichar* aString) +{ + NS_NOTREACHED("WriteUtf8Z"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteBytes(const char *aString, PRUint32 aLength) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = Write(aString, aLength, &bytesWritten); + if (NS_FAILED(rv)) return rv; + if (bytesWritten != aLength) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteByteArray(PRUint8 *aBytes, PRUint32 aLength) +{ + return WriteBytes(NS_REINTERPRET_CAST(char *, aBytes), aLength); +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteObject(nsISupports* aObject, PRBool aIsStrongRef) +{ + NS_NOTREACHED("WriteObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteSingleRefObject(nsISupports* aObject) +{ + NS_NOTREACHED("WriteSingleRefObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + NS_NOTREACHED("WriteCompoundObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryOutputStream::WriteID(const nsIID& aIID) +{ + NS_NOTREACHED("WriteID"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP_(char*) +nsBinaryOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask) +{ + if (mBufferAccess) + return mBufferAccess->GetBuffer(aLength, aAlignMask); + return nsnull; +} + +NS_IMETHODIMP_(void) +nsBinaryOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength) +{ + if (mBufferAccess) + mBufferAccess->PutBuffer(aBuffer, aLength); +} + +NS_IMPL_ISUPPORTS3(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStream, nsIInputStream) + +NS_IMETHODIMP +nsBinaryInputStream::Available(PRUint32* aResult) +{ + return mInputStream->Available(aResult); +} + +NS_IMETHODIMP +nsBinaryInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + return mInputStream->Read(aBuffer, aCount, aNumRead); +} + + +// when forwarding ReadSegments to mInputStream, we need to make sure +// 'this' is being passed to the writer each time. To do this, we need +// a thunking function which keeps the real input stream around. + +// the closure wrapper +struct ReadSegmentsClosure { + nsIInputStream* mRealInputStream; + void* mRealClosure; + nsWriteSegmentFun mRealWriter; +}; + +// the thunking function +static NS_METHOD +ReadSegmentForwardingThunk(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + ReadSegmentsClosure* thunkClosure = + NS_REINTERPRET_CAST(ReadSegmentsClosure*, aClosure); + + return thunkClosure->mRealWriter(thunkClosure->mRealInputStream, + thunkClosure->mRealClosure, + aFromSegment, aToOffset, + aCount, aWriteCount); +} + + +NS_IMETHODIMP +nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + ReadSegmentsClosure thunkClosure = { this, closure, writer }; + + return mInputStream->ReadSegments(ReadSegmentForwardingThunk, &thunkClosure, count, _retval); +} + +NS_IMETHODIMP +nsBinaryInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + return mInputStream->IsNonBlocking(aNonBlocking); +} + +NS_IMETHODIMP +nsBinaryInputStream::Close() { return mInputStream->Close(); } + +NS_IMETHODIMP +nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream) +{ + NS_ENSURE_ARG_POINTER(aInputStream); + mInputStream = aInputStream; + mBufferAccess = do_QueryInterface(aInputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadBoolean(PRBool* aBoolean) +{ + PRUint8 byteResult; + nsresult rv = Read8(&byteResult); + *aBoolean = byteResult; + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read8(PRUint8* aByte) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, aByte), sizeof(*aByte), &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != 1) + return NS_ERROR_FAILURE; + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read16(PRUint16* a16) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a16), sizeof *a16, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a16) + return NS_ERROR_FAILURE; + *a16 = NS_SWAP16(*a16); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read32(PRUint32* a32) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a32), sizeof *a32, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a32) + return NS_ERROR_FAILURE; + *a32 = NS_SWAP32(*a32); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::Read64(PRUint64* a64) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, a64), sizeof *a64, &bytesRead); + if (NS_FAILED(rv)) return rv; + if (bytesRead != sizeof *a64) + return NS_ERROR_FAILURE; + *a64 = NS_SWAP64(*a64); + return rv; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadFloat(float* aFloat) +{ + NS_ASSERTION(sizeof(float) == sizeof (PRUint32), + "False assumption about sizeof(float)"); + return Read32(NS_REINTERPRET_CAST(PRUint32*, aFloat)); +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadDouble(double* aDouble) +{ + NS_ASSERTION(sizeof(double) == sizeof(PRUint64), + "False assumption about sizeof(double)"); + return Read64(NS_REINTERPRET_CAST(PRUint64*, aDouble)); +} + +static NS_METHOD +WriteSegmentToCString(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + nsACString* outString = NS_STATIC_CAST(nsACString*,aClosure); + + outString->Append(aFromSegment, aCount); + + *aWriteCount = aCount; + + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadCString(nsACString& aString) +{ + nsresult rv; + PRUint32 length, bytesRead; + + rv = Read32(&length); + if (NS_FAILED(rv)) return rv; + + aString.Truncate(); + rv = ReadSegments(WriteSegmentToCString, &aString, length, &bytesRead); + if (NS_FAILED(rv)) return rv; + + if (bytesRead != length) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +// sometimes, WriteSegmentToString will be handed an odd-number of +// bytes, which means we only have half of the last PRUnichar +struct WriteStringClosure { + PRUnichar *mWriteCursor; + PRPackedBool mHasCarryoverByte; + char mCarryoverByte; +}; + +// there are a few cases we have to account for here: +// * even length buffer, no carryover - easy, just append +// * odd length buffer, no carryover - the last byte needs to be saved +// for carryover +// * odd length buffer, with carryover - first byte needs to be used +// with the carryover byte, and +// the rest of the even length +// buffer is appended as normal +// * even length buffer, with carryover - the first byte needs to be +// used with the previous carryover byte. +// this gives you an odd length buffer, +// so you have to save the last byte for +// the next carryover + + +// same version of the above, but with correct casting and endian swapping +static NS_METHOD +WriteSegmentToString(nsIInputStream* aStream, + void *aClosure, + const char* aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount) +{ + NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?"); + NS_PRECONDITION(sizeof(PRUnichar) == 2, "We can't handle other sizes!"); + + WriteStringClosure* closure = NS_STATIC_CAST(WriteStringClosure*,aClosure); + PRUnichar *cursor = closure->mWriteCursor; + + // we're always going to consume the whole buffer no matter what + // happens, so take care of that right now.. that allows us to + // tweak aCount later. Do NOT move this! + *aWriteCount = aCount; + + // if the last Write had an odd-number of bytes read, then + if (closure->mHasCarryoverByte) { + // re-create the two-byte sequence we want to work with + char bytes[2] = { closure->mCarryoverByte, *aFromSegment }; + *cursor = *(PRUnichar*)bytes; + // Now the little endianness dance +#ifdef IS_LITTLE_ENDIAN + *cursor = (PRUnichar) NS_SWAP16(*cursor); +#endif + ++cursor; + + // now skip past the first byte of the buffer.. code from here + // can assume normal operations, but should not assume aCount + // is relative to the ORIGINAL buffer + ++aFromSegment; + --aCount; + + closure->mHasCarryoverByte = PR_FALSE; + } + + // this array is possibly unaligned... be careful how we access it! + const PRUnichar *unicodeSegment = + NS_REINTERPRET_CAST(const PRUnichar*, aFromSegment); + + // calculate number of full characters in segment (aCount could be odd!) + PRUint32 segmentLength = aCount / sizeof(PRUnichar); + + // copy all data into our aligned buffer. byte swap if necessary. + memcpy(cursor, unicodeSegment, segmentLength * sizeof(PRUnichar)); + PRUnichar *end = cursor + segmentLength; +#ifdef IS_LITTLE_ENDIAN + for (; cursor < end; ++cursor) + *cursor = (PRUnichar) NS_SWAP16(*cursor); +#endif + closure->mWriteCursor = end; + + // remember this is the modifed aCount and aFromSegment, + // so that will take into account the fact that we might have + // skipped the first byte in the buffer + if (aCount % sizeof(PRUnichar) != 0) { + // we must have had a carryover byte, that we'll need the next + // time around + closure->mCarryoverByte = aFromSegment[aCount - 1]; + closure->mHasCarryoverByte = PR_TRUE; + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsBinaryInputStream::ReadString(nsAString& aString) +{ + nsresult rv; + PRUint32 length, bytesRead; + + rv = Read32(&length); + if (NS_FAILED(rv)) return rv; + + // pre-allocate output buffer, and get direct access to buffer... + aString.SetLength(length); + nsAString::iterator start; + aString.BeginWriting(start); + + WriteStringClosure closure; + closure.mWriteCursor = start.get(); + closure.mHasCarryoverByte = PR_FALSE; + + rv = ReadSegments(WriteSegmentToString, &closure, + length*sizeof(PRUnichar), &bytesRead); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!"); + + if (bytesRead != length*sizeof(PRUnichar)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadBytes(PRUint32 aLength, char* *_rval) +{ + nsresult rv; + PRUint32 bytesRead; + char* s; + + s = NS_REINTERPRET_CAST(char*, nsMemory::Alloc(aLength)); + if (!s) + return NS_ERROR_OUT_OF_MEMORY; + + rv = Read(s, aLength, &bytesRead); + if (NS_FAILED(rv)) { + nsMemory::Free(s); + return rv; + } + if (bytesRead != aLength) { + nsMemory::Free(s); + return NS_ERROR_FAILURE; + } + + *_rval = s; + return NS_OK; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadByteArray(PRUint32 aLength, PRUint8* *_rval) +{ + return ReadBytes(aLength, NS_REINTERPRET_CAST(char **, _rval)); +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) +{ + NS_NOTREACHED("ReadObject"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsBinaryInputStream::ReadID(nsID *aResult) +{ + NS_NOTREACHED("ReadID"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP_(char*) +nsBinaryInputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask) +{ + if (mBufferAccess) + return mBufferAccess->GetBuffer(aLength, aAlignMask); + return nsnull; +} + +NS_IMETHODIMP_(void) +nsBinaryInputStream::PutBuffer(char* aBuffer, PRUint32 aLength) +{ + if (mBufferAccess) + mBufferAccess->PutBuffer(aBuffer, aLength); +} + diff --git a/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h new file mode 100644 index 00000000..7be46dc7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsBinaryStream.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsBinaryStream_h___ +#define nsBinaryStream_h___ + +#include "nsCOMPtr.h" +#include "nsAString.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsIStreamBufferAccess.h" + +#define NS_BINARYOUTPUTSTREAM_CID \ +{ /* 86c37b9a-74e7-4672-844e-6e7dd83ba484 */ \ + 0x86c37b9a, \ + 0x74e7, \ + 0x4672, \ + {0x84, 0x4e, 0x6e, 0x7d, 0xd8, 0x3b, 0xa4, 0x84} \ +} + +#define NS_BINARYOUTPUTSTREAM_CONTRACTID "@mozilla.org/binaryoutputstream;1" +#define NS_BINARYOUTPUTSTREAM_CLASSNAME "Binary Output Stream" + +// Derive from nsIObjectOutputStream so this class can be used as a superclass +// by nsObjectOutputStream. +class nsBinaryOutputStream : public nsIObjectOutputStream +{ +public: + nsBinaryOutputStream() {}; + // virtual dtor since subclasses call our Release() + virtual ~nsBinaryOutputStream() {}; + +protected: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIOutputStream methods + NS_DECL_NSIOUTPUTSTREAM + + // nsIBinaryOutputStream methods + NS_DECL_NSIBINARYOUTPUTSTREAM + + // nsIObjectOutputStream methods + NS_DECL_NSIOBJECTOUTPUTSTREAM + + // Call Write(), ensuring that all proffered data is written + nsresult WriteFully(const char *aBuf, PRUint32 aCount); + + nsCOMPtr mOutputStream; + nsCOMPtr mBufferAccess; +}; + +#define NS_BINARYINPUTSTREAM_CID \ +{ /* c521a612-2aad-46db-b6ab-3b821fb150b1 */ \ + 0xc521a612, \ + 0x2aad, \ + 0x46db, \ + {0xb6, 0xab, 0x3b, 0x82, 0x1f, 0xb1, 0x50, 0xb1} \ +} + +#define NS_BINARYINPUTSTREAM_CONTRACTID "@mozilla.org/binaryinputstream;1" +#define NS_BINARYINPUTSTREAM_CLASSNAME "Binary Input Stream" + +// Derive from nsIObjectInputStream so this class can be used as a superclass +// by nsObjectInputStream. +class nsBinaryInputStream : public nsIObjectInputStream +{ +public: + nsBinaryInputStream() {}; + // virtual dtor since subclasses call our Release() + virtual ~nsBinaryInputStream() {}; + +protected: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIInputStream methods + NS_DECL_NSIINPUTSTREAM + + // nsIBinaryInputStream methods + NS_DECL_NSIBINARYINPUTSTREAM + + // nsIObjectInputStream methods + NS_DECL_NSIOBJECTINPUTSTREAM + + nsCOMPtr mInputStream; + nsCOMPtr mBufferAccess; +}; + +#endif // nsBinaryStream_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp new file mode 100644 index 00000000..364f71d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsByteArrayInputStream.h" +#include "nsMemory.h" + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsByteArrayInputStream, nsIInputStream, nsIByteArrayInputStream) + +nsByteArrayInputStream::nsByteArrayInputStream (char *buffer, PRUint32 bytes) + : _buffer (buffer), _nbytes (bytes), _pos (0) +{ +} + +nsByteArrayInputStream::~nsByteArrayInputStream () +{ + if (_buffer != NULL) + nsMemory::Free (_buffer); +} + +NS_IMETHODIMP +nsByteArrayInputStream::Available (PRUint32* aResult) +{ + if (aResult == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0 || _buffer == NULL) + *aResult = 0; + else + *aResult = _nbytes - _pos; + + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::Read (char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + if (aBuffer == NULL || aNumRead == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0) + return NS_ERROR_FAILURE; + + if (aCount == 0 || _pos == _nbytes) + *aNumRead = 0; + else + { + NS_ASSERTION (_buffer != NULL, "Stream buffer has been released - there's an ownership problem somewhere!"); + if (_buffer == NULL) + *aNumRead = 0; + else + if (aCount > _nbytes - _pos) + { + memcpy (aBuffer, &_buffer[_pos], *aNumRead = _nbytes - _pos); + _pos = _nbytes; + } + else + { + memcpy (aBuffer, &_buffer[_pos], *aNumRead = aCount); + _pos += aCount; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::ReadSegments(nsWriteSegmentFun writer, void * aClosure, PRUint32 aCount, PRUint32 *aNumRead) +{ + if (aNumRead == NULL) + return NS_ERROR_NULL_POINTER; + + if (_nbytes == 0) + return NS_ERROR_FAILURE; + + if (aCount == 0 || _pos == _nbytes) + *aNumRead = 0; + else { + NS_ASSERTION (_buffer != NULL, "Stream buffer has been released - there's an ownership problem somewhere!"); + PRUint32 readCount = PR_MIN(aCount, (_nbytes - _pos)); + if (_buffer == NULL) + *aNumRead = 0; + else { + nsresult rv = writer (this, aClosure, &_buffer[_pos], + _pos, readCount, aNumRead); + if (NS_SUCCEEDED(rv)) + _pos += *aNumRead; + } + } + + // do not propogate errors returned from writer! + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsByteArrayInputStream::Close () +{ + if (_buffer != NULL) + { + nsMemory::Free (_buffer); + _buffer = NULL; + _nbytes = 0; + } + else + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_COM nsresult +NS_NewByteArrayInputStream (nsIByteArrayInputStream* *aResult, char * buffer, unsigned long bytes) +{ + if (aResult == NULL) + return NS_ERROR_NULL_POINTER; + + nsIByteArrayInputStream * stream = new nsByteArrayInputStream (buffer, bytes); + + if (!stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF (stream); + *aResult = stream; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h new file mode 100644 index 00000000..2999eb5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsByteArrayInputStream.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIByteArrayInputStream.h" +#include "nsCOMPtr.h" + +class nsByteArrayInputStream : public nsIByteArrayInputStream +{ + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIInputStream methods + NS_DECL_NSIINPUTSTREAM + +public: + nsByteArrayInputStream (char *buffer, PRUint32 nbytes); + +private: + ~nsByteArrayInputStream (); + + char *_buffer; + PRUint32 _nbytes; + PRUint32 _pos; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp new file mode 100644 index 00000000..60b16eda --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.cpp @@ -0,0 +1,1241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsLocalFile.h" +#include "nsDebug.h" +#include "nsStaticAtom.h" + +#if defined(XP_MAC) +#include +#include +#include +#include +#include +#elif defined(XP_WIN) +#include +#include +#include +#include +#elif defined(XP_UNIX) || defined(XP_MACOSX) +#include +#include +#include +#include +#include "prenv.h" +#ifdef XP_MACOSX +#include +#include +#include +# ifndef VBOX_WITH_NEWER_OSX_SDK +# include +# endif +#include +#include +#include +#include +#endif +#elif defined(XP_OS2) +#define MAX_PATH _MAX_PATH +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#include "SpecialSystemDirectory.h" +#include "nsAppFileLocationProvider.h" + +#if defined(XP_MAC) +#define COMPONENT_REGISTRY_NAME NS_LITERAL_CSTRING("Component Registry") +#define COMPONENT_DIRECTORY NS_LITERAL_CSTRING("Components") +#else +#define COMPONENT_REGISTRY_NAME NS_LITERAL_CSTRING("compreg.dat") +#define COMPONENT_DIRECTORY NS_LITERAL_CSTRING("components") +#endif + +#define XPTI_REGISTRY_NAME NS_LITERAL_CSTRING("xpti.dat") + +// define home directory +// For Windows platform, We are choosing Appdata folder as HOME +#if defined (XP_WIN) +#define HOME_DIR NS_WIN_APPDATA_DIR +#elif defined (XP_MAC) || defined (XP_MACOSX) +#define HOME_DIR NS_OSX_HOME_DIR +#elif defined (XP_UNIX) +#define HOME_DIR NS_UNIX_HOME_DIR +#elif defined (XP_OS2) +#define HOME_DIR NS_OS2_HOME_DIR +#elif defined (XP_BEOS) +#define HOME_DIR NS_BEOS_HOME_DIR +#endif + +//---------------------------------------------------------------------------------------- +nsresult +nsDirectoryService::GetCurrentProcessDirectory(nsILocalFile** aFile) +//---------------------------------------------------------------------------------------- +{ + NS_ENSURE_ARG_POINTER(aFile); + *aFile = nsnull; + + // Set the component registry location: + if (!mService) + return NS_ERROR_FAILURE; + + nsresult rv; + + nsCOMPtr dirService; + rv = nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(dirService)); // needs to be around for life of product + + if (dirService) + { + nsCOMPtr aLocalFile; + dirService->Get(NS_XPCOM_INIT_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(aLocalFile)); + if (aLocalFile) + { + *aFile = aLocalFile; + NS_ADDREF(*aFile); + return NS_OK; + } + } + + nsLocalFile* localFile = new nsLocalFile; + + if (localFile == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(localFile); + + + +#ifdef XP_WIN + char buf[MAX_PATH]; + if ( ::GetModuleFileName(0, buf, sizeof(buf)) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buf, '\\'); + if (lastSlash) + *(lastSlash + 1) = '\0'; + + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + +#elif defined(XP_MAC) + // get info for the the current process to determine the directory + // its located in + OSErr err; + ProcessSerialNumber psn = {kNoProcess, kCurrentProcess}; + ProcessInfoRec pInfo; + FSSpec tempSpec; + + // initialize ProcessInfoRec before calling + // GetProcessInformation() or die horribly. + pInfo.processName = nil; + pInfo.processAppSpec = &tempSpec; + pInfo.processInfoLength = sizeof(ProcessInfoRec); + + err = GetProcessInformation(&psn, &pInfo); + if (!err) + { + // create an FSSpec from the volume and dirid of the app. + FSSpec appFSSpec; + ::FSMakeFSSpec(pInfo.processAppSpec->vRefNum, pInfo.processAppSpec->parID, 0, &appFSSpec); + + nsCOMPtr localFileMac = do_QueryInterface((nsIFile*)localFile); + if (localFileMac) + { + localFileMac->InitWithFSSpec(&appFSSpec); + *aFile = localFile; + return NS_OK; + } + } +#elif defined(XP_MACOSX) +# ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + rv = localFile->InitWithNativePath(nsDependentCString(MOZ_DEFAULT_VBOX_XPCOM_HOME)); + if (NS_SUCCEEDED(rv)) + *aFile = localFile; +# else + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (appBundle != nsnull) + { + CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle); + if (bundleURL != nsnull) + { + CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, bundleURL); + if (parentURL) + { + // Pass PR_TRUE for the "resolveAgainstBase" arg to CFURLGetFileSystemRepresentation. + // This will resolve the relative portion of the CFURL against it base, giving a full + // path, which CFURLCopyFileSystemPath doesn't do. + char buffer[PATH_MAX]; + if (CFURLGetFileSystemRepresentation(parentURL, PR_TRUE, (UInt8 *)buffer, sizeof(buffer))) + { +#ifdef DEBUG_conrad + printf("nsDirectoryService - CurrentProcessDir is: %s\n", buffer); +#endif + rv = localFile->InitWithNativePath(nsDependentCString(buffer)); + if (NS_SUCCEEDED(rv)) + *aFile = localFile; + } + CFRelease(parentURL); + } + CFRelease(bundleURL); + } + } +#endif + + NS_ASSERTION(*aFile, "nsDirectoryService - Could not determine CurrentProcessDir.\n"); + if (*aFile) + return NS_OK; + +#elif defined(XP_UNIX) + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + char buf[MAXPATHLEN]; + +#if 0 /* we need .so location. */ + // Actually we have a way on linux. + static volatile bool fPathSet = false; + static char szPath[MAXPATHLEN]; + if (!fPathSet) + { + char buf2[MAXPATHLEN + 3]; + buf2[0] = '\0'; + + /* + * Env.var. VBOX_XPCOM_HOME first. + */ + char *psz = PR_GetEnv("VBOX_XPCOM_HOME"); + if (psz) + { + if (strlen(psz) < MAXPATHLEN) + { + if (!realpath(psz, buf2)) + strcpy(buf2, psz); + strcat(buf2, "/x"); /* for the filename stripping */ + } + } + + /* + * The dynamic loader. + */ + if (!buf2[0]) + { + Dl_info DlInfo = {0}; + if ( !dladdr((void *)nsDirectoryService::mService, &DlInfo) + && DlInfo.dli_fname) + { + if (!realpath(DlInfo.dli_fname, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Executable location. + */ + if (!buf2[0]) + { + char buf[MAXPATHLEN]; + int cchLink = readlink("/proc/self/exe", buf, sizeof(buf) - 1); + if (cchLink > 0 || cchLink != sizeof(buf) - 1) + { + buf[cchLink] = '\0'; + if (!realpath(buf, buf2)) + buf2[0] = '\0'; + } + } + + /* + * Copy to static buffer on success. + */ + if (buf2[0]) + { + char *p = strrchr(buf2, '/'); + if (p) + { + p[p == buf2] = '\0'; + #ifdef DEBUG + printf("debug: (1) VBOX_XPCOM_HOME=%s\n", buf2); + #endif + strcpy(szPath, buf2); + fPathSet = true; + } + } + } + if (fPathSet) + { + localFile->InitWithNativePath(nsDependentCString(szPath)); + *aFile = localFile; + return NS_OK; + } + +#endif + + + // The MOZ_DEFAULT_VBOX_XPCOM_HOME variable can be set at configure time with + // a --with-default-mozilla-five-home=foo autoconf flag. + // + // The idea here is to allow for builds that have a default VBOX_XPCOM_HOME + // regardless of the environment. This makes it easier to write apps that + // embed mozilla without having to worry about setting up the environment + // + // We do this py putenv()ing the default value into the environment. Note that + // we only do this if it is not already set. +#ifdef MOZ_DEFAULT_VBOX_XPCOM_HOME + if (PR_GetEnv("VBOX_XPCOM_HOME") == nsnull) + PR_SetEnv("VBOX_XPCOM_HOME=" MOZ_DEFAULT_VBOX_XPCOM_HOME); +#endif + + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + + if (moz5) + { + if (realpath(moz5, buf)) { + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + } +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(!moz5 && firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buf, sizeof(buf))) + { + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char buffer[CCHMAXPATH]; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + localFile->InitWithNativePath(nsDependentCString(buffer)); + *aFile = localFile; + return NS_OK; + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + localFile->InitWithNativePath(nsDependentCString(moz5)); + localFile->Normalize(); + *aFile = localFile; + return NS_OK; + } + else + { + static char buf[MAXPATHLEN]; + int32 cookie = 0; + image_info info; + char *p; + *buf = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buf, info.name); + if((p = strrchr(buf, '/')) != 0) + { + *p = 0; + localFile->InitWithNativePath(nsDependentCString(buf)); + *aFile = localFile; + return NS_OK; + } + } + } + +#endif + + NS_RELEASE(localFile); + + NS_ERROR("unable to get current process directory"); + return NS_ERROR_FAILURE; +} // GetCurrentProcessDirectory() + + +nsIAtom* nsDirectoryService::sCurrentProcess = nsnull; +nsIAtom* nsDirectoryService::sComponentRegistry = nsnull; +nsIAtom* nsDirectoryService::sXPTIRegistry = nsnull; +nsIAtom* nsDirectoryService::sComponentDirectory = nsnull; +nsIAtom* nsDirectoryService::sGRE_Directory = nsnull; +nsIAtom* nsDirectoryService::sGRE_ComponentDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_DriveDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_TemporaryDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_CurrentProcessDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS_CurrentWorkingDirectory = nsnull; +#if defined (XP_MACOSX) +nsIAtom* nsDirectoryService::sDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sTrashDirectory = nsnull; +nsIAtom* nsDirectoryService::sStartupDirectory = nsnull; +nsIAtom* nsDirectoryService::sShutdownDirectory = nsnull; +nsIAtom* nsDirectoryService::sAppleMenuDirectory = nsnull; +nsIAtom* nsDirectoryService::sControlPanelDirectory = nsnull; +nsIAtom* nsDirectoryService::sExtensionDirectory = nsnull; +nsIAtom* nsDirectoryService::sFontsDirectory = nsnull; +nsIAtom* nsDirectoryService::sPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sInternetSearchDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserLibDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDefaultDownloadDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserApplicationsDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalApplicationsDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserInternetPlugInDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalInternetPlugInDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserFrameworksDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalFrameworksDirectory = nsnull; +nsIAtom* nsDirectoryService::sUserPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sLocalPreferencesDirectory = nsnull; +nsIAtom* nsDirectoryService::sPictureDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sMovieDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sMusicDocumentsDirectory = nsnull; +nsIAtom* nsDirectoryService::sInternetSitesDirectory = nsnull; +#elif defined (XP_WIN) +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +nsIAtom* nsDirectoryService::sWindowsDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktop = nsnull; +nsIAtom* nsDirectoryService::sPrograms = nsnull; +nsIAtom* nsDirectoryService::sControls = nsnull; +nsIAtom* nsDirectoryService::sPrinters = nsnull; +nsIAtom* nsDirectoryService::sPersonal = nsnull; +nsIAtom* nsDirectoryService::sFavorites = nsnull; +nsIAtom* nsDirectoryService::sStartup = nsnull; +nsIAtom* nsDirectoryService::sRecent = nsnull; +nsIAtom* nsDirectoryService::sSendto = nsnull; +nsIAtom* nsDirectoryService::sBitbucket = nsnull; +nsIAtom* nsDirectoryService::sStartmenu = nsnull; +nsIAtom* nsDirectoryService::sDesktopdirectory = nsnull; +nsIAtom* nsDirectoryService::sDrives = nsnull; +nsIAtom* nsDirectoryService::sNetwork = nsnull; +nsIAtom* nsDirectoryService::sNethood = nsnull; +nsIAtom* nsDirectoryService::sFonts = nsnull; +nsIAtom* nsDirectoryService::sTemplates = nsnull; +nsIAtom* nsDirectoryService::sCommon_Startmenu = nsnull; +nsIAtom* nsDirectoryService::sCommon_Programs = nsnull; +nsIAtom* nsDirectoryService::sCommon_Startup = nsnull; +nsIAtom* nsDirectoryService::sCommon_Desktopdirectory = nsnull; +nsIAtom* nsDirectoryService::sAppdata = nsnull; +nsIAtom* nsDirectoryService::sPrinthood = nsnull; +nsIAtom* nsDirectoryService::sWinCookiesDirectory = nsnull; +#elif defined (XP_UNIX) +nsIAtom* nsDirectoryService::sLocalDirectory = nsnull; +nsIAtom* nsDirectoryService::sLibDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +#elif defined (XP_OS2) +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +nsIAtom* nsDirectoryService::sOS2Directory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +#elif defined (XP_BEOS) +nsIAtom* nsDirectoryService::sSettingsDirectory = nsnull; +nsIAtom* nsDirectoryService::sHomeDirectory = nsnull; +nsIAtom* nsDirectoryService::sDesktopDirectory = nsnull; +nsIAtom* nsDirectoryService::sSystemDirectory = nsnull; +#endif + + +nsDirectoryService* nsDirectoryService::mService = nsnull; + +nsDirectoryService::nsDirectoryService() : + mHashtable(256, PR_TRUE) +{ +} + +NS_METHOD +nsDirectoryService::Create(nsISupports *outer, REFNSIID aIID, void **aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + if (!mService) + { + mService = new nsDirectoryService(); + if (!mService) + return NS_ERROR_OUT_OF_MEMORY; + } + return mService->QueryInterface(aIID, aResult); +} + +static const nsStaticAtom directory_atoms[] = { + { NS_XPCOM_CURRENT_PROCESS_DIR, &nsDirectoryService::sCurrentProcess }, + { NS_XPCOM_COMPONENT_REGISTRY_FILE, &nsDirectoryService::sComponentRegistry }, + { NS_XPCOM_COMPONENT_DIR, &nsDirectoryService::sComponentDirectory }, + { NS_XPCOM_XPTI_REGISTRY_FILE, &nsDirectoryService::sXPTIRegistry }, + { NS_GRE_DIR, &nsDirectoryService::sGRE_Directory }, + { NS_GRE_COMPONENT_DIR, &nsDirectoryService::sGRE_ComponentDirectory }, + { NS_OS_DRIVE_DIR, &nsDirectoryService::sOS_DriveDirectory }, + { NS_OS_TEMP_DIR, &nsDirectoryService::sOS_TemporaryDirectory }, + { NS_OS_CURRENT_PROCESS_DIR, &nsDirectoryService::sOS_CurrentProcessDirectory }, + { NS_OS_CURRENT_WORKING_DIR, &nsDirectoryService::sOS_CurrentWorkingDirectory }, + { NS_XPCOM_INIT_CURRENT_PROCESS_DIR, nsnull }, +#if defined (XP_MACOSX) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sDirectory }, + { NS_MAC_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, + { NS_MAC_TRASH_DIR, &nsDirectoryService::sTrashDirectory }, + { NS_MAC_STARTUP_DIR, &nsDirectoryService::sStartupDirectory }, + { NS_MAC_SHUTDOWN_DIR, &nsDirectoryService::sShutdownDirectory }, + { NS_MAC_APPLE_MENU_DIR, &nsDirectoryService::sAppleMenuDirectory }, + { NS_MAC_CONTROL_PANELS_DIR, &nsDirectoryService::sControlPanelDirectory }, + { NS_MAC_EXTENSIONS_DIR, &nsDirectoryService::sExtensionDirectory }, + { NS_MAC_FONTS_DIR, &nsDirectoryService::sFontsDirectory }, + { NS_MAC_PREFS_DIR, &nsDirectoryService::sPreferencesDirectory }, + { NS_MAC_DOCUMENTS_DIR, &nsDirectoryService::sDocumentsDirectory }, + { NS_MAC_INTERNET_SEARCH_DIR, &nsDirectoryService::sInternetSearchDirectory }, + { NS_MAC_USER_LIB_DIR, &nsDirectoryService::sUserLibDirectory }, + { NS_OSX_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_OSX_DEFAULT_DOWNLOAD_DIR, &nsDirectoryService::sDefaultDownloadDirectory }, + { NS_OSX_USER_DESKTOP_DIR, &nsDirectoryService::sUserDesktopDirectory }, + { NS_OSX_LOCAL_DESKTOP_DIR, &nsDirectoryService::sLocalDesktopDirectory }, + { NS_OSX_USER_APPLICATIONS_DIR, &nsDirectoryService::sUserApplicationsDirectory }, + { NS_OSX_LOCAL_APPLICATIONS_DIR, &nsDirectoryService::sLocalApplicationsDirectory }, + { NS_OSX_USER_DOCUMENTS_DIR, &nsDirectoryService::sUserDocumentsDirectory }, + { NS_OSX_LOCAL_DOCUMENTS_DIR, &nsDirectoryService::sLocalDocumentsDirectory }, + { NS_OSX_USER_INTERNET_PLUGIN_DIR, &nsDirectoryService::sUserInternetPlugInDirectory }, + { NS_OSX_LOCAL_INTERNET_PLUGIN_DIR, &nsDirectoryService::sLocalInternetPlugInDirectory }, + { NS_OSX_USER_FRAMEWORKS_DIR, &nsDirectoryService::sUserFrameworksDirectory }, + { NS_OSX_LOCAL_FRAMEWORKS_DIR, &nsDirectoryService::sLocalFrameworksDirectory }, + { NS_OSX_USER_PREFERENCES_DIR, &nsDirectoryService::sUserPreferencesDirectory }, + { NS_OSX_LOCAL_PREFERENCES_DIR, &nsDirectoryService::sLocalPreferencesDirectory }, + { NS_OSX_PICTURE_DOCUMENTS_DIR, &nsDirectoryService::sPictureDocumentsDirectory }, + { NS_OSX_MOVIE_DOCUMENTS_DIR, &nsDirectoryService::sMovieDocumentsDirectory }, + { NS_OSX_MUSIC_DOCUMENTS_DIR, &nsDirectoryService::sMusicDocumentsDirectory }, + { NS_OSX_INTERNET_SITES_DIR, &nsDirectoryService::sInternetSitesDirectory }, +#elif defined (XP_WIN) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_WIN_WINDOWS_DIR, &nsDirectoryService::sWindowsDirectory }, + { NS_WIN_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_WIN_DESKTOP_DIR, &nsDirectoryService::sDesktop }, + { NS_WIN_PROGRAMS_DIR, &nsDirectoryService::sPrograms }, + { NS_WIN_CONTROLS_DIR, &nsDirectoryService::sControls }, + { NS_WIN_PRINTERS_DIR, &nsDirectoryService::sPrinters }, + { NS_WIN_PERSONAL_DIR, &nsDirectoryService::sPersonal }, + { NS_WIN_FAVORITES_DIR, &nsDirectoryService::sFavorites }, + { NS_WIN_STARTUP_DIR, &nsDirectoryService::sStartup }, + { NS_WIN_RECENT_DIR, &nsDirectoryService::sRecent }, + { NS_WIN_SEND_TO_DIR, &nsDirectoryService::sSendto }, + { NS_WIN_BITBUCKET_DIR, &nsDirectoryService::sBitbucket }, + { NS_WIN_STARTMENU_DIR, &nsDirectoryService::sStartmenu }, + { NS_WIN_DESKTOP_DIRECTORY, &nsDirectoryService::sDesktopdirectory }, + { NS_WIN_DRIVES_DIR, &nsDirectoryService::sDrives }, + { NS_WIN_NETWORK_DIR, &nsDirectoryService::sNetwork }, + { NS_WIN_NETHOOD_DIR, &nsDirectoryService::sNethood }, + { NS_WIN_FONTS_DIR, &nsDirectoryService::sFonts }, + { NS_WIN_TEMPLATES_DIR, &nsDirectoryService::sTemplates }, + { NS_WIN_COMMON_STARTMENU_DIR, &nsDirectoryService::sCommon_Startmenu }, + { NS_WIN_COMMON_PROGRAMS_DIR, &nsDirectoryService::sCommon_Programs }, + { NS_WIN_COMMON_STARTUP_DIR, &nsDirectoryService::sCommon_Startup }, + { NS_WIN_COMMON_DESKTOP_DIRECTORY, &nsDirectoryService::sCommon_Desktopdirectory }, + { NS_WIN_APPDATA_DIR, &nsDirectoryService::sAppdata }, + { NS_WIN_PRINTHOOD, &nsDirectoryService::sPrinthood }, + { NS_WIN_COOKIES_DIR, &nsDirectoryService::sWinCookiesDirectory }, +#elif defined (XP_UNIX) + { NS_UNIX_LOCAL_DIR, &nsDirectoryService::sLocalDirectory }, + { NS_UNIX_LIB_DIR, &nsDirectoryService::sLibDirectory }, + { NS_UNIX_HOME_DIR, &nsDirectoryService::sHomeDirectory }, +#elif defined (XP_OS2) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_OS2_DIR, &nsDirectoryService::sOS2Directory }, + { NS_OS2_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_OS2_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, +#elif defined (XP_BEOS) + { NS_OS_SYSTEM_DIR, &nsDirectoryService::sSystemDirectory }, + { NS_BEOS_SETTINGS_DIR, &nsDirectoryService::sSettingsDirectory }, + { NS_BEOS_HOME_DIR, &nsDirectoryService::sHomeDirectory }, + { NS_BEOS_DESKTOP_DIR, &nsDirectoryService::sDesktopDirectory }, +#endif +}; + +nsresult +nsDirectoryService::Init() +{ + nsresult rv; + + rv = NS_NewISupportsArray(getter_AddRefs(mProviders)); + if (NS_FAILED(rv)) return rv; + + NS_RegisterStaticAtoms(directory_atoms, NS_ARRAY_LENGTH(directory_atoms)); + + // Let the list hold the only reference to the provider. + nsAppFileLocationProvider *defaultProvider = new nsAppFileLocationProvider; + if (!defaultProvider) + return NS_ERROR_OUT_OF_MEMORY; + // AppendElement returns PR_TRUE for success. + rv = mProviders->AppendElement(defaultProvider) ? NS_OK : NS_ERROR_FAILURE; + + return rv; +} + +PRBool +nsDirectoryService::ReleaseValues(nsHashKey* key, void* data, void* closure) +{ + nsISupports* value = (nsISupports*)data; + NS_IF_RELEASE(value); + return PR_TRUE; +} + +nsDirectoryService::~nsDirectoryService() +{ + // clear the global + mService = nsnull; + +} + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsDirectoryService, nsIProperties, nsIDirectoryService, nsIDirectoryServiceProvider, nsIDirectoryServiceProvider2) + + +NS_IMETHODIMP +nsDirectoryService::Undefine(const char* prop) +{ + nsCStringKey key(prop); + if (!mHashtable.Exists(&key)) + return NS_ERROR_FAILURE; + + mHashtable.Remove (&key); + return NS_OK; + } + +NS_IMETHODIMP +nsDirectoryService::GetKeys(PRUint32 *count, char ***keys) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +struct FileData +{ + FileData(const char* aProperty, + const nsIID& aUUID) : + property(aProperty), + data(nsnull), + persistent(PR_TRUE), + uuid(aUUID) {} + + const char* property; + nsISupports* data; + PRBool persistent; + const nsIID& uuid; +}; + +static PRBool FindProviderFile(nsISupports* aElement, void *aData) +{ + nsresult rv; + FileData* fileData = (FileData*)aData; + if (fileData->uuid.Equals(NS_GET_IID(nsISimpleEnumerator))) + { + // Not all providers implement this iface + nsCOMPtr prov2 = do_QueryInterface(aElement); + if (prov2) + { + rv = prov2->GetFiles(fileData->property, (nsISimpleEnumerator **)&fileData->data); + if (NS_SUCCEEDED(rv) && fileData->data) { + fileData->persistent = PR_FALSE; // Enumerators can never be peristent + return PR_FALSE; + } + } + } + else + { + nsCOMPtr prov = do_QueryInterface(aElement); + if (!prov) + return PR_FALSE; + rv = prov->GetFile(fileData->property, &fileData->persistent, (nsIFile **)&fileData->data); + if (NS_SUCCEEDED(rv) && fileData->data) + return PR_FALSE; + } + + return PR_TRUE; +} + +NS_IMETHODIMP +nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) +{ + nsCStringKey key(prop); + + nsCOMPtr value = dont_AddRef(mHashtable.Get(&key)); + + if (value) + { + nsCOMPtr cloneFile; + nsCOMPtr cachedFile = do_QueryInterface(value); + NS_ASSERTION(cachedFile, "nsIFile expected"); + + cachedFile->Clone(getter_AddRefs(cloneFile)); + return cloneFile->QueryInterface(uuid, result); + } + + // it is not one of our defaults, lets check any providers + FileData fileData(prop, uuid); + + mProviders->EnumerateBackwards(FindProviderFile, &fileData); + if (fileData.data) + { + if (fileData.persistent) + { + Set(prop, NS_STATIC_CAST(nsIFile*, fileData.data)); + } + nsresult rv = (fileData.data)->QueryInterface(uuid, result); + NS_RELEASE(fileData.data); // addref occurs in FindProviderFile() + return rv; + } + + FindProviderFile(NS_STATIC_CAST(nsIDirectoryServiceProvider*, this), &fileData); + if (fileData.data) + { + if (fileData.persistent) + { + Set(prop, NS_STATIC_CAST(nsIFile*, fileData.data)); + } + nsresult rv = (fileData.data)->QueryInterface(uuid, result); + NS_RELEASE(fileData.data); // addref occurs in FindProviderFile() + return rv; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::Set(const char* prop, nsISupports* value) +{ + nsCStringKey key(prop); + if (mHashtable.Exists(&key) || value == nsnull) + return NS_ERROR_FAILURE; + + nsCOMPtr ourFile; + value->QueryInterface(NS_GET_IID(nsIFile), getter_AddRefs(ourFile)); + if (ourFile) + { + nsCOMPtr cloneFile; + ourFile->Clone (getter_AddRefs (cloneFile)); + mHashtable.Put(&key, cloneFile); + + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::Has(const char *prop, PRBool *_retval) +{ + *_retval = PR_FALSE; + nsCOMPtr value; + nsresult rv = Get(prop, NS_GET_IID(nsIFile), getter_AddRefs(value)); + if (NS_FAILED(rv)) + return rv; + + if (value) + { + *_retval = PR_TRUE; + } + + return rv; +} + +NS_IMETHODIMP +nsDirectoryService::RegisterProvider(nsIDirectoryServiceProvider *prov) +{ + nsresult rv; + if (!prov) + return NS_ERROR_FAILURE; + if (!mProviders) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr supports = do_QueryInterface(prov, &rv); + if (NS_FAILED(rv)) return rv; + + // AppendElement returns PR_TRUE for success. + return mProviders->AppendElement(supports) ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDirectoryService::UnregisterProvider(nsIDirectoryServiceProvider *prov) +{ + nsresult rv; + if (!prov) + return NS_ERROR_FAILURE; + if (!mProviders) + return NS_ERROR_NOT_INITIALIZED; + + nsCOMPtr supports = do_QueryInterface(prov, &rv); + if (NS_FAILED(rv)) return rv; + + // RemoveElement returns PR_TRUE for success. + return mProviders->RemoveElement(supports) ? NS_OK : NS_ERROR_FAILURE; +} + +// DO NOT ADD ANY LOCATIONS TO THIS FUNCTION UNTIL YOU TALK TO: dougt@netscape.com. +// This is meant to be a place of xpcom or system specific file locations, not +// application specific locations. If you need the later, register a callback for +// your application. + +NS_IMETHODIMP +nsDirectoryService::GetFile(const char *prop, PRBool *persistent, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + *_retval = nsnull; + *persistent = PR_TRUE; + + nsIAtom* inAtom = NS_NewAtom(prop); + + // check to see if it is one of our defaults + + if (inAtom == nsDirectoryService::sCurrentProcess || + inAtom == nsDirectoryService::sOS_CurrentProcessDirectory ) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sComponentRegistry) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (!localFile) + return NS_ERROR_FAILURE; + + localFile->AppendNative(COMPONENT_DIRECTORY); + localFile->AppendNative(COMPONENT_REGISTRY_NAME); + } + else if (inAtom == nsDirectoryService::sXPTIRegistry) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (!localFile) + return NS_ERROR_FAILURE; + + localFile->AppendNative(COMPONENT_DIRECTORY); + localFile->AppendNative(XPTI_REGISTRY_NAME); + } + + // Unless otherwise set, the core pieces of the GRE exist + // in the current process directory. + else if (inAtom == nsDirectoryService::sGRE_Directory) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + } + // the GRE components directory is relative to the GRE directory + // by default; applications may override this behavior in special + // cases + else if (inAtom == nsDirectoryService::sGRE_ComponentDirectory) + { + rv = Get(NS_GRE_DIR, nsILocalFile::GetIID(), getter_AddRefs(localFile)); + if (localFile) + localFile->AppendNative(COMPONENT_DIRECTORY); + } + else if (inAtom == nsDirectoryService::sComponentDirectory) + { + rv = GetCurrentProcessDirectory(getter_AddRefs(localFile)); + if (localFile) + localFile->AppendNative(COMPONENT_DIRECTORY); + } + else if (inAtom == nsDirectoryService::sOS_DriveDirectory) + { + rv = GetSpecialSystemDirectory(OS_DriveDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_TemporaryDirectory) + { + rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_CurrentProcessDirectory) + { + rv = GetSpecialSystemDirectory(OS_CurrentProcessDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS_CurrentWorkingDirectory) + { + rv = GetSpecialSystemDirectory(OS_CurrentWorkingDirectory, getter_AddRefs(localFile)); + } + +#if defined(XP_MACOSX) + else if (inAtom == nsDirectoryService::sDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kSystemFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sTrashDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kTrashFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartupDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kStartupFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sShutdownDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kShutdownFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sAppleMenuDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kAppleMenuFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sControlPanelDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kControlPanelFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sExtensionDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kExtensionFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFontsDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kFontsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPreferencesDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDocumentsDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sInternetSearchDirectory) + { + rv = GetOSXFolderType(kClassicDomain, kInternetSearchSitesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserLibDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDomainLibraryFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDomainTopLevelFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDefaultDownloadDirectory) + { + NS_NewLocalFile(EmptyString(), PR_TRUE, getter_AddRefs(localFile)); + nsCOMPtr localMacFile(do_QueryInterface(localFile)); + + if (localMacFile) + { + OSErr err; + ICInstance icInstance; + + err = ::ICStart(&icInstance, 'XPCM'); + if (err == noErr) + { + ICAttr attrs; + ICFileSpec icFileSpec; + long size = kICFileSpecHeaderSize; + err = ::ICGetPref(icInstance, kICDownloadFolder, &attrs, &icFileSpec, &size); + if (err == noErr || (err == icTruncatedErr && size >= kICFileSpecHeaderSize)) + { + rv = localMacFile->InitWithFSSpec(&icFileSpec.fss); + } + ::ICStop(icInstance); + } + + if (NS_FAILED(rv)) + { + // We got an error getting the DL folder from IC so try finding the user's Desktop folder + rv = GetOSXFolderType(kUserDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + } + + // Don't cache the DL directory as the user may change it while we're running. + // Negligible perf hit as this directory is only requested for downloads + *persistent = PR_FALSE; + } + else if (inAtom == nsDirectoryService::sUserDesktopDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalDesktopDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kDesktopFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserApplicationsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kApplicationsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalApplicationsDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kApplicationsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalDocumentsDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserInternetPlugInDirectory) + { + rv = GetOSXFolderType(kUserDomain, kInternetPlugInFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalInternetPlugInDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kInternetPlugInFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserFrameworksDirectory) + { + rv = GetOSXFolderType(kUserDomain, kFrameworksFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalFrameworksDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kFrameworksFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sUserPreferencesDirectory) + { + rv = GetOSXFolderType(kUserDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLocalPreferencesDirectory) + { + rv = GetOSXFolderType(kLocalDomain, kPreferencesFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPictureDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kPictureDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sMovieDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kMovieDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sMusicDocumentsDirectory) + { + rv = GetOSXFolderType(kUserDomain, kMusicDocumentsFolderType, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sInternetSitesDirectory) + { + rv = GetOSXFolderType(kUserDomain, kInternetSitesFolderType, getter_AddRefs(localFile)); + } +#elif defined (XP_WIN) + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(Win_SystemDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sWindowsDirectory) + { + rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(Win_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktop) + { + rv = GetSpecialSystemDirectory(Win_Desktop, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrograms) + { + rv = GetSpecialSystemDirectory(Win_Programs, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sControls) + { + rv = GetSpecialSystemDirectory(Win_Controls, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrinters) + { + rv = GetSpecialSystemDirectory(Win_Printers, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPersonal) + { + rv = GetSpecialSystemDirectory(Win_Personal, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFavorites) + { + rv = GetSpecialSystemDirectory(Win_Favorites, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartup) + { + rv = GetSpecialSystemDirectory(Win_Startup, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sRecent) + { + rv = GetSpecialSystemDirectory(Win_Recent, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sSendto) + { + rv = GetSpecialSystemDirectory(Win_Sendto, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sBitbucket) + { + rv = GetSpecialSystemDirectory(Win_Bitbucket, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sStartmenu) + { + rv = GetSpecialSystemDirectory(Win_Startmenu, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopdirectory) + { + rv = GetSpecialSystemDirectory(Win_Desktopdirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDrives) + { + rv = GetSpecialSystemDirectory(Win_Drives, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sNetwork) + { + rv = GetSpecialSystemDirectory(Win_Network, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sNethood) + { + rv = GetSpecialSystemDirectory(Win_Nethood, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sFonts) + { + rv = GetSpecialSystemDirectory(Win_Fonts, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sTemplates) + { + rv = GetSpecialSystemDirectory(Win_Templates, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Startmenu) + { + rv = GetSpecialSystemDirectory(Win_Common_Startmenu, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Programs) + { + rv = GetSpecialSystemDirectory(Win_Common_Programs, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Startup) + { + rv = GetSpecialSystemDirectory(Win_Common_Startup, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sCommon_Desktopdirectory) + { + rv = GetSpecialSystemDirectory(Win_Common_Desktopdirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sAppdata) + { + rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sPrinthood) + { + rv = GetSpecialSystemDirectory(Win_Printhood, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sWinCookiesDirectory) + { + rv = GetSpecialSystemDirectory(Win_Cookies, getter_AddRefs(localFile)); + } +#elif defined (XP_UNIX) + + else if (inAtom == nsDirectoryService::sLocalDirectory) + { + rv = GetSpecialSystemDirectory(Unix_LocalDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sLibDirectory) + { + rv = GetSpecialSystemDirectory(Unix_LibDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(Unix_HomeDirectory, getter_AddRefs(localFile)); + } +#elif defined (XP_OS2) + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(OS2_SystemDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sOS2Directory) + { + rv = GetSpecialSystemDirectory(OS2_OS2Directory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(OS2_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetSpecialSystemDirectory(OS2_DesktopDirectory, getter_AddRefs(localFile)); + } +#elif defined (XP_BEOS) + else if (inAtom == nsDirectoryService::sSettingsDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_SettingsDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sHomeDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_HomeDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sDesktopDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_DesktopDirectory, getter_AddRefs(localFile)); + } + else if (inAtom == nsDirectoryService::sSystemDirectory) + { + rv = GetSpecialSystemDirectory(BeOS_SystemDirectory, getter_AddRefs(localFile)); + } +#endif + + + NS_RELEASE(inAtom); + + if (localFile && NS_SUCCEEDED(rv)) + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); +#ifdef DEBUG_dougt + printf("Failed to find directory for key: %s\n", prop); +#endif + return rv; +} + +NS_IMETHODIMP +nsDirectoryService::GetFiles(const char *prop, nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + + return NS_ERROR_FAILURE; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h new file mode 100644 index 00000000..67e6e371 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryService.h @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsDirectoryService_h___ +#define nsDirectoryService_h___ + +#include "nsIDirectoryService.h" +#include "nsHashtable.h" +#include "nsILocalFile.h" +#include "nsISupportsArray.h" +#include "nsIAtom.h" + +#define NS_XPCOM_INIT_CURRENT_PROCESS_DIR "MozBinD" // Can be used to set NS_XPCOM_CURRENT_PROCESS_DIR + // CANNOT be used to GET a location + +class nsDirectoryService : public nsIDirectoryService, + public nsIProperties, + public nsIDirectoryServiceProvider2 +{ + public: + + NS_DEFINE_STATIC_CID_ACCESSOR(NS_DIRECTORY_SERVICE_CID); + + // nsISupports interface + NS_DECL_ISUPPORTS + + NS_DECL_NSIPROPERTIES + + NS_DECL_NSIDIRECTORYSERVICE + + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + + NS_DECL_NSIDIRECTORYSERVICEPROVIDER2 + + nsDirectoryService(); + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsDirectoryService(); + + nsresult GetCurrentProcessDirectory(nsILocalFile** aFile); + + static nsDirectoryService* mService; + static PRBool PR_CALLBACK ReleaseValues(nsHashKey* key, void* data, void* closure); + nsSupportsHashtable mHashtable; + nsCOMPtr mProviders; + +public: + static nsIAtom *sCurrentProcess; + static nsIAtom *sComponentRegistry; + static nsIAtom *sComponentDirectory; + static nsIAtom *sXPTIRegistry; + static nsIAtom *sGRE_Directory; + static nsIAtom *sGRE_ComponentDirectory; + static nsIAtom *sOS_DriveDirectory; + static nsIAtom *sOS_TemporaryDirectory; + static nsIAtom *sOS_CurrentProcessDirectory; + static nsIAtom *sOS_CurrentWorkingDirectory; +#if defined (XP_MACOSX) + static nsIAtom *sDirectory; + static nsIAtom *sDesktopDirectory; + static nsIAtom *sTrashDirectory; + static nsIAtom *sStartupDirectory; + static nsIAtom *sShutdownDirectory; + static nsIAtom *sAppleMenuDirectory; + static nsIAtom *sControlPanelDirectory; + static nsIAtom *sExtensionDirectory; + static nsIAtom *sFontsDirectory; + static nsIAtom *sPreferencesDirectory; + static nsIAtom *sDocumentsDirectory; + static nsIAtom *sInternetSearchDirectory; + static nsIAtom *sUserLibDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDefaultDownloadDirectory; + static nsIAtom *sUserDesktopDirectory; + static nsIAtom *sLocalDesktopDirectory; + static nsIAtom *sUserApplicationsDirectory; + static nsIAtom *sLocalApplicationsDirectory; + static nsIAtom *sUserDocumentsDirectory; + static nsIAtom *sLocalDocumentsDirectory; + static nsIAtom *sUserInternetPlugInDirectory; + static nsIAtom *sLocalInternetPlugInDirectory; + static nsIAtom *sUserFrameworksDirectory; + static nsIAtom *sLocalFrameworksDirectory; + static nsIAtom *sUserPreferencesDirectory; + static nsIAtom *sLocalPreferencesDirectory; + static nsIAtom *sPictureDocumentsDirectory; + static nsIAtom *sMovieDocumentsDirectory; + static nsIAtom *sMusicDocumentsDirectory; + static nsIAtom *sInternetSitesDirectory; +#elif defined (XP_WIN) + static nsIAtom *sSystemDirectory; + static nsIAtom *sWindowsDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktop; + static nsIAtom *sPrograms; + static nsIAtom *sControls; + static nsIAtom *sPrinters; + static nsIAtom *sPersonal; + static nsIAtom *sFavorites; + static nsIAtom *sStartup; + static nsIAtom *sRecent; + static nsIAtom *sSendto; + static nsIAtom *sBitbucket; + static nsIAtom *sStartmenu; + static nsIAtom *sDesktopdirectory; + static nsIAtom *sDrives; + static nsIAtom *sNetwork; + static nsIAtom *sNethood; + static nsIAtom *sFonts; + static nsIAtom *sTemplates; + static nsIAtom *sCommon_Startmenu; + static nsIAtom *sCommon_Programs; + static nsIAtom *sCommon_Startup; + static nsIAtom *sCommon_Desktopdirectory; + static nsIAtom *sAppdata; + static nsIAtom *sPrinthood; + static nsIAtom *sWinCookiesDirectory; +#elif defined (XP_UNIX) + static nsIAtom *sLocalDirectory; + static nsIAtom *sLibDirectory; + static nsIAtom *sHomeDirectory; +#elif defined (XP_OS2) + static nsIAtom *sSystemDirectory; + static nsIAtom *sOS2Directory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktopDirectory; +#elif defined (XP_BEOS) + static nsIAtom *sSettingsDirectory; + static nsIAtom *sHomeDirectory; + static nsIAtom *sDesktopDirectory; + static nsIAtom *sSystemDirectory; +#endif + + +}; + + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h new file mode 100644 index 00000000..6b3c8ba4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceDefs.h @@ -0,0 +1,197 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen conrad@ingress.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Defines the property names for directories available from + * nsIDirectoryService. These dirs are always available even if no + * nsIDirectoryServiceProviders have been registered with the service. + * Application level keys are defined in nsAppDirectoryServiceDefs.h. + * + * Keys whose definition ends in "DIR" or "FILE" return a single nsIFile (or + * subclass). Keys whose definition ends in "LIST" return an nsISimpleEnumerator + * which enumerates a list of file objects. + * + * Defines listed in this file are FROZEN. This list may grow. + */ + +#ifndef nsDirectoryServiceDefs_h___ +#define nsDirectoryServiceDefs_h___ + +/* General OS specific locations */ + +#define NS_OS_HOME_DIR "Home" +#define NS_OS_TEMP_DIR "TmpD" +#define NS_OS_CURRENT_WORKING_DIR "CurWorkD" + +/* Property returns the directory in which the procces was started from. + * On Unix this will be the path in the VBOX_XPCOM_HOME env var and if + * unset will be the current working directory. + */ +#define NS_OS_CURRENT_PROCESS_DIR "CurProcD" + +/* This location is similar to NS_OS_CURRENT_PROCESS_DIR, however, + * NS_XPCOM_CURRENT_PROCESS_DIR can be overriden by passing a "bin + * directory" to NS_InitXPCOM2(). + */ +#define NS_XPCOM_CURRENT_PROCESS_DIR "XCurProcD" + +/* Property will return the location of the application components + * directory. By default, this directory will be contained in the + * NS_XPCOM_CURRENT_PROCESS_DIR. + */ +#define NS_XPCOM_COMPONENT_DIR "ComsD" + +/* Property will return a list of components directories that will + * will be registered after the application components directory. + */ +#define NS_XPCOM_COMPONENT_DIR_LIST "ComsDL" + +/* Property will return the location of the application components + * registry file. + */ +#define NS_XPCOM_COMPONENT_REGISTRY_FILE "ComRegF" + +/* Property will return the location of the application XPTI + * registry file. + */ +#define NS_XPCOM_XPTI_REGISTRY_FILE "XptiRegF" + +/* Property will return the location of the the XPCOM Shared Library. + */ +#define NS_XPCOM_LIBRARY_FILE "XpcomLib" + +/* Property will return the current location of the the GRE directory. + * If no GRE is used, this propery will behave like + * NS_XPCOM_CURRENT_PROCESS_DIR. + */ +#define NS_GRE_DIR "GreD" + +/* Property will return the current location of the the GRE component + * directory. If no GRE is used, this propery will behave like + * NS_XPCOM_COMPONENT_DIR. + */ +#define NS_GRE_COMPONENT_DIR "GreComsD" + + +/* Platform Specific Locations */ + +#if !defined (XP_UNIX) || defined(XP_MACOSX) + #define NS_OS_SYSTEM_DIR "SysD" +#endif + +#if defined (XP_MACOSX) + #define NS_MAC_DESKTOP_DIR "Desk" + #define NS_MAC_TRASH_DIR "Trsh" + #define NS_MAC_STARTUP_DIR "Strt" + #define NS_MAC_SHUTDOWN_DIR "Shdwn" + #define NS_MAC_APPLE_MENU_DIR "ApplMenu" + #define NS_MAC_CONTROL_PANELS_DIR "CntlPnl" + #define NS_MAC_EXTENSIONS_DIR "Exts" + #define NS_MAC_FONTS_DIR "Fnts" + #define NS_MAC_PREFS_DIR "Prfs" + #define NS_MAC_DOCUMENTS_DIR "Docs" + #define NS_MAC_INTERNET_SEARCH_DIR "ISrch" + #define NS_OSX_HOME_DIR "Home" + #define NS_MAC_HOME_DIR NS_OSX_HOME_DIR + #define NS_MAC_DEFAULT_DOWNLOAD_DIR "DfltDwnld" + #define NS_MAC_USER_LIB_DIR "ULibDir" // Only available under OS X + #define NS_OSX_DEFAULT_DOWNLOAD_DIR NS_MAC_DEFAULT_DOWNLOAD_DIR + #define NS_OSX_USER_DESKTOP_DIR "UsrDsk" + #define NS_OSX_LOCAL_DESKTOP_DIR "LocDsk" + #define NS_OSX_USER_APPLICATIONS_DIR "UsrApp" + #define NS_OSX_LOCAL_APPLICATIONS_DIR "LocApp" + #define NS_OSX_USER_DOCUMENTS_DIR "UsrDocs" + #define NS_OSX_LOCAL_DOCUMENTS_DIR "LocDocs" + #define NS_OSX_USER_INTERNET_PLUGIN_DIR "UsrIntrntPlgn" + #define NS_OSX_LOCAL_INTERNET_PLUGIN_DIR "LoclIntrntPlgn" + #define NS_OSX_USER_FRAMEWORKS_DIR "UsrFrmwrks" + #define NS_OSX_LOCAL_FRAMEWORKS_DIR "LocFrmwrks" + #define NS_OSX_USER_PREFERENCES_DIR "UsrPrfs" + #define NS_OSX_LOCAL_PREFERENCES_DIR "LocPrfs" + #define NS_OSX_PICTURE_DOCUMENTS_DIR "Pct" + #define NS_OSX_MOVIE_DOCUMENTS_DIR "Mov" + #define NS_OSX_MUSIC_DOCUMENTS_DIR "Music" + #define NS_OSX_INTERNET_SITES_DIR "IntrntSts" +#elif defined (XP_WIN) + #define NS_WIN_WINDOWS_DIR "WinD" + #define NS_WIN_HOME_DIR "Home" + #define NS_WIN_DESKTOP_DIR "DeskV" // virtual folder at the root of the namespace + #define NS_WIN_PROGRAMS_DIR "Progs" + #define NS_WIN_CONTROLS_DIR "Cntls" + #define NS_WIN_PRINTERS_DIR "Prnts" + #define NS_WIN_PERSONAL_DIR "Pers" + #define NS_WIN_FAVORITES_DIR "Favs" + #define NS_WIN_STARTUP_DIR "Strt" + #define NS_WIN_RECENT_DIR "Rcnt" + #define NS_WIN_SEND_TO_DIR "SndTo" + #define NS_WIN_BITBUCKET_DIR "Buckt" + #define NS_WIN_STARTMENU_DIR "Strt" + #define NS_WIN_DESKTOP_DIRECTORY "DeskP" // file sys dir which physically stores objects on desktop + #define NS_WIN_DRIVES_DIR "Drivs" + #define NS_WIN_NETWORK_DIR "NetW" + #define NS_WIN_NETHOOD_DIR "netH" + #define NS_WIN_FONTS_DIR "Fnts" + #define NS_WIN_TEMPLATES_DIR "Tmpls" + #define NS_WIN_COMMON_STARTMENU_DIR "CmStrt" + #define NS_WIN_COMMON_PROGRAMS_DIR "CmPrgs" + #define NS_WIN_COMMON_STARTUP_DIR "CmStrt" + #define NS_WIN_COMMON_DESKTOP_DIRECTORY "CmDeskP" + #define NS_WIN_APPDATA_DIR "AppData" + #define NS_WIN_PRINTHOOD "PrntHd" + #define NS_WIN_COOKIES_DIR "CookD" +#elif defined (XP_UNIX) + #define NS_UNIX_LOCAL_DIR "Locl" + #define NS_UNIX_LIB_DIR "LibD" + #define NS_UNIX_HOME_DIR "Home" +#elif defined (XP_OS2) + #define NS_OS2_DIR "OS2Dir" + #define NS_OS2_HOME_DIR "Home" + #define NS_OS2_DESKTOP_DIR "Desk" +#elif defined (XP_BEOS) + #define NS_BEOS_SETTINGS_DIR "Setngs" + #define NS_BEOS_HOME_DIR "Home" + #define NS_BEOS_DESKTOP_DIR "Desk" +#endif + +/* Deprecated */ + +#define NS_OS_DRIVE_DIR "DrvD" + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h new file mode 100644 index 00000000..f2482c76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsDirectoryServiceUtils.h @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsDirectoryServiceUtils_h___ +#define nsDirectoryServiceUtils_h___ + +#include "nsIServiceManager.h" +#include "nsIProperties.h" +#include "nsCOMPtr.h" + +#define NS_DIRECTORY_SERVICE_CID {0xf00152d0,0xb40b,0x11d3,{0x8c, 0x9c, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +inline nsresult +NS_GetSpecialDirectory(const char* specialDirName, nsIFile* *result) +{ + nsresult rv; + static NS_DEFINE_CID(kDirectoryServiceCID, NS_DIRECTORY_SERVICE_CID); + nsCOMPtr serv(do_GetService(kDirectoryServiceCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + return serv->Get(specialDirName, NS_GET_IID(nsIFile), + NS_REINTERPRET_CAST(void**, result)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp b/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp new file mode 100644 index 00000000..758339e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsEscape.cpp @@ -0,0 +1,491 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/12/03 by John R. McMullen, derived from net.h/mkparse.c. + +#include "nsEscape.h" +#include "nsMemory.h" +#include "nsCRT.h" +#include "nsReadableUtils.h" + +const int netCharType[256] = +/* Bit 0 xalpha -- the alphas +** Bit 1 xpalpha -- as xalpha but +** converts spaces to plus and plus to %2B +** Bit 3 ... path -- as xalphas but doesn't escape '/' +*/ + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x */ + 0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4, /* 2x !"#$%&'()*+,-./ */ + 7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0, /* 3x 0123456789:;<=>? */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 4x @ABCDEFGHIJKLMNO */ + /* bits for '@' changed from 7 to 0 so '@' can be escaped */ + /* in usernames and passwords in publishing. */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7, /* 5X PQRSTUVWXYZ[\]^_ */ + 0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, /* 6x `abcdefghijklmno */ + 7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, /* 7X pqrstuvwxyz{\}~ DEL */ + 0, }; + +/* decode % escaped hex codes into character values + */ +#define UNHEX(C) \ + ((C >= '0' && C <= '9') ? C - '0' : \ + ((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \ + ((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0))) + + +#define IS_OK(C) (netCharType[((unsigned int) (C))] & (mask)) +#define HEX_ESCAPE '%' + +//---------------------------------------------------------------------------------------- +static char* nsEscapeCount( + const char * str, + PRInt32 len, + nsEscapeMask mask, + PRInt32* out_len) +//---------------------------------------------------------------------------------------- +{ + if (!str) + return 0; + + int i, extra = 0; + static const char hexChars[] = "0123456789ABCDEF"; + + register const unsigned char* src = (const unsigned char *) str; + for (i = 0; i < len; i++) + { + if (!IS_OK(*src++)) + extra += 2; /* the escape, plus an extra byte for each nibble */ + } + + char* result = (char *)nsMemory::Alloc(len + extra + 1); + if (!result) + return 0; + + register unsigned char* dst = (unsigned char *) result; + src = (const unsigned char *) str; + if (mask == url_XPAlphas) + { + for (i = 0; i < len; i++) + { + unsigned char c = *src++; + if (IS_OK(c)) + *dst++ = c; + else if (c == ' ') + *dst++ = '+'; /* convert spaces to pluses */ + else + { + *dst++ = HEX_ESCAPE; + *dst++ = hexChars[c >> 4]; /* high nibble */ + *dst++ = hexChars[c & 0x0f]; /* low nibble */ + } + } + } + else + { + for (i = 0; i < len; i++) + { + unsigned char c = *src++; + if (IS_OK(c)) + *dst++ = c; + else + { + *dst++ = HEX_ESCAPE; + *dst++ = hexChars[c >> 4]; /* high nibble */ + *dst++ = hexChars[c & 0x0f]; /* low nibble */ + } + } + } + + *dst = '\0'; /* tack on eos */ + if(out_len) + *out_len = dst - (unsigned char *) result; + return result; +} + +//---------------------------------------------------------------------------------------- +NS_COM char* nsEscape(const char * str, nsEscapeMask mask) +//---------------------------------------------------------------------------------------- +{ + if(!str) + return NULL; + return nsEscapeCount(str, (PRInt32)strlen(str), mask, NULL); +} + +//---------------------------------------------------------------------------------------- +NS_COM char* nsUnescape(char * str) +//---------------------------------------------------------------------------------------- +{ + nsUnescapeCount(str); + return str; +} + +//---------------------------------------------------------------------------------------- +NS_COM PRInt32 nsUnescapeCount(char * str) +//---------------------------------------------------------------------------------------- +{ + register char *src = str; + register char *dst = str; + static const char hexChars[] = "0123456789ABCDEFabcdef"; + + char c1[] = " "; + char c2[] = " "; + char* const pc1 = c1; + char* const pc2 = c2; + + while (*src) + { + c1[0] = *(src+1); + if (*(src+1) == '\0') + c2[0] = '\0'; + else + c2[0] = *(src+2); + + if (*src != HEX_ESCAPE || PL_strpbrk(pc1, hexChars) == 0 || + PL_strpbrk(pc2, hexChars) == 0 ) + *dst++ = *src++; + else + { + src++; /* walk over escape */ + if (*src) + { + *dst = UNHEX(*src) << 4; + src++; + } + if (*src) + { + *dst = (*dst + UNHEX(*src)); + src++; + } + dst++; + } + } + + *dst = 0; + return (int)(dst - str); + +} /* NET_UnEscapeCnt */ + + +NS_COM char * +nsEscapeHTML(const char * string) +{ + /* XXX Hardcoded max entity len. The +1 is for the trailing null. */ + char *rv = (char *) nsMemory::Alloc(strlen(string) * 6 + 1); + char *ptr = rv; + + if(rv) + { + for(; *string != '\0'; string++) + { + if(*string == '<') + { + *ptr++ = '&'; + *ptr++ = 'l'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if(*string == '>') + { + *ptr++ = '&'; + *ptr++ = 'g'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if(*string == '&') + { + *ptr++ = '&'; + *ptr++ = 'a'; + *ptr++ = 'm'; + *ptr++ = 'p'; + *ptr++ = ';'; + } + else if (*string == '"') + { + *ptr++ = '&'; + *ptr++ = 'q'; + *ptr++ = 'u'; + *ptr++ = 'o'; + *ptr++ = 't'; + *ptr++ = ';'; + } + else if (*string == '\'') + { + *ptr++ = '&'; + *ptr++ = '#'; + *ptr++ = '3'; + *ptr++ = '9'; + *ptr++ = ';'; + } + else + { + *ptr++ = *string; + } + } + *ptr = '\0'; + } + + return(rv); +} + +NS_COM PRUnichar * +nsEscapeHTML2(const PRUnichar *aSourceBuffer, PRInt32 aSourceBufferLen) +{ + // if the caller didn't calculate the length + if (aSourceBufferLen == -1) { + aSourceBufferLen = nsCRT::strlen(aSourceBuffer); // ...then I will + } + + /* XXX Hardcoded max entity len. */ + PRUnichar *resultBuffer = (PRUnichar *)nsMemory::Alloc(aSourceBufferLen * + 6 * sizeof(PRUnichar) + sizeof(PRUnichar('\0'))); + PRUnichar *ptr = resultBuffer; + + if (resultBuffer) { + PRInt32 i; + + for(i = 0; i < aSourceBufferLen; i++) { + if(aSourceBuffer[i] == '<') { + *ptr++ = '&'; + *ptr++ = 'l'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if(aSourceBuffer[i] == '>') { + *ptr++ = '&'; + *ptr++ = 'g'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if(aSourceBuffer[i] == '&') { + *ptr++ = '&'; + *ptr++ = 'a'; + *ptr++ = 'm'; + *ptr++ = 'p'; + *ptr++ = ';'; + } else if (aSourceBuffer[i] == '"') { + *ptr++ = '&'; + *ptr++ = 'q'; + *ptr++ = 'u'; + *ptr++ = 'o'; + *ptr++ = 't'; + *ptr++ = ';'; + } else if (aSourceBuffer[i] == '\'') { + *ptr++ = '&'; + *ptr++ = '#'; + *ptr++ = '3'; + *ptr++ = '9'; + *ptr++ = ';'; + } else { + *ptr++ = aSourceBuffer[i]; + } + } + *ptr = 0; + } + + return resultBuffer; +} + +//---------------------------------------------------------------------------------------- + +const int EscapeChars[256] = +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0,1023, 0, 512,1023, 0,1023,1023,1023,1023,1023,1023,1023,1023, 953, 784, /* 2x !"#$%&'()*+,-./ */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008, 912, 0,1008, 0, 768, /* 3x 0123456789:;<=>? */ + 1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, /* 4x @ABCDEFGHIJKLMNO */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896, 896, 896, 896,1023, /* 5x PQRSTUVWXYZ[\]^_ */ + 0,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, /* 6x `abcdefghijklmno */ + 1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023, 0, /* 7x pqrstuvwxyz{|}~ */ + 0 /* 8x DEL */ +}; + +#define NO_NEED_ESC(C) (EscapeChars[((unsigned int) (C))] & (mask)) + +//---------------------------------------------------------------------------------------- + +/* returns an escaped string */ + +/* use the following masks to specify which + part of an URL you want to escape: + + esc_Scheme = 1 + esc_Username = 2 + esc_Password = 4 + esc_Host = 8 + esc_Directory = 16 + esc_FileBaseName = 32 + esc_FileExtension = 64 + esc_Param = 128 + esc_Query = 256 + esc_Ref = 512 +*/ + +/* by default this function will not escape parts of a string + that already look escaped, which means it already includes + a valid hexcode. This is done to avoid multiple escapes of + a string. Use the following mask to force escaping of a + string: + + esc_Forced = 1024 +*/ + +NS_COM PRBool NS_EscapeURL(const char *part, + PRInt32 partLen, + PRInt16 mask, + nsACString &result) +{ + if (!part) { + NS_NOTREACHED("null pointer"); + return PR_FALSE; + } + + int i = 0; + static const char hexChars[] = "0123456789ABCDEF"; + if (partLen < 0) + partLen = strlen(part); + PRBool forced = (mask & esc_Forced); + PRBool ignoreNonAscii = (mask & esc_OnlyASCII); + PRBool ignoreAscii = (mask & esc_OnlyNonASCII); + PRBool writing = (mask & esc_AlwaysCopy); + PRBool colon = (mask & esc_Colon); + + register const unsigned char* src = (const unsigned char *) part; + + char tempBuffer[100]; + unsigned int tempBufferPos = 0; + + for (i = 0; i < partLen; i++) + { + unsigned char c = *src++; + + // if the char has not to be escaped or whatever follows % is + // a valid escaped string, just copy the char. + // + // Also the % will not be escaped until forced + // See bugzilla bug 61269 for details why we changed this + // + // And, we will not escape non-ascii characters if requested. + // On special request we will also escape the colon even when + // not covered by the matrix. + // ignoreAscii is not honored for control characters (C0 and DEL) + if ((NO_NEED_ESC(c) || (c == HEX_ESCAPE && !forced) + || (c > 0x7f && ignoreNonAscii) + || (c > 0x1f && c < 0x7f && ignoreAscii)) + && !(c == ':' && colon)) + { + if (writing) + tempBuffer[tempBufferPos++] = c; + } + else /* do the escape magic */ + { + if (!writing) + { + result.Append(part, i); + writing = PR_TRUE; + } + tempBuffer[tempBufferPos++] = HEX_ESCAPE; + tempBuffer[tempBufferPos++] = hexChars[c >> 4]; /* high nibble */ + tempBuffer[tempBufferPos++] = hexChars[c & 0x0f]; /* low nibble */ + } + + if (tempBufferPos >= sizeof(tempBuffer) - 4) + { + NS_ASSERTION(writing, "should be writing"); + tempBuffer[tempBufferPos] = '\0'; + result += tempBuffer; + tempBufferPos = 0; + } + } + if (writing) { + tempBuffer[tempBufferPos] = '\0'; + result += tempBuffer; + } + return writing; +} + +#define ISHEX(c) memchr(hexChars, c, sizeof(hexChars)-1) + +NS_COM PRBool NS_UnescapeURL(const char *str, PRInt32 len, PRInt16 flags, nsACString &result) +{ + if (!str) { + NS_NOTREACHED("null pointer"); + return PR_FALSE; + } + + if (len < 0) + len = strlen(str); + + PRBool ignoreNonAscii = (flags & esc_OnlyASCII); + PRBool writing = (flags & esc_AlwaysCopy); + PRBool skipControl = (flags & esc_SkipControl); + + static const char hexChars[] = "0123456789ABCDEFabcdef"; + + const char *last = str; + const char *p = str; + + for (int i=0; i= '8') && + !(skipControl && + (*p1 < '2' || (*p1 == '7' && (*p2 == 'f' || *p2 == 'F'))))) { + //printf("- p1=%c p2=%c\n", *p1, *p2); + writing = PR_TRUE; + if (p > last) { + //printf("- p=%p, last=%p\n", p, last); + result.Append(last, p - last); + last = p; + } + char u = (UNHEX(*p1) << 4) + UNHEX(*p2); + //printf("- u=%c\n", u); + result.Append(u); + i += 2; + p += 2; + last += 3; + } + } + } + if (writing && last < str + len) + result.Append(last, str + len - last); + + return writing; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsEscape.h b/src/libs/xpcom18a4/xpcom/io/nsEscape.h new file mode 100644 index 00000000..aaf56738 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsEscape.h @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* First checked in on 98/12/03 by John R. McMullen, derived from net.h/mkparse.c. */ + +#ifndef _ESCAPE_H_ +#define _ESCAPE_H_ + +#include "prtypes.h" +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define nsEscape VBoxNsxpnsEscape +#define nsUnescape VBoxNsxpnsUnescape +#define nsUnescapeCount VBoxNsxpnsUnescapeCount +#define nsEscapeHTML VBoxNsxpnsEscapeHTML +#define nsEscapeHTML2 VBoxNsxpnsEscapeHTML2 +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * Valid mask values for nsEscape + */ +typedef enum { + url_XAlphas = PR_BIT(0) /**< Normal escape - leave alphas intact, escape the rest */ +, url_XPAlphas = PR_BIT(1) /**< As url_XAlphas, but convert spaces (0x20) to '+' and plus to %2B */ +, url_Path = PR_BIT(2) /**< As url_XAlphas, but don't escape slash ('/') */ +} nsEscapeMask; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Escape the given string according to mask + * @param str The string to escape + * @param mask How to escape the string + * @return A newly allocated escaped string that must be free'd with + * nsCRT::free, or null on failure + */ +NS_COM char * nsEscape(const char * str, nsEscapeMask mask); + +NS_COM char * nsUnescape(char * str); + /* decode % escaped hex codes into character values, + * modifies the parameter, returns the same buffer + */ + +NS_COM PRInt32 nsUnescapeCount (char * str); + /* decode % escaped hex codes into character values, + * modifies the parameter buffer, returns the length of the result + * (result may contain \0's). + */ + +NS_COM char * +nsEscapeHTML(const char * string); + +NS_COM PRUnichar * +nsEscapeHTML2(const PRUnichar *aSourceBuffer, + PRInt32 aSourceBufferLen = -1); + /* + * Escape problem char's for HTML display + */ + + +#ifdef __cplusplus +} +#endif + + +/** + * NS_EscapeURL/NS_UnescapeURL constants for |flags| parameter: + */ +enum EscapeMask { + /** url components **/ + esc_Scheme = PR_BIT(0), + esc_Username = PR_BIT(1), + esc_Password = PR_BIT(2), + esc_Host = PR_BIT(3), + esc_Directory = PR_BIT(4), + esc_FileBaseName = PR_BIT(5), + esc_FileExtension = PR_BIT(6), + esc_FilePath = esc_Directory | esc_FileBaseName | esc_FileExtension, + esc_Param = PR_BIT(7), + esc_Query = PR_BIT(8), + esc_Ref = PR_BIT(9), + /** special flags **/ + esc_Minimal = esc_Scheme | esc_Username | esc_Password | esc_Host | esc_FilePath | esc_Param | esc_Query | esc_Ref, + esc_Forced = PR_BIT(10), /* forces escaping of existing escape sequences */ + esc_OnlyASCII = PR_BIT(11), /* causes non-ascii octets to be skipped */ + esc_OnlyNonASCII = PR_BIT(12), /* causes _graphic_ ascii octets (0x20-0x7E) + * to be skipped when escaping. causes all + * ascii octets to be skipped when unescaping */ + esc_AlwaysCopy = PR_BIT(13), /* copy input to result buf even if escaping is unnecessary */ + esc_Colon = PR_BIT(14), /* forces escape of colon */ + esc_SkipControl = PR_BIT(15) /* skips C0 and DEL from unescaping */ +}; + +/** + * NS_EscapeURL + * + * Escapes invalid char's in an URL segment. Has no side-effect if the URL + * segment is already escaped. Otherwise, the escaped URL segment is appended + * to |result|. + * + * @param str url segment string + * @param len url segment string length (-1 if unknown) + * @param flags url segment type flag + * @param result result buffer, untouched if part is already escaped + * + * @return TRUE if escaping was performed, FALSE otherwise. + */ +NS_COM PRBool NS_EscapeURL(const char *str, + PRInt32 len, + PRInt16 flags, + nsACString &result); + +/** + * Expands URL escape sequences... beware embedded null bytes! + * + * @param str url string to unescape + * @param len length of |str| + * @param flags only esc_OnlyNonASCII, esc_SkipControl and esc_AlwaysCopy + * are recognized + * @param result result buffer, untouched if |str| is already unescaped + * + * @return TRUE if unescaping was performed, FALSE otherwise. + */ +NS_COM PRBool NS_UnescapeURL(const char *str, + PRInt32 len, + PRInt16 flags, + nsACString &result); + +/** returns resultant string length **/ +inline PRInt32 NS_UnescapeURL(char *str) { return nsUnescapeCount(str); } + +/** + * string friendly versions... + */ +inline const nsACString & +NS_EscapeURL(const nsASingleFragmentCString &part, PRInt16 partType, nsACString &result) { + const char *temp; + if (NS_EscapeURL(part.BeginReading(temp), part.Length(), partType, result)) + return result; + return part; +} +inline const nsACString & +NS_UnescapeURL(const nsASingleFragmentCString &str, PRInt16 flags, nsACString &result) { + const char *temp; + if (NS_UnescapeURL(str.BeginReading(temp), str.Length(), flags, result)) + return result; + return str; +} +// inline unescape +inline nsAFlatCString & +NS_UnescapeURL(nsAFlatCString &str) +{ + str.SetLength(nsUnescapeCount(str.BeginWriting())); + return str; +} + +#endif // _ESCAPE_H_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp new file mode 100644 index 00000000..56b09d22 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.cpp @@ -0,0 +1,2581 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "prtypes.h" +#include "nscore.h" +#include "nsDebug.h" +#include "nsEnumeratorUtils.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +#include "nsIComponentManager.h" +#include "nsIFile.h" +#include "nsILocalFile.h" +#include "nsISeekableStream.h" +#include "nsISerializable.h" +#include "nsIStreamBufferAccess.h" + +#include "nsBinaryStream.h" +#include "nsFastLoadFile.h" +#include "nsInt64.h" + +#ifdef DEBUG_brendan +# define METERING +# define DEBUG_MUX +#endif + +#ifdef METERING +# define METER(x) x +#else +# define METER(x) /* nothing */ +#endif + +#ifdef DEBUG_MUX +# include +# include + +static void trace_mux(char mode, const char *format, ...) +{ + va_list ap; + static FILE *tfp; + if (!tfp) { + char tfn[16]; + sprintf(tfn, "/tmp/mux.%ctrace", mode); + tfp = fopen(tfn, "w"); + if (!tfp) + return; + setvbuf(tfp, NULL, _IOLBF, 0); + } + va_start(ap, format); + vfprintf(tfp, format, ap); + va_end(ap); +} + +# define TRACE_MUX(args) trace_mux args +#else +# define TRACE_MUX(args) /* nothing */ +#endif + +/* + * Fletcher's 16-bit checksum, using 32-bit two's-complement arithmetic. + */ +#define FOLD_ONES_COMPLEMENT_CARRY(X) ((X) = ((X) & 0xffff) + ((X) >> 16)) +#define ONES_COMPLEMENT_ACCUMULATE(X,Y) (X) += (Y); if ((X) & 0x80000000) \ + FOLD_ONES_COMPLEMENT_CARRY(X) +#define FLETCHER_ACCUMULATE(A,B,U) ONES_COMPLEMENT_ACCUMULATE(A, U); \ + ONES_COMPLEMENT_ACCUMULATE(B, A) + +PR_IMPLEMENT(PRUint32) +NS_AccumulateFastLoadChecksum(PRUint32 *aChecksum, + const PRUint8* aBuffer, + PRUint32 aLength, + PRBool aLastBuffer) +{ + PRUint32 C = *aChecksum; + PRUint32 A = C & 0xffff; + PRUint32 B = C >> 16; + + PRUint16 U = 0; + if (aLength >= 4) { + PRBool odd = PRWord(aBuffer) & 1; + switch (PRWord(aBuffer) & 3) { + case 3: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = aBuffer[2]; + aBuffer += 3; + aLength -= 3; + break; + + case 2: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = 0; + aBuffer += 2; + aLength -= 2; + break; + + case 1: + U = *aBuffer++; + aLength--; + break; + } + + PRUint32 W; + if (odd) { + while (aLength > 3) { + W = *NS_REINTERPRET_CAST(const PRUint32*, aBuffer); + U <<= 8; +#ifdef IS_BIG_ENDIAN + U |= W >> 24; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W >> 8); + FLETCHER_ACCUMULATE(A, B, U); + U = W & 0xff; +#else + U |= W & 0xff; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W >> 8); + U = NS_SWAP16(U); + FLETCHER_ACCUMULATE(A, B, U); + U = W >> 24; +#endif + aBuffer += 4; + aLength -= 4; + } + aBuffer--; // we're odd, we didn't checksum the last byte + aLength++; + } else { + while (aLength > 3) { + W = *NS_REINTERPRET_CAST(const PRUint32*, aBuffer); +#ifdef IS_BIG_ENDIAN + U = W >> 16; + FLETCHER_ACCUMULATE(A, B, U); + U = PRUint16(W); + FLETCHER_ACCUMULATE(A, B, U); +#else + U = NS_SWAP16(W); + FLETCHER_ACCUMULATE(A, B, U); + U = W >> 16; + U = NS_SWAP16(W); + FLETCHER_ACCUMULATE(A, B, U); +#endif + aBuffer += 4; + aLength -= 4; + } + } + } + + if (aLastBuffer) { + NS_ASSERTION(aLength <= 4, "aLength botch"); + switch (aLength) { + case 4: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = (aBuffer[2] << 8) | aBuffer[3]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 3: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + U = aBuffer[2]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 2: + U = (aBuffer[0] << 8) | aBuffer[1]; + FLETCHER_ACCUMULATE(A, B, U); + break; + + case 1: + U = aBuffer[0]; + FLETCHER_ACCUMULATE(A, B, U); + break; + } + + aLength = 0; + } + + while (A >> 16) + FOLD_ONES_COMPLEMENT_CARRY(A); + while (B >> 16) + FOLD_ONES_COMPLEMENT_CARRY(B); + + *aChecksum = (B << 16) | A; + return aLength; +} + +PR_IMPLEMENT(PRUint32) +NS_AddFastLoadChecksums(PRUint32 sum1, PRUint32 sum2, PRUint32 sum2ByteCount) +{ + PRUint32 A1 = sum1 & 0xffff; + PRUint32 B1 = sum1 >> 16; + + PRUint32 A2 = sum2 & 0xffff; + PRUint32 B2 = sum2 >> 16; + + PRUint32 A = A1 + A2; + while (A >> 16) + FOLD_ONES_COMPLEMENT_CARRY(A); + + PRUint32 B = B2; + for (PRUint32 n = (sum2ByteCount + 1) / 2; n != 0; n--) + ONES_COMPLEMENT_ACCUMULATE(B, B1); + while (B >> 16) + FOLD_ONES_COMPLEMENT_CARRY(B); + + return (B << 16) | A; +} + +#undef FOLD_ONES_COMPLEMENT_CARRY +#undef ONES_COMPLEMENT_ACCUMULATE +#undef FLETCHER_ACCUMULATE + +static const char magic[] = MFL_FILE_MAGIC; + +// -------------------------- nsFastLoadFileReader -------------------------- + +nsID nsFastLoadFileReader::nsFastLoadFooter::gDummyID; +nsFastLoadFileReader::nsObjectMapEntry + nsFastLoadFileReader::nsFastLoadFooter::gDummySharpObjectEntry; + +NS_IMPL_ISUPPORTS_INHERITED5(nsFastLoadFileReader, + nsBinaryInputStream, + nsIObjectInputStream, + nsIFastLoadFileControl, + nsIFastLoadReadControl, + nsISeekableStream, + nsIFastLoadFileReader) + +MOZ_DECL_CTOR_COUNTER(nsFastLoadFileReader) + +nsresult +nsFastLoadFileReader::ReadHeader(nsFastLoadHeader *aHeader) +{ + nsresult rv; + PRUint32 bytesRead; + + rv = Read(NS_REINTERPRET_CAST(char*, aHeader), sizeof *aHeader, &bytesRead); + if (NS_FAILED(rv)) + return rv; + + if (bytesRead != sizeof *aHeader || + memcmp(aHeader->mMagic, magic, MFL_FILE_MAGIC_SIZE)) { + return NS_ERROR_UNEXPECTED; + } + + aHeader->mChecksum = NS_SWAP32(aHeader->mChecksum); + aHeader->mVersion = NS_SWAP32(aHeader->mVersion); + aHeader->mFooterOffset = NS_SWAP32(aHeader->mFooterOffset); + aHeader->mFileSize = NS_SWAP32(aHeader->mFileSize); + + return NS_OK; +} + +// nsIFastLoadFileControl methods: + +NS_IMETHODIMP +nsFastLoadFileReader::GetChecksum(PRUint32 *aChecksum) +{ + *aChecksum = mHeader.mChecksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::SetChecksum(PRUint32 aChecksum) +{ + mHeader.mChecksum = aChecksum; + return NS_OK; +} + +struct nsStringMapEntry : public PLDHashEntryHdr { + const char* mString; // key, must come first + nsISupports* mURI; // for SelectMuxedDocument return value +}; + +struct nsDocumentMapEntry : public nsStringMapEntry { + PRUint32 mInitialSegmentOffset; // offset of URI's first segment in file +}; + +struct nsDocumentMapReadEntry : public nsDocumentMapEntry { + PRUint32 mNextSegmentOffset; // offset of URI's next segment to read + PRUint32 mBytesLeft : 31, // bytes remaining in current segment + mNeedToSeek : 1; // flag to defer Seek from Select to + // Read, in case there is no Read before + // another entry is Selected (to improve + // input stream buffer utilization) + PRInt64 mSaveOffset; // in case demux schedule differs from + // mux schedule +}; + +PR_STATIC_CALLBACK(void) +strmap_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsStringMapEntry* entry = NS_STATIC_CAST(nsStringMapEntry*, aHdr); + + if (entry->mString) + nsMemory::Free((void*) entry->mString); + NS_IF_RELEASE(entry->mURI); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps strmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + strmap_ClearEntry, + PL_DHashFinalizeStub, + NULL +}; + +// An nsObjectMapEntry holds a strong reference to an XPCOM object, unless the +// mObject member, when cast to NSFastLoadOID, has its MFL_OBJECT_DEF_TAG bit +// set. NB: we rely on the fact that an nsISupports* is never an odd pointer. +struct nsObjectMapEntry : public PLDHashEntryHdr { + nsISupports* mObject; // key, must come first +}; + +// Fast mapping from URI object pointer back to spec-indexed document info. +struct nsURIMapReadEntry : public nsObjectMapEntry { + nsDocumentMapReadEntry* mDocMapEntry; +}; + +PR_STATIC_CALLBACK(void) +objmap_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsObjectMapEntry* entry = NS_STATIC_CAST(nsObjectMapEntry*, aHdr); + + // Ignore tagged object ids stored as object pointer keys (the updater + // code does this). + if ((NS_PTR_TO_INT32(entry->mObject) & MFL_OBJECT_DEF_TAG) == 0) + NS_IF_RELEASE(entry->mObject); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps objmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + objmap_ClearEntry, + PL_DHashFinalizeStub, + NULL +}; + +NS_IMETHODIMP +nsFastLoadFileReader::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsDocumentMapReadEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&mFooter.mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + *aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::StartMuxedDocument(nsISupports* aURI, const char* aURISpec) +{ + nsDocumentMapReadEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&mFooter.mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + // If the spec isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try for a file update. + if (PL_DHASH_ENTRY_IS_FREE(docMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_ADD)); + if (!uriMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(uriMapEntry->mDocMapEntry == nsnull, + "URI mapped to two different specs?"); + if (uriMapEntry->mDocMapEntry) + return NS_ERROR_UNEXPECTED; + + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); + uriMapEntry->mObject = key; + NS_ADDREF(uriMapEntry->mObject); + uriMapEntry->mDocMapEntry = docMapEntry; + TRACE_MUX(('r', "start %p (%p) %s\n", aURI, key.get(), aURISpec)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) +{ + nsresult rv; + + // Find the given URI's entry and select it for more reading. + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try selecting the file updater. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + // If we're interrupting another document's segment, save its offset so + // we can seek back when it's reselected. If prevDocMapEntry->mNeedToSeek + // is set, that means the stream is not positioned for prevDocMapEntry, to + // avoid buffer thrashing. See below in this function for more. + nsDocumentMapReadEntry* prevDocMapEntry = mCurrentDocumentMapEntry; + if (prevDocMapEntry && + prevDocMapEntry->mBytesLeft && + !prevDocMapEntry->mNeedToSeek) { + rv = Tell(&prevDocMapEntry->mSaveOffset); + if (NS_FAILED(rv)) + return rv; + } + + // It turns out we get a fair amount of redundant select calls, thanks to + // non-blocking hunks of data from the parser that are devoid of scripts. + // As more data gets FastLoaded, the number of these useless selects will + // decline. + nsDocumentMapReadEntry* docMapEntry = uriMapEntry->mDocMapEntry; + if (docMapEntry == prevDocMapEntry) { + TRACE_MUX(('r', "select prev %s same as current!\n", + docMapEntry->mString)); + } + + // Invariant: docMapEntry->mBytesLeft implies docMapEntry->mSaveOffset has + // been set non-zero by the Tell call above. + else if (docMapEntry->mBytesLeft) { + NS_ASSERTION(docMapEntry->mSaveOffset != 0, + "reselecting from multiplex at unsaved offset?"); + + // Defer Seek till Read, in case of "ping-pong" Selects without any + // intervening Reads, to avoid dumping the underlying mInputStream's + // input buffer for cases where alternate "pongs" fall in the same + // buffer. + docMapEntry->mNeedToSeek = PR_TRUE; + } + + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + + mCurrentDocumentMapEntry = docMapEntry; +#ifdef DEBUG_MUX + PRInt64 currentSegmentOffset; + Tell(¤tSegmentOffset); + trace_mux('r', "select %p (%p) offset %ld\n", + aURI, key.get(), (long) currentSegmentOffset); +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::EndMuxedDocument(nsISupports* aURI) +{ + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapReadEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapReadEntry*, + PL_DHashTableOperate(&mFooter.mURIMap, key, + PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, return NS_ERROR_NOT_AVAILABLE so the + // FastLoad service can try to end a select on its file updater. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_NOT_AVAILABLE; + + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(&mFooter.mURIMap); + if (mFooter.mURIMap.removedCount >= (size >> 2)) + PL_DHashTableOperate(&mFooter.mURIMap, key, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(&mFooter.mURIMap, uriMapEntry); + + TRACE_MUX(('r', "end %p (%p)\n", aURI, key.get())); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead) +{ + nsresult rv; + + nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry; + if (entry) { + // Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry. + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + if (entry->mNeedToSeek) { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mSaveOffset); + if (NS_FAILED(rv)) + return rv; + + entry->mNeedToSeek = PR_FALSE; + } + + // Loop to handle empty segments, which may be generated by the + // writer, given Start A; Start B; Select A; Select B; write B data; + // multiplexing schedules, which do tend to occur given non-blocking + // i/o with LIFO scheduling. XXXbe investigate LIFO issues + while (entry->mBytesLeft == 0) { + // Check for unexpected end of multiplexed stream. + NS_ASSERTION(entry->mNextSegmentOffset != 0, + "document demuxed from FastLoad file more than once?"); + if (entry->mNextSegmentOffset == 0) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mNextSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Clear mCurrentDocumentMapEntry temporarily to avoid recursion. + mCurrentDocumentMapEntry = nsnull; + + rv = Read32(&entry->mNextSegmentOffset); + if (NS_SUCCEEDED(rv)) { + PRUint32 bytesLeft = 0; + rv = Read32(&bytesLeft); + entry->mBytesLeft = bytesLeft; + } + + mCurrentDocumentMapEntry = entry; + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(entry->mBytesLeft >= 8, "demux segment length botch!"); + entry->mBytesLeft -= 8; + } + } + + rv = mInputStream->Read(aBuffer, aCount, aBytesRead); + + if (NS_SUCCEEDED(rv) && entry) { + NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!"); + entry->mBytesLeft -= *aBytesRead; + +#ifdef NS_DEBUG + // Invariant: !entry->mBytesLeft implies entry->mSaveOffset == 0. + if (entry->mBytesLeft == 0) + entry->mSaveOffset = 0; +#endif + } + return rv; +} + +NS_IMETHODIMP +nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32 *aResult) +{ + nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry; + + NS_ASSERTION(!entry || (!entry->mNeedToSeek && entry->mBytesLeft != 0), + "ReadSegments called from above nsFastLoadFileReader layer?!"); + + nsresult rv = nsBinaryInputStream::ReadSegments(aWriter, aClosure, aCount, + aResult); + if (NS_SUCCEEDED(rv) && entry) { + NS_ASSERTION(entry->mBytesLeft >= *aResult, + "demux ReadSegments underflow!"); + entry->mBytesLeft -= *aResult; + +#ifdef NS_DEBUG + // Invariant: !entry->mBytesLeft implies entry->mSaveOffset == 0. + if (entry->mBytesLeft == 0) + entry->mSaveOffset = 0; +#endif + } + return rv; +} + +/** + * XXX tuneme + */ +#define MFL_CHECKSUM_BUFSIZE 8192 + +NS_IMETHODIMP +nsFastLoadFileReader::ComputeChecksum(PRUint32 *aResult) +{ + nsCOMPtr stream = mInputStream; + + nsCOMPtr seekable(do_QueryInterface(stream)); + PRInt64 saveOffset; + nsresult rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr bufferAccess(do_QueryInterface(stream)); + if (bufferAccess) { + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(stream)); + if (NS_FAILED(rv)) + return rv; + + seekable = do_QueryInterface(stream); + if (!seekable) + return NS_ERROR_UNEXPECTED; + } + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + char buf[MFL_CHECKSUM_BUFSIZE]; + PRUint32 len, rem; + + rem = offsetof(nsFastLoadHeader, mChecksum); + rv = stream->Read(buf, rem, &len); + if (NS_FAILED(rv)) + return rv; + if (len != rem) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, 4); + if (NS_FAILED(rv)) + return rv; + memset(buf + rem, 0, 4); + rem += 4; + + PRUint32 checksum = 0; + while (NS_SUCCEEDED(rv = stream->Read(buf + rem, sizeof buf - rem, &len)) && + len) { + len += rem; + rem = NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + len, + PR_FALSE); + if (rem) + memcpy(buf, buf + len - rem, rem); + } + if (NS_FAILED(rv)) + return rv; + + if (rem) { + NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + rem, + PR_TRUE); + } + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + *aResult = checksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::GetDependencies(nsISimpleEnumerator* *aDependencies) +{ + return NS_NewArrayEnumerator(aDependencies, mFooter.mDependencies); +} + +nsresult +nsFastLoadFileReader::ReadFooter(nsFastLoadFooter *aFooter) +{ + nsresult rv; + + rv = ReadFooterPrefix(aFooter); + if (NS_FAILED(rv)) + return rv; + + aFooter->mIDMap = new nsID[aFooter->mNumIDs]; + if (!aFooter->mIDMap) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 i, n; + for (i = 0, n = aFooter->mNumIDs; i < n; i++) { + rv = ReadSlowID(&aFooter->mIDMap[i]); + if (NS_FAILED(rv)) + return rv; + } + + aFooter->mObjectMap = new nsObjectMapEntry[aFooter->mNumSharpObjects]; + if (!aFooter->mObjectMap) + return NS_ERROR_OUT_OF_MEMORY; + + for (i = 0, n = aFooter->mNumSharpObjects; i < n; i++) { + nsObjectMapEntry* entry = &aFooter->mObjectMap[i]; + + rv = ReadSharpObjectInfo(entry); + if (NS_FAILED(rv)) + return rv; + + entry->mReadObject = nsnull; + entry->mSkipOffset = 0; + entry->mSaveStrongRefCnt = entry->mStrongRefCnt; + entry->mSaveWeakRefCnt = entry->mWeakRefCnt; + } + + if (!PL_DHashTableInit(&aFooter->mDocumentMap, &strmap_DHashTableOps, + (void *)this, sizeof(nsDocumentMapReadEntry), + aFooter->mNumMuxedDocuments)) { + aFooter->mDocumentMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&aFooter->mURIMap, &objmap_DHashTableOps, + (void *)this, sizeof(nsURIMapReadEntry), + aFooter->mNumMuxedDocuments)) { + aFooter->mURIMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + for (i = 0, n = aFooter->mNumMuxedDocuments; i < n; i++) { + nsFastLoadMuxedDocumentInfo info; + + rv = ReadMuxedDocumentInfo(&info); + if (NS_FAILED(rv)) + return rv; + + nsDocumentMapReadEntry* entry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, + PL_DHashTableOperate(&aFooter->mDocumentMap, + info.mURISpec, + PL_DHASH_ADD)); + if (!entry) { + nsMemory::Free((void*) info.mURISpec); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ASSERTION(!entry->mString, "duplicate URISpec in MuxedDocumentMap"); + entry->mString = info.mURISpec; + entry->mURI = nsnull; + entry->mInitialSegmentOffset = info.mInitialSegmentOffset; + entry->mNextSegmentOffset = info.mInitialSegmentOffset; + entry->mBytesLeft = 0; + entry->mNeedToSeek = PR_FALSE; + entry->mSaveOffset = 0; + } + + nsCOMPtr readDeps; + rv = NS_NewISupportsArray(getter_AddRefs(readDeps)); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString filename; + for (i = 0, n = aFooter->mNumDependencies; i < n; i++) { + rv = ReadCString(filename); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fastLoadMtime; + rv = Read64(NS_REINTERPRET_CAST(PRUint64*, &fastLoadMtime)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr file; + rv = NS_NewNativeLocalFile(filename, PR_TRUE, getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + PRInt64 currentMtime; + rv = file->GetLastModifiedTime(¤tMtime); + if (NS_FAILED(rv)) + return rv; + + if (LL_NE(fastLoadMtime, currentMtime)) { +#ifdef DEBUG + nsCAutoString path; + file->GetNativePath(path); + printf("%s mtime changed, invalidating FastLoad file\n", + path.get()); +#endif + return NS_ERROR_FAILURE; + } + + rv = readDeps->AppendElement(file); + if (NS_FAILED(rv)) + return rv; + } + + aFooter->mDependencies = readDeps; + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadFooterPrefix(nsFastLoadFooterPrefix *aFooterPrefix) +{ + nsresult rv; + + rv = Read32(&aFooterPrefix->mNumIDs); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumSharpObjects); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumMuxedDocuments); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aFooterPrefix->mNumDependencies); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadSlowID(nsID *aID) +{ + nsresult rv; + + rv = Read32(&aID->m0); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aID->m1); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aID->m2); + if (NS_FAILED(rv)) + return rv; + + PRUint32 bytesRead; + rv = Read(NS_REINTERPRET_CAST(char*, aID->m3), sizeof aID->m3, &bytesRead); + if (NS_FAILED(rv)) + return rv; + + if (bytesRead != sizeof aID->m3) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadFastID(NSFastLoadID *aID) +{ + nsresult rv = Read32(aID); + if (NS_SUCCEEDED(rv)) + *aID ^= MFL_ID_XOR_KEY; + return rv; +} + +nsresult +nsFastLoadFileReader::ReadSharpObjectInfo(nsFastLoadSharpObjectInfo *aInfo) +{ + nsresult rv; + + rv = Read32(&aInfo->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(aInfo->mCIDOffset != 0, + "fastload reader: mCIDOffset cannot be zero!"); + + rv = Read16(&aInfo->mStrongRefCnt); + if (NS_FAILED(rv)) + return rv; + + rv = Read16(&aInfo->mWeakRefCnt); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadMuxedDocumentInfo(nsFastLoadMuxedDocumentInfo *aInfo) +{ + nsresult rv; + + nsCAutoString spec; + rv = ReadCString(spec); + if (NS_FAILED(rv)) + return rv; + + rv = Read32(&aInfo->mInitialSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + aInfo->mURISpec = ToNewCString(spec); + return NS_OK; +} + +nsresult +nsFastLoadFileReader::Open() +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + + // Don't bother buffering the header, as we immediately seek to EOF. + nsCOMPtr + bufferAccess(do_QueryInterface(mInputStream)); + if (bufferAccess) + bufferAccess->DisableBuffering(); + + rv = ReadHeader(&mHeader); + + if (bufferAccess) + bufferAccess->EnableBuffering(); + if (NS_FAILED(rv)) + return rv; + + if (mHeader.mVersion != MFL_FILE_VERSION) + return NS_ERROR_UNEXPECTED; + if (mHeader.mFooterOffset == 0) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_END, 0); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fileSize; + rv = seekable->Tell(&fileSize); + if (NS_FAILED(rv)) + return rv; + + nsInt64 fileSize64 = fileSize; + const nsInt64 maxUint32 = PR_UINT32_MAX; + NS_ASSERTION(fileSize64 <= maxUint32, "fileSize must fit in 32 bits"); + if ((PRUint32) fileSize64 != mHeader.mFileSize) + return NS_ERROR_UNEXPECTED; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + PRInt32(mHeader.mFooterOffset)); + if (NS_FAILED(rv)) + return rv; + + rv = ReadFooter(&mFooter); + if (NS_FAILED(rv)) + return rv; + + return seekable->Seek(nsISeekableStream::NS_SEEK_SET, + sizeof(nsFastLoadHeader)); +} + +NS_IMETHODIMP +nsFastLoadFileReader::Close() +{ + // Give up our strong "keepalive" references, in case not all objects that + // were deserialized were fully re-connected. + // + // This happens for sure when an nsFastLoadFileUpdater is created and wraps + // an nsFastLoadFileReader whose data was already deserialized by an earlier + // FastLoad episode. The reader is useful in the second such episode during + // a session not so much for reading objects as for its footer information, + // which primes the updater's tables so that after the update completes, the + // FastLoad file has a superset footer. + + for (PRUint32 i = 0, n = mFooter.mNumSharpObjects; i < n; i++) { + nsObjectMapEntry* entry = &mFooter.mObjectMap[i]; + entry->mReadObject = nsnull; + } + + return mInputStream->Close(); +} + +nsresult +nsFastLoadFileReader::DeserializeObject(nsISupports* *aObject) +{ + nsresult rv; + NSFastLoadID fastCID; + + rv = ReadFastID(&fastCID); + if (NS_FAILED(rv)) + return rv; + + const nsID& slowCID = mFooter.GetID(fastCID); + nsCOMPtr object(do_CreateInstance(slowCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr serializable(do_QueryInterface(object)); + if (!serializable) + return NS_ERROR_FAILURE; + + rv = serializable->Read(this); + if (NS_FAILED(rv)) + return rv; + + *aObject = object; + NS_ADDREF(*aObject); + return NS_OK; +} + +nsresult +nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject) +{ + nsresult rv; + NSFastLoadOID oid; + + rv = Read32(&oid); + if (NS_FAILED(rv)) + return rv; + oid ^= MFL_OID_XOR_KEY; + + nsCOMPtr object; + + if (oid == MFL_DULL_OBJECT_OID) { + // A very dull object, defined at point of single (strong) reference. + NS_ASSERTION(aIsStrongRef, "dull object read via weak ref!"); + + rv = DeserializeObject(getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + } else { + NS_ASSERTION((oid & MFL_WEAK_REF_TAG) == + (aIsStrongRef ? 0 : MFL_WEAK_REF_TAG), + "strong vs. weak ref deserialization mismatch!"); + + nsObjectMapEntry* entry = &mFooter.GetSharpObjectEntry(oid); + + // Check whether we've already deserialized the object for this OID. + object = entry->mReadObject; + if (!object) { + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + PRInt64 saveOffset; + nsDocumentMapReadEntry* saveDocMapEntry = nsnull; + + rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + PRUint32 saveOffset32 = saveOffset; + if (entry->mCIDOffset != saveOffset32) { + // We skipped deserialization of this object from its position + // earlier in the input stream, presumably due to the reference + // there being an nsFastLoadPtr, or (more likely) because the + // object was muxed in another document, and deserialization + // order does not match serialization order. So we must seek + // back and read it now. + NS_ASSERTION(entry->mCIDOffset < saveOffset32, + "out of order object?!"); + + // Ape our Seek wrapper by clearing mCurrentDocumentMapEntry. + // This allows for a skipped object to be referenced from two + // or more multiplexed documents in the FastLoad file. + saveDocMapEntry = mCurrentDocumentMapEntry; + mCurrentDocumentMapEntry = nsnull; + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + } + + rv = DeserializeObject(getter_AddRefs(object)); + if (NS_FAILED(rv)) + return rv; + + if (entry->mCIDOffset != saveOffset32) { + // Save the "skip offset" in case we need to skip this object + // definition when reading forward, later on. + rv = seekable->Tell(&entry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + + // Restore stream offset and mCurrentDocumentMapEntry in case + // we're still reading forward through a part of the multiplex + // to get object definitions eagerly. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + mCurrentDocumentMapEntry = saveDocMapEntry; + } + + // Save object until all refs have been deserialized. + entry->mReadObject = object; + } else { + // What if we are at a definition that's already been read? This + // case arises when a sharp object's def is serialized before its + // refs, while a non-defining ref is deserialized before the def. + // We must skip over the object definition. + if (oid & MFL_OBJECT_DEF_TAG) { + NS_ASSERTION(entry->mSkipOffset != 0, "impossible! see above"); + nsCOMPtr + seekable(do_QueryInterface(mInputStream)); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + entry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + } + } + + if (aIsStrongRef) { + NS_ASSERTION(entry->mStrongRefCnt != 0, + "mStrongRefCnt underflow!"); + --entry->mStrongRefCnt; + } else { + NS_ASSERTION(MFL_GET_WEAK_REFCNT(entry) != 0, + "mWeakRefCnt underflow!"); + MFL_DROP_WEAK_REFCNT(entry); + } + + if (entry->mStrongRefCnt == 0 && MFL_GET_WEAK_REFCNT(entry) == 0) + entry->mReadObject = nsnull; + } + + if (oid & MFL_QUERY_INTERFACE_TAG) { + NSFastLoadID iid; + rv = ReadFastID(&iid); + if (NS_FAILED(rv)) + return rv; + + rv = object->QueryInterface(mFooter.GetID(iid), + NS_REINTERPRET_CAST(void**, aObject)); + if (NS_FAILED(rv)) + return rv; + } else { + *aObject = object; + NS_ADDREF(*aObject); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::ReadID(nsID *aResult) +{ + nsresult rv; + NSFastLoadID fastID; + + rv = ReadFastID(&fastID); + if (NS_FAILED(rv)) + return rv; + + *aResult = mFooter.GetID(fastID); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileReader::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + mCurrentDocumentMapEntry = nsnull; + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->Seek(aWhence, aOffset); +} + +NS_IMETHODIMP +nsFastLoadFileReader::Tell(PRInt64 *aResult) +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->Tell(aResult); +} + +NS_IMETHODIMP +nsFastLoadFileReader::SetEOF() +{ + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + return seekable->SetEOF(); +} + +NS_COM nsresult +NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, + nsIInputStream* aSrcStream) +{ + nsFastLoadFileReader* reader = new nsFastLoadFileReader(aSrcStream); + if (!reader) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize reader's refcnt. + nsCOMPtr stream(reader); + + nsresult rv = reader->Open(); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +// -------------------------- nsFastLoadFileWriter -------------------------- + +NS_IMPL_ISUPPORTS_INHERITED4(nsFastLoadFileWriter, + nsBinaryOutputStream, + nsIObjectOutputStream, + nsIFastLoadFileControl, + nsIFastLoadWriteControl, + nsISeekableStream) + +MOZ_DECL_CTOR_COUNTER(nsFastLoadFileWriter) + +struct nsIDMapEntry : public PLDHashEntryHdr { + NSFastLoadID mFastID; // 1 + nsFastLoadFooter::mIDMap index + nsID mSlowID; // key, used by PLDHashTableOps below +}; + +PR_STATIC_CALLBACK(const void *) +idmap_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsIDMapEntry* entry = NS_STATIC_CAST(nsIDMapEntry*, aHdr); + + return &entry->mSlowID; +} + +PR_STATIC_CALLBACK(PLDHashNumber) +idmap_HashKey(PLDHashTable *aTable, const void *aKey) +{ + const nsID *idp = NS_REINTERPRET_CAST(const nsID*, aKey); + + return idp->m0; +} + +PR_STATIC_CALLBACK(PRBool) +idmap_MatchEntry(PLDHashTable *aTable, + const PLDHashEntryHdr *aHdr, + const void *aKey) +{ + const nsIDMapEntry* entry = NS_STATIC_CAST(const nsIDMapEntry*, aHdr); + const nsID *idp = NS_REINTERPRET_CAST(const nsID*, aKey); + + return memcmp(&entry->mSlowID, idp, sizeof(nsID)) == 0; +} + +static const PLDHashTableOps idmap_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + idmap_GetKey, + idmap_HashKey, + idmap_MatchEntry, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub, + NULL +}; + +nsresult +nsFastLoadFileWriter::MapID(const nsID& aSlowID, NSFastLoadID *aResult) +{ + nsIDMapEntry* entry = + NS_STATIC_CAST(nsIDMapEntry*, + PL_DHashTableOperate(&mIDMap, &aSlowID, PL_DHASH_ADD)); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (entry->mFastID == 0) { + entry->mFastID = mIDMap.entryCount; + entry->mSlowID = aSlowID; + } + + *aResult = entry->mFastID; + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteHeader(nsFastLoadHeader *aHeader) +{ + nsresult rv; + PRUint32 bytesWritten; + + rv = Write(aHeader->mMagic, MFL_FILE_MAGIC_SIZE, &bytesWritten); + if (NS_FAILED(rv)) + return rv; + + if (bytesWritten != MFL_FILE_MAGIC_SIZE) + return NS_ERROR_FAILURE; + + rv = Write32(aHeader->mChecksum); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mVersion); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aHeader->mFileSize); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +// nsIFastLoadFileControl methods: + +NS_IMETHODIMP +nsFastLoadFileWriter::GetChecksum(PRUint32 *aChecksum) +{ + if (mHeader.mChecksum == 0) + return NS_ERROR_NOT_AVAILABLE; + *aChecksum = mHeader.mChecksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SetChecksum(PRUint32 aChecksum) +{ + mHeader.mChecksum = aChecksum; + return NS_OK; +} + +struct nsDocumentMapWriteEntry : public nsDocumentMapEntry { + PRUint32 mCurrentSegmentOffset; // last written segment's offset +}; + +// Fast mapping from URI object pointer back to spec-indexed document info. +// We also may need the slow mapping from mURISpec to nsDocumentMapWriteEntry, +// because the writer's mDocumentMap double hash table may grow "behind the +// back of" each mURIMap entry's mDocMapEntry member. +struct nsURIMapWriteEntry : public nsObjectMapEntry { + nsDocumentMapWriteEntry* mDocMapEntry; + PRUint32 mGeneration; + const char* mURISpec; +}; + +NS_IMETHODIMP +nsFastLoadFileWriter::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsDocumentMapWriteEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, aURISpec, + PL_DHASH_LOOKUP)); + + *aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::StartMuxedDocument(nsISupports* aURI, + const char* aURISpec) +{ + // Save mDocumentMap table generation and mCurrentDocumentMapEntry key in + // case the hash table grows during the PL_DHASH_ADD operation. + PRUint32 saveGeneration = mDocumentMap.generation; + const char* saveURISpec = mCurrentDocumentMapEntry + ? mCurrentDocumentMapEntry->mString + : nsnull; + + nsDocumentMapWriteEntry* docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, aURISpec, + PL_DHASH_ADD)); + if (!docMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + // If the generation number changed, refresh mCurrentDocumentMapEntry. + if (mCurrentDocumentMapEntry && mDocumentMap.generation != saveGeneration) { + mCurrentDocumentMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, saveURISpec, + PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(mCurrentDocumentMapEntry), + "mCurrentDocumentMapEntry lost during table growth?!"); + + // Refresh saveGeneration for use below when initializing uriMapEntry. + saveGeneration = mDocumentMap.generation; + } + + NS_ASSERTION(docMapEntry->mString == nsnull, + "redundant multiplexed document?"); + if (docMapEntry->mString) + return NS_ERROR_UNEXPECTED; + + void* spec = nsMemory::Clone(aURISpec, strlen(aURISpec) + 1); + if (!spec) + return NS_ERROR_OUT_OF_MEMORY; + docMapEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); + + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_ADD)); + if (!uriMapEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(uriMapEntry->mDocMapEntry == nsnull, + "URI mapped to two different specs?"); + if (uriMapEntry->mDocMapEntry) + return NS_ERROR_UNEXPECTED; + + uriMapEntry->mObject = key; + NS_ADDREF(uriMapEntry->mObject); + uriMapEntry->mDocMapEntry = docMapEntry; + uriMapEntry->mGeneration = saveGeneration; + uriMapEntry->mURISpec = NS_REINTERPRET_CAST(const char*, spec); + TRACE_MUX(('w', "start %p (%p) %s\n", aURI, key.get(), aURISpec)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) +{ + // Avoid repeatedly QI'ing to nsISeekableStream as we tell and seek. + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + + // Capture the current file offset (XXXbe maintain our own via Write?) + nsresult rv; + PRInt64 currentSegmentOffset; + rv = seekable->Tell(¤tSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + PRUint32 currentSegmentOffset32 = currentSegmentOffset; + // Look for an existing entry keyed by aURI, added by StartMuxedDocument. + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(uriMapEntry), + "SelectMuxedDocument without prior StartMuxedDocument?"); + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) + return NS_ERROR_UNEXPECTED; + + // Beware that uriMapEntry->mDocMapEntry may be stale, if an mDocumentMap + // addition caused that table to grow. We save the mDocumentMap generation + // in each uriMapEntry and compare it to the current generation, rehashing + // uriMapEntry->mURISpec if necessary. + + nsDocumentMapWriteEntry* docMapEntry = uriMapEntry->mDocMapEntry; + if (uriMapEntry->mGeneration != mDocumentMap.generation) { + docMapEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&mDocumentMap, + uriMapEntry->mURISpec, + PL_DHASH_LOOKUP)); + NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(docMapEntry), "lost mDocMapEntry!?"); + uriMapEntry->mDocMapEntry = docMapEntry; + uriMapEntry->mGeneration = mDocumentMap.generation; + } + docMapEntry = uriMapEntry->mDocMapEntry; + + // If there is a muxed document segment open, close it now by setting its + // length, stored in the second PRUint32 of the segment. + nsDocumentMapWriteEntry* prevDocMapEntry = mCurrentDocumentMapEntry; + if (prevDocMapEntry) { + if (prevDocMapEntry == docMapEntry) { + TRACE_MUX(('w', "select prev %s same as current!\n", + prevDocMapEntry->mString)); + *aResult = docMapEntry->mURI; + NS_ADDREF(*aResult); + return NS_OK; + } + + PRUint32 prevSegmentOffset = prevDocMapEntry->mCurrentSegmentOffset; + TRACE_MUX(('w', "select prev %s offset %lu\n", + prevDocMapEntry->mString, prevSegmentOffset)); + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + prevSegmentOffset + 4); + if (NS_FAILED(rv)) + return rv; + + // The length counts all bytes in the segment, including the header + // that contains [nextSegmentOffset, length]. + rv = Write32(currentSegmentOffset32 - prevSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Seek back to the current offset only if we are not going to seek + // back to *this* entry's last "current" segment offset and write its + // next segment offset at the first PRUint32 of the segment. + if (!docMapEntry->mInitialSegmentOffset) { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + } + } + + // If this entry was newly added, set its key and initial segment offset. + // Otherwise, seek back to write the next segment offset of the previous + // segment for this document in the multiplex. + if (!docMapEntry->mInitialSegmentOffset) { + docMapEntry->mInitialSegmentOffset = currentSegmentOffset32; + } else { + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + docMapEntry->mCurrentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(currentSegmentOffset32); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + } + + // Update this document's current segment offset so we can later fix its + // next segment offset (unless it is last, in which case we leave the zero + // placeholder as a terminator). + docMapEntry->mCurrentSegmentOffset = currentSegmentOffset32; + + rv = Write32(0); // nextSegmentOffset placeholder + if (NS_FAILED(rv)) + return rv; + + rv = Write32(0); // length placeholder + if (NS_FAILED(rv)) + return rv; + + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + + mCurrentDocumentMapEntry = docMapEntry; + TRACE_MUX(('w', "select %p (%p) offset %lu\n", + aURI, key.get(), currentSegmentOffset)); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::EndMuxedDocument(nsISupports* aURI) +{ + nsCOMPtr key(do_QueryInterface(aURI)); + nsURIMapWriteEntry* uriMapEntry = + NS_STATIC_CAST(nsURIMapWriteEntry*, + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_LOOKUP)); + + // If the URI isn't in the map, nsFastLoadFileWriter::StartMuxedDocument + // must have been called with a redundant URI, *and* its caller must have + // ignored the NS_ERROR_UNEXPECTED it returned in that case. + if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) { + TRACE_MUX(('w', "bad end %p (%p)\n", aURI, key.get())); + return NS_ERROR_UNEXPECTED; + } + + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(&mURIMap); + if (mURIMap.removedCount >= (size >> 2)) + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(&mURIMap, uriMapEntry); + + TRACE_MUX(('w', "end %p (%p)\n", aURI, key.get())); + return NS_OK; +} + +struct nsDependencyMapEntry : public nsStringMapEntry { + PRInt64 mLastModified; +}; + +NS_IMETHODIMP +nsFastLoadFileWriter::AddDependency(nsIFile* aFile) +{ + nsCAutoString path; + nsresult rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsDependencyMapEntry* entry = + NS_STATIC_CAST(nsDependencyMapEntry*, + PL_DHashTableOperate(&mDependencyMap, path.get(), + PL_DHASH_ADD)); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (!entry->mString) { + const char *tmp = ToNewCString(path); + if (!tmp) + return NS_ERROR_OUT_OF_MEMORY; + entry->mString = tmp; + + // If we can't get the last modified time from aFile, assume it does + // not exist, or is otherwise inaccessible to us (due to permissions), + // remove the dependency, and suppress the failure. + // + // Otherwise, we would end up aborting the fastload process due to a + // missing .js or .xul or other file on every startup. + + rv = aFile->GetLastModifiedTime(&entry->mLastModified); + if (NS_FAILED(rv)) { + PL_DHashTableOperate(&mDependencyMap, path.get(), PL_DHASH_REMOVE); + rv = NS_OK; + } + } + return rv; +} + +nsresult +nsFastLoadFileWriter::WriteFooterPrefix(const nsFastLoadFooterPrefix& aFooterPrefix) +{ + nsresult rv; + + rv = Write32(aFooterPrefix.mNumIDs); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumSharpObjects); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumMuxedDocuments); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aFooterPrefix.mNumDependencies); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteSlowID(const nsID& aID) +{ + nsresult rv; + + rv = Write32(aID.m0); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aID.m1); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aID.m2); + if (NS_FAILED(rv)) + return rv; + + PRUint32 bytesWritten; + rv = Write(NS_REINTERPRET_CAST(const char*, aID.m3), sizeof aID.m3, + &bytesWritten); + if (NS_FAILED(rv)) + return rv; + + if (bytesWritten != sizeof aID.m3) + return NS_ERROR_FAILURE; + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteFastID(NSFastLoadID aID) +{ + return Write32(aID ^ MFL_ID_XOR_KEY); +} + +nsresult +nsFastLoadFileWriter::WriteSharpObjectInfo(const nsFastLoadSharpObjectInfo& aInfo) +{ + nsresult rv; + + NS_ASSERTION(aInfo.mCIDOffset != 0, + "fastload writer: mCIDOffset cannot be zero!"); + + rv = Write32(aInfo.mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aInfo.mStrongRefCnt); + if (NS_FAILED(rv)) + return rv; + + rv = Write16(aInfo.mWeakRefCnt); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::WriteMuxedDocumentInfo(const nsFastLoadMuxedDocumentInfo& aInfo) +{ + nsresult rv; + + rv = WriteStringZ(aInfo.mURISpec); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(aInfo.mInitialSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::IDMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsIDMapEntry* entry = NS_STATIC_CAST(nsIDMapEntry*, aHdr); + PRUint32 index = entry->mFastID - 1; + nsID* vector = NS_REINTERPRET_CAST(nsID*, aData); + + NS_ASSERTION(index < aTable->entryCount, "bad nsIDMap index!"); + vector[index] = entry->mSlowID; + return PL_DHASH_NEXT; +} + +struct nsSharpObjectMapEntry : public nsObjectMapEntry { + NSFastLoadOID mOID; + nsFastLoadSharpObjectInfo mInfo; +}; + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::ObjectMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsSharpObjectMapEntry* entry = NS_STATIC_CAST(nsSharpObjectMapEntry*, aHdr); + PRUint32 index = MFL_OID_TO_SHARP_INDEX(entry->mOID); + nsFastLoadSharpObjectInfo* vector = + NS_REINTERPRET_CAST(nsFastLoadSharpObjectInfo*, aData); + + NS_ASSERTION(index < aTable->entryCount, "bad nsObjectMap index!"); + vector[index] = entry->mInfo; + + NS_ASSERTION(entry->mInfo.mStrongRefCnt, "no strong ref in serialization!"); + + // Ignore tagged object ids stored as object pointer keys (the updater + // code does this). + if ((NS_PTR_TO_INT32(entry->mObject) & MFL_OBJECT_DEF_TAG) == 0) + NS_RELEASE(entry->mObject); + + return PL_DHASH_NEXT; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::DocumentMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFastLoadFileWriter* writer = + NS_REINTERPRET_CAST(nsFastLoadFileWriter*, aTable->data); + nsDocumentMapWriteEntry* entry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, aHdr); + nsresult* rvp = NS_REINTERPRET_CAST(nsresult*, aData); + + nsFastLoadMuxedDocumentInfo info; + info.mURISpec = entry->mString; + info.mInitialSegmentOffset = entry->mInitialSegmentOffset; + *rvp = writer->WriteMuxedDocumentInfo(info); + + return NS_FAILED(*rvp) ? PL_DHASH_STOP : PL_DHASH_NEXT; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileWriter::DependencyMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFastLoadFileWriter* writer = + NS_REINTERPRET_CAST(nsFastLoadFileWriter*, aTable->data); + nsDependencyMapEntry* entry = NS_STATIC_CAST(nsDependencyMapEntry*, aHdr); + nsresult* rvp = NS_REINTERPRET_CAST(nsresult*, aData); + + *rvp = writer->WriteStringZ(entry->mString); + if (NS_SUCCEEDED(*rvp)) + *rvp = writer->Write64(entry->mLastModified); + + return NS_FAILED(*rvp) ? PL_DHASH_STOP :PL_DHASH_NEXT; +} + +nsresult +nsFastLoadFileWriter::WriteFooter() +{ + nsresult rv; + PRUint32 i, count; + + nsFastLoadFooterPrefix footerPrefix; + footerPrefix.mNumIDs = mIDMap.entryCount; + footerPrefix.mNumSharpObjects = mObjectMap.entryCount; + footerPrefix.mNumMuxedDocuments = mDocumentMap.entryCount; + footerPrefix.mNumDependencies = mDependencyMap.entryCount; + + rv = WriteFooterPrefix(footerPrefix); + if (NS_FAILED(rv)) + return rv; + + // Enumerate mIDMap into a vector indexed by mFastID and write it. + nsID* idvec = new nsID[footerPrefix.mNumIDs]; + if (!idvec) + return NS_ERROR_OUT_OF_MEMORY; + + count = PL_DHashTableEnumerate(&mIDMap, IDMapEnumerate, idvec); + NS_ASSERTION(count == footerPrefix.mNumIDs, "bad mIDMap enumeration!"); + for (i = 0; i < count; i++) { + rv = WriteSlowID(idvec[i]); + if (NS_FAILED(rv)) break; + } + + delete[] idvec; + if (NS_FAILED(rv)) + return rv; + + // Enumerate mObjectMap into a vector indexed by mOID and write it. + nsFastLoadSharpObjectInfo* objvec = + new nsFastLoadSharpObjectInfo[footerPrefix.mNumSharpObjects]; + if (!objvec) + return NS_ERROR_OUT_OF_MEMORY; +#ifdef NS_DEBUG + memset(objvec, 0, footerPrefix.mNumSharpObjects * + sizeof(nsFastLoadSharpObjectInfo)); +#endif + + count = PL_DHashTableEnumerate(&mObjectMap, ObjectMapEnumerate, objvec); + NS_ASSERTION(count == footerPrefix.mNumSharpObjects, + "bad mObjectMap enumeration!"); + for (i = 0; i < count; i++) { + rv = WriteSharpObjectInfo(objvec[i]); + if (NS_FAILED(rv)) break; + } + + delete[] objvec; + if (NS_FAILED(rv)) + return rv; + + // Enumerate mDocumentMap, writing nsFastLoadMuxedDocumentInfo records + count = PL_DHashTableEnumerate(&mDocumentMap, DocumentMapEnumerate, &rv); + if (NS_FAILED(rv)) + return rv; + + NS_ASSERTION(count == footerPrefix.mNumMuxedDocuments, + "bad mDocumentMap enumeration!"); + + // Write out make-like file dependencies. + count = PL_DHashTableEnumerate(&mDependencyMap, DependencyMapEnumerate, &rv); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::Init() +{ + if (!PL_DHashTableInit(&mIDMap, &idmap_DHashTableOps, (void *)this, + sizeof(nsIDMapEntry), PL_DHASH_MIN_SIZE)) { + mIDMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mObjectMap, &objmap_DHashTableOps, (void *)this, + sizeof(nsSharpObjectMapEntry), PL_DHASH_MIN_SIZE)) { + mObjectMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mDocumentMap, &strmap_DHashTableOps, (void *)this, + sizeof(nsDocumentMapWriteEntry), + PL_DHASH_MIN_SIZE)) { + mDocumentMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mURIMap, &objmap_DHashTableOps, (void *)this, + sizeof(nsURIMapWriteEntry), PL_DHASH_MIN_SIZE)) { + mURIMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!PL_DHashTableInit(&mDependencyMap, &strmap_DHashTableOps, (void *)this, + sizeof(nsDependencyMapEntry), PL_DHASH_MIN_SIZE)) { + mDependencyMap.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +nsresult +nsFastLoadFileWriter::Open() +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + sizeof(nsFastLoadHeader)); + if (NS_FAILED(rv)) + return rv; + + return Init(); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Close() +{ + nsresult rv; + + memcpy(mHeader.mMagic, magic, MFL_FILE_MAGIC_SIZE); + mHeader.mChecksum = 0; + mHeader.mVersion = MFL_FILE_VERSION; + + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + + PRInt64 footerOffset; + rv = seekable->Tell(&footerOffset); + + LL_L2UI(mHeader.mFooterOffset, footerOffset); + if (NS_FAILED(rv)) + return rv; + + // If there is a muxed document segment open, close it now by setting its + // length, stored in the second PRUint32 of the segment. + if (mCurrentDocumentMapEntry) { + PRUint32 currentSegmentOffset = + mCurrentDocumentMapEntry->mCurrentSegmentOffset; + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + currentSegmentOffset + 4); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(mHeader.mFooterOffset - currentSegmentOffset); + if (NS_FAILED(rv)) + return rv; + + // Seek back to the current offset to write the footer. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + mHeader.mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + mCurrentDocumentMapEntry = nsnull; + } + + rv = WriteFooter(); + if (NS_FAILED(rv)) + return rv; + PRInt64 fileSize; + rv = seekable->Tell(&fileSize); + LL_L2UI(mHeader.mFileSize, fileSize); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + rv = WriteHeader(&mHeader); + if (NS_FAILED(rv)) + return rv; + + // Now compute the checksum, using mFileIO to get an input stream on the + // underlying FastLoad file. + if (mFileIO) { + // Get the unbuffered output stream, which flushes the buffered header + // so we can read and checksum it along with the rest of the file, and + // which allows us to write the checksum directly. + nsCOMPtr + bufferAccess(do_QueryInterface(mOutputStream)); + nsCOMPtr output; + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(output)); + if (NS_FAILED(rv) || !output) + return NS_ERROR_UNEXPECTED; + + nsCOMPtr input; + rv = mFileIO->GetInputStream(getter_AddRefs(input)); + if (NS_FAILED(rv)) + return rv; + + // Get the unbuffered input stream, to avoid copying overhead and to + // keep our view of the file coherent with the writer -- we don't want + // to hit a stale buffer in the reader's underlying stream. + bufferAccess = do_QueryInterface(input); + rv = bufferAccess->GetUnbufferedStream(getter_AddRefs(input)); + if (NS_FAILED(rv) || !input) + return NS_ERROR_UNEXPECTED; + + // Seek the input stream to offset 0, in case it's a reader who has + // already been used to consume some of the FastLoad file. + seekable = do_QueryInterface(input); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + if (NS_FAILED(rv)) + return rv; + + char buf[MFL_CHECKSUM_BUFSIZE]; + PRUint32 len, rem = 0; + PRUint32 checksum = 0; + + // Ok, we're finally ready to checksum the FastLoad file we just wrote! + while (NS_SUCCEEDED(rv = + input->Read(buf + rem, sizeof buf - rem, &len)) && + len) { + len += rem; + rem = NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, + buf), + len, + PR_FALSE); + if (rem) + memcpy(buf, buf + len - rem, rem); + } + if (NS_FAILED(rv)) + return rv; + + if (rem) { + NS_AccumulateFastLoadChecksum(&checksum, + NS_REINTERPRET_CAST(PRUint8*, buf), + rem, + PR_TRUE); + } + + // Store the checksum in the FastLoad file header and remember it via + // mHeader.mChecksum, for GetChecksum. + seekable = do_QueryInterface(output); + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + offsetof(nsFastLoadHeader, mChecksum)); + if (NS_FAILED(rv)) + return rv; + + mHeader.mChecksum = checksum; + checksum = NS_SWAP32(checksum); + PRUint32 bytesWritten; + rv = output->Write(NS_REINTERPRET_CAST(char*, &checksum), + sizeof checksum, + &bytesWritten); + if (NS_FAILED(rv)) + return rv; + if (bytesWritten != sizeof checksum) + return NS_ERROR_FAILURE; + } + + return mOutputStream->Close(); +} + +// Psuedo-tag used as flag between WriteSingleRefObject and WriteObjectCommon. +#define MFL_SINGLE_REF_PSEUDO_TAG PR_BIT(MFL_OBJECT_TAG_BITS) + +nsresult +nsFastLoadFileWriter::WriteObjectCommon(nsISupports* aObject, + PRBool aIsStrongRef, + PRUint32 aTags) +{ + nsrefcnt rc; + nsresult rv; + + NS_ASSERTION((NS_PTR_TO_INT32(aObject) & MFL_OBJECT_DEF_TAG) == 0, + "odd nsISupports*, oh no!"); + + // Here be manual refcounting dragons! + rc = aObject->AddRef(); + NS_ASSERTION(rc != 0, "bad refcnt when writing aObject!"); + + NSFastLoadOID oid; + nsCOMPtr classInfo; + + if (rc == 2 && (aTags & MFL_SINGLE_REF_PSEUDO_TAG)) { + // Dull object: only one strong ref and no weak refs in serialization. + // Conservative: we don't trust the caller if there are more than two + // refs (one from the AddRef above, one from the data structure that's + // being serialized). + oid = MFL_DULL_OBJECT_OID; + aObject->Release(); + } else { + // Object is presumed to be multiply connected through some combo of + // strong and weak refs. Hold onto it via mObjectMap. + nsSharpObjectMapEntry* entry = + NS_STATIC_CAST(nsSharpObjectMapEntry*, + PL_DHashTableOperate(&mObjectMap, aObject, + PL_DHASH_ADD)); + if (!entry) { + aObject->Release(); + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!entry->mObject) { + // First time we've seen this object address: add it to mObjectMap + // and serialize the object at the current stream offset. + PRInt64 thisOffset; + rv = Tell(&thisOffset); + if (NS_FAILED(rv)) { + aObject->Release(); + return rv; + } + + // NB: aObject was already held, and mObject is a raw nsISupports*. + entry->mObject = aObject; + + oid = (mObjectMap.entryCount << MFL_OBJECT_TAG_BITS); + entry->mOID = oid; + + // NB: the (32-bit, fast) CID and object data follow the OID. + entry->mInfo.mCIDOffset = thisOffset + sizeof(oid); + entry->mInfo.mStrongRefCnt = aIsStrongRef ? 1 : 0; + entry->mInfo.mWeakRefCnt = aIsStrongRef ? 0 : 1; + + // Record in oid the fact that we're defining this object in the + // stream, and get the object's class info here, so we can take + // note of singletons in order to avoid reserializing them when + // updating after reading. + oid |= MFL_OBJECT_DEF_TAG; + classInfo = do_QueryInterface(aObject); + if (!classInfo) + return NS_ERROR_FAILURE; + + PRUint32 flags; + if (NS_SUCCEEDED(classInfo->GetFlags(&flags)) && + (flags & nsIClassInfo::SINGLETON)) { + MFL_SET_SINGLETON_FLAG(&entry->mInfo); + } + } else { + // Already serialized, recover oid and update the desired refcnt. + oid = entry->mOID; + if (aIsStrongRef) { + ++entry->mInfo.mStrongRefCnt; + NS_ASSERTION(entry->mInfo.mStrongRefCnt != 0, + "mStrongRefCnt overflow"); + } else { + MFL_BUMP_WEAK_REFCNT(&entry->mInfo); + NS_ASSERTION(MFL_GET_WEAK_REFCNT(&entry->mInfo) != 0, + "mWeakRefCnt overflow"); + } + + aObject->Release(); + } + } + + if (!aIsStrongRef) + oid |= MFL_WEAK_REF_TAG; + oid |= (aTags & MFL_QUERY_INTERFACE_TAG); + + rv = Write32(oid ^ MFL_OID_XOR_KEY); + if (NS_FAILED(rv)) + return rv; + + if (oid & MFL_OBJECT_DEF_TAG) { + nsCOMPtr serializable(do_QueryInterface(aObject)); + if (!serializable) + return NS_ERROR_FAILURE; + + nsCID slowCID; + rv = classInfo->GetClassIDNoAlloc(&slowCID); + if (NS_FAILED(rv)) + return rv; + + NSFastLoadID fastCID; + rv = MapID(slowCID, &fastCID); + if (NS_FAILED(rv)) + return rv; + + rv = WriteFastID(fastCID); + if (NS_FAILED(rv)) + return rv; + + rv = serializable->Write(this); + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteObject(nsISupports* aObject, PRBool aIsStrongRef) +{ +#ifdef NS_DEBUG + nsCOMPtr rootObject(do_QueryInterface(aObject)); + + NS_ASSERTION(rootObject.get() == aObject, + "bad call to WriteObject -- call WriteCompoundObject!"); +#endif + + return WriteObjectCommon(aObject, aIsStrongRef, 0); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteSingleRefObject(nsISupports* aObject) +{ +#ifdef NS_DEBUG + nsCOMPtr rootObject(do_QueryInterface(aObject)); + + NS_ASSERTION(rootObject.get() == aObject, + "bad call to WriteSingleRefObject -- call WriteCompoundObject!"); +#endif + + return WriteObjectCommon(aObject, PR_TRUE, MFL_SINGLE_REF_PSEUDO_TAG); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + nsresult rv; + nsCOMPtr rootObject(do_QueryInterface(aObject)); + +#ifdef NS_DEBUG + nsCOMPtr roundtrip; + rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip)); + + NS_ASSERTION(rootObject.get() != aObject, + "wasteful call to WriteCompoundObject -- call WriteObject!"); + NS_ASSERTION(roundtrip.get() == aObject, + "bad aggregation or multiple inheritance detected by call to " + "WriteCompoundObject!"); +#endif + + rv = WriteObjectCommon(rootObject, aIsStrongRef, MFL_QUERY_INTERFACE_TAG); + if (NS_FAILED(rv)) + return rv; + + NSFastLoadID iid; + rv = MapID(aIID, &iid); + if (NS_FAILED(rv)) + return rv; + + return WriteFastID(iid); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::WriteID(const nsID& aID) +{ + nsresult rv; + NSFastLoadID fastID; + + rv = MapID(aID, &fastID); + if (NS_FAILED(rv)) + return rv; + + return WriteFastID(fastID); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + mCurrentDocumentMapEntry = nsnull; + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->Seek(aWhence, aOffset); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::Tell(PRInt64 *aResult) +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->Tell(aResult); +} + +NS_IMETHODIMP +nsFastLoadFileWriter::SetEOF() +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + return seekable->SetEOF(); +} + +NS_COM nsresult +NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult, + nsIOutputStream* aDestStream, + nsIFastLoadFileIO* aFileIO) +{ + nsFastLoadFileWriter* writer = + new nsFastLoadFileWriter(aDestStream, aFileIO); + if (!writer) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize writer's refcnt. + nsCOMPtr stream(writer); + + nsresult rv = writer->Open(); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +// -------------------------- nsFastLoadFileUpdater -------------------------- + +NS_IMPL_ISUPPORTS_INHERITED1(nsFastLoadFileUpdater, + nsFastLoadFileWriter, + nsIFastLoadFileIO) + +NS_IMETHODIMP +nsFastLoadFileUpdater::GetInputStream(nsIInputStream** aResult) +{ + *aResult = mInputStream; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileUpdater::GetOutputStream(nsIOutputStream** aResult) +{ + *aResult = nsnull; + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsFastLoadFileUpdater::CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsDocumentMapReadEntry* readEntry = + NS_STATIC_CAST(nsDocumentMapReadEntry*, aHdr); + nsFastLoadFileUpdater* updater = + NS_REINTERPRET_CAST(nsFastLoadFileUpdater*, aData); + + void* spec = nsMemory::Clone(readEntry->mString, + strlen(readEntry->mString) + 1); + if (!spec) + return PL_DHASH_STOP; + + nsDocumentMapWriteEntry* writeEntry = + NS_STATIC_CAST(nsDocumentMapWriteEntry*, + PL_DHashTableOperate(&updater->mDocumentMap, spec, + PL_DHASH_ADD)); + if (!writeEntry) { + nsMemory::Free(spec); + return PL_DHASH_STOP; + } + + writeEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + writeEntry->mURI = nsnull; + writeEntry->mInitialSegmentOffset = readEntry->mInitialSegmentOffset; + writeEntry->mCurrentSegmentOffset = 0; + return PL_DHASH_NEXT; +} + +nsresult +nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) +{ + nsCOMPtr seekable(do_QueryInterface(mOutputStream)); + if (!seekable) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + rv = nsFastLoadFileWriter::Init(); + if (NS_FAILED(rv)) + return rv; + + PRUint32 i, n; + + // Map from dense, zero-based, uint32 NSFastLoadID in reader to 16-byte + // nsID in updater. + nsID* readIDMap = aReader->mFooter.mIDMap; + for (i = 0, n = aReader->mFooter.mNumIDs; i < n; i++) { + NSFastLoadID fastID; + rv = MapID(readIDMap[i], &fastID); + NS_ASSERTION(fastID == i + 1, "huh?"); + if (NS_FAILED(rv)) + return rv; + } + + // Map from reader dense, zero-based MFL_OID_TO_SHARP_INDEX(oid) to sharp + // object offset and refcnt information in updater. + nsFastLoadFileReader::nsObjectMapEntry* readObjectMap = + aReader->mFooter.mObjectMap; + + // Prepare to save aReader state in case we need to seek back and read a + // singleton object that might otherwise get written by this updater. + nsDocumentMapReadEntry* saveDocMapEntry = nsnull; + nsCOMPtr inputSeekable; + PRInt64 saveOffset = 0; + + for (i = 0, n = aReader->mFooter.mNumSharpObjects; i < n; i++) { + nsFastLoadFileReader::nsObjectMapEntry* readEntry = &readObjectMap[i]; + + NS_ASSERTION(readEntry->mCIDOffset != 0, + "fastload updater: mCIDOffset cannot be zero!"); + + // If the reader didn't read this object but it's a singleton, we must + // "deserialize" it now, to discover its one and only root nsISupports + // address. The object already exists in memory if it was created at + // startup without resort to the FastLoad file. The canonical example + // is the system principal object held by all XUL JS scripts. + + nsISupports* obj = readEntry->mReadObject; + if (!obj && MFL_GET_SINGLETON_FLAG(readEntry)) { + if (!saveDocMapEntry) { + inputSeekable = do_QueryInterface(aReader->mInputStream); + rv = inputSeekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + saveDocMapEntry = aReader->mCurrentDocumentMapEntry; + aReader->mCurrentDocumentMapEntry = nsnull; + } + + rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, + readEntry->mCIDOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aReader + ->DeserializeObject(getter_AddRefs(readEntry->mReadObject)); + if (NS_FAILED(rv)) + return rv; + obj = readEntry->mReadObject; + + // Don't forget to set mSkipOffset in case someone calls the reader + // to "deserialize" (yet again) the object we just read. + // + // Say the singleton is the system principal, and the FastLoad file + // contains data for navigator.xul including scripts and functions. + // If we update the FastLoad file to contain data for messenger.xul + // in a separate session started via mozilla -mail, *and during the + // same FastLoad episode in this session* race to open a navigator + // window, we will attempt to read all objects serialized in the + // navigator.xul portion of the FastLoad file. + // + // mSkipOffset must be set in such a case so the reader can skip + // the system principal's serialized data, because the updater for + // messenger.xul being opened here has already read it. + + rv = inputSeekable->Tell(&readEntry->mSkipOffset); + if (NS_FAILED(rv)) + return rv; + } + + NSFastLoadOID oid = MFL_SHARP_INDEX_TO_OID(i); + void* key = obj + ? NS_REINTERPRET_CAST(void*, obj) + : NS_REINTERPRET_CAST(void*, (oid | MFL_OBJECT_DEF_TAG)); + + nsSharpObjectMapEntry* writeEntry = + NS_STATIC_CAST(nsSharpObjectMapEntry*, + PL_DHashTableOperate(&mObjectMap, key, + PL_DHASH_ADD)); + if (!writeEntry) + return NS_ERROR_OUT_OF_MEMORY; + + // Hold the object if there is one, so that objmap_ClearEntry can + // release the reference. + NS_IF_ADDREF(obj); + writeEntry->mObject = NS_REINTERPRET_CAST(nsISupports*, key); + writeEntry->mOID = oid; + writeEntry->mInfo.mCIDOffset = readEntry->mCIDOffset; + writeEntry->mInfo.mStrongRefCnt = readEntry->mSaveStrongRefCnt; + writeEntry->mInfo.mWeakRefCnt = readEntry->mSaveWeakRefCnt; + } + + // If we had to read any singletons, restore aReader's saved state. + if (saveDocMapEntry) { + rv = inputSeekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + aReader->mCurrentDocumentMapEntry = saveDocMapEntry; + } + + // Copy URI spec string and initial segment offset in FastLoad file from + // nsDocumentMapReadEntry in reader to nsDocumentMapWriteEntry in updater. + // If we didn't enumerate all entries, we ran out of memory. + n = PL_DHashTableEnumerate(&aReader->mFooter.mDocumentMap, + CopyReadDocumentMapEntryToUpdater, + this); + if (n != aReader->mFooter.mDocumentMap.entryCount) + return NS_ERROR_OUT_OF_MEMORY; + + // Copy source filename dependencies from reader to updater. + nsISupportsArray* readDeps = aReader->mFooter.mDependencies; + rv = readDeps->Count(&n); + if (NS_FAILED(rv)) + return rv; + + for (i = 0; i < n; i++) { + nsCOMPtr file; + rv = readDeps->GetElementAt(i, getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = AddDependency(file); + if (NS_FAILED(rv)) + return rv; + } + + // Seek to the reader's footer offset so we overwrite the footer. First, + // update the header to have a zero mFooterOffset, which will invalidate + // the FastLoad file on next startup read attempt, should we crash before + // completing this update. + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + offsetof(nsFastLoadHeader, mFooterOffset)); + if (NS_FAILED(rv)) + return rv; + + rv = Write32(0); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, + aReader->mHeader.mFooterOffset); + if (NS_FAILED(rv)) + return rv; + + // Avoid creating yet another object by implementing nsIFastLoadFileIO on + // this updater, and save aReader's input stream so it can be returned by + // GetInputStream called from nsFastLoadFileWriter::Close. This requires + // that we override Close to break the resulting zero-length cycle. + mFileIO = this; + mInputStream = aReader->mInputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadFileUpdater::Close() +{ + // Call base-class Close implementation, which uses mFileIO. + nsresult rv = nsFastLoadFileWriter::Close(); + + // Break degenerate cycle from this->mFileIO to this. + mFileIO = nsnull; + return rv; +} + +NS_COM nsresult +NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, + nsIOutputStream* aOutputStream, + nsIObjectInputStream* aReaderAsStream) +{ + // Make sure that aReaderAsStream is an nsFastLoadFileReader. + nsCOMPtr reader(do_QueryInterface(aReaderAsStream)); + if (!reader) + return NS_ERROR_UNEXPECTED; + + nsFastLoadFileUpdater* updater = new nsFastLoadFileUpdater(aOutputStream); + if (!updater) + return NS_ERROR_OUT_OF_MEMORY; + + // Stabilize updater's refcnt. + nsCOMPtr stream(updater); + + nsresult rv = updater->Open(NS_STATIC_CAST(nsFastLoadFileReader*, + aReaderAsStream)); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h new file mode 100644 index 00000000..9f6f061a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadFile.h @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsFastLoadFile_h___ +#define nsFastLoadFile_h___ + +/** + * Mozilla FastLoad file format and helper types. + */ + +#include "prtypes.h" +#include "pldhash.h" + +#include "nsBinaryStream.h" +#include "nsCOMPtr.h" +#include "nsDebug.h" +#include "nsID.h" +#include "nsMemory.h" +#include "nsVoidArray.h" + +#include "nsIFastLoadFileControl.h" +#include "nsIFastLoadService.h" +#include "nsISeekableStream.h" +#include "nsISupportsArray.h" + +/** + * FastLoad file Object ID (OID) is an identifier for multiply and cyclicly + * connected objects in the serialized graph of all reachable objects. + * + * Holy Mixed Metaphors: JS, after Common Lisp, uses #n= to define a "sharp + * variable" naming an object that's multiply or cyclicly connected, and #n# + * to stand for a connection to an already-defined object. We too call any + * object with multiple references "sharp", and (here it comes) any object + * with only one reference "dull". + * + * Note that only sharp objects require a mapping from OID to FastLoad file + * offset and other information. Dull objects can be serialized _in situ_ + * (where they are referenced) and deserialized when their (singular, shared) + * OID is scanned. + * + * We also compress 16-byte XPCOM IDs into 32-bit dense identifiers to save + * space. See nsFastLoadFooter, below, for the mapping data structure used to + * compute an nsID given an NSFastLoadID. + */ +typedef PRUint32 NSFastLoadID; // nsFastLoadFooter::mIDMap index +typedef PRUint32 NSFastLoadOID; // nsFastLoadFooter::mObjectMap index + +/** + * A Mozilla FastLoad file is an untagged (in general) stream of objects and + * primitive-type data. Small integers are fairly common, and could easily be + * confused for NSFastLoadIDs and NSFastLoadOIDs. To help catch bugs where + * reader and writer code fail to match, we XOR unlikely 32-bit numbers with + * NSFastLoad*IDs when storing and fetching. The following unlikely values are + * irrational numbers ((sqrt(5)-1)/2, sqrt(2)-1) represented in fixed point. + * + * The reader XORs, converts the ID to an index, and bounds-checks all array + * accesses that use the index. Array access code asserts that the index is in + * bounds, and returns a dummy array element if it isn't. + */ +#define MFL_ID_XOR_KEY 0x9E3779B9 // key XOR'd with ID when serialized +#define MFL_OID_XOR_KEY 0x6A09E667 // key XOR'd with OID when serialized + +/** + * An OID can be tagged to introduce the serialized definition of the object, + * or to stand for a strong or weak reference to that object. Thus the high + * 29 bits actually identify the object, and the low three bits tell whether + * the object is being defined or just referenced -- and via what inheritance + * chain or inner object, if necessary. + * + * The MFL_QUERY_INTERFACE_TAG bit helps us cope with aggregation and multiple + * inheritance: object identity follows the XPCOM rule, but a deserializer may + * need to query for an interface not on the primary inheritance chain ending + * in the nsISupports whose address uniquely identifies the XPCOM object being + * referenced or defined. + */ +#define MFL_OBJECT_TAG_BITS 3 +#define MFL_OBJECT_TAG_MASK PR_BITMASK(MFL_OBJECT_TAG_BITS) + +#define MFL_OBJECT_DEF_TAG 1U // object definition follows this OID +#define MFL_WEAK_REF_TAG 2U // OID weakly refers to a prior object + // NB: do not confuse with nsWeakPtr! +#define MFL_QUERY_INTERFACE_TAG 4U // QI object to the ID follows this OID + // NB: an NSFastLoadID, not an nsIID! + +/** + * The dull object identifier introduces the definition of all objects that + * have only one (necessarily strong) ref in the serialization. The definition + * appears at the point of reference. + */ +#define MFL_DULL_OBJECT_OID MFL_OBJECT_DEF_TAG + +/** + * Convert an OID to an index into nsFastLoadFooter::mObjectMap. + */ +#define MFL_OID_TO_SHARP_INDEX(oid) (((oid) >> MFL_OBJECT_TAG_BITS) - 1) +#define MFL_SHARP_INDEX_TO_OID(index) (((index) + 1) << MFL_OBJECT_TAG_BITS) + +/** + * Magic "number" at start of a FastLoad file. Inspired by the PNG "magic" + * string, which inspired XPCOM's typelib (.xpt) file magic. Guaranteed to be + * corrupted by FTP-as-ASCII and other likely errors, meaningful to clued-in + * humans, and ending in ^Z to terminate erroneous text input on Windows. + */ +#define MFL_FILE_MAGIC "XPCOM\nMozFASL\r\n\032" +#define MFL_FILE_MAGIC_SIZE 16 + +#define MFL_FILE_VERSION_0 0 +#define MFL_FILE_VERSION_1 1000 +#define MFL_FILE_VERSION 4 // fix to note singletons in object map + +/** + * Compute Fletcher's 16-bit checksum over aLength bytes starting at aBuffer, + * with the initial accumulators seeded from *aChecksum, and final checksum + * returned in *aChecksum. The return value is the number of unchecked bytes, + * which may be non-zero if aBuffer is misaligned or aLength is odd. Callers + * should copy any remaining bytes to the front of the next buffer. + * + * If aLastBuffer is false, do not check any bytes remaining due to misaligned + * aBuffer or odd aLength, instead returning the remaining byte count. But if + * aLastBuffer is true, treat aBuffer as the last buffer in the file and check + * every byte, returning 0. Here's a read-loop checksumming sketch: + * + * char buf[BUFSIZE]; + * PRUint32 len, rem = 0; + * PRUint32 checksum = 0; + * + * while (NS_SUCCEEDED(rv = Read(buf + rem, sizeof buf - rem, &len)) && len) { + * len += rem; + * rem = NS_AccumulateFastLoadChecksum(&checksum, + * NS_REINTERPRET_CAST(PRUint8*, buf), + * len, + * PR_FALSE); + * if (rem) + * memcpy(buf, buf + len - rem, rem); + * } + * + * if (rem) { + * NS_AccumulateFastLoadChecksum(&checksum, + * NS_REINTERPRET_CAST(PRUint8*, buf), + * rem, + * PR_TRUE); + * } + * + * After this, if NS_SUCCEEDED(rv), checksum contains a valid FastLoad sum. + */ +PR_EXTERN(PRUint32) +NS_AccumulateFastLoadChecksum(PRUint32 *aChecksum, + const PRUint8* aBuffer, + PRUint32 aLength, + PRBool aLastBuffer); + +PR_EXTERN(PRUint32) +NS_AddFastLoadChecksums(PRUint32 sum1, PRUint32 sum2, PRUint32 sum2ByteCount); + +/** + * Header at the start of a FastLoad file. + */ +struct nsFastLoadHeader { + char mMagic[MFL_FILE_MAGIC_SIZE]; + PRUint32 mChecksum; + PRUint32 mVersion; + PRUint32 mFooterOffset; + PRUint32 mFileSize; +}; + +/** + * Footer prefix structure (footer header, ugh), after which come arrays of + * structures or strings counted by these members. + */ +struct nsFastLoadFooterPrefix { + PRUint32 mNumIDs; + PRUint32 mNumSharpObjects; + PRUint32 mNumMuxedDocuments; + PRUint32 mNumDependencies; +}; + +struct nsFastLoadSharpObjectInfo { + PRUint32 mCIDOffset; // offset of object's NSFastLoadID and data + PRUint16 mStrongRefCnt; + PRUint16 mWeakRefCnt; // high bit is singleton flag, see below +}; + +#define MFL_SINGLETON_FLAG 0x8000 +#define MFL_WEAK_REFCNT_MASK 0x7fff + +#define MFL_GET_SINGLETON_FLAG(ip) ((ip)->mWeakRefCnt & MFL_SINGLETON_FLAG) +#define MFL_GET_WEAK_REFCNT(ip) ((ip)->mWeakRefCnt & MFL_WEAK_REFCNT_MASK) + +#define MFL_SET_SINGLETON_FLAG(ip) \ + ((ip)->mWeakRefCnt |= MFL_SINGLETON_FLAG) +#define MFL_SET_WEAK_REFCNT(ip,rc) \ + ((ip)->mWeakRefCnt = (((ip)->mWeakRefCnt & MFL_SINGLETON_FLAG) | (rc))) + +#define MFL_BUMP_WEAK_REFCNT(ip) (++(ip)->mWeakRefCnt) +#define MFL_DROP_WEAK_REFCNT(ip) (--(ip)->mWeakRefCnt) + +struct nsFastLoadMuxedDocumentInfo { + const char* mURISpec; + PRUint32 mInitialSegmentOffset; +}; + +// forward declarations of opaque types defined in nsFastLoadFile.cpp +struct nsDocumentMapReadEntry; +struct nsDocumentMapWriteEntry; + +// So nsFastLoadFileUpdater can verify that its nsIObjectInputStream parameter +// is an nsFastLoadFileReader. +#define NS_FASTLOADFILEREADER_IID \ + {0x7d37d1bb,0xcef3,0x4c5f,{0x97,0x68,0x0f,0x89,0x7f,0x1a,0xe1,0x40}} + +struct nsIFastLoadFileReader : public nsISupports { + NS_DEFINE_STATIC_IID_ACCESSOR(NS_FASTLOADFILEREADER_IID) +}; + +/** + * Inherit from the concrete class nsBinaryInputStream, which inherits from + * abstract nsIObjectInputStream but does not implement its direct methods. + * Though the names are not as clear as I'd like, this seems to be the best + * way to share nsBinaryStream.cpp code. + */ +class nsFastLoadFileReader + : public nsBinaryInputStream, + public nsIFastLoadReadControl, + public nsISeekableStream, + public nsIFastLoadFileReader +{ + public: + nsFastLoadFileReader(nsIInputStream *aStream) + : mCurrentDocumentMapEntry(nsnull) { + SetInputStream(aStream); + MOZ_COUNT_CTOR(nsFastLoadFileReader); + } + + virtual ~nsFastLoadFileReader() { + MOZ_COUNT_DTOR(nsFastLoadFileReader); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // overridden nsIObjectInputStream methods + NS_IMETHOD ReadObject(PRBool aIsStrongRef, nsISupports* *_retval); + NS_IMETHOD ReadID(nsID *aResult); + + // nsIFastLoadFileControl methods + NS_DECL_NSIFASTLOADFILECONTROL + + // nsIFastLoadReadControl methods + NS_DECL_NSIFASTLOADREADCONTROL + + // nsISeekableStream methods + NS_DECL_NSISEEKABLESTREAM + + // Override Read so we can demultiplex a document interleaved with others. + NS_IMETHOD Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead); + + // Override ReadSegments too, as nsBinaryInputStream::ReadSegments does + // not call through our overridden Read method -- it calls directly into + // the underlying input stream. + NS_IMETHODIMP ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, + PRUint32 aCount, PRUint32 *aResult); + + nsresult ReadHeader(nsFastLoadHeader *aHeader); + + /** + * In-memory representation of an indexed nsFastLoadSharpObjectInfo record. + */ + struct nsObjectMapEntry : public nsFastLoadSharpObjectInfo { + nsCOMPtr mReadObject; + PRInt64 mSkipOffset; + PRUint16 mSaveStrongRefCnt; // saved for an Update + PRUint16 mSaveWeakRefCnt; // after a Read + }; + + /** + * In-memory representation of the FastLoad file footer. + */ + struct nsFastLoadFooter : public nsFastLoadFooterPrefix { + nsFastLoadFooter() + : mIDMap(nsnull), + mObjectMap(nsnull) { + mDocumentMap.ops = mURIMap.ops = nsnull; + } + + ~nsFastLoadFooter() { + delete[] mIDMap; + delete[] mObjectMap; + if (mDocumentMap.ops) + PL_DHashTableFinish(&mDocumentMap); + if (mURIMap.ops) + PL_DHashTableFinish(&mURIMap); + } + + // These can't be static within GetID and GetSharpObjectEntry or the + // toolchains on HP-UX 10.20's, RH 7.0, and Mac OS X all barf at link + // time ("common symbols not allowed with MY_DHLIB output format", to + // quote the OS X rev of gcc). + static nsID gDummyID; + static nsObjectMapEntry gDummySharpObjectEntry; + + const nsID& GetID(NSFastLoadID aFastId) const { + PRUint32 index = aFastId - 1; + NS_ASSERTION(index < mNumIDs, "aFastId out of range"); + if (index >= mNumIDs) + return gDummyID; + return mIDMap[index]; + } + + nsObjectMapEntry& + GetSharpObjectEntry(NSFastLoadOID aOID) const { + PRUint32 index = MFL_OID_TO_SHARP_INDEX(aOID); + NS_ASSERTION(index < mNumSharpObjects, "aOID out of range"); + if (index >= mNumSharpObjects) + return gDummySharpObjectEntry; + return mObjectMap[index]; + } + + // Map from dense, zero-based, uint32 NSFastLoadID to 16-byte nsID. + nsID* mIDMap; + + // Map from dense, zero-based MFL_OID_TO_SHARP_INDEX(oid) to sharp + // object offset and refcnt information. + nsObjectMapEntry* mObjectMap; + + // Map from URI spec string to nsDocumentMapReadEntry, which helps us + // demultiplex a document's objects from among the interleaved object + // stream segments in the FastLoad file. + PLDHashTable mDocumentMap; + + // Fast mapping from URI object pointer to mDocumentMap entry, valid + // only while the muxed document is loading. + PLDHashTable mURIMap; + + // List of source filename dependencies that should trigger regeneration + // of the FastLoad file. + nsCOMPtr mDependencies; + }; + + nsresult ReadFooter(nsFastLoadFooter *aFooter); + nsresult ReadFooterPrefix(nsFastLoadFooterPrefix *aFooterPrefix); + nsresult ReadSlowID(nsID *aID); + nsresult ReadFastID(NSFastLoadID *aID); + nsresult ReadSharpObjectInfo(nsFastLoadSharpObjectInfo *aInfo); + nsresult ReadMuxedDocumentInfo(nsFastLoadMuxedDocumentInfo *aInfo); + nsresult DeserializeObject(nsISupports* *aObject); + + nsresult Open(); + NS_IMETHOD Close(); + + protected: + nsFastLoadHeader mHeader; + nsFastLoadFooter mFooter; + + nsDocumentMapReadEntry* mCurrentDocumentMapEntry; + + friend class nsFastLoadFileUpdater; +}; + +NS_COM nsresult +NS_NewFastLoadFileReader(nsIObjectInputStream* *aResult, + nsIInputStream* aSrcStream); + +/** + * Inherit from the concrete class nsBinaryInputStream, which inherits from + * abstract nsIObjectInputStream but does not implement its direct methods. + * Though the names are not as clear as I'd like, this seems to be the best + * way to share nsBinaryStream.cpp code. + */ +class nsFastLoadFileWriter + : public nsBinaryOutputStream, + public nsIFastLoadWriteControl, + public nsISeekableStream +{ + public: + nsFastLoadFileWriter(nsIOutputStream *aStream, nsIFastLoadFileIO* aFileIO) + : mCurrentDocumentMapEntry(nsnull), + mFileIO(aFileIO) + { + SetOutputStream(aStream); + mHeader.mChecksum = 0; + mIDMap.ops = mObjectMap.ops = mDocumentMap.ops = mURIMap.ops = nsnull; + mDependencyMap.ops = nsnull; + MOZ_COUNT_CTOR(nsFastLoadFileWriter); + } + + virtual ~nsFastLoadFileWriter() + { + if (mIDMap.ops) + PL_DHashTableFinish(&mIDMap); + if (mObjectMap.ops) + PL_DHashTableFinish(&mObjectMap); + if (mDocumentMap.ops) + PL_DHashTableFinish(&mDocumentMap); + if (mURIMap.ops) + PL_DHashTableFinish(&mURIMap); + if (mDependencyMap.ops) + PL_DHashTableFinish(&mDependencyMap); + MOZ_COUNT_DTOR(nsFastLoadFileWriter); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // overridden nsIObjectOutputStream methods + NS_IMETHOD WriteObject(nsISupports* aObject, PRBool aIsStrongRef); + NS_IMETHOD WriteSingleRefObject(nsISupports* aObject); + NS_IMETHOD WriteCompoundObject(nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef); + NS_IMETHOD WriteID(const nsID& aID); + + // nsIFastLoadFileControl methods + NS_DECL_NSIFASTLOADFILECONTROL + + // nsIFastLoadWriteControl methods + NS_DECL_NSIFASTLOADWRITECONTROL + + // nsISeekableStream methods + NS_DECL_NSISEEKABLESTREAM + + nsresult MapID(const nsID& aSlowID, NSFastLoadID *aResult); + + nsresult WriteHeader(nsFastLoadHeader *aHeader); + nsresult WriteFooter(); + nsresult WriteFooterPrefix(const nsFastLoadFooterPrefix& aFooterPrefix); + nsresult WriteSlowID(const nsID& aID); + nsresult WriteFastID(NSFastLoadID aID); + nsresult WriteSharpObjectInfo(const nsFastLoadSharpObjectInfo& aInfo); + nsresult WriteMuxedDocumentInfo(const nsFastLoadMuxedDocumentInfo& aInfo); + + nsresult Init(); + nsresult Open(); + NS_IMETHOD Close(); + + nsresult WriteObjectCommon(nsISupports* aObject, + PRBool aIsStrongRef, + PRUint32 aQITag); + + static PLDHashOperator PR_CALLBACK + IDMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + ObjectMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + DocumentMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + static PLDHashOperator PR_CALLBACK + DependencyMapEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + protected: + nsFastLoadHeader mHeader; + + PLDHashTable mIDMap; + PLDHashTable mObjectMap; + PLDHashTable mDocumentMap; + PLDHashTable mURIMap; + PLDHashTable mDependencyMap; + + nsDocumentMapWriteEntry* mCurrentDocumentMapEntry; + nsCOMPtr mFileIO; +}; + +NS_COM nsresult +NS_NewFastLoadFileWriter(nsIObjectOutputStream* *aResult, + nsIOutputStream* aDestStream, + nsIFastLoadFileIO* aFileIO); + +/** + * Subclass of nsFastLoadFileWriter, friend of nsFastLoadFileReader which it + * wraps when a FastLoad file needs to be updated. The wrapped reader can be + * used to demulitplex data for documents already in the FastLoad file, while + * the updater writes new data over the old footer, then writes a new footer + * that maps all data on Close. + */ +class nsFastLoadFileUpdater + : public nsFastLoadFileWriter, + nsIFastLoadFileIO +{ + public: + nsFastLoadFileUpdater(nsIOutputStream* aOutputStream) + : nsFastLoadFileWriter(aOutputStream, nsnull) { + MOZ_COUNT_CTOR(nsFastLoadFileUpdater); + } + + virtual ~nsFastLoadFileUpdater() { + MOZ_COUNT_DTOR(nsFastLoadFileUpdater); + } + + private: + // nsISupports methods + NS_DECL_ISUPPORTS_INHERITED + + // nsIFastLoadFileIO methods + NS_DECL_NSIFASTLOADFILEIO + + nsresult Open(nsFastLoadFileReader* aReader); + NS_IMETHOD Close(); + + static PLDHashOperator PR_CALLBACK + CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData); + + friend class nsFastLoadFileReader; + + protected: + nsCOMPtr mInputStream; +}; + +NS_COM nsresult +NS_NewFastLoadFileUpdater(nsIObjectOutputStream* *aResult, + nsIOutputStream* aOutputStream, + nsIObjectInputStream* aReaderAsStream); + +#endif // nsFastLoadFile_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h new file mode 100644 index 00000000..0c832357 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadPtr.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsFastLoadPtr_h___ +#define nsFastLoadPtr_h___ + +/** + * Mozilla FastLoad file object pointer template type. + * + * Use nsFastLoadPtr rather than nsCOMPtr when declaring a strong XPCOM + * ref member of a data structure that's conditionally loaded at application + * startup. You must be willing to tolerate the null mRawPtr test on every + * dereference of this member pointer, or else copy it to a local to optimize + * away the cost. + */ + +#ifndef nsCOMPtr_h___ +#include "nsCOMPtr.h" +#endif + +#ifndef nsIFastLoadService_h___ +#include "nsIFastLoadService.h" +#endif + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define gFastLoadService_ VBoxNsxpgFastLoadService_ +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/** + * nsFastLoadPtr is a template class, so we don't want a class static service + * pointer member declared in nsFastLoadPtr, above. Plus, we need special + * declaration magic to export data across DLL/DSO boundaries. So we use an + * old-fashioned global variable that refers weakly to the one true FastLoad + * service. This pointer is maintained by that singleton's ctor and dtor. + */ +PR_EXPORT_DATA(nsIFastLoadService*) gFastLoadService_; + +template +class nsFastLoadPtr : public nsCOMPtr { + public: + nsDerivedSafe* get() const { + if (!this->mRawPtr) { + gFastLoadService_->GetFastLoadReferent( + NS_REINTERPRET_CAST(nsISupports**, + &this->mRawPtr)); + } + return NS_REINTERPRET_CAST(nsDerivedSafe*, this->mRawPtr); + } + + /** + * Deserialize an nsFastLoadPtr from aInputStream, skipping the referent + * object, but saving the object's offset for later deserialization. + * + * Lowercase name _a la_ get, because it's called the same way -- not via + * operator->(). + */ + nsresult read(nsIObjectInputStream* aInputStream) { + return gFastLoadService_->ReadFastLoadPtr(aInputStream, + NS_REINTERPRET_CAST(nsISupports**, + &this->mRawPtr)); + } + + /** + * Serialize an nsFastLoadPtr reference and possibly the referent object, + * if that object has not yet been serialized. + * + * Lowercase name _a la_ get, because it's called the same way -- not via + * operator->(). + */ + nsresult write(nsIObjectOutputStream* aOutputStream) { + return gFastLoadService_->WriteFastLoadPtr(aOutputStream, + NS_REINTERPRET_CAST(nsISupports*, + this->mRawPtr)); + } +}; + +#endif // nsFastLoadPtr_h___ diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp new file mode 100644 index 00000000..4df187c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.cpp @@ -0,0 +1,571 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prtypes.h" +#include "prio.h" +#include "prtime.h" +#include "pldhash.h" + +#include "nsAppDirectoryServiceDefs.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsFastLoadFile.h" +#include "nsFastLoadPtr.h" +#include "nsFastLoadService.h" +#include "nsString.h" + +#include "nsIComponentManager.h" +#include "nsIEnumerator.h" +#include "nsIFastLoadFileControl.h" +#include "nsIFile.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsISeekableStream.h" +#include "nsISupports.h" + +PR_IMPLEMENT_DATA(nsIFastLoadService*) gFastLoadService_ = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFastLoadService, nsIFastLoadService) + +nsFastLoadService::nsFastLoadService() + : mLock(nsnull), + mFastLoadPtrMap(nsnull), + mDirection(0) +{ + NS_ASSERTION(gFastLoadService_ == nsnull, "double FastLoadService init?"); + gFastLoadService_ = this; +} + +nsFastLoadService::~nsFastLoadService() +{ + gFastLoadService_ = nsnull; + + if (mInputStream) + mInputStream->Close(); + if (mOutputStream) + mOutputStream->Close(); + + if (mFastLoadPtrMap) + PL_DHashTableDestroy(mFastLoadPtrMap); + if (mLock) + PR_DestroyLock(mLock); +} + +NS_IMETHODIMP +nsFastLoadService::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + *aResult = nsnull; + if (aOuter) + return NS_ERROR_NO_AGGREGATION; + + nsFastLoadService* fastLoadService = new nsFastLoadService(); + if (!fastLoadService) + return NS_ERROR_OUT_OF_MEMORY; + + fastLoadService->mLock = PR_NewLock(); + if (!fastLoadService->mLock) { + delete fastLoadService; + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(fastLoadService); + nsresult rv = fastLoadService->QueryInterface(aIID, aResult); + NS_RELEASE(fastLoadService); + return rv; +} + +#if defined XP_MAC + +// Mac format: " FastLoad File" with capitalized. +# include "nsCRT.h" + +# define MASSAGE_BASENAME(bn) (bn.SetCharAt(nsCRT::ToUpper(bn.CharAt(0)), 0)) +# define PLATFORM_FASL_SUFFIX " FastLoad File" + +#elif defined(XP_UNIX) || defined(XP_BEOS) + +// Unix format: ".mfasl". +# define MASSAGE_BASENAME(bn) /* nothing */ +# define PLATFORM_FASL_SUFFIX ".mfasl" + +#elif defined(XP_WIN) || defined(XP_OS2) + +// Windows format: ".mfl". +# define MASSAGE_BASENAME(bn) /* nothing */ +# define PLATFORM_FASL_SUFFIX ".mfl" + +#endif + +nsresult +nsFastLoadService::NewFastLoadFile(const char* aBaseName, nsIFile* *aResult) +{ + nsresult rv; + nsCOMPtr file; + + rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString name(aBaseName); + MASSAGE_BASENAME(name); + name += PLATFORM_FASL_SUFFIX; + rv = file->AppendNative(name); + if (NS_FAILED(rv)) + return rv; + + *aResult = file; + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::NewInputStream(nsIInputStream* aSrcStream, + nsIObjectInputStream* *aResult) +{ + nsAutoLock lock(mLock); + + nsCOMPtr stream; + nsresult rv = NS_NewFastLoadFileReader(getter_AddRefs(stream), aSrcStream); + if (NS_FAILED(rv)) + return rv; + + *aResult = stream; + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::NewOutputStream(nsIOutputStream* aDestStream, + nsIObjectOutputStream* *aResult) +{ + nsAutoLock lock(mLock); + + return NS_NewFastLoadFileWriter(aResult, aDestStream, mFileIO); +} + +NS_IMETHODIMP +nsFastLoadService::GetInputStream(nsIObjectInputStream* *aResult) +{ + NS_IF_ADDREF(*aResult = mInputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetInputStream(nsIObjectInputStream* aStream) +{ + nsAutoLock lock(mLock); + mInputStream = aStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetOutputStream(nsIObjectOutputStream* *aResult) +{ + NS_IF_ADDREF(*aResult = mOutputStream); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetOutputStream(nsIObjectOutputStream* aStream) +{ + nsAutoLock lock(mLock); + mOutputStream = aStream; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetFileIO(nsIFastLoadFileIO* *aResult) +{ + NS_IF_ADDREF(*aResult = mFileIO); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::SetFileIO(nsIFastLoadFileIO* aFileIO) +{ + nsAutoLock lock(mLock); + mFileIO = aFileIO; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::GetDirection(PRInt32 *aResult) +{ + *aResult = mDirection; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::HasMuxedDocument(const char* aURISpec, PRBool *aResult) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + + *aResult = PR_FALSE; + nsAutoLock lock(mLock); + + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) + rv = control->HasMuxedDocument(aURISpec, aResult); + } + + if (! *aResult && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->HasMuxedDocument(aURISpec, aResult); + } + + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec, + PRInt32 aDirectionFlags) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try for an input stream first, in case aURISpec's data is multiplexed + // in the current FastLoad file. + if ((aDirectionFlags & NS_FASTLOAD_READ) && mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) { + // If aURISpec is not in the multiplex, control->StartMuxedDocument + // will return NS_ERROR_NOT_AVAILABLE. + rv = control->StartMuxedDocument(aURI, aURISpec); + if (NS_SUCCEEDED(rv) || rv != NS_ERROR_NOT_AVAILABLE) + return rv; + + // Ok, aURISpec is not in the existing mux. If we have no output + // stream yet, wrap the reader with a FastLoad file updater. + if (!mOutputStream && mFileIO) { + nsCOMPtr output; + rv = mFileIO->GetOutputStream(getter_AddRefs(output)); + if (NS_FAILED(rv)) + return rv; + + // NB: mInputStream must be an nsFastLoadFileReader! + rv = NS_NewFastLoadFileUpdater(getter_AddRefs(mOutputStream), + output, + mInputStream); + if (NS_FAILED(rv)) + return rv; + } + + if (aDirectionFlags == NS_FASTLOAD_READ) { + // Tell our caller to re-start multiplexing, rather than attempt + // to select and deserialize now. + return NS_ERROR_NOT_AVAILABLE; + } + } + } + + if ((aDirectionFlags & NS_FASTLOAD_WRITE) && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->StartMuxedDocument(aURI, aURISpec); + } + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::SelectMuxedDocument(nsISupports* aURI, nsISupports** aResult) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try to select the reader, if any; then only if the URI was not in the + // file already, select the writer/updater. + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) { + rv = control->SelectMuxedDocument(aURI, aResult); + if (NS_SUCCEEDED(rv)) + mDirection = NS_FASTLOAD_READ; + } + } + + if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) { + rv = control->SelectMuxedDocument(aURI, aResult); + if (NS_SUCCEEDED(rv)) + mDirection = NS_FASTLOAD_WRITE; + } + } + + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::EndMuxedDocument(nsISupports* aURI) +{ + nsresult rv = NS_ERROR_NOT_AVAILABLE; + nsCOMPtr control; + nsAutoLock lock(mLock); + + // Try to end the document identified by aURI in the reader, if any; then + // only if the URI was not in the file already, end the writer/updater. + if (mInputStream) { + control = do_QueryInterface(mInputStream); + if (control) + rv = control->EndMuxedDocument(aURI); + } + + if (rv == NS_ERROR_NOT_AVAILABLE && mOutputStream) { + control = do_QueryInterface(mOutputStream); + if (control) + rv = control->EndMuxedDocument(aURI); + } + + mDirection = 0; + return rv; +} + +NS_IMETHODIMP +nsFastLoadService::AddDependency(nsIFile* aFile) +{ + nsAutoLock lock(mLock); + + nsCOMPtr control(do_QueryInterface(mOutputStream)); + if (!control) + return NS_ERROR_NOT_AVAILABLE; + + return control->AddDependency(aFile); +} + +NS_IMETHODIMP +nsFastLoadService::ComputeChecksum(nsIFile* aFile, + nsIFastLoadReadControl* aControl, + PRUint32 *aChecksum) +{ + nsCAutoString path; + nsresult rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(path); + PRUint32 checksum = NS_PTR_TO_INT32(mChecksumTable.Get(&key)); + if (checksum) { + *aChecksum = checksum; + return NS_OK; + } + + rv = aControl->ComputeChecksum(&checksum); + if (NS_FAILED(rv)) + return rv; + +#ifndef VBOX + mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum)); +#else /* VBOX */ + mChecksumTable.Put(&key, (void *)(uintptr_t)checksum); +#endif /* VBOX */ + *aChecksum = checksum; + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::CacheChecksum(nsIFile* aFile, nsIObjectOutputStream *aStream) +{ + nsCOMPtr control(do_QueryInterface(aStream)); + if (!control) + return NS_ERROR_FAILURE; + + PRUint32 checksum; + nsresult rv = control->GetChecksum(&checksum); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(path); +#ifndef VBOX + mChecksumTable.Put(&key, NS_INT32_TO_PTR(checksum)); +#else /* VBOX */ + mChecksumTable.Put(&key, (void *)(uintptr_t)checksum); +#endif /* VBOX */ + return NS_OK; +} + +struct nsFastLoadPtrEntry : public PLDHashEntryHdr { + nsISupports** mPtrAddr; // key, must come first for PL_DHashGetStubOps + PRUint32 mOffset; +}; + +NS_IMETHODIMP +nsFastLoadService::GetFastLoadReferent(nsISupports* *aPtrAddr) +{ + NS_ASSERTION(*aPtrAddr == nsnull, + "aPtrAddr doesn't point to null nsFastLoadPtr::mRawAddr?"); + + nsAutoLock lock(mLock); + if (!mFastLoadPtrMap || !mInputStream) + return NS_OK; + + nsFastLoadPtrEntry* entry = + NS_STATIC_CAST(nsFastLoadPtrEntry*, + PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_FREE(entry)) + return NS_OK; + + nsresult rv; + nsCOMPtr seekable(do_QueryInterface(mInputStream)); + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, entry->mOffset); + if (NS_FAILED(rv)) + return rv; + + rv = mInputStream->ReadObject(PR_TRUE, aPtrAddr); + if (NS_FAILED(rv)) + return rv; + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(mFastLoadPtrMap); + if (mFastLoadPtrMap->removedCount >= (size >> 2)) + PL_DHashTableOperate(mFastLoadPtrMap, entry, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(mFastLoadPtrMap, entry); + + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::ReadFastLoadPtr(nsIObjectInputStream* aInputStream, + nsISupports* *aPtrAddr) +{ + // nsFastLoadPtrs self-construct to null, so if we have a non-null value + // in our inout parameter, we must have been read already, alright! + if (*aPtrAddr) + return NS_OK; + + nsresult rv; + PRUint32 nextOffset; + nsAutoLock lock(mLock); + + rv = aInputStream->Read32(&nextOffset); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr seekable(do_QueryInterface(aInputStream)); + if (!seekable) + return NS_ERROR_FAILURE; + + PRInt64 thisOffset; + rv = seekable->Tell(&thisOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset); + if (NS_FAILED(rv)) + return rv; + + if (!mFastLoadPtrMap) { + mFastLoadPtrMap = PL_NewDHashTable(PL_DHashGetStubOps(), this, + sizeof(nsFastLoadPtrEntry), + PL_DHASH_MIN_SIZE); + if (!mFastLoadPtrMap) + return NS_ERROR_OUT_OF_MEMORY; + } + + nsFastLoadPtrEntry* entry = + NS_STATIC_CAST(nsFastLoadPtrEntry*, + PL_DHashTableOperate(mFastLoadPtrMap, aPtrAddr, + PL_DHASH_ADD)); + NS_ASSERTION(entry->mPtrAddr == nsnull, "duplicate nsFastLoadPtr?!"); + + entry->mPtrAddr = aPtrAddr; + + LL_L2UI(entry->mOffset, thisOffset); + return NS_OK; +} + +NS_IMETHODIMP +nsFastLoadService::WriteFastLoadPtr(nsIObjectOutputStream* aOutputStream, + nsISupports* aObject) +{ + NS_ASSERTION(aObject != nsnull, "writing an unread nsFastLoadPtr?!"); + if (!aObject) + return NS_ERROR_UNEXPECTED; + + nsresult rv; + nsAutoLock lock(mLock); // serialize writes to aOutputStream + + nsCOMPtr seekable(do_QueryInterface(aOutputStream)); + if (!seekable) + return NS_ERROR_FAILURE; + + PRInt64 saveOffset; + rv = seekable->Tell(&saveOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->Write32(0); // nextOffset placeholder + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->WriteObject(aObject, PR_TRUE); + if (NS_FAILED(rv)) + return rv; + + PRInt64 nextOffset; + rv = seekable->Tell(&nextOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, saveOffset); + if (NS_FAILED(rv)) + return rv; + + rv = aOutputStream->Write32(nextOffset); + if (NS_FAILED(rv)) + return rv; + + rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, nextOffset); + if (NS_FAILED(rv)) + return rv; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h new file mode 100644 index 00000000..8f1aa6ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsFastLoadService.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prtypes.h" +#include "pldhash.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsIFastLoadService.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" + +class nsFastLoadFileReader; +class nsFastLoadFileWriter; + +class nsFastLoadService : public nsIFastLoadService +{ + public: + nsFastLoadService(); + private: + ~nsFastLoadService(); + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIFASTLOADSERVICE + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + + private: + PRLock* mLock; + PLDHashTable* mFastLoadPtrMap; + nsCOMPtr mInputStream; + nsCOMPtr mOutputStream; + nsCOMPtr mFileIO; + PRInt32 mDirection; + nsHashtable mChecksumTable; +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl new file mode 100644 index 00000000..6ce0bb30 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIAsyncInputStream.idl @@ -0,0 +1,136 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIInputStream.idl" + +interface nsIInputStreamCallback; +interface nsIEventTarget; + +/** + * If an input stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK + * when read. The caller must then wait for the stream to have some data to + * read. If the stream implements nsIAsyncInputStream, then the caller can use + * this interface to request an asynchronous notification when the stream + * becomes readable or closed (via the AsyncWait method). + * + * While this interface is almost exclusively used with non-blocking streams, it + * is not necessary that nsIInputStream::isNonBlocking return true. Nor is it + * necessary that a non-blocking nsIInputStream implementation also implement + * nsIAsyncInputStream. + */ +[scriptable, uuid(15a15329-00de-44e8-ab06-0d0b0d43dc5b)] +interface nsIAsyncInputStream : nsIInputStream +{ + /** + * This method closes the stream and sets its internal status. If the + * stream is already closed, then this method is ignored. Once the stream + * is closed, the stream's status cannot be changed. Any successful status + * code passed to this method is treated as NS_BASE_STREAM_CLOSED, which + * has an effect equivalent to nsIInputStream::close. + * + * NOTE: this method exists in part to support pipes, which have both an + * input end and an output end. If the input end of a pipe is closed, then + * writes to the output end of the pipe will fail. The error code returned + * when an attempt is made to write to a "broken" pipe corresponds to the + * status code passed in when the input end of the pipe was closed, which + * greatly simplifies working with pipes in some cases. + * + * @param aStatus + * The error that will be reported if this stream is accessed after + * it has been closed. + */ + void closeWithStatus(in nsresult aStatus); + + /** + * Asynchronously wait for the stream to be readable or closed. The + * notification is one-shot, meaning that each asyncWait call will result + * in exactly one notification callback. After the OnInputStreamReady event + * is dispatched, the stream releases its reference to the + * nsIInputStreamCallback object. It is safe to call asyncWait again from the + * notification handler. + * + * This method may be called at any time (even if read has not been called). + * In other words, this method may be called when the stream already has + * data to read. It may also be called when the stream is closed. If the + * stream is already readable or closed when AsyncWait is called, then the + * OnInputStreamReady event will be dispatched immediately. Otherwise, the + * event will be dispatched when the stream becomes readable or closed. + * + * @param aCallback + * This object is notified when the stream becomes ready. + * @param aFlags + * This parameter specifies optional flags passed in to configure + * the behavior of this method. Pass zero to specify no flags. + * @param aRequestedCount + * Wait until at least this many bytes can be read. This is only + * a suggestion to the underlying stream; it may be ignored. The + * caller may pass zero to indicate no preference. + * @param aEventTarget + * Specify NULL to receive notification on ANY thread (possibly even + * recursively on the calling thread -- i.e., synchronously), or + * specify that the notification be delivered to a specific event + * target. + */ + void asyncWait(in nsIInputStreamCallback aCallback, + in unsigned long aFlags, + in unsigned long aRequestedCount, + in nsIEventTarget aEventTarget); + + /** + * If passed to asyncWait, this flag overrides the default behavior, + * causing the OnInputStreamReady notification to be suppressed until the + * stream becomes closed (either as a result of closeWithStatus/close being + * called on the stream or possibly due to some error in the underlying + * stream). + */ + const unsigned long WAIT_CLOSURE_ONLY = (1<<0); +}; + +/** + * This is a companion interface for nsIAsyncInputStream::asyncWait. + */ +[scriptable, uuid(d1f28e94-3a6e-4050-a5f5-2e81b1fc2a43)] +interface nsIInputStreamCallback : nsISupports +{ + /** + * Called to indicate that the stream is either readable or closed. + * + * @param aStream + * The stream whose asyncWait method was called. + */ + void onInputStreamReady(in nsIAsyncInputStream aStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl new file mode 100644 index 00000000..b0dd9ec0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIAsyncOutputStream.idl @@ -0,0 +1,136 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIOutputStream.idl" + +interface nsIOutputStreamCallback; +interface nsIEventTarget; + +/** + * If an output stream is non-blocking, it may return NS_BASE_STREAM_WOULD_BLOCK + * when written to. The caller must then wait for the stream to become + * writable. If the stream implements nsIAsyncOutputStream, then the caller can + * use this interface to request an asynchronous notification when the stream + * becomes writable or closed (via the AsyncWait method). + * + * While this interface is almost exclusively used with non-blocking streams, it + * is not necessary that nsIOutputStream::isNonBlocking return true. Nor is it + * necessary that a non-blocking nsIOutputStream implementation also implement + * nsIAsyncOutputStream. + */ +[scriptable, uuid(10dc9c94-8aff-49c6-8af9-d7fdb7339dae)] +interface nsIAsyncOutputStream : nsIOutputStream +{ + /** + * This method closes the stream and sets its internal status. If the + * stream is already closed, then this method is ignored. Once the stream + * is closed, the stream's status cannot be changed. Any successful status + * code passed to this method is treated as NS_BASE_STREAM_CLOSED, which + * is equivalent to nsIInputStream::close. + * + * NOTE: this method exists in part to support pipes, which have both an + * input end and an output end. If the output end of a pipe is closed, then + * reads from the input end of the pipe will fail. The error code returned + * when an attempt is made to read from a "closed" pipe corresponds to the + * status code passed in when the output end of the pipe is closed, which + * greatly simplifies working with pipes in some cases. + * + * @param aStatus + * The error that will be reported if this stream is accessed after + * it has been closed. + */ + void closeWithStatus(in nsresult reason); + + /** + * Asynchronously wait for the stream to be writable or closed. The + * notification is one-shot, meaning that each asyncWait call will result + * in exactly one notification callback. After the OnOutputStreamReady event + * is dispatched, the stream releases its reference to the + * nsIOutputStreamCallback object. It is safe to call asyncWait again from the + * notification handler. + * + * This method may be called at any time (even if write has not been called). + * In other words, this method may be called when the stream already has + * room for more data. It may also be called when the stream is closed. If + * the stream is already writable or closed when AsyncWait is called, then the + * OnOutputStreamReady event will be dispatched immediately. Otherwise, the + * event will be dispatched when the stream becomes writable or closed. + * + * @param aCallback + * This object is notified when the stream becomes ready. + * @param aFlags + * This parameter specifies optional flags passed in to configure + * the behavior of this method. Pass zero to specify no flags. + * @param aRequestedCount + * Wait until at least this many bytes can be written. This is only + * a suggestion to the underlying stream; it may be ignored. The + * caller may pass zero to indicate no preference. + * @param aEventTarget + * Specify NULL to receive notification on ANY thread (possibly even + * recursively on the calling thread -- i.e., synchronously), or + * specify that the notification be delivered to a specific event + * target. + */ + void asyncWait(in nsIOutputStreamCallback aCallback, + in unsigned long aFlags, + in unsigned long aRequestedCount, + in nsIEventTarget aEventTarget); + + /** + * If passed to asyncWait, this flag overrides the default behavior, + * causing the OnOutputStreamReady notification to be suppressed until the + * stream becomes closed (either as a result of closeWithStatus/close being + * called on the stream or possibly due to some error in the underlying + * stream). + */ + const unsigned long WAIT_CLOSURE_ONLY = (1<<0); +}; + +/** + * This is a companion interface for nsIAsyncOutputStream::asyncWait. + */ +[scriptable, uuid(40dbcdff-9053-42c5-a57c-3ec910d0f148)] +interface nsIOutputStreamCallback : nsISupports +{ + /** + * Called to indicate that the stream is either writable or closed. + * + * @param aStream + * The stream whose asyncWait method was called. + */ + void onOutputStreamReady(in nsIAsyncOutputStream aStream); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl new file mode 100644 index 00000000..12e4c5f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBaseStream.idl @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(6ccb17a0-e95e-11d1-beae-00805f8a66dc)] +interface nsIBaseStream : nsISupports +{ + /** Close the stream. */ + void close(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl new file mode 100644 index 00000000..bc9ea0b5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBinaryInputStream.idl @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" +#include "nsrootidl.idl" + +/** + * This interface allows consumption of primitive data types from a "binary + * stream" containing untagged, big-endian binary data, i.e. as produced by an + * implementation of nsIBinaryOutputStream. This might be used, for example, + * to implement network protocols or to read from architecture-neutral disk + * files, i.e. ones that can be read and written by both big-endian and + * little-endian platforms. + * + * @See nsIBinaryOutputStream + */ + +[scriptable, uuid(7b456cb0-8772-11d3-90cf-0040056a906e)] +interface nsIBinaryInputStream : nsIInputStream { + void setInputStream(in nsIInputStream aInputStream); + + PRBool readBoolean(); + + PRUint8 read8(); + PRUint16 read16(); + PRUint32 read32(); + PRUint64 read64(); + + float readFloat(); + double readDouble(); + + /** + * Read a NUL-terminated 8-bit char* string from a binary stream. + */ + ACString readCString(); + + /** + * Read a NUL-terminated 16-bit PRUnichar* string from a binary stream. + */ + AString readString(); + + /** + * Read an opaque byte array from a binary stream. + */ + void readBytes(in PRUint32 aLength, + [size_is(aLength), retval] out string aString); + + /** + * Read an opaque byte array from a binary stream, storing the results + * as an array of PRUint8s. + */ + void readByteArray(in PRUint32 aLength, + [array, size_is(aLength), retval] out PRUint8 aBytes); +}; + +%{C++ + +inline nsresult +NS_ReadOptionalCString(nsIBinaryInputStream* aStream, nsACString& aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadCString(aResult); + else + aResult.Truncate(); + } + return rv; +} + +inline nsresult +NS_ReadOptionalString(nsIBinaryInputStream* aStream, nsAString& aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadString(aResult); + else + aResult.Truncate(); + } + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl new file mode 100644 index 00000000..16a100b7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIBinaryOutputStream.idl @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIOutputStream.idl" +#include "nsrootidl.idl" + +/** + * This interface allows writing of primitive data types (integers, + * floating-point values, booleans, etc.) to a stream in a binary, untagged, + * fixed-endianness format. This might be used, for example, to implement + * network protocols or to produce architecture-neutral binary disk files, + * i.e. ones that can be read and written by both big-endian and little-endian + * platforms. Output is written in big-endian order (high-order byte first), + * as this is traditional network order. + * + * @See nsIBinaryInputStream + */ + +[scriptable, uuid(204ee610-8765-11d3-90cf-0040056a906e)] +interface nsIBinaryOutputStream : nsIOutputStream { + void setOutputStream(in nsIOutputStream aOutputStream); + + void writeBoolean(in PRBool aBoolean); + + void write8(in PRUint8 aByte); + void write16(in PRUint16 a16); + void write32(in PRUint32 a32); + void write64(in PRUint64 a64); + + void writeFloat(in float aFloat); + void writeDouble(in double aDouble); + + /** + * Write a NUL-terminated 8-bit char* string to a binary stream. + */ + void writeStringZ(in string aString); + + /** + * Write a NUL-terminated 16-bit PRUnichar* string to a binary stream. + */ + void writeWStringZ(in wstring aString); + + /** + * Write a NUL-terminated UTF8-encoded string to a binary stream, produced + * from a NUL-terminated 16-bit PRUnichar* string argument. + */ + void writeUtf8Z(in wstring aString); + + /** + * Write an opaque byte array to a binary stream. + */ + void writeBytes([size_is(aLength)] in string aString, in PRUint32 aLength); + + /** + * Write an opaque byte array to a binary stream. + */ + void writeByteArray([array, size_is(aLength)] in PRUint8 aBytes, + in PRUint32 aLength); + +}; + +%{C++ + +inline nsresult +NS_WriteOptionalStringZ(nsIBinaryOutputStream* aStream, const char* aString) +{ + PRBool nonnull = (aString != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteStringZ(aString); + return rv; +} + +inline nsresult +NS_WriteOptionalWStringZ(nsIBinaryOutputStream* aStream, const PRUnichar* aString) +{ + PRBool nonnull = (aString != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteWStringZ(aString); + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl new file mode 100644 index 00000000..a124e923 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIByteArrayInputStream.idl @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" + +[scriptable, uuid(b5a21556-35fc-4815-aff1-f9142639686e)] +interface nsIByteArrayInputStream : nsIInputStream +{ +}; + +%{C++ +extern NS_COM nsresult +NS_NewByteArrayInputStream (nsIByteArrayInputStream ** aResult, char * buffer, unsigned long size); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl new file mode 100644 index 00000000..b32a7f62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryEnumerator.idl @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Directory Enumerator Interface. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ben Goodger + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIFile; + +/** + * This interface provides a means for enumerating the contents of a directory. + * It is similar to nsISimpleEnumerator except the retrieved entries are QI'ed + * to nsIFile, and there is a mechanism for closing the directory when the + * enumeration is complete. + * + * @status UNDER_REVIEW + */ +[scriptable, uuid(31f7f4ae-6916-4f2d-a81e-926a4e3022ee)] +interface nsIDirectoryEnumerator : nsISupports +{ + /** + * Retrieves the next file in the sequence. The "nextFile" element is the + * first element upon the first call. This attribute is null if there is no + * next element. + */ + readonly attribute nsIFile nextFile; + + /** + * Closes the directory being enumerated, releasing the system resource. + * @throws NS_OK if the call succeeded and the directory was closed. + * NS_ERROR_FAILURE if the directory close failed. + * It is safe to call this function many times. + */ + void close(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl new file mode 100644 index 00000000..c34b7aa9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIDirectoryService.idl @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIFile.idl" + +/** + * nsIDirectoryServiceProvider + * + * Used by Directory Service to get file locations. + * + * @status FROZEN + */ + +[scriptable, uuid(bbf8cab0-d43a-11d3-8cc2-00609792278c)] +interface nsIDirectoryServiceProvider: nsISupports +{ + /** + * getFile + * + * Directory Service calls this when it gets the first request for + * a prop or on every request if the prop is not persistent. + * + * @param prop The symbolic name of the file. + * @param persistent TRUE - The returned file will be cached by Directory + * Service. Subsequent requests for this prop will + * bypass the provider and use the cache. + * FALSE - The provider will be asked for this prop + * each time it is requested. + * + * @return The file represented by the property. + * + */ + nsIFile getFile(in string prop, out PRBool persistent); +}; + +/** + * nsIDirectoryServiceProvider2 + * + * An extension of nsIDirectoryServiceProvider which allows + * multiple files to be returned for the given key. + * + * @status FROZEN + */ + +[scriptable, uuid(2f977d4b-5485-11d4-87e2-0010a4e75ef2)] +interface nsIDirectoryServiceProvider2: nsIDirectoryServiceProvider +{ + /** + * getFiles + * + * Directory Service calls this when it gets a request for + * a prop and the requested type is nsISimpleEnumerator. + * + * @param prop The symbolic name of the file list. + * + * @return An enumerator for a list of file locations. + * The elements in the enumeration are nsIFile + * + */ + nsISimpleEnumerator getFiles(in string prop); +}; + +/** + * nsIDirectoryService + * + * @status FROZEN + */ + +[scriptable, uuid(57a66a60-d43a-11d3-8cc2-00609792278c)] +interface nsIDirectoryService: nsISupports +{ + /** + * init + * + * Must be called. Used internally by XPCOM initialization. + * + */ + void init(); + + /** + * registerProvider + * + * Register a provider with the service. + * + * @param prov The service will keep a strong reference + * to this object. It will be released when + * the service is released. + * + */ + void registerProvider(in nsIDirectoryServiceProvider prov); + + /** + * unregisterProvider + * + * Unregister a provider with the service. + * + * @param prov + * + */ + void unregisterProvider(in nsIDirectoryServiceProvider prov); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl new file mode 100644 index 00000000..99f5a287 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadFileControl.idl @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIFile; +interface nsISimpleEnumerator; + +/** + * The nsIFastLoadFileControl interface and its subinterfaces are mix-ins for + * classes implementing nsIObjectInputStream and nsIObjectOutputStream, so that + * those stream types can be used with nsIFastLoadService to access and compute + * FastLoad file checksums, update and check FastLoad file dependencies, and + * multiplex documents loaded via non-blocking i/o. + * + * If an nsIObjectInputStream class doesn't support nsIFastLoadReadControl, or + * an nsIObjectOutputStream class doesn't support nsIFastLoadWriteControl, that + * implementation may still be useful for object serialization, but it can't be + * used to read or write a Mozilla FastLoad file. + */ +[scriptable, uuid(8a1e2c63-af50-4147-af7e-26289dc180dd)] +interface nsIFastLoadFileControl : nsISupports +{ + /** + * Get and set the recorded checksum value from the FastLoad file header. + */ + attribute PRUint32 checksum; + + /** + * Multiplexed document control methods. A FastLoad file may contain + * multiple interleaved documents identified by a URI specifier string, + * and indexed for fast multiplexor select by an opaque URI object key. + * You StartMuxedDocument when initiating a document load, then Select + * before every batch of calls to (de)serialize document data, and End + * when the load completes. + * + * Document multiplexing is necessary to support incremental FastLoad + * development in a non-blocking i/o architecture such as Mozilla, where + * some (but not all, at first, or for a while during development) of the + * results of parsing and compiling various inputs can be multiplexed to + * or from a FastLoad file. + * + * Note: Select returns the previously selected URI object in case the + * caller is synchronously selecting and writing data to the FastLoad + * file, so the caller can reselect the previous URI and return to code + * the continues to write FastLoad data for the previous URI, unaware of + * the nested select/write/reselect. + */ + void startMuxedDocument(in nsISupports aURI, in string aURISpec); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); + + /** + * Return true if aURISpec identifies a muxed document in the FastLoad + * file, false otherwise. + */ + boolean hasMuxedDocument(in string aURISpec); +}; + +[scriptable, uuid(652ecec6-d40b-45b6-afef-641d6c63a35b)] +interface nsIFastLoadReadControl : nsIFastLoadFileControl +{ + /** + * Computes the correct checksum of the FastLoad file, independent of the + * header's checksum value. The header checksum field is treated as zero + * when computing the checksum. + */ + PRUint32 computeChecksum(); + + /** + * Get the collection of dependency nsIFile instances recorded during the + * FastLoad file write or read/update process, and checked during the read + * process to invalidate the FastLoad file if any dependencies are newer. + */ + readonly attribute nsISimpleEnumerator dependencies; +}; + +[scriptable, uuid(2ad6e9e6-1379-4e45-a899-a54b27ff915c)] +interface nsIFastLoadWriteControl : nsIFastLoadFileControl +{ + /** + * Add a file dependency of the FastLoad file (e.g., a .jar file) to the + * set of dependencies that trigger regeneration if any dependency has a + * last-modified-time greater than the FastLoad file's mtime. + */ + void addDependency(in nsIFile aFile); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl new file mode 100644 index 00000000..0b177463 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFastLoadService.idl @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIFastLoadReadControl; +interface nsIFile; +interface nsIInputStream; +interface nsIOutputStream; +interface nsIObjectInputStream; +interface nsIObjectOutputStream; + +[scriptable, uuid(715577db-d9c5-464a-a32e-0a40c29b22d4)] +interface nsIFastLoadFileIO : nsISupports +{ + readonly attribute nsIInputStream inputStream; + readonly attribute nsIOutputStream outputStream; +}; + +[scriptable, uuid(759e475e-0c23-4dbf-b1b8-78c9369e3072)] +interface nsIFastLoadService : nsISupports +{ + nsIFile newFastLoadFile(in string aBaseName); + + nsIObjectInputStream newInputStream(in nsIInputStream aSrcStream); + nsIObjectOutputStream newOutputStream(in nsIOutputStream aDestStream); + + // Flag values for the direction attribute and the aDirectionFlags + // parameter to startMuxedDocument. + const PRInt32 NS_FASTLOAD_READ = 1; + const PRInt32 NS_FASTLOAD_WRITE = 2; + + attribute nsIObjectInputStream inputStream; + attribute nsIObjectOutputStream outputStream; + attribute nsIFastLoadFileIO fileIO; + readonly attribute PRInt32 direction; + + /** + * These methods associate a URI object with its spec, for faster select + * using the object pointer as a key, rather than the spec string. The + * selectMuxedDocument method returns the previously selected URI object, + * in case a caller needs to reselect the previous after muxing data for + * a given URI synchronously. For the non-blocking or "asynchronous" i/o + * case, the caller must select the source URI from the FastLoad multiplex + * before writing a new burst of data parsed from the slow-loaded source. + * + * Clients of inputStream and outputStream should try to demultiplex data + * from the input stream only if fastLoadService->StartMuxedDocument(uri, + * urispec, NS_FASTLOAD_READ) succeeds. If StartMuxedDocument fails with + * NS_ERROR_NOT_AVAILABLE, callers should slow-load the documents, muxing + * their data to the current output stream. + */ + void startMuxedDocument(in nsISupports aURI, + in string aURISpec, + in PRInt32 aDirectionFlags); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); + + void addDependency(in nsIFile aFile); + + PRUint32 computeChecksum(in nsIFile aFile, + in nsIFastLoadReadControl aControl); + void cacheChecksum(in nsIFile aFile, + in nsIObjectOutputStream aStream); + + [noscript] void getFastLoadReferent(inout nsISupports aPtr); + + [noscript] void readFastLoadPtr(in nsIObjectInputStream aInputStream, + inout nsISupports aPtr); + + [noscript] void writeFastLoadPtr(in nsIObjectOutputStream aOutputStream, + in nsISupports aPtr); + + /** + * Return true if aURISpec identifies a muxed document in the FastLoad + * file, false otherwise. + */ + boolean hasMuxedDocument(in string aURISpec); +}; + +%{C++ +#define NS_FASTLOADSERVICE_CLASSNAME "Mozilla FastLoad Service" + +#define NS_FASTLOADSERVICE_CID \ + {0xc943093c,0xac94,0x4bee,{0x84,0x0b,0x8b,0x5a,0x6e,0x31,0x4f,0xa7}} + +#define NS_FASTLOADSERVICE_CONTRACTID \ + "@mozilla.org/fast-load-service;1" + +#ifndef nsCOMPtr_h___ +# include "nsCOMPtr.h" +#endif +#ifndef __gen_nsIFile_h__ +# include "nsIFile.h" +#endif +#ifndef nsIServiceManager_h___ +# include "nsIServiceManager.h" +#endif + +inline const nsGetServiceByCID +do_GetFastLoadService(nsresult *aResultCode = 0) +{ + static NS_DEFINE_CID(kFastLoadServiceCID, NS_FASTLOADSERVICE_CID); + return nsGetServiceByCID(kFastLoadServiceCID, nsnull, aResultCode); +} + +inline nsresult +NS_AddFastLoadDependency(nsIFile* aFile) +{ + nsCOMPtr fastLoadService(do_GetFastLoadService()); + if (fastLoadService) { + nsresult rv = fastLoadService->AddDependency(aFile); + if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) + return rv; + } + return NS_OK; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIFile.idl b/src/libs/xpcom18a4/xpcom/io/nsIFile.idl new file mode 100644 index 00000000..1d70858e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIFile.idl @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Christopher Blizzard + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsISimpleEnumerator; + +/** + * This is the only correct cross-platform way to specify a file. + * Strings are not such a way. If you grew up on windows or unix, you + * may think they are. Welcome to reality. + * + * All methods with string parameters have two forms. The preferred + * form operates on UCS-2 encoded characters strings. An alternate + * form operates on characters strings encoded in the "native" charset. + * + * A string containing characters encoded in the native charset cannot + * be safely passed to javascript via xpconnect. Therefore, the "native + * methods" are not scriptable. + * + * @status FROZEN + */ +[scriptable, uuid(c8c0a080-0868-11d3-915f-d9d889d48e3c)] +interface nsIFile : nsISupports +{ + /** + * Create Types + * + * NORMAL_FILE_TYPE - A normal file. + * DIRECTORY_TYPE - A directory/folder. + */ + const unsigned long NORMAL_FILE_TYPE = 0; + const unsigned long DIRECTORY_TYPE = 1; + + /** + * append[Native] + * + * This function is used for constructing a descendent of the + * current nsIFile. + * + * @param node + * A string which is intended to be a child node of the nsIFile. + * For the |appendNative| method, the node must be in the native + * filesystem charset. + */ + void append(in AString node); + [noscript] void appendNative(in ACString node); + + /** + * Normalize the pathName (e.g. removing .. and . components on Unix). + */ + void normalize(); + + /** + * create + * + * This function will create a new file or directory in the + * file system. Any nodes that have not been created or + * resolved, will be. If the file or directory already + * exists create() will return NS_ERROR_FILE_ALREADY_EXISTS. + * + * @param type + * This specifies the type of file system object + * to be made. The only two types at this time + * are file and directory which are defined above. + * If the type is unrecongnized, we will return an + * error (NS_ERROR_FILE_UNKNOWN_TYPE). + * + * @param permissions + * The unix style octal permissions. This may + * be ignored on systems that do not need to do + * permissions. + */ + void create(in unsigned long type, in unsigned long permissions); + + /** + * Accessor to the leaf name of the file itself. + * For the |nativeLeafName| method, the nativeLeafName must + * be in the native filesystem charset. + */ + attribute AString leafName; + [noscript] attribute ACString nativeLeafName; + + /** + * copyTo[Native] + * + * This will copy this file to the specified newParentDir. + * If a newName is specified, the file will be renamed. + * If 'this' is not created we will return an error + * (NS_ERROR_FILE_TARGET_DOES_NOT_EXIST). + * + * copyTo may fail if the file already exists in the destination + * directory. + * + * copyTo will NOT resolve aliases/shortcuts during the copy. + * + * @param newParentDir + * This param is the destination directory. If the + * newParentDir is null, copyTo() will use the parent + * directory of this file. If the newParentDir is not + * empty and is not a directory, an error will be + * returned (NS_ERROR_FILE_DESTINATION_NOT_DIR). For the + * |CopyToNative| method, the newName must be in the + * native filesystem charset. + * + * @param newName + * This param allows you to specify a new name for + * the file to be copied. This param may be empty, in + * which case the current leaf name will be used. + */ + void copyTo(in nsIFile newParentDir, in AString newName); + [noscript] void CopyToNative(in nsIFile newParentDir, in ACString newName); + + /** + * copyToFollowingLinks[Native] + * + * This function is identical to copyTo with the exception that, + * as the name implies, it follows symbolic links. The XP_UNIX + * implementation always follow symbolic links when copying. For + * the |CopyToFollowingLinks| method, the newName must be in the + * native filesystem charset. + */ + void copyToFollowingLinks(in nsIFile newParentDir, in AString newName); + [noscript] void copyToFollowingLinksNative(in nsIFile newParentDir, in ACString newName); + + /** + * moveTo[Native] + * + * A method to move this file or directory to newParentDir. + * If a newName is specified, the file or directory will be renamed. + * If 'this' is not created we will return an error + * (NS_ERROR_FILE_TARGET_DOES_NOT_EXIST). + * If 'this' is a file, and the destination file already exists, moveTo + * will replace the old file. + * + * moveTo will NOT resolve aliases/shortcuts during the copy. + * moveTo will do the right thing and allow copies across volumes. + * moveTo will return an error (NS_ERROR_FILE_DIR_NOT_EMPTY) if 'this' is + * a directory and the destination directory is not empty. + * moveTo will return an error (NS_ERROR_FILE_ACCESS_DENIED) if 'this' is + * a directory and the destination directory is not writable. + * + * @param newParentDir + * This param is the destination directory. If the + * newParentDir is empty, moveTo() will rename the file + * within its current directory. If the newParentDir is + * not empty and does not name a directory, an error will + * be returned (NS_ERROR_FILE_DESTINATION_NOT_DIR). For + * the |moveToNative| method, the newName must be in the + * native filesystem charset. + * + * @param newName + * This param allows you to specify a new name for + * the file to be moved. This param may be empty, in + * which case the current leaf name will be used. + */ + void moveTo(in nsIFile newParentDir, in AString newName); + [noscript] void moveToNative(in nsIFile newParentDir, in ACString newName); + + /** + * This will try to delete this file. The 'recursive' flag + * must be PR_TRUE to delete directories which are not empty. + * + * This will not resolve any symlinks. + */ + void remove(in boolean recursive); + + /** + * Attributes of nsIFile. + */ + + attribute unsigned long permissions; + attribute unsigned long permissionsOfLink; + + /** + * File Times are to be in milliseconds from + * midnight (00:00:00), January 1, 1970 Greenwich Mean + * Time (GMT). + */ + attribute PRInt64 lastModifiedTime; + attribute PRInt64 lastModifiedTimeOfLink; + + /** + * WARNING! On the Mac, getting/setting the file size with nsIFile + * only deals with the size of the data fork. If you need to + * know the size of the combined data and resource forks use the + * GetFileSizeWithResFork() method defined on nsILocalFileMac. + */ + attribute PRInt64 fileSize; + readonly attribute PRInt64 fileSizeOfLink; + + /** + * target & path + * + * Accessor to the string path. The native version of these + * strings are not guaranteed to be a usable path to pass to + * NSPR or the C stdlib. There are problems that affect + * platforms on which a path does not fully specify a file + * because two volumes can have the same name (e.g., XP_MAC). + * This is solved by holding "private", native data in the + * nsIFile implementation. This native data is lost when + * you convert to a string. + * + * DO NOT PASS TO USE WITH NSPR OR STDLIB! + * + * target + * Find out what the symlink points at. Will give error + * (NS_ERROR_FILE_INVALID_PATH) if not a symlink. + * + * path + * Find out what the nsIFile points at. + * + * Note that the ACString attributes are returned in the + * native filesystem charset. + * + */ + readonly attribute AString target; + [noscript] readonly attribute ACString nativeTarget; + readonly attribute AString path; + [noscript] readonly attribute ACString nativePath; + + boolean exists(); + boolean isWritable(); + boolean isReadable(); + boolean isExecutable(); + boolean isHidden(); + boolean isDirectory(); + boolean isFile(); + boolean isSymlink(); + /** + * Not a regular file, not a directory, not a symlink. + */ + boolean isSpecial(); + + /** + * createUnique + * + * This function will create a new file or directory in the + * file system. Any nodes that have not been created or + * resolved, will be. If this file already exists, we try + * variations on the leaf name "suggestedName" until we find + * one that did not already exist. + * + * If the search for nonexistent files takes too long + * (thousands of the variants already exist), we give up and + * return NS_ERROR_FILE_TOO_BIG. + * + * @param type + * This specifies the type of file system object + * to be made. The only two types at this time + * are file and directory which are defined above. + * If the type is unrecongnized, we will return an + * error (NS_ERROR_FILE_UNKNOWN_TYPE). + * + * @param permissions + * The unix style octal permissions. This may + * be ignored on systems that do not need to do + * permissions. + */ + void createUnique(in unsigned long type, in unsigned long permissions); + + /** + * clone() + * + * This function will allocate and initialize a nsIFile object to the + * exact location of the |this| nsIFile. + * + * @param file + * A nsIFile which this object will be initialize + * with. + * + */ + nsIFile clone(); + + /** + * Will determine if the inFile equals this. + */ + boolean equals(in nsIFile inFile); + + /** + * Will determine if inFile is a descendant of this file + * If |recur| is true, look in subdirectories too + */ + boolean contains(in nsIFile inFile, in boolean recur); + + /** + * Parent will be null when this is at the top of the volume. + */ + readonly attribute nsIFile parent; + + /** + * Returns an enumeration of the elements in a directory. Each + * element in the enumeration is an nsIFile. + * + * @return NS_ERROR_FILE_NOT_DIRECTORY if the current nsIFile does + * not specify a directory. + */ + readonly attribute nsISimpleEnumerator directoryEntries; +}; + +%{C++ +#ifndef MOZILLA_STRICT_API +#include "nsDirectoryServiceUtils.h" +#endif +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl new file mode 100644 index 00000000..827f6363 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIInputStream.idl @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Warren Harris + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIInputStream; + +%{C++ +/** + * The signature of the writer function passed to ReadSegments. This + * is the "consumer" of data that gets read from the stream's buffer. + * + * @param aInStream stream being read + * @param aClosure opaque parameter passed to ReadSegments + * @param aFromSegment pointer to memory owned by the input stream + * @param aToOffset amount already read (since ReadSegments was called) + * @param aCount length of fromSegment + * @param aWriteCount number of bytes read + * + * Implementers should return the following: + * + * @return NS_OK and (*aWriteCount > 0) if consumed some data + * @return if not interested in consuming any data + * + * Errors are never passed to the caller of ReadSegments. + * + * NOTE: returning NS_OK and (*aWriteCount = 0) has undefined behavior. + * + * @status FROZEN + */ +typedef NS_CALLBACK(nsWriteSegmentFun)(nsIInputStream *aInStream, + void *aClosure, + const char *aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount); +%} + +native nsWriteSegmentFun(nsWriteSegmentFun); + +/** + * nsIInputStream + * + * @status FROZEN + */ +[scriptable, uuid(fa9c7f6c-61b3-11d4-9877-00c04fa0cf4a)] +interface nsIInputStream : nsISupports +{ + /** + * Close the stream. + */ + void close(); + + /** + * @return number of bytes currently available in the stream + */ + unsigned long available(); + + /** + * Read data from the stream. + * + * @param aBuf the buffer into which the data is to be read + * @param aCount the maximum number of bytes to be read + * + * @return number of bytes read (may be less than aCount). + * @return 0 if reached end of file + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + */ + [noscript] unsigned long read(in charPtr aBuf, in unsigned long aCount); + + /** + * Low-level read method that has access to the stream's underlying buffer. + * The writer function may be called multiple times for segmented buffers. + * ReadSegments is expected to keep calling the writer until either there is + * nothing left to read or the writer returns an error. ReadSegments should + * not call the writer with zero bytes to consume. + * + * @param aWriter the "consumer" of the data to be read + * @param aClosure opaque parameter passed to writer + * @param aCount the maximum number of bytes to be read + * + * @return number of bytes read (may be less than aCount) + * @return 0 if reached end of file (or if aWriter refused to consume data) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if reading from the input stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: this function may be unimplemented if a stream has no underlying + * buffer (e.g., socket input stream). + */ + [noscript] unsigned long readSegments(in nsWriteSegmentFun aWriter, + in voidPtr aClosure, + in unsigned long aCount); + + /** + * @return true if stream is non-blocking + */ + boolean isNonBlocking(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl b/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl new file mode 100644 index 00000000..524e7ee2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIInputStreamTee.idl @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStream.idl" + +interface nsIOutputStream; + +/** + * A nsIInputStreamTee is a wrapper for an input stream, that when read + * reads the specified amount of data from its |source| and copies that + * data to its |sink|. |sink| must be a blocking output stream. + */ +[scriptable, uuid(44e8b2c8-1ecb-4a63-8b23-3e3500c34f32)] +interface nsIInputStreamTee : nsIInputStream +{ + attribute nsIInputStream source; + attribute nsIOutputStream sink; +}; + +%{C++ +// factory method +extern NS_COM nsresult +NS_NewInputStreamTee(nsIInputStream **tee, // read from this input stream + nsIInputStream *source, + nsIOutputStream *sink); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl new file mode 100644 index 00000000..23781dc4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILineInputStream.idl @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Boris Zbarsky . + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsILineInputStream; + +[scriptable, uuid(c97b466c-1e6e-4773-a4ab-2b2b3190a7a6)] +interface nsILineInputStream : nsISupports +{ + /** + * Read a single line from the stream, where a line is a + * possibly zero length sequence of 8bit chars terminated by a + * CR, LF, CRLF, LFCR, or eof. + * The line terminator is not returned. + * Return false for end of file, true otherwise + */ + boolean readLine(out ACString aLine); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl new file mode 100644 index 00000000..8d7a1dda --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFile.idl @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIFile.idl" + +%{C++ +#include "prio.h" +#include "prlink.h" +#include +%} + +[ptr] native PRFileDescStar(PRFileDesc); +[ptr] native PRLibraryStar(PRLibrary); +[ptr] native FILE(FILE); + +/** + * This interface adds methods to nsIFile that are particular to a file + * that is accessible via the local file system. + * + * It follows the same string conventions as nsIFile. + * + * @status FROZEN + */ +[scriptable, uuid(aa610f20-a889-11d3-8c81-000064657374)] +interface nsILocalFile : nsIFile +{ + /** + * initWith[Native]Path + * + * This function will initialize the nsILocalFile object. Any + * internal state information will be reset. + * + * NOTE: This function has a known bug on the macintosh and + * other OSes which do not represent file locations as paths. + * If you do use this function, be very aware of this problem! + * + * @param filePath + * A string which specifies a full file path to a + * location. Relative paths will be treated as an + * error (NS_ERROR_FILE_UNRECOGNIZED_PATH). For + * initWithNativePath, the filePath must be in the native + * filesystem charset. + */ + void initWithPath(in AString filePath); + [noscript] void initWithNativePath(in ACString filePath); + + /** + * initWithFile + * + * Initialize this object with another file + * + * @param aFile + * the file this becomes equivalent to + */ + void initWithFile(in nsILocalFile aFile); + + /** + * followLinks + * + * This attribute will determine if the nsLocalFile will auto + * resolve symbolic links. By default, this value will be false + * on all non unix systems. On unix, this attribute is effectively + * a noop. + */ + attribute PRBool followLinks; + + [noscript] PRFileDescStar openNSPRFileDesc(in long flags, in long mode); + [noscript] FILE openANSIFileDesc(in string mode); + + [noscript] PRLibraryStar load(); + + readonly attribute PRInt64 diskSpaceAvailable; + + /** + * appendRelative[Native]Path + * + * Append a relative path to the current path of the nsILocalFile object. + * + * @param relativeFilePath + * relativeFilePath is a native relative path. For security reasons, + * this cannot contain .. or cannot start with a directory separator. + * For the |appendRelativeNativePath| method, the relativeFilePath + * must be in the native filesystem charset. + */ + void appendRelativePath(in AString relativeFilePath); + [noscript] void appendRelativeNativePath(in ACString relativeFilePath); + + /** + * Accessor to a null terminated string which will specify + * the file in a persistent manner for disk storage. + * + * The character set of this attribute is undefined. DO NOT TRY TO + * INTERPRET IT AS HUMAN READABLE TEXT! + */ + attribute ACString persistentDescriptor; + + /** + * reveal + * + * Ask the operating system to open the folder which contains + * this file or folder. This routine only works on platforms which + * support the ability to open a folder... + */ + void reveal(); + + /** + * launch + * + * Ask the operating system to attempt to open the file. + * this really just simulates "double clicking" the file on your platform. + * This routine only works on platforms which support this functionality. + */ + void launch(); + + /** + * getRelativeDescriptor + * + * Returns a relative file path in an opaque, XP format. It is therefore + * not a native path. + * + * The character set of the string returned from this function is + * undefined. DO NOT TRY TO INTERPRET IT AS HUMAN READABLE TEXT! + * + * @param fromFile + * the file from which the descriptor is relative. + * There is no defined result if this param is null. + */ + ACString getRelativeDescriptor(in nsILocalFile fromFile); + + /** + * setRelativeDescriptor + * + * Initializes the file to the location relative to fromFile using + * a string returned by getRelativeDescriptor. + * + * @param fromFile + * the file to which the descriptor is relative + * @param relative + * the relative descriptor obtained from getRelativeDescriptor + */ + void setRelativeDescriptor(in nsILocalFile fromFile, in ACString relativeDesc); +}; + diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl new file mode 100644 index 00000000..e04ea7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFileMac.idl @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * Mark Mentovai + * + * 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 "nsILocalFile.idl" + +%{C++ +#include +#include +%} + + native OSType(OSType); + native FSSpec(FSSpec); +[ptr] native FSSpecPtr(FSSpec); + native FSRef(FSRef); +[ptr] native FSRefPtr(FSRef); + native CFURLRef(CFURLRef); + +[scriptable, uuid(748f3ffe-27d9-4402-9de9-494badbeebf4)] +interface nsILocalFileMac : nsILocalFile +{ + /** + * initWithCFURL + * + * Init this object with a CFURLRef + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * NOTE: If the path of the CFURL is /a/b/c, at least a/b must exist beforehand. + * + * @param aCFURL the CoreFoundation URL + * + */ + [noscript] void initWithCFURL(in CFURLRef aCFURL); + + /** + * initWithFSRef + * + * Init this object with an FSRef + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @param aFSRef the native file spec + * + */ + [noscript] void initWithFSRef([const] in FSRefPtr aFSRef); + + /** + * initWithFSSpec + * + * Init this object with an FSSpec + * Legacy method - leaving in place for now + * + * @param aFileSpec the native file spec + * + */ + [noscript] void initWithFSSpec([const] in FSSpecPtr aFileSpec); + + /** + * initToAppWithCreatorCode + * + * Init this object to point to an application having the given + * creator code. If this app is missing, this will fail. It will first + * look for running application with the given creator. + * + * @param aAppCreator the signature of the app + * + */ + [noscript] void initToAppWithCreatorCode(in OSType aAppCreator); + + /** + * getCFURL + * + * Returns the CFURLRef of the file object. The caller is + * responsible for calling CFRelease() on it. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @return + * + */ + [noscript] CFURLRef getCFURL(); + + /** + * getFSRef + * + * Returns the FSRef of the file object. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * NOTE: Supported only for XP_MACOSX or TARGET_CARBON + * + * @return + * + */ + [noscript] FSRef getFSRef(); + + /** + * getFSSpec + * + * Returns the FSSpec of the file object. + * + * NOTE: Observes the state of the followLinks attribute. + * If the file object is an alias and followLinks is TRUE, returns + * the target of the alias. If followLinks is FALSE, returns + * the unresolved alias file. + * + * @return + * + */ + [noscript] FSSpec getFSSpec(); + + /** + * fileSizeWithResFork + * + * Returns the combined size of both the data fork and the resource + * fork (if present) rather than just the size of the data fork + * as returned by GetFileSize() + * + */ + readonly attribute PRInt64 fileSizeWithResFork; + + /** + * Use with SetFileType() to specify the signature of current process + */ + const unsigned long CURRENT_PROCESS_CREATOR = 0x8000000; + + /** + * fileType, creator + * + * File type and creator attributes + * + */ + [noscript] attribute OSType fileType; + [noscript] attribute OSType fileCreator; + + /** + * setFileTypeAndCreatorFromMIMEType + * + * Sets the file type and creator code from a MIME type. + * Internet Config is used to determine the mapping. + * + * @param aMIMEType + * + */ + void setFileTypeAndCreatorFromMIMEType(in string aMIMEType); + + /** + * setFileTypeAndCreatorFromExtension + * + * Sets the file type and creator code from a file extension + * Internet Config is used to determine the mapping. + * + * @param aExtension + * + */ + void setFileTypeAndCreatorFromExtension(in string aExtension); + + /** + * launchWithDoc + * + * Launch the application that this file points to with a document. + * + * @param aDocToLoad Must not be NULL. If no document, use nsILocalFile::launch + * @param aLaunchInBackground TRUE if the application should not come to the front. + * + */ + void launchWithDoc(in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); + + /** + * openDocWithApp + * + * Open the document that this file points to with the given application. + * + * @param aAppToOpenWith The application with which to open the document. + * If NULL, the creator code of the document is used + * to determine the application. + * @param aLaunchInBackground TRUE if the application should not come to the front. + * + */ + void openDocWithApp(in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); + + /** + * isPackage + * + * returns true if a directory is determined to be a package under Mac OS 9/X + * + */ + boolean isPackage(); + + /** + * bundleDisplayName + * + * returns the display name of the application bundle (usually the human + * readable name of the application) + */ + readonly attribute AString bundleDisplayName; + + /** + * bundleIdentifier + * + * returns the identifier of the bundle + */ + readonly attribute AUTF8String bundleIdentifier; +}; + +%{C++ +extern "C" +{ + +#ifndef XP_MACOSX +NS_EXPORT const char* NS_TruncNodeName(const char *aNode, char *outBuf); +#endif + +NS_EXPORT nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followSymlinks, nsILocalFileMac* *result); + +// NS_NewLocalFileWithFSRef is available since Mozilla 1.8.1. +NS_EXPORT nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowSymlinks, nsILocalFileMac** result); +} +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl b/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl new file mode 100644 index 00000000..95b4177b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsILocalFileOS2.idl @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Richard L. Walsh. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rich Walsh (Original Author) + * + * 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 "nsILocalFile.idl" + +interface nsIArray; + +[scriptable, uuid(26de2089-239d-4697-818b-bae1fe8e8e0d)] +interface nsILocalFileOS2 : nsILocalFile +{ + /** + * getFileTypes + * + * Returns the file's .TYPE extended attribute as an array of + * nsISupportsCStrings. + * + */ + nsIArray getFileTypes( ); + + /** + * setFileTypes + * + * Sets the file's .TYPE extended attribute from a comma-separated + * list of types (this format is used because clients are unlikely + * to write more than a single type). + * @param fileTypes + * a string in the filesystem's native character set + * + */ + void setFileTypes( in ACString fileTypes ); + + /** + * isFileType + * + * Returns TRUE if the file has a .TYPE extended attribute that + * matches the string passed in. The comparison is case-sensitive. + * @param fileType + * a string in the filesystem's native character set + * + */ + PRBool isFileType( in ACString fileType ); + + /** + * setFileSource + * + * Identifies the origin of a downloaded file by writing the + * source URI's spec to the .SUBJECT extended attribute. + * + * @param aURI + * the source URI + * + */ + void setFileSource( in AUTF8String aURI ); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl new file mode 100644 index 00000000..ec309ecd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIMultiplexInputStream.idl @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 "nsIInputStream.idl" + +/** + * The multiplex stream concatinates a list of input streams into a single + * stream. + */ + +[scriptable, uuid(a076fd12-1dd1-11b2-b19a-d53b5dffaade)] +interface nsIMultiplexInputStream : nsIInputStream +{ + /** + * Number of streams in this multiplex-stream + */ + readonly attribute unsigned long count; + + /** + * Appends a stream to the end of the streams. The cursor of the stream + * should be located at the beginning of the stream if the implementation + * of this nsIMultiplexInputStream also is used as an nsISeekableStream. + * @param stream stream to append + */ + void appendStream(in nsIInputStream stream); + + /** + * Insert a stream at specified index. If the cursor of this stream is at + * the beginning of the stream at index, the cursor will be placed at the + * beginning of the inserted stream instead. + * The cursor of the new stream should be located at the beginning of the + * stream if the implementation of this nsIMultiplexInputStream also is + * used as an nsISeekableStream. + * @param stream stream to insert + * @param index index to insert stream at, must be <= count + */ + void insertStream(in nsIInputStream stream, in unsigned long index); + + /** + * Remove stream at specified index. If this stream is the one currently + * being read the readcursor is moved to the beginning of the next + * stream + * @param index remove stream at this index, must be < count + */ + void removeStream(in unsigned long index); + + /** + * Get stream at specified index. + * @param index return stream at this index, must be < count + * @return stream at specified index + */ + nsIInputStream getStream(in unsigned long index); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl new file mode 100644 index 00000000..97c0ca6e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObjectInputStream.idl @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIBinaryInputStream.idl" +#include "nsrootidl.idl" + +/** + * @see nsIObjectOutputStream + * @see nsIBinaryInputStream + */ + +[scriptable, uuid(6c248606-4eae-46fa-9df0-ba58502368eb)] +interface nsIObjectInputStream : nsIBinaryInputStream +{ + /** + * Read an object from this stream to satisfy a strong or weak reference + * to one of its interfaces. If the interface was not along the primary + * inheritance chain ending in the "root" or XPCOM-identity nsISupports, + * readObject will QueryInterface from the deserialized object root to the + * correct interface, which was specified when the object was serialized. + * + * @see nsIObjectOutputStream + */ + nsISupports readObject(in PRBool aIsStrongRef); + + [notxpcom] nsresult readID(out nsID aID); + + /** + * Optimized deserialization support -- see nsIStreamBufferAccess.idl. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); +}; + +%{C++ + +inline nsresult +NS_ReadOptionalObject(nsIObjectInputStream* aStream, PRBool aIsStrongRef, + nsISupports* *aResult) +{ + PRBool nonnull; + nsresult rv = aStream->ReadBoolean(&nonnull); + if (NS_SUCCEEDED(rv)) { + if (nonnull) + rv = aStream->ReadObject(aIsStrongRef, aResult); + else + *aResult = nsnull; + } + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl new file mode 100644 index 00000000..b8072127 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObjectOutputStream.idl @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIBinaryOutputStream.idl" +#include "nsrootidl.idl" + +/** + * @See nsIObjectInputStream + * @See nsIBinaryOutputStream + */ + +[scriptable, uuid(92c898ac-5fde-4b99-87b3-5d486422094b)] +interface nsIObjectOutputStream : nsIBinaryOutputStream +{ + /** + * Write the object whose "root" or XPCOM-identity nsISupports is aObject. + * The cause for writing this object is a strong or weak reference, so the + * aIsStrongRef argument must tell which kind of pointer is being followed + * here during serialization. + * + * If the object has only one strong reference in the serialization and no + * weak refs, use writeSingleRefObject. This is a valuable optimization: + * it saves space in the stream, and cycles on both ends of the process. + * + * If the reference being serialized is a pointer to an interface not on + * the primary inheritance chain ending in the root nsISupports, you must + * call writeCompoundObject instead of this method. + */ + void writeObject(in nsISupports aObject, in PRBool aIsStrongRef); + + /** + * Write an object referenced singly and strongly via its root nsISupports + * or a subclass of its root nsISupports. There must not be other refs to + * aObject in memory, or in the serialization. + */ + void writeSingleRefObject(in nsISupports aObject); + + /** + * Write the object referenced by an interface pointer at aObject that + * inherits from a non-primary nsISupports, i.e., a reference to one of + * the multiply inherited interfaces derived from an nsISupports other + * than the root or XPCOM-identity nsISupports; or a reference to an + * inner object in the case of true XPCOM aggregation. aIID identifies + * this interface. + */ + void writeCompoundObject(in nsISupports aObject, + in nsIIDRef aIID, + in PRBool aIsStrongRef); + + void writeID(in nsIDRef aID); + + /** + * Optimized serialization support -- see nsIStreamBufferAccess.idl. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); +}; + +%{C++ + +inline nsresult +NS_WriteOptionalObject(nsIObjectOutputStream* aStream, nsISupports* aObject, + PRBool aIsStrongRef) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteObject(aObject, aIsStrongRef); + return rv; +} + +inline nsresult +NS_WriteOptionalSingleRefObject(nsIObjectOutputStream* aStream, + nsISupports* aObject) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteSingleRefObject(aObject); + return rv; +} + +inline nsresult +NS_WriteOptionalCompoundObject(nsIObjectOutputStream* aStream, + nsISupports* aObject, + const nsIID& aIID, + PRBool aIsStrongRef) +{ + PRBool nonnull = (aObject != nsnull); + nsresult rv = aStream->WriteBoolean(nonnull); + if (NS_SUCCEEDED(rv) && nonnull) + rv = aStream->WriteCompoundObject(aObject, aIID, aIsStrongRef); + return rv; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl new file mode 100644 index 00000000..66b2d6e6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObservableInputStream.idl @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Darin Fisher + * + * 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 "nsISupports.idl" + +interface nsIInputStream; +interface nsIInputStreamObserver; + +[scriptable, uuid(6f489efe-1dd2-11b2-af78-fb84ae21591b)] +interface nsIObservableInputStream : nsISupports +{ + /** + * Allows users to set an observer on an input stream to receive notifications + * about the consumer emptying the input stream's underlying buffer, or closing the + * stream. This is necessary for non-blocking streams so that the producer can suspend + * itself until more data can be written. + */ + attribute nsIInputStreamObserver observer; +}; + +[scriptable, uuid(019d67cc-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIInputStreamObserver : nsISupports +{ + /** + * Called when the input stream's consumer has read all the existing data from the stream. + */ + void onEmpty(in nsIInputStream inStr); + + /** + * Called when the consumer closes its end of the stream. + */ + void onClose(in nsIInputStream inStr); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl new file mode 100644 index 00000000..4cdab3c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIObservableOutputStream.idl @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): Darin Fisher + * + * 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 "nsISupports.idl" + +interface nsIOutputStream; +interface nsIOutputStreamObserver; + +[scriptable, uuid(15b374f8-1dd2-11b2-87ab-c3299d704fd3)] +interface nsIObservableOutputStream : nsISupports +{ + /** + * Allows users to set an observer on an input stream to receive notifications + * about the consumer emptying the input stream's underlying buffer, or closing the + * stream. This is necessary for non-blocking streams so that the producer can suspend + * itself until more data can be written. + */ + attribute nsIOutputStreamObserver observer; +}; + +[scriptable, uuid(12314194-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIOutputStreamObserver : nsISupports +{ + /** + * Called when the output stream's producer has written more data into the stream. + */ + void onWrite(in nsIOutputStream outStr, in unsigned long amount); + + /** + * Called when the stream's underlying buffer becomes full. + */ + void onFull(in nsIOutputStream outStr); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl new file mode 100644 index 00000000..ec5035c6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIOutputStream.idl @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Warren Harris + * Darin Fisher + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIOutputStream; +interface nsIInputStream; + +%{C++ +/** + * The signature for the reader function passed to WriteSegments. This + * is the "provider" of data that gets written into the stream's buffer. + * + * @param aOutStream stream being written to + * @param aClosure opaque parameter passed to WriteSegments + * @param aToSegment pointer to memory owned by the output stream + * @param aFromOffset amount already written (since WriteSegments was called) + * @param aCount length of toSegment + * @param aReadCount number of bytes written + * + * Implementers should return the following: + * + * @return NS_OK and (*aReadCount > 0) if successfully provided some data + * @return NS_OK and (*aReadCount = 0) or + * @return if not interested in providing any data + * + * Errors are never passed to the caller of WriteSegments. + * + * @status FROZEN + */ +typedef NS_CALLBACK(nsReadSegmentFun)(nsIOutputStream *aOutStream, + void *aClosure, + char *aToSegment, + PRUint32 aFromOffset, + PRUint32 aCount, + PRUint32 *aReadCount); +%} + +native nsReadSegmentFun(nsReadSegmentFun); + +/** + * nsIOutputStream + * + * @status FROZEN + */ +[scriptable, uuid(0d0acd2a-61b4-11d4-9877-00c04fa0cf4a)] +interface nsIOutputStream : nsISupports +{ + /** + * Close the stream. Forces the output stream to flush any buffered data. + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if unable to flush without blocking + * the calling thread (non-blocking mode only) + */ + void close(); + + /** + * Flush the stream. + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if unable to flush without blocking + * the calling thread (non-blocking mode only) + */ + void flush(); + + /** + * Write data into the stream. + * + * @param aBuf the buffer containing the data to be written + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + */ + unsigned long write(in string aBuf, in unsigned long aCount); + + /** + * Writes data into the stream from an input stream. + * + * @param aFromStream the stream containing the data to be written + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: This method is defined by this interface in order to allow the + * output stream to efficiently copy the data from the input stream into + * its internal buffer (if any). If this method was provided as an external + * facility, a separate char* buffer would need to be used in order to call + * the output stream's other Write method. + */ + unsigned long writeFrom(in nsIInputStream aFromStream, + in unsigned long aCount); + + /** + * Low-level write method that has access to the stream's underlying buffer. + * The reader function may be called multiple times for segmented buffers. + * WriteSegments is expected to keep calling the reader until either there + * is nothing left to write or the reader returns an error. WriteSegments + * should not call the reader with zero bytes to provide. + * + * @param aReader the "provider" of the data to be written + * @param aClosure opaque parameter passed to reader + * @param aCount the maximum number of bytes to be written + * + * @return number of bytes written (may be less than aCount) + * + * @throws NS_BASE_STREAM_WOULD_BLOCK if writing to the output stream would + * block the calling thread (non-blocking mode only) + * @throws on failure + * + * NOTE: this function may be unimplemented if a stream has no underlying + * buffer (e.g., socket output stream). + */ + [noscript] unsigned long writeSegments(in nsReadSegmentFun aReader, + in voidPtr aClosure, + in unsigned long aCount); + + /** + * @return true if stream is non-blocking + * + * NOTE: writing to a blocking output stream will block the calling thread + * until all given data can be consumed by the stream. + */ + boolean isNonBlocking(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl b/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl new file mode 100644 index 00000000..bbe3d978 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIPipe.idl @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAsyncInputStream.idl" +#include "nsIAsyncOutputStream.idl" + +interface nsIMemory; + +/** + * nsIPipe represents an in-process buffer that can be read using nsIInputStream + * and written using nsIOutputStream. The reader and writer of a pipe do not + * have to be on the same thread. As a result, the pipe is an ideal mechanism + * to bridge data exchange between two threads. For example, a worker thread + * might write data to a pipe from which the main thread will read. + * + * Each end of the pipe can be either blocking or non-blocking. Recall that a + * non-blocking stream will return NS_BASE_STREAM_WOULD_BLOCK if it cannot be + * read or written to without blocking the calling thread. For example, if you + * try to read from an empty pipe that has not yet been closed, then if that + * pipe's input end is non-blocking, then the read call will fail immediately + * with NS_BASE_STREAM_WOULD_BLOCK as the error condition. However, if that + * pipe's input end is blocking, then the read call will not return until the + * pipe has data or until the pipe is closed. This example presumes that the + * pipe is being filled asynchronously on some background thread. + * + * The pipe supports nsIAsyncInputStream and nsIAsyncOutputStream, which give + * the user of a non-blocking pipe the ability to wait for the pipe to become + * ready again. For example, in the case of an empty non-blocking pipe, the + * user can call AsyncWait on the input end of the pipe to be notified when + * the pipe has data to read (or when the pipe becomes closed). + * + * NS_NewPipe2 and NS_NewPipe provide convenient pipe constructors. In most + * cases nsIPipe is not actually used. It is usually enough to just get + * references to the pipe's input and output end. In which case, the pipe is + * automatically closed when the respective pipe ends are released. + */ +[scriptable, uuid(f4211abc-61b3-11d4-9877-00c04fa0cf4a)] +interface nsIPipe : nsISupports +{ + /** + * initialize this pipe + */ + void init(in boolean nonBlockingInput, + in boolean nonBlockingOutput, + in unsigned long segmentSize, + in unsigned long segmentCount, + in nsIMemory segmentAllocator); + + /** + * The pipe's input end, which also implements nsISearchableInputStream. + */ + readonly attribute nsIAsyncInputStream inputStream; + + /** + * The pipe's output end. + */ + readonly attribute nsIAsyncOutputStream outputStream; +}; + +/** + * XXX this interface doesn't really belong in here. It is here because + * currently nsPipeInputStream is the only implementation of this interface. + */ +[scriptable, uuid(8C39EF62-F7C9-11d4-98F5-001083010E9B)] +interface nsISearchableInputStream : nsISupports +{ + /** + * Searches for a string in the input stream. Since the stream has a notion + * of EOF, it is possible that the string may at some time be in the + * buffer, but is is not currently found up to some offset. Consequently, + * both the found and not found cases return an offset: + * if found, return offset where it was found + * if not found, return offset of the first byte not searched + * In the case the stream is at EOF and the string is not found, the first + * byte not searched will correspond to the length of the buffer. + */ + void search(in string forString, + in boolean ignoreCase, + out boolean found, + out unsigned long offsetSearchedTo); +}; + +%{C++ + +/** + * NS_NewPipe2 + * + * This function supercedes NS_NewPipe. It differs from NS_NewPipe in two + * major ways: + * (1) returns nsIAsyncInputStream and nsIAsyncOutputStream, so it is + * not necessary to QI in order to access these interfaces. + * (2) the size of the pipe is determined by the number of segments + * times the size of each segment. + * + * @param pipeIn + * resulting input end of the pipe + * @param pipeOut + * resulting output end of the pipe + * @param nonBlockingInput + * true specifies non-blocking input stream behavior + * @param nonBlockingOutput + * true specifies non-blocking output stream behavior + * @param segmentSize + * specifies the segment size in bytes (pass 0 to use default value) + * @param segmentCount + * specifies the max number of segments (pass 0 to use default value) + * passing PR_UINT32_MAX here causes the pipe to have "infinite" space. + * this mode can be useful in some cases, but should always be used with + * caution. the default value for this parameter is a finite value. + * @param segmentAlloc + * pass reference to nsIMemory to have all pipe allocations use this + * allocator (pass null to use the default allocator) + */ +extern NS_COM nsresult +NS_NewPipe2(nsIAsyncInputStream **pipeIn, + nsIAsyncOutputStream **pipeOut, + PRBool nonBlockingInput = PR_FALSE, + PRBool nonBlockingOutput = PR_FALSE, + PRUint32 segmentSize = 0, + PRUint32 segmentCount = 0, + nsIMemory *segmentAlloc = nsnull); + +/** + * NS_NewPipe + * + * Preserved for backwards compatibility. Plus, this interface is more + * amiable in certain contexts (e.g., when you don't need the pipe's async + * capabilities). + * + * @param pipeIn + * resulting input end of the pipe + * @param pipeOut + * resulting output end of the pipe + * @param segmentSize + * specifies the segment size in bytes (pass 0 to use default value) + * @param maxSize + * specifies the max size of the pipe (pass 0 to use default value) + * number of segments is maxSize / segmentSize, and maxSize must be a + * multiple of segmentSize. passing PR_UINT32_MAX here causes the + * pipe to have "infinite" space. this mode can be useful in some + * cases, but should always be used with caution. the default value + * for this parameter is a finite value. + * @param nonBlockingInput + * true specifies non-blocking input stream behavior + * @param nonBlockingOutput + * true specifies non-blocking output stream behavior + * @param segmentAlloc + * pass reference to nsIMemory to have all pipe allocations use this + * allocator (pass null to use the default allocator) + */ +inline nsresult +NS_NewPipe(nsIInputStream **pipeIn, + nsIOutputStream **pipeOut, + PRUint32 segmentSize = 0, + PRUint32 maxSize = 0, + PRBool nonBlockingInput = PR_FALSE, + PRBool nonBlockingOutput = PR_FALSE, + nsIMemory *segmentAlloc = nsnull) +{ + PRUint32 segmentCount; + if (segmentSize == 0) + segmentCount = 0; // use default + else + segmentCount = maxSize / segmentSize; + + nsIAsyncInputStream *in; + nsIAsyncOutputStream *out; + nsresult rv = NS_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput, + segmentSize, segmentCount, segmentAlloc); + if (NS_FAILED(rv)) return rv; + + *pipeIn = in; + *pipeOut = out; + return NS_OK; +} + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl new file mode 100644 index 00000000..9a21b1d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIScriptableInputStream.idl @@ -0,0 +1,73 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIInputStream; + +/** + * nsIScriptableInputStream provides scriptable access to the nsIInputStream. + * + * @status FROZEN + */ +[scriptable, uuid(a2a32f90-9b90-11d3-a189-0050041caf44)] +interface nsIScriptableInputStream : nsISupports +{ + /** + * Closes the stream. + */ + void close(); + + /** Wrap the given nsIInputStream with this nsIScriptableInputStream. + * @param aInputStream [in] parameter providing the stream to wrap + */ + void init(in nsIInputStream aInputStream); + + /** Return the number of bytes currently available in the stream + * @param _retval [out] parameter to hold the number of bytes + * if an error occurs, the parameter will be undefined + * @return error status + */ + unsigned long available(); + + /** Read data from the stream. + * @param aCount [in] the maximum number of bytes to read + * @param _retval [out] the data + */ + string read(in unsigned long aCount); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl b/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl new file mode 100644 index 00000000..b2827c12 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsISeekableStream.idl @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* + * nsISeekableStream + * + * Note that a stream might not implement all methods (e.g., a readonly stream + * won't implement setEOF) + * + * @status UNDER_REVIEW + */ + +#include "nsISupports.idl" + +[scriptable, uuid(8429d350-1040-4661-8b71-f2a6ba455980)] +interface nsISeekableStream : nsISupports +{ + /* + * Sets the stream pointer to the value of the 'offset' parameter + */ + const PRInt32 NS_SEEK_SET = 0; + + /* + * Sets the stream pointer to its current location plus the value + * of the offset parameter. + */ + const PRInt32 NS_SEEK_CUR = 1; + + /* + * Sets the stream pointer to the size of the stream plus the value + * of the offset parameter. + */ + const PRInt32 NS_SEEK_END = 2; + + /** + * seek + * + * This method moves the stream offset of the steam implementing this + * interface. + * + * @param whence specifies how to interpret the 'offset' parameter in + * setting the stream offset associated with the implementing + * stream. + * + * @param offset specifies a value, in bytes, that is used in conjunction + * with the 'whence' parameter to set the stream offset of the + * implementing stream. A negative value causes seeking in + * the reverse direction. + */ + void seek(in long whence, in long long offset); + + /** + * tell + * + * This method reports the current offset, in bytes, from the start of the + * stream. + */ + long long tell(); + + + /** + * setEOF + * + * This method truncates the stream at the current offset. + */ + void setEOF(); +}; diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl new file mode 100644 index 00000000..148136b9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStorageStream.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +interface nsIMemory; +interface nsIInputStream; +interface nsIOutputStream; + +/** + * The nsIStorageStream interface maintains an internal data buffer that can be + * filled using a single output stream. One or more independent input streams + * can be created to read the data from the buffer non-destructively. + */ + +[scriptable, uuid(604ad9d0-753e-11d3-90ca-34278643278f)] +interface nsIStorageStream : nsISupports +{ + /** + * + * Initialize the stream, setting up the amount of space that will be + * allocated for the stream's backing-store. + * + * @param segmentSize + * Size of each segment. Must be a power of two. + * @param maxSize + * Maximum total size of this stream. length will always be less + * than or equal to this value. Passing PR_UINT32_MAX is safe. + * @param segmentAllocator + * Which allocator to use for the segments. May be null, in which + * case a default allocator will be used. + */ + void init(in PRUint32 segmentSize, in PRUint32 maxSize, in nsIMemory segmentAllocator); + + /** + * Get a reference to the one and only output stream for this instance. + * The zero-based startPosition argument is used is used to set the initial + * write cursor position. The startPosition cannot be set larger than the + * current buffer length. Calling this method has the side-effect of + * truncating the internal buffer to startPosition bytes. + */ + nsIOutputStream getOutputStream(in PRInt32 startPosition); + + /** + * Create a new input stream to read data (written by the singleton output + * stream) from the internal buffer. Multiple, independent input streams + * can be created. + */ + nsIInputStream newInputStream(in PRInt32 startPosition); + + /** + * The length attribute indicates the total number of bytes stored in the + * nsIStorageStream internal buffer, regardless of any consumption by input + * streams. Assigning to the length field can be used to truncate the + * buffer data, but can not be used when either the instance's output + * stream is in use. + * + * @See #writeInProgress */ + attribute PRUint32 length; + + /** + * True, when output stream has not yet been Close'ed + */ + readonly attribute boolean writeInProgress; +}; + +%{C++ +// Factory method +NS_COM nsresult +NS_NewStorageStream(PRUint32 segmentSize, PRUint32 maxSize, nsIStorageStream **result); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl b/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl new file mode 100644 index 00000000..dc41585f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStreamBufferAccess.idl @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla FastLoad code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsrootidl.idl" + +/** + * An interface for access to a buffering stream implementation's underlying + * memory buffer. + * + * Stream implementations that QueryInterface to nsIStreamBufferAccess must + * ensure that all buffers are aligned on the most restrictive type size for + * the current architecture (e.g., sizeof(double) for RISCy CPUs). malloc(3) + * satisfies this requirement. + */ +[uuid(ac923b72-ac87-4892-ac7a-ca385d429435)] +interface nsIStreamBufferAccess : nsISupports +{ + /** + * Get access to a contiguous, aligned run of bytes in the stream's buffer. + * Exactly one successful getBuffer call must occur before a putBuffer call + * taking the non-null pointer returned by the successful getBuffer. + * + * The run of bytes are the next bytes (modulo alignment padding) to read + * for an input stream, and the next bytes (modulo alignment padding) to + * store before (eventually) writing buffered data to an output stream. + * There can be space beyond this run of bytes in the buffer for further + * accesses before the fill or flush point is reached. + * + * @param aLength + * Count of contiguous bytes requested at the address A that satisfies + * (A & aAlignMask) == 0 in the buffer, starting from the current stream + * position, mapped to a buffer address B. The stream implementation + * must pad from B to A by skipping bytes (if input stream) or storing + * zero bytes (if output stream). + * + * @param aAlignMask + * Bit-mask computed by subtracting 1 from the power-of-two alignment + * modulus (e.g., 3 or sizeof(PRUint32)-1 for PRUint32 alignment). + * + * @return + * The aligned pointer to aLength bytes in the buffer, or null if the + * buffer has no room for aLength bytes starting at the next address A + * after the current position that satisfies (A & aAlignMask) == 0. + */ + [notxpcom] charPtr getBuffer(in PRUint32 aLength, in PRUint32 aAlignMask); + + /** + * Relinquish access to the stream's buffer, filling if at end of an input + * buffer, flushing if completing an output buffer. After a getBuffer call + * that returns non-null, putBuffer must be called. + * + * @param aBuffer + * A non-null pointer returned by getBuffer on the same stream buffer + * access object. + * + * @param aLength + * The same count of contiguous bytes passed to the getBuffer call that + * returned aBuffer. + */ + [notxpcom] void putBuffer(in charPtr aBuffer, in PRUint32 aLength); + + /** + * Disable and enable buffering on the stream implementing this interface. + * DisableBuffering flushes an output stream's buffer, and invalidates an + * input stream's buffer. + */ + void disableBuffering(); + void enableBuffering(); + + /** + * The underlying, unbuffered input or output stream. + */ + readonly attribute nsISupports unbufferedStream; +}; + +%{C++ + +// Swap macros, used to convert to/from canonical (big-endian) format +#if defined IS_LITTLE_ENDIAN + +# define NS_SWAP16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) +# define NS_SWAP32(x) ((NS_SWAP16((x) & 0xffff) << 16) | (NS_SWAP16((x) >> 16))) + +// We want to avoid casting to 32-bit types if possible, since that violates +// aliasing rules (a standard compiler may assume that pointers of two types +// do not address overlapping storage). +// +// XXX What if we have a compiler that follows aliasing rules strictly but +// doesn't have a 64-bit int type? +// +// XXXbe shouldn't NSPR's LL_INIT work for non-constant arguments in all cases? + +# if defined HAVE_LONG_LONG +# if PR_BYTES_PER_LONG == 8 +# define ULL_(x) x ## UL +# elif (defined WIN32 || defined WIN16) && !defined __GNUC__ +# define ULL_(x) ((uint64) x ## i64) +# else +# define ULL_(x) x ## ULL +# endif + +# define NS_SWAP64(x) ((((x) & ULL_(0xff00000000000000)) >> 56) | \ + (((x) & ULL_(0x00ff000000000000)) >> 40) | \ + (((x) & ULL_(0x0000ff0000000000)) >> 24) | \ + (((x) & ULL_(0x000000ff00000000)) >> 8) | \ + (((x) & ULL_(0x00000000ff000000)) << 8) | \ + (((x) & ULL_(0x0000000000ff0000)) << 24) | \ + (((x) & ULL_(0x000000000000ff00)) << 40) | \ + (((x) /* & ULL_(0x00000000000000ff) */) << 56)) +# else +# define NS_SWAP64(x) LL_INIT((((x).lo /* & 0xff000000ul */) >> 24) | \ + (((x).lo & 0x00ff0000ul) >> 8) | \ + (((x).lo & 0x0000ff00ul) << 8) | \ + (((x).lo /* & 0x000000fful */) << 24), \ + (((x).hi /* & 0xff000000ul */) >> 24) | \ + (((x).hi & 0x00ff0000ul) >> 8) | \ + (((x).hi & 0x0000ff00ul) << 8) | \ + (((x).hi /* & 0x000000fful */) << 24)) +# endif + +#elif defined IS_BIG_ENDIAN + +# define NS_SWAP16(x) (x) +# define NS_SWAP32(x) (x) +# define NS_SWAP64(x) (x) + +#else + +# error "Unknown byte order" + +#endif + +/** + * These macros get and put a buffer given either an sba parameter that may + * point to an object implementing nsIStreamBufferAccess, nsIObjectInputStream, + * or nsIObjectOutputStream. + */ +#define NS_GET_BUFFER(sba,n,a) ((sba)->GetBuffer(n, a)) +#define NS_PUT_BUFFER(sba,p,n) ((sba)->PutBuffer(p, n)) + +#define NS_GET8(p) (*(PRUint8*)(p)) +#define NS_GET16(p) NS_SWAP16(*(PRUint16*)(p)) +#define NS_GET32(p) NS_SWAP32(*(PRUint32*)(p)) +#define NS_GET64(p) NS_SWAP64(*(PRUint64*)(p)) +#define NS_GET_FLOAT(p) ((float)NS_SWAP32(*(PRUint32*)(p))) +#define NS_GET_DOUBLE(p) ((double)NS_SWAP64(*(PRUint64*)(p))) + +#define NS_PUT8(p,x) (*(PRUint8*)(p) = (x)) +#define NS_PUT16(p,x) (*(PRUint16*)(p) = NS_SWAP16(x)) +#define NS_PUT32(p,x) (*(PRUint32*)(p) = NS_SWAP32(x)) +#define NS_PUT64(p,x) (*(PRUint64*)(p) = NS_SWAP64(x)) +#define NS_PUT_FLOAT(p,x) (*(PRUint32*)(p) = NS_SWAP32(*(PRUint32*)&(x))) +#define NS_PUT_DOUBLE(p,x) (*(PRUint64*)(p) = NS_SWAP64(*(PRUint64*)&(x))) + +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl b/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl new file mode 100644 index 00000000..09a90548 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIStringStream.idl @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * mcmullen@netscape.com (original author) + * scc@mozilla.org + * davidm@netscape.com + * darin@netscape.com + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Based on original code from nsIStringStream.h + */ + +#include "nsIInputStream.idl" + +/** + * nsIStringInputStream + * + * Provides scriptable and specialized C++ only methods for initializing a + * nsIInputStream implementation with a simple character array. + */ +[scriptable, uuid(450cd2d4-f0fd-424d-b365-b1251f80fd53)] +interface nsIStringInputStream : nsIInputStream +{ + /** + * SetData - assign data to the input stream (copied on assignment). + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + * + * NOTE: C++ code should consider using AdoptData or ShareData to avoid + * making an extra copy of the stream data. + */ + void setData(in string data, in long dataLen); + + /** + * NOTE: the following methods are designed to give C++ code added control + * over the ownership and lifetime of the stream data. Use with care :-) + */ + + /** + * AdoptData - assign data to the input stream. the input stream takes + * ownership of the given data buffer and will nsMemory::Free it when + * the input stream is destroyed. + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + */ + [noscript] void adoptData(in charPtr data, in long dataLen); + + /** + * ShareData - assign data to the input stream. the input stream references + * the given data buffer until the input stream is destroyed. the given + * data buffer must outlive the input stream. + * + * @param data - stream data + * @param dataLen - stream data length (-1 if length should be computed) + */ + [noscript] void shareData(in string data, in long dataLen); +}; + +%{C++ + +//----------------------------------------------------------------------------- +// C++ factory methods +//----------------------------------------------------------------------------- + +#include "nsIInputStream.h" +#include "nsString.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_NewByteInputStream VBoxNsxpNS_NewByteInputStream +#define NS_NewCStringInputStream VBoxNsxpNS_NewCStringInputStream +#define NS_NewCharInputStream VBoxNsxpNS_NewCharInputStream +#define NS_NewStringInputStream VBoxNsxpNS_NewStringInputStream +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from an nsAString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewStringInputStream(nsIInputStream** aStreamResult, + const nsAString& aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from an nsACString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCStringInputStream(nsIInputStream** aStreamResult, + const nsACString& aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from a string. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCharInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead); + +//----------------------------------------------------------------------------- +// Factory method to get an nsInputStream from a byte buffer. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewByteInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead, + PRInt32 aLength); +%} diff --git a/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h new file mode 100644 index 00000000..7232249d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsIUnicharInputStream.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIUnicharInputStream_h___ +#define nsIUnicharInputStream_h___ + +#include "nsIInputStream.h" +#include "nsString.h" +#include "nscore.h" + +class nsIUnicharInputStream; + +typedef NS_CALLBACK(nsWriteUnicharSegmentFun)(nsIUnicharInputStream *aInStream, + void *aClosure, + const PRUnichar *aFromSegment, + PRUint32 aToOffset, + PRUint32 aCount, + PRUint32 *aWriteCount); +/* c4bcf6ee-3a79-4d77-8d48-f17be3199b3b */ +#define NS_IUNICHAR_INPUT_STREAM_IID \ +{ 0xc4bcf6ee, 0x3a79, 0x4d77, \ + {0x8d, 0x48, 0xf1, 0x7b, 0xe3, 0x19, 0x9b, 0x3b} } + +/** Abstract unicode character input stream + * @see nsIInputStream + */ +class NS_NO_VTABLE nsIUnicharInputStream : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHAR_INPUT_STREAM_IID) + + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) = 0; + NS_IMETHOD Close() = 0; + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, + PRUint32 *aReadCount) = 0; +}; + +/** + * Create a nsIUnicharInputStream that wraps up a string. Data is fed + * from the string out until the done. When this object is destroyed + * it destroyes the string (so make a copy if you don't want it doing + * that) + */ +extern NS_COM nsresult + NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString); + +/** Create a new nsUnicharInputStream that provides a converter for the + * byte input stream aStreamToWrap. If no converter can be found then + * nsnull is returned and the error code is set to + * NS_INPUTSTREAM_NO_CONVERTER. + */ +extern NS_COM nsresult + NS_NewUTF8ConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize = 0); + +#endif /* nsUnicharInputStream_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp b/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp new file mode 100644 index 00000000..b0651ad1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsInputStreamTee.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIInputStreamTee.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsCOMPtr.h" + +class nsInputStreamTee : public nsIInputStreamTee +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIINPUTSTREAMTEE + + nsInputStreamTee(); + +private: + ~nsInputStreamTee() {} + + nsresult TeeSegment(const char *buf, PRUint32 count); + + static NS_METHOD WriteSegmentFun(nsIInputStream *, void *, const char *, + PRUint32, PRUint32, PRUint32 *); + +private: + nsCOMPtr mSource; + nsCOMPtr mSink; + nsWriteSegmentFun mWriter; // for implementing ReadSegments + void *mClosure; // for implementing ReadSegments +}; + +nsInputStreamTee::nsInputStreamTee() +{ +} + +nsresult +nsInputStreamTee::TeeSegment(const char *buf, PRUint32 count) +{ + if (!mSink) + return NS_OK; // nothing to do + nsresult rv; + PRUint32 bytesWritten = 0; + while (count) { + rv = mSink->Write(buf + bytesWritten, count, &bytesWritten); + if (NS_FAILED(rv)) { + // ok, this is not a fatal error... just drop our reference to mSink + // and continue on as if nothing happened. + NS_WARNING("Write failed (non-fatal)"); + // catch possible misuse of the input stream tee + NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "sink must be a blocking stream"); + mSink = 0; + break; + } + NS_ASSERTION(bytesWritten <= count, "wrote too much"); + count -= bytesWritten; + } + return NS_OK; +} + +NS_METHOD +nsInputStreamTee::WriteSegmentFun(nsIInputStream *in, void *closure, const char *fromSegment, + PRUint32 offset, PRUint32 count, PRUint32 *writeCount) +{ + nsInputStreamTee *tee = NS_REINTERPRET_CAST(nsInputStreamTee *, closure); + + nsresult rv = tee->mWriter(in, tee->mClosure, fromSegment, offset, count, writeCount); + if (NS_FAILED(rv) || (*writeCount == 0)) { + NS_ASSERTION((NS_FAILED(rv) ? (*writeCount == 0) : PR_TRUE), + "writer returned an error with non-zero writeCount"); + return rv; + } + + return tee->TeeSegment(fromSegment, *writeCount); +} + +NS_IMPL_ISUPPORTS2(nsInputStreamTee, + nsIInputStreamTee, + nsIInputStream) + +NS_IMETHODIMP +nsInputStreamTee::Close() +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + nsresult rv = mSource->Close(); + mSource = 0; + mSink = 0; + return rv; +} + +NS_IMETHODIMP +nsInputStreamTee::Available(PRUint32 *avail) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + return mSource->Available(avail); +} + +NS_IMETHODIMP +nsInputStreamTee::Read(char *buf, PRUint32 count, PRUint32 *bytesRead) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + + nsresult rv = mSource->Read(buf, count, bytesRead); + if (NS_FAILED(rv) || (*bytesRead == 0)) + return rv; + + return TeeSegment(buf, *bytesRead); +} + +NS_IMETHODIMP +nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, + void *closure, + PRUint32 count, + PRUint32 *bytesRead) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + + mWriter = writer; + mClosure = closure; + + return mSource->ReadSegments(WriteSegmentFun, this, count, bytesRead); +} + +NS_IMETHODIMP +nsInputStreamTee::IsNonBlocking(PRBool *result) +{ + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + return mSource->IsNonBlocking(result); +} + +NS_IMETHODIMP +nsInputStreamTee::SetSource(nsIInputStream *source) +{ + mSource = source; + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::GetSource(nsIInputStream **source) +{ + NS_IF_ADDREF(*source = mSource); + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::SetSink(nsIOutputStream *sink) +{ +#ifdef DEBUG + if (sink) { + PRBool nonBlocking; + nsresult rv = sink->IsNonBlocking(&nonBlocking); + if (NS_FAILED(rv) || nonBlocking) + NS_ERROR("sink should be a blocking stream"); + } +#endif + mSink = sink; + return NS_OK; +} + +NS_IMETHODIMP +nsInputStreamTee::GetSink(nsIOutputStream **sink) +{ + NS_IF_ADDREF(*sink = mSink); + return NS_OK; +} + +// factory method + +NS_COM nsresult +NS_NewInputStreamTee(nsIInputStream **result, + nsIInputStream *source, + nsIOutputStream *sink) +{ + nsresult rv; + + nsCOMPtr tee; + NS_NEWXPCOM(tee, nsInputStreamTee); + if (!tee) + return NS_ERROR_OUT_OF_MEMORY; + + rv = tee->SetSource(source); + if (NS_FAILED(rv)) return rv; + + rv = tee->SetSink(sink); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(*result = tee); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp new file mode 100644 index 00000000..88905f97 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.cpp @@ -0,0 +1,495 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsLinebreakConverter.h" + +#include "nsMemory.h" +#include "nsCRT.h" + + +#if defined(XP_WIN) && defined(_MSC_VER) && (_MSC_VER <= 1100) +#define LOSER_CHAR_CAST(t) (char *)(t) +#define LOSER_UNICHAR_CAST(t) (PRUnichar *)(t) +#else +#define LOSER_CHAR_CAST(t) (t) +#define LOSER_UNICHAR_CAST(t) (t) +#endif + +/*---------------------------------------------------------------------------- + GetLinebreakString + + Could make this inline +----------------------------------------------------------------------------*/ +static const char* GetLinebreakString(nsLinebreakConverter::ELinebreakType aBreakType) +{ + static const char* const sLinebreaks[] = { + "", // any + NS_LINEBREAK, // platform + LFSTR, // content + CRLF, // net + CRSTR, // Mac + LFSTR, // Unix + CRLF, // Windows + nsnull + }; + + return sLinebreaks[aBreakType]; +} + + +/*---------------------------------------------------------------------------- + AppendLinebreak + + Wee inline method to append a line break. Modifies ioDest. +----------------------------------------------------------------------------*/ +template +void AppendLinebreak(T*& ioDest, const char* lineBreakStr) +{ + *ioDest++ = *lineBreakStr; + + if (lineBreakStr[1]) + *ioDest++ = lineBreakStr[1]; +} + +/*---------------------------------------------------------------------------- + CountChars + + Counts occurrences of breakStr in aSrc +----------------------------------------------------------------------------*/ +template +PRInt32 CountLinebreaks(const T* aSrc, PRInt32 inLen, const char* breakStr) +{ + const T* src = aSrc; + const T* srcEnd = aSrc + inLen; + PRInt32 theCount = 0; + + while (src < srcEnd) + { + if (*src == *breakStr) + { + src ++; + if (src < srcEnd && breakStr[1] && *src == breakStr[1]) + src ++; + + theCount ++; + } + else + { + src ++; + } + } + + return theCount; +} + + +/*---------------------------------------------------------------------------- + ConvertBreaks + + ioLen *includes* a terminating null, if any +----------------------------------------------------------------------------*/ +template +static T* ConvertBreaks(const T* inSrc, PRInt32& ioLen, const char* srcBreak, const char* destBreak) +{ + NS_ASSERTION(inSrc && srcBreak && destBreak, "Got a null string"); + + T* resultString = nsnull; + + // handle the no conversion case + if (nsCRT::strcmp(srcBreak, destBreak) == 0) + { + resultString = (T *)nsMemory::Alloc(sizeof(T) * ioLen); + if (!resultString) return nsnull; + memcpy(resultString, inSrc, sizeof(T) * ioLen); // includes the null, if any + return resultString; + } + + PRInt32 srcBreakLen = strlen(srcBreak); + PRInt32 destBreakLen = strlen(destBreak); + + // handle the easy case, where the string length does not change, and the + // breaks are only 1 char long, i.e. CR <-> LF + if (srcBreakLen == destBreakLen && srcBreakLen == 1) + { + resultString = (T *)nsMemory::Alloc(sizeof(T) * ioLen); + if (!resultString) return nsnull; + + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + T* dst = resultString; + + char srcBreakChar = *srcBreak; // we know it's one char long already + char dstBreakChar = *destBreak; + + while (src < srcEnd) + { + if (*src == srcBreakChar) + { + *dst++ = dstBreakChar; + src++; + } + else + { + *dst++ = *src++; + } + } + + // ioLen does not change + } + else + { + // src and dest termination is different length. Do it a slower way. + + // count linebreaks in src. Assumes that chars in 2-char linebreaks are unique. + PRInt32 numLinebreaks = CountLinebreaks(inSrc, ioLen, srcBreak); + + PRInt32 newBufLen = ioLen - (numLinebreaks * srcBreakLen) + (numLinebreaks * destBreakLen); + resultString = (T *)nsMemory::Alloc(sizeof(T) * newBufLen); + if (!resultString) return nsnull; + + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + T* dst = resultString; + + while (src < srcEnd) + { + if (*src == *srcBreak) + { + *dst++ = *destBreak; + if (destBreak[1]) + *dst++ = destBreak[1]; + + src ++; + if (src < srcEnd && srcBreak[1] && *src == srcBreak[1]) + src ++; + } + else + { + *dst++ = *src++; + } + } + + ioLen = newBufLen; + } + + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertBreaksInSitu + + Convert breaks in situ. Can only do this if the linebreak length + does not change. +----------------------------------------------------------------------------*/ +template +static void ConvertBreaksInSitu(T* inSrc, PRInt32 inLen, char srcBreak, char destBreak) +{ + T* src = inSrc; + T* srcEnd = inSrc + inLen; + + while (src < srcEnd) + { + if (*src == srcBreak) + *src = destBreak; + + src ++; + } +} + + +/*---------------------------------------------------------------------------- + ConvertUnknownBreaks + + Convert unknown line breaks to the specified break. + + This will convert CRLF pairs to one break, and single CR or LF to a break. +----------------------------------------------------------------------------*/ +template +static T* ConvertUnknownBreaks(const T* inSrc, PRInt32& ioLen, const char* destBreak) +{ + const T* src = inSrc; + const T* srcEnd = inSrc + ioLen; // includes null, if any + + PRInt32 destBreakLen = strlen(destBreak); + PRInt32 finalLen = 0; + + while (src < srcEnd) + { + if (*src == nsCRT::CR) + { + if (src < srcEnd && src[1] == nsCRT::LF) + { + // CRLF + finalLen += destBreakLen; + src ++; + } + else + { + // Lone CR + finalLen += destBreakLen; + } + } + else if (*src == nsCRT::LF) + { + // Lone LF + finalLen += destBreakLen; + } + else + { + finalLen ++; + } + src ++; + } + + T* resultString = (T *)nsMemory::Alloc(sizeof(T) * finalLen); + if (!resultString) return nsnull; + + src = inSrc; + srcEnd = inSrc + ioLen; // includes null, if any + + T* dst = resultString; + + while (src < srcEnd) + { + if (*src == nsCRT::CR) + { + if (src < srcEnd && src[1] == nsCRT::LF) + { + // CRLF + AppendLinebreak(dst, destBreak); + src ++; + } + else + { + // Lone CR + AppendLinebreak(dst, destBreak); + } + } + else if (*src == nsCRT::LF) + { + // Lone LF + AppendLinebreak(dst, destBreak); + } + else + { + *dst++ = *src; + } + src ++; + } + + ioLen = finalLen; + return resultString; +} + + +#ifdef XP_MAC +#pragma mark - +#endif + + +/*---------------------------------------------------------------------------- + ConvertLineBreaks + +----------------------------------------------------------------------------*/ +char* nsLinebreakConverter::ConvertLineBreaks(const char* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + if (!aSrc) return nsnull; + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? strlen(aSrc) + 1 : aSrcLen; + + char* resultString; + if (aSrcBreaks == eLinebreakAny) + resultString = ConvertUnknownBreaks(LOSER_CHAR_CAST(aSrc), sourceLen, GetLinebreakString(aDestBreaks)); + else + resultString = ConvertBreaks(LOSER_CHAR_CAST(aSrc), sourceLen, GetLinebreakString(aSrcBreaks), GetLinebreakString(aDestBreaks)); + + if (outLen) + *outLen = sourceLen; + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertLineBreaksInSitu + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertLineBreaksInSitu(char **ioBuffer, ELinebreakType aSrcBreaks, + ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(ioBuffer && *ioBuffer, "Null pointer passed"); + if (!ioBuffer || !*ioBuffer) return NS_ERROR_NULL_POINTER; + + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? strlen(*ioBuffer) + 1 : aSrcLen; + + // can we convert in-place? + const char* srcBreaks = GetLinebreakString(aSrcBreaks); + const char* dstBreaks = GetLinebreakString(aDestBreaks); + + if ( (aSrcBreaks != eLinebreakAny) && + (strlen(srcBreaks) == 1) && + (strlen(dstBreaks) == 1) ) + { + ConvertBreaksInSitu(*ioBuffer, sourceLen, *srcBreaks, *dstBreaks); + if (outLen) + *outLen = sourceLen; + } + else + { + char* destBuffer; + + if (aSrcBreaks == eLinebreakAny) + destBuffer = ConvertUnknownBreaks(*ioBuffer, sourceLen, dstBreaks); + else + destBuffer = ConvertBreaks(*ioBuffer, sourceLen, srcBreaks, dstBreaks); + + if (!destBuffer) return NS_ERROR_OUT_OF_MEMORY; + *ioBuffer = destBuffer; + if (outLen) + *outLen = sourceLen; + } + + return NS_OK; +} + + +/*---------------------------------------------------------------------------- + ConvertUnicharLineBreaks + +----------------------------------------------------------------------------*/ +PRUnichar* nsLinebreakConverter::ConvertUnicharLineBreaks(const PRUnichar* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + if (!aSrc) return nsnull; + + PRInt32 bufLen = (aSrcLen == kIgnoreLen) ? nsCRT::strlen(aSrc) + 1 : aSrcLen; + + PRUnichar* resultString; + if (aSrcBreaks == eLinebreakAny) + resultString = ConvertUnknownBreaks(LOSER_UNICHAR_CAST(aSrc), bufLen, GetLinebreakString(aDestBreaks)); + else + resultString = ConvertBreaks(LOSER_UNICHAR_CAST(aSrc), bufLen, GetLinebreakString(aSrcBreaks), GetLinebreakString(aDestBreaks)); + + if (outLen) + *outLen = bufLen; + return resultString; +} + + +/*---------------------------------------------------------------------------- + ConvertStringLineBreaks + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertUnicharLineBreaksInSitu(PRUnichar **ioBuffer, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, PRInt32 aSrcLen, PRInt32* outLen) +{ + NS_ASSERTION(ioBuffer && *ioBuffer, "Null pointer passed"); + if (!ioBuffer || !*ioBuffer) return NS_ERROR_NULL_POINTER; + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + PRInt32 sourceLen = (aSrcLen == kIgnoreLen) ? nsCRT::strlen(*ioBuffer) + 1 : aSrcLen; + + // can we convert in-place? + const char* srcBreaks = GetLinebreakString(aSrcBreaks); + const char* dstBreaks = GetLinebreakString(aDestBreaks); + + if ( (aSrcBreaks != eLinebreakAny) && + (strlen(srcBreaks) == 1) && + (strlen(dstBreaks) == 1) ) + { + ConvertBreaksInSitu(*ioBuffer, sourceLen, *srcBreaks, *dstBreaks); + if (outLen) + *outLen = sourceLen; + } + else + { + PRUnichar* destBuffer; + + if (aSrcBreaks == eLinebreakAny) + destBuffer = ConvertUnknownBreaks(*ioBuffer, sourceLen, dstBreaks); + else + destBuffer = ConvertBreaks(*ioBuffer, sourceLen, srcBreaks, dstBreaks); + + if (!destBuffer) return NS_ERROR_OUT_OF_MEMORY; + *ioBuffer = destBuffer; + if (outLen) + *outLen = sourceLen; + } + + return NS_OK; +} + +/*---------------------------------------------------------------------------- + ConvertStringLineBreaks + +----------------------------------------------------------------------------*/ +nsresult nsLinebreakConverter::ConvertStringLineBreaks(nsString& ioString, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks) +{ + + NS_ASSERTION(aDestBreaks != eLinebreakAny, "Invalid parameter"); + + // nothing to do + if (ioString.IsEmpty()) return NS_OK; + + nsresult rv; + + // remember the old buffer in case + // we blow it away later + nsString::char_iterator stringBuf; + ioString.BeginWriting(stringBuf); + + PRInt32 newLen; + + rv = ConvertUnicharLineBreaksInSitu(&stringBuf, + aSrcBreaks, aDestBreaks, + ioString.Length() + 1, &newLen); + if (NS_FAILED(rv)) return rv; + + if (stringBuf != ioString.get()) + ioString.Adopt(stringBuf); + + return NS_OK; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h new file mode 100644 index 00000000..ec4bce57 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLinebreakConverter.h @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsLinebreakConverter_h_ +#define nsLinebreakConverter_h_ + + +#include "nscore.h" +#include "nsString.h" + +// utility class for converting between different line breaks. + +class NS_COM nsLinebreakConverter +{ +public: + + // Note: enum must match char* array in GetLinebreakString + typedef enum { + eLinebreakAny, // any kind of linebreak (i.e. "don't care" source) + + eLinebreakPlatform, // platform linebreak + eLinebreakContent, // Content model linebreak (LF) + eLinebreakNet, // Form submission linebreak (CRLF) + + eLinebreakMac, // CR + eLinebreakUnix, // LF + eLinebreakWindows // CRLF + + } ELinebreakType; + + enum { + kIgnoreLen = -1 + }; + + /* ConvertLineBreaks + * Convert line breaks in the supplied string, allocating and returning + * a new buffer. Returns nsnull on failure. + * @param aSrc: the source string. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static char* ConvertLineBreaks(const char* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertUnicharLineBreaks + * Convert line breaks in the supplied string, allocating and returning + * a new buffer. Returns nsnull on failure. + * @param aSrc: the source string. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source, in characters. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static PRUnichar* ConvertUnicharLineBreaks(const PRUnichar* aSrc, + ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertStringLineBreaks + * Convert line breaks in the supplied string, changing the string buffer (i.e. in-place conversion) + * @param ioString: the string to be converted. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source, in characters. If -1, the source is assumed to be a null- + * terminated string. + */ + static nsresult ConvertStringLineBreaks(nsString& ioString, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks); + + + /* ConvertLineBreaksInSitu + * Convert line breaks in place if possible. NOTE: THIS MAY REALLOCATE THE BUFFER, + * BUT IT WON'T FREE THE OLD BUFFER (because it doesn't know how). So be prepared + * to keep a copy of the old pointer, and free it if this passes back a new pointer. + * ALSO NOTE: DON'T PASS A STATIC STRING POINTER TO THIS FUNCTION. + * + * @param ioBuffer: the source buffer. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static nsresult ConvertLineBreaksInSitu(char **ioBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + + + /* ConvertUnicharLineBreaksInSitu + * Convert line breaks in place if possible. NOTE: THIS MAY REALLOCATE THE BUFFER, + * BUT IT WON'T FREE THE OLD BUFFER (because it doesn't know how). So be prepared + * to keep a copy of the old pointer, and free it if this passes back a new pointer. + * + * @param ioBuffer: the source buffer. if aSrcLen == kIgnoreLen this string is assumed + * to be null terminated, otherwise it must be at least aSrcLen long. + * @param aSrcBreaks: the line breaks in the source. If unknown, pass eLinebreakAny. + * If known, pass the known value, as this may be more efficient. + * @param aDestBreaks: the line breaks you want in the output. + * @param aSrcLen: length of the source in characters. If -1, the source is assumed to be a null- + * terminated string. + * @param aOutLen: used to return character length of returned buffer, if not null. + */ + static nsresult ConvertUnicharLineBreaksInSitu(PRUnichar **ioBuffer, ELinebreakType aSrcBreaks, ELinebreakType aDestBreaks, + PRInt32 aSrcLen = kIgnoreLen, PRInt32* aOutLen = nsnull); + +}; + + + + +#endif // nsLinebreakConverter_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h new file mode 100644 index 00000000..8201affb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFile.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. Modifications made by IBM + * described herein are Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. OS/2 build. + */ + +#ifndef _NS_LOCAL_FILE_H_ +#define _NS_LOCAL_FILE_H_ + +#define NS_LOCAL_FILE_CID {0x2e23e220, 0x60be, 0x11d3, {0x8c, 0x4a, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74}} + +#define NS_DECL_NSLOCALFILE_UNICODE_METHODS \ + nsresult AppendUnicode(const PRUnichar *aNode); \ + nsresult GetUnicodeLeafName(PRUnichar **aLeafName); \ + nsresult SetUnicodeLeafName(const PRUnichar *aLeafName); \ + nsresult CopyToUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult CopyToFollowingLinksUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult MoveToUnicode(nsIFile *aNewParentDir, const PRUnichar *aNewLeafName); \ + nsresult GetUnicodeTarget(PRUnichar **aTarget); \ + nsresult GetUnicodePath(PRUnichar **aPath); \ + nsresult InitWithUnicodePath(const PRUnichar *aPath); \ + nsresult AppendRelativeUnicodePath(const PRUnichar *aRelativePath); + +// nsXPComInit needs to know about how we are implemented, +// so here we will export it. Other users should not depend +// on this. + +#include +#include "nsILocalFile.h" + +#ifdef XP_WIN +#include "nsLocalFileWin.h" +#elif defined(XP_MACOSX) && !defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +#include "nsLocalFileOSX.h" +#elif defined(XP_MAC) +#include "nsLocalFileMac.h" +#elif defined(XP_UNIX) || defined(XP_BEOS) +#include "nsLocalFileUnix.h" +#elif defined(XP_OS2) +#include "nsLocalFileOS2.h" +#else +#error NOT_IMPLEMENTED +#endif + +#define NSRESULT_FOR_RETURN(ret) (((ret) < 0) ? NSRESULT_FOR_ERRNO() : NS_OK) + +inline nsresult +nsresultForErrno(int err) +{ + switch (err) { + case 0: + return NS_OK; + case ENOENT: + return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST; + case ENOTDIR: + return NS_ERROR_FILE_DESTINATION_NOT_DIR; +#ifdef ENOLINK + case ENOLINK: + return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; +#endif /* ENOLINK */ + case EEXIST: + return NS_ERROR_FILE_ALREADY_EXISTS; +#ifdef EPERM + case EPERM: +#endif /* EPERM */ + case EACCES: + return NS_ERROR_FILE_ACCESS_DENIED; + default: + return NS_ERROR_FAILURE; + } +} + +#define NSRESULT_FOR_ERRNO() nsresultForErrno(errno) + +void NS_StartupLocalFile(); +void NS_ShutdownLocalFile(); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp new file mode 100644 index 00000000..664c5304 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileCommon.cpp @@ -0,0 +1,278 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" + +#include "nsLocalFile.h" // includes platform-specific headers +#include "nsLocalFileUnicode.h" + +#include "nsString.h" +#include "nsCOMPtr.h" +#include "nsReadableUtils.h" +#include "nsPrintfCString.h" +#include "nsCRT.h" + +#ifdef XP_WIN +#include +#endif + + +void NS_StartupLocalFile() +{ + nsLocalFile::GlobalInit(); +} + +void NS_ShutdownLocalFile() +{ + nsLocalFile::GlobalShutdown(); +} + +#if (!defined(XP_MAC) && !defined(XP_MACOSX)) || defined(VBOX_MACOSX_FOLLOWS_UNIX_IO) +NS_IMETHODIMP +nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + + nsCAutoString path; + aFile->GetNativePath(path); + if (path.IsEmpty()) + return NS_ERROR_INVALID_ARG; + return InitWithNativePath(path); +} +#endif + +#if defined(XP_MAC) +#define kMaxFilenameLength 31 +#else +#define kMaxFilenameLength 255 +#endif + +NS_IMETHODIMP +nsLocalFile::CreateUnique(PRUint32 type, PRUint32 attributes) +{ + nsresult rv = Create(type, attributes); + + if (NS_SUCCEEDED(rv)) return NS_OK; + if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; + + nsCAutoString leafName; + rv = GetNativeLeafName(leafName); + + if (NS_FAILED(rv)) return rv; + + const char* lastDot = strrchr(leafName.get(), '.'); + char suffix[kMaxFilenameLength + 1] = ""; + if (lastDot) + { + strncpy(suffix, lastDot, kMaxFilenameLength); // include '.' + suffix[kMaxFilenameLength] = 0; // make sure it's null terminated + leafName.SetLength(lastDot - leafName.get()); // strip suffix and dot. + } + + const int maxRootLength = (kMaxFilenameLength - 4) - strlen(suffix) - 1; + + if ((int)leafName.Length() > (int)maxRootLength) + leafName.SetLength(maxRootLength); + + for (short indx = 1; indx < 10000; indx++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + SetNativeLeafName(leafName + + nsPrintfCString("-%d", indx) + + nsDependentCString(suffix)); + + rv = Create(type, attributes); + + if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS) + { + return rv; + } + } + + // The disk is full, sort of + return NS_ERROR_FILE_TOO_BIG; +} + +#if defined(XP_MAC) +static const PRUnichar kPathSeparatorChar = ':'; +#elif defined(XP_WIN) || defined(XP_OS2) +static const PRUnichar kPathSeparatorChar = '\\'; +#elif defined(XP_UNIX) || defined(XP_BEOS) +static const PRUnichar kPathSeparatorChar = '/'; +#else +#error Need to define file path separator for your platform +#endif + +#if defined(XP_MAC) +static const char kSlashStr[] = "/"; +static const char kESCSlashStr[] = "%2F"; +#endif + +static PRInt32 SplitPath(PRUnichar *path, PRUnichar **nodeArray, PRInt32 arrayLen) +{ + if (*path == 0) + return 0; + + PRUnichar **nodePtr = nodeArray; + if (*path == kPathSeparatorChar) + path++; + *nodePtr++ = path; + + for (PRUnichar *cp = path; *cp != 0; cp++) { + if (*cp == kPathSeparatorChar) { + *cp++ = 0; + if (*cp == 0) + break; + if (nodePtr - nodeArray >= arrayLen) + return -1; + *nodePtr++ = cp; + } + } + return nodePtr - nodeArray; +} + + +NS_IMETHODIMP +nsLocalFile::GetRelativeDescriptor(nsILocalFile *fromFile, nsACString& _retval) +{ + NS_ENSURE_ARG_POINTER(fromFile); + const PRInt32 kMaxNodesInPath = 32; + + // + // _retval will be UTF-8 encoded + // + + nsresult rv; + _retval.Truncate(0); + + nsAutoString thisPath, fromPath; + PRUnichar *thisNodes[kMaxNodesInPath], *fromNodes[kMaxNodesInPath]; + PRInt32 thisNodeCnt, fromNodeCnt, nodeIndex; + + rv = GetPath(thisPath); + if (NS_FAILED(rv)) + return rv; + rv = fromFile->GetPath(fromPath); + if (NS_FAILED(rv)) + return rv; + + // get raw pointer to mutable string buffer + PRUnichar *thisPathPtr; thisPath.BeginWriting(thisPathPtr); + PRUnichar *fromPathPtr; fromPath.BeginWriting(fromPathPtr); + + thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath); + fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath); + if (thisNodeCnt < 0 || fromNodeCnt < 0) + return NS_ERROR_FAILURE; + + for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) { +#ifdef XP_WIN + if (_wcsicmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) + break; +#else + if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) + break; +#endif + } + + PRInt32 branchIndex = nodeIndex; + for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; nodeIndex++) + _retval.AppendLiteral("../"); + for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) { + NS_ConvertUCS2toUTF8 nodeStr(thisNodes[nodeIndex]); +#ifdef XP_MAC + nodeStr.ReplaceSubstring(kSlashStr, kESCSlashStr); +#endif + _retval.Append(nodeStr); + if (nodeIndex + 1 < thisNodeCnt) + _retval.Append('/'); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetRelativeDescriptor(nsILocalFile *fromFile, const nsACString& relativeDesc) +{ + NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../"); + + nsCOMPtr targetFile; + nsresult rv = fromFile->Clone(getter_AddRefs(targetFile)); + if (NS_FAILED(rv)) + return rv; + + // + // relativeDesc is UTF-8 encoded + // + + nsCString::const_iterator strBegin, strEnd; + relativeDesc.BeginReading(strBegin); + relativeDesc.EndReading(strEnd); + + nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd); + nsCString::const_iterator pos(strBegin); + + nsCOMPtr parentDir; + while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) { + rv = targetFile->GetParent(getter_AddRefs(parentDir)); + if (NS_FAILED(rv)) + return rv; + targetFile = parentDir; + + nodeBegin = nodeEnd; + pos = nodeEnd; + nodeEnd = strEnd; + } + + nodeBegin = nodeEnd = pos; + while (nodeEnd != strEnd) { + FindCharInReadable('/', nodeEnd, strEnd); +#ifdef XP_MAC + nsCAutoString nodeString(Substring(nodeBegin, nodeEnd)); + nodeString.ReplaceSubstring(kESCSlashStr, kSlashStr); + targetFile->Append(NS_ConvertUTF8toUCS2(nodeString)); +#else + targetFile->Append(NS_ConvertUTF8toUCS2(Substring(nodeBegin, nodeEnd))); +#endif + if (nodeEnd != strEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. + ++nodeEnd; + nodeBegin = nodeEnd; + } + + nsCOMPtr targetLocalFile(do_QueryInterface(targetFile)); + return InitWithFile(targetLocalFile); +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp new file mode 100644 index 00000000..bebc76c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.cpp @@ -0,0 +1,3554 @@ +/* -*- 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Dagley + * John R. McMullen + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "nsIInternetConfigService.h" +#include "nsIMIMEInfo.h" +#include "prtypes.h" +#include "prerror.h" + +#include "nsReadableUtils.h" +#include "nsITimelineService.h" + +#ifdef XP_MACOSX +#include "nsXPIDLString.h" + +#include "private/pprio.h" +#else +#include "pprio.h" // Include this rather than prio.h so we get def of PR_ImportFile +#endif +#include "prmem.h" +#include "plbase64.h" + +#include "FullPath.h" +#include "FileCopy.h" +#include "MoreFilesExtras.h" +#include "DirectoryCopy.h" +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "macDirectoryCopy.h" + +#include + +// Stupid @#$% header looks like its got extern mojo but it doesn't really +extern "C" +{ +#ifndef XP_MACOSX +// BADPINK - this MSL header doesn't exist under macosx :-( +#include +#endif +} + +#if TARGET_CARBON +#include // Needed for definition of kUnresolvedCFragSymbolAddress +#include +#endif + +#pragma mark [Constants] + +const OSType kDefaultCreator = 'MOSS'; + +#pragma mark - +#pragma mark [nsPathParser] + +class nsPathParser +{ +public: + nsPathParser(const nsACString &path); + + ~nsPathParser() + { + if (mAllocatedBuffer) + nsMemory::Free(mAllocatedBuffer); + } + + const char* First() + { + return nsCRT::strtok(mBuffer, ":", &mNewString); + } + const char* Next() + { + return nsCRT::strtok(mNewString, ":", &mNewString); + } + const char* Remainder() + { + return mNewString; + } + +private: + char mAutoBuffer[512]; + char *mAllocatedBuffer; + char *mBuffer, *mNewString; +}; + +nsPathParser::nsPathParser(const nsACString &inPath) : + mAllocatedBuffer(nsnull), mNewString(nsnull) +{ + PRUint32 inPathLen = inPath.Length(); + if (inPathLen >= sizeof(mAutoBuffer)) { + mAllocatedBuffer = (char *)nsMemory::Alloc(inPathLen + 1); + mBuffer = mAllocatedBuffer; + } + else + mBuffer = mAutoBuffer; + + // copy inPath into mBuffer + nsACString::const_iterator start, end; + inPath.BeginReading(start); + inPath.EndReading(end); + + PRUint32 size, offset = 0; + for ( ; start != end; start.advance(size)) { + const char* buf = start.get(); + size = start.size_forward(); + memcpy(mBuffer + offset, buf, size); + offset += size; + } + mBuffer[offset] = '\0'; +} + +#pragma mark - +#pragma mark [static util funcs] + +static inline void ClearFSSpec(FSSpec& aSpec) +{ + aSpec.vRefNum = 0; + aSpec.parID = 0; + aSpec.name[0] = 0; +} + + +// Simple func to map Mac OS errors into nsresults +static nsresult MacErrorMapper(OSErr inErr) +{ + nsresult outErr; + + switch (inErr) + { + case noErr: + outErr = NS_OK; + break; + + case fnfErr: + outErr = NS_ERROR_FILE_NOT_FOUND; + break; + + case dupFNErr: + outErr = NS_ERROR_FILE_ALREADY_EXISTS; + break; + + case dskFulErr: + outErr = NS_ERROR_FILE_DISK_FULL; + break; + + case fLckdErr: + outErr = NS_ERROR_FILE_IS_LOCKED; + break; + + // Can't find good map for some + case bdNamErr: + outErr = NS_ERROR_FAILURE; + break; + + default: + outErr = NS_ERROR_FAILURE; + break; + } + return outErr; +} + + + +/*---------------------------------------------------------------------------- + IsEqualFSSpec + + Compare two canonical FSSpec records. + + Entry: file1 = pointer to first FSSpec record. + file2 = pointer to second FSSpec record. + + Exit: function result = true if the FSSpec records are equal. +----------------------------------------------------------------------------*/ + +static PRBool IsEqualFSSpec(const FSSpec& file1, const FSSpec& file2) +{ + return + file1.vRefNum == file2.vRefNum && + file1.parID == file2.parID && + EqualString(file1.name, file2.name, false, true); +} + + +/*---------------------------------------------------------------------------- + GetParentFolderSpec + + Given an FSSpec to a (possibly non-existent) file, get an FSSpec for its + parent directory. + +----------------------------------------------------------------------------*/ + +static OSErr GetParentFolderSpec(const FSSpec& fileSpec, FSSpec& parentDirSpec) +{ + CInfoPBRec pBlock = {0}; + OSErr err = noErr; + + parentDirSpec.name[0] = 0; + + pBlock.dirInfo.ioVRefNum = fileSpec.vRefNum; + pBlock.dirInfo.ioDrDirID = fileSpec.parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) return err; + + parentDirSpec.vRefNum = fileSpec.vRefNum; + parentDirSpec.parID = pBlock.dirInfo.ioDrParID; + + return err; +} + + +/*---------------------------------------------------------------------------- + VolHasDesktopDB + + Check to see if a volume supports the new desktop database. + + Entry: vRefNum = vol ref num of volumn + + Exit: function result = error code. + *hasDesktop = true if volume has the new desktop database. +----------------------------------------------------------------------------*/ + +static OSErr VolHasDesktopDB (short vRefNum, Boolean *hasDesktop) +{ + HParamBlockRec pb; + GetVolParmsInfoBuffer info; + OSErr err = noErr; + + pb.ioParam.ioCompletion = nil; + pb.ioParam.ioNamePtr = nil; + pb.ioParam.ioVRefNum = vRefNum; + pb.ioParam.ioBuffer = (Ptr)&info; + pb.ioParam.ioReqCount = sizeof(info); + err = PBHGetVolParmsSync(&pb); + *hasDesktop = err == noErr && (info.vMAttrib & (1L << bHasDesktopMgr)) != 0; + return err; +} + + +/*---------------------------------------------------------------------------- + GetLastModDateTime + + Get the last mod date and time of a file. + + Entry: fSpec = pointer to file spec. + + Exit: function result = error code. + *lastModDateTime = last mod date and time. +----------------------------------------------------------------------------*/ + +static OSErr GetLastModDateTime(const FSSpec *fSpec, unsigned long *lastModDateTime) +{ + CInfoPBRec pBlock; + OSErr err = noErr; + + pBlock.hFileInfo.ioNamePtr = (StringPtr)fSpec->name; + pBlock.hFileInfo.ioVRefNum = fSpec->vRefNum; + pBlock.hFileInfo.ioFDirIndex = 0; + pBlock.hFileInfo.ioDirID = fSpec->parID; + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) return err; + *lastModDateTime = pBlock.hFileInfo.ioFlMdDat; + return noErr; +} + + +/*---------------------------------------------------------------------------- + FindAppOnVolume + + Find an application on a volume. + + Entry: sig = application signature. + vRefNum = vol ref num + + Exit: function result = error code + = afpItemNotFound if app not found on vol. + *file = file spec for application on volume. +----------------------------------------------------------------------------*/ + +static OSErr FindAppOnVolume (OSType sig, short vRefNum, FSSpec *file) +{ + DTPBRec pb; + OSErr err = noErr; + short ioDTRefNum, i; + FInfo fInfo; + FSSpec candidate; + unsigned long lastModDateTime, maxLastModDateTime; + + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioVRefNum = vRefNum; + pb.ioNamePtr = nil; + err = PBDTGetPath(&pb); + if (err != noErr) return err; + ioDTRefNum = pb.ioDTRefNum; + + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioIndex = 0; + pb.ioFileCreator = sig; + pb.ioNamePtr = file->name; + pb.ioDTRefNum = ioDTRefNum; + err = PBDTGetAPPLSync(&pb); + + if (err == fnfErr || err == paramErr) return afpItemNotFound; + if (err != noErr) return err; + + file->vRefNum = vRefNum; + file->parID = pb.ioAPPLParID; + + err = FSpGetFInfo(file, &fInfo); + if (err == noErr) return noErr; + + i = 1; + maxLastModDateTime = 0; + while (true) + { + memset(&pb, 0, sizeof(DTPBRec)); + pb.ioCompletion = nil; + pb.ioIndex = i; + pb.ioFileCreator = sig; + pb.ioNamePtr = candidate.name; + pb.ioDTRefNum = ioDTRefNum; + err = PBDTGetAPPLSync(&pb); + if (err != noErr) break; + candidate.vRefNum = vRefNum; + candidate.parID = pb.ioAPPLParID; + err = GetLastModDateTime(file, &lastModDateTime); + if (err == noErr) { + if (lastModDateTime > maxLastModDateTime) { + maxLastModDateTime = lastModDateTime; + *file = candidate; + } + } + i++; + } + + return maxLastModDateTime > 0 ? noErr : afpItemNotFound; +} + + +/*---------------------------------------------------------------------------- + GetIndVolume + + Get a volume reference number by volume index. + + Entry: index = volume index + + Exit: function result = error code. + *vRefNum = vol ref num of indexed volume. +----------------------------------------------------------------------------*/ + +static OSErr GetIndVolume(short index, short *vRefNum) +{ + HParamBlockRec pb; + Str63 volumeName; + OSErr err = noErr; + + pb.volumeParam.ioCompletion = nil; + pb.volumeParam.ioNamePtr = volumeName; + pb.volumeParam.ioVolIndex = index; + + err = PBHGetVInfoSync(&pb); + + *vRefNum = pb.volumeParam.ioVRefNum; + return err; +} + + +// Private NSPR functions +static unsigned long gJanuaryFirst1970Seconds = 0; +/* + * 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; +} + +static 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(); +} + +static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp ) +{ + if ( gJanuaryFirst1970Seconds == 0) + MacintoshInitializeTime(); + timestamp -= gJanuaryFirst1970Seconds; + PRTime usecPerSec, dateInMicroSeconds; + LL_I2L(dateInMicroSeconds, timestamp); + LL_I2L(usecPerSec, PR_MSEC_PER_SEC); + LL_MUL(*aLastModifiedTime, usecPerSec, dateInMicroSeconds); + return NS_OK; +} + +static nsresult ConvertMillisecondsToMacTime(PRInt64 aTime, PRUint32 *aOutMacTime) +{ + NS_ENSURE_ARG( aOutMacTime ); + + PRTime usecPerSec, dateInSeconds; + dateInSeconds = LL_ZERO; + + LL_I2L(usecPerSec, PR_MSEC_PER_SEC); + LL_DIV(dateInSeconds, aTime, usecPerSec); // dateInSeconds = aTime/1,000 + LL_L2UI(*aOutMacTime, dateInSeconds); + *aOutMacTime += 2082844800; // date + Mac epoch + + return NS_OK; +} + +static void myPLstrcpy(Str255 dst, const char* src) +{ + int srcLength = strlen(src); + NS_ASSERTION(srcLength <= 255, "Oops, Str255 can't hold >255 chars"); + if (srcLength > 255) + srcLength = 255; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +static void myPLstrncpy(Str255 dst, const char* src, int inMax) +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +/* + NS_TruncNodeName + + Utility routine to do a mid-trunc on a potential file name so that it is + no longer than 31 characters. Until we move to the HFS+ APIs we need this + to come up with legal Mac file names. + + Entry: aNode = initial file name + outBuf = scratch buffer for the truncated name (MUST be >= 32 characters) + + Exit: function result = pointer to truncated name. Will be either aNode or outBuf. + +*/ +const char* NS_TruncNodeName(const char *aNode, char *outBuf) +{ + PRUint32 nodeLen; + if ((nodeLen = strlen(aNode)) > 31) + { + static PRBool sInitialized = PR_FALSE; + static CharByteTable sTable; + // Init to "..." in case we fail to get the ellipsis token + static char sEllipsisTokenStr[4] = { '.', '.', '.', 0 }; + static PRUint8 sEllipsisTokenLen = 3; + + if (!sInitialized) + { + // Entries in the table are: + // 0 == 1 byte char + // 1 == 2 byte char + FillParseTable(sTable, smSystemScript); + + Handle itl4ResHandle = nsnull; + long offset, len; + ::GetIntlResourceTable(smSystemScript, smUnTokenTable, &itl4ResHandle, &offset, &len); + if (itl4ResHandle) + { + UntokenTable *untokenTableRec = (UntokenTable *)(*itl4ResHandle + offset); + if (untokenTableRec->lastToken >= tokenEllipsis) + { + offset += untokenTableRec->index[tokenEllipsis]; + char *tokenStr = (*itl4ResHandle + offset); + sEllipsisTokenLen = tokenStr[0]; + memcpy(sEllipsisTokenStr, &tokenStr[1], sEllipsisTokenLen); + } + ::ReleaseResource(itl4ResHandle); + } + sInitialized = PR_TRUE; + } + + PRInt32 halfLen = (31 - sEllipsisTokenLen) / 2; + PRInt32 charSize = 0, srcPos, destPos; + for (srcPos = 0; srcPos + charSize <= halfLen; srcPos += charSize) + charSize = sTable[aNode[srcPos]] ? 2 : 1; + + memcpy(outBuf, aNode, srcPos); + memcpy(outBuf + srcPos, sEllipsisTokenStr, sEllipsisTokenLen); + destPos = srcPos + sEllipsisTokenLen; + + for (; srcPos < nodeLen - halfLen; srcPos += charSize) + charSize = sTable[aNode[srcPos]] ? 2 : 1; + + memcpy(outBuf + destPos, aNode + srcPos, nodeLen - srcPos); + destPos += (nodeLen - srcPos); + outBuf[destPos] = '\0'; + return outBuf; + } + return aNode; +} + +/** + * HFSPlusGetRawPath returns the path for an FSSpec as a unicode string. + * + * The reason for this routine instead of just calling FSRefMakePath is + * (1) inSpec does not have to exist + * (2) FSRefMakePath uses '/' as the separator under OSX and ':' under OS9 + */ +static OSErr HFSPlusGetRawPath(const FSSpec& inSpec, nsAString& outStr) +{ + OSErr err; + nsAutoString ucPathString; + + outStr.Truncate(0); + + FSRef nodeRef; + FSCatalogInfo catalogInfo; + catalogInfo.parentDirID = 0; + err = ::FSpMakeFSRef(&inSpec, &nodeRef); + + if (err == fnfErr) { + FSSpec parentDirSpec; + err = GetParentFolderSpec(inSpec, parentDirSpec); + if (err == noErr) { + const char *startPtr = (const char*)&inSpec.name[1]; + NS_CopyNativeToUnicode(Substring(startPtr, startPtr + PRUint32(inSpec.name[0])), outStr); + err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef); + } + } + + while (err == noErr && catalogInfo.parentDirID != fsRtParID) { + HFSUniStr255 nodeName; + FSRef parentRef; + err = ::FSGetCatalogInfo(&nodeRef, + kFSCatInfoNodeFlags + kFSCatInfoParentDirID, + &catalogInfo, + &nodeName, + nsnull, + &parentRef); + if (err == noErr) + { + if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) + nodeName.unicode[nodeName.length++] = PRUnichar(':'); + const PRUnichar* nodeNameUni = (const PRUnichar*) nodeName.unicode; + outStr.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0); + nodeRef = parentRef; + } + } + return err; +} + + +// The R**co FSSpec resolver - +// it slices, it dices, it juliannes fries and it even creates FSSpecs out of whatever you feed it +// This function will take a path and a starting FSSpec and generate a FSSpec to represent +// the target of the two. If the intial FSSpec is null the path alone will be resolved +static OSErr ResolvePathAndSpec(const char * filePath, FSSpec *inSpec, PRBool createDirs, FSSpec *outSpec) +{ + OSErr err = noErr; + size_t inLength = strlen(filePath); + Boolean isRelative = (filePath && inSpec); + FSSpec tempSpec; + Str255 ppath; + Boolean isDirectory; + + if (isRelative && inSpec) + { + outSpec->vRefNum = inSpec->vRefNum; + outSpec->parID = inSpec->parID; + + if (inSpec->name[0] != 0) + { + long theDirID; + + err = FSpGetDirectoryID(inSpec, &theDirID, &isDirectory); + + if (err == noErr && isDirectory) + outSpec->parID = theDirID; + else if (err == fnfErr && createDirs) + { + err = FSpDirCreate(inSpec, smCurrentScript, &theDirID); + if (err == noErr) + outSpec->parID = theDirID; + else if (err == fnfErr) + err = dirNFErr; + } + } + } + else + { + outSpec->vRefNum = 0; + outSpec->parID = 0; + } + + if (err) + return err; + + // Try making an FSSpec from the path + if (inLength < 255) + { + // Use tempSpec as dest because if FSMakeFSSpec returns dirNFErr, it + // will reset the dest spec and we'll lose what we determined above. + + myPLstrcpy(ppath, filePath); + err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, &tempSpec); + if (err == noErr || err == fnfErr) + *outSpec = tempSpec; + } + else if (!isRelative) + { + err = ::FSpLocationFromFullPath(inLength, filePath, outSpec); + } + else + { // If the path is relative and >255 characters we need to manually walk the + // path appending each node to the initial FSSpec so to reach that code we + // set the err to bdNamErr and fall into the code below + err = bdNamErr; + } + + // If we successfully created a spec then leave + if (err == noErr) + return err; + + // We get here when the directory hierarchy needs to be created or we're resolving + // a relative path >255 characters long + if (err == dirNFErr || err == bdNamErr) + { + const char* path = filePath; + + if (!isRelative) // If path is relative, we still need vRefNum & parID. + { + outSpec->vRefNum = 0; + outSpec->parID = 0; + } + + do + { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + myPLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, outSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // Since there's more to go, we have to get the directory ID, which becomes + // the parID for the next round. + if (err == noErr) + { + // The directory (or perhaps a file) exists. Find its dirID. + long dirID; + err = ::FSpGetDirectoryID(outSpec, &dirID, &isDirectory); + if (!isDirectory) + err = dupFNErr; // oops! a file exists with that name. + if (err != noErr) + break; // bail if we've got an error + outSpec->parID = dirID; + } + else if ((err == fnfErr) && createDirs) + { + // If we got "file not found" and we're allowed to create directories + // then we need to create one + err = ::FSpDirCreate(outSpec, smCurrentScript, &outSpec->parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + if (err != noErr) + break; + path = nextColon; // next round + } while (true); + } + + return err; +} + + +#pragma mark - +#pragma mark [StFollowLinksState] +class StFollowLinksState +{ + public: + StFollowLinksState(nsILocalFile *aFile) : + mFile(aFile) + { + NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); + if (mFile) + mFile->GetFollowLinks(&mSavedState); + } + + StFollowLinksState(nsILocalFile *aFile, PRBool followLinksState) : + mFile(aFile) + { + NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); + if (mFile) { + mFile->GetFollowLinks(&mSavedState); + mFile->SetFollowLinks(followLinksState); + } + } + + ~StFollowLinksState() + { + if (mFile) + mFile->SetFollowLinks(mSavedState); + } + + private: + nsCOMPtr mFile; + PRBool mSavedState; +}; + +#pragma mark - +#pragma mark [nsDirEnumerator] +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() + { + } + + nsresult Init(nsILocalFileMac* parent) + { + NS_ENSURE_ARG(parent); + nsresult rv; + FSSpec fileSpec; + + rv = parent->GetFSSpec(&fileSpec); + if (NS_FAILED(rv)) + return rv; + + OSErr err; + Boolean isDirectory; + + err = ::FSpGetDirectoryID(&fileSpec, &mDirID, &isDirectory); + if (err || !isDirectory) + return NS_ERROR_FILE_NOT_DIRECTORY; + + mCatInfo.hFileInfo.ioNamePtr = mItemName; + mCatInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum; + mItemIndex = 1; + + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv = NS_OK; + if (mNext == nsnull) + { + mItemName[0] = 0; + mCatInfo.dirInfo.ioFDirIndex = mItemIndex; + mCatInfo.dirInfo.ioDrDirID = mDirID; + + OSErr err = ::PBGetCatInfoSync(&mCatInfo); + if (err == fnfErr) + { + // end of dir entries + *result = PR_FALSE; + return NS_OK; + } + + // Make a new nsILocalFile for the new element + FSSpec tempSpec; + tempSpec.vRefNum = mCatInfo.hFileInfo.ioVRefNum; + tempSpec.parID = mDirID; + ::BlockMoveData(mItemName, tempSpec.name, mItemName[0] + 1); + + rv = NS_NewLocalFileWithFSSpec(&tempSpec, PR_TRUE, getter_AddRefs(mNext)); + if (NS_FAILED(rv)) + return rv; + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + ++mItemIndex; + return NS_OK; + } + + private: + ~nsDirEnumerator() {} + + protected: + nsCOMPtr mNext; + + CInfoPBRec mCatInfo; + short mItemIndex; + long mDirID; + Str63 mItemName; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + +#pragma mark - + +OSType nsLocalFile::sCurrentProcessSignature = 0; +PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE; +PRBool nsLocalFile::sRunningOSX = PR_FALSE; + +#pragma mark [CTOR/DTOR] +nsLocalFile::nsLocalFile() : + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE), + mSpecDirty(PR_TRUE), + mCatInfoDirty(PR_TRUE), + mType('TEXT'), + mCreator(kDefaultCreator) +{ + ClearFSSpec(mSpec); + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; +} + +nsLocalFile::nsLocalFile(const nsLocalFile& srcFile) +{ + *this = srcFile; +} + +nsLocalFile::nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath) : + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE), + mSpecDirty(PR_TRUE), + mSpec(aSpec), + mAppendedPath(aAppendedPath), + mCatInfoDirty(PR_TRUE), + mType('TEXT'), + mCreator(kDefaultCreator) +{ + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; +} + +nsLocalFile& nsLocalFile::operator=(const nsLocalFile& rhs) +{ + mFollowLinks = rhs.mFollowLinks; + mFollowLinksDirty = rhs.mFollowLinksDirty; + mSpecDirty = rhs.mSpecDirty; + mSpec = rhs.mSpec; + mAppendedPath = rhs.mAppendedPath; + mTargetSpec = rhs.mTargetSpec; + mCatInfoDirty = rhs.mCatInfoDirty; + mType = rhs.mType; + mCreator = rhs.mCreator; + + if (!rhs.mCatInfoDirty) + mCachedCatInfo = rhs.mCachedCatInfo; + + return *this; +} + +#pragma mark - +#pragma mark [nsISupports interface implementation] + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile, + nsILocalFileMac, + nsILocalFile, + nsIFile) + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + +// This function resets any cached information about the file. +void +nsLocalFile::MakeDirty() +{ + mSpecDirty = PR_TRUE; + mFollowLinksDirty = PR_TRUE; + mCatInfoDirty = PR_TRUE; + + ClearFSSpec(mTargetSpec); +} + + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + NS_ENSURE_ARG_POINTER(aFollowLinks); + *aFollowLinks = mFollowLinks; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + if (aFollowLinks != mFollowLinks) + { + mFollowLinks = aFollowLinks; + mFollowLinksDirty = PR_TRUE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::ResolveAndStat() +{ + OSErr err = noErr; + FSSpec resolvedSpec; + + // fnfErr means target spec is valid but doesn't exist. + // If the end result is fnfErr, we're cleanly resolved. + + if (mSpecDirty) + { + if (mAppendedPath.Length()) + { + err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_FALSE, &resolvedSpec); + if (err == noErr) + mAppendedPath.Truncate(0); + } + else + err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &resolvedSpec); + if (err == noErr) + { + mSpec = resolvedSpec; + mSpecDirty = PR_FALSE; + } + mFollowLinksDirty = PR_TRUE; + } + if (mFollowLinksDirty && (err == noErr)) + { + if (mFollowLinks) + { + // Resolve the alias to the original file. + resolvedSpec = mSpec; + Boolean resolvedWasFolder, resolvedWasAlias; + err = ::ResolveAliasFile(&resolvedSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); + if (err == noErr || err == fnfErr) { + err = noErr; + mTargetSpec = resolvedSpec; + mFollowLinksDirty = PR_FALSE; + } + } + else + { + mTargetSpec = mSpec; + mFollowLinksDirty = PR_FALSE; + } + mCatInfoDirty = PR_TRUE; + } + + return (MacErrorMapper(err)); +} + + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + // The incoming path must be a FULL path + + if (filePath.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + MakeDirty(); + + // If it starts with a colon, it's invalid + if (filePath.First() == ':') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + nsPathParser parser(filePath); + OSErr err; + Str255 pascalNode; + FSSpec nodeSpec; + + const char *root = parser.First(); + if (root == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // The first component must be an existing volume + myPLstrcpy(pascalNode, root); + pascalNode[++pascalNode[0]] = ':'; + err = ::FSMakeFSSpec(0, 0, pascalNode, &nodeSpec); + if (err) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // Build as much of a spec as possible from the rest of the path + // What doesn't exist will be left over in mAppendedPath + const char *nextNode; + while ((nextNode = parser.Next()) != nsnull) { + long dirID; + Boolean isDir; + err = ::FSpGetDirectoryID(&nodeSpec, &dirID, &isDir); + if (err || !isDir) + break; + myPLstrcpy(pascalNode, nextNode); + err = ::FSMakeFSSpec(nodeSpec.vRefNum, dirID, pascalNode, &nodeSpec); + if (err == fnfErr) + break; + } + mSpec = nodeSpec; + mAppendedPath = parser.Remainder(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(filePath, fsStr))) + rv = InitWithNativePath(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + nsLocalFile *asLocalFile = dynamic_cast(aFile); + if (!asLocalFile) + return NS_ERROR_NO_INTERFACE; // Well, sort of. + *this = *asLocalFile; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ +// Macintosh doesn't really have mode bits, just drop them +#pragma unused (mode) + + NS_ENSURE_ARG(_retval); + + nsresult rv = NS_OK; + FSSpec spec; + OSErr err = noErr; + + rv = ResolveAndStat(); + if (rv == NS_ERROR_FILE_NOT_FOUND && (flags & PR_CREATE_FILE)) + rv = NS_OK; + + if (flags & PR_CREATE_FILE) { + rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); + /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ + if ((flags & PR_EXCL) && (rv == NS_ERROR_FILE_ALREADY_EXISTS)) + return rv; + } + + rv = GetFSSpec(&spec); + if (NS_FAILED(rv)) + return rv; + + SInt8 perm; + if (flags & PR_RDWR) + perm = fsRdWrPerm; + else if (flags & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + + short refnum; + err = ::FSpOpenDF(&spec, perm, &refnum); + + if (err == noErr && (flags & PR_TRUNCATE)) + err = ::SetEOF(refnum, 0); + if (err == noErr && (flags & PR_APPEND)) + err = ::SetFPos(refnum, fsFromLEOF, 0); + if (err != noErr) + return MacErrorMapper(err); + + if ((*_retval = PR_ImportFile(refnum)) == 0) + return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,(PR_GetError() & 0xFFFF)); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + NS_ENSURE_ARG(mode); + NS_ENSURE_ARG_POINTER(_retval); + + nsresult rv; + FSSpec spec; + + rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + if (mode[0] == 'w' || mode[0] == 'a') // Create if it doesn't exist + { + if (rv == NS_ERROR_FILE_NOT_FOUND) { + mType = (mode[1] == 'b') ? 'BiNA' : 'TEXT'; + rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); + if (NS_FAILED(rv)) + return rv; + } + } + + rv = GetFSSpec(&spec); + if (NS_FAILED(rv)) + return rv; + +#ifdef MACOSX + // FSp_fopen() doesn't exist under macosx :-( + nsXPIDLCString ourPath; + rv = GetPath(getter_Copies(ourPath)); + if (NS_FAILED(rv)) + return rv; + *_retval = fopen(ourPath, mode); +#else + *_retval = FSp_fopen(&spec, mode); +#endif + + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + OSErr err; + + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + FSSpec newSpec; + + if (mAppendedPath.Length()) + { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec + err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_TRUE, &newSpec); + } + else + { + err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &newSpec); + } + + if (err != noErr && err != fnfErr) + return (MacErrorMapper(err)); + + switch (type) + { + case NORMAL_FILE_TYPE: + SetOSTypeAndCreatorFromExtension(); + err = ::FSpCreate(&newSpec, mCreator, mType, smCurrentScript); + break; + + case DIRECTORY_TYPE: + { + long newDirID; + err = ::FSpDirCreate(&newSpec, smCurrentScript, &newDirID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + break; + + default: + return NS_ERROR_FILE_UNKNOWN_TYPE; + break; + } + + if (err == noErr) + { + mSpec = mTargetSpec = newSpec; + mAppendedPath.Truncate(0); + } + + return (MacErrorMapper(err)); +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &aNode) +{ + if (aNode.IsEmpty()) + return NS_OK; + + nsACString::const_iterator start, end; + aNode.BeginReading(start); + aNode.EndReading(end); + if (FindCharInReadable(':', start, end)) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + MakeDirty(); + + char truncBuffer[32]; + const char *node = NS_TruncNodeName(PromiseFlatCString(aNode).get(), truncBuffer); + + if (!mAppendedPath.Length()) + { + OSErr err; + Boolean resolvedWasFolder, resolvedWasAlias; + err = ::ResolveAliasFile(&mSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); + if (err == noErr) + { + long dirID; + Boolean isDir; + + if (!resolvedWasFolder) + return NS_ERROR_FILE_NOT_DIRECTORY; + if ((err = ::FSpGetDirectoryID(&mSpec, &dirID, &isDir)) != noErr) + return MacErrorMapper(err); + + FSSpec childSpec; + Str255 pascalNode; + myPLstrcpy(pascalNode, node); + err = ::FSMakeFSSpec(mSpec.vRefNum, dirID, pascalNode, &childSpec); + if (err && err != fnfErr) + return MacErrorMapper(err); + mSpec = childSpec; + } + else if (err == fnfErr) + mAppendedPath.Assign(node); + else + return MacErrorMapper(err); + } + else + { + if (mAppendedPath.First() != ':') + mAppendedPath.Insert(':', 0); + mAppendedPath.Append(":"); + mAppendedPath.Append(node); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Append(const nsAString &node) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(node, fsStr))) + rv = AppendNative(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &relPath) +{ + if (relPath.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsresult rv; + nsPathParser parser(relPath); + const char* node = parser.First(); + + while (node) + { + if (NS_FAILED(rv = AppendNative(nsDependentCString(node)))) + return rv; + node = parser.Next(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativePath(const nsAString &relPath) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(relPath, fsStr))) + rv = AppendRelativeNativePath(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + // See if we've had a path appended + if (mAppendedPath.Length()) + { + const char* temp = mAppendedPath.get(); + if (temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = strrchr(temp, ':'); + + // if the working path is just a node without any directory delimeters. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName = leaf; + } + else + { + // We don't have an appended path so grab the leaf name from the FSSpec + // Convert the Pascal string to a C string + PRInt32 len = mSpec.name[0]; + char* leafName = (char *)malloc(len + 1); + if (!leafName) return NS_ERROR_OUT_OF_MEMORY; + ::BlockMoveData(&mSpec.name[1], leafName, len); + leafName[len] = '\0'; + aLeafName = leafName; + free(leafName); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativeLeafName(fsStr))) + rv = NS_CopyNativeToUnicode(fsStr, aLeafName); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + if (aLeafName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + MakeDirty(); + + char truncBuffer[32]; + const char *leafName = NS_TruncNodeName(PromiseFlatCString(aLeafName).get(), truncBuffer); + + if (mAppendedPath.Length()) + { // Lop off the end of the appended path and replace it with the new leaf name + PRInt32 offset = mAppendedPath.RFindChar(':'); + if (offset || ((!offset) && (1 < mAppendedPath.Length()))) + { + mAppendedPath.Truncate(offset + 1); + } + mAppendedPath.Append(leafName); + } + else + { + // We don't have an appended path so directly modify the FSSpec + myPLstrcpy(mSpec.name, leafName); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(aLeafName, fsStr))) + rv = SetNativeLeafName(fsStr); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval.Truncate(); + + nsCAutoString fsCharSetPathStr; + +#if TARGET_CARBON + if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... + { + OSErr err; + nsresult rv; + nsAutoString ucPathString; + + if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) + return MacErrorMapper(err); + rv = NS_CopyUnicodeToNative(ucPathString, fsCharSetPathStr); + if (NS_FAILED(rv)) + return rv; + } + else +#endif + { + // Now would be a good time to call the code that makes an FSSpec into a path + short fullPathLen; + Handle fullPathHandle; + (void)::FSpGetFullPath(&mSpec, &fullPathLen, &fullPathHandle); + if (!fullPathHandle) + return NS_ERROR_OUT_OF_MEMORY; + + ::HLock(fullPathHandle); + fsCharSetPathStr.Assign(*fullPathHandle, fullPathLen); + ::DisposeHandle(fullPathHandle); + } + + // We need to make sure that even if we have a path to a + // directory we don't return the trailing colon. It breaks + // the component manager. (Bugzilla bug #26102) + if (fsCharSetPathStr.Last() == ':') + fsCharSetPathStr.Truncate(fsCharSetPathStr.Length() - 1); + + // Now, tack on mAppendedPath. It never ends in a colon. + if (mAppendedPath.Length()) + { + if (mAppendedPath.First() != ':') + fsCharSetPathStr.Append(":"); + fsCharSetPathStr.Append(mAppendedPath); + } + + _retval = fsCharSetPathStr; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPath(nsAString &_retval) +{ + nsresult rv = NS_OK; + +#if TARGET_CARBON + if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... + { + OSErr err; + nsAutoString ucPathString; + + if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) + return MacErrorMapper(err); + + // We need to make sure that even if we have a path to a + // directory we don't return the trailing colon. It breaks + // the component manager. (Bugzilla bug #26102) + if (ucPathString.Last() == PRUnichar(':')) + ucPathString.Truncate(ucPathString.Length() - 1); + + // Now, tack on mAppendedPath. It never ends in a colon. + if (mAppendedPath.Length()) + { + nsAutoString ucAppendage; + if (mAppendedPath.First() != ':') + ucPathString.Append(PRUnichar(':')); + rv = NS_CopyNativeToUnicode(mAppendedPath, ucAppendage); + if (NS_FAILED(rv)) + return rv; + ucPathString.Append(ucAppendage); + } + + _retval = ucPathString; + } + else +#endif + { + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativePath(fsStr))) { + rv = NS_CopyNativeToUnicode(fsStr, _retval); + } + } + return rv; +} + +nsresult nsLocalFile::MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ) +{ + OSErr macErr; + FSSpec srcSpec; + Str255 newPascalName; + nsresult rv; + + StFollowLinksState srcFollowState(this, followLinks); + rv = GetFSSpec(&srcSpec); + if ( NS_FAILED( rv ) ) + return rv; + + // If newParentDir == nsnull, it's a simple rename + if ( !newParentDir ) + { + myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255 ); + macErr = ::FSpRename( &srcSpec, newPascalName ); + return MacErrorMapper( macErr ); + } + + nsCOMPtr destDir(do_QueryInterface( newParentDir )); + StFollowLinksState destFollowState(destDir, followLinks); + FSSpec destSpec; + rv = destDir->GetFSSpec(&destSpec); + if ( NS_FAILED( rv ) ) + return rv; + + long dirID; + Boolean isDirectory; + macErr = ::FSpGetDirectoryID(&destSpec, &dirID, &isDirectory); + if ( macErr || !isDirectory ) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + if ( !newName.IsEmpty() ) + myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255); + else + memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1); + if ( isCopy ) + { + macErr = ::FSpGetDirectoryID(&srcSpec, &dirID, &isDirectory); + if (macErr == noErr) + { + const PRInt32 kCopyBufferSize = (1024 * 512); // allocate our own buffer to speed file copies. Bug #103202 + OSErr tempErr; + Handle copyBufferHand = ::TempNewHandle(kCopyBufferSize, &tempErr); + void* copyBuffer = nsnull; + PRInt32 copyBufferSize = 0; + + // it's OK if the allocated failed; FSpFileCopy will just fall back on its own internal 16k buffer + if (copyBufferHand) + { + ::HLock(copyBufferHand); + copyBuffer = *copyBufferHand; + copyBufferSize = kCopyBufferSize; + } + + if ( isDirectory ) + macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true, NULL ); + else + macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true ); + + if (copyBufferHand) + ::DisposeHandle(copyBufferHand); + } + } + else + { + macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName); + if ( macErr == diffVolErr) + { + // On a different Volume so go for Copy and then delete + rv = CopyToNative( newParentDir, newName ); + if ( NS_FAILED ( rv ) ) + return rv; + return Remove( PR_TRUE ); + } + } + return MacErrorMapper( macErr ); +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE ); +} + +NS_IMETHODIMP +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = CopyToNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE ); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = CopyToFollowingLinksNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE ); +} + +NS_IMETHODIMP +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsresult rv; + nsCAutoString fsStr; + if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) + rv = MoveToNative(newParentDir, fsStr); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + +#if !TARGET_CARBON + // This call to SystemTask is here to give the OS time to grow its + // FCB (file control block) list, which it seems to be unable to + // do unless we yield some time to the OS. See bugs 64978 & 70543 + // for the whole story. + ::SystemTask(); +#endif + + // Use the new PR_LoadLibraryWithFlags which allows us to use a FSSpec + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_MacIndexedFragment; + libSpec.value.mac_indexed_fragment.fsspec = &mTargetSpec; + libSpec.value.mac_indexed_fragment.index = 0; + *_retval = PR_LoadLibraryWithFlags(libSpec, 0); + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER("PR_LoadLibrary"); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + OSErr err; + nsresult rv; + FSSpec specToDelete; + PRBool isDir; + + StFollowLinksState(this, PR_FALSE); + + rv = IsDirectory(&isDir); // Calls ResolveAndStat() + if (NS_FAILED(rv)) + return rv; + rv = GetFSSpec(&specToDelete); + if (NS_FAILED(rv)) + return rv; + + if (isDir && recursive) + err = ::DeleteDirectory( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); + else + err = ::HDelete( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); + + return MacErrorMapper( err ); +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + *aLastModifiedTime = 0; + + nsresult rv = ResolveAndStat(); + if ( NS_FAILED( rv ) ) + return rv; + rv = UpdateCachedCatInfo(PR_TRUE); + if ( NS_FAILED( rv ) ) + return rv; + + // The mod date is in the same spot for files and dirs. + return ConvertMacTimeToMilliseconds( aLastModifiedTime, mCachedCatInfo.hFileInfo.ioFlMdDat ); +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + nsresult rv = ResolveAndStat(); + if ( NS_FAILED(rv) ) + return rv; + + PRUint32 macTime = 0; + OSErr err = noErr; + + ConvertMillisecondsToMacTime(aLastModifiedTime, &macTime); + + if (NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) + { + if (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) + { + mCachedCatInfo.dirInfo.ioDrMdDat = macTime; + mCachedCatInfo.dirInfo.ioDrParID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; + } + else + { + mCachedCatInfo.hFileInfo.ioFlMdDat = macTime; + mCachedCatInfo.hFileInfo.ioDirID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; + } + + err = ::PBSetCatInfoSync(&mCachedCatInfo); + if (err != noErr) + return MacErrorMapper(err); + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + nsresult rv; + PRBool isLink; + + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + if (!isLink) + return NS_ERROR_FAILURE; + + StFollowLinksState followState(this, PR_FALSE); + return GetLastModifiedTime(aLastModifiedTime); +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + nsresult rv; + PRBool isLink; + + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + if (!isLink) + return NS_ERROR_FAILURE; + + StFollowLinksState followState(this, PR_FALSE); + return SetLastModifiedTime(aLastModifiedTime); +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + nsresult rv; + + *aFileSize = LL_Zero(); + + if (NS_SUCCEEDED(rv = ResolveAndStat()) && NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) + { + if (!(mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask)) + { + long dataSize = mCachedCatInfo.hFileInfo.ioFlLgLen; + long resSize = mCachedCatInfo.hFileInfo.ioFlRLgLen; + + // For now we've only got 32 bits of file size info + PRInt64 dataInt64 = LL_Zero(); + PRInt64 resInt64 = LL_Zero(); + + // WARNING!!!!!! + // + // For now we do NOT add the data and resource fork sizes as there are several + // assumptions in the code (notably in form submit) that only the data fork is + // used. + // LL_I2L(resInt64, resSize); + + LL_I2L(dataInt64, dataSize); + + LL_ADD((*aFileSize), dataInt64, resInt64); + } + // leave size at zero for dirs + } + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + short refNum; + OSErr err; + PRInt32 aNewLength; + + LL_L2I(aNewLength, aFileSize); + + // Need to open the file to set the size + if (::FSpOpenDF(&mTargetSpec, fsWrPerm, &refNum) != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + err = ::SetEOF(refNum, aNewLength); + + // Close the file unless we got an error that it was already closed + if (err != fnOpnErr) + (void)::FSClose(refNum); + + if (err != noErr) + return MacErrorMapper(err); + + return MacErrorMapper(err); +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + StFollowLinksState followState(this, PR_FALSE); + return GetFileSize(aFileSize); +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + PRInt64 space64Bits; + + LL_I2L(space64Bits , LONG_MAX); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + XVolumeParam pb; + pb.ioCompletion = nsnull; + pb.ioVolIndex = 0; + pb.ioNamePtr = nsnull; + pb.ioVRefNum = mFollowLinks ? mTargetSpec.vRefNum : mSpec.vRefNum; + + // we should check if this call is available + OSErr err = ::PBXGetVolInfoSync(&pb); + + if (err == noErr) + { + const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); +#ifdef HAVE_LONG_LONG + space64Bits = UnsignedWideToUInt64(freeBytes); +#else + space64Bits.lo = freeBytes.lo; + space64Bits.hi = freeBytes.hi; +#endif + } + + *aDiskSpaceAvailable = space64Bits; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + nsresult rv = NS_OK; + PRInt32 offset; + + nsCOMPtr localFile; + PRInt32 appendedLen = mAppendedPath.Length(); + OSErr err; + + if (!appendedLen || (appendedLen == 1 && mAppendedPath.CharAt(0) == ':')) + { + rv = ResolveAndStat(); + //if the file does not exist, does not mean that the parent does not. + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + CInfoPBRec pBlock = {0}; + FSSpec parentFolderSpec; + parentFolderSpec.name[0] = 0; + + pBlock.dirInfo.ioVRefNum = mSpec.vRefNum; + pBlock.dirInfo.ioDrDirID = mSpec.parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentFolderSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = PBGetCatInfoSync(&pBlock); + if (err != noErr) + return MacErrorMapper(err); + parentFolderSpec.vRefNum = mSpec.vRefNum; + parentFolderSpec.parID = pBlock.dirInfo.ioDrParID; + + localFile = new nsLocalFile; + if (!localFile) + return NS_ERROR_OUT_OF_MEMORY; + rv = localFile->InitWithFSSpec(&parentFolderSpec); + if (NS_FAILED(rv)) + return rv; + } + else + { + // trim off the last component of the appended path + // construct a new file from our spec + trimmed path + + nsCAutoString parentAppendage(mAppendedPath); + + if (parentAppendage.Last() == ':') + parentAppendage.Truncate(appendedLen - 1); + if ((offset = parentAppendage.RFindChar(':')) != -1) + parentAppendage.Truncate(offset); + else + parentAppendage.Truncate(0); + + localFile = new nsLocalFile(mSpec, parentAppendage); + if (!localFile) + return NS_ERROR_OUT_OF_MEMORY; + } + *aParent = localFile; + NS_ADDREF(*aParent); + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(UpdateCachedCatInfo(PR_TRUE))) + *_retval = PR_TRUE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsPackage(PRBool *outIsPackage) +{ + NS_ENSURE_ARG(outIsPackage); + *outIsPackage = PR_FALSE; + + // Note: IsDirectory() calls ResolveAndStat() & UpdateCachedCatInfo + PRBool isDir; + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + + *outIsPackage = ((mCachedCatInfo.dirInfo.ioFlAttrib & kioFlAttribDirMask) && + (mCachedCatInfo.dirInfo.ioDrUsrWds.frFlags & kHasBundle)); + + if ((!*outIsPackage) && isDir) + { + // Believe it or not, folders ending with ".app" are also considered + // to be packages, even if the top-level folder doesn't have bundle set + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) + { + const char *extPtr = strrchr(name.get(), '.'); + if (extPtr) + { + if (!nsCRT::strcasecmp(extPtr, ".app")) + { + *outIsPackage = PR_TRUE; + } + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *outIsWritable) +{ + NS_ENSURE_ARG(outIsWritable); + *outIsWritable = PR_TRUE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_TRUE); + if (NS_FAILED(rv)) return rv; + + *outIsWritable = !(mCachedCatInfo.hFileInfo.ioFlAttrib & kioFlAttribLockedMask); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + // is it ever not readable on Mac? + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *outIsExecutable) +{ + NS_ENSURE_ARG(outIsExecutable); + *outIsExecutable = PR_FALSE; // Assume failure + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + +#if TARGET_CARBON + // If we're running under OS X ask LaunchServices if we're executable + if (sRunningOSX) + { + if ( (UInt32)LSCopyItemInfoForRef != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + LSRequestedInfo theInfoRequest = kLSRequestAllInfo; + LSItemInfoRecord theInfo; + + if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) + { + if (::LSCopyItemInfoForRef(&theRef, theInfoRequest, &theInfo) == noErr) + { + if ((theInfo.flags & kLSItemInfoIsApplication) != 0) + *outIsExecutable = PR_TRUE; + } + } + } + } + else +#endif + { + OSType fileType; + rv = GetFileType(&fileType); + if (NS_FAILED(rv)) return rv; + + *outIsExecutable = (fileType == 'APPL' || fileType == 'appe' || fileType == 'FNDR'); + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *outIsDir) +{ + NS_ENSURE_ARG(outIsDir); + *outIsDir = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *outIsDir = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *outIsFile) +{ + NS_ENSURE_ARG(outIsFile); + *outIsFile = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *outIsFile = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; + + *_retval = (mCachedCatInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) != 0; + + if (sRunningOSX) + { + // on Mac OS X, also follow Unix "convention" where files + // beginning with a period are considered to be hidden + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) + { + if (name.First() == '.') + { + *_retval = PR_TRUE; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + Boolean isAlias, isFolder; + if (::IsAliasFile(&mSpec, &isAlias, &isFolder) == noErr) + *_retval = isAlias; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + // Building paths is expensive. If we can get the FSSpecs of + // both (they or their parents exist) just compare the specs. + nsCOMPtr inMacFile(do_QueryInterface(inFile)); + FSSpec fileSpec, inFileSpec; + if (NS_SUCCEEDED(GetFSSpec(&fileSpec)) && inMacFile && NS_SUCCEEDED(inMacFile->GetFSSpec(&inFileSpec))) + *_retval = IsEqualFSSpec(fileSpec, inFileSpec); + else + { + nsCAutoString filePath; + GetNativePath(filePath); + + nsXPIDLCString inFilePath; + inFile->GetNativePath(inFilePath); + + if (nsCRT::strcasecmp(inFilePath.get(), filePath.get()) == 0) + *_retval = PR_TRUE; + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *outContains) +{ + /* Note here that we make no attempt to deal with the problem + of folder aliases. Doing a 'Contains' test and dealing with + folder aliases is Hard. Think about it. + */ + *outContains = PR_FALSE; + + PRBool isDir; + nsresult rv = IsDirectory(&isDir); // need to cache this + if (NS_FAILED(rv)) return rv; + if (!isDir) return NS_OK; // must be a dir to contain someone + + nsCOMPtr macFile(do_QueryInterface(inFile)); + if (!macFile) return NS_OK; // trying to compare non-local with local file + + FSSpec mySpec = mSpec; + FSSpec compareSpec; + + // NOTE: we're not resolving inFile if it was an alias + StFollowLinksState followState(macFile, PR_FALSE); + rv = macFile->GetFSSpec(&compareSpec); + if (NS_FAILED(rv)) return rv; + + // if they are on different volumes, bail + if (mSpec.vRefNum != compareSpec.vRefNum) + return NS_OK; + + // if recur == true, test every parent, otherwise just test the first one + // (yes, recur does not get set in this loop) + OSErr err = noErr; + do + { + FSSpec parentFolderSpec; + err = GetParentFolderSpec(compareSpec, parentFolderSpec); + if (err != noErr) break; // we reached the top + + if (IsEqualFSSpec(parentFolderSpec, mySpec)) + { + *outContains = PR_TRUE; + break; + } + + compareSpec = parentFolderSpec; + } while (recur); + + return NS_OK; +} + + + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval.Truncate(); + + PRBool symLink; + + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + if (!symLink) + return NS_ERROR_FILE_INVALID_PATH; + + StFollowLinksState followState(this, PR_TRUE); + return GetNativePath(_retval); +} + +NS_IMETHODIMP +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsresult rv; + nsCAutoString fsStr; + + if (NS_SUCCEEDED(rv = GetNativeTarget(fsStr))) { + rv = NS_CopyNativeToUnicode(fsStr, _retval); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + aPersistentDescriptor.Truncate(); + + nsresult rv = ResolveAndStat(); + if ( NS_FAILED( rv ) ) + return rv; + + AliasHandle aliasH; + OSErr err = ::NewAlias(nil, &mTargetSpec, &aliasH); + if (err != noErr) + return MacErrorMapper(err); + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + HLock((Handle) aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); // Passing nsnull for dest makes NULL-term string + ::DisposeHandle((Handle) aliasH); + NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); + + aPersistentDescriptor = buf; + PR_Free(buf); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + if (aPersistentDescriptor.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + nsresult rv = NS_OK; + + PRUint32 dataSize = aPersistentDescriptor.Length(); + char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull); + // Cast to an alias record and resolve. + AliasHandle aliasH = nsnull; + if (::PtrToHand(decodedData, &(Handle)aliasH, (dataSize * 3) / 4) != noErr) + rv = NS_ERROR_OUT_OF_MEMORY; + PR_Free(decodedData); + NS_ENSURE_SUCCESS(rv, rv); + + Boolean changed; + FSSpec resolvedSpec; + OSErr err; + err = ::ResolveAlias(nsnull, aliasH, &resolvedSpec, &changed); + if (err == fnfErr) // resolvedSpec is valid in this case + err = noErr; + rv = MacErrorMapper(err); + DisposeHandle((Handle) aliasH); + NS_ENSURE_SUCCESS(rv, rv); + + return InitWithFSSpec(&resolvedSpec); +} + +#pragma mark - + +// a stack-based, exception safe class for an AEDesc + +#pragma mark +class StAEDesc: public AEDesc +{ +public: + StAEDesc() + { + descriptorType = typeNull; + dataHandle = nil; + } + + ~StAEDesc() + { + ::AEDisposeDesc(this); + } + + void Clear() + { + ::AEDisposeDesc(this); + descriptorType = typeNull; + dataHandle = nil; + } + +private: + // disallow copies and assigns + StAEDesc(const StAEDesc& rhs); // copy constructor + StAEDesc& operator= (const StAEDesc&rhs); // throws OSErrs + +}; + +#pragma mark - +#pragma mark [Utility methods] + + +nsresult nsLocalFile::UpdateCachedCatInfo(PRBool forceUpdate) +{ + if (!mCatInfoDirty && !forceUpdate) + return NS_OK; + + FSSpec spectoUse = mFollowLinks ? mTargetSpec : mSpec; + mCachedCatInfo.hFileInfo.ioCompletion = nsnull; + mCachedCatInfo.hFileInfo.ioFDirIndex = 0; // use dirID and name + mCachedCatInfo.hFileInfo.ioVRefNum = spectoUse.vRefNum; + mCachedCatInfo.hFileInfo.ioDirID = spectoUse.parID; + mCachedCatInfo.hFileInfo.ioNamePtr = spectoUse.name; + + OSErr err = ::PBGetCatInfoSync(&mCachedCatInfo); + if (err == noErr) + { + mCatInfoDirty = PR_FALSE; + return NS_OK; + } + return MacErrorMapper(err); +} + + +nsresult nsLocalFile::FindRunningAppBySignature (OSType aAppSig, FSSpec& outSpec, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + FSSpec tempFSSpec; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) break; + if (err != noErr) return NS_ERROR_FAILURE; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = &tempFSSpec; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) return NS_ERROR_FAILURE; + + if (info.processSignature == aAppSig) + { + outSpec = tempFSSpec; + return NS_OK; + } + } + + return NS_ERROR_FILE_NOT_FOUND; // really process not found +} + + +nsresult nsLocalFile::FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + FSSpec tempFSSpec; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) break; + if (err != noErr) return NS_ERROR_FAILURE; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = &tempFSSpec; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) return NS_ERROR_FAILURE; + + if (IsEqualFSSpec(appSpec, *info.processAppSpec)) + { + return NS_OK; + } + } + + return NS_ERROR_FILE_NOT_FOUND; // really process not found +} + + +nsresult nsLocalFile::FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec) +{ + OSErr err; + + // get the system volume + long systemFolderDirID; + short sysVRefNum; + err = FindFolder(kOnSystemDisk, kSystemFolderType, false, &sysVRefNum, &systemFolderDirID); + if (err != noErr) return NS_ERROR_FAILURE; + + short vRefNum = sysVRefNum; + short index = 0; + + while (true) + { + if (index == 0 || vRefNum != sysVRefNum) + { + // should we avoid AppleShare volumes? + + Boolean hasDesktopDB; + err = VolHasDesktopDB(vRefNum, &hasDesktopDB); + if (err != noErr) return err; + if (hasDesktopDB) + { + err = FindAppOnVolume(sig, vRefNum, &outSpec); + if (err != afpItemNotFound) return err; + } + } + index++; + err = GetIndVolume(index, &vRefNum); + if (err == nsvErr) return fnfErr; + if (err != noErr) return err; + } + + return NS_OK; +} + +#define aeSelectionKeyword 'fsel' +#define kAEOpenSelection 'sope' +#define kAERevealSelection 'srev' +#define kFinderType 'FNDR' + +NS_IMETHODIMP nsLocalFile::Launch() +{ + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + FSSpec dirSpec, appSpec; + AliasHandle DirAlias, FileAlias; + OSErr errorResult = noErr; + ProcessSerialNumber process; + + // for launching a file, we'll use mTargetSpec (which is both a resolved spec and a resolved alias) + ResolveAndStat(); + +#if TARGET_CARBON + if (sRunningOSX) + { // We're running under Mac OS X, LaunchServices here we come + + // First we make sure the LaunchServices routine we want is implemented + if ( (UInt32)LSOpenFSRef != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) + { + (void)::LSOpenFSRef(&theRef, NULL); + } + } + } + else +#endif + { // We're running under Mac OS 8.x/9.x, use the Finder Luke + nsresult rv = FindRunningAppBySignature ('MACS', appSpec, process); + if (NS_SUCCEEDED(rv)) + { + errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (errorResult == noErr) + { + /* Create the FinderEvent */ + errorResult = AECreateAppleEvent(kFinderType, kAEOpenSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + if (errorResult == noErr) + { + errorResult = FSMakeFSSpec(mTargetSpec.vRefNum, mTargetSpec.parID, nil, &dirSpec); + NewAlias(nil, &dirSpec, &DirAlias); + /* Create alias for file */ + NewAlias(nil, &mTargetSpec, &FileAlias); + + /* Create the file list */ + errorResult = AECreateList(nil, 0, false, &fileList); + /* create the folder descriptor */ + HLock((Handle)DirAlias); + errorResult = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc); + HUnlock((Handle)DirAlias); + if (errorResult == noErr) + { + errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDirDesc); + if ( errorResult == noErr) + { + /* create the file descriptor and add to aliasList */ + HLock((Handle)FileAlias); + errorResult = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem); + HLock((Handle)FileAlias); + if (errorResult == noErr) + { + errorResult = AEPutDesc(&fileList, 0, &listElem); + if (errorResult == noErr) + { + /* Add the file alias list to the event */ + errorResult = AEPutParamDesc(&aeEvent, aeSelectionKeyword, &fileList); + if (errorResult == noErr) + AESend(&aeEvent, &aeReply, kAEWaitReply + kAENeverInteract + + kAECanSwitchLayer, kAEHighPriority, kAEDefaultTimeout, nil, nil); + } + } + } + } + } + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::Reveal() +{ + FSSpec specToReveal; + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + OSErr errorResult = noErr; + ProcessSerialNumber process; + FSSpec appSpec; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + rv = GetFSSpec(&specToReveal); // Pay attention to followLinks + if (NS_FAILED(rv)) + return rv; + + rv = FindRunningAppBySignature ('MACS', appSpec, process); + if (NS_SUCCEEDED(rv)) + { + errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (errorResult == noErr) + { + /* Create the FinderEvent */ +#if TARGET_CARBON + // The Finder under OS X uses a different event to reveal + if (sRunningOSX) + errorResult = AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + else +#endif + errorResult = AECreateAppleEvent(kFinderType, kAERevealSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, + &aeEvent); + if (errorResult == noErr) + { + /* Create the file list */ + errorResult = AECreateList(nil, 0, false, &fileList); + if (errorResult == noErr) + { + errorResult = AEPutPtr(&fileList, 0, typeFSS, &specToReveal, sizeof(FSSpec)); + + if (errorResult == noErr) + { +#if TARGET_CARBON + // When we're sending the event under OS X the FSSpec must be a keyDirectObject + if (sRunningOSX) + errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &fileList); + else +#endif + errorResult = AEPutParamDesc(&aeEvent,keySelection, &fileList); + + if (errorResult == noErr) + { + errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); + if (errorResult == noErr) + SetFrontProcess(&process); + } + } + } + } + } + } + + return NS_OK; +} + +nsresult nsLocalFile::MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground) +{ + ProcessSerialNumber thePSN = {0}; + StAEDesc target; + StAEDesc docDesc; + StAEDesc launchDesc; + StAEDesc docList; + AppleEvent theEvent = {0, nil}; + AppleEvent theReply = {0, nil}; + OSErr err = noErr; + Boolean autoParamValue = false; + Boolean running = false; + nsresult rv = NS_OK; + +#if TARGET_CARBON + if (sRunningOSX) + { // Under Mac OS X we'll use LaunchServices + + // First we make sure the LaunchServices routine we want is implemented + if ( (UInt32)LSOpenFromRefSpec != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef appRef; + FSRef docRef; + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (::FSpMakeFSRef(&appSpec, &appRef) != noErr) + return NS_ERROR_FAILURE; + + if (aDocToLoad) + if (::FSpMakeFSRef(aDocToLoad, &docRef) != noErr) + return NS_ERROR_FAILURE; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appRef; + if (aDocToLoad) + { + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docRef; + } + thelaunchSpec.launchFlags = theLaunchFlags; + + err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + NS_ASSERTION((err != noErr), "Error calling LSOpenFromRefSpec"); + if (err != noErr) return NS_ERROR_FAILURE; + } + } + else +#endif + { // The old fashioned way for Mac OS 8.x/9.x + rv = FindRunningAppByFSSpec(appSpec, thePSN); + running = NS_SUCCEEDED(rv); + + err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AECreateAppleEvent(kCoreEventClass, aDocToLoad ? kAEOpenDocuments : kAEOpenApplication, &target, + kAutoGenerateReturnID, kAnyTransactionID, &theEvent); + if (err != noErr) return NS_ERROR_FAILURE; + + if (aDocToLoad) + { + err = AECreateList(nil, 0, false, &docList); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AECreateDesc(typeFSS, aDocToLoad, sizeof(FSSpec), &docDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AEPutDesc(&docList, 0, &docDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + err = AEPutParamDesc(&theEvent, keyDirectObject, &docList); + if (err != noErr) return NS_ERROR_FAILURE; + } + + if (running) + { + err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut, nil, nil); + if (err != noErr) return NS_ERROR_FAILURE; + + if (!aLaunchInBackground) + { + err = ::SetFrontProcess(&thePSN); + if (err != noErr) return NS_ERROR_FAILURE; + } + } + else + { + LaunchParamBlockRec launchThis = {0}; + PRUint16 launchControlFlags = (launchContinue | launchNoFileFlags); + if (aLaunchInBackground) + launchControlFlags |= launchDontSwitch; + + err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc); + if (err != noErr) return NS_ERROR_FAILURE; + + launchThis.launchAppSpec = (FSSpecPtr)&appSpec; +#if TARGET_CARBON && ACCESSOR_CALLS_ARE_FUNCTIONS + ::AEGetDescData(&launchDesc, &launchThis.launchAppParameters, sizeof(launchThis.launchAppParameters)); +#else + // no need to lock this handle. + launchThis.launchAppParameters = (AppParametersPtr) *(launchDesc.dataHandle); +#endif + launchThis.launchBlockID = extendedBlock; + launchThis.launchEPBLength = extendedBlockLen; + launchThis.launchFileFlags = 0; + launchThis.launchControlFlags = launchControlFlags; + err = ::LaunchApplication(&launchThis); + if (err != noErr) return NS_ERROR_FAILURE; + + // let's be nice and wait until it's running + const PRUint32 kMaxTimeToWait = 60; // wait 1 sec max + PRUint32 endTicks = ::TickCount() + kMaxTimeToWait; + + PRBool foundApp = PR_FALSE; + + do + { + EventRecord theEvent; + (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL); + + ProcessSerialNumber psn; + foundApp = NS_SUCCEEDED(FindRunningAppByFSSpec(appSpec, psn)); + + } while (!foundApp && (::TickCount() <= endTicks)); + + NS_ASSERTION(foundApp, "Failed to find app after launching it"); + } + + if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent); + if (theReply.dataHandle != nil) AEDisposeDesc(&theReply); + } + + return NS_OK; +} + + +#pragma mark - +#pragma mark [Methods that will not be implemented on Mac] + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +#pragma mark - +#pragma mark [nsILocalFileMac] +// Implementation of Mac specific finctions from nsILocalFileMac + + +NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG(aCFURL); + + // CFURLGetFSRef can only succeed if the entire path exists. + FSRef fsRef; + if (::CFURLGetFSRef(aCFURL, &fsRef) == PR_TRUE) + rv = InitWithFSRef(&fsRef); + else + { + CFURLRef parentURL = ::CFURLCreateCopyDeletingLastPathComponent(NULL, aCFURL); + if (!parentURL) + return NS_ERROR_FAILURE; + + // Get the FSRef from the parent and the FSSpec from that + FSRef parentFSRef; + FSSpec parentFSSpec; + if ((::CFURLGetFSRef(parentURL, &parentFSRef) == PR_TRUE) && + (::FSGetCatalogInfo(&parentFSRef, kFSCatInfoNone, + nsnull, nsnull, &parentFSSpec, nsnull) == noErr)) + { + // Get the leaf name of the file and turn it into a string HFS can use. + CFStringRef fileNameRef = ::CFURLCopyLastPathComponent(aCFURL); + if (fileNameRef) + { + TextEncoding theEncoding; + if (::UpgradeScriptInfoToTextEncoding(smSystemScript, + kTextLanguageDontCare, + kTextRegionDontCare, + NULL, + &theEncoding) != noErr) + theEncoding = kTextEncodingMacRoman; + + char origName[256]; + char truncBuf[32]; + if (::CFStringGetCString(fileNameRef, origName, sizeof(origName), theEncoding)) + { + MakeDirty(); + mSpec = parentFSSpec; + mAppendedPath = NS_TruncNodeName(origName, truncBuf); + rv = NS_OK; + } + ::CFRelease(fileNameRef); + } + } + ::CFRelease(parentURL); + } +#endif + + return rv; +} + + +NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef * aFSRef) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG(aFSRef); + + FSSpec fsSpec; + OSErr err = ::FSGetCatalogInfo(aFSRef, kFSCatInfoNone, nsnull, + nsnull, &fsSpec, nsnull); + if (err == noErr) + rv = InitWithFSSpec(&fsSpec); + else + rv = MacErrorMapper(err); +#endif + + return rv; +} + + +NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *fileSpec) +{ + MakeDirty(); + mSpec = *fileSpec; + mTargetSpec = *fileSpec; + mAppendedPath = ""; + return NS_OK; +} + + +NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) +{ + FSSpec appSpec; + ProcessSerialNumber psn; + +#if TARGET_CARBON + if (sRunningOSX) + { // If we're running under OS X use LaunchServices to determine the app + // corresponding to the creator code + if ( (UInt32)LSFindApplicationForInfo != (UInt32)kUnresolvedCFragSymbolAddress ) + { + FSRef theRef; + if (::LSFindApplicationForInfo(aAppCreator, NULL, NULL, &theRef, NULL) == noErr) + { + FSCatalogInfoBitmap whichInfo = kFSCatInfoNone; + + if (::FSGetCatalogInfo(&theRef, whichInfo, NULL, NULL, &appSpec, NULL) == noErr) + return InitWithFSSpec(&appSpec); + } + + // If we get here we didn't find an app + return NS_ERROR_FILE_NOT_FOUND; + } + } +#endif + + // is the app running? + nsresult rv = FindRunningAppBySignature(aAppCreator, appSpec, psn); + if (rv == NS_ERROR_FILE_NOT_FOUND) + { + // we have to look on disk + rv = FindAppOnLocalVolumes(aAppCreator, appSpec); + if (NS_FAILED(rv)) return rv; + } + else if (NS_FAILED(rv)) + return rv; + + // init with the spec here + return InitWithFSSpec(&appSpec); +} + +NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG_POINTER(_retval); + *_retval = nsnull; + + PRBool exists; + if (NS_SUCCEEDED(Exists(&exists)) && exists) + { + FSRef fsRef; + FSSpec fsSpec = mFollowLinks ? mTargetSpec : mSpec; + if (::FSpMakeFSRef(&fsSpec, &fsRef) == noErr) + { + *_retval = ::CFURLCreateFromFSRef(NULL, &fsRef); + if (*_retval) + return NS_OK; + } + } + else + { + nsCAutoString tempPath; + if (NS_SUCCEEDED(GetNativePath(tempPath))) + { + CFStringRef pathStrRef = ::CFStringCreateWithCString(NULL, tempPath.get(), kCFStringEncodingMacRoman); + if (!pathStrRef) + return NS_ERROR_FAILURE; + *_retval = ::CFURLCreateWithFileSystemPath(NULL, pathStrRef, kCFURLHFSPathStyle, false); + ::CFRelease(pathStrRef); + if (*_retval) + return NS_OK; + } + } +#endif + + return rv; +} + +NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) +{ + nsresult rv = NS_ERROR_FAILURE; + +#if TARGET_CARBON + NS_ENSURE_ARG_POINTER(_retval); + + FSSpec fsSpec; + rv = GetFSSpec(&fsSpec); + if (NS_SUCCEEDED(rv)) + rv = MacErrorMapper(::FSpMakeFSRef(&fsSpec, _retval)); +#endif + + return rv; +} + +NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *fileSpec) +{ + NS_ENSURE_ARG(fileSpec); + nsresult rv = ResolveAndStat(); + if (rv == NS_ERROR_FILE_NOT_FOUND) + rv = NS_OK; + if (NS_SUCCEEDED(rv)) + *fileSpec = mFollowLinks ? mTargetSpec : mSpec; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) +{ + NS_ENSURE_ARG(aFileType); + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + { + *aFileType = mType; + return NS_ERROR_FILE_NOT_FOUND; + } + + *aFileType = info.fdType; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) +{ + mType = aFileType; + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_NOT_FOUND; + + info.fdType = aFileType; + err = ::FSpSetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aCreator) +{ + NS_ENSURE_ARG(aCreator); + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + { + *aCreator = mCreator; + return NS_ERROR_FILE_NOT_FOUND; + } + + *aCreator = info.fdCreator; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aCreator) +{ + if (aCreator == CURRENT_PROCESS_CREATOR) + aCreator = sCurrentProcessSignature; + + mCreator = aCreator; + + FSSpec fileSpec; + (void)GetFSSpec(&fileSpec); + + FInfo info; + OSErr err = ::FSpGetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_NOT_FOUND; + + info.fdCreator = aCreator; + err = ::FSpSetFInfo(&fileSpec, &info); + if (err != noErr) + return NS_ERROR_FILE_ACCESS_DENIED; + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) +{ + NS_ENSURE_ARG(aExtension); + return SetOSTypeAndCreatorFromExtension(aExtension); +} + +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) +{ + NS_ENSURE_ARG(aMIMEType); + + nsresult rv; + nsCOMPtr icService(do_GetService + (NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv)); + + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mimeInfo; + PRUint32 fileType = 'TEXT'; + PRUint32 fileCreator = nsILocalFileMac::CURRENT_PROCESS_CREATOR; + + rv = icService->FillInMIMEInfo(aMIMEType, + nsnull, getter_AddRefs(mimeInfo)); + if (NS_SUCCEEDED(rv)) + rv = mimeInfo->GetMacType(&fileType); + if (NS_SUCCEEDED(rv)) + rv = mimeInfo->GetMacCreator(&fileCreator); + if (NS_SUCCEEDED(rv)) + rv = SetFileType(fileType); + if (NS_SUCCEEDED(rv)) + rv = SetFileCreator(fileCreator); + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + *aFileSize = LL_Zero(); + + ResolveAndStat(); + + long dataSize = 0; + long resSize = 0; + + OSErr err = FSpGetFileSize(&mTargetSpec, &dataSize, &resSize); + + if (err != noErr) + return MacErrorMapper(err); + + // For now we've only got 32 bits of file size info + PRInt64 dataInt64 = LL_Zero(); + PRInt64 resInt64 = LL_Zero(); + + // Combine the size of the resource and data forks + LL_I2L(resInt64, resSize); + LL_I2L(dataInt64, dataSize); + LL_ADD((*aFileSize), dataInt64, resInt64); + + return NS_OK; +} + + +// this nsLocalFile points to the app. We want to launch it, optionally with the document. +NS_IMETHODIMP +nsLocalFile::LaunchWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground) +{ + // are we launchable? + PRBool isExecutable; + nsresult rv = IsExecutable(&isExecutable); + if (NS_FAILED(rv)) return rv; + if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; + + FSSpec docSpec; + FSSpecPtr docSpecPtr = nsnull; + + nsCOMPtr macDoc = do_QueryInterface(aDocToLoad); + if (macDoc) + { + rv = macDoc->GetFSSpec(&docSpec); // XXX GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + + docSpecPtr = &docSpec; + } + + FSSpec appSpec; + rv = GetFSSpec(&appSpec); // XXX GetResolvedFSSpec + if (NS_FAILED(rv)) return rv; + + rv = MyLaunchAppWithDoc(appSpec, docSpecPtr, aLaunchInBackground); + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::OpenDocWithApp(nsILocalFile* aAppToOpenWith, PRBool aLaunchInBackground) +{ + // if aAppToOpenWith is nil, we have to find the app from the creator code + // of the document + nsresult rv = NS_OK; + + FSSpec appSpec; + + if (aAppToOpenWith) + { + nsCOMPtr appFileMac = do_QueryInterface(aAppToOpenWith, &rv); + if (!appFileMac) return rv; + + rv = appFileMac->GetFSSpec(&appSpec); // XXX GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + + // is it launchable? + PRBool isExecutable; + rv = aAppToOpenWith->IsExecutable(&isExecutable); + if (NS_FAILED(rv)) return rv; + if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; + } + else + { + // look for one + OSType fileCreator; + rv = GetFileCreator(&fileCreator); + if (NS_FAILED(rv)) return rv; + + // just make one on the stack + nsLocalFile localAppFile; + rv = localAppFile.InitToAppWithCreatorCode(fileCreator); + if (NS_FAILED(rv)) return rv; + + rv = localAppFile.GetFSSpec(&appSpec); // GetTargetFSSpec + if (NS_FAILED(rv)) return rv; + } + + FSSpec docSpec; + rv = GetFSSpec(&docSpec); // XXX GetResolvedFSSpec + if (NS_FAILED(rv)) return rv; + + rv = MyLaunchAppWithDoc(appSpec, &docSpec, aLaunchInBackground); + return rv; +} + +nsresult nsLocalFile::SetOSTypeAndCreatorFromExtension(const char* extension) +{ + nsresult rv; + + nsCAutoString localExtBuf; + const char *extPtr; + + if (!extension) + { + rv = GetNativeLeafName(localExtBuf); + extPtr = strrchr(localExtBuf.get(), '.'); + if (!extPtr) + return NS_ERROR_FAILURE; + ++extPtr; + } + else + { + extPtr = extension; + if (*extPtr == '.') + ++extPtr; + } + + nsCOMPtr icService = + do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mimeInfo; + rv = icService->GetMIMEInfoFromExtension(extPtr, getter_AddRefs(mimeInfo)); + if (NS_SUCCEEDED(rv)) + { + PRUint32 osType; + rv = mimeInfo->GetMacType(&osType); + if (NS_SUCCEEDED(rv)) + mType = osType; + PRBool skip; + rv = ExtensionIsOnExceptionList(extPtr, &skip); + if (NS_SUCCEEDED(rv) && !skip) + { + rv = mimeInfo->GetMacCreator(&osType); + if (NS_SUCCEEDED(rv)) + mCreator = osType; + } + } + } + return rv; +} + +nsresult nsLocalFile::ExtensionIsOnExceptionList(const char *extension, PRBool *onList) +{ + // Probably want to make a global list somewhere in the future + // for now, just check for "html" and "htm" + + *onList = PR_FALSE; + + if (!nsCRT::strcasecmp(extension, "html") || + !nsCRT::strcasecmp(extension, "htm")) + *onList = PR_TRUE; + return NS_OK; +} + + +void nsLocalFile::InitClassStatics() +{ + OSErr err; + + + if (sCurrentProcessSignature == 0) + { + ProcessSerialNumber psn; + ProcessInfoRec info; + + psn.highLongOfPSN = 0; + psn.lowLongOfPSN = kCurrentProcess; + + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = ::GetProcessInformation(&psn, &info); + if (err == noErr) + sCurrentProcessSignature = info.processSignature; + // Try again next time if error + } + + static PRBool didHFSPlusCheck = PR_FALSE; + if (!didHFSPlusCheck) + { + long response; + err = ::Gestalt(gestaltFSAttr, &response); + sHasHFSPlusAPIs = (err == noErr && (response & (1 << gestaltHasHFSPlusAPIs)) != 0); + didHFSPlusCheck = PR_TRUE; + } + + static PRBool didOSXCheck = PR_FALSE; + if (!didOSXCheck) + { + long version; + sRunningOSX = (::Gestalt(gestaltSystemVersion, &version) == noErr && version >= 0x00001000); + didOSXCheck = PR_TRUE; + } +} + + +#pragma mark - + +// Handy dandy utility create routine for something or the other +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString fsCharSetStr; + nsresult rv = NS_CopyUnicodeToNative(path, fsCharSetStr); + if (NS_FAILED(rv)) + return rv; + return NS_NewNativeLocalFile(fsCharSetStr, followLinks, result); +} + +nsresult +NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + nsresult rv = file->InitWithFSSpec(inSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h new file mode 100644 index 00000000..42eb2556 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileMac.h @@ -0,0 +1,137 @@ +/* -*- 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Steve Dagley + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _nsLocalFileMAC_H_ +#define _nsLocalFileMAC_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsILocalFileMac.h" +#include "nsIFactory.h" + +#include + +class NS_COM nsLocalFile : public nsILocalFileMac +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + + // nsILocalFileMac interface + NS_DECL_NSILOCALFILEMAC + +public: + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile() {} + +protected: + void MakeDirty(); + nsresult ResolveAndStat(); + nsresult UpdateCachedCatInfo(PRBool forceUpdate); + + nsresult FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec); + + nsresult FindRunningAppBySignature(OSType sig, FSSpec& outSpec, ProcessSerialNumber& outPsn); + nsresult FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn); + + nsresult MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground); + + nsresult TestFinderFlag(PRUint16 flagMask, PRBool *outFlagSet, PRBool testTargetSpec = PR_TRUE); + + nsresult MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ); + + // Passing nsnull for the extension uses leaf name + nsresult SetOSTypeAndCreatorFromExtension(const char* extension = nsnull); + + nsresult ExtensionIsOnExceptionList(const char *extension, PRBool *onList); + +private: + nsLocalFile(const nsLocalFile& srcFile); + nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath); + + // Copies all members except mRefCnt, copies mCachedCatInfo only if it's valid. + nsLocalFile& operator=(const nsLocalFile& rhs); + + PRPackedBool mFollowLinks; + PRPackedBool mFollowLinksDirty; + + // The object we specify is always: mSpec + mAppendedPath. + // mSpec is a valid spec in that its parent is known to exist. + // Appending nodes with Append() will update mSpec immediately + // if the appended node exists. If not, appended nodes are stored + // in mAppendedPath. + + PRPackedBool mSpecDirty; + FSSpec mSpec; + nsCString mAppendedPath; + FSSpec mTargetSpec; // If mSpec is an alias, this is the resolved alias. + + CInfoPBRec mCachedCatInfo; // cached file info, for the GetFSSpec() spec + PRPackedBool mCatInfoDirty; // does this need to be updated? + + OSType mType, mCreator; + + static void InitClassStatics(); + + static OSType sCurrentProcessSignature; + static PRBool sHasHFSPlusAPIs; + static PRBool sRunningOSX; +}; + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp new file mode 100644 index 00000000..269a13d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.cpp @@ -0,0 +1,1742 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * 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): + * Henry Sobotka + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "prtypes.h" +#include "prio.h" + +#include // needed for toupper +#include + +#include "nsXPIDLString.h" +#include "nsReadableUtils.h" +#include "prproces.h" +#include "prthread.h" + + +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor); +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor); +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf); +static int isleadbyte(int c); + +#include +#include + + +static nsresult ConvertOS2Error(int err) +{ + nsresult rv; + + switch (err) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rv = NS_ERROR_FILE_NOT_FOUND; + break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_SAME_DEVICE: + rv = NS_ERROR_FILE_ACCESS_DENIED; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_HANDLE: + case ERROR_ARENA_TRASHED: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + case ERROR_CURRENT_DIRECTORY: + rv = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + case ERROR_WRITE_PROTECT: + rv = NS_ERROR_FILE_READ_ONLY; + break; + case ERROR_HANDLE_DISK_FULL: + rv = NS_ERROR_FILE_TOO_BIG; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + case ERROR_CANNOT_MAKE: + rv = NS_ERROR_FILE_ALREADY_EXISTS; + break; + case 0: + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +static void +myLL_L2II(PRInt64 result, PRInt32 *hi, PRInt32 *lo ) +{ + PRInt64 a64, b64; // probably could have been done with + // only one PRInt64, but these are macros, + // and I am a wimp. + + // shift the hi word to the low word, then push it into a long. + LL_SHR(a64, result, 32); + LL_L2I(*hi, a64); + + // shift the low word to the hi word first, then shift it back. + LL_SHL(b64, result, 32); + LL_SHR(a64, b64, 32); + LL_L2I(*lo, a64); +} + + +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mDir(nsnull) + { + } + + nsresult Init(nsILocalFile* parent) + { + nsCAutoString filepath; + parent->GetNativeTarget(filepath); + + if (filepath.IsEmpty()) + { + parent->GetNativePath(filepath); + } + + if (filepath.IsEmpty()) + { + return NS_ERROR_UNEXPECTED; + } + + mDir = PR_OpenDir(filepath.get()); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mParent = parent; + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv; + if (mNext == nsnull && mDir) + { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) + { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + nsCOMPtr file; + rv = mParent->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(nsDependentCString(entry->name)); + if (NS_FAILED(rv)) + return rv; + + // make sure the thing exists. If it does, try the next one. + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + return HasMoreElements(result); + } + + mNext = do_QueryInterface(file); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + private: + ~nsDirEnumerator() + { + if (mDir) + { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + } + + protected: + PRDir* mDir; + nsCOMPtr mParent; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + + +nsLocalFile::nsLocalFile() +{ + MakeDirty(); +} + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mDirty(other.mDirty) + , mWorkingPath(other.mWorkingPath) + , mFileInfo64(other.mFileInfo64) +{ +} + +/* nsISupports interface implementation. */ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + +// This function resets any cached information about the file. +void +nsLocalFile::MakeDirty() +{ + mDirty = PR_TRUE; +} + +nsresult +nsLocalFile::Stat() +{ + if (!mDirty) + return NS_OK; + + char temp[4]; + const char* workingFilePath = mWorkingPath.get(); + const char* nsprPath = workingFilePath; + + if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') { + temp[0] = workingFilePath[0]; + temp[1] = workingFilePath[1]; + temp[2] = '\\'; + temp[3] = '\0'; + nsprPath = temp; + } + + DosError(FERR_DISABLEHARDERR); + PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64); + DosError(FERR_ENABLEHARDERR); + if ( status == PR_SUCCESS ) + return NS_OK; + + return NS_ERROR_FILE_NOT_FOUND; +} + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + MakeDirty(); + + nsACString::const_iterator begin, end; + filePath.BeginReading(begin); + filePath.EndReading(end); + + // input string must not be empty + if (begin == end) + return NS_ERROR_FAILURE; + + char firstChar = *begin; + char secondChar = *(++begin); + + // just do a sanity check. if it has any forward slashes, it is not a Native path + // on windows. Also, it must have a colon at after the first char. + + char *path = nsnull; + PRInt32 pathLen = 0; + + if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) || // normal path + ( (firstChar == '\\') && (secondChar == '\\') ) ) // network path + { + // This is a native path + path = ToNewCString(filePath); + pathLen = filePath.Length(); + } + + if (path == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // kill any trailing '\' provided it isn't the second char of DBCS + PRInt32 len = pathLen - 1; + if (path[len] == '\\' && !::isleadbyte(path[len-1])) + { + path[len] = '\0'; + pathLen = len; + } + + mWorkingPath.Adopt(path, pathLen); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = PR_Open(mWorkingPath.get(), flags, mode); + + if (*_retval) + return NS_OK; + + return NS_ErrorAccordingToNSPR(); +} + + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = fopen(mWorkingPath.get(), mode); + + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = Stat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // create nested directories to target + unsigned char* slash = _mbschr((const unsigned char*) mWorkingPath.get(), '\\'); + + + if (slash) + { + // skip the first '\\' + ++slash; + slash = _mbschr(slash, '\\'); + + while (slash) + { + *slash = '\0'; + + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) { + rv = ConvertOS2Error(rv); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv; + } + *slash = '\\'; + ++slash; + slash = _mbschr(slash, '\\'); + } + } + + if (type == NORMAL_FILE_TYPE) + { + PRFileDesc* file = PR_Open(mWorkingPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes); + if (!file) return NS_ERROR_FILE_ALREADY_EXISTS; + + PR_Close(file); + return NS_OK; + } + + if (type == DIRECTORY_TYPE) + { + rv = CreateDirectoryA(NS_CONST_CAST(char*, mWorkingPath.get()), NULL); + if (rv) + return ConvertOS2Error(rv); + else + return NS_OK; + } + + return NS_ERROR_FILE_UNKNOWN_TYPE; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + // Append only one component. Check for subdirs. + // XXX can we avoid the PromiseFlatCString call? + if (_mbschr((const unsigned char*) PromiseFlatCString(node).get(), '\\') != nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + return AppendRelativeNativePath(node); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &node) +{ + // Cannot start with a / or have .. or have / anywhere + nsACString::const_iterator begin, end; + node.BeginReading(begin); + node.EndReading(end); + if (node.IsEmpty() || FindCharInReadable('/', begin, end)) + { + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } + MakeDirty(); + mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + const char* temp = mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\'); + + // if the working path is just a node without any lashes. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName.Assign(leaf); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + MakeDirty(); + + const unsigned char* temp = (const unsigned char*) mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp); + if (offset) + { + mWorkingPath.Truncate(offset+1); + } + mWorkingPath.Append(aLeafName); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +nsresult +nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, PRBool move) +{ + nsresult rv; + nsCAutoString filePath; + + nsCAutoString destPath; + destParent->GetNativeTarget(destPath); + + destPath.Append("\\"); + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + sourceFile->GetNativeLeafName(aFileName); + destPath.Append(aFileName); + } + else + { + destPath.Append(newName); + } + + rv = sourceFile->GetNativePath(filePath); + + if (NS_FAILED(rv)) + return rv; + + APIRET rc = NO_ERROR; + + if( move ) + { + rc = DosMove(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get())); + } + + if (!move || rc == ERROR_NOT_SAME_DEVICE || rc == ERROR_ACCESS_DENIED) { + /* will get an error if the destination and source files aren't on the + * same drive. "MoveFile()" on Windows will go ahead and move the + * file without error, so we need to do the same IBM-AKR + */ + do { + rc = DosCopy(filePath.get(), (PSZ)NS_CONST_CAST(char*, destPath.get()), DCPY_EXISTING); + if (rc == ERROR_TOO_MANY_OPEN_FILES) { + ULONG CurMaxFH = 0; + LONG ReqCount = 20; + APIRET rc2; + rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH); + if (rc2 != NO_ERROR) { + break; + } + } + } while (rc == ERROR_TOO_MANY_OPEN_FILES); + + /* WSOD2 HACK */ + if (rc == 65) { // NETWORK_ACCESS_DENIED + CHAR achProgram[CCHMAXPATH]; // buffer for program name, parameters + RESULTCODES rescResults; // buffer for results of dosexecpgm + + strcpy(achProgram, "CMD.EXE /C "); + strcat(achProgram, """COPY "); + strcat(achProgram, filePath.get()); + strcat(achProgram, " "); + strcat(achProgram, (PSZ)NS_CONST_CAST(char*, destPath.get())); + strcat(achProgram, """"); + achProgram[strlen(achProgram) + 1] = '\0'; + achProgram[7] = '\0'; + DosExecPgm(NULL, 0, + EXEC_SYNC, achProgram, (PSZ)NULL, + &rescResults, achProgram); + rc = 0; // Assume it worked + + } /* rc == 65 */ + /* moving the file is supposed to act like a rename, so delete the + * original file if we got this far without error + */ + if( move && (rc == NO_ERROR) ) + { + DosDelete( filePath.get() ); + } + } /* !move or ERROR */ + + if (rc) + rv = ConvertOS2Error(rc); + + return rv; +} + + +nsresult +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool move) +{ + nsCOMPtr newParentDir = aParentDir; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + if (!newParentDir) + { + // no parent was specified. We must rename. + + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + if (!newParentDir) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + // make sure it exists and is a directory. Create it if not there. + PRBool exists; + newParentDir->Exists(&exists); + if (exists == PR_FALSE) + { + rv = newParentDir->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + PRBool isDir; + newParentDir->IsDirectory(&isDir); + if (isDir == PR_FALSE) + { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + // check to see if we are a directory, if so enumerate it. + + PRBool isDir; + IsDirectory(&isDir); + + if (!isDir) + { + rv = CopySingleFile(this, newParentDir, newName, move); + if (NS_FAILED(rv)) + return rv; + } + else + { + // create a new target destination in the new parentDir; + nsCOMPtr target; + rv = newParentDir->Clone(getter_AddRefs(target)); + + if (NS_FAILED(rv)) + return rv; + + nsCAutoString allocatedNewName; + if (newName.IsEmpty()) + { + GetNativeLeafName(allocatedNewName);// this should be the leaf name of the + } + else + { + allocatedNewName = newName; + } + + rv = target->AppendNative(allocatedNewName); + if (NS_FAILED(rv)) + return rv; + + allocatedNewName.Truncate(); + + target->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (!dirEnum) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr item; + nsCOMPtr file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + PRBool isDir, isLink; + + file->IsDirectory(&isDir); + + if (move) + { + rv = file->MoveToNative(target, nsCString()); + } + else + { + rv = file->CopyToNative(target, nsCString()); + } + + iterator->HasMoreElements(&more); + } + // we've finished moving all the children of this directory + // in the new directory. so now delete the directory + // note, we don't need to do a recursive delete. + // MoveTo() is recursive. At this point, + // we've already moved the children of the current folder + // to the new location. nothing should be left in the folder. + if (move) + { + rv = Remove(PR_FALSE); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + + // If we moved, we want to adjust this. + if (move) + { + MakeDirty(); + + nsCAutoString newParentPath; + newParentDir->GetNativePath(newParentPath); + + if (newParentPath.IsEmpty()) + return NS_ERROR_FAILURE; + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + GetNativeLeafName(aFileName); + + InitWithNativePath(newParentPath); + AppendNative(aFileName); + } + else + { + InitWithNativePath(newParentPath); + AppendNative(newName); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_TRUE); +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + *_retval = PR_LoadLibrary(mWorkingPath.get()); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + PRBool isDir; + + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + if (isDir) + { + if (recursive) + { + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = dirEnum->Init(this); + + nsCOMPtr iterator = do_QueryInterface(dirEnum); + + PRBool more; + iterator->HasMoreElements(&more); + while (more) + { + nsCOMPtr item; + nsCOMPtr file; + iterator->GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + + file->Remove(recursive); + + iterator->HasMoreElements(&more); + } + } + rv = rmdir(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + else + { + rv = remove(filePath) == -1 ? NSRESULT_FOR_ERRNO() : NS_OK; + } + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + *aLastModifiedTime = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + // microseconds -> milliseconds + *aLastModifiedTime = mFileInfo64.modifyTime / PR_USEC_PER_MSEC; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + return nsLocalFile::SetModDate(aLastModifiedTime); +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +nsLocalFile::SetModDate(PRInt64 aLastModifiedTime) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + PRExplodedTime pret; + FILESTATUS3 pathInfo; + + rv = DosQueryPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (NS_FAILED(rv)) + { + rv = ConvertOS2Error(rv); + return rv; + } + + // PR_ExplodeTime expects usecs... + PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret); + /* fdateLastWrite.year is based off of 1980 */ + if (pret.tm_year >= 1980) + pathInfo.fdateLastWrite.year = pret.tm_year-1980; + else + pathInfo.fdateLastWrite.year = pret.tm_year; + pathInfo.fdateLastWrite.month = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0 +// ???? OS2TODO st.wDayOfWeek = pret.tm_wday; + pathInfo.fdateLastWrite.day = pret.tm_mday; + pathInfo.ftimeLastWrite.hours = pret.tm_hour; + pathInfo.ftimeLastWrite.minutes = pret.tm_min; + pathInfo.ftimeLastWrite.twosecs = pret.tm_sec / 2; // adjust for twosecs? +// ??? OS2TODO st.wMilliseconds = pret.tm_usec/1000; + + rv = DosSetPathInfo(filePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo), + 0UL); + + if (NS_FAILED(rv)) + return rv; + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + if( chmod(filePath, aPermissions) == -1 ) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + *aFileSize = 0; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + + *aFileSize = mFileInfo64.size; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *filePath = mWorkingPath.get(); + + + APIRET rc; + HFILE hFile; + ULONG actionTaken; + + rc = DosOpen(filePath, + &hFile, + &actionTaken, + 0, + FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, + NULL); + + if (rc != NO_ERROR) + { + MakeDirty(); + return NS_ERROR_FAILURE; + } + + // Seek to new, desired end of file + PRInt32 hi, lo; + myLL_L2II(aFileSize, &hi, &lo ); + + rc = DosSetFileSize(hFile, lo); + if (rc == NO_ERROR) + DosClose(hFile); + else + goto error; + + MakeDirty(); + return NS_OK; + + error: + MakeDirty(); + DosClose(hFile); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + ULONG ulDriveNo = toupper(mWorkingPath.CharAt(0)) + 1 - 'A'; + FSALLOCATE fsAllocate; + APIRET rc = DosQueryFSInfo(ulDriveNo, + FSIL_ALLOC, + &fsAllocate, + sizeof(fsAllocate)); + + if (rc != NO_ERROR) + return NS_ERROR_FAILURE; + + *aDiskSpaceAvailable = fsAllocate.cUnitAvail; + *aDiskSpaceAvailable *= fsAllocate.cSectorUnit; + *aDiskSpaceAvailable *= fsAllocate.cbSector; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + + nsCAutoString parentPath(mWorkingPath); + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\') + - (const unsigned char *) parentPath.get()); + if (offset < 0) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + parentPath.Truncate(offset); + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(parentPath, PR_TRUE, getter_AddRefs(localFile)); + + if(NS_SUCCEEDED(rv) && localFile) + { + return CallQueryInterface(localFile, aParent); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + MakeDirty(); + *_retval = NS_SUCCEEDED(Stat()); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = !((pathInfo.attrFile & FILE_READONLY) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + GetNativeTarget(path); + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) path.get(), '\\'); + + if ( (strstr(leaf, ".bat") != nsnull) || + (strstr(leaf, ".exe") != nsnull) || + (strstr(leaf, ".cmd") != nsnull) || + (strstr(leaf, ".com") != nsnull) ) { + *_retval = PR_TRUE; + } else { + *_retval = PR_FALSE; + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_HIDDEN) != 0); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + // No Symlinks on OS/2 + *_retval = PR_FALSE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = Stat(); + + if (NS_FAILED(rv)) + return rv; + + const char *workingFilePath = mWorkingPath.get(); + + APIRET rc; + FILESTATUS3 pathInfo; + + rc = DosQueryPathInfo(workingFilePath, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + + if (rc != NO_ERROR) + { + rc = ConvertOS2Error(rc); + return rc; + } + + *_retval = ((pathInfo.attrFile & FILE_SYSTEM) != 0); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsCAutoString inFilePath; + inFile->GetNativePath(inFilePath); + + *_retval = inFilePath.Equals(mWorkingPath); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsCAutoString myFilePath; + if ( NS_FAILED(GetNativeTarget(myFilePath))) + GetNativePath(myFilePath); + + PRInt32 myFilePathLen = myFilePath.Length(); + + nsCAutoString inFilePath; + if ( NS_FAILED(inFile->GetNativeTarget(inFilePath))) + inFile->GetNativePath(inFilePath); + + if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0) + { + // now make sure that the |inFile|'s path has a trailing + // separator. + + if (inFilePath[myFilePathLen] == '\\') + { + *_retval = PR_TRUE; + } + + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = PR_TRUE; + return NS_OK; +} +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +#ifndef OPEN_DEFAULT +#define OPEN_DEFAULT 0 +#define OPEN_CONTENTS 1 +#endif + + +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + PRBool isDirectory = PR_FALSE; + nsCAutoString path; + + IsDirectory(&isDirectory); + if (isDirectory) + { + GetNativePath(path); + } + else + { + nsCOMPtr parent; + GetParent(getter_AddRefs(parent)); + if (parent) + parent->GetNativePath(path); + } + + HOBJECT hobject = WinQueryObject(path.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_CONTENTS, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + HOBJECT hobject = WinQueryObject(mWorkingPath.get()); + WinSetFocus(HWND_DESKTOP, HWND_DESKTOP); + WinOpenObject( hobject, OPEN_DEFAULT, TRUE); + + // we don't care if it succeeded or failed. + return NS_OK; +} + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + + *result = file; + return NS_OK; +} + +// Locates the first occurrence of charToSearchFor in the stringToSearch +static unsigned char* PR_CALLBACK +_mbschr( const unsigned char* stringToSearch, int charToSearchFor) +{ + const unsigned char* p = stringToSearch; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinNextChar(0,0,0,(char*)p); + } while (*p); /* enddo */ + // Result is p or NULL + return *p ? (unsigned char*)p : NULL; +} + +// Locates last occurence of charToSearchFor in the stringToSearch +extern unsigned char* +_mbsrchr( const unsigned char* stringToSearch, int charToSearchFor) +{ + int length = strlen((const char*)stringToSearch); + const unsigned char* p = stringToSearch+length; + do { + if (*p == charToSearchFor) + break; + p = (const unsigned char*)WinPrevChar(0,0,0,(char*)stringToSearch,(char*)p); + } while (p > stringToSearch); /* enddo */ + // Result is p or NULL + return (*p == charToSearchFor) ? (unsigned char*)p : NULL; +} + +// Implement equivalent of Win32 CreateDirectoryA +static nsresult PR_CALLBACK +CreateDirectoryA( PSZ path, PEAOP2 ppEABuf) +{ + APIRET rc; + nsresult rv; + FILESTATUS3 pathInfo; + + rc = DosCreateDir( path, ppEABuf ); + if (rc != NO_ERROR) { + rv = ConvertOS2Error(rc); + + // Check if directory already exists and if so, reflect that in the return value + rc = DosQueryPathInfo(path, + FIL_STANDARD, // Level 1 info + &pathInfo, + sizeof(pathInfo)); + if (rc == NO_ERROR) + rv = ERROR_FILE_EXISTS; + } + else + rv = rc; + + return rv; +} + +static int isleadbyte(int c) +{ + static BOOL bDBCSFilled=FALSE; + static BYTE DBCSInfo[12] = { 0 }; /* According to the Control Program Guide&Ref, + 12 bytes is sufficient */ + BYTE *curr; + BOOL retval = FALSE; + + if( !bDBCSFilled ) { + COUNTRYCODE ctrycodeInfo = { 0 }; + APIRET rc = NO_ERROR; + ctrycodeInfo.country = 0; /* Current Country */ + ctrycodeInfo.codepage = 0; /* Current Codepage */ + + rc = DosQueryDBCSEnv( sizeof( DBCSInfo ), + &ctrycodeInfo, + DBCSInfo ); + if( rc != NO_ERROR ) { + /* we had an error, do something? */ + return FALSE; + } + bDBCSFilled=TRUE; + } + + curr = DBCSInfo; + /* DBCSInfo returned by DosQueryDBCSEnv is terminated with two '0' bytes in a row */ + while(( *curr != 0 ) && ( *(curr+1) != 0)) { + if(( c >= *curr ) && ( c <= *(curr+1) )) { + retval=TRUE; + break; + } + curr+=2; + } + + return retval; +} + +NS_IMETHODIMP +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + if (filePath.IsEmpty()) + return InitWithNativePath(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(filePath, tmp); + + if (NS_SUCCEEDED(rv)) + return InitWithNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Append(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendNative(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + if (node.IsEmpty()) + return NS_OK; + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + + if (NS_SUCCEEDED(rv)) + return AppendRelativeNativePath(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = GetNativeLeafName(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, aLeafName); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + if (aLeafName.IsEmpty()) + return SetNativeLeafName(nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp); + + if (NS_SUCCEEDED(rv)) + return SetNativeLeafName(tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mWorkingPath, _retval); +} + +NS_IMETHODIMP +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return CopyToFollowingLinksNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + + if (NS_SUCCEEDED(rv)) + return MoveToNative(newParentDir, tmp); + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsCAutoString tmp; + nsresult rv = GetNativeTarget(tmp); + + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, _retval); + + return rv; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) { + *result = nsnull; + return rv; + } + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//---------------------------------------------------------------------------- +// global init/shutdown +//---------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h new file mode 100644 index 00000000..72f3127a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOS2.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * 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 of 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 Original Code has been modified by IBM Corporation. Modifications made by IBM + * described herein are Copyright (c) International Business Machines Corporation, 2000. + * Modifications to Mozilla code or documentation identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 05/26/2000 IBM Corp. Make more like Windows. + */ + +#ifndef _nsLocalFileOS2_H_ +#define _nsLocalFileOS2_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsIFactory.h" + +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_DOSSESMGR +#define INCL_DOSMODULEMGR +#define INCL_DOSNLS +#define INCL_DOSMISC +#define INCL_WINCOUNTRY +#define INCL_WINWORKPLACE + +#include + +class NS_COM nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile() {} + + nsLocalFile(const nsLocalFile& other); + + // this is the flag which indicates if I can used cached information about the file + PRPackedBool mDirty; + + // this string will alway be in native format! + nsCString mWorkingPath; + + PRFileInfo64 mFileInfo64; + + void MakeDirty(); + nsresult Stat(); + + nsresult CopyMove(nsIFile *newParentDir, const nsACString &newName, PRBool move); + nsresult CopySingleFile(nsIFile *source, nsIFile* dest, const nsACString &newName, PRBool move); + + nsresult SetModDate(PRInt64 aLastModifiedTime); +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp new file mode 100644 index 00000000..dfc431d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp @@ -0,0 +1,2542 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * Jungshik Shin + * Asaf Romano + * Mark Mentovai + * + * 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 "nsLocalFile.h" +#include "nsDirectoryServiceDefs.h" + +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsIDirectoryEnumerator.h" +#include "nsISimpleEnumerator.h" +#include "nsITimelineService.h" +#include "nsVoidArray.h" + +#include "plbase64.h" +#include "prmem.h" +#include "nsCRT.h" +#include "nsHashKeys.h" + +#include "MoreFilesX.h" +#include "FSCopyObject.h" +#include "nsAutoBuffer.h" +#include "nsTraceRefcntImpl.h" + +// Mac Includes +#include + +// Unix Includes +#include +#include +#include + +#if !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 +#define GetAliasSizeFromRecord(aliasRecord) aliasRecord.aliasSize +#else +#define GetAliasSizeFromRecord(aliasRecord) GetAliasSizeFromPtr(&aliasRecord) +#endif + +#define CHECK_mBaseRef() \ + PR_BEGIN_MACRO \ + if (!mBaseRef) \ + return NS_ERROR_NOT_INITIALIZED; \ + PR_END_MACRO + +//***************************************************************************** +// Static Function Prototypes +//***************************************************************************** + +static nsresult MacErrorMapper(OSErr inErr); +static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult); + +//***************************************************************************** +// Local Helper Classes +//***************************************************************************** + +#pragma mark - +#pragma mark [FSRef operator==] + +bool operator==(const FSRef& lhs, const FSRef& rhs) +{ + return (::FSCompareFSRefs(&lhs, &rhs) == noErr); +} + +#pragma mark - +#pragma mark [StFollowLinksState] + +class StFollowLinksState +{ + public: + StFollowLinksState(nsLocalFile& aFile) : + mFile(aFile) + { + mFile.GetFollowLinks(&mSavedState); + } + + StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) : + mFile(aFile) + { + mFile.GetFollowLinks(&mSavedState); + mFile.SetFollowLinks(followLinksState); + } + + ~StFollowLinksState() + { + mFile.SetFollowLinks(mSavedState); + } + + private: + nsLocalFile& mFile; + PRBool mSavedState; +}; + +#pragma mark - +#pragma mark [nsDirEnumerator] + +class nsDirEnumerator : public nsISimpleEnumerator, + public nsIDirectoryEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : + mIterator(nsnull), + mFSRefsArray(nsnull), + mArrayCnt(0), mArrayIndex(0) + { + } + + nsresult Init(nsILocalFileMac* parent) + { + NS_ENSURE_ARG(parent); + + OSErr err; + nsresult rv; + FSRef parentRef; + + rv = parent->GetFSRef(&parentRef); + if (NS_FAILED(rv)) + return rv; + + mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef) + * kRequestCountPerIteration); + if (!mFSRefsArray) + return NS_ERROR_OUT_OF_MEMORY; + + err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + if (mNext == nsnull) { + if (mArrayIndex >= mArrayCnt) { + ItemCount actualCnt; + OSErr err = ::FSGetCatalogInfoBulk(mIterator, + kRequestCountPerIteration, + &actualCnt, + nsnull, + kFSCatInfoNone, + nsnull, + mFSRefsArray, + nsnull, + nsnull); + + if (err == noErr || err == errFSNoMoreItems) { + mArrayCnt = actualCnt; + mArrayIndex = 0; + } + } + if (mArrayIndex < mArrayCnt) { + nsLocalFile *newFile = new nsLocalFile; + if (!newFile) + return NS_ERROR_OUT_OF_MEMORY; + FSRef fsRef = mFSRefsArray[mArrayIndex]; + if (NS_FAILED(newFile->InitWithFSRef(&fsRef))) + return NS_ERROR_FAILURE; + mArrayIndex++; + mNext = newFile; + } + } + *result = mNext != nsnull; + if (!*result) + Close(); + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; + + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + NS_IMETHOD GetNextFile(nsIFile **result) + { + *result = nsnull; + PRBool hasMore = PR_FALSE; + nsresult rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv) || !hasMore) + return rv; + *result = mNext; + NS_IF_ADDREF(*result); + mNext = nsnull; + return NS_OK; + } + + NS_IMETHOD Close() + { + if (mIterator) { + ::FSCloseIterator(mIterator); + mIterator = nsnull; + } + if (mFSRefsArray) { + nsMemory::Free(mFSRefsArray); + mFSRefsArray = nsnull; + } + return NS_OK; + } + + private: + ~nsDirEnumerator() + { + Close(); + } + + protected: + // According to Apple doc, request the number of objects + // per call that will fit in 4 VM pages. + enum { + kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef)) + }; + + nsCOMPtr mNext; + + FSIterator mIterator; + FSRef *mFSRefsArray; + PRInt32 mArrayCnt, mArrayIndex; +}; + +NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator) + +#pragma mark - +#pragma mark [StAEDesc] + +class StAEDesc: public AEDesc +{ +public: + StAEDesc() + { + descriptorType = typeNull; + dataHandle = nil; + } + + ~StAEDesc() + { + ::AEDisposeDesc(this); + } +}; + +#define FILENAME_BUFFER_SIZE 512 + +//***************************************************************************** +// nsLocalFile +//***************************************************************************** + +const char nsLocalFile::kPathSepChar = '/'; +const PRUnichar nsLocalFile::kPathSepUnichar = '/'; + +// The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local +// The NSPR epoch is Jan. 1, 1970 GMT +// 2082844800 is the difference in seconds between those dates +const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL; + +#pragma mark - +#pragma mark [CTORs/DTOR] + +nsLocalFile::nsLocalFile() : + mBaseRef(nsnull), + mTargetRef(nsnull), + mCachedFSRefValid(PR_FALSE), + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE) +{ +} + +nsLocalFile::nsLocalFile(const nsLocalFile& src) : + mBaseRef(src.mBaseRef), + mTargetRef(src.mTargetRef), + mCachedFSRef(src.mCachedFSRef), + mCachedFSRefValid(src.mCachedFSRefValid), + mFollowLinks(src.mFollowLinks), + mFollowLinksDirty(src.mFollowLinksDirty) +{ + // A CFURLRef is immutable so no need to copy, just retain. + if (mBaseRef) + ::CFRetain(mBaseRef); + if (mTargetRef) + ::CFRetain(mTargetRef); +} + +nsLocalFile::~nsLocalFile() +{ + if (mBaseRef) + ::CFRelease(mBaseRef); + if (mTargetRef) + ::CFRelease(mTargetRef); +} + + +//***************************************************************************** +// nsLocalFile::nsISupports +//***************************************************************************** +#pragma mark - +#pragma mark [nsISupports] + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile, + nsILocalFileMac, + nsILocalFile, + nsIFile, + nsIHashable) + +NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + + +//***************************************************************************** +// nsLocalFile::nsIFile +//***************************************************************************** +#pragma mark - +#pragma mark [nsIFile] + +/* void append (in AString node); */ +NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode) +{ + return AppendNative(NS_ConvertUTF16toUTF8(aNode)); +} + +/* [noscript] void appendNative (in ACString node); */ +NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsACString::const_iterator start, end; + aNode.BeginReading(start); + aNode.EndReading(end); + if (FindCharInReadable(kPathSepChar, start, end)) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, + PromiseFlatCString(aNode).get(), + kCFStringEncodingUTF8); + if (nodeStrRef) { + CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + mBaseRef, nodeStrRef, PR_FALSE); + ::CFRelease(nodeStrRef); + if (newRef) { + SetBaseRef(newRef); + ::CFRelease(newRef); + return NS_OK; + } + } + return NS_ERROR_FAILURE; +} + +/* void normalize (); */ +NS_IMETHODIMP nsLocalFile::Normalize() +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + // CFURL doesn't doesn't seem to resolve paths containing relative + // components, so we'll nick the stdlib code from nsLocalFileUnix + UInt8 path[PATH_MAX] = ""; + Boolean success; + success = ::CFURLGetFileSystemRepresentation(mBaseRef, true, path, PATH_MAX); + if (!success) + return NS_ERROR_FAILURE; + + char resolved_path[PATH_MAX] = ""; + char *resolved_path_ptr = nsnull; + resolved_path_ptr = realpath((char*)path, resolved_path); + + // if there is an error, the return is null. + if (!resolved_path_ptr) + return NSRESULT_FOR_ERRNO(); + + // Need to know whether we're a directory to create a new CFURLRef + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_ERROR_FAILURE; + CFStringRef pathStrRef = + ::CFStringCreateWithCString(kCFAllocatorDefault, + resolved_path, + kCFStringEncodingUTF8); + if (pathStrRef) { + CFURLRef newURLRef = + ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef, + kCFURLPOSIXPathStyle, isDirectory); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + ::CFRelease(pathStrRef); + } + + return rv; +} + +/* void create (in unsigned long type, in unsigned long permissions); */ +NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsStringArray nonExtantNodes; + CFURLRef pathURLRef = mBaseRef; + FSRef pathFSRef; + CFStringRef leafStrRef = nsnull; + nsAutoBuffer buffer; + Boolean success; + + // Work backwards through the path to find the last node which + // exists. Place the nodes which don't exist in an array and we'll + // create those below. + while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) { + leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef); + if (!leafStrRef) + break; + CFIndex leafLen = ::CFStringGetLength(leafStrRef); + if (!buffer.EnsureElemCapacity(leafLen + 1)) + break; + ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get()); + buffer.get()[leafLen] = '\0'; + nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get()))); + ::CFRelease(leafStrRef); + leafStrRef = nsnull; + + // Get the parent of the leaf for the next go round + CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef); + if (!parent) + break; + if (pathURLRef != mBaseRef) + ::CFRelease(pathURLRef); + pathURLRef = parent; + } + if (pathURLRef != mBaseRef) + ::CFRelease(pathURLRef); + if (leafStrRef != nsnull) + ::CFRelease(leafStrRef); + if (!success) + return NS_ERROR_FAILURE; + PRInt32 nodesToCreate = nonExtantNodes.Count(); + if (nodesToCreate == 0) + return NS_ERROR_FILE_ALREADY_EXISTS; + + OSErr err; + nsAutoString nextNodeName; + for (PRInt32 i = nodesToCreate - 1; i > 0; i--) { + nonExtantNodes.StringAt(i, nextNodeName); + err = ::FSCreateDirectoryUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, &pathFSRef, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + } + nonExtantNodes.StringAt(0, nextNodeName); + if (type == NORMAL_FILE_TYPE) { + err = ::FSCreateFileUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, nsnull, nsnull); + } + else { + err = ::FSCreateDirectoryUnicode(&pathFSRef, + nextNodeName.Length(), + (const UniChar *)nextNodeName.get(), + kFSCatInfoNone, + nsnull, nsnull, nsnull, nsnull); + } + + return MacErrorMapper(err); +} + +/* attribute AString leafName; */ +NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName) +{ + nsCAutoString nativeString; + nsresult rv = GetNativeLeafName(nativeString); + if (NS_FAILED(rv)) + return rv; + CopyUTF8toUTF16NFC(nativeString, aLeafName); + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName) +{ + return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName)); +} + +/* [noscript] attribute ACString nativeLeafName; */ +NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef); + if (leafStrRef) { + rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName); + ::CFRelease(leafStrRef); + } + return rv; +} + +NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (parentURLRef) { + CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, + PromiseFlatCString(aNativeLeafName).get(), + kCFStringEncodingUTF8); + + if (nodeStrRef) { + CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + parentURLRef, nodeStrRef, PR_FALSE); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + ::CFRelease(nodeStrRef); + } + ::CFRelease(parentURLRef); + } + return rv; +} + +/* void copyTo (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName) +{ + return CopyInternal(newParentDir, newName, PR_FALSE); +} + +/* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName) +{ + return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE); +} + +/* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName) +{ + return CopyInternal(newParentDir, newName, PR_TRUE); +} + +/* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName) +{ + return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE); +} + +/* void moveTo (in nsIFile newParentDir, in AString newName); */ +NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName) +{ + return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName)); +} + +/* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */ +NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + StFollowLinksState followLinks(*this, PR_FALSE); + + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + if (NS_FAILED(rv)) + return rv; + + // Get the source path. + nsCAutoString srcPath; + rv = GetNativePath(srcPath); + if (NS_FAILED(rv)) + return rv; + + // Build the destination path. + nsCOMPtr parentDir = newParentDir; + if (!parentDir) { + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + rv = GetParent(getter_AddRefs(parentDir)); + if (NS_FAILED(rv)) + return rv; + } + else { + PRBool exists; + rv = parentDir->Exists(&exists); + if (NS_FAILED(rv)) + return rv; + if (!exists) { + rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777); + if (NS_FAILED(rv)) + return rv; + } + } + + nsCAutoString destPath; + rv = parentDir->GetNativePath(destPath); + if (NS_FAILED(rv)) + return rv; + + if (!newName.IsEmpty()) + destPath.Append(NS_LITERAL_CSTRING("/") + newName); + else { + nsCAutoString leafName; + rv = GetNativeLeafName(leafName); + if (NS_FAILED(rv)) + return rv; + destPath.Append(NS_LITERAL_CSTRING("/") + leafName); + } + + // Perform the move. + if (rename(srcPath.get(), destPath.get()) != 0) { + if (errno == EXDEV) { + // Can't move across volume (device) boundaries. Copy and remove. + rv = CopyToNative(parentDir, newName); + if (NS_SUCCEEDED(rv)) { + // Permit removal failure. + Remove(PR_TRUE); + } + } + else + rv = NSRESULT_FOR_ERRNO(); + + if (NS_FAILED(rv)) + return rv; + } + + // Update |this| to refer to the moved file. + CFURLRef newBaseRef = + ::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(), + destPath.Length(), isDirectory); + if (!newBaseRef) + return NS_ERROR_FAILURE; + SetBaseRef(newBaseRef); + ::CFRelease(newBaseRef); + + return rv; +} + +/* void remove (in boolean recursive); */ +NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + // XXX If we're an alias, never remove target + StFollowLinksState followLinks(*this, PR_FALSE); + + PRBool isDirectory; + nsresult rv = IsDirectory(&isDirectory); + if (NS_FAILED(rv)) + return rv; + + if (recursive && isDirectory) { + FSRef fsRef; + rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + // Call MoreFilesX to do a recursive removal. + OSStatus err = ::FSDeleteContainer(&fsRef); + rv = MacErrorMapper(err); + } + else { + nsCAutoString path; + rv = GetNativePath(path); + if (NS_FAILED(rv)) + return rv; + + const char* pathPtr = path.get(); + int status; + if (isDirectory) + status = rmdir(pathPtr); + else + status = unlink(pathPtr); + + if (status != 0) + rv = NSRESULT_FOR_ERRNO(); + } + + mCachedFSRefValid = PR_FALSE; + return rv; +} + +/* attribute unsigned long permissions; */ +NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG_POINTER(aPermissions); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions; + *aPermissions = permPtr->mode; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions; + permPtr->mode = (UInt16)aPermissions; + err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo); + return MacErrorMapper(err); +} + +/* attribute unsigned long permissionsOfLink; */ +NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute PRInt64 lastModifiedTime; */ +NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aLastModifiedTime); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate); + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + OSErr err; + nsresult rv; + FSRef fsRef; + FSCatalogInfo catalogInfo; + + rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSRef parentRef; + PRBool notifyParent; + + /* Get the node flags, the content modification date and time, and the parent ref */ + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod, + &catalogInfo, NULL, NULL, &parentRef); + if (err != noErr) + return MacErrorMapper(err); + + /* Notify the parent if this is a file */ + notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); + + NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate); + err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo); + if (err != noErr) + return MacErrorMapper(err); + + /* Send a notification for the parent of the file, or for the directory */ + err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* attribute PRInt64 lastModifiedTimeOfLink; */ +NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} +NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* attribute PRInt64 fileSize; */ +NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG_POINTER(aFileSize); + *aFileSize = 0; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + // FSGetCatalogInfo can return a bogus size for directories sometimes, so only + // rely on the answer for files + if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0) + *aFileSize = catalogInfo.dataLogicalSize; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + SInt16 refNum; + OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum); + if (err != noErr) + return MacErrorMapper(err); + err = ::FSSetForkSize(refNum, fsFromStart, aFileSize); + ::FSCloseFork(refNum); + + return MacErrorMapper(err); +} + +/* readonly attribute PRInt64 fileSizeOfLink; */ +NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aFileSizeOfLink); + + StFollowLinksState followLinks(*this, PR_FALSE); + return GetFileSize(aFileSizeOfLink); +} + +/* readonly attribute AString target; */ +NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* [noscript] readonly attribute ACString nativeTarget; */ +NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* readonly attribute AString path; */ +NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath) +{ + nsCAutoString nativeString; + nsresult rv = GetNativePath(nativeString); + if (NS_FAILED(rv)) + return rv; + CopyUTF8toUTF16NFC(nativeString, aPath); + return NS_OK; +} + +/* [noscript] readonly attribute ACString nativePath; */ +NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsresult rv = NS_ERROR_FAILURE; + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle); + if (pathStrRef) { + rv = CFStringReftoUTF8(pathStrRef, aNativePath); + ::CFRelease(pathStrRef); + } + return rv; +} + +/* boolean exists (); */ +NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) { + *_retval = PR_TRUE; + } + + return NS_OK; +} + +/* boolean isWritable (); */ +NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + if (::FSCheckLock(&fsRef) == noErr) { + PRUint32 permissions; + rv = GetPermissions(&permissions); + if (NS_FAILED(rv)) + return rv; + *_retval = ((permissions & S_IWUSR) != 0); + } + return NS_OK; +} + +/* boolean isReadable (); */ +NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + PRUint32 permissions; + nsresult rv = GetPermissions(&permissions); + if (NS_FAILED(rv)) + return rv; + *_retval = ((permissions & S_IRUSR) != 0); + return NS_OK; +} + +/* boolean isExecutable (); */ +NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + LSRequestedInfo theInfoRequest = kLSRequestAllInfo; + LSItemInfoRecord theInfo; + if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) { + if ((theInfo.flags & kLSItemInfoIsApplication) != 0) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* boolean isHidden (); */ +NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + HFSUniStr255 leafName; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, + &leafName, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo + if ((fInfoPtr->finderFlags & kIsInvisible) != 0) { + *_retval = PR_TRUE; + } + else { + // If the leaf name begins with a '.', consider it invisible + if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.')) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* boolean isDirectory (); */ +NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0); + return NS_OK; +} + +/* boolean isFile (); */ +NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0); + return NS_OK; +} + +/* boolean isSymlink (); */ +NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + FSRef fsRef; + if (::CFURLGetFSRef(mBaseRef, &fsRef)) { + Boolean isAlias, isFolder; + if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr) + *_retval = isAlias; + } + return NS_OK; +} + +/* boolean isSpecial (); */ +NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* nsIFile clone (); */ +NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval) +{ + // Just copy-construct ourselves + *_retval = new nsLocalFile(*this); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*_retval); + + return NS_OK; +} + +/* boolean equals (in nsIFile inFile); */ +NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + return EqualsInternal(inFile, PR_TRUE, _retval); +} + +nsresult +nsLocalFile::EqualsInternal(nsISupports* inFile, PRBool aUpdateCache, + PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + nsCOMPtr inMacFile(do_QueryInterface(inFile)); + if (!inFile) + return NS_OK; + + nsLocalFile* inLF = + static_cast((nsILocalFileMac*) inMacFile); + + // If both exist, compare FSRefs + FSRef thisFSRef, inFSRef; + nsresult rv1 = GetFSRefInternal(thisFSRef, aUpdateCache); + nsresult rv2 = inLF->GetFSRefInternal(inFSRef, aUpdateCache); + if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) { + *_retval = (thisFSRef == inFSRef); + return NS_OK; + } + // If one exists and the other doesn't, not equal + if (rv1 != rv2) + return NS_OK; + + // Arg, we have to get their paths and compare + nsCAutoString thisPath, inPath; + if (NS_FAILED(GetNativePath(thisPath))) + return NS_ERROR_FAILURE; + if (NS_FAILED(inMacFile->GetNativePath(inPath))) + return NS_ERROR_FAILURE; + *_retval = thisPath.Equals(inPath); + + return NS_OK; +} + +/* boolean contains (in nsIFile inFile, in boolean recur); */ +NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + PRBool isDir; + nsresult rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_OK; // must be a dir to contain someone + + nsCAutoString thisPath, inPath; + if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath))) + return NS_ERROR_FAILURE; + size_t thisPathLen = thisPath.Length(); + if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) { + // Now make sure that the |inFile|'s path has a separator at thisPathLen, + // and there's at least one more character after that. + if (inPath[thisPathLen] == kPathSepChar) + *_retval = PR_TRUE; + } + return NS_OK; +} + +/* readonly attribute nsIFile parent; */ +NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + nsLocalFile *newFile = nsnull; + + // If it can be determined without error that a file does not + // have a parent, return nsnull for the parent and NS_OK as the result. + // See bug 133617. + nsresult rv = NS_OK; + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (parentURLRef) { + // If the parent path is longer than file's path then + // CFURLCreateCopyDeletingLastPathComponent must have simply added + // two dots at the end - in this case indicate that there is no parent. + // See bug 332389. + CFStringRef path = ::CFURLGetString(mBaseRef); + CFStringRef newPath = ::CFURLGetString(parentURLRef); + if (::CFStringGetLength(newPath) < ::CFStringGetLength(path)) { + rv = NS_ERROR_FAILURE; + newFile = new nsLocalFile; + if (newFile) { + rv = newFile->InitWithCFURL(parentURLRef); + if (NS_SUCCEEDED(rv)) { + NS_ADDREF(*aParent = newFile); + rv = NS_OK; + } + } + } + ::CFRelease(parentURLRef); + } + return rv; +} + +/* readonly attribute nsISimpleEnumerator directoryEntries; */ +NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries) +{ + NS_ENSURE_ARG_POINTER(aDirectoryEntries); + *aDirectoryEntries = nsnull; + + nsresult rv; + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator; + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) { + NS_RELEASE(dirEnum); + return rv; + } + *aDirectoryEntries = dirEnum; + + return NS_OK; +} + + +//***************************************************************************** +// nsLocalFile::nsILocalFile +//***************************************************************************** +#pragma mark - +#pragma mark [nsILocalFile] + +/* void initWithPath (in AString filePath); */ +NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath) +{ + return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath)); +} + +/* [noscript] void initWithNativePath (in ACString filePath); */ +NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath) +{ + nsCAutoString fixedPath; + if (Substring(filePath, 0, 2).EqualsLiteral("~/")) { + nsCOMPtr homeDir; + nsCAutoString homePath; + nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR, + getter_AddRefs(homeDir)); + NS_ENSURE_SUCCESS(rv, rv); + rv = homeDir->GetNativePath(homePath); + NS_ENSURE_SUCCESS(rv, rv); + + fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1); + } + else if (filePath.IsEmpty() || filePath.First() != '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + else + fixedPath.Assign(filePath); + + // A path with consecutive '/'s which are not between + // nodes crashes CFURLGetFSRef(). Consecutive '/'s which + // are between actual nodes are OK. So, convert consecutive + // '/'s to a single one. + fixedPath.ReplaceSubstring("//", "/"); + +#if 1 // bird: hack to fix RegistryLocationForSpec issues with /path/to/./components + fixedPath.ReplaceSubstring("/./", "/"); + size_t len = fixedPath.Length(); + while (len > 2) + { + size_t choplen = 0; + if (!strcmp(fixedPath.get() + len - 2, "/.")) + choplen = 2; + else if (!strcmp(fixedPath.get() + len - 1, "/")) + choplen = 1; + else + break; + fixedPath = StringHead(fixedPath, len - choplen); + } + // bird: another hack for the issue with VirtualBoxVM and symlinks... + char tmpBuf[PATH_MAX]; + if (realpath(fixedPath.get(), tmpBuf)) + fixedPath = tmpBuf; +#endif + + // On 10.2, huge paths also crash CFURLGetFSRef() + if (fixedPath.Length() > PATH_MAX) + return NS_ERROR_FILE_NAME_TOO_LONG; + + CFStringRef pathAsCFString; + CFURLRef pathAsCFURL; + + pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8); + if (!pathAsCFString) + return NS_ERROR_FAILURE; + pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE); + if (!pathAsCFURL) { + ::CFRelease(pathAsCFString); + return NS_ERROR_FAILURE; + } + SetBaseRef(pathAsCFURL); + ::CFRelease(pathAsCFURL); + ::CFRelease(pathAsCFString); + return NS_OK; +} + +/* void initWithFile (in nsILocalFile aFile); */ +NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile) +{ + NS_ENSURE_ARG(aFile); + + nsCOMPtr aFileMac(do_QueryInterface(aFile)); + if (!aFileMac) + return NS_ERROR_UNEXPECTED; + CFURLRef urlRef; + nsresult rv = aFileMac->GetCFURL(&urlRef); + if (NS_FAILED(rv)) + return rv; + rv = InitWithCFURL(urlRef); + ::CFRelease(urlRef); + return rv; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + NS_ENSURE_ARG_POINTER(aFollowLinks); + + *aFollowLinks = mFollowLinks; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + if (aFollowLinks != mFollowLinks) { + mFollowLinks = aFollowLinks; + UpdateTargetRef(); + } + return NS_OK; +} + +/* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */ +NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_Open(path.get(), flags, mode); + if (! *_retval) + return NS_ErrorAccordingToNSPR(); + + return NS_OK; +} + +/* [noscript] FILE openANSIFileDesc (in string mode); */ +NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + + *_retval = fopen(path.get(), mode); + if (! *_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +/* [noscript] PRLibraryStar load (); */ +NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(_retval); + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + + nsCAutoString path; + nsresult rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + + *_retval = PR_LoadLibrary(path.get()); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get()); + + if (!*_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +/* readonly attribute PRInt64 diskSpaceAvailable; */ +NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err; + FSCatalogInfo catalogInfo; + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo, + nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + FSVolumeInfo volumeInfo; + err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes, + &volumeInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + *aDiskSpaceAvailable = volumeInfo.freeBytes; + return NS_OK; +} + +/* void appendRelativePath (in AString relativeFilePath); */ +NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath) +{ + return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath)); +} + +/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */ +NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath) +{ + if (relativeFilePath.IsEmpty()) + return NS_OK; + // No leading '/' + if (relativeFilePath.First() == '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // Parse the nodes and call Append() for each + nsACString::const_iterator nodeBegin, pathEnd; + relativeFilePath.BeginReading(nodeBegin); + relativeFilePath.EndReading(pathEnd); + nsACString::const_iterator nodeEnd(nodeBegin); + + while (nodeEnd != pathEnd) { + FindCharInReadable(kPathSepChar, nodeEnd, pathEnd); + nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd)); + if (NS_FAILED(rv)) + return rv; + if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. + ++nodeEnd; + nodeBegin = nodeEnd; + } + return NS_OK; +} + +/* attribute ACString persistentDescriptor; */ +NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + AliasHandle aliasH; + OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH); + if (err != noErr) + return MacErrorMapper(err); + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + ::HLock((Handle) aliasH); + // Passing nsnull for dest makes NULL-term string + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + ::DisposeHandle((Handle) aliasH); + NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); + + aPersistentDescriptor = buf; + PR_Free(buf); + + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor) +{ + if (aPersistentDescriptor.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + // Support pathnames as user-supplied descriptors if they begin with '/' + // or '~'. These characters do not collide with the base64 set used for + // encoding alias records. + char first = aPersistentDescriptor.First(); + if (first == '/' || first == '~') + return InitWithNativePath(aPersistentDescriptor); + + nsresult rv = NS_OK; + + PRUint32 dataSize = aPersistentDescriptor.Length(); + char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull); + if (!decodedData) { + NS_ERROR("SetPersistentDescriptor was given bad data"); + return NS_ERROR_FAILURE; + } + + // Cast to an alias record and resolve. + AliasRecord aliasHeader = *(AliasPtr)decodedData; + PRInt32 aliasSize = GetAliasSizeFromRecord(aliasHeader); + if (aliasSize > ((PRInt32)dataSize * 3) / 4) { // be paranoid about having too few data + PR_Free(decodedData); + return NS_ERROR_FAILURE; + } + + // Move the now-decoded data into the Handle. + // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h + Handle newHandle = nsnull; + if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr) + rv = NS_ERROR_OUT_OF_MEMORY; + PR_Free(decodedData); + if (NS_FAILED(rv)) + return rv; + + Boolean changed; + FSRef resolvedFSRef; + OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed); + + rv = MacErrorMapper(err); + DisposeHandle(newHandle); + if (NS_FAILED(rv)) + return rv; + + return InitWithFSRef(&resolvedFSRef); +} + +/* void reveal (); */ +NS_IMETHODIMP nsLocalFile::Reveal() +{ + FSRef fsRefToReveal; + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + OSErr err; + ProcessSerialNumber process; + + nsresult rv = GetFSRefInternal(fsRefToReveal); + if (NS_FAILED(rv)) + return rv; + + err = ::FindRunningAppBySignature ('MACS', process); + if (err == noErr) { + err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); + if (err == noErr) { + // Create the FinderEvent + err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, + kAutoGenerateReturnID, kAnyTransactionID, &aeEvent); + if (err == noErr) { + // Create the file list + err = ::AECreateList(nil, 0, false, &fileList); + if (err == noErr) { + FSSpec fsSpecToReveal; + err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal); + if (err == noErr) { + err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec)); + if (err == noErr) { + err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList); + if (err == noErr) { + err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); + if (err == noErr) + ::SetFrontProcess(&process); + } + } + } + } + } + } + } + + return NS_OK; +} + +/* void launch (); */ +NS_IMETHODIMP nsLocalFile::Launch() +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::LSOpenFSRef(&fsRef, NULL); + return MacErrorMapper(err); +} + + +//***************************************************************************** +// nsLocalFile::nsILocalFileMac +//***************************************************************************** +#pragma mark - +#pragma mark [nsILocalFileMac] + +/* void initWithCFURL (in CFURLRef aCFURL); */ +NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) +{ + NS_ENSURE_ARG(aCFURL); + + SetBaseRef(aCFURL); + return NS_OK; +} + +/* void initWithFSRef ([const] in FSRefPtr aFSRef); */ +NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef) +{ + NS_ENSURE_ARG(aFSRef); + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); + if (newURLRef) { + SetBaseRef(newURLRef); + ::CFRelease(newURLRef); + rv = NS_OK; + } + return rv; +} + +/* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */ +NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec) +{ + NS_ENSURE_ARG(aFileSpec); + + FSRef fsRef; + OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef); + if (err == noErr) + return InitWithFSRef(&fsRef); + else if (err == fnfErr) { + CInfoPBRec pBlock; + FSSpec parentDirSpec; + + memset(&pBlock, 0, sizeof(CInfoPBRec)); + parentDirSpec.name[0] = 0; + pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum; + pBlock.dirInfo.ioDrDirID = aFileSpec->parID; + pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name; + pBlock.dirInfo.ioFDirIndex = -1; //get info on parID + err = ::PBGetCatInfoSync(&pBlock); + if (err != noErr) + return MacErrorMapper(err); + + parentDirSpec.vRefNum = aFileSpec->vRefNum; + parentDirSpec.parID = pBlock.dirInfo.ioDrParID; + err = ::FSpMakeFSRef(&parentDirSpec, &fsRef); + if (err != noErr) + return MacErrorMapper(err); + HFSUniStr255 unicodeName; + err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName); + if (err != noErr) + return MacErrorMapper(err); + nsresult rv = InitWithFSRef(&fsRef); + if (NS_FAILED(rv)) + return rv; + return Append(nsDependentString(unicodeName.unicode, unicodeName.length)); + } + return MacErrorMapper(err); +} + +/* void initToAppWithCreatorCode (in OSType aAppCreator); */ +NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) +{ + FSRef fsRef; + OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull); + if (err != noErr) + return MacErrorMapper(err); + return InitWithFSRef(&fsRef); +} + +/* CFURLRef getCFURL (); */ +NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + if (whichURLRef) + ::CFRetain(whichURLRef); + *_retval = whichURLRef; + return whichURLRef ? NS_OK : NS_ERROR_FAILURE; +} + +/* FSRef getFSRef (); */ +NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + return GetFSRefInternal(*_retval); +} + +/* FSSpec getFSSpec (); */ +NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + // Check we are correctly initialized. + CHECK_mBaseRef(); + + OSErr err; + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_SUCCEEDED(rv)) { + // If the leaf node exists, things are simple. + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, + nsnull, nsnull, _retval, nsnull); + return MacErrorMapper(err); + } + else if (rv == NS_ERROR_FILE_NOT_FOUND) { + // If the parent of the leaf exists, make an FSSpec from that. + CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); + if (!parentURLRef) + return NS_ERROR_FAILURE; + + err = fnfErr; + if (::CFURLGetFSRef(parentURLRef, &fsRef)) { + FSCatalogInfo catalogInfo; + if ((err = ::FSGetCatalogInfo(&fsRef, + kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding, + &catalogInfo, nsnull, nsnull, nsnull)) == noErr) { + nsAutoString leafName; + if (NS_SUCCEEDED(GetLeafName(leafName))) { + Str31 hfsName; + if ((err = ::UnicodeNameGetHFSName(leafName.Length(), + leafName.get(), + catalogInfo.textEncodingHint, + catalogInfo.nodeID == fsRtDirID, + hfsName)) == noErr) + err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval); + } + } + } + ::CFRelease(parentURLRef); + rv = MacErrorMapper(err); + } + return rv; +} + +/* readonly attribute PRInt64 fileSizeWithResFork; */ +NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork) +{ + NS_ENSURE_ARG_POINTER(aFileSizeWithResFork); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, + &catalogInfo, nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + + *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize; + return NS_OK; +} + +/* attribute OSType fileType; */ +NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) +{ + NS_ENSURE_ARG_POINTER(aFileType); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FinderInfo fInfo; + OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aFileType = fInfo.file.fileType; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType); + return MacErrorMapper(err); +} + +/* attribute OSType fileCreator; */ +NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator) +{ + NS_ENSURE_ARG_POINTER(aFileCreator); + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FinderInfo fInfo; + OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + *aFileCreator = fInfo.file.fileCreator; + return NS_OK; +} + +NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator) +{ + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0); + return MacErrorMapper(err); +} + +/* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */ +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) +{ + // XXX - This should be cut from the API. Would create an evil dependency. + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void setFileTypeAndCreatorFromExtension (in string aExtension); */ +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) +{ + // XXX - This should be cut from the API. Would create an evil dependency. + NS_ERROR("NS_ERROR_NOT_IMPLEMENTED"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */ +NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground) +{ + PRBool isExecutable; + nsresult rv = IsExecutable(&isExecutable); + if (NS_FAILED(rv)) + return rv; + if (!isExecutable) + return NS_ERROR_FILE_EXECUTION_FAILED; + + FSRef appFSRef, docFSRef; + rv = GetFSRefInternal(appFSRef); + if (NS_FAILED(rv)) + return rv; + + if (aDocToLoad) { + nsCOMPtr macDoc = do_QueryInterface(aDocToLoad); + rv = macDoc->GetFSRef(&docFSRef); + if (NS_FAILED(rv)) + return rv; + } + + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appFSRef; + if (aDocToLoad) { + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docFSRef; + } + thelaunchSpec.launchFlags = theLaunchFlags; + + OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */ +NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground) +{ + nsresult rv; + OSErr err; + + FSRef docFSRef, appFSRef; + rv = GetFSRefInternal(docFSRef); + if (NS_FAILED(rv)) + return rv; + + if (aAppToOpenWith) { + nsCOMPtr appFileMac = do_QueryInterface(aAppToOpenWith, &rv); + if (!appFileMac) + return rv; + + PRBool isExecutable; + rv = appFileMac->IsExecutable(&isExecutable); + if (NS_FAILED(rv)) + return rv; + if (!isExecutable) + return NS_ERROR_FILE_EXECUTION_FAILED; + + rv = appFileMac->GetFSRef(&appFSRef); + if (NS_FAILED(rv)) + return rv; + } + else { + OSType fileCreator; + rv = GetFileCreator(&fileCreator); + if (NS_FAILED(rv)) + return rv; + + err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull); + if (err != noErr) + return MacErrorMapper(err); + } + + LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; + LSLaunchFSRefSpec thelaunchSpec; + + if (aLaunchInBackground) + theLaunchFlags |= kLSLaunchDontSwitch; + memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); + + thelaunchSpec.appRef = &appFSRef; + thelaunchSpec.numDocs = 1; + thelaunchSpec.itemRefs = &docFSRef; + thelaunchSpec.launchFlags = theLaunchFlags; + + err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); + if (err != noErr) + return MacErrorMapper(err); + + return NS_OK; +} + +/* boolean isPackage (); */ +NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_FAILED(rv)) + return rv; + + FSCatalogInfo catalogInfo; + OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, + &catalogInfo, nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) { + FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); + if ((fInfoPtr->finderFlags & kHasBundle) != 0) { + *_retval = PR_TRUE; + } + else { + // Folders ending with ".app" are also considered to + // be packages, even if the top-level folder doesn't have bundle set + nsCAutoString name; + if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) { + const char *extPtr = strrchr(name.get(), '.'); + if (extPtr) { + if ((nsCRT::strcasecmp(extPtr, ".app") == 0)) + *_retval = PR_TRUE; + } + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetBundleDisplayName(nsAString& outBundleName) +{ + PRBool isPackage = PR_FALSE; + nsresult rv = IsPackage(&isPackage); + if (NS_FAILED(rv) || !isPackage) + return NS_ERROR_FAILURE; + + nsAutoString name; + rv = GetLeafName(name); + if (NS_FAILED(rv)) + return rv; + + PRInt32 length = name.Length(); + if (Substring(name, length - 4, length).EqualsLiteral(".app")) { + // 4 characters in ".app" + outBundleName = Substring(name, 0, length - 4); + } + else + outBundleName = name; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier) +{ + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef urlRef; + if (NS_SUCCEEDED(GetCFURL(&urlRef))) { + CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef); + if (bundle) { + CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle); + if (bundleIdentifier) + rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier); + + ::CFRelease(bundle); + } + ::CFRelease(urlRef); + } + + return rv; +} + + +//***************************************************************************** +// nsLocalFile Methods +//***************************************************************************** +#pragma mark - +#pragma mark [Protected Methods] + +nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef) +{ + NS_ENSURE_ARG(aCFURLRef); + + ::CFRetain(aCFURLRef); + if (mBaseRef) + ::CFRelease(mBaseRef); + mBaseRef = aCFURLRef; + + mFollowLinksDirty = PR_TRUE; + UpdateTargetRef(); + mCachedFSRefValid = PR_FALSE; + return NS_OK; +} + +nsresult nsLocalFile::UpdateTargetRef() +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + if (mFollowLinksDirty) { + if (mTargetRef) { + ::CFRelease(mTargetRef); + mTargetRef = nsnull; + } + if (mFollowLinks) { + mTargetRef = mBaseRef; + ::CFRetain(mTargetRef); + + FSRef fsRef; + if (::CFURLGetFSRef(mBaseRef, &fsRef)) { + Boolean targetIsFolder, wasAliased; + if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/, + &targetIsFolder, &wasAliased) == noErr && wasAliased) { + ::CFRelease(mTargetRef); + mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef); + if (!mTargetRef) + return NS_ERROR_FAILURE; + } + } + mFollowLinksDirty = PR_FALSE; + } + } + return NS_OK; +} + +nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache) +{ + if (bForceUpdateCache || !mCachedFSRefValid) { + mCachedFSRefValid = PR_FALSE; + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); + if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef)) + mCachedFSRefValid = PR_TRUE; + } + if (mCachedFSRefValid) { + aFSRef = mCachedFSRef; + return NS_OK; + } + // CFURLGetFSRef only returns a Boolean for success, + // so we have to assume what the error was. This is + // the only probable cause. + return NS_ERROR_FILE_NOT_FOUND; +} + +nsresult nsLocalFile::GetPathInternal(nsACString& path) +{ + nsresult rv = NS_ERROR_FAILURE; + + CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; + NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); + + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle); + if (pathStrRef) { + rv = CFStringReftoUTF8(pathStrRef, path); + ::CFRelease(pathStrRef); + } + return rv; +} + +nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir, + const nsAString& newName, + PRBool followLinks) +{ + // Check we are correctly initialized. + CHECK_mBaseRef(); + + StFollowLinksState srcFollowState(*this, followLinks); + + nsresult rv; + OSErr err; + FSRef srcFSRef, newFSRef; + + rv = GetFSRefInternal(srcFSRef); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr newParentDir = aParentDir; + + if (!newParentDir) { + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + // If newParentDir does not exist, create it + PRBool exists; + rv = newParentDir->Exists(&exists); + if (NS_FAILED(rv)) + return rv; + if (!exists) { + rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777); + if (NS_FAILED(rv)) + return rv; + } + + FSRef destFSRef; + nsCOMPtr newParentDirMac(do_QueryInterface(newParentDir)); + if (!newParentDirMac) + return NS_ERROR_NO_INTERFACE; + rv = newParentDirMac->GetFSRef(&destFSRef); + if (NS_FAILED(rv)) + return rv; + + err = + ::FSCopyObject(&srcFSRef, &destFSRef, newName.Length(), + newName.Length() ? PromiseFlatString(newName).get() : NULL, + 0, kFSCatInfoNone, false, false, NULL, NULL, &newFSRef); + + return MacErrorMapper(err); +} + +const PRInt64 kMillisecsPerSec = 1000LL; +const PRInt64 kUTCDateTimeFractionDivisor = 65535LL; + +PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime) +{ + // Start with seconds since Jan. 1, 1904 GMT + PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds; + // Subtract to convert to NSPR epoch of 1970 + result -= kJanuaryFirst1970Seconds; + // Convert to millisecs + result *= kMillisecsPerSec; + // Convert the fraction to millisecs and add it + result += ((PRInt64)utcTime.fraction * kMillisecsPerSec) / kUTCDateTimeFractionDivisor; + + return result; +} + +void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime) +{ + PRInt64 fraction = nsprTime % kMillisecsPerSec; + PRInt64 seconds = (nsprTime / kMillisecsPerSec) + kJanuaryFirst1970Seconds; + utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32); + utcTime.lowSeconds = (UInt32)seconds; + utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMillisecsPerSec); +} + +nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) +{ + nsresult rv = NS_ERROR_FAILURE; + CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef); + CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen); + if (charsConverted == inStrLen) { +#if 0 /* bird: too new? */ + aOutStr.SetLength(usedBufLen); + if (aOutStr.Length() != (unsigned int)usedBufLen) + return NS_ERROR_OUT_OF_MEMORY; + UInt8 *buffer = (UInt8*) aOutStr.BeginWriting(); + + ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, false, buffer, usedBufLen, &usedBufLen); + rv = NS_OK; +#else + nsAutoBuffer buffer; + if (buffer.EnsureElemCapacity(usedBufLen + 1)) { + ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), + kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen); + buffer.get()[usedBufLen] = '\0'; + aOutStr.Assign(nsDependentCString((char*)buffer.get())); + rv = NS_OK; + } +#endif + } + return rv; +} + +// nsIHashable + +NS_IMETHODIMP +nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult) +{ + return EqualsInternal(aOther, PR_FALSE, aResult); +} + +NS_IMETHODIMP +nsLocalFile::GetHashCode(PRUint32 *aResult) +{ + CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle); + nsCAutoString path; + CFStringReftoUTF8(pathStrRef, path); + ::CFRelease(pathStrRef); + *aResult = HashString(path); + return NS_OK; +} + +//***************************************************************************** +// Global Functions +//***************************************************************************** +#pragma mark - +#pragma mark [Global Functions] + +void nsLocalFile::GlobalInit() +{ +} + +void nsLocalFile::GlobalShutdown() +{ +} + +nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile; + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithPath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result) +{ + return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result); +} + +nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + nsresult rv = file->InitWithFSSpec(inSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(aFollowLinks); + + nsresult rv = file->InitWithFSRef(aFSRef); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; +} + +//***************************************************************************** +// Static Functions +//***************************************************************************** + +static nsresult MacErrorMapper(OSErr inErr) +{ + nsresult outErr; + + switch (inErr) + { + case noErr: + outErr = NS_OK; + break; + + case fnfErr: + case afpObjectNotFound: + case afpDirNotFound: + outErr = NS_ERROR_FILE_NOT_FOUND; + break; + + case dupFNErr: + case afpObjectExists: + outErr = NS_ERROR_FILE_ALREADY_EXISTS; + break; + + case dskFulErr: + case afpDiskFull: + outErr = NS_ERROR_FILE_DISK_FULL; + break; + + case fLckdErr: + case afpVolLocked: + outErr = NS_ERROR_FILE_IS_LOCKED; + break; + + case afpAccessDenied: + outErr = NS_ERROR_FILE_ACCESS_DENIED; + break; + + case afpDirNotEmpty: + outErr = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + + // Can't find good map for some + case bdNamErr: + outErr = NS_ERROR_FAILURE; + break; + + default: + outErr = NS_ERROR_FAILURE; + break; + } + return outErr; +} + +static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn) +{ + ProcessInfoRec info; + OSErr err = noErr; + + outPsn.highLongOfPSN = 0; + outPsn.lowLongOfPSN = kNoProcess; + + while (PR_TRUE) + { + err = ::GetNextProcess(&outPsn); + if (err == procNotFound) + break; + if (err != noErr) + return err; + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = ::GetProcessInformation(&outPsn, &info); + if (err != noErr) + return err; + + if (info.processSignature == aAppSig) + return noErr; + } + return procNotFound; +} + +// Convert a UTF-8 string to a UTF-16 string while normalizing to +// Normalization Form C (composed Unicode). We need this because +// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode) +// while most other OS', server-side programs usually expect NFC. + +typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult) +{ + static PRBool sChecked = PR_FALSE; + static UnicodeNormalizer sUnicodeNormalizer = NULL; + + // CFStringNormalize was not introduced until Mac OS 10.2 + if (!sChecked) { + CFBundleRef carbonBundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon")); + if (carbonBundle) + sUnicodeNormalizer = (UnicodeNormalizer) + ::CFBundleGetFunctionPointerForName(carbonBundle, + CFSTR("CFStringNormalize")); + sChecked = PR_TRUE; + } + + if (!sUnicodeNormalizer) { // OS X 10.2 or earlier + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc); + + // The number of 16bit code units in a UTF-16 string will never be + // larger than the number of bytes in the corresponding UTF-8 string. + CFMutableStringRef inStr = + ::CFStringCreateMutable(NULL, inFlatSrc.Length()); + + if (!inStr) { + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8); + + sUnicodeNormalizer(inStr, kCFStringNormalizationFormC); + + CFIndex length = CFStringGetLength(inStr); + const UniChar* chars = CFStringGetCharactersPtr(inStr); + + if (chars) + aResult.Assign(chars, length); + else { + nsAutoBuffer buffer; + if (!buffer.EnsureElemCapacity(length)) + CopyUTF8toUTF16(aSrc, aResult); + else { + CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get()); + aResult.Assign(buffer.get(), length); + } + } + CFRelease(inStr); +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h new file mode 100644 index 00000000..b6d74521 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.h @@ -0,0 +1,119 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001, 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Conrad Carlen + * + * 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 nsLocalFileMac_h__ +#define nsLocalFileMac_h__ + +#include "nsILocalFileMac.h" +#include "nsString.h" +#include "nsIHashable.h" + +class nsDirEnumerator; + +//***************************************************************************** +// nsLocalFile +// +// The native charset of this implementation is UTF-8. The Unicode used by the +// Mac OS file system is decomposed, so "Native" versions of these routines will +// always use decomposed Unicode (NFD). Their "non-Native" counterparts are +// intended to be simple wrappers which call the "Native" version and convert +// between UTF-8 and UTF-16. All the work is done on the "Native" side except +// for the conversion to NFC (composed Unicode) done in "non-Native" getters. +//***************************************************************************** + +class NS_COM nsLocalFile : public nsILocalFileMac, + public nsIHashable +{ + friend class nsDirEnumerator; + +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + NS_DECL_ISUPPORTS + NS_DECL_NSIFILE + NS_DECL_NSILOCALFILE + NS_DECL_NSILOCALFILEMAC + NS_DECL_NSIHASHABLE + +public: + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + ~nsLocalFile(); + +protected: + nsLocalFile(const nsLocalFile& src); + + nsresult SetBaseRef(CFURLRef aCFURLRef); // Does CFRetain on aCFURLRef + nsresult UpdateTargetRef(); + + nsresult GetFSRefInternal(FSRef& aFSSpec, PRBool bForceUpdateCache = PR_TRUE); + nsresult GetPathInternal(nsACString& path); // Returns path WRT mFollowLinks + nsresult EqualsInternal(nsISupports* inFile, + PRBool aUpdateCache, PRBool *_retval); + + nsresult CopyInternal(nsIFile* newParentDir, + const nsAString& newName, + PRBool followLinks); + + static PRInt64 HFSPlustoNSPRTime(const UTCDateTime& utcTime); + static void NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime); + static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr); + +protected: + CFURLRef mBaseRef; // The FS object we represent + CFURLRef mTargetRef; // If mBaseRef is an alias, its target + + FSRef mCachedFSRef; + PRPackedBool mCachedFSRefValid; + + PRPackedBool mFollowLinks; + PRPackedBool mFollowLinksDirty; + + static const char kPathSepChar; + static const PRUnichar kPathSepUnichar; + static const PRInt64 kJanuaryFirst1970Seconds; +}; + +#endif // nsLocalFileMac_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h new file mode 100644 index 00000000..90bc9c07 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnicode.h @@ -0,0 +1,47 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _NS_LOCALFILEUNICODE_H_ + +extern void NS_ShutdownLocalFileUnicode(); + +extern "C" NS_EXPORT nsresult +NS_NewUnicodeLocalFile(const PRUnichar *, PRBool, nsILocalFile **); + +#endif // _NS_LOCALFILEUNICODE_H_ + diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp new file mode 100644 index 00000000..eef17bde --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.cpp @@ -0,0 +1,1724 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * Christopher Blizzard + * Jason Eager + * Stuart Parmenter + * Brendan Eich + * Pete Collins + * Paul Ashford + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Implementation of nsIFile for ``Unixy'' systems. + */ + +// We're going to need some autoconf loving, I can just tell. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XP_BEOS + #include + #include + #include +#endif +#if defined(VMS) + #include +#endif + +#include "nsDirectoryServiceDefs.h" +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsIFile.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsLocalFile.h" +#include "nsIComponentManager.h" +#include "nsXPIDLString.h" +#include "prproces.h" +#include "nsISimpleEnumerator.h" +#include "nsITimelineService.h" + +#include "nsNativeCharsetUtils.h" + +// On some platforms file/directory name comparisons need to +// be case-blind. +#if defined(VMS) + #define FILE_STRCMP strcasecmp + #define FILE_STRNCMP strncasecmp +#else + #define FILE_STRCMP strcmp + #define FILE_STRNCMP strncmp +#endif + +#define VALIDATE_STAT_CACHE() \ + PR_BEGIN_MACRO \ + if (!mHaveCachedStat) { \ + FillStatCache(); \ + if (!mHaveCachedStat) \ + return NSRESULT_FOR_ERRNO(); \ + } \ + PR_END_MACRO + +#define CHECK_mPath() \ + PR_BEGIN_MACRO \ + if (mPath.IsEmpty()) \ + return NS_ERROR_NOT_INITIALIZED; \ + PR_END_MACRO + +/* directory enumerator */ +class NS_COM +nsDirEnumeratorUnix : public nsISimpleEnumerator +{ + public: + nsDirEnumeratorUnix(); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsISimpleEnumerator interface + NS_DECL_NSISIMPLEENUMERATOR + + NS_IMETHOD Init(nsLocalFile *parent, PRBool ignored); + + private: + ~nsDirEnumeratorUnix(); + + protected: + NS_IMETHOD GetNextEntry(); + + DIR *mDir; + struct dirent *mEntry; + nsCString mParentPath; +}; + +nsDirEnumeratorUnix::nsDirEnumeratorUnix() : + mDir(nsnull), + mEntry(nsnull) +{ +} + +nsDirEnumeratorUnix::~nsDirEnumeratorUnix() +{ + if (mDir) + closedir(mDir); +} + +NS_IMPL_ISUPPORTS1(nsDirEnumeratorUnix, nsISimpleEnumerator) + +NS_IMETHODIMP +nsDirEnumeratorUnix::Init(nsLocalFile *parent, PRBool resolveSymlinks /*ignored*/) +{ + nsCAutoString dirPath; + if (NS_FAILED(parent->GetNativePath(dirPath)) || + dirPath.IsEmpty()) { + return NS_ERROR_FILE_INVALID_PATH; + } + + if (NS_FAILED(parent->GetNativePath(mParentPath))) + return NS_ERROR_FAILURE; + + mDir = opendir(dirPath.get()); + if (!mDir) + return NSRESULT_FOR_ERRNO(); + return GetNextEntry(); +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::HasMoreElements(PRBool *result) +{ + *result = mDir && mEntry; + return NS_OK; +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::GetNext(nsISupports **_retval) +{ + nsresult rv; + if (!mDir || !mEntry) { + *_retval = nsnull; + return NS_OK; + } + + nsLocalFile* file = new nsLocalFile(); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + if (NS_FAILED(rv = file->InitWithNativePath(mParentPath)) || + NS_FAILED(rv = file->AppendNative(nsDependentCString(mEntry->d_name)))) { + return rv; + } + *_retval = NS_STATIC_CAST(nsISupports *, file); + NS_ADDREF(*_retval); + return GetNextEntry(); +} + +NS_IMETHODIMP +nsDirEnumeratorUnix::GetNextEntry() +{ + do { + errno = 0; + mEntry = readdir(mDir); + + // end of dir or error + if (!mEntry) + return NSRESULT_FOR_ERRNO(); + + // keep going past "." and ".." + } while (mEntry->d_name[0] == '.' && + (mEntry->d_name[1] == '\0' || // .\0 + (mEntry->d_name[1] == '.' && + mEntry->d_name[2] == '\0'))); // ..\0 + return NS_OK; +} + +nsLocalFile::nsLocalFile() : + mHaveCachedStat(PR_FALSE) +{ +} + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mCachedStat(other.mCachedStat) + , mPath(other.mPath) + , mHaveCachedStat(other.mHaveCachedStat) +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, + nsIFile, + nsILocalFile) + +nsresult +nsLocalFile::nsLocalFileConstructor(nsISupports *outer, + const nsIID &aIID, + void **aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + *aInstancePtr = nsnull; + + nsCOMPtr inst = new nsLocalFile(); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + return inst->QueryInterface(aIID, aInstancePtr); +} + +nsresult +nsLocalFile::FillStatCache() { + if (stat(mPath.get(), &mCachedStat) == -1) { + // try lstat it may be a symlink + if (lstat(mPath.get(), &mCachedStat) == -1) { + return NSRESULT_FOR_ERRNO(); + } + } + mHaveCachedStat = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + if (Substring(filePath, 0, 2).EqualsLiteral("~/")) { + nsCOMPtr homeDir; + nsCAutoString homePath; + if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR, + getter_AddRefs(homeDir))) || + NS_FAILED(homeDir->GetNativePath(homePath))) { + return NS_ERROR_FAILURE; + } + + mPath = homePath + Substring(filePath, 1, filePath.Length() - 1); + } else if (filePath.IsEmpty() || filePath.First() != '/') { + NS_ERROR("Relative paths not allowed"); + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } else { + mPath = filePath; + } + + // trim off trailing slashes + ssize_t len = mPath.Length(); + while ((len > 1) && (mPath[len - 1] == '/')) + --len; + mPath.SetLength(len); + + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CreateAllAncestors(PRUint32 permissions) +{ + // I promise to play nice + char *buffer = mPath.BeginWriting(), + *slashp = buffer; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: before: %s\n", buffer); +#endif + + while ((slashp = strchr(slashp + 1, '/'))) { + /* + * Sequences of '/' are equivalent to a single '/'. + */ + if (slashp[1] == '/') + continue; + + /* + * If the path has a trailing slash, don't make the last component, + * because we'll get EEXIST in Create when we try to build the final + * component again, and it's easier to condition the logic here than + * there. + */ + if (slashp[1] == '\0') + break; + + /* Temporarily NUL-terminate here */ + *slashp = '\0'; +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer); +#endif + int mkdir_result = mkdir(buffer, permissions); + int mkdir_errno = errno; + if (mkdir_result == -1) { + /* + * Always set |errno| to EEXIST if the dir already exists + * (we have to do this here since the errno value is not consistent + * in all cases - various reasons like different platform, + * automounter-controlled dir, etc. can affect it (see bug 125489 + * for details)). + */ + if (access(buffer, F_OK) == 0) { + mkdir_errno = EEXIST; + } + } + + /* Put the / back before we (maybe) return */ + *slashp = '/'; + + /* + * We could get EEXIST for an existing file -- not directory -- + * with the name of one of our ancestors, but that's OK: we'll get + * ENOTDIR when we try to make the next component in the path, + * either here on back in Create, and error out appropriately. + */ + if (mkdir_result == -1 && mkdir_errno != EEXIST) + return nsresultForErrno(mkdir_errno); + } + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: after: %s\n", buffer); +#endif + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + *_retval = PR_Open(mPath.get(), flags, mode); + if (! *_retval) + return NS_ErrorAccordingToNSPR(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) +{ + *_retval = fopen(mPath.get(), mode); + if (! *_retval) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +static int +do_create(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) +{ + *_retval = PR_Open(path, flags, mode); + return *_retval ? 0 : -1; +} + +static int +do_mkdir(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) +{ + *_retval = nsnull; + return mkdir(path, mode); +} + +nsresult +nsLocalFile::CreateAndKeepOpen(PRUint32 type, PRIntn flags, + PRUint32 permissions, PRFileDesc **_retval) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + int result; + int (*createFunc)(const char *, PRIntn, mode_t, PRFileDesc **) = + (type == NORMAL_FILE_TYPE) ? do_create : do_mkdir; + + result = createFunc(mPath.get(), flags, permissions, _retval); + if (result == -1 && errno == ENOENT) { + /* + * If we failed because of missing ancestor components, try to create + * them and then retry the original creation. + * + * Ancestor directories get the same permissions as the file we're + * creating, with the X bit set for each of (user,group,other) with + * an R bit in the original permissions. If you want to do anything + * fancy like setgid or sticky bits, do it by hand. + */ + int dirperm = permissions; + if (permissions & S_IRUSR) + dirperm |= S_IXUSR; + if (permissions & S_IRGRP) + dirperm |= S_IXGRP; + if (permissions & S_IROTH) + dirperm |= S_IXOTH; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, + dirperm); +#endif + + if (NS_FAILED(CreateAllAncestors(dirperm))) + return NS_ERROR_FAILURE; + +#ifdef DEBUG_NSIFILE + fprintf(stderr, "nsIFile: Create(\"%s\") again\n", mPath.get()); +#endif + result = createFunc(mPath.get(), flags, permissions, _retval); + } + + return NSRESULT_FOR_RETURN(result); +} + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 permissions) +{ + PRFileDesc *junk = nsnull; + nsresult rv = CreateAndKeepOpen(type, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE | + PR_EXCL, + permissions, + &junk); + if (junk) + PR_Close(junk); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &fragment) +{ + if (fragment.IsEmpty()) + return NS_OK; + + // only one component of path can be appended + nsACString::const_iterator begin, end; + if (FindCharInReadable('/', fragment.BeginReading(begin), + fragment.EndReading(end))) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + return AppendRelativeNativePath(fragment); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &fragment) +{ + if (fragment.IsEmpty()) + return NS_OK; + + // No leading '/' + if (fragment.First() == '/') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (mPath.EqualsLiteral("/")) + mPath.Append(fragment); + else + mPath.Append(NS_LITERAL_CSTRING("/") + fragment); + + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + char resolved_path[PATH_MAX] = ""; + char *resolved_path_ptr = nsnull; + +#ifdef XP_BEOS + BEntry be_e(mPath.get(), true); + BPath be_p; + status_t err; + if ((err = be_e.GetPath(&be_p)) == B_OK) { + resolved_path_ptr = (char *)be_p.Path(); + PL_strncpyz(resolved_path, resolved_path_ptr, PATH_MAX - 1); + } +#else + resolved_path_ptr = realpath(mPath.get(), resolved_path); +#endif + // if there is an error, the return is null. + if (!resolved_path_ptr) + return NSRESULT_FOR_ERRNO(); + + mPath = resolved_path; + return NS_OK; +} + +void +nsLocalFile::LocateNativeLeafName(nsACString::const_iterator &begin, + nsACString::const_iterator &end) +{ + // XXX perhaps we should cache this?? + + mPath.BeginReading(begin); + mPath.EndReading(end); + + nsACString::const_iterator it = end; + nsACString::const_iterator stop = begin; + --stop; + while (--it != stop) { + if (*it == '/') { + begin = ++it; + return; + } + } + // else, the entire path is the leaf name (which means this + // isn't an absolute path... unexpected??) +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + aLeafName = Substring(begin, end); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + mPath.Replace(begin.get() - mPath.get(), Distance(begin, end), aLeafName); + InvalidateCache(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mPath; + return NS_OK; +} + +nsresult +nsLocalFile::GetNativeTargetPathName(nsIFile *newParent, + const nsACString &newName, + nsACString &_retval) +{ + nsresult rv; + nsCOMPtr oldParent; + + if (!newParent) { + if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent)))) + return rv; + newParent = oldParent.get(); + } else { + // check to see if our target directory exists + PRBool targetExists; + if (NS_FAILED(rv = newParent->Exists(&targetExists))) + return rv; + + if (!targetExists) { + // XXX create the new directory with some permissions + rv = newParent->Create(DIRECTORY_TYPE, 0700); + if (NS_FAILED(rv)) + return rv; + } else { + // make sure that the target is actually a directory + PRBool targetIsDirectory; + if (NS_FAILED(rv = newParent->IsDirectory(&targetIsDirectory))) + return rv; + if (!targetIsDirectory) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + nsACString::const_iterator nameBegin, nameEnd; + if (!newName.IsEmpty()) { + newName.BeginReading(nameBegin); + newName.EndReading(nameEnd); + } + else + LocateNativeLeafName(nameBegin, nameEnd); + + nsCAutoString dirName; + if (NS_FAILED(rv = newParent->GetNativePath(dirName))) + return rv; + + _retval = dirName + + NS_LITERAL_CSTRING("/") + + Substring(nameBegin, nameEnd); + return NS_OK; +} + +nsresult +nsLocalFile::CopyDirectoryTo(nsIFile *newParent) +{ + nsresult rv; + /* + * dirCheck is used for various boolean test results such as from Equals, + * Exists, isDir, etc. + */ + PRBool dirCheck, isSymlink; + PRUint32 oldPerms; + + if (NS_FAILED((rv = IsDirectory(&dirCheck)))) + return rv; + if (!dirCheck) + return CopyToNative(newParent, EmptyCString()); + + if (NS_FAILED(rv = Equals(newParent, &dirCheck))) + return rv; + if (dirCheck) { + // can't copy dir to itself + return NS_ERROR_INVALID_ARG; + } + + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) + return rv; + // get the dirs old permissions + if (NS_FAILED(rv = GetPermissions(&oldPerms))) + return rv; + if (!dirCheck) { + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) + return rv; + } else { // dir exists lets try to use leaf + nsCAutoString leafName; + if (NS_FAILED(rv = GetNativeLeafName(leafName))) + return rv; + if (NS_FAILED(rv = newParent->AppendNative(leafName))) + return rv; + if (NS_FAILED(rv = newParent->Exists(&dirCheck))) + return rv; + if (dirCheck) + return NS_ERROR_FILE_ALREADY_EXISTS; // dest exists + if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) + return rv; + } + + nsCOMPtr dirIterator; + if (NS_FAILED(rv = GetDirectoryEntries(getter_AddRefs(dirIterator)))) + return rv; + + PRBool hasMore = PR_FALSE; + while (dirIterator->HasMoreElements(&hasMore), hasMore) { + nsCOMPtr entry; + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(entry)); + if (NS_FAILED(rv)) + continue; + if (NS_FAILED(rv = entry->IsSymlink(&isSymlink))) + return rv; + if (NS_FAILED(rv = entry->IsDirectory(&dirCheck))) + return rv; + if (dirCheck && !isSymlink) { + nsCOMPtr destClone; + rv = newParent->Clone(getter_AddRefs(destClone)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr newDir(do_QueryInterface(destClone)); + if (NS_FAILED(rv = entry->CopyToNative(newDir, EmptyCString()))) { +#ifdef DEBUG + nsresult rv2; + nsCAutoString pathName; + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) + return rv2; + printf("Operation not supported: %s\n", pathName.get()); +#endif + if (rv == NS_ERROR_OUT_OF_MEMORY) + return rv; + continue; + } + } + } else { + if (NS_FAILED(rv = entry->CopyToNative(newParent, EmptyCString()))) { +#ifdef DEBUG + nsresult rv2; + nsCAutoString pathName; + if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) + return rv2; + printf("Operation not supported: %s\n", pathName.get()); +#endif + if (rv == NS_ERROR_OUT_OF_MEMORY) + return rv; + continue; + } + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName) +{ + nsresult rv; + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // we copy the parent here so 'newParent' remains immutable + nsCOMPtr workParent; + if (newParent) { + if (NS_FAILED(rv = newParent->Clone(getter_AddRefs(workParent)))) + return rv; + } else { + if (NS_FAILED(rv = GetParent(getter_AddRefs(workParent)))) + return rv; + } + + // check to see if we are a directory or if we are a file + PRBool isDirectory; + if (NS_FAILED(rv = IsDirectory(&isDirectory))) + return rv; + + nsCAutoString newPathName; + if (isDirectory) { + if (!newName.IsEmpty()) { + if (NS_FAILED(rv = workParent->AppendNative(newName))) + return rv; + } else { + if (NS_FAILED(rv = GetNativeLeafName(newPathName))) + return rv; + if (NS_FAILED(rv = workParent->AppendNative(newPathName))) + return rv; + } + if (NS_FAILED(rv = CopyDirectoryTo(workParent))) + return rv; + } else { + rv = GetNativeTargetPathName(workParent, newName, newPathName); + if (NS_FAILED(rv)) + return rv; + +#ifdef DEBUG_blizzard + printf("nsLocalFile::CopyTo() %s -> %s\n", mPath.get(), newPathName.get()); +#endif + + // actually create the file. + nsLocalFile *newFile = new nsLocalFile(); + if (!newFile) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr fileRef(newFile); // release on exit + + rv = newFile->InitWithNativePath(newPathName); + if (NS_FAILED(rv)) + return rv; + + // get the old permissions + PRUint32 myPerms; + GetPermissions(&myPerms); + + // Create the new file with the old file's permissions, even if write + // permission is missing. We can't create with write permission and + // then change back to myPerm on all filesystems (FAT on Linux, e.g.). + // But we can write to a read-only file on all Unix filesystems if we + // open it successfully for writing. + + PRFileDesc *newFD; + rv = newFile->CreateAndKeepOpen(NORMAL_FILE_TYPE, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, + myPerms, + &newFD); + if (NS_FAILED(rv)) + return rv; + + // open the old file, too + PRBool specialFile; + if (NS_FAILED(rv = IsSpecial(&specialFile))) { + PR_Close(newFD); + return rv; + } + if (specialFile) { +#ifdef DEBUG + printf("Operation not supported: %s\n", mPath.get()); +#endif + // make sure to clean up properly + PR_Close(newFD); + return NS_OK; + } + + PRFileDesc *oldFD; + rv = OpenNSPRFileDesc(PR_RDONLY, myPerms, &oldFD); + if (NS_FAILED(rv)) { + // make sure to clean up properly + PR_Close(newFD); + return rv; + } + +#ifdef DEBUG_blizzard + PRInt32 totalRead = 0; + PRInt32 totalWritten = 0; +#endif + char buf[BUFSIZ]; + PRInt32 bytesRead; + + while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) { +#ifdef DEBUG_blizzard + totalRead += bytesRead; +#endif + + // PR_Write promises never to do a short write + PRInt32 bytesWritten = PR_Write(newFD, buf, bytesRead); + if (bytesWritten < 0) { + bytesRead = -1; + break; + } + NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?"); + +#ifdef DEBUG_blizzard + totalWritten += bytesWritten; +#endif + } + +#ifdef DEBUG_blizzard + printf("read %d bytes, wrote %d bytes\n", + totalRead, totalWritten); +#endif + + // close the files + PR_Close(newFD); + PR_Close(oldFD); + + // check for read (or write) error after cleaning up + if (bytesRead < 0) + return NS_ERROR_OUT_OF_MEMORY; + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParent, const nsACString &newName) +{ + return CopyToNative(newParent, newName); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParent, const nsACString &newName) +{ + nsresult rv; + + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // check to make sure that we have a new parent + nsCAutoString newPathName; + rv = GetNativeTargetPathName(newParent, newName, newPathName); + if (NS_FAILED(rv)) + return rv; + + // try for atomic rename, falling back to copy/delete + if (rename(mPath.get(), newPathName.get()) < 0) { +#ifdef VMS + if (errno == EXDEV || errno == ENXIO) { +#else + if (errno == EXDEV) { +#endif + rv = CopyToNative(newParent, newName); + if (NS_SUCCEEDED(rv)) + rv = Remove(PR_TRUE); + } else { + rv = NSRESULT_FOR_ERRNO(); + } + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + CHECK_mPath(); + + VALIDATE_STAT_CACHE(); + PRBool isSymLink, isDir; + + nsresult rv = IsSymlink(&isSymLink); + if (NS_FAILED(rv)) + return rv; + + if (!recursive && isSymLink) + return NSRESULT_FOR_RETURN(unlink(mPath.get())); + + isDir = S_ISDIR(mCachedStat.st_mode); + InvalidateCache(); + if (isDir) { + if (recursive) { + nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + if (!dir) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr dirRef(dir); // release on exit + + rv = dir->Init(this, PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + PRBool more; + while (dir->HasMoreElements(&more), more) { + nsCOMPtr item; + rv = dir->GetNext(getter_AddRefs(item)); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + nsCOMPtr file = do_QueryInterface(item, &rv); + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + if (NS_FAILED(rv = file->Remove(recursive))) + return rv; + } + } + + if (rmdir(mPath.get()) == -1) + return NSRESULT_FOR_ERRNO(); + } else { + if (unlink(mPath.get()) == -1) + return NSRESULT_FOR_ERRNO(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModTime) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aLastModTime); + + PRFileInfo64 info; + if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) + return NSRESULT_FOR_ERRNO(); + + // PRTime is a 64 bit value + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModTime, info.modifyTime, usecPerMsec); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime) +{ + CHECK_mPath(); + + int result; + if (! LL_IS_ZERO(aLastModTime)) { + VALIDATE_STAT_CACHE(); + struct utimbuf ut; + ut.actime = mCachedStat.st_atime; + + // convert milliseconds to seconds since the unix epoch + double dTime; + LL_L2D(dTime, aLastModTime); + ut.modtime = (time_t) (dTime / PR_MSEC_PER_SEC); + result = utime(mPath.get(), &ut); + } else { + result = utime(mPath.get(), nsnull); + } + InvalidateCache(); + return NSRESULT_FOR_RETURN(result); +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModTimeOfLink) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aLastModTimeOfLink); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + LL_I2L(*aLastModTimeOfLink, (PRInt32)sbuf.st_mtime); + + // lstat returns st_mtime in seconds + PRInt64 msecPerSec; + LL_I2L(msecPerSec, PR_MSEC_PER_SEC); + LL_MUL(*aLastModTimeOfLink, *aLastModTimeOfLink, msecPerSec); + + return NS_OK; +} + +/* + * utime(2) may or may not dereference symlinks, joy. + */ +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink) +{ + return SetLastModifiedTime(aLastModTimeOfLink); +} + +/* + * Only send back permissions bits: maybe we want to send back the whole + * mode_t to permit checks against other file types? + */ + +#define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO)) + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + VALIDATE_STAT_CACHE(); + *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aPermissionsOfLink); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + *aPermissionsOfLink = NORMALIZE_PERMS(sbuf.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + CHECK_mPath(); + + InvalidateCache(); + + /* + * Race condition here: we should use fchmod instead, there's no way to + * guarantee the name still refers to the same file. + */ + if (chmod(mPath.get(), aPermissions) < 0) + return NSRESULT_FOR_ERRNO(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + return SetPermissions(aPermissions); +} + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG_POINTER(aFileSize); + *aFileSize = LL_ZERO; + VALIDATE_STAT_CACHE(); + +#if defined(VMS) + /* Only two record formats can report correct file content size */ + if ((mCachedStat.st_fab_rfm != FAB$C_STMLF) && + (mCachedStat.st_fab_rfm != FAB$C_STMCR)) { + return NS_ERROR_FAILURE; + } +#endif + + /* XXX autoconf for and use stat64 if available */ + if (!S_ISDIR(mCachedStat.st_mode)) { + LL_UI2L(*aFileSize, (PRUint32)mCachedStat.st_size); + } + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + CHECK_mPath(); + + PRInt32 size; + LL_L2I(size, aFileSize); + /* XXX truncate64? */ + InvalidateCache(); + if (truncate(mPath.get(), (off_t)size) == -1) + return NSRESULT_FOR_ERRNO(); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + CHECK_mPath(); + NS_ENSURE_ARG(aFileSize); + + struct stat sbuf; + if (lstat(mPath.get(), &sbuf) == -1) + return NSRESULT_FOR_ERRNO(); + /* XXX autoconf for and use lstat64 if available */ + LL_UI2L(*aFileSize, (PRUint32)sbuf.st_size); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); + + // These systems have the operations necessary to check disk space. + +#if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) + + // check to make sure that mPath is properly initialized + CHECK_mPath(); + + struct STATFS fs_buf; + + /* + * Members of the STATFS struct that you should know about: + * f_bsize = block size on disk. + * f_bavail = number of free blocks available to a non-superuser. + * f_bfree = number of total free blocks in file system. + */ + + if (STATFS(mPath.get(), &fs_buf) < 0) { + // The call to STATFS failed. +#ifdef DEBUG + printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n"); +#endif + return NS_ERROR_FAILURE; + } +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", + fs_buf.f_bsize * (fs_buf.f_bavail - 1)); +#endif + + /* + * The number of bytes free == The number of free blocks available to + * a non-superuser, minus one as a fudge factor, multiplied by the size + * of the aforementioned blocks. + */ + PRInt64 bsize, bavail; + + LL_I2L(bsize, fs_buf.f_bsize); + LL_I2L(bavail, fs_buf.f_bavail - 1); + LL_MUL(*aDiskSpaceAvailable, bsize, bavail); + return NS_OK; + +#else + /* + * This platform doesn't have statfs or statvfs. I'm sure that there's + * a way to check for free disk space on platforms that don't have statfs + * (I'm SURE they have df, for example). + * + * Until we figure out how to do that, lets be honest and say that this + * command isn't implemented properly for these platforms yet. + */ +#ifdef DEBUG + printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n"); +#endif + return NS_ERROR_NOT_IMPLEMENTED; + +#endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ + +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile **aParent) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + // if '/' we are at the top of the volume, return null + if (mPath.Equals("/")) + return NS_OK; + + // I promise to play nice + char *buffer = mPath.BeginWriting(), + *slashp = buffer; + + // find the last significant slash in buffer + slashp = strrchr(buffer, '/'); + NS_ASSERTION(slashp, "non-canonical mPath?"); + if (!slashp) + return NS_ERROR_FILE_INVALID_PATH; + + // for the case where we are at '/' + if (slashp == buffer) + slashp++; + + // temporarily terminate buffer at the last significant slash + char c = *slashp; + *slashp = '\0'; + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buffer), PR_TRUE, + getter_AddRefs(localFile)); + + // make buffer whole again + *slashp = c; + + if (NS_SUCCEEDED(rv) && localFile) + rv = CallQueryInterface(localFile, aParent); + return rv; +} + +/* + * The results of Exists, isWritable and isReadable are not cached. + */ + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), F_OK) == 0); + return NS_OK; +} + +#ifdef XP_BEOS +// access() is buggy in BeOS POSIX implementation, at least for BFS, using stat() instead +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + struct stat buf; + *_retval = (stat(mPath.get(), &buf) == 0); + *_retval = *_retval && (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH )); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} +#else +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), W_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), R_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + *_retval = (access(mPath.get(), X_OK) == 0); + if (*_retval || errno == EACCES) + return NS_OK; + return NSRESULT_FOR_ERRNO(); +} +#endif +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + VALIDATE_STAT_CACHE(); + *_retval = S_ISDIR(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + VALIDATE_STAT_CACHE(); + *_retval = S_ISREG(mCachedStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + nsACString::const_iterator begin, end; + LocateNativeLeafName(begin, end); + *_retval = (*begin == '.'); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + CHECK_mPath(); + + struct stat symStat; + lstat(mPath.get(), &symStat); + *_retval=S_ISLNK(symStat.st_mode); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + VALIDATE_STAT_CACHE(); + *_retval = S_ISCHR(mCachedStat.st_mode) || + S_ISBLK(mCachedStat.st_mode) || +#ifdef S_ISSOCK + S_ISSOCK(mCachedStat.st_mode) || +#endif + S_ISFIFO(mCachedStat.st_mode); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); + *_retval = PR_FALSE; + + nsresult rv; + nsCAutoString inPath; + + if (NS_FAILED(rv = inFile->GetNativePath(inPath))) + return rv; + + *_retval = !FILE_STRCMP(inPath.get(), mPath.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString inPath; + nsresult rv; + + if (NS_FAILED(rv = inFile->GetNativePath(inPath))) + return rv; + + *_retval = PR_FALSE; + + ssize_t len = mPath.Length(); + if (FILE_STRNCMP(mPath.get(), inPath.get(), len) == 0) { + // Now make sure that the |inFile|'s path has a separator at len, + // which implies that it has more components after len. + if (inPath[len] == '/') + *_retval = PR_TRUE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + CHECK_mPath(); + _retval.Truncate(); + + struct stat symStat; + lstat(mPath.get(), &symStat); + if (!S_ISLNK(symStat.st_mode)) + return NS_ERROR_FILE_INVALID_PATH; + + PRInt64 targetSize64; + if (NS_FAILED(GetFileSizeOfLink(&targetSize64))) + return NS_ERROR_FAILURE; + + PRInt32 size; + LL_L2I(size, targetSize64); + char *target = (char *)nsMemory::Alloc(size + 1); + if (!target) + return NS_ERROR_OUT_OF_MEMORY; + + if (readlink(mPath.get(), target, (size_t)size) < 0) { + nsMemory::Free(target); + return NSRESULT_FOR_ERRNO(); + } + target[size] = '\0'; + + nsresult rv; + PRBool isSymlink; + nsCOMPtr self(this); + nsCOMPtr parent; + while (NS_SUCCEEDED(rv = self->GetParent(getter_AddRefs(parent)))) { + NS_ASSERTION(parent != nsnull, "no parent?!"); + + if (target[0] != '/') { + nsCOMPtr localFile(do_QueryInterface(parent, &rv)); + if (NS_FAILED(rv)) + break; + if (NS_FAILED(rv = localFile->AppendRelativeNativePath(nsDependentCString(target)))) + break; + if (NS_FAILED(rv = localFile->GetNativePath(_retval))) + break; + if (NS_FAILED(rv = parent->IsSymlink(&isSymlink))) + break; + self = parent; + } else { + nsCOMPtr localFile; + rv = NS_NewNativeLocalFile(nsDependentCString(target), PR_TRUE, + getter_AddRefs(localFile)); + if (NS_FAILED(rv)) + break; + if (NS_FAILED(rv = localFile->IsSymlink(&isSymlink))) + break; + _retval = target; // XXX can we avoid this buffer copy? + self = do_QueryInterface(localFile); + } + if (NS_FAILED(rv) || !isSymlink) + break; + + const nsPromiseFlatCString &flatRetval = PromiseFlatCString(_retval); + + // strip off any and all trailing '/' + PRInt32 len = strlen(target); + while (target[len-1] == '/' && len > 1) + target[--len] = '\0'; + if (lstat(flatRetval.get(), &symStat) < 0) { + rv = NSRESULT_FOR_ERRNO(); + break; + } + if (!S_ISLNK(symStat.st_mode)) { + rv = NS_ERROR_FILE_INVALID_PATH; + break; + } + size = symStat.st_size; + if (readlink(flatRetval.get(), target, size) < 0) { + rv = NSRESULT_FOR_ERRNO(); + break; + } + target[size] = '\0'; + + _retval.Truncate(); + } + + nsMemory::Free(target); + + if (NS_FAILED(rv)) + _retval.Truncate(); + return rv; +} + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries) +{ + nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); + if (!dir) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(dir); + nsresult rv = dir->Init(this, PR_FALSE); + if (NS_FAILED(rv)) { + *entries = nsnull; + NS_RELEASE(dir); + } else { + *entries = dir; // transfer reference + } + + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary **_retval) +{ + CHECK_mPath(); + NS_ENSURE_ARG_POINTER(_retval); + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + + *_retval = PR_LoadLibrary(mPath.get()); + + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath.get()); + + if (!*_retval) + return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +#ifdef XP_BEOS +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + BPath bPath(mPath.get()); + bPath.GetParent(&bPath); + entry_ref ref; + get_ref_for_path(bPath.Path(),&ref); + BMessage message(B_REFS_RECEIVED); + message.AddRef("refs",&ref); + BMessenger messenger("application/x-vnd.Be-TRAK"); + messenger.SendMessage(&message); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + entry_ref ref; + get_ref_for_path (mPath.get(), &ref); + be_roster->Launch (&ref); + + return NS_OK; +} +#else +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + return NS_ERROR_FAILURE; +} +#endif + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followSymlinks, nsILocalFile **result) +{ + nsLocalFile *file = new nsLocalFile(); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// unicode support +//----------------------------------------------------------------------------- + +#define SET_UCS(func, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ + if (NS_FAILED(rv)) \ + return rv; \ + return (func)(buf); \ + } + +#define GET_UCS(func, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = (func)(buf); \ + if (NS_FAILED(rv)) return rv; \ + return NS_CopyNativeToUnicode(buf, ucsArg); \ + } + +#define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \ + { \ + nsCAutoString buf; \ + nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ + if (NS_FAILED(rv)) \ + return rv; \ + return (func)(opaqueArg, buf); \ + } + +// Unicode interface Wrapper +nsresult +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + SET_UCS(InitWithNativePath, filePath); +} +nsresult +nsLocalFile::Append(const nsAString &node) +{ + SET_UCS(AppendNative, node); +} +nsresult +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + SET_UCS(AppendRelativeNativePath, node); +} +nsresult +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + GET_UCS(GetNativeLeafName, aLeafName); +} +nsresult +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + SET_UCS(SetNativeLeafName, aLeafName); +} +nsresult +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mPath, _retval); +} +nsresult +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(CopyToNative , newParentDir, newName); +} +nsresult +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(CopyToFollowingLinksNative , newParentDir, newName); +} +nsresult +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName); +} +nsresult +nsLocalFile::GetTarget(nsAString &_retval) +{ + GET_UCS(GetNativeTarget, _retval); +} +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) + return rv; + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//----------------------------------------------------------------------------- +// global init/shutdown +//----------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ +} + +void +nsLocalFile::GlobalShutdown() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h new file mode 100644 index 00000000..a994e1a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileUnix.h @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Implementation of nsIFile for ``Unixy'' systems. + */ + +#ifndef _nsLocalFileUNIX_H_ +#define _nsLocalFileUNIX_H_ + +#include +#include +#include + +#include "nscore.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +/** + * we need these for statfs() + */ +#ifdef HAVE_SYS_STATVFS_H + #if defined(__osf__) && defined(__DECCXX) + extern "C" int statvfs(const char *, struct statvfs *); + #endif + #include +#endif + +#ifdef HAVE_SYS_STATFS_H + #include +#endif + +#ifdef HAVE_STATVFS + #define STATFS statvfs +#else + #define STATFS statfs +#endif + +// so we can statfs on freebsd +#if defined(__FreeBSD__) + #define HAVE_SYS_STATFS_H + #define STATFS statfs + #include + #include +#endif + +class NS_COM nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFile + NS_DECL_NSIFILE + + // nsILocalFile + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + nsLocalFile(const nsLocalFile& other); + ~nsLocalFile() {} + +protected: + struct stat mCachedStat; + nsCString mPath; + PRPackedBool mHaveCachedStat; + + void LocateNativeLeafName(nsACString::const_iterator &, + nsACString::const_iterator &); + + nsresult CopyDirectoryTo(nsIFile *newParent); + nsresult CreateAllAncestors(PRUint32 permissions); + nsresult GetNativeTargetPathName(nsIFile *newParent, + const nsACString &newName, + nsACString &_retval); + + void InvalidateCache() { + mHaveCachedStat = PR_FALSE; + } + nsresult FillStatCache(); + + nsresult CreateAndKeepOpen(PRUint32 type, PRIntn flags, + PRUint32 permissions, PRFileDesc **_retval); +}; + +#endif /* _nsLocalFileUNIX_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp new file mode 100644 index 00000000..63414fc3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.cpp @@ -0,0 +1,2440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Dean Tessman + * Brodie Thiesfield + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsLocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "nsISimpleEnumerator.h" +#include "nsIComponentManager.h" +#include "prtypes.h" +#include "prio.h" + +#include "nsXPIDLString.h" +#include "nsReadableUtils.h" + +#include +#include + +#include "shellapi.h" +#include "shlguid.h" + +#include +#include +#include +#include + +#include "nsXPIDLString.h" +#include "prproces.h" +#include "nsITimelineService.h" + +#include "nsAutoLock.h" +#include "SpecialSystemDirectory.h" + +// _mbsstr isn't declared in w32api headers but it's there in the libs +#ifdef __MINGW32__ +extern "C" { +unsigned char *_mbsstr( const unsigned char *str, + const unsigned char *substr ); +} +#endif + +class nsDriveEnumerator : public nsISimpleEnumerator +{ +public: + nsDriveEnumerator(); + virtual ~nsDriveEnumerator(); + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + nsresult Init(); +private: + /* mDrives and mLetter share data + * Init sets them. + * HasMoreElements reads mLetter. + * GetNext advances mLetter. + */ + nsCString mDrives; + const char *mLetter; +}; + +//---------------------------------------------------------------------------- +// short cut resolver +//---------------------------------------------------------------------------- + +class ShortcutResolver +{ +public: + ShortcutResolver(); + // nonvirtual since we're not subclassed + ~ShortcutResolver(); + + nsresult Init(); + nsresult Resolve(const WCHAR* in, char* out); + +private: + PRLock* mLock; + IPersistFile* mPersistFile; + IShellLink* mShellLink; +}; + +ShortcutResolver::ShortcutResolver() +{ + mLock = nsnull; + mPersistFile = nsnull; + mShellLink = nsnull; +} + +ShortcutResolver::~ShortcutResolver() +{ + if (mLock) + PR_DestroyLock(mLock); + + // Release the pointer to the IPersistFile interface. + if (mPersistFile) + mPersistFile->Release(); + + // Release the pointer to the IShellLink interface. + if(mShellLink) + mShellLink->Release(); + + CoUninitialize(); +} + +nsresult +ShortcutResolver::Init() +{ + CoInitialize(NULL); // FIX: we should probably move somewhere higher up during startup + + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_FAILURE; + + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShellLink, + (void**)&mShellLink); + if (SUCCEEDED(hres)) + { + // Get a pointer to the IPersistFile interface. + hres = mShellLink->QueryInterface(IID_IPersistFile, (void**)&mPersistFile); + } + + if (mPersistFile == nsnull || mShellLink == nsnull) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// |out| must be an allocated buffer of size MAX_PATH +nsresult +ShortcutResolver::Resolve(const WCHAR* in, char* out) +{ + nsAutoLock lock(mLock); + + // see if we can Load the path. + HRESULT hres = mPersistFile->Load(in, STGM_READ); + + if (FAILED(hres)) + return NS_ERROR_FAILURE; + + // Resolve the link. + hres = mShellLink->Resolve(nsnull, SLR_NO_UI ); + + if (FAILED(hres)) + return NS_ERROR_FAILURE; + + WIN32_FIND_DATA wfd; + // Get the path to the link target. + hres = mShellLink->GetPath( out, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + if (FAILED(hres)) + return NS_ERROR_FAILURE; + return NS_OK; +} + +static ShortcutResolver * gResolver = nsnull; + +static nsresult NS_CreateShortcutResolver() +{ + gResolver = new ShortcutResolver(); + if (!gResolver) + return NS_ERROR_OUT_OF_MEMORY; + + return gResolver->Init(); +} + +static void NS_DestroyShortcutResolver() +{ + delete gResolver; + gResolver = nsnull; +} + + +//----------------------------------------------------------------------------- +// static helper functions +//----------------------------------------------------------------------------- + +// certainly not all the error that can be +// encountered, but many of them common ones +static nsresult ConvertWinError(DWORD winErr) +{ + nsresult rv; + + switch (winErr) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rv = NS_ERROR_FILE_NOT_FOUND; + break; + case ERROR_ACCESS_DENIED: + case ERROR_NOT_SAME_DEVICE: + rv = NS_ERROR_FILE_ACCESS_DENIED; + break; + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_INVALID_BLOCK: + case ERROR_INVALID_HANDLE: + case ERROR_ARENA_TRASHED: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + case ERROR_CURRENT_DIRECTORY: + rv = NS_ERROR_FILE_DIR_NOT_EMPTY; + break; + case ERROR_WRITE_PROTECT: + rv = NS_ERROR_FILE_READ_ONLY; + break; + case ERROR_HANDLE_DISK_FULL: + rv = NS_ERROR_FILE_TOO_BIG; + break; + case ERROR_FILE_EXISTS: + case ERROR_ALREADY_EXISTS: + case ERROR_CANNOT_MAKE: + rv = NS_ERROR_FILE_ALREADY_EXISTS; + break; + case 0: + rv = NS_OK; + break; + default: + rv = NS_ERROR_FAILURE; + break; + } + return rv; +} + +// definition of INVALID_SET_FILE_POINTER from VC.NET header files +// it doesn't appear to be defined by VC6 +#ifndef INVALID_SET_FILE_POINTER +# define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif +// same goes for INVALID_FILE_ATTRIBUTES +#ifndef INVALID_FILE_ATTRIBUTES +# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +// as suggested in the MSDN documentation on SetFilePointer +static __int64 +MyFileSeek64(HANDLE aHandle, __int64 aDistance, DWORD aMoveMethod) +{ + LARGE_INTEGER li; + + li.QuadPart = aDistance; + li.LowPart = SetFilePointer(aHandle, li.LowPart, &li.HighPart, aMoveMethod); + if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) + { + li.QuadPart = -1; + } + + return li.QuadPart; +} + +static PRBool +IsShortcutPath(const char *path) +{ + // Under Windows, the shortcuts are just files with a ".lnk" extension. + // Note also that we don't resolve links in the middle of paths. + // i.e. "c:\foo.lnk\bar.txt" is invalid. + NS_ABORT_IF_FALSE(path, "don't pass nulls"); + const char * ext = (const char *) _mbsrchr((const unsigned char *)path, '.'); + if (!ext || 0 != stricmp(ext + 1, "lnk")) + return PR_FALSE; + return PR_TRUE; +} + +//----------------------------------------------------------------------------- +// nsDirEnumerator +//----------------------------------------------------------------------------- + +class nsDirEnumerator : public nsISimpleEnumerator +{ + public: + + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mDir(nsnull) + { + } + + nsresult Init(nsILocalFile* parent) + { + nsCAutoString filepath; + parent->GetNativeTarget(filepath); + + if (filepath.IsEmpty()) + { + parent->GetNativePath(filepath); + } + + if (filepath.IsEmpty()) + { + return NS_ERROR_UNEXPECTED; + } + + mDir = PR_OpenDir(filepath.get()); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mParent = parent; + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) + { + nsresult rv; + if (mNext == nsnull && mDir) + { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) + { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + nsCOMPtr file; + rv = mParent->Clone(getter_AddRefs(file)); + if (NS_FAILED(rv)) + return rv; + + rv = file->AppendNative(nsDependentCString(entry->name)); + if (NS_FAILED(rv)) + return rv; + + // make sure the thing exists. If it does, try the next one. + PRBool exists; + rv = file->Exists(&exists); + if (NS_FAILED(rv) || !exists) + { + return HasMoreElements(result); + } + + mNext = do_QueryInterface(file); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) + { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + NS_IF_ADDREF(*result); + + mNext = nsnull; + return NS_OK; + } + + // dtor can be non-virtual since there are no subclasses, but must be + // public to use the class on the stack. + ~nsDirEnumerator() + { + if (mDir) + { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + } + + protected: + PRDir* mDir; + nsCOMPtr mParent; + nsCOMPtr mNext; +}; + +NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) + + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +nsLocalFile::nsLocalFile() + : mFollowSymlinks(PR_FALSE) +{ + MakeDirty(); + memset(&mFileInfo64, 0, sizeof(mFileInfo64)); +} + +NS_METHOD +nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); + + nsLocalFile* inst = new nsLocalFile(); + if (inst == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = inst->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) + { + delete inst; + return rv; + } + return NS_OK; +} + + +//----------------------------------------------------------------------------- +// nsLocalFile::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsLocalFile, nsILocalFile, nsIFile) + + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +nsLocalFile::nsLocalFile(const nsLocalFile& other) + : mDirty(other.mDirty) + , mFollowSymlinks(other.mFollowSymlinks) + , mWorkingPath(other.mWorkingPath) + , mResolvedPath(other.mResolvedPath) + , mFileInfo64(other.mFileInfo64) +{ +} + +// Resolve the shortcut file from mWorkingPath and write the path +// it points to into mResolvedPath. +nsresult +nsLocalFile::ResolveShortcut() +{ + // we can't do anything without the resolver + if (!gResolver) + return NS_ERROR_FAILURE; + + // allocate the memory for the result of the resolution + nsAutoString ucsBuf; + NS_CopyNativeToUnicode(mWorkingPath, ucsBuf); + + mResolvedPath.SetLength(MAX_PATH); + char *resolvedPath = mResolvedPath.BeginWriting(); + + // resolve this shortcut + nsresult rv = gResolver->Resolve(ucsBuf.get(), resolvedPath); + + size_t len = NS_FAILED(rv) ? 0 : strlen(resolvedPath); + mResolvedPath.SetLength(len); + + return rv; +} + +// Resolve any shortcuts and stat the resolved path. After a successful return +// the path is guaranteed valid and the members of mFileInfo64 can be used. +nsresult +nsLocalFile::ResolveAndStat() +{ + // if we aren't dirty then we are already done + if (!mDirty) + return NS_OK; + + // we can't resolve/stat anything that isn't a valid NSPR addressable path + if (mWorkingPath.IsEmpty()) + return NS_ERROR_FILE_INVALID_PATH; + + // this is usually correct + mResolvedPath.Assign(mWorkingPath); + + // slutty hack designed to work around bug 134796 until it is fixed + char temp[4]; + const char *nsprPath = mWorkingPath.get(); + if (mWorkingPath.Length() == 2 && mWorkingPath.CharAt(1) == ':') + { + temp[0] = mWorkingPath[0]; + temp[1] = mWorkingPath[1]; + temp[2] = '\\'; + temp[3] = '\0'; + nsprPath = temp; + } + + // first we will see if the working path exists. If it doesn't then + // there is nothing more that can be done + PRStatus status = PR_GetFileInfo64(nsprPath, &mFileInfo64); + if (status != PR_SUCCESS) + return NS_ERROR_FILE_NOT_FOUND; + + // if this isn't a shortcut file or we aren't following symlinks then we're done + if (!mFollowSymlinks + || mFileInfo64.type != PR_FILE_FILE + || !IsShortcutPath(mWorkingPath.get())) + { + mDirty = PR_FALSE; + return NS_OK; + } + + // we need to resolve this shortcut to what it points to, this will + // set mResolvedPath. Even if it fails we need to have the resolved + // path equal to working path for those functions that always use + // the resolved path. + nsresult rv = ResolveShortcut(); + if (NS_FAILED(rv)) + { + mResolvedPath.Assign(mWorkingPath); + return rv; + } + + // get the details of the resolved path + status = PR_GetFileInfo64(mResolvedPath.get(), &mFileInfo64); + if (status != PR_SUCCESS) + return NS_ERROR_FILE_NOT_FOUND; + + mDirty = PR_FALSE; + return NS_OK; +} + + +//----------------------------------------------------------------------------- +// nsLocalFile::nsIFile,nsILocalFile +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +nsLocalFile::Clone(nsIFile **file) +{ + // Just copy-construct ourselves + *file = new nsLocalFile(*this); + if (!*file) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(*file); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::InitWithNativePath(const nsACString &filePath) +{ + MakeDirty(); + + nsACString::const_iterator begin, end; + filePath.BeginReading(begin); + filePath.EndReading(end); + + // input string must not be empty + if (begin == end) + return NS_ERROR_FAILURE; + + char firstChar = *begin; + char secondChar = *(++begin); + + // just do a sanity check. if it has any forward slashes, it is not a Native path + // on windows. Also, it must have a colon at after the first char. + + char *path = nsnull; + PRInt32 pathLen = 0; + + if ( ( (secondChar == ':') && !FindCharInReadable('/', begin, end) ) || // normal path + ( (firstChar == '\\') && (secondChar == '\\') ) ) // network path + { + // This is a native path + path = ToNewCString(filePath); + pathLen = filePath.Length(); + } + + if (path == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // kill any trailing '\' provided it isn't the second char of DBCS + PRInt32 len = pathLen - 1; + if (path[len] == '\\' && + (!::IsDBCSLeadByte(path[len-1]) || + _mbsrchr((const unsigned char *)path, '\\') == (const unsigned char *)path+len)) + { + path[len] = '\0'; + pathLen = len; + } + + mWorkingPath.Adopt(path, pathLen); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = PR_Open(mResolvedPath.get(), flags, mode); + if (*_retval) + return NS_OK; + + return NS_ErrorAccordingToNSPR(); +} + + +NS_IMETHODIMP +nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + *_retval = fopen(mResolvedPath.get(), mode); + if (*_retval) + return NS_OK; + + return NS_ERROR_FAILURE; +} + + + +NS_IMETHODIMP +nsLocalFile::Create(PRUint32 type, PRUint32 attributes) +{ + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // create directories to target + // + // A given local file can be either one of these forms: + // + // - normal: X:\some\path\on\this\drive + // ^--- start here + // + // - UNC path: \\machine\volume\some\path\on\this\drive + // ^--- start here + // + // Skip the first 'X:\' for the first form, and skip the first full + // '\\machine\volume\' segment for the second form. + + const unsigned char* path = (const unsigned char*) mResolvedPath.get(); + if (path[0] == '\\' && path[1] == '\\') + { + // dealing with a UNC path here; skip past '\\machine\' + path = _mbschr(path + 2, '\\'); + if (!path) + return NS_ERROR_FILE_INVALID_PATH; + ++path; + } + + // search for first slash after the drive (or volume) name + unsigned char* slash = _mbschr(path, '\\'); + + if (slash) + { + // skip the first '\\' + ++slash; + slash = _mbschr(slash, '\\'); + + while (slash) + { + *slash = '\0'; + + if (!CreateDirectoryA(mResolvedPath.get(), NULL)) { + rv = ConvertWinError(GetLastError()); + // perhaps the base path already exists, or perhaps we don't have + // permissions to create the directory. NOTE: access denied could + // occur on a parent directory even though it exists. + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && + rv != NS_ERROR_FILE_ACCESS_DENIED) + return rv; + } + *slash = '\\'; + ++slash; + slash = _mbschr(slash, '\\'); + } + } + + if (type == NORMAL_FILE_TYPE) + { + PRFileDesc* file = PR_Open(mResolvedPath.get(), PR_RDONLY | PR_CREATE_FILE | PR_APPEND | PR_EXCL, attributes); + if (!file) return NS_ERROR_FILE_ALREADY_EXISTS; + + PR_Close(file); + return NS_OK; + } + + if (type == DIRECTORY_TYPE) + { + if (!CreateDirectoryA(mResolvedPath.get(), NULL)) + return ConvertWinError(GetLastError()); + else + return NS_OK; + } + + return NS_ERROR_FILE_UNKNOWN_TYPE; +} + +NS_IMETHODIMP +nsLocalFile::AppendNative(const nsACString &node) +{ + // append this path, multiple components are not permitted + return AppendNativeInternal(PromiseFlatCString(node), PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::AppendRelativeNativePath(const nsACString &node) +{ + // append this path, multiple components are permitted + return AppendNativeInternal(PromiseFlatCString(node), PR_TRUE); +} + +nsresult +nsLocalFile::AppendNativeInternal(const nsAFlatCString &node, PRBool multipleComponents) +{ + if (node.IsEmpty()) + return NS_OK; + + // check the relative path for validity + const unsigned char * nodePath = (const unsigned char *) node.get(); + if (*nodePath == '\\' // can't start with an '\' + || _mbschr(nodePath, '/') // can't contain / + || node.Equals("..")) // can't be .. + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (multipleComponents) + { + // can't contain .. as a path component. Ensure that the valid components + // "foo..foo", "..foo", and "foo.." are not falsely detected, but the invalid + // paths "..\", "foo\..", "foo\..\foo", "..\foo", etc are. + unsigned char * doubleDot = _mbsstr(nodePath, (unsigned char *)"\\.."); + while (doubleDot) + { + doubleDot += 3; + if (*doubleDot == '\0' || *doubleDot == '\\') + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + doubleDot = _mbsstr(doubleDot, (unsigned char *)"\\.."); + } + if (0 == _mbsncmp(nodePath, (unsigned char *)"..\\", 3)) // catches the remaining cases of prefixes + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + } + else if (_mbschr(nodePath, '\\')) // single components can't contain '\' + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + MakeDirty(); + + mWorkingPath.Append(NS_LITERAL_CSTRING("\\") + node); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Normalize() +{ + // XXX See bug 187957 comment 18 for possible problems with this implementation. + + if (mWorkingPath.IsEmpty()) + return NS_OK; + + // work in unicode for ease + nsAutoString path; + NS_CopyNativeToUnicode(mWorkingPath, path); + + // find the index of the root backslash for the path. Everything before + // this is considered fully normalized and cannot be ascended beyond + // using ".." For a local drive this is the first slash (e.g. "c:\"). + // For a UNC path it is the slash following the share name + // (e.g. "\\server\share\"). + PRInt32 rootIdx = 2; // default to local drive + if (path.First() == '\\') // if a share then calculate the rootIdx + { + rootIdx = path.FindChar('\\', 2); // skip \\ in front of the server + if (rootIdx == kNotFound) + return NS_OK; // already normalized + rootIdx = path.FindChar('\\', rootIdx+1); + if (rootIdx == kNotFound) + return NS_OK; // already normalized + } + else if (path.CharAt(rootIdx) != '\\') + { + // The path has been specified relative to the current working directory + // for that drive. To normalize it, the current working directory for + // that drive needs to be inserted before the supplied relative path + // which will provide an absolute path (and the rootIdx will still be 2). + char cwd[MAX_PATH]; + char * pcwd = cwd; + int drive = toupper(path.First()) - 'A' + 1; + if (!_getdcwd(drive, pcwd, MAX_PATH)) + pcwd = _getdcwd(drive, 0, 0); + if (!pcwd) + return NS_ERROR_OUT_OF_MEMORY; + + nsAutoString currentDir; + NS_CopyNativeToUnicode(nsDependentCString(pcwd), currentDir); + if (pcwd != cwd) + free(pcwd); + + if (currentDir.Last() == '\\') + path.Replace(0, 2, currentDir); + else + path.Replace(0, 2, currentDir + NS_LITERAL_STRING("\\")); + } + NS_POSTCONDITION(0 < rootIdx && rootIdx < (PRInt32)path.Length(), "rootIdx is invalid"); + NS_POSTCONDITION(path.CharAt(rootIdx) == '\\', "rootIdx is invalid"); + + // if there is nothing following the root path then it is already normalized + if (rootIdx + 1 == (PRInt32)path.Length()) + return NS_OK; + + // assign the root + nsAutoString normal; + const PRUnichar * pathBuffer = path.get(); // simplify access to the buffer + normal.SetCapacity(path.Length()); // it won't ever grow longer + normal.Assign(pathBuffer, rootIdx); + + // Normalize the path components. The actions taken are: + // + // "\\" condense to single backslash + // "." remove from path + // ".." up a directory + // "..." remove from path (any number of dots > 2) + // + // The last form is something that Windows 95 and 98 supported and + // is a shortcut for changing up multiple directories. Windows XP + // and ilk ignore it in a path, as is done here. + PRInt32 len, begin, end = rootIdx; + while (end < (PRInt32)path.Length()) + { + // find the current segment (text between the backslashes) to + // be examined, this will set the following variables: + // begin == index of first char in segment + // end == index 1 char after last char in segment + // len == length of segment + begin = end + 1; + end = path.FindChar('\\', begin); + if (end == kNotFound) + end = path.Length(); + len = end - begin; + + // ignore double backslashes + if (len == 0) + continue; + + // len != 0, and interesting paths always begin with a dot + if (pathBuffer[begin] == '.') + { + // ignore single dots + if (len == 1) + continue; + + // handle multiple dots + if (len >= 2 && pathBuffer[begin+1] == '.') + { + // back up a path component on double dot + if (len == 2) + { + PRInt32 prev = normal.RFindChar('\\'); + if (prev >= rootIdx) + normal.Truncate(prev); + continue; + } + + // length is > 2 and the first two characters are dots. + // if the rest of the string is dots, then ignore it. + int idx = len - 1; + for (; idx >= 2; --idx) + { + if (pathBuffer[begin+idx] != '.') + break; + } + + // this is true if the loop above didn't break + // and all characters in this segment are dots. + if (idx < 2) + continue; + } + } + + // add the current component to the path, including the preceding backslash + normal.Append(pathBuffer + begin - 1, len + 1); + } + + NS_CopyUnicodeToNative(normal, mWorkingPath); + MakeDirty(); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetNativeLeafName(nsACString &aLeafName) +{ + aLeafName.Truncate(); + + const char* temp = mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp, '\\'); + + // if the working path is just a node without any lashes. + if (leaf == nsnull) + leaf = temp; + else + leaf++; + + aLeafName.Assign(leaf); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) +{ + MakeDirty(); + + const unsigned char* temp = (const unsigned char*) mWorkingPath.get(); + if(temp == nsnull) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr(temp, '\\') - temp); + if (offset) + { + mWorkingPath.Truncate(offset+1); + } + mWorkingPath.Append(aLeafName); + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetNativePath(nsACString &_retval) +{ + _retval = mWorkingPath; + return NS_OK; +} + +nsresult +nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, const nsACString &newName, + PRBool followSymlinks, PRBool move) +{ + nsresult rv; + nsCAutoString filePath; + + // get the path that we are going to copy to. + // Since windows does not know how to auto + // resolve shortcuts, we must work with the + // target. + nsCAutoString destPath; + destParent->GetNativeTarget(destPath); + + destPath.Append("\\"); + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + sourceFile->GetNativeLeafName(aFileName); + destPath.Append(aFileName); + } + else + { + destPath.Append(newName); + } + + + if (followSymlinks) + { + rv = sourceFile->GetNativeTarget(filePath); + if (filePath.IsEmpty()) + rv = sourceFile->GetNativePath(filePath); + } + else + { + rv = sourceFile->GetNativePath(filePath); + } + + if (NS_FAILED(rv)) + return rv; + + int copyOK; + + if (!move) + copyOK = CopyFile(filePath.get(), destPath.get(), PR_TRUE); + else + { + // What we have to do is check to see if the destPath exists. If it + // does, we have to move it out of the say so that MoveFile will + // succeed. However, we don't want to just remove it since MoveFile + // can fail leaving us without a file. + + nsCAutoString backup; + PRFileInfo64 fileInfo64; + PRStatus status = PR_GetFileInfo64(destPath.get(), &fileInfo64); + if (status == PR_SUCCESS) + { + + // the file exists. Check to make sure it is not a directory, + // then move it out of the way. + if (fileInfo64.type == PR_FILE_FILE) + { + backup.Append(destPath); + backup.Append(".moztmp"); + + // remove any existing backup file that we may already have. + // maybe we should be doing some kind of unique naming here, + // but why bother. + remove(backup.get()); + + // move destination file to backup file + copyOK = MoveFile(destPath.get(), backup.get()); + if (!copyOK) + { + // I guess we can't do the backup copy, so return. + rv = ConvertWinError(GetLastError()); + return rv; + } + } + } + // move source file to destination file + copyOK = MoveFile(filePath.get(), destPath.get()); + + if (!backup.IsEmpty()) + { + if (copyOK) + { + // remove the backup copy. + remove(backup.get()); + } + else + { + // restore backup + int backupOk = MoveFile(backup.get(), destPath.get()); + NS_ASSERTION(backupOk, "move backup failed"); + } + } + } + if (!copyOK) // CopyFile and MoveFile returns non-zero if succeeds (backward if you ask me). + rv = ConvertWinError(GetLastError()); + + return rv; +} + + +nsresult +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsACString &newName, PRBool followSymlinks, PRBool move) +{ + nsCOMPtr newParentDir = aParentDir; + // check to see if this exists, otherwise return an error. + // we will check this by resolving. If the user wants us + // to follow links, then we are talking about the target, + // hence we can use the |followSymlinks| parameter. + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + if (!newParentDir) + { + // no parent was specified. We must rename. + + if (newName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + rv = GetParent(getter_AddRefs(newParentDir)); + if (NS_FAILED(rv)) + return rv; + } + + if (!newParentDir) + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + + // make sure it exists and is a directory. Create it if not there. + PRBool exists; + newParentDir->Exists(&exists); + if (!exists) + { + rv = newParentDir->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + PRBool isDir; + newParentDir->IsDirectory(&isDir); + if (isDir == PR_FALSE) + { + if (followSymlinks) + { + PRBool isLink; + newParentDir->IsSymlink(&isLink); + if (isLink) + { + nsCAutoString target; + newParentDir->GetNativeTarget(target); + + nsCOMPtr realDest = new nsLocalFile(); + if (realDest == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + rv = realDest->InitWithNativePath(target); + + if (NS_FAILED(rv)) + return rv; + + return CopyMove(realDest, newName, followSymlinks, move); + } + } + else + { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + } + + // check to see if we are a directory, if so enumerate it. + + PRBool isDir; + IsDirectory(&isDir); + PRBool isSymlink; + IsSymlink(&isSymlink); + + if (!isDir || (isSymlink && !followSymlinks)) + { + rv = CopySingleFile(this, newParentDir, newName, followSymlinks, move); + if (NS_FAILED(rv)) + return rv; + } + else + { + // create a new target destination in the new parentDir; + nsCOMPtr target; + rv = newParentDir->Clone(getter_AddRefs(target)); + + if (NS_FAILED(rv)) + return rv; + + nsCAutoString allocatedNewName; + if (newName.IsEmpty()) + { + PRBool isLink; + IsSymlink(&isLink); + if (isLink) + { + nsCAutoString temp; + GetNativeTarget(temp); + const char* leaf = (const char*) _mbsrchr((const unsigned char*) temp.get(), '\\'); + if (leaf[0] == '\\') + leaf++; + allocatedNewName = leaf; + } + else + { + GetNativeLeafName(allocatedNewName);// this should be the leaf name of the + } + } + else + { + allocatedNewName = newName; + } + + rv = target->AppendNative(allocatedNewName); + if (NS_FAILED(rv)) + return rv; + + allocatedNewName.Truncate(); + + // check if the destination directory already exists + target->Exists(&exists); + if (!exists) + { + // if the destination directory cannot be created, return an error + rv = target->Create(DIRECTORY_TYPE, 0644); // TODO, what permissions should we use + if (NS_FAILED(rv)) + return rv; + } + else + { + // check if the destination directory is writable and empty + PRBool isWritable; + + target->IsWritable(&isWritable); + if (!isWritable) + return NS_ERROR_FILE_ACCESS_DENIED; + + nsCOMPtr targetIterator; + rv = target->GetDirectoryEntries(getter_AddRefs(targetIterator)); + + PRBool more; + targetIterator->HasMoreElements(&more); + // return error if target directory is not empty + if (more) + return NS_ERROR_FILE_DIR_NOT_EMPTY; + } + + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); + if (NS_FAILED(rv)) { + NS_WARNING("dirEnum initalization failed"); + return rv; + } + + PRBool more; + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) + { + nsCOMPtr item; + nsCOMPtr file; + dirEnum.GetNext(getter_AddRefs(item)); + file = do_QueryInterface(item); + if (file) + { + PRBool isDir, isLink; + + file->IsDirectory(&isDir); + file->IsSymlink(&isLink); + + if (move) + { + if (followSymlinks) + return NS_ERROR_FAILURE; + + rv = file->MoveToNative(target, nsCString()); + NS_ENSURE_SUCCESS(rv,rv); + } + else + { + if (followSymlinks) + rv = file->CopyToFollowingLinksNative(target, nsCString()); + else + rv = file->CopyToNative(target, nsCString()); + NS_ENSURE_SUCCESS(rv,rv); + } + } + } + // we've finished moving all the children of this directory + // in the new directory. so now delete the directory + // note, we don't need to do a recursive delete. + // MoveTo() is recursive. At this point, + // we've already moved the children of the current folder + // to the new location. nothing should be left in the folder. + if (move) + { + rv = Remove(PR_FALSE /* recursive */); + NS_ENSURE_SUCCESS(rv,rv); + } + } + + + // If we moved, we want to adjust this. + if (move) + { + MakeDirty(); + + nsCAutoString newParentPath; + newParentDir->GetNativePath(newParentPath); + + if (newParentPath.IsEmpty()) + return NS_ERROR_FAILURE; + + if (newName.IsEmpty()) + { + nsCAutoString aFileName; + GetNativeLeafName(aFileName); + + InitWithNativePath(newParentPath); + AppendNative(aFileName); + } + else + { + InitWithNativePath(newParentPath); + AppendNative(newName); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_TRUE, PR_FALSE); +} + +NS_IMETHODIMP +nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) +{ + return CopyMove(newParentDir, newName, PR_FALSE, PR_TRUE); +} + +NS_IMETHODIMP +nsLocalFile::Load(PRLibrary * *_retval) +{ + PRBool isFile; + nsresult rv = IsFile(&isFile); + + if (NS_FAILED(rv)) + return rv; + + if (! isFile) + return NS_ERROR_FILE_IS_DIRECTORY; + + NS_TIMELINE_START_TIMER("PR_LoadLibrary"); + *_retval = PR_LoadLibrary(mResolvedPath.get()); + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); + NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mResolvedPath.get()); + + if (*_retval) + return NS_OK; + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsLocalFile::Remove(PRBool recursive) +{ + // NOTE: + // + // if the working path points to a shortcut, then we will only + // delete the shortcut itself. even if the shortcut points to + // a directory, we will not recurse into that directory or + // delete that directory itself. likewise, if the shortcut + // points to a normal file, we will not delete the real file. + // this is done to be consistent with the other platforms that + // behave this way. we do this even if the followLinks attribute + // is set to true. this helps protect against misuse that could + // lead to security bugs (e.g., bug 210588). + // + // Since shortcut files are no longer permitted to be used as unix-like + // symlinks interspersed in the path (e.g. "c:/file.lnk/foo/bar.txt") + // this processing is a lot simpler. Even if the shortcut file is + // pointing to a directory, only the mWorkingPath value is used and so + // only the shortcut file will be deleted. + + PRBool isDir, isLink; + nsresult rv; + + isDir = PR_FALSE; + rv = IsSymlink(&isLink); + if (NS_FAILED(rv)) + return rv; + + // only check to see if we have a directory if it isn't a link + if (!isLink) + { + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + } + + if (isDir) + { + if (recursive) + { + nsDirEnumerator dirEnum; + + rv = dirEnum.Init(this); + if (NS_FAILED(rv)) + return rv; + + PRBool more; + while (NS_SUCCEEDED(dirEnum.HasMoreElements(&more)) && more) + { + nsCOMPtr item; + dirEnum.GetNext(getter_AddRefs(item)); + nsCOMPtr file = do_QueryInterface(item); + if (file) + file->Remove(recursive); + } + } + rv = rmdir(mWorkingPath.get()); + } + else + { + rv = remove(mWorkingPath.get()); + } + + // fixup error code if necessary... + if (rv == (nsresult)-1) + rv = NSRESULT_FOR_ERRNO(); + + MakeDirty(); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + // get the modified time of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as GetLastModifiedTimeOfLink) + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModifiedTime, mFileInfo64.modifyTime, usecPerMsec); + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) +{ + NS_ENSURE_ARG(aLastModifiedTime); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + PRFileInfo64 info; + if (PR_GetFileInfo64(mWorkingPath.get(), &info) != PR_SUCCESS) + return NSRESULT_FOR_ERRNO(); + + // microseconds -> milliseconds + PRInt64 usecPerMsec; + LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); + LL_DIV(*aLastModifiedTime, info.modifyTime, usecPerMsec); + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // set the modified time of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as SetLastModifiedTimeOfLink) + + rv = SetModDate(aLastModifiedTime, mResolvedPath.get()); + if (NS_SUCCEEDED(rv)) + MakeDirty(); + + return rv; +} + + +NS_IMETHODIMP +nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) +{ + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + nsresult rv = SetModDate(aLastModifiedTime, mWorkingPath.get()); + if (NS_SUCCEEDED(rv)) + MakeDirty(); + + return rv; +} + +nsresult +nsLocalFile::SetModDate(PRInt64 aLastModifiedTime, const char *filePath) +{ + HANDLE file = CreateFile(filePath, // pointer to name of the file + GENERIC_WRITE, // access (write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + 0, // file attributes + NULL); + if (file == INVALID_HANDLE_VALUE) + { + return ConvertWinError(GetLastError()); + } + + FILETIME lft, ft; + SYSTEMTIME st; + PRExplodedTime pret; + + // PR_ExplodeTime expects usecs... + PR_ExplodeTime(aLastModifiedTime * PR_USEC_PER_MSEC, PR_LocalTimeParameters, &pret); + st.wYear = pret.tm_year; + st.wMonth = pret.tm_month + 1; // Convert start offset -- Win32: Jan=1; NSPR: Jan=0 + st.wDayOfWeek = pret.tm_wday; + st.wDay = pret.tm_mday; + st.wHour = pret.tm_hour; + st.wMinute = pret.tm_min; + st.wSecond = pret.tm_sec; + st.wMilliseconds = pret.tm_usec/1000; + + nsresult rv = NS_OK; + if ( 0 != SystemTimeToFileTime(&st, &lft) + || 0 != LocalFileTimeToFileTime(&lft, &ft) + || 0 != SetFileTime(file, NULL, &ft, &ft) ) + { + rv = ConvertWinError(GetLastError()); + } + + CloseHandle(file); + return rv; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissions(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + + // get the permissions of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as GetPermissionsOfLink) + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + PRBool isWritable, isExecutable; + IsWritable(&isWritable); + IsExecutable(&isExecutable); + + *aPermissions = PR_IRUSR|PR_IRGRP|PR_IROTH; // all read + if (isWritable) + *aPermissions |= PR_IWUSR|PR_IWGRP|PR_IWOTH; // all write + if (isExecutable) + *aPermissions |= PR_IXUSR|PR_IXGRP|PR_IXOTH; // all execute + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissions) +{ + NS_ENSURE_ARG(aPermissions); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. It is not + // possible for a link file to be executable. + + DWORD word = GetFileAttributes(mWorkingPath.get()); + if (word == INVALID_FILE_ATTRIBUTES) + return NS_ERROR_FILE_INVALID_PATH; + + PRBool isWritable = !(word & FILE_ATTRIBUTE_READONLY); + *aPermissions = PR_IRUSR|PR_IRGRP|PR_IROTH; // all read + if (isWritable) + *aPermissions |= PR_IWUSR|PR_IWGRP|PR_IWOTH; // all write + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::SetPermissions(PRUint32 aPermissions) +{ + // set the permissions of the target as determined by mFollowSymlinks + // If PR_TRUE, then this will be for the target of the shortcut file, + // otherwise it will be for the shortcut file itself (i.e. the same + // results as SetPermissionsOfLink) + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // windows only knows about the following permissions + int mode = 0; + if (aPermissions & (PR_IRUSR|PR_IRGRP|PR_IROTH)) // any read + mode |= _S_IREAD; + if (aPermissions & (PR_IWUSR|PR_IWGRP|PR_IWOTH)) // any write + mode |= _S_IWRITE; + + if (chmod(mResolvedPath.get(), mode) == -1) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) +{ + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + // windows only knows about the following permissions + int mode = 0; + if (aPermissions & (PR_IRUSR|PR_IRGRP|PR_IROTH)) // any read + mode |= _S_IREAD; + if (aPermissions & (PR_IWUSR|PR_IWGRP|PR_IWOTH)) // any write + mode |= _S_IWRITE; + + if (chmod(mWorkingPath.get(), mode) == -1) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSize(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *aFileSize = mFileInfo64.size; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) +{ + NS_ENSURE_ARG(aFileSize); + + // The caller is assumed to have already called IsSymlink + // and to have found that this file is a link. + + PRFileInfo64 info; + if (!PR_GetFileInfo64(mWorkingPath.get(), &info)) + return NS_ERROR_FILE_INVALID_PATH; + + *aFileSize = info.size; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::SetFileSize(PRInt64 aFileSize) +{ + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + HANDLE hFile = CreateFile(mResolvedPath.get(), // pointer to name of the file + GENERIC_WRITE, // access (write) mode + FILE_SHARE_READ, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return ConvertWinError(GetLastError()); + } + + // seek the file pointer to the new, desired end of file + // and then truncate the file at that position + rv = NS_ERROR_FAILURE; + aFileSize = MyFileSeek64(hFile, aFileSize, FILE_BEGIN); + if (aFileSize != -1 && SetEndOfFile(hFile)) + { + MakeDirty(); + rv = NS_OK; + } + + CloseHandle(hFile); + return rv; +} + +typedef BOOL (WINAPI *fpGetDiskFreeSpaceExA)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes); + +NS_IMETHODIMP +nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +{ + NS_ENSURE_ARG(aDiskSpaceAvailable); + + ResolveAndStat(); + + // Attempt to check disk space using the GetDiskFreeSpaceExA function. + // --- FROM MSDN --- + // The GetDiskFreeSpaceEx function is available beginning with Windows 95 OEM Service + // Release 2 (OSR2). To determine whether GetDiskFreeSpaceEx is available, call + // GetModuleHandle to get the handle to Kernel32.dll. Then you can call GetProcAddress. + // It is not necessary to call LoadLibrary on Kernel32.dll because it is already loaded + // into every process address space. + fpGetDiskFreeSpaceExA pGetDiskFreeSpaceExA = (fpGetDiskFreeSpaceExA) + GetProcAddress(GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA"); + if (pGetDiskFreeSpaceExA) + { + ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes; + if (pGetDiskFreeSpaceExA(mResolvedPath.get(), &liFreeBytesAvailableToCaller, + &liTotalNumberOfBytes, NULL)) + { + *aDiskSpaceAvailable = liFreeBytesAvailableToCaller.QuadPart; + return NS_OK; + } + } + + // use the old method of getting available disk space + char aDrive[_MAX_DRIVE + 2]; + _splitpath( mResolvedPath.get(), aDrive, NULL, NULL, NULL); + strcat(aDrive, "\\"); + + DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus; + if (GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus)) + { + __int64 bytes = dwFreeClus; + bytes *= dwSecPerClus; + bytes *= dwBytesPerSec; + + *aDiskSpaceAvailable = bytes; + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsLocalFile::GetParent(nsIFile * *aParent) +{ + NS_ENSURE_ARG_POINTER(aParent); + + nsCAutoString parentPath(mWorkingPath); + + // cannot use nsCString::RFindChar() due to 0x5c problem + PRInt32 offset = (PRInt32) (_mbsrchr((const unsigned char *) parentPath.get(), '\\') + - (const unsigned char *) parentPath.get()); + // adding this offset check that was removed in bug 241708 fixes mail + // directories that aren't relative to/underneath the profile dir. + // e.g., on a different drive. Before you remove them, please make + // sure local mail directories that aren't underneath the profile dir work. + if (offset < 0) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + if (offset == 1 && parentPath[0] == '\\') { + aParent = nsnull; + return NS_OK; + } + if (offset > 0) + parentPath.Truncate(offset); + else + parentPath.AssignLiteral("\\\\."); + + nsCOMPtr localFile; + nsresult rv = NS_NewNativeLocalFile(parentPath, mFollowSymlinks, getter_AddRefs(localFile)); + + if(NS_SUCCEEDED(rv) && localFile) + { + return CallQueryInterface(localFile, aParent); + } + return rv; +} + +NS_IMETHODIMP +nsLocalFile::Exists(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + MakeDirty(); + nsresult rv = ResolveAndStat(); + *_retval = NS_SUCCEEDED(rv); + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsWritable(PRBool *aIsWritable) +{ + //TODO: extend to support NTFS file permissions + + // The read-only attribute on a FAT directory only means that it can't + // be deleted. It is still possible to modify the contents of the directory. + nsresult rv = IsDirectory(aIsWritable); + if (NS_FAILED(rv)) + return rv; + if (*aIsWritable) + return NS_OK; + + // writable if the file doesn't have the readonly attribute + rv = HasFileAttribute(FILE_ATTRIBUTE_READONLY, aIsWritable); + if (NS_FAILED(rv)) + return rv; + *aIsWritable = !*aIsWritable; + + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsReadable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = PR_TRUE; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsExecutable(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; + + nsresult rv; + + // only files can be executables + PRBool isFile; + rv = IsFile(&isFile); + if (NS_FAILED(rv)) + return rv; + if (!isFile) + return NS_OK; + + //TODO: shouldn't we be checking mFollowSymlinks here? + PRBool symLink; + rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + nsCAutoString path; + if (symLink) + GetNativeTarget(path); + else + GetNativePath(path); + + // Get extension. + char * ext = (char *) _mbsrchr((unsigned char *)path.BeginWriting(), '.'); + if ( ext ) { + // Convert extension to lower case. + for( unsigned char *p = (unsigned char *)ext; *p; p++ ) + *p = _mbctolower( *p ); + + // Search for any of the set of executable extensions. + const char * const executableExts[] = { + ".ad", + ".adp", + ".asp", + ".bas", + ".bat", + ".chm", + ".cmd", + ".com", + ".cpl", + ".crt", + ".exe", + ".hlp", + ".hta", + ".inf", + ".ins", + ".isp", + ".js", + ".jse", + ".lnk", + ".mdb", + ".mde", + ".msc", + ".msi", + ".msp", + ".mst", + ".pcd", + ".pif", + ".reg", + ".scr", + ".sct", + ".shb", + ".shs", + ".url", + ".vb", + ".vbe", + ".vbs", + ".vsd", + ".vss", + ".vst", + ".vsw", + ".ws", + ".wsc", + ".wsf", + ".wsh", + 0 }; + for ( int i = 0; executableExts[i]; i++ ) { + if ( ::strcmp( executableExts[i], ext ) == 0 ) { + // Found a match. Set result and quit. + *_retval = PR_TRUE; + break; + } + } + } + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::IsDirectory(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_DIRECTORY); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsFile(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsHidden(PRBool *_retval) +{ + return HasFileAttribute(FILE_ATTRIBUTE_HIDDEN, _retval); +} + +nsresult +nsLocalFile::HasFileAttribute(DWORD fileAttrib, PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // get the file attributes for the correct item depending on following symlinks + const char *filePath = mFollowSymlinks ? mResolvedPath.get() : mWorkingPath.get(); + DWORD word = GetFileAttributes(filePath); + + *_retval = ((word & fileAttrib) != 0); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSymlink(PRBool *_retval) +{ + NS_ENSURE_ARG(_retval); + + // unless it is a valid shortcut path it's not a symlink + if (!IsShortcutPath(mWorkingPath.get())) + { + *_retval = PR_FALSE; + return NS_OK; + } + + // we need to know if this is a file or directory + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + + // it's only a shortcut if it is a file + *_retval = (mFileInfo64.type == PR_FILE_FILE); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::IsSpecial(PRBool *_retval) +{ + return HasFileAttribute(FILE_ATTRIBUTE_SYSTEM, _retval); +} + +NS_IMETHODIMP +nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) +{ + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + + nsCAutoString inFilePath; + inFile->GetNativePath(inFilePath); + + *_retval = inFilePath.Equals(mWorkingPath); + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) +{ + *_retval = PR_FALSE; + + nsCAutoString myFilePath; + if ( NS_FAILED(GetNativeTarget(myFilePath))) + GetNativePath(myFilePath); + + PRInt32 myFilePathLen = myFilePath.Length(); + + nsCAutoString inFilePath; + if ( NS_FAILED(inFile->GetNativeTarget(inFilePath))) + inFile->GetNativePath(inFilePath); + + if ( strnicmp( myFilePath.get(), inFilePath.get(), myFilePathLen) == 0) + { + // now make sure that the |inFile|'s path has a trailing + // separator. + + if (inFilePath[myFilePathLen] == '\\') + { + *_retval = PR_TRUE; + } + + } + + return NS_OK; +} + + + +NS_IMETHODIMP +nsLocalFile::GetNativeTarget(nsACString &_retval) +{ + _retval.Truncate(); +#if STRICT_FAKE_SYMLINKS + PRBool symLink; + + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; + + if (!symLink) + { + return NS_ERROR_FILE_INVALID_PATH; + } +#endif + ResolveAndStat(); + + _retval = mResolvedPath; + return NS_OK; +} + + +/* attribute PRBool followLinks; */ +NS_IMETHODIMP +nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) +{ + *aFollowLinks = mFollowSymlinks; + return NS_OK; +} +NS_IMETHODIMP +nsLocalFile::SetFollowLinks(PRBool aFollowLinks) +{ + MakeDirty(); + mFollowSymlinks = aFollowLinks; + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) +{ + nsresult rv; + + *entries = nsnull; + if (mWorkingPath.EqualsLiteral("\\\\.")) { + nsDriveEnumerator *drives = new nsDriveEnumerator; + if (!drives) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(drives); + rv = drives->Init(); + if (NS_FAILED(rv)) { + NS_RELEASE(drives); + return rv; + } + *entries = drives; + return NS_OK; + } + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) + return rv; + if (!isDir) + return NS_ERROR_FILE_NOT_DIRECTORY; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(this); + if (NS_FAILED(rv)) + { + NS_RELEASE(dirEnum); + return rv; + } + + *entries = dirEnum; + return NS_OK; +} + +NS_IMETHODIMP +nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return GetNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return InitWithNativePath(aPersistentDescriptor); +} + +NS_IMETHODIMP +nsLocalFile::Reveal() +{ + // make sure mResolvedPath is set + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) + return rv; + + // use the full path to explorer for security + nsCOMPtr winDir; + rv = GetSpecialSystemDirectory(Win_WindowsDirectory, getter_AddRefs(winDir)); + NS_ENSURE_SUCCESS(rv, rv); + nsCAutoString explorerPath; + rv = winDir->GetNativePath(explorerPath); + NS_ENSURE_SUCCESS(rv, rv); + explorerPath.Append("\\explorer.exe"); + + // Always open a new window for files because Win2K doesn't appear to select + // the file if a window showing that folder was already open. If the resolved + // path is a directory then instead of opening the parent and selecting it, + // we open the directory itself. + nsCAutoString explorerParams; + if (mFileInfo64.type != PR_FILE_DIRECTORY) // valid because we ResolveAndStat above + explorerParams.Append("/n,/select,"); + explorerParams.Append('\"'); + explorerParams.Append(mResolvedPath); + explorerParams.Append('\"'); + + if (::ShellExecute(NULL, "open", explorerPath.get(), explorerParams.get(), + NULL, SW_SHOWNORMAL) <= (HINSTANCE) 32) + return NS_ERROR_FAILURE; + + return NS_OK; +} + + +NS_IMETHODIMP +nsLocalFile::Launch() +{ + const nsCString &path = mWorkingPath; + + // use the app registry name to launch a shell execute.... + LONG r = (LONG) ::ShellExecute( NULL, NULL, path.get(), NULL, NULL, SW_SHOWNORMAL); + + // if the file has no association, we launch windows' "what do you want to do" dialog + if (r == SE_ERR_NOASSOC) { + nsCAutoString shellArg; + shellArg.Assign(NS_LITERAL_CSTRING("shell32.dll,OpenAs_RunDLL ") + path); + r = (LONG) ::ShellExecute(NULL, NULL, "RUNDLL32.EXE", shellArg.get(), + NULL, SW_SHOWNORMAL); + } + if (r < 32) { + switch (r) { + case 0: + case SE_ERR_OOM: + return NS_ERROR_OUT_OF_MEMORY; + case ERROR_FILE_NOT_FOUND: + return NS_ERROR_FILE_NOT_FOUND; + case ERROR_PATH_NOT_FOUND: + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + case ERROR_BAD_FORMAT: + return NS_ERROR_FILE_CORRUPTED; + case SE_ERR_ACCESSDENIED: + return NS_ERROR_FILE_ACCESS_DENIED; + case SE_ERR_ASSOCINCOMPLETE: + case SE_ERR_NOASSOC: + return NS_ERROR_UNEXPECTED; + case SE_ERR_DDEBUSY: + case SE_ERR_DDEFAIL: + case SE_ERR_DDETIMEOUT: + return NS_ERROR_NOT_AVAILABLE; + case SE_ERR_DLLNOTFOUND: + return NS_ERROR_FAILURE; + case SE_ERR_SHARE: + return NS_ERROR_FILE_IS_LOCKED; + default: + return NS_ERROR_FILE_EXECUTION_FAILED; + } + } + return NS_OK; +} + +nsresult +NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); + + file->SetFollowLinks(followLinks); + + if (!path.IsEmpty()) { + nsresult rv = file->InitWithNativePath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + + *result = file; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// UCS2 interface +//----------------------------------------------------------------------------- + +nsresult +nsLocalFile::InitWithPath(const nsAString &filePath) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(filePath, tmp); + if (NS_SUCCEEDED(rv)) + return InitWithNativePath(tmp); + + return rv; +} + +nsresult +nsLocalFile::Append(const nsAString &node) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + if (NS_SUCCEEDED(rv)) + return AppendNative(tmp); + + return rv; +} + +nsresult +nsLocalFile::AppendRelativePath(const nsAString &node) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(node, tmp); + if (NS_SUCCEEDED(rv)) + return AppendRelativeNativePath(tmp); + return rv; +} + +nsresult +nsLocalFile::GetLeafName(nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = GetNativeLeafName(tmp); + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, aLeafName); + + return rv; +} + +nsresult +nsLocalFile::SetLeafName(const nsAString &aLeafName) +{ + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(aLeafName, tmp); + if (NS_SUCCEEDED(rv)) + return SetNativeLeafName(tmp); + + return rv; +} + +nsresult +nsLocalFile::GetPath(nsAString &_retval) +{ + return NS_CopyNativeToUnicode(mWorkingPath, _retval); +} + +nsresult +nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return CopyToNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return CopyToFollowingLinksNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return CopyToFollowingLinksNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + if (newName.IsEmpty()) + return MoveToNative(newParentDir, nsCString()); + + nsCAutoString tmp; + nsresult rv = NS_CopyUnicodeToNative(newName, tmp); + if (NS_SUCCEEDED(rv)) + return MoveToNative(newParentDir, tmp); + + return rv; +} + +nsresult +nsLocalFile::GetTarget(nsAString &_retval) +{ + nsCAutoString tmp; + nsresult rv = GetNativeTarget(tmp); + if (NS_SUCCEEDED(rv)) + rv = NS_CopyNativeToUnicode(tmp, _retval); + + return rv; +} + +nsresult +NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) +{ + nsCAutoString buf; + nsresult rv = NS_CopyUnicodeToNative(path, buf); + if (NS_FAILED(rv)) { + *result = nsnull; + return rv; + } + return NS_NewNativeLocalFile(buf, followLinks, result); +} + +//----------------------------------------------------------------------------- +// nsLocalFile +//----------------------------------------------------------------------------- + +void +nsLocalFile::GlobalInit() +{ + nsresult rv = NS_CreateShortcutResolver(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Shortcut resolver could not be created"); +} + +void +nsLocalFile::GlobalShutdown() +{ + NS_DestroyShortcutResolver(); +} + +NS_IMPL_ISUPPORTS1(nsDriveEnumerator, nsISimpleEnumerator) + +nsDriveEnumerator::nsDriveEnumerator() + : mLetter(0) +{ +} + +nsDriveEnumerator::~nsDriveEnumerator() +{ +} + +nsresult nsDriveEnumerator::Init() +{ + /* If the length passed to GetLogicalDriveStrings is smaller + * than the length of the string it would return, it returns + * the length required for the string. */ + DWORD length = GetLogicalDriveStrings(0, 0); + /* The string is null terminated */ + mDrives.SetLength(length+1); + if (!GetLogicalDriveStrings(length, mDrives.BeginWriting())) + return NS_ERROR_FAILURE; + mLetter = mDrives.get(); + return NS_OK; +} + +NS_IMETHODIMP nsDriveEnumerator::HasMoreElements(PRBool *aHasMore) +{ + *aHasMore = *mLetter != '\0'; + return NS_OK; +} + +NS_IMETHODIMP nsDriveEnumerator::GetNext(nsISupports **aNext) +{ + /* GetLogicalDrives stored in mLetter is a concatenation + * of null terminated strings, followed by a null terminator. */ + if (!*mLetter) { + *aNext = nsnull; + return NS_OK; + } + const char *drive = mLetter; + mLetter += strlen(drive) + 1; + nsILocalFile *file; + nsresult rv = + NS_NewNativeLocalFile(nsDependentCString(drive), PR_FALSE, &file); + + *aNext = file; + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h new file mode 100644 index 00000000..0ef1d9f0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsLocalFileWin.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * Brodie Thiesfield + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _nsLocalFileWIN_H_ +#define _nsLocalFileWIN_H_ + +#include "nscore.h" +#include "nsError.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsIFile.h" +#include "nsIFactory.h" + +#include "windows.h" + +// For older version (<6.0) of the VC Compiler +#if (_MSC_VER == 1100) +#include +DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0); +#endif + +#include "shlobj.h" + +#include + +class nsLocalFile : public nsILocalFile +{ +public: + NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) + + nsLocalFile(); + + static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIFile interface + NS_DECL_NSIFILE + + // nsILocalFile interface + NS_DECL_NSILOCALFILE + +public: + static void GlobalInit(); + static void GlobalShutdown(); + +private: + nsLocalFile(const nsLocalFile& other); + ~nsLocalFile() {} + + PRPackedBool mDirty; // cached information can only be used when this is PR_FALSE + PRPackedBool mFollowSymlinks; // should we follow symlinks when working on this file + + // this string will always be in native format! + nsCString mWorkingPath; + + // this will be the resolved path of shortcuts, it will *NEVER* be returned to the user + nsCString mResolvedPath; + + PRFileInfo64 mFileInfo64; + + void MakeDirty() { mDirty = PR_TRUE; } + + nsresult ResolveAndStat(); + nsresult ResolveShortcut(); + + nsresult CopyMove(nsIFile *newParentDir, const nsACString &newName, PRBool followSymlinks, PRBool move); + nsresult CopySingleFile(nsIFile *source, nsIFile* dest, const nsACString &newName, PRBool followSymlinks, PRBool move); + + nsresult SetModDate(PRInt64 aLastModifiedTime, const char *filePath); + nsresult HasFileAttribute(DWORD fileAttrib, PRBool *_retval); + nsresult AppendNativeInternal(const nsAFlatCString &node, PRBool multipleComponents); +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp new file mode 100644 index 00000000..ba04a842 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.cpp @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 ***** */ + +/** + * The multiplex stream concatenates a list of input streams into a single + * stream. + */ + +#include "nsMultiplexInputStream.h" +#include "nsIMultiplexInputStream.h" +#include "nsISeekableStream.h" +#include "nsSupportsArray.h" +#include "nsInt64.h" + +class nsMultiplexInputStream : public nsIMultiplexInputStream, + public nsISeekableStream +{ +public: + nsMultiplexInputStream(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIMULTIPLEXINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + + static NS_METHOD Create(nsISupports *outer, REFNSIID iid, void **result); + +private: + ~nsMultiplexInputStream() {} + + + struct ReadSegmentsState { + nsIInputStream* mThisStream; + PRUint32 mOffset; + nsWriteSegmentFun mWriter; + void* mClosure; + PRBool mDone; + }; + + static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure, + const char* aFromRawSegment, PRUint32 aToOffset, + PRUint32 aCount, PRUint32 *aWriteCount); + + nsSupportsArray mStreams; + PRUint32 mCurrentStream; + PRBool mStartedReadingCurrent; +}; + + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiplexInputStream, + nsIMultiplexInputStream, + nsIInputStream, + nsISeekableStream) + +nsMultiplexInputStream::nsMultiplexInputStream() + : mCurrentStream(0), + mStartedReadingCurrent(PR_FALSE) +{ +} + +/* readonly attribute unsigned long count; */ +NS_IMETHODIMP +nsMultiplexInputStream::GetCount(PRUint32 *aCount) +{ + mStreams.Count(aCount); + return NS_OK; +} + +/* void appendStream (in nsIInputStream stream); */ +NS_IMETHODIMP +nsMultiplexInputStream::AppendStream(nsIInputStream *aStream) +{ + return mStreams.AppendElement(aStream); +} + +/* void insertStream (in nsIInputStream stream, in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, PRUint32 aIndex) +{ + nsresult rv = mStreams.InsertElementAt(aStream, aIndex); + NS_ENSURE_SUCCESS(rv, rv); + if (mCurrentStream > aIndex || + (mCurrentStream == aIndex && mStartedReadingCurrent)) + ++mCurrentStream; + return rv; +} + +/* void removeStream (in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::RemoveStream(PRUint32 aIndex) +{ + nsresult rv = mStreams.RemoveElementAt(aIndex); + NS_ENSURE_SUCCESS(rv, rv); + if (mCurrentStream > aIndex) + --mCurrentStream; + else if (mCurrentStream == aIndex) + mStartedReadingCurrent = PR_FALSE; + + return rv; +} + +/* nsIInputStream getStream (in unsigned long index); */ +NS_IMETHODIMP +nsMultiplexInputStream::GetStream(PRUint32 aIndex, nsIInputStream **_retval) +{ + return mStreams.QueryElementAt(aIndex, + NS_GET_IID(nsIInputStream), + (void**)_retval); +} + +/* void close (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Close() +{ + PRUint32 len, i; + nsresult rv = NS_OK; + + mStreams.Count(&len); + for (i = 0; i < len; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + nsresult rv2 = stream->Close(); + // We still want to close all streams, but we should return an error + if (NS_FAILED(rv2)) + rv = rv2; + } + return rv; +} + +/* unsigned long available (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Available(PRUint32 *_retval) +{ + nsresult rv; + PRUint32 i, len, avail = 0; + + mStreams.Count(&len); + for (i = mCurrentStream; i < len; i++) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + + PRUint32 streamAvail; + rv = stream->Available(&streamAvail); + NS_ENSURE_SUCCESS(rv, rv); + avail += streamAvail; + } + *_retval = avail; + return NS_OK; +} + +/* [noscript] unsigned long read (in charPtr buf, in unsigned long count); */ +NS_IMETHODIMP +nsMultiplexInputStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval) +{ + nsresult rv = NS_OK; + PRUint32 len, read; + + *_retval = 0; + + mStreams.Count(&len); + while (mCurrentStream < len && aCount) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, + mCurrentStream)); + rv = stream->Read(aBuf, aCount, &read); + + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + read = 0; + } + else if (NS_FAILED(rv)) + break; + + if (read == 0) { + ++mCurrentStream; + mStartedReadingCurrent = PR_FALSE; + } + else { + NS_ASSERTION(aCount >= read, "Read more than requested"); + *_retval += read; + aCount -= read; + aBuf += read; + mStartedReadingCurrent = PR_TRUE; + } + } + return *_retval ? NS_OK : rv; +} + +/* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer, + * in voidPtr closure, + * in unsigned long count); */ +NS_IMETHODIMP +nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, + PRUint32 aCount, PRUint32 *_retval) +{ + NS_ASSERTION(aWriter, "missing aWriter"); + + nsresult rv = NS_OK; + ReadSegmentsState state; + state.mThisStream = this; + state.mOffset = 0; + state.mWriter = aWriter; + state.mClosure = aClosure; + state.mDone = PR_FALSE; + + PRUint32 len; + mStreams.Count(&len); + while (mCurrentStream < len && aCount) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, + mCurrentStream)); + PRUint32 read; + rv = stream->ReadSegments(ReadSegCb, &state, aCount, &read); + + // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + read = 0; + } + + // if |aWriter| decided to stop reading segments... + if (state.mDone || NS_FAILED(rv)) + break; + + // if stream is empty, then advance to the next stream. + if (read == 0) { + ++mCurrentStream; + mStartedReadingCurrent = PR_FALSE; + } + else { + NS_ASSERTION(aCount >= read, "Read more than requested"); + state.mOffset += read; + aCount -= read; + mStartedReadingCurrent = PR_TRUE; + } + } + + // if we successfully read some data, then this call succeeded. + *_retval = state.mOffset; + return state.mOffset ? NS_OK : rv; +} + +NS_METHOD +nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure, + const char* aFromRawSegment, + PRUint32 aToOffset, PRUint32 aCount, + PRUint32 *aWriteCount) +{ + nsresult rv; + ReadSegmentsState* state = (ReadSegmentsState*)aClosure; + rv = (state->mWriter)(state->mThisStream, + state->mClosure, + aFromRawSegment, + aToOffset + state->mOffset, + aCount, + aWriteCount); + if (NS_FAILED(rv)) + state->mDone = PR_TRUE; + return rv; +} + +/* readonly attribute boolean nonBlocking; */ +NS_IMETHODIMP +nsMultiplexInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + nsresult rv; + PRUint32 i, len; + + mStreams.Count(&len); + for (i = 0; i < len; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + rv = stream->IsNonBlocking(aNonBlocking); + NS_ENSURE_SUCCESS(rv, rv); + // If one is non-blocking the entire stream becomes non-blocking + if (*aNonBlocking) + return NS_OK; + } + return NS_OK; +} + +/* void seek (in PRInt32 whence, in PRInt32 offset); */ +NS_IMETHODIMP +nsMultiplexInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + nsresult rv; + + // rewinding to start is easy, and should be the most common case + if (aWhence == NS_SEEK_SET && aOffset == 0) + { + PRUint32 i, last; + last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; + for (i = 0; i < last; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); + + rv = stream->Seek(NS_SEEK_SET, 0); + NS_ENSURE_SUCCESS(rv, rv); + } + mCurrentStream = 0; + mStartedReadingCurrent = PR_FALSE; + return NS_OK; + } + + // other Seeks not implemented yet + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* PRUint32 tell (); */ +NS_IMETHODIMP +nsMultiplexInputStream::Tell(PRInt64 *_retval) +{ + nsresult rv; + nsInt64 ret64 = 0; + PRUint32 i, last; + last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; + for (i = 0; i < last; ++i) { + nsCOMPtr stream(do_QueryElementAt(&mStreams, i)); + NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); + + PRInt64 pos; + rv = stream->Tell(&pos); + NS_ENSURE_SUCCESS(rv, rv); + ret64 += pos; + } + *_retval = ret64; + + return NS_OK; +} + +/* void setEOF (); */ +NS_IMETHODIMP +nsMultiplexInputStream::SetEOF() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_METHOD +nsMultiplexInputStreamConstructor(nsISupports *outer, + REFNSIID iid, + void **result) +{ + *result = nsnull; + + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsMultiplexInputStream *inst; + NS_NEWXPCOM(inst, nsMultiplexInputStream); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + nsresult rv = inst->QueryInterface(iid, result); + NS_RELEASE(inst); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h new file mode 100644 index 00000000..32d3026d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsMultiplexInputStream.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 frightening to behold. + * + * The Initial Developer of the Original Code is + * Jonas Sicking. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jonas Sicking + * + * 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 ***** */ + +/** + * The multiplex stream concatinates a list of input streams into a single + * stream. + */ + +#ifndef _nsMultiplexInputStream_h_ +#define _nsMultiplexInputStream_h_ + +#include "nsIMultiplexInputStream.h" + +#define NS_MULTIPLEXINPUTSTREAM_CLASSNAME "nsMultiplexInputStream" +#define NS_MULTIPLEXINPUTSTREAM_CONTRACTID "@mozilla.org/io/multiplex-input-stream;1" +#define NS_MULTIPLEXINPUTSTREAM_CID \ +{ /* 565e3a2c-1dd2-11b2-8da1-b4cef17e568d */ \ + 0x565e3a2c, \ + 0x1dd2, \ + 0x11b2, \ + {0x8d, 0xa1, 0xb4, 0xce, 0xf1, 0x7e, 0x56, 0x8d} \ +} + +extern NS_METHOD nsMultiplexInputStreamConstructor(nsISupports *outer, + REFNSIID iid, + void **result); + +#endif // _nsMultiplexInputStream_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp new file mode 100644 index 00000000..55b5c63c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.cpp @@ -0,0 +1,1280 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Brian Stell + * Frank Tang + * Brendan Eich + * Sergei Dolgov + * + * 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 "xpcom-private.h" + +//----------------------------------------------------------------------------- +// XP_UNIX +//----------------------------------------------------------------------------- +#if defined(XP_UNIX) + +#include // mbtowc, wctomb +#include // setlocale +#include "nscore.h" +#include "prlock.h" +#include "nsAString.h" +#include "nsReadableUtils.h" + +// +// choose a conversion library. we used to use mbrtowc/wcrtomb under Linux, +// but that doesn't work for non-BMP characters whether we use '-fshort-wchar' +// or not (see bug 206811 and +// news://news.mozilla.org:119/bajml3$fvr1@ripley.netscape.com). we now use +// iconv for all platforms where nltypes.h and nllanginfo.h are present +// along with iconv. +// +#if defined(HAVE_ICONV) && defined(HAVE_NL_TYPES_H) && defined(HAVE_LANGINFO_CODESET) +#define USE_ICONV 1 +#else +#define USE_STDCONV 1 +#endif + +static void +isolatin1_to_utf16(const char **input, PRUint32 *inputLeft, PRUnichar **output, PRUint32 *outputLeft) +{ + while (*inputLeft && *outputLeft) { + **output = (unsigned char) **input; + (*input)++; + (*inputLeft)--; + (*output)++; + (*outputLeft)--; + } +} + +static void +utf16_to_isolatin1(const PRUnichar **input, PRUint32 *inputLeft, char **output, PRUint32 *outputLeft) +{ + while (*inputLeft && *outputLeft) { + **output = (unsigned char) **input; + (*input)++; + (*inputLeft)--; + (*output)++; + (*outputLeft)--; + } +} + +//----------------------------------------------------------------------------- +// conversion using iconv +//----------------------------------------------------------------------------- +#if defined(USE_ICONV) +#include // CODESET +#include // nl_langinfo +#include // iconv_open, iconv, iconv_close +#include + +#if defined(HAVE_ICONV_WITH_CONST_INPUT) +#define ICONV_INPUT(x) (x) +#else +#define ICONV_INPUT(x) ((char **)x) +#endif + +// solaris definitely needs this, but we'll enable it by default +// just in case... but we know for sure that iconv(3) in glibc +// doesn't need this. +#if !defined(__GLIBC__) +#define ENABLE_UTF8_FALLBACK_SUPPORT +#endif + +#define INVALID_ICONV_T ((iconv_t) -1) + +static inline size_t +xp_iconv(iconv_t converter, + const char **input, + size_t *inputLeft, + char **output, + size_t *outputLeft) +{ + size_t res, outputAvail = outputLeft ? *outputLeft : 0; + res = iconv(converter, ICONV_INPUT(input), inputLeft, output, outputLeft); + if (res == (size_t) -1) { + // on some platforms (e.g., linux) iconv will fail with + // E2BIG if it cannot convert _all_ of its input. it'll + // still adjust all of the in/out params correctly, so we + // can ignore this error. the assumption is that we will + // be called again to complete the conversion. + if ((errno == E2BIG) && (*outputLeft < outputAvail)) + res = 0; + } + return res; +} + +static inline void +xp_iconv_reset(iconv_t converter) +{ + // NOTE: the man pages on Solaris claim that you can pass NULL + // for all parameter to reset the converter, but beware the + // evil Solaris crash if you go down this route >:-) + + const char *zero_char_in_ptr = NULL; + char *zero_char_out_ptr = NULL; + size_t zero_size_in = 0, + zero_size_out = 0; + + xp_iconv(converter, &zero_char_in_ptr, + &zero_size_in, + &zero_char_out_ptr, + &zero_size_out); +} + +static inline iconv_t +xp_iconv_open(const char **to_list, const char **from_list) +{ + iconv_t res; + const char **from_name; + const char **to_name; + + // try all possible combinations to locate a converter. + to_name = to_list; + while (*to_name) { + if (**to_name) { + from_name = from_list; + while (*from_name) { + if (**from_name) { + res = iconv_open(*to_name, *from_name); + if (res != INVALID_ICONV_T) + return res; + } + from_name++; + } + } + to_name++; + } + + return INVALID_ICONV_T; +} + +/* + * PRUnichar[] is NOT a UCS-2 array BUT a UTF-16 string. Therefore, we + * have to use UTF-16 with iconv(3) on platforms where it's supported. + * However, the way UTF-16 and UCS-2 are interpreted varies across platforms + * and implementations of iconv(3). On Tru64, it also depends on the environment + * variable. To avoid the trouble arising from byte-swapping + * (bug 208809), we have to try UTF-16LE/BE and UCS-2LE/BE before falling + * back to UTF-16 and UCS-2 and variants. We assume that UTF-16 and UCS-2 + * on systems without UTF-16LE/BE and UCS-2LE/BE have the native endianness, + * which isn't the case of glibc 2.1.x, for which we use 'UNICODELITTLE' + * and 'UNICODEBIG'. It's also not true of Tru64 V4 when the environment + * variable ICONV_BYTEORDER is set to 'big-endian', about which not much + * can be done other than adding a note in the release notes. (bug 206811) + */ +static const char *UTF_16_NAMES[] = { +#if defined(IS_LITTLE_ENDIAN) + "UTF-16LE", +#if defined(__GLIBC__) + "UNICODELITTLE", +#endif + "UCS-2LE", +#else + "UTF-16BE", +#if defined(__GLIBC__) + "UNICODEBIG", +#endif + "UCS-2BE", +#endif + "UTF-16", + "UCS-2", + "UCS2", + "UCS_2", + "ucs-2", + "ucs2", + "ucs_2", + NULL +}; + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) +static const char *UTF_8_NAMES[] = { + "UTF-8", + "UTF8", + "UTF_8", + "utf-8", + "utf8", + "utf_8", + NULL +}; +#endif + +static const char *ISO_8859_1_NAMES[] = { + "ISO-8859-1", +#if !defined(__GLIBC__) + "ISO8859-1", + "ISO88591", + "ISO_8859_1", + "ISO8859_1", + "iso-8859-1", + "iso8859-1", + "iso88591", + "iso_8859_1", + "iso8859_1", +#endif + NULL +}; + +class nsNativeCharsetConverter +{ +public: + nsNativeCharsetConverter(); + ~nsNativeCharsetConverter(); + + nsresult NativeToUnicode(const char **input , PRUint32 *inputLeft, + PRUnichar **output, PRUint32 *outputLeft); + nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft, + char **output, PRUint32 *outputLeft); + + static void GlobalInit(); + static void GlobalShutdown(); + +private: + static iconv_t gNativeToUnicode; + static iconv_t gUnicodeToNative; +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + static iconv_t gNativeToUTF8; + static iconv_t gUTF8ToNative; + static iconv_t gUnicodeToUTF8; + static iconv_t gUTF8ToUnicode; +#endif + static PRLock *gLock; + static PRBool gInitialized; + + static void LazyInit(); + + static void Lock() { if (gLock) PR_Lock(gLock); } + static void Unlock() { if (gLock) PR_Unlock(gLock); } +}; + +iconv_t nsNativeCharsetConverter::gNativeToUnicode = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUnicodeToNative = INVALID_ICONV_T; +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) +iconv_t nsNativeCharsetConverter::gNativeToUTF8 = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUTF8ToNative = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUnicodeToUTF8 = INVALID_ICONV_T; +iconv_t nsNativeCharsetConverter::gUTF8ToUnicode = INVALID_ICONV_T; +#endif +PRLock *nsNativeCharsetConverter::gLock = nsnull; +PRBool nsNativeCharsetConverter::gInitialized = PR_FALSE; + +void +nsNativeCharsetConverter::LazyInit() +{ + const char *blank_list[] = { "", NULL }; + const char **native_charset_list = blank_list; + const char *native_charset = nl_langinfo(CODESET); + if (native_charset == nsnull) { + NS_ERROR("native charset is unknown"); + // fallback to ISO-8859-1 + native_charset_list = ISO_8859_1_NAMES; + } + else + native_charset_list[0] = native_charset; + + gNativeToUnicode = xp_iconv_open(UTF_16_NAMES, native_charset_list); + gUnicodeToNative = xp_iconv_open(native_charset_list, UTF_16_NAMES); + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUnicode == INVALID_ICONV_T) { + gNativeToUTF8 = xp_iconv_open(UTF_8_NAMES, native_charset_list); + gUTF8ToUnicode = xp_iconv_open(UTF_16_NAMES, UTF_8_NAMES); + NS_ASSERTION(gNativeToUTF8 != INVALID_ICONV_T, "no native to utf-8 converter"); + NS_ASSERTION(gUTF8ToUnicode != INVALID_ICONV_T, "no utf-8 to utf-16 converter"); + } + if (gUnicodeToNative == INVALID_ICONV_T) { + gUnicodeToUTF8 = xp_iconv_open(UTF_8_NAMES, UTF_16_NAMES); + gUTF8ToNative = xp_iconv_open(native_charset_list, UTF_8_NAMES); + NS_ASSERTION(gUnicodeToUTF8 != INVALID_ICONV_T, "no utf-16 to utf-8 converter"); + NS_ASSERTION(gUTF8ToNative != INVALID_ICONV_T, "no utf-8 to native converter"); + } +#else + NS_ASSERTION(gNativeToUnicode != INVALID_ICONV_T, "no native to utf-16 converter"); + NS_ASSERTION(gUnicodeToNative != INVALID_ICONV_T, "no utf-16 to native converter"); +#endif + + /* + * On Solaris 8 (and newer?), the iconv modules converting to UCS-2 + * prepend a byte order mark unicode character (BOM, u+FEFF) during + * the first use of the iconv converter. The same is the case of + * glibc 2.2.9x and Tru64 V5 (see bug 208809) when 'UTF-16' is used. + * However, we use 'UTF-16LE/BE' in both cases, instead so that we + * should be safe. But just in case... + * + * This dummy conversion gets rid of the BOMs and fixes bug 153562. + */ + char dummy_input[1] = { ' ' }; + char dummy_output[4]; + + if (gNativeToUnicode != INVALID_ICONV_T) { + const char *input = dummy_input; + size_t input_left = sizeof(dummy_input); + char *output = dummy_output; + size_t output_left = sizeof(dummy_output); + + xp_iconv(gNativeToUnicode, &input, &input_left, &output, &output_left); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gUTF8ToUnicode != INVALID_ICONV_T) { + const char *input = dummy_input; + size_t input_left = sizeof(dummy_input); + char *output = dummy_output; + size_t output_left = sizeof(dummy_output); + + xp_iconv(gUTF8ToUnicode, &input, &input_left, &output, &output_left); + } +#endif + + gInitialized = PR_TRUE; +} + +void +nsNativeCharsetConverter::GlobalInit() +{ + gLock = PR_NewLock(); + NS_ASSERTION(gLock, "lock creation failed"); +} + +void +nsNativeCharsetConverter::GlobalShutdown() +{ + if (gLock) { + PR_DestroyLock(gLock); + gLock = nsnull; + } + + if (gNativeToUnicode != INVALID_ICONV_T) { + iconv_close(gNativeToUnicode); + gNativeToUnicode = INVALID_ICONV_T; + } + + if (gUnicodeToNative != INVALID_ICONV_T) { + iconv_close(gUnicodeToNative); + gUnicodeToNative = INVALID_ICONV_T; + } + +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUTF8 != INVALID_ICONV_T) { + iconv_close(gNativeToUTF8); + gNativeToUTF8 = INVALID_ICONV_T; + } + if (gUTF8ToNative != INVALID_ICONV_T) { + iconv_close(gUTF8ToNative); + gUTF8ToNative = INVALID_ICONV_T; + } + if (gUnicodeToUTF8 != INVALID_ICONV_T) { + iconv_close(gUnicodeToUTF8); + gUnicodeToUTF8 = INVALID_ICONV_T; + } + if (gUTF8ToUnicode != INVALID_ICONV_T) { + iconv_close(gUTF8ToUnicode); + gUTF8ToUnicode = INVALID_ICONV_T; + } +#endif + + gInitialized = PR_FALSE; +} + +nsNativeCharsetConverter::nsNativeCharsetConverter() +{ + Lock(); + if (!gInitialized) + LazyInit(); +} + +nsNativeCharsetConverter::~nsNativeCharsetConverter() +{ + // reset converters for next time + if (gNativeToUnicode != INVALID_ICONV_T) + xp_iconv_reset(gNativeToUnicode); + if (gUnicodeToNative != INVALID_ICONV_T) + xp_iconv_reset(gUnicodeToNative); +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + if (gNativeToUTF8 != INVALID_ICONV_T) + xp_iconv_reset(gNativeToUTF8); + if (gUTF8ToNative != INVALID_ICONV_T) + xp_iconv_reset(gUTF8ToNative); + if (gUnicodeToUTF8 != INVALID_ICONV_T) + xp_iconv_reset(gUnicodeToUTF8); + if (gUTF8ToUnicode != INVALID_ICONV_T) + xp_iconv_reset(gUTF8ToUnicode); +#endif + Unlock(); +} + +nsresult +nsNativeCharsetConverter::NativeToUnicode(const char **input, + PRUint32 *inputLeft, + PRUnichar **output, + PRUint32 *outputLeft) +{ + size_t res = 0; + size_t inLeft = (size_t) *inputLeft; + size_t outLeft = (size_t) *outputLeft * 2; + + if (gNativeToUnicode != INVALID_ICONV_T) { + + res = xp_iconv(gNativeToUnicode, input, &inLeft, (char **) output, &outLeft); + + *inputLeft = inLeft; + *outputLeft = outLeft / 2; + if (res != (size_t) -1) + return NS_OK; + + NS_WARNING("conversion from native to utf-16 failed"); + + // reset converter + xp_iconv_reset(gNativeToUnicode); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + else if ((gNativeToUTF8 != INVALID_ICONV_T) && + (gUTF8ToUnicode != INVALID_ICONV_T)) { + // convert first to UTF8, then from UTF8 to UCS2 + const char *in = *input; + + char ubuf[1024]; + + // we assume we're always called with enough space in |output|, + // so convert many chars at a time... + while (inLeft) { + char *p = ubuf; + size_t n = sizeof(ubuf); + res = xp_iconv(gNativeToUTF8, &in, &inLeft, &p, &n); + if (res == (size_t) -1) { + NS_ERROR("conversion from native to utf-8 failed"); + break; + } + NS_ASSERTION(outLeft > 0, "bad assumption"); + p = ubuf; + n = sizeof(ubuf) - n; + res = xp_iconv(gUTF8ToUnicode, (const char **) &p, &n, (char **) output, &outLeft); + if (res == (size_t) -1) { + NS_ERROR("conversion from utf-8 to utf-16 failed"); + break; + } + } + + (*input) += (*inputLeft - inLeft); + *inputLeft = inLeft; + *outputLeft = outLeft / 2; + + if (res != (size_t) -1) + return NS_OK; + + // reset converters + xp_iconv_reset(gNativeToUTF8); + xp_iconv_reset(gUTF8ToUnicode); + } +#endif + + // fallback: zero-pad and hope for the best + // XXX This is lame and we have to do better. + isolatin1_to_utf16(input, inputLeft, output, outputLeft); + + return NS_OK; +} + +nsresult +nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input, + PRUint32 *inputLeft, + char **output, + PRUint32 *outputLeft) +{ + size_t res = 0; + size_t inLeft = (size_t) *inputLeft * 2; + size_t outLeft = (size_t) *outputLeft; + + if (gUnicodeToNative != INVALID_ICONV_T) { + res = xp_iconv(gUnicodeToNative, (const char **) input, &inLeft, output, &outLeft); + + if (res != (size_t) -1) { + *inputLeft = inLeft / 2; + *outputLeft = outLeft; + return NS_OK; + } + + NS_ERROR("iconv failed"); + + // reset converter + xp_iconv_reset(gUnicodeToNative); + } +#if defined(ENABLE_UTF8_FALLBACK_SUPPORT) + else if ((gUnicodeToUTF8 != INVALID_ICONV_T) && + (gUTF8ToNative != INVALID_ICONV_T)) { + const char *in = (const char *) *input; + + char ubuf[6]; // max utf-8 char length (really only needs to be 4 bytes) + + // convert one uchar at a time... + while (inLeft && outLeft) { + char *p = ubuf; + size_t n = sizeof(ubuf), one_uchar = sizeof(PRUnichar); + res = xp_iconv(gUnicodeToUTF8, &in, &one_uchar, &p, &n); + if (res == (size_t) -1) { + NS_ERROR("conversion from utf-16 to utf-8 failed"); + break; + } + p = ubuf; + n = sizeof(ubuf) - n; + res = xp_iconv(gUTF8ToNative, (const char **) &p, &n, output, &outLeft); + if (res == (size_t) -1) { + if (errno == E2BIG) { + // not enough room for last uchar... back up and return. + in -= sizeof(PRUnichar); + res = 0; + } + else + NS_ERROR("conversion from utf-8 to native failed"); + break; + } + inLeft -= sizeof(PRUnichar); + } + + if (res != (size_t) -1) { + (*input) += (*inputLeft - inLeft/2); + *inputLeft = inLeft/2; + *outputLeft = outLeft; + return NS_OK; + } + + // reset converters + xp_iconv_reset(gUnicodeToUTF8); + xp_iconv_reset(gUTF8ToNative); + } +#endif + + // fallback: truncate and hope for the best + utf16_to_isolatin1(input, inputLeft, output, outputLeft); + + return NS_OK; +} + +#endif // USE_ICONV + +//----------------------------------------------------------------------------- +// conversion using mb[r]towc/wc[r]tomb +//----------------------------------------------------------------------------- +#if defined(USE_STDCONV) +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) +#include // mbrtowc, wcrtomb +#endif + +class nsNativeCharsetConverter +{ +public: + nsNativeCharsetConverter(); + + nsresult NativeToUnicode(const char **input , PRUint32 *inputLeft, + PRUnichar **output, PRUint32 *outputLeft); + nsresult UnicodeToNative(const PRUnichar **input , PRUint32 *inputLeft, + char **output, PRUint32 *outputLeft); + + static void GlobalInit(); + static void GlobalShutdown() { } + +private: + static PRBool gWCharIsUnicode; + +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) + mbstate_t ps; +#endif +}; + +PRBool nsNativeCharsetConverter::gWCharIsUnicode = PR_FALSE; + +nsNativeCharsetConverter::nsNativeCharsetConverter() +{ +#if defined(HAVE_WCRTOMB) || defined(HAVE_MBRTOWC) + memset(&ps, 0, sizeof(ps)); +#endif +} + +void +nsNativeCharsetConverter::GlobalInit() +{ + // verify that wchar_t for the current locale is actually unicode. + // if it is not, then we should avoid calling mbtowc/wctomb and + // just fallback on zero-pad/truncation conversion. + // + // this test cannot be done at build time because the encoding of + // wchar_t may depend on the runtime locale. sad, but true!! + // + // so, if wchar_t is unicode then converting an ASCII character + // to wchar_t should not change its numeric value. we'll just + // check what happens with the ASCII 'a' character. + // + // this test is not perfect... obviously, it could yield false + // positives, but then at least ASCII text would be converted + // properly (or maybe just the 'a' character) -- oh well :( + + char a = 'a'; + unsigned int w = 0; + + int res = mbtowc((wchar_t *) &w, &a, 1); + + gWCharIsUnicode = (res != -1 && w == 'a'); + +#ifdef DEBUG + if (!gWCharIsUnicode) + NS_WARNING("wchar_t is not unicode (unicode conversion will be lossy)"); +#endif +} + +nsresult +nsNativeCharsetConverter::NativeToUnicode(const char **input, + PRUint32 *inputLeft, + PRUnichar **output, + PRUint32 *outputLeft) +{ + if (gWCharIsUnicode) { + int incr; + + // cannot use wchar_t here since it may have been redefined (e.g., + // via -fshort-wchar). hopefully, sizeof(tmp) is sufficient XP. + unsigned int tmp = 0; + while (*inputLeft && *outputLeft) { +#ifdef HAVE_MBRTOWC + incr = (int) mbrtowc((wchar_t *) &tmp, *input, *inputLeft, &ps); +#else + // XXX is this thread-safe? + incr = (int) mbtowc((wchar_t *) &tmp, *input, *inputLeft); +#endif + if (incr < 0) { + NS_WARNING("mbtowc failed: possible charset mismatch"); + // zero-pad and hope for the best + tmp = (unsigned char) **input; + incr = 1; + } + **output = (PRUnichar) tmp; + (*input) += incr; + (*inputLeft) -= incr; + (*output)++; + (*outputLeft)--; + } + } + else { + // wchar_t isn't unicode, so the best we can do is treat the + // input as if it is isolatin1 :( + isolatin1_to_utf16(input, inputLeft, output, outputLeft); + } + + return NS_OK; +} + +nsresult +nsNativeCharsetConverter::UnicodeToNative(const PRUnichar **input, + PRUint32 *inputLeft, + char **output, + PRUint32 *outputLeft) +{ + if (gWCharIsUnicode) { + int incr; + + while (*inputLeft && *outputLeft >= MB_CUR_MAX) { +#ifdef HAVE_WCRTOMB + incr = (int) wcrtomb(*output, (wchar_t) **input, &ps); +#else + // XXX is this thread-safe? + incr = (int) wctomb(*output, (wchar_t) **input); +#endif + if (incr < 0) { + NS_WARNING("mbtowc failed: possible charset mismatch"); + **output = (unsigned char) **input; // truncate + incr = 1; + } + // most likely we're dead anyways if this assertion should fire + NS_ASSERTION(PRUint32(incr) <= *outputLeft, "wrote beyond end of string"); + (*output) += incr; + (*outputLeft) -= incr; + (*input)++; + (*inputLeft)--; + } + } + else { + // wchar_t isn't unicode, so the best we can do is treat the + // input as if it is isolatin1 :( + utf16_to_isolatin1(input, inputLeft, output, outputLeft); + } + + return NS_OK; +} + +#endif // USE_STDCONV + +//----------------------------------------------------------------------------- +// API implementation +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + output.Truncate(); + + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + + // + // OPTIMIZATION: preallocate space for largest possible result; convert + // directly into the result buffer to avoid intermediate buffer copy. + // + // this will generally result in a larger allocation, but that seems + // better than an extra buffer copy. + // + output.SetLength(inputLen); + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + + PRUnichar *result = out_iter.get(); + PRUint32 resultLeft = inputLen; + + const char *buf = iter.get(); + PRUint32 bufLeft = inputLen; + + nsNativeCharsetConverter conv; + nsresult rv = conv.NativeToUnicode(&buf, &bufLeft, &result, &resultLeft); + if (NS_SUCCEEDED(rv)) { + NS_ASSERTION(bufLeft == 0, "did not consume entire input buffer"); + output.SetLength(inputLen - resultLeft); + } + return rv; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + output.Truncate(); + + nsAString::const_iterator iter, end; + input.BeginReading(iter); + input.EndReading(end); + + // cannot easily avoid intermediate buffer copy. + char temp[4096]; + + nsNativeCharsetConverter conv; + + const PRUnichar *buf = iter.get(); + PRUint32 bufLeft = Distance(iter, end); + while (bufLeft) { + char *p = temp; + PRUint32 tempLeft = sizeof(temp); + + nsresult rv = conv.UnicodeToNative(&buf, &bufLeft, &p, &tempLeft); + if (NS_FAILED(rv)) return rv; + + if (tempLeft < sizeof(temp)) + output.Append(temp, sizeof(temp) - tempLeft); + } + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ + // + // need to initialize the locale or else charset conversion will fail. + // better not delay this in case some other component alters the locale + // settings. + // + // XXX we assume that we are called early enough that we should + // always be the first to care about the locale's charset. + // + setlocale(LC_CTYPE, ""); + + nsNativeCharsetConverter::GlobalInit(); +} + +void +NS_ShutdownNativeCharsetUtils() +{ + nsNativeCharsetConverter::GlobalShutdown(); +} + +//----------------------------------------------------------------------------- +// XP_BEOS +//----------------------------------------------------------------------------- +#elif defined(XP_BEOS) + +#include "nsAString.h" +#include "nsReadableUtils.h" +#include "nsString.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + CopyUTF8toUTF16(input, output); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + CopyUTF16toUTF8(input, output); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +//----------------------------------------------------------------------------- +// XP_WIN +//----------------------------------------------------------------------------- +#elif defined(XP_WIN) + +#include +#include "nsAString.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + + const char *buf = iter.get(); + + // determine length of result + PRUint32 resultLen = 0; + int n = ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, NULL, 0); + if (n > 0) + resultLen += n; + + // allocate sufficient space + output.SetLength(resultLen); + if (resultLen > 0) { + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + + PRUnichar *result = out_iter.get(); + + ::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, resultLen); + } + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + PRUint32 inputLen = input.Length(); + + nsAString::const_iterator iter; + input.BeginReading(iter); + + const PRUnichar *buf = iter.get(); + + // determine length of result + PRUint32 resultLen = 0; + + int n = ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, NULL, 0, NULL, NULL); + if (n > 0) + resultLen += n; + + // allocate sufficient space + output.SetLength(resultLen); + if (resultLen > 0) { + nsACString::iterator out_iter; + output.BeginWriting(out_iter); + + // default "defaultChar" is '?', which is an illegal character on windows + // file system. That will cause file uncreatable. Change it to '_' + const char defaultChar = '_'; + + char *result = out_iter.get(); + + ::WideCharToMultiByte(CP_ACP, 0, buf, inputLen, result, resultLen, + &defaultChar, NULL); + } + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +//----------------------------------------------------------------------------- +// XP_OS2 +//----------------------------------------------------------------------------- +#elif defined(XP_OS2) + +#define INCL_DOS +#include +#include +#include "nsAString.h" +#include +#include "nsNativeCharsetUtils.h" + +static UconvObject UnicodeConverter = NULL; + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + PRUint32 inputLen = input.Length(); + + nsACString::const_iterator iter; + input.BeginReading(iter); + const char *inputStr = iter.get(); + + // determine length of result + PRUint32 resultLen = inputLen; + output.SetLength(resultLen); + + nsAString::iterator out_iter; + output.BeginWriting(out_iter); + UniChar *result = (UniChar*)out_iter.get(); + + size_t cSubs = 0; + size_t resultLeft = resultLen; + + if (!UnicodeConverter) + NS_StartupNativeCharsetUtils(); + + int unirc = ::UniUconvToUcs(UnicodeConverter, (void**)&inputStr, &inputLen, + &result, &resultLeft, &cSubs); + + NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big"); + + if (unirc != ULS_SUCCESS) { + output.Truncate(); + return NS_ERROR_FAILURE; + } + + // Need to update string length to reflect how many bytes were actually + // written. + output.Truncate(resultLen - resultLeft); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + size_t inputLen = input.Length(); + + nsAString::const_iterator iter; + input.BeginReading(iter); + UniChar* inputStr = (UniChar*) NS_CONST_CAST(PRUnichar*, iter.get()); + + // maximum length of unicode string of length x converted to native + // codepage is x*2 + size_t resultLen = inputLen * 2; + output.SetLength(resultLen); + + nsACString::iterator out_iter; + output.BeginWriting(out_iter); + char *result = out_iter.get(); + + size_t cSubs = 0; + size_t resultLeft = resultLen; + + if (!UnicodeConverter) + NS_StartupNativeCharsetUtils(); + + int unirc = ::UniUconvFromUcs(UnicodeConverter, &inputStr, &inputLen, + (void**)&result, &resultLeft, &cSubs); + + NS_ASSERTION(unirc != UCONV_E2BIG, "Path too big"); + + if (unirc != ULS_SUCCESS) { + output.Truncate(); + return NS_ERROR_FAILURE; + } + + // Need to update string length to reflect how many bytes were actually + // written. + output.Truncate(resultLen - resultLeft); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ + ULONG ulLength; + ULONG ulCodePage; + DosQueryCp(sizeof(ULONG), &ulCodePage, &ulLength); + + UniChar codepage[20]; + int unirc = ::UniMapCpToUcsCp(ulCodePage, codepage, 20); + if (unirc == ULS_SUCCESS) { + unirc = ::UniCreateUconvObject(codepage, &UnicodeConverter); + if (unirc == ULS_SUCCESS) { + uconv_attribute_t attr; + ::UniQueryUconvObject(UnicodeConverter, &attr, sizeof(uconv_attribute_t), + NULL, NULL, NULL); + attr.options = UCONV_OPTION_SUBSTITUTE_BOTH; + attr.subchar_len=1; + attr.subchar[0]='_'; + ::UniSetUconvObject(UnicodeConverter, &attr); + } + } +} + +void +NS_ShutdownNativeCharsetUtils() +{ + ::UniFreeUconvObject(UnicodeConverter); +} + +//----------------------------------------------------------------------------- +// XP_MAC +//----------------------------------------------------------------------------- +#elif defined(XP_MAC) + +#include +#include +#include +#include +#include "nsAString.h" + +class nsFSStringConversionMac { +public: + static nsresult UCSToFS(const nsAString& aIn, nsACString& aOut); + static nsresult FSToUCS(const nsACString& ain, nsAString& aOut); + + static void CleanUp(); + +private: + static TextEncoding GetSystemEncoding(); + static nsresult PrepareEncoder(); + static nsresult PrepareDecoder(); + + static UnicodeToTextInfo sEncoderInfo; + static TextToUnicodeInfo sDecoderInfo; +}; + +UnicodeToTextInfo nsFSStringConversionMac::sEncoderInfo = nsnull; +TextToUnicodeInfo nsFSStringConversionMac::sDecoderInfo = nsnull; + +nsresult nsFSStringConversionMac::UCSToFS(const nsAString& aIn, nsACString& aOut) +{ + nsresult rv = PrepareEncoder(); + if (NS_FAILED(rv)) return rv; + + OSStatus err = noErr; + char stackBuffer[512]; + + aOut.Truncate(); + + // for each chunk of |aIn|... + nsReadingIterator iter; + aIn.BeginReading(iter); + + PRUint32 fragmentLength = PRUint32(iter.size_forward()); + UInt32 bytesLeft = fragmentLength * sizeof(UniChar); + + do { + UInt32 bytesRead = 0, bytesWritten = 0; + err = ::ConvertFromUnicodeToText(sEncoderInfo, + bytesLeft, + (const UniChar*)iter.get(), + kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask, + 0, nsnull, nsnull, nsnull, + sizeof(stackBuffer), + &bytesRead, + &bytesWritten, + stackBuffer); + if (err == kTECUsedFallbacksStatus) + err = noErr; + else if (err == kTECOutputBufferFullStatus) { + bytesLeft -= bytesRead; + iter.advance(bytesRead / sizeof(UniChar)); + } + aOut.Append(stackBuffer, bytesWritten); + } + while (err == kTECOutputBufferFullStatus); + + return (err == noErr) ? NS_OK : NS_ERROR_FAILURE; +} + +nsresult nsFSStringConversionMac::FSToUCS(const nsACString& aIn, nsAString& aOut) +{ + nsresult rv = PrepareDecoder(); + if (NS_FAILED(rv)) return rv; + + OSStatus err = noErr; + UniChar stackBuffer[512]; + + aOut.Truncate(0); + + // for each chunk of |aIn|... + nsReadingIterator iter; + aIn.BeginReading(iter); + + PRUint32 fragmentLength = PRUint32(iter.size_forward()); + UInt32 bytesLeft = fragmentLength; + + do { + UInt32 bytesRead = 0, bytesWritten = 0; + err = ::ConvertFromTextToUnicode(sDecoderInfo, + bytesLeft, + iter.get(), + kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask, + 0, nsnull, nsnull, nsnull, + sizeof(stackBuffer), + &bytesRead, + &bytesWritten, + stackBuffer); + if (err == kTECUsedFallbacksStatus) + err = noErr; + else if (err == kTECOutputBufferFullStatus) { + bytesLeft -= bytesRead; + iter.advance(bytesRead); + } + aOut.Append((PRUnichar *)stackBuffer, bytesWritten / sizeof(PRUnichar)); + } + while (err == kTECOutputBufferFullStatus); + + return (err == noErr) ? NS_OK : NS_ERROR_FAILURE; +} + +void nsFSStringConversionMac::CleanUp() +{ + if (sDecoderInfo) { + ::DisposeTextToUnicodeInfo(&sDecoderInfo); + sDecoderInfo = nsnull; + } + if (sEncoderInfo) { + ::DisposeUnicodeToTextInfo(&sEncoderInfo); + sEncoderInfo = nsnull; + } +} + +TextEncoding nsFSStringConversionMac::GetSystemEncoding() +{ + OSStatus err; + TextEncoding theEncoding; + + err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &theEncoding); + + if (err != noErr) + theEncoding = kTextEncodingMacRoman; + + return theEncoding; +} + +nsresult nsFSStringConversionMac::PrepareEncoder() +{ + nsresult rv = NS_OK; + if (!sEncoderInfo) { + OSStatus err; + err = ::CreateUnicodeToTextInfoByEncoding(GetSystemEncoding(), &sEncoderInfo); + if (err) + rv = NS_ERROR_FAILURE; + } + return rv; +} + +nsresult nsFSStringConversionMac::PrepareDecoder() +{ + nsresult rv = NS_OK; + if (!sDecoderInfo) { + OSStatus err; + err = ::CreateTextToUnicodeInfoByEncoding(GetSystemEncoding(), &sDecoderInfo); + if (err) + rv = NS_ERROR_FAILURE; + } + return rv; +} + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + return nsFSStringConversionMac::FSToUCS(input, output); +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + return nsFSStringConversionMac::UCSToFS(input, output); +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ + nsFSStringConversionMac::CleanUp(); +} + +//----------------------------------------------------------------------------- +// default : truncate/zeropad +//----------------------------------------------------------------------------- +#else + +#include "nsReadableUtils.h" + +NS_COM nsresult +NS_CopyNativeToUnicode(const nsACString &input, nsAString &output) +{ + CopyASCIItoUCS2(input, output); + return NS_OK; +} + +NS_COM nsresult +NS_CopyUnicodeToNative(const nsAString &input, nsACString &output) +{ + CopyUCS2toASCII(input, output); + return NS_OK; +} + +void +NS_StartupNativeCharsetUtils() +{ +} + +void +NS_ShutdownNativeCharsetUtils() +{ +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h new file mode 100644 index 00000000..539fa37f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsNativeCharsetUtils.h @@ -0,0 +1,66 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsNativeCharsetUtils_h__ +#define nsNativeCharsetUtils_h__ + + +/*****************************************************************************\ + * * + * **** NOTICE **** * + * * + * *** THESE ARE NOT GENERAL PURPOSE CONVERTERS *** * + * * + * NS_CopyNativeToUnicode / NS_CopyUnicodeToNative should only be used * + * for converting *FILENAMES* between native and unicode. They are not * + * designed or tested for general encoding converter use. * + * * +\*****************************************************************************/ + +/** + * thread-safe conversion routines that do not depend on uconv libraries. + */ +NS_COM nsresult NS_CopyNativeToUnicode(const nsACString &input, nsAString &output); +NS_COM nsresult NS_CopyUnicodeToNative(const nsAString &input, nsACString &output); + +/** + * internal + */ +void NS_StartupNativeCharsetUtils(); +void NS_ShutdownNativeCharsetUtils(); + +#endif // nsNativeCharsetUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp b/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp new file mode 100644 index 00000000..be06179f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsPipe3.cpp @@ -0,0 +1,1276 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIPipe.h" +#include "nsIEventTarget.h" +#include "nsISeekableStream.h" +#include "nsSegmentedBuffer.h" +#include "nsStreamUtils.h" +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "prlog.h" +#include "nsInt64.h" + +#if defined(PR_LOGGING) +// +// set NSPR_LOG_MODULES=nsPipe:5 +// +static PRLogModuleInfo *gPipeLog = nsnull; +#define LOG(args) PR_LOG(gPipeLog, PR_LOG_DEBUG, args) +#else +#define LOG(args) +#endif + +#define DEFAULT_SEGMENT_SIZE 4096 +#define DEFAULT_SEGMENT_COUNT 16 + +class nsPipe; +class nsPipeEvents; +class nsPipeInputStream; +class nsPipeOutputStream; + +//----------------------------------------------------------------------------- + +// this class is used to delay notifications until the end of a particular +// scope. it helps avoid the complexity of issuing callbacks while inside +// a critical section. +class nsPipeEvents +{ +public: + nsPipeEvents() { } + ~nsPipeEvents(); + + inline void NotifyInputReady(nsIAsyncInputStream *stream, + nsIInputStreamCallback *callback) + { + NS_ASSERTION(!mInputCallback, "already have an input event"); + mInputStream = stream; + mInputCallback = callback; + } + + inline void NotifyOutputReady(nsIAsyncOutputStream *stream, + nsIOutputStreamCallback *callback) + { + NS_ASSERTION(!mOutputCallback, "already have an output event"); + mOutputStream = stream; + mOutputCallback = callback; + } + +private: + nsCOMPtr mInputStream; + nsCOMPtr mInputCallback; + nsCOMPtr mOutputStream; + nsCOMPtr mOutputCallback; +}; + +//----------------------------------------------------------------------------- + +// the input end of a pipe (allocated as a member of the pipe). +class nsPipeInputStream : public nsIAsyncInputStream + , public nsISeekableStream + , public nsISearchableInputStream +{ +public: + // since this class will be allocated as a member of the pipe, we do not + // need our own ref count. instead, we share the lifetime (the ref count) + // of the entire pipe. this macro is just convenience since it does not + // declare a mRefCount variable; however, don't let the name fool you... + // we are not inheriting from nsPipe ;-) + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSIASYNCINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + NS_DECL_NSISEARCHABLEINPUTSTREAM + + nsPipeInputStream(nsPipe *pipe) + : mPipe(pipe) + , mReaderRefCnt(0) + , mLogicalOffset(0) + , mBlocking(PR_TRUE) + , mBlocked(PR_FALSE) + , mAvailable(0) + , mCallbackFlags(0) + { } + + nsresult Fill(); + void SetNonBlocking(PRBool aNonBlocking) { mBlocking = !aNonBlocking; } + + PRUint32 Available() { return mAvailable; } + void ReduceAvailable(PRUint32 avail) { mAvailable -= avail; } + + // synchronously wait for the pipe to become readable. + nsresult Wait(); + + // these functions return true to indicate that the pipe's monitor should + // be notified, to wake up a blocked reader if any. + PRBool OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &); + PRBool OnInputException(nsresult, nsPipeEvents &); + +private: + nsPipe *mPipe; + + // separate refcnt so that we know when to close the consumer + nsrefcnt mReaderRefCnt; + nsInt64 mLogicalOffset; + PRPackedBool mBlocking; + + // these variables can only be accessed while inside the pipe's monitor + PRPackedBool mBlocked; + PRUint32 mAvailable; + nsCOMPtr mCallback; + PRUint32 mCallbackFlags; +}; + +//----------------------------------------------------------------------------- + +// the output end of a pipe (allocated as a member of the pipe). +class nsPipeOutputStream : public nsIAsyncOutputStream + , public nsISeekableStream +{ +public: + // since this class will be allocated as a member of the pipe, we do not + // need our own ref count. instead, we share the lifetime (the ref count) + // of the entire pipe. this macro is just convenience since it does not + // declare a mRefCount variable; however, don't let the name fool you... + // we are not inheriting from nsPipe ;-) + NS_DECL_ISUPPORTS_INHERITED + + NS_DECL_NSIOUTPUTSTREAM + NS_DECL_NSIASYNCOUTPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + + nsPipeOutputStream(nsPipe *pipe) + : mPipe(pipe) + , mWriterRefCnt(0) + , mLogicalOffset(0) + , mBlocking(PR_TRUE) + , mBlocked(PR_FALSE) + , mWritable(PR_TRUE) + , mCallbackFlags(0) + { } + + void SetNonBlocking(PRBool aNonBlocking) { mBlocking = !aNonBlocking; } + void SetWritable(PRBool writable) { mWritable = writable; } + + // synchronously wait for the pipe to become writable. + nsresult Wait(); + + // these functions return true to indicate that the pipe's monitor should + // be notified, to wake up a blocked writer if any. + PRBool OnOutputWritable(nsPipeEvents &); + PRBool OnOutputException(nsresult, nsPipeEvents &); + +private: + nsPipe *mPipe; + + // separate refcnt so that we know when to close the producer + nsrefcnt mWriterRefCnt; + nsInt64 mLogicalOffset; + PRPackedBool mBlocking; + + // these variables can only be accessed while inside the pipe's monitor + PRPackedBool mBlocked; + PRPackedBool mWritable; + nsCOMPtr mCallback; + PRUint32 mCallbackFlags; +}; + +//----------------------------------------------------------------------------- + +class nsPipe : public nsIPipe +{ +public: + friend class nsPipeInputStream; + friend class nsPipeOutputStream; + + NS_DECL_ISUPPORTS + NS_DECL_NSIPIPE + + // nsPipe methods: + nsPipe(); + +private: + ~nsPipe(); + +public: + // + // methods below may only be called while inside the pipe's monitor + // + + void PeekSegment(PRUint32 n, char *&cursor, char *&limit); + + // + // methods below may be called while outside the pipe's monitor + // + + nsresult GetReadSegment(const char *&segment, PRUint32 &segmentLen); + void AdvanceReadCursor(PRUint32 count); + + nsresult GetWriteSegment(char *&segment, PRUint32 &segmentLen); + void AdvanceWriteCursor(PRUint32 count); + + void OnPipeException(nsresult reason, PRBool outputOnly = PR_FALSE); + +protected: + // We can't inherit from both nsIInputStream and nsIOutputStream + // because they collide on their Close method. Consequently we nest their + // implementations to avoid the extra object allocation. + nsPipeInputStream mInput; + nsPipeOutputStream mOutput; + + PRMonitor* mMonitor; + nsSegmentedBuffer mBuffer; + + char* mReadCursor; + char* mReadLimit; + + PRInt32 mWriteSegment; + char* mWriteCursor; + char* mWriteLimit; + + nsresult mStatus; +}; + +// +// NOTES on buffer architecture: +// +// +-----------------+ - - mBuffer.GetSegment(0) +// | | +// + - - - - - - - - + - - mReadCursor +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// +-----------------+ - - mReadLimit +// | +// +-----------------+ +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// |/////////////////| +// +-----------------+ +// | +// +-----------------+ - - mBuffer.GetSegment(mWriteSegment) +// |/////////////////| +// |/////////////////| +// |/////////////////| +// + - - - - - - - - + - - mWriteCursor +// | | +// | | +// +-----------------+ - - mWriteLimit +// +// (shaded region contains data) +// +// NOTE: on some systems (notably OS/2), the heap allocator uses an arena for +// small allocations (e.g., 64 byte allocations). this means that buffers may +// be allocated back-to-back. in the diagram above, for example, mReadLimit +// would actually be pointing at the beginning of the next segment. when +// making changes to this file, please keep this fact in mind. +// + +//----------------------------------------------------------------------------- +// nsPipe methods: +//----------------------------------------------------------------------------- + +nsPipe::nsPipe() + : mInput(this) + , mOutput(this) + , mMonitor(nsnull) + , mReadCursor(nsnull) + , mReadLimit(nsnull) + , mWriteSegment(-1) + , mWriteCursor(nsnull) + , mWriteLimit(nsnull) + , mStatus(NS_OK) +{ +} + +nsPipe::~nsPipe() +{ + if (mMonitor) + PR_DestroyMonitor(mMonitor); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsPipe, nsIPipe) + +NS_IMETHODIMP +nsPipe::Init(PRBool nonBlockingIn, + PRBool nonBlockingOut, + PRUint32 segmentSize, + PRUint32 segmentCount, + nsIMemory *segmentAlloc) +{ + mMonitor = PR_NewMonitor(); + if (!mMonitor) + return NS_ERROR_OUT_OF_MEMORY; + + if (segmentSize == 0) + segmentSize = DEFAULT_SEGMENT_SIZE; + if (segmentCount == 0) + segmentCount = DEFAULT_SEGMENT_COUNT; + + // protect against overflow + PRUint32 maxCount = PRUint32(-1) / segmentSize; + if (segmentCount > maxCount) + segmentCount = maxCount; + + nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc); + if (NS_FAILED(rv)) + return rv; + + mInput.SetNonBlocking(nonBlockingIn); + mOutput.SetNonBlocking(nonBlockingOut); + return NS_OK; +} + +NS_IMETHODIMP +nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream) +{ + NS_ADDREF(*aInputStream = &mInput); + return NS_OK; +} + +NS_IMETHODIMP +nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream) +{ + NS_ADDREF(*aOutputStream = &mOutput); + return NS_OK; +} + +void +nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit) +{ + if (index == 0) { + NS_ASSERTION(!mReadCursor || mBuffer.GetSegmentCount(), "unexpected state"); + cursor = mReadCursor; + limit = mReadLimit; + } + else { + PRUint32 numSegments = mBuffer.GetSegmentCount(); + if (index >= numSegments) + cursor = limit = nsnull; + else { + cursor = mBuffer.GetSegment(index); + if (mWriteSegment == (PRInt32) index) + limit = mWriteCursor; + else + limit = cursor + mBuffer.GetSegmentSize(); + } + } +} + +nsresult +nsPipe::GetReadSegment(const char *&segment, PRUint32 &segmentLen) +{ + nsAutoMonitor mon(mMonitor); + + if (mReadCursor == mReadLimit) + return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_WOULD_BLOCK; + + segment = mReadCursor; + segmentLen = mReadLimit - mReadCursor; + return NS_OK; +} + +void +nsPipe::AdvanceReadCursor(PRUint32 bytesRead) +{ + NS_ASSERTION(bytesRead, "dont call if no bytes read"); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + LOG(("III advancing read cursor by %u\n", bytesRead)); + NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much"); + + mReadCursor += bytesRead; + NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit"); + + mInput.ReduceAvailable(bytesRead); + + if (mReadCursor == mReadLimit) { + // we've reached the limit of how much we can read from this segment. + // if at the end of this segment, then we must discard this segment. + + // if still writing in this segment then bail because we're not done + // with the segment and have to wait for now... + if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) { + NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state"); + return; + } + + // shift write segment index (-1 indicates an empty buffer). + --mWriteSegment; + + // done with this segment + mBuffer.DeleteFirstSegment(); + LOG(("III deleting first segment\n")); + + if (mWriteSegment == -1) { + // buffer is completely empty + mReadCursor = nsnull; + mReadLimit = nsnull; + mWriteCursor = nsnull; + mWriteLimit = nsnull; + } + else { + // advance read cursor and limit to next buffer segment + mReadCursor = mBuffer.GetSegment(0); + if (mWriteSegment == 0) + mReadLimit = mWriteCursor; + else + mReadLimit = mReadCursor + mBuffer.GetSegmentSize(); + } + + // we've free'd up a segment, so notify output stream that pipe has + // room for a new segment. + if (mOutput.OnOutputWritable(events)) + mon.Notify(); + } + } +} + +nsresult +nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen) +{ + nsAutoMonitor mon(mMonitor); + + if (NS_FAILED(mStatus)) + return mStatus; + + // write cursor and limit may both be null indicating an empty buffer. + if (mWriteCursor == mWriteLimit) { + char *seg = mBuffer.AppendNewSegment(); + // pipe is full + if (seg == nsnull) + return NS_BASE_STREAM_WOULD_BLOCK; + LOG(("OOO appended new segment\n")); + mWriteCursor = seg; + mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize(); + ++mWriteSegment; + } + + // make sure read cursor is initialized + if (mReadCursor == nsnull) { + NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor"); + mReadCursor = mReadLimit = mWriteCursor; + } + + // check to see if we can roll-back our read and write cursors to the + // beginning of the current/first segment. this is purely an optimization. + if (mReadCursor == mWriteCursor && mWriteSegment == 0) { + char *head = mBuffer.GetSegment(0); + LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head)); + mWriteCursor = mReadCursor = mReadLimit = head; + } + + segment = mWriteCursor; + segmentLen = mWriteLimit - mWriteCursor; + return NS_OK; +} + +void +nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten) +{ + NS_ASSERTION(bytesWritten, "dont call if no bytes written"); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + LOG(("OOO advancing write cursor by %u\n", bytesWritten)); + + char *newWriteCursor = mWriteCursor + bytesWritten; + NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit"); + + // update read limit if reading in the same segment + if (mWriteSegment == 0 && mReadLimit == mWriteCursor) + mReadLimit = newWriteCursor; + + mWriteCursor = newWriteCursor; + + NS_ASSERTION(mReadCursor != mWriteCursor, "read cursor is bad"); + + // update the writable flag on the output stream + if (mWriteCursor == mWriteLimit) { + if (mBuffer.GetSize() >= mBuffer.GetMaxSize()) + mOutput.SetWritable(PR_FALSE); + } + + // notify input stream that pipe now contains additional data + if (mInput.OnInputReadable(bytesWritten, events)) + mon.Notify(); + } +} + +void +nsPipe::OnPipeException(nsresult reason, PRBool outputOnly) +{ + LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n", + reason, outputOnly)); + + nsPipeEvents events; + { + nsAutoMonitor mon(mMonitor); + + // if we've already hit an exception, then ignore this one. + if (NS_FAILED(mStatus)) + return; + + mStatus = reason; + + // an output-only exception applies to the input end if the pipe has + // zero bytes available. + if (outputOnly && !mInput.Available()) + outputOnly = PR_FALSE; + + if (!outputOnly) + if (mInput.OnInputException(reason, events)) + mon.Notify(); + + if (mOutput.OnOutputException(reason, events)) + mon.Notify(); + } +} + +//----------------------------------------------------------------------------- +// nsPipeEvents methods: +//----------------------------------------------------------------------------- + +nsPipeEvents::~nsPipeEvents() +{ + // dispatch any pending events + + if (mInputCallback) { + mInputCallback->OnInputStreamReady(mInputStream); + mInputCallback = 0; + mInputStream = 0; + } + if (mOutputCallback) { + mOutputCallback->OnOutputStreamReady(mOutputStream); + mOutputCallback = 0; + mOutputStream = 0; + } +} + +//----------------------------------------------------------------------------- +// nsPipeInputStream methods: +//----------------------------------------------------------------------------- + +nsresult +nsPipeInputStream::Wait() +{ + NS_ASSERTION(mBlocking, "wait on non-blocking pipe input stream"); + + nsAutoMonitor mon(mPipe->mMonitor); + + while (NS_SUCCEEDED(mPipe->mStatus) && (mAvailable == 0)) { + LOG(("III pipe input: waiting for data\n")); + + mBlocked = PR_TRUE; + mon.Wait(); + mBlocked = PR_FALSE; + + LOG(("III pipe input: woke up [pipe-status=%x available=%u]\n", + mPipe->mStatus, mAvailable)); + } + + return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus; +} + +PRBool +nsPipeInputStream::OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &events) +{ + PRBool result = PR_FALSE; + + mAvailable += bytesWritten; + + if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) { + events.NotifyInputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +PRBool +nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events) +{ + LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n", + this, reason)); + + PRBool result = PR_FALSE; + + NS_ASSERTION(NS_FAILED(reason), "huh? successful exception"); + + // force count of available bytes to zero. + mAvailable = 0; + + if (mCallback) { + events.NotifyInputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeInputStream::AddRef(void) +{ + ++mReaderRefCnt; + return mPipe->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeInputStream::Release(void) +{ + if (--mReaderRefCnt == 0) + Close(); + return mPipe->Release(); +} + +NS_IMPL_QUERY_INTERFACE4(nsPipeInputStream, + nsIInputStream, + nsIAsyncInputStream, + nsISeekableStream, + nsISearchableInputStream) + +NS_IMETHODIMP +nsPipeInputStream::CloseWithStatus(nsresult reason) +{ + LOG(("III CloseWithStatus [this=%x reason=%x]\n", this, reason)); + + if (NS_SUCCEEDED(reason)) + reason = NS_BASE_STREAM_CLOSED; + + mPipe->OnPipeException(reason); + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Close() +{ + return CloseWithStatus(NS_BASE_STREAM_CLOSED); +} + +NS_IMETHODIMP +nsPipeInputStream::Available(PRUint32 *result) +{ + nsAutoMonitor mon(mPipe->mMonitor); + + // return error if pipe closed + if (!mAvailable && NS_FAILED(mPipe->mStatus)) + return mPipe->mStatus; + + *result = mAvailable; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer, + void *closure, + PRUint32 count, + PRUint32 *readCount) +{ + LOG(("III ReadSegments [this=%x count=%u]\n", this, count)); + + nsresult rv = NS_OK; + + const char *segment; + PRUint32 segmentLen; + + *readCount = 0; + while (count) { + rv = mPipe->GetReadSegment(segment, segmentLen); + if (NS_FAILED(rv)) { + // ignore this error if we've already read something. + if (*readCount > 0) { + rv = NS_OK; + break; + } + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + // pipe is empty + if (!mBlocking) + break; + // wait for some data to be written to the pipe + rv = Wait(); + if (NS_SUCCEEDED(rv)) + continue; + } + // ignore this error, just return. + if (rv == NS_BASE_STREAM_CLOSED) { + rv = NS_OK; + break; + } + mPipe->OnPipeException(rv); + break; + } + + // read no more than count + if (segmentLen > count) + segmentLen = count; + + PRUint32 writeCount, originalLen = segmentLen; + while (segmentLen) { + writeCount = 0; + + rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount); + + if (NS_FAILED(rv) || writeCount == 0) { + count = 0; + // any errors returned from the writer end here: do not + // propogate to the caller of ReadSegments. + rv = NS_OK; + break; + } + + NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected"); + segment += writeCount; + segmentLen -= writeCount; + count -= writeCount; + *readCount += writeCount; + mLogicalOffset += writeCount; + } + + if (segmentLen < originalLen) + mPipe->AdvanceReadCursor(originalLen - segmentLen); + } + + return rv; +} + +static NS_METHOD +nsWriteToRawBuffer(nsIInputStream* inStr, + void *closure, + const char *fromRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *writeCount) +{ + char *toBuf = (char*)closure; + memcpy(&toBuf[offset], fromRawSegment, count); + *writeCount = count; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) +{ + return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount); +} + +NS_IMETHODIMP +nsPipeInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = !mBlocking; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback, + PRUint32 flags, + PRUint32 requestedCount, + nsIEventTarget *target) +{ + LOG(("III AsyncWait [this=%x]\n", this)); + + nsPipeEvents pipeEvents; + { + nsAutoMonitor mon(mPipe->mMonitor); + + // replace a pending callback + mCallback = 0; + mCallbackFlags = 0; + + nsCOMPtr proxy; + if (target) { + nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy), + callback, target); + if (NS_FAILED(rv)) return rv; + callback = proxy; + } + + if (NS_FAILED(mPipe->mStatus) || + (mAvailable && !(flags & WAIT_CLOSURE_ONLY))) { + // stream is already closed or readable; post event. + pipeEvents.NotifyInputReady(this, callback); + } + else { + // queue up callback object to be notified when data becomes available + mCallback = callback; + mCallbackFlags = flags; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + NS_NOTREACHED("nsPipeInputStream::Seek"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPipeInputStream::Tell(PRInt64 *offset) +{ + *offset = mLogicalOffset; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeInputStream::SetEOF() +{ + NS_NOTREACHED("nsPipeInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +#define COMPARE(s1, s2, i) \ + (ignoreCase \ + ? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) \ + : nsCRT::strncmp((const char *)s1, (const char *)s2, (PRUint32)i)) + +NS_IMETHODIMP +nsPipeInputStream::Search(const char *forString, + PRBool ignoreCase, + PRBool *found, + PRUint32 *offsetSearchedTo) +{ + LOG(("III Search [for=%s ic=%u]\n", forString, ignoreCase)); + + nsAutoMonitor mon(mPipe->mMonitor); + + char *cursor1, *limit1; + PRUint32 index = 0, offset = 0; + PRUint32 strLen = strlen(forString); + + mPipe->PeekSegment(0, cursor1, limit1); + if (cursor1 == limit1) { + *found = PR_FALSE; + *offsetSearchedTo = 0; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + + while (PR_TRUE) { + PRUint32 i, len1 = limit1 - cursor1; + + // check if the string is in the buffer segment + for (i = 0; i < len1 - strLen + 1; i++) { + if (COMPARE(&cursor1[i], forString, strLen) == 0) { + *found = PR_TRUE; + *offsetSearchedTo = offset + i; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + } + + // get the next segment + char *cursor2, *limit2; + PRUint32 len2; + + index++; + offset += len1; + + mPipe->PeekSegment(index, cursor2, limit2); + if (cursor2 == limit2) { + *found = PR_FALSE; + *offsetSearchedTo = offset - strLen + 1; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + len2 = limit2 - cursor2; + + // check if the string is straddling the next buffer segment + PRUint32 lim = PR_MIN(strLen, len2 + 1); + for (i = 0; i < lim; ++i) { + PRUint32 strPart1Len = strLen - i - 1; + PRUint32 strPart2Len = strLen - strPart1Len; + const char* strPart2 = &forString[strLen - strPart2Len]; + PRUint32 bufSeg1Offset = len1 - strPart1Len; + if (COMPARE(&cursor1[bufSeg1Offset], forString, strPart1Len) == 0 && + COMPARE(cursor2, strPart2, strPart2Len) == 0) { + *found = PR_TRUE; + *offsetSearchedTo = offset - strPart1Len; + LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo)); + return NS_OK; + } + } + + // finally continue with the next buffer + cursor1 = cursor2; + limit1 = limit2; + } + + NS_NOTREACHED("can't get here"); + return NS_ERROR_UNEXPECTED; // keep compiler happy +} + +//----------------------------------------------------------------------------- +// nsPipeOutputStream methods: +//----------------------------------------------------------------------------- + +nsresult +nsPipeOutputStream::Wait() +{ + NS_ASSERTION(mBlocking, "wait on non-blocking pipe output stream"); + + nsAutoMonitor mon(mPipe->mMonitor); + + if (NS_SUCCEEDED(mPipe->mStatus) && !mWritable) { + LOG(("OOO pipe output: waiting for space\n")); + mBlocked = PR_TRUE; + mon.Wait(); + mBlocked = PR_FALSE; + LOG(("OOO pipe output: woke up [pipe-status=%x writable=%u]\n", + mPipe->mStatus, mWritable == PR_TRUE)); + } + + return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus; +} + +PRBool +nsPipeOutputStream::OnOutputWritable(nsPipeEvents &events) +{ + PRBool result = PR_FALSE; + + mWritable = PR_TRUE; + + if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) { + events.NotifyOutputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + +PRBool +nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events) +{ + LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n", + this, reason)); + + nsresult result = PR_FALSE; + + NS_ASSERTION(NS_FAILED(reason), "huh? successful exception"); + mWritable = PR_FALSE; + + if (mCallback) { + events.NotifyOutputReady(this, mCallback); + mCallback = 0; + mCallbackFlags = 0; + } + else if (mBlocked) + result = PR_TRUE; + + return result; +} + + +NS_IMETHODIMP_(nsrefcnt) +nsPipeOutputStream::AddRef() +{ + mWriterRefCnt++; + return mPipe->AddRef(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsPipeOutputStream::Release() +{ + if (--mWriterRefCnt == 0) + Close(); + return mPipe->Release(); +} + +NS_IMPL_QUERY_INTERFACE2(nsPipeOutputStream, + nsIOutputStream, + nsIAsyncOutputStream) + +NS_IMETHODIMP +nsPipeOutputStream::CloseWithStatus(nsresult reason) +{ + LOG(("OOO CloseWithStatus [this=%x reason=%x]\n", this, reason)); + + if (NS_SUCCEEDED(reason)) + reason = NS_BASE_STREAM_CLOSED; + + // input stream may remain open + mPipe->OnPipeException(reason, PR_TRUE); + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Close() +{ + return CloseWithStatus(NS_BASE_STREAM_CLOSED); +} + +NS_IMETHODIMP +nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader, + void* closure, + PRUint32 count, + PRUint32 *writeCount) +{ + LOG(("OOO WriteSegments [this=%x count=%u]\n", this, count)); + + nsresult rv = NS_OK; + + char *segment; + PRUint32 segmentLen; + + *writeCount = 0; + while (count) { + rv = mPipe->GetWriteSegment(segment, segmentLen); + if (NS_FAILED(rv)) { + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + // pipe is full + if (!mBlocking) { + // ignore this error if we've already written something + if (*writeCount > 0) + rv = NS_OK; + break; + } + // wait for the pipe to have an empty segment. + rv = Wait(); + if (NS_SUCCEEDED(rv)) + continue; + } + mPipe->OnPipeException(rv); + break; + } + + // write no more than count + if (segmentLen > count) + segmentLen = count; + + PRUint32 readCount, originalLen = segmentLen; + while (segmentLen) { + readCount = 0; + + rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount); + + if (NS_FAILED(rv) || readCount == 0) { + count = 0; + // any errors returned from the reader end here: do not + // propogate to the caller of WriteSegments. + rv = NS_OK; + break; + } + + NS_ASSERTION(readCount <= segmentLen, "read more than expected"); + segment += readCount; + segmentLen -= readCount; + count -= readCount; + *writeCount += readCount; + mLogicalOffset += readCount; + } + + if (segmentLen < originalLen) + mPipe->AdvanceWriteCursor(originalLen - segmentLen); + } + + return rv; +} + +static NS_METHOD +nsReadFromRawBuffer(nsIOutputStream* outStr, + void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + const char* fromBuf = (const char*)closure; + memcpy(toRawSegment, &fromBuf[offset], count); + *readCount = count; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Write(const char* fromBuf, + PRUint32 bufLen, + PRUint32 *writeCount) +{ + return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::Flush(void) +{ + // nothing to do + return NS_OK; +} + +static NS_METHOD +nsReadFromInputStream(nsIOutputStream* outStr, + void* closure, + char* toRawSegment, + PRUint32 offset, + PRUint32 count, + PRUint32 *readCount) +{ + nsIInputStream* fromStream = (nsIInputStream*)closure; + return fromStream->Read(toRawSegment, count, readCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::WriteFrom(nsIInputStream* fromStream, + PRUint32 count, + PRUint32 *writeCount) +{ + return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount); +} + +NS_IMETHODIMP +nsPipeOutputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = !mBlocking; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback, + PRUint32 flags, + PRUint32 requestedCount, + nsIEventTarget *target) +{ + LOG(("OOO AsyncWait [this=%x]\n", this)); + + nsPipeEvents pipeEvents; + { + nsAutoMonitor mon(mPipe->mMonitor); + + // replace a pending callback + mCallback = 0; + mCallbackFlags = 0; + + nsCOMPtr proxy; + if (target) { + nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy), + callback, target); + if (NS_FAILED(rv)) return rv; + callback = proxy; + } + + if (NS_FAILED(mPipe->mStatus) || + (mWritable && !(flags & WAIT_CLOSURE_ONLY))) { + // stream is already closed or writable; post event. + pipeEvents.NotifyOutputReady(this, callback); + } + else { + // queue up callback object to be notified when data becomes available + mCallback = callback; + mCallbackFlags = flags; + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + NS_NOTREACHED("nsPipeOutputStream::Seek"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsPipeOutputStream::Tell(PRInt64 *offset) +{ + *offset = mLogicalOffset; + return NS_OK; +} + +NS_IMETHODIMP +nsPipeOutputStream::SetEOF() +{ + NS_NOTREACHED("nsPipeOutputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_NewPipe2(nsIAsyncInputStream **pipeIn, + nsIAsyncOutputStream **pipeOut, + PRBool nonBlockingInput, + PRBool nonBlockingOutput, + PRUint32 segmentSize, + PRUint32 segmentCount, + nsIMemory *segmentAlloc) +{ + nsresult rv; + +#if defined(PR_LOGGING) + if (!gPipeLog) + gPipeLog = PR_NewLogModule("nsPipe"); +#endif + + nsPipe *pipe = new nsPipe(); + if (!pipe) + return NS_ERROR_OUT_OF_MEMORY; + + rv = pipe->Init(nonBlockingInput, + nonBlockingOutput, + segmentSize, + segmentCount, + segmentAlloc); + if (NS_FAILED(rv)) { + NS_ADDREF(pipe); + NS_RELEASE(pipe); + return rv; + } + + pipe->GetInputStream(pipeIn); + pipe->GetOutputStream(pipeOut); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp new file mode 100644 index 00000000..5458b1b7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsScriptableInputStream.h" +#include "nsMemory.h" + +NS_IMPL_ISUPPORTS1(nsScriptableInputStream, nsIScriptableInputStream) + +// nsIBaseStream methods +NS_IMETHODIMP +nsScriptableInputStream::Close(void) { + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + return mInputStream->Close(); +} + +// nsIScriptableInputStream methods +NS_IMETHODIMP +nsScriptableInputStream::Init(nsIInputStream *aInputStream) { + if (!aInputStream) return NS_ERROR_NULL_POINTER; + mInputStream = aInputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsScriptableInputStream::Available(PRUint32 *_retval) { + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + return mInputStream->Available(_retval); +} + +NS_IMETHODIMP +nsScriptableInputStream::Read(PRUint32 aCount, char **_retval) { + nsresult rv = NS_OK; + PRUint32 count = 0; + char *buffer = nsnull; + + if (!mInputStream) return NS_ERROR_NOT_INITIALIZED; + + rv = mInputStream->Available(&count); + if (NS_FAILED(rv)) return rv; + + count = PR_MIN(count, aCount); + buffer = (char*)nsMemory::Alloc(count+1); // make room for '\0' + if (!buffer) return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 amtRead = 0; + rv = mInputStream->Read(buffer, count, &amtRead); + if (NS_FAILED(rv)) { + nsMemory::Free(buffer); + return rv; + } + + buffer[amtRead] = '\0'; + *_retval = buffer; + return NS_OK; +} + +NS_METHOD +nsScriptableInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { + if (aOuter) return NS_ERROR_NO_AGGREGATION; + + nsScriptableInputStream *sis = new nsScriptableInputStream(); + if (!sis) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(sis); + nsresult rv = sis->QueryInterface(aIID, aResult); + NS_RELEASE(sis); + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h new file mode 100644 index 00000000..b9976176 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsScriptableInputStream.h @@ -0,0 +1,71 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ___nsscriptableinputstream___h_ +#define ___nsscriptableinputstream___h_ + +#include "nsIScriptableInputStream.h" +#include "nsIInputStream.h" +#include "nsCOMPtr.h" + +#define NS_SCRIPTABLEINPUTSTREAM_CID \ +{ 0x7225c040, 0xa9bf, 0x11d3, { 0xa1, 0x97, 0x0, 0x50, 0x4, 0x1c, 0xaf, 0x44 } } + +#define NS_SCRIPTABLEINPUTSTREAM_CONTRACTID "@mozilla.org/scriptableinputstream;1" +#define NS_SCRIPTABLEINPUTSTREAM_CLASSNAME "Scriptable Input Stream" + +class nsScriptableInputStream : public nsIScriptableInputStream { +public: + // nsISupports methods + NS_DECL_ISUPPORTS + + // nsIScriptableInputStream methods + NS_DECL_NSISCRIPTABLEINPUTSTREAM + + // nsScriptableInputStream methods + nsScriptableInputStream() {}; + + static NS_METHOD + Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + +private: + ~nsScriptableInputStream() {}; + + nsCOMPtr mInputStream; +}; + +#endif // ___nsscriptableinputstream___h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp new file mode 100644 index 00000000..f6a1c15d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.cpp @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSegmentedBuffer.h" +#include "nsCRT.h" + +nsresult +nsSegmentedBuffer::Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory* allocator) +{ + if (mSegmentArrayCount != 0) + return NS_ERROR_FAILURE; // initialized more than once + mSegmentSize = segmentSize; + mMaxSize = maxSize; + mSegAllocator = allocator; + if (mSegAllocator == nsnull) { + mSegAllocator = nsMemory::GetGlobalMemoryService(); + } + else { + NS_ADDREF(mSegAllocator); + } +#if 0 // testing... + mSegmentArrayCount = 2; +#else + mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT; +#endif + return NS_OK; +} + +char* +nsSegmentedBuffer::AppendNewSegment() +{ + if (GetSize() >= mMaxSize) + return nsnull; + + if (mSegmentArray == nsnull) { + PRUint32 bytes = mSegmentArrayCount * sizeof(char*); + mSegmentArray = (char**)nsMemory::Alloc(bytes); + if (mSegmentArray == nsnull) + return nsnull; + memset(mSegmentArray, 0, bytes); + } + + if (IsFull()) { + PRUint32 newArraySize = mSegmentArrayCount * 2; + PRUint32 bytes = newArraySize * sizeof(char*); + char** newSegArray = (char**)nsMemory::Realloc(mSegmentArray, bytes); + if (newSegArray == nsnull) + return nsnull; + mSegmentArray = newSegArray; + // copy wrapped content to new extension + if (mFirstSegmentIndex > mLastSegmentIndex) { + // deal with wrap around case + memcpy(&mSegmentArray[mSegmentArrayCount], + mSegmentArray, + mLastSegmentIndex * sizeof(char*)); + memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*)); + mLastSegmentIndex += mSegmentArrayCount; + memset(&mSegmentArray[mLastSegmentIndex], 0, + (newArraySize - mLastSegmentIndex) * sizeof(char*)); + } + else { + memset(&mSegmentArray[mLastSegmentIndex], 0, + (newArraySize - mLastSegmentIndex) * sizeof(char*)); + } + mSegmentArrayCount = newArraySize; + } + + char* seg = (char*)mSegAllocator->Alloc(mSegmentSize); + if (seg == nsnull) { + return nsnull; + } + mSegmentArray[mLastSegmentIndex] = seg; + mLastSegmentIndex = ModSegArraySize(mLastSegmentIndex + 1); + return seg; +} + +PRBool +nsSegmentedBuffer::DeleteFirstSegment() +{ + NS_ASSERTION(mSegmentArray[mFirstSegmentIndex] != nsnull, "deleting bad segment"); + (void)mSegAllocator->Free(mSegmentArray[mFirstSegmentIndex]); + mSegmentArray[mFirstSegmentIndex] = nsnull; + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + if (mFirstSegmentIndex == last) { + mLastSegmentIndex = last; + return PR_TRUE; + } + else { + mFirstSegmentIndex = ModSegArraySize(mFirstSegmentIndex + 1); + return PR_FALSE; + } +} + +PRBool +nsSegmentedBuffer::DeleteLastSegment() +{ + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + NS_ASSERTION(mSegmentArray[last] != nsnull, "deleting bad segment"); + (void)mSegAllocator->Free(mSegmentArray[last]); + mSegmentArray[last] = nsnull; + mLastSegmentIndex = last; + return (PRBool)(mLastSegmentIndex == mFirstSegmentIndex); +} + +PRBool +nsSegmentedBuffer::ReallocLastSegment(size_t newSize) +{ + PRInt32 last = ModSegArraySize(mLastSegmentIndex - 1); + NS_ASSERTION(mSegmentArray[last] != nsnull, "realloc'ing bad segment"); + char *newSegment = + (char*)mSegAllocator->Realloc(mSegmentArray[last], newSize); + if (newSegment) { + mSegmentArray[last] = newSegment; + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +void +nsSegmentedBuffer::Empty() +{ + if (mSegmentArray) { + for (PRUint32 i = 0; i < mSegmentArrayCount; i++) { + if (mSegmentArray[i]) + mSegAllocator->Free(mSegmentArray[i]); + } + nsMemory::Free(mSegmentArray); + mSegmentArray = nsnull; + } + mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT; + mFirstSegmentIndex = mLastSegmentIndex = 0; +} + +#ifdef DEBUG +NS_COM void +TestSegmentedBuffer() +{ + nsSegmentedBuffer* buf = new nsSegmentedBuffer(); + NS_ASSERTION(buf, "out of memory"); + buf->Init(4, 16); + char* seg; + PRBool empty; + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + seg = buf->AppendNewSegment(); + NS_ASSERTION(seg, "AppendNewSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(!empty, "DeleteFirstSegment failed"); + empty = buf->DeleteFirstSegment(); + NS_ASSERTION(empty, "DeleteFirstSegment failed"); + delete buf; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h new file mode 100644 index 00000000..43620632 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsSegmentedBuffer.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsSegmentedBuffer_h__ +#define nsSegmentedBuffer_h__ + +#include "nsMemory.h" +#include "prclist.h" + +class nsSegmentedBuffer +{ +public: + nsSegmentedBuffer() + : mSegmentSize(0), mMaxSize(0), + mSegAllocator(nsnull), mSegmentArray(nsnull), + mSegmentArrayCount(0), + mFirstSegmentIndex(0), mLastSegmentIndex(0) {} + + ~nsSegmentedBuffer() { + Empty(); + NS_IF_RELEASE(mSegAllocator); + } + + + NS_COM nsresult Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory* allocator = nsnull); + + NS_COM char* AppendNewSegment(); // pushes at end + + // returns true if no more segments remain: + PRBool DeleteFirstSegment(); // pops from beginning + + // returns true if no more segments remain: + PRBool DeleteLastSegment(); // pops from beginning + + // Call Realloc() on last segment. This is used to reduce memory + // consumption when data is not an exact multiple of segment size. + PRBool ReallocLastSegment(size_t newSize); + + NS_COM void Empty(); // frees all segments + + inline PRUint32 GetSegmentCount() { + if (mFirstSegmentIndex <= mLastSegmentIndex) + return mLastSegmentIndex - mFirstSegmentIndex; + else + return mSegmentArrayCount + mLastSegmentIndex - mFirstSegmentIndex; + } + + inline PRUint32 GetSegmentSize() { return mSegmentSize; } + inline PRUint32 GetMaxSize() { return mMaxSize; } + inline PRUint32 GetSize() { return GetSegmentCount() * mSegmentSize; } + + inline char* GetSegment(PRUint32 indx) { + NS_ASSERTION(indx < GetSegmentCount(), "index out of bounds"); + PRInt32 i = ModSegArraySize(mFirstSegmentIndex + (PRInt32)indx); + return mSegmentArray[i]; + } + +protected: + inline PRInt32 ModSegArraySize(PRInt32 n) { + PRUint32 result = n & (mSegmentArrayCount - 1); + NS_ASSERTION(result == n % mSegmentArrayCount, + "non-power-of-2 mSegmentArrayCount"); + return result; + } + + inline PRBool IsFull() { + return ModSegArraySize(mLastSegmentIndex + 1) == mFirstSegmentIndex; + } + +protected: + PRUint32 mSegmentSize; + PRUint32 mMaxSize; + nsIMemory* mSegAllocator; + char** mSegmentArray; + PRUint32 mSegmentArrayCount; + PRInt32 mFirstSegmentIndex; + PRInt32 mLastSegmentIndex; +}; + +// NS_SEGMENTARRAY_INITIAL_SIZE: This number needs to start out as a +// power of 2 given how it gets used. We double the segment array +// when we overflow it, and use that fact that it's a power of 2 +// to compute a fast modulus operation in IsFull. +// +// 32 segment array entries can accommodate 128k of data if segments +// are 4k in size. That seems like a reasonable amount that will avoid +// needing to grow the segment array. +#define NS_SEGMENTARRAY_INITIAL_COUNT 32 + +#endif // nsSegmentedBuffer_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp new file mode 100644 index 00000000..2a6b0166 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.cpp @@ -0,0 +1,563 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * The storage stream provides an internal buffer that can be filled by a + * client using a single output stream. One or more independent input streams + * can be created to read the data out non-destructively. The implementation + * uses a segmented buffer internally to avoid realloc'ing of large buffers, + * with the attendant performance loss and heap fragmentation. + */ + +#include "nsStorageStream.h" +#include "nsSegmentedBuffer.h" +#include "nsCOMPtr.h" +#include "prbit.h" +#include "nsIInputStream.h" +#include "nsISeekableStream.h" +#include "prlog.h" +#include "nsInt64.h" +#if defined(PR_LOGGING) +// +// Log module for StorageStream logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=StorageStreamLog:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +PRLogModuleInfo* StorageStreamLog = nsnull; + +#endif /* PR_LOGGING */ + +nsStorageStream::nsStorageStream() + : mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(PR_FALSE), + mLastSegmentNum(-1), mWriteCursor(0), mSegmentEnd(0), mLogicalLength(0) +{ +#if defined(PR_LOGGING) + // + // Initialize the global PRLogModule for socket transport logging + // if necessary... + // + if (nsnull == StorageStreamLog) { + StorageStreamLog = PR_NewLogModule("StorageStreamLog"); + } +#endif /* PR_LOGGING */ + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("Creating nsStorageStream [%x].\n", this)); +} + +nsStorageStream::~nsStorageStream() +{ + if (mSegmentedBuffer) + delete mSegmentedBuffer; +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsStorageStream, + nsIStorageStream, + nsIOutputStream) + +NS_IMETHODIMP +nsStorageStream::Init(PRUint32 segmentSize, PRUint32 maxSize, + nsIMemory *segmentAllocator) +{ + mSegmentedBuffer = new nsSegmentedBuffer(); + if (!mSegmentedBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + mSegmentSize = segmentSize; + mSegmentSizeLog2 = PR_FloorLog2(segmentSize); + + // Segment size must be a power of two + if (mSegmentSize != ((PRUint32)1 << mSegmentSizeLog2)) + return NS_ERROR_INVALID_ARG; + + return mSegmentedBuffer->Init(segmentSize, maxSize, segmentAllocator); +} + +NS_IMETHODIMP +nsStorageStream::GetOutputStream(PRInt32 aStartingOffset, + nsIOutputStream * *aOutputStream) +{ + NS_ENSURE_ARG(aOutputStream); + if (mWriteInProgress) + return NS_ERROR_NOT_AVAILABLE; + + nsresult rv = Seek(aStartingOffset); + if (NS_FAILED(rv)) return rv; + + // Enlarge the last segment in the buffer so that it is the same size as + // all the other segments in the buffer. (It may have been realloc'ed + // smaller in the Close() method.) + if (mLastSegmentNum >= 0) + mSegmentedBuffer->ReallocLastSegment(mSegmentSize); + + // Need to re-Seek, since realloc might have changed segment base pointer + rv = Seek(aStartingOffset); + if (NS_FAILED(rv)) return rv; + + NS_ADDREF(this); + *aOutputStream = NS_STATIC_CAST(nsIOutputStream*, this); + mWriteInProgress = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Close() +{ + mWriteInProgress = PR_FALSE; + + PRInt32 segmentOffset = SegOffset(mLogicalLength); + + // Shrink the final segment in the segmented buffer to the minimum size + // needed to contain the data, so as to conserve memory. + if (segmentOffset) + mSegmentedBuffer->ReallocLastSegment(segmentOffset); + + mWriteCursor = 0; + mSegmentEnd = 0; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Close mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Flush() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) +{ + const char* readCursor; + PRUint32 count, availableInSegment, remaining; + nsresult rv = NS_OK; + + NS_ENSURE_ARG_POINTER(aNumWritten); + NS_ENSURE_ARG(aBuffer); + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Write mWriteCursor=%x mSegmentEnd=%x aCount=%d\n", + this, mWriteCursor, mSegmentEnd, aCount)); + + remaining = aCount; + readCursor = aBuffer; + while (remaining) { + availableInSegment = mSegmentEnd - mWriteCursor; + if (!availableInSegment) { + mWriteCursor = mSegmentedBuffer->AppendNewSegment(); + if (!mWriteCursor) { + mSegmentEnd = 0; + rv = NS_ERROR_OUT_OF_MEMORY; + goto out; + } + mLastSegmentNum++; + mSegmentEnd = mWriteCursor + mSegmentSize; + availableInSegment = mSegmentEnd - mWriteCursor; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Write (new seg) mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + } + + count = PR_MIN(availableInSegment, remaining); + memcpy(mWriteCursor, readCursor, count); + remaining -= count; + readCursor += count; + mWriteCursor += count; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Writing mWriteCursor=%x mSegmentEnd=%x count=%d\n", + this, mWriteCursor, mSegmentEnd, count)); + }; + + out: + *aNumWritten = aCount - remaining; + mLogicalLength += *aNumWritten; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Wrote mWriteCursor=%x mSegmentEnd=%x numWritten=%d\n", + this, mWriteCursor, mSegmentEnd, *aNumWritten)); + return rv; +} + +NS_IMETHODIMP +nsStorageStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteFrom"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsStorageStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsStorageStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::GetLength(PRUint32 *aLength) +{ + NS_ENSURE_ARG(aLength); + *aLength = mLogicalLength; + return NS_OK; +} + +// Truncate the buffer by deleting the end segments +NS_IMETHODIMP +nsStorageStream::SetLength(PRUint32 aLength) +{ + if (mWriteInProgress) + return NS_ERROR_NOT_AVAILABLE; + + if (aLength > mLogicalLength) + return NS_ERROR_INVALID_ARG; + + PRInt32 newLastSegmentNum = SegNum(aLength); + PRInt32 segmentOffset = SegOffset(aLength); + if (segmentOffset == 0) + newLastSegmentNum--; + + while (newLastSegmentNum < mLastSegmentNum) { + mSegmentedBuffer->DeleteLastSegment(); + mLastSegmentNum--; + } + + mLogicalLength = aLength; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageStream::GetWriteInProgress(PRBool *aWriteInProgress) +{ + NS_ENSURE_ARG(aWriteInProgress); + + *aWriteInProgress = mWriteInProgress; + return NS_OK; +} + +NS_METHOD +nsStorageStream::Seek(PRInt32 aPosition) +{ + // An argument of -1 means "seek to end of stream" + if (aPosition == -1) + aPosition = mLogicalLength; + + // Seeking beyond the buffer end is illegal + if ((PRUint32)aPosition > mLogicalLength) + return NS_ERROR_INVALID_ARG; + + // Seeking backwards in the write stream results in truncation + SetLength(aPosition); + + // Special handling for seek to start-of-buffer + if (aPosition == 0) { + mWriteCursor = 0; + mSegmentEnd = 0; + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Seek mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + return NS_OK; + } + + // Segment may have changed, so reset pointers + mWriteCursor = mSegmentedBuffer->GetSegment(mLastSegmentNum); + NS_ASSERTION(mWriteCursor, "null mWriteCursor"); + mSegmentEnd = mWriteCursor + mSegmentSize; + PRInt32 segmentOffset = SegOffset(aPosition); + mWriteCursor += segmentOffset; + + PR_LOG(StorageStreamLog, PR_LOG_DEBUG, + ("nsStorageStream [%x] Seek mWriteCursor=%x mSegmentEnd=%x\n", + this, mWriteCursor, mSegmentEnd)); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +// There can be many nsStorageInputStreams for a single nsStorageStream +class nsStorageInputStream : public nsIInputStream + , public nsISeekableStream +{ +public: + nsStorageInputStream(nsStorageStream *aStorageStream, PRUint32 aSegmentSize) + : mStorageStream(aStorageStream), mReadCursor(0), + mSegmentEnd(0), mSegmentNum(0), + mSegmentSize(aSegmentSize), mLogicalCursor(0) + { + NS_ADDREF(mStorageStream); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIINPUTSTREAM + NS_DECL_NSISEEKABLESTREAM + +private: + ~nsStorageInputStream() + { + NS_IF_RELEASE(mStorageStream); + } + +protected: + NS_METHOD Seek(PRUint32 aPosition); + + friend class nsStorageStream; + +private: + nsStorageStream* mStorageStream; + const char* mReadCursor; // Next memory location to read byte, or NULL + const char* mSegmentEnd; // One byte past end of current buffer segment + PRUint32 mSegmentNum; // Segment number containing read cursor + PRUint32 mSegmentSize; // All segments, except the last, are of this size + PRUint32 mLogicalCursor; // Logical offset into stream + + PRUint32 SegNum(PRUint32 aPosition) {return aPosition >> mStorageStream->mSegmentSizeLog2;} + PRUint32 SegOffset(PRUint32 aPosition) {return aPosition & (mSegmentSize - 1);} +}; + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsStorageInputStream, + nsIInputStream, + nsISeekableStream) + +NS_IMETHODIMP +nsStorageStream::NewInputStream(PRInt32 aStartingOffset, nsIInputStream* *aInputStream) +{ + nsStorageInputStream *inputStream = new nsStorageInputStream(this, mSegmentSize); + if (!inputStream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inputStream); + + nsresult rv = inputStream->Seek(aStartingOffset); + if (NS_FAILED(rv)) { + NS_RELEASE(inputStream); + return rv; + } + + *aInputStream = inputStream; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Close() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Available(PRUint32 *aAvailable) +{ + *aAvailable = mStorageStream->mLogicalLength - mLogicalCursor; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aNumRead) +{ + char* writeCursor; + PRUint32 count, availableInSegment, remainingCapacity; + + remainingCapacity = aCount; + writeCursor = aBuffer; + while (remainingCapacity) { + availableInSegment = mSegmentEnd - mReadCursor; + if (!availableInSegment) { + PRUint32 available = mStorageStream->mLogicalLength - mLogicalCursor; + if (!available) + goto out; + + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(++mSegmentNum); + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize, available); + } + + count = PR_MIN(availableInSegment, remainingCapacity); + memcpy(writeCursor, mReadCursor, count); + remainingCapacity -= count; + mReadCursor += count; + writeCursor += count; + mLogicalCursor += count; + }; + + out: + *aNumRead = aCount - remainingCapacity; + + PRBool isWriteInProgress = PR_FALSE; + if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) + isWriteInProgress = PR_FALSE; + + if (*aNumRead == 0 && isWriteInProgress) + return NS_BASE_STREAM_WOULD_BLOCK; + else + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 aCount, PRUint32 *aNumRead) +{ + PRUint32 count, availableInSegment, remainingCapacity, bytesConsumed; + nsresult rv; + + remainingCapacity = aCount; + while (remainingCapacity) { + availableInSegment = mSegmentEnd - mReadCursor; + if (!availableInSegment) { + PRUint32 available = mStorageStream->mLogicalLength - mLogicalCursor; + if (!available) + goto out; + + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(++mSegmentNum); + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize, available); + availableInSegment = mSegmentEnd - mReadCursor; + } + + count = PR_MIN(availableInSegment, remainingCapacity); + rv = writer(this, closure, mReadCursor, mLogicalCursor, count, &bytesConsumed); + if (NS_FAILED(rv) || (bytesConsumed == 0)) + break; + remainingCapacity -= bytesConsumed; + mReadCursor += bytesConsumed; + mLogicalCursor += bytesConsumed; + }; + + out: + *aNumRead = aCount - remainingCapacity; + + PRBool isWriteInProgress = PR_FALSE; + if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) + isWriteInProgress = PR_FALSE; + + if (*aNumRead == 0 && isWriteInProgress) + return NS_BASE_STREAM_WOULD_BLOCK; + else + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset) +{ + nsInt64 pos = aOffset; + + switch (aWhence) { + case NS_SEEK_SET: + break; + case NS_SEEK_CUR: + pos += mLogicalCursor; + break; + case NS_SEEK_END: + pos += mStorageStream->mLogicalLength; + break; + default: + NS_NOTREACHED("unexpected whence value"); + return NS_ERROR_UNEXPECTED; + } + nsInt64 logicalCursor(mLogicalCursor); + if (pos == logicalCursor) + return NS_OK; + + return Seek(pos); +} + +NS_IMETHODIMP +nsStorageInputStream::Tell(PRInt64 *aResult) +{ + LL_UI2L(*aResult, mLogicalCursor); + return NS_OK; +} + +NS_IMETHODIMP +nsStorageInputStream::SetEOF() +{ + NS_NOTREACHED("nsStorageInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_METHOD +nsStorageInputStream::Seek(PRUint32 aPosition) +{ + PRUint32 length = mStorageStream->mLogicalLength; + if (aPosition >= length) + return NS_ERROR_INVALID_ARG; + + mSegmentNum = SegNum(aPosition); + PRUint32 segmentOffset = SegOffset(aPosition); + mReadCursor = mStorageStream->mSegmentedBuffer->GetSegment(mSegmentNum) + + segmentOffset; + PRUint32 available = length - aPosition; + mSegmentEnd = mReadCursor + PR_MIN(mSegmentSize - segmentOffset, available); + mLogicalCursor = aPosition; + return NS_OK; +} + +NS_COM nsresult +NS_NewStorageStream(PRUint32 segmentSize, PRUint32 maxSize, nsIStorageStream **result) +{ + NS_ENSURE_ARG(result); + + nsStorageStream* storageStream = new nsStorageStream(); + if (!storageStream) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(storageStream); + nsresult rv = storageStream->Init(segmentSize, maxSize, nsnull); + if (NS_FAILED(rv)) { + NS_RELEASE(storageStream); + return rv; + } + *result = storageStream; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h new file mode 100644 index 00000000..0729c01c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStorageStream.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * The storage stream provides an internal buffer that can be filled by a + * client using a single output stream. One or more independent input streams + * can be created to read the data out non-destructively. The implementation + * uses a segmented buffer internally to avoid realloc'ing of large buffers, + * with the attendant performance loss and heap fragmentation. + */ + +#ifndef _nsStorageStream_h_ +#define _nsStorageStream_h_ + +#include "nsIStorageStream.h" +#include "nsIOutputStream.h" +#include "nsMemory.h" + +#define NS_STORAGESTREAM_CID \ +{ /* 669a9795-6ff7-4ed4-9150-c34ce2971b63 */ \ + 0x669a9795, \ + 0x6ff7, \ + 0x4ed4, \ + {0x91, 0x50, 0xc3, 0x4c, 0xe2, 0x97, 0x1b, 0x63} \ +} + +#define NS_STORAGESTREAM_CONTRACTID "@mozilla.org/storagestream;1" +#define NS_STORAGESTREAM_CLASSNAME "Storage Stream" + +class nsSegmentedBuffer; + +class nsStorageStream : public nsIStorageStream, + public nsIOutputStream +{ +public: + nsStorageStream(); + + NS_DECL_ISUPPORTS + NS_DECL_NSISTORAGESTREAM + NS_DECL_NSIOUTPUTSTREAM + + friend class nsStorageInputStream; + +private: + ~nsStorageStream(); + + nsSegmentedBuffer* mSegmentedBuffer; + PRUint32 mSegmentSize; // All segments, except possibly the last, are of this size + // Must be power-of-2 + PRUint32 mSegmentSizeLog2; // log2(mSegmentSize) + PRBool mWriteInProgress; // true, if an un-Close'ed output stream exists + PRInt32 mLastSegmentNum; // Last segment # in use, -1 initially + char* mWriteCursor; // Pointer to next byte to be written + char* mSegmentEnd; // Pointer to one byte after end of segment + // containing the write cursor + PRUint32 mLogicalLength; // Number of bytes written to stream + + NS_METHOD Seek(PRInt32 aPosition); + PRUint32 SegNum(PRUint32 aPosition) {return aPosition >> mSegmentSizeLog2;} + PRUint32 SegOffset(PRUint32 aPosition) {return aPosition & (mSegmentSize - 1);} +}; + +#endif // _nsStorageStream_h_ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp new file mode 100644 index 00000000..aeb52b2a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.cpp @@ -0,0 +1,583 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsStreamUtils.h" +#include "nsCOMPtr.h" +#include "nsIPipe.h" +#include "nsIEventTarget.h" +#include "nsAutoLock.h" + +//----------------------------------------------------------------------------- + +class nsInputStreamReadyEvent : public PLEvent + , public nsIInputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsInputStreamReadyEvent(nsIInputStreamCallback *callback, + nsIEventTarget *target) + : mCallback(callback) + , mTarget(target) + { + } + +private: + ~nsInputStreamReadyEvent() + { + if (mCallback) { + nsresult rv; + // + // whoa!! looks like we never posted this event. take care to + // release mCallback on the correct thread. if mTarget lives on the + // calling thread, then we are ok. otherwise, we have to try to + // proxy the Release over the right thread. if that thread is dead, + // then there's nothing we can do... better to leak than crash. + // + PRBool val; + rv = mTarget->IsOnCurrentThread(&val); + if (NS_FAILED(rv) || !val) { + nsCOMPtr event; + NS_NewInputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget); + mCallback = 0; + if (event) { + rv = event->OnInputStreamReady(nsnull); + if (NS_FAILED(rv)) { + NS_NOTREACHED("leaking stream event"); + nsISupports *sup = event; + NS_ADDREF(sup); + } + } + } + } + } + +public: + NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *stream) + { + mStream = stream; + + // will be released when event is handled + NS_ADDREF_THIS(); + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + + if (NS_FAILED(mTarget->PostEvent(this))) { + NS_WARNING("PostEvent failed"); + NS_RELEASE_THIS(); + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + +private: + nsCOMPtr mStream; + nsCOMPtr mCallback; + nsCOMPtr mTarget; + + PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent) + { + nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent; + // bypass event delivery if this is a cleanup event... + if (ev->mCallback) + ev->mCallback->OnInputStreamReady(ev->mStream); + ev->mCallback = 0; + return NULL; + } + + PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *plevent) + { + nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent; + NS_RELEASE(ev); + } +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsInputStreamReadyEvent, + nsIInputStreamCallback) + +//----------------------------------------------------------------------------- + +class nsOutputStreamReadyEvent : public PLEvent + , public nsIOutputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsOutputStreamReadyEvent(nsIOutputStreamCallback *callback, + nsIEventTarget *target) + : mCallback(callback) + , mTarget(target) + { + } + +private: + ~nsOutputStreamReadyEvent() + { + if (mCallback) { + nsresult rv; + // + // whoa!! looks like we never posted this event. take care to + // release mCallback on the correct thread. if mTarget lives on the + // calling thread, then we are ok. otherwise, we have to try to + // proxy the Release over the right thread. if that thread is dead, + // then there's nothing we can do... better to leak than crash. + // + PRBool val; + rv = mTarget->IsOnCurrentThread(&val); + if (NS_FAILED(rv) || !val) { + nsCOMPtr event; + NS_NewOutputStreamReadyEvent(getter_AddRefs(event), mCallback, mTarget); + mCallback = 0; + if (event) { + rv = event->OnOutputStreamReady(nsnull); + if (NS_FAILED(rv)) { + NS_NOTREACHED("leaking stream event"); + nsISupports *sup = event; + NS_ADDREF(sup); + } + } + } + } + } + +public: + void Init(nsIOutputStreamCallback *callback, nsIEventTarget *target) + { + mCallback = callback; + mTarget = target; + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + } + + NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *stream) + { + mStream = stream; + + // this will be released when the event is handled + NS_ADDREF_THIS(); + + PL_InitEvent(this, nsnull, EventHandler, EventCleanup); + + if (NS_FAILED(mTarget->PostEvent(this))) { + NS_WARNING("PostEvent failed"); + NS_RELEASE_THIS(); + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + +private: + nsCOMPtr mStream; + nsCOMPtr mCallback; + nsCOMPtr mTarget; + + PR_STATIC_CALLBACK(void *) EventHandler(PLEvent *plevent) + { + nsOutputStreamReadyEvent *ev = (nsOutputStreamReadyEvent *) plevent; + if (ev->mCallback) + ev->mCallback->OnOutputStreamReady(ev->mStream); + ev->mCallback = 0; + return NULL; + } + + PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *ev) + { + nsOutputStreamReadyEvent *event = (nsOutputStreamReadyEvent *) ev; + NS_RELEASE(event); + } +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsOutputStreamReadyEvent, + nsIOutputStreamCallback) + +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_NewInputStreamReadyEvent(nsIInputStreamCallback **event, + nsIInputStreamCallback *callback, + nsIEventTarget *target) +{ + nsInputStreamReadyEvent *ev = new nsInputStreamReadyEvent(callback, target); + if (!ev) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*event = ev); + return NS_OK; +} + +NS_COM nsresult +NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **event, + nsIOutputStreamCallback *callback, + nsIEventTarget *target) +{ + nsOutputStreamReadyEvent *ev = new nsOutputStreamReadyEvent(callback, target); + if (!ev) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*event = ev); + return NS_OK; +} + +//----------------------------------------------------------------------------- +// NS_AsyncCopy implementation + +// abstract stream copier... +class nsAStreamCopier : public nsIInputStreamCallback + , public nsIOutputStreamCallback +{ +public: + NS_DECL_ISUPPORTS + + nsAStreamCopier() + : mLock(nsnull) + , mCallback(nsnull) + , mClosure(nsnull) + , mChunkSize(0) + , mEventInProcess(PR_FALSE) + , mEventIsPending(PR_FALSE) + { + } + + // virtual since subclasses call superclass Release() + virtual ~nsAStreamCopier() + { + if (mLock) + PR_DestroyLock(mLock); + } + + // kick off the async copy... + nsresult Start(nsIInputStream *source, + nsIOutputStream *sink, + nsIEventTarget *target, + nsAsyncCopyCallbackFun callback, + void *closure, + PRUint32 chunksize) + { + mSource = source; + mSink = sink; + mTarget = target; + mCallback = callback; + mClosure = closure; + mChunkSize = chunksize; + + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + mAsyncSource = do_QueryInterface(mSource); + mAsyncSink = do_QueryInterface(mSink); + + return PostContinuationEvent(); + } + + // implemented by subclasses, returns number of bytes copied and + // sets source and sink condition before returning. + virtual PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) = 0; + + void Process() + { + if (!mSource || !mSink) + return; + + nsresult sourceCondition, sinkCondition; + + // ok, copy data from source to sink. + for (;;) { + PRUint32 n = DoCopy(&sourceCondition, &sinkCondition); + if (NS_FAILED(sourceCondition) || NS_FAILED(sinkCondition) || n == 0) { + if (sourceCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSource) { + // need to wait for more data from source. while waiting for + // more source data, be sure to observe failures on output end. + mAsyncSource->AsyncWait(this, 0, 0, nsnull); + + if (mAsyncSink) + mAsyncSink->AsyncWait(this, + nsIAsyncOutputStream::WAIT_CLOSURE_ONLY, + 0, nsnull); + } + else if (sinkCondition == NS_BASE_STREAM_WOULD_BLOCK && mAsyncSink) { + // need to wait for more room in the sink. while waiting for + // more room in the sink, be sure to observer failures on the + // input end. + mAsyncSink->AsyncWait(this, 0, 0, nsnull); + + if (mAsyncSource) + mAsyncSource->AsyncWait(this, + nsIAsyncInputStream::WAIT_CLOSURE_ONLY, + 0, nsnull); + } + else { + // close source + if (mAsyncSource) + mAsyncSource->CloseWithStatus(sinkCondition); + else + mSource->Close(); + mAsyncSource = nsnull; + mSource = nsnull; + + // close sink + if (mAsyncSink) + mAsyncSink->CloseWithStatus(sourceCondition); + else + mSink->Close(); + mAsyncSink = nsnull; + mSink = nsnull; + + // notify state complete... + if (mCallback) { + nsresult status = sourceCondition; + if (NS_SUCCEEDED(status)) + status = sinkCondition; + if (status == NS_BASE_STREAM_CLOSED) + status = NS_OK; + mCallback(mClosure, status); + } + } + break; + } + } + } + + NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *source) + { + PostContinuationEvent(); + return NS_OK; + } + + NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *sink) + { + PostContinuationEvent(); + return NS_OK; + } + + PR_STATIC_CALLBACK(void*) HandleContinuationEvent(PLEvent *event) + { + nsAStreamCopier *self = (nsAStreamCopier *) event->owner; + self->Process(); + + // clear "in process" flag and post any pending continuation event + nsAutoLock lock(self->mLock); + self->mEventInProcess = PR_FALSE; + if (self->mEventIsPending) { + self->mEventIsPending = PR_FALSE; + self->PostContinuationEvent_Locked(); + } + return nsnull; + } + + PR_STATIC_CALLBACK(void) DestroyContinuationEvent(PLEvent *event) + { + nsAStreamCopier *self = (nsAStreamCopier *) event->owner; + NS_RELEASE(self); + delete event; + } + + nsresult PostContinuationEvent() + { + // we cannot post a continuation event if there is currently + // an event in process. doing so could result in Process being + // run simultaneously on multiple threads, so we mark the event + // as pending, and if an event is already in process then we + // just let that existing event take care of posting the real + // continuation event. + + nsAutoLock lock(mLock); + return PostContinuationEvent_Locked(); + } + + nsresult PostContinuationEvent_Locked() + { + nsresult rv = NS_OK; + if (mEventInProcess) + mEventIsPending = PR_TRUE; + else { + PLEvent *event = new PLEvent; + if (!event) + rv = NS_ERROR_OUT_OF_MEMORY; + else { + NS_ADDREF_THIS(); + PL_InitEvent(event, this, + HandleContinuationEvent, + DestroyContinuationEvent); + + rv = mTarget->PostEvent(event); + if (NS_SUCCEEDED(rv)) + mEventInProcess = PR_TRUE; + else { + NS_ERROR("unable to post continuation event"); + PL_DestroyEvent(event); + } + } + } + return rv; + } + +protected: + nsCOMPtr mSource; + nsCOMPtr mSink; + nsCOMPtr mAsyncSource; + nsCOMPtr mAsyncSink; + nsCOMPtr mTarget; + PRLock *mLock; + nsAsyncCopyCallbackFun mCallback; + void *mClosure; + PRUint32 mChunkSize; + PRPackedBool mEventInProcess; + PRPackedBool mEventIsPending; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsAStreamCopier, + nsIInputStreamCallback, + nsIOutputStreamCallback) + +class nsStreamCopierIB : public nsAStreamCopier +{ +public: + nsStreamCopierIB() : nsAStreamCopier() {} + virtual ~nsStreamCopierIB() {} + + struct ReadSegmentsState { + nsIOutputStream *mSink; + nsresult mSinkCondition; + }; + + static NS_METHOD ConsumeInputBuffer(nsIInputStream *inStr, + void *closure, + const char *buffer, + PRUint32 offset, + PRUint32 count, + PRUint32 *countWritten) + { + ReadSegmentsState *state = (ReadSegmentsState *) closure; + + nsresult rv = state->mSink->Write(buffer, count, countWritten); + if (NS_FAILED(rv)) + state->mSinkCondition = rv; + else if (*countWritten == 0) + state->mSinkCondition = NS_BASE_STREAM_CLOSED; + + return state->mSinkCondition; + } + + PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) + { + ReadSegmentsState state; + state.mSink = mSink; + state.mSinkCondition = NS_OK; + + PRUint32 n; + *sourceCondition = + mSource->ReadSegments(ConsumeInputBuffer, &state, mChunkSize, &n); + *sinkCondition = state.mSinkCondition; + return n; + } +}; + +class nsStreamCopierOB : public nsAStreamCopier +{ +public: + nsStreamCopierOB() : nsAStreamCopier() {} + virtual ~nsStreamCopierOB() {} + + struct WriteSegmentsState { + nsIInputStream *mSource; + nsresult mSourceCondition; + }; + + static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr, + void *closure, + char *buffer, + PRUint32 offset, + PRUint32 count, + PRUint32 *countRead) + { + WriteSegmentsState *state = (WriteSegmentsState *) closure; + + nsresult rv = state->mSource->Read(buffer, count, countRead); + if (NS_FAILED(rv)) + state->mSourceCondition = rv; + else if (*countRead == 0) + state->mSourceCondition = NS_BASE_STREAM_CLOSED; + + return state->mSourceCondition; + } + + PRUint32 DoCopy(nsresult *sourceCondition, nsresult *sinkCondition) + { + WriteSegmentsState state; + state.mSource = mSource; + state.mSourceCondition = NS_OK; + + PRUint32 n; + *sinkCondition = + mSink->WriteSegments(FillOutputBuffer, &state, mChunkSize, &n); + *sourceCondition = state.mSourceCondition; + return n; + } +}; + +//----------------------------------------------------------------------------- + +NS_COM nsresult +NS_AsyncCopy(nsIInputStream *source, + nsIOutputStream *sink, + nsIEventTarget *target, + nsAsyncCopyMode mode, + PRUint32 chunkSize, + nsAsyncCopyCallbackFun callback, + void *closure) +{ + NS_ASSERTION(target, "non-null target required"); + + nsresult rv; + nsAStreamCopier *copier; + + if (mode == NS_ASYNCCOPY_VIA_READSEGMENTS) + copier = new nsStreamCopierIB(); + else + copier = new nsStreamCopierOB(); + + if (!copier) + return NS_ERROR_OUT_OF_MEMORY; + + // Start() takes an owning ref to the copier... + NS_ADDREF(copier); + rv = copier->Start(source, sink, target, callback, closure, chunkSize); + NS_RELEASE(copier); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h new file mode 100644 index 00000000..3d33f1c1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStreamUtils.h @@ -0,0 +1,111 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsStreamUtils_h__ +#define nsStreamUtils_h__ + +#include "nscore.h" + +class nsIInputStream; +class nsIOutputStream; +class nsIInputStreamCallback; +class nsIOutputStreamCallback; +class nsIEventTarget; + +/** + * A "one-shot" proxy of the OnInputStreamReady callback. The resulting + * proxy object's OnInputStreamReady function may only be called once! The + * proxy object ensures that the real notify object will be free'd on the + * thread corresponding to the given event target regardless of what thread + * the proxy object is destroyed on. + * + * This function is designed to be used to implement AsyncWait when the + * aEventTarget parameter is non-null. + */ +extern NS_COM nsresult +NS_NewInputStreamReadyEvent(nsIInputStreamCallback **aEvent, + nsIInputStreamCallback *aNotify, + nsIEventTarget *aEventTarget); + +/** + * A "one-shot" proxy of the OnOutputStreamReady callback. The resulting + * proxy object's OnOutputStreamReady function may only be called once! The + * proxy object ensures that the real notify object will be free'd on the + * thread corresponding to the given event target regardless of what thread + * the proxy object is destroyed on. + * + * This function is designed to be used to implement AsyncWait when the + * aEventTarget parameter is non-null. + */ +extern NS_COM nsresult +NS_NewOutputStreamReadyEvent(nsIOutputStreamCallback **aEvent, + nsIOutputStreamCallback *aNotify, + nsIEventTarget *aEventTarget); + +/* ------------------------------------------------------------------------- */ + +enum nsAsyncCopyMode { + NS_ASYNCCOPY_VIA_READSEGMENTS, + NS_ASYNCCOPY_VIA_WRITESEGMENTS +}; + +/** + * This function is called when the async copy process completes. The reported + * status is NS_OK on success and some error code on failure. + */ +typedef void (* nsAsyncCopyCallbackFun)(void *closure, nsresult status); + +/** + * This function asynchronously copies data from the source to the sink. All + * data transfer occurs on the thread corresponding to the given event target. + * A null event target is not permitted. + * + * The copier handles blocking or non-blocking streams transparently. If a + * stream operation returns NS_BASE_STREAM_WOULD_BLOCK, then the stream will + * be QI'd to nsIAsync{In,Out}putStream and its AsyncWait method will be used + * to determine when to resume copying. + */ +extern NS_COM nsresult +NS_AsyncCopy(nsIInputStream *aSource, + nsIOutputStream *aSink, + nsIEventTarget *aEventTarget, + nsAsyncCopyMode aMode = NS_ASYNCCOPY_VIA_READSEGMENTS, + PRUint32 aChunkSize = 4096, + nsAsyncCopyCallbackFun aCallbackFun = nsnull, + void *aCallbackClosure = nsnull); + +#endif // !nsStreamUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringIO.h b/src/libs/xpcom18a4/xpcom/io/nsStringIO.h new file mode 100644 index 00000000..beca1d19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringIO.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStringIO_h___ +#define nsStringIO_h___ + +#include "nsAString.h" +#include + + +template +class nsFileCharSink + { + public: + typedef CharT value_type; + + public: + nsFileCharSink( FILE* aOutputFile ) : mOutputFile(aOutputFile) { } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + return fwrite(s, sizeof(CharT), n, mOutputFile); + } + + private: + FILE* mOutputFile; + }; + + +template +inline +void +fprint_string( FILE* aFile, const basic_nsAString& aString ) + { + nsReadingIterator fromBegin, fromEnd; + nsFileCharSink toBegin(aFile); + copy_string(aString.BeginReading(fromBegin), aString.EndReading(fromEnd), toBegin); + } + + +template +inline +void +print_string( const basic_nsAString& aString ) + { + fprint_string(stdout, aString); + } + + +#endif // !defined(nsStringIO_h___) diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp new file mode 100644 index 00000000..536eab11 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringStream.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * mcmullen@netscape.com (original author) + * warren@netscape.com + * alecf@netscape.com + * scc@mozilla.org + * david.gardiner@unisa.edu.au + * fur@netscape.com + * norris@netscape.com + * pinkerton@netscape.com + * davidm@netscape.com + * sfraser@netscape.com + * darin@netscape.com + * bzbarsky@mit.edu + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * Based on original code from nsIStringStream.cpp + */ + +#include "nsStringStream.h" + +#include "prerror.h" +#include "plstr.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsISeekableStream.h" +#include "nsInt64.h" + +#define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x) +#define NS_FILE_FAILURE NS_FILE_RESULT(-1) + +static nsresult ns_file_convert_result(PRInt32 nativeErr) +{ + return nativeErr ? + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF)) + : NS_OK; +} + +//----------------------------------------------------------------------------- +// nsIStringInputStream implementation +//----------------------------------------------------------------------------- + +class nsStringInputStream : public nsIStringInputStream + , public nsIRandomAccessStore + +{ +public: + nsStringInputStream() + : mOffset(0) + , mLastResult(NS_OK) + , mEOF(PR_FALSE) + , mOwned(PR_FALSE) + , mConstString(nsnull) + , mLength(0) + {} + +private: + ~nsStringInputStream() + { + if (mOwned) + nsMemory::Free((char*)mConstString); + } + +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSISTRINGINPUTSTREAM + NS_DECL_NSIINPUTSTREAM + + // nsIRandomAccessStore interface + NS_IMETHOD GetAtEOF(PRBool* outAtEOF); + NS_IMETHOD SetAtEOF(PRBool inAtEOF); + + NS_DECL_NSISEEKABLESTREAM + +protected: + PRInt32 LengthRemaining() const + { + return mLength - mOffset; + } + + void Clear() + { + NS_ASSERTION(mConstString || !mOwned, + "Can't have mOwned set and have a null string!"); + if (mOwned) + nsMemory::Free((char*)mConstString); + + // We're about to get a new string; clear the members that + // would no longer have valid values. + mOffset = 0; + mLastResult = NS_OK; + mEOF = PR_FALSE; + } + + PRInt32 mOffset; + nsresult mLastResult; + PRPackedBool mEOF; + PRPackedBool mOwned; + const char* mConstString; + PRInt32 mLength; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS4(nsStringInputStream, + nsIStringInputStream, + nsIInputStream, + nsIRandomAccessStore, + nsISeekableStream) + +///////// +// nsIStringInputStream implementation +///////// +NS_IMETHODIMP +nsStringInputStream::SetData(const char *data, PRInt32 dataLen) +{ + if (dataLen < 0) + dataLen = strlen(data); + + return AdoptData(nsCRT::strndup(data, dataLen), dataLen); +} + +NS_IMETHODIMP +nsStringInputStream::AdoptData(char *data, PRInt32 dataLen) +{ + NS_ENSURE_ARG_POINTER(data); + + if (dataLen < 0) + dataLen = strlen(data); + + Clear(); + + mConstString = (const char *) data; + mLength = dataLen; + mOwned = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStringInputStream::ShareData(const char *data, PRInt32 dataLen) +{ + NS_ENSURE_ARG_POINTER(data); + + if (dataLen < 0) + dataLen = strlen(data); + + Clear(); + + mConstString = data; + mLength = dataLen; + mOwned = PR_FALSE; + return NS_OK; +} + +///////// +// nsIInputStream implementation +///////// +NS_IMETHODIMP nsStringInputStream::Close() +{ + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::Available(PRUint32 *aLength) +{ + NS_PRECONDITION(aLength != nsnull, "null ptr"); + if (!aLength) + return NS_ERROR_NULL_POINTER; + *aLength = LengthRemaining(); + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::Read(char* aBuf, PRUint32 aCount, + PRUint32 *aReadCount) +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + if (!aBuf) + return NS_ERROR_NULL_POINTER; + NS_PRECONDITION(aReadCount != nsnull, "null ptr"); + if (!aReadCount) + return NS_ERROR_NULL_POINTER; + if (NS_FAILED(mLastResult)) + return mLastResult; + + PRInt32 bytesRead; + PRInt32 maxCount = mLength - mOffset; + if ((PRInt32)aCount > maxCount) + bytesRead = maxCount; + else + bytesRead = aCount; + + memcpy(aBuf, mConstString + mOffset, bytesRead); + mOffset += bytesRead; + + *aReadCount = bytesRead; + if (bytesRead < (PRInt32)aCount) + SetAtEOF(PR_TRUE); + return NS_OK; +} + + +NS_IMETHODIMP +nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, + PRUint32 aCount, PRUint32 * result) +{ + nsresult rv; + PRInt32 maxCount = mLength - mOffset; + if (maxCount == 0) { + *result = 0; + return NS_OK; + } + if ((PRInt32)aCount > maxCount) + aCount = maxCount; + rv = writer(this, closure, mConstString + mOffset, + 0, aCount, result); + if (NS_SUCCEEDED(rv)) + mOffset += *result; + // errors returned from the writer end here! + return NS_OK; +} + +NS_IMETHODIMP +nsStringInputStream::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_TRUE; + return NS_OK; +} + + +///////// +// nsISeekableStream implementation +///////// +NS_IMETHODIMP nsStringInputStream::Seek(PRInt32 whence, PRInt64 offset) +{ + mLastResult = NS_OK; // reset on a seek. + const nsInt64 maxUint32 = PR_UINT32_MAX; + nsInt64 offset64(offset); + PRInt32 offset32; + LL_L2I(offset32, offset); + + NS_ASSERTION(maxUint32 > offset64, "string streams only support 32 bit offsets"); + mEOF = PR_FALSE; // reset on a seek. + PRInt32 fileSize = LengthRemaining(); + PRInt32 newPosition=-1; + switch (whence) + { + case NS_SEEK_CUR: newPosition = mOffset + offset32; break; + case NS_SEEK_SET: newPosition = offset32; break; + case NS_SEEK_END: newPosition = fileSize + offset32; break; + } + if (newPosition < 0) + { + newPosition = 0; + mLastResult = NS_FILE_RESULT(PR_FILE_SEEK_ERROR); + } + if (newPosition >= fileSize) + { + newPosition = fileSize; + mEOF = PR_TRUE; + } + mOffset = newPosition; + return NS_OK; +} + + +NS_IMETHODIMP nsStringInputStream::Tell(PRInt64* outWhere) +{ + *outWhere = mOffset; + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::SetEOF() +{ + NS_NOTYETIMPLEMENTED("nsStringInputStream::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +///////// +// nsIRandomAccessStore implementation +///////// +NS_IMETHODIMP nsStringInputStream::GetAtEOF(PRBool* outAtEOF) +{ + *outAtEOF = mEOF; + return NS_OK; +} + +NS_IMETHODIMP nsStringInputStream::SetAtEOF(PRBool inAtEOF) +{ + mEOF = inAtEOF; + return NS_OK; +} + +// Factory method to get an nsInputStream from an nsAString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewStringInputStream(nsIInputStream** aStreamResult, + const nsAString& aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + char* data = ToNewCString(aStringToRead); + if (!data) + return NS_ERROR_OUT_OF_MEMORY; + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) { + nsMemory::Free(data); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(stream); + + nsresult rv = stream->AdoptData(data, aStringToRead.Length()); + if (NS_FAILED(rv)) { + nsMemory::Free(data); + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from an nsACString. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCStringInputStream(nsIInputStream** aStreamResult, + const nsACString& aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + char* data = ToNewCString(aStringToRead); + if (!data) + return NS_ERROR_OUT_OF_MEMORY; + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) { + nsMemory::Free(data); + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(stream); + + nsresult rv = stream->AdoptData(data, aStringToRead.Length()); + if (NS_FAILED(rv)) { + nsMemory::Free(data); + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from a C string. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewCharInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + + nsresult rv = stream->ShareData(aStringToRead, -1); + + if (NS_FAILED(rv)) { + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// Factory method to get an nsInputStream from a byte array. Result will +// implement nsIStringInputStream and nsIRandomAccessStore +extern "C" NS_COM nsresult +NS_NewByteInputStream(nsIInputStream** aStreamResult, + const char* aStringToRead, + PRInt32 aLength) +{ + NS_PRECONDITION(aStreamResult, "null out ptr"); + + nsStringInputStream* stream = new nsStringInputStream(); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + + nsresult rv = stream->ShareData(aStringToRead, aLength); + + if (NS_FAILED(rv)) { + NS_RELEASE(stream); + return rv; + } + + *aStreamResult = stream; + return NS_OK; +} + +// factory method for constructing a nsStringInputStream object +NS_METHOD +nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result) +{ + *result = nsnull; + + if (outer) + return NS_ERROR_NO_AGGREGATION; + + nsStringInputStream *inst; + NS_NEWXPCOM(inst, nsStringInputStream); + if (!inst) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(inst); + nsresult rv = inst->QueryInterface(iid, result); + NS_RELEASE(inst); + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/io/nsStringStream.h b/src/libs/xpcom18a4/xpcom/io/nsStringStream.h new file mode 100644 index 00000000..6f2f7f20 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsStringStream.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * darin@netscape.com (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStringStream_h__ +#define nsStringStream_h__ + +#include "nsISeekableStream.h" + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IRANDOMACCESS_IID \ +{ 0xa6cf90eb, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIRandomAccessStore +// Supports Seek, Tell etc. +//======================================================================================== +: public nsISeekableStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRANDOMACCESS_IID) + +/* "PROTECTED" */ + NS_IMETHOD GetAtEOF(PRBool* outAtEOF) = 0; + NS_IMETHOD SetAtEOF(PRBool inAtEOF) = 0; +}; // class nsIRandomAccessStore + +#include "nsIStringStream.h" + +/** + * nsStringInputStream : nsIStringInputStream + * , nsIInputStream + * , nsISeekableStream + * , nsIRandomAccessStore + */ +#define NS_STRINGINPUTSTREAM_CLASSNAME "nsStringInputStream" +#define NS_STRINGINPUTSTREAM_CONTRACTID "@mozilla.org/io/string-input-stream;1" +#define NS_STRINGINPUTSTREAM_CID \ +{ /* 0abb0835-5000-4790-af28-61b3ba17c295 */ \ + 0x0abb0835, \ + 0x5000, \ + 0x4790, \ + {0xaf, 0x28, 0x61, 0xb3, 0xba, 0x17, 0xc2, 0x95} \ +} +extern NS_METHOD nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **); + + + +#endif // nsStringStream_h__ diff --git a/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp b/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp new file mode 100644 index 00000000..99e9364a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/io/nsUnicharInputStream.cpp @@ -0,0 +1,415 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIUnicharInputStream.h" +#include "nsIByteBuffer.h" +#include "nsIUnicharBuffer.h" +#include "nsIServiceManager.h" +#include "nsString.h" +#include "nsCRT.h" +#include "nsUTF8Utils.h" +#include +#if defined(NS_WIN32) +#include +#else +#include +#endif + +class StringUnicharInputStream : public nsIUnicharInputStream { +public: + StringUnicharInputStream(nsString* aString); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32* aReadCount); + NS_IMETHOD Close(); + + nsString* mString; + PRUint32 mPos; + PRUint32 mLen; + +private: + ~StringUnicharInputStream(); +}; + +StringUnicharInputStream::StringUnicharInputStream(nsString* aString) +{ + mString = aString; + mPos = 0; + mLen = aString->Length(); +} + +StringUnicharInputStream::~StringUnicharInputStream() +{ + if (nsnull != mString) { + delete mString; + } +} + +NS_IMETHODIMP +StringUnicharInputStream::Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) +{ + if (mPos >= mLen) { + *aReadCount = 0; + return NS_OK; + } + const PRUnichar* us = mString->get(); + NS_ASSERTION(mLen >= mPos, "unsigned madness"); + PRUint32 amount = mLen - mPos; + if (amount > aCount) { + amount = aCount; + } + memcpy(aBuf, us + mPos, sizeof(PRUnichar) * amount); + mPos += amount; + *aReadCount = amount; + return NS_OK; +} + +NS_IMETHODIMP +StringUnicharInputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32 *aReadCount) +{ + PRUint32 bytesWritten; + PRUint32 totalBytesWritten = 0; + + nsresult rv; + aCount = PR_MIN(mString->Length() - mPos, aCount); + + while (aCount) { + rv = aWriter(this, aClosure, mString->get() + mPos, + totalBytesWritten, aCount, &bytesWritten); + + if (NS_FAILED(rv)) { + // don't propagate errors to the caller + break; + } + + aCount -= bytesWritten; + totalBytesWritten += bytesWritten; + mPos += bytesWritten; + } + + *aReadCount = totalBytesWritten; + + return NS_OK; +} + +nsresult StringUnicharInputStream::Close() +{ + mPos = mLen; + if (nsnull != mString) { + delete mString; + mString = 0; + } + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(StringUnicharInputStream, nsIUnicharInputStream) + +NS_COM nsresult +NS_NewStringUnicharInputStream(nsIUnicharInputStream** aInstancePtrResult, + nsString* aString) +{ + NS_PRECONDITION(nsnull != aString, "null ptr"); + NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); + if ((nsnull == aString) || (nsnull == aInstancePtrResult)) { + return NS_ERROR_NULL_POINTER; + } + + StringUnicharInputStream* it = new StringUnicharInputStream(aString); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return it->QueryInterface(NS_GET_IID(nsIUnicharInputStream), + (void**) aInstancePtrResult); +} + +//---------------------------------------------------------------------- + +class UTF8InputStream : public nsIUnicharInputStream { +public: + UTF8InputStream(); + nsresult Init(nsIInputStream* aStream, PRUint32 aBufSize); + + NS_DECL_ISUPPORTS + NS_IMETHOD Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, + PRUint32 *aReadCount); + NS_IMETHOD Close(); + +private: + ~UTF8InputStream(); + +protected: + PRInt32 Fill(nsresult * aErrorCode); + + static void CountValidUTF8Bytes(const char *aBuf, PRUint32 aMaxBytes, PRUint32& aValidUTF8bytes, PRUint32& aValidUCS2bytes); + + nsCOMPtr mInput; + nsCOMPtr mByteData; + nsCOMPtr mUnicharData; + + PRUint32 mByteDataOffset; + PRUint32 mUnicharDataOffset; + PRUint32 mUnicharDataLength; +}; + +UTF8InputStream::UTF8InputStream() : + mByteDataOffset(0), + mUnicharDataOffset(0), + mUnicharDataLength(0) +{ +} + +nsresult +UTF8InputStream::Init(nsIInputStream* aStream, PRUint32 aBufferSize) +{ + if (aBufferSize == 0) { + aBufferSize = 8192; + } + + nsresult rv = NS_NewByteBuffer(getter_AddRefs(mByteData), nsnull, aBufferSize); + if (NS_FAILED(rv)) return rv; + rv = NS_NewUnicharBuffer(getter_AddRefs(mUnicharData), nsnull, aBufferSize); + if (NS_FAILED(rv)) return rv; + + mInput = aStream; + + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(UTF8InputStream,nsIUnicharInputStream) + +UTF8InputStream::~UTF8InputStream() +{ + Close(); +} + +nsresult UTF8InputStream::Close() +{ + mInput = nsnull; + mByteData = nsnull; + mUnicharData = nsnull; + + return NS_OK; +} + +nsresult UTF8InputStream::Read(PRUnichar* aBuf, + PRUint32 aCount, + PRUint32 *aReadCount) +{ + NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness"); + PRUint32 rv = mUnicharDataLength - mUnicharDataOffset; + nsresult errorCode; + if (0 == rv) { + // Fill the unichar buffer + rv = Fill(&errorCode); + if (rv <= 0) { + *aReadCount = 0; + return errorCode; + } + } + if (rv > aCount) { + rv = aCount; + } + memcpy(aBuf, mUnicharData->GetBuffer() + mUnicharDataOffset, + rv * sizeof(PRUnichar)); + mUnicharDataOffset += rv; + *aReadCount = rv; + return NS_OK; +} + +NS_IMETHODIMP +UTF8InputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter, + void* aClosure, + PRUint32 aCount, PRUint32 *aReadCount) +{ + NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness"); + PRUint32 bytesToWrite = mUnicharDataLength - mUnicharDataOffset; + nsresult rv = NS_OK; + if (0 == bytesToWrite) { + // Fill the unichar buffer + bytesToWrite = Fill(&rv); + if (bytesToWrite <= 0) { + *aReadCount = 0; + return rv; + } + } + + if (bytesToWrite > aCount) + bytesToWrite = aCount; + + PRUint32 bytesWritten; + PRUint32 totalBytesWritten = 0; + + while (bytesToWrite) { + rv = aWriter(this, aClosure, + mUnicharData->GetBuffer() + mUnicharDataOffset, + totalBytesWritten, bytesToWrite, &bytesWritten); + + if (NS_FAILED(rv)) { + // don't propagate errors to the caller + break; + } + + bytesToWrite -= bytesWritten; + totalBytesWritten += bytesWritten; + mUnicharDataOffset += bytesWritten; + } + + *aReadCount = totalBytesWritten; + + return NS_OK; +} + +PRInt32 UTF8InputStream::Fill(nsresult * aErrorCode) +{ + if (nsnull == mInput) { + // We already closed the stream! + *aErrorCode = NS_BASE_STREAM_CLOSED; + return -1; + } + + NS_ASSERTION(mByteData->GetLength() >= mByteDataOffset, "unsigned madness"); + PRUint32 remainder = mByteData->GetLength() - mByteDataOffset; + mByteDataOffset = remainder; + PRInt32 nb = mByteData->Fill(aErrorCode, mInput, remainder); + if (nb <= 0) { + // Because we assume a many to one conversion, the lingering data + // in the byte buffer must be a partial conversion + // fragment. Because we know that we have recieved no more new + // data to add to it, we can't convert it. Therefore, we discard + // it. + return nb; + } + NS_ASSERTION(remainder + nb == mByteData->GetLength(), "bad nb"); + + // Now convert as much of the byte buffer to unicode as possible + PRUint32 srcLen, dstLen; + CountValidUTF8Bytes(mByteData->GetBuffer(),remainder + nb, srcLen, dstLen); + + // the number of UCS2 characters should always be <= the number of + // UTF8 chars + NS_ASSERTION( (remainder+nb >= srcLen), "cannot be longer than out buffer"); + NS_ASSERTION(PRInt32(dstLen) <= mUnicharData->GetBufferSize(), + "Ouch. I would overflow my buffer if I wasn't so careful."); + if (PRInt32(dstLen) > mUnicharData->GetBufferSize()) return 0; + + ConvertUTF8toUTF16 converter(mUnicharData->GetBuffer()); + + nsASingleFragmentCString::const_char_iterator start = mByteData->GetBuffer(); + nsASingleFragmentCString::const_char_iterator end = mByteData->GetBuffer() + srcLen; + + copy_string(start, end, converter); + NS_ASSERTION(converter.Length() == dstLen, "length mismatch"); + + mUnicharDataOffset = 0; + mUnicharDataLength = dstLen; + mByteDataOffset = srcLen; + + return dstLen; +} + +void +UTF8InputStream::CountValidUTF8Bytes(const char* aBuffer, PRUint32 aMaxBytes, PRUint32& aValidUTF8bytes, PRUint32& aValidUCS2chars) +{ + const char *c = aBuffer; + const char *end = aBuffer + aMaxBytes; + const char *lastchar = c; // pre-initialize in case of 0-length buffer + PRUint32 ucs2bytes = 0; + while (c < end && *c) { + lastchar = c; + ucs2bytes++; + + if (UTF8traits::isASCII(*c)) + c++; + else if (UTF8traits::is2byte(*c)) + c += 2; + else if (UTF8traits::is3byte(*c)) + c += 3; + else if (UTF8traits::is4byte(*c)) + c += 4; + else if (UTF8traits::is5byte(*c)) + c += 5; + else if (UTF8traits::is6byte(*c)) + c += 6; + else { + NS_WARNING("Unrecognized UTF8 string in UTF8InputStream::CountValidUTF8Bytes()"); + break; // Otherwise we go into an infinite loop. But what happens now? + } + } + if (c > end) { + c = lastchar; + ucs2bytes--; + } + + aValidUTF8bytes = c - aBuffer; + aValidUCS2chars = ucs2bytes; +} + +NS_COM nsresult +NS_NewUTF8ConverterStream(nsIUnicharInputStream** aInstancePtrResult, + nsIInputStream* aStreamToWrap, + PRInt32 aBufferSize) +{ + // Create converter input stream + UTF8InputStream* it = new UTF8InputStream(); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult rv = it->Init(aStreamToWrap, aBufferSize); + if (NS_FAILED(rv)) + return rv; + + return it->QueryInterface(NS_GET_IID(nsIUnicharInputStream), + (void **) aInstancePtrResult); +} diff --git a/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html new file mode 100644 index 00000000..38cadb40 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/porting.html @@ -0,0 +1,13 @@ + + +Document Moved! + + + + + \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html new file mode 100644 index 00000000..22532119 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/libxpt/xptcall/status.html @@ -0,0 +1,13 @@ + + +Document Moved! + + +
The xptcall status document has been moved to: +

+http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/status.html +

+Please update your links. +

+ + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in b/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in new file mode 100644 index 00000000..5f8cd041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/Makefile.in @@ -0,0 +1,130 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom_obsolete +LIBRARY_NAME = xpcom_compat +ifneq ($(OS_ARCH),WINNT) +SHORT_LIBNAME = xpcomct +endif + +GRE_MODULE = 1 +PACKAGE_FILE = xpcomobsolete.pkg + +DIRS = component + +REQUIRES = xpcom \ + string \ + $(NULL) + +# pull in MoreFiles for MacOSX +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +REQUIRES += macmorefiles +endif + +CPPSRCS = \ + nsFileSpec.cpp \ + nsFileStream.cpp \ + nsIFileStream.cpp \ + nsFileSpecImpl.cpp \ + nsSpecialSystemDirectory.cpp \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +REQUIRES += libreg +CPPSRCS += dlldeps.cpp +endif + +EXPORTS = \ + xpcomobsolete.h \ + nsFileSpec.h \ + nsFileStream.h \ + nsIFileStream.h \ + nsSpecialSystemDirectory.h \ + nsIRegistryUtils.h \ + $(NULL) + +LOCAL_INCLUDES = \ + -I.. \ + -I$(srcdir)/../io \ + $(NULL) + +XPIDLSRCS = nsIFileSpec.idl \ + nsIRegistry.idl \ + $(NULL) +# Force use of PIC +FORCE_USE_PIC = 1 + +SHARED_LIBRARY_LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)mozreg_s.$(LIB_SUFFIX) \ + $(NULL) + +# due to symbol conflicts on win32, this needs to be shared +FORCE_SHARED_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM_OBSOLETE + + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +CXXFLAGS += $(TK_CFLAGS) +EXTRA_DSO_LDOPTS += $(TK_LIBS) +endif + +ifeq ($(OS_ARCH),BeOS) +EXTRA_DSO_LDOPTS += -lbe +endif + +ifeq ($(OS_ARCH),WINNT) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME, shell32 ole32) +ifneq (,$(MOZ_DEBUG)$(NS_TRACE_MALLOC)) +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME, imagehlp) +endif +ifdef GNU_CXX +DSO_LDOPTS += -Wl,--export-all-symbols +endif +endif # WINNT + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in b/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in new file mode 100644 index 00000000..a8bec32d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/Makefile.in @@ -0,0 +1,81 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom_compat_c +MODULE_NAME = xpcomObsoleteModule +LIBRARY_NAME = xpcom_compat_c +ifneq ($(OS_ARCH),WINNT) +SHORT_LIBNAME = xpcomctc +endif + +ifndef MINIMO +EXPORT_LIBRARY = 1 +endif +IS_COMPONENT = 1 +GRE_MODULE = 1 + +PACKAGE_FILE = xpcomobsoletec.pkg + +REQUIRES = xpcom \ + xpcom_obsolete \ + string \ + libreg \ + $(NULL) + +CPPSRCS = \ + nsXPCOMObsolete.cpp \ + nsRegistry.cpp \ + $(NULL) + + +LOCAL_INCLUDES = \ + -I$(srcdir)/../ \ + $(NULL) + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) \ + $(MOZ_XPCOM_OBSOLETE_LIBS) \ + $(NULL) + + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp new file mode 100644 index 00000000..7f51cdca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.cpp @@ -0,0 +1,857 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone. + +#include "nsIFileStream.h" +#include "nsFileStream.h" + +#include "nsILocalFile.h" + +#include "prmem.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileSpecImpl, nsIFileSpec) + +#ifdef NS_DEBUG +#define TEST_OUT_PTR(p) \ + if (!(p)) \ + return NS_ERROR_NULL_POINTER; +#else +#define TEST_OUT_PTR(p) +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl() +//---------------------------------------------------------------------------------------- + : mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- + : mFileSpec(inSpec) + , mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::~nsFileSpecImpl() +//---------------------------------------------------------------------------------------- +{ + CloseStream(); +} + +//---------------------------------------------------------------------------------------- +/* static */ +nsresult nsFileSpecImpl::MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + nsFileSpecImpl* it = new nsFileSpecImpl(inSpec); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + return it->QueryInterface(NS_GET_IID(nsIFileSpec), (void **) result); +} // nsFileSpecImpl::MakeInterface + +#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original) +//---------------------------------------------------------------------------------------- +{ + if (original) { + nsresult rv = ((nsIFileSpec *)original)->GetFileSpec( &mFileSpec); + if (NS_SUCCEEDED( rv)) + return mFileSpec.Error(); + else + return( rv); + } + else + return( NS_ERROR_FAILURE); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsChildOf(nsIFileSpec *possibleParent, + PRBool *_retval) +{ + *_retval = mFileSpec.IsChildOf(FILESPEC(possibleParent)); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetURLString(char * *aURLString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aURLString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFileURL url(mFileSpec); + *aURLString = nsCRT::strdup(url.GetURLString()); + if (!*aURLString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} // nsFileSpecImpl::GetURLString + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetURLString(const char * aURLString) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFileURL(aURLString); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnixStyleFilePath(char * *aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aUnixStyleFilePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFilePath path(mFileSpec); + *aUnixStyleFilePath = nsCRT::strdup((const char*) path); + if (!*aUnixStyleFilePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnixStyleFilePath(const char * aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFilePath(aUnixStyleFilePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetPersistentDescriptorString(char * *aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aPersistentDescriptorString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsPersistentFileDescriptor desc(mFileSpec); + nsCAutoString data; + desc.GetData(data); + *aPersistentDescriptorString = ToNewCString(data); + if (!*aPersistentDescriptorString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + nsPersistentFileDescriptor desc(mFileSpec); + desc.SetData(nsDependentCString(aPersistentDescriptorString)); + mFileSpec = desc; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNativePath(char * *aNativePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNativePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + *aNativePath = nsCRT::strdup(mFileSpec.GetNativePathCString()); + if (!*aNativePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetNativePath(const char * aNativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aNativePath; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNSPRPath(char * *aNSPRPath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNSPRPath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsNSPRPath path(mFileSpec); + *aNSPRPath = nsCRT::strdup((const char*) path); + if (!*aNSPRPath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Error() +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsValid(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Valid(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Failed(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + *_retval = mFileSpec.Failed(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetLeafName(char * *aLeafName) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aLeafName) + *aLeafName = mFileSpec.GetLeafName(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetLeafName(const char * aLeafName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.SetLeafName(aLeafName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetParent(nsIFileSpec * *aParent) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aParent) + nsFileSpec parent; + mFileSpec.GetParent(parent); + return MakeInterface(parent, aParent); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUniqueWithSuggestedName(const char *suggestedName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(suggestedName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetModDate(PRUint32 *aModDate) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aModDate) + nsFileSpec::TimeStamp stamp; + mFileSpec.GetModDate(stamp); + *aModDate = stamp; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ModDateChanged(PRUint32 oldStamp, PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.ModDateChanged(oldStamp); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsDirectory(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsDirectory(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsFile(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsFile(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Exists(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsHidden(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsHidden(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsSymlink(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsSymlink(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ResolveSymlink() +//---------------------------------------------------------------------------------------- +{ + PRBool ignore; + return mFileSpec.ResolveSymlink(ignore); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSize(PRUint32 *aFileSize) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSize) + *aFileSize = mFileSpec.GetFileSize(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aDiskSpaceAvailable) + *aDiskSpaceAvailable = mFileSpec.GetDiskSpaceAvailable(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::AppendRelativeUnixPath(const char *relativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec += relativePath; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Touch() +//---------------------------------------------------------------------------------------- +{ + // create an empty file, like the UNIX touch command. + nsresult rv; + rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + rv = CloseStream(); + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CreateDir() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.CreateDir(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Delete(PRBool aRecursive) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.Delete(aRecursive); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Truncate(PRInt32 aNewLength) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Truncate(aNewLength); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Rename(const char *newLeafName) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Rename(newLeafName); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CopyToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.CopyToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MoveToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.MoveToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Execute(const char *args) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Execute(args); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReading() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReadingAndWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + nsresult result = NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); + if (NS_SUCCEEDED(result)) + result = NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CloseStream() +//---------------------------------------------------------------------------------------- +{ + NS_IF_RELEASE(mInputStream); + NS_IF_RELEASE(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsStreamOpen(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = (mInputStream || mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetInputStream(nsIInputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mInputStream; + NS_IF_ADDREF(mInputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetOutputStream(nsIOutputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mOutputStream; + NS_IF_ADDREF(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFileContents(const char* inString) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + PRInt32 count; + rv = Write(inString, PL_strlen(inString), &count); + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileContents(char** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = nsnull; + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + PRInt32 theSize; + rv = GetFileSize((PRUint32*)&theSize); + if (NS_SUCCEEDED(rv)) + rv = Read(_retval, theSize, &theSize); + if (NS_SUCCEEDED(rv)) + (*_retval)[theSize] = 0; + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSpec(nsFileSpec *aFileSpec) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSpec) + *aFileSpec = mFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Equals(nsIFileSpec *spec, PRBool *result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv; + + if (!result || !spec) return NS_ERROR_NULL_POINTER; + + nsFileSpec otherSpec; + + rv = spec->GetFileSpec(&otherSpec); + if (NS_FAILED(rv)) return rv; + + if (mFileSpec == otherSpec) { + *result = PR_TRUE; + } + else { + *result = PR_FALSE; + } + + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFromFileSpec(const nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Eof(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.eof(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Read(char** buffer, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + TEST_OUT_PTR(buffer) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*buffer) + *buffer = (char*)PR_Malloc(requestedCount + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.read(*buffer, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ReadLine(char** line, PRInt32 bufferSize, PRBool *wasTruncated) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(wasTruncated) + TEST_OUT_PTR(line) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*line) + *line = (char*)PR_Malloc(bufferSize + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *wasTruncated = !s.readline(*line, bufferSize); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Write(const char * data, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + //if (!mOutputStream) + // return NS_ERROR_NULL_POINTER; + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) + return rv; + } + nsOutputFileStream s(mOutputStream); + *_retval = s.write(data, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return NS_ERROR_NULL_POINTER; + nsOutputFileStream s(mOutputStream); + s.flush(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Seek(PRInt32 offset) +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_OK; + if (mOutputStream) + { + nsOutputFileStream os(mOutputStream); + os.seek(offset); + result = os.error(); + } + if (NS_SUCCEEDED(result) && mInputStream) + { + nsInputFileStream is(mInputStream); + is.seek(offset); + result = is.error(); + } + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Tell(PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.tell(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::EndLine() +//---------------------------------------------------------------------------------------- +{ + nsOutputFileStream s(mOutputStream); + s << nsEndl; + return s.error(); +} + +NS_IMPL_ISUPPORTS1(nsDirectoryIteratorImpl, nsIDirectoryIterator) + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- + : mDirectoryIterator(nsnull) +{ +} + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::~nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Init(nsIFileSpec *parent, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; + mDirectoryIterator = new nsDirectoryIterator(FILESPEC(parent), resolveSymlink); + if (!mDirectoryIterator) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + *_retval = mDirectoryIterator->Exists(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Next() +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + (*mDirectoryIterator)++; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::GetCurrentSpec(nsIFileSpec * *aCurrentSpec) +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + return nsFileSpecImpl::MakeInterface(mDirectoryIterator->Spec(), aCurrentSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsDirectoryIteratorImpl* it = new nsDirectoryIteratorImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsFileSpecImpl* it = new nsFileSpecImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + if (!result) + return NS_ERROR_NULL_POINTER; + + return nsFileSpecImpl::MakeInterface(aSrcFileSpec, result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpec(nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + return nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) return rv; + + rv = (*result)->SetNativePath(path.get()); + if (NS_FAILED(rv)) + NS_RELEASE(*result); + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result) +//---------------------------------------------------------------------------------------- +{ + return nsDirectoryIteratorImpl::Create(nsnull, NS_GET_IID(nsIDirectoryIterator), (void**)result); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h new file mode 100644 index 00000000..502e254f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsFileSpecImpl.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _FILESPECIMPL_H_ +#define _FILESPECIMPL_H_ + +#include "nscore.h" +#include "nsIFileSpec.h" +#include "nsFileSpec.h" + +//======================================================================================== +class nsFileSpecImpl +//======================================================================================== + : public nsIFileSpec +{ + + public: + + NS_DECL_ISUPPORTS + + NS_DECL_NSIFILESPEC + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + + //---------------------- + // Implementation + //---------------------- + + nsFileSpecImpl(); + nsFileSpecImpl(const nsFileSpec& inSpec); + static nsresult MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** outSpec); + + //---------------------- + // Data + //---------------------- + + nsFileSpec mFileSpec; + nsIInputStream* mInputStream; + nsIOutputStream* mOutputStream; + +private: + ~nsFileSpecImpl(); +}; // class nsFileSpecImpl + +//======================================================================================== +class nsDirectoryIteratorImpl +//======================================================================================== + : public nsIDirectoryIterator +{ + +public: + + nsDirectoryIteratorImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(nsIFileSpec *parent, PRBool resolveSymlink); + + NS_IMETHOD Exists(PRBool *_retval); + + NS_IMETHOD Next(); + + NS_IMETHOD GetCurrentSpec(nsIFileSpec * *aCurrentSpec); + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + +private: + ~nsDirectoryIteratorImpl(); + +protected: + nsDirectoryIterator* mDirectoryIterator; +}; // class nsDirectoryIteratorImpl + +#endif // _FILESPECIMPL_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl new file mode 100644 index 00000000..bc9990e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistry.idl @@ -0,0 +1,186 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEnumerator.idl" + +interface nsIFile; + +typedef PRUint32 nsRegistryKey; +typedef long nsWellKnownRegistry; + +[scriptable,uuid(5D41A440-8E37-11d2-8059-00600811A9C3)] +interface nsIRegistry : nsISupports +{ + const long None = 0; + const long Users = 1; + const long Common = 2; + const long CurrentUser = 3; + + const long ApplicationComponentRegistry = 1; + const long ApplicationRegistry = 2; + + // Dont use this one. This for internal use only. + const long ApplicationCustomRegistry = -1; + + void open(in nsIFile regFile); + void openWellKnownRegistry(in nsWellKnownRegistry regid); + + void flush(); + boolean isOpen(); + + nsRegistryKey addKey(in nsRegistryKey baseKey, in wstring keyname); + nsRegistryKey getKey(in nsRegistryKey baseKey, in wstring keyname); + void removeKey(in nsRegistryKey baseKey, in wstring keyname); + + wstring getString(in nsRegistryKey baseKey, in wstring valname); + void setString(in nsRegistryKey baseKey, in wstring valname, in wstring value); + + string getStringUTF8(in nsRegistryKey baseKey, in string path); + void setStringUTF8(in nsRegistryKey baseKey, in string path, in string value); + + void getBytesUTF8(in nsRegistryKey baseKey, in string path, out PRUint32 length, [retval, array, size_is(length)] out PRUint8 valueArray); + void setBytesUTF8(in nsRegistryKey baseKey, in string path, in PRUint32 length, [array, size_is(length)] in PRUint8 valueArray); + PRInt32 getInt(in nsRegistryKey baseKey, in string path); + void setInt(in nsRegistryKey baseKey, in string path, in PRInt32 value); + PRInt64 getLongLong(in nsRegistryKey baseKey, in string path); + void setLongLong(in nsRegistryKey baseKey, in string path, inout PRInt64 value); + + /** + * addSubtree() and friends need to be renamed to addKeyUTF8(). + * If you are using these forms make sure you pass UTF8 data + */ + nsRegistryKey addSubtree(in nsRegistryKey baseKey, in string path); + void removeSubtree(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtree(in nsRegistryKey baseKey, in string path); + + nsRegistryKey addSubtreeRaw(in nsRegistryKey baseKey, in string path); + void removeSubtreeRaw(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtreeRaw(in nsRegistryKey baseKey, in string path); + + nsIEnumerator enumerateSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateAllSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateValues(in nsRegistryKey baseKey); + + const unsigned long String = 1; + const unsigned long Int32 = 2; + const unsigned long Bytes = 3; + const unsigned long File = 4; + + unsigned long getValueType(in nsRegistryKey baseKey, in string path); + PRUint32 getValueLength(in nsRegistryKey baseKey, in string path); + void deleteValue(in nsRegistryKey baseKey, in string path); + + /** + * escapeKey() takes arbitrary binary data and converts it into + * valid ASCII which can be used as registry key or value names + */ + void escapeKey([array, size_is(length)] in PRUint8 key, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 escaped); + void unescapeKey([array, size_is(length)] in PRUint8 escaped, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 key); + + attribute string currentUserName; + + void pack(); +}; + +[scriptable, uuid(8cecf236-1dd2-11b2-893c-f9848956eaec)] +interface nsIRegistryEnumerator : nsIEnumerator +{ + void currentItemInPlaceUTF8(out nsRegistryKey key, + [shared, retval] out string item); +}; + +[scriptable, uuid(D1B54831-AC07-11d2-805E-00600811A9C3)] +interface nsIRegistryNode : nsISupports +{ + readonly attribute string nameUTF8; + readonly attribute wstring name; + readonly attribute nsRegistryKey key; +}; + +[scriptable,uuid(5316C380-B2F8-11d2-A374-0080C6F80E4B)] +interface nsIRegistryValue : nsISupports +{ + readonly attribute wstring name; + readonly attribute string nameUTF8; + readonly attribute unsigned long type; + readonly attribute PRUint32 length; +}; + +[uuid(3A15FC88-7A61-4Ab4-8E58-31E95fAB3DA8)] +/** + * It sucks that nsIRegistry has to always allocate and return + * strings. nsIRegistryGetter adds in interfaces for non allocating getters + * to registry values. + */ +interface nsIRegistryGetter : nsISupports +{ + /** + * Get a string value of attribute valname in widestring or utf8 format + * + * @return + * NS_OK on success. + * buf has the string value copied into it. length is NOT changed. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in chars including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various failure codes otherwise. buf and length wont be updated. + */ + void getStringUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout char buf, inout PRUint32 length); + + /** + * Get a a byte array value of attribute valname + * + * @return + * NS_OK on success. buf has the string value copied into it. + * length is updated to actual number of bytes copied into buf. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in PRUint8s including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various other failure codes otherwise. buf and length wont be updated. + */ + void getBytesUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout PRUint8 buf, inout PRUint32 length); +}; + +%{ C++ +#include "nsIRegistryUtils.h" +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h new file mode 100644 index 00000000..a3d74d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsIRegistryUtils.h @@ -0,0 +1,63 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsIRegistryUtils_h +#define __nsIRegistryUtils_h + +#define NS_REGISTRY_CONTRACTID "@mozilla.org/registry;1" +#define NS_REGISTRY_CLASSNAME "Mozilla Registry" +/* be761f00-a3b0-11d2-996c-0080c7cb1081 */ +#define NS_REGISTRY_CID \ +{ \ + 0xbe761f00, \ + 0xa3b0, \ + 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x81} \ +} + +/*------------------------------- Error Codes ---------------------------------- +------------------------------------------------------------------------------*/ +#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 ) +#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 ) +#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 ) +#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 ) +#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 ) +#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 ) +#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 ) +#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 ) +#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 ) + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp new file mode 100644 index 00000000..d3ecfe62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.cpp @@ -0,0 +1,2019 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#ifdef MOZ_LOGGING +#define FORCE_PR_LOG /* Allow logging in the release build */ +#endif + +#include "nsIGenericFactory.h" + +#include "nsRegistry.h" +#include "nsIEnumerator.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "NSReg.h" +#include "prmem.h" +#include "prlock.h" +#include "prlog.h" +#include "prprf.h" +#include "nsCRT.h" +#include "nsMemory.h" + +#include "nsCOMPtr.h" +#include "nsILocalFile.h" +#include "nsIServiceManager.h" +#include "nsTextFormatter.h" + +#ifdef XP_BEOS +#include +#include +#endif + +/* extra locking for the paranoid */ +/* #define EXTRA_THREADSAFE */ +#ifndef EXTRA_THREADSAFE +#define PR_Lock(x) (void)0 +#define PR_Unlock(x) (void)0 +#endif + +// Logging of debug output +extern PRLogModuleInfo *nsComponentManagerLog; + +PRUnichar widestrFormat[] = { PRUnichar('%'),PRUnichar('s'),PRUnichar(0)}; + +/*-------------------------------- nsRegistry ---------------------------------- +| This class implements the nsIRegistry interface using the functions | +| provided by libreg (as declared in mozilla/modules/libreg/include/NSReg.h). | +| | +| Since that interface is designed to match the libreg function, this class | +| is implemented with each member function being a simple wrapper for the | +| corresponding libreg function. | +| | +| #define EXTRA_THREADSAFE if you are worried about libreg thread safety. | +| It should not be necessary, but I'll leave in the code for the paranoid. | +------------------------------------------------------------------------------*/ + +#define NS_MOZILLA_DIR_PERMISSION 00700 + +#include "nsRegistry.h" +/* +struct nsRegistry : public nsIRegistry { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistry interface functions. + NS_DECL_NSIREGISTRY + + // ctor/dtor + nsRegistry(); + +private: + ~nsRegistry(); + +protected: + HREG mReg; // Registry handle. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; // libreg isn't threadsafe. Use locks to synchronize. +#endif + char *mCurRegFile; // these are to prevent open from opening the registry again + nsWellKnownRegistry mCurRegID; + + NS_IMETHOD Close(); +}; // nsRegistry +*/ + +#include "nsIFactory.h" +/*----------------------------- nsRegistryFactory ------------------------------ +| Class factory for nsRegistry objects. | +------------------------------------------------------------------------------*/ +struct nsRegistryFactory : public nsIFactory { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // nsIFactory methods + NS_IMETHOD CreateInstance(nsISupports *,const nsIID &,void **); + NS_IMETHOD LockFactory(PRBool aLock); + + // ctor + nsRegistryFactory(); +}; + + +/*--------------------------- nsRegSubtreeEnumerator --------------------------- +| This class implements the nsIEnumerator interface and is used to implement | +| the nsRegistry EnumerateSubtrees and EnumerateAllSubtrees functions. | +------------------------------------------------------------------------------*/ +struct nsRegSubtreeEnumerator : public nsIRegistryEnumerator { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIEnumerator interface functions. + NS_DECL_NSIENUMERATOR + + // And our magic behind-the-back fast-path thing. + NS_DECL_NSIREGISTRYENUMERATOR + + // ctor/dtor + nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all ); + // virtual dtor since subclasses call our Release() + virtual ~nsRegSubtreeEnumerator(); + +protected: + NS_IMETHOD advance(); // Implementation file; does appropriate NR_RegEnum call. + HREG mReg; // Handle to registry we're affiliated with. + RKEY mKey; // Base key being enumerated. + char mName[MAXREGPATHLEN]; // The name of the current key which is in mNext + REGENUM mEnum; // Corresponding libreg "enumerator". + REGENUM mNext; // Lookahead value. + PRUint32 mStyle; // Style (indicates all or some); + PRBool mDone; // Done flag. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegSubtreeEnumerator + + +/*--------------------------- nsRegValueEnumerator ----------------------------- +| This class is a variation on nsRegSubtreeEnumerator that allocates | +| nsRegistryValue objects rather than nsRegistryNode objects. It also | +| overrides certain functions to make sure the "value" oriented libreg | +| functions used rather than the subtree oriented ones. | +------------------------------------------------------------------------------*/ +struct nsRegValueEnumerator : public nsRegSubtreeEnumerator { + // Override CurrentItem to allocate nsRegistryValue objects. + NS_IMETHOD CurrentItem( nsISupports **result ); + + // Override advance() to use proper NR_RegEnumEntries. + NS_IMETHOD advance(); + + // ctor/dtor + nsRegValueEnumerator( HREG hReg, RKEY rKey ); +}; // nsRegValueEnumerator + +/*------------------------------ nsRegistryNode -------------------------------- +| This class implements the nsIRegistryNode interface. Instances are | +| allocated by nsRegSubtreeEnumerator::CurrentItem. | +------------------------------------------------------------------------------*/ +struct nsRegistryNode : public nsIRegistryNode { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistryNode interface functions. + NS_DECL_NSIREGISTRYNODE + + // ctor + nsRegistryNode( HREG hReg, char *name, RKEY childKey ); + +private: + ~nsRegistryNode(); + +protected: + HREG mReg; // Handle to registry this node is part of. + char mName[MAXREGPATHLEN]; // Buffer to hold name. + RKEY mChildKey; // Key corresponding to mName +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegistryNode + + +/*------------------------------ nsRegistryValue ------------------------------- +| This class implements the nsIRegistryValue interface. Instances are | +| allocated by nsRegValueEnumerator::CurrentItem. | +------------------------------------------------------------------------------*/ +struct nsRegistryValue : public nsIRegistryValue { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistryValue interface functions. + NS_DECL_NSIREGISTRYVALUE + + // ctor + nsRegistryValue( HREG hReg, RKEY key, REGENUM slot ); + +private: + ~nsRegistryValue(); + +protected: + nsresult getInfo(); // Get registry info. + HREG mReg; // Handle to registry this node is part of. + RKEY mKey; // Key this node is under. + REGENUM mEnum; // Copy of corresponding content of parent enumerator. + REGINFO mInfo; // Value info. + char mName[MAXREGNAMELEN]; // Buffer to hold name. + REGERR mErr; // XXX This causes this class to be NON THREAD SAFE +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; +#endif +}; // nsRegistryValue + + +/*----------------------------- regerr2nsresult -------------------------------- +| This utility function maps a REGERR value to a corresponding nsresult | +| error code. | +------------------------------------------------------------------------------*/ +static nsresult regerr2nsresult( REGERR err ) { + nsresult rv = NS_ERROR_UNEXPECTED; + switch( err ) { + case REGERR_OK: + rv = NS_OK; + break; + + case REGERR_FAIL: + rv = NS_ERROR_FAILURE; + break; + + case REGERR_NOMORE: + rv = NS_ERROR_REG_NO_MORE; + break; + + case REGERR_NOFIND: + rv = NS_ERROR_REG_NOT_FOUND; + break; + + case REGERR_PARAM: + case REGERR_BADTYPE: + case REGERR_BADNAME: + rv = NS_ERROR_INVALID_ARG; + break; + + case REGERR_NOFILE: + rv = NS_ERROR_REG_NOFILE; + break; + + case REGERR_MEMORY: + rv = NS_ERROR_OUT_OF_MEMORY; + break; + + case REGERR_BUFTOOSMALL: + rv = NS_ERROR_REG_BUFFER_TOO_SMALL; + break; + + case REGERR_NAMETOOLONG: + rv = NS_ERROR_REG_NAME_TOO_LONG; + break; + + case REGERR_NOPATH: + rv = NS_ERROR_REG_NO_PATH; + break; + + case REGERR_READONLY: + rv = NS_ERROR_REG_READ_ONLY; + break; + + case REGERR_BADUTF8: + rv = NS_ERROR_REG_BAD_UTF8; + break; + + } + return rv; +} + +/*----------------------------- reginfo2DataType ------------------------------- +| This utility function converts the type field in the REGINFO structure to | +| the corresponding nsIRegistry::DataType value. | +------------------------------------------------------------------------------*/ +static void reginfo2DataType( const REGINFO &in, PRUint32 &out ) { + // Transfer information, based on entry type. + switch( in.entryType ) { + case REGTYPE_ENTRY_STRING_UTF: + out = nsIRegistry::String; + //out.length = in.entryLength; + break; + + case REGTYPE_ENTRY_INT32_ARRAY: + out = nsIRegistry::Int32; + // Convert length in bytes to array dimension. + //out.length = in.entryLength / sizeof(PRInt32); + break; + + case REGTYPE_ENTRY_BYTES: + out = nsIRegistry::Bytes; + //out.length = in.entryLength; + break; + + case REGTYPE_ENTRY_FILE: + out = nsIRegistry::File; + //out.length = in.entryLength; + break; + } +} + +/*----------------------------- reginfo2DataType ------------------------------- +| This utility function converts the length field in the REGINFO structure to | +| the proper units (if type==Int32 array, we divide by sizeof(PRInt32)). | +------------------------------------------------------------------------------*/ +static void reginfo2Length( const REGINFO &in, PRUint32 &out ) { + // Transfer information, based on entry type. + switch( in.entryType ) { + case REGTYPE_ENTRY_STRING_UTF: + out = in.entryLength; + break; + + case REGTYPE_ENTRY_INT32_ARRAY: + // Convert length in bytes to array dimension. + out = in.entryLength / sizeof(PRInt32); + break; + + case REGTYPE_ENTRY_BYTES: + out = in.entryLength; + break; + + case REGTYPE_ENTRY_FILE: + out = in.entryLength; + break; + } +} + +/*------------------------ nsISupports Implementation -------------------------- +| This code generates the implementation of the nsISupports member functions | +| for each class implemented in this file. | +------------------------------------------------------------------------------*/ +NS_IMPL_THREADSAFE_ISUPPORTS2(nsRegistry, nsIRegistry, nsIRegistryGetter) +NS_IMPL_ISUPPORTS2( nsRegSubtreeEnumerator, nsIEnumerator, + nsIRegistryEnumerator) +NS_IMPL_ISUPPORTS1( nsRegistryNode, nsIRegistryNode ) +NS_IMPL_ISUPPORTS1( nsRegistryValue, nsIRegistryValue ) + +/*-------------------------- nsRegistry::nsRegistry ---------------------------- +| Vanilla nsRegistry constructor. | +------------------------------------------------------------------------------*/ +nsRegistry::nsRegistry() + : mReg(0), mCurRegID(0) { +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + NR_StartupRegistry(); + return; +} + +/*------------------------- nsRegistry::~nsRegistry ---------------------------- +| The dtor closes the registry file(if open). | +------------------------------------------------------------------------------*/ +nsRegistry::~nsRegistry() { + if( mReg ) { + Close(); + } +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif + NR_ShutdownRegistry(); + return; +} + +/*----------------------------- nsRegistry::Open ------------------------------- +| If the argument is null, delegate to OpenDefault, else open the registry | +| file. We first check to see if a registry file is already open and close | +| it if so. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Open( nsIFile *regFile ) { + REGERR err = REGERR_OK; + + // Check for default. + if( !regFile ) { + return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry); + } + + nsCAutoString regPath; + nsresult rv = regFile->GetNativePath(regPath); + if (NS_FAILED(rv)) return rv; + +#ifdef DEBUG_dp + printf("nsRegistry: Opening registry %s\n", regPath.get()); +#endif /* DEBUG_dp */ + + if (mCurRegID != nsIRegistry::None && mCurRegID != nsIRegistry::ApplicationCustomRegistry) + { + // Cant open another registry without closing explictly. + return NS_ERROR_INVALID_ARG; + } + + // Do we have an open registry ? + if (mCurRegID != nsIRegistry::None) + { + PRBool equals; + if (mCurRegFile && NS_SUCCEEDED(mCurRegFile->Equals(regFile, &equals)) && equals) + { + // The right one is already open + return NS_OK; + } + else + { + // Opening a new registry without closing an already open one. + // This is an error. + return NS_ERROR_FAILURE; + } + } + + // Open specified registry. + PR_Lock(mregLock); + err = NR_RegOpen(NS_CONST_CAST(char*,regPath.get()), &mReg); + PR_Unlock(mregLock); + + mCurRegID = nsIRegistry::ApplicationCustomRegistry; + + // No error checking for no mem. Trust me. + if (NS_FAILED(regFile->Clone(getter_AddRefs(mCurRegFile)))) + mCurRegFile = nsnull; // not fatal + + // Convert the result. + return regerr2nsresult( err ); +} + +static void +EnsureDefaultRegistryDirectory() { +#if defined(XP_UNIX) && !defined(XP_MACOSX) + // Create ~/.mozilla as that is the default place for the registry file + + /* The default registry on the unix system is $HOME/.mozilla/registry per + * vr_findGlobalRegName(). vr_findRegFile() will create the registry file + * if it doesn't exist. But it wont create directories. + * + * Hence we need to create the directory if it doesn't exist already. + * + * Why create it here as opposed to the app ? + * ------------------------------------------ + * The app cannot create the directory in main() as most of the registry + * and initialization happens due to use of static variables. + * And we dont want to be dependent on the order in which + * these static stuff happen. + * + * Permission for the $HOME/.mozilla will be Read,Write,Execute + * for user only. Nothing to group and others. + */ + char *home = getenv("HOME"); + if (home != NULL) + { + char dotMozillaDir[1024]; + PR_snprintf(dotMozillaDir, sizeof(dotMozillaDir), + "%s/" MOZ_USER_DIR, home); + if (PR_Access(dotMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) + { + PR_MkDir(dotMozillaDir, NS_MOZILLA_DIR_PERMISSION); + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsComponentManager: Creating Directory %s", dotMozillaDir)); + } + } +#endif /* XP_UNIX */ + +#ifdef XP_BEOS + BPath p; + const char *settings = "/boot/home/config/settings"; + if(find_directory(B_USER_SETTINGS_DIRECTORY, &p) == B_OK) + settings = p.Path(); + char settingsMozillaDir[1024]; + PR_snprintf(settingsMozillaDir, sizeof(settingsMozillaDir), + "%s/" MOZ_USER_DIR, settings); + if (PR_Access(settingsMozillaDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { + PR_MkDir(settingsMozillaDir, NS_MOZILLA_DIR_PERMISSION); + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsComponentManager: Creating Directory %s", settingsMozillaDir)); + } +#endif +} + +/*----------------------------- nsRegistry::OpenWellKnownRegistry -------------- +| Takes a registry id and maps that to a file name for opening. We first check | +| to see if a registry file is already open and close it if so. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::OpenWellKnownRegistry( nsWellKnownRegistry regid ) +{ + REGERR err = REGERR_OK; + + if (mCurRegID != nsIRegistry::None && mCurRegID != regid) + { + // Cant open another registry without closing explictly. + return NS_ERROR_INVALID_ARG; + } + + if (mCurRegID == regid) + { + // Already opened. + return NS_OK; + } + + nsresult rv; + nsCOMPtr registryLocation; + + PRBool foundReg = PR_FALSE; + nsCAutoString regFile; + + switch ( (nsWellKnownRegistry) regid ) { + case ApplicationComponentRegistry: + NS_WARNING("ApplicationComponentRegistry is unsupported!"); + break; + case ApplicationRegistry: + { + EnsureDefaultRegistryDirectory(); + nsCOMPtr directoryService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + directoryService->Get(NS_APP_APPLICATION_REGISTRY_FILE, NS_GET_IID(nsIFile), + getter_AddRefs(registryLocation)); + + if (registryLocation) + { + foundReg = PR_TRUE; + rv = registryLocation->GetNativePath(regFile); // dougt fix... + // dveditz needs to fix his registry so that I can pass an + // nsIFile interface and not hack + if (NS_FAILED(rv)) + return rv; + } + } + break; + + default: + break; + } + + if (foundReg == PR_FALSE) { + return NS_ERROR_REG_BADTYPE; + } + +#ifdef DEBUG_dp + printf("nsRegistry: Opening std registry %s\n", regFile.get()); +#endif /* DEBUG_dp */ + + PR_Lock(mregLock); + err = NR_RegOpen(NS_CONST_CAST(char*, regFile.get()), &mReg ); + PR_Unlock(mregLock); + + // Store the registry that was opened for optimizing future opens. + mCurRegID = regid; + + // Convert the result. + return regerr2nsresult( err ); +} + +#if 0 +/*-------------------------- nsRegistry::OpenDefault --------------------------- +| Open the "default" registry; in the case of this libreg-based implementation | +| that is done by passing a null file name pointer to NR_RegOpen. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::OpenDefault() { + return OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry); +} +#endif + +/*----------------------------- nsRegistry::Close ------------------------------ +| Tests the mReg handle and if non-null, closes the registry via NR_RegClose. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Close() { + REGERR err = REGERR_OK; + if( mReg ) { + PR_Lock(mregLock); + err = NR_RegClose( mReg ); + PR_Unlock(mregLock); + mReg = 0; + mCurRegFile = nsnull; + mCurRegID = 0; + } + return regerr2nsresult( err ); +} + +/*----------------------------- nsRegistry::Flush ------------------------------ +| Flushes the registry via NR_RegFlush. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Flush() { + REGERR err = REGERR_FAIL; + if( mReg ) { + PR_Lock(mregLock); + err = NR_RegFlush( mReg ); + PR_Unlock(mregLock); + } + return regerr2nsresult( err ); +} + +/*----------------------------- nsRegistry::IsOpen ----------------------------- +| Tests the mReg handle and returns whether the registry is open or not. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::IsOpen( PRBool *result ) { + *result = ( mReg != 0 ); + return NS_OK; +} + + +/*--------------------------- nsRegistry::AddKey ------------------------------- +| Add a key into the registry or find an existing one. This is generally used | +| instead of GetKey unless it's an error for the key not to exist already i +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddKey( nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval) +{ + if ( !keyname ) + return NS_ERROR_NULL_POINTER; + + return AddSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval ); +} + +/*--------------------------- nsRegistry::GetKey ------------------------------- +| returns the nsRegistryKey associated with a given node in the registry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetKey(nsRegistryKey baseKey, const PRUnichar *keyname, nsRegistryKey *_retval) +{ + if ( !keyname || !_retval ) + return NS_ERROR_NULL_POINTER; + + return GetSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get(), _retval ); +} + +/*--------------------------- nsRegistry::RemoveKey ---------------------------- +| Delete a key from the registry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveKey(nsRegistryKey baseKey, const PRUnichar *keyname) +{ + if ( !keyname ) + return NS_ERROR_NULL_POINTER; + + return RemoveSubtree( baseKey, NS_ConvertUCS2toUTF8(keyname).get() ); +} + +NS_IMETHODIMP nsRegistry::GetString(nsRegistryKey baseKey, const PRUnichar *valname, PRUnichar **_retval) +{ + // Make sure caller gave us place for result. + if ( !valname || !_retval ) + return NS_ERROR_NULL_POINTER; + + // initialize the return value + *_retval = nsnull; + nsXPIDLCString tmpstr; + + nsresult rv = GetStringUTF8( baseKey, NS_ConvertUCS2toUTF8(valname).get(), getter_Copies(tmpstr) ); + + if (NS_SUCCEEDED(rv)) + { + *_retval = nsTextFormatter::smprintf( widestrFormat, tmpstr.get() ); + if ( *_retval == nsnull ) + rv = NS_ERROR_OUT_OF_MEMORY; + } + + return rv; +} + +NS_IMETHODIMP nsRegistry::SetString(nsRegistryKey baseKey, const PRUnichar *valname, const PRUnichar *value) +{ + if ( !valname || ! value ) + return NS_ERROR_NULL_POINTER; + + return SetStringUTF8( baseKey, + NS_ConvertUCS2toUTF8(valname).get(), + NS_ConvertUCS2toUTF8(value).get() ); +} + +/*--------------------------- nsRegistry::GetString ---------------------------- +| First, look for the entry using GetValueInfo. If found, and it's a string, | +| allocate space for it and fetch the value. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetStringUTF8( nsRegistryKey baseKey, const char *path, char **result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // Make sure caller gave us place for result. + if ( !result ) + return NS_ERROR_NULL_POINTER; + + char regStr[MAXREGPATHLEN]; + + // initialize the return value + *result = 0; + + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, regStr, + sizeof(regStr) ); + PR_Unlock(mregLock); + + if ( err == REGERR_OK ) + { + *result = nsCRT::strdup(regStr); + if (!*result) + rv = NS_ERROR_OUT_OF_MEMORY; + } + else if ( err == REGERR_BUFTOOSMALL ) + { + // find the real size and malloc it + PRUint32 length; + rv = GetValueLength( baseKey, path, &length ); + // See if that worked. + if( rv == NS_OK ) + { + *result =(char*)nsMemory::Alloc( length + 1 ); + if( *result ) + { + // Get string from registry into result buffer. + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, *result, length+1 ); + PR_Unlock(mregLock); + + // Convert status. + rv = regerr2nsresult( err ); + if ( rv != NS_OK ) + { + // Didn't get result, free buffer + nsCRT::free( *result ); + *result = 0; + } + } + else + { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } + else + { + // Convert status. + rv = regerr2nsresult( err ); + NS_ASSERTION(NS_FAILED(rv), "returning success code on failure"); + } + + return rv; +} + +NS_IMETHODIMP +nsRegistry::GetStringUTF8IntoBuffer( nsRegistryKey baseKey, const char *path, + char *buf, PRUint32 *length ) +{ + REGERR err = REGERR_OK; + + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntryString( mReg,(RKEY)baseKey,(char*)path, buf, *length ); + PR_Unlock(mregLock); + + // Convert status. + nsresult rv = regerr2nsresult( err ); + + if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) { + // fill length with the actual length + nsresult rv1 = GetValueLength( baseKey, path, length ); + if(NS_FAILED(rv1)) + return rv1; + } + + return rv; +} + +/*--------------------------- nsRegistry::SetString ---------------------------- +| Simply sets the registry contents using NR_RegSetEntryString. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetStringUTF8( nsRegistryKey baseKey, const char *path, const char *value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntryString( mReg,(RKEY)baseKey,(char*)path,(char*)value ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*---------------------------- nsRegistry::GetBytesUTF8 ------------------------------ +| This function is just shorthand for fetching a char array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32* length, PRUint8** result) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + if ( !result ) + return NS_ERROR_NULL_POINTER; + + char regStr[MAXREGPATHLEN]; + + // initialize the return value + *length = 0; + *result = 0; + + // Get info about the requested entry. + PRUint32 type; + rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if( rv == NS_OK ) + { + // Make sure the entry is an PRInt8 array. + if( type == Bytes ) + { + // Attempt to get string into our fixed buffer + PR_Lock(mregLock); + uint32 length2 = sizeof regStr; + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), regStr, &length2); + PR_Unlock(mregLock); + + if ( err == REGERR_OK ) + { + *length = length2; + *result = (PRUint8*)(nsCRT::strdup(regStr)); + if (!*result) + { + rv = NS_ERROR_OUT_OF_MEMORY; + *length = 0; + } + else + { + *length = length2; + } + } + else if ( err == REGERR_BUFTOOSMALL ) + { + // find the real size and malloc it + rv = GetValueLength( baseKey, path, length ); + // See if that worked. + if( rv == NS_OK ) + { + *result = NS_REINTERPRET_CAST(PRUint8*,nsMemory::Alloc( *length )); + if( *result ) + { + // Get bytes from registry into result field. + PR_Lock(mregLock); + length2 = *length; + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), *result, &length2); + *length = length2; + PR_Unlock(mregLock); + // Convert status. + rv = regerr2nsresult( err ); + if ( rv != NS_OK ) + { + // Didn't get result, free buffer + nsCRT::free( NS_REINTERPRET_CAST(char*, *result) ); + *result = 0; + *length = 0; + } + } + else + { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } + } + else + { + // They asked for the wrong type of value. + rv = NS_ERROR_REG_BADTYPE; + } + } + return rv; +} + +NS_IMETHODIMP +nsRegistry::GetBytesUTF8IntoBuffer( nsRegistryKey baseKey, const char *path, + PRUint8 *buf, PRUint32* length ) +{ + REGERR err = REGERR_OK; + + // Get info about the requested entry. + PRUint32 type; + nsresult rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if(NS_FAILED(rv)) + return rv; + // Make sure we are dealing with bytes + if (type != Bytes) + return NS_ERROR_REG_BADTYPE; + + // Attempt to get bytes into our fixed buffer + PR_Lock(mregLock); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,NS_CONST_CAST(char*,path), + buf, (uint32 *)length ); + PR_Unlock(mregLock); + + rv = regerr2nsresult(rv); + + if (rv == NS_ERROR_REG_BUFFER_TOO_SMALL) { + // fill length with the actual length + nsresult rv1 = GetValueLength( baseKey, path, length ); + if(NS_FAILED(rv1)) + return rv1; + } + + + return rv; +} + +/*---------------------------- nsRegistry::GetInt ------------------------------ +| This function is just shorthand for fetching a 1-element PRInt32 array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetInt( nsRegistryKey baseKey, const char *path, PRInt32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // Make sure caller gave us place for result. + if( result ) { + // Get info about the requested entry. + PRUint32 type; + rv = GetValueType( baseKey, path, &type ); + // See if that worked. + if( rv == NS_OK ) { + // Make sure the entry is an PRInt32 array. + if( type == Int32 ) { + uint32 len = sizeof *result; + // Get int from registry into result field. + PR_Lock(mregLock); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path, result, &len ); + PR_Unlock(mregLock); + // Convert status. + rv = regerr2nsresult( err ); + } else { + // They asked for the wrong type of value. + rv = NS_ERROR_REG_BADTYPE; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + + +/*---------------------------- nsRegistry::GetLongLong-------------------------- +| This function is just shorthand for fetching a 1-element PRInt64 array. We | +| implement it "manually" using NR_RegGetEntry | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetLongLong( nsRegistryKey baseKey, const char *path, PRInt64 *result ) { + REGERR err = REGERR_OK; + + PR_Lock(mregLock); + + uint32 length = sizeof(PRInt64); + err = NR_RegGetEntry( mReg,(RKEY)baseKey,(char*)path,(void*)result,&length); + + PR_Unlock(mregLock); + + // Convert status. + return regerr2nsresult( err ); +} +/*---------------------------- nsRegistry::SetBytesUTF8 ------------------------------ +| Write out the value as a char array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetBytesUTF8( nsRegistryKey baseKey, const char *path, PRUint32 length, PRUint8* value) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_BYTES, + (char*)value, + length); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*---------------------------- nsRegistry::SetInt ------------------------------ +| Write out the value as a one-element PRInt32 array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetInt( nsRegistryKey baseKey, const char *path, PRInt32 value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_INT32_ARRAY, + &value, + sizeof value ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + + + +/*---------------------------- nsRegistry::SetLongLong--------------------------- +| Write out the value as a one-element PRInt64 array, using NR_RegSetEntry. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetLongLong( nsRegistryKey baseKey, const char *path, PRInt64* value ) { + REGERR err = REGERR_OK; + // Set the contents. + PR_Lock(mregLock); + + err = NR_RegSetEntry( mReg, + (RKEY)baseKey, + (char*)path, + REGTYPE_ENTRY_BYTES, + (void*)value, + sizeof(PRInt64) ); + + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*-------------------------- nsRegistry::AddSubtree ---------------------------- +| Add a new registry subkey with the specified name, using NR_RegAddKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + REGERR err = REGERR_OK; + // Add the subkey. + PR_Lock(mregLock); + err = NR_RegAddKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*-------------------------- nsRegistry::AddSubtreeRaw-------------------------- +| Add a new registry subkey with the specified name, using NR_RegAddKeyRaw | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::AddSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + REGERR err = REGERR_OK; + // Add the subkey. + PR_Lock(mregLock); + err = NR_RegAddKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + + +/*------------------------- nsRegistry::RemoveSubtree -------------------------- +| Deletes the subtree at a given location using NR_RegDeleteKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveSubtree( nsRegistryKey baseKey, const char *path ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // libreg doesn't delete keys if there are subkeys under the key + // Hence we have to recurse through to delete the subtree + + RKEY key; + + PR_Lock(mregLock); + err = NR_RegGetKey(mReg, baseKey, (char *)path, &key); + PR_Unlock(mregLock); + if (err != REGERR_OK) + { + rv = regerr2nsresult( err ); + return rv; + } + + // Now recurse through and delete all keys under hierarchy + + char subkeyname[MAXREGPATHLEN+1]; + REGENUM state = 0; + subkeyname[0] = '\0'; + while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, sizeof(subkeyname), + REGENUM_NORMAL) == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...recursing into %s\n", subkeyname); +#endif /* DEBUG_dp */ + // Even though this is not a "Raw" API the subkeys may still, in fact, + // *be* raw. Since we're recursively deleting this will work either way. + // If we were guaranteed none would be raw then a depth-first enumeration + // would be much more efficient. + err = RemoveSubtreeRaw(key, subkeyname); + if (err != REGERR_OK) break; + } + + // If success in deleting all subkeys, delete this key too + if (err == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...deleting %s\n", path); +#endif /* DEBUG_dp */ + PR_Lock(mregLock); + err = NR_RegDeleteKey(mReg, baseKey, (char *)path); + PR_Unlock(mregLock); + } + + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + + +/*------------------------- nsRegistry::RemoveSubtreeRaw ----------------------- +| Deletes the subtree at a given location using NR_RegDeleteKeyRaw | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::RemoveSubtreeRaw( nsRegistryKey baseKey, const char *keyname ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + + // libreg doesn't delete keys if there are subkeys under the key + // Hence we have to recurse through to delete the subtree + + RKEY key; + char subkeyname[MAXREGPATHLEN+1]; + int n = sizeof(subkeyname); + REGENUM state = 0; + + PR_Lock(mregLock); + err = NR_RegGetKeyRaw(mReg, baseKey, (char *)keyname, &key); + PR_Unlock(mregLock); + if (err != REGERR_OK) + { + rv = regerr2nsresult( err ); + return rv; + } + + // Now recurse through and delete all keys under hierarchy + + subkeyname[0] = '\0'; + while (NR_RegEnumSubkeys(mReg, key, &state, subkeyname, n, REGENUM_NORMAL) == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...recursing into %s\n", subkeyname); +#endif /* DEBUG_dp */ + err = RemoveSubtreeRaw(key, subkeyname); + if (err != REGERR_OK) break; + } + + // If success in deleting all subkeys, delete this key too + if (err == REGERR_OK) + { +#ifdef DEBUG_dp + printf("...deleting %s\n", keyname); +#endif /* DEBUG_dp */ + PR_Lock(mregLock); + err = NR_RegDeleteKeyRaw(mReg, baseKey, (char *)keyname); + PR_Unlock(mregLock); + } + + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} +/*-------------------------- nsRegistry::GetSubtree ---------------------------- +| Returns a nsRegistryKey(RKEY) for a given key/path. The key is | +| obtained using NR_RegGetKey. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetSubtree( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place for the result. + if( result ) { + // Get key. + PR_Lock(mregLock); + err = NR_RegGetKey( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*-------------------------- nsRegistry::GetSubtreeRaw-------------------------- +| Returns a nsRegistryKey(RKEY) for a given key/path. The key is | +| obtained using NR_RegGetKeyRaw. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetSubtreeRaw( nsRegistryKey baseKey, const char *path, nsRegistryKey *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place for the result. + if( result ) { + // Get key. + PR_Lock(mregLock); + err = NR_RegGetKeyRaw( mReg,(RKEY)baseKey,(char*)path,(RKEY*)result ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + + +/*----------------------- nsRegistry::EnumerateSubtrees ------------------------ +| Allocate a nsRegSubtreeEnumerator object and return it to the caller. | +| We construct the enumerator using the registry handle from this registry | +| object, the user-specified registry key, and indicate that we don't want | +| to recurse down subtrees. No libreg functions are invoked at this point | +|(that will happen when the enumerator member functions are called). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_FALSE ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*--------------------- nsRegistry::EnumerateAllSubtrees ----------------------- +| Same as EnumerateSubtrees but we pass PR_TRUE to request that the | +| enumerator object descend subtrees when it is used. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateAllSubtrees( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegSubtreeEnumerator( mReg,(RKEY)baseKey, PR_TRUE ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistry::GetValueType --------------------------- +| Gets the type from the registry using the NR_GetEntryInfo libreg API. | +| The result is transferred to the PRUint32 value passed in (with conversion | +| to the appropriate nsIRegistry::DataType value). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetValueType( nsRegistryKey baseKey, const char *path, PRUint32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get registry info into local structure. + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info ); + PR_Unlock(mregLock); + if( err == REGERR_OK ) { + // Copy info to user's result value. + reginfo2DataType( info, *result ); + } else { + rv = regerr2nsresult( err ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------ nsRegistry::GetValueLength -------------------------- +| Gets the registry value info via NR_RegGetEntryInfo. The length is | +| converted to the proper "units" via reginfo2Length. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetValueLength( nsRegistryKey baseKey, const char *path, PRUint32 *result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get registry info into local structure. + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegGetEntryInfo( mReg,(RKEY)baseKey,(char*)path, &info ); + PR_Unlock(mregLock); + if( err == REGERR_OK ) { + // Copy info to user's result value. + reginfo2Length( info, *result ); + } else { + rv = regerr2nsresult( err ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*-------------------------- nsRegistry::DeleteValue --------------------------- +| Remove the registry value with the specified name | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::DeleteValue( nsRegistryKey baseKey, const char *path) +{ + REGERR err = REGERR_OK; + // Delete the value + PR_Lock(mregLock); + err = NR_RegDeleteEntry( mReg,(RKEY)baseKey,(char*)path ); + PR_Unlock(mregLock); + // Convert result. + return regerr2nsresult( err ); +} + +/*------------------------ nsRegistry::EnumerateValues ------------------------- +| Allocates and returns an instance of nsRegValueEnumerator constructed in | +| a similar fashion as the nsRegSubtreeEnumerator is allocated/returned by | +| EnumerateSubtrees. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::EnumerateValues( nsRegistryKey baseKey, nsIEnumerator **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + *result = new nsRegValueEnumerator( mReg,(RKEY)baseKey ); + // Check for success. + if( *result ) { + // Bump refcnt on behalf of caller. + NS_ADDREF(*result); + } else { + // Unable to allocate space for the enumerator object. + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistry::GetCurrentUserName ------------------------ +| Simple wrapper for NR_RegGetUsername. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::GetCurrentUserName( char **result ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Make sure we have a place to put the result. + if( result ) { + // Get the user name. + PR_Lock(mregLock); + err = NR_RegGetUsername( result ); + PR_Unlock(mregLock); + // Convert the result. + rv = regerr2nsresult( err ); + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistry::SetCurrentUserName ------------------------ +| Simple wrapper for NR_RegSetUsername. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::SetCurrentUserName( const char *name ) { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Set the user name. + PR_Lock(mregLock); + err = NR_RegSetUsername( name ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + +/*----------------------------- nsRegistry::Pack ------------------------------- +| Simple wrapper for NR_RegPack. We don't set up any callback. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::Pack() { + nsresult rv = NS_OK; + REGERR err = REGERR_OK; + // Pack the registry. + PR_Lock(mregLock); + err = NR_RegPack( mReg, 0, 0 ); + PR_Unlock(mregLock); + // Convert result. + rv = regerr2nsresult( err ); + return rv; +} + +/*----------------------------- nsRegistry::EscapeKey ------------------------------- +| Escape a binary key so that the registry works OK, since it expects UTF8 +| with no slashes or control characters. This is probably better than raw. +| If no escaping is required, then the method is successful and a null is +| returned, indicating that the caller should use the original string. +------------------------------------------------------------------------------*/ +static const char sEscapeKeyHex[] = "0123456789abcdef0123456789ABCDEF"; +NS_IMETHODIMP nsRegistry::EscapeKey(PRUint8* key, PRUint32 termination, PRUint32* length, PRUint8** escaped) +{ + nsresult rv = NS_OK; + char* value = (char*)key; + char* b = value; + char* e = b + *length; + int escapees = 0; + while (b < e) // Count characters outside legal range or slash + { + int c = *b++; + if (c <= ' ' + || c > '~' + || c == '/' + || c == '%') + { + escapees++; + } + } + if (escapees == 0) // If no escapees, then no results + { + *length = 0; + *escaped = nsnull; + return NS_OK; + } + // New length includes two extra chars for escapees. + *length += escapees * 2; + *escaped = (PRUint8*)nsMemory::Alloc(*length + termination); + if (*escaped == nsnull) + { + *length = 0; + *escaped = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + char* n = (char*)*escaped; + b = value; + while (escapees && b < e) + { + char c = *b++; + if (c < ' ' + || c > '~' + || c == '/' + || c == '%') + { + *(n++) = '%'; + *(n++) = sEscapeKeyHex[ 0xF & (c >> 4) ]; + *(n++) = sEscapeKeyHex[ 0xF & c ]; + escapees--; + } + else + { + *(n++) = c; + } + } + e += termination; + if (b < e) + { + strncpy(n, b, e - b); + } + return rv; +} + +/*----------------------------- nsRegistry::UnescapeKey ------------------------------- +| Unscape a binary key so that the registry works OK, since it expects UTF8 +| with no slashes or control characters. This is probably better than raw. +| If no escaping is required, then the method is successful and a null is +| returned, indicating that the caller should use the original string. +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistry::UnescapeKey(PRUint8* escaped, PRUint32 termination, PRUint32* length, PRUint8** key) +{ + nsresult rv = NS_OK; + char* value = (char*)escaped; + char* b = value; + char* e = b + *length; + int escapees = 0; + while (b < e) // Count characters outside legal range or slash + { + if (*b++ == '%') + { + escapees++; + } + } + if (escapees == 0) // If no escapees, then no results + { + *length = 0; + *key = nsnull; + return NS_OK; + } + // New length includes two extra chars for escapees. + *length -= escapees * 2; + *key = (PRUint8*)nsMemory::Alloc(*length + termination); + if (*key == nsnull) + { + *length = 0; + *key = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + char* n = (char*)*key; + b = value; + while (escapees && b < e) + { + char c = *(b++); + if (c == '%') + { + if (e - b >= 2) + { + const char* c1 = strchr(sEscapeKeyHex, *(b++)); + const char* c2 = strchr(sEscapeKeyHex, *(b++)); + if (c1 != nsnull + && c2 != nsnull) + { + *(n++) = ((c2 - sEscapeKeyHex) & 0xF) + | (((c1 - sEscapeKeyHex) & 0xF) << 4); + } + else + { + escapees = -1; + } + } + else + { + escapees = -1; + } + escapees--; + } + else + { + *(n++) = c; + } + } + if (escapees < 0) + { + nsMemory::Free(*key); + *length = 0; + *key = nsnull; + return NS_ERROR_INVALID_ARG; + } + e += termination; + if (b < e) + { + strncpy(n, b, e - b); + } + return rv; +} + + +/*-------------- nsRegistry::SetBufferSize------------------------------------- +| Sets the size of the file used for the registry's buffer size. | +------------------------------------------------------------------------------*/ +int nsRegistry::SetBufferSize( int bufsize ) +{ + int newSize; + // set the file buffer size + PR_Lock(mregLock); + newSize = NR_RegSetBufferSize( mReg, bufsize ); + PR_Unlock(mregLock); + return newSize; +} + + +/*-------------- nsRegSubtreeEnumerator::nsRegSubtreeEnumerator ---------------- +| The ctor simply stashes all the information that will be needed to enumerate | +| the subkeys. | +------------------------------------------------------------------------------*/ +nsRegSubtreeEnumerator::nsRegSubtreeEnumerator( HREG hReg, RKEY rKey, PRBool all ) + : mReg( hReg ), mKey( rKey ), mEnum( 0 ), mNext( 0 ), + mStyle( all ? REGENUM_DESCEND : REGENUM_CHILDREN ), mDone( PR_FALSE ) { + + mName[0] = '\0'; + +#ifdef EXTRA_THREADSAFE + // Create a registry lock + mregLock = PR_NewLock(); +#endif + return; +} + +nsRegSubtreeEnumerator::~nsRegSubtreeEnumerator() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*----------------------- nsRegSubtreeEnumerator::First ------------------------ +| Set mEnum to 0; this will cause the next NR_RegEnum call to go to | +| the beginning. We then do a Next() call in order to do a "lookahead" to | +| properly detect an empty list (i.e., set the mDone flag). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::First() { + nsresult rv = NS_OK; + // Reset "done" flag. + mDone = PR_FALSE; + // Clear Name + mName[0] = '\0'; + // Go to beginning. + mEnum = mNext = 0; + // Lookahead so mDone flag gets set for empty list. + rv = Next(); + return rv; +} + +/*----------------------- nsRegSubtreeEnumerator::Next ------------------------- +| First, we check if we've already advanced to the end by checking the mDone | +| flag. | +| | +| We advance mEnum to the next enumeration value which is in the mNext | +| lookahead buffer. We must then call advance to lookahead and properly set | +| the isDone flag. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::Next() { + nsresult rv = NS_OK; + // Check for at end. + if ( !mDone ) { + // Advance to next spot. + mEnum = mNext; + // Lookahead so mDone is properly set (and to update mNext). + rv = advance(); + } else { + // Set result accordingly. + rv = regerr2nsresult( REGERR_NOMORE ); + } + return rv; +} + +/*---------------------- nsRegSubtreeEnumerator::advance ----------------------- +| Advance mNext to next subkey using NR_RegEnumSubkeys. We set mDone if | +| there are no more subkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegSubtreeEnumerator::advance() { + REGERR err = REGERR_OK; + PR_Lock(mregLock); + err = NR_RegEnumSubkeys( mReg, mKey, &mNext, mName, sizeof mName, mStyle ); + // See if we ran off end. + if( err == REGERR_NOMORE ) { + // Remember we've run off end. + mDone = PR_TRUE; + } + PR_Unlock(mregLock); + // Convert result. + nsresult rv = regerr2nsresult( err ); + return rv; +} + +/*-------------------- nsRegSubtreeEnumerator::CurrentItem --------------------- +| Allocates and returns a new instance of class nsRegistryNode. The node | +| object will hold the curent mEnum value so it can obtain its name from | +| the registry when asked. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::CurrentItem( nsISupports **result) { + nsresult rv = NS_OK; + // Make sure there is a place to put the result. + if( result ) { + *result = new nsRegistryNode( mReg, mName, (RKEY) mNext ); + if( *result ) { + NS_ADDREF(*result); + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*--------------nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8----------------- +| An ugly name for an ugly function. Hands back a shared pointer to the | +| name (encoded as UTF-8), and the subkey identifier. | +-----------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::CurrentItemInPlaceUTF8( nsRegistryKey *childKey , + const char **name ) +{ + *childKey = mNext; + /* [shared] */ + *name = mName; + return NS_OK; +} + +/*---------------------- nsRegSubtreeEnumerator::IsDone ------------------------ +| Simply return mDone. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegSubtreeEnumerator::IsDone() { + nsresult rv = mDone ? NS_OK : NS_ENUMERATOR_FALSE; + return rv; +} + + +/*---------------- nsRegValueEnumerator::nsRegValueEnumerator ------------------ +| Delegates everything to the base class constructor. | +------------------------------------------------------------------------------*/ +nsRegValueEnumerator::nsRegValueEnumerator( HREG hReg, RKEY rKey ) + : nsRegSubtreeEnumerator( hReg, rKey, PR_FALSE ) { + return; +} + + +/*--------------------- nsRegValueEnumerator::CurrentItem ---------------------- +| As the nsRegSubtreeEnumerator counterpart, but allocates an object of | +| class nsRegistryValue. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP +nsRegValueEnumerator::CurrentItem( nsISupports **result ) { + nsresult rv = NS_OK; + // Make sure there is a place to put the result. + if( result ) { + *result = new nsRegistryValue( mReg, mKey, mEnum ); + if( *result ) { + NS_ADDREF(*result); + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*----------------------- nsRegValueEnumerator::advance ------------------------ +| Advance mNext to next subkey using NR_RegEnumEntries. We set mDone if | +| there are no more entries. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegValueEnumerator::advance() { + REGERR err = REGERR_OK; + char name[MAXREGNAMELEN]; + PRUint32 len = sizeof name; + REGINFO info = { sizeof info, 0, 0 }; + PR_Lock(mregLock); + err = NR_RegEnumEntries( mReg, mKey, &mNext, name, len, &info ); + // See if we ran off end. + if( err == REGERR_NOMORE ) { + // Remember we've run off end. + mDone = PR_TRUE; + } + PR_Unlock(mregLock); + // Convert result. + nsresult rv = regerr2nsresult( err ); + return rv; +} + + +/*---------------------- nsRegistryNode::nsRegistryNode ------------------------ +| Store the arguments in the corresponding data members and initialize | +| the other data members. We defer the libreg calls till we're asked for | +| our name. We use mErr==-1 to indicate we haven't fetched the name yet. | +------------------------------------------------------------------------------*/ +nsRegistryNode::nsRegistryNode( HREG hReg, char *name, RKEY childKey ) + : mReg( hReg ), mChildKey( childKey ) { + + PR_ASSERT(name != nsnull); + strcpy(mName, name); + +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + + return; +} + +nsRegistryNode::~nsRegistryNode() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*-------------------------- nsRegistryNode::GetName --------------------------- +| If we haven't fetched it yet, get the name of the corresponding subkey now, | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetName( PRUnichar **result ) { + if (result == nsnull) return NS_ERROR_NULL_POINTER; + // Make sure there is a place to put the result. + *result = nsTextFormatter::smprintf( widestrFormat, mName ); + if ( !*result ) return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/*-------------------------- nsRegistryNode::GetNameUTF8 ----------------------- +| If we haven't fetched it yet, get the name of the corresponding subkey now, | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetNameUTF8( char **result ) { + if (result == nsnull) return NS_ERROR_NULL_POINTER; + // Make sure there is a place to put the result. + *result = nsCRT::strdup( mName ); + if ( !*result ) return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/*-------------------------- nsRegistryNode::GetKey ---------------------------- +| Get the subkey corresponding to this node | +| using NR_RegEnumSubkeys. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryNode::GetKey( nsRegistryKey *r_key ) { + nsresult rv = NS_OK; + if (r_key == nsnull) return NS_ERROR_NULL_POINTER; + *r_key = mChildKey; + return rv; +} + + + +/*--------------------- nsRegistryValue::nsRegistryValue ----------------------- +| Implemented the same way as the nsRegistryNode ctor. | +------------------------------------------------------------------------------*/ +nsRegistryValue::nsRegistryValue( HREG hReg, RKEY key, REGENUM slot ) + : mReg( hReg ), mKey( key ), mEnum( slot ), mErr( -1 ) { +#ifdef EXTRA_THREADSAFE + mregLock = PR_NewLock(); +#endif + mInfo.size = sizeof(REGINFO); +} + +nsRegistryValue::~nsRegistryValue() +{ +#ifdef EXTRA_THREADSAFE + if (mregLock) { + PR_DestroyLock(mregLock); + } +#endif +} + +/*------------------------- nsRegistryValue::GetName --------------------------- +| See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetName( PRUnichar **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + // Ensure we've got the info we need. + rv = getInfo(); + if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) { + // worked, return actual result. + *result = nsTextFormatter::smprintf( widestrFormat, mName ); + if ( *result ) { + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistryValue::GetNameUTF8 ----------------------- +| See nsRegistryNode::GetName; we use NR_RegEnumEntries in this case. | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetNameUTF8( char **result ) { + nsresult rv = NS_OK; + // Make sure we have a place to put the result. + if( result ) { + // Ensure we've got the info we need. + rv = getInfo(); + if( rv == NS_OK || rv == NS_ERROR_REG_NO_MORE ) { + // worked, return actual result. + *result = nsCRT::strdup( mName ); + if ( *result ) { + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*----------------------- nsRegistryValue::GetType ------------------------ +| We test if we've got the info already. If not, we git it by calling | +| getInfo. We calculate the result by converting the REGINFO type field to | +| a nsIRegistry::DataType value (using reginfo2DataType). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetType( PRUint32 *result ) { + nsresult rv = NS_OK; + // Make sure we have room for th result. + if( result ) { + // Make sure we've got the info we need. + rv = getInfo(); + // Check if it worked. + if( rv == NS_OK ) { + // Convert result from REGINFO to nsIRegistry::ValueInfo. + reginfo2DataType( mInfo, *result ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*---------------------- nsRegistryValue::GetLength ----------------------- +| We test if we've got the info already. If not, we git it by calling | +| getInfo. We calculate the result by converting the REGINFO type field to | +| a nsIRegistry::DataType value (using reginfo2Length). | +------------------------------------------------------------------------------*/ +NS_IMETHODIMP nsRegistryValue::GetLength( PRUint32 *result ) { + nsresult rv = NS_OK; + // Make sure we have room for th result. + if( result ) { + // Make sure we've got the info we need. + rv = getInfo(); + // Check if it worked. + if( rv == NS_OK ) { + // Convert result from REGINFO to length. + reginfo2Length( mInfo, *result ); + } + } else { + rv = NS_ERROR_NULL_POINTER; + } + return rv; +} + +/*------------------------- nsRegistryValue::getInfo --------------------------- +| Call NR_RegEnumEntries to set the mInfo/mName data members. | +------------------------------------------------------------------------------*/ +nsresult nsRegistryValue::getInfo() { + nsresult rv = NS_OK; + // Test whether we haven't tried to get it yet. + if( mErr == -1 ) { + REGENUM temp = mEnum; + // Get name and info. + PR_Lock(mregLock); + mErr = NR_RegEnumEntries( mReg, mKey, &temp, mName, sizeof mName, &mInfo ); + // Convert result. + rv = regerr2nsresult( mErr ); + PR_Unlock(mregLock); + } + return rv; +} + + +nsRegistryFactory::nsRegistryFactory() { +} + +NS_IMPL_ISUPPORTS1(nsRegistryFactory, nsIFactory) + +NS_IMETHODIMP +nsRegistryFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) { + nsresult rv = NS_OK; + nsRegistry* newRegistry; + + if(aResult == nsnull) { + return NS_ERROR_NULL_POINTER; + } else { + *aResult = nsnull; + } + + if(0 != aOuter) { + return NS_ERROR_NO_AGGREGATION; + } + + NS_NEWXPCOM(newRegistry, nsRegistry); + + if(newRegistry == nsnull) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(newRegistry); + rv = newRegistry->QueryInterface(aIID, aResult); + NS_RELEASE(newRegistry); + + return rv; +} + +nsresult +nsRegistryFactory::LockFactory(PRBool aLock) +{ + // Not implemented in simplest case. + return NS_OK; +} + +// This is a temporary hack; needs work to support dynamic binding +// via nsComponentManager and support for multiple factories per DLL. +extern "C" NS_EXPORT nsresult +NS_RegistryGetFactory(nsIFactory** aFactory ) { + nsresult rv = NS_OK; + + if( aFactory == 0 ) { + return NS_ERROR_NULL_POINTER; + } else { + *aFactory = 0; + } + + nsIFactory* inst = new nsRegistryFactory(); + if(0 == inst) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + NS_ADDREF(inst); + *aFactory = inst; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h new file mode 100644 index 00000000..8b59db36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsRegistry.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Edward Kandrot + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsRegistry_h__ +#define nsRegistry_h__ + +#include "nsIRegistry.h" +#include "NSReg.h" +#include "nsIFile.h" +#include "nsCOMPtr.h" + +struct nsRegistry : public nsIRegistry, nsIRegistryGetter { + // This class implements the nsISupports interface functions. + NS_DECL_ISUPPORTS + + // This class implements the nsIRegistry interface functions. + NS_DECL_NSIREGISTRY + + // Fast registry getters + NS_DECL_NSIREGISTRYGETTER + + int SetBufferSize( int bufsize ); // changes the file buffer size for this registry + + // ctor/dtor + nsRegistry(); + +private: + ~nsRegistry(); + +protected: + HREG mReg; // Registry handle. +#ifdef EXTRA_THREADSAFE + PRLock *mregLock; // libreg isn't threadsafe. Use locks to synchronize. +#endif + nsCOMPtr mCurRegFile; // these are to prevent open from opening the registry again + nsWellKnownRegistry mCurRegID; + + NS_IMETHOD Close(); +}; // nsRegistry + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp new file mode 100644 index 00000000..9a71a916 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/nsXPCOMObsolete.cpp @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsIGenericFactory.h" + +#include "nsFileSpecImpl.h" +#include "nsRegistry.h" + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsRegistry) + +static const nsModuleComponentInfo components[] = +{ + COMPONENT(FILESPEC, nsFileSpecImpl::Create), + COMPONENT(DIRECTORYITERATOR, nsDirectoryIteratorImpl::Create), + COMPONENT(REGISTRY, nsRegistryConstructor), +}; + +NS_IMPL_NSGETMODULE(xpcomObsoleteModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp b/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp new file mode 100644 index 00000000..d1b2f85e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/regExport.cpp @@ -0,0 +1,357 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include "nsCOMPtr.h" +#include "nsIRegistry.h" +#include "nsIEnumerator.h" +#include "nsILocalFile.h" +#include "nsDependentString.h" +#include "prmem.h" +#include "plstr.h" +#include "nsMemory.h" + +static void display( nsIRegistry *reg, nsRegistryKey root, const char *name ); +static void displayValues( nsIRegistry *reg, nsRegistryKey root ); +static void printString( const char *value, int indent ); + +int main( int argc, char *argv[] ) { + + +#ifdef __MWERKS__ + // Hack in some arguments. A NULL registry name is supposed to tell libreg + // to use the default registry (which does seem to work). + argc = 1; + const char* myArgs[] = + { + "regExport" + }; + argv = const_cast(myArgs); +#endif + + nsresult rv; + + // Initialize XPCOM + nsIServiceManager *servMgr = NULL; + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + if (NS_FAILED(rv)) + { + // Cannot initialize XPCOM + printf("Cannot initialize XPCOM. Exit. [rv=0x%08X]\n", (int)rv); + exit(-1); + } + { + // Get the component manager + static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); + nsCOMPtr compMgr = do_GetService(kComponentManagerCID, &rv); + if (NS_FAILED(rv)) + { + // Cant get component manager + printf("Cannot get component manager from service manager.. Exit. [rv=0x%08X]\n", (int)rv); + exit(-1); + } + + nsIRegistry *reg; + + if (argc>1) { + // Create the registry + rv = compMgr->CreateInstanceByContractID(NS_REGISTRY_CONTRACTID, NULL, + NS_GET_IID(nsIRegistry), + (void **) ®); + // Check result. + if ( NS_FAILED(rv) ) + { + printf( "Error opening registry file %s, rv=0x%08X\n", argv[1] , (int)rv ); + return rv; + } + // Open it against the input file name. + nsCOMPtr regFile; + rv = NS_NewNativeLocalFile( nsDependentCString(argv[1]), PR_FALSE, getter_AddRefs(regFile) ); + if ( NS_FAILED(rv) ) { + printf( "Error instantiating local file for %s, rv=0x%08X\n", argv[1], (int)rv ); + return rv; + } + + rv = reg->Open( regFile ); + + if ( rv == NS_OK ) + { + printf( "Registry %s opened OK.\n", argv[1] ); + + // Recurse over all 3 branches. + display( reg, nsIRegistry::Common, "nsRegistry::Common" ); + display( reg, nsIRegistry::Users, "nsRegistry::Users" ); + } + NS_RELEASE(reg); + } + else + { + // Called with no arguments. Print both the default registry and + // the components registry. We already printed the default regsitry. + // So just do the component registry. + rv = compMgr->CreateInstanceByContractID(NS_REGISTRY_CONTRACTID, NULL, + NS_GET_IID(nsIRegistry), + (void **) ®); + + // Check result. + if ( NS_FAILED(rv) ) + { + printf( "Error opening creating registry instance, rv=0x%08X\n", (int)rv ); + return rv; + } + rv = reg->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry); + if ( rv == NS_ERROR_REG_BADTYPE ) { + printf( "\n\n\nThere is no \n" ); + } + else if ( rv == NS_OK ) { + + printf( "\n\n\nRegistry %s opened OK.\n", "\n" ); + + // Recurse over all 3 branches. + display( reg, nsIRegistry::Common, "nsRegistry::Common" ); + display( reg, nsIRegistry::Users, "nsRegistry::Users" ); + } + NS_RELEASE(reg); + } + } + NS_ShutdownXPCOM( servMgr ); + + return rv; +} + +void display( nsIRegistry *reg, nsRegistryKey root, const char *rootName ) { + // Print out key name. + printf( "%s\n", rootName ); + + // Make sure it isn't a "root" key. + if ( root != nsIRegistry::Common + && + root != nsIRegistry::Users + && + root != nsIRegistry::CurrentUser ) { + // Print values stored under this key. + displayValues( reg, root ); + } + + // Enumerate all subkeys (immediately) under the given node. + nsIEnumerator *keys; + nsresult rv = reg->EnumerateSubtrees( root, &keys ); + + // Check result. + if ( rv == NS_OK ) { + // Set enumerator to beginning. + rv = keys->First(); + // Enumerate subkeys till done. + while( NS_SUCCEEDED( rv ) && (NS_OK != keys->IsDone()) ) { + nsISupports *base; + rv = keys->CurrentItem( &base ); + // Test result. + if ( rv == NS_OK ) { + // Get specific interface. + nsIRegistryNode *node; + nsIID nodeIID = NS_IREGISTRYNODE_IID; + rv = base->QueryInterface( nodeIID, (void**)&node ); + // Test that result. + if ( rv == NS_OK ) { + // Get node name. + char *name; + rv = node->GetNameUTF8( &name ); + // Test result. + if ( rv == NS_OK ) { + // Build complete name. + char *fullName = new char[ PL_strlen(rootName) + PL_strlen(name) + 5 ]; + PL_strcpy( fullName, rootName ); + PL_strcat( fullName, " - " ); + PL_strcat( fullName, name ); + // Display contents under this subkey. + nsRegistryKey key; + rv = reg->GetSubtreeRaw( root, name, &key ); + if ( rv == NS_OK ) { + display( reg, key, fullName ); + printf( "\n" ); + } else { + printf( "Error getting key, rv=0x%08X\n", (int)rv ); + } + delete [] fullName; + } else { + printf( "Error getting subtree name, rv=0x%08X\n", (int)rv ); + } + // Release node. + node->Release(); + } else { + printf( "Error converting base node ptr to nsIRegistryNode, rv=0x%08X\n", (int)rv ); + } + // Release item. + base->Release(); + + // Advance to next key. + rv = keys->Next(); + // Check result. + if ( NS_SUCCEEDED( rv ) ) { + } else { + printf( "Error advancing enumerator, rv=0x%08X\n", (int)rv ); + } + } else { + printf( "Error getting current item, rv=0x%08X\n", (int)rv ); + } + } + // Release key enumerator. + keys->Release(); + } else { + printf( "Error creating enumerator for %s, root=0x%08X, rv=0x%08X\n", + rootName, (int)root, (int)rv ); + } + return; +} + +static void displayValues( nsIRegistry *reg, nsRegistryKey root ) { + // Emumerate values at this registry location. + nsIEnumerator *values; + nsresult rv = reg->EnumerateValues( root, &values ); + + // Check result. + if ( rv == NS_OK ) { + // Go to beginning. + rv = values->First(); + + // Enumerate values till done. + while( rv == NS_OK && (NS_OK != values->IsDone()) ) { + nsISupports *base; + rv = values->CurrentItem( &base ); + // Test result. + if ( rv == NS_OK ) { + // Get specific interface. + nsIRegistryValue *value; + nsIID valueIID = NS_IREGISTRYVALUE_IID; + rv = base->QueryInterface( valueIID, (void**)&value ); + // Test that result. + if ( rv == NS_OK ) { + // Get node name. + char *name; + rv = value->GetNameUTF8( &name ); + // Test result. + if ( rv == NS_OK ) { + // Print name: + printf( "\t\t%s", name ); + // Get info about this value. + PRUint32 type; + rv = reg->GetValueType( root, name, &type ); + if ( rv == NS_OK ) { + // Print value contents. + switch ( type ) { + case nsIRegistry::String: { + char *strValue; + rv = reg->GetStringUTF8( root, name, &strValue ); + if ( rv == NS_OK ) { + printString( strValue, strlen(name) ); + nsMemory::Free( strValue ); + } else { + printf( "\t Error getting string value, rv=0x%08X", (int)rv ); + } + } + break; + + case nsIRegistry::Int32: + { + PRInt32 val = 0; + rv = reg->GetInt( root, name, &val ); + if (NS_SUCCEEDED(rv)) { + printf( "\t= Int32 [%d, 0x%x]", val, val); + } + else { + printf( "\t Error getting int32 value, rv=%08X", (int)rv); + } + } + break; + + case nsIRegistry::Bytes: + printf( "\t= Bytes" ); + break; + + case nsIRegistry::File: + printf( "\t= File (?)" ); + break; + + default: + printf( "\t= ? (unknown type=0x%02X)", (int)type ); + break; + } + } else { + printf( "\t= ? (error getting value, rv=0x%08X)", (int)rv ); + } + printf("\n"); + nsMemory::Free( name ); + } else { + printf( "Error getting value name, rv=0x%08X\n", (int)rv ); + } + // Release node. + value->Release(); + } else { + printf( "Error converting base node ptr to nsIRegistryNode, rv=0x%08X\n", (int)rv ); + } + // Release item. + base->Release(); + + // Advance to next key. + rv = values->Next(); + // Check result. + if ( NS_SUCCEEDED( rv ) ) { + } else { + printf( "Error advancing enumerator, rv=0x%08X\n", (int)rv ); + break; + } + } else { + printf( "Error getting current item, rv=0x%08X\n", (int)rv ); + break; + } + } + + values->Release(); + } else { + printf( "\t\tError enumerating values, rv=0x%08X\n", (int)rv ); + } + return; +} + +static void printString( const char *value, int /*indent*/ ) { + // For now, just dump contents. + printf( "\t = %s", value ); + return; +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg b/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg new file mode 100644 index 00000000..88cbf236 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/component/xpcomobsoletec.pkg @@ -0,0 +1,6 @@ +[gecko xpi-bootstrap] +#if SHARED_LIBRARY +dist/bin/components/@SHARED_LIBRARY@ +#else +!staticcomp @LIBRARY@ @MODULE_NAME@ +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp b/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp new file mode 100644 index 00000000..d904e071 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/dlldeps.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Force references to all of the symbols that we want exported from +// the dll that are located in the .lib files we link with + +#include "nsFileSpec.h" +#include "NSReg.h" + +void XXXNeverCalled() +{ + nsFileURL(NULL); + nsFileSpec s; + + NR_RegSetBufferSize(NULL, 0); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp new file mode 100644 index 00000000..9be29eb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.cpp @@ -0,0 +1,1367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpec.h" + +#include "nsDebug.h" +#include "nsEscape.h" +#include "nsMemory.h" + +#include "prtypes.h" +#include "plstr.h" +#include "plbase64.h" +#include "prmem.h" + +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsILocalFile.h" + +#include +#include + +#if defined(XP_WIN) +#include +#endif + +#ifdef XP_OS2 +extern unsigned char* _mbsrchr( const unsigned char*, int); +#endif + +// return pointer to last instance of the given separator +static inline char *GetLastSeparator(const char *str, char sep) +{ +#if defined(XP_WIN) || defined(XP_OS2) + return (char*) _mbsrchr((const unsigned char *) str, sep); +#else + return (char*) strrchr(str, sep); +#endif +} + +#if defined(XP_MACOSX) +#include +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) +#include +#include +#endif + +//======================================================================================== +// class nsSimpleCharString +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString() +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const char* inString) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + if (inString) + CopyFrom(inString, strlen(inString)); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const nsString& inString) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + *this = inString; +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const nsSimpleCharString& inOther) +//---------------------------------------------------------------------------------------- +{ + mData = inOther.mData; + AddRefData(); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::nsSimpleCharString(const char* inData, PRUint32 inLength) +//---------------------------------------------------------------------------------------- +: mData(nsnull) +{ + CopyFrom(inData, inLength); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +nsSimpleCharString::~nsSimpleCharString() +//---------------------------------------------------------------------------------------- +{ + ReleaseData(); +} // nsSimpleCharString::nsSimpleCharString + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + if (inString) + CopyFrom(inString, strlen(inString)); + else + SetToEmpty(); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const nsString& inString) +//---------------------------------------------------------------------------------------- +{ + PRUint32 len = inString.Length(); + ReallocData(len); + if (!mData) + return; + inString.ToCString(mData->mString, len + 1); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator = (const nsSimpleCharString& inOther) +//---------------------------------------------------------------------------------------- +{ + if (mData == inOther.mData) + return; + ReleaseData(); + mData = inOther.mData; + AddRefData(); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::operator += (const char* inOther) +//---------------------------------------------------------------------------------------- +{ + if (!inOther) + return; + int newLength = Length() + strlen(inOther); + ReallocData(newLength); + strcat(mData->mString, inOther); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +nsSimpleCharString nsSimpleCharString::operator + (const char* inOther) const +//---------------------------------------------------------------------------------------- +{ + nsSimpleCharString result(*this); + result += inOther; + return result; +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::Catenate(const char* inString1, const char* inString2) +//---------------------------------------------------------------------------------------- +{ + if (!inString2) + { + *this += inString1; + return; + } + int newLength = Length() + strlen(inString1) + strlen(inString2); + ReallocData(newLength); + strcat(mData->mString, inString1); + strcat(mData->mString, inString2); +} // nsSimpleCharString::operator = + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::CopyFrom(const char* inData, PRUint32 inLength) +//---------------------------------------------------------------------------------------- +{ + if (!inData) + return; + ReallocData(inLength); + if (!mData) + return; + if (inLength != 0) { + memcpy(mData->mString, inData, inLength); + } + mData->mString[inLength] = '\0'; +} // nsSimpleCharString::CopyFrom + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::SetToEmpty() +//---------------------------------------------------------------------------------------- +{ + ReleaseData(); +} // nsSimpleCharString::SetToEmpty + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::Unescape() +//---------------------------------------------------------------------------------------- +{ + if (!mData) + return; + ReallocData(mData->mLength); + if (!mData) + return; + nsUnescape(mData->mString); + mData->mLength = strlen(mData->mString); +} // nsSimpleCharString::Unescape + + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::AddRefData() +//---------------------------------------------------------------------------------------- +{ + if (mData) + ++mData->mRefCount; +} // nsSimpleCharString::AddRefData + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::ReleaseData() +//---------------------------------------------------------------------------------------- +{ + if (!mData) + return; + NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!"); + if (--mData->mRefCount == 0) + PR_Free(mData); + mData = nsnull; +} // nsSimpleCharString::ReleaseData + +//---------------------------------------------------------------------------------------- +inline PRUint32 CalculateAllocLength(PRUint32 logicalLength) +// Round up to the next multiple of 256. +//---------------------------------------------------------------------------------------- +{ + return ((1 + (logicalLength >> 8)) << 8); +} + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::ReallocData(PRUint32 inLength) +// Reallocate mData to a new length. Since this presumably precedes a change to the string, +// we want to detach ourselves if the data is shared by another string, even if the length +// requested would not otherwise require a reallocation. +//---------------------------------------------------------------------------------------- +{ + PRUint32 newAllocLength = CalculateAllocLength(inLength); + PRUint32 oldAllocLength = CalculateAllocLength(Length()); + if (mData) + { + NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!"); + if (mData->mRefCount == 1) + { + // We are the sole owner, so just change its length, if necessary. + if (newAllocLength > oldAllocLength) + mData = (Data*)PR_Realloc(mData, newAllocLength + sizeof(Data)); + mData->mLength = inLength; + mData->mString[inLength] = '\0'; // we may be truncating + return; + } + } + PRUint32 copyLength = Length(); + if (inLength < copyLength) + copyLength = inLength; + Data* newData = (Data*)PR_Malloc(newAllocLength + sizeof(Data)); + // If data was already allocated when we get to here, then we are cloning the data + // from a shared pointer. + if (mData) + { + memcpy(newData, mData, sizeof(Data) + copyLength); + mData->mRefCount--; // Say goodbye + } + else + newData->mString[0] = '\0'; + + mData = newData; + mData->mRefCount = 1; + mData->mLength = inLength; +} // nsSimpleCharString::ReleaseData + + +//======================================================================================== +NS_NAMESPACE nsFileSpecHelpers +//======================================================================================== +{ + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; +#if !defined(XP_MAC) + NS_NAMESPACE_PROTOTYPE void Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs); + NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode); +#endif +#if defined(XP_WIN) || defined(XP_OS2) + NS_NAMESPACE_PROTOTYPE void NativeToUnix(nsSimpleCharString& ioPath); + NS_NAMESPACE_PROTOTYPE void UnixToNative(nsSimpleCharString& ioPath); +#endif +} NS_NAMESPACE_END + +//---------------------------------------------------------------------------------------- +nsresult ns_file_convert_result(PRInt32 nativeErr) +//---------------------------------------------------------------------------------------- +{ + return nativeErr ? + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF)) + : NS_OK; +} + +//---------------------------------------------------------------------------------------- +void nsSimpleCharString::LeafReplace(char inSeparator, const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + // Find the existing leaf name + if (IsEmpty()) + return; + if (!inLeafName) + { + SetToEmpty(); + return; + } + char* chars = mData->mString; + char* lastSeparator = GetLastSeparator(chars, inSeparator); + int oldLength = Length(); + PRBool trailingSeparator = (lastSeparator + 1 == chars + oldLength); + if (trailingSeparator) + { + char savedCh = *lastSeparator; + char *savedLastSeparator = lastSeparator; + *lastSeparator = '\0'; + lastSeparator = GetLastSeparator(chars, inSeparator); + *savedLastSeparator = savedCh; + } + if (lastSeparator) + lastSeparator++; // point at the trailing string + else + lastSeparator = chars; // the full monty + + PRUint32 savedLastSeparatorOffset = (lastSeparator - chars); + int newLength = + (lastSeparator - chars) + strlen(inLeafName) + (trailingSeparator != 0); + ReallocData(newLength); + + chars = mData->mString; // it might have moved. + chars[savedLastSeparatorOffset] = '\0'; // strip the current leaf name + + strcat(chars, inLeafName); + if (trailingSeparator) + { + // If the original ended in a slash, then the new one should, too. + char sepStr[2] = "/"; + *sepStr = inSeparator; + strcat(chars, sepStr); + } +} // nsSimpleCharString::LeafReplace + +//---------------------------------------------------------------------------------------- +char* nsSimpleCharString::GetLeaf(char inSeparator) const +// Returns a pointer to an allocated string representing the leaf. +//---------------------------------------------------------------------------------------- +{ + if (IsEmpty()) + return nsnull; + + char* chars = mData->mString; + const char* lastSeparator = GetLastSeparator(chars, inSeparator); + // If there was no separator, then return a copy of our path. + if (!lastSeparator) + return nsCRT::strdup(*this); + + // So there's at least one separator. What's just after it? + // If the separator was not the last character, return the trailing string. + const char* leafPointer = lastSeparator + 1; + if (*leafPointer) + return nsCRT::strdup(leafPointer); + + // So now, separator was the last character. Poke in a null instead. + *(char*)lastSeparator = '\0'; // Should use const_cast, but Unix has old compiler. + leafPointer = GetLastSeparator(chars, inSeparator); + char* result = leafPointer ? nsCRT::strdup(++leafPointer) : nsCRT::strdup(chars); + // Restore the poked null before returning. + *(char*)lastSeparator = inSeparator; +#if defined(XP_WIN) || defined(XP_OS2) + // If it's a drive letter use the colon notation. + if (!leafPointer && result[1] == '|' && result[2] == 0) + result[1] = ':'; +#endif + return result; +} // nsSimpleCharString::GetLeaf + + +#if 0 +#pragma mark - +#endif + +#if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)) + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode) +// Make the path a valid one by creating all the intermediate directories. Does NOT +// make the leaf into a directory. This should be a unix path. +//---------------------------------------------------------------------------------------- +{ + if (!inPath) + return; + + char* pathCopy = nsCRT::strdup( inPath ); + if (!pathCopy) + return; + + const char kSeparator = '/'; // I repeat: this should be a unix-style path. + const int kSkipFirst = 1; + +#if defined(XP_WIN) || defined(XP_OS2) + // Either this is a relative path, or we ensure that it has + // a drive letter specifier. + NS_ASSERTION( pathCopy[0] != '/' || (pathCopy[1] && (pathCopy[2] == '|' || pathCopy[2] == '/')), + "Not a UNC path and no drive letter!" ); +#endif + char* currentStart = pathCopy; + char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator); + if (currentEnd) + { + nsFileSpec spec; + *currentEnd = '\0'; + +#if defined(XP_WIN) || defined(XP_OS2) + /* + if we have a drive letter path, we must make sure that the inital path has a '/' on it, or + Canonify will turn "/c|" into a path relative to the running executable. + */ + if (pathCopy[0] == '/' && pathCopy[1] && pathCopy[2] == '|') + { + char* startDir = (char*)PR_Malloc(strlen(pathCopy) + 2); + strcpy(startDir, pathCopy); + strcat(startDir, "/"); + + spec = nsFilePath(startDir, PR_FALSE); + + PR_Free(startDir); + } + else + { + // move after server name and share name in UNC path + if (pathCopy[0] == '/' && + currentEnd == currentStart+kSkipFirst) + { + *currentEnd = '/'; + currentStart = strchr(pathCopy+2, kSeparator); + currentStart = strchr(currentStart+1, kSeparator); + currentEnd = strchr(currentStart+1, kSeparator); + if (currentEnd) + *currentEnd = '\0'; + } + spec = nsFilePath(pathCopy, PR_FALSE); + } +#else + spec = nsFilePath(pathCopy, PR_FALSE); +#endif + do + { + // If the node doesn't exist, and it is not the initial node in a full path, + // then make a directory (We cannot make the initial (volume) node). + if (!spec.Exists() && *currentStart != kSeparator) + spec.CreateDirectory(mode); + + currentStart = ++currentEnd; + currentEnd = strchr(currentStart, kSeparator); + if (!currentEnd) + break; + + *currentEnd = '\0'; + + spec += currentStart; // "lengthen" the path, adding the next node. + } while (currentEnd); + } + nsCRT::free(pathCopy); +} // nsFileSpecHelpers::MakeAllDirectories + +#endif // XP_UNIX || XP_WIN || XP_OS2 || XP_BEOS + +#if 0 +#pragma mark - +#endif + +#if defined(XP_WIN) +#include "nsFileSpecWin.cpp" // Windows-specific implementations +#elif defined(XP_MAC) +//#include "nsFileSpecMac.cpp" // Macintosh-specific implementations +// we include the .cpp file in the project now. +#elif defined(XP_BEOS) +#include "nsFileSpecBeOS.cpp" // BeOS-specific implementations +#elif defined(XP_UNIX) || defined(XP_MACOSX) +#include "nsFileSpecUnix.cpp" // Unix-specific implementations +#elif defined(XP_OS2) +#include "nsFileSpecOS2.cpp" // OS/2-specific implementations +#endif + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + if (!inString) + return; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + // Make canonical and absolute. Since it's a parameter to this constructor, + // inString is escaped. We want to make an nsFilePath, which requires + // an unescaped string. + nsSimpleCharString unescapedPath(inString + kFileURLPrefixLength); + unescapedPath.Unescape(); + nsFilePath path(unescapedPath, inCreateDirs); + *this = path; +} // nsFileURL::nsFileURL +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + NS_LossyConvertUCS2toASCII cstring(inString); + if (!inString.Length()) + return; + NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(), + "Not a URL!"); + // Make canonical and absolute. Since it's a parameter to this constructor, + // inString is escaped. We want to make an nsFilePath, which requires + // an unescaped string. + nsSimpleCharString unescapedPath(cstring.get() + kFileURLPrefixLength); + unescapedPath.Unescape(); + nsFilePath path(unescapedPath, inCreateDirs); + *this = path; +} // nsFileURL::nsFileURL +#endif + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mURL(inOther.mURL) +#if defined(XP_MAC) +, mFileSpec(inOther.GetFileSpec()) +#endif +{ +} // nsFileURL::nsFileURL + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL +#endif + +//---------------------------------------------------------------------------------------- +nsFileURL::~nsFileURL() +//---------------------------------------------------------------------------------------- +{ +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + // XXX is this called by nsFileSpecImpl.cpp::SetURLString? + // if so, there's a bug... + + mURL = inString; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); +} // nsFileURL::operator = +#endif + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator +=(const char* inRelativeUnixPath) +//---------------------------------------------------------------------------------------- +{ + char* escapedPath = nsEscape(inRelativeUnixPath, url_Path); + mURL += escapedPath; + nsCRT::free(escapedPath); +#if defined(XP_MAC) + mFileSpec += inRelativeUnixPath; +#endif +} // nsFileURL::operator += + +//---------------------------------------------------------------------------------------- +nsFileURL nsFileURL::operator +(const char* inRelativeUnixPath) const +//---------------------------------------------------------------------------------------- +{ + nsFileURL result(*this); + result += inRelativeUnixPath; + return result; +} // nsFileURL::operator + + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = inOther.mURL; +#if defined(XP_MAC) + mFileSpec = inOther.GetFileSpec(); +#endif +} // nsFileURL::operator = + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix; + char* original = (char*)(const char*)inOther; // we shall modify, but restore. + if (!original || !*original) return; +#if defined(XP_WIN) || defined(XP_OS2) + // because we don't want to escape the '|' character, change it to a letter. + // Note that a UNC path will not have a '|' character. + char oldchar = original[2]; + original[2] = 'x'; + char* escapedPath = nsEscape(original, url_Path); + original[2] = escapedPath[2] = oldchar; // restore it +#else + char* escapedPath = nsEscape(original, url_Path); +#endif + if (escapedPath) + mURL += escapedPath; + nsCRT::free(escapedPath); +} // nsFileURL::operator = +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inOther); + if (mURL[mURL.Length() - 1] != '/' && inOther.IsDirectory()) + mURL += "/"; +} // nsFileURL::operator = +#endif + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// nsFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- + : mPath(inPath.mPath) +#if defined(XP_MAC) + , mFileSpec(inPath.mFileSpec) +#endif +{ +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +{ + if (mPath.IsEmpty()) + return; + + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +#if defined(XP_WIN) || defined(XP_OS2) + // Assert native path is of one of these forms: + // - regular: X:\some\path + // - UNC: \\some_machine\some\path + NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'), + "unexpected canonical path" ); + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +{ + if (mPath.IsEmpty()) + return; + + NS_ASSERTION(strstr((const char*)mPath, kFileURLPrefix) != (const char*)mPath, "URL passed as path"); +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +#if defined(XP_WIN) || defined(XP_OS2) + NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'), + "unexpected canonical path" ); + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inOther.mURL + kFileURLPrefixLength; + mPath.Unescape(); +} +#endif + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +: mPath(inOther.mPath) +{ +} +#endif // XP_UNIX + +//---------------------------------------------------------------------------------------- +nsFilePath::~nsFilePath() +//---------------------------------------------------------------------------------------- +{ +} + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + // XXX bug here, again if. + + mPath = inOther.mPath; +} +#endif // XP_UNIX + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + mPath = inString; + if (mPath.IsEmpty()) + return; +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::UnixToNative(mPath); +#endif + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */); +#if defined(XP_WIN) || defined(XP_OS2) + nsFileSpecHelpers::NativeToUnix(mPath); +#endif +} +#endif // XP_MAC + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)nsFilePath(inOther); +} +#endif + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = inOther.mPath; +#if defined(XP_MAC) + mFileSpec = inOther.GetFileSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator +=(const char* inRelativeUnixPath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path"); + + char* escapedPath = nsEscape(inRelativeUnixPath, url_Path); + mPath += escapedPath; + nsCRT::free(escapedPath); +#if defined(XP_MAC) + mFileSpec += inRelativeUnixPath; +#endif +} // nsFilePath::operator += + +//---------------------------------------------------------------------------------------- +nsFilePath nsFilePath::operator +(const char* inRelativeUnixPath) const +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path"); + + nsFilePath resultPath(*this); + resultPath += inRelativeUnixPath; + return resultPath; +} // nsFilePath::operator + + + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// nsFileSpec implementation +//======================================================================================== + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec() +//---------------------------------------------------------------------------------------- +: mError(NS_OK) // XXX shouldn't this be NS_ERROR_NOT_INITIALIZED? +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Clear() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mError = NS_ERROR_NOT_INITIALIZED; +} + +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpec::~nsFileSpec() +//---------------------------------------------------------------------------------------- +{ + // mPath cleans itself up +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsPersistentFileDescriptor& inDescriptor) +//---------------------------------------------------------------------------------------- +{ + *this = inDescriptor; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileURL& inURL) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inURL); // convert to unix path first +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique(const char* inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName && *inSuggestedLeafName) + SetLeafName(inSuggestedLeafName); + + MakeUnique(); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + if (!Exists()) + return; + + char* leafName = GetLeafName(); + if (!leafName) + return; + + char* lastDot = strrchr(leafName, '.'); + char* suffix = ""; + if (lastDot) + { + suffix = nsCRT::strdup(lastDot); // include '.' + *lastDot = '\0'; // strip suffix and dot. + } + const int kMaxRootLength + = nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1; + if ((int)strlen(leafName) > (int)kMaxRootLength) + leafName[kMaxRootLength] = '\0'; + for (short indx = 1; indx < 1000 && Exists(); indx++) + { + // start with "Picture-1.jpg" after "Picture.jpg" exists + char newName[nsFileSpecHelpers::kMaxFilenameLength + 1]; + sprintf(newName, "%s-%d%s", leafName, indx, suffix); + SetLeafName(newName); + } + if (*suffix) + nsCRT::free(suffix); + nsCRT::free(leafName); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileURL& inURL) +//---------------------------------------------------------------------------------------- +{ + *this = nsFilePath(inURL); // convert to unix path first +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsPersistentFileDescriptor& inDescriptor) +//---------------------------------------------------------------------------------------- +{ + + nsCAutoString data; + inDescriptor.GetData(data); + +#if defined (XP_MAC) || defined(XP_MACOSX) + // Decode descriptor into a Handle (which is actually an AliasHandle) + char* decodedData = PL_Base64Decode(data.get(), data.Length(), nsnull); + Handle aliasH = nsnull; + mError = NS_FILE_RESULT(::PtrToHand(decodedData, &aliasH, (data.Length() * 3) / 4)); + PR_Free(decodedData); + if (NS_FAILED(mError)) + return; // not enough memory? +#endif + +#if defined(XP_MAC) + Boolean changed; + mError = NS_FILE_RESULT(::ResolveAlias(nsnull, (AliasHandle)aliasH, &mSpec, &changed)); + DisposeHandle((Handle) aliasH); + mPath.SetToEmpty(); +#elif defined(XP_MACOSX) + Boolean changed; + FSRef fileRef; + mError = NS_FILE_RESULT(::FSResolveAlias(nsnull, (AliasHandle)aliasH, &fileRef, &changed)); + ::DisposeHandle(aliasH); + + UInt8 pathBuf[PATH_MAX]; + mError = NS_FILE_RESULT(::FSRefMakePath(&fileRef, pathBuf, PATH_MAX)); + if (NS_FAILED(mError)) + return; + mPath = (const char*)pathBuf; +#else + mPath = data.get(); + mError = NS_OK; +#endif +} + +//======================================================================================== +// UNIX & WIN nsFileSpec implementation +//======================================================================================== + +#if (defined XP_UNIX || defined XP_BEOS) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +: mPath((const char*)inPath) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + mError = NS_OK; +} +#endif //XP_UNIX + +#if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)) +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mPath(inSpec.mPath) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mPath(inString) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + mError = inSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + mPath = inString; + // Make canonical and absolute. + nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */); + mError = NS_OK; +} +#endif //XP_UNIX,XP_WIN,XP_OS2,XP_BEOS + +//---------------------------------------------------------------------------------------- +nsFileSpec nsFileSpec::operator + (const char* inRelativePath) const +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to append name with a null string"); + + nsFileSpec resultSpec = *this; + resultSpec += inRelativePath; + return resultSpec; +} // nsFileSpec::operator + + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::operator == (const nsFileSpec& inOther) const +//---------------------------------------------------------------------------------------- +{ + +#if defined(XP_MAC) + if ( inOther.mSpec.vRefNum == mSpec.vRefNum && + inOther.mSpec.parID == mSpec.parID && + EqualString(inOther.mSpec.name, mSpec.name, false, true)) + return PR_TRUE; +#else + PRBool amEmpty = mPath.IsEmpty(); + PRBool heEmpty = inOther.mPath.IsEmpty(); + if (amEmpty) // we're the same if he's empty... + return heEmpty; + if (heEmpty) // ('cuz I'm not...) + return PR_FALSE; + + nsSimpleCharString str = mPath; + nsSimpleCharString inStr = inOther.mPath; + + // Length() is size of buffer, not length of string + PRUint32 strLast = str.Length() - 1, inLast = inStr.Length() - 1; +#if defined(XP_WIN) || defined(XP_OS2) +#define DIR_SEPARATOR '\\' // XXX doesn't NSPR have this? + /* windows does not care about case. */ +#ifdef XP_OS2 +#define DIR_STRCMP strcmp +#else +#define DIR_STRCMP _stricmp +#endif +#else +#define DIR_SEPARATOR '/' +#if defined(VMS) +#define DIR_STRCMP strcasecmp +#else +#define DIR_STRCMP strcmp +#endif +#endif + + if(str[strLast] == DIR_SEPARATOR) + str[strLast] = '\0'; + + if(inStr[inLast] == DIR_SEPARATOR) + inStr[inLast] = '\0'; + + if (DIR_STRCMP(str, inStr ) == 0) + return PR_TRUE; +#undef DIR_SEPARATOR +#undef DIR_STRCMP +#endif + return PR_FALSE; +} + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::operator != (const nsFileSpec& inOther) const +//---------------------------------------------------------------------------------------- +{ + return (! (*this == inOther) ); +} + +#if !defined(XP_MAC) +//---------------------------------------------------------------------------------------- +// This is the only automatic conversion to const char* +// that is provided, and it allows the +// path to be "passed" to NSPR file routines. This practice +// is VERY EVIL and should only be used to support legacy +// code. Using it guarantees bugs on Macintosh. The path is NOT allocated, so do +// not even think of deleting (or freeing) it. +const char* nsFileSpec::GetCString() const +//---------------------------------------------------------------------------------------- +{ + return mPath; +} +#endif + +//---------------------------------------------------------------------------------------- +// Is our spec a child of the provided parent? +PRBool nsFileSpec::IsChildOf(nsFileSpec &possibleParent) +//---------------------------------------------------------------------------------------- +{ + nsFileSpec iter = *this, parent; +#ifdef DEBUG + int depth = 0; +#endif + while (1) { +#ifdef DEBUG + // sanity + NS_ASSERTION(depth < 100, "IsChildOf has lost its little mind"); + if (depth > 100) + return PR_FALSE; +#endif + if (iter == possibleParent) + return PR_TRUE; + + iter.GetParent(parent); // shouldn't this be an error on parent? + if (iter.Failed()) + return PR_FALSE; + + if (iter == parent) // hit bottom + return PR_FALSE; + + iter = parent; +#ifdef DEBUG + depth++; +#endif + } + + // not reached, but I bet some compiler will whine + return PR_FALSE; +} + +#if 0 +#pragma mark - +#endif + +//======================================================================================== +// class nsPersistentFileDescriptor +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inDesc) +//---------------------------------------------------------------------------------------- + : mDescriptorString(inDesc.mDescriptorString) +{ +} // nsPersistentFileDescriptor::nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::operator = (const nsPersistentFileDescriptor& inDesc) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString = inDesc.mDescriptorString; +} // nsPersistentFileDescriptor::operator = + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsPersistentFileDescriptor::nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_MAC) + if (inSpec.Error()) + return; + AliasHandle aliasH; + OSErr err = NewAlias(nil, inSpec.GetFSSpecPtr(), &aliasH); + if (err != noErr) + return; + + PRUint32 bytes = GetHandleSize((Handle) aliasH); + HLock((Handle) aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + DisposeHandle((Handle) aliasH); + + mDescriptorString = buf; + PR_Free(buf); +#elif defined(XP_MACOSX) + if (inSpec.Error()) + return; + + FSRef fileRef; + Boolean isDir; + OSErr err = ::FSPathMakeRef((const UInt8*)inSpec.GetCString(), &fileRef, &isDir); + if (err != noErr) + return; + + AliasHandle aliasH; + err = ::FSNewAlias(nsnull, &fileRef, &aliasH); + if (err != noErr) + return; + + PRUint32 bytes = ::GetHandleSize((Handle) aliasH); + ::HLock((Handle)aliasH); + char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); + ::DisposeHandle((Handle) aliasH); + + mDescriptorString = buf; + PR_Free(buf); +#else + mDescriptorString = inSpec.GetCString(); +#endif // XP_MAC +} // nsPersistentFileDescriptor::operator = + +//---------------------------------------------------------------------------------------- +nsPersistentFileDescriptor::~nsPersistentFileDescriptor() +//---------------------------------------------------------------------------------------- +{ +} // nsPersistentFileDescriptor::~nsPersistentFileDescriptor + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::GetData(nsAFlatCString& outData) const +//---------------------------------------------------------------------------------------- +{ + outData.Assign(mDescriptorString, mDescriptorString.Length()); +} + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::SetData(const nsAFlatCString& inData) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString.CopyFrom(inData.get(), inData.Length()); +} + +//---------------------------------------------------------------------------------------- +void nsPersistentFileDescriptor::SetData(const char* inData, PRInt32 inSize) +//---------------------------------------------------------------------------------------- +{ + mDescriptorString.CopyFrom(inData, inSize); +} + +//======================================================================================== +// class nsNSPRPath +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsNSPRPath::operator const char*() const +// NSPR expects a UNIX path on unix and Macintosh, but a native path on windows. NSPR +// cannot be changed, so we have to do the dirty work. +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + if (!modifiedNSPRPath) + { + // If this is the first call, initialize modifiedNSPRPath. Start by cloning + // mFilePath, but strip the leading separator, if present + const char* unixPath = (const char*)mFilePath; + if (!unixPath) + return nsnull; + + ((nsNSPRPath*)this)->modifiedNSPRPath + = nsCRT::strdup(*unixPath == '/' ? unixPath + 1: unixPath); + + // Replace the bar + if (modifiedNSPRPath[1] == '|') + modifiedNSPRPath[1] = ':'; + + // Remove the ending separator only if it is not the last separator + int len = strlen(modifiedNSPRPath); + if (modifiedNSPRPath[len - 1 ] == '/' && modifiedNSPRPath[len - 2 ] != ':') + modifiedNSPRPath[len - 1 ] = '\0'; + } + return modifiedNSPRPath; +#else + return (const char*)mFilePath; +#endif +} + +//---------------------------------------------------------------------------------------- +nsNSPRPath::~nsNSPRPath() +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + if (modifiedNSPRPath) + nsCRT::free(modifiedNSPRPath); +#endif +} + + +nsresult +NS_FileSpecToIFile(nsFileSpec* fileSpec, nsILocalFile* *result) +{ + nsresult rv; + + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) return NS_ERROR_FAILURE; + +#if defined(XP_MAC) + { + FSSpec spec = fileSpec->GetFSSpec(); + nsCOMPtr psmAppMacFile = do_QueryInterface(file, &rv); + if (NS_FAILED(rv)) return rv; + rv = psmAppMacFile->InitWithFSSpec(&spec); + if (NS_FAILED(rv)) return rv; + file = do_QueryInterface(psmAppMacFile, &rv); + } +#else + // XP_MACOSX: do this for OS X to preserve long filenames + rv = file->InitWithNativePath(nsDependentCString(fileSpec->GetNativePathCString())); +#endif + if (NS_FAILED(rv)) return rv; + + *result = file; + NS_ADDREF(*result); + return NS_OK; +} + + + + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h new file mode 100644 index 00000000..53fa6c1a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpec.h @@ -0,0 +1,782 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + THESE CLASSES ARE DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + + + + + + + + + +// First checked in on 98/11/20 by John R. McMullen in the wrong directory. +// Checked in again 98/12/04. +// Polished version 98/12/08. + +//======================================================================================== +// +// Classes defined: +// +// nsFilePath, nsFileURL, nsFileSpec, nsPersistentFileDescriptor +// nsDirectoryIterator. +// +// Q. How should I represent files at run time? +// A. Use nsFileSpec. Using char* will lose information on some platforms. +// +// Q. Then what are nsFilePath and nsFileURL for? +// A. Only when you need a char* parameter for legacy code. +// +// Q. How should I represent files in a persistent way (eg, in a disk file)? +// A. Use nsPersistentFileDescriptor. Convert to and from nsFileSpec at run time. +// +// This suite provides the following services: +// +// 1. Encapsulates all platform-specific file details, so that files can be +// described correctly without any platform #ifdefs +// +// 2. Type safety. This will fix the problems that used to occur because people +// confused file paths. They used to use const char*, which could mean three +// or four different things. Bugs were introduced as people coded, right up +// to the moment Communicator 4.5 shipped. +// +// 3. Used in conjunction with nsFileStream.h (q.v.), this supports all the power +// and readability of the ansi stream syntax. +// +// Basic example: +// +// nsFilePath myPath("/Development/iotest.txt"); +// +// nsOutputFileStream testStream(nsFileSpec(myPath)); +// testStream << "Hello World" << nsEndl; +// +// 4. Handy methods for manipulating file specifiers safely, e.g. MakeUnique(), +// SetLeafName(), Exists(). +// +// 5. Easy cross-conversion. +// +// Examples: +// +// Initialize a URL from a string +// +// nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); +// +// Initialize a Unix-style path from a URL +// +// nsFilePath filePath(fileURL); +// +// Initialize a file spec from a URL +// +// nsFileSpec fileSpec(fileURL); +// +// Make the spec unique. +// +// fileSpec.MakeUnique(); +// +// Assign the spec to a URL (causing conversion) +// +// fileURL = fileSpec; +// +// Assign a unix path using a string +// +// filePath = "/Development/MPW/SysErrs.err"; +// +// Assign to a file spec using a unix path (causing conversion). +// +// fileSpec = filePath; +// +// Make this unique. +// +// fileSpec.MakeUnique(); +// +// 6. Fixes a bug that have been there for a long time, and +// is inevitable if you use NSPR alone, where files are described as paths. +// +// The problem affects platforms (Macintosh) in which a path does not fully +// specify a file, because two volumes can have the same name. This +// is solved by holding a "private" native file spec inside the +// nsFilePath and nsFileURL classes, which is used when appropriate. +// +//======================================================================================== + +#ifndef _FILESPEC_H_ +#define _FILESPEC_H_ + +#include "xpcomobsolete.h" +#include "nsError.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "prtypes.h" + +//======================================================================================== +// Compiler-specific macros, as needed +//======================================================================================== +#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(_MSC_VER)) +#define NS_USING_NAMESPACE +#endif + +#ifdef NS_USING_NAMESPACE + +#define NS_NAMESPACE_PROTOTYPE +#define NS_NAMESPACE namespace +#define NS_NAMESPACE_END +#define NS_EXPLICIT explicit +#else + +#define NS_NAMESPACE_PROTOTYPE static +#define NS_NAMESPACE struct +#define NS_NAMESPACE_END ; +#define NS_EXPLICIT + +#endif +//=========================== End Compiler-specific macros =============================== + +#include "nsILocalFile.h" +#include "nsCOMPtr.h" + +#if defined(XP_MAC) +#include +#include "nsILocalFileMac.h" +#elif defined(XP_UNIX) || defined(XP_BEOS) +#include +#elif defined(XP_WIN) + +// This clashes with some of the Win32 system headers (specifically, +// winbase.h). Hopefully they'll have been included first; else we may +// have problems. We could include winbase.h before doing this; +// unfortunately, it's bring in too much crap and'd slow stuff down +// more than it's worth doing. +#ifdef CreateDirectory +#undef CreateDirectory +#endif + +#include "prio.h" +#elif defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#define INCL_GPI +#include +#include "prio.h" +#endif + +//======================================================================================== +// Here are the allowable ways to describe a file. +//======================================================================================== + +class nsFileSpec; // Preferred. For i/o use nsInputFileStream, nsOutputFileStream +class nsFilePath; +class nsFileURL; +class nsNSPRPath; // This can be passed to NSPR file I/O routines, if you must. +class nsPersistentFileDescriptor; // Used for storage across program launches. + +#define kFileURLPrefix "file://" +#define kFileURLPrefixLength (7) + +class nsOutputStream; +class nsInputStream; +class nsIOutputStream; +class nsIInputStream; +class nsOutputFileStream; +class nsInputFileStream; +class nsOutputConsoleStream; + +class nsIUnicodeEncoder; +class nsIUnicodeDecoder; + +//======================================================================================== +// Conversion of native file errors to nsresult values. These are really only for use +// in the file module, clients of this interface shouldn't really need them. +// Error results returned from this interface have, in the low-order 16 bits, +// native errors that are masked to 16 bits. Assumption: a native error of 0 is success +// on all platforms. Note the way we define this using an inline function. This +// avoids multiple evaluation if people go NS_FILE_RESULT(function_call()). +#define NS_FILE_RESULT(x) ns_file_convert_result((PRInt32)x) +nsresult ns_file_convert_result(PRInt32 nativeErr); +#define NS_FILE_FAILURE NS_FILE_RESULT(-1) + +//======================================================================================== +class nsSimpleCharString +// An envelope for char*: reference counted. Used internally by all the nsFileSpec +// classes below. +//======================================================================================== +{ +public: + nsSimpleCharString(); + nsSimpleCharString(const char*); + nsSimpleCharString(const nsString&); + nsSimpleCharString(const nsSimpleCharString&); + nsSimpleCharString(const char* inData, PRUint32 inLength); + + ~nsSimpleCharString(); + + void operator = (const char*); + void operator = (const nsString&); + void operator = (const nsSimpleCharString&); + + operator const char*() const { return mData ? mData->mString : 0; } + operator char* () + { + ReallocData(Length()); // requires detaching if shared... + return mData ? mData->mString : 0; + } + PRBool operator == (const char*); + PRBool operator == (const nsString&); + PRBool operator == (const nsSimpleCharString&); + + void operator += (const char* inString); + nsSimpleCharString operator + (const char* inString) const; + + char operator [](int i) const { return mData ? mData->mString[i] : '\0'; } + char& operator [](int i) + { + if (i >= (int)Length()) + ReallocData((PRUint32)i + 1); + return mData->mString[i]; // caveat appelator + } + char& operator [](unsigned int i) { return (*this)[(int)i]; } + + void Catenate(const char* inString1, const char* inString2); + + void SetToEmpty(); + PRBool IsEmpty() const { return Length() == 0; } + + PRUint32 Length() const { return mData ? mData->mLength : 0; } + void SetLength(PRUint32 inLength) { ReallocData(inLength); } + void CopyFrom(const char* inData, PRUint32 inLength); + void LeafReplace(char inSeparator, const char* inLeafName); + char* GetLeaf(char inSeparator) const; // use PR_Free() + void Unescape(); + +protected: + + void AddRefData(); + void ReleaseData(); + void ReallocData(PRUint32 inLength); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + +protected: + + struct Data { + int mRefCount; + PRUint32 mLength; + char mString[1]; + }; + Data* mData; +}; // class nsSimpleCharString + +//======================================================================================== +class NS_COM_OBSOLETE nsFileSpec +// This is whatever each platform really prefers to describe files as. Declared first +// because the other two types have an embedded nsFileSpec object. +//======================================================================================== +{ + public: + nsFileSpec(); + + // These two meathods take *native* file paths. + NS_EXPLICIT nsFileSpec(const char* inNativePath, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileSpec(const nsString& inNativePath, PRBool inCreateDirs = PR_FALSE); + + + NS_EXPLICIT nsFileSpec(const nsFilePath& inPath); + NS_EXPLICIT nsFileSpec(const nsFileURL& inURL); + nsFileSpec(const nsFileSpec& inPath); + virtual ~nsFileSpec(); + + // These two operands take *native* file paths. + void operator = (const char* inNativePath); + + void operator = (const nsFilePath& inPath); + void operator = (const nsFileURL& inURL); + void operator = (const nsFileSpec& inOther); + void operator = (const nsPersistentFileDescriptor& inOther); + + PRBool operator ==(const nsFileSpec& inOther) const; + PRBool operator !=(const nsFileSpec& inOther) const; + + + // Returns a native path, and allows the + // path to be "passed" to legacy code. This practice + // is VERY EVIL and should only be used to support legacy + // code. Using it guarantees bugs on Macintosh. + // The path is cached and freed by the nsFileSpec destructor + // so do not delete (or free) it. See also nsNSPRPath below, + // if you really must pass a string to PR_OpenFile(). + // Doing so will introduce two automatic bugs. + const char* GetCString() const; + + // Same as GetCString (please read the comments). + // Do not try to free this! + operator const char* () const { return GetCString(); } + + // Same as GetCString (please read the comments). + // Do not try to free this! + const char* GetNativePathCString() const { return GetCString(); } + + PRBool IsChildOf(nsFileSpec &possibleParent); + +#if defined(XP_MAC) + // For Macintosh people, this is meant to be useful in its own right as a C++ version + // of the FSSpec struct. + nsFileSpec( + short vRefNum, + long parID, + ConstStr255Param name, + PRBool resolveAlias = PR_TRUE); + + nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias = PR_TRUE); + void operator = (const FSSpec& inSpec); + + operator FSSpec* () { return &mSpec; } + operator const FSSpec* const () { return &mSpec; } + operator FSSpec& () { return mSpec; } + operator const FSSpec& () const { return mSpec; } + + const FSSpec& GetFSSpec() const { return mSpec; } + FSSpec& GetFSSpec() { return mSpec; } + ConstFSSpecPtr GetFSSpecPtr() const { return &mSpec; } + FSSpecPtr GetFSSpecPtr() { return &mSpec; } + void MakeAliasSafe(); + void MakeUnique(ConstStr255Param inSuggestedLeafName); + StringPtr GetLeafPName() { return mSpec.name; } + ConstStr255Param GetLeafPName() const { return mSpec.name; } + + OSErr GetCatInfo(CInfoPBRec& outInfo) const; + + OSErr SetFileTypeAndCreator(OSType type, OSType creator); + OSErr GetFileTypeAndCreator(OSType* type, OSType* creator); + +#endif // end of Macintosh utility methods. + + PRBool Valid() const { return NS_SUCCEEDED(Error()); } + nsresult Error() const + { +#if !defined(XP_MAC) + if (mPath.IsEmpty() && NS_SUCCEEDED(mError)) + ((nsFileSpec*)this)->mError = NS_ERROR_NOT_INITIALIZED; +#endif + return mError; + } + PRBool Failed() const { return (PRBool)NS_FAILED(Error()); } + + //-------------------------------------------------- + // Queries and path algebra. These do not modify the disk. + //-------------------------------------------------- + + char* GetLeafName() const; // Allocated. Use nsCRT::free(). + // inLeafName can be a relative path, so this allows + // one kind of concatenation of "paths". + void SetLeafName(const char* inLeafName); + + // Return the filespec of the parent directory. Used + // in conjunction with GetLeafName(), this lets you + // parse a path into a list of node names. Beware, + // however, that the top node is still not a name, + // but a spec. Volumes on Macintosh can have identical + // names. Perhaps could be used for an operator --() ? + void GetParent(nsFileSpec& outSpec) const; + + + // ie nsFileSpec::TimeStamp. This is 32 bits now, + // but might change, eg, to a 64-bit class. So use the + // typedef, and use a streaming operator to convert + // to a string, so that your code won't break. It's + // none of your business what the number means. Don't + // rely on the implementation. + typedef PRUint32 TimeStamp; + + // This will return different values on different + // platforms, even for the same file (eg, on a server). + // But if the platform is constant, it will increase after + // every file modification. + void GetModDate(TimeStamp& outStamp) const; + + PRBool ModDateChanged(const TimeStamp& oldStamp) const + { + TimeStamp newStamp; + GetModDate(newStamp); + return newStamp != oldStamp; + } + + PRUint32 GetFileSize() const; + PRInt64 GetDiskSpaceAvailable() const; + + nsFileSpec operator + (const char* inRelativeUnixPath) const; + + // Concatenate the relative path to this directory. + // Used for constructing the filespec of a descendant. + // This must be a directory for this to work. This differs + // from SetLeafName(), since the latter will work + // starting with a sibling of the directory and throws + // away its leaf information, whereas this one assumes + // this is a directory, and the relative path starts + // "below" this. + void operator += (const char* inRelativeUnixPath); + + + void MakeUnique(); + void MakeUnique(const char* inSuggestedLeafName); + + + PRBool IsDirectory() const; // More stringent than Exists() + PRBool IsFile() const; // More stringent than Exists() + PRBool Exists() const; + + PRBool IsHidden() const; + + PRBool IsSymlink() const; + + //-------------------------------------------------- + // Creation and deletion of objects. These can modify the disk. + //-------------------------------------------------- + + // Called for the spec of an alias. Modifies the spec to + // point to the original. Sets mError. + nsresult ResolveSymlink(PRBool& wasSymlink); + + void CreateDirectory(int mode = 0775 /* for unix */); + void CreateDir(int mode = 0775) { CreateDirectory(mode); } + // workaround for yet another VC++ bug with long identifiers. + void Delete(PRBool inRecursive) const; + nsresult Truncate(PRInt32 aNewLength) const; + void RecursiveCopy(nsFileSpec newDir) const; + + nsresult Rename(const char* inNewName); // not const: gets updated + nsresult CopyToDir(const nsFileSpec& inNewParentDirectory) const; + nsresult MoveToDir(const nsFileSpec& inNewParentDirectory); + nsresult Execute(const char* args) const; + + protected: + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + + // Clear the nsFileSpec contents, resetting it + // to the uninitialized state; + void Clear(); + + friend class nsFilePath; + friend class nsFileURL; + friend class nsDirectoryIterator; +#if defined(XP_MAC) + FSSpec mSpec; +#endif + nsSimpleCharString mPath; + nsresult mError; + +private: + NS_EXPLICIT nsFileSpec(const nsPersistentFileDescriptor& inURL); + +}; // class nsFileSpec + +// FOR HISTORICAL REASONS: + +typedef nsFileSpec nsNativeFileSpec; + +//======================================================================================== +class NS_COM_OBSOLETE nsFileURL +// This is an escaped string that looks like "file:///foo/bar/mumble%20fish". Since URLs +// are the standard way of doing things in mozilla, this allows a string constructor, +// which just stashes the string with no conversion. +//======================================================================================== +{ + public: + nsFileURL(const nsFileURL& inURL); + NS_EXPLICIT nsFileURL(const char* inURLString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileURL(const nsString& inURLString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFileURL(const nsFilePath& inPath); + NS_EXPLICIT nsFileURL(const nsFileSpec& inPath); + virtual ~nsFileURL(); + +// nsString GetString() const { return mPath; } + // may be needed for implementation reasons, + // but should not provide a conversion constructor. + + void operator = (const nsFileURL& inURL); + void operator = (const char* inURLString); + void operator = (const nsString& inURLString) + { + *this = NS_LossyConvertUCS2toASCII(inURLString).get(); + } + void operator = (const nsFilePath& inOther); + void operator = (const nsFileSpec& inOther); + + void operator +=(const char* inRelativeUnixPath); + nsFileURL operator +(const char* inRelativeUnixPath) const; + operator const char* () const { return (const char*)mURL; } // deprecated. + const char* GetURLString() const { return (const char*)mURL; } + // Not allocated, so don't free it. + const char* GetAsString() const { return (const char*)mURL; } + // Not allocated, so don't free it. + +#if defined(XP_MAC) + // Accessor to allow quick assignment to a mFileSpec + const nsFileSpec& GetFileSpec() const { return mFileSpec; } +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + friend class nsFilePath; // to allow construction of nsFilePath + nsSimpleCharString mURL; + +#if defined(XP_MAC) + // Since the path on the macintosh does not uniquely specify a file (volumes + // can have the same name), stash the secret nsFileSpec, too. + nsFileSpec mFileSpec; +#endif +}; // class nsFileURL + +//======================================================================================== +class NS_COM_OBSOLETE nsFilePath +// This is a string that looks like "/foo/bar/mumble fish". Same as nsFileURL, but +// without the "file:// prefix", and NOT %20 ENCODED! Strings passed in must be +// valid unix-style paths in this format. +//======================================================================================== +{ + public: + nsFilePath(const nsFilePath& inPath); + NS_EXPLICIT nsFilePath(const char* inUnixPathString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFilePath(const nsString& inUnixPathString, PRBool inCreateDirs = PR_FALSE); + NS_EXPLICIT nsFilePath(const nsFileURL& inURL); + NS_EXPLICIT nsFilePath(const nsFileSpec& inPath); + virtual ~nsFilePath(); + + + operator const char* () const { return mPath; } + // This will return a UNIX string. If you + // need a string that can be passed into + // NSPR, take a look at the nsNSPRPath class. + + void operator = (const nsFilePath& inPath); + void operator = (const char* inUnixPathString); + void operator = (const nsString& inUnixPathString) + { + *this = NS_LossyConvertUCS2toASCII(inUnixPathString).get(); + } + void operator = (const nsFileURL& inURL); + void operator = (const nsFileSpec& inOther); + + void operator +=(const char* inRelativeUnixPath); + nsFilePath operator +(const char* inRelativeUnixPath) const; + +#if defined(XP_MAC) + public: + // Accessor to allow quick assignment to a mFileSpec + const nsFileSpec& GetFileSpec() const { return mFileSpec; } +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + private: + + nsSimpleCharString mPath; +#if defined(XP_MAC) + // Since the path on the macintosh does not uniquely specify a file (volumes + // can have the same name), stash the secret nsFileSpec, too. + nsFileSpec mFileSpec; +#endif +}; // class nsFilePath + +//======================================================================================== +class nsPersistentFileDescriptor +// To save information about a file's location in another file, initialize +// one of these from your nsFileSpec, and then write this out to your output stream. +// To retrieve the info, create one of these, read its value from an input stream. +// and then make an nsFileSpec from it. +//======================================================================================== +{ + public: + nsPersistentFileDescriptor() {} + // For use prior to reading in from a stream + nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inEncodedData); + virtual ~nsPersistentFileDescriptor(); + void operator = (const nsPersistentFileDescriptor& inEncodedData); + + // Conversions + NS_EXPLICIT nsPersistentFileDescriptor(const nsFileSpec& inSpec); + void operator = (const nsFileSpec& inSpec); + + // The following four functions are declared here (as friends). Their implementations + // are in mozilla/base/src/nsFileSpecStreaming.cpp. + + friend nsresult Read(nsIInputStream* aStream, nsPersistentFileDescriptor&); + friend nsresult Write(nsIOutputStream* aStream, const nsPersistentFileDescriptor&); + // writes the data to a file + friend NS_COM_OBSOLETE nsInputStream& operator >> (nsInputStream&, nsPersistentFileDescriptor&); + // reads the data from a file + friend NS_COM_OBSOLETE nsOutputStream& operator << (nsOutputStream&, const nsPersistentFileDescriptor&); + // writes the data to a file + friend class nsFileSpec; + + void GetData(nsAFlatCString& outData) const; + void SetData(const nsAFlatCString& inData); + void SetData(const char* inData, PRInt32 inSize); + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + protected: + + nsSimpleCharString mDescriptorString; + +}; // class nsPersistentFileDescriptor + +//======================================================================================== +class NS_COM_OBSOLETE nsDirectoryIterator +// Example: +// +// nsFileSpec parentDir(...); // directory over whose children we shall iterate +// for (nsDirectoryIterator i(parentDir, PR_FALSE); i.Exists(); i++) +// { +// // do something with i.Spec() +// } +// +// - or - +// +// for (nsDirectoryIterator i(parentDir, PR_TRUE); i.Exists(); i--) +// { +// // do something with i.Spec() +// } +// This one passed the PR_TRUE flag which will resolve any symlink encountered. +//======================================================================================== +{ + public: + nsDirectoryIterator( const nsFileSpec& parent, + PRBool resoveSymLinks); +#if !defined(XP_MAC) + // Macintosh currently doesn't allocate, so needn't clean up. + virtual ~nsDirectoryIterator(); +#endif + PRBool Exists() const { return mExists; } + nsDirectoryIterator& operator ++(); // moves to the next item, if any. + nsDirectoryIterator& operator ++(int) { return ++(*this); } // post-increment. + nsDirectoryIterator& operator --(); // moves to the previous item, if any. + nsDirectoryIterator& operator --(int) { return --(*this); } // post-decrement. + operator nsFileSpec&() { return mCurrent; } + + nsFileSpec& Spec() { return mCurrent; } + + private: + +#if defined(XP_MAC) + OSErr SetToIndex(); +#endif + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + + private: + + nsFileSpec mCurrent; + PRBool mExists; + PRBool mResoveSymLinks; + +#if (defined(XP_UNIX) || defined(XP_BEOS) || defined (XP_WIN) || defined(XP_OS2)) + nsFileSpec mStarting; +#endif + +#if defined(XP_MAC) + short mVRefNum; + long mParID; + short mIndex; + short mMaxIndex; +#elif defined(XP_UNIX) || defined(XP_BEOS) + DIR* mDir; +#elif defined(XP_WIN) || defined(XP_OS2) + PRDir* mDir; // XXX why not use PRDir for Unix too? +#endif +}; // class nsDirectoryIterator + +//======================================================================================== +class NS_COM_OBSOLETE nsNSPRPath +// This class will allow you to pass any one of the nsFile* classes directly into NSPR +// without the need to worry about whether you have the right kind of filepath or not. +// It will also take care of cleaning up any allocated memory. +//======================================================================================== +{ +public: + NS_EXPLICIT nsNSPRPath(const nsFileSpec& inSpec) + : mFilePath(inSpec), modifiedNSPRPath(nsnull) {} + NS_EXPLICIT nsNSPRPath(const nsFileURL& inURL) + : mFilePath(inURL), modifiedNSPRPath(nsnull) {} + NS_EXPLICIT nsNSPRPath(const nsFilePath& inUnixPath) + : mFilePath(inUnixPath), modifiedNSPRPath(nsnull) {} + + virtual ~nsNSPRPath(); + + operator const char*() const; + // Returns the path + // that NSPR file routines expect on each platform. + // Concerning constness, this can modify + // modifiedNSPRPath, but it's really just "mutable". + + //-------------------------------------------------- + // Data + //-------------------------------------------------- + +private: + + nsFilePath mFilePath; + char* modifiedNSPRPath; // Currently used only on XP_WIN,XP_OS2 +}; // class nsNSPRPath + + +NS_COM_OBSOLETE nsresult NS_FileSpecToIFile(nsFileSpec* fileSpec, nsILocalFile* *result); + +#endif // _FILESPEC_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp new file mode 100644 index 00000000..20a38f5e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecBeOS.cpp @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include +#include +#include "nsError.h" +#include "prio.h" /* for PR_Rename */ + +// BeOS specific headers +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode); + } + char buffer[MAXPATHLEN]; + errno = 0; + *buffer = '\0'; + BEntry e((const char *)ioPath, true); + BPath p; + e.GetPath(&p); + ioPath = p.Path(); +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.LeafReplace('/', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('/'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_TRUE; + char *leafname = GetLeafName(); + if (nsnull != leafname) + { + if ((!strcmp(leafname, ".")) || (!strcmp(leafname, ".."))) + { + hidden = PR_FALSE; + } + nsCRT::free(leafname); + } + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode)) + return PR_TRUE; + + return PR_FALSE; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = PR_FALSE; + + char resolvedPath[MAXPATHLEN]; + int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN); + if (0 < charCount) + { + if (MAXPATHLEN > charCount) + resolvedPath[charCount] = '\0'; + + wasAliased = PR_TRUE; + /* if it's not an absolute path, + replace the leaf with what got resolved */ + if (resolvedPath[0] != '/') { + SetLeafName(resolvedPath); + } + else { + mPath = (char*)resolvedPath; + } + + BEntry e((const char *)mPath, true); // traverse symlink + BPath p; + status_t err; + err = e.GetPath(&p); + NS_ASSERTION(err == B_OK, "realpath failed"); + + const char* canonicalPath = p.Path(); + if(err == B_OK) + mPath = (char*)canonicalPath; + else + return NS_ERROR_FAILURE; + } + return NS_OK; +} // nsFileSpec::ResolveSymlink + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '/'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + if (!inRelativePath || mPath.IsEmpty()) + return; + + char endChar = mPath[(int)(strlen(mPath) - 1)]; + if (endChar == '/') + mPath += "x"; + else + mPath += "/x"; + SetLeafName(inRelativePath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (mPath.IsEmpty()) + return; + mkdir(mPath, mode); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else if (!mPath.IsEmpty()) + remove(mPath); +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 offset) const +//---------------------------------------------------------------------------------------- +{ + char* Path = nsCRT::strdup(mPath); + + int rv = truncate(Path, offset) ; + + nsCRT::free(Path) ; + + if(!rv) + return NS_OK ; + else + return NS_ERROR_FAILURE ; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + // This function should not be used to move a file on disk. + if (mPath.IsEmpty() || strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +static int CrudeFileCopy(const char* in, const char* out) +//---------------------------------------------------------------------------------------- +{ + struct stat in_stat; + int stat_result = -1; + + char buf [1024]; + FILE *ifp, *ofp; + int rbytes, wbytes; + + if (!in || !out) + return -1; + + stat_result = stat (in, &in_stat); + + ifp = fopen (in, "r"); + if (!ifp) + { + return -1; + } + + ofp = fopen (out, "w"); + if (!ofp) + { + fclose (ifp); + return -1; + } + + while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0) + { + while (rbytes > 0) + { + if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 ) + { + fclose (ofp); + fclose (ifp); + unlink(out); + return -1; + } + rbytes -= wbytes; + } + } + fclose (ofp); + fclose (ifp); + + if (stat_result == 0) + chmod (out, in_stat.st_mode & 0777); + + return 0; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath)); + } + return result; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inNewParentDirectory.IsDirectory() && !IsDirectory()) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath)); + if (result == NS_OK) + { + // cast to fix const-ness + ((nsFileSpec*)this)->Delete(PR_FALSE); + + *this = inNewParentDirectory + GetLeafName(); + } + } + return result; +} + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty() && !IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + char curdir [MAXPATHLEN]; + if (!mPath || !*mPath) + { + (void) getcwd(curdir, MAXPATHLEN); + if (!curdir) + return ULONGLONG_MAX; /* hope for the best as we did in cheddar */ + } + else + sprintf(curdir, "%.200s", (const char*)mPath); + + BEntry e(curdir); + if(e.InitCheck() != B_OK) + return ULONGLONG_MAX; /* hope for the best as we did in cheddar */ + entry_ref ref; + e.GetRef(&ref); + BVolume v(ref.device); + +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", space); +#endif + return v.FreeBytes(); +} // nsFileSpec::GetDiskSpace() + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsFileSpec& inDirectory +, PRBool resolveSymlinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mDir(nsnull) + , mResoveSymLinks(resolveSymlinks) +{ + mStarting += "sysygy"; // save off the starting directory + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + char* dot = "."; + char* dotdot = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory + mCurrent.SetLeafName(entry->d_name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp new file mode 100644 index 00000000..b0e3cc15 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.cpp @@ -0,0 +1,879 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsFileSpecImpl.h"// Always first, to ensure that it compiles alone. + +#include "nsIFileStream.h" +#include "nsFileStream.h" + +#include "nsILocalFile.h" +#include "nsNativeCharsetUtils.h" + +#include "prmem.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsFileSpecImpl, nsIFileSpec) + +#ifdef NS_DEBUG +#define TEST_OUT_PTR(p) \ + if (!(p)) \ + return NS_ERROR_NULL_POINTER; +#else +#define TEST_OUT_PTR(p) +#endif + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl() +//---------------------------------------------------------------------------------------- + : mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::nsFileSpecImpl(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- + : mFileSpec(inSpec) + , mInputStream(nsnull) + , mOutputStream(nsnull) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + +} + +//---------------------------------------------------------------------------------------- +nsFileSpecImpl::~nsFileSpecImpl() +//---------------------------------------------------------------------------------------- +{ + CloseStream(); +} + +//---------------------------------------------------------------------------------------- +/* static */ +nsresult nsFileSpecImpl::MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + nsFileSpecImpl* it = new nsFileSpecImpl(inSpec); + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + return it->QueryInterface(NS_GET_IID(nsIFileSpec), (void **) result); +} // nsFileSpecImpl::MakeInterface + +#define FILESPEC(ifilespec) ((nsFileSpecImpl*)ifilespec)->mFileSpec + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::FromFileSpec(const nsIFileSpec *original) +//---------------------------------------------------------------------------------------- +{ + if (original) { + nsresult rv = ((nsIFileSpec *)original)->GetFileSpec( &mFileSpec); + if (NS_SUCCEEDED( rv)) + return mFileSpec.Error(); + else + return( rv); + } + else + return( NS_ERROR_FAILURE); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsChildOf(nsIFileSpec *possibleParent, + PRBool *_retval) +{ + *_retval = mFileSpec.IsChildOf(FILESPEC(possibleParent)); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetURLString(char * *aURLString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aURLString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFileURL url(mFileSpec); + *aURLString = nsCRT::strdup(url.GetURLString()); + if (!*aURLString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} // nsFileSpecImpl::GetURLString + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetURLString(const char * aURLString) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFileURL(aURLString); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnixStyleFilePath(char * *aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aUnixStyleFilePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsFilePath path(mFileSpec); + *aUnixStyleFilePath = nsCRT::strdup((const char*) path); + if (!*aUnixStyleFilePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnixStyleFilePath(const char * aUnixStyleFilePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = nsFilePath(aUnixStyleFilePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetPersistentDescriptorString(char * *aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aPersistentDescriptorString) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsPersistentFileDescriptor desc(mFileSpec); + nsCAutoString data; + desc.GetData(data); + *aPersistentDescriptorString = ToNewCString(data); + if (!*aPersistentDescriptorString) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetPersistentDescriptorString(const char * aPersistentDescriptorString) +//---------------------------------------------------------------------------------------- +{ + nsPersistentFileDescriptor desc(mFileSpec); + desc.SetData(nsDependentCString(aPersistentDescriptorString)); + mFileSpec = desc; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNativePath(char * *aNativePath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNativePath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + *aNativePath = nsCRT::strdup(mFileSpec.GetNativePathCString()); + if (!*aNativePath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetNativePath(const char * aNativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aNativePath; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetUnicodePath(nsAString & aUnicodePath) +//---------------------------------------------------------------------------------------- +{ + nsCAutoString native; + native = mFileSpec.GetNativePathCString(); + NS_CopyNativeToUnicode(native, aUnicodePath); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetUnicodePath(const nsAString & aUnicodePath) +//---------------------------------------------------------------------------------------- +{ + nsCAutoString native; + + NS_CopyUnicodeToNative(aUnicodePath, native); + mFileSpec = native.get(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetNSPRPath(char * *aNSPRPath) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aNSPRPath) + if (mFileSpec.Failed()) + return mFileSpec.Error(); + nsNSPRPath path(mFileSpec); + *aNSPRPath = nsCRT::strdup((const char*) path); + if (!*aNSPRPath) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Error() +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsValid(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Valid(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Failed(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + *_retval = mFileSpec.Failed(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetLeafName(char * *aLeafName) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aLeafName) + *aLeafName = mFileSpec.GetLeafName(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetLeafName(const char * aLeafName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.SetLeafName(aLeafName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetParent(nsIFileSpec * *aParent) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aParent) + nsFileSpec parent; + mFileSpec.GetParent(parent); + return MakeInterface(parent, aParent); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MakeUniqueWithSuggestedName(const char *suggestedName) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.MakeUnique(suggestedName); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetModDate(PRUint32 *aModDate) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aModDate) + nsFileSpec::TimeStamp stamp; + mFileSpec.GetModDate(stamp); + *aModDate = stamp; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ModDateChanged(PRUint32 oldStamp, PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.ModDateChanged(oldStamp); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsDirectory(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsDirectory(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsFile(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsFile(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.Exists(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsHidden(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsHidden(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsSymlink(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = mFileSpec.IsSymlink(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ResolveSymlink() +//---------------------------------------------------------------------------------------- +{ + PRBool ignore; + return mFileSpec.ResolveSymlink(ignore); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSize(PRUint32 *aFileSize) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSize) + *aFileSize = mFileSpec.GetFileSize(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aDiskSpaceAvailable) + *aDiskSpaceAvailable = mFileSpec.GetDiskSpaceAvailable(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::AppendRelativeUnixPath(const char *relativePath) +//---------------------------------------------------------------------------------------- +{ + mFileSpec += relativePath; + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Touch() +//---------------------------------------------------------------------------------------- +{ + // create an empty file, like the UNIX touch command. + nsresult rv; + rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + rv = CloseStream(); + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CreateDir() +//---------------------------------------------------------------------------------------- +{ + mFileSpec.CreateDir(); + return mFileSpec.Error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Delete(PRBool aRecursive) +//---------------------------------------------------------------------------------------- +{ + mFileSpec.Delete(aRecursive); + return mFileSpec.Error(); +} +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Truncate(PRInt32 aNewLength) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Truncate(aNewLength); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Rename(const char *newLeafName) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Rename(newLeafName); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CopyToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.CopyToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::MoveToDir(const nsIFileSpec *newParentDir) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.MoveToDir(FILESPEC(newParentDir)); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Execute(const char *args) +//---------------------------------------------------------------------------------------- +{ + return mFileSpec.Execute(args); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReading() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + return NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::OpenStreamForReadingAndWriting() +//---------------------------------------------------------------------------------------- +{ + if (mInputStream || mOutputStream) + return NS_ERROR_FAILURE; + nsresult result = NS_NewTypicalInputFileStream((nsISupports**)&mInputStream, mFileSpec); + if (NS_SUCCEEDED(result)) + result = NS_NewTypicalOutputFileStream((nsISupports**)&mOutputStream, mFileSpec); + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::CloseStream() +//---------------------------------------------------------------------------------------- +{ + NS_IF_RELEASE(mInputStream); + NS_IF_RELEASE(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::IsStreamOpen(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = (mInputStream || mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetInputStream(nsIInputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mInputStream; + NS_IF_ADDREF(mInputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetOutputStream(nsIOutputStream** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + } + *_retval = mOutputStream; + NS_IF_ADDREF(mOutputStream); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFileContents(const char* inString) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) return rv; + PRInt32 count; + rv = Write(inString, PL_strlen(inString), &count); + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileContents(char** _retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + *_retval = nsnull; + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + PRInt32 theSize; + rv = GetFileSize((PRUint32*)&theSize); + if (NS_SUCCEEDED(rv)) + rv = Read(_retval, theSize, &theSize); + if (NS_SUCCEEDED(rv)) + (*_retval)[theSize] = 0; + nsresult rv2 = CloseStream(); + return NS_FAILED(rv) ? rv : rv2; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::GetFileSpec(nsFileSpec *aFileSpec) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(aFileSpec) + *aFileSpec = mFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Equals(nsIFileSpec *spec, PRBool *result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv; + + if (!result || !spec) return NS_ERROR_NULL_POINTER; + + nsFileSpec otherSpec; + + rv = spec->GetFileSpec(&otherSpec); + if (NS_FAILED(rv)) return rv; + + if (mFileSpec == otherSpec) { + *result = PR_TRUE; + } + else { + *result = PR_FALSE; + } + + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::SetFromFileSpec(const nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = aFileSpec; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Eof(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.eof(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Read(char** buffer, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + TEST_OUT_PTR(buffer) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*buffer) + *buffer = (char*)PR_Malloc(requestedCount + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.read(*buffer, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::ReadLine(char** line, PRInt32 bufferSize, PRBool *wasTruncated) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(wasTruncated) + TEST_OUT_PTR(line) + if (!mInputStream) { + nsresult rv = OpenStreamForReading(); + if (NS_FAILED(rv)) return rv; + } + if (!*line) + *line = (char*)PR_Malloc(bufferSize + 1); + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *wasTruncated = !s.readline(*line, bufferSize); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Write(const char * data, PRInt32 requestedCount, PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + //if (!mOutputStream) + // return NS_ERROR_NULL_POINTER; + if (!mOutputStream) { + nsresult rv = OpenStreamForWriting(); + if (NS_FAILED(rv)) + return rv; + } + nsOutputFileStream s(mOutputStream); + *_retval = s.write(data, requestedCount); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return NS_ERROR_NULL_POINTER; + nsOutputFileStream s(mOutputStream); + s.flush(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Seek(PRInt32 offset) +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_OK; + if (mOutputStream) + { + nsOutputFileStream os(mOutputStream); + os.seek(offset); + result = os.error(); + } + if (NS_SUCCEEDED(result) && mInputStream) + { + nsInputFileStream is(mInputStream); + is.seek(offset); + result = is.error(); + } + return result; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Tell(PRInt32 *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mInputStream) + return NS_ERROR_NULL_POINTER; + nsInputFileStream s(mInputStream); + *_retval = s.tell(); + return s.error(); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::EndLine() +//---------------------------------------------------------------------------------------- +{ + nsOutputFileStream s(mOutputStream); + s << nsEndl; + return s.error(); +} + +NS_IMPL_ISUPPORTS1(nsDirectoryIteratorImpl, nsIDirectoryIterator) + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- + : mDirectoryIterator(nsnull) +{ +} + +//---------------------------------------------------------------------------------------- +nsDirectoryIteratorImpl::~nsDirectoryIteratorImpl() +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Init(nsIFileSpec *parent, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- +{ + delete mDirectoryIterator; + mDirectoryIterator = new nsDirectoryIterator(FILESPEC(parent), resolveSymlink); + if (!mDirectoryIterator) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Exists(PRBool *_retval) +//---------------------------------------------------------------------------------------- +{ + TEST_OUT_PTR(_retval) + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + *_retval = mDirectoryIterator->Exists(); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Next() +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + (*mDirectoryIterator)++; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::GetCurrentSpec(nsIFileSpec * *aCurrentSpec) +//---------------------------------------------------------------------------------------- +{ + if (!mDirectoryIterator) + return NS_ERROR_NULL_POINTER; + return nsFileSpecImpl::MakeInterface(mDirectoryIterator->Spec(), aCurrentSpec); +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsDirectoryIteratorImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsDirectoryIteratorImpl* it = new nsDirectoryIteratorImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP nsFileSpecImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec) +//---------------------------------------------------------------------------------------- +{ + if (aIFileSpec == NULL) + return NS_ERROR_NULL_POINTER; + + nsFileSpecImpl* it = new nsFileSpecImpl; + if (!it) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = it->QueryInterface(aIID, aIFileSpec); + if (NS_FAILED(rv)) + { + delete it; + return rv; + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + if (!result) + return NS_ERROR_NULL_POINTER; + + return nsFileSpecImpl::MakeInterface(aSrcFileSpec, result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpec(nsIFileSpec** result) +//---------------------------------------------------------------------------------------- +{ + return nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = nsFileSpecImpl::Create(nsnull, NS_GET_IID(nsIFileSpec), (void**)result); + if (NS_FAILED(rv)) return rv; + + nsCAutoString path; + rv = aFile->GetNativePath(path); + if (NS_FAILED(rv)) return rv; + + rv = (*result)->SetNativePath(path.get()); + if (NS_FAILED(rv)) + NS_RELEASE(*result); + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result) +//---------------------------------------------------------------------------------------- +{ + return nsDirectoryIteratorImpl::Create(nsnull, NS_GET_IID(nsIDirectoryIterator), (void**)result); +} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h new file mode 100644 index 00000000..811749cb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecImpl.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _FILESPECIMPL_H_ +#define _FILESPECIMPL_H_ + +#include "nscore.h" +#include "nsIFileSpec.h" +#include "nsFileSpec.h" + +//======================================================================================== +class NS_COM_OBSOLETE nsFileSpecImpl +//======================================================================================== + : public nsIFileSpec +{ + + public: + + NS_DECL_ISUPPORTS + + NS_DECL_NSIFILESPEC + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + + //---------------------- + // Implementation + //---------------------- + + nsFileSpecImpl(); + nsFileSpecImpl(const nsFileSpec& inSpec); + static nsresult MakeInterface(const nsFileSpec& inSpec, nsIFileSpec** outSpec); + + //---------------------- + // Data + //---------------------- + + nsFileSpec mFileSpec; + nsIInputStream* mInputStream; + nsIOutputStream* mOutputStream; + +private: + ~nsFileSpecImpl(); +}; // class nsFileSpecImpl + +//======================================================================================== +class NS_COM_OBSOLETE nsDirectoryIteratorImpl +//======================================================================================== + : public nsIDirectoryIterator +{ + +public: + + nsDirectoryIteratorImpl(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD Init(nsIFileSpec *parent, PRBool resolveSymlink); + + NS_IMETHOD Exists(PRBool *_retval); + + NS_IMETHOD Next(); + + NS_IMETHOD GetCurrentSpec(nsIFileSpec * *aCurrentSpec); + + //---------------------- + // COM Cruft + //---------------------- + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aIFileSpec); + +private: + ~nsDirectoryIteratorImpl(); + +protected: + nsDirectoryIterator* mDirectoryIterator; +}; // class nsDirectoryIteratorImpl + +#endif // _FILESPECIMPL_H_ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp new file mode 100644 index 00000000..fd208fb7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecMac.cpp @@ -0,0 +1,1471 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 file is included by nsFile.cp, and includes the Macintosh-specific +// implementations. + + +#include + +#include "prtypes.h" +#include "nscore.h" + +#include "FullPath.h" +#include "FileCopy.h" +#include "MoreFilesExtras.h" + +#include +#include +#include +#include +#include +#include // ULONG_MAX + +#include "nsFileSpec.h" +#include "nsEscape.h" +#include "nsXPIDLString.h" + + +const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven"; + +//======================================================================================== +namespace MacFileHelpers +//======================================================================================== +{ + inline void PLstrcpy(Str255 dst, ConstStr255Param src) + { + memcpy(dst, src, 1 + src[0]); + } + + void PLstrcpy(Str255 dst, const char* src, int inMaxLen=255); + void PLstrncpy(Str255 dst, const char* src, int inMaxLen); + + void SwapSlashColon(char * s); + OSErr FSSpecFromUnixPath( + const char * unixPath, + FSSpec& ioSpec, + Boolean hexDecode, + Boolean resolveAlias, + Boolean allowPartial = false, + Boolean createDirs = false); + char* MacPathFromUnixPath( + const char* unixPath, + Boolean hexDecode); + char* EncodeMacPath( + char* inPath, // NOT const - gets clobbered + Boolean prependSlash, + Boolean doEscape ); + OSErr FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& ioSpec, + Boolean inCreateDirs); + char* PathNameFromFSSpec( + const FSSpec& inSpec ); + OSErr CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID); // + + // Some routines to support an "alias haven" directory. Aliases in this directory + // are never resolved. There is a ResolveAlias here that respects that. This is + // to support attaching of aliases in mail. + void EnsureAliasHaven(); + void SetNoResolve(Boolean inResolve); + PRBool IsAliasSafe(const FSSpec& inSpec); + OSErr MakeAliasSafe(FSSpec& inOutSpec); + OSErr ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased); + + Boolean sNoResolve = false; + long sAliasHavenDirID = 0; + short sAliasHavenVRefNum = 0; +} // namespace MacFileHelpers + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!"); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax) +//---------------------------------------------------------------------------------------- +{ + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); +} + +//----------------------------------- +void MacFileHelpers::SwapSlashColon(char * s) +//----------------------------------- + +{ + while (*s) + { + if (*s == '/') + *s++ = ':'; + else if (*s == ':') + *s++ = '/'; + else + *s++; + } +} // MacFileHelpers::SwapSlashColon + +//----------------------------------- +char* MacFileHelpers::EncodeMacPath( + char* inPath, // NOT const, gets clobbered + Boolean prependSlash, + Boolean doEscape ) +// Transforms Macintosh style path into Unix one +// Method: Swap ':' and '/', hex escape the result +//----------------------------------- +{ + if (inPath == nsnull) + return nsnull; + int pathSize = strlen(inPath); + + // XP code sometimes chokes if there's a final slash in the unix path. + // Since correct mac paths to folders and volumes will end in ':', strip this + // first. + char* c = inPath + pathSize - 1; + if (*c == ':') + { + *c = 0; + pathSize--; + } + + char * newPath = nsnull; + char * finalPath = nsnull; + + if (prependSlash) + { + newPath = new char[pathSize + 2]; + newPath[0] = ':'; // It will be converted to '/' + memcpy(&newPath[1], inPath, pathSize + 1); + } + else + { + newPath = new char[pathSize + 1]; + strcpy(newPath, inPath); + } + if (newPath) + { + SwapSlashColon( newPath ); + if (doEscape) + { + finalPath = nsEscape(newPath, url_Path); + delete [] newPath; + } + else + finalPath = newPath; + } + delete [] inPath; + return finalPath; +} // MacFileHelpers::EncodeMacPath + +//---------------------------------------------------------------------------------------- +inline void MacFileHelpers::SetNoResolve(Boolean inResolve) +//---------------------------------------------------------------------------------------- +{ + sNoResolve = inResolve; +} // MacFileHelpers::SetNoResolve + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec) +// Pass in the spec of an alias. This copies the file to the safe haven folder, and +// returns the spec of the copy to the caller +//---------------------------------------------------------------------------------------- +{ + EnsureAliasHaven(); + nsFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p"); + + // Make sure its name is unique + nsFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day"); + if (havenSpec.Valid()) + havenSpec.MakeUnique(inOutSpec.name); + // Copy the file into the haven directory + if (havenSpec.Valid()) + { + OSErr err = ::FSpFileCopy( + &inOutSpec, + dstDirSpec, + havenSpec.GetLeafPName(), + nil, 0, true); + // Return the spec of the copy to the caller. + if (err != noErr) + return err; + inOutSpec = havenSpec; + } + return noErr; +} // MacFileHelpers::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath, Boolean hexDecode) +//---------------------------------------------------------------------------------------- +{ + // Relying on the fact that the unix path is always longer than the mac path: + size_t len = strlen(unixPath); + char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name + // REMEMBER: at the end we call SwapSlashColon, so bear that in mind when you see + // this code using '/' as a separator in what is supposed to be a Macintosh path! + if (result) + { + char* dst = result; + const char* src = unixPath; + if (*src == '/') // * full path + src++; + else if (strchr(src, '/') && *src != '.') + { + // * partial path, and not just a leaf name. The '.' test is there because + // the loop below will add sufficient colons in that case. + *dst++ = '/'; + } + // Copy src to dst, but watch out for .. and . + char c = '/'; + do + { + char cprev = c; // remember the previous char (initially /) + c = *src++; + if (c == '.' && cprev == '/') + { + char* dstSaved = dst; + // Special cases: "." and "..". Convert to ':' and '::' + *dst++ = '/'; // . becomes : + c = *src++; + if (c == '.') + { + *dst++ = '/'; // .. becomes :: + c = *src++; + } + if (c == '/') + { + // ../ becomes :: so just skip the slash + // ./ becomes : " " " " " + src++; + } + else if (c) + { + // Oh. A file called ".foo" or "..foo" + // Back up and just do the normal thing. + src -= (dst - dstSaved); + dst = dstSaved; + // Since c is not '/', we won't do this stuff on the + // next iteration. + } + continue; + } + else if (c == '/' && cprev == '/') + { + // Hmm. A 'run on' path with two slashes right next to each other. + // This is an illegal path, but, hey, we'll be tough and try to + // deal with it (especially since '::' has loaded semantics in + // a Mac path) + continue; + } + *dst++ = c; + } while (c); + if (hexDecode) + nsUnescape(result); // Hex Decode + MacFileHelpers::SwapSlashColon(result); + } + return result; +} // MacFileHelpers::MacPathFromUnixPath + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& ioSpec, // used as in-parameter for a relative path. + Boolean inCreateDirs) +// FSSpecFromPathname reverses PathNameFromFSSpec. +// It returns a FSSpec given a c string which is a mac pathname. +//---------------------------------------------------------------------------------------- +{ + OSErr err; + // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles + // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. + + short inVRefNum = ioSpec.vRefNum; + long inParID = ioSpec.parID; + + size_t inLength = strlen(inPathNamePtr); + bool isRelative = (strchr(inPathNamePtr, ':') == 0 || *inPathNamePtr == ':'); +#ifdef NS_DEBUG + // Attempt to catch people sending unix paths in to routines that expect native ones. + NS_ASSERTION(strchr(inPathNamePtr, '/') == 0, + "Possible unix path where native path is required"); +#endif + if (inLength < 255) + { + Str255 pascalpath; + MacFileHelpers::PLstrcpy(pascalpath, inPathNamePtr); + if (isRelative) + err = ::FSMakeFSSpec(inVRefNum, inParID, pascalpath, &ioSpec); + else + err = ::FSMakeFSSpec(0, 0, pascalpath, &ioSpec); + } + else if (!isRelative) + err = FSpLocationFromFullPath(inLength, inPathNamePtr, &ioSpec); + else + err = bdNamErr; + + if ((err == dirNFErr || err == bdNamErr) && inCreateDirs) + { + const char* path = inPathNamePtr; + if (isRelative) + { + ioSpec.vRefNum = inVRefNum; + ioSpec.parID = inParID; + } + else + { + ioSpec.vRefNum = 0; + ioSpec.parID = 0; + } + do { + // Locate the colon that terminates the node. + // But if we've a partial path (starting with a colon), find the second one. + const char* nextColon = strchr(path + (*path == ':'), ':'); + // Well, if there are no more colons, point to the end of the string. + if (!nextColon) + nextColon = path + strlen(path); + + // Make a pascal string out of this node. Include initial + // and final colon, if any! + Str255 ppath; + MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1); + + // Use this string as a relative path using the directory created + // on the previous round (or directory 0,0 on the first round). + err = ::FSMakeFSSpec(ioSpec.vRefNum, ioSpec.parID, ppath, &ioSpec); + + // If this was the leaf node, then we are done. + if (!*nextColon) + break; + + // Since there's more to go, we have to get the directory ID, which becomes + // the parID for the next round. + if (err == noErr) + { + // The directory (or perhaps a file) exists. Find its dirID. + long dirID; + Boolean isDirectory; + err = ::FSpGetDirectoryID(&ioSpec, &dirID, &isDirectory); + if (!isDirectory) + return dupFNErr; // oops! a file exists with that name. + if (err) + return err; + ioSpec.parID = dirID; + } + else if (err == fnfErr) + { + // If we got "file not found", then + // we need to create a directory. + err = ::FSpDirCreate(&ioSpec, smCurrentScript, &ioSpec.parID); + // For some reason, this usually returns fnfErr, even though it works. + if (err == fnfErr) + err = noErr; + } + if (err != noErr) + return err; + path = nextColon; // next round + } while (1); + } + return err; +} // MacFileHelpers::FSSpecFromPathname + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID) // +// Creates a folder named 'folderName' inside a folder. +// The errors returned are same as PBDirCreate +//---------------------------------------------------------------------------------------- +{ + HFileParam hpb; + hpb.ioVRefNum = refNum; + hpb.ioDirID = dirID; + hpb.ioNamePtr = (StringPtr)&folderName; + + OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb); + if (err == noErr) + { + outRefNum = hpb.ioVRefNum; + outDirID = hpb.ioDirID; + } + else + { + outRefNum = 0; + outDirID = 0; + } + return err; +} // MacFileHelpers::CreateFolderInFolder + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::EnsureAliasHaven() +//---------------------------------------------------------------------------------------- +{ + // Alias Haven is a directory in which we never resolve aliases. + if (sAliasHavenVRefNum != 0) + return; + + + FSSpec temp; + if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr) + { + CreateFolderInFolder( + temp.vRefNum, // Parent directory/volume + temp.parID, + kAliasHavenFolderName, // Name of the new folder + sAliasHavenVRefNum, // Volume of the created folder + sAliasHavenDirID); + } +} // MacFileHelpers::EnsureAliasHaven + +//---------------------------------------------------------------------------------------- +PRBool MacFileHelpers::IsAliasSafe(const FSSpec& inSpec) +// Returns true if the alias is in the alias haven directory, or if alias resolution +// has been turned off. +//---------------------------------------------------------------------------------------- +{ + return sNoResolve + || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum); +} // MacFileHelpers::IsAliasSafe + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = false; + if (IsAliasSafe(inOutSpec)) + return noErr; + Boolean dummy; + return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased); +} // MacFileHelpers::ResolveAliasFile + +//----------------------------------- +OSErr MacFileHelpers::FSSpecFromUnixPath( + const char * unixPath, + FSSpec& ioSpec, + Boolean hexDecode, + Boolean resolveAlias, + Boolean allowPartial, + Boolean createDirs) +// File spec from URL. Reverses GetURLFromFileSpec +// Its input is only the part of the URL +// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), +// then it is combined with inOutSpec's vRefNum and parID to form a new spec. +//----------------------------------- +{ + if (unixPath == nsnull) + return badFidErr; + char* macPath = MacPathFromUnixPath(unixPath, hexDecode); + if (!macPath) + return memFullErr; + + OSErr err = noErr; + if (!allowPartial) + { + NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!"); + } + err = FSSpecFromPathname(macPath, ioSpec, createDirs); + if (err == fnfErr) + err = noErr; + Boolean dummy; + if (err == noErr && resolveAlias) // Added + err = MacFileHelpers::ResolveAliasFile(ioSpec, dummy); + delete [] macPath; + NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!"); + return err; +} // MacFileHelpers::FSSpecFromLocalUnixPath + +//----------------------------------- +char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec ) +// Returns a full pathname to the given file +// Returned value is allocated with new [], and must be freed with delete [] +// For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work. +//----------------------------------- +{ + char* result = nil; + nsresult rv; + + FSSpec nonConstSpec = inSpec; + nsCAutoString path; + nsCOMPtr macFile; + + rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(macFile)); + if (NS_FAILED(rv)) return nsnull; + nsCOMPtr localFile(do_QueryInterface(macFile, &rv)); + if (NS_FAILED(rv)) return nsnull; + rv = localFile->GetNativePath(path); + if (NS_FAILED(rv)) return nsnull; + PRInt32 strLen = path.Length(); + result = new char [strLen + 1]; + if (!result) return nsnull; + memcpy(result, path.get(), strLen); + result[ strLen ] = 0; + + return result; +} // MacFileHelpers::PathNameFromFSSpec + + +#pragma mark - + +//======================================================================================== +// Macintosh nsFileSpec implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec() +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias) +//---------------------------------------------------------------------------------------- +: mSpec(inSpec) +, mError(NS_OK) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + if (resolveAlias) + { + PRBool dummy; + ResolveSymlink(dummy); + } +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const FSSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mSpec = inSpec; + mError = NS_OK; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mSpec(inSpec.mSpec) +, mError(inSpec.Error()) +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const char* inNativePathString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + if (inNativePathString) + { + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname( + inNativePathString, mSpec, inCreateDirs)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::nsFileSpec + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsString& inNativePathString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + mError = NS_FILE_RESULT( + MacFileHelpers::FSSpecFromPathname( + NS_LossyConvertUCS2toASCII(inNativePathString).get(), + mSpec, inCreateDirs)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + +} // nsFileSpec::nsFileSpec + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(short vRefNum, long parID, ConstStr255Param fileName, PRBool resolveAlias) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + mError = NS_FILE_RESULT(::FSMakeFSSpec(vRefNum, parID, fileName, &mSpec)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + + if (resolveAlias) + { + PRBool dummy; + ResolveSymlink(dummy); + } +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath.GetFileSpec(); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED + + if (inString) + { + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inString, mSpec, true)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mSpec.vRefNum = inSpec.mSpec.vRefNum; + mSpec.parID = inSpec.mSpec.parID; + + PRInt32 copySize = inSpec.mSpec.name[0] + 1; + if (copySize > sizeof(inSpec.mSpec.name)) + copySize = sizeof(inSpec.mSpec.name); + memcpy(mSpec.name, inSpec.mSpec.name, copySize); + mError = inSpec.Error(); // note that the error is propagated +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + *this = inPath.GetFileSpec(); +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +inline void nsFileSpec::Clear() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mSpec.vRefNum = 0; + mSpec.parID = 0; + mSpec.name[0] = 0; + mError = NS_ERROR_NOT_INITIALIZED; +} + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + if (NS_FAILED(mError)) return PR_FALSE; + FSSpec temp; + return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr; +} // nsFileSpec::Exists() + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec pb; + if (GetCatInfo(pb) == noErr) + outStamp = ((DirInfo*)&pb)->ioDrMdDat; // The mod date is in the same spot for files and dirs. + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec pb; + if (noErr == GetCatInfo(pb)) + return (PRUint32)((HFileInfo*)&pb)->ioFlLgLen; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +// In leaf name can actually be a partial path... +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to set leaf name with a null string"); + + mPath.SetToEmpty(); + + if (inLeafName) + { + // what about long relative paths? Hmm? We don't have a routine for this anywhere. + Str255 partialPath; + MacFileHelpers::PLstrcpy(partialPath, inLeafName); + mError = NS_FILE_RESULT( + ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec)); + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + } + +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +// Result needs to be nsCRT::free()ed. +//---------------------------------------------------------------------------------------- +{ + char leaf[sizeof(mSpec.name)]; + memcpy(leaf, &mSpec.name[1], mSpec.name[0]); + leaf[mSpec.name[0]] = '\0'; + return nsCRT::strdup(leaf); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeAliasSafe() +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + mError = NS_FILE_RESULT(MacFileHelpers::MakeAliasSafe(mSpec)); +} // nsFileSpec::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +void nsFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.SetToEmpty(); + if (inSuggestedLeafName[0] > 0) + MacFileHelpers::PLstrcpy(mSpec.name, inSuggestedLeafName); + + MakeUnique(); +} // nsFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + long dirID; + Boolean isDirectory; + return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cInfo; + PRBool hidden = PR_FALSE; + + if (noErr == GetCatInfo(cInfo)) + if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) + hidden = PR_TRUE; + + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cInfo; + PRBool hidden = PR_FALSE; + + if (noErr == GetCatInfo(cInfo)) + if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias) + hidden = PR_TRUE; + + return hidden; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + Boolean wasAliased2; // Type conversion Boolean <--> PRBool + OSErr err = MacFileHelpers::ResolveAliasFile(mSpec, wasAliased2); + if (wasAliased2) + { + mError = NS_FILE_RESULT(err); + wasAliased = PR_TRUE; + } + else + wasAliased = PR_FALSE; + + return mError; +} // nsFileSpec::ResolveSymlink + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + if (NS_SUCCEEDED(mError)) + outSpec.mError = NS_FILE_RESULT(::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, nsnull, outSpec)); +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to append relative path with null path"); + + // Invalidate the path cache string, since we're changing ourselves. + mPath.SetToEmpty(); + + // if we are already bad, don't allow appendage + if (NS_FAILED(Error())) + { + NS_WARNING("trying to append to a bad nsFileSpec"); + return; + } + + // Find the dirID of the directory described by this spec + long dirID; + Boolean isDirectory; + mError = NS_FILE_RESULT(::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory)); + if (NS_FAILED(mError) || !isDirectory || !inRelativePath) + return; + // mSpec.vRefNum is already correct. + mSpec.parID = dirID; + + // Next, determine if it is a UNIX or Mac style path. Now, Macintosh relative paths + // are either leaf names (in which the distinction between unix and macintosh + // relative paths disappears) or they start with a colon. If we find an initial colon, + // then assume it's a macintosh path. + // If it is a UNIX path (including just a leaf name), we will also look for ':' and + // assert if we find one. + if (*inRelativePath != ':') + { + // Looks like a UNIX path (including possibly just a leaf name) + NS_ASSERTION(strchr(inRelativePath, ':') == nsnull, "Can not determine path type"); + // Convert unix path (which is unencoded) to a spec + mError = NS_FILE_RESULT( + MacFileHelpers::FSSpecFromUnixPath(inRelativePath, mSpec, false, false, true, true)); + } + else + { + // We must be a mac path! + mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inRelativePath, mSpec, true)); + } + if (mError == NS_FILE_RESULT(fnfErr)) + mError = NS_OK; + +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /* unix mode */) +//---------------------------------------------------------------------------------------- +{ + long ignoredDirID; + OSErr err = ::FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID); + // it's OK if the dir already exists + if (err != noErr && IsDirectory()) + err = noErr; + + mError = NS_FILE_RESULT(err); + +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + OSErr anErr; + + nsresult& mutableError = const_cast(this)->mError; + if (inRecursive) + { + // MoreFilesExtras + anErr = ::DeleteDirectory( + mSpec.vRefNum, + mSpec.parID, + const_cast(mSpec.name)); + } + else + anErr = ::FSpDelete(&mSpec); + + if (anErr == fnfErr) // deleting a file that doesn't exist isn't an error! + anErr = noErr; + + mutableError = NS_FILE_RESULT(anErr); + +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 aNewLength) const +//---------------------------------------------------------------------------------------- +{ + short refNum; + OSErr err; + + // First see if we have an internal error set + if (NS_FAILED(mError)) + return mError; + + // Need to open the file to trunc + if (::FSpOpenDF(&mSpec, fsWrPerm, &refNum) != noErr) + return NS_FILE_FAILURE; + + err = ::SetEOF(refNum, aNewLength); + + // Close the file unless we got an error that it was already closed + if (err != fnOpnErr) + (void)::FSClose(refNum); + + if (err != noErr) + return NS_FILE_FAILURE; + + return NS_OK; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to rename with null new name"); + + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; // no relative paths here! + + Str255 pName; + MacFileHelpers::PLstrcpy(pName, inNewName); + if (::FSpRename(&mSpec, pName) != noErr) + return NS_FILE_FAILURE; + SetLeafName(inNewName); + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& newParentDir) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + + if (!newParentDir.IsDirectory() || (IsDirectory() ) ) + return NS_FILE_FAILURE; + + nsresult rv = NS_FILE_RESULT(::FSpFileCopy(&mSpec, + &newParentDir.mSpec, + const_cast(GetLeafPName()), + nsnull, + 0, + true)); + + return rv; + +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& newParentDir) +//---------------------------------------------------------------------------------------- +{ + // We can only move into a directory + + if (!newParentDir.IsDirectory()) + return NS_FILE_FAILURE; + + nsresult result = NS_FILE_RESULT(::FSpMoveRenameCompat(&mSpec, + &newParentDir.mSpec, + const_cast(GetLeafPName()))); + + if ( NS_SUCCEEDED(result) ) + { + char* leafName = GetLeafName(); + *this = newParentDir + leafName; + nsCRT::free(leafName); + } + return result; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* /*args - how can this be cross-platform? problem! */ ) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + return NS_FILE_FAILURE; + + LaunchParamBlockRec launchThis; + launchThis.launchAppSpec = const_cast(&mSpec); + launchThis.launchAppParameters = nsnull; // args; + /* launch the thing */ + launchThis.launchBlockID = extendedBlock; + launchThis.launchEPBLength = extendedBlockLen; + launchThis.launchFileFlags = nsnull; + launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum; + launchThis.launchControlFlags += launchDontSwitch; + + nsresult result = NS_FILE_RESULT(::LaunchApplication(&launchThis)); + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::GetCatInfo(CInfoPBRec& outInfo) const +//---------------------------------------------------------------------------------------- +{ + DirInfo *dipb=(DirInfo *)&outInfo; + dipb->ioCompletion = nsnull; + dipb->ioFDirIndex = 0; // use dirID and name + dipb->ioVRefNum = mSpec.vRefNum; + dipb->ioDrDirID = mSpec.parID; + dipb->ioNamePtr = const_cast(this)->mSpec.name; + return PBGetCatInfoSync(&outInfo); +} // nsFileSpec::GetCatInfo() + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::SetFileTypeAndCreator(OSType type, OSType creator) +//---------------------------------------------------------------------------------------- +{ + FInfo info; + OSErr err = ::FSpGetFInfo(&mSpec, &info); + if (err != noErr) + return err; + info.fdType = type; + info.fdCreator = creator; + err = ::FSpSetFInfo(&mSpec, &info); + return err; +} + +//---------------------------------------------------------------------------------------- +OSErr nsFileSpec::GetFileTypeAndCreator(OSType* type, OSType* creator) +//---------------------------------------------------------------------------------------- +{ + FInfo info; + OSErr err = ::FSpGetFInfo(&mSpec, &info); + if (err != noErr) + return err; + *type = info.fdType; + *creator = info.fdCreator; + return noErr; +} + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 space64Bits; + + LL_I2L(space64Bits , LONG_MAX); + + XVolumeParam pb; + pb.ioCompletion = nsnull; + pb.ioVolIndex = 0; + pb.ioNamePtr = nsnull; + pb.ioVRefNum = mSpec.vRefNum; + + // PBXGetVolInfoSync works on HFS+ volumes too! + OSErr err = ::PBXGetVolInfoSync(&pb); + + if (err == noErr) + { +#ifdef HAVE_LONG_LONG + space64Bits = pb.ioVFreeBytes; +#else + const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); + space64Bits.lo = freeBytes.lo; + space64Bits.hi = freeBytes.hi; +#endif + } + + return space64Bits; +} // nsFileSpec::GetDiskSpace() + +//---------------------------------------------------------------------------------------- +const char* nsFileSpec::GetCString() const +// This is the only conversion to const char* that is provided, and it allows the +// path to be "passed" to NSPR file routines. This practice is VERY EVIL and should only +// be used to support legacy code. Using it guarantees bugs on Macintosh. The string is +// cached and freed by the nsFileSpec destructor, so do not delete (or free) it. +//---------------------------------------------------------------------------------------- +{ + if (mPath.IsEmpty()) + { + char* path = MacFileHelpers::PathNameFromFSSpec(mSpec); + if (path != NULL) { + const_cast(this)->mPath = path; // operator =() copies the string!!! + delete[] path; + } else { + const_cast(this)->mError = NS_ERROR_OUT_OF_MEMORY; + } + } + return mPath; +} + +#pragma mark - + +//======================================================================================== +// Macintosh nsFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +static void AssignFromPath(nsFilePath& ioPath, const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inString, "AssignFromPath called with null inString"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path"); + + FSSpec spec; + spec.vRefNum = 0; + spec.parID = 0; + spec.name[0] = 0; + MacFileHelpers::FSSpecFromUnixPath( + inString, + spec, + false, + true, // resolve alias + true, + inCreateDirs); + // Now we have a spec, + // Invoke operator = (const nsFileSpec&) to do the rest. + // Why didn't we just say mPath = inString to get the path? Well, we want it to be + // canonical and absolute. + ioPath = spec; +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, inString, inCreateDirs); +} //nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, NS_LossyConvertUCS2toASCII(inString).get(), + inCreateDirs); +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + AssignFromPath(*this, inString, PR_FALSE); +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec(inSpec); + path = MacFileHelpers::EncodeMacPath(path, true, false); + mPath = path; + nsCRT::free(path); + mFileSpec = inSpec; +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec); + path = MacFileHelpers::EncodeMacPath(path, true, false); + mPath = path; + nsCRT::free(path); + mFileSpec = inOther.GetFileSpec(); +} + +#pragma mark - + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(inString) +{ + NS_ASSERTION(inString, "nsFileURL constructed with null inString"); + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + inString + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + false, // resolve alias + false, // must be a full path + inCreateDirs)); + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs) +//---------------------------------------------------------------------------------------- +: mURL(nsnull) +{ + NS_LossyConvertUCS2toASCII cstring(inString); + mURL = cstring.get(); + NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(), + "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + cstring.get() + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + false, // resolve alias + false, // must be a full path + inCreateDirs)); + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther.GetFileSpec(); +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther; +} // nsFileURL::nsFileURL + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + *this = inOther.GetFileSpec(); +} // nsFileURL::operator = + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mFileSpec = inOther; + char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec ); + char* encodedPath = MacFileHelpers::EncodeMacPath(path, true, true); + nsSimpleCharString encodedURL(kFileURLPrefix); + encodedURL += encodedPath; + nsCRT::free(encodedPath); + mURL = encodedURL; + if (encodedURL[encodedURL.Length() - 1] != '/' && inOther.IsDirectory()) + mURL += "/"; +} // nsFileURL::operator = + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const char* inString) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inString, "nsFileURL operator= constructed with null inString"); + + mURL = inString; + NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!"); + mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath( + inString + kFileURLPrefixLength, + mFileSpec.mSpec, + true, // need to decode + true, // resolve alias + false, // must be a full path + false)); // don't create dirs. + if (mFileSpec.mError == NS_FILE_RESULT(fnfErr)) + mFileSpec.mError = NS_OK; +} // nsFileURL::operator = + +#pragma mark - + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator( + const nsFileSpec& inDirectory +, PRBool resolveSymLinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(false) + , mResoveSymLinks(resolveSymLinks) + , mIndex(-1) +{ + CInfoPBRec pb; + OSErr err = inDirectory.GetCatInfo(pb); + + // test that we have got a directory back, not a file + DirInfo* dipb = (DirInfo*)&pb; + if (err != noErr || !( dipb->ioFlAttrib & 0x0010)) + return; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&(); + mVRefNum = currentSpec.vRefNum; + mParID = dipb->ioDrDirID; + mMaxIndex = pb.dirInfo.ioDrNmFls; + mIndex = 0; // ready to increment + ++(*this); // the pre-increment operator + +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +OSErr nsDirectoryIterator::SetToIndex() +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cipb; + DirInfo *dipb=(DirInfo *)&cipb; + Str255 objectName; + dipb->ioCompletion = nsnull; + dipb->ioFDirIndex = mIndex; + // Sorry about this, there seems to be a bug in CWPro 4: + FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&(); + dipb->ioVRefNum = mVRefNum; /* Might need to use vRefNum, not sure*/ + dipb->ioDrDirID = mParID; + dipb->ioNamePtr = objectName; + OSErr err = PBGetCatInfoSync(&cipb); + FSSpec temp; + if (err == noErr) + err = FSMakeFSSpec(mVRefNum, mParID, objectName, &temp); + mCurrent = temp; // use the operator: it clears the string cache. + mExists = err == noErr; + + if (mExists && mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + return err; +} // nsDirectoryIterator::SetToIndex() + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + while (--mIndex > 0) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator -- + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = false; + if (mIndex >= 0) // probably trying to use a file as a directory! + while (++mIndex <= mMaxIndex) + { + OSErr err = SetToIndex(); + if (err == noErr) + break; + } + return *this; +} // nsDirectoryIterator::operator ++ + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp new file mode 100644 index 00000000..4621d8b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecOS2.cpp @@ -0,0 +1,840 @@ +/* ***** 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 Mozilla OS/2 libraries. + * + * The Initial Developer of the Original Code is + * John Fairhurst, . + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * 00/01/06: general review and update against Win/Unix versions; + * replaced nsFileSpec::Execute implementation with system() call + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/23/2000 IBM Corp. Fixed bug where 2 char or less profile names treated as drive letters. + * 06/20/2000 IBM Corp. Make it more like Windows version. + */ + +#define INCL_DOSERRORS +#define INCL_DOS +#define INCL_WINWORKPLACE +#include + +#ifdef XP_OS2_VACPP +#include +#endif + +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist. This +// takes a (possibly relative) native path and converts it into a +// fully qualified native path. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + NS_ASSERTION(strchr((const char*)ioPath, '/') == 0, + "This smells like a Unix path. Native path expected! " + "Please fix."); + if (inMakeDirs) + { + const int mode = 0700; + nsSimpleCharString unixStylePath = ioPath; + nsFileSpecHelpers::NativeToUnix(unixStylePath); + nsFileSpecHelpers::MakeAllDirectories((const char*)unixStylePath, mode); + } + char buffer[_MAX_PATH]; + errno = 0; + *buffer = '\0'; +#ifdef XP_OS2 + PRBool removedBackslash = PR_FALSE; + PRUint32 lenstr = ioPath.Length(); + char &lastchar = ioPath[lenstr -1]; + + // Strip off any trailing backslash UNLESS it's the backslash that + // comes after "X:". Note also that "\" is valid. Sheesh. + // + if( lastchar == '\\' && (lenstr != 3 || ioPath[1] != ':') && lenstr != 1) + { + lastchar = '\0'; + removedBackslash = PR_TRUE; + } + + char canonicalPath[CCHMAXPATH] = ""; + + DosQueryPathInfo( (char*) ioPath, + FIL_QUERYFULLNAME, + canonicalPath, + CCHMAXPATH); +#else + char* canonicalPath = _fullpath(buffer, ioPath, _MAX_PATH); +#endif + + if (canonicalPath) + { + NS_ASSERTION( canonicalPath[0] != '\0', "Uh oh...couldn't convert" ); + if (canonicalPath[0] == '\0') + return; +#ifdef XP_OS2 + // If we removed that backslash, add it back onto the fullpath + if (removedBackslash) + strcat( canonicalPath, "\\"); +#endif + } + ioPath = canonicalPath; +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::UnixToNative(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything +//---------------------------------------------------------------------------------------- +{ + // Allow for relative or absolute. We can do this in place, because the + // native path is never longer. + + if (ioPath.IsEmpty()) + return; + + // Strip initial slash for an absolute path + char* src = (char*)ioPath; + if (*src == '/') { + if (!src[1]) { + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + return; + } + // Since it was an absolute path, check for the drive letter + char* colonPointer = src + 2; + if (strstr(src, "|/") == colonPointer) + *colonPointer = ':'; + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + } + + src = (char*)ioPath; + + if (*src) { + // Convert '/' to '\'. + while (*++src) + { + if (*src == '/') + *src = '\\'; + } + } +} // nsFileSpecHelpers::UnixToNative + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::NativeToUnix(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything. The unix path is longer, so we can't do it in place. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + // Convert the drive-letter separator, if present + nsSimpleCharString temp("/"); + + char* cp = (char*)ioPath + 1; + if (strstr(cp, ":\\") == cp) + *cp = '|'; // absolute path + else + temp[0] = '\0'; // relative path + + // Convert '\' to '/' + for (; *cp; cp++) + { +#ifdef XP_OS2 + // OS2TODO - implement equivalent of IsDBCSLeadByte +#else + if(IsDBCSLeadByte(*cp) && *(cp+1) != nsnull) + { + cp++; + continue; + } +#endif + if (*cp == '\\') + *cp = '/'; + } + // Add the slash in front. + temp += ioPath; + ioPath = temp; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath; +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + nsFileSpecHelpers::UnixToNative(mPath); + mError = NS_OK; +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + nsFileSpecHelpers::NativeToUnix(mPath); +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string"); + mPath.LeafReplace('\\', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('\\'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; +#ifdef XP_OS2 + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && ( S_IFREG & st.st_mode); +#else + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFREG & st.st_mode); +#endif +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; +#ifdef XP_OS2 + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && ( S_IFDIR & st.st_mode); +#else + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFDIR & st.st_mode); +#endif +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + if (!mPath.IsEmpty()) + { +#ifdef XP_OS2 + FILESTATUS3 fs3; + APIRET rc; + + rc = DosQueryPathInfo( mPath, + FIL_STANDARD, + &fs3, + sizeof fs3); + if(!rc) + hidden = fs3.attrFile & FILE_HIDDEN ? PR_TRUE : PR_FALSE; +#else + DWORD attr = GetFileAttributes(mPath); + if (FILE_ATTRIBUTE_HIDDEN & attr) + hidden = PR_TRUE; +#endif + } + return hidden; +} +// nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + return PR_FALSE; // No symlinks on OS/2 +#else + HRESULT hres; + IShellLink* psl; + + PRBool isSymlink = PR_FALSE; + + CoInitialize(NULL); + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WORD wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + isSymlink = PR_TRUE; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + return isSymlink; +#endif +} + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink) +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + return NS_OK; // no symlinks on OS/2 +#else + wasSymlink = PR_FALSE; // assume failure + + if (Exists()) + return NS_OK; + + + HRESULT hres; + IShellLink* psl; + + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WORD wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + wasSymlink = PR_TRUE; + + // Resolve the link. + hres = psl->Resolve(nsnull, SLR_NO_UI ); + if (SUCCEEDED(hres)) + { + char szGotPath[MAX_PATH]; + WIN32_FIND_DATA wfd; + + // Get the path to the link target. + hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + + if (SUCCEEDED(hres)) + { + // Here we modify the nsFileSpec; + mPath = szGotPath; + mError = NS_OK; + } + } + } + else { + // It wasn't a shortcut. Oh well. Leave it like it was. + hres = 0; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + if (SUCCEEDED(hres)) + return NS_OK; + + return NS_FILE_FAILURE; +#endif +} + + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '\\'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + if (mPath[mPath.Length() - 1] == '\\') + mPath += "x"; + else + mPath += "\\x"; + + // If it's a (unix) relative path, make it native + nsSimpleCharString dosPath = inRelativePath; + nsFileSpecHelpers::UnixToNative(dosPath); + SetLeafName(dosPath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /*mode*/) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (!mPath.IsEmpty()) +#ifdef XP_OS2 + // OS2TODO - vacpp complains about mkdir but PR_MkDir should be ok? + PR_MkDir(nsNSPRPath(*this), PR_CREATE_FILE); +#else + mkdir(nsNSPRPath(*this)); +#endif +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = i.Spec(); + child.Delete(inRecursive); + } + } +#ifdef XP_OS2 + // OS2TODO - vacpp complains if use rmdir but PR_RmDir should be ok? + PR_RmDir(nsNSPRPath(*this)); +#else + rmdir(nsNSPRPath(*this)); +#endif + } + else if (!mPath.IsEmpty()) + { + remove(nsNSPRPath(*this)); + } +} // nsFileSpec::Delete + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = i.Spec(); + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult +nsFileSpec::Truncate(PRInt32 aNewFileLength) const +//---------------------------------------------------------------------------------------- +{ +#ifdef XP_OS2 + APIRET rc; + HFILE hFile; + ULONG actionTaken; + + rc = DosOpen(mPath, + &hFile, + &actionTaken, + 0, + FILE_NORMAL, + OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE, + NULL); + + if (rc != NO_ERROR) + return NS_FILE_FAILURE; + + rc = DosSetFileSize(hFile, aNewFileLength); + + if (rc == NO_ERROR) + DosClose(hFile); + else + goto error; +#else + DWORD status; + HANDLE hFile; + + // Leave it to Microsoft to open an existing file with a function + // named "CreateFile". + hFile = CreateFile(mPath, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return NS_FILE_FAILURE; + + // Seek to new, desired end of file + status = SetFilePointer(hFile, aNewFileLength, NULL, FILE_BEGIN); + if (status == 0xffffffff) + goto error; + + // Truncate file at current cursor position + if (!SetEndOfFile(hFile)) + goto error; + + if (!CloseHandle(hFile)) + return NS_FILE_FAILURE; +#endif + + return NS_OK; + + error: +#ifdef XP_OS2 + DosClose(hFile); +#else + CloseHandle(hFile); +#endif + return NS_FILE_FAILURE; + +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // CopyFile returns non-zero if succeeds +#ifdef XP_OS2 + APIRET rc; + PRBool copyOK; + + rc = DosCopy(GetCString(), (PSZ)destPath, DCPY_EXISTING); + + if (rc == NO_ERROR) + copyOK = PR_TRUE; + else + copyOK = PR_FALSE; +#else + int copyOK = CopyFile(GetCString(), destPath, PR_TRUE); +#endif + if (copyOK) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inNewParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + if (DosMove(GetCString(), destPath) == NO_ERROR) + { + *this = inNewParentDirectory + GetLeafName(); + return NS_OK; + } + + } + return NS_FILE_FAILURE; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + if (!IsDirectory()) + { +#ifdef XP_OS2 + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + return result; +#else + nsSimpleCharString fileNameWithArgs = "\""; + fileNameWithArgs += mPath + "\" " + inArgs; + int execResult = WinExec( fileNameWithArgs, SW_NORMAL ); + if (execResult > 31) + return NS_OK; +#endif + } + return NS_FILE_FAILURE; +} // nsFileSpec::Execute + + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 nBytes = 0; + ULONG ulDriveNo = toupper(mPath[0]) + 1 - 'A'; + FSALLOCATE fsAllocate; + APIRET rc = DosQueryFSInfo(ulDriveNo, + FSIL_ALLOC, + &fsAllocate, + sizeof(fsAllocate)); + + if (rc == NO_ERROR) { + nBytes = fsAllocate.cUnitAvail; + nBytes *= fsAllocate.cSectorUnit; + nBytes *= fsAllocate.cbSector; + } + + return nBytes; +} + + + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymlink) +{ + mDir = PR_OpenDir(inDirectory); + mCurrent += "dummy"; + mStarting += "dummy"; + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + PR_CloseDir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); // Ignore '.' && '..' + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; + mCurrent.SetLeafName(entry->name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp new file mode 100644 index 00000000..8acb6330 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecUnix.cpp @@ -0,0 +1,703 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Henry Sobotka + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 file is included by nsFileSpec.cpp, and includes the Unix-specific +// implementations. + +#include +#include +#include +#include +#include +#include +#include +#include "xpcom-private.h" +#include "nsError.h" +#include "prio.h" /* for PR_Rename */ +#include "nsAutoBuffer.h" + +#if defined(_SCO_DS) +#define _SVID3 /* for statvfs.h */ +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#ifdef HAVE_SYS_STATFS_H +#include +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#undef Free +#endif + +#ifdef HAVE_STATVFS +#define STATFS statvfs +#else +#define STATFS statfs +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 /* Guessing this is okay. Works for SCO. */ +#endif + +#if defined(__QNX__) +#include /* for realpath */ +#define f_bavail f_bfree +extern "C" int truncate(const char *, off_t); +#endif + +#if defined(SUNOS4) +extern "C" int statfs(char *, struct statfs *); +#endif + +#if defined(OSF1) +extern "C" int statvfs(const char *, struct statvfs *); +#endif + +#ifdef XP_MACOSX +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult); +#endif + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + if (inMakeDirs) + { + const mode_t mode = 0700; + nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode); + } + + errno = 0; // needed? + + if (ioPath[0] != '/') + { + // the ioPath that was passed in is relative. We must cat it to the cwd. + char buffer[MAXPATHLEN]; + + (void) getcwd(buffer, MAXPATHLEN); + + strcat(buffer, "/"); + strcat(buffer, ioPath); + + ioPath = buffer; + } +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + mPath.LeafReplace('/', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ +#ifndef XP_MACOSX + return mPath.GetLeaf('/'); +#else + char *name = mPath.GetLeaf('/'); + if (!name || !*name) + return name; + nsAutoString nameInNFC; + CopyUTF8toUTF16NFC(nsDependentCString(name), nameInNFC); + nsCRT::free(name); + return nsCRT::strdup(NS_ConvertUTF16toUTF8(nameInNFC).get()); +#endif +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + char *leafname = GetLeafName(); + if (nsnull != leafname) + { + // rjc: don't return ".", "..", or any file/directory that begins with a "." + + /* if ((!strcmp(leafname, ".")) || (!strcmp(leafname, ".."))) */ + if (leafname[0] == '.') + { + hidden = PR_TRUE; + } + nsCRT::free(leafname); + } + return hidden; +} // nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode)) + return PR_TRUE; + + return PR_FALSE; +} // nsFileSpec::IsSymlink + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = PR_FALSE; + + char resolvedPath[MAXPATHLEN]; + int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN); + if (0 < charCount) + { + if (MAXPATHLEN > charCount) + resolvedPath[charCount] = '\0'; + + wasAliased = PR_TRUE; + + /* if it's not an absolute path, + replace the leaf with what got resolved */ + if (resolvedPath[0] != '/') { + SetLeafName(resolvedPath); + } + else { + mPath = (char*)&resolvedPath; + } + + char* canonicalPath = realpath((const char *)mPath, resolvedPath); + NS_ASSERTION(canonicalPath, "realpath failed"); + if (canonicalPath) { + mPath = (char*)&resolvedPath; + } + else { + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} // nsFileSpec::ResolveSymlink + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '/'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + char endChar = mPath[(int)(strlen(mPath) - 1)]; + if (endChar == '/') + mPath += "x"; + else + mPath += "/x"; + SetLeafName(inRelativePath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int mode) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (mPath.IsEmpty()) + return; + mkdir(mPath, mode); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +// To check if this worked, call Exists() afterwards, see? +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(mPath); + } + else if (!mPath.IsEmpty()) + remove(mPath); +} // nsFileSpec::Delete + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Truncate(PRInt32 offset) const +//---------------------------------------------------------------------------------------- +{ + char* Path = nsCRT::strdup(mPath); + + int rv = truncate(Path, offset) ; + + nsCRT::free(Path) ; + + if(!rv) + return NS_OK ; + else + return NS_ERROR_FAILURE ; +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (mPath.IsEmpty() || strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +static int CrudeFileCopy(const char* in, const char* out) +//---------------------------------------------------------------------------------------- +{ + struct stat in_stat; + int stat_result = -1; + + char buf [1024]; + FILE *ifp, *ofp; + int rbytes, wbytes; + + if (!in || !out) + return -1; + + stat_result = stat (in, &in_stat); + + ifp = fopen (in, "r"); + if (!ifp) + { + return -1; + } + + ofp = fopen (out, "w"); + if (!ofp) + { + fclose (ifp); + return -1; + } + + while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0) + { + while (rbytes > 0) + { + if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 ) + { + fclose (ofp); + fclose (ifp); + unlink(out); + return -1; + } + rbytes -= wbytes; + } + } + fclose (ofp); + fclose (ifp); + + if (stat_result == 0) + chmod (out, in_stat.st_mode & 0777); + + return 0; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath)); + } + return result; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + nsresult result = NS_FILE_FAILURE; + + if (inNewParentDirectory.IsDirectory() && !IsDirectory()) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "/"; + destPath += leafname; + nsCRT::free(leafname); + + result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath)); + if (result == NS_OK) + { + // cast to fix const-ness + ((nsFileSpec*)this)->Delete(PR_FALSE); + + *this = inNewParentDirectory + GetLeafName(); + } + } + return result; +} + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + nsresult result = NS_FILE_FAILURE; + + if (!mPath.IsEmpty() && !IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs; + result = NS_FILE_RESULT(system(fileNameWithArgs)); + } + + return result; + +} // nsFileSpec::Execute + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 bytes; /* XXX dougt needs to fix this */ + LL_I2L(bytes , LONG_MAX); // initialize to all the space in the world? + + +#if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) + + char curdir [MAXPATHLEN]; + if (mPath.IsEmpty()) + { + (void) getcwd(curdir, MAXPATHLEN); + if (!curdir) + return bytes; /* hope for the best as we did in cheddar */ + } + else + sprintf(curdir, "%.200s", (const char*)mPath); + + struct STATFS fs_buf; +#if defined(__QNX__) && !defined(HAVE_STATVFS) /* Maybe this should be handled differently? */ + if (STATFS(curdir, &fs_buf, 0, 0) < 0) +#else + if (STATFS(curdir, &fs_buf) < 0) +#endif + return bytes; /* hope for the best as we did in cheddar */ + +#ifdef DEBUG_DISK_SPACE + printf("DiskSpaceAvailable: %d bytes\n", + fs_buf.f_bsize * (fs_buf.f_bavail - 1)); +#endif + + PRInt64 bsize,bavail; + LL_I2L( bsize, fs_buf.f_bsize ); + LL_I2L( bavail, fs_buf.f_bavail - 1 ); + LL_MUL( bytes, bsize, bavail ); + return bytes; + +#else + /* + ** This platform doesn't have statfs or statvfs, so we don't have much + ** choice but to "hope for the best as we did in cheddar". + */ + return bytes; +#endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ + +} // nsFileSpec::GetDiskSpace() + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymLinks) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymLinks) + , mStarting(inDirectory) + , mDir(nsnull) + +{ + mStarting += "sysygy"; // save off the starting directory + mCurrent += "sysygy"; // prepare the path for SetLeafName + mDir = opendir((const char*)nsFilePath(inDirectory)); + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + closedir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + const char dot[] = "."; + const char dotdot[] = ".."; + struct dirent* entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dot) == 0) + entry = readdir(mDir); + if (entry && strcmp(entry->d_name, dotdot) == 0) + entry = readdir(mDir); + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory + mCurrent.SetLeafName(entry->d_name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + +// Convert a UTF-8 string to a UTF-16 string while normalizing to +// Normalization Form C (composed Unicode). We need this because +// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode) +// while most other OS', server-side programs usually expect NFC. + +#ifdef XP_MACOSX +typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm); +static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult) +{ + static PRBool sChecked = PR_FALSE; + static UnicodeNormalizer sUnicodeNormalizer = NULL; + + // CFStringNormalize was not introduced until Mac OS 10.2 + if (!sChecked) { + CFBundleRef carbonBundle = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon")); + if (carbonBundle) + sUnicodeNormalizer = (UnicodeNormalizer) + ::CFBundleGetFunctionPointerForName(carbonBundle, + CFSTR("CFStringNormalize")); + sChecked = PR_TRUE; + } + + if (!sUnicodeNormalizer) { // OS X 10.1 or earlier + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc); + + // The number of 16bit code units in a UTF-16 string will never be + // larger than the number of bytes in the corresponding UTF-8 string. + CFMutableStringRef inStr = + ::CFStringCreateMutable(NULL, inFlatSrc.Length()); + + if (!inStr) { + CopyUTF8toUTF16(aSrc, aResult); + return; + } + + ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8); + + sUnicodeNormalizer(inStr, kCFStringNormalizationFormC); + + CFIndex length = CFStringGetLength(inStr); + const UniChar* chars = CFStringGetCharactersPtr(inStr); + + if (chars) + aResult.Assign(chars, length); + else { + nsAutoBuffer buffer; + if (buffer.EnsureElemCapacity(length)) { + CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get()); + aResult.Assign(buffer.get(), length); + } + else + CopyUTF8toUTF16(aSrc, aResult); + } + CFRelease(inStr); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp new file mode 100644 index 00000000..7d7e863d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileSpecWin.cpp @@ -0,0 +1,766 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 file is included by nsFileSpec.cp, and includes the Windows-specific +// implementations. + +#include +#include +#include +#include +#include "prio.h" +#include "nsError.h" + +#include + +#if (_MSC_VER == 1100) || defined(__GNUC__) +#define INITGUID +#include +DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0); +#endif + +#include +#include +#include + +#ifdef UNICODE +#define CreateDirectoryW CreateDirectory +#else +#define CreateDirectoryA CreateDirectory +#endif + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs) +// Canonify, make absolute, and check whether directories exist. This +// takes a (possibly relative) native path and converts it into a +// fully qualified native path. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + NS_ASSERTION(strchr((const char*)ioPath, '/') == 0, + "This smells like a Unix path. Native path expected! " + "Please fix."); + if (inMakeDirs) + { + const int mode = 0755; + nsSimpleCharString unixStylePath = ioPath; + nsFileSpecHelpers::NativeToUnix(unixStylePath); + nsFileSpecHelpers::MakeAllDirectories((const char*)unixStylePath, mode); + } + char buffer[_MAX_PATH]; + errno = 0; + *buffer = '\0'; + char* canonicalPath = _fullpath(buffer, ioPath, _MAX_PATH); + + if (canonicalPath) + { + NS_ASSERTION( canonicalPath[0] != '\0', "Uh oh...couldn't convert" ); + if (canonicalPath[0] == '\0') + return; + } + ioPath = canonicalPath; +} // nsFileSpecHelpers::Canonify + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::UnixToNative(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything +//---------------------------------------------------------------------------------------- +{ + // Allow for relative or absolute. We can do this in place, because the + // native path is never longer. + + if (ioPath.IsEmpty()) + return; + + // Strip initial slash for an absolute path + char* src = (char*)ioPath; + if (*src == '/') { + if (!src[1]) { + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + return; + } + // Since it was an absolute path, check for the drive letter + char* colonPointer = src + 2; + if (strstr(src, "|/") == colonPointer) + *colonPointer = ':'; + // allocate new string by copying from ioPath[1] + nsSimpleCharString temp = src + 1; + ioPath = temp; + } + + // Convert '/' to '\'. (Must check EVERY character: consider UNC path + // case.) + for (src = (char*)ioPath; *src; ++src) + { + if (*src == '/') + *src = '\\'; + } + +} // nsFileSpecHelpers::UnixToNative + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::NativeToUnix(nsSimpleCharString& ioPath) +// This just does string manipulation. It doesn't check reality, or canonify, or +// anything. The unix path is longer, so we can't do it in place. +//---------------------------------------------------------------------------------------- +{ + if (ioPath.IsEmpty()) + return; + + // Convert the drive-letter separator, if present + nsSimpleCharString temp("/"); + + char* cp = (char*)ioPath + 1; + if (strstr(cp, ":\\") == cp) + *cp = '|'; // absolute path + else + if (cp[0] == '\\') // unc path + cp--; + else + temp[0] = '\0'; // relative path + + // Convert '\' to '/' + for (; *cp; cp++) + { + if(IsDBCSLeadByte(*cp) && *(cp+1) != nsnull) + { + cp++; + continue; + } + if (*cp == '\\') + *cp = '/'; + } + // Add the slash in front. + temp += ioPath; + ioPath = temp; +} + +//---------------------------------------------------------------------------------------- +nsFileSpec::nsFileSpec(const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ +// NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!"); + *this = inPath; +} + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator = (const nsFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mPath = (const char*)inPath; + nsFileSpecHelpers::UnixToNative(mPath); + mError = NS_OK; +} // nsFileSpec::operator = + +//---------------------------------------------------------------------------------------- +nsFilePath::nsFilePath(const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + *this = inSpec; +} // nsFilePath::nsFilePath + +//---------------------------------------------------------------------------------------- +void nsFilePath::operator = (const nsFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mPath = inSpec.mPath; + nsFileSpecHelpers::NativeToUnix(mPath); +} // nsFilePath::operator = + +//---------------------------------------------------------------------------------------- +void nsFileSpec::SetLeafName(const char* inLeafName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string"); + mPath.LeafReplace('\\', inLeafName); +} // nsFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +char* nsFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + return mPath.GetLeaf('\\'); +} // nsFileSpec::GetLeafName + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st); +} // nsFileSpec::Exists + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetModDate(TimeStamp& outStamp) const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + outStamp = st.st_mtime; + else + outStamp = 0; +} // nsFileSpec::GetModDate + +//---------------------------------------------------------------------------------------- +PRUint32 nsFileSpec::GetFileSize() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + if (!mPath.IsEmpty() && stat(nsNSPRPath(*this), &st) == 0) + return (PRUint32)st.st_size; + return 0; +} // nsFileSpec::GetFileSize + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsFile() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFREG & st.st_mode); +} // nsFileSpec::IsFile + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsDirectory() const +//---------------------------------------------------------------------------------------- +{ + struct stat st; + return !mPath.IsEmpty() && 0 == stat(nsNSPRPath(*this), &st) && (_S_IFDIR & st.st_mode); +} // nsFileSpec::IsDirectory + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsHidden() const +//---------------------------------------------------------------------------------------- +{ + PRBool hidden = PR_FALSE; + if (!mPath.IsEmpty()) + { + DWORD attr = GetFileAttributes(mPath); + if (FILE_ATTRIBUTE_HIDDEN & attr) + hidden = PR_TRUE; + } + return hidden; +} +// nsFileSpec::IsHidden + +//---------------------------------------------------------------------------------------- +PRBool nsFileSpec::IsSymlink() const +//---------------------------------------------------------------------------------------- +{ + HRESULT hres; + IShellLink* psl; + + PRBool isSymlink = PR_FALSE; + + CoInitialize(NULL); + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + isSymlink = PR_TRUE; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + return isSymlink; +} + + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::ResolveSymlink(PRBool& wasSymlink) +//---------------------------------------------------------------------------------------- +{ + wasSymlink = PR_FALSE; // assume failure + + if (Exists()) + return NS_OK; + + + HRESULT hres; + IShellLink* psl; + + CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + + // Get a pointer to the IPersistFile interface. + hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); + + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + // Ensure that the string is Unicode. + MultiByteToWideChar(CP_ACP, 0, mPath, -1, wsz, MAX_PATH); + + // Load the shortcut. + hres = ppf->Load(wsz, STGM_READ); + if (SUCCEEDED(hres)) + { + wasSymlink = PR_TRUE; + + // Resolve the link. + hres = psl->Resolve(nsnull, SLR_NO_UI ); + if (SUCCEEDED(hres)) + { + char szGotPath[MAX_PATH]; + WIN32_FIND_DATA wfd; + + // Get the path to the link target. + hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_UNCPRIORITY ); + + if (SUCCEEDED(hres)) + { + // Here we modify the nsFileSpec; + mPath = szGotPath; + mError = NS_OK; + } + } + } + else { + // It wasn't a shortcut. Oh well. Leave it like it was. + hres = 0; + } + + // Release the pointer to the IPersistFile interface. + ppf->Release(); + } + // Release the pointer to the IShellLink interface. + psl->Release(); + } + + CoUninitialize(); + + if (SUCCEEDED(hres)) + return NS_OK; + + return NS_FILE_FAILURE; +} + + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::GetParent(nsFileSpec& outSpec) const +//---------------------------------------------------------------------------------------- +{ + outSpec.mPath = mPath; + char* chars = (char*)outSpec.mPath; + chars[outSpec.mPath.Length() - 1] = '\0'; // avoid trailing separator, if any + char* cp = strrchr(chars, '\\'); + if (cp++) + outSpec.mPath.SetLength(cp - chars); // truncate. +} // nsFileSpec::GetParent + +//---------------------------------------------------------------------------------------- +void nsFileSpec::operator += (const char* inRelativePath) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inRelativePath, "Attempt to do += with a null string"); + + if (!inRelativePath || mPath.IsEmpty()) + return; + + if (mPath[mPath.Length() - 1] == '\\') + mPath += "x"; + else + mPath += "\\x"; + + // If it's a (unix) relative path, make it native + nsSimpleCharString dosPath = inRelativePath; + nsFileSpecHelpers::UnixToNative(dosPath); + SetLeafName(dosPath); +} // nsFileSpec::operator += + +//---------------------------------------------------------------------------------------- +void nsFileSpec::CreateDirectory(int /*mode*/) +//---------------------------------------------------------------------------------------- +{ + // Note that mPath is canonical! + if (!mPath.IsEmpty()) + mkdir(nsNSPRPath(*this)); +} // nsFileSpec::CreateDirectory + +//---------------------------------------------------------------------------------------- +void nsFileSpec::Delete(PRBool inRecursive) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (inRecursive) + { + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + child.Delete(inRecursive); + } + } + rmdir(nsNSPRPath(*this)); + } + else if (!mPath.IsEmpty()) + { + remove(nsNSPRPath(*this)); + } +} // nsFileSpec::Delete + + +//---------------------------------------------------------------------------------------- +void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const +//---------------------------------------------------------------------------------------- +{ + if (IsDirectory()) + { + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++) + { + nsFileSpec& child = (nsFileSpec&)i; + + if (child.IsDirectory()) + { + nsFileSpec tmpDirSpec(newDir); + + char *leafname = child.GetLeafName(); + tmpDirSpec += leafname; + nsCRT::free(leafname); + + child.RecursiveCopy(tmpDirSpec); + } + else + { + child.RecursiveCopy(newDir); + } + } + } + else if (!mPath.IsEmpty()) + { + nsFileSpec& filePath = (nsFileSpec&) *this; + + if (!(newDir.Exists())) + { + newDir.CreateDirectory(); + } + + filePath.CopyToDir(newDir); + } +} // nsFileSpec::RecursiveCopy + +//---------------------------------------------------------------------------------------- +nsresult +nsFileSpec::Truncate(PRInt32 aNewFileLength) const +//---------------------------------------------------------------------------------------- +{ + DWORD status; + HANDLE hFile; + + // Leave it to Microsoft to open an existing file with a function + // named "CreateFile". + hFile = CreateFile(mPath, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return NS_FILE_FAILURE; + + // Seek to new, desired end of file + status = SetFilePointer(hFile, aNewFileLength, NULL, FILE_BEGIN); + if (status == 0xffffffff) + goto error; + + // Truncate file at current cursor position + if (!SetEndOfFile(hFile)) + goto error; + + if (!CloseHandle(hFile)) + return NS_FILE_FAILURE; + + return NS_OK; + + error: + CloseHandle(hFile); + return NS_FILE_FAILURE; + +} // nsFileSpec::Truncate + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Rename(const char* inNewName) +//---------------------------------------------------------------------------------------- +{ + NS_ASSERTION(inNewName, "Attempt to Rename with a null string"); + + // This function should not be used to move a file on disk. + if (strchr(inNewName, '/')) + return NS_FILE_FAILURE; + + char* oldPath = nsCRT::strdup(mPath); + + SetLeafName(inNewName); + + if (PR_Rename(oldPath, mPath) != NS_OK) + { + // Could not rename, set back to the original. + mPath = oldPath; + return NS_FILE_FAILURE; + } + + nsCRT::free(oldPath); + + return NS_OK; +} // nsFileSpec::Rename + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // CopyFile returns non-zero if succeeds + int copyOK = CopyFile(GetCString(), destPath, PR_TRUE); + if (copyOK) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::CopyToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory) +//---------------------------------------------------------------------------------------- +{ + // We can only copy into a directory, and (for now) can not copy entire directories + if (inNewParentDirectory.IsDirectory() && (! IsDirectory() ) ) + { + char *leafname = GetLeafName(); + nsSimpleCharString destPath(inNewParentDirectory.GetCString()); + destPath += "\\"; + destPath += leafname; + nsCRT::free(leafname); + + // MoveFile returns non-zero if succeeds + int copyOK = MoveFile(GetCString(), destPath); + + if (copyOK) + { + *this = inNewParentDirectory + GetLeafName(); + return NS_OK; + } + + } + return NS_FILE_FAILURE; +} // nsFileSpec::MoveToDir + +//---------------------------------------------------------------------------------------- +nsresult nsFileSpec::Execute(const char* inArgs ) const +//---------------------------------------------------------------------------------------- +{ + if (!IsDirectory()) + { + nsSimpleCharString fileNameWithArgs = "\""; + fileNameWithArgs += mPath + "\" " + inArgs; + int execResult = WinExec( fileNameWithArgs, SW_NORMAL ); + if (execResult > 31) + return NS_OK; + } + return NS_FILE_FAILURE; +} // nsFileSpec::Execute + + +//---------------------------------------------------------------------------------------- +PRInt64 nsFileSpec::GetDiskSpaceAvailable() const +//---------------------------------------------------------------------------------------- +{ + PRInt64 int64; + + LL_I2L(int64 , LONG_MAX); + + char aDrive[_MAX_DRIVE + 2]; + _splitpath( (const char*)mPath, aDrive, NULL, NULL, NULL); + + if (aDrive[0] == '\0') + { + // The back end is always trying to pass us paths that look + // like /c|/netscape/mail. See if we've got one of them + if (mPath.Length() > 2 && mPath[0] == '/' && mPath[2] == '|') + { + aDrive[0] = mPath[1]; + aDrive[1] = ':'; + aDrive[2] = '\0'; + } + else + { + // Return bogus large number and hope for the best + return int64; + } + } + + strcat(aDrive, "\\"); + + // Check disk space + DWORD dwSecPerClus, dwBytesPerSec, dwFreeClus, dwTotalClus; + ULARGE_INTEGER liFreeBytesAvailableToCaller, liTotalNumberOfBytes, liTotalNumberOfFreeBytes; + double nBytes = 0; + + BOOL (WINAPI* getDiskFreeSpaceExA)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes) = NULL; + + HINSTANCE hInst = LoadLibrary("KERNEL32.DLL"); + NS_ASSERTION(hInst != NULL, "COULD NOT LOAD KERNEL32.DLL"); + if (hInst != NULL) + { + getDiskFreeSpaceExA = (BOOL (WINAPI*)(LPCTSTR lpDirectoryName, + PULARGE_INTEGER lpFreeBytesAvailableToCaller, + PULARGE_INTEGER lpTotalNumberOfBytes, + PULARGE_INTEGER lpTotalNumberOfFreeBytes)) + GetProcAddress(hInst, "GetDiskFreeSpaceExA"); + FreeLibrary(hInst); + } + + if (getDiskFreeSpaceExA && (*getDiskFreeSpaceExA)(aDrive, + &liFreeBytesAvailableToCaller, + &liTotalNumberOfBytes, + &liTotalNumberOfFreeBytes)) + { + nBytes = (double)(signed __int64)liFreeBytesAvailableToCaller.QuadPart; + } + else if ( GetDiskFreeSpace(aDrive, &dwSecPerClus, &dwBytesPerSec, &dwFreeClus, &dwTotalClus)) + { + nBytes = (double)dwFreeClus*(double)dwSecPerClus*(double) dwBytesPerSec; + } + return (PRInt64)nBytes; +} + + + +//======================================================================================== +// nsDirectoryIterator +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::nsDirectoryIterator(const nsFileSpec& inDirectory, PRBool resolveSymlink) +//---------------------------------------------------------------------------------------- + : mCurrent(inDirectory) + , mDir(nsnull) + , mStarting(inDirectory) + , mExists(PR_FALSE) + , mResoveSymLinks(resolveSymlink) +{ + mDir = PR_OpenDir(inDirectory); + mCurrent += "dummy"; + mStarting += "dummy"; + ++(*this); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator::~nsDirectoryIterator() +//---------------------------------------------------------------------------------------- +{ + if (mDir) + PR_CloseDir(mDir); +} // nsDirectoryIterator::nsDirectoryIterator + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator ++ () +//---------------------------------------------------------------------------------------- +{ + mExists = PR_FALSE; + if (!mDir) + return *this; + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); // Ignore '.' && '..' + if (entry) + { + mExists = PR_TRUE; + mCurrent = mStarting; + mCurrent.SetLeafName(entry->name); + if (mResoveSymLinks) + { + PRBool ignore; + mCurrent.ResolveSymlink(ignore); + } + } + return *this; +} // nsDirectoryIterator::operator ++ + +//---------------------------------------------------------------------------------------- +nsDirectoryIterator& nsDirectoryIterator::operator -- () +//---------------------------------------------------------------------------------------- +{ + return ++(*this); // can't do it backwards. +} // nsDirectoryIterator::operator -- + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp new file mode 100644 index 00000000..f20c60e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.cpp @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/12/08 by John R. McMullen. +// Since nsFileStream.h is entirely templates, common code (such as open()) +// which does not actually depend on the charT, can be placed here. + +#include "nsFileStream.h" +#include "nsFileSpec.h" +#include "nsIFileSpec.h" +#include "nsIStringStream.h" +#include "nsInt64.h" +#include +#include + + +//======================================================================================== +// nsInputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputStream::~nsInputStream() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +char nsInputStream::get() +//---------------------------------------------------------------------------------------- +{ + char c; + if (read(&c, sizeof(c)) == sizeof(c)) + return c; + return 0; +} + +//---------------------------------------------------------------------------------------- +PRInt32 nsInputStream::read(void* s, PRInt32 n) +//---------------------------------------------------------------------------------------- +{ + if (!mInputStream) + return 0; + PRInt32 result = 0; + mInputStream->Read((char*)s, n, (PRUint32*)&result); + if (result == 0) + set_at_eof(PR_TRUE); + return result; +} // nsInputStream::read + +//---------------------------------------------------------------------------------------- +static void TidyEndOfLine(char*& cp) +// Assumes that cp is pointing at \n or \r. Nulls out the character, checks for +// a second terminator (of the opposite persuasion), and returns cp pointing past the +// entire eol construct (one or two characters). +//---------------------------------------------------------------------------------------- +{ + char ch = *cp; + *cp++ = '\0'; // terminate at the newline, then skip past it + if ((ch == '\n' && *cp == '\r') || (ch == '\r' && *cp == '\n')) + cp++; // possibly a pair. +} + +//---------------------------------------------------------------------------------------- +nsInputStream& nsInputStream::operator >> (char& c) +//---------------------------------------------------------------------------------------- +{ + c = get(); + return *this; +} + +//======================================================================================== +// nsOutputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputStream::~nsOutputStream() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +void nsOutputStream::put(char c) +//---------------------------------------------------------------------------------------- +{ + write(&c, sizeof(c)); +} + +//---------------------------------------------------------------------------------------- +PRInt32 nsOutputStream::write(const void* s, PRInt32 n) +//---------------------------------------------------------------------------------------- +{ + if (!mOutputStream) + return 0; + PRInt32 result = 0; + mWriteStatus = mOutputStream->Write((char*)s, n, (PRUint32*)&result); + return result; +} // nsOutputStream::write + +//---------------------------------------------------------------------------------------- +nsresult nsOutputStream::flush() +//---------------------------------------------------------------------------------------- +{ + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +nsresult nsOutputStream::lastWriteStatus() +//---------------------------------------------------------------------------------------- +{ + return mWriteStatus; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (char c) +//---------------------------------------------------------------------------------------- +{ + put(c); + return *this; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (const char* s) +//---------------------------------------------------------------------------------------- +{ + if (s) + write(s, strlen(s)); + return *this; +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (short val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%hd", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned short val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%hu", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (long val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%ld", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned long val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%lu", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (int val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%d", val); + return (*this << buf); +} + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsOutputStream::operator << (unsigned int val) +//---------------------------------------------------------------------------------------- +{ + char buf[30]; + sprintf(buf, "%u", val); + return (*this << buf); +} + +//======================================================================================== +// nsRandomAccessInputStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +PRBool nsRandomAccessInputStream::readline(char* s, PRInt32 n) +// This will truncate if the buffer is too small. Result will always be null-terminated. +//---------------------------------------------------------------------------------------- +{ + PRBool bufferLargeEnough = PR_TRUE; // result + if (!s || !n) + return PR_TRUE; + + nsInt64 position = tell(); + const nsInt64 zero(0); + if (position < zero) + return PR_FALSE; + PRInt32 bytesRead = read(s, n - 1); + if (failed()) + return PR_FALSE; + s[bytesRead] = '\0'; // always terminate at the end of the buffer + char* tp = strpbrk(s, "\n\r"); + if (tp) + { + TidyEndOfLine(tp); + bytesRead = (tp - s); + } + else if (!eof() && n-1 == bytesRead) + bufferLargeEnough = PR_FALSE; + position += bytesRead; + seek(position); + return bufferLargeEnough; +} // nsRandomAccessInputStream::readline + +//======================================================================================== +// nsInputStringStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputStringStream::nsInputStringStream(const char* stringToRead) +//---------------------------------------------------------------------------------------- +{ + nsCOMPtr stream; + if (NS_FAILED(NS_NewCharInputStream(getter_AddRefs(stream), stringToRead))) + return; + mInputStream = stream; + mStore = do_QueryInterface(stream); +} + +//---------------------------------------------------------------------------------------- +nsInputStringStream::nsInputStringStream(const nsString& stringToRead) +//---------------------------------------------------------------------------------------- +{ + if (NS_FAILED(NS_NewStringInputStream(getter_AddRefs(mInputStream), stringToRead))) + return; + mStore = do_QueryInterface(mInputStream); +} + + +//======================================================================================== +// nsInputFileStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsInputFileStream::nsInputFileStream( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) +//---------------------------------------------------------------------------------------- +{ + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream(&stream, inFile, nsprMode, accessMode))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} // nsInputFileStream::nsInputFileStream + +//---------------------------------------------------------------------------------------- +nsInputFileStream::nsInputFileStream(nsIFileSpec* inSpec) +//---------------------------------------------------------------------------------------- +{ + nsIInputStream* stream; + if (NS_FAILED(inSpec->GetInputStream(&stream))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} // nsInputFileStream::nsInputFileStream + +//---------------------------------------------------------------------------------------- +nsInputFileStream::~nsInputFileStream() +//---------------------------------------------------------------------------------------- +{ +// if (is_open()) +// close(); +} + +//---------------------------------------------------------------------------------------- +void nsInputFileStream::AssignFrom(nsISupports* stream) +//---------------------------------------------------------------------------------------- +{ + mFile = do_QueryInterface(stream); + mInputStream = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mFileInputStream = do_QueryInterface(stream); +} + +//======================================================================================== +// nsOutputFileStream +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputFileStream::nsOutputFileStream(nsIFileSpec* inSpec) +//---------------------------------------------------------------------------------------- +{ + if (!inSpec) + return; + nsIOutputStream* stream; + if (NS_FAILED(inSpec->GetOutputStream(&stream))) + return; + AssignFrom(stream); + NS_RELEASE(stream); +} + +//---------------------------------------------------------------------------------------- +nsOutputFileStream::~nsOutputFileStream() +//---------------------------------------------------------------------------------------- +{ +// if (is_open()) +// close(); +} +//---------------------------------------------------------------------------------------- +void nsOutputFileStream::AssignFrom(nsISupports* stream) +//---------------------------------------------------------------------------------------- +{ + mFile = do_QueryInterface(stream); + mOutputStream = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mFileOutputStream = do_QueryInterface(stream); +} + +//---------------------------------------------------------------------------------------- +nsresult nsOutputFileStream::flush() +//---------------------------------------------------------------------------------------- +{ + if (mFileOutputStream) + mFileOutputStream->Flush(); + return error(); +} + +//---------------------------------------------------------------------------------------- +void nsOutputFileStream::abort() +//---------------------------------------------------------------------------------------- +{ + mResult = NS_FILE_FAILURE; + close(); +} + +//======================================================================================== +// Manipulators +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsOutputStream& nsEndl(nsOutputStream& os) +//---------------------------------------------------------------------------------------- +{ +#if defined(XP_WIN) || defined(XP_OS2) + os.write("\r\n", 2); +#elif defined (XP_MAC) + os.put('\r'); +#else + os.put('\n'); +#endif + //os.flush(); + return os; +} // nsEndl diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h new file mode 100644 index 00000000..b0cd5e8a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsFileStream.h @@ -0,0 +1,772 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// First checked in on 98/11/20 by John R. McMullen in the wrong directory. +// Checked in again 98/12/04. +// Polished version 98/12/08. +// Completely rewritten to integrate with nsIInputStream and nsIOutputStream (the +// xpcom stream objects. + +//======================================================================================== +// +// Classes defined: +// +// nsInputStream, nsOutputStream +// These are the lightweight STATICALLY LINKED wrappers for +// the xpcom objects nsIInputStream and nsIOutputstream. +// Possible uses: +// If you are implementing a function that accepts one of these xpcom +// streams, just make one of these little jobbies on the stack, and +// the handy << or >> notation can be yours. +// +// nsInputFileStream, nsOutputFileStream +// These are the STATICALLY LINKED wrappers for the file-related +// versions of the above. +// nsIOFileStream +// An input and output file stream attached to the same file. +// +// This suite provide the following services: +// +// 1. Encapsulates all platform-specific file details, so that file i/o +// can be done correctly without any platform #ifdefs +// +// 2. Uses NSPR file services (NOT ansi file I/O), in order to get best +// native performance. This performance difference is especially large on +// macintosh. +// +// 3. Allows all the power of the ansi stream syntax. +// +// Basic example: +// +// nsFileSpec myPath("/Development/iotest.txt"); +// +// nsOutputFileStream testStream(myPath); +// testStream << "Hello World" << nsEndl; +// +// 4. Requires streams to be constructed using typesafe nsFileSpec specifier +// (not the notorious and bug prone const char*), namely nsFileSpec. See +// nsFileSpec.h for more details. +// +// 5. Fixes a bug that have been there for a long time, and +// is inevitable if you use NSPR alone: +// +// The problem on platforms (Macintosh) in which a path does not fully +// specify a file, because two volumes can have the same name. +// +// Not yet provided: +// +// Endian-awareness for reading and writing crossplatform binary files. At this +// time there seems to be no demand for this. +// +//======================================================================================== + +#ifndef _FILESTREAM_H_ +#define _FILESTREAM_H_ + +#include "xpcomobsolete.h" +#include "nsStringFwd.h" + +#ifdef XP_MAC +#include "pprio.h" // To get PR_ImportFile +#else +#include "prio.h" +#endif + +#include "nsCOMPtr.h" +#include "nsIFileStream.h" + +// Defined elsewhere +class nsFileSpec; +class nsIInputStream; +class nsIOutputStream; +class nsIFileSpec; + +//======================================================================================== +// Compiler-specific macros, as needed +//======================================================================================== +#if !defined(NS_USING_NAMESPACE) && (defined(__MWERKS__) || defined(_MSC_VER)) +#define NS_USING_NAMESPACE +#endif + +#ifdef NS_USING_NAMESPACE + +#define NS_NAMESPACE_PROTOTYPE +#define NS_NAMESPACE namespace +#define NS_NAMESPACE_END + +#else + +#define NS_NAMESPACE_PROTOTYPE static +#define NS_NAMESPACE struct +#define NS_NAMESPACE_END ; + +#endif // NS_USING_NAMESPACE + +#if !defined(XP_MAC) && !defined(__KCC) +// PR_STDOUT and PR_STDIN are fatal on Macintosh. So for console i/o, we must use the std +// stream stuff instead. However, we have to require that cout and cin are passed in +// to the constructor because in the current build, there is a copy in the base.shlb, +// and another in the caller's file. Passing it in as a parameter ensures that the +// caller and this library are using the same global object. Groan. +// +// Unix currently does not support iostreams at all. Their compilers do not support +// ANSI C++, or even ARM C++. +// +// Windows supports them, but only if you turn on the -GX compile flag, to support +// exceptions. + +// Catch 22. +#define NS_USE_PR_STDIO +#endif + +#ifdef NS_USE_PR_STDIO +class istream; +class ostream; +#define CONSOLE_IN 0 +#define CONSOLE_OUT 0 +#else +#include +using std::istream; +using std::ostream; +#define CONSOLE_IN &std::cin +#define CONSOLE_OUT &std::cout +#endif + +//=========================== End Compiler-specific macros =============================== + +//======================================================================================== +class NS_COM_OBSOLETE nsInputStream +// This is a convenience class, for use on the STACK ("new" junkies: get detoxed first). +// Given a COM-style stream, this allows you to use the >> operators. It also acquires and +// reference counts its stream. +// Please read the comments at the top of this file +//======================================================================================== +{ +public: + nsInputStream(nsIInputStream* inStream) + : mInputStream(do_QueryInterface(inStream)) + , mEOF(PR_FALSE) + {} + virtual ~nsInputStream(); + + nsCOMPtr GetIStream() const + { + return mInputStream; + } + PRBool eof() const { return get_at_eof(); } + char get(); + nsresult close() + { + NS_ASSERTION(mInputStream, "mInputStream is null!"); + if (mInputStream) { + return mInputStream->Close(); + } + return NS_OK; + } + PRInt32 read(void* s, PRInt32 n); + + // Input streamers. Add more as needed (int&, unsigned int& etc). (but you have to + // add delegators to the derived classes, too, because these operators don't inherit). + nsInputStream& operator >> (char& ch); + + // Support manipulators + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { + return pf(*this); + } + +protected: + + // These certainly need to be overridden, they give the best shot we can at detecting + // eof in a simple nsIInputStream. + virtual void set_at_eof(PRBool atEnd) + { + mEOF = atEnd; + } + virtual PRBool get_at_eof() const + { + return mEOF; + } +private: + + nsInputStream& operator >> (char* buf); // TOO DANGEROUS. DON'T DEFINE. + + // private and unimplemented to disallow copies and assigns + nsInputStream(const nsInputStream& rhs); + nsInputStream& operator=(const nsInputStream& rhs); + +// DATA +protected: + nsCOMPtr mInputStream; + PRBool mEOF; +}; // class nsInputStream + +typedef nsInputStream nsBasicInStream; // historic support for this name + +//======================================================================================== +class NS_COM_OBSOLETE nsOutputStream +// This is a convenience class, for use on the STACK ("new" junkies, get detoxed first). +// Given a COM-style stream, this allows you to use the << operators. It also acquires and +// reference counts its stream. +// Please read the comments at the top of this file +//======================================================================================== +{ +public: + nsOutputStream() {} + nsOutputStream(nsIOutputStream* inStream) + : mOutputStream(do_QueryInterface(inStream)) + {} + + virtual ~nsOutputStream(); + + nsCOMPtr GetIStream() const + { + return mOutputStream; + } + nsresult close() + { + if (mOutputStream) + return mOutputStream->Close(); + return NS_OK; + } + void put(char c); + PRInt32 write(const void* s, PRInt32 n); + virtual nsresult flush(); + nsresult lastWriteStatus(); + + // Output streamers. Add more as needed (but you have to add delegators to the derived + // classes, too, because these operators don't inherit). + nsOutputStream& operator << (const char* buf); + nsOutputStream& operator << (char ch); + nsOutputStream& operator << (short val); + nsOutputStream& operator << (unsigned short val); + nsOutputStream& operator << (long val); + nsOutputStream& operator << (unsigned long val); + nsOutputStream& operator << (int val); + nsOutputStream& operator << (unsigned int val); + + // Support manipulators + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { + return pf(*this); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsOutputStream(const nsOutputStream& rhs); + nsOutputStream& operator=(const nsOutputStream& rhs); + + nsresult mWriteStatus; + +// DATA +protected: + nsCOMPtr mOutputStream; +}; // class nsOutputStream + +typedef nsOutputStream nsBasicOutStream; // Historic support for this name + +//======================================================================================== +class NS_COM_OBSOLETE nsErrorProne +// Common (virtual) base class for remembering errors on demand +//======================================================================================== +{ +public: + nsErrorProne() // for delayed opening + : mResult(NS_OK) + { + } + PRBool failed() const + { + return NS_FAILED(mResult); + } + nsresult error() const + { + return mResult; + } + +// DATA +protected: + nsresult mResult; +}; // class nsErrorProne + +//======================================================================================== +class NS_COM_OBSOLETE nsFileClient +// Because COM does not allow us to write functions which return a boolean value etc, +// this class is here to take care of the tedious "declare variable then call with +// the address of the variable" chores. +//======================================================================================== +: public virtual nsErrorProne +{ +public: + nsFileClient(const nsCOMPtr& inFile) + : mFile(do_QueryInterface(inFile)) + { + } + virtual ~nsFileClient() {} + + void open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) + { + if (mFile) + mResult = mFile->Open(inFile, nsprMode, accessMode); + } + PRBool is_open() const + { + PRBool result = PR_FALSE; + if (mFile) + mFile->GetIsOpen(&result); + return result; + } + PRBool is_file() const + { + return mFile ? PR_TRUE : PR_FALSE; + } + +protected: + + nsFileClient() // for delayed opening + { + } +// DATA +protected: + nsCOMPtr mFile; +}; // class nsFileClient + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessStoreClient +// Because COM does not allow us to write functions which return a boolean value etc, +// this class is here to take care of the tedious "declare variable then call with +// the address of the variable" chores. +//======================================================================================== +: public virtual nsErrorProne +{ +public: + nsRandomAccessStoreClient() // for delayed opening + { + } + nsRandomAccessStoreClient(const nsCOMPtr& inStore) + : mStore(do_QueryInterface(inStore)) + { + } + virtual ~nsRandomAccessStoreClient() {} + + void seek(PRInt64 offset) + { + seek(PR_SEEK_SET, offset); + } + + void seek(PRSeekWhence whence, PRInt64 offset) + { + set_at_eof(PR_FALSE); + if (mStore) + mResult = mStore->Seek(whence, offset); + } + PRInt64 tell() + { + PRInt64 result; + LL_I2L(result, -1); + if (mStore) + mResult = mStore->Tell(&result); + return result; + } + +protected: + + virtual PRBool get_at_eof() const + { + PRBool result = PR_TRUE; + if (mStore) + mStore->GetAtEOF(&result); + return result; + } + + virtual void set_at_eof(PRBool atEnd) + { + if (mStore) + mStore->SetAtEOF(atEnd); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessStoreClient(const nsRandomAccessStoreClient& rhs); + nsRandomAccessStoreClient& operator=(const nsRandomAccessStoreClient& rhs); + +// DATA +protected: + nsCOMPtr mStore; +}; // class nsRandomAccessStoreClient + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessInputStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessStoreClient +, public nsInputStream +{ +public: + nsRandomAccessInputStream(nsIInputStream* inStream) + : nsRandomAccessStoreClient(do_QueryInterface(inStream)) + , nsInputStream(inStream) + { + } + PRBool readline(char* s, PRInt32 n); + // Result always null-terminated. + // Check eof() before each call. + // CAUTION: false result only indicates line was truncated + // to fit buffer, or an error occurred (OTHER THAN eof). + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + +protected: + nsRandomAccessInputStream() + : nsInputStream(nsnull) + { + } + + virtual PRBool get_at_eof() const + { + return nsRandomAccessStoreClient::get_at_eof(); + } + + virtual void set_at_eof(PRBool atEnd) + { + nsRandomAccessStoreClient::set_at_eof(atEnd); + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessInputStream(const nsRandomAccessInputStream& rhs); + nsRandomAccessInputStream& operator=(const nsRandomAccessInputStream& rhs); + +}; // class nsRandomAccessInputStream + +//======================================================================================== +class NS_COM_OBSOLETE nsInputStringStream +//======================================================================================== +: public nsRandomAccessInputStream +{ +public: + nsInputStringStream(const char* stringToRead); + nsInputStringStream(const nsString& stringToRead); + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + + +private: + + // private and unimplemented to disallow copies and assigns + nsInputStringStream(const nsInputStringStream& rhs); + nsInputStringStream& operator=(const nsInputStringStream& rhs); + + +}; // class nsInputStringStream + +//======================================================================================== +class NS_COM_OBSOLETE nsInputFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessInputStream +, public nsFileClient +{ +public: + enum { kDefaultMode = PR_RDONLY }; + nsInputFileStream(nsIInputStream* inStream) + : nsRandomAccessInputStream(inStream) + , nsFileClient(do_QueryInterface(inStream)) + , mFileInputStream(do_QueryInterface(inStream)) + { + } + nsInputFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666); + nsInputFileStream(nsIFileSpec* inFile); + virtual ~nsInputFileStream(); + + void Open( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + { + if (mFile) + mFile->Open(inFile, nsprMode, accessMode); + } + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + +protected: + void AssignFrom(nsISupports* stream); + +private: + + // private and unimplemented to disallow copies and assigns + nsInputFileStream(const nsInputFileStream& rhs); + nsInputFileStream& operator=(const nsInputFileStream& rhs); + +// DATA +protected: + nsCOMPtr mFileInputStream; +}; // class nsInputFileStream + +//======================================================================================== +class NS_COM_OBSOLETE nsRandomAccessOutputStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessStoreClient +, public nsOutputStream +{ +public: + nsRandomAccessOutputStream(nsIOutputStream* inStream) + : nsRandomAccessStoreClient(do_QueryInterface(inStream)) + , nsOutputStream(inStream) + { + } + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + +protected: + nsRandomAccessOutputStream() + : nsOutputStream(nsnull) + { + } + +private: + + // private and unimplemented to disallow copies and assigns + nsRandomAccessOutputStream(const nsRandomAccessOutputStream& rhs); + nsRandomAccessOutputStream& operator=(const nsRandomAccessOutputStream& rhs); + +}; // class nsRandomAccessOutputStream + +//======================================================================================== +class NS_COM_OBSOLETE nsOutputFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsRandomAccessOutputStream +, public nsFileClient +{ +public: + enum { kDefaultMode = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE) }; + + nsOutputFileStream() {} + nsOutputFileStream(nsIOutputStream* inStream) + { + AssignFrom(inStream); + } + nsOutputFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + { + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream( + &stream, + inFile, nsprMode, accessMode))) + return; + AssignFrom(stream); + NS_RELEASE(stream); + } + nsOutputFileStream(nsIFileSpec* inFile); + virtual ~nsOutputFileStream(); + + virtual nsresult flush(); + virtual void abort(); + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + +protected: + void AssignFrom(nsISupports* stream); + +private: + + // private and unimplemented to disallow copies and assigns + nsOutputFileStream(const nsOutputFileStream& rhs); + nsOutputFileStream& operator=(const nsOutputFileStream& rhs); + +// DATA +protected: + nsCOMPtr mFileOutputStream; +}; // class nsOutputFileStream + + +//======================================================================================== +class nsIOFileStream +// Please read the comments at the top of this file +//======================================================================================== +: public nsInputFileStream +, public nsOutputStream +{ +public: + enum { kDefaultMode = (PR_RDWR | PR_CREATE_FILE) }; + + nsIOFileStream( + nsIInputStream* inInputStream + , nsIOutputStream* inOutputStream) + : nsInputFileStream(inInputStream) + , nsOutputStream(inOutputStream) + , mFileOutputStream(do_QueryInterface(inOutputStream)) + { + } + nsIOFileStream( + const nsFileSpec& inFile, + int nsprMode = kDefaultMode, + PRIntn accessMode = 00666) + : nsInputFileStream((nsIInputStream*)nsnull) + , nsOutputStream(nsnull) + { + nsISupports* stream; + if (NS_FAILED(NS_NewIOFileStream( + &stream, + inFile, nsprMode, accessMode))) + return; + mFile = do_QueryInterface(stream); + mStore = do_QueryInterface(stream); + mInputStream = do_QueryInterface(stream); + mOutputStream = do_QueryInterface(stream); + mFileInputStream = do_QueryInterface(stream); + mFileOutputStream = do_QueryInterface(stream); + NS_RELEASE(stream); + } + + virtual nsresult close() + { + // Doesn't matter which of the two we close: + // they're hooked up to the same file. + return nsInputFileStream::close(); + } + + // Output streamers. Unfortunately, they don't inherit! + nsOutputStream& operator << (const char* buf) + { return nsOutputStream::operator << (buf); } + nsOutputStream& operator << (char ch) + { return nsOutputStream::operator << (ch); } + nsOutputStream& operator << (short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned short val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned long val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (unsigned int val) + { return nsOutputStream::operator << (val); } + nsOutputStream& operator << (nsOutputStream& (*pf)(nsOutputStream&)) + { return nsOutputStream::operator << (pf); } + + // Input streamers. Unfortunately, they don't inherit! + nsInputStream& operator >> (char& ch) + { return nsInputStream::operator >>(ch); } + nsInputStream& operator >> (nsInputStream& (*pf)(nsInputStream&)) + { return nsInputStream::operator >>(pf); } + + virtual nsresult flush() {if (mFileOutputStream) mFileOutputStream->Flush(); return error(); } + + +private: + + // private and unimplemented to disallow copies and assigns + nsIOFileStream(const nsIOFileStream& rhs); + nsIOFileStream& operator=(const nsIOFileStream& rhs); + + // DATA +protected: + nsCOMPtr mFileOutputStream; +}; // class nsIOFileStream + +//======================================================================================== +// Manipulators +//======================================================================================== + +NS_COM_OBSOLETE nsOutputStream& nsEndl(nsOutputStream& os); // outputs and FLUSHES. + +//======================================================================================== +#endif /* _FILESTREAM_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl new file mode 100644 index 00000000..78abd9e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileSpec.idl @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 INTERFACE IS DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +// This is the only correct cross-platform way to specify a file. +// Strings are not such a way. If you grew up on windows or unix, you +// may think they are. Welcome to reality. + +#include "nsISupports.idl" + +%{C++ +#include "nsFileSpec.h" // for factory method +%} + +interface nsIFileURL; +interface nsIFilePath; +interface nsIOutputStream; +interface nsIInputStream; + +// Define Contractid and CID +%{C++ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + THIS INTERFACE IS DEPRECATED AND UNSUPPORTED! USE |nsIFile| and |nsILocalFile|. + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// {A5740FA2-146E-11d3-B00D-00C04FC2E79B} +#define NS_FILESPEC_CID \ +{ 0xa5740fa2, 0x146e, 0x11d3, { 0xb0, 0xd, 0x0, 0xc0, 0x4f, 0xc2, 0xe7, 0x9b } } + +#define NS_FILESPEC_CONTRACTID "@mozilla.org/filespec;1" +#define NS_FILESPEC_CLASSNAME "File Spec" + +%} + + native nsFileSpec(nsFileSpec); +[ref] native nsFileSpecRef(nsFileSpec); +[ptr] native nsFileSpecPtr(nsFileSpec); + +[scriptable, uuid(d8c0a080-0868-11d3-915f-d9d889d48e3c)] +interface nsIFileSpec : nsISupports +{ + void fromFileSpec([const] in nsIFileSpec original); + + attribute string URLString; + attribute string unixStyleFilePath; + attribute string persistentDescriptorString; + attribute string nativePath; + + readonly attribute string NSPRPath; + + void error(); + + boolean isValid(); + boolean failed(); + + attribute string leafName; + + readonly attribute nsIFileSpec parent; + readonly attribute nsIInputStream inputStream; + readonly attribute nsIOutputStream outputStream; + boolean isChildOf(in nsIFileSpec possibleParent); + [noscript] readonly attribute nsFileSpec fileSpec; + [noscript] void setFromFileSpec([const] in nsFileSpecRef spec); + + attribute string fileContents; + + void makeUnique(); + void makeUniqueWithSuggestedName(in string suggestedName); + + readonly attribute unsigned long modDate; + boolean modDateChanged(in unsigned long oldStamp); + + boolean isDirectory(); + boolean isFile(); + boolean exists(); + boolean isHidden(); + + boolean equals(in nsIFileSpec spec); + + readonly attribute unsigned long fileSize; + readonly attribute long long diskSpaceAvailable; + + void appendRelativeUnixPath(in string relativePath); + + void createDir(); + void touch(); + + boolean isSymlink(); + void resolveSymlink(); + + void delete(in boolean recursive); + void truncate(in long aNewLength); + void rename([const] in string newLeafName); + void copyToDir([const] in nsIFileSpec newParentDir); + void moveToDir([const] in nsIFileSpec newParentDir); + void execute([const] in string args); + + void openStreamForReading(); + void openStreamForWriting(); + void openStreamForReadingAndWriting(); + void closeStream(); + boolean isStreamOpen(); + + boolean eof(); + long read(inout string buffer, in long requestedCount); + void readLine(inout string line, in long bufferSize, out boolean wasTruncated); + + /** Check eof() before each call. + * CAUTION: false result only indicates line was truncated + * to fit buffer, or an error occurred (OTHER THAN eof). + */ + long write(in string data, in long requestedCount); + void flush(); + + void seek(in long offset); + long tell(); + void endLine(); + attribute AString unicodePath; + +}; + +// Define Contractid and CID +%{C++ +// {a3020981-2018-11d3-915f-a957795b7ebc} +#define NS_DIRECTORYITERATOR_CID \ +{ 0xa3020981, 0x2018, 0x11d3, { 0x91, 0x5f, 0xa9, 0x57, 0x79, 0x5b, 0x7e, 0xbc } } + +#define NS_DIRECTORYITERATOR_CONTRACTID "@mozilla.org/directoryiterator;1" +#define NS_DIRECTORYITERATOR_CLASSNAME "nsIDirectoryIterator" +%} + +[scriptable, uuid(d8c0a083-0868-11d3-915f-d9d889d48e3c)] +interface nsIDirectoryIterator : nsISupports +{ + void init(in nsIFileSpec parent, in boolean resolveSymlink); + boolean exists(); + void next(); + readonly attribute nsIFileSpec currentSpec; +}; + +%{C++ +// Factory methods if you link with xpcom +NS_COM_OBSOLETE nsresult NS_NewFileSpecWithSpec(const nsFileSpec& aSrcFileSpec, nsIFileSpec **result); +NS_COM_OBSOLETE nsresult NS_NewFileSpec(nsIFileSpec** result); +NS_COM_OBSOLETE nsresult NS_NewDirectoryIterator(nsIDirectoryIterator** result); + +// Convert from nsIFile to nsIFileSpec +// +// XXX This function is here only to assist with the migration from nsIFileSpec +// to nsIFile. This function will dissappear in future mozilla releases. +// +// ...ripped from nsPrefService.cpp: +// +// "So discouraged is the use of nsIFileSpec, nobody wanted to have this routine be +// public - It might lead to continued use of nsIFileSpec. Right now, [mozilla] has +// such a need for it, here it is. Let's stop having to use it though." +// +NS_COM_OBSOLETE nsresult NS_NewFileSpecFromIFile(nsIFile *aFile, nsIFileSpec **result); + +#define NS_BOOL_ACCESSOR(_method) { PRBool yes; return NS_SUCCEEDED(f->_method(&yes)) && yes; } +inline PRBool Exists(nsIFileSpec* f) NS_BOOL_ACCESSOR(Exists) +inline PRBool Exists(nsIDirectoryIterator* f) NS_BOOL_ACCESSOR(Exists) +inline PRBool IsDirectory(nsIFileSpec* f) NS_BOOL_ACCESSOR(IsDirectory) + +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp new file mode 100644 index 00000000..011bcdaa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.cpp @@ -0,0 +1,727 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIFileStream.h" +#include "nsFileSpec.h" +#include "nsCOMPtr.h" + +#include "prerror.h" + +#include "nsSegmentedBuffer.h" +#include "nsInt64.h" + +#ifdef XP_MAC +#include "pprio.h" // To get PR_ImportFile +#else +#include "prio.h" +#endif + +#ifdef XP_MAC +#include +#include +#endif + +//======================================================================================== +class FileImpl + : public nsIRandomAccessStore + , public nsIFileSpecOutputStream + , public nsIFileSpecInputStream + , public nsIOpenFile +//======================================================================================== +{ + public: + FileImpl(PRFileDesc* inDesc); + FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode); + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIOpenFile interface + NS_IMETHOD Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode); + NS_IMETHOD Close(); + NS_IMETHOD GetIsOpen(PRBool* outOpen); + + // nsIInputStream interface + NS_IMETHOD Available(PRUint32 *aLength); + NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount); + NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD IsNonBlocking(PRBool *aNonBlocking); + + // nsIOutputStream interface + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + NS_IMETHOD Flush(); + NS_IMETHOD WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval); + NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval); + + // nsIRandomAccessStore interface + NS_DECL_NSISEEKABLESTREAM + NS_IMETHOD GetAtEOF(PRBool* outAtEOF); + NS_IMETHOD SetAtEOF(PRBool inAtEOF); + + private: + + ~FileImpl(); + + protected: + + enum { + kOuputBufferSegmentSize = 4096, + kOuputBufferMaxSize = 4096 + }; + + nsresult InternalFlush(PRBool syncFile); + nsresult AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize); + + PRFileDesc* mFileDesc; + int mNSPRMode; + PRBool mFailed; + PRBool mEOF; + PRInt32 mLength; + + PRBool mGotBuffers; + nsSegmentedBuffer mOutBuffer; + char* mWriteCursor; + char* mWriteLimit; + +}; // class FileImpl + +NS_IMPL_RELEASE(FileImpl) +NS_IMPL_ADDREF(FileImpl) + +NS_IMPL_QUERY_HEAD(FileImpl) + NS_IMPL_QUERY_BODY(nsIOpenFile) + NS_IMPL_QUERY_BODY(nsISeekableStream) + NS_IMPL_QUERY_BODY(nsIRandomAccessStore) + NS_IMPL_QUERY_BODY(nsIOutputStream) + NS_IMPL_QUERY_BODY(nsIInputStream) + NS_IMPL_QUERY_BODY(nsIFileSpecInputStream) + NS_IMPL_QUERY_BODY(nsIFileSpecOutputStream) +NS_IMPL_QUERY_TAIL(nsIOutputStream) + + +//---------------------------------------------------------------------------------------- +FileImpl::FileImpl(PRFileDesc* inDesc) +//---------------------------------------------------------------------------------------- +: mFileDesc(inDesc) +, mNSPRMode(0) +, mFailed(PR_FALSE) +, mEOF(PR_FALSE) +, mLength(-1) +, mGotBuffers(PR_FALSE) +{ + mWriteCursor = nsnull; + mWriteLimit = nsnull; +} + + +//---------------------------------------------------------------------------------------- +FileImpl::FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode) +//---------------------------------------------------------------------------------------- +: mFileDesc(nsnull) +, mNSPRMode(-1) +, mEOF(PR_FALSE) +, mLength(-1) +, mGotBuffers(PR_FALSE) +{ + mWriteCursor = nsnull; + mWriteLimit = nsnull; + + nsresult rv = Open(inFile, nsprMode, accessMode); // this sets nsprMode + + if (NS_FAILED(rv)) + { + mFailed = PR_TRUE; +#if DEBUG + char *fileName = inFile.GetLeafName(); + printf("Opening file %s failed\n", fileName); + nsCRT::free(fileName); +#endif + } + else + { + mFailed = PR_FALSE; + } +} + +//---------------------------------------------------------------------------------------- +FileImpl::~FileImpl() +//---------------------------------------------------------------------------------------- +{ + nsresult rv = Close(); + NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed"); +} + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc) + if ((nsprMode & mNSPRMode) == nsprMode) + return NS_OK; + else + return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR); + + const int nspr_modes[]={ + PR_WRONLY | PR_CREATE_FILE, + PR_WRONLY | PR_CREATE_FILE | PR_APPEND, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + PR_RDONLY, + PR_RDONLY | PR_APPEND, + PR_RDWR | PR_CREATE_FILE, + PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, +// "wb", +// "ab", +// "wb", +// "rb", +// "r+b", +// "w+b", + 0 }; + const int* currentLegalMode = nspr_modes; + while (*currentLegalMode && nsprMode != *currentLegalMode) + ++currentLegalMode; + if (!*currentLegalMode) + return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR); + +#ifdef XP_MAC + // Use the file spec to open the file, because one path can be common to + // several files on the Macintosh (you can have several volumes with the + // same name, see). + mFileDesc = 0; + OSErr err = inFile.Error(); + if (err != noErr) + if (err != fnfErr || !(nsprMode & PR_CREATE_FILE)) + return NS_FILE_RESULT(inFile.Error()); + err = noErr; +#if DEBUG + const OSType kCreator = 'CWIE'; +#else + const OSType kCreator = 'MOSS'; +#endif + // Resolve the alias to the original file. + nsFileSpec original = inFile; + PRBool ignoredResult; + original.ResolveSymlink(ignoredResult); + const FSSpec& spec = original.operator const FSSpec&(); + if (nsprMode & PR_CREATE_FILE) { + // In order to get the right file type/creator, do it with an nsILocalFileMac + // Don't propagate any errors in doing this. If any error, just use FSpCreate. + FSSpec nonConstSpec = spec; + nsCOMPtr macFile; + nsresult res = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_FALSE, getter_AddRefs(macFile)); + if (NS_SUCCEEDED(res)) { + nsCOMPtr asFile(do_QueryInterface(macFile, &res)); + if (NS_SUCCEEDED(res)) { + res = asFile->Create(nsIFile::NORMAL_FILE_TYPE, 0); + if (res == NS_ERROR_FILE_ALREADY_EXISTS) + res = NS_OK; + } + } + if (NS_FAILED(res)) + err = FSpCreate(&spec, kCreator, 'TEXT', 0); + } + + if (err == dupFNErr) + err = noErr; + if (err != noErr) + return NS_FILE_RESULT(err); + + SInt8 perm; + if (nsprMode & PR_RDWR) + perm = fsRdWrPerm; + else if (nsprMode & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + + short refnum; + err = FSpOpenDF(&spec, perm, &refnum); + + if (err == noErr && (nsprMode & PR_TRUNCATE)) + err = ::SetEOF(refnum, 0); + if (err == noErr && (nsprMode & PR_APPEND)) + err = SetFPos(refnum, fsFromLEOF, 0); + if (err != noErr) + return NS_FILE_RESULT(err); + + if ((mFileDesc = PR_ImportFile(refnum)) == 0) + return NS_FILE_RESULT(PR_GetError()); +#else + // Platforms other than Macintosh... + // Another bug in NSPR: Mac PR_Open assumes a unix style path, but Win PR_Open assumes + // a windows path. + if ((mFileDesc = PR_Open((const char*)nsFileSpec(inFile), nsprMode, accessMode)) == 0) + return NS_FILE_RESULT(PR_GetError()); +#endif + mNSPRMode = nsprMode; + mLength = PR_Available(mFileDesc); + return NS_OK; +} // FileImpl::Open + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Available(PRUint32 *aLength) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aLength != nsnull, "null ptr"); + if (!aLength) + return NS_ERROR_NULL_POINTER; + if (mLength < 0) + return NS_ERROR_UNEXPECTED; + *aLength = mLength; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::GetIsOpen(PRBool* outOpen) +//---------------------------------------------------------------------------------------- +{ + *outOpen = (mFileDesc != nsnull && !mFailed); + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Seek(PRInt32 whence, PRInt64 offset) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + mFailed = PR_FALSE; // reset on a seek. + mEOF = PR_FALSE; // reset on a seek. + + // To avoid corruption, we flush during a seek. see bug number 18949 + InternalFlush(PR_FALSE); + + nsInt64 position = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR); + nsInt64 available = PR_Available64(mFileDesc); + nsInt64 fileSize = position + available; + nsInt64 newPosition = offset; + switch (whence) + { + case NS_SEEK_CUR: newPosition += position; break; + case NS_SEEK_SET: ; break; + case NS_SEEK_END: newPosition += fileSize; break; + } + const nsInt64 zero = 0; + if (newPosition < zero) + { + newPosition = 0; + mFailed = PR_TRUE; + } + if (newPosition >= fileSize) // nb: not "else if". + { + newPosition = fileSize; + mEOF = PR_TRUE; + } + if (PR_Seek64(mFileDesc, newPosition, PR_SEEK_SET) < 0) + mFailed = PR_TRUE; + return NS_OK; +} // FileImpl::Seek + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + if (!aBuf) + return NS_ERROR_NULL_POINTER; + NS_PRECONDITION(aReadCount != nsnull, "null ptr"); + if (!aReadCount) + return NS_ERROR_NULL_POINTER; + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + if (mFailed) + return NS_ERROR_FAILURE; + PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount); + if (bytesRead < 0) + { + *aReadCount = 0; + mFailed = PR_TRUE; + return NS_FILE_RESULT(PR_GetError()); + } + else if (bytesRead == 0) + { + mEOF = PR_TRUE; + } + *aReadCount = bytesRead; + return NS_OK; +} + +NS_IMETHODIMP +FileImpl::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval) +{ + NS_NOTREACHED("ReadSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aBuf != nsnull, "null ptr"); + NS_PRECONDITION(aWriteCount != nsnull, "null ptr"); + + *aWriteCount = 0; + +#ifdef XP_MAC + // Calling PR_Write on stdout is sure suicide. + if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR) + { + std::cout.write(aBuf, aCount); + *aWriteCount = aCount; + return NS_OK; + } +#endif + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + if (mFailed) + return NS_ERROR_FAILURE; + + if (!mGotBuffers) + { + nsresult rv = AllocateBuffers(kOuputBufferSegmentSize, kOuputBufferMaxSize); + if (NS_FAILED(rv)) + return rv; // try to write non-buffered? + } + + PRUint32 bufOffset = 0; + PRUint32 currentWrite = 0; + while (aCount > 0) + { + if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit) + { + char* seg = mOutBuffer.AppendNewSegment(); + if (seg == nsnull) + { + // buffer is full, try again + InternalFlush(PR_FALSE); + seg = mOutBuffer.AppendNewSegment(); + if (seg == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + mWriteCursor = seg; + mWriteLimit = seg + mOutBuffer.GetSegmentSize(); + } + + // move + currentWrite = mWriteLimit - mWriteCursor; + + if (aCount < currentWrite) + currentWrite = aCount; + + memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite); + + mWriteCursor += currentWrite; + + aCount -= currentWrite; + bufOffset += currentWrite; + *aWriteCount += currentWrite; + } + + return NS_OK; +} + +static NS_METHOD +nsWriteSegmentToFile(nsIInputStream* in, + void* closure, + const char* fromRawSegment, + PRUint32 toOffset, + PRUint32 count, + PRUint32 *writeCount) +{ + NS_NOTREACHED("nsWriteSegmentToFile"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +FileImpl::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result) +{ + return inStr->ReadSegments(nsWriteSegmentToFile, nsnull, count, result); +} + +NS_IMETHODIMP +FileImpl::WriteSegments(nsReadSegmentFun reader, void * closure, + PRUint32 count, PRUint32 *result) +{ + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +FileImpl::IsNonBlocking(PRBool *aNonBlocking) +{ + *aNonBlocking = PR_FALSE; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Tell(PRInt64* outWhere) +//---------------------------------------------------------------------------------------- +{ + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + *outWhere = PR_Seek64(mFileDesc, 0, PR_SEEK_CUR); + return NS_OK; +} // FileImpl::Tell + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Close() +//---------------------------------------------------------------------------------------- +{ + if ((mNSPRMode & PR_RDONLY) == 0) + InternalFlush(PR_FALSE); + + if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc) + return NS_OK; + if (PR_Close(mFileDesc) == PR_SUCCESS) + mFileDesc = 0; + else + return NS_FILE_RESULT(PR_GetError()); + return NS_OK; +} // FileImpl::close + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::Flush() +//---------------------------------------------------------------------------------------- +{ + // for external callers, this will do a Sync as well as flush buffers. + return InternalFlush(PR_TRUE); +} // FileImpl::flush + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::GetAtEOF(PRBool* outAtEOF) +//---------------------------------------------------------------------------------------- +{ + *outAtEOF = mEOF; + return NS_OK; +} + + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::SetAtEOF(PRBool inAtEOF) +//---------------------------------------------------------------------------------------- +{ + mEOF = inAtEOF; + return NS_OK; +} + +//---------------------------------------------------------------------------------------- +NS_IMETHODIMP FileImpl::SetEOF() +//---------------------------------------------------------------------------------------- +{ + NS_NOTYETIMPLEMENTED("FileImpl::SetEOF"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +//---------------------------------------------------------------------------------------- +nsresult FileImpl::AllocateBuffers(PRUint32 segmentSize, PRUint32 maxBufSize) +//---------------------------------------------------------------------------------------- +{ + nsresult rv = mOutBuffer.Init(segmentSize, maxBufSize); + if (NS_SUCCEEDED(rv)) + mGotBuffers = PR_TRUE; + + return rv; +} + +// external callers of Flush will have sync get called, +// but internal callers just want to flush the buffers to disk. +nsresult FileImpl::InternalFlush(PRBool syncFile) +{ +#ifdef XP_MAC + if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR) + { + std::cout.flush(); + return NS_OK; + } +#endif + if (!mFileDesc) + return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR); + + PRInt32 segCount = mOutBuffer.GetSegmentCount(); + PRUint32 segSize = mOutBuffer.GetSegmentSize(); + + for (PRInt32 i = 0; i < segCount; i++) + { + char* seg = mOutBuffer.GetSegment(i); + + // if it is the last buffer, it may not be completely full. + if(i == (segCount-1)) + segSize = (mWriteCursor - seg); + + PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize); + if (bytesWrit != (PRInt32)segSize) + { + mFailed = PR_TRUE; + return NS_FILE_RESULT(PR_GetError()); + } + } + + if (mGotBuffers) + mOutBuffer.Empty(); + mWriteCursor = nsnull; + mWriteLimit = nsnull; + + // On unix, it seems to fail always. + if (syncFile && PR_Sync(mFileDesc) != PR_SUCCESS) + mFailed = PR_TRUE; + + return NS_OK; +} +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalInputFileStream( + nsISupports** aResult, + const nsFileSpec& inFile + /*Default nsprMode == PR_RDONLY*/ + /*Default accessmode = 0666 (octal)*/) +// Factory method to get an nsInputStream from a file, using most common options +//---------------------------------------------------------------------------------------- +{ + // This QueryInterface was needed because NS_NewIOFileStream + // does a cast from (void *) to (nsISupports *) thus causing a + // vtable problem on Windows, where we really didn't have the proper pointer + // to an nsIInputStream, this ensures that we do + nsISupports * supports; + nsIInputStream * inStr; + + nsresult rv = NS_NewIOFileStream(&supports, inFile, PR_RDONLY, 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inStr))) { + *aResult = inStr; + } + NS_RELEASE(supports); + } + return rv; +} + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalOutputFileStream( + nsISupports** aResult, + const nsFileSpec& inFile + /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/ + /*Default accessMode= 0666 (octal)*/) +// Factory method to get an nsOutputStream to a file - most common case. +//---------------------------------------------------------------------------------------- +{ + // This QueryInterface was needed because NS_NewIOFileStream + // does a cast from (void *) to (nsISupports *) thus causing a + // vtable problem on Windows, where we really didn't have the proper pointer + // to an nsIOutputStream, this ensures that we do +#if 1 +/* nsISupports * supports; + nsIOutputStream * outStr; + + nsresult rv = NS_NewIOFileStream( + &supports, + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) { + *aResult = outStr; + } + NS_RELEASE(supports); + } + return rv; + */ + + nsCOMPtr supports; + nsIOutputStream * outStr; + + nsresult rv = NS_NewIOFileStream( + getter_AddRefs(supports), + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); + + *aResult = nsnull; + if (NS_SUCCEEDED(rv)) { + if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) { + *aResult = outStr; + } + } + return rv; +#else + return NS_NewIOFileStream( + aResult, + inFile, + (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE), + 0666); +#endif +} + +//---------------------------------------------------------------------------------------- +NS_COM_OBSOLETE nsresult NS_NewIOFileStream( + nsISupports** aResult, + const nsFileSpec& inFile, + PRInt32 nsprMode /*default = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/, + PRInt32 accessMode /*Default = 0666 (octal)*/) + // Factory method to get an object that implements both nsIInputStream + // and nsIOutputStream, associated with a file. +//---------------------------------------------------------------------------------------- +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + FileImpl* stream = new FileImpl(inFile, nsprMode, accessMode); + if (! stream) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(stream); + PRBool isOpened = PR_FALSE; + stream->GetIsOpen(&isOpened); + if (!isOpened) + { + NS_RELEASE(stream); + return NS_ERROR_FAILURE; + } + + *aResult = (nsISupports*)(void*)stream; + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h new file mode 100644 index 00000000..251b3ffc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIFileStream.h @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsIFileStream_h___ +#define nsIFileStream_h___ + +#include "xpcomobsolete.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsISeekableStream.h" +#include "prio.h" + +class nsFileSpec; + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IOPENFILE_IID \ +{ 0xa6cf90e8, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIOpenFile +// Represents a file, and supports Open. +//======================================================================================== +: public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IOPENFILE_IID) + + NS_IMETHOD Open( + const nsFileSpec& inFile, + int nsprMode, + PRIntn accessMode) = 0; + // Note: Open() is only needed after + // an explicit Close(). All file streams + // are automatically opened on construction. + NS_IMETHOD GetIsOpen(PRBool* outOpen) = 0; + +}; // class nsIOpenFile + +/* a6cf90e8-15b3-11d2-932e-00805f8add32 */ +#define NS_IRANDOMACCESS_IID \ +{ 0xa6cf90eb, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIRandomAccessStore +// Supports Seek, Tell etc. +//======================================================================================== +: public nsISeekableStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IRANDOMACCESS_IID) + +/* "PROTECTED" */ + NS_IMETHOD GetAtEOF(PRBool* outAtEOF) = 0; + NS_IMETHOD SetAtEOF(PRBool inAtEOF) = 0; +}; // class nsIRandomAccessStore + + +#ifndef NO_XPCOM_FILE_STREAMS // hack to work around duplicate class definitions in here + // and mozilla/netwerks/base/nsIFileStreams.idl + +/* a6cf90e6-15b3-11d2-932e-00805f8add32 */ +#define NS_IFILESPECINPUTSTREAM_IID \ +{ 0xa6cf90e6, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIFileSpecInputStream +// These are additional file-specific methods that files have, above what +// nsIInputStream supports. The current implementation supports both +// interfaces. +//======================================================================================== +: public nsIInputStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILESPECINPUTSTREAM_IID) +}; // class nsIFileSpecInputStream + +/* a6cf90e7-15b3-11d2-932e-00805f8add32 */ +#define NS_IFILESPECOUTPUTSTREAM_IID \ +{ 0xa6cf90e7, 0x15b3, 0x11d2, \ + {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + +//======================================================================================== +class nsIFileSpecOutputStream +// These are additional file-specific methods that files have, above what +// nsIOutputStream supports. The current implementation supports both +// interfaces. +//======================================================================================== +: public nsIOutputStream +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFILESPECOUTPUTSTREAM_IID) +}; // class nsIFileSpecOutputStream + +#endif // NO_XPCOM_FILE_STREAMS + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalInputFileStream( + nsISupports** aStreamResult, + const nsFileSpec& inFile + /*Default nsprMode == PR_RDONLY*/ + /*Default accessmode = 0700 (octal)*/); +// Factory method to get an nsInputStream from a file, using most common options + +//---------------------------------------------------------------------------------------- +nsresult NS_NewTypicalOutputFileStream( + nsISupports** aStreamResult, // will implement all the above interfaces + const nsFileSpec& inFile + /*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/ + /*Default accessMode= 0700 (octal)*/); + // Factory method to get an nsOutputStream to a file - most common case. + +//---------------------------------------------------------------------------------------- +extern "C" NS_COM_OBSOLETE nsresult NS_NewIOFileStream( + nsISupports** aStreamResult, // will implement all the above interfaces + const nsFileSpec& inFile, + PRInt32 nsprMode, + PRInt32 accessMode); + // Factory method to get an object that implements both nsIInputStream + // and nsIOutputStream, associated with a single file. + +#endif /* nsIFileSpecStream_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl new file mode 100644 index 00000000..bc9990e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistry.idl @@ -0,0 +1,186 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEnumerator.idl" + +interface nsIFile; + +typedef PRUint32 nsRegistryKey; +typedef long nsWellKnownRegistry; + +[scriptable,uuid(5D41A440-8E37-11d2-8059-00600811A9C3)] +interface nsIRegistry : nsISupports +{ + const long None = 0; + const long Users = 1; + const long Common = 2; + const long CurrentUser = 3; + + const long ApplicationComponentRegistry = 1; + const long ApplicationRegistry = 2; + + // Dont use this one. This for internal use only. + const long ApplicationCustomRegistry = -1; + + void open(in nsIFile regFile); + void openWellKnownRegistry(in nsWellKnownRegistry regid); + + void flush(); + boolean isOpen(); + + nsRegistryKey addKey(in nsRegistryKey baseKey, in wstring keyname); + nsRegistryKey getKey(in nsRegistryKey baseKey, in wstring keyname); + void removeKey(in nsRegistryKey baseKey, in wstring keyname); + + wstring getString(in nsRegistryKey baseKey, in wstring valname); + void setString(in nsRegistryKey baseKey, in wstring valname, in wstring value); + + string getStringUTF8(in nsRegistryKey baseKey, in string path); + void setStringUTF8(in nsRegistryKey baseKey, in string path, in string value); + + void getBytesUTF8(in nsRegistryKey baseKey, in string path, out PRUint32 length, [retval, array, size_is(length)] out PRUint8 valueArray); + void setBytesUTF8(in nsRegistryKey baseKey, in string path, in PRUint32 length, [array, size_is(length)] in PRUint8 valueArray); + PRInt32 getInt(in nsRegistryKey baseKey, in string path); + void setInt(in nsRegistryKey baseKey, in string path, in PRInt32 value); + PRInt64 getLongLong(in nsRegistryKey baseKey, in string path); + void setLongLong(in nsRegistryKey baseKey, in string path, inout PRInt64 value); + + /** + * addSubtree() and friends need to be renamed to addKeyUTF8(). + * If you are using these forms make sure you pass UTF8 data + */ + nsRegistryKey addSubtree(in nsRegistryKey baseKey, in string path); + void removeSubtree(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtree(in nsRegistryKey baseKey, in string path); + + nsRegistryKey addSubtreeRaw(in nsRegistryKey baseKey, in string path); + void removeSubtreeRaw(in nsRegistryKey baseKey, in string path); + nsRegistryKey getSubtreeRaw(in nsRegistryKey baseKey, in string path); + + nsIEnumerator enumerateSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateAllSubtrees(in nsRegistryKey baseKey); + nsIEnumerator enumerateValues(in nsRegistryKey baseKey); + + const unsigned long String = 1; + const unsigned long Int32 = 2; + const unsigned long Bytes = 3; + const unsigned long File = 4; + + unsigned long getValueType(in nsRegistryKey baseKey, in string path); + PRUint32 getValueLength(in nsRegistryKey baseKey, in string path); + void deleteValue(in nsRegistryKey baseKey, in string path); + + /** + * escapeKey() takes arbitrary binary data and converts it into + * valid ASCII which can be used as registry key or value names + */ + void escapeKey([array, size_is(length)] in PRUint8 key, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 escaped); + void unescapeKey([array, size_is(length)] in PRUint8 escaped, in PRUint32 terminator, inout PRUint32 length, [retval, array, size_is(length)] out PRUint8 key); + + attribute string currentUserName; + + void pack(); +}; + +[scriptable, uuid(8cecf236-1dd2-11b2-893c-f9848956eaec)] +interface nsIRegistryEnumerator : nsIEnumerator +{ + void currentItemInPlaceUTF8(out nsRegistryKey key, + [shared, retval] out string item); +}; + +[scriptable, uuid(D1B54831-AC07-11d2-805E-00600811A9C3)] +interface nsIRegistryNode : nsISupports +{ + readonly attribute string nameUTF8; + readonly attribute wstring name; + readonly attribute nsRegistryKey key; +}; + +[scriptable,uuid(5316C380-B2F8-11d2-A374-0080C6F80E4B)] +interface nsIRegistryValue : nsISupports +{ + readonly attribute wstring name; + readonly attribute string nameUTF8; + readonly attribute unsigned long type; + readonly attribute PRUint32 length; +}; + +[uuid(3A15FC88-7A61-4Ab4-8E58-31E95fAB3DA8)] +/** + * It sucks that nsIRegistry has to always allocate and return + * strings. nsIRegistryGetter adds in interfaces for non allocating getters + * to registry values. + */ +interface nsIRegistryGetter : nsISupports +{ + /** + * Get a string value of attribute valname in widestring or utf8 format + * + * @return + * NS_OK on success. + * buf has the string value copied into it. length is NOT changed. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in chars including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various failure codes otherwise. buf and length wont be updated. + */ + void getStringUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout char buf, inout PRUint32 length); + + /** + * Get a a byte array value of attribute valname + * + * @return + * NS_OK on success. buf has the string value copied into it. + * length is updated to actual number of bytes copied into buf. + * NS_ERROR_REG_BUFFER_TOO_SMALL if not enough buffer space. + * length is updated to actual length in PRUint8s including + * terminating NULL and buf will be unchanged. + * NS_ERROR_FAILURE if an unknown error happened. state of buf and + * length undefined. + * various other failure codes otherwise. buf and length wont be updated. + */ + void getBytesUTF8IntoBuffer(in nsRegistryKey baseKey, in string path, + inout PRUint8 buf, inout PRUint32 length); +}; + +%{ C++ +#include "nsIRegistryUtils.h" +%} diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h new file mode 100644 index 00000000..a3d74d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsIRegistryUtils.h @@ -0,0 +1,63 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsIRegistryUtils_h +#define __nsIRegistryUtils_h + +#define NS_REGISTRY_CONTRACTID "@mozilla.org/registry;1" +#define NS_REGISTRY_CLASSNAME "Mozilla Registry" +/* be761f00-a3b0-11d2-996c-0080c7cb1081 */ +#define NS_REGISTRY_CID \ +{ \ + 0xbe761f00, \ + 0xa3b0, \ + 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x81} \ +} + +/*------------------------------- Error Codes ---------------------------------- +------------------------------------------------------------------------------*/ +#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 ) +#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 ) +#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 ) +#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 ) +#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 ) +#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 ) +#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 ) +#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 ) +#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 ) + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp new file mode 100644 index 00000000..f120cd43 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.cpp @@ -0,0 +1,1189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsSpecialSystemDirectory.h" +#include "nsDebug.h" + +#ifdef XP_MAC +#include +#include +#include +#include +#include +#include "nsIInternetConfigService.h" +#ifdef DEBUG +#include "prenv.h" // For PR_Getenv +#endif +#elif defined(XP_WIN) +#include +#include +#include +#include +#elif defined(XP_OS2) +#define MAX_PATH _MAX_PATH +#define INCL_WINWORKPLACE +#include +#include +#include +#include "prenv.h" +#elif defined(XP_UNIX) +#include +#include +#include +#include "prenv.h" +#elif defined(XP_BEOS) +#include +#include +#include +#include +#include +#include +#include +#include "prenv.h" +#endif + +#if defined(VMS) +#include +#endif + +#include "plstr.h" + +#include "nsHashtable.h" +#include "prlog.h" + +#if defined (XP_MAC) && UNIVERSAL_INTERFACES_VERSION < 0x0340 + enum { + kSystemDomain = -32766, /* Read-only system hierarchy.*/ + kLocalDomain = -32765, /* All users of a single machine have access to these resources.*/ + kNetworkDomain = -32764, /* All users configured to use a common network server has access to these resources.*/ + kUserDomain = -32763, /* Read/write. Resources that are private to the user.*/ + kClassicDomain = -32762, /* Domain referring to the currently configured Classic System Folder*/ + + kDomainLibraryFolderType = FOUR_CHAR_CODE('dlib') + }; +#endif + + +class SystemDirectoriesKey : public nsHashKey { +public: + + SystemDirectoriesKey(nsSpecialSystemDirectory::SystemDirectories newKey) : sdKey(newKey) {} + + virtual PRUint32 HashCode(void) const + { + return PRUint32(sdKey); + } + + virtual PRBool Equals(const nsHashKey *aKey) const + { + nsSpecialSystemDirectory::SystemDirectories other = + ((SystemDirectoriesKey*)aKey)->sdKey; + return other == sdKey; + } + + virtual nsHashKey *Clone(void) const + { + return new SystemDirectoriesKey(sdKey); + } + +private: + nsSpecialSystemDirectory::SystemDirectories sdKey; // sd for SystemDirectories +}; + +PR_STATIC_CALLBACK(PRBool) DeleteSystemDirKeys(nsHashKey *aKey, void *aData, void* closure) +{ + delete ((nsFileSpec *)aData); + return PR_TRUE; +} + +#define NS_SYSTEMDIR_HASH_NUM (10) +static nsHashtable *systemDirectoriesLocations = NULL; +#if defined (XP_WIN) +typedef BOOL (WINAPI * GetSpecialPathProc) (HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); +GetSpecialPathProc gGetSpecialPathProc = NULL; +static HINSTANCE gShell32DLLInst = NULL; +#endif +NS_COM_OBSOLETE void StartupSpecialSystemDirectory() +{ +#if defined (XP_WIN) + /* On windows, the old method to get file locations is incredibly slow. + As of this writing, 3 calls to GetWindowsFolder accounts for 3% of mozilla + startup. Replacing these older calls with a single call to SHGetSpecialFolderPath + effectively removes these calls from the performace radar. We need to + support the older way of file location lookup on systems that do not have + IE4. (Note: gets the ansi version: SHGetSpecialFolderPathA). + */ + gShell32DLLInst = LoadLibrary("Shell32.dll"); + if(gShell32DLLInst) + { + gGetSpecialPathProc = (GetSpecialPathProc) GetProcAddress(gShell32DLLInst, + "SHGetSpecialFolderPathA"); + } +#endif +} + +NS_COM_OBSOLETE void ShutdownSpecialSystemDirectory() +{ + if (systemDirectoriesLocations) + { + systemDirectoriesLocations->Reset(DeleteSystemDirKeys); + delete systemDirectoriesLocations; + } +#if defined (XP_WIN) + if (gShell32DLLInst) + { + FreeLibrary(gShell32DLLInst); + gShell32DLLInst = NULL; + gGetSpecialPathProc = NULL; + } +#endif +} + +#if defined (XP_WIN) + +static PRBool gGlobalOSInitialized = PR_FALSE; +static PRBool gGlobalDBCSEnabledOS = PR_FALSE; + +//---------------------------------------------------------------------------------------- +static char* MakeUpperCase(char* aPath) +//---------------------------------------------------------------------------------------- +{ + // check if the Windows is DBCSEnabled once. + if (PR_FALSE == gGlobalOSInitialized) { + if (GetSystemMetrics(SM_DBCSENABLED)) + gGlobalDBCSEnabledOS = PR_TRUE; + gGlobalOSInitialized = PR_TRUE; + } + + // windows does not care about case. pu sh to uppercase: + int length = strlen(aPath); + int i = 0; /* C++ portability guide #20 */ + if (!gGlobalDBCSEnabledOS) { + // for non-DBCS windows + for (i = 0; i < length; i++) + if (islower(aPath[i])) + aPath[i] = _toupper(aPath[i]); + } + else { + // for DBCS windows + for (i = 0; i < length; i++) { + if (IsDBCSLeadByte(aPath[i])) { + // begining of the double bye char + i++; + } + else { + if ( islower(aPath[i])) + aPath[i] = _toupper(aPath[i]); + } + } //end of for loop + } + return aPath; +} + +//---------------------------------------------------------------------------------------- +static void GetWindowsFolder(int folder, nsFileSpec& outDirectory) +//---------------------------------------------------------------------------------------- +{ + + if (gGetSpecialPathProc) { + TCHAR path[MAX_PATH]; + HRESULT result = gGetSpecialPathProc(NULL, path, folder, true); + + if (!SUCCEEDED(result)) + return; + + // Append the trailing slash + int len = PL_strlen(path); + if (len>1 && path[len-1] != '\\') + { + path[len] = '\\'; + path[len + 1] = '\0'; + } + outDirectory = path; + return; + } + + LPMALLOC pMalloc = NULL; + LPSTR pBuffer = NULL; + LPITEMIDLIST pItemIDList = NULL; + int len; + + // Get the shell's allocator. + if (!SUCCEEDED(SHGetMalloc(&pMalloc))) + return; + + // Allocate a buffer + if ((pBuffer = (LPSTR) pMalloc->Alloc(MAX_PATH + 2)) == NULL) + return; + + // Get the PIDL for the folder. + if (!SUCCEEDED(SHGetSpecialFolderLocation( + NULL, folder, &pItemIDList))) + goto Clean; + + if (!SUCCEEDED(SHGetPathFromIDList(pItemIDList, pBuffer))) + goto Clean; + + // Append the trailing slash + len = PL_strlen(pBuffer); + pBuffer[len] = '\\'; + pBuffer[len + 1] = '\0'; + + // Assign the directory + outDirectory = pBuffer; + +Clean: + // Clean up. + if (pItemIDList) + pMalloc->Free(pItemIDList); + if (pBuffer) + pMalloc->Free(pBuffer); + + pMalloc->Release(); +} // GetWindowsFolder +#endif // XP_WIN + +//---------------------------------------------------------------------------------------- +static void GetCurrentWorkingDirectory(nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ + aFileSpec = "."; + return; +} // GetCurrentWorkingDirectory + +//---------------------------------------------------------------------------------------- +static void GetCurrentProcessDirectory(nsFileSpec& aFileSpec) +//---------------------------------------------------------------------------------------- +{ +#if defined (XP_WIN) + char buf[MAX_PATH]; + if ( ::GetModuleFileName(0, buf, sizeof(buf)) ) { + // chop of the executable name by finding the rightmost backslash + char* lastSlash = PL_strrchr(buf, '\\'); + if (lastSlash) + *(lastSlash + 1) = '\0'; + + aFileSpec = buf; + return; + } + +#elif defined(XP_OS2) + PPIB ppib; + PTIB ptib; + char buffer[CCHMAXPATH]; + DosGetInfoBlocks( &ptib, &ppib); + DosQueryModuleName( ppib->pib_hmte, CCHMAXPATH, buffer); + *strrchr( buffer, '\\') = '\0'; // XXX DBCS misery + aFileSpec = buffer; + return; + + +#elif defined(XP_MAC) + // get info for the the current process to determine the directory + // its located in + OSErr err; + ProcessSerialNumber psn = {kNoProcess, kCurrentProcess}; + ProcessInfoRec pInfo; + FSSpec tempSpec; + + // initialize ProcessInfoRec before calling + // GetProcessInformation() or die horribly. + pInfo.processName = nil; + pInfo.processAppSpec = &tempSpec; + pInfo.processInfoLength = sizeof(ProcessInfoRec); + + if (!(err = GetProcessInformation(&psn, &pInfo))) + { + FSSpec appFSSpec = *(pInfo.processAppSpec); + long theDirID = appFSSpec.parID; + + Str255 name; + CInfoPBRec catInfo; + catInfo.dirInfo.ioCompletion = NULL; + catInfo.dirInfo.ioNamePtr = (StringPtr)&name; + catInfo.dirInfo.ioVRefNum = appFSSpec.vRefNum; + catInfo.dirInfo.ioDrDirID = theDirID; + catInfo.dirInfo.ioFDirIndex = -1; // -1 = query dir in ioDrDirID + + if (!(err = PBGetCatInfoSync(&catInfo))) + { + aFileSpec = nsFileSpec(appFSSpec.vRefNum, + catInfo.dirInfo.ioDrParID, + name, + PR_TRUE); + return; + } + } +#if defined(DEBUG) + else + { + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + if (moz5) + { + printf( "nsSpecialSystemDirectory::VBOX_XPCOM_HOME is set to %s\n", moz5 ); + aFileSpec = moz5; + return; + } + else + { + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("***Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } + } + } +#endif /* DEBUG */ + +#elif defined(XP_UNIX) + + // In the absence of a good way to get the executable directory let + // us try this for unix: + // - if VBOX_XPCOM_HOME is defined, that is it + // - else give the current directory + char buf[MAXPATHLEN]; + char *moz5 = PR_GetEnv("VBOX_XPCOM_HOME"); + if (moz5) + { + aFileSpec = moz5; + return; + } + else + { +#if defined(DEBUG) + static PRBool firstWarning = PR_TRUE; + + if(firstWarning) { + // Warn that VBOX_XPCOM_HOME not set, once. + printf("Warning: VBOX_XPCOM_HOME not set.\n"); + firstWarning = PR_FALSE; + } +#endif /* DEBUG */ + + // Fall back to current directory. + if (getcwd(buf, sizeof(buf))) + { + aFileSpec = buf; + return; + } + } + +#elif defined(XP_BEOS) + + char *moz5 = getenv("VBOX_XPCOM_HOME"); + if (moz5) + { + aFileSpec = moz5; + return; + } + else + { + static char buf[MAXPATHLEN]; + int32 cookie = 0; + image_info info; + char *p; + *buf = 0; + if(get_next_image_info(0, &cookie, &info) == B_OK) + { + strcpy(buf, info.name); + if((p = strrchr(buf, '/')) != 0) + { + *p = 0; + aFileSpec = buf; + return; + } + } + } + +#endif + + NS_ERROR("unable to get current process directory"); +} // GetCurrentProcessDirectory() + +//nsSpecialSystemDirectory::nsSpecialSystemDirectory() +//: nsFileSpec(nsnull) +//{ +//} + +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::nsSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory) +//---------------------------------------------------------------------------------------- +: nsFileSpec(nsnull) +{ + *this = aSystemSystemDirectory; +} + +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::~nsSpecialSystemDirectory() +//---------------------------------------------------------------------------------------- +{ +} + +//---------------------------------------------------------------------------------------- +void nsSpecialSystemDirectory::operator = (SystemDirectories aSystemSystemDirectory) +//---------------------------------------------------------------------------------------- +{ + SystemDirectoriesKey dirKey(aSystemSystemDirectory); + SystemDirectoriesKey mozBinDirKey(Moz_BinDirectory); + + // This flag is used to tell whether or not we need to append something + // onto the *this. Search for needToAppend to how it's used. + // IT's VERY IMPORTANT that needToAppend is initialized to PR_TRUE. + PRBool needToAppend = PR_TRUE; + +#ifdef XP_MAC + OSErr err; + short vRefNum; + long dirID; +#endif + + *this = (const char*)nsnull; + switch (aSystemSystemDirectory) + { + + case OS_DriveDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + if (len) + { + if ( path[1] == ':' && path[2] == '\\' ) + path[3] = 0; + } + *this = MakeUpperCase(path); + } +#elif defined(XP_OS2) + { + // printf( "*** Warning warning OS_DriveDirectory called for"); + + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS_DriveDirectory: %s\n", buffer); +#endif + } +#elif defined(XP_MAC) + { + *this = kVolumeRootFolderType; + } +#else + *this = "/"; +#endif + break; + + + case OS_TemporaryDirectory: +#if defined (XP_WIN) + { + char path[_MAX_PATH]; + DWORD len = GetTempPath(_MAX_PATH, path); + *this = MakeUpperCase(path); + } +#elif defined(XP_OS2) + { + char buffer[CCHMAXPATH] = ""; + char *c = getenv( "TMP"); + if( c) strcpy( buffer, c); + else + { + c = getenv( "TEMP"); + if( c) strcpy( buffer, c); + } + if( c) *this = buffer; + // use exe's directory if not set + else GetCurrentProcessDirectory(*this); + } +#elif defined(XP_MAC) + *this = kTemporaryFolderType; + +#elif defined(XP_UNIX) || defined(XP_BEOS) + { + static const char *tPath = nsnull; + if (!tPath) { + tPath = PR_GetEnv("TMPDIR"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TMP"); + if (!tPath || !*tPath) { + tPath = PR_GetEnv("TEMP"); + if (!tPath || !*tPath) { + tPath = "/tmp/"; + } + } + } + } + + *this = tPath; + } +#endif + break; + + case OS_CurrentProcessDirectory: + GetCurrentProcessDirectory(*this); + break; + + case OS_CurrentWorkingDirectory: + GetCurrentWorkingDirectory(*this); + break; + + case XPCOM_CurrentProcessComponentRegistry: + { + nsFileSpec *dirSpec = NULL; + + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + if (!(dirSpec = (nsFileSpec *)systemDirectoriesLocations->Get(&dirKey))) { + // if not found, try Moz_BinDirectory + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&mozBinDirKey); + } + else { + // if the value is found for the argument key, + // we don't need to append. + needToAppend = PR_FALSE; + } + } + + if (dirSpec) + { + *this = *dirSpec; + } + else + { + GetCurrentProcessDirectory(*this); + } + + if (needToAppend) { + // XXX We need to unify these names across all platforms +#if defined(XP_MAC) + *this += "Component Registry"; +#else + *this += "component.reg"; +#endif /* XP_MAC */ + } + } + break; + + case XPCOM_CurrentProcessComponentDirectory: + { + nsFileSpec *dirSpec = NULL; + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + if (!(dirSpec = (nsFileSpec *)systemDirectoriesLocations->Get(&dirKey))) { + // if not found, try Moz_BinDirectory + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&mozBinDirKey); + } + else { + // if the value is found for the argument key, + // we don't need to append. + needToAppend = PR_FALSE; + } + } + if (dirSpec) + { + *this = *dirSpec; + } + else + { + // /Components + GetCurrentProcessDirectory(*this); + } + + if (needToAppend) { + // XXX We need to unify these names across all platforms +#if defined(XP_MAC) + *this += "Components"; +#else + *this += "components"; +#endif /* XP_MAC */ + } + } + break; + + case Moz_BinDirectory: + { + nsFileSpec *dirSpec = NULL; + // if someone has called nsSpecialSystemDirectory::Set() + if (systemDirectoriesLocations) { + // look for the value for the argument key + dirSpec = (nsFileSpec *) + systemDirectoriesLocations->Get(&dirKey); + } + if (dirSpec) { + *this = *dirSpec; + } + else { + GetCurrentProcessDirectory(*this); + } + } + break; + +#if defined(XP_MAC) + case Mac_SystemDirectory: + *this = kSystemFolderType; + break; + + case Mac_DesktopDirectory: + *this = kDesktopFolderType; + break; + + case Mac_TrashDirectory: + *this = kTrashFolderType; + break; + + case Mac_StartupDirectory: + *this = kStartupFolderType; + break; + + case Mac_ShutdownDirectory: + *this = kShutdownFolderType; + break; + + case Mac_AppleMenuDirectory: + *this = kAppleMenuFolderType; + break; + + case Mac_ControlPanelDirectory: + *this = kControlPanelFolderType; + break; + + case Mac_ExtensionDirectory: + *this = kExtensionFolderType; + break; + + case Mac_FontsDirectory: + *this = kFontsFolderType; + break; + + case Mac_ClassicPreferencesDirectory: + { + // whether Mac OS X or pre-Mac OS X, return Classic's Prefs folder + short domain; + long response; + err = ::Gestalt(gestaltSystemVersion, &response); + domain = (!err && response >= 0x00001000) ? kClassicDomain : kOnSystemDisk; + err = ::FindFolder(domain, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } + + case Mac_PreferencesDirectory: + { + // if Mac OS X, return Mac OS X's Prefs folder + // if pre-Mac OS X, return Mac OS's Prefs folder + err = ::FindFolder(kOnSystemDisk, kPreferencesFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } + + case Mac_DocumentsDirectory: + *this = kDocumentsFolderType; + break; + + case Mac_InternetSearchDirectory: + *this = kInternetSearchSitesFolderType; + break; + + case Mac_DefaultDownloadDirectory: + *this = kDefaultDownloadFolderType; + break; + + case Mac_UserLibDirectory: + { + err = ::FindFolder(kUserDomain, kDomainLibraryFolderType, true, &vRefNum, &dirID); + if (!err) { + err = ::FSMakeFSSpec(vRefNum, dirID, "\p", &mSpec); + } + mError = NS_FILE_RESULT(err); + break; + } +#endif + +#if defined (XP_WIN) + case Win_SystemDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetSystemDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + + break; + } + + case Win_WindowsDirectory: + { + char path[_MAX_PATH]; + PRInt32 len = GetWindowsDirectory( path, _MAX_PATH ); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH-2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + + case Win_HomeDirectory: + { + char path[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOME"), path, _MAX_PATH) > 0) + { + PRInt32 len = PL_strlen(path); + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + + if (GetEnvironmentVariable(TEXT("HOMEDRIVE"), path, _MAX_PATH) > 0) + { + char temp[_MAX_PATH]; + if (GetEnvironmentVariable(TEXT("HOMEPATH"), temp, _MAX_PATH) > 0) + PL_strcatn(path, _MAX_PATH, temp); + + PRInt32 len = PL_strlen(path); + + // Need enough space to add the trailing backslash + if (len > _MAX_PATH - 2) + break; + + path[len] = '\\'; + path[len+1] = '\0'; + + *this = MakeUpperCase(path); + break; + } + } + case Win_Desktop: + { + GetWindowsFolder(CSIDL_DESKTOP, *this); + break; + } + case Win_Programs: + { + GetWindowsFolder(CSIDL_PROGRAMS, *this); + break; + } + case Win_Controls: + { + GetWindowsFolder(CSIDL_CONTROLS, *this); + break; + } + case Win_Printers: + { + GetWindowsFolder(CSIDL_PRINTERS, *this); + break; + } + case Win_Personal: + { + GetWindowsFolder(CSIDL_PERSONAL, *this); + break; + } + case Win_Favorites: + { + GetWindowsFolder(CSIDL_FAVORITES, *this); + break; + } + case Win_Startup: + { + GetWindowsFolder(CSIDL_STARTUP, *this); + break; + } + case Win_Recent: + { + GetWindowsFolder(CSIDL_RECENT, *this); + break; + } + case Win_Sendto: + { + GetWindowsFolder(CSIDL_SENDTO, *this); + break; + } + case Win_Bitbucket: + { + GetWindowsFolder(CSIDL_BITBUCKET, *this); + break; + } + case Win_Startmenu: + { + GetWindowsFolder(CSIDL_STARTMENU, *this); + break; + } + case Win_Desktopdirectory: + { + GetWindowsFolder(CSIDL_DESKTOPDIRECTORY, *this); + break; + } + case Win_Drives: + { + GetWindowsFolder(CSIDL_DRIVES, *this); + break; + } + case Win_Network: + { + GetWindowsFolder(CSIDL_NETWORK, *this); + break; + } + case Win_Nethood: + { + GetWindowsFolder(CSIDL_NETHOOD, *this); + break; + } + case Win_Fonts: + { + GetWindowsFolder(CSIDL_FONTS, *this); + break; + } + case Win_Templates: + { + GetWindowsFolder(CSIDL_TEMPLATES, *this); + break; + } + case Win_Common_Startmenu: + { + GetWindowsFolder(CSIDL_COMMON_STARTMENU, *this); + break; + } + case Win_Common_Programs: + { + GetWindowsFolder(CSIDL_COMMON_PROGRAMS, *this); + break; + } + case Win_Common_Startup: + { + GetWindowsFolder(CSIDL_COMMON_STARTUP, *this); + break; + } + case Win_Common_Desktopdirectory: + { + GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, *this); + break; + } + case Win_Appdata: + { + GetWindowsFolder(CSIDL_APPDATA, *this); + break; + } + case Win_Printhood: + { + GetWindowsFolder(CSIDL_PRINTHOOD, *this); + break; + } + case Win_Cookies: + { + GetWindowsFolder(CSIDL_COOKIES, *this); + break; + } +#endif // XP_WIN + +#if defined(XP_UNIX) + case Unix_LocalDirectory: + *this = "/usr/local/netscape/"; + break; + + case Unix_LibDirectory: + *this = "/usr/local/lib/netscape/"; + break; + + case Unix_HomeDirectory: +#ifdef VMS + { + char *pHome; + pHome = getenv("HOME"); + if (*pHome == '/') + *this = pHome; + else + *this = decc$translate_vms(pHome); + } +#else + *this = PR_GetEnv("HOME"); +#endif + break; + +#endif + +#ifdef XP_BEOS + case BeOS_SettingsDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_HomeDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_USER_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_DesktopDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_DESKTOP_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } + + case BeOS_SystemDirectory: + { + char path[MAXPATHLEN]; + find_directory(B_BEOS_DIRECTORY, 0, 0, path, MAXPATHLEN); + // Need enough space to add the trailing backslash + int len = strlen(path); + if (len > MAXPATHLEN-2) + break; + path[len] = '/'; + path[len+1] = '\0'; + *this = path; + break; + } +#endif +#ifdef XP_OS2 + case OS2_SystemDirectory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\System\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS2_SystemDirectory: %s\n", buffer); +#endif + break; + } + + case OS2_OS2Directory: + { + ULONG ulBootDrive = 0; + char buffer[] = " :\\OS2\\"; + DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, + &ulBootDrive, sizeof ulBootDrive); + buffer[0] = 'A' - 1 + ulBootDrive; // duh, 1-based index... + *this = buffer; +#ifdef DEBUG + printf( "Got OS2_OS2Directory: %s\n", buffer); +#endif + break; + } + + case OS2_HomeDirectory: + { + char *tPath = PR_GetEnv("MOZILLA_HOME"); + /* If MOZILLA_HOME is not set, use GetCurrentProcessDirectory */ + /* To ensure we get a long filename system */ + if (!tPath || !*tPath) + GetCurrentProcessDirectory(*this); + else + *this = tPath; + PrfWriteProfileString(HINI_USERPROFILE, "Mozilla", "Home", *this); + break; + } + + case OS2_DesktopDirectory: + { + char szPath[CCHMAXPATH + 1]; + BOOL fSuccess; + fSuccess = WinQueryActiveDesktopPathname (szPath, sizeof(szPath)); + int len = strlen (szPath); + if (len > CCHMAXPATH -1) + break; + szPath[len] = '\\'; + szPath[len + 1] = '\0'; +#ifdef DEBUG + if (fSuccess) { + printf ("Got OS2_DesktopDirectory: %s\n", szPath); + } else { + printf ("Failed getting OS2_DesktopDirectory: %s\n", szPath); + } +#endif + break; + } + +#endif + default: + break; + } +} + +void +nsSpecialSystemDirectory::Set(SystemDirectories dirToSet, nsFileSpec *dirSpec) +{ + SystemDirectoriesKey dirKey(dirToSet); + + PR_ASSERT(NULL != dirSpec); + + if (NULL == systemDirectoriesLocations) { + systemDirectoriesLocations = new nsHashtable(NS_SYSTEMDIR_HASH_NUM); + } + PR_ASSERT(NULL != systemDirectoriesLocations); + + nsFileSpec *newSpec = new nsFileSpec(*dirSpec); + if (NULL != newSpec) { + systemDirectoriesLocations->Put(&dirKey, newSpec); + } + + return; +} + +#if defined(XP_MAC) +//---------------------------------------------------------------------------------------- +nsSpecialSystemDirectory::nsSpecialSystemDirectory(OSType folderType) +//---------------------------------------------------------------------------------------- +{ + *this = folderType; +} + +//---------------------------------------------------------------------------------------- +void nsSpecialSystemDirectory::operator = (OSType folderType) +//---------------------------------------------------------------------------------------- +{ + CInfoPBRec cinfo; + DirInfo *dipb=(DirInfo *)&cinfo; + + // hack: first check for kDefaultDownloadFolderType + // if it is, get Internet Config Download folder, if that's + // not availble use desktop folder + if (folderType == kDefaultDownloadFolderType) + { + nsCOMPtr icService (do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID)); + if (icService) + { + if (NS_SUCCEEDED(icService->GetDownloadFolder(&mSpec))) + return; + else + folderType = kDesktopFolderType; + } + else + { + folderType = kDesktopFolderType; + } + } + // Call FindFolder to fill in the vrefnum and dirid + for (int attempts = 0; attempts < 2; attempts++) + { + mError = NS_FILE_RESULT( + FindFolder( + kOnSystemDisk, + folderType, + true, + &dipb->ioVRefNum, + &dipb->ioDrDirID)); + if (NS_SUCCEEDED(mError)) + break; + if (attempts > 0) + return; + switch (folderType) + { + case kDocumentsFolderType: + // Find folder will find this, as long as it exists. + // The "create" parameter, however, is sadly ignored. + // How do we internationalize this? + *this = kVolumeRootFolderType; + *this += "Documents"; + CreateDirectory(); + break; + } // switch + } // for + StrFileName filename; + filename[0] = '\0'; + dipb->ioNamePtr = (StringPtr)&filename; + dipb->ioFDirIndex = -1; + + mError = NS_FILE_RESULT(PBGetCatInfoSync(&cinfo)); + if (NS_SUCCEEDED(mError)) + { + mError = NS_FILE_RESULT(FSMakeFSSpec(dipb->ioVRefNum, dipb->ioDrParID, filename, &mSpec)); + } +} +#endif // XP_MAC diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h new file mode 100644 index 00000000..577cd0c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsSpecialSystemDirectory.h @@ -0,0 +1,167 @@ +/* -*- 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _NSSPECIALSYSTEMDIRECTORY_H_ +#define _NSSPECIALSYSTEMDIRECTORY_H_ + +#include "xpcomobsolete.h" +#include "nsFileSpec.h" + +#if defined(XP_MAC) || defined(XP_MACOSX) +#include +#endif + + +extern NS_COM_OBSOLETE void StartupSpecialSystemDirectory(); +extern NS_COM_OBSOLETE void ShutdownSpecialSystemDirectory(); + + +// SEE ALSO: +// mozilla/xpfe/appshell/public/nsFileLocations.h + +class NS_COM_OBSOLETE nsSpecialSystemDirectory : public nsFileSpec +{ + + public: + enum SystemDirectories + { + OS_DriveDirectory = 1 + , OS_TemporaryDirectory = 2 + , OS_CurrentProcessDirectory= 3 + , OS_CurrentWorkingDirectory= 4 + + , XPCOM_CurrentProcessComponentDirectory= 5 + , XPCOM_CurrentProcessComponentRegistry= 6 + + , Moz_BinDirectory = 10 + + , Mac_SystemDirectory = 101 + , Mac_DesktopDirectory = 102 + , Mac_TrashDirectory = 103 + , Mac_StartupDirectory = 104 + , Mac_ShutdownDirectory = 105 + , Mac_AppleMenuDirectory = 106 + , Mac_ControlPanelDirectory = 107 + , Mac_ExtensionDirectory = 108 + , Mac_FontsDirectory = 109 + , Mac_ClassicPreferencesDirectory = 110 + , Mac_DocumentsDirectory = 111 + , Mac_InternetSearchDirectory = 112 + , Mac_DefaultDownloadDirectory = 113 + , Mac_UserLibDirectory = 114 + , Mac_PreferencesDirectory = 115 + + , Win_SystemDirectory = 201 + , Win_WindowsDirectory = 202 + + , Win_HomeDirectory = 203 + , Win_Desktop = 204 + , Win_Programs = 205 + , Win_Controls = 206 + , Win_Printers = 207 + , Win_Personal = 208 + , Win_Favorites = 209 + , Win_Startup = 210 + , Win_Recent = 211 + , Win_Sendto = 212 + , Win_Bitbucket = 213 + , Win_Startmenu = 214 + , Win_Desktopdirectory = 215 + , Win_Drives = 216 + , Win_Network = 217 + , Win_Nethood = 218 + , Win_Fonts = 219 + , Win_Templates = 220 + , Win_Common_Startmenu = 221 + , Win_Common_Programs = 222 + , Win_Common_Startup = 223 + , Win_Common_Desktopdirectory = 224 + , Win_Appdata = 225 + , Win_Printhood = 226 + , Win_Cookies = 227 + + , Unix_LocalDirectory = 301 + , Unix_LibDirectory = 302 + , Unix_HomeDirectory = 303 + + , BeOS_SettingsDirectory = 401 + , BeOS_HomeDirectory = 402 + , BeOS_DesktopDirectory = 403 + , BeOS_SystemDirectory = 404 + + , OS2_SystemDirectory = 501 + , OS2_OS2Directory = 502 + , OS2_DesktopDirectory = 503 + , OS2_HomeDirectory = 504 + }; + + //nsSpecialSystemDirectory(); + nsSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory); + + virtual ~nsSpecialSystemDirectory(); + + void operator = (SystemDirectories aSystemSystemDirectory); + +#if defined(XP_MAC) || defined(XP_MACOSX) + void operator = (OSType folderType); + nsSpecialSystemDirectory(OSType folderType); + enum { + kDefaultDownloadFolderType = FOUR_CHAR_CODE('DfDÄ') /* Default Download Folder */ + }; +#endif + + /** + + * @param: dirToSet, the value to set for this safeLocation + + * @param: dirSpec, the directory specified as a filespec + + */ + + static void Set(SystemDirectories dirToSet, nsFileSpec *dirSpec); + + +private: + void operator = (const char* inPath) { *(nsFileSpec*)this = inPath; } + +}; // class NS_COM_OBSOLETE nsSpecialSystemDirectory + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp b/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp new file mode 100644 index 00000000..45391c0f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/nsXPCOMObsolete.cpp @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsXPCOM.h" +#include "nsIGenericFactory.h" + +#include "nsFileSpecImpl.h" + +#define COMPONENT(NAME, Ctor) \ + { NS_##NAME##_CLASSNAME, NS_##NAME##_CID, NS_##NAME##_CONTRACTID, Ctor } + + +static const nsModuleComponentInfo components[] = +{ + COMPONENT(FILESPEC, nsFileSpecImpl::Create), + COMPONENT(DIRECTORYITERATOR, nsDirectoryIteratorImpl::Create), +}; + +NS_IMPL_NSGETMODULE(xpcomObsoleteModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h new file mode 100644 index 00000000..13914115 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 xpcomobsolete_h___ +#define xpcomobsolete_h___ + +#include "nscore.h" + +#ifdef _IMPL_NS_COM_OBSOLETE +#define NS_COM_OBSOLETE NS_EXPORT +#else +#define NS_COM_OBSOLETE NS_IMPORT +#endif + +#endif /* !defined(xpcomobsolete_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg new file mode 100644 index 00000000..d44a8939 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/obsolete/xpcomobsolete.pkg @@ -0,0 +1,7 @@ +[gecko xpi-bootstrap] +#if SHARED_LIBRARY +dist/bin/@SHARED_LIBRARY@ +#endif + +[gecko] +!xpt dist/bin/components/xpcom_obsolete.xpt diff --git a/src/libs/xpcom18a4/xpcom/proxy/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in new file mode 100644 index 00000000..c30f214f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 mozilla.org Code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in new file mode 100644 index 00000000..d6950b9a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/Makefile.in @@ -0,0 +1,63 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +ifeq ($(OS_ARCH),WINNT) +XPIDL_MODULE = proxyObject +else +XPIDL_MODULE = proxyObjInst +endif + +EXPORTS = \ + nsProxyEvent.h \ + nsProxyRelease.h \ + nsProxiedService.h \ + $(NULL) + +XPIDLSRCS = nsIProxyCreateInstance.idl \ + nsIProxyObjectManager.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl new file mode 100644 index 00000000..cd576f7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyCreateInstance.idl @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(948c2080-0398-11d3-915e-0000863011c4)] +interface nsIProxyCreateInstance : nsISupports +{ + [noscript] void CreateInstanceByIID(in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); + + [noscript] void CreateInstanceByContractID(in string aContractID, + in nsISupports aOuter, + in nsIIDRef iid, + out voidPtr result); +}; + diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl new file mode 100644 index 00000000..5b2cfd4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsIProxyObjectManager.idl @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner (Original Author) + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +interface nsIEventQueue; + +[scriptable, uuid(eea90d43-b059-11d2-915e-c12b696c9333)] +interface nsIProxyObjectManager : nsISupports +{ + void getProxyForObject(in nsIEventQueue destQueue, + in nsIIDRef iid, + in nsISupports object, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + + void getProxy(in nsIEventQueue destQueue, + in nsIIDRef cid, + in nsISupports aOuter, + in nsIIDRef iid, + in PRInt32 proxyType, + [iid_is(iid),retval] out nsQIResult result); + +}; + + +%{C++ +#include "nsProxyEvent.h" + +#define NS_XPCOMPROXY_CONTRACTID "@mozilla.org/xpcomproxy;1" +#define NS_XPCOMPROXY_CLASSNAME "XPCom Proxy" + +#define NS_PROXYEVENT_MANAGER_CID \ +{ 0xeea90d41, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +/** + * Helper function for code that already has a link-time dependency on + * libxpcom and needs to get proxies in a bunch of different places. + * This way, the caller isn't forced to get the proxy object manager + * themselves every single time, thus making the calling code more + * readable. + */ +extern NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject); +%} diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h new file mode 100644 index 00000000..3a39ade1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxiedService.h @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsProxiedServiceManager_h_ +#define __nsProxiedServiceManager_h_ + +#include "nsIServiceManager.h" +#include "nsIProxyObjectManager.h" + +//////////////////////////////////////////////////////////////////////////////// +// NS_WITH_PROXIED_SERVICE: macro to make using services that need to be proxied +// before using them easier. +// Now you can replace this: +// { +// nsresult rv; +// nsCOMPtr pIMyService = +// do_GetService(kMyServiceCID, &rv); +// if(NS_FAILED(rv)) +// return; +// nsCOMPtr pIProxyObjectManager = +// do_GetService(kProxyObjectManagerCID, &rv); +// if(NS_FAILED(rv)) +// return; +// nsIMyService pIProxiedObject = NULL; +// rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue, +// NS_GET_IID(nsIMyService), +// pIMyService, PROXY_SYNC, +// (void**)&pIProxiedObject); +// pIProxiedObject->DoIt(...); // Executed on same thread as pIProxyQueue +// ... +// pIProxiedObject->Release(); // Must be done as not managed for you. +// } +// with this: +// { +// nsresult rv; +// NS_WITH_PROXIED_SERVICE(nsIMyService, pIMyService, kMyServiceCID, +// pIProxyQueue, &rv); +// if(NS_FAILED(rv)) +// return; +// pIMyService->DoIt(...); // Executed on the same thread as pIProxyQueue +// } +// and the automatic destructor will take care of releasing the service and +// the proxied object for you. +// +// Note that this macro requires you to link with the xpcom DLL to pick up the +// static member functions from nsServiceManager. + +#define NS_WITH_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \ + nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, PR_FALSE, rvAddr); \ + T* var = (T*)(nsISupports*)_serv##var; + +#define NS_WITH_ALWAYS_PROXIED_SERVICE(T, var, cid, Q, rvAddr) \ + nsProxiedService _serv##var(cid, NS_GET_IID(T), Q, PR_TRUE, rvAddr); \ + T* var = (T*)(nsISupports*)_serv##var; + +//////////////////////////////////////////////////////////////////////////////// +// nsProxiedService +//////////////////////////////////////////////////////////////////////////////// + +class nsProxiedService +{ + public: + + nsProxiedService(const nsCID &aClass, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aClass, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + nsProxiedService(const char* aContractID, const nsIID &aIID, + nsIEventQueue* pIProxyQueue, PRBool always, nsresult*rv) + { + *rv = nsServiceManager::GetService(aContractID, + aIID, + getter_AddRefs(mService)); + if (NS_FAILED(*rv)) return; + InitProxy(aIID, pIProxyQueue, always, rv); + } + + void InitProxy(const nsIID &aIID, nsIEventQueue* pIProxyQueue, + PRBool always, nsresult*rv) + { + static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); + + nsCOMPtr pIProxyObjectManager = + do_GetService(kProxyObjectManagerCID, rv); + if (NS_FAILED(*rv)) return; + + PRInt32 proxyType = PROXY_SYNC; + if (always) proxyType |= PROXY_ALWAYS; + *rv = pIProxyObjectManager->GetProxyForObject(pIProxyQueue, + aIID, + mService, + proxyType, + getter_AddRefs(mProxiedService)); + } + + ~nsProxiedService() + { + } + + nsISupports* operator->() const + { + NS_PRECONDITION(mProxiedService != 0, "Your code should test the error result from the constructor."); + return mProxiedService; + } + + PRBool operator==(const nsISupports* other) + { + return ((mProxiedService == other) || (mService == other)); + } + + operator nsISupports*() const + { + return mProxiedService; + } + + protected: + nsCOMPtr mProxiedService; + nsCOMPtr mService; + + }; + + +#endif //__nsProxiedServiceManager_h_ diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h new file mode 100644 index 00000000..c718bbdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyEvent.h @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsProxyEvent_h_ +#define __nsProxyEvent_h_ + +#include "nsCOMPtr.h" +#include "nsAutoPtr.h" +#include "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" + +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" +#include "plevent.h" +#include "prtypes.h" +#include "xptcall.h" +#include "xptinfo.h" + +class nsProxyObjectCallInfo; + +#define PROXY_SYNC 0x0001 // acts just like a function call. +#define PROXY_ASYNC 0x0002 // fire and forget. This will return immediately and you will lose all return information. +#define PROXY_ALWAYS 0x0004 // ignore check to see if the eventQ is on the same thread as the caller, and alway return a proxied object. + +//#define AUTOPROXIFICATION + +// WARNING about PROXY_ASYNC: +// +// If the calling thread goes away, any function which accesses the calling stack +// will blow up. +// +// example: +// +// myFoo->bar(&x) +// +// ... thread goes away ... +// +// bar(PRInt32 *x) +// { +// *x = 0; <----- You will blow up here. +// +// +// So what gets saved? +// +// You can safely pass base types by value. You can also pass interface pointers. +// I will make sure that the interface pointers are addrefed while they are being +// proxied. You can also pass string and wstring. These I will copy and free. +// +// I do **NOT** copy arrays or strings with size. If you are using these either +// change your interface, or contact me about this feature request. + + + + +class nsProxyObject +{ +public: + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject); + nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID); + + void AddRef(); + void Release(); + + ~nsProxyObject(); + + nsresult Post( PRUint32 methodIndex, + nsXPTMethodInfo * info, + nsXPTCMiniVariant * params, + nsIInterfaceInfo * interfaceInfo); + + nsresult PostAndWait(nsProxyObjectCallInfo *proxyInfo); + nsISupports* GetRealObject() const { return mRealObject; } + nsIEventQueue* GetQueue() const { return mDestQueue; } + PRInt32 GetProxyType() const { return mProxyType; } + + friend class nsProxyEventObject; +private: + + nsAutoRefCnt mRefCnt; + + PRInt32 mProxyType; + + nsCOMPtr mDestQueue; /* destination queue */ + + nsCOMPtr mRealObject; /* the non-proxy object that this event is referring to. + This is a strong ref. */ + nsCOMPtr mEventQService; + + nsresult convertMiniVariantToVariant(nsXPTMethodInfo * methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *paramCount); + +}; + + +class nsProxyObjectCallInfo +{ +public: + + nsProxyObjectCallInfo(nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event); + + ~nsProxyObjectCallInfo(); + + PRUint32 GetMethodIndex() const { return mMethodIndex; } + nsXPTCVariant* GetParameterList() const { return mParameterList; } + PRUint32 GetParameterCount() const { return mParameterCount; } + PLEvent* GetPLEvent() const { return mEvent; } + nsresult GetResult() const { return mResult; } + nsProxyObject* GetProxyObject() const { return mOwner; } + + PRBool GetCompleted(); + void SetCompleted(); + void PostCompleted(); + + void SetResult(nsresult rv) {mResult = rv; } + + nsIEventQueue* GetCallersQueue(); + void SetCallersQueue(nsIEventQueue* queue); + +private: + + nsresult mResult; /* this is the return result of the called function */ + nsXPTMethodInfo *mMethodInfo; + PRUint32 mMethodIndex; /* which method to be called? */ + nsXPTCVariant *mParameterList; /* marshalled in parameter buffer */ + PRUint32 mParameterCount; /* number of params */ + PLEvent *mEvent; /* the current plevent */ + PRInt32 mCompleted; /* is true when the method has been called. */ + + nsCOMPtr mCallersEventQ; /* this is the eventQ that we must post a message back to + when we are done invoking the method (only PROXY_SYNC). + */ + + nsRefPtr mOwner; /* this is the strong referenced nsProxyObject */ + + void RefCountInInterfacePointers(PRBool addRef); + void CopyStrings(PRBool copy); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h new file mode 100644 index 00000000..413a3d0e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/public/nsProxyRelease.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsProxyRelease_h__ +#define nsProxyRelease_h__ + +#include "nsIEventQueueService.h" +#include "pratom.h" +#include "prmem.h" + +/** + * Ensures that the delete of a nsISupports object occurs on the target thread. + * + * @param target + * the target thread where the doomed object should be released. + * @param doomed + * the doomed object; the object to be released on the target thread. + * @param alwaysProxy + * normally, if NS_ProxyRelease is called on the target thread, then the + * doomed object will released directly. however, if this parameter is + * true, then a PLEvent will always be posted to the target thread and + * the release will happen when that PLEvent is handled. + */ +NS_COM nsresult NS_ProxyRelease + (nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE); + + +#define NS_IMPL_PROXY_RELEASE(_class) \ +NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ +{ \ + NS_PRECONDITION(0 != mRefCnt, "dup release"); \ + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); \ + NS_LOG_RELEASE(this, count, #_class); \ + \ + if (count == 0) \ + { \ + mRefCnt = 1; /* stabilize */ \ + PRBool callDirectly = PR_TRUE; \ + static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); \ + nsCOMPtr eventQService \ + = do_GetService(kEventQueueServiceCID); \ + NS_ASSERTION(eventQService, "event queue service is unavailable"); \ + \ + nsCOMPtr eventQ; \ + if (eventQService) { \ + eventQService->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(eventQ)); \ + if (eventQ) \ + eventQ->IsOnCurrentThread(&callDirectly); \ + } \ + \ + if (callDirectly) \ + { \ + NS_RELEASE(this); \ + return 0; \ + } \ + PLEvent *event = new PLEvent; \ + if (event == nsnull) \ + { \ + NS_ASSERTION(0, "Could not create a plevent. Deleting on wrong thread!"); \ + NS_DELETEXPCOM(this); \ + return 0; \ + } \ + \ + PL_InitEvent(event, \ + NS_STATIC_CAST(nsISupports*, this), \ + ReleaseDestructorEventHandler, \ + ReleaseDestructorDestroyHandler); \ + \ + eventQ->PostEvent(event); \ + return 0; \ + } \ + return count; \ +} \ + + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in new file mode 100644 index 00000000..3d46f60b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/Makefile.in @@ -0,0 +1,67 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpcomproxy_s +REQUIRES = string \ + $(NULL) + + +CPPSRCS = \ + nsProxyEvent.cpp \ + nsProxyEventClass.cpp \ + nsProxyEventObject.cpp \ + nsProxyObjectManager.cpp \ + nsProxyRelease.cpp \ + $(NULL) + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTC_API -DEXPORT_XPTI_API + +# No shared lib; Force creation of static lib +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h new file mode 100644 index 00000000..13755d74 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsIProxyCreateInstance.h @@ -0,0 +1,39 @@ +/* + * DO NOT EDIT. THIS FILE IS GENERATED FROM nsIProxyCreateInstance.idl + */ + +#ifndef __gen_nsIProxyCreateInstance_h__ +#define __gen_nsIProxyCreateInstance_h__ + +#include "nsISupports.h" /* interface nsISupports */ +#include "nsrootidl.h" /* interface nsrootidl */ + +#ifdef XPIDL_JS_STUBS +#include "jsapi.h" +#endif + +/* starting interface: nsIProxyCreateInstance */ + +/* {948c2080-0398-11d3-915e-0000863011c4} */ +#define NS_IPROXYCREATEINSTANCE_IID_STR "948c2080-0398-11d3-915e-0000863011c4" +#define NS_IPROXYCREATEINSTANCE_IID \ + {0x948c2080, 0x0398, 0x11d3, \ + { 0x91, 0x5e, 0x00, 0x00, 0x86, 0x30, 0x11, 0xc4 }} + +class nsIProxyCreateInstance : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPROXYCREATEINSTANCE_IID) + + /* void CreateInstanceByIID (in nsIIDRef cid, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + + /* void CreateInstanceByContractID (in string aContractID, in nsISupports aOuter, in nsIIDRef iid, out voidStar result); */ + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) = 0; + +#ifdef XPIDL_JS_STUBS + static NS_EXPORT_(JSObject *) InitJSClass(JSContext *cx); + static NS_EXPORT_(JSObject *) GetJSObject(JSContext *cx, nsIProxyCreateInstance *priv); +#endif +}; + +#endif /* __gen_nsIProxyCreateInstance_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp new file mode 100644 index 00000000..561c2fdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEvent.cpp @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include "nsProxyEvent.h" +#include "nsProxyEventPrivate.h" +#include "nsIProxyObjectManager.h" +#include "nsCRT.h" + +#include "pratom.h" +#include "prmem.h" +#include "xptcall.h" + +#include "nsIComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsIEventQueueService.h" +#include "nsIThread.h" + +#include "nsIAtom.h" //hack! Need a way to define a component as threadsafe (ie. sta). + +/** + * Map the nsAUTF8String, nsUTF8String classes to the nsACString and + * nsCString classes respectively for now. These defines need to be removed + * once Jag lands his nsUTF8String implementation. + */ +#define nsAUTF8String nsACString +#define nsUTF8String nsCString + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +static void* PR_CALLBACK EventHandler(PLEvent *self); +static void PR_CALLBACK DestroyHandler(PLEvent *self); +static void* PR_CALLBACK CompletedEventHandler(PLEvent *self); +static void PR_CALLBACK CompletedDestroyHandler(PLEvent *self) ; +static void* PR_CALLBACK ProxyDestructorEventHandler(PLEvent *self); +static void PR_CALLBACK ProxyDestructorDestroyHandler(PLEvent *self) ; + +nsProxyObjectCallInfo::nsProxyObjectCallInfo( nsProxyObject* owner, + nsXPTMethodInfo *methodInfo, + PRUint32 methodIndex, + nsXPTCVariant* parameterList, + PRUint32 parameterCount, + PLEvent *event) +{ + NS_ASSERTION(owner, "No nsProxyObject!"); + NS_ASSERTION(methodInfo, "No nsXPTMethodInfo!"); + NS_ASSERTION(event, "No PLEvent!"); + + mCompleted = 0; + mMethodIndex = methodIndex; + mParameterList = parameterList; + mParameterCount = parameterCount; + mEvent = event; + mMethodInfo = methodInfo; + mCallersEventQ = nsnull; + + mOwner = owner; + + RefCountInInterfacePointers(PR_TRUE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_TRUE); +} + + +nsProxyObjectCallInfo::~nsProxyObjectCallInfo() +{ + RefCountInInterfacePointers(PR_FALSE); + if (mOwner->GetProxyType() & PROXY_ASYNC) + CopyStrings(PR_FALSE); + + mOwner = nsnull; + + PR_FREEIF(mEvent); + + if (mParameterList) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free((void*) mParameterList); +#else + free( (void*) mParameterList); +#endif +} + +void +nsProxyObjectCallInfo::RefCountInInterfacePointers(PRBool addRef) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i); + + if (paramInfo.GetType().IsInterfacePointer() ) + { + nsISupports* anInterface = nsnull; + + if (paramInfo.IsIn()) + { + anInterface = ((nsISupports*)mParameterList[i].val.p); + + if (anInterface) + { + if(addRef) + anInterface->AddRef(); + else + anInterface->Release(); + + } + } + } + } +} + +void +nsProxyObjectCallInfo::CopyStrings(PRBool copy) +{ + for (PRUint32 i = 0; i < mParameterCount; i++) + { + const nsXPTParamInfo paramInfo = mMethodInfo->GetParam(i); + + if(paramInfo.IsIn()) + { + const nsXPTType& type = paramInfo.GetType(); + uint8 type_tag = type.TagPart(); + void *ptr = mParameterList[i].val.p; + + if (!ptr) + continue; + + if (copy) + { + switch (type_tag) + { + case nsXPTType::T_CHAR_STR: + mParameterList[i].val.p = + PL_strdup((const char *)ptr); + break; + case nsXPTType::T_WCHAR_STR: + mParameterList[i].val.p = + nsCRT::strdup((const PRUnichar *)ptr); + break; + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_ASTRING: + mParameterList[i].val.p = + new nsString(*((nsAString*) ptr)); + break; + case nsXPTType::T_CSTRING: + mParameterList[i].val.p = + new nsCString(*((nsACString*) ptr)); + break; + case nsXPTType::T_UTF8STRING: + mParameterList[i].val.p = + new nsUTF8String(*((nsAUTF8String*) ptr)); + break; + default: + // Other types are ignored + break; + } + } + else + { + switch (type_tag) + { + case nsXPTType::T_CHAR_STR: + case nsXPTType::T_WCHAR_STR: + PL_strfree((char*) ptr); + break; + case nsXPTType::T_DOMSTRING: + case nsXPTType::T_ASTRING: + delete (nsString*) ptr; + break; + case nsXPTType::T_CSTRING: + delete (nsCString*) ptr; + break; + case nsXPTType::T_UTF8STRING: + delete (nsUTF8String*) ptr; + break; + default: + // Other types are ignored + break; + } + } + } + } +} + +PRBool +nsProxyObjectCallInfo::GetCompleted() +{ + return (PRBool)mCompleted; +} + +void +nsProxyObjectCallInfo::SetCompleted() +{ + PR_AtomicSet(&mCompleted, 1); +} + +void +nsProxyObjectCallInfo::PostCompleted() +{ + if (mCallersEventQ) + { + PLEvent *event = PR_NEW(PLEvent); + + PL_InitEvent(event, + this, + CompletedEventHandler, + CompletedDestroyHandler); + + mCallersEventQ->PostSynchronousEvent(event, nsnull); + PR_FREEIF(event); + } + else + { + // caller does not have an eventQ? This is an error! + SetCompleted(); + } +} + +nsIEventQueue* +nsProxyObjectCallInfo::GetCallersQueue() +{ + return mCallersEventQ; +} +void +nsProxyObjectCallInfo::SetCallersQueue(nsIEventQueue* queue) +{ + mCallersEventQ = queue; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, nsISupports *realObject) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + mRealObject = realObject; + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + + +nsProxyObject::nsProxyObject(nsIEventQueue *destQueue, PRInt32 proxyType, const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID) +{ + mEventQService = do_GetService(kEventQueueServiceCID); + + nsComponentManager::CreateInstance(aClass, + aDelegate, + aIID, + getter_AddRefs(mRealObject)); + + mDestQueue = do_QueryInterface(destQueue); + mProxyType = proxyType; +} + +nsProxyObject::~nsProxyObject() +{ + // I am worried about order of destruction here. + // do not remove assignments. + + mRealObject = 0; + mDestQueue = 0; +} + + +void +nsProxyObject::AddRef() +{ + PR_AtomicIncrement((PRInt32 *)&mRefCnt); + NS_LOG_ADDREF(this, mRefCnt, "nsProxyObject", sizeof(*this)); +} + +void +nsProxyObject::Release(void) +{ + NS_PRECONDITION(0 != mRefCnt, "dup release"); + + nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyObject"); + + if (count == 0) + { + mRefCnt = 1; /* stabilize */ + + PRBool callDirectly; + mDestQueue->IsOnCurrentThread(&callDirectly); + + if (callDirectly) + { + delete this; + return; + } + + // need to do something special here so that + // the real object will always be deleted on + // the correct thread.. + + PLEvent *event = PR_NEW(PLEvent); + if (event == nsnull) + { + NS_ASSERTION(0, "Could not create a plevent. Leaking nsProxyObject!"); + return; // if this happens we are going to leak. + } + + PL_InitEvent(event, + this, + ProxyDestructorEventHandler, + ProxyDestructorDestroyHandler); + + mDestQueue->PostEvent(event); + } +} + + +nsresult +nsProxyObject::PostAndWait(nsProxyObjectCallInfo *proxyInfo) +{ + if (proxyInfo == nsnull || mEventQService == nsnull) + return NS_ERROR_NULL_POINTER; + + PRBool eventLoopCreated = PR_FALSE; + nsresult rv; + + nsCOMPtr eventQ; + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + if (NS_FAILED(rv)) + { + rv = mEventQService->CreateMonitoredThreadEventQueue(); + eventLoopCreated = PR_TRUE; + if (NS_FAILED(rv)) + return rv; + + rv = mEventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); + } + + if (NS_FAILED(rv)) + return rv; + + proxyInfo->SetCallersQueue(eventQ); + + PLEvent* event = proxyInfo->GetPLEvent(); + if (!event) + return NS_ERROR_NULL_POINTER; + + mDestQueue->PostEvent(event); + + while (! proxyInfo->GetCompleted()) + { + PLEvent *nextEvent; + rv = eventQ->WaitForEvent(&nextEvent); + if (NS_FAILED(rv)) break; + + eventQ->HandleEvent(nextEvent); + } + + if (eventLoopCreated) + { + mEventQService->DestroyThreadEventQueue(); + eventQ = 0; + } + + return rv; +} + + +nsresult +nsProxyObject::convertMiniVariantToVariant(nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsXPTCVariant **fullParam, + uint8 *outParamCount) +{ + uint8 paramCount = methodInfo->GetParamCount(); + *outParamCount = paramCount; + *fullParam = nsnull; + + if (!paramCount) return NS_OK; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + *fullParam = (nsXPTCVariant*)nsMemory::Alloc(sizeof(nsXPTCVariant) * paramCount); +#else + *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount); +#endif + + if (*fullParam == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + for (int i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& paramInfo = methodInfo->GetParam(i); + if ((mProxyType & PROXY_ASYNC) && paramInfo.IsDipper()) + { + NS_WARNING("Async proxying of out parameters is not supported"); + return NS_ERROR_PROXY_INVALID_OUT_PARAMETER; + } + uint8 flags = paramInfo.IsOut() ? nsXPTCVariant::PTR_IS_DATA : 0; + (*fullParam)[i].Init(params[i], paramInfo.GetType(), flags); + } + + return NS_OK; +} + +nsresult +nsProxyObject::Post( PRUint32 methodIndex, + nsXPTMethodInfo *methodInfo, + nsXPTCMiniVariant * params, + nsIInterfaceInfo *interfaceInfo) +{ + nsresult rv = NS_OK; + + if (! mDestQueue || ! mRealObject) + return NS_ERROR_OUT_OF_MEMORY; + + if (methodInfo->IsNotXPCOM()) + return NS_ERROR_PROXY_INVALID_IN_PARAMETER; + + nsXPTCVariant *fullParam; + uint8 paramCount; + rv = convertMiniVariantToVariant(methodInfo, params, &fullParam, ¶mCount); + + if (NS_FAILED(rv)) + return rv; + + PRBool callDirectly; + + // see if we should call into the method directly. Either it is a QI function call + // (methodIndex == 0), or it is a sync proxy and this code is running on the same thread + // as the destination event queue. + if ( (methodIndex == 0) || + (mProxyType & PROXY_SYNC && + NS_SUCCEEDED(mDestQueue->IsOnCurrentThread(&callDirectly)) && + callDirectly)) + { + + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( mRealObject, + methodIndex, + paramCount, + fullParam); + + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return rv; + } + + PLEvent *event = PR_NEW(PLEvent); + + if (event == nsnull) { + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + nsProxyObjectCallInfo *proxyInfo = new nsProxyObjectCallInfo(this, + methodInfo, + methodIndex, + fullParam, // will be deleted by ~() + paramCount, + event); // will be deleted by ~() + + if (proxyInfo == nsnull) { + PR_DELETE(event); + if (fullParam) +#ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(fullParam); +#else + free(fullParam); +#endif + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(event, + proxyInfo, + EventHandler, + DestroyHandler); + + if (mProxyType & PROXY_SYNC) + { + rv = PostAndWait(proxyInfo); + + if (NS_SUCCEEDED(rv)) + rv = proxyInfo->GetResult(); + delete proxyInfo; + return rv; + } + + if (mProxyType & PROXY_ASYNC) + { + mDestQueue->PostEvent(event); + return NS_OK; + } + return NS_ERROR_UNEXPECTED; +} + + + +static void DestroyHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + nsProxyObject* proxyObject = owner->GetProxyObject(); + + if (proxyObject == nsnull) + return; + + if (proxyObject->GetProxyType() & PROXY_ASYNC) + { + delete owner; + } + else + { + owner->PostCompleted(); + } + +} + +static void* EventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo *info = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + NS_ASSERTION(info, "No nsProxyObjectCallInfo!"); + + nsProxyObject *proxyObject = info->GetProxyObject(); + + if (proxyObject) + { + // invoke the magic of xptc... + nsresult rv = XPTC_InvokeByIndex( proxyObject->GetRealObject(), + info->GetMethodIndex(), + info->GetParameterCount(), + info->GetParameterList()); + info->SetResult(rv); + } + else + { + info->SetResult(NS_ERROR_OUT_OF_MEMORY); + } + return NULL; +} + +static void CompletedDestroyHandler(PLEvent *self) +{ +} + +static void* CompletedEventHandler(PLEvent *self) +{ + nsProxyObjectCallInfo* owner = (nsProxyObjectCallInfo*)PL_GetEventOwner(self); + owner->SetCompleted(); + return nsnull; +} + +static void* ProxyDestructorEventHandler(PLEvent *self) +{ + nsProxyObject* owner = (nsProxyObject*) PL_GetEventOwner(self); + NS_DELETEXPCOM(owner); + return nsnull; +} + +static void ProxyDestructorDestroyHandler(PLEvent *self) +{ + PR_DELETE(self); +} + diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp new file mode 100644 index 00000000..8e221afa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventClass.cpp @@ -0,0 +1,367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nsMemory.h" +#include "nsHashtable.h" + +#include "nsAutoLock.h" +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +// LIFETIME_CACHE will cache class for the entire cyle of the application. +#define LIFETIME_CACHE + +static uint32 zero_methods_descriptor; + + +/* ssc@netscape.com wishes he could get rid of this instance of + * |NS_DEFINE_IID|, but |ProxyEventClassIdentity| is not visible from + * here. + */ +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + +////////////////////////////////////////////////////////////////////////////////////////////////// +// nsProxyEventClass +////////////////////////////////////////////////////////////////////////////////////////////////// +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyEventClass, nsProxyEventClass) + +// static +nsProxyEventClass* +nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID) +{ + /* find in our hash table */ + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return nsnull; + + // dont need to lock the map, because this is only called + // by nsProxyEventClass::GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap == nsnull) + { + return nsnull; + } + + nsProxyEventClass* clazz = nsnull; + nsIDKey key(aIID); + +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s\n", iidStr); + nsCRT::free(iidStr); +#endif + + clazz = (nsProxyEventClass*) iidToClassMap->Get(&key); + if(clazz) + { + NS_ADDREF(clazz); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s hit\n", iidStr); + nsCRT::free(iidStr); +#endif + } + else + { + nsCOMPtr iimgr = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + if(iimgr) + { + nsCOMPtr info; + if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, getter_AddRefs(info)))) + { + /* + Check to see if isISupportsDescendent + */ + nsCOMPtr oldest = info; + nsCOMPtr parent; + + while(NS_SUCCEEDED(oldest->GetParent(getter_AddRefs(parent)))&& + parent) + { + oldest = parent; + } + + PRBool isISupportsDescendent = PR_FALSE; + nsID* iid; + if(NS_SUCCEEDED(oldest->GetInterfaceIID(&iid))) + { + isISupportsDescendent = iid->Equals(NS_GET_IID(nsISupports)); + nsMemory::Free(iid); + } + + NS_ASSERTION(isISupportsDescendent, "!isISupportsDescendent"); + + if (isISupportsDescendent) + { + clazz = new nsProxyEventClass(aIID, info); + if(!clazz->mDescriptors) + NS_RELEASE(clazz); // sets clazz to NULL + } + } + } + } + return clazz; +} + +nsProxyEventClass::nsProxyEventClass() +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo) +: mIID(aIID), + mDescriptors(NULL) +{ + NS_ADDREF_THIS(); + + mInfo = aInfo; + + /* add use to the used classes */ + nsIDKey key(aIID); + + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) return; + // dont need to lock the map, because this is only called + // by GetNewOrUsed which locks it for us. + + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Put(&key, this); +#ifdef LIFETIME_CACHE + // extra addref to hold it in the cache + NS_ADDREF_THIS(); +#endif +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = aIID.ToString(); + printf("GetNewOrUsedClass %s put\n", iidStr); + nsCRT::free(iidStr); +#endif + } + + uint16 methodCount; + if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount))) + { + if(methodCount) + { + int wordCount = (methodCount/32)+1; + if(NULL != (mDescriptors = new uint32[wordCount])) + { + memset(mDescriptors, 0, wordCount * sizeof(uint32)); + } + } + else + { + mDescriptors = &zero_methods_descriptor; + } + } +} + +nsProxyEventClass::~nsProxyEventClass() +{ + if(mDescriptors && mDescriptors != &zero_methods_descriptor) + delete [] mDescriptors; + + if (nsProxyObjectManager::IsManagerShutdown()) + return; + +#ifndef LIFETIME_CACHE + nsIDKey key(mIID); + + nsCOMPtr manager = getter_AddRefs(nsProxyObjectManager::GetInstance()); + if (manager == nsnull) return; + nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap(); + + if (iidToClassMap != nsnull) + { + iidToClassMap->Remove(&key); +#ifdef PROXYEVENTCLASS_DEBUG + char* iidStr = mIID.ToString(); + printf("GetNewOrUsedClass %s remove\n", iidStr); + nsCRT::free(iidStr); +#endif + } +#endif +} + +nsresult +nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID aIID, nsProxyEventObject** aInstancePtr) +{ + NS_PRECONDITION(aInstancePtr, "Requires non-null result"); + + nsresult rv; + + *aInstancePtr = nsnull; // in case of error. + + + // The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr) + + nsXPTCMiniVariant var[2]; + + var[0].val.p = (void*)&aIID; + var[1].val.p = (void*)aInstancePtr; + + nsCOMPtr interfaceInfo; + const nsXPTMethodInfo *mi; + + nsCOMPtr iim = getter_AddRefs(XPTI_GetInterfaceInfoManager()); + + if (!iim) return NS_NOINTERFACE; + iim->GetInfoForName("nsISupports", getter_AddRefs(interfaceInfo)); + interfaceInfo->GetMethodInfo(0, &mi); // 0 is QueryInterface + + rv = self->CallMethod(0, mi, var); + + if (NS_SUCCEEDED(rv)) + { + nsISupports *aIdentificationObject; + + rv = (*aInstancePtr)->QueryInterface(kProxyObject_Identity_Class_IID, (void**)&aIdentificationObject); + + if (NS_FAILED(rv)) + { + // okay, aInstancePtr was not a proxy. Lets create one. + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (manager == nsnull) + { + NS_IF_RELEASE((*aInstancePtr)); + return NS_ERROR_FAILURE; + } + + rv = manager->GetProxyForObject(self->GetQueue(), + aIID, + self->GetRealObject(), + self->GetProxyType(), + (void**) &aIdentificationObject); + } + + NS_IF_RELEASE((*aInstancePtr)); + (*aInstancePtr) = NS_STATIC_CAST(nsProxyEventObject*, aIdentificationObject); + } + return rv; +} + + +/***************************************************************************/ +// This 'ProxyEventClassIdentity' class and singleton allow us to figure out if +// any given nsISupports* is implemented by a nsProxy object. This is done +// using a QueryInterface call on the interface pointer with our ID. If +// that call returns NS_OK and the pointer is to a nsProxyEventObject. It must +// be released when done. + +// NS_PROXYEVENT_IDENTITY_CLASS_IID defined in nsProxyEventPrivate.h +class ProxyEventClassIdentity +{ + // no instance methods... +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID) + + static void* GetSingleton() + { + static ProxyEventClassIdentity* singleton = NULL; + if(!singleton) + singleton = new ProxyEventClassIdentity(); + return (void*) singleton; + } +}; + +NS_IMETHODIMP +nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr) +{ + + if(aIID.Equals(NS_GET_IID(ProxyEventClassIdentity))) + { + *aInstancePtr = NS_STATIC_CAST(void*, self); + NS_ADDREF(self); + return NS_OK; + } + + nsProxyEventObject* sibling; + { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager->GetMonitor()); + + // This includes checking for nsISupports and the iid of self. + // And it also checks for other wrappers that have been constructed + // for this object. + if(nsnull != (sibling = self->LockedFind(aIID))) + { + NS_ADDREF(sibling); + *aInstancePtr = (void*) sibling; + return NS_OK; + } + + // check if asking for an interface that we inherit from + nsCOMPtr current = GetInterfaceInfo(); + nsCOMPtr parent; + + while(NS_SUCCEEDED(current->GetParent(getter_AddRefs(parent))) && parent) + { + current = parent; + + nsIID* iid; + if(NS_SUCCEEDED(current->GetInterfaceIID(&iid)) && iid) + { + PRBool found = aIID.Equals(*iid); + nsMemory::Free(iid); + if(found) + { + *aInstancePtr = (void*) self; + NS_ADDREF(self); + return NS_OK; + } + } + } + } + + return CallQueryInterfaceOnProxy(self, aIID, (nsProxyEventObject**)aInstancePtr); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp new file mode 100644 index 00000000..d529fc05 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventObject.cpp @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prprf.h" +#include "prmem.h" + +#include "nscore.h" +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsHashtable.h" + +#include "nsIInterfaceInfoManager.h" +#include "xptcall.h" + +#include "nsAutoLock.h" + +static NS_DEFINE_IID(kProxyObject_Identity_Class_IID, NS_PROXYEVENT_IDENTITY_CLASS_IID); + + +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyEventKey : public nsHashKey +{ +public: + nsProxyEventKey(void* rootObjectKey, void* destQueueKey, PRInt32 proxyType) + : mRootObjectKey(rootObjectKey), mDestQueueKey(destQueueKey), mProxyType(proxyType) { + } + + PRUint32 HashCode(void) const { + return NS_PTR_TO_INT32(mRootObjectKey) ^ + NS_PTR_TO_INT32(mDestQueueKey) ^ mProxyType; + } + + PRBool Equals(const nsHashKey *aKey) const { + const nsProxyEventKey* other = (const nsProxyEventKey*)aKey; + return mRootObjectKey == other->mRootObjectKey + && mDestQueueKey == other->mDestQueueKey + && mProxyType == other->mProxyType; + } + + nsHashKey *Clone() const { + return new nsProxyEventKey(mRootObjectKey, mDestQueueKey, mProxyType); + } + +protected: + void* mRootObjectKey; + void* mDestQueueKey; + PRInt32 mProxyType; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG_xpcom_proxy +static PRMonitor* mon = nsnull; +static PRUint32 totalProxyObjects = 0; +static PRUint32 outstandingProxyObjects = 0; + +void +nsProxyEventObject::DebugDump(const char * message, PRUint32 hashKey) +{ + + if (mon == nsnull) + { + mon = PR_NewMonitor(); + } + + PR_EnterMonitor(mon); + + if (message) + { + printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + printf("%s\n", message); + + if(strcmp(message, "Create") == 0) + { + totalProxyObjects++; + outstandingProxyObjects++; + } + else if(strcmp(message, "Delete") == 0) + { + outstandingProxyObjects--; + } + } + printf("nsProxyEventObject @ %x with mRefCnt = %d\n", this, mRefCnt); + + PRBool isRoot = mRoot == nsnull; + printf("%s wrapper around @ %x\n", isRoot ? "ROOT":"non-root\n", GetRealObject()); + + nsCOMPtr rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); + printf("Hashkey: %d\n", key.HashCode()); + + char* name; + GetClass()->GetInterfaceInfo()->GetName(&name); + printf("interface name is %s\n", name); + if(name) + nsMemory::Free(name); + char * iid = GetClass()->GetProxiedIID().ToString(); + printf("IID number is %s\n", iid); + delete iid; + printf("nsProxyEventClass @ %x\n", mClass); + + if(mNext) + { + if(isRoot) + { + printf("Additional wrappers for this object...\n"); + } + mNext->DebugDump(nsnull, 0); + } + + printf("[proxyobjects] %d total used in system, %d outstading\n", totalProxyObjects, outstandingProxyObjects); + + if (message) + printf("-=-=-=-=-=-=-=-=-=-=-=-=-\n"); + + PR_ExitMonitor(mon); +} +#endif + + + +////////////////////////////////////////////////////////////////////////////////////////////////// +// +// nsProxyEventObject +// +////////////////////////////////////////////////////////////////////////////////////////////////// +nsProxyEventObject* +nsProxyEventObject::GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID) +{ + nsresult rv; + + if (!aObj) + return nsnull; + + nsISupports* rawObject = aObj; + + // + // make sure that the object pass in is not a proxy... + // if the object *is* a proxy, then be nice and build the proxy + // for the real object... + // + nsCOMPtr identificationObject; + + rv = rawObject->QueryInterface(kProxyObject_Identity_Class_IID, + getter_AddRefs(identificationObject)); + if (NS_SUCCEEDED(rv)) { + // + // ATTENTION!!!! + // + // If you are hitting any of the assertions in this block of code, + // please contact dougt@netscape.com. + // + + // if you hit this assertion, you might want to check out how + // you are using proxies. You shouldn't need to be creating + // a proxy from a proxy. -- dougt@netscape.com + NS_ASSERTION(0, "Someone is building a proxy from a proxy"); + + NS_ASSERTION(identificationObject, "where did my identification object go!"); + if (!identificationObject) { + return nsnull; + } + + // someone is asking us to create a proxy for a proxy. Lets get + // the real object and build aproxy for that! + rawObject = identificationObject->GetRealObject(); + + NS_ASSERTION(rawObject, "where did my real object go!"); + if (!rawObject) { + return nsnull; + } + } + + // + // Get the root nsISupports of the |real| object. + // + nsCOMPtr rootObject; + + rootObject = do_QueryInterface(rawObject, &rv); + if (NS_FAILED(rv) || !rootObject) { + NS_ASSERTION(NS_FAILED(rv), "where did my root object go!"); + return nsnull; + } + + // Get the root nsISupports of the event queue... This is used later, + // as part of the hashtable key... + nsCOMPtr destQRoot = do_QueryInterface(destQueue, &rv); + if (NS_FAILED(rv) || !destQRoot) { + return nsnull; + } + + // + // Enter the proxy object creation lock. + // + // This lock protects thev linked list which chains proxies together + // (ie. mRoot and mNext) and ensures that there is no hashtable contention + // between the time that a proxy is looked up (and not found) in the + // hashtable and then added... + // + nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance(); + if (!manager) { + return nsnull; + } + + nsAutoMonitor mon(manager->GetMonitor()); + + // Get the hash table containing root proxy objects... + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + if (!realToProxyMap) { + return nsnull; + } + + // Now, lookup the root nsISupports of the raw object in the hashtable + // The key consists of 3 pieces of information: + // - root nsISupports of the raw object + // - event queue of the current thread + // - type of proxy being constructed... + // + nsProxyEventKey rootkey(rootObject.get(), destQRoot.get(), proxyType); + + nsCOMPtr rootProxy; + nsCOMPtr proxy; + nsProxyEventObject* peo; + + // find in our hash table + rootProxy = (nsProxyEventObject*) realToProxyMap->Get(&rootkey); + + if(rootProxy) { + // + // At least one proxy has already been created for this raw object... + // + // Look for the specific interface proxy in the list off of + // the root proxy... + // + peo = rootProxy->LockedFind(aIID); + + if(peo) { + // An existing proxy is available... So use it. + NS_ADDREF(peo); + return peo; + } + } + else { + // build the root proxy + nsCOMPtr rootClazz; + + rootClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass( + NS_GET_IID(nsISupports))); + if (!rootClazz) { + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rootObject, + rootClazz, + nsnull); + if(!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // Add this root proxy into the hash table... + realToProxyMap->Put(&rootkey, peo); + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + // + // Since the requested proxy is for the nsISupports interface of + // the raw object, use the new root proxy as the specific proxy + // too... + // + NS_ADDREF(peo); + return peo; + } + + // This assignment is an owning reference to the new ProxyEventObject. + // So, it will automatically get deleted if any subsequent early + // returns are taken... + rootProxy = do_QueryInterface(peo); + } + + // + // at this point we have a proxy for the root nsISupports (ie. rootProxy) + // but we need to build the specific proxy for this interface... + // + NS_ASSERTION(rootProxy, "What happened to the root proxy!"); + + // Get a class for this IID. + nsCOMPtr proxyClazz; + + proxyClazz = dont_AddRef(nsProxyEventClass::GetNewOrUsedClass(aIID)); + if(!proxyClazz) { + return nsnull; + } + + // Get the raw interface for this IID + nsCOMPtr rawInterface; + + rv = rawObject->QueryInterface(aIID, getter_AddRefs(rawInterface)); + if (NS_FAILED(rv) || !rawInterface) { + NS_ASSERTION(NS_FAILED(rv), "where did my rawInterface object go!"); + return nsnull; + } + + peo = new nsProxyEventObject(destQueue, + proxyType, + rawInterface, + proxyClazz, + rootProxy); + if (!peo) { + // Ouch... Out of memory! + return nsnull; + } + + // + // Add the new specific proxy to the head of the list of proxies hanging + // off of the rootProxy... + // + peo->mNext = rootProxy->mNext; + rootProxy->mNext = peo; + + NS_ADDREF(peo); + return peo; + +} + +nsProxyEventObject* nsProxyEventObject::LockedFind(REFNSIID aIID) +{ + if(aIID.Equals(mClass->GetProxiedIID())) { + return this; + } + + if(aIID.Equals(NS_GET_IID(nsISupports))) { + return this; + } + + nsProxyEventObject* cur = (mRoot ? mRoot : mNext); + while(cur) { + if(aIID.Equals(cur->GetClass()->GetProxiedIID())) { + return cur; + } + cur = cur->mNext; + } + + return nsnull; +} + +nsProxyEventObject::nsProxyEventObject() +: mNext(nsnull) +{ + NS_WARNING("This constructor should never be called"); +} + +nsProxyEventObject::nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root) + : mClass(aClass), + mRoot(root), + mNext(nsnull) +{ + NS_IF_ADDREF(mRoot); + + mProxyObject = new nsProxyObject(destQueue, proxyType, aObj); + +#ifdef DEBUG_xpcom_proxy + DebugDump("Create", 0); +#endif +} + +nsProxyEventObject::~nsProxyEventObject() +{ +#ifdef DEBUG_xpcom_proxy + DebugDump("Delete", 0); +#endif + if (mRoot) { + // + // This proxy is not the root interface so it must be removed + // from the chain of proxies... + // + nsProxyEventObject* cur = mRoot; + while(cur) { + if(cur->mNext == this) { + cur->mNext = mNext; + mNext = nsnull; + break; + } + cur = cur->mNext; + } + NS_ASSERTION(cur, "failed to find wrapper in its own chain"); + } + else { + // + // This proxy is for the root interface. Each proxy in the chain + // has a strong reference to the root... So, when its refcount goes + // to zero, it safe to remove it because no proxies are in its chain. + // + if (! nsProxyObjectManager::IsManagerShutdown()) { + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap(); + + NS_ASSERTION(!mNext, "There are still proxies in the chain!"); + + if (realToProxyMap != nsnull) { + nsCOMPtr rootObject = do_QueryInterface(mProxyObject->mRealObject); + nsCOMPtr rootQueue = do_QueryInterface(mProxyObject->mDestQueue); + nsProxyEventKey key(rootObject, rootQueue, mProxyObject->mProxyType); +#ifdef DEBUG_dougt + void* value = +#endif + realToProxyMap->Remove(&key); +#ifdef DEBUG_dougt + NS_ASSERTION(value, "failed to remove from realToProxyMap"); +#endif + } + } + } + + // I am worried about ordering. + // do not remove assignments. + mProxyObject = nsnull; + mClass = nsnull; + NS_IF_RELEASE(mRoot); +} + +// +// nsISupports implementation... +// + +NS_IMPL_THREADSAFE_ADDREF(nsProxyEventObject) + +NS_IMETHODIMP_(nsrefcnt) +nsProxyEventObject::Release(void) +{ + // + // Be pessimistic about whether the manager or even the monitor exist... + // This is to protect against shutdown issues where a proxy object could + // be destroyed after (or while) the Proxy Manager is being destroyed... + // + nsProxyObjectManager* manager = nsProxyObjectManager::GetInstance(); + nsAutoMonitor mon(manager ? manager->GetMonitor() : nsnull); + + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + // Decrement atomically - in case the Proxy Object Manager has already + // been deleted and the monitor is unavailable... + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsProxyEventObject"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + // + // Remove the proxy from the hashtable (if necessary) or its + // proxy chain. This must be done inside of the proxy lock to + // prevent GetNewOrUsedProxy(...) from ressurecting it... + // + NS_DELETEXPCOM(this); + return 0; + } + return count; +} + +NS_IMETHODIMP +nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if( aIID.Equals(GetIID()) ) + { + *aInstancePtr = NS_STATIC_CAST(nsISupports*, this); + NS_ADDREF_THIS(); + return NS_OK; + } + + return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr); +} + +// +// nsXPTCStubBase implementation... +// + +NS_IMETHODIMP +nsProxyEventObject::GetInterfaceInfo(nsIInterfaceInfo** info) +{ + NS_ENSURE_ARG_POINTER(info); + + *info = mClass->GetInterfaceInfo(); + + NS_ASSERTION(*info, "proxy class without interface"); + if (!*info) { + return NS_ERROR_UNEXPECTED; + } + + NS_ADDREF(*info); + return NS_OK; +} + +NS_IMETHODIMP +nsProxyEventObject::CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant * params) +{ + nsresult rv; + + if (mProxyObject) { + rv = mProxyObject->Post(methodIndex, + (nsXPTMethodInfo*)info, + params, + mClass->GetInterfaceInfo()); + } else { + rv = NS_ERROR_NULL_POINTER; + } + + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h new file mode 100644 index 00000000..ee34927e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyEventPrivate.h @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __nsProxyEventPrivate_h_ +#define __nsProxyEventPrivate_h_ + +#include "nscore.h" +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsHashtable.h" + +#include "plevent.h" +#include "xptcall.h" // defines nsXPTCVariant +#include "nsIEventQueue.h" + +#include "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" + +class nsProxyEventObject; +class nsProxyEventClass; + +#define NS_PROXYEVENT_CLASS_IID \ +{ 0xeea90d42, \ + 0xb059, \ + 0x11d2, \ + {0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33}\ +} + +#define NS_PROXYEVENT_IDENTITY_CLASS_IID \ +{ 0xeea90d45, 0xb059, 0x11d2, \ + { 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } } + + +#define NS_PROXYEVENT_OBJECT_IID \ +{ 0xec373590, 0x9164, 0x11d3, \ +{0x8c, 0x73, 0x00, 0x00, 0x64, 0x65, 0x73, 0x74} } + + +class nsProxyEventClass : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_CLASS_IID) + static nsProxyEventClass* GetNewOrUsedClass(REFNSIID aIID); + + NS_IMETHOD DelegatedQueryInterface( nsProxyEventObject* self, + REFNSIID aIID, + void** aInstancePtr); + + + nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo;} + const nsIID& GetProxiedIID() const {return mIID; } +protected: + nsProxyEventClass(); + nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo); + +private: + ~nsProxyEventClass(); + + nsIID mIID; + nsCOMPtr mInfo; + uint32* mDescriptors; + + nsresult CallQueryInterfaceOnProxy(nsProxyEventObject* self, + REFNSIID aIID, + nsProxyEventObject** aInstancePtr); +}; + + + +class nsProxyEventObject : public nsXPTCStubBase +{ +public: + + NS_DECL_ISUPPORTS + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_OBJECT_IID) + + static nsProxyEventObject* GetNewOrUsedProxy(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports *aObj, + REFNSIID aIID); + + + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info); + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, const nsXPTMethodInfo* info, nsXPTCMiniVariant* params); + + + nsProxyEventClass* GetClass() const { return mClass; } + nsIEventQueue* GetQueue() const { return (mProxyObject ? mProxyObject->GetQueue() : nsnull);} + nsISupports* GetRealObject() const { return (mProxyObject ? mProxyObject->GetRealObject(): nsnull);} + PRInt32 GetProxyType() const { return (mProxyObject ? mProxyObject->GetProxyType() : nsnull);} + + nsProxyEventObject(); + nsProxyEventObject(nsIEventQueue *destQueue, + PRInt32 proxyType, + nsISupports* aObj, + nsProxyEventClass* aClass, + nsProxyEventObject* root); + + nsProxyEventObject* LockedFind(REFNSIID aIID); + +#ifdef DEBUG_xpcom_proxy + void DebugDump(const char * message, PRUint32 hashKey); +#endif + +private: + ~nsProxyEventObject(); + +protected: + void LockedRemoveProxy(); + +protected: + nsCOMPtr mClass; + nsRefPtr mProxyObject; + + // Owning reference... + nsProxyEventObject *mRoot; + + // Weak reference... + nsProxyEventObject *mNext; +}; + + + + +//////////////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +//////////////////////////////////////////////////////////////////////////////// + +class nsProxyObjectManager: public nsIProxyObjectManager +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROXYOBJECTMANAGER + + + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + nsProxyObjectManager(); + + static nsProxyObjectManager *GetInstance(); + static PRBool IsManagerShutdown(); + + static void Shutdown(); + + nsHashtable* GetRealObjectToProxyObjectMap() { return &mProxyObjectMap;} + nsHashtable* GetIIDToProxyClassMap() { return &mProxyClassMap; } + + PRMonitor* GetMonitor() const { return mProxyCreationMonitor; } + +private: + ~nsProxyObjectManager(); + + static nsProxyObjectManager* mInstance; + nsHashtable mProxyObjectMap; + nsHashtable mProxyClassMap; + PRMonitor *mProxyCreationMonitor; +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp new file mode 100644 index 00000000..0602bcd7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyObjectManager.cpp @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Doug Turner (Original Author) + * Judson Valeski + * Dan Matejka + * Scott Collins + * Heikki Toivonen + * Patrick Beard + * Pierre Phaneuf + * Warren Harris + * Chris Seawood + * Chris Waterson + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsProxyEvent.h" +#include "nsIProxyObjectManager.h" +#include "nsProxyEventPrivate.h" + +#include "nsIProxyCreateInstance.h" + +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsCOMPtr.h" + +#include "nsIEventQueueService.h" +#include "nsIThread.h" + + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* nsProxyCreateInstance */ +/* This private class will allow us to create Instances on another thread */ +/***************************************************************************/ +class nsProxyCreateInstance : public nsIProxyCreateInstance +{ + NS_DECL_ISUPPORTS + NS_IMETHOD CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result); + NS_IMETHOD CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result); + + nsProxyCreateInstance() {} + +private: + ~nsProxyCreateInstance() {} +}; + +NS_IMPL_ISUPPORTS1(nsProxyCreateInstance, nsIProxyCreateInstance) + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByIID(const nsIID & cid, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( cid, + aOuter, + iid, + result); +} + + +NS_IMETHODIMP nsProxyCreateInstance::CreateInstanceByContractID(const char *aContractID, nsISupports *aOuter, const nsIID & iid, void * *result) +{ + return nsComponentManager::CreateInstance( aContractID, + aOuter, + iid, + result); +} + +///////////////////////////////////////////////////////////////////////// +// nsProxyObjectManager +///////////////////////////////////////////////////////////////////////// + +nsProxyObjectManager* nsProxyObjectManager::mInstance = nsnull; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsProxyObjectManager, nsIProxyObjectManager) + +nsProxyObjectManager::nsProxyObjectManager() + : mProxyObjectMap(256, PR_TRUE), + mProxyClassMap(256, PR_TRUE) +{ + mProxyCreationMonitor = PR_NewMonitor(); +} + +static PRBool PurgeProxyClasses(nsHashKey *aKey, void *aData, void* closure) +{ + nsProxyEventClass* ptr = NS_REINTERPRET_CAST(nsProxyEventClass*, aData); + NS_RELEASE(ptr); + return PR_TRUE; +} + +nsProxyObjectManager::~nsProxyObjectManager() +{ + mProxyClassMap.Reset((nsHashtableEnumFunc)PurgeProxyClasses, nsnull); + + if (mProxyCreationMonitor) { + PR_DestroyMonitor(mProxyCreationMonitor); + } + + nsProxyObjectManager::mInstance = nsnull; +} + +PRBool +nsProxyObjectManager::IsManagerShutdown() +{ + if (mInstance) + return PR_FALSE; + return PR_TRUE; +} + +nsProxyObjectManager * +nsProxyObjectManager::GetInstance() +{ + if (! mInstance) + { + mInstance = new nsProxyObjectManager(); + } + return mInstance; +} + + +void +nsProxyObjectManager::Shutdown() +{ + mInstance = nsnull; +} + + +// Helpers +NS_IMETHODIMP +nsProxyObjectManager::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + nsProxyObjectManager *proxyObjectManager = GetInstance(); + + if (proxyObjectManager == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + + return proxyObjectManager->QueryInterface(aIID, aInstancePtr); +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aObj) return NS_ERROR_NULL_POINTER; + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + + nsresult rv; + nsCOMPtr postQ; + + + *aProxyObject = nsnull; + + // check to see if the destination Q is a special case. + + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = eventQService->ResolveEventQueue(destQueue, getter_AddRefs(postQ)); + if (NS_FAILED(rv)) + return rv; + + // check to see if the eventQ is on our thread. If so, just return the real object. + + if (postQ && !(proxyType & PROXY_ASYNC) && !(proxyType & PROXY_ALWAYS)) + { + PRBool aResult; + postQ->IsOnCurrentThread(&aResult); + + if (aResult) + { + return aObj->QueryInterface(aIID, aProxyObject); + } + } + + // check to see if proxy is there or not. + *aProxyObject = nsProxyEventObject::GetNewOrUsedProxy(postQ, proxyType, aObj, aIID); + + if (*aProxyObject == nsnull) + return NS_ERROR_NO_INTERFACE; //fix error code? + + return NS_OK; +} + + +NS_IMETHODIMP +nsProxyObjectManager::GetProxy( nsIEventQueue *destQueue, + const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + PRInt32 proxyType, + void** aProxyObject) +{ + if (!aProxyObject) return NS_ERROR_NULL_POINTER; + *aProxyObject = nsnull; + + // 1. Create a proxy for creating an instance on another thread. + + nsIProxyCreateInstance* ciProxy = nsnull; + + nsProxyCreateInstance* ciObject = new nsProxyCreateInstance(); + + if (ciObject == nsnull) + return NS_ERROR_NULL_POINTER; + + NS_ADDREF(ciObject); + + nsresult rv = GetProxyForObject(destQueue, + NS_GET_IID(nsIProxyCreateInstance), + ciObject, + PROXY_SYNC, + (void**)&ciProxy); + + if (NS_FAILED(rv)) + { + NS_RELEASE(ciObject); + return rv; + } + + // 2. now create a new instance of the request object via our proxy. + + nsISupports* aObj; + + rv = ciProxy->CreateInstanceByIID(aClass, + aDelegate, + aIID, + (void**)&aObj); + + + // 3. Delete the create instance proxy and its real object. + + NS_RELEASE(ciProxy); + NS_RELEASE(ciObject); + + // 4. Check to see if creating the requested instance failed. + if ( NS_FAILED(rv)) + { + return rv; + } + + // 5. Now create a proxy object for the requested object. + + rv = GetProxyForObject(destQueue, aIID, aObj, proxyType, aProxyObject); + + // 6. release ownership of aObj so that aProxyObject owns it. + + NS_RELEASE(aObj); + + // 7. return the error returned from GetProxyForObject. Either way, we our out of here. + + return rv; +} + +/** + * Helper function for code that already has a link-time dependency on + * libxpcom and needs to get proxies in a bunch of different places. + * This way, the caller isn't forced to get the proxy object manager + * themselves every single time, thus making the calling code more + * readable. + */ +NS_COM nsresult +NS_GetProxyForObject(nsIEventQueue *destQueue, + REFNSIID aIID, + nsISupports* aObj, + PRInt32 proxyType, + void** aProxyObject) +{ + static NS_DEFINE_CID(proxyObjMgrCID, NS_PROXYEVENT_MANAGER_CID); + + nsresult rv; // temp for return value + + // get the proxy object manager + // + nsCOMPtr proxyObjMgr = + do_GetService(proxyObjMgrCID, &rv); + + if (NS_FAILED(rv)) + return NS_ERROR_FAILURE; + + // and try to get the proxy object + // + return proxyObjMgr->GetProxyForObject(destQueue, aIID, aObj, + proxyType, aProxyObject); +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp new file mode 100644 index 00000000..3ceeb667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/src/nsProxyRelease.cpp @@ -0,0 +1,55 @@ +#include "nsProxyRelease.h" + +PR_STATIC_CALLBACK(void*) +HandleProxyReleaseEvent(PLEvent *self) +{ + nsISupports* owner = (nsISupports*) self->owner; + NS_RELEASE(owner); + return nsnull; +} + +PR_STATIC_CALLBACK(void) +DestroyProxyReleaseEvent(PLEvent *self) +{ + delete self; +} + +NS_COM nsresult +NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, PRBool alwaysProxy) +{ + nsresult rv; + + if (!target) { + NS_RELEASE(doomed); + return NS_OK; + } + + if (!alwaysProxy) { + PRBool onCurrentThread = PR_FALSE; + rv = target->IsOnCurrentThread(&onCurrentThread); + if (NS_SUCCEEDED(rv) && onCurrentThread) { + NS_RELEASE(doomed); + return NS_OK; + } + } + + PLEvent *ev = new PLEvent; + if (!ev) { + // we do not release doomed here since it may cause a delete on the + // wrong thread. better to leak than crash. + return NS_ERROR_OUT_OF_MEMORY; + } + + PL_InitEvent(ev, doomed, + HandleProxyReleaseEvent, + DestroyProxyReleaseEvent); + + rv = target->PostEvent(ev); + if (NS_FAILED(rv)) { + NS_WARNING("failed to post proxy release event"); + PL_DestroyEvent(ev); + // again, it is better to leak the doomed object than risk crashing as + // a result of deleting it on the wrong thread. + } + return rv; +} diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore new file mode 100644 index 00000000..b7457ff6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +proxytests diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in new file mode 100644 index 00000000..e5e908f1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = proxytest +REQUIRES = $(NULL) + +CPPSRCS = proxytests.cpp +XPIDLSRCS = nsITestProxy.idl + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl new file mode 100644 index 00000000..98cb3f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/nsITestProxy.idl @@ -0,0 +1,9 @@ +#include "nsISupports.idl" + +[uuid(1979e980-1cfd-11d3-915e-0000863011c4)] +interface nsITestProxy : nsISupports +{ + long Test(in long p1, in long p2); + void Test2(); + void Test3(in nsISupports p1, out nsISupports p2); +}; diff --git a/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp new file mode 100644 index 00000000..20693463 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/proxy/tests/proxytests.cpp @@ -0,0 +1,553 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +#include "nsXPCOM.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +#include "nscore.h" +#include "nspr.h" +#include "prmon.h" + +#include "nsITestProxy.h" + +#include "nsIProxyObjectManager.h" +#include "nsIEventQueueService.h" + +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + +/***************************************************************************/ +/* nsTestXPCFoo */ +/***************************************************************************/ +class nsTestXPCFoo : public nsITestProxy +{ + NS_DECL_ISUPPORTS + NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD Test2(); + NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2); + + nsTestXPCFoo(); +}; + +nsTestXPCFoo::nsTestXPCFoo() +{ + NS_ADDREF_THIS(); +} + +NS_IMPL_ISUPPORTS1(nsTestXPCFoo, nsITestProxy) + +NS_IMETHODIMP nsTestXPCFoo::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + printf("Thread (%d) Test Called successfully! Party on...\n", p1); + *retval = p1+p2; + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo::Test2() +{ + printf("The quick brown netscape jumped over the old lazy ie..\n"); + + return NS_OK; +} + +NS_IMETHODIMP nsTestXPCFoo::Test3(nsISupports *p1, nsISupports **p2) +{ + if (p1 != nsnull) + { + nsITestProxy *test; + + p1->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test); + + test->Test2(); + PRInt32 a; + test->Test( 1, 2, &a); + printf("\n1+2=%d\n",a); + } + + + *p2 = new nsTestXPCFoo(); + return NS_OK; +} + +/***************************************************************************/ +/* nsTestXPCFoo2 */ +/***************************************************************************/ +class nsTestXPCFoo2 : public nsITestProxy +{ + NS_DECL_ISUPPORTS + NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD Test2(); + NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2); + + nsTestXPCFoo2(); +}; + +nsTestXPCFoo2::nsTestXPCFoo2() +{ + NS_ADDREF_THIS(); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTestXPCFoo2, nsITestProxy) + +NS_IMETHODIMP nsTestXPCFoo2::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ +printf("calling back to caller!\n\n"); + + nsIProxyObjectManager* manager; + nsITestProxy * proxyObject; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + manager->GetProxyForObject((nsIEventQueue*)p1, NS_GET_IID(nsITestProxy), this, PROXY_SYNC, (void**)&proxyObject); + proxyObject->Test3(nsnull, nsnull); + + printf("Deleting Proxy Object\n"); + NS_RELEASE(proxyObject); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test2() +{ + printf("nsTestXPCFoo2::Test2() called\n"); + + return NS_OK; +} + + +NS_IMETHODIMP nsTestXPCFoo2::Test3(nsISupports *p1, nsISupports **p2) +{ + printf("Got called"); + return NS_OK; +} + + + +typedef struct _ArgsStruct +{ + nsIEventQueue* queue; + PRInt32 threadNumber; +}ArgsStruct; + + + +// This will create two objects both descendants of a single IID. +void TestCase_TwoClassesOneInterface(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsITestProxy *proxyObject2; + + nsTestXPCFoo* foo = new nsTestXPCFoo(); + nsTestXPCFoo2* foo2 = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + PR_ASSERT(foo2); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo2, PROXY_SYNC, (void**)&proxyObject2); + + + + if (proxyObject && proxyObject2) + { + // release ownership of the real object. + + PRInt32 a; + nsresult rv; + PRInt32 threadNumber = argsStruct->threadNumber; + + printf("Deleting real Object (%d)\n", threadNumber); + NS_RELEASE(foo); + + printf("Deleting real Object 2 (%d)\n", threadNumber); + NS_RELEASE(foo2); + + + printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber); + rv = proxyObject->Test(threadNumber, 0, &a); + printf("Thread (%d) error: %d.\n", threadNumber, rv); + + + printf("Thread (%d) Prior to calling proxyObject->Test2.\n", threadNumber); + rv = proxyObject->Test2(); + printf("Thread (%d) error: %d.\n", threadNumber, rv); + + printf("Thread (%d) Prior to calling proxyObject2->Test2.\n", threadNumber); + rv = proxyObject2->Test2(); + printf("Thread (%d) proxyObject2 error: %d.\n", threadNumber, rv); + + printf("Deleting Proxy Object (%d)\n", threadNumber ); + NS_RELEASE(proxyObject); + + printf("Deleting Proxy Object 2 (%d)\n", threadNumber ); + NS_RELEASE(proxyObject2); + } + + PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters +} + + + +void TestCase_NestedLoop(void *arg) +{ + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + printf("ProxyObjectManager: %p \n", manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo2* foo = new nsTestXPCFoo2(); + + PR_ASSERT(foo); + + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + if (proxyObject) + { + // release ownership of the real object. + + nsresult rv; + PRInt32 threadNumber = argsStruct->threadNumber; + + printf("Deleting real Object (%d)\n", threadNumber); + NS_RELEASE(foo); + + PRInt32 retval; + + printf("Getting EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) + { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + + printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber); + rv = proxyObject->Test(NS_PTR_TO_INT32(eventQ), 0, &retval); + printf("Thread (%d) proxyObject error: %d.\n", threadNumber, rv); + + printf("Deleting Proxy Object (%d)\n", threadNumber ); + NS_RELEASE(proxyObject); + } + + PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters + } +} + + + +void TestCase_2(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + + manager->GetProxy(argsStruct->queue, + NS_GET_IID(nsITestProxy), // should be CID! + nsnull, + NS_GET_IID(nsITestProxy), + PROXY_SYNC, + (void**)&proxyObject); + + if (proxyObject != nsnull) + { + NS_RELEASE(proxyObject); + } +} + + + +void TestCase_nsISupports(void *arg) +{ + + ArgsStruct *argsStruct = (ArgsStruct*) arg; + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(argsStruct->queue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + if (proxyObject != nsnull) + { + nsISupports *bISupports = nsnull, *cISupports = nsnull; + + proxyObject->Test3(foo, &bISupports); + proxyObject->Test3(bISupports, &cISupports); + + nsITestProxy *test; + bISupports->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test); + + test->Test2(); + + NS_RELEASE(foo); + NS_RELEASE(proxyObject); + } +} + + + + + +/***************************************************************************/ +/* ProxyTest */ +/***************************************************************************/ + +static void PR_CALLBACK ProxyTest( void *arg ) +{ + //TestCase_TwoClassesOneInterface(arg); + // TestCase_2(arg); + //TestCase_nsISupports(arg); + TestCase_NestedLoop(arg); + + NS_RELEASE( ((ArgsStruct*) arg)->queue); + free((void*) arg); +} + +nsIEventQueue *gEventQueue = nsnull; + +static void PR_CALLBACK EventLoop( void *arg ) +{ + nsresult rv; + printf("Creating EventQueue...\n"); + + nsIEventQueue* eventQ; + nsCOMPtr eventQService = + do_GetService(kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv)) { + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + if (NS_FAILED(rv)) + rv = eventQService->CreateThreadEventQueue(); + if (NS_FAILED(rv)) + return; + else + rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &eventQ); + } + if (NS_FAILED(rv)) return; + + rv = eventQ->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&gEventQueue); + if (NS_FAILED(rv)) return; + + + printf("Verifing calling Proxy on eventQ thread.\n"); + + nsIProxyObjectManager* manager; + + nsServiceManager::GetService( NS_XPCOMPROXY_CONTRACTID, + NS_GET_IID(nsIProxyObjectManager), + (nsISupports **)&manager); + + PR_ASSERT(manager); + + nsITestProxy *proxyObject; + nsTestXPCFoo* foo = new nsTestXPCFoo(); + + PR_ASSERT(foo); + + manager->GetProxyForObject(gEventQueue, NS_GET_IID(nsITestProxy), foo, PROXY_SYNC, (void**)&proxyObject); + + PRInt32 a; + proxyObject->Test(1, 2, &a); + proxyObject->Test2(); + + + NS_RELEASE(proxyObject); + delete foo; + + printf("End of Verification calling Proxy on eventQ thread.\n"); + + + printf("Looping for events.\n"); + + PLEvent* event = nsnull; + + while ( PR_SUCCESS == PR_Sleep( PR_MillisecondsToInterval(1)) ) + { + rv = gEventQueue->GetEvent(&event); + if (NS_FAILED(rv)) + return; + gEventQueue->HandleEvent(event); + } + + gEventQueue->ProcessPendingEvents(); + + printf("Closing down Event Queue.\n"); + delete gEventQueue; + gEventQueue = nsnull; + + printf("End looping for events.\n\n"); +} + +int +main(int argc, char **argv) +{ + int numberOfThreads = 1; + + if (argc > 1) + numberOfThreads = atoi(argv[1]); + + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + static PRThread** threads = (PRThread**) calloc(sizeof(PRThread*), numberOfThreads); + static PRThread* aEventThread; + + aEventThread = PR_CreateThread(PR_USER_THREAD, + EventLoop, + NULL, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + + PR_Sleep(PR_MillisecondsToInterval(1000)); + + NS_ASSERTION(gEventQueue, "no main event queue"); // BAD BAD BAD. EVENT THREAD DID NOT CREATE QUEUE. This may be a timing issue, set the + // sleep about longer, and try again. + + printf("Spawn Threads:\n"); + for (PRInt32 spawn = 0; spawn < numberOfThreads; spawn++) + { + + ArgsStruct *args = (ArgsStruct *) malloc (sizeof(ArgsStruct)); + + args->queue = gEventQueue; + NS_ADDREF(args->queue); + args->threadNumber = spawn; + + threads[spawn] = PR_CreateThread(PR_USER_THREAD, + ProxyTest, + args, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0 ); + + printf("\tThread (%d) spawned\n", spawn); + + PR_Sleep( PR_MillisecondsToInterval(250) ); + } + + printf("All Threads Spawned.\n\n"); + + + + printf("Wait for threads.\n"); + for (PRInt32 i = 0; i < numberOfThreads; i++) + { + PRStatus rv; + printf("Thread (%d) Join...\n", i); + rv = PR_JoinThread(threads[i]); + printf("Thread (%d) Joined. (error: %d).\n", i, rv); + } + + PR_Interrupt(aEventThread); + PR_JoinThread(aEventThread); + + + printf("Calling Cleanup.\n"); + PR_Cleanup(); + + printf("Return zero.\n"); + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/Makefile.in new file mode 100644 index 00000000..171900b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = xptinfo xptcall + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore new file mode 100644 index 00000000..a1af50c2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/.cvsignore @@ -0,0 +1,4 @@ +Makefile +mk.bat +set_env.bat +none.pdb diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in new file mode 100644 index 00000000..e3173730 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/README b/src/libs/xpcom18a4/xpcom/reflect/xptcall/README new file mode 100644 index 00000000..0c401fe8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/README @@ -0,0 +1,6 @@ +see: + +http://www.mozilla.org/scriptable/xptcall-faq.html +and +http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/porting.html + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html b/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html new file mode 100644 index 00000000..b8b204a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/porting.html @@ -0,0 +1,212 @@ + + +xptcall Porting Guide + + +

xptcall Porting Guide

+ +

Overview

+ +
+ + xptcall is a +library that supports both invoking methods on arbitrary xpcom objects and +implementing classes whose objects can impersonate any xpcom interface. It does +this using platform specific assembly language code. This code needs to be +ported to all platforms that want to support xptcall (and thus mozilla). + +
+ +

The tree

+ +
+
+mozilla/xpcom/reflect/xptcall
+  +--public  // exported headers
+  +--src  // core source
+  |  \--md  // platform specific parts
+  |     +--mac  // mac ppc
+  |     +--unix  // all unix
+  |     \--win32  // win32
+  |     +--test  // simple tests to get started
+  \--tests  // full tests via api
+
+ +Porters are free to create subdirectories under the base md +directory for their given platforms and to integrate into the build system as +appropriate for their platform. + +
+ +

Theory of operation

+ +
+ +There are really two pieces of functionality: invoke and stubs... + +

+ +The invoke functionality requires the implementation of the +following on each platform (from xptcall/public/xptcall.h): + +

+XPTC_PUBLIC_API(nsresult)
+XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
+                   PRUint32 paramCount, nsXPTCVariant* params);
+
+ +Calling code is expected to supply an array of nsXPTCVariant +structs. These are discriminated unions describing the type and value of each +parameter of the target function. The platform specific code then builds a call +frame and invokes the method indicated by the index methodIndex on +the xpcom interface that. + +

+ +Here are examples of this implementation for +Win32 +and +Linux x86, NetBSD x86, and FreeBSD. + +Both of these implementations use the basic strategy of: figure out how much +stack space is needed for the params, make the space in a new frame, copy the +params to that space, invoke the method, cleanup and return. C++ is used where +appropriate, Assembly language is used where necessary. Inline assembly language is used here, +but it is equally valid to use separate assembly language source files. Porters +can decide how best to do this for their platforms. + +

+ +The stubs functionality is more complex. The goal here is a class +whose vtbl can look like the vtbl of any arbitrary xpcom interface. Objects of +this class can then be built to impersonate any xpcom object. The base interface +for this is (from xptcall/public/xptcall.h): + +

+class nsXPTCStubBase : public nsISupports
+{
+public:
+    // Include generated vtbl stub declarations.
+    // These are virtual and *also* implemented by this class..
+#include "xptcstubsdecl.inc"
+
+    // The following methods must be provided by inheritor of this class.
+
+    // return a refcounted pointer to the InterfaceInfo for this object
+    // NOTE: on some platforms this MUST not fail or we crash!
+    NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) = 0;
+
+    // call this method and return result
+    NS_IMETHOD CallMethod(PRUint16 methodIndex,
+                          const nsXPTMethodInfo* info,
+                          nsXPTCMiniVariant* params) = 0;
+};
+
+ +Code that wishes to make use of this stubs functionality (such as +XPConnect) implement a class +which inherits from nsXPTCStubBase and implements the +GetInterfaceInfo and CallMethod to let the +platform specific code know how to get interface information and how to dispatch methods +once their parameters have been pulled out of the platform specific calling +frame. + +

+ +Porters of this functionality implement the platform specific code for the +stub methods that fill the vtbl for this class. The idea here is that the +class has a vtbl full of a large number of generic stubs. All instances of this +class share that vtbl and the same stubs. The stubs forward calls to a platform +specific method that uses the interface information supplied by +the overridden GetInterfaceInfo to extract the parameters and build +an array of platform independent nsXPTCMiniVariant structs which +are in turn passed on to the overridden CallMethod. The +platform dependent code is responsible for doing any cleanup and returning. + +

+ +The stub methods are declared in xptcall/public/xptcstubsdecl.inc. +These are '#included' into the declaration of nsXPTCStubBase. A +similar include file (xptcall/public/xptcstubsdef.inc) +is expanded using platform specific macros to define the stub functions. These +'.inc' files are checked into cvs. However, they can be regenerated as necessary +(i.e. to change the number of stubs or to change their specific declaration) +using the Perl script xptcall/public/genstubs.pl. + +

+ +Here are examples of this implementation for Win32 +and Linux x86, NetBSD x86, and FreeBSD. +Both of these examples use inline assembly language. That is just how I +decided to do it. You can do it as you choose. + +

+ +The Win32 version is somewhat tighter because the __declspec(naked) feature +allows for very small stubs. However, the __stdcall requires the callee to clean +up the stack, so it is imperative that the interface information scheme allow +the code to determine the correct stack pointer fixup for return without fail, +else the process will crash. + +

+ +I opted to use inline assembler for the gcc Linux x86 port. I ended up with +larger stubs than I would have preferred rather than battle the compiler over +what would happen to the stack before my asm code began running. + +

+ +I believe that the non-assembly parts of these files can be copied and reused +with minimal (but not zero) platform specific tweaks. Feel free to copy and +paste as necessary. Please remember that safety and reliability are more +important than speed optimizations. This code is primarily used to connect XPCOM +components with JavaScript; function call overhead is a tiny part of the +time involved. + +

+ +I put together +xptcall/src/md/test + as a place to evolve the basic functionality as a port is coming together. +Not all of the functionality is exercised, but it is a place to get started. +xptcall/tests + has an api level test for XPTC_InvokeByIndex, but no tests for +the stubs functionality. Such a test ought to be written, but this has not +yet been done. + +

+ +A full 'test' at this point requires building the client and running the +XPConnect test called TestXPC in +mozilla/js/src/xpconnect/tests +. + +

+ +Getting these ports done is very important. Please let me know if you are interested in doing one. +I'll answer any questions as I get them. + +

+ + +Porting Status + + +

+ +
+Author: John Bandhauer <jband@netscape.com>
+Last modified: 31 May 1999 + + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in new file mode 100644 index 00000000..ac8432af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +EXPORTS = \ + xptcall.h \ + xptcstubsdecl.inc \ + xptcstubsdef.inc \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl new file mode 100755 index 00000000..b8962930 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/genstubs.pl @@ -0,0 +1,78 @@ +#!/usr/local/bin/perl + +# This is used to generate stub entry points. We generate a file to +# be included in the declaraion and a file to be used for expanding macros +# to represent the implementation of the stubs. + +# +# if "$entry_count" is ever changed and the .inc files regenerated then +# the following issues need to be addressed: +# +# 1) Alpha NT has a .def file that lists exports by symbol. It will need +# updating. +# 2) The current Linux ARM code has a limitation of only having 256-3 stubs +# +# more dependencies??? +# + +# 3 entries are already 'used' by the 3 methods of nsISupports. +# 3+247+5=255 This should get us in under the Linux ARM limitation +$entry_count = 247; +$sentinel_count = 5; + +$decl_name = "xptcstubsdecl.inc"; +$def_name = "xptcstubsdef.inc"; + +## +## Write the declarations include file +## + +die "Can't open $decl_name" if !open(OUTFILE, ">$decl_name"); + +print OUTFILE "/* generated file - DO NOT EDIT */\n\n"; +print OUTFILE "/* includes ",$entry_count," stub entries, and ", + $sentinel_count," sentinel entries */\n\n"; +print OUTFILE "/*\n"; +print OUTFILE "* declarations of normal stubs...\n"; +print OUTFILE "* 0 is QueryInterface\n"; +print OUTFILE "* 1 is AddRef\n"; +print OUTFILE "* 2 is Release\n"; +print OUTFILE "*/\n"; +print OUTFILE "#if !defined(__ia64) || (!defined(__hpux) && !defined(__linux__))\n"; +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "NS_IMETHOD Stub",$i+3,"();\n"; +} +print OUTFILE "#else\n"; +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "NS_IMETHOD Stub",$i+3,"(PRUint64,\n"; + print OUTFILE " PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64);\n"; + +} +print OUTFILE "#endif\n"; + +print OUTFILE "\n/* declarations of sentinel stubs */\n"; + +for($i = 0; $i < $sentinel_count; $i++) { + print OUTFILE "NS_IMETHOD Sentinel",$i,"();\n"; +} +close(OUTFILE); + + +## +## Write the definitions include file. This assumes a macro will be used to +## expand the entries written... +## + +die "Can't open $def_name" if !open(OUTFILE, ">$def_name"); + +print OUTFILE "/* generated file - DO NOT EDIT */\n\n"; +print OUTFILE "/* includes ",$entry_count," stub entries, and ", + $sentinel_count," sentinel entries */\n\n"; + +for($i = 0; $i < $entry_count; $i++) { + print OUTFILE "STUB_ENTRY(",$i+3,")\n"; +} + +for($i = 0; $i < $sentinel_count; $i++) { + print OUTFILE "SENTINEL_ENTRY(",$i,")\n"; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h new file mode 100644 index 00000000..153a047e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcall.h @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Public declarations for xptcall. */ + +#ifndef xptcall_h___ +#define xptcall_h___ + +#include "prtypes.h" +#include "nscore.h" +#include "nsISupports.h" +#include "xpt_struct.h" +#include "xptinfo.h" +#include "nsIInterfaceInfo.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPTC_InvokeByIndex VBoxNsxpXPTC_InvokeByIndex +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/***************************************************************************/ +/* + * The linkage of XPTC API functions differs depending on whether the file is + * used within the XPTC library or not. Any source file within the XPTC + * library should define EXPORT_XPTC_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPTC_API +#define XPTC_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPTC_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#if defined(_WIN32) +# define XPTC_EXPORT __declspec(dllexport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTC_EXPORT __declspec(dllexport) +#elif defined(XP_OS2_VACPP) +# define XPTC_EXPORT extern +#else +# ifdef VBOX_HAVE_VISIBILITY_HIDDEN +# define XPTC_EXPORT __attribute__((visibility("default"))) +# else +# define XPTC_EXPORT +# endif +#endif +#else +#if defined(_WIN32) +# define XPTC_PUBLIC_API(t) __declspec(dllimport) t +# define XPTC_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTC_EXPORT __declspec(dllimport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTC_PUBLIC_API(t) __declspec(dllimport) t +# define XPTC_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTC_EXPORT __declspec(dllimport) +#elif defined(XP_OS2_VACPP) +# define XPTC_PUBLIC_API(t) extern t +# define XPTC_PUBLIC_DATA(t) extern t +# define XPTC_EXPORT extern +#else +# define XPTC_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPTC_PUBLIC_DATA(t) t +# define XPTC_EXPORT +#endif +#endif +#define XPTC_FRIEND_API(t) XPTC_PUBLIC_API(t) +#define XPTC_FRIEND_DATA(t) XPTC_PUBLIC_DATA(t) +/***************************************************************************/ + +struct nsXPTCMiniVariant +{ +// No ctors or dtors so that we can use arrays of these on the stack +// with no penalty. + union + { + PRInt8 i8; + PRInt16 i16; + PRInt32 i32; + PRInt64 i64; + PRUint8 u8; + PRUint16 u16; + PRUint32 u32; + PRUint64 u64; + float f; + double d; + PRBool b; + char c; + PRUnichar wc; + void* p; + } val; +}; + +struct nsXPTCVariant : public nsXPTCMiniVariant +{ +// No ctors or dtors so that we can use arrays of these on the stack +// with no penalty. + + // inherits 'val' here + void* ptr; + nsXPTType type; + PRUint8 flags; + + enum + { + // these are bitflags! + PTR_IS_DATA = 0x1, // ptr points to 'real' data in val + VAL_IS_ALLOCD = 0x2, // val.p holds alloc'd ptr that must be freed + VAL_IS_IFACE = 0x4, // val.p holds interface ptr that must be released + VAL_IS_ARRAY = 0x8, // val.p holds a pointer to an array needing cleanup + VAL_IS_DOMSTR = 0x10, // val.p holds a pointer to domstring needing cleanup + VAL_IS_UTF8STR = 0x20, // val.p holds a pointer to utf8string needing cleanup + VAL_IS_CSTR = 0x40 // val.p holds a pointer to cstring needing cleanup + }; + + /* VBox: Added to prevent -Wclass-memaccess warnings (nsXPTType has a constructor) in python/src/VariantUtils.cpp */ + nsXPTCVariant() : ptr(NULL), flags(0) + { + val.p = NULL; + type.flags = 0; /* stupid nsXPTType constructor only do random bytes (documented) */ + } + + void ClearFlags() {flags = 0;} + void SetPtrIsData() {flags |= PTR_IS_DATA;} + void SetValIsAllocated() {flags |= VAL_IS_ALLOCD;} + void SetValIsInterface() {flags |= VAL_IS_IFACE;} + void SetValIsArray() {flags |= VAL_IS_ARRAY;} + void SetValIsDOMString() {flags |= VAL_IS_DOMSTR;} + void SetValIsUTF8String() {flags |= VAL_IS_UTF8STR;} + void SetValIsCString() {flags |= VAL_IS_CSTR;} + + PRBool IsPtrData() const {return 0 != (flags & PTR_IS_DATA);} + PRBool IsValAllocated() const {return 0 != (flags & VAL_IS_ALLOCD);} + PRBool IsValInterface() const {return 0 != (flags & VAL_IS_IFACE);} + PRBool IsValArray() const {return 0 != (flags & VAL_IS_ARRAY);} + PRBool IsValDOMString() const {return 0 != (flags & VAL_IS_DOMSTR);} + PRBool IsValUTF8String() const {return 0 != (flags & VAL_IS_UTF8STR);} + PRBool IsValCString() const {return 0 != (flags & VAL_IS_CSTR);} +#ifdef VBOX + PRBool MustFreeVal() const {return 0 != (flags & ( VAL_IS_ALLOCD + | VAL_IS_IFACE + | VAL_IS_DOMSTR + | VAL_IS_UTF8STR + | VAL_IS_CSTR)); } +#endif + + void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f) + { + type = t; + flags = f; + + if(f & PTR_IS_DATA) + { + ptr = mv.val.p; + val.p = nsnull; + } + else + { + ptr = nsnull; + switch(t.TagPart()) { + case nsXPTType::T_I8: val.i8 = mv.val.i8; break; + case nsXPTType::T_I16: val.i16 = mv.val.i16; break; + case nsXPTType::T_I32: val.i32 = mv.val.i32; break; + case nsXPTType::T_I64: val.i64 = mv.val.i64; break; + case nsXPTType::T_U8: val.u8 = mv.val.u8; break; + case nsXPTType::T_U16: val.u16 = mv.val.u16; break; + case nsXPTType::T_U32: val.u32 = mv.val.u32; break; + case nsXPTType::T_U64: val.u64 = mv.val.u64; break; + case nsXPTType::T_FLOAT: val.f = mv.val.f; break; + case nsXPTType::T_DOUBLE: val.d = mv.val.d; break; + case nsXPTType::T_BOOL: val.b = mv.val.b; break; + case nsXPTType::T_CHAR: val.c = mv.val.c; break; + case nsXPTType::T_WCHAR: val.wc = mv.val.wc; break; + case nsXPTType::T_VOID: /* fall through */ + case nsXPTType::T_IID: /* fall through */ + case nsXPTType::T_DOMSTRING: /* fall through */ + case nsXPTType::T_CHAR_STR: /* fall through */ + case nsXPTType::T_WCHAR_STR: /* fall through */ + case nsXPTType::T_INTERFACE: /* fall through */ + case nsXPTType::T_INTERFACE_IS: /* fall through */ + case nsXPTType::T_ARRAY: /* fall through */ + case nsXPTType::T_PSTRING_SIZE_IS: /* fall through */ + case nsXPTType::T_PWSTRING_SIZE_IS: /* fall through */ + case nsXPTType::T_UTF8STRING: /* fall through */ + case nsXPTType::T_CSTRING: /* fall through */ + default: val.p = mv.val.p; break; + } + } + } +}; + +/***************************************************************************/ + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_DEFAULT + +class XPTC_EXPORT nsXPTCStubBase : public nsISupports +{ +public: + // We are going to implement this to force the compiler to generate a + // vtbl for this class. Since this is overridden in the inheriting class + // we expect it to never be called. + // *This is needed by the Irix implementation.* + NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); + + // Implement dummy constructor, destructor to workaround Solaris gcc 4.8.2 + // linking issue (see @bugref{5838}). + nsXPTCStubBase() {} + ~nsXPTCStubBase() {} + + // Include generated vtbl stub declarations. + // These are virtual and *also* implemented by this class.. +#include "xptcstubsdecl.inc" + + // The following methods must be provided by inheritor of this class. + + // return a refcounted pointer to the InterfaceInfo for this object + // NOTE: on some platforms this MUST not fail or we crash! + NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) = 0; + + // call this method and return result + NS_IMETHOD CallMethod(PRUint16 methodIndex, + const nsXPTMethodInfo* info, + nsXPTCMiniVariant* params) = 0; +}; + +#undef IMETHOD_VISIBILITY +#define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN + +PR_BEGIN_EXTERN_C + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +// Used to force linking of these obj for the static library into the dll +extern void xptc_dummy(); +extern void xptc_dummy2(); + +PR_END_EXTERN_C + +#endif /* xptcall_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc new file mode 100644 index 00000000..99116d68 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdecl.inc @@ -0,0 +1,761 @@ +/* generated file - DO NOT EDIT */ + +/* includes 247 stub entries, and 5 sentinel entries */ + +/* +* declarations of normal stubs... +* 0 is QueryInterface +* 1 is AddRef +* 2 is Release +*/ +#if !defined(__ia64) || (!defined(__hpux) && !defined(__linux__)) +NS_IMETHOD Stub3(); +NS_IMETHOD Stub4(); +NS_IMETHOD Stub5(); +NS_IMETHOD Stub6(); +NS_IMETHOD Stub7(); +NS_IMETHOD Stub8(); +NS_IMETHOD Stub9(); +NS_IMETHOD Stub10(); +NS_IMETHOD Stub11(); +NS_IMETHOD Stub12(); +NS_IMETHOD Stub13(); +NS_IMETHOD Stub14(); +NS_IMETHOD Stub15(); +NS_IMETHOD Stub16(); +NS_IMETHOD Stub17(); +NS_IMETHOD Stub18(); +NS_IMETHOD Stub19(); +NS_IMETHOD Stub20(); +NS_IMETHOD Stub21(); +NS_IMETHOD Stub22(); +NS_IMETHOD Stub23(); +NS_IMETHOD Stub24(); +NS_IMETHOD Stub25(); +NS_IMETHOD Stub26(); +NS_IMETHOD Stub27(); +NS_IMETHOD Stub28(); +NS_IMETHOD Stub29(); +NS_IMETHOD Stub30(); +NS_IMETHOD Stub31(); +NS_IMETHOD Stub32(); +NS_IMETHOD Stub33(); +NS_IMETHOD Stub34(); +NS_IMETHOD Stub35(); +NS_IMETHOD Stub36(); +NS_IMETHOD Stub37(); +NS_IMETHOD Stub38(); +NS_IMETHOD Stub39(); +NS_IMETHOD Stub40(); +NS_IMETHOD Stub41(); +NS_IMETHOD Stub42(); +NS_IMETHOD Stub43(); +NS_IMETHOD Stub44(); +NS_IMETHOD Stub45(); +NS_IMETHOD Stub46(); +NS_IMETHOD Stub47(); +NS_IMETHOD Stub48(); +NS_IMETHOD Stub49(); +NS_IMETHOD Stub50(); +NS_IMETHOD Stub51(); +NS_IMETHOD Stub52(); +NS_IMETHOD Stub53(); +NS_IMETHOD Stub54(); +NS_IMETHOD Stub55(); +NS_IMETHOD Stub56(); +NS_IMETHOD Stub57(); +NS_IMETHOD Stub58(); +NS_IMETHOD Stub59(); +NS_IMETHOD Stub60(); +NS_IMETHOD Stub61(); +NS_IMETHOD Stub62(); +NS_IMETHOD Stub63(); +NS_IMETHOD Stub64(); +NS_IMETHOD Stub65(); +NS_IMETHOD Stub66(); +NS_IMETHOD Stub67(); +NS_IMETHOD Stub68(); +NS_IMETHOD Stub69(); +NS_IMETHOD Stub70(); +NS_IMETHOD Stub71(); +NS_IMETHOD Stub72(); +NS_IMETHOD Stub73(); +NS_IMETHOD Stub74(); +NS_IMETHOD Stub75(); +NS_IMETHOD Stub76(); +NS_IMETHOD Stub77(); +NS_IMETHOD Stub78(); +NS_IMETHOD Stub79(); +NS_IMETHOD Stub80(); +NS_IMETHOD Stub81(); +NS_IMETHOD Stub82(); +NS_IMETHOD Stub83(); +NS_IMETHOD Stub84(); +NS_IMETHOD Stub85(); +NS_IMETHOD Stub86(); +NS_IMETHOD Stub87(); +NS_IMETHOD Stub88(); +NS_IMETHOD Stub89(); +NS_IMETHOD Stub90(); +NS_IMETHOD Stub91(); +NS_IMETHOD Stub92(); +NS_IMETHOD Stub93(); +NS_IMETHOD Stub94(); +NS_IMETHOD Stub95(); +NS_IMETHOD Stub96(); +NS_IMETHOD Stub97(); +NS_IMETHOD Stub98(); +NS_IMETHOD Stub99(); +NS_IMETHOD Stub100(); +NS_IMETHOD Stub101(); +NS_IMETHOD Stub102(); +NS_IMETHOD Stub103(); +NS_IMETHOD Stub104(); +NS_IMETHOD Stub105(); +NS_IMETHOD Stub106(); +NS_IMETHOD Stub107(); +NS_IMETHOD Stub108(); +NS_IMETHOD Stub109(); +NS_IMETHOD Stub110(); +NS_IMETHOD Stub111(); +NS_IMETHOD Stub112(); +NS_IMETHOD Stub113(); +NS_IMETHOD Stub114(); +NS_IMETHOD Stub115(); +NS_IMETHOD Stub116(); +NS_IMETHOD Stub117(); +NS_IMETHOD Stub118(); +NS_IMETHOD Stub119(); +NS_IMETHOD Stub120(); +NS_IMETHOD Stub121(); +NS_IMETHOD Stub122(); +NS_IMETHOD Stub123(); +NS_IMETHOD Stub124(); +NS_IMETHOD Stub125(); +NS_IMETHOD Stub126(); +NS_IMETHOD Stub127(); +NS_IMETHOD Stub128(); +NS_IMETHOD Stub129(); +NS_IMETHOD Stub130(); +NS_IMETHOD Stub131(); +NS_IMETHOD Stub132(); +NS_IMETHOD Stub133(); +NS_IMETHOD Stub134(); +NS_IMETHOD Stub135(); +NS_IMETHOD Stub136(); +NS_IMETHOD Stub137(); +NS_IMETHOD Stub138(); +NS_IMETHOD Stub139(); +NS_IMETHOD Stub140(); +NS_IMETHOD Stub141(); +NS_IMETHOD Stub142(); +NS_IMETHOD Stub143(); +NS_IMETHOD Stub144(); +NS_IMETHOD Stub145(); +NS_IMETHOD Stub146(); +NS_IMETHOD Stub147(); +NS_IMETHOD Stub148(); +NS_IMETHOD Stub149(); +NS_IMETHOD Stub150(); +NS_IMETHOD Stub151(); +NS_IMETHOD Stub152(); +NS_IMETHOD Stub153(); +NS_IMETHOD Stub154(); +NS_IMETHOD Stub155(); +NS_IMETHOD Stub156(); +NS_IMETHOD Stub157(); +NS_IMETHOD Stub158(); +NS_IMETHOD Stub159(); +NS_IMETHOD Stub160(); +NS_IMETHOD Stub161(); +NS_IMETHOD Stub162(); +NS_IMETHOD Stub163(); +NS_IMETHOD Stub164(); +NS_IMETHOD Stub165(); +NS_IMETHOD Stub166(); +NS_IMETHOD Stub167(); +NS_IMETHOD Stub168(); +NS_IMETHOD Stub169(); +NS_IMETHOD Stub170(); +NS_IMETHOD Stub171(); +NS_IMETHOD Stub172(); +NS_IMETHOD Stub173(); +NS_IMETHOD Stub174(); +NS_IMETHOD Stub175(); +NS_IMETHOD Stub176(); +NS_IMETHOD Stub177(); +NS_IMETHOD Stub178(); +NS_IMETHOD Stub179(); +NS_IMETHOD Stub180(); +NS_IMETHOD Stub181(); +NS_IMETHOD Stub182(); +NS_IMETHOD Stub183(); +NS_IMETHOD Stub184(); +NS_IMETHOD Stub185(); +NS_IMETHOD Stub186(); +NS_IMETHOD Stub187(); +NS_IMETHOD Stub188(); +NS_IMETHOD Stub189(); +NS_IMETHOD Stub190(); +NS_IMETHOD Stub191(); +NS_IMETHOD Stub192(); +NS_IMETHOD Stub193(); +NS_IMETHOD Stub194(); +NS_IMETHOD Stub195(); +NS_IMETHOD Stub196(); +NS_IMETHOD Stub197(); +NS_IMETHOD Stub198(); +NS_IMETHOD Stub199(); +NS_IMETHOD Stub200(); +NS_IMETHOD Stub201(); +NS_IMETHOD Stub202(); +NS_IMETHOD Stub203(); +NS_IMETHOD Stub204(); +NS_IMETHOD Stub205(); +NS_IMETHOD Stub206(); +NS_IMETHOD Stub207(); +NS_IMETHOD Stub208(); +NS_IMETHOD Stub209(); +NS_IMETHOD Stub210(); +NS_IMETHOD Stub211(); +NS_IMETHOD Stub212(); +NS_IMETHOD Stub213(); +NS_IMETHOD Stub214(); +NS_IMETHOD Stub215(); +NS_IMETHOD Stub216(); +NS_IMETHOD Stub217(); +NS_IMETHOD Stub218(); +NS_IMETHOD Stub219(); +NS_IMETHOD Stub220(); +NS_IMETHOD Stub221(); +NS_IMETHOD Stub222(); +NS_IMETHOD Stub223(); +NS_IMETHOD Stub224(); +NS_IMETHOD Stub225(); +NS_IMETHOD Stub226(); +NS_IMETHOD Stub227(); +NS_IMETHOD Stub228(); +NS_IMETHOD Stub229(); +NS_IMETHOD Stub230(); +NS_IMETHOD Stub231(); +NS_IMETHOD Stub232(); +NS_IMETHOD Stub233(); +NS_IMETHOD Stub234(); +NS_IMETHOD Stub235(); +NS_IMETHOD Stub236(); +NS_IMETHOD Stub237(); +NS_IMETHOD Stub238(); +NS_IMETHOD Stub239(); +NS_IMETHOD Stub240(); +NS_IMETHOD Stub241(); +NS_IMETHOD Stub242(); +NS_IMETHOD Stub243(); +NS_IMETHOD Stub244(); +NS_IMETHOD Stub245(); +NS_IMETHOD Stub246(); +NS_IMETHOD Stub247(); +NS_IMETHOD Stub248(); +NS_IMETHOD Stub249(); +#else +NS_IMETHOD Stub3(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub4(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub5(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub6(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub7(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub8(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub9(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub10(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub11(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub12(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub13(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub14(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub15(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub16(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub17(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub18(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub19(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub20(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub21(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub22(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub23(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub24(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub25(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub26(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub27(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub28(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub29(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub30(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub31(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub32(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub33(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub34(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub35(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub36(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub37(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub38(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub39(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub40(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub41(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub42(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub43(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub44(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub45(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub46(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub47(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub48(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub49(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub50(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub51(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub52(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub53(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub54(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub55(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub56(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub57(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub58(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub59(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub60(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub61(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub62(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub63(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub64(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub65(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub66(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub67(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub68(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub69(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub70(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub71(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub72(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub73(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub74(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub75(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub76(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub77(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub78(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub79(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub80(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub81(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub82(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub83(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub84(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub85(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub86(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub87(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub88(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub89(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub90(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub91(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub92(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub93(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub94(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub95(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub96(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub97(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub98(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub99(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub100(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub101(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub102(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub103(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub104(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub105(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub106(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub107(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub108(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub109(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub110(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub111(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub112(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub113(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub114(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub115(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub116(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub117(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub118(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub119(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub120(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub121(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub122(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub123(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub124(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub125(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub126(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub127(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub128(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub129(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub130(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub131(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub132(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub133(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub134(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub135(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub136(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub137(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub138(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub139(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub140(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub141(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub142(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub143(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub144(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub145(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub146(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub147(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub148(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub149(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub150(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub151(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub152(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub153(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub154(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub155(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub156(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub157(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub158(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub159(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub160(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub161(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub162(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub163(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub164(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub165(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub166(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub167(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub168(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub169(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub170(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub171(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub172(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub173(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub174(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub175(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub176(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub177(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub178(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub179(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub180(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub181(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub182(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub183(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub184(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub185(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub186(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub187(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub188(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub189(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub190(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub191(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub192(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub193(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub194(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub195(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub196(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub197(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub198(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub199(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub200(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub201(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub202(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub203(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub204(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub205(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub206(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub207(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub208(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub209(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub210(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub211(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub212(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub213(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub214(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub215(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub216(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub217(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub218(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub219(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub220(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub221(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub222(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub223(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub224(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub225(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub226(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub227(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub228(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub229(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub230(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub231(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub232(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub233(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub234(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub235(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub236(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub237(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub238(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub239(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub240(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub241(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub242(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub243(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub244(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub245(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub246(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub247(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub248(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +NS_IMETHOD Stub249(PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); +#endif + +/* declarations of sentinel stubs */ +NS_IMETHOD Sentinel0(); +NS_IMETHOD Sentinel1(); +NS_IMETHOD Sentinel2(); +NS_IMETHOD Sentinel3(); +NS_IMETHOD Sentinel4(); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc new file mode 100644 index 00000000..780e2f52 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/public/xptcstubsdef.inc @@ -0,0 +1,256 @@ +/* generated file - DO NOT EDIT */ + +/* includes 247 stub entries, and 5 sentinel entries */ + +STUB_ENTRY(3) +STUB_ENTRY(4) +STUB_ENTRY(5) +STUB_ENTRY(6) +STUB_ENTRY(7) +STUB_ENTRY(8) +STUB_ENTRY(9) +STUB_ENTRY(10) +STUB_ENTRY(11) +STUB_ENTRY(12) +STUB_ENTRY(13) +STUB_ENTRY(14) +STUB_ENTRY(15) +STUB_ENTRY(16) +STUB_ENTRY(17) +STUB_ENTRY(18) +STUB_ENTRY(19) +STUB_ENTRY(20) +STUB_ENTRY(21) +STUB_ENTRY(22) +STUB_ENTRY(23) +STUB_ENTRY(24) +STUB_ENTRY(25) +STUB_ENTRY(26) +STUB_ENTRY(27) +STUB_ENTRY(28) +STUB_ENTRY(29) +STUB_ENTRY(30) +STUB_ENTRY(31) +STUB_ENTRY(32) +STUB_ENTRY(33) +STUB_ENTRY(34) +STUB_ENTRY(35) +STUB_ENTRY(36) +STUB_ENTRY(37) +STUB_ENTRY(38) +STUB_ENTRY(39) +STUB_ENTRY(40) +STUB_ENTRY(41) +STUB_ENTRY(42) +STUB_ENTRY(43) +STUB_ENTRY(44) +STUB_ENTRY(45) +STUB_ENTRY(46) +STUB_ENTRY(47) +STUB_ENTRY(48) +STUB_ENTRY(49) +STUB_ENTRY(50) +STUB_ENTRY(51) +STUB_ENTRY(52) +STUB_ENTRY(53) +STUB_ENTRY(54) +STUB_ENTRY(55) +STUB_ENTRY(56) +STUB_ENTRY(57) +STUB_ENTRY(58) +STUB_ENTRY(59) +STUB_ENTRY(60) +STUB_ENTRY(61) +STUB_ENTRY(62) +STUB_ENTRY(63) +STUB_ENTRY(64) +STUB_ENTRY(65) +STUB_ENTRY(66) +STUB_ENTRY(67) +STUB_ENTRY(68) +STUB_ENTRY(69) +STUB_ENTRY(70) +STUB_ENTRY(71) +STUB_ENTRY(72) +STUB_ENTRY(73) +STUB_ENTRY(74) +STUB_ENTRY(75) +STUB_ENTRY(76) +STUB_ENTRY(77) +STUB_ENTRY(78) +STUB_ENTRY(79) +STUB_ENTRY(80) +STUB_ENTRY(81) +STUB_ENTRY(82) +STUB_ENTRY(83) +STUB_ENTRY(84) +STUB_ENTRY(85) +STUB_ENTRY(86) +STUB_ENTRY(87) +STUB_ENTRY(88) +STUB_ENTRY(89) +STUB_ENTRY(90) +STUB_ENTRY(91) +STUB_ENTRY(92) +STUB_ENTRY(93) +STUB_ENTRY(94) +STUB_ENTRY(95) +STUB_ENTRY(96) +STUB_ENTRY(97) +STUB_ENTRY(98) +STUB_ENTRY(99) +STUB_ENTRY(100) +STUB_ENTRY(101) +STUB_ENTRY(102) +STUB_ENTRY(103) +STUB_ENTRY(104) +STUB_ENTRY(105) +STUB_ENTRY(106) +STUB_ENTRY(107) +STUB_ENTRY(108) +STUB_ENTRY(109) +STUB_ENTRY(110) +STUB_ENTRY(111) +STUB_ENTRY(112) +STUB_ENTRY(113) +STUB_ENTRY(114) +STUB_ENTRY(115) +STUB_ENTRY(116) +STUB_ENTRY(117) +STUB_ENTRY(118) +STUB_ENTRY(119) +STUB_ENTRY(120) +STUB_ENTRY(121) +STUB_ENTRY(122) +STUB_ENTRY(123) +STUB_ENTRY(124) +STUB_ENTRY(125) +STUB_ENTRY(126) +STUB_ENTRY(127) +STUB_ENTRY(128) +STUB_ENTRY(129) +STUB_ENTRY(130) +STUB_ENTRY(131) +STUB_ENTRY(132) +STUB_ENTRY(133) +STUB_ENTRY(134) +STUB_ENTRY(135) +STUB_ENTRY(136) +STUB_ENTRY(137) +STUB_ENTRY(138) +STUB_ENTRY(139) +STUB_ENTRY(140) +STUB_ENTRY(141) +STUB_ENTRY(142) +STUB_ENTRY(143) +STUB_ENTRY(144) +STUB_ENTRY(145) +STUB_ENTRY(146) +STUB_ENTRY(147) +STUB_ENTRY(148) +STUB_ENTRY(149) +STUB_ENTRY(150) +STUB_ENTRY(151) +STUB_ENTRY(152) +STUB_ENTRY(153) +STUB_ENTRY(154) +STUB_ENTRY(155) +STUB_ENTRY(156) +STUB_ENTRY(157) +STUB_ENTRY(158) +STUB_ENTRY(159) +STUB_ENTRY(160) +STUB_ENTRY(161) +STUB_ENTRY(162) +STUB_ENTRY(163) +STUB_ENTRY(164) +STUB_ENTRY(165) +STUB_ENTRY(166) +STUB_ENTRY(167) +STUB_ENTRY(168) +STUB_ENTRY(169) +STUB_ENTRY(170) +STUB_ENTRY(171) +STUB_ENTRY(172) +STUB_ENTRY(173) +STUB_ENTRY(174) +STUB_ENTRY(175) +STUB_ENTRY(176) +STUB_ENTRY(177) +STUB_ENTRY(178) +STUB_ENTRY(179) +STUB_ENTRY(180) +STUB_ENTRY(181) +STUB_ENTRY(182) +STUB_ENTRY(183) +STUB_ENTRY(184) +STUB_ENTRY(185) +STUB_ENTRY(186) +STUB_ENTRY(187) +STUB_ENTRY(188) +STUB_ENTRY(189) +STUB_ENTRY(190) +STUB_ENTRY(191) +STUB_ENTRY(192) +STUB_ENTRY(193) +STUB_ENTRY(194) +STUB_ENTRY(195) +STUB_ENTRY(196) +STUB_ENTRY(197) +STUB_ENTRY(198) +STUB_ENTRY(199) +STUB_ENTRY(200) +STUB_ENTRY(201) +STUB_ENTRY(202) +STUB_ENTRY(203) +STUB_ENTRY(204) +STUB_ENTRY(205) +STUB_ENTRY(206) +STUB_ENTRY(207) +STUB_ENTRY(208) +STUB_ENTRY(209) +STUB_ENTRY(210) +STUB_ENTRY(211) +STUB_ENTRY(212) +STUB_ENTRY(213) +STUB_ENTRY(214) +STUB_ENTRY(215) +STUB_ENTRY(216) +STUB_ENTRY(217) +STUB_ENTRY(218) +STUB_ENTRY(219) +STUB_ENTRY(220) +STUB_ENTRY(221) +STUB_ENTRY(222) +STUB_ENTRY(223) +STUB_ENTRY(224) +STUB_ENTRY(225) +STUB_ENTRY(226) +STUB_ENTRY(227) +STUB_ENTRY(228) +STUB_ENTRY(229) +STUB_ENTRY(230) +STUB_ENTRY(231) +STUB_ENTRY(232) +STUB_ENTRY(233) +STUB_ENTRY(234) +STUB_ENTRY(235) +STUB_ENTRY(236) +STUB_ENTRY(237) +STUB_ENTRY(238) +STUB_ENTRY(239) +STUB_ENTRY(240) +STUB_ENTRY(241) +STUB_ENTRY(242) +STUB_ENTRY(243) +STUB_ENTRY(244) +STUB_ENTRY(245) +STUB_ENTRY(246) +STUB_ENTRY(247) +STUB_ENTRY(248) +STUB_ENTRY(249) +SENTINEL_ENTRY(0) +SENTINEL_ENTRY(1) +SENTINEL_ENTRY(2) +SENTINEL_ENTRY(3) +SENTINEL_ENTRY(4) diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in new file mode 100644 index 00000000..987fc505 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.in @@ -0,0 +1,62 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcall + + +DIRS = md + +CPPSRCS = xptcall.cpp + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in new file mode 100644 index 00000000..dd70cabf --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.in @@ -0,0 +1,56 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +DIRS = os2 +else +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +DIRS = win32 +else +DIRS = unix +endif +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp new file mode 100644 index 00000000..29343c08 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.cpp @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef XP_MAC +#error "This code is for Macintosh only" +#endif + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ + PRUint32 fpCount = 0; + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt32*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; + if (fpCount < 13) + fprData[fpCount++] = s->val.f; + break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; + if (fpCount < 13) + fprData[fpCount++] = s->val.d; + break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRInt32*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((PRUint32*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +#pragma export on + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + +#pragma export off diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s new file mode 100644 index 00000000..47544dd3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcinvoke_mac.s @@ -0,0 +1,128 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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 mozilla.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + + csect CODE{PR} +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + + import .invoke_count_words + import .invoke_copy_to_stack + import .__ptr_glue + +._XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-144(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers, + # 8 to keep stack 16-byte aligned. + +# set up for and call 'invoke_count_words' to get new stack size +# + mr r3,r5 + mr r4,r6 + bl .invoke_count_words + nop + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,176(sp) # paramCount + lwz r5,180(sp) # params +# addi r6,sp,128 # fprData + mr r6,sp # fprData + slwi r3,r3,2 # number of bytes of stack required + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + sub sp,sp,r3 # bump the stack + clrrwi sp,sp,4 # keep the stack 16-byte aligned. + lwz r3,0(r31) # act like real alloca, so 0(sp) always points back to + stw r3,0(sp) # previous stack frame. + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,168(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,172(r31) # methodIndex + slwi r5,r5,2 # methodIndex * 4 + addi r5,r5,8 # step over junk at start of vTable ! + lwzx r12,r5,r4 # get function pointer + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl .__ptr_glue + nop + + + mr sp,r31 + lwz r0,152(sp) + addi sp,sp,144 + mtlr r0 + lwz r31,-4(sp) + blr + +# traceback table. + traceback: + dc.l 0 + dc.l 0x00002040 + dc.l 0 + dc.l (traceback - ._XPTC_InvokeByIndex) # size of the code. + dc.w 20 # short length of identifier. + dc.b '._XPTC_InvokeByIndex' + + csect DATA + import TOC + export ._XPTC_InvokeByIndex + + dc.l ._XPTC_InvokeByIndex + dc.l TOC + \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp new file mode 100644 index 00000000..3fea7d51 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#pragma export on + +#include "xptcprivate.h" + +#if defined(XP_MAC) + +/* + For mac, the first 8 integral and the first 13 f.p. parameters arrive + in a separate chunk of data that has been loaded from the registers. The + args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : +#ifdef HAVE_LONG_LONG + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) + { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else + { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; +#else + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRInt32) gprData[iCount++]; + else + dp->val.i64.hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRUint8) gprData[iCount++]; + else + dp->val.i8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRUint16) gprData[iCount++]; + else + dp->val.i16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRUint32) gprData[iCount++]; + else + dp->val.i32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : +#ifdef HAVE_LONG_LONG + // PRUint64 tempu64; // declared above and still in scope + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) + { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else + { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; +#else + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRUint32) gprData[iCount++]; + else + dp->val.i64.hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" void SharedStub(); + +#define STUB_ENTRY(n) \ +asm nsresult nsXPTCStubBase::Stub##n() \ +{ \ + addi r12,r0,n; \ + b SharedStub \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + + +#include "xptcstubsdef.inc" + +#pragma export off + +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s new file mode 100644 index 00000000..d2f7185b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/mac/xptcstubs_mac.s @@ -0,0 +1,78 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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 mozilla.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + + csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# + import .PrepareAndDispatch + +.SharedStub: + mflr r0 + stw r0,8(sp) + + stwu sp,-176(sp) # room for linkage (24), fprData (104), gprData(28) + # outgoing params to PrepareAndDispatch (20) + + stw r4,44(sp) + stw r5,48(sp) + stw r6,52(sp) + stw r7,56(sp) + stw r8,60(sp) + stw r9,64(sp) + stw r10,68(sp) + stfd f1,72(sp) + stfd f2,80(sp) + stfd f3,88(sp) + stfd f4,96(sp) + stfd f5,104(sp) + stfd f6,112(sp) + stfd f7,120(sp) + stfd f8,128(sp) + stfd f9,136(sp) + stfd f10,144(sp) + stfd f11,152(sp) + stfd f12,156(sp) + stfd f13,164(sp) + + addi r6,sp,44 # gprData + addi r7,sp,72 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector + addi r5,sp,232 # pointer to callers args area, beyond r3-r10 mapped range + + bl .PrepareAndDispatch + nop + + lwz r0,184(sp) + addi sp,sp,176 + mtlr r0 + blr + + csect DATA + import TOC + export .SharedStub + + dc.l .SharedStub + dc.l TOC diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in new file mode 100644 index 00000000..cfd57c83 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/Makefile.in @@ -0,0 +1,72 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +ifdef GNU_CXX +CPPSRCS = \ + ../unix/xptcinvoke_gcc_x86_unix.cpp \ + ../unix/xptcstubs_gcc_x86_unix.cpp \ + $(NULL) +LOCAL_INCLUDES = -I$(srcdir)/../unix +DEFINES += -DMOZ_NEED_LEADING_UNDERSCORE +else +CPPSRCS = xptcstubs_os2.cpp +ASFILES = xptcinvoke_vacpp.asm xptcstubs_vacpp.asm +endif + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API + +INCLUDES += -I$(srcdir)/../.. diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp new file mode 100644 index 00000000..17fcadfe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_emx.cpp @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Fairhurst + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 03/22/2000 IBM Corp. Fixed multiple inheritance bug in XPTC_InvokeByIndex to adjust the + * "that" (this) pointer appropriately. + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +// This is 80% copied directly from other platforms; the assembler +// stuff is all my fault, though. (jmf) + +#if !defined(__EMX__) +#error "This code is for OS/2 EMX only" +#endif + +#include "xptcprivate.h" + +// Remember that these 'words' are 32-bit DWORDs +static PRUint32 +invoke_count_words( PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + result++; + + else { + + switch(s->type) + { + // 64-bit types + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + result+=2; + break; + + // all others are dwords + default: + result++; + break; + } + } + } + return result; +} + + +static void +invoke_copy_to_stack( PRUint32* d, uint32 paramCount, nsXPTCVariant* s) +{ + for( PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + *((void**)d) = s->ptr; + + else { + + switch(s->type) + { + case nsXPTType::T_I8 : *((int8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((int16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((int64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((uint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((uint16*) d) = s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) d) = s->val.u32; break; + case nsXPTType::T_U64 : *((uint64*) d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*)d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex( nsISupports *that, PRUint32 index, + PRUint32 paramcount, nsXPTCVariant* params) +{ + int ibytes; + void *pStack; + int result = NS_OK; + + // Find size in bytes necessary for call + ibytes = 4 * invoke_count_words( paramcount, params); + + __asm__ __volatile__( + "movl %1, %%eax\n" /* load |ibytes| into eax */ + "subl %%eax, %%esp\n" /* make room on stack */ + "movl %%esp, %0" /* store base in |pStack| */ + : "=g" (pStack) /* %0 */ + : "g" (ibytes) /* %1 */ + : "ax", "memory", "sp" + ); + + // Fill in that gap in the stack with the params to the method + invoke_copy_to_stack( (PRUint32*) pStack, paramcount, params); + + // push the hidden 'this' parameter, traverse the vtable, + // and then call the method. + + __asm__ __volatile__( + "movl %2, %%eax\n" /* |that| ptr -> eax */ + "movl (%%eax), %%edx\n" /* vptr -> edx */ + "movl %3, %%ebx\n" + "shl $3, %%ebx\n" /* 8 bytes per method.. */ + "addl $8, %%ebx\n" /* ..plus 8 to skip over 1st 8 bytes of vtbl */ + + "addl %%ebx, %%edx\n" /* find appropriate vtbl entry */ + "movswl (%%edx),%%ecx\n" /* get possible |that| ptr adjustment value */ + "addl %%ecx, %%eax\n" /* adjust the |that| ptr (needed for multiple inheritance) */ + "pushl %%eax\n" /* enstack the possibly-adjusted |that| */ + + "addl $4, %%edx\n" /* ..add 4 more to get to the method's entry point */ + + "call (%%edx)\n" /* call method */ + "movl %%eax, %0\n" /* save rc in |result| */ + "movl %1, %%ebx\n" /* clear up stack */ + "addl $4, %%ebx\n" + "addl %%ebx, %%esp" + : "=g" (result) /* %0 */ + : "g" (ibytes), /* %1 */ + "g" (that), /* %2 */ + "g" (index) /* %3 */ + : "ax", "bx", "dx", "memory", "sp" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp new file mode 100644 index 00000000..6bbb93b0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_gcc_x86_os2.cpp @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* This file is basically a copy of xptcinvoke_gcc_x86_unix.cpp with some + * irrelevant parts stipped off and some OS/2 specific modifications added, + * so it needs to be kept in sync with the original. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static +void ATTRIBUTE_USED __attribute__ ((regparm(3))) +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + default : *((void**)d) = s->val.p; break; + } + } +} +} // extern "C" + +/* + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + Each param takes at most two 4-byte words. + It doesn't matter if we push too many words, and calculating the exact + amount takes time. + + that = ebp + 0x08 + methodIndex = ebp + 0x0c + paramCount = ebp + 0x10 + params = ebp + 0x14 + + NOTE NOTE NOTE: + As of 2002-04-29 this function references no global variables nor does + it call non-static functions so preserving and loading the PIC register + is unnecessary. Define MOZ_PRESERVE_PIC if this changes. See mozilla + bug 140412 for details. However, avoid this if you can. It's slower. +*/ + +#if defined(__declspec) +#define SYMBOL_EXPORT(sym) \ + ".stabs \"" sym ",0=" sym ",code\", 0x6c,0,0,-42\n\t" +#else +#define SYMBOL_EXPORT(sym) +#endif + +__asm__ ( + ".text\n\t" +/* alignment here seems unimportant here; this was 16, now it's 2 which + is what xptcstubs uses. */ + ".align 2\n\t" + ".globl " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex,@function\n" + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "XPTC_InvokeByIndex") + SYMBOL_UNDERSCORE "XPTC_InvokeByIndex:\n\t" + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" +#ifdef MOZ_PRESERVE_PIC + "pushl %ebx\n\t" + "call 0f\n\t" + ".subsection 1\n" + "0:\n\t" + "movl (%esp), %ebx\n\t" + "ret\n\t" + ".previous\n\t" + "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t" +#endif + "movl 0x10(%ebp), %eax\n\t" + "leal 0(,%eax,8),%edx\n\t" + "movl %esp, %ecx\n\t" + "subl %edx, %ecx\n\t" +/* Since there may be 64-bit data, it occurs to me that aligning this + space might be a performance gain. However, I don't think the rest + of mozilla worries about such things. In any event, do it here. + "andl $0xfffffff8, %ecx\n\t" + */ + "movl %ecx, %esp\n\t" /* make stack space */ + "movl 0x14(%ebp), %edx\n\t" + "call " SYMBOL_UNDERSCORE "invoke_copy_to_stack\n\t" + "movl 0x08(%ebp), %ecx\n\t" /* 'that' */ +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "shll $3, %eax\n\t" /* *= 8 */ + "addl $8, %eax\n\t" /* += 8 skip first entry */ + "addl %eax, %edx\n\t" + "movswl (%edx), %eax\n\t" /* 'this' offset */ + "addl %eax, %ecx\n\t" + "pushl %ecx\n\t" + "addl $4, %edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %ecx\n\t" + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "leal (%edx,%eax,4), %edx\n\t" +#endif + "call *(%edx)\n\t" +#ifdef MOZ_PRESERVE_PIC + "movl -4(%ebp), %ebx\n\t" +#endif + "movl %ebp, %esp\n\t" + "popl %ebp\n\t" + "ret\n" + ".size " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" +); + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm new file mode 100644 index 00000000..4d013fdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcinvoke_vacpp.asm @@ -0,0 +1,268 @@ +COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + + ***** 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 mozilla.org Code. + + The Initial Developer of the Original Code is + Netscape Communications Corporation. + Portions created by the Initial Developer are Copyright (C) 2001 + the Initial Developer. All Rights Reserved. + + Contributor(s): + Henry Sobotka + + Alternatively, the contents of this file may be used under the terms of + either of 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 ***** + Version 1.0 (the "NPL"); you may not use this file except in + compliance with the NPL. You may obtain a copy of the NPL at + http://www.mozilla.org/NPL/ + + Software distributed under the NPL is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + for the specific language governing rights and limitations under the + NPL. + + The Initial Developer of this code under the NPL is Netscape + Communications Corporation. Portions created by Netscape are + Copyright (C) 1999 Netscape Communications Corporation. All Rights + Reserved. + + Contributor: Henry Sobotka + + This Original Code has been modified by IBM Corporation. + Modifications made by IBM described herein are + Copyright (c) International Business Machines + Corporation, 2000 + + Modifications to Mozilla code or documentation + identified per MPL Section 3.3 + + Date Modified by Description of modification + 03/23/2000 IBM Corp. Various fixes for parameter passing and adjusting the 'this' + pointer for multiply inherited objects. + + xptcall_vacpp.asm: ALP assembler procedures for VAC++ build of xptcall + + We use essentially the same algorithm as the other platforms, except + Optlink as calling convention. This means loading the three leftmost + conforming (<= 4 bytes, enum or pointer) parameters into eax, edx and ecx, + and the four leftmost float types atop the FP stack. As "this" goes into + eax, we only have to load edx and ecx (if there are two parameters). + Nonconforming parameters go on the stack. As the right-size space has + to be allocated at the proper place (order of parameters) in the stack + for each conforming parameter, we simply copy them all. | + + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + +t_Int4Bytes equ 001004h +t_Int8Bytes equ 001008h +t_Float4Bytes equ 000104h +t_Float8Bytes equ 000108h + +TypesArray dd t_Int4Bytes ; nsXPTType::T_I8 + dd t_Int4Bytes ; nsXPTType::T_I16 + dd t_Int4Bytes ; nsXPTType::T_I32 + dd t_Int8Bytes ; nsXPTType::T_I64 (***) + dd t_Int4Bytes ; nsXPTType::T_U8 + dd t_Int4Bytes ; nsXPTType::T_U16 + dd t_Int4Bytes ; nsXPTType::T_U32 + dd t_Int8Bytes ; nsXPTType::T_U64 (***) + dd t_Float4Bytes ; nsXPTType::T_FLOAT (***) + dd t_Float8Bytes ; nsXPTType::T_DOUBLE (***) + dd t_Int4Bytes ; nsXPTType::T_BOOL + dd t_Int4Bytes ; nsXPTType::T_CHAR + dd t_Int4Bytes ; nsXPTType::T_WCHAR + dd t_Int4Bytes ; TD_VOID + dd t_Int4Bytes ; TD_PNSIID + dd t_Int4Bytes ; TD_DOMSTRING + dd t_Int4Bytes ; TD_PSTRING + dd t_Int4Bytes ; TD_PWSTRING + dd t_Int4Bytes ; TD_INTERFACE_TYPE + dd t_Int4Bytes ; TD_INTERFACE_IS_TYPE + dd t_Int4Bytes ; TD_ARRAY + dd t_Int4Bytes ; TD_PSTRING_SIZE_IS + dd t_Int4Bytes ; TD_PWSTRING_SIZE_IS + dd t_Int4Bytes ; TD_UTF8STRING + dd t_Int4Bytes ; TD_CSTRING + dd t_Int4Bytes ; TD_ASTRING + ; All other values default to 4 byte int/ptr + + + + ; Optlink puts 'that' in eax, 'index' in edx, 'paramcount' in ecx + ; 'params' is on the stack... +XPTC_InvokeByIndex PROC OPTLINK EXPORT USES ebx edi esi, that, index, paramcount, params + + LOCAL cparams:dword, fparams:dword, reg_edx:dword, reg_ecx:dword, count:dword + + mov dword ptr [that], eax ; that + mov dword ptr [index], edx ; index + mov dword ptr [paramcount], ecx ; paramcount + mov dword ptr [count], ecx ; save a copy of count + +; #define FOURBYTES 4 +; #define EIGHTBYTES 8 +; #define FLOAT 0x00000100 +; #define INT 0x00001000 +; #define LENGTH 0x000000ff +; +;types[ ] = { +; FOURBYES | INT, // int/uint/ptr/etc +; EIGHTBYTES | INT, // long long +; FOURBYES | FLOAT, // float +; EIGHTBYTES | FLOAT // double +;}; +; params+00h = val // double +; params+08h = ptr +; params+0ch = type +; params+0dh = flags +; PTR_IS_DATA = 0x01 +; ecx = params +; edx = src +; edi = dst +; ebx = type (bh = int/float, bl = byte count) + + xor eax, eax + mov dword ptr [cparams],eax ; cparams = 0; + mov dword ptr [fparams],eax ; fparams = 0; + + shl ecx, 03h + sub esp, ecx ; dst/esp = add esp, paramCount * 8 + mov edi, esp + + push eax ; push 0 // "end" of floating point register stack... + + mov ecx, dword ptr [params] ; // params is a "register" variable +@While1: + mov eax, dword ptr [count] ; while( count-- ) + or eax, eax ; // (test for zero) + je @EndWhile1 + dec eax + mov dword ptr [count], eax + ; { + + test byte ptr [ecx+0dh],01h ; if ( params->flags & PTR_IS_DATA ) { + je @IfElse1 + lea edx, dword ptr [ecx+08h] ; src = ¶ms->ptr; + mov ebx, 01004h ; type = INT | FOURBYTES; + jmp @EndIf1 +@IfElse1: ; } else { + mov edx, ecx ; src = ¶ms->val + movzx eax, byte ptr [ecx+0ch] ; type = types[params->type]; + cmp eax, 22 ; // range check params->type... (0 to 22) + jle @TypeOK + mov eax,2 ; // all others default to 4 byte int +@TypeOK: + mov ebx, dword ptr [TypesArray+eax*4] +@EndIf1: ; } + + test bh, 001h ; if ( type & FLOAT ) { + je @EndIf2 + cmp dword ptr [fparams], 4 ; if ( fparams < 4 ) { + jge @EndIf3 + push edx ; push src; + push ebx ; push type + inc dword ptr [fparams] ; fparams++; +;;; movzx eax, bl ; // dst += (type & LENGTH); +;;; add edi, eax ; +;;; xor ebx, ebx ; // type = 0; // "handled" +@EndIf3: ; } +@EndIf2: ; } + + ; // copy bytes... +@While2: or bl, bl ; while( type & LENGTH ) { + je @EndWhile2 + test bh, 010h ; if( type & INT ) { + je @EndIf4 + cmp dword ptr [cparams], 8 ; if( cparams < 8 ) { + jge @EndIf5 + lea eax, dword ptr [reg_edx] ; (®_edx)[cparams] = *src; + sub eax, dword ptr [cparams] + mov esi, dword ptr [edx] + mov dword ptr [eax], esi + add dword ptr [cparams], 4 ; cparams += 4; +;;; jmp @NoCopy ; // goto nocopy; +@EndIf5: ; } +@EndIf4: ; } + mov eax, dword ptr [edx] ; *dst = *src; + mov dword ptr [edi], eax +@NoCopy: ;nocopy: + add edi, 4 ; dst++; + add edx, 4 ; src++; + sub bl, 4 ; type -= 4; + jmp @While2 +@EndWhile2: ; } + add ecx, 010h ; params++; + jmp @While1 +@EndWhile1: ; } + + ; // Set up fpu and regs can make the call... +@While3: pop ebx ; while ( pop type ) { + or ebx, ebx + je @EndWhile3 + pop edx ; pop src + cmp bl, 08h ; if( type & EIGHTBYTES ) { + jne @IfElse6 + fld qword ptr [edx] ; fld qword ptr [src] + jmp @EndIf6 +@IfElse6: ; } else { + fld dword ptr [edx] ; fld dword ptr [src] +@EndIf6: ; } + jmp @While3 +@EndWhile3: ; } + + ; make the call + mov eax, dword ptr [that] ; get 'that' ("this" ptr) + mov ebx, dword ptr [index] ; get index + shl ebx, 03h ; index *= 8 bytes per method + add ebx, 08h ; += 8 at head of vtable + add ebx, [eax] ; calculate address + + mov ecx, dword ptr [ebx+04h] + add eax, ecx + sub esp, 04h ; make room for 'this' ptr on stack + + mov edx, dword ptr [reg_edx] + mov ecx, dword ptr [reg_ecx] + + call dword ptr [ebx] ; call method + + mov ecx, dword ptr [paramcount] + shl ecx, 03h + add esp, ecx ; remove space on stack for params + add esp, 04h ; remove space on stack for 'this' ptr + ret + + ENDP + + END + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp new file mode 100644 index 00000000..6cde9231 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_emx.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods */ + +// This is a 98% copy of other implementations; see comment at top of +// xptcinvoke_emx.cpp for why this file exists. +// + +#include "xptcprivate.h" + +#if !defined(__EMX__) +#error "This code is for OS/2 EMX only" +#endif + +static nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register void* method = PrepareAndDispatch; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx" /* PrepareAndDispatch */ \ + : "=a" (result) /* %0 */ \ + : "d" (method) /* %1 */ \ + : "ax", "dx", "cx", "memory" ); \ + return result; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPCWrappedJS::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp new file mode 100644 index 00000000..6304b67a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_gcc_x86_os2.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +/* This file is basically a copy of xptcinvoke_gcc_x86_unix.cpp with some + * irrelevant parts stipped off and some OS/2 specific modifications added, + * so it needs to be kept in sync with the original. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static nsresult ATTRIBUTE_USED +__attribute__ ((regparm (3))) +PrepareAndDispatch(uint32 methodIndex, nsXPTCStubBase* self, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} +} // extern "C" + +#if defined(__declspec) +#define SYMBOL_EXPORT(sym) \ + ".stabs \"" sym ",0=" sym ",code\", 0x6c,0,0,-42\n\t" +#else +#define SYMBOL_EXPORT(sym) +#endif + +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + SYMBOL_EXPORT(SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev") \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) __attribute__((regparm(1))) +asm(".text\n\t" + ".align 2\n\t" + ".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t" + SYMBOL_UNDERSCORE "SharedStub:\n\t" + "leal 0x08(%esp), %ecx\n\t" + "movl 0x04(%esp), %edx\n\t" + "jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t" + ".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp new file mode 100644 index 00000000..33e8574a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_os2.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Fairhurst + * Henry Sobotka added VAC++ support + * and fixed emx asm to work with gcc 2.95.2 (Jan. 2000) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods */ + +#include "xptcprivate.h" + +#if !defined (__EMX__) && !defined(__IBMCPP__) +#error "This code is only for OS/2" +#endif + +// Procedure in xptcall_vacpp.asm +#ifdef XP_OS2_VACPP +extern nsresult SetEntryFromIndex(int stubidx); +#endif + +#ifdef XP_OS2_VACPP +nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +#else +static nsresult +PrepareAndDispatch( nsXPTCStubBase *self, PRUint32 methodIndex, + PRUint32 *args) +#endif +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + +#ifdef XP_OS2_VACPP + /* If paramCount is > 0, write out the EDX pointer to the + space on the stack args[0]. args[-4] is the space on + the stack where it was pushed */ + if (paramCount) { + args[0] = args[-4]; + + /* If this is the second parameter, or if the first parameter is an + 8 byte long long, write out the ECX pointer to the space on the + stack args[1]. args[-3] is the space on the stack where it was + pushed */ + nsXPTType type = info->GetParam(0).GetType(); + if( paramCount > 1 || + type == nsXPTType::T_I64 || type == nsXPTType::T_U64 ) + { + args[1] = args[-3]; + } + } +#endif + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef XP_OS2_VACPP + +#define STUB_ENTRY(n) + +#else + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, PRUint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + "addl $12, %%esp" \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + : "2" (method) /* %2 */ \ + : "memory" ); \ + return result; \ +} +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPCWrappedJS::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm new file mode 100644 index 00000000..3464a1f9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/os2/xptcstubs_vacpp.asm @@ -0,0 +1,1563 @@ +COMMENT | -*- Mode: asm; tab-width: 8; c-basic-offset: 4 -*- + + ***** 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 mozilla.org Code. + + The Initial Developer of the Original Code is + Netscape Communications Corporation. + Portions created by the Initial Developer are Copyright (C) 2001 + the Initial Developer. All Rights Reserved. + + Contributor(s): + John Fairhurst + Henry Sobotka + + Alternatively, the contents of this file may be used under the terms of + either of 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 ***** + Version 1.0 (the "NPL"); you may not use this file except in + compliance with the NPL. You may obtain a copy of the NPL at + http://www.mozilla.org/NPL/ + + Software distributed under the NPL is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + for the specific language governing rights and limitations under the + NPL. + + The Initial Developer of this code under the NPL is Netscape + Communications Corporation. Portions created by Netscape are + Copyright (C) 1999 Netscape Communications Corporation. All Rights + Reserved. + + Contributor: Henry Sobotka + + xptcallstub_vacpp.asm: ALP assembler procedure for VAC++ build of xptcall + | + + .486P + .MODEL FLAT, OPTLINK + .STACK + + .CODE + + EXTERN OPTLINK PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi:PROC + +setentidx MACRO index + + push ecx ; Save parameters + push edx ; Save parameters - don't need to save eax - it is the "this" ptr + lea ecx, dword ptr [esp+10h] ; Load pointer to "args" into ecx + mov edx, index ; Move vtable index into edx + sub esp, 0ch ; Make room for three parameters on the stack + call PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi + add esp, 14h ; Reset stack pointer + ret + ENDM + +; 251 STUB_ENTRY(249) + +Stub249__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f9h +Stub249__14nsXPTCStubBaseFv endp + +; 250 STUB_ENTRY(248) + +Stub248__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f8h +Stub248__14nsXPTCStubBaseFv endp + +; 249 STUB_ENTRY(247) + +Stub247__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f7h +Stub247__14nsXPTCStubBaseFv endp + +; 248 STUB_ENTRY(246) + +Stub246__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f6h +Stub246__14nsXPTCStubBaseFv endp + +; 247 STUB_ENTRY(245) + +Stub245__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f5h +Stub245__14nsXPTCStubBaseFv endp + +; 246 STUB_ENTRY(244) + +Stub244__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f4h +Stub244__14nsXPTCStubBaseFv endp + +; 245 STUB_ENTRY(243) + +Stub243__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f3h +Stub243__14nsXPTCStubBaseFv endp + +; 244 STUB_ENTRY(242) + +Stub242__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f2h +Stub242__14nsXPTCStubBaseFv endp + +; 243 STUB_ENTRY(241) + +Stub241__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f1h +Stub241__14nsXPTCStubBaseFv endp + +; 242 STUB_ENTRY(240) + +Stub240__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0f0h +Stub240__14nsXPTCStubBaseFv endp + +; 241 STUB_ENTRY(239) + +Stub239__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0efh +Stub239__14nsXPTCStubBaseFv endp + +; 240 STUB_ENTRY(238) + +Stub238__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eeh +Stub238__14nsXPTCStubBaseFv endp + +; 239 STUB_ENTRY(237) + +Stub237__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0edh +Stub237__14nsXPTCStubBaseFv endp + +; 238 STUB_ENTRY(236) + +Stub236__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ech +Stub236__14nsXPTCStubBaseFv endp + +; 237 STUB_ENTRY(235) + +Stub235__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ebh +Stub235__14nsXPTCStubBaseFv endp + +; 236 STUB_ENTRY(234) + +Stub234__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eah +Stub234__14nsXPTCStubBaseFv endp + +; 235 STUB_ENTRY(233) + +Stub233__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e9h +Stub233__14nsXPTCStubBaseFv endp + +; 234 STUB_ENTRY(232) + +Stub232__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e8h +Stub232__14nsXPTCStubBaseFv endp + +; 233 STUB_ENTRY(231) + +Stub231__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e7h +Stub231__14nsXPTCStubBaseFv endp + +; 232 STUB_ENTRY(230) + +Stub230__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e6h +Stub230__14nsXPTCStubBaseFv endp + +; 231 STUB_ENTRY(229) + +Stub229__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e5h +Stub229__14nsXPTCStubBaseFv endp + +; 230 STUB_ENTRY(228) + +Stub228__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e4h +Stub228__14nsXPTCStubBaseFv endp + +; 229 STUB_ENTRY(227) + +Stub227__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e3h +Stub227__14nsXPTCStubBaseFv endp + +; 228 STUB_ENTRY(226) + +Stub226__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e2h +Stub226__14nsXPTCStubBaseFv endp + +; 227 STUB_ENTRY(225) + +Stub225__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e1h +Stub225__14nsXPTCStubBaseFv endp + +; 226 STUB_ENTRY(224) + +Stub224__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0e0h +Stub224__14nsXPTCStubBaseFv endp + +; 225 STUB_ENTRY(223) + +Stub223__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dfh +Stub223__14nsXPTCStubBaseFv endp + +; 224 STUB_ENTRY(222) + +Stub222__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0deh +Stub222__14nsXPTCStubBaseFv endp + +; 223 STUB_ENTRY(221) + +Stub221__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ddh +Stub221__14nsXPTCStubBaseFv endp + +; 222 STUB_ENTRY(220) + +Stub220__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dch +Stub220__14nsXPTCStubBaseFv endp + +; 221 STUB_ENTRY(219) + +Stub219__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dbh +Stub219__14nsXPTCStubBaseFv endp + +; 220 STUB_ENTRY(218) + +Stub218__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dah +Stub218__14nsXPTCStubBaseFv endp + +; 219 STUB_ENTRY(217) + +Stub217__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d9h +Stub217__14nsXPTCStubBaseFv endp + +; 218 STUB_ENTRY(216) + +Stub216__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d8h +Stub216__14nsXPTCStubBaseFv endp + +; 217 STUB_ENTRY(215) + +Stub215__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d7h +Stub215__14nsXPTCStubBaseFv endp + +; 216 STUB_ENTRY(214) + +Stub214__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d6h +Stub214__14nsXPTCStubBaseFv endp + +; 215 STUB_ENTRY(213) + +Stub213__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d5h +Stub213__14nsXPTCStubBaseFv endp + +; 214 STUB_ENTRY(212) + +Stub212__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d4h +Stub212__14nsXPTCStubBaseFv endp + +; 213 STUB_ENTRY(211) + +Stub211__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d3h +Stub211__14nsXPTCStubBaseFv endp + +; 212 STUB_ENTRY(210) + +Stub210__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d2h +Stub210__14nsXPTCStubBaseFv endp + +; 211 STUB_ENTRY(209) + +Stub209__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d1h +Stub209__14nsXPTCStubBaseFv endp + +; 210 STUB_ENTRY(208) + +Stub208__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0d0h +Stub208__14nsXPTCStubBaseFv endp + +; 209 STUB_ENTRY(207) + +Stub207__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cfh +Stub207__14nsXPTCStubBaseFv endp + +; 208 STUB_ENTRY(206) + +Stub206__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ceh +Stub206__14nsXPTCStubBaseFv endp + +; 207 STUB_ENTRY(205) + +Stub205__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cdh +Stub205__14nsXPTCStubBaseFv endp + +; 206 STUB_ENTRY(204) + +Stub204__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cch +Stub204__14nsXPTCStubBaseFv endp + +; 205 STUB_ENTRY(203) + +Stub203__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cbh +Stub203__14nsXPTCStubBaseFv endp + +; 204 STUB_ENTRY(202) + +Stub202__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0cah +Stub202__14nsXPTCStubBaseFv endp + +; 203 STUB_ENTRY(201) + +Stub201__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c9h +Stub201__14nsXPTCStubBaseFv endp + +; 202 STUB_ENTRY(200) + +Stub200__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c8h +Stub200__14nsXPTCStubBaseFv endp + +; 201 STUB_ENTRY(199) + +Stub199__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c7h +Stub199__14nsXPTCStubBaseFv endp + +; 200 STUB_ENTRY(198) + +Stub198__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c6h +Stub198__14nsXPTCStubBaseFv endp + +; 199 STUB_ENTRY(197) + +Stub197__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c5h +Stub197__14nsXPTCStubBaseFv endp + +; 198 STUB_ENTRY(196) + +Stub196__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c4h +Stub196__14nsXPTCStubBaseFv endp + +; 197 STUB_ENTRY(195) + +Stub195__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c3h +Stub195__14nsXPTCStubBaseFv endp + +; 196 STUB_ENTRY(194) + +Stub194__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c2h +Stub194__14nsXPTCStubBaseFv endp + +; 195 STUB_ENTRY(193) + +Stub193__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c1h +Stub193__14nsXPTCStubBaseFv endp + +; 194 STUB_ENTRY(192) + +Stub192__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0c0h +Stub192__14nsXPTCStubBaseFv endp + +; 193 STUB_ENTRY(191) + +Stub191__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bfh +Stub191__14nsXPTCStubBaseFv endp + +; 192 STUB_ENTRY(190) + +Stub190__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0beh +Stub190__14nsXPTCStubBaseFv endp + +; 191 STUB_ENTRY(189) + +Stub189__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bdh +Stub189__14nsXPTCStubBaseFv endp + +; 190 STUB_ENTRY(188) + +Stub188__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bch +Stub188__14nsXPTCStubBaseFv endp + +; 189 STUB_ENTRY(187) + +Stub187__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bbh +Stub187__14nsXPTCStubBaseFv endp + +; 188 STUB_ENTRY(186) + +Stub186__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bah +Stub186__14nsXPTCStubBaseFv endp + +; 187 STUB_ENTRY(185) + +Stub185__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b9h +Stub185__14nsXPTCStubBaseFv endp + +; 186 STUB_ENTRY(184) + +Stub184__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b8h +Stub184__14nsXPTCStubBaseFv endp + +; 185 STUB_ENTRY(183) + +Stub183__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b7h +Stub183__14nsXPTCStubBaseFv endp + +; 184 STUB_ENTRY(182) + +Stub182__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b6h +Stub182__14nsXPTCStubBaseFv endp + +; 183 STUB_ENTRY(181) + +Stub181__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b5h +Stub181__14nsXPTCStubBaseFv endp + +; 182 STUB_ENTRY(180) + +Stub180__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b4h +Stub180__14nsXPTCStubBaseFv endp + +; 181 STUB_ENTRY(179) + +Stub179__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b3h +Stub179__14nsXPTCStubBaseFv endp + +; 180 STUB_ENTRY(178) + +Stub178__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b2h +Stub178__14nsXPTCStubBaseFv endp + +; 179 STUB_ENTRY(177) + +Stub177__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b1h +Stub177__14nsXPTCStubBaseFv endp + +; 178 STUB_ENTRY(176) + +Stub176__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0b0h +Stub176__14nsXPTCStubBaseFv endp + +; 177 STUB_ENTRY(175) + +Stub175__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0afh +Stub175__14nsXPTCStubBaseFv endp + +; 176 STUB_ENTRY(174) + +Stub174__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0aeh +Stub174__14nsXPTCStubBaseFv endp + +; 175 STUB_ENTRY(173) + +Stub173__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0adh +Stub173__14nsXPTCStubBaseFv endp + +; 174 STUB_ENTRY(172) + +Stub172__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ach +Stub172__14nsXPTCStubBaseFv endp + +; 173 STUB_ENTRY(171) + +Stub171__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0abh +Stub171__14nsXPTCStubBaseFv endp + +; 172 STUB_ENTRY(170) + +Stub170__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0aah +Stub170__14nsXPTCStubBaseFv endp + +; 171 STUB_ENTRY(169) + +Stub169__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a9h +Stub169__14nsXPTCStubBaseFv endp + +; 170 STUB_ENTRY(168) + +Stub168__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a8h +Stub168__14nsXPTCStubBaseFv endp + +; 169 STUB_ENTRY(167) + +Stub167__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a7h +Stub167__14nsXPTCStubBaseFv endp + +; 168 STUB_ENTRY(166) + +Stub166__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a6h +Stub166__14nsXPTCStubBaseFv endp + +; 167 STUB_ENTRY(165) + +Stub165__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a5h +Stub165__14nsXPTCStubBaseFv endp + +; 166 STUB_ENTRY(164) + +Stub164__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a4h +Stub164__14nsXPTCStubBaseFv endp + +; 165 STUB_ENTRY(163) + +Stub163__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a3h +Stub163__14nsXPTCStubBaseFv endp + +; 164 STUB_ENTRY(162) + +Stub162__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a2h +Stub162__14nsXPTCStubBaseFv endp + +; 163 STUB_ENTRY(161) + +Stub161__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a1h +Stub161__14nsXPTCStubBaseFv endp + +; 162 STUB_ENTRY(160) + +Stub160__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0a0h +Stub160__14nsXPTCStubBaseFv endp + +; 161 STUB_ENTRY(159) + +Stub159__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09fh +Stub159__14nsXPTCStubBaseFv endp + +; 160 STUB_ENTRY(158) + +Stub158__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09eh +Stub158__14nsXPTCStubBaseFv endp + +; 159 STUB_ENTRY(157) + +Stub157__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09dh +Stub157__14nsXPTCStubBaseFv endp + +; 158 STUB_ENTRY(156) + +Stub156__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09ch +Stub156__14nsXPTCStubBaseFv endp + +; 157 STUB_ENTRY(155) + +Stub155__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09bh +Stub155__14nsXPTCStubBaseFv endp + +; 156 STUB_ENTRY(154) + +Stub154__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09ah +Stub154__14nsXPTCStubBaseFv endp + +; 155 STUB_ENTRY(153) + +Stub153__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 099h +Stub153__14nsXPTCStubBaseFv endp + +; 154 STUB_ENTRY(152) + +Stub152__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 098h +Stub152__14nsXPTCStubBaseFv endp + +; 153 STUB_ENTRY(151) + +Stub151__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 097h +Stub151__14nsXPTCStubBaseFv endp + +; 152 STUB_ENTRY(150) + +Stub150__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 096h +Stub150__14nsXPTCStubBaseFv endp + +; 151 STUB_ENTRY(149) + +Stub149__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 095h +Stub149__14nsXPTCStubBaseFv endp + +; 150 STUB_ENTRY(148) + +Stub148__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 094h +Stub148__14nsXPTCStubBaseFv endp + +; 149 STUB_ENTRY(147) + +Stub147__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 093h +Stub147__14nsXPTCStubBaseFv endp + +; 148 STUB_ENTRY(146) + +Stub146__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 092h +Stub146__14nsXPTCStubBaseFv endp + +; 147 STUB_ENTRY(145) + +Stub145__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 091h +Stub145__14nsXPTCStubBaseFv endp + +; 146 STUB_ENTRY(144) + +Stub144__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 090h +Stub144__14nsXPTCStubBaseFv endp + +; 145 STUB_ENTRY(143) + +Stub143__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08fh +Stub143__14nsXPTCStubBaseFv endp + +; 144 STUB_ENTRY(142) + +Stub142__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08eh +Stub142__14nsXPTCStubBaseFv endp + +; 143 STUB_ENTRY(141) + +Stub141__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08dh +Stub141__14nsXPTCStubBaseFv endp + +; 142 STUB_ENTRY(140) + +Stub140__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08ch +Stub140__14nsXPTCStubBaseFv endp + +; 141 STUB_ENTRY(139) + +Stub139__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08bh +Stub139__14nsXPTCStubBaseFv endp + +; 140 STUB_ENTRY(138) + +Stub138__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08ah +Stub138__14nsXPTCStubBaseFv endp + +; 139 STUB_ENTRY(137) + +Stub137__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 089h +Stub137__14nsXPTCStubBaseFv endp + +; 138 STUB_ENTRY(136) + +Stub136__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 088h +Stub136__14nsXPTCStubBaseFv endp + +; 137 STUB_ENTRY(135) + +Stub135__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 087h +Stub135__14nsXPTCStubBaseFv endp + +; 136 STUB_ENTRY(134) + +Stub134__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 086h +Stub134__14nsXPTCStubBaseFv endp + +; 135 STUB_ENTRY(133) + +Stub133__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 085h +Stub133__14nsXPTCStubBaseFv endp + +; 134 STUB_ENTRY(132) + +Stub132__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 084h +Stub132__14nsXPTCStubBaseFv endp + +; 133 STUB_ENTRY(131) + +Stub131__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 083h +Stub131__14nsXPTCStubBaseFv endp + +; 132 STUB_ENTRY(130) + +Stub130__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 082h +Stub130__14nsXPTCStubBaseFv endp + +; 131 STUB_ENTRY(129) + +Stub129__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 081h +Stub129__14nsXPTCStubBaseFv endp + +; 130 STUB_ENTRY(128) + +Stub128__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 080h +Stub128__14nsXPTCStubBaseFv endp + +; 129 STUB_ENTRY(127) + +Stub127__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07fh +Stub127__14nsXPTCStubBaseFv endp + +; 128 STUB_ENTRY(126) + +Stub126__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07eh +Stub126__14nsXPTCStubBaseFv endp + +; 127 STUB_ENTRY(125) + +Stub125__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07dh +Stub125__14nsXPTCStubBaseFv endp + +; 126 STUB_ENTRY(124) + +Stub124__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07ch +Stub124__14nsXPTCStubBaseFv endp + +; 125 STUB_ENTRY(123) + +Stub123__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07bh +Stub123__14nsXPTCStubBaseFv endp + +; 124 STUB_ENTRY(122) + +Stub122__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07ah +Stub122__14nsXPTCStubBaseFv endp + +; 123 STUB_ENTRY(121) + +Stub121__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 079h +Stub121__14nsXPTCStubBaseFv endp + +; 122 STUB_ENTRY(120) + +Stub120__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 078h +Stub120__14nsXPTCStubBaseFv endp + +; 121 STUB_ENTRY(119) + +Stub119__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 077h +Stub119__14nsXPTCStubBaseFv endp + +; 120 STUB_ENTRY(118) + +Stub118__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 076h +Stub118__14nsXPTCStubBaseFv endp + +; 119 STUB_ENTRY(117) + +Stub117__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 075h +Stub117__14nsXPTCStubBaseFv endp + +; 118 STUB_ENTRY(116) + +Stub116__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 074h +Stub116__14nsXPTCStubBaseFv endp + +; 117 STUB_ENTRY(115) + +Stub115__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 073h +Stub115__14nsXPTCStubBaseFv endp + +; 116 STUB_ENTRY(114) + +Stub114__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 072h +Stub114__14nsXPTCStubBaseFv endp + +; 115 STUB_ENTRY(113) + +Stub113__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 071h +Stub113__14nsXPTCStubBaseFv endp + +; 114 STUB_ENTRY(112) + +Stub112__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 070h +Stub112__14nsXPTCStubBaseFv endp + +; 113 STUB_ENTRY(111) + +Stub111__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06fh +Stub111__14nsXPTCStubBaseFv endp + +; 112 STUB_ENTRY(110) + +Stub110__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06eh +Stub110__14nsXPTCStubBaseFv endp + +; 111 STUB_ENTRY(109) + +Stub109__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06dh +Stub109__14nsXPTCStubBaseFv endp + +; 110 STUB_ENTRY(108) + +Stub108__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06ch +Stub108__14nsXPTCStubBaseFv endp + +; 109 STUB_ENTRY(107) + +Stub107__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06bh +Stub107__14nsXPTCStubBaseFv endp + +; 108 STUB_ENTRY(106) + +Stub106__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06ah +Stub106__14nsXPTCStubBaseFv endp + +; 107 STUB_ENTRY(105) + +Stub105__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 069h +Stub105__14nsXPTCStubBaseFv endp + +; 106 STUB_ENTRY(104) + +Stub104__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 068h +Stub104__14nsXPTCStubBaseFv endp + +; 105 STUB_ENTRY(103) + +Stub103__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 067h +Stub103__14nsXPTCStubBaseFv endp + +; 104 STUB_ENTRY(102) + +Stub102__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 066h +Stub102__14nsXPTCStubBaseFv endp + +; 103 STUB_ENTRY(101) + +Stub101__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 065h +Stub101__14nsXPTCStubBaseFv endp + +; 102 STUB_ENTRY(100) + +Stub100__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 064h +Stub100__14nsXPTCStubBaseFv endp + +; 101 STUB_ENTRY(99) + +Stub99__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 063h +Stub99__14nsXPTCStubBaseFv endp + +; 100 STUB_ENTRY(98) + +Stub98__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 062h +Stub98__14nsXPTCStubBaseFv endp + +; 99 STUB_ENTRY(97) + +Stub97__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 061h +Stub97__14nsXPTCStubBaseFv endp + +; 98 STUB_ENTRY(96) + +Stub96__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 060h +Stub96__14nsXPTCStubBaseFv endp + +; 97 STUB_ENTRY(95) + +Stub95__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05fh +Stub95__14nsXPTCStubBaseFv endp + +; 96 STUB_ENTRY(94) + +Stub94__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05eh +Stub94__14nsXPTCStubBaseFv endp + +; 95 STUB_ENTRY(93) + +Stub93__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05dh +Stub93__14nsXPTCStubBaseFv endp + +; 94 STUB_ENTRY(92) + +Stub92__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05ch +Stub92__14nsXPTCStubBaseFv endp + +; 93 STUB_ENTRY(91) + +Stub91__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05bh +Stub91__14nsXPTCStubBaseFv endp + +; 92 STUB_ENTRY(90) + +Stub90__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05ah +Stub90__14nsXPTCStubBaseFv endp + +; 91 STUB_ENTRY(89) + +Stub89__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 059h +Stub89__14nsXPTCStubBaseFv endp + +; 90 STUB_ENTRY(88) + +Stub88__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 058h +Stub88__14nsXPTCStubBaseFv endp + +; 89 STUB_ENTRY(87) + +Stub87__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 057h +Stub87__14nsXPTCStubBaseFv endp + +; 88 STUB_ENTRY(86) + +Stub86__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 056h +Stub86__14nsXPTCStubBaseFv endp + +; 87 STUB_ENTRY(85) + +Stub85__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 055h +Stub85__14nsXPTCStubBaseFv endp + +; 86 STUB_ENTRY(84) + +Stub84__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 054h +Stub84__14nsXPTCStubBaseFv endp + +; 85 STUB_ENTRY(83) + +Stub83__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 053h +Stub83__14nsXPTCStubBaseFv endp + +; 84 STUB_ENTRY(82) + +Stub82__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 052h +Stub82__14nsXPTCStubBaseFv endp + +; 83 STUB_ENTRY(81) + +Stub81__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 051h +Stub81__14nsXPTCStubBaseFv endp + +; 82 STUB_ENTRY(80) + +Stub80__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 050h +Stub80__14nsXPTCStubBaseFv endp + +; 81 STUB_ENTRY(79) + +Stub79__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04fh +Stub79__14nsXPTCStubBaseFv endp + +; 80 STUB_ENTRY(78) + +Stub78__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04eh +Stub78__14nsXPTCStubBaseFv endp + +; 79 STUB_ENTRY(77) + +Stub77__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04dh +Stub77__14nsXPTCStubBaseFv endp + +; 78 STUB_ENTRY(76) + +Stub76__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04ch +Stub76__14nsXPTCStubBaseFv endp + +; 77 STUB_ENTRY(75) + +Stub75__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04bh +Stub75__14nsXPTCStubBaseFv endp + +; 76 STUB_ENTRY(74) + +Stub74__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04ah +Stub74__14nsXPTCStubBaseFv endp + +; 75 STUB_ENTRY(73) + +Stub73__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 049h +Stub73__14nsXPTCStubBaseFv endp + +; 74 STUB_ENTRY(72) + +Stub72__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 048h +Stub72__14nsXPTCStubBaseFv endp + +; 73 STUB_ENTRY(71) + +Stub71__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 047h +Stub71__14nsXPTCStubBaseFv endp + +; 72 STUB_ENTRY(70) + +Stub70__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 046h +Stub70__14nsXPTCStubBaseFv endp + +; 71 STUB_ENTRY(69) + +Stub69__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 045h +Stub69__14nsXPTCStubBaseFv endp + +; 70 STUB_ENTRY(68) + +Stub68__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 044h +Stub68__14nsXPTCStubBaseFv endp + +; 69 STUB_ENTRY(67) + +Stub67__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 043h +Stub67__14nsXPTCStubBaseFv endp + +; 68 STUB_ENTRY(66) + +Stub66__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 042h +Stub66__14nsXPTCStubBaseFv endp + +; 67 STUB_ENTRY(65) + +Stub65__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 041h +Stub65__14nsXPTCStubBaseFv endp + +; 66 STUB_ENTRY(64) + +Stub64__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 040h +Stub64__14nsXPTCStubBaseFv endp + +; 65 STUB_ENTRY(63) + +Stub63__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03fh +Stub63__14nsXPTCStubBaseFv endp + +; 64 STUB_ENTRY(62) + +Stub62__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03eh +Stub62__14nsXPTCStubBaseFv endp + +; 63 STUB_ENTRY(61) + +Stub61__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03dh +Stub61__14nsXPTCStubBaseFv endp + +; 62 STUB_ENTRY(60) + +Stub60__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03ch +Stub60__14nsXPTCStubBaseFv endp + +; 61 STUB_ENTRY(59) + +Stub59__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03bh +Stub59__14nsXPTCStubBaseFv endp + +; 60 STUB_ENTRY(58) + +Stub58__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03ah +Stub58__14nsXPTCStubBaseFv endp + +; 59 STUB_ENTRY(57) + +Stub57__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 039h +Stub57__14nsXPTCStubBaseFv endp + +; 58 STUB_ENTRY(56) + +Stub56__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 038h +Stub56__14nsXPTCStubBaseFv endp + +; 57 STUB_ENTRY(55) + +Stub55__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 037h +Stub55__14nsXPTCStubBaseFv endp + +; 56 STUB_ENTRY(54) + +Stub54__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 036h +Stub54__14nsXPTCStubBaseFv endp + +; 55 STUB_ENTRY(53) + +Stub53__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 035h +Stub53__14nsXPTCStubBaseFv endp + +; 54 STUB_ENTRY(52) + +Stub52__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 034h +Stub52__14nsXPTCStubBaseFv endp + +; 53 STUB_ENTRY(51) + +Stub51__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 033h +Stub51__14nsXPTCStubBaseFv endp + +; 52 STUB_ENTRY(50) + +Stub50__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 032h +Stub50__14nsXPTCStubBaseFv endp + +; 51 STUB_ENTRY(49) + +Stub49__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 031h +Stub49__14nsXPTCStubBaseFv endp + +; 50 STUB_ENTRY(48) + +Stub48__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 030h +Stub48__14nsXPTCStubBaseFv endp + +; 49 STUB_ENTRY(47) + +Stub47__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02fh +Stub47__14nsXPTCStubBaseFv endp + +; 48 STUB_ENTRY(46) + +Stub46__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02eh +Stub46__14nsXPTCStubBaseFv endp + +; 47 STUB_ENTRY(45) + +Stub45__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02dh +Stub45__14nsXPTCStubBaseFv endp + +; 46 STUB_ENTRY(44) + +Stub44__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02ch +Stub44__14nsXPTCStubBaseFv endp + +; 45 STUB_ENTRY(43) + +Stub43__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02bh +Stub43__14nsXPTCStubBaseFv endp + +; 44 STUB_ENTRY(42) + +Stub42__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 02ah +Stub42__14nsXPTCStubBaseFv endp + +; 43 STUB_ENTRY(41) + +Stub41__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 029h +Stub41__14nsXPTCStubBaseFv endp + +; 42 STUB_ENTRY(40) + +Stub40__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 028h +Stub40__14nsXPTCStubBaseFv endp + +; 41 STUB_ENTRY(39) + +Stub39__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 027h +Stub39__14nsXPTCStubBaseFv endp + +; 40 STUB_ENTRY(38) + +Stub38__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 026h +Stub38__14nsXPTCStubBaseFv endp + +; 39 STUB_ENTRY(37) + +Stub37__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 025h +Stub37__14nsXPTCStubBaseFv endp + +; 38 STUB_ENTRY(36) + +Stub36__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 024h +Stub36__14nsXPTCStubBaseFv endp + +; 37 STUB_ENTRY(35) + +Stub35__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 023h +Stub35__14nsXPTCStubBaseFv endp + +; 36 STUB_ENTRY(34) + +Stub34__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 022h +Stub34__14nsXPTCStubBaseFv endp + +; 35 STUB_ENTRY(33) + +Stub33__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 021h +Stub33__14nsXPTCStubBaseFv endp + +; 34 STUB_ENTRY(32) + +Stub32__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 020h +Stub32__14nsXPTCStubBaseFv endp + +; 33 STUB_ENTRY(31) + +Stub31__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01fh +Stub31__14nsXPTCStubBaseFv endp + +; 32 STUB_ENTRY(30) + +Stub30__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01eh +Stub30__14nsXPTCStubBaseFv endp + +; 31 STUB_ENTRY(29) + +Stub29__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01dh +Stub29__14nsXPTCStubBaseFv endp + +; 30 STUB_ENTRY(28) + +Stub28__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01ch +Stub28__14nsXPTCStubBaseFv endp + +; 29 STUB_ENTRY(27) + +Stub27__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01bh +Stub27__14nsXPTCStubBaseFv endp + +; 28 STUB_ENTRY(26) + +Stub26__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 01ah +Stub26__14nsXPTCStubBaseFv endp + +; 27 STUB_ENTRY(25) + +Stub25__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 019h +Stub25__14nsXPTCStubBaseFv endp + +; 26 STUB_ENTRY(24) + +Stub24__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 018h +Stub24__14nsXPTCStubBaseFv endp + +; 25 STUB_ENTRY(23) + +Stub23__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 017h +Stub23__14nsXPTCStubBaseFv endp + +; 24 STUB_ENTRY(22) + +Stub22__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 016h +Stub22__14nsXPTCStubBaseFv endp + +; 23 STUB_ENTRY(21) + +Stub21__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 015h +Stub21__14nsXPTCStubBaseFv endp + +; 22 STUB_ENTRY(20) + +Stub20__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 014h +Stub20__14nsXPTCStubBaseFv endp + +; 21 STUB_ENTRY(19) + +Stub19__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 013h +Stub19__14nsXPTCStubBaseFv endp + +; 20 STUB_ENTRY(18) + +Stub18__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 012h +Stub18__14nsXPTCStubBaseFv endp + +; 19 STUB_ENTRY(17) + +Stub17__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 011h +Stub17__14nsXPTCStubBaseFv endp + +; 18 STUB_ENTRY(16) + +Stub16__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 010h +Stub16__14nsXPTCStubBaseFv endp + +; 17 STUB_ENTRY(15) + +Stub15__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0fh +Stub15__14nsXPTCStubBaseFv endp + +; 16 STUB_ENTRY(14) + +Stub14__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0eh +Stub14__14nsXPTCStubBaseFv endp + +; 15 STUB_ENTRY(13) + +Stub13__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0dh +Stub13__14nsXPTCStubBaseFv endp + +; 14 STUB_ENTRY(12) + +Stub12__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ch +Stub12__14nsXPTCStubBaseFv endp + +; 13 STUB_ENTRY(11) + +Stub11__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0bh +Stub11__14nsXPTCStubBaseFv endp + +; 12 STUB_ENTRY(10) + +Stub10__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 0ah +Stub10__14nsXPTCStubBaseFv endp + +; 11 STUB_ENTRY(9) + +Stub9__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 09h +Stub9__14nsXPTCStubBaseFv endp + +; 10 STUB_ENTRY(8) + +Stub8__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 08h +Stub8__14nsXPTCStubBaseFv endp + +; 9 STUB_ENTRY(7) + +Stub7__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 07h +Stub7__14nsXPTCStubBaseFv endp + +; 8 STUB_ENTRY(6) + +Stub6__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 06h +Stub6__14nsXPTCStubBaseFv endp + +; 7 STUB_ENTRY(5) + +Stub5__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 05h +Stub5__14nsXPTCStubBaseFv endp + +; 6 STUB_ENTRY(4) + +Stub4__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 04h +Stub4__14nsXPTCStubBaseFv endp + +; 5 STUB_ENTRY(3) + +Stub3__14nsXPTCStubBaseFv PROC OPTLINK EXPORT + setentidx 03h +Stub3__14nsXPTCStubBaseFv endp + + + END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore new file mode 100644 index 00000000..055e647f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/.cvsignore @@ -0,0 +1,2 @@ +Makefile +invoke_test diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in new file mode 100644 index 00000000..dbf0f64d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPPSRCS = stub_test.cpp #invoke_test.cpp +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README new file mode 100644 index 00000000..04850b2e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/README @@ -0,0 +1,6 @@ +These are just simple test programs in which stripped down versions of the +XPConnect invoke and stubs code can be built and tested as the code is brought +up on various platforms. These probrams do not test the param sizing and copying +functionality of the routines. However, they do supply a place where the lowest +level assembly language code can be developed and debugged in the simplest of +contexts before it is moved into the real routines. \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat new file mode 100644 index 00000000..f320e222 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/clean.bat @@ -0,0 +1,5 @@ +@echo off +echo deleting intermediate files +if exist *.obj del *.obj > NUL +if exist *.ilk del *.ilk > NUL +if exist *.pdb del *.pdb > NUL \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp new file mode 100644 index 00000000..376ba58f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/invoke_test.cpp @@ -0,0 +1,239 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 + +typedef unsigned nsresult; +typedef unsigned PRUint32; +typedef unsigned nsXPCVariant; + + +#if defined(WIN32) +#define NS_IMETHOD virtual nsresult __stdcall +#define NS_IMETHODIMP nsresult __stdcall +#else +#define NS_IMETHOD virtual nsresult +#define NS_IMETHODIMP nsresult +#endif + + +class base{ +public: + NS_IMETHOD ignored() = 0; +}; + +class foo : public base { +public: + NS_IMETHOD callme1(int i, int j) = 0; + NS_IMETHOD callme2(int i, int j) = 0; + NS_IMETHOD callme3(int i, int j) = 0; +}; + +class bar : public foo{ +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(int i, int j); + NS_IMETHOD callme2(int i, int j); + NS_IMETHOD callme3(int i, int j); +}; + +/* +class baz : public base { +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(); + NS_IMETHOD callme2(); + NS_IMETHOD callme3(); + void setfoo(foo* f) {other = f;} + + foo* other; +}; +NS_IMETHODIMP baz::ignored(){return 0;} +*/ + +NS_IMETHODIMP bar::ignored(){return 0;} + +NS_IMETHODIMP bar::callme1(int i, int j) +{ + printf("called bar::callme1 with: %d %d\n", i, j); + return 5; +} + +NS_IMETHODIMP bar::callme2(int i, int j) +{ + printf("called bar::callme2 with: %d %d\n", i, j); + return 5; +} + +NS_IMETHODIMP bar::callme3(int i, int j) +{ + printf("called bar::callme3 with: %d %d\n", i, j); + return 5; +} + +void docall(foo* f, int i, int j){ + f->callme1(i, j); +} + +/***************************************************************************/ +#if defined(WIN32) + +static PRUint32 __stdcall +invoke_count_words(PRUint32 paramCount, nsXPCVariant* s) +{ + return paramCount; +} + +static void __stdcall +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + *((PRUint32*)d) = *((PRUint32*)s); + } +} + +static nsresult __stdcall +DoInvoke(void* that, PRUint32 index, + PRUint32 paramCount, nsXPCVariant* params) +{ + __asm { + push params + push paramCount + call invoke_count_words // stdcall, result in eax + shl eax,2 // *= 4 + sub esp,eax // make space for params + mov edx,esp + push params + push paramCount + push edx + call invoke_copy_to_stack // stdcall + mov ecx,that // instance in ecx + push ecx // push this + mov edx,[ecx] // vtable in edx + mov eax,index + shl eax,2 // *= 4 + add edx,eax + call [edx] // stdcall, i.e. callee cleans up stack. + } +} + +#else +/***************************************************************************/ +// just Linux_x86 now. Add other later... + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPCVariant* s) +{ + return paramCount; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + *((PRUint32*)d) = *((PRUint32*)s); + } +} + +static nsresult +DoInvoke(void* that, PRUint32 index, + PRUint32 paramCount, nsXPCVariant* params) +{ + PRUint32 result; + void* fn_count = invoke_count_words; + void* fn_copy = invoke_copy_to_stack; + + __asm__ __volatile__( + "pushl %4\n\t" + "pushl %3\n\t" + "movl %5, %%eax\n\t" + "call *%%eax\n\t" /* count words */ + "addl $0x8, %%esp\n\t" + "shl $2, %%eax\n\t" /* *= 4 */ + "subl %%eax, %%esp\n\t" /* make room for params */ + "movl %%esp, %%edx\n\t" + "pushl %4\n\t" + "pushl %3\n\t" + "pushl %%edx\n\t" + "movl %6, %%eax\n\t" + "call *%%eax\n\t" /* copy params */ + "addl $0xc, %%esp\n\t" + "movl %1, %%ecx\n\t" + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %2, %%eax\n\t" /* function index */ + "shl $2, %%eax\n\t" /* *= 4 */ + "addl $8, %%eax\n\t" /* += 8 */ + "addl %%eax, %%edx\n\t" + "call *(%%edx)\n\t" /* safe to not cleanup esp */ + "movl %%eax, %0" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (index), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params), /* %4 */ + "g" (fn_count), /* %5 */ + "g" (fn_copy) /* %6 */ + : "ax", "cx", "dx", "memory" + ); + + return result; +} + +#endif +/***************************************************************************/ + +int main() +{ + nsXPCVariant params1[2] = {1,2}; + nsXPCVariant params2[2] = {2,4}; + nsXPCVariant params3[2] = {3,6}; + + foo* a = new bar(); + +// printf("calling via C++...\n"); +// docall(a, 12, 24); + + printf("calling via ASM...\n"); + DoInvoke(a, 1, 2, params1); + DoInvoke(a, 2, 2, params2); + DoInvoke(a, 3, 2, params3); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat new file mode 100644 index 00000000..10a9be51 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_invoke.bat @@ -0,0 +1,9 @@ +@echo off +@echo deleing old output +if exist invoke_test.obj del invoke_test.obj > NUL +if exist invoke_test.ilk del invoke_test.ilk > NUL +if exist *.pdb del *.pdb > NUL +if exist invoke_test.exe del invoke_test.exe > NUL + +@echo building... +cl /nologo -Zi -DWIN32 invoke_test.cpp \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat new file mode 100644 index 00000000..f9af17af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/mk_stub.bat @@ -0,0 +1,9 @@ +@echo off +@echo deleing old output +if exist stub_test.obj del stub_test.obj > NUL +if exist stub_test.ilk del stub_test.ilk > NUL +if exist *.pdb del *.pdb > NUL +if exist stub_test.exe del stub_test.exe > NUL + +@echo building... +cl /nologo -Zi -DWIN32 stub_test.cpp \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp new file mode 100644 index 00000000..10935299 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/test/stub_test.cpp @@ -0,0 +1,210 @@ + +#include + +typedef unsigned nsresult; +typedef unsigned PRUint32; +typedef unsigned nsXPCVariant; + + +#if defined(WIN32) +#define NS_IMETHOD virtual nsresult __stdcall +#define NS_IMETHODIMP nsresult __stdcall +#else +#define NS_IMETHOD virtual nsresult +#define NS_IMETHODIMP nsresult +#endif + + +class base{ +public: + NS_IMETHOD ignored() = 0; +}; + +class foo : public base { +public: + NS_IMETHOD callme1(int i, int j) = 0; + NS_IMETHOD callme2(int i, int j) = 0; + NS_IMETHOD callme3(int i, int j) = 0; +}; + +class bar : public foo{ +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(int i, int j); + NS_IMETHOD callme2(int i, int j); + NS_IMETHOD callme3(int i, int j); +}; + +class baz : public base { +public: + NS_IMETHOD ignored(); + NS_IMETHOD callme1(); + NS_IMETHOD callme2(); + NS_IMETHOD callme3(); + void setfoo(foo* f) {other = f;} + + foo* other; +}; +NS_IMETHODIMP baz::ignored(){return 0;} + +NS_IMETHODIMP bar::ignored(){return 0;} + +NS_IMETHODIMP bar::callme1(int i, int j) +{ + printf("called bar::callme1 with: %d %d\n", i, j); + return 15; +} + +NS_IMETHODIMP bar::callme2(int i, int j) +{ + printf("called bar::callme2 with: %d %d\n", i, j); + return 25; +} + +NS_IMETHODIMP bar::callme3(int i, int j) +{ + printf("called bar::callme3 with: %d %d\n", i, j); + return 35; +} + +void docall(foo* f, int i, int j){ + f->callme1(i, j); +} + +/***************************************************************************/ +#if defined(WIN32) + +static int __stdcall +PrepareAndDispatch(baz* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* stackBytesToPop) +{ + fprintf(stdout, "PrepareAndDispatch (%p, %d, %p)\n", + (void*)self, methodIndex, (void*)args); + foo* a = self->other; + int p1 = (int) *args; + int p2 = (int) *(args+1); + int out = 0; + switch(methodIndex) + { + case 1: out = a->callme1(p1, p2); break; + case 2: out = a->callme2(p1, p2); break; + case 3: out = a->callme3(p1, p2); break; + } + *stackBytesToPop = 2*4; + return out; +} + +#ifndef __GNUC__ +static __declspec(naked) void SharedStub(void) +{ + __asm { + push ebp // set up simple stack frame + mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args + push ecx // make room for a ptr + lea eax, [ebp-4] // pointer to stackBytesToPop + push eax + lea ecx, [ebp+16] // pointer to args + push ecx + mov edx, [ebp+4] // vtbl_index + push edx + mov eax, [ebp+12] // this + push eax + call PrepareAndDispatch + mov edx, [ebp+8] // return address + mov ecx, [ebp-4] // stackBytesToPop + add ecx, 12 // for this, the index, and ret address + mov esp, ebp + pop ebp + add esp, ecx // fix up stack pointer + jmp edx // simulate __stdcall return + } +} + +// these macros get expanded (many times) in the file #included below +#define STUB_ENTRY(n) \ +__declspec(naked) nsresult __stdcall baz::callme##n() \ +{ __asm push n __asm jmp SharedStub } + +#else /* __GNUC__ */ + +#define STUB_ENTRY(n) \ +nsresult __stdcall baz::callme##n() \ +{ \ + PRUint32 *args, stackBytesToPop; \ + int result = 0; \ + baz *obj; \ + __asm__ __volatile__ ( \ + "leal 0x0c(%%ebp), %0\n\t" /* args */ \ + "movl 0x08(%%ebp), %1\n\t" /* this */ \ + : "=r" (args), \ + "=r" (obj)); \ + result = PrepareAndDispatch(obj, n, args,&stackBytesToPop); \ + fprintf(stdout, "stub returning: %d\n", result); \ + fprintf(stdout, "bytes to pop: %d\n", stackBytesToPop); \ + return result; \ +} + +#endif /* ! __GNUC__ */ + +#else +/***************************************************************************/ +// just Linux_x86 now. Add other later... + +static int +PrepareAndDispatch(baz* self, PRUint32 methodIndex, PRUint32* args) +{ + foo* a = self->other; + int p1 = (int) *args; + int p2 = (int) *(args+1); + switch(methodIndex) + { + case 1: a->callme1(p1, p2); break; + case 2: a->callme2(p1, p2); break; + case 3: a->callme3(p1, p2); break; + } + return 1; +} + +#define STUB_ENTRY(n) \ +nsresult baz::callme##n() \ +{ \ + register void* method = PrepareAndDispatch; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx" /* PrepareAndDispatch */ \ + : "=a" (result) /* %0 */ \ + : "d" (method) /* %1 */ \ + : "memory" ); \ + return result; \ +} + +#endif +/***************************************************************************/ + +STUB_ENTRY(1) +STUB_ENTRY(2) +STUB_ENTRY(3) + +int main() +{ + foo* a = new bar(); + baz* b = new baz(); + + /* here we make the global 'check for alloc failure' checker happy */ + if(!a || !b) + return 1; + + foo* c = (foo*)b; + + b->setfoo(a); + c->callme1(1,2); + c->callme2(2,4); + c->callme3(3,6); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore new file mode 100644 index 00000000..ff6fd9bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/.cvsignore @@ -0,0 +1,2 @@ +Makefile +xptcstubs_asm_mips.s diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in new file mode 100644 index 00000000..78bf1f92 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.in @@ -0,0 +1,416 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +# +# The default is this buildable, but non-functioning code. +# +CPPSRCS := xptcinvoke_unsupported.cpp xptcstubs_unsupported.cpp + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +###################################################################### +# i386 and beyond +###################################################################### +# +# Lots of Unixish x86 flavors +# +ifneq (,$(filter FreeBSD NetBSD OpenBSD BSD_OS Darwin,$(OS_ARCH))) +ifeq (86,$(findstring 86,$(OS_TEST))) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif +endif +# +# New code for Linux, et. al., with gcc +# Migrate other platforms here after testing +# +ifneq (,$(filter Linux,$(OS_ARCH))) +# Linux/x86-64 +ifeq (x86_64,$(OS_TEST)) +CPPSRCS := xptcinvoke_x86_64_linux.cpp xptcstubs_x86_64_linux.cpp +else +ifeq (86,$(findstring 86,$(OS_TEST))) +CPPSRCS := xptcinvoke_gcc_x86_unix.cpp xptcstubs_gcc_x86_unix.cpp +endif +endif +endif +# IA64 Linux +ifneq (,$(filter Linux,$(OS_ARCH))) +ifneq (,$(findstring ia64,$(OS_TEST))) +CPPSRCS := xptcinvoke_ipf64.cpp xptcstubs_ipf64.cpp +ASFILES := xptcstubs_asm_ipf64.s xptcinvoke_asm_ipf64.s +endif +endif +# +# BeOS/Intel (uses the same unixish_x86 code) +# +ifeq ($(OS_ARCH)$(OS_TEST),BeOSBePC) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif +# +# Neutrino/Intel (uses the same unixish_x86 code) +# +ifeq ($(OS_TARGET)$(OS_TEST),NTOx86) +CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp +endif + +###################################################################### +# Solaris/Intel +###################################################################### +# +# Solaris/Intel +# +ifeq ($(OS_ARCH),SunOS) +ifeq ($(OS_TEST),i86pc) +CPPSRCS := xptcinvoke_x86_solaris.cpp xptcstubs_x86_solaris.cpp +# 28817: if Solaris Intel OS, and native compiler, always build optimised. +ifndef GNU_CC +CXXFLAGS += -O +endif +endif +endif + +###################################################################### +# Alpha +###################################################################### +# +# Tru64/Alpha +# +ifeq ($(OS_ARCH)$(OS_TEST),OSF1alpha) +CPPSRCS := xptcinvoke_osf1_alpha.cpp xptcstubs_osf1_alpha.cpp +ASFILES := xptcinvoke_asm_osf1_alpha.s xptcstubs_asm_osf1_alpha.s +endif +# +# Linux/Alpha +# +ifneq (,$(filter Linuxalpha FreeBSDalpha NetBSDalpha,$(OS_ARCH)$(OS_TEST))) +CPPSRCS := xptcinvoke_linux_alpha.cpp xptcstubs_linux_alpha.cpp +endif +# +# OpenVMS/Alpha +# +ifeq ($(OS_ARCH)$(CPU_ARCH),OpenVMSAlpha) +CPPSRCS := xptcinvoke_openvms_alpha.cpp xptcstubs_openvms_alpha.cpp +ASFILES := xptcinvoke_asm_openvms_alpha.s xptcstubs_asm_openvms_alpha.s +endif + +###################################################################### +# ARM +###################################################################### +# +# Linux/ARM +# +ifeq ($(OS_ARCH),Linux) +ifneq (,$(filter arm% sa110,$(OS_TEST))) +CPPSRCS := xptcinvoke_arm.cpp xptcstubs_arm.cpp +CXXFLAGS += -O2 +endif +endif +# +# NetBSD/ARM +# +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter arm% sa110,$(OS_TEST))) +CPPSRCS := xptcinvoke_arm_netbsd.cpp xptcstubs_arm_netbsd.cpp +endif +endif + +###################################################################### +# HPPA +###################################################################### +# +# HP-UX/PA32 +# +# for gas and gcc, check comment in xptcinvoke_asm_pa32.s +ifeq ($(OS_ARCH),HP-UX) +ifneq ($(CC),gcc) +ifneq ($(OS_TEST),ia64) +CPPSRCS := xptcinvoke_pa32.cpp xptcstubs_pa32.cpp +ASFILES := xptcstubs_asm_pa32.s xptcinvoke_asm_pa32.s +else +CPPSRCS := xptcinvoke_ipf32.cpp xptcstubs_ipf32.cpp +ASFILES := xptcstubs_asm_ipf32.s xptcinvoke_asm_ipf32.s +endif + +# #18875 Building the CPP's (CXX) optimized causes a crash +CXXFLAGS := $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(CXXFLAGS)) +endif +endif + +###################################################################### +# M68k +###################################################################### +# +# NetBSD/m68k +# +ifeq ($(OS_ARCH),NetBSD) +ifneq (,$(filter amiga atari hp300 mac68k mvme68k next68k sun3 sun3x x68k,$(OS_TEST))) +CPPSRCS := xptcinvoke_netbsd_m68k.cpp xptcstubs_netbsd_m68k.cpp +endif +endif + +# +# Linux/m68k +# +ifeq ($(OS_ARCH),Linux) +ifeq ($(OS_TEST),m68k) +CPPSRCS := xptcinvoke_linux_m68k.cpp xptcstubs_linux_m68k.cpp +endif +endif + +###################################################################### +# MIPS +###################################################################### +# +# IRIX/MIPS +# +ifeq ($(OS_ARCH),IRIX) +ifneq ($(basename $(OS_RELEASE)),5) +CPPSRCS := xptcinvoke_irix.cpp xptcstubs_irix.cpp +ASFILES := xptcinvoke_asm_irix.s xptcstubs_asm_irix.s +ifdef GNU_CC +ASFLAGS += -Wa,-D__GNUC__ +else +CXXFLAGS := $(shell echo $(CXXFLAGS) | sed 's/-O\(3\|fast\)/-O2/g') +endif +endif +endif + +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring mips, $(OS_TEST))) +CPPSRCS := xptcinvoke_mips.cpp xptcstubs_mips.cpp +ASFILES := xptcinvoke_asm_mips.s xptcstubs_asm_mips.s +#xptcstubs_mips.cpp +# xptcstubs_asm_mips.s +ifdef GNU_CC +ASFLAGS += $(INCLUDES) -x assembler-with-cpp -D__GNUC__ +endif +endif +endif + +###################################################################### +# PowerPC +###################################################################### +# +# AIX/PPC +# +ifeq ($(OS_ARCH),AIX) +ifdef HAVE_64BIT_OS +CPPSRCS := xptcinvoke_ppc_aix64.cpp xptcstubs_ppc_aix64.cpp +ASFILES := xptcinvoke_asm_ppc_aix64.s xptcstubs_asm_ppc_aix64.s +else +ifeq ($(AIX_OBJMODEL),ibm) +CPPSRCS := xptcinvoke_ppc_aix.cpp xptcstubs_ppc_aix.cpp +ASFILES := xptcinvoke_asm_ppc_ibmobj_aix.s xptcstubs_asm_ppc_aix.s +else +CPPSRCS := xptcinvoke_ppc_aix.cpp xptcstubs_ppc_aix.cpp +ASFILES := xptcinvoke_asm_ppc_aix.s xptcstubs_asm_ppc_aix.s +endif +endif + +# #24617 Building the CPP's (CXX) optimized causes a crash +CXXFLAGS := $(filter-out $(MOZ_OPTIMIZE_FLAGS), $(CXXFLAGS)) +endif + +# +# Linux/PPC +# +ifeq ($(OS_ARCH)$(OS_TEST),Linuxppc) +CPPSRCS := xptcinvoke_ppc_linux.cpp xptcstubs_ppc_linux.cpp +ASFILES := xptcinvoke_asm_ppc_linux.s xptcstubs_asm_ppc_linux.s +AS := $(CC) -c -x assembler-with-cpp +endif + +# +# NetBSD/PPC +# +ifneq (,$(filter NetBSDmacppc NetBSDbebox NetBSDofppc NetBSDprep NetBSDamigappc,$(OS_ARCH)$(OS_TEST))) +CPPSRCS := xptcinvoke_ppc_netbsd.cpp xptcstubs_ppc_netbsd.cpp +ASFILES := xptcinvoke_asm_ppc_netbsd.s xptcstubs_asm_ppc_netbsd.s +endif + +# +# Darwin/PPC +# +ifeq ($(OS_ARCH),Darwin) +ifeq ($(TARGET_CPU), powerpc) +ASFLAGS += -x assembler-with-cpp # assumes $(AS) == $(CC) +ifdef HAVE_GCC3_ABI +ASFLAGS += -DHAVE_GCC3_ABI +endif +CPPSRCS := xptcinvoke_ppc_rhapsody.cpp xptcstubs_ppc_rhapsody.cpp +ASFILES := xptcinvoke_asm_ppc_rhapsody.s xptcstubs_asm_ppc_darwin.s +endif +endif + +###################################################################### +# SPARC +###################################################################### +# +# BSD_OS/SPARC +# +ifeq ($(OS_ARCH),BSD_OS) +ifneq (,$(findstring sparc,$(OS_TEST))) +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +ASFILES := xptcinvoke_asm_sparc_bsdos.s xptcstubs_asm_sparc_solaris.s +endif +endif +# +# Linux/SPARC +# +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring sparc,$(OS_TEST))) +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +ifdef HAVE_GCC3_ABI +ASFILES := xptcinvoke_asm_sparc_linux_GCC3.s xptcstubs_asm_sparc_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_linux.s xptcstubs_asm_sparc_solaris.s +endif +endif +endif +# +# NetBSD/SPARC +# +ifeq ($(OS_ARCH)$(OS_TEST),NetBSDsparc) +CPPSRCS := xptcinvoke_sparc_netbsd.cpp xptcstubs_sparc_netbsd.cpp +ASFILES := xptcinvoke_asm_sparc_netbsd.s xptcstubs_asm_sparc_netbsd.s +endif +# +# Solaris/SPARC +# +ifeq ($(OS_ARCH),SunOS) +ifneq (86,$(findstring 86,$(OS_TEST))) +ifdef HAVE_64BIT_OS +CPPSRCS := xptcinvoke_sparcv9_solaris.cpp xptcstubs_sparcv9_solaris.cpp +else +CPPSRCS := xptcinvoke_sparc_solaris.cpp xptcstubs_sparc_solaris.cpp +endif + +ifeq ($(GNU_CC),1) +ifdef HAVE_GCC3_ABI +ASFILES := xptcinvoke_asm_sparc_solaris_GCC3.s xptcstubs_asm_sparc_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_solaris_GCC.s xptcstubs_asm_sparc_solaris.s +endif +else +ifdef HAVE_64BIT_OS +ASFILES := xptcinvoke_asm_sparcv9_solaris_SUNW.s xptcstubs_asm_sparcv9_solaris.s +else +ASFILES := xptcinvoke_asm_sparc_solaris_SUNW.s xptcstubs_asm_sparc_solaris.s +endif +endif + +endif +endif + +###################################################################### +# S/390 +###################################################################### +# +# Linux for S/390 +# +ifeq ($(OS_ARCH)$(OS_TEST),Linuxs390) +CPPSRCS := xptcinvoke_linux_s390.cpp xptcstubs_linux_s390.cpp +endif + +ifeq ($(OS_ARCH)$(OS_TEST),Linuxs390x) +CPPSRCS := xptcinvoke_linux_s390x.cpp xptcstubs_linux_s390x.cpp +endif + + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API + +INCLUDES += -I$(srcdir)/../.. + +ifeq ($(OS_ARCH),Linux) +ifneq (,$(findstring mips, $(OS_TEST))) +xptcstubs_asm_mips.o: xptcstubs_asm_mips.s.m4 $(PUBLIC)/xptcstubsdef.inc + m4 $(INCLUDES) $< > ./xptcstubs_asm_mips.s && \ + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_mips.s + $(RM) -f ./xptcstubs_asm_mips.s +endif +endif + +ifeq ($(OS_ARCH),Darwin) +xptcstubs_asm_ppc_darwin.o: xptcstubs_asm_ppc_darwin.s.m4 $(PUBLIC)/xptcstubsdef.inc Makefile + gm4 $(INCLUDES) $< > ./xptcstubs_asm_ppc_darwin.s && \ + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_ppc_darwin.s + $(RM) -f ./xptcstubs_asm_ppc_darwin.s +endif + +ifeq ($(OS_ARCH),IRIX) +# The assembler on IRIX (6.3 only?) seems to have trouble with the default command, +# but works fine if we first copy the header and source file into the current dir. +xptcstubs_asm_irix.o: $(PUBLIC)/xptcstubsdef.inc $(srcdir)/xptcstubs_asm_irix.s + @rm -f ./xptcstubsdef.inc + @cp $(PUBLIC)/xptcstubsdef.inc . + @if test ! -f ./Makefile.in; then rm -f ./xptcstubs_asm_irix.s; cp $(srcdir)/xptcstubs_asm_irix.s .; else true; fi + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) ./xptcstubs_asm_irix.s + @rm -f ./xptcstubsdef.inc + @if test ! -f ./Makefile.in; then rm -f ./xptcstubs_asm_irix.s; else true; fi +endif + +ifeq ($(OS_ARCH),OpenVMS) +# Our assembler wants the include file to be of assembler syntax, not C/C++ +# syntax, so we have to massage it slightly. + +xptcstubs_asm_openvms_alpha.o: $(PUBLIC)/xptcstubsdef.inc $(srcdir)/xptcstubs_asm_openvms_alpha.s + sed \ + -e 's/^\(.*_ENTRY\)(\([0-9]*\))/ \1 \2/' \ + -e 's/\/\*\(.*\)\*\//; \1/' \ + $(PUBLIC)/xptcstubsdef.inc > ./xptcstubsdef_asm.vms + $(AS) -o $@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(srcdir)/xptcstubs_asm_openvms_alpha.s + @rm -f ./xptcstubsdef_asm.vms +endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp new file mode 100644 index 00000000..912f50e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/vtable_layout_x86.cpp @@ -0,0 +1,62 @@ +/* this code contributed by Bert Driehuis */ + +#include + +// Try to determine the vtable layout generated by G++ +// Produces the offset at which the first vtable entry can be +// found, and the factor to apply for subsequent entries on stdout. +// Example output: +// #define GCC_VTABLE_START 0xc +// #define GCC_VTABLE_FACTOR 0x8 + +class test { +public: + virtual int t1(void); + virtual int t2(void); + int x; +}; + +test::test() { this->x = 0x12121212; }; + +int test::t1(void) { return 1; } +int test::t2(void) { return 2; } + +void die(char *x) { + fprintf(stderr, "%s\n", x); + exit(1); +} + +int +main() +{ + int i; + test *t = new test(); + int *tp = (int *) t; + int off1 = -1; + int off2 = -1; + int factor; + int factorshift; + + if (*tp++ != 0x12121212) + die("Integer element test::x not found!"); + tp = (int *) *tp; + for (i = 0; i < 10; i++) { + if (tp[i] == (int) t->t1) + off1 = i; + if (tp[i] == (int) t->t2) + off2 = i; + } + if (off1 == -1 || off2 == -1) + die("Could not determine offset into vtable!"); + factor = (off2 - off1) * 4; + factorshift = -1; + while (factor) { + factorshift++; + factor >>= 1; + } + printf("/* Automatically generated by vtable_layout_x86.cpp */\n"); + printf("#define GCC_VTABLE_START\t0x%x\n", off1 * 4); + printf("#define GCC_VTABLE_FACTOR\t0x%x\n", (off2 - off1) * 4); + printf("#define GCC_VTABLE_SHIFT\t0x%x\n", factorshift); + exit(0); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h new file mode 100644 index 00000000..707352aa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Special include file for xptc*_gcc_x86_unix.cpp */ + +// +// this may improve the static function calls, but may not. +// + +// #define MOZ_USE_STDCALL + +#ifdef MOZ_USE_STDCALL +#define ATTRIBUTE_STDCALL __attribute__ ((__stdcall__)) +#else +#define ATTRIBUTE_STDCALL +#endif + +#ifdef MOZ_NEED_LEADING_UNDERSCORE +#define SYMBOL_UNDERSCORE "_" +#else +#define SYMBOL_UNDERSCORE +#endif + +/* + What are those keeper functions? + + The problem: gcc doesn't know that the assembler routines call + static functions so gcc may not emit the definition (i.e., the + code) for these functions. In gcc 3.1 and up + "__attribute__ ((used))" exists and solves the problem. + For older gcc versions it's not so easy. One could use the + -fkeep-inline-functions but that keeps a surprising number of + functions which bloats the compiled library. It seems otherwise + harmless, though. Alternatively, one could use + -fno-inline-functions which works right now but might cause a + slowdown under some circumstances. The problem with these methods + is that they do not automatically adapt to the compiler used. + + The best solution seems to be to create dummy functions that + reference the appropriate static functions. It's then necessary + to "use" these functions in a way that gcc will not optimize + away. The keeper functions use assembly code to confuse gcc. + + One drawback is that the keeper functions are externally visible + so they shouldn't do anything harmful. + + With the right linker, one could make the keeper functions local + so they wouldn't be visible. + */ + + +// gcc 3.1 and up +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define ATTRIBUTE_USED __attribute__ ((__used__)) +#else +#define ATTRIBUTE_USED +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h new file mode 100644 index 00000000..23eb23ee --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific #defines to be shared by the various platforms sharing +* the unixish_86 code +*/ + +/* +* The goal here is to clearly define the binary compatibility parameters for +* the platforms that will use this code. Rather than switch at compile time +* based on the compiler that happens to be in use we are forcing implementors +* to make a conscious decision. +* +* For some of these platforms the community may choose to have more than one +* binary model in effect. In that case I suggest that there be explicit sub +* defines for that platform specifying 'TYPE1', 'TYPE2', etc. The decision on +* which 'TYPE' to use would be triggered by a setting passed through from the +* config system. +* +* For example we might end up with something like: +* +* #elif defined(NTO) +* # if defined(TYPE1) +* # define CFRONT_STYLE_THIS_ADJUST +* # elif defined(TYPE1) +* # define THUNK_BASED_THIS_ADJUST +* # else +* # error "need TYPE1 or TYPE2 for NTO" +* # endif +* #elif defined(__BEOS__) +* +* and so on.... +* +*/ + +#if defined(LINUX) + +#if (__GNUC__ == 2) && (__GNUC_MINOR__ <= 7) +/* Old gcc 2.7.x.x. What does gcc 2.8.x do?? */ +#define CFRONT_STYLE_THIS_ADJUST +#else +/* egcs and later */ +#define THUNK_BASED_THIS_ADJUST +#endif + +#elif defined(__FreeBSD__) +/* System versions of gcc on FreeBSD don't use thunks. On 3.x, the system + * compiler is gcc 2.7.2.3, which doesn't use thunks by default. On 4.x and + * 5.x, /usr/src/contrib/gcc/config/freebsd.h explicitly undef's + * DEFAULT_VTABLE_THUNKS. (The one exception is a brief period (September + * 1999 - Jan 2000) during 4.0-CURRENT, after egcs was merged -- + * this was changed before 4.0-RELEASE, but we can handle it anyway.) + * + * Versions of gcc from the ports collection (/usr/ports/lang/egcs), + * however, have DEFAULT_VTABLE_THUNKS #defined to 1, at least + * in all ports collections since the 2.95 merge. (Supporting optional + * compilers from FreeBSD 3.2 or earlier seems unnecessary). + * + * The easiest way to distinguish the ports collection gcc from the system + * gcc is that the system gcc defines __FreeBSD_cc_version. This variable + * can also identify versions that use thunks. This includes some 4.x versions + * and now newer 5.x versions. + */ +#if defined(__FreeBSD_cc_version) && \ + (__FreeBSD_cc_version < 500003) && \ + (__FreeBSD_cc_version < 400002 || __FreeBSD_cc_version > 400003) +#define CFRONT_STYLE_THIS_ADJUST +#else +#define THUNK_BASED_THIS_ADJUST +#endif + +#elif defined(__NetBSD__) +#define THUNK_BASED_THIS_ADJUST + +#elif defined(__OpenBSD__) +/* OpenBSD instroduces GCC 2.95.x in late May 1999 */ +#include +#if OpenBSD <= 199905 +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(__bsdi__) +#include +#if _BSDI_VERSION >= 199910 +/* BSDI/4.1 ships with egcs, ergo thunk-based */ +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(NTO) +#define CFRONT_STYLE_THIS_ADJUST + +#elif defined(__BEOS__) +#define CFRONT_STYLE_THIS_ADJUST + +#elif defined(__sun__) || defined(__sun) +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +#define THUNK_BASED_THIS_ADJUST +#else +#define CFRONT_STYLE_THIS_ADJUST +#endif + +#elif defined(_WIN32) +#define THUNK_BASED_THIS_ADJUST + +#elif defined(__EMX__) +#define THUNK_BASED_THIS_ADJUST + +#elif defined (__APPLE__) && (__MACH__) +#define THUNK_BASED_THIS_ADJUST + +#else +#error "need a platform define if using unixish x86 code" +#endif + +/***************************************************************************/ + +#if !defined(THUNK_BASED_THIS_ADJUST) && !defined(CFRONT_STYLE_THIS_ADJUST) +#error "need to define 'this' adjust scheme" +#endif + +#if defined(THUNK_BASED_THIS_ADJUST) && defined(CFRONT_STYLE_THIS_ADJUST) +#error "need to define only ONE 'this' adjust scheme" +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp new file mode 100644 index 00000000..af2919d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_darwin.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +#include "xptcprivate.h" + +// 6 integral parameters are passed in registers +const PRUint32 GPR_COUNT = 6; + +// 8 floating point parameters are passed in SSE registers +const PRUint32 FPR_COUNT = 8; + +// Remember that these 'words' are 64-bit long +static inline void +invoke_count_words(PRUint32 paramCount, nsXPTCVariant * s, + PRUint32 & nr_gpr, PRUint32 & nr_fpr, PRUint32 & nr_stack) +{ + nr_gpr = 1; // skip one GP register for 'that' + nr_fpr = 0; + nr_stack = 0; + + /* Compute number of eightbytes of class MEMORY. */ + for (uint32 i = 0; i < paramCount; i++, s++) { + if (!s->IsPtrData() + && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(PRUint64 * d, PRUint32 paramCount, nsXPTCVariant * s, + PRUint64 * gpregs, double * fpregs) +{ + PRUint32 nr_gpr = 1; // skip one GP register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (uint32 i = 0; i < paramCount; i++, s++) { + if (s->IsPtrData()) + value = (PRUint64) s->ptr; + else { + switch (s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: value = s->val.i8; break; + case nsXPTType::T_I16: value = s->val.i16; break; + case nsXPTType::T_I32: value = s->val.i32; break; + case nsXPTType::T_I64: value = s->val.i64; break; + case nsXPTType::T_U8: value = s->val.u8; break; + case nsXPTType::T_U16: value = s->val.u16; break; + case nsXPTType::T_U32: value = s->val.u32; break; + case nsXPTType::T_U64: value = s->val.u64; break; + case nsXPTType::T_BOOL: value = s->val.b; break; + case nsXPTType::T_CHAR: value = s->val.c; break; + case nsXPTType::T_WCHAR: value = s->val.wc; break; + default: value = (PRUint64) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + fpregs[nr_fpr++] = s->val.d; + else { + *((double *)d) = s->val.d; + d++; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + fpregs[nr_fpr++] = s->val.d; + else { + *((float *)d) = s->val.f; + d++; + } + } + else { + if (nr_gpr < GPR_COUNT) + gpregs[nr_gpr++] = value; + else + *d++ = value; + } + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports * that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant * params) +{ + PRUint32 nr_gpr, nr_fpr, nr_stack; + invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + + // Load parameters to stack, if necessary + PRUint64 *stack = (PRUint64 *) __builtin_alloca(nr_stack * 8); + PRUint64 gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; + invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); + + // disable the warning about sometimes not initialized variables which is hit + // when we pass less than 8 XMM or less than 6 GPR registers. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsometimes-uninitialized" + + // Load FPR registers from fpregs[] + register double d0 asm("xmm0"); + register double d1 asm("xmm1"); + register double d2 asm("xmm2"); + register double d3 asm("xmm3"); + register double d4 asm("xmm4"); + register double d5 asm("xmm5"); + register double d6 asm("xmm6"); + register double d7 asm("xmm7"); + + switch (nr_fpr) { +#define ARG_FPR(N) \ + case N+1: d##N = fpregs[N]; + ARG_FPR(7); + ARG_FPR(6); + ARG_FPR(5); + ARG_FPR(4); + ARG_FPR(3); + ARG_FPR(2); + ARG_FPR(1); + ARG_FPR(0); + case 0:; +#undef ARG_FPR + } + + // Load GPR registers from gpregs[] + register PRUint64 a0 asm("rdi"); + register PRUint64 a1 asm("rsi"); + register PRUint64 a2 asm("rdx"); + register PRUint64 a3 asm("rcx"); + register PRUint64 a4 asm("r8"); + register PRUint64 a5 asm("r9"); + + switch (nr_gpr) { +#define ARG_GPR(N) \ + case N+1: a##N = gpregs[N]; + ARG_GPR(5); + ARG_GPR(4); + ARG_GPR(3); + ARG_GPR(2); + ARG_GPR(1); + case 1: a0 = (PRUint64) that; + case 0:; +#undef ARG_GPR + } + + // Ensure that assignments to SSE registers won't be optimized away + asm("" :: + "x" (d0), "x" (d1), "x" (d2), "x" (d3), + "x" (d4), "x" (d5), "x" (d6), "x" (d7)); + + // Get pointer to method + PRUint64 methodAddress = *((PRUint64 *)that); + methodAddress += 8 * methodIndex; + methodAddress = *((PRUint64 *)methodAddress); + + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5); + return result; + +#pragma clang diagnostic pop +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm new file mode 100644 index 00000000..c0746855 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_amd64_vbox.asm @@ -0,0 +1,403 @@ +; $Id: xptcinvoke_amd64_vbox.asm $ +;; @file +; XPCOM - Implementation XPTC_InvokeByIndex in assembly. +; +; This solves the problem of Clang and gcc (sometimes) not playing along with +; the alloca() based trick to pass stack parameters. We first had trouble +; when enabling asan with gcc 8.2, then Clang 11 on mac had similar issues +; (at least for profile builds). +; + +; +; Copyright (C) 2020-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; SPDX-License-Identifier: GPL-3.0-only +; + + +;********************************************************************************************************************************* +;* Internal Functions * +;********************************************************************************************************************************* +%include "iprt/asmdefs.mac" + + +;********************************************************************************************************************************* +;* Structures and Typedefs * +;********************************************************************************************************************************* +struc nsXPTCVariant + .val resq 1 + .ptr resq 1 + .type resb 1 + .flags resb 1 + alignb 8 +endstruc + + +;********************************************************************************************************************************* +;* Defined Constants And Macros * +;********************************************************************************************************************************* +;; @name Selected nsXPTCVariant::flags values. +;; @{ +%define PTR_IS_DATA 1 +;; @} + +;; @name Selected nsXPTType (nsXPTCVariant::type) values. +;; @{ +%define T_FLOAT 8 +%define T_DOUBLE 9 +;; @} + +;; Error code we use if there are too many parameters. +%define DISP_E_BADPARAMCOUNT 0x8002000e + +;; Effect name mangling. +%ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + %define XPTC_InvokeByIndex VBoxNsxpXPTC_InvokeByIndex +%endif + + +BEGINCODE + +;; +; +; @cproto nsresult XPTC_InvokeByIndex(nsISupports *pThat, PRUint32 idxMethod, PRUint32 cParams, nsXPTCVariant *paParams) +; +; @param pThat Pointer to the object we're invoking a method on. register:rdi +; @param idxMethod The VTable method index. register:esi +; @param cParams Number of parameters in addition to pThat. register:edx +; @param paParams Array of parameter values and info. register:rcx +; +BEGINPROC_EXPORTED XPTC_InvokeByIndex + push rbp + mov rbp, rsp + push rbx + push r12 + + ; + ; Move essential input parameters into non-parameter registers. + ; + mov rbx, rcx ; rbx = first / current parameter + mov r12d, edx ; r12 = parameter count / left + + ; Look up the method address in the vtable and store it in r11 (freeing up rsi). + mov r11, [rdi] ; r11 = vtable + mov esi, esi ; zero extend vtable index. + mov r11, [r11 + rsi * 8] ; r11 = method to call. + +%define WITH_OPTIMIZATION +%ifdef WITH_OPTIMIZATION + ; + ; If there are 5 or fewer parameters and they are all suitable for GREGs, + ; we can try optimize the processing here. + ; + ; Switch on count, using fall-thought-to-smaller-value logic, default + ; case goes to generic (slow) code path. + ; + dec edx ; we can still use edx for the parameter count here as a throwaway. + jz .fast_1 + dec edx + jz .fast_2 + dec edx + jz .fast_3 + dec edx + jz .fast_4 + dec edx + jnz .slow_or_zero +%macro fast_case 4 +%1: + mov eax, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.type] ; ASSUMES 'type' and 'flags' are adjacent byte fields. + test ah, PTR_IS_DATA + mov %4, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.ptr] + jnz %2 + sub al, T_FLOAT + sub al, 2 + jl .fast_bailout + mov %4, [rbx + nsXPTCVariant_size * %3 + nsXPTCVariant.val] +%endmacro + fast_case .fast_5, .fast_4, 4, r9 + fast_case .fast_4, .fast_3, 3, r8 + fast_case .fast_3, .fast_2, 2, rcx + fast_case .fast_2, .fast_1, 1, rdx + fast_case .fast_1, .fast_0, 0, rsi +.fast_0: + xor eax, eax + call r11 ; note! stack is aligned here. + +.fast_return: + lea rsp, [rbp - 8*2] + pop r12 + pop rbx + leave + ret + +.slow_or_zero: + cmp r12d, 0 + je .fast_0 + %if 0 + jmp .slow +.fast_bailout: + int3 + %else +.fast_bailout: + %endif +.slow: +%endif + ; One more push. + push r13 + + ; + ; Check that there aren't unreasonably many parameters + ; (we could do ~255, but 64 is more reasonable number). + ; + cmp r12d, 64 + je .too_many_parameters + + ; + ; For simplicity reserve stack space for all parameters and point r10 at it. + ; + lea edx, [r12d * 8] + sub rsp, rdx + and rsp, byte 0ffffffffffffffe0h ; 32 byte aligned stack. + mov r10, rsp ; r10 = next stack parameter. + + ; + ; Set up parameter pointer and register distribution counts. + ; + mov eax, 1 ; al = greg count, ah = fpreg count. + + ; + ; Anything to do here? + ; +%ifndef WITH_OPTIMIZATION + test r12d,r12d + jz .make_call +%endif + jmp .param_loop + + ; + ; The loop. + ; + ALIGNCODE(64) +.param_loop_advance: + add rbx, nsXPTCVariant_size +.param_loop: + ; First test for pointers using 'flags' then work 'type' for the rest. + test byte [rbx + nsXPTCVariant.flags], PTR_IS_DATA + jnz .is_ptr + cmp byte [rbx + nsXPTCVariant.type], T_FLOAT + jge .maybe_in_fpreg + + ; + ; nsXPTCVariant.val belongs in a GREG or on the stack. + ; Note! Hope we can get away with not zero extending the value here. + ; +.in_greg: + inc al + cmp al, 1+1 + je .in_greg_rsi + cmp al, 2+1 + je .in_greg_rdx + cmp al, 3+1 + je .in_greg_rcx + cmp al, 4+1 + je .in_greg_r8 + cmp al, 5+1 + ja .on_stack +.in_greg_r9: + mov r9, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_r8: + mov r8, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rcx: + mov rcx, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rdx: + mov rdx, [rbx + nsXPTCVariant.val] + jmp .next +.in_greg_rsi: + mov rsi, [rbx + nsXPTCVariant.val] + jmp .next + + ; + ; Pointers are loaded from the 'ptr' rather than the 'val' member. + ; + ALIGNCODE(64) +.is_ptr: + inc al + cmp al, 1+1 + je .ptr_in_greg_rsi + cmp al, 2+1 + je .ptr_in_greg_rdx + cmp al, 3+1 + je .ptr_in_greg_rcx + cmp al, 4+1 + je .ptr_in_greg_r8 + cmp al, 5+1 + je .ptr_in_greg_r9 + mov r13, [rbx + nsXPTCVariant.ptr] + jmp .r13_on_stack + +.ptr_in_greg_r9: + mov r9, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_r8: + mov r8, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rcx: + mov rcx, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rdx: + mov rdx, [rbx + nsXPTCVariant.ptr] + jmp .next +.ptr_in_greg_rsi: + mov rsi, [rbx + nsXPTCVariant.ptr] + jmp .next + + ; + ; Maybe we've got a float or double type here... + ; +.maybe_in_fpreg: + je .float_in_fpreg + cmp byte [rbx + nsXPTCVariant.type], T_DOUBLE + jne .in_greg + +.double_in_fpreg: + cmp ah, 8 ; Ensure max AL value of 8 when making call. + jge .on_stack + inc ah + cmp ah, 0+1 + je .double_in_xmm0 + cmp ah, 1+1 + je .double_in_xmm1 + cmp ah, 2+1 + je .double_in_xmm2 + cmp ah, 3+1 + je .double_in_xmm3 + cmp ah, 4+1 + je .double_in_xmm4 + cmp ah, 5+1 + je .double_in_xmm5 + cmp ah, 6+1 + je .double_in_xmm6 +.double_in_xmm7: + movsd xmm7, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm6: + movsd xmm6, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm5: + movsd xmm5, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm4: + movsd xmm4, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm3: + movsd xmm3, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm2: + movsd xmm2, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm1: + movsd xmm1, [rbx + nsXPTCVariant.val] + jmp .next +.double_in_xmm0: + movsd xmm0, [rbx + nsXPTCVariant.val] + jmp .next + +.float_in_fpreg: + cmp ah, 8 ; Ensure max AL value of 8 when making call. + jge .on_stack + inc ah + cmp ah, 0+1 + je .float_in_xmm0 + cmp ah, 1+1 + je .float_in_xmm1 + cmp ah, 2+1 + je .float_in_xmm2 + cmp ah, 3+1 + je .float_in_xmm3 + cmp ah, 4+1 + je .float_in_xmm4 + cmp ah, 5+1 + je .float_in_xmm5 + cmp ah, 6+1 + je .float_in_xmm6 +.float_in_xmm7: + movss xmm7, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm6: + movss xmm6, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm5: + movss xmm5, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm4: + movss xmm4, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm3: + movss xmm3, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm2: + movss xmm2, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm1: + movss xmm1, [rbx + nsXPTCVariant.val] + jmp .next +.float_in_xmm0: + movss xmm0, [rbx + nsXPTCVariant.val] + jmp .next + + ; + ; Put the value onto the stack via r13. + ; + ALIGNCODE(64) +.on_stack: + mov r13, [rbx + nsXPTCVariant.val] +.r13_on_stack: + mov [r10], r13 + lea r10, [r10 + 8] + + ; + ; Update parameter pointer and count and maybe loop again. + ; +.next: + dec r12d + jnz .param_loop_advance + + ; + ; Call the method and return. + ; +.make_call: + movzx eax, ah ; AL = number of parameters in XMM registers (variadict only, but easy to do). +.make_just_call: + call r11 + +.return: + lea rsp, [rbp - 8*3] + pop r13 + pop r12 + pop rbx + leave + ret + +.too_many_parameters: + mov eax, DISP_E_BADPARAMCOUNT + jmp .return +ENDPROC XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp new file mode 100644 index 00000000..1b2c5c67 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if !defined(LINUX) || !defined(__arm__) +#error "This code is for Linux ARM only. Check that it works on your system, too.\nBeware that this code is highly compiler dependent." +#endif + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" { + struct my_params_struct { + nsISupports* that; + PRUint32 Index; + PRUint32 Count; + nsXPTCVariant* params; + PRUint32 fn_count; + PRUint32 fn_copy; + }; +}; + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + struct my_params_struct my_params; + my_params.that = that; + my_params.Index = methodIndex; + my_params.Count = paramCount; + my_params.params = params; + my_params.fn_copy = (PRUint32) &invoke_copy_to_stack; + my_params.fn_count = (PRUint32) &invoke_count_words; + +/* This is to call a given method of class that. + * The parameters are in params, the number is in paramCount. + * The routine will issue calls to count the number of words + * required for argument passing and to copy the arguments to + * the stack. + * Since APCS passes the first 3 params in r1-r3, we need to + * load the first three words from the stack and correct the stack + * pointer (sp) in the appropriate way. This means: + * + * 1.) more than 3 arguments: load r1-r3, correct sp and remember No. + * of bytes left on the stack in r4 + * + * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope), + * restore sp as if nothing had happened and set the marker r4 to zero. + * + * Afterwards sp will be restored using the value in r4 (which is not a temporary register + * and will be preserved by the function/method called according to APCS [ARM Procedure + * Calling Standard]). + * + * !!! IMPORTANT !!! + * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented + * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])! + * + */ + + __asm__ __volatile__( + "ldr r1, [%1, #12] \n\t" /* prepare to call invoke_count_words */ + "ldr ip, [%1, #16] \n\t" /* r0=paramCount, r1=params */ + "ldr r0, [%1, #8] \n\t" + "mov lr, pc \n\t" /* call it... */ + "mov pc, ip \n\t" + "mov r4, r0, lsl #2 \n\t" /* This is the amount of bytes needed. */ + "sub sp, sp, r4 \n\t" /* use stack space for the args... */ + "mov r0, sp \n\t" /* prepare a pointer an the stack */ + "ldr r1, [%1, #8] \n\t" /* =paramCount */ + "ldr r2, [%1, #12] \n\t" /* =params */ + "ldr ip, [%1, #20] \n\t" /* =invoke_copy_to_stack */ + "mov lr, pc \n\t" /* copy args to the stack like the */ + "mov pc, ip \n\t" /* compiler would. */ + "ldr r0, [%1] \n\t" /* =that */ + "ldr r1, [r0, #0] \n\t" /* get that->vtable offset */ + "ldr r2, [%1, #4] \n\t" + "mov r2, r2, lsl #2 \n\t" /* a vtable_entry(x)=8 + (4 bytes * x) */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "ldr ip, [r1, r2] \n\t" /* get method adress from vtable */ +#else /* non G++ V3 ABI */ + "add r2, r2, #8 \n\t" /* with this compilers */ + "ldr ip, [r1, r2] \n\t" /* get method adress from vtable */ +#endif + "cmp r4, #12 \n\t" /* more than 3 arguments??? */ + "ldmgtia sp!, {r1, r2, r3}\n\t" /* yes: load arguments for r1-r3 */ + "subgt r4, r4, #12 \n\t" /* and correct the stack pointer */ + "ldmleia sp, {r1, r2, r3}\n\t" /* no: load r1-r3 from stack */ + "addle sp, sp, r4 \n\t" /* and restore stack pointer */ + "movle r4, #0 \n\t" /* a mark for restoring sp */ + "ldr r0, [%1, #0] \n\t" /* get (self) */ + "mov lr, pc \n\t" /* call mathod */ + "mov pc, ip \n\t" + "add sp, sp, r4 \n\t" /* restore stack pointer */ + "mov %0, r0 \n\t" /* the result... */ + : "=r" (result) + : "r" (&my_params) + : "r0", "r1", "r2", "r3", "r4", "ip", "lr", "sp" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp new file mode 100644 index 00000000..6611f667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp @@ -0,0 +1,296 @@ +/* $Id: xptcinvoke_arm64_vbox.cpp $ */ +/** @file + * XPCOM - Implementation XPTC_InvokeByIndex for arm64. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "xptcprivate.h" +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define NUM_ARGS_IN_GPRS 8 /**< Number of arguments passed in general purpose registers (starting with x0). */ +#define NUM_ARGS_IN_FPRS 8 /**< Number of arguments passed in floating point registers (starting with d0). */ + +#define MY_MAX_ARGS 64 /**< Limit ourselves to 64 arguments. */ + + + +AssertCompileMemberOffset(nsXPTCVariant, val, 0); + +extern "C" __attribute__((naked)) nsresult +arm64AsmInvoker(uintptr_t pfnMethod /*x0*/, uint32_t cParams /*w1*/, nsXPTCVariant *paParams /*x2*/, uint64_t cbStack /*x3*/, + uint8_t *acbStackArgs /*x4*/, uint64_t *pauGprArgs /*x5*/, uint64_t *pauFprArgs /*x6*/, uint32_t cFprArgs /*x7*/) +{ + __asm__ __volatile__( + /* Prologue - create the frame. */ "\ + sub sp, sp, 16 \n\ + stp x29, x30, [sp] \n\ + mov x29, sp \n\ + .cfi_def_cfa x29, 16 \n\ + .cfi_rel_offset x30, -8 \n\ + .cfi_rel_offset x29, -16 \n\ +\n\ +" /* Move pfnMethod to x16 and pauGprArgs to x7 free up x0 and x5: */ "\ + mov x16, x0 \n\ + mov x17, x5 \n\ +\n\ +" /* Load FPU registers first so we free up x6 & x7 early: */ "\ + cmp w7, #0 \n\ + b.eq Lno_fprs\n\ + ldp d0, d1, [x6] \n\ + ldp d2, d3, [x6, #16] \n\ + ldp d4, d5, [x6, #32] \n\ + ldp d6, d7, [x6, #48] \n\ +Lno_fprs:\n\ +\n\ +" /* Do argument passing by stack (if any). We align the stack to 16 bytes. */ "\ + cmp x3, #0 \n\ + beq Lno_stack_args \n\ + sub x3, sp, x3 \n\ + bic x3, x3, #15 \n\ + mov sp, x3 \n\ +Lnext_parameter: \n\ + ldrb w7, [x4] \n\ + cmp w7, #0 \n\ + beq Ladvance\n\ +\n\ + cmp w7, #4 \n\ + bgt Lstore_64bits\n\ + cmp w7, #1 \n\ + beq Lstore_8bits\n\ + cmp w7, #2 \n\ + beq Lstore_16bits\n\ +\n\ +Lstore_32bits:\n\ + ldr w0, [x2] \n\ + add x3, x3, #3 \n\ + bic x3, x3, #3 \n\ + str w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #4 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_8bits:\n\ + ldrb w0, [x2] \n\ + strb w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #1 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_16bits:\n\ + ldrh w0, [x2] \n\ + add x3, x3, #1 \n\ + bic x3, x3, #1 \n\ + strh w0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #2 \n" +#endif +" b Ladvance \n\ +\n\ +Lstore_64bits_ptr:\n\ + ldr x0, [x2, %[offPtrInXPTCVariant]] \n\ + b Lstore_64bits_common \n\ +Lstore_64bits:\n\ + tst w7, #0x80 \n\ + bne Lstore_64bits_ptr \n\ + ldr x0, [x2] \n\ +Lstore_64bits_common:\n\ + add x3, x3, #7 \n\ + bic x3, x3, #7 \n\ + str x0, [x3] \n" +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #8 \n" +#endif +"\n\ +Ladvance:\n" +#ifndef RT_OS_DARWIN /* macOS compacts stack usage. */ +" add x3, x3, #8 \n" +#endif +" add x4, x4, #1 \n\ + add x2, x2, %[cbXPTCVariant] \n\ + sub w1, w1, #1 \n\ + cmp w1, #0 \n\ + bne Lnext_parameter \n\ +\n\ +" /* reserve stack space for the integer and floating point registers and save them: */ "\ +Lno_stack_args: \n\ +\n\ +" /* Load general purpose argument registers: */ "\ + ldp x0, x1, [x17] \n\ + ldp x2, x3, [x17, #16] \n\ + ldp x4, x5, [x17, #32] \n\ + ldp x6, x7, [x17, #48] \n\ +\n\ +" /* Make the call: */ "\ + blr x16 \n\ +\n\ +" /* Epilogue (clang does not emit the .cfi's here, so drop them too?): */ "\ + mov sp, x29 \n\ + ldp x29, x30, [sp] \n\ + add sp, sp, #16 \n\ + .cfi_def_cfa sp, 0 \n\ + .cfi_restore x29 \n\ + .cfi_restore x30 \n\ + ret \n\ +" : + : [cbXPTCVariant] "i" (sizeof(nsXPTCVariant)) + , [offPtrInXPTCVariant] "i" (offsetof(nsXPTCVariant, ptr)) + :); +} + + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports *pThis, PRUint32 idxMethod, PRUint32 cParams, nsXPTCVariant *paParams) +{ + AssertMsgReturn(cParams <= MY_MAX_ARGS, ("cParams=%#x idxMethod=%#x\n", cParams, idxMethod), NS_ERROR_UNEXPECTED); + + /* + * Prepare + */ + uint64_t auGprArgs[NUM_ARGS_IN_GPRS] = {0}; + uint64_t auFprArgs[NUM_ARGS_IN_GPRS] = {0}; + uint8_t acbStackArgs[MY_MAX_ARGS]; /* The number of value bytes to copy onto the stack. Zero if in register. */ + uint32_t cbStackArgs = 0; + uint32_t cFprArgs = 0; + uint32_t cGprArgs = 0; + + /* First argument is always 'pThis'. The 'pThis' argument is not accounted + for in cParams or acbStackArgs. */ + auGprArgs[cGprArgs++] = (uintptr_t)pThis; + + /* Do the other arguments. */ + for (PRUint32 i = 0; i < cParams; i++) + { + if (paParams[i].IsPtrData()) + { + if (cGprArgs < NUM_ARGS_IN_GPRS) + { + auGprArgs[cGprArgs++] = (uintptr_t)paParams[i].ptr; + acbStackArgs[i] = 0; + } + else + { + acbStackArgs[i] = sizeof(paParams[i].ptr) | UINT8_C(0x80); +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, sizeof(paParams[i].ptr)) + sizeof(paParams[i].ptr); +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + else + { + if ( paParams[i].type != nsXPTType::T_FLOAT + && paParams[i].type != nsXPTType::T_DOUBLE) + { + if (cGprArgs < NUM_ARGS_IN_GPRS) + { + switch (paParams[i].type) + { + case nsXPTType::T_I8: auGprArgs[cGprArgs++] = paParams[i].val.i8; break; + case nsXPTType::T_I16: auGprArgs[cGprArgs++] = paParams[i].val.i16; break; + case nsXPTType::T_I32: auGprArgs[cGprArgs++] = paParams[i].val.i32; break; + case nsXPTType::T_I64: auGprArgs[cGprArgs++] = paParams[i].val.i64; break; + case nsXPTType::T_U8: auGprArgs[cGprArgs++] = paParams[i].val.u8; break; + case nsXPTType::T_U16: auGprArgs[cGprArgs++] = paParams[i].val.u16; break; + case nsXPTType::T_U32: auGprArgs[cGprArgs++] = paParams[i].val.u32; break; + default: + case nsXPTType::T_U64: auGprArgs[cGprArgs++] = paParams[i].val.u64; break; + case nsXPTType::T_BOOL: auGprArgs[cGprArgs++] = paParams[i].val.b; break; + case nsXPTType::T_CHAR: auGprArgs[cGprArgs++] = paParams[i].val.c; break; + case nsXPTType::T_WCHAR: auGprArgs[cGprArgs++] = paParams[i].val.wc; break; + } + acbStackArgs[i] = 0; + } + else + { + uint8_t cbStack; + switch (paParams[i].type) + { + case nsXPTType::T_I8: cbStack = sizeof(paParams[i].val.i8); break; + case nsXPTType::T_I16: cbStack = sizeof(paParams[i].val.i16); break; + case nsXPTType::T_I32: cbStack = sizeof(paParams[i].val.i32); break; + case nsXPTType::T_I64: cbStack = sizeof(paParams[i].val.i64); break; + case nsXPTType::T_U8: cbStack = sizeof(paParams[i].val.u8); break; + case nsXPTType::T_U16: cbStack = sizeof(paParams[i].val.u16); break; + case nsXPTType::T_U32: cbStack = sizeof(paParams[i].val.u32); break; + default: + case nsXPTType::T_U64: cbStack = sizeof(paParams[i].val.u64); break; + case nsXPTType::T_BOOL: cbStack = sizeof(paParams[i].val.b); break; + case nsXPTType::T_CHAR: cbStack = sizeof(paParams[i].val.c); break; + case nsXPTType::T_WCHAR: cbStack = sizeof(paParams[i].val.wc); break; + } + acbStackArgs[i] = cbStack; +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack; +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + else if (cFprArgs < NUM_ARGS_IN_FPRS) + { + AssertCompile(sizeof(paParams[i].val.f) == 4); + AssertCompile(sizeof(paParams[i].val.d) == 8); + if (paParams[i].type == nsXPTType::T_FLOAT) + auFprArgs[cFprArgs++] = paParams[i].val.u32; + else + auFprArgs[cFprArgs++] = paParams[i].val.u64; + acbStackArgs[i] = 0; + } + else + { + uint8_t cbStack; + if (paParams[i].type == nsXPTType::T_FLOAT) + cbStack = sizeof(paParams[i].val.f); + else + cbStack = sizeof(paParams[i].val.d); + acbStackArgs[i] = cbStack; +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack; +#else + cbStackArgs += sizeof(uint64_t); +#endif + } + } + } + + /* + * Pass it on to a naked wrapper function that does the nitty gritty work. + */ + uintptr_t *pauVtable = *(uintptr_t **)pThis; + return arm64AsmInvoker(pauVtable[idxMethod], cParams, paParams, cbStackArgs, acbStackArgs, auGprArgs, auFprArgs, cFprArgs); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp new file mode 100644 index 00000000..0213bd76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm_netbsd.cpp @@ -0,0 +1,213 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" +struct my_params_struct { + nsISupports* that; + PRUint32 Index; + PRUint32 Count; + nsXPTCVariant* params; + PRUint32 fn_count; + PRUint32 fn_copy; +}; + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + struct my_params_struct my_params; + my_params.that = that; + my_params.Index = methodIndex; + my_params.Count = paramCount; + my_params.params = params; + my_params.fn_copy = (PRUint32) &invoke_copy_to_stack; + my_params.fn_count = (PRUint32) &invoke_count_words; + +/* This is to call a given method of class that. + * The parameters are in params, the number is in paramCount. + * The routine will issue calls to count the number of words + * required for argument passing and to copy the arguments to + * the stack. + * Since APCS passes the first 3 params in r1-r3, we need to + * load the first three words from the stack and correct the stack + * pointer (sp) in the appropriate way. This means: + * + * 1.) more than 3 arguments: load r1-r3, correct sp and remember No. + * of bytes left on the stack in r4 + * + * 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope), + * restore sp as if nothing had happened and set the marker r4 to zero. + * + * Afterwards sp will be restored using the value in r4 (which is not a temporary register + * and will be preserved by the function/method called according to APCS [ARM Procedure + * Calling Standard]). + * + * !!! IMPORTANT !!! + * This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented + * for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])! + * + */ + + __asm__ __volatile__( + "ldr r1, [%1, #12] \n\t" /* prepare to call invoke_count_words */ + "ldr ip, [%1, #16] \n\t" /* r0=paramCount, r1=params */ + "ldr r0, [%1, #8] \n\t" + "mov lr, pc \n\t" /* call it... */ + "mov pc, ip \n\t" + "mov r4, r0, lsl #2 \n\t" /* This is the amount of bytes needed. */ + "sub sp, sp, r4 \n\t" /* use stack space for the args... */ + "mov r0, sp \n\t" /* prepare a pointer an the stack */ + "ldr r1, [%1, #8] \n\t" /* =paramCount */ + "ldr r2, [%1, #12] \n\t" /* =params */ + "ldr ip, [%1, #20] \n\t" /* =invoke_copy_to_stack */ + "mov lr, pc \n\t" /* copy args to the stack like the */ + "mov pc, ip \n\t" /* compiler would. */ + "ldr r0, [%1] \n\t" /* =that */ + "ldr r1, [r0, #0] \n\t" /* get that->vtable offset */ + "ldr r2, [%1, #4] \n\t" + "add r2, r1, r2, lsl #3\n\t" /* a vtable_entry(x)=8 + (8 bytes * x) */ + "add r2, r2, #8 \n\t" /* with this compilers */ + "ldr r3, [r2] \n\t" /* get virtual offset from vtable */ + "mov r3, r3, lsl #16 \n\t" + "add r0, r0, r3, asr #16\n\t" + "ldr ip, [r2, #4] \n\t" /* get method address from vtable */ + "cmp r4, #12 \n\t" /* more than 3 arguments??? */ + "ldmgtia sp!, {r1, r2, r3}\n\t" /* yes: load arguments for r1-r3 */ + "subgt r4, r4, #12 \n\t" /* and correct the stack pointer */ + "ldmleia sp, {r1, r2, r3}\n\t" /* no: load r1-r3 from stack */ + "addle sp, sp, r4 \n\t" /* and restore stack pointer */ + "movle r4, #0 \n\t" /* a mark for restoring sp */ + "mov lr, pc \n\t" /* call mathod */ + "mov pc, ip \n\t" + "add sp, sp, r4 \n\t" /* restore stack pointer */ + "mov %0, r0 \n\t" /* the result... */ + : "=r" (result) + : "r" (&my_params) + : "r0", "r1", "r2", "r3", "r4", "ip", "lr" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s new file mode 100644 index 00000000..c846b1f4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf32.s @@ -0,0 +1,145 @@ + +// Select C numeric constant + .radix C +// for 64 bit mode, use .psr abi64 + .psr abi32 +// big endian + .psr msb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'XPTC_InvokeByIndex' + .proc XPTC_InvokeByIndex +// manual bundling + .explicit + +// extern "C" PRUint32 +// invoke_copy_to_stack(uint64_t* d, +// const PRUint32 paramCount, nsXPTCVariant* s) + .global invoke_copy_to_stack +// .exclass invoke_copy_to_stack, @fullyvisible + .type invoke_copy_to_stack,@function + +// .exclass XPTC_InvokeByIndex, @fullyvisible + .type XPTC_InvokeByIndex,@function + +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params); +XPTC_InvokeByIndex:: + .prologue + .save ar.pfs, r37 +// allocate 4 input args, 6 local args, and 8 output args + alloc r37 = ar.pfs, 4, 6, 8, 0 // M + nop.i 0 ;; // I + +// unwind table already knows gp, no need to specify anything + add r39 = 0, gp // A + .save rp, r36 + mov r36 = rp // I + .vframe r38 + add r38 = 0, sp ;; // A + +// We first calculate the amount of extra memory stack space required +// for the arguments, and register storage. +// We then call invoke_copy_to_stack() to write the argument contents +// to the specified memory regions. +// We then copy the integer arguments to integer registers, and floating +// arguments to float registers. +// Lastly we load the virtual table jump pointer, and call the target +// subroutine. + +// in0 : that +// in1 : methodIndex +// in2 : paramCount +// in3 : params + +// stack frame size is 16 + (8 * even(paramCount)) + 64 + 64 +// 16 byte frame header +// 8 * even(paramCount) memory argument area +// 64 bytes integer register area +// 64 bytes float register area +// This scheme makes sure stack fram size is a multiple of 16 + + .body + add r10 = 8, r0 // A +// r41 points to float register area + add r41 = -64, sp // A +// r40 points to int register area + add r40 = -128, sp ;; // A + + add out1 = 0, r40 // A + add out2 = 0, r41 // A + tbit.z p14,p15 = in2,0 ;; // I + +// compute 8 * even(paramCount) +(p14) shladd r11 = in2, 3, r0 ;; // A +(p15) shladd r11 = in2, 3, r10 ;; // A + sub out0 = r40, r11 ;; // A + +// advance the stack frame + add sp = -16, out0 // A + add out3 = 0, in2 // A + add out4 = 0, in3 // A + +// branch to invoke_copy_to_stack + br.call.sptk.few rp = invoke_copy_to_stack ;; // B + +// restore gp + add gp = 0, r39 // A + add out0 = 0, in0 // A + +// load the integer and float registers + ld8 out1 = [r40], 8 // M + ldfd f8 = [r41], 8 ;; // M + + ld8 out2 = [r40], 8 // M + ldfd f9 = [r41], 8 ;; // M + + ld8 out3 = [r40], 8 // M + ldfd f10 = [r41], 8 ;; // M + + ld8 out4 = [r40], 8 // M + ldfd f11 = [r41], 8 ;; // M + + ld8 out5 = [r40], 8 // M + ldfd f12 = [r41], 8 ;; // M +// 16 * methodIndex + shladd r11 = in1, 4, r0 // A + + ld8 out6 = [r40], 8 // M + ldfd f13 = [r41], 8 ;; // M + + ld8 out7 = [r40], 8 // M + ldfd f14 = [r41], 8 // M + addp4 r8 = 0, in0 ;; // A + +// look up virtual base table and dispatch to target subroutine +// This section assumes 32 bit pointer mode, and virtual base table +// layout from the ABI http://www.codesourcery.com/cxx-abi/abi.html + +// load base table + ld4 r8 = [r8] ;; // M + addp4 r8 = r11, r8 ;; // A + + // first entry is jump pointer, second entry is gp + addp4 r9 = 8, r8 ;; // A +// load jump pointer + ld8 r8 = [r8] + +// load gp + ld8 gp = [r9] ;; // M + mov b6 = r8 ;; // I + +// branch to target virtual function + br.call.sptk.few rp = b6 ;; // B + +// epilog + mov ar.pfs = r37 // I + mov rp = r36 ;; // I + + add sp = 0, r38 // A + add gp = 0, r39 // A + br.ret.sptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s new file mode 100644 index 00000000..5e1b1a23 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ipf64.s @@ -0,0 +1,145 @@ + +// Select C numeric constant + .radix C +// for 64 bit mode, use .psr abi64 + .psr abi64 +// little endian + .psr lsb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'XPTC_InvokeByIndex' + .proc XPTC_InvokeByIndex +// manual bundling + .explicit + +// extern "C" PRUint32 +// invoke_copy_to_stack(uint64_t* d, +// const PRUint32 paramCount, nsXPTCVariant* s) + .global invoke_copy_to_stack +// .exclass invoke_copy_to_stack, @fullyvisible + .type invoke_copy_to_stack,@function + +// .exclass XPTC_InvokeByIndex, @fullyvisible + .type XPTC_InvokeByIndex,@function + +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params); +XPTC_InvokeByIndex:: + .prologue + .save ar.pfs, r37 +// allocate 4 input args, 6 local args, and 8 output args + alloc r37 = ar.pfs, 4, 6, 8, 0 // M + nop.i 0 ;; // I + +// unwind table already knows gp, no need to specify anything + add r39 = 0, gp // A + .save rp, r36 + mov r36 = rp // I + .vframe r38 + add r38 = 0, sp ;; // A + +// We first calculate the amount of extra memory stack space required +// for the arguments, and register storage. +// We then call invoke_copy_to_stack() to write the argument contents +// to the specified memory regions. +// We then copy the integer arguments to integer registers, and floating +// arguments to float registers. +// Lastly we load the virtual table jump pointer, and call the target +// subroutine. + +// in0 : that +// in1 : methodIndex +// in2 : paramCount +// in3 : params + +// stack frame size is 16 + (8 * even(paramCount)) + 64 + 64 +// 16 byte frame header +// 8 * even(paramCount) memory argument area +// 64 bytes integer register area +// 64 bytes float register area +// This scheme makes sure stack fram size is a multiple of 16 + + .body + add r10 = 8, r0 // A +// r41 points to float register area + add r41 = -64, sp // A +// r40 points to int register area + add r40 = -128, sp ;; // A + + add out1 = 0, r40 // A + add out2 = 0, r41 // A + tbit.z p14,p15 = in2,0 ;; // I + +// compute 8 * even(paramCount) +(p14) shladd r11 = in2, 3, r0 ;; // A +(p15) shladd r11 = in2, 3, r10 ;; // A + sub out0 = r40, r11 ;; // A + +// advance the stack frame + add sp = -16, out0 // A + add out3 = 0, in2 // A + add out4 = 0, in3 // A + +// branch to invoke_copy_to_stack + br.call.sptk.few rp = invoke_copy_to_stack ;; // B + +// restore gp + add gp = 0, r39 // A + add out0 = 0, in0 // A + +// load the integer and float registers + ld8 out1 = [r40], 8 // M + ldfd f8 = [r41], 8 ;; // M + + ld8 out2 = [r40], 8 // M + ldfd f9 = [r41], 8 ;; // M + + ld8 out3 = [r40], 8 // M + ldfd f10 = [r41], 8 ;; // M + + ld8 out4 = [r40], 8 // M + ldfd f11 = [r41], 8 ;; // M + + ld8 out5 = [r40], 8 // M + ldfd f12 = [r41], 8 ;; // M +// 16 * methodIndex + shladd r11 = in1, 4, r0 // A + + ld8 out6 = [r40], 8 // M + ldfd f13 = [r41], 8 ;; // M + + ld8 out7 = [r40], 8 // M + ldfd f14 = [r41], 8 // M + add r8 = 0, in0 ;; // A + +// look up virtual base table and dispatch to target subroutine +// This section assumes 64 bit pointer mode, and virtual base table +// layout from the ABI http://www.codesourcery.com/cxx-abi/abi.html + +// load base table + ld8 r8 = [r8] ;; // M + add r8 = r11, r8 ;; // A + + // first entry is jump pointer, second entry is gp + add r9 = 8, r8 ;; // A +// load jump pointer + ld8 r8 = [r8] + +// load gp + ld8 gp = [r9] ;; // M + mov b6 = r8 ;; // I + +// branch to target virtual function + br.call.sptk.few rp = b6 ;; // B + +// epilog + mov ar.pfs = r37 // I + mov rp = r36 ;; // I + + add sp = 0, r38 // A + add gp = 0, r39 // A + br.ret.sptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s new file mode 100644 index 00000000..4e8e0895 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_irix.s @@ -0,0 +1,149 @@ + +#include +#include + +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +LOCALSZ=7 # a0, a1, a2, a3, s0, ra, gp +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +RAOFF=FRAMESZ-(1*SZREG) +A0OFF=FRAMESZ-(2*SZREG) +A1OFF=FRAMESZ-(3*SZREG) +A2OFF=FRAMESZ-(4*SZREG) +A3OFF=FRAMESZ-(5*SZREG) +S0OFF=FRAMESZ-(6*SZREG) +GPOFF=FRAMESZ-(7*SZREG) + + # + # _XPTC_InvokeByIndex(that, methodIndex, paramCount, params) + # a0 a1 a2 a3 + +NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra) + SETUP_GP + PTR_SUBU sp, FRAMESZ + SETUP_GP64(GPOFF, _XPTC_InvokeByIndex) + SAVE_GP(GPOFF) + + REG_S ra, RAOFF(sp) + REG_S a0, A0OFF(sp) + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + REG_S s0, S0OFF(sp) + REG_S gp, GPOFF(sp) + + # invoke_count_words(paramCount, params) + move a0, a2 + move a1, a3 + jal invoke_count_words + + # invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + # nsXPTCVariant* s, PRUint32 *reg) + + REG_L a1, A2OFF(sp) # a1 - paramCount + REG_L a2, A3OFF(sp) # a2 - params + + # save sp before we copy the params to the stack + move t0, sp + + # assume full size of 8 bytes per param to be safe + sll v0, 4 # 8 bytes * num params + subu sp, sp, v0 # make room + move a0, sp # a0 - param stack address + + # create temporary stack space to write int and fp regs + subu sp, 64 # 64 = 8 regs of 8 bytes + + move a3, sp + + # save the old sp and save the arg stack + subu sp, sp, 16 + REG_S t0, 0(sp) + REG_S a0, 8(sp) + + # copy the param into the stack areas + jal invoke_copy_to_stack + + REG_L t3, 8(sp) # get previous a0 + REG_L sp, 0(sp) # get orig sp back + + REG_L a0, A0OFF(sp) # a0 - that + REG_L a1, A1OFF(sp) # a1 - methodIndex + +#ifdef __GNUC__ + # t1 = methodIndex * 8 + # (use shift instead of mult) + sll t1, a1, 3 +#else + # t1 = methodIndex * 12 + # (use shift and subtract trick instead of mult) + sll t1, a1, 2 + subu t1, t1, a1 + sll t1, t1, 2 +#endif + + # calculate the function we need to jump to, + # which must then be saved in t9 + lw t9, 0(a0) + addu t9, t9, t1 +#ifdef __GNUC__ + lw t9, 12(t9) # t9 = *(that+t1+12) +#else + li t2, 20 + addu t9, t9, t2 + lw t9, 0(t9) # t9 = *(that+t1+20) +#endif + + # calculate the proper "this" pointer for the + # function that they asked for + lw t0, 0(a0) + addu t0, t1 +#ifdef __GNUC__ + lh t0, 8(t0) +#else + lw t0, 12(t0) +#endif + + addu a0, a0, t0 + + # get register save area from invoke_copy_to_stack + subu t1, t3, 64 + + # a1..a7 and f13..f19 should now be set to what + # invoke_copy_to_stack told us. skip a0 and f12 + # because that's the "this" pointer + + REG_L a1, 0(t1) + REG_L a2, 8(t1) + REG_L a3, 16(t1) + REG_L a4, 24(t1) + REG_L a5, 32(t1) + REG_L a6, 40(t1) + REG_L a7, 48(t1) + + l.d $f13, 0(t1) + l.d $f14, 8(t1) + l.d $f15, 16(t1) + l.d $f16, 24(t1) + l.d $f17, 32(t1) + l.d $f18, 40(t1) + l.d $f19, 48(t1) + + # save away our stack pointer and create + # the stack pointer for the function + move s0, sp + move sp, t3 + + jalr ra, t9 + + move sp, s0 + + RESTORE_GP64 + REG_L ra, RAOFF(sp) + REG_L s0, S0OFF(sp) + PTR_ADDU sp, FRAMESZ + j ra +.end _XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s new file mode 100644 index 00000000..f011aaf5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_mips.s @@ -0,0 +1,166 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brendan Eich + * Stuart Parmenter + */ + +/* This code is for MIPS using the O32 ABI. */ + +#include +#include + +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +# We need a variable number of words allocated from the stack for copies of +# the params, and this space must come between the high frame (where ra, gp, +# and s0 are saved) and the low frame (where a0-a3 are saved by the callee +# functions we invoke). + +LOCALSZ=4 # s0, s1, ra, gp +NARGSAVE=4 # a0, a1, a2, a3 +HIFRAMESZ=(LOCALSZ*SZREG) +LOFRAMESZ=(NARGSAVE*SZREG) +FRAMESZ=(HIFRAMESZ+LOFRAMESZ+ALSZ)&ALMASK + +# XXX these 2*SZREG, etc. are very magic -- we *know* that ALSZ&ALMASK cause +# FRAMESZ to be 0 mod 8, in this case to be 16 and not 12. +RAOFF=FRAMESZ - (2*SZREG) +GPOFF=FRAMESZ - (3*SZREG) +S0OFF=FRAMESZ - (4*SZREG) +S1OFF=FRAMESZ - (5*SZREG) + +# These are not magic -- they are just our argsave slots in the caller frame. +A0OFF=FRAMESZ +A1OFF=FRAMESZ + (1*SZREG) +A2OFF=FRAMESZ + (2*SZREG) +A3OFF=FRAMESZ + (3*SZREG) + + # + # _XPTC_InvokeByIndex(that, methodIndex, paramCount, params) + # a0 a1 a2 a3 + +NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra) + + .set noreorder + .cpload t9 + .set reorder + + subu sp, FRAMESZ + + # specify the save register mask -- XXX do we want the a0-a3 here, given + # our "split" frame where the args are saved below a dynamicly allocated + # region under the high frame? + # + # 10010000000000010000000011110000 + .mask 0x900100F0, -((NARGSAVE+LOCALSZ)*SZREG) + + # thou shalt not use .cprestore if yer frame has variable size... + # .cprestore GPOFF + + REG_S ra, RAOFF(sp) + + # this happens automatically with .cprestore, but we cannot use that op... + REG_S gp, GPOFF(sp) + REG_S s0, S0OFF(sp) + REG_S s1, S1OFF(sp) + + REG_S a0, A0OFF(sp) + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + + # invoke_count_words(paramCount, params) + move a0, a2 + move a1, a3 + + jal invoke_count_words + lw gp, GPOFF(sp) + + # save the old sp so we can pop the param area and any "low frame" + # needed as an argsave area below the param block for callees that + # we invoke. + move s0, sp + + REG_L a1, A2OFF(sp) # a1 = paramCount + REG_L a2, A3OFF(sp) # a2 = params + + # we define a word as 4 bytes, period end of story! + sll v0, 2 # 4 bytes * result of invoke_copy_words + subu v0, LOFRAMESZ # but we take back the argsave area built into + # our stack frame -- SWEET! + subu sp, sp, v0 # make room + move a0, sp # a0 = param stack address + move s1, a0 # save it for later -- it should be safe here + + # the old sp is still saved in s0, but we now need another argsave + # area ("low frame") for the invoke_copy_to_stack call. + subu sp, sp, LOFRAMESZ + + # copy the param into the stack areas + # invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + # nsXPTCVariant* s) + jal invoke_copy_to_stack + lw gp, GPOFF(s0) + + move sp, s0 # get orig sp back, popping params and argsave + + REG_L a0, A0OFF(sp) # a0 = set "that" to be "this" + REG_L a1, A1OFF(sp) # a1 = methodIndex + + # t1 = methodIndex * 4 + # (use shift instead of mult) + sll t1, a1, 2 + + # calculate the function we need to jump to, + # which must then be saved in t9 + lw t9, 0(a0) + addu t9, t9, t1 + lw t9, 8(t9) + + # a1..a3 and f13..f14 should now be set to what + # invoke_copy_to_stack told us. skip a0 and f12 + # because that is the "this" pointer + + REG_L a1, 1*SZREG(s1) + REG_L a2, 2*SZREG(s1) + REG_L a3, 3*SZREG(s1) + + l.d $f13, 8(s1) + l.d $f14, 16(s1) + + # Create the stack pointer for the function, which must have 4 words + # of space for callee-saved args. invoke_count_words allocated space + # for a0 starting at s1, so we just move s1 into sp. + move sp, s1 + + jalr ra, t9 + lw gp, GPOFF(s0) + + move sp, s0 + + REG_L ra, RAOFF(sp) + REG_L s0, S0OFF(sp) + addu sp, FRAMESZ + j ra +.end _XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s new file mode 100644 index 00000000..d37a91d2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_openvms_alpha.s @@ -0,0 +1,99 @@ +;* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +;* +;* The contents of this file are subject to the Netscape 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/NPL/ +;* +;* 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 mozilla.org code. +;* +;* The Initial Developer of the Original Code is Netscape +;* Communications Corporation. Portions created by Netscape are +;* Copyright (C) 1998 Netscape Communications Corporation. All +;* Rights Reserved. +;* +;* Contributor(s): +;*/ + +; +; XPTC_PUBLIC_API(nsresult) +; XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +; PRUint32 paramCount, nsXPTCVariant* params) +; + + .title "INVOKE" "Invoke By Index" + + $routine XPTC_InvokeByIndex, kind=stack, saved_regs= + + mov r27,r2 ; Need to set up a base register... + .base r2,$LS ; ...for the LINKAGE_PAIR call + + mov r17,r3 ; save methodIndex in r3 + mov r18,r4 ; save paramCount in r4 + +; +; Allocate enough stack space to hold the greater of 6 or "paramCount"+1 +; parameters. (+1 for "this" pointer) Room for at least 6 parameters +; is required for storage of those passed via registers. +; + + cmplt R18,5,R1 ; paramCount = MAX(5, "paramCount") + cmovne R1,5,R18 + s8addq R18,16,R1 ; room for "paramCount"+1 params (8 bytes each) + bic R1,15,R1 ; stack space is rounded up to 0 % 16 + subq SP,R1,SP + + stq R16,0(SP) ; save "that" (as "this" pointer) + addq SP,8,R16 ; pass stack pointer + mov R4,R17 ; pass original "paramCount + mov R19,R18 ; pass "params" + mov 4,r25 ; argument count + + $LINKAGE_PAIR invoke_copy_to_stack + ldq r26,$LP ; get entry point address from linkage pair + ldq r27,$LP+8 ; get procedure descriptor address from lp + jsr r26,r26 ; and call the routine + +; +; Copy the first 6 parameters to registers and remove from stack frame. +; Both the integer and floating point registers are set for each parameter +; except the first which is the "this" pointer. (integer only) +; The floating point registers are all set as doubles since the +; invoke_copy_to_stack function should have converted the floats. +; + ldq R16,0(SP) ; integer registers + ldq R17,8(SP) + ldq R18,16(SP) + ldq R19,24(SP) + ldq R20,32(SP) + ldq R21,40(SP) + ldt F17,8(SP) ; floating point registers + ldt F18,16(SP) + ldt F19,24(SP) + ldt F20,32(SP) + ldt F21,40(SP) + + addq SP,48,SP ; remove params from stack + +; +; Call the virtual function with the constructed stack frame. +; First three methods are always QueryInterface, AddRef and Release. +; + addq r4,1,r25 ; argument count now includes "this" + mov R16,R1 ; load "this" + ldl R1,0(R1) ; load vtable + s4addq r3,0,r28 ; vtable index = "methodIndex" * 4 + addq r1,r28,r1 + ldl r27,0(r1) ; load procedure value + ldq r26,8(r27) ; load entry point address + jsr r26,r26 ; call virtual function + + $return + + $end_routine XPTC_InvokeByIndex + .end diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s new file mode 100644 index 00000000..ad7b2f82 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_osf1_alpha.s @@ -0,0 +1,83 @@ +/* + * XPTC_PUBLIC_API(nsresult) + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params) + */ +.text +.align 4 +.globl XPTC_InvokeByIndex +.ent XPTC_InvokeByIndex +XPTC_InvokeByIndex: +.frame $15,32,$26,0 +.mask 0x4008000,-32 +ldgp $29,0($27) +XPTC_InvokeByIndexXv: +subq $30,32,$30 +stq $26,0($30) +stq $15,8($30) +bis $30,$30,$15 +.prologue 1 + +/* + * Allocate enough stack space to hold the greater of 6 or "paramCount"+1 + * parameters. (+1 for "this" pointer) Room for at least 6 parameters + * is required for storage of those passed via registers. + */ + +bis $31,5,$2 /* count = MAX(5, "paramCount") */ +cmplt $2,$18,$1 +cmovne $1,$18,$2 +s8addq $2,16,$1 /* room for count+1 params (8 bytes each) */ +bic $1,15,$1 /* stack space is rounded up to 0 % 16 */ +subq $30,$1,$30 + +stq $16,0($30) /* save "that" (as "this" pointer) */ +stq $17,16($15) /* save "methodIndex" */ + +addq $30,8,$16 /* pass stack pointer */ +bis $18,$18,$17 /* pass "paramCount" */ +bis $19,$19,$18 /* pass "params" */ +jsr $26,invoke_copy_to_stack /* call invoke_copy_to_stack */ +ldgp $29,0($26) + +/* + * Copy the first 6 parameters to registers and remove from stack frame. + * Both the integer and floating point registers are set for each parameter + * except the first which is the "this" pointer. (integer only) + * The floating point registers are all set as doubles since the + * invoke_copy_to_stack function should have converted the floats. + */ +ldq $16,0($30) /* integer registers */ +ldq $17,8($30) +ldq $18,16($30) +ldq $19,24($30) +ldq $20,32($30) +ldq $21,40($30) +ldt $f17,8($30) /* floating point registers */ +ldt $f18,16($30) +ldt $f19,24($30) +ldt $f20,32($30) +ldt $f21,40($30) + +addq $30,48,$30 /* remove params from stack */ + +/* + * Call the virtual function with the constructed stack frame. + */ +bis $16,$16,$1 /* load "this" */ +ldq $2,16($15) /* load "methodIndex" */ +ldq $1,0($1) /* load vtable */ +s8addq $2,0,$2 /* vtable index = "methodIndex" * 8 + 16 */ +addq $1,$2,$1 +ldq $27,0($1) /* load address of function */ +jsr $26,($27),0 /* call virtual function */ +ldgp $29,0($26) + +bis $15,$15,$30 +ldq $26,0($30) +ldq $15,8($30) +addq $30,32,$30 +ret $31,($26),1 +.end XPTC_InvokeByIndex + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s new file mode 100644 index 00000000..8ce8f17f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_pa32.s @@ -0,0 +1,131 @@ + .LEVEL 1.1 +framesz .EQU 128 + +; XPTC_InvokeByIndex(nsISuppots* that, PRUint32 methodIndex, +; PRUint32 paramCount, nsXPTCVariant* params); + +; g++ need to compile everything with -fvtable-thunks ! + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 +XPTC_InvokeByIndex + .PROC + .CALLINFO CALLER,FRAME=72,ENTRY_GR=%r3,SAVE_RP,SAVE_SP,ARGS_SAVED,ALLOCA_FRAME + + ; frame marker takes 48 bytes, + ; register spill area takes 8 bytes, + ; local stack area takes 72 bytes result in 128 bytes total + + .ENTRY + STW %rp,-20(%sp) + STW,MA %r3,128(%sp) + + LDO -framesz(%r30),%r28 + STW %r28,-4(%r30) ; save previous sp + STW %r19,-32(%r30) + + STW %r26,-36-framesz(%r30) ; save argument registers in + STW %r25,-40-framesz(%r30) ; in PREVIOUS frame + STW %r24,-44-framesz(%r30) ; + STW %r23,-48-framesz(%r30) ; + + B,L .+8,%r2 + ADDIL L'invoke_count_bytes-$PIC_pcrel$1+4,%r2,%r1 + LDO R'invoke_count_bytes-$PIC_pcrel$2+8(%r1),%r1 +$PIC_pcrel$1 + LDSID (%r1),%r31 +$PIC_pcrel$2 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR ;in=24,25,26;out=28 + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + CMPIB,>= 0,%r28, .+76 + COPY %r30,%r3 ; copy stack ptr to saved stack ptr + ADD %r30,%r28,%r30 ; extend stack frame + LDW -4(%r3),%r28 ; move frame + STW %r28,-4(%r30) + LDW -8(%r3),%r28 + STW %r28,-8(%r30) + LDW -12(%r3),%r28 + STW %r28,-12(%r30) + LDW -16(%r3),%r28 + STW %r28,-16(%r30) + LDW -20(%r3),%r28 + STW %r28,-20(%r30) + LDW -24(%r3),%r28 + STW %r28,-24(%r30) + LDW -28(%r3),%r28 + STW %r28,-28(%r30) + LDW -32(%r3),%r28 + STW %r28,-32(%r30) + + LDO -40(%r30),%r26 ; load copy address + LDW -44-framesz(%r3),%r25 ; load rest of 2 arguments + LDW -48-framesz(%r3),%r24 ; + + LDW -32(%r30),%r19 ; shared lib call destroys r19; reload + B,L .+8,%r2 + ADDIL L'invoke_copy_to_stack-$PIC_pcrel$3+4,%r2,%r1 + LDO R'invoke_copy_to_stack-$PIC_pcrel$4+8(%r1),%r1 +$PIC_pcrel$3 + LDSID (%r1),%r31 +$PIC_pcrel$4 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR ;in=24,25,26 + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + LDO -48(%r30),%r20 + EXTRW,U,= %r28,31,1,%r22 + FLDD 0(%r20),%fr7 ; load double arg 1 + EXTRW,U,= %r28,30,1,%r22 + FLDW 8(%r20),%fr5L ; load float arg 1 + EXTRW,U,= %r28,29,1,%r22 + FLDW 4(%r20),%fr6L ; load float arg 2 + EXTRW,U,= %r28,28,1,%r22 + FLDW 0(%r20),%fr7L ; load float arg 3 + + LDW -36-framesz(%r3),%r26 ; load ptr to 'that' + LDW -40(%r30),%r25 ; load the rest of dispatch argument registers + LDW -44(%r30),%r24 + LDW -48(%r30),%r23 + + LDW -36-framesz(%r3),%r20 ; load vtable addr + LDW -40-framesz(%r3),%r28 ; load index + LDW 0(%r20),%r20 ; follow vtable + LDO 16(%r20),%r20 ; offset vtable by 16 bytes (g++: 8, aCC: 16) + SH2ADDL %r28,%r20,%r28 ; add 4*index to vtable entry + LDW 0(%r28),%r22 ; load vtable entry + + B,L .+8,%r2 + ADDIL L'$$dyncall_external-$PIC_pcrel$5+4,%r2,%r1 + LDO R'$$dyncall_external-$PIC_pcrel$6+8(%r1),%r1 +$PIC_pcrel$5 + LDSID (%r1),%r31 +$PIC_pcrel$6 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR +;in=22-26;out=28; + BE,L 0(%sr0,%r1),%r31 + COPY %r31,%r2 + + LDW -32(%r30),%r19 + COPY %r3,%r30 ; restore saved stack ptr + + LDW -148(%sp),%rp + BVE (%rp) + .EXIT + LDW,MB -128(%sp),%r3 + + .PROCEND ;in=23,24,25,26; + + .ALIGN 8 + .SPACE $TEXT$ + .SUBSPA $CODE$ + .IMPORT $$dyncall_external,MILLICODE + .IMPORT invoke_count_bytes,CODE + .IMPORT invoke_copy_to_stack,CODE + .EXPORT XPTC_InvokeByIndex,ENTRY,PRIV_LEV=3,ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR,LONG_RETURN + .END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s new file mode 100644 index 00000000..3684d154 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix.s @@ -0,0 +1,146 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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 mozilla.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # IBM Corporation + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-136(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,168(sp) # paramCount + lwz r5,172(sp) # params + mr r6,sp # fprData + slwi r3,r4,3 # number of bytes of stack required + # at most 8*paramCount + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,160(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,164(r31) # methodIndex + slwi r5,r5,3 # methodIndex * 8 + addi r5,r5,8 # step over junk at start of vTable ! + lwzx r11,r5,r4 # get function pointer + + addi r5,r5,4 # We need to manually adjust the 'that' pointer, this is CFRONT based + lwzx r5,r4,r5 # offset = r4(vtable) + r5(methodIndex offset) - 4 + add r3,r5,r3 # adjust 'that' r3 = r3 + r5 + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + lwz r0,144(sp) + addi sp,sp,136 + mtlr r0 + lwz r31,-4(sp) + blr + + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .long .XPTC_InvokeByIndex # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s new file mode 100644 index 00000000..a174e424 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_aix64.s @@ -0,0 +1,161 @@ +# ***** BEGIN LICENSE BLOCK ***** +# +# Version: MPL 1.1/LGPL 2.1/GPL 2.0 +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is IBM Corporation. +# Portions created by IBM are +# Copyright (C) 2002, International Business Machines Corporation. +# All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 LGPL or the GPL. 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 ***** + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + std r31,-8(sp) +# +# save off the incoming values in the caller's parameter area +# + std r3,48(sp) # that + std r4,56(sp) # methodIndex + std r5,64(sp) # paramCount + std r6,72(sp) # params + std r0,16(sp) + stdu sp,-168(sp) # 2*24=48 for linkage area, + # 8*13=104 for fprData area + # 16 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + ld r4,232(sp) # paramCount (168+8+56) + ld r5,240(sp) # params + mr r6,sp # fprData + sldi r3,r4,3 # number of bytes of stack required + # is at most numParams*8 + addi r3,r3,56 # linkage area (48) + this (8) + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,56 # parameter pointer excludes linkage area + # size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + ld r3,216(r31) # that (168+48) + ld r4,0(r3) # get vTable from 'that' + ld r5,224(r31) # methodIndex (168+56) + sldi r5,r5,3 # methodIndex * 8 + # No junk at the start of 64bit vtable !!! + ldx r11,r5,r4 # get function pointer (this jumps + # either to the function if no adjustment + # is needed (displacement = 0), or it + # jumps to the thunk code, which will jump + # to the function at the end) + + # No adjustment of the that pointer in 64bit mode, this is done + # by the thunk code + + ld r4,56(sp) + ld r5,64(sp) + ld r6,72(sp) + ld r7,80(sp) + ld r8,88(sp) + ld r9,96(sp) + ld r10,104(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + ld r0,184(sp) # 168+16 + addi sp,sp,168 + mtlr r0 + ld r31,-8(sp) + blr + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .llong .XPTC_InvokeByIndex # "\0\0\0\0" + .llong TOC{TC0} # "\0\0\0008" + .llong 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s new file mode 100644 index 00000000..064a73ab --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_ibmobj_aix.s @@ -0,0 +1,140 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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 mozilla.org code. + # + # The Initial Developer of the Original Code is IBM Corporation. + # Portions created by IBM are + # Copyright (C) 2004, International Business Machines Corporation. + # All Rights Reserved. + # + # Contributor(s): + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 +.set BO_IF,12 +.set CR0_EQ,2 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.XPTC_InvokeByIndex{TC},"XPTC_InvokeByIndex" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .XPTC_InvokeByIndex + .globl XPTC_InvokeByIndex{DS} + .extern .invoke_copy_to_stack + .extern ._ptrgl{PR} + + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(sp) +# +# save off the incoming values in the caller's parameter area +# + stw r3,24(sp) # that + stw r4,28(sp) # methodIndex + stw r5,32(sp) # paramCount + stw r6,36(sp) # params + stw r0,8(sp) + stwu sp,-136(sp) # = 24 for linkage area, 8 * 13 for fprData area, 8 for saved registers + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,168(sp) # paramCount + lwz r5,172(sp) # params + mr r6,sp # fprData + slwi r3,r4,3 # number of bytes of stack required + # at most 8*paramCount + addi r3,r3,28 # linkage area + mr r31,sp # save original stack top + subfc sp,r3,sp # bump the stack + addi r3,sp,28 # parameter pointer excludes linkage area size + 'this' + + bl .invoke_copy_to_stack + nop + + lfd f1,0(r31) # Restore floating point registers + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,160(r31) # that + lwz r4,0(r3) # get vTable from 'that' + lwz r5,164(r31) # methodIndex + slwi r5,r5,2 # methodIndex * 4 + lwzx r11,r5,r4 # get function pointer + + lwz r4,28(sp) + lwz r5,32(sp) + lwz r6,36(sp) + lwz r7,40(sp) + lwz r8,44(sp) + lwz r9,48(sp) + lwz r10,52(sp) + + bl ._ptrgl{PR} + nop + + mr sp,r31 + lwz r0,144(sp) + addi sp,sp,136 + mtlr r0 + lwz r31,-4(sp) + blr + + +# .data section + + .toc # 0x00000038 +T.18.XPTC_InvokeByIndex: + .tc H.18.XPTC_InvokeByIndex{TC},XPTC_InvokeByIndex{DS} + + .csect XPTC_InvokeByIndex{DS} + .long .XPTC_InvokeByIndex # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect XPTC_InvokeByIndex{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s new file mode 100644 index 00000000..b9aaa997 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_linux.s @@ -0,0 +1,113 @@ +// -*- Mode: Asm -*- +// +// The contents of this file are subject to the Netscape 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/NPL/ +// +// 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 mozilla.org code. +// +// The Initial Developer of the Original Code is Netscape +// Communications Corporation. Portions created by Netscape are +// Copyright (C) 1999 Netscape Communications Corporation. All +// Rights Reserved. +// +// Contributor(s): +// Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +// beard@netscape.com (Patrick Beard) +// waterson@netscape.com (Chris Waterson) +// + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl XPTC_InvokeByIndex + .type XPTC_InvokeByIndex,@function + +// +// XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +// PRUint32 paramCount, nsXPTCVariant* params) +// + +XPTC_InvokeByIndex: + stwu sp,-32(sp) // setup standard stack frame + mflr r0 // save LR + stw r3,8(sp) // r3 <= that + stw r4,12(sp) // r4 <= methodIndex + stw r30,16(sp) + stw r31,20(sp) + + stw r0,36(sp) // store LR backchain + mr r31,sp + + rlwinm r10,r5,3,0,27 // r10 = (ParamCount * 2 * 4) & ~0x0f + addi r0,r10,96 // reserve stack for GPR and FPR register save area r0 = r10 + 96 + lwz r9,0(sp) // r9 = backchain + neg r0,r0 + stwux r9,sp,r0 // reserve stack space and save SP backchain + + addi r3,sp,8 // r3 <= args + mr r4,r5 // r4 <= paramCount + mr r5,r6 // r5 <= params + add r6,r3,r10 // r6 <= gpregs ( == args + r10 ) + mr r30,r6 // store in r30 for use later... + addi r7,r6,32 // r7 <= fpregs ( == gpregs + 32 ) + + bl invoke_copy_to_stack@local // (args, paramCount, params, gpregs, fpregs) + + lfd f1,32(r30) // load FP registers with method parameters + lfd f2,40(r30) + lfd f3,48(r30) + lfd f4,56(r30) + lfd f5,64(r30) + lfd f6,72(r30) + lfd f7,80(r30) + lfd f8,88(r30) + + lwz r3,8(r31) // r3 <= that + lwz r4,12(r31) // r4 <= methodIndex + lwz r5,0(r3) // r5 <= vtable ( == *that ) +#if !((__GNUC__ == 3 && __GNUC_MINOR__ < 2) || __GXX_ABI_VERSION >= 100) // G++ pre-V3 ABI + addi r4,r4,2 // skip first two vtable entries +#endif + slwi r4,r4,2 // convert to offset ( *= 4 ) + lwzx r0,r5,r4 // r0 <= methodpointer ( == vtable + offset ) + + lwz r4,4(r30) // load GP regs with method parameters + lwz r5,8(r30) + lwz r6,12(r30) + lwz r7,16(r30) + lwz r8,20(r30) + lwz r9,24(r30) + lwz r10,28(r30) + + mtlr r0 // copy methodpointer to LR + blrl // call method + + lwz r30,16(r31) // restore r30 & r31 + lwz r31,20(r31) + + lwz r11,0(sp) // clean up the stack + lwz r0,4(r11) + mtlr r0 + mr sp,r11 + blr diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s new file mode 100644 index 00000000..18c775a9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_netbsd.s @@ -0,0 +1,114 @@ +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +# beard@netscape.com (Patrick Beard) +# waterson@netscape.com (Chris Waterson) +# +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl XPTC_InvokeByIndex + .type XPTC_InvokeByIndex,@function + +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +XPTC_InvokeByIndex: + stwu sp,-32(sp) # setup standard stack frame + mflr r0 # save LR + stw r3,8(sp) # r3 <= that + stw r4,12(sp) # r4 <= methodIndex + stw r30,16(sp) + stw r31,20(sp) + + stw r0,36(sp) # store LR backchain + mr r31,sp + + rlwinm r10,r5,3,0,27 # r10 = (ParamCount * 2 * 4) & ~0x0f + addi r0,r10,96 # reserve stack for GPR and FPR register save area r0 = r10 + 96 + lwz r9,0(sp) # r9 = backchain + neg r0,r0 + stwux r9,sp,r0 # reserve stack sapce and save SP backchain + + addi r3,sp,8 # r3 <= args + mr r4,r5 # r4 <= paramCount + mr r5,r6 # r5 <= params + add r6,r3,r10 # r6 <= gpregs ( == args + r10 ) + mr r30,r6 # store in r30 for use later... + addi r7,r6,32 # r7 <= fpregs ( == gpregs + 32 ) + + bl invoke_copy_to_stack@local # (args, paramCount, params, gpregs, fpregs) + + lfd f1,32(r30) # load FP registers with method parameters + lfd f2,40(r30) + lfd f3,48(r30) + lfd f4,56(r30) + lfd f5,64(r30) + lfd f6,72(r30) + lfd f7,80(r30) + lfd f8,88(r30) + + lwz r3,8(r31) # r3 <= that + lwz r4,12(r31) # r4 <= methodIndex + lwz r5,0(r3) # r5 <= vtable ( == *that ) + slwi r4,r4,3 # convert to offset ( *= 8 ) + addi r4,r4,8 # skip first two vtable entries + add r4,r4,r5 + lhz r0,0(r4) # virtual base offset + extsh r0,r0 + add r3,r3,r0 + lwz r0,4(r4) # r0 <= methodpointer ( == vtable + offset ) + + lwz r4,4(r30) # load GP regs with method parameters + lwz r5,8(r30) + lwz r6,12(r30) + lwz r7,16(r30) + lwz r8,20(r30) + lwz r9,24(r30) + lwz r10,28(r30) + + mtlr r0 # copy methodpointer to LR + blrl # call method + + lwz r30,16(r31) # restore r30 & r31 + lwz r31,20(r31) + + lwz r11,0(sp) # clean up the stack + lwz r0,4(r11) + mtlr r0 + mr sp,r11 + blr diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s new file mode 100644 index 00000000..8a5c9afb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_rhapsody.s @@ -0,0 +1,162 @@ +# +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Patrick C. Beard +# + +# +# ** Assumed vtable layout (obtained by disassembling with gdb): +# ** 4 bytes per vtable entry, skip 0th and 1st entries, so the mapping +# ** from index to entry is (4 * index) + 8. +# + +.text + .align 2 +# +# XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, +# PRUint32 paramCount, nsXPTCVariant* params) +# + +.globl __XPTC_InvokeByIndex +__XPTC_InvokeByIndex: + mflr r0 + stw r31,-4(r1) +# +# save off the incoming values in the callers parameter area +# + stw r3,24(r1) ; that + stw r4,28(r1) ; methodIndex + stw r5,32(r1) ; paramCount + stw r6,36(r1) ; params + stw r0,8(r1) + stwu r1,-144(r1) ; 24 for linkage area, + ; 8*13 for fprData area, + ; 8 for saved registers, + ; 8 to keep stack 16-byte aligned + +# set up for and call 'invoke_count_words' to get new stack size +# + mr r3,r5 + mr r4,r6 + + stwu r1,-24(r1) + bl L_invoke_count_words$stub + lwz r1,0(r1) + +# prepare args for 'invoke_copy_to_stack' call +# + lwz r4,176(r1) ; paramCount + lwz r5,180(r1) ; params + mr r6,r1 ; fprData + slwi r3,r3,2 ; number of stack bytes required + addi r3,r3,28 ; linkage area + mr r31,r1 ; save original stack top + sub r1,r1,r3 ; bump the stack + clrrwi r1,r1,4 ; keep the stack 16-byte aligned + addi r3,r31,144 ; act like real alloca, so 0(sp) always + stw r3,0(r1) ; points back to previous stack frame + addi r3,r1,28 ; parameter pointer excludes linkage area size + 'this' + +# create "temporary" stack frame for _invoke_copy_to_stack to operate in. + stwu r1,-40(r1) + bl L_invoke_copy_to_stack$stub +# remove temporary stack frame. + lwz r1,0(r1) + + lfd f1,0(r31) + lfd f2,8(r31) + lfd f3,16(r31) + lfd f4,24(r31) + lfd f5,32(r31) + lfd f6,40(r31) + lfd f7,48(r31) + lfd f8,56(r31) + lfd f9,64(r31) + lfd f10,72(r31) + lfd f11,80(r31) + lfd f12,88(r31) + lfd f13,96(r31) + + lwz r3,168(r31) ; that + lwz r4,0(r3) ; get vTable from 'that' + lwz r5,172(r31) ; methodIndex + slwi r5,r5,2 ; methodIndex * 4 +#ifndef HAVE_GCC3_ABI + addi r5,r5,8 ; (methodIndex * 4) + 8 +#endif + lwzx r12,r5,r4 ; get function pointer + + lwz r4,28(r1) + lwz r5,32(r1) + lwz r6,36(r1) + lwz r7,40(r1) + lwz r8,44(r1) + lwz r9,48(r1) + lwz r10,52(r1) + + mtlr r12 + blrl + + mr r1,r31 + lwz r0,152(r1) + addi r1,r1,144 + mtlr r0 + lwz r31,-4(r1) + + blr + +.picsymbol_stub +L_invoke_count_words$stub: + .indirect_symbol _invoke_count_words + mflr r0 + bcl 20,31,L1$pb +L1$pb: + mflr r11 + addis r11,r11,ha16(L1$lz-L1$pb) + mtlr r0 + lwz r12,lo16(L1$lz-L1$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L1$lz-L1$pb) + bctr +.lazy_symbol_pointer +L1$lz: + .indirect_symbol _invoke_count_words + .long dyld_stub_binding_helper + + +.picsymbol_stub +L_invoke_copy_to_stack$stub: + .indirect_symbol _invoke_copy_to_stack + mflr r0 + bcl 20,31,L2$pb +L2$pb: + mflr r11 + addis r11,r11,ha16(L2$lz-L2$pb) + mtlr r0 + lwz r12,lo16(L2$lz-L2$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L2$lz-L2$pb) + bctr +.lazy_symbol_pointer +L2$lz: + .indirect_symbol _invoke_copy_to_stack + .long dyld_stub_binding_helper + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s new file mode 100644 index 00000000..b744ee9b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_bsdos.s @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Chris Torek (torek@bsdi.com), Kurt Lidl (lidl@pix.net) + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + /* regular C/C++ stack frame -- see */ + save %sp, -96, %sp + + /* + * invoke_count_words(paramCount, params) apparently tells us + * how many "32-bit words" are involved in passing the given + * parameters to the target function. + */ + mov %i2, %o0 + call invoke_count_words ! invoke_count_words(paramCount, params) + mov %i3, %o1 + + /* + * ??? Torek wonders: does invoke_count_words always force its + * return value to be even? If not, we would have to adjust + * the return value ... should make it a multiple of 8 anyway, + * for efficiency (32 byte cache lines); will do that here thus: + * + * We already have room (in our callee's "argument dump" area, + * sp->fr_argd) for six parameters, and we are going to use + * five of those (fr_argd[1] through fr_argd[5]) in a moment. + * This space is followed by fr_argx[1], room for a seventh. + * Thus, if invoke_count_words returns a value between 0 and 6 + * inclusive, we do not need any stack adjustment. For values + * from 7 through (7+8) we want to make room for another 8 + * parameters, and so on. Thus, we want to calculate: + * + * n_extra_words = (wordcount + 1) & ~7 + * + * and then make room for that many more 32-bit words. (Normally + * it would be ((w+7)&~7; we just subtract off the room-for-6 we + * already have.) + */ + inc %o0 + andn %o0, 7, %o0 + sll %o0, 2, %o0 ! convert to bytes + sub %sp, %o0, %sp ! and make room for arguments + + /* + * Copy all the arguments to the stack, starting at the argument + * dump area at [%sp + 68], even though the first six arguments + * go in the six %o registers. We will just load up those + * arguments after the copy is done. The first argument to + * any C++ member function is always the "this" parameter so + * we actually start with what will go in %o1, at [%sp + 72]. + */ + add %sp, 72, %o0 ! invoke_copy_to_stack(addr, + mov %i2, %o1 ! paramCount, + call invoke_copy_to_stack + mov %i3, %o2 ! params); + + /* + * This is the only really tricky (compiler-dependent) part + * (everything else here relies only on the V8 SPARC calling + * conventions). "methodIndex" (%i1) is an index into a C++ + * vtable. The word at "*that" points to the vtable, but for + * some reason, the first function (index=0) is at vtable[2*4], + * the second (index 1) at vtable[3*4], the third at vtable[4*4], + * and so on. Thus, we want, in effect: + * + * that->vTable[index + 2] + */ + ld [%i0], %l0 ! vTable = *that + add %i1, 2, %l1 + sll %l1, 2, %l1 + ld [%l0 + %l1], %l0 ! fn = vTable[index + 2] + + /* + * Now load up the various function parameters. We do not know, + * nor really care, how many there are -- we just load five words + * from the stack (there are always at least five such words to + * load, even if some of them are junk) into %o1 through %o5, + * and set %o0 = %i0, to pass "that" to the target member function + * as its C++ "this" parameter. + * + * If there are more than five parameters, any extras go on our + * stack starting at sp->fr_argx ([%sp + 92]), which is of course + * where we have just copied them. + */ + ld [%sp + 72], %o1 + ld [%sp + 76], %o2 + ld [%sp + 80], %o3 + ld [%sp + 84], %o4 + ld [%sp + 88], %o5 + call %l0 ! fn(that, %o1, %o2, %o3, %o4, %o5) + mov %i0, %o0 + + ! return whatever fn() returned + ret + restore %o0, 0, %o0 + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s new file mode 100644 index 00000000..c23fd1e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux.s @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! 32 bit pointer + add %i1,%l1,%l1 ! vTable[index * 4], l1 now points to vTable entry + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s new file mode 100644 index 00000000..9a6b02ae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_linux_GCC3.s @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David S. Miller (ported to gcc3) + * + * 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. + */ + +/* + * Platform specific code to invoke XPCOM methods on native objects for + * Linux/Sparc with gcc 3 ABI. + */ + .global XPTC_InvokeByIndex +/* + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params); + * + */ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! multiply index by 4 + add %i1,%l1,%l1 ! l1 now points to vTable entry + ld [%l1],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s new file mode 100644 index 00000000..be0e34a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_netbsd.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s new file mode 100644 index 00000000..be0e34a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 16),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 16 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s new file mode 100644 index 00000000..203e3f1c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC.s @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + .global XPTC_InvokeByIndex +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + add %i1,1,%i1 ! vTable is zero-based, index is 1 based (?) + ld [%i0],%l1 ! *that --> vTable + sll %i1,3,%i1 + add %i1,%l1,%l1 ! vTable[index * 8], l1 now points to vTable entry + lduh [%l1],%l0 ! this adjustor + sll %l0,16,%l0 ! sign extend to 32 bits + sra %l0,16,%l0 + add %l0,%i0,%i0 ! adjust this + ld [%l1 + 4],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s new file mode 100644 index 00000000..6a2e9606 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_GCC3.s @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * David Baron (ported to + * gcc 3/sparc-sun-solaris from gcc 2.x/sparc-sun-solaris) + */ + +/* + * Platform specific code to invoke XPCOM methods on native objects for + * solaris/sparc with gcc 3 ABI. + */ + .global XPTC_InvokeByIndex +/* + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params); + */ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + mov %i2,%o0 ! paramCount + call invoke_count_words ! returns the required stack size in %o0 + mov %i3,%o1 ! params + + sll %o0,2,%l0 ! number of bytes + sub %sp,%l0,%sp ! create the additional stack space + + mov %sp,%o0 ! pointer for copied args + add %o0,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params +! +! calculate the target address from the vtable +! + ld [%i0],%l1 ! *that --> vTable + sll %i1,2,%i1 ! multiply index by 4 + add %i1,%l1,%l1 ! l1 now points to vTable entry + ld [%l1],%l0 ! target address + +.L5: ld [%sp + 88],%o5 +.L4: ld [%sp + 84],%o4 +.L3: ld [%sp + 80],%o3 +.L2: ld [%sp + 76],%o2 +.L1: ld [%sp + 72],%o1 +.L0: + jmpl %l0,%o7 ! call the routine +! always have a 'this', from the incoming 'that' + mov %i0,%o0 + + mov %o0,%i0 ! propagate return value + ret + restore diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s new file mode 100644 index 00000000..b70f1b46 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparc_solaris_SUNW.s @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + + .global XPTC_InvokeByIndex + .type XPTC_InvokeByIndex, #function +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 + sll %i2,3,%l0 ! assume the worst case + ! paramCount * 2 * 4 bytes + cmp %l0, 0 ! are there any args? If not, + be .invoke ! no need to copy args to stack + + sub %sp,%l0,%sp ! create the additional stack space + add %sp,72,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params + +! +! load arguments from stack into the outgoing registers +! + ld [%sp + 72],%o1 + ld [%sp + 76],%o2 + ld [%sp + 80],%o3 + ld [%sp + 84],%o4 + ld [%sp + 88],%o5 + +! +! calculate the target address from the vtable +! +.invoke: + sll %i1,2,%l0 ! index *= 4 + add %l0,8,%l0 ! there are 2 extra entries in the vTable + ld [%i0],%l1 ! *that --> address of vtable + ld [%l0 + %l1],%l0 ! that->vtable[index * 4 + 8] --> address + + jmpl %l0,%o7 ! call the routine + mov %i0,%o0 ! move 'this' pointer to out register + + mov %o0,%i0 ! propagate return value + ret + restore + + .size XPTC_InvokeByIndex, .-XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s new file mode 100644 index 00000000..232ed6bd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_sparcv9_solaris_SUNW.s @@ -0,0 +1,103 @@ +/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Seawood + */ + +/* + Platform specific code to invoke XPCOM methods on native objects + for sparcv9 Solaris. + + See the SPARC Compliance Definition (SCD) Chapter 3 + for more information about what is going on here, including + the use of BIAS (0x7ff). + The SCD is available from http://www.sparc.com/. +*/ + + .global XPTC_InvokeByIndex + .type XPTC_InvokeByIndex, #function + +/* + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +*/ +XPTC_InvokeByIndex: + save %sp,-(128 + 64),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 64 + sll %i2,4,%l0 ! assume the worst case + ! paramCount * 2 * 8 bytes + cmp %l0, 0 ! are there any args? If not, + be .invoke ! no need to copy args to stack + + sub %sp,%l0,%sp ! create the additional stack space + add %sp,0x7ff+136,%o0 ! step past the register window, the + ! struct result pointer and the 'this' slot + mov %i2,%o1 ! paramCount + call invoke_copy_to_stack + mov %i3,%o2 ! params + +! +! load arguments from stack into the outgoing registers +! BIAS is 0x7ff (2047) +! + +! load the %o1..5 64bit (extended word) output registers registers + ldx [%sp + 0x7ff + 136],%o1 ! %i1 + ldx [%sp + 0x7ff + 144],%o2 ! %i2 + ldx [%sp + 0x7ff + 152],%o3 ! %i3 + ldx [%sp + 0x7ff + 160],%o4 ! %i4 + ldx [%sp + 0x7ff + 168],%o5 ! %i5 + +! load the even number double registers starting with %d2 + ldd [%sp + 0x7ff + 136],%d2 + ldd [%sp + 0x7ff + 144],%d4 + ldd [%sp + 0x7ff + 152],%d6 + ldd [%sp + 0x7ff + 160],%d8 + ldd [%sp + 0x7ff + 168],%d10 + ldd [%sp + 0x7ff + 176],%d12 + ldd [%sp + 0x7ff + 184],%d14 + ldd [%sp + 0x7ff + 192],%d16 + ldd [%sp + 0x7ff + 200],%d18 + ldd [%sp + 0x7ff + 208],%d20 + ldd [%sp + 0x7ff + 216],%d22 + ldd [%sp + 0x7ff + 224],%d24 + ldd [%sp + 0x7ff + 232],%d26 + ldd [%sp + 0x7ff + 240],%d28 + ldd [%sp + 0x7ff + 248],%d30 + +! +! calculate the target address from the vtable +! +.invoke: + sll %i1,3,%l0 ! index *= 8 + add %l0,16,%l0 ! there are 2 extra entries in the vTable (16bytes) + ldx [%i0],%l1 ! *that --> address of vtable + ldx [%l0 + %l1],%l0 ! that->vtable[index * 8 + 16] --> address + + jmpl %l0,%o7 ! call the routine + mov %i0,%o0 ! move 'this' pointer to out register + + mov %o0,%i0 ! propagate return value + ret + restore + + .size XPTC_InvokeByIndex, .-XPTC_InvokeByIndex diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp new file mode 100644 index 00000000..79b17ae3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_gcc_x86_unix.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#ifdef __GNUC__ /* Gnu compiler. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +#ifndef XP_WIN32 +static +#endif +void ATTRIBUTE_USED __attribute__ ((regparm(3))) +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + default : *((void**)d) = s->val.p; break; + } + } +} +} // extern "C" + +// NOTE! See xptc_gcc_x86_unix.h for the reason why this function exists. +#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)) +PRUint32 +xptc_invoke_copy_to_stack_keeper (void) +{ + PRUint32 dummy1; + void ATTRIBUTE_USED __attribute__ ((regparm(3))) (*dummy2) + (PRUint32, nsXPTCVariant*, PRUint32*) = invoke_copy_to_stack; + +// dummy2 references invoke_copy_to_stack, now we have to "use" it + __asm__ __volatile__ ( + "" + : "=&a" (dummy1) + : "g" (dummy2) + ); + + return dummy1 & 0xF0F00000; +} +#endif + + +/* + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + Each param takes at most two 4-byte words. + It doesn't matter if we push too many words, and calculating the exact + amount takes time. + + that = ebp + 0x08 + methodIndex = ebp + 0x0c + paramCount = ebp + 0x10 + params = ebp + 0x14 + + NOTE NOTE NOTE: + As of 2002-04-29 this function references no global variables nor does + it call non-static functions so preserving and loading the PIC register + is unnecessary. Define MOZ_PRESERVE_PIC if this changes. See mozilla + bug 140412 for details. However, avoid this if you can. It's slower. +*/ +/* + * Hack for gcc for win32. Functions used externally must be + * explicitly dllexported. + * Bug 226609 + */ +#ifdef XP_WIN32 +extern "C" { + nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + XPTC_PUBLIC_API(nsresult) + XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) { + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); + } +} +#endif + +__asm__ ( + ".text\n\t" +/* alignment here seems unimportant here; this was 16, now it's 2 which + is what xptcstubs uses. */ + ".align 2\n\t" +#ifdef XP_WIN32 + ".globl " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex:\n\t" +#else +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + ".globl " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex:\n\t" +#else + ".globl " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" + ".type " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex,@function\n" + SYMBOL_UNDERSCORE "XPTC_InvokeByIndex:\n\t" +#endif +#endif + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" +#ifdef MOZ_PRESERVE_PIC + "pushl %ebx\n\t" + "call 0f\n\t" + ".subsection 1\n" + "0:\n\t" + "movl (%esp), %ebx\n\t" + "ret\n\t" + ".previous\n\t" + "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\t" +#endif + "movl 0x10(%ebp), %eax\n\t" + "leal 0(,%eax,8),%edx\n\t" + "movl %esp, %ecx\n\t" + "subl %edx, %ecx\n\t" +/* Since there may be 64-bit data, it occurs to me that aligning this + space might be a performance gain. However, I don't think the rest + of mozilla worries about such things. In any event, do it here. + "andl $0xfffffff8, %ecx\n\t" + */ + "movl %ecx, %esp\n\t" /* make stack space */ + "movl 0x14(%ebp), %edx\n\t" + "call " SYMBOL_UNDERSCORE "invoke_copy_to_stack\n\t" + "movl 0x08(%ebp), %ecx\n\t" /* 'that' */ +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ + "shll $3, %eax\n\t" /* *= 8 */ + "addl $8, %eax\n\t" /* += 8 skip first entry */ + "addl %eax, %edx\n\t" + "movswl (%edx), %eax\n\t" /* 'this' offset */ + "addl %eax, %ecx\n\t" + "pushl %ecx\n\t" + "addl $4, %edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %ecx\n\t" + "movl (%ecx), %edx\n\t" + "movl 0x0c(%ebp), %eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%edx,%eax,4), %edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%edx,%eax,4), %edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%edx)\n\t" +#ifdef MOZ_PRESERVE_PIC + "movl -4(%ebp), %ebx\n\t" +#endif + "movl %ebp, %esp\n\t" + "popl %ebp\n\t" + "ret\n" +#ifdef XP_WIN32 + ".size " SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "_XPTC_InvokeByIndex\n\t" +#else +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP + ".size " SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "VBoxNsxpXPTC_InvokeByIndex\n\t" +#else + ".size " SYMBOL_UNDERSCORE "XPTC_InvokeByIndex, . -" SYMBOL_UNDERSCORE "XPTC_InvokeByIndex\n\t" +#endif +#endif +); + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp new file mode 100644 index 00000000..5a959317 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf32.cpp @@ -0,0 +1,164 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include + +// "This code is for IA64 only" + + +/* invoke_copy_to_stack() will copy from variant array 's' to + * the stack argument area 'mloc', the integer register area 'iloc', and + * the float register area 'floc'. + * + */ +extern "C" void +invoke_copy_to_stack(uint64_t* mloc, uint64_t* iloc, uint64_t* floc, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + uint64_t* dest = mloc; + PRUint32 len = paramCount; + nsXPTCVariant* source = s; + + PRUint32 indx; + PRUint32 endlen; + endlen = (len > 7) ? 7 : len; + /* handle the memory arguments */ + for (indx = 7; indx < len; ++indx) + { + if (source[indx].IsPtrData()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].ptr; +#endif + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_DOUBLE: *(dest) = source[indx].val.u64; break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; +#else + { + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].val.p; + } +#endif + } + ++dest; + } + /* process register arguments */ + dest = iloc; + for (indx = 0; indx < endlen; ++indx) + { + if (source[indx].IsPtrData()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].ptr; +#endif + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : + *((double*) (floc++)) = (double) source[indx].val.f; + break; + case nsXPTType::T_DOUBLE: + *((double*) (floc++)) = source[indx].val.d; + break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types +#ifdef __LP64__ + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; +#else + { + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) dest; + *(adr) = 0; + *(adr+1) = (uint32_t) source[indx].val.p; + } +#endif + } + ++dest; + } + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp new file mode 100644 index 00000000..356c2c7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ipf64.cpp @@ -0,0 +1,133 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include + +// "This code is for IA64 only" + + +/* invoke_copy_to_stack() will copy from variant array 's' to + * the stack argument area 'mloc', the integer register area 'iloc', and + * the float register area 'floc'. + * + */ +extern "C" void +invoke_copy_to_stack(uint64_t* mloc, uint64_t* iloc, uint64_t* floc, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + uint64_t* dest = mloc; + PRUint32 len = paramCount; + nsXPTCVariant* source = s; + + PRUint32 indx; + PRUint32 endlen; + endlen = (len > 7) ? 7 : len; + /* handle the memory arguments */ + for (indx = 7; indx < len; ++indx) + { + if (source[indx].IsPtrData()) + { + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_DOUBLE: *(dest) = source[indx].val.u64; break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; + } + ++dest; + } + /* process register arguments */ + dest = iloc; + for (indx = 0; indx < endlen; ++indx) + { + if (source[indx].IsPtrData()) + { + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].ptr; + } + else + switch (source[indx].type) + { + case nsXPTType::T_I8 : *(dest) = source[indx].val.i8; break; + case nsXPTType::T_I16 : *(dest) = source[indx].val.i16; break; + case nsXPTType::T_I32 : *(dest) = source[indx].val.i32; break; + case nsXPTType::T_I64 : *(dest) = source[indx].val.i64; break; + case nsXPTType::T_U8 : *(dest) = source[indx].val.u8; break; + case nsXPTType::T_U16 : *(dest) = source[indx].val.u16; break; + case nsXPTType::T_U32 : *(dest) = source[indx].val.u32; break; + case nsXPTType::T_U64 : *(dest) = source[indx].val.u64; break; + case nsXPTType::T_FLOAT : + *((double*) (floc++)) = (double) source[indx].val.f; + break; + case nsXPTType::T_DOUBLE: + *((double*) (floc++)) = source[indx].val.d; + break; + case nsXPTType::T_BOOL : *(dest) = source[indx].val.b; break; + case nsXPTType::T_CHAR : *(dest) = source[indx].val.c; break; + case nsXPTType::T_WCHAR : *(dest) = source[indx].val.wc; break; + default: + // all the others are plain pointer types + /* 64 bit pointer mode */ + *((void**) dest) = source[indx].val.p; + } + ++dest; + } + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp new file mode 100644 index 00000000..67aa6144 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_irix.cpp @@ -0,0 +1,173 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if (_MIPS_SIM != _ABIN32) +#error "This code is for IRIX N32 only" +#endif + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return(paramCount*2); +} + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, + nsXPTCVariant* s, PRUint64 *regs) +{ +#define N_ARG_REGS 7 /* 8 regs minus 1 for "this" ptr */ + + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + if (s->IsPtrData()) { + if (i < N_ARG_REGS) + regs[i] = (PRUint64)s->ptr; + else + *d++ = (PRUint64)s->ptr; + continue; + } + switch (s->type) { + // + // signed types first + // + case nsXPTType::T_I8: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i8; + else + *d++ = s->val.i8; + break; + case nsXPTType::T_I16: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i16; + else + *d++ = s->val.i16; + break; + case nsXPTType::T_I32: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i32; + else + *d++ = s->val.i32; + break; + case nsXPTType::T_I64: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i64; + else + *d++ = s->val.i64; + break; + // + // unsigned types next + // + case nsXPTType::T_U8: + if (i < N_ARG_REGS) + regs[i] = s->val.u8; + else + *d++ = s->val.u8; + break; + case nsXPTType::T_U16: + if (i < N_ARG_REGS) + regs[i] = s->val.u16; + else + *d++ = s->val.u16; + break; + case nsXPTType::T_U32: + if (i < N_ARG_REGS) + regs[i] = s->val.u32; + else + *d++ = s->val.u32; + break; + case nsXPTType::T_U64: + if (i < N_ARG_REGS) + regs[i] = s->val.u64; + else + *d++ = s->val.u64; + break; + case nsXPTType::T_FLOAT: + if (i < N_ARG_REGS) + // Place a float in least significant bytes. + *(float*)(((char*)®s[i+1]) - sizeof(float)) = s->val.f; + else + *(float*)d++ = s->val.f; + break; + case nsXPTType::T_DOUBLE: + if (i < N_ARG_REGS) + *(double*)®s[i] = s->val.d; + else + *(double*)d++ = s->val.d; + break; + case nsXPTType::T_BOOL: + if (i < N_ARG_REGS) + regs[i] = s->val.b; + else + *d++ = s->val.b; + break; + case nsXPTType::T_CHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.c; + else + *d++ = s->val.c; + break; + case nsXPTType::T_WCHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.wc; + else + *d++ = s->val.wc; + break; + default: + // all the others are plain pointer types + if (i < N_ARG_REGS) + regs[i] = (PRUint64)s->val.p; + else + *d++ = (PRUint64)s->val.p; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp new file mode 100644 index 00000000..7f7d84c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_alpha.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Glen Nakamura + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name and disables unused warning */ +static void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +__asm__("invoke_copy_to_stack") __attribute__((unused)); + +static void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.u32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} + +/* + * XPTC_PUBLIC_API(nsresult) + * XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + * PRUint32 paramCount, nsXPTCVariant* params) + */ +__asm__( + "#### XPTC_InvokeByIndex ####\n" +".text\n\t" + ".align 5\n\t" + ".globl XPTC_InvokeByIndex\n\t" + ".ent XPTC_InvokeByIndex\n" +"XPTC_InvokeByIndex:\n\t" + ".frame $15,32,$26,0\n\t" + ".mask 0x4008000,-32\n\t" + "ldgp $29,0($27)\n" +"$XPTC_InvokeByIndex..ng:\n\t" + "subq $30,32,$30\n\t" + "stq $26,0($30)\n\t" + "stq $15,8($30)\n\t" + "bis $30,$30,$15\n\t" + ".prologue 1\n\t" + + /* + * Allocate enough stack space to hold the greater of 6 or "paramCount"+1 + * parameters. (+1 for "this" pointer) Room for at least 6 parameters + * is required for storage of those passed via registers. + */ + + "bis $31,5,$2\n\t" /* count = MAX(5, "paramCount") */ + "cmplt $2,$18,$1\n\t" + "cmovne $1,$18,$2\n\t" + "s8addq $2,16,$1\n\t" /* room for count+1 params (8 bytes each) */ + "bic $1,15,$1\n\t" /* stack space is rounded up to 0 % 16 */ + "subq $30,$1,$30\n\t" + + "stq $16,0($30)\n\t" /* save "that" (as "this" pointer) */ + "stq $17,16($15)\n\t" /* save "methodIndex" */ + + "addq $30,8,$16\n\t" /* pass stack pointer */ + "bis $18,$18,$17\n\t" /* pass "paramCount" */ + "bis $19,$19,$18\n\t" /* pass "params" */ + "bsr $26,$invoke_copy_to_stack..ng\n\t" /* call invoke_copy_to_stack */ + + /* + * Copy the first 6 parameters to registers and remove from stack frame. + * Both the integer and floating point registers are set for each parameter + * except the first which is the "this" pointer. (integer only) + * The floating point registers are all set as doubles since the + * invoke_copy_to_stack function should have converted the floats. + */ + "ldq $16,0($30)\n\t" /* integer registers */ + "ldq $17,8($30)\n\t" + "ldq $18,16($30)\n\t" + "ldq $19,24($30)\n\t" + "ldq $20,32($30)\n\t" + "ldq $21,40($30)\n\t" + "ldt $f17,8($30)\n\t" /* floating point registers */ + "ldt $f18,16($30)\n\t" + "ldt $f19,24($30)\n\t" + "ldt $f20,32($30)\n\t" + "ldt $f21,40($30)\n\t" + + "addq $30,48,$30\n\t" /* remove params from stack */ + + /* + * Call the virtual function with the constructed stack frame. + */ + "bis $16,$16,$1\n\t" /* load "this" */ + "ldq $2,16($15)\n\t" /* load "methodIndex" */ + "ldq $1,0($1)\n\t" /* load vtable */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "s8addq $2,$31,$2\n\t" /* vtable index = "methodIndex" * 8 */ +#else /* not G++ V3 ABI */ + "s8addq $2,16,$2\n\t" /* vtable index = "methodIndex" * 8 + 16 */ +#endif /* G++ V3 ABI */ + "addq $1,$2,$1\n\t" + "ldq $27,0($1)\n\t" /* load address of function */ + "jsr $26,($27),0\n\t" /* call virtual function */ + "ldgp $29,0($26)\n\t" + + "bis $15,$15,$30\n\t" + "ldq $26,0($30)\n\t" + "ldq $15,8($30)\n\t" + "addq $30,32,$30\n\t" + "ret $31,($26),1\n\t" + ".end XPTC_InvokeByIndex" + ); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp new file mode 100644 index 00000000..363e45e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_m68k.cpp @@ -0,0 +1,170 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +extern "C" { + static PRUint32 + invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) + { + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; + } + + void + invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) + { + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + // 8 and 16 bit types should be promoted to 32 bits when copying + // onto the stack. + case nsXPTType::T_I8 : *((PRUint32*)d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRUint32*)d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*)d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*)d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result, n; + + n = invoke_count_words(paramCount, params) * 4; + + __asm__ __volatile__( + "subl %5, %/sp\n\t" /* make room for params */ + "movl %/sp, %/a0\n\t" + "movl %4, %/sp@-\n\t" + "movl %3, %/sp@-\n\t" + "movl %/a0, %/sp@-\n\t" + "jbsr invoke_copy_to_stack\n\t" /* copy params */ + "addl #12, %/sp\n\t" + "movl %1, %/a0\n\t" + "movl %/a0, %/sp@-\n\t" + "movl %/a0@, %/a0\n\t" + "movl %2, %/d0\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "movl %/a0@(%/d0:l:4), %/a0\n\t" +#else /* not V3 */ + "movl %/a0@(8,%/d0:l:4), %/a0\n\t" +#endif + "jbsr %/a0@\n\t" /* safe to not cleanup sp */ + "movl %/d0, %0\n\t" + "addql #4, %/sp\n\t" + "addl %5, %/sp" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (methodIndex), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params), /* %4 */ + "g" (n) /* %5 */ + : "a0", "a1", "d0", "d1", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp new file mode 100644 index 00000000..5da035ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390.cpp @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 overflow = 0, gpr = 1 /*this*/, fpr = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) gpr++; else overflow++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) gpr+=2; else gpr=5, overflow+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) gpr+=2; else gpr=5, overflow+=2; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) fpr++; else overflow++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) fpr++; else overflow+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + if (gpr < 5) gpr++; else overflow++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) gpr++; else overflow++; + break; + } + } + /* Round up number of overflow words to ensure stack + stays aligned to 8 bytes. */ + return (overflow + 1) & ~1; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d_ov, PRUint32 overflow) +{ + PRUint32 *d_gpr = d_ov + overflow; + PRUint64 *d_fpr = (PRUint64 *)(d_gpr + 4); + PRUint32 gpr = 1 /*this*/, fpr = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) + *((void**)d_gpr) = s->ptr, d_gpr++, gpr++; + else + *((void**)d_ov ) = s->ptr, d_ov++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i8, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i8, d_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i16, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i16, d_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + *((PRInt32*) d_gpr) = s->val.i32, d_gpr++, gpr++; + else + *((PRInt32*) d_ov ) = s->val.i32, d_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) + *((PRInt64*) d_gpr) = s->val.i64, d_gpr+=2, gpr+=2; + else + *((PRInt64*) d_ov ) = s->val.i64, d_ov+=2, gpr=5; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + *((PRUint32*) d_gpr) = s->val.u8, d_gpr++, gpr++; + else + *((PRUint32*) d_ov ) = s->val.u8, d_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.u16, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.u16, d_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.u32, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.u32, d_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) + *((PRUint64*)d_gpr) = s->val.u64, d_gpr+=2, gpr+=2; + else + *((PRUint64*)d_ov ) = s->val.u64, d_ov+=2, gpr=5; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) + *((float*) d_fpr) = s->val.f, d_fpr++, fpr++; + else + *((float*) d_ov ) = s->val.f, d_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) + *((double*) d_fpr) = s->val.d, d_fpr++, fpr++; + else + *((double*) d_ov ) = s->val.d, d_ov+=2; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.b, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.b, d_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.c, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.c, d_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + *((PRUint32*)d_gpr) = s->val.wc, d_gpr++, gpr++; + else + *((PRUint32*)d_ov ) = s->val.wc, d_ov++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) + *((void**) d_gpr) = s->val.p, d_gpr++, gpr++; + else + *((void**) d_ov ) = s->val.p, d_ov++; + break; + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 *vtable = *(PRUint32 **)that; +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + PRUint32 method = vtable[methodIndex]; +#else /* not G++ V3 ABI */ + PRUint32 method = vtable[methodIndex + 2]; +#endif /* G++ V3 ABI */ + PRUint32 overflow = invoke_count_words (paramCount, params); + PRUint32 result; + + __asm__ __volatile__ + ( + "lr 7,15\n\t" + "ahi 7,-32\n\t" + + "lr 3,%3\n\t" + "sll 3,2\n\t" + "lcr 3,3\n\t" + "l 2,0(15)\n\t" + "la 15,0(3,7)\n\t" + "st 2,0(15)\n\t" + + "lr 2,%1\n\t" + "lr 3,%2\n\t" + "la 4,96(15)\n\t" + "lr 5,%3\n\t" + "basr 14,%4\n\t" + + "lr 2,%5\n\t" + "ld 0,112(7)\n\t" + "ld 2,120(7)\n\t" + "lm 3,6,96(7)\n\t" + "basr 14,%6\n\t" + + "la 15,32(7)\n\t" + + "lr %0,2\n\t" + : "=r" (result) + : "r" (paramCount), + "r" (params), + "r" (overflow), + "a" (invoke_copy_to_stack), + "a" (that), + "a" (method) + : "2", "3", "4", "5", "6", "7", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp new file mode 100644 index 00000000..5a4268b6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_linux_s390x.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 overflow = 0, gpr = 1 /*this*/, fpr = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) gpr++; else overflow++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + case nsXPTType::T_I64 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + case nsXPTType::T_U64 : + if (gpr < 5) gpr++; else overflow++; + break; + case nsXPTType::T_FLOAT : + case nsXPTType::T_DOUBLE : + if (fpr < 4) fpr++; else overflow++; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + if (gpr < 5) gpr++; else overflow++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) gpr++; else overflow++; + break; + } + } + /* Round up number of overflow words to ensure stack + stays aligned to 8 bytes. */ + return (overflow + 1) & ~1; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint64* d_ov, PRUint32 overflow) +{ + PRUint64 *d_gpr = d_ov + overflow; + PRUint64 *d_fpr = (PRUint64 *)(d_gpr + 4); + PRUint32 gpr = 1 /*this*/, fpr = 0; + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + if (gpr < 5) + *((void**)d_gpr) = s->ptr, d_gpr++, gpr++; + else + *((void**)d_ov ) = s->ptr, d_ov++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i8, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i8, d_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i16, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i16, d_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i32, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i32, d_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 5) + *((PRInt64*) d_gpr) = s->val.i64, d_gpr++, gpr++; + else + *((PRInt64*) d_ov ) = s->val.i64, d_ov++; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + *((PRUint64*) d_gpr) = s->val.u8, d_gpr++, gpr++; + else + *((PRUint64*) d_ov ) = s->val.u8, d_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u16, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u16, d_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u32, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u32, d_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.u64, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.u64, d_ov++; + break; + case nsXPTType::T_FLOAT : + if (fpr < 4) + *((float*) d_fpr) = s->val.f, d_fpr++, fpr++; + else + *(((float*) d_ov )+1) = s->val.f, d_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 4) + *((double*) d_fpr) = s->val.d, d_fpr++, fpr++; + else + *((double*) d_ov ) = s->val.d, d_ov++; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.b, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.b, d_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.c, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.c, d_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + *((PRUint64*)d_gpr) = s->val.wc, d_gpr++, gpr++; + else + *((PRUint64*)d_ov ) = s->val.wc, d_ov++; + break; + default: + // all the others are plain pointer types + if (gpr < 5) + *((void**) d_gpr) = s->val.p, d_gpr++, gpr++; + else + *((void**) d_ov ) = s->val.p, d_ov++; + break; + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint64 *vtable = *(PRUint64 **)that; +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + PRUint64 method = vtable[methodIndex]; +#else /* not G++ V3 ABI */ + PRUint64 method = vtable[methodIndex + 2]; +#endif /* G++ V3 ABI */ + PRUint64 overflow = invoke_count_words (paramCount, params); + PRUint64 result; + + __asm__ __volatile__ + ( + "lgr 7,15\n\t" + "aghi 7,-64\n\t" + + "lgr 3,%3\n\t" + "sllg 3,3,3\n\t" + "lcgr 3,3\n\t" + "lg 2,0(15)\n\t" + "la 15,0(3,7)\n\t" + "stg 2,0(15)\n\t" + + "lgr 2,%1\n\t" + "lgr 3,%2\n\t" + "la 4,160(15)\n\t" + "lgr 5,%3\n\t" + "basr 14,%4\n\t" + + "lgr 2,%5\n\t" + "ld 0,192(7)\n\t" + "ld 2,200(7)\n\t" + "ld 4,208(7)\n\t" + "ld 6,216(7)\n\t" + "lmg 3,6,160(7)\n\t" + "basr 14,%6\n\t" + + "la 15,64(7)\n\t" + + "lgr %0,2\n\t" + : "=r" (result) + : "r" ((PRUint64)paramCount), + "r" (params), + "r" (overflow), + "a" (invoke_copy_to_stack), + "a" (that), + "a" (method) + : "2", "3", "4", "5", "6", "7", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp new file mode 100644 index 00000000..a73e4327 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_mips.cpp @@ -0,0 +1,122 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Brendan Eich + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 code is for MIPS using the O32 ABI. */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + // Count a word for a0 even though it's never stored or loaded + // We do this only for alignment of register pairs. + PRUint32 result = 1; + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + result++; + + if (s->IsPtrData()) + continue; + + switch(s->type) + { + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + if (result & 1) + result++; + result++; + break; + } + } + return (result + 1) & ~(PRUint32)1; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, + nsXPTCVariant* s) +{ + // Skip the unused a0 slot, which we keep only for register pair alignment. + d++; + + for (PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if (s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : + if ((PRWord)d & 4) d++; + *((PRInt64*) d) = s->val.i64; d++; + break; + case nsXPTType::T_U64 : + if ((PRWord)d & 4) d++; + *((PRUint64*) d) = s->val.u64; d++; + break; + case nsXPTType::T_DOUBLE : + if ((PRWord)d & 4) d++; + *((double*) d) = s->val.d; d++; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, + nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp new file mode 100644 index 00000000..65bf8f0c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_netbsd_m68k.cpp @@ -0,0 +1,175 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +// Remember that these 'words' are 32bit DWORDS + +#if !defined(__NetBSD__) || !defined(__m68k__) +#error This code is for NetBSD/m68k only +#endif + +extern "C" { + static PRUint32 + invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) + { + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; + } + + static void + invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) + { + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + // 8 and 16 bit types should be promoted to 32 bits when copying + // onto the stack. + case nsXPTType::T_I8 : *((PRUint32*)d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRUint32*)d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*)d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*)d) = s->val.c; break; + // wchar_t is an int (32 bits) on NetBSD + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } + } +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + PRUint32 result; + + __asm__ __volatile__( + "movl %4, sp@-\n\t" + "movl %3, sp@-\n\t" + "jbsr _invoke_count_words\n\t" /* count words */ + "addql #8, sp\n\t" + "lsll #2, d0\n\t" /* *= 4 */ + "movl sp, a2\n\t" /* save original sp */ + "subl d0, sp\n\t" /* make room for params */ + "movl sp, a0\n\t" + "movl %4, sp@-\n\t" + "movl %3, sp@-\n\t" + "movl a0, sp@-\n\t" + "jbsr _invoke_copy_to_stack\n\t" /* copy params */ + "addl #12, sp\n\t" + "movl %1, a0\n\t" + "movl a0@, a1\n\t" + "movl %2, d0\n\t" /* function index */ + "movl a0, d1\n\t" + "movw a1@(8,d0:l:8), a0\n\t" + "addl a0, d1\n\t" + "movl a1@(12,d0:l:8), a1\n\t" + "movl d1, sp@-\n\t" + "jbsr a1@\n\t" + "movl a2, sp\n\t" /* restore original sp */ + "movl d0, %0\n\t" + : "=g" (result) /* %0 */ + : "g" (that), /* %1 */ + "g" (methodIndex), /* %2 */ + "g" (paramCount), /* %3 */ + "g" (params) /* %4 */ + : "a0", "a1", "a2", "d0", "d1", "memory" + ); + + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp new file mode 100644 index 00000000..ae22a48c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_openvms_alpha.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +extern "C" { + +/* This is in the ASM file */ +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + + +void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + /* + ** The line for T_U32 may look wrong (we use signed value for an + ** unsigned data type), but it is right. Why? The Alpha calling + ** standard is defined to sign extend all 32-bit values, regardless + ** of whether they are int, unsigned int, or 32-bit pointer. The + ** caller must "sign-extend" it by replicating bit 31 in bits 32 + ** thru 63 (yes, even for unsigned). This is the format that results + ** naturally from the LDL instruction, the ADDL instruction, etc. + */ + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} + +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp new file mode 100644 index 00000000..13c3b23d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_osf1_alpha.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* contributed by Steve Streeter */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name */ +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s); + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *d = (PRUint64)s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *d = (PRUint64)s->val.i8; break; + case nsXPTType::T_I16 : *d = (PRUint64)s->val.i16; break; + case nsXPTType::T_I32 : *d = (PRUint64)s->val.i32; break; + case nsXPTType::T_I64 : *d = (PRUint64)s->val.i64; break; + case nsXPTType::T_U8 : *d = (PRUint64)s->val.u8; break; + case nsXPTType::T_U16 : *d = (PRUint64)s->val.u16; break; + case nsXPTType::T_U32 : *d = (PRUint64)s->val.u32; break; + case nsXPTType::T_U64 : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // convert floats to doubles if they are to be passed + // via registers so we can just deal with doubles later + union { PRUint64 u64; double d; } t; + t.d = (double)s->val.f; + *d = t.u64; + } + else + // otherwise copy to stack normally + *d = (PRUint64)s->val.u32; + break; + case nsXPTType::T_DOUBLE : *d = (PRUint64)s->val.u64; break; + case nsXPTType::T_BOOL : *d = (PRUint64)s->val.b; break; + case nsXPTType::T_CHAR : *d = (PRUint64)s->val.c; break; + case nsXPTType::T_WCHAR : *d = (PRUint64)s->val.wc; break; + default: + // all the others are plain pointer types + *d = (PRUint64)s->val.p; + break; + } + } +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp new file mode 100644 index 00000000..c6208a50 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_pa32.cpp @@ -0,0 +1,181 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#if _HPUX +#error "This code is for HP-PA RISC 32 bit mode only" +#endif + +#include + +typedef unsigned nsXPCVariant; + +extern "C" PRInt32 +invoke_count_bytes(nsISupports* that, const PRUint32 methodIndex, + const PRUint32 paramCount, const nsXPTCVariant* s) +{ + PRInt32 result = 4; /* variant records do not include self pointer */ + + /* counts the number of bytes required by the argument stack, + 64 bit integer, and double requires 8 bytes. All else requires + 4 bytes. + */ + + { + PRUint32 indx; + for (indx = paramCount; indx > 0; --indx, ++s) + { + if (! s->IsPtrData()) + { + if (s->type == nsXPTType::T_I64 || s->type == nsXPTType::T_U64 || + s->type == nsXPTType::T_DOUBLE) + { + /* 64 bit integer and double aligned on 8 byte boundaries */ + result += (result & 4) + 8; + continue; + } + } + result += 4; /* all other cases use 4 bytes */ + } + } + result -= 72; /* existing stack buffer is 72 bytes */ + if (result < 0) + return 0; + { + /* round up to 64 bytes boundary */ + PRInt32 remainder = result & 63; + return (remainder == 0) ? result : (result + 64 - remainder); + } +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, + const PRUint32 paramCount, nsXPTCVariant* s) +{ + + typedef struct + { + PRUint32 hi; + PRUint32 lo; + } DU; + + PRUint32* dest = d; + nsXPTCVariant* source = s; + /* we clobber param vars by copying stuff on stack, have to use local var */ + + PRUint32 floatflags = 0; + /* flag indicating which floating point registers to load */ + + PRUint32 regwords = 1; /* register 26 is reserved for ptr to 'that' */ + PRUint32 indx; + + for (indx = paramCount; indx > 0; --indx, --dest, ++source) + { + if (source->IsPtrData()) + { + *((void**) dest) = source->ptr; + ++regwords; + continue; + } + switch (source->type) + { + case nsXPTType::T_I8 : *((PRInt32*) dest) = source->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) dest) = source->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) dest) = source->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + if (regwords & 1) + { + /* align on double word boundary */ + --dest; + ++regwords; + } + *((uint32*) dest) = ((DU *) source)->lo; + *((uint32*) --dest) = ((DU *) source)->hi; + /* big endian - hi word in low addr */ + regwords += 2; + continue; + case nsXPTType::T_DOUBLE : + if (regwords & 1) + { + /* align on double word boundary */ + --dest; + ++regwords; + } + switch (regwords) /* load double precision float register */ + { + case 2: + floatflags |= 1; + } + *((uint32*) dest) = ((DU *) source)->lo; + *((uint32*) --dest) = ((DU *) source)->hi; + /* big endian - hi word in low addr */ + regwords += 2; + continue; + case nsXPTType::T_FLOAT : + switch (regwords) /* load single precision float register */ + { + case 1: + floatflags |= 2; + break; + case 2: + floatflags |= 4; + break; + case 3: + floatflags |= 8; + } + *((float*) dest) = source->val.f; + break; + case nsXPTType::T_U8 : *((PRUint32*) (dest)) = source->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*) (dest)) = source->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*) (dest)) = source->val.u32; break; + case nsXPTType::T_BOOL : *((PRBool*) (dest)) = source->val.b; break; + case nsXPTType::T_CHAR : *((PRUint32*) (dest)) = source->val.c; break; + case nsXPTType::T_WCHAR : *((PRInt32*) (dest)) = source->val.wc; break; + + default: + // all the others are plain pointer types + *((void**) dest) = source->val.p; + } + ++regwords; + } + return floatflags; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp new file mode 100644 index 00000000..d353063c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef AIX +#error "This code is for PowerPC only" +#endif + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + PRUint32 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint32 l_paramCount = paramCount, fpCount = 0; + double *l_fprData = fprData; + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + *((uint32*) l_d++) = ((DU *)l_s)->hi; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_DOUBLE : + *((uint32*) l_d++) = ((DU *)l_s)->hi; + *((uint32*) l_d) = ((DU *)l_s)->lo; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.d; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : + *((float*) l_d) = l_s->val.f; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.f; + break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*) l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp new file mode 100644 index 00000000..a42611b8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_aix64.cpp @@ -0,0 +1,95 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/LGPL 2.1/GPL 2.0 + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM are + * Copyright (C) 2002, International Business Machines Corporation. + * All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 LGPL or the GPL. 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifdef _AIX + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + PRUint64 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint32 l_paramCount = paramCount, fpCount = 0; + double *l_fprData = fprData; + + for(PRUint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if(l_s->IsPtrData()) + { + *l_d = (PRUint64)l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8: *l_d = (PRUint64)l_s->val.i8; break; + case nsXPTType::T_I16: *l_d = (PRUint64)l_s->val.i16; break; + case nsXPTType::T_I32: *l_d = (PRUint64)l_s->val.i32; break; + case nsXPTType::T_I64: *l_d = (PRUint64)l_s->val.i64; break; + case nsXPTType::T_U8: *l_d = (PRUint64)l_s->val.u8; break; + case nsXPTType::T_U16: *l_d = (PRUint64)l_s->val.u16; break; + case nsXPTType::T_U32: *l_d = (PRUint64)l_s->val.u32; break; + case nsXPTType::T_U64: *l_d = (PRUint64)l_s->val.u64; break; + case nsXPTType::T_BOOL: *l_d = (PRUint64)l_s->val.b; break; + case nsXPTType::T_CHAR: *l_d = (PRUint64)l_s->val.c; break; + case nsXPTType::T_WCHAR: *l_d = (PRUint64)l_s->val.wc; break; + + case nsXPTType::T_DOUBLE: + *((double*)l_d) = l_s->val.d; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.d; + break; + case nsXPTType::T_FLOAT: + *((float*)l_d) = l_s->val.f; + if(fpCount < 13) + l_fprData[fpCount++] = l_s->val.f; + break; + default: + // all the others are plain pointer types + *l_d = (PRUint64)l_s->val.p; + break; + } + } +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp new file mode 100644 index 00000000..7303045a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_linux.cpp @@ -0,0 +1,141 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +// The purpose of XPTC_InvokeByIndex() is to map a platform +// indepenpent call to the platform ABI. To do that, +// XPTC_InvokeByIndex() has to determine the method to call via vtable +// access. The parameters for the method are read from the +// nsXPTCVariant* and prepared for th native ABI. For the Linux/PPC +// ABI this means that the first 8 integral and floating point +// parameters are passed in registers. + +#include "xptcprivate.h" + +// 8 integral parameters are passed in registers +#define GPR_COUNT 8 + +// 8 floating point parameters are passed in registers, floats are +// promoted to doubles when passed in registers +#define FPR_COUNT 8 + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return PRUint32(((paramCount * 2) + 3) & ~3); +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, + PRUint32 paramCount, + nsXPTCVariant* s, + PRUint32* gpregs, + double* fpregs) +{ + PRUint32 gpr = 1; // skip one GP reg for 'that' + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(uint32 i = 0; i < paramCount; i++, s++) { + if(s->IsPtrData()) + tempu32 = (PRUint32) s->ptr; + else { + switch(s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: tempu32 = s->val.i8; break; + case nsXPTType::T_I16: tempu32 = s->val.i16; break; + case nsXPTType::T_I32: tempu32 = s->val.i32; break; + case nsXPTType::T_I64: tempu64 = s->val.i64; break; + case nsXPTType::T_U8: tempu32 = s->val.u8; break; + case nsXPTType::T_U16: tempu32 = s->val.u16; break; + case nsXPTType::T_U32: tempu32 = s->val.u32; break; + case nsXPTType::T_U64: tempu64 = s->val.u64; break; + case nsXPTType::T_BOOL: tempu32 = s->val.b; break; + case nsXPTType::T_CHAR: tempu32 = s->val.c; break; + case nsXPTType::T_WCHAR: tempu32 = s->val.wc; break; + default: tempu32 = (PRUint32) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.d; + else { + if ((PRUint32) d & 4) d++; // doubles are 8-byte aligned on stack + *((double*) d) = s->val.d; + d += 2; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.f; // if passed in registers, floats are promoted to doubles + else + *((float*) d++) = s->val.f; + } + else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64 + || s->type == nsXPTType::T_U64)) { + if ((gpr + 1) < GPR_COUNT) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + *((PRUint64*) &gpregs[gpr]) = tempu64; + gpr += 2; + } + else { + if ((PRUint32) d & 4) d++; // longlongs are 8-byte aligned on stack + *((PRUint64*) d) = tempu64; + d += 2; + } + } + else { + if (gpr < GPR_COUNT) + gpregs[gpr++] = tempu32; + else + *d++ = tempu32; + } + + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp new file mode 100644 index 00000000..0de8ea62 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_netbsd.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +// The purpose of XPTC_InvokeByIndex() is to map a platform +// indepenpent call to the platform ABI. To do that, +// XPTC_InvokeByIndex() has to determine the method to call via vtable +// access. The parameters for the method are read from the +// nsXPTCVariant* and prepared for th native ABI. For the Linux/PPC +// ABI this means that the first 8 integral and floating point +// parameters are passed in registers. + +#include "xptcprivate.h" + +// 8 integral parameters are passed in registers +#define GPR_COUNT 8 + +// 8 floating point parameters are passed in registers, floats are +// promoted to doubles when passed in registers +#define FPR_COUNT 8 + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return PRUint32(((paramCount * 2) + 3) & ~3); +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, + PRUint32 paramCount, + nsXPTCVariant* s, + PRUint32* gpregs, + double* fpregs) +{ + PRUint32 gpr = 1; // skip one GP reg for 'that' + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(uint32 i = 0; i < paramCount; i++, s++) { + if(s->IsPtrData()) + tempu32 = (PRUint32) s->ptr; + else { + switch(s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: tempu32 = s->val.i8; break; + case nsXPTType::T_I16: tempu32 = s->val.i16; break; + case nsXPTType::T_I32: tempu32 = s->val.i32; break; + case nsXPTType::T_I64: tempu64 = s->val.i64; break; + case nsXPTType::T_U8: tempu32 = s->val.u8; break; + case nsXPTType::T_U16: tempu32 = s->val.u16; break; + case nsXPTType::T_U32: tempu32 = s->val.u32; break; + case nsXPTType::T_U64: tempu64 = s->val.u64; break; + case nsXPTType::T_BOOL: tempu32 = s->val.b; break; + case nsXPTType::T_CHAR: tempu32 = s->val.c; break; + case nsXPTType::T_WCHAR: tempu32 = s->val.wc; break; + default: tempu32 = (PRUint32) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.d; + else { + if ((PRUint32) d & 4) d++; // doubles are 8-byte aligned on stack + *((double*) d) = s->val.d; + d += 2; + if (gpr < GPR_COUNT) + gpr += 2; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + fpregs[fpr++] = s->val.f; // if passed in registers, floats are promoted to doubles + else { + *((float*) d) = s->val.f; + d += 1; + if (gpr < GPR_COUNT) + gpr += 1; + } + } + else if (!s->IsPtrData() && (s->type == nsXPTType::T_I64 + || s->type == nsXPTType::T_U64)) { + if ((gpr + 1) < GPR_COUNT) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + *((PRUint64*) &gpregs[gpr]) = tempu64; + gpr += 2; + } + else { + if ((PRUint32) d & 4) d++; // longlongs are 8-byte aligned on stack + *((PRUint64*) d) = tempu64; + d += 2; + } + } + else { + if (gpr < GPR_COUNT) + gpregs[gpr++] = tempu32; + else + *d++ = tempu32; + } + + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp new file mode 100644 index 00000000..9a08acfd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_ppc_rhapsody.cpp @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + /* fprintf(stderr,"invoke_count_words(%d,%p)\n",paramCount, s);*/ + + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + return result; +} + +extern "C" void +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s, double *fprData) +{ + PRUint32 fpCount = 0; + + /* fprintf(stderr,"invoke_copy_to_stack(%p, %d, %p, %p)\n", d, paramCount, s, fprData);*/ + + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt32*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt32*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint32*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint32*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; + if (fpCount < 13) + fprData[fpCount++] = s->val.f; + break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; + if (fpCount < 13) + fprData[fpCount++] = s->val.d; + break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((PRInt32*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((PRUint32*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp new file mode 100644 index 00000000..fb2af366 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_netbsd.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* solaris defines __sparc for workshop compilers and + linux defines __sparc__ */ + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +typedef unsigned nsXPCVariant; + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + // nuts, I know there's a cooler way of doing this, but it's late + // now and it'll probably come to me in the morning. + if (result & 0x3) result += 4 - (result & 0x3); // ensure q-word alignment + return result; +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + uint32 *l_d = d; + nsXPTCVariant *l_s = s; + uint32 l_paramCount = paramCount; + uint32 regCount = 0; // return the number of registers to load from the stack + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : *((uint32*) l_d++) = ((DU *)l_s)->hi; + if (regCount < 5) regCount++; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : *((float*) l_d) = l_s->val.f; break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*)l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + return regCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp new file mode 100644 index 00000000..fb2af366 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparc_solaris.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +/* solaris defines __sparc for workshop compilers and + linux defines __sparc__ */ + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +typedef unsigned nsXPCVariant; + +extern "C" PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : + case nsXPTType::T_I16 : + case nsXPTType::T_I32 : + result++; + break; + case nsXPTType::T_I64 : + result+=2; + break; + case nsXPTType::T_U8 : + case nsXPTType::T_U16 : + case nsXPTType::T_U32 : + result++; + break; + case nsXPTType::T_U64 : + result+=2; + break; + case nsXPTType::T_FLOAT : + result++; + break; + case nsXPTType::T_DOUBLE : + result+=2; + break; + case nsXPTType::T_BOOL : + case nsXPTType::T_CHAR : + case nsXPTType::T_WCHAR : + result++; + break; + default: + // all the others are plain pointer types + result++; + break; + } + } + // nuts, I know there's a cooler way of doing this, but it's late + // now and it'll probably come to me in the morning. + if (result & 0x3) result += 4 - (result & 0x3); // ensure q-word alignment + return result; +} + +extern "C" PRUint32 +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ +/* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. +*/ + uint32 *l_d = d; + nsXPTCVariant *l_s = s; + uint32 l_paramCount = paramCount; + uint32 regCount = 0; // return the number of registers to load from the stack + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + + for(uint32 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + if(l_s->IsPtrData()) + { + *((void**)l_d) = l_s->ptr; + continue; + } + switch(l_s->type) + { + case nsXPTType::T_I8 : *((int32*) l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((int32*) l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((int32*) l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : *((uint32*) l_d++) = ((DU *)l_s)->hi; + if (regCount < 5) regCount++; + *((uint32*) l_d) = ((DU *)l_s)->lo; + break; + case nsXPTType::T_U8 : *((uint32*) l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((uint32*) l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((uint32*) l_d) = l_s->val.u32; break; + case nsXPTType::T_FLOAT : *((float*) l_d) = l_s->val.f; break; + case nsXPTType::T_BOOL : *((PRBool*) l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((uint32*) l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((int32*)l_d) = l_s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + return regCount; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp new file mode 100644 index 00000000..83b28ebb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_sparcv9_solaris.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Seawood + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#if !defined(__sparc) && !defined(__sparc__) +#error "This code is for Sparc only" +#endif + +/* Prototype specifies unmangled function name */ +extern "C" PRUint64 +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s); + +extern "C" PRUint64 +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + /* + We need to copy the parameters for this function to locals and use them + from there since the parameters occupy the same stack space as the stack + we're trying to populate. + */ + PRUint64 *l_d = d; + nsXPTCVariant *l_s = s; + PRUint64 l_paramCount = paramCount; + PRUint64 regCount = 0; // return the number of registers to load from the stack + + for(PRUint64 i = 0; i < l_paramCount; i++, l_d++, l_s++) + { + if (regCount < 5) regCount++; + + if (l_s->IsPtrData()) + { + *l_d = (PRUint64)l_s->ptr; + continue; + } + switch (l_s->type) + { + case nsXPTType::T_I8 : *((PRInt64*)l_d) = l_s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt64*)l_d) = l_s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt64*)l_d) = l_s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*)l_d) = l_s->val.i64; break; + + case nsXPTType::T_U8 : *((PRUint64*)l_d) = l_s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint64*)l_d) = l_s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint64*)l_d) = l_s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)l_d) = l_s->val.u64; break; + + /* in the case of floats, we want to put the bits in to the + 64bit space right justified... floats in the paramter array on + sparcv9 use odd numbered registers.. %f1, %f3, so we have to skip + the space that would be occupied by %f0, %f2, etc. + */ + case nsXPTType::T_FLOAT : *(((float*)l_d) + 1) = l_s->val.f; break; + case nsXPTType::T_DOUBLE: *((double*)l_d) = l_s->val.d; break; + case nsXPTType::T_BOOL : *((PRBool*)l_d) = l_s->val.b; break; + case nsXPTType::T_CHAR : *((PRUint64*)l_d) = l_s->val.c; break; + case nsXPTType::T_WCHAR : *((PRInt64*)l_d) = l_s->val.wc; break; + + default: + // all the others are plain pointer types + *((void**)l_d) = l_s->val.p; + break; + } + } + + return regCount; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp new file mode 100644 index 00000000..76445fa4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unixish_x86.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mark Mentovai + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" + +extern "C" { + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = paramCount; i >0; i--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + +/* XXX: the following line is here (rather than as the default clause in + * the following switch statement) so that the Sun native compiler + * will generate the correct assembly code on the Solaris Intel + * platform. See the comments in bug #28817 for more details. + */ + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + } + } +} + +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ +#ifdef __GNUC__ /* Gnu compiler. */ + PRUint32 result; + /* Each param takes at most 2, 4-byte words + It doesn't matter if we push too many words, and calculating the exact + amount takes time. */ + PRUint32 n = paramCount << 3; + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + int temp1, temp2; + + /* These are only significant when KEEP_STACK_16_BYTE_ALIGNED is + defined. Otherwise, they're just placeholders to keep the parameter + indices the same for aligned and unaligned users in the inline asm + block. */ + unsigned int saved_esp; + + __asm__ __volatile__( +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "movl %%esp, %3\n\t" +#endif + "subl %8, %%esp\n\t" /* make room for params */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* For the second CALL, there will be one parameter before the ones + copied by invoke_copy_to_stack. Make sure that the stack will be + aligned for that CALL. */ + "subl $4, %%esp\n\t" + "andl $0xfffffff0, %%esp\n\t" + /* For the first CALL, there are three parameters. Leave padding to + ensure alignment. */ + "subl $4, %%esp\n\t" + /* The third parameter to invoke_copy_to_stack is the destination pointer. + It needs to point into the parameter area prepared for the second CALL, + leaving room for the |that| parameter. This reuses |n|, which was + the stack space to reserve, but that's OK because it's no longer needed + if the stack is being kept aligned. */ + "leal 8(%%esp), %8\n\t" + "pushl %8\n\t" +#else + "pushl %%esp\n\t" +#endif + "pushl %7\n\t" + "pushl %6\n\t" + "call *%9\n\t" /* copy params */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* The stack is still aligned from the first CALL. Keep it aligned for + the next one by popping past the parameters from the first CALL and + leaving space for the first (|that|) parameter for the second CALL. */ + "addl $0x14, %%esp\n\t" +#else + "addl $0xc, %%esp\n\t" +#endif + "movl %4, %%ecx\n\t" +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ + "shl $3, %%eax\n\t" /* *= 8 */ + "addl $8, %%eax\n\t" /* += 8 skip first entry */ + "addl %%eax, %%edx\n\t" + "movswl (%%edx), %%eax\n\t" /* 'this' offset */ + "addl %%eax, %%ecx\n\t" + "pushl %%ecx\n\t" + "addl $4, %%edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%%edx,%%eax,4), %%edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%%edx,%%eax,4), %%edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%%edx)\n\t" /* safe to not cleanup esp */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "movl %3, %%esp\n\t" +#else + "addl $4, %%esp\n\t" + "addl %8, %%esp" +#endif + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2), /* %2 */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + "=&g" (saved_esp) /* %3 */ +#else + /* Don't waste a register, this isn't used if alignment is unimportant */ + "=m" (saved_esp) /* %3 */ +#endif + : "g" (that), /* %4 */ + "g" (methodIndex), /* %5 */ + "1" (paramCount), /* %6 */ + "2" (params), /* %7 */ +#ifdef KEEP_STACK_16_BYTE_ALIGNED + /* Must be in a register, it's the target of an LEA instruction */ + "r" (n), /* %8 */ +#else + "g" (n), /* %8 */ +#endif + "0" (fn_copy) /* %9 */ + : "memory" + ); + + return result; + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp new file mode 100644 index 00000000..88219d8d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_unsupported.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + NS_ASSERTION(0,"XPTC_InvokeByIndex called on unsupported platform"); + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp new file mode 100644 index 00000000..b017c741 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_64_linux.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Platform specific code to invoke XPCOM methods on native objects + +#include "xptcprivate.h" + +// 6 integral parameters are passed in registers +const PRUint32 GPR_COUNT = 6; + +// 8 floating point parameters are passed in SSE registers +const PRUint32 FPR_COUNT = 8; + +// Remember that these 'words' are 64-bit long +static inline void +invoke_count_words(PRUint32 paramCount, nsXPTCVariant * s, + PRUint32 & nr_gpr, PRUint32 & nr_fpr, PRUint32 & nr_stack) +{ + nr_gpr = 1; // skip one GP register for 'that' + nr_fpr = 0; + nr_stack = 0; + + /* Compute number of eightbytes of class MEMORY. */ + for (uint32 i = 0; i < paramCount; i++, s++) { + if (!s->IsPtrData() + && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(PRUint64 * d, PRUint32 paramCount, nsXPTCVariant * s, + PRUint64 * gpregs, double * fpregs) +{ + PRUint32 nr_gpr = 1; // skip one GP register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (uint32 i = 0; i < paramCount; i++, s++) { + if (s->IsPtrData()) + value = (PRUint64) s->ptr; + else { + switch (s->type) { + case nsXPTType::T_FLOAT: break; + case nsXPTType::T_DOUBLE: break; + case nsXPTType::T_I8: value = s->val.i8; break; + case nsXPTType::T_I16: value = s->val.i16; break; + case nsXPTType::T_I32: value = s->val.i32; break; + case nsXPTType::T_I64: value = s->val.i64; break; + case nsXPTType::T_U8: value = s->val.u8; break; + case nsXPTType::T_U16: value = s->val.u16; break; + case nsXPTType::T_U32: value = s->val.u32; break; + case nsXPTType::T_U64: value = s->val.u64; break; + case nsXPTType::T_BOOL: value = s->val.b; break; + case nsXPTType::T_CHAR: value = s->val.c; break; + case nsXPTType::T_WCHAR: value = s->val.wc; break; + default: value = (PRUint64) s->val.p; break; + } + } + + if (!s->IsPtrData() && s->type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + fpregs[nr_fpr++] = s->val.d; + else { + *((double *)d) = s->val.d; + d++; + } + } + else if (!s->IsPtrData() && s->type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + fpregs[nr_fpr++] = s->val.d; + else { + *((float *)d) = s->val.f; + d++; + } + } + else { + if (nr_gpr < GPR_COUNT) + gpregs[nr_gpr++] = value; + else + *d++ = value; + } + } +} + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports * that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant * params) +{ + PRUint32 nr_gpr, nr_fpr, nr_stack; + invoke_count_words(paramCount, params, nr_gpr, nr_fpr, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + +#ifndef VBOX_WITH_GCC_SANITIZER + // Load parameters to stack, if necessary + PRUint64 *stack = (PRUint64 *) __builtin_alloca(nr_stack * 8); +#else + typedef struct { PRUint64 stack[20]; } methodStack; + if (nr_stack > 20) + return NS_ERROR_CALL_FAILED; + methodStack stack; +#endif + PRUint64 gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; +#ifndef VBOX_WITH_GCC_SANITIZER + invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); +#else + invoke_copy_to_stack(stack.stack, paramCount, params, gpregs, fpregs); +#endif + + // Load FPR registers from fpregs[] + register double d0 asm("xmm0"); + register double d1 asm("xmm1"); + register double d2 asm("xmm2"); + register double d3 asm("xmm3"); + register double d4 asm("xmm4"); + register double d5 asm("xmm5"); + register double d6 asm("xmm6"); + register double d7 asm("xmm7"); + + switch (nr_fpr) { +#define ARG_FPR(N) \ + case N+1: d##N = fpregs[N]; + ARG_FPR(7); + ARG_FPR(6); + ARG_FPR(5); + ARG_FPR(4); + ARG_FPR(3); + ARG_FPR(2); + ARG_FPR(1); + ARG_FPR(0); + case 0:; +#undef ARG_FPR + } + + // Load GPR registers from gpregs[] + register PRUint64 a0 asm("rdi"); + register PRUint64 a1 asm("rsi"); + register PRUint64 a2 asm("rdx"); + register PRUint64 a3 asm("rcx"); + register PRUint64 a4 asm("r8"); + register PRUint64 a5 asm("r9"); + + switch (nr_gpr) { +#define ARG_GPR(N) \ + case N+1: a##N = gpregs[N]; + ARG_GPR(5); + ARG_GPR(4); + ARG_GPR(3); + ARG_GPR(2); + ARG_GPR(1); + case 1: a0 = (PRUint64) that; + case 0:; +#undef ARG_GPR + } + + // Ensure that assignments to SSE registers won't be optimized away + asm("" :: + "x" (d0), "x" (d1), "x" (d2), "x" (d3), + "x" (d4), "x" (d5), "x" (d6), "x" (d7)); + + // Get pointer to method + PRUint64 methodAddress = *((PRUint64 *)that); + methodAddress += 8 * methodIndex; + methodAddress = *((PRUint64 *)methodAddress); + +#ifndef VBOX_WITH_GCC_SANITIZER + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5); +#else + typedef PRUint32 (*Method)(PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, PRUint64, methodStack); + PRUint32 result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5, stack); +#endif + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp new file mode 100644 index 00000000..14ecb2d8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_x86_solaris.cpp @@ -0,0 +1,285 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#ifdef VBOX +# include +#endif + +extern "C" { + +// Remember that these 'words' are 32bit DWORDS + +static PRUint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + PRUint32 result = 0; + for(PRUint32 i = 0; i < paramCount; i++, s++) + { + if(s->IsPtrData()) + { + result++; + continue; + } + result++; + switch(s->type) + { + case nsXPTType::T_I64 : + case nsXPTType::T_U64 : + case nsXPTType::T_DOUBLE : + result++; + break; + } + } + return result; +} + +static void +invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d) +{ + for(PRUint32 i = 0; i < paramCount; i++, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + +/* XXX: the following line is here (rather than as the default clause in + * the following switch statement) so that the Sun native compiler + * will generate the correct assembly code on the Solaris Intel + * platform. See the comments in bug #28817 for more details. + */ + + *((void**)d) = s->val.p; + + switch(s->type) + { + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + } + } +} + +} + +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ +#ifdef __GNUC__ /* Gnu compiler. */ + PRUint32 result; + PRUint32 n = invoke_count_words (paramCount, params) * 4; + int temp1, temp2, temp3; + +# ifdef VBOX + /* This is for dealing with gcc 4.5.2 not using registers for 'g' parameters + and instead trying to get things like 'that' via %esp after we've changed it. */ +# if 1 /* safe version. */ + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + struct Combined + { + PRUint32 that; /* offset: 0 */ + PRUint32 pfn; /* offset: 4 */ + PRUint32 savedEsp; /* offset: 8 */ + PRUint32 paramCount; /* offset: 12 */ + PRUint32 params; /* offset: 16 */ + } Combined; +# ifdef CFRONT_STYLE_THIS_ADJUST + struct CFRONTVTE { uintptr_t off, pfn } *pVtab = *(struct CFRONTVTE **)that; + Combined.that = (uintptr_t)that + pVtab[methodIndex + 1].off; + Combined.pfn = pVtab[methodIndex + 1].pfn; +# elif defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + Combined.that = (uintptr_t)that; + Combined.pfn = (*(uintptr_t **)that)[methodIndex]; +# else /* not G++ V3 ABI */ + Combined.that = (uintptr_t)that; + Combined.pfn = (*(uintptr_t **)that)[2 + methodIndex]; +# endif /* G++ V3 ABI */ + Combined.paramCount = paramCount; + Combined.params = (uintptr_t)params; + + __asm__ __volatile__( + "mov %%esp, 8(%%esi)\n\t" /* savedEsp = %esp */ + "subl %1, %%esp\n\t" /* make room for params */ + + /* Call invoke_count_words to copy the parameters. */ + "pushl %%esp\n\t" /* arg2: dest */ + "pushl 16(%%esi)\n\t" /* arg1: params */ + "pushl 12(%%esi)\n\t" /* arg0: paramCount */ + "call *%0\n\t" + "addl $0xc, %%esp\n\t" + + /* Push the this pointer. */ + "pushl (%%esi)\n\t" /* that */ + "call *4(%%esi)\n\t" + "mov 8(%%esi), %%esp\n\t" + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2) /* %2 */ + : "S" (&Combined), /* %3 */ + "0" (fn_copy), + "1" (n) + : "memory" + ); + +# else /* Small version; ASSUMES nothing important gets put on the stack after the the alloca. */ + uintptr_t *pauStack = (uintptr_t *)alloca(n + sizeof(uintptr_t)); + invoke_copy_to_stack(paramCount, params, &pauStack[1]); +# ifdef CFRONT_STYLE_THIS_ADJUST + struct CFRONTVTE { uintptr_t off, pfn } *pVtab = *(struct CFRONTVTE **)that; + pauStack[0] = (uintptr_t)that + pVtab[methodIndex + 1].off; + uintptr_t pfn = pVtab[methodIndex + 1].pfn; +# elif defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + pauStack[0] = (uintptr_t)that; + uintptr_t pfn = (*(uintptr_t **)that)[methodIndex]; +# else /* not G++ V3 ABI */ + pauStack[0] = (uintptr_t)that; + uintptr_t pfn = (*(uintptr_t **)that)[2 + methodIndex]; +# endif /* G++ V3 ABI */ + + __asm__ __volatile__( + "xchg %%esp, %3\n\t" /* save+load %esp */ + "call *%0\n\t" + "xchg %%esp, %3\n\t" /* restore %esp */ + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2) /* %2 */ + : "S" (pauStack), /* %3 */ + "0" (pfn) + : "memory" + ); +# endif + +# else /* !VBOX */ + void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack; + __asm__ __volatile__( + "subl %8, %%esp\n\t" /* make room for params */ + "pushl %%esp\n\t" + "pushl %7\n\t" + "pushl %6\n\t" + "call *%0\n\t" /* copy params */ + "addl $0xc, %%esp\n\t" + "movl %4, %%ecx\n\t" +#ifdef CFRONT_STYLE_THIS_ADJUST + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ + "shl $3, %%eax\n\t" /* *= 8 */ + "addl $8, %%eax\n\t" /* += 8 skip first entry */ + "addl %%eax, %%edx\n\t" + "movswl (%%edx), %%eax\n\t" /* 'this' offset */ + "addl %%eax, %%ecx\n\t" + "pushl %%ecx\n\t" + "addl $4, %%edx\n\t" /* += 4, method pointer */ +#else /* THUNK_BASED_THIS_ADJUST */ + "pushl %%ecx\n\t" + "movl (%%ecx), %%edx\n\t" + "movl %5, %%eax\n\t" /* function index */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + "leal (%%edx,%%eax,4), %%edx\n\t" +#else /* not G++ V3 ABI */ + "leal 8(%%edx,%%eax,4), %%edx\n\t" +#endif /* G++ V3 ABI */ +#endif + "call *(%%edx)\n\t" /* safe to not cleanup esp */ + "addl $4, %%esp\n\t" + "addl %8, %%esp" + : "=a" (result), /* %0 */ + "=c" (temp1), /* %1 */ + "=d" (temp2), /* %2 */ + "=g" (temp3) /* %3 */ + : "g" (that), /* %4 */ + "g" (methodIndex), /* %5 */ + "1" (paramCount), /* %6 */ + "2" (params), /* %7 */ + "g" (n), /* %8 */ + "0" (fn_copy) /* %3 */ + : "memory" + ); +# endif /* !VBOX */ + + return result; +#elif defined(__SUNPRO_CC) /* Sun Workshop Compiler. */ + +asm( + "\n\t /: PRUint32 n = invoke_count_words (paramCount, params) * 4;" + + "\n\t pushl %ebx / preserve ebx" + "\n\t pushl %esi / preserve esi" + "\n\t movl %esp, %ebx / save address of pushed esi and ebx" + + "\n\t pushl 20(%ebp) / \"params\"" + "\n\t pushl 16(%ebp) / \"paramCount\"" + "\n\t call invoke_count_words" + "\n\t mov %ebx, %esp / restore esp" + + "\n\t sall $2,%eax" + "\n\t subl %eax, %esp / make room for arguments" + "\n\t movl %esp, %esi / save new esp" + + "\n\t pushl %esp" + "\n\t pushl 20(%ebp) / \"params\"" + "\n\t pushl 16(%ebp) / \"paramCount\"" + "\n\t call invoke_copy_to_stack / copy params" + "\n\t movl %esi, %esp / restore new esp" + + "\n\t movl 8(%ebp),%ecx / \"that\"" + "\n\t pushl %ecx / \"that\"" + "\n\t movl (%ecx), %edx" + "\n\t movl 12(%ebp), %eax / function index: \"methodIndex\"" + "\n\t movl 8(%edx,%eax,4), %edx" + + "\n\t call *%edx" + "\n\t mov %ebx, %esp" + "\n\t popl %esi" + "\n\t popl %ebx" +); + +/* result == %eax */ + if(0) /* supress "*** is expected to return a value." error */ + return 0; + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp new file mode 100644 index 00000000..5b55c930 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_darwin.cpp @@ -0,0 +1,243 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Darwin/AMD64 uses gcc >= 3.1 +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl __ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl __ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl __ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + /*".type __ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n"*/ \ + "__ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + /*".size __ZN14nsXPTCStubBase5Stub" #n "Ev,.-__ZN14nsXPTCStubBase5Stub" #n "Ev\n\t"*/ \ + ".elseif " #n " < 100\n\t" \ + /*".size __ZN14nsXPTCStubBase6Stub" #n "Ev,.-__ZN14nsXPTCStubBase6Stub" #n "Ev\n\t"*/ \ + ".else\n\t" \ + /*".size __ZN14nsXPTCStubBase7Stub" #n "Ev,.-__ZN14nsXPTCStubBase7Stub" #n "Ev\n\t"*/ \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) [methodIndex is in eax]. +asm(".text\n\t" + ".align 2\n\t" +/* ".type SharedStub,@function\n\t" */ + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call _PrepareAndDispatch\n\t" + "leave\n\t" + "ret\n\t" +/* ".size SharedStub,.-SharedStub" */ + ); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Darwin/AMD64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp new file mode 100644 index 00000000..fc90ecea --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Russell King + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if !defined(LINUX) || !defined(__arm__) +#error "This code is for Linux ARM only. Please check if it works for you, too.\nDepends strongly on gcc behaviour." +#endif + +/* Specify explicitly a symbol for this function, don't try to guess the c++ mangled symbol. */ +static nsresult PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) asm("_PrepareAndDispatch"); + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * This is our shared stub. + * + * r0 = Self. + * + * The Rules: + * We pass an (undefined) number of arguments into this function. + * The first 3 C++ arguments are in r1 - r3, the rest are built + * by the calling function on the stack. + * + * We are allowed to corrupt r0 - r3, ip, and lr. + * + * Other Info: + * We pass the stub number in using `ip'. + * + * Implementation: + * - We save r1 to r3 inclusive onto the stack, which will be + * immediately below the caller saved arguments. + * - setup r2 (PrepareAndDispatch's args pointer) to point at + * the base of all these arguments + * - Save LR (for the return address) + * - Set r1 (PrepareAndDispatch's methodindex argument) from ip + * - r0 is passed through (self) + * - Call PrepareAndDispatch + * - When the call returns, we return by loading the PC off the + * stack, and undoing the stack (one instruction)! + * + */ +__asm__ ("\n\ +SharedStub: \n\ + stmfd sp!, {r1, r2, r3} \n\ + mov r2, sp \n\ + str lr, [sp, #-4]! \n\ + mov r1, ip \n\ + bl _PrepareAndDispatch \n\ + ldr pc, [sp], #16"); + +/* + * Create sets of stubs to call the SharedStub. + * We don't touch the stack here, nor any registers, other than IP. + * IP is defined to be corruptable by a called function, so we are + * safe to use it. + * + * This will work with or without optimisation. + */ +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +/* + * Note : As G++3 ABI contains the length of the functionname in the + * mangled name, it is difficult to get a generic assembler mechanism like + * in the G++ 2.95 case. + * Create names would be like : + * _ZN14nsXPTCStubBase5Stub9Ev + * _ZN14nsXPTCStubBase6Stub13Ev + * _ZN14nsXPTCStubBase7Stub144Ev + * Use the assembler directives to get the names right... + */ + +#define STUB_ENTRY(n) \ + __asm__( \ + ".section \".text\"\n" \ +" .align 2\n" \ +" .iflt ("#n" - 10)\n" \ +" .globl _ZN14nsXPTCStubBase5Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase5Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase5Stub"#n"Ev:\n" \ +" .else\n" \ +" .iflt ("#n" - 100)\n" \ +" .globl _ZN14nsXPTCStubBase6Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase6Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase6Stub"#n"Ev:\n" \ +" .else\n" \ +" .iflt ("#n" - 1000)\n" \ +" .globl _ZN14nsXPTCStubBase7Stub"#n"Ev\n" \ +" .type _ZN14nsXPTCStubBase7Stub"#n"Ev,#function\n" \ +"_ZN14nsXPTCStubBase7Stub"#n"Ev:\n" \ +" .else\n" \ +" .err \"stub number "#n"> 1000 not yet supported\"\n" \ +" .endif\n" \ +" .endif\n" \ +" .endif\n" \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); + +#if 0 +/* + * This part is left in as comment : this is how the method definition + * should look like. + */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n () \ +{ \ + __asm__ ( \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); \ + return 0; /* avoid warnings */ \ +} +#endif + +#else /* G++2.95 ABI */ + +#define STUB_ENTRY(n) \ + __asm__( \ + ".section \".text\"\n" \ +" .align\n" \ +" .globl Stub"#n"__14nsXPTCStubBase\n" \ +" .type Stub"#n"__14nsXPTCStubBase,#function\n\n" \ +"Stub"#n"__14nsXPTCStubBase:\n" \ +" mov ip, #"#n"\n" \ +" b SharedStub\n\t"); + +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp new file mode 100644 index 00000000..82856234 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm64_vbox.cpp @@ -0,0 +1,272 @@ +/* $Id: xptcstubs_arm64_vbox.cpp $ */ +/** @file + * XPCOM - XPTC stubs for arm64. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "xptcprivate.h" +#include +#include +#include + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(RT_OS_DARWIN) +# define NAME_PREFIX _ +# define NAME_PREFIX_STR "_" +#else +# define NAME_PREFIX +# define NAME_PREFIX_STR "" +#endif +#define ASMNAME(a_Name) NAME_PREFIX ## a_Name +#define NUM_ARGS_IN_GPRS 8 /**< Number of arguments passed in general purpose registers (starting with x0). */ +#define NUM_ARGS_IN_FPRS 8 /**< Number of arguments passed in floating point registers (starting with d0). */ + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +extern "C" __attribute__((naked)) nsresult CommonXPTCStub(void); +DECL_NO_INLINE(extern "C", nsresult) +CommonXPTCStubCWorker(nsXPTCStubBase *pThis, uint32_t idxMethod, uint64_t *pauGprArgs, uint64_t *pauFprArgs, uint64_t *puStackArgs); + + +/** + * All the stubs call this shared code w/ method index in w17. + * + * The naked attribute means pure inline assembly function. clang complains + * if we put C statements in it. So, this exacty what we need here and for the + * stubs. + * + * @note This could be static if we weren't afraid the compile would optimize it + * out. + */ +extern "C" __attribute__((naked)) nsresult CommonXPTCStub(void) +{ + __asm__ __volatile__( + /* Prologue - reserve space for frame+link reg spill and the GPR and FPR arrays. */ "\ + sub sp, sp, %[cbGPRandFPRs] + 16 \n\ + stp x29, x30, [sp, %[cbGPRandFPRs]] \n\ + add x29, sp, %[cbGPRandFPRs] \n\ + .cfi_def_cfa x29, 16 \n\ + .cfi_rel_offset x30, -8 \n\ + .cfi_rel_offset x29, -16 \n\ +" + /* reserve stack space for the integer and floating point registers and save them: */ "\ + \n\ + stp x0, x1, [sp, #0] \n\ + stp x2, x3, [sp, #16] \n\ + stp x4, x5, [sp, #32] \n\ + stp x6, x7, [sp, #48] \n\ + \n\ + stp d0, d1, [sp, %[cbGPRs]] \n\ + stp d2, d3, [sp, %[cbGPRs] + 16] \n\ + stp d4, d5, [sp, %[cbGPRs] + 32] \n\ + stp d6, d7, [sp, %[cbGPRs] + 48] \n\ +\n" + /* Call the C worker. We keep x0 as is. + Set w1 to the w17 method index from the stubs. */ "\ + mov w1, w17 \n\ + mov x2, sp \n\ + add x3, sp, %[cbGPRs] \n\ + add x4, sp, %[cbGPRandFPRs] + 16 \n\ + bl " NAME_PREFIX_STR "CommonXPTCStubCWorker \n\ +" + /* Epilogue (clang does not emit the .cfi's here, so drop them too?): */ "\ + ldp x29, x30, [sp, %[cbGPRandFPRs]] \n\ + add sp, sp, %[cbGPRandFPRs] + 16 \n\ + .cfi_def_cfa sp, 0 \n\ + .cfi_restore x29 \n\ + .cfi_restore x30 \n\ + ret \n\ +" : + : [cbGPRandFPRs] "i" (NUM_ARGS_IN_GPRS * 8 + NUM_ARGS_IN_FPRS * 8) + , [cbGPRs] "i" (NUM_ARGS_IN_GPRS * 8) + :); +} + +#define STUB_ENTRY(n) \ + __attribute__((naked)) nsresult nsXPTCStubBase::Stub##n() \ + { \ + __asm__ __volatile__ ("mov w17, #" #n "\n\t" \ + "b " NAME_PREFIX_STR "CommonXPTCStub\n\t"); \ + } + +#define SENTINEL_ENTRY(n) \ + nsresult nsXPTCStubBase::Sentinel##n() \ + { \ + AssertMsgFailed(("nsXPTCStubBase::Sentinel" #n " called!\n")); \ + return NS_ERROR_NOT_IMPLEMENTED; \ + } + +/* Instantiate the stubs and sentinels */ +#include "xptcstubsdef.inc" + + + +/* + * Function templates for fetching arguments + */ + +template static inline void fetchStack(Type *pRet, uint64_t *&rpuStackArgs) +{ +#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */ + Type *pStackTmp = RT_ALIGN_PT(rpuStackArgs, sizeof(Type), Type *); + *pRet = *pStackTmp; + rpuStackArgs = (uint64_t *)(pStackTmp + 1); +#else + *pRet = (Type)*rpuStackArgs++; +#endif +} + +template static inline void fetchFpr(Type *pRet, uint64_t *pauFprArgs, unsigned &ridxFpr, uint64_t *&rpuStackArgs) +{ + if (ridxFpr < NUM_ARGS_IN_FPRS) + *pRet = (Type)pauFprArgs[ridxFpr++]; + else + fetchStack(pRet, rpuStackArgs); +} + + +template static inline void fetchGpr(Type *pRet, uint64_t *pauGprArgs, unsigned &ridxGpr, uint64_t *&rpuStackArgs) +{ + if (ridxGpr < NUM_ARGS_IN_GPRS) + *pRet = (Type)pauGprArgs[ridxGpr++]; + else + fetchStack(pRet, rpuStackArgs); +} + + +/** + * Called by CommonXPTCStub below after it dumps registers and locates + * arguments on the stack (if any). + */ +DECL_NO_INLINE(extern "C", nsresult) +CommonXPTCStubCWorker(nsXPTCStubBase *pThis, uint32_t idxMethod, uint64_t *pauGprArgs, uint64_t *pauFprArgs, uint64_t *puStackArgs) +{ + AssertReturn(pThis, NS_ERROR_UNEXPECTED); + + /* Get method information: */ + nsIInterfaceInfo *pInterfaceInfo = NULL; + nsresult hrc = pThis->GetInterfaceInfo(&pInterfaceInfo); + AssertReturn(NS_SUCCEEDED(hrc), hrc); + AssertReturn(pInterfaceInfo, NS_ERROR_UNEXPECTED); + + const nsXPTMethodInfo *pMethodInfo; + hrc = pInterfaceInfo->GetMethodInfo((PRUint16)idxMethod, &pMethodInfo); + AssertReturn(NS_SUCCEEDED(hrc), hrc); + AssertReturn(pMethodInfo, NS_ERROR_UNEXPECTED); + + /* Allocate dispatcher parameter array. */ + PRUint8 const cParams = pMethodInfo->GetParamCount(); + nsXPTCMiniVariant aParamsStatic[8]; + nsXPTCMiniVariant *paParams; + if (cParams <= RT_ELEMENTS(aParamsStatic)) + paParams = aParamsStatic; + else + { + paParams = (nsXPTCMiniVariant *)alloca(sizeof(paParams[0]) * cParams); + AssertReturn(paParams, NS_ERROR_UNEXPECTED); + } + + /* + * Populate the dispatcher parameter array. + */ + unsigned idxGprArgs = 1; /* The 'pThis' pointer (x0) is not included in cParams. */ + unsigned idxFprArgs = 0; + for (PRUint8 i = 0; i < cParams; i++) + { + const nsXPTParamInfo &rParam = pMethodInfo->GetParam(i); + if (rParam.IsOut()) + fetchGpr(&paParams[i].val.p, pauGprArgs, idxGprArgs, puStackArgs); + else + { + const nsXPTType Type = rParam.GetType(); + switch (Type) + { + case nsXPTType::T_I8: fetchGpr(&paParams[i].val.i8, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I16: fetchGpr(&paParams[i].val.i16, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I32: fetchGpr(&paParams[i].val.i32, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_I64: fetchGpr(&paParams[i].val.i64, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U8: fetchGpr(&paParams[i].val.u8, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U16: fetchGpr(&paParams[i].val.u16, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U32: fetchGpr(&paParams[i].val.u32, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_U64: fetchGpr(&paParams[i].val.u64, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_BOOL: fetchGpr(&paParams[i].val.b, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_CHAR: fetchGpr(&paParams[i].val.c, pauGprArgs, idxGprArgs, puStackArgs); break; + case nsXPTType::T_WCHAR: fetchGpr(&paParams[i].val.wc, pauGprArgs, idxGprArgs, puStackArgs); break; + + case nsXPTType::T_FLOAT: fetchFpr(&paParams[i].val.f, pauFprArgs, idxFprArgs, puStackArgs); break; + case nsXPTType::T_DOUBLE: fetchFpr(&paParams[i].val.d, pauFprArgs, idxFprArgs, puStackArgs); break; + + default: + if (!Type.IsArithmetic()) + fetchGpr(&paParams[i].val.p, pauGprArgs, idxGprArgs, puStackArgs); + else + AssertMsgFailedReturn(("%#x idxMethod=%#x\n",(unsigned)Type, idxMethod), NS_ERROR_UNEXPECTED); + break; + } + } + } + + /* + * Dispatch the method call. + */ + hrc = pThis->CallMethod((PRUint16)idxMethod, pMethodInfo, paParams); + + NS_RELEASE(pInterfaceInfo); + return hrc; + +} + +#if 0 +extern "C" nsresult CommonXPTCStubTest(uint64_t x0, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + uint64_t x5, + uint64_t x6, + uint64_t x7) +{ + uint64_t aGprs[8]; + aGprs[0] = x0; + aGprs[1] = x1; + aGprs[2] = x2; + aGprs[3] = x3; + aGprs[4] = x4; + aGprs[5] = x5; + aGprs[6] = x6; + aGprs[7] = x7; + + return CommonXPTCStubCWorker((nsXPTCStubBase *)x0, x1, aGprs, aGprs, aGprs); +} +#endif + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp new file mode 100644 index 00000000..47c09a42 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * These stubs move just move the values passed in registers onto the stack, + * so they are contiguous with values passed on the stack, and then calls + * PrepareAndDispatch() to do the dirty work. + */ + +#define STUB_ENTRY(n) \ +__asm__( \ + ".global _Stub"#n"__14nsXPTCStubBase\n\t" \ +"_Stub"#n"__14nsXPTCStubBase:\n\t" \ + "stmfd sp!, {r1, r2, r3} \n\t" \ + "mov ip, sp \n\t" \ + "stmfd sp!, {fp, ip, lr, pc} \n\t" \ + "sub fp, ip, #4 \n\t" \ + "mov r1, #"#n" \n\t" /* = methodIndex */ \ + "add r2, sp, #16 \n\t" \ + "bl _PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi \n\t" \ + "ldmea fp, {fp, sp, lr} \n\t" \ + "add sp, sp, #12 \n\t" \ + "mov pc, lr \n\t" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s new file mode 100644 index 00000000..591e88e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf32.s @@ -0,0 +1,124 @@ + +// Select C numeric constant + .radix C + .psr abi32 + .psr msb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'SharedStub' + .proc SharedStub +// manual bundling + .explicit + + .global PrepareAndDispatch +// .exclass PrepareAndDispatch, @fullyvisible + .type PrepareAndDispatch,@function + +SharedStub:: +// 9 arguments, first 8 are the input arguments of previous +// function call. The last one is methodIndex, and is passed in memory + .prologue + .save ar.pfs , r41 +// allocate 8 input args, 4 local args, and 5 output args + alloc r41 = ar.pfs, 8, 4, 5, 0 // M + .save rp, r40 + mov r40 = rp // I + nop.i 0 ;; // I + + .save ar.unat, r42 + mov r42 = ar.unat // M + .fframe 144 + add sp = -144, sp // A +// unwind table already knows gp, don't need to specify anything + add r43 = 0, gp ;; // A + +// We have possible 8 integer registers and 8 float registers that could +// be arguments. We also have a stack region from the previous +// stack frame that may hold some stack arguments. +// We need to write the integer registers to a memory region, write +// the float registers to a memory region (making sure we don't step +// on NAT while touching the registers). We also mark the memory +// address of the stack arguments. +// We then call PrepareAndDispatch() specifying the three memory +// region pointers. + + + .body + add out0 = 0, in0 // A move self ptr +// 144 bytes = 16 byte stack header + 64 byte int space + 64 byte float space +// current frame is 144 bytes, previous frame is 112 bytes +// restarg is at 144 + 112 + 16 bytes away from current sp +// (current frame + previous frame + previous previous frame header) +// methodIndex is at 144 + 16 bytes away from current sp +// (current frame + previous frame header) + add out4 = 192, sp // A restarg address + add r11 = 160, sp ;; // A address of methodIndex + + ld8 out1 = [r11] // M load methodIndex +// sp + 16 is the start of intargs + add out2 = 16, sp // A address of intargs +// the intargs take up 64 bytes, so sp + 16 + 64 is the start of floatargs + add out3 = 80, sp ;; // A address of floatargs + + add r11 = 0, out2 ;; // A + st8.spill [r11] = in1, 8 // M + add r10 = 0, out3 ;; // A + + st8.spill [r11] = in2, 8 ;; // M + st8.spill [r11] = in3, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in4, 8 ;; // M + st8.spill [r11] = in5, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in6, 8 ;; // M + st8.spill [r11] = in7 // M + fclass.nm p14,p15 = f8,@nat ;; // F + +(p14) stfd [r10] = f8, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 = f9,@nat ;; // F + +(p12) stfd [r10] = f9, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f10,@nat ;; // F + +(p14) stfd [r10] = f10, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f11,@nat ;; // F + +(p12) stfd [r10] = f11, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f12,@nat ;; // F + +(p14) stfd [r10] = f12, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f13,@nat ;; // F + +(p12) stfd [r10] = f13, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f14,@nat ;; // F + +(p14) stfd [r10] = f14, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f15,@nat ;; // F + +(p12) stfd [r10] = f15, 8 // M +(p13) add r10 = 8, r10 // A + +// branch to PrepareAndDispatch + br.call.dptk.few rp = PrepareAndDispatch ;; // B + +// epilog + mov ar.unat = r42 // M + mov ar.pfs = r41 // I + mov rp = r40 ;; // I + + add gp = 0, r43 // A + add sp = 144, sp // A + br.ret.dptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s new file mode 100644 index 00000000..177b2646 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ipf64.s @@ -0,0 +1,124 @@ + +// Select C numeric constant + .radix C + .psr abi64 + .psr lsb +// Section has executable code + .section .text, "ax","progbits" +// procedure named 'SharedStub' + .proc SharedStub +// manual bundling + .explicit + + .global PrepareAndDispatch +// .exclass PrepareAndDispatch, @fullyvisible + .type PrepareAndDispatch,@function + +SharedStub:: +// 9 arguments, first 8 are the input arguments of previous +// function call. The last one is methodIndex, and is passed in memory + .prologue + .save ar.pfs , r41 +// allocate 8 input args, 4 local args, and 5 output args + alloc r41 = ar.pfs, 8, 4, 5, 0 // M + .save rp, r40 + mov r40 = rp // I + nop.i 0 ;; // I + + .save ar.unat, r42 + mov r42 = ar.unat // M + .fframe 144 + add sp = -144, sp // A +// unwind table already knows gp, don't need to specify anything + add r43 = 0, gp ;; // A + +// We have possible 8 integer registers and 8 float registers that could +// be arguments. We also have a stack region from the previous +// stack frame that may hold some stack arguments. +// We need to write the integer registers to a memory region, write +// the float registers to a memory region (making sure we don't step +// on NAT while touching the registers). We also mark the memory +// address of the stack arguments. +// We then call PrepareAndDispatch() specifying the three memory +// region pointers. + + + .body + add out0 = 0, in0 // A move self ptr +// 144 bytes = 16 byte stack header + 64 byte int space + 64 byte float space +// current frame is 144 bytes, previous frame is 112 bytes +// restarg is at 144 + 112 + 16 bytes away from current sp +// (current frame + previous frame + previous previous frame header) +// methodIndex is at 144 + 16 bytes away from current sp +// (current frame + previous frame header) + add out4 = 192, sp // A restarg address + add r11 = 160, sp ;; // A address of methodIndex + + ld8 out1 = [r11] // M load methodIndex +// sp + 16 is the start of intargs + add out2 = 16, sp // A address of intargs +// the intargs take up 64 bytes, so sp + 16 + 64 is the start of floatargs + add out3 = 80, sp ;; // A address of floatargs + + add r11 = 0, out2 ;; // A + st8.spill [r11] = in1, 8 // M + add r10 = 0, out3 ;; // A + + st8.spill [r11] = in2, 8 ;; // M + st8.spill [r11] = in3, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in4, 8 ;; // M + st8.spill [r11] = in5, 8 // M + nop.i 0 ;; // I + + st8.spill [r11] = in6, 8 ;; // M + st8.spill [r11] = in7 // M + fclass.nm p14,p15 = f8,@nat ;; // F + +(p14) stfd [r10] = f8, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 = f9,@nat ;; // F + +(p12) stfd [r10] = f9, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f10,@nat ;; // F + +(p14) stfd [r10] = f10, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f11,@nat ;; // F + +(p12) stfd [r10] = f11, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f12,@nat ;; // F + +(p14) stfd [r10] = f12, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f13,@nat ;; // F + +(p12) stfd [r10] = f13, 8 // M +(p13) add r10 = 8, r10 // A + fclass.nm p14,p15 =f14,@nat ;; // F + +(p14) stfd [r10] = f14, 8 // M +(p15) add r10 = 8, r10 // A + fclass.nm p12,p13 =f15,@nat ;; // F + +(p12) stfd [r10] = f15, 8 // M +(p13) add r10 = 8, r10 // A + +// branch to PrepareAndDispatch + br.call.dptk.few rp = PrepareAndDispatch ;; // B + +// epilog + mov ar.unat = r42 // M + mov ar.pfs = r41 // I + mov rp = r40 ;; // I + + add gp = 0, r43 // A + add sp = 144, sp // A + br.ret.dptk.few rp ;; // B + + .endp + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s new file mode 100644 index 00000000..4ca1e542 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_irix.s @@ -0,0 +1,97 @@ + +#include +#include + + .text + .globl PrepareAndDispatch + +LOCALSZ=16 +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +A1OFF=FRAMESZ-(9*SZREG) +A2OFF=FRAMESZ-(8*SZREG) +A3OFF=FRAMESZ-(7*SZREG) +A4OFF=FRAMESZ-(6*SZREG) +A5OFF=FRAMESZ-(5*SZREG) +A6OFF=FRAMESZ-(4*SZREG) +A7OFF=FRAMESZ-(3*SZREG) +GPOFF=FRAMESZ-(2*SZREG) +RAOFF=FRAMESZ-(1*SZREG) + +F13OFF=FRAMESZ-(16*SZREG) +F14OFF=FRAMESZ-(15*SZREG) +F15OFF=FRAMESZ-(14*SZREG) +F16OFF=FRAMESZ-(13*SZREG) +F17OFF=FRAMESZ-(12*SZREG) +F18OFF=FRAMESZ-(11*SZREG) +F19OFF=FRAMESZ-(10*SZREG) + +#define SENTINEL_ENTRY(nn) /* defined in cpp file, not here */ + +#ifdef __GNUC__ +#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBase) +#else +#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBaseGv) +#endif + +#define MAKE_STUB(nn, name) \ +NESTED(name, FRAMESZ, ra); \ + SETUP_GP; \ + PTR_SUBU sp, FRAMESZ; \ + SETUP_GP64(GPOFF, name); \ + SAVE_GP(GPOFF); \ + li t0, nn; \ + b sharedstub; \ +.end name; \ + +#include "xptcstubsdef.inc" + + .globl sharedstub + .ent sharedstub +sharedstub: + + REG_S a1, A1OFF(sp) + REG_S a2, A2OFF(sp) + REG_S a3, A3OFF(sp) + REG_S a4, A4OFF(sp) + REG_S a5, A5OFF(sp) + REG_S a6, A6OFF(sp) + REG_S a7, A7OFF(sp) + REG_S ra, RAOFF(sp) + + s.d $f13, F13OFF(sp) + s.d $f14, F14OFF(sp) + s.d $f15, F15OFF(sp) + s.d $f16, F16OFF(sp) + s.d $f17, F17OFF(sp) + s.d $f18, F18OFF(sp) + s.d $f19, F19OFF(sp) + + # t0 is methodIndex + move a1, t0 + + # a2 is stack address where extra function params + # are stored that do not fit in registers + move a2, sp + addi a2, FRAMESZ + + # a3 is stack address of a1..a7 + move a3, sp + addi a3, A1OFF + + # a4 is stack address of f13..f19 + move a4, sp + addi a4, F13OFF + + # PrepareAndDispatch(that, methodIndex, args, gprArgs, fpArgs) + # a0 a1 a2 a3 a4 + # + jal PrepareAndDispatch + + REG_L ra, RAOFF(sp) + REG_L gp, GPOFF(sp) + + PTR_ADDU sp, FRAMESZ + j ra + +.end sharedstub diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 new file mode 100644 index 00000000..f327adfb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_mips.s.m4 @@ -0,0 +1,109 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 code is for MIPS using the O32 ABI. */ + +#include +#include + + .text + .globl PrepareAndDispatch + +NARGSAVE=4 # extra space for the callee to use. gccism + # we can put our a0-a3 in our callers space. +LOCALSZ=2 # gp, ra +FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK + +define(STUB_NAME, `Stub'$1`__14nsXPTCStubBase') + +define(STUB_ENTRY, +` .globl 'STUB_NAME($1)` + .align 2 + .type 'STUB_NAME($1)`,@function + .ent 'STUB_NAME($1)`, 0 +'STUB_NAME($1)`: + .frame sp, FRAMESZ, ra + .set noreorder + .cpload t9 + .set reorder + subu sp, FRAMESZ + .cprestore 16 + li t0, '$1` + b sharedstub +.end 'STUB_NAME($1)` + +') + +define(SENTINEL_ENTRY, `') + +include(xptcstubsdef.inc) + + .globl sharedstub + .ent sharedstub +sharedstub: + + REG_S ra, 20(sp) + + REG_S a0, 24(sp) + REG_S a1, 28(sp) + REG_S a2, 32(sp) + REG_S a3, 36(sp) + + # t0 is methodIndex + move a1, t0 + + # put the start of a1, a2, a3, and stack + move a2, sp + addi a2, 24 # have a2 point to sp + 24 (where a0 is) + + # PrepareAndDispatch(that, methodIndex, args) + # a0 a1 a2 + # + jal PrepareAndDispatch + + REG_L ra, 20(sp) + REG_L a1, 28(sp) + REG_L a2, 32(sp) + + addu sp, FRAMESZ + j ra + +.end sharedstub diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s new file mode 100644 index 00000000..9f04d4c4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_openvms_alpha.s @@ -0,0 +1,115 @@ +;* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +;* +;* The contents of this file are subject to the Netscape 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/NPL/ +;* +;* 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 mozilla.org code. +;* +;* The Initial Developer of the Original Code is Netscape +;* Communications Corporation. Portions created by Netscape are +;* Copyright (C) 1999 Netscape Communications Corporation. All +;* Rights Reserved. +;* +;* Contributor(s): +;*/ + +; Implement shared vtbl methods. + + .title "STUBS" "Stub Code" + + MBIT = "__14nsXPTCStubBasexv" ; this is the mangled part of the name + +; The layout of the linkage section is important. First comes +; PrepareAndDispatch, and then the Procedure Descriptors for the stubs. Each +; is known to be 16 bytes long, and we use this fact to be able to locate the +; PrepareAndDispatch linkage pair from any of the stubs. + + .PSECT $LINK$, OCTA, NOPIC, CON, REL, LCL, NOSHR, NOEXE, RD, NOWRT + .LINKAGE_PAIR PrepareAndDispatch + LINKOFF = 16 ; first stub lp will be 16 bytes away + +; STUB_ENTRY createa a routine nsXPTCStubBase::Stub() where n is the +; argument passed in to STUB_ENTRY. It puts its stub number into R1 and then +; jumps into SharedStub. It does it this way because we don't want to mess +; up the arguments that may be on the stack. In order that we can find +; our way around the linkage section, we subtract our offset from the +; start of the linkage section (LINKOFF) from our own PV, thus giving +; us the PV os the first entry in the linkage section (this should be +; PrepareAndDispatch); + + .macro STUB_ENTRY n + $routine Stub'n%MBIT%, kind=null + mov LINKOFF, r1 ; distance from lp for PrepareAndDispatch + subq r27,r1,r27 ; subtract it from address of our proc desc + mov n,r1 ; stub number is passed in r1 + br SharedStub ; off to common code + $end_routine + LINKOFF = LINKOFF + 16 ; we just put 16 bytes into linkage section + .endm STUB_ENTRY + +; SENTINEL_ENTRY is in the C++ module. We need to define a empty macro +; here to keep the assembler happy. + .macro SENTINEL_ENTRY n + .endm SENTINEL_ENTRY + + .PSECT $CODE$, OCTA, PIC, CON, REL, LCL, SHR, EXE, NORD, NOWRT + +; +; SharedStub() +; Collects arguments and calls PrepareAndDispatch. +; +; r1 - The "methodIndex" +; r27 - points to the first entry in the linkage section, which by design +; is the linkage pair for PrepareAndDispatch. +; +; Arguments are passed in a non-standard way so that we don't disturb the +; original arguments that were passed in to the stub. Since some args (if +; there were more than 6) will already be on the stack, the stub had to not +; only preserve R16-R21, but also preserve the stack too. +; + +SharedStub:: + subq sp,96,sp ; get some stack space for the args and saves + stq r26,0(sp) ; save r26 (the return address) + + ; + ; Store arguments passed via registers to the stack. + ; Floating point registers are stored as doubles and converted + ; to floats in PrepareAndDispatch if necessary. + ; + stt f17,16(sp) ; floating point registers + stt f18,24(sp) + stt f19,32(sp) + stt f20,40(sp) + stt f21,48(sp) + stq r17,56(sp) ; integer registers + stq r18,64(sp) + stq r19,72(sp) + stq r20,80(sp) + stq r21,88(sp) + + ; + ; Call PrepareAndDispatch function. + ; + mov r1,r17 ; pass "methodIndex" + addq sp,16,r18 ; pass "args" + mov 3,r25 ; number of args into AI + + LDQ R26, 0(R27) ; get entry point address from linkage pair + LDQ R27, 8(R27) ; get procedure descriptor address from lp + JSR R26, R26 + + ldq r26, 0(sp) ; restore return address + addq sp,96,sp ; return stack space + ret r26 ; and we're outta here + + .include "xptcstubsdef_asm.vms" + + .end diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s new file mode 100644 index 00000000..3bef9b1b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_osf1_alpha.s @@ -0,0 +1,75 @@ + .text + .align 5 + .globl SharedStub + .ent SharedStub +SharedStub: + .frame $30, 96, $26, 0 + .mask 0x4000000,-96 + ldgp $29,0($27) +SharedStubXv: + subq $30,96,$30 + stq $26,0($30) + .prologue 1 + stt $f17,16($30) + stt $f18,24($30) + stt $f19,32($30) + stt $f20,40($30) + stt $f21,48($30) + stq $17,56($30) + stq $18,64($30) + stq $19,72($30) + stq $20,80($30) + stq $21,88($30) + bis $1,$1,$17 + addq $30,16,$18 + bsr $26,PrepareAndDispatch + ldq $26,0($30) + addq $30,96,$30 + ret $31,($26),1 + .end SharedStub + +/* + The C preprocessor doesn't handle # and ## if run with -std or -std0. + + If -std then __STDC__ is 0 [default] (K&R behavior) + If -std0 then __STDC__ is undefined (K&R behavior) + If -std1 then __STDC__ is 1 (ANSI preprocessor) +*/ + +#if __STDC__ +#define STUB_ENTRY(n) ;\ + .text ;\ + .align 5 ;\ + .globl Stub##n##__14nsXPTCStubBase ;\ + .globl Stub##n##__14nsXPTCStubBaseXv ;\ + .ent Stub##n##__14nsXPTCStubBase ;\ +Stub##n##__14nsXPTCStubBase: ;\ + .frame $30,0,$26,0 ;\ + ldgp $29,0($27) ;\ + .prologue 1 ;\ +Stub##n##__14nsXPTCStubBaseXv: ;\ + lda $1,n ;\ + br $31,SharedStubXv ;\ + .end Stub##n##__14nsXPTCStubBase \ + +#else +#define STUB_ENTRY(n) ;\ + .text ;\ + .align 5 ;\ + .globl Stub/**/n/**/__14nsXPTCStubBase ;\ + .globl Stub/**/n/**/__14nsXPTCStubBaseXv ;\ + .ent Stub/**/n/**/__14nsXPTCStubBase ;\ +Stub/**/n/**/__14nsXPTCStubBase: ;\ + .frame $30,0,$26,0 ;\ + ldgp $29,0($27) ;\ + .prologue 1 ;\ +Stub/**/n/**/__14nsXPTCStubBaseXv: ;\ + lda $1,n ;\ + br $31,SharedStubXv ;\ + .end Stub/**/n/**/__14nsXPTCStubBase \ + +#endif + +#define SENTINEL_ENTRY(n) \ + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s new file mode 100644 index 00000000..9e86848f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_pa32.s @@ -0,0 +1,68 @@ + .LEVEL 1.1 + +curframesz .EQU 128 +; SharedStub has stack size of 128 bytes + +lastframesz .EQU 64 +; the StubN C++ function has a small stack size of 64 bytes + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 +SharedStub + .PROC + .CALLINFO CALLER,FRAME=80,SAVE_RP,ARGS_SAVED + + .ENTRY + STW %rp,-20(%sp) + LDO 128(%sp),%sp + + STW %r19,-32(%r30) + STW %r26,-36-curframesz(%r30) ; save arg0 in previous frame + + LDO -80(%r30),%r28 + FSTD,MA %fr5,8(%r28) ; save darg0 + FSTD,MA %fr7,8(%r28) ; save darg1 + FSTW,MA %fr4L,4(%r28) ; save farg0 + FSTW,MA %fr5L,4(%r28) ; save farg1 + FSTW,MA %fr6L,4(%r28) ; save farg2 + FSTW,MA %fr7L,4(%r28) ; save farg3 + + ; Former value of register 26 is already properly saved by StubN, + ; but register 25-23 are not because of the arguments mismatch + STW %r25,-40-curframesz-lastframesz(%r30) ; save r25 + STW %r24,-44-curframesz-lastframesz(%r30) ; save r24 + STW %r23,-48-curframesz-lastframesz(%r30) ; save r23 + COPY %r26,%r25 ; method index is arg1 + LDW -36-curframesz-lastframesz(%r30),%r26 ; self is arg0 + LDO -40-curframesz-lastframesz(%r30),%r24 ; normal args is arg2 + LDO -80(%r30),%r23 ; floating args is arg3 + + BL .+8,%r2 + ADDIL L'PrepareAndDispatch-$PIC_pcrel$0+4,%r2 + LDO R'PrepareAndDispatch-$PIC_pcrel$1+8(%r1),%r1 +$PIC_pcrel$0 + LDSID (%r1),%r31 +$PIC_pcrel$1 + MTSP %r31,%sr0 + .CALL ARGW0=GR,ARGW1=GR,ARGW2=GR,ARGW3=GR,RTNVAL=GR +;in=23-26;out=28; + BLE 0(%sr0,%r1) + COPY %r31,%r2 + + LDW -32(%r30),%r19 + + LDW -148(%sp),%rp + BVE (%rp) + .EXIT + LDO -128(%sp),%sp + + + .PROCEND ;in=26;out=28; + + .ALIGN 8 + .SPACE $TEXT$ + .SUBSPA $CODE$ + .IMPORT PrepareAndDispatch,CODE + .EXPORT SharedStub,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR,LONG_RETURN + .END + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s new file mode 100644 index 00000000..667da705 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s @@ -0,0 +1,117 @@ + # + # -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + # + # The contents of this file are subject to the Netscape 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/NPL/ + # + # 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 mozilla.org code. + # + # The Initial Developer of the Original Code is Netscape + # Communications Corporation. Portions created by Netscape are + # Copyright (C) 1999 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): + # + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.SharedStub{TC},"SharedStub" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .SharedStub + .globl SharedStub{DS} + .extern .PrepareAndDispatch + + +#jimbo csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# +#jimbo import .PrepareAndDispatch + +.SharedStub: + mflr r0 + stw r0,8(sp) + + mr r12,r3 # Move methodIndex into r12 for LATER + lwz r3,104(sp) # Get the 'original' r3 + + stwu sp,-176(sp) # room for linkage (24), fprData (104), gprData(28) + # outgoing params to PrepareAndDispatch (20) + + stw r4,44(sp) + stw r5,48(sp) + stw r6,52(sp) + stw r7,56(sp) + stw r8,60(sp) + stw r9,64(sp) + stw r10,68(sp) + stfd f1,72(sp) + stfd f2,80(sp) + stfd f3,88(sp) + stfd f4,96(sp) + stfd f5,104(sp) + stfd f6,112(sp) + stfd f7,120(sp) + stfd f8,128(sp) + stfd f9,136(sp) + stfd f10,144(sp) + stfd f11,152(sp) + stfd f12,156(sp) + stfd f13,164(sp) + + addi r6,sp,44 # gprData + addi r7,sp,72 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector (it is now LATER) + addi r5,sp,312 # pointer to callers args area, beyond r3-r10 mapped range + + bl .PrepareAndDispatch + nop + + lwz r0,184(sp) + addi sp,sp,176 + mtlr r0 + blr + +# .data section + + .toc # 0x00000038 +T.18.SharedStub: + .tc H.18.SharedStub{TC},SharedStub{DS} + + .csect SharedStub{DS} + .long .SharedStub # "\0\0\0\0" + .long TOC{TC0} # "\0\0\0008" + .long 0x00000000 # "\0\0\0\0" +# End csect SharedStub{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s new file mode 100644 index 00000000..94245d5e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s @@ -0,0 +1,137 @@ +# ***** BEGIN LICENSE BLOCK ***** +# +# Version: MPL 1.1/LGPL 2.1/GPL 2.0 +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is IBM Corporation. +# Portions created by IBM are +# Copyright (C) 2002, International Business Machines Corporation. +# All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 LGPL or the GPL. 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 ***** + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + + .rename H.10.NO_SYMBOL{PR},"" + .rename H.18.SharedStub{TC},"SharedStub" + + +# .text section + + .csect H.10.NO_SYMBOL{PR} + .globl .SharedStub + .globl SharedStub{DS} + .extern .PrepareAndDispatch + + +#jimbo csect CODE{PR} +# +# on entry SharedStub has the method selector in r12, the rest of the original +# parameters are in r3 thru r10 and f1 thru f13 +# +#jimbo import .PrepareAndDispatch + +.SharedStub: + mflr r0 + std r0,16(sp) + + mr r12,r3 # Move methodIndex into r12 for LATER + ld r3,176(sp) # Get the 'original' r3 (load 'this' into r3) + + stdu sp,-248(sp) # room for linkage (24*2), fprData (104), + # gprData(28*2), outgoing params to + # PrepareAndDispatch (40) + + std r4,88(sp) # link area (48) + PrepareAndDispatch parms (40) + std r5,96(sp) + std r6,104(sp) + std r7,112(sp) + std r8,120(sp) + std r9,128(sp) + std r10,136(sp) + stfd f1,144(sp) + stfd f2,152(sp) + stfd f3,160(sp) + stfd f4,168(sp) + stfd f5,176(sp) + stfd f6,184(sp) + stfd f7,192(sp) + stfd f8,200(sp) + stfd f9,208(sp) + stfd f10,216(sp) + stfd f11,224(sp) + stfd f12,232(sp) + stfd f13,240(sp) + + addi r6,sp,88 # gprData + addi r7,sp,144 # fprData + # r3 has the 'self' pointer already + mr r4,r12 # methodIndex selector (it is now LATER) + addi r5,sp,488 # pointer to callers args area, beyond r3-r10 + # mapped range + # 32bit: 176 (stack-distance) 64bit: 248 (stack-distance) + # 104 (this ptr offset) 176 + # 32 (8*4 for r3-r10) 64 (8*8) + # --- --- + # 312 488 + + bl .PrepareAndDispatch + nop + + ld r0,264(sp) # 248+16 + addi sp,sp,248 + mtlr r0 + blr + +# .data section + + .toc # 0x00000038 +T.18.SharedStub: + .tc H.18.SharedStub{TC},SharedStub{DS} + + .csect SharedStub{DS} + .llong .SharedStub # "\0\0\0\0" + .llong TOC{TC0} # "\0\0\0008" + .llong 0x00000000 # "\0\0\0\0" +# End csect SharedStub{DS} + +# .bss section diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 new file mode 100644 index 00000000..60dbd7c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_darwin.s.m4 @@ -0,0 +1,126 @@ +/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999-2002 + * 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 ***** */ + + .text + .globl _SharedStub + +define(STUB_MANGLED_ENTRY, +` .globl '$2` + .align 2 +'$2`: + addi r12, 0, '$1` + b _SharedStub +') + +define(STUB_ENTRY, +`#ifdef HAVE_GCC3_ABI + .if '$1` < 10 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase5Stub'$1`Ev') + .elseif '$1` < 100 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase6Stub'$1`Ev') + .elseif '$1` < 1000 +STUB_MANGLED_ENTRY('$1`, `__ZN14nsXPTCStubBase7Stub'$1`Ev') + .else + .err "Stub'$1` >= 1000 not yet supported." + .endif +#else /* !defined(HAVE_GCC3_ABI) */ +STUB_MANGLED_ENTRY('$1`, `_Stub'$1`__14nsXPTCStubBase') +#endif /* !defined(HAVE_GCC3_ABI) */ +') + +define(SENTINEL_ENTRY, `') + +include(xptcstubsdef.inc) + +_SharedStub: + mflr r0 + stw r0,8(r1) + + stwu r1,-176(r1) + + stw r4,44(r1) + stw r5,48(r1) + stw r6,52(r1) + stw r7,56(r1) + stw r8,60(r1) + stw r9,64(r1) + stw r10,68(r1) + stfd f1,72(r1) + stfd f2,80(r1) + stfd f3,88(r1) + stfd f4,96(r1) + stfd f5,104(r1) + stfd f6,112(r1) + stfd f7,120(r1) + stfd f8,128(r1) + stfd f9,136(r1) + stfd f10,144(r1) + stfd f11,152(r1) + stfd f12,156(r1) + stfd f13,164(r1) + + addi r6,r1,44 + addi r7,r1,72 + + mr r4,r12 + addi r5,r1,232 + + bl L_PrepareAndDispatch$stub + nop + + lwz r0,184(r1) + addi r1,r1,176 + mtlr r0 + blr + +.picsymbol_stub +L_PrepareAndDispatch$stub: + .indirect_symbol _PrepareAndDispatch + mflr r0 + bcl 20,31,L1$pb +L1$pb: + mflr r11 + addis r11,r11,ha16(L1$lz-L1$pb) + mtlr r0 + lwz r12,lo16(L1$lz-L1$pb)(r11) + mtctr r12 + addi r11,r11,lo16(L1$lz-L1$pb) + bctr +.lazy_symbol_pointer +L1$lz: + .indirect_symbol _PrepareAndDispatch + .long dyld_stub_binding_helper diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s new file mode 100644 index 00000000..fc85bdb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_linux.s @@ -0,0 +1,89 @@ +// -*- Mode: Asm -*- +// +// The contents of this file are subject to the Netscape 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/NPL/ +// +// 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 mozilla.org code. +// +// The Initial Developer of the Original Code is Netscape +// Communications Corporation. Portions created by Netscape are +// Copyright (C) 1999 Netscape Communications Corporation. All +// Rights Reserved. +// +// Contributor(s): +// Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +// beard@netscape.com (Patrick Beard) +// waterson@netscape.com (Chris Waterson) +// + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl SharedStub + .type SharedStub,@function + +SharedStub: + stwu sp,-112(sp) // room for + // linkage (8), + // gprData (32), + // fprData (64), + // stack alignment(8) + mflr r0 + stw r0,116(sp) // save LR backchain + + stw r4,12(sp) // save GP registers + stw r5,16(sp) // (n.b. that we don't save r3 + stw r6,20(sp) // because PrepareAndDispatch() is savvy) + stw r7,24(sp) + stw r8,28(sp) + stw r9,32(sp) + stw r10,36(sp) + + stfd f1,40(sp) // save FP registers + stfd f2,48(sp) + stfd f3,56(sp) + stfd f4,64(sp) + stfd f5,72(sp) + stfd f6,80(sp) + stfd f7,88(sp) + stfd f8,96(sp) + + // r3 has the 'self' pointer already + + mr r4,r11 // r4 <= methodIndex selector, passed + // via r11 in the nsXPTCStubBase::StubXX() call + + addi r5,sp,120 // r5 <= pointer to callers args area, + // beyond r3-r10/f1-f8 mapped range + + addi r6,sp,8 // r6 <= gprData + addi r7,sp,40 // r7 <= fprData + + bl PrepareAndDispatch@local // Go! + + lwz r0,116(sp) // restore LR + mtlr r0 + la sp,112(sp) // clean up the stack + blr + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s new file mode 100644 index 00000000..f94aac4f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_netbsd.s @@ -0,0 +1,89 @@ +# -*- Mode: Asm -*- +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1999 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Franz.Sirl-kernel@lauterbach.com (Franz Sirl) +# beard@netscape.com (Patrick Beard) +# waterson@netscape.com (Chris Waterson) +# + +.set r0,0; .set sp,1; .set RTOC,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31 +.set f0,0; .set f1,1; .set f2,2; .set f3,3; .set f4,4 +.set f5,5; .set f6,6; .set f7,7; .set f8,8; .set f9,9 +.set f10,10; .set f11,11; .set f12,12; .set f13,13; .set f14,14 +.set f15,15; .set f16,16; .set f17,17; .set f18,18; .set f19,19 +.set f20,20; .set f21,21; .set f22,22; .set f23,23; .set f24,24 +.set f25,25; .set f26,26; .set f27,27; .set f28,28; .set f29,29 +.set f30,30; .set f31,31 + + .section ".text" + .align 2 + .globl SharedStub + .type SharedStub,@function + +SharedStub: + stwu sp,-112(sp) # room for + # linkage (8), + # gprData (32), + # fprData (64), + # stack alignment(8) + mflr r0 + stw r0,116(sp) # save LR backchain + + stw r4,12(sp) # save GP registers + stw r5,16(sp) # (n.b. that we don't save r3 + stw r6,20(sp) # because PrepareAndDispatch() is savvy) + stw r7,24(sp) + stw r8,28(sp) + stw r9,32(sp) + stw r10,36(sp) + + stfd f1,40(sp) # save FP registers + stfd f2,48(sp) + stfd f3,56(sp) + stfd f4,64(sp) + stfd f5,72(sp) + stfd f6,80(sp) + stfd f7,88(sp) + stfd f8,96(sp) + + # r3 has the 'self' pointer already + + mr r4,r11 # r4 <= methodIndex selector, passed + # via r11 in the nsXPTCStubBase::StubXX() call + + addi r5,sp,120 # r5 <= pointer to callers args area, + # beyond r3-r10/f1-f8 mapped range + + addi r6,sp,8 # r6 <= gprData + addi r7,sp,40 # r7 <= fprData + + bl PrepareAndDispatch@local # Go! + + lwz r0,116(sp) # restore LR + mtlr r0 + la sp,112(sp) # clean up the stack + blr + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s new file mode 100644 index 00000000..4a8a4698 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_netbsd.s @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 72, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + st %i1, [%fp + 72] + st %i2, [%fp + 76] + st %i3, [%fp + 80] + st %i4, [%fp + 84] + st %i5, [%fp + 88] +! now we can build our own stack frame + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s new file mode 100644 index 00000000..4a8a4698 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparc_solaris.s @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 72, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + st %i1, [%fp + 72] + st %i2, [%fp + 76] + st %i3, [%fp + 80] + st %i4, [%fp + 84] + st %i5, [%fp + 88] +! now we can build our own stack frame + save %sp,-(64 + 32),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 32 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s new file mode 100644 index 00000000..e3bbcf8b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_sparcv9_solaris.s @@ -0,0 +1,67 @@ +/* -*- Mode: asm; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + */ + + .global SharedStub + +/* + in the frame for the function that called SharedStub are the + rest of the parameters we need + +*/ + +SharedStub: +! we don't create a new frame yet, but work within the frame of the calling +! function to give ourselves the other parameters we want + + mov %o0, %o1 ! shuffle the index up to 2nd place + mov %i0, %o0 ! the original 'this' + add %fp, 0x7ff + 136, %o2 ! previous stack top adjusted to the first argument slot (beyond 'this') + +! save off the original incoming parameters that arrived in +! registers, the ABI guarantees the space for us to do this + stx %i1, [%fp + 0x7ff + 136] + stx %i2, [%fp + 0x7ff + 144] + stx %i3, [%fp + 0x7ff + 152] + stx %i4, [%fp + 0x7ff + 160] + stx %i5, [%fp + 0x7ff + 168] +! now we can build our own stack frame + save %sp,-(128 + 64),%sp ! room for the register window and + ! struct pointer, rounded up to 0 % 64 +! our function now appears to have been called +! as SharedStub(nsISupports* that, PRUint32 index, PRUint32* args) +! so we can just copy these through + + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + call PrepareAndDispatch + nop + mov %o0,%i0 ! propagate return value + b .LL1 + nop +.LL1: + ret + restore + + .size SharedStub, .-SharedStub + .type SharedStub, #function diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp new file mode 100644 index 00000000..351ee512 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#ifdef __GNUC__ /* Gnu Compiler. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +#include "xptc_gcc_x86_unix.h" + +extern "C" { +static nsresult ATTRIBUTE_USED +__attribute__ ((regparm (3))) +PrepareAndDispatch(uint32 methodIndex, nsXPTCStubBase* self, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} +} // extern "C" + +// NOTE! See xptc_gcc_x86_unix.h for the reason this function exists. +#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)) +PRUint32 +xptc_PrepareAndDispatch_keeper (void) +{ + PRUint32 dummy1; + nsresult ATTRIBUTE_USED __attribute__ ((regparm (3))) (*dummy2) + (uint32, nsXPTCStubBase *, PRUint32*) = PrepareAndDispatch; +// dummy2 references PrepareAndDispatch, now "use" it + __asm__ __volatile__ ( + "" + : "=&a" (dummy1) + : "g" (dummy2) + ); + return dummy1 & 0xF0F00000; +} +#endif + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// gcc3 mangling tends to insert the length of the method name +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); +#else +#define STUB_ENTRY(n) \ +asm(".text\n\t" \ + ".align 2\n\t" \ + ".globl " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase\n\t" \ + ".type " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase,@function\n" \ + SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase:\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \ + ".size " SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase,.-" SYMBOL_UNDERSCORE "Stub" #n "__14nsXPTCStubBase"); +#endif + +// static nsresult SharedStub(PRUint32 methodIndex) __attribute__((regparm(1))) +asm(".text\n\t" + ".align 2\n\t" + ".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t" + SYMBOL_UNDERSCORE "SharedStub:\n\t" + "leal 0x08(%esp), %ecx\n\t" + "movl 0x04(%esp), %edx\n\t" + "jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t" + ".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp new file mode 100644 index 00000000..844f55dd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp @@ -0,0 +1,185 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include + +// "This code is for IA64 only" + +/* Implement shared vtbl methods. */ + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + nsresult result = NS_ERROR_FAILURE; + uint64_t* iargs = intargs; + uint64_t* fargs = floatargs; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i) + { + int isfloat = 0; + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + dp->val.p = (void*) *iargs; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) iargs; + dp->val.p = (void*) (*(adr+1)); +#endif + } + else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *(iargs); break; + case nsXPTType::T_I16 : dp->val.i16 = *(iargs); break; + case nsXPTType::T_I32 : dp->val.i32 = *(iargs); break; + case nsXPTType::T_I64 : dp->val.i64 = *(iargs); break; + case nsXPTType::T_U8 : dp->val.u8 = *(iargs); break; + case nsXPTType::T_U16 : dp->val.u16 = *(iargs); break; + case nsXPTType::T_U32 : dp->val.u32 = *(iargs); break; + case nsXPTType::T_U64 : dp->val.u64 = *(iargs); break; + case nsXPTType::T_FLOAT : + isfloat = 1; + if (i < 7) + dp->val.f = (float) *((double*) fargs); /* register */ + else + dp->val.u32 = *(fargs); /* memory */ + break; + case nsXPTType::T_DOUBLE : + isfloat = 1; + dp->val.u64 = *(fargs); + break; + case nsXPTType::T_BOOL : dp->val.b = *(iargs); break; + case nsXPTType::T_CHAR : dp->val.c = *(iargs); break; + case nsXPTType::T_WCHAR : dp->val.wc = *(iargs); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + if (i < 7) + { + /* we are parsing register arguments */ + if (i == 6) + { + // run out of register arguments, move on to memory arguments + iargs = restargs; + fargs = restargs; + } + else + { + ++iargs; // advance one integer register slot + if (isfloat) ++fargs; // advance float register slot if isfloat + } + } + else + { + /* we are parsing memory arguments */ + ++iargs; + ++fargs; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(PRUint64,PRUint64,PRUint64,PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); + +/* Variable a0-a7 were put there so we can have access to the 8 input + registers on Stubxyz entry */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n(PRUint64 a1, \ +PRUint64 a2,PRUint64 a3,PRUint64 a4,PRUint64 a5,PRUint64 a6,PRUint64 a7) \ +{ uint64_t a0 = (uint64_t) this; \ + return SharedStub(a0,a1,a2,a3,a4,a5,a6,a7,(PRUint64) n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp new file mode 100644 index 00000000..6a11f692 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp @@ -0,0 +1,186 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#include +#include +#include + +// "This code is for IA64 only" + +/* Implement shared vtbl methods. */ + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + nsresult result = NS_ERROR_FAILURE; + uint64_t* iargs = intargs; + uint64_t* fargs = floatargs; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i) + { + int isfloat = 0; + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { +#ifdef __LP64__ + /* 64 bit pointer mode */ + dp->val.p = (void*) *iargs; +#else + /* 32 bit pointer mode */ + uint32_t* adr = (uint32_t*) iargs; + dp->val.p = (void*) (*(adr+1)); +#endif + } + else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *(iargs); break; + case nsXPTType::T_I16 : dp->val.i16 = *(iargs); break; + case nsXPTType::T_I32 : dp->val.i32 = *(iargs); break; + case nsXPTType::T_I64 : dp->val.i64 = *(iargs); break; + case nsXPTType::T_U8 : dp->val.u8 = *(iargs); break; + case nsXPTType::T_U16 : dp->val.u16 = *(iargs); break; + case nsXPTType::T_U32 : dp->val.u32 = *(iargs); break; + case nsXPTType::T_U64 : dp->val.u64 = *(iargs); break; + case nsXPTType::T_FLOAT : + isfloat = 1; + if (i < 7) + dp->val.f = (float) *((double*) fargs); /* register */ + else + dp->val.u32 = *(fargs); /* memory */ + break; + case nsXPTType::T_DOUBLE : + isfloat = 1; + dp->val.u64 = *(fargs); + break; + case nsXPTType::T_BOOL : dp->val.b = *(iargs); break; + case nsXPTType::T_CHAR : dp->val.c = *(iargs); break; + case nsXPTType::T_WCHAR : dp->val.wc = *(iargs); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + if (i < 7) + { + /* we are parsing register arguments */ + if (i == 6) + { + // run out of register arguments, move on to memory arguments + iargs = restargs; + fargs = restargs; + } + else + { + ++iargs; // advance one integer register slot + if (isfloat) ++fargs; // advance float register slot if isfloat + } + } + else + { + /* we are parsing memory arguments */ + ++iargs; + ++fargs; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(PRUint64,PRUint64,PRUint64,PRUint64, + PRUint64,PRUint64,PRUint64,PRUint64,PRUint64); + +/* Variable a0-a7 were put there so we can have access to the 8 input + registers on Stubxyz entry */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n(PRUint64 a1, \ +PRUint64 a2,PRUint64 a3,PRUint64 a4,PRUint64 a5,PRUint64 a6,PRUint64 a7) \ +{ uint64_t a0 = (uint64_t) this; \ + return SharedStub(a0,a1,a2,a3,a4,a5,a6,a7,(PRUint64) n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp new file mode 100644 index 00000000..556b5bbe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_irix.cpp @@ -0,0 +1,226 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +#if defined(IRIX) + +#if (_MIPS_SIM != _ABIN32) +#error "This code is for IRIX N32 only" +#endif + +/* + * This is for IRIX N32 ABI + * + * When we're called, the "gp" registers are stored in gprData and + * the "fp" registers are stored in fprData. There are 8 regs + * available which coorespond to the first 7 parameters of the + * function and the "this" pointer. If there are additional parms, + * they are stored on the stack at address "args". + * + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint64* args, + PRUint64 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 +#define PARAM_FPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*)gprData[iCount++]; + else + dp->val.p = (void*)*ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8: + if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8)gprData[iCount++]; + else + dp->val.i8 = (PRInt8)*ap++; + break; + + case nsXPTType::T_I16: + if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16)gprData[iCount++]; + else + dp->val.i16 = (PRInt16)*ap++; + break; + + case nsXPTType::T_I32: + if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32)gprData[iCount++]; + else + dp->val.i32 = (PRInt32)*ap++; + break; + + case nsXPTType::T_I64: + if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64)gprData[iCount++]; + else + dp->val.i64 = (PRInt64)*ap++; + break; + + case nsXPTType::T_U8: + if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8)gprData[iCount++]; + else + dp->val.u8 = (PRUint8)*ap++; + break; + + case nsXPTType::T_U16: + if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16)gprData[iCount++]; + else + dp->val.u16 = (PRUint16)*ap++; + break; + + case nsXPTType::T_U32: + if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32)gprData[iCount++]; + else + dp->val.u32 = (PRUint32)*ap++; + break; + + case nsXPTType::T_U64: + if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64)gprData[iCount++]; + else + dp->val.u64 = (PRUint64)*ap++; + break; + + case nsXPTType::T_FLOAT: + if (iCount < PARAM_FPR_COUNT) + dp->val.f = (double)fprData[iCount++]; + else + dp->val.f = *((double*)ap++); + break; + + case nsXPTType::T_DOUBLE: + if (iCount < PARAM_FPR_COUNT) + dp->val.d = (double)fprData[iCount++]; + else + dp->val.d = *((double*)ap++); + break; + + case nsXPTType::T_BOOL: + if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool)gprData[iCount++]; + else + dp->val.b = (PRBool)*ap++; + break; + + case nsXPTType::T_CHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char)gprData[iCount++]; + else + dp->val.c = (char)*ap++; + break; + + case nsXPTType::T_WCHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t)gprData[iCount++]; + else + dp->val.wc = (wchar_t)*ap++; + break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) /* defined in the assembly file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp new file mode 100644 index 00000000..e5b1c642 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp @@ -0,0 +1,236 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Glen Nakamura + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* Prototype specifies unmangled function name and disables unused warning */ +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +__asm__("PrepareAndDispatch") __attribute__((unused)); + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * SharedStub() + * Collects arguments and calls PrepareAndDispatch. The "methodIndex" is + * passed to this function via $1 to preserve the argument registers. + */ +__asm__( + "#### SharedStub ####\n" +".text\n\t" + ".align 5\n\t" + ".ent SharedStub\n" +"SharedStub:\n\t" + ".frame $30,96,$26,0\n\t" + ".mask 0x4000000,-96\n\t" + "ldgp $29,0($27)\n" +"$SharedStub..ng:\n\t" + "subq $30,96,$30\n\t" + "stq $26,0($30)\n\t" + ".prologue 1\n\t" + + /* + * Store arguments passed via registers to the stack. + * Floating point registers are stored as doubles and converted + * to floats in PrepareAndDispatch if necessary. + */ + "stt $f17,16($30)\n\t" /* floating point registers */ + "stt $f18,24($30)\n\t" + "stt $f19,32($30)\n\t" + "stt $f20,40($30)\n\t" + "stt $f21,48($30)\n\t" + "stq $17,56($30)\n\t" /* integer registers */ + "stq $18,64($30)\n\t" + "stq $19,72($30)\n\t" + "stq $20,80($30)\n\t" + "stq $21,88($30)\n\t" + + /* + * Call PrepareAndDispatch function. + */ + "bis $1,$1,$17\n\t" /* pass "methodIndex" */ + "addq $30,16,$18\n\t" /* pass "args" */ + "bsr $26,$PrepareAndDispatch..ng\n\t" + + "ldq $26,0($30)\n\t" + "addq $30,96,$30\n\t" + "ret $31,($26),1\n\t" + ".end SharedStub" + ); + +/* + * nsresult nsXPTCStubBase::Stub##n() + * Sets register $1 to "methodIndex" and jumps to SharedStub. + */ +#define STUB_MANGLED_ENTRY(n, symbol) \ + "#### Stub"#n" ####" "\n\t" \ + ".text" "\n\t" \ + ".align 5" "\n\t" \ + ".globl " symbol "\n\t" \ + ".ent " symbol "\n" \ +symbol ":" "\n\t" \ + ".frame $30,0,$26,0" "\n\t" \ + "ldgp $29,0($27)" "\n" \ +"$" symbol "..ng:" "\n\t" \ + ".prologue 1" "\n\t" \ + "lda $1,"#n "\n\t" \ + "br $31,$SharedStub..ng" "\n\t" \ + ".end " symbol + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ + +#define STUB_ENTRY(n) \ +__asm__( \ + ".if "#n" < 10" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase5Stub"#n"Ev") "\n\t" \ + ".elseif "#n" < 100" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase6Stub"#n"Ev") "\n\t" \ + ".elseif "#n" < 1000" "\n\t" \ + STUB_MANGLED_ENTRY(n, "_ZN14nsXPTCStubBase7Stub"#n"Ev") "\n\t" \ + ".else" "\n\t" \ + ".err \"Stub"#n" >= 1000 not yet supported.\"" "\n\t" \ + ".endif" \ + ); + +#else /* not G++ V3 ABI */ + +#define STUB_ENTRY(n) \ +__asm__( \ + STUB_MANGLED_ENTRY(n, "Stub"#n"__14nsXPTCStubBase") \ + ); + +#endif /* G++ V3 ABI */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp new file mode 100644 index 00000000..eb094762 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +extern "C" { + nsresult + PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) + { +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + switch(type) + { + // the 8 and 16 bit types will have been promoted to 32 bits before + // being pushed onto the stack. Since the 68k is big endian, we + // need to skip over the leading high order bytes. + case nsXPTType::T_I8 : dp->val.i8 = *(((PRInt8*) ap) + 3); break; + case nsXPTType::T_I16 : dp->val.i16 = *(((PRInt16*) ap) + 1); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *(((PRUint8*) ap) + 3); break; + case nsXPTType::T_U16 : dp->val.u16 = *(((PRUint16*)ap) + 1); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *(((char*) ap) + 3); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; + } +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult result; \ + __asm__ __volatile__( \ + "lea %/a6@(12), %/a0\n\t" /* args */ \ + "movl %/a0, %/sp@-\n\t" \ + "movl #"#n", %/sp@-\n\t" /* method index */ \ + "movl %/a6@(8), %/sp@-\n\t" /* this */ \ + "jbsr PrepareAndDispatch\n\t" \ + "movl %/d0, %0\n\t" \ + "addl #12, %/sp" \ + : "=d" (result) /* %0 */ \ + : \ + : "a0", "a1", "d0", "d1", "memory" ); \ + return result; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp new file mode 100644 index 00000000..0f8502cd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, + PRUint32* a_gpr, PRUint64 *a_fpr, PRUint32 *a_ov) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32 gpr = 1, fpr = 0; + + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (gpr < 5) + dp->val.p = (void*) *a_gpr++, gpr++; + else + dp->val.p = (void*) *a_ov++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + dp->val.i8 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i8 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + dp->val.i16 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i16 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + dp->val.i32 = *((PRInt32*) a_gpr), a_gpr++, gpr++; + else + dp->val.i32 = *((PRInt32*) a_ov ), a_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 4) + dp->val.i64 = *((PRInt64*) a_gpr), a_gpr+=2, gpr+=2; + else + dp->val.i64 = *((PRInt64*) a_ov ), a_ov+=2, gpr=5; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + dp->val.u8 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u8 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + dp->val.u16 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u16 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + dp->val.u32 = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.u32 = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 4) + dp->val.u64 = *((PRUint64*)a_gpr), a_gpr+=2, gpr+=2; + else + dp->val.u64 = *((PRUint64*)a_ov ), a_ov+=2, gpr=5; + break; + case nsXPTType::T_FLOAT : + if (fpr < 2) + dp->val.f = *((float*) a_fpr), a_fpr++, fpr++; + else + dp->val.f = *((float*) a_ov ), a_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 2) + dp->val.d = *((double*) a_fpr), a_fpr++, fpr++; + else + dp->val.d = *((double*) a_ov ), a_ov+=2; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + dp->val.b = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.b = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + dp->val.c = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.c = *((PRUint32*)a_ov ), a_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + dp->val.wc = *((PRUint32*)a_gpr), a_gpr++, gpr++; + else + dp->val.wc = *((PRUint32*)a_ov ), a_ov++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + PRUint32 a_gpr[4]; \ + PRUint64 a_fpr[2]; \ + PRUint32 *a_ov; \ + \ + __asm__ __volatile__ \ + ( \ + "l %0,0(15)\n\t" \ + "ahi %0,96\n\t" \ + "stm 3,6,0(%3)\n\t" \ + "std 0,%1\n\t" \ + "std 2,%2\n\t" \ + : "=&a" (a_ov), \ + "=m" (a_fpr[0]), \ + "=m" (a_fpr[1]) \ + : "a" (a_gpr) \ + : "memory", "cc", \ + "3", "4", "5", "6" \ + ); \ + \ + return PrepareAndDispatch(this, n, a_gpr, a_fpr, a_ov); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp new file mode 100644 index 00000000..9a645dd1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp @@ -0,0 +1,224 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, + PRUint64* a_gpr, PRUint64 *a_fpr, PRUint64 *a_ov) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32 gpr = 1, fpr = 0; + + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (gpr < 5) + dp->val.p = (void*) *a_gpr++, gpr++; + else + dp->val.p = (void*) *a_ov++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : + if (gpr < 5) + dp->val.i8 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i8 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I16 : + if (gpr < 5) + dp->val.i16 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i16 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I32 : + if (gpr < 5) + dp->val.i32 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i32 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_I64 : + if (gpr < 5) + dp->val.i64 = *((PRInt64*) a_gpr), a_gpr++, gpr++; + else + dp->val.i64 = *((PRInt64*) a_ov ), a_ov++; + break; + case nsXPTType::T_U8 : + if (gpr < 5) + dp->val.u8 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u8 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U16 : + if (gpr < 5) + dp->val.u16 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u16 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U32 : + if (gpr < 5) + dp->val.u32 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u32 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_U64 : + if (gpr < 5) + dp->val.u64 = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.u64 = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_FLOAT : + if (fpr < 4) + dp->val.f = *((float*) a_fpr), a_fpr++, fpr++; + else + dp->val.f = *(((float*) a_ov )+1), a_ov++; + break; + case nsXPTType::T_DOUBLE : + if (fpr < 4) + dp->val.d = *((double*) a_fpr), a_fpr++, fpr++; + else + dp->val.d = *((double*) a_ov ), a_ov++; + break; + case nsXPTType::T_BOOL : + if (gpr < 5) + dp->val.b = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.b = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_CHAR : + if (gpr < 5) + dp->val.c = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.c = *((PRUint64*)a_ov ), a_ov++; + break; + case nsXPTType::T_WCHAR : + if (gpr < 5) + dp->val.wc = *((PRUint64*)a_gpr), a_gpr++, gpr++; + else + dp->val.wc = *((PRUint64*)a_ov ), a_ov++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + PRUint64 a_gpr[4]; \ + PRUint64 a_fpr[4]; \ + PRUint64 *a_ov; \ + \ + __asm__ __volatile__ \ + ( \ + "lg %0,0(15)\n\t" \ + "aghi %0,160\n\t" \ + "stmg 3,6,0(%5)\n\t"\ + "std 0,%1\n\t" \ + "std 2,%2\n\t" \ + "std 4,%3\n\t" \ + "std 6,%4\n\t" \ + : "=&a" (a_ov), \ + "=m" (a_fpr[0]), \ + "=m" (a_fpr[1]), \ + "=m" (a_fpr[2]), \ + "=m" (a_fpr[3]) \ + : "a" (a_gpr) \ + : "memory", "cc", \ + "3", "4", "5", "6" \ + ); \ + \ + return PrepareAndDispatch(this, n, a_gpr, a_fpr, a_ov); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp new file mode 100644 index 00000000..4d60f7be --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * Version: MPL 1.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp, Inc. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "xptcprivate.h" + +/* + * This is for MIPS O32 ABI + * Args contains a0-3 and then the stack. + * Because a0 is 'this', we want to skip it + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args) +{ + args++; // always skip over a0 + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + dp->val.p = (void*) *ap; + + switch(type) + { + case nsXPTType::T_I64 : + if ((PRWord)ap & 4) ap++; + dp->val.i64 = *((PRInt64*) ap); ap++; + break; + case nsXPTType::T_U64 : + if ((PRWord)ap & 4) ap++; + dp->val.u64 = *((PRInt64*) ap); ap++; + break; + case nsXPTType::T_DOUBLE: + if ((PRWord)ap & 4) ap++; + dp->val.d = *((double*) ap); ap++; + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) // done in the .s file + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp new file mode 100644 index 00000000..4069a6bc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if !defined(__NetBSD__) || !defined(__m68k__) +#error This code is for NetBSD/m68k only +#endif + +extern "C" { + static nsresult + PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) + { +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + + switch(type) + { + // the 8 and 16 bit types will have been promoted to 32 bits before + // being pushed onto the stack. Since the 68k is big endian, we + // need to skip over the leading high order bytes. + case nsXPTType::T_I8 : dp->val.i8 = *(((PRInt8*) ap) + 3); break; + case nsXPTType::T_I16 : dp->val.i16 = *(((PRInt16*) ap) + 1); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *(((PRUint8*) ap) + 3); break; + case nsXPTType::T_U16 : dp->val.u16 = *(((PRUint16*)ap) + 1); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *(((char*) ap) + 3); break; + // wchar_t is an int (32 bits) on NetBSD + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; + } +} + +#define STUB_ENTRY(n) \ +__asm__( \ + ".global _Stub"#n"__14nsXPTCStubBase\n\t" \ +"_Stub"#n"__14nsXPTCStubBase:\n\t" \ + "link a6,#0 \n\t" \ + "lea a6@(12), a0 \n\t" /* pointer to args */ \ + "movl a0, sp@- \n\t" \ + "movl #"#n", sp@- \n\t" /* method index */ \ + "movl a6@(8), sp@- \n\t" /* this */ \ + "jbsr _PrepareAndDispatch \n\t" \ + "unlk a6 \n\t" \ + "rts \n\t" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp new file mode 100644 index 00000000..c4d1b364 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_openvms_alpha.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +extern "C" { + +nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +} + +#define STUB_ENTRY(n) /* This is in the ASM file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp new file mode 100644 index 00000000..cd8fe40b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_osf1_alpha.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +/* contributed by Glen Nakamura */ + +#include "xptcprivate.h" + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint64* args) +{ + const PRUint8 PARAM_BUFFER_COUNT = 16; + const PRUint8 NUM_ARG_REGS = 6-1; // -1 for "this" pointer + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + // args[0] to args[NUM_ARG_REGS] hold floating point register values + PRUint64* ap = args + NUM_ARG_REGS; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = (PRInt8) *ap; break; + case nsXPTType::T_I16 : dp->val.i16 = (PRInt16) *ap; break; + case nsXPTType::T_I32 : dp->val.i32 = (PRInt32) *ap; break; + case nsXPTType::T_I64 : dp->val.i64 = (PRInt64) *ap; break; + case nsXPTType::T_U8 : dp->val.u8 = (PRUint8) *ap; break; + case nsXPTType::T_U16 : dp->val.u16 = (PRUint16) *ap; break; + case nsXPTType::T_U32 : dp->val.u32 = (PRUint32) *ap; break; + case nsXPTType::T_U64 : dp->val.u64 = (PRUint64) *ap; break; + case nsXPTType::T_FLOAT : + if(i < NUM_ARG_REGS) + { + // floats passed via registers are stored as doubles + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (PRUint64) args[i]; + dp->val.f = (float) dp->val.d; // convert double to float + } + else + dp->val.u32 = (PRUint32) *ap; + break; + case nsXPTType::T_DOUBLE : + // doubles passed via registers are also stored + // in the first NUM_ARG_REGS entries in args + dp->val.u64 = (i < NUM_ARG_REGS) ? args[i] : *ap; + break; + case nsXPTType::T_BOOL : dp->val.b = (PRBool) *ap; break; + case nsXPTType::T_CHAR : dp->val.c = (char) *ap; break; + case nsXPTType::T_WCHAR : dp->val.wc = (PRUnichar) *ap; break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +/* + * nsresult nsXPTCStubBase::Stub##n() ;\ + * Sets arguments to registers and calls PrepareAndDispatch. + * This is defined in the ASM file. + */ +#define STUB_ENTRY(n) \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp new file mode 100644 index 00000000..b3a42442 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp @@ -0,0 +1,176 @@ + +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if _HPUX +#error "This code is for HP-PA RISC 32 bit mode only" +#endif + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* floatargs) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRInt32 regwords = 1; /* self pointer is not in the variant records */ + nsresult result = NS_ERROR_FAILURE; + PRUint8 paramCount; + PRUint8 i; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + for(i = 0; i < paramCount; ++i, --args) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *args; + ++regwords; + continue; + } + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) args); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) args); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) args); break; + case nsXPTType::T_DOUBLE : + if (regwords & 1) + { + ++regwords; /* align on double word */ + --args; + } + if (regwords == 0 || regwords == 2) + { + dp->val.d=*((double*) (floatargs + regwords)); + --args; + } + else + { + dp->val.d = *((double*) --args); + } + regwords += 2; + continue; + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : + if (regwords & 1) + { + ++regwords; /* align on double word */ + --args; + } + ((DU *)dp)->lo = *((PRUint32*) args); + ((DU *)dp)->hi = *((PRUint32*) --args); + regwords += 2; + continue; + case nsXPTType::T_FLOAT : + if (regwords >= 4) + dp->val.f = *((float*) args); + else + dp->val.f = *((float*) floatargs+4+regwords); + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) args); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*) args); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*) args); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) args); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) args); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) args); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + ++regwords; + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp new file mode 100644 index 00000000..870669d7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: C; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(AIX) + +/* + For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters + arrive in a separate chunk of data that has been loaded from the registers. + The args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ + typedef struct { + uint32 hi; + uint32 lo; // have to move 64 bit entities as 32 bit halves since + } DU; // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->hi = (PRInt32) gprData[iCount++]; + else + ((DU *)dp)->hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->lo = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->lo = (PRUint32) *ap++; + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8) gprData[iCount++]; + else + dp->val.u8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16) gprData[iCount++]; + else + dp->val.u16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32) gprData[iCount++]; + else + dp->val.u32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->hi = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + ((DU *)dp)->lo = (PRUint32) gprData[iCount++]; + else + ((DU *)dp)->lo = (PRUint32) *ap++; + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* AIX */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp new file mode 100644 index 00000000..cf2ddba9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp @@ -0,0 +1,215 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/LGPL 2.1/GPL 2.0 + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM are + * Copyright (C) 2002, International Business Machines Corporation. + * All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 LGPL or the GPL. 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(AIX) + +/* + For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters + arrive in a separate chunk of data that has been loaded from the registers. + The args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint64 methodIndex, PRUint64* args, PRUint64 *gprData, double *fprData) +{ + +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64) gprData[iCount++]; + else + dp->val.i64 = (PRInt64) *ap++; + break; + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8) gprData[iCount++]; + else + dp->val.u8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16) gprData[iCount++]; + else + dp->val.u16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32) gprData[iCount++]; + else + dp->val.u32 = (PRUint32) *ap++; + break; + case nsXPTType::T_U64 : if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64) gprData[iCount++]; + else + dp->val.u64 = (PRUint64) *ap++; + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + return SharedStub(n); \ +} \ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* AIX */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp new file mode 100644 index 00000000..b1c98571 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp @@ -0,0 +1,253 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral +// parameters and the first 8 floating point parameters in registers +// (r3-r10 and f1-f8), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. The stack pointer has to retain 16-byte alignment, longlongs +// and doubles are aligned on 8-byte boundaries. + +#define PARAM_BUFFER_COUNT 16 +#define GPR_COUNT 8 +#define FPR_COUNT 8 + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gprData[]' contains the arguments passed in integer registers +// - 'fprData[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, + PRUint32 methodIndex, + PRUint32* args, + PRUint32 *gprData, + double *fprData) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (! iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (! info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (! dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + PRUint32 gpr = 1; // skip one GPR register + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + dp->val.d = fprData[fpr++]; + else { + if ((PRUint32) ap & 4) ap++; // doubles are 8-byte aligned on stack + dp->val.d = *(double*) ap; + ap += 2; + } + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles + else + dp->val.f = *(float*) ap++; + continue; + } + else if (!param.IsOut() && (type == nsXPTType::T_I64 + || type == nsXPTType::T_U64)) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((gpr + 1) < GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[gpr]; + gpr += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + } + else { + if (gpr < GPR_COUNT) + tempu32 = gprData[gpr++]; + else + tempu32 = *ap++; + } + + if(param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) tempu32; + continue; + } + + switch(type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) tempu32; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) tempu32; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) tempu32; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) tempu64; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) tempu32; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) tempu32; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) tempu32; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) tempu64; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) tempu32; break; + case nsXPTType::T_CHAR: dp->val.c = (char) tempu32; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) tempu32; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +// Load r11 with the constant 'n' and branch to SharedStub(). +// +// XXX Yes, it's ugly that we're relying on gcc's name-mangling here; +// however, it's quick, dirty, and'll break when the ABI changes on +// us, which is what we want ;-). + +#if __GXX_ABI_VERSION < 100 +// gcc-2 version +# define STUB_ENTRY(n) \ +__asm__ ( \ + ".section \".text\" \n\t" \ + ".align 2 \n\t" \ + ".globl Stub"#n"__14nsXPTCStubBase \n\t" \ + ".type Stub"#n"__14nsXPTCStubBase,@function \n\n" \ + \ +"Stub"#n"__14nsXPTCStubBase: \n\t" \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); +#else +// gcc-3 version +// +// As G++3 ABI contains the length of the functionname in the mangled +// name, it is difficult to get a generic assembler mechanism like +// in the G++ 2.95 case. +// Create names would be like: +// _ZN14nsXPTCStubBase5Stub1Ev +// _ZN14nsXPTCStubBase6Stub12Ev +// _ZN14nsXPTCStubBase7Stub123Ev +// _ZN14nsXPTCStubBase8Stub1234Ev +// etc. +// Use assembler directives to get the names right... + +# define STUB_ENTRY(n) \ +__asm__ ( \ + ".align 2 \n\t" \ + ".if "#n" < 10 \n\t" \ + ".globl _ZN14nsXPTCStubBase5Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase5Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase5Stub"#n"Ev: \n\t" \ + \ + ".elseif "#n" < 100 \n\t" \ + ".globl _ZN14nsXPTCStubBase6Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase6Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase6Stub"#n"Ev: \n\t" \ + \ + ".elseif "#n" < 1000 \n\t" \ + ".globl _ZN14nsXPTCStubBase7Stub"#n"Ev \n\t" \ + ".type _ZN14nsXPTCStubBase7Stub"#n"Ev,@function \n\n" \ +"_ZN14nsXPTCStubBase7Stub"#n"Ev: \n\t" \ + \ + ".else \n\t" \ + ".err \"stub number "#n" >= 1000 not yet supported\"\n" \ + ".endif \n\t" \ + \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); +#endif + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp new file mode 100644 index 00000000..68d572ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp @@ -0,0 +1,217 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Franz.Sirl-kernel@lauterbach.com (Franz Sirl) + * beard@netscape.com (Patrick Beard) + * waterson@netscape.com (Chris Waterson) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral +// parameters and the first 8 floating point parameters in registers +// (r3-r10 and f1-f8), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. The stack pointer has to retain 16-byte alignment, longlongs +// and doubles are aligned on 8-byte boundaries. + +#define PARAM_BUFFER_COUNT 16 +#define GPR_COUNT 8 +#define FPR_COUNT 8 + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gprData[]' contains the arguments passed in integer registers +// - 'fprData[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, + PRUint32 methodIndex, + PRUint32* args, + PRUint32 *gprData, + double *fprData) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (! iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (! info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (! dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + PRUint32 gpr = 1; // skip one GPR register + PRUint32 fpr = 0; + PRUint32 tempu32; + PRUint64 tempu64; + + for(i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (fpr < FPR_COUNT) + dp->val.d = fprData[fpr++]; + else { + if ((PRUint32) ap & 4) ap++; // doubles are 8-byte aligned on stack + dp->val.d = *(double*) ap; + ap += 2; + if (gpr < GPR_COUNT) + gpr += 2; + } + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (fpr < FPR_COUNT) + dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles + else { + dp->val.f = *(float*) ap; + ap += 1; + if (gpr < GPR_COUNT) + gpr += 1; + } + continue; + } + else if (!param.IsOut() && (type == nsXPTType::T_I64 + || type == nsXPTType::T_U64)) { + if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((gpr + 1) < GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[gpr]; + gpr += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + } + else { + if (gpr < GPR_COUNT) + tempu32 = gprData[gpr++]; + else + tempu32 = *ap++; + } + + if(param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) tempu32; + continue; + } + + switch(type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) tempu32; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) tempu32; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) tempu32; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) tempu64; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) tempu32; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) tempu32; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) tempu32; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) tempu64; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) tempu32; break; + case nsXPTType::T_CHAR: dp->val.c = (char) tempu32; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) tempu32; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +// Load r11 with the constant 'n' and branch to SharedStub(). +// +// XXX Yes, it's ugly that we're relying on gcc's name-mangling here; +// however, it's quick, dirty, and'll break when the ABI changes on +// us, which is what we want ;-). + +#define STUB_ENTRY(n) \ +__asm__ ( \ + ".section \".text\" \n\t" \ + ".align 2 \n\t" \ + ".globl Stub"#n"__14nsXPTCStubBase \n\t" \ + ".type Stub"#n"__14nsXPTCStubBase,@function \n\n" \ + \ +"Stub"#n"__14nsXPTCStubBase: \n\t" \ + "li 11,"#n" \n\t" \ + "b SharedStub@local \n" \ +); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp new file mode 100644 index 00000000..fcf96d4f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp @@ -0,0 +1,254 @@ +/* -*- Mode: C; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* + For mac, the first 8 integral and the first 13 f.p. parameters arrive + in a separate chunk of data that has been loaded from the registers. The + args pointer has been set to the start of the parameters BEYOND the ones + arriving in registers +*/ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint32* args, PRUint32 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 7 + + // fprintf(stderr, "PrepareAndDispatch %p, %d, %p, %p, %p\n", self, methodIndex, args, gprData, fprData); + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + PRUint32 iCount = 0; + PRUint32 fpCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*) gprData[iCount++]; + else + dp->val.p = (void*) *ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8) gprData[iCount++]; + else + dp->val.i8 = (PRInt8) *ap++; + break; + case nsXPTType::T_I16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16) gprData[iCount++]; + else + dp->val.i16 = (PRInt16) *ap++; + break; + case nsXPTType::T_I32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32) gprData[iCount++]; + else + dp->val.i32 = (PRInt32) *ap++; + break; + + case nsXPTType::T_I64 : + { + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; + } + break; + +#if 0 + case nsXPTType::T_I64 : if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRInt32) gprData[iCount++]; + else + dp->val.i64.hi = (PRInt32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; + break; +#endif + case nsXPTType::T_U8 : if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRUint8) gprData[iCount++]; + else + dp->val.i8 = (PRUint8) *ap++; + break; + case nsXPTType::T_U16 : if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRUint16) gprData[iCount++]; + else + dp->val.i16 = (PRUint16) *ap++; + break; + case nsXPTType::T_U32 : if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRUint32) gprData[iCount++]; + else + dp->val.i32 = (PRUint32) *ap++; + break; + + case nsXPTType::T_U64 : +#if 0 + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.hi = (PRUint32) gprData[iCount++]; + else + dp->val.i64.hi = (PRUint32) *ap++; + if (iCount < PARAM_GPR_COUNT) + dp->val.i64.lo = (PRUint32) gprData[iCount++]; + else + dp->val.i64.lo = (PRUint32) *ap++; +#endif + { + PRUint64 tempu64; + if (iCount & 1) iCount++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 + if ((iCount + 1) < PARAM_GPR_COUNT) { + tempu64 = *(PRUint64*) &gprData[iCount]; + iCount += 2; + } + else { + if ((PRUint32) ap & 4) ap++; // longlongs are 8-byte aligned on stack + tempu64 = *(PRUint64*) ap; + ap += 2; + } + dp->val.i64 = (PRUint64)tempu64; + } + break; + case nsXPTType::T_FLOAT : if (fpCount < 13) { + dp->val.f = (float) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else + dp->val.f = *((float*) ap++); + break; + case nsXPTType::T_DOUBLE : if (fpCount < 13) { + dp->val.d = (double) fprData[fpCount++]; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + if (iCount < PARAM_GPR_COUNT) + ++iCount; + else + ++ap; + } + else { + dp->val.f = *((double*) ap); + ap += 2; + } + break; + case nsXPTType::T_BOOL : if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool) gprData[iCount++]; + else + dp->val.b = (PRBool) *ap++; + break; + case nsXPTType::T_CHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char) gprData[iCount++]; + else + dp->val.c = (char) *ap++; + break; + case nsXPTType::T_WCHAR : if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t) gprData[iCount++]; + else + dp->val.wc = (wchar_t) *ap++; + break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + + +#define STUB_ENTRY(n) +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp new file mode 100644 index 00000000..cbed6041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : ((DU *)dp)->hi = ((DU *)ap)->hi; + ((DU *)dp)->lo = ((DU *)ap)->lo; + ap++; + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp new file mode 100644 index 00000000..cbed6041 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, uint32* args) +{ + + typedef struct { + uint32 hi; + uint32 lo; + } DU; // have to move 64 bit entities as 32 bit halves since + // stack slots are not guaranteed 16 byte aligned + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : + case nsXPTType::T_U64 : + case nsXPTType::T_I64 : ((DU *)dp)->hi = ((DU *)ap)->hi; + ((DU *)dp)->lo = ((DU *)ap)->lo; + ap++; + break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp new file mode 100644 index 00000000..f64b309e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#if defined(sparc) || defined(__sparc__) + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint64 methodIndex, PRUint64* args) +{ + +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt32*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt32*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint32*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint32*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((PRUint32*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((PRInt32*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +extern "C" int SharedStub(int, int*); + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + int dummy; /* defeat tail-call optimization */ \ + return SharedStub(n, &dummy); \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#endif /* sparc || __sparc__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp new file mode 100644 index 00000000..91c5c5db --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unixish_x86.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" +/*#include "xptiprivate.h"*/ + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef __GNUC__ /* Gnu Compiler. */ + +#ifdef KEEP_STACK_16_BYTE_ALIGNED +/* Make sure the stack is 16-byte aligned. Do that by aligning to 16 bytes and + * then subtracting 4 so the three subsequent pushes result in a 16-byte aligned + * stack. */ +#define ALIGN_STACK_DECL \ + unsigned int saved_esp = 0; /* VBOX: Initialize it to shut up half a million gcc warnings on darwin. + * ALIGN_STACK_REGS_OUT/IN are a bit bogus, so the warning is probably correct. */ + +#define ALIGN_STACK_SAVE \ + "movl %%esp, %3\n\t" + +#define ALIGN_STACK_ALIGN \ + "addl $0x4, %%esp\n\t" \ + "andl $0xfffffff0, %%esp\n\t" \ + "subl $0x4, %%esp\n\t" + +#define STACK_RESTORE \ + "movl %3, %%esp\n" + +#define ALIGN_STACK_REGS_IN \ + , "=r"(saved_esp) /* 3 */ + +#define ALIGN_STACK_REGS_OUT \ + , "3"(saved_esp) + +#else +#define ALIGN_STACK_DECL +#define ALIGN_STACK_SAVE +#define ALIGN_STACK_ALIGN +#define STACK_RESTORE \ + "addl $12, %%esp\n" +#define ALIGN_STACK_REGS_IN +#define ALIGN_STACK_REGS_OUT +#endif + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, uint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + ALIGN_STACK_DECL \ + __asm__ __volatile__( \ + ALIGN_STACK_SAVE \ + ALIGN_STACK_ALIGN \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + STACK_RESTORE /* "addl $12, %%esp" or restore saved */ \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + ALIGN_STACK_REGS_IN \ + : "2" (method) /* %2 */ \ + ALIGN_STACK_REGS_OUT \ + : "memory" \ + ); \ + return result; \ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp new file mode 100644 index 00000000..0eea6567 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_unsupported.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Stub called on unsupported platform"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp new file mode 100644 index 00000000..3381c48e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp @@ -0,0 +1,242 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Linux/x86-64 uses gcc >= 3.1 +#define STUB_ENTRY(n) \ +asm(".section \".text\"\n\t" \ + ".align 2\n\t" \ + ".if " #n " < 10\n\t" \ + ".globl _ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".globl _ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \ + ".elseif " #n " < 1000\n\t" \ + ".globl _ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \ + ".else\n\t" \ + ".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \ + ".endif\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".if " #n " < 10\n\t" \ + ".size _ZN14nsXPTCStubBase5Stub" #n "Ev,.-_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \ + ".elseif " #n " < 100\n\t" \ + ".size _ZN14nsXPTCStubBase6Stub" #n "Ev,.-_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \ + ".else\n\t" \ + ".size _ZN14nsXPTCStubBase7Stub" #n "Ev,.-_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \ + ".endif"); + +// static nsresult SharedStub(PRUint32 methodIndex) +asm(".section \".text\"\n\t" + ".align 2\n\t" + ".type SharedStub,@function\n\t" + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call PrepareAndDispatch@plt\n\t" + "leave\n\t" + "ret\n\t" + ".size SharedStub,.-SharedStub"); + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Linux/x86-64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp new file mode 100644 index 00000000..59e0202f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp @@ -0,0 +1,271 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +// Implement shared vtbl methods. + +#include "xptcprivate.h" + +// The Linux/x86-64 ABI passes the first 6 integer parameters and the +// first 8 floating point parameters in registers (rdi, rsi, rdx, rcx, +// r8, r9 and xmm0-xmm7), no stack space is allocated for these by the +// caller. The rest of the parameters are passed in the callers stack +// area. +// Solaris does the same, just the assembler may differ. + +const PRUint32 PARAM_BUFFER_COUNT = 16; +const PRUint32 GPR_COUNT = 6; +const PRUint32 FPR_COUNT = 8; + +// PrepareAndDispatch() is called by SharedStub() and calls the actual method. +// +// - 'args[]' contains the arguments passed on stack +// - 'gpregs[]' contains the arguments passed in integer registers +// - 'fpregs[]' contains the arguments passed in floating point registers +// +// The parameters are mapped into an array of type 'nsXPTCMiniVariant' +// and then the method gets called. + +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase * self, PRUint32 methodIndex, + PRUint64 * args, PRUint64 * gpregs, double *fpregs) +{ + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint32 paramCount; + PRUint32 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if (paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint64* ap = args; + PRUint32 nr_gpr = 1; // skip one GPR register for 'that' + PRUint32 nr_fpr = 0; + PRUint64 value; + + for (i = 0; i < paramCount; i++) { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { + if (nr_fpr < FPR_COUNT) + dp->val.d = fpregs[nr_fpr++]; + else + dp->val.d = *(double*) ap++; + continue; + } + else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { + if (nr_fpr < FPR_COUNT) + // The value in %xmm register is already prepared to + // be retrieved as a float. Therefore, we pass the + // value verbatim, as a double without conversion. + dp->val.d = *(double*) ap++; + else + dp->val.f = *(float*) ap++; + continue; + } + else { + if (nr_gpr < GPR_COUNT) + value = gpregs[nr_gpr++]; + else + value = *ap++; + } + + if (param.IsOut() || !type.IsArithmetic()) { + dp->val.p = (void*) value; + continue; + } + + switch (type) { + case nsXPTType::T_I8: dp->val.i8 = (PRInt8) value; break; + case nsXPTType::T_I16: dp->val.i16 = (PRInt16) value; break; + case nsXPTType::T_I32: dp->val.i32 = (PRInt32) value; break; + case nsXPTType::T_I64: dp->val.i64 = (PRInt64) value; break; + case nsXPTType::T_U8: dp->val.u8 = (PRUint8) value; break; + case nsXPTType::T_U16: dp->val.u16 = (PRUint16) value; break; + case nsXPTType::T_U32: dp->val.u32 = (PRUint32) value; break; + case nsXPTType::T_U64: dp->val.u64 = (PRUint64) value; break; + case nsXPTType::T_BOOL: dp->val.b = (PRBool) value; break; + case nsXPTType::T_CHAR: dp->val.c = (char) value; break; + case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) value; break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16) methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if (dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#include + +#if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */ +// Solaris/x86-64 uses gcc >= 3.1 +#define STUB_ENTRY(n,m) \ +asm(".section .text\n\t" \ + ".align 2\n\t" \ + ".globl _ZN14nsXPTCStubBase" #m "Stub" #n "Ev\n\t" \ + ".type _ZN14nsXPTCStubBase" #m "Stub" #n "Ev,@function\n" \ + "_ZN14nsXPTCStubBase" #m "Stub" #n "Ev:\n\t" \ + "movl $" #n ", %eax\n\t" \ + "jmp SharedStub\n\t" \ + ".size _ZN14nsXPTCStubBase" #m "Stub" #n "Ev,.-_ZN14nsXPTCStubBase" #m "Stub" #n "Ev\n\t" \ + ) + +#define STUB_ENTRY_10(n10,m) \ + STUB_ENTRY(n10##0,m); \ + STUB_ENTRY(n10##1,m); \ + STUB_ENTRY(n10##2,m); \ + STUB_ENTRY(n10##3,m); \ + STUB_ENTRY(n10##4,m); \ + STUB_ENTRY(n10##5,m); \ + STUB_ENTRY(n10##6,m); \ + STUB_ENTRY(n10##7,m); \ + STUB_ENTRY(n10##8,m); \ + STUB_ENTRY(n10##9,m) +STUB_ENTRY_10(,5); +STUB_ENTRY_10(1,6); +STUB_ENTRY_10(2,6); +STUB_ENTRY_10(3,6); +STUB_ENTRY_10(4,6); +STUB_ENTRY_10(5,6); +STUB_ENTRY_10(6,6); +STUB_ENTRY_10(7,6); +STUB_ENTRY_10(8,6); +STUB_ENTRY_10(9,6); +STUB_ENTRY_10(10,7); +STUB_ENTRY_10(11,7); +STUB_ENTRY_10(12,7); +STUB_ENTRY_10(13,7); +STUB_ENTRY_10(14,7); +STUB_ENTRY_10(15,7); +STUB_ENTRY_10(16,7); +STUB_ENTRY_10(17,7); +STUB_ENTRY_10(18,7); +STUB_ENTRY_10(19,7); +STUB_ENTRY_10(20,7); +STUB_ENTRY_10(21,7); +STUB_ENTRY_10(22,7); +STUB_ENTRY_10(23,7); +STUB_ENTRY_10(24,7); + + +// static nsresult SharedStub(PRUint32 methodIndex) +asm(".section .text\n\t" + ".align 2\n\t" + ".type SharedStub,@function\n\t" + "SharedStub:\n\t" + // make room for gpregs (48), fpregs (64) + "pushq %rbp\n\t" + "movq %rsp,%rbp\n\t" + "subq $112,%rsp\n\t" + // save GP registers + "movq %rdi,-112(%rbp)\n\t" + "movq %rsi,-104(%rbp)\n\t" + "movq %rdx, -96(%rbp)\n\t" + "movq %rcx, -88(%rbp)\n\t" + "movq %r8 , -80(%rbp)\n\t" + "movq %r9 , -72(%rbp)\n\t" + "leaq -112(%rbp),%rcx\n\t" + // save FP registers + "movsd %xmm0,-64(%rbp)\n\t" + "movsd %xmm1,-56(%rbp)\n\t" + "movsd %xmm2,-48(%rbp)\n\t" + "movsd %xmm3,-40(%rbp)\n\t" + "movsd %xmm4,-32(%rbp)\n\t" + "movsd %xmm5,-24(%rbp)\n\t" + "movsd %xmm6,-16(%rbp)\n\t" + "movsd %xmm7, -8(%rbp)\n\t" + "leaq -64(%rbp),%r8\n\t" + // rdi has the 'self' pointer already + "movl %eax,%esi\n\t" + "leaq 16(%rbp),%rdx\n\t" + "call PrepareAndDispatch@plt\n\t" + "leave\n\t" + "ret\n\t" + ".size SharedStub,.-SharedStub"); + + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +SENTINEL_ENTRY(0) +SENTINEL_ENTRY(1) +SENTINEL_ENTRY(2) +SENTINEL_ENTRY(3) +SENTINEL_ENTRY(4) + +#else +#error "Unsupported compiler. Use gcc >= 3.1 for Linux/x86-64." +#endif /* __GNUC__ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp new file mode 100644 index 00000000..d4ae7667 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp @@ -0,0 +1,165 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" +#include "xptc_platforms_unixish_x86.h" + +static nsresult +PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + if (!iface_info) + return NS_ERROR_UNEXPECTED; + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no method info"); + if (!info) + return NS_ERROR_UNEXPECTED; + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + if (!dispatchParams) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + dp->val.p = (void*) *ap; + switch(type) + { + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#ifdef __GNUC__ /* Gnu Compiler. */ +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + register nsresult (*method) (nsXPTCStubBase *, uint32, PRUint32 *) = PrepareAndDispatch; \ + int temp0, temp1; \ + register nsresult result; \ + __asm__ __volatile__( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "pushl %%ecx\n\t" \ + "pushl $"#n"\n\t" /* method index */ \ + "movl 0x08(%%ebp), %%ecx\n\t" /* this */ \ + "pushl %%ecx\n\t" \ + "call *%%edx\n\t" /* PrepareAndDispatch */ \ + "addl $12, %%esp" \ + : "=a" (result), /* %0 */ \ + "=&c" (temp0), /* %1 */ \ + "=d" (temp1) /* %2 */ \ + : "2" (method) /* %2 */ \ + : "memory" ); \ + return result; \ +} + +#elif defined(__SUNPRO_CC) /* Sun Workshop Compiler. */ + +#define STUB_ENTRY(n) \ +nsresult nsXPTCStubBase::Stub##n() \ +{ \ + asm ( \ + "\n\t leal 0x0c(%ebp), %ecx\t / args" \ + "\n\t pushl %ecx" \ + "\n\t pushl $"#n"\t / method index" \ + "\n\t movl 0x08(%ebp), %ecx\t / this" \ + "\n\t pushl %ecx" \ + "\n\t call __1cSPrepareAndDispatch6FpnOnsXPTCStubBase_IpI_I_\t / PrepareAndDispatch" \ + "\n\t addl $12, %esp" \ + ); \ +/* result == %eax */ \ + if(0) /* supress "*** is expected to return a value." error */ \ + return 0; \ +} + +#else +#error "can't find a compiler to use" +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in new file mode 100644 index 00000000..0de74ee2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/Makefile.in @@ -0,0 +1,82 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptcmd + +# +# The default is this buildable, but non-functioning code. +# +ifdef GNU_CXX +CPPSRCS = \ + ../unix/xptcinvoke_gcc_x86_unix.cpp \ + xptcstubs.cpp \ + $(NULL) +LOCAL_INCLUDES = -I$(srcdir)/../unix +DEFINES += -DMOZ_USE_STDCALL -DMOZ_NEED_LEADING_UNDERSCORE +else +CPPSRCS = xptcinvoke.cpp xptcstubs.cpp +endif + + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/config.mk + +ifeq ($(CPU),ALPHA) +CPPSRCS := xptcinvoke_alpha.cpp xptcstubs_alpha.cpp +ASFILES := xptcinvoke_asm_alpha.s xptcstubs_asm_alpha.s +AS := asaxp +ASFLAGS += /I../../..public +endif + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTC_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + +LOCAL_INCLUDES += -I$(srcdir)/../.. diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp new file mode 100644 index 00000000..9fbf2f94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +#include "xptcprivate.h" + +#ifndef WIN32 +#error "This code is for Win32 only" +#endif + +static void __fastcall +invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount, nsXPTCVariant* s) +{ + for(; paramCount > 0; paramCount--, d++, s++) + { + if(s->IsPtrData()) + { + *((void**)d) = s->ptr; + continue; + } + switch(s->type) + { + case nsXPTType::T_I8 : *((PRInt8*) d) = s->val.i8; break; + case nsXPTType::T_I16 : *((PRInt16*) d) = s->val.i16; break; + case nsXPTType::T_I32 : *((PRInt32*) d) = s->val.i32; break; + case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break; + case nsXPTType::T_U8 : *((PRUint8*) d) = s->val.u8; break; + case nsXPTType::T_U16 : *((PRUint16*)d) = s->val.u16; break; + case nsXPTType::T_U32 : *((PRUint32*)d) = s->val.u32; break; + case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break; + case nsXPTType::T_FLOAT : *((float*) d) = s->val.f; break; + case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break; + case nsXPTType::T_BOOL : *((PRBool*) d) = s->val.b; break; + case nsXPTType::T_CHAR : *((char*) d) = s->val.c; break; + case nsXPTType::T_WCHAR : *((wchar_t*) d) = s->val.wc; break; + default: + // all the others are plain pointer types + *((void**)d) = s->val.p; + break; + } + } +} + +#pragma warning(disable : 4035) // OK to have no return value +__declspec(naked) XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + __asm { + push ebp + mov ebp,esp + mov edx,paramCount // Save paramCount for later + test edx,edx // maybe we don't have any params to copy + jz noparams + mov eax,edx + shl eax,3 // *= 8 (max possible param size) + sub esp,eax // make space for params + mov ecx,esp + push params + call invoke_copy_to_stack // fastcall, ecx = d, edx = paramCount, params is on the stack +noparams: + mov ecx,that // instance in ecx + push ecx // push this + mov edx,[ecx] // vtable in edx + mov eax,methodIndex + call [edx][eax*4] // stdcall, i.e. callee cleans up stack. + mov esp,ebp + pop ebp + ret + } +} +#pragma warning(default : 4035) // restore default diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp new file mode 100644 index 00000000..06334ac0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_alpha.cpp @@ -0,0 +1,171 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Platform specific code to invoke XPCOM methods on native objects */ + +/* contributed by bob meader */ + +#include "xptcprivate.h" + +extern "C" uint32 +invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s) +{ + return(paramCount*2); +} + +extern "C" void +invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount, + nsXPTCVariant* s, PRUint64 *regs) +{ +#define N_ARG_REGS 5 /* 6 regs minus 1 for "this" ptr */ + + for (PRUint32 i = 0; i < paramCount; i++, s++) + { + if (s->IsPtrData()) { + if (i < N_ARG_REGS) + regs[i] = (PRUint32)s->ptr; + else + *((PRUint32*)d++) = (PRUint32)s->ptr; + continue; + } + switch (s->type) { + // + // signed types first + // + case nsXPTType::T_I8: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i8; + else + *((PRInt8 *)d++) = s->val.i8; + break; + case nsXPTType::T_I16: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i16; + else + *((PRInt16 *)d++) = s->val.i16; + break; + case nsXPTType::T_I32: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i32; + else + *((PRUint32*)d++) = s->val.i32; + break; + case nsXPTType::T_I64: + if (i < N_ARG_REGS) + ((PRInt64*)regs)[i] = s->val.i64; + else + *((PRInt64*)d++) = s->val.i64; + break; + // + // unsigned types next + // + case nsXPTType::T_U8: + if (i < N_ARG_REGS) + regs[i] = s->val.u8; + else + *((PRUint8 *)d++) = s->val.u8; + break; + case nsXPTType::T_U16: + if (i < N_ARG_REGS) + regs[i] = s->val.u16; + else + *((PRUint16 *)d++) = s->val.u16; + break; + case nsXPTType::T_U32: + if (i < N_ARG_REGS) + regs[i] = s->val.u32; + else + *((PRUint32*)d++) = s->val.u32; + break; + case nsXPTType::T_U64: + if (i < N_ARG_REGS) + regs[i] = s->val.u64; + else + *((PRUint64*)d++) = s->val.u64; + break; + case nsXPTType::T_FLOAT: + if (i < N_ARG_REGS) + ((double*)regs)[i] = s->val.f; + else + *((float*)d++) = s->val.f; + break; + case nsXPTType::T_DOUBLE: + if (i < N_ARG_REGS) + ((double*)regs)[i] = s->val.d; + else + *((double*)d++) = s->val.d; + break; + case nsXPTType::T_BOOL: + if (i < N_ARG_REGS) + regs[i] = s->val.b; + else + *((PRBool*)d++) = s->val.b; + break; + case nsXPTType::T_CHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.c; + else + *((char*)d++) = s->val.c; + break; + case nsXPTType::T_WCHAR: + if (i < N_ARG_REGS) + regs[i] = s->val.wc; + else + *((wchar_t*)d++) = s->val.wc; + break; + default: + // all the others are plain pointer types + if (i < N_ARG_REGS) + regs[i] = (PRUint32)s->val.p; + else + *((PRUint32*)d++) = (PRUint32)s->val.p; + break; + } + } +} + +extern "C" nsresult XPTC__InvokebyIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params); + +extern "C" +XPTC_PUBLIC_API(nsresult) +XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex, + PRUint32 paramCount, nsXPTCVariant* params) +{ + return XPTC__InvokebyIndex(that, methodIndex, paramCount, params); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s new file mode 100644 index 00000000..7f8b343b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcinvoke_asm_alpha.s @@ -0,0 +1,128 @@ +.text +.globl invoke_count_words +.globl invoke_copy_to_stack + +#define v0 $0 +#define t0 $1 +#define t1 $2 +#define t2 $3 +#define t3 $4 +#define s0 $9 +#define fp $15 +#define a0 $16 +#define a1 $17 +#define a2 $18 +#define a3 $19 +#define a4 $20 +#define a5 $21 +#define t9 $23 +#define ra $26 +#define gp $29 +#define sp $30 +#define zero $31 +#define f0 $f0 + +#define LOCALSZ 7 +#define NARG 2 +#define SZREG 8 +#define FRAMESZ ((NARG+LOCALSZ)*SZREG) +RAOFF=FRAMESZ-(1*SZREG) +A0OFF=FRAMESZ-(2*SZREG) +A1OFF=FRAMESZ-(3*SZREG) +A2OFF=FRAMESZ-(4*SZREG) +A3OFF=FRAMESZ-(5*SZREG) +S0OFF=FRAMESZ-(6*SZREG) +GPOFF=FRAMESZ-(7*SZREG) + +// +// Nested +// XPTC__InvokebyIndex( that, methodIndex, paramCount, params) +// a0 a1 a2 a3 +// + .text + .align 4 + .globl XPTC__InvokebyIndex + .ent XPTC__InvokebyIndex,0 +XPTC__InvokebyIndex: + .frame sp, FRAMESZ, ra + subl sp,FRAMESZ,sp // allocate stack space for structure + stq ra, RAOFF(sp) + stq a0, A0OFF(sp) + stq a1, A1OFF(sp) + stq a2, A2OFF(sp) + stq a3, A3OFF(sp) + stq s0, S0OFF(sp) +// stq gp, GPOFF(sp) Don't think I am to save gp + + // invoke_count_words(paramCount, params) + bis a2,zero,a0 // move a2 into a0 + bis a3,zero,a1 // move a3 into a1 + bsr ra,invoke_count_words + + // invoke_copy_to_stack + ldq a1, A2OFF(sp) // a1 = paramCount + ldq a2, A3OFF(sp) // a2 = params + + // save sp before we copy the params to the stack + bis sp,zero,t0 // t0 = sp + + // assume full size of 8 bytes per param to be safe + sll v0,4,v0 //v0 = 8 bytes * num params + subl sp,v0,sp //sp = sp - v0 + bis sp,zero,a0 //a0 = param stack address + + // create temporary stack space to write int and fp regs + subl sp,64,sp //sp = sp -64 // (64 = 8 regs of eight bytes) + bis sp,zero,a3 // a3 = sp + + // save the old sp and save the arg stack + subl sp,16,sp //sp = sp -16 + stq t0,0(sp) + stq a0,8(sp) + // copy the param into the stack areas + bsr ra,invoke_copy_to_stack + + ldq t3,8(sp) // get previous a0 + ldq sp,0(sp) // get orig sp back + + ldq a0,A0OFF(sp) // a0 = that + ldq a1,A1OFF(sp) // a1 = methodIndex + + // calculate jmp address from method index + ldl t1,0(a0) // t1 = *that + sll a1,2,a1 // a1 = 4*index + addl t1,a1,t9 + ldl t9,0(t9) // t9=*(that + 4*index) + + // get register save area from invoke_copy_to_stack + subl t3,64,t1 + + // a1..a5 and f17..f21 should now be set to what + // invoke_copy_to_stack told us. skip a0 and f16 + // because that's the "this" pointer + + ldq a1,0(t1) + ldq a2,8(t1) + ldq a3,16(t1) + ldq a4,24(t1) + ldq a5,32(t1) + + ldt $f17,0(t1) + ldt $f18,8(t1) + ldt $f19,16(t1) + ldt $f20,24(t1) + ldt $f21,32(t1) + + // save away our stack point and create + // the stack pointer for the function + bis sp,zero,s0 + bis t3,zero,sp + jsr ra,(t9) + bis s0,zero,sp + ldq ra,RAOFF(sp) + ldq s0,S0OFF(sp) + addl sp,FRAMESZ,sp + ret + +.end XPTC__InvokebyIndex + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp new file mode 100644 index 00000000..bd5ab975 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +#ifndef WIN32 +#error "This code is for Win32 only" +#endif + +extern "C" { + +static nsresult __stdcall +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, + PRUint32* args, PRUint32* stackBytesToPop) +{ +#define PARAM_BUFFER_COUNT 16 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info = NULL; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + // If anything fails before stackBytesToPop can be set then + // the failure is completely catastrophic! + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint32* ap = args; + for(i = 0; i < paramCount; i++, ap++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + dp->val.p = (void*) *ap; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8 : dp->val.i8 = *((PRInt8*) ap); break; + case nsXPTType::T_I16 : dp->val.i16 = *((PRInt16*) ap); break; + case nsXPTType::T_I32 : dp->val.i32 = *((PRInt32*) ap); break; + case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break; + case nsXPTType::T_U8 : dp->val.u8 = *((PRUint8*) ap); break; + case nsXPTType::T_U16 : dp->val.u16 = *((PRUint16*)ap); break; + case nsXPTType::T_U32 : dp->val.u32 = *((PRUint32*)ap); break; + case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break; + case nsXPTType::T_FLOAT : dp->val.f = *((float*) ap); break; + case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break; + case nsXPTType::T_BOOL : dp->val.b = *((PRBool*) ap); break; + case nsXPTType::T_CHAR : dp->val.c = *((char*) ap); break; + case nsXPTType::T_WCHAR : dp->val.wc = *((wchar_t*) ap); break; + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + *stackBytesToPop = ((PRUint32)ap) - ((PRUint32)args); + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +} // extern "C" + +// declspec(naked) is broken in gcc +#ifndef __GNUC__ +static +__declspec(naked) +void SharedStub(void) +{ + __asm { + push ebp // set up simple stack frame + mov ebp, esp // stack has: ebp/vtbl_index/retaddr/this/args + push ecx // make room for a ptr + lea eax, [ebp-4] // pointer to stackBytesToPop + push eax + lea eax, [ebp+12] // pointer to args + push eax + push ecx // vtbl_index + mov eax, [ebp+8] // this + push eax + call PrepareAndDispatch + mov edx, [ebp+4] // return address + mov ecx, [ebp-4] // stackBytesToPop + add ecx, 8 // for 'this' and return address + mov esp, ebp + pop ebp + add esp, ecx // fix up stack pointer + jmp edx // simulate __stdcall return + } +} + +// these macros get expanded (many times) in the file #included below +#define STUB_ENTRY(n) \ +__declspec(naked) nsresult __stdcall nsXPTCStubBase::Stub##n() \ +{ __asm mov ecx, n __asm jmp SharedStub } + +#else + +#define STUB_ENTRY(n) \ +nsresult __stdcall nsXPTCStubBase::Stub##n() \ +{ \ + PRUint32 *args, stackBytesToPop = 0; \ + nsresult result = 0; \ + nsXPTCStubBase *obj; \ + __asm__ __volatile__ ( \ + "leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \ + "movl 0x08(%%ebp), %%edx\n\t" /* this */ \ + : "=c" (args), \ + "=d" (obj)); \ + result = PrepareAndDispatch(obj, n, args, &stackBytesToPop); \ + return result; \ +} + +#endif /* __GNUC__ */ + +#define SENTINEL_ENTRY(n) \ +nsresult __stdcall nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#ifdef _MSC_VER +#pragma warning(disable : 4035) // OK to have no return value +#endif +#include "xptcstubsdef.inc" +#ifdef _MSC_VER +#pragma warning(default : 4035) // restore default +#endif + +void +#ifdef __GNUC__ +__cdecl +#endif +xptc_dummy() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp new file mode 100644 index 00000000..69a10e70 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_alpha.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implement shared vtbl methods. */ + +#include "xptcprivate.h" + +/* contributed by bob meader */ + +/* + * This is for Alpha /NT 32 bits + * + * When we're called, the "gp" registers are stored in gprData and + * the "fp" registers are stored in fprData. There are 6 regs + * available which coorespond to the first 5 parameters of the + * function and the "this" pointer. If there are additional parms, + * they are stored on the stack at address "args". + * + */ +extern "C" nsresult +PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint64* args, + PRUint64 *gprData, double *fprData) +{ +#define PARAM_BUFFER_COUNT 16 +#define PARAM_GPR_COUNT 5 +#define PARAM_FPR_COUNT 5 + + nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; + nsXPTCMiniVariant* dispatchParams = NULL; + nsIInterfaceInfo* iface_info = NULL; + const nsXPTMethodInfo* info; + PRUint8 paramCount; + PRUint8 i; + nsresult result = NS_ERROR_FAILURE; + + NS_ASSERTION(self,"no self"); + + self->GetInterfaceInfo(&iface_info); + NS_ASSERTION(iface_info,"no interface info"); + + iface_info->GetMethodInfo(PRUint16(methodIndex), &info); + NS_ASSERTION(info,"no interface info"); + + paramCount = info->GetParamCount(); + + // setup variant array pointer + if(paramCount > PARAM_BUFFER_COUNT) + dispatchParams = new nsXPTCMiniVariant[paramCount]; + else + dispatchParams = paramBuffer; + NS_ASSERTION(dispatchParams,"no place for params"); + + PRUint64* ap = args; + PRUint32 iCount = 0; + for(i = 0; i < paramCount; i++) + { + const nsXPTParamInfo& param = info->GetParam(i); + const nsXPTType& type = param.GetType(); + nsXPTCMiniVariant* dp = &dispatchParams[i]; + + if(param.IsOut() || !type.IsArithmetic()) + { + if (iCount < PARAM_GPR_COUNT) + dp->val.p = (void*)gprData[iCount++]; + else + dp->val.p = (void*)ap++; + continue; + } + // else + switch(type) + { + case nsXPTType::T_I8: + if (iCount < PARAM_GPR_COUNT) + dp->val.i8 = (PRInt8)gprData[iCount++]; + else + dp->val.i8 = *((PRInt8*)ap++); + break; + + case nsXPTType::T_I16: + if (iCount < PARAM_GPR_COUNT) + dp->val.i16 = (PRInt16)gprData[iCount++]; + else + dp->val.i16 = *((PRInt16*)ap++); + break; + + case nsXPTType::T_I32: + if (iCount < PARAM_GPR_COUNT) + dp->val.i32 = (PRInt32)gprData[iCount++]; + else + dp->val.i32 = *((PRInt32*)ap++); + break; + + case nsXPTType::T_I64: + if (iCount < PARAM_GPR_COUNT) + dp->val.i64 = (PRInt64)gprData[iCount++]; + else + dp->val.i64 = *((PRInt64*)ap++); + break; + + case nsXPTType::T_U8: + if (iCount < PARAM_GPR_COUNT) + dp->val.u8 = (PRUint8)gprData[iCount++]; + else + dp->val.u8 = *((PRUint8*)ap++); + break; + + case nsXPTType::T_U16: + if (iCount < PARAM_GPR_COUNT) + dp->val.u16 = (PRUint16)gprData[iCount++]; + else + dp->val.u16 = *((PRUint16*)ap++); + break; + + case nsXPTType::T_U32: + if (iCount < PARAM_GPR_COUNT) + dp->val.u32 = (PRUint32)gprData[iCount++]; + else + dp->val.u32 = *((PRUint32*)ap++); + break; + + case nsXPTType::T_U64: + if (iCount < PARAM_GPR_COUNT) + dp->val.u64 = (PRUint64)gprData[iCount++]; + else + dp->val.u64 = (PRUint64)*ap++; + break; + + case nsXPTType::T_FLOAT: + if (iCount < PARAM_FPR_COUNT) + dp->val.f = (float)fprData[iCount++]; + else + dp->val.f = *((float*)ap++); + break; + + case nsXPTType::T_DOUBLE: + if (iCount < PARAM_FPR_COUNT) + dp->val.d = (double)fprData[iCount++]; + else + dp->val.d = *((double*)ap++); + break; + + case nsXPTType::T_BOOL: + if (iCount < PARAM_GPR_COUNT) + dp->val.b = (PRBool)gprData[iCount++]; + else + dp->val.b = *((PRBool*)ap++); + break; + + case nsXPTType::T_CHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.c = (char)gprData[iCount++]; + else + dp->val.c = *((char*)ap++); + break; + + case nsXPTType::T_WCHAR: + if (iCount < PARAM_GPR_COUNT) + dp->val.wc = (wchar_t)gprData[iCount++]; + else + dp->val.wc = *((wchar_t*)ap++); + break; + + default: + NS_ASSERTION(0, "bad type"); + break; + } + } + + result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams); + + NS_RELEASE(iface_info); + + if(dispatchParams != paramBuffer) + delete [] dispatchParams; + + return result; +} + +#define STUB_ENTRY(n) /* defined in the assembly file */ + +#define SENTINEL_ENTRY(n) \ +nsresult nsXPTCStubBase::Sentinel##n() \ +{ \ + NS_ASSERTION(0,"nsXPTCStubBase::Sentinel called"); \ + return NS_ERROR_NOT_IMPLEMENTED; \ +} + +#include "xptcstubsdef.inc" + +void +xptc_dummy() +{ +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s new file mode 100644 index 00000000..5f8f861d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/win32/xptcstubs_asm_alpha.s @@ -0,0 +1,120 @@ + +#define v0 $0 // return value register +#define t0 $1 // caller saved (temporary) registers +#define t1 $2 // +#define t2 $3 // +#define t3 $4 // +#define t4 $5 // +#define t5 $6 // +#define t6 $7 // +#define t7 $8 // +#define s0 $9 // callee saved (nonvolatile) registers +#define a0 $16 // argument registers +#define a1 $17 // +#define a2 $18 // +#define a3 $19 // +#define a4 $20 // +#define a5 $21 // +#define t8 $22 // caller saved (temporary) registers +#define t9 $23 // +#define t10 $24 // +#define t11 $25 // +#define ra $26 // return address register +#define sp $30 // stack pointer register +#define zero $31 // zero register +#define f16 $f16 // argument registers +#define f17 $f17 // +#define f18 $f18 // +#define f19 $f19 // +#define f20 $f20 // +#define f21 $f21 // + +#define NARGSAVE 2 +#define LOCALSZ 16 +#define SZREG 8 +#define FRAMESZ (NARGSAVE+LOCALSZ)*SZREG + + .text + .globl PrepareAndDispatch + +A1OFF=FRAMESZ-(9*SZREG) +A2OFF=FRAMESZ-(8*SZREG) +A3OFF=FRAMESZ-(7*SZREG) +A4OFF=FRAMESZ-(6*SZREG) +A5OFF=FRAMESZ-(5*SZREG) +A6OFF=FRAMESZ-(4*SZREG) //not used +A7OFF=FRAMESZ-(3*SZREG) //not used +GPOFF=FRAMESZ-(2*SZREG) //not used +RAOFF=FRAMESZ-(1*SZREG) + +F16OFF=FRAMESZ-(16*SZREG) //not used +F17OFF=FRAMESZ-(15*SZREG) +F18OFF=FRAMESZ-(14*SZREG) +F19OFF=FRAMESZ-(13*SZREG) +F20OFF=FRAMESZ-(12*SZREG) +F21OFF=FRAMESZ-(11*SZREG) +F22OFF=FRAMESZ-(10*SZREG) // not used + +#define NESTED_ENTRY(Name, fsize, retrg) \ + .text; \ + .align 4; \ + .globl Name; \ + .ent Name, 0; \ +Name:; \ + .frame sp, fsize, retrg; + +#define SENTINEL_ENTRY(nn) +#define STUB_ENTRY(nn) MAKE_PART(nn,@nsXPTCStubBase@@UAAIXZ ) + +#define MAKE_PART(aa, bb) MAKE_STUB(aa, ?Stub##aa##bb ) + +#define MAKE_STUB(nn, name) \ +NESTED_ENTRY(name, FRAMESZ,ra); \ + subl sp,FRAMESZ,sp; \ + mov nn,t0; \ + jmp sharedstub; \ +.end name; + +#include "xptcstubsdef.inc" + + .globl sharedstub + .ent sharedstub +sharedstub: + stq a1,A1OFF(sp) + stq a2,A2OFF(sp) + stq a3,A3OFF(sp) + stq a4,A4OFF(sp) + stq a5,A5OFF(sp) + stq ra,RAOFF(sp) + + stt f17,F17OFF(sp) + stt f18,F18OFF(sp) + stt f19,F19OFF(sp) + stt f20,F20OFF(sp) + stt f21,F21OFF(sp) + + // t0 is methodIndex + bis t0,zero,a1 // a1 = methodIndex + + // a2 is stack address where extra function params + // are stored that do not fit in registers + bis sp,zero,a2 //a2 = sp + addl a2,FRAMESZ,a2 //a2+=FRAMESZ + + // a3 is stack addrss of a1..a5 + bis sp,zero,a3 //a3 = sp + addl a3,A1OFF,a3 //a3+=A1OFF + + // a4 is stack address of f17..f21 + bis sp,zero,a4 //a4 = sp + addl a4,F17OFF,a4 //a4+=F17OFF + + // PrepareAndDispatch(that, methodIndex, args, gprArgs, fpArgs) + // a0 a1 a2 a3 a4 + bsr PrepareAndDispatch + ldq ra,RAOFF(sp) + addl sp,FRAMESZ,sp + ret + +.end sharedstub + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp new file mode 100644 index 00000000..f25a94e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcall.cpp @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* entry point wrappers. */ + +#if defined(XP_MAC) +#pragma export on +#endif + +#include "xptcprivate.h" + +// This method is never called and is only here so the compiler +// will generate a vtbl for this class. +// *Needed by the Irix implementation.* +NS_IMETHODIMP nsXPTCStubBase::QueryInterface(REFNSIID aIID, + void** aInstancePtr) +{ + NS_ASSERTION(0,"wowa! nsXPTCStubBase::QueryInterface called"); + return NS_ERROR_FAILURE; +} +#if defined(XP_MAC) +#pragma export off +#endif + +void +xptc_dummy2() +{ +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h new file mode 100644 index 00000000..3691fa0a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/xptcprivate.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* All the xptcall private declarations - only include locally. */ + +#ifndef xptcprivate_h___ +#define xptcprivate_h___ + +#include "xptcall.h" + +#endif /* xptcprivate_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html b/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html new file mode 100644 index 00000000..e3686999 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/status.html @@ -0,0 +1,404 @@ + + +xptcall Porting Status + + +

xptcall Porting Status

+ +

What is this?

+ +This is a status page for the multiplatform porting of xptcall. +xptcall has a +FAQ +and a +Porting Guide. + +

+ +This is being maintained by John Bandhauer <jband@netscape.com>. +Feel free to email me with questions or to volunteer to contribute xptcall code for any platform. + +

+ +Mike Shaver <shaver@mozilla.org> +is the best contact regarding 'nix (Unix, Linux, Finux, etc.) ports of xptcall. + +

Status

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusPlatformContributors and ? Possible ContributorsNotes
DoneWin32 x86Contributed code! +John Bandhauer <jband@netscape.com> + +win32
DoneLinux x86Contributed code! +John Bandhauer <jband@netscape.com>
+Contributed code! +Ulrich Drepper <drepper@cygnus.com> +
unix +
DoneFreeBSD and NetBSD x86Contributed code! +Christoph Toshok <toshok@hungry.com>,
+Contributed code! +John Bandhauer <jband@netscape.com>
unix (same as Linux 86 code)
DoneBSD/OS x86Contributed code! +Bert Driehuis <bert_driehuis@nl.compuware.com>unix (same as Linux 86 code) +Bert contributed patches that *should* do the right thing for all the unixish-x86 +versions of this code for GCC 2.7 or 2.8 vs. EGCS 1.1. He notes that the vtbl +scheme is different. He is hoping that others will help test the changes using +these two compilers on the various platforms where this same code is used. +Bert's details +
DoneMac PPCContributed code! + Roger Lawrence <rogerl@netscape.com>,
+Contributed code! +Patrick Beard <beard@netscape.com> +
mac (passing tests and checked in)
DoneSolaris SparcContributed code! +Roger Lawrence <rogerl@netscape.com>,
+Contributed code! +Chris McAfee <mcafee@netscape.com> +
unix This is checked in and working.
DoneSolaris Sparc v9 (64bit)Contributed code! +Stuart Parmenter <pavlov@netscape.com>,
+Contributed code! +Chris Seawood <cls@seawood.org> +
unix This is checked in and (pavlov claims!) working.
DoneOS/2Contributed code! +John Fairhurst <mjf35@cam.ac.uk>I never heard exactly who did what. But mozilla has been working on OS/2 +for a long time now. +
DoneOpenVMS AlphaContributed code! +Colin R. Blake <colin@theblakes.com> +Colin says this is passing all the tests on OpenVMS Alpha! +
DoneNT AlphaContributed code! +bob meader <bob@guiduck.com> +bob writes:
+Enclosed is xptcall for alpha/nt target.. +

+It is a variation of the IRIS port (only targeted for win32). +

+Notice the last 2 files (the change to mozilla\xpcom\build\makefile.win and +mozilla\xpcom\build) are needed because I was unable to figure how to do a +"declspecexport" from the assembler ASAXP ... if some knows how to do that then +those last 2 files won't be needed. +

+I have had someone look over this code at bridge.com (the entry point to +compaq/gem compiler team) and this code was given the OK. I consider it "done". +

+This code lives in the files where the name includes 'alpha' in the win32 directory.
+

DoneLinux ARMStarted +Stefan Hanske<sh990154@mail.uni-greifswald.de>
+? +Matthew Wilcox <willy@bofh.ai>
+Stefan's code is checked in and he says it is working. +
DoneLinux Sparc +Contributed code! +Anton Blanchard <anton@progsoc.uts.edu.au>, +
+Contributed code! +Roger Lawrence <rogerl@netscape.com>, +
+Maybe +Brandon Ehle <ehle.3@osu.edu> +
+Anton contributed patches to Roger's Sparc code. Anton says it works and passes the tests! +(24-Aug-1999) Brandon writes: I've finished testing XPTCALL Sparc Linux on 12 different Sparc machines and it checks out good. +
DoneLinux PPC +Contributed code! +Patrick Beard <beard@netscape.com>
+Contributed code! +Chris Waterson <waterson@netscape.com>
+Contributed code! +Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+? +Jason Y. Sproul <jsproul@condor.fddi.wesleyan.edu>
+ ? + Sean Chitwood <darkmane@w-link.net>
+waterson said: Mozilla runs on Linux/PPC +
DoneLinux Alpha +Contributed code! +Glen Nakamura <glen.nakamura@usa.net>
+Contributed code! +Dan Morril <morrildl@nycap.rr.com>
+
+Glen writes: +

+I am attaching a patch which contains my Linux Alpha xptcall code. +It passes TestXPTCInvoke and TestXPC on my machine which runs +kernel 2.2.7, glibc 2.1.1, and egcs 1.1.2. I have not tested it +with older GNU compilers such as gcc 2.8.x. From looking at the +Linux x86 code, I gather that the vtable layout is a little different +for those compilers and the code will need minor modifications +in order to work properly. +

+I am not sure how much of the code can be used for OpenVMS Alpha +and/or Digital UNIX. Currently the code is dependent on the g++ +name mangling convention and a few GNU extensions so I'm not sure +how useful it will be for the other systems. Hopefully the +comments in the code are detailed enough to help people attempting +a port. +

+

DoneSunOS x86 +Contributed code! +Arthur Jones <aljones@lbl.gov>
+? +Philip Pokorny <ppokorny@mindspring.com>
+
+The word I hear is that this is working and done +
DoneHP-UX +Contributed code! +Thomas Wang <wang@cup.hp.com>
+Contributed code! +Mike Gleeson <mgleeson1@netscape.com> +
I hear that this code is checked in and working. Though, there is some +doubt - see bug +#17997 +
DoneAIX PPCContributed code! +Jim Dunn <jdunn@netscape.com>Philip K. Warren writes:
+ +We have gone through several releases of AIX without any problems. +
DoneIrixContributed code! +Jason Heirtzler <jasonh@m7.engr.sgi.com>
+
Jason has declared this done. Jason is no longer working at SGI and will +not be maintaining this code. There is some doubt as to whether or not this is +working for everyone - see bug +#10061. +Mike Shaver <shaver@mozilla.org> +is the interim maintainer until someone more suitable can be found. +
DoneBeOS x86Contributed code! +Duncan Wilcox <duncan@be.com>
+
+unix (yet another reuse of the Linux 86 code!)
+Duncan says this is all working. He did the code for old cfront style 'this' adjustment for others to use too! +
HELP!BeOS PPC--
DoneCompaq Tru64 UNIX (Digital UNIX)Contributed code! +Steve Streeter <streeter@zk3.dec.com>
+
Code passes the tests and is checked in.
WorkingNeutrio x86Contributed code! +Jerry L. Kirk <Jerry.Kirk@Nexwarecorp.com>
+
+Patches for xptc*_unixish_x86.cpp checked in. Waiting for verification that this is really finished. +
InvestigatingSCO UW7 and OSR5 +Investigating +J. Kean Johnston <jkj@sco.com>
+Investigating +Evan Hunt <evanh@sco.com>
+
Recent (Feb-2001) email from jkj@sco.com suggests that work will be occuring soon.
WorksNetBSD/m68kContributed code! +Dave Huang <khym@bga.com>
+
+Dave's changes are in the tree. Waiting for verification that it is really finished.
Partially WorkingNetBSD/arm32Investigating +Mike Pumford <mpumford@black-star.demon.co.uk> +Mike writes:
+I have started porting to the platform based on the code for Linux ARM. The +InvokeByIndex code works correctly when used with TestXPTCInvoke. I am +currently working on making TestXPC function correctly. +

+I am doing the porting work with egcs-1.1.2 on NetBSD 1.4P (NetBSD-current +snapshot from a couple of days ago). +

HELP!linux/ia64-bug 40950
HELP!All others!--
+ +

+ +Note: I've used the symbol (?) to +indicate people who have expressed an interest in possibly contributing code. +Just because these people are listed here does not mean that they have commited +themselves to do the work. If you would like to contribute then let me +know. Feel free to email these folks and offer to help or find out what's going +on. We're all in this together. + +

+ +


+Author: John Bandhauer <jband@netscape.com>
+Last modified: 3 February 2003 + + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore new file mode 100644 index 00000000..177fd905 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestXPTCInvoke diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in new file mode 100644 index 00000000..a1bf16ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/Makefile.in @@ -0,0 +1,64 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = TestXPTC +SIMPLE_PROGRAMS = TestXPTCInvoke$(BIN_SUFFIX) +REQUIRES = xpcom \ + $(NULL) + +CPPSRCS = TestXPTCInvoke.cpp + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +# For _write(). +ifeq ($(OS_ARCH),BSD_OS) +OS_LIBS += -lgcc +endif + + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp new file mode 100644 index 00000000..79e4bc08 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/tests/TestXPTCInvoke.cpp @@ -0,0 +1,1464 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Stuart Parmenter + * Chris Seawood + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Invoke tests xptcall. */ + +#include +#include "xptcall.h" +#include "prlong.h" +#include "prinrval.h" +#include "nsMemory.h" + +// forward declration +static int DoMultipleInheritenceTest(int rcExit); +static int DoMultipleInheritenceTest2(int rcExit); +static void DoSpeedTest(); + + +#include + +static char g_szDirect[16384]; +static char g_szInvoke[16384]; +static char *g_pszBuffer = NULL; +static void bufprintf(const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + vprintf(pszFormat, va); + va_end(va); + if (g_pszBuffer) + { + size_t cchBuf = strlen(g_pszBuffer); + ssize_t cbLeft = (ssize_t)sizeof(g_szDirect) - (ssize_t)cchBuf; + if (cbLeft > 0) + { + va_list va; + va_start(va, pszFormat); + vsnprintf(&g_pszBuffer[cchBuf], (size_t)cbLeft, pszFormat, va); + va_end(va); + } + } +} + +static void setbuffer(bool fDirect) +{ + g_pszBuffer = fDirect ? g_szDirect : g_szInvoke; + *g_pszBuffer = '\0'; +} + +static int comparebuffers(int rcExit) +{ + if (strcmp(g_szDirect, g_szInvoke) == 0) + return rcExit; + size_t offLine = 0; + unsigned iLine = 1; + for (size_t off = 0; ; off++) + { + char chDirect = g_szDirect[off]; + char chInvoke = g_szInvoke[off]; + if (chDirect == chInvoke) + { + if (!chDirect) + return rcExit; + if (chDirect == '\n') + { + offLine = off + 1; + iLine++; + } + } + else + { + size_t cchDirectLine = RTStrOffCharOrTerm(&g_szDirect[offLine], '\n'); + size_t cchInvokeLine = RTStrOffCharOrTerm(&g_szInvoke[offLine], '\n'); + printf("direct and invoke runs differs on line %u!\n", iLine); + printf("direct: %*.*s\n", (int)cchDirectLine, (int)cchDirectLine, &g_szDirect[offLine]); + printf("invoke: %*.*s\n", (int)cchInvokeLine, (int)cchInvokeLine, &g_szInvoke[offLine]); + + return 1; + } + + } + printf("direct and invoke runs differs!\n"); + return 1; +} + + +// {AAC1FB90-E099-11d2-984E-006008962422} +#define INVOKETESTTARGET_IID \ +{ 0xaac1fb90, 0xe099, 0x11d2, \ + { 0x98, 0x4e, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + + +class InvokeTestTargetInterface : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(INVOKETESTTARGET_IID) + NS_IMETHOD AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) = 0; + NS_IMETHOD MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) = 0; + NS_IMETHOD AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) = 0; + NS_IMETHOD MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) = 0; + + NS_IMETHOD AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval) = 0; + + NS_IMETHOD AddTwoFloats(float p1, float p2, float* retval) = 0; + + NS_IMETHOD AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval) = 0; + + NS_IMETHOD AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval) = 0; + + NS_IMETHOD AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval) = 0; + + NS_IMETHOD AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval) = 0; + + NS_IMETHOD AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval) = 0; + + NS_IMETHOD AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval) = 0; + + NS_IMETHOD PassTwoStrings(const char* s1, const char* s2, char** retval) = 0; + +}; + +class InvokeTestTarget : public InvokeTestTargetInterface +{ +public: + NS_DECL_ISUPPORTS + NS_IMETHOD AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval); + NS_IMETHOD AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval); + NS_IMETHOD MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval); + + NS_IMETHOD AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval); + + NS_IMETHOD AddTwoFloats(float p1, float p2, float* retval); + + NS_IMETHOD AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval); + + NS_IMETHOD AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval); + + NS_IMETHOD AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval); + + NS_IMETHOD AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval); + + NS_IMETHOD AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval); + + NS_IMETHOD AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval); + + NS_IMETHOD PassTwoStrings(const char* s1, const char* s2, char** retval); + + InvokeTestTarget(); +}; + +NS_IMPL_ISUPPORTS1(InvokeTestTarget, InvokeTestTargetInterface) + +InvokeTestTarget::InvokeTestTarget() +{ + NS_ADDREF_THIS(); +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + *retval = p1 + p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::MultTwoInts(PRInt32 p1, PRInt32 p2, PRInt32* retval) +{ + *retval = p1 * p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) +{ + LL_ADD(*retval, p1, p2); + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::MultTwoLLs(PRInt64 p1, PRInt64 p2, PRInt64* retval) +{ + LL_MUL(*retval, p1, p2); + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyInts(PRInt32 p1, PRInt32 p2, PRInt32 p3, PRInt32 p4, + PRInt32 p5, PRInt32 p6, PRInt32 p7, PRInt32 p8, + PRInt32 p9, PRInt32 p10, PRInt32* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddTwoFloats(float p1, float p2, float *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f\n", p1, p2); +#endif + *retval = p1 + p2; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyDoubles(double p1, double p2, double p3, double p4, + double p5, double p6, double p7, double p8, + double p9, double p10, double* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf, %lf\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float* retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedFloats(float p1, float p2, double p3, double p4, + float p5, float p6, double p7, double p8, + float p9, double p10, float p11, + double *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %lf, %lf, %f, %f, %lf, %lf, %f, %lf, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddManyManyFloats(float p1, float p2, float p3, float p4, + float p5, float p6, float p7, float p8, + float p9, float p10, float p11, float p12, + float p13, float p14, float p15, float p16, + float p17, float p18, float p19, float p20, + float *retval) +{ +#ifdef DEBUG_TESTINVOKE + printf("%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, " + "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); +#endif + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + + p11 + p12 + p13 + p14 + p15 + p16 + p17 + p18 + p19 + p20; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedInts(PRInt64 p1, PRInt32 p2, PRInt64 p3, PRInt32 p4, + PRInt32 p5, PRInt64 p6, PRInt32 p7, PRInt32 p8, + PRInt64 p9, PRInt32 p10, PRInt64* retval) +{ + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::AddMixedInts2(PRInt32 p1, PRInt64 p2, PRInt32 p3, PRInt64 p4, + PRInt64 p5, PRInt32 p6, PRInt64 p7, PRInt64 p8, + PRInt32 p9, PRInt64 p10, PRInt64* retval) +{ + *retval = p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10; + return NS_OK; +} + +NS_IMETHODIMP +InvokeTestTarget::PassTwoStrings(const char* s1, const char* s2, char** retval) +{ + const char milk[] = "milk"; + char *ret = (char*)nsMemory::Alloc(sizeof(milk)); + if (!ret) + return NS_ERROR_OUT_OF_MEMORY; + strncpy(ret, milk, sizeof(milk)); + printf("\t%s %s", s1, s2); + *retval = ret; + return NS_OK; +} + +int main() +{ + InvokeTestTarget *test = new InvokeTestTarget(); + + /* here we make the global 'check for alloc failure' checker happy */ + if(!test) + return 1; + + PRInt32 out, tmp32 = 0; + PRInt64 out64; + printf("calling direct:\n"); + setbuffer(true); + if(NS_SUCCEEDED(test->AddTwoInts(1,1,&out))) + bufprintf("\t1 + 1 = %d\n", out); + else + bufprintf("\tFAILED"); + PRInt64 one, two; + LL_I2L(one, 1); + LL_I2L(two, 2); + if(NS_SUCCEEDED(test->AddTwoLLs(one,one,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1L + 1L = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + if(NS_SUCCEEDED(test->MultTwoInts(2,2,&out))) + bufprintf("\t2 * 2 = %d\n", out); + else + bufprintf("\tFAILED"); + if(NS_SUCCEEDED(test->MultTwoLLs(two,two,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t2L * 2L = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + double outD; + float outF; + PRInt32 outI; + char *outS; + + if(NS_SUCCEEDED(test->AddManyInts(1,2,3,4,5,6,7,8,9,10,&outI))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", outI); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddTwoFloats(1,2,&outF))) + bufprintf("\t1 + 2 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyDoubles(1,2,3,4,5,6,7,8,9,10,&outD))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %f\n", outD); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyFloats(1,2,3,4,5,6,7,8,9,10,&outF))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddManyManyFloats(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,&outF))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 = %ff\n", (double)outF); + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedInts(1,2,3,4,5,6,7,8,9,10,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedInts2(1,2,3,4,5,6,7,8,9,10,&out64))) + { + LL_L2I(tmp32, out64); + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", (int)tmp32); + } + else + bufprintf("\tFAILED"); + + if(NS_SUCCEEDED(test->AddMixedFloats(1,2,3,4,5,6,7,8,9,10,11,&outD))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 = %f\n", (double)outD); + else + bufprintf("\tFAILED"); + + if (NS_SUCCEEDED(test->PassTwoStrings("moo","cow",&outS))) { + bufprintf(" = %s\n", outS); + nsMemory::Free(outS); + } else + bufprintf("\tFAILED"); + + printf("calling via invoke:\n"); + setbuffer(false); + + nsXPTCVariant var[21]; + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 1; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 3, 3, var))) + bufprintf("\t1 + 1 = %d\n", var[2].val.i32); + else + bufprintf("\tFAILED"); + + LL_I2L(var[0].val.i64, 1); + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + LL_I2L(var[1].val.i64, 1); + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + LL_I2L(var[2].val.i64, 0); + var[2].type = nsXPTType::T_I64; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 5, 3, var))) + bufprintf("\t1L + 1L = %d\n", (int)var[2].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 4, 3, var))) + bufprintf("\t2 * 2 = %d\n", var[2].val.i32); + else + bufprintf("\tFAILED"); + + LL_I2L(var[0].val.i64,2); + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + LL_I2L(var[1].val.i64,2); + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + LL_I2L(var[2].val.i64,0); + var[2].type = nsXPTType::T_I64; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 6, 3, var))) + bufprintf("\t2L * 2L = %d\n", (int)var[2].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 3; + var[2].type = nsXPTType::T_I32; + var[2].flags = 0; + + var[3].val.i32 = 4; + var[3].type = nsXPTType::T_I32; + var[3].flags = 0; + + var[4].val.i32 = 5; + var[4].type = nsXPTType::T_I32; + var[4].flags = 0; + + var[5].val.i32 = 6; + var[5].type = nsXPTType::T_I32; + var[5].flags = 0; + + var[6].val.i32 = 7; + var[6].type = nsXPTType::T_I32; + var[6].flags = 0; + + var[7].val.i32 = 8; + var[7].type = nsXPTType::T_I32; + var[7].flags = 0; + + var[8].val.i32 = 9; + var[8].type = nsXPTType::T_I32; + var[8].flags = 0; + + var[9].val.i32 = 10; + var[9].type = nsXPTType::T_I32; + var[9].flags = 0; + + var[10].val.i32 = 0; + var[10].type = nsXPTType::T_I32; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i32; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 7, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + var[10].val.i32); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 0.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 8, 3, var))) + bufprintf("\t1 + 2 = %ff\n", + (double) var[2].val.f); + + + var[0].val.d = 1.0; + var[0].type = nsXPTType::T_DOUBLE; + var[0].flags = 0; + + var[1].val.d = 2.0; + var[1].type = nsXPTType::T_DOUBLE; + var[1].flags = 0; + + var[2].val.d = 3.0; + var[2].type = nsXPTType::T_DOUBLE; + var[2].flags = 0; + + var[3].val.d = 4.0; + var[3].type = nsXPTType::T_DOUBLE; + var[3].flags = 0; + + var[4].val.d = 5.0; + var[4].type = nsXPTType::T_DOUBLE; + var[4].flags = 0; + + var[5].val.d = 6.0; + var[5].type = nsXPTType::T_DOUBLE; + var[5].flags = 0; + + var[6].val.d = 7.0; + var[6].type = nsXPTType::T_DOUBLE; + var[6].flags = 0; + + var[7].val.d = 8.0; + var[7].type = nsXPTType::T_DOUBLE; + var[7].flags = 0; + + var[8].val.d = 9.0; + var[8].type = nsXPTType::T_DOUBLE; + var[8].flags = 0; + + var[9].val.d = 10.0; + var[9].type = nsXPTType::T_DOUBLE; + var[9].flags = 0; + + var[10].val.d = 0.0; + var[10].type = nsXPTType::T_DOUBLE; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.d; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 9, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %f\n", + var[10].val.d); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 3.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = 0; + + var[3].val.f = 4.0f; + var[3].type = nsXPTType::T_FLOAT; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.f = 7.0f; + var[6].type = nsXPTType::T_FLOAT; + var[6].flags = 0; + + var[7].val.f = 8.0f; + var[7].type = nsXPTType::T_FLOAT; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.f = 10.0f; + var[9].type = nsXPTType::T_FLOAT; + var[9].flags = 0; + + var[10].val.f = 0.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 10, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %ff\n", + (double) var[10].val.f); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.f = 3.0f; + var[2].type = nsXPTType::T_FLOAT; + var[2].flags = 0; + + var[3].val.f = 4.0f; + var[3].type = nsXPTType::T_FLOAT; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.f = 7.0f; + var[6].type = nsXPTType::T_FLOAT; + var[6].flags = 0; + + var[7].val.f = 8.0f; + var[7].type = nsXPTType::T_FLOAT; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.f = 10.0f; + var[9].type = nsXPTType::T_FLOAT; + var[9].flags = 0; + + var[10].val.f = 11.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = 0; + + var[11].val.f = 12.0f; + var[11].type = nsXPTType::T_FLOAT; + var[11].flags = 0; + + var[12].val.f = 13.0f; + var[12].type = nsXPTType::T_FLOAT; + var[12].flags = 0; + + var[13].val.f = 14.0f; + var[13].type = nsXPTType::T_FLOAT; + var[13].flags = 0; + + var[14].val.f = 15.0f; + var[14].type = nsXPTType::T_FLOAT; + var[14].flags = 0; + + var[15].val.f = 16.0f; + var[15].type = nsXPTType::T_FLOAT; + var[15].flags = 0; + + var[16].val.f = 17.0f; + var[16].type = nsXPTType::T_FLOAT; + var[16].flags = 0; + + var[17].val.f = 18.0f; + var[17].type = nsXPTType::T_FLOAT; + var[17].flags = 0; + + var[18].val.f = 19.0f; + var[18].type = nsXPTType::T_FLOAT; + var[18].flags = 0; + + var[19].val.f = 20.0f; + var[19].type = nsXPTType::T_FLOAT; + var[19].flags = 0; + + var[20].val.f = 0.0f; + var[20].type = nsXPTType::T_FLOAT; + var[20].flags = nsXPTCVariant::PTR_IS_DATA; + var[20].ptr = &var[20].val.f; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 11, 21, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 = %ff\n", + (double) var[20].val.f); + + var[0].val.i64 = 1; + var[0].type = nsXPTType::T_I64; + var[0].flags = 0; + + var[1].val.i32 = 2; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i64 = 3; + var[2].type = nsXPTType::T_I64; + var[2].flags = 0; + + var[3].val.i32 = 4; + var[3].type = nsXPTType::T_I32; + var[3].flags = 0; + + var[4].val.i32 = 5; + var[4].type = nsXPTType::T_I32; + var[4].flags = 0; + + var[5].val.i64 = 6; + var[5].type = nsXPTType::T_I64; + var[5].flags = 0; + + var[6].val.i32 = 7; + var[6].type = nsXPTType::T_I32; + var[6].flags = 0; + + var[7].val.i32 = 8; + var[7].type = nsXPTType::T_I32; + var[7].flags = 0; + + var[8].val.i64 = 9; + var[8].type = nsXPTType::T_I64; + var[8].flags = 0; + + var[9].val.i32 = 10; + var[9].type = nsXPTType::T_I32; + var[9].flags = 0; + + var[10].val.i64 = 0; + var[10].type = nsXPTType::T_I64; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 12, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + (int)var[10].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i64 = 2; + var[1].type = nsXPTType::T_I64; + var[1].flags = 0; + + var[2].val.i32 = 3; + var[2].type = nsXPTType::T_I32; + var[2].flags = 0; + + var[3].val.i64 = 4; + var[3].type = nsXPTType::T_I64; + var[3].flags = 0; + + var[4].val.i64 = 5; + var[4].type = nsXPTType::T_I64; + var[4].flags = 0; + + var[5].val.i32 = 6; + var[5].type = nsXPTType::T_I32; + var[5].flags = 0; + + var[6].val.i64 = 7; + var[6].type = nsXPTType::T_I64; + var[6].flags = 0; + + var[7].val.i64 = 8; + var[7].type = nsXPTType::T_I64; + var[7].flags = 0; + + var[8].val.i32 = 9; + var[8].type = nsXPTType::T_I32; + var[8].flags = 0; + + var[9].val.i64 = 10; + var[9].type = nsXPTType::T_I64; + var[9].flags = 0; + + var[10].val.i64 = 0; + var[10].type = nsXPTType::T_I64; + var[10].flags = nsXPTCVariant::PTR_IS_DATA; + var[10].ptr = &var[10].val.i64; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 13, 11, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = %d\n", + (int)var[10].val.i64); + else + bufprintf("\tFAILED"); + + var[0].val.f = 1.0f; + var[0].type = nsXPTType::T_FLOAT; + var[0].flags = 0; + + var[1].val.f = 2.0f; + var[1].type = nsXPTType::T_FLOAT; + var[1].flags = 0; + + var[2].val.d = 3.0; + var[2].type = nsXPTType::T_DOUBLE; + var[2].flags = 0; + + var[3].val.d = 4.0; + var[3].type = nsXPTType::T_DOUBLE; + var[3].flags = 0; + + var[4].val.f = 5.0f; + var[4].type = nsXPTType::T_FLOAT; + var[4].flags = 0; + + var[5].val.f = 6.0f; + var[5].type = nsXPTType::T_FLOAT; + var[5].flags = 0; + + var[6].val.d = 7.0; + var[6].type = nsXPTType::T_DOUBLE; + var[6].flags = 0; + + var[7].val.d = 8.0; + var[7].type = nsXPTType::T_DOUBLE; + var[7].flags = 0; + + var[8].val.f = 9.0f; + var[8].type = nsXPTType::T_FLOAT; + var[8].flags = 0; + + var[9].val.d = 10.0; + var[9].type = nsXPTType::T_DOUBLE; + var[9].flags = 0; + + var[10].val.f = 11.0f; + var[10].type = nsXPTType::T_FLOAT; + var[10].flags = 0; + + var[11].val.d = 0.0; + var[11].type = nsXPTType::T_DOUBLE; + var[11].flags = nsXPTCVariant::PTR_IS_DATA; + var[11].ptr = &var[11].val.d; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 14, 12, var))) + bufprintf("\t1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 = %f\n", + var[11].val.d); + else + bufprintf("\tFAILED"); + + var[0].val.p = (void*)"moo"; + var[0].type = nsXPTType::T_CHAR_STR; + var[0].flags = 0; + + var[1].val.p = (void*)"cow"; + var[1].type = nsXPTType::T_CHAR_STR; + var[1].flags = 0; + + var[2].val.p = 0; + var[2].type = nsXPTType::T_CHAR_STR; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.p; + + if(NS_SUCCEEDED(XPTC_InvokeByIndex(test, 15, 3, var))) + { + bufprintf(" = %s\n", var[2].val.p); + nsMemory::Free(var[2].val.p); + } + else + bufprintf("\tFAILED"); + int rcExit = comparebuffers(0); + + rcExit = DoMultipleInheritenceTest(rcExit); + rcExit = DoMultipleInheritenceTest2(rcExit); + // Disabled by default - takes too much time on slow machines + //DoSpeedTest(); + + NS_RELEASE(test); + + return rcExit; +} + +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ + +// {491C65A0-3317-11d3-9885-006008962422} +#define FOO_IID \ +{ 0x491c65a0, 0x3317, 0x11d3, \ + { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + +// {491C65A1-3317-11d3-9885-006008962422} +#define BAR_IID \ +{ 0x491c65a1, 0x3317, 0x11d3, \ + { 0x98, 0x85, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } } + +/***************************/ + +class nsIFoo : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(FOO_IID) + NS_IMETHOD FooMethod1(PRInt32 i) = 0; + NS_IMETHOD FooMethod2(PRInt32 i) = 0; +}; + +class nsIBar : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(BAR_IID) + NS_IMETHOD BarMethod1(PRInt32 i) = 0; + NS_IMETHOD BarMethod2(PRInt32 i) = 0; +}; + +/***************************/ + +class FooImpl : public nsIFoo +{ +public: + NS_IMETHOD FooMethod1(PRInt32 i); + NS_IMETHOD FooMethod2(PRInt32 i); + + FooImpl(); + +protected: + ~FooImpl() {} + +public: + virtual const char* ImplName() = 0; + + int SomeData1; + int SomeData2; + const char* Name; +}; + +class BarImpl : public nsIBar +{ +public: + NS_IMETHOD BarMethod1(PRInt32 i); + NS_IMETHOD BarMethod2(PRInt32 i); + + BarImpl(); + +protected: + ~BarImpl() {} + +public: + virtual const char * ImplName() = 0; + + int SomeData1; + int SomeData2; + const char* Name; +}; + +/***************************/ + +FooImpl::FooImpl() : Name("FooImpl") +{ +} + +NS_IMETHODIMP FooImpl::FooMethod1(PRInt32 i) +{ + bufprintf("\tFooImpl::FooMethod1 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +NS_IMETHODIMP FooImpl::FooMethod2(PRInt32 i) +{ + bufprintf("\tFooImpl::FooMethod2 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +/***************************/ + +BarImpl::BarImpl() : Name("BarImpl") +{ +} + +NS_IMETHODIMP BarImpl::BarMethod1(PRInt32 i) +{ + bufprintf("\tBarImpl::BarMethod1 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +NS_IMETHODIMP BarImpl::BarMethod2(PRInt32 i) +{ + bufprintf("\tBarImpl::BarMethod2 called with i == %d, %s part of a %s\n", + i, Name, ImplName()); + return NS_OK; +} + +/***************************/ + +class FooBarImpl : public FooImpl, public BarImpl +{ +public: + NS_DECL_ISUPPORTS + + const char* ImplName(); + + FooBarImpl(); + +private: + ~FooBarImpl() {} + +public: + const char* MyName; +}; + +FooBarImpl::FooBarImpl() : MyName("FooBarImpl") +{ + NS_ADDREF_THIS(); +} + +const char* FooBarImpl::ImplName() +{ + return MyName; +} + +NS_IMETHODIMP +FooBarImpl::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + *aInstancePtr = NULL; + + + if (aIID.Equals(NS_GET_IID(nsIFoo))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIFoo*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIBar))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIBar*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + + if (aIID.Equals(NS_GET_IID(nsISupports))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsIFoo*,this)); + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(FooBarImpl) +NS_IMPL_RELEASE(FooBarImpl) + + +static int DoMultipleInheritenceTest(int rcExit) +{ + FooBarImpl* impl = new FooBarImpl(); + if(!impl) + return 1; + + nsIFoo* foo; + nsIBar* bar; + + nsXPTCVariant var[1]; + + printf("\n"); + if(NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIFoo), (void**)&foo)) && + NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIBar), (void**)&bar))) + { + printf("impl == %p\n", impl); + printf("foo == %p\n", foo); + printf("bar == %p\n", bar); + + printf("Calling Foo...\n"); + printf("direct calls:\n"); + setbuffer(true); + foo->FooMethod1(1); + foo->FooMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + printf("Calling Bar...\n"); + printf("direct calls:\n"); + setbuffer(true); + bar->BarMethod1(1); + bar->BarMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + NS_RELEASE(foo); + NS_RELEASE(bar); + } + else + rcExit = 1; + NS_RELEASE(impl); + return rcExit; +} +/***************************************************************************/ +/***************************************************************************/ +/***************************************************************************/ +/* This is a variation on the theme submitted by duncan@be.com (Duncan Wilcox). +* He was seeing the other test work and this test not work. They should both +* Work on any given platform +*/ + +class nsIFoo2 : public nsISupports +{ +public: + NS_IMETHOD FooMethod1(PRInt32 i) = 0; + NS_IMETHOD FooMethod2(PRInt32 i) = 0; +}; + +class nsIBar2 : public nsISupports +{ +public: + NS_IMETHOD BarMethod1(PRInt32 i) = 0; + NS_IMETHOD BarMethod2(PRInt32 i) = 0; +}; + +class FooBarImpl2 : public nsIFoo2, public nsIBar2 +{ +public: + // Foo interface + NS_IMETHOD FooMethod1(PRInt32 i); + NS_IMETHOD FooMethod2(PRInt32 i); + + // Bar interface + NS_IMETHOD BarMethod1(PRInt32 i); + NS_IMETHOD BarMethod2(PRInt32 i); + + NS_DECL_ISUPPORTS + + FooBarImpl2(); + +private: + ~FooBarImpl2() {} + +public: + PRInt32 value; +}; + +FooBarImpl2::FooBarImpl2() : value(0x12345678) +{ + NS_ADDREF_THIS(); +} + +NS_IMETHODIMP FooBarImpl2::FooMethod1(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::FooMethod1 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::FooMethod2(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::FooMethod2 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::BarMethod1(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::BarMethod1 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP FooBarImpl2::BarMethod2(PRInt32 i) +{ + bufprintf("\tFooBarImpl2::BarMethod2 called with i == %d, local value = %x\n", + i, value); + return NS_OK; +} + +NS_IMETHODIMP +FooBarImpl2::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (NULL == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + *aInstancePtr = NULL; + + + if (aIID.Equals(NS_GET_IID(nsIFoo))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIFoo2*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + if (aIID.Equals(NS_GET_IID(nsIBar))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsIBar2*,this); + NS_ADDREF_THIS(); + return NS_OK; + } + + if (aIID.Equals(NS_GET_IID(nsISupports))) { + *aInstancePtr = (void*) NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsIFoo2*,this)); + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMPL_ADDREF(FooBarImpl2) +NS_IMPL_RELEASE(FooBarImpl2) + +static int DoMultipleInheritenceTest2(int rcExit) +{ + FooBarImpl2* impl = new FooBarImpl2(); + if(!impl) + return 1; + + nsIFoo2* foo; + nsIBar2* bar; + + nsXPTCVariant var[1]; + + printf("\n"); + if(NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIFoo), (void**)&foo)) && + NS_SUCCEEDED(impl->QueryInterface(NS_GET_IID(nsIBar), (void**)&bar))) + { + printf("impl == %p\n", impl); + printf("foo == %p\n", foo); + printf("bar == %p\n", bar); + + printf("Calling Foo...\n"); + printf("direct calls:\n"); + setbuffer(true); + foo->FooMethod1(1); + foo->FooMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(foo, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + printf("Calling Bar...\n"); + printf("direct calls:\n"); + setbuffer(true); + bar->BarMethod1(1); + bar->BarMethod2(2); + + printf("invoke calls:\n"); + setbuffer(false); + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 3, 1, var); + + var[0].val.i32 = 2; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + XPTC_InvokeByIndex(bar, 4, 1, var); + + rcExit = comparebuffers(rcExit); + printf("\n"); + + NS_RELEASE(foo); + NS_RELEASE(bar); + } + else + rcExit = 1; + NS_RELEASE(impl); + return rcExit; +} + +static void DoSpeedTest() +{ + InvokeTestTarget *test = new InvokeTestTarget(); + + nsXPTCVariant var[3]; + + var[0].val.i32 = 1; + var[0].type = nsXPTType::T_I32; + var[0].flags = 0; + + var[1].val.i32 = 1; + var[1].type = nsXPTType::T_I32; + var[1].flags = 0; + + var[2].val.i32 = 0; + var[2].type = nsXPTType::T_I32; + var[2].flags = nsXPTCVariant::PTR_IS_DATA; + var[2].ptr = &var[2].val.i32; + + PRInt32 in1 = 1; + PRInt32 in2 = 1; + PRInt32 out; + + // Crank this number down if your platform is slow :) + static const int count = 100000000; + int i; + PRIntervalTime start; + PRIntervalTime interval_direct; + PRIntervalTime interval_invoke; + + printf("Speed test...\n\n"); + printf("Doing %d direct call iterations...\n", count); + start = PR_IntervalNow(); + for(i = count; i; i--) + (void)test->AddTwoInts(in1, in2, &out); + interval_direct = PR_IntervalNow() - start; + + printf("Doing %d invoked call iterations...\n", count); + start = PR_IntervalNow(); + for(i = count; i; i--) + (void)XPTC_InvokeByIndex(test, 3, 3, var); + interval_invoke = PR_IntervalNow() - start; + + printf(" direct took %0.2f seconds\n", + (double)interval_direct/(double)PR_TicksPerSecond()); + printf(" invoke took %0.2f seconds\n", + (double)interval_invoke/(double)PR_TicksPerSecond()); + printf(" So, invoke overhead was ~ %0.2f seconds (~ %0.0f%%)\n", + (double)(interval_invoke-interval_direct)/(double)PR_TicksPerSecond(), + (double)(interval_invoke-interval_direct)/(double)interval_invoke*100); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in new file mode 100644 index 00000000..d7e3b9c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = public src + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in new file mode 100644 index 00000000..dbf13d8b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/Makefile.in @@ -0,0 +1,66 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1999 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +XPIDL_MODULE = xpcom_xpti + +GRE_MODULE = 1 + +EXPORTS = \ + xptinfo.h \ + $(NULL) + +XPIDLSRCS = \ + nsIInterfaceInfo.idl \ + nsIInterfaceInfoManager.idl \ + nsIXPTLoader.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +include $(topsrcdir)/config/rules.mk + +CFLAGS += -DEXPORT_XPCI_API + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl new file mode 100644 index 00000000..f77dbcfc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfo.idl @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The nsIInterfaceInfo public declaration. */ + + +#include "nsISupports.idl" + +// forward declaration of non-XPCOM types + +[ptr] native nsXPTMethodInfoPtr(nsXPTMethodInfo); +[ptr] native nsXPTConstantPtr(nsXPTConstant); +[ptr] native nsXPTParamInfoPtr(nsXPTParamInfo); + native nsXPTType(nsXPTType); + +// We bend the rules to do a [shared] nsIID (but this is never scriptable) +[ptr] native nsIIDPtrShared(nsIID); + +%{C++ +class nsXPTMethodInfo; +class nsXPTConstant; +class nsXPTParamInfo; +class nsXPTType; +%} + +/* this is NOT intended to be scriptable */ +[uuid(215DBE04-94A7-11d2-BA58-00805F8A5DD7)] +interface nsIInterfaceInfo : nsISupports +{ + readonly attribute string name; + readonly attribute nsIIDPtr InterfaceIID; + + PRBool isScriptable(); + + readonly attribute nsIInterfaceInfo parent; + + /** + * These include counts for parent (and all ancestors). + */ + readonly attribute PRUint16 methodCount; + readonly attribute PRUint16 constantCount; + + /** + * These include methods and constants for parent (and all ancestors). + * + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + void getMethodInfo(in PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getMethodInfoForName(in string methodName, out PRUint16 index, + [shared, retval] out nsXPTMethodInfoPtr info); + + void getConstant(in PRUint16 index, + [shared, retval] out nsXPTConstantPtr constant); + + + /** + * Get the interface information or iid associated with a param of some + * method in this interface. + */ + + nsIInterfaceInfo getInfoForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + nsIIDPtr getIIDForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + + /** + * These do *not* make copies ***explicit bending of XPCOM rules***. + */ + + nsXPTType getTypeForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getSizeIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getLengthIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + in PRUint16 dimension); + + PRUint8 getInterfaceIsArgNumberForParam(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param); + + PRBool isIID(in nsIIDPtr IID); + + void getNameShared([shared,retval] out string name); + void getIIDShared([shared,retval] out nsIIDPtrShared iid); + + PRBool isFunction(); + + PRBool hasAncestor(in nsIIDPtr iid); + + [notxpcom] nsresult getIIDForParamNoAlloc(in PRUint16 methodIndex, + [const] in nsXPTParamInfoPtr param, + out nsIID iid); +}; + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl new file mode 100644 index 00000000..48277691 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIInterfaceInfoManager.idl @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* The nsIInterfaceInfoManager public declaration. */ + + +#include "nsISupports.idl" +#include "nsIInterfaceInfo.idl" +#include "nsIEnumerator.idl" +#include "nsISimpleEnumerator.idl" + +/* this is NOT intended to be scriptable */ +[uuid(8B161900-BE2B-11d2-9831-006008962422)] +interface nsIInterfaceInfoManager : nsISupports +{ + nsIInterfaceInfo getInfoForIID(in nsIIDPtr iid); + nsIInterfaceInfo getInfoForName(in string name); + + nsIIDPtr getIIDForName(in string name); + string getNameForIID(in nsIIDPtr iid); + + nsIEnumerator enumerateInterfaces(); + + void autoRegisterInterfaces(); + + nsIEnumerator enumerateInterfacesWhoseNamesStartWith(in string prefix); +}; + +[uuid(0ee22850-bc6a-11d5-9134-0010a4e73d9a)] +interface nsIInterfaceInfoSuperManager : nsIInterfaceInfoManager +{ + void addAdditionalManager(in nsIInterfaceInfoManager manager); + void removeAdditionalManager(in nsIInterfaceInfoManager manager); + + PRBool hasAdditionalManagers(); + nsISimpleEnumerator enumerateAdditionalManagers(); +}; + +%{C++ +#define NS_INTERFACEINFOMANAGER_SERVICE_CLASSNAME \ + "Interface Information Manager Service" + +#define NS_INTERFACEINFOMANAGER_SERVICE_CID \ + { /* 13bef784-f8e0-4f96-85c1-09f9ef4f9a19 */ \ + 0x13bef784, 0xf8e0, 0x4f96, \ + {0x85, 0xc1, 0x09, 0xf9, 0xef, 0x4f, 0x9a, 0x19} } + +#define NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID \ + "@mozilla.org/xpti/interfaceinfomanager-service;1" +%} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl new file mode 100644 index 00000000..8918daa3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/nsIXPTLoader.idl @@ -0,0 +1,100 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 external XPT loader interface. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corp. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * Alec Flett + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsILocalFile.idl" +#include "nsIInputStream.idl" + +/** + * Implement nsIXPTLoaderSink if you want to enumerate the entries in + * an XPT archive of some kind + */ +[scriptable, uuid(6E48C500-8682-4730-ADD6-7DB693B9E7BA)] +interface nsIXPTLoaderSink : nsISupports { + + /** + * called by the loader for each entry in the archive + * @param itemName the name of this particular item in the archive + * @param index the index of the item inthe archive + * @param stream contains the contents of the xpt file + */ + void foundEntry(in string itemName, + in long index, + in nsIInputStream xptData); +}; + +/** + * The XPT loader interface: implemented by a loader to grab an input + * stream which will be consumed by the interface loader. + */ +[scriptable, uuid(368A15D9-17A9-4c2b-AC3D-A35B3A22B876)] +interface nsIXPTLoader : nsISupports { + /** + * enumerate entries in the given archive + * for each entry found, the loader will call the sink's + * foundEntry() method with the appropriate information and a + * stream that the consumer can read from + * @param file the file to read from + * @param sink an object which will be called with each file found + * in the file + */ + void enumerateEntries(in nsILocalFile file, + in nsIXPTLoaderSink sink ); + + /** + * Load a specific entry from the archive + * @param file the file to read from + * @param name the name of the xpt within the file + * @return an input stream that will read the raw xpt data from + * the file + */ + nsIInputStream loadEntry(in nsILocalFile file, + in string name); +}; + + +%{C++ + +// the first part of the contractID for any loader +// append the type of loader that you need, such as "zip" +#define NS_XPTLOADER_CONTRACTID_PREFIX \ + "@mozilla.org/xptinfo/loader;1&type=" + +%} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h new file mode 100644 index 00000000..076482a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/public/xptinfo.h @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* XPTI_PUBLIC_API and XPTI_GetInterfaceInfoManager declarations. */ + +#ifndef xptiinfo_h___ +#define xptiinfo_h___ + +#include "prtypes.h" +#include "xpt_struct.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPTI_GetInterfaceInfoManager VBoxNsxpXPTI_GetInterfaceInfoManager +#define XPTI_FreeInterfaceInfoManager VBoxNsxpXPTI_FreeInterfaceInfoManager +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* + * The linkage of XPTI API functions differs depending on whether the file is + * used within the XPTI library or not. Any source file within the XPTI + * library should define EXPORT_XPTI_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPTI_API +#define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPTI_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#if defined(_WIN32) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_EXPORT __declspec(dllexport) +#elif defined(XP_OS2_VACPP) +# define XPTI_EXPORT extern +#else +# define XPTI_EXPORT +#endif +#else +#if defined(_WIN32) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2) && defined(__declspec) +# define XPTI_PUBLIC_API(t) __declspec(dllimport) t +# define XPTI_PUBLIC_DATA(t) __declspec(dllimport) t +# define XPTI_EXPORT __declspec(dllimport) +#elif defined(XP_OS2_VACPP) +# define XPTI_PUBLIC_API(t) extern t +# define XPTI_PUBLIC_DATA(t) extern t +# define XPTI_EXPORT extern +#else +# define XPTI_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPTI_PUBLIC_DATA(t) t +# define XPTI_EXPORT +#endif +#endif +#define XPTI_FRIEND_API(t) XPTI_PUBLIC_API(t) +#define XPTI_FRIEND_DATA(t) XPTI_PUBLIC_DATA(t) + +class nsIInterfaceInfoManager; +PR_BEGIN_EXTERN_C +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager(); + +// Even if this is a service, it is cool to provide a direct accessor +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager(); +PR_END_EXTERN_C + + + +// Flyweight wrapper classes for xpt_struct.h structs. +// Everything here is dependent upon - and sensitive to changes in - +// xpcom/typelib/xpt/public/xpt_struct.h! + +class nsXPTType : public XPTTypeDescriptorPrefix +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTType() + {} // random contents + nsXPTType(const XPTTypeDescriptorPrefix& prefix) + {*(XPTTypeDescriptorPrefix*)this = prefix;} + + nsXPTType(const uint8& prefix) + {*(uint8*)this = prefix;} + + nsXPTType& operator=(uint8 val) + {flags = val; return *this;} + + nsXPTType& operator=(const nsXPTType& other) + {flags = other.flags; return *this;} + + operator uint8() const + {return flags;} + + PRBool IsPointer() const + {return 0 != (XPT_TDP_IS_POINTER(flags));} + + PRBool IsUniquePointer() const + {return 0 != (XPT_TDP_IS_UNIQUE_POINTER(flags));} + + PRBool IsReference() const + {return 0 != (XPT_TDP_IS_REFERENCE(flags));} + + PRBool IsArithmetic() const // terminology from Harbison/Steele + {return flags <= T_WCHAR;} + + PRBool IsInterfacePointer() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE: + case T_INTERFACE_IS: + return PR_TRUE; + } + } + + PRBool IsArray() const + {return (PRBool) TagPart() == T_ARRAY;} + + // 'Dependent' means that params of this type are dependent upon other + // params. e.g. an T_INTERFACE_IS is dependent upon some other param at + // runtime to say what the interface type of this param really is. + PRBool IsDependent() const + { switch (TagPart()) { + default: + return PR_FALSE; + case T_INTERFACE_IS: + case TD_ARRAY: + case T_PSTRING_SIZE_IS: + case T_PWSTRING_SIZE_IS: + return PR_TRUE; + } + } + + uint8 TagPart() const + {return (uint8) (flags & XPT_TDP_TAGMASK);} + + enum + { + T_I8 = TD_INT8 , + T_I16 = TD_INT16 , + T_I32 = TD_INT32 , + T_I64 = TD_INT64 , + T_U8 = TD_UINT8 , + T_U16 = TD_UINT16 , + T_U32 = TD_UINT32 , + T_U64 = TD_UINT64 , + T_FLOAT = TD_FLOAT , + T_DOUBLE = TD_DOUBLE , + T_BOOL = TD_BOOL , + T_CHAR = TD_CHAR , + T_WCHAR = TD_WCHAR , + T_VOID = TD_VOID , + T_IID = TD_PNSIID , + T_DOMSTRING = TD_DOMSTRING , + T_CHAR_STR = TD_PSTRING , + T_WCHAR_STR = TD_PWSTRING , + T_INTERFACE = TD_INTERFACE_TYPE , + T_INTERFACE_IS = TD_INTERFACE_IS_TYPE, + T_ARRAY = TD_ARRAY , + T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS , + T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS , + T_UTF8STRING = TD_UTF8STRING , + T_CSTRING = TD_CSTRING , + T_ASTRING = TD_ASTRING + }; +// NO DATA - this a flyweight wrapper +}; + +class nsXPTParamInfo : public XPTParamDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTParamInfo(const XPTParamDescriptor& desc) + {*(XPTParamDescriptor*)this = desc;} + + + PRBool IsIn() const {return 0 != (XPT_PD_IS_IN(flags));} + PRBool IsOut() const {return 0 != (XPT_PD_IS_OUT(flags));} + PRBool IsRetval() const {return 0 != (XPT_PD_IS_RETVAL(flags));} + PRBool IsShared() const {return 0 != (XPT_PD_IS_SHARED(flags));} + PRBool IsDipper() const {return 0 != (XPT_PD_IS_DIPPER(flags));} + const nsXPTType GetType() const {return type.prefix;} + + // NOTE: other activities on types are done via methods on nsIInterfaceInfo + +private: + nsXPTParamInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +class nsXPTMethodInfo : public XPTMethodDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTMethodInfo(const XPTMethodDescriptor& desc) + {*(XPTMethodDescriptor*)this = desc;} + + PRBool IsGetter() const {return 0 != (XPT_MD_IS_GETTER(flags) );} + PRBool IsSetter() const {return 0 != (XPT_MD_IS_SETTER(flags) );} + PRBool IsNotXPCOM() const {return 0 != (XPT_MD_IS_NOTXPCOM(flags));} + PRBool IsConstructor() const {return 0 != (XPT_MD_IS_CTOR(flags) );} + PRBool IsHidden() const {return 0 != (XPT_MD_IS_HIDDEN(flags) );} + const char* GetName() const {return name;} + uint8 GetParamCount() const {return num_args;} + /* idx was index before I got _sick_ of the warnings on Unix, sorry jband */ + const nsXPTParamInfo GetParam(uint8 idx) const + { + NS_PRECONDITION(idx < GetParamCount(),"bad arg"); + return params[idx]; + } + const nsXPTParamInfo GetResult() const + {return *result;} +private: + nsXPTMethodInfo(); // no implementation +// NO DATA - this a flyweight wrapper +}; + + +// forward declaration +struct nsXPTCMiniVariant; + +class nsXPTConstant : public XPTConstDescriptor +{ +// NO DATA - this a flyweight wrapper +public: + nsXPTConstant(const XPTConstDescriptor& desc) + {*(XPTConstDescriptor*)this = desc;} + + const char* GetName() const + {return name;} + + const nsXPTType GetType() const + {return type.prefix;} + + // XXX this is ugly. But sometimes you gotta do what you gotta do. + // A reinterpret_cast won't do the trick here. And this plain C cast + // works correctly and is safe enough. + // See http://bugzilla.mozilla.org/show_bug.cgi?id=49641 + const nsXPTCMiniVariant* GetValue() const + {return (nsXPTCMiniVariant*) &value;} +private: + nsXPTConstant(); // no implementation +// NO DATA - this a flyweight wrapper +}; + +#endif /* xptiinfo_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in new file mode 100644 index 00000000..de5fd9b1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/Makefile.in @@ -0,0 +1,75 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xptinfo +REQUIRES = \ + string \ + $(NULL) + +CPPSRCS = \ + xptiFile.cpp \ + xptiInterfaceInfo.cpp \ + xptiInterfaceInfoManager.cpp \ + xptiManifest.cpp \ + xptiMisc.cpp \ + xptiTypelibGuts.cpp \ + xptiWorkingSet.cpp \ + xptiZipItem.cpp \ + xptiZipLoader.cpp \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +# For nsManifestLineReader class. +LOCAL_INCLUDES = -I$(srcdir)/../../../ds + +DEFINES += -DEXPORT_XPTI_API -DEXPORT_XPT_API -D_IMPL_NS_COM -D_IMPL_NS_BASE + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO new file mode 100644 index 00000000..c5bb1c64 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/TODO @@ -0,0 +1,20 @@ +/* jband - 03/24/00 - */ + +- DOCS +- improve error handling + - should some errors really be warnings? + - should autoreg support additional channel to recieve warnings so that + an installer can decide whether or not to accept the consequences of + leaving the newly installed files in place? +- verification of interfaces (warnings and/or errors) + - verify that repeated interfaces are identical in all ways + - verify that interface names are always one-to-one with iids +- check for truncated xpt files and version problems + - http://bugzilla.mozilla.org/show_bug.cgi?id=33193 +- TESTS! + - e.g. verify the merge stuff really works for various inputs. + - we really need a set of .xpt and .zip files and code that does an array + of autoreg and interfaceinof use activitities to test various corners + of the system. +- better autoreg logging +- use only 32 bits for file size? diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp new file mode 100644 index 00000000..50362c75 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiFile.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiFile. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiFile) + +xptiFile::xptiFile() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mSize(), + mDate(), + mName(nsnull), + mGuts(nsnull), + mDirectory(0) +{ + // empty + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(aSize), + mDate(aDate), + mName(aName), + mGuts(nsnull), + mDirectory(aDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mSize(r.mSize), + mDate(r.mDate), + mName(nsnull), + mGuts(nsnull), + mDirectory(r.mDirectory) +{ + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); + + MOZ_COUNT_CTOR(xptiFile); +} + +xptiFile::~xptiFile() +{ + MOZ_COUNT_DTOR(xptiFile); +} + +PRBool +xptiFile::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp new file mode 100644 index 00000000..69bf86df --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */ + +#include "xptiprivate.h" + +/***************************************************************************/ +// Debug Instrumentation... + +#ifdef SHOW_INFO_COUNT_STATS +static int DEBUG_TotalInfos = 0; +static int DEBUG_CurrentInfos = 0; +static int DEBUG_MaxInfos = 0; +static int DEBUG_MonitorEntryCount = 0; + +#define LOG_INFO_CREATE(t) \ + DEBUG_TotalInfos++; \ + DEBUG_CurrentInfos++; \ + if(DEBUG_MaxInfos < DEBUG_CurrentInfos) \ + DEBUG_MaxInfos = DEBUG_CurrentInfos /* no ';' */ + +#define LOG_INFO_DESTROY(t) \ + DEBUG_CurrentInfos-- /* no ';' */ + +#define LOG_INFO_MONITOR_ENTRY \ + DEBUG_MonitorEntryCount++ /* no ';' */ + +#else /* SHOW_INFO_COUNT_STATS */ + +#define LOG_INFO_CREATE(t) ((void)0) +#define LOG_INFO_DESTROY(t) ((void)0) +#define LOG_INFO_MONITOR_ENTRY ((void)0) +#endif /* SHOW_INFO_COUNT_STATS */ + +#ifdef DEBUG +// static +void xptiInterfaceInfo::DEBUG_ShutdownNotification() +{ +#ifdef SHOW_INFO_COUNT_STATS + printf("iiii %d total xptiInterfaceInfos created\n", DEBUG_TotalInfos); + printf("iiii %d max xptiInterfaceInfos alive at one time\n", DEBUG_MaxInfos); + printf("iiii %d xptiInterfaceInfos still alive\n", DEBUG_CurrentInfos); + printf("iiii %d times locked\n", DEBUG_MonitorEntryCount); +#endif +} +#endif /* DEBUG */ + +/***************************************************************************/ + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(name, nameLength, iid, typelib); +} + +// static +xptiInterfaceEntry* +xptiInterfaceEntry::NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet) +{ + size_t nameLength = PL_strlen(r.mName); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceEntry) + nameLength); + if(!place) + return nsnull; + return new(place) xptiInterfaceEntry(r, nameLength, typelib); +} + + +xptiInterfaceEntry::xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib) + : mIID(iid), + mTypelib(typelib), + mInfo(nsnull), + mFlags(uint8(0)) +{ + memcpy(mName, name, nameLength); +} + +xptiInterfaceEntry::xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib) + : mIID(r.mIID), + mTypelib(typelib), + mInfo(nsnull), + mFlags(r.mFlags) +{ + SetResolvedState(NOT_RESOLVED); + memcpy(mName, r.mName, nameLength); +} + +PRBool +xptiInterfaceEntry::Resolve(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + nsAutoLock lock(xptiInterfaceInfoManager::GetResolveLock()); + return ResolveLocked(aWorkingSet); +} + +PRBool +xptiInterfaceEntry::ResolveLocked(xptiWorkingSet* aWorkingSet /* = nsnull */) +{ + int resolvedState = GetResolveState(); + + if(resolvedState == FULLY_RESOLVED) + return PR_TRUE; + if(resolvedState == RESOLVE_FAILED) + return PR_FALSE; + + xptiInterfaceInfoManager* mgr = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + + if(!mgr) + return PR_FALSE; + + if(!aWorkingSet) + { + aWorkingSet = mgr->GetWorkingSet(); + } + + if(resolvedState == NOT_RESOLVED) + { + LOG_RESOLVE(("! begin resolve of %s\n", mName)); + // Make a copy of mTypelib because the underlying memory will change! + xptiTypelib typelib = mTypelib; + + // We expect our PartiallyResolveLocked() to get called before + // this returns. + if(!mgr->LoadFile(typelib, aWorkingSet)) + { + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + // The state was changed by LoadFile to PARTIALLY_RESOLVED, so this + // ...falls through... + } + + NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!"); + + // Finish out resolution by finding parent and Resolving it so + // we can set the info we get from it. + + PRUint16 parent_index = mInterface->mDescriptor->parent_interface; + + if(parent_index) + { + xptiInterfaceEntry* parent = + aWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(parent_index - 1); + + if(!parent || !parent->EnsureResolvedLocked()) + { + xptiTypelib aTypelib = mInterface->mTypelib; + mInterface = nsnull; + mTypelib = aTypelib; + SetResolvedState(RESOLVE_FAILED); + return PR_FALSE; + } + + mInterface->mParent = parent; + + mInterface->mMethodBaseIndex = + parent->mInterface->mMethodBaseIndex + + parent->mInterface->mDescriptor->num_methods; + + mInterface->mConstantBaseIndex = + parent->mInterface->mConstantBaseIndex + + parent->mInterface->mDescriptor->num_constants; + + } + LOG_RESOLVE(("+ complete resolve of %s\n", mName)); + + SetResolvedState(FULLY_RESOLVED); + return PR_TRUE; +} + +// This *only* gets called by xptiInterfaceInfoManager::LoadFile (while locked). +PRBool +xptiInterfaceEntry::PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(GetResolveState() == NOT_RESOLVED, "bad state"); + + LOG_RESOLVE(("~ partial resolve of %s\n", mName)); + + xptiInterfaceGuts* iface = + xptiInterfaceGuts::NewGuts(aDescriptor, mTypelib, aWorkingSet); + + if(!iface) + return PR_FALSE; + + mInterface = iface; + +#ifdef DEBUG + if(!DEBUG_ScriptableFlagIsValid()) + { + NS_ERROR("unexpected scriptable flag!"); + SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)); + } +#endif + + SetResolvedState(PARTIALLY_RESOLVED); + return PR_TRUE; +} + +/**************************************************/ +// These non-virtual methods handle the delegated nsIInterfaceInfo methods. + +nsresult +xptiInterfaceEntry::GetName(char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = (char*) nsMemory::Clone(mName, PL_strlen(mName)+1); + return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::GetIID(nsIID **iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID)); + return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +nsresult +xptiInterfaceEntry::IsScriptable(PRBool* result) +{ + // It is not necessary to Resolve because this info is read from manifest. + NS_ASSERTION(DEBUG_ScriptableFlagIsValid(), "scriptable flag out of sync!"); + *result = GetScriptableFlag(); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::IsFunction(PRBool* result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *result = XPT_ID_IS_FUNCTION(GetInterfaceGuts()->mDescriptor->flags); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetConstantCount(uint16* count) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + *count = mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodInfo(uint16 index, const nsXPTMethodInfo** info) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetMethodInfo(index, info); + + if(index >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad param"); + *info = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[index - + mInterface->mMethodBaseIndex]); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16 *index, + const nsXPTMethodInfo** result) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + // This is a slow algorithm, but this is not expected to be called much. + for(uint16 i = 0; i < mInterface->mDescriptor->num_methods; ++i) + { + const nsXPTMethodInfo* info; + info = NS_REINTERPRET_CAST(nsXPTMethodInfo*, + &mInterface->mDescriptor-> + method_descriptors[i]); + if (PL_strcmp(methodName, info->GetName()) == 0) { + *index = i + mInterface->mMethodBaseIndex; + *result = info; + return NS_OK; + } + } + + if(mInterface->mParent) + return mInterface->mParent->GetMethodInfoForName(methodName, index, result); + else + { + *index = 0; + *result = 0; + return NS_ERROR_INVALID_ARG; + } +} + +nsresult +xptiInterfaceEntry::GetConstant(uint16 index, const nsXPTConstant** constant) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(index < mInterface->mConstantBaseIndex) + return mInterface->mParent->GetConstant(index, constant); + + if(index >= mInterface->mConstantBaseIndex + + mInterface->mDescriptor->num_constants) + { + NS_PRECONDITION(0, "bad param"); + *constant = NULL; + return NS_ERROR_INVALID_ARG; + } + + // else... + *constant = + NS_REINTERPRET_CAST(nsXPTConstant*, + &mInterface->mDescriptor-> + const_descriptors[index - + mInterface->mConstantBaseIndex]); + return NS_OK; +} + +// this is a private helper + +nsresult +xptiInterfaceEntry::GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent->GetEntryForParam(methodIndex, param, entry); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad param"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor->additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) { + NS_ERROR("not an interface"); + return NS_ERROR_INVALID_ARG; + } + + xptiInterfaceEntry* theEntry = + mInterface->mWorkingSet->GetTypelibGuts(mInterface->mTypelib)-> + GetEntryAt(td->type.iface - 1); + + // This can happen if a declared interface is not available at runtime. + if(!theEntry) + { + NS_WARNING("Declared InterfaceInfo not found"); + *entry = nsnull; + return NS_ERROR_FAILURE; + } + + *entry = theEntry; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInfoForParam(uint16 methodIndex, + const nsXPTParamInfo *param, + nsIInterfaceInfo** info) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + + xptiInterfaceInfo* theInfo; + rv = entry->GetInterfaceInfo(&theInfo); + if(NS_FAILED(rv)) + return rv; + + *info = NS_STATIC_CAST(nsIInterfaceInfo*, theInfo); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetIIDForParam(uint16 methodIndex, + const nsXPTParamInfo* param, nsIID** iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + return entry->GetIID(iid); +} + +nsresult +xptiInterfaceEntry::GetIIDForParamNoAlloc(PRUint16 methodIndex, + const nsXPTParamInfo * param, + nsIID *iid) +{ + xptiInterfaceEntry* entry; + nsresult rv = GetEntryForParam(methodIndex, param, &entry); + if(NS_FAILED(rv)) + return rv; + *iid = entry->mIID; + return NS_OK; +} + +// this is a private helper +nsresult +xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type) +{ + NS_ASSERTION(IsFullyResolved(), "bad state"); + + const XPTTypeDescriptor *td = ¶m->type; + const XPTTypeDescriptor *additional_types = + mInterface->mDescriptor->additional_types; + + for (uint16 i = 0; i < dimension; i++) { + if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) { + NS_ERROR("bad dimension"); + return NS_ERROR_INVALID_ARG; + } + td = &additional_types[td->type.additional_type]; + } + + *type = td; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetTypeForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + nsXPTType* type) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetTypeForParam(methodIndex, param, dimension, type); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + *type = nsXPTType(td->prefix); + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) + return rv; + } + else + td = ¶m->type; + + // verify that this is a type that has size_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ERROR("not a size_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetLengthIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint16 dimension, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetLengthIsArgNumberForParam(methodIndex, param, dimension, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td; + + if(dimension) { + nsresult rv = GetTypeInArray(param, dimension, &td); + if(NS_FAILED(rv)) { + return rv; + } + } + else + td = ¶m->type; + + // verify that this is a type that has length_is + switch (XPT_TDP_TAG(td->prefix)) { + case TD_ARRAY: + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + break; + default: + NS_ERROR("not a length_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum2; + return NS_OK; +} + +nsresult +xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16 methodIndex, + const nsXPTParamInfo* param, + uint8* argnum) +{ + if(!EnsureResolved()) + return NS_ERROR_UNEXPECTED; + + if(methodIndex < mInterface->mMethodBaseIndex) + return mInterface->mParent-> + GetInterfaceIsArgNumberForParam(methodIndex, param, argnum); + + if(methodIndex >= mInterface->mMethodBaseIndex + + mInterface->mDescriptor->num_methods) + { + NS_ERROR("bad index"); + return NS_ERROR_INVALID_ARG; + } + + const XPTTypeDescriptor *td = ¶m->type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &mInterface->mDescriptor-> + additional_types[td->type.additional_type]; + } + + if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) { + NS_ERROR("not an iid_is"); + return NS_ERROR_INVALID_ARG; + } + + *argnum = td->argnum; + return NS_OK; +} + +/* PRBool isIID (in nsIIDPtr IID); */ +nsresult +xptiInterfaceEntry::IsIID(const nsIID * IID, PRBool *_retval) +{ + // It is not necessary to Resolve because this info is read from manifest. + *_retval = mIID.Equals(*IID); + return NS_OK; +} + +/* void getNameShared ([shared, retval] out string name); */ +nsresult +xptiInterfaceEntry::GetNameShared(const char **name) +{ + // It is not necessary to Resolve because this info is read from manifest. + *name = mName; + return NS_OK; +} + +/* void getIIDShared ([shared, retval] out nsIIDPtrShared iid); */ +nsresult +xptiInterfaceEntry::GetIIDShared(const nsIID * *iid) +{ + // It is not necessary to Resolve because this info is read from manifest. + *iid = &mIID; + return NS_OK; +} + +/* PRBool hasAncestor (in nsIIDPtr iid); */ +nsresult +xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval) +{ + *_retval = PR_FALSE; + + for(xptiInterfaceEntry* current = this; + current; + current = current->mInterface->mParent) + { + if(current->mIID.Equals(*iid)) + { + *_retval = PR_TRUE; + break; + } + if(!current->EnsureResolved()) + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +/***************************************************/ + +nsresult +xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info) +{ + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + +#ifdef SHOW_INFO_COUNT_STATS + static int callCount = 0; + if(!(++callCount%100)) + printf("iiii %d xptiInterfaceInfos currently alive\n", DEBUG_CurrentInfos); +#endif + + if(!mInfo) + { + mInfo = new xptiInterfaceInfo(this); + if(!mInfo) + { + *info = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_ADDREF(*info = mInfo); + return NS_OK; +} + +void +xptiInterfaceEntry::LockedInvalidateInterfaceInfo() +{ + if(mInfo) + { + mInfo->Invalidate(); + mInfo = nsnull; + } +} + +/***************************************************************************/ + +NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo) + +xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry) + : mEntry(entry), mParent(nsnull) +{ + LOG_INFO_CREATE(this); +} + +xptiInterfaceInfo::~xptiInterfaceInfo() +{ + LOG_INFO_DESTROY(this); + NS_IF_RELEASE(mParent); + NS_ASSERTION(!mEntry, "bad state in dtor"); +} + +nsrefcnt +xptiInterfaceInfo::AddRef(void) +{ + nsrefcnt cnt = (nsrefcnt) PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this)); + return cnt; +} + +nsrefcnt +xptiInterfaceInfo::Release(void) +{ + xptiInterfaceEntry* entry = mEntry; + nsrefcnt cnt = (nsrefcnt) PR_AtomicDecrement((PRInt32*)&mRefCnt); + NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo"); + if(!cnt) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + LOG_INFO_MONITOR_ENTRY; + + // If GetInterfaceInfo added and *released* a reference before we + // acquired the monitor then 'this' might already be dead. In that + // case we would not want to try to access any instance data. We + // would want to bail immediately. If 'this' is already dead then the + // entry will no longer have a pointer to 'this'. So, we can protect + // ourselves from danger without more aggressive locking. + if(entry && !entry->InterfaceInfoEquals(this)) + return 0; + + // If GetInterfaceInfo added a reference before we acquired the monitor + // then we want to bail out of here without destorying the object. + if(mRefCnt) + return 1; + + if(mEntry) + { + mEntry->LockedInterfaceInfoDeathNotification(); + mEntry = nsnull; + } + + NS_DELETEXPCOM(this); + return 0; + } + return cnt; +} + +/***************************************************************************/ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp new file mode 100644 index 00000000..5ae06914 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -0,0 +1,2126 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiInterfaceInfoManager. */ + +#include "xptiprivate.h" +#include "nsDependentString.h" +#include "nsString.h" + +#define NS_ZIPLOADER_CONTRACTID NS_XPTLOADER_CONTRACTID_PREFIX "zip" + +NS_IMPL_THREADSAFE_ISUPPORTS2(xptiInterfaceInfoManager, + nsIInterfaceInfoManager, + nsIInterfaceInfoSuperManager) + +static xptiInterfaceInfoManager* gInterfaceInfoManager = nsnull; +#ifdef DEBUG +static int gCallCount = 0; +#endif + +// static +xptiInterfaceInfoManager* +xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef() +{ + if(!gInterfaceInfoManager) + { + nsCOMPtr searchPath; + BuildFileSearchPath(getter_AddRefs(searchPath)); + if(!searchPath) + { + NS_ERROR("can't get xpt search path!"); + return nsnull; + } + + gInterfaceInfoManager = new xptiInterfaceInfoManager(searchPath); + if(gInterfaceInfoManager) + NS_ADDREF(gInterfaceInfoManager); + if(!gInterfaceInfoManager->IsValid()) + { + NS_RELEASE(gInterfaceInfoManager); + } + else + { + PRBool mustAutoReg = + !xptiManifest::Read(gInterfaceInfoManager, + &gInterfaceInfoManager->mWorkingSet); +#ifdef DEBUG + { + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(gInterfaceInfoManager, + gInterfaceInfoManager->mAutoRegLogFile, PR_TRUE); + LOG_AUTOREG(("debug build forced autoreg after %s load of manifest\n", mustAutoReg ? "FAILED" : "successful")); + + mustAutoReg = PR_TRUE; + } +#endif // DEBUG + if(mustAutoReg) + gInterfaceInfoManager->AutoRegisterInterfaces(); + } + } + return gInterfaceInfoManager; +} + +void +xptiInterfaceInfoManager::FreeInterfaceInfoManager() +{ + if(gInterfaceInfoManager) + gInterfaceInfoManager->LogStats(); + + NS_IF_RELEASE(gInterfaceInfoManager); +} + +PRBool +xptiInterfaceInfoManager::IsValid() +{ + return mWorkingSet.IsValid() && + mResolveLock && + mAutoRegLock && + mInfoMonitor && + mAdditionalManagersLock; +} + +xptiInterfaceInfoManager::xptiInterfaceInfoManager(nsISupportsArray* aSearchPath) + : mWorkingSet(aSearchPath), + mOpenLogFile(nsnull), + mResolveLock(PR_NewLock()), + mAutoRegLock(PR_NewLock()), + mInfoMonitor(nsAutoMonitor::NewMonitor("xptiInfoMonitor")), + mAdditionalManagersLock(PR_NewLock()), + mSearchPath(aSearchPath) +{ + const char* statsFilename = PR_GetEnv("MOZILLA_XPTI_STATS"); + if(statsFilename) + { + mStatsLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mStatsLogFile && + NS_SUCCEEDED(mStatsLogFile->InitWithNativePath(nsDependentCString(statsFilename)))) + { + printf("* Logging xptinfo stats to: %s\n", statsFilename); + } + else + { + printf("* Failed to create xptinfo stats file: %s\n", statsFilename); + mStatsLogFile = nsnull; + } + } + + const char* autoRegFilename = PR_GetEnv("MOZILLA_XPTI_REGLOG"); + if(autoRegFilename) + { + mAutoRegLogFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if(mAutoRegLogFile && + NS_SUCCEEDED(mAutoRegLogFile->InitWithNativePath(nsDependentCString(autoRegFilename)))) + { + printf("* Logging xptinfo autoreg to: %s\n", autoRegFilename); + } + else + { + printf("* Failed to create xptinfo autoreg file: %s\n", autoRegFilename); + mAutoRegLogFile = nsnull; + } + } +} + +xptiInterfaceInfoManager::~xptiInterfaceInfoManager() +{ + // We only do this on shutdown of the service. + mWorkingSet.InvalidateInterfaceInfos(); + + if(mResolveLock) + PR_DestroyLock(mResolveLock); + if(mAutoRegLock) + PR_DestroyLock(mAutoRegLock); + if(mInfoMonitor) + nsAutoMonitor::DestroyMonitor(mInfoMonitor); + if(mAdditionalManagersLock) + PR_DestroyLock(mAdditionalManagersLock); + + gInterfaceInfoManager = nsnull; +#ifdef DEBUG + xptiInterfaceInfo::DEBUG_ShutdownNotification(); + gCallCount = 0; +#endif +} + +static nsresult +GetDirectoryFromDirService(const char* codename, nsILocalFile** aDir) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aDir,"loser!"); + + nsresult rv; + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + + return dirService->Get(codename, NS_GET_IID(nsILocalFile), (void**) aDir); +} + +static PRBool +AppendFromDirServiceList(const char* codename, nsISupportsArray* aPath) +{ + NS_ASSERTION(codename,"loser!"); + NS_ASSERTION(aPath,"loser!"); + + nsCOMPtr dirService = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); + if(!dirService) + return PR_FALSE; + + nsCOMPtr fileList; + dirService->Get(codename, NS_GET_IID(nsISimpleEnumerator), + getter_AddRefs(fileList)); + if(!fileList) + return PR_FALSE; + + PRBool more; + while(NS_SUCCEEDED(fileList->HasMoreElements(&more)) && more) + { + nsCOMPtr dir; + fileList->GetNext(getter_AddRefs(dir)); + if(!dir || !aPath->AppendElement(dir)) + return PR_FALSE; + } + + return PR_TRUE; +} + +// static +PRBool xptiInterfaceInfoManager::BuildFileSearchPath(nsISupportsArray** aPath) +{ +#ifdef DEBUG + NS_ASSERTION(!gCallCount++, "Expected only one call!"); +#endif + + nsCOMPtr searchPath; + NS_NewISupportsArray(getter_AddRefs(searchPath)); + if(!searchPath) + return PR_FALSE; + + nsCOMPtr compDir; + + // Always put components directory first + + if(NS_FAILED(GetDirectoryFromDirService(NS_XPCOM_COMPONENT_DIR, + getter_AddRefs(compDir))) || + !searchPath->AppendElement(compDir)) + { + return PR_FALSE; + } + + // Add additional plugins dirs + // No error checking here since this is optional in some embeddings + + // Add the GRE's component directory to searchPath if the + // application is using an GRE. + // An application indicates that it's using an GRE by returning + // a valid nsIFile via it's directory service provider interface. + // + // Please see http://www.mozilla.org/projects/embedding/MRE.html + // for more info. on GREs + // + nsCOMPtr greComponentDirectory; + nsresult rv = GetDirectoryFromDirService(NS_GRE_COMPONENT_DIR, + getter_AddRefs(greComponentDirectory)); + if(NS_SUCCEEDED(rv) && greComponentDirectory) + { + // make sure we only append a directory if its a different one + PRBool equalsCompDir = PR_FALSE; + greComponentDirectory->Equals(compDir, &equalsCompDir); + + if(!equalsCompDir) + searchPath->AppendElement(greComponentDirectory); + } + + (void)AppendFromDirServiceList(NS_XPCOM_COMPONENT_DIR_LIST, searchPath); + (void)AppendFromDirServiceList(NS_APP_PLUGINS_DIR_LIST, searchPath); + + NS_ADDREF(*aPath = searchPath); + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetCloneOfManifestLocation(nsILocalFile** aFile) +{ + // We *trust* that this will not change! + nsCOMPtr lf; + nsresult rv = GetDirectoryFromDirService(NS_XPCOM_XPTI_REGISTRY_FILE, + getter_AddRefs(lf)); + + if (NS_FAILED(rv)) return PR_FALSE; + + rv = xptiCloneLocalFile(lf, aFile); + if (NS_FAILED(rv)) return PR_FALSE; + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::GetApplicationDir(nsILocalFile** aDir) +{ + // We *trust* that this will not change! + return NS_SUCCEEDED(GetDirectoryFromDirService(NS_XPCOM_CURRENT_PROCESS_DIR, aDir)); +} + +PRBool +xptiInterfaceInfoManager::BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList) +{ + NS_ASSERTION(aFileList, "loser!"); + + nsresult rv; + + nsCOMPtr fileList = + do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID); + if(!fileList) + return PR_FALSE; + + PRUint32 pathCount; + if(NS_FAILED(aSearchPath->Count(&pathCount))) + return PR_FALSE; + + for(PRUint32 i = 0; i < pathCount; i++) + { + nsCOMPtr dir; + rv = xptiCloneElementAsLocalFile(aSearchPath, i, getter_AddRefs(dir)); + if(NS_FAILED(rv) || !dir) + return PR_FALSE; + + nsCOMPtr entries; + rv = dir->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + continue; + + PRUint32 count = 0; + PRBool hasMore; + while(NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr sup; + entries->GetNext(getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + PRBool isFile; + if(NS_FAILED(file->IsFile(&isFile)) || !isFile) + { + continue; + } + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + if(xptiFileType::IsUnknown(name.get())) + continue; + + LOG_AUTOREG(("found file: %s\n", name.get())); + + if(!fileList->InsertElementAt(file, count)) + return PR_FALSE; + ++count; + } + } + + NS_ADDREF(*aFileList = fileList); + return PR_TRUE; +} + +XPTHeader* +xptiInterfaceInfoManager::ReadXPTFile(nsILocalFile* aFile, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFile, "loser!"); + + XPTHeader *header = nsnull; + char *whole = nsnull; + PRFileDesc* fd = nsnull; + XPTState *state = nsnull; + XPTCursor cursor; + PRInt32 flen; + PRInt64 fileSize; + + PRBool saveFollowLinks; + aFile->GetFollowLinks(&saveFollowLinks); + aFile->SetFollowLinks(PR_TRUE); + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + whole = new char[flen]; + if (!whole) + { + aFile->SetFollowLinks(saveFollowLinks); + return nsnull; + } + + // all exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + { + goto out; + } + + if(flen > PR_Read(fd, whole, flen)) + { + goto out; + } + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet->GetStructArena(), &cursor, &header)) + { + header = nsnull; + goto out; + } + + out: + if(fd) + PR_Close(fd); + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + aFile->SetFollowLinks(saveFollowLinks); + return header; +} + +PRBool +xptiInterfaceInfoManager::LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet) +{ + if(!aWorkingSet) + aWorkingSet = &mWorkingSet; + + if(!aWorkingSet->IsValid()) + return PR_FALSE; + + xptiFile* fileRecord = &aWorkingSet->GetFileAt(aTypelibRecord.GetFileIndex()); + xptiZipItem* zipItem = nsnull; + + nsCOMPtr file; + if(NS_FAILED(aWorkingSet->GetCloneOfDirectoryAt(fileRecord->GetDirectory(), + getter_AddRefs(file))) || !file) + return PR_FALSE; + + if(NS_FAILED(file->AppendNative(nsDependentCString(fileRecord->GetName())))) + return PR_FALSE; + + XPTHeader* header; + + if(aTypelibRecord.IsZip()) + { + zipItem = &aWorkingSet->GetZipItemAt(aTypelibRecord.GetZipItemIndex()); + + // See the big comment below in the 'non-zip' case... + if(zipItem->GetGuts()) + { + NS_ERROR("Trying to load an xpt file from a zip twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("# loading zip item %s::%s\n", fileRecord->GetName(), zipItem->GetName())); + + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr stream; + rv = loader->LoadEntry(file, zipItem->GetName(), + getter_AddRefs(stream)); + + if (NS_FAILED(rv)) + return PR_FALSE; + + header = + xptiZipLoader::ReadXPTFileFromInputStream(stream, aWorkingSet); + } else { + header = nsnull; + NS_WARNING("Could not load XPT Zip loader"); + } + } + else + { + // The file would only have guts already if we previously failed to + // find an interface info in a file where the manifest claimed it was + // going to be. + // + // Normally, when the file gets loaded (and the guts set) then all + // interfaces would also be resolved. So, if we are here again for + // the same file then there must have been some interface that was + // expected but not present. Now we are explicitly trying to find it + // and it isn't going to be there this time either. + // + // This is an assertion style error in a DEBUG build because it shows + // that we failed to detect this in autoreg. For release builds (where + // autoreg is not run on every startup) it is just bad. But by returning + // PR_FALSE we mark this interface as RESOLVE_FAILED and get on with + // things without crashing or anything. + // + // We don't want to do an autoreg here because this is too much of an + // edge case (and in that odd case it might autoreg multiple times if + // many interfaces had been removed). But, by deleting the manifest we + // force the system to get it right on the next run. + + if(fileRecord->GetGuts()) + { + NS_ERROR("Trying to load an xpt file twice"); + + // Force an autoreg on next run + (void) xptiManifest::Delete(this); + + return PR_FALSE; + } + + LOG_LOAD(("^ loading file %s\n", fileRecord->GetName())); + header = ReadXPTFile(file, aWorkingSet); + } + + if(!header) + return PR_FALSE; + + + if(aTypelibRecord.IsZip()) + { + // This also allocs zipItem.GetGuts() used below. + if(!zipItem->SetHeader(header, aWorkingSet)) + return PR_FALSE; + } + else + { + // This also allocs fileRecord.GetGuts() used below. + if(!fileRecord->SetHeader(header, aWorkingSet)) + return PR_FALSE; + } + + // For each interface in the header we want to find the xptiInterfaceInfo + // object and set its resolution info. + + for(PRUint16 i = 0; i < header->num_interfaces; i++) + { + static const nsID zeroIID = + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }; + + XPTInterfaceDirectoryEntry* iface = header->interface_directory + i; + + xptiHashEntry* hashEntry; + + if(!iface->iid.Equals(zeroIID)) + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + &iface->iid, PL_DHASH_LOOKUP); + } + else + { + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + iface->name, PL_DHASH_LOOKUP); + } + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + // This one is just not resolved anywhere! + continue; + } + + if(aTypelibRecord.IsZip()) + zipItem->GetGuts()->SetEntryAt(i, entry); + else + fileRecord->GetGuts()->SetEntryAt(i, entry); + + XPTInterfaceDescriptor* descriptor = iface->interface_descriptor; + + if(descriptor && aTypelibRecord.Equals(entry->GetTypelibRecord())) + entry->PartiallyResolveLocked(descriptor, aWorkingSet); + } + return PR_TRUE; +} + +static int +IndexOfFileWithName(const char* aName, const xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aName, "loser!"); + + for(PRUint32 i = 0; i < aWorkingSet->GetFileCount(); ++i) + { + if(0 == PL_strcmp(aName, aWorkingSet->GetFileAt(i).GetName())) + return i; + } + return -1; +} + +static int +IndexOfDirectoryOfFile(nsISupportsArray* aSearchPath, nsILocalFile* aFile) +{ + nsCOMPtr parent; + aFile->GetParent(getter_AddRefs(parent)); + if(parent) + { + PRUint32 count = 0; + aSearchPath->Count(&count); + NS_ASSERTION(count, "broken search path! bad count"); + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr current; + aSearchPath->QueryElementAt(i, NS_GET_IID(nsIFile), + getter_AddRefs(current)); + NS_ASSERTION(current, "broken search path! bad element"); + PRBool same; + if(NS_SUCCEEDED(parent->Equals(current, &same)) && same) + return (int) i; + } + } + NS_ERROR("file not in search directory!"); + return -1; +} + +struct SortData +{ + nsISupportsArray* mSearchPath; + xptiWorkingSet* mWorkingSet; +}; + +PR_STATIC_CALLBACK(int) +xptiSortFileList(const void * p1, const void *p2, void * closure) +{ + nsILocalFile* pFile1 = *((nsILocalFile**) p1); + nsILocalFile* pFile2 = *((nsILocalFile**) p2); + SortData* data = (SortData*) closure; + + nsCAutoString name1; + nsCAutoString name2; + + if(NS_FAILED(pFile1->GetNativeLeafName(name1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetNativeLeafName(name2))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + + int index1 = IndexOfFileWithName(name1.get(), data->mWorkingSet); + int index2 = IndexOfFileWithName(name2.get(), data->mWorkingSet); + + // Get these now in case we need them later. + PRBool isXPT1 = xptiFileType::IsXPT(name1.get()); + PRBool isXPT2 = xptiFileType::IsXPT(name2.get()); + int nameOrder = Compare(name1, name2); + + // both in workingSet, preserve old order + if(index1 != -1 && index2 != -1) + return index1 - index2; + + if(index1 != -1) + return 1; + + if(index2 != -1) + return -1; + + // neither is in workingset + + // check how they compare in search path order + + int dirIndex1 = IndexOfDirectoryOfFile(data->mSearchPath, pFile1); + int dirIndex2 = IndexOfDirectoryOfFile(data->mSearchPath, pFile2); + + if(dirIndex1 != dirIndex2) + return dirIndex1 - dirIndex2; + + // .xpt files come before archives (.zip, .jar, etc) + if(isXPT1 &&!isXPT2) + return -1; + + if(!isXPT1 && isXPT2) + return 1; + + // neither element is in the workingSet and both are same type and in + // the same directory, sort by size + + PRInt64 size1; + PRInt64 size2; + + if(NS_FAILED(pFile1->GetFileSize(&size1))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + if(NS_FAILED(pFile2->GetFileSize(&size2))) + { + NS_ERROR("way bad, with no happy out!"); + return 0; + } + + // by size with largest first, or by name if size is the same + int sizeDiff = int(PRInt32(nsInt64(size2) - nsInt64(size1))); + return sizeDiff != 0 ? sizeDiff : nameOrder; +} + +nsILocalFile** +xptiInterfaceInfoManager::BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + // We want to end up with a file list that starts with the files from + // aWorkingSet (but only those that are in aFileList) in the order in + // which they appeared in aWorkingSet-> Following those files will be those + // files in aFileList which are not in aWorkingSet-> These additional + // files will be ordered by file size (larger first) but all .xpt files + // will preceed all zipfile of those files not already in the working set. + // To do this we will do a fancy sort on a copy of aFileList. + + nsILocalFile** orderedFileList = nsnull; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList)) || + 0 == countOfFilesInFileList) + return nsnull; + + orderedFileList = (nsILocalFile**) + XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(nsILocalFile*) * countOfFilesInFileList); + + if(!orderedFileList) + return nsnull; + + // fill our list for sorting + for(i = 0; i < countOfFilesInFileList; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + // Intentionally NOT addref'd cuz we know these are pinned in aFileList. + orderedFileList[i] = file.get(); + } + + // sort the filelist + + SortData sortData = {aSearchPath, aWorkingSet}; + NS_QuickSort(orderedFileList, countOfFilesInFileList, sizeof(nsILocalFile*), + xptiSortFileList, &sortData); + + return orderedFileList; +} + +xptiInterfaceInfoManager::AutoRegMode +xptiInterfaceInfoManager::DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + PRUint32 countOfFilesInWorkingSet = aWorkingSet->GetFileCount(); + PRUint32 countOfFilesInFileList; + PRUint32 i; + PRUint32 k; + + if(0 == countOfFilesInWorkingSet) + { + // Loading manifest might have failed. Better safe... + return FULL_VALIDATION_REQUIRED; + } + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + if(countOfFilesInFileList == countOfFilesInWorkingSet) + { + // try to determine if *no* files are new or changed. + + PRBool same = PR_TRUE; + for(i = 0; i < countOfFilesInFileList && same; ++i) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + PRInt64 size; + PRInt64 date; + nsCAutoString name; + PRUint32 directory; + + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &directory)) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + for(k = 0; k < countOfFilesInWorkingSet; ++k) + { + xptiFile& target = aWorkingSet->GetFileAt(k); + + if(directory == target.GetDirectory() && + name.Equals(target.GetName())) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the workingset? + if(k == countOfFilesInWorkingSet) + same = PR_FALSE; + } + if(same) + return NO_FILES_CHANGED; + } + else if(countOfFilesInFileList > countOfFilesInWorkingSet) + { + // try to determine if the only changes are additional new files + // XXX Wimping out and doing this as a separate walk through the lists. + + PRBool same = PR_TRUE; + + for(i = 0; i < countOfFilesInWorkingSet && same; ++i) + { + xptiFile& target = aWorkingSet->GetFileAt(i); + + for(k = 0; k < countOfFilesInFileList; ++k) + { + nsCOMPtr file; + aFileList->QueryElementAt(k, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + NS_ASSERTION(file, "loser!"); + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name))) + { + NS_ERROR("unexpected!"); + return FULL_VALIDATION_REQUIRED; + } + + PRBool sameName = name.Equals(target.GetName()); + if(sameName) + { + if(nsInt64(size) != target.GetSize() || + nsInt64(date) != target.GetDate()) + same = PR_FALSE; + break; + } + } + // failed to find our file in the file list? + if(k == countOfFilesInFileList) + same = PR_FALSE; + } + if(same) + return FILES_ADDED_ONLY; + } + + return FULL_VALIDATION_REQUIRED; +} + +PRBool +xptiInterfaceInfoManager::AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + NS_ASSERTION(aWorkingSet->IsValid(), "loser!"); + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + NS_ASSERTION(countOfFilesInFileList, "loser!"); + NS_ASSERTION(countOfFilesInFileList > aWorkingSet->GetFileCount(), "loser!"); + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // Make enough space in aWorkingset for additions to xptiFile array. + + if(!aWorkingSet->ExtendFileArray(countOfFilesInFileList)) + return PR_FALSE; + + // For each file that is not already in our working set, add any valid + // interfaces that don't conflict with previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + + if(xptiWorkingSet::NOT_FOUND != aWorkingSet->FindFile(dir, name.get())) + { + // This file was found in the working set, so skip it. + continue; + } + + LOG_AUTOREG((" finding interfaces in new file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR(""); + continue; + } + + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + else // its another kind of archive + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet) +{ + nsILocalFile** orderedFileArray; + PRUint32 countOfFilesInFileList; + PRUint32 i; + + NS_ASSERTION(aFileList, "loser!"); + + if(!aWorkingSet->IsValid()) + return PR_FALSE; + + if(NS_FAILED(aFileList->Count(&countOfFilesInFileList))) + return PR_FALSE; + + if(!countOfFilesInFileList) + { + // maybe there are no xpt files to register. + // a minimal install would have this case. + return PR_TRUE; + } + + orderedFileArray = BuildOrderedFileArray(aSearchPath, aFileList, aWorkingSet); + + if(!orderedFileArray) + return PR_FALSE; + + // DEBUG_DumpFileArray(orderedFileArray, countOfFilesInFileList); + + // Make space in aWorkingset for a new xptiFile array. + + if(!aWorkingSet->NewFileArray(countOfFilesInFileList)) + return PR_FALSE; + + aWorkingSet->ClearZipItems(); + aWorkingSet->ClearHashTables(); + + // For each file, add any valid interfaces that don't conflict with + // previous interfaces added. + for(i = 0; i < countOfFilesInFileList; i++) + { + nsILocalFile* file = orderedFileArray[i]; + + nsCAutoString name; + PRInt64 size; + PRInt64 date; + PRUint32 dir; + if(NS_FAILED(file->GetFileSize(&size)) || + NS_FAILED(file->GetLastModifiedTime(&date)) || + NS_FAILED(file->GetNativeLeafName(name)) || + !aWorkingSet->FindDirectoryOfFile(file, &dir)) + { + return PR_FALSE; + } + + LOG_AUTOREG((" finding interfaces in file: %s\n", name.get())); + + xptiFile fileRecord; + fileRecord = xptiFile(nsInt64(size), nsInt64(date), dir, + name.get(), aWorkingSet); + +// printf("* found %s\n", fileRecord.GetName()); + + + if(xptiFileType::IsXPT(fileRecord.GetName())) + { + XPTHeader* header = ReadXPTFile(file, aWorkingSet); + if(!header) + { + // XXX do something! + NS_ERROR("Unable to read an XPT file, turn logging on to see which file"); + LOG_AUTOREG((" unable to read file\n")); + continue; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount()); + + PRBool AddedFile = PR_FALSE; + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this file then + // setup the fileRecord for the header and infos. + if(!AddedFile) + { + if(!fileRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + AddedFile = PR_TRUE; + } + fileRecord.GetGuts()->SetEntryAt(k, entry); + } + + // This will correspond to typelibRecord above. + aWorkingSet->AppendFile(fileRecord); + } + + else + { + nsCOMPtr loader = + do_GetService(NS_ZIPLOADER_CONTRACTID); + + if (loader) { + nsresult rv; + + nsCOMPtr sink = + new xptiZipLoaderSink(this, aWorkingSet); + if (!sink) + return PR_FALSE; + + rv = loader->EnumerateEntries(file, sink); + if (NS_FAILED(rv)) + return PR_FALSE; + // This will correspond to typelibRecord used in + // xptiInterfaceInfoManager::FoundEntry. + aWorkingSet->AppendFile(fileRecord); + } else { + NS_WARNING("Could not load XPT Zip loader"); + } + } + } + return PR_TRUE; +} + +NS_IMPL_ISUPPORTS1(xptiZipLoaderSink, nsIXPTLoaderSink) + +// implement nsIXPTLoader +NS_IMETHODIMP +xptiZipLoaderSink::FoundEntry(const char* entryName, + PRInt32 index, + nsIInputStream *aStream) +{ + XPTHeader *header = + xptiZipLoader::ReadXPTFileFromInputStream(aStream, mWorkingSet); + if (!header) + return NS_ERROR_OUT_OF_MEMORY; + + if (!mManager->FoundZipEntry(entryName, index, header, mWorkingSet)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +// implement xptiEntrySink +PRBool +xptiInterfaceInfoManager::FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet) +{ + + NS_ASSERTION(entryName, "loser!"); + NS_ASSERTION(header, "loser!"); + NS_ASSERTION(aWorkingSet, "loser!"); + + int countOfInterfacesAddedForItem = 0; + xptiZipItem zipItemRecord(entryName, aWorkingSet); + + LOG_AUTOREG((" finding interfaces in file: %s\n", entryName)); + + if(header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) + { + NS_ASSERTION(!header->num_interfaces,"bad libxpt"); + LOG_AUTOREG((" file is version %d.%d. Type file of version %d.0 or higher can not be read.\n", (int)header->major_version, (int)header->minor_version, (int)XPT_MAJOR_INCOMPATIBLE_VERSION)); + } + + if(!header->num_interfaces) + { + // We are not interested in files without interfaces. + return PR_TRUE; + } + + xptiTypelib typelibRecord; + typelibRecord.Init(aWorkingSet->GetFileCount(), + aWorkingSet->GetZipItemCount()); + + for(PRUint16 k = 0; k < header->num_interfaces; k++) + { + xptiInterfaceEntry* entry = nsnull; + + if(!VerifyAndAddEntryIfNew(aWorkingSet, + header->interface_directory + k, + typelibRecord, + &entry)) + return PR_FALSE; + + if(!entry) + continue; + + // If this is the first interface we found for this item + // then setup the zipItemRecord for the header and infos. + if(!countOfInterfacesAddedForItem) + { + // XXX fix this! + if(!zipItemRecord.SetHeader(header, aWorkingSet)) + { + // XXX that would be bad. + return PR_FALSE; + } + } + + // zipItemRecord.GetGuts()->SetEntryAt(k, entry); + ++countOfInterfacesAddedForItem; + } + + if(countOfInterfacesAddedForItem) + { + if(!aWorkingSet->GetZipItemFreeSpace()) + { + if(!aWorkingSet->ExtendZipItemArray( + aWorkingSet->GetZipItemCount() + 20)) + { + // out of space! + return PR_FALSE; + } + } + aWorkingSet->AppendZipItem(zipItemRecord); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded) +{ + NS_ASSERTION(iface, "loser!"); + NS_ASSERTION(entryAdded, "loser!"); + + *entryAdded = nsnull; + + if(!iface->interface_descriptor) + { + // Not resolved, ignore this one. + // XXX full logging might note this... + return PR_TRUE; + } + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, &iface->iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(entry) + { + // XXX validate this info to find possible inconsistencies + LOG_AUTOREG((" ignoring repeated interface: %s\n", iface->name)); + return PR_TRUE; + } + + // Build a new xptiInterfaceEntry object and hook it up. + + entry = xptiInterfaceEntry::NewEntry(iface->name, strlen(iface->name), + iface->iid, + typelibRecord, aWorkingSet); + if(!entry) + { + // XXX bad! + return PR_FALSE; + } + + //XXX We should SetHeader too as part of the validation, no? + entry->SetScriptableFlag(XPT_ID_IS_SCRIPTABLE(iface->interface_descriptor->flags)); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + *entryAdded = entry; + + LOG_AUTOREG((" added interface: %s\n", iface->name)); + + return PR_TRUE; +} + +// local struct used to pass two pointers as one pointer +struct TwoWorkingSets +{ + TwoWorkingSets(xptiWorkingSet* src, xptiWorkingSet* dest) + : aSrcWorkingSet(src), aDestWorkingSet(dest) {} + + xptiWorkingSet* aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Merger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* srcEntry = ((xptiHashEntry*)hdr)->value; + xptiWorkingSet* aSrcWorkingSet = ((TwoWorkingSets*)arg)->aSrcWorkingSet; + xptiWorkingSet* aDestWorkingSet = ((TwoWorkingSets*)arg)->aDestWorkingSet; + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + srcEntry->GetTheIID(), PL_DHASH_LOOKUP); + + xptiInterfaceEntry* destEntry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(destEntry) + { + // Let's see if this is referring to the same exact typelib + + const char* destFilename = + aDestWorkingSet->GetTypelibFileName(destEntry->GetTypelibRecord()); + + const char* srcFilename = + aSrcWorkingSet->GetTypelibFileName(srcEntry->GetTypelibRecord()); + + if(0 == PL_strcmp(destFilename, srcFilename) && + (destEntry->GetTypelibRecord().GetZipItemIndex() == + srcEntry->GetTypelibRecord().GetZipItemIndex())) + { + // This is the same item. + // But... Let's make sure they didn't change the interface name. + // There are wacky developers that do stuff like that! + if(0 == PL_strcmp(destEntry->GetTheName(), srcEntry->GetTheName())) + return PL_DHASH_NEXT; + } + } + + // Clone the xptiInterfaceEntry into our destination WorkingSet. + + xptiTypelib typelibRecord; + + uint16 fileIndex = srcEntry->GetTypelibRecord().GetFileIndex(); + uint16 zipItemIndex = srcEntry->GetTypelibRecord().GetZipItemIndex(); + + fileIndex += aDestWorkingSet->mFileMergeOffsetMap[fileIndex]; + + // If it is not a zipItem, then the original index is fine. + if(srcEntry->GetTypelibRecord().IsZip()) + zipItemIndex += aDestWorkingSet->mZipItemMergeOffsetMap[zipItemIndex]; + + typelibRecord.Init(fileIndex, zipItemIndex); + + destEntry = xptiInterfaceEntry::NewEntry(*srcEntry, typelibRecord, + aDestWorkingSet); + if(!destEntry) + { + // XXX bad! should log + return PL_DHASH_NEXT; + } + + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mNameTable, + destEntry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aDestWorkingSet->mIIDTable, + destEntry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = destEntry; + + return PL_DHASH_NEXT; +} + +PRBool +xptiInterfaceInfoManager::MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet) +{ + + PRUint32 i; + + // Combine file lists. + + PRUint32 originalFileCount = aDestWorkingSet->GetFileCount(); + PRUint32 additionalFileCount = aSrcWorkingSet->GetFileCount(); + + // Create a new array big enough to hold both lists and copy existing files + + if(additionalFileCount) + { + if(!aDestWorkingSet->ExtendFileArray(originalFileCount + + additionalFileCount)) + return PR_FALSE; + + // Now we are where we started, but we know we have enough space. + + // Prepare offset array for later fixups. + // NOTE: Storing with dest, but alloc'ing from src. This is intentional. + aDestWorkingSet->mFileMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalFileCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mFileMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalFileCount; ++i) + { + xptiFile& srcFile = aSrcWorkingSet->GetFileAt(i); + PRUint32 k; + for(k = 0; k < originalFileCount; ++k) + { + // If file (with same name, date, and time) is in both lists + // then reuse that record. + xptiFile& destFile = aDestWorkingSet->GetFileAt(k); + if(srcFile.Equals(destFile)) + { + aDestWorkingSet->mFileMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalFileCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetFileCount(); + + aDestWorkingSet->AppendFile(xptiFile(srcFile, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mFileMergeOffsetMap[i] = newIndex - i; + } + } + + // Combine ZipItem lists. + + PRUint32 originalZipItemCount = aDestWorkingSet->GetZipItemCount(); + PRUint32 additionalZipItemCount = aSrcWorkingSet->GetZipItemCount(); + + // Create a new array big enough to hold both lists and copy existing ZipItems + + if(additionalZipItemCount) + { + if(!aDestWorkingSet->ExtendZipItemArray(originalZipItemCount + + additionalZipItemCount)) + return PR_FALSE; + + // Now we are where we started, but we know we have enough space. + + // Prepare offset array for later fixups. + // NOTE: Storing with dest, but alloc'ing from src. This is intentional. + aDestWorkingSet->mZipItemMergeOffsetMap = (PRUint32*) + XPT_CALLOC(aSrcWorkingSet->GetStructArena(), + additionalZipItemCount * sizeof(PRUint32)); + if(!aDestWorkingSet->mZipItemMergeOffsetMap) + return PR_FALSE; + } + + for(i = 0; i < additionalZipItemCount; ++i) + { + xptiZipItem& srcZipItem = aSrcWorkingSet->GetZipItemAt(i); + PRUint32 k; + for(k = 0; k < originalZipItemCount; ++k) + { + // If ZipItem (with same name) is in both lists + // then reuse that record. + xptiZipItem& destZipItem = aDestWorkingSet->GetZipItemAt(k); + if(srcZipItem.Equals(destZipItem)) + { + aDestWorkingSet->mZipItemMergeOffsetMap[i] = k - i; + break; + } + } + if(k == originalZipItemCount) + { + // No match found, tack it on the end. + + PRUint32 newIndex = aDestWorkingSet->GetZipItemCount(); + + aDestWorkingSet->AppendZipItem( + xptiZipItem(srcZipItem, aDestWorkingSet)); + + // Fixup the merge offset map. + aDestWorkingSet->mZipItemMergeOffsetMap[i] = newIndex - i; + } + } + + // Migrate xptiInterfaceInfos + + TwoWorkingSets sets(aSrcWorkingSet, aDestWorkingSet); + + PL_DHashTableEnumerate(aSrcWorkingSet->mNameTable, xpti_Merger, &sets); + + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileList(nsISupportsArray* aFileList) +{ + PRUint32 count; + + if(NS_FAILED(aFileList->Count(&count))) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + nsCOMPtr file; + aFileList->QueryElementAt(i, NS_GET_IID(nsILocalFile), getter_AddRefs(file)); + if(!file) + return PR_FALSE; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("* found %s\n", name.get()); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileListInWorkingSet(xptiWorkingSet* aWorkingSet) +{ + for(PRUint16 i = 0; i < aWorkingSet->GetFileCount(); ++i) + { + xptiFile& record = aWorkingSet->GetFileAt(i); + + printf("! has %s\n", record.GetName()); + } + return PR_TRUE; +} + +PRBool +xptiInterfaceInfoManager::DEBUG_DumpFileArray(nsILocalFile** aFileArray, + PRUint32 count) +{ + // dump the sorted list + for(PRUint32 i = 0; i < count; ++i) + { + nsILocalFile* file = aFileArray[i]; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + printf("found file: %s\n", name.get()); + } + return PR_TRUE; +} + +/***************************************************************************/ + +// static +void +xptiInterfaceInfoManager::WriteToLog(const char *fmt, ...) +{ + if(!gInterfaceInfoManager) + return; + + PRFileDesc* fd = gInterfaceInfoManager->GetOpenLogFile(); + if(fd) + { + va_list ap; + va_start(ap, fmt); + PR_vfprintf(fd, fmt, ap); + va_end(ap); + } +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ResolvedFileNameLogger(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + xptiInterfaceInfoManager* mgr = (xptiInterfaceInfoManager*) arg; + + if(entry->IsFullyResolved()) + { + xptiWorkingSet* aWorkingSet = mgr->GetWorkingSet(); + PRFileDesc* fd = mgr->GetOpenLogFile(); + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + const char* filename = + aWorkingSet->GetFileAt(typelib.GetFileIndex()).GetName(); + + if(typelib.IsZip()) + { + const char* zipItemName = + aWorkingSet->GetZipItemAt(typelib.GetZipItemIndex()).GetName(); + PR_fprintf(fd, "xpti used interface: %s from %s::%s\n", + entry->GetTheName(), filename, zipItemName); + } + else + { + PR_fprintf(fd, "xpti used interface: %s from %s\n", + entry->GetTheName(), filename); + } + } + return PL_DHASH_NEXT; +} + +void +xptiInterfaceInfoManager::LogStats() +{ + PRUint32 i; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mStatsLogFile, PR_FALSE); + + PRFileDesc* fd = GetOpenLogFile(); + if(!fd) + return; + + // Show names of xpt (only) files from which at least one interface + // was resolved. + + PRUint32 fileCount = mWorkingSet.GetFileCount(); + for(i = 0; i < fileCount; ++i) + { + xptiFile& f = mWorkingSet.GetFileAt(i); + if(f.GetGuts()) + PR_fprintf(fd, "xpti used file: %s\n", f.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show names of xptfiles loaded from zips from which at least + // one interface was resolved. + + PRUint32 zipItemCount = mWorkingSet.GetZipItemCount(); + for(i = 0; i < zipItemCount; ++i) + { + xptiZipItem& zi = mWorkingSet.GetZipItemAt(i); + if(zi.GetGuts()) + PR_fprintf(fd, "xpti used file from zip: %s\n", zi.GetName()); + } + + PR_fprintf(fd, "\n"); + + // Show name of each interface that was fully resolved and the name + // of the file and (perhaps) zip from which it was loaded. + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, + xpti_ResolvedFileNameLogger, this); + +} + +/***************************************************************************/ + +// this is a private helper +static nsresult +EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval) +{ + xptiInterfaceInfo* info; + nsresult rv; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + rv = entry->GetInterfaceInfo(&info); + if(NS_FAILED(rv)) + return rv; + + // Transfer the AddRef done by GetInterfaceInfo. + *_retval = NS_STATIC_CAST(nsIInterfaceInfo*, info); + return NS_OK; +} + +/* nsIInterfaceInfo getInfoForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIInterfaceInfo getInfoForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInterfaceInfo **_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + return EntryToInfo(entry, _retval); +} + +/* nsIIDPtr getIIDForName (in string name); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID * *_retval) +{ + NS_ASSERTION(name, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mNameTable, name, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->GetIID(_retval); +} + +/* string getNameForIID (in nsIIDPtr iid); */ +NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **_retval) +{ + NS_ASSERTION(iid, "bad param"); + NS_ASSERTION(_retval, "bad param"); + + xptiHashEntry* hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(mWorkingSet.mIIDTable, iid, PL_DHASH_LOOKUP); + + xptiInterfaceEntry* entry = + PL_DHASH_ENTRY_IS_FREE(hashEntry) ? nsnull : hashEntry->value; + + if(!entry) + { + *_retval = nsnull; + return NS_ERROR_FAILURE; + } + + return entry->GetName(_retval); +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + nsISupportsArray* array = (nsISupportsArray*) arg; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + array->AppendElement(ii); + return PL_DHASH_NEXT; +} + +/* nsIEnumerator enumerateInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_retval) +{ + // I didn't want to incur the size overhead of using nsHashtable just to + // make building an enumerator easier. So, this code makes a snapshot of + // the table using an nsISupportsArray and builds an enumerator for that. + // We can afford this transient cost. + + nsCOMPtr array; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayAppender, array); + + return array->Enumerate(_retval); +} + +struct ArrayAndPrefix +{ + nsISupportsArray* array; + const char* prefix; + PRUint32 length; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_ArrayPrefixAppender(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + ArrayAndPrefix* args = (ArrayAndPrefix*) arg; + + const char* name = entry->GetTheName(); + if(name != PL_strnstr(name, args->prefix, args->length)) + return PL_DHASH_NEXT; + + nsCOMPtr ii; + if(NS_SUCCEEDED(EntryToInfo(entry, getter_AddRefs(ii)))) + args->array->AppendElement(ii); + return PL_DHASH_NEXT; +} + +/* nsIEnumerator enumerateInterfacesWhoseNamesStartWith (in string prefix); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(const char *prefix, nsIEnumerator **_retval) +{ + nsCOMPtr array; + NS_NewISupportsArray(getter_AddRefs(array)); + if(!array) + return NS_ERROR_UNEXPECTED; + + ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)}; + PL_DHashTableEnumerate(mWorkingSet.mNameTable, xpti_ArrayPrefixAppender, &args); + + return array->Enumerate(_retval); +} + +/* void autoRegisterInterfaces (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AutoRegisterInterfaces() +{ + nsCOMPtr fileList; + AutoRegMode mode; + PRBool ok; + + nsAutoLock lock(xptiInterfaceInfoManager::GetAutoRegLock(this)); + + xptiWorkingSet workingSet(mSearchPath); + if(!workingSet.IsValid()) + return NS_ERROR_UNEXPECTED; + + // This sets what will be returned by GetOpenLogFile(). + xptiAutoLog autoLog(this, mAutoRegLogFile, PR_TRUE); + + LOG_AUTOREG(("start AutoRegister\n")); + + // We re-read the manifest rather than muck with the 'live' one. + // It is OK if this fails. + // XXX But we should track failure as a warning. + ok = xptiManifest::Read(this, &workingSet); + + LOG_AUTOREG(("read of manifest %s\n", ok ? "successful" : "FAILED")); + + // Grovel for all the typelibs we can find (in .xpt or .zip, .jar,...). + if(!BuildFileList(mSearchPath, getter_AddRefs(fileList)) || !fileList) + return NS_ERROR_UNEXPECTED; + + // DEBUG_DumpFileList(fileList); + + // Check to see how much work we need to do. + mode = DetermineAutoRegStrategy(mSearchPath, fileList, &workingSet); + + switch(mode) + { + case NO_FILES_CHANGED: + LOG_AUTOREG(("autoreg strategy: no files changed\n")); + LOG_AUTOREG(("successful end of AutoRegister\n")); + return NS_OK; + case FILES_ADDED_ONLY: + LOG_AUTOREG(("autoreg strategy: files added only\n")); + if(!AddOnlyNewFilesFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to add new files\n")); + return NS_ERROR_UNEXPECTED; + } + break; + case FULL_VALIDATION_REQUIRED: + LOG_AUTOREG(("autoreg strategy: doing full validation merge\n")); + if(!DoFullValidationMergeFromFileList(mSearchPath, fileList, &workingSet)) + { + LOG_AUTOREG(("FAILED to do full validation\n")); + return NS_ERROR_UNEXPECTED; + } + break; + default: + NS_ERROR("switch missing a case"); + return NS_ERROR_UNEXPECTED; + } + + // Failure to write the manifest is not fatal in production builds. + // However, this would require the next startup to find and read all the + // xpt files. This will make that startup slower. If this ever becomes a + // chronic problem for anyone, then we'll want to figure out why! + + if(!xptiManifest::Write(this, &workingSet)) + { + LOG_AUTOREG(("FAILED to write manifest\n")); + NS_ERROR("Failed to write xpti manifest!"); + } + + if(!MergeWorkingSets(&mWorkingSet, &workingSet)) + { + LOG_AUTOREG(("FAILED to merge into live workingset\n")); + return NS_ERROR_UNEXPECTED; + } + +// DEBUG_DumpFileListInWorkingSet(mWorkingSet); + + LOG_AUTOREG(("successful end of AutoRegister\n")); + + return NS_OK; +} + +/***************************************************************************/ + +class xptiAdditionalManagersEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + + xptiAdditionalManagersEnumerator(); + + PRBool SizeTo(PRUint32 likelyCount) {return mArray.SizeTo(likelyCount);} + PRBool AppendElement(nsIInterfaceInfoManager* element); + +private: + ~xptiAdditionalManagersEnumerator() {} + + nsSupportsArray mArray; + PRUint32 mIndex; + PRUint32 mCount; +}; + +NS_IMPL_ISUPPORTS1(xptiAdditionalManagersEnumerator, nsISimpleEnumerator) + +xptiAdditionalManagersEnumerator::xptiAdditionalManagersEnumerator() + : mIndex(0), mCount(0) +{ +} + +PRBool xptiAdditionalManagersEnumerator::AppendElement(nsIInterfaceInfoManager* element) +{ + if(!mArray.AppendElement(NS_STATIC_CAST(nsISupports*, element))) + return PR_FALSE; + mCount++; + return PR_TRUE; +} + +/* boolean hasMoreElements (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = mIndex < mCount; + return NS_OK; +} + +/* nsISupports getNext (); */ +NS_IMETHODIMP xptiAdditionalManagersEnumerator::GetNext(nsISupports **_retval) +{ + if(!(mIndex < mCount)) + { + NS_ERROR("Bad nsISimpleEnumerator caller!"); + return NS_ERROR_FAILURE; + } + + *_retval = mArray.ElementAt(mIndex++); + return *_retval ? NS_OK : NS_ERROR_FAILURE; +} + +/***************************************************************************/ + +/* void addAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::AddAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToAdd = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + PRInt32 index; + nsresult rv = mAdditionalManagers.GetIndexOf(ptrToAdd, &index); + if(NS_FAILED(rv) || -1 != index) + return NS_ERROR_FAILURE; + if(!mAdditionalManagers.AppendElement(ptrToAdd)) + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +/* void removeAdditionalManager (in nsIInterfaceInfoManager manager); */ +NS_IMETHODIMP xptiInterfaceInfoManager::RemoveAdditionalManager(nsIInterfaceInfoManager *manager) +{ + nsCOMPtr weakRef = do_GetWeakReference(manager); + nsISupports* ptrToRemove = weakRef ? + NS_STATIC_CAST(nsISupports*, weakRef) : + NS_STATIC_CAST(nsISupports*, manager); + { // scoped lock... + nsAutoLock lock(mAdditionalManagersLock); + if(!mAdditionalManagers.RemoveElement(ptrToRemove)) + return NS_ERROR_FAILURE; + } + return NS_OK; +} + +/* PRBool hasAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::HasAdditionalManagers(PRBool *_retval) +{ + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + *_retval = count != 0; + return rv; +} + +/* nsISimpleEnumerator enumerateAdditionalManagers (); */ +NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateAdditionalManagers(nsISimpleEnumerator **_retval) +{ + nsAutoLock lock(mAdditionalManagersLock); + + PRUint32 count; + nsresult rv = mAdditionalManagers.Count(&count); + if(NS_FAILED(rv)) + return rv; + + nsCOMPtr enumerator = + new xptiAdditionalManagersEnumerator(); + if(!enumerator) + return NS_ERROR_OUT_OF_MEMORY; + + enumerator->SizeTo(count); + + for(PRUint32 i = 0; i < count; /* i incremented in the loop body */) + { + nsCOMPtr raw = + dont_AddRef(mAdditionalManagers.ElementAt(i++)); + if(!raw) + return NS_ERROR_FAILURE; + nsCOMPtr weakRef = do_QueryInterface(raw); + if(weakRef) + { + nsCOMPtr manager = + do_QueryReferent(weakRef); + if(manager) + { + if(!enumerator->AppendElement(manager)) + return NS_ERROR_FAILURE; + } + else + { + // The manager is no more. Remove the element. + if(!mAdditionalManagers.RemoveElementAt(--i)) + return NS_ERROR_FAILURE; + count--; + } + } + else + { + // We *know* we put a pointer to either a nsIWeakReference or + // an nsIInterfaceInfoManager into the array, so we can avoid an + // extra QI here and just do a cast. + if(!enumerator->AppendElement( + NS_REINTERPRET_CAST(nsIInterfaceInfoManager*, raw.get()))) + return NS_ERROR_FAILURE; + } + } + + NS_ADDREF(*_retval = enumerator); + return NS_OK; +} + +/***************************************************************************/ + +XPTI_PUBLIC_API(nsIInterfaceInfoManager*) +XPTI_GetInterfaceInfoManager() +{ + nsIInterfaceInfoManager* iim = + xptiInterfaceInfoManager::GetInterfaceInfoManagerNoAddRef(); + NS_IF_ADDREF(iim); + return iim; +} + +XPTI_PUBLIC_API(void) +XPTI_FreeInterfaceInfoManager() +{ + xptiInterfaceInfoManager::FreeInterfaceInfoManager(); +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp new file mode 100644 index 00000000..03ab7029 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiManifest.cpp @@ -0,0 +1,710 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiManifest. */ + +#include "xptiprivate.h" +#include "nsManifestLineReader.h" +#include "nsString.h" + +static const char g_Disclaimer[] = "# Generated file. ** DO NOT EDIT! **"; + +static const char g_TOKEN_Files[] = "Files"; +static const char g_TOKEN_ArchiveItems[] = "ArchiveItems"; +static const char g_TOKEN_Interfaces[] = "Interfaces"; +static const char g_TOKEN_Header[] = "Header"; +static const char g_TOKEN_Version[] = "Version"; +static const char g_TOKEN_AppDir[] = "AppDir"; +static const char g_TOKEN_Directories[] = "Directories"; + +static const int g_VERSION_MAJOR = 2; +static const int g_VERSION_MINOR = 0; + +/***************************************************************************/ + +static PRBool +GetCurrentAppDirString(xptiInterfaceInfoManager* aMgr, nsACString &aStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + if(appDir) + return NS_SUCCEEDED(appDir->GetPersistentDescriptor(aStr)); + return PR_FALSE; +} + +static PRBool +CurrentAppDirMatchesPersistentDescriptor(xptiInterfaceInfoManager* aMgr, + const char *inStr) +{ + nsCOMPtr appDir; + aMgr->GetApplicationDir(getter_AddRefs(appDir)); + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inStr)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = appDir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_InterfaceWriter(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + PRFileDesc* fd = (PRFileDesc*) arg; + + char* iidStr = entry->GetTheIID()->ToString(); + if(!iidStr) + return PL_DHASH_STOP; + + const xptiTypelib& typelib = entry->GetTypelibRecord(); + + PRBool success = PR_fprintf(fd, "%d,%s,%s,%d,%d,%d\n", + (int) number, + entry->GetTheName(), + iidStr, + (int) typelib.GetFileIndex(), + (int) (typelib.IsZip() ? + typelib.GetZipItemIndex() : -1), + (int) entry->GetScriptableFlag()); + + nsCRT::free(iidStr); + + return success ? PL_DHASH_NEXT : PL_DHASH_STOP; +} + + +// static +PRBool xptiManifest::Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + + PRBool succeeded = PR_FALSE; + PRFileDesc* fd = nsnull; + PRUint32 i; + PRUint32 size32; + PRIntn interfaceCount = 0; + nsCAutoString appDirString; + + nsCOMPtr tempFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(tempFile)) || !tempFile) + return PR_FALSE; + + nsCAutoString originalLeafName; + tempFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + tempFile->SetNativeLeafName(leafName); + + // All exits via "goto out;" from here on... + if(NS_FAILED(tempFile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0600, &fd)) || !fd) + { + goto out; + } + + // write file header comments + + if(!PR_fprintf(fd, "%s\n", g_Disclaimer)) + goto out; + + // write the [Header] block, version number, and appdir. + + if(!PR_fprintf(fd, "\n[%s,%d]\n", g_TOKEN_Header, 2)) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%d,%d\n", + 0, g_TOKEN_Version, g_VERSION_MAJOR, g_VERSION_MINOR)) + goto out; + + GetCurrentAppDirString(aMgr, appDirString); + if(appDirString.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s,%s\n", + 1, g_TOKEN_AppDir, appDirString.get())) + goto out; + + // write Directories list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Directories, + (int) aWorkingSet->GetDirectoryCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetDirectoryCount(); i++) + { + nsCOMPtr dir; + nsCAutoString str; + + aWorkingSet->GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + goto out; + + dir->GetPersistentDescriptor(str); + if(str.IsEmpty()) + goto out; + + if(!PR_fprintf(fd, "%d,%s\n", (int) i, str.get())) + goto out; + } + + // write Files list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Files, + (int) aWorkingSet->GetFileCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetFileCount(); i++) + { + const xptiFile& file = aWorkingSet->GetFileAt(i); + + LL_L2UI(size32, file.GetSize()); + + if(!PR_fprintf(fd, "%d,%s,%d,%u,%lld\n", + (int) i, + file.GetName(), + (int) file.GetDirectory(), + size32, PRInt64(file.GetDate()))) + goto out; + } + + // write ArchiveItems list + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_ArchiveItems, + (int) aWorkingSet->GetZipItemCount())) + goto out; + + for(i = 0; i < aWorkingSet->GetZipItemCount(); i++) + { + if(!PR_fprintf(fd, "%d,%s\n", + (int) i, + aWorkingSet->GetZipItemAt(i).GetName())) + goto out; + } + + // write the Interfaces list + + interfaceCount = aWorkingSet->mNameTable->entryCount; + + if(!PR_fprintf(fd, "\n[%s,%d]\n", + g_TOKEN_Interfaces, + (int) interfaceCount)) + goto out; + + if(interfaceCount != (PRIntn) + PL_DHashTableEnumerate(aWorkingSet->mNameTable, + xpti_InterfaceWriter, fd)) + goto out; + + + if(PR_SUCCESS == PR_Close(fd)) + { + succeeded = PR_TRUE; + } + fd = nsnull; + +out: + if(fd) + PR_Close(fd); + + if(succeeded) + { + // delete the old file and rename this + nsCOMPtr mainFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(mainFile)) || !mainFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(mainFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mainFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mainFile->GetParent(getter_AddRefs(parent)); + + // MoveTo means rename. + if(NS_FAILED(tempFile->MoveToNative(parent, originalLeafName))) + return PR_FALSE; + } + + return succeeded; +} + +/***************************************************************************/ +/***************************************************************************/ + +static char* +ReadManifestIntoMemory(xptiInterfaceInfoManager* aMgr, + PRUint32* pLength) +{ + PRFileDesc* fd = nsnull; + PRInt32 flen; + PRInt64 fileSize; + char* whole = nsnull; + PRBool success = PR_FALSE; + + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return nsnull; + +#ifdef DEBUG + { + static PRBool shown = PR_FALSE; + + nsCAutoString path; + if(!shown && NS_SUCCEEDED(aFile->GetNativePath(path)) && !path.IsEmpty()) + { + fprintf(stderr, "Type Manifest File: %s\n", path.get()); + shown = PR_TRUE; + } + } +#endif + + if(NS_FAILED(aFile->GetFileSize(&fileSize)) || !(flen = nsInt64(fileSize))) + return nsnull; + + whole = new char[flen]; + if (!whole) + return nsnull; + + // All exits from on here should be via 'goto out' + + if(NS_FAILED(aFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd)) || !fd) + goto out; + + if(flen > PR_Read(fd, whole, flen)) + goto out; + + success = PR_TRUE; + + out: + if(fd) + PR_Close(fd); + + if(!success) + { + delete [] whole; + return nsnull; + } + + *pLength = flen; + return whole; +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, + const char *token, int minCount, int* count) +{ + while(1) + { + if(!reader.NextLine()) + break; + if(*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if(*p != ']') + break; + *p = 0; + + char* values[2]; + int lengths[2]; + if(2 != reader.ParseLine(values, lengths, 2)) + break; + + // ignore the leading '[' + if(0 != PL_strcmp(values[0]+1, token)) + break; + + if((*count = atoi(values[1])) < minCount) + break; + + return PR_TRUE; + } + } + return PR_FALSE; +} + + +// static +PRBool xptiManifest::Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) +{ + int i; + char* whole = nsnull; + PRBool succeeded = PR_FALSE; + PRUint32 flen = 0; + nsManifestLineReader reader; + xptiHashEntry* hashEntry; + int headerCount = 0; + int dirCount = 0; + int fileCount = 0; + int zipItemCount = -1; + int interfaceCount = 0; + int dir; + int flags; + char* values[6]; // 6 is currently the max items we need to parse + int lengths[6]; + PRUint32 size32; + PRInt64 size; + PRInt64 date; + + whole = ReadManifestIntoMemory(aMgr, &flen); + if(!whole) + return PR_FALSE; + + reader.Init(whole, flen); + + // All exits from here on should be via 'goto out' + + // Look for "Header" section + + // This version accepts only version 1,0. We also freak if the header + // has more than one entry. The rationale is that we want to force an + // autoreg if the xpti.dat file was written by *any* other version of + // the software. Future versions may wish to support updating older + // manifests in some interesting way. + + if(!ReadSectionHeader(reader, g_TOKEN_Header, 2, &headerCount)) + goto out; + + if(headerCount != 2) + goto out; + + // Verify the version number + + if(!reader.NextLine()) + goto out; + + // index,VersionLiteral,major,minor + if(4 != reader.ParseLine(values, lengths, 4)) + goto out; + + // index + if(0 != atoi(values[0])) + goto out; + + // VersionLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_Version)) + goto out; + + // major + if(g_VERSION_MAJOR != atoi(values[2])) + goto out; + + // minor + if(g_VERSION_MINOR != atoi(values[3])) + goto out; + + // Verify the application directory + + if(!reader.NextLine()) + goto out; + + // index,AppDirLiteral,directoryname + if(3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // index + if(1 != atoi(values[0])) + goto out; + + // AppDirLiteral + if(0 != PL_strcmp(values[1], g_TOKEN_AppDir)) + goto out; + + if(!CurrentAppDirMatchesPersistentDescriptor(aMgr, values[2])) + goto out; + + // Look for "Directories" section + + if(!ReadSectionHeader(reader, g_TOKEN_Directories, 1, &dirCount)) + goto out; + else + { + // To validate that the directory list matches the current search path + // we first confirm that the list lengths match. + + nsCOMPtr searchPath; + aMgr->GetSearchPath(getter_AddRefs(searchPath)); + + PRUint32 searchPathCount; + searchPath->Count(&searchPathCount); + + if(dirCount != (int) searchPathCount) + goto out; + } + + // Read the directory records + + for(i = 0; i < dirCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,directoryname + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // directoryname + if(!aWorkingSet->DirectoryAtMatchesPersistentDescriptor(i, values[1])) + goto out; + } + + // Look for "Files" section + + if(!ReadSectionHeader(reader, g_TOKEN_Files, 1, &fileCount)) + goto out; + + + // Alloc room in the WorkingSet for the filearray. + + if(!aWorkingSet->NewFileArray(fileCount)) + goto out; + + // Read the file records + + for(i = 0; i < fileCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,filename,dirIndex,dilesSize,filesDate + if(5 != reader.ParseLine(values, lengths, 5)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // dirIndex + dir = atoi(values[2]); + if(dir < 0 || dir > dirCount) + goto out; + + // fileSize + size32 = atoi(values[3]); + if(size32 <= 0) + goto out; + LL_UI2L(size, size32); + + // fileDate + date = nsCRT::atoll(values[4]); + if(LL_IS_ZERO(date)) + goto out; + + // Append a new file record to the array. + + aWorkingSet->AppendFile( + xptiFile(nsInt64(size), nsInt64(date), dir, values[1], aWorkingSet)); + } + + // Look for "ZipItems" section + + if(!ReadSectionHeader(reader, g_TOKEN_ArchiveItems, 0, &zipItemCount)) + goto out; + + // Alloc room in the WorkingSet for the zipItemarray. + + if(zipItemCount) + if(!aWorkingSet->NewZipItemArray(zipItemCount)) + goto out; + + // Read the zipItem records + + for(i = 0; i < zipItemCount; ++i) + { + if(!reader.NextLine()) + goto out; + + // index,filename + if(2 != reader.ParseLine(values, lengths, 2)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // filename + if(!*values[1]) + goto out; + + // Append a new zipItem record to the array. + + aWorkingSet->AppendZipItem(xptiZipItem(values[1], aWorkingSet)); + } + + // Look for "Interfaces" section + + if(!ReadSectionHeader(reader, g_TOKEN_Interfaces, 1, &interfaceCount)) + goto out; + + // Read the interface records + + for(i = 0; i < interfaceCount; ++i) + { + int fileIndex; + int zipItemIndex; + nsIID iid; + xptiInterfaceEntry* entry; + xptiTypelib typelibRecord; + + if(!reader.NextLine()) + goto out; + + // index,interfaceName,iid,fileIndex,zipIndex,flags + if(6 != reader.ParseLine(values, lengths, 6)) + goto out; + + // index + if(i != atoi(values[0])) + goto out; + + // interfaceName + if(!*values[1]) + goto out; + + // iid + if(!iid.Parse(values[2])) + goto out; + + // fileIndex + fileIndex = atoi(values[3]); + if(fileIndex < 0 || fileIndex >= fileCount) + goto out; + + // zipIndex (NOTE: -1 is a valid value) + zipItemIndex = atoi(values[4]); + if(zipItemIndex < -1 || zipItemIndex >= zipItemCount) + goto out; + + // flags + flags = atoi(values[5]); + if(flags != 0 && flags != 1) + goto out; + + // Build an InterfaceInfo and hook it in. + + if(zipItemIndex == -1) + typelibRecord.Init(fileIndex); + else + typelibRecord.Init(fileIndex, zipItemIndex); + + entry = xptiInterfaceEntry::NewEntry(values[1], lengths[1], + iid, typelibRecord, + aWorkingSet); + if(!entry) + goto out; + + entry->SetScriptableFlag(flags==1); + + // Add our entry to the iid hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mNameTable, + entry->GetTheName(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + + // Add our entry to the name hashtable. + + hashEntry = (xptiHashEntry*) + PL_DHashTableOperate(aWorkingSet->mIIDTable, + entry->GetTheIID(), PL_DHASH_ADD); + if(hashEntry) + hashEntry->value = entry; + } + + // success! + + succeeded = PR_TRUE; + + out: + if(whole) + delete [] whole; + + if(!succeeded) + { + // Cleanup the WorkingSet on failure. + aWorkingSet->InvalidateInterfaceInfos(); + aWorkingSet->ClearHashTables(); + aWorkingSet->ClearFiles(); + } + return succeeded; +} + +// static +PRBool xptiManifest::Delete(xptiInterfaceInfoManager* aMgr) +{ + nsCOMPtr aFile; + if(!aMgr->GetCloneOfManifestLocation(getter_AddRefs(aFile)) || !aFile) + return PR_FALSE; + + PRBool exists; + if(NS_FAILED(aFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(aFile->Remove(PR_FALSE))) + return PR_FALSE; + + return PR_TRUE; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp new file mode 100644 index 00000000..a1dbf5c3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiMisc.cpp @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of misc. xpti stuff. */ + +#include "xptiprivate.h" + +struct xptiFileTypeEntry +{ + const char* name; + int len; + xptiFileType::Type type; +}; + +static const xptiFileTypeEntry g_Entries[] = + { + {".xpt", 4, xptiFileType::XPT}, + {".zip", 4, xptiFileType::ZIP}, + {".jar", 4, xptiFileType::ZIP}, + {nsnull, 0, xptiFileType::UNKNOWN} + }; + +// static +xptiFileType::Type xptiFileType::GetType(const char* name) +{ + NS_ASSERTION(name, "loser!"); + int len = PL_strlen(name); + for(const xptiFileTypeEntry* p = g_Entries; p->name; p++) + { + if(len > p->len && 0 == PL_strcasecmp(p->name, &(name[len - p->len]))) + return p->type; + } + return UNKNOWN; +} + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiAutoLog) + +xptiAutoLog::xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append) + : mMgr(nsnull), mOldFileDesc(nsnull) +{ + MOZ_COUNT_CTOR(xptiAutoLog); + + if(mgr && logfile) + { + PRFileDesc* fd; + if(NS_SUCCEEDED(logfile-> + OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_APPEND | + (append ? 0 : PR_TRUNCATE), + 0600, &fd)) && fd) + { +#ifdef DEBUG + m_DEBUG_FileDesc = fd; +#endif + mMgr = mgr; + mOldFileDesc = mMgr->SetOpenLogFile(fd); + if(append) + PR_Seek(fd, 0, PR_SEEK_END); + WriteTimestamp(fd, "++++ start logging "); + + } + else + { +#ifdef DEBUG + printf("xpti failed to open log file for writing\n"); +#endif + } + } +} + +xptiAutoLog::~xptiAutoLog() +{ + MOZ_COUNT_DTOR(xptiAutoLog); + + if(mMgr) + { + PRFileDesc* fd = mMgr->SetOpenLogFile(mOldFileDesc); + NS_ASSERTION(fd == m_DEBUG_FileDesc, "bad unravel"); + if(fd) + { + WriteTimestamp(fd, "---- end logging "); + PR_Close(fd); + } + } +} + +void xptiAutoLog::WriteTimestamp(PRFileDesc* fd, const char* msg) +{ + PRExplodedTime expTime; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &expTime); + char time[128]; + PR_FormatTimeUSEnglish(time, 128, "%Y-%m-%d-%H:%M:%S", &expTime); + PR_fprintf(fd, "\n%s %s\n\n", msg, time); +} + +/***************************************************************************/ + +nsresult +xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile) +{ + nsresult rv; + nsCOMPtr cloneRaw; + + rv = aLocalFile->Clone(getter_AddRefs(cloneRaw)); + if(NS_FAILED(rv)) + return rv; + + return CallQueryInterface(cloneRaw, aCloneLocalFile); +} + + +nsresult +xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile) +{ + nsresult rv; + nsCOMPtr original; + + rv = aArray->QueryElementAt(aIndex, NS_GET_IID(nsILocalFile), + getter_AddRefs(original)); + if(NS_FAILED(rv)) + return rv; + + return xptiCloneLocalFile(original, aLocalFile); +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp new file mode 100644 index 00000000..50956585 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiTypelibGuts.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiTypelibGuts. */ + +#include "xptiprivate.h" + +// static +xptiTypelibGuts* +xptiTypelibGuts::NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(aHeader, "bad param"); + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiTypelibGuts) + + (sizeof(xptiInterfaceEntry*) * + (aHeader->num_interfaces - 1))); + if(!place) + return nsnull; + return new(place) xptiTypelibGuts(aHeader); +} + +xptiTypelibGuts::xptiTypelibGuts(XPTHeader* aHeader) + : mHeader(aHeader) +{ + // empty +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp new file mode 100644 index 00000000..b9602726 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiWorkingSet.cpp @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiWorkingSet. */ + +#include "xptiprivate.h" +#include "nsString.h" + +#define XPTI_STRING_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_STRUCT_ARENA_BLOCK_SIZE (1024 * 1) +#define XPTI_HASHTABLE_SIZE 128 + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +IIDGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheIID(); +} + +PR_STATIC_CALLBACK(PLDHashNumber) +IIDHash(PLDHashTable *table, const void *key) +{ + return (PLDHashNumber) ((const nsIID*)key)->m0; +} + +PR_STATIC_CALLBACK(PRBool) +IIDMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const nsIID* iid1 = ((xptiHashEntry*)entry)->value->GetTheIID(); + const nsIID* iid2 = (const nsIID*)key; + + return iid1 == iid2 || iid1->Equals(*iid2); +} + +const static struct PLDHashTableOps IIDTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + IIDGetKey, + IIDHash, + IIDMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +PR_STATIC_CALLBACK(const void*) +NameGetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + return ((xptiHashEntry*)entry)->value->GetTheName(); +} + +PR_STATIC_CALLBACK(PRBool) +NameMatch(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const char* str1 = ((xptiHashEntry*)entry)->value->GetTheName(); + const char* str2 = (const char*) key; + return str1 == str2 || 0 == PL_strcmp(str1, str2); +} + +static const struct PLDHashTableOps NameTableOps = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + NameGetKey, + PL_DHashStringKey, + NameMatch, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +/***************************************************************************/ + +MOZ_DECL_CTOR_COUNTER(xptiWorkingSet) + +xptiWorkingSet::xptiWorkingSet(nsISupportsArray* aDirectories) + : mFileCount(0), + mMaxFileCount(0), + mFileArray(nsnull), + mZipItemCount(0), + mMaxZipItemCount(0), + mZipItemArray(nsnull), + mStringArena(XPT_NewArena(XPTI_STRING_ARENA_BLOCK_SIZE, sizeof(char), + "xptiWorkingSet strings")), + mStructArena(XPT_NewArena(XPTI_STRUCT_ARENA_BLOCK_SIZE, sizeof(double), + "xptiWorkingSet structs")), + mDirectories(aDirectories), + mNameTable(PL_NewDHashTable(&NameTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mIIDTable(PL_NewDHashTable(&IIDTableOps, nsnull, sizeof(xptiHashEntry), + XPTI_HASHTABLE_SIZE)), + mFileMergeOffsetMap(nsnull), + mZipItemMergeOffsetMap(nsnull) +{ + MOZ_COUNT_CTOR(xptiWorkingSet); + // do nothing else... +} + +PRBool +xptiWorkingSet::IsValid() const +{ + return (mFileCount == 0 || mFileArray) && + (mZipItemCount == 0 || mZipItemArray) && + mStringArena && + mStructArena && + mNameTable && + mIIDTable; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Remover(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + return PL_DHASH_REMOVE; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +xpti_Invalidator(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + xptiInterfaceEntry* entry = ((xptiHashEntry*)hdr)->value; + entry->LockedInvalidateInterfaceInfo(); + return PL_DHASH_NEXT; +} + +void +xptiWorkingSet::InvalidateInterfaceInfos() +{ + if(mNameTable) + { + nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor()); + PL_DHashTableEnumerate(mNameTable, xpti_Invalidator, nsnull); + } +} + +void +xptiWorkingSet::ClearHashTables() +{ + if(mNameTable) + PL_DHashTableEnumerate(mNameTable, xpti_Remover, nsnull); + + if(mIIDTable) + PL_DHashTableEnumerate(mIIDTable, xpti_Remover, nsnull); +} + +void +xptiWorkingSet::ClearFiles() +{ + if(mFileArray) + delete [] mFileArray; + mFileArray = nsnull; + mMaxFileCount = 0; + mFileCount = 0; +} + +void +xptiWorkingSet::ClearZipItems() +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemArray = nsnull; + mMaxZipItemCount = 0; + mZipItemCount = 0; +} + +xptiWorkingSet::~xptiWorkingSet() +{ + MOZ_COUNT_DTOR(xptiWorkingSet); + + ClearFiles(); + ClearZipItems(); + ClearHashTables(); + + if(mNameTable) + PL_DHashTableDestroy(mNameTable); + + if(mIIDTable) + PL_DHashTableDestroy(mIIDTable); + + if(mFileArray) + delete [] mFileArray; + + if(mZipItemArray) + delete [] mZipItemArray; + + // Destroy arenas last in case they are referenced in other members' dtors. + + if(mStringArena) + { +#ifdef DEBUG + XPT_DumpStats(mStringArena); +#endif + XPT_DestroyArena(mStringArena); + } + + if(mStructArena) + { +#ifdef DEBUG + XPT_DumpStats(mStructArena); +#endif + XPT_DestroyArena(mStructArena); + } +} + +PRUint32 +xptiWorkingSet::FindFile(PRUint32 dir, const char* name) +{ + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount;++i) + { + xptiFile& file = mFileArray[i]; + if(file.GetDirectory() == dir && + 0 == PL_strcmp(name, file.GetName())) + { + return i; + } + } + } + return NOT_FOUND; +} + +PRBool +xptiWorkingSet::NewFileArray(PRUint32 count) +{ + if(mFileArray) + delete [] mFileArray; + mFileCount = 0; + mFileArray = new xptiFile[count]; + if(!mFileArray) + { + mMaxFileCount = 0; + return PR_FALSE; + } + mMaxFileCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendFileArray(PRUint32 count) +{ + if(mFileArray && count < mMaxFileCount) + return PR_TRUE; + + xptiFile* newArray = new xptiFile[count]; + if(!newArray) + return PR_FALSE; + + if(mFileArray) + { + for(PRUint32 i = 0; i < mFileCount; ++i) + newArray[i] = mFileArray[i]; + delete [] mFileArray; + } + mFileArray = newArray; + mMaxFileCount = count; + return PR_TRUE; +} + +/***************************************************************************/ + +PRUint32 +xptiWorkingSet::FindZipItemWithName(const char* name) +{ + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount;++i) + if(0 == PL_strcmp(name, mZipItemArray[i].GetName())) + return i; + } + return NOT_FOUND; +} + +PRBool +xptiWorkingSet::NewZipItemArray(PRUint32 count) +{ + if(mZipItemArray) + delete [] mZipItemArray; + mZipItemCount = 0; + mZipItemArray = new xptiZipItem[count]; + if(!mZipItemArray) + { + mMaxZipItemCount = 0; + return PR_FALSE; + } + mMaxZipItemCount = count; + return PR_TRUE; +} + +PRBool +xptiWorkingSet::ExtendZipItemArray(PRUint32 count) +{ + if(mZipItemArray && count < mMaxZipItemCount) + return PR_TRUE; + + xptiZipItem* newArray = new xptiZipItem[count]; + if(!newArray) + return PR_FALSE; + + if(mZipItemArray) + { + for(PRUint32 i = 0; i < mZipItemCount; ++i) + newArray[i] = mZipItemArray[i]; + delete [] mZipItemArray; + } + mZipItemArray = newArray; + mMaxZipItemCount = count; + return PR_TRUE; +} + +/***************************************************************************/ +// Directory stuff... + +PRUint32 xptiWorkingSet::GetDirectoryCount() +{ + PRUint32 count = 0; + mDirectories->Count(&count); + return count; +} + +nsresult xptiWorkingSet::GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return xptiCloneElementAsLocalFile(mDirectories, i, dir); +} + +nsresult xptiWorkingSet::GetDirectoryAt(PRUint32 i, nsILocalFile** dir) +{ + return mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), (void**)dir); +} + +PRBool xptiWorkingSet::FindDirectory(nsILocalFile* dir, PRUint32* index) +{ + PRUint32 count; + nsresult rv = mDirectories->Count(&count); + if(NS_FAILED(rv)) + return PR_FALSE; + + for(PRUint32 i = 0; i < count; i++) + { + PRBool same; + nsCOMPtr current; + mDirectories->QueryElementAt(i, NS_GET_IID(nsILocalFile), + getter_AddRefs(current)); + if(!current || NS_FAILED(current->Equals(dir, &same))) + break; + if(same) + { + *index = i; + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool xptiWorkingSet::FindDirectoryOfFile(nsILocalFile* file, PRUint32* index) +{ + nsCOMPtr dirAbstract; + file->GetParent(getter_AddRefs(dirAbstract)); + if(!dirAbstract) + return PR_FALSE; + nsCOMPtr dir = do_QueryInterface(dirAbstract); + if(!dir) + return PR_FALSE; + return FindDirectory(dir, index); +} + +PRBool xptiWorkingSet::DirectoryAtMatchesPersistentDescriptor(PRUint32 i, + const char* inDesc) +{ + nsCOMPtr dir; + GetDirectoryAt(i, getter_AddRefs(dir)); + if(!dir) + return PR_FALSE; + + nsCOMPtr descDir; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), PR_FALSE, getter_AddRefs(descDir)); + if(NS_FAILED(rv)) + return PR_FALSE; + + rv = descDir->SetPersistentDescriptor(nsDependentCString(inDesc)); + if(NS_FAILED(rv)) + return PR_FALSE; + + PRBool matches; + rv = dir->Equals(descDir, &matches); + return NS_SUCCEEDED(rv) && matches; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp new file mode 100644 index 00000000..c9a6178b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipItem.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiZipItem. */ + +#include "xptiprivate.h" + +MOZ_DECL_CTOR_COUNTER(xptiZipItem) + +xptiZipItem::xptiZipItem() + : +#ifdef DEBUG + mDEBUG_WorkingSet(nsnull), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + // empty +} + +xptiZipItem::xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet) + + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(aName), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), aName); +} + +xptiZipItem::xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet) + : +#ifdef DEBUG + mDEBUG_WorkingSet(aWorkingSet), +#endif + mName(nsnull), + mGuts(nsnull) +{ + MOZ_COUNT_CTOR(xptiZipItem); + + NS_ASSERTION(aWorkingSet,"bad param"); + mName = XPT_STRDUP(aWorkingSet->GetStringArena(), r.mName); +} + +xptiZipItem::~xptiZipItem() +{ + MOZ_COUNT_DTOR(xptiZipItem); +} + +PRBool +xptiZipItem::SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet) +{ + NS_ASSERTION(!mGuts,"bad state"); + NS_ASSERTION(aHeader,"bad param"); + NS_ASSERTION(aWorkingSet,"bad param"); + + mGuts = xptiTypelibGuts::NewGuts(aHeader, aWorkingSet); + return mGuts != nsnull; +} diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp new file mode 100644 index 00000000..caba49d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiZipLoader.cpp @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of xptiZipLoader. */ + +#include "xptiprivate.h" + +XPTHeader* +xptiZipLoader::ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet) +{ + XPTCursor cursor; + PRUint32 totalRead = 0; + XPTState *state = nsnull; + XPTHeader *header = nsnull; + + PRUint32 flen; + stream->Available(&flen); + + char *whole = new char[flen]; + if (!whole) + { + return nsnull; + } + + // all exits from on here should be via 'goto out' + + while(flen - totalRead) + { + PRUint32 avail; + PRUint32 read; + + if(NS_FAILED(stream->Available(&avail))) + { + goto out; + } + + if(avail > flen) + { + goto out; + } + + if(NS_FAILED(stream->Read(whole+totalRead, avail, &read))) + { + goto out; + } + + totalRead += read; + } + + // Go ahead and close the stream now. + stream = nsnull; + + if(!(state = XPT_NewXDRState(XPT_DECODE, whole, flen))) + { + goto out; + } + + if(!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) + { + goto out; + } + + if (!XPT_DoHeader(aWorkingSet->GetStructArena(), &cursor, &header)) + { + header = nsnull; + goto out; + } + + out: + if(state) + XPT_DestroyXDRState(state); + if(whole) + delete [] whole; + return header; +} + diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h new file mode 100644 index 00000000..3d159c2c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiprivate.h @@ -0,0 +1,981 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike McCabe + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Library-private header for Interface Info system. */ + +#ifndef xptiprivate_h___ +#define xptiprivate_h___ + +#include "nscore.h" +#include "nsISupports.h" + +// this after nsISupports, to pick up IID +// so that xpt stuff doesn't try to define it itself... +#include "xpt_struct.h" +#include "xpt_xdr.h" + +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" +#include "nsIXPTLoader.h" + +#include "nsIServiceManager.h" +#include "nsILocalFile.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "nsIWeakReference.h" + +#include "nsCRT.h" +#include "nsMemory.h" + +#include "nsISupportsArray.h" +#include "nsSupportsArray.h" +#include "nsInt64.h" + +#include "nsQuickSort.h" + +#include "nsXPIDLString.h" + +#include "nsIInputStream.h" + +#include "nsAutoLock.h" + +#include "pldhash.h" +#include "plstr.h" +#include "prprf.h" +#include "prio.h" +#include "prtime.h" +#include "prenv.h" + +#include +#include + +/***************************************************************************/ + +#if 0 && defined(DEBUG_jband) +#define LOG_RESOLVE(x) printf x +#define LOG_LOAD(x) printf x +#define LOG_AUTOREG(x) do{printf x; xptiInterfaceInfoManager::WriteToLog x;}while(0) +#else +#define LOG_RESOLVE(x) ((void)0) +#define LOG_LOAD(x) ((void)0) +#define LOG_AUTOREG(x) xptiInterfaceInfoManager::WriteToLog x +#endif + +#if 1 && defined(DEBUG_jband) +#define SHOW_INFO_COUNT_STATS +#endif + +/***************************************************************************/ + +class xptiFile; +class xptiInterfaceInfo; +class xptiInterfaceInfoManager; +class xptiInterfaceEntry; +class xptiInterfaceGuts; +class xptiTypelibGuts; +class xptiWorkingSet; + +/***************************************************************************/ + +class xptiTypelib +{ +public: + // No ctors or dtors so that we can be in a union in xptiInterfaceInfo. + // Allow automatic shallow copies. + + uint16 GetFileIndex() const {return mFileIndex;} + uint16 GetZipItemIndex() const {return mZipItemIndex;} + + enum {NOT_ZIP = 0xffff}; + + PRBool IsZip() const {return mZipItemIndex != NOT_ZIP;} + + void Init(uint16 aFileIndex, uint16 aZipItemIndex = NOT_ZIP) + {mFileIndex = aFileIndex; mZipItemIndex = aZipItemIndex;} + + PRBool Equals(const xptiTypelib& r) const + {return mFileIndex == r.mFileIndex && + mZipItemIndex == r.mZipItemIndex;} + +private: + uint16 mFileIndex; + uint16 mZipItemIndex; +}; + +/***************************************************************************/ + +// No virtuals. +// These are always constructed in the struct arena using placement new. +// dtor need not be called. + +class xptiTypelibGuts +{ +public: + static xptiTypelibGuts* NewGuts(XPTHeader* aHeader, + xptiWorkingSet* aWorkingSet); + + XPTHeader* GetHeader() {return mHeader;} + PRUint16 GetEntryCount() const {return mHeader->num_interfaces;} + + void SetEntryAt(PRUint16 i, xptiInterfaceEntry* ptr) + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + mEntryArray[i] = ptr; + } + + xptiInterfaceEntry* GetEntryAt(PRUint16 i) const + { + NS_ASSERTION(mHeader,"bad state!"); + NS_ASSERTION(i < GetEntryCount(),"bad param!"); + return mEntryArray[i]; + } + +private: + xptiTypelibGuts(); // not implemented + xptiTypelibGuts(XPTHeader* aHeader); + ~xptiTypelibGuts() {} + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + +private: + XPTHeader* mHeader; // hold pointer into arena + xptiInterfaceEntry* mEntryArray[1]; // Always last. Sized to fit. +}; + +/***************************************************************************/ + +class xptiFile +{ +public: + const nsInt64& GetSize() const {return mSize;} + const nsInt64& GetDate() const {return mDate;} + const char* GetName() const {return mName;} + /*const*/ PRUint32 GetDirectory() const {return mDirectory;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiFile(); + + xptiFile(const nsInt64& aSize, + const nsInt64& aDate, + PRUint32 aDirectory, + const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiFile(const xptiFile& r, xptiWorkingSet* aWorkingSet); + + ~xptiFile(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + PRBool Equals(const xptiFile& r) const + { + return mDirectory == r.mDirectory && + mSize == r.mSize && + mDate == r.mDate && + 0 == PL_strcmp(mName, r.mName); + } + + xptiFile(const xptiFile& r) {CopyFields(r);} + xptiFile& operator= (const xptiFile& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiFile& r) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mSize = r.mSize; + mDate = r.mDate; + mName = r.mName; + mDirectory = r.mDirectory; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + nsInt64 mSize; + nsInt64 mDate; + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena + PRUint32 mDirectory; +}; + +/***************************************************************************/ + +class xptiZipItem +{ +public: + const char* GetName() const {return mName;} + xptiTypelibGuts* GetGuts() {return mGuts;} + + xptiZipItem(); + + xptiZipItem(const char* aName, + xptiWorkingSet* aWorkingSet); + + xptiZipItem(const xptiZipItem& r, xptiWorkingSet* aWorkingSet); + + ~xptiZipItem(); + + PRBool SetHeader(XPTHeader* aHeader, xptiWorkingSet* aWorkingSet); + + PRBool Equals(const xptiZipItem& r) const + { + return 0 == PL_strcmp(mName, r.mName); + } + + xptiZipItem(const xptiZipItem& r) {CopyFields(r);} + xptiZipItem& operator= (const xptiZipItem& r) + { + if(this != &r) + CopyFields(r); + return *this; + } + +private: + void CopyFields(const xptiZipItem& r) + { +#ifdef DEBUG + // If 'this' has a workingset then it better match that of the assigner. + NS_ASSERTION(!mDEBUG_WorkingSet || + mDEBUG_WorkingSet == r.mDEBUG_WorkingSet, + "illegal xptiFile assignment"); + mDEBUG_WorkingSet = r.mDEBUG_WorkingSet; +#endif + + mName = r.mName; + mGuts = r.mGuts; + } + +private: +#ifdef DEBUG + xptiWorkingSet* mDEBUG_WorkingSet; +#endif + const char* mName; // hold pointer into arena from initializer + xptiTypelibGuts* mGuts; // hold pointer into arena +}; + +/***************************************************************************/ + +class xptiWorkingSet +{ +public: + xptiWorkingSet(); // not implmented + xptiWorkingSet(nsISupportsArray* aDirectories); + ~xptiWorkingSet(); + + PRBool IsValid() const; + + void InvalidateInterfaceInfos(); + void ClearHashTables(); + void ClearFiles(); + void ClearZipItems(); + + // utility methods... + + xptiTypelibGuts* GetTypelibGuts(const xptiTypelib& typelib) + { + return typelib.IsZip() ? + GetZipItemAt(typelib.GetZipItemIndex()).GetGuts() : + GetFileAt(typelib.GetFileIndex()).GetGuts(); + } + + enum {NOT_FOUND = 0xffffffff}; + + // FileArray stuff... + + PRUint32 GetFileCount() const {return mFileCount;} + PRUint32 GetFileFreeSpace() + {return mFileArray ? mMaxFileCount - mFileCount : 0;} + + PRUint32 FindFile(PRUint32 dir, const char* name); + + PRUint32 GetTypelibDirectoryIndex(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetDirectory(); + } + + const char* GetTypelibFileName(const xptiTypelib& typelib) + { + return GetFileAt(typelib.GetFileIndex()).GetName(); + } + + xptiFile& GetFileAt(PRUint32 i) const + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + return mFileArray[i]; + } + + void SetFileAt(PRUint32 i, const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(i < mFileCount, "bad param!"); + mFileArray[i] = r; + } + + void AppendFile(const xptiFile& r) + { + NS_ASSERTION(mFileArray, "bad state!"); + NS_ASSERTION(mFileCount < mMaxFileCount, "bad param!"); + mFileArray[mFileCount++] = r; + } + + PRBool NewFileArray(PRUint32 count); + PRBool ExtendFileArray(PRUint32 count); + + // ZipItemArray stuff... + + PRUint32 GetZipItemCount() const {return mZipItemCount;} + PRUint32 GetZipItemFreeSpace() + {return mZipItemArray ? mMaxZipItemCount - mZipItemCount : 0;} + + PRUint32 FindZipItemWithName(const char* name); + + xptiZipItem& GetZipItemAt(PRUint32 i) const + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + return mZipItemArray[i]; + } + + void SetZipItemAt(PRUint32 i, const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(i < mZipItemCount, "bad param!"); + mZipItemArray[i] = r; + } + + void AppendZipItem(const xptiZipItem& r) + { + NS_ASSERTION(mZipItemArray, "bad state!"); + NS_ASSERTION(mZipItemCount < mMaxZipItemCount, "bad param!"); + mZipItemArray[mZipItemCount++] = r; + } + + PRBool NewZipItemArray(PRUint32 count); + PRBool ExtendZipItemArray(PRUint32 count); + + // Directory stuff... + + PRUint32 GetDirectoryCount(); + nsresult GetCloneOfDirectoryAt(PRUint32 i, nsILocalFile** dir); + nsresult GetDirectoryAt(PRUint32 i, nsILocalFile** dir); + PRBool FindDirectory(nsILocalFile* dir, PRUint32* index); + PRBool FindDirectoryOfFile(nsILocalFile* file, PRUint32* index); + PRBool DirectoryAtMatchesPersistentDescriptor(PRUint32 i, const char* desc); + + // Arena stuff... + + XPTArena* GetStringArena() {return mStringArena;} + XPTArena* GetStructArena() {return mStructArena;} + + +private: + PRUint32 mFileCount; + PRUint32 mMaxFileCount; + xptiFile* mFileArray; // using new[] and delete[] + + PRUint32 mZipItemCount; + PRUint32 mMaxZipItemCount; + xptiZipItem* mZipItemArray; // using new[] and delete[] + + XPTArena* mStringArena; + XPTArena* mStructArena; + + nsCOMPtr mDirectories; + +public: + // XXX make these private with accessors + PLDHashTable* mNameTable; + PLDHashTable* mIIDTable; + PRUint32* mFileMergeOffsetMap; // always in an arena + PRUint32* mZipItemMergeOffsetMap; // always in an arena +}; + +/***************************************************************************/ + +class xptiInterfaceGuts +{ +public: + uint16 mMethodBaseIndex; + uint16 mConstantBaseIndex; + xptiInterfaceEntry* mParent; + XPTInterfaceDescriptor* mDescriptor; + xptiTypelib mTypelib; + xptiWorkingSet* mWorkingSet; + + static xptiInterfaceGuts* NewGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + { + void* place = XPT_MALLOC(aWorkingSet->GetStructArena(), + sizeof(xptiInterfaceGuts)); + if(!place) + return nsnull; + return new(place) xptiInterfaceGuts(aDescriptor, aTypelib, aWorkingSet); + } + +private: + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + xptiInterfaceGuts(XPTInterfaceDescriptor* aDescriptor, + const xptiTypelib& aTypelib, + xptiWorkingSet* aWorkingSet) + : mMethodBaseIndex(0), + mConstantBaseIndex(0), + mParent(nsnull), + mDescriptor(aDescriptor), + mTypelib(aTypelib), + mWorkingSet(aWorkingSet) {} + + ~xptiInterfaceGuts() {} +}; + +/***************************************************************************/ + +// This class exists to help xptiInterfaceInfo store a 4-state (2 bit) value +// and a set of bitflags in one 8bit value. See below. + +class xptiInfoFlags +{ + enum {STATE_MASK = 3}; +public: + xptiInfoFlags(uint8 n) : mData(n) {} + xptiInfoFlags(const xptiInfoFlags& r) : mData(r.mData) {} + + static uint8 GetStateMask() + {return uint8(STATE_MASK);} + + void Clear() + {mData = 0;} + + uint8 GetData() const + {return mData;} + + uint8 GetState() const + {return mData & GetStateMask();} + + void SetState(uint8 state) + {mData &= ~GetStateMask(); mData |= state;} + + void SetFlagBit(uint8 flag, PRBool on) + {if(on) + mData |= ~GetStateMask() & flag; + else + mData &= GetStateMask() | ~flag;} + + PRBool GetFlagBit(uint8 flag) const + {return (mData & flag) ? PR_TRUE : PR_FALSE;} + +private: + uint8 mData; +}; + +/****************************************************/ + +// No virtual methods. +// We always create in the struct arena and construct using "placement new". +// No members need dtor calls. + +class xptiInterfaceEntry +{ +public: + static xptiInterfaceEntry* NewEntry(const char* name, + int nameLength, + const nsID& iid, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + static xptiInterfaceEntry* NewEntry(const xptiInterfaceEntry& r, + const xptiTypelib& typelib, + xptiWorkingSet* aWorkingSet); + + enum { + NOT_RESOLVED = 0, + PARTIALLY_RESOLVED = 1, + FULLY_RESOLVED = 2, + RESOLVE_FAILED = 3 + }; + + // Additional bit flags... + enum {SCRIPTABLE = 4}; + + uint8 GetResolveState() const {return mFlags.GetState();} + + PRBool IsFullyResolved() const + {return GetResolveState() == (uint8) FULLY_RESOLVED;} + + PRBool HasInterfaceRecord() const + {int s = (int) GetResolveState(); + return (s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface;} + + const xptiTypelib& GetTypelibRecord() const + {return HasInterfaceRecord() ? mInterface->mTypelib : mTypelib;} + + xptiInterfaceGuts* GetInterfaceGuts() const + {return HasInterfaceRecord() ? mInterface : nsnull;} + +#ifdef DEBUG + PRBool DEBUG_ScriptableFlagIsValid() const + {int s = (int) GetResolveState(); + if((s == PARTIALLY_RESOLVED || s == FULLY_RESOLVED) && mInterface) + { + if(XPT_ID_IS_SCRIPTABLE(mInterface->mDescriptor->flags)) + return GetScriptableFlag(); + return !GetScriptableFlag(); + } + return PR_TRUE; + } +#endif + + void SetScriptableFlag(PRBool on) + {mFlags.SetFlagBit(uint8(SCRIPTABLE),on);} + PRBool GetScriptableFlag() const + {return mFlags.GetFlagBit(uint8(SCRIPTABLE));} + + const nsID* GetTheIID() const {return &mIID;} + const char* GetTheName() const {return mName;} + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : Resolve(aWorkingSet);} + + PRBool PartiallyResolveLocked(XPTInterfaceDescriptor* aDescriptor, + xptiWorkingSet* aWorkingSet); + + nsresult GetInterfaceInfo(xptiInterfaceInfo** info); + PRBool InterfaceInfoEquals(const xptiInterfaceInfo* info) const + {return info == mInfo;} + + void LockedInvalidateInterfaceInfo(); + void LockedInterfaceInfoDeathNotification() {mInfo = nsnull;} + + ////////////////////// + // These non-virtual methods handle the delegated nsIInterfaceInfo methods. + + nsresult GetName(char * *aName); + nsresult GetIID(nsIID * *aIID); + nsresult IsScriptable(PRBool *_retval); + // Except this one. + //nsresult GetParent(nsIInterfaceInfo * *aParent); + nsresult GetMethodCount(PRUint16 *aMethodCount); + nsresult GetConstantCount(PRUint16 *aConstantCount); + nsresult GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info); + nsresult GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info); + nsresult GetConstant(PRUint16 index, const nsXPTConstant * *constant); + nsresult GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval); + nsresult GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval); + nsresult GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval); + nsresult GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval); + nsresult GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval); + nsresult IsIID(const nsIID * IID, PRBool *_retval); + nsresult GetNameShared(const char **name); + nsresult GetIIDShared(const nsIID * *iid); + nsresult IsFunction(PRBool *_retval); + nsresult HasAncestor(const nsIID * iid, PRBool *_retval); + nsresult GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid); + + ////////////////////// + +private: + xptiInterfaceEntry(); // not implemented + + xptiInterfaceEntry(const char* name, + size_t nameLength, + const nsID& iid, + const xptiTypelib& typelib); + + xptiInterfaceEntry(const xptiInterfaceEntry& r, + size_t nameLength, + const xptiTypelib& typelib); + ~xptiInterfaceEntry(); + + void* operator new(size_t, void* p) CPP_THROW_NEW {return p;} + + void SetResolvedState(int state) + {mFlags.SetState(uint8(state));} + + PRBool Resolve(xptiWorkingSet* aWorkingSet = nsnull); + + // We only call these "*Locked" variants after locking. This is done to + // allow reentrace as files are loaded and various interfaces resolved + // without having to worry about the locked state. + + PRBool EnsureResolvedLocked(xptiWorkingSet* aWorkingSet = nsnull) + {return IsFullyResolved() ? PR_TRUE : ResolveLocked(aWorkingSet);} + PRBool ResolveLocked(xptiWorkingSet* aWorkingSet = nsnull); + + // private helpers + + nsresult GetEntryForParam(PRUint16 methodIndex, + const nsXPTParamInfo * param, + xptiInterfaceEntry** entry); + + nsresult GetTypeInArray(const nsXPTParamInfo* param, + uint16 dimension, + const XPTTypeDescriptor** type); + +private: + nsID mIID; + union { + xptiTypelib mTypelib; // Valid only until resolved. + xptiInterfaceGuts* mInterface; // Valid only after resolved. + }; + xptiInterfaceInfo* mInfo; // May come and go. + xptiInfoFlags mFlags; + char mName[1]; // Always last. Sized to fit. +}; + +struct xptiHashEntry : public PLDHashEntryHdr +{ + xptiInterfaceEntry* value; +}; + +/****************************************************/ + +class xptiInterfaceInfo : public nsIInterfaceInfo +{ +public: + NS_DECL_ISUPPORTS + + // Use delegation to implement (most!) of nsIInterfaceInfo. + NS_IMETHOD GetName(char * *aName) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetName(aName); } + NS_IMETHOD GetInterfaceIID(nsIID * *aIID) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIID(aIID); } + NS_IMETHOD IsScriptable(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsScriptable(_retval); } + // Except this one. + NS_IMETHOD GetParent(nsIInterfaceInfo * *aParent) + { + if(!EnsureResolved() || !EnsureParent()) + return NS_ERROR_UNEXPECTED; + NS_IF_ADDREF(*aParent = mParent); + return NS_OK; + } + NS_IMETHOD GetMethodCount(PRUint16 *aMethodCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodCount(aMethodCount); } + NS_IMETHOD GetConstantCount(PRUint16 *aConstantCount) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstantCount(aConstantCount); } + NS_IMETHOD GetMethodInfo(PRUint16 index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfo(index, info); } + NS_IMETHOD GetMethodInfoForName(const char *methodName, PRUint16 *index, const nsXPTMethodInfo * *info) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetMethodInfoForName(methodName, index, info); } + NS_IMETHOD GetConstant(PRUint16 index, const nsXPTConstant * *constant) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetConstant(index, constant); } + NS_IMETHOD GetInfoForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIInterfaceInfo **_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInfoForParam(methodIndex, param, _retval); } + NS_IMETHOD GetIIDForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID * *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParam(methodIndex, param, _retval); } + NS_IMETHOD GetTypeForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, nsXPTType *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetTypeForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetSizeIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetSizeIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetLengthIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint16 dimension, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetLengthIsArgNumberForParam(methodIndex, param, dimension, _retval); } + NS_IMETHOD GetInterfaceIsArgNumberForParam(PRUint16 methodIndex, const nsXPTParamInfo * param, PRUint8 *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetInterfaceIsArgNumberForParam(methodIndex, param, _retval); } + NS_IMETHOD IsIID(const nsIID * IID, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsIID(IID, _retval); } + NS_IMETHOD GetNameShared(const char **name) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetNameShared(name); } + NS_IMETHOD GetIIDShared(const nsIID * *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDShared(iid); } + NS_IMETHOD IsFunction(PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->IsFunction(_retval); } + NS_IMETHOD HasAncestor(const nsIID * iid, PRBool *_retval) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->HasAncestor(iid, _retval); } + NS_IMETHOD GetIIDForParamNoAlloc(PRUint16 methodIndex, const nsXPTParamInfo * param, nsIID *iid) { return !mEntry ? NS_ERROR_UNEXPECTED : mEntry->GetIIDForParamNoAlloc(methodIndex, param, iid); } + +public: + xptiInterfaceInfo(xptiInterfaceEntry* entry); + + void Invalidate() + {NS_IF_RELEASE(mParent); mEntry = nsnull;} + +#ifdef DEBUG + static void DEBUG_ShutdownNotification(); +#endif + +private: + + ~xptiInterfaceInfo(); + + // Note that mParent might still end up as nsnull if we don't have one. + PRBool EnsureParent(xptiWorkingSet* aWorkingSet = nsnull) + { + NS_ASSERTION(mEntry && mEntry->IsFullyResolved(), "bad EnsureParent call"); + return mParent || !mEntry->GetInterfaceGuts()->mParent || BuildParent(); + } + + PRBool EnsureResolved(xptiWorkingSet* aWorkingSet = nsnull) + { + return mEntry && mEntry->EnsureResolved(aWorkingSet); + } + + PRBool BuildParent() + { + NS_ASSERTION(mEntry && + mEntry->IsFullyResolved() && + !mParent && + mEntry->GetInterfaceGuts()->mParent, + "bad BuildParent call"); + return NS_SUCCEEDED(mEntry->GetInterfaceGuts()->mParent-> + GetInterfaceInfo(&mParent)); + } + + xptiInterfaceInfo(); // not implemented + +private: + xptiInterfaceEntry* mEntry; + xptiInterfaceInfo* mParent; +}; + +/***************************************************************************/ + +class xptiManifest +{ +public: + static PRBool Read(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Write(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet); + + static PRBool Delete(xptiInterfaceInfoManager* aMgr); + +private: + xptiManifest(); // no implementation +}; + +/***************************************************************************/ + +class xptiZipLoaderSink : public nsIXPTLoaderSink +{ +public: + xptiZipLoaderSink(xptiInterfaceInfoManager* aMgr, + xptiWorkingSet* aWorkingSet) : + mManager(aMgr), + mWorkingSet(aWorkingSet) {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIXPTLOADERSINK + +private: + ~xptiZipLoaderSink() {} + + xptiInterfaceInfoManager* mManager; + xptiWorkingSet* mWorkingSet; + +}; + +class xptiZipLoader +{ +public: + xptiZipLoader(); // not implemented + + static XPTHeader* + ReadXPTFileFromInputStream(nsIInputStream *stream, + xptiWorkingSet* aWorkingSet); + +}; + + +/***************************************************************************/ + +class xptiFileType +{ +public: + enum Type {UNKNOWN = -1, XPT = 0, ZIP = 1 }; + + static Type GetType(const char* name); + + static PRBool IsUnknown(const char* name) + {return GetType(name) == UNKNOWN;} + + static PRBool IsXPT(const char* name) + {return GetType(name) == XPT;} + + static PRBool IsZip(const char* name) + {return GetType(name) == ZIP;} +private: + xptiFileType(); // no implementation +}; + +/***************************************************************************/ + +// We use this is as a fancy way to open a logfile to be used within the scope +// of some given function where it is instantiated. + +class xptiAutoLog +{ +public: + xptiAutoLog(); // not implemented + xptiAutoLog(xptiInterfaceInfoManager* mgr, + nsILocalFile* logfile, PRBool append); + ~xptiAutoLog(); +private: + void WriteTimestamp(PRFileDesc* fd, const char* msg); + + xptiInterfaceInfoManager* mMgr; + PRFileDesc* mOldFileDesc; +#ifdef DEBUG + PRFileDesc* m_DEBUG_FileDesc; +#endif +}; + +/***************************************************************************/ + +class xptiInterfaceInfoManager + : public nsIInterfaceInfoSuperManager +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEINFOMANAGER + NS_DECL_NSIINTERFACEINFOSUPERMANAGER + + // helper + PRBool + FoundZipEntry(const char* entryName, + int index, + XPTHeader* header, + xptiWorkingSet* aWorkingSet); + +public: + static xptiInterfaceInfoManager* GetInterfaceInfoManagerNoAddRef(); + static void FreeInterfaceInfoManager(); + + xptiWorkingSet* GetWorkingSet() {return &mWorkingSet;} + PRFileDesc* GetOpenLogFile() {return mOpenLogFile;} + PRFileDesc* SetOpenLogFile(PRFileDesc* fd) + {PRFileDesc* temp = mOpenLogFile; mOpenLogFile = fd; return temp;} + + PRBool LoadFile(const xptiTypelib& aTypelibRecord, + xptiWorkingSet* aWorkingSet = nsnull); + + PRBool GetApplicationDir(nsILocalFile** aDir); + PRBool GetCloneOfManifestLocation(nsILocalFile** aDir); + + void GetSearchPath(nsISupportsArray** aSearchPath) + {NS_ADDREF(*aSearchPath = mSearchPath);} + + static PRLock* GetResolveLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mResolveLock;} + + static PRLock* GetAutoRegLock(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mAutoRegLock;} + + static PRMonitor* GetInfoMonitor(xptiInterfaceInfoManager* self = nsnull) + {if(!self && !(self = GetInterfaceInfoManagerNoAddRef())) + return nsnull; + return self->mInfoMonitor;} + + static void WriteToLog(const char *fmt, ...); + +private: + ~xptiInterfaceInfoManager(); + xptiInterfaceInfoManager(); // not implmented + xptiInterfaceInfoManager(nsISupportsArray* aSearchPath); + + enum AutoRegMode { + NO_FILES_CHANGED = 0, + FILES_ADDED_ONLY, + FULL_VALIDATION_REQUIRED + }; + + PRBool IsValid(); + + PRBool BuildFileList(nsISupportsArray* aSearchPath, + nsISupportsArray** aFileList); + + nsILocalFile** BuildOrderedFileArray(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + XPTHeader* ReadXPTFile(nsILocalFile* aFile, xptiWorkingSet* aWorkingSet); + + AutoRegMode DetermineAutoRegStrategy(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool AddOnlyNewFilesFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool DoFullValidationMergeFromFileList(nsISupportsArray* aSearchPath, + nsISupportsArray* aFileList, + xptiWorkingSet* aWorkingSet); + + PRBool VerifyAndAddEntryIfNew(xptiWorkingSet* aWorkingSet, + XPTInterfaceDirectoryEntry* iface, + const xptiTypelib& typelibRecord, + xptiInterfaceEntry** entryAdded); + + PRBool MergeWorkingSets(xptiWorkingSet* aDestWorkingSet, + xptiWorkingSet* aSrcWorkingSet); + + void LogStats(); + + PRBool DEBUG_DumpFileList(nsISupportsArray* aFileList); + PRBool DEBUG_DumpFileArray(nsILocalFile** aFileArray, PRUint32 count); + PRBool DEBUG_DumpFileListInWorkingSet(xptiWorkingSet* aWorkingSet); + + static PRBool BuildFileSearchPath(nsISupportsArray** aPath); + +private: + xptiWorkingSet mWorkingSet; + nsCOMPtr mStatsLogFile; + nsCOMPtr mAutoRegLogFile; + PRFileDesc* mOpenLogFile; + PRLock* mResolveLock; + PRLock* mAutoRegLock; + PRMonitor* mInfoMonitor; + PRLock* mAdditionalManagersLock; + nsSupportsArray mAdditionalManagers; + nsCOMPtr mSearchPath; +}; + +/***************************************************************************/ +// utilities... + +nsresult xptiCloneLocalFile(nsILocalFile* aLocalFile, + nsILocalFile** aCloneLocalFile); + +nsresult xptiCloneElementAsLocalFile(nsISupportsArray* aArray, PRUint32 aIndex, + nsILocalFile** aLocalFile); + +#endif /* xptiprivate_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore new file mode 100644 index 00000000..f29041e6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/.cvsignore @@ -0,0 +1,2 @@ +Makefile +TestInterfaceInfo diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in new file mode 100644 index 00000000..9b7f1ed4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +SIMPLE_PROGRAMS = TestInterfaceInfo$(BIN_SUFFIX) + +CPPSRCS = TestInterfaceInfo.cpp + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp new file mode 100644 index 00000000..75005c50 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/reflect/xptinfo/tests/TestInterfaceInfo.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Some simple smoke tests of the typelib loader. */ + +#include "nscore.h" + +#include "nsISupports.h" +#include "nsIInterfaceInfo.h" +#include "nsIInterfaceInfoManager.h" +#include "xptinfo.h" + +#include + +// This file expects the nsInterfaceInfoManager to be able to discover +// .xpt files corresponding to those in xpcom/idl. Currently this +// means setting XPTDIR in the environment to some directory +// containing these files. + +int main (int argc, char **argv) { + int i; + nsIID *iid1, *iid2, *iid3; + char *name1, *name2, *name3; + nsIInterfaceInfo *info2, *info3, *info4, *info5; + + nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager(); + + fprintf(stderr, "\ngetting iid for 'nsISupports'\n"); + iim->GetIIDForName("nsISupports", &iid1); + iim->GetNameForIID(iid1, &name1); + fprintf(stderr, "%s iid %s\n", name1, iid1->ToString()); + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid2); + iim->GetNameForIID(iid2, &name2); + fprintf(stderr, "%s iid %s\n", name2, iid2->ToString()); + + fprintf(stderr, "iid: %s, name: %s\n", iid1->ToString(), name1); + fprintf(stderr, "iid: %s, name: %s\n", iid2->ToString(), name2); + + fprintf(stderr, "\ngetting info for iid2 from above\n"); + iim->GetInfoForIID(iid2, &info2); +#ifdef DEBUG +// ((nsInterfaceInfo *)info2)->print(stderr); +#endif + + fprintf(stderr, "\ngetting iid for 'nsIInputStream'\n"); + iim->GetIIDForName("nsIInputStream", &iid3); + iim->GetNameForIID(iid3, &name3); + fprintf(stderr, "%s iid %s\n", name3, iid2->ToString()); + iim->GetInfoForIID(iid3, &info3); +#ifdef DEBUG +// ((nsInterfaceInfo *)info3)->print(stderr); +#endif + + fprintf(stderr, "\ngetting info for name 'nsIBidirectionalEnumerator'\n"); + iim->GetInfoForName("nsIBidirectionalEnumerator", &info4); +#ifdef DEBUG +// ((nsInterfaceInfo *)info4)->print(stderr); +#endif + + fprintf(stderr, "\nparams work?\n"); + fprintf(stderr, "\ngetting info for name 'nsIServiceManager'\n"); + iim->GetInfoForName("nsIServiceManager", &info5); +#ifdef DEBUG +// ((nsInterfaceInfo *)info5)->print(stderr); +#endif + + // XXX: nsIServiceManager is no more; what do we test with? + if (info5 == NULL) { + fprintf(stderr, "\nNo nsIServiceManager; cannot continue.\n"); + return 1; + } + + uint16 methodcount; + info5->GetMethodCount(&methodcount); + const nsXPTMethodInfo *mi; + for (i = 0; i < methodcount; i++) { + info5->GetMethodInfo(i, &mi); + fprintf(stderr, "method %d, name %s\n", i, mi->GetName()); + } + + // 7 is GetServiceWithListener, which has juicy params. + info5->GetMethodInfo(7, &mi); +// uint8 paramcount = mi->GetParamCount(); + + nsXPTParamInfo param2 = mi->GetParam(2); + // should be IID for nsIShutdownListener + nsIID *nsISL; + info5->GetIIDForParam(7, ¶m2, &nsISL); +// const nsIID *nsISL = param2.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 2 of method 7 of GetServiceWithListener - %s\n", nsISL->ToString()); + // if we look up the name? + char *nsISLname; + iim->GetNameForIID(nsISL, &nsISLname); + fprintf(stderr, "which is called %s\n", nsISLname); + + fprintf(stderr, "\nhow about one defined in a different typelib\n"); + nsXPTParamInfo param3 = mi->GetParam(3); + // should be IID for nsIShutdownListener + nsIID *nsISS; + info5->GetIIDForParam(7, ¶m3, &nsISS); +// const nsIID *nsISS = param3.GetInterfaceIID(info5); + fprintf(stderr, "iid assoc'd with param 3 of method 7 of GetServiceWithListener - %s\n", nsISS->ToString()); + // if we look up the name? + char *nsISSname; + iim->GetNameForIID(nsISS, &nsISSname); + fprintf(stderr, "which is called %s\n", nsISSname); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/sample/.cvsignore b/src/libs/xpcom18a4/xpcom/sample/.cvsignore new file mode 100644 index 00000000..d1f93146 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/.cvsignore @@ -0,0 +1,2 @@ +Makefile +nsTestSample diff --git a/src/libs/xpcom18a4/xpcom/sample/Makefile.in b/src/libs/xpcom18a4/xpcom/sample/Makefile.in new file mode 100644 index 00000000..5510e795 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/Makefile.in @@ -0,0 +1,113 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcomsample +XPIDL_MODULE = xpcomsample +LIBRARY_NAME = xpcomsample +SHORT_LIBNAME = xpcomsmp + +IS_COMPONENT = 1 +MODULE_NAME = nsSampleModule + +# Ensure that the xpcom classes that we build +# do not export themselves +DEFINES += -DXPCOM_GLUE + + +REQUIRES = string \ + xpcom \ + $(NULL) + +CPPSRCS = \ + nsSample.cpp \ + nsSampleModule.cpp \ + $(NULL) + +XPIDLSRCS = nsISample.idl + +TESTCPPSRCS = nsTestSample.cpp + +CPPSRCS += $(TESTCPPSRCS) + +SIMPLE_PROGRAMS = $(TESTCPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +EXTRA_COMPONENTS = nsSample.js + +# separate libraries linked in. +EXTRA_DSO_LDOPTS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +# Needed to resolve __yylex (?) +ifeq ($(OS_ARCH)$(OS_RELEASE),FreeBSD2) +LIBS += -lpcap +endif + +# Need to link with CoreFoundation on Mac +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +EXTRA_DSO_LDOPTS += \ + $(TK_LIBS) \ + $(NULL) + +LIBS += \ + $(TK_LIBS) \ + $(NULL) +endif + +include $(topsrcdir)/config/rules.mk + +libs:: $(TARGETS) + $(INSTALL) $(srcdir)/xpconnect-sample.html $(DIST)/bin/res/samples + +install:: $(TARGETS) + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/xpconnect-sample.html $(DESTDIR)$(mozappdir)/res/samples + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsISample.idl b/src/libs/xpcom18a4/xpcom/sample/nsISample.idl new file mode 100644 index 00000000..22454e7b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsISample.idl @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * A sample of XPConnect. This file contains a sample interface. + * + */ + +#include "nsISupports.idl" + +/** + * The uuid is a unique number identifying the interface normally + * called IID. It can be generated as follows: + * + * Windows: guidgen.exe + * Unix: uuidgen which comes with e2fsprogs package + * Mac: ??? + * All platform: Using irc, connect to irc.mozilla.org and type in + * /join #mozilla + * /msg mozbot uuid + * + */ +[scriptable, uuid(7CB5B7A1-07D7-11d3-BDE2-000064657374)] +interface nsISample : nsISupports +{ + attribute string value; + void writeValue(in string aPrefix); + void poke(in string aValue); +}; + + + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp b/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp new file mode 100644 index 00000000..ac3d8449 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * + * A sample of XPConnect. This file contains an implementation nsSample + * of the interface nsISample. + * + */ +#include + +#include "nsSample.h" +#include "nsMemory.h" + +#include "nsEmbedString.h" +//////////////////////////////////////////////////////////////////////// + +nsSampleImpl::nsSampleImpl() : mValue(nsnull) +{ + mValue = (char*)nsMemory::Clone("initial value", 14); +} + +nsSampleImpl::~nsSampleImpl() +{ + if (mValue) + nsMemory::Free(mValue); +} + +/** + * NS_IMPL_ISUPPORTS1 expands to a simple implementation of the nsISupports + * interface. This includes a proper implementation of AddRef, Release, + * and QueryInterface. If this class supported more interfaces than just + * nsISupports, + * you could use NS_IMPL_ADDREF() and NS_IMPL_RELEASE() to take care of the + * simple stuff, but you would have to create QueryInterface on your own. + * nsSampleFactory.cpp is an example of this approach. + * Notice that the second parameter to the macro is name of the interface, and + * NOT the #defined IID. + * + * The _CI variant adds support for nsIClassInfo, which permits introspection + * and interface flattening. + */ +NS_IMPL_ISUPPORTS1_CI(nsSampleImpl, nsISample) + +/** + * Notice that in the protoype for this function, the NS_IMETHOD macro was + * used to declare the return type. For the implementation, the return + * type is declared by NS_IMETHODIMP + */ +NS_IMETHODIMP +nsSampleImpl::GetValue(char** aValue) +{ + NS_PRECONDITION(aValue != nsnull, "null ptr"); + if (! aValue) + return NS_ERROR_NULL_POINTER; + + if (mValue) { + /** + * GetValue's job is to return data known by an instance of + * nsSampleImpl to the outside world. If we were to simply return + * a pointer to data owned by this instance, and the client were to + * free it, bad things would surely follow. + * On the other hand, if we create a new copy of the data for our + * client, and it turns out that client is implemented in JavaScript, + * there would be no way to free the buffer. The solution to the + * buffer ownership problem is the nsMemory singleton. Any buffer + * returned by an XPCOM method should be allocated by the nsMemory. + * This convention lets things like JavaScript reflection do their + * job, and simplifies the way C++ clients deal with returned buffers. + */ + *aValue = (char*) nsMemory::Clone(mValue, strlen(mValue) + 1); + if (! *aValue) + return NS_ERROR_NULL_POINTER; + } + else { + *aValue = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP +nsSampleImpl::SetValue(const char* aValue) +{ + NS_PRECONDITION(aValue != nsnull, "null ptr"); + if (! aValue) + return NS_ERROR_NULL_POINTER; + + if (mValue) { + nsMemory::Free(mValue); + } + + /** + * Another buffer passing convention is that buffers passed INTO your + * object ARE NOT YOURS. Keep your hands off them, unless they are + * declared "inout". If you want to keep the value for posterity, + * you will have to make a copy of it. + */ + mValue = (char*) nsMemory::Clone(aValue, strlen(aValue) + 1); + return NS_OK; +} + +NS_IMETHODIMP +nsSampleImpl::Poke(const char* aValue) +{ + return SetValue((char*) aValue); +} + + +static void GetStringValue(nsACString& aValue) +{ + NS_CStringSetData(aValue, "GetValue"); +} + +NS_IMETHODIMP +nsSampleImpl::WriteValue(const char* aPrefix) +{ + NS_PRECONDITION(aPrefix != nsnull, "null ptr"); + if (! aPrefix) + return NS_ERROR_NULL_POINTER; + + printf("%s %s\n", aPrefix, mValue); + + // This next part illustrates the nsEmbedString: + nsEmbedString foopy; + foopy.Append(PRUnichar('f')); + foopy.Append(PRUnichar('o')); + foopy.Append(PRUnichar('o')); + foopy.Append(PRUnichar('p')); + foopy.Append(PRUnichar('y')); + + const PRUnichar* f = foopy.get(); + PRUint32 l = foopy.Length(); + printf("%c%c%c%c%c %d\n", char(f[0]), char(f[1]), char(f[2]), char(f[3]), char(f[4]), l); + + nsEmbedCString foopy2; + GetStringValue(foopy2); + + //foopy2.AppendLiteral("foopy"); + const char* f2 = foopy2.get(); + PRUint32 l2 = foopy2.Length(); + + printf("%s %d\n", f2, l2); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.h b/src/libs/xpcom18a4/xpcom/sample/nsSample.h new file mode 100644 index 00000000..40dec0b3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/** + * A sample of XPConnect. This file is the header of an implementation + * nsSample of the nsISample interface. + * + */ + +#include "nsISample.h" + +/** + * SampleImpl is an implementation of the nsISample interface. In XPCOM, + * there can be more than one implementation of an given interface. Class + * IDs (CIDs) uniquely identify a particular implementation of an interface. + * Interface IDs (IIDs) uniquely identify an interface. + * + * The CID is also a unique number that looks just like an IID + * and uniquely identifies an implementation + * {7CB5B7A0-07D7-11d3-BDE2-000064657374} + */ + +#define NS_SAMPLE_CID \ +{ 0x7cb5b7a0, 0x7d7, 0x11d3, { 0xbd, 0xe2, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } + +#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1" + + +class nsSampleImpl : public nsISample +{ +public: + nsSampleImpl(); + + /** + * This macro expands into a declaration of the nsISupports interface. + * Every XPCOM component needs to implement nsISupports, as it acts + * as the gateway to other interfaces this component implements. You + * could manually declare QueryInterface, AddRef, and Release instead + * of using this macro, but why? + */ + // nsISupports interface + NS_DECL_ISUPPORTS + + /** + * This macro is defined in the nsISample.h file, and is generated + * automatically by the xpidl compiler. It expands to + * declarations of all of the methods required to implement the + * interface. xpidl will generate a NS_DECL_[INTERFACENAME] macro + * for each interface that it processes. + * + * The methods of nsISample are discussed individually below, but + * commented out (because this macro already defines them.) + */ + NS_DECL_NSISAMPLE + + /** + * The following is an explanation of how the interface header + * file expands to for a c++ implementation. NS_DELC_NSISAMPLE + * takes care of defining the right c++ implementation. + * + * The following if provided for more understanding. + * + * NS_IMETHOD expands to the standard XPCOM return type. XPCOM methods + * should never return any other type. The return value is used + * behind the scenes by the XPConnect runtime to figure out if the call + * failed in any way. + * These methods were generated by "attribute string Value" in + * nsISample.idl. When reflected into JavaScript, XPCOM will use these + * calls as Getter/Setter ops, so that they can be called transparently + * as "sample.Value='foo';" and "var val = sample.Value" + */ + /* NS_IMETHOD GetValue(char * *aValue); */ + /* NS_IMETHOD SetValue(char * aValue); */ + + /** + * The const came from the "in" specifier in nsISample.idl. "in" + * specifies that the value of this parameter is used only for input, + * this method is not allowed to modify the contents of the buffer. + */ + /* NS_IMETHOD WriteValue(const char *aPrefix); */ + + /** + * nsISample.idl specifies all of it's string types as string, instead + * of wstring (wide string), the Unicode type. If the world were a + * perfect place, all normal strings in XPCOM interfaces would be unicode. + * If this type had been specified as wstring, it would appear as + * PRUnichar * in C++, which is the NSPR type for unicode characters. + */ + /* NS_IMETHOD Poke(const char* aValue); */ + +private: + ~nsSampleImpl(); + + char* mValue; +}; diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSample.js b/src/libs/xpcom18a4/xpcom/sample/nsSample.js new file mode 100644 index 00000000..1cc9a091 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSample.js @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * No magic constructor behaviour, as is de rigeur for XPCOM. + * If you must perform some initialization, and it could possibly fail (even + * due to an out-of-memory condition), you should use an Init method, which + * can convey failure appropriately (thrown exception in JS, + * NS_FAILED(nsresult) return in C++). + * + * In JS, you can actually cheat, because a thrown exception will cause the + * CreateInstance call to fail in turn, but not all languages are so lucky. + * (Though ANSI C++ provides exceptions, they are verboten in Mozilla code + * for portability reasons -- and even when you're building completely + * platform-specific code, you can't throw across an XPCOM method boundary.) + */ +function mySample() { /* big comment for no code, eh? */ } + +/* decorate prototype to provide ``class'' methods and property accessors */ +mySample.prototype = { + /* + * get and set are new Magic in JS1.5, borrowing the intent -- if not + * the exact syntax -- from the JS2 design. They define accessors for + * properties on the JS object, follow the expected rules for prototype + * delegation, and make a mean cup of coffee. + */ + get value() { return this.val; }, + set value(newval) { return this.val = newval; }, + + writeValue: function (aPrefix) { + debug("mySample::writeValue => " + aPrefix + this.val + "\n"); + }, + poke: function (aValue) { this.val = aValue; }, + + QueryInterface: function (iid) { + if (iid.equals(Components.interfaces.nsISample) || + iid.equals(Components.interfaces.nsISupports)) + return this; + + Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; + return null; + }, + + val: "" +} + +var myModule = { + firstTime: true, + + /* + * RegisterSelf is called at registration time (component installation + * or the only-until-release startup autoregistration) and is responsible + * for notifying the component manager of all components implemented in + * this module. The fileSpec, location and type parameters are mostly + * opaque, and should be passed on to the registerComponent call + * unmolested. + */ + registerSelf: function (compMgr, fileSpec, location, type) { + if (this.firstTime) { + debug("*** Deferring registration of sample JS components\n"); + this.firstTime = false; + throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; + } + debug("*** Registering sample JS components\n"); + compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar); + compMgr.registerFactoryLocation(this.myCID, + "Sample JS Component", + this.myProgID, + fileSpec, + location, + type); + }, + + /* + * The GetClassObject method is responsible for producing Factory objects + */ + getClassObject: function (compMgr, cid, iid) { + if (!cid.equals(this.myCID)) + throw Components.results.NS_ERROR_NO_INTERFACE; + + if (!iid.equals(Components.interfaces.nsIFactory)) + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + + return this.myFactory; + }, + + /* CID for this class */ + myCID: Components.ID("{dea98e50-1dd1-11b2-9344-8902b4805a2e}"), + + /* ProgID for this class */ + myProgID: "@mozilla.org/jssample;1", + + /* factory object */ + myFactory: { + /* + * Construct an instance of the interface specified by iid, possibly + * aggregating it with the provided outer. (If you don't know what + * aggregation is all about, you don't need to. It reduces even the + * mightiest of XPCOM warriors to snivelling cowards.) + */ + createInstance: function (outer, iid) { + debug("CI: " + iid + "\n"); + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + + return (new mySample()).QueryInterface(iid); + } + }, + + /* + * The canUnload method signals that the component is about to be unloaded. + * C++ components can return false to indicate that they don't wish to be + * unloaded, but the return value from JS components' canUnload is ignored: + * mark-and-sweep will keep everything around until it's no longer in use, + * making unconditional ``unload'' safe. + * + * You still need to provide a (likely useless) canUnload method, though: + * it's part of the nsIModule interface contract, and the JS loader _will_ + * call it. + */ + canUnload: function(compMgr) { + debug("*** Unloading sample JS components\n"); + return true; + } +}; + +function NSGetModule(compMgr, fileSpec) { + return myModule; +} + + diff --git a/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp b/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp new file mode 100644 index 00000000..f02b9a5c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsSampleModule.cpp @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddu + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIGenericFactory.h" + +#include "nsSample.h" + +//////////////////////////////////////////////////////////////////////// +// NOTE this file supercedes nsSampleFactory.cpp. nsSampleFactory has +// extensive comments, but it has been CVS removed to reduce clutter +// in this sample. It's available to the interested via CVS history: +// cvs up nsSampleFactory.cpp -r 1.10 +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// With the below sample, you can define an implementation glue +// that talks with xpcom for creation of component nsSampleImpl +// that implement the interface nsISample. This can be extended for +// any number of components. +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// Define the contructor function for the object nsSampleImpl +// +// What this does is defines a function nsSampleImplConstructor which we +// will specific in the nsModuleComponentInfo table. This function will +// be used by the generic factory to create an instance of nsSampleImpl. +// +// NOTE: This creates an instance of nsSampleImpl by using the default +// constructor nsSampleImpl::nsSampleImpl() +// +NS_GENERIC_FACTORY_CONSTRUCTOR(nsSampleImpl) + +//////////////////////////////////////////////////////////////////////// +// Define a table of CIDs implemented by this module along with other +// information like the function to create an instance, contractid, and +// class name. +// +// The Registration and Unregistration proc are optional in the structure. +// +static NS_METHOD nsSampleRegistrationProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const char *componentType, + const nsModuleComponentInfo *info) +{ + // Do any registration specific activity like adding yourself to a + // category. The Generic Module will take care of registering your + // component with xpcom. You dont need to do that. Only any component + // specific additional activity needs to be done here. + + // This functions is optional. If you dont need it, dont add it to the structure. + + return NS_OK; +} + +static NS_METHOD nsSampleUnregistrationProc(nsIComponentManager *aCompMgr, + nsIFile *aPath, + const char *registryLocation, + const nsModuleComponentInfo *info) +{ + // Undo any component specific registration like adding yourself to a + // category here. The Generic Module will take care of unregistering your + // component from xpcom. You dont need to do that. Only any component + // specific additional activity needs to be done here. + + // This functions is optional. If you dont need it, dont add it to the structure. + + // Return value is not used from this function. + return NS_OK; +} + +// For each class that wishes to support nsIClassInfo, add a line like this +NS_DECL_CLASSINFO(nsSampleImpl) + +static const nsModuleComponentInfo components[] = +{ + { "Sample Component", NS_SAMPLE_CID, NS_SAMPLE_CONTRACTID, nsSampleImplConstructor, + nsSampleRegistrationProc /* NULL if you dont need one */, + nsSampleUnregistrationProc /* NULL if you dont need one */, + NULL /* no factory destructor */, + NS_CI_INTERFACE_GETTER_NAME(nsSampleImpl), + NULL /* no language helper */, + &NS_CLASSINFO_NAME(nsSampleImpl) + } +}; + +//////////////////////////////////////////////////////////////////////// +// Implement the NSGetModule() exported function for your module +// and the entire implementation of the module object. +// +// NOTE: If you want to use the module shutdown to release any +// module specific resources, use the macro +// NS_IMPL_NSGETMODULE_WITH_DTOR() instead of the vanilla +// NS_IMPL_NSGETMODULE() +// +NS_IMPL_NSGETMODULE(nsSampleModule, components) diff --git a/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp b/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp new file mode 100644 index 00000000..edf9ce78 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/nsTestSample.cpp @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/** + * A Test application that exercises the sample moudule. This is intented + * to be a sample application for using xpcom standalone. + */ + +#include + +#include "nsISample.h" +#include "nsIServiceManager.h" +#include "nsIComponentRegistrar.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#include "nsMemory.h" +#else +#include "nsXPIDLString.h" +#endif + +#define NS_SAMPLE_CONTRACTID "@mozilla.org/sample;1" + +int +main(void) +{ + nsresult rv; + +#ifdef XPCOM_GLUE + XPCOMGlueStartup(nsnull); +#endif + + // Initialize XPCOM + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) + { + printf("ERROR: XPCOM intialization error [%x].\n", rv); + return -1; + } + // register all components in our default component directory + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + nsCOMPtr manager = do_QueryInterface(registrar); + NS_ASSERTION(registrar, "Null nsIComponentManager"); + + // Create an instance of our component + nsCOMPtr mysample; + rv = manager->CreateInstanceByContractID(NS_SAMPLE_CONTRACTID, + nsnull, + NS_GET_IID(nsISample), + getter_AddRefs(mysample)); + if (NS_FAILED(rv)) + { + printf("ERROR: Cannot create instance of component " NS_SAMPLE_CONTRACTID " [%x].\n" + "Debugging hint:\n" + "\tsetenv NSPR_LOG_MODULES nsComponentManager:5\n" + "\tsetenv NSPR_LOG_FILE xpcom.log\n" + "\t./nsTestSample\n" + "\t.\n", + rv); + return -2; + } + + // Call methods on our sample to test it out. + rv = mysample->WriteValue("Inital print:"); + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::WriteValue() [%x]\n", rv); + return -3; + } + + const char *testValue = "XPCOM defies gravity"; + rv = mysample->SetValue(testValue); + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::SetValue() [%x]\n", rv); + return -3; + } + printf("Set value to: %s\n", testValue); +#ifndef XPCOM_GLUE + nsXPIDLCString str; + rv = mysample->GetValue(getter_Copies(str)); +#else + char *str; + rv = mysample->GetValue(&str); +#endif + + if (NS_FAILED(rv)) + { + printf("ERROR: Calling nsISample::GetValue() [%x]\n", rv); + return -3; + } + if (strcmp(str, testValue)) + { + printf("Test FAILED.\n"); + return -4; + } + +#ifdef XPCOM_GLUE + nsMemory::Free(str); +#endif + rv = mysample->WriteValue("Final print :"); + printf("Test passed.\n"); + + // All nsCOMPtr's must be deleted prior to calling shutdown XPCOM + // as we should not hold references passed XPCOM Shutdown. + servMan = 0; + registrar = 0; + manager = 0; + mysample = 0; + + // Shutdown XPCOM + NS_ShutdownXPCOM(nsnull); + +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/sample/win32.order b/src/libs/xpcom18a4/xpcom/sample/win32.order new file mode 100644 index 00000000..bf181a81 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/win32.order @@ -0,0 +1 @@ +_NSGetModule ; 1 diff --git a/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html b/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html new file mode 100644 index 00000000..78e91be1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/sample/xpconnect-sample.html @@ -0,0 +1,220 @@ + +
XPConnect Sample + +

+Ariel Blackenroth <arielb@rice.edu> +
+Michael Ang <mang@subcarrier.org> +
+Last modified + +

+ +

In the spirit of "worse is better" this somewhat rough guide is being +released to the world. It will be expanded upon and improved. + +

XPConnect allows JavaScript +to transparantly access and manipulate XPCOM objects; this communication +between JavaScript and +native code is done by having their interfaces defined in the XPIDL interface +definition language. See the Roadmap +for documentation on XPCOM, XPConnect, XPTCall and XPIDL for more information. + +

Overview + +

+This sample demonstrates accessing a XPCOM object through XPConnect. +The JavaScript executed when this page loads creates an instance +of the object by +using the Components object, then accesses it through +the nsISample interface by calling QueryInterface: +
+

+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsISample);
+
+ +

+The buttons on the form are connected to JavaScript event handlers which +call the methods defined in C++. + + +

nsISample.idl +

This is the interface declaration for the XPCOM object. It defines +two functions, their parameters, and one attribute. It also defines +the interface's id. The idl file is compiled by the xpidl compiler +into a C++ header, nsISample.h and a .xpt file which is a binary representation +of the interface used at runtime. +
attribute string value; +
void writeValue(in string aPrefix); +
void poke(in string aValue); +

nsSample.cpp +

This contains the implementation of nsISample.idl. SampleImpl +inherits from nsISample.h, the header dynamically created by the xpidl +compiler. The attribute Value has been expanded into a get and set +and the return values have been modified to NS_IMETHOD, a success status +for the method. The macro NS_DECL_ISUPPORTS, defined in mozilla/xpcom/public/nsISupportsUtils.h +defines the inherited methods from nsISupports.h. +
NS_IMPL_ISUPPORTS1(SampleImpl, nsISample) +
In the constructor, the macro NS_INIT_REFCNT is called which sets the +reference count to 0.

+Note that the methods in the C++ bindings use InterCaps style, while the IDL +and JavaScript versions should use interCaps naming. The JavaScript binding +matches the case of the IDL, except QueryInterface. +

nsSampleFactory.cpp +

This is the class which builds the instance of the nsSample class. +The COM framework uses factories to create instance of implementations +rather than having the implementations instatiate themselves in order to +increase portability of code. This factory inherits from nsFactory, +which is also an XPCOM object. To gain more knowledge of factories +see the generic +factory document or the Modularization techniques document. +

nsSample.js +

This file implements the nsISample interface, and associated factory glue, +in JavaScript. + +

Compiling the idl + +

The XPIDL compiler (xpidl on Unix, xpidl.exe on Windows, and a CodeWarrior plugin on Mac) +is compiled at build time (except on Mac) thus +you will have to build mozilla in order to test this out. If you +have already built mozilla then the compiler will be located at mozilla\dist\WIN32_D.OBJ\bin\xpidl.exe. + +

Once you have the XPIDL compiler enter the following command at your +prompt: +
D:\mozilla\xpcom\sample>d:\mozilla\dist\WIN32_D.OBJ\bin\xpidl -I +d:\mozilla\dist\idl -m header nsISample.idl + +

The -I d:\mozilla\dist\idl points the compiler to the folder +containing the other idl files, needed because nsISample.idl inherits from +nsISupports.idl. The -m header instruction tells the compiler +to build the C++ header. To build the .xpt file substitute -m +typelib. + +

+For more information on compilation see the xpidl +compiler page. + +

Building the Sample + +

To build the Sample just enter +
d:\mozilla\xpcom\sample>nmake /f makefile.win + +

In order to do this you need to have your environment variables set +correctly. See the Build +page for more information. + +

Running the sample +

Using Mozilla, load +resource://res/samples/xpconnect-sample.html (i.e. what +you're reading now). Pay attention +to the console when clicking "write". Notice that the value +printed is calculated in C++ code defined in nsSample.cpp. + + + + +

+ + + + + + + + +


+ +

+JavaScript and form source: + + +

+<script>
+/* to use nsSample.js version, use "@mozilla.org/jssample;1" */
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+var sample = Components.classes["@mozilla.org/sample;1"].createInstance();
+sample = sample.QueryInterface(Components.interfaces.nsISample);
+dump("sample = " + sample + "\n");
+
+function get()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  field.value = sample.value;
+}
+
+function set()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  sample.value = field.value;
+}
+
+function poke()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  var field = document.getElementById('Value');
+  sample.poke(field.value);
+}
+
+function sampleWrite()
+{
+  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+  sample.writeValue("here is what I'm writing: ");
+}
+</script>
+
+<form name="form">
+<input type="button" value="Get" onclick="get();">
+<input type="button" value="Set" onclick="set();">
+<input type="button" value="Poke" onclick="poke();">
+<input type="text" id="Value">
+<input type="button" value="Write" onclick="sampleWrite();">
+<form>
+
+
+ +

+


+Resources: + +
+Comments to: +Michael Ang <mang@subcarrier.org> diff --git a/src/libs/xpcom18a4/xpcom/string/.cvsignore b/src/libs/xpcom18a4/xpcom/string/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/Makefile.in b/src/libs/xpcom18a4/xpcom/string/Makefile.in new file mode 100644 index 00000000..6a664cb9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/Makefile.in @@ -0,0 +1,54 @@ +# +# ***** 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 Mozilla. +# +# The Initial Developer of the Original Code is +# Netscape Communications. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string +DIRS = public src + +#ifdef ENABLE_TESTS +#DIRS += \ +# tests +#endif + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/string/README.html b/src/libs/xpcom18a4/xpcom/string/README.html new file mode 100644 index 00000000..1fdcfdd1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/README.html @@ -0,0 +1,44 @@ + + + +

managing sequences of characters

+

+ +

+ + diff --git a/src/libs/xpcom18a4/xpcom/string/doc/README.html b/src/libs/xpcom18a4/xpcom/string/doc/README.html new file mode 100644 index 00000000..154b7969 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/doc/README.html @@ -0,0 +1,44 @@ + + + +

documentation aimed at programmers who are clients of the string library

+

+ +

+ + diff --git a/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html b/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html new file mode 100644 index 00000000..41dbd217 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/doc/string-guide.html @@ -0,0 +1,2508 @@ + + + + an incomplete guide to mozilla/string + + + + + + + +

an incomplete guide to mozilla/string

+

This document is now deprecated in favor of The new string guide.

+
+

by Scott Collins +

last modified 8 April 2001 +

+ +
+

+

Abstract

+ This document provides + an introduction to the design and use of the string classes in mozilla, + detailed information on their implementation and how one may extend them, + and answers to frequently asked questions about strings. +

+
+ + + +

contents

+ + + +

+ Please direct all comments, requests, and contributions to, + in order of preference, + the tracking bug #70076 for this document, + the author scc@mozilla.org, and/or + the newsgroup news:netscape.public.mozilla.xpcom + (should there be a strings newsgroup?) +

+ +
+

+ A note to potential editors: + don't even consider modifying this document with an HTML editor. + That would destroy the internal formatting, + and make patches unmanagable. +

+
+ + + + + +
+

user's guide

+ +
+

+ Strings in mozilla are a world apart from char*s. + If you don't know why they are different, + this section is the place for you to start. + If you're already familiar with the hierarchy of string classes in mozilla, + then you might want to skip ahead to the implementor's guide + or the FAQ. +

+
+ + + +

introduction

+

what and what isn't a string?

+

+ A string is an opaque container holding a, possibly zero length, linear sequence of characters. + Understanding the implications of this statement is the foundation for understanding all mozilla's string classes. +

+ +

readable and writable

+

dependent strings

+

flat strings

+

encoding

+

sharing

+ +

using the string classes correctly; using the correct string class

+

basic string operations

+

comparison

+

concatenation

+

substrings

+

find and replace

+

conversions

+

calling a function that expects a different kind of string

+

converting between string classes

+

converting between encodings

+

selecting the right string class

+

user string classes

+

selecting the right string class for a parameter

+

selecting the right string class for a local variable

+

selecting the right string class for a member variable

+

selecting the right string class for a return value

+

selecting the right string class in IDL

+

dont's

+ +

using string iterators

+

what is an iterator?

+

reading iterators and writing iterators

+

`chunky' iterating for efficiency

+

copy_string, character sources and sinks

+

encoding conversion iterators

+ +

summary

+ + + +
+

implementor's guide

+ +
+

+ +

+
+ +
+
    + +
+
+ + + + +
+

frequently asked questions

+ +
+
+ +
+
    + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
you have some chars
you want'x'char c"foo"char* cpnsACString& cs
char. [] [] extract a character
PRUnichar PRUnichar('x') PRUnichar(c)convert encoding, extract a character
char* & & & . get a pointer
PRUnichar*convert encoding, get a pointer
nsACString NS_LITERAL_CSTRING("x") make a string NS_LITERAL_CSTRING("foo") make a string .
nsAString NS_LITERAL_STRING("x") convert encoding NS_LITERAL_STRING("foo")convert encoding
to call printf. call printf
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
you have some PRUnichars
you wantPRUnichar wPRUnichar* wpnsAString& s
char
PRUnichar [] extract a character
char*
PRUnichar* & get a pointer
nsACString
nsAString
to call printf call printf
+ +
+
+
+ is there any string doc? +
+
+ Yes, you're soaking in it! +
+ + + + +
+ I have a string, how do I get a pointer to the characters? +
+
+ You want to avoid this situation. + In your own interfaces, prefer string types over raw pointers. + Any interface that wants to process a string using a single pointer is making two expensive assumptions. + First, that the string is stored in one contiguous hunk; and + second, that the string is zero-terminated. + If this isn't the case, + then to get a pointer, storage must be allocated and the entire string must be copied to it and zero-terminated. + You may not be able to avoid needing a pointer when interacting with system calls. +
+
+ Some string classes guarantee that they are `flat'. + That is, that their data is stored in one contiguous zero-terminated hunk. + This does not imply that there are no embedded nulls. Caveat emptor. + All strings that explicitly promise flatness + inherit from the class nsAFlatString + or nsAFlatCString + and can produce a constant pointer to their data with the get() member function. + Even strings that don't explicitly promise to be flat + may happen to be flat. + The helper function PromiseFlatString will produce + a const dependent string that is guaranteed to be flat. + If you use this on a string that already happens to be flat, + the result is simply a reference through to that string. + Otherwise, + PromiseFlatString does the work to allocate, copy, terminate, and manage + a temporary flat string. + Since the result of PromiseFlatString is a temporary, + you must be careful not to get and hold a pointer to its data for longer than the temporary itself lives. +
+
+
+
+  /* I have a string, how do I get a pointer to the characters? */
+
+extern void EvilNarrowOSFunction( const char* );    // evil OS routines that want a pointers
+extern void EvilWideOSFunction( const PRUnichar* );
+
+void func( const nsAString& aString, const nsACString& aCString )
+  {
+    EvilWideOSFunction( NS_LITERAL_STRING("Hello, World!").get() );
+      // literal strings are flat already (as are |nsString|s, et al), just use |.get()|
+
+    EvilWideOSFunction( PromiseFlatString(aString).get() );
+      // for strings that don't explicitly guarantee flatness, use |PromiseFlatString|
+
+
+      // beware holding the pointer for longer than the life of the promise
+    const PRUnichar* wp = PromiseFlatString(aString).get(); // BAD! |wp| dangles
+    EvilWideOSFunction(wp);
+
+      // if you really need to use the pointer from |PromiseFlatString| in more than one expression...
+    const nsAFlatString& flat = PromiseFlatString(aString);
+    EvilWideOSFunction(flat.get());
+    SomeOtherFunction(flat.get());
+
+      // similarly for |char| strings
+    EvilNarrowOSFunction( PromiseFlatCString(aCString).get() );
+  }
+
+
+
+ + + + +
+ How do I get a particular character out of a string? +
+
+ Flat strings provide operator[] and CharAt(). + All strings provide First(), Last(), and access with iterators. + Don't promise a string flat just to do character indexing. + Prefer, instead, to get an iterator and advance it to the position you care about. +
+
+
+
+  /* How do I get a particular character out of a string? */
+
+PRUnichar Get5thCharacterOf( const nsAString& aString )
+  {
+    if ( aString.Length() >= 5 )
+      {
+        nsAString::const_iterator iter;
+        aString.BeginReading(iter); // make |iter| point to the beginning of |aString|
+        iter.advance(5);
+        return *iter;
+      }
+
+    return PRUnichar(0);
+  }
+
+
+
+
+ Using iterators isn't as bad as the example above makes it feel. + The typical use is for advancing through a string, examining many characters. +
+ + + + +
+ How do I convert from one encoding to another? +
+
+
+ + + + +
+ How do I create a string? +
+
+
+ + + +
+ What is the best way to return a string? +
+
+

+ There are several reasonable ways to produce a string result from a function. + If you are already holding the answer as a sharable string, + you can simply return that string (pass-by-value). + Otherwise, + the most efficient and flexible way to return a string is + to assign your result into a non-const reference parameter. + Don't bother to create a sharable string from scratch with your generated result. +

+

+ Why? + The two things you want to minimize in string manipulation are, + in order of importance, + heap allocation, and + moving characters around. +

+
+
+
+
+  /* What is the best way to return a string? */
+
+class foo
+  {
+    public:
+      // ...
+      void GetShortName( nsAString& aResult ) const;
+      nsCommonString GetFullName() const;
+      
+    private:
+      nsCommonString    mFullName;
+
+      const PRUnichar*  mShortName;
+      PRUint32          mShortNameLength;
+      
+  };
+
+nsCommonString
+foo::GetFullName() const
+  {
+    return mFullName;
+  }
+
+void
+foo::GetShortName( nsAString& aResult ) const
+  {
+    aResult = DependentString(mShortName, mShortNameLength);
+  }
+
+
+
+ + +
+ How do I printf a string, e.g., for debugging. +
+
+ If your string is already narrow, you just have to worry about making it flat, and then getting a pointer. +
+
+ If your string happens to be wide, + you'll need to convert it before you can printf something reasonable. + If it's just for debugging, + you probably wouldn't care if something odd was printed in the case of a Unicode character that didn't have + an ASCII equivalent. (If you have a UTF-8 terminal, the result is + perfectly legible and nothing odd is printed.) + The simplest thing in this case is to make a temporary conversion using NS_ConvertUTF16toUTF8. + The result is conveniently flat already, so getting the pointer is simple. + Remember not to hold onto the pointer you get out of this beyond the lifetime of temporary. +
+
+
+
+  /* How do I |printf| a string? */
+
+
+void PrintSomeStrings( const nsAString& aString, const PRUnichar* aKey, const nsACString& aCString )
+  {
+      // |printf|ing a narrow string is easy
+    printf("%s\n", PromiseFlatCString(aCString).get());     // GOOD
+
+      // the simplest way to get a |printf|-able |const char*| out of a string
+    printf("%s\n", NS_ConvertUTF16toUTF8(aKey).get());       // GOOD
+
+      // works just as well with an formal wide string type...
+    printf("%s\n", NS_ConvertUTF16toUTF8(aString).get());
+
+
+      // But don't hold onto the pointer longer than the lifetime of the temporary!
+    const char* cstring = NS_ConvertUTF16toUTF8(aKey).get(); // BAD! |cstring| is dangling
+    printf("%s\n", cstring);
+  }
+
+
+
+ +
+ +

+ Here are the email answers I have yet to format into the FAQ. + Some of the URLs may be out-dated or moved. + The messages are in order from oldest to newest. +

+

[Note : In June, 2003, these emails were modified +to better reflect what is stored in 'wide' string +classes (UTF-16 string instead of UCS-2) and what +related methods do as a part of the patch for bug 183156. +Therefore, they're a little different from the original emails +written by Scott Collins] +

+
+
+Date: Thu, 13 Apr 2000 19:41:47 -0400
+
+ +

Encoding Wars + +

This message is all about strings and the various encodings that might +be used to interpret their contents, the ramifications of that, and +where we're heading. The point of this message is to say what we're +currently thinking, and get feedback. I apologize in advance for the +rambling, and for the fact that this message may accidentally mix +discussion of how things are and how they will be. + +

There are many different possible encodings. Three in common use in +the Mozilla source base are: ASCII, UTF-16, and UTF-8. In ASCII, every + +character fits in 7-bits and is typically stored in an 8-bit byte. We +usually represent ASCII strings with nsCStrings, nsXPIDLCStrings, +or char string literals. In UTF-16, characters occupy one 16-bit code unit ( + +BMPcharacters) +or two 16-bit code units +( +non-BMP characters). +We usually represent UTF-16 strings as nsStrings, etc., i.e., two-byte +or `wide' strings. UTF-8 is a multi-byte encoding. A character might +occupy one, two, three, or four bytes. It is easiest to store and +manipulate such a string within a single-byte or `narrow' string +implementation. + +

None of our current string implementations know the encoding of the +data they hold at any given moment. An nsCString might legitimately +hold data encoded in ASCII, UTF-8 or even EBCDIC for that matter. + +

Operations that convert from one encoding to another, or operations +that are encoding sensitive (e.g., to_upper), rightly belong in +i18n. The fact that our current string interfaces automatically and +implicitly convert between wide and narrow strings is actually the +source of many errors in two particular categories: (1) unintended +extra work, (2) mistaken re-encoding, e.g., accidentally `converting' +a UTF-8 string to UTF-16 by pretending the UTF-8 string is ASCII and then +padding with '\0's. + +

We've known these were bad for a long time, and have been trying to +find the right way to fix them. The current thinking is to just byte +the bullet and eliminate implicit conversions. That has interesting +ramifications. + +

+
+void foo( const nsString&  aUTF16string );
+
+foo("hello"); // works!  constructs a temporary |nsString| by
+              // converting the ASCII literal with padding.
+              // Note: this requires an allocation
+
+
+ +

Though we've always hated this form since it requires a heap +allocation. In current code, we recommend + +

+
+foo( nsAutoString("hello") );
+
+
+ +

which still copy/converts, but at least it probably doesn't need to do +a heap allocation. In the best of all worlds, no conversion, copying, +or allocation would be necessary. To do that, you would need to be +able to directly specify a UTF-16 string, e.g., with the L"hello" +notation, and wrap that in an interface that just held a pointer. +E.g., something like + +

+
+void foo( const nsAReadableString&  aUTF16string );
+
+foo( nsLiteralString(L"hello") );
+
+
+ +

There are problems with this example, however. The L notation +specifically makes objects that are arrays of wchar_t, which under +GCC is a 4-byte element. This leads to incompatibility with JS, and +the annoyance of possibly bloated storage (I'm sort of minimizing the +situation here. It's worse that I make it sound). More about tricks +to get around this in a bit, but first, let me talk about what to do +in the meantime while we're just getting rid of implicit constructors. + Initially to get around this problem (what problem? The problem that +foo("hello") stopped compiling on my machine when I threw the +switch) I made a routine called NS_ConvertToString which looked like +this + +

+
+inline
+nsAutoString
+NS_ConvertToString( const char* anASCIIstring )
+  {
+    nsAutoString aUCS2string;
+    aUCS2string.AssignWithConversion(anASCIIstring);
+    return aUCS2string;
+  }
+
+
+ +

Which lets me write + +

+
+foo( NS_ConvertToString("hello") );
+
+
+ +

This was OK, but in discussion there were concerns about performance +on machines that didn't inline well, and issues about naming. In +that meeting we came up with an alternate naming strategy that we +think has room for growth and an implementation more likely to be +efficient on every platform. The implementation is to define a new +class that derives from nsAutoString, but allows construction from a +char* + +

+
+class NS_ConvertASCIItoUTF16 : public nsAutoString
+  {
+    public:
+      NS_ConvertASCIItoUTF16( const char* );
+      // ...
+  };
+
+
+ +

Which gives identical (though renamed) notation for calling foo: + +

+
+foo( NS_ConvertASCIItoUTF16("hello") );
+
+
+ +

It looks like a function call to an explicit encoding conversion. It +acts like a function call to an explicit encoding conversion. It is +a function call to an explicit encoding conversion. We think that +this naming pattern has room for growth. In the meeting, we concluded +that the best representation for encoding conversions is a family of +functions, and NS_ConvertASCIItoUTF16 fits right in. We think that +XPCOM probably can't live without the ASCII to UTF-16 conversion (though +as explicit as possible) but that all others rightly belong in i18n +land. + +

You can probably deduce from the clues in NS_ConvertToString, above, +that constructors weren't the only thing that became explicit. +Assignment, appending, comparison, et al, got renamed so that when +assigning, appending, or comparing to a value in a different encoding +the `WithConversion' form must be used. E.g., + +

+
+nsString aUTF16string;
+nsCString anASCIIstring;
+// ...
+
+aUTF16string += anASCIIstring;  // Currently legal, but not for long
+aUTF16string.Append(anASCIIstring); // same
+
+aUTF16string.AppendWithConversion(anASCIIstring); // the new way
+
+if ( aUTF16string == anASCIIstring ) // Sorry, this is going away too
+  // ...
+
+if ( aUTF16string.EqualsWithConversion(anASCIIstring) )
+  // ...
+
+
+ +

Yes, it's long and annoying. Just like the extra work you were +implicitly asking to have done, perhaps incorrectly. There are other +reasons to rename these functions. When nsString and nsCString +defined a ton of, e.g., Appends each there was no problem, because +nobody wanted to override Append. Now, with strings inheriting from +abstract base classes we immediately run into the problem that +overriding and overloading don't mix very well in C++. Because of a +feature of C++ called name hiding, it is problematic to override only +a single signature of a name overloaded in a base class. The base +nsAWritableString provides several Appends, all for objects of +(hopefully) the same encoding. nsString can't easily add a bunch of +new Appends (the converting ones) without running face first into +the name hiding problem. The discussion of the fix for this is mostly +unrelated to encoding issues, so I'll defer it to another post. + +

In hindsight, after the meeting, it seemed clear that all the +`WithConversion' forms would be better named + +

+
+xxxConvertingASCIItoUTF16
+xxxConvertingUTF16toASCII
+
+
+ +

however, the real goal (probably) is to move most such conversions +into i18n. Just bringing attention to the previously implicit +conversions is a good first step. Renaming these conversions as just +suggested is probably the right thing to do, though it sort of +validates them, which I'm not sure we really want. This is a decision +we need to discuss further. + +

Now, back to the string literal problem above. One possible solution +is to use a macro. Imagine + +

+
+NS_LITERAL_STRING("Hello")
+
+
+ +

which on a machine where the L trick works, turns into + +

+
+nsLiteralString(L"Hello")
+
+
+ +

but on a machine where there is trouble, turns into something less +appealing, but more likely to work, like + +

+
+NS_ConvertASCIItoUTF16("Hello")
+
+
+ +

Another solution is to add a compilation step that fixes L strings +on bad platforms to be non-L strings, but padded with \0s. E.g., +L"Hello" gets preprocessed into "\000H\000e\000l\000l\000o\000". +This solution is more annoying to the developer, where the prior +solution is more annoying during the runtime. + +

Before we go to too much trouble on this specific feature, we will +probably want to do more measurement to see just how much and how +often we are converting constant literal strings, and why. + + +

I'm currently ripping through the tree fixing things to use the +`WithConversion' forms where appropriate. I was also converting +things to use NS_ConvertToString where appropriate; unless I get +talked out of it, I want to switch midstream to +NS_ConvertASCIItoUTF16, then go back and fix up the +NS_ConvertToString instances later. I've set things up so I can +check in as I go. After all these conversions have been done, I'll be +able to throw the switch (what switch? NEW_STRING_APIS) which will +make nsString inherit from nsAWritableString, etc. and allow us to +start exploiting these other opportunities (e.g., for literal strings, +shared strings, etc. See +http://bugzilla.mozilla.org/show_bug.cgi?id=28221 for details and +reasoning.) + +

I guess I'm expecting comments on: + +

    +
  • how really annoying this whole topic is +
  • how bad L"xxx" is +
  • whether to move forward with NS_ConvertASCIItoUTF16 +
  • whether we should move to xxxConvertingASCIItoUTF16 etc instead + of `WithConverting' +
  • arguments about where encoding conversions should live +
  • arguments about whether going between 1 and 2 byte storage is an + encoding conversion +
  • questions about stuff I didn't mention or didn't explain well +
  • pointing out stuff I'm just plain wrong about, or things I forgot +
  • etc +
+ +

So as not to jumble the discussion, I'll be separately posting other +requests for comments about specific features of the design of the new +string hierarchy. + +

I hope this helps keep everybody filled in on what we're thinking and +able to point out what we're forgetting or screwing up :-) + + + + + +


+
+Date: Wed, 19 Apr 2000 21:12:47 -0400
+Subject: more string info
+
+ +

news://news.mozilla.org/scc-705460.16423913042000@news.mozilla.org + + + + + +


+
+Date: Fri, 26 May 2000 15:31:37 -0400
+Subject: Re: Question on ==
+
+ +

I would prefer you compare with Equals (which should really be named +IsEqualTo) rather than operator==() because of this: + +

+
+char* a;
+char* b;
+
+// ...
+
+if ( a == b )
+  // ...
+
+
+ +

Comparing two raw `string' pointers doesn't compare the characters +they point to, but instead compares the bits of the pointers. For +this reason, I may eventually make comparison of a string with a +pointer using operators just go away. + + + + + +


+
+Date: Wed, 14 Jun 2000 14:38:55 -0400
+Subject: Re: Fix to XprtDefs.h
+
+ +

Yes, we're aware that turning off wchar_t support makes wchar_t be +a synonym for unsigned short under Metrowerks. We know that the +current version of VC++ also makes these types equivalent. In theory, +though, the types are distinct even when they are the same size and +shape. By using real wchar_t support, we are forced to recognize +the distinction and navigate it appropriately with reinterpret_cast +(via NS_REINTERPRET_CAST). The win here is that we aren't caught by +compiler changes that suddenly make some set of compilers compliant +and therefore break our code. We will add an autoconf test that lets +UNIX compilers opt in to our string scheme when they have an +appropriately shaped wchar_t. If these happen to be compliant +compilers, all will be well. If they don't, the casts don't hurt, +because they are type correct. We are writing our code to meet the +standard as we move forward. + +

The win for us is realized by the following macros + +

+
+#ifdef HAVE_CPP_2BYTE_WCHAR_T
+  #define NS_LITERAL_STRING(s)  nsLiteralString(L##s, \
+                      (sizeof(L##s)/sizeof(wchar_t))-1)
+#else
+  #define NS_LITERAL_STRING(s)  NS_ConvertASCIItoUTF16(s, \
+                       sizeof(s)-1)
+#endif
+
+
+ +

An nsLiteralString points directly to the literal characters. No +copying, no conversion, and the length calculation happens at compile +time. This has turned out to be as large a savings as 15% of code +space and 8% of data space, net, in our string test harness It's +faster as well, again by eliminating the copying, conversion, and +length calculation. We don't know yet what those numbers translate +into in our real code base, but we have high hopes. + +

I don't want to be in the position to ask you to change your code. I +don't think it's appropriate for me to do so. The AIM application +that is your client is our client as well. They need to resolve this +difference between us in whatever way they think best. That may mean +asking you if changing your apis is the right thing to do. Or it may +mean applying the casts. Our code-base and yours, Justin, are more +like cousins. I don't think you should have to change just to conform +to us. You may think my arguments for using real wchar_t have +merit, and adopt similar usage just because you agree; but I think the +only obligation you have is to follow the technical solution you think +is right for your code. + +

If you decide to make this api change, it will mean shipping a new +binary (on Mac) for your library to clients who want to switch over to +the new api (since the name mangling will be different, and therefore, +the link requirements will change). + +

Hope this helps, + + + + + +


+
+Date: Thu, 15 Jun 2000 19:36:55 -0400
+Subject: Re: Checkin approval for bug 32336
+
+ +
+
+S.Equals(NS_LITERAL_STRING("bar"), PR_TRUE, 3)
+
+
+ +

doesn't compile because there is no three parameter form for Equals. + For all definitions of Equals on strings, see "nsAReadableString.h" + +

http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h + +

There is an EqualsWithConversion that takes three parameters. + +

http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsString2.h#731 + +

It is ``EqualsWithConversion'' because it admits the possibility of an +encoding specific transformation, in this case to provide +case-insensitive comparison. This also wouldn't compile, however, +since, at the moment, an nsLiteralString doesn't provide an operator +to produce a const PRUnichar* (though perhaps it should), and it +doesn't satisfy the other interfaces that match this call, e.g., a +const nsString&. + +

Perhaps I need to move case-insensitive comparison up out of +nsString into a global encoding specific transformations and +algorithms file (which was on its way anyway as Waterson, knows); this +use is one bit of evidence to support this. In the short term, this +can be fixed (if we think the current behavior is wrong) by providing +operator const CharT*() const on literal string. + +

If you can live with out case-folding, the earlier form is preferred + +

+
+S == NS_LITERAL_STRING("bar")
+
+
+ +

if you can't, then one of the fixes I mentioned is in order. + + + + + +


+
+Date: Thu, 15 Jun 2000 19:47:12 -0400
+Subject: Re: [Fwd: how to use nsString ?]
+
+ + + +

Apologies. Documentation mentioning strings is getting out of date. +Here are some specific answers. + + +

+ +

...is now perhaps best expressed as + + nsString URLString( NS_LITERAL_STRING("http://www.mozilla.org") ); + +

since an nsString is a sequence of 2-byte wide characters, and the +routines that implicitly convert 1-byte sequences (like the literal +sequence you specified, "http:...") are now gone. + +

Up until not too long ago, one would have had to say + +

+
+nsString URLString;
+URLString.AssignWithConversion("http://www.mozilla.org");
+
+
+ +

The NS_LITERAL_STRING construction is new machinery that has the +potential to make many operations much more efficient. + +

+ +

SetString was a synonym for Assign or assignment with +operator=(), it too went away. The equivalent is the second +example I gave above, that is, the one with AssignWithConversion. + +

Assign still exists. AssignWithConversion takes on that +functionality for assignments that require encoding transformations +(e.g., from ASCII to UTF16). SetString is gone, since it was always +a synonym for Assign. + +

Learn more about the general APIs for strings that we are trying to +move to by examining + +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAWritableString.h + +

Hope this helps, + + + + + +


+
+Date: Thu, 15 Jun 2000 21:26:51 -0400
+Subject: Re: Checkin approval for bug 32336
+
+ + + +

This is what substrings are for. In that case, you could use + +

+
+Substring(S, 0, 3) == NS_LITERAL_STRING("bar")
+
+
+ +

As for case-folding, it's best if you can case-fold everything up +front, instead of doing it repeatedly. I'll have to get back to you +on a general solution to that problem, or what my schedule for getting +it checked in would be. I'm sorry, I know that's not what you needed +to hear. If the source string is an nsString, you can continue to +exploit its implementation of these routines, e.g., ToLower all +up-front. + +

Hope this helps, + + + + + +


+
+Date: Mon, 19 Jun 2000 14:23:47 -0400
+Subject: Re: string fu
+
+ + + +

What would you prefer? That extracting a character not in the string +always return CharT(0)? Can't do it for two reasons: (1) 0 may be +a valid character in a particular encoding, so it can't be used in +general as a ``no character at that position'' marker; and (2) I can't +control what an individual string implementation does when asked to +get an out-of-bounds fragment, it's explicitly undefined. That means +the result of CharAt is explicitly undefined for indexes outside the +defined contents of the string. As a debugging convenience, I have +made this assert, but it has always been the case that retrieving such +a character had undefined results ... even in [the old] code. + +

OK, you might say, well at least let me ask for a character that is +only off the end by one. E.g., Last of an empty string. Reason (1) +from above still applies. How bad is it to say, for the case you gave + +

+
+PRBool needsDelim = PR_FALSE;
+if ( !path.IsEmpty() )
+  {
+    PRUnichar last = path.Last();
+    needsDelim = !(last == '/' || last == '\\');
+  }
+
+
+ +

In general, you probably want to opt out of a whole lot of work when +the source string is empty. It is slightly less convenient, but it +doesn't tie us to a bunch of implementation specific mojo. + + +

+ +

This is an annoying property of auto strings, e.g., that they always +have an allocated buffer. I'm happy to fix this bug, however, be +aware that GetUnicode and GetBuffer are artifacts of [the old] +implementation that we don't want to support. They are not part of +the abstract interface. We will keep them no longer than we have to. +They don't support our multi-fragment paradigm. People who require a +contiguous hunk of characters in the future, and are unwilling to +switch over to chunky-iterators, may be forced to copy the string to +their own buffer. There will be an implementation of narrow character +string that guarantees contiguous allocation and a zero-terminator, +much as nsCString does now, for compatibility with platform uses, +but this won't be the default string class. + + + + + +


+
+Date: Mon, 19 Jun 2000 17:22:31 -0400
+
+ +

Clarifying String Sematics + +

Recently, I added an assert to the string operations that extract +characters, namely First(), Last(), CharAt(), and +operator[](). This assert fires when any of these routines are used +to access a character outside the defined contents of the string. For +First() and Last() that means whenever they are applied to an +empty string. For CharAt() and operator[](), that means whenever +they are used to access an index outside the range of +0..Length()-1. There have been some complaints, however, the +result was always undefined. What follows is extracted from an email +exchange between me and warren on this topic. I hope it clarifies +strings semantics + +

Warren writes: +

+ +

I replied: +

+ +

Warren also asks: +

+ +

And I reply: +

+ +

In a later message, Chris Waterson asks a related question +

+ +

And I reply: +

+ +

Hope this makes sense, + + + + +


+
+Date: Tue, 20 Jun 2000 04:05:31 -0400
+Subject: Re: NS_LITERAL_STRING is broken
+
+ +

The behavior you describe sounds exactly like when you say + +

+
+const char* foobar = "foobar";
+
+... NS_LITERAL_STRING(foobar).get() ...
+
+
+ +

because in this case, the thing passed in is a const char*. +NS_LITERAL_STRING is not meant to be used in this way. It is only +meant to be used around a " delimited string. The type of such is +const char[N] where N is the number of characters in the string + 1 +for the zero terminator it helpfully adds. sizeof such a type is +N. + +

Are you sure you had the actual string as an argument, as in your +example to me? Or could the actual code have been like my sample, +above? + + + + + +


+
+Date: Thu, 29 Jun 2000 13:35:10 -0400
+Subject: Re: a fix
+
+ + + + +

Dave, + +

please read + + news://news.mozilla.org/scc-314ABF.14261619062000@news.mozilla.org + +

It's just plain wrong to let people try to index into a string outside +its defined contents. I can't just return '\0' or PRUnichar('\0') +there as that could be a legal value to have somewhere in your +string for some encodings ... and the encoding is not specified. So +your patch has the basic problem of defeating my plan to stop people +from doing this bad thing. + +

The second problem with your patch is that you use the symbolic +constant nsnull, which is ostensibly a pointer value; Last returns +a character. nsnull is not appropriate for that purpose. In fact, +C++ gurus pretty much eschew the use of symbolic constants for 0. +NULL is to be avoided. nsnull is wrong-headed in that it presumes +we could have some other application specific value for NULL. We +can't, it would never work. It's just wasted brain-print. Always use +0 for these situations, and if you want to communicate the fact that +something is a pointer type, either use a comment or a +(construction-style) cast, like so (graded examples from worst to +best:) + +

    +
  • F: FindChildByNameWithHint("Chuck", nsnull); + +
  • D: FindChildByNameWithHint("Chuck", NULL); + +
  • C: FindChildByNameWithHint("Chuck", /* Child* */ 0); + +
  • B: typedef Child* Child_ptr; + FindChildByNameWithHint("Chuck", Child_ptr(0)); + +
  • A: FindChildByNameWithHint("Chuck", 0); +
+ +

Don't let this discourage you; keep up the good work :-) + + + + + +


+
+Date: Tue, 8 Aug 2000 23:47:16 -0400
+Subject: Re: nsWritingIterator?
+
+ + + + http://ScottCollins.net/Journal/discussion/string_iterators.html + +

does this help? + +

I can personally walk you through any specific scenario you need. + + + + + +


+
+Date: Wed, 9 Aug 2000 02:35:03 -0400
+Subject: Re: nsWritingIterator?
+
+ +

You got it right... it's nsWritingIterator for whichever +character type you care about, either char or PRUnichar. You +_can_ use this iterator like a character pointer ... that is, you can +dereference it, assign into its dereference, etc. It is more +efficient, though, to directly address a particular range of +characters around where it points by asking it for its actual +character pointer with get, and knowing that there are +size_forward() characters available ahead of that pointer and +size_backward() characters available behind it. After examining +those characters by hand, you can advance the iterator beyond the +characters you have examined (and possibly into the next chunk, should +one exist) by adding into it (with +=) the count of the characters you +have processed. + +

Here are three examples of running through a string and modifying some +of the characters in it. All use nsWritingIterators. + + +

+
+  // inefficient, but works in a pinch:
+  //  iterators can hide all details of chunks by acting like
+  //  a raw character pointer
+
+nsWritingIterator<PRUnichar> s = S.BeginWriting();
+nsWritingIterator<PRUnichar> done_with_string = S.EndWriting();
+
+  // for each character in the string |S|
+while ( s != done_with_string )
+  {
+      // if the character is lower case, capitalize it
+    if ( 'a' <= *s && *s <= 'z' )
+      *s = *s -'a' + 'A';
+  }
+
+
+
+
+  // efficient
+  //  iterators provide a mechanism by which you can process
+  //  a chunk-at-a-time
+
+nsWritingIterator<PRUnichar> iter = S.BeginWriting();
+nsWritingIterator<PRUnichar> done_with_string = S.EndWriting();
+
+  // for each chunk of the string
+while ( iter != done_with_string )
+  {
+    size_t N = iter.size_forward();  // # of chars in this chunk
+    PRUnichar* s = iter.get();
+    PRUnichar* done_with_chunk = s + N;
+
+      // for each character in this chunk
+    for ( ; s < done_with_chunk; ++s )
+      {
+         // if the character is lower case, capitalize it
+       if ( 'a' <= *s && *s <= 'z' )
+          *s = *s - 'a' + 'A';
+      } 
+
+      // advance the iterator past characters
+      //  we examined (and into the next chunk, if any)
+    s += N;
+  }
+
+
+
+  // elegant
+  //  pull your transformation into a `sink', and |copy_string|
+  //  will efficiently pump any kind of string into it
+
+struct Capitalize
+  {
+      // inline
+    PRUint32
+    write( PRUnichar* s, PRUint32 N )
+        // processes one chunk, called repeatedly by |copy_string|
+      {
+        PRUnichar* done_with_chunk = s + N;
+
+         // for each character in this chunk
+        for ( ; s < done_with_chunk; ++s )
+          {
+              // if the character is lower case, capitalize it
+            if ( 'a' <= *s && *s <= 'z' )
+              *s = *s - 'a' + 'A';
+          }
+      }
+  };
+
+copy_string(S.BeginWriting(), S.EndWriting(), Capitalize());
+
+
+ + + +

Does this show it better? + + + + + +


+
+Date: Thu, 17 Aug 2000 18:23:22 -0400
+
+ + + +

I'll explain things in a little more detail than you need, then so +that some of the stuff you see in these headers will make more sense. +I'll also answer your questions out of order. + +

First: the string hierarchy looks like this + +http://ScottCollins.net/Journal/discussion/string_hierarchy.gif + +

The two most important headers are: + +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAReadableString.h +http://lxr.mozilla.org/seamonkey/source/xpcom/ds/nsAWritableString.h + +

These abstract classes, nsAReadable[C]String, and +nsAWritable[C]String are typically what you will want to use in the +interfaces of new code. If you write a piece of code that takes a +string for input, consider, e.g., + +

+
+void consumes_a_string( const nsAReadableString&  aInput );
+
+
+ +

If you write a piece of code that modifies a string, consider + +

+
+void modifies_a_string( nsAWritableString&  aResult );
+
+
+ + +

When creating your own classes, member strings will typically be +nsStrings. When you can't avoid creating a short string that you +need only temporarily during a function, you will typically use +nsAutoString. When someone passes you a raw pointer, or a raw +pointer and a length, representing a buffer of characters that you may +examine, but won't own, you can treat it like a string by wrapping it +in an nsLiteralString, e.g., + +

+
+void
+reads_a_buffer( const PRUnichar* aInput, PRUint32 aInputLength )
+  {
+    nsLiteralString input(aInput, aInputLength);
+      // doesn't allocate or copy
+
+    // ...
+  }
+
+
+ +

You will use nsLiteralString around quoted constant strings as well, +though typically through the NS_LITERAL_STRING macro, to avoid doing +a length calculation + +

+
+NS_LITERAL_STRING("x")
+
+
+ +

expands to + +

+
+nsLiteralString(L"x", (sizeof(L"x")/sizeof(PRUnichar) - 1))
+
+
+ +

if L notation works as needed on your platform. + +Those are the basics. Now onto your questions: + + +

+ + +

L"abc " makes a an object that is a const wchar_t[5], and none of +the string code knows about wchar_t. The main reason is that +wchar_t is not necessarily the right size (it can be 4 bytes under +gcc). If you wrap these constant expressions in NS_LITERAL_STRING, +as described above, you should get the right thing, e.g., + +

+
+str1 += NS_LITERAL_STRING("abc ") + str2 + NS_LITERAL_STRING("def");
+
+
+ + + + +

This one, I have a quick and easy explanation for. If function was +declared like this + +

+
+function( const nsAReadableString&  )
+
+
+ +

then, no problem, since a nsPromiseConcatenation (which was the +result of adding those two things together) is a readable string. +No other objects need to be created; no copying needs to be performed. + +

In all cases, we want the creation of nsStrings et al, to be +explicit, since creation is unbelievably expensive, requiring heap +allocation, locks, copying, etc. + +

I hope this answers both your posts, + + + + + +


+
+Date: Thu, 17 Aug 2000 20:57:08 -0400
+Subject: re our conversation
+
+ + return ToNewUnicode( nsLiteralCString(buffer) ); + + + + + + +
+
+Date: Fri, 18 Aug 2000 02:52:45 -0400
+Subject: Re: More questions and new string API
+
+ + + +

Unfortunately, NS_LITERAL_STRINGs definition is not particularly +amenable to this use. Instead, you would have to say something like +this: + +

+
+const nsAReadableString&
+foo()
+  {
+#ifdef HAVE_CPP_2BYTE_WCHAR_T
+    static nsLiteralString static_foo(L"x", 1);
+#else
+    static nsLiteralString static_foo;
+    static PRBool initialized = PR_FALSE;
+    if ( !initialized )
+      {
+        static_foo.AssignWithConversion("x", 1);
+        initialized = PR_TRUE;
+      }
+#endif
+    return static_foo;
+  }
+
+
+ + + + +

I don't know what errors you are getting; but it probably doesn't work +because a reference isn't an assignable type. This is just a guess. +You may need to use + +

+
+map
+
+
+ +

If you actually want the map to manage ownership of the keys, then +you'll want to use a concrete type, e.g., + +

+
+map
+
+
+ +

or perhaps + +

+
+map
+
+
+ +

Or maybe there's something else wrong. Send me the error messages. +If you end up using a pointer, then of course you'll have to supply a +comparison function to the map template. You won't be satisfied +with the default comparison of pointers :-) Sorry I couldn't answer +this one more completely. + + +

+ +

The problem with this scenario is that an nsAReadableString doesn't +promise that all its data is contiguous, nor that it is +zero-terminated, which is what I suspect you want in this case. If +the function you want to call can take {pointer, length} tuples, and +can consume the string in hunks without zero termination ... then you +can use copy_string to pump the string into your function, see + + http://ScottCollins.net/Journal/discussion/string_iterators.html + +

If not, and you absolutely have to have a contiguous zero-terminated +buffer, then there is a new facility (part of the DOMAPI branch) that +does what you need. It's not checked in on the trunk; it should +be in early next week. It is nsPromiseFlatString. This class +promises a contiguous zero-terminated buffer; and has an operator +PRUnichar* to produce a pointer to that buffer automatically. If the +underlying class is one that happens to be a single fragment and +zero-terminated, then, like nsPromiseSubstring and +nsPromiseConcatenation, this class merely holds a reference into the +original data. If, however, the underlying string is multi-fragment +or not zero-terminated, then nsPromiseFlatString allocates a +contiguous buffer of appropriate size and copies the fragmented string +data to it. So given + +

+
+void ReadBuffer( PRUnichar* );
+
+
+ +

You can call this as efficiently as possible with an arbitrary string +like so + +

+
+ReadBuffer( nsPromiseFlatString(aString) );
+
+
+ + +

If the function you are calling needs to take ownership of the buffer +you hand it, then you will probably call ToNewUnicode like so + +

+
+void ConsumeBuffer( PRUnichar* );
+
+ConsumeBuffer( ToNewUnicode(aString) );
+
+
+ +

The global function ToNewUnicode is declared in "nsReadableUtils.h", +and was only recently added to the build. It is currently being used +in the DOMAPI branch. It is part of the build, but the file +"dlldeps.c" in XPCOM may need to be modified to ensure it is exported +on your platform if you are building the tip. + +Needless to say, you want to avoid functions that require bare +pointers for several reasons: (a) they typically assume +zero-termination, which is not guaranteed by the normal encodings; (b) +they require contiguous allocation, which may not be possible; (c) +they scan for the end of the string, at linear cost (if the encoding +makes it possible at all), when the length could be known in advance. +If you have to do it, the above mechanisms work, but be aware of the +cost and the potential need to copy. + + +

+ +

nsAReadableString is an abstract type. So you can't have a concrete +instance of it. All strings in the hierarchy are readable strings. +If you just want a reference to a readable string, you can say, e.g., + +

+
+struct foo
+  {
+    const nsAReadableString&  mString;
+    // ...
+
+    foo( const nsAReadableString&  aString ) : mString(aString) { }
+  };
+
+
+ +

...similarly with pointers; but I suspect you are looking for +something more concrete. An nsString is a nsAReadableString, and +is the typical thing you want as a member variable. An nsAutoString +is also an nsAReadableString and is typically what you would use for +a short (in length) temporary (in lifetime) local variable, as I +mentioned in my previous post. + + +

+ +

Yes, though remember, an nsLiteralString assumes the lifetime of the +underlying data is under someone else's control. If the called +function gives you a buffer that you need to delete, you will have +to manage that yourself. Currently, people often use nsXPIDLString +to handle that. XPIDL strings are not part of the hierarchy. They +are only used as a sort of string-auto_ptr. However, I'm +integrating their functionality into nsString. There is no problem +in wrapping the same pointer in both as two separate local variables, +one to give you the readable interface, and one to manage the +lifetime. + +

If it's OK with you, I'd like to post this reply (including your +quoted questions) to n.p.m.xpcom and also put a copy near the string +iterator discussion I provided a link to above, so that other people +with similar questions can see these answers. + +

Hope this helps, + + + + + +


+
+Date: Sun, 3 Sep 2000 03:52:17 -0400
+
+ +

In article <8nu9m2$eo14@secnews.netscape.com>, "Jon Smirl" + wrote: + +> I have the new strings up and running in my app. They work as +> advertised and +> I haven't found any bugs. Thanks for the good job in designing and +> implementing them. Here's are a summary of issues I've encountered +> so far... + +

Thanks, and I appreciate your comments and insights. + + +> +> 1) Should there be a nsSegmentedString derived from nsString instead +> of building segment support into nsString? None of my strings are +> segmented but +> I keep executing code that is supports it. nsPromiseFlatString would +> be trivial in the non-segmented case. + +

The general case is that a string does not promise to have contiguous +data. A specific case is that, for some implementations, it does. +You couldn't do it the other way around, because a segmented string +couldn't satisfy all the promises of a flat string. However, through +the use of chunky iterators, operating on strings that happen to be +flat is very efficient. In fact, nsPromiseFlatString is trivial in +the non-segmented case. In addition, I'll be adding an abstract flat +class into the hierarchy, which will present additional interface ... +in your local routines where you actually have declared a concrete +string instance that happens to be flat, the compiler will give you +the benefit of using the flat specific routines (e.g., a substring +object over a flat string is simpler than the general purpose +substring). I need to be cautious about this, though, since I don't +automatically want people propagating the flat type through their +interfaces. That would put us in the same boat we're in right now ... +where routines only work on a specific kind of string, which denies +other parts of the code the opportunity to use an implementation +beneficial to its specific needs, and typically for no good reason. + +> +> 2) Should nsAWritableString have a way to get the buffer and then +> return it? +> I need to get the buffer to pass it to OS calls. I'm doing this now +> by passing around nsStrings instead of the interface. If I just use +> the interface I encur an extra copy since I have to use a temporary +> buffer. + +

A specific string implementation could promise this, but in general, a +writable could not. After all, a writable doesn't even guarantee +contiguous storage. To some degree, this is what +nsPromiseFlatString is for. However, this is a readable promise +only. It will also be the case that ns[C]Strings, in the very near +future will be able to just assume ownership of an arbitrary buffer +allocated on the free store with the XPCOM allocators ... getting one +to give up its buffer, on the other hand, presents some problems. Do +you have a lot of places where the system writes into your string +buffer space? Or do you have a lot of system routines that return you +new buffers? I can imagine using nsPromiseFlatString for this, but +what happens when the OS alters the underlying data? If the promise +had generated that flat data on behalf of a multi-fragment string, +should it now put the changes back? It's possible to do, I just want +to know if it's correct to allow this situation to happen. + + + +> +> 3) There needs to be a NS_LITERAL_CHAR() to go along with +> NS_LITERAL_STRING(). + +

OK. + + + +> Having NS_LITERAL_STRING() all over the code clutters +> it up and makes it hard to tell what the code is doing, could we +> have a standard short alias for this? + +

Yes, I'll try to think of something ... perhaps NS_LSTR? + + +> 4) nsLiteralString should support n.ToInteger(&error); + +

ToInteger is actually a bad interface. It's only good if your +entire string is the number; this encourages you to edit your string +until it is one, or perhaps copy the numeric part to another string. +Better if you just sscanf a string (don't know if I can provide +that in the general case, but I'm thinking about it), or else use +regular C++ extractors (which wouldn't be too hard for me to +provide), or else I could give you a ToInteger that works on a pair +of iterators, extracting the integer from the digits between them. + +> +> 5) There should be a global define for an interface to a readonly +> empty string. + +

Yes, there will be. + + +> +> 6) Something is wrong with concatenation.... + +

Hopefully I've fixed this now. + + + +> 8) A forward definition is missing in the h files + +

I'll check it out. + + + +

My understanding is that you have already found the answers to your +other questions. + +

I hope this helps, + + + + +


+
+Date: Wed, 20 Sep 2000 17:32:13 -0400
+Subject: Re: how to free an nsString::ToNewCString
+
+ + + +

nsMemory::Free + + + + + +


+ +

You use several NS_ConvertASCIItoUTF16("...").get(), these should be + + NS_LITERAL_STRING("...").get() + +

Don't do this to the very first case where you aren't wrapping an actual literal string. +The first instance would should exploit NS_LITERAL_STRING technology as well, +around the initial declarations of the strings ... probably want to do this with +NS_NAMED_LITERAL_STRING. + + + +


+
+Date: Thu, 12 Oct 2000 00:57:28 -0400
+Subject: string answers
+
+ +
+
+nsresult
+DoSomething( nsAWritableString&  answer )
+  {
+    nsresult rv;
+
+    nsXPIDLString registry_data;
+    Fetch("key", getter_Shares(registry_data));
+
+    nsLiteralString path(not_my_string);
+
+    PRInt32 first_colon = path.FindChar(PRUnichar(':'));
+    if ( first_colon != -1 )
+      {
+        // convert ... extract path from |path|
+        nsCOMPtr localFile( do_CreateInstance(CID, &rv)
+);
+        if ( localFile )
+          {
+           
+localFile->SetPersistentDescriptor(NS_ConvertUTF16toUTF8(path));
+
+            nsXPIDLString converted_path;
+            localFile->GetUnicodePath(getter_Copies(converted_path));
+            answer = converted_path.get();
+          }
+      }
+    else
+      {
+        answer = path;
+      }
+
+
+    return rv;
+  }
+
+
+ + + + + +
+
+Date: Thu, 12 Oct 2000 02:03:49 -0400
+Subject: Re: and the answer is ...
+
+ +

You can see from the line of code that you're on, that this should +have been fine. nsMemory::Alloc would be asked to allocate a 1 byte +object. But it failed trying to allocate that. Which suggests that +the allocator was busy and non-reentrant and the debugger tried to +misuse it. Yes? + +

Of course, this doesn't solve your problem. Perhaps we need to go +back to the idea of a function that returns a pointer to the first +hunk of the string. + +

+
+const char*
+debug_string( const nsAReadableCString& aCString )
+  {
+    nsReadingIterator<char> iter;
+    aCString.BeginReading(iter);
+    return aCString.IsEmpty() ? "" : iter.get();
+  }
+
+
+ +

This code should work regardless of what the allocator is doing. The +downsides are (a) it only returns the first hunk of the string, in the +case of a multi-fragment string; and (b) that hunk might not be +zero-terminated. + +

Hope this helps, + + + + + +


+
+Date: Thu, 12 Oct 2000 08:30:32 -0400
+Subject: Re: Self healing the cache :-)
+
+ +

At 3:04 PM -0400 10/11/00, Mike Shaver wrote: +

+ +

Macro ugliness makes NS_LITERAL_STRING inappropriate for use over +other macros. In other words: + +

+
+NS_LITERAL_STRING("foo")
+
+
+ +

is good. + +

+
+#define FOO "foo"
+NS_LITERAL_STRING(FOO)
+
+
+ +

is bad. Why? Because it turns into + +

+
+nsLiteralString(LFOO, sizeof(LFOO)...
+
+
+ +

and there is no LFOO. Sorry. If you have to do this to a +macro-ized string, do the magic by hand, e.g., + +

+
+nsLiteralString(FOO, sizeof(FOO)/sizeof(PRUnichar)
+                                          + sizeof(PRUnichar('\0')))
+
+
+ +

or else if you don't care that nsLiteralString will scan for the +length, just say + +

+
+nsLiteralString(FOO)
+
+
+ +

Hope this helps, + + + + + +


+
+Date: Thu, 12 Oct 2000 08:36:14 -0400
+Subject: Re: Self healing the cache :-)
+
+ +

Actually, I'm not even sure you can do it by hand, since you didn't + +

+
+#define FOO L"foo"
+
+
+ +

and can't do that cross-platform. The other way around this is to +define a global instead of a macro, that is, instead of saying + +

+
+#define FOO "foo"
+
+
+ +

at the top of your file, say + +

+
+NS_NAMED_LITERAL_STRING(FOO, "foo")
+
+
+ +

or else, if the macro was used only in one spot ... perhaps you could +just eliminate the macro in favor of NS_NAMED_LITERAL in situ. + +

Arghh. In this case, you may be stuck with the extra work of +AssignWithConversion. + + + + + +


+
+Date: Sun, 3 Dec 2000 16:38:07 -0400
+Subject: Re: another copy_string question
+
+ + + +

No, there isn't. But you could move such special processing into the +destructor of the sink. Remember, the sink is passed by reference, so +you can exactly control its lifetime. + +

+
+{
+  MySink sink;
+  nsReadingIterator<PRUnichar> sourceStart = aStr.BeginReading();
+  nsReadingIterator<PRUnichar> sourceEnd = aStr.EndReading();
+  copy_string(sourceStart, sourceEnd, sink);
+    // |sink| destructor executed here
+}
+
+
+ +

Hope this helps, + + + + + +


+
+Date: Fri, 15 Dec 2000 20:02:08 -0400
+Subject: fragment of code
+
+ +
+
+nsPromiseFlatString flatKey(aReadable);
+
+flatKey.get()
+
+
+ + + + + + +
+
+Date: Tue, 16 Jan 2001 16:47:37 -0400
+Subject: Re: a few string questions...
+
+ +>I've accumulated a few questions I've been wanting to ask you, mostly +>about string stuff. Nothing urgent, but I want to ask them before I +>forget. So here goes...: +> +>1) Is it acceptable to use nsLiteralCString or nsLiteralString on +>something that's not a literal? This can be useful in some places, +>for example, to convert a char* to PRUnichar*: +> +>PRUnichar* new = ToNewUnicode(nsLiteralCString(myCharPtr)); + +

This is explicitly allowed. That's why I'm proposing to change the +names of those classes to nsLocal[C]String. + + +>2) Should nsString2x.h and nsString2x.cpp go away? They look like a +>never-completed rewrite or something... + +

Yes. They should go away. They are uncompleted [old] bullshit, +exactly as you diagnosed. + +

I'll look into the other two questions. + + + + + +


+
+Date: Thu, 1 Feb 2001 15:12:41 -0400
+Subject: Re: [Fwd: bad string, bad string]
+
+ +

We've been removing implicit conversion operators because they +_always_ lead to trouble. Usually they make it harder to pick the +right function when overloading is involved and in the past they have +led to huge performance suckage because we ended up doing conversions +when we didn't need to because the implicit operator made us pick the +wrong function. + +

It's borderline when the class implements something that is so +close, as with a guaranteed flat string or an nsCOMPtr ... but the +general recommendation is to avoid implicit conversions. + +

See bug #53057. + + + + + +


+
+Date: Tue, 6 Feb 2001 18:52:23 -0400
+Subject: seeking review for bug #57087
+
+ +

bug: + http://bugzilla.mozilla.org/show_bug.cgi?id=57087 + + patch: + http://bugzilla.mozilla.org/showattachment.cgi?attach_id=24576 + +

This patch is supposed to add the ability to define very long literal +strings more easily by breaking lines, e.g., + +

+
+NS_MULTILINE_LITERAL( NS_L("This is the start of a very long line")
+                      NS_L(" which actually continues across")
+                      NS_L(" a couple more.") )
+
+
+ +

The main danger in this scheme is callers who omit the inner NS_L +wrapping. Though I believe this will be caught at compile time as the +wrong type initializer. + +

Seeking input from everybody, and waterson in particular. + + + + + +


+
+Date: Wed, 14 Feb 2001 16:09:10 -0400
+Subject: Re: Question...
+
+ +

There are some utilities in "xpcom/ds/nsReadableUtils.h". In +particular, if you want to get back a new heap-allocated ASCII string +with the minimal work, you would say + +

+
+PRUnichar* sourceChars = ...;
+
+char* destChars = ToNewCString(nsLiteralString(sourceChars));
+
+
+ + +

It's more efficient if you happen to already know the length. If you +don't, don't bother counting, that's what I'll do in the constructor +for nsLiteralString. If you do, then call like this + +

+
+destChars = ToNewCString( nsLiteralString(sourceChars, length) );
+
+
+ +

Other routines in that file will help you if, for instance, you wanted +to translate into a buffer you had already allocated. + +

Hope this helps, + + + + + +


+
+Date: Fri, 23 Feb 2001 03:12:58 -0400
+Subject: string snippet
+
+ +
+
+nsCString aInput;
+
+
+
+nsReadingIterator<char> search_start;
+aInput.BeginReading(search_start);
+
+nsReadingIterator<char> search_end;
+aInput.EndReading(search_end);
+
+if ( FindCharInReadable(':', search_start, search_end) )
+  {
+    ++search_start;
+    return ToNewCString( Substring(aInput, search_start, search_end)
+);
+  }
+
+
+ + + + + + +
+
+Date: Wed, 7 Mar 2001 19:44:08 -0400
+Subject: string help
+
+ +

Here you go, Mike: + + http://scottcollins.net/journal/discussion/mjudge-scratch.cpp + + + + + + +


+
+Date: Fri, 9 Mar 2001 20:56:07 -0400
+Subject: Re: string assertions
+
+ +

If you get an iterator into a string and you advance it all the way to +the end of the string, and then keep trying to advance it, you hit +this assert. This could happen, for example if you tried to copy 10 +characters out of a 9 character string. I've tried to make this +impossible to get to. As far as I know, all my routines trim requests +in advance of manipulating iterators. When you see this, you should +get the stack. That will take you right to the bad spot. + + + + + +


+
+Date: Sat, 31 Mar 2001 11:04:03 -0400
+Subject: Re: Sun bustage and string advice
+
+ +

You do know you are comparing two pointers now? It seems unlikely +those two pointers would ever be the same pointer. You probably want +to say something like + +

+
+NS_LITERAL_STRING("foo").Equals(aTopic) // or
+
+NS_LITERAL_STRING("foo") == nsLiteralString(aTopic)
+
+
+ +

...so that you compare the contents of two strings. Right now, +you're just testing to see if two pointers both point to the same +location in memory. A lot of people make this mistake. I would like +to make it obvious to people that comparing two pointers does not +compare strings. Can you tell me what gave you that impression so +that I can figure out how to better educate people not to do this? By +the way, it's not that I don't want to make this compare two +strings; it's that in C++, you can't override operations for built-in +types. And pointers are built-in types. So I can't make +operator==(const PRUnichar*, const PRUnichar*) do anything different +than it already does, which is the same thing it does for any other +pointer. + + + + + + +

+ + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/string/public/.cvsignore b/src/libs/xpcom18a4/xpcom/string/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/public/Makefile.in b/src/libs/xpcom18a4/xpcom/string/public/Makefile.in new file mode 100644 index 00000000..d3582bcc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/Makefile.in @@ -0,0 +1,86 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** 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 Mozilla. +# +# The Initial Developer of the Original Code is +# Netscape Communications. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# Scott Collins +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string + +EXPORTS = \ + nsAString.h \ + nsAlgorithm.h \ + nsCharTraits.h \ + nsDependentString.h \ + nsDependentSubstring.h \ + nsLiteralString.h \ + nsObsoleteAString.h \ + nsPrintfCString.h \ + nsPromiseFlatString.h \ + nsReadableUtils.h \ + nsString.h \ + nsStringFwd.h \ + nsStringIterator.h \ + nsSubstring.h \ + nsSubstringTuple.h \ + nsTAString.h \ + nsTDependentString.h \ + nsTDependentSubstring.h \ + nsTObsoleteAString.h \ + nsTPromiseFlatString.h \ + nsTString.h \ + nsTSubstring.h \ + nsTSubstringTuple.h \ + nsUTF8Utils.h \ + nsXPIDLString.h \ + string-template-def-unichar.h \ + string-template-def-char.h \ + string-template-undef.h \ + $(NULL) + +SDK_HEADERS = \ + nsStringAPI.h \ + nsEmbedString.h \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsAString.h new file mode 100644 index 00000000..3675989c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsAString.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsAString_h___ +#define nsAString_h___ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nsStringIterator_h___ +#include "nsStringIterator.h" +#endif + +#ifndef nsObsoleteAString_h___ +#include "nsObsoleteAString.h" +#endif + +// If some platform(s) can't handle our template that matches literal strings, +// then we'll disable it on those platforms. +#ifndef NS_DISABLE_LITERAL_TEMPLATE +# if (defined(_MSC_VER) && (_MSC_VER < 1310)) || (defined(__SUNPRO_CC) & (__SUNPRO_CC < 0x560)) || (defined(__HP_aCC) && (__HP_aCC <= 012100)) +# define NS_DISABLE_LITERAL_TEMPLATE +# endif +#endif /* !NS_DISABLE_LITERAL_TEMPLATE */ + +#include + + // declare nsAString +#include "string-template-def-unichar.h" +#include "nsTAString.h" +#include "string-template-undef.h" + + + // declare nsACString +#include "string-template-def-char.h" +#include "nsTAString.h" +#include "string-template-undef.h" + + + /** + * ASCII case-insensitive comparator. (for Unicode case-insensitive + * comparision, see nsUnicharUtils.h) + */ +class NS_COM nsCaseInsensitiveCStringComparator + : public nsCStringComparator + { + public: + typedef char char_type; + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const; + virtual int operator()( char_type, char_type ) const; + }; + + + // included here for backwards compatibility +#ifndef nsSubstringTuple_h___ +#include "nsSubstringTuple.h" +#endif + +#endif // !defined(nsAString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h b/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h new file mode 100644 index 00000000..e81e6f57 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsAlgorithm.h @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsAlgorithm_h___ +#define nsAlgorithm_h___ + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" + // for |nsCharSourceTraits|, |nsCharSinkTraits| +#endif + +#ifndef prtypes_h___ +#include "prtypes.h" + // for |PRUint32|... +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" + // for NS_ASSERTION +#endif + +template +inline +const T& +NS_MIN( const T& a, const T& b ) + { + return b < a ? b : a; + } + +template +inline +const T& +NS_MAX( const T& a, const T& b ) + { + return a > b ? a : b; + } + +template +inline +PRUint32 +NS_COUNT( InputIterator& first, const InputIterator& last, const T& value ) + { + PRUint32 result = 0; + for ( ; first != last; ++first ) + if ( *first == value ) + ++result; + return result; + } + +template +inline +OutputIterator& +copy_string( InputIterator& first, const InputIterator& last, OutputIterator& result ) + { + typedef nsCharSourceTraits source_traits; + typedef nsCharSinkTraits sink_traits; + + while ( first != last ) + { + PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last))); + NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate"); + source_traits::advance(first, count_copied); + } + + return result; + } + +template +OutputIterator& +copy_string_backward( const InputIterator& first, InputIterator& last, OutputIterator& result ) + { + while ( first != last ) + { + last.normalize_backward(); + result.normalize_backward(); + PRUint32 lengthToCopy = PRUint32( NS_MIN(last.size_backward(), result.size_backward()) ); + if ( first.fragment().mStart == last.fragment().mStart ) + lengthToCopy = NS_MIN(lengthToCopy, PRUint32(last.get() - first.get())); + + NS_ASSERTION(lengthToCopy, "|copy_string_backward| will never terminate"); + +#ifdef _MSC_VER + // XXX Visual C++ can't stomach 'typename' where it rightfully should + nsCharTraits::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy); +#else + nsCharTraits::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy); +#endif + + last.advance( -PRInt32(lengthToCopy) ); + result.advance( -PRInt32(lengthToCopy) ); + } + + return result; + } + +#endif // !defined(nsAlgorithm_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h b/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h new file mode 100644 index 00000000..e7713c95 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsCharTraits.h @@ -0,0 +1,784 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsCharTraits_h___ +#define nsCharTraits_h___ + +#include + // for |EOF|, |WEOF| + +#define FORCED_CPP_2BYTE_WCHAR_T + // disable special optimizations for now through this hack + +#if defined(HAVE_CPP_2BYTE_WCHAR_T) && !defined(FORCED_CPP_2BYTE_WCHAR_T) +#define USE_CPP_WCHAR_FUNCS +#endif + +#ifdef USE_CPP_WCHAR_FUNCS +#include + // for |wmemset|, et al +#endif + +#include + // for |memcpy|, et al + +#ifndef nscore_h___ +#include "nscore.h" + // for |PRUnichar| +#endif + +#ifndef nsDebug_h__ +#include "nsDebug.h" + // for NS_ASSERTION +#endif + +#ifdef HAVE_CPP_BOOL + typedef bool nsCharTraits_bool; +#else + typedef PRBool nsCharTraits_bool; +#endif + +template struct nsCharTraits {}; + +NS_SPECIALIZE_TEMPLATE +struct nsCharTraits + { + typedef PRUnichar char_type; + typedef PRUint16 unsigned_char_type; + typedef char incompatible_char_type; + + NS_COM static const char_type *sEmptyBuffer; + + static + void + assign( char_type& lhs, char_type rhs ) + { + lhs = rhs; + } + + + // integer representation of characters: + +#ifdef USE_CPP_WCHAR_FUNCS + typedef wint_t int_type; +#else + typedef int int_type; +#endif + + static + char_type + to_char_type( int_type c ) + { + return char_type(c); + } + + static + int_type + to_int_type( char_type c ) + { + return int_type( NS_STATIC_CAST(unsigned_char_type, c) ); + } + + static + nsCharTraits_bool + eq_int_type( int_type lhs, int_type rhs ) + { + return lhs == rhs; + } + + + // |char_type| comparisons: + + static + nsCharTraits_bool + eq( char_type lhs, char_type rhs ) + { + return lhs == rhs; + } + + static + nsCharTraits_bool + lt( char_type lhs, char_type rhs ) + { + return lhs < rhs; + } + + + // operations on s[n] arrays: + + static + char_type* + move( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copy( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copyASCII( char_type* s1, const char* s2, size_t n ) + { + for (char_type* s = s1; n--; ++s, ++s2) { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + *s = *s2; + } + return s1; + } + + static + char_type* + assign( char_type* s, size_t n, char_type c ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return NS_STATIC_CAST(char_type*, wmemset(s, to_int_type(c), n)); +#else + char_type* result = s; + while ( n-- ) + assign(*s++, c); + return result; +#endif + } + + static + int + compare( const char_type* s1, const char_type* s2, size_t n ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return wmemcmp(s1, s2, n); +#else + for ( ; n--; ++s1, ++s2 ) + { + if ( !eq(*s1, *s2) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + return 0; +#endif + } + + static + int + compareASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( !eq_int_type(to_int_type(*s1), to_int_type(*s2)) ) + return to_int_type(*s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + /** + * Convert c to its lower-case form, but only if the lower-case form is + * ASCII. Otherwise leave it alone. + * + * There are only two non-ASCII Unicode characters whose lowercase + * equivalents are ASCII: KELVIN SIGN and LATIN CAPITAL LETTER I WITH + * DOT ABOVE. So it's a simple matter to handle those explicitly. + */ + static + char_type + ASCIIToLower( char_type c ) + { + if (c < 0x100) + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; + else + { + if (c == 0x212A) // KELVIN SIGN + return 'k'; + if (c == 0x0130) // LATIN CAPITAL LETTER I WITH DOT ABOVE + return 'i'; + return c; + } + } + + static + int + compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != to_char_type(*s2) ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != to_char_type(*s2) ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + static + size_t + length( const char_type* s ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return wcslen(s); +#else + size_t result = 0; + while ( !eq(*s++, char_type(0)) ) + ++result; + return result; +#endif + } + + static + const char_type* + find( const char_type* s, size_t n, char_type c ) + { +#ifdef USE_CPP_WCHAR_FUNCS + return NS_REINTERPRET_CAST(const char_type*, wmemchr(s, to_int_type(c), n)); +#else + while ( n-- ) + { + if ( eq(*s, c) ) + return s; + ++s; + } + + return 0; +#endif + } + +#if 0 + // I/O related: + + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static + int_type + eof() + { +#ifdef USE_CPP_WCHAR_FUNCS + return WEOF; +#else + return EOF; +#endif + } + + static + int_type + not_eof( int_type c ) + { + return eq_int_type(c, eof()) ? ~eof() : c; + } + + // static state_type get_state( pos_type ); +#endif + }; + +NS_SPECIALIZE_TEMPLATE +struct nsCharTraits + { + typedef char char_type; + typedef unsigned char unsigned_char_type; + typedef PRUnichar incompatible_char_type; + + NS_COM static const char_type *sEmptyBuffer; + + static + void + assign( char_type& lhs, char_type rhs ) + { + lhs = rhs; + } + + + // integer representation of characters: + + typedef int int_type; + + static + char_type + to_char_type( int_type c ) + { + return char_type(c); + } + + static + int_type + to_int_type( char_type c ) + { + return int_type( NS_STATIC_CAST(unsigned_char_type, c) ); + } + + static + nsCharTraits_bool + eq_int_type( int_type lhs, int_type rhs ) + { + return lhs == rhs; + } + + + // |char_type| comparisons: + + static + nsCharTraits_bool + eq( char_type lhs, char_type rhs ) + { + return lhs == rhs; + } + + static + nsCharTraits_bool + lt( char_type lhs, char_type rhs ) + { + return lhs < rhs; + } + + + // operations on s[n] arrays: + + static + char_type* + move( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memmove(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copy( char_type* s1, const char_type* s2, size_t n ) + { + return NS_STATIC_CAST(char_type*, memcpy(s1, s2, n * sizeof(char_type))); + } + + static + char_type* + copyASCII( char_type* s1, const char* s2, size_t n ) + { + return copy(s1, s2, n); + } + + static + char_type* + assign( char_type* s, size_t n, char_type c ) + { + return NS_STATIC_CAST(char_type*, memset(s, to_int_type(c), n)); + } + + static + int + compare( const char_type* s1, const char_type* s2, size_t n ) + { + return memcmp(s1, s2, n); + } + + static + int + compareASCII( const char_type* s1, const char* s2, size_t n ) + { +#ifdef DEBUG + for (size_t i = 0; i < n; ++i) + { + NS_ASSERTION(!(s2[i] & ~0x7F), "Unexpected non-ASCII character"); + } +#endif + return compare(s1, s2, n); + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + // can't use strcmp here because we don't want to stop when s1 + // contains a null + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + if ( *s1 != *s2 ) + return to_int_type(*s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + /** + * Convert c to its lower-case form, but only if c is ASCII. + */ + static + char_type + ASCIIToLower( char_type c ) + { + return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c; + } + + static + int + compareLowerCaseToASCII( const char_type* s1, const char* s2, size_t n ) + { + for ( ; n--; ++s1, ++s2 ) + { + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != *s2 ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + return 0; + } + + // this version assumes that s2 is null-terminated and s1 has length n. + // if s1 is shorter than s2 then we return -1; if s1 is longer than s2, + // we return 1. + static + int + compareLowerCaseToASCIINullTerminated( const char_type* s1, size_t n, const char* s2 ) + { + for ( ; n--; ++s1, ++s2 ) + { + if ( !*s2 ) + return 1; + NS_ASSERTION(!(*s2 & ~0x7F), "Unexpected non-ASCII character"); + NS_ASSERTION(!(*s2 >= 'A' && *s2 <= 'Z'), + "Unexpected uppercase character"); + char_type lower_s1 = ASCIIToLower(*s1); + if ( lower_s1 != *s2 ) + return to_int_type(lower_s1) - to_int_type(*s2); + } + + if ( *s2 ) + return -1; + + return 0; + } + + static + size_t + length( const char_type* s ) + { + return strlen(s); + } + + static + const char_type* + find( const char_type* s, size_t n, char_type c ) + { + return NS_REINTERPRET_CAST(const char_type*, memchr(s, to_int_type(c), n)); + } + +#if 0 + // I/O related: + + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static + int_type + eof() + { + return EOF; + } + + static + int_type + not_eof( int_type c ) + { + return eq_int_type(c, eof()) ? ~eof() : c; + } + + // static state_type get_state( pos_type ); +#endif + }; + +template +struct nsCharSourceTraits + { + typedef typename InputIterator::difference_type difference_type; + + static + PRUint32 + readable_distance( const InputIterator& first, const InputIterator& last ) + { + // assumes single fragment + return last.get() - first.get(); + } + + static + const typename InputIterator::value_type* + read( const InputIterator& iter ) + { + return iter.get(); + } + + static + void + advance( InputIterator& s, difference_type n ) + { + s.advance(n); + } + }; + +#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION + +template +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( CharT* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( CharT* first, CharT* last ) + { + return PRUint32(last-first); + } + + static + const CharT* + read( CharT* s ) + { + return s; + } + + static + void + advance( CharT*& s, difference_type n ) + { + s += n; + } + }; + +#else + +NS_SPECIALIZE_TEMPLATE +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( const char* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( const char* first, const char* last ) + { + return PRUint32(last-first); + } + + static + const char* + read( const char* s ) + { + return s; + } + + static + void + advance( const char*& s, difference_type n ) + { + s += n; + } + }; + + +NS_SPECIALIZE_TEMPLATE +struct nsCharSourceTraits + { + typedef ptrdiff_t difference_type; + + static + PRUint32 + readable_distance( const PRUnichar* s ) + { + return PRUint32(nsCharTraits::length(s)); +// return numeric_limits::max(); + } + + static + PRUint32 + readable_distance( const PRUnichar* first, const PRUnichar* last ) + { + return PRUint32(last-first); + } + + static + const PRUnichar* + read( const PRUnichar* s ) + { + return s; + } + + static + void + advance( const PRUnichar*& s, difference_type n ) + { + s += n; + } + }; + +#endif + + +template +struct nsCharSinkTraits + { + static + PRUint32 + write( OutputIterator& iter, const typename OutputIterator::value_type* s, PRUint32 n ) + { + return iter.write(s, n); + } + }; + +#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION + +template +struct nsCharSinkTraits + { + static + PRUint32 + write( CharT*& iter, const CharT* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +#else + +NS_SPECIALIZE_TEMPLATE +struct nsCharSinkTraits + { + static + PRUint32 + write( char*& iter, const char* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +NS_SPECIALIZE_TEMPLATE +struct nsCharSinkTraits + { + static + PRUint32 + write( PRUnichar*& iter, const PRUnichar* s, PRUint32 n ) + { + nsCharTraits::move(iter, s, n); + iter += n; + return n; + } + }; + +#endif + +#endif // !defined(nsCharTraits_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h b/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h new file mode 100644 index 00000000..22e05b31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsDependentString.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsDependentString_h___ +#define nsDependentString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + + // declare nsDependentString +#include "string-template-def-unichar.h" +#include "nsTDependentString.h" +#include "string-template-undef.h" + + // declare nsDependentCString +#include "string-template-def-char.h" +#include "nsTDependentString.h" +#include "string-template-undef.h" + +#endif /* !defined(nsDependentString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h new file mode 100644 index 00000000..c6459436 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsDependentSubstring.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsDependentSubstring_h___ +#define nsDependentSubstring_h___ + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + + // declare nsDependentSubstring +#include "string-template-def-unichar.h" +#include "nsTDependentSubstring.h" +#include "string-template-undef.h" + + // declare nsDependentCSubstring +#include "string-template-def-char.h" +#include "nsTDependentSubstring.h" +#include "string-template-undef.h" + +#endif /* !defined(nsDependentSubstring_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h b/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h new file mode 100644 index 00000000..7af03ee3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsEmbedString.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 a small implementation of the nsAString and nsACString. + * + * The Initial Developer of the Original Code is + * Peter Annema . + * + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsEmbedString_h___ +#define nsEmbedString_h___ + +#include "nsStringAPI.h" + +class nsEmbedString : public nsStringContainer + { + public: + typedef nsEmbedString self_type; + typedef nsAString abstract_string_type; + + nsEmbedString() + { + NS_StringContainerInit(*this); + } + + nsEmbedString(const self_type& aString) +#ifdef VBOX + : nsStringContainer() +#endif + { + NS_StringContainerInit(*this); + NS_StringCopy(*this, aString); + } + + explicit + nsEmbedString(const abstract_string_type& aReadable) + { + NS_StringContainerInit(*this); + NS_StringCopy(*this, aReadable); + } + + explicit + nsEmbedString(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_StringContainerInit(*this); + NS_StringSetData(*this, aData, aLength); + } + + ~nsEmbedString() + { + NS_StringContainerFinish(*this); + } + + const char_type* get() const + { + const char_type* data; + NS_StringGetData(*this, &data); + return data; + } + + self_type& operator=(const self_type& aString) { Assign(aString); return *this; } + self_type& operator=(const abstract_string_type& aReadable) { Assign(aReadable); return *this; } + self_type& operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + self_type& operator=(char_type aChar) { Assign(aChar); return *this; } + }; + +class nsEmbedCString : public nsCStringContainer + { + public: + typedef nsEmbedCString self_type; + typedef nsACString abstract_string_type; + + nsEmbedCString() +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + } + + nsEmbedCString(const self_type& aString) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringCopy(*this, aString); + } + + explicit + nsEmbedCString(const abstract_string_type& aReadable) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringCopy(*this, aReadable); + } + + explicit + nsEmbedCString(const char_type* aData, size_type aLength = PR_UINT32_MAX) +#ifdef VBOX + : nsCStringContainer() +#endif + { + NS_CStringContainerInit(*this); + NS_CStringSetData(*this, aData, aLength); + } + + ~nsEmbedCString() + { + NS_CStringContainerFinish(*this); + } + + const char_type* get() const + { + const char_type* data; + NS_CStringGetData(*this, &data); + return data; + } + + self_type& operator=(const self_type& aString) { Assign(aString); return *this; } + self_type& operator=(const abstract_string_type& aReadable) { Assign(aReadable); return *this; } + self_type& operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + self_type& operator=(char_type aChar) { Assign(aChar); return *this; } + }; + +#endif // !defined(nsEmbedString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h b/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h new file mode 100644 index 00000000..ba536297 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsLiteralString.h @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsLiteralString_h___ +#define nsLiteralString_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + +#ifndef nsDependentString_h___ +#include "nsDependentString.h" +#endif + + +#if 0 +inline +const nsDependentString +literal_string( const nsAString::char_type* aPtr ) + { + return nsDependentString(aPtr); + } + +inline +const nsDependentString +literal_string( const nsAString::char_type* aPtr, PRUint32 aLength ) + { + return nsDependentString(aPtr, aLength); + } + +inline +const nsDependentCString +literal_string( const nsACString::char_type* aPtr ) + { + return nsDependentCString(aPtr); + } + +inline +const nsDependentCString +literal_string( const nsACString::char_type* aPtr, PRUint32 aLength ) + { + return nsDependentCString(aPtr, aLength); + } +#endif + +#ifdef HAVE_CPP_2BYTE_WCHAR_T + #define NS_LL(s) L##s + #define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + #define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const nsDependentString n(NS_REINTERPRET_CAST(const nsAString::char_type*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1)) + typedef nsDependentString nsLiteralString; +#else + #define NS_LL(s) s + #define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUTF16(s, PRUint32(sizeof(s)-1)) + #define NS_MULTILINE_LITERAL_STRING_INIT(n,s) n(s, PRUint32(sizeof(s)-1)) + #define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) const NS_ConvertASCIItoUTF16 n(s, PRUint32(sizeof(s)-1)) + typedef NS_ConvertASCIItoUTF16 nsLiteralString; +#endif + +/* + * Macro arguments used in concatenation or stringification won't be expanded. + * Therefore, in order for |NS_L(FOO)| to work as expected (which is to expand + * |FOO| before doing whatever |NS_L| needs to do to it) a helper macro needs + * to be inserted in between to allow the macro argument to expand. + * See "3.10.6 Separate Expansion of Macro Arguments" of the CPP manual for a + * more accurate and precise explanation. + */ + +#define NS_L(s) NS_LL(s) + +#define NS_LITERAL_STRING(s) NS_STATIC_CAST(const nsAFlatString&, NS_MULTILINE_LITERAL_STRING(NS_LL(s))) +#define NS_LITERAL_STRING_INIT(n,s) NS_MULTILINE_LITERAL_STRING_INIT(n, NS_LL(s)) +#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n, NS_LL(s)) + +#define NS_LITERAL_CSTRING(s) NS_STATIC_CAST(const nsDependentCString&, nsDependentCString(s, PRUint32(sizeof(s)-1))) +#define NS_LITERAL_CSTRING_INIT(n,s) n(s, PRUint32(sizeof(s)-1)) +#define NS_NAMED_LITERAL_CSTRING(n,s) const nsDependentCString n(s, PRUint32(sizeof(s)-1)) + +typedef nsDependentCString nsLiteralCString; + +#endif /* !defined(nsLiteralString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h new file mode 100644 index 00000000..00d5892e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsObsoleteAString.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsObsoleteAString_h___ +#define nsObsoleteAString_h___ + +/* + STRING INTERNALS + + This file defines nsObsoleteAString and nsObsoleteACString. These are + abstract classes (interfaces), containing only virtual functions + corresponding to the FROZEN nsA[C]String classes. They exist to provide + the new non-abstract nsA[C]String classes with a mechanism to maintain + backwards binary compatability. + + From a binary point-of-view, the new nsA[C]String classes appear to have a + vtable pointer to the vtable of nsObsoleteA[C]StringThunk. + nsObsoleteA[C]StringThunk is a subclass of nsObsoleteA[C]String that serves + as a simple bridge between the virtual functions that make up the FROZEN + nsA[C]String contract and the new ns[C]Substring, which is now our only + subclass of nsA[C]String. + + The methods on the new nsA[C]String are now all non-virtual. This reduces + codesize at the callsite, and reduces the number of memory dereferences and + jumps required to invoke a method on nsA[C]String. The result is improved + performance and reduced codesize. However, to maintain binary + compatibility, each method on nsA[C]String must check the value of its + vtable to determine if it corresponds to the built-in implementation of + nsObsoleteA[C]String (i.e., the address of the canonical vtable). If it + does, then the vtable can be ignored, and the nsA[C]String object (i.e., + |this|) can be cast to ns[C]Substring directly. In which case, the + nsA[C]String methods can be satisfied by invoking the corresponding methods + directly on ns[C]Substring. If the vtable address does not correspond to + the built-in implementation, then the virtual functions on + nsObsoleteA[C]String must be invoked instead. + + So, if a nsA[C]String reference corresponds to an external implementation + (such as the old nsEmbed[C]String that shipped with previous versions of + Mozilla), then methods invoked on that nsA[C]String will still act like + virtual function calls. This ensures binary compatibility while avoiding + virtual function calls in most cases. + + Finally, nsObsoleteA[C]String (i.e., the FROZEN nsA[C]String vtable) is + now a DEPRECATED interface. See nsStringAPI.h and nsEmbedString.h for + the new preferred way to access nsA[C]String references in an external + component or Gecko embedding application. + */ + +#ifndef nsStringFwd_h___ +#include "nsStringFwd.h" +#endif + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + // declare nsObsoleteAString +#include "string-template-def-unichar.h" +#include "nsTObsoleteAString.h" +#include "string-template-undef.h" + + // declare nsObsoleteACString +#include "string-template-def-char.h" +#include "nsTObsoleteAString.h" +#include "string-template-undef.h" + +#endif // !defined(nsObsoleteAString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h b/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h new file mode 100644 index 00000000..3f3d04d3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsPrintfCString.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsPrintfCString_h___ +#define nsPrintfCString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + + + /** + * |nsPrintfCString| lets you use a formated |printf| string as an |const nsACString|. + * + * myCStr += nsPrintfCString("%f", 13.917); + * // ...a general purpose substitute for |AppendFloat| + * + * For longer patterns, you'll want to use the constructor that takes a length + * + * nsPrintfCString(128, "%f, %f, %f, %f, %f, %f, %f, %i, %f", x, y, z, 3.2, j, k, l, 3, 3.1); + * + * Exceding the default size (which you must specify in the constructor, it is not determined) + * causes an allocation, so avoid that. If your formatted string exceeds the allocated space, it is + * cut off at the size of the buffer, no error is reported (and no out-of-bounds writing occurs). + * This class is intended to be useful for numbers and short + * strings, not arbitrary formatting of other strings (e.g., with %s). There is currently no + * wide version of this class, since wide |printf| is not generally available. That means + * to get a wide version of your formatted data, you must, e.g., + * + * CopyASCIItoUTF16(nsPrintfCString("%f", 13.917"), myStr); + * + * That's another good reason to avoid this class for anything but numbers ... as strings can be + * much more efficiently handled with |NS_LITERAL_[C]STRING| and |nsLiteral[C]String|. + */ + +class NS_COM nsPrintfCString : public nsCString + { + typedef nsCString string_type; + + enum { kLocalBufferSize=15 }; + // ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask) + // pinkerton suggests 7. We should measure and decide what's appropriate + + public: + // XXX don't these need to be declared CDECL ?? + explicit nsPrintfCString( const char_type* format, ... ); + nsPrintfCString( size_type n, const char_type* format, ...); + + private: + char_type mLocalBuffer[ kLocalBufferSize + 1 ]; + }; + +#endif // !defined(nsPrintfCString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h b/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h new file mode 100644 index 00000000..b98aa1a2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsPromiseFlatString.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsPromiseFlatString_h___ +#define nsPromiseFlatString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + + // declare nsPromiseFlatString +#include "string-template-def-unichar.h" +#include "nsTPromiseFlatString.h" +#include "string-template-undef.h" + + // declare nsPromiseFlatCString +#include "string-template-def-char.h" +#include "nsTPromiseFlatString.h" +#include "string-template-undef.h" + +#endif /* !defined(nsPromiseFlatString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h b/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h new file mode 100644 index 00000000..13f94c09 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsReadableUtils.h @@ -0,0 +1,370 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Johnny Stenbeck + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsReadableUtils_h___ +#define nsReadableUtils_h___ + + /** + * I guess all the routines in this file are all mis-named. + * According to our conventions, they should be |NS_xxx|. + */ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +inline size_t Distance( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return end.get() - start.get(); + } +inline size_t Distance( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return end.get() - start.get(); + } + +NS_COM void LossyCopyUTF16toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void LossyCopyUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void CopyASCIItoUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void CopyUTF16toUTF8( const nsAString& aSource, nsACString& aDest ); +NS_COM void CopyUTF8toUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void CopyUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void CopyUTF8toUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void LossyAppendUTF16toASCII( const nsAString& aSource, nsACString& aDest ); +NS_COM void AppendASCIItoUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void LossyAppendUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void AppendASCIItoUTF16( const char* aSource, nsAString& aDest ); + +NS_COM void AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest ); +NS_COM void AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest ); + +NS_COM void AppendUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ); +NS_COM void AppendUTF8toUTF16( const char* aSource, nsAString& aDest ); + +// Backward compatibility +inline +NS_COM void CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest ) +{ LossyCopyUTF16toASCII(aSource, aDest); } +inline +NS_COM void CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest ) +{ CopyASCIItoUTF16(aSource, aDest); } + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|. + * Performs a lossy encoding conversion by chopping 16-bit wide characters down to 8-bits wide while copying |aSource| to your new buffer. + * This conversion is not well defined; but it reproduces legacy string behavior. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource a 16-bit wide string + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ +NS_COM char* ToNewCString( const nsAString& aSource ); + + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ +NS_COM char* ToNewCString( const nsACString& aSource ); + + /** + * Returns a new |char| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with + * |nsMemory::Free|. + * Performs an encoding conversion from a UTF-16 string to a UTF-8 string + * copying |aSource| to your new buffer. + * The new buffer is zero-terminated, but that may not help you if |aSource| + * contains embedded nulls. + * + * @param aSource a UTF-16 string (made of PRUnichar's) + * @param aUTF8Count the number of 8-bit units that was returned + * @return a new |char| buffer you must free with |nsMemory::Free|. + */ + +NS_COM char* ToNewUTF8String( const nsAString& aSource, PRUint32 *aUTF8Count = nsnull ); + + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy of + * |aSource|. + * + * Allocates and returns a new |PRUnichar| buffer which you must free with + * |nsMemory::Free|. + * The new buffer is zero-terminated, but that may not help you if |aSource| + * contains embedded nulls. + * + * @param aSource a UTF-16 string + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + */ +NS_COM PRUnichar* ToNewUnicode( const nsAString& aSource ); + + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy of |aSource|. + * + * Allocates and returns a new |PRUnichar| buffer which you must free with |nsMemory::Free|. + * Performs an encoding conversion by 0-padding 8-bit wide characters up to 16-bits wide while copying |aSource| to your new buffer. + * This conversion is not well defined; but it reproduces legacy string behavior. + * The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string (a C-string, NOT UTF-8) + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + */ +NS_COM PRUnichar* ToNewUnicode( const nsACString& aSource ); + + /** + * Returns a new |PRUnichar| buffer containing a zero-terminated copy + * of |aSource|. + * + * Allocates and returns a new |char| buffer which you must free with + * |nsMemory::Free|. Performs an encoding conversion from UTF-8 to UTF-16 + * while copying |aSource| to your new buffer. This conversion is well defined + * for a valid UTF-8 string. The new buffer is zero-terminated, but that + * may not help you if |aSource| contains embedded nulls. + * + * @param aSource an 8-bit wide string, UTF-8 encoded + * @param aUTF16Count the number of 16-bit units that was returned + * @return a new |PRUnichar| buffer you must free with |nsMemory::Free|. + * (UTF-16 encoded) + */ +NS_COM PRUnichar* UTF8ToNewUnicode( const nsACString& aSource, PRUint32 *aUTF16Count = nsnull ); + + /** + * Copies |aLength| 16-bit code units from the start of |aSource| to the + * |PRUnichar| buffer |aDest|. + * + * After this operation |aDest| is not null terminated. + * + * @param aSource a UTF-16 string + * @param aSrcOffset start offset in the source string + * @param aDest a |PRUnichar| buffer + * @param aLength the number of 16-bit code units to copy + * @return pointer to destination buffer - identical to |aDest| + */ +NS_COM PRUnichar* CopyUnicodeTo( const nsAString& aSource, + PRUint32 aSrcOffset, + PRUnichar* aDest, + PRUint32 aLength ); + + + /** + * Copies 16-bit characters between iterators |aSrcStart| and + * |aSrcEnd| to the writable string |aDest|. Similar to the + * |nsString::Mid| method. + * + * After this operation |aDest| is not null terminated. + * + * @param aSrcStart start source iterator + * @param aSrcEnd end source iterator + * @param aDest destination for the copy + */ +NS_COM void CopyUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ); + + /** + * Appends 16-bit characters between iterators |aSrcStart| and + * |aSrcEnd| to the writable string |aDest|. + * + * After this operation |aDest| is not null terminated. + * + * @param aSrcStart start source iterator + * @param aSrcEnd end source iterator + * @param aDest destination for the copy + */ +NS_COM void AppendUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ); + + /** + * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). + * + * @param aString a 16-bit wide string to scan + */ +NS_COM PRBool IsASCII( const nsAString& aString ); + + /** + * Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F). + * + * @param aString a 8-bit wide string to scan + */ +NS_COM PRBool IsASCII( const nsACString& aString ); + + + /** + * Returns |PR_TRUE| if |aString| is a valid UTF-8 string. + * XXX This is not bullet-proof and nor an all-purpose UTF-8 validator. + * It is mainly written to replace and roughly equivalent to + * + * str.Equals(NS_ConvertUTF16toUTF8(NS_ConvertUTF8toUTF16(str))) + * + * (see bug 191541) + * As such, it does not check for non-UTF-8 7bit encodings such as + * ISO-2022-JP and HZ. However, it filters out UTF-8 representation + * of surrogate codepoints and non-characters ( 0xFFFE and 0xFFFF + * in planes 0 through 16.) as well as overlong UTF-8 sequences. + * Also note that it regards UTF-8 sequences corresponding to + * codepoints above 0x10FFFF as invalid in accordance with + * http://www.ietf.org/internet-drafts/draft-yergeau-rfc2279bis-04.txt + * + * @param aString an 8-bit wide string to scan + */ +NS_COM PRBool IsUTF8( const nsACString& aString ); + + + /** + * Converts case in place in the argument string. + */ +NS_COM void ToUpperCase( nsACString& ); + +NS_COM void ToLowerCase( nsACString& ); + +NS_COM void ToUpperCase( nsCSubstring& ); + +NS_COM void ToLowerCase( nsCSubstring& ); + + /** + * Converts case from string aSource to aDest. + */ +NS_COM void ToUpperCase( const nsACString& aSource, nsACString& aDest ); + +NS_COM void ToLowerCase( const nsACString& aSource, nsACString& aDest ); + + /** + * Finds the leftmost occurance of |aPattern|, if any in the range |aSearchStart|..|aSearchEnd|. + * + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to + * point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|. + * + * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. + * If we need something faster, then we can implement that later. + */ + +NS_COM PRBool FindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator&, const nsStringComparator& = nsDefaultStringComparator() ); +NS_COM PRBool FindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator&, const nsCStringComparator& = nsDefaultCStringComparator() ); + +/* sometimes we don't care about where the string was, just that we + * found it or not */ +inline PRBool FindInReadable( const nsAString& aPattern, const nsAString& aSource, const nsStringComparator& compare = nsDefaultStringComparator() ) +{ + nsAString::const_iterator start, end; + aSource.BeginReading(start); + aSource.EndReading(end); + return FindInReadable(aPattern, start, end, compare); +} + +inline PRBool FindInReadable( const nsACString& aPattern, const nsACString& aSource, const nsCStringComparator& compare = nsDefaultCStringComparator() ) +{ + nsACString::const_iterator start, end; + aSource.BeginReading(start); + aSource.EndReading(end); + return FindInReadable(aPattern, start, end, compare); +} + + +NS_COM PRBool CaseInsensitiveFindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator& ); + + /** + * Finds the rightmost occurance of |aPattern| + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to + * point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|. + * + * Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|. + * If we need something faster, then we can implement that later. + */ +NS_COM PRBool RFindInReadable( const nsAString& aPattern, nsAString::const_iterator&, nsAString::const_iterator&, const nsStringComparator& = nsDefaultStringComparator() ); +NS_COM PRBool RFindInReadable( const nsACString& aPattern, nsACString::const_iterator&, nsACString::const_iterator&, const nsCStringComparator& = nsDefaultCStringComparator() ); + + /** + * Finds the leftmost occurance of |aChar|, if any in the range + * |aSearchStart|..|aSearchEnd|. + * + * Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| to + * point to the match. If no match was found, returns |PR_FALSE| and + * makes |aSearchStart == aSearchEnd|. + */ +NS_COM PRBool FindCharInReadable( PRUnichar aChar, nsAString::const_iterator& aSearchStart, const nsAString::const_iterator& aSearchEnd ); +NS_COM PRBool FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd ); + + /** + * Finds the number of occurences of |aChar| in the string |aStr| + */ +NS_COM PRUint32 CountCharInReadable( const nsAString& aStr, + PRUnichar aChar ); +NS_COM PRUint32 CountCharInReadable( const nsACString& aStr, + char aChar ); + +NS_COM PRBool +StringBeginsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator = + nsDefaultStringComparator() ); +NS_COM PRBool +StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator = + nsDefaultCStringComparator() ); +NS_COM PRBool +StringEndsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator = + nsDefaultStringComparator() ); +NS_COM PRBool +StringEndsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator = + nsDefaultCStringComparator() ); + +NS_COM PRUint32 HashString( const nsAString& aStr ); +NS_COM PRUint32 HashString( const nsACString& aStr ); + +NS_COM const nsAFlatString& EmptyString(); +NS_COM const nsAFlatCString& EmptyCString(); + + +#endif // !defined(nsReadableUtils_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsString.h b/src/libs/xpcom18a4/xpcom/string/public/nsString.h new file mode 100644 index 00000000..67376d19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsString.h @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsString_h___ +#define nsString_h___ + + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + +#ifndef nsDependentSubstring_h___ +#include "nsDependentSubstring.h" +#endif + +#ifndef nsReadableUtils_h___ +#include "nsReadableUtils.h" +#endif + +#include NEW_H + + // enable support for the obsolete string API if not explicitly disabled +#ifndef MOZ_STRING_WITH_OBSOLETE_API +#define MOZ_STRING_WITH_OBSOLETE_API 1 +#endif + +#if MOZ_STRING_WITH_OBSOLETE_API + // radix values for ToInteger/AppendInt +#define kRadix10 (10) +#define kRadix16 (16) +#define kAutoDetect (100) +#define kRadixUnknown (kAutoDetect+1) +#define IGNORE_CASE (PR_TRUE) +#endif + + + // declare nsString, et. al. +#include "string-template-def-unichar.h" +#include "nsTString.h" +#include "string-template-undef.h" + + // declare nsCString, et. al. +#include "string-template-def-char.h" +#include "nsTString.h" +#include "string-template-undef.h" + + + /** + * A helper class that converts a UTF-16 string to ASCII in a lossy manner + */ +class NS_LossyConvertUTF16toASCII : public nsCAutoString + { + public: + explicit + NS_LossyConvertUTF16toASCII( const PRUnichar* aString ) + { + LossyAppendUTF16toASCII(aString, *this); + } + + NS_LossyConvertUTF16toASCII( const PRUnichar* aString, PRUint32 aLength ) + { + LossyAppendUTF16toASCII(Substring(aString, aString + aLength), *this); + } + + explicit + NS_LossyConvertUTF16toASCII( const nsAString& aString ) + { + LossyAppendUTF16toASCII(aString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_LossyConvertUTF16toASCII( char ); + }; + + +class NS_ConvertASCIItoUTF16 : public nsAutoString + { + public: + explicit + NS_ConvertASCIItoUTF16( const char* aCString ) + { + AppendASCIItoUTF16(aCString, *this); + } + + NS_ConvertASCIItoUTF16( const char* aCString, PRUint32 aLength ) + { + AppendASCIItoUTF16(Substring(aCString, aCString + aLength), *this); + } + + explicit + NS_ConvertASCIItoUTF16( const nsACString& aCString ) + { + AppendASCIItoUTF16(aCString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertASCIItoUTF16( PRUnichar ); + }; + + + /** + * A helper class that converts a UTF-16 string to UTF-8 + */ +class NS_ConvertUTF16toUTF8 : public nsCAutoString + { + public: + explicit + NS_ConvertUTF16toUTF8( const PRUnichar* aString ) + { + AppendUTF16toUTF8(aString, *this); + } + + NS_ConvertUTF16toUTF8( const PRUnichar* aString, PRUint32 aLength ) + { + AppendUTF16toUTF8(Substring(aString, aString + aLength), *this); + } + + explicit + NS_ConvertUTF16toUTF8( const nsAString& aString ) + { + AppendUTF16toUTF8(aString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertUTF16toUTF8( char ); + }; + + +class NS_ConvertUTF8toUTF16 : public nsAutoString + { + public: + explicit + NS_ConvertUTF8toUTF16( const char* aCString ) + { + AppendUTF8toUTF16(aCString, *this); + } + + NS_ConvertUTF8toUTF16( const char* aCString, PRUint32 aLength ) + { + AppendUTF8toUTF16(Substring(aCString, aCString + aLength), *this); + } + + explicit + NS_ConvertUTF8toUTF16( const nsACString& aCString ) + { + AppendUTF8toUTF16(aCString, *this); + } + + private: + // NOT TO BE IMPLEMENTED + NS_ConvertUTF8toUTF16( PRUnichar ); + }; + + +// the following are included/declared for backwards compatibility + +typedef NS_ConvertUTF16toUTF8 NS_ConvertUCS2toUTF8; +typedef NS_LossyConvertUTF16toASCII NS_LossyConvertUCS2toASCII; +typedef NS_ConvertASCIItoUTF16 NS_ConvertASCIItoUCS2; +typedef NS_ConvertUTF8toUTF16 NS_ConvertUTF8toUCS2; +typedef nsAutoString nsVoidableString; + +#ifndef nsDependentString_h___ +#include "nsDependentString.h" +#endif + +#ifndef nsLiteralString_h___ +#include "nsLiteralString.h" +#endif + +#ifndef nsPromiseFlatString_h___ +#include "nsPromiseFlatString.h" +#endif + +// need to include these for backwards compatibility +#include "nsMemory.h" +#include +#include +#include "plhash.h" + +inline PRInt32 MinInt(PRInt32 x, PRInt32 y) + { + return NS_MIN(x, y); + } + +inline PRInt32 MaxInt(PRInt32 x, PRInt32 y) + { + return NS_MAX(x, y); + } + +/** + * Deprecated: don't use |Recycle|, just call |nsMemory::Free| directly + * + * Return the given buffer to the heap manager. Calls allocator::Free() + */ +inline void Recycle( char* aBuffer) { nsMemory::Free(aBuffer); } +inline void Recycle( PRUnichar* aBuffer) { nsMemory::Free(aBuffer); } + +#endif // !defined(nsString_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h new file mode 100644 index 00000000..cc0818b6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringAPI.h @@ -0,0 +1,853 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsStringAPI_h__ +#define nsStringAPI_h__ + +/** + * nsStringAPI.h + * + * This file describes a minimal API for working with XPCOM's abstract + * string classes. It divorces the consumer from having any run-time + * dependency on the implementation details of the abstract string types. + */ + +#include "nscore.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define NS_CStringContainerInit VBoxNsxpNS_CStringContainerInit +#define NS_CStringContainerFinish VBoxNsxpNS_CStringContainerFinish +#define NS_CStringCloneData VBoxNsxpNS_CStringCloneData +#define NS_CStringCopy VBoxNsxpNS_CStringCopy +#define NS_CStringGetData VBoxNsxpNS_CStringGetData +#define NS_CStringSetData VBoxNsxpNS_CStringSetData +#define NS_CStringSetDataRange VBoxNsxpNS_CStringSetDataRange +#define NS_UTF16ToCString VBoxNsxpNS_UTF16ToCString +#define NS_CStringToUTF16 VBoxNsxpNS_CStringToUTF16 +#define NS_StringContainerInit VBoxNsxpNS_StringContainerInit +#define NS_StringContainerFinish VBoxNsxpNS_StringContainerFinish +#define NS_StringCloneData VBoxNsxpNS_StringCloneData +#define NS_StringCopy VBoxNsxpNS_StringCopy +#define NS_StringGetData VBoxNsxpNS_StringGetData +#define NS_StringSetData VBoxNsxpNS_StringSetData +#define NS_StringSetDataRange VBoxNsxpNS_StringSetDataRange +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +#define NS_STRINGAPI(x) extern "C" NS_COM x + +/* The base string types */ +class nsAString; +class nsACString; + +/* ------------------------------------------------------------------------- */ + +/** + * nsStringContainer + * + * This is an opaque data type that is large enough to hold the canonical + * implementation of nsAString. The binary structure of this class is an + * implementation detail. + * + * The string data stored in a string container is always single fragment + * and null-terminated. + * + * Typically, string containers are allocated on the stack for temporary + * use. However, they can also be malloc'd if necessary. In either case, + * a string container is not useful until it has been initialized with a + * call to NS_StringContainerInit. The following example shows how to use + * a string container to call a function that takes a |nsAString &| out-param. + * + * NS_METHOD GetBlah(nsAString &aBlah); + * + * nsresult MyCode() + * { + * nsresult rv; + * + * nsStringContainer sc; + * rv = NS_StringContainerInit(sc); + * if (NS_FAILED(rv)) + * return rv; + * + * rv = GetBlah(sc); + * if (NS_SUCCEEDED(rv)) + * { + * const PRUnichar *data; + * NS_StringGetData(sc, &data); + * // + * // |data| now points to the result of the GetBlah function + * // + * } + * + * NS_StringContainerFinish(sc); + * return rv; + * } + * + * The following example show how to use a string container to pass a string + * parameter to a function taking a |const nsAString &| in-param. + * + * NS_METHOD SetBlah(const nsAString &aBlah); + * + * nsresult MyCode() + * { + * nsresult rv; + * + * nsStringContainer sc; + * rv = NS_StringContainerInit(sc); + * if (NS_FAILED(rv)) + * return rv; + * + * const PRUnichar kData[] = {'x','y','z','\0'}; + * rv = NS_StringSetData(sc, kData, sizeof(kData)/2 - 1); + * if (NS_SUCCEEDED(rv)) + * rv = SetBlah(sc); + * + * NS_StringContainerFinish(sc); + * return rv; + * } + */ +class nsStringContainer; + +/** + * NS_StringContainerInit + * + * @param aContainer string container reference + * @return NS_OK if string container successfully initialized + * + * This function may allocate additional memory for aContainer. When + * aContainer is no longer needed, NS_StringContainerFinish should be called. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer); + +/** + * NS_StringContainerFinish + * + * @param aContainer string container reference + * + * This function frees any memory owned by aContainer. + * + * @status FROZEN + */ +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer); + +/* ------------------------------------------------------------------------- */ + +/** + * NS_StringGetData + * + * This function returns a const character pointer to the string's internal + * buffer, the length of the string, and a boolean value indicating whether + * or not the buffer is null-terminated. + * + * @param aStr abstract string reference + * @param aData out param that will hold the address of aStr's + * internal buffer + * @param aTerminated if non-null, this out param will be set to indicate + * whether or not aStr's internal buffer is null- + * terminated + * @return length of aStr's internal buffer + * + * @status FROZEN + */ +NS_STRINGAPI(PRUint32) +NS_StringGetData + (const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated = nsnull); + +/** + * NS_StringCloneData + * + * This function returns a null-terminated copy of the string's + * internal buffer. + * + * @param aStr abstract string reference + * @return null-terminated copy of the string's internal buffer + * (it must be free'd using using nsMemory::Free) + * + * @status FROZEN + */ +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData + (const nsAString &aStr); + +/** + * NS_StringSetData + * + * This function copies aData into aStr. + * + * @param aStr abstract string reference + * @param aData character buffer + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringSetData + (nsAString &aStr, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_StringSetDataRange + * + * This function copies aData into a section of aStr. As a result it can be + * used to insert new characters into the string. + * + * @param aStr abstract string reference + * @param aCutOffset starting index where the string's existing data + * is to be overwritten (pass PR_UINT32_MAX to cause + * aData to be appended to the end of aStr, in which + * case the value of aCutLength is ignored). + * @param aCutLength number of characters to overwrite starting at + * aCutOffset (pass PR_UINT32_MAX to overwrite until the + * end of aStr). + * @param aData character buffer (pass null to cause this function + * to simply remove the "cut" range) + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringSetDataRange + (nsAString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_StringCopy + * + * This function makes aDestStr have the same value as aSrcStr. It is + * provided as an optimization. + * + * @param aDestStr abstract string reference to be modified + * @param aSrcStr abstract string reference containing source string + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aDestStr after copying + * data from aSrcStr. The behavior depends on the implementation of the + * abstract string, aDestStr. If aDestStr is a reference to a + * nsStringContainer, then its data will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_StringCopy + (nsAString &aDestStr, const nsAString &aSrcStr); + +/** + * NS_StringAppendData + * + * This function appends data to the existing value of aStr. + * + * @param aStr abstract string reference to be modified + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_StringAppendData(nsAString &aStr, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_StringSetDataRange(aStr, PR_UINT32_MAX, 0, aData, aDataLength); +} + +/** + * NS_StringInsertData + * + * This function inserts data into the existing value of aStr at the specified + * offset. + * + * @param aStr abstract string reference to be modified + * @param aOffset specifies where in the string to insert aData + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_StringInsertData(nsAString &aStr, PRUint32 aOffset, const PRUnichar *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_StringSetDataRange(aStr, aOffset, 0, aData, aDataLength); +} + +/** + * NS_StringCutData + * + * This function shortens the existing value of aStr, by removing characters + * at the specified offset. + * + * @param aStr abstract string reference to be modified + * @param aCutOffset specifies where in the string to insert aData + * @param aCutLength number of characters to remove + * @return NS_OK if function succeeded + */ +inline NS_HIDDEN_(nsresult) +NS_StringCutData(nsAString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength) +{ + return NS_StringSetDataRange(aStr, aCutOffset, aCutLength, nsnull, 0); +} + +/* ------------------------------------------------------------------------- */ + +/** + * nsCStringContainer + * + * This is an opaque data type that is large enough to hold the canonical + * implementation of nsACString. The binary structure of this class is an + * implementation detail. + * + * The string data stored in a string container is always single fragment + * and null-terminated. + * + * @see nsStringContainer for use cases and further documentation. + */ +class nsCStringContainer; + +/** + * NS_CStringContainerInit + * + * @param aContainer string container reference + * @return NS_OK if string container successfully initialized + * + * This function may allocate additional memory for aContainer. When + * aContainer is no longer needed, NS_CStringContainerFinish should be called. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer); + +/** + * NS_CStringContainerFinish + * + * @param aContainer string container reference + * + * This function frees any memory owned by aContainer. + * + * @status FROZEN + */ +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer); + +/* ------------------------------------------------------------------------- */ + +/** + * NS_CStringGetData + * + * This function returns a const character pointer to the string's internal + * buffer, the length of the string, and a boolean value indicating whether + * or not the buffer is null-terminated. + * + * @param aStr abstract string reference + * @param aData out param that will hold the address of aStr's + * internal buffer + * @param aTerminated if non-null, this out param will be set to indicate + * whether or not aStr's internal buffer is null- + * terminated + * @return length of aStr's internal buffer + * + * @status FROZEN + */ +NS_STRINGAPI(PRUint32) +NS_CStringGetData + (const nsACString &aStr, const char **aData, + PRBool *aTerminated = nsnull); + +/** + * NS_CStringCloneData + * + * This function returns a null-terminated copy of the string's + * internal buffer. + * + * @param aStr abstract string reference + * @return null-terminated copy of the string's internal buffer + * (it must be free'd using using nsMemory::Free) + * + * @status FROZEN + */ +NS_STRINGAPI(char *) +NS_CStringCloneData + (const nsACString &aStr); + +/** + * NS_CStringSetData + * + * This function copies aData into aStr. + * + * @param aStr abstract string reference + * @param aData character buffer + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringSetData + (nsACString &aStr, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_CStringSetDataRange + * + * This function copies aData into a section of aStr. As a result it can be + * used to insert new characters into the string. + * + * @param aStr abstract string reference + * @param aCutOffset starting index where the string's existing data + * is to be overwritten (pass PR_UINT32_MAX to cause + * aData to be appended to the end of aStr, in which + * case the value of aCutLength is ignored). + * @param aCutLength number of characters to overwrite starting at + * aCutOffset (pass PR_UINT32_MAX to overwrite until the + * end of aStr). + * @param aData character buffer (pass null to cause this function + * to simply remove the "cut" range) + * @param aDataLength number of characters to copy from source string (pass + * PR_UINT32_MAX to copy until end of aData, designated by + * a null character) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr after copying data + * from aData. The behavior depends on the implementation of the abstract + * string, aStr. If aStr is a reference to a nsStringContainer, then its data + * will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange + (nsACString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength = PR_UINT32_MAX); + +/** + * NS_CStringCopy + * + * This function makes aDestStr have the same value as aSrcStr. It is + * provided as an optimization. + * + * @param aDestStr abstract string reference to be modified + * @param aSrcStr abstract string reference containing source string + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aDestStr after copying + * data from aSrcStr. The behavior depends on the implementation of the + * abstract string, aDestStr. If aDestStr is a reference to a + * nsStringContainer, then its data will be null-terminated by this function. + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringCopy + (nsACString &aDestStr, const nsACString &aSrcStr); + +/** + * NS_CStringAppendData + * + * This function appends data to the existing value of aStr. + * + * @param aStr abstract string reference to be modified + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_CStringAppendData(nsACString &aStr, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_CStringSetDataRange(aStr, PR_UINT32_MAX, 0, aData, aDataLength); +} + +/** + * NS_CStringInsertData + * + * This function inserts data into the existing value of aStr at the specified + * offset. + * + * @param aStr abstract string reference to be modified + * @param aOffset specifies where in the string to insert aData + * @param aData character buffer + * @param aDataLength number of characters to append (pass PR_UINT32_MAX to + * append until a null-character is encountered) + * @return NS_OK if function succeeded + * + * This function does not necessarily null-terminate aStr upon completion. + * The behavior depends on the implementation of the abstract string, aStr. + * If aStr is a reference to a nsStringContainer, then its data will be null- + * terminated by this function. + */ +inline NS_HIDDEN_(nsresult) +NS_CStringInsertData(nsACString &aStr, PRUint32 aOffset, const char *aData, + PRUint32 aDataLength = PR_UINT32_MAX) +{ + return NS_CStringSetDataRange(aStr, aOffset, 0, aData, aDataLength); +} + +/** + * NS_CStringCutData + * + * This function shortens the existing value of aStr, by removing characters + * at the specified offset. + * + * @param aStr abstract string reference to be modified + * @param aCutOffset specifies where in the string to insert aData + * @param aCutLength number of characters to remove + * @return NS_OK if function succeeded + */ +inline NS_HIDDEN_(nsresult) +NS_CStringCutData(nsACString &aStr, PRUint32 aCutOffset, PRUint32 aCutLength) +{ + return NS_CStringSetDataRange(aStr, aCutOffset, aCutLength, nsnull, 0); +} + +/* ------------------------------------------------------------------------- */ + +/** + * Encodings that can be used with the following conversion routines. + */ +enum nsCStringEncoding { + /* Conversion between ASCII and UTF-16 assumes that all bytes in the source + * string are 7-bit ASCII and can be inflated to UTF-16 by inserting null + * bytes. Reverse conversion is done by truncating every other byte. The + * conversion may result in loss and/or corruption of information if the + * strings do not strictly contain ASCII data. */ + NS_CSTRING_ENCODING_ASCII = 0, + + /* Conversion between UTF-8 and UTF-16 is non-lossy. */ + NS_CSTRING_ENCODING_UTF8 = 1, + + /* Conversion from UTF-16 to the native filesystem charset may result in a + * loss of information. No attempt is made to protect against data loss in + * this case. The native filesystem charset applies to strings passed to + * the "Native" method variants on nsIFile and nsILocalFile. */ + NS_CSTRING_ENCODING_NATIVE_FILESYSTEM = 2 +}; + +/** + * NS_CStringToUTF16 + * + * This function converts the characters in a nsACString to an array of UTF-16 + * characters, in the platform endianness. The result is stored in a nsAString + * object. + * + * @param aSource abstract string reference containing source string + * @param aSrcEncoding character encoding of the source string + * @param aDest abstract string reference to hold the result + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSource, nsCStringEncoding aSrcEncoding, + nsAString &aDest); + +/** + * NS_UTF16ToCString + * + * This function converts the UTF-16 characters in a nsAString to a single-byte + * encoding. The result is stored in a nsACString object. In some cases this + * conversion may be lossy. In such cases, the conversion may succeed with a + * return code indicating loss of information. The exact behavior is not + * specified at this time. + * + * @param aSource abstract string reference containing source string + * @param aDestEncoding character encoding of the resulting string + * @param aDest abstract string reference to hold the result + * + * @status FROZEN + */ +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSource, nsCStringEncoding aDestEncoding, + nsACString &aDest); + +/* ------------------------------------------------------------------------- */ + +/** + * Below we define nsAString and nsACString. The "_external" suffix is an + * implementation detail. nsAString_external is the name of the external + * representation of nsAString from the point of view of the Mozilla codebase. + * To a user of this API, nsAString_external is exactly nsAString. + * + * These classes should be treated as abstract classes with unspecified + * structure. The inline methods are provided as helper functions around the + * C-style API provided above. + * + * Do not try to mix these definitions of nsAString and nsACString with the + * internal definition of these classes from nsAString.h in the Mozilla tree. + */ + +#ifndef NS_STRINGAPI_IMPL +#define nsAString_external nsAString +#define nsACString_external nsACString +#endif + +class nsAString_external +{ +#ifndef NS_STRINGAPI_IMPL + +public: + typedef PRUnichar char_type; + typedef nsAString_external self_type; + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + NS_HIDDEN_(const char_type*) BeginReading() const + { + const char_type *data; + NS_StringGetData(*this, &data); + return data; + } + + NS_HIDDEN_(const char_type*) EndReading() const + { + const char_type *data; + PRUint32 len = NS_StringGetData(*this, &data); + return data + len; + } + + NS_HIDDEN_(size_type) Length() const + { + const char_type* data; + return NS_StringGetData(*this, &data); + } + + NS_HIDDEN_(void) Assign(const self_type& aString) + { + NS_StringCopy(*this, aString); + } + NS_HIDDEN_(void) Assign(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_StringSetData(*this, aData, aLength); + } + NS_HIDDEN_(void) Assign(char_type aChar) + { + NS_StringSetData(*this, &aChar, 1); + } + + NS_HIDDEN_(self_type&) operator=(const self_type& aString) { Assign(aString); return *this; } + NS_HIDDEN_(self_type&) operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + NS_HIDDEN_(self_type&) operator=(char_type aChar) { Assign(aChar); return *this; } + + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ) + { + NS_StringSetDataRange(*this, cutStart, cutLength, data, length); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, char_type c ) + { + Replace(cutStart, cutLength, &c, 1); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + const char_type* data; + PRUint32 dataLen = NS_StringGetData(readable, &data); + NS_StringSetDataRange(*this, cutStart, cutLength, data, dataLen); + } + + NS_HIDDEN_(void) Append( char_type c ) { Replace(size_type(-1), 0, c); } + NS_HIDDEN_(void) Append( const char_type* data, size_type length = size_type(-1) ) { Replace(size_type(-1), 0, data, length); } + NS_HIDDEN_(void) Append( const self_type& readable ) { Replace(size_type(-1), 0, readable); } + + NS_HIDDEN_(self_type&) operator+=( char_type c ) { Append(c); return *this; } + NS_HIDDEN_(self_type&) operator+=( const char_type* data ) { Append(data); return *this; } + NS_HIDDEN_(self_type&) operator+=( const self_type& readable ) { Append(readable); return *this; } + + NS_HIDDEN_(void) Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + NS_HIDDEN_(void) Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + NS_HIDDEN_(void) Insert( const self_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } + +#endif // NS_STRINGAPI_IMPL + +private: + void *v; +}; + +class nsACString_external +{ +#ifndef NS_STRINGAPI_IMPL + +public: + typedef char char_type; + typedef nsACString_external self_type; + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + NS_HIDDEN_(const char_type*) BeginReading() const + { + const char_type *data; + NS_CStringGetData(*this, &data); + return data; + } + + NS_HIDDEN_(const char_type*) EndReading() const + { + const char_type *data; + PRUint32 len = NS_CStringGetData(*this, &data); + return data + len; + } + + NS_HIDDEN_(size_type) Length() const + { + const char_type* data; + return NS_CStringGetData(*this, &data); + } + + NS_HIDDEN_(void) Assign(const self_type& aString) + { + NS_CStringCopy(*this, aString); + } + NS_HIDDEN_(void) Assign(const char_type* aData, size_type aLength = PR_UINT32_MAX) + { + NS_CStringSetData(*this, aData, aLength); + } + NS_HIDDEN_(void) Assign(char_type aChar) + { + NS_CStringSetData(*this, &aChar, 1); + } + + NS_HIDDEN_(self_type&) operator=(const self_type& aString) { Assign(aString); return *this; } + NS_HIDDEN_(self_type&) operator=(const char_type* aPtr) { Assign(aPtr); return *this; } + NS_HIDDEN_(self_type&) operator=(char_type aChar) { Assign(aChar); return *this; } + + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ) + { + NS_CStringSetDataRange(*this, cutStart, cutLength, data, length); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, char_type c ) + { + Replace(cutStart, cutLength, &c, 1); + } + NS_HIDDEN_(void) Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + const char_type* data; + PRUint32 dataLen = NS_CStringGetData(readable, &data); + NS_CStringSetDataRange(*this, cutStart, cutLength, data, dataLen); + } + + NS_HIDDEN_(void) Append( char_type c ) { Replace(size_type(-1), 0, c); } + NS_HIDDEN_(void) Append( const char_type* data, size_type length = size_type(-1) ) { Replace(size_type(-1), 0, data, length); } + NS_HIDDEN_(void) Append( const self_type& readable ) { Replace(size_type(-1), 0, readable); } + + NS_HIDDEN_(self_type&) operator+=( char_type c ) { Append(c); return *this; } + NS_HIDDEN_(self_type&) operator+=( const char_type* data ) { Append(data); return *this; } + NS_HIDDEN_(self_type&) operator+=( const self_type& readable ) { Append(readable); return *this; } + + NS_HIDDEN_(void) Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + NS_HIDDEN_(void) Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + NS_HIDDEN_(void) Insert( const self_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + NS_HIDDEN_(void) Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, nsnull, 0); } + +#endif // NS_STRINGAPI_IMPL + +private: + void *v; +}; + +/* ------------------------------------------------------------------------- */ + +/** + * Below we define nsStringContainer and nsCStringContainer. These classes + * have unspecified structure. In most cases, your code should use + * nsEmbedString instead of these classes; however, if you prefer C-style + * programming, then look no further... + */ + +class nsStringContainer : public nsAString_external +{ +private: + void *d1; + PRUint32 d2; + void *d3; + +public: + nsStringContainer() {} // MSVC6 needs this +}; + +class nsCStringContainer : public nsACString_external +{ +private: + void *d1; + PRUint32 d2; + void *d3; + +public: + nsCStringContainer() {} // MSVC6 needs this +}; + +#endif // nsStringAPI_h__ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h new file mode 100644 index 00000000..4c664011 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringFwd.h @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* nsStringFwd.h --- forward declarations for string classes */ + +#ifndef nsStringFwd_h___ +#define nsStringFwd_h___ + +#ifndef nscore_h___ +#include "nscore.h" +#endif + + + /** + * double-byte (PRUnichar) string types + */ + +class nsAString; +class nsObsoleteAString; +class nsSubstring; +class nsSubstringTuple; +class nsString; +class nsAutoString; +class nsDependentString; +class nsDependentSubstring; +class nsPromiseFlatString; +class nsStringComparator; +class nsDefaultStringComparator; +class nsXPIDLString; + + + /** + * single-byte (char) string types + */ + +class nsACString; +class nsObsoleteACString; +class nsCSubstring; +class nsCSubstringTuple; +class nsCString; +class nsCAutoString; +class nsDependentCString; +class nsDependentCSubstring; +class nsPromiseFlatCString; +class nsCStringComparator; +class nsDefaultCStringComparator; +class nsXPIDLCString; + + + /** + * typedefs for backwards compatibility + */ + +typedef nsString nsAFlatString; +typedef nsSubstring nsASingleFragmentString; + +typedef nsCString nsAFlatCString; +typedef nsCSubstring nsASingleFragmentCString; + + +#endif /* !defined(nsStringFwd_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h b/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h new file mode 100644 index 00000000..1848594c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsStringIterator.h @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStringIterator_h___ +#define nsStringIterator_h___ + +#ifndef nsCharTraits_h___ +#include "nsCharTraits.h" +#endif + +#ifndef nsAlgorithm_h___ +#include "nsAlgorithm.h" +#endif + +#ifndef nsDebug_h___ +#include "nsDebug.h" +#endif + + /** + * @see nsTAString + */ + +template +class nsReadingIterator + { + public: + typedef nsReadingIterator self_type; + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef const CharT* pointer; + typedef const CharT& reference; + + private: + friend class nsAString; + friend class nsACString; + friend class nsSubstring; + friend class nsCSubstring; + + // unfortunately, the API for nsReadingIterator requires that the + // iterator know its start and end positions. this was needed when + // we supported multi-fragment strings, but now it is really just + // extra baggage. we should remove mStart and mEnd at some point. + + const CharT* mStart; + const CharT* mEnd; + const CharT* mPosition; + + public: + nsReadingIterator() { } + // nsReadingIterator( const nsReadingIterator& ); // auto-generated copy-constructor OK + // nsReadingIterator& operator=( const nsReadingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward() {} + inline void normalize_backward() {} + + pointer + start() const + { + return mStart; + } + + pointer + end() const + { + return mEnd; + } + + pointer + get() const + { + return mPosition; + } + + CharT + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + self_type& + operator++() + { + ++mPosition; + return *this; + } + + self_type + operator++( int ) + { + self_type result(*this); + ++mPosition; + return result; + } + + self_type& + operator--() + { + --mPosition; + return *this; + } + + self_type + operator--( int ) + { + self_type result(*this); + --mPosition; + return result; + } + + difference_type + size_forward() const + { + return mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mStart; + } + + self_type& + advance( difference_type n ) + { + if (n > 0) + { + difference_type step = NS_MIN(n, size_forward()); + + NS_ASSERTION(step>0, "can't advance a reading iterator beyond the end of a string"); + + mPosition += step; + } + else if (n < 0) + { + difference_type step = NS_MAX(n, -size_backward()); + + NS_ASSERTION(step<0, "can't advance (backward) a reading iterator beyond the end of a string"); + + mPosition += step; + } + return *this; + } + }; + + /** + * @see nsTAString + */ + +template +class nsWritingIterator + { + public: + typedef nsWritingIterator self_type; + typedef ptrdiff_t difference_type; + typedef CharT value_type; + typedef CharT* pointer; + typedef CharT& reference; + + private: + friend class nsAString; + friend class nsACString; + friend class nsSubstring; + friend class nsCSubstring; + + // unfortunately, the API for nsWritingIterator requires that the + // iterator know its start and end positions. this was needed when + // we supported multi-fragment strings, but now it is really just + // extra baggage. we should remove mStart and mEnd at some point. + + CharT* mStart; + CharT* mEnd; + CharT* mPosition; + + public: + nsWritingIterator() { } + // nsWritingIterator( const nsWritingIterator& ); // auto-generated copy-constructor OK + // nsWritingIterator& operator=( const nsWritingIterator& ); // auto-generated copy-assignment operator OK + + inline void normalize_forward() {} + inline void normalize_backward() {} + + pointer + start() const + { + return mStart; + } + + pointer + end() const + { + return mEnd; + } + + pointer + get() const + { + return mPosition; + } + + reference + operator*() const + { + return *get(); + } + +#if 0 + // An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2) + // don't like this when |CharT| is a type without members. + pointer + operator->() const + { + return get(); + } +#endif + + self_type& + operator++() + { + ++mPosition; + return *this; + } + + self_type + operator++( int ) + { + self_type result(*this); + ++mPosition; + return result; + } + + self_type& + operator--() + { + --mPosition; + return *this; + } + + self_type + operator--( int ) + { + self_type result(*this); + --mPosition; + return result; + } + + difference_type + size_forward() const + { + return mEnd - mPosition; + } + + difference_type + size_backward() const + { + return mPosition - mStart; + } + + self_type& + advance( difference_type n ) + { + if (n > 0) + { + difference_type step = NS_MIN(n, size_forward()); + + NS_ASSERTION(step>0, "can't advance a writing iterator beyond the end of a string"); + + mPosition += step; + } + else if (n < 0) + { + difference_type step = NS_MAX(n, -size_backward()); + + NS_ASSERTION(step<0, "can't advance (backward) a writing iterator beyond the end of a string"); + + mPosition += step; + } + return *this; + } + + PRUint32 + write( const value_type* s, PRUint32 n ) + { + NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!"); + + nsCharTraits::move(mPosition, s, n); + advance( difference_type(n) ); + return n; + } + }; + +template +inline +PRBool +operator==( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsReadingIterator& lhs, const nsReadingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + + + // + // |nsWritingIterator|s + // + +template +inline +PRBool +operator==( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() == rhs.get(); + } + +template +inline +PRBool +operator!=( const nsWritingIterator& lhs, const nsWritingIterator& rhs ) + { + return lhs.get() != rhs.get(); + } + +#endif /* !defined(nsStringIterator_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h new file mode 100644 index 00000000..35a1a568 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsSubstring.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsSubstring_h___ +#define nsSubstring_h___ + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + +#define kNotFound -1 + +// If some platform(s) can't handle our template that matches literal strings, +// then we'll disable it on those platforms. +#ifndef NS_DISABLE_LITERAL_TEMPLATE +# if (defined(_MSC_VER) && (_MSC_VER < 1310)) || (defined(__SUNPRO_CC) & (__SUNPRO_CC < 0x560)) || (defined(__HP_aCC) && (__HP_aCC <= 012100)) +# define NS_DISABLE_LITERAL_TEMPLATE +# endif +#endif /* !NS_DISABLE_LITERAL_TEMPLATE */ + +#include + + // declare nsSubstring +#include "string-template-def-unichar.h" +#include "nsTSubstring.h" +#include "string-template-undef.h" + + + // declare nsCSubstring +#include "string-template-def-char.h" +#include "nsTSubstring.h" +#include "string-template-undef.h" + + +#ifndef nsSubstringTuple_h___ +#include "nsSubstringTuple.h" +#endif + +#endif // !defined(nsSubstring_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h b/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h new file mode 100644 index 00000000..8cf6f803 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsSubstringTuple.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsSubstringTuple_h___ +#define nsSubstringTuple_h___ + +#ifndef nsSubstring_h___ +#include "nsSubstring.h" +#endif + + // declare nsSubstringTuple +#include "string-template-def-unichar.h" +#include "nsTSubstringTuple.h" +#include "string-template-undef.h" + + // declare nsCSubstringTuple +#include "string-template-def-char.h" +#include "nsTSubstringTuple.h" +#include "string-template-undef.h" + +#endif // !defined(nsSubstringTuple_h___) diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h new file mode 100644 index 00000000..93b88443 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTAString.h @@ -0,0 +1,618 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Darin Fisher + * + * 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 ***** */ + + + /** + * The base for string comparators + */ +class NS_COM nsTStringComparator_CharT + { + public: + typedef CharT char_type; + + nsTStringComparator_CharT() {} + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const = 0; + virtual int operator()( char_type, char_type ) const = 0; + }; + + + /** + * The default string comparator (case-sensitive comparision) + */ +class NS_COM nsTDefaultStringComparator_CharT + : public nsTStringComparator_CharT + { + public: + typedef CharT char_type; + + nsTDefaultStringComparator_CharT() {} + + virtual int operator()( const char_type*, const char_type*, PRUint32 length ) const; + virtual int operator()( char_type, char_type ) const; + }; + + + /** + * nsTAString is the most abstract class in the string hierarchy. + * + * In its original inception, nsTAString was designed to allow the data + * storage for a string to be separated into multiple fragments. This was + * intended to enable lazy string flattening or avoid string flattening + * altogether in some cases. This abstraction, however, meant that every + * single string operation (including simple operations such as IsEmpty() and + * BeginReading()) required virtual function calls. A virtual destructor was + * also required. This not only meant additional overhead for invoking + * string methods but also added to additional codesize at every callsite (to + * load the virtual function address). + * + * Today nsTAString exists mainly for backwards compatibility of the string + * API. It is restricted to representing a contiguous array of characters, + * where the character array is not necessarily null-terminated. Moreover, + * since nsTAString's virtual function table was frozen for Mozilla 1.0, + * nsTAString necessarily maintains ABI compatibility with older versions of + * Gecko. (nsTObsoleteAString provides that frozen ABI. See + * nsObsoleteAString.h for a description of how we solve the ABI + * compatibility requirement while eliminating virtual function calls on + * nsTAString.) + * + * XPIDL still generates C++ header files with references to nsTAStrings, so + * nsTAString will still be heavily used in real code. + * + * If the opportunity to break ABI compatibility with Mozilla 1.0 were to + * ever arise, our first move should be to make nsTAString equate to + * nsTSubstring. This may in fact be an option today for some Gecko-based + * products. + */ +class nsTAString_CharT + { + public: + + typedef CharT char_type; + typedef nsCharTraits char_traits; + + typedef char_traits::incompatible_char_type incompatible_char_type; + + typedef nsTAString_CharT self_type; + typedef nsTAString_CharT abstract_string_type; + typedef nsTObsoleteAString_CharT obsolete_string_type; + typedef nsTSubstring_CharT substring_type; + typedef nsTSubstringTuple_CharT substring_tuple_type; + + typedef nsReadingIterator const_iterator; + typedef nsWritingIterator iterator; + + typedef nsTStringComparator_CharT comparator_type; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + public: + + // this acts like a virtual destructor + NS_COM NS_FASTCALL ~nsTAString_CharT(); + + + /** + * BeginReading/EndReading can be used to get immutable access to the + * string's underlying buffer. EndReading returns a pointer to the + * end of the string's buffer. nsReadableUtils.h provides a collection + * of utility functions that work with these iterators. + */ + + inline const_iterator& BeginReading( const_iterator& iter ) const + { + size_type len = GetReadableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mStart; + return iter; + } + + inline const_iterator& EndReading( const_iterator& iter ) const + { + size_type len = GetReadableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mEnd; + return iter; + } + + + /** + * BeginWriting/EndWriting can be used to get mutable access to the + * string's underlying buffer. EndWriting returns a pointer to the + * end of the string's buffer. This iterator API cannot be used to + * grow a buffer. Use SetLength to resize the string's buffer. + */ + + inline iterator& BeginWriting( iterator& iter ) + { + size_type len = GetWritableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mStart; + return iter; + } + + inline iterator& EndWriting( iterator& iter ) + { + size_type len = GetWritableBuffer(&iter.mStart); + iter.mEnd = iter.mStart + len; + iter.mPosition = iter.mEnd; + return iter; + } + + + /** + * Length checking functions. IsEmpty is a helper function to avoid + * writing code like: |if (str.Length() == 0)| + */ + + NS_COM size_type NS_FASTCALL Length() const; + PRBool IsEmpty() const { return Length() == 0; } + + + /** + * String equality tests. Pass a string comparator if you want to + * control how the strings are compared. By default, a binary + * "case-sensitive" comparision is performed. + */ + + NS_COM PRBool NS_FASTCALL Equals( const self_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type* ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type*, const comparator_type& ) const; + + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when you know the + * length of 'data'. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when 'data' is + * null-terminated. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data ) const; + + // EqualsLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. + // The template trick to acquire the array length at compile time without + // using a macro is due to Corey Kosak, with much thanks. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool EqualsLiteral( const char* str ) const + { + return EqualsASCII(str); + } +#else + template + inline PRBool EqualsLiteral( const char (&str)[N] ) const + { + return EqualsASCII(str, N-1); + } + template + inline PRBool EqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return EqualsASCII(s, N-1); + } +#endif + + // The LowerCaseEquals methods compare the lower case version of + // this string to some ASCII/Literal string. The ASCII string is + // *not* lowercased for you. If you compare to an ASCII or literal + // string that contains an uppercase character, it is guaranteed to + // return false. We will throw assertions too. + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; + + // LowerCaseEqualsLiteral must ONLY be applied to an actual + // literal string. Do not attempt to use it with a regular char* + // pointer, or with a char array variable. Use + // LowerCaseEqualsASCII for them. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool LowerCaseEqualsLiteral( const char* str ) const + { + return LowerCaseEqualsASCII(str); + } +#else + template + inline PRBool LowerCaseEqualsLiteral( const char (&str)[N] ) const + { + return LowerCaseEqualsASCII(str, N-1); + } + template + inline PRBool LowerCaseEqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return LowerCaseEqualsASCII(s, N-1); + } +#endif + + /** + * A string always references a non-null data pointer. In some + * applications (e.g., the DOM) it is necessary for a string class + * to have some way to distinguish an empty string from a null (or + * void) string. These methods enable support for the concept of + * a void string. + */ + + NS_COM PRBool NS_FASTCALL IsVoid() const; + NS_COM void NS_FASTCALL SetIsVoid( PRBool ); + + + /** + * This method returns true if the string's underlying buffer is + * null-terminated. This should rarely be needed by applications. + * The PromiseFlatTString method should be used to ensure that a + * string's underlying buffer is null-terminated. + */ + + NS_COM PRBool NS_FASTCALL IsTerminated() const; + + + /** + * These are contant time since nsTAString uses flat storage + */ + NS_COM char_type NS_FASTCALL First() const; + NS_COM char_type NS_FASTCALL Last() const; + + + /** + * Returns the number of occurances of the given character. + */ + NS_COM size_type NS_FASTCALL CountChar( char_type ) const; + + + /** + * Locates the offset of the first occurance of the character. Pass a + * non-zero offset to control where the search begins. + */ + + NS_COM PRInt32 NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; + + + /** + * SetCapacity is not required to do anything; however, it can be used + * as a hint to the implementation to reduce allocations. + * + * SetCapacity(0) is a suggestion to discard all associated storage. + */ + NS_COM void NS_FASTCALL SetCapacity( size_type ); + + + /** + * XXX talk to dbaron about this comment. we do need a method that + * XXX allows someone to resize a string's buffer so that it can be + * XXX populated using writing iterators. SetLength seems to be the + * XXX right method for the job, and we do use it in this capacity + * XXX in certain places. + * + * SetLength is used in two ways: + * 1) to |Cut| a suffix of the string; + * 2) to prepare to |Append| or move characters around. + * + * External callers are not allowed to use |SetLength| in this + * latter capacity, and should prefer |Truncate| for the former. + * In other words, |SetLength| is deprecated for all use outside + * of the string library and the internal use may at some point + * be replaced as well. + * + * This distinction makes me think the two different uses should + * be split into two distinct functions. + */ + NS_COM void NS_FASTCALL SetLength( size_type ); + + + /** + * Can't use |Truncate| to make a string longer! + */ + void Truncate( size_type aNewLength=0 ) + { + NS_ASSERTION(aNewLength <= Length(), "Truncate cannot make string longer"); + SetLength(aNewLength); + } + + + /** + * |Assign| and |operator=| make |this| equivalent to the string or + * buffer given as an argument. If possible, they do this by sharing + * a reference counted buffer (see |nsTSubstring|). If not, they copy + * the buffer into their own buffer. + */ + + NS_COM void NS_FASTCALL Assign( const self_type& readable ); + NS_COM void NS_FASTCALL Assign( const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Assign( const char_type* data ); + NS_COM void NS_FASTCALL Assign( const char_type* data, size_type length ); + NS_COM void NS_FASTCALL Assign( char_type c ); + + NS_COM void NS_FASTCALL AssignASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AssignASCII( const char* data ); + + // AssignLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AssignASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AssignLiteral( const char* str ) + { AssignASCII(str); } +#else + template + void AssignLiteral( const char (&str)[N] ) + { AssignASCII(str, N-1); } + template + void AssignLiteral( char (&str)[N] ) + { AssignASCII(str, N-1); } +#endif + + // copy-assignment operator. I must define my own if I don't want the compiler to make me one + self_type& operator=( const self_type& readable ) { Assign(readable); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( char_type c ) { Assign(c); return *this; } + + + + /** + * |Append|, |operator+=| are used to add characters to the end of this string. + */ + + NS_COM void NS_FASTCALL Append( const self_type& readable ); + NS_COM void NS_FASTCALL Append( const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Append( const char_type* data ); + NS_COM void NS_FASTCALL Append( const char_type* data, size_type length ); + NS_COM void NS_FASTCALL Append( char_type c ); + + NS_COM void NS_FASTCALL AppendASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AppendASCII( const char* data ); + + // AppendLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AppendASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AppendLiteral( const char* str ) + { AppendASCII(str); } +#else + template + void AppendLiteral( const char (&str)[N] ) + { AppendASCII(str, N-1); } + template + void AppendLiteral( char (&str)[N] ) + { AppendASCII(str, N-1); } +#endif + + self_type& operator+=( const self_type& readable ) { Append(readable); return *this; } + self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } + self_type& operator+=( const char_type* data ) { Append(data); return *this; } + self_type& operator+=( char_type c ) { Append(c); return *this; } + + + /** + * |Insert| is used to add characters into this string at a given position. + * NOTE: It's a shame the |pos| parameter isn't at the front of the arg list. + */ + + NS_COM void NS_FASTCALL Insert( const self_type& readable, index_type pos ); + NS_COM void NS_FASTCALL Insert( const substring_tuple_type& tuple, index_type pos ); + NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos ); + NS_COM void NS_FASTCALL Insert( const char_type* data, index_type pos, size_type length ); + NS_COM void NS_FASTCALL Insert( char_type c, index_type pos ); + + + /** + * |Cut| is used to remove a range of characters from this string. + */ + + NS_COM void NS_FASTCALL Cut( index_type cutStart, size_type cutLength ); + + + /** + * |Replace| is used overwrite a range of characters from this string. + */ + + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const self_type& readable ); + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& readable ); + + + /** + * this is public to support automatic conversion of tuple to abstract + * string, which is necessary to support our API. + */ + nsTAString_CharT(const substring_tuple_type& tuple) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mData(nsnull) + , mLength(0) + , mFlags(0) + { + Assign(tuple); + } + + protected: + + friend class nsTSubstringTuple_CharT; + + // GCC 3.2 erroneously needs these (even though they are subclasses!) + friend class nsTSubstring_CharT; + friend class nsTDependentSubstring_CharT; + friend class nsTPromiseFlatString_CharT; + + /** + * the address of our virtual function table. required for backwards + * compatibility with Mozilla 1.0 frozen nsAC?String interface. + */ + const void* mVTable; + + /** + * these fields are "here" only when mVTable == sCanonicalVTable. + * + * they exist to support automatic construction of a nsTAString + * from a nsTSubstringTuple. + */ + char_type* mData; + size_type mLength; + PRUint32 mFlags; + + /** + * nsTAString must be subclassed before it can be instantiated. + */ + nsTAString_CharT(char_type* data, size_type length, PRUint32 flags) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mData(data) + , mLength(length) + , mFlags(flags) + {} + + /** + * optional ctor for use by subclasses. + * + * NOTE: mData and mLength are intentionally left uninitialized. + */ + explicit + nsTAString_CharT(PRUint32 flags) + : mVTable(obsolete_string_type::sCanonicalVTable) + , mFlags(flags) + {} + + /** + * get pointer to internal string buffer (may not be null terminated). + * return length of buffer. + */ + NS_COM size_type NS_FASTCALL GetReadableBuffer( const char_type **data ) const; + NS_COM size_type NS_FASTCALL GetWritableBuffer( char_type **data ); + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + PRBool NS_FASTCALL IsDependentOn(const char_type *start, const char_type *end) const; + + /** + * we can be converted to a const nsTSubstring (dependent on this) + */ + const substring_type NS_FASTCALL ToSubstring() const; + + /** + * type cast helpers + */ + + const obsolete_string_type* AsObsoleteString() const + { + return NS_REINTERPRET_CAST(const obsolete_string_type*, this); + } + + obsolete_string_type* AsObsoleteString() + { + return NS_REINTERPRET_CAST(obsolete_string_type*, this); + } + + const substring_type* AsSubstring() const + { + return NS_REINTERPRET_CAST(const substring_type*, this); + } + + substring_type* AsSubstring() + { + return NS_REINTERPRET_CAST(substring_type*, this); + } + + private: + + // GCC 2.95.3, EGCS-2.91.66, Sun Workshop/Forte, and IBM VisualAge C++ + // require a public copy-constructor in order to support automatic + // construction of a nsTAString from a nsTSubstringTuple. I believe + // enabling the default copy-constructor is harmless, but I do not want + // it to be enabled by default because that might tempt people into + // using it (where it would be invalid). +#if !defined(__SUNPRO_CC) && \ + !(defined(_AIX) && defined(__IBMCPP__)) && \ + (!defined(__GNUC__) || __GNUC__ > 2 || __GNUC_MINOR__ > 95) + + // NOT TO BE IMPLEMENTED + nsTAString_CharT( const self_type& ); + +#endif + + // NOT TO BE IMPLEMENTED + void operator= ( incompatible_char_type ); + void Assign ( incompatible_char_type ); + void operator+= ( incompatible_char_type ); + void Append ( incompatible_char_type ); + void Insert ( incompatible_char_type, index_type ); + }; + + +NS_COM +int NS_FASTCALL Compare( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs, const nsTStringComparator_CharT& = nsTDefaultStringComparator_CharT() ); + + +inline +PRBool operator!=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return !lhs.Equals(rhs); + } + +inline +PRBool operator< ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)< 0; + } + +inline +PRBool operator<=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)<=0; + } + +inline +PRBool operator==( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return lhs.Equals(rhs); + } + +inline +PRBool operator>=( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)>=0; + } + +inline +PRBool operator> ( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs ) + { + return Compare(lhs, rhs)> 0; + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h new file mode 100644 index 00000000..91a2b53e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentString.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Darin Fisher + * + * 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 ***** */ + + + /** + * nsTDependentString_CharT + * + * Stores a null-terminated, immutable sequence of characters. + * + * Subclass of nsTString that restricts string value to an immutable + * character sequence. This class does not own its data, so the creator + * of objects of this type must take care to ensure that a + * nsTDependentString continues to reference valid memory for the + * duration of its use. + */ +class nsTDependentString_CharT : public nsTString_CharT + { + public: + + typedef nsTDependentString_CharT self_type; + + public: + + /** + * verify restrictions + */ + void AssertValid() + { + NS_ASSERTION(mData, "nsTDependentString must wrap a non-NULL buffer"); + NS_ASSERTION(mLength != size_type(-1), "nsTDependentString has bogus length"); + NS_ASSERTION(mData[mLength] == 0, "nsTDependentString must wrap only null-terminated strings"); + } + + + /** + * constructors + */ + + nsTDependentString_CharT( const char_type* start, const char_type* end ) + : string_type(NS_CONST_CAST(char_type*, start), end - start, F_TERMINATED) + { + AssertValid(); + } + + nsTDependentString_CharT( const char_type* data, PRUint32 length ) + : string_type(NS_CONST_CAST(char_type*, data), length, F_TERMINATED) + { + AssertValid(); + } + + explicit + nsTDependentString_CharT( const char_type* data ) + : string_type(NS_CONST_CAST(char_type*, data), char_traits::length(data), F_TERMINATED) + { + AssertValid(); + } + + explicit + nsTDependentString_CharT( const substring_type& str ) + : string_type(NS_CONST_CAST(char_type*, str.Data()), str.Length(), F_TERMINATED) + { + AssertValid(); + } + + // XXX are you sure?? + // auto-generated copy-constructor OK + // auto-generated copy-assignment operator OK + // auto-generated destructor OK + + + /** + * allow this class to be bound to a different string... + */ + + void Rebind( const char_type* data ) + { + mData = NS_CONST_CAST(char_type*, data); + mLength = char_traits::length(data); + SetDataFlags(F_TERMINATED); + AssertValid(); + } + + void Rebind( const char_type* data, size_type length ) + { + mData = NS_CONST_CAST(char_type*, data); + mLength = length; + SetDataFlags(F_TERMINATED); + AssertValid(); + } + + void Rebind( const char_type* start, const char_type* end ) + { + Rebind(start, end - start); + } + + private: + + // NOT USED + nsTDependentString_CharT( const substring_tuple_type& ); + nsTDependentString_CharT( const abstract_string_type& ); + }; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h new file mode 100644 index 00000000..00e5f189 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTDependentSubstring.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Darin Fisher + * + * 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 ***** */ + + + /** + * nsTDependentSubstring_CharT + */ +class nsTDependentSubstring_CharT : public nsTSubstring_CharT + { + public: + + typedef nsTDependentSubstring_CharT self_type; + + public: + + NS_COM void Rebind( const abstract_string_type&, PRUint32 startPos, PRUint32 length = size_type(-1) ); + NS_COM void Rebind( const substring_type&, PRUint32 startPos, PRUint32 length = size_type(-1) ); + + void Rebind( const char_type* start, const char_type* end ) + { + NS_ASSERTION(start && end, "nsTDependentSubstring must wrap a non-NULL buffer"); + mData = NS_CONST_CAST(char_type*, start); + mLength = end - start; + SetDataFlags(F_NONE); + } + + nsTDependentSubstring_CharT( const abstract_string_type& str, PRUint32 startPos, PRUint32 length = size_type(-1) ) + : substring_type(F_NONE) + { + Rebind(str, startPos, length); + } + + nsTDependentSubstring_CharT( const substring_type& str, PRUint32 startPos, PRUint32 length = size_type(-1) ) + : substring_type(F_NONE) + { + Rebind(str, startPos, length); + } + + nsTDependentSubstring_CharT( const char_type* start, const char_type* end ) + : substring_type(NS_CONST_CAST(char_type*, start), end - start, F_NONE) {} + + nsTDependentSubstring_CharT( const const_iterator& start, const const_iterator& end ) + : substring_type(NS_CONST_CAST(char_type*, start.get()), end.get() - start.get(), F_NONE) {} + + // auto-generated copy-constructor OK (XXX really?? what about base class copy-ctor?) + + private: + // we're immutable, you can't assign into a substring + void operator=( const self_type& ) NS_DELETE; + + }; + +inline +const nsTDependentSubstring_CharT +Substring( const nsTAString_CharT& str, PRUint32 startPos, PRUint32 length = PRUint32(-1) ) + { + return nsTDependentSubstring_CharT(str, startPos, length); + } + +inline +const nsTDependentSubstring_CharT +Substring( const nsTSubstring_CharT& str, PRUint32 startPos, PRUint32 length = PRUint32(-1) ) + { + return nsTDependentSubstring_CharT(str, startPos, length); + } + +inline +const nsTDependentSubstring_CharT +Substring( const nsReadingIterator& start, const nsReadingIterator& end ) + { + return nsTDependentSubstring_CharT(start.get(), end.get()); + } + +inline +const nsTDependentSubstring_CharT +Substring( const CharT* start, const CharT* end ) + { + return nsTDependentSubstring_CharT(start, end); + } + +inline +const nsTDependentSubstring_CharT +StringHead( const nsTAString_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, 0, count); + } + +inline +const nsTDependentSubstring_CharT +StringHead( const nsTSubstring_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, 0, count); + } + +inline +const nsTDependentSubstring_CharT +StringTail( const nsTAString_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, str.Length() - count, count); + } + +inline +const nsTDependentSubstring_CharT +StringTail( const nsTSubstring_CharT& str, PRUint32 count ) + { + return nsTDependentSubstring_CharT(str, str.Length() - count, count); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h new file mode 100644 index 00000000..82d5f56c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTObsoleteAString.h @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * nsTObsoleteAString_CharT : binary compatible with old nsAC?String vtable + * + * @status FROZEN + */ +class nsTObsoleteAString_CharT + { + public: + /** + * This is holds the address of the vtable for the canonical string + * implementation (i.e., nsTString). + */ + NS_COM static const void *sCanonicalVTable; + + /** + * An |nsFragmentRequest| is used to tell |GetReadableFragment| and + * |GetWritableFragment| what to do. + * + * @see GetReadableFragment + */ + enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt }; + + /** + * A |nsReadableFragment| provides |const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsReadableFragment| is the underlying machinery that lets + * |nsReadingIterator|s work. + * + * @see nsReadingIterator + * @status FROZEN + */ + struct nsReadableFragment + { + const CharT* mStart; + const CharT* mEnd; + const void* mFragmentIdentifier; + + nsReadableFragment() : mStart(0), mEnd(0), mFragmentIdentifier(0) {} + }; + + + /** + * A |nsWritableFragment| provides non-|const| access to a contiguous hunk of + * string of homogenous units, e.g., bytes (|char|). This doesn't mean it + * represents a flat hunk. It could be a variable length encoding, for + * instance UTF-8. And the fragment itself need not be zero-terminated. + * + * An |nsWritableFragment| is the underlying machinery that lets + * |nsWritingIterator|s work. + * + * @see nsWritingIterator + * @status FROZEN + */ + struct nsWritableFragment + { + CharT* mStart; + CharT* mEnd; + void* mFragmentIdentifier; + + nsWritableFragment() : mStart(0), mEnd(0), mFragmentIdentifier(0) {} + }; + + protected: + + typedef CharT char_type; + + typedef void buffer_handle_type; + typedef void shared_buffer_handle_type; + typedef nsReadableFragment const_fragment_type; + typedef nsWritableFragment fragment_type; + + typedef nsTAString_CharT abstract_string_type; + + typedef PRUint32 size_type; + typedef PRUint32 index_type; + + protected: + + friend class nsTAString_CharT; + friend class nsTSubstring_CharT; + + /** here's the old nsAC?String vtable **/ + + virtual ~nsTObsoleteAString_CharT() { } + + virtual PRUint32 GetImplementationFlags() const = 0; + virtual const buffer_handle_type* GetFlatBufferHandle() const = 0; + virtual const buffer_handle_type* GetBufferHandle() const = 0; + virtual const shared_buffer_handle_type* GetSharedBufferHandle() const = 0; + + virtual size_type Length() const = 0; + + virtual PRBool IsVoid() const = 0; + virtual void SetIsVoid( PRBool ) = 0; + + virtual void SetCapacity( size_type ) = 0; + virtual void SetLength( size_type ) = 0; + + virtual void Cut( index_type cutStart, size_type cutLength ) = 0; + + virtual void do_AssignFromReadable( const abstract_string_type& ) = 0; + virtual void do_AssignFromElementPtr( const char_type* ) = 0; + virtual void do_AssignFromElementPtrLength( const char_type*, size_type ) = 0; + virtual void do_AssignFromElement( char_type ) = 0; + + virtual void do_AppendFromReadable( const abstract_string_type& ) = 0; + virtual void do_AppendFromElementPtr( const char_type* ) = 0; + virtual void do_AppendFromElementPtrLength( const char_type*, size_type ) = 0; + virtual void do_AppendFromElement( char_type ) = 0; + + virtual void do_InsertFromReadable( const abstract_string_type&, index_type ) = 0; + virtual void do_InsertFromElementPtr( const char_type*, index_type ) = 0; + virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type ) = 0; + virtual void do_InsertFromElement( char_type, index_type ) = 0; + + virtual void do_ReplaceFromReadable( index_type, size_type, const abstract_string_type& ) = 0; + + virtual const char_type* GetReadableFragment( const_fragment_type&, nsFragmentRequest, PRUint32 = 0 ) const = 0; + virtual char_type* GetWritableFragment( fragment_type&, nsFragmentRequest, PRUint32 = 0 ) = 0; + }; + + // forward declare implementation +class nsTObsoleteAStringThunk_CharT; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h new file mode 100644 index 00000000..6899df7c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTPromiseFlatString.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * Darin Fisher + * + * 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 ***** */ + + + /** + * NOTE: + * + * Try to avoid flat strings. |PromiseFlat[C]String| will help you as a last + * resort, and this may be necessary when dealing with legacy or OS calls, + * but in general, requiring a null-terminated array of characters kills many + * of the performance wins the string classes offer. Write your own code to + * use |nsA[C]String&|s for parameters. Write your string proccessing + * algorithms to exploit iterators. If you do this, you will benefit from + * being able to chain operations without copying or allocating and your code + * will be significantly more efficient. Remember, a function that takes an + * |const nsA[C]String&| can always be passed a raw character pointer by + * wrapping it (for free) in a |nsDependent[C]String|. But a function that + * takes a character pointer always has the potential to force allocation and + * copying. + * + * + * How to use it: + * + * A |nsPromiseFlat[C]String| doesn't necessarily own the characters it + * promises. You must never use it to promise characters out of a string + * with a shorter lifespan. The typical use will be something like this: + * + * SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD + * + * Here's a BAD use: + * + * const char* buffer = PromiseFlatCString(aCString).get(); + * SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer + * + * The only way to make one is with the function |PromiseFlat[C]String|, + * which produce a |const| instance. ``What if I need to keep a promise + * around for a little while?'' you might ask. In that case, you can keep a + * reference, like so + * + * const nsPromiseFlatString& flat = PromiseFlatString(aString); + * // this reference holds the anonymous temporary alive, but remember, + * // it must _still_ have a lifetime shorter than that of |aString| + * + * SomeOSFunction(flat.get()); + * SomeOtherOSFunction(flat.get()); + * + * + * How does it work? + * + * A |nsPromiseFlat[C]String| is just a wrapper for another string. If you + * apply it to a string that happens to be flat, your promise is just a + * dependent reference to the string's data. If you apply it to a non-flat + * string, then a temporary flat string is created for you, by allocating and + * copying. In the event that you end up assigning the result into a sharing + * string (e.g., |nsTString|), the right thing happens. + */ + +class nsTPromiseFlatString_CharT : public nsTString_CharT + { + public: + + typedef nsTPromiseFlatString_CharT self_type; + + private: + + NS_COM void Init( const substring_type& ); + NS_COM void Init( const abstract_string_type& ); + + // NOT TO BE IMPLEMENTED + void operator=( const self_type& ) NS_DELETE; + + // NOT TO BE IMPLEMENTED + nsTPromiseFlatString_CharT() NS_DELETE; + + public: + + explicit + nsTPromiseFlatString_CharT( const substring_type& str ) + : string_type() + { + Init(str); + } + + explicit + nsTPromiseFlatString_CharT( const abstract_string_type& readable ) + : string_type() + { + Init(readable); + } + + explicit + nsTPromiseFlatString_CharT( const substring_tuple_type& tuple ) + : string_type() + { + // nothing else to do here except assign the value of the tuple + // into ourselves. + Assign(tuple); + } + }; + +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTAString_CharT& str ) + { + return nsTPromiseFlatString_CharT(str); + } + + // e.g., PromiseFlatCString(Substring(s)) +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTSubstring_CharT& frag ) + { + return nsTPromiseFlatString_CharT(frag); + } + + // e.g., PromiseFlatCString(a + b) +inline +const nsTPromiseFlatString_CharT +TPromiseFlatString_CharT( const nsTSubstringTuple_CharT& tuple ) + { + return nsTPromiseFlatString_CharT(tuple); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTString.h b/src/libs/xpcom18a4/xpcom/string/public/nsTString.h new file mode 100644 index 00000000..2ef241b2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTString.h @@ -0,0 +1,721 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Rick Gessner (original author) + * Scott Collins + * Darin Fisher + * + * 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 is the canonical null-terminated string class. All subclasses + * promise null-terminated storage. Instances of this class allocate + * strings on the heap. + * + * This class is also known as nsAFlat[C]String, where "flat" is used + * to denote a null-terminated string. + */ +class nsTString_CharT : public nsTSubstring_CharT + { + public: + + typedef nsTString_CharT self_type; + + public: + + /** + * constructors + */ + + nsTString_CharT() + : substring_type() {} + + explicit + nsTString_CharT( char_type c ) + : substring_type() + { + Assign(c); + } + + explicit + nsTString_CharT( const char_type* data, size_type length = size_type(-1) ) + : substring_type() + { + Assign(data, length); + } + + nsTString_CharT( const self_type& str ) + : substring_type() + { + Assign(str); + } + + nsTString_CharT( const substring_tuple_type& tuple ) + : substring_type() + { + Assign(tuple); + } + + explicit + nsTString_CharT( const abstract_string_type& readable ) + : substring_type() + { + Assign(readable); + } + + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + + /** + * returns the null-terminated string + */ + + const char_type* get() const + { + return mData; + } + + + /** + * returns character at specified index. + * + * NOTE: unlike nsTSubstring::CharAt, this function allows you to index + * the null terminator character. + */ + + char_type CharAt( index_type i ) const + { + NS_ASSERTION(i <= mLength, "index exceeds allowable range"); + return mData[i]; + } + + char_type operator[]( index_type i ) const + { + return CharAt(i); + } + + +#if MOZ_STRING_WITH_OBSOLETE_API + + + /** + * Search for the given substring within this string. + * + * @param aString is substring to be sought in this + * @param aIgnoreCase selects case sensitivity + * @param aOffset tells us where in this string to start searching + * @param aCount tells us how far from the offset we are to search. Use + * -1 to search the whole string. + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 Find( const nsCString& aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 Find( const char* aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 Find( const nsAFlatString& aString, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 Find( const PRUnichar* aString, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; +#endif + + + /** + * This methods scans the string backwards, looking for the given string + * + * @param aString is substring to be sought in this + * @param aIgnoreCase tells us whether or not to do caseless compare + * @param aOffset tells us where in this string to start searching. + * Use -1 to search from the end of the string. + * @param aCount tells us how many iterations to make starting at the + * given offset. + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 RFind( const nsCString& aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFind( const char* aCString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 RFind( const nsAFlatString& aString, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFind( const PRUnichar* aString, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; +#endif + + + /** + * Search for given char within this string + * + * @param aChar is the character to search for + * @param aOffset tells us where in this strig to start searching + * @param aCount tells us how far from the offset we are to search. + * Use -1 to search the whole string. + * @return offset in string, or kNotFound + */ + + // PRInt32 FindChar( PRUnichar aChar, PRInt32 aOffset=0, PRInt32 aCount=-1 ) const; + NS_COM PRInt32 RFindChar( PRUnichar aChar, PRInt32 aOffset=-1, PRInt32 aCount=-1 ) const; + + + /** + * This method searches this string for the first character found in + * the given string. + * + * @param aString contains set of chars to be found + * @param aOffset tells us where in this string to start searching + * (counting from left) + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 FindCharInSet( const char* aString, PRInt32 aOffset=0 ) const; + PRInt32 FindCharInSet( const self_type& aString, PRInt32 aOffset=0 ) const + { + return FindCharInSet(aString.get(), aOffset); + } + +#ifdef CharT_is_PRUnichar + NS_COM PRInt32 FindCharInSet( const PRUnichar* aString, PRInt32 aOffset=0 ) const; +#endif + + + /** + * This method searches this string for the last character found in + * the given string. + * + * @param aString contains set of chars to be found + * @param aOffset tells us where in this string to start searching + * (counting from left) + * @return offset in string, or kNotFound + */ + + NS_COM PRInt32 RFindCharInSet( const char_type* aString, PRInt32 aOffset=-1 ) const; + PRInt32 RFindCharInSet( const self_type& aString, PRInt32 aOffset=-1 ) const + { + return RFindCharInSet(aString.get(), aOffset); + } + + + /** + * Compares a given string to this string. + * + * @param aString is the string to be compared + * @param aIgnoreCase tells us how to treat case + * @param aCount tells us how many chars to compare + * @return -1,0,1 + */ + +#ifdef CharT_is_char + NS_COM PRInt32 Compare( const char* aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aCount=-1 ) const; +#endif + + + /** + * Equality check between given string and this string. + * + * @param aString is the string to check + * @param aIgnoreCase tells us how to treat case + * @param aCount tells us how many chars to compare + * @return boolean + */ +#ifdef CharT_is_char + PRBool EqualsIgnoreCase( const char* aString, PRInt32 aCount=-1 ) const { + return Compare(aString, PR_TRUE, aCount) == 0; + } +#else + NS_COM PRBool EqualsIgnoreCase( const char* aString, PRInt32 aCount=-1 ) const; + + + /** + * Copies data from internal buffer onto given char* buffer + * + * NOTE: This only copies as many chars as will fit in given buffer (clips) + * @param aBuf is the buffer where data is stored + * @param aBuflength is the max # of chars to move to buffer + * @param aOffset is the offset to copy from + * @return ptr to given buffer + */ + + NS_COM char* ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset=0 ) const; + +#endif // !CharT_is_PRUnichar + + /** + * Perform string to float conversion. + * + * @param aErrorCode will contain error if one occurs + * @return float rep of string value + */ + NS_COM float ToFloat( PRInt32* aErrorCode ) const; + + + /** + * Perform string to int conversion. + * @param aErrorCode will contain error if one occurs + * @param aRadix tells us which radix to assume; kAutoDetect tells us to determine the radix for you. + * @return int rep of string value, and possible (out) error code + */ + NS_COM PRInt32 ToInteger( PRInt32* aErrorCode, PRUint32 aRadix=kRadix10 ) const; + + + /** + * |Left|, |Mid|, and |Right| are annoying signatures that seem better almost + * any _other_ way than they are now. Consider these alternatives + * + * aWritable = aReadable.Left(17); // ...a member function that returns a |Substring| + * aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring| + * Left(aReadable, 17, aWritable); // ...a global function that does the assignment + * + * as opposed to the current signature + * + * aReadable.Left(aWritable, 17); // ...a member function that does the assignment + * + * or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality + * + * aWritable = Substring(aReadable, 0, 17); + */ + + NS_COM size_type Mid( self_type& aResult, PRUint32 aStartPos, PRUint32 aCount ) const; + + size_type Left( self_type& aResult, size_type aCount ) const + { + return Mid(aResult, 0, aCount); + } + + size_type Right( self_type& aResult, size_type aCount ) const + { + aCount = NS_MIN(mLength, aCount); + return Mid(aResult, mLength - aCount, aCount); + } + + + /** + * Set a char inside this string at given index + * + * @param aChar is the char you want to write into this string + * @param anIndex is the ofs where you want to write the given char + * @return TRUE if successful + */ + + NS_COM PRBool SetCharAt( PRUnichar aChar, PRUint32 aIndex ); + + + /** + * These methods are used to remove all occurances of the + * characters found in aSet from this string. + * + * @param aSet -- characters to be cut from this + */ + NS_COM void StripChars( const char* aSet ); + + + /** + * This method is used to remove all occurances of aChar from this + * string. + * + * @param aChar -- char to be stripped + * @param aOffset -- where in this string to start stripping chars + */ + + NS_COM void StripChar( char_type aChar, PRInt32 aOffset=0 ); + + + /** + * This method strips whitespace throughout the string. + */ + NS_COM void StripWhitespace(); + + + /** + * swaps occurence of 1 string for another + */ + + NS_COM void ReplaceChar( char_type aOldChar, char_type aNewChar ); + NS_COM void ReplaceChar( const char* aSet, char_type aNewChar ); + NS_COM void ReplaceSubstring( const self_type& aTarget, const self_type& aNewValue); + NS_COM void ReplaceSubstring( const char_type* aTarget, const char_type* aNewValue); + + + /** + * This method trims characters found in aTrimSet from + * either end of the underlying string. + * + * @param aSet -- contains chars to be trimmed from both ends + * @param aEliminateLeading + * @param aEliminateTrailing + * @param aIgnoreQuotes -- if true, causes surrounding quotes to be ignored + * @return this + */ + NS_COM void Trim( const char* aSet, PRBool aEliminateLeading=PR_TRUE, PRBool aEliminateTrailing=PR_TRUE, PRBool aIgnoreQuotes=PR_FALSE ); + + /** + * This method strips whitespace from string. + * You can control whether whitespace is yanked from start and end of + * string as well. + * + * @param aEliminateLeading controls stripping of leading ws + * @param aEliminateTrailing controls stripping of trailing ws + */ + NS_COM void CompressWhitespace( PRBool aEliminateLeading=PR_TRUE, PRBool aEliminateTrailing=PR_TRUE ); + + + /** + * assign/append/insert with _LOSSY_ conversion + */ + + NS_COM void AssignWithConversion( const nsTAString_IncompatibleCharT& aString ); + NS_COM void AssignWithConversion( const incompatible_char_type* aData, PRInt32 aLength=-1 ); + + NS_COM void AppendWithConversion( const nsTAString_IncompatibleCharT& aString ); + NS_COM void AppendWithConversion( const incompatible_char_type* aData, PRInt32 aLength=-1 ); + + /** + * Append the given integer to this string + */ + NS_COM void AppendInt( PRInt32 aInteger, PRInt32 aRadix=kRadix10 ); //radix=8,10 or 16 + + /** + * Append the given unsigned integer to this string + */ + inline void AppendInt( PRUint32 aInteger, PRInt32 aRadix = kRadix10 ) + { + AppendInt(PRInt32(aInteger), aRadix); + } + + /** + * Append the given 64-bit integer to this string. + * @param aInteger The integer to append + * @param aRadix The radix to use; can be 8, 10 or 16. + */ + NS_COM void AppendInt( PRInt64 aInteger, PRInt32 aRadix=kRadix10 ); + + /** + * Append the given float to this string + */ + + NS_COM void AppendFloat( double aFloat ); + +#endif // !MOZ_STRING_WITH_OBSOLETE_API + + + protected: + + explicit + nsTString_CharT( PRUint32 flags ) + : substring_type(flags) {} + + // allow subclasses to initialize fields directly + nsTString_CharT( char_type* data, size_type length, PRUint32 flags ) + : substring_type(data, length, flags) {} + }; + + +class nsTFixedString_CharT : public nsTString_CharT + { + public: + + typedef nsTFixedString_CharT self_type; + typedef nsTFixedString_CharT fixed_string_type; + + public: + + /** + * @param data + * fixed-size buffer to be used by the string (the contents of + * this buffer may be modified by the string) + * @param storageSize + * the size of the fixed buffer + * @param length (optional) + * the length of the string already contained in the buffer + */ + + nsTFixedString_CharT( char_type* data, size_type storageSize ) + : string_type(data, char_traits::length(data), F_TERMINATED | F_FIXED | F_CLASS_FIXED) + , mFixedCapacity(storageSize - 1) + , mFixedBuf(data) + {} + + nsTFixedString_CharT( char_type* data, size_type storageSize, size_type length ) + : string_type(data, length, F_TERMINATED | F_FIXED | F_CLASS_FIXED) + , mFixedCapacity(storageSize - 1) + , mFixedBuf(data) + { + // null-terminate + mFixedBuf[length] = char_type(0); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + protected: + + friend class nsTSubstring_CharT; + + size_type mFixedCapacity; + char_type *mFixedBuf; + }; + + + /** + * nsTAutoString_CharT + * + * Subclass of nsTString_CharT that adds support for stack-based string + * allocation. Do not allocate this class on the heap! ;-) + */ +class nsTAutoString_CharT : public nsTFixedString_CharT + { + public: + + typedef nsTAutoString_CharT self_type; + + public: + + /** + * constructors + */ + + nsTAutoString_CharT() + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + {} + + explicit + nsTAutoString_CharT( char_type c ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(c); + } + + explicit + nsTAutoString_CharT( const char_type* data, size_type length = size_type(-1) ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(data, length); + } + + nsTAutoString_CharT( const self_type& str ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(str); + } + + explicit + nsTAutoString_CharT( const substring_type& str ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(str); + } + + nsTAutoString_CharT( const substring_tuple_type& tuple ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(tuple); + } + + explicit + nsTAutoString_CharT( const abstract_string_type& readable ) + : fixed_string_type(mStorage, kDefaultStorageSize, 0) + { + Assign(readable); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + enum { kDefaultStorageSize = 64 }; + + private: + + char_type mStorage[kDefaultStorageSize]; + }; + + + /** + * nsTXPIDLString extends nsTString such that: + * + * (1) mData can be null + * (2) objects of this type can be automatically cast to |const CharT*| + * (3) getter_Copies method is supported to adopt data + */ +class nsTXPIDLString_CharT : public nsTString_CharT + { + public: + + typedef nsTXPIDLString_CharT self_type; + + public: + + nsTXPIDLString_CharT() + : string_type(NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED) {} + + // copy-constructor required to avoid default + nsTXPIDLString_CharT( const self_type& str ) + : string_type(NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED | F_VOIDED) + { + Assign(str); + } + + // return nsnull if we are voided + const char_type* get() const + { + return (mFlags & F_VOIDED) ? nsnull : mData; + } + + // this case operator is the reason why this class cannot just be a + // typedef for nsTString + operator const char_type*() const + { + return get(); + } + + // need this to diambiguous operator[int] + char_type operator[]( PRInt32 i ) const + { + return CharAt(index_type(i)); + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + }; + + + /** + * getter_Copies support for use with raw string out params: + * + * NS_IMETHOD GetBlah(char**); + * + * void some_function() + * { + * nsXPIDLCString blah; + * GetBlah(getter_Copies(blah)); + * // ... + * } + */ +class nsTGetterCopies_CharT + { + public: + typedef CharT char_type; + + nsTGetterCopies_CharT(nsTXPIDLString_CharT& str) + : mString(str), mData(nsnull) {} + + ~nsTGetterCopies_CharT() + { + mString.Adopt(mData); // OK if mData is null + } + + operator char_type**() + { + return &mData; + } + + private: + nsTXPIDLString_CharT& mString; + char_type* mData; + }; + +inline +nsTGetterCopies_CharT +getter_Copies( nsTXPIDLString_CharT& aString ) + { + return nsTGetterCopies_CharT(aString); + } + + + /** + * nsTAdoptingString extends nsTXPIDLString such that: + * + * (1) Adopt given string on construction or assignment, i.e. take + * the value of what's given, and make what's given forget its + * value. Note that this class violates constness in a few + * places. Be careful! + */ +class nsTAdoptingString_CharT : public nsTXPIDLString_CharT + { + public: + + typedef nsTAdoptingString_CharT self_type; + + public: + + explicit nsTAdoptingString_CharT() {} + explicit nsTAdoptingString_CharT(char_type* str, size_type length = size_type(-1)) + { + Adopt(str, length); + } + + // copy-constructor required to adopt on copy. Note that this + // will violate the constness of |str| in the operator=() + // call. |str| will be truncated as a side-effect of this + // constructor. + nsTAdoptingString_CharT( const self_type& str ) +#ifdef VBOX /* bird: shut up annoying warnings */ + : nsTXPIDLString_CharT() +#endif + { + *this = str; + } + + // |operator=| does not inherit, so we must define our own + self_type& operator=( const substring_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + // Adopt(), if possible, when assigning to a self_type&. Note + // that this violates the constness of str, str is always + // truncated when this operator is called. + NS_COM self_type& operator=( const self_type& str ); + + private: + // NOT TO BE IMPLEMENTED. + self_type& operator=( const char_type* data ); + self_type& operator=( char_type* data ); + }; + diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h new file mode 100644 index 00000000..aaaf5a64 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstring.h @@ -0,0 +1,575 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * nsTSubstring + * + * The base string type. This type is not instantiated directly. A sub- + * class is instantiated instead. For example, see nsTString. + * + * This type works like nsTAString except that it does not have the ABI + * requirements of that interface. Like nsTAString, nsTSubstring + * represents a single contiguous array of characters that may or may not + * be null-terminated. + * + * Many of the accessors on nsTSubstring are inlined as an optimization. + * + * This class is also known as "nsASingleFragmentC?String". + */ +class nsTSubstring_CharT : public nsTAString_CharT + { + public: + + typedef nsTSubstring_CharT self_type; + typedef nsTString_CharT string_type; + + typedef char_type* char_iterator; + typedef const char_type* const_char_iterator; + + public: + + /** + * reading iterators + */ + + const_char_iterator BeginReading() const { return mData; } + const_char_iterator EndReading() const { return mData + mLength; } + + /** + * deprecated reading iterators + */ + + const_iterator& BeginReading( const_iterator& iter ) const + { + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mStart; + return iter; + } + + const_iterator& EndReading( const_iterator& iter ) const + { + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mEnd; + return iter; + } + + const_char_iterator& BeginReading( const_char_iterator& iter ) const + { + return iter = mData; + } + + const_char_iterator& EndReading( const_char_iterator& iter ) const + { + return iter = mData + mLength; + } + + + /** + * writing iterators + */ + + char_iterator BeginWriting() { EnsureMutable(); return mData; } + char_iterator EndWriting() { EnsureMutable(); return mData + mLength; } + + /** + * deprecated writing iterators + */ + + iterator& BeginWriting( iterator& iter ) + { + EnsureMutable(); + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mStart; + return iter; + } + + iterator& EndWriting( iterator& iter ) + { + EnsureMutable(); + iter.mStart = mData; + iter.mEnd = mData + mLength; + iter.mPosition = iter.mEnd; + return iter; + } + + char_iterator& BeginWriting( char_iterator& iter ) + { + EnsureMutable(); + return iter = mData; + } + + char_iterator& EndWriting( char_iterator& iter ) + { + EnsureMutable(); + return iter = mData + mLength; + } + + + /** + * accessors + */ + + // returns pointer to string data (not necessarily null-terminated) + const char_type *Data() const + { + return mData; + } + + size_type Length() const + { + return mLength; + } + + PRBool IsEmpty() const + { + return mLength == 0; + } + + PRBool IsVoid() const + { + return mFlags & F_VOIDED; + } + + PRBool IsTerminated() const + { + return mFlags & F_TERMINATED; + } + + char_type CharAt( index_type i ) const + { + NS_ASSERTION(i < mLength, "index exceeds allowable range"); + return mData[i]; + } + + char_type operator[]( index_type i ) const + { + return CharAt(i); + } + + char_type First() const + { + NS_ASSERTION(mLength > 0, "|First()| called on an empty string"); + return mData[0]; + } + + inline + char_type Last() const + { + NS_ASSERTION(mLength > 0, "|Last()| called on an empty string"); + return mData[mLength - 1]; + } + + NS_COM size_type NS_FASTCALL CountChar( char_type ) const; + NS_COM PRInt32 NS_FASTCALL FindChar( char_type, index_type offset = 0 ) const; + + + /** + * equality + */ + + NS_COM PRBool NS_FASTCALL Equals( const self_type& ) const; + NS_COM PRBool NS_FASTCALL Equals( const self_type&, const comparator_type& ) const; + + NS_COM PRBool NS_FASTCALL Equals( const abstract_string_type& readable ) const; + NS_COM PRBool NS_FASTCALL Equals( const abstract_string_type& readable, const comparator_type& comp ) const; + + NS_COM PRBool NS_FASTCALL Equals( const char_type* data ) const; + NS_COM PRBool NS_FASTCALL Equals( const char_type* data, const comparator_type& comp ) const; + + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when you know the + * length of 'data'. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data, size_type len ) const; + /** + * An efficient comparison with ASCII that can be used even + * for wide strings. Call this version when 'data' is + * null-terminated. + */ + NS_COM PRBool NS_FASTCALL EqualsASCII( const char* data ) const; + + // EqualsLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. + // The template trick to acquire the array length at compile time without + // using a macro is due to Corey Kosak, with much thanks. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool EqualsLiteral( const char* str ) const + { + return EqualsASCII(str); + } +#else + template + inline PRBool EqualsLiteral( const char (&str)[N] ) const + { + return EqualsASCII(str, N-1); + } + template + inline PRBool EqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return EqualsASCII(s, N-1); + } +#endif + + // The LowerCaseEquals methods compare the lower case version of + // this string to some ASCII/Literal string. The ASCII string is + // *not* lowercased for you. If you compare to an ASCII or literal + // string that contains an uppercase character, it is guaranteed to + // return false. We will throw assertions too. + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data, size_type len ) const; + NS_COM PRBool NS_FASTCALL LowerCaseEqualsASCII( const char* data ) const; + + // LowerCaseEqualsLiteral must ONLY be applied to an actual + // literal string. Do not attempt to use it with a regular char* + // pointer, or with a char array variable. Use + // LowerCaseEqualsASCII for them. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + inline PRBool LowerCaseEqualsLiteral( const char* str ) const + { + return LowerCaseEqualsASCII(str); + } +#else + template + inline PRBool LowerCaseEqualsLiteral( const char (&str)[N] ) const + { + return LowerCaseEqualsASCII(str, N-1); + } + template + inline PRBool LowerCaseEqualsLiteral( char (&str)[N] ) const + { + const char* s = str; + return LowerCaseEqualsASCII(s, N-1); + } +#endif + + /** + * assignment + */ + + void Assign( char_type c ) { Assign(&c, 1); } + NS_COM void NS_FASTCALL Assign( const char_type* data, size_type length = size_type(-1) ); + NS_COM void NS_FASTCALL Assign( const self_type& ); + NS_COM void NS_FASTCALL Assign( const substring_tuple_type& ); + NS_COM void NS_FASTCALL Assign( const abstract_string_type& ); + + NS_COM void NS_FASTCALL AssignASCII( const char* data, size_type length ); + NS_COM void NS_FASTCALL AssignASCII( const char* data ); + + // AssignLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AssignASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AssignLiteral( const char* str ) + { AssignASCII(str); } +#else + template + void AssignLiteral( const char (&str)[N] ) + { AssignASCII(str, N-1); } + template + void AssignLiteral( char (&str)[N] ) + { AssignASCII(str, N-1); } +#endif + + self_type& operator=( char_type c ) { Assign(c); return *this; } + self_type& operator=( const char_type* data ) { Assign(data); return *this; } + self_type& operator=( const self_type& str ) { Assign(str); return *this; } + self_type& operator=( const substring_tuple_type& tuple ) { Assign(tuple); return *this; } + self_type& operator=( const abstract_string_type& readable ) { Assign(readable); return *this; } + + NS_COM void NS_FASTCALL Adopt( char_type* data, size_type length = size_type(-1) ); + + + /** + * buffer manipulation + */ + + void Replace( index_type cutStart, size_type cutLength, char_type c ) { Replace(cutStart, cutLength, &c, 1); } + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ); + void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); } + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ); + NS_COM void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const abstract_string_type& readable ); + + NS_COM void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) ); + + void Append( char_type c ) { Replace(mLength, 0, c); } + void Append( const char_type* data, size_type length = size_type(-1) ) { Replace(mLength, 0, data, length); } + void Append( const self_type& str ) { Replace(mLength, 0, str); } + void Append( const substring_tuple_type& tuple ) { Replace(mLength, 0, tuple); } + void Append( const abstract_string_type& readable ) { Replace(mLength, 0, readable); } + + void AppendASCII( const char* data, size_type length = size_type(-1) ) { ReplaceASCII(mLength, 0, data, length); } + + // AppendLiteral must ONLY be applied to an actual literal string. + // Do not attempt to use it with a regular char* pointer, or with a char + // array variable. Use AppendASCII for those. +#ifdef NS_DISABLE_LITERAL_TEMPLATE + void AppendLiteral( const char* str ) + { AppendASCII(str); } +#else + template + void AppendLiteral( const char (&str)[N] ) + { AppendASCII(str, N-1); } + template + void AppendLiteral( char (&str)[N] ) + { AppendASCII(str, N-1); } +#endif + + self_type& operator+=( char_type c ) { Append(c); return *this; } + self_type& operator+=( const char_type* data ) { Append(data); return *this; } + self_type& operator+=( const self_type& str ) { Append(str); return *this; } + self_type& operator+=( const substring_tuple_type& tuple ) { Append(tuple); return *this; } + self_type& operator+=( const abstract_string_type& readable ) { Append(readable); return *this; } + + void Insert( char_type c, index_type pos ) { Replace(pos, 0, c); } + void Insert( const char_type* data, index_type pos, size_type length = size_type(-1) ) { Replace(pos, 0, data, length); } + void Insert( const self_type& str, index_type pos ) { Replace(pos, 0, str); } + void Insert( const substring_tuple_type& tuple, index_type pos ) { Replace(pos, 0, tuple); } + void Insert( const abstract_string_type& readable, index_type pos ) { Replace(pos, 0, readable); } + + void Cut( index_type cutStart, size_type cutLength ) { Replace(cutStart, cutLength, char_traits::sEmptyBuffer, 0); } + + + /** + * buffer sizing + */ + + NS_COM void NS_FASTCALL SetCapacity( size_type capacity ); + + NS_COM void NS_FASTCALL SetLength( size_type ); + + void Truncate( size_type newLength = 0 ) + { + NS_ASSERTION(newLength <= mLength, "Truncate cannot make string longer"); + SetLength(newLength); + } + + + /** + * string data is never null, but can be marked void. if true, the + * string will be truncated. @see nsTSubstring::IsVoid + */ + + NS_COM void NS_FASTCALL SetIsVoid( PRBool ); + + + public: + + /** + * this is public to support automatic conversion of tuple to string + * base type, which helps avoid converting to nsTAString. + */ + nsTSubstring_CharT(const substring_tuple_type& tuple) + : abstract_string_type(nsnull, 0, F_NONE) + { + Assign(tuple); + } + + protected: + + friend class nsTObsoleteAStringThunk_CharT; + friend class nsTAString_CharT; + friend class nsTSubstringTuple_CharT; + + // XXX GCC 3.4 needs this :-( + friend class nsTPromiseFlatString_CharT; + + // default initialization + nsTSubstring_CharT() + : abstract_string_type( + NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer), 0, F_TERMINATED) {} + + // allow subclasses to initialize fields directly + nsTSubstring_CharT( char_type *data, size_type length, PRUint32 flags ) + : abstract_string_type(data, length, flags) {} + + // version of constructor that leaves mData and mLength uninitialized + explicit + nsTSubstring_CharT( PRUint32 flags ) + : abstract_string_type(flags) {} + + // copy-constructor, constructs as dependent on given object + // (NOTE: this is for internal use only) + nsTSubstring_CharT( const self_type& str ) + : abstract_string_type( + str.mData, str.mLength, str.mFlags & (F_TERMINATED | F_VOIDED)) {} + + /** + * this function releases mData and does not change the value of + * any of its member variables. inotherwords, this function acts + * like a destructor. + */ + void NS_FASTCALL Finalize(); + + /** + * this function prepares mData to be mutated. + * + * @param capacity specifies the required capacity of mData + * @param old_data returns null or the old value of mData + * @param old_flags returns 0 or the old value of mFlags + * + * if mData is already mutable and of sufficient capacity, then this + * function will return immediately. otherwise, it will either resize + * mData or allocate a new shared buffer. if it needs to allocate a + * new buffer, then it will return the old buffer and the corresponding + * flags. this allows the caller to decide when to free the old data. + * + * XXX we should expose a way for subclasses to free old_data. + */ + PRBool NS_FASTCALL MutatePrep( size_type capacity, char_type** old_data, PRUint32* old_flags ); + + /** + * this function prepares a section of mData to be modified. if + * necessary, this function will reallocate mData and possibly move + * existing data to open up the specified section. + * + * @param cutStart specifies the starting offset of the section + * @param cutLength specifies the length of the section to be replaced + * @param newLength specifies the length of the new section + * + * for example, suppose mData contains the string "abcdef" then + * + * ReplacePrep(2, 3, 4); + * + * would cause mData to look like "ab____f" where the characters + * indicated by '_' have an unspecified value and can be freely + * modified. this function will null-terminate mData upon return. + */ + void NS_FASTCALL ReplacePrep( index_type cutStart, size_type cutLength, size_type newLength ); + + /** + * returns the number of writable storage units starting at mData. + * the value does not include space for the null-terminator character. + * + * NOTE: this function returns size_type(-1) if mData is immutable. + */ + size_type NS_FASTCALL Capacity() const; + + /** + * this helper function can be called prior to directly manipulating + * the contents of mData. see, for example, BeginWriting. + */ + NS_COM void NS_FASTCALL EnsureMutable(); + + /** + * returns true if this string overlaps with the given string fragment. + */ + PRBool IsDependentOn( const char_type *start, const char_type *end ) const + { + /** + * if it _isn't_ the case that one fragment starts after the other ends, + * or ends before the other starts, then, they conflict: + * + * !(f2.begin >= f1.end || f2.end <= f1.begin) + * + * Simplified, that gives us: + */ + return ( start < (mData + mLength) && end > mData ); + } + + /** + * this helper function stores the specified dataFlags in mFlags + */ + void SetDataFlags(PRUint32 dataFlags) + { + NS_ASSERTION((dataFlags & 0xFFFF0000) == 0, "bad flags"); + mFlags = dataFlags | (mFlags & 0xFFFF0000); + } + + public: + + // mFlags is a bitwise combination of the following flags. the meaning + // and interpretation of these flags is an implementation detail. + // + // NOTE: these flags are declared public _only_ for convenience inside + // the string implementation. + + enum + { + F_NONE = 0, // no flags + + // data flags are in the lower 16-bits + F_TERMINATED = 1 << 0, // IsTerminated returns true + F_VOIDED = 1 << 1, // IsVoid returns true + F_SHARED = 1 << 2, // mData points to a heap-allocated, shared buffer + F_OWNED = 1 << 3, // mData points to a heap-allocated, raw buffer + F_FIXED = 1 << 4, // mData points to a fixed-size writable, dependent buffer + + // class flags are in the upper 16-bits + F_CLASS_FIXED = 1 << 16 // indicates that |this| is of type nsTFixedString + }; + + // + // Some terminology: + // + // "dependent buffer" A dependent buffer is one that the string class + // does not own. The string class relies on some + // external code to ensure the lifetime of the + // dependent buffer. + // + // "shared buffer" A shared buffer is one that the string class + // allocates. When it allocates a shared string + // buffer, it allocates some additional space at + // the beginning of the buffer for additional + // fields, including a reference count and a + // buffer length. See nsStringHeader. + // + // "adopted buffer" An adopted buffer is a raw string buffer + // allocated on the heap (using nsMemory::Alloc) + // of which the string class subsumes ownership. + // + // Some comments about the string flags: + // + // F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive. They + // indicate the allocation type of mData. If none of these flags + // are set, then the string buffer is dependent. + // + // F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED. This is because + // the string classes always allocate null-terminated buffers, and + // non-terminated substrings are always dependent. + // + // F_VOIDED implies F_TERMINATED, and moreover it implies that mData + // points to char_traits::sEmptyBuffer. Therefore, F_VOIDED is + // mutually exclusive with F_SHARED, F_OWNED, and F_FIXED. + // + }; diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h new file mode 100644 index 00000000..2ded17d5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsTSubstringTuple.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * nsTSubstringTuple_CharT + * + * Represents a tuple of string fragments. Built as a recursive binary tree. + * It is used to implement the concatenation of two or more string objects. + * + * NOTE: This class is a private implementation detail and should never be + * referenced outside the string code. + */ +class nsTSubstringTuple_CharT + { + public: + + typedef CharT char_type; + typedef nsCharTraits char_traits; + + typedef nsTSubstringTuple_CharT self_type; + typedef nsTSubstring_CharT substring_type; + typedef nsTString_CharT string_type; + typedef nsTAString_CharT abstract_string_type; + typedef nsTObsoleteAString_CharT obsolete_string_type; + + typedef PRUint32 size_type; + + public: + + nsTSubstringTuple_CharT(const abstract_string_type* a, const abstract_string_type* b) + : mHead(nsnull) + , mFragA(a) + , mFragB(b) {} + + nsTSubstringTuple_CharT(const self_type& head, const abstract_string_type* b) + : mHead(&head) + , mFragA(nsnull) // this fragment is ignored when head != nsnull + , mFragB(b) {} + + /** + * computes the aggregate string length + */ + NS_COM size_type Length() const; + + /** + * writes the aggregate string to the given buffer. bufLen is assumed + * to be equal to or greater than the value returned by the Length() + * method. the string written to |buf| is not null-terminated. + */ + NS_COM void WriteTo(char_type *buf, PRUint32 bufLen) const; + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + NS_COM PRBool IsDependentOn(const char_type *start, const char_type *end) const; + + private: + + const self_type* mHead; + const abstract_string_type* mFragA; + const abstract_string_type* mFragB; + }; + +inline +const nsTSubstringTuple_CharT +operator+(const nsTAString_CharT& a, const nsTAString_CharT& b) + { + return nsTSubstringTuple_CharT(&a, &b); + } + +inline +const nsTSubstringTuple_CharT +operator+(const nsTSubstringTuple_CharT& head, const nsTAString_CharT& b) + { + return nsTSubstringTuple_CharT(head, &b); + } diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h b/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h new file mode 100644 index 00000000..c91079c2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsUTF8Utils.h @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Peter Annema (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsUTF8Utils_h_ +#define nsUTF8Utils_h_ + +class UTF8traits + { + public: + static PRBool isASCII(char c) { return (c & 0x80) == 0x00; } + static PRBool isInSeq(char c) { return (c & 0xC0) == 0x80; } + static PRBool is2byte(char c) { return (c & 0xE0) == 0xC0; } + static PRBool is3byte(char c) { return (c & 0xF0) == 0xE0; } + static PRBool is4byte(char c) { return (c & 0xF8) == 0xF0; } + static PRBool is5byte(char c) { return (c & 0xFC) == 0xF8; } + static PRBool is6byte(char c) { return (c & 0xFE) == 0xFC; } + }; + +#define PLANE1_BASE 0x00010000 +#define UCS2_REPLACEMENT_CHAR 0xfffd + +#ifdef __GNUC__ +#define NS_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define NS_ALWAYS_INLINE +#endif + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for converting + * UTF-8 to UTF-16 + */ +class ConvertUTF8toUTF16 + { + public: + typedef nsACString::char_type value_type; + typedef nsAString::char_type buffer_type; + + ConvertUTF8toUTF16( buffer_type* aBuffer ) + : mStart(aBuffer), mBuffer(aBuffer), mErrorEncountered(PR_FALSE) {} + + size_t Length() const { return mBuffer - mStart; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + if ( mErrorEncountered ) + return N; + + // algorithm assumes utf8 units won't + // be spread across fragments + const value_type* p = start; + const value_type* end = start + N; + buffer_type* out = mBuffer; + for ( ; p != end /* && *p */; ) + { + char c = *p++; + + if ( UTF8traits::isASCII(c) ) + { + *out++ = buffer_type(c); + continue; + } + + PRUint32 ucs4; + PRUint32 minUcs4; + PRInt32 state = 0; + + if ( UTF8traits::is2byte(c) ) + { + ucs4 = (PRUint32(c) << 6) & 0x000007C0L; + state = 1; + minUcs4 = 0x00000080; + } + else if ( UTF8traits::is3byte(c) ) + { + ucs4 = (PRUint32(c) << 12) & 0x0000F000L; + state = 2; + minUcs4 = 0x00000800; + } + else if ( UTF8traits::is4byte(c) ) + { + ucs4 = (PRUint32(c) << 18) & 0x001F0000L; + state = 3; + minUcs4 = 0x00010000; + } + else if ( UTF8traits::is5byte(c) ) + { + ucs4 = (PRUint32(c) << 24) & 0x03000000L; + state = 4; + minUcs4 = 0x00200000; + } + else if ( UTF8traits::is6byte(c) ) + { + ucs4 = (PRUint32(c) << 30) & 0x40000000L; + state = 5; + minUcs4 = 0x04000000; + } + else + { + NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings."); + mErrorEncountered = PR_TRUE; + mBuffer = out; + return N; + } + + while ( state-- ) + { + c = *p++; + + if ( UTF8traits::isInSeq(c) ) + { + PRInt32 shift = state * 6; + ucs4 |= (PRUint32(c) & 0x3F) << shift; + } + else + { + NS_ERROR("not a UTF8 string"); + mErrorEncountered = PR_TRUE; + mBuffer = out; + return N; + } + } + + if ( ucs4 < minUcs4 ) + { + // Overlong sequence + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 <= 0xD7FF ) + { + *out++ = ucs4; + } + else if ( /* ucs4 >= 0xD800 && */ ucs4 <= 0xDFFF ) + { + // Surrogates + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 == 0xFFFE || ucs4 == 0xFFFF ) + { + // Prohibited characters + *out++ = UCS2_REPLACEMENT_CHAR; + } + else if ( ucs4 >= PLANE1_BASE ) + { + if ( ucs4 >= 0x00110000 ) + *out++ = UCS2_REPLACEMENT_CHAR; + else { + // surrogate, see unicode specification 3.7 for following math. + ucs4 -= PLANE1_BASE; + *out++ = (PRUnichar)(ucs4 >> 10) | 0xd800u; + *out++ = (PRUnichar)(ucs4 & 0x3ff) | 0xdc00u; + } + } + else + { + *out++ = ucs4; + } + } + mBuffer = out; + return p - start; + } + + void write_terminator() + { + *mBuffer = buffer_type(0); + } + + private: + buffer_type* const mStart; + buffer_type* mBuffer; + PRBool mErrorEncountered; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for computing + * the length of the UTF-16 string equivalent to a UTF-8 string. + */ +class CalculateUTF8Length + { + public: + typedef nsACString::char_type value_type; + + CalculateUTF8Length() : mLength(0), mErrorEncountered(PR_FALSE) { } + + size_t Length() const { return mLength; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + // ignore any further requests + if ( mErrorEncountered ) + return N; + + // algorithm assumes utf8 units won't + // be spread across fragments + const value_type* p = start; + const value_type* end = start + N; + for ( ; p < end /* && *p */; ++mLength ) + { + if ( UTF8traits::isASCII(*p) ) + p += 1; + else if ( UTF8traits::is2byte(*p) ) + p += 2; + else if ( UTF8traits::is3byte(*p) ) + p += 3; + else if ( UTF8traits::is4byte(*p) ) { + p += 4; + // Because a UTF-8 sequence of 4 bytes represents a codepoint + // greater than 0xFFFF, it will become a surrogate pair in the + // UTF-16 string, so add 1 more to mLength. + // This doesn't happen with is5byte and is6byte because they + // are illegal UTF-8 sequences (greater than 0x10FFFF) so get + // converted to a single replacement character. + // + // XXX: if the 4-byte sequence is an illegal non-shortest form, + // it also gets converted to a replacement character, so + // mLength will be off by one in this case. + ++mLength; + } + else if ( UTF8traits::is5byte(*p) ) + p += 5; + else if ( UTF8traits::is6byte(*p) ) + p += 6; + else + { + break; + } + } + if ( p != end ) + { + NS_ERROR("Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings."); + mErrorEncountered = PR_TRUE; + mLength = 0; + return N; + } + return p - start; + } + + private: + size_t mLength; + PRBool mErrorEncountered; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for converting + * UTF-16 to UTF-8. + */ +class ConvertUTF16toUTF8 + { + public: + typedef nsAString::char_type value_type; + typedef nsACString::char_type buffer_type; + + // The error handling here is more lenient than that in + // |ConvertUTF8toUTF16|, but it's that way for backwards + // compatibility. + + ConvertUTF16toUTF8( buffer_type* aBuffer ) + : mStart(aBuffer), mBuffer(aBuffer) {} + + size_t Size() const { return mBuffer - mStart; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + buffer_type *out = mBuffer; // gcc isn't smart enough to do this! + + for (const value_type *p = start, *end = start + N; p < end; ++p ) + { + value_type c = *p; + if (! (c & 0xFF80)) // U+0000 - U+007F + { + *out++ = (char)c; + } + else if (! (c & 0xF800)) // U+0100 - U+07FF + { + *out++ = 0xC0 | (char)(c >> 6); + *out++ = 0x80 | (char)(0x003F & c); + } + else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF + { + *out++ = 0xE0 | (char)(c >> 12); + *out++ = 0x80 | (char)(0x003F & (c >> 6)); + *out++ = 0x80 | (char)(0x003F & c ); + } + else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF + { + // D800- DBFF - High Surrogate + // N = (H- D800) *400 + 10000 + ... + PRUint32 ucs4 = 0x10000 + ((0x03FF & c) << 10); + + ++p; + if (p == end) + { + NS_ERROR("Surrogate pair split between fragments"); + mBuffer = out; + return N; + } + c = *p; + + if (0xDC00 == (0xFC00 & c)) + { + // DC00- DFFF - Low Surrogate + // N += ( L - DC00 ) + ucs4 |= (0x03FF & c); + + // 0001 0000-001F FFFF + *out++ = 0xF0 | (char)(ucs4 >> 18); + *out++ = 0x80 | (char)(0x003F & (ucs4 >> 12)); + *out++ = 0x80 | (char)(0x003F & (ucs4 >> 6)); + *out++ = 0x80 | (char)(0x003F & ucs4); + } + else + { + NS_ERROR("got a High Surrogate but no low surrogate"); + // output nothing. + } + } + else // U+DC00 - U+DFFF + { + // DC00- DFFF - Low Surrogate + NS_ERROR("got a low Surrogate but no high surrogate"); + // output nothing. + } + } + + mBuffer = out; + return N; + } + + void write_terminator() + { + *mBuffer = buffer_type(0); + } + + private: + buffer_type* const mStart; + buffer_type* mBuffer; + }; + +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for computing + * the number of bytes a UTF-16 would occupy in UTF-8. + */ +class CalculateUTF8Size + { + public: + typedef nsAString::char_type value_type; + + CalculateUTF8Size() + : mSize(0) { } + + size_t Size() const { return mSize; } + + PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N ) + { + // Assume UCS2 surrogate pairs won't be spread across fragments. + for (const value_type *p = start, *end = start + N; p < end; ++p ) + { + value_type c = *p; + if (! (c & 0xFF80)) // U+0000 - U+007F + mSize += 1; + else if (! (c & 0xF800)) // U+0100 - U+07FF + mSize += 2; + else if (0xD800 != (0xF800 & c)) // U+0800 - U+D7FF,U+E000 - U+FFFF + mSize += 3; + else if (0xD800 == (0xFC00 & c)) // U+D800 - U+DBFF + { + ++p; + if (p == end) + { + NS_ERROR("Surrogate pair split between fragments"); + return N; + } + c = *p; + + if (0xDC00 == (0xFC00 & c)) + mSize += 4; + else + NS_ERROR("got a high Surrogate but no low surrogate"); + } + else // U+DC00 - U+DFFF + NS_ERROR("got a low Surrogate but no high surrogate"); + } + + return N; + } + + private: + size_t mSize; + }; + +/** + * A character sink that performs a |reinterpret_cast| style conversion + * between character types. + */ +template +class LossyConvertEncoding + { + public: + typedef FromCharT value_type; + + typedef FromCharT input_type; + typedef ToCharT output_type; + + typedef typename nsCharTraits::unsigned_char_type unsigned_input_type; + + public: + LossyConvertEncoding( output_type* aDestination ) : mDestination(aDestination) { } + + PRUint32 + write( const input_type* aSource, PRUint32 aSourceLength ) + { + const input_type* done_writing = aSource + aSourceLength; + while ( aSource < done_writing ) + *mDestination++ = (output_type)(unsigned_input_type)(*aSource++); // use old-style cast to mimic old |ns[C]String| behavior + return aSourceLength; + } + + void + write_terminator() + { + *mDestination = output_type(0); + } + + private: + output_type* mDestination; + }; + +#endif /* !defined(nsUTF8Utils_h_) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h b/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h new file mode 100644 index 00000000..c66a2d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/nsXPIDLString.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsXPIDLString_h___ +#define nsXPIDLString_h___ + +#ifndef nsString_h___ +#include "nsString.h" +#endif + +#endif /* !defined(nsXPIDLString_h___) */ diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h new file mode 100644 index 00000000..d0f3a907 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-char.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +#define CharT char +#define CharT_is_char 1 +#define nsTObsoleteAString_CharT nsObsoleteACString +#define nsTObsoleteAStringThunk_CharT nsObsoleteACStringThunk +#define nsTAString_CharT nsACString +#define nsTAString_IncompatibleCharT nsAString +#define nsTString_CharT nsCString +#define nsTFixedString_CharT nsFixedCString +#define nsTAutoString_CharT nsCAutoString +#define nsTSubstring_CharT nsCSubstring +#define nsTSubstringTuple_CharT nsCSubstringTuple +#define nsTStringComparator_CharT nsCStringComparator +#define nsTDefaultStringComparator_CharT nsDefaultCStringComparator +#define nsTDependentString_CharT nsDependentCString +#define nsTDependentSubstring_CharT nsDependentCSubstring +#define nsTXPIDLString_CharT nsXPIDLCString +#define nsTGetterCopies_CharT nsCGetterCopies +#define nsTAdoptingString_CharT nsAdoptingCString +#define nsTPromiseFlatString_CharT nsPromiseFlatCString +#define TPromiseFlatString_CharT PromiseFlatCString diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h new file mode 100644 index 00000000..c966dfbe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-def-unichar.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +#define CharT PRUnichar +#define CharT_is_PRUnichar 1 +#define nsTObsoleteAString_CharT nsObsoleteAString +#define nsTObsoleteAStringThunk_CharT nsObsoleteAStringThunk +#define nsTAString_CharT nsAString +#define nsTAString_IncompatibleCharT nsACString +#define nsTString_CharT nsString +#define nsTFixedString_CharT nsFixedString +#define nsTAutoString_CharT nsAutoString +#define nsTSubstring_CharT nsSubstring +#define nsTSubstringTuple_CharT nsSubstringTuple +#define nsTStringComparator_CharT nsStringComparator +#define nsTDefaultStringComparator_CharT nsDefaultStringComparator +#define nsTDependentString_CharT nsDependentString +#define nsTDependentSubstring_CharT nsDependentSubstring +#define nsTXPIDLString_CharT nsXPIDLString +#define nsTGetterCopies_CharT nsGetterCopies +#define nsTAdoptingString_CharT nsAdoptingString +#define nsTPromiseFlatString_CharT nsPromiseFlatString +#define TPromiseFlatString_CharT PromiseFlatString diff --git a/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h b/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h new file mode 100644 index 00000000..45344370 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/public/string-template-undef.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +#undef CharT +#undef CharT_is_PRUnichar +#undef CharT_is_char +#undef nsTObsoleteAString_CharT +#undef nsTObsoleteAStringThunk_CharT +#undef nsTAString_CharT +#undef nsTAString_IncompatibleCharT +#undef nsTString_CharT +#undef nsTFixedString_CharT +#undef nsTAutoString_CharT +#undef nsTSubstring_CharT +#undef nsTSubstringTuple_CharT +#undef nsTStringComparator_CharT +#undef nsTDefaultStringComparator_CharT +#undef nsTDependentString_CharT +#undef nsTDependentSubstring_CharT +#undef nsTXPIDLString_CharT +#undef nsTGetterCopies_CharT +#undef nsTAdoptingString_CharT +#undef nsTPromiseFlatString_CharT +#undef TPromiseFlatString_CharT diff --git a/src/libs/xpcom18a4/xpcom/string/src/.cvsignore b/src/libs/xpcom18a4/xpcom/string/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/string/src/Makefile.in b/src/libs/xpcom18a4/xpcom/string/src/Makefile.in new file mode 100644 index 00000000..81033c6c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/Makefile.in @@ -0,0 +1,77 @@ +# vim:set ts=8 sw=8 sts=8 noet: +# +# ***** 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 Mozilla. +# +# The Initial Developer of the Original Code is +# Netscape Communications. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Johnny Stenback (original author) +# Scott Collins +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = string +LIBRARY_NAME = string_s + +REQUIRES = xpcom \ + $(NULL) + +CPPSRCS = \ + nsAString.cpp \ + nsDependentSubstring.cpp \ + nsObsoleteAStringThunk.cpp \ + nsPrintfCString.cpp \ + nsPromiseFlatString.cpp \ + nsReadableUtils.cpp \ + nsSubstring.cpp \ + nsSubstringTuple.cpp \ + nsString.cpp \ + nsStringComparator.cpp \ + nsStringObsolete.cpp \ + $(NULL) + +# we don't want the shared lib, but we want to force the creation of a +# static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp new file mode 100644 index 00000000..5b481662 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsAString.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsAString.h" +#include "nsObsoleteAString.h" +#include "nsString.h" + + // define nsAString +#include "string-template-def-unichar.h" +#include "nsTAString.cpp" +#include "string-template-undef.h" + + // define nsACString +#include "string-template-def-char.h" +#include "nsTAString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp new file mode 100644 index 00000000..971defc8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsDependentSubstring.cpp @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsDependentSubstring.h" +#include "nsAlgorithm.h" + + // define nsDependentSubstring +#include "string-template-def-unichar.h" +#include "nsTDependentSubstring.cpp" +#include "string-template-undef.h" + + // define nsDependentCSubstring +#include "string-template-def-char.h" +#include "nsTDependentSubstring.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp new file mode 100644 index 00000000..8b511d1e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsObsoleteAStringThunk.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsObsoleteAString.h" +#include "nsString.h" + + + // define nsObsoleteAStringThunk +#include "string-template-def-unichar.h" +#include "nsTObsoleteAStringThunk.cpp" +#include "string-template-undef.h" + + + // define nsObsoleteACStringThunk +#include "string-template-def-char.h" +#include "nsTObsoleteAStringThunk.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp new file mode 100644 index 00000000..8bb06da6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsPrintfCString.cpp @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsPrintfCString.h" +#include +#include "prprf.h" + + +// though these classes define a fixed buffer, they do not set the F_FIXED +// flag. this is because they are not intended to be modified after they have +// been constructed. we could change this but it would require adding a new +// class to the hierarchy, one that both this class and nsCAutoString would +// inherit from. for now, we populate the fixed buffer, and then let the +// nsCString code treat the buffer as if it were a dependent buffer. + +nsPrintfCString::nsPrintfCString( const char_type* format, ... ) + : string_type(mLocalBuffer, 0, F_TERMINATED) + { + va_list ap; + + size_type logical_capacity = kLocalBufferSize; + size_type physical_capacity = logical_capacity + 1; + + va_start(ap, format); + mLength = PR_vsnprintf(mData, physical_capacity, format, ap); + va_end(ap); + } + +nsPrintfCString::nsPrintfCString( size_type n, const char_type* format, ... ) + : string_type(mLocalBuffer, 0, F_TERMINATED) + { + va_list ap; + + // make sure there's at least |n| space + size_type logical_capacity = kLocalBufferSize; + if ( n > logical_capacity ) + { + SetCapacity(n); + if (Capacity() < n) + return; // out of memory !! + logical_capacity = n; + } + size_type physical_capacity = logical_capacity + 1; + + va_start(ap, format); + mLength = PR_vsnprintf(mData, physical_capacity, format, ap); + va_end(ap); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp new file mode 100644 index 00000000..aab4f209 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsPromiseFlatString.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsPromiseFlatString.h" + + // define nsPromiseFlatString +#include "string-template-def-unichar.h" +#include "nsTPromiseFlatString.cpp" +#include "string-template-undef.h" + + // define nsPromiseFlatCString +#include "string-template-def-char.h" +#include "nsTPromiseFlatString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp new file mode 100644 index 00000000..24305b6a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsReadableUtils.cpp @@ -0,0 +1,1122 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsReadableUtils.h" +#include "nsMemory.h" +#include "nsString.h" +#include "nsUTF8Utils.h" + +NS_COM +void +LossyCopyUTF16toASCII( const nsAString& aSource, nsACString& aDest ) + { + aDest.Truncate(); + LossyAppendUTF16toASCII(aSource, aDest); + } + +NS_COM +void +CopyASCIItoUTF16( const nsACString& aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendASCIItoUTF16(aSource, aDest); + } + +NS_COM +void +LossyCopyUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ) + { + aDest.Truncate(); + if (aSource) { + LossyAppendUTF16toASCII(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +CopyASCIItoUTF16( const char* aSource, nsAString& aDest ) + { + aDest.Truncate(); + if (aSource) { + AppendASCIItoUTF16(nsDependentCString(aSource), aDest); + } + } + +NS_COM +void +CopyUTF16toUTF8( const nsAString& aSource, nsACString& aDest ) + { + aDest.Truncate(); + AppendUTF16toUTF8(aSource, aDest); + } + +NS_COM +void +CopyUTF8toUTF16( const nsACString& aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendUTF8toUTF16(aSource, aDest); + } + +NS_COM +void +CopyUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ) + { + aDest.Truncate(); + AppendUTF16toUTF8(aSource, aDest); + } + +NS_COM +void +CopyUTF8toUTF16( const char* aSource, nsAString& aDest ) + { + aDest.Truncate(); + AppendUTF8toUTF16(aSource, aDest); + } + +NS_COM +void +LossyAppendUTF16toASCII( const nsAString& aSource, nsACString& aDest ) + { + PRUint32 old_dest_length = aDest.Length(); + aDest.SetLength(old_dest_length + aSource.Length()); + + nsAString::const_iterator fromBegin, fromEnd; + + nsACString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + // right now, this won't work on multi-fragment destinations + LossyConvertEncoding converter(dest.get()); + + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +NS_COM +void +AppendASCIItoUTF16( const nsACString& aSource, nsAString& aDest ) + { + PRUint32 old_dest_length = aDest.Length(); + aDest.SetLength(old_dest_length + aSource.Length()); + + nsACString::const_iterator fromBegin, fromEnd; + + nsAString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + // right now, this won't work on multi-fragment destinations + LossyConvertEncoding converter(dest.get()); + + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +NS_COM +void +LossyAppendUTF16toASCII( const PRUnichar* aSource, nsACString& aDest ) + { + if (aSource) { + LossyAppendUTF16toASCII(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +AppendASCIItoUTF16( const char* aSource, nsAString& aDest ) + { + if (aSource) { + AppendASCIItoUTF16(nsDependentCString(aSource), aDest); + } + } + +NS_COM +void +AppendUTF16toUTF8( const nsAString& aSource, nsACString& aDest ) + { + nsAString::const_iterator source_start, source_end; + CalculateUTF8Size calculator; + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), calculator); + + PRUint32 count = calculator.Size(); + + if (count) + { + PRUint32 old_dest_length = aDest.Length(); + + // Grow the buffer if we need to. + aDest.SetLength(old_dest_length + count); + + nsACString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + if (count <= (PRUint32)dest.size_forward()) + { + // aDest has enough room in the fragment just past the end + // of its old data that it can hold what we're about to + // append. Append using copy_string(). + + // All ready? Time to convert + + ConvertUTF16toUTF8 converter(dest.get()); + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), converter); + + if (converter.Size() != count) + { + NS_ERROR("Input invalid or incorrect length was calculated"); + + aDest.SetLength(old_dest_length); + } + } + else + { + // This isn't the fastest way to do this, but it gets + // complicated to convert UTF16 into a fragmented UTF8 + // string, so we'll take the easy way out here in this + // rare situation. + + aDest.Replace(old_dest_length, count, + NS_ConvertUTF16toUTF8(aSource)); + } + } + } + +NS_COM +void +AppendUTF8toUTF16( const nsACString& aSource, nsAString& aDest ) + { + nsACString::const_iterator source_start, source_end; + CalculateUTF8Length calculator; + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), calculator); + + PRUint32 count = calculator.Length(); + + if (count) + { + PRUint32 old_dest_length = aDest.Length(); + + // Grow the buffer if we need to. + aDest.SetLength(old_dest_length + count); + + nsAString::iterator dest; + aDest.BeginWriting(dest); + + dest.advance(old_dest_length); + + if (count <= (PRUint32)dest.size_forward()) + { + // aDest has enough room in the fragment just past the end + // of its old data that it can hold what we're about to + // append. Append using copy_string(). + + // All ready? Time to convert + + ConvertUTF8toUTF16 converter(dest.get()); + copy_string(aSource.BeginReading(source_start), + aSource.EndReading(source_end), converter); + + if (converter.Length() != count) + { + NS_ERROR("Input wasn't UTF8 or incorrect length was calculated"); + aDest.SetLength(old_dest_length); + } + } + else + { + // This isn't the fastest way to do this, but it gets + // complicated to convert parts of a UTF8 string into a + // UTF16 string, so we'll take the easy way out here in + // this rare situation. + + aDest.Replace(old_dest_length, count, + NS_ConvertUTF8toUTF16(aSource)); + } + } + } + +NS_COM +void +AppendUTF16toUTF8( const PRUnichar* aSource, nsACString& aDest ) + { + if (aSource) { + AppendUTF16toUTF8(nsDependentString(aSource), aDest); + } + } + +NS_COM +void +AppendUTF8toUTF16( const char* aSource, nsAString& aDest ) + { + if (aSource) { + AppendUTF8toUTF16(nsDependentCString(aSource), aDest); + } + } + + + /** + * A helper function that allocates a buffer of the desired character type big enough to hold a copy of the supplied string (plus a zero terminator). + * + * @param aSource an string you will eventually be making a copy of + * @return a new buffer (of the type specified by the second parameter) which you must free with |nsMemory::Free|. + * + */ +template +inline +ToCharT* +AllocateStringCopy( const FromStringT& aSource, ToCharT* ) + { + return NS_STATIC_CAST(ToCharT*, nsMemory::Alloc((aSource.Length()+1) * sizeof(ToCharT))); + } + + +NS_COM +char* +ToNewCString( const nsAString& aSource ) + { + char* result = AllocateStringCopy(aSource, (char*)0); + + nsAString::const_iterator fromBegin, fromEnd; + LossyConvertEncoding converter(result); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator(); + return result; + } + +NS_COM +char* +ToNewUTF8String( const nsAString& aSource, PRUint32 *aUTF8Count ) + { + nsAString::const_iterator start, end; + CalculateUTF8Size calculator; + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + calculator); + + if (aUTF8Count) + *aUTF8Count = calculator.Size(); + + char *result = NS_STATIC_CAST(char*, + nsMemory::Alloc(calculator.Size() + 1)); + + ConvertUTF16toUTF8 converter(result); + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + converter).write_terminator(); + NS_ASSERTION(calculator.Size() == converter.Size(), "length mismatch"); + + return result; + } + +NS_COM +char* +ToNewCString( const nsACString& aSource ) + { + // no conversion needed, just allocate a buffer of the correct length and copy into it + + char* result = AllocateStringCopy(aSource, (char*)0); + + nsACString::const_iterator fromBegin, fromEnd; + char* toBegin = result; + *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = char(0); + return result; + } + +NS_COM +PRUnichar* +ToNewUnicode( const nsAString& aSource ) + { + // no conversion needed, just allocate a buffer of the correct length and copy into it + + PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); + + nsAString::const_iterator fromBegin, fromEnd; + PRUnichar* toBegin = result; + *copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), toBegin) = PRUnichar(0); + return result; + } + +NS_COM +PRUnichar* +ToNewUnicode( const nsACString& aSource ) + { + PRUnichar* result = AllocateStringCopy(aSource, (PRUnichar*)0); + + nsACString::const_iterator fromBegin, fromEnd; + LossyConvertEncoding converter(result); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter).write_terminator(); + return result; + } + +NS_COM +PRUnichar* +UTF8ToNewUnicode( const nsACString& aSource, PRUint32 *aUTF16Count ) + { + nsACString::const_iterator start, end; + CalculateUTF8Length calculator; + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + calculator); + + if (aUTF16Count) + *aUTF16Count = calculator.Length(); + + PRUnichar *result = NS_STATIC_CAST(PRUnichar*, + nsMemory::Alloc(sizeof(PRUnichar) * (calculator.Length() + 1))); + + ConvertUTF8toUTF16 converter(result); + copy_string(aSource.BeginReading(start), aSource.EndReading(end), + converter).write_terminator(); + NS_ASSERTION(calculator.Length() == converter.Length(), "length mismatch"); + + return result; + } + +NS_COM +PRUnichar* +CopyUnicodeTo( const nsAString& aSource, PRUint32 aSrcOffset, PRUnichar* aDest, PRUint32 aLength ) + { + nsAString::const_iterator fromBegin, fromEnd; + PRUnichar* toBegin = aDest; + copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ), aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ), toBegin); + return aDest; + } + +NS_COM +void +CopyUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ) + { + nsAString::iterator writer; + aDest.SetLength(Distance(aSrcStart, aSrcEnd)); + aDest.BeginWriting(writer); + nsAString::const_iterator fromBegin(aSrcStart); + + copy_string(fromBegin, aSrcEnd, writer); + } + +NS_COM +void +AppendUnicodeTo( const nsAString::const_iterator& aSrcStart, + const nsAString::const_iterator& aSrcEnd, + nsAString& aDest ) + { + nsAString::iterator writer; + PRUint32 oldLength = aDest.Length(); + aDest.SetLength(oldLength + Distance(aSrcStart, aSrcEnd)); + aDest.BeginWriting(writer).advance(oldLength); + nsAString::const_iterator fromBegin(aSrcStart); + + copy_string(fromBegin, aSrcEnd, writer); + } + +NS_COM +PRBool +IsASCII( const nsAString& aString ) + { + static const PRUnichar NOT_ASCII = PRUnichar(~0x007F); + + + // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character + + nsAString::const_iterator done_reading; + aString.EndReading(done_reading); + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsAString::const_iterator iter; + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const PRUnichar* c = iter.get(); + const PRUnichar* fragmentEnd = c + fragmentLength; + + // for each character in this chunk... + while ( c < fragmentEnd ) + if ( *c++ & NOT_ASCII ) + return PR_FALSE; + } + + return PR_TRUE; + } + +NS_COM +PRBool +IsASCII( const nsACString& aString ) + { + static const char NOT_ASCII = char(~0x7F); + + + // Don't want to use |copy_string| for this task, since we can stop at the first non-ASCII character + + nsACString::const_iterator done_reading; + aString.EndReading(done_reading); + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsACString::const_iterator iter; + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const char* c = iter.get(); + const char* fragmentEnd = c + fragmentLength; + + // for each character in this chunk... + while ( c < fragmentEnd ) + if ( *c++ & NOT_ASCII ) + return PR_FALSE; + } + + return PR_TRUE; + } + +NS_COM +PRBool +IsUTF8( const nsACString& aString ) + { + nsReadingIterator done_reading; + aString.EndReading(done_reading); + + PRInt32 state = 0; + PRBool overlong = PR_FALSE; + PRBool surrogate = PR_FALSE; + PRBool nonchar = PR_FALSE; + PRUint16 olupper = 0; // overlong byte upper bound. + PRUint16 slower = 0; // surrogate byte lower bound. + + // for each chunk of |aString|... + PRUint32 fragmentLength = 0; + nsReadingIterator iter; + + for ( aString.BeginReading(iter); iter != done_reading; iter.advance( PRInt32(fragmentLength) ) ) + { + fragmentLength = PRUint32(iter.size_forward()); + const char* ptr = iter.get(); + const char* fragmentEnd = ptr + fragmentLength; + + // for each character in this chunk... + while ( ptr < fragmentEnd ) + { + PRUint8 c; + + if (0 == state) + { + c = *ptr++; + + if ( UTF8traits::isASCII(c) ) + continue; + + if ( c <= 0xC1 ) // [80-BF] where not expected, [C0-C1] for overlong. + return PR_FALSE; + else if ( UTF8traits::is2byte(c) ) + state = 1; + else if ( UTF8traits::is3byte(c) ) + { + state = 2; + if ( c == 0xE0 ) // to exclude E0[80-9F][80-BF] + { + overlong = PR_TRUE; + olupper = 0x9F; + } + else if ( c == 0xED ) // ED[A0-BF][80-BF] : surrogate codepoint + { + surrogate = PR_TRUE; + slower = 0xA0; + } + else if ( c == 0xEF ) // EF BF [BE-BF] : non-character + nonchar = PR_TRUE; + } + else if ( c <= 0xF4 ) // XXX replace /w UTF8traits::is4byte when it's updated to exclude [F5-F7].(bug 199090) + { + state = 3; + nonchar = PR_TRUE; + if ( c == 0xF0 ) // to exclude F0[80-8F][80-BF]{2} + { + overlong = PR_TRUE; + olupper = 0x8F; + } + else if ( c == 0xF4 ) // to exclude F4[90-BF][80-BF] + { + // actually not surrogates but codepoints beyond 0x10FFFF + surrogate = PR_TRUE; + slower = 0x90; + } + } + else + return PR_FALSE; // Not UTF-8 string + } + + while (ptr < fragmentEnd && state) + { + c = *ptr++; + --state; + + // non-character : EF BF [BE-BF] or F[0-7] [89AB]F BF [BE-BF] + if ( nonchar && ( (!state && c < 0xBE) || + (state == 1 && c != 0xBF) || + (state == 2 && 0x0F != (0x0F & c)) )) + nonchar = PR_FALSE; + + if ( !UTF8traits::isInSeq(c) || (overlong && c <= olupper) || + (surrogate && slower <= c) || (nonchar && !state) ) + return PR_FALSE; // Not UTF-8 string + overlong = surrogate = PR_FALSE; + } + } + } + return !state; // state != 0 at the end indicates an invalid UTF-8 seq. + } + + /** + * A character sink for in-place case conversion. + */ +class ConvertToUpperCase + { + public: + typedef char value_type; + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + char* cp = NS_CONST_CAST(char*,aSource); + const char* end = aSource + aSourceLength; + while (cp != end) { + char ch = *cp; + if ((ch >= 'a') && (ch <= 'z')) + *cp = ch - ('a' - 'A'); + ++cp; + } + return aSourceLength; + } + }; + +NS_COM +void +ToUpperCase( nsACString& aCString ) + { + nsACString::iterator fromBegin, fromEnd; + ConvertToUpperCase converter; + copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); + } + +NS_COM +void +ToUpperCase( nsCSubstring& aCString ) + { + ConvertToUpperCase converter; + char* start; + converter.write(aCString.BeginWriting(start), aCString.Length()); + } + + /** + * A character sink for copying with case conversion. + */ +class CopyToUpperCase + { + public: + typedef char value_type; + + CopyToUpperCase( nsACString::iterator& aDestIter ) + : mIter(aDestIter) + { + } + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + char* cp = mIter.get(); + const char* end = aSource + len; + while (aSource != end) { + char ch = *aSource; + if ((ch >= 'a') && (ch <= 'z')) + *cp = ch - ('a' - 'A'); + else + *cp = ch; + ++aSource; + ++cp; + } + mIter.advance(len); + return len; + } + + protected: + nsACString::iterator& mIter; + }; + +NS_COM +void +ToUpperCase( const nsACString& aSource, nsACString& aDest ) + { + nsACString::const_iterator fromBegin, fromEnd; + nsACString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToUpperCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + + /** + * A character sink for case conversion. + */ +class ConvertToLowerCase + { + public: + typedef char value_type; + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + char* cp = NS_CONST_CAST(char*,aSource); + const char* end = aSource + aSourceLength; + while (cp != end) { + char ch = *cp; + if ((ch >= 'A') && (ch <= 'Z')) + *cp = ch + ('a' - 'A'); + ++cp; + } + return aSourceLength; + } + }; + +NS_COM +void +ToLowerCase( nsACString& aCString ) + { + nsACString::iterator fromBegin, fromEnd; + ConvertToLowerCase converter; + copy_string(aCString.BeginWriting(fromBegin), aCString.EndWriting(fromEnd), converter); + } + +NS_COM +void +ToLowerCase( nsCSubstring& aCString ) + { + ConvertToLowerCase converter; + char* start; + converter.write(aCString.BeginWriting(start), aCString.Length()); + } + + /** + * A character sink for copying with case conversion. + */ +class CopyToLowerCase + { + public: + typedef char value_type; + + CopyToLowerCase( nsACString::iterator& aDestIter ) + : mIter(aDestIter) + { + } + + PRUint32 + write( const char* aSource, PRUint32 aSourceLength ) + { + PRUint32 len = PR_MIN(PRUint32(mIter.size_forward()), aSourceLength); + char* cp = mIter.get(); + const char* end = aSource + len; + while (aSource != end) { + char ch = *aSource; + if ((ch >= 'A') && (ch <= 'Z')) + *cp = ch + ('a' - 'A'); + else + *cp = ch; + ++aSource; + ++cp; + } + mIter.advance(len); + return len; + } + + protected: + nsACString::iterator& mIter; + }; + +NS_COM +void +ToLowerCase( const nsACString& aSource, nsACString& aDest ) + { + nsACString::const_iterator fromBegin, fromEnd; + nsACString::iterator toBegin; + aDest.SetLength(aSource.Length()); + CopyToLowerCase converter(aDest.BeginWriting(toBegin)); + copy_string(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), converter); + } + +template +PRBool +FindInReadable_Impl( const StringT& aPattern, IteratorT& aSearchStart, IteratorT& aSearchEnd, const Comparator& compare ) + { + PRBool found_it = PR_FALSE; + + // only bother searching at all if we're given a non-empty range to search + if ( aSearchStart != aSearchEnd ) + { + IteratorT aPatternStart, aPatternEnd; + aPattern.BeginReading(aPatternStart); + aPattern.EndReading(aPatternEnd); + + // outer loop keeps searching till we find it or run out of string to search + while ( !found_it ) + { + // fast inner loop (that's what it's called, not what it is) looks for a potential match + while ( aSearchStart != aSearchEnd && + compare(*aPatternStart, *aSearchStart) ) + ++aSearchStart; + + // if we broke out of the `fast' loop because we're out of string ... we're done: no match + if ( aSearchStart == aSearchEnd ) + break; + + // otherwise, we're at a potential match, let's see if we really hit one + IteratorT testPattern(aPatternStart); + IteratorT testSearch(aSearchStart); + + // slow inner loop verifies the potential match (found by the `fast' loop) at the current position + for(;;) + { + // we already compared the first character in the outer loop, + // so we'll advance before the next comparison + ++testPattern; + ++testSearch; + + // if we verified all the way to the end of the pattern, then we found it! + if ( testPattern == aPatternEnd ) + { + found_it = PR_TRUE; + aSearchEnd = testSearch; // return the exact found range through the parameters + break; + } + + // if we got to end of the string we're searching before we hit the end of the + // pattern, we'll never find what we're looking for + if ( testSearch == aSearchEnd ) + { + aSearchStart = aSearchEnd; + break; + } + + // else if we mismatched ... it's time to advance to the next search position + // and get back into the `fast' loop + if ( compare(*testPattern, *testSearch) ) + { + ++aSearchStart; + break; + } + } + } + } + + return found_it; + } + + +NS_COM +PRBool +FindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator ) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); + } + +NS_COM +PRBool +FindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, aComparator); + } + +NS_COM +PRBool +CaseInsensitiveFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd ) + { + return FindInReadable_Impl(aPattern, aSearchStart, aSearchEnd, nsCaseInsensitiveCStringComparator()); + } + + /** + * This implementation is simple, but does too much work. + * It searches the entire string from left to right, and returns the last match found, if any. + * This implementation will be replaced when I get |reverse_iterator|s working. + */ +NS_COM +PRBool +RFindInReadable( const nsAString& aPattern, nsAString::const_iterator& aSearchStart, nsAString::const_iterator& aSearchEnd, const nsStringComparator& aComparator) + { + PRBool found_it = PR_FALSE; + + nsAString::const_iterator savedSearchEnd(aSearchEnd); + nsAString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd); + + while ( searchStart != searchEnd ) + { + if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) ) + { + found_it = PR_TRUE; + + // this is the best match so far, so remember it + aSearchStart = searchStart; + aSearchEnd = searchEnd; + + // ...and get ready to search some more + // (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns) + ++searchStart; + searchEnd = savedSearchEnd; + } + } + + // if we never found it, return an empty range + if ( !found_it ) + aSearchStart = aSearchEnd; + + return found_it; + } + +NS_COM +PRBool +RFindInReadable( const nsACString& aPattern, nsACString::const_iterator& aSearchStart, nsACString::const_iterator& aSearchEnd, const nsCStringComparator& aComparator) + { + PRBool found_it = PR_FALSE; + + nsACString::const_iterator savedSearchEnd(aSearchEnd); + nsACString::const_iterator searchStart(aSearchStart), searchEnd(aSearchEnd); + + while ( searchStart != searchEnd ) + { + if ( FindInReadable(aPattern, searchStart, searchEnd, aComparator) ) + { + found_it = PR_TRUE; + + // this is the best match so far, so remember it + aSearchStart = searchStart; + aSearchEnd = searchEnd; + + // ...and get ready to search some more + // (it's tempting to set |searchStart=searchEnd| ... but that misses overlapping patterns) + ++searchStart; + searchEnd = savedSearchEnd; + } + } + + // if we never found it, return an empty range + if ( !found_it ) + aSearchStart = aSearchEnd; + + return found_it; + } + +NS_COM +PRBool +FindCharInReadable( PRUnichar aChar, nsAString::const_iterator& aSearchStart, const nsAString::const_iterator& aSearchEnd ) + { + PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get(); + + const PRUnichar* charFoundAt = nsCharTraits::find(aSearchStart.get(), fragmentLength, aChar); + if ( charFoundAt ) { + aSearchStart.advance( charFoundAt - aSearchStart.get() ); + return PR_TRUE; + } + + aSearchStart.advance(fragmentLength); + return PR_FALSE; + } + +NS_COM +PRBool +FindCharInReadable( char aChar, nsACString::const_iterator& aSearchStart, const nsACString::const_iterator& aSearchEnd ) + { + PRInt32 fragmentLength = aSearchEnd.get() - aSearchStart.get(); + + const char* charFoundAt = nsCharTraits::find(aSearchStart.get(), fragmentLength, aChar); + if ( charFoundAt ) { + aSearchStart.advance( charFoundAt - aSearchStart.get() ); + return PR_TRUE; + } + + aSearchStart.advance(fragmentLength); + return PR_FALSE; + } + +NS_COM +PRUint32 +CountCharInReadable( const nsAString& aStr, + PRUnichar aChar ) +{ + PRUint32 count = 0; + nsAString::const_iterator begin, end; + + aStr.BeginReading(begin); + aStr.EndReading(end); + + while (begin != end) { + if (*begin == aChar) { + ++count; + } + ++begin; + } + + return count; +} + +NS_COM +PRUint32 +CountCharInReadable( const nsACString& aStr, + char aChar ) +{ + PRUint32 count = 0; + nsACString::const_iterator begin, end; + + aStr.BeginReading(begin); + aStr.EndReading(end); + + while (begin != end) { + if (*begin == aChar) { + ++count; + } + ++begin; + } + + return count; +} + +NS_COM PRBool +StringBeginsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator ) + { + nsAString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); + } + +NS_COM PRBool +StringBeginsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator ) + { + nsACString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, 0, sub_len).Equals(aSubstring, aComparator); + } + +NS_COM PRBool +StringEndsWith( const nsAString& aSource, const nsAString& aSubstring, + const nsStringComparator& aComparator ) + { + nsAString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, + aComparator); + } + +NS_COM PRBool +StringEndsWith( const nsACString& aSource, const nsACString& aSubstring, + const nsCStringComparator& aComparator ) + { + nsACString::size_type src_len = aSource.Length(), + sub_len = aSubstring.Length(); + if (sub_len > src_len) + return PR_FALSE; + return Substring(aSource, src_len - sub_len, sub_len).Equals(aSubstring, + aComparator); + } + + + +template +class CalculateHashCode + { + public: + typedef CharT char_type; + typedef PRUint32 hashcode_type; + typedef CharT value_type; + + CalculateHashCode() : mHashCode(0) { } + hashcode_type GetHashCode() const { return mHashCode; } + + PRUint32 write( const CharT* chars, PRUint32 N ) + { + for ( const CharT *end = chars + N; chars < end; ++chars) + mHashCode = (mHashCode>>28) ^ (mHashCode<<4) ^ PRUint32(*chars); + return N; + } + + private: + hashcode_type mHashCode; + }; + +NS_COM PRUint32 HashString( const nsAString& aStr ) + { + CalculateHashCode sink; + nsAString::const_iterator begin, end; + aStr.BeginReading(begin); + aStr.EndReading(end); + copy_string(begin, end, sink); + return sink.GetHashCode(); + } + +NS_COM PRUint32 HashString( const nsACString& aStr ) + { + CalculateHashCode sink; + nsACString::const_iterator begin, end; + aStr.BeginReading(begin); + aStr.EndReading(end); + copy_string(begin, end, sink); + return sink.GetHashCode(); + } + +static const PRUnichar empty_buffer[1] = { '\0' }; + +NS_COM const nsAFlatString& EmptyString() + { + static const nsDependentString sEmpty(empty_buffer); + + return sEmpty; + } + +NS_COM const nsAFlatCString& EmptyCString() + { + static const nsDependentCString sEmpty((const char *)empty_buffer); + + return sEmpty; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp new file mode 100644 index 00000000..aedf3295 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsString.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsString.h" + + // define nsString +#include "string-template-def-unichar.h" +#include "nsTString.cpp" +#include "string-template-undef.h" + + // define nsCString +#include "string-template-def-char.h" +#include "nsTString.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp new file mode 100644 index 00000000..ced75c73 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsStringComparator.cpp @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "nsAString.h" +#include "plstr.h" + + + // define nsStringComparator +#include "string-template-def-unichar.h" +#include "nsTStringComparator.cpp" +#include "string-template-undef.h" + + // define nsCStringComparator +#include "string-template-def-char.h" +#include "nsTStringComparator.cpp" +#include "string-template-undef.h" + + +int +nsCaseInsensitiveCStringComparator::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const + { + PRInt32 result=PRInt32(PL_strncasecmp(lhs, rhs, aLength)); + //Egads. PL_strncasecmp is returning *very* negative numbers. + //Some folks expect -1,0,1, so let's temper its enthusiasm. + if (result<0) + result=-1; + return result; + } + +int +nsCaseInsensitiveCStringComparator::operator()( char lhs, char rhs ) const + { + if (lhs == rhs) return 0; + + lhs = tolower(lhs); + rhs = tolower(rhs); + + return lhs - rhs; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp new file mode 100644 index 00000000..76106a27 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsStringObsolete.cpp @@ -0,0 +1,1327 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsString.h" + + + /** + * nsTString obsolete API support + */ + +#if MOZ_STRING_WITH_OBSOLETE_API + +#include "nsDependentString.h" +#include "nsDependentSubstring.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsUTF8Utils.h" +#include "prdtoa.h" +#include "prprf.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +/* ***** BEGIN RICKG BLOCK ***** + * + * NOTE: This section of code was extracted from rickg's bufferRoutines.h file. + * For the most part it remains unmodified. We want to eliminate (or at + * least clean up) this code at some point. If you find the formatting + * in this section somewhat inconsistent, don't blame me! ;-) + */ + +// XXXdarin what is wrong with STDC's tolower? +inline char +ascii_tolower(char aChar) +{ + if (aChar >= 'A' && aChar <= 'Z') + return aChar + ('a' - 'A'); + return aChar; +} + +//----------------------------------------------------------------------------- +// +// This set of methods is used to search a buffer looking for a char. +// + + +/** + * This methods cans the given buffer for the given char + * + * @update gess 02/17/00 + * @param aDest is the buffer to be searched + * @param aDestLength is the size (in char-units, not bytes) of the buffer + * @param anOffset is the start pos to begin searching + * @param aChar is the target character we're looking for + * @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length. + * @return index of pos if found, else -1 (kNotFound) + */ +static PRInt32 +FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRInt32 aCount) { + + if(anOffset < 0) + anOffset=0; + + if(aCount < 0) + aCount = (PRInt32)aDestLength; + + if((aChar < 256) && (0 < aDestLength) && ((PRUint32)anOffset < aDestLength)) { + + //We'll only search if the given aChar is within the normal ascii a range, + //(Since this string is definitely within the ascii range). + + if(0 + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + PRInt32 result=0; + if(aIgnoreCase) + result=PRInt32(PL_strncasecmp(aStr1, aStr2, aCount)); + else + result=nsCharTraits::compare(aStr1,aStr2,aCount); + + // alien comparisons may return out-of-bound answers + // instead of the -1, 0, 1 expected by most clients + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To2(const PRUnichar* aStr1,const PRUnichar* aStr2,PRUint32 aCount){ + PRInt32 result; + + if ( aStr1 && aStr2 ) + result = nsCharTraits::compare(aStr1, aStr2, aCount); + + // The following cases are rare and survivable caller errors. + // Two null pointers are equal, but any string, even 0 length + // is greater than a null pointer. It might not really matter, + // but we pick something reasonable anyway. + else if ( !aStr1 && !aStr2 ) + result = 0; + else if ( aStr1 ) + result = 1; + else + result = -1; + + // alien comparisons may give answers outside the -1, 0, 1 expected by callers + if ( result < -1 ) + result = -1; + else if ( result > 1 ) + result = 1; + return result; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +static +#ifdef __SUNPRO_CC +inline +#endif /* __SUNPRO_CC */ +PRInt32 +Compare2To1(const PRUnichar* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + const PRUnichar* s1 = aStr1; + const char *s2 = aStr2; + + if (aStr1 && aStr2) { + if (aCount != 0) { + do { + + PRUnichar c1 = *s1++; + PRUnichar c2 = PRUnichar((unsigned char)*s2++); + + if (c1 != c2) { +#ifdef NS_DEBUG + // we won't warn on c1>=128 (the 2-byte value) because often + // it is just fine to compare an constant, ascii value (i.e. "body") + // against some non-ascii value (i.e. a unicode string that + // was downloaded from a web page) + if (aIgnoreCase && c2>=128) + NS_WARNING("got a non-ASCII string, but we can't do an accurate case conversion!"); +#endif + + // can't do case conversion on characters out of our range + if (aIgnoreCase && c1<128 && c2<128) { + + c1 = ascii_tolower(char(c1)); + c2 = ascii_tolower(char(c2)); + + if (c1 == c2) continue; + } + + if (c1 < c2) return -1; + return 1; + } + } while (--aCount); + } + } + return 0; +} + + +/** + * This method compares the data in one buffer with another + * @update gess 01/04/99 + * @param aStr1 is the first buffer to be compared + * @param aStr2 is the 2nd buffer to be compared + * @param aCount is the number of chars to compare + * @param aIgnoreCase tells us whether to use a case-sensitive comparison + * @return -1,0,1 depending on <,==,> + */ +inline PRInt32 +Compare1To2(const char* aStr1,const PRUnichar* aStr2,PRUint32 aCount,PRBool aIgnoreCase){ + return Compare2To1(aStr2, aStr1, aCount, aIgnoreCase) * -1; +} + + +//----------------------------------------------------------------------------- +// +// This set of methods is used compress char sequences in a buffer... +// + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars1(char* aString,PRUint32 aLength,const char* aSet){ + + char* from = aString; + char* end = aString + aLength; + char* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + char theChar = *from++; + + *to++=theChar; //always copy this char... + + if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - aString; +} + + + +/** + * This method compresses duplicate runs of a given char from the given buffer + * + * @update rickg 03.23.2000 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +CompressChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + PRUnichar* from = aString; + PRUnichar* end = from + aLength; + PRUnichar* to = from; + + //this code converts /n, /t, /r into normal space ' '; + //it also compresses runs of whitespace down to a single char... + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + + while (from < end) { + PRUnichar theChar = *from++; + + *to++=theChar; //always copy this char... + + if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,aSetLen))){ + while (from < end) { + theChar = *from++; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + break; + } + } //while + } //if + } //if + *to = 0; + } + return to - (PRUnichar*)aString; +} + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars1(char* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + char* to = aString; + char* from = aString-1; + char* end = aString + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + char theChar = *from; + if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,aSetLen)){ + *to++ = theChar; + } + } + *to = 0; + } + return to - (char*)aString; +} + + +/** + * This method strips chars in a given set from the given buffer + * + * @update gess 01/04/99 + * @param aString is the buffer to be manipulated + * @param aLength is the length of the buffer + * @param aSet tells us which chars to compress from given buffer + * @param aEliminateLeading tells us whether to strip chars from the start of the buffer + * @param aEliminateTrailing tells us whether to strip chars from the start of the buffer + * @return the new length of the given buffer + */ +static PRInt32 +StripChars2(PRUnichar* aString,PRUint32 aLength,const char* aSet){ + + // XXXdarin this code should defer writing until necessary. + + PRUnichar* to = aString; + PRUnichar* from = aString-1; + PRUnichar* end = to + aLength; + + if(aSet && aString && (0 < aLength)){ + PRUint32 aSetLen=strlen(aSet); + while (++from < end) { + PRUnichar theChar = *from; + //Note the test for ascii range below. If you have a real unicode char, + //and you're searching for chars in the (given) ascii string, there's no + //point in doing the real search since it's out of the ascii range. + if((255 +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +CharT +GetFindInSetFilter( const CharT* set) + { + CharT filter = ~CharT(0); // All bits set + while (*set) { + filter &= ~(*set); + ++set; + } + return filter; + } + +// This template class is used by our code to access rickg's buffer routines. +template struct nsBufferRoutines {}; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines + { + static + PRInt32 compare( const char* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare1To1(a, b, max, ic); + } + + static + PRInt32 compare( const char* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + return Compare1To2(a, b, max, ic); + } + + static + PRInt32 find_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar1(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const char* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar1(s, max, offset, c, count); + } + + static + char get_find_in_set_filter( const char* set ) + { + return GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( char* s, PRUint32 len, const char* set ) + { + return StripChars1(s, len, set); + } + + static + PRInt32 compress_chars( char* s, PRUint32 len, const char* set ) + { + return CompressChars1(s, len, set); + } + }; + +NS_SPECIALIZE_TEMPLATE +struct nsBufferRoutines + { + static + PRInt32 compare( const PRUnichar* a, const PRUnichar* b, PRUint32 max, PRBool ic ) + { + NS_ASSERTION(!ic, "no case-insensitive compare here"); + return Compare2To2(a, b, max); + } + + static + PRInt32 compare( const PRUnichar* a, const char* b, PRUint32 max, PRBool ic ) + { + return Compare2To1(a, b, max, ic); + } + + static + PRInt32 find_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return FindChar2(s, max, offset, c, count); + } + + static + PRInt32 rfind_char( const PRUnichar* s, PRUint32 max, PRInt32 offset, const PRUnichar c, PRInt32 count ) + { + return RFindChar2(s, max, offset, c, count); + } + + static + PRUnichar get_find_in_set_filter( const PRUnichar* set ) + { + return GetFindInSetFilter(set); + } + + static + PRUnichar get_find_in_set_filter( const char* set ) + { + return (~PRUnichar(0)^~char(0)) | GetFindInSetFilter(set); + } + + static + PRInt32 strip_chars( PRUnichar* s, PRUint32 max, const char* set ) + { + return StripChars2(s, max, set); + } + + static + PRInt32 compress_chars( PRUnichar* s, PRUint32 len, const char* set ) + { + return CompressChars2(s, len, set); + } + }; + +//----------------------------------------------------------------------------- + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + for (i=0; i<=max; ++i, ++big) + { + if (nsBufferRoutines::compare(big, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindSubstring( const L* big, PRUint32 bigLen, + const R* little, PRUint32 littleLen, + PRBool ignoreCase ) + { + if (littleLen > bigLen) + return kNotFound; + + PRInt32 i, max = PRInt32(bigLen - littleLen); + + const L* iter = big + max; + for (i=max; iter >= big; --i, --iter) + { + if (nsBufferRoutines::compare(iter, little, littleLen, ignoreCase) == 0) + return i; + } + + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +FindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines::get_find_in_set_filter(set); + + const CharT* end = data + dataLen; + for (const CharT* iter = data; iter < end; ++iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const SetCharT* charInSet = set; + CharT setChar = CharT(*charInSet); + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = CharT(*(++charInSet)); + } + } + return kNotFound; + } + +template +#ifndef __SUNPRO_CC +static +#endif /* !__SUNPRO_CC */ +PRInt32 +RFindCharInSet( const CharT* data, PRUint32 dataLen, const SetCharT* set ) + { + CharT filter = nsBufferRoutines::get_find_in_set_filter(set); + + for (const CharT* iter = data + dataLen - 1; iter >= data; --iter) + { + CharT currentChar = *iter; + if (currentChar & filter) + continue; // char is not in filter set; go on with next char. + + // test all chars + const CharT* charInSet = set; + CharT setChar = *charInSet; + while (setChar) + { + if (setChar == currentChar) + return iter - data; // found it! return index of the found char. + + setChar = *(++charInSet); + } + } + return kNotFound; + } + +/** + * This is a copy of |PR_cnvtf| with a bug fixed. (The second argument + * of PR_dtoa is 2 rather than 1.) + * + * XXXdarin if this is the right thing, then why wasn't it fixed in NSPR?!? + */ +void +Modified_cnvtf(char *buf, int bufsz, int prcsn, double fval) +{ + PRIntn decpt, sign, numdigits; + char *num, *nump; + char *bufp = buf; + char *endnum; + + /* If anything fails, we store an empty string in 'buf' */ +#ifdef VBOX_USE_IPRT_IN_XPCOM + num = (char*)RTMemAlloc(bufsz); +#else + num = (char*)malloc(bufsz); +#endif + if (num == NULL) { + buf[0] = '\0'; + return; + } + if (PR_dtoa(fval, 2, prcsn, &decpt, &sign, &endnum, num, bufsz) + == PR_FAILURE) { + buf[0] = '\0'; + goto done; + } + numdigits = endnum - num; + nump = num; + + /* + * The NSPR code had a fancy way of checking that we weren't dealing + * with -0.0 or -NaN, but I'll just use < instead. + * XXX Should we check !isnan(fval) as well? Is it portable? We + * probably don't need to bother since NAN isn't portable. + */ + if (sign && fval < 0.0f) { + *bufp++ = '-'; + } + + if (decpt == 9999) { + while ((*bufp++ = *nump++) != 0) {} /* nothing to execute */ + goto done; + } + + if (decpt > (prcsn+1) || decpt < -(prcsn-1) || decpt < -5) { + *bufp++ = *nump++; + if (numdigits != 1) { + *bufp++ = '.'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = 'e'; + PR_snprintf(bufp, bufsz - (bufp - buf), "%+d", decpt-1); + } + else if (decpt >= 0) { + if (decpt == 0) { + *bufp++ = '0'; + } + else { + while (decpt--) { + if (*nump != '\0') { + *bufp++ = *nump++; + } + else { + *bufp++ = '0'; + } + } + } + if (*nump != '\0') { + *bufp++ = '.'; + while (*nump != '\0') { + *bufp++ = *nump++; + } + } + *bufp++ = '\0'; + } + else if (decpt < 0) { + *bufp++ = '0'; + *bufp++ = '.'; + while (decpt++) { + *bufp++ = '0'; + } + + while (*nump != '\0') { + *bufp++ = *nump++; + } + *bufp++ = '\0'; + } +done: +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(num); +#else + free(num); +#endif +} + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + */ +static void +Find_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + // |count| specifies how many iterations to make from |offset| + + if (offset < 0) + { + offset = 0; + } + else if (PRUint32(offset) > bigLen) + { + count = 0; + return; + } + + PRInt32 maxCount = bigLen - offset; + if (count < 0 || count > maxCount) + { + count = maxCount; + } + else + { + count += littleLen; + if (count > maxCount) + count = maxCount; + } + } + + /** + * this method changes the meaning of |offset| and |count|: + * + * upon entry, + * |offset| specifies the end point from which to search backwards + * |count| specifies the number of iterations from |offset| + * + * upon return, + * |offset| specifies start of search range + * |count| specifies length of search range + * + * + * EXAMPLE + * + * + -- littleLen=4 -- + + * : : + * |____|____|____|____|____|____|____|____|____|____|____|____| + * : : + * offset=5 bigLen=12 + * + * if count = 4, then we expect this function to return offset = 2 and + * count = 7. + * + */ +static void +RFind_ComputeSearchRange( PRUint32 bigLen, PRUint32 littleLen, PRInt32& offset, PRInt32& count ) + { + if (littleLen > bigLen) + { + offset = 0; + count = 0; + return; + } + + if (offset < 0) + offset = bigLen - littleLen; + if (count < 0) + count = offset + 1; + + PRInt32 start = offset - count + 1; + if (start < 0) + start = 0; + + count = offset + littleLen - start; + offset = start; + } + +//----------------------------------------------------------------------------- + + // define nsString obsolete methods +#include "string-template-def-unichar.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + + // define nsCString obsolete methods +#include "string-template-def-char.h" +#include "nsTStringObsolete.cpp" +#include "string-template-undef.h" + +//----------------------------------------------------------------------------- + +// specialized methods: + +PRInt32 +nsString::Find( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::Find( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return Find(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::RFind( const nsAFlatString& aString, PRInt32 aOffset, PRInt32 aCount ) const + { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), PR_FALSE); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsString::RFind( const PRUnichar* aString, PRInt32 aOffset, PRInt32 aCount ) const + { + return RFind(nsDependentString(aString), aOffset, aCount); + } + +PRInt32 +nsString::FindCharInSet( const PRUnichar* aSet, PRInt32 aOffset ) const + { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= PRInt32(mLength)) + return kNotFound; + + PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + if (result != kNotFound) + result += aOffset; + return result; + } + + + /** + * nsTString::Compare,CompareWithConversion,etc. + */ + +PRInt32 +nsCString::Compare( const char* aString, PRBool aIgnoreCase, PRInt32 aCount ) const + { + PRUint32 strLen = char_traits::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines::compare(mData, aString, compareCount, aIgnoreCase); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = (mLength < strLen) ? -1 : 1; + } + return result; + } + +PRBool +nsString::EqualsIgnoreCase( const char* aString, PRInt32 aCount ) const + { + PRUint32 strLen = nsCharTraits::length(aString); + + PRInt32 maxCount = PRInt32(NS_MIN(mLength, strLen)); + + PRInt32 compareCount; + if (aCount < 0 || aCount > maxCount) + compareCount = maxCount; + else + compareCount = aCount; + + PRInt32 result = + nsBufferRoutines::compare(mData, aString, compareCount, PR_TRUE); + + if (result == 0 && + (aCount < 0 || strLen < PRUint32(aCount) || mLength < PRUint32(aCount))) + { + // Since the caller didn't give us a length to test, or strings shorter + // than aCount, and compareCount characters matched, we have to assume + // that the longer string is greater. + + if (mLength != strLen) + result = 1; // Arbitrarily using any number != 0 + } + return result == 0; + } + + /** + * ToCString, ToFloat, ToInteger + */ + +char* +nsString::ToCString( char* aBuf, PRUint32 aBufLength, PRUint32 aOffset ) const + { + // because the old implementation checked aBuf + if (!(aBuf && aBufLength > 0 && aOffset <= mLength)) + return nsnull; + + PRUint32 maxCount = NS_MIN(aBufLength-1, mLength - aOffset); + + LossyConvertEncoding converter(aBuf); + converter.write(mData + aOffset, maxCount); + converter.write_terminator(); + return aBuf; + } + +float +nsCString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + if (mLength > 0) + { + char *conv_stopped; + const char *str = mData; + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + +float +nsString::ToFloat(PRInt32* aErrorCode) const + { + float res = 0.0f; + char buf[100]; + if (mLength > 0 && mLength < sizeof(buf)) + { + char *conv_stopped; + const char *str = ToCString(buf, sizeof(buf)); + // Use PR_strtod, not strtod, since we don't want locale involved. + res = (float)PR_strtod(str, &conv_stopped); + if (conv_stopped == str+mLength) + *aErrorCode = (PRInt32) NS_OK; + else // Not all the string was scanned + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + else + { + // The string was too short (0 characters) or too long (sizeof(buf)) + *aErrorCode = (PRInt32) NS_ERROR_ILLEGAL_VALUE; + } + return res; + } + + + /** + * nsTString::AssignWithConversion + */ + +void +nsCString::AssignWithConversion( const nsAString& aData ) + { + LossyCopyUTF16toASCII(aData, *this); + } + +void +nsString::AssignWithConversion( const nsACString& aData ) + { + CopyASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendWithConversion + */ + +void +nsCString::AppendWithConversion( const nsAString& aData ) + { + LossyAppendUTF16toASCII(aData, *this); + } + +void +nsString::AppendWithConversion( const nsACString& aData ) + { + AppendASCIItoUTF16(aData, *this); + } + + + /** + * nsTString::AppendInt + */ + +void +nsCString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt32 aInteger, PRInt32 aRadix ) + { + char buf[20]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%o"; + break; + case 10: + fmt = "%d"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%x"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + +void +nsCString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + Append(buf); + } + +void +nsString::AppendInt( PRInt64 aInteger, PRInt32 aRadix ) + { + char buf[30]; + const char* fmt; + switch (aRadix) { + case 8: + fmt = "%llo"; + break; + case 10: + fmt = "%lld"; + break; + default: + NS_ASSERTION(aRadix == 16, "Invalid radix!"); + fmt = "%llx"; + } + PR_snprintf(buf, sizeof(buf), fmt, aInteger); + AppendASCIItoUTF16(buf, *this); + } + + /** + * nsTString::AppendFloat + */ + +void +nsCString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + Append(buf); + } + +void +nsString::AppendFloat( double aFloat ) + { + char buf[40]; + // Use Modified_cnvtf, which is locale-insensitive, instead of the + // locale-sensitive PR_snprintf or sprintf(3) + Modified_cnvtf(buf, sizeof(buf), 6, aFloat); + AppendWithConversion(buf); + } + +#endif // !MOZ_STRING_WITH_OBSOLETE_API diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp new file mode 100644 index 00000000..6ed0c5c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsSubstring.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +#ifdef DEBUG +#define ENABLE_STRING_STATS +#endif + +#ifdef ENABLE_STRING_STATS +#include +#endif + +#include +#include "nsSubstring.h" +#include "nsString.h" +#include "nsDependentString.h" +#include "nsMemory.h" +#include "pratom.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + +// --------------------------------------------------------------------------- + +static const PRUnichar gNullChar = 0; + +const char* nsCharTraits ::sEmptyBuffer = (const char*) &gNullChar; +const PRUnichar* nsCharTraits::sEmptyBuffer = &gNullChar; + +// --------------------------------------------------------------------------- + +#ifdef ENABLE_STRING_STATS +class nsStringStats + { + public: + nsStringStats() + : mAllocCount(0), mReallocCount(0), mFreeCount(0), mShareCount(0) {} + + ~nsStringStats() + { + // this is a hack to suppress duplicate string stats printing + // in seamonkey as a result of the string code being linked + // into seamonkey and libxpcom! :-( + if (!mAllocCount && !mAdoptCount) + return; + +#ifndef VBOX + printf("nsStringStats\n"); + printf(" => mAllocCount: % 10d\n", mAllocCount); + printf(" => mReallocCount: % 10d\n", mReallocCount); + printf(" => mFreeCount: % 10d", mFreeCount); + if (mAllocCount > mFreeCount) + printf(" -- LEAKED %d !!!\n", mAllocCount - mFreeCount); + else + printf("\n"); + printf(" => mShareCount: % 10d\n", mShareCount); + printf(" => mAdoptCount: % 10d\n", mAdoptCount); + printf(" => mAdoptFreeCount: % 10d", mAdoptFreeCount); + if (mAdoptCount > mAdoptFreeCount) + printf(" -- LEAKED %d !!!\n", mAdoptCount - mAdoptFreeCount); + else + printf("\n"); +#endif + } + + PRInt32 mAllocCount; + PRInt32 mReallocCount; + PRInt32 mFreeCount; + PRInt32 mShareCount; + PRInt32 mAdoptCount; + PRInt32 mAdoptFreeCount; + }; +static nsStringStats gStringStats; +#define STRING_STAT_INCREMENT(_s) PR_AtomicIncrement(&gStringStats.m ## _s ## Count) +#else +#define STRING_STAT_INCREMENT(_s) +#endif + +// --------------------------------------------------------------------------- + + /** + * This structure precedes the string buffers "we" allocate. It may be the + * case that nsTSubstring::mData does not point to one of these special + * buffers. The mFlags member variable distinguishes the buffer type. + * + * When this header is in use, it enables reference counting, and capacity + * tracking. NOTE: A string buffer can be modified only if its reference + * count is 1. + */ +class nsStringHeader + { + private: + + PRInt32 mRefCount; + PRUint32 mStorageSize; + + public: + + void AddRef() + { + PR_AtomicIncrement(&mRefCount); + STRING_STAT_INCREMENT(Share); + } + + void Release() + { + if (PR_AtomicDecrement(&mRefCount) == 0) + { + STRING_STAT_INCREMENT(Free); +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(this); // we were allocated with |malloc| +#else + free(this); // we were allocated with |malloc| +#endif + } + } + + /** + * Alloc returns a pointer to a new string header with set capacity. + */ + static nsStringHeader* Alloc(size_t size) + { + STRING_STAT_INCREMENT(Alloc); + + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + + nsStringHeader *hdr = +#ifdef VBOX_USE_IPRT_IN_XPCOM + (nsStringHeader *) RTMemAlloc(sizeof(nsStringHeader) + size); +#else + (nsStringHeader *) malloc(sizeof(nsStringHeader) + size); +#endif + if (hdr) + { + hdr->mRefCount = 1; + hdr->mStorageSize = size; + } + return hdr; + } + + static nsStringHeader* Realloc(nsStringHeader* hdr, size_t size) + { + STRING_STAT_INCREMENT(Realloc); + + NS_ASSERTION(size != 0, "zero capacity allocation not allowed"); + + // no point in trying to save ourselves if we hit this assertion + NS_ASSERTION(!hdr->IsReadonly(), "|Realloc| attempted on readonly string"); + +#ifdef VBOX_USE_IPRT_IN_XPCOM + hdr = (nsStringHeader*) RTMemRealloc(hdr, sizeof(nsStringHeader) + size); +#else + hdr = (nsStringHeader*) realloc(hdr, sizeof(nsStringHeader) + size); +#endif + if (hdr) + hdr->mStorageSize = size; + + return hdr; + } + + static nsStringHeader* FromData(void* data) + { + return (nsStringHeader*) ( ((char*) data) - sizeof(nsStringHeader) ); + } + + void* Data() const + { + return (void*) ( ((char*) this) + sizeof(nsStringHeader) ); + } + + PRUint32 StorageSize() const + { + return mStorageSize; + } + + /** + * Because nsTSubstring allows only single threaded access, if this + * method returns FALSE, then the caller can be sure that it has + * exclusive access to the nsStringHeader and associated data. + * However, if this function returns TRUE, then other strings may + * rely on the data in this buffer being constant and other threads + * may access this buffer simultaneously. + */ + PRBool IsReadonly() const + { + return mRefCount > 1; + } + }; + +// --------------------------------------------------------------------------- + +inline void +ReleaseData( void* data, PRUint32 flags ) + { + if (flags & nsSubstring::F_SHARED) + { + nsStringHeader::FromData(data)->Release(); + } + else if (flags & nsSubstring::F_OWNED) + { + nsMemory::Free(data); + STRING_STAT_INCREMENT(AdoptFree); + } + // otherwise, nothing to do. + } + + + // define nsSubstring +#include "string-template-def-unichar.h" +#include "nsTSubstring.cpp" +#include "string-template-undef.h" + + // define nsCSubstring +#include "string-template-def-char.h" +#include "nsTSubstring.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp new file mode 100644 index 00000000..a5445d7a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsSubstringTuple.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsSubstringTuple.h" + +#if 0 + // convert fragment to |const string_base_type&| +#define TO_SUBSTRING(_v) \ + ( (ptrdiff_t(_v) & 0x1) \ + ? NS_REINTERPRET_CAST(const abstract_string_type*, \ + ((unsigned long)_v & ~0x1))->ToSubstring() \ + : *NS_REINTERPRET_CAST(const substring_type*, (_v)) ) +#endif + + // convert fragment to |const substring_type&| +#define TO_SUBSTRING(_v) \ + ( (_v)->mVTable == obsolete_string_type::sCanonicalVTable \ + ? *(_v)->AsSubstring() \ + : (_v)->ToSubstring() ) + + // define nsSubstringTuple +#include "string-template-def-unichar.h" +#include "nsTSubstringTuple.cpp" +#include "string-template-undef.h" + + // define nsCSubstringTuple +#include "string-template-def-char.h" +#include "nsTSubstringTuple.cpp" +#include "string-template-undef.h" diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp new file mode 100644 index 00000000..ffd75fe8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTAString.cpp @@ -0,0 +1,509 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * Some comments on this implementation... + * + * This class is a bridge between the old string implementation and the new + * string implementation. If mVTable points to the canonical vtable for the + * new string implementation, then we can cast directly to the new string + * classes (helped by the AsSubstring() methods). However, if mVTable is not + * ours, then we need to call through the vtable to satisfy the nsTAString + * methods. + * + * In most cases we will avoid the vtable. + */ + + +nsTAString_CharT::~nsTAString_CharT() + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Finalize(); + else + AsObsoleteString()->~nsTObsoleteAString_CharT(); + } + + +nsTAString_CharT::size_type +nsTAString_CharT::Length() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Length(); + + return AsObsoleteString()->Length(); + } + +PRBool +nsTAString_CharT::Equals( const self_type& readable ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(readable); + + return ToSubstring().Equals(readable); + } + +PRBool +nsTAString_CharT::Equals( const self_type& readable, const comparator_type& comparator ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(readable, comparator); + + return ToSubstring().Equals(readable, comparator); + } + +PRBool +nsTAString_CharT::Equals( const char_type* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(data); + + return ToSubstring().Equals(data); + } + +PRBool +nsTAString_CharT::Equals( const char_type* data, const comparator_type& comparator ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Equals(data, comparator); + + return ToSubstring().Equals(data, comparator); + } + +PRBool +nsTAString_CharT::EqualsASCII( const char* data, size_type len ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->EqualsASCII(data, len); + + return ToSubstring().EqualsASCII(data, len); + } + +PRBool +nsTAString_CharT::EqualsASCII( const char* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->EqualsASCII(data); + + return ToSubstring().EqualsASCII(data); + } + +PRBool +nsTAString_CharT::LowerCaseEqualsASCII( const char* data, size_type len ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->LowerCaseEqualsASCII(data, len); + + return ToSubstring().LowerCaseEqualsASCII(data, len); + } + +PRBool +nsTAString_CharT::LowerCaseEqualsASCII( const char* data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->LowerCaseEqualsASCII(data); + + return ToSubstring().LowerCaseEqualsASCII(data); + } + +PRBool +nsTAString_CharT::IsVoid() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsVoid(); + + return AsObsoleteString()->IsVoid(); + } + +void +nsTAString_CharT::SetIsVoid( PRBool val ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetIsVoid(val); + else + AsObsoleteString()->SetIsVoid(val); + } + +PRBool +nsTAString_CharT::IsTerminated() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsTerminated(); + + return AsObsoleteString()->GetFlatBufferHandle() != nsnull; + } + +CharT +nsTAString_CharT::First() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->First(); + + return ToSubstring().First(); + } + +CharT +nsTAString_CharT::Last() const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->Last(); + + return ToSubstring().Last(); + } + +nsTAString_CharT::size_type +nsTAString_CharT::CountChar( char_type c ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->CountChar(c); + + return ToSubstring().CountChar(c); + } + +PRInt32 +nsTAString_CharT::FindChar( char_type c, index_type offset ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->FindChar(c, offset); + + return ToSubstring().FindChar(c, offset); + } + +void +nsTAString_CharT::SetCapacity( size_type size ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetCapacity(size); + else + AsObsoleteString()->SetCapacity(size); + } + +void +nsTAString_CharT::SetLength( size_type size ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->SetLength(size); + else + AsObsoleteString()->SetLength(size); + } + +void +nsTAString_CharT::Assign( const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(readable); + else + AsObsoleteString()->do_AssignFromReadable(readable); + } + +void +nsTAString_CharT::Assign( const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(tuple); + else + AsObsoleteString()->do_AssignFromReadable(nsTAutoString_CharT(tuple)); + } + +void +nsTAString_CharT::Assign( const char_type* data ) + { + // null check and SetLength(0) cases needed for backwards compat + + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(data); + else if (data) + AsObsoleteString()->do_AssignFromElementPtr(data); + else + AsObsoleteString()->SetLength(0); + } + +void +nsTAString_CharT::Assign( const char_type* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(data, length); + else + AsObsoleteString()->do_AssignFromElementPtrLength(data, length); + } + +void +nsTAString_CharT::AssignASCII( const char* data ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AssignASCII(data); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AssignFromElementPtr(data); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data); + AsObsoleteString()->do_AssignFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::AssignASCII( const char* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AssignASCII(data, length); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AssignFromElementPtrLength(data, length); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data, length); + AsObsoleteString()->do_AssignFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::Assign( char_type c ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Assign(c); + else + AsObsoleteString()->do_AssignFromElement(c); + } + +void +nsTAString_CharT::Append( const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(readable); + else + AsObsoleteString()->do_AppendFromReadable(readable); + } + +void +nsTAString_CharT::Append( const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(tuple); + else + AsObsoleteString()->do_AppendFromReadable(nsTAutoString_CharT(tuple)); + } + +void +nsTAString_CharT::Append( const char_type* data ) + { + // null check case needed for backwards compat + + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(data); + else if (data) + AsObsoleteString()->do_AppendFromElementPtr(data); + } + +void +nsTAString_CharT::Append( const char_type* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(data, length); + else + AsObsoleteString()->do_AppendFromElementPtrLength(data, length); + } + +void +nsTAString_CharT::AppendASCII( const char* data ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AppendASCII(data); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AppendFromElementPtr(data); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data); + AsObsoleteString()->do_AppendFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::AppendASCII( const char* data, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->AppendASCII(data, length); + else + { +#ifdef CharT_is_char + AsObsoleteString()->do_AppendFromElementPtrLength(data, length); +#else + nsTAutoString_CharT temp; + temp.AssignASCII(data, length); + AsObsoleteString()->do_AppendFromReadable(temp); +#endif + } + } + +void +nsTAString_CharT::Append( char_type c ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Append(c); + else + AsObsoleteString()->do_AppendFromElement(c); + } + +void +nsTAString_CharT::Insert( const self_type& readable, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(readable, pos); + else + AsObsoleteString()->do_InsertFromReadable(readable, pos); + } + +void +nsTAString_CharT::Insert( const substring_tuple_type& tuple, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(tuple, pos); + else + AsObsoleteString()->do_InsertFromReadable(nsTAutoString_CharT(tuple), pos); + } + +void +nsTAString_CharT::Insert( const char_type* data, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(data, pos); + else + AsObsoleteString()->do_InsertFromElementPtr(data, pos); + } + +void +nsTAString_CharT::Insert( const char_type* data, index_type pos, size_type length ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(data, pos, length); + else + AsObsoleteString()->do_InsertFromElementPtrLength(data, pos, length); + } + +void +nsTAString_CharT::Insert( char_type c, index_type pos ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Insert(c, pos); + else + AsObsoleteString()->do_InsertFromElement(c, pos); + } + +void +nsTAString_CharT::Cut( index_type cutStart, size_type cutLength ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Cut(cutStart, cutLength); + else + AsObsoleteString()->Cut(cutStart, cutLength); + } + +void +nsTAString_CharT::Replace( index_type cutStart, size_type cutLength, const self_type& readable ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Replace(cutStart, cutLength, readable); + else + AsObsoleteString()->do_ReplaceFromReadable(cutStart, cutLength, readable); + } + +void +nsTAString_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + AsSubstring()->Replace(cutStart, cutLength, tuple); + else + AsObsoleteString()->do_ReplaceFromReadable(cutStart, cutLength, nsTAutoString_CharT(tuple)); + } + +nsTAString_CharT::size_type +nsTAString_CharT::GetReadableBuffer( const char_type **data ) const + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + { + const substring_type* str = AsSubstring(); + *data = str->mData; + return str->mLength; + } + + obsolete_string_type::const_fragment_type frag; + AsObsoleteString()->GetReadableFragment(frag, obsolete_string_type::kFirstFragment, 0); + *data = frag.mStart; + return (frag.mEnd - frag.mStart); + } + +nsTAString_CharT::size_type +nsTAString_CharT::GetWritableBuffer(char_type **data) + { + if (mVTable == obsolete_string_type::sCanonicalVTable) + { + substring_type* str = AsSubstring(); + str->BeginWriting(*data); + return str->Length(); + } + + obsolete_string_type::fragment_type frag; + AsObsoleteString()->GetWritableFragment(frag, obsolete_string_type::kFirstFragment, 0); + *data = frag.mStart; + return (frag.mEnd - frag.mStart); + } + +PRBool +nsTAString_CharT::IsDependentOn(const char_type* start, const char_type *end) const + { + // this is an optimization... + if (mVTable == obsolete_string_type::sCanonicalVTable) + return AsSubstring()->IsDependentOn(start, end); + + return ToSubstring().IsDependentOn(start, end); + } + +const nsTAString_CharT::substring_type +nsTAString_CharT::ToSubstring() const + { + const char_type* data; + size_type length = GetReadableBuffer(&data); + return substring_type(NS_CONST_CAST(char_type*, data), length, 0); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp new file mode 100644 index 00000000..8421ecc0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTDependentSubstring.cpp @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +void +nsTDependentSubstring_CharT::Rebind( const abstract_string_type& readable, PRUint32 startPos, PRUint32 length ) + { + size_type strLength = readable.GetReadableBuffer((const char_type**) &mData); + + if (startPos > strLength) + startPos = strLength; + + mData += startPos; + mLength = NS_MIN(length, strLength - startPos); + + SetDataFlags(F_NONE); + } + +void +nsTDependentSubstring_CharT::Rebind( const substring_type& str, PRUint32 startPos, PRUint32 length ) + { + size_type strLength = str.Length(); + + if (startPos > strLength) + startPos = strLength; + + mData = NS_CONST_CAST(char_type*, str.Data()) + startPos; + mLength = NS_MIN(length, strLength - startPos); + + SetDataFlags(F_NONE); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp new file mode 100644 index 00000000..3d1590a8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTObsoleteAStringThunk.cpp @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + +class nsTObsoleteAStringThunk_CharT : public nsTObsoleteAString_CharT + { + public: + typedef nsTObsoleteAStringThunk_CharT self_type; + typedef nsTSubstring_CharT substring_type; + + public: + + nsTObsoleteAStringThunk_CharT() {} + + + static const void* get_vptr() + { + const void* result; + new (&result) self_type(); + return result; + } + + + /** + * we are a nsTSubstring in disguise! + */ + + substring_type* concrete_self() { return NS_REINTERPRET_CAST( substring_type*, this); } + const substring_type* concrete_self() const { return NS_REINTERPRET_CAST(const substring_type*, this); } + + + /** + * all virtual methods need to be redirected to appropriate nsString methods + */ + + virtual ~nsTObsoleteAStringThunk_CharT() + { + concrete_self()->Finalize(); + } + + virtual PRUint32 GetImplementationFlags() const + { + return 0; + } + + virtual const buffer_handle_type* GetFlatBufferHandle() const + { + return (const buffer_handle_type*) (concrete_self()->IsTerminated() != PR_FALSE); + } + + virtual const buffer_handle_type* GetBufferHandle() const + { + return 0; + } + + virtual const shared_buffer_handle_type* GetSharedBufferHandle() const + { + return 0; + } + + virtual size_type Length() const + { + return concrete_self()->Length(); + } + + virtual PRBool IsVoid() const + { + return concrete_self()->IsVoid(); + } + + virtual void SetIsVoid(PRBool val) + { + concrete_self()->SetIsVoid(val); + } + + virtual void SetCapacity(size_type size) + { + concrete_self()->SetCapacity(size); + } + + virtual void SetLength(size_type size) + { + concrete_self()->SetLength(size); + } + + virtual void Cut(index_type cutStart, size_type cutLength) + { + concrete_self()->Cut(cutStart, cutLength); + } + + virtual void do_AssignFromReadable(const abstract_string_type &s) + { + concrete_self()->Assign(s); + } + + virtual void do_AssignFromElementPtr(const char_type *data) + { + concrete_self()->Assign(data); + } + + virtual void do_AssignFromElementPtrLength(const char_type *data, size_type length) + { + concrete_self()->Assign(data, length); + } + + virtual void do_AssignFromElement(char_type c) + { + concrete_self()->Assign(c); + } + + virtual void do_AppendFromReadable(const abstract_string_type &s) + { + concrete_self()->Append(s); + } + + virtual void do_AppendFromElementPtr(const char_type *data) + { + concrete_self()->Append(data); + } + + virtual void do_AppendFromElementPtrLength(const char_type *data, size_type length) + { + concrete_self()->Append(data, length); + } + + virtual void do_AppendFromElement(char_type c) + { + concrete_self()->Append(c); + } + + virtual void do_InsertFromReadable(const abstract_string_type &s, index_type pos) + { + concrete_self()->Insert(s, pos); + } + + virtual void do_InsertFromElementPtr(const char_type *data, index_type pos) + { + concrete_self()->Insert(data, pos); + } + + virtual void do_InsertFromElementPtrLength(const char_type *data, index_type pos, size_type length) + { + concrete_self()->Insert(data, pos, length); + } + + virtual void do_InsertFromElement(char_type c, index_type pos) + { + concrete_self()->Insert(c, pos); + } + + virtual void do_ReplaceFromReadable(index_type cutStart, size_type cutLength, const abstract_string_type &s) + { + concrete_self()->Replace(cutStart, cutLength, s); + } + + virtual const char_type *GetReadableFragment(const_fragment_type& frag, nsFragmentRequest which, PRUint32 offset) const + { + const substring_type* s = concrete_self(); + switch (which) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + frag.mStart = s->Data(); + frag.mEnd = frag.mStart + s->Length(); + return frag.mStart + offset; + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + + virtual char_type *GetWritableFragment(fragment_type& frag, nsFragmentRequest which, PRUint32 offset) + { + substring_type* s = concrete_self(); + switch (which) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + char_type* start; + s->BeginWriting(start); + frag.mStart = start; + frag.mEnd = start + s->Length(); + return frag.mStart + offset; + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + }; + + + /** + * initialize the pointer to the canonical vtable... + */ + +const void *nsTObsoleteAString_CharT::sCanonicalVTable = nsTObsoleteAStringThunk_CharT::get_vptr(); diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp new file mode 100644 index 00000000..bf0bfc32 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTPromiseFlatString.cpp @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +void +nsTPromiseFlatString_CharT::Init(const substring_type& str) + { + // we have to manually set this here since we are being called on an + // unitialized object. + mVTable = nsTObsoleteAString_CharT::sCanonicalVTable; + + if (str.IsTerminated()) + { + mData = NS_CONST_CAST(char_type*, str.Data()); + mLength = str.Length(); + mFlags = F_TERMINATED; // does not promote F_VOIDED + } + else + { + Assign(str); + } + } + + // this function is non-inline to minimize codesize +void +nsTPromiseFlatString_CharT::Init(const abstract_string_type& readable) + { + if (readable.mVTable == nsTObsoleteAString_CharT::sCanonicalVTable) + Init(*readable.AsSubstring()); + else + Init(readable.ToSubstring()); + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp new file mode 100644 index 00000000..84911f5f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTString.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * Johnny Stenback + * + * 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 ***** */ + +NS_COM nsTAdoptingString_CharT& +nsTAdoptingString_CharT::operator=( const self_type& str ) + { + // This'll violate the constness of this argument, that's just + // the nature of this class... + self_type* mutable_str = NS_CONST_CAST(self_type*, &str); + + if (str.mFlags & F_OWNED) + { + Adopt(str.mData, str.mLength); + + // Make str forget the buffer we just took ownership of. + new (mutable_str) self_type(); + } + else + { + Assign(str); + + mutable_str->Truncate(); + } + + return *this; + } + diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp new file mode 100644 index 00000000..6d2645a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTStringComparator.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + +NS_COM int +Compare( const nsTAString_CharT& lhs, const nsTAString_CharT& rhs, const nsTStringComparator_CharT& comp ) + { + typedef nsTAString_CharT::size_type size_type; + + if ( &lhs == &rhs ) + return 0; + + nsTAString_CharT::const_iterator leftIter, rightIter; + lhs.BeginReading(leftIter); + rhs.BeginReading(rightIter); + + size_type lLength = leftIter.size_forward(); + size_type rLength = rightIter.size_forward(); + size_type lengthToCompare = NS_MIN(lLength, rLength); + + int result; + if ( (result = comp(leftIter.get(), rightIter.get(), lengthToCompare)) == 0 ) + { + if ( lLength < rLength ) + result = -1; + else if ( rLength < lLength ) + result = 1; + else + result = 0; + } + + return result; + } + +int +nsTDefaultStringComparator_CharT::operator()( const char_type* lhs, const char_type* rhs, PRUint32 aLength ) const + { + return nsCharTraits::compare(lhs, rhs, aLength); + } + +int +nsTDefaultStringComparator_CharT::operator()( char_type lhs, char_type rhs) const + { + return lhs - rhs; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp new file mode 100644 index 00000000..5ed065ad --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTStringObsolete.cpp @@ -0,0 +1,518 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + + /** + * nsTString::Find + * + * aOffset specifies starting index + * aCount specifies number of string compares (iterations) + */ + +PRInt32 +nsTString_CharT::Find( const nsCString& aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + // this method changes the meaning of aOffset and aCount: + Find_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = FindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsTString_CharT::Find( const char* aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + return Find(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + } + + + /** + * nsTString::RFind + * + * aOffset specifies starting index + * aCount specifies number of string compares (iterations) + */ + +PRInt32 +nsTString_CharT::RFind( const nsCString& aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + // this method changes the meaning of aOffset and aCount: + RFind_ComputeSearchRange(mLength, aString.Length(), aOffset, aCount); + + PRInt32 result = RFindSubstring(mData + aOffset, aCount, aString.get(), aString.Length(), aIgnoreCase); + if (result != kNotFound) + result += aOffset; + return result; + } + +PRInt32 +nsTString_CharT::RFind( const char* aString, PRBool aIgnoreCase, PRInt32 aOffset, PRInt32 aCount) const + { + return RFind(nsDependentCString(aString), aIgnoreCase, aOffset, aCount); + } + + + /** + * nsTString::RFindChar + */ + +PRInt32 +nsTString_CharT::RFindChar( PRUnichar aChar, PRInt32 aOffset, PRInt32 aCount) const + { + return nsBufferRoutines::rfind_char(mData, mLength, aOffset, aChar, aCount); + } + + + /** + * nsTString::FindCharInSet + */ + +PRInt32 +nsTString_CharT::FindCharInSet( const char* aSet, PRInt32 aOffset ) const + { + if (aOffset < 0) + aOffset = 0; + else if (aOffset >= PRInt32(mLength)) + return kNotFound; + + PRInt32 result = ::FindCharInSet(mData + aOffset, mLength - aOffset, aSet); + if (result != kNotFound) + result += aOffset; + return result; + } + + + /** + * nsTString::RFindCharInSet + */ + +PRInt32 +nsTString_CharT::RFindCharInSet( const CharT* aSet, PRInt32 aOffset ) const + { + // We want to pass a "data length" to ::RFindCharInSet + if (aOffset < 0 || aOffset > PRInt32(mLength)) + aOffset = mLength; + else + ++aOffset; + + return ::RFindCharInSet(mData, aOffset, aSet); + } + + + // it's a shame to replicate this code. it was done this way in the past + // to help performance. this function also gets to keep the rickg style + // indentation :-/ +PRInt32 +nsTString_CharT::ToInteger( PRInt32* aErrorCode, PRUint32 aRadix ) const +{ + CharT* cp=mData; + PRInt32 theRadix=10; // base 10 unless base 16 detected, or overriden (aRadix != kAutoDetect) + PRInt32 result=0; + PRBool negate=PR_FALSE; + CharT theChar=0; + + //initial value, override if we find an integer + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + + if(cp) { + + //begin by skipping over leading chars that shouldn't be part of the number... + + CharT* endcp=cp+mLength; + PRBool done=PR_FALSE; + + while((cp='A') && (theChar<='F')) { + if(10==theRadix) { + if(kAutoDetect==aRadix){ + theRadix=16; + cp=first; //backup + result=0; + haveValue = PR_FALSE; + } + else { + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + result=0; + break; + } + } + else { + result = (theRadix * result) + ((theChar-'A')+10); + haveValue = PR_TRUE; + } + } + else if((theChar>='a') && (theChar<='f')) { + if(10==theRadix) { + if(kAutoDetect==aRadix){ + theRadix=16; + cp=first; //backup + result=0; + haveValue = PR_FALSE; + } + else { + *aErrorCode=NS_ERROR_ILLEGAL_VALUE; + result=0; + break; + } + } + else { + result = (theRadix * result) + ((theChar-'a')+10); + haveValue = PR_TRUE; + } + } + else if((('X'==theChar) || ('x'==theChar)) && (!haveValue || result == 0)) { + continue; + } + else if((('#'==theChar) || ('+'==theChar)) && !haveValue) { + continue; + } + else { + //we've encountered a char that's not a legal number or sign + break; + } + } //while + if(negate) + result=-result; + } //if + } + return result; +} + + + /** + * nsTString::Mid + */ + +PRUint32 +nsTString_CharT::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const + { + if (aStartPos == 0 && aLengthToCopy >= mLength) + aResult = *this; + else + aResult = Substring(*this, aStartPos, aLengthToCopy); + + return aResult.mLength; + } + + + /** + * nsTString::SetCharAt + */ + +PRBool +nsTString_CharT::SetCharAt( PRUnichar aChar, PRUint32 aIndex ) + { + if (aIndex >= mLength) + return PR_FALSE; + + EnsureMutable(); + + mData[aIndex] = CharT(aChar); + return PR_TRUE; + } + + + /** + * nsTString::StripChars,StripChar,StripWhitespace + */ + +void +nsTString_CharT::StripChars( const char* aSet ) + { + EnsureMutable(); + mLength = nsBufferRoutines::strip_chars(mData, mLength, aSet); + } + +void +nsTString_CharT::StripChar( char_type aChar, PRInt32 aOffset ) + { + if (mLength == 0 || aOffset >= PRInt32(mLength)) + return; + + EnsureMutable(); // XXX do this lazily? + + // XXXdarin this code should defer writing until necessary. + + char_type* to = mData + aOffset; + char_type* from = mData + aOffset; + char_type* end = mData + mLength; + + while (from < end) + { + char_type theChar = *from++; + if (aChar != theChar) + *to++ = theChar; + } + *to = char_type(0); // add the null + mLength = to - mData; + } + +void +nsTString_CharT::StripWhitespace() + { + StripChars(kWhitespace); + } + + + /** + * nsTString::ReplaceChar,ReplaceSubstring + */ + +void +nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) + { + EnsureMutable(); // XXX do this lazily? + + for (PRUint32 i=0; i 2 && mData[0] == mData[mLength - 1] && + (mData[0] == '\'' || mData[0] == '"')) + { + ++start; + --end; + } + + PRUint32 setLen = nsCharTraits::length(aSet); + + if (aTrimLeading) + { + PRUint32 cutStart = start - mData; + PRUint32 cutLength = 0; + + // walk forward from start to end + for (; start != end; ++start, ++cutLength) + { + PRInt32 pos = FindChar1(aSet, setLen, 0, *start, setLen); + if (pos == kNotFound) + break; + } + + if (cutLength) + { + Cut(cutStart, cutLength); + + // reset iterators + start = mData + cutStart; + end = mData + mLength - cutStart; + } + } + + if (aTrimTrailing) + { + PRUint32 cutEnd = end - mData; + PRUint32 cutLength = 0; + + // walk backward from end to start + --end; + for (; end >= start; --end, ++cutLength) + { + PRInt32 pos = FindChar1(aSet, setLen, 0, *end, setLen); + if (pos == kNotFound) + break; + } + + if (cutLength) + Cut(cutEnd - cutLength, cutLength); + } + } + + + /** + * nsTString::CompressWhitespace + */ + +void +nsTString_CharT::CompressWhitespace( PRBool aTrimLeading, PRBool aTrimTrailing ) + { + const char* set = kWhitespace; + + ReplaceChar(set, ' '); + Trim(set, aTrimLeading, aTrimTrailing); + + // this one does some questionable fu... just copying the old code! + mLength = nsBufferRoutines::compress_chars(mData, mLength, set); + } + + + /** + * nsTString::AssignWithConversion + */ + +void +nsTString_CharT::AssignWithConversion( const incompatible_char_type* aData, PRInt32 aLength ) + { + // for compatibility with the old string implementation, we need to allow + // for a NULL input buffer :-( + if (!aData) + { + Truncate(); + } + else + { + if (aLength < 0) + aLength = nsCharTraits::length(aData); + + AssignWithConversion(Substring(aData, aData + aLength)); + } + } + + + /** + * nsTString::AppendWithConversion + */ + +void +nsTString_CharT::AppendWithConversion( const incompatible_char_type* aData, PRInt32 aLength ) + { + // for compatibility with the old string implementation, we need to allow + // for a NULL input buffer :-( + if (aData) + { + if (aLength < 0) + aLength = nsCharTraits::length(aData); + + AppendWithConversion(Substring(aData, aData + aLength)); + } + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp new file mode 100644 index 00000000..e36b1863 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstring.cpp @@ -0,0 +1,656 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * helper function for down-casting a nsTSubstring to a nsTFixedString. + */ +inline const nsTFixedString_CharT* +AsFixedString( const nsTSubstring_CharT* s ) + { + return NS_STATIC_CAST(const nsTFixedString_CharT*, s); + } + + + /** + * this function is called to prepare mData for writing. the given capacity + * indicates the required minimum storage size for mData, in sizeof(char_type) + * increments. this function returns true if the operation succeeds. it also + * returns the old data and old flags members if mData is newly allocated. + * the old data must be released by the caller. + */ +PRBool +nsTSubstring_CharT::MutatePrep( size_type capacity, char_type** oldData, PRUint32* oldFlags ) + { + // initialize to no old data + *oldData = nsnull; + *oldFlags = 0; + + size_type curCapacity = Capacity(); + + // |curCapacity == size_type(-1)| means that the buffer is immutable, so we + // need to allocate a new buffer. we cannot use the existing buffer even + // though it might be large enough. + + if (curCapacity != size_type(-1)) + { + if (capacity <= curCapacity) + return PR_TRUE; + + if (curCapacity > 0) + { + // use doubling algorithm when forced to increase available capacity, + // but always start out with exactly the requested amount. + PRUint32 temp = curCapacity; + while (temp < capacity) + temp <<= 1; + capacity = temp; + } + } + + // + // several cases: + // + // (1) we have a shared buffer (mFlags & F_SHARED) + // (2) we have an owned buffer (mFlags & F_OWNED) + // (3) we have a fixed buffer (mFlags & F_FIXED) + // (4) we have a readonly buffer + // + // requiring that we in some cases preserve the data before creating + // a new buffer complicates things just a bit ;-) + // + + size_type storageSize = (capacity + 1) * sizeof(char_type); + + // case #1 + if (mFlags & F_SHARED) + { + nsStringHeader* hdr = nsStringHeader::FromData(mData); + if (!hdr->IsReadonly()) + { + nsStringHeader *newHdr = nsStringHeader::Realloc(hdr, storageSize); + if (newHdr) + { + hdr = newHdr; + mData = (char_type*) hdr->Data(); + return PR_TRUE; + } + hdr->Release(); + // out of memory!! put us in a consistent state at least. + mData = NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer); + mLength = 0; + SetDataFlags(F_TERMINATED); + return PR_FALSE; + } + } + + char_type* newData; + PRUint32 newDataFlags; + + // if we have a fixed buffer of sufficient size, then use it. this helps + // avoid heap allocations. + if ((mFlags & F_CLASS_FIXED) && (capacity < AsFixedString(this)->mFixedCapacity)) + { + newData = AsFixedString(this)->mFixedBuf; + newDataFlags = F_TERMINATED | F_FIXED; + } + else + { + // if we reach here then, we must allocate a new buffer. we cannot + // make use of our F_OWNED or F_FIXED buffers because they are not + // large enough. + + nsStringHeader* newHdr = nsStringHeader::Alloc(storageSize); + if (!newHdr) + return PR_FALSE; // we are still in a consistent state + + newData = (char_type*) newHdr->Data(); + newDataFlags = F_TERMINATED | F_SHARED; + } + + // save old data and flags + *oldData = mData; + *oldFlags = mFlags; + + mData = newData; + SetDataFlags(newDataFlags); + + // mLength does not change + + // though we are not necessarily terminated at the moment, now is probably + // still the best time to set F_TERMINATED. + + return PR_TRUE; + } + +void +nsTSubstring_CharT::Finalize() + { + ::ReleaseData(mData, mFlags); + // mData, mLength, and mFlags are purposefully left dangling + } + +void +nsTSubstring_CharT::ReplacePrep( index_type cutStart, size_type cutLen, size_type fragLen ) + { + // bound cut length + cutLen = NS_MIN(cutLen, mLength - cutStart); + + PRUint32 newLen = mLength - cutLen + fragLen; + + char_type* oldData; + PRUint32 oldFlags; + if (!MutatePrep(newLen, &oldData, &oldFlags)) + return; // XXX out-of-memory error occured! + + if (oldData) + { + // determine whether or not we need to copy part of the old string + // over to the new string. + + if (cutStart > 0) + { + // copy prefix from old string + char_traits::copy(mData, oldData, cutStart); + } + + if (cutStart + cutLen < mLength) + { + // copy suffix from old string to new offset + size_type from = cutStart + cutLen; + size_type fromLen = mLength - from; + PRUint32 to = cutStart + fragLen; + char_traits::copy(mData + to, oldData + from, fromLen); + } + + ::ReleaseData(oldData, oldFlags); + } + else + { + // original data remains intact + + // determine whether or not we need to move part of the existing string + // to make room for the requested hole. + if (fragLen != cutLen && cutStart + cutLen < mLength) + { + PRUint32 from = cutStart + cutLen; + PRUint32 fromLen = mLength - from; + PRUint32 to = cutStart + fragLen; + char_traits::move(mData + to, mData + from, fromLen); + } + } + + // add null terminator (mutable mData always has room for the null- + // terminator). + mData[newLen] = char_type(0); + mLength = newLen; + } + +nsTSubstring_CharT::size_type +nsTSubstring_CharT::Capacity() const + { + // return size_type(-1) to indicate an immutable buffer + + size_type capacity; + if (mFlags & F_SHARED) + { + // if the string is readonly, then we pretend that it has no capacity. + nsStringHeader* hdr = nsStringHeader::FromData(mData); + if (hdr->IsReadonly()) + capacity = size_type(-1); + else + capacity = (hdr->StorageSize() / sizeof(char_type)) - 1; + } + else if (mFlags & F_FIXED) + { + capacity = AsFixedString(this)->mFixedCapacity; + } + else if (mFlags & F_OWNED) + { + // we don't store the capacity of an adopted buffer because that would + // require an additional member field. the best we can do is base the + // capacity on our length. remains to be seen if this is the right + // trade-off. + capacity = mLength; + } + else + { + capacity = size_type(-1); + } + + return capacity; + } + +void +nsTSubstring_CharT::EnsureMutable() + { + if (mFlags & (F_FIXED | F_OWNED)) + return; + if ((mFlags & F_SHARED) && !nsStringHeader::FromData(mData)->IsReadonly()) + return; + + // promote to a shared string buffer + Assign(string_type(mData, mLength)); + } + +// --------------------------------------------------------------------------- + +void +nsTSubstring_CharT::Assign( const char_type* data, size_type length ) + { + // unfortunately, some callers pass null :-( + if (!data) + { + Truncate(); + return; + } + + if (length == size_type(-1)) + length = char_traits::length(data); + + if (IsDependentOn(data, data + length)) + { + // take advantage of sharing here... + Assign(string_type(data, length)); + return; + } + + ReplacePrep(0, mLength, length); + char_traits::copy(mData, data, length); + } + +void +nsTSubstring_CharT::AssignASCII( const char* data, size_type length ) + { + // A Unicode string can't depend on an ASCII string buffer, + // so this dependence check only applies to CStrings. +#ifdef CharT_is_char + if (IsDependentOn(data, data + length)) + { + // take advantage of sharing here... + Assign(string_type(data, length)); + return; + } +#endif + + ReplacePrep(0, mLength, length); + char_traits::copyASCII(mData, data, length); + } + +void +nsTSubstring_CharT::AssignASCII( const char* data ) + { + AssignASCII(data, strlen(data)); + } + +void +nsTSubstring_CharT::Assign( const self_type& str ) + { + // |str| could be sharable. we need to check its flags to know how to + // deal with it. + + if (&str == this) + return; + + if (str.mFlags & F_SHARED) + { + // nice! we can avoid a string copy :-) + + // |str| should be null-terminated + NS_ASSERTION(str.mFlags & F_TERMINATED, "shared, but not terminated"); + + ::ReleaseData(mData, mFlags); + + mData = str.mData; + mLength = str.mLength; + SetDataFlags(F_TERMINATED | F_SHARED); + + // get an owning reference to the mData + nsStringHeader::FromData(mData)->AddRef(); + } + else if (str.mFlags & F_VOIDED) + { + // inherit the F_VOIDED attribute + SetIsVoid(PR_TRUE); + } + else + { + // else, treat this like an ordinary assignment. + Assign(str.Data(), str.Length()); + } + } + +void +nsTSubstring_CharT::Assign( const substring_tuple_type& tuple ) + { + if (tuple.IsDependentOn(mData, mData + mLength)) + { + // take advantage of sharing here... + Assign(string_type(tuple)); + return; + } + + size_type length = tuple.Length(); + + ReplacePrep(0, mLength, length); + if (length) + tuple.WriteTo(mData, length); + } + + // this is non-inline to reduce codesize at the callsite +void +nsTSubstring_CharT::Assign( const abstract_string_type& readable ) + { + // promote to string if possible to take advantage of sharing + if (readable.mVTable == nsTObsoleteAString_CharT::sCanonicalVTable) + Assign(*readable.AsSubstring()); + else + Assign(readable.ToSubstring()); + } + + +void +nsTSubstring_CharT::Adopt( char_type* data, size_type length ) + { + if (data) + { + ::ReleaseData(mData, mFlags); + + if (length == size_type(-1)) + length = char_traits::length(data); + + mData = data; + mLength = length; + SetDataFlags(F_TERMINATED | F_OWNED); + + STRING_STAT_INCREMENT(Adopt); + } + else + { + SetIsVoid(PR_TRUE); + } + } + + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length ) + { + // unfortunately, some callers pass null :-( + if (!data) + { + length = 0; + } + else + { + if (length == size_type(-1)) + length = char_traits::length(data); + + if (IsDependentOn(data, data + length)) + { + nsTAutoString_CharT temp(data, length); + Replace(cutStart, cutLength, temp); + return; + } + } + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + char_traits::copy(mData + cutStart, data, length); + } + +void +nsTSubstring_CharT::ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length ) + { + if (length == size_type(-1)) + length = strlen(data); + + // A Unicode string can't depend on an ASCII string buffer, + // so this dependence check only applies to CStrings. +#ifdef CharT_is_char + if (IsDependentOn(data, data + length)) + { + nsTAutoString_CharT temp(data, length); + Replace(cutStart, cutLength, temp); + return; + } +#endif + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + char_traits::copyASCII(mData + cutStart, data, length); + } + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ) + { + if (tuple.IsDependentOn(mData, mData + mLength)) + { + nsTAutoString_CharT temp(tuple); + Replace(cutStart, cutLength, temp); + return; + } + + size_type length = tuple.Length(); + + cutStart = PR_MIN(cutStart, Length()); + + ReplacePrep(cutStart, cutLength, length); + + if (length > 0) + tuple.WriteTo(mData + cutStart, length); + } + +void +nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const abstract_string_type& readable ) + { + Replace(cutStart, cutLength, readable.ToSubstring()); + } + +void +nsTSubstring_CharT::SetCapacity( size_type capacity ) + { + // capacity does not include room for the terminating null char + + // if our capacity is reduced to zero, then free our buffer. + if (capacity == 0) + { + ::ReleaseData(mData, mFlags); + mData = NS_CONST_CAST(char_type*, char_traits::sEmptyBuffer); + mLength = 0; + SetDataFlags(F_TERMINATED); + } + else + { + char_type* oldData; + PRUint32 oldFlags; + if (!MutatePrep(capacity, &oldData, &oldFlags)) + return; // XXX out-of-memory error occured! + + // compute new string length + size_type newLen = NS_MIN(mLength, capacity); + + if (oldData) + { + // preserve old data + if (mLength > 0) + char_traits::copy(mData, oldData, newLen); + + ::ReleaseData(oldData, oldFlags); + } + + // adjust mLength if our buffer shrunk down in size + if (newLen < mLength) + mLength = newLen; + + // always null-terminate here, even if the buffer got longer. this is + // for backwards compat with the old string implementation. + mData[capacity] = char_type(0); + } + } + +void +nsTSubstring_CharT::SetLength( size_type length ) + { + SetCapacity(length); + mLength = length; + } + +void +nsTSubstring_CharT::SetIsVoid( PRBool val ) + { + if (val) + { + Truncate(); + mFlags |= F_VOIDED; + } + else + { + mFlags &= ~F_VOIDED; + } + } + +PRBool +nsTSubstring_CharT::Equals( const self_type& str ) const + { + return mLength == str.mLength && char_traits::compare(mData, str.mData, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const self_type& str, const comparator_type& comp ) const + { + return mLength == str.mLength && comp(mData, str.mData, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const abstract_string_type& readable ) const + { + const char_type* data; + size_type length = readable.GetReadableBuffer(&data); + + return mLength == length && char_traits::compare(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const abstract_string_type& readable, const comparator_type& comp ) const + { + const char_type* data; + size_type length = readable.GetReadableBuffer(&data); + + return mLength == length && comp(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const char_type* data ) const + { + // unfortunately, some callers pass null :-( + if (!data) + { + NS_NOTREACHED("null data pointer"); + return mLength == 0; + } + + // XXX avoid length calculation? + size_type length = char_traits::length(data); + return mLength == length && char_traits::compare(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::Equals( const char_type* data, const comparator_type& comp ) const + { + // unfortunately, some callers pass null :-( + if (!data) + { + NS_NOTREACHED("null data pointer"); + return mLength == 0; + } + + // XXX avoid length calculation? + size_type length = char_traits::length(data); + return mLength == length && comp(mData, data, mLength) == 0; + } + +PRBool +nsTSubstring_CharT::EqualsASCII( const char* data, size_type len ) const + { + return mLength == len && char_traits::compareASCII(mData, data, len) == 0; + } + +PRBool +nsTSubstring_CharT::EqualsASCII( const char* data ) const + { + return char_traits::compareASCIINullTerminated(mData, mLength, data) == 0; + } + +PRBool +nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data, size_type len ) const + { + return mLength == len && char_traits::compareLowerCaseToASCII(mData, data, len) == 0; + } + +PRBool +nsTSubstring_CharT::LowerCaseEqualsASCII( const char* data ) const + { + return char_traits::compareLowerCaseToASCIINullTerminated(mData, mLength, data) == 0; + } + +nsTSubstring_CharT::size_type +nsTSubstring_CharT::CountChar( char_type c ) const + { + const char_type *start = mData; + const char_type *end = mData + mLength; + + return NS_COUNT(start, end, c); + } + +PRInt32 +nsTSubstring_CharT::FindChar( char_type c, index_type offset ) const + { + if (offset < mLength) + { + const char_type* result = char_traits::find(mData + offset, mLength - offset, c); + if (result) + return result - mData; + } + return -1; + } diff --git a/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp new file mode 100644 index 00000000..7fff5175 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/string/src/nsTSubstringTuple.cpp @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 ***** */ + + + /** + * computes the aggregate string length + */ + +nsTSubstringTuple_CharT::size_type +nsTSubstringTuple_CharT::Length() const + { + PRUint32 len; + if (mHead) + len = mHead->Length(); + else + len = TO_SUBSTRING(mFragA).Length(); + + return len + TO_SUBSTRING(mFragB).Length(); + } + + + /** + * writes the aggregate string to the given buffer. bufLen is assumed + * to be equal to or greater than the value returned by the Length() + * method. the string written to |buf| is not null-terminated. + */ + +void +nsTSubstringTuple_CharT::WriteTo( char_type *buf, PRUint32 bufLen ) const + { + const substring_type& b = TO_SUBSTRING(mFragB); + + NS_ASSERTION(bufLen >= b.Length(), "buffer too small"); + PRUint32 headLen = bufLen - b.Length(); + if (mHead) + { + mHead->WriteTo(buf, headLen); + } + else + { + const substring_type& a = TO_SUBSTRING(mFragA); + + NS_ASSERTION(a.Length() == headLen, "buffer incorrectly sized"); + char_traits::copy(buf, a.Data(), a.Length()); + } + + char_traits::copy(buf + headLen, b.Data(), b.Length()); + +#if 0 + // we need to write out data into |buf|, ending at |buf+bufLen|. so our + // data needs to precede |buf+bufLen| exactly. we trust that the buffer + // was properly sized! + + const substring_type& b = TO_SUBSTRING(mFragB); + + NS_ASSERTION(bufLen >= b.Length(), "buffer is too small"); + char_traits::copy(buf + bufLen - b.Length(), b.Data(), b.Length()); + + bufLen -= b.Length(); + + if (mHead) + { + mHead->WriteTo(buf, bufLen); + } + else + { + const substring_type& a = TO_SUBSTRING(mFragA); + NS_ASSERTION(bufLen == a.Length(), "buffer is too small"); + char_traits::copy(buf, a.Data(), a.Length()); + } +#endif + } + + + /** + * returns true if this tuple is dependent on (i.e., overlapping with) + * the given char sequence. + */ + +PRBool +nsTSubstringTuple_CharT::IsDependentOn( const char_type *start, const char_type *end ) const + { + // we start with the right-most fragment since it is faster to check. + + if (TO_SUBSTRING(mFragB).IsDependentOn(start, end)) + return PR_TRUE; + + if (mHead) + return mHead->IsDependentOn(start, end); + + return TO_SUBSTRING(mFragA).IsDependentOn(start, end); + } diff --git a/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp b/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp new file mode 100644 index 00000000..ca9a76e4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/stub/nsStringAPI.cpp @@ -0,0 +1,261 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsString.h" +#include "nsCharTraits.h" + +#define NS_STRINGAPI_IMPL +#include "nsStringAPI.h" +#include "nsNativeCharsetUtils.h" + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_StringContainerInit(nsStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsStringContainer) >= sizeof(nsString), + "nsStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsString object + new (&aContainer) nsString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_StringContainerFinish(nsStringContainer &aContainer) +{ + // call the nsString dtor + NS_REINTERPRET_CAST(nsString *, &aContainer)->~nsString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_StringGetData(const nsAString &aStr, const PRUnichar **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsAString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(PRUnichar *) +NS_StringCloneData(const nsAString &aStr) +{ + return ToNewUnicode(aStr); +} + +NS_STRINGAPI(nsresult) +NS_StringSetData(nsAString &aStr, const PRUnichar *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringSetDataRange(nsAString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const PRUnichar *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_StringCopy(nsAString &aDest, const nsAString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringContainerInit(nsCStringContainer &aContainer) +{ + NS_ASSERTION(sizeof(nsCStringContainer) >= sizeof(nsCString), + "nsCStringContainer is not large enough"); + + // use placement new to avoid heap allocating nsCString object + new (&aContainer) nsCString(); + + return NS_OK; +} + +NS_STRINGAPI(void) +NS_CStringContainerFinish(nsCStringContainer &aContainer) +{ + // call the nsCString dtor + NS_REINTERPRET_CAST(nsCString *, &aContainer)->~nsCString(); +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(PRUint32) +NS_CStringGetData(const nsACString &aStr, const char **aData, + PRBool *aTerminated) +{ + if (aTerminated) + *aTerminated = aStr.IsTerminated(); + + nsACString::const_iterator begin; + aStr.BeginReading(begin); + *aData = begin.get(); + return begin.size_forward(); +} + +NS_STRINGAPI(char *) +NS_CStringCloneData(const nsACString &aStr) +{ + return ToNewCString(aStr); +} + +NS_STRINGAPI(nsresult) +NS_CStringSetData(nsACString &aStr, const char *aData, PRUint32 aDataLength) +{ + aStr.Assign(aData, aDataLength); + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringSetDataRange(nsACString &aStr, + PRUint32 aCutOffset, PRUint32 aCutLength, + const char *aData, PRUint32 aDataLength) +{ + if (aCutOffset == PR_UINT32_MAX) + { + // append case + if (aData) + aStr.Append(aData, aDataLength); + return NS_OK; // XXX report errors + } + + if (aCutLength == PR_UINT32_MAX) + aCutLength = aStr.Length() - aCutOffset; + + if (aData) + { + if (aDataLength == PR_UINT32_MAX) + aStr.Replace(aCutOffset, aCutLength, nsDependentCString(aData)); + else + aStr.Replace(aCutOffset, aCutLength, Substring(aData, aData + aDataLength)); + } + else + aStr.Cut(aCutOffset, aCutLength); + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_CStringCopy(nsACString &aDest, const nsACString &aSrc) +{ + aDest.Assign(aSrc); + return NS_OK; // XXX report errors +} + +/* ------------------------------------------------------------------------- */ + +NS_STRINGAPI(nsresult) +NS_CStringToUTF16(const nsACString &aSrc, + nsCStringEncoding aSrcEncoding, + nsAString &aDest) +{ + switch (aSrcEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + CopyASCIItoUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF8toUTF16(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyNativeToUnicode(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} + +NS_STRINGAPI(nsresult) +NS_UTF16ToCString(const nsAString &aSrc, + nsCStringEncoding aDestEncoding, + nsACString &aDest) +{ + switch (aDestEncoding) + { + case NS_CSTRING_ENCODING_ASCII: + LossyCopyUTF16toASCII(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_UTF8: + CopyUTF16toUTF8(aSrc, aDest); + break; + case NS_CSTRING_ENCODING_NATIVE_FILESYSTEM: + NS_CopyUnicodeToNative(aSrc, aDest); + break; + default: + return NS_ERROR_NOT_IMPLEMENTED; + } + + return NS_OK; // XXX report errors +} diff --git a/src/libs/xpcom18a4/xpcom/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/.cvsignore new file mode 100644 index 00000000..d01075e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/.cvsignore @@ -0,0 +1,31 @@ +CvtURL +FilesTest +Makefile +PropertiesTest +RegFactory +SizeTest01 +SizeTest02 +SizeTest03 +SizeTest04 +SizeTest05 +SizeTest06 +TestAtoms +TestAutoLock +TestBuffers +TestCOMPtr +TestCOMPtrEq +TestArray +TestCRT +TestFactory +TestID +TestObserverService +TestPermanentAtoms +TestPipes +TestThreads +TestVoidBTree +TestXPIDLString +TestServMgr +nsIFileEnumerator +nsIFileTest +TestCallTemplates +TestDeque diff --git a/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp b/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp new file mode 100644 index 00000000..4dd052ac --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/CvtURL.cpp @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "nscore.h" +#include "nsIConverterInputStream.h" +#include "nsIURL.h" +#include "nsNetUtil.h" +#include "nsCRT.h" +#include "nsString.h" +#include "prprf.h" +#include "prtime.h" + +static nsString* ConvertCharacterSetName(const char* aName) +{ + return new nsString(NS_ConvertASCIItoUCS2(aName)); +} + +int main(int argc, char** argv) +{ + if (3 != argc) { + printf("usage: CvtURL url utf8\n"); + return -1; + } + + char* characterSetName = argv[2]; + nsString* cset = ConvertCharacterSetName(characterSetName); + if (NS_PTR_TO_INT32(cset) < 0) { + printf("illegal character set name: '%s'\n", characterSetName); + return -1; + } + + // Create url object + char* urlName = argv[1]; + nsIURI* url; + nsresult rv; + rv = NS_NewURI(&url, urlName); + if (NS_OK != rv) { + printf("invalid URL: '%s'\n", urlName); + return -1; + } + + // Get an input stream from the url + nsresult ec; + nsIInputStream* in; + ec = NS_OpenURI(&in, url); + if (nsnull == in) { + printf("open of url('%s') failed: error=%x\n", urlName, ec); + return -1; + } + + // Translate the input using the argument character set id into + // unicode + nsCOMPtr uin = + do_CreateInstance("@mozilla.org/intl/converter-input-stream;1", &rv); + if (NS_SUCCEEDED(rv)) + uin->Init(in, cset->get(), nsnull, PR_TRUE); + if (NS_OK != rv) { + printf("can't create converter input stream: %d\n", rv); + return -1; + } + + // Read the input and write some output + PRTime start = PR_Now(); + PRInt32 count = 0; + for (;;) { + PRUnichar buf[1000]; + PRUint32 nb; + ec = uin->Read(buf, 0, 1000, &nb); + if (NS_FAILED(ec)) { + printf("i/o error: %d\n", ec); + break; + } + if (nb == 0) break; // EOF + count += nb; + } + PRTime end = PR_Now(); + PRTime conversion, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(conversion, end, start); + LL_DIV(conversion, conversion, ustoms); + char buf[500]; + PR_snprintf(buf, sizeof(buf), + "converting and discarding %d bytes took %lldms", + count, conversion); + puts(buf); + + // Release the objects + in->Release(); + url->Release(); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/Makefile.in new file mode 100644 index 00000000..2bd730e9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/Makefile.in @@ -0,0 +1,116 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = dynamic services +ifeq ($(OS_ARCH),WINNT) +DIRS += windows +endif + +REQUIRES = \ + string \ + $(NULL) + +CPPSRCS = \ + nsIFileEnumerator.cpp \ + nsIFileTest.cpp \ + TestArray.cpp \ + TestAtoms.cpp \ + TestAutoLock.cpp \ + TestCallTemplates.cpp \ + TestCOMPtr.cpp \ + TestCOMPtrEq.cpp \ + TestCRT.cpp \ + TestFactory.cpp \ + TestHashtables.cpp \ + TestID.cpp \ + TestObserverService.cpp \ + TestPermanentAtoms.cpp \ + TestPipes.cpp \ + TestServMgr.cpp \ + TestThreads.cpp \ + TestXPIDLString.cpp \ + TestDeque.cpp \ + TestAutoPtr.cpp \ + TestMinStringAPI.cpp \ + TestStrings.cpp \ + $(NULL) + +#CPPSRCS += TimerTest.cpp + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +LIBS += \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +# Needed to resolve __yylex (?) +ifeq ($(OS_ARCH)$(OS_RELEASE),FreeBSD2) +LIBS += -lpcap +endif + +include $(topsrcdir)/config/rules.mk + +LOCAL_INCLUDES = \ + -I$(srcdir)/../ds \ + -I$(srcdir)/services \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +ifdef GNU_CXX +CXXFLAGS += -fexceptions +else +CXXFLAGS += -GX +endif +endif + +libs:: + $(INSTALL) $(srcdir)/test.properties $(DIST)/bin/res + +install:: + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/test.properties $(DESTDIR)$(mozappdir)/res + diff --git a/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp b/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp new file mode 100644 index 00000000..79e53394 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/RegFactory.cpp @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "plstr.h" +#include "prlink.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsILocalFile.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +static PRBool gUnreg = PR_FALSE; + +void print_err(nsresult err) +{ + switch (err) { + case NS_ERROR_FACTORY_NOT_LOADED: + cerr << "Factory not loaded"; + break; + case NS_NOINTERFACE: + cerr << "No Interface"; + break; + case NS_ERROR_NULL_POINTER: + cerr << "Null pointer"; + break; + case NS_ERROR_OUT_OF_MEMORY: + cerr << "Out of memory"; + break; + default: + cerr << hex << err << dec; + } +} + +nsresult Register(nsIComponentRegistrar* registrar, const char *path) +{ + nsCOMPtr file; + nsresult rv = + NS_NewLocalFile( + NS_ConvertUTF8toUCS2(path), + PR_TRUE, + getter_AddRefs(file)); + if (NS_FAILED(rv)) return rv; + rv = registrar->AutoRegister(file); + return rv; +} + +nsresult Unregister(const char *path) +{ + /* NEEDS IMPLEMENTATION */ +#if 0 + nsresult res = nsComponentManager::AutoUnregisterComponent(path); + return res; +#else + return NS_ERROR_FAILURE; +#endif +} + +int ProcessArgs(nsIComponentRegistrar* registrar, int argc, char *argv[]) +{ + int i = 1; + nsresult res; + + while (i < argc) { + if (argv[i][0] == '-') { + int j; + for (j = 1; argv[i][j] != '\0'; j++) { + switch (argv[i][j]) { + case 'u': + gUnreg = PR_TRUE; + break; + default: + cerr << "Unknown option '" << argv[i][j] << "'\n"; + } + } + i++; + } else { + if (gUnreg == PR_TRUE) { + res = Unregister(argv[i]); + if (NS_SUCCEEDED(res)) { + cout << "Successfully unregistered: " << argv[i] << "\n"; + } else { + cerr << "Unregister failed ("; + print_err(res); + cerr << "): " << argv[i] << "\n"; + } + } else { + res = Register(registrar, argv[i]); + if (NS_SUCCEEDED(res)) { + cout << "Successfully registered: " << argv[i] << "\n"; + } else { + cerr << "Register failed ("; + print_err(res); + cerr << "): " << argv[i] << "\n"; + } + } + i++; + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + nsresult rv; + { + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + + /* With no arguments, RegFactory will autoregister */ + if (argc <= 1) + { + rv = registrar->AutoRegister(nsnull); + ret = (NS_FAILED(rv)) ? -1 : 0; + } + else + ret = ProcessArgs(registrar, argc, argv); + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM( NULL ); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return ret; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp new file mode 100644 index 00000000..2d552a36 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest01.cpp @@ -0,0 +1,107 @@ +// Test01.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +NS_DEF_PTR(nsIDOMNode); + + /* + This test file compares the generated code size of similar functions between raw + COM interface pointers (|AddRef|ing and |Release|ing by hand) and |nsCOMPtr|s. + + Function size results were determined by examining dissassembly of the generated code. + mXXX is the size of the generated code on the Macintosh. wXXX is the size on Windows. + For these tests, all reasonable optimizations were enabled and exceptions were + disabled (just as we build for release). + + The tests in this file explore only the simplest functionality: assigning a pointer + to be reference counted into a [raw, nsCOMPtr] object; ensuring that it is + |AddRef|ed and |Release|d appropriately; calling through the pointer to a function + supplied by the underlying COM interface. + + Windows: + raw_optimized 31 bytes + raw, nsCOMPtr* 34 + nsCOMPtr_optimized* 38 + nsCOMPtr_optimized 42 + nsCOMPtr 46 + + Macintosh: + raw_optimized, nsCOMPtr_optimized 112 bytes (1.0000) + nsCOMPtr 120 (1.0714) i.e., 7.14% bigger than raw_optimized et al + raw 140 (1.2500) + + The overall difference in size between Windows and Macintosh is caused by the + the PowerPC RISC architecture where every instruction is 4 bytes. + + On Macintosh, nsCOMPtr generates out-of-line destructors which are + not referenced, and which can be stripped by the linker. + */ + +void +Test01_raw( nsIDOMNode* aDOMNode, nsString* aResult ) + // m140, w34 + { + /* + This test is designed to be more like a typical large function where, + because you are working with several resources, you don't just return when + one of them is |NULL|. Similarly: |Test01_nsCOMPtr00|, and |Test01_nsIPtr00|. + */ + + nsIDOMNode* node = aDOMNode; + NS_IF_ADDREF(node); + + if ( node ) + node->GetNodeName(*aResult); + + NS_IF_RELEASE(node); + } + +void +Test01_raw_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w31 + { + /* + This test simulates smaller functions where you _do_ just return + |NULL| at the first sign of trouble. Similarly: |Test01_nsCOMPtr01|, + and |Test01_nsIPtr01|. + */ + + /* + This test produces smaller code that |Test01_raw| because it avoids + the three tests: |NS_IF_...|, and |if ( node )|. + */ + +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode ) +// return; + + nsIDOMNode* node = aDOMNode; + NS_ADDREF(node); + node->GetNodeName(*aResult); + NS_RELEASE(node); + } + +void +Test01_nsCOMPtr( nsIDOMNode* aDOMNode, nsString* aResult ) + // m120, w46/34 + { + nsCOMPtr node = aDOMNode; + + if ( node ) + node->GetNodeName(*aResult); + } + +void +Test01_nsCOMPtr_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w42/38 + { +// if ( !aDOMNode ) +// return; + + nsCOMPtr node = aDOMNode; + node->GetNodeName(*aResult); + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp new file mode 100644 index 00000000..8515fcb1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest02.cpp @@ -0,0 +1,93 @@ +// Test02.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + This test file compares the generated code size of similar functions between raw + COM interface pointers (|AddRef|ing and |Release|ing by hand) and |nsCOMPtr|s. + + Function size results were determined by examining dissassembly of the generated code. + mXXX is the size of the generated code on the Macintosh. wXXX is the size on Windows. + For these tests, all reasonable optimizations were enabled and exceptions were + disabled (just as we build for release). + + The tests in this file explore more complicated functionality: assigning a pointer + to be reference counted into a [raw, nsCOMPtr] object using |QueryInterface|; + ensuring that it is |AddRef|ed and |Release|d appropriately; calling through the pointer + to a function supplied by the underlying COM interface. The tests in this file expand + on the tests in "Test01.cpp" by adding |QueryInterface|. + + Windows: + raw01 52 + nsCOMPtr 63 + raw 66 + nsCOMPtr* 68 + + Macintosh: + nsCOMPtr 120 (1.0000) + Raw01 128 (1.1429) i.e., 14.29% bigger than nsCOMPtr + Raw00 144 (1.2000) + */ + + +void // nsresult +Test02_Raw00( nsISupports* aDOMNode, nsString* aResult ) + // m144, w66 + { +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* node = 0; + nsresult status = aDOMNode->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)&node); + if ( NS_SUCCEEDED(status) ) + { + node->GetNodeName(*aResult); + } + + NS_IF_RELEASE(node); + +// return status; + } + +void // nsresult +Test02_Raw01( nsISupports* aDOMNode, nsString* aResult ) + // m128, w52 + { +// if ( !aDOMNode ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* node; + nsresult status = aDOMNode->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)&node); + if ( NS_SUCCEEDED(status) ) + { + node->GetNodeName(*aResult); + NS_RELEASE(node); + } + +// return status; + } + +void // nsresult +Test02_nsCOMPtr( nsISupports* aDOMNode, nsString* aResult ) + // m120, w63/68 + { + nsresult status; + nsCOMPtr node = do_QueryInterface(aDOMNode, &status); + + if ( node ) + node->GetNodeName(*aResult); + +// return status; + } + diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp new file mode 100644 index 00000000..9ca71c72 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest03.cpp @@ -0,0 +1,101 @@ +// Test03.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + nsCOMPtr_optimized* 45 + raw_optimized 48 + nsCOMPtr_optimized 50 + nsCOMPtr 54 + nsCOMPtr* 59 + raw 62 + + Macintosh: + nsCOMPtr_optimized 112 (1.0000) + raw_optimized 124 bytes (1.1071) i.e., 10.71% bigger than nsCOMPtr_optimized + nsCOMPtr 144 (1.2857) + */ + +void // nsresult +Test03_raw( nsIDOMNode* aDOMNode, nsString* aResult ) + // m140, w62 + { +// -- the following code is assumed, but is commented out so we compare only +// the relevent generated code + +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* parent = 0; + nsresult status = aDOMNode->GetParentNode(&parent); + + if ( NS_SUCCEEDED(status) ) + { + parent->GetNodeName(*aResult); + } + + NS_IF_RELEASE(parent); + +// return status; + } + + +void // nsresult +Test03_raw_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m124, w48 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* parent; + nsresult status = aDOMNode->GetParentNode(&parent); + + if ( NS_SUCCEEDED(status) ) + { + parent->GetNodeName(*aResult); + NS_RELEASE(parent); + } + +// return status; + } + + +void // nsresult +Test03_nsCOMPtr( nsIDOMNode* aDOMNode, nsString* aResult ) + // m144, w54/59 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsCOMPtr parent; + nsresult status = aDOMNode->GetParentNode( getter_AddRefs(parent) ); + if ( parent ) + parent->GetNodeName(*aResult); + +// return status; + } + +void // nsresult +Test03_nsCOMPtr_optimized( nsIDOMNode* aDOMNode, nsString* aResult ) + // m112, w50/45 + { +// if ( !aDOMNode || !aResult ) +// return NS_ERROR_NULL_POINTER; + + nsIDOMNode* temp; + nsresult status = aDOMNode->GetParentNode(&temp); + nsCOMPtr parent( dont_AddRef(temp) ); + if ( parent ) + parent->GetNodeName(*aResult); + +// return status; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp new file mode 100644 index 00000000..aad4ee68 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest04.cpp @@ -0,0 +1,72 @@ +// Test04.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + nsCOMPtr 13 + raw 36 + + Macintosh: + nsCOMPtr 36 bytes (1.0000) + raw 120 (3.3333) i.e., 333.33% bigger than nsCOMPtr + */ + +class Test04_Raw + { + public: + Test04_Raw(); + ~Test04_Raw(); + + void /*nsresult*/ SetNode( nsIDOMNode* newNode ); + + private: + nsIDOMNode* mNode; + }; + +Test04_Raw::Test04_Raw() + : mNode(0) + { + // nothing else to do here + } + +Test04_Raw::~Test04_Raw() + { + NS_IF_RELEASE(mNode); + } + +void // nsresult +Test04_Raw::SetNode( nsIDOMNode* newNode ) + // m120, w36 + { + NS_IF_ADDREF(newNode); + NS_IF_RELEASE(mNode); + mNode = newNode; + +// return NS_OK; + } + + + +class Test04_nsCOMPtr + { + public: + void /*nsresult*/ SetNode( nsIDOMNode* newNode ); + + private: + nsCOMPtr mNode; + }; + +void // nsresult +Test04_nsCOMPtr::SetNode( nsIDOMNode* newNode ) + // m36, w13/13 + { + mNode = newNode; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp new file mode 100644 index 00000000..0211610e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest05.cpp @@ -0,0 +1,78 @@ +// Test05.cpp + +#include "nsIDOMNode.h" +#include "nsCOMPtr.h" + +#ifdef __MWERKS__ + #pragma exceptions off +#endif + +NS_DEF_PTR(nsIDOMNode); + + /* + Windows: + raw, nsCOMPtr 21 bytes + + Macintosh: + Raw, nsCOMPtr 64 bytes + */ + +class Test05_Raw + { + public: + Test05_Raw(); + ~Test05_Raw(); + + void /*nsresult*/ GetNode( nsIDOMNode** aNode ); + + private: + nsIDOMNode* mNode; + }; + +Test05_Raw::Test05_Raw() + : mNode(0) + { + // nothing else to do here + } + +Test05_Raw::~Test05_Raw() + { + NS_IF_RELEASE(mNode); + } + +void // nsresult +Test05_Raw::GetNode( nsIDOMNode** aNode ) + // m64, w21 + { +// if ( !aNode ) +// return NS_ERROR_NULL_POINTER; + + *aNode = mNode; + NS_IF_ADDREF(*aNode); + +// return NS_OK; + } + + + +class Test05_nsCOMPtr + { + public: + void /*nsresult*/ GetNode( nsIDOMNode** aNode ); + + private: + nsCOMPtr mNode; + }; + +void // nsresult +Test05_nsCOMPtr::GetNode( nsIDOMNode** aNode ) + // m64, w21 + { +// if ( !aNode ) +// return NS_ERROR_NULL_POINTER; + + *aNode = mNode; + NS_IF_ADDREF(*aNode); + +// return NS_OK; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp b/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp new file mode 100644 index 00000000..2c28e7f3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/SizeTest06.cpp @@ -0,0 +1,231 @@ +// Test06.cpp + +#include "nsIDOMWindowInternal.h" +#include "nsIScriptGlobalObject.h" +#include "nsIWebShell.h" +#include "nsIDocShell.h" +#include "nsIWebShellWindow.h" +#include "nsCOMPtr.h" + +NS_DEF_PTR(nsIScriptGlobalObject); +NS_DEF_PTR(nsIWebShell); +NS_DEF_PTR(nsIWebShellContainer); +NS_DEF_PTR(nsIWebShellWindow); + + /* + Windows: + nsCOMPtr_optimized 176 + nsCOMPtr_as_found 181 + nsCOMPtr_optimized* 182 + nsCOMPtr02* 184 + nsCOMPtr02 187 + nsCOMPtr02* 188 + nsCOMPtr03 189 + raw_optimized, nsCOMPtr00 191 + nsCOMPtr00* 199 + nsCOMPtr_as_found* 201 + raw 214 + + Macintosh: + nsCOMPtr_optimized 300 (1.0000) + nsCOMPtr02 320 (1.0667) i.e., 6.67% bigger than nsCOMPtr_optimized + nsCOMPtr00 328 (1.0933) + raw_optimized, nsCOMPtr03 332 (1.1067) + nsCOMPtr_as_found 344 (1.1467) + raw 388 (1.2933) + + */ + + +void // nsresult +Test06_raw(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m388, w214 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsIScriptGlobalObject* scriptGlobalObject = 0; + nsresult status = aDOMWindow->QueryInterface(NS_GET_IID(nsIScriptGlobalObject), (void**)&scriptGlobalObject); + nsIDocShell* docShell = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&docShell); + nsIWebShell* webShell = 0; + if (docShell) + status=docShell->QueryInterface(NS_GET_IID(nsIWebShell), (void**)&webShell); + nsIWebShell* rootWebShell = 0; + if (webShell) + //status = webShell->GetRootWebShellEvenIfChrome(rootWebShell); + {} + nsIWebShellContainer* webShellContainer = 0; + if (rootWebShell) + status = rootWebShell->GetContainer(webShellContainer); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + else + (*aWebShellWindow) = 0; + NS_IF_RELEASE(webShellContainer); + NS_IF_RELEASE(rootWebShell); + NS_IF_RELEASE(webShell); + NS_IF_RELEASE(docShell); + NS_IF_RELEASE(scriptGlobalObject); +// return status; +} + +void // nsresult +Test06_raw_optimized(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m332, w191 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsIScriptGlobalObject* scriptGlobalObject; + nsresult status = aDOMWindow->QueryInterface(NS_GET_IID(nsIScriptGlobalObject), (void**)&scriptGlobalObject); + if (NS_SUCCEEDED(status)) { + nsIDocShell* docShell = 0; + scriptGlobalObject->GetDocShell(&docShell); + if (docShell) { + nsIWebShell* webShell = 0; + docShell->QueryInterface(NS_GET_IID(nsIWebShell), (void**)webShell); + if (webShell) { + nsIWebShell* rootWebShell; + // status = webShell->GetRootWebShellEvenIfChrome(rootWebShell); + if (NS_SUCCEEDED(status)) { + nsIWebShellContainer* webShellContainer; + status = rootWebShell->GetContainer(webShellContainer); + if (NS_SUCCEEDED(status)) { + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + NS_RELEASE(webShellContainer); + } + NS_RELEASE(rootWebShell); + } + NS_RELEASE(webShell); + } + NS_RELEASE(docShell); + } + NS_RELEASE(scriptGlobalObject); + } +// return status; +} + +void +Test06_nsCOMPtr_as_found(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m344, w181/201 +{ +// if (!aDOMWindow) +// return; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow); + nsCOMPtr docShell; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); + nsCOMPtr webShell; + if (docShell) + webShell = do_QueryInterface(docShell); + nsCOMPtr rootWebShell; + if (webShell) + //webShell->GetRootWebShellEvenIfChrome(*getter_AddRefs(rootWebShell)); + {} + nsCOMPtr webShellContainer; + if (rootWebShell) + rootWebShell->GetContainer(*getter_AddRefs(webShellContainer)); + (*aWebShellWindow) = do_QueryInterface(webShellContainer); +} + +void // nsresult +Test06_nsCOMPtr00(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m328, w191/199 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + nsIDocShell* temp0 = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr docShell = dont_AddRef(temp0); + nsCOMPtr webShell; + if (docShell) + webShell=do_QueryInterface(docShell, &status); + nsIWebShellContainer* temp2 = 0; + if (webShell) + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + else + (*aWebShellWindow) = 0; +// return status; +} + +void // nsresult +Test06_nsCOMPtr_optimized(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m300, w176/182 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + nsIDocShell* temp0 = 0; + if (scriptGlobalObject) + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr webShell = do_QueryInterface(temp0, &status); + nsIWebShell* temp2 = 0; + if (webShell) + // status = webShell->GetRootWebShellEvenIfChrome(temp2); + {} + nsCOMPtr rootWebShell = dont_AddRef(temp2); + nsIWebShellContainer* temp3 = 0; + if (rootWebShell) + status = rootWebShell->GetContainer(temp3); + nsCOMPtr webShellContainer = dont_AddRef(temp3); + (*aWebShellWindow) = do_QueryInterface(webShellContainer, &status); +// return status; +} + +void // nsresult +Test06_nsCOMPtr02(nsIDOMWindowInternal* aDOMWindow, nsIWebShellWindow** aWebShellWindow) + // m320, w187/184 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + if (scriptGlobalObject) { + nsIDocShell* temp0; + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr webShell = do_QueryInterface(temp0); + if (webShell) { + nsIWebShellContainer* temp2; + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + if (webShellContainer) + status = webShellContainer->QueryInterface(NS_GET_IID(nsIWebShellWindow), (void**)aWebShellWindow); + } + } +// return status; +} + +void // nsresult +Test06_nsCOMPtr03(nsIDOMWindowInternal* aDOMWindow, nsCOMPtr* aWebShellWindow) + // m332, w189/188 +{ +// if (!aDOMWindow) +// return NS_ERROR_NULL_POINTER; + (*aWebShellWindow) = 0; + nsresult status; + nsCOMPtr scriptGlobalObject = do_QueryInterface(aDOMWindow, &status); + if (scriptGlobalObject) { + nsIDocShell* temp0; + scriptGlobalObject->GetDocShell(&temp0); + nsCOMPtr docShell = dont_AddRef(temp0); + if (docShell) { + nsCOMPtr webShell = do_QueryInterface(docShell, &status); + if (webShell) { + nsIWebShellContainer* temp2; + status = webShell->GetContainer(temp2); + nsCOMPtr webShellContainer = dont_AddRef(temp2); + (*aWebShellWindow) = do_QueryInterface(webShellContainer, &status); + } + } + } +// return status; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in new file mode 100644 index 00000000..1ced5d3e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/Makefile.in @@ -0,0 +1,76 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +PROGRAM = profile_strings +#PROGRAM = test_main + +CPPSRCS = \ + $(topsrcdir)/xpcom/ds/nsString2.cpp \ + $(topsrcdir)/xpcom/ds/nsStr.cpp \ + $(topsrcdir)/xpcom/ds/nsString.cpp \ + $(topsrcdir)/xpcom/ds/nsCRT.cpp \ + $(topsrcdir)/xpcom/base/nsAllocator.cpp \ + $(topsrcdir)/xpcom/ds/nsDeque.cpp \ + profile_main.cpp \ + $(NULL) +# test_main.cpp \ + + +LIBS += \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DNEW_STRING_APIS -DSTANDALONE_STRING_TESTS -UDEBUG -DNDEBUG +#DEFINES += -DSTANDALONE_STRING_TESTS -UDEBUG -DNDEBUG +INCLUDES += -I$(srcdir)/../public -I$(srcdir)/services + +libs:: + $(INSTALL) $(srcdir)/test.properties $(DIST)/bin/res + +install:: + $(SYSINSTALL) $(IFLAGS1) $(srcdir)/test.properties $(DESTDIR)$(mozappdir)/res + diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix new file mode 100644 index 00000000..b9580e49 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.Prefix @@ -0,0 +1,4 @@ +// StringTest.Prefix + +#define STANDALONE_STRING_TESTS +#define HAVE_CPP_2BYTE_WCHAR_T diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp new file mode 100644 index 00000000..12b125ed Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTest.mcp differ diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix new file mode 100644 index 00000000..3724af94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestDebug.Prefix @@ -0,0 +1,4 @@ +#include "StringTest.Prefix" + +#define DEBUG 1 +#undef NDEBUG diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix new file mode 100644 index 00000000..dddf8450 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestNo_wchar_t.Prefix @@ -0,0 +1,5 @@ +// StringTestNo_wchar_t.Prefix + +#include "StringTest.Prefix" + +#undef HAVE_CPP_2BYTE_WCHAR_T diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix new file mode 100644 index 00000000..b6ca50d3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileNew.Prefix @@ -0,0 +1,3 @@ +// StringTestProfileNew.Prefix + +#include "StringTest.Prefix" diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix new file mode 100644 index 00000000..d23e3ea9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileOld.Prefix @@ -0,0 +1,6 @@ +// StringTestProfileOld.Prefix + +#include "StringTest.Prefix" + +#define OLD_STRING_APIS +#undef HAVE_CPP_2BYTE_WCHAR_T \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix new file mode 100644 index 00000000..eb8a7a85 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/StringTestProfileStd.Prefix @@ -0,0 +1,7 @@ +// StringTestProfileOld.Prefix + +#include "StringTest.Prefix" + +#define OLD_STRING_APIS +#define TEST_STD_STRING +#undef HAVE_CPP_2BYTE_WCHAR_T \ No newline at end of file diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc new file mode 100644 index 00000000..da114471 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/ToDo.doc @@ -0,0 +1,41 @@ +// To Do... + + - Decide: do I really want to define |Equals| (i.e., so many extra signatures) + + . Make |ns[C]String| rename its converting operations to, e.g., |EqualsWithConversion|, + |AssignWithConversion|, |CompareWithConversion|, |AppendWithConversion|, etc. + + . Bring |Equals| and |Compare| into scope + + . Implement chunky iterators + + . Get "nsAReadableString.h" and "nsAWritableString.h" to added to the MANIFEST, etc. + + - Get "nsAReadableString.h" and "nsAWritableString.h" to compile everywhere + + - Add test for |Replace|... + + - Add tests for Find and RFind + + - Implement the Find and RFind signatures + + . Fix Truncate / SetLength confusion (make SetLength the real function in |nsString|) + + . Chop out conflicting |ns[C]String| operators + + . Figure out how if we can make PRUnichar be wchar_t, so we get the cheap constructors, + ...and ensure the cheap constructors can be made to work everywhere + + x Try the |static const unsigned long kLeftString = 1 - 1; /* because VC++ doesn't like =0 */| hack + + . Add tests for |nsShared[C]String| + + . Implement |nsShared[C]String| + + - Add tests for the shared string smart pointer + + . Implement the shared string smart pointer + + . Figure out why StdStringWrapper isn't as good as raw std::string + + - Implement a smart allocator for StdStringWrapper diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h new file mode 100644 index 00000000..6e43b528 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/nsStdStringWrapper.h @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsStdStringWrapper_h___ +#define nsStdStringWrapper_h___ + +#include + +#ifndef nsAString_h___ +#include "nsAString.h" +#endif + + +template +class nsStringAllocator + : public std::allocator // temporarily + { + // ... + }; + + +template < class CharT, class TraitsT = nsCharTraits, class AllocatorT = nsStringAllocator > +class basic_nsStdStringWrapper + : public basic_nsAString + /* + ... + */ + { + protected: + std::basic_string mRawString; + + typedef std::basic_string basic_string_t; + + using typename basic_string_t::traits_type; + using typename basic_string_t::value_type; + using typename basic_string_t::allocator_type; + using typename basic_string_t::size_type; + using typename basic_string_t::difference_type; + using typename basic_string_t::reference; + using typename basic_string_t::const_reference; + using typename basic_string_t::pointer; + using typename basic_string_t::const_pointer; + using typename basic_string_t::iterator; + using typename basic_string_t::const_iterator; + using typename basic_string_t::reverse_iterator; + using typename basic_string_t::const_reverse_iterator; + + static const size_type npos = size_type(-1); + + protected: + virtual const void* Implementation() const; + + virtual const CharT* GetReadableFragment( nsReadableFragment&, nsFragmentRequest, PRUint32 ) const; + virtual CharT* GetWritableFragment( nsWritableFragment&, nsFragmentRequest, PRUint32 ); + + public: + basic_nsStdStringWrapper() { } + +#if 0 + explicit + basic_nsStdStringWrapper( const AllocatorT& a = AllocatorT() ) + : mRawString(a) + { + } +#endif + + explicit + basic_nsStdStringWrapper( const basic_nsAString& str ) + { + Assign(str); + } + +#if 0 + explicit + basic_nsStdStringWrapper( const basic_string_t& str, size_type pos = 0, size_type n = npos ) + : mRawString(str, pos, n) + { + } + + basic_nsStdStringWrapper( const basic_string_t& str, size_type pos, size_type n, const AllocatorT& a ) + : mRawString(str, pos, n, a) + { + } +#endif + + basic_nsStdStringWrapper( const CharT* s, size_type n, const AllocatorT& a = AllocatorT() ) + : mRawString(s, n, a) + { + } + + explicit + basic_nsStdStringWrapper( const CharT* s, const AllocatorT& a = AllocatorT() ) + : mRawString(s, a) + { + } + +#if 0 + basic_nsStdStringWrapper( size_type n, CharT c, const AllocatorT& a = AllocatorT() ) + : mRawString(n, c, a) + { + } +#endif + + virtual + PRUint32 + Length() const + { + return mRawString.length(); + } + + virtual + void + SetCapacity( PRUint32 aNewCapacity ) + { + mRawString.reserve(aNewCapacity); + } + + virtual + void + SetLength( PRUint32 aNewLength ) + { + mRawString.resize(aNewLength); + } + + protected: + virtual void do_AssignFromReadable( const basic_nsAString& ); + + // ... + }; + +NS_DEF_TEMPLATE_STRING_COMPARISON_OPERATORS(basic_nsStdStringWrapper, CharT) + + + +template +const void* +basic_nsStdStringWrapper::Implementation() const + { + static const char* implementation = "nsStdStringWrapper"; + return implementation; + } + + +template +const CharT* +basic_nsStdStringWrapper::GetReadableFragment( nsReadableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + aFragment.mEnd = (aFragment.mStart = mRawString.data()) + mRawString.length(); + return aFragment.mStart + aOffset; + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +template +CharT* +basic_nsStdStringWrapper::GetWritableFragment( nsWritableFragment& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) + { + switch ( aRequest ) + { + case kFirstFragment: + case kLastFragment: + case kFragmentAt: + aFragment.mEnd = (aFragment.mStart = NS_CONST_CAST(CharT*, mRawString.data())) + mRawString.length(); + return aFragment.mStart + aOffset; + + case kPrevFragment: + case kNextFragment: + default: + return 0; + } + } + +template +void +basic_nsStdStringWrapper::do_AssignFromReadable( const basic_nsAString& rhs ) + { + typedef basic_nsStdStringWrapper this_t; + + if ( SameImplementation(*this, rhs) ) + mRawString = NS_STATIC_CAST(this_t, rhs).mRawString; + else + basic_nsAString::do_AssignFromReadable(rhs); + } + + +typedef basic_nsStdStringWrapper nsStdString; +typedef basic_nsStdStringWrapper nsStdCString; + + +#endif // !defined(nsStdStringWrapper_h___) diff --git a/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp new file mode 100644 index 00000000..d7c14621 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/StringFactoringTests/profile_main.cpp @@ -0,0 +1,497 @@ +// profile_main.cpp + +#include "nscore.h" +#include +#include +#include + +#include "nsInt64.h" + +#ifdef XP_MAC +#include +#include "Profiler.h" +#else +#include "prtime.h" +#endif + +#ifndef TEST_STD_STRING +#include "nsString.h" +#else +#include "nsStdStringWrapper.h" +typedef nsStdCString nsCString; +#endif + +static const int kTestSucceeded = 0; +static const int kTestFailed = 1; + +static const size_t N = 100000; + + +template +inline +PRUint32 +TotalLength( const T& s ) + { + return s.Length(); + } + +NS_SPECIALIZE_TEMPLATE +inline +PRUint32 +TotalLength( const string& s ) + { + return s.length(); + } + +template +inline +PRUint32 +Find( const T& text, const T& pattern ) + { + return text.Find(pattern); + } + +NS_SPECIALIZE_TEMPLATE +inline +PRUint32 +Find( const string& text, const string& pattern ) + { + return text.find(pattern); + } + +inline +nsInt64 +GetTime() + { +#ifdef XP_MAC + UnsignedWide time; + Microseconds(&time); + return nsInt64( *reinterpret_cast(&time) ); +#else + return nsInt64( PR_Now() ); +#endif + } + +class TestTimer + { + public: + TestTimer() : mStartTime(GetTime()) { } + + ~TestTimer() + { + nsInt64 stopTime = GetTime(); + nsInt64 totalTime = stopTime - mStartTime; +#ifdef HAVE_LONG_LONG + cout << setw(10) << NS_STATIC_CAST(PRInt64, totalTime) << " µs : "; +#else + cout << setw(10) << NS_STATIC_CAST(PRInt32, totalTime) << "µs : "; +#endif + } + + private: + nsInt64 mStartTime; + }; + +inline +int +foo( const nsCString& ) + { + return 1; + } + +static +int +test_construction() + { + cout << endl; + + { + nsCString someCString; + int total = 0; + TestTimer timer; + for ( int i=0; i s2 ) + ++count; + } + cout << "s1 > s2" << endl; + + { + TestTimer timer; + for ( int i=0; i +#include "nsStringIO.h" + +//#define TEST_STD_STRING + + +#include "nsString.h" +#include "nsFragmentedString.h" +#include "nsReadableUtils.h" +#include "nsSlidingString.h" + +#ifdef TEST_STD_STRING +#include "nsStdStringWrapper.h" +#else + typedef nsString nsStdString; + typedef nsCString nsStdCString; +#endif + +template +basic_nsLiteralString +literal_hello( CharT* ) + { + } + +NS_SPECIALIZE_TEMPLATE +basic_nsLiteralString +literal_hello( char* ) + { + return basic_nsLiteralString("Hello"); + } + +NS_SPECIALIZE_TEMPLATE +basic_nsLiteralString +literal_hello( PRUnichar* ) + { +#ifdef HAVE_CPP_2BYTE_WCHAR_T + return basic_nsLiteralString(L"Hello"); +#else + static PRUnichar constant_unicode[] = { 'H', 'e', 'l', 'l', 'o', PRUnichar() }; + return basic_nsLiteralString(constant_unicode); +#endif + } + +template +struct string_class_traits + { + }; + +NS_SPECIALIZE_TEMPLATE +struct string_class_traits + { + typedef PRUnichar* pointer; + typedef nsString implementation_t; + + static basic_nsLiteralString literal_hello() { return ::literal_hello(pointer()); } + }; + +NS_SPECIALIZE_TEMPLATE +struct string_class_traits + { + typedef char* pointer; + typedef nsCString implementation_t; + + static basic_nsLiteralString literal_hello() { return ::literal_hello(pointer()); } + }; + + +static +void +CallCMid( nsACString& aResult, const nsACString& aSource, PRUint32 aStartPos, PRUint32 aLengthToCopy ) + { + aSource.Mid(aResult, aStartPos, aLengthToCopy); + } + + + +template +int +test_multifragment_iterators( const basic_nsAString& aString ) + /* + ...this tests a problem that was present in |nsPromiseConcatenation| where, + because it originally stored some iteration state in the object itself, rather than + in the fragment, the iterators could get confused if used out of sequence. + + This test should be run on any multi-fragment implementation to verify that it + does not have the same bug. Make sure the first fragment is only one character long. + */ + { + typedef typename basic_nsAString::const_iterator ConstIterator; + + int tests_failed = 0; + + ConstIterator iter1 = aString.BeginReading(); + ConstIterator iter2 = aString.BeginReading(); + ++iter2; ++iter2; + + ConstIterator iter3 = aString.EndReading(); + --iter3; + ++iter1; ++iter1; + if ( iter1 != iter2 ) + { + cout << "FAILED in |test_multifragment_iterators|" << endl; + ++tests_failed; + } + + return tests_failed; + } + +template +int +test_Vidur_functions( const basic_nsAString& aString ) + { + char* char_copy = ToNewCString(aString); + PRUnichar* PRUnichar_copy = ToNewUnicode(aString); + + nsMemory::Free(PRUnichar_copy); + nsMemory::Free(char_copy); + + return 0; + } + +template +int +test_readable_hello( const basic_nsAString& aReadable ) + { + int tests_failed = 0; + + if ( aReadable.Length() != 5 ) + { + cout << "FAILED |test_readable_hello|: |Length()| --> " << aReadable.Length() << endl; + ++tests_failed; + } + + if ( aReadable.First() != CharT('H') ) + { + cout << "FAILED |test_readable_hello|: |First()| --> '" << aReadable.First() << "'" << endl; + ++tests_failed; + } + + if ( aReadable.Last() != CharT('o') ) + { + cout << "FAILED |test_readable_hello|: |Last()| --> '" << aReadable.Last() << "'" << endl; + ++tests_failed; + } + + if ( aReadable[3] != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: |operator[]| --> '" << aReadable[3] << "'" << endl; + ++tests_failed; + } + + if ( aReadable.CountChar( CharT('l') ) != 2 ) + { + cout << "FAILED |test_readable_hello|: |CountChar('l')| --> " << aReadable.CountChar(CharT('l')) << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter = aReadable.BeginReading(); + if ( *iter != CharT('H') ) + { + cout << "FAILED |test_readable_hello|: didn't start out pointing to the right thing, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + ++iter; + + if ( *iter != CharT('e') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be incremented, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + iter = aReadable.EndReading(); + --iter; + if ( *iter != CharT('o') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |EndReading()|, or else couldn't be decremented, or else couldn't be dereferenced. --> '" << *iter << "'" << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter1 = aReadable.BeginReading().advance(3); + if ( *iter1 != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |BeginReading()+=n|, or else couldn't be dereferenced. --> '" << *iter1 << "'" << endl; + ++tests_failed; + } + + basic_nsAString::const_iterator iter2 = aReadable.EndReading().advance(-2); + if ( *iter2 != CharT('l') ) + { + cout << "FAILED |test_readable_hello|: iterator couldn't be set to |EndReading()-=n|, or else couldn't be dereferenced. --> '" << *iter2 << "'" << endl; + ++tests_failed; + } + + if ( iter1 != iter2 ) + { + cout << "FAILED |test_readable_hello|: iterator comparison with !=." << endl; + ++tests_failed; + } + + if ( !(iter1 == iter2) ) + { + cout << "FAILED |test_readable_hello|: iterator comparison with ==." << endl; + ++tests_failed; + } + + typedef CharT* CharT_ptr; + if ( aReadable != literal_hello(CharT_ptr()) ) + { + cout << "FAILED |test_readable_hello|: comparison with \"Hello\"" << endl; + ++tests_failed; + } + + tests_failed += test_multifragment_iterators(aReadable); + // tests_failed += test_deprecated_GetBufferGetUnicode(aReadable); + + test_Vidur_functions(aReadable); + + return tests_failed; + } + + +template +int +test_SetLength( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + string_class_traits::implementation_t oldValue(aWritable); + + + size_t oldLength = aWritable.Length(); + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, saving the value didn't work." << endl; + ++tests_failed; + } + + size_t newLength = 2*(oldLength+1); + + aWritable.SetLength(newLength); + if ( aWritable.Length() != newLength ) + { + cout << "FAILED growing a string in |test_SetLength|, length is wrong." << endl; + ++tests_failed; + } + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, contents damaged after growing." << endl; + ++tests_failed; + } + + aWritable.SetLength(oldLength); + if ( aWritable.Length() != oldLength ) + { + cout << "FAILED shrinking a string in |test_SetLength|." << endl; + ++tests_failed; + } + + if ( oldValue != Substring(aWritable, 0, oldLength) ) + { + cout << "FAILED growing a string in |test_SetLength|, contents damaged after shrinking." << endl; + ++tests_failed; + } + + return tests_failed; + } + + +template +int +test_insert( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + string_class_traits::implementation_t oldValue(aWritable); + + if ( oldValue != aWritable ) + { + cout << "FAILED saving the old string value in |test_insert|." << endl; + ++tests_failed; + } + + string_class_traits::implementation_t insertable( string_class_traits::literal_hello() ); + + insertable.SetLength(1); + aWritable.Insert(insertable, 0); + + if ( aWritable != (insertable + oldValue) ) + { + cout << "FAILED in |test_insert|." << endl; + ++tests_failed; + } + + aWritable = oldValue; + + return tests_failed; + } + + +template +int +test_cut( basic_nsAString& aWritable ) + { + int tests_failed = 0; + + aWritable.Cut(0, aWritable.Length()+5); + + return tests_failed; + } + +template +int +test_self_assign( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable = aWritable; + if ( aWritable != oldValue ) + { + cout << "FAILED self assignment." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_append( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable += aWritable; + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self append." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_insert( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable.Insert(aWritable, 0); + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self insert." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + +template +int +test_self_replace( basic_nsAString& aWritable ) + { + int tests_failed = 0; + string_class_traits::implementation_t oldValue(aWritable); + + aWritable.Replace(0, 0, aWritable); + if ( aWritable != oldValue + oldValue ) + { + cout << "FAILED self insert." << endl; + ++tests_failed; + } + + aWritable = oldValue; + return tests_failed; + } + + + +template +int +test_writable( basic_nsAString& aWritable ) + { + int tests_failed = 0; + // ... + + + { + typedef CharT* CharT_ptr; + aWritable = literal_hello(CharT_ptr()); + + if ( aWritable != literal_hello(CharT_ptr()) ) + { + cout << "FAILED assignment and/or comparison in |test_writable|." << endl; + ++tests_failed; + } + + tests_failed += test_readable_hello(aWritable); + } + + tests_failed += test_SetLength(aWritable); + tests_failed += test_insert(aWritable); + tests_failed += test_cut(aWritable); + tests_failed += test_self_assign(aWritable); + tests_failed += test_self_append(aWritable); + tests_failed += test_self_insert(aWritable); + tests_failed += test_self_replace(aWritable); + + return tests_failed; + } + + + +typedef void* void_ptr; + +int +main() + { + int tests_failed = 0; + cout << "String unit tests. Compiled " __DATE__ " " __TIME__ << endl; + +#if 0 + { + nsFragmentedCString fs0; + fs0.Append("Hello"); + tests_failed += test_readable_hello(fs0); + tests_failed += test_writable(fs0); + } +#endif + + { + NS_NAMED_LITERAL_STRING(literal, "Hello"); + PRUnichar* buffer = ToNewUnicode(literal); + + nsSlidingString ss0(buffer, buffer+5, buffer+6); +// ss0.AppendBuffer(buffer, buffer+5, buffer+6); + nsReadingIterator ri0; + ss0.BeginReading(ri0); + + tests_failed += test_readable_hello(ss0); + + nsSlidingSubstring ss1(ss0); + tests_failed += test_readable_hello(ss1); + + buffer = ToNewUnicode(literal); + ss0.AppendBuffer(buffer, buffer+5, buffer+6); + + ri0.advance(5); + ss0.DiscardPrefix(ri0); + + tests_failed += test_readable_hello(ss0); + tests_failed += test_readable_hello(ss1); + + nsReadingIterator ri1; + ss0.EndReading(ri1); + + nsSlidingSubstring ss2(ss0, ri0, ri1); + tests_failed += test_readable_hello(ss2); + } + + + { + nsLiteralCString s0("Patrick Beard made me write this: \"This is just a test\"\n"); + print_string(s0); + + const char* raw_string = "He also made me write this.\n"; + nsFileCharSink output(stdout); + copy_string(raw_string, raw_string+nsCharTraits::length(raw_string), output); + + nsLiteralCString s1("This ", 5), s2("is ", 3), s3("a ", 2), s4("test\n", 5); + print_string(s1+s2+s3+s4); + + nsLiteralCString s5( "This is " "a " "test" ); + print_string(s5+NS_LITERAL_CSTRING("\n")); + + print_string(nsLiteralCString("The value of the string |x| is \"") + Substring(s0, 0, s0.Length()-1) + NS_LITERAL_CSTRING("\". Hope you liked it.")); + } + + + { + tests_failed += test_readable_hello(NS_LITERAL_STRING("Hello")); + + nsLiteralCString s1("Hello"); + tests_failed += test_readable_hello(s1); + } + + { + + nsString s3( NS_LITERAL_STRING("Hello") ); + + tests_failed += test_readable_hello(s3); + tests_failed += test_writable(s3); + + nsCString s4("Hello"); + tests_failed += test_readable_hello(s4); + tests_failed += test_writable(s4); + } + + { + nsStdString s5( NS_LITERAL_STRING("Hello") ); + + tests_failed += test_readable_hello(s5); + tests_failed += test_writable(s5); + + nsStdCString s6("Hello"); + tests_failed += test_readable_hello(s6); + tests_failed += test_writable(s6); + } + + { + nsLiteralString s7(NS_LITERAL_STRING("He")); + nsString s8(NS_LITERAL_STRING("l")); + nsStdString s9(NS_LITERAL_STRING("lo")); + + tests_failed += test_readable_hello(s7+s8+s9); + + nsString s13( s7 + s8 + s9 ); + tests_failed += test_readable_hello(s13); + + nsStdString s14( s7 + s8 + s9 ); + tests_failed += test_readable_hello(s14); + + nsCString s10("He"); + nsLiteralCString s11("l"); + nsStdCString s12("lo"); + + tests_failed += test_readable_hello(s10+s11+s12); + + + } + + { + const char *foo = "this is a really long string"; + nsCString origString; + nsCString string2; + nsCString string3; + + origString = foo; + + string2 = Substring(origString, 0, 5); + string3 = Substring(origString, 6, origString.Length() - 6); + } + + { + nsLiteralCString s13("He"); + nsCAutoString s14("l"); + nsLiteralCString s15("lo"); + + s14.Assign(s13 + s14 + s15); + + if ( int failures = test_readable_hello(s14) ) + { + tests_failed += failures; + cout << "FAILED to keep a promise." << endl; + } + } + + + { + nsLiteralCString str1("Hello"); + nsStdCString str2("Hello"); + + nsLiteralCString str3("Hello there"); + + if ( str1 != str2 ) + { + cout << "string comparison using != failed" << endl; + ++tests_failed; + } + + if ( !(str3 > str2) ) + { + cout << "string comparison using > failed" << endl; + ++tests_failed; + } + + if ( !(str2 < str3) ) + { + cout << "string comparison using < failed" << endl; + ++tests_failed; + } + + if ( str1 != "Hello" ) + { + cout << "string comparison using == failed" << endl; + ++tests_failed; + } + } + +#if 0 + nsStdCString extracted_middle("XXXXXXXXXX"); + CallCMid(extracted_middle, part1+part2a+part2b, 1, 3); + + cout << "The result of mid was \"" << extracted_middle << "\"" << endl; + + nsLiteralCString middle_answer("ell"); + if ( middle_answer != extracted_middle ) + { + cout << "mid FAILED on nsConcatString" << endl; + ++tests_failed; + } + + + + // + // |nsStdStringWrapper|, i.e., |nsStdCString| + // + + { + nsStdCString extracted_middle; + CallCMid(extracted_middle, part1+part2a+part2b, 1, 3); + + cout << "The result of mid was \"" << extracted_middle << "\"" << endl; + + nsLiteralCString middle_answer("ell"); + if ( middle_answer != extracted_middle ) + { + cout << "mid FAILED on nsStdCString" << endl; + ++tests_failed; + } + } + + + + nsStdCString leftString; + source.Left(leftString, 9); + // cout << static_cast(leftString) << endl; + + + + tests_failed += test_multifragment_iterators(part1+part2a+part2b); +#endif + + + + cout << "End of string unit tests." << endl; + if ( !tests_failed ) + cout << "OK, all tests passed." << endl; + else + cout << "FAILED one or more tests." << endl; + + return tests_failed; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp b/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp new file mode 100644 index 00000000..852938fe --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestArray.cpp @@ -0,0 +1,230 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsISupportsArray.h" + +// {9e70a320-be02-11d1-8031-006008159b5a} +#define NS_IFOO_IID \ + {0x9e70a320, 0xbe02, 0x11d1, \ + {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}} + +static const PRBool kExitOnError = PR_TRUE; + +class IFoo : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + NS_IMETHOD_(nsrefcnt) RefCnt() = 0; + NS_IMETHOD_(PRInt32) ID() = 0; +}; + +class Foo : public IFoo { +public: + + Foo(PRInt32 aID); + + // nsISupports implementation + NS_DECL_ISUPPORTS + + // IFoo implementation + NS_IMETHOD_(nsrefcnt) RefCnt() { return mRefCnt; } + NS_IMETHOD_(PRInt32) ID() { return mID; } + + static PRInt32 gCount; + + PRInt32 mID; + +private: + ~Foo(); +}; + +PRInt32 Foo::gCount; + +Foo::Foo(PRInt32 aID) +{ + mID = aID; + ++gCount; + fprintf(stdout, "init: %d (%p), %d total)\n", mID, this, gCount); +} + +Foo::~Foo() +{ + --gCount; + fprintf(stdout, "destruct: %d (%p), %d remain)\n", mID, this, gCount); +} + +NS_IMPL_ISUPPORTS1(Foo, IFoo) + +const char* AssertEqual(PRInt32 aValue1, PRInt32 aValue2) +{ + if (aValue1 == aValue2) { + return "OK"; + } + if (kExitOnError) { + exit(1); + } + return "ERROR"; +} + +void DumpArray(nsISupportsArray* aArray, PRInt32 aExpectedCount, PRInt32 aElementIDs[], PRInt32 aExpectedTotal) +{ + PRUint32 cnt = 0; + nsresult rv = aArray->Count(&cnt); + NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed"); + PRInt32 count = cnt; + PRInt32 index; + + fprintf(stdout, "object count %d = %d %s\n", Foo::gCount, aExpectedTotal, + AssertEqual(Foo::gCount, aExpectedTotal)); + fprintf(stdout, "array count %d = %d %s\n", count, aExpectedCount, + AssertEqual(count, aExpectedCount)); + + for (index = 0; (index < count) && (index < aExpectedCount); index++) { + IFoo* foo = (IFoo*)(aArray->ElementAt(index)); + fprintf(stdout, "%2d: %d=%d (%p) c: %d %s\n", + index, aElementIDs[index], foo->ID(), foo, foo->RefCnt() - 1, + AssertEqual(foo->ID(), aElementIDs[index])); + foo->Release(); + } +} + +void FillArray(nsISupportsArray* aArray, PRInt32 aCount) +{ + PRInt32 index; + for (index = 0; index < aCount; index++) { + nsCOMPtr foo = new Foo(index); + aArray->AppendElement(foo); + } +} + +int main(int argc, char *argv[]) +{ + nsISupportsArray* array; + nsresult rv; + + if (NS_OK == (rv = NS_NewISupportsArray(&array))) { + FillArray(array, 10); + fprintf(stdout, "Array created:\n"); + PRInt32 fillResult[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + DumpArray(array, 10, fillResult, 10); + + // test insert + IFoo* foo = (IFoo*)array->ElementAt(3); + foo->Release(); // pre-release to fix ref count for dumps + array->InsertElementAt(foo, 5); + fprintf(stdout, "insert 3 at 5:\n"); + PRInt32 insertResult[11] = {0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9}; + DumpArray(array, 11, insertResult, 10); + fprintf(stdout, "insert 3 at 0:\n"); + array->InsertElementAt(foo, 0); + PRInt32 insertResult2[12] = {3, 0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9}; + DumpArray(array, 12, insertResult2, 10); + fprintf(stdout, "append 3:\n"); + array->AppendElement(foo); + PRInt32 appendResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 6, 7, 8, 9, 3}; + DumpArray(array, 13, appendResult, 10); + + + // test IndexOf && LastIndexOf + PRInt32 expectedIndex[5] = {0, 4, 6, 12, -1}; + PRInt32 count = 0; + PRInt32 index = array->IndexOf(foo); + fprintf(stdout, "IndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + while (-1 != index) { + count++; + index = array->IndexOfStartingAt(foo, index + 1); + if (-1 != index) + fprintf(stdout, "IndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + } + index = array->LastIndexOf(foo); + count--; + fprintf(stdout, "LastIndexOf(foo): %d=%d %s\n", index, expectedIndex[count], + AssertEqual(index, expectedIndex[count])); + + // test ReplaceElementAt + fprintf(stdout, "ReplaceElementAt(8):\n"); + array->ReplaceElementAt(foo, 8); + PRInt32 replaceResult[13] = {3, 0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3}; + DumpArray(array, 13, replaceResult, 9); + + // test RemoveElementAt, RemoveElement RemoveLastElement + fprintf(stdout, "RemoveElementAt(0):\n"); + array->RemoveElementAt(0); + PRInt32 removeResult[12] = {0, 1, 2, 3, 4, 3, 5, 3, 7, 8, 9, 3}; + DumpArray(array, 12, removeResult, 9); + fprintf(stdout, "RemoveElementAt(7):\n"); + array->RemoveElementAt(7); + PRInt32 removeResult2[11] = {0, 1, 2, 3, 4, 3, 5, 7, 8, 9, 3}; + DumpArray(array, 11, removeResult2, 9); + fprintf(stdout, "RemoveElement(foo):\n"); + array->RemoveElement(foo); + PRInt32 removeResult3[10] = {0, 1, 2, 4, 3, 5, 7, 8, 9, 3}; + DumpArray(array, 10, removeResult3, 9); + fprintf(stdout, "RemoveLastElement(foo):\n"); + array->RemoveLastElement(foo); + PRInt32 removeResult4[9] = {0, 1, 2, 4, 3, 5, 7, 8, 9}; + DumpArray(array, 9, removeResult4, 9); + + // test clear + fprintf(stdout, "clear array:\n"); + array->Clear(); + DumpArray(array, 0, 0, 0); + fprintf(stdout, "add 4 new:\n"); + FillArray(array, 4); + DumpArray(array, 4, fillResult, 4); + + // test compact + fprintf(stdout, "compact array:\n"); + array->Compact(); + DumpArray(array, 4, fillResult, 4); + + // test delete + fprintf(stdout, "release array:\n"); + NS_RELEASE(array); + } + else { + fprintf(stdout, "error can't create array: %x\n", rv); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp new file mode 100644 index 00000000..48b2f603 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAtoms.cpp @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIAtom.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "prprf.h" +#include "prtime.h" +#include + +extern "C" int _CrtSetDbgFlag(int); + +int main(int argc, char** argv) +{ + FILE* fp = fopen("words.txt", "r"); + if (nsnull == fp) { + printf("can't open words.txt\n"); + return -1; + } + + PRInt32 count = 0; + PRUnichar** strings = new PRUnichar*[60000]; + nsIAtom** ids = new nsIAtom*[60000]; + nsAutoString s1, s2; + PRTime start = PR_Now(); + PRInt32 i; + for (i = 0; i < 30000; i++) { + char buf[1000]; + char* s = fgets(buf, sizeof(buf), fp); + if (nsnull == s) { + break; + } + nsCAutoString sb; + sb.Assign(buf); + strings[count++] = ToNewUnicode(sb); + ToUpperCase(sb); + strings[count++] = ToNewUnicode(sb); + } + PRTime end0 = PR_Now(); + + // Find and create idents + for (i = 0; i < count; i++) { + ids[i] = NS_NewAtom(strings[i]); + } + PRUnichar qqs[1]; qqs[0] = 0; + nsIAtom* qq = NS_NewAtom(qqs); + PRTime end1 = PR_Now(); + + // Now make sure we can find all the idents we just made + for (i = 0; i < count; i++) { + const char *utf8String; + ids[i]->GetUTF8String(&utf8String); + nsIAtom* id = NS_NewAtom(utf8String); + if (id != ids[i]) { + id->ToString(s1); + ids[i]->ToString(s2); + printf("find failed: id='%s' ids[%d]='%s'\n", + NS_LossyConvertUCS2toASCII(s1).get(), i, NS_LossyConvertUCS2toASCII(s2).get()); + return -1; + } + NS_RELEASE(id); + } + PRTime end2 = PR_Now(); + + // Destroy all the atoms we just made + NS_RELEASE(qq); + for (i = 0; i < count; i++) { + NS_RELEASE(ids[i]); + } + + // Print out timings + PRTime end3 = PR_Now(); + PRTime creates, finds, lookups, dtor, ustoms; + LL_I2L(ustoms, 1000); + LL_SUB(creates, end0, start); + LL_DIV(creates, creates, ustoms); + LL_SUB(finds, end1, end0); + LL_DIV(finds, finds, ustoms); + LL_SUB(lookups, end2, end1); + LL_DIV(lookups, lookups, ustoms); + LL_SUB(dtor, end3, end2); + char buf[500]; + PR_snprintf(buf, sizeof(buf), "making %d ident strings took %lldms", + count, creates); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d new idents took %lldms", + count, finds); + puts(buf); + PR_snprintf(buf, sizeof(buf), "%d ident lookups took %lldms", + count, lookups); + puts(buf); + PR_snprintf(buf, sizeof(buf), "dtor took %lldusec", dtor); + puts(buf); + + printf("%d live atoms\n", NS_GetNumberOfAtoms()); + NS_POSTCONDITION(0 == NS_GetNumberOfAtoms(), "dangling atoms"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp new file mode 100644 index 00000000..4537044f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAutoLock.cpp @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + + Some tests for nsAutoLock. + + */ + +#include "nsAutoLock.h" +#include "prthread.h" + +PRLock* gLock; +int gCount; + +static void PR_CALLBACK run(void* arg) +{ + for (int i = 0; i < 1000000; ++i) { + nsAutoLock guard(gLock); + ++gCount; + PR_ASSERT(gCount == 1); + --gCount; + } +} + + +int main(int argc, char** argv) +{ + gLock = PR_NewLock(); + gCount = 0; + + // This shouldn't compile + //nsAutoLock* l1 = new nsAutoLock(theLock); + //delete l1; + + // Create a block-scoped lock. This should compile. + { + nsAutoLock l2(gLock); + } + + // Fork a thread to access the shared variable in a tight loop + PRThread* t1 = + PR_CreateThread(PR_SYSTEM_THREAD, + run, + nsnull, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + + // ...and now do the same thing ourselves + run(nsnull); + + // Wait for the background thread to finish, if necessary. + PR_JoinThread(t1); + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp new file mode 100644 index 00000000..c48134a4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestAutoPtr.cpp @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ts=4:et:sw=4: +/* ***** 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 TestCOMPtrEq.cpp. + * + * The Initial Developer of the Original Code is + * L. David Baron. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAutoPtr.h" +#include +#include "nscore.h" + +class TestObjectBaseA { + public: + // Virtual dtor for deleting through base class pointer + virtual ~TestObjectBaseA() { }; + int fooA; +}; + +class TestObjectBaseB { + public: + // Virtual dtor for deleting through base class pointer + virtual ~TestObjectBaseB() { }; + int fooB; +}; + +class TestObject : public TestObjectBaseA, public TestObjectBaseB { + public: + TestObject() + { + printf(" Creating TestObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + // Virtual dtor for deleting through base class pointer + virtual ~TestObject() + { + printf(" Destroying TestObject %p.\n", + NS_STATIC_CAST(void*, this)); + } +}; + +class TestRefObjectBaseA { + public: + int fooA; + // Must return |nsrefcnt| to keep |nsDerivedSafe| happy. + virtual nsrefcnt AddRef() = 0; + virtual nsrefcnt Release() = 0; +}; + +class TestRefObjectBaseB { + public: + int fooB; + virtual nsrefcnt AddRef() = 0; + virtual nsrefcnt Release() = 0; +}; + +class TestRefObject : public TestRefObjectBaseA, public TestRefObjectBaseB { + public: + TestRefObject() + : mRefCount(0) + { + printf(" Creating TestRefObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + ~TestRefObject() + { + printf(" Destroying TestRefObject %p.\n", + NS_STATIC_CAST(void*, this)); + } + + nsrefcnt AddRef() + { + ++mRefCount; + printf(" AddRef to %d on TestRefObject %p.\n", + mRefCount, NS_STATIC_CAST(void*, this)); + return mRefCount; + } + + nsrefcnt Release() + { + --mRefCount; + printf(" Release to %d on TestRefObject %p.\n", + mRefCount, NS_STATIC_CAST(void*, this)); + if (mRefCount == 0) { + delete NS_CONST_CAST(TestRefObject*, this); + return 0; + } + return mRefCount; + } + + protected: + PRUint32 mRefCount; + +}; + +static void CreateTestObject(TestObject **aResult) +{ + *aResult = new TestObject(); +} + +static void CreateTestRefObject(TestRefObject **aResult) +{ + (*aResult = new TestRefObject())->AddRef(); +} + +static void DoSomethingWithTestObject(TestObject *aIn) +{ + printf(" Doing something with |TestObject| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestObject(const TestObject *aIn) +{ + printf(" Doing something with |const TestObject| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestRefObject(TestRefObject *aIn) +{ + printf(" Doing something with |TestRefObject| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestRefObject(const TestRefObject *aIn) +{ + printf(" Doing something with |const TestRefObject| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestObjectBaseB(TestObjectBaseB *aIn) +{ + printf(" Doing something with |TestObjectBaseB| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestObjectBaseB(const TestObjectBaseB *aIn) +{ + printf(" Doing something with |const TestObjectBaseB| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +static void DoSomethingWithTestRefObjectBaseB(TestRefObjectBaseB *aIn) +{ + printf(" Doing something with |TestRefObjectBaseB| %p.\n", + NS_STATIC_CAST(void*, aIn)); +} + +static void DoSomethingWithConstTestRefObjectBaseB(const TestRefObjectBaseB *aIn) +{ + printf(" Doing something with |const TestRefObjectBaseB| %p.\n", + NS_STATIC_CAST(const void*, aIn)); +} + +int main() +{ + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should create one |TestObject| and then destroy one:\n"); + pobj = new TestObject(); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj( new TestObject[3] ); + printf("Should create 5 |TestObject|s and then destroy 3:\n"); + pobj = new TestObject[5]; + printf("Should destroy 5 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj( new TestRefObject() ); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj( new TestRefObject() ); + printf("Should create and AddRef one |TestRefObject| and then Release and destroy one:\n"); + pobj = new TestRefObject(); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr p1( new TestRefObject() ); + printf("Should AddRef one |TestRefObject|:\n"); + nsRefPtr p2( p1 ); + printf("Should Release twice and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting equality (with all const-ness combinations):\n"); + + { + nsRefPtr p1( new TestRefObject() ); + nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + const nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const nsRefPtr p2( p1 ); + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + +#if 0 /* MSVC++ 6.0 can't be coaxed to accept this */ + { + nsRefPtr p1( new TestRefObject() ); + TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } +#endif /* Things that MSVC++ 6.0 can't be coaxed to accept */ + + { + nsRefPtr p1( new TestRefObject() ); + const TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const TestRefObject * p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + nsRefPtr p1( new TestRefObject() ); + const TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + { + const nsRefPtr p1( new TestRefObject() ); + const TestRefObject * const p2 = p1; + printf("equality %s.\n", + ((p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) ? "OK" : "broken"); + } + + printf("\nTesting getter_Transfers and getter_AddRefs.\n"); + + { + nsAutoPtr ptr; + printf("Should create one |TestObject|:\n"); + CreateTestObject(getter_Transfers(ptr)); + printf("Should destroy one |TestObject|:\n"); + } + + { + nsRefPtr ptr; + printf("Should create and AddRef one |TestRefObject|:\n"); + CreateTestRefObject(getter_AddRefs(ptr)); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting casts and equality tests.\n"); + + if ((void*)(TestObject*)0x1000 == + (void*)(TestObjectBaseB*)(TestObject*)0x1000) + printf("\n\nAll these tests are meaningless!\n\n\n"); + + { + nsAutoPtr p1(new TestObject()); + TestObjectBaseB *p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + TestObject *p1 = new TestObject(); + nsAutoPtr p2(p1); + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + nsRefPtr p1 = new TestRefObject(); + // nsCOMPtr requires a |get| for something like this as well + nsRefPtr p2 = p1.get(); + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + nsRefPtr p1 = new TestRefObject(); + TestRefObjectBaseB *p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + { + TestRefObject *p1 = new TestRefObject(); + nsRefPtr p2 = p1; + printf("equality %s.\n", + ((NS_STATIC_CAST(void*, p1) != NS_STATIC_CAST(void*, p2)) && + (p1 == p2) && !(p1 != p2) && (p2 == p1) && !(p2 != p1)) + ? "OK" : "broken"); + } + + printf("\nTesting |forget()|.\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj( new TestObject() ); + printf("Should do nothing:\n"); + nsAutoPtr pobj2( pobj.forget() ); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj( new TestObject[3] ); + printf("Should do nothing:\n"); + nsAutoArrayPtr pobj2( pobj.forget() ); + printf("Should destroy 3 |TestObject|s:\n"); + } + + printf("\nTesting construction.\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + printf("\nTesting calling of functions (including array access and casts).\n"); + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObject(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObject(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObjectBaseB(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObjectBaseB(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + const nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + const nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObject(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObject(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + const nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObject(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObject(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + { + printf("Should create one |TestObject|:\n"); + const nsAutoPtr pobj(new TestObject()); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj); + printf("Should destroy one |TestObject|:\n"); + } + + { + printf("Should create 3 |TestObject|s:\n"); + const nsAutoArrayPtr pobj(new TestObject[3]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(&pobj[2]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(&pobj[1]); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithTestObjectBaseB(pobj + 2); + printf("Should do something with one |TestObject|:\n"); + DoSomethingWithConstTestObjectBaseB(pobj + 1); + printf("Should destroy 3 |TestObject|s:\n"); + } + + { + printf("Should create and AddRef one |TestRefObject|:\n"); + const nsRefPtr pobj = new TestRefObject(); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithTestRefObjectBaseB(pobj); + printf("Should do something with one |TestRefObject|:\n"); + DoSomethingWithConstTestRefObjectBaseB(pobj); + printf("Should Release and destroy one |TestRefObject|:\n"); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp new file mode 100644 index 00000000..c48219e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCOMPtr.cpp @@ -0,0 +1,651 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsCOMPtr.h" +#include "nsISupports.h" + +#ifdef HAVE_CPP_NEW_CASTS + #define STATIC_CAST(T,x) static_cast(x) + #define REINTERPRET_CAST(T,x) reinterpret_cast(x) +#else + #define STATIC_CAST(T,x) ((T)(x)) + #define REINTERPRET_CAST(T,x) ((T)(x)) +#endif + + +#define NS_IFOO_IID \ +{ 0x6f7652e0, 0xee43, 0x11d1, \ + { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class IFoo : public nsISupports + { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + public: + IFoo(); + // virtual dtor because IBar uses our Release() + virtual ~IFoo(); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + static void print_totals(); + + private: + unsigned int refcount_; + + static unsigned int total_constructions_; + static unsigned int total_destructions_; + }; + +class IBar; + + // some types I'll need +typedef unsigned long NS_RESULT; + + // some functions I'll need (and define below) + nsresult CreateIFoo( void** ); + nsresult CreateIBar( void** result ); + void AnIFooPtrPtrContext( IFoo** ); + void AnISupportsPtrPtrContext( nsISupports** ); + void AVoidPtrPtrContext( void** ); + void set_a_IFoo( nsCOMPtr* result ); +nsCOMPtr return_a_IFoo(); + + + + +unsigned int IFoo::total_constructions_; +unsigned int IFoo::total_destructions_; + +class test_message + { + public: + test_message() + { + printf("BEGIN unit tests for |nsCOMPtr|, compiled " __DATE__ "\n"); + } + + ~test_message() + { + IFoo::print_totals(); + printf("END unit tests for |nsCOMPtr|.\n"); + } + }; + +test_message gTestMessage; + + + /* + ... + */ + +void +IFoo::print_totals() + { + printf("total constructions/destructions --> %d/%d\n", + total_constructions_, total_destructions_); + } + +IFoo::IFoo() + : refcount_(0) + { + ++total_constructions_; + printf(" new IFoo@%p [#%d]\n", + STATIC_CAST(void*, this), total_constructions_); + } + +IFoo::~IFoo() + { + ++total_destructions_; + printf("IFoo@%p::~IFoo() [#%d]\n", + STATIC_CAST(void*, this), total_destructions_); + } + +nsrefcnt +IFoo::AddRef() + { + ++refcount_; + printf("IFoo@%p::AddRef(), refcount --> %d\n", + STATIC_CAST(void*, this), refcount_); + return refcount_; + } + +nsrefcnt +IFoo::Release() + { + int wrap_message = (refcount_ == 1); + if ( wrap_message ) + printf(">>"); + + nsrefcnt const newcount = --refcount_; + printf("IFoo@%p::Release(), refcount --> %d\n", + STATIC_CAST(void*, this), newcount); + + if ( !newcount ) + { + printf(" delete IFoo@%p\n", STATIC_CAST(void*, this)); + delete this; + } + + if ( wrap_message ) + printf("<>CreateIFoo() --> "); + IFoo* foop = new IFoo; + printf("IFoo@%p\n", STATIC_CAST(void*, foop)); + + foop->AddRef(); + *result = foop; + + printf("<* result ) + { + printf(">>set_a_IFoo()\n"); + assert(result); + + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + *result = foop; + printf("< +return_a_IFoo() + { + printf(">>return_a_IFoo()\n"); + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + printf("<>CreateIBar() --> "); + IBar* barp = new IBar; + printf("IBar@%p\n", STATIC_CAST(void*, barp)); + + barp->AddRef(); + *result = barp; + + printf("<QueryInterface(NS_GET_IID(IFoo), REINTERPRET_CAST(void**, &fooP)) ) ) + { + try + { + fooP->print_totals(); + } + catch( ... ) + { + NS_RELEASE(fooP); + throw; + } + + NS_RELEASE(fooP); + } + } + catch( ... ) + { + NS_RELEASE(barP); + throw; + } + + NS_RELEASE(barP); + } + + return result; + } +#endif // TEST_EXCEPTIONS + +static +nsresult +TestBloat_Raw_Unsafe() + { + IBar* barP = 0; + nsresult result = CreateIBar(REINTERPRET_CAST(void**, &barP)); + + if ( barP ) + { + IFoo* fooP = 0; + if ( NS_SUCCEEDED( result = barP->QueryInterface(NS_GET_IID(IFoo), REINTERPRET_CAST(void**, &fooP)) ) ) + { + fooP->print_totals(); + NS_RELEASE(fooP); + } + + NS_RELEASE(barP); + } + + return result; + } + + +static +nsresult +TestBloat_Smart() + { + nsCOMPtr barP; + nsresult result = CreateIBar( getter_AddRefs(barP) ); + + nsCOMPtr fooP( do_QueryInterface(barP, &result) ); + + if ( fooP ) + fooP->print_totals(); + + return result; + } + + + + +nsCOMPtr gFoop; + +int +main() + { + printf(">>main()\n"); + + printf("sizeof(nsCOMPtr) --> %zd\n", sizeof(nsCOMPtr)); + +#ifdef TEST_EXCEPTIONS + TestBloat_Raw(); +#endif // TEST_EXCEPTIONS + TestBloat_Raw_Unsafe(); + TestBloat_Smart(); + + + { + printf("\n### Test 1: will a |nsCOMPtr| call |AddRef| on a pointer assigned into it?\n"); + nsCOMPtr foop( do_QueryInterface(new IFoo) ); + + printf("\n### Test 2: will a |nsCOMPtr| |Release| its old pointer when a new one is assigned in?\n"); + foop = do_QueryInterface(new IFoo); + + // [Shouldn't compile] Is it a compile time error to try to |AddRef| by hand? + //foop->AddRef(); + + // [Shouldn't compile] Is it a compile time error to try to |Release| be hand? + //foop->Release(); + + // [Shouldn't compile] Is it a compile time error to try to |delete| an |nsCOMPtr|? + //delete foop; + + printf("\n### Test 3: can you |AddRef| if you must?\n"); + STATIC_CAST(IFoo*, foop)->AddRef(); + + printf("\n### Test 4: can you |Release| if you must?\n"); + STATIC_CAST(IFoo*, foop)->Release(); + + printf("\n### Test 5: will a |nsCOMPtr| |Release| when it goes out of scope?\n"); + } + + { + printf("\n### Test 6: will a |nsCOMPtr| call the correct destructor?\n"); + nsCOMPtr foop( do_QueryInterface(new IBar) ); + } + + { + printf("\n### Test 7: can you compare one |nsCOMPtr| with another [!=]?\n"); + + nsCOMPtr foo1p( do_QueryInterface(new IFoo) ); + + // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? + //AnIFooPtrPtrContext(&foo1p); + + // [Shouldn't compile] Is it a compile time error to omit |getter_[doesnt_]AddRef[s]|? + //AVoidPtrPtrContext(&foo1p); + + nsCOMPtr foo2p( do_QueryInterface(new IFoo) ); + + if ( foo1p != foo2p ) + printf("foo1p != foo2p\n"); + else + printf("foo1p == foo2p\n"); + + printf("\n### Test 7.5: can you compare a |nsCOMPtr| with NULL, 0, nsnull [!=]?\n"); + if ( foo1p != 0 ) + printf("foo1p != 0\n"); + if ( 0 != foo1p ) + printf("0 != foo1p\n"); + if ( foo1p == 0 ) + printf("foo1p == 0\n"); + if ( 0 == foo1p ) + printf("0 == foo1p\n"); + + + IFoo* raw_foo2p = foo2p.get(); + + printf("\n### Test 8: can you compare a |nsCOMPtr| with a raw interface pointer [!=]?\n"); + if ( foo1p.get() != raw_foo2p ) + printf("foo1p != raw_foo2p\n"); + else + printf("foo1p == raw_foo2p\n"); + + + printf("\n### Test 9: can you assign one |nsCOMPtr| into another?\n"); + foo1p = foo2p; + + printf("\n### Test 10: can you compare one |nsCOMPtr| with another [==]?\n"); + if ( foo1p == foo2p ) + printf("foo1p == foo2p\n"); + else + printf("foo1p != foo2p\n"); + + printf("\n### Test 11: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); + if ( raw_foo2p == foo2p.get() ) + printf("raw_foo2p == foo2p\n"); + else + printf("raw_foo2p != foo2p\n"); + +#if 1 + printf("\n### Test 11.5: can you compare a |nsCOMPtr| with a raw interface pointer [==]?\n"); + if ( nsCOMPtr( raw_foo2p ) == foo2p ) + printf("raw_foo2p == foo2p\n"); + else + printf("raw_foo2p != foo2p\n"); +#endif + + printf("\n### Test 12: bare pointer test?\n"); + if ( foo1p ) + printf("foo1p is not NULL\n"); + else + printf("foo1p is NULL\n"); + + printf("\n### Test 13: numeric pointer test?\n"); + if ( foo1p == 0 ) + printf("foo1p is NULL\n"); + else + printf("foo1p is not NULL\n"); + +#if 0 + if ( foo1p == 1 ) + printf("foo1p allowed compare with in\n"); +#endif + + printf("\n### Test 14: how about when two |nsCOMPtr|s referring to the same object go out of scope?\n"); + } + + { + printf("\n### Test 15,16 ...setup...\n"); + IFoo* raw_foo1p = new IFoo; + raw_foo1p->AddRef(); + + IFoo* raw_foo2p = new IFoo; + raw_foo2p->AddRef(); + + printf("\n### Test 15: what if I don't want to |AddRef| when I construct?\n"); + nsCOMPtr foo1p( dont_AddRef(raw_foo1p) ); + //nsCOMPtr foo1p = dont_AddRef(raw_foo1p); + + printf("\n### Test 16: what if I don't want to |AddRef| when I assign in?\n"); + nsCOMPtr foo2p; + foo2p = dont_AddRef(raw_foo2p); + } + + + + + + + + { + printf("\n### setup for Test 17\n"); + nsCOMPtr foop; + printf("### Test 17: basic parameter behavior?\n"); + CreateIFoo( nsGetterAddRefs(foop) ); + } + printf("### End Test 17\n"); + + + { + printf("\n### setup for Test 18\n"); + nsCOMPtr foop; + printf("### Test 18: basic parameter behavior, using the short form?\n"); + CreateIFoo( getter_AddRefs(foop) ); + } + printf("### End Test 18\n"); + + + { + printf("\n### setup for Test 19, 20\n"); + nsCOMPtr foop; + printf("### Test 19: reference parameter behavior?\n"); + set_a_IFoo(address_of(foop)); + + printf("### Test 20: return value behavior?\n"); + foop = return_a_IFoo(); + } + printf("### End Test 19, 20\n"); + + { + printf("\n### setup for Test 21\n"); + nsCOMPtr fooP; + + printf("### Test 21: is |QueryInterface| called on assigning in a raw pointer?\n"); + fooP = do_QueryInterface(new IFoo); + } + printf("### End Test 21\n"); + + { + printf("\n### setup for Test 22\n"); + nsCOMPtr fooP; + fooP = do_QueryInterface(new IFoo); + + nsCOMPtr foo2P; + + printf("### Test 22: is |QueryInterface| _not_ called when assigning in a smart-pointer of the same type?\n"); + foo2P = fooP; + } + printf("### End Test 22\n"); + + { + printf("\n### setup for Test 23\n"); + nsCOMPtr barP( do_QueryInterface(new IBar) ); + + printf("### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?\n"); + + nsCOMPtr fooP( do_QueryInterface(barP) ); + if ( fooP ) + printf("an IBar* is an IFoo*\n"); + } + printf("### End Test 23\n"); + + + { + nsCOMPtr fooP; + + AnIFooPtrPtrContext( getter_AddRefs(fooP) ); + AVoidPtrPtrContext( getter_AddRefs(fooP) ); + AnISupportsPtrPtrContext( getter_AddRefs(fooP) ); + } + + + { + nsCOMPtr supportsP; + + AVoidPtrPtrContext( getter_AddRefs(supportsP) ); + AnISupportsPtrPtrContext( getter_AddRefs(supportsP) ); + } + + + printf("\n### Test 24: will a static |nsCOMPtr| |Release| before program termination?\n"); + gFoop = do_QueryInterface(new IFoo); + + printf("< (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 attempts to test all the possible variations of |operator==| + * used with |nsCOMPtr|s. Currently only the tests where pointers + * are to the same class are enabled. It's not clear whether we + * should be supporting other tests, and some of them won't work + * on at least some platforms. If we add separate comparisons + * for nsCOMPtr we'll need to add more tests for + * those cases. + */ + +#include "nsCOMPtr.h" + + // Don't test these now, since some of them won't work and it's + // not clear whether they should (see above). +#undef NSCAP_EQTEST_TEST_ACROSS_TYPES + +#define NS_ICOMPTREQTESTFOO_IID \ + {0x8eb5bbef, 0xd1a3, 0x4659, \ + {0x9c, 0xf6, 0xfd, 0xf3, 0xe4, 0xd2, 0x00, 0x0e}} + +class nsICOMPtrEqTestFoo : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMPTREQTESTFOO_IID) +}; + +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + +#define NS_ICOMPTREQTESTFOO2_IID \ + {0x6516387b, 0x36c5, 0x4036, \ + {0x82, 0xc9, 0xa7, 0x4d, 0xd9, 0xe5, 0x92, 0x2f}} + +class nsICOMPtrEqTestFoo2 : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMPTREQTESTFOO2_IID) +}; + +#endif + +int +main() + { + nsCOMPtr s; + nsICOMPtrEqTestFoo* r = 0; + const nsCOMPtr sc; + const nsICOMPtrEqTestFoo* rc = 0; + nsICOMPtrEqTestFoo* const rk = 0; + const nsICOMPtrEqTestFoo* const rkc = 0; + nsDerivedSafe* d = s.get(); + +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + nsCOMPtr s2; + nsICOMPtrEqTestFoo2* r2 = 0; + const nsCOMPtr sc2; + const nsICOMPtrEqTestFoo2* rc2 = 0; + nsICOMPtrEqTestFoo2* const rk2 = 0; + const nsICOMPtrEqTestFoo2* const rkc2 = 0; + nsDerivedSafe* d2 = s2.get(); +#endif + + return (!(PR_TRUE && + (s == s) && + (s == r) && + (s == sc) && + (s == rc) && + (s == rk) && + (s == rkc) && + (s == d) && + (r == s) && + (r == r) && + (r == sc) && + (r == rc) && + (r == rk) && + (r == rkc) && + (r == d) && + (sc == s) && + (sc == r) && + (sc == sc) && + (sc == rc) && + (sc == rk) && + (sc == rkc) && + (sc == d) && + (rc == s) && + (rc == r) && + (rc == sc) && + (rc == rc) && + (rc == rk) && + (rc == rkc) && + (rc == d) && + (rk == s) && + (rk == r) && + (rk == sc) && + (rk == rc) && + (rk == rk) && + (rk == rkc) && + (rk == d) && + (rkc == s) && + (rkc == r) && + (rkc == sc) && + (rkc == rc) && + (rkc == rk) && + (rkc == rkc) && + (rkc == d) && + (d == s) && + (d == r) && + (d == sc) && + (d == rc) && + (d == rk) && + (d == rkc) && + (d == d) && +#ifdef NSCAP_EQTEST_TEST_ACROSS_TYPES + (s == s2) && + (s == r2) && + (s == sc2) && + (s == rc2) && + (s == rk2) && + (s == rkc2) && + (s == d2) && + (r == s2) && + (r == r2) && + (r == sc2) && + (r == rc2) && + (r == rk2) && + (r == rkc2) && + (r == d2) && + (sc == s2) && + (sc == r2) && + (sc == sc2) && + (sc == rc2) && + (sc == rk2) && + (sc == rkc2) && + (sc == d2) && + (rc == s2) && + (rc == r2) && + (rc == sc2) && + (rc == rc2) && + (rc == rk2) && + (rc == rkc2) && + (rc == d2) && + (rk == s2) && + (rk == r2) && + (rk == sc2) && + (rk == rc2) && + (rk == rk2) && + (rk == rkc2) && + (rk == d2) && + (rkc == s2) && + (rkc == r2) && + (rkc == sc2) && + (rkc == rc2) && + (rkc == rk2) && + (rkc == rkc2) && + (rkc == d2) && + (d == s2) && + (d == r2) && + (d == sc2) && + (d == rc2) && + (d == rk2) && + (d == rkc2) && + (d == d2) && +#endif + PR_TRUE)); + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp new file mode 100644 index 00000000..11bdd512 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCRT.cpp @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCRT.h" +#include "nsString.h" +#include "plstr.h" +#include + +// The return from strcmp etc is only defined to be postive, zero or +// negative. The magnitude of a non-zero return is irrelevant. +PRIntn sign(PRIntn val) { + if (val == 0) + return 0; + else { + if (val > 0) + return 1; + else + return -1; + } +} + + +// Verify that nsCRT versions of string comparison routines get the +// same answers as the native non-unicode versions. We only pass in +// iso-latin-1 strings, so the comparison must be valid. +static void Check(const char* s1, const char* s2, PRIntn n) +{ + PRIntn clib = PL_strcmp(s1, s2); + PRIntn clib_n = PL_strncmp(s1, s2, n); + PRIntn clib_case = PL_strcasecmp(s1, s2); + PRIntn clib_case_n = PL_strncasecmp(s1, s2, n); + + nsAutoString t1,t2; + t1.AssignWithConversion(s1); + t2.AssignWithConversion(s2); + const PRUnichar* us1 = t1.get(); + const PRUnichar* us2 = t2.get(); + + PRIntn u2 = nsCRT::strcmp(us1, us2); + PRIntn u2_n = nsCRT::strncmp(us1, us2, n); + + NS_ASSERTION(sign(clib) == sign(u2), "strcmp"); + NS_ASSERTION(sign(clib_n) == sign(u2_n), "strncmp"); +} + +struct Test { + const char* s1; + const char* s2; + PRIntn n; +}; + +static Test tests[] = { + { "foo", "foo", 3 }, + { "foo", "fo", 3 }, + + { "foo", "bar", 3 }, + { "foo", "ba", 3 }, + + { "foo", "zap", 3 }, + { "foo", "za", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, + + { "bar", "foo", 3 }, + { "bar", "fo", 3 }, +}; +#define NUM_TESTS int((sizeof(tests) / sizeof(tests[0]))) + +int main() +{ + Test* tp = tests; + for (int i = 0; i < NUM_TESTS; i++, tp++) { + Check(tp->s1, tp->s2, tp->n); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp b/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp new file mode 100644 index 00000000..3ec9c29a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestCallTemplates.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim:cindent:ts=8:et:sw=4: + * + * ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 test is NOT intended to be run. It's a test to make sure + * a group of functions BUILD correctly. + */ + +#include "nsISupportsUtils.h" +#include "nsIWeakReference.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsWeakReference.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" + +#define NS_ITESTSERVICE_IID \ + {0x127b5253, 0x37b1, 0x43c7, \ + { 0x96, 0x2b, 0xab, 0xf1, 0x2d, 0x22, 0x56, 0xae }} + +class NS_NO_VTABLE nsITestService : public nsISupports { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITESTSERVICE_IID) +}; + +class nsTestService : public nsITestService, public nsSupportsWeakReference +{ + public: + NS_DECL_ISUPPORTS +}; + +NS_IMPL_ISUPPORTS2(nsTestService, nsITestService, nsISupportsWeakReference) + +#define NS_TEST_SERVICE_CONTRACTID "@mozilla.org/test/testservice;1" +#define NS_TEST_SERVICE_CID \ + {0xa00c1406, 0x283a, 0x45c9, \ + {0xae, 0xd2, 0x1a, 0xb6, 0xdd, 0xba, 0xfe, 0x53}} +static NS_DEFINE_CID(kTestServiceCID, NS_TEST_SERVICE_CID); + +int main() +{ + /* + * NOTE: This does NOT demonstrate how these functions are + * intended to be used. They are intended for filling in out + * parameters that need to be |AddRef|ed. I'm just too lazy + * to write lots of little getter functions for a test program + * when I don't need to. + */ + + NS_NOTREACHED("This test is not intended to run, only to compile!"); + + /* Test CallQueryInterface */ + + nsISupports *mySupportsPtr = NS_REINTERPRET_CAST(nsISupports*, 0x1000); + + nsITestService *myITestService = nsnull; + CallQueryInterface(mySupportsPtr, &myITestService); + + nsTestService *myTestService = + NS_REINTERPRET_CAST(nsTestService*, mySupportsPtr); + nsISupportsWeakReference *mySupportsWeakRef; + CallQueryInterface(myTestService, &mySupportsWeakRef); + + /* Test CallQueryReferent */ + + nsIWeakReference *myWeakRef = + NS_STATIC_CAST(nsIWeakReference*, mySupportsPtr); + CallQueryReferent(myWeakRef, &myITestService); + + /* Test CallCreateInstance */ + + CallCreateInstance(kTestServiceCID, mySupportsPtr, &myITestService); + CallCreateInstance(kTestServiceCID, &myITestService); + CallCreateInstance(NS_TEST_SERVICE_CONTRACTID, mySupportsPtr, + &myITestService); + CallCreateInstance(NS_TEST_SERVICE_CONTRACTID, &myITestService); + + /* Test CallGetService */ + nsIShutdownListener *myShutdownListener = nsnull; + CallGetService(kTestServiceCID, &myITestService); + CallGetService(kTestServiceCID, myShutdownListener, &myITestService); + CallGetService(NS_TEST_SERVICE_CONTRACTID, &myITestService); + CallGetService(NS_TEST_SERVICE_CONTRACTID, myShutdownListener, + &myITestService); + + /* Test CallGetInterface */ + nsIInterfaceRequestor *myInterfaceRequestor = + NS_STATIC_CAST(nsIInterfaceRequestor*, mySupportsPtr); + CallGetInterface(myInterfaceRequestor, &myITestService); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp b/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp new file mode 100644 index 00000000..4b00c7fb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestDeque.cpp @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsDeque.h" +#include "nsCRT.h" +#include + +/************************************************************** + Now define the token deallocator class... + **************************************************************/ +class _TestDeque { +public: + _TestDeque() { + SelfTest(); + } + int SelfTest(); + nsresult OriginalTest(); + nsresult OriginalFlaw(); + nsresult AssignFlaw(); +}; +static _TestDeque sTestDeque; + +class _Dealloc: public nsDequeFunctor { + virtual void* operator()(void* aObject) { + return 0; + } +}; + +/** + * conduct automated self test for this class + * + * @param + * @return + */ +int _TestDeque::SelfTest() { + /* the old deque should have failed a bunch of these tests */ + int results=0; + results+=OriginalTest(); + results+=OriginalFlaw(); + results+=AssignFlaw(); + return results; +} + +nsresult _TestDeque::OriginalTest() { + int ints[200]; + int count=sizeof(ints)/sizeof(int); + int i=0; + int* temp; + nsDeque theDeque(new _Dealloc); //construct a simple one... + + for (i=0;icapacity\n"); + + /* Oh, I see ... it's a circular buffer */ + printf("but the old code wasn't behaving accordingly.\n"); + + /*right*/ + printf("we shouldn't crash or anything interesting, "); + + temp=(int*)secondDeque.Peek(); + printf("peek: %d\n",*temp); + return NS_OK; +} + +nsresult _TestDeque::AssignFlaw() { + nsDeque src(new _Dealloc),dest(new _Dealloc); + return NS_OK; +} + +int main (void) { + _TestDeque test; + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp b/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp new file mode 100644 index 00000000..f0d5f777 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestFactory.cpp @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "TestFactory.h" +#include "nsISupports.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" + +NS_DEFINE_CID(kTestFactoryCID, NS_TESTFACTORY_CID); +NS_DEFINE_CID(kTestLoadedFactoryCID, NS_TESTLOADEDFACTORY_CID); + + +/** + * ITestClass implementation + */ + +class TestClassImpl: public ITestClass { + NS_DECL_ISUPPORTS +public: + TestClassImpl() { + } + + void Test(); +}; + +NS_IMPL_ISUPPORTS1(TestClassImpl, ITestClass) + +void TestClassImpl::Test() { + printf("hello, world!\n"); +} + +/** + * TestFactory implementation + */ + +class TestFactory: public nsIFactory { + NS_DECL_ISUPPORTS + +public: + TestFactory() { + } + + NS_IMETHOD CreateInstance(nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock) { return NS_OK; } +}; + +NS_IMPL_ISUPPORTS1(TestFactory, nsIFactory) + +nsresult TestFactory::CreateInstance(nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) { + if (aDelegate != NULL) { + return NS_ERROR_NO_AGGREGATION; + } + + TestClassImpl *t = new TestClassImpl(); + + if (t == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsresult res = t->QueryInterface(aIID, aResult); + + if (NS_FAILED(res)) { + *aResult = NULL; + delete t; + } + + return res; +} + + +int main(int argc, char **argv) { + nsresult rv; + + { + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->RegisterFactory(kTestFactoryCID, + nsnull, + nsnull, + new TestFactory()); + + ITestClass *t = NULL; + nsComponentManager::CreateInstance(kTestFactoryCID, + NULL, + NS_GET_IID(ITestClass), + (void **) &t); + + if (t != NULL) { + t->Test(); + t->Release(); + } else { + printf("CreateInstance failed\n"); + } + + t = NULL; + + nsComponentManager::CreateInstance(kTestLoadedFactoryCID, + NULL, + NS_GET_IID(ITestClass), + (void **) &t); + + if (t != NULL) { + t->Test(); + t->Release(); + } else { + printf("Dynamic CreateInstance failed\n"); + } + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/TestFactory.h b/src/libs/xpcom18a4/xpcom/tests/TestFactory.h new file mode 100644 index 00000000..d81cefc7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestFactory.h @@ -0,0 +1,69 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 __TestFactory_h +#define __TestFactory_h + +#include "nsIFactory.h" + +// {8B330F20-A24A-11d1-A961-00805F8A7AC4} +#define NS_TESTFACTORY_CID \ +{ 0x8b330f20, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +// {8B330F21-A24A-11d1-A961-00805F8A7AC4} +#define NS_ITESTCLASS_IID \ +{ 0x8b330f21, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +// {8B330F22-A24A-11d1-A961-00805F8A7AC4} +#define NS_TESTLOADEDFACTORY_CID \ +{ 0x8b330f22, 0xa24a, 0x11d1, \ + { 0xa9, 0x61, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +#define NS_TESTLOADEDFACTORY_CONTRACTID "@mozilla.org/xpcom/dynamic-test;1" + +class ITestClass: public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITESTCLASS_IID) + virtual void Test() = 0; +}; + +extern "C" void RegisterTestFactories(); + +#endif diff --git a/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp b/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp new file mode 100644 index 00000000..1b2d3671 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestHashtables.cpp @@ -0,0 +1,939 @@ +/* -*- Mode: C++; tab-width: 2; 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 C++ hashtable templates. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg. + * Portions created by the Initial Developer are Copyright (C) 2002 + * 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 "nsTHashtable.h" +#include "nsBaseHashtable.h" +#include "nsDataHashtable.h" +#include "nsInterfaceHashtable.h" +#include "nsClassHashtable.h" + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsCRT.h" +#include "nsCOMArray.h" + +class TestUniChar // for nsClassHashtable +{ +public: + TestUniChar(PRUint32 aWord) + { + printf(" TestUniChar::TestUniChar() %u\n", aWord); + mWord = aWord; + } + + ~TestUniChar() + { + printf(" TestUniChar::~TestUniChar() %u\n", mWord); + } + + PRUint32 GetChar() const { return mWord; } + +private: + PRUint32 mWord; +}; + +struct EntityNode { + const char* mStr; // never owns buffer + PRUint32 mUnicode; +}; + +EntityNode gEntities[] = { + {"nbsp",160}, + {"iexcl",161}, + {"cent",162}, + {"pound",163}, + {"curren",164}, + {"yen",165}, + {"brvbar",166}, + {"sect",167}, + {"uml",168}, + {"copy",169}, + {"ordf",170}, + {"laquo",171}, + {"not",172}, + {"shy",173}, + {"reg",174}, + {"macr",175} +}; + +#define ENTITY_COUNT (sizeof(gEntities)/sizeof(EntityNode)) + +class EntityToUnicodeEntry : public PLDHashEntryHdr +{ +public: + typedef const char* KeyType; + typedef const char* KeyTypePointer; + + EntityToUnicodeEntry(const char* aKey) { mNode = nsnull; } + EntityToUnicodeEntry(const EntityToUnicodeEntry& aEntry) { mNode = aEntry.mNode; } + ~EntityToUnicodeEntry() { }; + + const char* GetKeyPointer() const { return mNode->mStr; } + PRBool KeyEquals(const char* aEntity) const { return !strcmp(mNode->mStr, aEntity); } + static const char* KeyToPointer(const char* aEntity) { return aEntity; } + static PLDHashNumber HashKey(const char* aEntity) { return nsCRT::HashCode(aEntity); } + enum { ALLOW_MEMMOVE = PR_TRUE }; + + const EntityNode* mNode; +}; + +PLDHashOperator +nsTEnumGo(EntityToUnicodeEntry* aEntry, void* userArg) { + printf(" enumerated \"%s\" = %u\n", + aEntry->mNode->mStr, aEntry->mNode->mUnicode); + + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsTEnumStop(EntityToUnicodeEntry* aEntry, void* userArg) { + printf(" enumerated \"%s\" = %u\n", + aEntry->mNode->mStr, aEntry->mNode->mUnicode); + + return PL_DHASH_REMOVE; +} + +void +testTHashtable(nsTHashtable& hash, PRUint32 numEntries) { + printf("Filling hash with %d entries.\n", numEntries); + + PRUint32 i; + for (i = 0; i < numEntries; ++i) { + printf(" Putting entry \"%s\"...", gEntities[i].mStr); + EntityToUnicodeEntry* entry = + hash.PutEntry(gEntities[i].mStr); + + if (!entry) { + printf("FAILED\n"); + exit (2); + } + printf("OK..."); + + if (entry->mNode) { + printf("entry already exists!\n"); + exit (3); + } + printf("\n"); + + entry->mNode = &gEntities[i]; + } + + printf("Testing Get:\n"); + + for (i = 0; i < numEntries; ++i) { + printf(" Getting entry \"%s\"...", gEntities[i].mStr); + EntityToUnicodeEntry* entry = + hash.GetEntry(gEntities[i].mStr); + + if (!entry) { + printf("FAILED\n"); + exit (4); + } + + printf("Found %u\n", entry->mNode->mUnicode); + } + + printf("Testing non-existent entries..."); + + EntityToUnicodeEntry* entry = + hash.GetEntry("xxxy"); + + if (entry) { + printf("FOUND! BAD!\n"); + exit (5); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + PRUint32 count = hash.EnumerateEntries(nsTEnumGo, nsnull); + if (count != numEntries) { + printf(" Bad count!\n"); + exit (6); + } +} + +PLDHashOperator +nsDEnumRead(const PRUint32& aKey, const char* aData, void* userArg) { + printf(" enumerated %u = \"%s\"\n", aKey, aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsDEnum(const PRUint32& aKey, const char*& aData, void* userArg) { + printf(" enumerated %u = \"%s\"\n", aKey, aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsCEnumRead(const nsACString& aKey, TestUniChar* aData, void* userArg) { + printf(" enumerated \"%s\" = %c\n", + PromiseFlatCString(aKey).get(), aData->GetChar()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsCEnum(const nsACString& aKey, nsAutoPtr& aData, void* userArg) { + printf(" enumerated \"%s\" = %c\n", + PromiseFlatCString(aKey).get(), aData->GetChar()); + return PL_DHASH_NEXT; +} + +// +// all this nsIFoo stuff was copied wholesale from TestCOMPTr.cpp +// + +#define NS_IFOO_IID \ +{ 0x6f7652e0, 0xee43, 0x11d1, \ + { 0x9c, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3 } } + +class IFoo : public nsISupports + { + public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFOO_IID) + + public: + IFoo(); + + NS_IMETHOD_(nsrefcnt) AddRef(); + NS_IMETHOD_(nsrefcnt) Release(); + NS_IMETHOD QueryInterface( const nsIID&, void** ); + + NS_IMETHOD SetString(const nsACString& /*in*/ aString); + NS_IMETHOD GetString(nsACString& /*out*/ aString); + + static void print_totals(); + + private: + ~IFoo(); + + unsigned int refcount_; + + static unsigned int total_constructions_; + static unsigned int total_destructions_; + nsCString mString; + }; + +unsigned int IFoo::total_constructions_; +unsigned int IFoo::total_destructions_; + +void +IFoo::print_totals() + { + printf("total constructions/destructions --> %d/%d\n", + total_constructions_, total_destructions_); + } + +IFoo::IFoo() + : refcount_(0) + { + ++total_constructions_; + printf(" new IFoo@%p [#%d]\n", + NS_STATIC_CAST(void*, this), total_constructions_); + } + +IFoo::~IFoo() + { + ++total_destructions_; + printf("IFoo@%p::~IFoo() [#%d]\n", + NS_STATIC_CAST(void*, this), total_destructions_); + } + +nsrefcnt +IFoo::AddRef() + { + ++refcount_; + printf("IFoo@%p::AddRef(), refcount --> %d\n", + NS_STATIC_CAST(void*, this), refcount_); + return refcount_; + } + +nsrefcnt +IFoo::Release() + { + int wrap_message = (refcount_ == 1); + if ( wrap_message ) + printf(">>"); + + nsrefcnt newrefcount = --refcount_; + printf("IFoo@%p::Release(), refcount --> %d\n", + NS_STATIC_CAST(void*, this), newrefcount); + + if ( !newrefcount ) + { + printf(" delete IFoo@%p\n", NS_STATIC_CAST(void*, this)); + delete this; + } + + if ( wrap_message ) + printf(" delete IFoo@%p\n", NS_STATIC_CAST(void*, this)); + + return newrefcount; + } + +nsresult +IFoo::QueryInterface( const nsIID& aIID, void** aResult ) + { + printf("IFoo@%p::QueryInterface()\n", NS_STATIC_CAST(void*, this)); + nsISupports* rawPtr = 0; + nsresult status = NS_OK; + + if ( aIID.Equals(GetIID()) ) + rawPtr = this; + else + { + nsID iid_of_ISupports = NS_ISUPPORTS_IID; + if ( aIID.Equals(iid_of_ISupports) ) + rawPtr = NS_STATIC_CAST(nsISupports*, this); + else + status = NS_ERROR_NO_INTERFACE; + } + + NS_IF_ADDREF(rawPtr); + *aResult = rawPtr; + + return status; + } + +nsresult +IFoo::SetString(const nsACString& aString) +{ + mString = aString; + return NS_OK; +} + +nsresult +IFoo::GetString(nsACString& aString) +{ + aString = mString; + return NS_OK; +} + +nsresult +CreateIFoo( IFoo** result ) + // a typical factory function (that calls AddRef) + { + printf(" >>CreateIFoo() --> "); + IFoo* foop = new IFoo(); + printf("IFoo@%p\n", NS_STATIC_CAST(void*, foop)); + + foop->AddRef(); + *result = foop; + + printf("<GetString(str); + + printf(" enumerated %u = \"%s\"\n", aKey, str.get()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum(const PRUint32& aKey, nsCOMPtr& aData, void* userArg) { + nsCAutoString str; + aData->GetString(str); + + printf(" enumerated %u = \"%s\"\n", aKey, str.get()); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum2Read(nsISupports* aKey, PRUint32 aData, void* userArg) { + nsCAutoString str; + nsCOMPtr foo = do_QueryInterface(aKey); + foo->GetString(str); + + + printf(" enumerated \"%s\" = %u\n", str.get(), aData); + return PL_DHASH_NEXT; +} + +PLDHashOperator +nsIEnum2(nsISupports* aKey, PRUint32& aData, void* userArg) { + nsCAutoString str; + nsCOMPtr foo = do_QueryInterface(aKey); + foo->GetString(str); + + printf(" enumerated \"%s\" = %u\n", str.get(), aData); + return PL_DHASH_NEXT; +} + +int +main(void) { + // check an nsTHashtable + nsTHashtable EntityToUnicode; + + printf("Initializing nsTHashtable..."); + if (!EntityToUnicode.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (1); + } + printf("OK\n"); + + printf("Partially filling nsTHashtable:\n"); + testTHashtable(EntityToUnicode, 5); + + printf("Enumerate-removing...\n"); + PRUint32 count = EntityToUnicode.EnumerateEntries(nsTEnumStop, nsnull); + if (count != 5) { + printf("wrong count\n"); + exit (7); + } + printf("OK\n"); + + printf("Check enumeration..."); + count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nsnull); + if (count) { + printf("entries remain in table!\n"); + exit (8); + } + printf("OK\n"); + + printf("Filling nsTHashtable:\n"); + testTHashtable(EntityToUnicode, ENTITY_COUNT); + + printf("Clearing..."); + EntityToUnicode.Clear(); + printf("OK\n"); + + printf("Check enumeration..."); + count = EntityToUnicode.EnumerateEntries(nsTEnumGo, nsnull); + if (count) { + printf("entries remain in table!\n"); + exit (9); + } + printf("OK\n"); + + // + // now check a data-hashtable + // + + nsDataHashtable UniToEntity; + + printf("Initializing nsDataHashtable..."); + if (!UniToEntity.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (10); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + PRUint32 i; + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + if (!UniToEntity.Put(gEntities[i].mUnicode, gEntities[i].mStr)) { + printf("FAILED\n"); + exit (11); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + const char* str; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %u...", gEntities[i].mUnicode); + if (!UniToEntity.Get(gEntities[i].mUnicode, &str)) { + printf("FAILED\n"); + exit (12); + } + + printf("Found %s\n", str); + } + + printf("Testing non-existent entries..."); + if (UniToEntity.Get(99446, &str)) { + printf("FOUND! BAD!\n"); + exit (13); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntity.EnumerateRead(nsDEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (14); + } + + printf("Clearing..."); + UniToEntity.Clear(); + printf("OK\n"); + + printf("Checking count..."); + count = UniToEntity.Enumerate(nsDEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (15); + } + + printf("OK\n"); + + // + // now check a thread-safe data-hashtable + // + + nsDataHashtableMT UniToEntityL; + + printf("Initializing nsDataHashtableMT..."); + if (!UniToEntityL.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (10); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + if (!UniToEntityL.Put(gEntities[i].mUnicode, gEntities[i].mStr)) { + printf("FAILED\n"); + exit (11); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %u...", gEntities[i].mUnicode); + if (!UniToEntityL.Get(gEntities[i].mUnicode, &str)) { + printf("FAILED\n"); + exit (12); + } + + printf("Found %s\n", str); + } + + printf("Testing non-existent entries..."); + if (UniToEntityL.Get(99446, &str)) { + printf("FOUND! BAD!\n"); + exit (13); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntityL.EnumerateRead(nsDEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (14); + } + + printf("Clearing..."); + UniToEntityL.Clear(); + printf("OK\n"); + + printf("Checking count..."); + count = UniToEntityL.Enumerate(nsDEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (15); + } + + printf("OK\n"); + + // + // now check a class-hashtable + // + + nsClassHashtable EntToUniClass; + + printf("Initializing nsClassHashtable..."); + if (!EntToUniClass.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (16); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + TestUniChar* temp = new TestUniChar(gEntities[i].mUnicode); + + if (!EntToUniClass.Put(nsDependentCString(gEntities[i].mStr), temp)) { + printf("FAILED\n"); + delete temp; + exit (17); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + TestUniChar* myChar; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + if (!EntToUniClass.Get(nsDependentCString(gEntities[i].mStr), &myChar)) { + printf("FAILED\n"); + exit (18); + } + + printf("Found %c\n", myChar->GetChar()); + } + + printf("Testing non-existent entries..."); + if (EntToUniClass.Get(NS_LITERAL_CSTRING("xxxx"), &myChar)) { + printf("FOUND! BAD!\n"); + exit (19); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClass.EnumerateRead(nsCEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (20); + } + + printf("Clearing...\n"); + EntToUniClass.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClass.Enumerate(nsCEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (21); + } + + printf("OK\n"); + + // + // now check a thread-safe class-hashtable + // + + nsClassHashtableMT EntToUniClassL; + + printf("Initializing nsClassHashtableMT..."); + if (!EntToUniClassL.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (16); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + TestUniChar* temp = new TestUniChar(gEntities[i].mUnicode); + + if (!EntToUniClassL.Put(nsDependentCString(gEntities[i].mStr), temp)) { + printf("FAILED\n"); + delete temp; + exit (17); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + if (!EntToUniClassL.Get(nsDependentCString(gEntities[i].mStr), &myChar)) { + printf("FAILED\n"); + exit (18); + } + + printf("Found %c\n", myChar->GetChar()); + } + + printf("Testing non-existent entries..."); + if (EntToUniClassL.Get(NS_LITERAL_CSTRING("xxxx"), &myChar)) { + printf("FOUND! BAD!\n"); + exit (19); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClassL.EnumerateRead(nsCEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (20); + } + + printf("Clearing...\n"); + EntToUniClassL.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClassL.Enumerate(nsCEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (21); + } + + printf("OK\n"); + + // + // now check a data-hashtable with an interface key + // + + nsDataHashtable EntToUniClass2; + + printf("Initializing nsDataHashtable with interface key..."); + if (!EntToUniClass2.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (22); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + nsCOMArray fooArray; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + + fooArray.InsertObjectAt(foo, i); + + if (!EntToUniClass2.Put(foo, gEntities[i].mUnicode)) { + printf("FAILED\n"); + exit (23); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + PRUint32 myChar2; + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + if (!EntToUniClass2.Get(fooArray[i], &myChar2)) { + printf("FAILED\n"); + exit (24); + } + + printf("Found %c\n", myChar2); + } + + printf("Testing non-existent entries..."); + if (EntToUniClass2.Get((nsISupports*) 0x55443316, &myChar2)) { + printf("FOUND! BAD!\n"); + exit (25); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = EntToUniClass2.EnumerateRead(nsIEnum2Read, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (26); + } + + printf("Clearing...\n"); + EntToUniClass2.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = EntToUniClass2.Enumerate(nsIEnum2, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (27); + } + + printf("OK\n"); + + // + // now check an interface-hashtable with an PRUint32 key + // + + nsInterfaceHashtable UniToEntClass2; + + printf("Initializing nsInterfaceHashtable..."); + if (!UniToEntClass2.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (28); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + if (!UniToEntClass2.Put(gEntities[i].mUnicode, foo)) { + printf("FAILED\n"); + exit (29); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + nsCOMPtr myEnt; + if (!UniToEntClass2.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) { + printf("FAILED\n"); + exit (30); + } + + nsCAutoString str; + myEnt->GetString(str); + printf("Found %s\n", str.get()); + } + + printf("Testing non-existent entries..."); + nsCOMPtr myEnt; + if (UniToEntClass2.Get(9462, getter_AddRefs(myEnt))) { + printf("FOUND! BAD!\n"); + exit (31); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntClass2.EnumerateRead(nsIEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (32); + } + + printf("Clearing...\n"); + UniToEntClass2.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = UniToEntClass2.Enumerate(nsIEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (33); + } + + printf("OK\n"); + + // + // now check a thread-safe interface hashtable + // + + nsInterfaceHashtableMT UniToEntClass2L; + + printf("Initializing nsInterfaceHashtableMT..."); + if (!UniToEntClass2L.Init(ENTITY_COUNT)) { + printf("FAILED\n"); + exit (28); + } + printf("OK\n"); + + printf("Filling hash with %zd entries.\n", ENTITY_COUNT); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Putting entry %u...", gEntities[i].mUnicode); + nsCOMPtr foo; + CreateIFoo(getter_AddRefs(foo)); + foo->SetString(nsDependentCString(gEntities[i].mStr)); + + if (!UniToEntClass2L.Put(gEntities[i].mUnicode, foo)) { + printf("FAILED\n"); + exit (29); + } + printf("OK...\n"); + } + + printf("Testing Get:\n"); + + for (i = 0; i < ENTITY_COUNT; ++i) { + printf(" Getting entry %s...", gEntities[i].mStr); + + nsCOMPtr myEnt; + if (!UniToEntClass2L.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) { + printf("FAILED\n"); + exit (30); + } + + nsCAutoString str; + myEnt->GetString(str); + printf("Found %s\n", str.get()); + } + + printf("Testing non-existent entries..."); + if (UniToEntClass2L.Get(9462, getter_AddRefs(myEnt))) { + printf("FOUND! BAD!\n"); + exit (31); + } + + printf("not found; good.\n"); + + printf("Enumerating:\n"); + + count = UniToEntClass2L.EnumerateRead(nsIEnumRead, nsnull); + if (count != ENTITY_COUNT) { + printf(" Bad count!\n"); + exit (32); + } + + printf("Clearing...\n"); + UniToEntClass2L.Clear(); + printf(" Clearing OK\n"); + + printf("Checking count..."); + count = UniToEntClass2L.Enumerate(nsIEnum, nsnull); + if (count) { + printf(" Clear did not remove all entries.\n"); + exit (33); + } + + printf("OK\n"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestID.cpp b/src/libs/xpcom18a4/xpcom/tests/TestID.cpp new file mode 100644 index 00000000..f91fda9f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestID.cpp @@ -0,0 +1,77 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "plstr.h" +#include "nsID.h" +#include "prmem.h" + +static const char* const ids[] = { + "5C347B10-D55C-11D1-89B7-006008911B81", + "{5C347B10-D55C-11D1-89B7-006008911B81}", + "5c347b10-d55c-11d1-89b7-006008911b81", + "{5c347b10-d55c-11d1-89b7-006008911b81}", + + "FC347B10-D55C-F1D1-F9B7-006008911B81", + "{FC347B10-D55C-F1D1-F9B7-006008911B81}", + "fc347b10-d55c-f1d1-f9b7-006008911b81", + "{fc347b10-d55c-f1d1-f9b7-006008911b81}", +}; +#define NUM_IDS ((int) (sizeof(ids) / sizeof(ids[0]))) + +int main(int argc, char** argv) +{ + nsID id; + for (int i = 0; i < NUM_IDS; i++) { + const char* idstr = ids[i]; + if (!id.Parse(idstr)) { + fprintf(stderr, "TestID: Parse failed on test #%d\n", i); + return -1; + } + char* cp = id.ToString(); + if (NULL == cp) { + fprintf(stderr, "TestID: ToString failed on test #%d\n", i); + return -1; + } + if (0 != PL_strcmp(cp, ids[4*(i/4) + 3])) { + fprintf(stderr, "TestID: compare of ToString failed on test #%d\n", i); + return -1; + } + PR_Free(cp); + } + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp b/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp new file mode 100644 index 00000000..811df138 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestMinStringAPI.cpp @@ -0,0 +1,333 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "nsStringAPI.h" +#include "nsCRT.h" + +static const char kAsciiData[] = "hello world"; + +static const PRUnichar kUnicodeData[] = + {'h','e','l','l','o',' ','w','o','r','l','d','\0'}; + +static PRBool test_basic_1() + { + nsCStringContainer s; + NS_CStringContainerInit(s); + + const char *ptr; + PRUint32 len; + char *clone; + + NS_CStringGetData(s, &ptr); + if (ptr == nsnull || *ptr != '\0') + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_CStringSetData(s, kAsciiData, PR_UINT32_MAX); + len = NS_CStringGetData(s, &ptr); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kAsciiData)-1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + clone = NS_CStringCloneData(s); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + nsMemory::Free(clone); + + nsCStringContainer temp; + NS_CStringContainerInit(temp); + NS_CStringCopy(temp, s); + + len = NS_CStringGetData(temp, &ptr); + if (ptr == nsnull || strcmp(ptr, kAsciiData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kAsciiData)-1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_CStringContainerFinish(temp); + + NS_CStringContainerFinish(s); + return PR_TRUE; + } + +static PRBool test_basic_2() + { + nsStringContainer s; + NS_StringContainerInit(s); + + const PRUnichar *ptr; + PRUint32 len; + PRUnichar *clone; + + NS_StringGetData(s, &ptr); + if (ptr == nsnull || *ptr != '\0') + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_StringSetData(s, kUnicodeData, PR_UINT32_MAX); + len = NS_StringGetData(s, &ptr); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kUnicodeData)/2 - 1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + clone = NS_StringCloneData(s); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + nsMemory::Free(clone); + + nsStringContainer temp; + NS_StringContainerInit(temp); + NS_StringCopy(temp, s); + + len = NS_StringGetData(temp, &ptr); + if (ptr == nsnull || nsCRT::strcmp(ptr, kUnicodeData) != 0) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + if (len != sizeof(kUnicodeData)/2 - 1) + { + NS_ERROR("unexpected result"); + return PR_FALSE; + } + + NS_StringContainerFinish(temp); + + NS_StringContainerFinish(s); + + return PR_TRUE; + } + +static PRBool test_convert() + { + nsStringContainer s; + NS_StringContainerInit(s); + NS_StringSetData(s, kUnicodeData, sizeof(kUnicodeData)/2 - 1); + + nsCStringContainer temp; + NS_CStringContainerInit(temp); + + const char *data; + + NS_UTF16ToCString(s, NS_CSTRING_ENCODING_ASCII, temp); + NS_CStringGetData(temp, &data); + if (strcmp(data, kAsciiData) != 0) + return PR_FALSE; + + NS_UTF16ToCString(s, NS_CSTRING_ENCODING_UTF8, temp); + NS_CStringGetData(temp, &data); + if (strcmp(data, kAsciiData) != 0) + return PR_FALSE; + + NS_CStringContainerFinish(temp); + + NS_StringContainerFinish(s); + return PR_TRUE; + } + +static PRBool test_append() + { + nsCStringContainer s; + NS_CStringContainerInit(s); + + NS_CStringSetData(s, "foo"); + NS_CStringAppendData(s, "bar"); + + NS_CStringContainerFinish(s); + return PR_TRUE; + } + +// Replace all occurances of |matchVal| with |newVal| +static void ReplaceSubstring( nsACString& str, + const nsACString& matchVal, + const nsACString& newVal ) + { + const char* sp, *mp, *np; + PRUint32 sl, ml, nl; + + sl = NS_CStringGetData(str, &sp); + ml = NS_CStringGetData(matchVal, &mp); + nl = NS_CStringGetData(newVal, &np); + + for (const char* iter = sp; iter <= sp + sl - ml; ++iter) + { + if (memcmp(iter, mp, ml) == 0) + { + PRUint32 offset = iter - sp; + + NS_CStringSetDataRange(str, offset, ml, np, nl); + + sl = NS_CStringGetData(str, &sp); + + iter = sp + offset + nl - 1; + } + } + } + +static PRBool test_replace_driver(const char *strVal, + const char *matchVal, + const char *newVal, + const char *finalVal) + { + nsCStringContainer a; + NS_CStringContainerInit(a); + NS_CStringSetData(a, strVal); + + nsCStringContainer b; + NS_CStringContainerInit(b); + NS_CStringSetData(b, matchVal); + + nsCStringContainer c; + NS_CStringContainerInit(c); + NS_CStringSetData(c, newVal); + + ReplaceSubstring(a, b, c); + + const char *data; + NS_CStringGetData(a, &data); + if (strcmp(data, finalVal) != 0) + return PR_FALSE; + + NS_CStringContainerFinish(c); + NS_CStringContainerFinish(b); + NS_CStringContainerFinish(a); + return PR_TRUE; + } + +static PRBool test_replace() + { + PRBool rv; + + rv = test_replace_driver("hello world, hello again!", + "hello", + "goodbye", + "goodbye world, goodbye again!"); + if (!rv) + return rv; + + rv = test_replace_driver("foofoofoofoo!", + "foo", + "bar", + "barbarbarbar!"); + if (!rv) + return rv; + + rv = test_replace_driver("foo bar systems", + "xyz", + "crazy", + "foo bar systems"); + if (!rv) + return rv; + + rv = test_replace_driver("oh", + "xyz", + "crazy", + "oh"); + if (!rv) + return rv; + + return PR_TRUE; + } + +//---- + +typedef PRBool (*TestFunc)(); + +static const struct Test + { + const char* name; + TestFunc func; + } +tests[] = + { + { "test_basic_1", test_basic_1 }, + { "test_basic_2", test_basic_2 }, + { "test_convert", test_convert }, + { "test_append", test_append }, + { "test_replace", test_replace }, + { nsnull, nsnull } + }; + +//---- + +int main(int argc, char **argv) + { + int count = 1; + if (argc > 1) + count = atoi(argv[1]); + + while (count--) + { + for (const Test* t = tests; t->name != nsnull; ++t) + { + printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE"); + } + } + + return 0; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp b/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp new file mode 100644 index 00000000..148400e2 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestObserverService.cpp @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.h" +#include "nsIComponentManager.h" +#include "nsIObserverService.h" +#include "nsIObserver.h" +#include "nsIEnumerator.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "prprf.h" +#include "nsWeakReference.h" + +static nsIObserverService *anObserverService = NULL; + +#ifdef VBOX +static bool testResult( nsresult rv ) { + if ( NS_SUCCEEDED( rv ) ) { + printf("...ok\n"); + return true; + } + printf("...failed, rv=0x%x\n", (int)rv); + return false; +} +#else +static void testResult( nsresult rv ) { + if ( NS_SUCCEEDED( rv ) ) { + printf("...ok\n"); + } else { + printf("...failed, rv=0x%x\n", (int)rv); + } + return; +} +#endif + +void printString(nsString &str) { +#ifdef VBOX /* asan complains about mixing different allocators */ + char *cstr = ToNewCString(str); + printf("%s", cstr); + nsMemory::Free(cstr); +#else + const char *cstr = ToNewCString(str); + printf("%s", cstr); + delete [] (char*)cstr; +#endif +} + +class TestObserver : public nsIObserver, public nsSupportsWeakReference { +public: + TestObserver( const nsAString &name ) + : mName( name ) { + } + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + nsString mName; + +private: + ~TestObserver() {} +}; + +NS_IMPL_ISUPPORTS2( TestObserver, nsIObserver, nsISupportsWeakReference ) + +NS_IMETHODIMP +TestObserver::Observe( nsISupports *aSubject, + const char *aTopic, + const PRUnichar *someData ) { + nsCString topic( aTopic ); + nsString data( someData ); + /* + The annoying double-cast below is to work around an annoying bug in + the compiler currently used on wensleydale. This is a test. + */ + printString(mName); + printf(" has observed something: subject@%p", (void*)aSubject); + printf(" name="); + printString(NS_REINTERPRET_CAST(TestObserver*, NS_REINTERPRET_CAST(void*, aSubject))->mName); + printf(" aTopic=%s", topic.get()); + printf(" someData="); + printString(data); + printf("\n"); + return NS_OK; +} + +int main(int argc, char *argv[]) +{ + nsCString topicA; topicA.Assign( "topic-A" ); + nsCString topicB; topicB.Assign( "topic-B" ); + nsresult rv; + + nsresult res = nsComponentManager::CreateInstance("@mozilla.org/observer-service;1", + NULL, + NS_GET_IID(nsIObserverService), + (void **) &anObserverService); +#ifdef VBOX + bool fSuccess = res == NS_OK; +#endif + + if (res == NS_OK) { + + nsIObserver *aObserver = new TestObserver(NS_LITERAL_STRING("Observer-A")); + aObserver->AddRef(); + nsIObserver *bObserver = new TestObserver(NS_LITERAL_STRING("Observer-B")); + bObserver->AddRef(); + + printf("Adding Observer-A as observer of topic-A...\n"); + rv = anObserverService->AddObserver(aObserver, topicA.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Adding Observer-B as observer of topic-A...\n"); + rv = anObserverService->AddObserver(bObserver, topicA.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Adding Observer-B as observer of topic-B...\n"); + rv = anObserverService->AddObserver(bObserver, topicB.get(), PR_FALSE); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing Notify(observer-A, topic-A)...\n"); + rv = anObserverService->NotifyObservers( aObserver, + topicA.get(), + NS_LITERAL_STRING("Testing Notify(observer-A, topic-A)").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing Notify(observer-B, topic-B)...\n"); + rv = anObserverService->NotifyObservers( bObserver, + topicB.get(), + NS_LITERAL_STRING("Testing Notify(observer-B, topic-B)").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Testing EnumerateObserverList (for topic-A)...\n"); + nsCOMPtr e; + rv = anObserverService->EnumerateObservers(topicA.get(), getter_AddRefs(e)); + +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + printf("Enumerating observers of topic-A...\n"); + if ( e ) { + nsCOMPtr observer; + PRBool loop = PR_TRUE; + while( NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) + { + e->GetNext(getter_AddRefs(observer)); + printf("Calling observe on enumerated observer "); + printString(NS_REINTERPRET_CAST(TestObserver*, + NS_REINTERPRET_CAST(void*, observer.get()))->mName); + printf("...\n"); + rv = observer->Observe( observer, + topicA.get(), + NS_LITERAL_STRING("during enumeration").get() ); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + } + } + printf("...done enumerating observers of topic-A\n"); + + printf("Removing Observer-A...\n"); + rv = anObserverService->RemoveObserver(aObserver, topicA.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + + + printf("Removing Observer-B (topic-A)...\n"); + rv = anObserverService->RemoveObserver(bObserver, topicB.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + printf("Removing Observer-B (topic-B)...\n"); + rv = anObserverService->RemoveObserver(bObserver, topicA.get()); +#ifdef VBOX + fSuccess = fSuccess && +#endif + testResult(rv); + +#ifdef VBOX + /* Cleanup: */ + nsrefcnt refs = bObserver->Release(); + fSuccess = fSuccess && refs == 0; + if (refs != 0) + printf("bObserver->Release() -> %d, expected 0\n", (int)refs); + + refs = aObserver->Release(); + fSuccess = fSuccess && refs == 0; + if (refs != 0) + printf("aObserver->Release() -> %d, expected 0\n", (int)refs); +#endif + } +#ifdef VBOX + return fSuccess ? 0 : 1; +#else + return NS_OK; +#endif +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp b/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp new file mode 100644 index 00000000..09b0b2e9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestPermanentAtoms.cpp @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +// vim:cindent:ts=8:et:sw=4: +/* ***** 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 TestPermanentAtoms.cpp. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * L. David Baron (original author) + * + * 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 "nsIAtom.h" +#include "nsAtomTable.h" +#include "nsCOMPtr.h" +#include +#include "nsString.h" +#include "nsReadableUtils.h" + +static void Assert(PRBool aCondition, const char* aStatement) +{ + printf("%s: %s\n", aCondition?"PASS":"FAIL", aStatement); +} + +static void AssertString(nsIAtom *aAtom, const nsACString& aString) +{ + const char *str; + NS_STATIC_CAST(AtomImpl*,aAtom)->GetUTF8String(&str); + Assert(nsDependentCString(str) == aString, "string is correct"); +} + +static void AssertPermanence(nsIAtom *aAtom, PRBool aPermanence) +{ + Assert(NS_STATIC_CAST(AtomImpl*,aAtom)->IsPermanent() == aPermanence, + aPermanence ? "atom is permanent" : "atom is not permanent"); +} + +int main() +{ + nsCOMPtr foo = do_GetAtom("foo"); + AssertString(foo, NS_LITERAL_CSTRING("foo")); + AssertPermanence(foo, PR_FALSE); + + nsCOMPtr foop = do_GetPermanentAtom("foo"); + AssertString(foop, NS_LITERAL_CSTRING("foo")); + AssertPermanence(foop, PR_TRUE); + + Assert(foo == foop, "atoms are equal"); + + nsCOMPtr barp = do_GetPermanentAtom("bar"); + AssertString(barp, NS_LITERAL_CSTRING("bar")); + AssertPermanence(barp, PR_TRUE); + + nsCOMPtr bar = do_GetAtom("bar"); + AssertString(bar, NS_LITERAL_CSTRING("bar")); + AssertPermanence(bar, PR_TRUE); + + Assert(bar == barp, "atoms are equal"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp b/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp new file mode 100644 index 00000000..2d798a5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestPipes.cpp @@ -0,0 +1,655 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIThread.h" +#include "nsIRunnable.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsIServiceManager.h" +#include "prprf.h" +#include "prinrval.h" +#include "plstr.h" +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include +#include "nsIPipe.h" // new implementation +#include "nsAutoLock.h" +#include // for rand + +#define KEY 0xa7 +#define ITERATIONS 33333 +char kTestPattern[] = "My hovercraft is full of eels.\n"; + +PRBool gTrace = PR_FALSE; + +static nsresult +WriteAll(nsIOutputStream *os, const char *buf, PRUint32 bufLen, PRUint32 *lenWritten) +{ + const char *p = buf; + *lenWritten = 0; + while (bufLen) { + PRUint32 n; + nsresult rv = os->Write(p, bufLen, &n); + if (NS_FAILED(rv)) return rv; + p += n; + bufLen -= n; + *lenWritten += n; + } + return NS_OK; +} + +class nsReceiver : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + PRIntervalTime start = PR_IntervalNow(); + while (PR_TRUE) { + rv = mIn->Read(buf, 100, &count); + if (NS_FAILED(rv)) { + printf("read failed\n"); + break; + } + if (count == 0) { +// printf("EOF count = %d\n", mCount); + break; + } + + if (gTrace) { + printf("read: "); + buf[count] = '\0'; + printf(buf); + printf("\n"); + } + mCount += count; + } + PRIntervalTime end = PR_IntervalNow(); + printf("read %d bytes, time = %dms\n", mCount, + PR_IntervalToMilliseconds(end - start)); + return rv; + } + + nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) { + NS_ADDREF(in); + } + + PRUint32 GetBytesRead() { return mCount; } + +private: + ~nsReceiver() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mCount; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsReceiver, nsIRunnable) + +nsresult +TestPipe(nsIInputStream* in, nsIOutputStream* out) +{ + nsresult rv; + nsIThread* thread; + nsReceiver* receiver = new nsReceiver(in); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + PRIntervalTime start = PR_IntervalNow(); + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char *buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + rv = WriteAll(out, buf, len, &writeCount); + if (gTrace) { + printf("wrote: "); + for (PRUint32 j = 0; j < writeCount; j++) { + putc(buf[j], stdout); + } + printf("\n"); + } + PR_smprintf_free(buf); + if (NS_FAILED(rv)) return rv; + total += writeCount; + } + rv = out->Close(); + if (NS_FAILED(rv)) return rv; + + PRIntervalTime end = PR_IntervalNow(); + + thread->Join(); + + printf("wrote %d bytes, time = %dms\n", total, + PR_IntervalToMilliseconds(end - start)); + NS_ASSERTION(receiver->GetBytesRead() == total, "didn't read everything"); + + NS_RELEASE(thread); + NS_RELEASE(receiver); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +class nsShortReader : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + PRUint32 total = 0; + while (PR_TRUE) { + //if (gTrace) + // printf("calling Read\n"); + rv = mIn->Read(buf, 100, &count); + if (NS_FAILED(rv)) { + printf("read failed\n"); + break; + } + if (count == 0) { + break; + } + buf[count] = '\0'; + if (gTrace) + printf("read %d bytes: %s\n", count, buf); + Received(count); + total += count; + } + printf("read %d bytes\n", total); + return rv; + } + + nsShortReader(nsIInputStream* in) : mIn(in), mReceived(0) { + NS_ADDREF(in); + } + + void Received(PRUint32 count) { + nsAutoCMonitor mon(this); + mReceived += count; + mon.Notify(); + } + + PRUint32 WaitForReceipt() { + nsAutoCMonitor mon(this); + PRUint32 result = mReceived; + while (result == 0) { + mon.Wait(); + NS_ASSERTION(mReceived >= 0, "failed to receive"); + result = mReceived; + } + mReceived = 0; + return result; + } + +private: + ~nsShortReader() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mReceived; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsShortReader, nsIRunnable) + +nsresult +TestShortWrites(nsIInputStream* in, nsIOutputStream* out) +{ + nsresult rv; + nsIThread* thread; + nsShortReader* receiver = new nsShortReader(in); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&thread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + len = len * rand() / RAND_MAX; + len = PR_MAX(1, len); + rv = WriteAll(out, buf, len, &writeCount); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(writeCount == len, "didn't write enough"); + total += writeCount; + + if (gTrace) + printf("wrote %d bytes: %s\n", writeCount, buf); + PR_smprintf_free(buf); + //printf("calling Flush\n"); + out->Flush(); + //printf("calling WaitForReceipt\n"); + PRUint32 received = receiver->WaitForReceipt(); + NS_ASSERTION(received == writeCount, "received wrong amount"); + } + rv = out->Close(); + if (NS_FAILED(rv)) return rv; + + thread->Join(); + printf("wrote %d bytes\n", total); + + NS_RELEASE(thread); + NS_RELEASE(receiver); + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +#if 0 + +class nsPipeObserver : public nsIInputStreamObserver, + public nsIOutputStreamObserver +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD OnFull(nsIOutputStream *outStr) { + printf("OnFull outStr=%p\n", outStr); + return NS_OK; + } + + NS_IMETHOD OnWrite(nsIOutputStream *outStr, PRUint32 amount) { + printf("OnWrite outStr=%p amount=%d\n", outStr, amount); + return NS_OK; + } + + NS_IMETHOD OnEmpty(nsIInputStream* inStr) { + printf("OnEmpty inStr=%p\n", inStr); + return NS_OK; + } + + NS_IMETHOD OnClose(nsIInputStream* inStr) { + printf("OnClose inStr=%p\n", inStr); + return NS_OK; + } + + nsPipeObserver() { } + +private: + ~nsPipeObserver() {} +}; + +NS_IMPL_ISUPPORTS2(nsPipeObserver, nsIInputStreamObserver, nsIOutputStreamObserver) + +nsresult +TestPipeObserver() +{ + nsresult rv; + nsPipeObserver* obs = new nsPipeObserver(); + if (obs == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(obs); + + printf("TestPipeObserver: OnWrite and OnFull should be called once, OnEmpty should be called twice.\n"); + nsIInputStream* in; + nsIOutputStream* out; + rv = NS_NewPipe(&in, &out, 18, 36, PR_TRUE, PR_TRUE); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr observableIn(do_QueryInterface(in, &rv)); + if (NS_FAILED(rv)) return rv; + nsCOMPtr observableOut(do_QueryInterface(out, &rv)); + if (NS_FAILED(rv)) return rv; + + rv = observableIn->SetObserver(obs); + if (NS_FAILED(rv)) return rv; + rv = observableOut->SetObserver(obs); + if (NS_FAILED(rv)) return rv; + + char buf[] = "puirt a beul: a style of Gaelic vocal music intended for dancing."; + PRUint32 cnt; + printf("> should see OnWrite message:\n"); + rv = out->Write(buf, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Write failed"); + + printf("> should see OnWrite message followed by OnFull message:\n"); + rv = out->Write(buf + 20, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 16, "Write failed"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 36, "Available failed"); + + char buf2[40]; + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 40, &cnt); + if (NS_FAILED(rv)) return rv; + printf("cnt = %u\n", cnt); + NS_ASSERTION(cnt == 36, "Read failed"); + NS_ASSERTION(nsCRT::strncmp(buf, buf2, 36) == 0, "Read wrong stuff"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 0, "Available failed"); + + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 2, &cnt); + if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) return rv; + NS_ASSERTION(cnt == 0 && rv == NS_BASE_STREAM_WOULD_BLOCK, "Read failed"); + + printf("> should see OnWrite message:\n"); + rv = out->Write(buf, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Write failed"); + + rv = in->Available(&cnt); + if (NS_FAILED(rv)) return rv; + printf("available = %u\n", cnt); + NS_ASSERTION(cnt == 20, "Available failed"); + + printf("> should see OnEmpty message:\n"); + rv = in->Read(buf2, 20, &cnt); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(cnt == 20, "Read failed"); + + printf("> should see OnClose message:\n"); + NS_RELEASE(obs); + NS_RELEASE(in); + NS_RELEASE(out); + return NS_OK; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// + +class nsPump : public nsIRunnable +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + PRUint32 count; + while (PR_TRUE) { + nsAutoCMonitor mon(this); + rv = mOut->WriteFrom(mIn, ~0U, &count); + if (NS_FAILED(rv)) { + printf("Write failed\n"); + break; + } + if (count == 0) { + printf("EOF count = %d\n", mCount); + break; + } + + if (gTrace) { + printf("Wrote: %d\n", count); + } + mCount += count; + } + mOut->Close(); + return rv; + } + + nsPump(nsIInputStream* in, + nsIOutputStream* out) + : mIn(in), mOut(out), mCount(0) { + } + +private: + ~nsPump() {} + +protected: + nsCOMPtr mIn; + nsCOMPtr mOut; + PRUint32 mCount; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsPump, + nsIRunnable) + +nsresult +TestChainedPipes() +{ + nsresult rv; + printf("TestChainedPipes\n"); + + nsIInputStream* in1; + nsIOutputStream* out1; + rv = NS_NewPipe(&in1, &out1, 20, 1999); + if (NS_FAILED(rv)) return rv; + + nsIInputStream* in2; + nsIOutputStream* out2; + rv = NS_NewPipe(&in2, &out2, 200, 401); + if (NS_FAILED(rv)) return rv; + + nsIThread* thread; + nsPump* pump = new nsPump(in1, out2); + if (pump == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(pump); + + rv = NS_NewThread(&thread, pump, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + nsIThread* receiverThread; + nsReceiver* receiver = new nsReceiver(in2); + if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(receiver); + + rv = NS_NewThread(&receiverThread, receiver, 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) return rv; + + PRUint32 total = 0; + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + PRUint32 len = strlen(buf); + len = len * rand() / RAND_MAX; + len = PR_MAX(1, len); + rv = WriteAll(out1, buf, len, &writeCount); + if (NS_FAILED(rv)) return rv; + NS_ASSERTION(writeCount == len, "didn't write enough"); + total += writeCount; + + if (gTrace) + printf("wrote %d bytes: %s\n", writeCount, buf); + + PR_smprintf_free(buf); + } + printf("wrote total of %d bytes\n", total); + rv = out1->Close(); + if (NS_FAILED(rv)) return rv; + + thread->Join(); + receiverThread->Join(); + + NS_RELEASE(thread); + NS_RELEASE(pump); + NS_RELEASE(receiverThread); + NS_RELEASE(receiver); + NS_RELEASE(out2); + NS_RELEASE(in2); + NS_RELEASE(in1); + NS_RELEASE(out1); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +void +RunTests(PRUint32 segSize, PRUint32 segCount) +{ + nsresult rv; + nsIInputStream* in = 0; /* bird: initialize to quiet gcc. */ + nsIOutputStream* out = 0; /* ditto */ + PRUint32 bufSize; + + bufSize = segSize * segCount; + printf("Testing New Pipes: segment size %d buffer size %d\n", segSize, bufSize); + + printf("Testing long writes...\n"); + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + rv = TestPipe(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed"); + + printf("Testing short writes...\n"); + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + rv = TestShortWrites(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed"); +} + +//////////////////////////////////////////////////////////////////////////////// +#if 0 +void +TestSearch(const char* delim, PRUint32 segSize) +{ + nsresult rv; + // need at least 2 segments to test boundary conditions: + PRUint32 bufDataSize = segSize * 2; + PRUint32 bufSize = segSize * 2; + nsIInputStream* in; + nsIOutputStream* out; + rv = NS_NewPipe(&in, &out, segSize, bufSize); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewPipe failed"); + out->SetNonBlocking(PR_TRUE); + + PRUint32 i, j, amt; + PRUint32 delimLen = nsCRT::strlen(delim); + for (i = 0; i < bufDataSize; i++) { + // first fill the buffer + for (j = 0; j < i; j++) { + rv = out->Write("-", 1, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); + } + rv = out->Write(delim, delimLen, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv), "Write failed"); + if (i + amt < bufDataSize) { + for (j = i + amt; j < bufDataSize; j++) { + rv = out->Write("+", 1, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); + } + } + + // now search for the delimiter + PRBool found; + PRUint32 offset; + rv = in->Search(delim, PR_FALSE, &found, &offset); + NS_ASSERTION(NS_SUCCEEDED(rv), "Search failed"); + + // print the results + char* bufferContents = new char[bufDataSize + 1]; + rv = in->Read(bufferContents, bufDataSize, &amt); + NS_ASSERTION(NS_SUCCEEDED(rv) && amt == bufDataSize, "Read failed"); + bufferContents[bufDataSize] = '\0'; + printf("Buffer: %s\nDelim: %s %s offset: %d\n", bufferContents, + delim, (found ? "found" : "not found"), offset); + } + NS_RELEASE(in); + NS_RELEASE(out); +} +#endif +//////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG +extern NS_COM void +TestSegmentedBuffer(); +#endif + +int +main(int argc, char* argv[]) +{ + nsresult rv; + nsIServiceManager* servMgr; + + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + if (NS_FAILED(rv)) return rv; + + if (argc > 1 && nsCRT::strcmp(argv[1], "-trace") == 0) + gTrace = PR_TRUE; + +#ifdef DEBUG + TestSegmentedBuffer(); +#endif + +#if 0 // obsolete old implementation + rv = NS_NewPipe(&in, &out, 4096 * 4); + if (NS_FAILED(rv)) { + printf("NewPipe failed\n"); + return -1; + } + + rv = TestPipe(in, out); + NS_RELEASE(in); + NS_RELEASE(out); + if (NS_FAILED(rv)) { + printf("TestPipe failed\n"); + return -1; + } +#endif +#if 0 + TestSearch("foo", 8); + TestSearch("bar", 6); + TestSearch("baz", 2); +#endif + + rv = TestChainedPipes(); + NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed"); + RunTests(16, 1); + RunTests(4096, 16); + NS_RELEASE(servMgr); + rv = NS_ShutdownXPCOM( NULL ); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp b/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp new file mode 100644 index 00000000..8eaaaa77 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestServMgr.cpp @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "MyService.h" +#include "nsXPCOM.h" +#include "nsIServiceManager.h" +#include "nsIComponentManager.h" +#include + +static NS_DEFINE_CID(kIMyServiceCID, NS_IMYSERVICE_CID); + +//////////////////////////////////////////////////////////////////////////////// + +IMyService* myServ = NULL; + +nsresult +BeginTest(int testNumber) +{ + nsresult err; + NS_ASSERTION(myServ == NULL, "myServ not reset"); + err = nsServiceManager::GetService(kIMyServiceCID, NS_GET_IID(IMyService), + (nsISupports**)&myServ); + return err; +} + +nsresult +EndTest(int testNumber) +{ + nsresult err = NS_OK; + + if (myServ) { + err = myServ->Doit(); + if (err != NS_OK) return err; + + err = nsServiceManager::ReleaseService(kIMyServiceCID, myServ); + if (err != NS_OK) return err; + myServ = NULL; + } + + printf("test %d succeeded\n", testNumber); + return NS_OK; +} + +nsresult +SimpleTest(int testNumber) +{ + // This test just gets a service, uses it and releases it. + + nsresult err; + err = BeginTest(testNumber); + if (err != NS_OK) return err; + err = EndTest(testNumber); + return err; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +AsyncShutdown(int testNumber) +{ + nsresult err; + + // If the AsyncShutdown was truly asynchronous and happened on another + // thread, we'd have to protect all accesses to myServ throughout this + // code with a monitor. + + err = nsServiceManager::UnregisterService(kIMyServiceCID); + if (err == NS_ERROR_SERVICE_NOT_AVAILABLE) { + printf("async shutdown -- service not found\n"); + return NS_OK; + } + return err; +} + +nsresult +AsyncNoShutdownTest(int testNumber) +{ + // This test gets a service, and also gets an async request for shutdown, + // but the service doesn't get shut down because some other client (who's + // not participating in the async shutdown game as he should) is + // continuing to hang onto the service. This causes myServ variable to + // get set to NULL, but the service doesn't get unloaded right away as + // it should. + + nsresult err; + + err = BeginTest(testNumber); + if (err != NS_OK) return err; + + // Create some other user of kIMyServiceCID, preventing it from + // really going away: + IMyService* otherClient; + err = nsServiceManager::GetService(kIMyServiceCID, NS_GET_IID(IMyService), + (nsISupports**)&otherClient); + if (err != NS_OK) return err; + + err = AsyncShutdown(testNumber); + if (err != NS_OK) return err; + err = EndTest(testNumber); + + // Finally, release the other client. + err = nsServiceManager::ReleaseService(kIMyServiceCID, otherClient); + + return err; +} + +//////////////////////////////////////////////////////////////////////////////// +int +main(void) +{ + nsresult err; + int testNumber = 0; + + err = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(err)) { + printf("NS_InitXPCOM2 failed\n"); + return -1; + } + + err = SimpleTest(++testNumber); + if (err != NS_OK) + goto error; + + err = AsyncNoShutdownTest(++testNumber); + if (err != NS_OK) + goto error; + + AsyncShutdown(++testNumber); + + printf("there was great success\n"); + return 0; + + error: + printf("test %d failed\n", testNumber); + return -1; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp b/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp new file mode 100644 index 00000000..259a7b31 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestShutdown.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" + +// Gee this seems simple! It's for testing for memory leaks with Purify. + +void main(int argc, char* argv[]) +{ + nsresult rv; + nsIServiceManager* servMgr; + rv = NS_InitXPCOM2(&servMgr, NULL, NULL); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_InitXPCOM failed"); + + // try loading a component and releasing it to see if it leaks + if (argc > 1 && argv[1] != nsnull) { + char* cidStr = argv[1]; + nsISupports* obj = nsnull; + if (cidStr[0] == '{') { + nsCID cid; + cid.Parse(cidStr); + rv = nsComponentManager::CreateInstance(cid, nsnull, + NS_GET_IID(nsISupports), + (void**)&obj); + } + else { + // contractID case: + rv = nsComponentManager::CreateInstance(cidStr, nsnull, + NS_GET_IID(nsISupports), + (void**)&obj); + } + if (NS_SUCCEEDED(rv)) { + printf("Successfully created %s\n", cidStr); + NS_RELEASE(obj); + } + else { + printf("Failed to create %s (%x)\n", cidStr, rv); + } + } + + rv = NS_ShutdownXPCOM(servMgr); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp b/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp new file mode 100644 index 00000000..76187edd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestStackCrawl.cpp @@ -0,0 +1,11 @@ +#include + +#include "nsISupportsUtils.h" +#include "nsTraceRefCntImpl.h" + +int main(int argc, char* argv[]) +{ + nsTraceRefcntImpl::WalkTheStack(stdout); + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp b/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp new file mode 100644 index 00000000..b1b725a4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestStrings.cpp @@ -0,0 +1,643 @@ +/* vim:set ts=2 sw=2 et cindent: */ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" + +void test_assign_helper(const nsACString& in, nsACString &_retval) + { + _retval = in; + } + +PRBool test_assign() + { + nsCString result; + test_assign_helper(NS_LITERAL_CSTRING("a") + NS_LITERAL_CSTRING("b"), result); + PRBool r = strcmp(result.get(), "ab") == 0; + if (!r) + printf("[result=%s]\n", result.get()); + return r; + } + +PRBool test_assign_c() + { + nsCString c; c.Assign('c'); + PRBool r = strcmp(c.get(), "c") == 0; + if (!r) + printf("[result=%s]\n", c.get()); + return r; + } + +PRBool test1() + { + NS_NAMED_LITERAL_STRING(empty, ""); + const nsAString& aStr = empty; + + nsAutoString buf(aStr); + + PRInt32 n = buf.FindChar(','); + + n = buf.Length(); + + buf.Cut(0, n + 1); + n = buf.FindChar(','); + + if (n != kNotFound) + printf("n=%d\n", n); + + return n == kNotFound; + } + +PRBool test2() + { + nsCString data("hello world"); + const nsACString& aStr = data; + + nsCString temp(aStr); + temp.Cut(0, 6); + + PRBool r = strcmp(temp.get(), "world") == 0; + if (!r) + printf("[temp=%s]\n", temp.get()); + return r; + } + +PRBool test_find() + { + nsCString src(""); + + PRInt32 i = src.Find("DOCTYPE", PR_TRUE, 2, 1); + if (i == 2) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind() + { + const char text[] = ""; + const char term[] = "bLaH"; + nsCString src(text); + PRInt32 i; + + i = src.RFind(term, PR_TRUE, 3, -1); + if (i != kNotFound) + { + printf("unexpected result searching from offset=3, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, -1, -1); + if (i != 20) + { + printf("unexpected result searching from offset=-1, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, 13, -1); + if (i != 10) + { + printf("unexpected result searching from offset=13, i=%d\n", i); + return PR_FALSE; + } + + i = src.RFind(term, PR_TRUE, 22, 3); + if (i != 20) + { + printf("unexpected result searching from offset=22, i=%d\n", i); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_rfind_2() + { + const char text[] = ""; + nsCString src(text); + PRInt32 i = src.RFind("TYPE", PR_FALSE, 5, -1); + if (i == 5) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind_3() + { + const char text[] = "urn:mozilla:locale:en-US:necko"; + nsCAutoString value(text); + PRInt32 i = value.RFind(":"); + if (i == 24) + return PR_TRUE; + + printf("i=%d\n", i); + return PR_FALSE; + } + +PRBool test_rfind_4() + { + nsCString value("a.msf"); + PRInt32 i = value.RFind(".msf"); + if (i != 1) + { + printf("i=%d\n", i); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_distance() + { + const char text[] = "abc-xyz"; + nsCString s(text); + nsCString::const_iterator begin, end; + s.BeginReading(begin); + s.EndReading(end); + size_t d = Distance(begin, end); + PRBool r = (d == sizeof(text)-1); + if (!r) + printf("d=%zu\n", d); + return r; + } + +PRBool test_length() + { + const char text[] = "abc-xyz"; + nsCString s(text); + size_t d = s.Length(); + PRBool r = (d == sizeof(text)-1); + if (!r) + printf("d=%zu\n", d); + return r; + } + +PRBool test_trim() + { + const char text[] = " a\t $ "; + const char set[] = " \t$"; + + nsCString s(text); + s.Trim(set); + PRBool r = strcmp(s.get(), "a") == 0; + if (!r) + printf("[s=%s]\n", s.get()); + return r; + } + +PRBool test_replace_substr() + { + const char text[] = "abc-ppp-qqq-ppp-xyz"; + nsCString s(text); + s.ReplaceSubstring("ppp", "www"); + PRBool r = strcmp(s.get(), "abc-www-qqq-www-xyz") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foobar"); + s.ReplaceSubstring("foo", "bar"); + s.ReplaceSubstring("bar", ""); + r = strcmp(s.get(), "") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foofoofoo"); + s.ReplaceSubstring("foo", "foo"); + r = strcmp(s.get(), "foofoofoo") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + s.Assign("foofoofoo"); + s.ReplaceSubstring("of", "fo"); + r = strcmp(s.get(), "fofoofooo") == 0; + if (!r) + { + printf("[s=%s]\n", s.get()); + return PR_FALSE; + } + + return PR_TRUE; + } + +PRBool test_replace_substr_2() + { + const char *oldName = nsnull; + const char *newName = "user"; + nsString acctName; acctName.AssignLiteral("forums.foo.com"); + nsAutoString newAcctName, oldVal, newVal; + oldVal.AssignWithConversion(oldName); + newVal.AssignWithConversion(newName); + newAcctName.Assign(acctName); + + // here, oldVal is empty. we are testing that this function + // does not hang. see bug 235355. + newAcctName.ReplaceSubstring(oldVal, newVal); + + // we expect that newAcctName will be unchanged. + if (!newAcctName.Equals(acctName)) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_strip_ws() + { + const char text[] = " a $ "; + nsCString s(text); + s.StripWhitespace(); + PRBool r = strcmp(s.get(), "a$") == 0; + if (!r) + printf("[s=%s]\n", s.get()); + return r; + } + +PRBool test_equals_ic() + { + nsCString s; + PRBool r = s.LowerCaseEqualsLiteral("view-source"); + if (r) + printf("[r=%d]\n", r); + return !r; + } + +PRBool test_fixed_string() + { + char buf[256] = "hello world"; + + nsFixedCString s(buf, sizeof(buf)); + + if (s.Length() != strlen(buf)) + return PR_FALSE; + + if (strcmp(s.get(), buf) != 0) + return PR_FALSE; + + s.Assign("foopy doopy doo"); + if (s.get() != buf) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_concat() + { + nsCString bar("bar"); + const nsACString& barRef = bar; + + const nsPromiseFlatCString& result = + PromiseFlatCString(NS_LITERAL_CSTRING("foo") + + NS_LITERAL_CSTRING(",") + + barRef); + if (strcmp(result.get(), "foo,bar") == 0) + return PR_TRUE; + + printf("[result=%s]\n", result.get()); + return PR_FALSE; + } + +PRBool test_concat_2() + { + nsCString fieldTextStr("xyz"); + nsCString text("text"); + const nsACString& aText = text; + + nsCAutoString result( fieldTextStr + aText ); + + if (strcmp(result.get(), "xyztext") == 0) + return PR_TRUE; + + printf("[result=%s]\n", result.get()); + return PR_FALSE; + } + +#if 0 +PRBool test_concat_3() + { + nsCString a("a"), b("b"); + + // THIS DOES NOT COMPILE + const nsACString& r = a + b; + + return PR_TRUE; + } +#endif + +PRBool test_xpidl_string() + { + nsXPIDLCString a, b; + a = b; + if (a != b) + return PR_FALSE; + + a.Adopt(0); + if (a != b) + return PR_FALSE; + + a.Append("foopy"); + a.Assign(b); + if (a != b) + return PR_FALSE; + + a.Insert("", 0); + a.Assign(b); + if (a != b) + return PR_FALSE; + + const char text[] = "hello world"; + *getter_Copies(a) = nsCRT::strdup(text); + if (strcmp(a, text) != 0) + return PR_FALSE; + + b = a; + if (strcmp(a, b) != 0) + return PR_FALSE; + + a.Adopt(0); + nsACString::const_iterator begin, end; + a.BeginReading(begin); + a.EndReading(end); + char *r = ToNewCString(Substring(begin, end)); + if (strcmp(r, "") != 0) + return PR_FALSE; + nsMemory::Free(r); + + a.Adopt(0); + if (a != (const char*) 0) + return PR_FALSE; + + /* + PRInt32 index = a.FindCharInSet("xyz"); + if (index != kNotFound) + return PR_FALSE; + */ + + return PR_TRUE; + } + +PRBool test_empty_assign() + { + nsCString a; + a.AssignLiteral(""); + + a.AppendLiteral(""); + + nsCString b; + b.SetCapacity(0); + return PR_TRUE; + } + +PRBool test_set_length() + { + const char kText[] = "Default Plugin"; + nsCString buf; + buf.SetCapacity(sizeof(kText)-1); + buf.Assign(kText); + buf.SetLength(sizeof(kText)-1); + if (strcmp(buf.get(), kText) != 0) + return PR_FALSE; + return PR_TRUE; + } + +PRBool test_substring() + { + nsCString super("hello world"), sub("hello"); + + // this tests that |super| starts with |sub|, + + PRBool r = sub.Equals(StringHead(super, sub.Length())); + if (!r) + return PR_FALSE; + + // and verifies that |sub| does not start with |super|. + + r = super.Equals(StringHead(sub, super.Length())); + if (r) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_appendint64() + { + nsCString str; + + PRInt64 max = LL_MaxInt(); + static const char max_expected[] = "9223372036854775807"; + PRInt64 min = LL_MinInt(); + static const char min_expected[] = "-9223372036854775808"; + static const char min_expected_oct[] = "1000000000000000000000"; + PRInt64 maxint_plus1 = LL_INIT(1, 0); + static const char maxint_plus1_expected[] = "4294967296"; + static const char maxint_plus1_expected_x[] = "100000000"; + + str.AppendInt(max); + + if (!str.Equals(max_expected)) { + fprintf(stderr, "Error appending LL_MaxInt(): Got %s\n", str.get()); + return PR_FALSE; + } + + str.Truncate(); + str.AppendInt(min); + if (!str.Equals(min_expected)) { + fprintf(stderr, "Error appending LL_MinInt(): Got %s\n", str.get()); + return PR_FALSE; + } + str.Truncate(); + str.AppendInt(min, 8); + if (!str.Equals(min_expected_oct)) { + fprintf(stderr, "Error appending LL_MinInt() (oct): Got %s\n", str.get()); + return PR_FALSE; + } + + + str.Truncate(); + str.AppendInt(maxint_plus1); + if (!str.Equals(maxint_plus1_expected)) { + fprintf(stderr, "Error appending PR_UINT32_MAX + 1: Got %s\n", str.get()); + return PR_FALSE; + } + str.Truncate(); + str.AppendInt(maxint_plus1, 16); + if (!str.Equals(maxint_plus1_expected_x)) { + fprintf(stderr, "Error appending PR_UINT32_MAX + 1 (hex): Got %s\n", str.get()); + return PR_FALSE; + } + + + return PR_TRUE; + } + +PRBool test_findcharinset() + { + nsCString buf("hello, how are you?"); + + PRInt32 index = buf.FindCharInSet(",?", 5); + if (index != 5) + return PR_FALSE; + + index = buf.FindCharInSet("helo", 0); + if (index != 0) + return PR_FALSE; + + index = buf.FindCharInSet("z?", 6); + if (index != (PRInt32) buf.Length()-1) + return PR_FALSE; + + return PR_TRUE; + } + +PRBool test_rfindcharinset() + { + nsCString buf("hello, how are you?"); + + PRInt32 index = buf.RFindCharInSet(",?", 5); + if (index != 5) + return PR_FALSE; + + index = buf.RFindCharInSet("helo", 0); + if (index != 0) + return PR_FALSE; + + index = buf.RFindCharInSet("z?", 6); + if (index != kNotFound) + return PR_FALSE; + + index = buf.RFindCharInSet("l", 5); + if (index != 3) + return PR_FALSE; + + buf.Assign("abcdefghijkabc"); + + index = buf.RFindCharInSet("ab"); + if (index != 12) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 11); + if (index != 11) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 10); + if (index != 1) + return PR_FALSE; + + index = buf.RFindCharInSet("ab", 0); + if (index != 0) + return PR_FALSE; + + index = buf.RFindCharInSet("cd", 1); + if (index != kNotFound) + return PR_FALSE; + + index = buf.RFindCharInSet("h"); + if (index != 7) + return PR_FALSE; + + return PR_TRUE; + } + +//---- + +typedef PRBool (*TestFunc)(); + +static const struct Test + { + const char* name; + TestFunc func; + } +tests[] = + { + { "test_assign", test_assign }, + { "test_assign_c", test_assign_c }, + { "test1", test1 }, + { "test2", test2 }, + { "test_find", test_find }, + { "test_rfind", test_rfind }, + { "test_rfind_2", test_rfind_2 }, + { "test_rfind_3", test_rfind_3 }, + { "test_rfind_4", test_rfind_4 }, + { "test_distance", test_distance }, + { "test_length", test_length }, + { "test_trim", test_trim }, + { "test_replace_substr", test_replace_substr }, + { "test_replace_substr_2", test_replace_substr_2 }, + { "test_strip_ws", test_strip_ws }, + { "test_equals_ic", test_equals_ic }, + { "test_fixed_string", test_fixed_string }, + { "test_concat", test_concat }, + { "test_concat_2", test_concat_2 }, + { "test_xpidl_string", test_xpidl_string }, + { "test_empty_assign", test_empty_assign }, + { "test_set_length", test_set_length }, + { "test_substring", test_substring }, + { "test_appendint64", test_appendint64 }, + { "test_findcharinset", test_findcharinset }, + { "test_rfindcharinset", test_rfindcharinset }, + { nsnull, nsnull } + }; + +//---- + +int main(int argc, char **argv) + { + int count = 1; + if (argc > 1) + count = atoi(argv[1]); + + while (count--) + { + for (const Test* t = tests; t->name != nsnull; ++t) + { + printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE <--"); + } + } + + return 0; + } diff --git a/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp b/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp new file mode 100644 index 00000000..10025a05 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestThreads.cpp @@ -0,0 +1,280 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIThread.h" +#include "nsIRunnable.h" +#include +#include +#include "nspr.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" + +class nsRunner : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsCOMPtr thread; + nsresult rv = nsIThread::GetCurrent(getter_AddRefs(thread)); + if (NS_FAILED(rv)) { + printf("failed to get current thread\n"); + return rv; + } + printf("running %d on thread %p\n", mNum, (void *)thread.get()); + + // if we don't do something slow, we'll never see the other + // worker threads run + PR_Sleep(PR_MillisecondsToInterval(100)); + + return rv; + } + + nsRunner(int num) : mNum(num) { + } + +protected: + int mNum; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunner, nsIRunnable) + +nsresult +TestThreads() +{ + nsresult rv; + + nsCOMPtr runner; + rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(0), 0, PR_JOINABLE_THREAD); + if (NS_FAILED(rv)) { + printf("failed to create thread\n"); + return rv; + } + + nsCOMPtr thread; + rv = nsIThread::GetCurrent(getter_AddRefs(thread)); + if (NS_FAILED(rv)) { + printf("failed to get current thread\n"); + return rv; + } + + PRThreadScope scope; + rv = runner->GetScope(&scope); + if (NS_FAILED(rv)) { + printf("runner already exited\n"); + } + + rv = runner->Join(); // wait for the runner to die before quitting + if (NS_FAILED(rv)) { + printf("join failed\n"); + } + + rv = runner->GetScope(&scope); // this should fail after Join + if (NS_SUCCEEDED(rv)) { + printf("get scope failed\n"); + } + + rv = runner->Interrupt(); // this should fail after Join + if (NS_SUCCEEDED(rv)) { + printf("interrupt failed\n"); + } + + //////////////////////////////////////////////////////////////////////////// + // try an unjoinable thread + rv = NS_NewThread(getter_AddRefs(runner), new nsRunner(1)); + if (NS_FAILED(rv)) { + printf("failed to create thread\n"); + return rv; + } + + rv = runner->Join(); // wait for the runner to die before quitting + if (NS_SUCCEEDED(rv)) { + printf("shouldn't have been able to join an unjoinable thread\n"); + } + + PR_Sleep(PR_MillisecondsToInterval(100)); // hopefully the runner will quit here + + return NS_OK; +} + +class nsStressRunner : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + NS_ASSERTION(!mWasRun, "run twice!"); + mWasRun = PR_TRUE; + PR_Sleep(1); + if (!PR_AtomicDecrement(&gNum)) { + printf(" last thread was %d\n", mNum); + } + return NS_OK; + } + + nsStressRunner(int num) : mNum(num), mWasRun(PR_FALSE) { + PR_AtomicIncrement(&gNum); + } + + static PRInt32 GetGlobalCount() {return gNum;} + +private: + ~nsStressRunner() { + NS_ASSERTION(mWasRun, "never run!"); + } + +protected: + static PRInt32 gNum; + PRInt32 mNum; + PRBool mWasRun; +}; + +PRInt32 nsStressRunner::gNum = 0; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsStressRunner, nsIRunnable) + +static int Stress(int loops, int threads) +{ + + for (int i = 0; i < loops; i++) { + printf("Loop %d of %d\n", i+1, loops); + + int k; + nsIThread** array = new nsIThread*[threads]; + NS_ASSERTION(array, "out of memory"); + + NS_ASSERTION(!nsStressRunner::GetGlobalCount(), "bad count of runnables"); + + for (k = 0; k < threads; k++) { + nsCOMPtr t; + nsresult rv = NS_NewThread(getter_AddRefs(t), + new nsStressRunner(k), + 0, PR_JOINABLE_THREAD); + NS_ASSERTION(NS_SUCCEEDED(rv), "can't create thread"); + NS_ADDREF(array[k] = t); + } + + for (k = threads-1; k >= 0; k--) { + array[k]->Join(); + NS_RELEASE(array[k]); + } + delete [] array; + } + return 0; +} + +PR_STATIC_CALLBACK(void) threadProc(void *arg) +{ + // printf(" running thread %d\n", (int) arg); + PR_Sleep(1); + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(PR_GetCurrentThread())); +} + +static int StressNSPR(int loops, int threads) +{ + + for (int i = 0; i < loops; i++) { + printf("Loop %d of %d\n", i+1, loops); + + int k; + PRThread** array = new PRThread*[threads]; + PR_ASSERT(array); + + for (k = 0; k < threads; k++) { + array[k] = PR_CreateThread(PR_USER_THREAD, + threadProc, (void*)(uintptr_t)k, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + PR_ASSERT(array[k]); + } + + for (k = 0; k < threads; k++) { + PR_ASSERT(PR_JOINABLE_THREAD == PR_GetThreadState(array[k])); + } + + for (k = threads-1; k >= 0; k--) { + PR_JoinThread(array[k]); + } + delete [] array; + } + return 0; +} + + +int +main(int argc, char** argv) +{ + int retval = 0; + nsresult rv; + + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + + if (argc > 1 && !strcmp(argv[1], "-stress")) { + int loops; + int threads; + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { + printf("To use -stress you must pass loop count and thread count...\n" + " TestThreads -stress -1000 -50\n"); + } else { + printf("Running stress test with %d loops of %d threads each\n", + loops, threads); + retval = Stress(loops, threads); + } + } else if (argc > 1 && !strcmp(argv[1], "-stress-nspr")) { + int loops; + int threads; + if (argc != 4 || *argv[2] != '-' || *argv[3] != '-' || + !(loops = atoi(argv[2]+1)) || !(threads = atoi(argv[3]+1))) { + printf("To use -stress-nspr you must pass loop count and thread count...\n" + " TestThreads -stress -1000 -50\n"); + } else { + printf("Running stress test with %d loops of %d threads each\n", + loops, threads); + retval = StressNSPR(loops, threads); + } + } else { + rv = TestThreads(); + if (NS_FAILED(rv)) return -1; + } + + rv = NS_ShutdownXPCOM(nsnull); + if (NS_FAILED(rv)) return -1; + return retval; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp b/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp new file mode 100644 index 00000000..956f179f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestVoidBTree.cpp @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include "nsVoidBTree.h" +#include "nsVoidArray.h" + +#define COUNT 1024 +#define POINTER(i) NS_REINTERPRET_CAST(void*, 4 + 4 * (i)) + +static PRBool +Equal(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + if (aControl.Count() != aTest.Count()) { + printf("counts not equal; "); + return PR_FALSE; + } + + for (PRInt32 i = aControl.Count() - 1; i >= 0; --i) { + if (aControl[i] != aTest[i]) { + printf("element %d differs; ", i); + return PR_FALSE; + } + } + + return PR_TRUE; +} + + +static void +CheckForwardEnumeration(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + PRInt32 index = 0; + + nsVoidBTree::ConstIterator last = aTest.Last(); + for (nsVoidBTree::ConstIterator element = aTest.First(); element != last; ++element, ++index) { + if (*element != aControl[index]) { + printf("failed forward enumeration\n"); + exit(-1); + } + } + + if (index != aControl.Count()) { + printf("erratic termination during forward enumeration\n"); + exit(-1); + } +} + +static void +CheckBackwardEnumeration(const nsVoidArray& aControl, const nsVoidBTree& aTest) +{ + PRInt32 index = aControl.Count(); + nsVoidBTree::ConstIterator first = aTest.First(); + nsVoidBTree::ConstIterator element = aTest.Last(); + + if (first != element) { + do { + if (*--element != aControl[--index]) { + printf("failed backward enumeration\n"); + exit(-1); + } + } while (element != first); + } + + if (index != 0) { + printf("erratic termination during backward enumeration\n"); + exit(-1); + } +} + +int main(int argc, char* argv[]) +{ + nsVoidBTree btree; + + PRInt32 i; + + //---------------------------------------- + // Tail fill + for (i = 0; i < COUNT; ++i) + btree.InsertElementAt(NS_REINTERPRET_CAST(void*, POINTER(i)), i); + + for (i = 0; i < COUNT; ++i) { + if (btree[i] != POINTER(i)) { + printf("tail fill failed\n"); + return -1; + } + } + + printf("tail fill succeeded\n"); + + //---------------------------------------- + // Tail empty + for (i = COUNT - 1; i >= 0; --i) + btree.RemoveElementAt(i); + + if (btree.Count() != 0) { + printf("tail empty failed\n"); + return -1; + } + + printf("tail empty succeeded\n"); + + // N.B. no intervening Clear() to verify that we handle the re-use + // case. + + //---------------------------------------- + // Front fill + for (i = 0; i < COUNT; ++i) + btree.InsertElementAt(POINTER(i), 0); + + for (i = 0; i < COUNT; ++i) { + if (btree[COUNT - (i + 1)] != POINTER(i)) { + printf("simple front fill failed\n"); + return -1; + } + } + + printf("front fill succeeded\n"); + + //---------------------------------------- + // Front empty + for (i = COUNT - 1; i >= 0; --i) + btree.RemoveElementAt(0); + + if (btree.Count() != 0) { + printf("front empty failed\n"); + return -1; + } + + printf("front empty succeeded\n"); + fflush(stdout); + + //---------------------------------------- + // Test boundary conditions with small btree + + { + printf("small btree boundary conditions "); + fflush(stdout); + + nsVoidArray control; + btree.Clear(); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.AppendElement(POINTER(0)); + control.AppendElement(POINTER(0)); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.AppendElement(POINTER(1)); + control.AppendElement(POINTER(1)); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + btree.RemoveElementAt(0); + btree.RemoveElementAt(0); + control.RemoveElementAt(0); + control.RemoveElementAt(0); + + CheckBackwardEnumeration(control, btree); + CheckForwardEnumeration(control, btree); + + printf("succeeded\n"); + } + + //---------------------------------------- + // Iterator + { + nsVoidArray control; + btree.Clear(); + + // Fill + for (i = 0; i < COUNT; ++i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.InsertElementAt(POINTER(i), slot); + control.InsertElementAt(POINTER(i), slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + + for (nsVoidBTree::Iterator m = btree.First(); m != btree.Last(); ++m) { + nsVoidBTree::Iterator n; + for (n = m, ++n; n != btree.Last(); ++n) { + if (*m > *n) { + void* tmp = *m; + *m = *n; + *n = tmp; + } + } + } + + nsVoidBTree::Iterator el; + for (el = btree.First(), i = 0; el != btree.Last(); ++el, ++i) { + if (*el != POINTER(i)) { + printf("bubble sort failed\n"); + return -1; + } + } + + printf("iteration succeeded\n"); + } + + //---------------------------------------- + // Random hammering + + printf("random fill/empty: "); + + for (PRInt32 iter = 10; iter >= 1; --iter) { + printf("%d ", iter); + fflush(stdout); + + nsVoidArray control; + btree.Clear(); + + // Fill + for (i = 0; i < COUNT; ++i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.InsertElementAt(POINTER(i), slot); + control.InsertElementAt(POINTER(i), slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + + // IndexOf + for (i = 0; i < COUNT; ++i) { + void* element = control[i]; + if (btree.IndexOf(element) != i) { + printf("failed IndexOf at %d\n", i); + return -1; + } + } + + // Backward enumeration + CheckBackwardEnumeration(control, btree); + + // Forward enumeration + CheckForwardEnumeration(control, btree); + + // Empty + for (i = COUNT - 1; i >= 0; --i) { + PRInt32 slot = i ? rand() % i : 0; + + btree.RemoveElementAt(slot); + control.RemoveElementAt(slot); + + if (! Equal(control, btree)) { + printf("failed\n"); + return -1; + } + } + } + + printf("succeeded\n"); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp b/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp new file mode 100644 index 00000000..f2802e1f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/TestXPIDLString.cpp @@ -0,0 +1,18 @@ +#include "nsString.h" +#include "nsReadableUtils.h" +#include "nsXPIDLString.h" + +static void +nsXPIDLStringTest_Value(PRUnichar** aResult) +{ + *aResult = ToNewUnicode(NS_LITERAL_STRING("Hello, World")); +} + +int +main(int argc, char* argv[]) +{ + nsXPIDLString s1; + nsXPIDLStringTest_Value(getter_Copies(s1)); + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in new file mode 100644 index 00000000..c17318c0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/Makefile.in @@ -0,0 +1,61 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +IS_COMPONENT = 1 +MODULE_NAME = nsTestDynamicModule +MODULE = xpcom +LIBRARY_NAME = testdynamic +SHORT_LIBNAME = tdynamic + +CPPSRCS = TestDynamic.cpp + +include $(topsrcdir)/config/config.mk + +LOCAL_INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../public + +include $(topsrcdir)/config/rules.mk + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp b/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp new file mode 100644 index 00000000..a27d8ea9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/TestDynamic.cpp @@ -0,0 +1,76 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Suresh Duddi + * Christopher Blizzard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include "TestFactory.h" +#include "nsIGenericFactory.h" + +/** + * ITestClass implementation + */ + +class TestDynamicClassImpl: public ITestClass { + NS_DECL_ISUPPORTS + + TestDynamicClassImpl() { + } + void Test(); +}; + +NS_IMPL_ISUPPORTS1(TestDynamicClassImpl, ITestClass) + +void TestDynamicClassImpl::Test() { + printf("hello, dynamic world!\n"); +} + +/** + * Generic Module + */ + +NS_GENERIC_FACTORY_CONSTRUCTOR(TestDynamicClassImpl) + +static const nsModuleComponentInfo components[] = +{ + { "Test Dynamic", NS_TESTLOADEDFACTORY_CID, NS_TESTLOADEDFACTORY_CONTRACTID, + TestDynamicClassImplConstructor + } +}; + +NS_IMPL_NSGETMODULE(nsTestDynamicModule, components) + diff --git a/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order b/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order new file mode 100644 index 00000000..bf181a81 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/dynamic/win32.order @@ -0,0 +1 @@ +_NSGetModule ; 1 diff --git a/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp b/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp new file mode 100644 index 00000000..a5f3551d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/nsIFileEnumerator.cpp @@ -0,0 +1,95 @@ +#include "nsILocalFile.h" +#include "nsDependentString.h" +#include "nsString.h" + +#include +#include "nsIComponentRegistrar.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsMemory.h" +#include "nsXPIDLString.h" +#include "nsISimpleEnumerator.h" + + +PRBool LoopInDir(nsILocalFile* file) +{ + nsresult rv; + nsCOMPtr entries; + rv = file->GetDirectoryEntries(getter_AddRefs(entries)); + if(NS_FAILED(rv) || !entries) + return PR_FALSE; + + PRBool hasMore; + while(NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) + { + nsCOMPtr sup; + entries->GetNext(getter_AddRefs(sup)); + if(!sup) + return PR_FALSE; + + nsCOMPtr file = do_QueryInterface(sup); + if(!file) + return PR_FALSE; + + nsCAutoString name; + if(NS_FAILED(file->GetNativeLeafName(name))) + return PR_FALSE; + + PRBool isDir; + printf("%s\n", name.get()); + rv = file->IsDirectory(&isDir); + if (NS_FAILED(rv)) + { + printf("IsDirectory Failed!!!\n"); + return PR_FALSE; + } + + if (isDir == PR_TRUE) + { + nsCOMPtr lfile = do_QueryInterface(file); + LoopInDir(lfile); + } + } + return PR_TRUE; +} + + +int +main(int argc, char* argv[]) +{ + nsresult rv; + { + nsCOMPtr topDir; + + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if (NS_FAILED(rv)) return -1; + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + if (registrar) + registrar->AutoRegister(nsnull); + + if (argc > 1 && argv[1] != nsnull) + { + char* pathStr = argv[1]; + NS_NewNativeLocalFile(nsDependentCString(pathStr), PR_FALSE, getter_AddRefs(topDir)); + } + + if (!topDir) + { + printf("No Top Dir\n"); + return -1; + } + PRInt32 startTime = PR_IntervalNow(); + + LoopInDir(topDir); + + PRInt32 endTime = PR_IntervalNow(); + + printf("\nTime: %d\n", PR_IntervalToMilliseconds(endTime - startTime)); + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + rv = NS_ShutdownXPCOM(nsnull); + NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp b/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp new file mode 100644 index 00000000..1dd2cd54 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/nsIFileTest.cpp @@ -0,0 +1,475 @@ +#include "nsILocalFile.h" +#if 0 /* too new */ +#include "nsStringGlue.h" +#else +#include "nsString.h" +#endif + +#include +#include "nsXPCOM.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsIMemory.h" + +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" + +void Passed(); +void Failed(const char* explanation = nsnull); +void Inspect(); +void Banner(const char* bannerString); + +void VerifyResult(nsresult rv) +{ + if (NS_FAILED(rv)) + { + Failed("rv failed"); + printf("rv = %d\n", rv); + } +} +//---------------------------------------------------------------------------- +void Banner(const char* bannerString) +//---------------------------------------------------------------------------- +{ + printf("---------------------------\n"); + printf("%s\n", bannerString); + printf("---------------------------\n"); +} + +//---------------------------------------------------------------------------- +void Passed() +//---------------------------------------------------------------------------- +{ + printf("Test passed."); +} + +//---------------------------------------------------------------------------- +void Failed(const char* explanation) +//---------------------------------------------------------------------------- +{ + printf("ERROR : Test failed.\n"); + printf("REASON: %s.\n", explanation); +} + +//---------------------------------------------------------------------------- +void Inspect() +//---------------------------------------------------------------------------- +{ + printf("^^^^^^^^^^ PLEASE INSPECT OUTPUT FOR ERRORS\n"); +} + +void GetPaths(nsILocalFile* file) +{ + nsresult rv; + nsCAutoString pathName; + + printf("Getting Path\n"); + + rv = file->GetNativePath(pathName); + VerifyResult(rv); + + printf("filepath: %s\n", pathName.get()); +} + +void InitTest(const char* creationPath, const char* appendPath) +{ + nsILocalFile* file = nsnull; + nsresult rv = CallCreateInstance(NS_LOCAL_FILE_CONTRACTID, &file); + + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + nsCAutoString leafName; + + Banner("InitWithPath"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Getting Filename\n"); + rv = file->GetNativeLeafName(leafName); + printf(" %s\n", leafName.get()); + VerifyResult(rv); + + printf("Appending %s \n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Getting Filename\n"); + rv = file->GetNativeLeafName(leafName); + printf(" %s\n", leafName.get()); + VerifyResult(rv); + + GetPaths(file); + + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + NS_RELEASE(file); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); +} + + +void CreationTest(const char* creationPath, const char* appendPath, + PRInt32 whatToCreate, PRInt32 perm) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Creation Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendRelativeNativePath(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + + rv = file->Create(whatToCreate, perm); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + + if (!exists) + { + Failed("Did not create file system object!"); + return; + } + +} + +void CreateUniqueTest(const char* creationPath, const char* appendPath, + PRInt32 whatToCreate, PRInt32 perm) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Creation Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existence\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + + rv = file->CreateUnique(whatToCreate, perm); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + + if (!exists) + { + Failed("Did not create file system object!"); + return; + } + +} + + +void +CopyTest(const char *testFile, const char *targetDir) +{ + printf("start copy test\n"); + + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testFile)); + VerifyResult(rv); + + nsCOMPtr dir = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!dir)) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = dir->InitWithNativePath(nsDependentCString(targetDir)); + VerifyResult(rv); + + rv = file->CopyTo(dir, EmptyString()); + VerifyResult(rv); + + printf("end copy test\n"); +} + +void +DeletionTest(const char* creationPath, const char* appendPath, PRBool recursive) +{ + nsresult rv; + nsCOMPtr file = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + + if (NS_FAILED(rv) || (!file)) + { + printf("create nsILocalFile failed\n"); + return; + } + + Banner("Deletion Test"); + printf("creationPath == %s\nappendPath == %s\n", creationPath, appendPath); + + rv = file->InitWithNativePath(nsDependentCString(creationPath)); + VerifyResult(rv); + + printf("Appending %s\n", appendPath); + rv = file->AppendNative(nsDependentCString(appendPath)); + VerifyResult(rv); + + printf("Check For Existance\n"); + + PRBool exists; + file->Exists(&exists); + + if (exists) + printf("Yup!\n"); + else + printf("no.\n"); + + rv = file->Remove(recursive); + VerifyResult(rv); + + rv = file->Exists(&exists); + VerifyResult(rv); + + if (exists) + { + Failed("Did not create delete system object!"); + return; + } + +} + +void +MoveTest(const char *testFile, const char *targetDir) +{ + Banner("Move Test"); + + printf("start move test\n"); + + nsresult rv; + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testFile)); + VerifyResult(rv); + + nsCOMPtr dir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!dir) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = dir->InitWithNativePath(nsDependentCString(targetDir)); + VerifyResult(rv); + + rv = file->MoveToNative(dir, NS_LITERAL_CSTRING("newtemp")); + VerifyResult(rv); + if (NS_FAILED(rv)) + { + printf("MoveToNative() test Failed.\n"); + } + printf("end move test\n"); +} + +// move up the number of directories in moveUpCount, then append "foo/bar" +void +NormalizeTest(const char *testPath, int moveUpCount, + const char *expected) +{ + Banner("Normalize Test"); + + nsresult rv; + nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!file) + { + printf("create nsILocalFile failed\n"); + return; + } + + rv = file->InitWithNativePath(nsDependentCString(testPath)); + VerifyResult(rv); + + nsCOMPtr parent; + nsAutoString path; + for (int i=0; i < moveUpCount; i++) + { + rv = file->GetParent(getter_AddRefs(parent)); + VerifyResult(rv); + rv = parent->GetPath(path); + VerifyResult(rv); + rv = file->InitWithPath(path); + VerifyResult(rv); + } + + if (!parent) { + printf("Getting parent failed!\n"); + return; + } + + rv = parent->Append(NS_LITERAL_STRING("foo")); + VerifyResult(rv); + rv = parent->Append(NS_LITERAL_STRING("bar")); + VerifyResult(rv); + + rv = parent->Normalize(); + VerifyResult(rv); + + nsCAutoString newPath; + rv = parent->GetNativePath(newPath); + VerifyResult(rv); + + nsCOMPtr + expectedFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + + if (!expectedFile) + { + printf("create nsILocalFile failed\n"); + return; + } + rv = expectedFile->InitWithNativePath(nsDependentCString(expected)); + VerifyResult(rv); + + rv = expectedFile->Normalize(); + VerifyResult(rv); + + nsCAutoString expectedPath; + rv = expectedFile->GetNativePath(expectedPath); + VerifyResult(rv); + + if (!newPath.Equals(expectedPath)) { + printf("ERROR: Normalize() test Failed!\n"); + printf(" Got: %s\n", newPath.get()); + printf("Expected: %s\n", expectedPath.get()); + } + + printf("end normalize test.\n"); +} + +int main(void) +{ + nsCOMPtr servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + +#if defined(XP_WIN) || defined(XP_OS2) + InitTest("c:\\temp\\", "sub1/sub2/"); // expect failure + InitTest("d:\\temp\\", "sub1\\sub2\\"); // expect failure + + CreationTest("c:\\temp\\", "file.txt", nsIFile::NORMAL_FILE_TYPE, 0644); + DeletionTest("c:\\temp\\", "file.txt", PR_FALSE); + + MoveTest("c:\\newtemp\\", "d:"); + + CreationTest("c:\\temp\\", "mumble\\a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("c:\\temp\\", "mumble", PR_TRUE); + + CreateUniqueTest("c:\\temp\\", "foo", nsIFile::NORMAL_FILE_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "foo", nsIFile::NORMAL_FILE_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "bar.xx", nsIFile::DIRECTORY_TYPE, 0644); + CreateUniqueTest("c:\\temp\\", "bar.xx", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("c:\\temp\\", "foo", PR_TRUE); + DeletionTest("c:\\temp\\", "foo-1", PR_TRUE); + DeletionTest("c:\\temp\\", "bar.xx", PR_TRUE); + DeletionTest("c:\\temp\\", "bar-1.xx", PR_TRUE); + +#else +#ifdef XP_UNIX + InitTest("/tmp/", "sub1/sub2/"); // expect failure + + CreationTest("/tmp", "file.txt", nsIFile::NORMAL_FILE_TYPE, 0644); + DeletionTest("/tmp/", "file.txt", PR_FALSE); + + CreationTest("/tmp", "mumble/a/b/c/d/e/f/g/h/i/j/k/", nsIFile::DIRECTORY_TYPE, 0644); + DeletionTest("/tmp", "mumble", PR_TRUE); + + CreationTest("/tmp", "file", nsIFile::NORMAL_FILE_TYPE, 0644); + CopyTest("/tmp/file", "/tmp/newDir"); + MoveTest("/tmp/file", "/tmp/newDir/anotherNewDir"); + DeletionTest("/tmp", "newDir", PR_TRUE); + + CreationTest("/tmp", "qux/quux", nsIFile::NORMAL_FILE_TYPE, 0644); + CreationTest("/tmp", "foo/bar", nsIFile::NORMAL_FILE_TYPE, 0644); + NormalizeTest("/tmp/qux/quux/..", 1, "/tmp/foo/bar"); + DeletionTest("/tmp", "qux", PR_TRUE); + DeletionTest("/tmp", "foo", PR_TRUE); + +#endif /* XP_UNIX */ +#endif /* XP_WIN || XP_OS2 */ + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/resources.h b/src/libs/xpcom18a4/xpcom/tests/resources.h new file mode 100644 index 00000000..b82df25e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/resources.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Waterson + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 resources_h___ +#define resources_h___ + +#define TIMER_1SECOND 40000 +#define TIMER_5SECOND 40001 +#define TIMER_10SECOND 40002 + +#define TIMER_1REPEAT 40003 +#define TIMER_5REPEAT 40004 +#define TIMER_10REPEAT 40005 + +#define TIMER_CANCEL 40006 +#define TIMER_EXIT 40010 + +#endif /* resources_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in new file mode 100644 index 00000000..84cd3c84 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/Makefile.in @@ -0,0 +1,58 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +IS_COMPONENT = 1 +MODULE_NAME = MyService +LIBRARY_NAME = MyService +SHORT_LIBNAME = MyServce + +CPPSRCS = MyService.cpp + +LOCAL_INCLUDES = -I$(srcdir)/.. + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp b/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp new file mode 100644 index 00000000..aec78449 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/MyService.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "MyService.h" +#include "nsIServiceManager.h" +#include "nsIGenericFactory.h" +#include + +//////////////////////////////////////////////////////////////////////////////// + +class MyService : public IMyService { +public: + + NS_IMETHOD + Doit(void); + + MyService(); + NS_DECL_ISUPPORTS + +private: + ~MyService(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// MyService Implementation + +NS_IMPL_ISUPPORTS1(MyService, IMyService) + +MyService::MyService() +{ + printf(" creating my service\n"); +} + +MyService::~MyService() +{ + printf(" destroying my service\n"); +} + +nsresult +MyService::Doit(void) +{ + printf(" invoking my service\n"); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// MyServiceFactory Implementation + +NS_GENERIC_FACTORY_CONSTRUCTOR(MyService) + +static const nsModuleComponentInfo myService_components[] = { + { "MyService", NS_IMYSERVICE_CID, nsnull, MyServiceConstructor }, +}; + +NS_IMPL_NSGETMODULE(MyService, myService_components) + + + diff --git a/src/libs/xpcom18a4/xpcom/tests/services/MyService.h b/src/libs/xpcom18a4/xpcom/tests/services/MyService.h new file mode 100644 index 00000000..30b0e30a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/MyService.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 MyService_h__ +#define MyService_h__ + +#include "nsISupports.h" + +#define NS_IMYSERVICE_IID \ +{ /* fedc3380-3648-11d2-8163-006008119d7a */ \ + 0xfedc3380, \ + 0x3648, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +class IMyService : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IMYSERVICE_IID) + + NS_IMETHOD + Doit(void) = 0; + +}; + +#define NS_IMYSERVICE_CID \ +{ /* 34876550-364b-11d2-8163-006008119d7a */ \ + 0x34876550, \ + 0x364b, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +#endif // MyService_h__ diff --git a/src/libs/xpcom18a4/xpcom/tests/services/win32.order b/src/libs/xpcom18a4/xpcom/tests/services/win32.order new file mode 100644 index 00000000..132a4357 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/services/win32.order @@ -0,0 +1 @@ +_NSCanUnload ; 1 diff --git a/src/libs/xpcom18a4/xpcom/tests/test.properties b/src/libs/xpcom18a4/xpcom/tests/test.properties new file mode 100644 index 00000000..4ed37783 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/test.properties @@ -0,0 +1,46 @@ +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** +1=1 + 2=2 +3 =3 + 4 =4 +5=5 +6= 6 +7=7 +8= 8 +# this is a comment +9=this is the first part of a continued line \ + and here is the 2nd part diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp b/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp new file mode 100644 index 00000000..13942f3b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/WhatError.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsError.h" +#include +#include + +int +main(int argc, char **argv) +{ + int errorCode = 0; + char buffer[100]; + + if (argc != 2) + return -1; + + sscanf( argv[1], "0x%x", &errorCode); + sprintf(buffer, "%d", errorCode); + sscanf( buffer, "%d", &errorCode); + + printf( "Code: %d, Module: %d, Severity: %d\n", + NS_ERROR_GET_CODE(errorCode), + NS_ERROR_GET_MODULE(errorCode), + NS_ERROR_GET_SEVERITY(errorCode)); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/cp.js b/src/libs/xpcom18a4/xpcom/tests/utils/cp.js new file mode 100644 index 00000000..a38c120b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/cp.js @@ -0,0 +1,111 @@ +const nsILocalFile = Components.interfaces.nsILocalFile; +var prefix = ""; + +function rename(source, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + + try { + sourceFile.copyTo(null, newName); + } + catch (e) { + dump("error coping" + e + "\n"); + } +} + + +function cp(source, dest, followLinks, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + var destFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + destFile.initWithPath(dest); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + try { + + if (! destFile.isDirectory()) + { + dump("destination not a directory!\n"); + return; + } + } + catch (e) { + dump("error accessing dest"); + } + + try { + if (followLinks) + { + sourceFile.copyToFollowingLinks(destFile, newName); + } + else + { + sourceFile.copyTo(destFile, newName); + } + } + catch (e) { + dump("error coping" + e + "\n"); + } +} + + +function mv(source, dest, followLinks, newName) +{ + try { + var sourceFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + sourceFile.initWithPath(source); + + var destFile = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + destFile.initWithPath(dest); + + } + catch (e) { + dump("Could not create nsILocalFile\n"); + } + + try { + + if (! destFile.isDirectory()) + { + dump("destination not a directory!\n"); + return; + } + } + catch (e) { + dump("error accessing dest"); + } + + try { + if (followLinks) + { + sourceFile.moveToFollowingLinks(destFile, newName); + } + else + { + sourceFile.moveTo(destFile, newName); + } + } + catch (e) { + dump("error coping" + e + "\n"); + } +} diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js b/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js new file mode 100644 index 00000000..c3fc2479 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/dirs.js @@ -0,0 +1,155 @@ +function dumpPathOfProperty(prop) +{ + dump(prop +' = '); + + try + { + var file = dsprops.get(prop, Components.interfaces.nsIFile); + dump(file.path + '\n'); + } + catch (ar) + { + dump('undefined or error \n'); + } +} + +var dscontractid = "@mozilla.org/file/directory_service;1"; // XXX old-style +var ds = Components.classes[dscontractid].getService(); +var dsprops = ds.QueryInterface(Components.interfaces.nsIProperties); + +dump("xpcom locations::\n"); +// XPCOM Locations: + dumpPathOfProperty ("xpcom.currentProcess"); + dumpPathOfProperty ("xpcom.currentProcess.componentRegistry"); + dumpPathOfProperty ("xpcom.currentProcess.componentDirectory"); + dumpPathOfProperty ("system.OS_DriveDirectory"); + dumpPathOfProperty ("system.OS_TemporaryDirectory"); + dumpPathOfProperty ("system.OS_CurrentProcessDirectory"); + dumpPathOfProperty ("system.OS_CurrentWorkingDirectory"); + +dump("Mac locations::\n"); +// Mac + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.DesktopDirectory"); + dumpPathOfProperty ("system.TrashDirectory"); + dumpPathOfProperty ("system.StartupDirectory"); + dumpPathOfProperty ("system.ShutdownDirectory"); + dumpPathOfProperty ("system.AppleMenuDirectory"); + dumpPathOfProperty ("system.ControlPanelDirectory"); + dumpPathOfProperty ("system.ExtensionDirectory"); + dumpPathOfProperty ("system.FontsDirectory"); + dumpPathOfProperty ("system.PreferencesDirectory"); + dumpPathOfProperty ("system.DocumentsDirectory"); + dumpPathOfProperty ("system.InternetSearchDirectory"); + +dump("PC locations::\n"); +// PC + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.WindowsDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + dumpPathOfProperty ("system.Desktop"); + dumpPathOfProperty ("system.Programs"); + dumpPathOfProperty ("system.Controls"); + dumpPathOfProperty ("system.Printers"); + dumpPathOfProperty ("system.Personal"); + dumpPathOfProperty ("system.Favorites"); + dumpPathOfProperty ("system.Startup"); + dumpPathOfProperty ("system.Recent"); + dumpPathOfProperty ("system.Sendto"); + dumpPathOfProperty ("system.Bitbucket"); + dumpPathOfProperty ("system.Startmenu"); + dumpPathOfProperty ("system.Desktopdirectory"); + dumpPathOfProperty ("system.Drives"); + dumpPathOfProperty ("system.Network"); + dumpPathOfProperty ("system.Nethood"); + dumpPathOfProperty ("system.Fonts"); + dumpPathOfProperty ("system.Templates"); + dumpPathOfProperty ("system.Common_Startmenu"); + dumpPathOfProperty ("system.Common_Programs"); + dumpPathOfProperty ("system.Common_Startup"); + dumpPathOfProperty ("system.Common_Desktopdirectory"); + dumpPathOfProperty ("system.Appdata"); + dumpPathOfProperty ("system.Printhood"); + +dump("Unix locations::\n"); +// Unix + + dumpPathOfProperty ("system.LocalDirectory"); + dumpPathOfProperty ("system.LibDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + +dump("Beos locations::\n"); +// Beos + + dumpPathOfProperty ("system.SettingsDirectory"); + dumpPathOfProperty ("system.HomeDirectory"); + dumpPathOfProperty ("system.DesktopDirectory"); + dumpPathOfProperty ("system.SystemDirectory"); + +dump("OS2 locations::\n"); +// OS2 + dumpPathOfProperty ("system.SystemDirectory"); + dumpPathOfProperty ("system.OS2Directory"); + dumpPathOfProperty ("system.DesktopDirectory"); + + +// XPFE locations: + + +// application Directories: + dumpPathOfProperty ("app.res.directory"); + dumpPathOfProperty ("app.defaults.directory"); + dumpPathOfProperty ("app.chrome.directory"); + dumpPathOfProperty ("app.chrome.user.directory"); + dumpPathOfProperty ("app.plugins.directory"); + +// application Files: + + dumpPathOfProperty ("app.registry.file.4"); + dumpPathOfProperty ("app.registry.file.5"); + dumpPathOfProperty ("app.local.store.file.5"); + dumpPathOfProperty ("app.history.file.5"); + dumpPathOfProperty ("app.user.panels.5"); + +// Preferences: + +// dumpPathOfProperty ("app.prefs.directory.3"); +// dumpPathOfProperty ("app.prefs.directory.4"); + dumpPathOfProperty ("app.prefs.directory.5"); + dumpPathOfProperty ("app.pref.default.directory.5"); + +// dumpPathOfProperty ("app.prefs.file.3"); +// dumpPathOfProperty ("app.prefs.file.4"); + dumpPathOfProperty ("app.prefs.file.5"); + +// Profile: + +// dumpPathOfProperty ("app.profile.user.directory.3"); +// dumpPathOfProperty ("app.profile.user.directory.4"); + dumpPathOfProperty ("app.profile.user.directory.5"); +// dumpPathOfProperty ("app.profile.default.user.directory.3"); +// dumpPathOfProperty ("app.profile.default.user.directory.4"); + dumpPathOfProperty ("app.profile.default.user.directory.5"); +// dumpPathOfProperty ("app.profile.defaults.directory.3"); +// dumpPathOfProperty ("app.profile.defaults.directory.4"); + dumpPathOfProperty ("app.profile.defaults.directory.5"); + + + +// Bookmarks: + +// dumpPathOfProperty ("app.bookmark.file.3"); +// dumpPathOfProperty ("app.bookmark.file.4"); + dumpPathOfProperty ("app.bookmark.file.5"); + +// Search + dumpPathOfProperty ("app.search.file.5"); + dumpPathOfProperty ("app.search.directory.5"); + + +// MailNews: + + dumpPathOfProperty ("app.mail.directory.5"); + dumpPathOfProperty ("app.mail.imap.directory.5"); + dumpPathOfProperty ("app.mail.news.directory.5"); + dumpPathOfProperty ("app.mail.messenger.cache.directory.5"); diff --git a/src/libs/xpcom18a4/xpcom/tests/utils/ls.js b/src/libs/xpcom18a4/xpcom/tests/utils/ls.js new file mode 100644 index 00000000..8ae62f06 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/utils/ls.js @@ -0,0 +1,64 @@ +const nsILocalFile = Components.interfaces.nsILocalFile; +var prefix = ""; + +function ls(path, recur) +{ + var file = Components.classes["@mozilla.org/file/local;1"]. + createInstance(nsILocalFile); + try { + file.initWithPath( path ); + + if (file.isDirectory() && arguments.length == 1) + ls_dir(file, recur); + else + ls_file(file, recur); + } + catch (e) { + dump("Error Returned " + e + "\n"); + } +} +function ls_file(file, recur) +{ + dump(prefix); + + try { + if (file.isDirectory()) { + dump("directory " + file.leafName + "\n"); + if(recur) + ls_dir(file, true); + return; + } + + dump(file.leafName + " " + file.fileSize); + if (file.isSymlink()) + dump(" -> " + file.target); + dump("\n"); + } + + catch (e) { + dump(file.leafName + " (error accessing)\n"); + } +} + +function ls_dir(file, recur) +{ + var leafName = file.leafName; + + var old = prefix; + prefix = prefix + " "; + + iter = file.directoryEntries; + dump(iter + "\n"); + + foreach_iter(iter, + function (file) { ls_file(file, recur); }); + prefix = old; +} + +function foreach_iter(iter, fun) +{ + while (iter.hasMoreElements()) { + var item = iter.getNext().QueryInterface(nsILocalFile); + fun(item); + } +} diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore b/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in b/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in new file mode 100644 index 00000000..8bd782c8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/Makefile.in @@ -0,0 +1,60 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +REQUIRES = string + +CPPSRCS = TestCOM.cpp +#TestHelloXPLoop.cpp nsStringTest.cpp + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +include $(topsrcdir)/config/config.mk + +include $(topsrcdir)/config/rules.mk + +OS_LIBS = $(call EXPAND_LIBNAME,rpcrt4 uuid) + +LIBS = $(XPCOM_LIBS) $(NSPR_LIBS) diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp new file mode 100644 index 00000000..b76eccb4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/TestCOM.cpp @@ -0,0 +1,181 @@ +/* -*- 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include +#include "nsISupports.h" +#include "nsIFactory.h" + +// unknwn.h is needed to build with WIN32_LEAN_AND_MEAN +#include + +// {5846BA30-B856-11d1-A98A-00805F8A7AC4} +#define NS_ITEST_COM_IID \ +{ 0x5846ba30, 0xb856, 0x11d1, \ + { 0xa9, 0x8a, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 } } + +class nsITestCom: public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ITEST_COM_IID) + NS_IMETHOD Test() = 0; +}; + +/* + * nsTestCom + */ + +class nsTestCom: public nsITestCom { + NS_DECL_ISUPPORTS + +public: + nsTestCom() { + } + + NS_IMETHOD Test() { + printf("Accessed nsITestCom::Test() from COM\n"); + return NS_OK; + } + +private: + ~nsTestCom() { + printf("nsTestCom instance successfully deleted\n"); + } +}; + +NS_IMPL_QUERY_INTERFACE1(nsTestCom, nsITestCom) + +nsrefcnt nsTestCom::AddRef() +{ + nsrefcnt res = ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsTestCom", sizeof(*this)); + printf("nsTestCom: Adding ref = %d\n", res); + return res; +} + +nsrefcnt nsTestCom::Release() +{ + nsrefcnt res = --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsTestCom"); + printf("nsTestCom: Releasing = %d\n", res); + if (res == 0) { + delete this; + } + return res; +} + +class nsTestComFactory: public nsIFactory { + NS_DECL_ISUPPORTS +public: + nsTestComFactory() { + } + + NS_IMETHOD CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult); + + NS_IMETHOD LockFactory(PRBool aLock) { + printf("nsTestComFactory: "); + printf("%s", (aLock == PR_TRUE ? "Locking server" : "Unlocking server")); + printf("\n"); + return S_OK; + } +}; + +NS_IMPL_ISUPPORTS1(nsTestComFactory, nsIFactory) + +nsresult nsTestComFactory::CreateInstance(nsISupports *aOuter, + const nsIID &aIID, + void **aResult) +{ + if (aOuter != NULL) { + return NS_ERROR_NO_AGGREGATION; + } + + nsTestCom *t = new nsTestCom(); + + if (t == NULL) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(t); + nsresult res = t->QueryInterface(aIID, aResult); + NS_RELEASE(t); + + if (NS_SUCCEEDED(res)) { + printf("nsTestComFactory: successfully created nsTestCom instance\n"); + } + + return res; +} + +/* + * main + */ + +int main(int argc, char *argv[]) +{ + nsTestComFactory *inst = new nsTestComFactory(); + IClassFactory *iFactory; + inst->QueryInterface(NS_GET_IID(nsIFactory), (void **) &iFactory); + + IUnknown *iUnknown; + nsITestCom *iTestCom; + + nsresult res; + iFactory->LockServer(TRUE); + res = iFactory->CreateInstance(NULL, + IID_IUnknown, + (void **) &iUnknown); + iFactory->LockServer(FALSE); + + GUID testGUID = NS_ITEST_COM_IID; + HRESULT hres; + hres= iUnknown->QueryInterface(testGUID, + (void **) &iTestCom); + + iTestCom->Test(); + + iUnknown->Release(); + iTestCom->Release(); + iFactory->Release(); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp new file mode 100644 index 00000000..fdfa1218 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/TestHelloXPLoop.cpp @@ -0,0 +1,177 @@ +/* -*- 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 Mozilla browser. + * + * The Initial Developer of the Original Code is + * Netscape Communications, Inc. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Travis Bogard + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "nsCNativeApp.h" +#include "nsIEventLoop.h" +#include + +static NS_DEFINE_CID(kNativeAppCID, NS_NATIVE_APP_CID); + +LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam); + +void ErrorBox(LPSTR text) +{ + MessageBox(NULL, text, "XP Event Loop", MB_OK | MB_ICONSTOP); +} + +void InfoBox(LPSTR text) +{ + MessageBox(NULL, text, "XP Event Loop", MB_OK | MB_ICONINFORMATION); +} + +int WINAPI WinMain(HINSTANCE inst, + HINSTANCE prevInstance, + LPSTR lpszCmdLine, + int nShowCmd) +{ + char* lpszAppName = "HelloWorld"; + HWND wnd; + WNDCLASSEX wndclass; + int retCode; + + { // Needed to scope all nsCOMPtr within XPCOM Init and Shutdown + nsresult rv; + nsCOMPtr servMan; + rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull); + if(NS_FAILED(rv)) + { + ErrorBox("Failed to initalize xpcom."); + return -1; + } + + nsCOMPtr registrar = do_QueryInterface(servMan); + NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); + registrar->AutoRegister(nsnull); + + nsCOMPtr nativeAppService(do_GetService(kNativeAppCID, &rv)); + + if(NS_FAILED(rv)) + { + ErrorBox("Failed to get nativeAppService"); + return -1; + } + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = inst; + wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = lpszAppName; + wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + RegisterClassEx(&wndclass) ; + + wnd = CreateWindow(lpszAppName, "The Hello World", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, inst, NULL); + + ShowWindow(wnd, nShowCmd); + UpdateWindow(wnd); + + nsCOMPtr eventLoop; + + if(NS_FAILED(nativeAppService->CreateEventLoop(L"_MainLoop", + nsEventLoopTypes::MainAppLoop, getter_AddRefs(eventLoop)))) + { + ErrorBox("Failed to create event Loop"); + return 0; + } + + eventLoop->Run(nsnull, nsnull, nsnull, &retCode); + eventLoop = nsnull; // Clear out before Shutting down XPCOM + + InfoBox("Hello World app is out of loop"); + } + NS_ShutdownXPCOM(nsnull); + InfoBox("Hello World app is exiting"); + return retCode; +} + +LRESULT CALLBACK WndProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + + switch(msg) + { + case WM_PAINT: + hdc = BeginPaint(wnd, &ps); + + GetClientRect(wnd, &rect); + + DrawText(hdc, "Hello, XP Event Loop!", -1, &rect, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); + + EndPaint(wnd, &ps); + return 0; + + case WM_DESTROY: + { + nsresult rv; + nsCOMPtr nativeAppService = + do_GetService(kNativeAppCID, &rv); + if(NS_FAILED(rv)) + { + ErrorBox("Could not get NativeAppService"); + return 0; + } + nsCOMPtr eventLoop; + + if(NS_FAILED(nativeAppService->FindEventLoop(L"_MainLoop", + getter_AddRefs(eventLoop)))) + { + ErrorBox("Failed to find event Loop"); + return 0; + } + eventLoop->Exit(0); + } + return 0; + } + + return DefWindowProc(wnd, msg, wParam, lParam); +} diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp new file mode 100644 index 00000000..6719ed38 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.cpp @@ -0,0 +1,33 @@ + +#include +#include "nsStr.h" +#include "nsStringTest2.h" +#include "nsString.h" +#include "nsReadableUtils.h" + +int main(){ + + nsString temp("\t\t\n\r\n\r25,* \t \n\n \t"); + temp.CompressWhitespace(); + + nsString temp1("\t\t\n\r\n\r25,* \t \n\n \t"); + temp1.CompressSet("\t\n\r ",' ',false,false); + + nsString temp3(""); + char* s = ToNewCString(temp3); + delete s; + + char* f = ToNewCString(nsAutoString("")); + char* f1 = ToNewCString(nsCAutoString("")); + delete f; + delete f1; + + + CStringTester gStringTester; + + gStringTester.TestI18nString(); + + return 0; +} + + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h new file mode 100644 index 00000000..8244a5a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest.h @@ -0,0 +1,2277 @@ +/******************************************************************************************** + * + * MODULES NOTES: + * + * This file is designed to help test the new nsString classes. + * + * Contributor(s): + * Rick Gessner + * + * History: + * + * 02.29.2000: Original files (rickg) + * 03.02.2000: Flesh out the interface to be compatible with old library (rickg) + * + ********************************************************************************************/ + +#ifndef _STRINGTEST +#define _STRINGTEST + + +#include "nsString.h" +#include "nsReadableUtils.h" +#include + +#define USE_STL + +#ifdef USE_STL +#include +using namespace std; +#endif + +#define USE_WIDE 1 +#ifdef USE_WIDE + #define stringtype nsString + #define astringtype nsAutoString + #define chartype PRUnichar +#else + #define stringtype nsCString + #define astringtype nsCAutoString + #define chartype char +#endif + + +#include + + + +static const char* kConstructorError = "constructor error"; +static const char* kComparisonError = "Comparision error!"; +static const char* kEqualsError = "Equals error!"; + +static char* kNumbers[]={"0123456789","0\01\02\03\04\05\06\07\08\09\0\0\0"}; +static char* kLetters[]={"abcdefghij","a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0\0\0"}; +static char* kAAA[]={"AAA","A\0A\0A\0\0\0"}; +static char* kBBB[]={"BBB","B\0B\0B\0\0\0"}; +static char* kHello[]={"hello","h\0e\0l\0l\0o\0\0\0"}; +static char* kWSHello[]={" hello "," \0 \0h\0e\0l\0l\0o\0 \0 \0\0\0"}; + + + +/******************************************************** + + This class's only purpose in life is to test the + netscape string library. We exercise the string + API's here, and do a bit of performance testing + against the standard c++ library string (from STL). + + ********************************************************/ +class CStringTester { +public: + CStringTester() { + TestConstructors(); + TestAutoStrings(); + TestAppend(); + TestAssignAndAdd(); + TestInsert(); + TestDelete(); + TestTruncate(); + TestLogical(); + TestLexomorphic(); + TestCreators(); + TestNumerics(); + TestExtractors(); + TestSearching(); + TestSubsumables(); + TestRandomOps(); + TestReplace(); + TestRegressions(); + TestStringPerformance(); + TestWideStringPerformance(); + } +protected: + int TestConstructors(); + int TestLogical(); + int TestAutoStrings(); + int TestAppend(); + int TestAssignAndAdd(); + int TestInsert(); + int TestDelete(); + int TestTruncate(); + int TestLexomorphic(); + int TestCreators(); + int TestNumerics(); + int TestExtractors(); + int TestSearching(); + int TestSubsumables(); + int TestRandomOps(); + int TestReplace(); + int TestStringPerformance(); + int TestWideStringPerformance(); + int TestRegressions(); +}; + + +class Stopwatch { +public: + Stopwatch() { + start=clock(); + } + + void Stop() { + stop=clock(); + } + + double Elapsed() { + return (double)(stop - start) / CLOCKS_PER_SEC; + } + + void Print(const char* msg= "") { + printf("%s %f\n",msg,Elapsed()); + } + + clock_t start,stop; +}; + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestSearching(){ + int result=0; + + + + PRUnichar pbuf[10]={'e','f','g',0}; + PRUnichar pbuf2[10]={'a','b','c',0}; + + + //Since there is so much ground to cover with searching, we use a typedef to + //allow you to vary the string type being searched... + + + stringtype theDest("abcdefghijkabc"); + nsString s1("ijk"); + nsCString c1("ijk"); + + PRInt32 pos=theDest.Find(pbuf); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.Find(pbuf2,PR_FALSE,-1); + NS_ASSERTION(pos==0,"Error: Find routine"); + + pos=theDest.Find(pbuf2,PR_FALSE,pos+1); + NS_ASSERTION(pos==11,"Error: Find routine"); + + pos=theDest.FindChar('a'); + NS_ASSERTION(pos==0,"Error: Find routine"); + + pos=theDest.FindChar('a',PR_FALSE,pos+1); + NS_ASSERTION(pos==11,"Error: Find routine"); + + pos=theDest.Find("efg"); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.Find("EFG",PR_TRUE); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.FindChar('d'); + NS_ASSERTION(pos==3,"Error: Find char routine"); + + pos=theDest.Find(s1); + NS_ASSERTION(pos==8,"Error: Find char routine"); + + pos=theDest.FindCharInSet("12k"); + NS_ASSERTION(pos==10,"Error: Findcharinset routine"); + + pos=theDest.FindCharInSet(pbuf); + NS_ASSERTION(pos==4,"Error: Findcharinset routine"); + + pos=theDest.FindCharInSet(s1); + NS_ASSERTION(pos==8,"Error: Findcharinset routine"); + + pos=theDest.Find("efg",PR_FALSE,2); + NS_ASSERTION(pos==4,"Error: Find routine"); + + pos=theDest.RFindCharInSet("12k"); + NS_ASSERTION(pos==10,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet("xyz"); + NS_ASSERTION(pos==-1,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet(pbuf); + NS_ASSERTION(pos==6,"Error: RFindcharinset routine"); + + pos=theDest.RFindCharInSet(s1); + NS_ASSERTION(pos==10,"Error: RFindcharinset routine"); + + pos=theDest.RFind("efg"); + NS_ASSERTION(pos==4,"Error: RFind routine"); + + pos=theDest.RFind("xxx"); + NS_ASSERTION(pos==-1,"Error: RFind routine"); //this should fail + + pos=theDest.RFind(""); + NS_ASSERTION(pos==-1,"Error: RFind routine"); //this too should fail. + + pos=theDest.RFindChar('a',PR_FALSE,4); + NS_ASSERTION(pos==-1,"Error: RFind routine"); + + + //now try searching with FindChar using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos=s1.FindChar('r'); //this will search from the beginning, and for the length of the string. + NS_ASSERTION(pos==9,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('r',PR_FALSE,0,5); //this will search from the front using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('r',PR_FALSE,0,10); //this will search from the front using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==9,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('i',PR_FALSE,5,5); //this will search from the middle using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('i',PR_FALSE,5,10); //this will search from the middle using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==13,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,2); //this will search from near the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,7); //this will search from near the end using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==15,"Error: FindChar() with offset and count"); + + //now let's try a few with bad data... + + pos=s1.FindChar('k',PR_FALSE,100,2); //this will search from a bad offset. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,0); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,20); //this will search for a bad count. THIS WILL SUCCEED! + NS_ASSERTION(pos==15,"Error: FindChar() with offset and count"); + + pos=s1.FindChar('k',PR_FALSE,10,4); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: FindChar() with offset and count"); + + pos=10; + } + + //now try searching with RFindChar using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos=s1.RFindChar('o'); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==4,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('i'); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==13,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar(' ',PR_FALSE,-1,4); //this will search from the end, and for the length of the string. + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); //THIS WILL FAIL + + pos=s1.RFindChar(' ',PR_FALSE,12,1); //this will search from the middle, and for the length of 1. + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); //THIS WILL FAIL + + pos=s1.RFindChar(' ',PR_FALSE,12,2); //this will search from the middle, and for the length of 2. + NS_ASSERTION(pos==11,"Error: RFindChar() with offset and count"); //THIS WILL SUCCEED + + pos=s1.RFindChar('o',PR_FALSE,-1,5); //this will search from the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('o',PR_FALSE,-1,12); //this will search from the front using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==4,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('l',PR_FALSE,8,2); //this will search from the middle using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('l',PR_FALSE,8,7); //this will search from the middle using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==3,"Error: RFindChar() with offset and count"); + +//*** + + pos=s1.RFindChar('h',PR_FALSE,3,2); //this will search from near the end using count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('h',PR_FALSE,3,7); //this will search from near the end using count. THIS WILL SUCCEED! + NS_ASSERTION(pos==0,"Error: RFindChar() with offset and count"); + + //now let's try a few with bad data... + + pos=s1.RFindChar('k',PR_FALSE,100,2); //this will search from a bad offset. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=s1.RFindChar('k',PR_FALSE,10,0); //this will search for a bad count. THIS WILL FAIL! + NS_ASSERTION(pos==-1,"Error: RFindChar() with offset and count"); + + pos=10; + } + + //now try searching with Find() using offset and count... + { + stringtype s1("hello there rick"); + + PRInt32 pos= s1.Find("there",PR_FALSE,0,4); //first search from front using offset + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("there",PR_FALSE,0,8); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find) with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,4,1); //first search from front using count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("there",PR_FALSE,5,2); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,6,1); //first search from front using count + NS_ASSERTION(pos==6,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("there",PR_FALSE,6,0); //first search from front using a bogus count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos= s1.Find("k",PR_FALSE,15,1); //first search from end using a count + NS_ASSERTION(pos==15,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("k",PR_FALSE,15,10); //first search from end using a LARGE count + NS_ASSERTION(pos==15,"Error: Find() with offset and count"); //THIS WILL SUCCEED + + pos= s1.Find("k",PR_FALSE,25,10); //first search from bogus offset using a LARGE count + NS_ASSERTION(pos==-1,"Error: Find() with offset and count"); //THIS WILL FAIL + + pos=10; + } + + //now try substringsearching with RFind() using offset and count... + { + nsString s1("abcdefghijklmnopqrstuvwxyz"); + + PRInt32 pos= s1.RFind("ghi"); //first search from end using count + NS_ASSERTION(pos==6,"Error: RFind() with offset and count"); //THIS WILL SUCCEED! + + pos= s1.RFind("nop",PR_FALSE,-1,4); //first search from end using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("nop",PR_FALSE,-1,15); //first search from end using count + NS_ASSERTION(pos==13,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("nop",PR_FALSE,16,3); //first search from middle using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("nop",PR_FALSE,16,7); //first search from middle using count + NS_ASSERTION(pos==13,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("nop",PR_FALSE,0,1); //first search from front using count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("abc",PR_FALSE,0,1); //first search from middle using count + NS_ASSERTION(pos==0,"Error: RFind() with offset and count"); //THIS WILL SUCCEED + + pos= s1.RFind("foo",PR_FALSE,10,100); //first search from front using bogus count + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos= s1.RFind("ghi",PR_FALSE,30,1); //first search from middle using bogus offset + NS_ASSERTION(pos==-1,"Error: RFind() with offset and count"); //THIS WILL FAIL + + pos=10; + } + + //Various UNICODE tests... + { + //do some searching against chinese unicode chars... + + PRUnichar chinese[] = {0x4e41,0x4e42, 0x4e43, 0x0000}; // 3 chinese unicode + + nsString T2(chinese); + nsString T2copy(chinese); + + pos = T2.FindCharInSet("A"); + NS_ASSERTION(kNotFound==pos,"Error in FindCharInSet"); + + pos=T2.RFindCharInSet("A",2); + NS_ASSERTION(kNotFound==pos,"Error in RFindCharInSet"); + + pos=T2.Find("A", PR_FALSE, 0, 1); + NS_ASSERTION(kNotFound==pos,"Error in Find"); + + pos=T2.RFind("A", PR_FALSE, 2, 1); + NS_ASSERTION(kNotFound==pos,"Error in RFind"); + + T2.ReplaceChar("A",' '); + NS_ASSERTION(T2==T2copy,"Error in ReplaceChar"); + + //Here's the 3rd FTang unicode test... + + static char test4[]="ABCDEF"; + static char test4b[]=" BCDEF"; + + PRUnichar test5[]={0x4e41, 0x0000}; + PRUnichar test6[]={0x0041, 0x0000}; + + nsCString T4(test4); + nsCString T4copy(test4); + nsCString T4copyb(test4b); + nsCString T5(test5); + nsCString T6(test6); + + pos = T4.FindCharInSet(T5.get()); + NS_ASSERTION(0==pos,"Error in FindcharInSet"); //This should succeed. + + pos = T4.FindCharInSet(T6.get()); + NS_ASSERTION(kNotFoundtemp8.Compare(bbbb),kComparisonError); + NS_ASSERTION(0>temp8.Compare(temp9),kComparisonError); + NS_ASSERTION(0=temp8)),kComparisonError); + + NS_ASSERTION(((temp9>temp8) && (temp8<=temp9)),kComparisonError); + NS_ASSERTION(temp9>aaaa,kComparisonError); + + NS_ASSERTION(temp8<=temp8,kComparisonError); + NS_ASSERTION(temp8<=temp9,kComparisonError); + NS_ASSERTION(temp8<=bbbb,kComparisonError); + + NS_ASSERTION(((temp9>=temp8) && (temp8=temp8,kComparisonError); + NS_ASSERTION(temp9>=aaaa,kComparisonError); + + NS_ASSERTION(temp8.Equals(temp8),kEqualsError); + NS_ASSERTION(temp8.Equals(aaaa),kEqualsError); + + stringtype temp10(temp8); + ToUpperCase(temp10); + NS_ASSERTION(temp8.Equals(temp10,PR_TRUE),kEqualsError); + NS_ASSERTION(temp8.Equals("AAAA",PR_TRUE),kEqualsError); + + + //now test the new string Equals APIs.. + { + nsCString s1("hello there"); + NS_ASSERTION(s1.Equals("hello there"),kEqualsError); + NS_ASSERTION(s1.Equals("hello rick",PR_FALSE,5),kEqualsError); + NS_ASSERTION(!s1.Equals("hello rick",PR_FALSE-1),kEqualsError); + + nsCString s2(""); + NS_ASSERTION(s2.Equals(""),kEqualsError); + + nsCString s3("view-source:"); + NS_ASSERTION(s3.Equals("VIEW-SOURCE:",PR_TRUE,12),kEqualsError); + } + + //now test the count argument... + { + nsString s1("rickgessner"); + nsString s2("rickricardo"); + PRInt32 result=s1.Compare(s2); //assume no case conversion, and full-length comparison... + result=s1.Compare(s2,PR_FALSE,4); + result=s1.Compare(s2,PR_FALSE,5); + + PRBool b=s1.Equals(s2); + b=s1.Equals("rick",PR_FALSE,4); + b=s1.Equals("rickz",PR_FALSE,5); + + result=10; + + nsString s3("view"); + +#define kString "view-source" + + b=s3.Equals(kString); + result=10; + } + + return result; +} + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestAssignAndAdd(){ + int result=0; + + static const char* s1="hello"; + static const char* s2="world"; + static const PRUnichar pbuf[] = {' ','w','o','r','l','d',0}; + + nsString ns1("I'm an nsString"); + nsCString nc1("I'm an nsCString"); + + nsAutoString as1("nsAutoString source"); + nsCAutoString ac1("nsCAutoString source"); + + + { + //**** Test assignments to nsCString... + + nsCString theDest; + theDest.Assign(theDest); //assign nsString to itself + theDest.Assign(ns1); //assign an nsString to an nsString + NS_ASSERTION(theDest==ns1,"Assignment error"); + + theDest.Assign(nc1); //assign an nsCString to an nsString + NS_ASSERTION(theDest==nc1,"Assignment error"); + + theDest.Assign(as1); //assign an nsAutoString to an nsString +// NS_ASSERTION(theDest==as1,"Assignment error"); + + theDest.Assign(ac1); //assign an nsCAutoString to an nsString +// NS_ASSERTION(theDest==ac1,"Assignment error"); + + theDest.Assign("simple char*"); //assign a char* to an nsString + NS_ASSERTION(theDest=="simple char*","Assignment error"); + + theDest.Assign(pbuf); //assign a PRUnichar* to an nsString + NS_ASSERTION(theDest==pbuf,"Assignment error"); + + theDest.Assign('!'); //assign a char to an nsString + NS_ASSERTION(theDest=="!","Assignment error"); + + theDest.Assign(PRUnichar('$')); //assign a char to an nsString + NS_ASSERTION(theDest=="$","Assignment error"); + + theDest=ns1; + NS_ASSERTION(theDest==ns1,"Assignment error"); + + theDest=nc1; + NS_ASSERTION(theDest==nc1,"Assignment error"); + + theDest='a'; + NS_ASSERTION(theDest=="a","Assignment error"); + + theDest=PRUnichar('a'); + NS_ASSERTION(theDest=="a","Assignment error"); + + theDest=s1; + NS_ASSERTION(theDest==s1,"Assignment error"); + + theDest=pbuf; + NS_ASSERTION(theDest==pbuf,"Assignment error"); + + } + + //test operator+()... + { + + /* NOT WORKING YET... + nsString s1("hello"); + nsString s2(" world"); + nsCString c1(" world"); + + stringtype theDest; + + theDest=s1+s2; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+c1; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+" world"; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+pbuf; + NS_ASSERTION(theDest=="hello world","Assignment error"); + + theDest=s1+'!'; + NS_ASSERTION(theDest=="hello!","Assignment error"); + + theDest=s1+PRUnichar('!'); + NS_ASSERTION(theDest=="hello!","Assignment error"); +*/ + + } + + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestAppend(){ + int result=0; + + + static const char* s1="hello"; + static const char* s2="world"; + static const PRUnichar pbuf[] = {' ','w','o','r','l','d',0}; + static const PRUnichar pbuf1[] = {'a','b','c','d','l','d'}; + + + stringtype theDest; + theDest.Append((float)100.100); + NS_ASSERTION(theDest=="100.1","Append(float) error"); + + theDest.Truncate(); + theDest.Append(12345); + NS_ASSERTION(theDest=="12345","Append(int) error"); + + theDest.Truncate(); + theDest.Append(pbuf1,1); + NS_ASSERTION(theDest=="a","Append(PRUnichar*,count) error"); + + theDest.Truncate(); + theDest.Append('a'); + NS_ASSERTION(theDest=="a","Append(char) error"); + + + static const PRUnichar pbuf2[] = {'w','h','a','t','s',' ','u','p',' ','d','o','c','?',0}; + + theDest.Truncate(); + theDest.Append(pbuf,20); //try appending more chars than actual length of pbuf + NS_ASSERTION(theDest!=pbuf,"Append(PRUnichar*) error"); + //(NOTE: if you tell me to append X chars, I'll assume you really have X chars, and the length + // get's set accordingly. This test really is correct; it just seems odd. + + theDest.Truncate(0); + theDest.Append(pbuf,5); //try appending fewer chars than actual length of pbuf + NS_ASSERTION(theDest==" worl","Append(PRUnichar*) error"); + + theDest.Truncate(0); + theDest.Append(pbuf); //try appending all of pbuf + NS_ASSERTION(theDest==pbuf,"Append(PRUnichar*) error"); + + char* ss=0; + theDest.Truncate(); + theDest.Append(ss); //try appending NULL + NS_ASSERTION(theDest=="","Append(nullstr) error"); + + theDest.Append(pbuf,0); //try appending nothing + NS_ASSERTION(theDest=="","Append(nullstr) error"); + + + { + //test improvement to unichar appends... + stringtype s1("hello"); + char c='!'; + s1+=c; + NS_ASSERTION(s1=="hello!","operator+=() error"); + + c=(char)0xfa; + s1+=c; + s1.Append(c); + + PRUnichar theChar='f'; + s1+=theChar; + + char theChar2='g'; + s1+=theChar2; + +// long theLong= 1234; +// s1+=theLong; + + } + + { + //this just proves we can append nulls in our buffers... + stringtype c("hello"); + stringtype s(" there"); + c.Append(s); + char buf[]={'a','b',0,'d','e'}; + s.Append(buf,5); + } + + + stringtype temp2("there"); + + theDest.Append(temp2); + theDest.Append(" xxx "); + theDest.Append(pbuf); + theDest.Append('4'); + theDest.Append(PRUnichar('Z')); + + stringtype a(s1); + stringtype b(s2); + + theDest.Truncate(); + temp2.Truncate(); + +/* NOT WORKING YET... + theDest=a+b; + temp2=a+"world!"; + temp2=a+pbuf; + stringtype temp3; + temp3=temp2+'!'; +*/ + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestExtractors(){ + int result=0; + + //first test the 2 byte version... + + + { + nsString temp1("hello there rick"); + nsString temp2; + + temp1.Left(temp2,10); + NS_ASSERTION(temp2=="hello ther","Left() error"); + + temp1.Mid(temp2,6,5); + NS_ASSERTION(temp2=="there","Mid() error"); + + temp1.Right(temp2,4); + NS_ASSERTION(temp2=="rick","Right() error"); + + //Now test the character accessor methods... + nsString theString("hello"); + PRUint32 len=theString.Length(); + PRUnichar theChar; + for(PRUint32 i=0;i2) { + pos=theString.Length()/2; + theSTLString.insert(pos,str[index],4); + theString.Insert(str[index],pos); + } + break; + + case 6: + case 7: + case 8: + case 9: + theOp=eDelete; + if(theString.Length()>10) { + len=theString.Length()/2; + pos=theString.Length()/4; + theSTLString.erase(pos,len); + theString.Cut(pos,len); + } + break; + + default: + theOp=eNOP; + + } //for + + if(eNOP300) { + theString.Truncate(); + theSTLString.erase(); + } +#endif + thePrevString=theString; + } + } +#endif + return result; +} + + +/** + * + * @update gess10/30/98 + * @param + * @return + */ +int CStringTester::TestReplace(){ + int result=0; + + const char* find=".."; + const char* rep= "+"; + + const char* s1="hello..there..rick..gessner."; + const char* s2="hello+there+rick+gessner."; + + nsCString s(s1); + s.ReplaceSubstring(find,rep); + NS_ASSERTION(s==s2,"ReplaceSubstring error"); + + s.ReplaceSubstring(rep,find); + NS_ASSERTION(s==s1,"ReplaceSubstring error"); + + return result; +} + + +/** + * This method tests the performance of various methods. + * + * + * @return + */ +int CStringTester::TestWideStringPerformance() { + + printf("Widestring performance tests...\n"); + + char* libname[] = {"STL","nsString",0}; + + + //************************************************** + //Test Construction against STL::wstring... + //************************************************** + { + nsString theConst; + for(int z=0;z<10;z++){ + theConst.Append("0123456789"); + } + + Stopwatch watch1; + int i; + for(i=0;i<1000000;i++){ + nsString s(theConst); + } + watch1.Stop(); + + wchar_t wbuf[] = {'a','b','c','d','e','f','g','h','i','j',0}; + wstring theConst2; + for(int w=0;w<10;w++){ + theConst2.append(wbuf); + } + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000000;i++){ + wstring s(theConst2); + } +#endif + watch2.Stop(); + + printf("Construct(abcde) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + + //************************************************** + //Test append("abcde") against STL::wstring... + //************************************************** + { + + PRUnichar pbuf[10]={'a','b','c','d','e',0}; + + Stopwatch watch1; + int i; + for(i=0;i<1000;i++){ + nsString s; + for(int j=0;j<200;j++){ + s.Append("abcde"); + } + } + watch1.Stop(); + + wchar_t wbuf[10] = {'a','b','c','d','e',0}; + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000;i++){ + wstring s; + for(int j=0;j<200;j++){ + s.append(wbuf); + } + } +#endif + watch2.Stop(); + + printf("Append(abcde) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + //************************************************** + //Test append(char) against STL::wstring + //************************************************** + { + + Stopwatch watch1; + int i; + for(i=0;i<500;i++){ + nsString s; + for(int j=0;j<200;j++){ + s.Append('a'); + } + } + watch1.Stop(); + + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<500;i++){ + wstring s; + wchar_t theChar('a'); + for(int j=0;j<200;j++){ + s.append('a',1); + } + } +#endif + watch2.Stop(); + + printf("Append('a') NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + int x=0; + } + + //************************************************** + //Test insert("123") against STL::wstring + //************************************************** + { + + PRUnichar pbuf1[10]={'a','b','c','d','e','f',0}; + PRUnichar pbuf2[10]={'1','2','3',0}; + + Stopwatch watch1; + int i; + for(i=0;i<1000;i++){ + nsString s("abcdef"); + int inspos=3; + for(int j=0;j<100;j++){ + s.Insert(pbuf2,inspos); + inspos+=3; + } + } + watch1.Stop(); + + + wchar_t wbuf1[10] = {'a','b','c','d','e','f',0}; + wchar_t wbuf2[10] = {'1','2','3',0}; + + Stopwatch watch2; +#ifdef USE_STL + for(i=0;i<1000;i++){ + wstring s(wbuf1); + int inspos=3; + for(int j=0;j<100;j++){ + s.insert(inspos,wbuf2); + inspos+=3; + } + } +#endif + watch2.Stop(); + + printf("Insert(123) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + int x=0; + } + + //************************************************** + //Let's test substring searching performance... + //************************************************** + { + PRUnichar pbuf1[] = {'a','a','a','a','a','a','a','a','a','a','b',0}; + PRUnichar pbuf2[] = {'a','a','b',0}; + + nsString s(pbuf1); + nsString target(pbuf2); + + Stopwatch watch1; + int i; + for(i=-1;i<200000;i++) { + PRInt32 result=s.Find(target,PR_FALSE); + } + watch1.Stop(); + + Stopwatch watch2; +#ifdef USE_STL + wchar_t wbuf1[] = {'a','a','a','a','a','a','a','a','a','a','b',0}; + wchar_t wbuf2[] = {'a','a','b',0}; + wstring ws(wbuf1); + wstring wtarget(wbuf2); + + for(i=-1;i<200000;i++) { + PRInt32 result=ws.find(wtarget); + } +#endif + watch2.Stop(); + + printf("Find(aab) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + } + + //************************************************** + //Now let's test comparisons... + //************************************************** + { + nsString s("aaaaaaaaaaaaaaaaaaab"); + PRUnichar target[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + size_t theLen=(sizeof(target)-1)/2; + + Stopwatch watch1; + int result=0; + int i; + for(i=-1;i<1000000;i++) { + result=s.Compare(target,PR_FALSE,theLen); + result++; + } + watch1.Stop(); + + Stopwatch watch2; +#ifdef USE_STL + wchar_t buf[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + wstring ws(buf); + wchar_t wtarget[]={'a','a','a','a','a','a','a','a','a','a','a','a','a','b',0}; + + for(i=-1;i<1000000;i++) { + result=ws.compare(0,theLen,wtarget); + result++; + } +#endif + watch2.Stop(); + + printf("Compare(aaaaaaaab) NSString: %f STL: %f\n",watch1.Elapsed(),watch2.Elapsed()); + + } + + //************************************************** + //Now lets test string deletions... + //************************************************** + { + + int strcount=6000; + int outerIter=100; + int innerIter=100; + + PRUnichar pbuf[] = {'1','2','3','4','5','6','7','8','9','0',0}; + nsString source1; //build up our target string... + int i; + for(i=0;i"); + PRInt32 result=s.Find("",PR_TRUE); + + //this was a known bug... + { + nsString s0(""); + PRInt32 pos=s0.RFind("-->"); + nsString s1("debug"); + pos=s1.RFind("b"); + pos=s1.RFind("de",PR_FALSE,1); + pos=10; + } + + //this was a known bug... + { + nsString s0("RDF:RDF"); + PRInt32 pos=s0.Find(":"); + pos=10; + } + + return result; +} + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h new file mode 100644 index 00000000..16ffc11a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tests/windows/nsStringTest2.h @@ -0,0 +1,444 @@ +/******************************************************************************************** + * + * MODULES NOTES: + * + * This file is designed to help test the new nsString classes. + * + * Contributor(s): + * Rick Gessner + * + * History: + * + * 02.29.2000: Original files (rickg) + * 03.02.2000: Flesh out the interface to be compatible with old library (rickg) + * + ********************************************************************************************/ + +#ifndef _STRINGTEST2 +#define _STRINGTEST2 + + +#include "nsString.h" +#include + +#define USE_STL + +#ifdef USE_STL +#include +using namespace std; +#endif + +#define USE_WIDE 1 +#ifdef USE_WIDE + #define stringtype nsString + #define astringtype nsAutoString + #define chartype PRUnichar +#else + #define stringtype nsCString + #define astringtype nsCAutoString + #define chartype char +#endif + +#include +const double gTicks = 1.0e-7; + + + + + +/******************************************************** + + This class's only purpose in life is to test the + netscape string library. We exercise the string + API's here, and do a bit of performance testing + against the standard c++ library string (from STL). + + ********************************************************/ +class CStringTester { + +public: + + int TestI18nString(); + +}; + + + + +//test 1: unicode char is stripped correctly using StripChars() +void nsStringTest1(){ + PRUnichar test[]={0x0041,0x0051,0x0052,0x0000}; + nsString T(test); + PRUnichar result[]={0x0051,0x0052,0x0000}; + nsString R(result); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Test 1: Unicode comparison error"); +} +//test 2: unicode char is not matched and stripped when high-order byte is not 0x00 +void nsStringTest2(){ + PRUnichar test[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + //test 3: unicode char is not matched and stripped when high-order byte is 0xFF +void nsStringTest3(){ + + PRUnichar test[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(test); + T.StripChars("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest4(){ + //test 4: unicode char is matched and stripped correctly using StripChar() + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest5(){ + //test 5: unicode char is not matched and stripped when high-order byte is not 0x00 + + PRUnichar test[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[]={0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest6(){ + //test 6: unicode char is not matched and stripped when high-order byte is 0xFF + + PRUnichar test[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFF41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.StripChar('A'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest7(){ + //test 7: unicode char is matched and replaced correctly using ReplaceChar() + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0050,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest8(){ + //test 8: unicode char is not matched or replaced when high-order byte != 0x00 + + PRUnichar test[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest9(){ + //test 9: unicode char is not matched or replaced when high-order byte matches search char + + PRUnichar test[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest10(){ + //test 10: unicode char is not matched or replaced when high-order byte == 0xFF + + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar('A',0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + +void nsStringTest11(){ + //test 11: unicode char is correctly replaced when parameter 1 is a string + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0050,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest12(){ + //test 12: unicode char is not replaced when high-order byte != 0x00 + + PRUnichar test[] = {0x4e41,0x0051,0x0052,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x0051,0x0052,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",0x50); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest13(){ + //test 13: unicode char is not replaced when high-order byte matches char in search string + PRUnichar test[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4150,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest14(){ + PRUnichar test[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.ReplaceChar("ABC",'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest15(){ + PRUnichar test[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0xFFc2,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + PRUnichar s = 0xc2; //compiler error on this line + T.ReplaceChar(s,'T'); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} + +void nsStringTest16(){ + /* TESTS for ReplaceSubstring()*/ + + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0044,0x0045,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0044,0x0045,0x0046,0x0044,0x0045}; + nsAutoString R(result); + T.ReplaceSubstring("ABC","DEF"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +void nsStringTest17(){ + + PRUnichar test[] = {0x0041,0x4e42,0x0043,0x0044,0x0045,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x0041,0x4e42,0x0043,0x0044,0x0045,0x0000}; + nsAutoString R(result); + T.ReplaceSubstring("ABC","DEF"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest18(){ + /*TESTS for Trim()*/ + + PRUnichar test[] = {0x0041,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R (result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest19(){ + PRUnichar test[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e41,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString R(result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +} +void nsStringTest22(){ + PRUnichar test[] = {0x4e51,0x4e52,0x4e53,0x4e41,0x0000}; + nsAutoString T(test); + PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x4e41,0x0000}; + nsAutoString R(result); + T.Trim("ABC"); + NS_ASSERTION(T.Equals(R), "Unicode comparison error"); + +} +//void nsStringTest23(){ +// PRUnichar test[] = {0x4e51,0x4e52,0x4e53,0x4e22,0x0000}; +// nsAutoString T(test); +// PRUnichar s(0x4e22); +// PRUnichar result[] = {0x4e51,0x4e52,0x4e53,0x0000}; +// nsAutoString R(result); +// T.Trim(s,PR_TRUE,PR_TRUE,PR_FALSE); +// NS_ASSERTION(T.Equals(R), "Unicode comparison error"); +//} +void nsStringTest24(){ + /*TESTS for Find()*/ + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Find("ABC") == 0, "Unicode comparison error"); + +} +void nsStringTest25(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Find("ABC") == -1, "Unicode comparison error"); + +} +void nsStringTest26(){ + PRUnichar test[] = {0xFFc1,0x0051,0x0052,0x0053,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0x51,0x52}; + nsAutoString S(str); + NS_ASSERTION(T.Find(S) == -1, "Unicode comparison error"); +} +void nsStringTest27(){ + /*TESTS for FindChar()*/ + + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A') == 0, "Unicode comparison error"); +} +void nsStringTest28(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A') == -1, "Unicode comparison error"); +} +void nsStringTest29(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar(0xc1) == -1, "Unicode comparison error"); + +} +void nsStringTest30(){ + PRUnichar test[] = {0x4132,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindChar('A1') == -1, "Unicode comparison error"); +} + /*TESTS for FindCharInSet()*/ +void nsStringTest31(){ + PRUnichar test[] = {0x0041,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == 0, "Unicode comparison error"); +} +void nsStringTest32(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == -1, "Unicode comparison error"); + +} +void nsStringTest33(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0x51,0x52}; + nsAutoString s(str); + NS_ASSERTION(T.FindCharInSet(s) == -1, "Unicode comparison error"); +} +void nsStringTest34(){ + PRUnichar test[] = {0x4132,0x5132,0x5232,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.FindCharInSet("ABC") == -1, "Unicode comparison error"); +} + /*TESTS for RFind()*/ +void nsStringTest35(){ + + PRUnichar test[] = {0x0051,0x0052,0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFind("ABC") == 2, "Unicode comparison error"); +} +void nsStringTest36(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFind("ABC") == -1, "Unicode comparison error"); +} +void nsStringTest37(){ + PRUnichar test[] = {0xFFc1,0xFFc2,0xFFc3,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0xc2,0xc3}; + nsAutoString s(str); + NS_ASSERTION(T.RFind(s) == -1, "Unicode comparison error"); +} + /*TESTS for RFindCharInSet*/ +void nsStringTest38(){ + + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + int res = T.RFindCharInSet("ABC"); + NS_ASSERTION(res==0, "Unicode comparison error"); +} +void nsStringTest39(){ + PRUnichar test[] = {0x4e41,0x4e42,0x4e43,0x4e53,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFindCharInSet("ABC") == -1, "Unicode comparison error"); +} +void nsStringTest40(){ + PRUnichar test[] = {0xFFc1,0x4e51,0x4e52,0x4e53,0x0000}; + nsAutoString T(test); + PRUnichar str[] = {0xc1,0xc2,0xc3}; + nsAutoString s(str); + NS_ASSERTION(T.RFindCharInSet(s) == -1, "Unicode comparison error"); +} +void nsStringTest41(){ + PRUnichar test[] = {0x4132,0x0051,0x0052,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.RFindCharInSet("ABC") == -1, "Unicode comparison error"); +} + /* TESTS for Compare() */ +void nsStringTest42(){ + PRUnichar test[] = {0x0041,0x0042,0x0043,0x0000}; + nsAutoString T(test); + NS_ASSERTION(T.Compare("ABC") == 0, "Unicode comparison error"); +} +void nsStringTest43(){ + PRUnichar test[] = {0xc341,0xc342,0xc343}; + nsAutoString T(test); + NS_ASSERTION(T.Compare("ABC") == 1, "Unicode comparison error"); +} + + +int CStringTester::TestI18nString(){ + nsStringTest1(); + nsStringTest2(); + nsStringTest3(); + nsStringTest4(); + nsStringTest5(); + nsStringTest6(); + nsStringTest7(); + nsStringTest8(); + nsStringTest9(); + nsStringTest10(); + nsStringTest11(); + nsStringTest12(); + nsStringTest13(); + nsStringTest14(); + nsStringTest15(); + nsStringTest16(); + nsStringTest17(); + nsStringTest18(); + nsStringTest19(); + //nsStringTest20(); + //nsStringTest21(); + nsStringTest22(); + //nsStringTest23(); + nsStringTest24(); + nsStringTest25(); + nsStringTest26(); + nsStringTest27(); + nsStringTest28(); + nsStringTest29(); + nsStringTest30(); + nsStringTest31(); + nsStringTest32(); + nsStringTest33(); + nsStringTest34(); + nsStringTest35(); + nsStringTest36(); + nsStringTest37(); + nsStringTest38(); + nsStringTest39(); + nsStringTest40(); + nsStringTest41(); + nsStringTest42(); + nsStringTest43(); + + return 0; +} + +#endif + diff --git a/src/libs/xpcom18a4/xpcom/threads/.cvsignore b/src/libs/xpcom18a4/xpcom/threads/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/threads/Makefile.in b/src/libs/xpcom18a4/xpcom/threads/Makefile.in new file mode 100644 index 00000000..83433706 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/Makefile.in @@ -0,0 +1,105 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +ifeq ($(OS_ARCH),WINNT) +XPIDL_MODULE = xpcom_thread +else +XPIDL_MODULE = xpcom_threads +endif +LIBRARY_NAME = xpcomthreads_s +GRE_MODULE = 1 +REQUIRES = string \ + $(NULL) + + +CSRCS = \ + plevent.c \ + $(NULL) + +CPPSRCS = \ + nsAutoLock.cpp \ + nsEnvironment.cpp \ + nsEventQueue.cpp \ + nsEventQueueService.cpp \ + nsThread.cpp \ + nsTimerImpl.cpp \ + nsProcessCommon.cpp \ + TimerThread.cpp \ + $(NULL) + +EXPORTS = \ + nsAutoLock.h \ + plevent.h \ + nsProcess.h \ + nsEventQueueUtils.h \ + $(NULL) + +XPIDLSRCS = \ + nsIThread.idl \ + nsITimer.idl \ + nsITimerInternal.idl \ + nsITimerManager.idl \ + nsIRunnable.idl \ + nsIEventTarget.idl \ + nsIEventQueue.idl \ + nsIEventQueueService.idl \ + nsIEnvironment.idl \ + nsIProcess.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +LOCAL_INCLUDES = -I$(srcdir)/../components + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM + diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp new file mode 100644 index 00000000..94076892 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.cpp @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimerImpl.h" +#include "TimerThread.h" + +#include "nsAutoLock.h" +#include "pratom.h" + +#include "nsIObserverService.h" +#include "nsIServiceManager.h" + +NS_IMPL_THREADSAFE_ISUPPORTS3(TimerThread, nsIRunnable, nsISupportsWeakReference, nsIObserver) + +TimerThread::TimerThread() : + mInitInProgress(0), + mInitialized(PR_FALSE), + mLock(nsnull), + mCondVar(nsnull), + mShutdown(PR_FALSE), + mWaiting(PR_FALSE), + mSleeping(PR_FALSE), + mDelayLineCounter(0), + mMinTimerPeriod(0), + mTimeoutAdjustment(0) +{ +} + +TimerThread::~TimerThread() +{ + if (mCondVar) + PR_DestroyCondVar(mCondVar); + if (mLock) + PR_DestroyLock(mLock); + + mThread = nsnull; + + PRInt32 n = mTimers.Count(); + while (--n >= 0) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[n]); + NS_RELEASE(timer); + } + + nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + if (observerService) { + observerService->RemoveObserver(this, "sleep_notification"); + observerService->RemoveObserver(this, "wake_notification"); + } + +} + +nsresult +TimerThread::InitLocks() +{ + NS_ASSERTION(!mLock, "InitLocks called twice?"); + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + mCondVar = PR_NewCondVar(mLock); + if (!mCondVar) + return NS_ERROR_OUT_OF_MEMORY; + + return NS_OK; +} + +nsresult TimerThread::Init() +{ + if (mInitialized) { + if (!mThread) + return NS_ERROR_FAILURE; + + return NS_OK; + } + + if (PR_AtomicSet(&mInitInProgress, 1) == 0) { + nsresult rv; + + mEventQueueService = do_GetService("@mozilla.org/event-queue-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr observerService + (do_GetService("@mozilla.org/observer-service;1", &rv)); + + if (NS_SUCCEEDED(rv)) { + // We hold on to mThread to keep the thread alive. + rv = NS_NewThread(getter_AddRefs(mThread), + NS_STATIC_CAST(nsIRunnable*, this), + 0, + PR_JOINABLE_THREAD, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD); + + if (NS_FAILED(rv)) { + mThread = nsnull; + } + else { + observerService->AddObserver(this, "sleep_notification", PR_TRUE); + observerService->AddObserver(this, "wake_notification", PR_TRUE); + } + } + } + + PR_Lock(mLock); + mInitialized = PR_TRUE; + PR_NotifyAllCondVar(mCondVar); + PR_Unlock(mLock); + } + else { + PR_Lock(mLock); + while (!mInitialized) { + PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(mLock); + } + + if (!mThread) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +nsresult TimerThread::Shutdown() +{ + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + + { // lock scope + nsAutoLock lock(mLock); + + mShutdown = PR_TRUE; + + // notify the cond var so that Run() can return + if (mCondVar && mWaiting) + PR_NotifyCondVar(mCondVar); + + nsTimerImpl *timer; + for (PRInt32 i = mTimers.Count() - 1; i >= 0; i--) { + timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]); + RemoveTimerInternal(timer); + } + } + + mThread->Join(); // wait for the thread to die + return NS_OK; +} + +// Keep track of how early (positive slack) or late (negative slack) timers +// are running, and use the filtered slack number to adaptively estimate how +// early timers should fire to be "on time". +void TimerThread::UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, + PRIntervalTime aNow) +{ + PRInt32 slack = (PRInt32) (aTimeout - aNow); + double smoothSlack = 0; + PRUint32 i, filterLength; + static PRIntervalTime kFilterFeedbackMaxTicks = + PR_MillisecondsToInterval(FILTER_FEEDBACK_MAX); + + if (slack > 0) { + if (slack > (PRInt32)kFilterFeedbackMaxTicks) + slack = kFilterFeedbackMaxTicks; + } else { + if (slack < -(PRInt32)kFilterFeedbackMaxTicks) + slack = -(PRInt32)kFilterFeedbackMaxTicks; + } + mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] = slack; + if (++mDelayLineCounter < DELAY_LINE_LENGTH) { + // Startup mode: accumulate a full delay line before filtering. + PR_ASSERT(mTimeoutAdjustment == 0); + filterLength = 0; + } else { + // Past startup: compute number of filter taps based on mMinTimerPeriod. + if (mMinTimerPeriod == 0) { + mMinTimerPeriod = (aDelay != 0) ? aDelay : 1; + } else if (aDelay != 0 && aDelay < mMinTimerPeriod) { + mMinTimerPeriod = aDelay; + } + + filterLength = (PRUint32) (FILTER_DURATION / mMinTimerPeriod); + if (filterLength > DELAY_LINE_LENGTH) + filterLength = DELAY_LINE_LENGTH; + else if (filterLength < 4) + filterLength = 4; + + for (i = 1; i <= filterLength; i++) + smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK]; + smoothSlack /= filterLength; + + // XXXbe do we need amplification? hacking a fudge factor, need testing... + mTimeoutAdjustment = (PRInt32) (smoothSlack * 1.5); + } + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("UpdateFilter: smoothSlack = %g, filterLength = %u\n", + smoothSlack, filterLength)); + } +#endif +} + +/* void Run(); */ +NS_IMETHODIMP TimerThread::Run() +{ + nsAutoLock lock(mLock); + + while (!mShutdown) { + PRIntervalTime waitFor; + + if (mSleeping) { + // Sleep for 0.1 seconds while not firing timers. + waitFor = PR_MillisecondsToInterval(100); + } else { + waitFor = PR_INTERVAL_NO_TIMEOUT; + PRIntervalTime now = PR_IntervalNow(); + nsTimerImpl *timer = nsnull; + + if (mTimers.Count() > 0) { + timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[0]); + + if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) { + next: + // NB: AddRef before the Release under RemoveTimerInternal to avoid + // mRefCnt passing through zero, in case all other refs than the one + // from mTimers have gone away (the last non-mTimers[i]-ref's Release + // must be racing with us, blocked in gThread->RemoveTimer waiting + // for TimerThread::mLock, under nsTimerImpl::Release. + + NS_ADDREF(timer); + RemoveTimerInternal(timer); + + // We release mLock around the Fire call to avoid deadlock. + lock.unlock(); + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("Timer thread woke up %dms from when it was supposed to\n", + (now >= timer->mTimeout) + ? PR_IntervalToMilliseconds(now - timer->mTimeout) + : -(PRInt32)PR_IntervalToMilliseconds(timer->mTimeout-now)) + ); + } +#endif + + // We are going to let the call to PostTimerEvent here handle the + // release of the timer so that we don't end up releasing the timer + // on the TimerThread instead of on the thread it targets. + timer->PostTimerEvent(); + timer = nsnull; + + lock.lock(); + if (mShutdown) + break; + + // Update now, as PostTimerEvent plus the locking may have taken a + // tick or two, and we may goto next below. + now = PR_IntervalNow(); + } + } + + if (mTimers.Count() > 0) { + timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[0]); + + PRIntervalTime timeout = timer->mTimeout + mTimeoutAdjustment; + + // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer + // is due now or overdue. + if (!TIMER_LESS_THAN(now, timeout)) + goto next; + waitFor = timeout - now; + } + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + if (waitFor == PR_INTERVAL_NO_TIMEOUT) + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("waiting for PR_INTERVAL_NO_TIMEOUT\n")); + else + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor))); + } +#endif + } + + mWaiting = PR_TRUE; + PR_WaitCondVar(mCondVar, waitFor); + mWaiting = PR_FALSE; + } + + return NS_OK; +} + +nsresult TimerThread::AddTimer(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Add the timer to our list. + PRInt32 i = AddTimerInternal(aTimer); + if (i < 0) + return NS_ERROR_OUT_OF_MEMORY; + + // Awaken the timer thread. + if (mCondVar && mWaiting && i == 0) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Our caller has a strong ref to aTimer, so it can't go away here under + // ReleaseTimerInternal. + RemoveTimerInternal(aTimer); + + PRInt32 i = AddTimerInternal(aTimer); + if (i < 0) + return NS_ERROR_OUT_OF_MEMORY; + + // Awaken the timer thread. + if (mCondVar && mWaiting && i == 0) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer) +{ + nsAutoLock lock(mLock); + + // Remove the timer from our array. Tell callers that aTimer was not found + // by returning NS_ERROR_NOT_AVAILABLE. Unlike the TimerDelayChanged case + // immediately above, our caller may be passing a (now-)weak ref in via the + // aTimer param, specifically when nsTimerImpl::Release loses a race with + // TimerThread::Run, must wait for the mLock auto-lock here, and during the + // wait Run drops the only remaining ref to aTimer via RemoveTimerInternal. + + if (!RemoveTimerInternal(aTimer)) + return NS_ERROR_NOT_AVAILABLE; + + // Awaken the timer thread. + if (mCondVar && mWaiting) + PR_NotifyCondVar(mCondVar); + + return NS_OK; +} + +// This function must be called from within a lock +PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer) +{ + PRIntervalTime now = PR_IntervalNow(); + PRInt32 count = mTimers.Count(); + PRInt32 i = 0; + for (; i < count; i++) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl *, mTimers[i]); + + // Don't break till we have skipped any overdue timers. Do not include + // mTimeoutAdjustment here, because we are really trying to avoid calling + // TIMER_LESS_THAN(t, u), where the t is now + DELAY_INTERVAL_MAX, u is + // now - overdue, and DELAY_INTERVAL_MAX + overdue > DELAY_INTERVAL_LIMIT. + // In other words, we want to use now-based time, now adjusted time, even + // though "overdue" ultimately depends on adjusted time. + + // XXX does this hold for TYPE_REPEATING_PRECISE? /be + + if (TIMER_LESS_THAN(now, timer->mTimeout) && + TIMER_LESS_THAN(aTimer->mTimeout, timer->mTimeout)) { + break; + } + } + + if (!mTimers.InsertElementAt(aTimer, i)) + return -1; + + aTimer->mArmed = PR_TRUE; + NS_ADDREF(aTimer); + return i; +} + +PRBool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer) +{ + if (!mTimers.RemoveElement(aTimer)) + return PR_FALSE; + + // Order is crucial here -- see nsTimerImpl::Release. + aTimer->mArmed = PR_FALSE; + NS_RELEASE(aTimer); + return PR_TRUE; +} + +void TimerThread::DoBeforeSleep() +{ + mSleeping = PR_TRUE; +} + +void TimerThread::DoAfterSleep() +{ + for (PRInt32 i = 0; i < mTimers.Count(); i ++) { + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, mTimers[i]); + // get and set the delay to cause its timeout to be recomputed + PRUint32 delay; + timer->GetDelay(&delay); + timer->SetDelay(delay); + } + + // nuke the stored adjustments, so they get recalibrated + mTimeoutAdjustment = 0; + mDelayLineCounter = 0; + mSleeping = PR_FALSE; +} + + +/* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */ +NS_IMETHODIMP +TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */) +{ + if (strcmp(aTopic, "sleep_notification") == 0) + DoBeforeSleep(); + else if (strcmp(aTopic, "wake_notification") == 0) + DoAfterSleep(); + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/TimerThread.h b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h new file mode 100644 index 00000000..fa23cfc9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/TimerThread.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 TimerThread_h___ +#define TimerThread_h___ + +#include "nsWeakReference.h" + +#include "nsIEventQueueService.h" +#include "nsIObserver.h" +#include "nsIRunnable.h" +#include "nsIThread.h" + +#include "nsTimerImpl.h" + +#include "nsVoidArray.h" + +#include "prcvar.h" +#include "prinrval.h" +#include "prlock.h" + +class TimerThread : public nsSupportsWeakReference, + public nsIRunnable, + public nsIObserver +{ +public: + TimerThread(); + NS_HIDDEN_(nsresult) InitLocks(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + NS_DECL_NSIOBSERVER + + NS_HIDDEN_(nsresult) Init(); + NS_HIDDEN_(nsresult) Shutdown(); + + nsresult AddTimer(nsTimerImpl *aTimer); + nsresult TimerDelayChanged(nsTimerImpl *aTimer); + nsresult RemoveTimer(nsTimerImpl *aTimer); + +#define FILTER_DURATION 1e3 /* one second */ +#define FILTER_FEEDBACK_MAX 100 /* 1/10th of a second */ + + void UpdateFilter(PRUint32 aDelay, PRIntervalTime aTimeout, + PRIntervalTime aNow); + + // For use by nsTimerImpl::Fire() + nsCOMPtr mEventQueueService; + + void DoBeforeSleep(); + void DoAfterSleep(); + +private: + ~TimerThread(); + + PRInt32 mInitInProgress; + PRBool mInitialized; + + // These two internal helper methods must be called while mLock is held. + // AddTimerInternal returns the position where the timer was added in the + // list, or -1 if it failed. + PRInt32 AddTimerInternal(nsTimerImpl *aTimer); + PRBool RemoveTimerInternal(nsTimerImpl *aTimer); + + nsCOMPtr mThread; + PRLock *mLock; + PRCondVar *mCondVar; + + PRPackedBool mShutdown; + PRPackedBool mWaiting; + PRPackedBool mSleeping; + + nsVoidArray mTimers; + +#define DELAY_LINE_LENGTH_LOG2 5 +#define DELAY_LINE_LENGTH_MASK PR_BITMASK(DELAY_LINE_LENGTH_LOG2) +#define DELAY_LINE_LENGTH PR_BIT(DELAY_LINE_LENGTH_LOG2) + + PRInt32 mDelayLine[DELAY_LINE_LENGTH]; + PRUint32 mDelayLineCounter; + PRUint32 mMinTimerPeriod; // milliseconds + PRInt32 mTimeoutAdjustment; +}; + +#endif /* TimerThread_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp new file mode 100644 index 00000000..df89408c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsAutoLock.h" + +#ifdef DEBUG + +#include "plhash.h" +#include "prprf.h" +#include "prlock.h" +#include "prthread.h" +#include "nsDebug.h" +#include "nsVoidArray.h" + +#ifdef NS_TRACE_MALLOC_XXX +# include +# include "nsTraceMalloc.h" +#endif + +static PRUintn LockStackTPI = (PRUintn)-1; +static PLHashTable* OrderTable = 0; +static PRLock* OrderTableLock = 0; + +static const char* const LockTypeNames[] = {"Lock", "Monitor", "CMonitor"}; + +struct nsNamedVector : public nsVoidArray { + const char* mName; + +#ifdef NS_TRACE_MALLOC_XXX + // Callsites for the inner locks/monitors stored in our base nsVoidArray. + // This array parallels our base nsVoidArray. + nsVoidArray mInnerSites; +#endif + + nsNamedVector(const char* name = 0, PRUint32 initialSize = 0) + : nsVoidArray(initialSize), + mName(name) + { + } +}; + +static void * PR_CALLBACK +_hash_alloc_table(void *pool, PRSize size) +{ + return operator new(size); +} + +static void PR_CALLBACK +_hash_free_table(void *pool, void *item) +{ + operator delete(item); +} + +static PLHashEntry * PR_CALLBACK +_hash_alloc_entry(void *pool, const void *key) +{ + return new PLHashEntry; +} + +/* + * Because monitors and locks may be associated with an nsAutoLockBase, + * without having had their associated nsNamedVector created explicitly in + * nsAutoMonitor::NewMonitor/DeleteMonitor, we need to provide a freeEntry + * PLHashTable hook, to avoid leaking nsNamedVectors which are replaced by + * nsAutoMonitor::NewMonitor. + * + * There is still a problem with the OrderTable containing orphaned + * nsNamedVector entries, for manually created locks wrapped by nsAutoLocks. + * (there should be no manually created monitors wrapped by nsAutoMonitors: + * you should use nsAutoMonitor::NewMonitor and nsAutoMonitor::DestroyMonitor + * instead of PR_NewMonitor and PR_DestroyMonitor). These lock vectors don't + * strictly leak, as they are killed on shutdown, but there are unnecessary + * named vectors in the hash table that outlive their associated locks. + * + * XXX so we should have nsLock, nsMonitor, etc. and strongly type their + * XXX nsAutoXXX counterparts to take only the non-auto types as inputs + */ +static void PR_CALLBACK +_hash_free_entry(void *pool, PLHashEntry *entry, PRUintn flag) +{ + nsNamedVector* vec = (nsNamedVector*) entry->value; + if (vec) { + entry->value = 0; + delete vec; + } + if (flag == HT_FREE_ENTRY) + delete entry; +} + +static const PLHashAllocOps _hash_alloc_ops = { + _hash_alloc_table, _hash_free_table, + _hash_alloc_entry, _hash_free_entry +}; + +PR_STATIC_CALLBACK(PRIntn) +_purge_one(PLHashEntry* he, PRIntn cnt, void* arg) +{ + nsNamedVector* vec = (nsNamedVector*) he->value; + + if (he->key == arg) + return HT_ENUMERATE_REMOVE; + vec->RemoveElement(arg); + return HT_ENUMERATE_NEXT; +} + +PR_STATIC_CALLBACK(void) +OnMonitorRecycle(void* addr) +{ + PR_Lock(OrderTableLock); + PL_HashTableEnumerateEntries(OrderTable, _purge_one, addr); + PR_Unlock(OrderTableLock); +} + +PR_STATIC_CALLBACK(PLHashNumber) +_hash_pointer(const void* key) +{ + return PLHashNumber(NS_PTR_TO_INT32(key)) >> 2; +} + +// Must be single-threaded here, early in primordial thread. +static void InitAutoLockStatics() +{ + (void) PR_NewThreadPrivateIndex(&LockStackTPI, 0); + OrderTable = PL_NewHashTable(64, _hash_pointer, + PL_CompareValues, PL_CompareValues, + &_hash_alloc_ops, 0); + if (OrderTable && !(OrderTableLock = PR_NewLock())) { + PL_HashTableDestroy(OrderTable); + OrderTable = 0; + } + PR_CSetOnMonitorRecycle(OnMonitorRecycle); +} + +void _FreeAutoLockStatics() +{ + PLHashTable* table = OrderTable; + if (!table) return; + + // Called at shutdown, so we don't need to lock. + PR_CSetOnMonitorRecycle(0); + PR_DestroyLock(OrderTableLock); + OrderTableLock = 0; + PL_HashTableDestroy(table); + OrderTable = 0; +} + +static nsNamedVector* GetVector(PLHashTable* table, const void* key) +{ + PLHashNumber hash = _hash_pointer(key); + PLHashEntry** hep = PL_HashTableRawLookup(table, hash, key); + PLHashEntry* he = *hep; + if (he) + return (nsNamedVector*) he->value; + nsNamedVector* vec = new nsNamedVector(); + if (vec) + PL_HashTableRawAdd(table, hep, hash, key, vec); + return vec; +} + +// We maintain an acyclic graph in OrderTable, so recursion can't diverge. +static PRBool Reachable(PLHashTable* table, const void* goal, const void* start) +{ + PR_ASSERT(goal); + PR_ASSERT(start); + nsNamedVector* vec = GetVector(table, start); + for (PRUint32 i = 0, n = vec->Count(); i < n; i++) { + void* addr = vec->ElementAt(i); + if (addr == goal || Reachable(table, goal, addr)) + return PR_TRUE; + } + return PR_FALSE; +} + +static PRBool WellOrdered(const void* addr1, const void* addr2, + const void *callsite2, PRUint32* index2p, + nsNamedVector** vec1p, nsNamedVector** vec2p) +{ + PRBool rv = PR_TRUE; + PLHashTable* table = OrderTable; + if (!table) return rv; + PR_Lock(OrderTableLock); + + // Check whether we've already asserted (addr1 < addr2). + nsNamedVector* vec1 = GetVector(table, addr1); + if (vec1) { + PRUint32 i, n; + + for (i = 0, n = vec1->Count(); i < n; i++) + if (vec1->ElementAt(i) == addr2) + break; + + if (i == n) { + // Now check for (addr2 < addr1) and return false if so. + nsNamedVector* vec2 = GetVector(table, addr2); + if (vec2) { + for (i = 0, n = vec2->Count(); i < n; i++) { + void* addri = vec2->ElementAt(i); + PR_ASSERT(addri); + if (addri == addr1 || Reachable(table, addr1, addri)) { + *index2p = i; + *vec1p = vec1; + *vec2p = vec2; + rv = PR_FALSE; + break; + } + } + + if (rv) { + // Assert (addr1 < addr2) into the order table. + // XXX fix plvector/nsVector to use const void* + vec1->AppendElement((void*) addr2); +#ifdef NS_TRACE_MALLOC_XXX + vec1->mInnerSites.AppendElement((void*) callsite2); +#endif + } + } + } + } + + PR_Unlock(OrderTableLock); + return rv; +} + +nsAutoLockBase::nsAutoLockBase(void* addr, nsAutoLockType type) +{ + if (LockStackTPI == PRUintn(-1)) + InitAutoLockStatics(); + + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + if (stackTop) { + if (stackTop->mAddr == addr) { + // Ignore reentry: it's legal for monitors, and NSPR will assert + // if you reenter a PRLock. + } else if (!addr) { + // Ignore null addresses: the caller promises not to use the + // lock at all, and NSPR will assert if you enter it. + } else { + const void* node = +#ifdef NS_TRACE_MALLOC_XXX + NS_GetStackTrace(1) +#else + nsnull +#endif + ; + nsNamedVector* vec1; + nsNamedVector* vec2; + PRUint32 i2; + + if (!WellOrdered(stackTop->mAddr, addr, node, &i2, &vec1, &vec2)) { + char buf[128]; + PR_snprintf(buf, sizeof buf, + "Potential deadlock between %s%s@%p and %s%s@%p", + vec1->mName ? vec1->mName : "", + LockTypeNames[stackTop->mType], + stackTop->mAddr, + vec2->mName ? vec2->mName : "", + LockTypeNames[type], + addr); +#ifdef NS_TRACE_MALLOC_XXX + fprintf(stderr, "\n*** %s\n\nCurrent stack:\n", buf); + NS_DumpStackTrace(node, stderr); + + fputs("\nPrevious stack:\n", stderr); + NS_DumpStackTrace(vec2->mInnerSites.ElementAt(i2), stderr); + putc('\n', stderr); +#endif + NS_ERROR(buf); + } + } + } + + mAddr = addr; + mDown = stackTop; + mType = type; + if (mAddr) + (void) PR_SetThreadPrivate(LockStackTPI, this); +} + +nsAutoLockBase::~nsAutoLockBase() +{ + if (mAddr) + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +} + +void nsAutoLockBase::Show() +{ + if (!mAddr) + return; + nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + nsAutoLockBase* prev = nsnull; + while (curr != mDown) { + prev = curr; + curr = prev->mDown; + } + if (!prev) + PR_SetThreadPrivate(LockStackTPI, this); + else + prev->mDown = this; +} + +void nsAutoLockBase::Hide() +{ + if (!mAddr) + return; + nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + nsAutoLockBase* prev = nsnull; + while (curr != this) { + prev = curr; + curr = prev->mDown; + } + if (!prev) + PR_SetThreadPrivate(LockStackTPI, mDown); + else + prev->mDown = mDown; +} + +#endif /* DEBUG */ + +PRMonitor* nsAutoMonitor::NewMonitor(const char* name) +{ + PRMonitor* mon = PR_NewMonitor(); +#ifdef DEBUG + if (mon && OrderTable) { + nsNamedVector* value = new nsNamedVector(name); + if (value) { + PR_Lock(OrderTableLock); + PL_HashTableAdd(OrderTable, mon, value); + PR_Unlock(OrderTableLock); + } + } +#endif + return mon; +} + +void nsAutoMonitor::DestroyMonitor(PRMonitor* mon) +{ +#ifdef DEBUG + if (OrderTable) + OnMonitorRecycle(mon); +#endif + PR_DestroyMonitor(mon); +} + +void nsAutoMonitor::Enter() +{ +#ifdef DEBUG + if (!mAddr) { + NS_ERROR("It is not legal to enter a null monitor"); + return; + } + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoMonitor::Enter"); + mDown = stackTop; + (void) PR_SetThreadPrivate(LockStackTPI, this); +#endif + PR_EnterMonitor(mMonitor); + mLockCount += 1; +} + +void nsAutoMonitor::Exit() +{ +#ifdef DEBUG + if (!mAddr) { + NS_ERROR("It is not legal to exit a null monitor"); + return; + } + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +#endif + PRStatus status = PR_ExitMonitor(mMonitor); + NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed"); + mLockCount -= 1; +} + +// XXX we don't worry about cached monitors being destroyed behind our back. +// XXX current NSPR (mozilla/nsprpub/pr/src/threads/prcmon.c) never destroys +// XXX a cached monitor! potential resource pig in conjunction with necko... + +void nsAutoCMonitor::Enter() +{ +#ifdef DEBUG + nsAutoLockBase* stackTop = + (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI); + NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoCMonitor::Enter"); + mDown = stackTop; + (void) PR_SetThreadPrivate(LockStackTPI, this); +#endif + PR_CEnterMonitor(mLockObject); + mLockCount += 1; +} + +void nsAutoCMonitor::Exit() +{ +#ifdef DEBUG + (void) PR_SetThreadPrivate(LockStackTPI, mDown); +#endif + PRStatus status = PR_CExitMonitor(mLockObject); + NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed"); + mLockCount -= 1; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h new file mode 100644 index 00000000..a82d6ffc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h @@ -0,0 +1,383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + + +/* + A stack-based lock object that makes using PRLock a bit more + convenient. It acquires the monitor when constructed, and releases + it when it goes out of scope. + + For example, + + class Foo { + private: + PRLock* mLock; + + public: + Foo(void) { + mLock = PR_NewLock(); + } + + ~Foo(void) { + PR_DestroyLock(mLock); + } + + void ThreadSafeMethod(void) { + // we're don't hold the lock yet... + + nsAutoLock lock(mLock); + // ...but now we do. + + // we even can do wacky stuff like return from arbitrary places w/o + // worrying about forgetting to release the lock + if (some_weird_condition) + return; + + // otherwise do some other stuff + } + + void ThreadSafeBlockScope(void) { + // we're not in the lock here... + + { + nsAutoLock lock(mLock); + // but we are now, at least until the block scope closes + } + + // ...now we're not in the lock anymore + } + }; + + A similar stack-based locking object is available for PRMonitor. The + major difference is that the PRMonitor must be created and destroyed + via the static methods on nsAutoMonitor. + + For example: + Foo::Foo() { + mMon = nsAutoMonitor::NewMonitor("FooMonitor"); + } + nsresult Foo::MyMethod(...) { + nsAutoMonitor mon(mMon); + ... + // go ahead and do deeply nested returns... + return NS_ERROR_FAILURE; + ... + // or call Wait or Notify... + mon.Wait(); + ... + // cleanup is automatic + } + */ + +#ifndef nsAutoLock_h__ +#define nsAutoLock_h__ + +#include "nscore.h" +#include "prlock.h" +#include "prlog.h" + +/** + * nsAutoLockBase + * This is the base class for the stack-based locking objects. + * Clients of derived classes need not play with this superclass. + **/ +class NS_COM nsAutoLockBase { +protected: + nsAutoLockBase() {} + enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor}; + +#ifdef DEBUG + nsAutoLockBase(void* addr, nsAutoLockType type); + ~nsAutoLockBase(); + + void Show(); + void Hide(); + + void* mAddr; + nsAutoLockBase* mDown; + nsAutoLockType mType; +#else + nsAutoLockBase(void* addr, nsAutoLockType type) {} + ~nsAutoLockBase() {} + + void Show() {} + void Hide() {} +#endif +}; + +/** + * nsAutoLock + * Stack-based locking object for PRLock. + **/ +class NS_COM nsAutoLock : public nsAutoLockBase { +private: + PRLock* mLock; + PRBool mLocked; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoLock(void); + nsAutoLock(const nsAutoLock& /*aLock*/); + nsAutoLock& operator =(const nsAutoLock& /*aLock*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); + +public: + /** + * Constructor + * The constructor aquires the given lock. The destructor + * releases the lock. + * + * @param aLock A valid PRLock* returned from the NSPR's + * PR_NewLock() function. + **/ + nsAutoLock(PRLock* aLock) + : nsAutoLockBase(aLock, eAutoLock), + mLock(aLock), + mLocked(PR_TRUE) { + PR_ASSERT(mLock); + + // This will assert deep in the bowels of NSPR if you attempt + // to re-enter the lock. + PR_Lock(mLock); + } + + ~nsAutoLock(void) { + if (mLocked) + PR_Unlock(mLock); + } + + /** + * lock + * Client may call this to reaquire the given lock. Take special + * note that attempting to aquire a locked lock will hang or crash. + **/ + void lock() { + Show(); + PR_ASSERT(!mLocked); + PR_Lock(mLock); + mLocked = PR_TRUE; + } + + + /** + * unlock + * Client may call this to release the given lock. Take special + * note unlocking an unlocked lock has undefined results. + **/ + void unlock() { + PR_ASSERT(mLocked); + PR_Unlock(mLock); + mLocked = PR_FALSE; + Hide(); + } +}; + +#include "prcmon.h" +#include "nsError.h" +#include "nsDebug.h" + +class NS_COM nsAutoMonitor : public nsAutoLockBase { +public: + + /** + * NewMonitor + * Allocates a new PRMonitor for use with nsAutoMonitor. + * @param name A (unique /be?) name which can reference this monitor + * @returns nsnull if failure + * A valid PRMonitor* is successful while must be destroyed + * by nsAutoMonitor::DestroyMonitor() + **/ + static PRMonitor* NewMonitor(const char* name); + static void DestroyMonitor(PRMonitor* mon); + + + /** + * Constructor + * The constructor locks the given monitor. During destruction + * the monitor will be unlocked. + * + * @param mon A valid PRMonitor* returned from + * nsAutoMonitor::NewMonitor(). + **/ + nsAutoMonitor(PRMonitor* mon) + : nsAutoLockBase((void*)mon, eAutoMonitor), + mMonitor(mon), mLockCount(0) + { + NS_ASSERTION(mMonitor, "null monitor"); + if (mMonitor) { + PR_EnterMonitor(mMonitor); + mLockCount = 1; + } + } + + ~nsAutoMonitor() { + NS_ASSERTION(mMonitor, "null monitor"); + if (mMonitor && mLockCount) { +#ifdef DEBUG + PRStatus status = +#endif + PR_ExitMonitor(mMonitor); + NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed"); + } + } + + /** + * Enter + * Client may call this to reenter the given monitor. + * @see prmon.h + **/ + void Enter(); + + /** + * Exit + * Client may call this to exit the given monitor. + * @see prmon.h + **/ + void Exit(); + + /** + * Wait + * @see prmon.h + **/ + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) { + return PR_Wait(mMonitor, interval) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + /** + * Notify + * @see prmon.h + **/ + nsresult Notify() { + return PR_Notify(mMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + /** + * NotifyAll + * @see prmon.h + **/ + nsresult NotifyAll() { + return PR_NotifyAll(mMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + +private: + PRMonitor* mMonitor; + PRInt32 mLockCount; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoMonitor(void); + nsAutoMonitor(const nsAutoMonitor& /*aMon*/); + nsAutoMonitor& operator =(const nsAutoMonitor& /*aMon*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); +}; + +//////////////////////////////////////////////////////////////////////////////// +// Once again, this time with a cache... +// (Using this avoids the need to allocate a PRMonitor, which may be useful when +// a large number of objects of the same class need associated monitors.) + +#include "prcmon.h" +#include "nsError.h" + +class NS_COM nsAutoCMonitor : public nsAutoLockBase { +public: + nsAutoCMonitor(void* lockObject) + : nsAutoLockBase(lockObject, eAutoCMonitor), + mLockObject(lockObject), mLockCount(0) + { + NS_ASSERTION(lockObject, "null lock object"); + PR_CEnterMonitor(mLockObject); + mLockCount = 1; + } + + ~nsAutoCMonitor() { + if (mLockCount) { +#ifdef DEBUG + PRStatus status = +#endif + PR_CExitMonitor(mLockObject); + NS_ASSERTION(status == PR_SUCCESS, "PR_CExitMonitor failed"); + } + } + + void Enter(); + void Exit(); + + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) { + return PR_CWait(mLockObject, interval) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult Notify() { + return PR_CNotify(mLockObject) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + nsresult NotifyAll() { + return PR_CNotifyAll(mLockObject) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + +private: + void* mLockObject; + PRInt32 mLockCount; + + // Not meant to be implemented. This makes it a compiler error to + // construct or assign an nsAutoLock object incorrectly. + nsAutoCMonitor(void); + nsAutoCMonitor(const nsAutoCMonitor& /*aMon*/); + nsAutoCMonitor& operator =(const nsAutoCMonitor& /*aMon*/); + + // Not meant to be implemented. This makes it a compiler error to + // attempt to create an nsAutoLock object on the heap. + static void* operator new(size_t /*size*/) CPP_THROW_NEW; + static void operator delete(void* /*memory*/); +}; + +#endif // nsAutoLock_h__ + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp new file mode 100644 index 00000000..139b24a6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.cpp @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * 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 "nsEnvironment.h" +#include "prenv.h" +#include "prprf.h" +#include "nsAutoLock.h" +#include "nsBaseHashtable.h" +#include "nsHashKeys.h" +#include "nsPromiseFlatString.h" +#include "nsDependentString.h" +#include "nsNativeCharsetUtils.h" + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsEnvironment, nsIEnvironment) + +NS_METHOD +nsEnvironment::Create(nsISupports *aOuter, REFNSIID aIID, + void **aResult) +{ + nsresult rv; + *aResult = nsnull; + + if (aOuter != nsnull) { + return NS_ERROR_NO_AGGREGATION; + } + + nsEnvironment* obj = new nsEnvironment(); + if (!obj) { + return NS_ERROR_OUT_OF_MEMORY; + } + + obj->mLock = PR_NewLock(); + if (!obj->mLock) { + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = obj->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) { + delete obj; + } + return rv; +} + +nsEnvironment::~nsEnvironment() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +NS_IMETHODIMP +nsEnvironment::Exists(const nsAString& aName, PRBool *aOutValue) +{ + nsCAutoString nativeName; + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString nativeVal; +#if defined(XP_UNIX) + /* For Unix/Linux platforms we follow the Unix definition: + * An environment variable exists when |getenv()| returns a non-NULL value. + * An environment variable does not exist when |getenv()| returns NULL. + */ + const char *value = PR_GetEnv(nativeName.get()); + + *aOutValue = (value)?(PR_TRUE):(PR_FALSE); +#else + /* For non-Unix/Linux platforms we have to fall back to a + * "portable" definition (which is incorrect for Unix/Linux!!!!) + * which simply checks whether the string returned by |Get()| is empty + * or not. + */ + nsAutoString value; + Get(aName, value); + *aOutValue = (value.IsEmpty())?(PR_FALSE):(PR_TRUE); +#endif /* XP_UNIX */ + + return NS_OK; +} + +NS_IMETHODIMP +nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue) +{ + nsCAutoString nativeName; + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString nativeVal; + const char *value = PR_GetEnv(nativeName.get()); + if (value) { + rv = NS_CopyNativeToUnicode(nsDependentCString(value), aOutValue); + } else { + aOutValue.Truncate(); + rv = NS_OK; + } + + return rv; +} + +/* Environment strings must have static duration; We're gonna leak all of this + * at shutdown: this is by design, caused how Unix/Linux implement environment + * vars. + */ + +typedef nsBaseHashtableET EnvEntryType; +typedef nsTHashtable EnvHashType; + +static EnvHashType *gEnvHash = nsnull; + +static PRBool +EnsureEnvHash() +{ + if (gEnvHash) + return PR_TRUE; + + gEnvHash = new EnvHashType; + if (!gEnvHash) + return PR_FALSE; + + if(gEnvHash->Init()) + return PR_TRUE; + + delete gEnvHash; + gEnvHash = nsnull; + return PR_FALSE; +} + +NS_IMETHODIMP +nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) +{ + nsCAutoString nativeName; + nsCAutoString nativeVal; + + nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_CopyUnicodeToNative(aValue, nativeVal); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoLock lock(mLock); // autolock unlocks automagically + + if (!EnsureEnvHash()){ + return NS_ERROR_UNEXPECTED; + } + + EnvEntryType* entry = gEnvHash->PutEntry(nativeName); + if (!entry) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char* newData = PR_smprintf("%s=%s", + nativeName.get(), + nativeVal.get()); + if (!newData) { + return NS_ERROR_OUT_OF_MEMORY; + } + + PR_SetEnv(newData); + if (entry->mData) { + PR_smprintf_free(entry->mData); + } + entry->mData = newData; + return NS_OK; +} + + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h new file mode 100644 index 00000000..46e8d66a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEnvironment.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * 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 nsEnvironment_h__ +#define nsEnvironment_h__ + +#include "nsIEnvironment.h" +#include "prlock.h" + +#define NS_ENVIRONMENT_CID \ + { 0X3D68F92UL, 0X9513, 0X4E25, \ + { 0X9B, 0XE9, 0X7C, 0XB2, 0X39, 0X87, 0X41, 0X72 } } +#define NS_ENVIRONMENT_CONTRACTID "@mozilla.org/process/environment;1" + +class nsEnvironment : public nsIEnvironment +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIENVIRONMENT + + static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, + void **aResult); + +private: + nsEnvironment() { } + ~nsEnvironment(); + + PRLock *mLock; +}; + +#endif /* !nsEnvironment_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp new file mode 100644 index 00000000..7dc8f089 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.cpp @@ -0,0 +1,632 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsCOMPtr.h" +#include "nsEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsIThread.h" + +#include "nsIServiceManager.h" +#include "nsIObserverService.h" + +#include "nsString.h" + +#include "prlog.h" + +#ifdef NS_DEBUG +#include "prprf.h" +#endif + +#if defined(PR_LOGGING) && defined(DEBUG_danm) +/* found these logs useful in conjunction with netlibStreamEvent logging + from netwerk. */ +PRLogModuleInfo* gEventQueueLog = 0; +PRUint32 gEventQueueLogCount = 0; +PRUint32 gEventQueueLogPPCount = 0; +static int gEventQueueLogPPLevel = 0; +static PLEventQueue *gEventQueueLogQueue = 0; +static PRThread *gEventQueueLogThread = 0; +#endif + +// in a real system, these would be members in a header class... +static const char gActivatedNotification[] = "nsIEventQueueActivated"; +static const char gDestroyedNotification[] = "nsIEventQueueDestroyed"; + +nsEventQueueImpl::nsEventQueueImpl() +{ + NS_ADDREF_THIS(); + /* The slightly weird ownership model for eventqueues goes like this: + + General: + There's an addref from the factory generally held by whoever asked for + the queue. The queue addrefs itself (right here) and releases itself + after someone calls StopAcceptingEvents() on the queue and when it is + dark and empty (in CheckForDeactivation()). + + Chained queues: + + Eldest queue: + The eldest queue in a chain is held on to by the EventQueueService + in a hash table, so it is possible that the eldest queue may not be + released until the EventQueueService is shutdown. + You may not call StopAcceptingEvents() on this queue until you have + done so on all younger queues. + + General: + Each queue holds a reference to their immediate elder link and a weak + reference to their immediate younger link. Because you must shut down + queues from youngest to eldest, all the references will be removed. + + It happens something like: + queue->StopAcceptingEvents() + { + CheckForDeactivation() + { + -- hopefully we are able to shutdown now -- + Unlink() + { + -- remove the reference we hold to our elder queue -- + -- NULL out our elder queues weak reference to us -- + } + RELEASE ourself (to balance the ADDREF here in the constructor) + -- and we should go away. -- + } + } + + + Notes: + A dark queue no longer accepts events. An empty queue simply has no events. + */ + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Created [queue=%lx]",(long)mEventQueue)); + ++gEventQueueLogCount; +#endif + + mYoungerQueue = nsnull; + mEventQueue = nsnull; + mAcceptingEvents = PR_TRUE; + mCouldHaveEvents = PR_TRUE; +} + +nsEventQueueImpl::~nsEventQueueImpl() +{ + Unlink(); + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Destroyed [queue=%lx]",(long)mEventQueue)); + ++gEventQueueLogCount; +#endif + + if (mEventQueue) { + NotifyObservers(gDestroyedNotification); + PL_DestroyEventQueue(mEventQueue); + } +} + +NS_IMETHODIMP +nsEventQueueImpl::Init(PRBool aNative) +{ + PRThread *thread = PR_GetCurrentThread(); + if (aNative) + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread); + else + mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread); + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPRThread(PRThread* thread, PRBool aNative) +{ + if (thread == NS_CURRENT_THREAD) + { + thread = PR_GetCurrentThread(); + } + else if (thread == NS_UI_THREAD) + { + nsCOMPtr mainIThread; + nsresult rv; + + // Get the primordial thread + rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread)); + if (NS_FAILED(rv)) return rv; + + rv = mainIThread->GetPRThread(&thread); + if (NS_FAILED(rv)) return rv; + } + + if (aNative) + mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", thread); + else + mEventQueue = PL_CreateMonitoredEventQueue("Thread event queue...", thread); + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::InitFromPLQueue(PLEventQueue* aQueue) +{ + mEventQueue = aQueue; + NotifyObservers(gActivatedNotification); + return NS_OK; +} + +/* nsISupports interface implementation... */ +NS_IMPL_THREADSAFE_ISUPPORTS3(nsEventQueueImpl, + nsIEventQueue, + nsIEventTarget, + nsPIEventQueueChain) + +/* nsIEventQueue interface implementation... */ + +NS_IMETHODIMP +nsEventQueueImpl::StopAcceptingEvents() +{ + // this assertion is bogus. I should be able to shut down the eldest queue, + // as long as there are no younger children + + + NS_ASSERTION(mElderQueue || !mYoungerQueue, "attempted to disable eldest queue in chain"); + mAcceptingEvents = PR_FALSE; + CheckForDeactivation(); +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: StopAccepting [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + return NS_OK; +} + +// utility funtion to send observers a notification +void +nsEventQueueImpl::NotifyObservers(const char *aTopic) +{ + nsresult rv; + + nsCOMPtr os = do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr kungFuDeathGrip(this); + nsCOMPtr us(do_QueryInterface(kungFuDeathGrip)); + os->NotifyObservers(us, aTopic, NULL); + } +} + + +NS_IMETHODIMP +nsEventQueueImpl::InitEvent(PLEvent* aEvent, + void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor) +{ + PL_InitEvent(aEvent, owner, handler, destructor); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::PostEvent(PLEvent* aEvent) +{ + if (!mAcceptingEvents) { +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Punt posted event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + nsresult rv = NS_ERROR_FAILURE; + NS_ASSERTION(mElderQueue, "event dropped because event chain is dead"); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + rv = elder->PostEvent(aEvent); + } + return rv; + } +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Posting event [queue=%lx]", (long)mEventQueue)); + ++gEventQueueLogCount; +#endif + return PL_PostEvent(mEventQueue, aEvent) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsEventQueueImpl::PostSynchronousEvent(PLEvent* aEvent, void** aResult) +{ + if (!mAcceptingEvents) { +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Punt posted synchronous event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + nsresult rv = NS_ERROR_NO_INTERFACE; + NS_ASSERTION(mElderQueue, "event dropped because event chain is dead"); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + rv = elder->PostSynchronousEvent(aEvent, aResult); + return rv; + } + return NS_ERROR_ABORT; + } + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Posting synchronous event [queue=%lx]", (long)mEventQueue)); + ++gEventQueueLogCount; +#endif + void* result = PL_PostSynchronousEvent(mEventQueue, aEvent); + if (aResult) + *aResult = result; + + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EnterMonitor() +{ + PL_ENTER_EVENT_QUEUE_MONITOR(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::ExitMonitor() +{ + PL_EXIT_EVENT_QUEUE_MONITOR(mEventQueue); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::RevokeEvents(void* owner) +{ + PL_RevokeEvents(mEventQueue, owner); + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + elder->RevokeEvents(owner); + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::GetPLEventQueue(PLEventQueue** aEventQueue) +{ + if (!mEventQueue) + return NS_ERROR_NULL_POINTER; + + *aEventQueue = mEventQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::IsOnCurrentThread(PRBool *aResult) +{ + *aResult = PL_IsQueueOnCurrentThread( mEventQueue ); + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::IsQueueNative(PRBool *aResult) +{ + *aResult = PL_IsQueueNative(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::PendingEvents(PRBool *aResult) +{ + *aResult = PL_EventAvailable(mEventQueue); + if (!*aResult && mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + return elder->EventAvailable(*aResult); + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueImpl::ProcessPendingEvents() +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + + if (!correctThread) + return NS_ERROR_FAILURE; +#if defined(PR_LOGGING) && defined(DEBUG_danm) + ++gEventQueueLogPPLevel; + if ((gEventQueueLogQueue != mEventQueue || gEventQueueLogThread != PR_GetCurrentThread() || + gEventQueueLogCount != gEventQueueLogPPCount) && gEventQueueLogPPLevel == 1) { + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Process pending [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + gEventQueueLogPPCount = ++gEventQueueLogCount; + gEventQueueLogQueue = mEventQueue; + gEventQueueLogThread = PR_GetCurrentThread(); + } +#endif + PL_ProcessPendingEvents(mEventQueue); + + // if we're no longer accepting events and there are still events in the + // queue, then process remaining events. + if (!mAcceptingEvents && PL_EventAvailable(mEventQueue)) + PL_ProcessPendingEvents(mEventQueue); + + CheckForDeactivation(); + + if (mElderQueue) { + nsCOMPtr elder(do_QueryInterface(mElderQueue)); + if (elder) + elder->ProcessPendingEvents(); + } +#if defined(PR_LOGGING) && defined(DEBUG_danm) + --gEventQueueLogPPLevel; +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventLoop() +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + + if (!correctThread) + return NS_ERROR_FAILURE; + + PL_EventLoop(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::EventAvailable(PRBool& aResult) +{ + aResult = PL_EventAvailable(mEventQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetEvent(PLEvent** aResult) +{ + *aResult = PL_GetEvent(mEventQueue); + CheckForDeactivation(); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::HandleEvent(PLEvent* aEvent) +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + if (!correctThread) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: handle event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + PL_HandleEvent(aEvent); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::WaitForEvent(PLEvent** aResult) +{ + PRBool correctThread = PL_IsQueueOnCurrentThread(mEventQueue); + NS_ASSERTION(correctThread, "attemping to process events on the wrong thread"); + if (!correctThread) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: wait for event [queue=%lx, accept=%d, could=%d]", + (long)mEventQueue,(int)mAcceptingEvents,(int)mCouldHaveEvents)); + ++gEventQueueLogCount; +#endif + *aResult = PL_WaitForEvent(mEventQueue); + CheckForDeactivation(); + return NS_OK; +} + +NS_IMETHODIMP_(PRInt32) +nsEventQueueImpl::GetEventQueueSelectFD() +{ + return PL_GetEventQueueSelectFD(mEventQueue); +} + +NS_METHOD +nsEventQueueImpl::Create(nsISupports *aOuter, + REFNSIID aIID, + void **aResult) +{ + nsEventQueueImpl* evt = new nsEventQueueImpl(); + if (evt == NULL) + return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = evt->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) { + delete evt; + } + return rv; +} + +// ---------------- nsPIEventQueueChain ----------------- + +NS_IMETHODIMP +nsEventQueueImpl::AppendQueue(nsIEventQueue *aQueue) +{ + nsresult rv; + nsCOMPtr end; + nsCOMPtr queueChain(do_QueryInterface(aQueue)); + + if (!aQueue) + return NS_ERROR_NO_INTERFACE; + +/* this would be nice + NS_ASSERTION(aQueue->mYoungerQueue == NULL && aQueue->mElderQueue == NULL, + "event queue repeatedly appended to queue chain"); +*/ + rv = NS_ERROR_NO_INTERFACE; + +#ifdef NS_DEBUG + int depth = 0; + nsEventQueueImpl *next = this; + while (next && depth < 100) { + next = NS_STATIC_CAST(nsEventQueueImpl *, next->mYoungerQueue); + ++depth; + } + if (depth > 5) { + char warning[80]; + PR_snprintf(warning, sizeof(warning), + "event queue chain length is %d. this is almost certainly a leak.", depth); + NS_WARNING(warning); + } +#endif + + // (be careful doing this outside nsEventQueueService's mEventQMonitor) + + GetYoungest(getter_AddRefs(end)); + nsCOMPtr endChain(do_QueryInterface(end)); + if (endChain) { + endChain->SetYounger(queueChain); + queueChain->SetElder(endChain); + rv = NS_OK; + } + return rv; +} + +NS_IMETHODIMP +nsEventQueueImpl::Unlink() +{ + nsCOMPtr young = mYoungerQueue, + old = mElderQueue; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: unlink [queue=%lx, younger=%lx, elder=%lx]", + (long)mEventQueue,(long)mYoungerQueue, (long)mElderQueue.get())); + ++gEventQueueLogCount; +#endif + + // this is probably OK, but shouldn't happen by design, so tell me if it does + NS_ASSERTION(!mYoungerQueue, "event queue chain broken in middle"); + + // break links early in case the Release cascades back onto us + mYoungerQueue = nsnull; + mElderQueue = nsnull; + + if (young) + young->SetElder(old); + if (old) { + old->SetYounger(young); + } + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYoungest(nsIEventQueue **aQueue) +{ + if (mYoungerQueue) + return mYoungerQueue->GetYoungest(aQueue); + + nsIEventQueue *answer = NS_STATIC_CAST(nsIEventQueue *, this); + NS_ADDREF(answer); + *aQueue = answer; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYoungestActive(nsIEventQueue **aQueue) +{ + nsCOMPtr answer; + + if (mYoungerQueue) + mYoungerQueue->GetYoungestActive(getter_AddRefs(answer)); + if (!answer) { + if (mAcceptingEvents && mCouldHaveEvents) + answer = NS_STATIC_CAST(nsIEventQueue *, this); + } + *aQueue = answer; + NS_IF_ADDREF(*aQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::SetYounger(nsPIEventQueueChain *aQueue) +{ + mYoungerQueue = aQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::SetElder(nsPIEventQueueChain *aQueue) +{ + mElderQueue = aQueue; + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueImpl::GetYounger(nsIEventQueue **aQueue) +{ + if (!mYoungerQueue) { + *aQueue = nsnull; + return NS_OK; + } + return mYoungerQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue); +} + +NS_IMETHODIMP +nsEventQueueImpl::GetElder(nsIEventQueue **aQueue) +{ + if (!mElderQueue) { + *aQueue = nsnull; + return NS_OK; + } + return mElderQueue->QueryInterface(NS_GET_IID(nsIEventQueue), (void**)&aQueue); +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h new file mode 100644 index 00000000..51f33e47 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueue.h @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "prmon.h" +#include "nsIEventQueue.h" +#include "nsPIEventQueueChain.h" + +class nsEventQueueImpl : public nsIEventQueue, + public nsPIEventQueueChain +{ +public: + nsEventQueueImpl(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIEVENTTARGET + NS_DECL_NSIEVENTQUEUE + + // Helpers + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + + static const nsCID& CID() { static nsCID cid = NS_EVENTQUEUE_CID; return cid; } + + // nsPIEventQueueChain interface + NS_IMETHOD AppendQueue(nsIEventQueue *aQueue); + NS_IMETHOD Unlink(); + NS_IMETHOD GetYoungest(nsIEventQueue **aQueue); + NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue); + NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue); + NS_IMETHOD GetYounger(nsIEventQueue **aQueue); + NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue); + NS_IMETHOD GetElder(nsIEventQueue **aQueue); + +private: + ~nsEventQueueImpl(); + + PLEventQueue *mEventQueue; + PRBool mAcceptingEvents, // accept new events or pass them on? + mCouldHaveEvents; // accepting new ones, or still have old ones? + nsCOMPtr mElderQueue; // younger can hold on to elder + nsPIEventQueueChain *mYoungerQueue; // but elder can't hold on to younger + + void NotifyObservers(const char *aTopic); + + void CheckForDeactivation() { + if (mCouldHaveEvents && !mAcceptingEvents && !PL_EventAvailable(mEventQueue)) { + if (PL_IsQueueOnCurrentThread(mEventQueue)) { + mCouldHaveEvents = PR_FALSE; + NS_RELEASE_THIS(); // balance ADDREF from the constructor + } else + NS_ERROR("CheckForDeactivation called from wrong thread!"); + } + } +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp new file mode 100644 index 00000000..4fbb65aa --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rick Potts + * Ramiro Estrugo + * Warren Harris + * Leaf Nunes + * David Matiskella + * David Hyatt + * Seth Spitzer + * Suresh Duddi + * Bruce Mitchener + * Scott Collins + * Daniel Matejka + * Doug Turner + * Stuart Parmenter + * Mike Kaply + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsEventQueueService.h" +#include "prmon.h" +#include "nsIComponentManager.h" +#include "nsIThread.h" +#include "nsPIEventQueueChain.h" + +#include "prlog.h" + +#if defined(PR_LOGGING) || defined(DEBUG_danm) +extern PRLogModuleInfo* gEventQueueLog; +extern PRUint32 gEventQueueLogCount; +#endif + +static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); + +nsEventQueueServiceImpl::nsEventQueueServiceImpl() +{ + mEventQMonitor = PR_NewMonitor(); +#if defined(PR_LOGGING) && defined(DEBUG_danm) + if (!gEventQueueLog) + gEventQueueLog = PR_NewLogModule("nseventqueue"); +#endif +} + +PR_STATIC_CALLBACK(PLDHashOperator) +hash_enum_remove_queues(const void *aThread_ptr, + nsCOMPtr& aEldestQueue, + void* closure) +{ + // 'aQueue' should be the eldest queue. + nsCOMPtr pie(do_QueryInterface(aEldestQueue)); + nsCOMPtr q; + + // stop accepting events for youngest to oldest + pie->GetYoungest(getter_AddRefs(q)); + while (q) { + q->StopAcceptingEvents(); + + nsCOMPtr pq(do_QueryInterface(q)); + pq->GetElder(getter_AddRefs(q)); + } + + return PL_DHASH_REMOVE; +} + +nsEventQueueServiceImpl::~nsEventQueueServiceImpl() +{ + // XXX make it so we only enum over this once + mEventQTable.Enumerate(hash_enum_remove_queues, nsnull); // call StopAcceptingEvents on everything and clear out the hashtable + + PR_DestroyMonitor(mEventQMonitor); +} + +nsresult +nsEventQueueServiceImpl::Init() +{ + NS_ENSURE_TRUE(mEventQMonitor, NS_ERROR_OUT_OF_MEMORY); + + // This will only be called once on the main thread, so it's safe to + // not enter the monitor here. + if (!mEventQTable.Init()) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // ensure that a main thread event queue exists! + nsresult rv; + nsCOMPtr mainThread; + rv = nsIThread::GetMainThread(getter_AddRefs(mainThread)); + if (NS_SUCCEEDED(rv)) { + PRThread *thr; + rv = mainThread->GetPRThread(&thr); + if (NS_SUCCEEDED(rv)) + rv = CreateEventQueue(thr, PR_TRUE); + } + return rv; +} + +/* nsISupports interface implementation... */ +NS_IMPL_THREADSAFE_ISUPPORTS1(nsEventQueueServiceImpl, nsIEventQueueService) + +/* nsIEventQueueService interface implementation... */ + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateThreadEventQueue() +{ + return CreateEventQueue(PR_GetCurrentThread(), PR_TRUE); +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateMonitoredThreadEventQueue() +{ + return CreateEventQueue(PR_GetCurrentThread(), PR_FALSE); +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromIThread(nsIThread *aThread, PRBool aNative, + nsIEventQueue **aResult) +{ + nsresult rv; + PRThread *prThread; + + rv = aThread->GetPRThread(&prThread); + if (NS_SUCCEEDED(rv)) { + rv = CreateEventQueue(prThread, aNative); // addrefs + if (NS_SUCCEEDED(rv)) + rv = GetThreadEventQueue(prThread, aResult); // addrefs + } + return rv; +} + +// private method +NS_IMETHODIMP +nsEventQueueServiceImpl::MakeNewQueue(PRThread* thread, + PRBool aNative, + nsIEventQueue **aQueue) +{ + nsresult rv; + nsCOMPtr queue = do_CreateInstance(kEventQueueCID, &rv); + + if (NS_SUCCEEDED(rv)) { + rv = queue->InitFromPRThread(thread, aNative); + } + *aQueue = queue; + NS_IF_ADDREF(*aQueue); + return rv; +} + +// private method +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateEventQueue(PRThread *aThread, PRBool aNative) +{ + nsresult rv = NS_OK; + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + /* create only one event queue chain per thread... */ + if (!mEventQTable.GetWeak(aThread)) { + nsCOMPtr queue; + + // we don't have one in the table + rv = MakeNewQueue(aThread, aNative, getter_AddRefs(queue)); // create new queue + mEventQTable.Put(aThread, queue); // add to the table (initial addref) + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + + +NS_IMETHODIMP +nsEventQueueServiceImpl::DestroyThreadEventQueue(void) +{ + nsresult rv = NS_OK; + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + PRThread* currentThread = PR_GetCurrentThread(); + nsIEventQueue* queue = mEventQTable.GetWeak(currentThread); + if (queue) { + queue->StopAcceptingEvents(); // tell the queue to stop accepting events + queue = nsnull; // Queue may die on the next line + mEventQTable.Remove(currentThread); // remove nsIEventQueue from hash table (releases) + } + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult) +{ + // Create our thread queue using the component manager + nsresult rv; + nsCOMPtr queue = do_CreateInstance(kEventQueueCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = queue->InitFromPLQueue(aPLEventQueue); + if (NS_FAILED(rv)) return rv; + + *aResult = queue; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + + +// Return the active event queue on our chain +/* inline */ +nsresult nsEventQueueServiceImpl::GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult) +{ + nsCOMPtr answer; + + if (queue) { + nsCOMPtr ourChain(do_QueryInterface(queue)); + if (ourChain) + ourChain->GetYoungestActive(getter_AddRefs(answer)); + else + answer = queue; + } + + *aResult = answer; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + + +// create new event queue, append it to the current thread's chain of event queues. +// return it, addrefed. +NS_IMETHODIMP +nsEventQueueServiceImpl::PushThreadEventQueue(nsIEventQueue **aNewQueue) +{ + nsresult rv = NS_OK; + PRThread* currentThread = PR_GetCurrentThread(); + PRBool native = PR_TRUE; // native by default as per old comment + + + NS_ASSERTION(aNewQueue, "PushThreadEventQueue called with null param"); + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsIEventQueue* queue = mEventQTable.GetWeak(currentThread); + + NS_ASSERTION(queue, "pushed event queue on top of nothing"); + + if (queue) { // find out what kind of queue our relatives are + nsCOMPtr youngQueue; + GetYoungestEventQueue(queue, getter_AddRefs(youngQueue)); + if (youngQueue) { + youngQueue->IsQueueNative(&native); + } + } + + nsIEventQueue* newQueue = nsnull; + MakeNewQueue(currentThread, native, &newQueue); // create new queue; addrefs + + if (!queue) { + // shouldn't happen. as a fallback, we guess you wanted a native queue + mEventQTable.Put(currentThread, newQueue); + } + + // append to the event queue chain + nsCOMPtr ourChain(do_QueryInterface(queue)); // QI the queue in the hash table + if (ourChain) + ourChain->AppendQueue(newQueue); // append new queue to it + + *aNewQueue = newQueue; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PLEventQueue *equeue; + (*aNewQueue)->GetPLEventQueue(&equeue); + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Service push queue [queue=%lx]",(long)equeue)); + ++gEventQueueLogCount; +#endif + + // Release the EventQ lock... + PR_ExitMonitor(mEventQMonitor); + return rv; +} + +// disable and release the given queue (though the last one won't be released) +NS_IMETHODIMP +nsEventQueueServiceImpl::PopThreadEventQueue(nsIEventQueue *aQueue) +{ + PRThread* currentThread = PR_GetCurrentThread(); + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsCOMPtr eldestQueue; + mEventQTable.Get(currentThread, getter_AddRefs(eldestQueue)); + + // If we are popping the eldest queue, remove its mEventQTable entry. + if (aQueue == eldestQueue) + mEventQTable.Remove(currentThread); + + // Exit the monitor before processing pending events to avoid deadlock. + // Our reference from the eldestQueue nsCOMPtr will keep that object alive. + // Since it is thread-private, no one else can race with us here. + PR_ExitMonitor(mEventQMonitor); + if (!eldestQueue) + return NS_ERROR_FAILURE; + +#if defined(PR_LOGGING) && defined(DEBUG_danm) + PLEventQueue *equeue; + aQueue->GetPLEventQueue(&equeue); + PR_LOG(gEventQueueLog, PR_LOG_DEBUG, + ("EventQueue: Service pop queue [queue=%lx]",(long)equeue)); + ++gEventQueueLogCount; +#endif + aQueue->StopAcceptingEvents(); + aQueue->ProcessPendingEvents(); // make sure we don't orphan any events + + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult) +{ + /* Parameter validation... */ + if (NULL == aResult) return NS_ERROR_NULL_POINTER; + + PRThread* keyThread = aThread; + + if (keyThread == NS_CURRENT_THREAD) + { + keyThread = PR_GetCurrentThread(); + } + else if (keyThread == NS_UI_THREAD) + { + nsCOMPtr mainIThread; + + // Get the primordial thread + nsresult rv = nsIThread::GetMainThread(getter_AddRefs(mainIThread)); + if (NS_FAILED(rv)) return rv; + + rv = mainIThread->GetPRThread(&keyThread); + if (NS_FAILED(rv)) return rv; + } + + /* Enter the lock that protects the EventQ hashtable... */ + PR_EnterMonitor(mEventQMonitor); + + nsCOMPtr queue; + mEventQTable.Get(keyThread, getter_AddRefs(queue)); + + PR_ExitMonitor(mEventQMonitor); + + if (queue) { + GetYoungestEventQueue(queue, aResult); // get the youngest active queue + } else { + *aResult = nsnull; + } + // XXX: Need error code for requesting an event queue when none exists... + if (!*aResult) { + return NS_ERROR_NOT_AVAILABLE; + } + return NS_OK; +} + + +NS_IMETHODIMP +nsEventQueueServiceImpl::ResolveEventQueue(nsIEventQueue* queueOrConstant, nsIEventQueue* *resultQueue) +{ + if (queueOrConstant == NS_CURRENT_EVENTQ) { + return GetThreadEventQueue(NS_CURRENT_THREAD, resultQueue); + } + else if (queueOrConstant == NS_UI_THREAD_EVENTQ) { + return GetThreadEventQueue(NS_UI_THREAD, resultQueue); + } + + *resultQueue = queueOrConstant; + NS_ADDREF(*resultQueue); + return NS_OK; +} + +NS_IMETHODIMP +nsEventQueueServiceImpl::GetSpecialEventQueue(PRInt32 aQueue, + nsIEventQueue* *_retval) +{ + nsresult rv; + + // barf if someone gave us a zero pointer + // + if (!_retval) { + return NS_ERROR_NULL_POINTER; + } + + // try and get the requested event queue, returning NS_ERROR_FAILURE if there + // is a problem. GetThreadEventQueue() does the AddRef() for us. + // + switch (aQueue) { + case CURRENT_THREAD_EVENT_QUEUE: + rv = GetThreadEventQueue(NS_CURRENT_THREAD, _retval); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + break; + + case UI_THREAD_EVENT_QUEUE: + rv = GetThreadEventQueue(NS_UI_THREAD, _retval); + if (NS_FAILED(rv)) { + return NS_ERROR_FAILURE; + } + break; + + // somebody handed us a bogus constant + // + default: + return NS_ERROR_ILLEGAL_VALUE; + } + + return NS_OK; +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h new file mode 100644 index 00000000..6fddb941 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueService.h @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsEventQueueService_h__ +#define nsEventQueueService_h__ + +#include "nsIEventQueueService.h" +#include "nsInterfaceHashtable.h" +#include "nsHashKeys.h" +#include "nsIEventQueue.h" + +//////////////////////////////////////////////////////////////////////////////// + +class nsEventQueueServiceImpl : public nsIEventQueueService +{ +public: + nsEventQueueServiceImpl(); + + nsresult Init(); + + // nsISupports interface... + NS_DECL_ISUPPORTS + + // nsIEventQueueService interface... + NS_DECL_NSIEVENTQUEUESERVICE + +private: + ~nsEventQueueServiceImpl(); + + /* Create a queue for the given thread if one does not exist. + Addref the descriptor in any case. parameter aNative is + ignored if the queue already exists. */ + NS_IMETHOD CreateEventQueue(PRThread *aThread, PRBool aNative); + NS_IMETHOD MakeNewQueue(PRThread* thread, PRBool aNative, nsIEventQueue **aQueue); + inline nsresult GetYoungestEventQueue(nsIEventQueue *queue, nsIEventQueue **aResult); + + nsInterfaceHashtable mEventQTable; + PRMonitor *mEventQMonitor; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsEventQueueService_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h new file mode 100644 index 00000000..5df2e406 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsEventQueueUtils.h @@ -0,0 +1,78 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 nsEventQueueUtils_h__ +#define nsEventQueueUtils_h__ + +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" + +inline nsresult +NS_GetEventQueueService(nsIEventQueueService **result) +{ + static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); + return CallGetService(kEventQueueServiceCID, result); +} + +inline nsresult +NS_GetCurrentEventQ(nsIEventQueue **result, + nsIEventQueueService *serv = nsnull) +{ + nsCOMPtr eqs; + if (!serv) { + nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs)); + if (NS_FAILED(rv)) return rv; + serv = eqs; + } + return serv->GetThreadEventQueue(NS_CURRENT_THREAD, result); +} + +inline nsresult +NS_GetMainEventQ(nsIEventQueue **result, + nsIEventQueueService *serv = nsnull) +{ + nsCOMPtr eqs; + if (!serv) { + nsresult rv = NS_GetEventQueueService(getter_AddRefs(eqs)); + if (NS_FAILED(rv)) return rv; + serv = eqs; + } + return serv->GetThreadEventQueue(NS_UI_THREAD, result); +} + +#endif // !nsEventQueueUtils_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl new file mode 100644 index 00000000..95351346 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEnvironment.idl @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla embedding code. + * + * The Initial Developers of the Original Code are + * Benjamin Smedberg and + * Roland Mainz . + * + * Portions created by the Initial Developer are Copyright (C) 2003/2004 + * 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 "nsISupports.idl" + +/** + * Scriptable access to the current process environment. + * + */ +[scriptable, uuid(101d5941-d820-4e85-a266-9a3469940807)] +interface nsIEnvironment : nsISupports +{ + /** + * Set the value of an environment variable. + * + * @param aName the variable name to set. + * @param aValue the value to set. + */ + void set(in AString aName, in AString aValue); + + /** + * Get the value of an environment variable. + * + * @param aName the variable name to retrieve. + * @return returns the value of the env variable. An empty string + * will be returned when the env variable does not exist or + * when the value itself is an empty string - please use + * |exists()| to probe whether the env variable exists + * or not. + */ + AString get(in AString aName); + + /** + * Check the existence of an environment variable. + * This method checks whether an environment variable is present in + * the environment or not. + * + * - For Unix/Linux platforms we follow the Unix definition: + * An environment variable exists when |getenv()| returns a non-NULL value. + * An environment variable does not exist when |getenv()| returns NULL. + * - For non-Unix/Linux platforms we have to fall back to a + * "portable" definition (which is incorrect for Unix/Linux!!!!) + * which simply checks whether the string returned by |Get()| is empty + * or not. + * + * @param aName the variable name to probe. + * @return if the variable has been set, the value returned is + * PR_TRUE. If the variable was not defined in the + * environment PR_FALSE will be returned. + */ + boolean exists(in AString aName); +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl new file mode 100644 index 00000000..416c80a1 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueue.idl @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * David Hyatt + * Suresh Duddi + * Doug Turner + * Judson Valeski + * Dan Matejka + * Ray Whitmer + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsIEventTarget.idl" + +%{C++ +#include "prthread.h" + +// {13D86C61-00A9-11d3-9F2A-00400553EEF0} +#define NS_EVENTQUEUE_CID \ +{ 0x13d86c61, 0xa9, 0x11d3, { 0x9f, 0x2a, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } } + +#define NS_EVENTQUEUE_CONTRACTID "@mozilla.org/event-queue;1" +#define NS_EVENTQUEUE_CLASSNAME "Event Queue" + +%} + +// some forward decls +// +[ptr] native PLEventQueuePtr(PLEventQueue); +[ptr] native PRThreadPtr(PRThread); +native PRStatus(PRStatus); +[ref] native PRBoolRef(PRBool); +native PLHandleEventProc(PLHandleEventProc); +native PLDestroyEventProc(PLDestroyEventProc); + +[scriptable, uuid(176AFB41-00A4-11d3-9F2A-00400553EEF0)] +interface nsIEventQueue : nsIEventTarget +{ + [noscript] void initEvent(in PLEventPtr aEvent, + in voidPtr owner, + in PLHandleEventProc handler, + in PLDestroyEventProc destructor); + + [noscript] void postSynchronousEvent(in PLEventPtr aEvent, + out voidPtr aResult); + + boolean pendingEvents(); + void processPendingEvents(); + void eventLoop(); + + [noscript] void eventAvailable(in PRBoolRef aResult); + [noscript] PLEventPtr getEvent(); + [noscript] void handleEvent(in PLEventPtr aEvent); + [noscript] PLEventPtr waitForEvent(); + + [notxpcom] PRInt32 getEventQueueSelectFD(); + + void init(in boolean aNative); + [noscript] void initFromPRThread(in PRThreadPtr thread, + in boolean aNative); + [noscript] void initFromPLQueue(in PLEventQueuePtr aQueue); + + void enterMonitor(); + void exitMonitor(); + + [noscript] void revokeEvents(in voidPtr owner); + [noscript] PLEventQueuePtr getPLEventQueue(); + + boolean isQueueNative(); + + // effectively kill the queue. warning: the queue is allowed to delete + // itself any time after this. + void stopAcceptingEvents(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl new file mode 100644 index 00000000..e9c93e86 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventQueueService.idl @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rick Potts + * David Matiskella + * David Hyatt + * Suresh Duddi + * Scott Collins + * Dan Matejka + * Doug Turner + * Ray Whitmer + * Dan Mosedale + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" +#include "nsIEventQueue.idl" + +%{C++ +#include "prthread.h" +#include "plevent.h" + +/* be761f00-a3b0-11d2-996c-0080c7cb1080 */ +#define NS_EVENTQUEUESERVICE_CID \ +{ 0xbe761f00, 0xa3b0, 0x11d2, \ + {0x99, 0x6c, 0x00, 0x80, 0xc7, 0xcb, 0x10, 0x80} } + +#define NS_EVENTQUEUESERVICE_CONTRACTID "@mozilla.org/event-queue-service;1" +#define NS_EVENTQUEUESERVICE_CLASSNAME "Event Queue Service" + +#define NS_CURRENT_THREAD ((PRThread*)0) +#define NS_CURRENT_EVENTQ ((nsIEventQueue*)0) + +#define NS_UI_THREAD ((PRThread*)1) +#define NS_UI_THREAD_EVENTQ ((nsIEventQueue*)1) + +%} + +/* a forward decl */ +interface nsIThread; + +[scriptable, uuid(a6cf90dc-15b3-11d2-932e-00805f8add32)] +interface nsIEventQueueService : nsISupports +{ + /** + * Creates and holds a native event queue for the current thread. + * "Native" queues have an associated callback mechanism which is + * automatically triggered when an event is posted. See plevent.c for + * details. + * @return NS_OK on success, or a host of failure indications + */ + void createThreadEventQueue(); + + /** + * Creates and hold a monitored event queue for the current thread. + * "Monitored" queues have no callback processing mechanism. + * @return NS_OK on success, or a host of failure indications + */ + void createMonitoredThreadEventQueue(); + + /** + * Somewhat misnamed, this method releases the service's hold on the event + * queue(s) for this thread. Subsequent attempts to access this thread's + * queue (GetThreadEventQueue, for example) may fail, though the queue itself + * will be destroyed only after all references to it are released and the + * queue itself is no longer actively processing events. + * @return nonsense. + */ + void destroyThreadEventQueue(); + + nsIEventQueue createFromIThread(in nsIThread aThread, + in boolean aNative); + + [noscript] nsIEventQueue createFromPLEventQueue(in PLEventQueuePtr + aPLEventQueue); + + // Add a new event queue for the current thread, making it the "current" + // queue. Return that queue, addrefed. + nsIEventQueue pushThreadEventQueue(); + + // release and disable the queue + void popThreadEventQueue(in nsIEventQueue aQueue); + + [noscript] nsIEventQueue getThreadEventQueue(in PRThreadPtr aThread); + + /** + * @deprecated in favor of getSpecialEventQueue, since that's + * scriptable and this isn't. + * + * Check for any "magic" event queue constants (NS_CURRENT_EVENTQ, + * NS_UI_THREAD_EVENTQ) and return the real event queue that they + * represent, AddRef()ed. Otherwise, return the event queue passed + * in, AddRef()ed. This is not scriptable because the arguments in + * question may be magic constants rather than real nsIEventQueues. + * + * @arg queueOrConstant either a real event queue or a magic + * constant to be resolved + * + * @return a real event queue, AddRef()ed + */ + [noscript] nsIEventQueue resolveEventQueue(in nsIEventQueue queueOrConstant); + + /** + * Returns the appropriate special event queue, AddRef()ed. Really + * just a scriptable version of ResolveEventQueue. + * + * @arg aQueue Either CURRENT_THREAD_EVENT_QUEUE or + * UI_THREAD_EVENT_QUEUE + * @return The requested nsIEventQueue, AddRef()ed + * @exception NS_ERROR_NULL_POINTER Zero pointer passed in for return value + * @exception NS_ERROR_ILLEGAL_VALUE Bogus constant passed in aQueue + * @exception NS_ERROR_FAILURE Error while calling + * GetThreadEventQueue() + */ + nsIEventQueue getSpecialEventQueue(in long aQueue); + + const long CURRENT_THREAD_EVENT_QUEUE = 0; + const long UI_THREAD_EVENT_QUEUE = 1; + +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl new file mode 100644 index 00000000..3b19d9ca --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIEventTarget.idl @@ -0,0 +1,67 @@ +/* ***** 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 Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * 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 "nsISupports.idl" + +%{C++ +#include "plevent.h" +%} + +[ptr] native PLEventPtr(PLEvent); + +/** + * nsIEventTarget + * + * This interface is used to dispatch events to a particular thread. In many + * cases the event target also supports nsIEventQueue. + */ +[scriptable, uuid(ea99ad5b-cc67-4efb-97c9-2ef620a59f2a)] +interface nsIEventTarget : nsISupports +{ + /** + * Method for posting an asynchronous event to the event target. If this + * method succeeds, then the event will be dispatched on the target thread. + * + * @param aEvent + * The event to dispatched. + */ + [noscript] void postEvent(in PLEventPtr aEvent); + + /** + * This method returns true if the event target is the current thread. + */ + boolean isOnCurrentThread(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl new file mode 100644 index 00000000..07769cb7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIProcess.idl @@ -0,0 +1,32 @@ +#include "nsIFile.idl" +#include "nsISupports.idl" + +[scriptable, uuid(9da0b650-d07e-4617-a18a-250035572ac8)] + +interface nsIProcess : nsISupports +{ + void init(in nsIFile executable); + void initWithPid(in unsigned long pid); + + void kill(); + + /** XXX what charset? **/ + /** Executes the file this object was initialized with + * @param blocking Whether to wait until the process terminates before returning or not + * @param args An array of arguments to pass to the process + * @param count The length of the args array + * @return the PID of the newly spawned process */ + unsigned long run(in boolean blocking, [array, size_is(count)] in string args, in unsigned long count); + + readonly attribute nsIFile location; + readonly attribute unsigned long pid; + readonly attribute string processName; + readonly attribute unsigned long processSignature; + readonly attribute long exitValue; +}; + +%{C++ + +#define NS_PROCESS_CONTRACTID "@mozilla.org/process/util;1" +#define NS_PROCESS_CLASSNAME "Process Specification" +%} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl new file mode 100644 index 00000000..1cedda38 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIRunnable.idl @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(4a2abaf0-6886-11d3-9382-00104ba0fd40)] +interface nsIRunnable : nsISupports +{ + void run(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl new file mode 100644 index 00000000..f28d6ec9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsIThread.idl @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +%{C++ +#include "prthread.h" + +#define NS_THREAD_CID \ +{ /* 85CE5510-7808-11d3-A181-0050041CAF44 */ \ + 0x85ce5510, \ + 0x7808, \ + 0x11d3, \ + {0xa1, 0x81, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ +} + +#define NS_THREAD_CONTRACTID "@mozilla.org/thread;1" +#define NS_THREAD_CLASSNAME "Thread" +#if 0 +%} + +typedef PRUint32 PRThreadPriority; +typedef PRUint32 PRThreadScope; +typedef PRUint32 PRThreadState; + +%{C++ +#endif +%} + +interface nsIRunnable; + +[ptr] native PRThread(PRThread); + +[scriptable, uuid(6be5e380-6886-11d3-9382-00104ba0fd40)] +interface nsIThread : nsISupports +{ + // These must all match the values used in prthread.h + const PRUint32 PRIORITY_LOW = 0; + const PRUint32 PRIORITY_NORMAL = 1; + const PRUint32 PRIORITY_HIGH = 2; + const PRUint32 PRIORITY_URGENT = 3; + + const PRUint32 SCOPE_LOCAL = 0; + const PRUint32 SCOPE_GLOBAL = 1; + const PRUint32 SCOPE_BOUND = 2; + + const PRUint32 STATE_JOINABLE = 0; + const PRUint32 STATE_UNJOINABLE = 1; + + void join(); + void interrupt(); + + attribute PRThreadPriority priority; + readonly attribute PRThreadScope scope; + readonly attribute PRThreadState state; + + [noscript] PRThread GetPRThread(); + + void init(in nsIRunnable aRunnable, + in PRUint32 aStackSize, + in PRThreadPriority aPriority, + in PRThreadScope aScope, + in PRThreadState aState); + + /* + * Get the currently running thread (really a static method sort of thing). + */ + readonly attribute nsIThread currentThread; + + /* + * Sleep to at least this many milliseconds (only works on currrent thread). + */ + void sleep(in PRUint32 msec); + +%{C++ + // returns the nsIThread for the current thread: + static NS_COM nsresult GetCurrent(nsIThread* *result); + + // returns the nsIThread for an arbitrary PRThread: + static NS_COM nsresult GetIThread(PRThread* prthread, nsIThread* *result); + + // initializes the "main" thread (really, just saves the current thread + // at time of calling. meant to be called once at app startup, in lieu + // of proper static initializers, to save the primordial thread + // for later recall.) + static NS_COM nsresult SetMainThread(); + + // return the "main" thread + static NS_COM nsresult GetMainThread(nsIThread **result); + + static NS_COM PRBool IsMainThread(); +%} +}; + +%{C++ +extern NS_COM nsresult +NS_NewThread(nsIThread* *result, + nsIRunnable* runnable, + PRUint32 stackSize = 0, + PRThreadState state = PR_UNJOINABLE_THREAD, + PRThreadPriority priority = PR_PRIORITY_NORMAL, + PRThreadScope scope = PR_GLOBAL_THREAD); + +extern NS_COM nsresult +NS_NewThread(nsIThread* *result, + PRUint32 stackSize = 0, + PRThreadState state = PR_UNJOINABLE_THREAD, + PRThreadPriority priority = PR_PRIORITY_NORMAL, + PRThreadScope scope = PR_GLOBAL_THREAD); +%} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl new file mode 100644 index 00000000..855d538d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimer.idl @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +interface nsIObserver; + +%{C++ +/** + * The signature of the timer callback function passed to initWithCallback. This + * is the function that will get called when the timer expires if the timer is + * initialized via initWithCallback. + * + * @param aTimer the timer which has expired + * @param aClosure opaque parameter passed to initWithCallback + * + * Implementers should return the following: + * + * @return NS_OK + * + */ +class nsITimer; +typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure); +%} + +native nsTimerCallbackFunc(nsTimerCallbackFunc); + +/** + * The callback interface for timers. + */ +interface nsITimer; + +[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)] +interface nsITimerCallback : nsISupports +{ + /** + * @param aTimer the timer which has expired + */ + void notify(in nsITimer timer); +}; + + +/** + * nsITimer instances must be initialized by calling one of the "init" methods + * documented below. You may also re-initialize an existing instance with new + * delay to avoid the overhead of destroying and creating a timer. It is not + * necessary to cancel the timer in that case. + */ +[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)] +interface nsITimer : nsISupports +{ + /* Timer types */ + + /** + * Type of a timer that fires once only. + */ + const short TYPE_ONE_SHOT = 0; + + /** + * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted + * until its callback completes. Specified timer period will be at least + * the time between when processing for last firing the callback completes + * and when the next firing occurs. + * + * This is the preferable repeating type for most situations. + */ + const short TYPE_REPEATING_SLACK = 1; + + /** + * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period + * between firings. The processing time for each timer callback should not + * influence the timer period. However, if the processing for the last + * timer firing could not be completed until just before the next firing + * occurs, then you could have two timer notification routines being + * executed in quick succession. + */ + const short TYPE_REPEATING_PRECISE = 2; + + /** + * Initialize a timer that will fire after the said delay. + * A user must keep a reference to this timer till it is + * is no longer needed or has been cancelled. + * + * @param aObserver the callback object that observes the + * ``timer-callback'' topic with the subject being + * the timer itself when the timer fires: + * + * observe(nsISupports aSubject, => nsITimer + * string aTopic, => ``timer-callback'' + * wstring data => null + * + * @param aDelay delay in milliseconds for timer to fire + * @param aType timer type per TYPE* consts defined above + */ + void init(in nsIObserver aObserver, in unsigned long aDelay, + in unsigned long aType); + + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes a function to call and a closure to pass to + * that function. + * + * @param aFunc The function to invoke + * @param aClosure An opaque pointer to pass to that function + * @param aDelay The millisecond interval + * @param aType Timer type per TYPE* consts defined above + */ + [noscript] void initWithFuncCallback(in nsTimerCallbackFunc aCallback, + in voidPtr aClosure, + in unsigned long aDelay, + in unsigned long aType); + + /** + * Initialize a timer to fire after the given millisecond interval. + * This version takes a function to call and a closure to pass to + * that function. + * + * @param aFunc nsITimerCallback interface to call when timer expires + * @param aDelay The millisecond interval + * @param aType Timer type per TYPE* consts defined above + */ + void initWithCallback(in nsITimerCallback aCallback, + in unsigned long aDelay, + in unsigned long aType); + + /** + * Cancel the timer. This method works on all types, not just on repeating + * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse + * it by re-initializing it (to avoid object destruction and creation costs + * by conserving one timer instance). + */ + void cancel(); + + /** + * The millisecond delay of the timeout + */ + attribute unsigned long delay; + + /** + * The timer type : one shot or repeating + */ + attribute unsigned long type; + + /** + * The opaque pointer pass to initWithCallback. + */ + [noscript] readonly attribute voidPtr closure; +}; + +%{C++ +#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1" +#define NS_TIMER_CALLBACK_TOPIC "timer-callback" +%} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl new file mode 100644 index 00000000..c334ae19 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerInternal.idl @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + + +[scriptable, uuid(6dd8f185-ceb8-4878-8e38-2d13edc2d079)] +interface nsITimerInternal : nsISupports +{ + attribute boolean idle; +}; + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl new file mode 100644 index 00000000..f391d313 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsITimerManager.idl @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsISupports.idl" + +[scriptable, uuid(8fce8c6a-1dd2-11b2-8352-8cdd2b965efc)] +interface nsITimerManager : nsISupports +{ + /** + * A flag that turns on the use of idle timers on the main thread. + * this should only be called once. + * + * By default, idle timers are off. + * + * One this is set to TRUE, you are expected to call hasIdleTimers/fireNextIdleTimer + * when you have time in your main loop. + */ + attribute boolean useIdleTimers; + + boolean hasIdleTimers(); + + // Fire next idle timers waiting on the current thread + void fireNextIdleTimer(); +}; diff --git a/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h new file mode 100644 index 00000000..8d3c0933 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsPIEventQueueChain.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsPIEventQueueChain_h__ +#define nsPIEventQueueChain_h__ + +#include "nsISupports.h" + +// {8f310040-82a7-11d3-95bc-0060083a0bcf} +#define NS_IEVENTQUEUECHAIN_IID \ +{ 0x8f310040, 0x82a7, 0x11d3, { 0x95, 0xbc, 0x0, 0x60, 0x8, 0x3a, 0xb, 0xcf } } + +class nsIEventQueue; + +class nsPIEventQueueChain : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IEVENTQUEUECHAIN_IID); + + /** + * Add the given queue as the new youngest member of our chain. + * It will not be addrefed. + * @param aQueue the queue. must not be null. + * @return error indication + */ + NS_IMETHOD AppendQueue(nsIEventQueue *aQueue) = 0; + + /** + * Remove this element from the chain. + * @return NS_OK + */ + NS_IMETHOD Unlink() = 0; + + /** + * Fetch (and addref) the youngest member of the chain. + * @param *aQueue the youngest queue. aQueue must not be null. + * @return error indication + */ + NS_IMETHOD GetYoungest(nsIEventQueue **aQueue) = 0; + + /** + * Fetch (and addref) the youngest member of the chain which is + * still accepting events, or at least still contains events in need + * of processing. + * @param *aQueue the youngest such queue. aQueue must not be null. + * *aQueue will be returned null, if no such queue is found. + * @return error indication -- can be NS_OK even if *aQueue is 0 + */ + NS_IMETHOD GetYoungestActive(nsIEventQueue **aQueue) = 0; + + NS_IMETHOD SetYounger(nsPIEventQueueChain *aQueue) = 0; + NS_IMETHOD GetYounger(nsIEventQueue **aQueue) = 0; + + NS_IMETHOD SetElder(nsPIEventQueueChain *aQueue) = 0; + NS_IMETHOD GetElder(nsIEventQueue **aQueue) = 0; +}; + +#endif /* nsPIEventQueueChain_h___ */ + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcess.h b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h new file mode 100644 index 00000000..f061fe1c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcess.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 _nsPROCESSWIN_H_ +#define _nsPROCESSWIN_H_ + +#include "nsIProcess.h" +#include "nsIFile.h" +#include "nsString.h" +#include "prproces.h" + +#define NS_PROCESS_CID \ +{0x7b4eeb20, 0xd781, 0x11d4, \ + {0x8A, 0x83, 0x00, 0x10, 0xa4, 0xe0, 0xc9, 0xca}} + +class nsProcess : public nsIProcess +{ +public: + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROCESS + + nsProcess(); + +private: + ~nsProcess() {} + + nsCOMPtr mExecutable; + PRInt32 mExitValue; + nsCString mTargetPath; + PRProcess *mProcess; + +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp new file mode 100644 index 00000000..07087c2f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessCommon.cpp @@ -0,0 +1,363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/***************************************************************************** + * + * nsProcess is used to execute new processes and specify if you want to + * wait (blocking) or continue (non-blocking). + * + ***************************************************************************** + */ + +#include "nsCOMPtr.h" +#include "nsMemory.h" +#include "nsProcess.h" +#include "prtypes.h" +#include "prio.h" +#include "prenv.h" +#include "nsCRT.h" + +#include + +#if defined( XP_WIN ) +#include "prmem.h" +#include "nsString.h" +#include "nsLiteralString.h" +#include "nsReadableUtils.h" +#include +#endif + +//-------------------------------------------------------------------// +// nsIProcess implementation +//-------------------------------------------------------------------// +NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess) + +//Constructor +nsProcess::nsProcess():mExitValue(-1), + mProcess(nsnull) +{ +} + +NS_IMETHODIMP +nsProcess::Init(nsIFile* executable) +{ + PRBool isFile; + + //First make sure the file exists + nsresult rv = executable->IsFile(&isFile); + if (NS_FAILED(rv)) return rv; + if (!isFile) + return NS_ERROR_FAILURE; + + //Store the nsIFile in mExecutable + mExecutable = executable; + //Get the path because it is needed by the NSPR process creation +#ifdef XP_WIN + rv = mExecutable->GetNativeTarget(mTargetPath); + if (NS_FAILED(rv) || mTargetPath.IsEmpty() ) +#endif + rv = mExecutable->GetNativePath(mTargetPath); + + return rv; +} + + +#if defined( XP_WIN ) +static int assembleCmdLine(char *const *argv, char **cmdLine) +{ + char *const *arg; + char *p, *q; + int cmdLineSize; + int numBackslashes; + int i; + int argNeedQuotes; + + /* + * Find out how large the command line buffer should be. + */ + cmdLineSize = 0; + for (arg = argv; *arg; arg++) { + /* + * \ and " need to be escaped by a \. In the worst case, + * every character is a \ or ", so the string of length + * may double. If we quote an argument, that needs two ". + * Finally, we need a space between arguments, and + * a null byte at the end of command line. + */ + cmdLineSize += 2 * strlen(*arg) /* \ and " need to be escaped */ + + 2 /* we quote every argument */ + + 1; /* space in between, or final null */ + } + p = *cmdLine = (char *) PR_MALLOC(cmdLineSize); + if (p == NULL) { + return -1; + } + + for (arg = argv; *arg; arg++) { + /* Add a space to separates the arguments */ + if (arg != argv) { + *p++ = ' '; + } + q = *arg; + numBackslashes = 0; + argNeedQuotes = 0; + + /* If the argument contains white space, it needs to be quoted. */ + if (strpbrk(*arg, " \f\n\r\t\v")) { + argNeedQuotes = 1; + } + + if (argNeedQuotes) { + *p++ = '"'; + } + while (*q) { + if (*q == '\\') { + numBackslashes++; + q++; + } else if (*q == '"') { + if (numBackslashes) { + /* + * Double the backslashes since they are followed + * by a quote + */ + for (i = 0; i < 2 * numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + /* To escape the quote */ + *p++ = '\\'; + *p++ = *q++; + } else { + if (numBackslashes) { + /* + * Backslashes are not followed by a quote, so + * don't need to double the backslashes. + */ + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + numBackslashes = 0; + } + *p++ = *q++; + } + } + + /* Now we are at the end of this argument */ + if (numBackslashes) { + /* + * Double the backslashes if we have a quote string + * delimiter at the end. + */ + if (argNeedQuotes) { + numBackslashes *= 2; + } + for (i = 0; i < numBackslashes; i++) { + *p++ = '\\'; + } + } + if (argNeedQuotes) { + *p++ = '"'; + } + } + + *p = '\0'; + return 0; +} +#endif + +// XXXldb |args| has the wrong const-ness +NS_IMETHODIMP +nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid) +{ + nsresult rv = NS_OK; + + // make sure that when we allocate we have 1 greater than the + // count since we need to null terminate the list for the argv to + // pass into PR_CreateProcess + char **my_argv = NULL; +#ifdef VBOX + my_argv = (char **)nsMemory::Alloc(sizeof(char *) * (count + 2) ); +#else + my_argv = (char **)malloc(sizeof(char *) * (count + 2) ); +#endif + if (!my_argv) { + return NS_ERROR_OUT_OF_MEMORY; + } + + // copy the args + PRUint32 i; + for (i=0; i < count; i++) { + my_argv[i+1] = NS_CONST_CAST(char*, args[i]); + } + // we need to set argv[0] to the program name. + my_argv[0] = mTargetPath.BeginWriting(); + // null terminate the array + my_argv[count+1] = NULL; + + #if defined(XP_WIN) + STARTUPINFO startupInfo; + PROCESS_INFORMATION procInfo; + BOOL retVal; + char *cmdLine; + + if (assembleCmdLine(my_argv, &cmdLine) == -1) { + nsMemory::Free(my_argv); + return NS_ERROR_FILE_EXECUTION_FAILED; + } + + ZeroMemory(&startupInfo, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + retVal = CreateProcess(NULL, + // NS_CONST_CAST(char*, mTargetPath.get()), + cmdLine, + NULL, /* security attributes for the new + * process */ + NULL, /* security attributes for the primary + * thread in the new process */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* env */ + NULL, /* current drive and directory */ + &startupInfo, + &procInfo + ); + PR_FREEIF( cmdLine ); + if (blocking) { + + // if success, wait for process termination. the early returns and such + // are a bit ugly but preserving the logic of the nspr code I copied to + // minimize our risk abit. + + if ( retVal == TRUE ) { + DWORD dwRetVal; + unsigned long exitCode; + + dwRetVal = WaitForSingleObject(procInfo.hProcess, INFINITE); + if (dwRetVal == WAIT_FAILED) { + nsMemory::Free(my_argv); + return PR_FAILURE; + } + if (GetExitCodeProcess(procInfo.hProcess, &exitCode) == FALSE) { + mExitValue = exitCode; + nsMemory::Free(my_argv); + return PR_FAILURE; + } + mExitValue = exitCode; + CloseHandle(procInfo.hProcess); + } + else + rv = PR_FAILURE; + } + else { + + // map return value into success code + + if ( retVal == TRUE ) + rv = PR_SUCCESS; + else + rv = PR_FAILURE; + } + +#else + if ( blocking ) { + mProcess = PR_CreateProcess(mTargetPath.get(), my_argv, NULL, NULL); + if (mProcess) + rv = PR_WaitProcess(mProcess, &mExitValue); + } + else { + rv = PR_CreateProcessDetached(mTargetPath.get(), my_argv, NULL, NULL); + } +#endif + + // free up our argv + nsMemory::Free(my_argv); + + if (rv != PR_SUCCESS) + return NS_ERROR_FILE_EXECUTION_FAILED; + return NS_OK; +} + +NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetLocation(nsIFile** aLocation) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetPid(PRUint32 *aPid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessName(char** aProcessName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessSignature(PRUint32 *aProcessSignature) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::Kill() +{ + nsresult rv = NS_OK; + if (mProcess) + rv = PR_KillProcess(mProcess); + + return rv; +} + +NS_IMETHODIMP +nsProcess::GetExitValue(PRInt32 *aExitValue) +{ + *aExitValue = mExitValue; + + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp new file mode 100644 index 00000000..d6411f47 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsProcessMac.cpp @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Don Bragg + * Samir Gehani + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/***************************************************************************** + * + * nsProcess is used to execute new processes and specify if you want to + * wait (blocking) or continue (non-blocking). + * + ***************************************************************************** + */ + +#include "nsCOMPtr.h" +#include "nsMemory.h" + +#include "nsProcess.h" + +#include "prtypes.h" +#include "prio.h" +#include "prenv.h" +#include "nsCRT.h" +#include "prthread.h" + +#include +#include + +#include "nsILocalFileMac.h" + +//-------------------------------------------------------------------// +// nsIProcess implementation +//-------------------------------------------------------------------// +NS_IMPL_ISUPPORTS1(nsProcess, nsIProcess) + +//Constructor +nsProcess::nsProcess() +:mExitValue(-1), + mProcess(nsnull) +{ +} + +NS_IMETHODIMP +nsProcess::Init(nsIFile* executable) +{ + PRBool isFile; + + //First make sure the file exists + nsresult rv = executable->IsFile(&isFile); + if (NS_FAILED(rv)) return rv; + + if (!isFile) + return NS_ERROR_FAILURE; + + mExecutable = executable; + + return NS_OK; +} + + +NS_IMETHODIMP +nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid) +{ + OSErr err = noErr; + LaunchParamBlockRec launchPB; + FSSpec resolvedSpec; + Boolean bDone = false; + ProcessInfoRec info; + + nsCOMPtr macExecutable = do_QueryInterface(mExecutable); + macExecutable->GetFSSpec(&resolvedSpec); + + launchPB.launchAppSpec = &resolvedSpec; + launchPB.launchAppParameters = NULL; + launchPB.launchBlockID = extendedBlock; + launchPB.launchEPBLength = extendedBlockLen; + launchPB.launchFileFlags = NULL; + launchPB.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum; + if (!blocking) + launchPB.launchControlFlags += launchDontSwitch; + + err = LaunchApplication(&launchPB); + if (err != noErr) + return NS_ERROR_FAILURE; + + // NOTE: blocking mode assumes you are running on a thread + // other than the UI thread that has teh main event loop + if (blocking) + { + do + { + info.processInfoLength = sizeof(ProcessInfoRec); + info.processName = nil; + info.processAppSpec = nil; + err = GetProcessInformation(&launchPB.launchProcessSN, &info); + + if (err == noErr) + { + // still running so sleep some more (200 msecs) + PR_Sleep(200); + } + else + { + // no longer in process manager's internal list: so assume done + bDone = true; + } + } + while (!bDone); + } + + return NS_OK; +} + +NS_IMETHODIMP nsProcess::InitWithPid(PRUint32 pid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetLocation(nsIFile** aLocation) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetPid(PRUint32 *aPid) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessName(char** aProcessName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetProcessSignature(PRUint32 *aProcessSignature) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::Kill() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsProcess::GetExitValue(PRInt32 *aExitValue) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp new file mode 100644 index 00000000..b4cc15f4 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.cpp @@ -0,0 +1,457 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsThread.h" +#include "prmem.h" +#include "prlog.h" +#include "nsAutoLock.h" + +PRUintn nsThread::kIThreadSelfIndex = 0; +static nsIThread *gMainThread = 0; + +#if defined(PR_LOGGING) +// +// Log module for nsIThread logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=nsIThread:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +// gSocketLog is defined in nsSocketTransport.cpp +// +PRLogModuleInfo* nsIThreadLog = nsnull; + +#endif /* PR_LOGGING */ + +//////////////////////////////////////////////////////////////////////////////// + +nsThread::nsThread() + : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull) +{ +#if defined(PR_LOGGING) + // + // Initialize the global PRLogModule for nsIThread logging + // if necessary... + // + if (nsIThreadLog == nsnull) { + nsIThreadLog = PR_NewLogModule("nsIThread"); + } +#endif /* PR_LOGGING */ + + // enforce matching of constants to enums in prthread.h + NS_ASSERTION(int(nsIThread::PRIORITY_LOW) == int(PR_PRIORITY_LOW) && + int(nsIThread::PRIORITY_NORMAL) == int(PRIORITY_NORMAL) && + int(nsIThread::PRIORITY_HIGH) == int(PRIORITY_HIGH) && + int(nsIThread::PRIORITY_URGENT) == int(PRIORITY_URGENT) && + int(nsIThread::SCOPE_LOCAL) == int(PR_LOCAL_THREAD) && + int(nsIThread::SCOPE_GLOBAL) == int(PR_GLOBAL_THREAD) && + int(nsIThread::STATE_JOINABLE) == int(PR_JOINABLE_THREAD) && + int(nsIThread::STATE_UNJOINABLE) == int(PR_UNJOINABLE_THREAD), + "Bad constant in nsIThread!"); +} + +nsThread::~nsThread() +{ + if (mStartLock) + PR_DestroyLock(mStartLock); + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p destroyed\n", this)); + + // This code used to free the nsIThreadLog loginfo stuff + // Don't do that; loginfo structures are owned by nspr + // and would be freed if we ever called PR_Cleanup() + // see bug 142072 +} + +void +nsThread::Main(void* arg) +{ + nsThread* self = (nsThread*)arg; + + self->WaitUntilReadyToStartMain(); + + nsresult rv = NS_OK; + rv = self->RegisterThreadSelf(); + NS_ASSERTION(rv == NS_OK, "failed to set thread self"); + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start run %p\n", self, self->mRunnable.get())); + rv = self->mRunnable->Run(); + NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); + +#ifdef DEBUG + // Because a thread can die after gMainThread dies and takes nsIThreadLog with it, + // we need to check for it being null so that we don't crash on shutdown. + if (nsIThreadLog) { + PRThreadState state; + rv = self->GetState(&state); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end run %p\n", self, self->mRunnable.get())); + } +#endif + + // explicitly drop the runnable now in case there are circular references + // between it and the thread object + self->mRunnable = nsnull; +} + +void +nsThread::Exit(void* arg) +{ + nsThread* self = (nsThread*)arg; + + if (self->mDead) { + NS_ERROR("attempt to Exit() thread twice"); + return; + } + + self->mDead = PR_TRUE; + +#if defined(PR_LOGGING) + if (nsIThreadLog) { + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p exited\n", self)); + } +#endif + NS_RELEASE(self); +} + +NS_METHOD +nsThread::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +{ + nsThread* thread = new nsThread(); + if (!thread) return NS_ERROR_OUT_OF_MEMORY; + nsresult rv = thread->QueryInterface(aIID, aResult); + if (NS_FAILED(rv)) delete thread; + return rv; +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsThread, nsIThread) + +NS_IMETHODIMP +nsThread::Join() +{ + // don't check for mDead here because nspr calls Exit (cleaning up + // thread-local storage) before they let us join with the thread + + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start join\n", this)); + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PRStatus status = PR_JoinThread(mThread); + // XXX can't use NS_RELEASE here because the macro wants to set + // this to null (bad c++) + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end join\n", this)); + if (status == PR_SUCCESS) { + NS_RELEASE_THIS(); // most likely the final release of this thread + return NS_OK; + } + else + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsThread::GetPriority(PRThreadPriority *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadPriority(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::SetPriority(PRThreadPriority value) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PR_SetThreadPriority(mThread, value); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::Interrupt() +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + PRStatus status = PR_Interrupt(mThread); + return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsThread::GetScope(PRThreadScope *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadScope(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::GetState(PRThreadState *result) +{ + if (mDead) + return NS_ERROR_FAILURE; + if (!mThread) + return NS_ERROR_NOT_INITIALIZED; + *result = PR_GetThreadState(mThread); + return NS_OK; +} + +NS_IMETHODIMP +nsThread::GetPRThread(PRThread* *result) +{ + if (mDead) { + *result = nsnull; + return NS_ERROR_FAILURE; + } + *result = mThread; + return NS_OK; +} + +NS_IMETHODIMP +nsThread::Init(nsIRunnable* runnable, + PRUint32 stackSize, + PRThreadPriority priority, + PRThreadScope scope, + PRThreadState state) +{ + NS_ENSURE_ARG_POINTER(runnable); + mRunnable = runnable; + + NS_ADDREF_THIS(); // released in nsThread::Exit + if (state == PR_JOINABLE_THREAD) + NS_ADDREF_THIS(); // released in nsThread::Join + mStartLock = PR_NewLock(); + if (mStartLock == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + PR_Lock(mStartLock); + mThread = PR_CreateThread(PR_USER_THREAD, Main, this, + priority, scope, state, stackSize); + PR_Unlock(mStartLock); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p created\n", this)); + + if (mThread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +/* readonly attribute nsIThread currentThread; */ +NS_IMETHODIMP +nsThread::GetCurrentThread(nsIThread * *aCurrentThread) +{ + return GetIThread(PR_GetCurrentThread(), aCurrentThread); +} + +/* void sleep (in PRUint32 msec); */ +NS_IMETHODIMP +nsThread::Sleep(PRUint32 msec) +{ + if (PR_GetCurrentThread() != mThread) + return NS_ERROR_FAILURE; + + if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_COM nsresult +NS_NewThread(nsIThread* *result, + nsIRunnable* runnable, + PRUint32 stackSize, + PRThreadState state, + PRThreadPriority priority, + PRThreadScope scope) +{ + nsresult rv; + nsThread* thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); + + rv = thread->Init(runnable, stackSize, priority, scope, state); + if (NS_FAILED(rv)) { + NS_RELEASE(thread); + return rv; + } + + *result = thread; + return NS_OK; +} + +NS_COM nsresult +NS_NewThread(nsIThread* *result, + PRUint32 stackSize, + PRThreadState state, + PRThreadPriority priority, + PRThreadScope scope) +{ + nsThread* thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); + *result = thread; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +nsThread::RegisterThreadSelf() +{ + PRStatus status; + + if (kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + } + + status = PR_SetThreadPrivate(kIThreadSelfIndex, this); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + + return NS_OK; +} + +void +nsThread::WaitUntilReadyToStartMain() +{ + PR_Lock(mStartLock); + PR_Unlock(mStartLock); + PR_DestroyLock(mStartLock); + mStartLock = nsnull; +} + +NS_COM nsresult +nsIThread::GetCurrent(nsIThread* *result) +{ + return GetIThread(PR_GetCurrentThread(), result); +} + +NS_COM nsresult +nsIThread::GetIThread(PRThread* prthread, nsIThread* *result) +{ + PRStatus status; + nsThread* thread; + + if (nsThread::kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit); + if (status != PR_SUCCESS) return NS_ERROR_FAILURE; + } + + thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex); + if (thread == nsnull) { + // if the current thread doesn't have an nsIThread associated + // with it, make one + thread = new nsThread(); + if (thread == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(thread); // released by Exit + thread->SetPRThread(prthread); + nsresult rv = thread->RegisterThreadSelf(); + if (NS_FAILED(rv)) return rv; + } + NS_ADDREF(thread); + *result = thread; + return NS_OK; +} + +NS_COM nsresult +nsIThread::SetMainThread() +{ + // strictly speaking, it could be set twice. but practically speaking, + // it's almost certainly an error if it is + if (gMainThread != 0) { + NS_ERROR("Setting main thread twice?"); + return NS_ERROR_FAILURE; + } + return GetCurrent(&gMainThread); +} + +NS_COM nsresult +nsIThread::GetMainThread(nsIThread **result) +{ + NS_ASSERTION(result, "bad result pointer"); + if (gMainThread == 0) + return NS_ERROR_FAILURE; + *result = gMainThread; + NS_ADDREF(gMainThread); + return NS_OK; +} + +NS_COM PRBool +nsIThread::IsMainThread() +{ + if (gMainThread == 0) + return PR_TRUE; + + PRThread *theMainThread; + gMainThread->GetPRThread(&theMainThread); + return theMainThread == PR_GetCurrentThread(); +} + +void +nsThread::Shutdown() +{ + if (gMainThread) { + // XXX nspr doesn't seem to be calling the main thread's destructor + // callback, so let's help it out: + nsThread::Exit(NS_STATIC_CAST(nsThread*, gMainThread)); + nsrefcnt cnt; + NS_RELEASE2(gMainThread, cnt); + NS_WARN_IF_FALSE(cnt == 0, "Main thread being held past XPCOM shutdown."); + gMainThread = nsnull; + + kIThreadSelfIndex = 0; + } +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/libs/xpcom18a4/xpcom/threads/nsThread.h b/src/libs/xpcom18a4/xpcom/threads/nsThread.h new file mode 100644 index 00000000..e75086a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsThread.h @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#ifndef nsThread_h__ +#define nsThread_h__ + +#include "nsIRunnable.h" +#include "nsIThread.h" +#include "nsCOMPtr.h" + +class nsThread : public nsIThread +{ +public: + NS_DECL_ISUPPORTS + + // nsIThread methods: + NS_DECL_NSITHREAD + + // nsThread methods: + nsThread(); + + nsresult RegisterThreadSelf(); + void SetPRThread(PRThread* thread) { mThread = thread; } + void WaitUntilReadyToStartMain(); + + static void PR_CALLBACK Main(void* arg); + static void PR_CALLBACK Exit(void* arg); + static void PR_CALLBACK Shutdown(); + + static PRUintn kIThreadSelfIndex; + + static NS_METHOD + Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); + +private: + ~nsThread(); + +protected: + PRThread* mThread; + nsCOMPtr mRunnable; + PRBool mDead; + PRLock* mStartLock; +}; + +//////////////////////////////////////////////////////////////////////////////// + +#endif // nsThread_h__ diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp new file mode 100644 index 00000000..dc19452f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.cpp @@ -0,0 +1,642 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "nsTimerImpl.h" +#include "TimerThread.h" +#include "nsAutoLock.h" + +#include "nsVoidArray.h" + +#include "nsIEventQueue.h" + +#include "prmem.h" + +static PRInt32 gGenerator = 0; +static TimerThread* gThread = nsnull; +static PRBool gFireOnIdle = PR_FALSE; +static nsTimerManager* gManager = nsnull; + +#ifdef DEBUG_TIMERS +#include + +double nsTimerImpl::sDeltaSumSquared = 0; +double nsTimerImpl::sDeltaSum = 0; +double nsTimerImpl::sDeltaNum = 0; + +static void +myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues, + double *meanResult, double *stdDevResult) +{ + double mean = 0.0, var = 0.0, stdDev = 0.0; + if (n > 0.0 && sumOfValues >= 0) { + mean = sumOfValues / n; + double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues); + if (temp < 0.0 || n <= 1) + var = 0.0; + else + var = temp / (n * (n - 1)); + // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this: + stdDev = var != 0.0 ? sqrt(var) : 0.0; + } + *meanResult = mean; + *stdDevResult = stdDev; +} +#endif + +NS_IMPL_THREADSAFE_QUERY_INTERFACE2(nsTimerImpl, nsITimer, nsITimerInternal) +NS_IMPL_THREADSAFE_ADDREF(nsTimerImpl) + +NS_IMETHODIMP_(nsrefcnt) nsTimerImpl::Release(void) +{ + nsrefcnt count; + + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "nsTimerImpl"); + if (count == 0) { + mRefCnt = 1; /* stabilize */ + + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(nsTimerImpl); */ + NS_DELETEXPCOM(this); + return 0; + } + + // If only one reference remains, and mArmed is set, then the ref must be + // from the TimerThread::mTimers array, so we Cancel this timer to remove + // the mTimers element, and return 0 if Cancel in fact disarmed the timer. + // + // We use an inlined version of nsTimerImpl::Cancel here to check for the + // NS_ERROR_NOT_AVAILABLE code returned by gThread->RemoveTimer when this + // timer is not found in the mTimers array -- i.e., when the timer was not + // in fact armed once we acquired TimerThread::mLock, in spite of mArmed + // being true here. That can happen if the armed timer is being fired by + // TimerThread::Run as we race and test mArmed just before it is cleared by + // the timer thread. If the RemoveTimer call below doesn't find this timer + // in the mTimers array, then the last ref to this timer is held manually + // and temporarily by the TimerThread, so we should fall through to the + // final return and return 1, not 0. + // + // The original version of this thread-based timer code kept weak refs from + // TimerThread::mTimers, removing this timer's weak ref in the destructor, + // but that leads to double-destructions in the race described above, and + // adding mArmed doesn't help, because destructors can't be deferred, once + // begun. But by combining reference-counting and a specialized Release + // method with "is this timer still in the mTimers array once we acquire + // the TimerThread's lock" testing, we defer destruction until we're sure + // that only one thread has its hot little hands on this timer. + // + // Note that both approaches preclude a timer creator, and everyone else + // except the TimerThread who might have a strong ref, from dropping all + // their strong refs without implicitly canceling the timer. Timers need + // non-mTimers-element strong refs to stay alive. + + if (count == 1 && mArmed) { + mCanceled = PR_TRUE; + + if (NS_SUCCEEDED(gThread->RemoveTimer(this))) + return 0; + } + + return count; +} + +nsTimerImpl::nsTimerImpl() : + mClosure(nsnull), + mCallbackType(CALLBACK_TYPE_UNKNOWN), + mIdle(PR_TRUE), + mFiring(PR_FALSE), + mArmed(PR_FALSE), + mCanceled(PR_FALSE), + mGeneration(0), + mDelay(0), + mTimeout(0) +{ + // XXXbsmedberg: shouldn't this be in Init()? + nsIThread::GetCurrent(getter_AddRefs(mCallingThread)); + + mCallback.c = nsnull; + +#ifdef DEBUG_TIMERS + mStart = 0; + mStart2 = 0; +#endif +} + +nsTimerImpl::~nsTimerImpl() +{ + ReleaseCallback(); +} + +//static +nsresult +nsTimerImpl::Startup() +{ + nsresult rv; + + gThread = new TimerThread(); + if (!gThread) return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(gThread); + rv = gThread->InitLocks(); + + if (NS_FAILED(rv)) { + NS_RELEASE(gThread); + } + + return rv; +} + +void nsTimerImpl::Shutdown() +{ +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + double mean = 0, stddev = 0; + myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev); + + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n", sDeltaNum, sDeltaSum, sDeltaSumSquared)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("mean: %fms, stddev: %fms\n", mean, stddev)); + } +#endif + + if (!gThread) + return; + + gThread->Shutdown(); + NS_RELEASE(gThread); + + gFireOnIdle = PR_FALSE; +} + + +nsresult nsTimerImpl::InitCommon(PRUint32 aType, PRUint32 aDelay) +{ + nsresult rv; + + NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); + + rv = gThread->Init(); + NS_ENSURE_SUCCESS(rv, rv); + + /** + * In case of re-Init, both with and without a preceding Cancel, clear the + * mCanceled flag and assign a new mGeneration. But first, remove any armed + * timer from the timer thread's list. + * + * If we are racing with the timer thread to remove this timer and we lose, + * the RemoveTimer call made here will fail to find this timer in the timer + * thread's list, and will return false harmlessly. We test mArmed here to + * avoid the small overhead in RemoveTimer of locking the timer thread and + * checking its list for this timer. It's safe to test mArmed even though + * it might be cleared on another thread in the next cycle (or even already + * be cleared by another CPU whose store hasn't reached our CPU's cache), + * because RemoveTimer is idempotent. + */ + if (mArmed) + gThread->RemoveTimer(this); + mCanceled = PR_FALSE; + mGeneration = PR_AtomicIncrement(&gGenerator); + + mType = (PRUint8)aType; + SetDelayInternal(aDelay); + + return gThread->AddTimer(this); +} + +NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc, + void *aClosure, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_FUNC; + mCallback.c = aFunc; + mClosure = aClosure; + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_INTERFACE; + mCallback.i = aCallback; + NS_ADDREF(mCallback.i); + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver, + PRUint32 aDelay, + PRUint32 aType) +{ + ReleaseCallback(); + mCallbackType = CALLBACK_TYPE_OBSERVER; + mCallback.o = aObserver; + NS_ADDREF(mCallback.o); + + return InitCommon(aType, aDelay); +} + +NS_IMETHODIMP nsTimerImpl::Cancel() +{ + mCanceled = PR_TRUE; + + if (gThread) + gThread->RemoveTimer(this); + + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetDelay(PRUint32 aDelay) +{ + // If we're already repeating precisely, update mTimeout now so that the + // new delay takes effect in the future. + if (mTimeout != 0 && mType == TYPE_REPEATING_PRECISE) + mTimeout = PR_IntervalNow(); + + SetDelayInternal(aDelay); + + if (!mFiring && gThread) + gThread->TimerDelayChanged(this); + + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::GetDelay(PRUint32* aDelay) +{ + *aDelay = mDelay; + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetType(PRUint32 aType) +{ + mType = (PRUint8)aType; + // XXX if this is called, we should change the actual type.. this could effect + // repeating timers. we need to ensure in Fire() that if mType has changed + // during the callback that we don't end up with the timer in the queue twice. + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::GetType(PRUint32* aType) +{ + *aType = mType; + return NS_OK; +} + + +NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure) +{ + *aClosure = mClosure; + return NS_OK; +} + + +NS_IMETHODIMP nsTimerImpl::GetIdle(PRBool *aIdle) +{ + *aIdle = mIdle; + return NS_OK; +} + +NS_IMETHODIMP nsTimerImpl::SetIdle(PRBool aIdle) +{ + mIdle = aIdle; + return NS_OK; +} + +void nsTimerImpl::Fire() +{ + if (mCanceled) + return; + + PRIntervalTime now = PR_IntervalNow(); +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PRIntervalTime a = now - mStart; // actual delay in intervals + PRUint32 b = PR_MillisecondsToInterval(mDelay); // expected delay in intervals + PRUint32 d = PR_IntervalToMilliseconds((a > b) ? a - b : b - a); // delta in ms + sDeltaSum += d; + sDeltaSumSquared += double(d) * double(d); + sDeltaNum++; + + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] expected delay time %4dms\n", this, mDelay)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] actual delay time %4dms\n", this, PR_IntervalToMilliseconds(a))); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] (mType is %d) -------\n", this, mType)); + PR_LOG(gTimerLog, PR_LOG_DEBUG, ("[this=%p] delta %4dms\n", this, (a > b) ? (PRInt32)d : -(PRInt32)d)); + + mStart = mStart2; + mStart2 = 0; + } +#endif + + PRIntervalTime timeout = mTimeout; + if (mType == TYPE_REPEATING_PRECISE) { + // Precise repeating timers advance mTimeout by mDelay without fail before + // calling Fire(). + timeout -= PR_MillisecondsToInterval(mDelay); + } + gThread->UpdateFilter(mDelay, timeout, now); + + mFiring = PR_TRUE; + + switch (mCallbackType) { + case CALLBACK_TYPE_FUNC: + mCallback.c(this, mClosure); + break; + case CALLBACK_TYPE_INTERFACE: + mCallback.i->Notify(this); + break; + case CALLBACK_TYPE_OBSERVER: + mCallback.o->Observe(NS_STATIC_CAST(nsITimer*,this), + NS_TIMER_CALLBACK_TOPIC, + nsnull); + break; + default:; + } + + mFiring = PR_FALSE; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("[this=%p] Took %dms to fire timer callback\n", + this, PR_IntervalToMilliseconds(PR_IntervalNow() - now))); + } +#endif + + if (mType == TYPE_REPEATING_SLACK) { + SetDelayInternal(mDelay); // force mTimeout to be recomputed. + if (gThread) + gThread->AddTimer(this); + } +} + + +struct TimerEventType : public PLEvent { + PRInt32 mGeneration; +#ifdef DEBUG_TIMERS + PRIntervalTime mInitTime; +#endif +}; + + +void* handleTimerEvent(TimerEventType* event) +{ + nsTimerImpl* timer = NS_STATIC_CAST(nsTimerImpl*, event->owner); + if (event->mGeneration != timer->GetGeneration()) + return nsnull; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + PRIntervalTime now = PR_IntervalNow(); + PR_LOG(gTimerLog, PR_LOG_DEBUG, + ("[this=%p] time between PostTimerEvent() and Fire(): %dms\n", + event->owner, PR_IntervalToMilliseconds(now - event->mInitTime))); + } +#endif + + if (gFireOnIdle) { + PRBool idle = PR_FALSE; + timer->GetIdle(&idle); + if (idle) { + NS_ASSERTION(gManager, "Global Thread Manager is null!"); + if (gManager) + gManager->AddIdleTimer(timer); + return nsnull; + } + } + + timer->Fire(); + + return nsnull; +} + +void destroyTimerEvent(TimerEventType* event) +{ + nsTimerImpl *timer = NS_STATIC_CAST(nsTimerImpl*, event->owner); + NS_RELEASE(timer); + PR_DELETE(event); +} + + +void nsTimerImpl::PostTimerEvent() +{ + // XXX we may want to reuse the PLEvent in the case of repeating timers. + TimerEventType* event; + + // construct + event = PR_NEW(TimerEventType); + if (!event) + return; + + // initialize + PL_InitEvent((PLEvent*)event, this, + (PLHandleEventProc)handleTimerEvent, + (PLDestroyEventProc)destroyTimerEvent); + + // Since TimerThread addref'd 'this' for us, we don't need to addref here. + // We will release in destroyMyEvent. We do need to copy the generation + // number from this timer into the event, so we can avoid firing a timer + // that was re-initialized after being canceled. + event->mGeneration = mGeneration; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + event->mInitTime = PR_IntervalNow(); + } +#endif + + // If this is a repeating precise timer, we need to calculate the time for + // the next timer to fire before we make the callback. + if (mType == TYPE_REPEATING_PRECISE) { + SetDelayInternal(mDelay); + if (gThread) + gThread->AddTimer(this); + } + + PRThread *thread; + nsresult rv = mCallingThread->GetPRThread(&thread); + if (NS_FAILED(rv)) { + NS_WARNING("Dropping timer event because thread is dead"); + return; + } + + nsCOMPtr queue; + if (gThread) + gThread->mEventQueueService->GetThreadEventQueue(thread, getter_AddRefs(queue)); + if (queue) + queue->PostEvent(event); +} + +void nsTimerImpl::SetDelayInternal(PRUint32 aDelay) +{ + PRIntervalTime delayInterval = PR_MillisecondsToInterval(aDelay); + if (delayInterval > DELAY_INTERVAL_MAX) { + delayInterval = DELAY_INTERVAL_MAX; + aDelay = PR_IntervalToMilliseconds(delayInterval); + } + + mDelay = aDelay; + + PRIntervalTime now = PR_IntervalNow(); + if (mTimeout == 0 || mType != TYPE_REPEATING_PRECISE) + mTimeout = now; + + mTimeout += delayInterval; + +#ifdef DEBUG_TIMERS + if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { + if (mStart == 0) + mStart = now; + else + mStart2 = now; + } +#endif +} + +/** + * Timer Manager code + */ + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsTimerManager, nsITimerManager) + +nsTimerManager::nsTimerManager() +{ + mLock = PR_NewLock(); + gManager = this; +} + +nsTimerManager::~nsTimerManager() +{ + gManager = nsnull; + PR_DestroyLock(mLock); + + nsTimerImpl *theTimer; + PRInt32 count = mIdleTimers.Count(); + + for (PRInt32 i = 0; i < count; i++) { + theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[i]); + NS_IF_RELEASE(theTimer); + } +} + +NS_IMETHODIMP nsTimerManager::SetUseIdleTimers(PRBool aUseIdleTimers) +{ + if (aUseIdleTimers == PR_FALSE && gFireOnIdle == PR_TRUE) + return NS_ERROR_FAILURE; + + gFireOnIdle = aUseIdleTimers; + + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::GetUseIdleTimers(PRBool *aUseIdleTimers) +{ + *aUseIdleTimers = gFireOnIdle; + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::HasIdleTimers(PRBool *aHasTimers) +{ + nsAutoLock lock (mLock); + PRUint32 count = mIdleTimers.Count(); + *aHasTimers = (count != 0); + return NS_OK; +} + +nsresult nsTimerManager::AddIdleTimer(nsITimer* timer) +{ + if (!timer) + return NS_ERROR_FAILURE; + nsAutoLock lock(mLock); + mIdleTimers.AppendElement(timer); + NS_ADDREF(timer); + return NS_OK; +} + +NS_IMETHODIMP nsTimerManager::FireNextIdleTimer() +{ + if (!gFireOnIdle || !nsIThread::IsMainThread()) { + return NS_OK; + } + + nsTimerImpl *theTimer = nsnull; + + { + nsAutoLock lock (mLock); + PRUint32 count = mIdleTimers.Count(); + + if (count == 0) + return NS_OK; + + theTimer = NS_STATIC_CAST(nsTimerImpl*, mIdleTimers[0]); + mIdleTimers.RemoveElement(theTimer); + } + + theTimer->Fire(); + + NS_RELEASE(theTimer); + + return NS_OK; +} + + +// NOT FOR PUBLIC CONSUMPTION! +nsresult +NS_NewTimer(nsITimer* *aResult, nsTimerCallbackFunc aCallback, void *aClosure, + PRUint32 aDelay, PRUint32 aType) +{ + nsTimerImpl* timer = new nsTimerImpl(); + if (timer == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(timer); + + nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure, + aDelay, aType); + if (NS_FAILED(rv)) { + NS_RELEASE(timer); + return rv; + } + + *aResult = timer; + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h new file mode 100644 index 00000000..98596f4e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/nsTimerImpl.h @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Stuart Parmenter + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 nsTimerImpl_h___ +#define nsTimerImpl_h___ + +//#define FORCE_PR_LOG /* Allow logging in the release build */ + +#include "nsITimer.h" +#include "nsVoidArray.h" +#include "nsIThread.h" +#include "nsITimerInternal.h" +#include "nsIObserver.h" + +#include "nsCOMPtr.h" + +#include "prlog.h" + +#if defined(PR_LOGGING) +static PRLogModuleInfo *gTimerLog = PR_NewLogModule("nsTimerImpl"); +#define DEBUG_TIMERS 1 +#else +#undef DEBUG_TIMERS +#endif + +#define NS_TIMER_CLASSNAME "Timer" +#define NS_TIMER_CID \ +{ /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */ \ + 0x5ff24248, \ + 0x1dd2, \ + 0x11b2, \ + {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \ +} + +enum { + CALLBACK_TYPE_UNKNOWN = 0, + CALLBACK_TYPE_INTERFACE = 1, + CALLBACK_TYPE_FUNC = 2, + CALLBACK_TYPE_OBSERVER = 3 +}; + +// Two timer deadlines must differ by less than half the PRIntervalTime domain. +#define DELAY_INTERVAL_LIMIT PR_BIT(8 * sizeof(PRIntervalTime) - 1) + +// Maximum possible delay (XXX rework to use ms rather than interval ticks). +#define DELAY_INTERVAL_MAX (DELAY_INTERVAL_LIMIT - 1) + +// Is interval-time t less than u, even if t has wrapped PRIntervalTime? +#define TIMER_LESS_THAN(t, u) ((t) - (u) > DELAY_INTERVAL_LIMIT) + +class nsTimerImpl : public nsITimer, public nsITimerInternal +{ +public: + + nsTimerImpl(); + + static NS_HIDDEN_(nsresult) Startup(); + static NS_HIDDEN_(void) Shutdown(); + + friend class TimerThread; + + void Fire(); + void PostTimerEvent(); + void SetDelayInternal(PRUint32 aDelay); + + NS_DECL_ISUPPORTS + NS_DECL_NSITIMER + NS_DECL_NSITIMERINTERNAL + + PRInt32 GetGeneration() { return mGeneration; } + +private: + ~nsTimerImpl(); + + nsresult InitCommon(PRUint32 aType, PRUint32 aDelay); + + void ReleaseCallback() + { + if (mCallbackType == CALLBACK_TYPE_INTERFACE) + NS_RELEASE(mCallback.i); + else if (mCallbackType == CALLBACK_TYPE_OBSERVER) + NS_RELEASE(mCallback.o); + } + + nsCOMPtr mCallingThread; + + void * mClosure; + + union { + nsTimerCallbackFunc c; + nsITimerCallback * i; + nsIObserver * o; + } mCallback; + + // These members are set by Init (called from NS_NewTimer) and never reset. + PRUint8 mCallbackType; + PRPackedBool mIdle; + + // These members are set by the initiating thread, when the timer's type is + // changed and during the period where it fires on that thread. + PRUint8 mType; + PRPackedBool mFiring; + + + // Use a PRBool (int) here to isolate loads and stores of these two members + // done on various threads under the protection of TimerThread::mLock, from + // loads and stores done on the initiating/type-changing/timer-firing thread + // to the above PRUint8/PRPackedBool members. + PRBool mArmed; + PRBool mCanceled; + + // The generation number of this timer, re-generated each time the timer is + // initialized so one-shot timers can be canceled and re-initialized by the + // arming thread without any bad race conditions. + PRInt32 mGeneration; + + PRUint32 mDelay; + PRIntervalTime mTimeout; + +#ifdef DEBUG_TIMERS + PRIntervalTime mStart, mStart2; + static double sDeltaSum; + static double sDeltaSumSquared; + static double sDeltaNum; +#endif + +}; + +#define NS_TIMERMANAGER_CONTRACTID "@mozilla.org/timer/manager;1" +#define NS_TIMERMANAGER_CLASSNAME "Timer Manager" +#define NS_TIMERMANAGER_CID \ +{ /* 4fe206fa-1dd2-11b2-8a0a-88bacbecc7d2 */ \ + 0x4fe206fa, \ + 0x1dd2, \ + 0x11b2, \ + {0x8a, 0x0a, 0x88, 0xba, 0xcb, 0xec, 0xc7, 0xd2} \ +} + +#include "nsITimerManager.h" + +class nsTimerManager : nsITimerManager +{ +public: + nsTimerManager(); + + NS_DECL_ISUPPORTS + NS_DECL_NSITIMERMANAGER + + nsresult AddIdleTimer(nsITimer* timer); +private: + ~nsTimerManager(); + + PRLock *mLock; + nsVoidArray mIdleTimers; +}; + + +#endif /* nsTimerImpl_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.c b/src/libs/xpcom18a4/xpcom/threads/plevent.c new file mode 100644 index 00000000..c5e9040f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/plevent.c @@ -0,0 +1,1774 @@ +/* -*- 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +#if defined(_WIN32) +#include +#endif + +#if defined(XP_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_WIN +#include +#define DefWindowProc WinDefWindowProc +#endif /* XP_OS2 */ + +#include "nspr.h" +#include "plevent.h" + +#if !defined(WIN32) +#include +#include +#if !defined(XP_OS2) +#include +#endif /* !XP_OS2 */ +#endif /* !Win32 */ + +#if defined(XP_UNIX) +/* for fcntl */ +#include +#include +#endif + +#if defined(XP_BEOS) +#include +#endif + +#if defined(XP_MACOSX) +#if defined(MOZ_WIDGET_COCOA) +#include +#define MAC_USE_CFRUNLOOPSOURCE +#elif defined(TARGET_CARBON) +/* #include */ +/* #define MAC_USE_CARBON_EVENT */ +#include +#define MAC_USE_CFRUNLOOPSOURCE +#endif +#endif + +#include "private/pprthred.h" + +#if defined(VMS) +/* +** On OpenVMS, XtAppAddInput doesn't want a regular fd, instead it +** wants an event flag. So, we don't create and use a pipe for +** notification of when an event queue has something ready, instead +** we use an event flag. Shouldn't be a problem if we only have +** a few event queues. +*/ +#include +#include +#include +#endif /* VMS */ + +#if defined(_WIN32) +/* Comment out the following USE_TIMER define to prevent + * WIN32 from using a WIN32 native timer for PLEvent notification. + * With USE_TIMER defined we will use a timer when pending input + * or paint events are starved, otherwise it will use a posted + * WM_APP msg for PLEvent notification. + */ +#define USE_TIMER + +/* Threshold defined in milliseconds for determining when the input + * and paint events have been held in the WIN32 msg queue too long + */ +#define INPUT_STARVATION_LIMIT 50 +/* The paint starvation limit is set to the smallest value which + * does not cause performance degradation while running page load tests + */ +#define PAINT_STARVATION_LIMIT 750 +/* The WIN9X paint starvation limit is larger because it was + * determined that the following value was required to prevent performance + * degradation on page load tests for WIN98/95 only. + */ +#define WIN9X_PAINT_STARVATION_LIMIT 3000 + +#define TIMER_ID 0 +/* If _md_PerformanceSetting <=0 then no event starvation otherwise events will be starved */ +static PRInt32 _md_PerformanceSetting = 0; +static PRUint32 _md_StarvationDelay = 0; +static PRUint32 _md_SwitchTime = 0; +#endif + +static PRLogModuleInfo *event_lm = NULL; + +/******************************************************************************* + * Private Stuff + ******************************************************************************/ + +/* +** EventQueueType -- Defines notification type for an event queue +** +*/ +typedef enum { + EventQueueIsNative = 1, + EventQueueIsMonitored = 2 +} EventQueueType; + + +struct PLEventQueue { + const char* name; + PRCList queue; + PRMonitor* monitor; + PRThread* handlerThread; + EventQueueType type; + PRPackedBool processingEvents; + PRPackedBool notified; +#if defined(_WIN32) + PRPackedBool timerSet; +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) +#if defined(VMS) + int efn; +#else + PRInt32 eventPipe[2]; +#endif + PLGetEventIDFunc idFunc; + void* idFuncClosure; +#elif defined(_WIN32) || defined(XP_OS2) + HWND eventReceiverWindow; + PRBool removeMsg; +#elif defined(XP_BEOS) + port_id eventport; +#elif defined(XP_MACOSX) +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceRef mRunLoopSource; + CFRunLoopRef mMainRunLoop; + CFStringRef mRunLoopModeStr; /* vbox */ +#elif defined(MAC_USE_CARBON_EVENT) + EventHandlerUPP eventHandlerUPP; + EventHandlerRef eventHandlerRef; +#endif +#endif +}; + +#define PR_EVENT_PTR(_qp) \ + ((PLEvent*) ((char*) (_qp) - offsetof(PLEvent, link))) + +static PRStatus _pl_SetupNativeNotifier(PLEventQueue* self); +static void _pl_CleanupNativeNotifier(PLEventQueue* self); +static PRStatus _pl_NativeNotify(PLEventQueue* self); +static PRStatus _pl_AcknowledgeNativeNotify(PLEventQueue* self); +static void _md_CreateEventQueue( PLEventQueue *eventQueue ); +static PRInt32 _pl_GetEventCount(PLEventQueue* self); + + +#if defined(_WIN32) || defined(XP_OS2) +#if defined(XP_OS2) +ULONG _pr_PostEventMsgId; +#else +UINT _pr_PostEventMsgId; +#endif /* OS2 */ +static char *_pr_eventWindowClass = "XPCOM:EventWindow"; +#endif /* Win32, OS2 */ + +#if defined(_WIN32) + +static LPCTSTR _md_GetEventQueuePropName() { + static ATOM atom = 0; + if (!atom) { + atom = GlobalAddAtom("XPCOM_EventQueue"); + } + return MAKEINTATOM(atom); +} +#endif + +#if defined(MAC_USE_CARBON_EVENT) +enum { + kEventClassPL = FOUR_CHAR_CODE('PLEC'), + + kEventProcessPLEvents = 1, + + kEventParamPLEventQueue = FOUR_CHAR_CODE('OWNQ') +}; + +static pascal Boolean _md_CarbonEventComparator(EventRef inEvent, void *inCompareData); +#endif + +/******************************************************************************* + * Event Queue Operations + ******************************************************************************/ + +/* +** _pl_CreateEventQueue() -- Create the event queue +** +** +*/ +static PLEventQueue * _pl_CreateEventQueue(const char *name, + PRThread *handlerThread, + EventQueueType qtype) +{ + PRStatus err; + PLEventQueue* self = NULL; + PRMonitor* mon = NULL; + + if (event_lm == NULL) + event_lm = PR_NewLogModule("event"); + + self = PR_NEWZAP(PLEventQueue); + if (self == NULL) return NULL; + + mon = PR_NewNamedMonitor(name); + if (mon == NULL) goto error; + + self->name = name; + self->monitor = mon; + self->handlerThread = handlerThread; + self->processingEvents = PR_FALSE; + self->type = qtype; +#if defined(_WIN32) + self->timerSet = PR_FALSE; +#endif +#if defined(_WIN32) || defined(XP_OS2) + self->removeMsg = PR_TRUE; +#endif + + self->notified = PR_FALSE; + + PR_INIT_CLIST(&self->queue); + if ( qtype == EventQueueIsNative ) { + err = _pl_SetupNativeNotifier(self); + if (err) goto error; + _md_CreateEventQueue( self ); + } + return self; + + error: + if (mon != NULL) + PR_DestroyMonitor(mon); + PR_DELETE(self); + return NULL; +} + +PR_IMPLEMENT(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative )); +} + +PR_EXTERN(PLEventQueue *) +PL_CreateNativeEventQueue(const char *name, PRThread *handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsNative )); +} + +PR_EXTERN(PLEventQueue *) +PL_CreateMonitoredEventQueue(const char *name, PRThread *handlerThread) +{ + return( _pl_CreateEventQueue( name, handlerThread, EventQueueIsMonitored )); +} + +PR_IMPLEMENT(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self) +{ + return self->monitor; +} + +static void PR_CALLBACK +_pl_destroyEvent(PLEvent* event, void* data, PLEventQueue* queue) +{ + PL_DequeueEvent(event, queue); + PL_DestroyEvent(event); +} + +PR_IMPLEMENT(void) +PL_DestroyEventQueue(PLEventQueue* self) +{ + PR_EnterMonitor(self->monitor); + + /* destroy undelivered events */ + PL_MapEvents(self, _pl_destroyEvent, NULL); + + if ( self->type == EventQueueIsNative ) + _pl_CleanupNativeNotifier(self); + + /* destroying the monitor also destroys the name */ + PR_ExitMonitor(self->monitor); + PR_DestroyMonitor(self->monitor); + PR_DELETE(self); + +} + +PR_IMPLEMENT(PRStatus) +PL_PostEvent(PLEventQueue* self, PLEvent* event) +{ + PRStatus err = PR_SUCCESS; + PRMonitor* mon; + + if (self == NULL) + return PR_FAILURE; + + mon = self->monitor; + PR_EnterMonitor(mon); + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + if (self->idFunc && event) + event->id = self->idFunc(self->idFuncClosure); +#endif + + /* insert event into thread's event queue: */ + if (event != NULL) { + PR_APPEND_LINK(&event->link, &self->queue); + } + + if (self->type == EventQueueIsNative && !self->notified) { + err = _pl_NativeNotify(self); + + if (err != PR_SUCCESS) + goto error; + + self->notified = PR_TRUE; + } + + /* + * This may fall on deaf ears if we're really notifying the native + * thread, and no one has called PL_WaitForEvent (or PL_EventLoop): + */ + err = PR_Notify(mon); + +error: + PR_ExitMonitor(mon); + return err; +} + +PR_IMPLEMENT(void*) +PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event) +{ + void* result; + + if (self == NULL) + return NULL; + + PR_ASSERT(event != NULL); + + if (PR_GetCurrentThread() == self->handlerThread) { + /* Handle the case where the thread requesting the event handling + * is also the thread that's supposed to do the handling. */ + result = event->handler(event); + } + else { + int i, entryCount; + + event->lock = PR_NewLock(); + if (!event->lock) { + return NULL; + } + event->condVar = PR_NewCondVar(event->lock); + if(!event->condVar) { + PR_DestroyLock(event->lock); + event->lock = NULL; + return NULL; + } + + PR_Lock(event->lock); + + entryCount = PR_GetMonitorEntryCount(self->monitor); + + event->synchronousResult = (void*)PR_TRUE; + + PL_PostEvent(self, event); + + /* We need temporarily to give up our event queue monitor if + we're holding it, otherwise, the thread we're going to wait + for notification from won't be able to enter it to process + the event. */ + if (entryCount) { + for (i = 0; i < entryCount; i++) + PR_ExitMonitor(self->monitor); + } + + event->handled = PR_FALSE; + + while (!event->handled) { + /* wait for event to be handled or destroyed */ + PR_WaitCondVar(event->condVar, PR_INTERVAL_NO_TIMEOUT); + } + + if (entryCount) { + for (i = 0; i < entryCount; i++) + PR_EnterMonitor(self->monitor); + } + + result = event->synchronousResult; + event->synchronousResult = NULL; + PR_Unlock(event->lock); + } + + /* For synchronous events, they're destroyed here on the caller's + thread before the result is returned. See PL_HandleEvent. */ + PL_DestroyEvent(event); + + return result; +} + +PR_IMPLEMENT(PLEvent*) +PL_GetEvent(PLEventQueue* self) +{ + PLEvent* event = NULL; + PRStatus err = PR_SUCCESS; + + if (self == NULL) + return NULL; + + PR_EnterMonitor(self->monitor); + + if (!PR_CLIST_IS_EMPTY(&self->queue)) { + if ( self->type == EventQueueIsNative && + self->notified && + !self->processingEvents && + 0 == _pl_GetEventCount(self) ) + { + err = _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + } + if (err) + goto done; + + /* then grab the event and return it: */ + event = PR_EVENT_PTR(self->queue.next); + PR_REMOVE_AND_INIT_LINK(&event->link); + } + + done: + PR_ExitMonitor(self->monitor); + return event; +} + +PR_IMPLEMENT(PRBool) +PL_EventAvailable(PLEventQueue* self) +{ + PRBool result = PR_FALSE; + + if (self == NULL) + return PR_FALSE; + + PR_EnterMonitor(self->monitor); + + if (!PR_CLIST_IS_EMPTY(&self->queue)) + result = PR_TRUE; + + PR_ExitMonitor(self->monitor); + return result; +} + +PR_IMPLEMENT(void) +PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data) +{ + PRCList* qp; + + if (self == NULL) + return; + + PR_EnterMonitor(self->monitor); + qp = self->queue.next; + while (qp != &self->queue) { + PLEvent* event = PR_EVENT_PTR(qp); + qp = qp->next; + (*fun)(event, data, self); + } + PR_ExitMonitor(self->monitor); +} + +static void PR_CALLBACK +_pl_DestroyEventForOwner(PLEvent* event, void* owner, PLEventQueue* queue) +{ + PR_ASSERT(PR_GetMonitorEntryCount(queue->monitor) > 0); + if (event->owner == owner) { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ \tdestroying event %0x for owner %0x", event, owner)); + PL_DequeueEvent(event, queue); + + if (event->synchronousResult == (void*)PR_TRUE) { + PR_Lock(event->lock); + event->synchronousResult = NULL; + event->handled = PR_TRUE; + PR_NotifyCondVar(event->condVar); + PR_Unlock(event->lock); + } + else { + PL_DestroyEvent(event); + } + } + else { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ \tskipping event %0x for owner %0x", event, owner)); + } +} + +PR_IMPLEMENT(void) +PL_RevokeEvents(PLEventQueue* self, void* owner) +{ + if (self == NULL) + return; + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ revoking events for owner %0x", owner)); + + /* + ** First we enter the monitor so that no one else can post any events + ** to the queue: + */ + PR_EnterMonitor(self->monitor); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ owner %0x, entered monitor", owner)); + + /* + ** Discard any pending events for this owner: + */ + PL_MapEvents(self, _pl_DestroyEventForOwner, owner); + +#ifdef DEBUG + { + PRCList* qp = self->queue.next; + while (qp != &self->queue) { + PLEvent* event = PR_EVENT_PTR(qp); + qp = qp->next; + PR_ASSERT(event->owner != owner); + } + } +#endif /* DEBUG */ + + PR_ExitMonitor(self->monitor); + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ revoking events for owner %0x", owner)); +} + +static PRInt32 +_pl_GetEventCount(PLEventQueue* self) +{ + PRCList* node; + PRInt32 count = 0; + + PR_EnterMonitor(self->monitor); + node = PR_LIST_HEAD(&self->queue); + while (node != &self->queue) { + count++; + node = PR_NEXT_LINK(node); + } + PR_ExitMonitor(self->monitor); + + return count; +} + +PR_IMPLEMENT(void) +PL_ProcessPendingEvents(PLEventQueue* self) +{ + PRInt32 count; + + if (self == NULL) + return; + + + PR_EnterMonitor(self->monitor); + + if (self->processingEvents) { + _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + PR_ExitMonitor(self->monitor); + return; + } + self->processingEvents = PR_TRUE; + + /* Only process the events that are already in the queue, and + * not any new events that get added. Do this by counting the + * number of events currently in the queue + */ + count = _pl_GetEventCount(self); + PR_ExitMonitor(self->monitor); + + while (count-- > 0) { + PLEvent* event = PL_GetEvent(self); + if (event == NULL) + break; + + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event")); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + } + + PR_EnterMonitor(self->monitor); + + if (self->type == EventQueueIsNative) { + count = _pl_GetEventCount(self); + + if (count <= 0) { + _pl_AcknowledgeNativeNotify(self); + self->notified = PR_FALSE; + } + else { + _pl_NativeNotify(self); + self->notified = PR_TRUE; + } + + } + self->processingEvents = PR_FALSE; + + PR_ExitMonitor(self->monitor); +} + +/******************************************************************************* + * Event Operations + ******************************************************************************/ + +PR_IMPLEMENT(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor) +{ +#ifdef PL_POST_TIMINGS + self->postTime = PR_IntervalNow(); +#endif + PR_INIT_CLIST(&self->link); + self->handler = handler; + self->destructor = destructor; + self->owner = owner; + self->synchronousResult = NULL; + self->handled = PR_FALSE; + self->lock = NULL; + self->condVar = NULL; +#if defined(XP_UNIX) && !defined(XP_MACOSX) + self->id = 0; +#endif +} + +PR_IMPLEMENT(void*) +PL_GetEventOwner(PLEvent* self) +{ + return self->owner; +} + +PR_IMPLEMENT(void) +PL_HandleEvent(PLEvent* self) +{ + void* result; + if (self == NULL) + return; + + /* This event better not be on an event queue anymore. */ + PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link)); + + result = self->handler(self); + if (NULL != self->synchronousResult) { + PR_Lock(self->lock); + self->synchronousResult = result; + self->handled = PR_TRUE; + PR_NotifyCondVar(self->condVar); + PR_Unlock(self->lock); + } + else { + /* For asynchronous events, they're destroyed by the event-handler + thread. See PR_PostSynchronousEvent. */ + PL_DestroyEvent(self); + } +} +#ifdef PL_POST_TIMINGS +static long s_eventCount = 0; +static long s_totalTime = 0; +#endif + +PR_IMPLEMENT(void) +PL_DestroyEvent(PLEvent* self) +{ + if (self == NULL) + return; + + /* This event better not be on an event queue anymore. */ + PR_ASSERT(PR_CLIST_IS_EMPTY(&self->link)); + + if(self->condVar) + PR_DestroyCondVar(self->condVar); + if(self->lock) + PR_DestroyLock(self->lock); + +#ifdef PL_POST_TIMINGS + s_totalTime += PR_IntervalNow() - self->postTime; + s_eventCount++; + printf("$$$ running avg (%d) \n", PR_IntervalToMilliseconds(s_totalTime/s_eventCount)); +#endif + + self->destructor(self); +} + +PR_IMPLEMENT(void) +PL_DequeueEvent(PLEvent* self, PLEventQueue* queue) +{ + if (self == NULL) + return; + + /* Only the owner is allowed to dequeue events because once the + client has put it in the queue, they have no idea whether it's + been processed and destroyed or not. */ + + PR_ASSERT(queue->handlerThread == PR_GetCurrentThread()); + + PR_EnterMonitor(queue->monitor); + + PR_ASSERT(!PR_CLIST_IS_EMPTY(&self->link)); + +#if 0 + /* I do not think that we need to do this anymore. + if we do not acknowledge and this is the only + only event in the queue, any calls to process + the eventQ will be effective noop. + */ + if (queue->type == EventQueueIsNative) + _pl_AcknowledgeNativeNotify(queue); +#endif + + PR_REMOVE_AND_INIT_LINK(&self->link); + + PR_ExitMonitor(queue->monitor); +} + +PR_IMPLEMENT(void) +PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, + PRUint32 starvationDelay) +{ +#if defined(_WIN32) + + _md_StarvationDelay = starvationDelay; + + if (favorPerformanceOverEventStarvation) { + _md_PerformanceSetting++; + return; + } + + _md_PerformanceSetting--; + + if (_md_PerformanceSetting == 0) { + /* Switched from allowing event starvation to no event starvation so grab + the current time to determine when to actually switch to using timers + instead of posted WM_APP messages. */ + _md_SwitchTime = PR_IntervalToMilliseconds(PR_IntervalNow()); + } + +#endif +} + +/******************************************************************************* + * Pure Event Queues + * + * For when you're only processing PLEvents and there is no native + * select, thread messages, or AppleEvents. + ******************************************************************************/ + +PR_IMPLEMENT(PLEvent*) +PL_WaitForEvent(PLEventQueue* self) +{ + PLEvent* event; + PRMonitor* mon; + + if (self == NULL) + return NULL; + + mon = self->monitor; + PR_EnterMonitor(mon); + + while ((event = PL_GetEvent(self)) == NULL) { + PRStatus err; + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ waiting for event")); + err = PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + if ((err == PR_FAILURE) + && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break; + } + + PR_ExitMonitor(mon); + return event; +} + +PR_IMPLEMENT(void) +PL_EventLoop(PLEventQueue* self) +{ + if (self == NULL) + return; + + while (PR_TRUE) { + PLEvent* event = PL_WaitForEvent(self); + if (event == NULL) { + /* This can only happen if the current thread is interrupted */ + return; + } + + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event")); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + } +} + +/******************************************************************************* + * Native Event Queues + * + * For when you need to call select, or WaitNextEvent, and yet also want + * to handle PLEvents. + ******************************************************************************/ + +static PRStatus +_pl_SetupNativeNotifier(PLEventQueue* self) +{ +#if defined(VMS) + unsigned int status; + self->idFunc = 0; + self->idFuncClosure = 0; + status = LIB$GET_EF(&self->efn); + if (!$VMS_STATUS_SUCCESS(status)) + return PR_FAILURE; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ Allocated event flag %d", self->efn)); + return PR_SUCCESS; +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + int err; + int flags; + + self->idFunc = 0; + self->idFuncClosure = 0; + + err = pipe(self->eventPipe); + if (err != 0) { + return PR_FAILURE; + } +#ifdef VBOX + fcntl(self->eventPipe[0], F_SETFD, FD_CLOEXEC); + fcntl(self->eventPipe[1], F_SETFD, FD_CLOEXEC); +#endif + + /* make the pipe nonblocking */ + flags = fcntl(self->eventPipe[0], F_GETFL, 0); + if (flags == -1) { + goto failed; + } + err = fcntl(self->eventPipe[0], F_SETFL, flags | O_NONBLOCK); + if (err == -1) { + goto failed; + } + flags = fcntl(self->eventPipe[1], F_GETFL, 0); + if (flags == -1) { + goto failed; + } + err = fcntl(self->eventPipe[1], F_SETFL, flags | O_NONBLOCK); + if (err == -1) { + goto failed; + } + return PR_SUCCESS; + +failed: + close(self->eventPipe[0]); + close(self->eventPipe[1]); + return PR_FAILURE; +#elif defined(XP_BEOS) + /* hook up to the nsToolkit queue, however the appshell + * isn't necessairly started, so we might have to create + * the queue ourselves + */ + char portname[64]; + char semname[64]; + PR_snprintf(portname, sizeof(portname), "event%lx", + (long unsigned) self->handlerThread); + PR_snprintf(semname, sizeof(semname), "sync%lx", + (long unsigned) self->handlerThread); + + if((self->eventport = find_port(portname)) < 0) + { + /* create port + */ + self->eventport = create_port(500, portname); + + /* We don't use the sem, but it has to be there + */ + create_sem(0, semname); + } + + return PR_SUCCESS; +#else + return PR_SUCCESS; +#endif +} + +static void +_pl_CleanupNativeNotifier(PLEventQueue* self) +{ +#if defined(VMS) + { + unsigned int status; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ Freeing event flag %d", self->efn)); + status = LIB$FREE_EF(&self->efn); + } +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + close(self->eventPipe[0]); + close(self->eventPipe[1]); +#elif defined(_WIN32) + if (self->timerSet) { + KillTimer(self->eventReceiverWindow, TIMER_ID); + self->timerSet = PR_FALSE; + } + RemoveProp(self->eventReceiverWindow, _md_GetEventQueuePropName()); + + /* DestroyWindow doesn't do anything when called from a non ui thread. Since + * self->eventReceiverWindow was created on the ui thread, it must be destroyed + * on the ui thread. + */ + SendMessage(self->eventReceiverWindow, WM_CLOSE, 0, 0); + +#elif defined(XP_OS2) + WinDestroyWindow(self->eventReceiverWindow); +#elif defined(MAC_USE_CFRUNLOOPSOURCE) + + CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, kCFRunLoopCommonModes); + CFRunLoopRemoveSource(self->mMainRunLoop, self->mRunLoopSource, self->mRunLoopModeStr); /* vbox */ + CFRelease(self->mRunLoopSource); + CFRelease(self->mMainRunLoop); + CFRelease(self->mRunLoopModeStr); /* vbox */ + +#elif defined(MAC_USE_CARBON_EVENT) + EventComparatorUPP comparator = NewEventComparatorUPP(_md_CarbonEventComparator); + PR_ASSERT(comparator != NULL); + if (comparator) { + FlushSpecificEventsFromQueue(GetMainEventQueue(), comparator, self); + DisposeEventComparatorUPP(comparator); + } + DisposeEventHandlerUPP(self->eventHandlerUPP); + RemoveEventHandler(self->eventHandlerRef); +#endif +} + +#if defined(_WIN32) + +static PRBool _md_WasInputPending = PR_FALSE; +static PRUint32 _md_InputTime = 0; +static PRBool _md_WasPaintPending = PR_FALSE; +static PRUint32 _md_PaintTime = 0; +/* last mouse location */ +static POINT _md_LastMousePos; + +/******************************************************************************* + * Timer callback function. Timers are used on WIN32 instead of APP events + * when there are pending UI events because APP events can cause the GUI to lockup + * because posted messages are processed before other messages. + ******************************************************************************/ + +static void CALLBACK _md_TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) +{ + PREventQueue* queue = (PREventQueue *) GetProp(hwnd, _md_GetEventQueuePropName()); + PR_ASSERT(queue != NULL); + + KillTimer(hwnd, TIMER_ID); + queue->timerSet = PR_FALSE; + queue->removeMsg = PR_FALSE; + PL_ProcessPendingEvents( queue ); + queue->removeMsg = PR_TRUE; +} + +static PRBool _md_IsWIN9X = PR_FALSE; +static PRBool _md_IsOSSet = PR_FALSE; + +static void _md_DetermineOSType() +{ + OSVERSIONINFO os; + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&os); + if (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId) { + _md_IsWIN9X = PR_TRUE; + } +} + +static PRUint32 _md_GetPaintStarvationLimit() +{ + if (! _md_IsOSSet) { + _md_DetermineOSType(); + _md_IsOSSet = PR_TRUE; + } + + if (_md_IsWIN9X) { + return WIN9X_PAINT_STARVATION_LIMIT; + } + + return PAINT_STARVATION_LIMIT; +} + + +/* + * Determine if an event is being starved (i.e the starvation limit has + * been exceeded. + * Note: this function uses the current setting and updates the contents + * of the wasPending and lastTime arguments + * + * ispending: PR_TRUE if the event is currently pending + * starvationLimit: Threshold defined in milliseconds for determining when + * the event has been held in the queue too long + * wasPending: PR_TRUE if the last time _md_EventIsStarved was called + * the event was pending. This value is updated within + * this function. + * lastTime: Holds the last time the event was in the queue. + * This value is updated within this function + * returns: PR_TRUE if the event is starved, PR_FALSE otherwise + */ + +static PRBool _md_EventIsStarved(PRBool isPending, PRUint32 starvationLimit, + PRBool *wasPending, PRUint32 *lastTime, + PRUint32 currentTime) +{ + if (*wasPending && isPending) { + /* + * It was pending previously and the event is still + * pending so check to see if the elapsed time is + * over the limit which indicates the event was starved + */ + if ((currentTime - *lastTime) > starvationLimit) { + return PR_TRUE; /* pending and over the limit */ + } + + return PR_FALSE; /* pending but within the limit */ + } + + if (isPending) { + /* + * was_pending must be false so record the current time + * so the elapsed time can be computed the next time this + * function is called + */ + *lastTime = currentTime; + *wasPending = PR_TRUE; + return PR_FALSE; + } + + /* Event is no longer pending */ + *wasPending = PR_FALSE; + return PR_FALSE; +} + +/* Determines if the there is a pending Mouse or input event */ + +static PRBool _md_IsInputPending(WORD qstatus) +{ + /* Return immediately there aren't any pending input or paints. */ + if (qstatus == 0) { + return PR_FALSE; + } + + /* Is there anything other than a QS_MOUSEMOVE pending? */ + if ((qstatus & QS_MOUSEBUTTON) || + (qstatus & QS_KEY) || + (qstatus & QS_HOTKEY)) { + return PR_TRUE; + } + + /* + * Mouse moves need extra processing to determine if the mouse + * pointer actually changed location because Windows automatically + * generates WM_MOVEMOVE events when a new window is created which + * we need to filter out. + */ + if (qstatus & QS_MOUSEMOVE) { + POINT cursorPos; + GetCursorPos(&cursorPos); + if ((_md_LastMousePos.x == cursorPos.x) && + (_md_LastMousePos.y == cursorPos.y)) { + return PR_FALSE; /* This is a fake mouse move */ + } + + /* Real mouse move */ + _md_LastMousePos.x = cursorPos.x; + _md_LastMousePos.y = cursorPos.y; + return PR_TRUE; + } + + return PR_FALSE; +} + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#ifdef USE_TIMER + WORD qstatus; + + PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow()); + + /* Since calls to set the _md_PerformanceSetting can be nested + * only performance setting values <= 0 will potentially trigger + * the use of a timer. + */ + if ((_md_PerformanceSetting <= 0) && + ((now - _md_SwitchTime) > _md_StarvationDelay)) { + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + _md_WasInputPending = PR_FALSE; + _md_WasPaintPending = PR_FALSE; + return PR_SUCCESS; + } + + qstatus = HIWORD(GetQueueStatus(QS_INPUT | QS_PAINT)); + + /* Check for starved input */ + if (_md_EventIsStarved( _md_IsInputPending(qstatus), + INPUT_STARVATION_LIMIT, + &_md_WasInputPending, + &_md_InputTime, + now )) { + /* + * Use a timer for notification. Timers have the lowest priority. + * They are not processed until all other events have been processed. + * This allows any starved paints and input to be processed. + */ + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + + /* + * Clear any pending paint. _md_WasInputPending was cleared in + * _md_EventIsStarved. + */ + _md_WasPaintPending = PR_FALSE; + return PR_SUCCESS; + } + + if (_md_EventIsStarved( (qstatus & QS_PAINT), + _md_GetPaintStarvationLimit(), + &_md_WasPaintPending, + &_md_PaintTime, + now) ) { + /* + * Use a timer for notification. Timers have the lowest priority. + * They are not processed until all other events have been processed. + * This allows any starved paints and input to be processed + */ + SetTimer(self->eventReceiverWindow, TIMER_ID, 0 ,_md_TimerProc); + self->timerSet = PR_TRUE; + + /* + * Clear any pending input. _md_WasPaintPending was cleared in + * _md_EventIsStarved. + */ + _md_WasInputPending = PR_FALSE; + return PR_SUCCESS; + } + + /* + * Nothing is being starved so post a message instead of using a timer. + * Posted messages are processed before other messages so they have the + * highest priority. + */ +#endif + PostMessage( self->eventReceiverWindow, _pr_PostEventMsgId, + (WPARAM)0, (LPARAM)self ); + + return PR_SUCCESS; +}/* --- end _pl_NativeNotify() --- */ +#endif + + +#if defined(XP_OS2) +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + BOOL rc = WinPostMsg( self->eventReceiverWindow, _pr_PostEventMsgId, + 0, MPFROMP(self)); + return (rc == TRUE) ? PR_SUCCESS : PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#endif /* XP_OS2 */ + +#if defined(VMS) +/* Just set the event flag */ +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + unsigned int status; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_NativeNotify: self=%p efn=%d", + self, self->efn)); + status = SYS$SETEF(self->efn); + return ($VMS_STATUS_SUCCESS(status)) ? PR_SUCCESS : PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#define NOTIFY_TOKEN 0xFA + PRInt32 count; + unsigned char buf[] = { NOTIFY_TOKEN }; + +# ifdef VBOX + /* Don't write two chars, because we'll only acknowledge one and that'll + cause trouble for anyone selecting/polling on the read descriptor. */ + if (self->notified) + return PR_SUCCESS; +# endif + + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_NativeNotify: self=%p", + self)); + count = write(self->eventPipe[1], buf, 1); + if (count == 1) + return PR_SUCCESS; + if (count == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) + return PR_SUCCESS; + return PR_FAILURE; +}/* --- end _pl_NativeNotify() --- */ +#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */ + +#if defined(XP_BEOS) +struct ThreadInterfaceData +{ + void *data; + int32 sync; +}; + +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ + struct ThreadInterfaceData id; + id.data = self; + id.sync = false; + write_port(self->eventport, 'natv', &id, sizeof(id)); + + return PR_SUCCESS; /* Is this correct? */ +} +#endif /* XP_BEOS */ + +#if defined(XP_MACOSX) +static PRStatus +_pl_NativeNotify(PLEventQueue* self) +{ +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceSignal(self->mRunLoopSource); + CFRunLoopWakeUp(self->mMainRunLoop); +#elif defined(MAC_USE_CARBON_EVENT) + OSErr err; + EventRef newEvent; + if (CreateEvent(NULL, kEventClassPL, kEventProcessPLEvents, + 0, kEventAttributeNone, &newEvent) != noErr) + return PR_FAILURE; + err = SetEventParameter(newEvent, kEventParamPLEventQueue, + typeUInt32, sizeof(PREventQueue*), &self); + if (err == noErr) { + err = PostEventToQueue(GetMainEventQueue(), newEvent, kEventPriorityLow); + ReleaseEvent(newEvent); + } + if (err != noErr) + return PR_FAILURE; +#endif + return PR_SUCCESS; +} +#endif /* defined(XP_MACOSX) */ + +static PRStatus +_pl_AcknowledgeNativeNotify(PLEventQueue* self) +{ +#if defined(_WIN32) || defined(XP_OS2) +#ifdef XP_OS2 + QMSG aMsg; +#else + MSG aMsg; +#endif + /* + * only remove msg when we've been called directly by + * PL_ProcessPendingEvents, not when we've been called by + * the window proc because the window proc will remove the + * msg for us. + */ + if (self->removeMsg) { + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p", self)); +#ifdef XP_OS2 + WinPeekMsg((HAB)0, &aMsg, self->eventReceiverWindow, + _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE); +#else + PeekMessage(&aMsg, self->eventReceiverWindow, + _pr_PostEventMsgId, _pr_PostEventMsgId, PM_REMOVE); + if (self->timerSet) { + KillTimer(self->eventReceiverWindow, TIMER_ID); + self->timerSet = PR_FALSE; + } +#endif + } + return PR_SUCCESS; +#elif defined(VMS) + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p efn=%d", + self, self->efn)); + /* + ** If this is the last entry, then clear the event flag. Also make sure + ** the flag is cleared on any spurious wakeups. + */ + sys$clref(self->efn); + return PR_SUCCESS; +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + + PRInt32 count; + unsigned char c; + PR_LOG(event_lm, PR_LOG_DEBUG, + ("_pl_AcknowledgeNativeNotify: self=%p", + self)); + /* consume the byte NativeNotify put in our pipe: */ + count = read(self->eventPipe[0], &c, 1); + if ((count == 1) && (c == NOTIFY_TOKEN)) + return PR_SUCCESS; + if ((count == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) + return PR_SUCCESS; + return PR_FAILURE; +#elif defined(MAC_USE_CFRUNLOOPSOURCE) /* vbox */ + /* vbox */ + CFRunLoopRunInMode(self->mRunLoopModeStr, 0.0, 1); /* vbox */ + return PR_SUCCESS; /* vbox */ +#else + + /* nothing to do on the other platforms */ + return PR_SUCCESS; +#endif +} + +PR_IMPLEMENT(PRInt32) +PL_GetEventQueueSelectFD(PLEventQueue* self) +{ + if (self == NULL) + return -1; + +#if defined(VMS) + return -(self->efn); +#elif defined(XP_UNIX) && !defined(XP_MACOSX) + return self->eventPipe[0]; +#else + return -1; /* other platforms don't handle this (yet) */ +#endif +} + +PR_IMPLEMENT(PRBool) +PL_IsQueueOnCurrentThread( PLEventQueue *queue ) +{ + PRThread *me = PR_GetCurrentThread(); + return me == queue->handlerThread; +} + +PR_EXTERN(PRBool) +PL_IsQueueNative(PLEventQueue *queue) +{ + return queue->type == EventQueueIsNative ? PR_TRUE : PR_FALSE; +} + +#if defined(_WIN32) +/* +** Global Instance handle... +** In Win32 this is the module handle of the DLL. +** +*/ +static HINSTANCE _pr_hInstance; +#endif + + +#if defined(_WIN32) + +/* +** Initialization routine for the DLL... +*/ + +BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + _pr_hInstance = hDLL; + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + _pr_hInstance = NULL; + break; + } + + return TRUE; +} +#endif + + +#if defined(_WIN32) || defined(XP_OS2) +#ifdef XP_OS2 +MRESULT EXPENTRY +_md_EventReceiverProc(HWND hwnd, ULONG uMsg, MPARAM wParam, MPARAM lParam) +#else +LRESULT CALLBACK +_md_EventReceiverProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +#endif +{ + if (_pr_PostEventMsgId == uMsg ) + { + PREventQueue *queue = (PREventQueue *)lParam; + queue->removeMsg = PR_FALSE; + PL_ProcessPendingEvents(queue); + queue->removeMsg = PR_TRUE; +#ifdef XP_OS2 + return MRFROMLONG(TRUE); +#else + return TRUE; +#endif + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +static PRBool isInitialized; +static PRCallOnceType once; +static PRLock *initLock; + +/* +** InitWinEventLib() -- Create the Windows initialization lock +** +*/ +static PRStatus InitEventLib( void ) +{ + PR_ASSERT( initLock == NULL ); + + initLock = PR_NewLock(); + return initLock ? PR_SUCCESS : PR_FAILURE; +} + +#endif /* Win32, OS2 */ + +#if defined(_WIN32) + +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + WNDCLASS wc; + + /* + ** If this is the first call to PL_InitializeEventsLib(), + ** make the call to InitWinEventLib() to create the initLock. + ** + ** Then lock the initializer lock to insure that + ** we have exclusive control over the initialization sequence. + ** + */ + + + /* Register the windows message for XPCOM Event notification */ + _pr_PostEventMsgId = RegisterWindowMessage("XPCOM_PostEvent"); + + /* Register the class for the event receiver window */ + if (!GetClassInfo(_pr_hInstance, _pr_eventWindowClass, &wc)) { + wc.style = 0; + wc.lpfnWndProc = _md_EventReceiverProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = _pr_hInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH) NULL; + wc.lpszMenuName = (LPCSTR) NULL; + wc.lpszClassName = _pr_eventWindowClass; + RegisterClass(&wc); + } + + /* Create the event receiver window */ + eventQueue->eventReceiverWindow = CreateWindow(_pr_eventWindowClass, + "XPCOM:EventReceiver", + 0, 0, 0, 10, 10, + NULL, NULL, _pr_hInstance, + NULL); + PR_ASSERT(eventQueue->eventReceiverWindow); + /* Set a property which can be used to retrieve the event queue + * within the _md_TimerProc callback + */ + SetProp(eventQueue->eventReceiverWindow, + _md_GetEventQueuePropName(), (HANDLE)eventQueue); + + return; +} /* end _md_CreateEventQueue() */ +#endif /* Winxx */ + +#if defined(XP_OS2) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + /* Must have HMQ for this & can't assume we already have appshell */ + if( FALSE == WinQueryQueueInfo( HMQ_CURRENT, NULL, 0)) + { + PPIB ppib; + PTIB ptib; + HAB hab; + HMQ hmq; + + /* Set our app to be a PM app before attempting Win calls */ + DosGetInfoBlocks(&ptib, &ppib); + ppib->pib_ultype = 3; + + hab = WinInitialize(0); + hmq = WinCreateMsgQueue(hab, 0); + PR_ASSERT(hmq); + } + + if( !_pr_PostEventMsgId) + { + WinRegisterClass( 0 /* hab_current */, + _pr_eventWindowClass, + _md_EventReceiverProc, + 0, 0); + + _pr_PostEventMsgId = WinAddAtom( WinQuerySystemAtomTable(), + "XPCOM_PostEvent"); + } + + eventQueue->eventReceiverWindow = WinCreateWindow( HWND_DESKTOP, + _pr_eventWindowClass, + "", 0, + 0, 0, 0, 0, + HWND_DESKTOP, + HWND_TOP, + 0, + NULL, + NULL); + PR_ASSERT(eventQueue->eventReceiverWindow); + + return; +} /* end _md_CreateEventQueue() */ +#endif /* XP_OS2 */ + +#if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ + /* there's really nothing special to do here, + ** the guts of the unix stuff is in the setupnativenotify + ** and related functions. + */ + return; +} /* end _md_CreateEventQueue() */ +#endif /* (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS) */ + +#if defined(MAC_USE_CFRUNLOOPSOURCE) +static void _md_EventReceiverProc(void *info) +{ + PLEventQueue *queue = (PLEventQueue*)info; + PL_ProcessPendingEvents(queue); +} + +#elif defined(MAC_USE_CARBON_EVENT) +/* +** _md_CreateEventQueue() -- ModelDependent initializer +*/ + +static pascal OSStatus _md_EventReceiverProc(EventHandlerCallRef nextHandler, + EventRef inEvent, + void* userData) +{ + if (GetEventClass(inEvent) == kEventClassPL && + GetEventKind(inEvent) == kEventProcessPLEvents) + { + PREventQueue *queue; + if (GetEventParameter(inEvent, kEventParamPLEventQueue, + typeUInt32, NULL, sizeof(PREventQueue*), NULL, + &queue) == noErr) + { + PL_ProcessPendingEvents(queue); + return noErr; + } + } + return eventNotHandledErr; +} + +static pascal Boolean _md_CarbonEventComparator(EventRef inEvent, + void *inCompareData) +{ + Boolean match = false; + + if (GetEventClass(inEvent) == kEventClassPL && + GetEventKind(inEvent) == kEventProcessPLEvents) + { + PREventQueue *queue; + match = ((GetEventParameter(inEvent, kEventParamPLEventQueue, + typeUInt32, NULL, sizeof(PREventQueue*), NULL, + &queue) == noErr) && (queue == inCompareData)); + } + return match; +} + +#endif /* defined(MAC_USE_CARBON_EVENT) */ + +#if defined(XP_MACOSX) +static void _md_CreateEventQueue( PLEventQueue *eventQueue ) +{ +#if defined(MAC_USE_CFRUNLOOPSOURCE) + CFRunLoopSourceContext sourceContext = { 0 }; + sourceContext.version = 0; + sourceContext.info = (void*)eventQueue; + sourceContext.perform = _md_EventReceiverProc; + + /* make a run loop source */ + eventQueue->mRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 /* order */, &sourceContext); + PR_ASSERT(eventQueue->mRunLoopSource); + + eventQueue->mMainRunLoop = CFRunLoopGetCurrent(); + CFRetain(eventQueue->mMainRunLoop); + + /* and add it to the run loop */ + CFRunLoopAddSource(eventQueue->mMainRunLoop, eventQueue->mRunLoopSource, kCFRunLoopCommonModes); + + /* Add it again but with a unique mode name so we can acknowledge it + without processing any other message sources. */ + { /* vbox */ + char szModeName[80]; /* vbox */ + snprintf(szModeName, sizeof(szModeName), "VBoxXPCOMQueueMode-%p", eventQueue); /* vbox */ + eventQueue->mRunLoopModeStr = CFStringCreateWithCString(kCFAllocatorDefault, /* vbox */ + szModeName, kCFStringEncodingASCII); /* vbox */ + CFRunLoopAddSource(eventQueue->mMainRunLoop, /* vbox */ + eventQueue->mRunLoopSource, eventQueue->mRunLoopModeStr); /* vbox */ + } /* vbox */ + +#elif defined(MAC_USE_CARBON_EVENT) + eventQueue->eventHandlerUPP = NewEventHandlerUPP(_md_EventReceiverProc); + PR_ASSERT(eventQueue->eventHandlerUPP); + if (eventQueue->eventHandlerUPP) + { + EventTypeSpec eventType; + + eventType.eventClass = kEventClassPL; + eventType.eventKind = kEventProcessPLEvents; + + InstallApplicationEventHandler(eventQueue->eventHandlerUPP, 1, &eventType, + eventQueue, &eventQueue->eventHandlerRef); + PR_ASSERT(eventQueue->eventHandlerRef); + } +#endif +} /* end _md_CreateEventQueue() */ +#endif /* defined(XP_MACOSX) */ + +/* extra functions for unix */ + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + +PR_IMPLEMENT(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID) +{ + PRInt32 count = 0; + PRInt32 fullCount; + + if (aSelf == NULL) + return -1; + + PR_EnterMonitor(aSelf->monitor); + + if (aSelf->processingEvents) { + PR_ExitMonitor(aSelf->monitor); + return 0; + } + + aSelf->processingEvents = PR_TRUE; + + /* Only process the events that are already in the queue, and + * not any new events that get added. Do this by counting the + * number of events currently in the queue + */ + fullCount = _pl_GetEventCount(aSelf); + PR_LOG(event_lm, PR_LOG_DEBUG, + ("$$$ fullCount is %d id is %ld\n", fullCount, aID)); + + if (fullCount == 0) { + aSelf->processingEvents = PR_FALSE; + PR_ExitMonitor(aSelf->monitor); + return 0; + } + + PR_ExitMonitor(aSelf->monitor); + + while (fullCount-- > 0) { + /* peek at the next event */ + PLEvent *event; + event = PR_EVENT_PTR(aSelf->queue.next); + if (event == NULL) + break; + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ processing event %ld\n", + event->id)); + if (event->id >= aID) { + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ skipping event and breaking")); + break; + } + + event = PL_GetEvent(aSelf); + PL_HandleEvent(event); + PR_LOG(event_lm, PR_LOG_DEBUG, ("$$$ done processing event")); + count++; + } + + PR_EnterMonitor(aSelf->monitor); + + /* if full count still had items left then there's still items left + in the queue. Let the native notify token stay. */ + + if (aSelf->type == EventQueueIsNative) { + fullCount = _pl_GetEventCount(aSelf); + + if (fullCount <= 0) { + _pl_AcknowledgeNativeNotify(aSelf); + aSelf->notified = PR_FALSE; + } + } + + aSelf->processingEvents = PR_FALSE; + + PR_ExitMonitor(aSelf->monitor); + + return count; +} + +PR_IMPLEMENT(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure) +{ + aSelf->idFunc = aFunc; + aSelf->idFuncClosure = aClosure; +} + +PR_IMPLEMENT(void) +PL_UnregisterEventIDFunc(PLEventQueue *aSelf) +{ + aSelf->idFunc = 0; + aSelf->idFuncClosure = 0; +} + +#endif /* defined(XP_UNIX) && !defined(XP_MACOSX) */ + +/* --- end plevent.c --- */ diff --git a/src/libs/xpcom18a4/xpcom/threads/plevent.h b/src/libs/xpcom18a4/xpcom/threads/plevent.h new file mode 100644 index 00000000..5bc9c89f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/threads/plevent.h @@ -0,0 +1,690 @@ +/* -*- 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 mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/********************************************************************** +NSPL Events + +Defining Events +--------------- + +Events are essentially structures that represent argument lists for a +function that will run on another thread. All event structures you +define must include a PLEvent struct as their first field: + + typedef struct MyEventType { + PLEvent e; + // arguments follow... + int x; + char* y; + } MyEventType; + +It is also essential that you establish a model of ownership for each +argument passed in an event record, i.e. whether particular arguments +will be deleted by the event destruction callback, or whether they +only loaned to the event handler callback, and guaranteed to persist +until the time at which the handler is called. + +Sending Events +-------------- + +Events are initialized by PL_InitEvent and can be sent via +PL_PostEvent or PL_PostSynchronousEvent. Events can also have an +owner. The owner of an event can revoke all the events in a given +event-queue by calling PL_RevokeEvents. An owner might want +to do this if, for instance, it is being destroyed, and handling the +events after the owner's destruction would cause an error (e.g. an +MWContext). + +Since the act of initializing and posting an event must be coordinated +with it's possible revocation, it is essential that the event-queue's +monitor be entered surrounding the code that constructs, initializes +and posts the event: + + void postMyEvent(MyOwner* owner, int x, char* y) + { + MyEventType* event; + + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + + // construct + event = PR_NEW(MyEventType); + if (event == NULL) goto done; + + // initialize + PL_InitEvent(event, owner, + (PLHandleEventProc)handleMyEvent, + (PLDestroyEventProc)destroyMyEvent); + event->x = x; + event->y = strdup(y); + + // post + PL_PostEvent(myQueue, &event->e); + + done: + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + } + +If you don't call PL_InitEvent and PL_PostEvent within the +event-queue's monitor, you'll get a big red assert. + +Handling Events +--------------- + +To handle an event you must write a callback that is passed the event +record you defined containing the event's arguments: + + void* handleMyEvent(MyEventType* event) + { + doit(event->x, event->y); + return NULL; // you could return a value for a sync event + } + +Similarly for the destruction callback: + + void destroyMyEvent(MyEventType* event) + { + free(event->y); // created by strdup + free(event); + } + +Processing Events in Your Event Loop +------------------------------------ + +If your main loop only processes events delivered to the event queue, +things are rather simple. You just get the next event (which may +block), and then handle it: + + while (1) { + event = PL_GetEvent(myQueue); + PL_HandleEvent(event); + } + +However, if other things must be waited on, you'll need to obtain a +file-descriptor that represents your event queue, and hand it to select: + + fd = PL_GetEventQueueSelectFD(myQueue); + ...add fd to select set... + while (select(...)) { + if (...fd...) { + PL_ProcessPendingEvents(myQueue); + } + ... + } + +Of course, with Motif and Windows it's more complicated than that, and +on Mac it's completely different, but you get the picture. + +Revoking Events +--------------- +If at any time an owner of events is about to be destroyed, you must +take steps to ensure that no one tries to use the event queue after +the owner is gone (or a crash may result). You can do this by either +processing all the events in the queue before destroying the owner: + + { + ... + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + PL_ProcessPendingEvents(myQueue); + DestroyMyOwner(owner); + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + ... + } + +or by revoking the events that are in the queue for that owner. This +removes them from the queue and calls their destruction callback: + + { + ... + PL_ENTER_EVENT_QUEUE_MONITOR(myQueue); + PL_RevokeEvents(myQueue, owner); + DestroyMyOwner(owner); + PL_EXIT_EVENT_QUEUE_MONITOR(myQueue); + ... + } + +In either case it is essential that you be in the event-queue's monitor +to ensure that all events are removed from the queue for that owner, +and to ensure that no more events will be delivered for that owner. +**********************************************************************/ + +#ifndef plevent_h___ +#define plevent_h___ + +#include "prtypes.h" +#include "prclist.h" +#include "prthread.h" +#include "prlock.h" +#include "prcvar.h" +#include "prmon.h" + +/* For HWND */ +#if defined(XP_WIN32) +#include +#elif defined(XP_OS2) +#define INCL_DOSMISC +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#include +#endif + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define PL_DestroyEvent VBoxNsplPL_DestroyEvent +#define PL_HandleEvent VBoxNsplPL_HandleEvent +#define PL_InitEvent VBoxNsplPL_InitEvent +#define PL_CreateEventQueue VBoxNsplPL_CreateEventQueue +#define PL_CreateMonitoredEventQueue VBoxNsplPL_CreateMonitoredEventQueue +#define PL_CreateNativeEventQueue VBoxNsplPL_CreateNativeEventQueue +#define PL_DequeueEvent VBoxNsplPL_DequeueEvent +#define PL_DestroyEventQueue VBoxNsplPL_DestroyEventQueue +#define PL_EventAvailable VBoxNsplPL_EventAvailable +#define PL_EventLoop VBoxNsplPL_EventLoop +#define PL_GetEvent VBoxNsplPL_GetEvent +#define PL_GetEventOwner VBoxNsplPL_GetEventOwner +#define PL_GetEventQueueMonitor VBoxNsplPL_GetEventQueueMonitor +#define PL_GetEventQueueSelectFD VBoxNsplPL_GetEventQueueSelectFD +#define PL_MapEvents VBoxNsplPL_MapEvents +#define PL_PostEvent VBoxNsplPL_PostEvent +#define PL_PostSynchronousEvent VBoxNsplPL_PostSynchronousEvent +#define PL_ProcessEventsBeforeID VBoxNsplPL_ProcessEventsBeforeID +#define PL_ProcessPendingEvents VBoxNsplPL_ProcessPendingEvents +#define PL_RegisterEventIDFunc VBoxNsplPL_RegisterEventIDFunc +#define PL_RevokeEvents VBoxNsplPL_RevokeEvents +#define PL_UnregisterEventIDFunc VBoxNsplPL_UnregisterEventIDFunc +#define PL_WaitForEvent VBoxNsplPL_WaitForEvent +#define PL_IsQueueNative VBoxNsplPL_IsQueueNative +#define PL_IsQueueOnCurrentThread VBoxNsplPL_IsQueueOnCurrentThread +#define PL_FavorPerformanceHint VBoxNsplPL_FavorPerformanceHint +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* Typedefs */ + +typedef struct PLEvent PLEvent; +typedef struct PLEventQueue PLEventQueue; + +/******************************************************************************* + * Event Queue Operations + ******************************************************************************/ + +/* +** Creates a new event queue. Returns NULL on failure. +*/ +PR_EXTERN(PLEventQueue*) +PL_CreateEventQueue(const char* name, PRThread* handlerThread); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_CreateNativeEventQueue() +** +** DESCRIPTION: +** PL_CreateNativeEventQueue() creates an event queue that +** uses platform specific notify mechanisms. +** +** For Unix, the platform specific notify mechanism provides +** an FD that may be extracted using the function +** PL_GetEventQueueSelectFD(). The FD returned may be used in +** a select() function call. +** +** For Windows, the platform specific notify mechanism +** provides an event receiver window that is called by +** Windows to process the event using the windows message +** pump engine. +** +** INPUTS: +** name: A name, as a diagnostic aid. +** +** handlerThread: A pointer to the PRThread structure for +** the thread that will "handle" events posted to this event +** queue. +** +** RETURNS: +** A pointer to a PLEventQueue structure or NULL. +** +*/ +PR_EXTERN(PLEventQueue *) + PL_CreateNativeEventQueue( + const char *name, + PRThread *handlerThread + ); + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_CreateMonitoredEventQueue() +** +** DESCRIPTION: +** PL_CreateMonitoredEventQueue() creates an event queue. No +** platform specific notify mechanism is created with the +** event queue. +** +** Users of this type of event queue must explicitly poll the +** event queue to retreive and process events. +** +** +** INPUTS: +** name: A name, as a diagnostic aid. +** +** handlerThread: A pointer to the PRThread structure for +** the thread that will "handle" events posted to this event +** queue. +** +** RETURNS: +** A pointer to a PLEventQueue structure or NULL. +** +*/ +PR_EXTERN(PLEventQueue *) + PL_CreateMonitoredEventQueue( + const char *name, + PRThread *handlerThread + ); + +/* +** Destroys an event queue. +*/ +PR_EXTERN(void) +PL_DestroyEventQueue(PLEventQueue* self); + +/* +** Returns the monitor associated with an event queue. This monitor is +** selectable. The monitor should be entered to protect against anyone +** calling PL_RevokeEvents while the event is trying to be constructed +** and delivered. +*/ +PR_EXTERN(PRMonitor*) +PL_GetEventQueueMonitor(PLEventQueue* self); + +#define PL_ENTER_EVENT_QUEUE_MONITOR(queue) \ + PR_EnterMonitor(PL_GetEventQueueMonitor(queue)) + +#define PL_EXIT_EVENT_QUEUE_MONITOR(queue) \ + PR_ExitMonitor(PL_GetEventQueueMonitor(queue)) + +/* +** Posts an event to an event queue, waking up any threads waiting for an +** event. If event is NULL, notification still occurs, but no event will +** be available. +** +** Any events delivered by this routine will be destroyed by PL_HandleEvent +** when it is called (by the event-handling thread). +*/ +PR_EXTERN(PRStatus) +PL_PostEvent(PLEventQueue* self, PLEvent* event); + +/* +** Like PL_PostEvent, this routine posts an event to the event handling +** thread, but does so synchronously, waiting for the result. The result +** which is the value of the handler routine is returned. +** +** Any events delivered by this routine will be not be destroyed by +** PL_HandleEvent, but instead will be destroyed just before the result is +** returned (by the current thread). +*/ +PR_EXTERN(void*) +PL_PostSynchronousEvent(PLEventQueue* self, PLEvent* event); + +/* +** Gets an event from an event queue. Returns NULL if no event is +** available. +*/ +PR_EXTERN(PLEvent*) +PL_GetEvent(PLEventQueue* self); + +/* +** Returns true if there is an event available for PL_GetEvent. +*/ +PR_EXTERN(PRBool) +PL_EventAvailable(PLEventQueue* self); + +/* +** This is the type of the function that must be passed to PL_MapEvents +** (see description below). +*/ +typedef void +(PR_CALLBACK *PLEventFunProc)(PLEvent* event, void* data, PLEventQueue* queue); + +/* +** Applies a function to every event in the event queue. This can be used +** to selectively handle, filter, or remove events. The data pointer is +** passed to each invocation of the function fun. +*/ +PR_EXTERN(void) +PL_MapEvents(PLEventQueue* self, PLEventFunProc fun, void* data); + +/* +** This routine walks an event queue and destroys any event whose owner is +** the owner specified. The == operation is used to compare owners. +*/ +PR_EXTERN(void) +PL_RevokeEvents(PLEventQueue* self, void* owner); + +/* +** This routine processes all pending events in the event queue. It can be +** called from the thread's main event-processing loop whenever the event +** queue's selectFD is ready (returned by PL_GetEventQueueSelectFD). +*/ +PR_EXTERN(void) +PL_ProcessPendingEvents(PLEventQueue* self); + +/******************************************************************************* + * Pure Event Queues + * + * For when you're only processing PLEvents and there is no native + * select, thread messages, or AppleEvents. + ******************************************************************************/ + +/* +** Blocks until an event can be returned from the event queue. This routine +** may return NULL if the current thread is interrupted. +*/ +PR_EXTERN(PLEvent*) +PL_WaitForEvent(PLEventQueue* self); + +/* +** One stop shopping if all you're going to do is process PLEvents. Just +** call this and it loops forever processing events as they arrive. It will +** terminate when your thread is interrupted or dies. +*/ +PR_EXTERN(void) +PL_EventLoop(PLEventQueue* self); + +/******************************************************************************* + * Native Event Queues + * + * For when you need to call select, or WaitNextEvent, and yet also want + * to handle PLEvents. + ******************************************************************************/ + +/* +** This routine allows you to grab the file descriptor associated with an +** event queue and use it in the readFD set of select. Useful for platforms +** that support select, and must wait on other things besides just PLEvents. +*/ +PR_EXTERN(PRInt32) +PL_GetEventQueueSelectFD(PLEventQueue* self); + +/* +** This routine will allow you to check to see if the given eventQueue in +** on the current thread. It will return PR_TRUE if so, else it will return +** PR_FALSE +*/ +PR_EXTERN(PRBool) + PL_IsQueueOnCurrentThread( PLEventQueue *queue ); + +/* +** Returns whether the queue is native (true) or monitored (false) +*/ +PR_EXTERN(PRBool) +PL_IsQueueNative(PLEventQueue *queue); + +/******************************************************************************* + * Event Operations + ******************************************************************************/ + +/* +** The type of an event handler function. This function is passed as an +** initialization argument to PL_InitEvent, and called by +** PL_HandleEvent. If the event is called synchronously, a void* result +** may be returned (otherwise any result will be ignored). +*/ +typedef void* +(PR_CALLBACK *PLHandleEventProc)(PLEvent* self); + +/* +** The type of an event destructor function. This function is passed as +** an initialization argument to PL_InitEvent, and called by +** PL_DestroyEvent. +*/ +typedef void +(PR_CALLBACK *PLDestroyEventProc)(PLEvent* self); + +/* +** Initializes an event. Usually events are embedded in a larger event +** structure which holds event-specific data, so this is an initializer +** for that embedded part of the structure. +*/ +PR_EXTERN(void) +PL_InitEvent(PLEvent* self, void* owner, + PLHandleEventProc handler, + PLDestroyEventProc destructor); + +/* +** Returns the owner of an event. +*/ +PR_EXTERN(void*) +PL_GetEventOwner(PLEvent* self); + +/* +** Handles an event, calling the event's handler routine. +*/ +PR_EXTERN(void) +PL_HandleEvent(PLEvent* self); + +/* +** Destroys an event, calling the event's destructor. +*/ +PR_EXTERN(void) +PL_DestroyEvent(PLEvent* self); + +/* +** Removes an event from an event queue. +*/ +PR_EXTERN(void) +PL_DequeueEvent(PLEvent* self, PLEventQueue* queue); + + +/* + * Give hint to native PL_Event notification mechanism. If the native + * platform needs to tradeoff performance vs. native event starvation + * this hint tells the native dispatch code which to favor. + * The default is to prevent event starvation. + * + * Calls to this function may be nested. When the number of calls that + * pass PR_TRUE is subtracted from the number of calls that pass PR_FALSE + * is greater than 0, performance is given precedence over preventing + * event starvation. + * + * The starvationDelay arg is only used when + * favorPerformanceOverEventStarvation is PR_FALSE. It is the + * amount of time in milliseconds to wait before the PR_FALSE actually + * takes effect. + */ +PR_EXTERN(void) +PL_FavorPerformanceHint(PRBool favorPerformanceOverEventStarvation, PRUint32 starvationDelay); + + +/******************************************************************************* + * Private Stuff + ******************************************************************************/ + +struct PLEvent { + PRCList link; + PLHandleEventProc handler; + PLDestroyEventProc destructor; + void* owner; + void* synchronousResult; + PRLock* lock; + PRCondVar* condVar; + PRBool handled; +#ifdef PL_POST_TIMINGS + PRIntervalTime postTime; +#endif +#ifdef XP_UNIX + unsigned long id; +#endif /* XP_UNIX */ + /* other fields follow... */ +}; + +/******************************************************************************/ + +/* +** Returns the event queue associated with the main thread. +** +*/ +#if defined(XP_WIN) || defined(XP_OS2) +/* ----------------------------------------------------------------------- +** FUNCTION: PL_GetNativeEventReceiverWindow() +** +** DESCRIPTION: +** PL_GetNativeEventReceiverWindow() returns the windows +** handle of the event receiver window associated with the +** referenced PLEventQueue argument. +** +** INPUTS: +** PLEventQueue pointer +** +** RETURNS: +** event receiver window handle. +** +** RESTRICTIONS: MS-Windows ONLY. +** +*/ +PR_EXTERN(HWND) + PL_GetNativeEventReceiverWindow( + PLEventQueue *eqp + ); +#endif /* XP_WIN || XP_OS2 */ + +#ifdef XP_UNIX +/* ----------------------------------------------------------------------- +** FUNCTION: PL_ProcessEventsBeforeID() +** +** DESCRIPTION: +** +** PL_ProcessEventsBeforeID() will process events in a native event +** queue that have an id that is older than the ID passed in. +** +** INPUTS: +** PLEventQueue *aSelf +** unsigned long aID +** +** RETURNS: +** PRInt32 number of requests processed, -1 on error. +** +** RESTRICTIONS: Unix only (well, X based unix only) +*/ +PR_EXTERN(PRInt32) +PL_ProcessEventsBeforeID(PLEventQueue *aSelf, unsigned long aID); + +/* This prototype is a function that can be called when an event is + posted to stick an ID on it. */ + +typedef unsigned long +(PR_CALLBACK *PLGetEventIDFunc)(void *aClosure); + + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_RegisterEventIDFunc() +** +** DESCRIPTION: +** +** This function registers a function for getting the ID on unix for +** this event queue. +** +** INPUTS: +** PLEventQueue *aSelf +** PLGetEventIDFunc func +** void *aClosure +** +** RETURNS: +** void +** +** RESTRICTIONS: Unix only (well, X based unix only) */ +PR_EXTERN(void) +PL_RegisterEventIDFunc(PLEventQueue *aSelf, PLGetEventIDFunc aFunc, + void *aClosure); + +/* ----------------------------------------------------------------------- +** FUNCTION: PL_RegisterEventIDFunc() +** +** DESCRIPTION: +** +** This function unregisters a function for getting the ID on unix for +** this event queue. +** +** INPUTS: +** PLEventQueue *aSelf +** +** RETURNS: +** void +** +** RESTRICTIONS: Unix only (well, X based unix only) */ +PR_EXTERN(void) +PL_UnregisterEventIDFunc(PLEventQueue *aSelf); + +#endif /* XP_UNIX */ + + +/* ----------------------------------------------------------------------- */ + +#if defined(NO_NSPR_10_SUPPORT) +#else +/********* ???????????????? FIX ME ??????????????????????????? *****/ +/********************** Some old definitions *****************************/ + +/* Re: prevent.h->plevent.h */ +#define PREvent PLEvent +#define PREventQueue PLEventQueue +#define PR_CreateEventQueue PL_CreateEventQueue +#define PR_DestroyEventQueue PL_DestroyEventQueue +#define PR_GetEventQueueMonitor PL_GetEventQueueMonitor +#define PR_ENTER_EVENT_QUEUE_MONITOR PL_ENTER_EVENT_QUEUE_MONITOR +#define PR_EXIT_EVENT_QUEUE_MONITOR PL_EXIT_EVENT_QUEUE_MONITOR +#define PR_PostEvent PL_PostEvent +#define PR_PostSynchronousEvent PL_PostSynchronousEvent +#define PR_GetEvent PL_GetEvent +#define PR_EventAvailable PL_EventAvailable +#define PREventFunProc PLEventFunProc +#define PR_MapEvents PL_MapEvents +#define PR_RevokeEvents PL_RevokeEvents +#define PR_ProcessPendingEvents PL_ProcessPendingEvents +#define PR_WaitForEvent PL_WaitForEvent +#define PR_EventLoop PL_EventLoop +#define PR_GetEventQueueSelectFD PL_GetEventQueueSelectFD +#define PRHandleEventProc PLHandleEventProc +#define PRDestroyEventProc PLDestroyEventProc +#define PR_InitEvent PL_InitEvent +#define PR_GetEventOwner PL_GetEventOwner +#define PR_HandleEvent PL_HandleEvent +#define PR_DestroyEvent PL_DestroyEvent +#define PR_DequeueEvent PL_DequeueEvent +#define PR_GetMainEventQueue PL_GetMainEventQueue + +/********* ????????????? End Fix me ?????????????????????????????? *****/ +#endif /* NO_NSPR_10_SUPPORT */ + +PR_END_EXTERN_C + +#endif /* plevent_h___ */ diff --git a/src/libs/xpcom18a4/xpcom/tools/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tools/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/Makefile.in new file mode 100644 index 00000000..be87de04 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/Makefile.in @@ -0,0 +1,53 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = registry + +ifeq ($(OS_ARCH),WINNT) +DIRS += windows +endif + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl b/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl new file mode 100755 index 00000000..81ccb212 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/analyze-xpcom-log.pl @@ -0,0 +1,177 @@ +#!/usr/local/bin/perl -w + +# Perl script to analyze the xpcom output file +# +# To create xpcom output file : +# +# setenv NSPR_LOG_MODULES nsComponentManager:5 +# setenv NSPR_LOG_FILE xpcom.out +# ./mozilla +# +# Also to try to convert CID -> contractID this program looks for +# a file reg.out in the current directory. To generate this file +# +# $ regExport > reg.out +# +# Usage: analyze-xpcom-log.pl < xpcom.out +# [does better if ./reg.out is available] +# +# Suresh Duddi + + +use strict; + +# forward declarations +sub getContractID($); +sub sum($); + +# Configuration parameters +# Print all ? +my $all = 0; + +# hash of cid -> contractid +my %contractid; +my %contractid_n; +my %failedContractid_n; + +# count of instances of objects created +my (%objs, %objs_contractid, %failedObjs) = (); + +# dlls loaded +my @dlls; + +# temporaries +my ($cid, $n, $str); + +while (<>) { + chomp; + + # dlls loaded + if (/loading \"(.*)\"/) { + push @dlls, $1; + next; + } + + # FAILED ContractIDToClassID + if (/ContractIDToClassID\((.*)\).*\[FAILED\]/) { + $failedContractid_n{$1}++; + next; + } + + # ContractIDToClassID + if (/ContractIDToClassID\((.*)\).*\{(.*)\}/) { + $contractid{$2} = $1; + $contractid_n{$2}++; + next; + } + + # CreateInstance() + if (/CreateInstance\(\{(.*)\}\) succeeded/) { + $objs{$1}++; + next; + } + + # CreateInstanceByContractID() + if (/CreateInstanceByContractID\((.*)\) succeeded/) { + $objs_contractid{$1}++; + next; + } + + # FAILED CreateInstance() + if (/CreateInstance\(\{(.*)\}\) FAILED/) { + $failedObjs{$1}++; + next; + } +} + +# if there is a file named reg.out in the current dir +# then use that to fill in the ContractIDToClassID mapping. +my $REG; +open REG, ") { + chomp; + if (/contractID - (.*)$/) { + my $id = $1; + $cid = ; + chomp($cid); + $cid =~ s/^.*\{(.*)\}.*$/$1/; + $contractid{$cid} = $id; + } +} + +# print results +# ---------------------------------------------------------------------- + +# dlls loaded +print "dlls loaded [", scalar @dlls, "]\n"; +print "----------------------------------------------------------------------\n"; +for ($n = 0; $n < scalar @dlls; $n++) { + printf "%2d. %s\n", $n+1, $dlls[$n]; +} +print "\n"; + +# Objects created +print "Object creations from CID [", sum(\%objs), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$objs{$b} <=> $objs{$a} } keys %objs) { + last if (!$all && $objs{$cid} < 50); + printf "%5d. %s - %s\n", $objs{$cid}, $cid, getContractID($cid); +} +print "\n"; + +print "Object creations from ContractID [", sum(\%objs_contractid), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$objs_contractid{$b} <=> $objs_contractid{$a} } keys %objs_contractid) { + last if (!$all && $objs_contractid{$cid} < 50); + printf "%5d. %s - %s\n", $objs_contractid{$cid}, $cid, getContractID($cid); +} +print "\n"; + +# FAILED Objects created +print "FAILED Objects creations [", sum(\%failedObjs), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$failedObjs{$b} <=> $failedObjs{$a} } keys %failedObjs) { + last if (!$all && $failedObjs{$cid} < 50); + printf "%5d. %s - %s", $failedObjs{$cid}, $cid, getContractID($cid); +} +print "\n"; + +# ContractIDToClassID calls +print "ContractIDToClassID() calls [", sum(\%contractid_n),"]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$contractid_n{$b} <=> $contractid_n{$a} } keys %contractid_n) { + last if (!$all && $contractid_n{$cid} < 50); + printf "%5d. %s - %s\n", $contractid_n{$cid}, $cid, getContractID($cid); +} +print "\n"; + + +# FAILED ContractIDToClassID calls +print "FAILED ContractIDToClassID() calls [", sum(\%failedContractid_n), "]\n"; +print "----------------------------------------------------------------------\n"; +foreach $cid (sort {$failedContractid_n{$b} <=> $failedContractid_n{$a} } keys %failedContractid_n) { + last if (!$all && $failedContractid_n{$cid} < 50); + printf "%5d. %s\n", $failedContractid_n{$cid}, $cid; +} +print "\n"; + + +# Subroutines + +sub getContractID($) { + my $cid = shift; + my $ret = ""; + $ret = $contractid{$cid} if (exists $contractid{$cid}); + return $ret; +} + +sub sum($) { + my $hash_ref = shift; + my %hash = %$hash_ref; + my $total = 0; + my $key; + foreach $key (keys %hash) { + $total += $hash{$key}; + } + return $total; +} diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore new file mode 100644 index 00000000..91acd38b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/.cvsignore @@ -0,0 +1,3 @@ +Makefile +regExport +regxpcom diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in new file mode 100644 index 00000000..5c19d014 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/Makefile.in @@ -0,0 +1,77 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPPSRCS = regxpcom.cpp + +DEFINES += -DXPCOM_GLUE + +REQUIRES = \ + string \ + $(NULL) + +LOCAL_INCLUDES = \ + -I$(srcdir)/../../build \ + $(NULL) + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = \ + $(DIST)/lib/$(LIB_PREFIX)xpcomglue.$(LIB_SUFFIX) \ + $(NSPR_LIBS) \ + $(NULL) + +# Need to link with CoreFoundation on Mac +ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +LIBS += \ + $(TK_LIBS) \ + $(NULL) +endif + +SDK_BINARY = \ + $(SIMPLE_PROGRAMS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp b/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp new file mode 100644 index 00000000..b8822b8f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/registry/regxpcom.cpp @@ -0,0 +1,404 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * Mike Shaver + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 "stdlib.h" +#include "prenv.h" +#include "nspr.h" + +#include "nsXPCOMPrivate.h" // for XPCOM_DLL defines. + +#include "nsXPCOMGlue.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIServiceManager.h" +#include "nsCOMPtr.h" +#include "nsILocalFile.h" +#include "nsEmbedString.h" +#include "nsIDirectoryService.h" +#include "nsDirectoryServiceDefs.h" + + +static PRBool gUnreg = PR_FALSE, gQuiet = PR_FALSE; + +static const char* gXPCOMLocation = nsnull; +static const char* gCompRegLocation = nsnull; +static const char* gXPTIDatLocation = nsnull; +static char* gPathEnvString = nsnull; + +class DirectoryServiceProvider : public nsIDirectoryServiceProvider +{ + public: + DirectoryServiceProvider() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIDIRECTORYSERVICEPROVIDER + + private: + ~DirectoryServiceProvider() {} +}; + +NS_IMPL_ISUPPORTS1(DirectoryServiceProvider, nsIDirectoryServiceProvider) + +NS_IMETHODIMP +DirectoryServiceProvider::GetFile(const char *prop, PRBool *persistant, nsIFile **_retval) +{ + nsCOMPtr localFile; + nsresult rv = NS_ERROR_FAILURE; + + *_retval = nsnull; + *persistant = PR_TRUE; + + const char* fileLocation = nsnull; + + if(strcmp(prop, NS_XPCOM_CURRENT_PROCESS_DIR) == 0 && gXPCOMLocation) + { + fileLocation = gXPCOMLocation; + } + else if(strcmp(prop, NS_XPCOM_COMPONENT_REGISTRY_FILE) == 0 && gCompRegLocation) + { + fileLocation = gCompRegLocation; + } + else if(strcmp(prop, NS_XPCOM_XPTI_REGISTRY_FILE) == 0 && gXPTIDatLocation) + { + fileLocation = gXPTIDatLocation; + } + else + return NS_ERROR_FAILURE; + + rv = NS_NewNativeLocalFile(nsEmbedCString(fileLocation), PR_TRUE, getter_AddRefs(localFile)); + if (NS_FAILED(rv)) return rv; + + return localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)_retval); +} + +int startup_xpcom() +{ + nsresult rv; + + if (gXPCOMLocation) { + int len = strlen(gXPCOMLocation); + char* xpcomPath = (char*) malloc(len + sizeof(XPCOM_DLL) + sizeof(XPCOM_FILE_PATH_SEPARATOR) + 1); + sprintf(xpcomPath, "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, gXPCOMLocation); + + rv = XPCOMGlueStartup(xpcomPath); + + free(xpcomPath); + + const char* path = PR_GetEnv(XPCOM_SEARCH_KEY); + if (!path) { + path = ""; + } + + if (gPathEnvString) + PR_smprintf_free(gPathEnvString); + + gPathEnvString = PR_smprintf("%s=%s;%s", + XPCOM_SEARCH_KEY, + gXPCOMLocation, + path); + + if (gXPCOMLocation) + PR_SetEnv(gPathEnvString); + } + else + { + rv = XPCOMGlueStartup(nsnull); + } + + if (NS_FAILED(rv)) + { + printf("Can not initialize XPCOM Glue\n"); + return -1; + } + + DirectoryServiceProvider *provider = new DirectoryServiceProvider(); + if ( !provider ) + { + NS_WARNING("GRE_Startup failed"); + XPCOMGlueShutdown(); + return -1; + } + + nsCOMPtr file; + if (gXPCOMLocation) + { + rv = NS_NewNativeLocalFile(nsEmbedCString(gXPCOMLocation), + PR_TRUE, + getter_AddRefs(file)); + } + + NS_ADDREF(provider); + rv = NS_InitXPCOM2(nsnull, file, provider); + NS_RELEASE(provider); + + if (NS_FAILED(rv)) { + printf("Can not initialize XPCOM\n"); + XPCOMGlueShutdown(); + return -1; + } + + return 0; +} + +void shutdown_xpcom() +{ + nsresult rv; + + rv = NS_ShutdownXPCOM(nsnull); + + if (NS_FAILED(rv)) { + printf("Can not shutdown XPCOM cleanly\n"); + } + + rv = XPCOMGlueShutdown(); + + if (NS_FAILED(rv)) { + printf("Can not shutdown XPCOM Glue cleanly\n"); + } + if (gPathEnvString) + PR_smprintf_free(gPathEnvString); +} + + +nsresult Register(const char *path) +{ + startup_xpcom(); + + nsresult rv; + nsCOMPtr spec; + + if (path) { + rv = NS_NewNativeLocalFile(nsEmbedCString(path), + PR_TRUE, + getter_AddRefs(spec)); + } + + nsCOMPtr registrar; + rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); + if (NS_FAILED(rv)) { + printf("Can not aquire component registrar\n"); + return rv; + } + + if (gUnreg) + rv = registrar->AutoUnregister(spec); + else + rv = registrar->AutoRegister(spec); + + spec = 0; + registrar = 0; + + shutdown_xpcom(); + return rv; +} + + +void ReportSuccess(const char *file) +{ + if (gQuiet) + return; + + if (gUnreg) + printf("Unregistration successful for %s\n", file); + else + printf("Registration successful for %s\n", file); +} + +void ReportError(nsresult err, const char *file) +{ + if (gUnreg) + printf("Unregistration failed: ("); + else + printf("Registration failed: ("); + + switch (err) + { + case NS_ERROR_FACTORY_NOT_LOADED: + printf("Factory not loaded"); + break; + case NS_NOINTERFACE: + printf("No Interface"); + break; + case NS_ERROR_NULL_POINTER: + printf("Null pointer"); + break; + case NS_ERROR_OUT_OF_MEMORY: + printf("Out of memory"); + break; + default: + printf("%x", (unsigned)err); + } + + printf(") %s\n", file); +} + +void printHelp() +{ + printf( +"Mozilla regxpcom - a registration tool for xpcom components \n" +" \n" +"Usage: regxpcom [options] [file-or-directory] \n" +" \n" +"Options: \n" +" -x path Specifies the location of a directory containing the \n" +" xpcom library which will be used when registering new \n" +" component libraries. This path will also be added to \n" +" the \"load library\" path. If not specified, the \n" +" current working directory will be used. \n" +" -c path Specifies the location of the compreg.dat file. If \n" +" not specifed, the compreg.dat file will be in its \n" +" default location. \n" +" -d path Specifies the location of the xpti.dat file. If not \n" +" specifed, the xpti.dat file will be in its default \n" +" location. \n" +" -a Option to register all files in the default component \n" +" directories. This is the default behavior if regxpcom \n" +" is called without any arguments. \n" +" -h Displays this help screen. Must be the only option \n" +" specified. \n" +" -u Option to uninstall the files-or-directory instead of \n" +" registering them. \n" +" -q Quiets some of the output of regxpcom. \n\n"); +} + +int ProcessArgs(int argc, char *argv[]) +{ + int i = 1, result = 0; + nsresult res; + + while (i < argc) + { + if (argv[i][0] == '-') + { + int j; + for (j = 1; argv[i][j] != '\0'; j++) + { + switch (argv[i][j]) + { + case 'h': + printHelp(); + return 0; // we are all done! + + case 'u': + gUnreg = PR_TRUE; + break; + + case 'q': + gQuiet = PR_TRUE; + break; + + case 'a': + { + res = Register(nsnull); + if (NS_FAILED(res)) + { + ReportError(res, "component directory"); + result = -1; + } + else + { + ReportSuccess("component directory"); + } + } + break; + + case 'x': + gXPCOMLocation = argv[++i]; + j = strlen(gXPCOMLocation) - 1; + break; + + case 'c': + gCompRegLocation = argv[++i]; + j = strlen(gCompRegLocation) - 1; + break; + + case 'd': + gXPTIDatLocation = argv[++i]; + j = strlen(gXPTIDatLocation) - 1; + break; + + default: + printf("Unknown option '%c'\n", argv[i][j]); + } + } + } + else + { + res = Register(argv[i]); + + if (NS_FAILED(res)) + { + ReportError(res, argv[i]); + result = -1; + } + else + { + ReportSuccess(argv[i]); + } + } + i++; + } + return result; +} + + +int main(int argc, char *argv[]) +{ + int ret; + nsresult rv; + + /* With no arguments, regxpcom will autoregister */ + if (argc <= 1) + { + startup_xpcom(); + nsCOMPtr registrar; + rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); + if (NS_FAILED(rv)) { + printf("Can not aquire component registrar\n"); + return -1; + } + rv = registrar->AutoRegister(nsnull); + ret = (NS_FAILED(rv)) ? -1 : 0; + registrar = 0; + shutdown_xpcom(); + } else + ret = ProcessArgs(argc, argv); + + return ret; +} diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore b/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in b/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in new file mode 100644 index 00000000..f6ba7e69 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/Makefile.in @@ -0,0 +1,52 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +SIMPLE_PROGRAMS = rebasedlls$(BIN_SUFFIX) + +CPPSRCS = rebasedlls.cpp + +OS_LIBS += $(call EXPAND_LIBNAME,imagehlp) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp b/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp new file mode 100644 index 00000000..321160e7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/tools/windows/rebasedlls.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; 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 Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 +#include +#include +#include + +static char* gSymbolPath = NULL; +static DWORD gBaseAddr = (DWORD) 0x60000000; +static time_t now; + +static void +ReBase(char* aDLLName) +{ + DWORD oldsize, oldbase, newsize; + DWORD newbase = gBaseAddr; + BOOL b = ReBaseImage(aDLLName, gSymbolPath, TRUE, FALSE, FALSE, + 0, &oldsize, &oldbase, &newsize, &newbase, + now); + DWORD lastError = ::GetLastError(); + printf("%-20s %08x %08x %08x %08x", + aDLLName, oldbase, oldsize, newbase, newsize); + if (!b) { + printf(" (failed: error=%d/0x%x)", lastError, lastError); + } + fputs("\n", stdout); + + // advance base; round size up to nearest 64k + newsize = ((newsize + 65535) >> 16) << 16; + gBaseAddr = newbase + newsize; +} + +static void +Usage() +{ + printf("Usage: ReBase [-libs library-path] dlls...\n"); +} + +int +main(int argc, char** argv) +{ + now = time(0); + int i; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-libs") == 0) { + if (i == argc - 1) { + Usage(); + return -1; + } + gSymbolPath = argv[++i]; + } + else { + Usage(); + return -1; + } + } + else + break; + } + + if (i < argc) { + printf("Library OldBase OldSize NewBase NewSize\n"); + printf("------- ------- ------- ------- -------\n"); + } + for (; i < argc; i++) { + ReBase(argv[i]); + } + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/Makefile.in new file mode 100644 index 00000000..43d92023 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/Makefile.in @@ -0,0 +1,49 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +DIRS = xpt xpidl + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore new file mode 100644 index 00000000..8e5eac0d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/.cvsignore @@ -0,0 +1,2 @@ +xpidl +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in new file mode 100644 index 00000000..ae228ef0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/Makefile.in @@ -0,0 +1,88 @@ +# +# The contents of this file are subject to the Netscape 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/NPL/ +# +# 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 mozilla.org code. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +PROGRAM = xpidl$(BIN_SUFFIX) +INTERNAL_TOOLS = 1 + +# glib and libIDL link against the non-debug msvcrt +MOZ_NO_DEBUG_RTL=1 + +CSRCS = \ + xpidl.c \ + xpidl_idl.c \ + xpidl_util.c \ + xpidl_header.c \ + xpidl_typelib.c \ + xpidl_doc.c \ + xpidl_java.c \ + $(NULL) + +SDK_BINARY = \ + $(PROGRAM) \ + $(NULL) + +ifdef CROSS_COMPILE +HOST_PROGRAM = host_xpidl$(HOST_BIN_SUFFIX) +HOST_CSRCS = $(CSRCS) +endif + +include $(topsrcdir)/config/rules.mk + +CFLAGS += $(LIBIDL_CFLAGS) + +# Compile directly against the static lib, so we can use xpidl during the build +# without the shared library path being set. +ifeq (WINNT,$(OS_ARCH)) +DEFINES += -DEXPORT_XPT_API +ifndef GNU_CC +LDFLAGS += -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRTD +endif +endif + +# Tell the $(PROGRAM) target that we need to be recompiled when libxpt changes. +LIBS = $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) $(LIBIDL_LIBS) +EXTRA_DEPS = $(wildcard $(DIST)/lib/$(LIB_PREFIX)xpt.*) + +ifdef CROSS_COMPILE +HOST_CFLAGS += $(HOST_LIBIDL_CFLAGS) +HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) $(HOST_LIBIDL_LIBS) +HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*) + +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + +ifdef MACOS_SDK_DIR +NEXT_ROOT= +OS_LIBS := $(patsubst -L$(MACOS_SDK_DIR)/usr/lib%,,$(OS_LIBS)) +endif + +export:: + @$(MAKE) libs diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/README b/src/libs/xpcom18a4/xpcom/typelib/xpidl/README new file mode 100644 index 00000000..b7a400e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/README @@ -0,0 +1,16 @@ +Wed Dec 2 14:35:41 EST 1998 + +xpidl depends on Andrew Veliath and Elliot Lee's libIDL, a part of the +GNOME ORBit C ORB. We currently require libIDL >= 0.6.3, which in turn +requires glib >= 1.2.0. + +libIDL builds for Linux and Win32 can be found, along with source +tarballs, at http://www.rpi.edu/~veliaa/libIDL/, and Win32 users will +need glib 1.2 and glib 1.2-dev from +http://user.sgic.fi/~tml/gimp/win32/. Source and Linux RPMs are also +available from ftp://ftp.mozilla.org/pub/mozilla/libraries, and Win32 +binaries are included in the wintools.zip file at +ftp://ftp.mozilla.org/pub/mozilla/source/wintools.zip. A Mac project +is in progress, and should be appearing shortly. + +glib tarballs and RPMs for Linux can be found through http://www.gtk.org. diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc new file mode 100644 index 00000000..fb06f6a3 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/compiler.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc new file mode 100644 index 00000000..bec7c043 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/linker.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c new file mode 100644 index 00000000..ecda11e0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.c @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mac_console.h" + +#ifndef __CONSOLE__ +#include +#endif + +extern CWPluginContext gPluginContext; + +UInt32 mac_console_count = 0; +CWMemHandle mac_console_handle = NULL; + +/* + * The following four functions provide the UI for the console package. + * Users wishing to replace SIOUX with their own console package need + * only provide the four functions below in a library. + */ + +/* + * extern short InstallConsole(short fd); + * + * Installs the Console package, this function will be called right + * before any read or write to one of the standard streams. + * + * short fd: The stream which we are reading/writing to/from. + * returns short: 0 no error occurred, anything else error. + */ + +short InstallConsole(short fd) +{ +#pragma unused (fd) + mac_console_count = 0; + CWAllocMemHandle(gPluginContext, 8192, false, &mac_console_handle); + return 0; +} + +/* + * extern void RemoveConsole(void); + * + * Removes the console package. It is called after all other streams + * are closed and exit functions (installed by either atexit or _atexit) + * have been called. Since there is no way to recover from an error, + * this function doesn't need to return any. + */ + +void RemoveConsole(void) +{ + if (mac_console_handle != NULL) { + CWFreeMemHandle(gPluginContext, mac_console_handle); + mac_console_handle = NULL; + } +} + +/* + * extern long WriteCharsToConsole(char *buffer, long n); + * + * Writes a stream of output to the Console window. This function is + * called by write. + * + * char *buffer: Pointer to the buffer to be written. + * long n: The length of the buffer to be written. + * returns short: Actual number of characters written to the stream, + * -1 if an error occurred. + */ + +long WriteCharsToConsole(char *buffer, long n) +{ + long size = 0; + void* ptr = NULL; + + if (CWGetMemHandleSize(gPluginContext, mac_console_handle, &size) == noErr) { + if (mac_console_count + n >= size) { + size += 8192; + if (CWResizeMemHandle(gPluginContext, mac_console_handle, size) != noErr) + return -1; + } + } + + if (CWLockMemHandle(gPluginContext, mac_console_handle, false, &ptr) == noErr) { + BlockMoveData(buffer, (char *)ptr + mac_console_count, n); + mac_console_count += n; + CWUnlockMemHandle(gPluginContext, mac_console_handle); + } + + return 0; +} + +/* + * extern long ReadCharsFromConsole(char *buffer, long n); + * + * Reads from the Console into a buffer. This function is called by + * read. + * + * char *buffer: Pointer to the buffer which will recieve the input. + * long n: The maximum amount of characters to be read (size of + * buffer). + * returns short: Actual number of characters read from the stream, + * -1 if an error occurred. + */ + +long ReadCharsFromConsole(char *buffer, long n) +{ + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h new file mode 100644 index 00000000..88809f85 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_console.h @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_console.h + */ + +#pragma once + +#include +#include + +#include "CWPlugins.h" + +extern UInt32 mac_console_count; +extern CWMemHandle mac_console_handle; diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp new file mode 100644 index 00000000..41d03d88 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_memory.cpp @@ -0,0 +1,146 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_memory.cpp + */ + +#include +#include + +#include +#include + +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +extern CWPluginContext gPluginContext; + +/** + * Note: memory allocated by these operators will automatically be freed after the + * current call into xpidl_compiler completes. This should be fine in most cases, + * as we are also having the compiler be reloaded for every request to reinitialize + * global data. Just be careful out there! + */ + +const Boolean kTemporaryAllocation = false; + +void* operator new(size_t size) +{ + void* ptr = NULL; + if (CWAllocateMemory(gPluginContext, size, kTemporaryAllocation, &ptr) == cwNoErr) + return ptr; + return NULL; +} + +void operator delete(void* ptr) +{ + if (ptr != NULL) + CWFreeMemory(gPluginContext, ptr, kTemporaryAllocation); +} + +void* operator new[] (size_t size) +{ + void* ptr = NULL; + if (CWAllocateMemory(gPluginContext, size, kTemporaryAllocation, &ptr) == cwNoErr) + return ptr; + return NULL; +} + +void operator delete[](void* ptr) +{ + if (ptr != NULL) + CWFreeMemory(gPluginContext, ptr, kTemporaryAllocation); +} + +namespace std { + +#define TRACK_ALLOCATION +#define kTrackedCookie 'TRKD' + +void* malloc(size_t size) +{ +#if defined(TRACK_ALLOCATION) + OSType* ptr = (OSType*) new char[sizeof(OSType) + size]; + if (ptr != NULL) + *ptr++ = kTrackedCookie; + return ptr; +#else + return new char[size]; +#endif +} + +void free(void *ptr) +{ +#if defined(TRACK_ALLOCATION) + OSType* type = (OSType*)ptr; + if (*--type == kTrackedCookie) + delete[] (char*) type; + else + DebugStr("\pillegal block passed to free."); +#else + delete[] (char*) ptr; +#endif +} + +void* calloc(size_t nmemb, size_t size) +{ + size *= nmemb; + void* ptr = malloc(size); + if (ptr != NULL) { + BlockZero(ptr, size); + } + return ptr; +} + +void* realloc(void * ptr, size_t size) +{ + void* newptr = NULL; + + if (size > 0) + newptr = malloc(size); + + if (ptr != NULL && newptr != NULL) + BlockMoveData(ptr, newptr, size); + + if (ptr != NULL) + free(ptr); + + return newptr; +} + +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp new file mode 100644 index 00000000..881dcb0b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_stdlib.cpp @@ -0,0 +1,58 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_stdlib.cpp + + replacement functions for the CodeWarrior plugin. + + by Patrick C. Beard. + */ + +#include +#include +#include + +// simply throw us out of here! + +jmp_buf exit_jump; +int exit_status = 0; + +void std::exit(int status) +{ + exit_status = status; + longjmp(exit_jump, -1); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp new file mode 100644 index 00000000..37e389e5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.cpp @@ -0,0 +1,38 @@ +/* + mac_strings.cpp + */ + +#include "mac_strings.h" + +#include +#include +#include + +StringPtr c2p_strcpy(StringPtr pstr, const char* cstr) +{ + size_t len = ::strlen(cstr); + if (len > 255) len = 255; + BlockMoveData(cstr, pstr + 1, len); + pstr[0] = len; + return pstr; +} + +char* p2c_strcpy(char* cstr, const StringPtr pstr) +{ + size_t len = pstr[0]; + BlockMoveData(pstr + 1, cstr, len); + cstr[len] = '\0'; + return cstr; +} + +char* p2c_strdup(StringPtr pstr) +{ + size_t len = pstr[0]; + char* cstr = new char[1 + len]; + if (cstr != NULL) { + BlockMoveData(pstr + 1, cstr, len); + cstr[len] = '\0'; + } + return cstr; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h new file mode 100644 index 00000000..44f39312 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_strings.h @@ -0,0 +1,47 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_strings.h + */ + +#pragma once + +#include + +StringPtr c2p_strcpy(StringPtr pstr, const char* cstr); +char* p2c_strcpy(char* cstr, const StringPtr pstr); +char* p2c_strdup(StringPtr pstr); diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp new file mode 100644 index 00000000..49f061d9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.cpp @@ -0,0 +1,417 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl.cpp + + Metrowerks Codewarrior IDL plugin. + + by Patrick C. Beard. + */ + +/* standard headers */ +#include +#include +#include +#include +#include +#include + +/* system headers */ +#include +#include +#include + +#include "FullPath.h" +#include "MoreFilesExtras.h" + +/* compiler headers */ +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +/* local headers. */ +#include "mac_xpidl.h" +#include "mac_console.h" +#include "mac_strings.h" +#include "mac_xpidl_panel.h" + +/* prototypes of local functions */ +static CWResult Compile(CWPluginContext context); +static CWResult Disassemble(CWPluginContext context); +static CWResult LocateFile(CWPluginContext context, const char* filename, FSSpec& file); + +/* external variables */ +extern jmp_buf exit_jump; +extern int exit_status; + +/* global variables */ +CWPluginContext gPluginContext; + +/* local variables */ +static CWFileSpec gSourceFile; +static char* gSourcePath = NULL; +static CWFileSpec gOutputFile; + +extern "C" { +pascal short xpidl_compiler(CWPluginContext context); +int xpidl_main(int argc, char* argv[]); +int xptdump_main(int argc, char* argv[]); + +FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode); +} + +pascal short xpidl_compiler(CWPluginContext context) +{ + long request; + if (CWGetPluginRequest(context, &request) != cwNoErr) + return cwErrRequestFailed; + + gPluginContext = context; + short result = cwNoErr; + + /* dispatch on compiler request */ + switch (request) { + case reqInitCompiler: + /* compiler has just been loaded into memory */ + break; + + case reqTermCompiler: + /* compiler is about to be unloaded from memory */ + break; + + case reqCompile: + /* compile a source file */ + result = Compile(context); + break; + + case reqCompDisassemble: + /* disassemble a source file */ + result = Disassemble(context); + break; + + default: + result = cwErrRequestFailed; + break; + } + + /* is this necessary? */ + CWDonePluginRequest(context, result); + + /* return result code */ + return (result); +} + +static char* full_path_to(const FSSpec& file) +{ + short len = 0; + Handle fullPath = NULL; + if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) { + char* path = new char[1 + len]; + if (path != NULL) { + BlockMoveData(*fullPath, path, len); + path[len] = '\0'; + } + DisposeHandle(fullPath); + return path; + } + return NULL; +} + +static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings) +{ + CWMemHandle settingsHand; + CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand); + if (!CWSUCCESS(err)) + return (err); + + XPIDLSettings* settingsPtr = NULL; + err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr); + if (!CWSUCCESS(err)) + return (err); + + settings = *settingsPtr; + + err = CWUnlockMemHandle(context, settingsHand); + if (!CWSUCCESS(err)) + return (err); + + return noErr; +} + +static CWResult Compile(CWPluginContext context) +{ + CWResult err = CWGetMainFileSpec(context, &gSourceFile); + if (!CWSUCCESS(err)) + return (err); + + long fileNum; + err = CWGetMainFileNumber(context, &fileNum); + if (!CWSUCCESS(err)) + return (err); + + // get the name of the source file to compile. + gSourcePath = p2c_strdup(gSourceFile.name); + if (gSourcePath == NULL) + return cwErrOutOfMemory; + + // build an argument list and call the compiler. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeHeader, false, false }; + GetSettings(context, settings); + +#if 0 + // if generating .xpt files, let the IDE tell us where to put the output file. + // otherwise, put them in the project's output directory. + if (settings.mode == kXPIDLModeTypelib) + err = CWGetSuggestedObjectFileSpec(context, fileNum, &gOutputFile); + else + err = CWGetOutputFileDirectory(gPluginContext, &gOutputFile); +#else + // always generate the output file into the project target's data directory. + err = CWGetSuggestedObjectFileSpec(context, fileNum, &gOutputFile); +#endif + if (!CWSUCCESS(err)) + return (err); + + int argc = 3; + char* modes[] = { "header", "java", "typelib", "doc" }; + char* argv[] = { "xpidl", "-m", modes[settings.mode - 1], NULL, NULL, NULL, NULL, }; + if (settings.warnings) argv[argc++] = "-w"; + if (settings.verbose) argv[argc++] = "-v"; + argv[argc++] = gSourcePath; + + if (setjmp(exit_jump) == 0) { + if (xpidl_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + // if the compilation succeeded, tell CodeWarrior about the output file. + // this ensures several things: 1. if the output file is deleted by the user, + // then the IDE will know to recompile it, which is good for dirty builds, + // where the output files may be hand deleted; 2. if the user elects to remove + // objects, the output files are deleted. Thanks to robv@metrowerks.com for + // pointing this new CWPro4 API out. + if (err == cwNoErr) { + CWObjectData objectData; + BlockZero(&objectData, sizeof(objectData)); + + // for fun, show how large the output file is in the data area. + long dataSize, rsrcSize; + if (FSpGetFileSize(&gOutputFile, &dataSize, &rsrcSize) == noErr) + objectData.idatasize = dataSize; + + // tell the IDE that this file was generated by the compiler. + objectData.objectfile = &gOutputFile; + + err = CWStoreObjectData(context, fileNum, &objectData); + } else { + // an error occured, delete the output file, which might be a partial file. + if (gOutputFile.name[0] != 0) { + ::FSpDelete(&gOutputFile); + } + } + + delete[] gSourcePath; + gSourcePath = NULL; + + return (err); +} + +static CWResult Disassemble(CWPluginContext context) +{ + // the disassembly code has moved to the linker. + return noErr; +} + +static CWResult LocateFile(CWPluginContext context, const char* filename, FSSpec& file) +{ + /* prefill the CWFileInfo struct */ + CWFileInfo fileinfo; + BlockZero(&fileinfo, sizeof(fileinfo)); + // memset(&fileinfo, 0, sizeof(fileinfo)); + fileinfo.fullsearch = true; + fileinfo.suppressload = true; + fileinfo.dependencyType = cwNormalDependency; + fileinfo.isdependentoffile = kCurrentCompiledFile; + + /* locate the file name using the project's access paths */ + CWResult err = CWFindAndLoadFile(context, filename, &fileinfo); + if (err == cwNoErr) { + file = fileinfo.filespec; + } else if (err == cwErrFileNotFound) { + char errmsg[200]; + sprintf(errmsg, "Can't locate file \"%s\".", filename); + CWResult callbackResult = CWReportMessage(context, 0, errmsg, 0, messagetypeError, 0); + } + + return (err); +} + +/** + * Substitute for standard fopen, treats certain filenames specially, + * and also considers the mode argument. If a file is being opened + * for reading, the file is assumed to be locateable using CodeWarrior's + * standard access paths. If it's for writing, the file is opened in + * the current project's output directory. + */ +FILE* std::fopen(const char* filename, const char *mode) +{ + FSSpec filespec; + CWResult err = noErr; + do { + if (filename == gSourcePath || strcmp(filename, gSourcePath) == 0) { + // opening the main source file. + filespec = gSourceFile; + } else if (mode[0] == 'w') { + // if an output file, open it in the current compilation's output directory. + c2p_strcpy(filespec.name, filename); + filespec.vRefNum = gOutputFile.vRefNum; + filespec.parID = gOutputFile.parID; + c2p_strcpy(gOutputFile.name, filename); + } else { + // an input file, use CodeWarrior's search paths to find the named source file. + err = LocateFile(gPluginContext, filename, filespec); + } + } while (0); + // if all went well, we have a file to open. + return (err == noErr ? FSp_fopen(&filespec, mode) : NULL); +} + +/** + * Returns the length of a file, assuming it is always located in the + * project's output directory. + */ +size_t mac_get_file_length(const char* filename) +{ + long dataSize= 0, rsrcSize = 0; + FSSpec filespec; + if (CWGetOutputFileDirectory(gPluginContext, &filespec) != noErr) + return 0; + c2p_strcpy(filespec.name, filename); + if (FSpGetFileSize(&filespec, &dataSize, &rsrcSize) != noErr) + return 0; + return dataSize; +} + +void mac_warning(const char* warning_message) +{ + CWReportMessage(gPluginContext, 0, warning_message, 0, messagetypeWarning, 0); +} + +void mac_error(const char* error_message) +{ + CWReportMessage(gPluginContext, 0, error_message, 0, messagetypeError, 0); +} + +// plugin compiler exports. + +#if CW_USE_PRAGMA_EXPORT +#pragma export on +#endif + +CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize) +{ + static const DropInFlags sFlags = { + kCurrentDropInFlagsVersion, + CWDROPINCOMPILERTYPE, + DROPINCOMPILERLINKERAPIVERSION, + (kGeneratescode | /* kCandisassemble | */ kCompMultiTargAware | kCompAlwaysReload), + Lang_MISC, + DROPINCOMPILERLINKERAPIVERSION + }; + + *flags = &sFlags; + *flagsSize = sizeof(sFlags); + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName) +{ + static const char* sDropInName = "xpidl"; + + *dropinName = sDropInName; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName) +{ + static const char* sDisplayName = "xpidl"; + + *displayName = sDisplayName; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList) +{ + static const char* sPanelName = kXPIDLPanelName; + static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName }; + + *panelList = &sPanelList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList) +{ + static CWDataType sCPU = '****'; + static CWDataType sOS = '****'; + static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS }; + + *targetList = &sTargetList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList) +{ + static CWExtensionMapping sExtension = { 'TEXT', ".idl", 0 }; + static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension }; + + *defaultMappingList = &sExtensionMapList; + + return cwNoErr; +} + +#if CW_USE_PRAGMA_EXPORT +#pragma export off +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h new file mode 100644 index 00000000..bb1c5048 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl.h @@ -0,0 +1,25 @@ +/* + mac_xpidl.h + + prototypes for the Mac CodeWarrior plugin version of xpidl. + + by Patrick C. Beard. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDIO_H +#include +#endif + +size_t mac_get_file_length(const char* filename); +void mac_warning(const char* warning_message); +void mac_error(const char* error_message); + +#ifdef __cplusplus +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp new file mode 100644 index 00000000..b046071d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.cpp @@ -0,0 +1,695 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl_panel.cpp + */ + +#define CW_STRICT_DIALOGS 1 + +/* standard headers */ +#include +#include +#include + +/* system headers */ +#include +#include +#include +#include +#include +#include +#include + +/* compiler headers */ +#include + +/* project headers */ +#include "mac_xpidl_panel.h" + +enum { + kFactoryPrefsID = 128, + kCW7ItemListID = 128, + kCW8ItemListID = 129, + + kXPIDLModeItem = 1, + kXPIDLWarningsItem, + kXPIDLVerboseItem, + + kXPTLinkerOutputItem = 4 +}; + + +/* local variables */ +static RgnHandle sDragRgn; +static Boolean sHighlightOn; + + +/* prototypes of local functions */ +static short InitDialog(PanelParameterBlock *pb); +static void TermDialog(PanelParameterBlock *pb); +static void PutData(PanelParameterBlock *pb, Handle options); +static short GetData(PanelParameterBlock *pb, Handle options, Boolean noisy); +static void ByteSwapData(XPIDLSettingsHandle options); +static short Filter(PanelParameterBlock *pb, EventRecord *event, short *itemHit); +static void ItemHit(PanelParameterBlock *pb); +static void Validate(Handle original, Handle current, Boolean *recompile, Boolean *relink, Boolean *reset); +static short GetPref(AEKeyword keyword, AEDesc *prefsDesc, Handle settings); +static short SetPref(AEKeyword keyword, const AEDesc *prefsDesc, Handle settings); +static short GetFactory(Handle settings); +static short UpdatePref(Handle settings); +static Boolean ComparePrefs(Handle prefsHand1, Handle prefsHand2); +static Boolean ComparePrefs(XPIDLSettings& prefs1, XPIDLSettings& prefs2); +static void OutlineRect(const Rect* focusRect, Boolean outlineOn); +static OSErr DragEnter(PanelParameterBlock *pb); +static void DragWithin(PanelParameterBlock *pb); +static void DragExit(PanelParameterBlock *pb); +static void DragDrop(PanelParameterBlock *pb); + +extern "C" { + +pascal short xpidl_panel(PanelParameterBlock *pb); + +} + +/* + * main - entry-point for Drop-In Preferences Panel + * + */ + +pascal short xpidl_panel(PanelParameterBlock *pb) +{ + short result; + + result = noErr; + + switch (pb->request) + { + case reqInitPanel: + /* panel has just been loaded into memory */ + break; + + case reqTermPanel: + /* panel is about to be unloaded from memory */ + break; + + case reqFirstLoad: + /* first time panel was loaded. */ + break; + + case reqInitDialog: + /* hook our dialog item list into the preferences dialog */ + result = InitDialog(pb); + break; + + case reqTermDialog: + /* unhook our dialog item list from the preferences dialog */ + TermDialog(pb); + break; + + case reqPutData: + /* put the data in the given handle into our dialog items */ + PutData(pb, pb->currentPrefs); + break; + + case reqGetData: + /* fill in the given handle with our dialog items */ + result = GetData(pb, pb->currentPrefs, true); + break; + + case reqByteSwapData: + /* byte swap the data in the handle */ + ByteSwapData((XPIDLSettingsHandle)pb->currentPrefs); + break; + + case reqFilter: + /* filter an event in the dialog */ + result = Filter(pb, pb->event, &pb->itemHit); + break; + + case reqItemHit: + /* handle a hit on one of our dialog items */ + ItemHit(pb); + break; + + case reqDrawCustomItem: + /* handle a request to draw one of our user items (CW/8 and later) */ + break; + + case reqActivateItem: + break; + + case reqDeactivateItem: + break; + + case reqHandleKey: + break; + + case reqHandleClick: + break; + + case reqFindStatus: + break; + + case reqObeyCommand: + break; + + case reqAEGetPref: + /* return one item in the given handle as an Apple Event descriptor */ + result = GetPref(pb->prefsKeyword, &pb->prefsDesc, pb->currentPrefs); + break; + + case reqAESetPref: + /* change one item in the given handle according to the given Apple Event descriptor */ + result = SetPref(pb->prefsKeyword, &pb->prefsDesc, pb->currentPrefs); + break; + + case reqValidate: + /* determine if we need to reset paths, recompile, or relink */ + Validate(pb->originalPrefs, pb->currentPrefs, &pb->recompile, &pb->relink, &pb->reset); + break; + + case reqGetFactory: + /* return our factory settings */ + result = GetFactory(pb->factoryPrefs); + break; + + case reqUpdatePref: + /* update the given handle to use the current format for our prefs data */ + result = UpdatePref(pb->currentPrefs); + break; + + case reqDragEnter: + /* determine if we can accept the drag and, if so, start tracking */ + result = DragEnter(pb); + break; + + case reqDragWithin: + /* continue tracking */ + DragWithin(pb); + break; + + case reqDragExit: + /* stop tracking */ + DragExit(pb); + break; + + case reqDragDrop: + /* the user has dropped in our panel */ + DragDrop(pb); + break; + + default: + result = paramErr; + break; + } + + return (result); +} + +/* + * InitDialog - initialize Dialog Box items for this panel + * + */ + +static short InitDialog(PanelParameterBlock *pb) +{ + OSErr err; + + // The library function will call the IDE to append the dialog items + // if possible; else it will call AppendDITL itself. This way, you + // don't have to worry about it. + + err = CWPanlAppendItems(pb, kCW8ItemListID); + if (err != noErr) + return (err); + + sDragRgn = NewRgn(); + + return (err); +} + +/* + * TermDialog - destroy Dialog Box items for this panel + * + */ + +static void TermDialog(PanelParameterBlock *pb) +{ + DisposeRgn(sDragRgn); +} + +inline Boolean hasLinkerOutput(short mode) +{ + return (mode == kXPIDLModeHeader || mode == kXPIDLModeTypelib); +} + +/* + * PutData - copy the options data from the handle to the screen + * + */ + +static void PutData(PanelParameterBlock *pb, Handle options) +{ + // make sure the options are the right size. + UpdatePref(options); + + XPIDLSettings prefsData = **(XPIDLSettingsHandle) options; + + CWPanlSetItemValue(pb, kXPIDLModeItem, prefsData.mode); + CWPanlSetItemValue(pb, kXPIDLWarningsItem, prefsData.warnings); + CWPanlSetItemValue(pb, kXPIDLVerboseItem, prefsData.verbose); + + CWPanlEnableItem(pb, kXPTLinkerOutputItem, hasLinkerOutput(prefsData.mode)); + CWPanlSetItemText(pb, kXPTLinkerOutputItem, prefsData.output); +} + +/* + * GetData - copy the options data from screen to the handle + * + */ + +static short GetData(PanelParameterBlock *pb, Handle options, Boolean noisy) +{ + XPIDLSettings prefsData = **(XPIDLSettingsHandle) options; + long mode, warnings, verbose; + + CWPanlGetItemValue(pb, kXPIDLModeItem, &mode); + CWPanlGetItemValue(pb, kXPIDLWarningsItem, &warnings); + CWPanlGetItemValue(pb, kXPIDLVerboseItem, &verbose); + + prefsData.mode = (short) mode; + prefsData.warnings = (Boolean) warnings; + prefsData.verbose = (Boolean) verbose; + + CWPanlGetItemText(pb, kXPTLinkerOutputItem, prefsData.output, sizeof(Str32)); + + ** (XPIDLSettingsHandle) options = prefsData; + + return (noErr); +} + +static void ByteSwapShort(short* x) +{ + union { + short s; + char c[2]; + } from,to; + + from.s=*x; + to.c[0]=from.c[1]; + to.c[1]=from.c[0]; + *x = to.s; +} + +/* + * ByteSwapData - byte-swap the options data + * + */ + +static void ByteSwapData(XPIDLSettingsHandle options) +{ + ByteSwapShort(&(**options).version); + ByteSwapShort(&(**options).mode); +} + +/* + * Filter - filter an event for the Preferences panel + * + */ +static short Filter(PanelParameterBlock *pb, EventRecord *event, short *itemHit) +{ +#pragma unused(pb, event, itemHit) + + return (noErr); +} + +/* + * ItemHit - handle an itemHit in a Preferences panel + * + */ + +static void ItemHit(PanelParameterBlock *pb) +{ + short theItem = pb->itemHit - pb->baseItems; + long oldValue; + + switch (theItem) { + case kXPIDLModeItem: + CWPanlGetItemValue(pb, theItem, &oldValue); + CWPanlEnableItem(pb, kXPTLinkerOutputItem, hasLinkerOutput(oldValue)); + break; + + case kXPIDLWarningsItem: + case kXPIDLVerboseItem: + CWPanlGetItemValue(pb, theItem, &oldValue); + break; + } + + GetData(pb, pb->currentPrefs, false); + + pb->canRevert = !ComparePrefs(pb->originalPrefs, pb->currentPrefs); + pb->canFactory = !ComparePrefs(pb->factoryPrefs, pb->currentPrefs); +} + +/* + * Validate - check if panel's changes require a recompile or relink + * + */ + +static void Validate(Handle original, Handle current, Boolean *recompile, Boolean *relink, Boolean *reset) +{ +#pragma unused(original, current) + XPIDLSettings& origSettings = **(XPIDLSettingsHandle) original; + XPIDLSettings& currentSettings = **(XPIDLSettingsHandle) current; + + *recompile = currentSettings.mode != origSettings.mode; + *relink = *recompile && hasLinkerOutput(currentSettings.mode); + *reset = false; +} + +/* + * GetPref - get a specified Preference setting for an AppleEvent request + * + */ +static short GetPref(AEKeyword keyword, AEDesc *prefsDesc, Handle settings) +{ +#if 0 + XPIDLSettings prefsData = ** (XPIDLSettingsHandle) settings; + DescType anEnum; + OSErr err; + + switch (keyword) { + case prefsLN_GenerateSymFile: + err = AECreateDesc(typeBoolean, &prefsData.linksym, sizeof(Boolean), prefsDesc); + break; + + case prefsPR_ProjectType: + switch (prefsData.projtype) + { + case kProjTypeApplication: anEnum = enum_Project_Application; break; + case kProjTypeLibrary: anEnum = enum_Project_Library; break; + case kProjTypeSharedLib: anEnum = enum_Project_SharedLibrary; break; + case kProjTypeCodeResource: anEnum = enum_Project_CodeResource; break; + case kProjTypeMPWTool: anEnum = enum_Project_MPWTool; break; + default: return (paramErr); + } + err = AECreateDesc(typeEnumeration, &anEnum, sizeof(anEnum), prefsDesc); + break; + + case prefsPR_FileName: + err = AECreateDesc(typeChar, prefsData.outfile+1, StrLength(prefsData.outfile), prefsDesc); + break; + + default: + err = errAECantHandleClass; + break; + } + + return (err); +#else + return (errAECantHandleClass); +#endif +} + +/* + * SetPref - set a specified Preference setting from an AppleEvent request + * + */ + +static short SetPref(AEKeyword keyword, const AEDesc *prefsDesc, Handle settings) +{ +#if 0 + XPIDLSettings prefsData = ** (XPIDLSettingsHandle) settings; + AEDesc toDesc = { typeNull, NULL }; + OSErr err = noErr; + Handle dataHand; + Size textLength; + DescType anEnum; + + switch (keyword) + { + case prefsLN_GenerateSymFile: + if (prefsDesc->descriptorType == typeBoolean) + { + dataHand = prefsDesc->dataHandle; + } + else + { + err = AECoerceDesc(prefsDesc, typeBoolean, &toDesc); + if (err == noErr) + dataHand = toDesc.dataHandle; + } + if (err == noErr) + { + prefsData.linksym = ** (Boolean **) dataHand; + } + break; + + case prefsPR_ProjectType: + if (prefsDesc->descriptorType != typeEnumeration) + { + err = errAETypeError; + break; + } + + anEnum = ** (DescType **) prefsDesc->dataHandle; + + switch (anEnum) + { + case enum_Project_Application: prefsData.projtype = kProjTypeApplication; break; + case enum_Project_Library: prefsData.projtype = kProjTypeLibrary; break; + case enum_Project_SharedLibrary: prefsData.projtype = kProjTypeSharedLib; break; + case enum_Project_CodeResource: prefsData.projtype = kProjTypeCodeResource; break; + case enum_Project_MPWTool: prefsData.projtype = kProjTypeMPWTool; break; + default: return (errAECoercionFail); + } + break; + + case prefsPR_FileName: + if (prefsDesc->descriptorType == typeChar) + { + dataHand = prefsDesc->dataHandle; + } + else + { + err = AECoerceDesc(prefsDesc, typeChar, &toDesc); + if (err == noErr) + dataHand = toDesc.dataHandle; + } + if (err == noErr) + { + textLength = GetHandleSize(dataHand); + if (textLength > sizeof(prefsData.outfile) - 1) + textLength = sizeof(prefsData.outfile) - 1; + BlockMoveData(*dataHand, prefsData.outfile+1, textLength); + prefsData.outfile[0] = textLength; + } + break; + + default: + err = errAECantHandleClass; + break; + } + + if (err == noErr) + { + ** (XPIDLSettingsHandle) settings = prefsData; + } + + AEDisposeDesc(&toDesc); + + return (err); +#else + return (errAECantHandleClass); +#endif +} + +/* + * GetFactory - retrieve factory settings + * + */ + +static short GetFactory(Handle settings) +{ + Handle factory; + Size size; + OSErr err; + + factory = Get1Resource('pref', kFactoryPrefsID); + if (factory == NULL) { + err = ResError(); + if (err == noErr) + err = resNotFound; + return (err); + } + + size = GetHandleSize(factory); + SetHandleSize(settings, size); + err = MemError(); + + if (err == noErr) { + BlockMoveData(*factory, *settings, size); + } + + return (err); +} + +/* + * UpdatePref - "upgrade" a pref to the current version + */ +static short UpdatePref(Handle settings) +{ + if (GetHandleSize(settings) != sizeof(XPIDLSettings)) + GetFactory(settings); + + return (noErr); +} + +/* + * ComparePrefs + * + */ +static Boolean ComparePrefs(Handle prefsHand1, Handle prefsHand2) +{ + XPIDLSettings& prefs1 = **(XPIDLSettingsHandle) prefsHand1; + XPIDLSettings& prefs2 = **(XPIDLSettingsHandle) prefsHand2; + + return ((prefs1.mode == prefs2.mode) && + (prefs1.warnings == prefs2.warnings) && + (prefs1.verbose == prefs2.verbose) && + (EqualString(prefs1.output, prefs2.output, true, true))); +} + +static Boolean ComparePrefs(XPIDLSettings& prefs1, XPIDLSettings& prefs2) +{ + return ((prefs1.mode == prefs2.mode) && + (prefs1.warnings == prefs2.warnings) && + (prefs1.verbose == prefs2.verbose) && + (EqualString(prefs1.output, prefs2.output, true, true))); +} + +/* + * OutlineRect + * + */ +static void OutlineRect(const Rect* focusRect, Boolean outlineOn) +{ + ColorSpec savedForeColor, backColor; + PenState savedPen; + + GetPenState(&savedPen); + PenNormal(); + + if (!outlineOn) + { + SaveFore(&savedForeColor); + SaveBack(&backColor); + RestoreFore(&backColor); + } + + PenSize(2, 2); + FrameRect(focusRect); + + SetPenState(&savedPen); + + if (!outlineOn) + { + RestoreFore(&savedForeColor); + } +} + +/* + * DragEnter + * + */ +static OSErr DragEnter(PanelParameterBlock *pb) +{ +#if 0 + short theItem = pb->itemHit - pb->baseItems; + unsigned short itemCount; + Rect itemRect; + OSErr err; +#endif + + /* Return paramErr if the user is on a item that can't be dropped on */ + return (paramErr); +} + +/* + * DragWithin + * + */ +static void DragWithin(PanelParameterBlock *pb) +{ +#pragma unused(pb) + + /* there's nothing to do */ + +/// SysBreakStr("\preqDragWithin"); +} + +/* + * DragExit + * + */ +static void DragExit(PanelParameterBlock *pb) +{ + OSErr err; + +/// SysBreakStr("\preqDragExit"); + + if (sHighlightOn) { + err = HideDragHilite(pb->dragref); + if (err == noErr) + sHighlightOn = false; + } +} + +/* + * DragDrop + * + */ +static void DragDrop(PanelParameterBlock *pb) +{ +#if 0 + Rect itemRect; +#endif + +/// SysBreakStr("\preqDragDrop"); + + DragExit(pb); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h new file mode 100644 index 00000000..582b1055 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpidl_panel.h @@ -0,0 +1,106 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpidl_panel.h + */ + +#pragma once + +#ifndef __MAC_XPIDL_PANEL__ +#define __MAC_XPIDL_PANEL__ + +#ifndef __TYPES__ +#include +#endif + +#pragma options align=mac68k + +/* this is the name of the panel, as shown in the Finder */ +#define kXPIDLPanelName "xpidl Settings" + +/* + * AppleScript dictionary info. As a rule of thumb, dropin panels should use the + * same terminology and numeric code in their 'aete' that the IDE uses if there + * is already a similar item in the IDE's 'aete'. That is the case here, so we + * merely duplicate applicable 68K Project and 68K Linker user terms below. + */ + +enum { +/* Symbolic Name Code AETE Terminology */ + class_XPIDL = 'XIDL', + + prefsPR_ProjectType = 'PR01', /* Project Type */ + prefsPR_FileName = 'PR02', /* File Name */ + prefsLN_GenerateSymFile = 'LN02', /* Generate SYM File */ + + /* enumeration for project type */ + enumeration_ProjectType = 'PRPT', + enum_Project_Application = 'PRPA', /* application */ + enum_Project_Library = 'PRPL', /* library */ + enum_Project_SharedLibrary = 'PRPS', /* shared library */ + enum_Project_CodeResource = 'PRPC', /* code resource */ + enum_Project_MPWTool = 'PRPM' /* MPW tool */ +}; + +enum { + kXPIDLModeHeader = 1, + kXPIDLModeJava, + kXPIDLModeTypelib, + kXPIDLModeDoc +}; + +/* This is the structure that is manipulated by the panel. The sample + * compiler & linker both "know" about this structure. + */ + +enum { + kXPIDLSettingsVersion = 0x0100 +}; + +struct XPIDLSettings { + short version; /* version # of settings data */ + short mode; /* one of kXPIDLModeHeader, ... */ + Boolean warnings; /* generate warnings. */ + Boolean verbose; /* verbose mode */ + Str32Field output; /* name of the output file */ +}; + +typedef struct XPIDLSettings XPIDLSettings, **XPIDLSettingsHandle; + +#pragma options align=reset + +#endif /* __MAC_XPIDL_PANEL__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp new file mode 100644 index 00000000..fe137959 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/mac_xpt_linker.cpp @@ -0,0 +1,546 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + mac_xpt_linker.cpp + + CodeWarrior plugin linker, links together multiple .xpt files. + + by Patrick C. Beard. + */ + +/* standard headers */ +#include +#include +#include + +/* system headers */ +#include +#include +#include +#include + +/* compiler headers */ +#include "DropInCompilerLinker.h" +#include "CompilerMapping.h" +#include "CWPluginErrors.h" + +/* project headers */ +#include "mac_xpidl_panel.h" +#include "mac_console.h" +#include "mac_strings.h" +#include "FullPath.h" +#include "MoreFilesExtras.h" + +/* use standard CodeWarrior debugger */ +#define kDebuggerCreator 'MWDB' + +/* prototypes of local functions */ +static CWResult Link(CWPluginContext context); +static CWResult Disassemble(CWPluginContext context); +static CWResult GetTargetInfo(CWPluginContext context); + +extern "C" { +pascal short xpt_linker(CWPluginContext context); +int xptlink_main(int argc, char* argv[]); +int xptdump_main(int argc, char* argv[]); + +FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode); +size_t mac_get_file_length(const char* filename); +} + +/* external variables */ +extern jmp_buf exit_jump; +extern int exit_status; + +/* global variables */ +CWPluginContext gPluginContext; + +/* local variables */ +static CWFileSpec gOutputDirectory; +static CWFileSpec gObjectCodeDirectory; + +/* + * xpt_linker - main entry-point for linker plugin + * + */ +pascal short xpt_linker(CWPluginContext context) +{ + long request; + if (CWGetPluginRequest(context, &request) != cwNoErr) + return cwErrRequestFailed; + + gPluginContext = context; + short result = cwNoErr; + + /* dispatch on linker request */ + switch (request) { + case reqInitLinker: + /* linker has just been loaded into memory */ + break; + + case reqTermLinker: + /* linker is about to be unloaded from memory */ + break; + + case reqLink: + /* build the final executable */ + result = Link(context); + break; + + case reqDisassemble: + /* disassemble object code for a given project file */ + result = Disassemble(context); + break; + + case reqTargetInfo: + /* return info describing target characteristics */ + result = GetTargetInfo(context); + break; + + default: + result = cwErrRequestFailed; + break; + } + + result = CWDonePluginRequest(context, result); + + /* return result code */ + return result; +} + +static char* full_path_to(const FSSpec& file) +{ + short len = 0; + Handle fullPath = NULL; + if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) { + char* path = new char[1 + len]; + if (path != NULL) { + BlockMoveData(*fullPath, path, len); + path[len] = '\0'; + } + DisposeHandle(fullPath); + return path; + } + return NULL; +} + +/** + * Provides the full path name to a given directory. + */ +static char* full_path_to(short vRefNum, long dirID) +{ + long parID; + if (GetParentID(vRefNum, dirID, NULL, &parID) == noErr) { + FSSpec dirSpec = { vRefNum, parID }; + if (GetDirName(vRefNum, dirID, dirSpec.name) == noErr) { + return full_path_to(dirSpec); + } + } + return NULL; +} + +/** + * Returns the length of a file, assuming it is always located in the + * project's object code directory. + */ +size_t mac_get_file_length(const char* filename) +{ + FSSpec fileSpec = { gObjectCodeDirectory.vRefNum, gObjectCodeDirectory.parID }; + c2p_strcpy(fileSpec.name, filename); + long dataSize, rsrcSize; + if (FSpGetFileSize(&fileSpec, &dataSize, &rsrcSize) != noErr) + dataSize = 0; + return dataSize; +} + +/** + * replaces standard fopen -- opens files for writing in the project's output directory, + * and files for reading in the object code directory. + */ +FILE* std::fopen(const char* filename, const char *mode) +{ + CWFileSpec& fileDir = (mode[0] == 'r' ? gObjectCodeDirectory : gOutputDirectory); + FSSpec fileSpec = { fileDir.vRefNum, fileDir.parID }; + c2p_strcpy(fileSpec.name, filename); + return FSp_fopen(&fileSpec, mode); +} + +static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings) +{ + CWMemHandle settingsHand; + CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand); + if (!CWSUCCESS(err)) + return err; + + XPIDLSettings* settingsPtr = NULL; + err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr); + if (!CWSUCCESS(err)) + return err; + + settings = *settingsPtr; + + err = CWUnlockMemHandle(context, settingsHand); + if (!CWSUCCESS(err)) + return err; + + return cwNoErr; +} + +static CWResult LinkHeaders(CWPluginContext context, XPIDLSettings& settings) +{ + // find out how many files there are to link. + long fileCount = 0; + CWResult err = CWGetProjectFileCount(context, &fileCount); + if (err != cwNoErr || fileCount == 0) + return err; + + // get the output directory. + FSSpec outputDir; + err = CWGetOutputFileDirectory(context, &outputDir); + if (!CWSUCCESS(err)) + return err; + + // enumerate all of the output header files, and make aliases to them in + // the output directory. + for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) { + // get the name of each output file. + CWFileSpec outputFile; + err = CWGetStoredObjectFileSpec(context, index, &outputFile); + if (err == cwNoErr) { + FInfo info; + err = FSpGetFInfo(&outputFile, &info); + + FSSpec aliasFile = { outputDir.vRefNum, outputDir.parID }; + BlockMoveData(outputFile.name, aliasFile.name, 1 + outputFile.name[0]); + + AliasHandle alias = NULL; + if (NewAliasMinimal(&outputFile, &alias) == noErr) { + // recreate the alias file from scratch. + FSpDelete(&aliasFile); + FSpCreateResFile(&aliasFile, info.fdCreator, info.fdType, smRoman); + short refNum = FSpOpenResFile(&aliasFile, fsRdWrPerm); + if (refNum != -1) { + UseResFile(refNum); + AddResource(Handle(alias), rAliasType, 0, aliasFile.name); + ReleaseResource(Handle(alias)); + UpdateResFile(refNum); + CloseResFile(refNum); + } + // finally, mark the newly created file as an alias file. + FSpGetFInfo(&aliasFile, &info); + info.fdFlags |= kIsAlias; + FSpSetFInfo(&aliasFile, &info); + } + } + } + + // create the target file in the output directory. + BlockMoveData(settings.output, outputDir.name, 1 + settings.output[0]); + FILE* outputFile = FSp_fopen(&outputDir, "w"); + if (outputFile != NULL) fclose(outputFile); + + return err; +} + +static CWResult LinkTypeLib(CWPluginContext context, XPIDLSettings& settings) +{ + // find out how many files there are to link. + long fileCount = 0; + CWResult err = CWGetProjectFileCount(context, &fileCount); + if (err != cwNoErr || fileCount == 0) + return err; + + // assemble the argument list. + // { "xpt_link", outputFile, inputFile1, ..., inputFileN, NULL } + char** argv = new char*[2 + fileCount + 1]; + int argc = 0; + argv[argc++] = "xpt_link"; + + // get the output directory. + err = CWGetOutputFileDirectory(context, &gOutputDirectory); + if (!CWSUCCESS(err)) + return err; + + // get the object code directory. + err = CWGetStoredObjectFileSpec(context, 0, &gObjectCodeDirectory); + if (!CWSUCCESS(err)) + return err; + + // push the output file name. + if ((argv[argc++] = p2c_strdup(settings.output)) == NULL) + return cwErrOutOfMemory; + + for (long index = 0; (err == cwNoErr) && (index < fileCount); index++) { + // get the name of each output file. + CWFileSpec outputFile; + err = CWGetStoredObjectFileSpec(context, index, &outputFile); + if (err == cwNoErr) { + if ((argv[argc++] = p2c_strdup(outputFile.name)) == NULL) { + err = cwErrOutOfMemory; + break; + } + } + } + + if (err != cwNoErr) + return err; + + // trap calls to exit, which longjmp back to here. + if (setjmp(exit_jump) == 0) { + if (xptlink_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + return err; +} + +static CWResult Link(CWPluginContext context) +{ + // load the relevant prefs. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + CWResult err = GetSettings(context, settings); + if (err != cwNoErr) + return err; + + switch (settings.mode) { + case kXPIDLModeHeader: + return LinkHeaders(context, settings); + case kXPIDLModeTypelib: + return LinkTypeLib(context, settings); + default: + return cwNoErr; + } +} + +static CWResult Disassemble(CWPluginContext context) +{ + CWResult err = noErr; + + // cache the project's output directory. + err = CWGetOutputFileDirectory(gPluginContext, &gOutputDirectory); + if (!CWSUCCESS(err)) + return err; + + long fileNum; + err = CWGetMainFileNumber(context, &fileNum); + if (!CWSUCCESS(err)) + return err; + + // get the output file's location from the stored object data. + err = CWGetStoredObjectFileSpec(context, fileNum, &gObjectCodeDirectory); + if (!CWSUCCESS(err)) + return err; + + char* outputName = p2c_strdup(gObjectCodeDirectory.name); + if (outputName == NULL) + return cwErrOutOfMemory; + + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + GetSettings(context, settings); + + // build an argument list and call xpt_dump. + int argc = 1; + char* argv[] = { "xpt_dump", NULL, NULL, NULL }; + if (settings.verbose) argv[argc++] = "-v"; + argv[argc++] = outputName; + + // trap calls to exit, which longjmp back to here. + if (setjmp(exit_jump) == 0) { + if (xptdump_main(argc, argv) != 0) + err = cwErrRequestFailed; + } else { + // evidently the good old exit function got called. + if (exit_status != 0) + err = cwErrRequestFailed; + } + + delete[] outputName; + + if (err == noErr) { + // display the disassembly in its own fresh text window. + CWNewTextDocumentInfo info = { + NULL, + mac_console_handle, + false + }; + CWResizeMemHandle(context, mac_console_handle, mac_console_count); + err = CWCreateNewTextDocument(context, &info); + } + + return err; +} + +static CWResult GetTargetInfo(CWPluginContext context) +{ + CWTargetInfo targ; + memset(&targ, 0, sizeof(targ)); + + CWResult err = CWGetOutputFileDirectory(context, &targ.outfile); + targ.outputType = linkOutputFile; + targ.symfile = targ.outfile; /* location of SYM file */ + targ.linkType = exelinkageFlat; + targ.targetCPU = '****'; + targ.targetOS = '****'; + + // load the relevant settings. + XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false }; + err = GetSettings(context, settings); + if (err != cwNoErr) + return err; + +#if CWPLUGIN_HOST == CWPLUGIN_HOST_MACOS + // tell the IDE about the output file. + targ.outfileCreator = 'MMCH'; + targ.outfileType = 'CWIE'; + targ.debuggerCreator = kDebuggerCreator; /* so IDE can locate our debugger */ + + BlockMoveData(settings.output, targ.outfile.name, 1 + settings.output[0]); + targ.symfile.name[0] = 0; +#endif + +#if CWPLUGIN_HOST == CWPLUGIN_HOST_WIN32 + targ.debugHelperIsRegKey = true; + *(long*)targ.debugHelperName = kDebuggerCreator; + targ.debugHelperName[4] = 0; + strcat(targ.outfile.path, "\\"); + strcat(targ.outfile.path, prefsData.outfile); + strcpy(targ.symfile.path, targ.outfile.path); + strcat(targ.symfile.path, ".SYM"); +#endif + + targ.runfile = targ.outfile; + targ.linkAgainstFile = targ.outfile; + + /* we can only run applications */ + // targ.canRun = (prefsData.projtype == kProjTypeApplication); + + /* we can only debug if we have a SYM file */ + // targ.canDebug = prefsData.linksym; + + err = CWSetTargetInfo(context, &targ); + + return err; +} + +#if 0 + +#if CW_USE_PRAGMA_EXPORT +#pragma export on +#endif + +CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize) +{ + static const DropInFlags sFlags = { + kCurrentDropInFlagsVersion, + CWDROPINLINKERTYPE, + DROPINCOMPILERLINKERAPIVERSION_7, + (linkMultiTargAware | linkAlwaysReload), + 0, + DROPINCOMPILERLINKERAPIVERSION + }; + + *flags = &sFlags; + *flagsSize = sizeof(sFlags); + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName) +{ + static const char* sDropInName = "xpt Linker"; + *dropinName = sDropInName; + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName) +{ + static const char* sDisplayName = "xpt Linker"; + *displayName = sDisplayName; + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList) +{ + // +++Turn this on when the sample panel has been converted! + static const char* sPanelName = kXPIDLPanelName; + static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName }; + + *panelList = &sPanelList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList) +{ + static CWDataType sCPU = '****'; + static CWDataType sOS = '****'; + static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS }; + + *targetList = &sTargetList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList) +{ + static CWExtensionMapping sExtension = { 'MMCH', ".xpt", 0 }; + static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension }; + + *defaultMappingList = &sExtensionMapList; + + return cwNoErr; +} + +CWPLUGIN_ENTRY (CWPlugin_GetFamilyList)(const CWFamilyList** familyList) +{ + static CWFamily sFamily = { 'XIDL', "xpidl Settings" }; + static CWFamilyList sFamilyList = { kCurrentCWFamilyListVersion, 0, &sFamily }; + + *familyList = &sFamilyList; + + return cwNoErr; +} + +#if CW_USE_PRAGMA_EXPORT +#pragma export off +#endif + +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc new file mode 100644 index 00000000..c5777088 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/panel.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc new file mode 100644 index 00000000..6737d356 Binary files /dev/null and b/src/libs/xpcom18a4/xpcom/typelib/xpidl/macplugin/version.rsrc differ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c new file mode 100644 index 00000000..e1a7c58d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.c @@ -0,0 +1,275 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Main xpidl program entry point. + */ + +#include "xpidl.h" + +static ModeData modes[] = { + {"header", "Generate C++ header", "h", xpidl_header_dispatch}, + {"typelib", "Generate XPConnect typelib", "xpt", xpidl_typelib_dispatch}, + {"doc", "Generate HTML documentation", "html", xpidl_doc_dispatch}, + {"java", "Generate Java interface", "java", xpidl_java_dispatch}, + {0, 0, 0, 0} +}; + +static ModeData * +FindMode(char *mode) +{ + int i; + for (i = 0; modes[i].mode; i++) { + if (!strcmp(modes[i].mode, mode)) + return &modes[i]; + } + return NULL; +} + +gboolean enable_debug = FALSE; +gboolean enable_warnings = FALSE; +gboolean verbose_mode = FALSE; +gboolean emit_typelib_annotations = FALSE; +gboolean explicit_output_filename = FALSE; + +/* The following globals are explained in xpt_struct.h */ +PRUint8 major_version = XPT_MAJOR_VERSION; +PRUint8 minor_version = XPT_MINOR_VERSION; + +static char xpidl_usage_str[] = +"Usage: %s -m mode [-w] [-v] [-t version number]\n" +" [-I path] [-o basename | -e filename.ext] filename.idl\n" +" -a emit annotations to typelib\n" +" -w turn on warnings (recommended)\n" +" -v verbose mode (NYI)\n" +" -t create a typelib of a specific version number\n" +" -I add entry to start of include path for ``#include \"nsIThing.idl\"''\n" +" -o use basename (e.g. ``/tmp/nsIThing'') for output\n" +" -e use explicit output filename\n" +" -m specify output mode:\n"; + +static void +xpidl_usage(int argc, char *argv[]) +{ + int i; + fprintf(stderr, xpidl_usage_str, argv[0]); + for (i = 0; modes[i].mode; i++) { + fprintf(stderr, " %-12s %-30s (.%s)\n", modes[i].mode, + modes[i].modeInfo, modes[i].suffix); + } +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +#define main xpidl_main +int xpidl_main(int argc, char *argv[]); +#endif + +int main(int argc, char *argv[]) +{ + int i; + IncludePathEntry *inc, *inc_head, **inc_tail; + char *file_basename = NULL; + ModeData *mode = NULL; + gboolean create_old_typelib = FALSE; + + /* turn this on for extra checking of our code */ +/* IDL_check_cast_enable(TRUE); */ + + inc_head = xpidl_malloc(sizeof *inc); +#ifndef XP_MAC + inc_head->directory = "."; +#else + inc_head->directory = ""; +#endif + inc_head->next = NULL; + inc_tail = &inc_head->next; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') + break; + switch (argv[i][1]) { + case '-': + argc++; /* pretend we didn't see this */ + /* fall through */ + case 0: /* - is a legal input filename (stdin) */ + goto done_options; + case 'a': + emit_typelib_annotations = TRUE; + break; + case 'w': + enable_warnings = TRUE; + break; + case 'v': + verbose_mode = TRUE; + break; + case 't': + { + /* Parse for "-t version number" and store it into global boolean + * and string variables. + */ + const gchar* typelib_version_string = NULL; + + /* + * If -t is the last argument on the command line, we have a problem + */ + + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing version number after -t\n"); + xpidl_usage(argc, argv); + return 1; + } + + /* Do not allow more than one "-t" definition */ + if (create_old_typelib) { + fprintf(stderr, + "ERROR: -t argument used twice. " + "Cannot specify more than one version\n"); + xpidl_usage(argc, argv); + return 1; + } + + /* + * Assume that the argument after "-t" is the version number string + * and search for it in our internal list of acceptable version + * numbers. + */ + switch (XPT_ParseVersionString(argv[++i], &major_version, + &minor_version)) { + case XPT_VERSION_CURRENT: + break; + case XPT_VERSION_OLD: + create_old_typelib = TRUE; + break; + case XPT_VERSION_UNSUPPORTED: + fprintf(stderr, "ERROR: version \"%s\" not supported.\n", + argv[i]); + xpidl_usage(argc, argv); + return 1; + case XPT_VERSION_UNKNOWN: + default: + fprintf(stderr, "ERROR: version \"%s\" not recognised.\n", + argv[i]); + xpidl_usage(argc, argv); + return 1; + } + break; + } + case 'I': + if (argv[i][2] == '\0' && i == argc) { + fputs("ERROR: missing path after -I\n", stderr); + xpidl_usage(argc, argv); + return 1; + } + inc = xpidl_malloc(sizeof *inc); + if (argv[i][2] == '\0') { + /* is it the -I foo form? */ + inc->directory = argv[++i]; + } else { + /* must be the -Ifoo form. Don't preincrement i. */ + inc->directory = argv[i] + 2; + } +#ifdef DEBUG_shaver_includes + fprintf(stderr, "adding %s to include path\n", inc->directory); +#endif + inc->next = NULL; + *inc_tail = inc; + inc_tail = &inc->next; + break; + case 'o': + if (i == argc) { + fprintf(stderr, "ERROR: missing basename after -o\n"); + xpidl_usage(argc, argv); + return 1; + } + file_basename = argv[++i]; + explicit_output_filename = FALSE; + break; + case 'e': + if (i == argc) { + fprintf(stderr, "ERROR: missing basename after -e\n"); + xpidl_usage(argc, argv); + return 1; + } + file_basename = argv[++i]; + explicit_output_filename = TRUE; + break; + case 'm': + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing modename after -m\n"); + xpidl_usage(argc, argv); + return 1; + } + if (mode) { + fprintf(stderr, + "ERROR: must specify exactly one mode " + "(first \"%s\", now \"%s\")\n", mode->mode, + argv[i + 1]); + xpidl_usage(argc, argv); + return 1; + } + mode = FindMode(argv[++i]); + if (!mode) { + fprintf(stderr, "ERROR: unknown mode \"%s\"\n", argv[i]); + xpidl_usage(argc, argv); + return 1; + } + break; + default: + fprintf(stderr, "unknown option %s\n", argv[i]); + xpidl_usage(argc, argv); + return 1; + } + } + done_options: + if (!mode) { + fprintf(stderr, "ERROR: must specify output mode\n"); + xpidl_usage(argc, argv); + return 1; + } + if (argc != i + 1) { + fprintf(stderr, "ERROR: extra arguments after input file\n"); + } + + /* + * Don't try to process multiple files, given that we don't handle -o + * multiply. + */ + if (xpidl_process_idl(argv[i], inc_head, file_basename, mode)) + return 0; + + return 1; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h new file mode 100644 index 00000000..857bfdf8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl.h @@ -0,0 +1,278 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Intramodule declarations. + */ + +#ifndef __xpidl_h +#define __xpidl_h + +#include +#include +#include +#include +#include +#include /* After glib.h to avoid warnings about shadowing 'index'. */ + +#ifndef XP_MAC +#include +#else +#include +#endif + +#include + +/* + * IDL_tree_warning bombs on libIDL version 6.5, and I don't want to not write + * warnings... so I define a versioned one here. Thanks to Mike Shaver for the + * this solution, which allows us to pass through varargs calls. + */ +#if !(LIBIDL_MAJOR_VERSION == 0 && LIBIDL_MINOR_VERSION == 6 && \ + LIBIDL_MICRO_VERSION == 5) && !defined(DEBUG_shaver) +/* + * This turns a varargs call to XPIDL_WARNING directly into a varargs + * call to IDL_tree_warning or xpidl_tree_warning as appropriate. The + * only tricky bit is that you must call XPIDL_WARNING with extra + * parens, e.g. XPIDL_WARNING((foo, bar, "sil")) + * + * Probably best removed when we leave 6.5. */ +#define XPIDL_WARNING(x) IDL_tree_warning x +#else +extern void xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...); +#define XPIDL_WARNING(x) xpidl_tree_warning x +#endif + +/* + * Internal operation flags. + */ +extern gboolean enable_debug; +extern gboolean enable_warnings; +extern gboolean verbose_mode; +extern gboolean emit_typelib_annotations; +extern gboolean explicit_output_filename; + +extern PRUint8 major_version; +extern PRUint8 minor_version; + +typedef struct TreeState TreeState; + +/* + * A function to handle an IDL_tree type. + */ +typedef gboolean (*nodeHandler)(TreeState *); + +/* + * Struct containing functions to define the behavior of a given output mode. + */ +typedef struct backend { + nodeHandler *dispatch_table; /* nodeHandlers table, indexed by node type. */ + nodeHandler emit_prolog; /* called at beginning of output generation. */ + nodeHandler emit_epilog; /* called at end. */ +} backend; + +/* Function that produces a struct of output-generation functions */ +typedef backend *(*backendFactory)(); + +extern backend *xpidl_header_dispatch(void); +extern backend *xpidl_typelib_dispatch(void); +extern backend *xpidl_doc_dispatch(void); +extern backend *xpidl_java_dispatch(void); + +typedef struct ModeData { + char *mode; + char *modeInfo; + char *suffix; + backendFactory factory; +} ModeData; + +typedef struct IncludePathEntry { + char *directory; + struct IncludePathEntry *next; +} IncludePathEntry; + +struct TreeState { + FILE *file; + /* Maybe supplied by -o. Not related to (g_)basename from string.h or glib */ + char *basename; + IDL_ns ns; + IDL_tree tree; + GSList *base_includes; + nodeHandler *dispatch; + void *priv; /* mode-private data */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + char *real_outname; +#endif + +}; + +/* + * Process an IDL file, generating InterfaceInfo, documentation and headers as + * appropriate. + */ +int +xpidl_process_idl(char *filename, IncludePathEntry *include_path, + char *file_basename, ModeData *mode); + +/* + * Iterate over an IDLN_LIST -- why is this not part of libIDL? + */ +void +xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data); + +/* + * Wrapper whines to stderr then exits after null return from malloc or strdup. + */ +void * +xpidl_malloc(size_t nbytes); + +char * +xpidl_strdup(const char *s); + +/* + * Return a newly allocated string to the start of the base filename of path. + * Free with g_free(). + */ +char * +xpidl_basename(const char * path); + +/* + * Process an XPIDL node and its kids, if any. + */ +gboolean +xpidl_process_node(TreeState *state); + +/* + * Write a newline folllowed by an indented, one-line comment containing IDL + * source decompiled from state->tree. + */ +void +xpidl_write_comment(TreeState *state, int indent); + + + +/* + * Functions for parsing and printing UUIDs. + */ + +/* + * How large should the buffer supplied to xpidl_sprint_IID be? + */ +#define UUID_LENGTH 37 + +/* + * Print an iid to into a supplied buffer; the buffer should be at least + * UUID_LENGTH bytes. + */ +gboolean +xpidl_sprint_iid(nsID *iid, char iidbuf[]); + +/* + * Parse a uuid string into an nsID struct. We cannot link against libxpcom, + * so we re-implement nsID::Parse here. + */ +gboolean +xpidl_parse_iid(nsID *id, const char *str); + + +/* Try to common a little node-handling stuff. */ + +/* is this node from an aggregate type (interface)? */ +#define UP_IS_AGGREGATE(node) \ + (IDL_NODE_UP(node) && \ + (IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_INTERFACE || \ + IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_FORWARD_DCL)) + +#define UP_IS_NATIVE(node) \ + (IDL_NODE_UP(node) && \ + IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_NATIVE) + +/* is this type output in the form " *"? */ +#define STARRED_TYPE(node) (IDL_NODE_TYPE(node) == IDLN_TYPE_STRING || \ + IDL_NODE_TYPE(node) == IDLN_TYPE_WIDE_STRING || \ + (IDL_NODE_TYPE(node) == IDLN_IDENT && \ + UP_IS_AGGREGATE(node))) + +#define DIPPER_TYPE(node) \ + (NULL != IDL_tree_property_get(node, "domstring") || \ + NULL != IDL_tree_property_get(node, "utf8string") || \ + NULL != IDL_tree_property_get(node, "cstring") || \ + NULL != IDL_tree_property_get(node, "astring")) + +/* + * Find the underlying type of an identifier typedef. Returns NULL + * (and doesn't complain) on failure. + */ +IDL_tree /* IDL_TYPE_DCL */ +find_underlying_type(IDL_tree typedef_ident); + +/* + * Check that const declarations match their stated sign and are of the + * appropriate types. + */ +gboolean +verify_const_declaration(IDL_tree const_tree); + +/* + * Check that scriptable attributes in scriptable interfaces actually are. + */ +gboolean +verify_attribute_declaration(IDL_tree method_tree); + +/* + * Perform various validation checks on methods. + */ +gboolean +verify_method_declaration(IDL_tree method_tree); + +/* + * Verifies the interface declaration + */ +gboolean +verify_interface_declaration(IDL_tree method_tree); + +/* + * Verify that a native declaration has an associated C++ expression, i.e. that + * it's of the form native () + */ +gboolean +check_native(TreeState *state); + +void +printlist(FILE *outfile, GSList *slist); + +#endif /* __xpidl_h */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c new file mode 100644 index 00000000..d560e407 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_doc.c @@ -0,0 +1,312 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "xpidl.h" + +/* + * Generates documentation from javadoc-style comments in XPIDL files. + */ + +static gboolean +doc_prolog(TreeState *state) +{ + fprintf(state->file, "\n"); + fprintf(state->file, "\n"); + + fprintf(state->file, + "\n", + state->basename); + fprintf(state->file, "documentation for %s.idl interfaces\n", + state->basename); + fprintf(state->file, "\n\n"); + fprintf(state->file, "\n"); + + return TRUE; +} + +static gboolean +doc_epilog(TreeState *state) +{ + fprintf(state->file, "\n"); + fprintf(state->file, "\n"); + + return TRUE; +} + + +static gboolean +doc_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +print_list(FILE *outfile, IDL_tree list) +{ + if (list == NULL) + return TRUE; + + fprintf(outfile, "
    \n"); + while (list != NULL) { + fprintf(outfile, "
  • %s\n", + IDL_IDENT(IDL_LIST(list).data).str); + list = IDL_LIST(list).next; + } + fprintf(outfile, "
\n"); + return TRUE; +} + +static gboolean +doc_interface(TreeState *state) +{ + IDL_tree iface = state->tree; + IDL_tree iter; + IDL_tree orig; + char *classname = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; + + fprintf(state->file, "interface %s
\n", classname); + + /* Much more could happen at this step. */ + /* + * If parsing doc comments, you might need to take some care with line + * endings, as the xpidl frontend will return comments containing of /r, + * /n, /r/n depending on the platform. It's best to leave out platform + * #defines and just treat them all as equivalent. + */ + if (doc_comments != NULL) { + fprintf(state->file, "doc comments:
\n"); + fprintf(state->file, "
\n");
+        printlist(state->file, doc_comments);
+        fprintf(state->file, "
\n"); + fprintf(state->file, "
\n"); + } + + /* inherits from */ + /* + * Note that we accept multiple inheritance here (for e.g. gnome idl) + * even though the header backend (specific to mozilla idl) rejects it. + */ + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + fprintf(state->file, "%s inherits from:
\n", classname); + print_list(state->file, iter); + fprintf(state->file, "
\n"); + } + + /* + * Call xpidl_process_node to recur through list of declarations in + * interface body; another option would be to explicitly iterate through + * the list. xpidl_process_node currently requires twiddling the state to + * get the right node; I'll fix that soon to just take the node. Makes it + * easier to follow what's going on, I think... + */ + orig = state->tree; + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; + state->tree = orig; + + return TRUE; +} + +/* + * Copied from xpidl_header.c. You'll probably want to change it; if you can + * use it verbatim or abstract it, we could move it to xpidl_util.c and share + * it from there. + */ +static gboolean +write_type(IDL_tree type_tree, FILE *outfile) +{ + if (!type_tree) { + fputs("void", outfile); + return TRUE; + } + + switch (IDL_NODE_TYPE(type_tree)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed; + switch (IDL_TYPE_INTEGER(type_tree).f_type) { + case IDL_INTEGER_TYPE_SHORT: + fputs(sign ? "PRInt16" : "PRUint16", outfile); + break; + case IDL_INTEGER_TYPE_LONG: + fputs(sign ? "PRInt32" : "PRUint32", outfile); + break; + case IDL_INTEGER_TYPE_LONGLONG: + fputs(sign ? "PRInt64" : "PRUint64", outfile); + break; + default: + g_error("Unknown integer type %d\n", + IDL_TYPE_INTEGER(type_tree).f_type); + return FALSE; + } + break; + } + case IDLN_TYPE_CHAR: + fputs("char", outfile); + break; + case IDLN_TYPE_WIDE_CHAR: + fputs("PRUnichar", outfile); /* wchar_t? */ + break; + case IDLN_TYPE_WIDE_STRING: + fputs("PRUnichar *", outfile); + break; + case IDLN_TYPE_STRING: + fputs("char *", outfile); + break; + case IDLN_TYPE_BOOLEAN: + fputs("PRBool", outfile); + break; + case IDLN_TYPE_OCTET: + fputs("PRUint8", outfile); + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT(type_tree).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", outfile); + break; + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", outfile); + break; + /* XXX 'long double' just ignored, or what? */ + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + break; + case IDLN_IDENT: + if (UP_IS_NATIVE(type_tree)) { + fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile); + if (IDL_tree_property_get(type_tree, "ptr")) { + fputs(" *", outfile); + } else if (IDL_tree_property_get(type_tree, "ref")) { + fputs(" &", outfile); + } + } else { + fputs(IDL_IDENT(type_tree).str, outfile); + } + if (UP_IS_AGGREGATE(type_tree)) + fputs(" *", outfile); + break; + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + return TRUE; +} + +/* handle ATTR_DCL (attribute declaration) nodes */ +static gboolean +doc_attribute_declaration(TreeState *state) +{ + IDL_tree attr = state->tree; + + if (!verify_attribute_declaration(attr)) + return FALSE; + /* + * Attribute idents can also take doc comments. They're ignored here; + * should they be? + */ + + if (IDL_ATTR_DCL(attr).f_readonly) + fprintf(state->file, "readonly "); + + fprintf(state->file, "attribute "); + + if (!write_type(IDL_ATTR_DCL(attr).param_type_spec, state->file)) + return FALSE; + + fprintf(state->file, "\n"); + print_list(state->file, IDL_ATTR_DCL(attr).simple_declarations); + fprintf(state->file, "
\n"); + + return TRUE; +} + +/* handle OP_DCL (method declaration) nodes */ +static gboolean +doc_method_declaration(TreeState *state) +{ + /* + * Doc comment for attributes also applies here. + */ + + /* + * Look at 'write_method_signature' in xpidl_header.c for an example of how + * to navigate parse trees for methods. For here, I just print the method + * name. + */ + + fprintf(state->file, + "method %s
\n", + IDL_IDENT(IDL_OP_DCL(state->tree).ident).str); + + return TRUE; +} + +backend * +xpidl_doc_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = doc_prolog; + result.emit_epilog = doc_epilog; + + if (!initialized) { + /* Initialize non-NULL elements */ + + /* I just handle a few... many still to be filled in! */ + + table[IDLN_LIST] = doc_list; + table[IDLN_INTERFACE] = doc_interface; + table[IDLN_ATTR_DCL] = doc_attribute_declaration; + table[IDLN_OP_DCL] = doc_method_declaration; + + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c new file mode 100644 index 00000000..f4fe9d5b --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_header.c @@ -0,0 +1,1196 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate XPCOM headers from XPIDL. + */ + +#include "xpidl.h" +#include + +#define AS_DECL 0 +#define AS_CALL 1 +#define AS_IMPL 2 + +static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile, + int mode, const char *className); +static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile, + gboolean getter, + int mode, const char *className); + +static void +write_indent(FILE *outfile) { + fputs(" ", outfile); +} + +static gboolean +header_prolog(TreeState *state) +{ + char *define = xpidl_basename(state->basename); + fprintf(state->file, "/*\n * DO NOT EDIT. THIS FILE IS GENERATED FROM" + " %s.idl\n */\n", state->basename); + fprintf(state->file, + "\n#ifndef __gen_%s_h__\n" + "#define __gen_%s_h__\n", + define, define); + g_free(define); + if (state->base_includes != NULL) { + guint len = g_slist_length(state->base_includes); + guint i; + + fputc('\n', state->file); + for (i = 0; i < len; i++) { + char *ident, *dot; + + ident = (char *)g_slist_nth_data(state->base_includes, i); + + /* suppress any trailing .extension */ + + /* XXX use g_basename instead ? ? */ + + dot = strrchr(ident, '.'); + if (dot != NULL) + *dot = '\0'; + + + /* begin include guard */ + fprintf(state->file, + "\n#ifndef __gen_%s_h__\n", + ident); + + fprintf(state->file, "#include \"%s.h\"\n", + (char *)g_slist_nth_data(state->base_includes, i)); + + fprintf(state->file, "#endif\n"); + + } + if (i > 0) + fputc('\n', state->file); + } + /* + * Support IDL files that don't include a root IDL file that defines + * NS_NO_VTABLE. + */ + fprintf(state->file, + "/* For IDL files that don't want to include root IDL files. */\n" + "#ifndef NS_NO_VTABLE\n" + "#define NS_NO_VTABLE\n" + "#endif\n"); + + return TRUE; +} + +static gboolean +header_epilog(TreeState *state) +{ + char *define = xpidl_basename(state->basename); + fprintf(state->file, "\n#endif /* __gen_%s_h__ */\n", define); + g_free(define); + return TRUE; +} + +static void +write_classname_iid_define(FILE *file, const char *className) +{ + const char *iidName; + if (className[0] == 'n' && className[1] == 's') { + /* backcompat naming styles */ + fputs("NS_", file); + iidName = className + 2; + } else { + iidName = className; + } + while (*iidName) + fputc(toupper(*iidName++), file); + fputs("_IID", file); +} + +static gboolean +interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter, orig; + char *className = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + char *classNameUpper = NULL; + char *classNameImpl = NULL; + char *cp; + gboolean ok = TRUE; + gboolean keepvtable; + const char *iid; + const char *name_space; + struct nsID id; + char iid_parsed[UUID_LENGTH]; + GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(iface).ident).comments; + + if (!verify_interface_declaration(iface)) + return FALSE; + +#define FAIL do {ok = FALSE; goto out;} while(0) + + fprintf(state->file, "\n/* starting interface: %s */\n", + className); + + name_space = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "namespace"); + if (name_space) { + fprintf(state->file, "/* namespace: %s */\n", + name_space); + fprintf(state->file, "/* fully qualified name: %s.%s */\n", + name_space,className); + } + + iid = IDL_tree_property_get(IDL_INTERFACE(iface).ident, "uuid"); + if (iid) { + /* Redundant, but a better error than 'cannot parse.' */ + if (strlen(iid) != 36) { + IDL_tree_error(state->tree, "IID %s is the wrong length\n", iid); + FAIL; + } + + /* + * Parse uuid and then output resulting nsID to string, to validate + * uuid and normalize resulting .h files. + */ + if (!xpidl_parse_iid(&id, iid)) { + IDL_tree_error(state->tree, "cannot parse IID %s\n", iid); + FAIL; + } + if (!xpidl_sprint_iid(&id, iid_parsed)) { + IDL_tree_error(state->tree, "error formatting IID %s\n", iid); + FAIL; + } + + /* #define NS_ISUPPORTS_IID_STR "00000000-0000-0000-c000-000000000046" */ + fputs("#define ", state->file); + write_classname_iid_define(state->file, className); + fprintf(state->file, "_STR \"%s\"\n", iid_parsed); + fputc('\n', state->file); + + /* #define NS_ISUPPORTS_IID { {0x00000000 .... 0x46 }} */ + fprintf(state->file, "#define "); + write_classname_iid_define(state->file, className); + fprintf(state->file, " \\\n" + " {0x%.8x, 0x%.4x, 0x%.4x, \\\n" + " { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, " + "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }}\n", + id.m0, id.m1, id.m2, + id.m3[0], id.m3[1], id.m3[2], id.m3[3], + id.m3[4], id.m3[5], id.m3[6], id.m3[7]); + fputc('\n', state->file); + } else { + IDL_tree_error(state->tree, "interface %s lacks a uuid attribute\n", + className); + FAIL; + } + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + /* + * NS_NO_VTABLE is defined in nsISupportsUtils.h, and defined on windows + * to __declspec(novtable) on windows. This optimization is safe + * whenever the constructor calls no virtual methods. Writing in IDL + * almost guarantees this, except for the case when a %{C++ block occurs in + * the interface. We detect that case, and emit a macro call that disables + * the optimization. + */ + keepvtable = FALSE; + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + if (IDL_NODE_TYPE(data) == IDLN_CODEFRAG) + keepvtable = TRUE; + } + + /* The interface declaration itself. */ + fprintf(state->file, + "class %s%s", + (keepvtable ? "" : "NS_NO_VTABLE "), className); + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + fputs(" : ", state->file); + if (IDL_LIST(iter).next != NULL) { + IDL_tree_error(iter, + "multiple inheritance is not supported by xpidl"); + FAIL; + } + fprintf(state->file, "public %s", IDL_IDENT(IDL_LIST(iter).data).str); + } + fputs(" {\n" + " public: \n\n", state->file); + if (iid) { + fputs(" NS_DEFINE_STATIC_IID_ACCESSOR(", state->file); + write_classname_iid_define(state->file, className); + fputs(")\n\n", state->file); + } + + orig = state->tree; /* It would be nice to remove this state-twiddling. */ + + state->tree = IDL_INTERFACE(iface).body; + + if (state->tree && !xpidl_process_node(state)) + FAIL; + + fputs("};\n", state->file); + fputc('\n', state->file); + + /* + * #define NS_DECL_NSIFOO - create method prototypes that can be used in + * class definitions that support this interface. + * + * Walk the tree explicitly to prototype a reworking of xpidl to get rid of + * the callback mechanism. + */ + state->tree = orig; + fputs("/* Use this macro when declaring classes that implement this " + "interface. */\n", state->file); + fputs("#define NS_DECL_", state->file); + classNameUpper = xpidl_strdup(className); + for (cp = classNameUpper; *cp != '\0'; cp++) + *cp = toupper(*cp); + fprintf(state->file, "%s \\\n", classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + /* '; \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + /* ignore it here; it doesn't contribute to the macro. */ + continue; + + case IDLN_CODEFRAG: + XPIDL_WARNING((iter, IDL_WARNING1, + "%%{ .. %%} code fragment within interface " + "ignored when generating NS_DECL_%s macro; " + "if the code fragment contains method " + "declarations, the macro probably isn't " + "complete.", classNameUpper)); + continue; + + default: + IDL_tree_error(iter, + "unexpected node type %d! " + "Please file a bug against the xpidl component.", + IDL_NODE_TYPE(data)); + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; \\\n"); + } else { + fprintf(state->file, "; \n"); + } + } + fputc('\n', state->file); + + /* XXX abstract above and below into one function? */ + /* + * #define NS_FORWARD_NSIFOO - create forwarding methods that can delegate + * behavior from in implementation to another object. As generated by + * idlc. + */ + fprintf(state->file, + "/* Use this macro to declare functions that forward the " + "behavior of this interface to another object. */\n" + "#define NS_FORWARD_%s(_to) \\\n", + classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + fputs(" { return _to ", state->file); + write_method_signature(data, state->file, AS_CALL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + fputs(" { return _to ", state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; } \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + fputs(" { return _to ", state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_CALL, NULL)) + FAIL; + /* '; } \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; } \\\n"); + } else { + fprintf(state->file, "; } \n"); + } + } + fputc('\n', state->file); + + + /* XXX abstract above and below into one function? */ + /* + * #define NS_FORWARD_SAFE_NSIFOO - create forwarding methods that can delegate + * behavior from in implementation to another object. As generated by + * idlc. + */ + fprintf(state->file, + "/* Use this macro to declare functions that forward the " + "behavior of this interface to another object in a safe way. */\n" + "#define NS_FORWARD_SAFE_%s(_to) \\\n", + classNameUpper); + if (IDL_INTERFACE(state->tree).body == NULL) { + write_indent(state->file); + fputs("/* no methods! */\n", state->file); + } + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + write_indent(state->file); + write_method_signature(data, state->file, AS_DECL, NULL); + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + write_method_signature(data, state->file, AS_CALL, NULL); + break; + + case IDLN_ATTR_DCL: + write_indent(state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_DECL, NULL)) + FAIL; + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + if (!write_attr_accessor(data, state->file, TRUE, AS_CALL, NULL)) + FAIL; + if (!IDL_ATTR_DCL(data).f_readonly) { + fputs("; } \\\n", state->file); /* Terminate the previous one. */ + write_indent(state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_DECL, NULL)) + FAIL; + fputs(" { return !_to ? NS_ERROR_NULL_POINTER : _to->", state->file); + if (!write_attr_accessor(data, state->file, + FALSE, AS_CALL, NULL)) + FAIL; + /* '; } \n' at end will clean up. */ + } + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + + if (IDL_LIST(iter).next != NULL) { + fprintf(state->file, "; } \\\n"); + } else { + fprintf(state->file, "; } \n"); + } + } + fputc('\n', state->file); + + /* + * Build a sample implementation template. + */ + if (strlen(className) >= 3 && className[2] == 'I') { + classNameImpl = xpidl_strdup(className); + if (!classNameImpl) + FAIL; + memmove(&classNameImpl[2], &classNameImpl[3], strlen(classNameImpl) - 2); + } else { + classNameImpl = xpidl_strdup("_MYCLASS_"); + if (!classNameImpl) + FAIL; + } + + fputs("#if 0\n" + "/* Use the code below as a template for the " + "implementation class for this interface. */\n" + "\n" + "/* Header file */" + "\n", + state->file); + fprintf(state->file, "class %s : public %s\n", classNameImpl, className); + fputs("{\n" + "public:\n", state->file); + write_indent(state->file); + fputs("NS_DECL_ISUPPORTS\n", state->file); + write_indent(state->file); + fprintf(state->file, "NS_DECL_%s\n", classNameUpper); + fputs("\n", state->file); + write_indent(state->file); + fprintf(state->file, "%s();\n", classNameImpl); + fputs("\n" + "private:\n", state->file); + write_indent(state->file); + fprintf(state->file, "~%s();\n", classNameImpl); + fputs("\n" + "protected:\n", state->file); + write_indent(state->file); + fputs("/* additional members */\n", state->file); + fputs("};\n\n", state->file); + + fputs("/* Implementation file */\n", state->file); + + fprintf(state->file, + "NS_IMPL_ISUPPORTS1(%s, %s)\n", classNameImpl, className); + fputs("\n", state->file); + + fprintf(state->file, "%s::%s()\n", classNameImpl, classNameImpl); + fputs("{\n", state->file); + write_indent(state->file); + fputs("/* member initializers and constructor code */\n", state->file); + fputs("}\n\n", state->file); + + fprintf(state->file, "%s::~%s()\n", classNameImpl, classNameImpl); + fputs("{\n", state->file); + write_indent(state->file); + fputs("/* destructor code */\n", state->file); + fputs("}\n\n", state->file); + + for (iter = IDL_INTERFACE(state->tree).body; + iter != NULL; + iter = IDL_LIST(iter).next) + { + IDL_tree data = IDL_LIST(iter).data; + + switch(IDL_NODE_TYPE(data)) { + case IDLN_OP_DCL: + /* It would be nice to remove this state-twiddling. */ + orig = state->tree; + state->tree = data; + xpidl_write_comment(state, 0); + state->tree = orig; + + write_method_signature(data, state->file, AS_IMPL, classNameImpl); + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n" + "\n", state->file); + break; + + case IDLN_ATTR_DCL: + /* It would be nice to remove this state-twiddling. */ + orig = state->tree; + state->tree = data; + xpidl_write_comment(state, 0); + state->tree = orig; + + if (!write_attr_accessor(data, state->file, TRUE, + AS_IMPL, classNameImpl)) + FAIL; + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n", state->file); + + if (!IDL_ATTR_DCL(data).f_readonly) { + if (!write_attr_accessor(data, state->file, FALSE, + AS_IMPL, classNameImpl)) + FAIL; + fputs("\n{\n", state->file); + write_indent(state->file); + write_indent(state->file); + fputs("return NS_ERROR_NOT_IMPLEMENTED;\n" + "}\n", state->file); + } + fputs("\n", state->file); + break; + + case IDLN_CONST_DCL: + case IDLN_CODEFRAG: + continue; + + default: + FAIL; + } + } + + fputs("/* End of implementation class template. */\n" + "#endif\n" + "\n", state->file); + +#undef FAIL + +out: + if (classNameUpper) + free(classNameUpper); + if (classNameImpl) + free(classNameImpl); + return ok; +} + +static gboolean +list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile) +{ + if (!type_tree) { + fputs("void", outfile); + return TRUE; + } + + switch (IDL_NODE_TYPE(type_tree)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed; + switch (IDL_TYPE_INTEGER(type_tree).f_type) { + case IDL_INTEGER_TYPE_SHORT: + fputs(sign ? "PRInt16" : "PRUint16", outfile); + break; + case IDL_INTEGER_TYPE_LONG: + fputs(sign ? "PRInt32" : "PRUint32", outfile); + break; + case IDL_INTEGER_TYPE_LONGLONG: + fputs(sign ? "PRInt64" : "PRUint64", outfile); + break; + default: + g_error("Unknown integer type %d\n", + IDL_TYPE_INTEGER(type_tree).f_type); + return FALSE; + } + break; + } + case IDLN_TYPE_CHAR: + fputs("char", outfile); + break; + case IDLN_TYPE_WIDE_CHAR: + fputs("PRUnichar", outfile); /* wchar_t? */ + break; + case IDLN_TYPE_WIDE_STRING: + fputs("PRUnichar *", outfile); + break; + case IDLN_TYPE_STRING: + fputs("char *", outfile); + break; + case IDLN_TYPE_BOOLEAN: + fputs("PRBool", outfile); + break; + case IDLN_TYPE_OCTET: + fputs("PRUint8", outfile); + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT(type_tree).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", outfile); + break; + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", outfile); + break; + /* XXX 'long double' just ignored, or what? */ + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + break; + case IDLN_IDENT: + if (UP_IS_NATIVE(type_tree)) { + if (IDL_tree_property_get(type_tree, "domstring") || + IDL_tree_property_get(type_tree, "astring")) { + fputs("nsAString", outfile); + } else if (IDL_tree_property_get(type_tree, "utf8string")) { + fputs("nsACString", outfile); + } else if (IDL_tree_property_get(type_tree, "cstring")) { + fputs("nsACString", outfile); + } else { + fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile); + } + if (IDL_tree_property_get(type_tree, "ptr")) { + fputs(" *", outfile); + } else if (IDL_tree_property_get(type_tree, "ref")) { + fputs(" &", outfile); + } + } else { + fputs(IDL_IDENT(type_tree).str, outfile); + } + if (UP_IS_AGGREGATE(type_tree)) + fputs(" *", outfile); + break; + default: + fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); + break; + } + return TRUE; +} + +/* + * An attribute declaration looks like: + * + * [ IDL_ATTR_DCL] + * - param_type_spec [IDL_TYPE_* or NULL for void] + * - simple_declarations [IDL_LIST] + * - data [IDL_IDENT] + * - next [IDL_LIST or NULL if no more idents] + * - data [IDL_IDENT] + */ + +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data)) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec) +#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree))) + +/* + * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)' + * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)' + * AS_CALL writes 'foo(bar, sil)' + */ +static gboolean +write_attr_accessor(IDL_tree attr_tree, FILE * outfile, + gboolean getter, int mode, const char *className) +{ + char *attrname = ATTR_IDENT(attr_tree).str; + + if (mode == AS_DECL) { + fputs("NS_IMETHOD ", outfile); + } else if (mode == AS_IMPL) { + fprintf(outfile, "NS_IMETHODIMP %s::", className); + } + fprintf(outfile, "%cet%c%s(", + getter ? 'G' : 'S', + toupper(*attrname), attrname + 1); + if (mode == AS_DECL || mode == AS_IMPL) { + /* Setters for string, wstring, nsid, domstring, utf8string, + * cstring and astring get const. + */ + if (!getter && + (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") || + IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring"))) + { + fputs("const ", outfile); + } + + if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile)) + return FALSE; + fprintf(outfile, "%s%s", + (STARRED_TYPE(attr_tree) ? "" : " "), + (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : ""); + } + fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1); + return TRUE; +} + +static gboolean +attr_dcl(TreeState *state) +{ + GSList *doc_comments; + + if (!verify_attribute_declaration(state->tree)) + return FALSE; + + doc_comments = + IDL_IDENT(IDL_LIST(IDL_ATTR_DCL + (state->tree).simple_declarations).data).comments; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + + /* + * XXX lists of attributes with the same type, e.g. + * attribute string foo, bar sil; + * are legal IDL... but we don't do anything with 'em. + */ + if (IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).next != NULL) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "multiple attributes in a single declaration aren't " + "currently supported by xpidl")); + } + + xpidl_write_comment(state, 2); + + write_indent(state->file); + if (!write_attr_accessor(state->tree, state->file, TRUE, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n", state->file); + + if (!IDL_ATTR_DCL(state->tree).f_readonly) { + write_indent(state->file); + if (!write_attr_accessor(state->tree, state->file, FALSE, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n", state->file); + } + fputc('\n', state->file); + + return TRUE; +} + +static gboolean +do_enum(TreeState *state) +{ + IDL_tree_error(state->tree, "enums not supported, " + "see http://bugzilla.mozilla.org/show_bug.cgi?id=8781"); + return FALSE; +} + +static gboolean +do_const_dcl(TreeState *state) +{ + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(dcl->ident).str; + gboolean is_signed; + GSList *doc_comments = IDL_IDENT(dcl->ident).comments; + IDL_tree real_type; + const char *const_format; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + is_signed = IDL_TYPE_INTEGER(real_type).f_signed; + + const_format = is_signed ? "%" IDL_LL "d" : "%" IDL_LL "uU"; + write_indent(state->file); + fprintf(state->file, "enum { %s = ", name); + fprintf(state->file, const_format, IDL_INTEGER(dcl->const_exp).value); + fprintf(state->file, " };\n\n"); + + return TRUE; +} + +static gboolean +do_typedef(TreeState *state) +{ + IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec; + IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls; + IDL_tree complex; + GSList *doc_comments; + + if (IDL_NODE_TYPE(type) == IDLN_TYPE_SEQUENCE) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "sequences not supported, ignored")); + } else { + if (IDL_NODE_TYPE(complex = IDL_LIST(dcls).data) == IDLN_TYPE_ARRAY) { + IDL_tree dim = IDL_TYPE_ARRAY(complex).size_list; + doc_comments = IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).comments; + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + fputs("typedef ", state->file); + if (!write_type(type, FALSE, state->file)) + return FALSE; + fputs(" ", state->file); + + fprintf(state->file, "%s", + IDL_IDENT(IDL_TYPE_ARRAY(complex).ident).str); + do { + fputc('[', state->file); + if (IDL_LIST(dim).data) { + fprintf(state->file, "%ld", + (long)IDL_INTEGER(IDL_LIST(dim).data).value); + } + fputc(']', state->file); + } while ((dim = IDL_LIST(dim).next) != NULL); + } else { + doc_comments = IDL_IDENT(IDL_LIST(dcls).data).comments; + + if (doc_comments != NULL) + printlist(state->file, doc_comments); + + fputs("typedef ", state->file); + if (!write_type(type, FALSE, state->file)) + return FALSE; + fputs(" ", state->file); + fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file); + } + fputs(";\n\n", state->file); + } + return TRUE; +} + +/* + * param generation: + * in string foo --> nsString *foo + * out string foo --> nsString **foo; + * inout string foo --> nsString **foo; + */ + +/* If notype is true, just write the param name. */ +static gboolean +write_param(IDL_tree param_tree, FILE *outfile) +{ + IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec; + gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN; + /* in string, wstring, nsid, domstring, utf8string, cstring and + * astring any explicitly marked [const] are const + */ + + if (is_in && + (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING || + IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "const") || + IDL_tree_property_get(param_type_spec, "nsid") || + IDL_tree_property_get(param_type_spec, "domstring") || + IDL_tree_property_get(param_type_spec, "utf8string") || + IDL_tree_property_get(param_type_spec, "cstring") || + IDL_tree_property_get(param_type_spec, "astring"))) { + fputs("const ", outfile); + } + else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT && + IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "shared")) { + fputs("const ", outfile); + } + + if (!write_type(param_type_spec, !is_in, outfile)) + return FALSE; + + /* unless the type ended in a *, add a space */ + if (!STARRED_TYPE(param_type_spec)) + fputc(' ', outfile); + + /* out and inout params get a bonus '*' (unless this is type that has a + * 'dipper' class that is passed in to receive 'out' data) + */ + if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN && + !DIPPER_TYPE(param_type_spec)) { + fputc('*', outfile); + } + /* arrays get a bonus * too */ + /* XXX Should this be a leading '*' or a trailing "[]" ?*/ + if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, + "array")) + fputc('*', outfile); + + fputs(IDL_IDENT(IDL_PARAM_DCL(param_tree).simple_declarator).str, outfile); + + return TRUE; +} + +/* + * A forward declaration, usually an interface. + */ +static gboolean +forward_dcl(TreeState *state) +{ + IDL_tree iface = state->tree; + const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + + if (!className) + return FALSE; + + fprintf(state->file, "class %s; /* forward declaration */\n\n", className); + return TRUE; +} + +/* + * Shared between the interface class declaration and the NS_DECL_IFOO macro + * provided to aid declaration of implementation classes. + * mode... + * AS_DECL writes 'NS_IMETHOD foo(string bar, long sil)' + * AS_IMPL writes 'NS_IMETHODIMP className::foo(string bar, long sil)' + * AS_CALL writes 'foo(bar, sil)' + */ +static gboolean +write_method_signature(IDL_tree method_tree, FILE *outfile, int mode, + const char *className) +{ + struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree); + gboolean no_generated_args = TRUE; + gboolean op_notxpcom = + (IDL_tree_property_get(op->ident, "notxpcom") != NULL); + const char *name; + IDL_tree iter; + + if (mode == AS_DECL) { + if (op_notxpcom) { + fputs("NS_IMETHOD_(", outfile); + if (!write_type(op->op_type_spec, FALSE, outfile)) + return FALSE; + fputc(')', outfile); + } else { + fputs("NS_IMETHOD", outfile); + } + fputc(' ', outfile); + } + else if (mode == AS_IMPL) { + if (op_notxpcom) { + fputs("NS_IMETHODIMP_(", outfile); + if (!write_type(op->op_type_spec, FALSE, outfile)) + return FALSE; + fputc(')', outfile); + } else { + fputs("NS_IMETHODIMP", outfile); + } + fputc(' ', outfile); + } + name = IDL_IDENT(op->ident).str; + if (mode == AS_IMPL) { + fprintf(outfile, "%s::%c%s(", className, toupper(*name), name + 1); + } else { + fprintf(outfile, "%c%s(", toupper(*name), name + 1); + } + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) { + if (mode == AS_DECL || mode == AS_IMPL) { + if (!write_param(IDL_LIST(iter).data, outfile)) + return FALSE; + } else { + fputs(IDL_IDENT(IDL_PARAM_DCL(IDL_LIST(iter).data) + .simple_declarator).str, + outfile); + } + if ((IDL_LIST(iter).next || + (!op_notxpcom && op->op_type_spec) || op->f_varargs)) + fputs(", ", outfile); + no_generated_args = FALSE; + } + + /* make IDL return value into trailing out argument */ + if (op->op_type_spec && !op_notxpcom) { + IDL_tree fake_param = IDL_param_dcl_new(IDL_PARAM_OUT, + op->op_type_spec, + IDL_ident_new("_retval")); + if (!fake_param) + return FALSE; + if (mode == AS_DECL || mode == AS_IMPL) { + if (!write_param(fake_param, outfile)) + return FALSE; + } else { + fputs("_retval", outfile); + } + if (op->f_varargs) + fputs(", ", outfile); + no_generated_args = FALSE; + } + + /* varargs go last */ + if (op->f_varargs) { + if (mode == AS_DECL || mode == AS_IMPL) { + fputs("nsVarArgs *", outfile); + } + fputs("_varargs", outfile); + no_generated_args = FALSE; + } + + /* + * If generated method has no arguments, output 'void' to avoid C legacy + * behavior of disabling type checking. + */ + if (no_generated_args && mode == AS_DECL) { + fputs("void", outfile); + } + + fputc(')', outfile); + + return TRUE; +} + +/* + * A method is an `operation', therefore a method decl is an `op dcl'. + * I blame Elliot. + */ +static gboolean +op_dcl(TreeState *state) +{ + GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments; + + /* + * Verify that e.g. non-scriptable methods in [scriptable] interfaces + * are declared so. Do this in a separate verification pass? + */ + if (!verify_method_declaration(state->tree)) + return FALSE; + + if (doc_comments != NULL) { + write_indent(state->file); + printlist(state->file, doc_comments); + } + xpidl_write_comment(state, 2); + + write_indent(state->file); + if (!write_method_signature(state->tree, state->file, AS_DECL, NULL)) + return FALSE; + fputs(" = 0;\n\n", state->file); + + return TRUE; +} + +static void +write_codefrag_line(gpointer data, gpointer user_data) +{ + TreeState *state = (TreeState *)user_data; + const char *line = (const char *)data; + fputs(line, state->file); + fputc('\n', state->file); +} + +static gboolean +codefrag(TreeState *state) +{ + const char *desc = IDL_CODEFRAG(state->tree).desc; + GSList *lines = IDL_CODEFRAG(state->tree).lines; + guint fragment_length; + + if (strcmp(desc, "C++") && /* libIDL bug? */ strcmp(desc, "C++\r")) { + XPIDL_WARNING((state->tree, IDL_WARNING1, + "ignoring '%%{%s' escape. " + "(Use '%%{C++' to escape verbatim C++ code.)", desc)); + + return TRUE; + } + + /* + * Emit #file directive to point debuggers back to the original .idl file + * for the duration of the code fragment. We look at internal IDL node + * properties _file, _line to do this; hopefully they won't change. + * + * _line seems to refer to the line immediately after the closing %}, so + * we backtrack to get the proper line for the beginning of the block. + */ + /* + * Looks like getting this right means maintaining an accurate line + * count of everything generated, so we can set the file back to the + * correct line in the generated file afterwards. Skipping for now... + */ + + fragment_length = g_slist_length(lines); +/* fprintf(state->file, "#line %d \"%s\"\n", */ +/* state->tree->_line - fragment_length - 1, */ +/* state->tree->_file); */ + + g_slist_foreach(lines, write_codefrag_line, (gpointer)state); + + return TRUE; +} + +backend * +xpidl_header_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = header_prolog; + result.emit_epilog = header_epilog; + + if (!initialized) { + table[IDLN_LIST] = list; + table[IDLN_ATTR_DCL] = attr_dcl; + table[IDLN_OP_DCL] = op_dcl; + table[IDLN_FORWARD_DCL] = forward_dcl; + table[IDLN_TYPE_ENUM] = do_enum; + table[IDLN_INTERFACE] = interface; + table[IDLN_CODEFRAG] = codefrag; + table[IDLN_TYPE_DCL] = do_typedef; + table[IDLN_CONST_DCL] = do_const_dcl; + table[IDLN_NATIVE] = check_native; + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c new file mode 100644 index 00000000..175f379a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_idl.c @@ -0,0 +1,836 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Michael Ang + * + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Common IDL-processing code. + */ + +#include "xpidl.h" + +#ifdef XP_MAC +#include +#endif + +static gboolean parsed_empty_file; + +/* + * The bulk of the generation happens here. + */ +gboolean +xpidl_process_node(TreeState *state) +{ + gint type; + nodeHandler *dispatch, handler; + + XPT_ASSERT(state->tree); + type = IDL_NODE_TYPE(state->tree); + + if ((dispatch = state->dispatch) && (handler = dispatch[type])) + return handler(state); + return TRUE; +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +extern void mac_warning(const char* warning_message); +#endif + +static int +msg_callback(int level, int num, int line, const char *file, + const char *message) +{ + char *warning_message; + + /* + * Egregious hack to permit empty files. + * XXX libIDL needs an API to detect this case robustly. + */ + if (0 == strcmp(message, "File empty after optimization")) { + parsed_empty_file = TRUE; + return 1; + } + + if (!file) + file = ""; + warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message); + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + mac_warning(warning_message); +#else + fputs(warning_message, stderr); +#endif + + g_free(warning_message); + return 1; +} + +/* + * To keep track of the state associated with a given input file. The 'next' + * field lets us maintain a stack of input files. + */ +typedef struct input_data { + char *filename; /* where did I come from? */ + unsigned int lineno; /* last lineno processed */ + char *buf; /* contents of file */ + char *point; /* next char to feed to libIDL */ + char *max; /* 1 past last char in buf */ + struct input_data *next; /* file from which we were included */ +} input_data; + +/* + * Passed to us by libIDL. Holds global information and the current stack of + * include files. + */ +typedef struct input_callback_state { + struct input_data *input_stack; /* linked list of input_data */ + GHashTable *already_included; /* to prevent redundant includes */ + IncludePathEntry *include_path; /* search path for included files */ + GSList *base_includes; /* to accumulate #includes from *first* file; + * for passing thru TreeState to + * xpidl_header backend. */ +} input_callback_state; + +static FILE * +fopen_from_includes(const char *filename, const char *mode, + IncludePathEntry *include_path) +{ + IncludePathEntry *current_path = include_path; + char *pathname; + FILE *inputfile; + if (!strcmp(filename, "-")) + return stdin; + + if (filename[0] != '/') { + while (current_path) { + pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", + current_path->directory, filename); + if (!pathname) + return NULL; + inputfile = fopen(pathname, mode); + g_free(pathname); + if (inputfile) + return inputfile; + current_path = current_path->next; + } + } else { + inputfile = fopen(filename, mode); + if (inputfile) + return inputfile; + } + return NULL; +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) +extern FILE* mac_fopen(const char* filename, const char *mode); +#endif + +static input_data * +new_input_data(const char *filename, IncludePathEntry *include_path) +{ + input_data *new_data; + FILE *inputfile; + char *buffer = NULL; + size_t offset = 0; + size_t buffer_size; +#ifdef XP_MAC + size_t i; +#endif + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + /* on Mac, fopen knows how to find files. */ + inputfile = fopen(filename, "r"); +#elif defined(XP_OS2) || defined(XP_WIN32) + /* + * if filename is fully qualified (starts with driver letter), then + * just call fopen(); else, go with fopen_from_includes() + */ + if( filename[1] == ':' ) + inputfile = fopen(filename, "r"); + else + inputfile = fopen_from_includes(filename, "r", include_path); +#else + inputfile = fopen_from_includes(filename, "r", include_path); +#endif + + if (!inputfile) + return NULL; + +#ifdef XP_MAC + { + struct stat input_stat; + if (fstat(fileno(inputfile), &input_stat)) + return NULL; + buffer = malloc(input_stat.st_size + 1); + if (!buffer) + return NULL; + offset = fread(buffer, 1, input_stat.st_size, inputfile); + if (ferror(inputfile)) + return NULL; + } +#else + /* + * Rather than try to keep track of many different varieties of state + * around the boundaries of a circular buffer, we just read in the entire + * file. + * + * We iteratively grow the buffer here; an alternative would be to use + * stat to find the exact buffer size we need, as xpt_dump does. + */ + for (buffer_size = 8191; ; buffer_size *= 2) { + size_t just_read; + buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */ + just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile); + if (ferror(inputfile)) + return NULL; + + if (just_read < buffer_size - offset || just_read == 0) { + /* Done reading. */ + offset += just_read; + break; + } + offset += just_read; + } +#endif + + fclose(inputfile); + +#ifdef XP_MAC + /* + * libIDL doesn't speak '\r' properly - always make sure lines end with + * '\n'. + */ + for (i = 0; i < offset; i++) { + if (buffer[i] == '\r') + buffer[i] = '\n'; + } +#endif + + new_data = xpidl_malloc(sizeof (struct input_data)); + new_data->point = new_data->buf = buffer; + new_data->max = buffer + offset; + *new_data->max = '\0'; + new_data->filename = xpidl_strdup(filename); + /* libIDL expects the line number to be that of the *next* line */ + new_data->lineno = 2; + new_data->next = NULL; + + return new_data; +} + +/* process pending raw section */ +static int +NextIsRaw(input_data *data, char **startp, int *lenp) +{ + char *end, *start; + + /* + * XXXmccabe still needed: an in_raw flag to handle the case where we're in + * a raw block, but haven't managed to copy it all to xpidl. This will + * happen when we have a raw block larger than + * IDL_input_data->fill.max_size (currently 8192.) + */ + if (!(data->point[0] == '%' && data->point[1] == '{')) + return 0; + + start = *startp = data->point; + + end = NULL; + while (start < data->max && (end = strstr(start, "%}"))) { + if (end[-1] == '\r' || + end[-1] == '\n') + break; + start = end + 1; + } + + if (end && start < data->max) { + *lenp = end - data->point + 2; + return 1; + } else { + const char *filename; + int lineno; + + IDL_file_get(&filename, &lineno); + msg_callback(IDL_ERROR, 0, lineno, filename, + "unterminated %{ block"); + return -1; + } +} + +/* process pending comment */ +static int +NextIsComment(input_data *data, char **startp, int *lenp) +{ + char *end; + + if (!(data->point[0] == '/' && data->point[1] == '*')) + return 0; + + end = strstr(data->point, "*/"); + *lenp = 0; + if (end) { + int skippedLines = 0; + char *tempPoint; + + /* get current lineno */ + IDL_file_get(NULL,(int *)&data->lineno); + + /* get line count */ + for (tempPoint = data->point; tempPoint < end; tempPoint++) { + if (*tempPoint == '\n') + skippedLines++; + } + + data->lineno += skippedLines; + IDL_file_set(data->filename, (int)data->lineno); + + *startp = end + 2; + + /* If it's a ** comment, tell libIDL about it. */ + if (data->point[2] == '*') { + /* hack termination. +2 to get past '*' '/' */ + char t = *(end + 2); + *(end + 2) = '\0'; + IDL_queue_new_ident_comment(data->point); + *(end + 2) = t; + } + + data->point = *startp; /* XXXmccabe move this out of function? */ + return 1; + } else { + const char *filename; + int lineno; + + IDL_file_get(&filename, &lineno); + msg_callback(IDL_ERROR, 0, lineno, filename, + "unterminated comment"); + return -1; + } +} + +static int +NextIsInclude(input_callback_state *callback_state, char **startp, + int *lenp) +{ + input_data *data = callback_state->input_stack; + input_data *new_data; + char *filename, *end; + const char *scratch; + + /* process the #include that we're in now */ + if (strncmp(data->point, "#include \"", 10)) { + return 0; + } + + filename = data->point + 10; /* skip #include " */ + XPT_ASSERT(filename < data->max); + end = filename; + while (end < data->max) { + if (*end == '\"' || *end == '\n' || *end == '\r') + break; + end++; + } + + if (*end != '\"') { + /* + * Didn't find end of include file. Scan 'til next whitespace to find + * some reasonable approximation of the filename, and use it to report + * an error. + */ + + end = filename; + while (end < data->max) { + if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t') + break; + end++; + } + *end = '\0'; + + /* make sure we have accurate line info */ + IDL_file_get(&scratch, (int *)&data->lineno); + fprintf(stderr, + "%s:%u: didn't find end of quoted include name \"%s\n", + scratch, data->lineno, filename); + return -1; + } + + *end = '\0'; + *startp = end + 1; + + if (data->next == NULL) { + /* + * If we're in the initial file, add this filename to the list + * of filenames to be turned into #include "filename.h" + * directives in xpidl_header.c. We do it here rather than in the + * block below so it still gets added to the list even if it's + * already been recursively included from some other file. + */ + char *filename_cp = xpidl_strdup(filename); + + /* note that g_slist_append accepts and likes null as list-start. */ + callback_state->base_includes = + g_slist_append(callback_state->base_includes, filename_cp); + } + + /* store offset for when we pop, or if we skip this one */ + data->point = *startp; + + if (!g_hash_table_lookup(callback_state->already_included, filename)) { + filename = xpidl_strdup(filename); + g_hash_table_insert(callback_state->already_included, + filename, (void *)TRUE); + new_data = new_input_data(filename, callback_state->include_path); + if (!new_data) { + char *error_message; + IDL_file_get(&scratch, (int *)&data->lineno); + error_message = + g_strdup_printf("can't open included file %s for reading\n", + filename); + msg_callback(IDL_ERROR, 0, + data->lineno, scratch, error_message); + g_free(error_message); + return -1; + } + + new_data->next = data; + /* tell libIDL to exclude this IDL from the toplevel tree */ + IDL_inhibit_push(); + IDL_file_get(&scratch, (int *)&data->lineno); + callback_state->input_stack = new_data; + IDL_file_set(new_data->filename, (int)new_data->lineno); + } + + *lenp = 0; /* this is magic, see the comment below */ + return 1; +} + +static void +FindSpecial(input_data *data, char **startp, int *lenp) +{ + char *point = data->point; + + /* magic sequences are: + * "%{" raw block + * "/\*" comment + * "#include \"" include + * The first and last want a newline [\r\n] before, or the start of the + * file. + */ + +#define LINE_START(data, point) (point == data->buf || \ + (point > data->point && \ + (point[-1] == '\r' || point[-1] == '\n'))) + + while (point < data->max) { + if (point[0] == '/' && point[1] == '*') + break; + if (LINE_START(data, point)) { + if (point[0] == '%' && point[1] == '{') + break; + if (point[0] == '#' && !strncmp(point + 1, "include \"", 9)) + break; + } + point++; + } + +#undef LINE_START + + *startp = data->point; + *lenp = point - data->point; +} + +/* set this with a debugger to see exactly what libIDL sees */ +static FILE *tracefile; + +static int +input_callback(IDL_input_reason reason, union IDL_input_data *cb_data, + gpointer user_data) +{ + input_callback_state *callback_state = user_data; + input_data *data = callback_state->input_stack; + input_data *new_data = NULL; + unsigned int len, copy; + int rv; + char *start; + + switch(reason) { + case IDL_INPUT_REASON_INIT: + if (data == NULL || data->next == NULL) { + /* + * This is the first file being processed. As it's the target + * file, we only look for it in the first entry in the include + * path, which we assume to be the current directory. + */ + + /* XXXmccabe proper assumption? Do we handle files in other + directories? */ + + IncludePathEntry first_entry; + + first_entry.directory = callback_state->include_path->directory; + first_entry.next = NULL; + + new_data = new_input_data(cb_data->init.filename, + &first_entry); + } else { + new_data = new_input_data(cb_data->init.filename, + callback_state->include_path); + } + + if (!new_data) + return -1; + + IDL_file_set(new_data->filename, (int)new_data->lineno); + callback_state->input_stack = new_data; + return 0; + + case IDL_INPUT_REASON_FILL: + start = NULL; + len = 0; + + while (data->point >= data->max) { + if (!data->next) + return 0; + + /* Current file is done; revert to including file */ + callback_state->input_stack = data->next; + free(data->filename); + free(data->buf); + free(data); + data = callback_state->input_stack; + + IDL_file_set(data->filename, (int)data->lineno); + IDL_inhibit_pop(); + } + + /* + * Now we scan for sequences which require special attention: + * \n#include begins an include statement + * \n%{ begins a raw-source block + * /\* begins a comment + * + * We used to be fancier here, so make sure that we sent the most + * data possible at any given time. To that end, we skipped over + * \n%{ raw \n%} blocks and then _continued_ the search for special + * sequences like \n#include or /\* comments . + * + * It was really ugly, though -- liberal use of goto! lots of implicit + * state! what fun! -- so now we just do this: + * + * if (special at start) { + * process that special - + * - raw: send it to libIDL, and don't look inside for specials + * - comments: adjust point and start over + * - includes: push new input_data struct for included file, and + * start over + * } else { + * scan for next special + * send data up to that special to libIDL + * } + * + * If len is set to zero, it is a sentinel value indicating we a comment + * or include was found, and parsing should start over. + * + * XXX const string foo = "/\*" will just screw us horribly. + * Hm but. We could treat strings as we treat raw blocks, eh? + */ + + /* + * Order is important, so that you can have /\* comments and + * #includes within raw sections, and so that you can comment out + * #includes. + */ + rv = NextIsRaw(data, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) { + /* + * When NextIsComment succeeds, it returns a 0 len (requesting a + * restart) and adjusts data->point to pick up after the comment. + */ + rv = NextIsComment(data, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) { + /* + * NextIsInclude might push a new input_data struct; if so, it + * will return a 0 len, letting the callback pick up the new + * file the next time around. + */ + rv = NextIsInclude(callback_state, &start, (int *)&len); + if (rv == -1) return -1; + if (!rv) + FindSpecial(data, &start, (int *)&len); + } + } + + if (len == 0) { + /* + * len == 0 is a sentinel value that means we found a comment or + * include. If we found a comment, point has been adjusted to + * point past the comment. If we found an include, a new input_data + * has been pushed. In both cases, calling the input_callback again + * will pick up the new state. + */ + return input_callback(reason, cb_data, user_data); + } + + copy = MIN(len, (unsigned int) cb_data->fill.max_size); + memcpy(cb_data->fill.buffer, start, copy); + data->point = start + copy; + + if (tracefile) + fwrite(cb_data->fill.buffer, copy, 1, tracefile); + + return copy; + + case IDL_INPUT_REASON_ABORT: + case IDL_INPUT_REASON_FINISH: + while (data != NULL) { + input_data *next; + + next = data->next; + free(data->filename); + free(data->buf); + free(data); + data = next; + } + return 0; + + default: + g_error("unknown input reason %d!", reason); + return -1; + } +} + +static void +free_ghash_key(gpointer key, gpointer value, gpointer user_data) +{ + /* We're only storing TRUE in the value... */ + free(key); +} + +static void +free_gslist_data(gpointer data, gpointer user_data) +{ + free(data); +} + +/* Pick up unlink. */ +#ifdef XP_UNIX +#include +#elif XP_WIN +/* We get it from stdio.h. */ +#endif + +int +xpidl_process_idl(char *filename, IncludePathEntry *include_path, + char *file_basename, ModeData *mode) +{ + char *tmp, *outname, *real_outname = NULL; + IDL_tree top; + TreeState state; + int rv; + input_callback_state callback_state; + gboolean ok = TRUE; + backend *emitter; + + callback_state.input_stack = NULL; + callback_state.base_includes = NULL; + callback_state.include_path = include_path; + callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal); + + if (!callback_state.already_included) { + fprintf(stderr, "failed to create hashtable. out of memory?\n"); + return 0; + } + + state.basename = xpidl_strdup(filename); + + /* if basename has an .extension, truncate it. */ + tmp = strrchr(state.basename, '.'); + if (tmp) + *tmp = '\0'; + + if (!file_basename) + outname = xpidl_strdup(state.basename); + else + outname = xpidl_strdup(file_basename); + + /* so we don't include it again! */ + g_hash_table_insert(callback_state.already_included, + xpidl_strdup(filename), (void *)TRUE); + + parsed_empty_file = FALSE; + + rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state, + msg_callback, &top, + &state.ns, + IDLF_IGNORE_FORWARDS | + IDLF_XPIDL, + enable_warnings ? IDL_WARNING1 : + IDL_ERROR); + if (parsed_empty_file) { + /* + * If we've detected (via hack in msg_callback) that libIDL returned + * failure because it found a file with no IDL, set the parse tree to + * null and proceed. Allowing this is useful to permit .idl files that + * collect #includes. + */ + top = NULL; + state.ns = NULL; + } else if (rv != IDL_SUCCESS) { + if (rv == -1) { + g_warning("Parse of %s failed: %s", filename, g_strerror(errno)); + } else { + g_warning("Parse of %s failed", filename); + } + return 0; + } + + state.basename = xpidl_strdup(filename); + tmp = strrchr(state.basename, '.'); + if (tmp) + *tmp = '\0'; + + /* so xpidl_header.c can use it to generate a list of #include directives */ + state.base_includes = callback_state.base_includes; + + emitter = mode->factory(); + state.dispatch = emitter->dispatch_table; + + if (strcmp(outname, "-")) { + const char *fopen_mode; + char *out_basename; + + /* explicit_output_filename can't be true without a filename */ + if (explicit_output_filename) { + real_outname = g_strdup(outname); + } else { +/* + *This combination seems a little strange, what about OS/2? + * Assume it's some build issue + */ +#if defined(XP_UNIX) || defined(XP_WIN) + if (!file_basename) { + out_basename = xpidl_basename(outname); + } else { + out_basename = outname; + } +#else + out_basename = outname; +#endif + real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix); + if (out_basename != outname) + g_free(out_basename); + } + + /* Use binary write for typelib mode */ + fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb"; + state.file = fopen(real_outname, fopen_mode); + if (!state.file) { + perror("error opening output file"); + return 0; + } + } else { + state.file = stdout; + } + state.tree = top; +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + state.real_outname = real_outname; +#endif + + if (emitter->emit_prolog) + emitter->emit_prolog(&state); + if (state.tree) /* Only if we have a tree to process. */ + ok = xpidl_process_node(&state); + if (emitter->emit_epilog) + emitter->emit_epilog(&state); + + if (state.file != stdout) + fclose(state.file); + free(state.basename); + free(outname); + g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL); + g_hash_table_destroy(callback_state.already_included); + g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL); + + if (state.ns) + IDL_ns_free(state.ns); + if (top) + IDL_tree_free(top); + + if (real_outname != NULL) { + /* + * Delete partial output file on failure. (Mac does this in the plugin + * driver code, if the compiler returns failure.) + */ +#if defined(XP_UNIX) || defined(XP_WIN) + if (!ok) + unlink(real_outname); +#endif + g_free(real_outname); + } + + return ok; +} + +/* + * Our own version of IDL_tree_warning, which we use when IDL_tree_warning + * would crash on us. + */ +void +xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...) +{ + va_list ap; + char *msg, *file; + int lineno; + + /* XXX need to check against __IDL_max_msg_level, no accessor */ + va_start(ap, fmt); + msg = g_strdup_vprintf(fmt, ap); + + if (p) { + file = p->_file; + lineno = p->_line; + } else { + file = NULL; + lineno = 0; + } + + /* call our message callback, like IDL_tree_warning would */ + msg_callback(level, 0, lineno, file, msg); + g_free(msg); + va_end(ap); +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c new file mode 100644 index 00000000..4f708027 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_java.c @@ -0,0 +1,1053 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Sun Microsystems, + * Inc. Portions created by Sun are + * Copyright (C) 1999 Sun Microsystems, Inc. All + * Rights Reserved. + * + * Contributor(s): + * Michael Allen (michael.allen@sun.com) + * Frank Mitchell (frank.mitchell@sun.com) + */ + +/* + * Generate Java interfaces from XPIDL. + */ + +#include "xpidl.h" +#include +#include + + +struct java_priv_data { + GHashTable *typedefTable; +}; + +#define TYPEDEFS(state) (((struct java_priv_data *)state->priv)->typedefTable) + +static gboolean +write_classname_iid_define(FILE *file, const char *className) +{ + const char *iidName; + if (className[0] == 'n' && className[1] == 's') { + /* backcompat naming styles */ + fputs("NS_", file); + iidName = className + 2; + } else { + iidName = className; + } + + while (*iidName) { + fputc(toupper(*iidName++), file); + } + + fputs("_IID", file); + return TRUE; +} + +static gboolean +java_prolog(TreeState *state) +{ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + const char *basename; + const char *ext; +#endif + + state->priv = calloc(1, sizeof(struct java_priv_data)); + if (!state->priv) + return FALSE; + TYPEDEFS(state) = 0; + TYPEDEFS(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!TYPEDEFS(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + + /* + * First pass + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + basename = xpidl_basename(state->real_outname ? state->real_outname : state->basename); + ext = strrchr(basename, '.'); + if (!ext) + ext = strchr(basename, '\0'); + fprintf(state->file, + "/**\n" + " * NOTE: THIS IS A GENERATED FILE. PLEASE CONSULT THE ORIGINAL IDL FILE\n" + " * FOR THE FULL DOCUMENTATION AND LICENSE.\n" + " *\n" + " * @see \n" + " **/\n" + "\n" + "package org.mozilla.interfaces;\n\n" + "import java.math.BigInteger;\n\n" + "\n" + , ext - basename >= 19 ? 19 : (int)(ext - basename), basename); + g_free(basename); +#else + fputs("/*\n * ************* DO NOT EDIT THIS FILE ***********\n", + state->file); + + fprintf(state->file, + " *\n * This file was automatically generated from %s.idl.\n", + state->basename); + + fputs(" */\n\n", state->file); +#endif + + return TRUE; +} + +static gboolean +java_epilog(TreeState *state) +{ + /* points to other elements of the tree, so just destroy the table */ + g_hash_table_destroy(TYPEDEFS(state)); + free(state->priv); + state->priv = NULL; + +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* + * Last pass + */ + + fprintf(state->file, "\n/*\n * end\n */\n"); +#endif + + return TRUE; +} + +static gboolean +forward_declaration(TreeState *state) +{ + /* + * Java doesn't need forward declarations unless the declared + * class resides in a different package. + */ +#if 0 + IDL_tree iface = state->tree; + const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str; + const char *pkgName = "org.mozilla.xpcom"; + if (!className) + return FALSE; + /* XXX: Get package name and compare */ + fprintf(state->file, "import %s.%s;\n", pkgName, className); +#endif + return TRUE; +} + + +static gboolean +interface_declaration(TreeState *state) +{ + IDL_tree interface = state->tree; + IDL_tree iterator = NULL; + char *interface_name = IDL_IDENT(IDL_INTERFACE(interface).ident).str; + const char *iid = NULL; + + if (!verify_interface_declaration(interface)) + return FALSE; +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* + * Write out JavaDoc comment + */ + + fprintf(state->file, "\n/**\n * Interface %s\n", interface_name); +#endif + +#ifndef LIBIDL_MAJOR_VERSION + iid = IDL_tree_property_get(interface, "uuid"); +#else + iid = IDL_tree_property_get(IDL_INTERFACE(interface).ident, "uuid"); +#endif + +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + if (iid != NULL) { + fprintf(state->file, " *\n * IID: 0x%s\n */\n\n", iid); + } else { + fputs(" */\n\n", state->file); + } +#endif + + /* + * Write "public interface " + */ + + fprintf(state->file, "public interface %s ", interface_name); + + /* + * Check for inheritence, and iterator over the inherited names, + * if any. + */ + + if ((iterator = IDL_INTERFACE(interface).inheritance_spec)) { + fputs("extends ", state->file); + + do { + + fprintf(state->file, "%s", + IDL_IDENT(IDL_LIST(iterator).data).str); + + if (IDL_LIST(iterator).next) { + fputs(", ", state->file); + } + } while ((iterator = IDL_LIST(iterator).next)); + + } + + fputs("\n{\n", state->file); + + if (iid) { + /* + * Write interface constants for IID + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" public static final String ", state->file); +#else + fputs(" public static final String ", state->file); +#endif + + /* XXX s.b just "IID" ? */ + if (!write_classname_iid_define(state->file, interface_name)) { + return FALSE; + } + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs(" =\n \"{", state->file); + while (*iid) { + fputc(tolower(*iid++), state->file); + } + fputs("}\";\n", state->file); + +#else + fprintf(state->file, "_STRING =\n \"%s\";\n\n", iid); + + fputs(" public static final nsID ", state->file); + + /* XXX s.b just "IID" ? */ + if (!write_classname_iid_define(state->file, interface_name)) { + return FALSE; + } + + fprintf(state->file, " =\n new nsID(\"%s\");\n\n", iid); +#endif + } + + /* + * Advance the state of the tree, go on to process more + */ + + state->tree = IDL_INTERFACE(interface).body; + + if (state->tree && !xpidl_process_node(state)) { + return FALSE; + } + + + fputs("\n}\n", state->file); + + return TRUE; +} + +static gboolean +process_list(TreeState *state) +{ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + /* To make the diffing simple, group the constants, methods and attributes. */ + IDL_tree list = state->tree; + IDL_tree iter; + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_CONST_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_ATTR_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if (IDL_NODE_TYPE(IDL_LIST(iter).data) == IDLN_OP_DCL) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + for (iter = list; iter; iter = IDL_LIST(iter).next) { + if ( IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_CONST_DCL + && IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_OP_DCL + && IDL_NODE_TYPE(IDL_LIST(iter).data) != IDLN_ATTR_DCL ) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + } + +#else + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } +#endif + return TRUE; +} + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +static gboolean +interface_declaration_wrapper(TreeState *state) +{ + IDL_tree interface = state->tree; + char *interface_name = IDL_IDENT(IDL_INTERFACE(interface).ident).str; + FILE *org_file = state->file; + char *org_name = state->real_outname; + void *org_priv = state->priv; + gboolean rc; + + /* + * Skip non-scriptable interfaces. + */ + if ( !IDL_tree_property_get(IDL_INTERFACE(interface).ident, "scriptable") + && strcmp(interface_name, "nsIAppShell") ) + return TRUE; + + /* + * GROSS HACK: If the interface isn't the same as the file name, + * temporarily switch output file. + */ + if (state->real_outname) { + const char *basename = xpidl_basename(state->real_outname); + const char *ext = strrchr(basename, '.'); + if ( ext + && !strcmp(ext, ".java") + && ( strncmp(interface_name, basename, ext - basename) + || interface_name[ext - basename] != '.') ) { + size_t needed = strlen(state->real_outname) + strlen(interface_name) + strlen(".java") + 4; + char *tmp = malloc(needed); + if (basename != state->real_outname) + sprintf(tmp,"%.*s/%s.java", (int)(basename - state->real_outname - 1), state->real_outname, interface_name); + else + sprintf(tmp,"%s.java", interface_name); + state->file = fopen(tmp, "w"); + if (!state->file) { + perror("error opening output file"); + state->file = org_file; + free(tmp); + return FALSE; + } + state->real_outname = tmp; + java_prolog(state); + } + g_free(basename); + } + + rc = interface_declaration(state); + + if (state->file != org_file) { + java_epilog(state); + fclose(state->file); + free(state->real_outname); + state->file = org_file; + state->real_outname = org_name; + state->priv = org_priv; + } + return rc; +} +#endif /* VBOX_XPIDL_EMULATE_GENJIFACES */ + +static gboolean +xpcom_to_java_type (TreeState *state) +{ + if (!state->tree) { + fputs("Object", state->file); + return TRUE; + } + + switch(IDL_NODE_TYPE(state->tree)) { + + case IDLN_TYPE_INTEGER: { + + switch(IDL_TYPE_INTEGER(state->tree).f_type) { + + case IDL_INTEGER_TYPE_SHORT: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("short", state->file); + else + fputs("int", state->file); +#else + fputs("short", state->file); +#endif + break; + + case IDL_INTEGER_TYPE_LONG: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("int", state->file); + else + fputs("long", state->file); +#else + fputs("int", state->file); +#endif + break; + + case IDL_INTEGER_TYPE_LONGLONG: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_TYPE_INTEGER(state->tree).f_signed) + fputs("long", state->file); + else + fputs("double", state->file); +#else + fputs("long", state->file); +#endif + break; + + default: + g_error(" Unknown integer type: %d\n", + IDL_TYPE_INTEGER(state->tree).f_type); + return FALSE; + + } + + break; + } + + case IDLN_TYPE_CHAR: + case IDLN_TYPE_WIDE_CHAR: + fputs("char", state->file); + break; + + case IDLN_TYPE_WIDE_STRING: + case IDLN_TYPE_STRING: + fputs("String", state->file); + break; + + case IDLN_TYPE_BOOLEAN: + fputs("boolean", state->file); + break; + + case IDLN_TYPE_OCTET: +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("short", state->file); +#else + fputs("byte", state->file); +#endif + break; + + case IDLN_TYPE_FLOAT: + switch(IDL_TYPE_FLOAT(state->tree).f_type) { + + case IDL_FLOAT_TYPE_FLOAT: + fputs("float", state->file); + break; + + case IDL_FLOAT_TYPE_DOUBLE: + fputs("double", state->file); + break; + + default: + g_error(" Unknown floating point typ: %d\n", + IDL_NODE_TYPE(state->tree)); + break; + } + break; + + + case IDLN_IDENT: + if (IDL_NODE_UP(state->tree) && + IDL_NODE_TYPE(IDL_NODE_UP(state->tree)) == IDLN_NATIVE) { + const char *user_type = IDL_NATIVE(IDL_NODE_UP(state->tree)).user_type; + if (strcmp(user_type, "void") == 0) { +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("nsISupports", state->file); +#else + fputs("Object", state->file); +#endif + } + else if (strcmp(user_type, "nsID") == 0 || + strcmp(user_type, "nsIID") == 0 || + strcmp(user_type, "nsCID") == 0) { + /* XXX: s.b test for "iid" attribute */ + /* XXX: special class for nsIDs */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("String", state->file); +#else + fputs("nsID", state->file); +#endif + } + else { + /* XXX: special class for opaque types */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + fputs("String", state->file); +#else + fputs("OpaqueValue", state->file); +#endif + } + } else { + const char *ident_str = IDL_IDENT(state->tree).str; + + /* XXX: big kludge; s.b. way to match to typedefs */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (strcmp(ident_str, "PRInt8") == 0) { + fputs("byte", state->file); + } + else if (strcmp(ident_str, "PRInt16") == 0 || + strcmp(ident_str, "PRUint8") == 0) { + fputs("short", state->file); + } + else if (strcmp(ident_str, "PRInt32") == 0 || + strcmp(ident_str, "PRUint16") == 0) { + fputs("int", state->file); + } + else if (strcmp(ident_str, "PRInt64") == 0 || + strcmp(ident_str, "PRUint32") == 0 || + strcmp(ident_str, "PRThreadPriority") == 0 || + strcmp(ident_str, "PRThreadScope") == 0 || + strcmp(ident_str, "PRThreadState") == 0) { + fputs("long", state->file); + } + else if (strcmp(ident_str, "PRUint64") == 0) { + fputs("double", state->file); + } +#else + if (strcmp(ident_str, "PRInt8") == 0 || + strcmp(ident_str, "PRUint8") == 0) { + fputs("byte", state->file); + } + else if (strcmp(ident_str, "PRInt16") == 0 || + strcmp(ident_str, "PRUint16") == 0) { + fputs("short", state->file); + } + else if (strcmp(ident_str, "PRInt32") == 0 || + strcmp(ident_str, "PRUint32") == 0) { + fputs("int", state->file); + } + else if (strcmp(ident_str, "PRInt64") == 0 || + strcmp(ident_str, "PRUint64") == 0) { + fputs("long", state->file); + } +#endif + else if (strcmp(ident_str, "PRBool") == 0) { + fputs("boolean", state->file); + } + else if (strcmp(ident_str, "nsrefcnt") == 0) { + fputs("int", state->file); + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* XXX: Use find_underlying_type instead? */ + else if ( strcmp(ident_str, "nsresult") == 0 + || strcmp(ident_str, "size_t") == 0) { + fputs("long", state->file); + } + else if ( strcmp(ident_str, "PRTime") == 0) { + fputs("double", state->file); + } + /* In Javaconnect, we handle weak references internally; no need for the + |nsIWeakReference| interface. So just return |nsISupports|. */ + else if (strcmp(ident_str, "nsIWeakReference") == 0) { + fputs("nsISupports", state->file); + } +#endif + else { + IDL_tree real_type = + g_hash_table_lookup(TYPEDEFS(state), ident_str); + + if (real_type) { + IDL_tree orig_tree = state->tree; + + state->tree = real_type; + xpcom_to_java_type(state); + + state->tree = orig_tree; + } + else { + fputs(ident_str, state->file); + } + } + } + + break; + + case IDLN_TYPE_ENUM: + case IDLN_TYPE_OBJECT: + default: + g_error(" Unknown type: %d\n", + IDL_TYPE_FLOAT(state->tree).f_type); + break; + } + + return TRUE; + +} + +static gboolean +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF +xpcom_to_java_param(TreeState *state, unsigned nparam) +#else +xpcom_to_java_param(TreeState *state) +#endif +{ + IDL_tree param = state->tree; + state->tree = IDL_PARAM_DCL(param).param_type_spec; + + /* + * Put in type of parameter + */ + + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * If the parameter is out or inout, make it a Java array of the + * appropriate type + */ + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* XXX: Causes nsILineInputStream::readLine(String[] arg1) where genjifaces drops the []. */ +#endif + if (IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) { + fputs("[]", state->file); + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /*XXX: nsIConsoleService::getMessageArray ends up with [][] arg1... */ + /*else*/ if (IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array")) { + fputs("[]", state->file); + } +#endif + + /* + * Put in name of parameter + */ + + fputc(' ', state->file); + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fprintf(state->file, "arg%u", nparam+1); +#else + fputs(IDL_IDENT(IDL_PARAM_DCL(param).simple_declarator).str, state->file); +#endif + + return TRUE; +} + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +static gboolean is_java_keyword(char ch0, const char *name) +{ + static const char * const kJavaKeywords[] = { + "abstract", "default", "if" , "private" , "this" , + "boolean" , "do" , "implements", "protected" , "throw" , + "break" , "double" , "import", "public" , "throws" , + "byte" , "else" , "instanceof", "return" , "transient", + "case" , "extends", "int" , "short" , "try" , + "catch" , "final" , "interface" , "static" , "void" , + "char" , "finally", "long" , "strictfp" , "volatile" , + "class" , "float" , "native" , "super" , "while" , + "const" , "for" , "new" , "switch" , + "continue", "goto" , "package" , "synchronized", + "assert" , /* added in Java 1.4 */ + "enum" , /* added in Java 5.0 */ + "clone" , /* clone is a member function of java.lang.Object */ + "finalize" /* finalize is a member function of java.lang.Object */ + }; + unsigned i; + for (i = 0; i < sizeof(kJavaKeywords) / sizeof(kJavaKeywords[0]); i++) { + if (kJavaKeywords[i][0] == ch0 && !strcmp(&kJavaKeywords[i][1], &name[1])) { + return TRUE; + } + } + return FALSE; +} +#endif + +static gboolean +type_declaration(TreeState *state) +{ + /* + * Unlike C, Java has no type declaration directive. + * Instead, we record the mapping, and look up the actual type + * when needed. + */ + IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec; + IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls; + + /* XXX: check for illegal types */ + + g_hash_table_insert(TYPEDEFS(state), + IDL_IDENT(IDL_LIST(dcls).data).str, + type); + + return TRUE; +} + +static gboolean +method_declaration(TreeState *state) +{ + /* IDL_tree method_tree = state->tree; */ + struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree); + gboolean method_notxpcom = + (IDL_tree_property_get(method->ident, "notxpcom") != NULL); + gboolean method_noscript = + (IDL_tree_property_get(method->ident, "noscript") != NULL); + IDL_tree iterator = NULL; + IDL_tree retval_param = NULL; + const char *method_name = IDL_IDENT(method->ident).str; +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + unsigned nparam = 0; +#endif + + if (!verify_method_declaration(state->tree)) + return FALSE; + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* + * Skip most (todo) non-scriptable and not-xpcom methods. + */ + if (method_noscript || method_notxpcom) { + return TRUE; + } +#endif + + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + + /* + * Write beginning of method declaration + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + /* Nonscriptable methods become package-protected */ + fputs("public ", state->file); + } + + /* + * Write return type + * Unlike C++ headers, Java interfaces return the declared + * return value; an exception indicates XPCOM method failure. + */ + if (method_notxpcom || method->op_type_spec) { + state->tree = method->op_type_spec; + if (!xpcom_to_java_type(state)) { + return FALSE; + } + } else { + /* Check for retval attribute */ + for (iterator = method->parameter_dcls; iterator != NULL; + iterator = IDL_LIST(iterator).next) { + + IDL_tree original_tree = state->tree; + + state->tree = IDL_LIST(iterator).data; + + if (IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "retval")) { + retval_param = iterator; + + state->tree = IDL_PARAM_DCL(state->tree).param_type_spec; + + /* + * Put in type of parameter + */ + + if (!xpcom_to_java_type(state)) { + return FALSE; + } +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (IDL_tree_property_get(IDL_PARAM_DCL(IDL_LIST(iterator).data).simple_declarator, "array")) { + fputs("[]", state->file); + } +#endif + } + + state->tree = original_tree; + } + + if (retval_param == NULL) { + fputs("void", state->file); + } + } + + /* + * Write method name + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + if (is_java_keyword(tolower(method_name[0]), method_name)) { + fprintf(state->file, " %c%s_(", tolower(method_name[0]), method_name + 1); + } else { + fprintf(state->file, " %c%s(", tolower(method_name[0]), method_name + 1); + } +#else + fprintf(state->file, " %c%s(", tolower(method_name[0]), method_name + 1); +#endif + + /* + * Write parameters + */ + for (iterator = method->parameter_dcls; iterator != NULL; + iterator = IDL_LIST(iterator).next) { + + /* Skip "retval" */ + if (iterator == retval_param) { + continue; + } + + if (iterator != method->parameter_dcls) { + fputs(", ", state->file); + } + + state->tree = IDL_LIST(iterator).data; + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + if (!xpcom_to_java_param(state, nparam++)) { +#else + if (!xpcom_to_java_param(state)) { +#endif + return FALSE; + } + } + + fputs(")", state->file); + + if (method->raises_expr) { + IDL_tree iter = method->raises_expr; + IDL_tree dataNode = IDL_LIST(iter).data; + + fputs(" throws ", state->file); + fputs(IDL_IDENT(dataNode).str, state->file); + iter = IDL_LIST(iter).next; + + while (iter) { + dataNode = IDL_LIST(iter).data; + fprintf(state->file, ", %s", IDL_IDENT(dataNode).str); + iter = IDL_LIST(iter).next; + } + } + + fputs(";\n", state->file); + + return TRUE; + +} + + +static gboolean +constant_declaration(TreeState *state) +{ + struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(declaration->ident).str; + IDL_tree real_type; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(declaration->const_type); + real_type = real_type ? real_type : declaration->const_type; + + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES +# ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" public static final ", state->file); +# else + fputs(" public static final ", state->file); +# endif + if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG) { + if (IDL_TYPE_INTEGER(real_type).f_signed) + fprintf(state->file, "int %s = %" IDL_LL "d;\n", name, IDL_INTEGER(declaration->const_exp).value); + else + fprintf(state->file, "long %s = %" IDL_LL "uL;\n", name, IDL_INTEGER(declaration->const_exp).value); + } else { + if (IDL_TYPE_INTEGER(real_type).f_signed) + fprintf(state->file, "short %s = %" IDL_LL "d;\n", name, IDL_INTEGER(declaration->const_exp).value); + else + fprintf(state->file, "int %s = %" IDL_LL "u;\n", name, IDL_INTEGER(declaration->const_exp).value); + } +#else /* !VBOX_XPIDL_EMULATE_GENJIFACES */ + fprintf(state->file, " public static final %s %s = %d;\n", + (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG + ? "long" : "short"), + name, (int) IDL_INTEGER(declaration->const_exp).value); +#endif /* !VBOX_XPIDL_EMULATE_GENJIFACES */ + + return TRUE; + +} + +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data)) +#define ATTR_PROPS(tree) (IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL((tree)).param_type_spec) + + +static gboolean +attribute_declaration(TreeState *state) +{ + gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly; + char *attribute_name = ATTR_IDENT(state->tree).str; + + gboolean method_noscript = + (IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") != NULL); + +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + /* + * Skip most non-scriptable attributes. + */ + if (method_noscript) { + return TRUE; + } +#endif + +#if 0 + /* + * Disabled here because I can't verify this check against possible + * users of the java xpidl backend. + */ + if (!verify_attribute_declaration(state->tree)) + return FALSE; +#endif + + /* Comment */ + fputc('\n', state->file); +#ifndef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + xpidl_write_comment(state, 4); +#endif + + state->tree = ATTR_TYPE_DECL(state->tree); + + /* + * Write access permission ("public" unless nonscriptable) + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + fputs("public ", state->file); + } + + /* + * Write the proper Java return value for the get operation + */ + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * Write the name of the accessor ("get") method. + */ + fprintf(state->file, " get%c%s();\n", + toupper(attribute_name[0]), attribute_name + 1); + + + if (!read_only) { + /* Nonscriptable methods become package-protected */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs("\n ", state->file); +#else + fputs(" ", state->file); +#endif + if (!method_noscript) { + fputs("public ", state->file); + } + + /* + * Write attribute access method name and return type + */ + fprintf(state->file, "void set%c%s(", + toupper(attribute_name[0]), + attribute_name+1); + + /* + * Write the proper Java type for the set operation + */ + if (!xpcom_to_java_type(state)) { + return FALSE; + } + + /* + * Write the name of the formal parameter. + */ +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES_DIFF + fputs(" arg1);\n", state->file); +#else + fputs(" value);\n", state->file); +#endif + } + + return TRUE; +} + + +static gboolean +enum_declaration(TreeState *state) +{ + XPIDL_WARNING((state->tree, IDL_WARNING1, + "enums not supported, enum \'%s\' ignored", + IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str)); + return TRUE; +} + +backend * +xpidl_java_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = java_prolog; + result.emit_epilog = java_epilog; + + if (!initialized) { +#ifdef VBOX_XPIDL_EMULATE_GENJIFACES + table[IDLN_INTERFACE] = interface_declaration_wrapper; +#else + table[IDLN_INTERFACE] = interface_declaration; +#endif + table[IDLN_LIST] = process_list; + + table[IDLN_OP_DCL] = method_declaration; + table[IDLN_ATTR_DCL] = attribute_declaration; + table[IDLN_CONST_DCL] = constant_declaration; + + table[IDLN_TYPE_DCL] = type_declaration; + table[IDLN_FORWARD_DCL] = forward_declaration; + + table[IDLN_TYPE_ENUM] = enum_declaration; + + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c new file mode 100644 index 00000000..f2daae0d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_typelib.c @@ -0,0 +1,1237 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Generate typelib files for use with InterfaceInfo. + * http://www.mozilla.org/scriptable/typelib_file.html + */ + +#include "xpidl.h" +#include +#include +#include /* XXX XP? */ + +struct priv_data { + XPTHeader *header; + uint16 ifaces; + GHashTable *interface_map; + XPTInterfaceDescriptor *current; + XPTArena *arena; + uint16 next_method; + uint16 next_const; + uint16 next_type; /* used for 'additional_types' for idl arrays */ +}; + +#define HEADER(state) (((struct priv_data *)state->priv)->header) +#define IFACES(state) (((struct priv_data *)state->priv)->ifaces) +#define IFACE_MAP(state) (((struct priv_data *)state->priv)->interface_map) +#define CURRENT(state) (((struct priv_data *)state->priv)->current) +#define ARENA(state) (((struct priv_data *)state->priv)->arena) +#define NEXT_METH(state) (((struct priv_data *)state->priv)->next_method) +#define NEXT_CONST(state) (((struct priv_data *)state->priv)->next_const) +#define NEXT_TYPE(state) (((struct priv_data *)state->priv)->next_type) + +#ifdef DEBUG_shaver +/* #define DEBUG_shaver_sort */ +#endif + +typedef struct { + char *full_name; + char *name; + char *name_space; + char *iid; + gboolean is_forward_dcl; +} NewInterfaceHolder; + +static NewInterfaceHolder* +CreateNewInterfaceHolder(char *name, char *name_space, char *iid, + gboolean is_forward_dcl) +{ + NewInterfaceHolder *holder = calloc(1, sizeof(NewInterfaceHolder)); + if (holder) { + holder->is_forward_dcl = is_forward_dcl; + if (name) + holder->name = xpidl_strdup(name); + if (name_space) + holder->name_space = xpidl_strdup(name_space); + if (holder->name && holder->name_space) { + holder->full_name = calloc(1, strlen(holder->name) + + strlen(holder->name_space) + 2); + } + if (holder->full_name) { + strcpy(holder->full_name, holder->name_space); + strcat(holder->full_name, "."); + strcat(holder->full_name, holder->name); + } + else + holder->full_name = holder->name; + if (iid) + holder->iid = xpidl_strdup(iid); + } + return holder; +} + +static void +DeleteNewInterfaceHolder(NewInterfaceHolder *holder) +{ + if (holder) { + if (holder->full_name && holder->full_name != holder->name) + free(holder->full_name); + if (holder->name) + free(holder->name); + if (holder->name_space) + free(holder->name_space); + if (holder->iid) + free(holder->iid); + free(holder); + } +} + +/* + * If p is an ident for an interface, and we don't have an entry in the + * interface map yet, add one. + */ +static gboolean +add_interface_maybe(IDL_tree_func_data *tfd, gpointer user_data) +{ + TreeState *state = user_data; + IDL_tree up; + if (IDL_NODE_TYPE(tfd->tree) == IDLN_IDENT) { + IDL_tree_type node_type = IDL_NODE_TYPE((up = IDL_NODE_UP(tfd->tree))); + if (node_type == IDLN_INTERFACE || node_type == IDLN_FORWARD_DCL) { + + /* We only want to add a new entry if there is no entry by this + * name or if the previously found entry was just a forward + * declaration and the new entry is not. + */ + + char *iface = IDL_IDENT(tfd->tree).str; + NewInterfaceHolder *old_holder = (NewInterfaceHolder *) + g_hash_table_lookup(IFACE_MAP(state), iface); + if (old_holder && old_holder->is_forward_dcl && + node_type != IDLN_FORWARD_DCL) + { + g_hash_table_remove(IFACE_MAP(state), iface); + DeleteNewInterfaceHolder(old_holder); + old_holder = NULL; + } + if (!old_holder) { + /* XXX should we parse here and store a struct nsID *? */ + char *iid = (char *)IDL_tree_property_get(tfd->tree, "uuid"); + char *name_space = (char *) + IDL_tree_property_get(tfd->tree, "namespace"); + NewInterfaceHolder *holder = + CreateNewInterfaceHolder(iface, name_space, iid, + (gboolean) node_type == IDLN_FORWARD_DCL); + if (!holder) + return FALSE; + g_hash_table_insert(IFACE_MAP(state), + holder->full_name, holder); + IFACES(state)++; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "adding interface #%d: %s/%s\n", IFACES(state), + iface, iid[0] ? iid : ""); +#endif + } + } else { +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "ident %s isn't an interface (%s)\n", + IDL_IDENT(tfd->tree).str, IDL_NODE_TYPE_NAME(up)); +#endif + } + } + + return TRUE; +} + +/* Find all the interfaces referenced in the tree (uses add_interface_maybe) */ +static gboolean +find_interfaces(IDL_tree_func_data *tfd, gpointer user_data) +{ + IDL_tree node = NULL; + + switch (IDL_NODE_TYPE(tfd->tree)) { + case IDLN_ATTR_DCL: + node = IDL_ATTR_DCL(tfd->tree).param_type_spec; + break; + case IDLN_OP_DCL: + IDL_tree_walk_in_order(IDL_OP_DCL(tfd->tree).parameter_dcls, find_interfaces, + user_data); + node = IDL_OP_DCL(tfd->tree).op_type_spec; + break; + case IDLN_PARAM_DCL: + node = IDL_PARAM_DCL(tfd->tree).param_type_spec; + break; + case IDLN_INTERFACE: + node = IDL_INTERFACE(tfd->tree).inheritance_spec; + if (node) + xpidl_list_foreach(node, add_interface_maybe, user_data); + node = IDL_INTERFACE(tfd->tree).ident; + break; + case IDLN_FORWARD_DCL: + node = IDL_FORWARD_DCL(tfd->tree).ident; + break; + default: + node = NULL; + } + + if (node && IDL_NODE_TYPE(node) == IDLN_IDENT) { + IDL_tree_func_data new_tfd; + new_tfd.tree = node; + add_interface_maybe(&new_tfd, user_data); + } + + return TRUE; +} + +#ifdef DEBUG_shaver +/* for calling from gdb */ +static void +print_IID(struct nsID *iid, FILE *file) +{ + char iid_buf[UUID_LENGTH]; + + xpidl_sprint_iid(iid, iid_buf); + fprintf(file, "%s\n", iid_buf); +} +#endif + +/* fill the interface_directory IDE table from the interface_map */ +static gboolean +fill_ide_table(gpointer key, gpointer value, gpointer user_data) +{ + TreeState *state = user_data; + NewInterfaceHolder *holder = (NewInterfaceHolder *) value; + struct nsID id; + XPTInterfaceDirectoryEntry *ide; + + XPT_ASSERT(holder); + +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "filling %s\n", holder->full_name); +#endif + + if (holder->iid) { + if (strlen(holder->iid) != 36) { + IDL_tree_error(state->tree, "IID %s is the wrong length\n", + holder->iid); + return FALSE; + } + if (!xpidl_parse_iid(&id, holder->iid)) { + IDL_tree_error(state->tree, "cannot parse IID %s\n", holder->iid); + return FALSE; + } + } else { + memset(&id, 0, sizeof(id)); + } + + ide = &(HEADER(state)->interface_directory[IFACES(state)]); + if (!XPT_FillInterfaceDirectoryEntry(ARENA(state), ide, &id, holder->name, + holder->name_space, NULL)) { + IDL_tree_error(state->tree, "INTERNAL: XPT_FillIDE failed for %s\n", + holder->full_name); + return FALSE; + } + + IFACES(state)++; + DeleteNewInterfaceHolder(holder); + return TRUE; +} + +static int +compare_IDEs(const void *ap, const void *bp) +{ + const XPTInterfaceDirectoryEntry *a = ap, *b = bp; + const nsID *aid = &a->iid, *bid = &b->iid; + const char *ans, *bns; + + int i; +#define COMPARE(field) if (aid->field > bid->field) return 1; \ + if (bid->field > aid->field) return -1; + COMPARE(m0); + COMPARE(m1); + COMPARE(m2); + for (i = 0; i < 8; i++) { + COMPARE(m3[i]); + } + + /* defend against NULL name_space by using empty string. */ + ans = a->name_space ? a->name_space : ""; + bns = b->name_space ? b->name_space : ""; + + if (a->name_space && b->name_space) { + if ((i = strcmp(a->name_space, b->name_space))) + return i; + } else { + if (a->name_space || b->name_space) { + if (a->name_space) + return -1; + return 1; + } + } + /* these had better not be NULL... */ + return strcmp(a->name, b->name); +#undef COMPARE +} + +/* sort the IDE block as per the typelib spec: IID order, unresolved first */ +static void +sort_ide_block(TreeState *state) +{ + XPTInterfaceDirectoryEntry *ide; + int i; + + /* boy, I sure hope qsort works correctly everywhere */ +#ifdef DEBUG_shaver_sort + fputs("before sort:\n", stderr); + for (i = 0; i < IFACES(state); i++) { + fputs(" ", stderr); + print_IID(&HEADER(state)->interface_directory[i].iid, stderr); + fputc('\n', stderr); + } +#endif + qsort(HEADER(state)->interface_directory, IFACES(state), + sizeof(*ide), compare_IDEs); +#ifdef DEBUG_shaver_sort + fputs("after sort:\n", stderr); + for (i = 0; i < IFACES(state); i++) { + fputs(" ", stderr); + print_IID(&HEADER(state)->interface_directory[i].iid, stderr); + fputc('\n', stderr); + } +#endif + + for (i = 0; i < IFACES(state); i++) { + ide = HEADER(state)->interface_directory + i; + g_hash_table_insert(IFACE_MAP(state), ide->name, (void *)(i + 1)); + } + + return; +} + +static gboolean +typelib_list(TreeState *state) +{ + IDL_tree iter; + for (iter = state->tree; iter; iter = IDL_LIST(iter).next) { + state->tree = IDL_LIST(iter).data; + if (!xpidl_process_node(state)) + return FALSE; + } + return TRUE; +} + +static gboolean +typelib_prolog(TreeState *state) +{ + state->priv = calloc(1, sizeof(struct priv_data)); + if (!state->priv) + return FALSE; + IFACES(state) = 0; + IFACE_MAP(state) = g_hash_table_new(g_str_hash, g_str_equal); + if (!IFACE_MAP(state)) { + /* XXX report error */ + free(state->priv); + return FALSE; + } + /* find all interfaces, top-level and referenced by others */ + IDL_tree_walk_in_order(state->tree, find_interfaces, state); + ARENA(state) = XPT_NewArena(1024, sizeof(double), "main xpidl arena"); + HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state), + major_version, minor_version); + + /* fill IDEs from hash table */ + IFACES(state) = 0; + g_hash_table_foreach_remove(IFACE_MAP(state), fill_ide_table, state); + + /* if any are left then we must have failed in fill_ide_table */ + if (g_hash_table_size(IFACE_MAP(state))) + return FALSE; + + /* sort the IDEs by IID order and store indices in the interface map */ + sort_ide_block(state); + + return TRUE; +} + +static gboolean +typelib_epilog(TreeState *state) +{ + XPTState *xstate = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + XPTCursor curs, *cursor = &curs; + PRUint32 i, len, header_sz; + PRUint32 oldOffset; + PRUint32 newOffset; + char *data; + + /* Write any annotations */ + if (emit_typelib_annotations) { + PRUint32 annotation_len, written_so_far; + char *annotate_val, *timestr; + time_t now; + static char *annotation_format = + "Created from %s.idl\nCreation date: %sInterfaces:"; + + /* fill in the annotations, listing resolved interfaces in order */ + + (void)time(&now); + timestr = ctime(&now); + + /* Avoid dependence on nspr; no PR_smprintf and friends. */ + + /* How large should the annotation string be? */ + annotation_len = strlen(annotation_format) + strlen(state->basename) + + strlen(timestr); +#ifdef VBOX + /* note that '%s' is contained two times in annotation_format and both + * format specifiers are replaced by a string. So in fact we reserve 4 + * bytes minus one byte (for the terminating '\0') more than necessary. */ +#endif + for (i = 0; i < HEADER(state)->num_interfaces; i++) { + XPTInterfaceDirectoryEntry *ide; + ide = &HEADER(state)->interface_directory[i]; + if (ide->interface_descriptor) { + annotation_len += strlen(ide->name) + 1; + } + } + + annotate_val = (char *) malloc(annotation_len); + written_so_far = sprintf(annotate_val, annotation_format, + state->basename, timestr); + + for (i = 0; i < HEADER(state)->num_interfaces; i++) { + XPTInterfaceDirectoryEntry *ide; + ide = &HEADER(state)->interface_directory[i]; + if (ide->interface_descriptor) { + written_so_far += sprintf(annotate_val + written_so_far, " %s", + ide->name); + } + } + + HEADER(state)->annotations = + XPT_NewAnnotation(ARENA(state), + XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ(ARENA(state), "xpidl 0.99.9"), + XPT_NewStringZ(ARENA(state), annotate_val)); + free(annotate_val); + } else { + HEADER(state)->annotations = + XPT_NewAnnotation(ARENA(state), XPT_ANN_LAST, NULL, NULL); + } + + if (!HEADER(state)->annotations) { + /* XXX report out of memory error */ + return FALSE; + } + + /* Write the typelib */ + header_sz = XPT_SizeOfHeaderBlock(HEADER(state)); + + if (!xstate || + !XPT_MakeCursor(xstate, XPT_HEADER, header_sz, cursor)) + goto destroy_header; + oldOffset = cursor->offset; + if (!XPT_DoHeader(ARENA(state), cursor, &HEADER(state))) + goto destroy; + newOffset = cursor->offset; + XPT_GetXDRDataLength(xstate, XPT_HEADER, &len); + HEADER(state)->file_length = len; + XPT_GetXDRDataLength(xstate, XPT_DATA, &len); + HEADER(state)->file_length += len; + XPT_SeekTo(cursor, oldOffset); + if (!XPT_DoHeaderPrologue(ARENA(state), cursor, &HEADER(state), NULL)) + goto destroy; + XPT_SeekTo(cursor, newOffset); + XPT_GetXDRData(xstate, XPT_HEADER, &data, &len); + fwrite(data, len, 1, state->file); + XPT_GetXDRData(xstate, XPT_DATA, &data, &len); + fwrite(data, len, 1, state->file); + + destroy: + XPT_DestroyXDRState(xstate); + destroy_header: + /* XXX XPT_DestroyHeader(HEADER(state)) */ + + XPT_FreeHeader(ARENA(state), HEADER(state)); + XPT_DestroyArena(ARENA(state)); + + /* XXX should destroy priv_data here */ + + return TRUE; +} + +static XPTInterfaceDirectoryEntry * +FindInterfaceByName(XPTInterfaceDirectoryEntry *ides, uint16 num_interfaces, + const char *name) +{ + uint16 i; + for (i = 0; i < num_interfaces; i++) { + if (!strcmp(ides[i].name, name)) + return &ides[i]; + } + return NULL; +} + +static gboolean +typelib_interface(TreeState *state) +{ + IDL_tree iface = state->tree, iter; + char *name = IDL_IDENT(IDL_INTERFACE(iface).ident).str; + XPTInterfaceDirectoryEntry *ide; + XPTInterfaceDescriptor *id; + uint16 parent_id = 0; + PRUint8 interface_flags = 0; + + if (!verify_interface_declaration(iface)) + return FALSE; + + if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable")) + interface_flags |= XPT_ID_SCRIPTABLE; + + if (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "function")) + interface_flags |= XPT_ID_FUNCTION; + + ide = FindInterfaceByName(HEADER(state)->interface_directory, + HEADER(state)->num_interfaces, name); + if (!ide) { + IDL_tree_error(iface, "ERROR: didn't find interface %s in " + "IDE block. Giving up.\n", name); + return FALSE; + } + + if ((iter = IDL_INTERFACE(iface).inheritance_spec)) { + char *parent; + if (IDL_LIST(iter).next) { + IDL_tree_error(iface, + "ERROR: more than one parent interface for %s\n", + name); + return FALSE; + } + parent = IDL_IDENT(IDL_LIST(iter).data).str; + parent_id = (uint16)(uint32)g_hash_table_lookup(IFACE_MAP(state), + parent); + if (!parent_id) { + IDL_tree_error(iface, + "ERROR: no index found for %s. Giving up.\n", + parent); + return FALSE; + } + } + + id = XPT_NewInterfaceDescriptor(ARENA(state), parent_id, 0, 0, + interface_flags); + if (!id) + return FALSE; + + CURRENT(state) = ide->interface_descriptor = id; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "DBG: starting interface %s @ %p\n", name, id); +#endif + + NEXT_METH(state) = 0; + NEXT_CONST(state) = 0; + NEXT_TYPE(state) = 0; + + state->tree = IDL_INTERFACE(iface).body; + if (state->tree && !xpidl_process_node(state)) + return FALSE; +#ifdef DEBUG_shaver_ifaces + fprintf(stderr, "DBG: ending interface %s\n", name); +#endif + return TRUE; +} + +static gboolean +find_arg_with_name(TreeState *state, const char *name, int16 *argnum) +{ + int16 count; + IDL_tree params; + + XPT_ASSERT(state); + XPT_ASSERT(name); + XPT_ASSERT(argnum); + + params = IDL_OP_DCL(IDL_NODE_UP(IDL_NODE_UP(state->tree))).parameter_dcls; + for (count = 0; + params != NULL && IDL_LIST(params).data != NULL; + params = IDL_LIST(params).next, count++) + { + const char *cur_name = IDL_IDENT( + IDL_PARAM_DCL(IDL_LIST(params).data).simple_declarator).str; + if (!strcmp(cur_name, name)) { + /* XXX ought to verify that this is the right type here */ + /* XXX for iid_is this must be an iid */ + /* XXX for size_is and length_is this must be a uint32 */ + *argnum = count; + return TRUE; + } + } + return FALSE; +} + +/* return value is for success or failure */ +static gboolean +get_size_and_length(TreeState *state, IDL_tree type, + int16 *size_is_argnum, int16 *length_is_argnum, + gboolean *has_size_is, gboolean *has_length_is) +{ + *has_size_is = FALSE; + *has_length_is = FALSE; + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator; + const char *size_is; + const char *length_is; + + /* only if size_is is found does any of this matter */ + size_is = IDL_tree_property_get(sd, "size_is"); + if (!size_is) + return TRUE; + + if (!find_arg_with_name(state, size_is, size_is_argnum)) { + IDL_tree_error(state->tree, "can't find matching argument for " + "[size_is(%s)]\n", size_is); + return FALSE; + } + *has_size_is = TRUE; + + /* length_is is optional */ + length_is = IDL_tree_property_get(sd, "length_is"); + if (length_is) { + *has_length_is = TRUE; + if (!find_arg_with_name(state, length_is, length_is_argnum)) { + IDL_tree_error(state->tree, "can't find matching argument for " + "[length_is(%s)]\n", length_is); + return FALSE; + } + } + } + return TRUE; +} + +static gboolean +fill_td_from_type(TreeState *state, XPTTypeDescriptor *td, IDL_tree type) +{ + IDL_tree up; + int16 size_is_argnum; + int16 length_is_argnum; + gboolean has_size_is; + gboolean has_length_is; + gboolean is_array = FALSE; + + if (type) { + + /* deal with array */ + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + IDL_tree sd = IDL_PARAM_DCL(state->tree).simple_declarator; + if (IDL_tree_property_get(sd, "array")) { + + is_array = TRUE; + + /* size_is is required! */ + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + + if (!has_size_is) { + IDL_tree_error(state->tree, "[array] requires [size_is()]\n"); + return FALSE; + } + + td->prefix.flags = TD_ARRAY | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + + /* + * XXX - NOTE - this will be broken for multidimensional + * arrays because of the realloc XPT_InterfaceDescriptorAddTypes + * uses. The underlying 'td' can change as we recurse in to get + * additional dimensions. Luckily, we don't yet support more + * than on dimension in the arrays + */ + /* setup the additional_type */ + if (!XPT_InterfaceDescriptorAddTypes(ARENA(state), + CURRENT(state), 1)) { + g_error("out of memory\n"); + return FALSE; + } + td->type.additional_type = NEXT_TYPE(state); + td = &CURRENT(state)->additional_types[NEXT_TYPE(state)]; + NEXT_TYPE(state)++ ; + } + } + +handle_typedef: + switch (IDL_NODE_TYPE(type)) { + case IDLN_TYPE_INTEGER: { + gboolean sign = IDL_TYPE_INTEGER(type).f_signed; + switch(IDL_TYPE_INTEGER(type).f_type) { + case IDL_INTEGER_TYPE_SHORT: + td->prefix.flags = sign ? TD_INT16 : TD_UINT16; + break; + case IDL_INTEGER_TYPE_LONG: + td->prefix.flags = sign ? TD_INT32 : TD_UINT32; + break; + case IDL_INTEGER_TYPE_LONGLONG: + td->prefix.flags = sign ? TD_INT64 : TD_UINT64; + break; + } + break; + } + case IDLN_TYPE_CHAR: + td->prefix.flags = TD_CHAR; + break; + case IDLN_TYPE_WIDE_CHAR: + td->prefix.flags = TD_WCHAR; + break; + case IDLN_TYPE_STRING: + if (is_array) { + td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + } else { + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + if (has_size_is) { + td->prefix.flags = TD_PSTRING_SIZE_IS | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + } else { + td->prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + } + } + break; + case IDLN_TYPE_WIDE_STRING: + if (is_array) { + td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER; + } else { + if (!get_size_and_length(state, type, + &size_is_argnum, &length_is_argnum, + &has_size_is, &has_length_is)) { + /* error was reported by helper function */ + return FALSE; + } + if (has_size_is) { + td->prefix.flags = TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER; + td->argnum = size_is_argnum; + if (has_length_is) + td->argnum2 = length_is_argnum; + else + td->argnum2 = size_is_argnum; + } else { + td->prefix.flags = TD_PWSTRING | XPT_TDP_POINTER; + } + } + break; + case IDLN_TYPE_BOOLEAN: + td->prefix.flags = TD_BOOL; + break; + case IDLN_TYPE_OCTET: + td->prefix.flags = TD_UINT8; + break; + case IDLN_TYPE_FLOAT: + switch (IDL_TYPE_FLOAT (type).f_type) { + case IDL_FLOAT_TYPE_FLOAT: + td->prefix.flags = TD_FLOAT; + break; + case IDL_FLOAT_TYPE_DOUBLE: + td->prefix.flags = TD_DOUBLE; + break; + /* XXX 'long double' just ignored, or what? */ + default: break; + } + break; + case IDLN_IDENT: + if (!(up = IDL_NODE_UP(type))) { + IDL_tree_error(state->tree, + "ERROR: orphan ident %s in param list\n", + IDL_IDENT(type).str); + return FALSE; + } + switch (IDL_NODE_TYPE(up)) { + /* This whole section is abominably ugly */ + case IDLN_FORWARD_DCL: + case IDLN_INTERFACE: { + XPTInterfaceDirectoryEntry *ide, *ides; + uint16 num_ifaces; + char *className; + const char *iid_is; +handle_iid_is: + ides = HEADER(state)->interface_directory; + num_ifaces = HEADER(state)->num_interfaces; + /* might get here via the goto, so re-check type */ + if (IDL_NODE_TYPE(up) == IDLN_INTERFACE) + className = IDL_IDENT(IDL_INTERFACE(up).ident).str; + else if (IDL_NODE_TYPE(up) == IDLN_FORWARD_DCL) + className = IDL_IDENT(IDL_FORWARD_DCL(up).ident).str; + else + className = IDL_IDENT(IDL_NATIVE(up).ident).str; + iid_is = NULL; + + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL) { + iid_is = + IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "iid_is"); + } + if (iid_is) { + int16 argnum; + if (!find_arg_with_name(state, iid_is, &argnum)) { + IDL_tree_error(state->tree, + "can't find matching argument for " + "[iid_is(%s)]\n", iid_is); + return FALSE; + } + td->prefix.flags = TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER; + td->argnum = argnum; + } else { + td->prefix.flags = TD_INTERFACE_TYPE | XPT_TDP_POINTER; + ide = FindInterfaceByName(ides, num_ifaces, className); + if (!ide || ide < ides || ide > ides + num_ifaces) { + IDL_tree_error(state->tree, + "unknown iface %s in param\n", + className); + return FALSE; + } + td->type.iface = ide - ides + 1; +#ifdef DEBUG_shaver_index + fprintf(stderr, "DBG: index %d for %s\n", + td->type.iface, className); +#endif + } + break; + } + case IDLN_NATIVE: { + char *ident; + + /* jband - adding goto for iid_is when type is native */ + if (IDL_NODE_TYPE(state->tree) == IDLN_PARAM_DCL && + IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator, + "iid_is")) + goto handle_iid_is; + + ident = IDL_IDENT(type).str; + if (IDL_tree_property_get(type, "nsid")) { + td->prefix.flags = TD_PNSIID; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_POINTER | XPT_TDP_REFERENCE; + else if (IDL_tree_property_get(type,"ptr")) + td->prefix.flags |= XPT_TDP_POINTER; + } else if (IDL_tree_property_get(type, "domstring")) { + td->prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "astring")) { + td->prefix.flags = TD_ASTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "utf8string")) { + td->prefix.flags = TD_UTF8STRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else if (IDL_tree_property_get(type, "cstring")) { + td->prefix.flags = TD_CSTRING | XPT_TDP_POINTER; + if (IDL_tree_property_get(type, "ref")) + td->prefix.flags |= XPT_TDP_REFERENCE; + } else { + td->prefix.flags = TD_VOID | XPT_TDP_POINTER; + } + break; + } + default: + if (IDL_NODE_TYPE(IDL_NODE_UP(up)) == IDLN_TYPE_DCL) { + /* restart with the underlying type */ + IDL_tree new_type; + new_type = IDL_TYPE_DCL(IDL_NODE_UP(up)).type_spec; +#ifdef DEBUG_shaver_misc + fprintf(stderr, "following %s typedef to %s\n", + IDL_IDENT(type).str, IDL_NODE_TYPE_NAME(new_type)); +#endif + /* + * Do a nice messy goto rather than recursion so that + * we can avoid screwing up the *array* information. + */ +/* return fill_td_from_type(state, td, new_type); */ + if (new_type) { + type = new_type; + goto handle_typedef; + } else { + /* do what we would do in recursion if !type */ + td->prefix.flags = TD_VOID; + return TRUE; + } + } + IDL_tree_error(state->tree, + "can't handle %s ident in param list\n", +#ifdef DEBUG_shaver + /* XXX is this safe to use on Win now? */ + IDL_NODE_TYPE_NAME(IDL_NODE_UP(type)) +#else + "that type of" +#endif + ); +#ifdef DEBUG_shaver + XPT_ASSERT(0); +#endif + return FALSE; + } + break; + default: + IDL_tree_error(state->tree, "can't handle %s in param list\n", +#ifdef DEBUG_shaver + /* XXX is this safe to use on Win now? */ + IDL_NODE_TYPE_NAME(IDL_NODE_UP(type)) +#else + "that type" +#endif + ); + return FALSE; + } + } else { + td->prefix.flags = TD_VOID; + } + + return TRUE; +} + +static gboolean +fill_pd_from_type(TreeState *state, XPTParamDescriptor *pd, uint8 flags, + IDL_tree type) +{ + pd->flags = flags; + return fill_td_from_type(state, &pd->type, type); +} + +static gboolean +fill_pd_from_param(TreeState *state, XPTParamDescriptor *pd, IDL_tree tree) +{ + uint8 flags = 0; + gboolean is_dipper_type = DIPPER_TYPE(IDL_PARAM_DCL(tree).param_type_spec); + + switch (IDL_PARAM_DCL(tree).attr) { + case IDL_PARAM_IN: + flags = XPT_PD_IN; + break; + case IDL_PARAM_OUT: + flags = XPT_PD_OUT; + break; + case IDL_PARAM_INOUT: + flags = XPT_PD_IN | XPT_PD_OUT; + break; + } + + if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator, + "retval")) { + if (flags != XPT_PD_OUT) { + IDL_tree_error(tree, "can't have [retval] with in%s param " + "(only out)\n", + flags & XPT_PD_OUT ? "out" : ""); + return FALSE; + } + flags |= XPT_PD_RETVAL; + } + + if (is_dipper_type && (flags & XPT_PD_OUT)) { + flags &= ~XPT_PD_OUT; + flags |= XPT_PD_IN | XPT_PD_DIPPER; + } + + if (IDL_tree_property_get(IDL_PARAM_DCL(tree).simple_declarator, + "shared")) { + if (flags & XPT_PD_IN) { + IDL_tree_error(tree, "can't have [shared] with in%s param " + "(only out)\n", + flags & XPT_PD_OUT ? "out" : ""); + return FALSE; + } + flags |= XPT_PD_SHARED; + } + + /* stick param where we can see it later */ + state->tree = tree; + return fill_pd_from_type(state, pd, flags, + IDL_PARAM_DCL(tree).param_type_spec); +} + +/* XXXshaver common with xpidl_header.c */ +#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL(tree).simple_declarations).data)) +#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL(tree).param_type_spec) +#define ATTR_TYPE(tree) (IDL_NODE_TYPE(ATTR_TYPE_DECL(tree))) + +static gboolean +fill_pd_as_nsresult(XPTParamDescriptor *pd) +{ + pd->type.prefix.flags = TD_UINT32; /* TD_NSRESULT */ + return TRUE; +} + +static gboolean +typelib_attr_accessor(TreeState *state, XPTMethodDescriptor *meth, + gboolean getter, gboolean hidden) +{ + uint8 methflags = 0; + uint8 pdflags = 0; + + methflags |= getter ? XPT_MD_GETTER : XPT_MD_SETTER; + methflags |= hidden ? XPT_MD_HIDDEN : 0; + if (!XPT_FillMethodDescriptor(ARENA(state), meth, methflags, + ATTR_IDENT(state->tree).str, 1)) + return FALSE; + + if (getter) { + if (DIPPER_TYPE(ATTR_TYPE_DECL(state->tree))) { + pdflags |= (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER); + } else { + pdflags |= (XPT_PD_RETVAL | XPT_PD_OUT); + } + } else { + pdflags |= XPT_PD_IN; + } + + if (!fill_pd_from_type(state, meth->params, pdflags, + ATTR_TYPE_DECL(state->tree))) + return FALSE; + + fill_pd_as_nsresult(meth->result); + NEXT_METH(state)++; + return TRUE; +} + +static gboolean +typelib_attr_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly; + + /* XXX this only handles the first ident; elsewhere too... */ + IDL_tree ident = + IDL_LIST(IDL_ATTR_DCL(state->tree).simple_declarations).data; + + /* If it's marked [noscript], mark it as hidden in the typelib. */ + gboolean hidden = (IDL_tree_property_get(ident, "noscript") != NULL); + + if (!verify_attribute_declaration(state->tree)) + return FALSE; + + if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id, + (PRUint16) (read_only ? 1 : 2))) + return FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + return typelib_attr_accessor(state, meth, TRUE, hidden) && + (read_only || typelib_attr_accessor(state, meth + 1, FALSE, hidden)); +} + +static gboolean +typelib_op_dcl(TreeState *state) +{ + XPTInterfaceDescriptor *id = CURRENT(state); + XPTMethodDescriptor *meth; + struct _IDL_OP_DCL *op = &IDL_OP_DCL(state->tree); + IDL_tree iter; + uint16 num_args = 0; + uint8 op_flags = 0; + gboolean op_notxpcom = (IDL_tree_property_get(op->ident, "notxpcom") + != NULL); + gboolean op_noscript = (IDL_tree_property_get(op->ident, "noscript") + != NULL); + + if (!verify_method_declaration(state->tree)) + return FALSE; + + if (!XPT_InterfaceDescriptorAddMethods(ARENA(state), id, 1)) + return FALSE; + + meth = &id->method_descriptors[NEXT_METH(state)]; + + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) + num_args++; /* count params */ + if (op->op_type_spec && !op_notxpcom) + num_args++; /* fake param for _retval */ + + if (op_noscript) + op_flags |= XPT_MD_HIDDEN; + if (op_notxpcom) + op_flags |= XPT_MD_NOTXPCOM; + + /* XXXshaver constructor? */ + +#ifdef DEBUG_shaver_method + fprintf(stdout, "DBG: adding method %s (nargs %d)\n", + IDL_IDENT(op->ident).str, num_args); +#endif + if (!XPT_FillMethodDescriptor(ARENA(state), meth, op_flags, + IDL_IDENT(op->ident).str, + (uint8) num_args)) + return FALSE; + + for (num_args = 0, iter = op->parameter_dcls; iter; + iter = IDL_LIST(iter).next, num_args++) { + XPTParamDescriptor *pd = &meth->params[num_args]; + if (!fill_pd_from_param(state, pd, IDL_LIST(iter).data)) + return FALSE; + } + + /* stick retval param where we can see it later */ + state->tree = op->op_type_spec; + + /* XXX unless [notxpcom] */ + if (!op_notxpcom) { + if (op->op_type_spec) { + uint8 pdflags = DIPPER_TYPE(op->op_type_spec) ? + (XPT_PD_RETVAL | XPT_PD_IN | XPT_PD_DIPPER) : + (XPT_PD_RETVAL | XPT_PD_OUT); + + if (!fill_pd_from_type(state, &meth->params[num_args], + pdflags, op->op_type_spec)) + return FALSE; + } + + if (!fill_pd_as_nsresult(meth->result)) + return FALSE; + } else { +#ifdef DEBUG_shaver_notxpcom + fprintf(stderr, "%s is notxpcom\n", IDL_IDENT(op->ident).str); +#endif + if (!fill_pd_from_type(state, meth->result, XPT_PD_RETVAL, + op->op_type_spec)) + return FALSE; + } + NEXT_METH(state)++; + return TRUE; +} + +static gboolean +typelib_const_dcl(TreeState *state) +{ + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree); + const char *name = IDL_IDENT(dcl->ident).str; + gboolean is_long; + gboolean sign; + IDL_tree real_type; + XPTInterfaceDescriptor *id; + XPTConstDescriptor *cd; + IDL_longlong_t value; + + if (!verify_const_declaration(state->tree)) + return FALSE; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + is_long = (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG); + + id = CURRENT(state); + if (!XPT_InterfaceDescriptorAddConsts(ARENA(state), id, 1)) + return FALSE; + cd = &id->const_descriptors[NEXT_CONST(state)]; + + cd->name = IDL_IDENT(dcl->ident).str; +#ifdef DEBUG_shaver_const + fprintf(stderr, "DBG: adding const %s\n", cd->name); +#endif + if (!fill_td_from_type(state, &cd->type, dcl->const_type)) + return FALSE; + + value = IDL_INTEGER(dcl->const_exp).value; + sign = IDL_TYPE_INTEGER(dcl->const_type).f_signed; + if (is_long) { + if (sign) + cd->value.i32 = value; + else + cd->value.ui32 = value; + } else { + if (sign) + cd->value.i16 = value; + else + cd->value.ui16 = value; + } + NEXT_CONST(state)++; + return TRUE; +} + +static gboolean +typelib_enum(TreeState *state) +{ + XPIDL_WARNING((state->tree, IDL_WARNING1, + "enums not supported, enum \'%s\' ignored", + IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str)); + return TRUE; +} + +backend * +xpidl_typelib_dispatch(void) +{ + static backend result; + static nodeHandler table[IDLN_LAST]; + static gboolean initialized = FALSE; + + result.emit_prolog = typelib_prolog; + result.emit_epilog = typelib_epilog; + + if (!initialized) { + /* Initialize non-NULL elements */ + table[IDLN_LIST] = typelib_list; + table[IDLN_ATTR_DCL] = typelib_attr_dcl; + table[IDLN_OP_DCL] = typelib_op_dcl; + table[IDLN_INTERFACE] = typelib_interface; + table[IDLN_CONST_DCL] = typelib_const_dcl; + table[IDLN_TYPE_ENUM] = typelib_enum; + table[IDLN_NATIVE] = check_native; + initialized = TRUE; + } + + result.dispatch_table = table; + return &result; +} + + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c new file mode 100644 index 00000000..25d04212 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpidl/xpidl_util.c @@ -0,0 +1,851 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * 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 NPL, 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 NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * Utility functions called by various backends. + */ + +#include "xpidl.h" + +/* XXXbe static */ char OOM[] = "ERROR: out of memory\n"; + +void * +xpidl_malloc(size_t nbytes) +{ + void *p = malloc(nbytes); + if (!p) { + fputs(OOM, stderr); + exit(1); + } + return p; +} + +char * +xpidl_strdup(const char *s) +{ +#if defined(XP_MAC) || defined(XP_SOLARIS) /* bird: dunno why this is required, but whatever*/ + size_t len = strlen(s); + char *ns = malloc(len + 1); + if (ns) + memcpy(ns, s, len + 1); +#else + char *ns = strdup(s); +#endif + if (!ns) { + fputs(OOM, stderr); + exit(1); + } + return ns; +} + +void +xpidl_write_comment(TreeState *state, int indent) +{ + fprintf(state->file, "%*s/* ", indent, ""); + IDL_tree_to_IDL(state->tree, state->ns, state->file, + IDLF_OUTPUT_NO_NEWLINES | + IDLF_OUTPUT_NO_QUALIFY_IDENTS | + IDLF_OUTPUT_PROPERTIES); + fputs(" */\n", state->file); +} + +/* + * Print an iid to into a supplied buffer; the buffer should be at least + * UUID_LENGTH bytes. + */ +gboolean +xpidl_sprint_iid(nsID *id, char iidbuf[]) +{ + int printed; + + printed = sprintf(iidbuf, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) id->m0, (PRUint32) id->m1,(PRUint32) id->m2, + (PRUint32) id->m3[0], (PRUint32) id->m3[1], + (PRUint32) id->m3[2], (PRUint32) id->m3[3], + (PRUint32) id->m3[4], (PRUint32) id->m3[5], + (PRUint32) id->m3[6], (PRUint32) id->m3[7]); + +#ifdef SPRINTF_RETURNS_STRING + return (printed && strlen((char *)printed) == 36); +#else + return (printed == 36); +#endif +} + +/* We only parse the {}-less format. */ +static const char nsIDFmt2[] = + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; + +/* + * Parse a uuid string into an nsID struct. We cannot link against libxpcom, + * so we re-implement nsID::Parse here. + */ +gboolean +xpidl_parse_iid(nsID *id, const char *str) +{ + PRInt32 count = 0; + PRInt32 n1, n2, n3[8]; + PRInt32 n0, i; + + XPT_ASSERT(str != NULL); + + if (strlen(str) != 36) { + return FALSE; + } + +#ifdef DEBUG_shaver_iid + fprintf(stderr, "parsing iid %s\n", str); +#endif + + count = sscanf(str, nsIDFmt2, + &n0, &n1, &n2, + &n3[0],&n3[1],&n3[2],&n3[3], + &n3[4],&n3[5],&n3[6],&n3[7]); + + id->m0 = (PRInt32) n0; + id->m1 = (PRInt16) n1; + id->m2 = (PRInt16) n2; + for (i = 0; i < 8; i++) { + id->m3[i] = (PRInt8) n3[i]; + } + +#ifdef DEBUG_shaver_iid + if (count == 11) { + fprintf(stderr, "IID parsed to "); + print_IID(id, stderr); + fputs("\n", stderr); + } +#endif + return (gboolean)(count == 11); +} + +gboolean +verify_const_declaration(IDL_tree const_tree) { + struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(const_tree); + const char *name = IDL_IDENT(dcl->ident).str; + IDL_tree real_type; + + /* const -> list -> interface */ + if (!IDL_NODE_UP(IDL_NODE_UP(const_tree)) || + IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(const_tree))) + != IDLN_INTERFACE) { + IDL_tree_error(const_tree, + "const declaration \'%s\' outside interface", + name); + return FALSE; + } + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(dcl->const_type); + real_type = real_type ? real_type : dcl->const_type; + if (IDL_NODE_TYPE(real_type) == IDLN_TYPE_INTEGER && + (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_SHORT || + IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG)) + { + if (!IDL_TYPE_INTEGER(real_type).f_signed && + IDL_INTEGER(dcl->const_exp).value < 0) + { +#ifndef G_HAVE_GINT64 + /* + * For platforms without longlong support turned on we can get + * confused by the high bit of the long value and think that it + * represents a negative value in an unsigned declaration. + * In that case we don't know if it is the programmer who is + * confused or the compiler. So we issue a warning instead of + * an error. + */ + if (IDL_TYPE_INTEGER(real_type).f_type == IDL_INTEGER_TYPE_LONG) + { + XPIDL_WARNING((const_tree, IDL_WARNING1, + "unsigned const declaration \'%s\' " + "initialized with (possibly) negative constant", + name)); + return TRUE; + } +#endif + IDL_tree_error(const_tree, + "unsigned const declaration \'%s\' initialized with " + "negative constant", + name); + return FALSE; + } + } else { + IDL_tree_error(const_tree, + "const declaration \'%s\' must be of type short or long", + name); + return FALSE; + } + + return TRUE; +} + + + +/* + * This method consolidates error checking needed when coercing the XPIDL compiler + * via the -t flag to generate output for a specific version of XPConnect. + */ +static gboolean +verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree) +{ + if (major_version == 1 && minor_version == 1) + { + /* XPIDL Version 1.1 checks */ + + /* utf8string, cstring, and astring types are not supported */ + if (IDL_tree_property_get(in_tree, "utf8string") != NULL || + IDL_tree_property_get(in_tree, "cstring") != NULL || + IDL_tree_property_get(in_tree, "astring") != NULL) + { + IDL_tree_error(error_tree, + "Cannot use [utf8string], [cstring] and [astring] " + "types when generating version 1.1 typelibs\n"); + return FALSE; + } + } + return TRUE; +} + +gboolean +verify_attribute_declaration(IDL_tree attr_tree) +{ + IDL_tree iface; + IDL_tree ident; + IDL_tree attr_type; + gboolean scriptable_interface; + + /* We don't support attributes named IID, conflicts with static GetIID + * member. The conflict is due to certain compilers (VC++) choosing a + * different vtable order, placing GetIID at the beginning regardless + * of it's placement + */ + if (strcmp( + IDL_IDENT( + IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data).str, + "IID") == 0) { + IDL_tree_error(attr_tree, + "Attributes named IID not supported, causes vtable " + "ordering problems"); + return FALSE; + } + /* + * Verify that we've been called on an interface, and decide if the + * interface was marked [scriptable]. + */ + if (IDL_NODE_UP(attr_tree) && IDL_NODE_UP(IDL_NODE_UP(attr_tree)) && + IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(attr_tree))) + == IDLN_INTERFACE) + { + scriptable_interface = + (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable") + != NULL); + } else { + IDL_tree_error(attr_tree, + "verify_attribute_declaration called on a non-interface?"); + return FALSE; + } + + /* + * Grab the first of the list of idents and hope that it'll + * say scriptable or no. + */ + ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data; + + /* + * If the interface isn't scriptable, or the attribute is marked noscript, + * there's no need to check. + */ + if (!scriptable_interface || + IDL_tree_property_get(ident, "noscript") != NULL) + return TRUE; + + /* + * If it should be scriptable, check that the type is non-native. nsid, + * domstring, utf8string, cstring, astring are exempted. + */ + attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec; + + if (attr_type != NULL) + { + if (UP_IS_NATIVE(attr_type) && + IDL_tree_property_get(attr_type, "nsid") == NULL && + IDL_tree_property_get(attr_type, "domstring") == NULL && + IDL_tree_property_get(attr_type, "utf8string") == NULL && + IDL_tree_property_get(attr_type, "cstring") == NULL && + IDL_tree_property_get(attr_type, "astring") == NULL) + { + IDL_tree_error(attr_tree, + "attributes in [scriptable] interfaces that are " + "non-scriptable because they refer to native " + "types must be marked [noscript]\n"); + return FALSE; + } + /* + * We currently don't support properties of type nsid that aren't + * pointers or references, unless they are marked [notxpcom} and + * must be read-only + */ + + if ((IDL_tree_property_get(ident, "notxpcom") == NULL || !(IDL_ATTR_DCL(attr_tree).f_readonly)) && + IDL_tree_property_get(attr_type,"nsid") != NULL && + IDL_tree_property_get(attr_type,"ptr") == NULL && + IDL_tree_property_get(attr_type,"ref") == NULL) + { + IDL_tree_error(attr_tree, + "Feature not currently supported: " + "attributes with a type of nsid must be marked " + "either [ptr] or [ref], or " + "else must be marked [notxpcom] " + "and must be read-only\n"); + return FALSE; + } + + /* + * Run additional error checks on the attribute type if targetting an + * older version of XPConnect. + */ + + if (!verify_type_fits_version(attr_type, attr_tree)) + return FALSE; + } + + if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL) + { + IDL_tree_error(attr_tree, + "multiple attributes in a single declaration is not supported\n"); + return FALSE; + } + return TRUE; +} + +/* + * Find the underlying type of an identifier typedef. + * + * All the needed tree-walking seems pretty shaky; isn't there something in + * libIDL to automate this? + */ +IDL_tree /* IDL_TYPE_DCL */ +find_underlying_type(IDL_tree typedef_ident) +{ + IDL_tree up; + + if (typedef_ident == NULL || IDL_NODE_TYPE(typedef_ident) != IDLN_IDENT) + return NULL; + + up = IDL_NODE_UP(typedef_ident); + if (up == NULL || IDL_NODE_TYPE(up) != IDLN_LIST) + return NULL; + up = IDL_NODE_UP(up); + if (up == NULL || IDL_NODE_TYPE(up) != IDLN_TYPE_DCL) + return NULL; + + return IDL_TYPE_DCL(up).type_spec; +} + +static IDL_tree /* IDL_PARAM_DCL */ +find_named_parameter(IDL_tree method_tree, const char *param_name) +{ + IDL_tree iter; + for (iter = IDL_OP_DCL(method_tree).parameter_dcls; iter; + iter = IDL_LIST(iter).next) + { + IDL_tree param = IDL_LIST(iter).data; + IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator; + const char *current_name = IDL_IDENT(simple_decl).str; + if (strcmp(current_name, param_name) == 0) + return param; + } + return NULL; +} + +typedef enum ParamAttrType { + IID_IS, + LENGTH_IS, + SIZE_IS +} ParamAttrType; + +/* + * Check that parameters referred to by attributes such as size_is exist and + * refer to parameters of the appropriate type. + */ +static gboolean +check_param_attribute(IDL_tree method_tree, IDL_tree param, + ParamAttrType whattocheck) +{ + const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str; + const char *referred_name = NULL; + IDL_tree param_type = IDL_PARAM_DCL(param).param_type_spec; + IDL_tree simple_decl = IDL_PARAM_DCL(param).simple_declarator; + const char *param_name = IDL_IDENT(simple_decl).str; + const char *attr_name; + const char *needed_type; + + if (whattocheck == IID_IS) { + attr_name = "iid_is"; + needed_type = "IID"; + } else if (whattocheck == LENGTH_IS) { + attr_name = "length_is"; + needed_type = "unsigned long (or PRUint32)"; + } else if (whattocheck == SIZE_IS) { + attr_name = "size_is"; + needed_type = "unsigned long (or PRUint32)"; + } else { + XPT_ASSERT("asked to check an unknown attribute type!"); + return TRUE; + } + + referred_name = IDL_tree_property_get(simple_decl, attr_name); + if (referred_name != NULL) { + IDL_tree referred_param = find_named_parameter(method_tree, + referred_name); + IDL_tree referred_param_type; + if (referred_param == NULL) { + IDL_tree_error(method_tree, + "attribute [%s(%s)] refers to missing " + "parameter \"%s\"", + attr_name, referred_name, referred_name); + return FALSE; + } + if (referred_param == param) { + IDL_tree_error(method_tree, + "attribute [%s(%s)] refers to it's own parameter", + attr_name, referred_name); + return FALSE; + } + + referred_param_type = IDL_PARAM_DCL(referred_param).param_type_spec; + if (whattocheck == IID_IS) { + /* require IID type */ + if (IDL_tree_property_get(referred_param_type, "nsid") == NULL) { + IDL_tree_error(method_tree, + "target \"%s\" of [%s(%s)] attribute " + "must be of %s type", + referred_name, attr_name, referred_name, + needed_type); + return FALSE; + } + } else if (whattocheck == LENGTH_IS || whattocheck == SIZE_IS) { + /* require PRUint32 type */ + IDL_tree real_type; + + /* Could be a typedef; try to map it to the real type. */ + real_type = find_underlying_type(referred_param_type); + real_type = real_type ? real_type : referred_param_type; + + if (IDL_NODE_TYPE(real_type) != IDLN_TYPE_INTEGER || + IDL_TYPE_INTEGER(real_type).f_signed != FALSE || + IDL_TYPE_INTEGER(real_type).f_type != IDL_INTEGER_TYPE_LONG) + { + IDL_tree_error(method_tree, + "target \"%s\" of [%s(%s)] attribute " + "must be of %s type", + referred_name, attr_name, referred_name, + needed_type); + + return FALSE; + } + } + } + + return TRUE; +} + + +/* + * Common method verification code, called by *op_dcl in the various backends. + */ +gboolean +verify_method_declaration(IDL_tree method_tree) +{ + struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree); + IDL_tree iface; + IDL_tree iter; + gboolean notxpcom; + gboolean scriptable_interface; + gboolean scriptable_method; + gboolean seen_retval = FALSE; + const char *method_name = IDL_IDENT(IDL_OP_DCL(method_tree).ident).str; + + /* We don't support attributes named IID, conflicts with static GetIID + * member. The conflict is due to certain compilers (VC++) choosing a + * different vtable order, placing GetIID at the beginning regardless + * of it's placement + */ + if (strcmp(method_name, "GetIID") == 0) { + IDL_tree_error(method_tree, + "Methods named GetIID not supported, causes vtable " + "ordering problems"); + return FALSE; + } + if (op->f_varargs) { + /* We don't currently support varargs. */ + IDL_tree_error(method_tree, "varargs are not currently supported"); + return FALSE; + } + + /* + * Verify that we've been called on an interface, and decide if the + * interface was marked [scriptable]. + */ + if (IDL_NODE_UP(method_tree) && IDL_NODE_UP(IDL_NODE_UP(method_tree)) && + IDL_NODE_TYPE(iface = IDL_NODE_UP(IDL_NODE_UP(method_tree))) + == IDLN_INTERFACE) + { + scriptable_interface = + (IDL_tree_property_get(IDL_INTERFACE(iface).ident, "scriptable") + != NULL); + } else { + IDL_tree_error(method_tree, + "verify_method_declaration called on a non-interface?"); + return FALSE; + } + + /* + * Require that any method in an interface marked as [scriptable], that + * *isn't* scriptable because it refers to some native type, be marked + * [noscript] or [notxpcom]. + * + * Also check that iid_is points to nsid, and length_is, size_is points + * to unsigned long. + */ + notxpcom = IDL_tree_property_get(op->ident, "notxpcom") != NULL; + + scriptable_method = scriptable_interface && + !notxpcom && + IDL_tree_property_get(op->ident, "noscript") == NULL; + + /* Loop through the parameters and check. */ + for (iter = op->parameter_dcls; iter; iter = IDL_LIST(iter).next) { + IDL_tree param = IDL_LIST(iter).data; + IDL_tree param_type = + IDL_PARAM_DCL(param).param_type_spec; + IDL_tree simple_decl = + IDL_PARAM_DCL(param).simple_declarator; + const char *param_name = IDL_IDENT(simple_decl).str; + + /* + * Reject this method if it should be scriptable and some parameter is + * native that isn't marked with either nsid, domstring, utf8string, + * cstring, astring or iid_is. + */ + if (scriptable_method && + UP_IS_NATIVE(param_type) && + IDL_tree_property_get(param_type, "nsid") == NULL && + IDL_tree_property_get(simple_decl, "iid_is") == NULL && + IDL_tree_property_get(param_type, "domstring") == NULL && + IDL_tree_property_get(param_type, "utf8string") == NULL && + IDL_tree_property_get(param_type, "cstring") == NULL && + IDL_tree_property_get(param_type, "astring") == NULL) + { + IDL_tree_error(method_tree, + "methods in [scriptable] interfaces that are " + "non-scriptable because they refer to native " + "types (parameter \"%s\") must be marked " + "[noscript]", param_name); + return FALSE; + } + + /* + * nsid's parameters that aren't ptr's or ref's are not currently + * supported in xpcom or non-xpcom (marked with [notxpcom]) methods + * as input parameters + */ + if (!(notxpcom && IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) && + IDL_tree_property_get(param_type, "nsid") != NULL && + IDL_tree_property_get(param_type, "ptr") == NULL && + IDL_tree_property_get(param_type, "ref") == NULL) + { + IDL_tree_error(method_tree, + "Feature currently not supported: " + "parameter \"%s\" is of type nsid and " + "must be marked either [ptr] or [ref] " + "or method \"%s\" must be marked [notxpcom] " + "and must not be an input parameter", + param_name, + method_name); + return FALSE; + } + /* + * Sanity checks on return values. + */ + if (IDL_tree_property_get(simple_decl, "retval") != NULL) { + if (IDL_LIST(iter).next != NULL) { + IDL_tree_error(method_tree, + "only the last parameter can be marked [retval]"); + return FALSE; + } + if (op->op_type_spec) { + IDL_tree_error(method_tree, + "can't have [retval] with non-void return type"); + return FALSE; + } + /* In case XPConnect relaxes the retval-is-last restriction. */ + if (seen_retval) { + IDL_tree_error(method_tree, + "can't have more than one [retval] parameter"); + return FALSE; + } + seen_retval = TRUE; + } + + /* + * Confirm that [shared] attributes are only used with string, wstring, + * or native (but not nsid, domstring, utf8string, cstring or astring) + * and can't be used with [array]. + */ + if (IDL_tree_property_get(simple_decl, "shared") != NULL) { + IDL_tree real_type; + real_type = find_underlying_type(param_type); + real_type = real_type ? real_type : param_type; + + if (IDL_tree_property_get(simple_decl, "array") != NULL) { + IDL_tree_error(method_tree, + "[shared] parameter \"%s\" cannot " + "be of array type", param_name); + return FALSE; + } + + if (!(IDL_NODE_TYPE(real_type) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING || + (UP_IS_NATIVE(real_type) && + !IDL_tree_property_get(real_type, "nsid") && + !IDL_tree_property_get(real_type, "domstring") && + !IDL_tree_property_get(real_type, "utf8string") && + !IDL_tree_property_get(real_type, "cstring") && + !IDL_tree_property_get(real_type, "astring")))) + { + IDL_tree_error(method_tree, + "[shared] parameter \"%s\" must be of type " + "string, wstring or native", param_name); + return FALSE; + } + } + + /* + * inout is not allowed with "domstring", "UTF8String", "CString" + * and "AString" types + */ + if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT && + UP_IS_NATIVE(param_type) && + (IDL_tree_property_get(param_type, "domstring") != NULL || + IDL_tree_property_get(param_type, "utf8string") != NULL || + IDL_tree_property_get(param_type, "cstring") != NULL || + IDL_tree_property_get(param_type, "astring") != NULL )) { + IDL_tree_error(method_tree, + "[domstring], [utf8string], [cstring], [astring] " + "types cannot be used as inout parameters"); + return FALSE; + } + + + /* + * arrays of domstring, utf8string, cstring, astring types not allowed + */ + if (IDL_tree_property_get(simple_decl, "array") != NULL && + UP_IS_NATIVE(param_type) && + (IDL_tree_property_get(param_type, "domstring") != NULL || + IDL_tree_property_get(param_type, "utf8string") != NULL || + IDL_tree_property_get(param_type, "cstring") != NULL || + IDL_tree_property_get(param_type, "astring") != NULL)) { + IDL_tree_error(method_tree, + "[domstring], [utf8string], [cstring], [astring] " + "types cannot be used in array parameters"); + return FALSE; + } + + if (!check_param_attribute(method_tree, param, IID_IS) || + !check_param_attribute(method_tree, param, LENGTH_IS) || + !check_param_attribute(method_tree, param, SIZE_IS)) + return FALSE; + + /* + * Run additional error checks on the parameter type if targetting an + * older version of XPConnect. + */ + + if (!verify_type_fits_version(param_type, method_tree)) + return FALSE; + + } + + /* XXX q: can return type be nsid? */ + /* Native return type? */ + if (scriptable_method && + op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) && + IDL_tree_property_get(op->op_type_spec, "nsid") == NULL && + IDL_tree_property_get(op->op_type_spec, "domstring") == NULL && + IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL && + IDL_tree_property_get(op->op_type_spec, "cstring") == NULL && + IDL_tree_property_get(op->op_type_spec, "astring") == NULL) + { + IDL_tree_error(method_tree, + "methods in [scriptable] interfaces that are " + "non-scriptable because they return native " + "types must be marked [noscript]"); + return FALSE; + } + + + /* + * nsid's parameters that aren't ptr's or ref's are not currently + * supported in xpcom + */ + if (!notxpcom && + op->op_type_spec != NULL && + IDL_tree_property_get(op->op_type_spec, "nsid") != NULL && + IDL_tree_property_get(op->op_type_spec, "ptr") == NULL && + IDL_tree_property_get(op->op_type_spec, "ref") == NULL) + { + IDL_tree_error(method_tree, + "Feature currently not supported: " + "return value is of type nsid and " + "must be marked either [ptr] or [ref], " + "or else method \"%s\" must be marked [notxpcom] ", + method_name); + return FALSE; + } + + /* + * Run additional error checks on the return type if targetting an + * older version of XPConnect. + */ + + if (op->op_type_spec != NULL && + !verify_type_fits_version(op->op_type_spec, method_tree)) + { + return FALSE; + } + + return TRUE; +} + +/* + * Verify that a native declaration has an associated C++ expression, i.e. that + * it's of the form native () + */ +gboolean +check_native(TreeState *state) +{ + char *native_name; + /* require that native declarations give a native type */ + if (IDL_NATIVE(state->tree).user_type) + return TRUE; + native_name = IDL_IDENT(IDL_NATIVE(state->tree).ident).str; + IDL_tree_error(state->tree, + "``native %s;'' needs C++ type: ``native %s();''", + native_name, native_name); + return FALSE; +} + +/* + * Print a GSList as char strings to a file. + */ +void +printlist(FILE *outfile, GSList *slist) +{ + guint i; + guint len = g_slist_length(slist); + + for(i = 0; i < len; i++) { + fprintf(outfile, + "%s\n", (char *)g_slist_nth_data(slist, i)); + } +} + +void +xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data) +{ + IDL_tree_func_data tfd; + + while (p) { + struct _IDL_LIST *list = &IDL_LIST(p); + tfd.tree = list->data; + if (!foreach(&tfd, user_data)) + return; + p = list->next; + } +} + +/* + * Verify that the interface declaration is correct + */ +gboolean +verify_interface_declaration(IDL_tree interface_tree) +{ + IDL_tree iter; + /* + * If we have the scriptable attribute then make sure all of our direct + * parents have it as well. + * NOTE: We don't recurse since all interfaces will fall through here + */ + if (IDL_tree_property_get(IDL_INTERFACE(interface_tree).ident, + "scriptable")) { + for (iter = IDL_INTERFACE(interface_tree).inheritance_spec; iter; + iter = IDL_LIST(iter).next) { + if (IDL_tree_property_get( + IDL_INTERFACE(iter).ident, "scriptable") == 0) { + XPIDL_WARNING((interface_tree,IDL_WARNING1, + "%s is scriptable but inherits from the non-scriptable interface %s\n", + IDL_IDENT(IDL_INTERFACE(interface_tree).ident).str, + IDL_IDENT(IDL_INTERFACE(iter).ident).str)); + } + } + } + return TRUE; +} + +/* + * Return a pointer to the start of the base filename of path + */ +char * +xpidl_basename(const char * path) +{ + char * result = g_path_get_basename(path); + /* + *If this is windows then we'll handle either / or \ as a separator + * g_basename only handles \ for windows + */ +#if defined(XP_WIN32) +# error adapt regarding g_basename() vs. g_path_get_basename()! + const char * slash = strrchr(path, '/'); + /* If we found a slash and its after the current default OS separator */ + if (slash != NULL && (slash > result)) + result = slash + 1; +#endif + return result; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in new file mode 100644 index 00000000..1447128f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +DIRS = public src tools + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in new file mode 100644 index 00000000..3e452486 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/Makefile.in @@ -0,0 +1,51 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom + +EXPORTS = xpt_arena.h xpt_struct.h xpt_xdr.h +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h new file mode 100644 index 00000000..2b277467 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_arena.h @@ -0,0 +1,145 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Simple arena allocator for xpt (which avoids using NSPR). + */ + +#ifndef __xpt_arena_h__ +#define __xpt_arena_h__ + +#include "prtypes.h" +#include + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_NewArena VBoxNsxpXPT_NewArena +#define XPT_ArenaMalloc VBoxNsxpXPT_ArenaMalloc +#define XPT_DestroyArena VBoxNsxpXPT_DestroyArena +#define XPT_ArenaFree VBoxNsxpXPT_ArenaFree +#define XPT_DestroyArena VBoxNsxpXPT_DestroyArena +#define XPT_DumpStats VBoxNsxpXPT_DumpStats +#define XPT_NotifyDoneLoading VBoxNsxpXPT_NotifyDoneLoading +#define XPT_ArenaStrDup VBoxNsxpXPT_ArenaStrDup +#define XPT_AssertFailed VBoxNsxpXPT_AssertFailed +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +/* + * The linkage of XPT API functions differs depending on whether the file is + * used within the XPT library or not. Any source file within the XPT + * library should define EXPORT_XPT_API whereas any client of the library + * should not. + */ +#ifdef EXPORT_XPT_API +#define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +#define XPT_PUBLIC_DATA(t) PR_IMPLEMENT_DATA(t) +#else +#ifdef _WIN32 +# define XPT_PUBLIC_API(t) __declspec(dllimport) t +# define XPT_PUBLIC_DATA(t) __declspec(dllimport) t +#else +# define XPT_PUBLIC_API(t) PR_IMPLEMENT(t) +# define XPT_PUBLIC_DATA(t) t +#endif +#endif +#define XPT_FRIEND_API(t) XPT_PUBLIC_API(t) +#define XPT_FRIEND_DATA(t) XPT_PUBLIC_DATA(t) + +PR_BEGIN_EXTERN_C + +/* + * Simple Arena support. Use with caution! + */ + +typedef struct XPTArena XPTArena; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name); + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena); + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size); + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s); + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena); + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void* block); + +/* --------------------------------------------------------- */ + +#define XPT_MALLOC(_arena, _bytes) \ + XPT_ArenaMalloc((_arena), (_bytes)) + +#ifdef DEBUG +#define XPT_FREE(_arena, _ptr) \ + XPT_ArenaFree((_arena), (_ptr)) +#else +#define XPT_FREE(_arena, _ptr) \ + ((void)0) +#endif + +#define XPT_STRDUP(_arena, _s) \ + XPT_ArenaStrDup((_arena), (_s)) + +#define XPT_CALLOC(_arena, _size) XPT_MALLOC((_arena), (_size)) +#define XPT_NEW(_arena, _struct) ((_struct *) XPT_MALLOC((_arena), sizeof(_struct))) +#define XPT_NEWZAP(_arena, _struct) XPT_NEW((_arena), _struct) +#define XPT_DELETE(_arena, _ptr) do{XPT_FREE((_arena), (_ptr)); ((_ptr)) = NULL;}while(0) +#define XPT_FREEIF(_arena, _ptr) do{if ((_ptr)) XPT_FREE((_arena), (_ptr));}while(0) + +/* --------------------------------------------------------- */ + +#ifdef DEBUG +XPT_PUBLIC_API(void) +XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno); +#define XPT_ASSERT(_expr) \ + ((_expr)?((void)0):XPT_AssertFailed(# _expr, __FILE__, __LINE__)) +#else +#define XPT_ASSERT(_expr) ((void)0) +#endif + +PR_END_EXTERN_C + +#endif /* __xpt_arena_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h new file mode 100644 index 00000000..c7f36f2d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_struct.h @@ -0,0 +1,562 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Structures matching the in-memory representation of typelib structures. + * http://www.mozilla.org/scriptable/typelib_file.html + */ + +#ifndef __xpt_struct_h__ +#define __xpt_struct_h__ + +#include "xpt_arena.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_NewHeader VBoxNsxpXPT_NewHeader +#define XPT_NewStringZ VBoxNsxpXPT_NewStringZ +#define XPT_NewAnnotation VBoxNsxpXPT_NewAnnotation +#define XPT_SizeOfHeaderBlock VBoxNsxpXPT_SizeOfHeaderBlock +#define XPT_NewInterfaceDescriptor VBoxNsxpXPT_NewInterfaceDescriptor +#define XPT_FillInterfaceDirectoryEntry VBoxNsxpXPT_FillInterfaceDirectoryEntry +#define XPT_FillMethodDescriptor VBoxNsxpXPT_FillMethodDescriptor +#define XPT_FreeHeader VBoxNsxpXPT_FreeHeader +#define XPT_ParseVersionString VBoxNsxpXPT_ParseVersionString +#define XPT_DestroyInterfaceDirectoryEntry VBoxNsxpXPT_DestroyInterfaceDirectoryEntry +#define XPT_FillParamDescriptor VBoxNsxpXPT_FillParamDescriptor +#define XPT_FreeInterfaceDescriptor VBoxNsxpXPT_FreeInterfaceDescriptor +#define XPT_InterfaceDescriptorAddConsts VBoxNsxpXPT_InterfaceDescriptorAddConsts +#define XPT_InterfaceDescriptorAddMethods VBoxNsxpXPT_InterfaceDescriptorAddMethods +#define XPT_InterfaceDescriptorAddTypes VBoxNsxpXPT_InterfaceDescriptorAddTypes +#define XPT_GetInterfaceIndexByName VBoxNsxpXPT_GetInterfaceIndexByName +#define XPT_NewString VBoxNsxpXPT_NewString +#define XPT_SizeOfHeader VBoxNsxpXPT_SizeOfHeader +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +/* + * Originally, I was going to have structures that exactly matched the on-disk + * representation, but that proved difficult: different compilers can pack + * their structs differently, and that makes overlaying them atop a + * read-from-disk byte buffer troublesome. So now I just have some structures + * that are used in memory, and we're going to write a nice XDR library to + * write them to disk and stuff. It is pure joy. -- shaver + */ + +/* Structures for the typelib components */ + +typedef struct XPTHeader XPTHeader; +typedef struct XPTInterfaceDirectoryEntry XPTInterfaceDirectoryEntry; +typedef struct XPTInterfaceDescriptor XPTInterfaceDescriptor; +typedef struct XPTConstDescriptor XPTConstDescriptor; +typedef struct XPTMethodDescriptor XPTMethodDescriptor; +typedef struct XPTParamDescriptor XPTParamDescriptor; +typedef struct XPTTypeDescriptor XPTTypeDescriptor; +typedef struct XPTTypeDescriptorPrefix XPTTypeDescriptorPrefix; +typedef struct XPTString XPTString; +typedef struct XPTAnnotation XPTAnnotation; +#ifndef nsID_h__ +/* + * We can't include nsID.h, because it's full of C++ goop and we're not doing + * C++ here, so we define our own minimal struct. We protect against multiple + * definitions of this struct, though, and use the same field naming. + */ +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +#endif + +#define XPT_COPY_IID(to, from) \ + (to).m0 = (from).m0; \ + (to).m1 = (from).m1; \ + (to).m2 = (from).m2; \ + (to).m3[0] = (from).m3[0]; \ + (to).m3[1] = (from).m3[1]; \ + (to).m3[2] = (from).m3[2]; \ + (to).m3[3] = (from).m3[3]; \ + (to).m3[4] = (from).m3[4]; \ + (to).m3[5] = (from).m3[5]; \ + (to).m3[6] = (from).m3[6]; \ + (to).m3[7] = (from).m3[7]; + + +/* + * Every XPCOM typelib file begins with a header. + */ +struct XPTHeader { + PRUint8 magic[16]; + PRUint8 major_version; + PRUint8 minor_version; + PRUint16 num_interfaces; + PRUint32 file_length; + XPTInterfaceDirectoryEntry *interface_directory; + PRUint32 data_pool; + XPTAnnotation *annotations; +}; + +#define XPT_MAGIC "XPCOM\nTypeLib\r\n\032" +/* For error messages. */ +#define XPT_MAGIC_STRING "XPCOM\\nTypeLib\\r\\n\\032" +#define XPT_MAJOR_VERSION 0x01 +#define XPT_MINOR_VERSION 0x02 + +/* Any file with a major version number of XPT_MAJOR_INCOMPATIBLE_VERSION + * or higher is to be considered incompatible by this version of xpt and + * we will refuse to read it. We will return a header with magic, major and + * minor versions set from the file. num_interfaces and file_length will be + * set to zero to confirm our inability to read the file; i.e. even if some + * client of this library gets out of sync with us regarding the agreed upon + * value for XPT_MAJOR_INCOMPATIBLE_VERSION, anytime num_interfaces and + * file_length are both zero we *know* that this library refused to read the + * file due to version imcompatibility. + */ +#define XPT_MAJOR_INCOMPATIBLE_VERSION 0x02 + +/* + * The "[-t version number]" cmd line parameter to the XPIDL compiler and XPT + * linker specifies the major and minor version number of the output + * type library. + * + * The goal is for the compiler to check that the input IDL file only uses + * constructs that are supported in the version specified. The linker will + * check that all typelib files it reads are of the version specified or + * below. + * + * Both the compiler and the linker will report errors and abort if these + * checks fail. + * + * When you rev up major or minor versions of the type library in the future, + * think about the new stuff that you added to the type library and add checks + * to make sure that occurrences of that new "stuff" will get caught when [-t + * version number] is used with the compiler. Here's what you'll probably + * have to do each time you rev up major/minor versions: + * + * 1) Add the current version number string (before your change) to the + * XPT_TYPELIB_VERSIONS list. + * + * 2) Do your changes add new features to XPIDL? Ensure that those new + * features are rejected by the XPIDL compiler when any version number in + * the XPT_TYPELIB_VERSIONS list is specified on the command line. The + * one place that currently does this kind of error checking is the function + * verify_type_fits_version() in xpidl_util.c. It currently checks + * attribute types, parameter types, and return types. You'll probably have + * to add to it or generalize it further based on what kind of changes you + * are making. + * + * 3) You will probably NOT need to make any changes to the error checking + * in the linker. + */ + +#define XPT_VERSION_UNKNOWN 0 +#define XPT_VERSION_UNSUPPORTED 1 +#define XPT_VERSION_OLD 2 +#define XPT_VERSION_CURRENT 3 + +typedef struct { + const char* str; + PRUint8 major; + PRUint8 minor; + PRUint16 code; +} XPT_TYPELIB_VERSIONS_STRUCT; + +/* Currently accepted list of versions for typelibs */ +#define XPT_TYPELIB_VERSIONS { \ + {"1.0", 1, 0, XPT_VERSION_UNSUPPORTED}, \ + {"1.1", 1, 1, XPT_VERSION_OLD}, \ + {"1.2", 1, 2, XPT_VERSION_CURRENT} \ +} + +extern XPT_PUBLIC_API(PRUint16) +XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor); + +extern XPT_PUBLIC_API(XPTHeader *) +XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, + PRUint8 major_version, PRUint8 minor_version); + +extern XPT_PUBLIC_API(void) +XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader); + +/* size of header and annotations */ +extern XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeader(XPTHeader *header); + +/* size of header and annotations and InterfaceDirectoryEntries */ +extern XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeaderBlock(XPTHeader *header); + +/* + * A contiguous array of fixed-size InterfaceDirectoryEntry records begins at + * the byte offset identified by the interface_directory field in the file + * header. The array is used to quickly locate an interface description + * using its IID. No interface should appear more than once in the array. + */ +struct XPTInterfaceDirectoryEntry { + nsID iid; + char *name; + char *name_space; + XPTInterfaceDescriptor *interface_descriptor; + +#if 0 /* not yet */ + /* not stored on disk */ + PRUint32 offset; /* the offset for an ID still to be read */ +#endif +}; + +extern XPT_PUBLIC_API(PRBool) +XPT_FillInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry *ide, + nsID *iid, char *name, char *name_space, + XPTInterfaceDescriptor *descriptor); + +extern XPT_PUBLIC_API(void) +XPT_DestroyInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry* ide); + +/* + * An InterfaceDescriptor is a variable-size record used to describe a + * single XPCOM interface, including all of its methods. + */ +struct XPTInterfaceDescriptor { + PRUint16 parent_interface; + PRUint16 num_methods; + XPTMethodDescriptor *method_descriptors; + PRUint16 num_constants; + XPTConstDescriptor *const_descriptors; + PRUint8 flags; + + /* additional_types are used for arrays where we may need multiple + * XPTTypeDescriptors for a single XPTMethodDescriptor. Since we still + * want to have a simple array of XPTMethodDescriptor (each with a single + * embedded XPTTypeDescriptor), a XPTTypeDescriptor can have a reference + * to an 'additional_type'. That reference is an index in this + * "additional_types" array. So a given XPTMethodDescriptor might have + * a whole chain of these XPTTypeDescriptors to represent, say, a multi + * dimensional array. + * + * Note that in the typelib file these additional types are stored 'inline' + * in the MethodDescriptor. But, in the typelib MethodDescriptors can be + * of varying sizes, where in XPT's in memory mapping of the data we want + * them to be of fixed size. This additional_types scheme is here to allow + * for that. + */ + + XPTTypeDescriptor *additional_types; + PRUint16 num_additional_types; +}; + +#define XPT_ID_SCRIPTABLE 0x80 +#define XPT_ID_FUNCTION 0x40 +#define XPT_ID_FLAGMASK 0xc0 +#define XPT_ID_TAGMASK (~XPT_ID_FLAGMASK) +#define XPT_ID_TAG(id) ((id).flags & XPT_ID_TAGMASK) + +#define XPT_ID_IS_SCRIPTABLE(flags) (flags & XPT_ID_SCRIPTABLE) +#define XPT_ID_IS_FUNCTION(flags) (flags & XPT_ID_FUNCTION) + +extern XPT_PUBLIC_API(PRBool) +XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block, + PRUint16 num_interfaces, char *name, + PRUint16 *indexp); + +extern XPT_PUBLIC_API(XPTInterfaceDescriptor *) +XPT_NewInterfaceDescriptor(XPTArena *arena, + PRUint16 parent_interface, PRUint16 num_methods, + PRUint16 num_constants, PRUint8 flags); + +extern XPT_PUBLIC_API(void) +XPT_FreeInterfaceDescriptor(XPTArena *arena, XPTInterfaceDescriptor* id); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddMethods(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +extern XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddConsts(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num); + +/* + * This is our special string struct with a length value associated with it, + * which means that it can contains embedded NULs. + */ +struct XPTString { + PRUint16 length; + char *bytes; +}; + +extern XPT_PUBLIC_API(XPTString *) +XPT_NewString(XPTArena *arena, PRUint16 length, char *bytes); + +extern XPT_PUBLIC_API(XPTString *) +XPT_NewStringZ(XPTArena *arena, char *bytes); + +/* + * A TypeDescriptor is a variable-size record used to identify the type of a + * method argument or return value. + * + * There are three types of TypeDescriptors: + * + * SimpleTypeDescriptor + * InterfaceTypeDescriptor + * InterfaceIsTypeDescriptor + * + * The tag field in the prefix indicates which of the variant TypeDescriptor + * records is being used, and hence the way any remaining fields should be + * parsed. Values from 0 to 17 refer to SimpleTypeDescriptors. The value 18 + * designates an InterfaceTypeDescriptor, while 19 represents an + * InterfaceIsTypeDescriptor. + */ + +/* why bother with a struct? - other code relies on this being a struct */ +struct XPTTypeDescriptorPrefix { + PRUint8 flags; +}; + +/* flag bits -- fur and jband were right, I was miserably wrong */ +#define XPT_TDP_POINTER 0x80 +#define XPT_TDP_UNIQUE_POINTER 0x40 +#define XPT_TDP_REFERENCE 0x20 +#define XPT_TDP_FLAGMASK 0xe0 +#define XPT_TDP_TAGMASK (~XPT_TDP_FLAGMASK) +#define XPT_TDP_TAG(tdp) ((tdp).flags & XPT_TDP_TAGMASK) + +#define XPT_TDP_IS_POINTER(flags) (flags & XPT_TDP_POINTER) +#define XPT_TDP_IS_UNIQUE_POINTER(flags) (flags & XPT_TDP_UNIQUE_POINTER) +#define XPT_TDP_IS_REFERENCE(flags) (flags & XPT_TDP_REFERENCE) + +/* + * The following enum maps mnemonic names to the different numeric values + * of XPTTypeDescriptor->tag. + */ +enum XPTTypeDescriptorTags { + TD_INT8 = 0, + TD_INT16 = 1, + TD_INT32 = 2, + TD_INT64 = 3, + TD_UINT8 = 4, + TD_UINT16 = 5, + TD_UINT32 = 6, + TD_UINT64 = 7, + TD_FLOAT = 8, + TD_DOUBLE = 9, + TD_BOOL = 10, + TD_CHAR = 11, + TD_WCHAR = 12, + TD_VOID = 13, + TD_PNSIID = 14, + TD_DOMSTRING = 15, + TD_PSTRING = 16, + TD_PWSTRING = 17, + TD_INTERFACE_TYPE = 18, + TD_INTERFACE_IS_TYPE = 19, + TD_ARRAY = 20, + TD_PSTRING_SIZE_IS = 21, + TD_PWSTRING_SIZE_IS = 22, + TD_UTF8STRING = 23, + TD_CSTRING = 24, + TD_ASTRING = 25 +}; + +struct XPTTypeDescriptor { + XPTTypeDescriptorPrefix prefix; + PRUint8 argnum; /* used for iid_is and size_is */ + PRUint8 argnum2; /* used for length_is */ + union { + PRUint16 iface; /* used for TD_INTERFACE_TYPE */ + PRUint16 additional_type; /* used for TD_ARRAY */ + } type; +}; + +#define XPT_COPY_TYPE(to, from) \ + (to).prefix.flags = (from).prefix.flags; \ + (to).argnum = (from).argnum; \ + (to).argnum2 = (from).argnum2; \ + (to).type.additional_type = (from).type.additional_type; + +/* + * A ConstDescriptor is a variable-size record that records the name and + * value of a scoped interface constant. + * + * The types of the method parameter are restricted to the following subset + * of TypeDescriptors: + * + * int8, uint8, int16, uint16, int32, uint32, + * int64, uint64, wchar_t, char, string + * + * The type (and thus the size) of the value record is determined by the + * contents of the associated TypeDescriptor record. For instance, if type + * corresponds to int16, then value is a two-byte record consisting of a + * 16-bit signed integer. For a ConstDescriptor type of string, the value + * record is of type String*, i.e. an offset within the data pool to a + * String record containing the constant string. + */ +union XPTConstValue { + PRInt8 i8; + PRUint8 ui8; + PRInt16 i16; + PRUint16 ui16; + PRInt32 i32; + PRUint32 ui32; + PRInt64 i64; + PRUint64 ui64; + float flt; + double dbl; + PRBool bul; + char ch; + PRUint16 wch; + nsID *iid; + XPTString *string; + char *str; + PRUint16 *wstr; +}; /* varies according to type */ + +struct XPTConstDescriptor { + char *name; + XPTTypeDescriptor type; + union XPTConstValue value; +}; + +/* + * A ParamDescriptor is a variable-size record used to describe either a + * single argument to a method or a method's result. + */ +struct XPTParamDescriptor { + PRUint8 flags; + XPTTypeDescriptor type; +}; + +/* flag bits -- jband and fur were right, and I was miserably wrong */ +#define XPT_PD_IN 0x80 +#define XPT_PD_OUT 0x40 +#define XPT_PD_RETVAL 0x20 +#define XPT_PD_SHARED 0x10 +#define XPT_PD_DIPPER 0x08 +#define XPT_PD_FLAGMASK 0xf8 + +#define XPT_PD_IS_IN(flags) (flags & XPT_PD_IN) +#define XPT_PD_IS_OUT(flags) (flags & XPT_PD_OUT) +#define XPT_PD_IS_RETVAL(flags) (flags & XPT_PD_RETVAL) +#define XPT_PD_IS_SHARED(flags) (flags & XPT_PD_SHARED) +#define XPT_PD_IS_DIPPER(flags) (flags & XPT_PD_DIPPER) + +/* this is bogus +#define XPT_PARAMDESCRIPTOR_SIZE (XPT_TYPEDESCRIPTOR_SIZE + 1) +*/ + +extern XPT_PUBLIC_API(PRBool) +XPT_FillParamDescriptor(XPTArena *arena, + XPTParamDescriptor *pd, PRUint8 flags, + XPTTypeDescriptor *type); + +/* + * A MethodDescriptor is a variable-size record used to describe a single + * interface method. + */ +struct XPTMethodDescriptor { + char *name; + XPTParamDescriptor *params; + XPTParamDescriptor *result; + PRUint8 flags; + PRUint8 num_args; +}; + +/* flag bits -- jband and fur were right, and I was miserably wrong */ +#define XPT_MD_GETTER 0x80 +#define XPT_MD_SETTER 0x40 +#define XPT_MD_NOTXPCOM 0x20 +#define XPT_MD_CTOR 0x10 +#define XPT_MD_HIDDEN 0x08 +#define XPT_MD_FLAGMASK 0xf8 + +#define XPT_MD_IS_GETTER(flags) (flags & XPT_MD_GETTER) +#define XPT_MD_IS_SETTER(flags) (flags & XPT_MD_SETTER) +#define XPT_MD_IS_NOTXPCOM(flags) (flags & XPT_MD_NOTXPCOM) +#define XPT_MD_IS_CTOR(flags) (flags & XPT_MD_CTOR) +#define XPT_MD_IS_HIDDEN(flags) (flags & XPT_MD_HIDDEN) + +extern XPT_PUBLIC_API(PRBool) +XPT_FillMethodDescriptor(XPTArena *arena, + XPTMethodDescriptor *meth, PRUint8 flags, char *name, + PRUint8 num_args); + +/* + * Annotation records are variable-size records used to store secondary + * information about the typelib, e.g. such as the name of the tool that + * generated the typelib file, the date it was generated, etc. The + * information is stored with very loose format requirements so as to + * allow virtually any private data to be stored in the typelib. + * + * There are two types of Annotations: + * + * EmptyAnnotation + * PrivateAnnotation + * + * The tag field of the prefix discriminates among the variant record + * types for Annotation's. If the tag is 0, this record is an + * EmptyAnnotation. EmptyAnnotation's are ignored - they're only used to + * indicate an array of Annotation's that's completely empty. If the tag + * is 1, the record is a PrivateAnnotation. + */ + +struct XPTAnnotation { + XPTAnnotation *next; + PRUint8 flags; + /* remaining fields are present in typelib iff XPT_ANN_IS_PRIVATE */ + XPTString *creator; + XPTString *private_data; +}; + +#define XPT_ANN_LAST 0x80 +#define XPT_ANN_IS_LAST(flags) (flags & XPT_ANN_LAST) +#define XPT_ANN_PRIVATE 0x40 +#define XPT_ANN_IS_PRIVATE(flags) (flags & XPT_ANN_PRIVATE) + +extern XPT_PUBLIC_API(XPTAnnotation *) +XPT_NewAnnotation(XPTArena *arena, PRUint8 flags, XPTString *creator, + XPTString *private_data); + +PR_END_EXTERN_C + +#endif /* __xpt_struct_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h new file mode 100644 index 00000000..89d1c3f6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/public/xpt_xdr.h @@ -0,0 +1,240 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * Basic APIs for streaming typelib structures to/from disk. + */ + +#ifndef __xpt_xdr_h__ +#define __xpt_xdr_h__ + +#include "xpt_struct.h" + +#ifdef VBOX_WITH_XPCOM_NAMESPACE_CLEANUP +#define XPT_Do8 VBoxNsxpXPT_Do8 +#define XPT_Do16 VBoxNsxpXPT_Do16 +#define XPT_Do32 VBoxNsxpXPT_Do32 +#define XPT_Do64 VBoxNsxpXPT_Do64 +#define XPT_DoIID VBoxNsxpXPT_DoIID +#define XPT_DoCString VBoxNsxpXPT_DoCString +#define XPT_DoString VBoxNsxpXPT_DoString +#define XPT_DoStringInline VBoxNsxpXPT_DoStringInline +#define XPT_NewXDRState VBoxNsxpXPT_NewXDRState +#define XPT_SetDataOffset VBoxNsxpXPT_SetDataOffset +#define XPT_SeekTo VBoxNsxpXPT_SeekTo +#define XPT_MakeCursor VBoxNsxpXPT_MakeCursor +#define XPT_DestroyXDRState VBoxNsxpXPT_DestroyXDRState +#define XPT_GetXDRData VBoxNsxpXPT_GetXDRData +#define XPT_GetXDRDataLength VBoxNsxpXPT_GetXDRDataLength +#define XPT_DoHeader VBoxNsxpXPT_DoHeader +#define XPT_DoHeaderPrologue VBoxNsxpXPT_DoHeaderPrologue +#define XPT_UpdateFileLength VBoxNsxpXPT_UpdateFileLength +#define XPT_DataOffset VBoxNsxpXPT_DataOffset +#define XPT_GetOffsetForAddr VBoxNsxpXPT_GetOffsetForAddr +#define XPT_SetOffsetForAddr VBoxNsxpXPT_SetOffsetForAddr +#define XPT_SetAddrForOffset VBoxNsxpXPT_SetAddrForOffset +#define XPT_GetAddrForOffset VBoxNsxpXPT_GetAddrForOffset +#endif /* VBOX_WITH_XPCOM_NAMESPACE_CLEANUP */ + +PR_BEGIN_EXTERN_C + +typedef struct XPTState XPTState; +typedef struct XPTDatapool XPTDatapool; +typedef struct XPTCursor XPTCursor; + +/* Opaque type, for internal use */ +typedef struct XPTHashTable XPTHashTable; + +extern XPT_PUBLIC_API(PRBool) +XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoStringInline(XPTArena *arena, XPTCursor *cursor, XPTString **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **strp); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoIID(XPTCursor *cursor, nsID *iidp); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do64(XPTCursor *cursor, PRInt64 *u64p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do32(XPTCursor *cursor, PRUint32 *u32p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do16(XPTCursor *cursor, PRUint16 *u16p); + +extern XPT_PUBLIC_API(PRBool) +XPT_Do8(XPTCursor *cursor, PRUint8 *u8p); + +extern XPT_PUBLIC_API(PRBool) +XPT_DoHeaderPrologue(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp, PRUint32 * ide_offset); +extern XPT_PUBLIC_API(PRBool) +XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp); + +typedef enum { + XPT_ENCODE, + XPT_DECODE +} XPTMode; + +typedef enum { + XPT_HEADER = 0, + XPT_DATA = 1 +} XPTPool; + +struct XPTState { + XPTMode mode; + PRUint32 data_offset; + PRUint32 next_cursor[2]; + XPTDatapool *pool; + XPTArena *arena; +}; + +struct XPTDatapool { + XPTHashTable *offset_map; + char *data; + PRUint32 count; + PRUint32 allocated; +}; + +struct XPTCursor { + XPTState *state; + XPTPool pool; + PRUint32 offset; + PRUint8 bits; +}; + +extern XPT_PUBLIC_API(XPTState *) +XPT_NewXDRState(XPTMode mode, char *data, PRUint32 len); + +extern XPT_PUBLIC_API(PRBool) +XPT_MakeCursor(XPTState *state, XPTPool pool, PRUint32 len, XPTCursor *cursor); + +extern XPT_PUBLIC_API(PRBool) +XPT_SeekTo(XPTCursor *cursor, PRUint32 offset); + +extern XPT_PUBLIC_API(void) +XPT_DestroyXDRState(XPTState *state); + +/* Set file_length based on the data used in the state. (Only ENCODE.) */ +extern XPT_PUBLIC_API(PRBool) +XPT_UpdateFileLength(XPTState *state); + +/* returns the length of the specified data block */ +extern XPT_PUBLIC_API(void) +XPT_GetXDRDataLength(XPTState *state, XPTPool pool, PRUint32 *len); + +extern XPT_PUBLIC_API(void) +XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, PRUint32 *len); + +/* set or get the data offset for the state, depending on mode */ +extern XPT_PUBLIC_API(void) +XPT_DataOffset(XPTState *state, PRUint32 *data_offsetp); + +extern XPT_PUBLIC_API(void) +XPT_SetDataOffset(XPTState *state, PRUint32 data_offset); + +extern XPT_PUBLIC_API(PRUint32) +XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr); + +extern XPT_PUBLIC_API(PRBool) +XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset); + +extern XPT_PUBLIC_API(PRBool) +XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr); + +extern XPT_PUBLIC_API(void *) +XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset); + +/* all data structures are big-endian */ + +#if defined IS_BIG_ENDIAN +# ifdef VBOX +# error "Misconfigured endian!" +# endif +# define XPT_SWAB32(x) x +# define XPT_SWAB16(x) x +#elif defined IS_LITTLE_ENDIAN +# define XPT_SWAB32(x) (((x) >> 24) | \ + (((x) >> 8) & 0xff00) | \ + (((x) << 8) & 0xff0000) | \ + ((x) << 24)) +# define XPT_SWAB16(x) (((x) >> 8) | ((x) << 8)) +#else +# error "unknown byte order" +#endif + +/* + * If we're decoding, we want to read the offset before we check + * for already-decoded values. + * + * Then we check for repetition: CheckForRepeat will see if we've already + * encoded/decoded this value, and if so will set offset/addr correctly + * and make already be true. If not, it will set up the cursor for + * encoding (reserve space) or decoding (seek to correct location) as + * appropriate. In the encode case, it will also set the addr->offset + * mapping. + */ + +#define XPT_PREAMBLE_(cursor, addrp, pool, size, new_curs, already) \ + XPTMode mode = cursor->state->mode; \ + if (!(mode == XPT_ENCODE || XPT_Do32(cursor, &new_curs.offset)) || \ + !CheckForRepeat(cursor, (void **)addrp, pool, \ + mode == XPT_ENCODE ? size : 0u, &new_curs, \ + &already) || \ + !(mode == XPT_DECODE || XPT_Do32(cursor, &new_curs.offset))) \ + return PR_FALSE; \ + if (already) \ + return PR_TRUE; \ + +#define XPT_PREAMBLE_NO_ALLOC(cursor, addrp, pool, size, new_curs, already) \ + { \ + XPT_PREAMBLE_(cursor, addrp, pool, size, new_curs, already) \ + } + +#define XPT_ERROR_HANDLE(arena, free_it) \ + error: \ + if (cursor->state->mode == XPT_DECODE) \ + XPT_FREEIF(arena, free_it); \ + return PR_FALSE; + + +PR_END_EXTERN_C + +#endif /* __xpt_xdr_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in new file mode 100644 index 00000000..e0578556 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/Makefile.in @@ -0,0 +1,76 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +LIBRARY_NAME = xpt +LIB_IS_C_ONLY = 1 +ifdef CROSS_COMPILE +HOST_LIBRARY_NAME = hostxpt +endif + +CSRCS = xpt_arena.c xpt_struct.c xpt_xdr.c +HOST_CSRCS = $(CSRCS) + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPT_API +HOST_CFLAGS += -DEXPORT_XPT_API + +# Build libxpt early so that it'll be available to xpidl, which also +# must be built early. +export:: + @$(MAKE) libs + +ifdef CROSS_COMPILE +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c new file mode 100644 index 00000000..a0813b8f --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_arena.c @@ -0,0 +1,358 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Quick arena hack for xpt. */ + +/* XXX This exists because we don't want to drag in NSPR. It *seemed* +* to make more sense to write a quick and dirty arena than to clone +* plarena (like js/src did). This is not optimal, but it works. +* Half of the code here is instrumentation. +*/ + +#include "xpt_arena.h" +#include +#include +#include +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include +#endif + + +/*************************/ +/* logging stats support */ + +#if 0 && defined(DEBUG_jband) +#define XPT_ARENA_LOGGING 1 +#endif + +#ifdef XPT_ARENA_LOGGING + +#define LOG_MALLOC(_a, _req, _used) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_MallocCallCount; \ + (_a)->LOG_MallocTotalBytesRequested += (_req); \ + (_a)->LOG_MallocTotalBytesUsed += (_used); \ + } while(0) + +#define LOG_REAL_MALLOC(_a, _size) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_RealMallocCallCount; \ + (_a)->LOG_RealMallocTotalBytesRequested += (_size); \ + } while(0) + +#define LOG_FREE(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + ++(_a)->LOG_FreeCallCount; \ + } while(0) + +#define LOG_DONE_LOADING(_a) \ + do{ \ + XPT_ASSERT((_a)); \ + (_a)->LOG_LoadingFreeCallCount = (_a)->LOG_FreeCallCount; \ + } while(0) + +#define PRINT_STATS(_a) xpt_DebugPrintArenaStats((_a)) +static void xpt_DebugPrintArenaStats(XPTArena *arena); + +#else /* !XPT_ARENA_LOGGING */ + +#define LOG_MALLOC(_a, _req, _used) ((void)0) +#define LOG_REAL_MALLOC(_a, _size) ((void)0) +#define LOG_FREE(_a) ((void)0) + +#define LOG_DONE_LOADING(_a) ((void)0) +#define PRINT_STATS(_a) ((void)0) + +#endif /* XPT_ARENA_LOGGING */ + +/****************************************************/ + +/* Block header for each block in the arena */ +typedef struct BLK_HDR BLK_HDR; +struct BLK_HDR +{ + BLK_HDR *next; + size_t size; +}; + +#define XPT_MIN_BLOCK_SIZE 32 + +/* XXX this is lame. Should clone the code to do this bitwise */ +#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a))) + +struct XPTArena +{ + BLK_HDR *first; + PRUint8 *next; + size_t space; + size_t alignment; + size_t block_size; + char *name; + +#ifdef XPT_ARENA_LOGGING + PRUint32 LOG_MallocCallCount; + PRUint32 LOG_MallocTotalBytesRequested; + PRUint32 LOG_MallocTotalBytesUsed; + PRUint32 LOG_FreeCallCount; + PRUint32 LOG_LoadingFreeCallCount; + PRUint32 LOG_RealMallocCallCount; + PRUint32 LOG_RealMallocTotalBytesRequested; +#endif /* XPT_ARENA_LOGGING */ +}; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(PRUint32 block_size, size_t alignment, const char* name) +{ +#ifdef VBOX_USE_IPRT_IN_XPCOM + XPTArena *arena = RTMemAllocZ(sizeof(XPTArena)); +#else + XPTArena *arena = calloc(1, sizeof(XPTArena)); +#endif + if (arena) { + XPT_ASSERT(alignment); + if (alignment > sizeof(double)) + alignment = sizeof(double); + arena->alignment = alignment; + + if (block_size < XPT_MIN_BLOCK_SIZE) + block_size = XPT_MIN_BLOCK_SIZE; + arena->block_size = ALIGN_RND(block_size, alignment); + + /* must have room for at least one item! */ + XPT_ASSERT(arena->block_size >= + ALIGN_RND(sizeof(BLK_HDR), alignment) + + ALIGN_RND(1, alignment)); + + if (name) { + arena->name = XPT_STRDUP(arena, name); +#ifdef XPT_ARENA_LOGGING + /* fudge the stats since we are using space in the arena */ + arena->LOG_MallocCallCount = 0; + arena->LOG_MallocTotalBytesRequested = 0; + arena->LOG_MallocTotalBytesUsed = 0; +#endif /* XPT_ARENA_LOGGING */ + } + } + return arena; +} + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena) +{ + BLK_HDR* cur; + BLK_HDR* next; + + cur = arena->first; + while (cur) { + next = cur->next; +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(cur); +#else + free(cur); +#endif + cur = next; + } +#ifdef VBOX_USE_IPRT_IN_XPCOM + RTMemFree(arena); +#else + free(arena); +#endif +} + +XPT_PUBLIC_API(void) +XPT_DumpStats(XPTArena *arena) +{ + PRINT_STATS(arena); +} + + +/* +* Our alignment rule is that we always round up the size of each allocation +* so that the 'arena->next' pointer one will point to properly aligned space. +*/ + +XPT_PUBLIC_API(void *) +XPT_ArenaMalloc(XPTArena *arena, size_t size) +{ + PRUint8 *cur; + size_t bytes; + + if (!size) + return NULL; + + if (!arena) { + XPT_ASSERT(0); + return NULL; + } + + bytes = ALIGN_RND(size, arena->alignment); + + LOG_MALLOC(arena, size, bytes); + + if (bytes > arena->space) { + BLK_HDR* new_block; + size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), arena->alignment); + size_t new_space = arena->block_size; + + if (bytes > new_space - block_header_size) + new_space += bytes; + +#ifdef VBOX_USE_IPRT_IN_XPCOM + new_block = (BLK_HDR*) RTMemAllocZ(new_space/arena->alignment * (size_t)arena->alignment); +#else + new_block = (BLK_HDR*) calloc(new_space/arena->alignment, + arena->alignment); +#endif + if (!new_block) { + arena->next = NULL; + arena->space = 0; + return NULL; + } + + LOG_REAL_MALLOC(arena, new_space); + + /* link block into the list of blocks for use when we destroy */ + new_block->next = arena->first; + arena->first = new_block; + + /* save other block header info */ + new_block->size = new_space; + + /* set info for current block */ + arena->next = ((PRUint8*)new_block) + block_header_size; + arena->space = new_space - block_header_size; + +#ifdef DEBUG + /* mark block for corruption check */ + memset(arena->next, 0xcd, arena->space); +#endif + } + +#ifdef DEBUG + { + /* do corruption check */ + size_t i; + for (i = 0; i < bytes; ++i) { + XPT_ASSERT(arena->next[i] == 0xcd); + } + /* we guarantee that the block will be filled with zeros */ + memset(arena->next, 0, bytes); + } +#endif + + cur = arena->next; + arena->next += bytes; + arena->space -= bytes; + + return cur; +} + + +XPT_PUBLIC_API(char *) +XPT_ArenaStrDup(XPTArena *arena, const char * s) +{ + size_t len; + char* cur; + + if (!s) + return NULL; + + len = strlen(s)+1; + cur = XPT_ArenaMalloc(arena, len); + memcpy(cur, s, len); + return cur; +} + +XPT_PUBLIC_API(void) +XPT_NotifyDoneLoading(XPTArena *arena) +{ +#ifdef XPT_ARENA_LOGGING + if (arena) { + LOG_DONE_LOADING(arena); + } +#endif +} + +XPT_PUBLIC_API(void) +XPT_ArenaFree(XPTArena *arena, void *block) +{ + LOG_FREE(arena); +} + +#ifdef XPT_ARENA_LOGGING +static void xpt_DebugPrintArenaStats(XPTArena *arena) +{ + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); + printf("Start xpt arena stats for \"%s\"\n", + arena->name ? arena->name : "unnamed arena"); + printf("\n"); + printf("%d times arena malloc called\n", (int) arena->LOG_MallocCallCount); + printf("%d total bytes requested from arena malloc\n", (int) arena->LOG_MallocTotalBytesRequested); + printf("%d average bytes requested per call to arena malloc\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for alignment overhead)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0); + printf("%d average bytes used per call (accounts for all overhead and waste)\n", (int)arena->LOG_MallocCallCount ? (arena->LOG_RealMallocTotalBytesRequested/arena->LOG_MallocCallCount) : 0); + printf("\n"); + printf("%d during loading times arena free called\n", (int) arena->LOG_LoadingFreeCallCount); + printf("%d during loading approx total bytes not freed\n", (int) arena->LOG_LoadingFreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0)); + printf("\n"); + printf("%d total times arena free called\n", (int) arena->LOG_FreeCallCount); + printf("%d approx total bytes not freed until arena destruction\n", (int) arena->LOG_FreeCallCount * (int) (arena->LOG_MallocCallCount ? (arena->LOG_MallocTotalBytesUsed/arena->LOG_MallocCallCount) : 0 )); + printf("\n"); + printf("%d times arena called system malloc\n", (int) arena->LOG_RealMallocCallCount); + printf("%d total bytes arena requested from system\n", (int) arena->LOG_RealMallocTotalBytesRequested); + printf("%d byte block size specified at arena creation time\n", (int) arena->block_size); + printf("%d byte block alignment specified at arena creation time\n", (int) arena->alignment); + printf("\n"); + printf("End xpt arena stats\n"); + printf("()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()\n"); +} +#endif + +/***************************************************************************/ + +#ifdef DEBUG +XPT_PUBLIC_API(void) +XPT_AssertFailed(const char *s, const char *file, PRUint32 lineno) +{ + fprintf(stderr, "Assertion failed: %s, file %s, line %d\n", + s, file, lineno); + abort(); +} +#endif diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c new file mode 100644 index 00000000..93435910 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_struct.c @@ -0,0 +1,956 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of XDR routines for typelib structures. */ + +#include "xpt_xdr.h" +#include "xpt_struct.h" +#include +#include + +/***************************************************************************/ +/* Forward declarations. */ + +static PRUint32 +SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id); + +static PRUint32 +SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id); + +static PRBool +DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index); + +static PRBool +DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id); + +static PRBool +DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id); + +static PRBool +DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp); + +static PRBool +DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, XPTInterfaceDescriptor **idp); + +static PRBool +DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp); + +static PRBool +DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id); + +static PRBool +DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id); + +/***************************************************************************/ + +XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeader(XPTHeader *header) +{ + XPTAnnotation *ann, *last; + PRUint32 size = 16 /* magic */ + + 1 /* major */ + 1 /* minor */ + + 2 /* num_interfaces */ + 4 /* file_length */ + + 4 /* interface_directory */ + 4 /* data_pool */; + + ann = header->annotations; + do { + size += 1; /* Annotation prefix */ + if (XPT_ANN_IS_PRIVATE(ann->flags)) + size += 2 + ann->creator->length + 2 + ann->private_data->length; + last = ann; + ann = ann->next; + } while (!XPT_ANN_IS_LAST(last->flags)); + + return size; +} + +XPT_PUBLIC_API(PRUint32) +XPT_SizeOfHeaderBlock(XPTHeader *header) +{ + PRUint32 size = XPT_SizeOfHeader(header); + + size += header->num_interfaces * sizeof (XPTInterfaceDirectoryEntry); + + return size; +} + +XPT_PUBLIC_API(XPTHeader *) +XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, PRUint8 major_version, PRUint8 minor_version) +{ + XPTHeader *header = XPT_NEWZAP(arena, XPTHeader); + if (!header) + return NULL; + memcpy(header->magic, XPT_MAGIC, 16); + header->major_version = major_version; + header->minor_version = minor_version; + header->num_interfaces = num_interfaces; + if (num_interfaces) { + header->interface_directory = + XPT_CALLOC(arena, + num_interfaces * sizeof(XPTInterfaceDirectoryEntry)); + if (!header->interface_directory) { + XPT_DELETE(arena, header); + return NULL; + } + } + header->data_pool = 0; /* XXX do we even need this struct any more? */ + + return header; +} + +XPT_PUBLIC_API(void) +XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader) +{ + if (aHeader) { + XPTAnnotation* ann; + XPTInterfaceDirectoryEntry* entry = aHeader->interface_directory; + XPTInterfaceDirectoryEntry* end = entry + aHeader->num_interfaces; + for (; entry < end; entry++) { + XPT_DestroyInterfaceDirectoryEntry(arena, entry); + } + + ann = aHeader->annotations; + while (ann) { + XPTAnnotation* next = ann->next; + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + XPT_FREEIF(arena, ann->creator); + XPT_FREEIF(arena, ann->private_data); + } + XPT_DELETE(arena, ann); + ann = next; + } + + XPT_FREEIF(arena, aHeader->interface_directory); + XPT_DELETE(arena, aHeader); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_DoHeaderPrologue(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp, PRUint32 * ide_offset) +{ + XPTMode mode = cursor->state->mode; + unsigned int i; + XPTHeader * header; + + if (mode == XPT_DECODE) { + header = XPT_NEWZAP(arena, XPTHeader); + if (!header) + return PR_FALSE; + *headerp = header; + } else { + header = *headerp; + } + + if (mode == XPT_ENCODE) { + /* IDEs appear after header, including annotations */ + if (ide_offset != NULL) + { + *ide_offset = XPT_SizeOfHeader(*headerp) + 1; /* one-based offset */ + } + header->data_pool = XPT_SizeOfHeaderBlock(*headerp); + XPT_SetDataOffset(cursor->state, header->data_pool); + } + + for (i = 0; i < sizeof(header->magic); i++) { + if (!XPT_Do8(cursor, &header->magic[i])) + goto error; + } + + if (mode == XPT_DECODE && + strncmp((const char*)header->magic, XPT_MAGIC, 16) != 0) + { + /* Require that the header contain the proper magic */ + fprintf(stderr, + "libxpt: bad magic header in input file; " + "found '%s', expected '%s'\n", + header->magic, XPT_MAGIC_STRING); + goto error; + } + + if (!XPT_Do8(cursor, &header->major_version) || + !XPT_Do8(cursor, &header->minor_version)) { + goto error; + } + + if (mode == XPT_DECODE && + header->major_version >= XPT_MAJOR_INCOMPATIBLE_VERSION) { + /* This file is newer than we are and set to an incompatible version + * number. We must set the header state thusly and return. + */ + header->num_interfaces = 0; + header->file_length = 0; + return PR_TRUE; + } + + if (!XPT_Do16(cursor, &header->num_interfaces) || + !XPT_Do32(cursor, &header->file_length) || + (ide_offset != NULL && !XPT_Do32(cursor, ide_offset))) { + goto error; + } + return PR_TRUE; + /* XXX need to free child data sometimes! */ + XPT_ERROR_HANDLE(arena, header); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp) +{ + const int HEADER_SIZE = 24; + XPTMode mode = cursor->state->mode; + XPTHeader * header; + PRUint32 ide_offset; + int i; + XPTAnnotation *ann, *next, **annp; + + if (!XPT_DoHeaderPrologue(arena, cursor, headerp, &ide_offset)) + return PR_FALSE; + header = *headerp; + /* + * Make sure the file length reported in the header is the same size as + * as our buffer unless it is zero (not set) + */ + if (mode == XPT_DECODE && (header->file_length != 0 && + cursor->state->pool->allocated < header->file_length)) { + fputs("libxpt: File length in header does not match actual length. File may be corrupt\n", + stderr); + goto error; + } + + if (mode == XPT_ENCODE) + XPT_DataOffset(cursor->state, &header->data_pool); + if (!XPT_Do32(cursor, &header->data_pool)) + goto error; + if (mode == XPT_DECODE) + XPT_DataOffset(cursor->state, &header->data_pool); + + if (mode == XPT_DECODE && header->num_interfaces) { + header->interface_directory = + XPT_CALLOC(arena, header->num_interfaces * + sizeof(XPTInterfaceDirectoryEntry)); + if (!header->interface_directory) + goto error; + } + + /* + * Iterate through the annotations rather than recurring, to avoid blowing + * the stack on large xpt files. + */ + ann = next = header->annotations; + annp = &header->annotations; + do { + ann = next; + if (!DoAnnotation(arena, cursor, &ann)) + goto error; + if (mode == XPT_DECODE) { + /* + * Make sure that we store the address of the newly allocated + * annotation in the previous annotation's ``next'' slot, or + * header->annotations for the first one. + */ + *annp = ann; + annp = &ann->next; + } + next = ann->next; + } while (!XPT_ANN_IS_LAST(ann->flags)); + + /* shouldn't be necessary now, but maybe later */ + XPT_SeekTo(cursor, ide_offset); + + for (i = 0; i < header->num_interfaces; i++) { + if (!DoInterfaceDirectoryEntry(arena, cursor, + &header->interface_directory[i], + (PRUint16)(i + 1))) + goto error; + } + + return PR_TRUE; + + /* XXX need to free child data sometimes! */ + XPT_ERROR_HANDLE(arena, header); +} + +XPT_PUBLIC_API(PRBool) +XPT_FillInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry *ide, + nsID *iid, char *name, char *name_space, + XPTInterfaceDescriptor *descriptor) +{ + XPT_COPY_IID(ide->iid, *iid); + ide->name = name ? XPT_STRDUP(arena, name) : NULL; /* what good is it w/o a name? */ + ide->name_space = name_space ? XPT_STRDUP(arena, name_space) : NULL; + ide->interface_descriptor = descriptor; + return PR_TRUE; +} + +XPT_PUBLIC_API(void) +XPT_DestroyInterfaceDirectoryEntry(XPTArena *arena, + XPTInterfaceDirectoryEntry* ide) +{ + if (ide) { + if (ide->name) XPT_FREE(arena, ide->name); + if (ide->name_space) XPT_FREE(arena, ide->name_space); + XPT_FreeInterfaceDescriptor(arena, ide->interface_descriptor); + } +} + +/* InterfaceDirectoryEntry records go in the header */ +PRBool +DoInterfaceDirectoryEntry(XPTArena *arena, XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, PRUint16 entry_index) +{ + XPTMode mode = cursor->state->mode; + + /* write the IID in our cursor space */ + if (!XPT_DoIID(cursor, &(ide->iid)) || + + /* write the name string in the data pool, and the offset in our + cursor space */ + !XPT_DoCString(arena, cursor, &(ide->name)) || + + /* write the name_space string in the data pool, and the offset in our + cursor space */ + !XPT_DoCString(arena, cursor, &(ide->name_space)) || + + /* do InterfaceDescriptors -- later, only on encode (see below) */ + !DoInterfaceDescriptor(arena, cursor, &ide->interface_descriptor)) { + goto error; + } + + if (mode == XPT_DECODE) + XPT_SetOffsetForAddr(cursor, ide, entry_index); + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, ide); +} + +XPT_PUBLIC_API(XPTInterfaceDescriptor *) +XPT_NewInterfaceDescriptor(XPTArena *arena, + PRUint16 parent_interface, PRUint16 num_methods, + PRUint16 num_constants, PRUint8 flags) +{ + + XPTInterfaceDescriptor *id = XPT_NEWZAP(arena, XPTInterfaceDescriptor); + if (!id) + return NULL; + + if (num_methods) { + id->method_descriptors = XPT_CALLOC(arena, num_methods * + sizeof(XPTMethodDescriptor)); + if (!id->method_descriptors) + goto free_id; + id->num_methods = num_methods; + } + + if (num_constants) { + id->const_descriptors = XPT_CALLOC(arena, num_constants * + sizeof(XPTConstDescriptor)); + if (!id->const_descriptors) + goto free_meth; + id->num_constants = num_constants; + } + + if (parent_interface) { + id->parent_interface = parent_interface; + } else { + id->parent_interface = 0; + } + + id->flags = flags; + + return id; + + free_meth: + XPT_FREEIF(arena, id->method_descriptors); + free_id: + XPT_DELETE(arena, id); + return NULL; +} + +XPT_PUBLIC_API(void) +XPT_FreeInterfaceDescriptor(XPTArena *arena, XPTInterfaceDescriptor* id) +{ + if (id) { + XPTMethodDescriptor *md, *mdend; + XPTConstDescriptor *cd, *cdend; + + /* Free up method descriptors */ + md = id->method_descriptors; + mdend = md + id->num_methods; + for (; md < mdend; md++) { + XPT_FREEIF(arena, md->name); + XPT_FREEIF(arena, md->params); + XPT_FREEIF(arena, md->result); + } + XPT_FREEIF(arena, id->method_descriptors); + + /* Free up const descriptors */ + cd = id->const_descriptors; + cdend = cd + id->num_constants; + for (; cd < cdend; cd++) { + XPT_FREEIF(arena, cd->name); + } + XPT_FREEIF(arena, id->const_descriptors); + + /* Free up type descriptors */ + XPT_FREEIF(arena, id->additional_types); + + XPT_DELETE(arena, id); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddTypes(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTTypeDescriptor *old = id->additional_types; + XPTTypeDescriptor *new; + size_t old_size = id->num_additional_types * sizeof(XPTTypeDescriptor); + size_t new_size = (num * sizeof(XPTTypeDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->additional_types = new; + id->num_additional_types += num; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddMethods(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTMethodDescriptor *old = id->method_descriptors; + XPTMethodDescriptor *new; + size_t old_size = id->num_methods * sizeof(XPTMethodDescriptor); + size_t new_size = (num * sizeof(XPTMethodDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->method_descriptors = new; + id->num_methods += num; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_InterfaceDescriptorAddConsts(XPTArena *arena, XPTInterfaceDescriptor *id, + PRUint16 num) +{ + XPTConstDescriptor *old = id->const_descriptors; + XPTConstDescriptor *new; + size_t old_size = id->num_constants * sizeof(XPTConstDescriptor); + size_t new_size = (num * sizeof(XPTConstDescriptor)) + old_size; + + /* XXX should grow in chunks to minimize alloc overhead */ + new = XPT_CALLOC(arena, new_size); + if (!new) + return PR_FALSE; + if (old) { + if (old_size) + memcpy(new, old, old_size); + XPT_FREE(arena, old); + } + id->const_descriptors = new; + id->num_constants += num; + return PR_TRUE; +} + +PRUint32 +SizeOfTypeDescriptor(XPTTypeDescriptor *td, XPTInterfaceDescriptor *id) +{ + PRUint32 size = 1; /* prefix */ + + switch (XPT_TDP_TAG(td->prefix)) { + case TD_INTERFACE_TYPE: + size += 2; /* interface_index */ + break; + case TD_INTERFACE_IS_TYPE: + size += 1; /* argnum */ + break; + case TD_ARRAY: + size += 2 + SizeOfTypeDescriptor( + &id->additional_types[td->type.additional_type], id); + break; + case TD_PSTRING_SIZE_IS: + size += 2; /* argnum + argnum2 */ + break; + case TD_PWSTRING_SIZE_IS: + size += 2; /* argnum + argnum2 */ + break; + default: + /* nothing special */ + break; + } + return size; +} + +PRUint32 +SizeOfMethodDescriptor(XPTMethodDescriptor *md, XPTInterfaceDescriptor *id) +{ + PRUint32 i, size = 1 /* flags */ + 4 /* name */ + 1 /* num_args */; + + for (i = 0; i < md->num_args; i++) + size += 1 + SizeOfTypeDescriptor(&md->params[i].type, id); + + size += 1 + SizeOfTypeDescriptor(&md->result->type, id); + return size; +} + +PRUint32 +SizeOfConstDescriptor(XPTConstDescriptor *cd, XPTInterfaceDescriptor *id) +{ + PRUint32 size = 4 /* name */ + SizeOfTypeDescriptor(&cd->type, id); + + switch (XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + case TD_UINT8: + case TD_CHAR: + size ++; + break; + case TD_INT16: + case TD_UINT16: + case TD_WCHAR: + size += 2; + break; + case TD_INT32: + case TD_UINT32: + case TD_PSTRING: + size += 4; + break; + case TD_INT64: + case TD_UINT64: + size += 8; + break; + default: + fprintf(stderr, "libxpt: illegal type in ConstDescriptor: 0x%02x\n", + XPT_TDP_TAG(cd->type.prefix)); + return 0; + } + + return size; +} + +PRUint32 +SizeOfInterfaceDescriptor(XPTInterfaceDescriptor *id) +{ + PRUint32 size = 2 /* parent interface */ + 2 /* num_methods */ + + 2 /* num_constants */ + 1 /* flags */, i; + for (i = 0; i < id->num_methods; i++) + size += SizeOfMethodDescriptor(&id->method_descriptors[i], id); + for (i = 0; i < id->num_constants; i++) + size += SizeOfConstDescriptor(&id->const_descriptors[i], id); + return size; +} + +PRBool +DoInterfaceDescriptor(XPTArena *arena, XPTCursor *outer, + XPTInterfaceDescriptor **idp) +{ + XPTMode mode = outer->state->mode; + XPTInterfaceDescriptor *id; + XPTCursor curs, *cursor = &curs; + PRUint32 i, id_sz = 0; + + if (mode == XPT_DECODE) { + id = XPT_NEWZAP(arena, XPTInterfaceDescriptor); + if (!id) + return PR_FALSE; + *idp = id; + } else { + id = *idp; + if (!id) { + id_sz = 0; + return XPT_Do32(outer, &id_sz); + } + id_sz = SizeOfInterfaceDescriptor(id); + } + + if (!XPT_MakeCursor(outer->state, XPT_DATA, id_sz, cursor)) + goto error; + + if (!XPT_Do32(outer, &cursor->offset)) + goto error; + if (mode == XPT_DECODE && !cursor->offset) { + XPT_DELETE(arena, *idp); + return PR_TRUE; + } + if(!XPT_Do16(cursor, &id->parent_interface) || + !XPT_Do16(cursor, &id->num_methods)) { + goto error; + } + + if (mode == XPT_DECODE && id->num_methods) { + id->method_descriptors = XPT_CALLOC(arena, id->num_methods * + sizeof(XPTMethodDescriptor)); + if (!id->method_descriptors) + goto error; + } + + for (i = 0; i < id->num_methods; i++) { + if (!DoMethodDescriptor(arena, cursor, &id->method_descriptors[i], id)) + goto error; + } + + if (!XPT_Do16(cursor, &id->num_constants)) { + goto error; + } + + if (mode == XPT_DECODE && id->num_constants) { + id->const_descriptors = XPT_CALLOC(arena, id->num_constants * + sizeof(XPTConstDescriptor)); + if (!id->const_descriptors) + goto error; + } + + for (i = 0; i < id->num_constants; i++) { + if (!DoConstDescriptor(arena, cursor, &id->const_descriptors[i], id)) { + goto error; + } + } + + if (!XPT_Do8(cursor, &id->flags)) { + goto error; + } + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, id); +} + +PRBool +DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id) +{ + PRBool ok = PR_FALSE; + + if (!XPT_DoCString(arena, cursor, &cd->name) || + !DoTypeDescriptor(arena, cursor, &cd->type, id)) { + + return PR_FALSE; + } + + switch(XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + ok = XPT_Do8(cursor, (PRUint8*) &cd->value.i8); + break; + case TD_INT16: + ok = XPT_Do16(cursor, (PRUint16*) &cd->value.i16); + break; + case TD_INT32: + ok = XPT_Do32(cursor, (PRUint32*) &cd->value.i32); + break; + case TD_INT64: + ok = XPT_Do64(cursor, &cd->value.i64); + break; + case TD_UINT8: + ok = XPT_Do8(cursor, &cd->value.ui8); + break; + case TD_UINT16: + ok = XPT_Do16(cursor, &cd->value.ui16); + break; + case TD_UINT32: + ok = XPT_Do32(cursor, &cd->value.ui32); + break; + case TD_UINT64: + ok = XPT_Do64(cursor, (PRInt64 *)&cd->value.ui64); + break; + case TD_CHAR: + ok = XPT_Do8(cursor, (PRUint8*) &cd->value.ch); + break; + case TD_WCHAR: + ok = XPT_Do16(cursor, &cd->value.wch); + break; + /* fall-through */ + default: + fprintf(stderr, "illegal type!\n"); + break; + } + + return ok; + +} + +XPT_PUBLIC_API(PRBool) +XPT_FillMethodDescriptor(XPTArena *arena, XPTMethodDescriptor *meth, + PRUint8 flags, char *name, PRUint8 num_args) +{ + meth->flags = flags & XPT_MD_FLAGMASK; + meth->name = XPT_STRDUP(arena, name); + if (!meth->name) + return PR_FALSE; + meth->num_args = num_args; + if (num_args) { + meth->params = XPT_CALLOC(arena, num_args * sizeof(XPTParamDescriptor)); + if (!meth->params) + goto free_name; + } else { + meth->params = NULL; + } + meth->result = XPT_NEWZAP(arena, XPTParamDescriptor); + if (!meth->result) + goto free_params; + return PR_TRUE; + + free_params: + XPT_DELETE(arena, meth->params); + free_name: + XPT_DELETE(arena, meth->name); + return PR_FALSE; +} + +PRBool +DoMethodDescriptor(XPTArena *arena, XPTCursor *cursor, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id) +{ + XPTMode mode = cursor->state->mode; + int i; + + if (!XPT_Do8(cursor, &md->flags) || + !XPT_DoCString(arena, cursor, &md->name) || + !XPT_Do8(cursor, &md->num_args)) + return PR_FALSE; + + if (mode == XPT_DECODE && md->num_args) { + md->params = XPT_CALLOC(arena, md->num_args * sizeof(XPTParamDescriptor)); + if (!md->params) + return PR_FALSE; + } + + for(i = 0; i < md->num_args; i++) { + if (!DoParamDescriptor(arena, cursor, &md->params[i], id)) + goto error; + } + + if (mode == XPT_DECODE) { + md->result = XPT_NEWZAP(arena, XPTParamDescriptor); + if (!md->result) + return PR_FALSE; + } + + if (!md->result || + !DoParamDescriptor(arena, cursor, md->result, id)) + goto error; + + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, md->params); +} + +XPT_PUBLIC_API(PRBool) +XPT_FillParamDescriptor(XPTArena *arena, XPTParamDescriptor *pd, PRUint8 flags, + XPTTypeDescriptor *type) +{ + pd->flags = flags & XPT_PD_FLAGMASK; + XPT_COPY_TYPE(pd->type, *type); + return PR_TRUE; +} + +PRBool +DoParamDescriptor(XPTArena *arena, XPTCursor *cursor, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id) +{ + if (!XPT_Do8(cursor, &pd->flags) || + !DoTypeDescriptor(arena, cursor, &pd->type, id)) + return PR_FALSE; + + return PR_TRUE; +} + +PRBool +DoTypeDescriptorPrefix(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptorPrefix *tdp) +{ + return XPT_Do8(cursor, &tdp->flags); +} + +PRBool +DoTypeDescriptor(XPTArena *arena, XPTCursor *cursor, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id) +{ + if (!DoTypeDescriptorPrefix(arena, cursor, &td->prefix)) { + goto error; + } + + switch (XPT_TDP_TAG(td->prefix)) { + case TD_INTERFACE_TYPE: + if (!XPT_Do16(cursor, &td->type.iface)) + goto error; + break; + case TD_INTERFACE_IS_TYPE: + if (!XPT_Do8(cursor, &td->argnum)) + goto error; + break; + case TD_ARRAY: + if (!XPT_Do8(cursor, &td->argnum) || + !XPT_Do8(cursor, &td->argnum2)) + goto error; + + if (cursor->state->mode == XPT_DECODE) { + if(!XPT_InterfaceDescriptorAddTypes(arena, id, 1)) + goto error; + td->type.additional_type = id->num_additional_types - 1; + } + + if (!DoTypeDescriptor(arena, cursor, + &id->additional_types[td->type.additional_type], + id)) + goto error; + break; + case TD_PSTRING_SIZE_IS: + case TD_PWSTRING_SIZE_IS: + if (!XPT_Do8(cursor, &td->argnum) || + !XPT_Do8(cursor, &td->argnum2)) + goto error; + break; + + default: + /* nothing special */ + break; + } + return PR_TRUE; + + XPT_ERROR_HANDLE(arena, td); +} + +XPT_PUBLIC_API(XPTAnnotation *) +XPT_NewAnnotation(XPTArena *arena, PRUint8 flags, XPTString *creator, + XPTString *private_data) +{ + XPTAnnotation *ann = XPT_NEWZAP(arena, XPTAnnotation); + if (!ann) + return NULL; + ann->flags = flags; + if (XPT_ANN_IS_PRIVATE(flags)) { + ann->creator = creator; + ann->private_data = private_data; + } + return ann; +} + +PRBool +DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp) +{ + XPTMode mode = cursor->state->mode; + XPTAnnotation *ann; + + if (mode == XPT_DECODE) { + ann = XPT_NEWZAP(arena, XPTAnnotation); + if (!ann) + return PR_FALSE; + *annp = ann; + } else { + ann = *annp; + } + + if (!XPT_Do8(cursor, &ann->flags)) + goto error; + + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + if (!XPT_DoStringInline(arena, cursor, &ann->creator) || + !XPT_DoStringInline(arena, cursor, &ann->private_data)) + goto error_2; + } + + return PR_TRUE; + + error_2: + if (ann && XPT_ANN_IS_PRIVATE(ann->flags)) { + XPT_FREEIF(arena, ann->creator); + XPT_FREEIF(arena, ann->private_data); + } + XPT_ERROR_HANDLE(arena, ann); +} + +PRBool +XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block, + PRUint16 num_interfaces, char *name, + PRUint16 *indexp) +{ + int i; + + for (i=1; i<=num_interfaces; i++) { + fprintf(stderr, "%s == %s ?\n", ide_block[i].name, name); + if (strcmp(ide_block[i].name, name) == 0) { + *indexp = i; + return PR_TRUE; + } + } + *indexp = 0; + return PR_FALSE; +} + +static XPT_TYPELIB_VERSIONS_STRUCT versions[] = XPT_TYPELIB_VERSIONS; +#define XPT_TYPELIB_VERSIONS_COUNT (sizeof(versions) / sizeof(versions[0])) + +XPT_PUBLIC_API(PRUint16) +XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor) +{ + int i; + for (i = 0; i < XPT_TYPELIB_VERSIONS_COUNT; i++) { + if (!strcmp(versions[i].str, str)) { + *major = versions[i].major; + *minor = versions[i].minor; + return versions[i].code; + } + } + return XPT_VERSION_UNKNOWN; +} + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c new file mode 100644 index 00000000..cd9261d0 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/src/xpt_xdr.c @@ -0,0 +1,665 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Implementation of XDR primitives. */ + +#include "xpt_xdr.h" +#include "nspr.h" +#include /* strchr */ + +static PRBool +CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len, + XPTCursor *new_cursor, PRBool *already); + +#define ENCODING(cursor) \ + ((cursor)->state->mode == XPT_ENCODE) + +#define CURS_POOL_OFFSET_RAW(cursor) \ + ((cursor)->pool == XPT_HEADER \ + ? (cursor)->offset \ + : (XPT_ASSERT((cursor)->state->data_offset), \ + (cursor)->offset + (cursor)->state->data_offset)) + +#define CURS_POOL_OFFSET(cursor) \ + (CURS_POOL_OFFSET_RAW(cursor) - 1) + +/* can be used as lvalue */ +#define CURS_POINT(cursor) \ + ((cursor)->state->pool->data[CURS_POOL_OFFSET(cursor)]) + +#if defined(DEBUG_shaver) || defined(DEBUG_jband) || defined(DEBUG_mccabe) +#define DBG(x) printf##x +#else +#define DBG(x) (0) +#endif + +/* XXX fail if XPT_DATA and !state->data_offset */ +#define CHECK_COUNT_(cursor, space) \ + /* if we're in the header, then exceeding the data_offset is illegal */ \ +((cursor)->pool == XPT_HEADER ? \ + (ENCODING(cursor) && \ + ((cursor)->state->data_offset && \ + ((cursor)->offset - 1 + (space) > (cursor)->state->data_offset)) \ + ? (DBG(("no space left in HEADER %d + %d > %d\n", (cursor)->offset, \ + (space), (cursor)->state->data_offset)) && PR_FALSE) \ + : PR_TRUE) : \ + /* if we're in the data area and we're about to exceed the allocation */ \ + (CURS_POOL_OFFSET(cursor) + (space) > (cursor)->state->pool->allocated ? \ + /* then grow if we're in ENCODE mode */ \ + (ENCODING(cursor) ? GrowPool((cursor)->state->arena, \ + (cursor)->state->pool, \ + (cursor)->state->pool->allocated, \ + 0, CURS_POOL_OFFSET(cursor) + (space)) \ + /* and fail if we're in DECODE mode */ \ + : (DBG(("can't extend in DECODE")) && PR_FALSE)) \ + /* otherwise we're OK */ \ + : PR_TRUE)) + +#define CHECK_COUNT(cursor, space) \ + (CHECK_COUNT_(cursor, space) \ + ? PR_TRUE \ + : (XPT_ASSERT(0), \ + fprintf(stderr, "FATAL: can't no room for %d in cursor\n", space), \ + PR_FALSE)) + +/* increase the data allocation for the pool by XPT_GROW_CHUNK */ +#define XPT_GROW_CHUNK 8192 + +/* + * quick and dirty hardcoded hashtable, to avoid dependence on nspr or glib. + * XXXmccabe it might turn out that we could use a simpler data structure here. + */ +typedef struct XPTHashRecord { + void *key; + void *value; + struct XPTHashRecord *next; +} XPTHashRecord; + +#define XPT_HASHSIZE 512 + +struct XPTHashTable { /* it's already typedef'ed from before. */ + XPTHashRecord *buckets[XPT_HASHSIZE]; + XPTArena *arena; +}; + +static XPTHashTable * +XPT_NewHashTable(XPTArena *arena) { + XPTHashTable *table; + table = XPT_NEWZAP(arena, XPTHashTable); + if (table) + table->arena = arena; + return table; +} + +static void trimrecord(XPTArena* arena, XPTHashRecord *record) { + if (record == NULL) + return; + trimrecord(arena, record->next); + XPT_DELETE(arena, record); +} + +static void +XPT_HashTableDestroy(XPTHashTable *table) { + int i; + for (i = 0; i < XPT_HASHSIZE; i++) + trimrecord(table->arena, table->buckets[i]); + XPT_FREE(table->arena, table); +} + +static void * +XPT_HashTableAdd(XPTHashTable *table, void *key, void *value) { + XPTHashRecord **bucketloc = table->buckets + + (((PRUint32)(uintptr_t)key) % XPT_HASHSIZE); + XPTHashRecord *bucket; + + while (*bucketloc != NULL) + bucketloc = &((*bucketloc)->next); + + bucket = XPT_NEW(table->arena, XPTHashRecord); + bucket->key = key; + bucket->value = value; + bucket->next = NULL; + *bucketloc = bucket; + return value; +} + +static void * +XPT_HashTableLookup(XPTHashTable *table, void *key) { + XPTHashRecord *bucket = table->buckets[(PRUint32)(uintptr_t)key % XPT_HASHSIZE]; + while (bucket != NULL) { + if (bucket->key == key) + return bucket->value; + bucket = bucket->next; + } + return NULL; +} + +XPT_PUBLIC_API(XPTState *) +XPT_NewXDRState(XPTMode mode, char *data, PRUint32 len) +{ + XPTState *state; + XPTArena *arena; + + arena = XPT_NewArena(512, sizeof(double), "an XDRState"); + if (!arena) + return NULL; + + state = XPT_NEWZAP(arena, XPTState); + if (!state) + goto err_free_arena; + + state->arena = arena; + state->mode = mode; + state->pool = XPT_NEW(arena, XPTDatapool); + state->next_cursor[0] = state->next_cursor[1] = 1; + if (!state->pool) + goto err_free_state; + + state->pool->count = 0; + state->pool->offset_map = XPT_NewHashTable(arena); + + if (!state->pool->offset_map) + goto err_free_pool; + if (mode == XPT_DECODE) { + state->pool->data = data; + state->pool->allocated = len; + } else { + state->pool->data = XPT_MALLOC(arena, XPT_GROW_CHUNK); + if (!state->pool->data) + goto err_free_hash; + state->pool->allocated = XPT_GROW_CHUNK; + } + + return state; + + err_free_hash: + XPT_HashTableDestroy(state->pool->offset_map); + err_free_pool: + XPT_DELETE(arena, state->pool); + err_free_state: + XPT_DELETE(arena, state); + err_free_arena: + if (arena) + XPT_DestroyArena(arena); + return NULL; +} + +XPT_PUBLIC_API(void) +XPT_DestroyXDRState(XPTState *state) +{ + XPTArena *arena = state->arena; + + if (state->pool->offset_map) + XPT_HashTableDestroy(state->pool->offset_map); + if (state->mode == XPT_ENCODE) + XPT_DELETE(arena, state->pool->data); + XPT_DELETE(arena, state->pool); + XPT_DELETE(arena, state); + if (arena) + XPT_DestroyArena(arena); +} + +XPT_PUBLIC_API(void) +XPT_GetXDRDataLength(XPTState *state, XPTPool pool, PRUint32 *len) +{ + *len = state->next_cursor[pool] - 1; +} + +XPT_PUBLIC_API(void) +XPT_GetXDRData(XPTState *state, XPTPool pool, char **data, PRUint32 *len) +{ + if (pool == XPT_HEADER) { + *data = state->pool->data; + } else { + *data = state->pool->data + state->data_offset; + } + *len = state->next_cursor[pool] - 1; +} + +/* All offsets are 1-based */ +XPT_PUBLIC_API(void) +XPT_DataOffset(XPTState *state, PRUint32 *data_offsetp) +{ + if (state->mode == XPT_DECODE) + XPT_SetDataOffset(state, *data_offsetp); + else + *data_offsetp = state->data_offset; +} + +/* if 'exact' is set use that, else grow by the next chunk but + * be sure to grow no less that 'at_least' so that we can't get + * behind on required space. + */ +static PRBool +GrowPool(XPTArena *arena, XPTDatapool *pool, PRUint32 old_size, + PRUint32 exact, PRUint32 at_least) +{ + PRUint32 total_size; + char *newdata; + + if (exact) { + XPT_ASSERT(exact > pool->allocated); + total_size = exact; + } else { + total_size = pool->allocated + XPT_GROW_CHUNK; + if (at_least > total_size) + total_size = at_least; + } + + newdata = XPT_MALLOC(arena, total_size); + if (!newdata) + return PR_FALSE; + if (pool->data) { + if (old_size) + memcpy(newdata, pool->data, old_size); + XPT_FREE(arena, pool->data); + } + pool->data = newdata; + pool->allocated = total_size; + return PR_TRUE; +} + +XPT_PUBLIC_API(void) +XPT_SetDataOffset(XPTState *state, PRUint32 data_offset) +{ + state->data_offset = data_offset; + /* make sure we've allocated enough space for the header */ + if (state->mode == XPT_ENCODE && + data_offset > state->pool->allocated) { + (void)GrowPool(state->arena, state->pool, state->pool->allocated, + data_offset, 0); + } +} + +XPT_PUBLIC_API(PRBool) +XPT_MakeCursor(XPTState *state, XPTPool pool, PRUint32 len, XPTCursor *cursor) +{ + cursor->state = state; + cursor->pool = pool; + cursor->bits = 0; + cursor->offset = state->next_cursor[pool]; + + if (!(CHECK_COUNT(cursor, len))) + return PR_FALSE; + + /* this check should be in CHECK_CURSOR */ + if (pool == XPT_DATA && !state->data_offset) { + fprintf(stderr, "no data offset for XPT_DATA cursor!\n"); + return PR_FALSE; + } + + state->next_cursor[pool] += len; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_SeekTo(XPTCursor *cursor, PRUint32 offset) +{ + /* XXX do some real checking and update len and stuff */ + cursor->offset = offset; + return PR_TRUE; +} + +XPT_PUBLIC_API(XPTString *) +XPT_NewString(XPTArena *arena, PRUint16 length, char *bytes) +{ + XPTString *str = XPT_NEW(arena, XPTString); + if (!str) + return NULL; + str->length = length; + /* Alloc one extra to store the trailing nul. */ + str->bytes = XPT_MALLOC(arena, length + 1u); + if (!str->bytes) { + XPT_DELETE(arena, str); + return NULL; + } + memcpy(str->bytes, bytes, length); + /* nul-terminate it. */ + str->bytes[length] = '\0'; + return str; +} + +XPT_PUBLIC_API(XPTString *) +XPT_NewStringZ(XPTArena *arena, char *bytes) +{ + PRUint32 length = strlen(bytes); + if (length > 0xffff) + return NULL; /* too long */ + return XPT_NewString(arena, (PRUint16)length, bytes); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoStringInline(XPTArena *arena, XPTCursor *cursor, XPTString **strp) +{ + XPTString *str = *strp; + XPTMode mode = cursor->state->mode; + int i; + + if (mode == XPT_DECODE) { + str = XPT_NEWZAP(arena, XPTString); + if (!str) + return PR_FALSE; + *strp = str; + } + + if (!XPT_Do16(cursor, &str->length)) + goto error; + + if (mode == XPT_DECODE) + if (!(str->bytes = XPT_MALLOC(arena, str->length + 1u))) + goto error; + + for (i = 0; i < str->length; i++) + if (!XPT_Do8(cursor, (PRUint8 *)&str->bytes[i])) + goto error_2; + + if (mode == XPT_DECODE) + str->bytes[str->length] = 0; + + return PR_TRUE; + error_2: + XPT_DELETE(arena, str->bytes); + error: + XPT_DELETE(arena, str); + return PR_FALSE; +} + +XPT_PUBLIC_API(PRBool) +XPT_DoString(XPTArena *arena, XPTCursor *cursor, XPTString **strp) +{ + XPTCursor my_cursor; + XPTString *str = *strp; + PRBool already; + + XPT_PREAMBLE_NO_ALLOC(cursor, strp, XPT_DATA, str->length + 2, my_cursor, + already) + + return XPT_DoStringInline(arena, &my_cursor, strp); +} + +XPT_PUBLIC_API(PRBool) +XPT_DoCString(XPTArena *arena, XPTCursor *cursor, char **identp) +{ + XPTCursor my_cursor; + char *ident = *identp; + PRUint32 offset = 0; + + XPTMode mode = cursor->state->mode; + + if (mode == XPT_DECODE) { + char *start, *end; + int len; + + if (!XPT_Do32(cursor, &offset)) + return PR_FALSE; + + if (!offset) { + *identp = NULL; + return PR_TRUE; + } + + my_cursor.pool = XPT_DATA; + my_cursor.offset = offset; + my_cursor.state = cursor->state; + start = &CURS_POINT(&my_cursor); + + end = strchr(start, 0); /* find the end of the string */ + if (!end) { + fprintf(stderr, "didn't find end of string on decode!\n"); + return PR_FALSE; + } + len = end - start; + XPT_ASSERT(len > 0); + + ident = XPT_MALLOC(arena, len + 1u); + if (!ident) + return PR_FALSE; + + memcpy(ident, start, (size_t)len); + ident[len] = 0; + *identp = ident; + + } else { + + if (!ident) { + offset = 0; + if (!XPT_Do32(cursor, &offset)) + return PR_FALSE; + return PR_TRUE; + } + + if (!XPT_MakeCursor(cursor->state, XPT_DATA, strlen(ident) + 1, + &my_cursor) || + !XPT_Do32(cursor, &my_cursor.offset)) + return PR_FALSE; + + while(*ident) + if (!XPT_Do8(&my_cursor, (PRUint8 *)ident++)) + return PR_FALSE; + if (!XPT_Do8(&my_cursor, (PRUint8 *)ident)) /* write trailing zero */ + return PR_FALSE; + } + + return PR_TRUE; +} + +/* XXXjband it bothers me that this is one hashtable instead of two. + */ +XPT_PUBLIC_API(PRUint32) +XPT_GetOffsetForAddr(XPTCursor *cursor, void *addr) +{ + return (PRUint32)(uintptr_t)XPT_HashTableLookup(cursor->state->pool->offset_map, addr); +} + +XPT_PUBLIC_API(PRBool) +XPT_SetOffsetForAddr(XPTCursor *cursor, void *addr, PRUint32 offset) +{ + return XPT_HashTableAdd(cursor->state->pool->offset_map, + addr, (void *)(uintptr_t)offset) != NULL; +} + +XPT_PUBLIC_API(PRBool) +XPT_SetAddrForOffset(XPTCursor *cursor, PRUint32 offset, void *addr) +{ + return XPT_HashTableAdd(cursor->state->pool->offset_map, + (void *)(uintptr_t)offset, addr) != NULL; +} + +XPT_PUBLIC_API(void *) +XPT_GetAddrForOffset(XPTCursor *cursor, PRUint32 offset) +{ + return XPT_HashTableLookup(cursor->state->pool->offset_map, (void *)(uintptr_t)offset); +} + +/* Used by XPT_PREAMBLE_NO_ALLOC. */ +static PRBool +CheckForRepeat(XPTCursor *cursor, void **addrp, XPTPool pool, PRUint32 len, + XPTCursor *new_cursor, PRBool *already) +{ + void *last = *addrp; + + *already = PR_FALSE; + new_cursor->state = cursor->state; + new_cursor->pool = pool; + new_cursor->bits = 0; + + if (cursor->state->mode == XPT_DECODE) { + + last = XPT_GetAddrForOffset(new_cursor, new_cursor->offset); + + if (last) { + *already = PR_TRUE; + *addrp = last; + } + + } else { + + new_cursor->offset = XPT_GetOffsetForAddr(new_cursor, last); + if (new_cursor->offset) { + *already = PR_TRUE; + return PR_TRUE; + } + + /* haven't already found it, so allocate room for it. */ + if (!XPT_MakeCursor(cursor->state, pool, len, new_cursor) || + !XPT_SetOffsetForAddr(new_cursor, *addrp, new_cursor->offset)) + return PR_FALSE; + } + return PR_TRUE; +} + +/* + * IIDs are written in struct order, in the usual big-endian way. From the + * typelib file spec: + * + * "For example, this IID: + * {00112233-4455-6677-8899-aabbccddeeff} + * is converted to the 128-bit value + * 0x00112233445566778899aabbccddeeff + * Note that the byte storage order corresponds to the layout of the nsIID + * C-struct on a big-endian architecture." + * + * (http://www.mozilla.org/scriptable/typelib_file.html#iid) + */ +XPT_PUBLIC_API(PRBool) +XPT_DoIID(XPTCursor *cursor, nsID *iidp) +{ + int i; + + if (!XPT_Do32(cursor, &iidp->m0) || + !XPT_Do16(cursor, &iidp->m1) || + !XPT_Do16(cursor, &iidp->m2)) + return PR_FALSE; + + for (i = 0; i < 8; i++) + if (!XPT_Do8(cursor, (PRUint8 *)&iidp->m3[i])) + return PR_FALSE; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do64(XPTCursor *cursor, PRInt64 *u64p) +{ + return XPT_Do32(cursor, (PRUint32 *)u64p) && + XPT_Do32(cursor, ((PRUint32 *)u64p) + 1); +} + +/* + * When we're writing 32- or 16-bit quantities, we write a byte at a time to + * avoid alignment issues. Someone could come and optimize this to detect + * well-aligned cases and do a single store, if they cared. I might care + * later. + */ +XPT_PUBLIC_API(PRBool) +XPT_Do32(XPTCursor *cursor, PRUint32 *u32p) +{ + union { + PRUint8 b8[4]; + PRUint32 b32; + } u; + + if (!CHECK_COUNT(cursor, 4)) + return PR_FALSE; + + if (ENCODING(cursor)) { + u.b32 = XPT_SWAB32(*u32p); + CURS_POINT(cursor) = u.b8[0]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[1]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[2]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[3]; + } else { + u.b8[0] = CURS_POINT(cursor); + cursor->offset++; + u.b8[1] = CURS_POINT(cursor); + cursor->offset++; + u.b8[2] = CURS_POINT(cursor); + cursor->offset++; + u.b8[3] = CURS_POINT(cursor); + *u32p = XPT_SWAB32(u.b32); + } + cursor->offset++; + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do16(XPTCursor *cursor, PRUint16 *u16p) +{ + union { + PRUint8 b8[2]; + PRUint16 b16; + } u; + + if (!CHECK_COUNT(cursor, 2)) + return PR_FALSE; + + if (ENCODING(cursor)) { + u.b16 = XPT_SWAB16(*u16p); + CURS_POINT(cursor) = u.b8[0]; + cursor->offset++; + CURS_POINT(cursor) = u.b8[1]; + } else { + u.b8[0] = CURS_POINT(cursor); + cursor->offset++; + u.b8[1] = CURS_POINT(cursor); + *u16p = XPT_SWAB16(u.b16); + } + cursor->offset++; + + return PR_TRUE; +} + +XPT_PUBLIC_API(PRBool) +XPT_Do8(XPTCursor *cursor, PRUint8 *u8p) +{ + if (!CHECK_COUNT(cursor, 1)) + return PR_FALSE; + if (cursor->state->mode == XPT_ENCODE) + CURS_POINT(cursor) = *u8p; + else + *u8p = CURS_POINT(cursor); + + cursor->offset++; + + return PR_TRUE; +} + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore new file mode 100644 index 00000000..ebc62d94 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/.cvsignore @@ -0,0 +1,3 @@ +Makefile +PrimitiveTest +SimpleTypeLib diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in new file mode 100644 index 00000000..afdc31b3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/Makefile.in @@ -0,0 +1,59 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +CPP_PROG_LINK = 1 + +SIMPLE_PROGRAMS = PrimitiveTest$(BIN_SUFFIX) SimpleTypeLib$(BIN_SUFFIX) + +CSRCS = PrimitiveTest.c SimpleTypeLib.c + +LIBS = \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +include $(topsrcdir)/config/rules.mk + +DEFINES += -DEXPORT_XPT_API diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c new file mode 100644 index 00000000..aad33ccc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/PrimitiveTest.c @@ -0,0 +1,157 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Test the xdr primitives from xpt_xdr.c */ + +#include "xpt_xdr.h" +#include +#include /* for memcpy */ + +#define PASS(msg) \ + fprintf(stderr, "PASSED : %s\n", msg); + +#define FAIL(msg) \ + fprintf(stderr, "FAILURE: %s\n", msg); + +#define TRY_(msg, cond, silent) \ + if ((cond) && !silent) { \ + PASS(msg); \ + } else { \ + FAIL(msg); \ + return 1; \ + } + +#define TRY(msg, cond) TRY_(msg, cond, 0) +#define TRY_Q(msg, cond) TRY_(msg, cond, 1); + +XPTString in_str = { 4, "bazz" }; + +struct TestData { + PRUint32 bit32; + PRUint16 bit16; + PRUint8 bit8[2]; + char *cstr; + XPTString *str; +} input = { 0xdeadbeef, 0xcafe, {0xba, 0xbe}, "foobar", &in_str}, + output = {0, 0, {0, 0}, NULL, NULL }; + +void +dump_struct(char *label, struct TestData *str) +{ + fprintf(stderr, "%s: {%#08x, %#04x, {%#02x, %#02x}, %s, %d/%s}\n", + label, str->bit32, str->bit16, str->bit8[0], str->bit8[1], + str->cstr, str->str->length, str->str->bytes); +} + +PRBool +XDR(XPTArena *arena, XPTCursor *cursor, struct TestData *str) +{ + TRY("Do32", XPT_Do32(cursor, &str->bit32)); + TRY("Do16", XPT_Do16(cursor, &str->bit16)); + TRY("Do8", XPT_Do8 (cursor, &str->bit8[0])); + TRY("Do8", XPT_Do8 (cursor, &str->bit8[1])); + TRY("DoCString", XPT_DoCString(arena, cursor, &str->cstr)); + TRY("DoString", XPT_DoString(arena, cursor, &str->str)); + return 0; +} + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + char *header, *data, *whole; + PRUint32 hlen, dlen, i; + + TRY("XPT_NewArena", (arena = XPT_NewArena(1024, sizeof(double), "main"))); + + TRY("NewState (ENCODE)", (state = XPT_NewXDRState(XPT_ENCODE, NULL, 0))); + + XPT_SetDataOffset(state, sizeof input); + + TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor)); + + dump_struct("before", &input); + + if (XDR(arena, cursor, &input)) + return 1; + + fprintf(stderr, "ENCODE successful\n"); + XPT_GetXDRData(state, XPT_HEADER, &header, &hlen); + fprintf(stderr, "XDR header %d bytes at %p:", + hlen, header); + for (i = 0; i < hlen; i++) + fprintf(stderr, "%c%02x", i ? ',' : ' ', (uint8)header[i]); + fprintf(stderr, "\n"); + + XPT_GetXDRData(state, XPT_DATA, &data, &dlen); + + fprintf(stderr, "XDR data %d bytes at %p:", + dlen, data); + for (i = 0; i < dlen; i++) + fprintf(stderr, "%c%02x/%c", i ? ',' : ' ', (uint8)data[i], + (uint8)data[i]); + fprintf(stderr, "\n"); + + whole = malloc(dlen + hlen); + if (!whole) { + fprintf(stderr, "malloc %d failed!\n", dlen + hlen); + return 1; + } + + /* TRY_Q("malloc", (data2 = malloc(len))); */ + memcpy(whole, header, hlen); + memcpy(whole + hlen, data, dlen); + XPT_DestroyXDRState(state); + + TRY("NewState (DECODE)", (state = XPT_NewXDRState(XPT_DECODE, whole, + hlen + dlen))); + + TRY("MakeCursor", XPT_MakeCursor(state, XPT_HEADER, sizeof input, cursor)); + XPT_SetDataOffset(state, sizeof input); + + if (XDR(arena, cursor, &output)) + return 1; + + dump_struct("after", &output); + XPT_DestroyXDRState(state); + XPT_DestroyArena(arena); + free(whole); + + return 0; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c new file mode 100644 index 00000000..305b8520 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tests/SimpleTypeLib.c @@ -0,0 +1,192 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Test the structure creation and serialization APIs from xpt_struct.c */ +#include + +#include "xpt_xdr.h" +#include "xpt_struct.h" + +#define PASS(msg) \ + fprintf(stderr, "PASSED : %s\n", msg); + +#define FAIL(msg) \ + fprintf(stderr, "FAILURE: %s\n", msg); + +#define TRY_(msg, cond, silent) \ + if ((cond) && !silent) { \ + PASS(msg); \ + } else { \ + FAIL(msg); \ + return 1; \ + } + +#define TRY(msg, cond) TRY_(msg, cond, 0) +#define TRY_Q(msg, cond) TRY_(msg, cond, 1); + +struct nsID iid = { + 0x00112233, + 0x4455, + 0x6677, + {0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} +}; + +XPTTypeDescriptor td_void; + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTHeader *header; + XPTAnnotation *ann; + XPTInterfaceDescriptor *id; + XPTMethodDescriptor *meth; + + XPTState *state; + XPTCursor curs, *cursor = &curs; + char *data, *head; + FILE *out; + PRUint32 len, header_sz; + + PRBool ok; + + td_void.prefix.flags = TD_VOID; + +#ifdef XP_MAC + if (argc == 0) { + static char* args[] = { "SimpleTypeLib", "simple.xpt", NULL }; + argc = 2; + argv = args; + } +#endif + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n" + " Creates a simple typelib file.\n", argv[0]); + + return 1; + } + + arena = XPT_NewArena(1024, sizeof(double), "main"); + TRY("XPT_NewArena", arena); + + /* construct a header */ + header = XPT_NewHeader(arena, 1, XPT_MAJOR_VERSION, XPT_MINOR_VERSION); + TRY("NewHeader", header); + + + ann = XPT_NewAnnotation(arena, XPT_ANN_LAST | XPT_ANN_PRIVATE, + XPT_NewStringZ(arena, "SimpleTypeLib 1.0"), + XPT_NewStringZ(arena, "See You In Rome")); + TRY("NewAnnotation", ann); + header->annotations = ann; + + header_sz = XPT_SizeOfHeaderBlock(header); + + id = XPT_NewInterfaceDescriptor(arena, 0, 2, 2, 0); + TRY("NewInterfaceDescriptor", id); + + ok = XPT_FillInterfaceDirectoryEntry(arena, header->interface_directory, &iid, + "Interface", "NS", id); + TRY("FillInterfaceDirectoryEntry", ok); + + /* void method1(void) */ + meth = &id->method_descriptors[0]; + ok = XPT_FillMethodDescriptor(arena, meth, 0, "method1", 0); + TRY("FillMethodDescriptor", ok); + meth->result->flags = 0; + meth->result->type.prefix.flags = TD_VOID; + + /* wstring method2(in uint32, in bool) */ + meth = &id->method_descriptors[1]; + ok = XPT_FillMethodDescriptor(arena, meth, 0, "method2", 2); + TRY("FillMethodDescriptor", ok); + + meth->result->flags = 0; + meth->result->type.prefix.flags = TD_PSTRING | XPT_TDP_POINTER; + meth->params[0].type.prefix.flags = TD_UINT32; + meth->params[0].flags = XPT_PD_IN; + meth->params[1].type.prefix.flags = TD_BOOL; + meth->params[1].flags = XPT_PD_IN; + +#if 0 + /* const one = 1; */ + id->const_descriptors[0].name = "one"; + id->const_descriptors[0].type.prefix.flags = TD_UINT16; + id->const_descriptors[0].value.ui16 = 1; + + /* const squeamish = "ossifrage"; */ + id->const_descriptors[1].name = "squeamish"; + id->const_descriptors[1].type.prefix.flags = TD_PBSTR | XPT_TDP_POINTER; + id->const_descriptors[1].value.string = XPT_NewStringZ(arena, "ossifrage"); +#endif + + /* serialize it */ + state = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + TRY("NewState (ENCODE)", state); + + ok = XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor); + TRY("MakeCursor", ok); + + ok = XPT_DoHeader(arena, cursor, &header); + TRY("DoHeader", ok); + + out = fopen(argv[1], "wb"); + if (!out) { + perror("FAILED: fopen"); + return 1; + } + + XPT_GetXDRData(state, XPT_HEADER, &head, &len); + fwrite(head, len, 1, out); + + XPT_GetXDRData(state, XPT_DATA, &data, &len); + fwrite(data, len, 1, out); + + if (ferror(out) != 0 || fclose(out) != 0) { + fprintf(stderr, "\nError writing file: %s\n\n", argv[1]); + } else { + fprintf(stderr, "\nFile written: %s\n\n", argv[1]); + } + XPT_DestroyXDRState(state); + + XPT_FreeHeader(arena, header); + XPT_DestroyArena(arena); + + return 0; +} + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore new file mode 100644 index 00000000..985cc7a7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/.cvsignore @@ -0,0 +1,3 @@ +Makefile +xpt_dump +xpt_link diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in new file mode 100644 index 00000000..bedece8e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/Makefile.in @@ -0,0 +1,90 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +INTERNAL_TOOLS = 1 + +SIMPLE_PROGRAMS = xpt_dump$(BIN_SUFFIX) xpt_link$(BIN_SUFFIX) + +CSRCS = xpt_dump.c xpt_link.c + +SDK_BINARY = \ + $(SIMPLE_PROGRAMS) \ + $(NULL) + +ifdef CROSS_COMPILE +HOST_SIMPLE_PROGRAMS = $(addprefix host_, $(SIMPLE_PROGRAMS:$(BIN_SUFFIX)=$(HOST_BIN_SUFFIX))) +HOST_CSRCS = $(CSRCS) +endif + +include $(topsrcdir)/config/rules.mk + +# Compile directly against the static lib, so we can use the tools +# during the build without the shared library path being set. +ifeq ($(OS_ARCH),WINNT) +DEFINES += -DEXPORT_XPT_API +endif + +LIBS = $(DIST)/lib/$(LIB_PREFIX)xpt.$(LIB_SUFFIX) + +# Tell the $(SIMPLE_PROGRAMS) target that we need to be recompiled +# when libxpt changes. +EXTRA_DEPS = $(wildcard $(DIST)/lib/$(LIB_PREFIX)xpt.*) + +ifdef CROSS_COMPILE +HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) +HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*) + +ifdef HOST_NSPR_MDCPUCFG +HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG) +endif +endif + + +# Build xpt_link and xpt_dump early. (libs creates .deps used by libs.) +export:: + @$(MAKE) libs + + + diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c new file mode 100644 index 00000000..8926b9c9 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_dump.c @@ -0,0 +1,941 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * A utility for dumping the contents of a typelib file (.xpt) to screen + */ + +#include "xpt_xdr.h" +#include +#ifdef XP_MAC +#include +#include +#include "FullPath.h" +#else +#ifdef XP_OS2_EMX +#include +#endif +#include +#endif +#include +#include +#include "prprf.h" + +#define BASE_INDENT 3 + +static char *type_array[32] = + {"int8", "int16", "int32", "int64", + "uint8", "uint16", "uint32", "uint64", + "float", "double", "boolean", "char", + "wchar_t", "void", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +static char *ptype_array[32] = + {"int8 *", "int16 *", "int32 *", "int64 *", + "uint8 *", "uint16 *", "uint32 *", "uint64 *", + "float *", "double *", "boolean *", "char *", + "wchar_t *", "void *", "nsIID *", "DOMString *", + "string", "wstring", "Interface *", "InterfaceIs *", + "array", "string_s", "wstring_s", "UTF8String *", + "CString *", "AString *", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +static char *rtype_array[32] = + {"int8 &", "int16 &", "int32 &", "int64 &", + "uint8 &", "uint16 &", "uint32 &", "uint64 &", + "float &", "double &", "boolean &", "char &", + "wchar_t &", "void &", "nsIID &", "DOMString &", + "string &", "wstring &", "Interface &", "InterfaceIs &", + "array &", "string_s &", "wstring_s &", "UTF8String &", + "CString &", "AString &", "reserved", "reserved", + "reserved", "reserved", "reserved", "reserved"}; + +PRBool param_problems = PR_FALSE; + +PRBool +XPT_DumpHeader(XPTCursor *cursor, XPTHeader *header, + const int indent, PRBool verbose_mode); + +PRBool +XPT_DumpAnnotations(XPTAnnotation *ann, const int indent, PRBool verbose_mode); + +PRBool +XPT_DumpInterfaceDirectoryEntry(XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, + XPTHeader *header, const int indent, + PRBool verbose_mode); + +PRBool +XPT_DumpInterfaceDescriptor(XPTCursor *cursor, XPTInterfaceDescriptor *id, + XPTHeader *header, const int indent, + PRBool verbose_mode); + +PRBool +XPT_DumpMethodDescriptor(XPTHeader *header, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode); +PRBool +XPT_GetStringForType(XPTHeader *header, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + char **type_string); + +PRBool +XPT_DumpXPTString(XPTString *str); + +PRBool +XPT_DumpParamDescriptor(XPTHeader *header, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode, + PRBool is_result); + +PRBool +XPT_DumpTypeDescriptor(XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + int indent, PRBool verbose_mode); + +PRBool +XPT_DumpConstDescriptor(XPTHeader *header, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode); + +static void +xpt_dump_usage(char *argv[]) { + fprintf(stdout, "Usage: %s [-v] \n" + " -v verbose mode\n", argv[0]); +} + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + +#define main xptdump_main +int xptdump_main(int argc, char *argv[]); + +#define get_file_length mac_get_file_length +extern size_t mac_get_file_length(const char* filename); + +#else /* !(XP_MAC && XPIDL_PLUGIN) */ + +static size_t get_file_length(const char* filename) +{ + struct stat file_stat; + if (stat(filename, &file_stat) != 0) { + perror("FAILED: get_file_length"); + exit(1); + } + return file_stat.st_size; +} + +#endif /* !(XP_MAC && XPIDL_PLUGIN) */ + +int +main(int argc, char **argv) +{ + PRBool verbose_mode = PR_FALSE; + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + XPTHeader *header; + size_t flen; + char *name; + char *whole; + FILE *in; + int result = 1; + + switch (argc) { + case 2: + if (argv[1][0] == '-') { + xpt_dump_usage(argv); + return 1; + } + name = argv[1]; + flen = get_file_length(name); + in = fopen(name, "rb"); + break; + case 3: + verbose_mode = PR_TRUE; + if (argv[1][0] != '-' || argv[1][1] != 'v') { + xpt_dump_usage(argv); + return 1; + } + name = argv[2]; + flen = get_file_length(name); + in = fopen(name, "rb"); + break; + default: + xpt_dump_usage(argv); + return 1; + } + + if (!in) { + perror("FAILED: fopen"); + return 1; + } + + arena = XPT_NewArena(1024, sizeof(double), "main xpt_dump arena"); + if (!arena) { + perror("XPT_NewArena failed"); + return 1; + } + + /* after arena creation all exits via 'goto out' */ + + whole = XPT_MALLOC(arena, flen); + if (!whole) { + perror("FAILED: XPT_MALLOC for whole"); + goto out; + } + + if (flen > 0) { + size_t rv = fread(whole, 1, flen, in); + if (rv < flen) { + fprintf(stderr, "short read (%zd vs %zd)! ouch!\n", rv, flen); + goto out; + } + if (ferror(in) != 0 || fclose(in) != 0) + perror("FAILED: Unable to read typelib file.\n"); + + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + fprintf(stdout, "XPT_MakeCursor failed for %s\n", name); + goto out; + } + if (!XPT_DoHeader(arena, cursor, &header)) { + fprintf(stdout, + "DoHeader failed for %s. Is %s a valid .xpt file?\n", + name, name); + goto out; + } + + if (!XPT_DumpHeader(cursor, header, BASE_INDENT, verbose_mode)) { + perror("FAILED: XPT_DumpHeader"); + goto out; + } + + if (param_problems) { + fprintf(stdout, "\nWARNING: ParamDescriptors are present with " + "bad in/out/retval flag information.\n" + "These have been marked with 'XXX'.\n" + "Remember, retval params should always be marked as out!\n"); + } + + XPT_DestroyXDRState(state); + XPT_FREE(arena, whole); + + } else { + fclose(in); + perror("FAILED: file length <= 0"); + goto out; + } + + result = 0; + +out: + XPT_DestroyArena(arena); + return result; +} + +PRBool +XPT_DumpHeader(XPTCursor *cursor, XPTHeader *header, + const int indent, PRBool verbose_mode) +{ + int i; + + fprintf(stdout, "Header:\n"); + + if (verbose_mode) { + fprintf(stdout, "%*sMagic beans: ", indent, " "); + for (i=0; i<16; i++) { + fprintf(stdout, "%02x", header->magic[i]); + } + fprintf(stdout, "\n"); + if (strncmp((const char*)header->magic, XPT_MAGIC, 16) == 0) + fprintf(stdout, "%*s PASSED\n", indent, " "); + else + fprintf(stdout, "%*s FAILED\n", indent, " "); + } + fprintf(stdout, "%*sMajor version: %d\n", indent, " ", + header->major_version); + fprintf(stdout, "%*sMinor version: %d\n", indent, " ", + header->minor_version); + fprintf(stdout, "%*sNumber of interfaces: %d\n", indent, " ", + header->num_interfaces); + + if (verbose_mode) { + fprintf(stdout, "%*sFile length: %d\n", indent, " ", + header->file_length); + fprintf(stdout, "%*sData pool offset: %d\n\n", indent, " ", + header->data_pool); + } + + fprintf(stdout, "%*sAnnotations:\n", indent, " "); + if (!XPT_DumpAnnotations(header->annotations, indent*2, verbose_mode)) + return PR_FALSE; + + fprintf(stdout, "\nInterface Directory:\n"); + for (i=0; inum_interfaces; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sInterface #%d:\n", indent, " ", i); + if (!XPT_DumpInterfaceDirectoryEntry(cursor, + &header->interface_directory[i], + header, indent*2, + verbose_mode)) { + return PR_FALSE; + } + } else { + if (!XPT_DumpInterfaceDirectoryEntry(cursor, + &header->interface_directory[i], + header, indent, + verbose_mode)) { + return PR_FALSE; + } + } + } + + return PR_TRUE; +} + +PRBool +XPT_DumpAnnotations(XPTAnnotation *ann, const int indent, PRBool verbose_mode) +{ + int i = -1; + XPTAnnotation *last; + int new_indent = indent + BASE_INDENT; + + do { + i++; + if (XPT_ANN_IS_PRIVATE(ann->flags)) { + if (verbose_mode) { + fprintf(stdout, "%*sAnnotation #%d is private.\n", + indent, " ", i); + } else { + fprintf(stdout, "%*sAnnotation #%d:\n", + indent, " ", i); + } + fprintf(stdout, "%*sCreator: ", new_indent, " "); + if (!XPT_DumpXPTString(ann->creator)) + return PR_FALSE; + fprintf(stdout, "\n"); + fprintf(stdout, "%*sPrivate Data: ", new_indent, " "); + if (!XPT_DumpXPTString(ann->private_data)) + return PR_FALSE; + fprintf(stdout, "\n"); + } else { + fprintf(stdout, "%*sAnnotation #%d is empty.\n", + indent, " ", i); + } + last = ann; + ann = ann->next; + } while (!XPT_ANN_IS_LAST(last->flags)); + + if (verbose_mode) { + fprintf(stdout, "%*sAnnotation #%d is the last annotation.\n", + indent, " ", i); + } + + return PR_TRUE; +} + +static void +print_IID(struct nsID *iid, FILE *file) +{ + fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2, + (PRUint32) iid->m3[0], (PRUint32) iid->m3[1], + (PRUint32) iid->m3[2], (PRUint32) iid->m3[3], + (PRUint32) iid->m3[4], (PRUint32) iid->m3[5], + (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]); + +} + +PRBool +XPT_DumpInterfaceDirectoryEntry(XPTCursor *cursor, + XPTInterfaceDirectoryEntry *ide, + XPTHeader *header, const int indent, + PRBool verbose_mode) +{ + int new_indent = indent + BASE_INDENT; + + if (verbose_mode) { + fprintf(stdout, "%*sIID: ", indent, " "); + print_IID(&ide->iid, stdout); + fprintf(stdout, "\n"); + + fprintf(stdout, "%*sName: %s\n", + indent, " ", ide->name); + fprintf(stdout, "%*sNamespace: %s\n", + indent, " ", ide->name_space ? ide->name_space : "none"); + fprintf(stdout, "%*sAddress of interface descriptor: %p\n", + indent, " ", ide->interface_descriptor); + + fprintf(stdout, "%*sDescriptor:\n", indent, " "); + + if (!XPT_DumpInterfaceDescriptor(cursor, ide->interface_descriptor, + header, new_indent, verbose_mode)) { + return PR_FALSE; + } + } else { + fprintf(stdout, "%*s- %s::%s (", indent, " ", + ide->name_space ? ide->name_space : "", ide->name); + print_IID(&ide->iid, stdout); + fprintf(stdout, "):\n"); + if (!XPT_DumpInterfaceDescriptor(cursor, ide->interface_descriptor, + header, new_indent, verbose_mode)) { + return PR_FALSE; + } + } + + return PR_TRUE; +} + +PRBool +XPT_DumpInterfaceDescriptor(XPTCursor *cursor, XPTInterfaceDescriptor *id, + XPTHeader *header, const int indent, + PRBool verbose_mode) +{ + XPTInterfaceDirectoryEntry *parent_ide; + int i; + int new_indent = indent + BASE_INDENT; + int more_indent = new_indent + BASE_INDENT; + + if (!id) { + fprintf(stdout, "%*s[Unresolved]\n", indent, " "); + return PR_TRUE; + } + + if (id->parent_interface) { + + parent_ide = &header->interface_directory[id->parent_interface - 1]; + + fprintf(stdout, "%*sParent: %s::%s\n", indent, " ", + parent_ide->name_space ? + parent_ide->name_space : "", + parent_ide->name); + } + + fprintf(stdout, "%*sFlags:\n", indent, " "); + + fprintf(stdout, "%*sScriptable: %s\n", new_indent, " ", + XPT_ID_IS_SCRIPTABLE(id->flags) ? "TRUE" : "FALSE"); + + fprintf(stdout, "%*sFunction: %s\n", new_indent, " ", + XPT_ID_IS_FUNCTION(id->flags) ? "TRUE" : "FALSE"); + + if (verbose_mode) { + if (id->parent_interface) { + fprintf(stdout, + "%*sIndex of parent interface (in data pool): %d\n", + indent, " ", id->parent_interface); + + } + } else { + } + + if (id->num_methods > 0) { + if (verbose_mode) { + fprintf(stdout, + "%*s# of Method Descriptors: %d\n", + indent, " ", id->num_methods); + } else { + fprintf(stdout, "%*sMethods:\n", indent, " "); + } + + for (i=0; inum_methods; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sMethod #%d:\n", new_indent, " ", i); + if (!XPT_DumpMethodDescriptor(header, + &id->method_descriptors[i], id, + more_indent, verbose_mode)) { + return PR_FALSE; + } + } else { + if (!XPT_DumpMethodDescriptor(header, + &id->method_descriptors[i], id, + new_indent, verbose_mode)) { + return PR_FALSE; + } + } + } + } else { + fprintf(stdout, "%*sMethods:\n", indent, " "); + fprintf(stdout, "%*sNo Methods\n", new_indent, " "); + } + + if (id->num_constants > 0) { + if (verbose_mode) { + fprintf(stdout, + "%*s# of Constant Descriptors: %d\n", + indent, " ", id->num_constants); + } else { + fprintf(stdout, "%*sConstants:\n", indent, " "); + } + + for (i=0; inum_constants; i++) { + if (verbose_mode) { + fprintf(stdout, "%*sConstant #%d:\n", new_indent, " ", i); + if (!XPT_DumpConstDescriptor(header, + &id->const_descriptors[i], id, + more_indent, verbose_mode)) + return PR_FALSE; + } else { + if (!XPT_DumpConstDescriptor(header, + &id->const_descriptors[i], id, + new_indent, verbose_mode)) { + return PR_FALSE; + } + } + } + } else { + fprintf(stdout, "%*sConstants:\n", indent, " "); + fprintf(stdout, "%*sNo Constants\n", new_indent, " "); + } + + return PR_TRUE; +} + +PRBool +XPT_DumpMethodDescriptor(XPTHeader *header, XPTMethodDescriptor *md, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode) +{ + int i; + int new_indent = indent + BASE_INDENT; + int more_indent = new_indent + BASE_INDENT; + + if (verbose_mode) { + fprintf(stdout, "%*sName: %s\n", indent, " ", md->name); + fprintf(stdout, "%*sIs Getter? ", indent, " "); + if (XPT_MD_IS_GETTER(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Setter? ", indent, " "); + if (XPT_MD_IS_SETTER(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs NotXPCOM? ", indent, " "); + if (XPT_MD_IS_NOTXPCOM(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Constructor? ", indent, " "); + if (XPT_MD_IS_CTOR(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Hidden? ", indent, " "); + if (XPT_MD_IS_HIDDEN(md->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*s# of arguments: %d\n", indent, " ", md->num_args); + fprintf(stdout, "%*sParameter Descriptors:\n", indent, " "); + + for (i=0; inum_args; i++) { + fprintf(stdout, "%*sParameter #%d:\n", new_indent, " ", i); + + if (!XPT_DumpParamDescriptor(header, &md->params[i], id, + more_indent, verbose_mode, PR_FALSE)) + return PR_FALSE; + } + + fprintf(stdout, "%*sResult:\n", indent, " "); + if (!XPT_DumpParamDescriptor(header, md->result, id, new_indent, + verbose_mode, PR_TRUE)) { + return PR_FALSE; + } + } else { + char *param_type; + XPTParamDescriptor *pd; + + if (!XPT_GetStringForType(header, &md->result->type, id, ¶m_type)) { + return PR_FALSE; + } + fprintf(stdout, "%*s%c%c%c%c%c %s %s(", indent - 6, " ", + XPT_MD_IS_GETTER(md->flags) ? 'G' : ' ', + XPT_MD_IS_SETTER(md->flags) ? 'S' : ' ', + XPT_MD_IS_HIDDEN(md->flags) ? 'H' : ' ', + XPT_MD_IS_NOTXPCOM(md->flags) ? 'N' : ' ', + XPT_MD_IS_CTOR(md->flags) ? 'C' : ' ', + param_type, md->name); + for (i=0; inum_args; i++) { + if (i!=0) { + fprintf(stdout, ", "); + } + pd = &md->params[i]; + if (XPT_PD_IS_IN(pd->flags)) { + fprintf(stdout, "in"); + if (XPT_PD_IS_OUT(pd->flags)) { + fprintf(stdout, "out "); + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + if (XPT_PD_IS_SHARED(pd->flags)) { + fprintf(stdout, "shared "); + } + } else { + fprintf(stdout, " "); + if (XPT_PD_IS_DIPPER(pd->flags)) { + fprintf(stdout, "dipper "); + } + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + } + } else { + if (XPT_PD_IS_OUT(pd->flags)) { + fprintf(stdout, "out "); + if (XPT_PD_IS_RETVAL(pd->flags)) { + fprintf(stdout, "retval "); + } + if (XPT_PD_IS_SHARED(pd->flags)) { + fprintf(stdout, "shared "); + } + } else { + param_problems = PR_TRUE; + fprintf(stdout, "XXX "); + } + } + if (!XPT_GetStringForType(header, &pd->type, id, ¶m_type)) { + return PR_FALSE; + } + fprintf(stdout, "%s", param_type); + } + fprintf(stdout, ");\n"); + } + return PR_TRUE; +} + +PRBool +XPT_GetStringForType(XPTHeader *header, XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + char **type_string) +{ + static char buf[128]; /* ugly non-reentrant use of static buffer! */ + PRBool isArray = PR_FALSE; + + int tag = XPT_TDP_TAG(td->prefix); + + if (tag == TD_ARRAY) { + isArray = PR_TRUE; + td = &id->additional_types[td->type.additional_type]; + tag = XPT_TDP_TAG(td->prefix); + } + + if (tag == TD_INTERFACE_TYPE) { + int idx = td->type.iface; + if (!idx || idx > header->num_interfaces) + *type_string = "UNKNOWN_INTERFACE"; + else + *type_string = header->interface_directory[idx-1].name; + } else if (XPT_TDP_IS_POINTER(td->prefix.flags)) { + if (XPT_TDP_IS_REFERENCE(td->prefix.flags)) + *type_string = rtype_array[tag]; + else + *type_string = ptype_array[tag]; + } else { + *type_string = type_array[tag]; + } + + if(isArray) { + sprintf(buf, "%s []", *type_string); + *type_string = buf; + } + + return PR_TRUE; +} + +PRBool +XPT_DumpXPTString(XPTString *str) +{ + int i; + for (i=0; ilength; i++) { + fprintf(stdout, "%c", str->bytes[i]); + } + return PR_TRUE; +} + +PRBool +XPT_DumpParamDescriptor(XPTHeader *header, XPTParamDescriptor *pd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode, + PRBool is_result) +{ + int new_indent = indent + BASE_INDENT; + + if (!XPT_PD_IS_IN(pd->flags) && + !XPT_PD_IS_OUT(pd->flags) && + (XPT_PD_IS_RETVAL(pd->flags) || + XPT_PD_IS_SHARED(pd->flags))) { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } else { + if (!XPT_PD_IS_IN(pd->flags) && !XPT_PD_IS_OUT(pd->flags)) { + if (is_result) { + if (XPT_TDP_TAG(pd->type.prefix) != TD_UINT32 && + XPT_TDP_TAG(pd->type.prefix) != TD_VOID) { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } + } else { + param_problems = PR_TRUE; + fprintf(stdout, "XXX\n"); + } + } + } + + fprintf(stdout, "%*sIn Param? ", indent, " "); + if (XPT_PD_IS_IN(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sOut Param? ", indent, " "); + if (XPT_PD_IS_OUT(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sRetval? ", indent, " "); + if (XPT_PD_IS_RETVAL(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sShared? ", indent, " "); + if (XPT_PD_IS_SHARED(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sDipper? ", indent, " "); + if (XPT_PD_IS_DIPPER(pd->flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + + fprintf(stdout, "%*sType Descriptor:\n", indent, " "); + if (!XPT_DumpTypeDescriptor(&pd->type, id, new_indent, verbose_mode)) + return PR_FALSE; + + return PR_TRUE; +} + +PRBool +XPT_DumpTypeDescriptor(XPTTypeDescriptor *td, + XPTInterfaceDescriptor *id, + int indent, PRBool verbose_mode) +{ + int new_indent; + + if (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + fprintf(stdout, "%*sArray (size in arg %d and length in arg %d) of...\n", + indent, " ", td->argnum, td->argnum2); + td = &id->additional_types[td->type.additional_type]; + indent += BASE_INDENT; + } + + new_indent = indent + BASE_INDENT; + + fprintf(stdout, "%*sIs Pointer? ", indent, " "); + if (XPT_TDP_IS_POINTER(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Unique Pointer? ", indent, " "); + if (XPT_TDP_IS_UNIQUE_POINTER(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sIs Reference? ", indent, " "); + if (XPT_TDP_IS_REFERENCE(td->prefix.flags)) + fprintf(stdout, "TRUE\n"); + else + fprintf(stdout, "FALSE\n"); + + fprintf(stdout, "%*sTag: %d\n", indent, " ", + XPT_TDP_TAG(td->prefix)); + + if (XPT_TDP_TAG(td->prefix) == TD_PSTRING_SIZE_IS || + XPT_TDP_TAG(td->prefix) == TD_PWSTRING_SIZE_IS) { + fprintf(stdout, "%*s - size in arg %d and length in arg %d\n", + indent, " ", td->argnum, td->argnum2); + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + fprintf(stdout, "%*sInterfaceTypeDescriptor:\n", indent, " "); + fprintf(stdout, "%*sIndex of IDE: %d\n", new_indent, " ", + td->type.iface); + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_IS_TYPE) { + fprintf(stdout, "%*sInterfaceTypeDescriptor:\n", indent, " "); + fprintf(stdout, "%*sIndex of Method Argument: %d\n", new_indent, " ", + td->argnum); + } + + return PR_TRUE; +} + +PRBool +XPT_DumpConstDescriptor(XPTHeader *header, XPTConstDescriptor *cd, + XPTInterfaceDescriptor *id, + const int indent, PRBool verbose_mode) +{ + int new_indent = indent + BASE_INDENT; + char *const_type; +/* char *out; */ + PRUint32 uintout; + PRInt32 intout; + + if (verbose_mode) { + fprintf(stdout, "%*sName: %s\n", indent, " ", cd->name); + fprintf(stdout, "%*sType Descriptor: \n", indent, " "); + if (!XPT_DumpTypeDescriptor(&cd->type, id, new_indent, verbose_mode)) + return PR_FALSE; + fprintf(stdout, "%*sValue: ", indent, " "); + } else { + if (!XPT_GetStringForType(header, &cd->type, id, &const_type)) { + return PR_FALSE; + } + fprintf(stdout, "%*s%s %s = ", indent, " ", const_type, cd->name); + } + + switch(XPT_TDP_TAG(cd->type.prefix)) { + case TD_INT8: + fprintf(stdout, "%d", cd->value.i8); + break; + case TD_INT16: + fprintf(stdout, "%d", cd->value.i16); + break; + case TD_INT64: + /* XXX punt for now to remove NSPR linkage... + * borrow from mozilla/nsprpub/pr/src/io/prprf.c::cvt_ll? */ + +/* out = PR_smprintf("%lld", cd->value.i64); */ +/* fputs(out, stdout); */ +/* PR_smprintf_free(out); */ + LL_L2I(intout, cd->value.i64); + fprintf(stdout, "%d", intout); + break; + case TD_INT32: + fprintf(stdout, "%d", cd->value.i32); + break; + case TD_UINT8: + fprintf(stdout, "%u", cd->value.ui8); + break; + case TD_UINT16: + fprintf(stdout, "%u", cd->value.ui16); + break; + case TD_UINT64: +/* out = PR_smprintf("%lld", cd->value.ui64); */ +/* fputs(out, stdout); */ +/* PR_smprintf_free(out); */ + /* XXX punt for now to remove NSPR linkage. */ + LL_L2UI(uintout, cd->value.ui64); + fprintf(stdout, "%u", uintout); + break; + case TD_UINT32: + fprintf(stdout, "%u", cd->value.ui32); + break; + case TD_FLOAT: + fprintf(stdout, "%f", cd->value.flt); + break; + case TD_DOUBLE: + fprintf(stdout, "%g", cd->value.dbl); + break; + case TD_BOOL: + if (cd->value.bul) + fprintf(stdout, "TRUE"); + else + fprintf(stdout, "FALSE"); + break; + case TD_CHAR: + fprintf(stdout, "%c", cd->value.ch); + break; + case TD_WCHAR: + fprintf(stdout, "%c", cd->value.wch & 0xff); + break; + case TD_VOID: + fprintf(stdout, "VOID"); + break; + case TD_PNSIID: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + print_IID(cd->value.iid, stdout); + } else + return PR_FALSE; + break; + case TD_PSTRING: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + fprintf(stdout, "%s", cd->value.str); + } else + return PR_FALSE; + break; + case TD_PWSTRING: + if (XPT_TDP_IS_POINTER(cd->type.prefix.flags)) { + PRUint16 *ch = cd->value.wstr; + while (*ch) { + fprintf(stdout, "%c", *ch & 0xff); + ch++; + } + } else + return PR_FALSE; + break; + default: + perror("Unrecognized type"); + return PR_FALSE; + break; + } + + if (verbose_mode) { + fprintf(stdout, "\n"); + } else { + fprintf(stdout, ";\n"); + } + + return PR_TRUE; +} diff --git a/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c new file mode 100644 index 00000000..872b96fd --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/typelib/xpt/tools/xpt_link.c @@ -0,0 +1,883 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* + * A utility for linking multiple typelib files. + */ + +#include "xpt_xdr.h" +#include +#ifdef XP_MAC +#include +#else +#include +#endif +#include +#include +#include "prlong.h" + +#ifndef NULL +#define NULL (void *) 0 +#endif + +/* Forward declarations. */ +typedef struct fixElement fixElement; +static int compare_IDEs_by_IID(const void *ap, const void *bp); +static int compare_IDE_with_zero(const void *ap); +static int compare_IDEs_by_name(const void *ap, const void *bp); +static int compare_IDEs_by_name_space(const void *ap, const void *bp); +static int compare_strings(const void *ap, const void *bp); +static int compare_pointers(const void *ap, const void *bp); +static int compare_fixElements_by_IID(const void *ap, const void *bp); +static int compare_fixElements_by_name(const void *ap, const void *bp); +static int compare_IIDs(const void *ap, const void *bp); +PRBool shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, + int element_to_delete, int num_interfaces); +PRBool update_fix_array(XPTArena *arena, fixElement *fix, int element_to_delete, + int num_interfaces, int replacement); +static int get_new_index(const fixElement *fix, int num_elements, + int target_file, int target_interface); +PRBool copy_IDE(XPTInterfaceDirectoryEntry *from, + XPTInterfaceDirectoryEntry *to); +PRBool copy_fixElement(fixElement *from, fixElement *to); +static void print_IID(struct nsID *iid, FILE *file); +static void xpt_link_usage(char *argv[]); + +struct fixElement { + nsID iid; + char* name; + int file_num; + int interface_num; + PRBool is_deleted; + /* These next two variables will point you to the substitute interface + * if this one has been deleted. + */ + int maps_to_file_num; + int maps_to_interface_num; +}; + +/* Global variables. */ +PRUint16 trueNumberOfInterfaces = 0; +PRUint16 totalNumberOfInterfaces = 0; +PRUint16 oldTotalNumberOfInterfaces = 0; + +/* The following globals are explained in xpt_struct.h */ +PRUint8 major_version = XPT_MAJOR_VERSION; +PRUint8 minor_version = XPT_MINOR_VERSION; + +#if defined(XP_MAC) && defined(XPIDL_PLUGIN) + +#define main xptlink_main +int xptlink_main(int argc, char *argv[]); +extern size_t mac_get_file_length(const char* filename); +#define get_file_length mac_get_file_length + +#else + +static size_t get_file_length(const char* filename) +{ + struct stat file_stat; + if (stat(filename, &file_stat) != 0) { + perror("FAILED: get_file_length"); + exit(1); + } + return file_stat.st_size; +} + +#endif /* XP_MAC && XPIDL_PLUGIN */ + +int +main(int argc, char **argv) +{ + XPTArena *arena; + XPTState *state; + XPTCursor curs, *cursor = &curs; + XPTHeader *header; + XPTInterfaceDirectoryEntry *IDE_array = NULL; + XPTInterfaceDescriptor *id; + XPTTypeDescriptor *td; + XPTAnnotation *ann, *first_ann; + PRUint32 header_sz, len; + PRUint32 oldOffset; + PRUint32 newOffset; + size_t flen = 0; + char *head, *data, *whole; + const char *outFileName; + FILE *in, *out; + fixElement *fix_array = NULL; + int i,j; + int k = 0; + + if (argc < 3) { + xpt_link_usage(argv); + return 1; + } + + arena = XPT_NewArena(1024 * 10, sizeof(double), "main xpt_link arena"); + if (!arena) { + perror("FAILED: XPT_NewArena"); + return 1; + } + + first_ann = XPT_NewAnnotation(arena, XPT_ANN_LAST, NULL, NULL); + + /* Check if the "-t version numnber" cmd line arg is present */ + i = 1; + if (argv[i][0] == '-' && argv[i][1] == 't') { + /* Parse for "-t version number" */ + + /* If -t is the last argument on the command line, we have a problem */ + if (i + 1 == argc) { + fprintf(stderr, "ERROR: missing version number after -t\n"); + xpt_link_usage(argv); + return 1; + } + + /* + * Assume that the argument after "-t" is the version number string + * and search for it in our internal list of acceptable version + * numbers. + */ + + switch (XPT_ParseVersionString(argv[++i], &major_version, + &minor_version)) { + case XPT_VERSION_CURRENT: + case XPT_VERSION_OLD: + break; + case XPT_VERSION_UNSUPPORTED: + fprintf(stderr, "ERROR: version \"%s\" not supported.\n", + argv[i]); + xpt_link_usage(argv); + return 1; + case XPT_VERSION_UNKNOWN: + default: + fprintf(stderr, "ERROR: version \"%s\" not recognised.\n", + argv[i]); + xpt_link_usage(argv); + return 1; + } + + /* Hang onto the output file name. It's needed later. */ + outFileName = argv[++i]; + + /* Increment i to the cmd line arg after outFileName */ + i++; + } + else { + outFileName = argv[1]; + i = 2; + } + + for ( /* use i from earlier */ ; i < argc; i++) { + char *name = argv[i]; + + flen = get_file_length(name); + if (!flen) { + fprintf(stderr, "ERROR: file %s is zero length\n", name); + return 1; + } + + in = fopen(name, "rb"); + if (!in) { + perror("FAILED: fopen"); + return 1; + } + + whole = XPT_MALLOC(arena, flen); + if (!whole) { + perror("FAILED: XPT_MALLOC for whole"); + return 1; + } + + if (flen > 0) { + size_t rv = fread(whole, 1, flen, in); + if (rv < flen) { + fprintf(stderr, "short read (%zd vs %zd)! ouch!\n", rv, flen); + return 1; + } + if (ferror(in) != 0 || fclose(in) != 0) { + perror("FAILED: Unable to read typelib file.\n"); + return 1; + } + + state = XPT_NewXDRState(XPT_DECODE, whole, flen); + if (!XPT_MakeCursor(state, XPT_HEADER, 0, cursor)) { + fprintf(stdout, "XPT_MakeCursor failed for %s\n", name); + return 1; + } + if (!XPT_DoHeader(arena, cursor, &header)) { + fprintf(stdout, + "DoHeader failed for %s. Is %s a valid .xpt file?\n", + name, name); + return 1; + } + + /* + * Make sure that the version of the typelib file is less than or + * equal to the version specified in the -t cmd line arg. + */ + + if (header && + (header->major_version > major_version || + (header->major_version == major_version && + header->minor_version > minor_version))) { + fprintf(stderr, "FAILED: %s's version, %d.%d, is newer than " + "the version (%d.%d) specified in the -t " + "command line argument.\n", + name, header->major_version, header->minor_version, + major_version, minor_version); + return 1; + } + + oldTotalNumberOfInterfaces = totalNumberOfInterfaces; + totalNumberOfInterfaces += header->num_interfaces; + if (header->num_interfaces > 0) { + XPTInterfaceDirectoryEntry *newIDE; + fixElement *newFix; + + newIDE = (XPTInterfaceDirectoryEntry *) + XPT_MALLOC(arena, totalNumberOfInterfaces * + sizeof(XPTInterfaceDirectoryEntry)); + if (!newIDE) { + perror("FAILED: XPT_MALLOC of IDE_array"); + return 1; + } + + if (IDE_array) { + if (oldTotalNumberOfInterfaces) + memcpy(newIDE, IDE_array, + oldTotalNumberOfInterfaces * + sizeof(XPTInterfaceDirectoryEntry)); + XPT_FREE(arena, IDE_array); + } + IDE_array = newIDE; + + + newFix = (fixElement *) + XPT_MALLOC(arena, + totalNumberOfInterfaces * sizeof(fixElement)); + if (!newFix) { + perror("FAILED: XPT_MALLOC of fix_array"); + return 1; + } + + if (fix_array) { + if (oldTotalNumberOfInterfaces) + memcpy(newFix, fix_array, + oldTotalNumberOfInterfaces * + sizeof(fixElement)); + XPT_FREE(arena, fix_array); + } + fix_array = newFix; + + for (j=0; jnum_interfaces; j++) { + if (!copy_IDE(&header->interface_directory[j], + &IDE_array[k])) { + perror("FAILED: 1st copying of IDE"); + return 1; + } + fix_array[k].iid = IDE_array[k].iid; + fix_array[k].name = IDE_array[k].name; + fix_array[k].file_num = i-2; + fix_array[k].interface_num = j+1; + fix_array[k].is_deleted = PR_FALSE; + fix_array[k].maps_to_file_num = i-2; + fix_array[k].maps_to_interface_num = j+1; + + k++; + } + } + + /* Copy the annotations if they are not 'empty' + */ + if (header->annotations != NULL && + header->annotations->flags != XPT_ANN_LAST) { + ann = first_ann; + while (ann->next != NULL) { + ann = ann->next; + } + ann->next = header->annotations; + } + + XPT_FREEIF(arena, header); + if (state) + XPT_DestroyXDRState(state); + XPT_FREE(arena, whole); + flen = 0; + + } else { + fclose(in); + perror("FAILED: file length <= 0"); + return 1; + } + } + + /* Make sure the last annotation is the only one marked as XP_ANN_LAST. + */ + ann = first_ann; + while (ann->next != NULL) { + ann->flags &= ~XPT_ANN_LAST; + ann = ann->next; + } + ann->flags |= XPT_ANN_LAST; + + /* Sort both IDE_array and fix_array by name so we can check for + * name_space::name collisions. + */ + qsort(IDE_array, + totalNumberOfInterfaces, + sizeof(XPTInterfaceDirectoryEntry), + compare_IDEs_by_name); + + qsort(fix_array, + totalNumberOfInterfaces, + sizeof(fixElement), + compare_fixElements_by_name); + + /* trueNumberOfInterfaces == number of interfaces left after deletions + * are made. Initialize it here to be the same as the total number of + * interfaces we'ce encountered thus far. + */ + trueNumberOfInterfaces = totalNumberOfInterfaces; + + /* Iterate through the sorted interfaces. Start at one so we don't + * accidentally walk off the end of the array. + */ + i = 1; + while (i != trueNumberOfInterfaces) { + + /* Check for name_space::name collision. + */ + if (compare_strings(IDE_array[i-1].name, + IDE_array[i].name) == 0 && + compare_strings(IDE_array[i-1].name_space, + IDE_array[i].name_space) == 0) { + + /* If one of the interfaces is unresolved, delete that one + * preferentailly. + */ + if (!IDE_array[i-1].interface_descriptor) { + /* Shrink the IDE_array to delete the duplicate interface. + */ + if (!shrink_IDE_array(IDE_array, + i-1, + trueNumberOfInterfaces)) { + perror("FAILED: shrink_IDE_array"); + return 1; + } + /* Update the fix array. This involves moving the deleted + * entry to the end of the array (rather than deleting it) + * and mapping it to the "replacement" element so we can + * update interface indices appropriately later. + */ + update_fix_array(arena, fix_array, i-1, + totalNumberOfInterfaces, i); + /* Decrement the true number of interfaces since we just + * deleted one. There's more than one way to get out of + * this loop. + */ + trueNumberOfInterfaces--; + } else { + if (!IDE_array[i].interface_descriptor || + (compare_IIDs(&IDE_array[i-1].iid, &IDE_array[i].iid) == 0)) + { + /* Shrink the IDE_array to delete the duplicate interface. + */ + if (!shrink_IDE_array(IDE_array, + i, + trueNumberOfInterfaces)) { + perror("FAILED: shrink_IDE_array"); + return 1; + } + /* Update the fix array. This involves moving the deleted + * entry to the end of the array (rather than deleting it) + * and mapping it to the "replacement" element so we can + * update interface indices appropriately later. + */ + update_fix_array(arena, fix_array, i, + totalNumberOfInterfaces, i-1); + /* Decrement the true number of interfaces since we just + * deleted one. There's more than one way to get out of + * this loop. + */ + trueNumberOfInterfaces--; + } else { + /* Found interfaces with duplicate names but different + * iids! */ + char *ns = IDE_array[i].name_space; + fprintf(stderr, + "ERROR: found duplicate definitions of interface " + "%s%s%s with iids \n", + ns ? ns : "", ns ? "::" : "", IDE_array[i].name); + print_IID(&IDE_array[i].iid, stderr); + fprintf(stderr, " and "); + print_IID(&IDE_array[i-1].iid, stderr); + fprintf(stderr, "\n"); + return 1; + } + } + } else { + /* Only increment if there was no name_space::name collision. + */ + i++; + } + } + + /* Sort the IDE_array (put them in their final order) so that updating + * of indices will be meaningful. + */ + qsort(IDE_array, + trueNumberOfInterfaces, + sizeof(XPTInterfaceDirectoryEntry), + compare_IDEs_by_IID); + + /* Sort the fix_array to match the IDE_array. + */ + qsort(fix_array, + trueNumberOfInterfaces, + sizeof(fixElement), + compare_fixElements_by_IID); + + /* Iterate through the remaining interfaces (those not deleted) + * looking for references to interfaces (such as id->parent_interface) + * which need an updated index number. + */ + for (i=0; iparent_interface && id->parent_interface != 0) { + id->parent_interface = + get_new_index(fix_array, totalNumberOfInterfaces, + fix_array[i].file_num, id->parent_interface); + } + /* Iterate through the method descriptors looking for params of + * type TD_INTERFACE_TYPE. + */ + for (j=0; jnum_methods; j++) { + /* Cycle through the params first. + */ + for (k=0; kmethod_descriptors[j].num_args; k++) { + /* Define td to save some keystrokes. + */ + td = &id->method_descriptors[j].params[k].type; + + while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) { + td = &id->additional_types[td->type.additional_type]; + } + + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + td->type.iface = + get_new_index(fix_array, + totalNumberOfInterfaces, + fix_array[i].file_num, + td->type.iface); + } + } + + /* Check the result param too. Define td again to save + * some keystrokes. + */ + td = &id->method_descriptors[j].result->type; + if (XPT_TDP_TAG(td->prefix) == TD_INTERFACE_TYPE) { + td->type.iface = + get_new_index(fix_array, totalNumberOfInterfaces, + fix_array[i].file_num, + td->type.iface); + } + } + } + } + + /* Iterate through the array quickly looking for duplicate IIDS. + * This shouldn't happen, i.e. is a failure condition, so bail + * if we find a duplicate. If we have more than one entry, start + * at one so we don't accidentally grep the ether. + */ + if (trueNumberOfInterfaces>1) { + for (i=1; iannotations = first_ann; + for (i=0; iinterface_directory[i])) { + perror("FAILED: 2nd copying of IDE"); + return 1; + } + } + + header_sz = XPT_SizeOfHeaderBlock(header); + + state = XPT_NewXDRState(XPT_ENCODE, NULL, 0); + if (!state) { + perror("FAILED: error creating XDRState"); + return 1; + } + + XPT_SetDataOffset(state, header_sz); + + if (!XPT_MakeCursor(state, XPT_HEADER, header_sz, cursor)) { + perror("FAILED: error making cursor"); + return 1; + } + oldOffset = cursor->offset; + if (!XPT_DoHeader(arena, cursor, &header)) { + perror("FAILED: error doing Header"); + return 1; + } + newOffset = cursor->offset; + XPT_GetXDRDataLength(state, XPT_HEADER, &len); + header->file_length = len; + XPT_GetXDRDataLength(state, XPT_DATA, &len); + header->file_length += len; + XPT_SeekTo(cursor, oldOffset); + if (!XPT_DoHeaderPrologue(arena, cursor, &header, NULL)) { + perror("FAILED: error doing Header"); + return 1; + } + XPT_SeekTo(cursor, newOffset); + out = fopen(outFileName, "wb"); + if (!out) { + perror("FAILED: fopen"); + return 1; + } + + XPT_GetXDRData(state, XPT_HEADER, &head, &len); + fwrite(head, len, 1, out); + + XPT_GetXDRData(state, XPT_DATA, &data, &len); + fwrite(data, len, 1, out); + + if (ferror(out) != 0 || fclose(out) != 0) { + fprintf(stderr, "Error writing file: %s\n", argv[1]); + } else { +/* fprintf(stderr, "File written: %s\n", argv[1]); */ + } + + if (state) + XPT_DestroyXDRState(state); + + XPT_DestroyArena(arena); + + return 0; +} + +static int +compare_IDEs_by_IID(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + int answer = compare_IIDs(&ide1->iid, &ide2->iid); + if(!answer) + answer = compare_strings(ide1->name, ide2->name); + + return answer; +} + +/* For detecting unresolved interfaces. */ +const nsID iid_zero = { 0x0, 0x0, 0x0, + { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }; + +static int +compare_IDE_with_zero(const void *ap) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap; + + return compare_IIDs(&ide1->iid, &iid_zero); +} + +static int +compare_fixElements_by_IID(const void *ap, + const void *bp) +{ + const fixElement *fix1 = ap, *fix2 = bp; + + int answer = compare_IIDs(&fix1->iid, &fix2->iid); + if(!answer) + answer = compare_strings(fix1->name, fix2->name); + + return answer; +} + +static int +compare_IDEs_by_name(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + int answer = compare_strings(ide1->name, ide2->name); + if(!answer) + answer = compare_pointers(ide1->name, ide2->name); + + return answer; +} + +static int +compare_IDEs_by_name_space(const void *ap, + const void *bp) +{ + const XPTInterfaceDirectoryEntry *ide1 = ap, *ide2 = bp; + + return compare_strings(ide1->name_space, ide2->name_space); +} + +static int +compare_strings(const void *ap, const void *bp) +{ + const char *string1 = ap, *string2 = bp; + + if (!string1 && !string2) + return 0; + if (!string1) + return -1; + if (!string2) + return 1; + + return strcmp(string1, string2); +} + +static int +compare_pointers(const void *ap, const void *bp) +{ + if (ap == bp) { +#ifdef DEBUG_jband + perror("name addresses were equal!"); +#endif + return 0; + } + if (ap > bp) + return 1; + return -1; +} + +static int +compare_fixElements_by_name(const void *ap, + const void *bp) +{ + const fixElement *fix1 = ap, *fix2 = bp; + + int answer= compare_strings(fix1->name, fix2->name); + if(!answer) + answer = compare_pointers(fix1->name, fix2->name); + + return answer; +} + +static int +compare_IIDs(const void *ap, const void *bp) +{ + const nsID *a = ap, *b = bp; + int i; +#define COMPARE(field) if (a->field > b->field) return 1; \ + if (b->field > a->field) return -1; + COMPARE(m0); + COMPARE(m1); + COMPARE(m2); + for (i = 0; i < 8; i++) { + COMPARE(m3[i]); + } + return 0; +#undef COMPARE +} + +PRBool +shrink_IDE_array(XPTInterfaceDirectoryEntry *ide, int element_to_delete, + int num_interfaces) +{ + int i; + + if (element_to_delete >= num_interfaces) { + return PR_FALSE; + } + + for (i=element_to_delete+1; i= num_interfaces) { + return PR_FALSE; + } + + deleted = XPT_CALLOC(arena, sizeof(fixElement)); + if (!copy_fixElement(&fix[element_to_delete], deleted)) { + return PR_FALSE; + } + deleted->is_deleted = PR_TRUE; + deleted->maps_to_file_num = fix[replacement].file_num; + deleted->maps_to_interface_num = fix[replacement].interface_num; + + for (i=element_to_delete+1; iiid = from->iid; + to->name = from->name; + to->name_space = from->name_space; + to->interface_descriptor = from->interface_descriptor; + return PR_TRUE; +} + +PRBool +copy_fixElement(fixElement *from, fixElement *to) +{ + if (!from || !to) { + return PR_FALSE; + } + + to->iid = from->iid; + to->name = from->name; + to->file_num = from->file_num; + to->interface_num = from->interface_num; + to->is_deleted = from->is_deleted; + to->maps_to_file_num = from->maps_to_file_num; + to->maps_to_interface_num = from->maps_to_interface_num; + + return PR_TRUE; +} + +static void +print_IID(struct nsID *iid, FILE *file) +{ + fprintf(file, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (PRUint32) iid->m0, (PRUint32) iid->m1,(PRUint32) iid->m2, + (PRUint32) iid->m3[0], (PRUint32) iid->m3[1], + (PRUint32) iid->m3[2], (PRUint32) iid->m3[3], + (PRUint32) iid->m3[4], (PRUint32) iid->m3[5], + (PRUint32) iid->m3[6], (PRUint32) iid->m3[7]); +} + +static void +xpt_link_usage(char *argv[]) +{ + fprintf(stdout, "Usage: %s [-t version number] outfile file1.xpt file2.xpt ...\n" + " Links multiple typelib files into one outfile\n" + " -t create a typelib of an older version number\n", argv[0]); +} + diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore b/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in b/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in new file mode 100644 index 00000000..da1bcfae --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/Makefile.in @@ -0,0 +1,50 @@ +# +# ***** 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 mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +SIMPLE_PROGRAMS = windbgdlg$(BIN_SUFFIX) + +CPPSRCS = windbgdlg.cpp + +include $(topsrcdir)/config/rules.mk + diff --git a/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp b/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp new file mode 100644 index 00000000..9023ef4d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/windbgdlg/windbgdlg.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** 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 Mozilla Communicator client code, released + * March 31, 1998. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * John Bandhauer + * + * Alternatively, the contents of this file may be used under the terms of + * either of 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 ***** */ + +/* Windows only app to show a modal debug dialog - launched by nsDebug.cpp */ + +#include + +int WINAPI +WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, int nCmdShow) +{ + static char msg[4048]; + + wsprintf(msg, + "%s\n\nClick Abort to exit the Application.\n" + "Click Retry to Debug the Application..\n" + "Click Ignore to continue running the Application.", + lpszCmdLine); + + return MessageBox(NULL, msg, "nsDebug::Assertion", + MB_ICONSTOP | MB_SYSTEMMODAL| + MB_ABORTRETRYIGNORE | MB_DEFBUTTON3); +} diff --git a/src/libs/xpcom18a4/xpcom/xpcom-config.h.in b/src/libs/xpcom18a4/xpcom/xpcom-config.h.in new file mode 100644 index 00000000..5338a41d --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/xpcom-config.h.in @@ -0,0 +1,65 @@ +/* Global defines needed by xpcom clients */ + +#ifndef _XPCOM_CONFIG_H_ +#define _XPCOM_CONFIG_H_ + +/* Define this to throw() if the compiler complains about + * constructors returning NULL + */ +#undef CPP_THROW_NEW + +/* Define if the c++ compiler supports a 2-byte wchar_t */ +#undef HAVE_CPP_2BYTE_WCHAR_T + +/* Define if the c++ compiler supports changing access with |using| */ +#undef HAVE_CPP_ACCESS_CHANGING_USING + +/* Define if the c++ compiler can resolve ambiguity with |using| */ +#undef HAVE_CPP_AMBIGUITY_RESOLVING_USING + +/* Define if the c++ compiler has builtin Bool type */ +#undef HAVE_CPP_BOOL + +/* Define if a dyanmic_cast to void* gives the most derived object */ +#undef HAVE_CPP_DYNAMIC_CAST_TO_VOID_PTR + +/* Define if the c++ compiler supports the |explicit| keyword */ +#undef HAVE_CPP_EXPLICIT + +/* Define if the c++ compiler supports the modern template + * specialization syntax + */ +#undef HAVE_CPP_MODERN_SPECIALIZE_TEMPLATE_SYNTAX + +/* Define if the c++ compiler supports the |std| namespace */ +#undef HAVE_CPP_NAMESPACE_STD + +/* Define if the c++ compiler supports reinterpret_cast */ +#undef HAVE_CPP_NEW_CASTS + +/* Define if the c++ compiler supports partial template specialization */ +#undef HAVE_CPP_PARTIAL_SPECIALIZATION + +/* Define if the c++ compiler has trouble comparing a constant + * reference to a templatized class to zero + */ +#undef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO + +/* Define if the c++ compiler supports the |typename| keyword */ +#undef HAVE_CPP_TYPENAME + +/* Define if the stanard template operator!=() is ambiguous */ +#undef HAVE_CPP_UNAMBIGUOUS_STD_NOTEQUAL + +/* Define if statvfs() is available */ +#undef HAVE_STATVFS + +/* Define if the c++ compiler requires implementations of + * unused virtual methods + */ +#undef NEED_CPP_UNUSED_IMPLEMENTATIONS + +/* Define to either or */ +#undef NEW_H + +#endif /* _XPCOM_CONFIG_H_ */ diff --git a/src/libs/xpcom18a4/xpcom/xpcom-private.h.in b/src/libs/xpcom18a4/xpcom/xpcom-private.h.in new file mode 100644 index 00000000..ae1c4605 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/xpcom-private.h.in @@ -0,0 +1,31 @@ +/* The following defines are only used by the xpcom implementation */ + +#ifndef _XPCOM_PRIVATE_H_ +#define _XPCOM_PRIVATE_H_ + +/* Define to build the static component loader */ +#undef ENABLE_STATIC_COMPONENT_LOADER + +/* Define if getpagesize() is available */ +#undef HAVE_GETPAGESIZE + +/* Define if iconv() is available */ +#undef HAVE_ICONV + +/* Define if iconv() supports const input */ +#undef HAVE_ICONV_WITH_CONST_INPUT + +/* Define if mbrtowc() is available */ +#undef HAVE_MBRTOWC + +/* Define if is present */ +#undef HAVE_SYS_MOUNT_H + +/* Define if is present */ +#undef HAVE_SYS_VFS_H + +/* Define if wcrtomb() is available */ +#undef HAVE_WCRTOMB + +#endif /* _XPCOM_PRIVATE_H_ */ + -- cgit v1.2.3
The xptcall porting document has been moved to: +

+http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/porting.html +

+Please update your links. +